Exaflair Case study · Legends of Hearts
Exaflair design context
Exaflair

Case study · Legends of Hearts · web3 & blockchain

Legends of Hearts arrived as a zip file that could not mint. Exaflair audited it, built the quests web app and the admin panel from scratch, and shipped it on Monad and Base mainnet.

The codebase came over as an archive and a handoff document: a stylized multiplayer web3 action-adventure game with a reward layer that looked finished and could not issue a token. Exaflair audited it, then built the quests web app players use and the admin panel behind it from scratch, developed and deployed the contracts, and shipped to Monad and Base mainnet — redesigning the interface and repairing the inherited contract layer on the way. The mechanism at the centre of it is a signature-gated ERC-721 mint: players earn progress off-chain, a backend key signs a one-time claim, and the contract verifies that signature — with five checks in Solidity — before it will mint anything.

  • SubjectThe inherited quest and reward platform behind the Legends of Hearts game
  • MeasureTwo products built from scratch — the quests web app and the admin panel — contracts developed and deployed to Monad and Base mainnet, and a security audit that catalogued 46 issues with CVSS v3.1 severities and fixed 42 of them, behind a signature-gated ERC-721 mint that enforces 5 checks in Solidity before it will issue a token
  • BaselineThe build as handed over could not complete a mint: outdated ABIs, a broken signature setup, no value sent on the payable mint call, and a hardcoded network and mint fee — so the quests web app and the admin panel were built from scratch, and the contracts were developed and deployed to both mainnets

Proof, before you scroll

Exaflair developed the contracts and deployed them to Monad mainnet and to Base mainnet. The Base pair is the one linked above, and every contract value quoted as text on this page is read from the deployed source and from BaseScan rather than off a screen.

Product screenLegends of Hearts quests · MissionsBuilt by Exaflair
The Missions screen of the Legends of Hearts quests app: a Missions panel reading 2 / 18 Completed, mission categories Starter, Legendary, Partners, Bonus and Quiz, individual tasks worth 10 XP each such as connecting an EVM wallet and linking X and Discord, a 25 XP referral, a Love Score counter, an Early Legend activation state and a remaining-supply counter.
The real product: the quests web app Exaflair built from scratch, and the quest board players work through in it. Eighteen missions across five categories — Starter, Legendary, Partners, Bonus and Quiz — ten XP a task, twenty-five for inviting a legend, and a Love Score that adds up to an attempt at a mint.

Quest-to-mint lifecycle · selected step

  1. Earn XP
  2. Authorize
  3. Submit
  4. Verify
  5. Mint
  6. Close

Pick a step in the explorer under “What we built”; the table in Result follows it.

Engagement

Client
Legends of HeartsA stylized multiplayer web3 action-adventure game, made by the studio Angscope.
Sector
Web3 & blockchainRecorded as the service category on Exaflair's portfolio sheet.
Exaflair's role
Built from scratch, audited, deployedThe quests web app built from scratch, the admin panel built from scratch, the security audit, contracts development and deployment, and deployment to Monad and Base mainnet — around an inherited codebase that could not mint, whose contract layer was repaired and whose interface was redesigned on the way.
Engagement
OngoingOne piece of work rather than a set of tickets: two products built from scratch, the audit, contracts development and deployment, and both mainnet deployments — with further work committed.
Networks
Monad and Base mainnetExaflair developed the contracts and deployed them to both mainnets: Monad mainnet, after Monad testnet, and Base mainnet. It is the Base pair that is linked and read from on this page.
Stack
Next.jsNestJSPostgreSQLDockerNext.js admin panelSolidity 0.8.27ERC-721OpenZeppelinECDSA

In the client's words

Ahmed Y. Alansari
Ahmed Y. Alansari
Creative Director,
Legends of Hearts

“Excellent developers with outstanding communication. We couldn't ask for more. They're expert full-stack programmers who took the entire project to the next level with their proactive recommendations and advice. Totally recommended.”

Supplied by Exaflair.

Context

A reward layer that looked finished, and could not issue a token.

In the client's own words, Legends of Hearts is “a stylized multiplayer Web3 action-adventure game where players race through obstacle-filled levels, convert emotions, liberate hearts, defeat the villain Sharshoor, and share victories with loved ones via NFT gifts on social media.” The heroes are Delmo and Dala, carrying purity weapons against Sharshoor's dark alchemy, and the world is Candy Valley.

