Quickstart
Validator, deploy, registry, prices, a demo market and the app, in one command.
Everything below runs against a throwaway local validator. Nothing here touches a public cluster.
The default Solana ports are occupied on the machine this was built on, so
every script owns the validator lifecycle itself on 9020 / 8760 / 9910 and
only ever reaps a validator on its own RPC port. If you run other validators,
check that block is free before you start: lsof -ti :9020.
The whole stack, one command
anchor build
This is also what writes target/idl/*.json, which the relayer and the
reference pages both read.
./scripts/test.sh # 157 passing on 2026-08-25
A fresh ledger every run. State carries over otherwise and every init
instruction fails with "already in use".
./scripts/dev.sh # then http://localhost:3111
Validator, deploy, registry, one relayer cycle for prices, a demo market with holders and fees, and the app. Ctrl-C tears it all down.
The order in that script is not arbitrary. The seeder needs the program, the relayer needs the registry, and the demo needs a price. A pairable with no price cannot settle anything, so a market created before the relayer runs would be inert.
scripts/demo.ts launches $PEAR against the pear pairable with three holders
of very different sizes and five rounds of fees, so the pro-rata split is
visibly doing something. Passing --history writes a synthetic seasonal pear
series so the chart has a shape before the relayer has run for a year, and the
market page prints SYNTHETIC beside the print count.
The pieces, separately
./scripts/localnet.sh # validator + deploy + seed, then tear down
./scripts/localnet.sh --hold # same, but leave it up until Ctrl-C
cd relayer && npm install
npm test # 296 passing on 2026-08-25, offline
npm run probe # read every provider, touch no cluster
npm run once # one real cycle against the localnet
npm run verify-mints # re-check the pinned hard-grade mints
npm run sync-badges # --write to correct drifted provider counts
cd relayer
npm run sweep # claim pool fees, then credit every market
npm run crank # sync each perp's index and charge funding
npm run convert:dry # quote every native market's inbox, print the edge
npx ts-node scripts/launch.ts --all --dry # every entry, with reasons
npx ts-node scripts/launch.ts --id BTC # one market, for real
What a full local run does not price
A full cycle pushes most of the registry. The ones that do not are worth knowing
about, because an unbound pairable and a working one look identical in the UI
until somebody tries to trade against it, which is why the relayer reports
UNBOUND on every cycle rather than skipping quietly.
- Honestly unbound: NYC month-to-date rainfall, the Ethereum base fee, and
the Mad Lads floor. The last one wants
floorlaunch's Tensor and Magic Eden ladder pipeline lifted across. SOL-STAKE-APYholds on a fresh localnet, because nothing is staked there yet.- Every hard entry, on devnet, because the pinned mints are mainnet
addresses.
scripts/launch.tscalls that the honest answer rather than a fault.
After a fresh deploy, rotate the authorities
scripts/seed.ts points admin, oracle and fulfilment authority all at the
deployer. That is convenient and it is also a single point of total compromise:
the oracle signs the index that decides who gets liquidated on every perp, the
admin can change the rules, and on a fresh deploy they are the same key that
holds program upgrade authority. One leak is all three.
npx ts-node scripts/rotate-authorities.ts --oracle <path> --fulfillment <path>
The admin is rotated last and only when explicitly asked for, because the admin is what authorises the instruction. Hand it to a key you got wrong and there is no second attempt. Everything else is rotated while the original admin still holds the pen, so a mistake there is recoverable by running the script again.
See Key management for what each key is actually for.
Re-running the seeder
scripts/seed.ts is idempotent: a pairable whose PDA already exists is skipped
rather than failing the run, so it is safe to re-run after adding entries. It
registers only. Prices come from the relayer, so a half-seeded registry is inert
rather than dangerous.
peard