Skip to content

Issue a token backed 1:1 by USDC or any IBC coin. One invariant and two approvals give you deposit-to-mint, burn-to-withdraw, and an x/bank denom.

A backed token is a collection whose every unit is held 1:1 against an existing IBC coin. Users send USDC to a protocol-controlled backing address and receive your token. They send your token back and receive their USDC. The chain enforces the 1:1 ratio in an invariant, so no contract holds the reserve and no admin key can mint unbacked supply.

The same shape covers a compliant stablecoin wrapper, a branded deposit receipt, a permissioned version of a foreign asset, and the vault under an AI agent.

What Makes It Work

RequirementToken-standard primitive
Every unit is backed 1:1invariants.cosmosCoinBackedPath with a sideA coin and a sideB token conversion. See Backed Minting
Deposit mints, withdraw burnsTwo collection approvals: fromListId = backing address (deposit) and toListId = backing address (withdraw), both with allowBackedMinting: true. See Special Address Flags
Reserve address nobody controlsThe backing address is derived from the IBC denom. bb account alias for-ibc-backing <denom> or the generate_backing_address tool prints it
Spendable as an x/bank coin and over IBCAn alias path with the same decimals as the backing coin. See Alias Denoms
Holders can or cannot tradeOne optional post-mint approval (fromListId: "!Mint", toListId: "All"). Omit it for a vault, include it for a wrapped asset
Rules can never changecanUpdateCollectionApprovals locked, noForcefulPostMintTransfers: true

The Fields That Matter

json
{
  "standards": ["Smart Token"],
  "invariants": {
    "cosmosCoinBackedPath": {
      "conversion": {
        "sideA": { "amount": "1", "denom": "ibc/E1116484B327AEE59CDC3DA73D319834781A13DB2A7DFC1F38A30CD45ABF58B8" },
        "sideB": [{ "amount": "1", "tokenIds": [{ "start": "1", "end": "1" }], "ownershipTimes": [{ "start": "1", "end": "18446744073709551615" }] }]
      }
    },
    "noForcefulPostMintTransfers": true
  },
  "collectionApprovals": [
    {
      "approvalId": "smart-token-deposit",
      "fromListId": "bb1backingaddress...",
      "toListId": "!bb1backingaddress...",
      "initiatedByListId": "All",
      "approvalCriteria": { "mustPrioritize": true, "allowBackedMinting": true }
    },
    {
      "approvalId": "smart-token-withdraw",
      "fromListId": "!Mint:bb1backingaddress...",
      "toListId": "bb1backingaddress...",
      "initiatedByListId": "All",
      "approvalCriteria": { "mustPrioritize": true, "allowBackedMinting": true }
    }
  ]
}
smart-token-depositcollectionID: smart-token-deposit
Senderbb1backing...s...
RecipientAll exceptbb1backing...s...
InitiatorAll
Transfer TimesAll time
Token IDsAll
Ownership TimesAll time
Backed mintingMust prioritize

The deposit approval as the transferability tab lists it: the backing address is the sender, and anyone except that address can receive.

The !Mint:bb1backingaddress... list means "everyone except Mint and the backing address", so only real holders can withdraw. There is no fromListId: "Mint" approval anywhere: supply exists only when a deposit backs it.

bash
bb build smart-token --backing-coin USDC --symbol sUSDC --tradable \
  --uri ipfs://bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi/collection.json

This emits one MsgUniversalUpdateCollection with the invariant, the two approvals above, a usUSDC alias path with 6 decimals, and a third transferable approval because of --tradable.

Variations

  • Withdraw limits: add approvalAmounts with resetTimeIntervals.intervalLength: "86400000" to the withdraw approval for a daily cap. See Approval Trackers.
  • Withdraw 2FA: add mustOwnTokens pointing at a custom 2FA collection so a withdrawal needs a fresh short-lived token.
  • Compliance on every hop: put dynamicStoreChallenges or mustOwnTokens (a KYC credential) on the transferable approval. Pools and orderbooks inherit the check. See Compliance Zones.
  • DEX trading: add the Liquidity Pools standard and set disablePoolCreation: false. See Trade on the DEX.
  • Native coin instead of IBC: wrap ubadge or another x/bank coin with a wrapper path and allowSpecialWrapping: true.

Build It

text
Load the smart-token skill. Build a USDC-backed token called sUSDC that holders can transfer peer to peer, with a 10000 USDC per day withdraw limit. Run validate, review, and simulate, fix anything critical, then give me the review link.

Edit this page on GitHub