That last clause is where the engineering starts. A gift you can share is a token someone actually owns, on a chain, in their own wallet — and a game cannot simply mint one whenever a player asks, or the supply is whatever the studio is willing to give away. The quest layer that was meant to do this arrived at Exaflair as a codebase in an archive with a handoff document: an app that presented a full quest board and could not carry a player through to a token.

What the archive settled was that the quest layer had to be built rather than patched. Exaflair audited what was there, built the quests web app players use and the admin panel the client did not have from scratch, developed the contracts and deployed them to Monad and Base mainnet — redesigning the interface and repairing the inherited contract layer along the way.

Angscope, the studio behind the game, makes immersive, story-driven games with family-friendly gameplay.

  • In-game capturelegendsofhearts.com
    In-game capture with the HUD showing a score of 80, four lives, 23 heart coins and a 0:00 timer; two characters stand beside an open treasure chest under a heart-shaped tree holding a glowing bell.
    The run. Score, lives, heart coins and the bell in the heart tree — the game the reward layer attaches to.
  • In-game capturelegendsofhearts.com
    In-game capture: a character in a blue hat stands on a mossy ledge casting golden magic at a sleeping cat, beside a glowing cyan portal arch, with spiked crushing traps to the left.
    The levels. Platform hazards, a sleeping cat and a portal arch — the “obstacle-filled levels” of the client's description.
  • In-game capturelegendsofhearts.com
    In-game capture: an orange-haired character stands on a crumbling pillar above a row of spikes, with gold heart coins floating between plank platforms.
    The in-game reward. Gold heart coins collected between plank platforms — the earned thing the token layer sits on top of.
  • Concept sheetlegendsofhearts.com
    Concept sheet showing seven octopus-themed weapons, each one labelled.
    The weapons. A published concept sheet, not a game screen: seven octopus-themed weapons, each labelled.
  • Character sheetlegendsofhearts.com
    Character line-up: an archer boy holding a bow and a gold heart coin, a girl with a horn, and a magenta squid-headed figure in a white coat.
    The cast. A published line-up, not a game screen: the archer with a gold heart coin, the girl with a horn, and a squid-headed figure in a white coat.
  • Asset sheetlegendsofhearts.com
    Environment asset sheet showing seven level props, including a heart-shaped tree holding a bell and a glowing portal doorway.
    The props. A published asset sheet: the heart tree with its bell and the portal doorway among seven level props.

These six are art the client published on legendsofhearts.com. They are the game, not the product — the product screens on this page are labelled as such.

Partner brands shown on the client's site

  • LootGO partner medallion: a circular purple stone medallion with the LootGO mark and a stone nameplate.LootGO
  • Pixel Realm partner medallion: a circular purple stone medallion with the Pixel Realm mark and a stone nameplate.Pixel Realm
  • Merso partner medallion: a circular purple stone medallion with the Merso mark and a stone nameplate.Merso
  • Mind Agents partner medallion: a circular purple stone medallion with the Mind Agents mark and a stone nameplate.Mind Agents

Constraint

The reward could not complete, and the reason was in the contract layer.

The shape of the mechanism was right: progress is earned off-chain where the game lives, and proven on-chain in a single transaction, because a contract that cannot see a quest has to be handed a proof it can check for itself. What the audit found was that the bridge carrying that proof was broken at both ends, and that the backend underneath it was carrying known vulnerabilities — which is why the quests web app and the admin panel were built from scratch and the contracts were developed and deployed afresh to Monad and Base mainnet.

  • The mint call was malformedOutdated ABIs, and no value sent on a payable mint. The transaction could not succeed even for a player who had genuinely earned it.
  • The signature scheme did not holdNonce and signature verification were broken — the single thing the whole off-chain gate rests on, and the one place a replayed claim would break the cap.
  • The network and the fee were fixed in codeBoth were hardcoded, so neither the chain nor the mint fee could move without a redeploy.
  • Twelve high-severity backend dependenciesCarried in with the inherited codebase, before a line of new work was written.

What we built

A signature is the bridge: earned off-chain, verified in Solidity, minted in the same call.

