Sickle Sol

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

PathLinesPurpose
venue/adapters/mod.rs138Re-exports 9 request and prepared-state types, and holds the 2 macros both venues use.
venue/adapters/orca.rs1977Trait implementations for the 11 Orca account structs. 1,711 before its test module.
venue/adapters/orca_flows.rs1331The ordered Orca CPI legs orca.rs drives, and the account bundles they take.
venue/adapters/raydium.rs1723Trait implementations for the 10 Raydium account structs.
venue/adapters/raydium_flows.rs1506The 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_accounts in 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

ItemKindMeaning
OrcaKeeperExitVenueRequest, OrcaKeeperRebalanceVenueRequest, OrcaOwnerRebalanceVenueRequest, OrcaPreparedYieldre-exportThe Orca types a handler or a runner names (adapters/mod.rs:13-16).
RaydiumKeeperExitVenueRequest, RaydiumKeeperRebalanceVenueRequest, RaydiumOpenVenueRequest, RaydiumOwnerRebalanceVenueRequest, RaydiumPreparedYieldre-exportThe Raydium types a handler or a runner names (adapters/mod.rs:17-20).
impl_active_flow_policy!macroWrites ActiveFlowPolicy for a flat account struct. Invoked 6 times, 3 per venue (adapters/mod.rs:33-54).
impl_nested_active_flow_policy!macroWrites the same policy for the 4 rebalance structs whose fields now live in shared composites (adapters/mod.rs:56-80).
keeper_intent_methods!macroWrites 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

ItemKindLinesMeaning
take_pool_hooks_and_reward_groupsprivate fn71-118Splits the pool hook run, the reward token program, and one group per initialized slot. Used by 3 prepares.
OrcaPreparedYieldstruct120-124Hook lengths, pool hook count, and parsed reward groups for harvest and compound.
orca_modify_liquidity_infos!macro136-162The 15 CPI account infos of ModifyLiquidity, plus the hook tail. Invoked by increase and decrease.
orca_owner_rebalance_receipt!macro173-216Maps a drain outcome into RawDrainFlowReceipt. Invoked by the 3 rebalance and exit flows.
orca_reopen_receipt!macro224-259The body of both reopen methods.
prepare_orca_yield!macro267-325Splits pool hook accounts, then parses reward groups. Used by 2 trait impls.
claim_orca_yield!macro327-398Calls collect_fees_and_charge then collect_orca_rewards_and_charge and maps the receipt.
OrcaOwnerRebalanceVenueRequeststruct401-406Metadata flag, hook lengths, reward hook lengths, new settings bump.
OrcaPreparedOwnerRebalancestruct408-420Both account bundles, old position snapshot, tick spacing, open args, minimums, hooks, reward groups.
OrcaKeeperRebalanceVenueRequeststruct598-602Metadata flag, hook lengths, reward hook lengths.
OrcaPreparedKeeperRebalancestruct604-612Both account bundles, open args, minimums, hooks, reward groups. No snapshot.
OrcaKeeperExitVenueRequeststruct838-841Hook lengths, reward hook lengths.
OrcaPreparedKeeperExitstruct843-849One account bundle, minimums, hooks, reward groups.
OrcaPreparedOpenstruct1171-1173The Orca open arguments.
OrcaPreparedIncreasestruct1294-1297The Orca increase arguments and the hook account count.
OrcaPreparedDecreasestruct1427-1430The Orca decrease arguments and the hook account count.
OrcaPreparedClosestruct1557-1559The parsed reward groups.
keeper_drain_accountsprivate fn814-819Calls orca_drain_accounts_from! for RebalanceFor.
keeper_reopen_accountsprivate fn822-835Builds OrcaReopenAccounts from RebalanceFor on the heap.
keeper_exit_drain_accountsprivate fn1003-1014Calls 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.

ItemKindLinesMeaning
orca_drain_accounts_from!macro97-126The 23-field drain bundle. Invoked by the owner builder and both keeper builders.
drain_accountsfn851-856The owner rebalance's bundle. Expands the macro above, like the two keeper builders.

