For the complete documentation index, see llms.txt. This page is also available as Markdown.

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)

  1. `set_valid_token_ids` β€” set [{ start: "1", end: "<NUM_PRODUCTS>" }]

  2. `set_standards` β€” set ["Products"]

  3. `set_invariants` β€” set { noCustomOwnershipTimes: true }

  4. `add_approval` xN β€” one purchase approval per product

  5. `add_approval` β€” optional burn approval

  6. `set_collection_metadata` β€” store name, description, image

  7. `set_token_metadata` xN β€” metadata for each product

  8. `set_permissions` β€” preset "fully-immutable"

  9. `validate_transaction` β€” verify structure

  10. `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