Exaflair built the quests web app players use and the admin panel behind it from scratch, developed and deployed the contracts, and shipped to Monad and Base mainnet. The inherited archive supplied the audit target and the shape of the mechanism; everything a player or an operator touches today is Exaflair's build. This is what shipped.

  • The quests web app, built from scratch. The front end players actually use: wallet gating, the eighteen-mission board across five categories, the XP scoring behind the Love Score, the remaining-supply counter and the tiered heart badges.

  • The admin panel, built from scratch. Password authentication and refresh tokens, task creation, and filtered exports — the operations side the client did not have.

  • The security audit. Forty-six issues catalogued and scored with CVSS v3.1 severities, forty-two of them fixed and twelve high-severity backend dependencies cleared. The contract-layer findings fed the client's own audit.

  • Contracts development and deployment. The signature-gated ERC-721 pair in Solidity 0.8.27 on OpenZeppelin and ECDSA, developed and deployed — including the repairs the audit turned up in the inherited contract layer: nonce and signature verification corrected, the payable mint call carrying its fee, and the network and fee no longer hardcoded.

  • Deployment to Monad and Base mainnet. Both networks, as mainnet deployments: Monad mainnet after Monad testnet, and the Base mainnet pair that is linked and read from on this page.

  • Quiz and evidence tasks. Multiple-choice quizzes with answer validation, and evidence tasks that are reviewed by hand before they count.

  • Discord roles. Role assignment and membership checks wired to the outcome of a claim.

  • The interface redesign. The from-scratch app was drawn from the client's own Illustrator mockup and made safe across aspect ratios, with a disclaimer and consent checkbox on the mint.

  • Staging, deployment and recovery. A staging environment stood up after untangling a frontend-to-backend route mismatch and its nginx configuration, the client's environments restored after they were broken on their side, and the mainnet deployments walked through with the client's own developer.

The quest backend holds a signer key. When a player has earned a mint, it signs an ECDSA payload that hashes the contract address, the chain id, the recipient, the current token counter, a timestamp and a nonce. The player's own wallet then calls safeMint with that signature and the fee, and the contract re-derives the same hash and checks who signed it. Step through the whole lifecycle below — the evidence card, the step description and the table in Result all follow your selection.

Product screenLegends of Hearts quests · the way in
The quests app landing screen, gated behind connecting a wallet.
The app is wallet-gated. Connect first, then the board opens.

In the client's own words on that app: players complete simple tasks to earn XP, called a Love Score; every hundred XP earns an attempt to mint, and a successful mint unlocks a Discord role. This is the quests web app Exaflair built from scratch, on the rewards backend behind it.

App screens on this page are imagery of the product, and the figures inside them are the app's own live counters. Contract values quoted as text on this page are read from the deployed contract source and from the block explorer, never off a screen.

Quest-to-mint lifecycle explorer

