Venue adapters
This layer implements the runner traits for each concrete Orca and Raydium account struct, so one runner can serve both venues.
Every fact on this page comes from programs/sickle/src/venue/adapters/ and
the files it imports, read on 2026-09-09. Line numbers are path:line under
programs/sickle/src/. Meteora has no adapter in this directory. Its four
keeper structs get the yield trait from one macro in
instructions/meteora/yield_adapter.rs.
Where an implementation is the same for every account struct that carries the
same fields, it is written once as a macro and invoked per struct. The two
macros both venues use live in mod.rs. The rest live in the file of the venue
they serve. Every macro added for that purpose carries a doc comment naming what
varies between its call sites. The four pre-existing yield macros carry none.
Note: a /// block binds to the item below it, so inserting a macro directly
above another macro's definition silently moves that block onto the new macro.
Check the doc comment of the macro above and below after any such insertion.
Files
| Path | Lines | Purpose |
|---|---|---|
venue/adapters/mod.rs | 138 | Re-exports 9 request and prepared-state types, and holds the 2 macros both venues use. |
venue/adapters/orca.rs | 1977 | Trait implementations for the 11 Orca account structs. 1,711 before its test module. |
venue/adapters/orca_flows.rs | 1331 | The ordered Orca CPI legs orca.rs drives, and the account bundles they take. |
venue/adapters/raydium.rs | 1723 | Trait implementations for the 10 Raydium account structs. |
venue/adapters/raydium_flows.rs | 1506 | The ordered Raydium CPI legs raydium.rs drives, and the account bundles they take. |
orca.rs has a #[cfg(test)] module (adapters/orca.rs:1688). raydium.rs
has none; see L04-N019.
Responsibilities
- Give the runner a stable identity for the flow: authority, Sickle, venue, venue program, pool, position, mints.
- Expose the optional accounts the runner needs: the global keeper record, the position settings, the intent accounts.
- Check the venue accounts the account struct left unchecked: pool owner, position owner, position PDA, position token account, bitmap PDA.
- Consume
remaining_accountsin the venue's fixed order and return the unused tail. - Build the account bundles for the shared flow helpers.
- Invoke the venue CPI, through a binding builder or through a helper in a handler file.
- Read the post-CPI position state and the vault balance deltas into a receipt.
- Map venue-specific reward outcomes into the runner's receipt types.
Public items
venue/adapters/mod.rs
| Item | Kind | Meaning |
|---|---|---|
OrcaKeeperExitVenueRequest, OrcaKeeperRebalanceVenueRequest, OrcaOwnerRebalanceVenueRequest, OrcaPreparedYield | re-export | The Orca types a handler or a runner names (adapters/mod.rs:13-16). |
RaydiumKeeperExitVenueRequest, RaydiumKeeperRebalanceVenueRequest, RaydiumOpenVenueRequest, RaydiumOwnerRebalanceVenueRequest, RaydiumPreparedYield | re-export | The Raydium types a handler or a runner names (adapters/mod.rs:17-20). |
impl_active_flow_policy! | macro | Writes ActiveFlowPolicy for a flat account struct. Invoked 6 times, 3 per venue (adapters/mod.rs:33-54). |
impl_nested_active_flow_policy! | macro | Writes the same policy for the 4 rebalance structs whose fields now live in shared composites (adapters/mod.rs:56-80). |
keeper_intent_methods! | macro | Writes intent_accounts and intent_assets into a keeper adapter impl. Invoked 4 times, 2 per venue (adapters/mod.rs:94-134). |
venue/adapters/orca.rs
| Item | Kind | Lines | Meaning |
|---|---|---|---|
take_pool_hooks_and_reward_groups | private fn | 71-118 | Splits the pool hook run, the reward token program, and one group per initialized slot. Used by 3 prepares. |
OrcaPreparedYield | struct | 120-124 | Hook lengths, pool hook count, and parsed reward groups for harvest and compound. |
orca_modify_liquidity_infos! | macro | 136-162 | The 15 CPI account infos of ModifyLiquidity, plus the hook tail. Invoked by increase and decrease. |
orca_owner_rebalance_receipt! | macro | 173-216 | Maps a drain outcome into RawDrainFlowReceipt. Invoked by the 3 rebalance and exit flows. |
orca_reopen_receipt! | macro | 224-259 | The body of both reopen methods. |
prepare_orca_yield! | macro | 267-325 | Splits pool hook accounts, then parses reward groups. Used by 2 trait impls. |
claim_orca_yield! | macro | 327-398 | Calls collect_fees_and_charge then collect_orca_rewards_and_charge and maps the receipt. |
OrcaOwnerRebalanceVenueRequest | struct | 401-406 | Metadata flag, hook lengths, reward hook lengths, new settings bump. |
OrcaPreparedOwnerRebalance | struct | 408-420 | Both account bundles, old position snapshot, tick spacing, open args, minimums, hooks, reward groups. |
OrcaKeeperRebalanceVenueRequest | struct | 598-602 | Metadata flag, hook lengths, reward hook lengths. |
OrcaPreparedKeeperRebalance | struct | 604-612 | Both account bundles, open args, minimums, hooks, reward groups. No snapshot. |
OrcaKeeperExitVenueRequest | struct | 838-841 | Hook lengths, reward hook lengths. |
OrcaPreparedKeeperExit | struct | 843-849 | One account bundle, minimums, hooks, reward groups. |
OrcaPreparedOpen | struct | 1171-1173 | The Orca open arguments. |
OrcaPreparedIncrease | struct | 1294-1297 | The Orca increase arguments and the hook account count. |
OrcaPreparedDecrease | struct | 1427-1430 | The Orca decrease arguments and the hook account count. |
OrcaPreparedClose | struct | 1557-1559 | The parsed reward groups. |
keeper_drain_accounts | private fn | 814-819 | Calls orca_drain_accounts_from! for RebalanceFor. |
keeper_reopen_accounts | private fn | 822-835 | Builds OrcaReopenAccounts from RebalanceFor on the heap. |
keeper_exit_drain_accounts | private fn | 1003-1014 | Calls orca_drain_accounts_from! for ExitFor. |
venue/adapters/orca_flows.rs
The legs orca.rs calls: the drain, collect, reward-claim and reopen CPIs,
their account bundles, and the derivation checks around them. It names no
instruction handler except the OrcaRebalancePosition account struct, which
is the by-design edge every adapter has.
These items lived in three instructions/orca/ handler files until contract 11. orca.rs imported fourteen of them upward, which is the adapter-reaching-
into-handlers edge the dependency graph recorded.
One module rather than three mirroring the files they came from: what they
have in common is that the adapter calls them, and which handler file each sat
in was an accident of writing order. Separate from orca.rs rather than
appended to it only because adapters/orca.rs is already 1,977 lines; the two
are one layer.
| Item | Kind | Lines | Meaning |
|---|---|---|---|
orca_drain_accounts_from! | macro | 97-126 | The 23-field drain bundle. Invoked by the owner builder and both keeper builders. |
drain_accounts | fn | 851-856 | The owner rebalance's bundle. Expands the macro above, like the two keeper builders. |
venue/adapters/raydium.rs
| Item | Kind | Lines | Meaning |
|---|---|---|---|
RaydiumPreparedYield | struct | 60-64 | Parsed reward groups, reward collectors, and the bitmap state. |
PreparedBitmap | private enum | 67-70 | Validated(Option<Pubkey>) or ValidateBeforeClaim. Records when the bitmap check ran. |
raydium_owner_rebalance_receipt! | macro | 81-127 | Maps a drain outcome into RawDrainFlowReceipt. Invoked by the 3 rebalance and exit flows. |
raydium_reopen_receipt! | macro | 135-172 | The body of both reopen methods. |
prepare_raydium_yield! | macro | 220-301 | Runs validate_decrease_accounts, parses reward groups and collectors, and checks the bitmap in one of 3 modes. |
claim_raydium_yield! | macro | 303-387 | Runs a zero-liquidity decrease_liquidity_and_charge and maps the receipt. |
RaydiumOwnerRebalanceVenueRequest | struct | 390-395 | Two tick-array start indices, metadata flag, new settings bump. |
RaydiumPreparedOwnerRebalance | struct | 397-408 | Both account bundles, old position snapshot, tick spacing, open args, minimums, reward groups, collectors. |
RaydiumKeeperRebalanceVenueRequest | struct | 613-617 | Two tick-array start indices, metadata flag. |
RaydiumPreparedKeeperRebalance | struct | 619-626 | Both account bundles, open args, minimums, reward groups, collectors. |
RaydiumKeeperExitVenueRequest | unit struct | 929 | Raydium exit carries no venue-specific request. |
RaydiumPreparedKeeperExit | struct | 931-936 | One account bundle, minimums, reward groups, collectors. |
RaydiumOpenVenueRequest | struct | 1202-1206 | Two tick-array start indices, metadata flag. |
RaydiumPreparedOpen | struct | 1208-1211 | The Raydium open arguments and the bitmap key. |
RaydiumPreparedIncrease | struct | 1371-1374 | The Raydium increase arguments and the bitmap key. |
RaydiumPreparedDecrease | struct | 1507-1511 | Reward groups, bitmap key, decrease arguments. |
assert_keeper_position_nft_account | private fn | 857-874 | Re-runs the token-account constraints the keeper struct dropped. |
keeper_drain_accounts | private fn | 877-882 | Calls raydium_drain_accounts_from! for RaydiumRebalanceFor. |
keeper_reopen_accounts | private fn | 885-926 | Builds RaydiumReopenAccounts from RaydiumRebalanceFor on the heap. |
keeper_exit_drain_accounts | private fn | 1115-1126 | Calls raydium_drain_accounts_from! for RaydiumExitFor. |
venue/adapters/raydium_flows.rs
The mirror of orca_flows.rs: the drain, collect, reward-claim and reopen CPIs
raydium.rs calls, their account bundles, and the checks around them. It names
no instruction handler except the RaydiumRebalancePosition account struct.
All fifteen items moved, which is what the caller table said rather than a
preference. Twelve had exactly one code reference outside their home file and it
was the adapter; two more were used only from inside
collect_drain_charge_close_with_actions, which moved with them; and
RewardCharge was never used in the file that defined it.
Both #[cfg(test)] modules came too, renamed for what they cover. A unit test
belongs beside what it tests, and leaving them would have created a test-only
upward edge -- the kind that gets waved through because it is "only tests".
| Item | Kind | Lines | Meaning |
|---|---|---|---|
raydium_drain_accounts_from! | macro | 95-128 | The drain bundle. Invoked by the owner builder and both keeper builders. |
drain_accounts | fn | 763-768 | The owner rebalance's bundle. Expands the macro above, like the two keeper builders. |
Trait implementations in adapters/orca.rs
| Trait | Account struct | Lines |
|---|---|---|
ActiveFlowPolicy | OrcaRebalancePosition | 422-427 |
OwnerRebalanceFlowAdapter | OrcaRebalancePosition | 429-595 |
ActiveFlowPolicy | RebalanceFor | 614-619 |
KeeperRebalanceFlowAdapter | RebalanceFor | 621-812 |
ActiveFlowPolicy | ExitFor | 851 |
KeeperExitFlowAdapter | ExitFor | 853-1000 |
CollectTradingFeesAdapter | OrcaCollectFees | 1016-1067 |
CollectRewardsAdapter | OrcaCollectRewards | 1069-1121 |
ClaimAllYieldAdapter | HarvestFor | 1123-1144 |
ClaimAllYieldAdapter | CompoundFor | 1146-1167 |
ActiveFlowPolicy | OrcaOpenPosition | 1169 |
OpenFlowAdapter | OrcaOpenPosition | 1175-1286 |
ActiveFlowPolicy | OrcaIncreaseLiquidity | 1288-1292 |
IncreaseFlowAdapter | OrcaIncreaseLiquidity | 1299-1425 |
DecreaseFlowAdapter | OrcaDecreaseLiquidity | 1432-1555 |
CloseFlowAdapter | OrcaClosePosition | 1561-1686 |
Trait implementations in adapters/raydium.rs
| Trait | Account struct | Lines |
|---|---|---|
ActiveFlowPolicy | RaydiumRebalancePosition | 410-415 |
OwnerRebalanceFlowAdapter | RaydiumRebalancePosition | 417-610 |
ActiveFlowPolicy | RaydiumRebalanceFor | 628-633 |
KeeperRebalanceFlowAdapter | RaydiumRebalanceFor | 635-854 |
ActiveFlowPolicy | RaydiumExitFor | 938 |
KeeperExitFlowAdapter | RaydiumExitFor | 940-1112 |
ClaimAllYieldAdapter | RaydiumCollectFees | 1128-1149 |
ClaimAllYieldAdapter | RaydiumHarvestFor | 1151-1173 |
ClaimAllYieldAdapter | RaydiumCompoundFor | 1175-1197 |
ActiveFlowPolicy | RaydiumOpenPosition | 1199 |
OpenFlowAdapter | RaydiumOpenPosition | 1213-1363 |
ActiveFlowPolicy | RaydiumIncreaseLiquidity | 1365-1369 |
IncreaseFlowAdapter | RaydiumIncreaseLiquidity | 1376-1505 |
DecreaseFlowAdapter | RaydiumDecreaseLiquidity | 1513-1636 |
CloseFlowAdapter | RaydiumClosePosition | 1638-1723 |
The compound policy trait CompoundFlowPolicy is implemented in
venue/compound.rs, not here (venue/compound.rs:88, :209, :306). The
marker and capability traits that declare the flows a struct supports are
implemented in venue/clmm.rs:246-300.
What each adapter method does
Every adapter trait has the same four method kinds. The table names one example per kind.
| Kind | Method examples | What it does | Example |
|---|---|---|---|
| identity | active_flow_identity, open_identity, owner_rebalance_identity, keeper_exit_identity, decrease_identity, close_identity | Copies keys and mints out of the struct into a plain struct. The runner compares the copies against each other and the receipt. | adapters/orca.rs:433-449 |
| access | global_config, sickle_account, global_automator, position_settings, action_intent_mut, intent_accounts, intent_assets, rent_accounts, accounts_closed_by_protocol | Returns a reference or an AccountInfo for one struct field. intent_assets also reads the vault balances as baselines. | adapters/orca.rs:669 |
| prepare | prepare_open, prepare_increase, prepare_decrease, prepare_close, prepare_all_yield, prepare_owner_rebalance, prepare_keeper_rebalance, prepare_keeper_exit, load_keeper_*_state, validate_keeper_*_static_accounts | Checks the venue accounts, parses remaining_accounts, reads pool and position state, and builds the CPI arguments and account bundles. | adapters/orca.rs:523-592 |
| execute | execute_open, execute_increase, execute_decrease, close_empty_position, settle_close_yield, claim_all_yield, execute_drain_and_close, execute_reopen, execute_keeper_exit | Invokes the venue CPI, or the helper that does, and reads the post-CPI state into a receipt. | adapters/orca.rs:560-585 |
The receipt types are RawOpenFlowReceipt, RawDecreaseFlowReceipt,
CloseYieldReceipt, AllYieldClaimReceipt, PoolFeeClaimReceipt,
RewardClaimReceipt, and RawDrainFlowReceipt. The adapter fills them
from the helper outcome structs CollectOutcome, DecreaseOutcome,
DrainOutcome, and RaydiumDrainOutcome. Reward dispositions differ by venue:
Orca always reports Measured (adapters/orca.rs:211). Raydium reports
IncludedInPoolToken { side } when a reward mint equals a pool mint
(adapters/raydium.rs:119-122).
Remaining-account grammar
The adapters consume remaining_accounts left to right. N is the number of initialized reward slots parsed from the pool account. h_a and h_b are the two entries of hook_lens. r_i is entry i of reward_hook_lens.
| Venue | Flow | Grammar | Tail | Parser |
|---|---|---|---|---|
| Orca | open | none | not read | adapters/orca.rs:1191 |
| Orca | increase, decrease, collect fees | hookA{h_a} hookB{h_b} | returned | adapters/orca.rs:1376-1393, :1478-1495, venue/adapters/orca_flows.rs:940 |
| Orca | collect rewards, close | [vault recipient mint]{N} [collector]{N} rewardhook0{r_0} rewardhook1{r_1} rewardhook2{r_2} | rewards: must be empty. close: returned | venue/adapters/orca_flows.rs:1064-1151, adapters/orca.rs:1102 |
| Orca | harvest, compound | hookA{h_a} hookB{h_b} then the reward grammar above | returned, compound uses it for intent vaults | adapters/orca.rs:267-325 |
| Orca | owner rebalance, keeper rebalance, keeper exit | hookA{h_a} hookB{h_b} reward_token_program then the reward grammar above | owner: must be empty. keeper: intent tail | adapters/orca.rs:513-521, :712-720, :919-927, runner venue/owner_rebalance.rs:496 |
| Raydium | open, increase | none | returned unread | adapters/raydium.rs:1229, :1450 |
| Raydium | decrease | [vault recipient mint]{N} | returned | venue/adapters/raydium_flows.rs:870-920 |
| Raydium | collect fees, harvest, compound, owner rebalance, keeper rebalance, keeper exit | [vault recipient mint]{N} [collector]{N} | returned, keeper flows use it as intent tail | venue/adapters/raydium_flows.rs:870-946, adapters/raydium.rs:355-356 |
One hook slice follows one rule (fees.rs:519-560). The mint's Token-2022
data names the hook program, or no hook. With no hook the declared length must
be 0. With a hook the declared length must be at least 1. The first account
must equal the hook program. When the length is at least 2, the second account
must equal the PDA [b"extra-account-metas", mint] under the hook program. The
program does not check the accounts after the second.
The Orca reward grammar takes the slot count and each slot's index, vault, and
mint from the pool account (venue/adapters/orca_flows.rs:1079-1082). It requires
each recipient to equal the Sickle's associated token account for the reward
mint under the mint's owning token program (:1119-1124). It requires each
collector to equal the fee collector's associated token account (:1126-1131).
It returns RewardGroupMissing when fewer than 3N accounts are present and
RewardCollectorMissing when fewer than 4N (:1084-1090).
The Raydium reward grammar takes the same values from the Raydium pool account
(venue/adapters/raydium_flows.rs:875-878). The collector tail is a separate
parser with the same address rule
(venue/adapters/raydium_flows.rs:922-946). The plain decrease takes no
collector tail, since it charges no fee (adapters/raydium.rs:1540-1544).
The Raydium bitmap is a named optional account, not a remaining account.
validate_bitmap_extension requires it to equal the PDA
[b"pool_tick_array_bitmap_extension", pool_state] under the Raydium program
and returns its key for the instruction builder
(venue/adapters/raydium_flows.rs:1378-1394). The adapter appends the
account to the CPI account list only when present (adapters/raydium.rs:1329-1331, :1499-1501).
Per-venue derivations
| Derivation | Orca | Raydium |
|---|---|---|
| Position account | PDA [b"position", position_mint] under the Orca program (adapters/orca.rs:1204-1212, venue/adapters/orca_flows.rs:73-77) | PDA [b"position", nft_mint] under the Raydium program (adapters/raydium.rs:1280-1287, venue/adapters/raydium_flows.rs:70-77) |
| Position token account | Associated token account of (sickle, position_mint) under Token-2022 (adapters/orca.rs:1214-1223) | Associated token account of (sickle, nft_mint) under Token-2022 (adapters/raydium.rs:1248-1257) |
| Pool owner | whirlpool.owner == whirlpool_program (adapters/orca.rs:1197-1201) | pool_state.owner == clmm_program (adapters/raydium.rs:1231-1235) |
| Position owner | position.owner == whirlpool_program (adapters/orca.rs:1360-1364) | personal_position.owner == clmm_program (adapters/raydium.rs:1428-1432) |
| Position belongs to pool | position.whirlpool == whirlpool through read_old_position (venue/adapters/orca_flows.rs:52-60) | position.pool_id == pool_state through read_raydium_position (venue/adapters/raydium_flows.rs:45-55) |
| New position after reopen | Reads the position state and reports pool, range, liquidity (adapters/orca.rs:229-257) | Same, plus state.nft_mint == new_position_nft_mint (adapters/raydium.rs:146-150, :1338-1342) |
| Tick arrays | Not derived. Passed as unchecked accounts. Orca validates them. | Not derived. Passed as unchecked accounts with two start indices in the request (adapters/raydium.rs:1271-1272). |
| Tick spacing, current tick | parse_whirlpool_tick_spacing, parse_whirlpool_current_tick_index (adapters/orca.rs:753-759) | parse_pool_tick_spacing, parse_pool_current_tick (adapters/raydium.rs:796-802) |
| Protocol position | Not applicable | Must equal the Raydium program ID. Owner structs use address =. Keeper structs check in the adapter (adapters/raydium.rs:660-664) |
| Reward token program | First remaining account after the hooks on rebalance and exit. Must be the classic Token ID and executable (adapters/orca.rs:93-104) | Not applicable. The struct carries both token programs. |
| Metadata update authority | address = WP_NFT_UPDATE_AUTH on owner structs. Adapter check on RebalanceFor (adapters/orca.rs:649-654) | Not applicable |
Side-by-side comparison
| Aspect | Orca adapter | Raydium adapter |
|---|---|---|
| Lines | 1,981, 1,690 before its test module | 1,727 |
| Trait impls | 16 | 15 |
| Account structs served | 11 | 10 |
| Fee collect for the owner | CollectTradingFeesAdapter + CollectRewardsAdapter, two instructions | ClaimAllYieldAdapter on RaydiumCollectFees, one instruction |
| Yield claim CPI | collect_fees_v2 then one collect_reward_v2 per slot | One decrease_liquidity_v2 with liquidity = 0 (adapters/raydium.rs:357-361) |
| Fee collector accounts | Typed in every struct | One shared unchecked rebalance composite, checked from both adapters by assert_fee_collector_account (adapters/raydium.rs:515-531, :746-762). Typed on the other 4 structs. |
| Transfer hook accounts | Parsed and forwarded | None |
| Bitmap extension | Not applicable | Optional named account, PDA check, three different check orderings |
| Close rent | Orca pays the receiver. rent_accounts returns source == receiver (adapters/orca.rs:463-468) | Raydium pays the Sickle. rent_accounts returns source = sickle and the runner forwards (adapters/raydium.rs:448-453) |
| Keeper struct constraints dropped | old_position_mint re-checked by assert_token_2022_mint (adapters/orca.rs:646-648) | old_position_nft_account re-checked by assert_keeper_position_nft_account (adapters/raydium.rs:665-669) |
| Exit static checks | None (adapters/orca.rs:871-873) | Protocol position and memo program (adapters/raydium.rs:955-967) |
| Reward disposition | Always Measured | Measured or IncludedInPoolToken |
| Plain decrease composition | PrincipalOnly (adapters/orca.rs:1551) | PrincipalAndIncidentalYield (adapters/raydium.rs:1621) |
| Close yield | Collects every reward slot before close (adapters/orca.rs:1632-1648) | Returns an empty receipt (adapters/raydium.rs:1693) |
| Instruction account types | 11 top-level account structs (adapters/orca.rs:20-24) | 10 top-level account structs (adapters/raydium.rs:24-28) |
#[inline(never)] methods | 24 | 24 |
How a call flows through it
The walk-through follows raydium_exit_for through the keeper exit runner and the Raydium adapter.
instructions/raydium/exit_for.rs:244-250callsrun_keeper_exitwith the two minimums and the unit request.venue/keeper_exit.rs:242callsactive_flow_identity(adapters/raydium.rs:938). The runner runs the pause check in owner-exit form and the allowlist check (venue/keeper_exit.rs:243-249).venue/keeper_exit.rs:251callskeeper_exit_identity(adapters/raydium.rs:944-953) and requires it to match the flow.venue/keeper_exit.rs:256callsintent_accounts(adapters/raydium.rs:985). The payer is the authority.venue/keeper_exit.rs:262callsrent_accounts(adapters/raydium.rs:987-992). The source is the Sickle, the receiver is the owner.venue/keeper_exit.rs:266-269callsglobal_automator(adapters/raydium.rs:969-971) for the keeper check.venue/keeper_exit.rs:278callsposition_settings(adapters/raydium.rs:977-979) for the settings identity check.venue/keeper_exit.rs:286callsvalidate_keeper_exit_static_accounts(adapters/raydium.rs:955-967). The adapter requires the protocol position to equal the Raydium program ID and the memo program to equal its constant.venue/keeper_exit.rs:294callsprepare_keeper_exit(adapters/raydium.rs:1003-1052). The adapter checks the pool and position owners and parsesNreward groups andNcollectors. It checks the bitmap PDA and both fee collector accounts. It builds the account bundle on the heap (:1115-1126).venue/keeper_exit.rs:295callsload_keeper_exit_state(adapters/raydium.rs:1055-1076). The adapter reads the position and the current tick.venue/keeper_exit.rs:307-310callsintent_sickle,position_settings, andintent_assets(adapters/raydium.rs:985) to open the action ledger.venue/keeper_exit.rs:316callsaccounts_closed_by_protocol(adapters/raydium.rs:994-1000).venue/keeper_exit.rs:318callsexecute_keeper_exit(adapters/raydium.rs:1079-1111). The adapter callscollect_drain_charge_close_with_actions(venue/adapters/raydium_flows.rs:502-603) and maps the outcome intoRawDrainFlowReceipt.- The runner validates the receipt, the closed accounts, and the intent credit, then returns the event set. The handler emits it (
instructions/raydium/exit_for.rs:253-268).
Invariants the layer owns
- The venue pool and position accounts belong to the venue program. Every prepare method checks the owner (
adapters/orca.rs:485-493,:1193-1197,:1356-1360,adapters/raydium.rs:471-480,:1231-1235,:1428-1432). ErrorInvalidAccountOwner. - The position account is the venue PDA for the position mint, and the position token account is the Sickle's associated token account for it. Checked on open (
adapters/orca.rs:1200-1219,adapters/raydium.rs:1238-1257) and on every reopen through the shared helpers. ErrorInvalidPosition. - The reopened position carries the requested range, no liquidity, and the venue program as owner. The adapter reads the state into
RawOpenFlowReceipt(adapters/orca.rs:594,adapters/raydium.rs:609). The runner validates it (venue/open_increase.rs:102-151). Raydium additionally requires the stored NFT mint to equal the new mint (adapters/raydium.rs:146-150). ErrorInvalidProtocolAccountDataorInvalidPosition. - The reward group count equals the number of initialized slots in the pool. The caller cannot add or drop a group (
venue/adapters/orca_flows.rs:1079-1091,venue/adapters/raydium_flows.rs:875-880). ErrorsRewardGroupMissing,RewardGroupMismatch. - Every reward recipient is the Sickle's associated token account and every reward collector is the fee collector's (
venue/adapters/orca_flows.rs:1119-1132,venue/adapters/raydium_flows.rs:890-895, venue/adapters/raydium_flows.rs:936-941). ErrorsRewardRecipientMismatch,RewardCollectorMismatch. - A hook slice starts with the mint's hook program, and a mint without a hook carries no accounts (
fees.rs:519-560). ErrorTransferHookAccountsMissing. - The Raydium bitmap account, when present, is the pool's bitmap PDA (
venue/adapters/raydium_flows.rs:1378-1394). ErrorInvalidPosition. - Both pool mints pass the Token-2022 extension screen before an increase (
adapters/orca.rs:1369-1370,adapters/raydium.rs:1438-1439). The error comes fromassert_mint_extensions_for_custody. - On Orca, each token program equals the owner of its mint (
adapters/orca.rs:1361-1368,:1465-1472). ErrorInvalidAccountOwner. - On decrease and close, the venue program equals its allowlist slot. The adapter checks it because these two traits have no
ActiveFlowPolicysupertrait (adapters/orca.rs:1452-1453,:1601-1602,adapters/raydium.rs:1719-1720,venue/adapters/raydium_flows.rs:826). - On Raydium rebalance and exit, both fee collector accounts are the fee collector's accounts for the pool mints (
adapters/raydium.rs:515-531,:746-762,:1032-1041). The error comes fromassert_fee_collector_account. - The Orca reward token program in the remaining accounts is the classic Token program and is executable (
adapters/orca.rs:94-102). ErrorInvalidAccountOwner.
Tests
| Test location | What it covers |
|---|---|
programs/sickle/tests/clmm_conformance.rs | Compile-time proof that every Orca and Raydium struct implements the adapter traits its manifest requires. |
programs/sickle/tests/ui/*.rs | 22 fixtures: 7 pass and 15 compile-fail, for a missing adapter, a partial yield implementation, or a Meteora struct. |
tests/sickle/orca.ts, tests/sickle/raydium.ts | Integration tests that exercise every adapter method through the instructions. |
tests/surfpool-lifecycle.ts, surfpool-raydium-lifecycle.ts, surfpool-t22-*.ts | Mainnet-fork lifecycles with real reward slots and Token-2022 pools. |
instructions/raydium/decrease_liquidity.rs unit tests | The Raydium reward-group parser and same-mint reward handling. |
instructions/orca/rebalance_for.rs unit test | assert_token_2022_mint. |
adapters/orca.rs:1688-1977, 4 unit tests | take_pool_hooks_and_reward_groups on the verbatim mainnet Whirlpool in tests/fixtures/clmm-mainnet-accounts.json. |
The four Orca tests cover the remaining-account grammar this layer owns, and they fail when it changes. Dropping the executable check on the reward token program, ignoring the declared hook lengths, and accepting any program in that slot each break at least one of them.
Gaps. adapters/raydium.rs has no unit test. Its remaining-account parsers
live in the handler layer and are unit-tested there
(instructions/raydium/decrease_liquidity.rs), so it has no equivalent seam.
assert_keeper_position_nft_account has no unit test. The three bitmap check
orderings in adapters/raydium.rs are not asserted by a test. No test asserts
that keeper_drain_accounts and drain_accounts build the same bundle from
the same accounts.
Simplification and audit notes
Historical notes 1, 2, 3, 5, 6, and 8 were resolved in #175. Historical notes 4
and 15 were resolved for the part of each that lives in this layer. The Orca
half of L04-N019 was resolved, while its Raydium finding remains open. The
resolved records are listed under "Resolved" at the end of this section. The
numbering of the kept notes is unchanged, so both lists carry a
prettier-ignore comment: without it, prettier renumbers a list from its first
item.
- L04-N007 — The Raydium bitmap check runs at three different points for the same instruction shape.
RaydiumCollectFeeschecks it after the reward groups (adapters/raydium.rs:1138, macro argumentfalse).RaydiumHarvestForchecks it before the reward groups (:1162, argumenttrue).RaydiumCompoundFordefers it toclaim_all_yield(:1186,bitmap = deferred). ThePreparedBitmapenum exists only to carry this difference (:66-70). Kept: the three modes are now named next to each other in one macro (:221-228), but settling on one ordering changes which error a malformed input hits first, which is a behavior decision rather than a simplification. - L04-N009 — The allowlist check lives in the adapter for decrease and close (
adapters/orca.rs:1453,:1602,adapters/raydium.rs:1719,venue/adapters/raydium_flows.rs:826) and in the runner for open, increase, and the rebalances.DecreaseFlowAdapterandCloseFlowAdapterhave noActiveFlowPolicysupertrait (venue/decrease_close.rs:93,:217), so the same check is owned by two layers. Kept: closing this needs a supertrait added invenue/, which is the shared-runner layer and is sequenced separately. - L04-N010 —
RaydiumRebalanceForchecks the protocol position and the memo program in the adapter (adapters/raydium.rs:660-669).RaydiumExitForchecks the same two accounts in the adapter (:955-967) and the memo program again throughaddress = MEMO_PROGRAM_ID(instructions/raydium/exit_for.rs:194).RaydiumRebalancePositionchecks both throughaddress =only. Three structs, three placements. Kept: two of the three placements are account-struct attributes in handler files. - L04-N011 —
assert_keeper_position_nft_account(adapters/raydium.rs:857-874) andassert_token_2022_mint(instructions/orca/rebalance_for.rs:241-252) re-implement Anchortoken::andmint::constraints by hand for the keeper structs. The owner structs keep the constraints. A constraint change must be made in two places. Kept: the constraints and one of the two helpers live in handler files. - L04-N012 —
validate_keeper_exit_static_accountsonExitForreturnsOk(())(adapters/orca.rs:875-877). The memo check for that flow runs insidewithdraw_collect_charge_close_with_actions(venue/adapters/orca_flows.rs:748-752) after the intent accounts are loaded, later than the Raydium equivalent (adapters/raydium.rs:961-965). Kept: moving the check earlier changes the order in which a malformed exit fails, and the check itself is in a handler file. - L04-N014 —
prepare_orca_yield!andclaim_orca_yield!(adapters/orca.rs:267-398) are macros with a$accounts:exprargument that must resolve to a struct with 17 named fields. The same holds forprepare_raydium_yield!andclaim_raydium_yield!(adapters/raydium.rs:220-387): the shared composites reduce repeated declarations but do not give these macros a typed account interface. Kept, and this contract widened it: the seven macros added here take the same kind of argument. A trait that names the fields would fix all of them at once and belongs with the trait work invenue/. - L04-N015 —
execute_openon Raydium builds the account list withvec![...]and a conditionalpushfor the bitmap (adapters/raydium.rs:1307-1331).execute_increaserepeats the same pattern (:1482-1501). The shared Orca helper pushes into aVecinstead, to stay inside the SBF frame (venue/adapters/orca_flows.rs:493-508). Kept for these three: the Orca pair now shares one list, but Raydium's conditional bitmap and the handler helper's frame budget are two different reasons for two different shapes. - L04-N016 —
load_keeper_rebalance_stateandload_keeper_exit_stateignore the_preparedparameter on both venues (adapters/orca.rs:741-744,:942,adapters/raydium.rs:788-791,:1055). The trait passes a value no implementation reads. Kept: removing the parameter changes two trait signatures invenue/and every call site, which is wider than the one-line caller updates this contract allows. - L04-N017 —
RaydiumCollectFeesimplementsClaimAllYieldAdapter(adapters/raydium.rs:1128), the keeper yield trait, whileOrcaCollectFeesimplementsCollectTradingFeesAdapter(adapters/orca.rs:1016). The owner fee-collect instruction sits on a different trait per venue. Kept: aligning them moves an instruction onto a different runner, which is a behavior decision. - L04-N018 —
RaydiumExitFor.fee_collector_account_0and_1are typedInterfaceAccountwith constraints (instructions/raydium/exit_for.rs:159-167), andprepare_keeper_exitchecks them again withassert_fee_collector_account(adapters/raydium.rs:1032-1041). Both rebalance handlers shareRaydiumRebalanceFeeCollectors, whose two fields areUncheckedAccount(instructions/raydium/rebalance_accounts.rs:95-104), and rely on the same adapter check. One check, two mechanisms, and one exit struct with both. Kept: the account types are attributes in handler files. - L04-N019 —
adapters/raydium.rshas no#[cfg(test)]module. Kept for Raydium: its remaining-account parsers live in the handler layer and are unit-tested there, so the adapter has no equivalent seam to test without building Anchor account structs. - L04-N020 — The macros this contract added carry the
#[inline(never)]their call sites had, inside the macro body (adapters/mod.rs:98,adapters/orca.rs:229,adapters/raydium.rs:140). That attribute is load-bearing: it holds a method in its own SBF stack frame. A future macro that writes a method has to keep it, and the compiler does not warn if it is dropped. - L04-N021 — The compiled artifact checks an adapter refactor in one direction only. The build is reproducible, so a byte-identical
.sois sufficient evidence that behavior did not change. A differing.soproves nothing. Anchor stores the source line of everyrequire!in its error origin, so three added comment lines change the hash. Expanded-source comparison supplements it.cargo expandof the two modules, withline: <n>u32normalized away, shows whether anything other than those positions moved. It does not cover SBF codegen, the IDL, the account metas, or parser output. - L04-N022 —
PreparedBitmap::ValidateBeforeClaim(adapters/raydium.rs:69) is produced by exactly one call site, the compound prepare, and consumed byclaim_raydium_yield!. It is a two-variant enum in service of one flow.
Resolved
L04-R001 —
adapters/orca.rs:776-787keeper_drain_accounts,adapters/orca.rs:962-973keeper_exit_drain_accounts, andvenue/adapters/orca_flows.rs:546-557drain_accountsbuildOrcaDrainAccountsfrom three structs with the same field list.adapters/raydium.rs:879-890,:1111-1122, andvenue/adapters/raydium_flows.rs:448repeat this. Kept for the Raydium copy alone: all three Orca builders now expand one macro in the adapter layer, and the third Raydium copy stays in a handler file until that venue's helpers move. Resolved in this pass.All three Orca builders expand
orca_drain_accounts_from!and all three Raydium builders expandraydium_drain_accounts_from!; both macros now sit beside the struct they fill, in the flows module.L04-R002 —
adapters/raydium.rs:11-21imports the CPI helpers and the account bundles from handler files. The adapter layer depends upward on the handler layer fordecrease_liquidity_and_charge,collect_drain_charge_close_with_actions,validate_decrease_accounts,validate_bitmap_extension, and the Raydium bundle builders. The Orca half of this edge is gone:collect_fees_and_chargeandwithdraw_collect_charge_close_with_actionsnow live inadapters/orca_flows.rs, andadapters/orca.rs:5-11reaches sideways to a sibling rather than upward. Kept: removing what remains means moving the Raydium helpers the same way. Resolved in this pass.
adapters/raydium.rs names no handler item. Fifteen moved to
venue/adapters/raydium_flows.rs, one more than the import list showed,
because RewardCharge was never used in the file that defined it.
- L04-R003 —
adapters/orca.rs:279-306,:603-630, and:961-988hold the same 28-line block. The block splits pool hooks, takes the reward token program, checks its ID and executable flag, and parses reward groups. Three copies in one file. Resolved in #175. - L04-R004 —
adapters/orca.rs:376-415,:705-749, and:1043-1087mapDrainOutcomeintoRawOwnerRebalanceReceiptwith the same code.adapters/raydium.rs:398-445,:744-791, and:1138-1185do the same forRaydiumDrainOutcome. Six copies of one mapping. Resolved in #175. - L04-R005 —
adapters/orca.rs:419-444execute_reopenandadapters/orca.rs:753-778execute_keeper_reopenhave identical bodies.adapters/raydium.rs:449-479andadapters/raydium.rs:795-825match the same way. Resolved in #175. - L04-R006 —
ActiveFlowPolicyis implemented 5 times inadapters/orca.rs(:181,:464,:843,:1261,:1397) and 5 times inadapters/raydium.rs(:208,:498,:928,:1313,:1496). Each body reads the same four fields. Resolved in #175. - L04-R007 —
intent_accountsis implemented 4 times with the same body except the payer field (adapters/orca.rs:534-552,:901-919,adapters/raydium.rs:571-589,:993-1011). The rebalance payer isfunder, the exit payer isauthority.intent_assetsis implemented 4 times with identical bodies (adapters/orca.rs:554-567,:921-934,adapters/raydium.rs:591-604,:1013-1026). Resolved in #175. - L04-R008 —
RaydiumCompoundFor::prepare_all_yield(adapters/raydium.rs:1275-1301) repeats the body ofprepare_raydium_yield!(:70-113) by hand, minus the bitmap step. Resolved in #175.
The line citations in the resolved notes, in the resolved half of historical notes 4 and 15, and in the resolved Orca half of L04-N019 refer to the files as they were before #175.