Support Token-2022 in BeginSettle and FinalizeSettle - #128
Open
kaze-cow wants to merge 2 commits into
Open
Conversation
This was referenced Aug 28, 2026
`BeginSettle` and `FinalizeSettle` each took a `token_program` account and rejected anything that wasn't the legacy SPL Token program, so the buffers `CreateBuffer` can now open under Token-2022 had no way to be settled. They accept it too, and issue every transfer against whichever of the two they were handed, through the same `token::validate_token_program` gate the buffer instructions use. Token-2022 encodes `Transfer` exactly as the legacy program does, so only the CPI target changes. What differs is the account data: a Token-2022 account carrying extensions is longer than the base layout, and the legacy reader insists on an exact length. Both sides now read through `token::read_token_account`, which dispatches on the validated program — the sell account's owner in `BeginSettle`, the destination's mint in `FinalizeSettle`. That reader grows the `mint` and `owner` fields the settlement needs and the buffer instructions didn't, which costs `ReclaimBuffer` a little: its `max_buffers_in_one_instruction` goes 137,046 -> 138,392 CU for the wider read. The settle benchmarks rise 0.3-1.6% from the added dispatch. The `token_program` account is shared by the whole instruction, so every token one settlement touches must live under the same program; a mixed settlement still needs two instruction pairs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`BeginSettle` and `FinalizeSettle` took one `token_program` account, so every token an instruction touched had to live under the same program: settling a legacy SPL mint and a Token-2022 mint meant two instruction pairs. They now take one account per supported program, at fixed positions after the state PDA, and issue each transfer against the program that owns the account it moves. One pair can settle both, and the two sides of a single order need not agree — the pull follows the sell account's owner, the push the buy account's. A program the settlement doesn't touch is left out by putting the system program in its slot. The transfers still need their program named by the transaction, so the placeholder is how an instruction says this one isn't; in a transaction that already references the system program it costs an account index instead of another 32-byte address. Nothing new goes into the instruction data: the owner is the authority on which program an account belongs to, and the slots only decide whether the settlement can reach it. Resolving an account gives one of three answers: - owned by a carried program: its transfers CPI into that program; - owned by a supported program whose slot holds the placeholder: the new `SettlementError::TokenProgramNotProvided` (36), so a forgotten slot reads as itself rather than as a malformed account; - owned by neither: the existing `SellTokenAccountInvalid` / `InvalidBuyTokenAccount`, unchanged. The slots are positional. Each holds its own program or the placeholder; anything else, swapping the two included, is `IncorrectProgramId`. `FINALIZE_FIXED_ACCOUNTS` becomes 4, which `push_destinations` follows on its own. `CreateBuffer` and `ReclaimBuffer` keep their single `token_program` account: each works on one mint at a time, so there is nothing to mix. The settle benchmarks each gain one account, 34 transaction bytes, and 50-170 CU. The one- and two-unit drift on the unrelated create/reclaim lines is codegen, not behaviour. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
kaze-cow
force-pushed
the
kaze/sc-153-token-2022-settle
branch
from
August 28, 2026 08:29
7af181d to
35bb3fe
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add support for Token2022. Both token programs can be used in the same settlement without issues.
Motivation
BeginSettleandFinalizeSettleeach took atoken_programaccount and rejected anything but the legacy SPL Token program. As settlements may need to pull or push from many different in the same settlement, we need a way to specify both.Methodology
Rather than including one token program per order, since there are only two possible token programs we are ever anticipating needing to support, we add the token2022 program to the list of fixed accounts for both
BeginSettleandFinalizeSettle.If either the token2022 program or the SPL token program is not required to complete the relevant settlement instruction, they can be excluded without incurring account cost by setting the slot to the system program.
Compute cost
bench-report.jsonis regenerated. The settle benchmarks each gain one account, 34 transaction bytes, and 50–170 CU on top of the Token-2022 dispatch above.Out of scope
Integration tests are expanded in #121
Test Plan
Verify methodology.
🤖 Generated with Claude Code