Off-chain code
This layer builds, checks, signs, and sends the transactions that call the Sickle program, and it tests the program from the outside.
Note: Every path:line below is relative to the repository root. Nothing
in this layer links the Rust crate. Every module reads the program through the
Anchor IDL.
management-ui/ is a legacy compatibility tree, not the application serving
so.vf.at; vfat-io/sickle-sol-ui owns that surface and its deployment. The
legacy tree cannot yet be deleted because both Meteora canary adapters bundle
its action builder and preparation modules
(deploy/meteora-keeper/meteora-canary-adapter.ts:20-21,
deploy/meteora-keeper/meteora-ui-acceptance-adapter.ts:27-28), and root tests
consume its IDL and fixtures. Treat its routes and pages as retirement scope,
not as the target for a live UI fix.
Files
The layer has 5 parts. The tables below give one row per file. The last column says whether the file is pure or whether it touches RPC, an HTTP API, a signer, or the process environment.
Builder: scripts/builder/, shared timing
| Path | Lines | Purpose | Pure or I/O |
|---|---|---|---|
shared/intent-timing.ts | 8 | Authorization validity, quote age, and pre-expiry send margin | pure |
scripts/builder/pdas.ts | 251 | Seeds, program IDs, and every PDA and ATA derivation | pure |
scripts/builder/common-accounts.ts | 120 | Shared pool-token, fee-collector, intent, event, and account-coder primitives | pure |
scripts/builder/protocol-account.ts | 7 | Shared foreign-account decode error | pure |
scripts/builder/accounts.ts | 1036 | Orca and authorization account maps in Anchor camelCase | pure |
scripts/builder/instructions.ts | 943 | Anchor .instruction() wrappers for Orca, swap, and authorization instructions | pure, plus 2 RPC helpers for ATAs |
scripts/builder/orca.ts | 905 | Orca account decoders, tick math, tick-array PDAs, placement formula | pure |
scripts/builder/liquidity.ts | 163 | Q64.64 sqrt-price and liquidity math | pure |
scripts/builder/zap.ts | 135 | Sizes an add-liquidity instruction from two balances | pure |
scripts/builder/fees.ts | 38 | Fee index constants and floor fee math | pure |
scripts/builder/transfer-fees.ts | 159 | Token-2022 transfer-fee math and schedule load | pure, plus 1 RPC loader |
scripts/builder/jupiter.ts | 400 | Swap planner, route ceilings, Jupiter JSON to instruction | pure |
scripts/builder/jupiter-api.ts | 191 | HTTP client for Jupiter /quote and /swap-instructions | HTTP API |
scripts/builder/clmm-owner-rebalance.ts | 230 | Shared CLMM owner drain, optional swap, and re-add pipeline | RPC config and optional quote |
scripts/builder/clmm-intent-composer.ts | 361 | Shared CLMM keeper authorization guards and signed swap composition | pure |
scripts/builder/flows.ts | 358 | Orca pool/position load and owner-rebalance adapter, quote freeze, simulate | RPC |
scripts/builder/intent-codec.ts | 655 | Byte codec, canonical form, digest, and signature for the authorization | pure |
scripts/builder/intent.ts | 1603 | Authorization planner and the Orca keeper composers for rebalance, compound, and exit | RPC in loaders, pure composers |
scripts/builder/intent-packets.ts | 266 | Freezes transaction A, transaction B, and the cancellation before A is sent | RPC |
scripts/builder/intent-cleanup.ts | 78 | Cancels or expires scanned authorizations with a recheck | RPC |
scripts/builder/executor-authorization.ts | 31 | Maps the executor role to the optional global keeper account | pure |
scripts/builder/canary-session.ts | 70 | Requires 3 distinct keys for the canary | pure |
scripts/builder/compound-credit.ts | 1314 | Same-mint reward credit for compound, both CLMM venues | pure planners, plus 2 RPC loaders |
scripts/builder/budgets.ts | 48 | Compute-unit budgets and the Meteora simulation limit | pure |
scripts/builder/alt.ts | 315 | Lookup-table address selection, create, extend, fetch | pure selection, RPC create and fetch |
scripts/builder/send.ts | 423 | Compute-budget instructions, packet size check, single send, retry classification | pure helpers, RPC send loop |
scripts/builder/dry-run.ts | 381 | Simulates a canary step and prices its fee and rent | RPC |
scripts/builder/raydium.ts | 811 | Raydium account decoders, tick math, bitmap extension, placement formula | pure |
scripts/builder/raydium-accounts.ts | 779 | Raydium account maps in Anchor camelCase | pure |
scripts/builder/raydium-instructions.ts | 354 | Anchor wrappers for the Raydium instructions | pure, plus 2 RPC helpers for ATAs |
scripts/builder/raydium-flows.ts | 236 | Raydium pool/position load and owner-rebalance adapter | RPC |
scripts/builder/raydium-intent.ts | 1105 | Raydium keeper composers for rebalance, compound, and exit | RPC in loaders, pure composers |
scripts/builder/meteora.ts | 679 | Meteora account decoders, bin-array PDAs, chunk planning | pure |
scripts/builder/meteora-accounts.ts | 887 | Meteora account maps in Anchor camelCase | pure |
scripts/builder/meteora-instructions.ts | 367 | Anchor wrappers for the Meteora instructions | pure |
scripts/builder/meteora-intent-codec.ts | 249 | Byte codec and digest for the DLMM authorization | pure |
scripts/builder/meteora-intent.ts | 692 | DLMM authorization planner and the Meteora keeper composers | RPC in planner, pure composers |
scripts/builder/meteora-flow.ts | 530 | Owner Meteora steps from an observed position, frozen packet execution | pure steps, transport interface |
scripts/builder/meteora-driver.ts | 473 | Reads one coherent Meteora snapshot and prepares one owner packet | RPC |
Keeper: scripts/keeper/, scripts/keeper-sim.ts, scripts/canary*.ts
| Path | Lines | Purpose | Pure or I/O |
|---|---|---|---|
scripts/keeper/decide.ts | 275 | Off-chain copy of the 4 keeper checks and the automator authorization rule | pure |
scripts/keeper/rpc-connection.ts | 32 | A Connection with a 10 s deadline and no rate-limit retry | RPC factory |
scripts/keeper/meteora-planner.ts | 784 | Meteora eligibility planner over one snapshot | pure |
scripts/keeper/meteora-post-confirm.ts | 406 | Expected post-transaction state and its check | pure |
scripts/keeper/meteora-canary.ts | 322 | Canary policy parser and admission rules | pure |
scripts/keeper/meteora-rpc-collector.ts | 1312 | Reads pairs, positions, settings, and authorizations in one slot context | RPC |
scripts/keeper/meteora-live-adapter.ts | 1378 | Production dependencies: authorization loader, action builder, composer, post-confirm reader | RPC, signs with an injected keypair |
scripts/keeper/meteora-runtime-adapter.ts | 471 | Dry-run, lookup-table, packet-size, and raw-send mechanics for one runtime packet | RPC |
scripts/keeper/meteora-runtime.ts | 2832 | Durable single-replica runtime: SQLite store, file lock, HTTP health, work loop | filesystem, SQLite, HTTP server, injected sends |
scripts/keeper/meteora-runtime-entry.ts | 175 | Container entry point that reads the environment and starts the runtime | process.env |
scripts/keeper/meteora-observe-soak.ts | 314 | Bounded observe-only soak of the collector | RPC, filesystem |
scripts/keeper-sim.ts | 334 | Dry-run planner for the Orca keeper actions over every PositionSettings account | RPC, never sends |
scripts/canary.ts | 757 | Owner lifecycle on mainnet with small funds | RPC, signs with the provider wallet |
scripts/canary-intent.ts | 1494 | Orca keeper flows on mainnet: authorization, rebalance, exit, replayed nonce | RPC, HTTP API, signs with owner, session, keeper |
scripts/canary-raydium.ts | 1632 | Raydium owner and keeper flows on mainnet | RPC, HTTP API, signs with owner, session, keeper |
shared/meteora-recovery.ts | 256 | Selects the next Meteora exit step from one decoded position. Shared with the UI. | pure |
Legacy compatibility UI: management-ui/src/
| Path | Lines | Purpose | Pure or I/O |
|---|---|---|---|
management-ui/src/hooks.server.ts | 23 | Redirects owner and keeper pages when a feature flag is off | process.env |
management-ui/src/routes/api/**/+server.ts | 1869 | 20 HTTP endpoints. See the route table below. | RPC through $lib/server |
management-ui/src/lib/server/solana.ts | 180 | The only reader of SOLANA_RPC_URL, PDA helpers, account fetchers | RPC |
management-ui/src/lib/server/tx.ts | 461 | Unsigned legacy and v0 serializers, owner-management instruction builders | RPC for the blockhash |
management-ui/src/lib/server/runtime.ts | 178 | Feature flags and the per-action transaction check | pure over an environment record |
management-ui/src/lib/server/input.ts | 40 | Shared public-key, amount, and tick request validation | pure |
management-ui/src/lib/server/intent.ts | 830 | Authorization state read, plan, signature check, transaction A assembly | RPC, HTTP API |
management-ui/src/lib/server/orca.ts | 1473 | Orca owner flows: fund, deposit, harvest, exit, compound, rebalance, zap | RPC, HTTP API |
management-ui/src/lib/server/raydium.ts | 1384 | Raydium owner flows and the rebalance lookup-table plan | RPC, HTTP API |
management-ui/src/lib/server/admin.ts | 141 | Admin instruction builders checked against the live global config | RPC |
management-ui/src/lib/server/jupiter.ts | 147 | Jupiter HTTP client for the UI | HTTP API |
management-ui/src/lib/server/venue.ts, depth.ts | 480 | Venue market data and depth curves | HTTP API, RPC |
management-ui/src/lib/server/meteora*.ts (excluding *.test.ts) | 10732 | Meteora reads, owner entry, recovery, automation, coordination, keeper composers | RPC, HTTP API, in-memory state |
management-ui/src/lib/sickle/decode.ts | 339 | Borsh decoders for the 4 program account types | pure |
management-ui/src/lib/sickle/instructions.ts | 601 | Instruction discriminators and argument encoders | pure |
management-ui/src/lib/sickle/orca.ts, orca-tx.ts | 1159 | Orca decoders, tick and liquidity math, Orca instruction encoders | pure |
management-ui/src/lib/sickle/raydium.ts, raydium-tx.ts | 977 | Raydium decoders, tick math, Raydium instruction encoders | pure |
management-ui/src/lib/sickle/intent.ts, intent-tx.ts | 1100 | Second copy of the authorization codec, PDAs, decoders, and transaction encoders | pure |
management-ui/src/lib/sickle/intent-timing.ts | 3 | Re-exports the shared builder/UI intent timing policy | pure |
management-ui/src/lib/sickle/jupiter.ts | 351 | Second copy of the swap planner and route conversion | pure |
management-ui/src/lib/sickle/fees.ts, transfer-fees.ts | 164 | Second copy of fee math and Token-2022 fee math | pure |
management-ui/src/lib/sickle/meteora-*.ts, settings-tx.ts (excluding *.test.ts) | 2626 | Meteora codec and transaction encoders, settings encoder, readiness | pure |
management-ui/src/lib/dlmm/*.ts (excluding *.test.ts) | 3150 | Meteora lb_clmm decoders, support policy, range planner, chart data | pure |
management-ui/src/lib/wallet/wallet.svelte.ts | 233 | Wallet Standard connector. The only place a transaction is signed. | browser wallet, /api/rpc |
management-ui/src/lib/idl/sickle.json | 9037 | The checked-in IDL snapshot | data |
Tests and fixtures
| Path | Lines | Purpose |
|---|---|---|
tests/*.ts | 48141 | 63 top-level files: 56 spec files, 6 helper modules, 1 registration module |
tests/sickle/*.ts | 10320 | 8 legacy-validator modules registered by tests/sickle.ts |
tests/support/sickle-context.ts | 171 | Provider, program, PDAs, and event decoder for the legacy-validator suite |
tests/fixtures/intent-vectors.json | 131 | Authorization byte vectors shared with Rust |
tests/fixtures/meteora-intent-vectors.json | 62 | DLMM authorization byte vectors shared with Rust |
tests/fixtures/meteora-dlmm-layout.json | 559 | Meteora account offsets shared with Rust |
tests/fixtures/meteora-builder-packets.json | 71 | Meteora packet fixture for tests/builder-meteora-packets.ts |
tests/fixtures/meteora-cu-probe.json | 445 | Raw compute samples for the docs |
tests/fixtures/meteora-cu-campaign.json | 7264 | Cross-pair crossings with per-bin settlement-work counts |
tests/fixtures/meteora-cu-work-premium.json | 2203 | Paired per-bin settlement premium, same bins |
tests/fixtures/meteora-cu-surfpool-worst-work.json | 344 | CI complete-transaction figures in the worst settlement state |
Scripts and configuration
| Path | Lines | Purpose |
|---|---|---|
/package.json | 45 | test, test:ts, test:surfpool, test:keeper-runtime, keeper:sim, keeper:meteora |
Anchor.toml | 77 | [scripts] test entry points, [test.validator] clone list, [surfpool] fork settings |
.mocharc.json | 5 | ts-node/register, timeout 1,000,000 ms |
scripts/dev/gen-idl.mjs | 242 | Writes the IDL snapshot, target/idl/sickle.json, and target/types/sickle.ts |
Responsibilities
- Derive every PDA and ATA that the program re-derives on chain.
- Produce the exact camelCase account map that
accountsStrictrequires for each instruction. - Decode the foreign venue accounts that the IDL does not describe.
- Size liquidity, slippage floors, fees, and Token-2022 transfer fees.
- Plan a keeper authorization in canonical form, compute its digest, and sign it.
- Compose the atomic transaction B for each keeper action.
- Freeze transaction A, transaction B, and a cancellation before A is sent.
- Check the packet size against the wire limit before a send.
- Send with a blockhash refresh and refuse to retry a program error.
- Predict off chain whether the program accepts a keeper action.
- Serve the management UI with unsigned transactions and read models.
- Proxy JSON-RPC for the browser with a method allowlist.
- Test the program on a legacy validator, on a mainnet fork, and on mainnet.
Public items
scripts/builder/pdas.ts
| Item | Kind | Meaning |
|---|---|---|
GLOBAL_CONFIG_SEED, SICKLE_SEED, POSITION_SETTINGS_SEED, KEEPER_SEED | const | Program seeds. pdas.ts:21-27 |
ORCA_POSITION_SEED, RAYDIUM_POSITION_SEED | const | Both equal "position". Kept distinct on purpose. pdas.ts:29-36 |
RAYDIUM_TICK_ARRAY_SEED, RAYDIUM_TICK_ARRAY_BITMAP_SEED | const | Raydium seeds. pdas.ts:38-42 |
INTENT_*_SEED, DLMM_INTENT_AUTHORIZATION_SEED, DLMM_INTENT_POSITION_SEED, ACTION_INTENT_SEED | const | Authorization and per-nonce position seeds. pdas.ts:44-58 |
EVENT_AUTHORITY_SEED | const | Anchor's __event_authority. pdas.ts:64 |
TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID, ASSOCIATED_TOKEN_PROGRAM_ID | const | Token program IDs. pdas.ts:66-75 |
associatedTokenAddress | fn | ATA for owner, mint, and token program. pdas.ts:84 |
globalConfigPda, sicklePda, positionSettingsPda, globalAutomatorPda | fn | Program PDAs. pdas.ts:97-130 |
eventAuthorityPda | fn | The event authority PDA. pdas.ts:133 |
intentDomainPda, intentNoncePda, intentSessionPda | fn | Durable authorization PDAs. pdas.ts:138-163 |
nonceLeBytes | fn | 8-byte little-endian nonce seed. pdas.ts:166 |
intentAuthorizationPda, dlmmIntentAuthorizationPda, dlmmIntentPositionPda, actionIntentPda | fn | Per-nonce PDAs. pdas.ts:173-221 |
orcaPositionPda, raydiumPersonalPositionPda | fn | Venue position PDAs. pdas.ts:228-251 |
scripts/builder/accounts.ts
| Item | Kind | Meaning |
|---|---|---|
CommonInput | interface | programId, owner, authority, whirlpoolProgram, whirlpool, decoded pool. accounts.ts:66 |
ModifyLiquidityInput, RebalanceInput | type | CommonInput plus position mint and tick range, or plus old and new mints. accounts.ts:221, accounts.ts:753 |
SwapFeeAction | type | "deposit" or "withdraw". accounts.ts:564 |
orcaRewardGroupMetas, orcaRewardCollectorMetas, orcaRewardRemainingAccounts | fn | Reward vault, Sickle ATA, mint, and collector ATA metas per initialized slot. accounts.ts:109-145 |
resolveOpenPositionAccounts | fn | orca_open_position. accounts.ts:148 |
resolveIncreaseLiquidityAccounts | fn | orca_increase_liquidity. Consent account defaults on when keeper or intent is set. accounts.ts:242 |
resolveDecreaseLiquidityAccounts | fn | orca_decrease_liquidity. accounts.ts:271 |
resolveCollectFeesAccounts, resolveCollectRewardsAccounts | fn | orca_collect_fees, orca_collect_rewards. accounts.ts:276-345 |
resolveClosePositionAccounts | fn | orca_close_position. Settings PDA is always present. accounts.ts:354 |
resolveHarvestForAccounts, resolveCompoundForAccounts, resolveExitForAccounts | fn | harvest_for, compound_for, exit_for. accounts.ts:389, :476, :491 |
resolveJupiterSwapAccounts | fn | jupiter_swap. Fee collector ATA only when a fee action is set. accounts.ts:580 |
resolveRebalanceAccounts, resolveRebalanceForAccounts | fn | orca_rebalance_position, rebalance_for. accounts.ts:764-792 |
resolveInitializeIntentDomainAccounts, resolveSetIntentSessionAccounts | fn | Admin migration and session instruction. accounts.ts:795-823 |
resolvePreauthorizeIntentAccounts, resolvePreauthorizeDlmmIntentAccounts | fn | Transaction A, both families. accounts.ts:830-883 |
resolveCancelIntentAccounts, resolveCancelDlmmIntentAccounts | fn | Owner cancellation. accounts.ts:886-925 |
resolveExpireIntentAuthorizationAccounts, resolveExpireDlmmIntentAuthorizationAccounts | fn | Permissionless expiry. accounts.ts:932-967 |
resolveFinalizeIntentAccounts, resolveFinalizeDlmmIntentAccounts | fn | Finalizer, both families. accounts.ts:1013-1036 |
accounts.ts:60-63 re-exports SNAPSHOT_ACCOUNT_CODER_NAMES and
eventCpiAccounts, and accounts.ts:459 re-exports IntentRef, so existing
Orca-facing imports keep working while the canonical definitions live in the
venue-neutral module below.
scripts/builder/common-accounts.ts
| Item | Kind | Meaning |
|---|---|---|
SNAPSHOT_ACCOUNT_CODER_NAMES | const | Anchor's runtime names for GlobalConfig and PositionSettings. common-accounts.ts:17-20 |
decodeSickleSnapshotAccount | fn | Generated-IDL typed decoder for coherent snapshots after caller ownership validation. common-accounts.ts:22-36 |
PoolTokenDescriptor, IntentRef | interface | One mint/program pair, and one intent nonce plus optional session signer. common-accounts.ts:38-41, :82-85 |
resolveSicklePoolAccounts | fn | Sickle, global config, and both program-aware pool-token ATAs. common-accounts.ts:47-67 |
feeCollectorAccount | fn | Program-aware fee-collector ATA. common-accounts.ts:70-76 |
intentInitAccounts | fn | The three nullable transaction-B intent accounts. common-accounts.ts:92-108 |
eventCpiAccounts | fn | Anchor event authority plus the Sickle program. common-accounts.ts:115-120 |
scripts/builder/instructions.ts
| Item | Kind | Meaning |
|---|---|---|
OrcaRewardAtaPreparationInput, TransferHookAccounts, RewardHookAccounts | type | Reward ATA inputs and transfer-hook account groups. instructions.ts:73, instructions.ts:182-196 |
buildOrcaRewardAtaPreparation, buildMissingOrcaRewardAtaPreparation, assertOrcaRewardAtasPrepared | fn | Idempotent reward ATA creates. The last 2 read RPC. instructions.ts:98-164 |
buildOpenPosition, buildIncreaseLiquidity, buildDecreaseLiquidity | fn | Orca position instructions. instructions.ts:226-300 |
buildCollectFees, buildCollectRewards, buildClosePosition | fn | Orca collect and close. instructions.ts:303-356 |
buildHarvestFor, buildCompoundFor, buildExitFor | fn | Orca keeper instructions. instructions.ts:359-432 |
buildJupiterSwap | fn | Owner swap. Rejects keeper or position inputs. instructions.ts:444 |
buildIntentJupiterSwap | fn | Keeper swap with fee_action = null. instructions.ts:502 |
authorizationToAnchorArg, dlmmAuthorizationToAnchorArg | fn | Codec payload to Anchor argument shape. instructions.ts:561-628 |
buildInitializeIntentDomain, buildSetIntentSession | fn | Domain migration and session. instructions.ts:631-671 |
buildPreauthorizeIntentIx, buildPreauthorizeDlmmIntentIx | fn | The program instruction of transaction A. instructions.ts:679-728 |
buildCancelIntent, buildCancelDlmmIntent, buildExpireIntentAuthorization, buildExpireDlmmIntentAuthorization | fn | Cancellation and expiry. instructions.ts:731-795 |
buildFinalizeIntent, buildFinalizeDlmmIntent | fn | Finalizer with vaults, owner ATAs, and mints as remaining accounts. instructions.ts:849-878 |
buildRebalance, buildRebalanceFor | fn | Orca owner and keeper rebalance. instructions.ts:881-943 |
scripts/builder/clmm-owner-rebalance.ts
| Item | Kind | Meaning |
|---|---|---|
SwapLegFetcher | type | Injected Jupiter quote boundary. clmm-owner-rebalance.ts:41 |
ClmmOwnerRebalanceComposition | interface | Shared instruction and lookup-table result. clmm-owner-rebalance.ts:95 |
composeClmmOwnerRebalance | fn | Fee-aware drain, optional swap, conservative re-add, ordering, and ALT propagation. clmm-owner-rebalance.ts:101 |
shared/intent-timing.ts
| Item | Kind | Meaning |
|---|---|---|
DEFAULT_VALIDITY_SLOTS, INTENT_QUOTE_MAX_AGE_SLOTS, SEND_MARGIN_SLOTS | const | Builder, server, and browser timing defaults. intent-timing.ts:2-8 |
scripts/builder/clmm-intent-composer.ts
| Item | Kind | Meaning |
|---|---|---|
SEND_MARGIN_SLOTS | const | Compatibility re-export of the shared pre-expiry margin. clmm-intent-composer.ts:23 |
assertIntentActionAndPosition, assertIntentExpiryMargin | fn | Shared action, venue-position, and expiry guards. clmm-intent-composer.ts:26-58 |
assertSignedWithdrawalFloors | fn | Compares both signed drain floors with the frozen economic plan. clmm-intent-composer.ts:61 |
composeClmmIntentSingleSwap, composeClmmIntentExitSwaps | fn | Signed compound/rebalance leg or exit target legs, including quote and vault validation. clmm-intent-composer.ts:110, :236 |
scripts/builder/flows.ts
| Item | Kind | Meaning |
|---|---|---|
FetchedPoolState | interface | Decoded pool plus both transfer-fee schedules. flows.ts:38 |
getPoolState, getPositionState | fn | Fetch and decode a pool with its mint owners, or a position. flows.ts:46, flows.ts:124 |
RebalanceFlow | interface | Instructions, new mint keypair, lookup tables. flows.ts:133 |
SwapLegFetcher | type | Compatibility re-export of the shared quote boundary. flows.ts:30 |
INTENT_QUOTE_MAX_AGE_SLOTS | const | Compatibility re-export of the shared quote age. flows.ts:149 |
FrozenIntentSwapLeg | interface | One frozen route with mints, programs, amounts, and slot window. flows.ts:156 |
assertFreshIntentQuote | fn | Rejects a zero, stale, or non-exact-floor quote. flows.ts:168 |
freezeIntentSwapLeg | fn | Fetches a quote and stamps its slot window. flows.ts:193 |
composeRebalance | fn | Owner Orca rebalance. Rejects a keeper input. flows.ts:247 |
simulate | fn | Simulates a legacy or v0 transaction without a send. flows.ts:329 |
scripts/builder/intent.ts
| Item | Kind | Meaning |
|---|---|---|
DEFAULT_VALIDITY_SLOTS, SEND_MARGIN_SLOTS | const | Compatibility re-exports of the shared timing policy. intent.ts:126-129 |
PlannedIntentAuthorization, PlannedSwapBound, PlanIntentAuthorizationBase, IntentPlanningContext | interface | Planner inputs and outputs. intent.ts:138-216 |
plannedSwapBoundFromFrozenQuote | fn | A signed edge from a frozen quote. intent.ts:164 |
loadIntentPlanningContext | fn | Domain value, nonce, and slot in one read. intent.ts:224 |
planIntentAuthorization, planIntentAuthorizationForPool | fn | Orca wrapper and the venue-neutral planner. intent.ts:260, intent.ts:289 |
buildPreauthorizeIntent | fn | Signs the digest and returns [ed25519, preauthorize_intent]. intent.ts:400 |
ConfirmedIntentAuthorization, confirmIntentAuthorization | interface, fn | Stored authorization image and its digest check. intent.ts:436-475 |
IntentActionFlow, IntentExitFlow, IntentCompoundFlow, OrcaIntentCompoundFlow | interface | Composer outputs. intent.ts:478, intent.ts:684, intent.ts:928-940 |
OrcaIntentRebalanceSnapshot, OrcaIntentExitSnapshot, OrcaIntentCompoundSnapshot | interface, type | Frozen economic images. intent.ts:485, intent.ts:619, intent.ts:884 |
loadOrcaIntentRebalanceSnapshot, loadOrcaIntentCompoundSnapshot | fn | One-context loaders. intent.ts:510, intent.ts:948 |
planOrcaExitEconomics, planOrcaRebalanceEconomics, planOrcaCompoundEconomics | fn | Floors, usable credit, swap direction. intent.ts:631, intent.ts:826, intent.ts:1048 |
assessCompoundDustSide, planOrcaCompoundReadd | fn | Dust proof and compound add-liquidity plan. intent.ts:1068, intent.ts:1117 |
composeIntentExit | fn | [exit_for, swaps..., finalize_intent]. intent.ts:695 |
composeIntentCompound | fn | [update_fees_and_rewards?, compound_for, swap?, increase?, finalize_intent]. intent.ts:1260 |
composeIntentRebalance | fn | [rebalance_for, swap?, increase, finalize_intent]. intent.ts:1434 |
scripts/builder/intent-codec.ts
| Item | Kind | Meaning |
|---|---|---|
AUTHORIZATION_VERSION, MAX_INTENT_ASSETS, MAX_SWAP_EDGES, INTENT_DIGEST_PREFIX, MAX_DUST_BPS, MAX_COMPOUND_DUST_BPS | const | Copies of constants.rs. intent-codec.ts:27-36 |
IntentAction, IntentSignerKind | type | Enum names mapped to Borsh indexes. intent-codec.ts:39-51 |
IntentAssetBound, SwapEdge, RebalanceIntentParams, ExitIntentParams, AuthorizationV2 | interface | Field-for-field copies of intent.rs:108-208. intent-codec.ts:54-106 |
ZERO_REBALANCE_PARAMS, zeroExitParams, AUTHORIZATION_V2_SIZE | const, fn | Zero fillers and the fixed size. intent-codec.ts:108-138 |
serializeAuthorizationV2 | fn | Fixed-size Borsh bytes, zero-padded. intent-codec.ts:199 |
canonicalizeAuthorizationV2, validateCanonicalAuthorization | fn | Sort, then apply the rules of validate_canonical. intent-codec.ts:257, intent-codec.ts:276 |
authorizationDigest | fn | sha256(prefix, version, program, domain PDA, domain value, payload). intent-codec.ts:433 |
signIntentDigest, verifyIntentDigest, ed25519VerifyInstruction | fn | Raw ed25519 over the digest and the native verify instruction. intent-codec.ts:460-495 |
decodeIntentDomain, decodeIntentNonce, decodeIntentSession, decodeIntentAuthorization | fn | Account decoders at fixed offsets. intent-codec.ts:504-655 |
scripts/builder/intent-packets.ts, scripts/builder/alt.ts, scripts/builder/send.ts
| Item | Kind | Meaning |
|---|---|---|
IntentPacketSpec, FrozenIntentPacket, FrozenIntentPacketSet, IntentPacketValidity | interface | Packet inputs and frozen bytes. intent-packets.ts:28-58 |
freezeIntentPackets | fn | Freezes A, B, and cancellation on one blockhash, then checks the window. intent-packets.ts:116 |
executeFrozenIntentPackets | fn | Sends A then B. On failure sends the cancellation and proves removal. intent-packets.ts:223 |
lookupAddressesForInstructions, missingLookupAddresses | fn | Table-eligible keys and the missing subset. alt.ts:40, alt.ts:69 |
newestSlotInSlotHashes, recentSlotsInSlotHashes, unclaimedRecentSlotForLookupTable | fn | SlotHashes parsing for table creation. alt.ts:111-132 |
ensureLookupTable, ensurePersistentLookupTable, fetchLookupTables | fn | Create, reuse and extend, fetch. alt.ts:162, alt.ts:258, alt.ts:302 |
PriorityFeeOptions, RetryOptions, SendResult, SendOptions, TransactionLifetime, SendAndConfirmOptions | interface | Send knobs and one-attempt lifetime. send.ts:48-229 |
priorityFeeInstructions, withPriorityFees | fn | Heap frame, CU limit, CU price. send.ts:87, send.ts:123 |
retryDelayMs, isRetriableError | fn | Backoff and error class by message text. send.ts:135, send.ts:153 |
signedTransactionBytes, signedV0TransactionBytes | fn | Signed bytes, legacy or v0. send.ts:237, send.ts:268 |
PACKET_LIMIT, assertPacketFit, assertV0PacketFit | const, fn | Wire limit and its check. send.ts:286-337 |
sendAndConfirmTransactionBytes | fn | Sends signed bytes once and confirms against their original lifetime. send.ts:344 |
sendWithRetry | fn | Refreshes the blockhash and re-signs around the single-send helper. send.ts:381 |
Other builder files
| File | Public items |
|---|---|
scripts/builder/orca.ts | TICK_ARRAY_SIZE, WP_NFT_UPDATE_AUTH, MEMO_PROGRAM_ID, MIN_TICK_INDEX, MAX_TICK_INDEX, TICK_ARRAY_SEED, REWARD_SLOT_COUNT, 5 discriminators, pool/position and reward/fee state interfaces, decodePool, decodeWhirlpool, decodePosition and 6 reward/fee state decoders, tickArrayStartIndex, tickArrayPda, tickArrayPdaForTick, updateFeesAndRewardsInstruction, TickRounding, alignTick, buildSymmetricRange, FULL_RANGE_ONLY_TICK_SPACING_THRESHOLD, isFullRangeOnly, fullRangeTicks, buildOpenRange, expectedRebalanceRange |
scripts/builder/protocol-account.ts | InvalidProtocolAccountData |
scripts/builder/raydium.ts | Tick constants, MEMO_PROGRAM_ID, 3 discriminators, POOL_REWARD_SLOT_COUNT, RaydiumPoolState and 10 state interfaces, raydiumSwapSide, decodePool, decodePersonalPosition and 6 state decoders, tick-array and bitmap helpers raydium.ts:618-765, alignTick, expectedRebalanceRange |
scripts/builder/raydium-accounts.ts | rewardGroupMetas, rewardCollectorMetas, RaydiumCommonInput, RaydiumPositionInput, RaydiumRebalanceInput, 10 resolveRaydium*Accounts functions |
scripts/builder/raydium-instructions.ts | RaydiumRewardAtaPreparationInput, buildMissingRaydiumRewardAtaPreparation, assertRaydiumRewardAtasPrepared, 10 buildRaydium* wrappers |
scripts/builder/raydium-flows.ts | FetchedRaydiumPoolState, getRaydiumPoolState, getRaydiumPositionState, RaydiumRebalanceFlow, composeRaydiumRebalance |
scripts/builder/raydium-intent.ts | planRaydiumIntentAuthorization, 3 snapshot loaders, 3 economics planners, 1 swap-limit planner, raydiumPoolTokenYieldReceiptsFromPlan, composeIntentRaydiumCompound, composeIntentRaydiumExit, composeIntentRaydiumRebalance, 9 interfaces |
scripts/builder/meteora.ts | DLMM_PROGRAM_ID, METEORA_DLMM_AUTOMATION_LB_PAIR, METEORA_DLMM_INTENT_MAX_WIDTH, 24 layout constants, DlmmPairState, DlmmPositionState and 6 interfaces, decodeLbPair, decodeLbPairMintKeys, decodePositionV2, assertDlmmPairSupported, assertSicklePosition, bin-array PDA helpers, planMeteoraChunks, planMeteoraPositionAllocation, validateMeteoraLiquidityParameters |
scripts/builder/meteora-accounts.ts | MeteoraCommonInput, 6 input types, meteoraBinArrayMetas, 4 remaining-account helpers, 12 resolveMeteora*Accounts functions |
scripts/builder/meteora-instructions.ts | MeteoraAtaPreparationInput, buildMeteoraAtaPreparation, buildMeteoraInitializeBinArray, 14 buildMeteora* wrappers |
scripts/builder/meteora-intent-codec.ts | DLMM_AUTHORIZATION_VERSION, METEORA_DLMM_PROTOCOL_INDEX, DLMM_INTENT_DIGEST_PREFIX, 3 size constants, DlmmActionParameters, DlmmAuthorizationV1, validateCanonicalDlmmAuthorization, canonicalizeDlmmAuthorizationV1, serializeDlmmAuthorizationV1, decodeDlmmAuthorizationV1, dlmmAuthorizationDigest |
scripts/builder/meteora-intent.ts | PlannedDlmmIntentAuthorization, PlanMeteoraIntentAuthorizationInput, planMeteoraIntentAuthorization, buildPreauthorizeDlmmIntent, buildCancelPlannedDlmmIntent, buildExpirePlannedDlmmIntent, composeMeteoraIntentCompound, composeMeteoraIntentRebalance, composeMeteoraIntentExit |
scripts/builder/meteora-flow.ts | Step types, nextMeteoraAllocationStep, buildNextMeteoraAllocationStep, buildMeteoraPreparationStep, buildMeteoraFundingStep, buildMeteoraHarvestStep, nextMeteoraExitStep, buildMeteoraExitStep, freezeMeteoraOwnerPacket, executeFrozenMeteoraOwnerPacket, 2 error classes |
scripts/builder/meteora-driver.ts | Reader and RPC interfaces, loadMeteoraOwnerSnapshot, 5 prepare*Packet functions, executePreparedMeteoraOwnerStep |
scripts/builder/compound-credit.ts | 15 interfaces and types, planOrcaPoolTokenFeeReceipts, planRaydiumPoolTokenFeeReceipts, planOrcaPoolTokenCompoundCredits, planRaydiumPoolTokenCompoundCredits, loadOrcaPoolTokenCompoundCredits, loadRaydiumPoolTokenCompoundCredits |
scripts/builder/jupiter.ts | JUPITER_CPI_EXCLUDED_DEXES, jupiterCpiQuoteParams, RebalanceSwapPlan, planRebalanceSwap, JupiterApiInstruction, JupiterRouteLimitError, 7 ceiling constants, RAYDIUM_DRAIN_CLOSE_HEAP_FRAME_BYTES, RouteLimits, 3 limit sets, JUPITER_FIXED_ROUTE_ACCOUNTS, SINGLE_LEG_QUOTE_MAX_ACCOUNTS, JupiterSwapLeg, jupiterSwapLegFromApi |
scripts/builder/jupiter-api.ts | JUPITER_API_BASE_URL, QuotedSwapLeg, fetchJupiterSwapLeg |
scripts/builder/liquidity.ts | Q64, tickIndexToSqrtPriceX64, liquidityFromTokenA, liquidityFromTokenB, estimateLiquidity, tokenAmountsFromLiquidity, applySlippage |
scripts/builder/zap.ts | ZapInPlan, FixedMaxZapInPlan, planZapIn, planZapInAgainstFixedMaxima |
scripts/builder/fees.ts | FEE_ACTION_HARVEST 0, _COMPOUND 1, _REBALANCE 2, _EXIT 3, _DEPOSIT 4, feeAmount, afterFee |
scripts/builder/transfer-fees.ts | ActiveTransferFee, MintAccountForTransferFee, transferFeeExcludedAmount, transferFeeIncludedAmount, activeTransferFeesForEpoch, loadActiveTransferFees |
scripts/builder/budgets.ts | INTENT_COMPOUND_CU, ORCA_HARVEST_CU, INTENT_REBALANCE_CU, INTENT_EXIT_CU, METEORA_KEEPER_SIMULATION_CU_LIMIT |
scripts/builder/dry-run.ts | LAMPORTS_PER_SIGNATURE, DryRunSealBreach, isDryRunSealBreach, sealConnection, DryRunPrerequisiteMissing, isDryRunPrerequisiteMissing, DryRunOptions, DryRunResult, dryRun, printDryRun, summariseDryRun |
scripts/builder/intent-cleanup.ts | ScannedIntentAuthorization, IntentCleanupResult, cancelScannedIntentAuthorizations, expireScannedIntentAuthorizations |
scripts/builder/executor-authorization.ts | SickleExecutorAuthorizationRole, optionalGlobalKeeper |
scripts/builder/canary-session.ts | CanarySessionAuthorization, assertCanarySessionActors, assertCanarySessionKeypair, canarySessionAuthorization |
scripts/keeper/decide.ts
| Item | Kind | Meaning |
|---|---|---|
PERMISSION_HARVEST, _COMPOUND, _REBALANCE, _EXIT | const | Bits 0 to 3. decide.ts:18-21 |
DEFAULT_PUBKEY | const | The all-zeros key as base58. decide.ts:24 |
RewardBehavior, KeeperAction, NormalizedSettings, Decision | type | Inputs and outputs of the checks. decide.ts:26-64 |
evaluateHarvest, evaluateCompound | fn | Copies of validate_harvest_for and validate_compound_for. decide.ts:70-79 |
evaluateRebalance | fn | Copy of validate_rebalance_for: delay, cutoff, debounce, buffer, stop-loss. decide.ts:87 |
evaluateExit | fn | Copy of validate_exit_for. decide.ts:126 |
GlobalAutomatorRecord, SickleAuthority, isAuthorizedAutomator | interface, fn | Copy of is_authorized_automator. decide.ts:146-193 |
ACTION_PERMISSION, LiveState, ActionPlan, planForPosition | const, fn | All 4 checks for one position. decide.ts:196-272 |
Meteora keeper runtime
| File | Public items |
|---|---|
scripts/keeper/meteora-planner.ts | METEORA_ADX_USDC_LB_PAIR, METEORA_INTENT_MAX_BIN_WIDTH, KEEPER_ACTION_PRIORITY, KEEPER_ACTION_PERMISSION, KEEPER_SKIP_REASON_CODES, blocksMeteoraActionEconomicPlan, splitIntoMeteoraKeeperChunks, compareAddress, resolveMeteoraExecutorAuthorization, assessMeteoraActionSettingsReadiness, planMeteoraKeeperDiscovery |
scripts/keeper/meteora-post-confirm.ts | METEORA_POST_CONFIRM_VIOLATIONS, assertMeteoraPostConfirmExpectation, validateMeteoraPostConfirmEvidence, 6 types |
scripts/keeper/meteora-canary.ts | 4 cohort constants, 3 canary caps, METEORA_CANARY_ADMISSION_REASONS, parseMeteoraAdxUsdcCanaryPolicy, parseMeteoraAdxUsdcCanaryRecoveryPolicy |
scripts/keeper/meteora-rpc-collector.ts | connectionMeteoraRpcCollectorReader, createMeteoraKeeperRpcCollector, 3 types |
scripts/keeper/meteora-live-adapter.ts | connectionMeteoraKeeperLiveReader, createMeteoraAuthorizationLoader, createMeteoraKeeperReviewedActionBuilder, assertMeteoraKeeperActionDraft, createMeteoraKeeperLiveComposer, createMeteoraPostConfirmInspector, createMeteoraKeeperLiveDependencies |
scripts/keeper/meteora-runtime-adapter.ts | simulateAndFreezeMeteoraRuntimeFlow, packetFromFrozenIntentPacket, frozenPacketSignature, frozenMeteoraPacketTransport |
scripts/keeper/meteora-runtime.ts | METEORA_KEEPER_WORK_STATUSES, MeteoraKeeperPermanentPreparationError, isMeteoraKeeperPermanentPreparationError, stableJson, redactSecrets, FilesystemLock, MeteoraKeeperRuntimeStore, MeteoraKeeperRuntime |
scripts/keeper/meteora-runtime-entry.ts | selectMeteoraKeeperRuntimeDependencies |
scripts/keeper/meteora-observe-soak.ts | assertLoopbackRpcUrl, runBoundedMeteoraObserveSoak, runMeteoraSurfpoolObserveSoak |
scripts/keeper/rpc-connection.ts | KEEPER_RPC_TIMEOUT_MS, fetchWithKeeperRpcDeadline, createBoundedKeeperRpcConnection |
Management UI routes
Every route is a SvelteKit +server.ts. The server builds unsigned
transactions and reads state. The browser signs. The table names the server
function each route calls. No route calls scripts/builder/. The UI has its
own copy of the encoders under management-ui/src/lib/sickle/.
| Route | Method | Input | Output | Server function |
|---|---|---|---|---|
/api/rpc | POST | JSON-RPC body, 1 to 10 requests | Upstream response, or an error | fetch(rpcUrl()). api/rpc/+server.ts:94 |
/api/tx | POST | action plus action fields. api/tx/+server.ts:84-142 | { transaction, description } or { steps[] }, base64 unsigned | 56 case branches. api/tx/+server.ts:328-928 |
/api/intent | GET | ?owner= | Domain, nonce, sessions, pending authorizations | fetchIntentState. server/intent.ts:139 |
/api/intent | POST | owner, protocol, pool, position, action, executor, validitySlots, swaps, session | Canonical authorization JSON plus digest | planIntent. server/intent.ts:281 |
/api/sickle | GET | ?owner= | PDA, decoded account, lamports, vaults | fetchSickleByOwner. server/solana.ts:94 |
/api/admin | GET | none | Global config and global keepers | fetchGlobalConfig, listGlobalAutomators. server/solana.ts:87, server/admin.ts:24 |
/api/pools | GET | ?venue=orca or ?venue=raydium, plus q, sort, limit | { total, pools } | listVenuePools. server/venue.ts:208 |
/api/pools/depth | GET | ?venue=&address=&span= | Liquidity curve | liquidityCurve. server/depth.ts:220 |
/api/orca/positions | GET | ?owner= | { positions } | listOrcaPositions. server/orca.ts:357 |
/api/orca/pool | GET | ?address= | Decoded pool plus market data | describePool, venuePool. server/orca.ts:220, server/venue.ts:219 |
/api/raydium/positions | GET | ?owner= | { positions } | listRaydiumPositions. server/raydium.ts:287 |
/api/raydium/pool | GET | ?address= | Decoded pool plus market data | describeRaydiumPool, venuePool. server/raydium.ts:179 |
/api/meteora/pools | GET | ?q=&sort=&limit= | { total, pools } | listMeteoraPools. server/meteora.ts:103 |
/api/meteora/pair | GET | ?address= | Pair context, oracle window, fee rates, market | loadPairContext, loadOracleWindow, meteoraPool. server/meteora.ts:169, server/meteora.ts:567, server/meteora.ts:118 |
/api/meteora/bins | GET | ?address=&span= | Bin window around the active bin | loadPairContext, loadBinWindow. server/meteora.ts:252 |
/api/meteora/positions | GET | ?owner=&page=&pageSize= | Paged positions with total | listSicklePositions. server/meteora.ts:342 |
/api/meteora/position | GET | ?address=&owner= | One position resolved bin by bin | describePosition. server/meteora.ts:465 |
/api/meteora/automation | GET | ?owner=&position= | Readiness snapshot | loadMeteoraAutomation. server/meteora-automation.ts:382 |
/api/meteora/recovery | POST | owner, position | One unsigned recovery step, or complete | buildNextMeteoraRecovery, meteoraRecoveryPacketInstructions. server/meteora-actions.ts:455, server/meteora-actions.ts:89 |
/api/meteora/enter | POST | action in prepare-next, allocate-next, fund, add, plus keys and amounts | One unsigned packet, or a lookup-required result | buildNextMeteoraPreparation, buildNextMeteoraAllocation, buildMeteoraVaultFunding, buildMeteoraAddLiquidity, toMeteoraOwnerPacket. server/meteora-enter.ts:453-636, server/tx.ts:367 |
/api/meteora/coordination | POST | Strict owner, position, action, session tuple. server/meteora-coordination-request.ts | The next coordinator state | loadMeteoraCoordination. server/meteora-coordination.ts:932 |
The /api/tx actions map to these server builders.
| Action group | Server builders |
|---|---|
initialize, setManager, setAutomator, createAta, sweep | initializeSickleIx, setManagerIx, setCustomAutomatorIx, createSickleAtaIx, sweepTokenIxs. server/tx.ts:86-170 |
orcaFund, orcaDeposit, orcaHarvest, orcaExit, orcaCompound | buildOrcaFund, buildOrcaDeposit, buildOrcaHarvest, buildOrcaExit, buildOrcaCompound. server/orca.ts:482-772 |
orcaRebalance, orcaRebalanceSwap, orcaRebalanceIncrease | buildOrcaRebalanceStart, buildOrcaRebalanceSwap, buildOrcaRebalanceIncrease. server/orca.ts:831-1064 |
orcaZapInSwap, orcaZapInDeposit, orcaZapOutSwap | buildOrcaZapInSwap, buildOrcaZapInDeposit, buildOrcaZapOutSwap. server/orca.ts:1149-1369 |
raydium* | buildRaydiumFund, buildRaydiumDeposit, buildRaydiumHarvest, buildRaydiumCompound, buildRaydiumExit, buildRaydiumIncrease, buildRaydiumZapInSwap, buildRaydiumZapInDeposit, buildRaydiumZapOutSwap, planRaydiumRebalanceTable, buildRaydiumRebalanceStart, buildRaydiumRebalanceSwap. server/raydium.ts:405-1296 |
setPositionSettings, unsetPositionSettings | buildSetPositionSettings, buildUnsetPositionSettings. server/orca.ts:1456-1468 |
setIntentSession, intentPreauthorize, dlmmIntentPreauthorize, cancelIntent, cancelDlmmIntent | buildSetIntentSession, buildPreauthorizeIntent, buildPreauthorizeDlmmIntent, buildCancelIntent, buildCancelDlmmIntent, planIntentPreauthorizationTable. server/intent.ts:654-816 |
admin* | 9 builders. server/admin.ts:51-127 |
meteoraClose, meteoraSetPositionSettings, meteoraUnsetPositionSettings, meteoraCancelDlmmIntent | buildMeteoraClose, buildMeteoraPositionSettings, buildMeteoraUnsetPositionSettings, buildMeteoraCancelDlmmAuthorization. server/meteora-actions.ts:575, server/meteora-automation.ts:415-513 |
The IDL contract
| Item | Where | Meaning |
|---|---|---|
target/idl/sickle.json | written by anchor build or scripts/dev/gen-idl.mjs. Git ignores target/ | The live IDL. Six runtime/deploy tools load it: scripts/canary.ts:152, scripts/canary-raydium.ts:198, scripts/canary-intent.ts:175, scripts/keeper-sim.ts:109, scripts/deploy/init-config.ts:53, and scripts/deploy/init-intent-domain.ts:47; no offline spec does |
target/types/sickle.ts | written by gen-idl.mjs with convertIdlToCamelCase | The generated Sickle type used to parameterize Anchor programs and coders. Every builder import is type-only, enforced at tests/offchain-boundaries.ts:254-281 |
management-ui/src/lib/idl/sickle.json | checked in | The snapshot. tests/builder-accounts.ts:13, tests/builder-meteora.ts:4, tests/builder-meteora-flow.ts:6, and tests/builder-meteora-driver.ts:7 load it |
anchor.workspace.Sickle | tests/support/sickle-context.ts:64 | How the legacy-validator suite gets its Program |
| camelCase account names | common-accounts.ts:16-20 | Anchor renames token_2022_program to token2022Program. Account decoders use globalConfig, not GlobalConfig |
eventCpiAccounts | common-accounts.ts:110-120 | Adds eventAuthority and program to every map for an instruction that emits an event. The test context has its own copy at tests/support/sickle-context.ts:83-89 |
How a call flows through it
This follows one keeper Orca rebalance as scripts/canary-intent.ts runs it.
Transaction A carries the owner's signed limits. Transaction B does the work.
- The canary reads pool, position, global config, settings, mint owners, and
transfer fees in one slot context.
scripts/builder/intent.ts:510-606 - It derives the exact new tick range from the live tick and the settings
shape.
scripts/canary-intent.ts:942-947,scripts/builder/orca.ts:894 - It plans the withdrawal floors, the post-fee balances, and the swap
direction.
scripts/builder/intent.ts:826-881 - If a swap is needed it fetches one Jupiter quote and freezes it with a slot
window and the exact slippage floor.
scripts/builder/flows.ts:193-224,scripts/builder/jupiter-api.ts:61 - It builds the authorization: 2 pool vaults as assets, the swap edge, the
floors, the window, the nonce. It sorts the assets and edges and checks the
canonical rules.
scripts/builder/intent.ts:289-392,scripts/builder/intent-codec.ts:257-426 - It computes the digest over prefix, version, program, domain PDA, domain
value, and payload.
scripts/builder/intent-codec.ts:433-452 - It composes transaction B from the same snapshot and frozen quote:
rebalance_for, the optional keeper swap,orca_increase_liquidity, andfinalize_intent. The Orca adapter owns the venue legs and the shared core validates/builds the signed swap.scripts/builder/intent.ts:1434-1603,scripts/builder/clmm-intent-composer.ts:110-209 - Each instruction maps its accounts through a resolver and the Anchor client.
scripts/builder/accounts.ts:773-792,scripts/builder/instructions.ts:912-943 - The owner or session key signs the digest, and transaction A becomes
[ed25519 verify, preauthorize_intent].scripts/builder/intent.ts:400-433,scripts/builder/intent-codec.ts:460-495 - A cancellation for the same nonce is built.
scripts/builder/instructions.ts:731 - All 3 packets are signed on one blockhash, fetched lookup tables are
checked, and each packet is measured against the wire limit. Then the
window and the quote age are checked one last time.
scripts/builder/intent-packets.ts:66-170 - A is sent and confirmed, then B. On any failure the cancellation is sent and
the authorization PDA must be absent.
scripts/builder/intent-packets.ts:223-266
Invariants the layer owns
- An owner composer never composes a keeper flow.
composeRebalanceandcomposeRaydiumRebalancethrow whenkeeperis set.scripts/builder/flows.ts:263-267,scripts/builder/raydium-flows.ts:171-175. - A standalone swap instruction never carries automator accounts.
buildJupiterSwaprejectskeeperandposition.scripts/builder/instructions.ts:467-473. - An authorization reaches the signer only in canonical form. The codec sorts
and then applies every rule of
validate_canonical, with a plainErrorper rule.scripts/builder/intent-codec.ts:257-426. - Every swap output asset carries a positive floor. The codec rejects a zero
minOuton an edge output.scripts/builder/intent-codec.ts:322-329. - A frozen quote is exact.
assertFreshIntentQuoterequiresminAmountOut === applySlippage(quotedOut, bps, "min")and a slot inside the window.scripts/builder/flows.ts:168-190. - A composer refuses a snapshot that disagrees with the signed authorization.
Withdrawal floors, edge direction, input cap, output floor, position, and
action are compared. Venue adapters check snapshot identity; the shared
core checks authorization and swap bounds.
scripts/builder/intent.ts:1486-1496,scripts/builder/clmm-intent-composer.ts:26-75,scripts/builder/clmm-intent-composer.ts:110-209. - Nothing is quoted, planned, or fetched after transaction A. The freeze does
the last RPC read before A and the executor only sends and confirms.
scripts/builder/intent-packets.ts:149-169,scripts/builder/intent-packets.ts:223-266. - A packet never exceeds the wire limit.
assertPacketFitthrows with the measured size.scripts/builder/send.ts:294-314,scripts/builder/intent-packets.ts:92-98. - A route never exceeds its ceiling.
jupiterSwapLegFromApithrowsJupiterRouteLimitErroron data bytes or account count.scripts/builder/jupiter.ts:372-387. - The Sickle PDA is never marked a signer in a Jupiter route.
scripts/builder/jupiter.ts:391-398. - A landed program error is never retried. The single-attempt helper throws
on
confirmation.value.err, andisRetriableErrorreturns false forcustom program error,InstructionError, andsimulation failed.scripts/builder/send.ts:153-180,scripts/builder/send.ts:344-369. - A keeper session key is never the executor. The codec rejects
sessionSigner === executor.scripts/builder/intent-codec.ts:403-407. - The management server never signs.
/api/txreturnsserialize({ requireAllSignatures: false })bytes. The browser adds local position-mint signatures and then the wallet signature.management-ui/src/lib/server/tx.ts:223-233,management-ui/src/lib/wallet/wallet.svelte.ts:143-185. - A digest signature is re-verified on the server before transaction A is
assembled.
management-ui/src/lib/server/intent.ts:681-684. - A disabled feature returns 403 before the body is parsed further.
management-ui/src/routes/api/tx/+server.ts:316-324,management-ui/src/lib/server/runtime.ts:139-163. - The RPC proxy forwards only 4 methods.
management-ui/src/routes/api/rpc/+server.ts:9-14.
Limits
| Limit | Value | Where |
|---|---|---|
| Packet size | 1232 bytes | scripts/builder/send.ts:286 |
| Authorization payload | 663 bytes | scripts/builder/intent-codec.ts:123-138 |
| Assets per authorization | 3 | scripts/builder/intent-codec.ts:29 |
| Swap edges per authorization | 2 | scripts/builder/intent-codec.ts:31 |
| Dust, any action | 5000 bps | scripts/builder/intent-codec.ts:35 |
| Dust, compound | 100 bps | scripts/builder/intent-codec.ts:36 |
| Default authorization validity | 150 slots | shared/intent-timing.ts:2 |
| Send margin before expiry | 20 slots | shared/intent-timing.ts:8 |
| Quote age | 20 slots | shared/intent-timing.ts:5 |
| Single-swap route data | 280 bytes | scripts/builder/jupiter.ts:296 |
| Route accounts | 40 | scripts/builder/jupiter.ts:297 |
| Orca keeper rebalance route data | 204 bytes | scripts/builder/jupiter.ts:301 |
| Raydium keeper rebalance route data | 222 bytes | scripts/builder/jupiter.ts:302 |
| Multi-swap route data, accounts | 130 bytes, 24 | scripts/builder/jupiter.ts:303-304 |
Quote maxAccounts | 26 | scripts/builder/jupiter.ts:352-354 |
| Raydium keeper heap frame | 256 KiB | scripts/builder/jupiter.ts:315 |
| Heap frame range | 32 to 256 KiB | scripts/builder/send.ts:37-39 |
| Compute budget, every CLMM action | 1,400,000 CU | scripts/builder/budgets.ts:20-33 |
| Retry attempts, base delay, cap | 3, 500 ms, 10,000 ms | scripts/builder/send.ts:63-68 |
| Keeper RPC deadline | 10,000 ms | scripts/keeper/rpc-connection.ts:4 |
| RPC proxy body, response | 256 KiB, 4 MiB | management-ui/src/routes/api/rpc/+server.ts:16-17 |
| RPC proxy batch, concurrency, timeout | 10, 16, 10,000 ms | management-ui/src/routes/api/rpc/+server.ts:18-20 |
| RPC proxy rate | 30 requests per 10,000 ms | management-ui/src/routes/api/rpc/+server.ts:21-22 |
| Coordination state TTL, entries | 300,000 ms, 128 | management-ui/src/lib/server/meteora-coordination-state.ts:64-65 |
Tests
The routine check is anchor test --validator legacy. It runs
tests/**/*.ts minus tests/mainnet-acceptance.ts on a
solana-test-validator with 8 cloned mainnet accounts. Anchor.toml:28,
Anchor.toml:47-69. The Surfpool scripts run 3 fork processes.
Anchor.toml:29-32. CI runs yarn test:keeper-runtime without a validator
and the 3 Surfpool scripts after the legacy run. .github/workflows/ci.yml:114,
.github/workflows/ci.yml:218-244.
| Kind | Files | Covers | Needs |
|---|---|---|---|
| Pure unit, builder | builder.ts, builder-accounts.ts, builder-alt.ts, builder-canary-session.ts, builder-clmm-intent-composer.ts, builder-common-accounts.ts, builder-compound-credit.ts, builder-compound-intent.ts, builder-dry-run.ts, builder-executor-authorization.ts, builder-fees.ts, builder-finalize-intent.ts, builder-flows.ts, builder-intent.ts, builder-intent-alt.ts, builder-intent-cleanup.ts, builder-intent-packets.ts, builder-intent-timing.ts, builder-jupiter.ts, builder-raydium.ts, builder-raydium-intent.ts, builder-send.ts, builder-transfer-fees.ts, builder-zap.ts, offchain-boundaries.ts | PDAs, decoders, account key sets against the IDL snapshot, math, codec vectors, timing policy, packet budgets, composer arguments with a recording program, stubbed RPC | nothing |
| Pure unit, Meteora builder | builder-meteora.ts, builder-meteora-flow.ts, builder-meteora-driver.ts, builder-meteora-intent.ts, builder-meteora-packets.ts | Layout fixture, chunking, account maps, owner steps, driver snapshot, DLMM codec vectors, 1,400-bin packet | nothing |
| Pure unit, keeper | keeper-sim.ts, meteora-keeper-runtime.ts, meteora-keeper-rpc-collector.ts, meteora-keeper-live-adapter.ts, meteora-keeper-alerts.ts, meteora-keeper-observe-soak.ts, meteora-keeper-canary-adapter.ts, meteora-ui-acceptance-adapter.ts, meteora-pair-admission.ts | decide.ts and decode.ts against state.rs and orca.rs, runtime store and loop with stubbed RPC, collector, adapter, Prometheus rules, admission registry | nothing. 2 files read process.env for artifact paths |
| Pure unit, acceptance tooling | acceptance-artifact-unit.ts, acceptance-closeout-unit.ts, acceptance-coverage-unit.ts, acceptance-guards-unit.ts, acceptance-matrix-unit.ts, mainnet-meteora-acceptance-unit.ts, mainnet-meteora-closeout-unit.ts, deploy-provenance-unit.ts, orca-pool-fixture-unit.ts, rpc-relay-hardening-unit.ts | Spend guard, coverage ledger, artifact hash, matrix document, pool fixture bytes | nothing |
Helper modules, no it | acceptance-artifact.ts, acceptance-coverage.ts, acceptance-guards.ts, orca-pool-fixture.ts, surfpool-helpers.ts, mainnet-meteora-acceptance.ts, support/sickle-context.ts | Shared code the specs import | loaded by the glob, run nothing |
| Legacy validator | sickle.ts registers sickle/core.ts, sickle/orca.ts, sickle/jupiter.ts, sickle/intents.ts, sickle/raydium.ts, sickle/raydium-fork.ts, sickle/orca-fork.ts, sickle/orca-lifecycle.ts | Every instruction against the built program, authorization flow, events, a local Orca pool | anchor test --validator legacy |
| Surfpool mainnet fork | surfpool-lifecycle.ts, surfpool-t22-lifecycle.ts, surfpool-jupiter.ts, surfpool-raydium-lifecycle.ts, surfpool-t22-raydium-lifecycle.ts, surfpool-meteora-lifecycle.ts | Funded lifecycles on live pools with cheatcodes, keeper flows, Token-2022 pools, Meteora compute limits | Surfpool. Each self-skips on a legacy validator through isSurfnet. tests/surfpool-helpers.ts:50 |
| Mainnet, real funds | mainnet-acceptance.ts with mainnet-meteora-acceptance.ts as phase 15 | The deployed artifact, config, allowlist, and every instruction, or an explicit skip with a reason | scripts/deploy/acceptance.sh, excluded from the glob. Anchor.toml:28 |
Fixtures shared with Rust.
| Fixture | Rust reader | TypeScript readers |
|---|---|---|
tests/fixtures/intent-vectors.json | programs/sickle/src/intent.rs:3380 | tests/builder-intent.ts, management-ui/src/lib/sickle/intent.test.ts:35, scripts/dev/gen-intent-vectors.ts |
tests/fixtures/meteora-intent-vectors.json | programs/sickle/src/intent.rs:3425 | tests/builder-meteora-intent.ts, management-ui/src/lib/sickle/meteora-intent.test.ts, scripts/dev/gen-meteora-intent-vectors.ts |
tests/fixtures/meteora-dlmm-layout.json | programs/sickle/src/meteora.rs:2123 | tests/builder-meteora.ts, management-ui/src/lib/dlmm/meteora.ts, management-ui/src/lib/dlmm/pdas.ts |
The management UI has 62 vitest files under management-ui/src/ (61 before this change; src/lib/server/input.test.ts is new). One of
them, management-ui/src/lib/sickle/builder-parity.test.ts, compares the UI
encoders with scripts/builder/pdas.ts, jupiter.ts, and transfer-fees.ts
byte for byte.
Gaps.
composeRaydiumRebalanceruns only intests/builder-transfer-fees.ts:838with a recording program. No validator or fork test sends its output.decide.tsdoes not modelvalidate_rebalance_progressprograms/sickle/src/state.rs:723or the placement check.tests/keeper-sim.tshas no case forRebalanceNoOporInvalidRangePlacement.- The shared send transport is unit-tested with a stubbed
Connection, but no validator or fork test sends through it. Only mainnet acceptance and the canaries use that path live. ensureLookupTableandensurePersistentLookupTablerun only in the validator and fork suites.surfpool-jupiter.tsself-skips when the Jupiter API is unreachable.tests/surfpool-jupiter.ts:271-279. A network fault reads as a pass.
Simplification and audit notes
L10-N007 — Retirement boundary and duplication across repositories. The legacy management UI does not import
scripts/builder/. It carries a second implementation of 7 modules. The PDAs are atmanagement-ui/src/lib/sickle/orca-tx.ts:36-104. The tick and liquidity math is atmanagement-ui/src/lib/sickle/orca.ts:329-503. The Raydium tick math is atmanagement-ui/src/lib/sickle/raydium.ts:299-355. The fee math is atmanagement-ui/src/lib/sickle/fees.ts:11-19. The transfer-fee math is atmanagement-ui/src/lib/sickle/transfer-fees.ts:97-113. The swap planner is atmanagement-ui/src/lib/sickle/jupiter.ts:83-282. The authorization codec is atmanagement-ui/src/lib/sickle/intent.ts:175-425. The UI comments say so atorca.ts:2-3,raydium.ts:2,jupiter.ts:1,fees.ts:2.builder-parity.test.ts:1-25states that nothing else checks the claim. That test covers PDAs, admin encoding, discriminators, transfer fees, and Jupiter. It does not cover the tick or liquidity math, the account maps of the Orca and Raydium position instructions, or the codec. The codec rests on the shared vectors alone. The HTTP app is not served:deploy-restricted.sh:59-80recognizes the authoritativesickle-sol-uimarker and exits without rebuilding or repointing traffic. Two selected server modules remain production inputs through the canary adapter imports cited at the start of this page, so deleting the whole tree is not yet safe. A shared live off-chain core would have to include the sibling repository; extracting only against this legacy copy would solve the wrong boundary.L10-N008 — Duplication inside the legacy UI. PDA derivation appears in
management-ui/src/lib/server/solana.ts:62-80,management-ui/src/lib/server/tx.ts:44-48,management-ui/src/lib/sickle/orca-tx.ts:36-104,management-ui/src/lib/sickle/intent.ts:458-507, andmanagement-ui/src/lib/dlmm/pdas.ts:31-40.L10-N009 — Very long functions.
MeteoraKeeperRuntimescripts/keeper/meteora-runtime.ts:1837-2824is 988 lines.MeteoraKeeperRuntimeStoremeteora-runtime.ts:669-1800is 1132 lines.createMeteoraKeeperRpcCollectorscripts/keeper/meteora-rpc-collector.ts:667-1312is 646 lines. The/api/txPOSThandlermanagement-ui/src/routes/api/tx/+server.ts:314-935is 622 lines with 2switchstatements over the samebody.action.planIntentmanagement-ui/src/lib/server/intent.ts:281-645is 365 lines.planRebalanceSwapscripts/builder/jupiter.ts:139-258is 120 lines.L10-N010 — Error handling is inconsistent. The builder throws
Errorin most places,RangeErrorinsend.ts:71-79andintent.ts:1074-1089, and 4 custom classes:JupiterRouteLimitErrorjupiter.ts:268,InvalidProtocolAccountDatascripts/builder/protocol-account.ts:2,DryRunSealBreachdry-run.ts:64,MeteoraOwnerPacketRejectedmeteora-flow.ts:466.buildJupiterSwapreturnsPromise.rejectinstructions.ts:467-473whilebuildFinalizeIntentthrows synchronouslyinstructions.ts:821-823.isRetriableErrorclassifies by substring match on the message textsend.ts:153-180./api/txmaps every thrownErrorto HTTP 422, including a programming errorapi/tx/+server.ts:931-934.L10-N011 — Comment does not match code.
management-ui/README.md:68says the RPC proxy passessendTransactionandsimulateTransaction. The allowlist atmanagement-ui/src/routes/api/rpc/+server.ts:9-14hasgetAccountInfo,getSignatureStatuses,getTransaction, andsendTransactiononly.L10-N012 — Comment does not match code.
scripts/builder/zap.ts:5-10says the program requires the add-liquidity instruction through the Instructions sysvar withMissingZapInLeg.programs/sickle/src/errors.rs:96still declares the variant, and no handler raises it.tests/sickle/orca.ts:2338-2341records that the authorization ledger replaced it.L10-N013 — Comment does not match code.
scripts/builder/instructions.ts:166is a one-line doc comment fororca_open_positionfollowed by theTransferHookAccountsdoc block.buildOpenPositionatinstructions.ts:226has no doc comment.L10-N014 — Off-chain copy is incomplete.
evaluateRebalancescripts/keeper/decide.ts:87-123mirrorsvalidate_rebalance_forprograms/sickle/src/state.rs:586-687but notvalidate_rebalance_progressstate.rs:723or the placement check. The header atdecide.ts:5-10says it predicts the exact on-chain error.L10-N015 — Anchor
nullfor an optional account.resolveIncreaseLiquidityAccountsreturnsnullforglobalAutomator,positionSettings, andactionIntentscripts/builder/accounts.ts:258-266. The comment inscripts/builder/executor-authorization.ts:8-11explains that Anchor then emits the program ID as a sentinel. A reader ofaccounts.tsalone does not see that.L10-N016 — Test self-skips. The 6 Surfpool files return early on a legacy validator
tests/surfpool-lifecycle.ts:747-753,tests/surfpool-meteora-lifecycle.ts:872-875.tests/surfpool-jupiter.ts:271-279also skips on any Jupiter transport failure.tests/mainnet-acceptance.tsrecords 47ledger.skipcalls with reasons in its ledger. A green legacy run proves nothing about those files.L10-N017 — Missing execution tests. See the remaining gaps under Tests:
composeRaydiumRebalance, the shared send transport, and the lookup-table creation path.L10-N019 — A registry that looks like a gate gates nothing. The Meteora pair admission registry evaluates pairs as executable or not
scripts/meteora-pair-admission.ts:1-24. No keeper, runtime, or UI code reads it. Only its report script and its test read it. The keeper and the UI act on pairs through their own hard-coded constants instead. Its v1 recorddocs/release-evidence/meteora-pair-admission-v1.jsonbounds ADX-USDC at 56 bins. The program now allows at most 55 on that pair, so the record evaluates as not executable. No path acts on that result.L10-N020 — Some UI checks compare a width with the wrong limit. The program limits a keeper action to f of the pair's initialized reward slots: 55, 55, or 48 bins. Three management UI surfaces compare with the structural 55 instead. The settings encoder does it at
management-ui/src/lib/sickle/settings-tx.ts:275,:358, and:430. The economics snapshot does it atmanagement-ui/src/lib/sickle/meteora-economics.ts:215andmanagement-ui/src/lib/server/meteora-economics.ts:262. The action preparation does it atmanagement-ui/src/lib/server/meteora-action-preparation.ts:330. On the one admitted pair, ADX-USDC, 55 is also f(1), so today the result is correct. If that pair initializes a second reward slot, f drops to 48. These surfaces then accept settings of 49 to 55 bins that the program rejects in transaction B. The user sees valid settings, and the keeper holds the rows. The fix is to compare withmeteoraDlmmIntentMaxWidth(pair), as the readiness check and the intent composers already do. The review of pull request 297 found this.
Resolved
L10-R001 — The six Orca and Raydium keeper composers repeated authorization action, venue-position, expiry-margin, withdrawal-floor, and signed-edge guards. Four repeated the same optional single-swap validation/build block, and the two exit composers repeated the same zero-to-two target-swap pipeline. Those shared rules now live in
clmm-intent-composer.ts; the venue adapters retain their distinct snapshot predicates, economic planners, account maps, drain/re-add instructions, output names, and Raydium heap requirement. The oldSEND_MARGIN_SLOTSimport remains available throughintent.ts. The focused composer and transfer-fee suites pin instruction order, mixed token programs, fee math, post-swap arithmetic, and both swap directions; the source-level boundary test also requires all six wrappers to call the shared guards and appropriate swap composer. A direct shared-composer suite now pins every migrated guard, current-slot quote freshness, the optional no-swap path, zero-leg rejection, strict signed limits, cumulative exit floors, and lookup-table propagation. Focused Orca and Raydium compound, rebalance (with and without a swap), and exit cases pin the returned venue/swap/re-add/finalize order. The Orca exit cases also run both in-kind and target-swapcomposeIntentExitpaths offline with mixed token programs. The zero-amount frozen-leg branch was removed as unreachable because the now directly tested quote validation rejects a zero-sized leg.L10-R002 — The Orca and Raydium owner-rebalance composers independently estimated the drain, loaded the protocol fee, applied transfer fees, planned and built an optional Jupiter swap, derived conservative post-swap balances, sized the re-add, ordered the three legs, and propagated route lookup tables. Those decisions now live once in
clmm-owner-rebalance.ts. Each venue wrapper loads its own accounts, maps A/B or 0/1 into the shared pair, and supplies only its drain and increase builders.SwapLegFetchermoved with the shared policy and remains re-exported fromflows.tsfor compatibility. The existing 12 owner fee/swap cases pin both adapters; a source-level test also requires each wrapper to call the shared composer exactly once and forbids it from re-importing the extracted policy helpers.L10-R003 — Six TypeScript exports had no importer in
scripts/,tests/,shared/, ormanagement-ui/src/, and this private package exposes no package entrypoint. The declarations and their orphaned imports are removed. The three composerconnectionparameters retain their call positions as_connection, following the existing exit-composer convention; unused drain-credit destructures, Sickle aliases, and theflows.tsvalue alias are removed. TypeScript compilation and the existing builder and keeper suites preserve the reachable account, instruction, and packet behavior.L10-R004 — Orca, Raydium, and Meteora separately derived the same Sickle, global config, pool-token, and fee-collector accounts, while the two CLMM resolvers separately built the same three optional intent slots. Resolved by moving those derivations, the event-CPI pair, and shared account-coder names into
scripts/builder/common-accounts.ts. Venue adapters retain only their intentional A/B, 0/1, and X/Y output names, andaccounts.tsre-exports its old public names for compatibility.tests/builder-common-accounts.tsdirectly pins the shared contract; the existing Orca, Raydium, and Meteora suites still pin every public resolver map. Their mutation check rejected a side-1 ATA derived with side 0's token program in four independent tests.L10-R005 — The keeper's narrow Orca decoder and the builder's full decoder both read the Whirlpool tick spacing and live tick, while the builder imported the position decoder and shared error upward from
scripts/keeper/. Resolved by makingscripts/builder/orca.tsthe one owner of Orca account layouts: the narrow and full pool decoders share one field reader, every position decoder shares one core reader, and the keeper now imports those builder decoders. The venue-neutral error lives inprotocol-account.ts, used by both Orca and Raydium.tests/offchain-boundaries.tswalks every builder TypeScript import and fails if the reverse dependency returns; its mutation check caughtprotocol-account.ts -> ../keeper/decidebefore this text was written.L10-R006 — The UI coordinator generated and cached a replacement-position keypair it never used to sign, while the keeper independently generated a second keypair for the same logical role. Resolved by eliminating both secrets. The destination is now the PDA
[b"dlmm_intent_position", sickle, nonce_le];meteora_rebalance_forandmeteora_intent_open_positionindependently require it, and the open handler supplies its signer privilege only throughinvoke_signed. The keeper packet is signed only by its ordinary service identity. The UI's bounded state retains the unsigned authorization draft, but no private key, and a stored authorization remains reconstructible after a server restart.L10-R007 —
buildFinalizeIntentandbuildFinalizeDlmmIntentduplicated the same non-exit and exit remaining-account grammar, while their account resolvers duplicated every fixed key except the authorization PDA name. The two public builders are now thin wrappers overfinalizeIntentRemainingAccountsthat keep the family-specific discriminators and mismatch errors. The two public resolvers now shareresolveFinalizeCommonAccounts, with a callback that inserts the typed authorization key at its original position. A focused offline suite pins every fixed key to its absolute expected address, both remaining-account forms, and both errors, while the source-level boundary test requires both public families to keep calling the shared cores.L10-R008 —
sendFrozenPacketandsendWithRetryduplicated raw submission, blockhash-lifetime confirmation, and landed-error handling even though their retry policies intentionally differ. That one-attempt boundary now lives insendAndConfirmTransactionBytes. Frozen A, B, and cancellation packets each call it once without refreshing their reviewed bytes;sendWithRetrykeeps the blockhash refresh, re-sign, backoff, and transient-error classification around it. Stubbed-RPC tests pin the exact bytes and lifetime, default and overridden transport options, landed failure, fresh signature on retry, and terminal no-retry path. The packet-orchestration suite continues to prove an uncertain A failure goes straight to the pre-frozen cancellation, while the source-level boundary test requires both callers to use the shared helper.L10-R009 — Intent authorization timing was independently copied between the root builder, packet executor, management server, and browser form. The three defaults now live in dependency-free
shared/intent-timing.ts; thin builder and UI modules preserve the old public import paths. The packet freeze uses the shared send margin instead of a literal, Meteora coordination imports validity directly instead of through the server intent module, and the form derives its string default from the shared bigint. Root and UI unit tests pin the three values and compatibility exports, while the source-level boundary test requires every consumer to import the shared policy. The send tests now also pin both callers' exact blockhash lifetime, commitment, and preflight options. Live transport remains an explicit acceptance/canary coverage gap.L10-R010 — Four API routes carried local public-key parsers, and the transaction and intent routes separately parsed non-negative amounts. Those request primitives now live in
management-ui/src/lib/server/input.ts:4-40. Public keys and amounts intentionally require JSON strings. The explicit key type guard is defense in depth relative to the shared parser introduced by the extraction, which already stringified and rejected non-string JSON keys. The extraction itself tightened the older transaction-route parser, which passed non-string values directly toPublicKeyand accepted some of them. The amount rule intentionally tightens the old contract: it prevents already-rounded JSON numbers above JavaScript's safe-integer range from silently changing instruction data, accepts only canonical unsigned decimal strings, and rejects values aboveu64::MAX. Empty, padded, whitespace, signed, fractional, and radix-prefixed forms all fail with HTTP 400. All in-repo callers already send canonical decimal strings; valid request behavior is unchanged.parseRequiredKeypreserves the Meteora owner-step routes' distinct missing-value error before delegating to the same key parser. The shared tick parser also replaces the Orca and Raydium deposit paths'?? NaNbypasses atmanagement-ui/src/routes/api/tx/+server.ts:701-771, so every CLMM tick request fails with the same HTTP 400 contract. The focused suite pins string-only values and both error shapes, requires all four routes to import the shared module, checks every Meteora owner-step key, and checks each deposit case independentlymanagement-ui/src/lib/server/input.test.ts:30-123. The transaction-route header now describes its admin, intent, and protocol-management scope.L10-R011 — Two offline Meteora suites loaded the ignored build IDL while the other builder specs used the checked-in snapshot.
builder-meteora-flow.tsandbuilder-meteora-driver.tsnow use the snapshot too, so their runtime no longer depends onanchor buildhaving populatedtarget/idl. The source-level boundary suite walks every TypeScript spec's direct imports and rejects any dependency on the ignored IDLtests/offchain-boundaries.ts:373-396; reverting either import makes that guard fail. Generatedtarget/typesremain a typecheck input, not a runtime IDL source.L10-R012 — The Orca and Raydium coherent intent snapshot loaders decoded
GlobalConfigandPositionSettingsthrough raw account coders and erased the generated account types withas any, including the earlier settings fetches.decodeSickleSnapshotAccountnow maps the two runtime coder names toanchor.IdlAccounts<Sickle>once incommon-accounts.ts. Both venue loaders keep the same raw buffers from their single-context account reads but use the typed helper for all four frozen decodes and typed Anchor fetch results. A source-level test pins both account mappings, four helper calls per venue, and rejects raw coder calls oras anyin either loadertests/offchain-boundaries.ts:181-209. The helper documents the caller's owner check, the generated exit-token keys now flow without redundantPublicKeycasts, and all builder references to the generatedSickletype are explicit type-only imports; a second boundary case enforces that import contracttests/offchain-boundaries.ts:254-281. Typecheck and the existing compound and rebalance suites preserve behavior.L10-R013 — The Orca keeper rebalance wrapper forced
withSettings: true, then re-derived and overwrote the same old/new settings PDAs already returned byresolveRebalanceCommon; the Raydium wrapper carried the identical dead override. Both wrappers now re-export the common resolver's values with non-null assertions solely to preserve the account type required byaccountsStrictscripts/builder/accounts.ts:743-762,scripts/builder/raydium-accounts.ts:706-728. The source boundary requires each wrapper to force settings, forbids a secondpositionSettingsPdacall, and pins both re-exported valuestests/offchain-boundaries.ts:211-252. The Orca and Raydium unit suites independently pin both returned settings addressestests/builder-accounts.ts:523-537,tests/builder-raydium.ts:921-926. The program must still validate the required keeper settings because transactions are untrusted; that on-chain boundary is not removable duplication.L10-N018 — A compute check depended on live mainnet state. The Meteora Surfpool test compared three measured compute figures with caps 1,400 CU above each measurement. The fork read the ADX-USDC pair and its bin arrays from mainnet, and one code path measured 3,866 CU and 5,056 CU apart on two days. Resolved by pinning that state, not by widening the allowance. The test writes the accounts in
tests/fixtures/meteora-acceptance-state.json, captured at one mainnet slot, before it measurestests/surfpool-helpers.ts:237-273. It also refuses to measure a transaction that names a Meteora account outside the pinned set or the accounts that the test createstests/surfpool-meteora-lifecycle.ts:1442-1484. That refusal stops a later flow from reading live state again without notice.Throwaway pull requests 300 to 303 show both properties. Each branch changed the test or the program on top of the fix, ran CI, and was closed without a merge. The figures are compound / rebalance / exit in CU. The pinned figures are 850,547 / 1,141,737 / 593,730.
Run Figures Result 300: one more address derivation 850,547 / 1,143,266 / 593,713 Fails: 129 over the cap 302: light changed state, no pin 850,724 / 1,141,807 / 593,730 +177 / +70 / 0 301: light changed state, then the pin 850,547 / 1,141,737 / 593,730 Equal to the pin 302: strong changed state, no pin 850,621 / 1,120,640 / 593,713 +74 / −21,097 / −17 301: strong changed state, then pin 850,547 / 1,141,737 / 593,713 Pin, exit −17 303: strong, no pin, two-sided check 850,621 / 1,120,640 / 593,713 Fails: below the lower end 299 at 6443f51, after an outage850,547 / 1,141,737 / 593,730 Equal to the pin 299 at 57e07b9, the next day850,547 / 1,141,768 / 593,713 +0 / +31 / −17 The light change multiplies bin amounts and liquidity by 1.5 and increases the fee accumulators and the volatility. The strong change also empties every other bin and adds 2^120 to each fee accumulator. The strong change without the pin moves rebalance by about 4 times the largest measured daily drift. Pull request 303 ran it twice and measured the same 1,120,640 both times. The two runs of pull request 299 are the first pinned runs apart in time: hours for
6443f51and about one day for57e07b9. They are not the week that the note asks for.Under the pin the figures agree within tens of CU. They are not always equal. Rebalance moved 31 CU and exit 17 CU with no code change. The likely cause is the number of digits in logged amounts. That is a hypothesis with some support: compound once moved 31 CU the same way, and no movement is a multiple of the 1,500 CU cost of one bump candidate. It is not a proven mechanism.
The claim does not rest on a sample. The test overwrites each account that it reads, and the refusal enforces that. A later change made the check two-sided. Each figure must now stay within 1,400 CU of its pinned value in both directions
tests/surfpool-meteora-lifecycle.ts:194-210. The earlier check allowed any decrease. With the pin, only a code change can move a figure by more than the residue, and a decrease is a change too. The two upper ends are the old caps without change, so the new check only adds a lower end. A later run on another day therefore needs no human check. Normal CI runs this test on each pull request that changes code. If the pin is incomplete, a figure moves and CI fails in either direction. A figure outside the band is a finding to report. After a deliberate optimization, set the figure again from CI in the same change. The residue sets a lower limit on the allowance. Do not make the band as small as about 100 CU, because it would then fail with no code change. Whether a flow fits is a separate check, the worst-work margin in the same test.
Related
- Entry points
- Venue bindings, the on-chain decoders the builder mirrors.
- State and settings, the checks
decide.tsmirrors. - Keeper authorization, the on-chain side of the codec and the finalizer.
- Dependency graph, section 8.