Lineagei
Frameworki
What's Anchor?
Batteries-included Rust framework. Ships account-validation codegen, 8-byte instruction discriminators, and an on-chain IDL — the program describes itself.
Bigger binary and higher rent in exchange for safety rails, introspection, and dev speed. The choice of a team optimizing for correctness over on-chain footprint.
Originally Coral (Armani Ferrante); now community-maintained.
What it is
The de facto standard. Rust macros (#[program], #[derive(Accounts)]) eliminate boilerplate: it auto-generates 8-byte account and instruction discriminators — SHA256("account:<Name>")[..8] and SHA256("global:<ix>")[..8] — handles Borsh (de)serialization, enforces account constraints declaratively (mut, has_one, seeds, init), and emits a JSON IDL that client libraries consume directly. The cost: Borsh copies data on every deserialize (not zero-copy), and the macro machinery adds binary bloat and compute overhead — irrelevant for ~99% of programs.
When to pick it
Building a new protocol, moving fast, or wanting maximum ecosystem compatibility. It's the beginner default and stays the right call for most production programs.
How it looks on-chain
The most recognizable framework. Every account it owns begins with an 8-byte discriminator, and the IDL is often published on-chain at a PDA derived from the program id. Both are strong, reliable fingerprints — this is the only framework we can label with confidence.
Others in the wild: Steel (Ore team — near-native performance on solana-program), Seahorse (Python → Anchor), and Poseidon & Quasar (TypeScript → Rust). Transpilers inherit their lowering target's fingerprint: a Quasar or Poseidon program that compiles down to Anchor will look like Anchor on-chain — discriminators and all.
Anchor docsFootprinti
Recovered architecturei
Reachi
Controli
What's upgrade authority?
The upgrade authority is the account allowed to replace a program's code after it's deployed.
If it's set (mutable), that key can push new bytecode at any time — including malicious code, the classic "rug" vector. If it's null (immutable / frozen), the code can never change; what 's on-chain is final. A Squads multisig sits in between — upgrades are possible but need M-of-N signers, not one hot wallet. So mutable + single hot-wallet = highest risk; immutable or multisig = stronger guarantees.
What's a verified build?
A verified build proves the program running on-chain was compiled from the public source you can read — nothing hidden.
Someone re-compiles the source in a deterministic (Docker) environment and checks the resulting bytecode is byte-for-byte identical to what's deployed; tools like solana-verify do this and record it with a verification service. "Not verified" isn't a red flag by itself — most programs simply never submit one. It just means you're trusting the deployed bytecode as-is, with no source cross-check.
Convictioni
Interface — the on-chain IDLi
12 of 27 instructions used · 15 never called in this window
Instructions 27
add_market_asset
- signersignerwritable
- marketwritable
- mint
- market_assetwritable
- vaultwritable
- system_program
- token_program
- associated_token_program
- rent
cancel_deposit
Refund a `DepositPlan` where no leg has executed yet. Closes the plan PDA and returns `deposit_amount` from `Market.base_asset_vault` to the depositor. Depositor-only — agent cannot force a refund.
- ownersignerwritable
- market
- planwritable
- base_vaultwritable
- base_mint
- owner_base_atawritable
- token_program
- nonceu64
cancel_withdraw
Refund a `WithdrawPlan` where no leg has executed yet. Closes the plan PDA only — no token movement (prepare_withdraw doesn't lock funds; shares stay intact on `Portfolio.shares`). Owner-only.
- ownersignerwritable
- market
- planwritable
- nonceu64
close_market
- marketwritable
- signersignerwritable
- global_state
- registry
close_portfolio
- ownersignerwritable
- market
- portfoliowritable
create_market
- signersignerwritable
- agentoptional
- registrywritable
- global_state
- marketwritable
- base_asset_mint
- base_asset_vaultwritable
- system_program
- token_program
- associated_token_program
- rent
- market_fee_bpsu16
- fee_asset_mintpubkey
- agent_identity_collectionOption<pubkey>
- market_metadata_uristring
create_portfolio
- ownersignerwritable
- market
- portfoliowritable
- system_program
deposit_leg
- signersigner
- depositor
- market
- planwritable
- base_vaultwritable
- base_mint
- token_program
- router_program
- nonceu64
- leg_indexu8
- routerRouter
- min_outu64
- router_payloadbytes
extend_deposit_deadline
Push a `DepositPlan`'s deadline forward. Depositor or `Market.agent` may call. Bounded extension; re-call for more. See `ix::portfolio::extend_deposit_deadline` for the rationale.
- signersigner
- market
- planwritable
- nonceu64
- new_deadlinei64
extend_withdraw_deadline
Push a `WithdrawPlan`'s deadline forward. Owner or `Market.agent` may call. Same bound as `extend_deposit_deadline`.
- signersigner
- market
- planwritable
- nonceu64
- new_deadlinei64
force_skip_deposit_leg
Admin-only. Marks a Pending `deposit_leg` as `Skipped` so the plan can settle when the leg's route is permanently broken. See `ix::portfolio::force_skip_leg` for the trade-off (skipped leg's base slice contributes to NAV; depositor still gets full shares).
- authoritysigner
- global_state
- market
- planwritable
- nonceu64
- leg_indexu8
force_skip_withdraw_leg
Admin-only. Force-skip a permanently-broken `withdraw_leg` so the user can settle. See `ix::portfolio::force_skip_leg` for the trade-off (user is short the leg's expected proceeds).
- authoritysigner
- global_state
- market
- planwritable
- nonceu64
- leg_indexu8
init_global_state
- authoritysignerwritable
- global_statewritable
- registrywritable
- fee_vault
- system_program
- platform_fee_bpsu16
init_portfolio_from_holdings
Agent-only one-shot ix for legacy-pool backfill. Initialises a Portfolio + credits the user with `initial_total_value` shares (1:1 with the assumed total NAV in base atomic units). Tokens must already be in the Market's vaults before this runs. Gated by `Market.total_shares == 0`.
- agentsignerwritable
- marketwritable
- user
- portfoliowritable
- system_program
- initial_total_valueu64
prepare_deposit
- ownersignerwritable
- global_state
- market
- portfolio
- base_mint
- base_vaultwritable
- owner_base_atawritable
- agent_fee_destwritable
- platform_fee_destwritable
- planwritable
- token_program
- system_program
- nonceu64
- deposit_amountu64
- deadlinei64
prepare_rebalance
- signersignerwritable
- market
- planwritable
- system_program
- nonceu64
- deadlinei64
- new_base_target_weight_bpsu16
- asset_targetsVec<AssetTarget>
prepare_withdraw
- ownersignerwritable
- market
- portfolio
- base_vault
- planwritable
- system_program
- nonceu64
- shares_to_burnu64
- deadlinei64
rebalance_leg
- signersigner
- global_state
- marketwritable
- planwritable
- base_vaultwritable
- base_mint
- fee_asset_mint
- fee_asset_token_program
- token_program
- router_program
- fee_router_program
- nonceu64
- leg_indexu8
- routerRouter
- directionu8
- amount_inu64
- min_outu64
- new_total_value_baseu64
- router_payloadbytes
- main_router_account_countu16
- fee_routerRouter
- fee_min_outu64
- fee_router_payloadbytes
recover_stuck_funds
- ownersignerwritable
- market
- portfolio
- mint
- portfolio_token_accountwritable
- owner_token_accountwritable
- token_program
remove_market_asset
- signersignerwritable
- global_state
- marketwritable
- mint
- base_mint
- fee_asset_mint
- fee_asset_token_program
- market_assetwritable
- vaultwritable
- base_vaultwritable
- signer_base_atawritable
- agent_fee_destinationwritable
- platform_fee_destinationwritable
- token_program
- router_program
- fee_router_program
- deadlinei64
- min_outu64
- routerRouter
- router_payloadbytes
- main_router_account_countu16
- fee_routerRouter
- fee_min_outu64
- fee_router_payloadbytes
settle_deposit
- signersigner
- depositorwritable
- marketwritable
- portfoliowritable
- planwritable
- nonceu64
settle_rebalance
- signersignerwritable
- marketwritable
- planwritable
- nonceu64
settle_withdraw
- signersigner
- ownerwritable
- global_state
- marketwritable
- portfoliowritable
- planwritable
- base_mint
- base_vaultwritable
- owner_base_atawritable
- agent_fee_destwritable
- platform_fee_destwritable
- token_program
- nonceu64
update_global_state
- authoritysigner
- global_statewritable
- new_global_configNewGlobalConfig
update_market
- signersignerwritable
- marketwritable
- global_state
- system_program
- new_fee_asset_mintOption<pubkey>
- new_market_fee_bpsOption<u16>
- new_agent_identity_collectionAgentIdentityCollectionUpdate
- new_metadata_uriOption<string>
update_nav
- signersigner
- marketwritable
- total_valueu64
withdraw_leg
- signersigner
- owner
- market
- planwritable
- base_vaultwritable
- base_mint
- token_program
- router_program
- nonceu64
- leg_indexu8
- routerRouter
- min_outu64
- router_payloadbytes
Accounts 8
DepositPlan
no fields
GlobalState
no fields
Market
no fields
MarketAsset
no fields
Portfolio
no fields
RebalancePlan
no fields
Registry
no fields
WithdrawPlan
no fields
Types 14
AgentIdentityCollectionUpdateenum
- NoChange
- Clear
- Set
AssetTargetstruct
- mintpubkey
- new_target_weight_bpsu16
AssetWithdrawSnapshotstruct
- mintpubkey
- amount_inu64
DepositPlanstruct
- marketpubkey
- depositorpubkey
- nonceu64
- deadlinei64
- deposit_amountu64Base-asset amount pulled into the market's base vault at prepare-time. Each leg consumes a fraction proportional to its asset's target weight.
- shares_to_mintu64Shares the depositor will receive at settle. Computed at prepare-time against the NAV cache; locked into the plan PDA so price drift between prepare and settle doesn't change the depositor's allocation.
- leg_statusVec<LegStatus>Per-leg execution state. Parallel to the market's registry walk at prepare-time. Length captured then so settle can verify the market hasn't grown/shrunk mid-deposit.
- bumpu8
GlobalStatestruct
- authoritypubkey
- fee_vaultpubkeyOwner of the platform-fee ATAs. The post-swap fee split transfer inside `rebalance_leg` deposits Avo's cut into an ATA whose `owner == fee_vault` and `mint == leg.output_mint`.
- platform_fee_bpsu16Avo's platform fee in basis points. Applied to the gross output of every swap leg by setting `platform_fee_bps = global.platform_fee_bps + market.market_fee_bps` on the router CPI; the program then splits the resulting referral-ATA balance into `fee_vault` and `market.agent` ATAs at the proportional ratio.
- registrypubkey
- bumpu8
LegStatusenum
- Pending
- Done
- Skipped
Marketstruct
- agentpubkey
- indexu16
- bumpu8
- base_asset_mintpubkey
- base_asset_vaultpubkey
- target_asset_countu8
- base_target_weight_bpsu16Target allocation weight for the base asset, in basis points. Sum of `base_target_weight_bps` + every `MarketAsset.target_weight_bps` for this market = 10_000. Maintained by `rebalance` zero-sum deltas.
- market_fee_bpsu16Market owner's fee in basis points. The total fee taken out of each swap leg is `global.platform_fee_bps + market.market_fee_bps`. The market owner ATA receives the `market_fee_bps` share. Capped at `10_000 - global.platform_fee_bps` on every write so the total never exceeds the bps universe.
- fee_asset_mintpubkeyMint in which platform + market fees are denominated. Per-leg fee destinations (`agent_fee_ata` + `platform_fee_ata`) must be ATAs in this mint. When a swap's output mint matches `fee_asset_mint`, the fee is withheld directly from the output. When it doesn't, the leg ix is expected to drive a secondary router CPI to convert the fee portion into `fee_asset_mint` — that mechanism lands in a follow-up to D3-P4.5; the field itself is set + persisted now so create_market + update flows can begin populating it.
- market_share_mintOption<pubkey>
- total_sharesu64
- last_total_valueu64Last computed total value in atomic units of base
- last_nav_tsi64Timestamp of last NAV update.
- prev_entrypubkeyDead field — kept only to preserve byte-layout compatibility with existing on-chain Market accounts. The intrusive registry linked list this belonged to was never wired up (`create_market` never populated it), so `close_market` no longer touches it. Always `Pubkey::default()`. Do not read.
- next_entrypubkeyDead field — see `prev_entry`. Always `Pubkey::default()`.
- agent_identity_collectionOption<pubkey>Optional MPL-8004 collection gate (Metaplex MPL Agent Registry, program id `1DREGFgysWYxLnRnKQnwrxnJQeSMk2HmGaC6whw2B2p`). When `Some`, `create_market` (and any future ix that rotates the agent) requires the agent to own a Metaplex Core asset whose update authority points at this collection — see `crate::auth::verify_agent_identity`. Identity is checked once at create-time; subsequent agent-signed ixs only re-check `market.agent == signer` (cheaper, and the NFT-ownership world model can't change without an off-chain transfer the operator is responsible for).
- market_metadata_uristringOff-chain metadata pointer for this market — typically an IPFS / Arweave / HTTPS URL to a JSON document describing the market's branding (name, description, image, asset thesis). Analogous to a Metaplex Core asset's `uri` field; serialised as a borsh `String` (4-byte LE length prefix + UTF-8 bytes), so the account size grows/shrinks with the URI. Use `update_market_metadata_uri` to mutate; it reallocs the account in-place. Cap: `MAX_METADATA_URI_LEN` bytes — a generous limit that still rejects pathological inputs. Distinct from `Agent.agent_uri` (off-chain): the agent URI is the MPL-8004 identity manifest pointer (per-agent); this is the per-market metadata pointer. An agent can operate multiple markets, each with its own metadata.
MarketAssetstruct
- marketpubkey
- mintpubkey
- vaultpubkeySPL token account owned by the Market PDA.
- last_known_balanceu64Cached vault balance, updated on every swap leg.
- target_weight_bpsu16Target allocation weight for this asset, in basis points. Sum across all MarketAssets + Market.base_target_weight_bps = 10_000. Adjusted only by `rebalance` (zero-sum delta with the swap counterpart).
- bumpu8
NewGlobalConfigstruct
- authorityOption<pubkey>
- platform_fee_bpsOption<u16>New platform fee in basis points. Caller must keep `platform_fee_bps + max(market.market_fee_bps for any market) <= 10_000` off-chain — we can't enforce per-market caps from here without iterating the registry. `update_market_fee` re-validates per market.
- fee_vaultOption<pubkey>
Portfoliostruct
- ownerpubkey
- marketpubkey
- sharesu64
- bumpu8
RebalancePlanstruct
- marketpubkey
- agentpubkey
- nonceu64
- deadlinei64
- new_base_target_weight_bpsu16New base-asset target weight (bps). Written into the Market by `settle_rebalance`, not by individual legs — keeps the Market's `base_target_weight_bps` consistent until the whole plan lands.
- asset_targetsVec<AssetTarget>Per-asset targets, parallel to `leg_status`.
- leg_statusVec<LegStatus>Per-leg execution state. `rebalance_leg(idx)` advances entry `idx`.
- bumpu8
Registrystruct
- head_entrypubkeyDead field — kept only to preserve byte-layout compatibility with the existing on-chain Registry account. The linked-list wiring was never populated; `close_market` no longer touches it. Always `Pubkey::default()` on new inits. Do not read.
- tail_entrypubkeyDead field — see `head_entry`. Always `Pubkey::default()`.
- lenu16Monotonic count of markets ever created. Doubles as the index assigned to the next market — Market PDA seed is `[b"market", &index.to_le_bytes()]`. Never decremented; closing a market leaves a gap in the index space rather than recycling the id (recycling would collide with a fresh PDA at the same seed).
- bumpu8
Routerenum
- Jupiter
- Dflow
WithdrawPlanstruct
- marketpubkey
- ownerpubkey
- nonceu64
- deadlinei64
- shares_to_burnu64Shares to burn at settle. Locked at prepare so concurrent share movements (theoretical — `Portfolio.shares` only changes via deposit/withdraw, which are serialized per-owner) can't drift the withdraw amount mid-flight.
- base_pro_ratau64Snapshot of the user's pro-rata claim on the market's base vault (`shares_to_burn × base_vault_balance / total_shares`). Paid out at settle alongside `accumulated_swap_proceeds`.
- accumulated_swap_proceedsu64Running total of swap net-of-fee proceeds (in base mint units), accumulated as each `withdraw_leg` lands. Fresh at prepare = 0. Paid out to the owner at settle alongside `base_pro_rata`.
- per_assetVec<AssetWithdrawSnapshot>Snapshot of the user's pro-rata claim on each registered MarketAsset (`shares_to_burn × ma.last_known_balance / total_shares`), captured at prepare. Each leg liquidates exactly `amount_in` of its `mint` to base.
- leg_statusVec<LegStatus>Per-leg execution state. Same length as `per_asset`.
- bumpu8
Errors 42
- 6000InvalidAuthorityInvalid authority
- 6001InvalidPdaDataInvalid PDA data
- 6002InvalidAccountListReceived more accounts than expected
- 6003MathOverflowArithmetic overflow
- 6004InsufficientSharesInsufficient shares
- 6005ZeroDepositDeposit amount must be greater than zero
- 6006DegenerateMarketStateCannot deposit when total_shares > 0 and last_total_value == 0
- 6007StaleNavNAV is stale; agent must call update_nav before deposit
- 6008NavTimestampRegressionAttested NAV timestamp must be monotonic
- 6009MarketAssetMismatchMarketAsset does not belong to this market
- 6010MintMismatchMint does not match the MarketAsset
- 6011VaultMismatchVault does not match the MarketAsset
- 6012DuplicateAssetAsset is already registered to this market
- 6013AssetNotEmptyCannot remove an asset with non-zero balance
- 6014SlippageExceededSlippage / minimum-out check failed
- 6015WeightDeltaUnderflowWeight delta would underflow the input asset's target weight
- 6016WeightDeltaOverflowWeight delta would overflow the output asset's target weight
- 6017WeightSumInvariantSum of base + per-leg target weights must equal 10_000
- 6018InvalidDirectionRebalance leg direction must be 0 (buy) or 1 (sell)
- 6019LegCountMismatchNumber of legs does not match market.target_asset_count
- 6020FeeDestinationMintMismatchFee destination mint must match the swap output mint
- 6021AgentFeeDestinationMismatchAgent fee destination must be owned by market.agent
- 6022PlatformFeeDestinationMismatchPlatform fee destination must be owned by global_state.fee_vault
- 6023InvalidFeeBpsplatform_fee_bps + market_fee_bps must be <= 10_000
- 6024InvalidAgentShareBpslegacy: agent_share_bps must be <= 10_000
- 6025DeadlinePassedTransaction deadline has passed
- 6026BaseInputVaultMismatchInput vault must equal market.base_asset_vault when no input MarketAsset is supplied
- 6027BaseOutputVaultMismatchOutput vault must equal market.base_asset_vault when no output MarketAsset is supplied
- 6028AmountInMismatchJupiter consumed a different amount than declared in amount_in
- 6029RouterProgramMismatchRouter program account does not match the program id expected for the chosen Router variant
- 6030LegAlreadyRunLeg has already been executed; cannot run twice
- 6031LegNotDoneCannot settle: at least one leg is still Pending
- 6032LegAssetMismatchLeg's MarketAsset does not match the mint recorded in the plan
- 6033NavDeltaExceededNAV delta from previous cached value exceeds MAX_NAV_DELTA_BPS
- 6034FeeConversionRequiredFee-conversion context required: output_mint != fee_asset_mint
- 6035FeeConversionUnexpectedFee-conversion context provided but output_mint == fee_asset_mint
- 6036MarketAlreadyInitializedinit_portfolio_from_holdings is only allowed on a market with total_shares == 0
- 6037AgentIdentityRequiredMarket has agent_identity_collection set but no identity account was supplied
- 6038InvalidCoreAssetIdentity account is not a Metaplex Core asset (wrong discriminator or too small)
- 6039CoreAssetOwnerMismatchCore asset's on-chain owner does not match market.agent
- 6040CoreAssetCollectionMismatchCore asset's update authority does not point at the expected collection
- 6041MetadataUriTooLongmarket_metadata_uri exceeds Market::MAX_METADATA_URI_LEN
What's an IDL?
An IDL — Interface Description Language — is a JSON spec that describes how to talk to a program: its instructions, the accounts each one needs, argument and account types, events, and errors.
Anchor auto-generates it at build time. A program can publish it on-chain at a PDA derived from its id, so any client or explorer can decode the program's transactions without its source code.
Why it's often missing
Publishing is opt-in — a courtesy, not a requirement. Many programs never do, and non-Anchor frameworks (Pinocchio, native, Steel) don't produce one at all; their interface lives in an off-chain Shank/Codama artifact, or nowhere public. Absence means you can't auto-decode it — not that anything is wrong.
12 of 27 instructions used · 15 never called in this window · +9 more
Tractioni
Code familyi
The recordi
| Event | When | Detail | Receipt |
|---|---|---|---|
| SIBLING DEPLOY | 2d ago | packs_mining | same code, fresh id |
| UPGRADE | 2d ago | slot 432,113,409 | poll…3409 |
| UPGRADE | 2d ago | slot 432,112,802 | poll…2802 |
| DEPLOY | 3d ago | slot 432,065,265 | poll…5265 |
| SIBLING DEPLOY | 3d ago | Collateral Program | same code, fresh id |