Skip to content

Single-item auction with intent-based bidding. Seller mints NFT directly to the winning bidder during the accept window.

Auction

Instruction text for agents that use the Auction skill, loaded by bb dev skills auction and the MCP get_skill_instructions tool.

Try it

Paste this into Claude Code, Codex, or Cursor with the BitBadges MCP server wired. The agent loads the skill, builds, verifies, and hands back a link to review and sign.

text
Load the auction skill and build me one: single-item auction with intent-based bidding. Seller mints NFT directly to the winning bidder during the accept window. Use the session tools, run validate, review, and simulate in parallel, fix anything critical, then call get_review_url and give me the link.

From a shell, bb dev skills auction prints the same instructions.

Summary

Required standards: ["Auction"]

  • 1 token ID (the auctioned item)
  • 2 collection-level approvals: mint-to-winner (combines mint + accept), burn (cleanup)
  • Mint-to-winner: seller mints NFT directly to winning bidder during accept window (bidDeadline → bidDeadline + acceptWindow)
  • No separate mint-at-creation step, token doesn't exist until seller accepts a bid
  • Burn: anyone can burn token to burn address (permanent cleanup)
  • Bidding via user-level incoming approval intents (not collection approvals)
  • Bids must have transferTimes valid through end of accept window (not just bid deadline)
  • initiatedByListId on mint-to-winner = seller address (only seller can accept)
  • maxNumTransfers = 1 on all approvals (one-shot)
  • overridesToIncomingApprovals: false on mint-to-winner (bidder's incoming approval handles payment)
  • Burn approval has no override flags, relies on defaultBalances autoApproveSelfInitiatedOutgoingTransfers + burn destination
  • noForcefulPostMintTransfers: true in invariants (permanently locks out forceful transfers post-mint)
  • After settlement, the mint-to-winner approval is auto-deleted via afterOneUse, protocol validators treat a missing mint-to-winner as a valid post-settlement state, not an error
  • All permissions frozen after creation
  • Don't use coinTransfers on collection approvals, payment happens via intent matching
  • Don't set initiatedByListId to "All" on mint-to-winner, must be seller
  • Don't set transferTimes to forever, must be bounded to accept window
  • Don't put override flags on the burn approval, auction has noForcefulPostMintTransfers: true, so non-mint override flags would be invariant violations
  • Do use autoDeletionOptions.afterOneUse: true on mint-to-winner

Instructions

Auction Configuration

Mental Model

A single-item auction where the seller creates a collection, bidders place intent-based bids, and the seller mints the NFT directly to the winning bidder during the accept window. There is no separate mint-then-transfer flow, mint + accept happen in one action. The collection has no coinTransfers, payment is handled entirely through the bidder's user-level approval (intent matching).

Collection Structure

  • Token ID 1 = The auctioned item
  • Standard: "Auction"
  • validTokenIds: [{ start: "1", end: "1" }]
  • invariants: { noCustomOwnershipTimes: true, maxSupplyPerId: "0", noForcefulPostMintTransfers: true, disablePoolCreation: true }
  • noForcefulPostMintTransfers: true locks the collection so no non-mint approval can ever use overridesFromOutgoingApprovals or overridesToIncomingApprovals, the burn approval below relies on defaultBalances auto-approve flags instead
  • All permissions frozen after creation

Bidding Mechanism

Bidders set user-level incoming approvals on their own accounts that say "I will pay X coins for token 1 from this collection." The seller then accepts the best bid by minting the token directly to the winning bidder during the accept window. The bidder's incoming approval handles the coin payment side via intent matching.

Bids must have transferTimes that stay valid through the end of the accept window (not just the bid deadline), so the seller can match them during the entire accept period.

Preferred path: presets (two short tool calls)

ts
add_preset_approval({
  presetId: "auction.mint-to-winner",
  params: {
    sellerAddress: "bb1...",
    bidDeadlineMs: "<unix ms>",
    acceptWindowEndMs: "<unix ms>"
  }
})
add_preset_approval({ presetId: "auction.burn", params: {} })

2 Approvals

1. Mint-to-Winner (seller mints NFT directly to winning bidder during accept window)

json
{
  "approvalId": "auction-mint-to-winner",
  "fromListId": "Mint",
  "toListId": "All",
  "initiatedByListId": "<SELLER_ADDRESS>",
  "tokenIds": [{ "start": "1", "end": "1" }],
  "transferTimes": [{ "start": "<BID_DEADLINE>", "end": "<BID_DEADLINE + ACCEPT_WINDOW>" }],
  "approvalCriteria": {
    "overridesFromOutgoingApprovals": true,
    "overridesToIncomingApprovals": false,
    "coinTransfers": [],
    "predeterminedBalances": {
      "incrementedBalances": {
        "startBalances": [{ "amount": "1", "tokenIds": [{ "start": "1", "end": "1" }], "ownershipTimes": [{ "start": "1", "end": "18446744073709551615" }] }]
      },
      "orderCalculationMethod": { "useOverallNumTransfers": true }
    },
    "maxNumTransfers": { "overallMaxNumTransfers": "1" },
    "autoDeletionOptions": { "afterOneUse": true, "afterOverallMaxNumTransfers": true }
  }
}

Critical: overridesToIncomingApprovals: false: the bidder's incoming approval (intent) must be checked so the coin payment side executes. transferTimes are bounded to the accept window only, the seller cannot mint before the bid deadline. toListId: "All" allows minting to any address (the winning bidder).

2. Burn (cleanup: anyone can burn the token)

json
{
  "approvalId": "auction-burn",
  "fromListId": "!Mint",
  "toListId": "<BURN_ADDRESS>",
  "initiatedByListId": "All",
  "tokenIds": [{ "start": "1", "end": "1" }],
  "transferTimes": [{ "start": "1", "end": "18446744073709551615" }]
}

No approvalCriteria overrides: because the invariants lock noForcefulPostMintTransfers: true, the burn approval must not set overridesFromOutgoingApprovals or overridesToIncomingApprovals. It relies on defaultBalances.autoApproveSelfInitiatedOutgoingTransfers: true for the outgoing side and on the burn destination for the incoming side.

Auction Flow

  1. Create: Seller creates auction collection with 2 approvals. No token is minted yet.
  2. Bid: Bidders place intent-based bids (user-level incoming approvals with coin payment offers). Bids must have transferTimes valid through end of accept window.
  3. Accept: After bid deadline, seller mints token 1 directly to the winning bidder's address. The bidder's incoming approval triggers coin payment via intent matching. One action: mint + payment.
  4. Cleanup: If unsold, burn approval allows cleanup.

Creation Flow (Tool Calls)

  1. set_valid_token_ids: set [{ start: "1", end: "1" }]
  2. set_standards: set ["Auction"]
  3. set_invariants: set { noCustomOwnershipTimes: true, maxSupplyPerId: "0", noForcefulPostMintTransfers: true, disablePoolCreation: true }
  4. add_approval x2: mint-to-winner, burn
  5. set_collection_metadata: auction title, description, image
  6. set_token_metadata: token 1 metadata (the item being auctioned)
  7. set_permissions: preset "fully-immutable"
  8. validate_transaction: verify structure
  9. simulate_transaction: dry run

Common Mistakes

  • Don't add coinTransfers to collection approvals, payment flows through intent matching, not collection-level coin transfers
  • Don't set initiatedByListId to "All" on mint-to-winner, only the seller can accept bids
  • Don't set transferTimes to forever, must be bounded to accept window (bidDeadline → bidDeadline + acceptWindow)
  • Don't set overridesToIncomingApprovals to true on mint-to-winner, must be false so the bidder's incoming approval (payment intent) is checked
  • Don't add override flags to the burn approval, the invariant noForcefulPostMintTransfers: true rejects overridesFromOutgoingApprovals or overridesToIncomingApprovals on any non-mint approval
  • Don't worry if the mint-to-winner approval is absent after settlement, autoDeletionOptions.afterOneUse: true removes it after the first successful mint, and the protocol validator accepts that as a valid post-settlement state
  • Don't create a separate mint-to-seller approval, the token should not exist until the seller accepts a bid
  • Don't forget autoDeletionOptions on mint-to-winner, without afterOneUse: true, the seller could mint to multiple bidders
  • Don't forget that bids must have transferTimes valid through the end of the accept window, not just the bid deadline

Edit this page on GitHub

For agents

How agents read these docs