Product Catalogs and Commerce
Sell SKUs on-chain with independent prices, supply caps, and burn-on-purchase. One purchase approval per product routes payment straight to the store.
A catalog is one token ID per product and one purchase approval per token ID. Each approval carries that product's price, its supply cap, and whether the buyer keeps a receipt token or the token burns on purchase (a consumable). Payment goes from the buyer to the store address in the same transaction as the mint. There is no cart contract and no escrow; a purchase is one MsgTransferTokens from Mint.
The receipt token is what makes the rest of the standard available: a receipt can gate a download with BB-402, be refunded through a return approval, or expire for a time-limited license.
What Makes It Work
| Requirement | Token-standard primitive |
|---|---|
| Independent price per SKU | coinTransfers on each purchase approval, overrideFromWithApproverAddress: false so the buyer pays. See Coin Transfers |
| Exactly one unit per purchase | predeterminedBalances.incrementedBalances.startBalances of amount 1 for that token ID |
| Limited stock | maxNumTransfers.overallMaxNumTransfers = supply; 0 for unlimited. See Approval Trackers |
| Consumable versus keepsake | toListId: "All" mints a receipt to the buyer; toListId = burn address consumes it on purchase |
| Buyer can discard a receipt | One !Mint to burn-address approval over every product ID |
| Prices cannot change under a buyer | All permissions frozen at creation. See Permissions |
The Fields That Matter
{
"approvalId": "product-purchase-1",
"fromListId": "Mint",
"toListId": "All",
"initiatedByListId": "All",
"tokenIds": [{ "start": "1", "end": "1" }],
"approvalCriteria": {
"predeterminedBalances": {
"incrementedBalances": { "startBalances": [{ "amount": "1", "tokenIds": [{ "start": "1", "end": "1" }], "ownershipTimes": [{ "start": "1", "end": "18446744073709551615" }] }] },
"orderCalculationMethod": { "useOverallNumTransfers": true }
},
"coinTransfers": [{ "to": "bb1p0rrel3365scadq5k9pv0x0zp9j22js6dnw70d", "coins": [{ "amount": "25000000", "denom": "ibc/E1116484B327AEE59CDC3DA73D319834781A13DB2A7DFC1F38A30CD45ABF58B8" }], "overrideFromWithApproverAddress": false, "overrideToWithInitiator": false }],
"maxNumTransfers": { "overallMaxNumTransfers": "100", "amountTrackerId": "product-purchase-1" },
"overridesFromOutgoingApprovals": true,
"overridesToIncomingApprovals": true
}
}Product 2 is the same approval on token ID 2 with its own price, and toListId set to the burn address if it is a consumable.
bb build product-catalog --store-address bb1p0rrel3365scadq5k9pv0x0zp9j22js6dnw70d \
--uri ipfs://bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi/collection.json \
--products '[{"name":"Widget","price":25,"denom":"USDC","maxSupply":100},{"name":"Pass","price":5,"denom":"USDC","burn":true}]'This emits a Products collection with two purchase approvals, one burn approval, per-product token metadata, and frozen permissions.
Variations
- Members-only pricing: a second purchase approval on the same token ID with a lower price and
mustOwnTokensof a membership; buyers prioritize the one they qualify for. - Pay in credits:
mustOwnTokensof a credit token plus a burn of those credits in the same transaction. - Time-limited license: mint receipts with
ownershipTimesso the download gate closes after a year. - Returns: a
!Mintto burn-address approval withcoinTransfersfrom the mint escrow back to the initiator, bounded bytransferTimesto the return window. - Drops: bound each purchase approval's
transferTimesto the sale window, and addperInitiatedByAddressMaxNumTransfers: "1"for one per customer.
Build It
- Skill: Product Catalog
- Guide: Mint and Distribute for paid mints, Token-Gated Access to gate the delivery
- CLI:
bb build product-catalog,bb productsfrom Standards
Load the product-catalog skill. Build a store paid to bb1p0rrel3365scadq5k9pv0x0zp9j22js6dnw70d with three products: Sticker Pack at 3 USDC unlimited, Poster at 20 USDC with 50 in stock, and Day Pass at 5 USDC that burns on purchase. Validate, review, simulate, then give me the review link.