venue/adapters/raydium.rs

ItemKindLinesMeaning
RaydiumPreparedYieldstruct60-64Parsed reward groups, reward collectors, and the bitmap state.
PreparedBitmapprivate enum67-70Validated(Option<Pubkey>) or ValidateBeforeClaim. Records when the bitmap check ran.
raydium_owner_rebalance_receipt!macro81-127Maps a drain outcome into RawDrainFlowReceipt. Invoked by the 3 rebalance and exit flows.
raydium_reopen_receipt!macro135-172The body of both reopen methods.
prepare_raydium_yield!macro220-301Runs validate_decrease_accounts, parses reward groups and collectors, and checks the bitmap in one of 3 modes.
claim_raydium_yield!macro303-387Runs a zero-liquidity decrease_liquidity_and_charge and maps the receipt.
RaydiumOwnerRebalanceVenueRequeststruct390-395Two tick-array start indices, metadata flag, new settings bump.
RaydiumPreparedOwnerRebalancestruct397-408Both account bundles, old position snapshot, tick spacing, open args, minimums, reward groups, collectors.
RaydiumKeeperRebalanceVenueRequeststruct613-617Two tick-array start indices, metadata flag.
RaydiumPreparedKeeperRebalancestruct619-626Both account bundles, open args, minimums, reward groups, collectors.
RaydiumKeeperExitVenueRequestunit struct929Raydium exit carries no venue-specific request.
RaydiumPreparedKeeperExitstruct931-936One account bundle, minimums, reward groups, collectors.
RaydiumOpenVenueRequeststruct1202-1206Two tick-array start indices, metadata flag.
RaydiumPreparedOpenstruct1208-1211The Raydium open arguments and the bitmap key.
RaydiumPreparedIncreasestruct1371-1374The Raydium increase arguments and the bitmap key.
RaydiumPreparedDecreasestruct1507-1511Reward groups, bitmap key, decrease arguments.
assert_keeper_position_nft_accountprivate fn857-874Re-runs the token-account constraints the keeper struct dropped.
keeper_drain_accountsprivate fn877-882Calls raydium_drain_accounts_from! for RaydiumRebalanceFor.
keeper_reopen_accountsprivate fn885-926Builds RaydiumReopenAccounts from RaydiumRebalanceFor on the heap.
keeper_exit_drain_accountsprivate fn1115-1126Calls 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".

ItemKindLinesMeaning
raydium_drain_accounts_from!macro95-128The drain bundle. Invoked by the owner builder and both keeper builders.
drain_accountsfn763-768The owner rebalance's bundle. Expands the macro above, like the two keeper builders.

Trait implementations in adapters/orca.rs

TraitAccount structLines
ActiveFlowPolicyOrcaRebalancePosition422-427
OwnerRebalanceFlowAdapterOrcaRebalancePosition429-595
ActiveFlowPolicyRebalanceFor614-619
KeeperRebalanceFlowAdapterRebalanceFor621-812
ActiveFlowPolicyExitFor851
KeeperExitFlowAdapterExitFor853-1000
CollectTradingFeesAdapterOrcaCollectFees1016-1067
CollectRewardsAdapterOrcaCollectRewards1069-1121
ClaimAllYieldAdapterHarvestFor1123-1144
ClaimAllYieldAdapterCompoundFor1146-1167
ActiveFlowPolicyOrcaOpenPosition1169
OpenFlowAdapterOrcaOpenPosition1175-1286
ActiveFlowPolicyOrcaIncreaseLiquidity1288-1292
IncreaseFlowAdapterOrcaIncreaseLiquidity1299-1425
DecreaseFlowAdapterOrcaDecreaseLiquidity1432-1555
CloseFlowAdapterOrcaClosePosition1561-1686

Trait implementations in adapters/raydium.rs

