Products
Multi-product storefront with per-product pricing, supply limits, and optional burn-on-purchase. Each product is a separate token ID.
Category: Token Types
Summary
Required standards: ["Products"]
N token IDs (one per product), starting at 1
N+1 approvals: 1 purchase approval per product + 1 optional burn approval
Each purchase approval: fromListId="Mint", toListId="All" (or burn address if burn-on-purchase), 1 coinTransfer paying the store address
Payment goes directly to store address (NOT to escrow) β overrideFromWithApproverAddress: false
Each product has independent price, supply limit (maxNumTransfers), and burn-on-purchase toggle
predeterminedBalances.incrementedBalances.startBalances: 1x of that product's token ID
Optional burn approval: !Mint β burn address, no coinTransfers
invariants: { noCustomOwnershipTimes: true }
All permissions frozen after creation
DON'T use overrideFromWithApproverAddress β payment goes directly to store, not from escrow
DON'T use allowAmountScaling β fixed price per item
DON'T use votingChallenges, merkleChallenges, or mustOwnTokens
DO use unique approvalId per product (e.g. "product-purchase-1", "product-purchase-2")
DO set maxNumTransfers to supply limit (0 = unlimited)
Instructions
Products Configuration
Mental Model
A multi-product storefront where each product is a separate token ID. Buyers pay coins to mint a product token. Each product has its own price, supply limit, and optional burn-on-purchase setting. Payment goes directly to the store owner's address (not escrow).
Collection Structure
Token IDs 1..N (one per product)
Standard: "Products"
validTokenIds: [{ start: "1", end: "<NUM_PRODUCTS>" }]
invariants: { noCustomOwnershipTimes: true }
All permissions frozen after creation
Approval Structure
Each product gets its own purchase approval. There's also an optional global burn approval.
Purchase Approval (per product)
For burn-on-purchase products, set toListId to the burn address instead of "All". The buyer never holds the token β it's minted directly to burn, and the purchase receipt is the transaction itself.
Burn Approval (optional, for all products)
Creation Flow (Tool Calls)
`set_valid_token_ids` β set [{ start: "1", end: "<NUM_PRODUCTS>" }]
`set_standards` β set ["Products"]
`set_invariants` β set { noCustomOwnershipTimes: true }
`add_approval` xN β one purchase approval per product
`add_approval` β optional burn approval
`set_collection_metadata` β store name, description, image
`set_token_metadata` xN β metadata for each product
`set_permissions` β preset "fully-immutable"
`validate_transaction` β verify structure
`simulate_transaction` β dry run
Common Mistakes
DON'T use overrideFromWithApproverAddress on purchase approvals β payment goes directly to the store address, not from escrow
DON'T use allowAmountScaling β each purchase is exactly 1 item at fixed price
DON'T use a single approval for multiple products β each product needs its own approval with its own tokenIds, price, and supply limit
DON'T forget unique approvalIds β duplicate IDs will cause the chain to reject the transaction
DON'T set maxNumTransfers > 0 on the burn approval β burns should be unlimited
DON'T use votingChallenges, merkleChallenges, or mustOwnTokens β purchases are open to all
DON'T forget to set toListId to burn address for burn-on-purchase products
Last updated