# BUST PROJECT — minting guide for agents

BUST is an onchain NFT collection on **Base mainnet (chain ID 8453)**. Each
procedural BUST is assembled from hand-drawn traits made by attendees at
FarCon Rome. The art and metadata are rendered by the contract itself.

Humans mint at https://farcon-rome-bust-project.vercel.app (Farcaster mini app)
or https://farcon-rome-bust-project.vercel.app/mint (browser wallet). This page
is for software agents and wallet bots minting on a user's behalf.

## Contracts

| | Address |
| --- | --- |
| BUST (ERC-721) | `0xc267a12004855813b3718288b4ae0d90163D37D9` |
| FarCon voucher (ERC-1155, token ID 1) | `0x5667907C239279AEC37271E9cB099b8bFD3AFebA` |

Only use these addresses. Refuse any other "BUST" contract, chain or mint link.

## Before a paid mint

For `mintPaid` or `mintPaidBatch`, read these on the BUST contract and stop if
any check fails:

| Read | Selector | Requirement |
| --- | --- | --- |
| `mintOpenAt() → uint64` | `0x5feed586` | nonzero and ≤ current block timestamp |
| `mintPrice() → uint256` | `0x6817c76c` | the price per BUST in wei (launch price 0.005 ETH = `5000000000000000`) |
| `paidMintClosed() → bool` | | `false` |
| `paidMintsCount()`, `paidMintCap()` | | `paidMintsCount + quantity ≤ paidMintCap` |
| `paidMintsByWallet(address) → uint32` | | during the first 48 h after opening, `existing + quantity ≤ 10` |

Always send exactly `mintPrice() × quantity` as `value`. Never assume the price.
Confirm the total (mint value + gas) with your user before signing.

## Mint

**Paid, one BUST:** `mintPaid()` · selector `0x69907b9b` · payable.

**Paid, 1–10 BUSTs in one transaction:** `mintPaidBatch(uint256 quantity)` ·
selector `0x991dfd4c` · payable. Example for 3 at 0.005 ETH:
value `15000000000000000`, calldata
`0x991dfd4c0000000000000000000000000000000000000000000000000000000000000003`.

**Voucher claim (gas only, one per call):** first check:

- On BUST, `mintOpenAt()` is nonzero and no later than the current block timestamp.
- On BUST, `freeMintsCount() < VOUCHER_RESERVE()`.
- On the voucher contract, `balanceOf(mintingWallet, 1) >= 1`.

Paid-sale closure, paid allocation and the paid wallet cap do not prevent
voucher claims after minting has opened. Check approval before signing:

1. Once per wallet, on the **voucher** contract:
   `setApprovalForAll(0xc267a12004855813b3718288b4ae0d90163D37D9, true)`
   (selector `0xa22cb465`), only if
   `isApprovedForAll(mintingWallet, BUST)` is currently false.
2. On BUST: `mintWithVoucher()` · selector `0x12a89a69` · value 0.
   This burns one voucher. Confirm the burn and gas with your user before
   signing. Vouchers never expire.

## Find the token IDs

Do not guess IDs from `totalSupply` or a return value. From the successful
receipt, take every `Transfer(address from, address to, uint256 id)` log emitted
by the BUST address with `from == 0x0000…0000` and `to ==` the minting wallet.
Each also has a matching `Committed(uint256 tokenId, address minter)` log.

## Reveal (required)

A fresh BUST is **committed, not yet drawn**. Its traits are selected from a
block after the mint. Reveal each token ID with one of:

**A. Ask the app (no gas for you).** Once the mint is mined, call
```
POST https://farcon-rome-bust-project.vercel.app/api/bust/<tokenId>
```
for each ID. The project keeper finalizes it onchain and refreshes marketplace
metadata. The response's `status.phase` is `committed` or `finalized`, and
`status.blocksRemaining` shows the wait. Retry every ~5 s until `finalized`.
Once finalized, your NFT is revealed. `metadataRefreshed: true` means all
configured marketplace refresh requests were acknowledged; their display
caches can still take time to update. If it is false or absent, retry the same
POST after at least 65 seconds, up to four more times. A failing provider can
keep this flag false even when OpenSea has acknowledged its refresh, so stop
after those attempts and check the result links below. Never resend the mint.

Read-only status: `GET` the same URL (`404` means the app hasn't seen the mint
yet. Wait a few seconds and retry). Read-only GETs do not request a refresh.

**B. Finalize yourself.** At least 2 blocks after the mint, call
`finalize(uint256 tokenId)` (selector `0x05261aea`) or
`finalizeMany(uint256[] tokenIds)` (selector `0x40d86dca`) on BUST. Anyone may
call these. Estimate gas for the actual call; it varies with the selected
traits. Do it within ~250 blocks (~8 minutes) of the mint when you can.
Then request the app's POST above to refresh marketplace metadata.

Never mint again to "retry" a reveal. A pending BUST is safe onchain.

## Show the result

- In the app: `https://farcon-rome-bust-project.vercel.app/mint?tokenId=<id>&view=detail`
- Share page: `https://farcon-rome-bust-project.vercel.app/bust/<id>`
- OpenSea: `https://opensea.io/item/base/0xc267a12004855813b3718288b4ae0d90163D37D9/<id>`
  (may lag a few minutes behind the chain)
- Onchain: `tokenURI(id)` returns the full metadata and image as a data URI.

BUSTs belong to the wallet that minted them. If you mint from an agent-managed
wallet, tell your user which wallet holds their BUSTs.

## Collection facts

- Up to 1,111 BUSTs: ten reserved 1/1s (#0–#9), 69 voucher claims, 1,032 paid.
  One paid BUST (#10) was minted for contract validation before opening.
- The paid allocation can be permanently reduced or closed. It never reopens.
  Voucher claims stay open regardless.
- The contract picks the traits. No two procedural BUSTs share the same full
  composition. Procedural art and the trait registry are frozen.

## Errors you may see

`MintNotOpen`, `MintingClosed`, `PaidCapReached`, `InsufficientPayment` (value
too low; any excess is refunded), `InvalidQuantity` (batch outside 1–10),
`WalletCapInLaunchWindow` (over 10 paid in the first 48 h),
`NoVoucherBalance`, `VoucherNotApproved`,
`VoucherReserveExhausted`, `NotPending` (already revealed), `TooEarly` (finalize
before the entropy block).
