Protocol

The mechanism in detail.

Permanent Collection moves through three motions. Trading feeds a live bid. An eligible Punk accepts. A 72-hour return auction decides whether the Punk returns to circulation or enters the vault. This page walks through each motion, the contracts behind them, and the invariants that make the work durable.

Architecture

Permanent Collection sits on top of the artcoins protocol. Artcoins handles the token deploy, the V4 pool, the hook, the LP locker, and the MEV module. PC adds the live bid, the return auction, the vault, and the rendering stack that turns vault state into on-chain art. PunksData is the sealed external source for trait names and pixel data; Punks is the canonical 2017 market where vaulted Punks actually live, at PunkVault's address.

ArtCoinsFactorydeploys + binds, owner-only$111ERC20 artcointokenURI renders the workV4 Pool$111 / ETH0.5% LP + 6% skimHook + MEVHookSkimFee + LinearSkimanti-sniper windowLocker + EscrowLpLockerFeeConversionFeeEscrow buffers claimsFee adaptersLiveBid · ProtocolFee · ReferralPatronlive-bid ETH hubacceptBid / acceptListingReturnAuctionModule72-hour auctioncleared or vaultedPunkVaultimmutable custodyERC721 issuer (Title + Proofs)acceptsettlePunkVault NFTsTitle + 111 ProofsRendererRegistrystable front addressMosaicRendererTitle + ProofRendererCachesPunkSvg + TraitIconPunks marketcanonical 2017 contractvaulted Punks live at PunkVault addressPunksDatasealed, canonicaltrait names + per-Punk pixelsholds Punksreads trait data
Architecture: $111 and the trading infrastructure deploy from the artcoins factory; PC adds the live bid (Patron), the return auction (ReturnAuctionModule), the vault (PunkVault), and the renderer stack; the bottom band is the external read-only contracts everything else depends on.
The official pool

$111 pairs with native ETH in a Uniswap V4 pool. Total fee on every swap is 6.5%: 0.5% is the V4 LP fee paid to liquidity providers via the standard mechanism, plus 6% is a baseline skim the hook splits inside the same transaction. The split happens before the user sees the result; there's no separate router and no off-chain collection.

At launch the LP fee also feeds the live bid: a conversion locker holds 100% of LP positions and routes its single reward slot to LiveBidAdapter. The recipient slot is admin-locked to a dead address so it can't be redirected. Public LPs can mint positions after the anti-sniper window and earn their pro-rata share alongside the locker.

For the first ~30.000000000000004 minutes after launch, the pool runs an anti-sniper window. The fee starts at 90% and decays linearly to 6% at 2.8% per minute. Everything above the 6% baseline routes 100% to the live bid; the baseline split below is what runs forever.

Fee routing

Of the 6% baseline skim, three legs route inside the same swap through dedicated adapters, each to a fixed destination from block one. The bid leg routes to Patron (the live bid). The protocol leg routes to PCController. The referral leg, when a swap carries an attribution payload, routes a thin slice from the protocol leg to the named referrer.

Pool + Hook6% per swap5%1%up to 0.25%LiveBidAdapterProtocolFeePhaseAdapterReferralPayoutPatronlive bidPCControllerPC treasury + $LAYER burnReferrerattributed swaps
Fee routing: the 6% baseline skim splits into three legs inside the hook on every swap, each to a fixed destination from block one — the bid leg to Patron, the protocol leg to PCController, the referral leg to the named referrer on attributed swaps. The separate 0.5% V4 LP fee (not shown) is paid to LP holders; at launch the conversion locker routes its share to the live bid too.
  • 5% → LiveBidAdapter: always routes to Patron (the live bid). The adapter meters it in two modes: below an activation threshold it fills the bid fast (the launch warm-up); above it a rate cap throttles, so a single big swap can't flood the bid in one block
  • 1% → ProtocolFeePhaseAdapter: sweeps to PCController from block one, which splits 86.67% to the PC treasury and 13.33% to the $LAYER buy-and-burn
  • Up to 0.25% → ReferralPayout: if a swap carries a PCAttribution payload, a thin slice routes from the protocol leg to the named referrer, from the first swap. The referrer pulls from a per-address ledger. With no referrer the slice stays in the protocol leg
  • 0.5% LP fee → liquidity providers: paid via V4's standard mechanism, not the hook. At launch the conversion locker holds 100% of LP positions and forwards its share to LiveBidAdapter, so the LP fee effectively joins the live bid until public LPs add depth
