Skip to content

feat(token-2022) PR 1: settle Token-2022 mints under their own token program - #5002

Merged
squadgazzz merged 4 commits into
mainfrom
solana-driver/be-337-settle-token-2022-tokens
Oct 2, 2026
Merged

squadgazzz merged 4 commits into
mainfrom
solana-driver/be-337-settle-token-2022-tokens

Conversation

@squadgazzz

@squadgazzz squadgazzz commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Description

Solana has two token programs: the classic SPL Token program and Token-2022. Every mint belongs to one of them. The settlement program handles both, even mixed in one settlement (cowprotocol/solana-programs#128). But the driver assumes SPL Token for every mint.

So any settlement that moves a Token-2022 mint fails simulation. BeginSettle pulls the user's sell tokens into the payer's ATA. The payer is the solver account that signs the settlement. An ATA address derives from the wallet, the mint and the token program, so the driver derives the wrong address and asks SPL Token to create it. On the buy side, CreateBuffers initializes the buffers (token accounts that hold the bought tokens until payout) under one token program, and the driver always passes SPL Token.

This PR looks up the program that owns each mint account. That lookup has to run first, since the addresses of the accounts the driver checks and creates depend on it. The Solana adapter caches the answer, so only the first lookup of a mint costs an extra RPC round trip. The entries never expire. A mint changes owner only if it is closed and re-created, and its settlements would then fail simulation until the driver restarts.

The buy token account check from #4982 derives an order's ATA the same way, so at /solve the driver reads the buy mints before the buy token accounts. An order whose buy mint is missing or not a mint is dropped from the auction, since no settlement can pay it out.

Mints with transfer fees or transfer hooks still fail simulation, because the program moves tokens with a plain Transfer and Token-2022 rejects that for them. #5003 keeps them out of the auction.

Changes

  • The Solana adapter reads and caches each mint's token program
  • The payer's ATAs, the orders' buy ATAs and the BeginSettle pull destinations derive under their mint's token program
  • One CreateBuffers instruction per token program with missing buffers
  • Existing Token-2022 buffers and ATAs count as usable, so the settlement skips creating them
  • /solve drops an order whose buy mint is missing on chain or not a mint of either token program
  • A settlement fails to build with InvalidMint when one of its mints is missing on chain or not a mint of either token program. The error names which.

How to test

New unit tests. Updated unit and API tests.

Related issues

BE-337

@linear-code

linear-code Bot commented Sep 30, 2026

Copy link
Copy Markdown

BE-337

@squadgazzz squadgazzz changed the title solana-driver: settle Token-2022 mints under their own token program feat(token-2022) PR 1: settle Token-2022 mints under their own token program Oct 1, 2026
@squadgazzz
squadgazzz marked this pull request as ready for review October 1, 2026 12:32
@squadgazzz
squadgazzz requested a review from a team as a code owner October 1, 2026 12:32
@claude

claude Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Claude finished @squadgazzz's task in 7m 44s —— View job


Review complete ✅

I reviewed the diff against origin/main. This is a clean, well-documented, and thoroughly tested PR. The core logic is sound:

  • Mints are resolved before the accounts that derive from them in resolve_accounts (correct ordering — ATA addresses depend on the token program).
  • token_programs caching, the empty-input short-circuit in multiple_accounts, duplicate-mint handling via partition_map, and the per-program CreateBuffers loop (over sorted missing_buffers, deterministic) all check out.
  • Invalid-mint handling is consistent across both paths: dropped as unreceivable at /solve, and fails the build with InvalidMint at settle time.
  • The Mint-vs-token-account disambiguation (StateWithExtensions::<Mint>::unpack + owner check) is tested for the Token-2022 account case.
  • wSOL is correctly kept on the SPL Token program throughout (require_token_balance, close_token_account, native_payout_funding).

One minor point (posted inline):

  • In classify_buy_token_accounts the mint lookup and the account lookup are independent (the fetched address is the solver-supplied buy_token_account, not a derived ATA), so the sequential ordering isn't required here and the explanatory comment's justification doesn't apply on this path. They could run concurrently to save a round trip on cache misses, or the comment could be adjusted.

Nothing blocking. Nice work on the test coverage and the inline documentation.

--- · solana-driver/be-337-settle-token-2022-tokens

Comment thread crates/solana-driver/src/domain/auction.rs Outdated
@squadgazzz
squadgazzz marked this pull request as draft October 1, 2026 12:44
`resolve_accounts` turns the chain results into a `TokenPrograms` map first and hands it to the setup account derivation, the missing account check and the instruction builder. One lookup and one `UnresolvedMint` error for a mint outside `Settlement::mints`, shared by `ResolveError` and `Error`. The infra `MintPrograms` newtype goes away: its `get` read a mint that was never looked up as not found, which conflated a code bug with a chain fact.

The results arrive in a `HashMap`, so with several invalid mints the reported one varies. The test accepts either mint of the order.
The fetched addresses are the orders' buy token accounts, the program is only compared against them afterwards, so the two lookups do not depend on each other.
@squadgazzz
squadgazzz marked this pull request as ready for review October 1, 2026 17:18
@claude

claude Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Claude finished @squadgazzz's task in 4m 22s —— View job


Re-review complete ✅

I re-reviewed the full diff against origin/main. This remains a clean, carefully-documented, and thoroughly-tested PR. I found no new blocking issues.

What I verified this pass:

  • Lookup ordering is correct where it matters. In resolve_accounts the account addresses genuinely derive from each mint's token program, so reading mints first is required. The per-program CreateBuffers loop over sorted missing_buffers is deterministic (iterates TokenProgram::ALL).
  • mints() covers every downstream lookup — sell mints, token-buy mints, and wSOL for native-SOL buys — so every token_programs.get(..)? in setup_accounts, accounts_to_create, orders(), and instructions() resolves; the UnresolvedMint/InvalidMint arms are purely defensive and map to Unknown.
  • Cache semantics. Only resolved programs are cached; missing/invalid mints are re-read (documented). The resolved_token_programs_are_cached test is sound — the Solana MockSender consumes a Mocks entry once, so the second lookup only succeeds via the cache, and the first fetch's [mint, absent] chunk zips in order against [mint_account, null].
  • Mint disambiguation (StateWithExtensions::<Mint>::unpack + owner check) correctly rejects Token-2022 token accounts as NotAMint, and both Initialized/Frozen Token-2022 account states are tested.
  • wSOL stays on SPL Token throughout (native_payout_funding, require_token_balance, close_token_account).
  • Solve/settle consistency: the buy-ATA is_ata(program) check at /solve and the accounts_to_create derivation at settle both use the mint's resolved program, so they agree.

One standing note (already posted inline on classify_buy_token_accounts, not re-posting): on the /solve path the mint lookup and the buy-token-account lookup are independent and could run concurrently to save a serial round trip on a cache miss — caching makes this negligible in steady state.

CI: no failures so far (cla, signature verification green; pull request, CodeQL still running).

Nice work on the test coverage and the inline documentation.
· solana-driver/be-337-settle-token-2022-tokens

@squadgazzz
squadgazzz added this pull request to the merge queue Oct 2, 2026
Merged via the queue into main with commit c48fb0b Oct 2, 2026
26 checks passed
@squadgazzz
squadgazzz deleted the solana-driver/be-337-settle-token-2022-tokens branch October 2, 2026 17:58
@github-actions github-actions Bot locked and limited conversation to collaborators Oct 2, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants