Skip to content

Sell prepaid credits at a fixed exchange rate, or pay a reward for every completed quest. Soulbound fungible tokens with a coin transfer on the mint approval.

A credit token is a fungible, non-transferable balance a user buys at a fixed rate: 1 USDC mints 100 credits, 0.5 USDC mints 50. The mint approval carries the price and allowAmountScaling, so one approval serves every purchase size. There is no post-mint approval, so credits cannot be resold; the app debits them off-chain and reconciles to the on-chain purchase record.

A quest token is the reverse flow. The issuer funds an escrow with reward * maxClaims, and each claimant who passes the gate mints one token and receives the reward coin in the same transaction.

What Makes It Work

RequirementToken-standard primitive
Fixed exchange rate at any sizepredeterminedBalances with startBalances.amount = credits per unit and allowAmountScaling: true. See Predetermined Balances
Pay per unitcoinTransfers of "1" base unit of the payment denom per scaled step. See Coin Transfers
Cannot be transferred or soldNo !Mint approval. noForcefulPostMintTransfers: true
Displays as a balance with decimalsAn alias path with the payment denom's decimals. See Alias Denoms
Reward paid on claimcoinTransfers with overrideFromWithApproverAddress: true (escrow pays) and overrideToWithInitiator: true (claimant receives)
One claim per person, capped totalmerkleChallenges with maxUsesPerLeaf: "1" and maxNumTransfers.overallMaxNumTransfers. See Merkle Challenges

The Fields That Matter

The credit mint approval at 100 credits per USDC:

json
{
  "approvalId": "credit-scaled",
  "fromListId": "Mint",
  "toListId": "All",
  "initiatedByListId": "All",
  "tokenIds": [{ "start": "1", "end": "1" }],
  "approvalCriteria": {
    "predeterminedBalances": {
      "incrementedBalances": {
        "startBalances": [{ "amount": "100", "tokenIds": [{ "start": "1", "end": "1" }], "ownershipTimes": [{ "start": "1", "end": "18446744073709551615" }] }],
        "allowAmountScaling": true,
        "maxScalingMultiplier": "18446744073709551615"
      }
    },
    "coinTransfers": [{ "to": "bb1p0rrel3365scadq5k9pv0x0zp9j22js6dnw70d", "coins": [{ "amount": "1", "denom": "ibc/E1116484B327AEE59CDC3DA73D319834781A13DB2A7DFC1F38A30CD45ABF58B8" }] }],
    "overridesFromOutgoingApprovals": true,
    "mustPrioritize": true
  }
}
Token Ownership Requirements
Off
No ownership check
Coin Transfers per Use
On
  • 0.000001 USDCbb1p0rrel3...w70d
Merkle Challenges
Off
No proof required
Predetermined Balances
On
Start: x100 of IDs 1, or any whole multiple of it
Amount Restrictions
Off
No amount limit
Max Transfers
Off
Unlimited uses
Address Checks
Off
No initiator check
Sender and Recipient Approvals
On
Skips the sender's outgoing approvals
Must satisfy the recipient's incoming approvals

The credit mint on bitbadges.io: 100 credits per unit, scaled to the amount bought, with the base price on the payment card.

amount: "1" is one micro-USDC. A user who mints 1000000 credits pays 10000 micro-USDC, which is 0.01 USDC, so the displayed rate is 100 credits per 0.000001 USDC at base units; the alias path makes the wallet show it as intended.

bash
bb build credit-token --payment-denom USDC --recipient bb1p0rrel3365scadq5k9pv0x0zp9j22js6dnw70d \
  --symbol CREDIT --tokens-per-unit 100 --uri ipfs://bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi/collection.json

This emits a Credit Token collection with the single scaled mint approval, a ucredit alias path, autoApproveAllIncomingTransfers: true for holders, and every permission frozen.

Variations

  • Quests: a Quests collection with mintEscrowCoinsToTransfer of reward * maxClaims and a claim approval gated by a Merkle challenge or an on-chain check (mustOwnTokens, dynamicStoreChallenges, evmQueryChallenges). See the quest variant in Create a Collection.
  • Off-chain gates: a claim with plugins (email, Discord, a form) emits the Merkle proof the approval checks.
  • Points that expire: mint with ownershipTimes so unused points lapse at year end, as in a subscription.
  • Redeem for goods: pair credits with a product catalog whose purchase approval requires mustOwnTokens of credits.
  • Spendable points: add a !Mint to burn-address approval so users can burn points on-chain instead of the app tracking usage.

Build It

text
Load the credit-token skill. Build API credits called DEMO where 1 USDC buys 1000 credits paid to bb1p0rrel3365scadq5k9pv0x0zp9j22js6dnw70d, non-transferable, permissions frozen. Validate, review, simulate, then give me the review link.

Edit this page on GitHub