TraitAccount structLines
ActiveFlowPolicyRaydiumRebalancePosition410-415
OwnerRebalanceFlowAdapterRaydiumRebalancePosition417-610
ActiveFlowPolicyRaydiumRebalanceFor628-633
KeeperRebalanceFlowAdapterRaydiumRebalanceFor635-854
ActiveFlowPolicyRaydiumExitFor938
KeeperExitFlowAdapterRaydiumExitFor940-1112
ClaimAllYieldAdapterRaydiumCollectFees1128-1149
ClaimAllYieldAdapterRaydiumHarvestFor1151-1173
ClaimAllYieldAdapterRaydiumCompoundFor1175-1197
ActiveFlowPolicyRaydiumOpenPosition1199
OpenFlowAdapterRaydiumOpenPosition1213-1363
ActiveFlowPolicyRaydiumIncreaseLiquidity1365-1369
IncreaseFlowAdapterRaydiumIncreaseLiquidity1376-1505
DecreaseFlowAdapterRaydiumDecreaseLiquidity1513-1636
CloseFlowAdapterRaydiumClosePosition1638-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.

KindMethod examplesWhat it doesExample
identityactive_flow_identity, open_identity, owner_rebalance_identity, keeper_exit_identity, decrease_identity, close_identityCopies 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
accessglobal_config, sickle_account, global_automator, position_settings, action_intent_mut, intent_accounts, intent_assets, rent_accounts, accounts_closed_by_protocolReturns a reference or an AccountInfo for one struct field. intent_assets also reads the vault balances as baselines.adapters/orca.rs:669
prepareprepare_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_accountsChecks the venue accounts, parses remaining_accounts, reads pool and position state, and builds the CPI arguments and account bundles.adapters/orca.rs:523-592
executeexecute_open, execute_increase, execute_decrease, close_empty_position, settle_close_yield, claim_all_yield, execute_drain_and_close, execute_reopen, execute_keeper_exitInvokes 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.

VenueFlowGrammarTailParser
Orcaopennonenot readadapters/orca.rs:1191
Orcaincrease, decrease, collect feeshookA{h_a} hookB{h_b}returnedadapters/orca.rs:1376-1393, :1478-1495, venue/adapters/orca_flows.rs:940
Orcacollect rewards, close[vault recipient mint]{N} [collector]{N} rewardhook0{r_0} rewardhook1{r_1} rewardhook2{r_2}rewards: must be empty. close: returnedvenue/adapters/orca_flows.rs:1064-1151, adapters/orca.rs:1102
Orcaharvest, compoundhookA{h_a} hookB{h_b} then the reward grammar abovereturned, compound uses it for intent vaultsadapters/orca.rs:267-325
Orcaowner rebalance, keeper rebalance, keeper exithookA{h_a} hookB{h_b} reward_token_program then the reward grammar aboveowner: must be empty. keeper: intent tailadapters/orca.rs:513-521, :712-720, :919-927, runner venue/owner_rebalance.rs:496
Raydiumopen, increasenonereturned unreadadapters/raydium.rs:1229, :1450
Raydiumdecrease[vault recipient mint]{N}returnedvenue/adapters/raydium_flows.rs:870-920
Raydiumcollect fees, harvest, compound, owner rebalance, keeper rebalance, keeper exit[vault recipient mint]{N} [collector]{N}returned, keeper flows use it as intent tailvenue/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