The live bid

Patron holds the live bid as native ETH. Its balance is the bid: there's no separate accounting variable. The number on the homepage is address(patron).balance.

Any address can top up the live bid by sending ETH to the LiveBidAdapter, which meters it into Patron. To accept the bid, the owner of an eligible Punk first lists it exclusively to Patron at a price at or below the live bid (the frontend defaults to the full bid), then anyone can finalize the acceptance by calling acceptBid. Anyone can call acceptListing against an allowlisted listing contract (see below).

Patron buys the Punk at the listed price, so the canonical 2017 market pays the seller: the proceeds queue in the market's pendingWithdrawals and the seller collects them with withdraw(). The Punk transfers to ReturnAuctionEscrow and the 72-hour return auction opens.

Listings from other protocols

Some Punks sit inside autonomous protocols rather than at an owner's wallet. PunkStrategy (PNKSTR) is the canonical example: it buys floor Punks and immediately re-lists them at 1.2× cost on the 2017 Punks market; when one of those listings sells, PunkStrategy uses the proceeds to buy and burn PNKSTR. The Punks pass through the contract on a fixed-flow yoyo.

Permanent Collection has a custom path for protocols like this: any address can call acceptListing against an allowlisted listing contract whose published price is at or below the live bid, bridging the trade in one transaction. PunkStrategy receives its 1.2× and triggers its own buy-and-burn cycle; PC takes custody of the Punk and opens the same 72-hour return auction. Both protocols' cycles complete on the same swap.

The caller earns a small finder fee — a share of the live-bid balance, not the listing price: 0.5% of the live bid, hard-capped at 0.01 ETH. The acceptListing path only opens once the live bid is at least 0.5 ETH.

At launch the allowlist seeds PunkStrategy only. Patron.addAllowedSeller stays editable past the protocol's 1-year admin auto-lock (one of the three scoped carve-outs) so new peer protocols can be registered as they emerge. Any contract that lists Punks via the canonical 2017 market's offerPunkForSale surface is eligible; the allowlist gates which ones PC is willing to source from. The mechanism on the caller side is permissionless.

The return auction

Once a Punk is in escrow, anyone can bid above the reserve to return it to circulation. The reserve is set at acceptance time from the acquisition cost and the number of times the protocol has already tried for that trait: cost × (101 + previousAttempts) / 100, rounded up. First attempt for a trait reserves at 1.01× cost; each subsequent attempt against the same trait adds 1%.

Bids in the last 15 minutes extend the auction by 1 hour. There is no cap on extensions. The auction either clears (a bid lands above the reserve) or it doesn't.

T = 0acceptBidT = 72hdeadlinePunk → escrowcost paid to ownerAuction endscleared or silencedbid above the reserve clears (15min anti-snipe extends +1h)Clearedbid above reservePunk → buyerSilencedno bid by deadlinePunk → PunkVault65% cost → Patron25% cost → BuybackBurner10% cost + premium → vault burn poolchosen trait → permanentProof mints to sellervault burn pool sweeps in
Return auction lifecycle: 72 hours from acceptance to settle. A bid above the reserve clears the auction; no bid sends the Punk to the vault and locks the chosen trait as permanent. Any premium the cleared bid carries above cost queues in the vault burn pool and flushes to BuybackBurner on the next vaulted settle.

On clear, the high bidder takes the Punk. The acquisition cost splits three ways: 65% refills the live bid via Patron, 25% buys back and burns $111 via BuybackBurner, and 10% goes to the vault burn pool. Any premium the high bid carries above cost also routes to the vault burn pool — minus up to 5% of that premium to the winning bid's referrer, if one is attributed. The vault burn pool sweeps to BuybackBurner on the next vaulted settle.

On silence (no bid by the deadline), the Punk transfers to PunkVault. The chosen trait flips from pending to permanent on PermanentCollection. A Proof NFT mints to the original seller. The vault burn pool sweeps on the same settle, feeding any accumulated premium into the buyback.

The vault

PunkVault is the immutable custody contract. It has no transfer, withdraw, rescue, or sweep selector. This is asserted at the bytecode level: the deployed contract's selector table is scanned by a fork test that fails if any market-write or admin-exit pattern appears.