Use ← → or click a step.
On-chain · inside safeMintFrom the contract source
Calls at this step
    What the contract enforces
      Events emitted

        Every value in this card is read from the deployed contract source, not from a screen.

        4 / 6

        Verify

        What happens

        Why it is built this way

        Exaflair's part

        Solidity 0.8.27, on OpenZeppelin's ERC721, ERC721Pausable, Ownable and ECDSA. Administrative actions sit behind a 300-second cooldown, and tokenURI is constant across every token: one shared artwork, no per-token traits.

        • ERC-721 · Base mainnet · the reward side

          Early Legend NFT

          The reward side of a quest attempt: the token a player receives when the signed claim verifies.

          0xF16e3c2c7E49A0c7610Fb42637f5229181eC64df
          273tokens minted
          46holders
        • ERC-721 · Base mainnet · the consolation side

          Try Again NFT

          The consolation side of the same attempt, on the same mechanism — a player walks away with a token either way.

          0xC55d7766ABA9e3147478Bb3DE6e3f5f36F4c72EE
          229tokens minted
          106holders

        The Base mainnet pair Exaflair developed and deployed, alongside the same mechanism on Monad mainnet. Mint and holder counts read from BaseScan.

        What we did not build

        Boundaries, so the credit lands where it belongs.

        • Not the game art. The characters, levels, concept sheets and every piece of art on this page are the client's, and remain theirs.

        • Not the game engine. The 2.5D game itself is the studio's build; Exaflair's work is the quests web app and reward layer around it, built from scratch.

        • Not the inherited archive. The codebase came over as an archive with a handoff document, and that is what the security audit was run against. The quests web app and the admin panel that shipped were built from scratch, and the contracts were developed and deployed by Exaflair to Monad and Base mainnet.

        • Not the tokenomics. What the token is worth and how the drop is shaped were the client's calls; Exaflair built and deployed the mechanism that enforces them.

        • No new chain and no bespoke token standard. The work sits on OpenZeppelin's ERC-721, which is why anyone can read the deployed contract on a block explorer today.

        • No per-token art or trait system: tokenURI returns the same metadata for every token, by design.

        • No claim about players, sales, revenue or secondary trading is made anywhere on this page. The mint and holder counts are the only distribution figures, and they are read from the chain.

        Result

        What the audit found, and what can be read off the chain.

        • 46
          issues catalogued in the security audit
          Each scored with a CVSS v3.1 severity
        • 42
          of those issues fixed
          The contract-layer findings also fed the client's own audit
        • 12
          high-severity backend dependencies cleared
          Carried in with the inherited codebase
        • 5
          checks the contract makes per mint
          Fee, cap, signature age, nonce, recovered signer
        • 273
          Early Legend NFTs minted
          To 46 holders, read from BaseScan
        • 229
          Try Again NFTs minted
          To 106 holders on the paired contract
        • 7,000
          maximum supply, enforced in the contract
          A check inside the mint, not a policy document
        • 0.00044ETH
          mint fee, exact
          Not a minimum: an exact-amount check, forwarded straight to the owner

        The first four tiles are Exaflair's own audit record, from the security audit that ran alongside building the quests web app and the admin panel from scratch. The last four are read from the contracts Exaflair developed and deployed — the Base mainnet pair, deployed as the same mechanism went to Monad mainnet.

        Step by step: where it runs, and what the contract enforces

        The row for the step you picked in the explorer is highlighted, and clicking a row selects that step. “Where it runs” is the honest split: half of this lifecycle never touches the chain, which is exactly why the signature exists.

        StepWhere it runsWhat the contract enforces
        Earn XPOff-chain, in the quest platform.Nothing. There is no XP, task or quest state in either contract; the gate is entirely off-chain.
        AuthorizeOff-chain, with the backend's signer key.Nothing yet — but the payload it signs is what the contract will re-derive: contract address, chain id, recipient, token counter, timestamp, nonce.ECDSA
        SubmitThe player's own wallet, on-chain.The call arrives with everything the decision needs and the exact fee attached.safeMint(to, signature, nonce, timestamp)
        VerifyOn-chain, inside the mint call.Five checks: exact fee, under the 7,000 cap, signature younger than one hour, nonce unused for that recipient, recovered signer matches. Any one failing reverts the call.
        MintOn-chain, in the same transaction.Nonce marked used, counter incremented, sequential token id minted, fee forwarded to the owner so no ETH accumulates.NFTMinted
        CloseOn-chain, owner only.Pausing blocks minting and nothing else: every token already issued stays transferable. Admin actions wait out a 300-second cooldown.MintFeeUpdated · SignerChanged · CoolDownSet

        Selected in the explorer: Verify —

        Closing quote

        “They took the entire project to the next level with their proactive recommendations and advice.”

        Ahmed Y. Alansari, Creative Director, Legends of Hearts.

        What's next

        Two products built from scratch, live on two mainnets, and more work committed.

        The client went from an archive that could not mint to a quests web app and an admin panel built from scratch, an audited platform, and contracts developed and deployed to Monad and Base mainnet — and committed further work to the team on the strength of it. The mechanism is the durable part: an off-chain gate, an ECDSA payload bound to the contract, the chain and the token counter, and five checks in Solidity that decide whether a mint happens. It is readable on a block explorer by anyone, which is why this page can be specific without asking you to take our word for anything.

        If you have inherited a build you cannot ship, this is the shape of the job: audit it properly and score what you find, build from scratch what has to be built rather than patched, develop and deploy the contracts to the mainnets they belong on, and keep the cap and the fee inside the contract rather than in a policy document.

        Exaflair

        Exaflair Technologies plugs product minds and AI-boosted builders into your team. One conversation to scope it.

        Book a call

        Powered by intelligence, driven by flair