DerivationOrcaRaydium
Position accountPDA [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 accountAssociated 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 ownerwhirlpool.owner == whirlpool_program (adapters/orca.rs:1197-1201)pool_state.owner == clmm_program (adapters/raydium.rs:1231-1235)
Position ownerposition.owner == whirlpool_program (adapters/orca.rs:1360-1364)personal_position.owner == clmm_program (adapters/raydium.rs:1428-1432)
Position belongs to poolposition.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 reopenReads 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 arraysNot 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 tickparse_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 positionNot applicableMust equal the Raydium program ID. Owner structs use address =. Keeper structs check in the adapter (adapters/raydium.rs:660-664)
Reward token programFirst 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 authorityaddress = WP_NFT_UPDATE_AUTH on owner structs. Adapter check on RebalanceFor (adapters/orca.rs:649-654)Not applicable

Side-by-side comparison

AspectOrca adapterRaydium adapter
Lines1,981, 1,690 before its test module1,727
Trait impls1615
Account structs served1110
Fee collect for the ownerCollectTradingFeesAdapter + CollectRewardsAdapter, two instructionsClaimAllYieldAdapter on RaydiumCollectFees, one instruction
Yield claim CPIcollect_fees_v2 then one collect_reward_v2 per slotOne decrease_liquidity_v2 with liquidity = 0 (adapters/raydium.rs:357-361)
Fee collector accountsTyped in every structOne 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 accountsParsed and forwardedNone
Bitmap extensionNot applicableOptional named account, PDA check, three different check orderings
Close rentOrca 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 droppedold_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 checksNone (adapters/orca.rs:871-873)Protocol position and memo program (adapters/raydium.rs:955-967)
Reward dispositionAlways MeasuredMeasured or IncludedInPoolToken
Plain decrease compositionPrincipalOnly (adapters/orca.rs:1551)PrincipalAndIncidentalYield (adapters/raydium.rs:1621)
Close yieldCollects every reward slot before close (adapters/orca.rs:1632-1648)Returns an empty receipt (adapters/raydium.rs:1693)
Instruction account types11 top-level account structs (adapters/orca.rs:20-24)10 top-level account structs (adapters/raydium.rs:24-28)
#[inline(never)] methods2424

How a call flows through it

The walk-through follows raydium_exit_for through the keeper exit runner and the Raydium adapter.

  1. instructions/raydium/exit_for.rs:244-250 calls run_keeper_exit with the two minimums and the unit request.
  2. venue/keeper_exit.rs:242 calls active_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).
  3. venue/keeper_exit.rs:251 calls keeper_exit_identity (adapters/raydium.rs:944-953) and requires it to match the flow.
  4. venue/keeper_exit.rs:256 calls intent_accounts (adapters/raydium.rs:985). The payer is the authority.
  5. venue/keeper_exit.rs:262 calls rent_accounts (adapters/raydium.rs:987-992). The source is the Sickle, the receiver is the owner.
  6. venue/keeper_exit.rs:266-269 calls global_automator (adapters/raydium.rs:969-971) for the keeper check.
  7. venue/keeper_exit.rs:278 calls position_settings (adapters/raydium.rs:977-979) for the settings identity check.
  8. venue/keeper_exit.rs:286 calls validate_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.
  9. venue/keeper_exit.rs:294 calls prepare_keeper_exit (adapters/raydium.rs:1003-1052). The adapter checks the pool and position owners and parses N reward groups and N collectors. It checks the bitmap PDA and both fee collector accounts. It builds the account bundle on the heap (:1115-1126).
  10. venue/keeper_exit.rs:295 calls load_keeper_exit_state (adapters/raydium.rs:1055-1076). The adapter reads the position and the current tick.
  11. venue/keeper_exit.rs:307-310 calls intent_sickle, position_settings, and intent_assets (adapters/raydium.rs:985) to open the action ledger.
  12. venue/keeper_exit.rs:316 calls accounts_closed_by_protocol (adapters/raydium.rs:994-1000).
  13. venue/keeper_exit.rs:318 calls execute_keeper_exit (adapters/raydium.rs:1079-1111). The adapter calls collect_drain_charge_close_with_actions (venue/adapters/raydium_flows.rs:502-603) and maps the outcome into RawDrainFlowReceipt.
  14. 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

  1. 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). Error InvalidAccountOwner.
  2. 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. Error InvalidPosition.
  3. 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). Error InvalidProtocolAccountData or InvalidPosition.
  4. 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). Errors RewardGroupMissing, RewardGroupMismatch.
  5. 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). Errors RewardRecipientMismatch, RewardCollectorMismatch.
  6. A hook slice starts with the mint's hook program, and a mint without a hook carries no accounts (fees.rs:519-560). Error TransferHookAccountsMissing.
  7. The Raydium bitmap account, when present, is the pool's bitmap PDA (venue/adapters/raydium_flows.rs:1378-1394). Error InvalidPosition.
  8. 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 from assert_mint_extensions_for_custody.
  9. On Orca, each token program equals the owner of its mint (adapters/orca.rs:1361-1368, :1465-1472). Error InvalidAccountOwner.
  10. On decrease and close, the venue program equals its allowlist slot. The adapter checks it because these two traits have no ActiveFlowPolicy supertrait (adapters/orca.rs:1452-1453, :1601-1602, adapters/raydium.rs:1719-1720, venue/adapters/raydium_flows.rs:826).
  11. 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 from assert_fee_collector_account.
  12. The Orca reward token program in the remaining accounts is the classic Token program and is executable (adapters/orca.rs:94-102). Error InvalidAccountOwner.

