Quest
Quest/reward collection β users complete criteria and claim a badge + coin payout
Category: Token Types
Summary
Required standards: ["Quests"]
Single token only: validTokenIds = [{start: "1", end: "1"}]
Quest approval MUST be properly gated β typically via an off-chain claim (merkle challenge with claimConfig), but can also use on-chain criteria (mustOwnTokens, dynamicStoreChallenges, evmQueryChallenges, votingChallenges)
Coin transfers with overrideFromWithApproverAddress: true + overrideToWithInitiator: true
predeterminedBalances: amount 1, no increments, no recurring, no duration
Escrow funded upfront via set_mint_escrow_coins (rewardAmount * maxClaims)
invariants.noCustomOwnershipTimes: true
Permissions: use "locked-approvals" preset (recommended)
Default balances: empty balances, all auto-approve flags true
Instructions
Quest Configuration
Mental Model
A quest collection rewards users for completing criteria. Users receive a quest badge (token 1) + coin payout.
The quest approval MUST be properly gated so that only eligible users can claim. Gating options:
Off-chain claim (most common): A merkle challenge with claimConfig containing plugins (password, codes, whitelist, etc.). The claim is verified off-chain by BitBadges, and a merkle proof is issued for on-chain redemption.
On-chain criteria: mustOwnTokens (require holding specific tokens/badges), dynamicStoreChallenges, evmQueryChallenges, votingChallenges β these are checked directly on-chain during the transfer.
Both: Combine off-chain claims with on-chain criteria for layered verification.
Choose the gating approach based on the user's request. If they mention passwords, codes, or whitelists, use an off-chain claim. If they mention token ownership or on-chain conditions, use the corresponding on-chain criteria.
Build Steps (call ALL in parallel in one round)
set_standardsβ["Quests"]set_valid_token_idsβ[{ "start": "1", "end": "1" }]set_invariantsβ{ "noCustomOwnershipTimes": true }set_permissionsβ{ "preset": "locked-approvals" }set_default_balancesβ empty balances, all auto-approve trueset_collection_metadata/set_token_metadataβ descriptive contentadd_approvalβ the quest approval (see exact structure below)set_mint_escrow_coinsβ REQUIRED for coin rewards. Amount = rewardPerClaim Γ maxClaims.
Quest Approval (add_approval)
Use approvalId "quest-approval". The EXACT approvalCriteria structure:
Gating β add ONE OR MORE of these to approvalCriteria based on the user's request:
Off-chain claim:
"merkleChallenges": [{ "root": "", "expectedProofLength": "0", "maxUsesPerLeaf": "1", "uri": "", "customData": "", "useCreatorAddressAsLeaf": false, "claimConfig": { "approach": "in-site", "label": "...", "plugins": [...] } }]Token ownership:
"mustOwnTokens": [{ "collectionId": "...", "amountRange": {"start":"1","end":"18446744073709551615"}, ... }]β Use collectionId "0" to self-reference this collection (e.g., require holding token 1 from this quest collection itself).Dynamic store:
"dynamicStoreChallenges": [...]EVM query:
"evmQueryChallenges": [...]
Off-chain claims are the most common for quests (passwords, codes, whitelists). On-chain criteria can be combined with or used instead of claims.
Escrow Funding (REQUIRED)
Call set_mint_escrow_coins in the SAME round as the other tools. Example for 10 ATOM reward Γ 50 claims:
Without this, the escrow has no funds and claims will fail.
Common Mistakes
DON'T add extra fields to coinTransfers β the ONLY fields are: to, overrideFromWithApproverAddress, overrideToWithInitiator, coins. NO startTime, NO other fields.
DON'T omit
manualBalances: []in predeterminedBalances β SDK crashes without itDON'T omit fields in orderCalculationMethod β include ALL boolean fields
DON'T forget
set_mint_escrow_coinsβ without it, the escrow is empty and rewards can't be paidDON'T set maxUsesPerLeaf to anything other than "1" β each user claims once
DON'T set allowOverrideTimestamp: true β quests require false
DON'T set useCreatorAddressAsLeaf: true β quests require false
Last updated