The vault is also the issuer of 112 named tokens. Token id 111 is the Vault Title, auctioned through PunkVaultTitleAuction once 11 of 111 traits are collected. Token ids 0..110 are the 111 Proofs, one per trait, minted on first-vaulting to the original seller. The Title and the Proofs are ERC721 and freely transferable; the Punks themselves are not ERC721 and live at the canonical 2017 Punks contract.

Title grants no withdrawal rights, no admin control, no governance, and no claim on the Punks. It's a stewardship record, named in the contract for display purposes only.

Records

Every acceptance appends a row to PermanentCollection.Acquisition[]. The log records the Punk id, the chosen trait, the pending-mask snapshot at acquisition, the acquirer, the original seller, the price paid, and the block. Rows never delete and never reorder. Custody on each row moves forward only: from InReturnAuction to either ReturnedToMarket or Vaulted, then freezes.

Acquisition isn't the same as collection. The trait bitmap (collectedMask) only flips a bit when a Punk actually enters the vault carrying that trait, and only for the recorded target trait, not for every uncollected bit on the Punk's mask.

Proofs encode that record as art. Each Proof carries the Punk id, the trait id, the sequence (Nth Proof minted), and the vault-settle block. The metadata is frozen at mint time and survives transfer.

Composability

Two builder surfaces are live from day one:

  • Attribution: every swap can carry a sourceId and referrer field via hookData. The official hook emits a SwapAttribution event for every attributed swap. Permissionless, no allowlist
  • Referral fee: up to 0.25% of swap volume can flow to the referrer on every attributed swap, pulled from the protocol slice. The live bid stays structurally untouched
Contracts

The full system is below. Addresses fill in here once the protocol deploys to mainnet.

Permanent core

  • PermanentCollectionAppend-only acquisition log and the collected-trait bitmap. No funds, no Punks
  • PatronLive-bid ETH hub. Entry point for acceptBid and acceptListing
  • ReturnAuctionModule72-hour return auction. Settles cleared or vaulted
  • ReturnAuctionEscrowSettlement escrow tied to ReturnAuctionModule by construction
  • PunkVaultImmutable custody. ERC721 issuer for the Title and the 111 Proofs
  • BuybackBurnerPaced buy-and-burn of $111 from cleared-auction revenue and vault-burn-pool sweeps
  • VaultBurnPoolAccumulator for the auction premium above cost. Flushes to BuybackBurner on every vaulted settle
  • ProtocolAdmin1-year auto-locking admin role over a handful of economic parameters

Fee adapters

  • LiveBidAdapter5% bid leg plus the LP fee. Sweeps 100% to Patron
  • ProtocolFeePhaseAdapter1% protocol leg. Sweeps to PCController from block 1, which splits 86.67% to the PC treasury and 13.33% to the LAYER burn
  • ReferralPayoutPer-address pull ledger for the referral slice

Composability and admin

  • PCSwapContextTransient-storage reentrancy registry shared across PC contracts
  • TokenAdminPokerHolds the $111 tokenAdmin role. Exposes the bind-extension safety valve

Renderer

  • PermanentCollectionMosaicRendererRenders the Title (token 111) and dispatches Proof renders to the Proof renderer
  • PermanentCollectionProofRendererPer-Proof renderer for token ids 0..110
  • RendererRegistryStable address fronting the live renderer. Swappable until frozen
  • PunkVaultTitleAuctionKickoff plus auction for the Vault Title once 11 traits are collected
Invariants

These are the durability claims the protocol holds. Each is enforced at the bytecode level (selector scans) or via the adversarial fork test suite. None of them can be loosened without a redeploy:

  • collectedMask is monotonically increasing. Bits never unset
  • Acquisition[] only grows. Rows never delete or reorder; only the custody field mutates forward
  • Custody transitions are strictly InReturnAuction → ReturnedToMarket | Vaulted, then frozen
  • Acquisition does not imply collection. recordAcquisition never touches collectedMask; only markCustody(Vaulted) does
  • Vaulted collects only the recorded target trait, not every uncollected bit on the Punk's mask
  • No Punk can leave PunkVault or PermanentCollection. Neither contract holds a Punks market-write selector
  • The cleared-path proceeds split is hard-coded: CLEARED_BID_BPS = 6500. No setter, no admin override
  • bidBalance == address(patron).balance. No separate accounting variable; the balance is the bid
  • Token holders have no governance over the protocol
  • The 6% baseline skim split is enforced at swap-time inside the hook, not collected post-hoc
Protocol · Permanent Collection · Permanent Collection