Tests

Test locationWhat it covers
programs/sickle/tests/clmm_conformance.rsCompile-time proof that every Orca and Raydium struct implements the adapter traits its manifest requires.
programs/sickle/tests/ui/*.rs22 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.tsIntegration tests that exercise every adapter method through the instructions.
tests/surfpool-lifecycle.ts, surfpool-raydium-lifecycle.ts, surfpool-t22-*.tsMainnet-fork lifecycles with real reward slots and Token-2022 pools.
instructions/raydium/decrease_liquidity.rs unit testsThe Raydium reward-group parser and same-mint reward handling.
instructions/orca/rebalance_for.rs unit testassert_token_2022_mint.
adapters/orca.rs:1688-1977, 4 unit teststake_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.

  1. L04-N007 — The Raydium bitmap check runs at three different points for the same instruction shape. RaydiumCollectFees checks it after the reward groups (adapters/raydium.rs:1138, macro argument false). RaydiumHarvestFor checks it before the reward groups (:1162, argument true). RaydiumCompoundFor defers it to claim_all_yield (:1186, bitmap = deferred). The PreparedBitmap enum 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.
  2. 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. DecreaseFlowAdapter and CloseFlowAdapter have no ActiveFlowPolicy supertrait (venue/decrease_close.rs:93, :217), so the same check is owned by two layers. Kept: closing this needs a supertrait added in venue/, which is the shared-runner layer and is sequenced separately.
  3. L04-N010 — RaydiumRebalanceFor checks the protocol position and the memo program in the adapter (adapters/raydium.rs:660-669). RaydiumExitFor checks the same two accounts in the adapter (:955-967) and the memo program again through address = MEMO_PROGRAM_ID (instructions/raydium/exit_for.rs:194). RaydiumRebalancePosition checks both through address = only. Three structs, three placements. Kept: two of the three placements are account-struct attributes in handler files.
  4. L04-N011 — assert_keeper_position_nft_account (adapters/raydium.rs:857-874) and assert_token_2022_mint (instructions/orca/rebalance_for.rs:241-252) re-implement Anchor token:: and mint:: 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.
  5. L04-N012 — validate_keeper_exit_static_accounts on ExitFor returns Ok(()) (adapters/orca.rs:875-877). The memo check for that flow runs inside withdraw_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.
  6. L04-N014 — prepare_orca_yield! and claim_orca_yield! (adapters/orca.rs:267-398) are macros with a $accounts:expr argument that must resolve to a struct with 17 named fields. The same holds for prepare_raydium_yield! and claim_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 in venue/.
  7. L04-N015 — execute_open on Raydium builds the account list with vec![...] and a conditional push for the bitmap (adapters/raydium.rs:1307-1331). execute_increase repeats the same pattern (:1482-1501). The shared Orca helper pushes into a Vec instead, 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.
  8. L04-N016 — load_keeper_rebalance_state and load_keeper_exit_state ignore the _prepared parameter 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 in venue/ and every call site, which is wider than the one-line caller updates this contract allows.
  9. L04-N017 — RaydiumCollectFees implements ClaimAllYieldAdapter (adapters/raydium.rs:1128), the keeper yield trait, while OrcaCollectFees implements CollectTradingFeesAdapter (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.
  10. L04-N018 — RaydiumExitFor.fee_collector_account_0 and _1 are typed InterfaceAccount with constraints (instructions/raydium/exit_for.rs:159-167), and prepare_keeper_exit checks them again with assert_fee_collector_account (adapters/raydium.rs:1032-1041). Both rebalance handlers share RaydiumRebalanceFeeCollectors, whose two fields are UncheckedAccount (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.
  11. L04-N019 — adapters/raydium.rs has 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.
  12. 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.
  13. L04-N021 — The compiled artifact checks an adapter refactor in one direction only. The build is reproducible, so a byte-identical .so is sufficient evidence that behavior did not change. A differing .so proves nothing. Anchor stores the source line of every require! in its error origin, so three added comment lines change the hash. Expanded-source comparison supplements it. cargo expand of the two modules, with line: <n>u32 normalized away, shows whether anything other than those positions moved. It does not cover SBF codegen, the IDL, the account metas, or parser output.
  14. L04-N022 — PreparedBitmap::ValidateBeforeClaim (adapters/raydium.rs:69) is produced by exactly one call site, the compound prepare, and consumed by claim_raydium_yield!. It is a two-variant enum in service of one flow.

Resolved

  1. L04-R001 — adapters/orca.rs:776-787 keeper_drain_accounts, adapters/orca.rs:962-973 keeper_exit_drain_accounts, and venue/adapters/orca_flows.rs:546-557 drain_accounts build OrcaDrainAccounts from three structs with the same field list. adapters/raydium.rs:879-890, :1111-1122, and venue/adapters/raydium_flows.rs:448 repeat 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 expand raydium_drain_accounts_from!; both macros now sit beside the struct they fill, in the flows module.

  2. L04-R002 — adapters/raydium.rs:11-21 imports the CPI helpers and the account bundles from handler files. The adapter layer depends upward on the handler layer for decrease_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_charge and withdraw_collect_charge_close_with_actions now live in adapters/orca_flows.rs, and adapters/orca.rs:5-11 reaches 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.

  1. L04-R003 — adapters/orca.rs:279-306, :603-630, and :961-988 hold 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.
  2. L04-R004 — adapters/orca.rs:376-415, :705-749, and :1043-1087 map DrainOutcome into RawOwnerRebalanceReceipt with the same code. adapters/raydium.rs:398-445, :744-791, and :1138-1185 do the same for RaydiumDrainOutcome. Six copies of one mapping. Resolved in #175.
  3. L04-R005 — adapters/orca.rs:419-444 execute_reopen and adapters/orca.rs:753-778 execute_keeper_reopen have identical bodies. adapters/raydium.rs:449-479 and adapters/raydium.rs:795-825 match the same way. Resolved in #175.
  4. L04-R006 — ActiveFlowPolicy is implemented 5 times in adapters/orca.rs (:181, :464, :843, :1261, :1397) and 5 times in adapters/raydium.rs (:208, :498, :928, :1313, :1496). Each body reads the same four fields. Resolved in #175.
  5. L04-R007 — intent_accounts is 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 is funder, the exit payer is authority. intent_assets is implemented 4 times with identical bodies (adapters/orca.rs:554-567, :921-934, adapters/raydium.rs:591-604, :1013-1026). Resolved in #175.
  6. L04-R008 — RaydiumCompoundFor::prepare_all_yield (adapters/raydium.rs:1275-1301) repeats the body of prepare_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.

Source: docs/dev/layers/04-venue-adapters.md in vfat-io/sickle-programs, vendored here by its sync workflow. Edit the markdown there; this page is rebuilt from it on deploy.