peard
Standing behind it

Backing by real things

peard_vault holds NFTs and nothing else. Live on devnet, backing one pool, and pinned three ways.


Live on devnet since 26 August 2026, and holding one reserve. That reserve issues the receipt that a real pool quotes in, and the pool names the reserve on its own account. Both are linked at the bottom of this page.

What is still true: peard's init_global leaves Global.backing_program at Pubkey::default() until governance pins it, so a market's backing_value stays zero until somebody does. The pool-level backing below does not depend on that pin, because it is a different join and is checked differently.

A pairable is a type. An NFT is an instance.

"A pear" is a type. 40 cartons of D'Anjou 80s, bought 14 September at $48, CA storage in Wenatchee, expires 15 May is an instance. Pears bought in September and pears bought in March share a name and nothing else, and no registry row can be true of both.

Every variable that decides value lives on the batch: quantity, cost basis, acquisition date, expiry, carry, haircut, appraiser, custodian.

The core values nothing itself

ItemKind is metadata and no instruction branches on it, exactly as Resolver never dispatches in peard and Delivery never dispatches in the fulfilment valve.

That is the only way "support every type" is tractable instead of becoming a growing switch statement inside a deployed program: adding graded cards or service vouchers is writing an appraiser, not editing this.

ItemKindWhat it is
PerishableLota quantity of something that spoils. Shrinks, then stops existing
DurableLota quantity of something that does not. Metal, bags of rice, fuel
Collectibleone graded, unique object. No clock, a floor price, and a spread
Vouchera claim on a service, good until it is not
Tokenizeda position in something already tokenised, held here for custody
Othervalued entirely by whoever appraises it

Four decisions worth defending

Carry is charged against the appraised value rather than cost, because what it costs to store a thing tracks what the thing is worth far better than what somebody paid for it a season ago.

The join is an address and a hand parse

peard_vault publishes a Backing account: magic, version, value, cost basis, item count, and as_of_ts. Tiny, frozen, and seeded by the market alone, so a reader derives it rather than being handed it.

It is written in exactly one place, close_epoch, which is precisely when every held item is known to be current.

pub const BACKING_MAGIC: u64 = 0x4241_434b_494e_4731; // "BACKING1"
pub const BACKING_VERSION: u8 = 1;

peard's sync_backing is permissionless and guarded by two pins: governance pins which program may vouch, and the market pins which account. Then the magic, the version, and the market named inside the attestation all have to agree.

The layout is mirrored in peard rather than imported. A build dependency would make the two programs upgrade together, and that is precisely the coupling the attestation exists to avoid. The magic and version are what turn a wrong or moved account into a loud failure instead of plausible nonsense parsed out of somebody else's bytes.

peard_perps reads the same format the same way, and pins it three times: the program that owns the account, the address the market names, and the market the attestation names back.

The backing is on the pool, not beside it

A backing somebody has to be told about is one most people will never check. So peard_amm's Pool carries the reserve on its own account:

/// The peard_vault reserve whose receipt this pool's quote leg IS, or
/// default for a pool with nothing behind it.
pub backing_reserve: Pubkey,

One account read, and a reader knows what stands behind the token they are about to buy. They do not have to know a second program exists, or which account in it to look up.

It is a fact, not a claim

attach_backing refuses unless the reserve's own receipt_mint is this pool's quote_mint. A pool cannot point at a warehouse that does not issue the token it trades.

1
The pool must not already be backed

One-way and immutable, for the same reason fee_claimer is. A backing somebody can repoint is a story rather than a guarantee.

2
The account must be owned by peard_vault

An owner constraint, which pins the program but says nothing about type.

3
Its discriminator must be Reserve

Owner plus length is not a type check. peard_vault owns several kinds of account and so does peard; only the discriminator separates them.

4
Its receipt_mint must be the pool's quote_mint

The join, and the only one of the four that makes the field mean anything. Without it the pool is a pointer at an unrelated warehouse.

What it does not do

It is 32 bytes of pubkey in the account's data. There is no vault behind it and no instruction moves it. buy and sell touch exactly two token accounts, base_vault and quote_vault, and the swap arithmetic never reads the field. It is a label on the jar, not something in the jar.

A backed pool holds no USDC. Its quote leg is the receipt, so the price it quotes is "this token, in crates", and buying requires already holding receipts. Instant tradeability and a redeemable quote leg pull in opposite directions, and a USDC-quoted pool is a separate build.

Appending to Pool, and why the field is last

backing_reserve sits at the very end of the struct, and nothing may be added above it. Borsh carries no field names on the wire, so a field inserted anywhere but the end shifts every field after it.

This was not theoretical. The field was first declared in the middle, and when migrate_pool grew the two pools already on devnet, both decoded their own fee_bps, decimals and bump as the first five bytes of the new pubkey and read zeroes as their fee. Nothing errored. The migration reported success on both. It was caught because the migration printed a backing address where 11111111111111111111111111111111 belonged.

Cash coverage and total coverage are different numbers

holder_usdc still bounds every payout. Backing only counts in total_coverage.

Pears in a warehouse do not pay dollars until somebody sells them, so folding them into the ratio that governs USDC claims would let a market read fully covered while holding no money. That is the same overstatement as counting the protocol's own accrued cut.

Appraisers live outside

relayer/src/appraise.ts is pure and offline-tested.

KindFormula
Perishable lotquantity x index x (1 - shrink x days)
Collectiblea floor, less what it costs to actually sell
Voucherface value, less the odds nobody honours it

Shrink is an appraisal input rather than on-chain state, because two lots of the same fruit in different rooms shrink at different rates and neither the program nor the registry should have an opinion.

It refuses rather than guesses, and a sanity band against cost basis catches a units error before the on-chain breaker has to. A units error looks exactly like a hundredfold rally and only one of them is real.

Not built

  • Fractional redemption. A holder owed 3.7 pears cannot be handed part of a deed, so that path settles in USDC at appraisal and does not exist yet.
  • Custodian limits. Nothing bounds how much a single custodian may hold.
  • The bond, which is a field rather than a mechanism.
  • Anything actually in the warehouse. The devnet reserve below holds zero items and has issued zero receipts. Every mechanism around it is live and exercised; what is missing is somebody buying the pears and renting the cold storage. A reserve holding nothing backs nothing, and the page says so rather than letting the presence of an account imply otherwise.
  • A USDC-quoted pool with a declared backing. See the warning above: today a backed pool's quote leg is the receipt itself.

Look at it

Devnet, 26 August 2026. The pool's backingReserve is the reserve, and the reserve's receiptMint is the pool's own quoteMint.

Both programs have their IDL published on devnet, so an explorer renders those as named fields rather than base64. scripts/devnet-backed-pool.ts builds the whole thing from nothing and prints the two links.