Skip to main content

Build a vault

A new vault implements the trait, proves on a mainnet fork that its quotes match its swaps, and is registered before Charisma's router uses it.

Checklist​

MustWhy
(impl-trait 'SP2ZNGJ85ENDY6QRHQ5P2D4FXKGZWCKTB2T0Z55KS.dexterity-traits-v0.liquidity-pool-trait)Routers call execute; dexterity-sdk prices with quote
Dispatch on byte 0 and return an error for anything elsenone reads as 0x00
Move tokens to and from tx-senderIt is the user under multihop and the router under x-multihop-v1
quote reads the same live state execute usesA quote that ignores pool state invents prices
quote equals execute at every size, both directionsPost-conditions are built from quotes
Pools answer quote(0, 0x04)The reserves refresh reads it
get-name, get-symbol, get-decimals, get-token-uriRegistration and the token list read them

Fork-simulate first​

Never call a route profitable until it has been fork-simulated

A listed vault once quoted a fixed 1:1 rate instead of reading its pool. The router saw a +51% STX-to-STX loop, and the real swap aborted on post-conditions. That vault is now block-listed.

Test on a simnet fork of mainnet (the Clarinet SDK with remote data), with a real mainnet wallet as the sender. Devnet addresses fail mainnet is-standard checks.

  • Compare quote with the real swap from tiny to large sizes, both directions. They must be equal.
  • Swap through both routers, alone and next to a deep Charisma pool, with deny-mode post-conditions built the way each SDK builds them.
  • Measure the quote's read cost. Hiro's public read-only API caps read length at 500 KB, so a quote that makes many external calls can fail over the API even when the swap works on-chain.

Register it​

StepWhereWhat
MetadataPOST https://metadata.charisma.rocks/api/v1/metadata/<contractId>Name, symbol and image, signed by the deployer
ConfirmThe Import button on Invest's /pools page, or POST https://invest.charisma.rocks/api/v1/admin/vaults/<contractId>/confirmAdmin only, with a signed dex-cache-admin-access message. Sends type, protocol, tokenA and tokenB in opcode order, externalPoolId, the fee as lpRebatePercent, and stxWrapper or forwardsInputFee when needed
Reserves/api/cron/update-reserves, every 10 minutesCalls quote(0, 0x04). If that fails, reads the token balances of externalPoolId, or of the vault
RoutingSwap reloads its vault list every 10 minutesThe vault starts appearing in /quote hops

A vault that misbehaves is block-listed, which drops it from /vaults and from routing.