Repository navigation
feat(sdk-coin-sol): rewrite fee payer for versioned custom transactions - #9849
Draft
ralph-bitgo[bot] wants to merge 2 commits into
Draft
ralph-bitgo[bot] wants to merge 2 commits into
ralph-bitgo[bot] wants to merge 2 commits into
Conversation
Contributor
3 tasks done
ralph-bitgo
Bot
force-pushed
the
CHALO-1652-fee-payer-rewrite-versioned-tx-pt2
branch
from
September 29, 2026 10:56
0f66fca to
4d5b460
Compare
Add addFeePayerSignature(publicKey, signature) to Transaction and TransactionBuilder, wrapping the existing addSignature() and rejecting a key that is not account 0 of the message (the fee payer). For versioned transactions account 0 is the first static account key; for legacy transactions web3.js places the fee payer first, so the signature lands in slot 0 on both. Sponsored SOL transactions need the enterprise fee key's signature in slot 0 (CHALO-983); SOL had no such method yet. This is the CHALO-996 dependency surface of the fee-payer rewrite. Ticket: CHALO-1652 Session-Id: c2138ca7-d8a2-46e6-8dd0-e00e22cc44c0 Task-Id: 40c147ec-2821-4dfc-a85f-85bc82e625fa
ralph-bitgo
Bot
force-pushed
the
CHALO-1652-fee-payer-rewrite-versioned-tx-pt1
branch
from
September 29, 2026 10:56
29f424f to
71b0f65
Compare
In fromVersionedTransactionData(), when feePayer() is set and differs from staticAccountKeys[0], rewrite the message so the fee payer becomes static account 0: insert it as a writable signer, or move it there and adjust numRequiredSignatures plus the header read-only counts of the section it left. Every static and lookup-table index is remapped with one full old to new map, so instructions keep targeting the same accounts, and a fee payer that is an address lookup table account is rejected. The rewrite runs before injectNonceAdvanceInstruction(), so a fee payer that is also the nonce authority is already a signer and ends up with a single signature. Without feePayer() the data is used as supplied, so no bytes change for today's callers. Today .feePayer() has no effect on versioned transactions, so caller-built customTx / WalletConnect transactions cannot be sponsored by the enterprise fee address (CHALO-983): the fee payer of a versioned transaction is simply staticAccountKeys[0] as the caller supplied it. Also add EnterpriseFeePayerParams to iface.ts as the named params type for sponsored builds, and document that wallet-platform must not rewrite a transaction a third party has already signed (it would invalidate signatures); those build wallet-pays. Ticket: CHALO-1652 Session-Id: c2138ca7-d8a2-46e6-8dd0-e00e22cc44c0 Task-Id: 40c147ec-2821-4dfc-a85f-85bc82e625fa
ralph-bitgo
Bot
force-pushed
the
CHALO-1652-fee-payer-rewrite-versioned-tx-pt2
branch
from
September 29, 2026 10:58
4d5b460 to
d40972c
Compare
MohammedRyaan786
force-pushed
the
CHALO-1652-fee-payer-rewrite-versioned-tx-pt1
branch
from
October 7, 2026 06:17
71b0f65 to
a0c5168
Compare
This branch has not been deployed
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.
What
CustomInstructionBuilder.fromVersionedTransactionData(), whenfeePayer()is set and differs fromstaticAccountKeys[0], the versioned message is rewritten so the fee payer becomes static account 0 (the fee payer of a versioned transaction is simplystaticAccountKeys[0]as supplied, so.feePayer()previously had no effect):numRequiredSignaturesis incremented;numRequiredSignaturesis incremented if it was a non-signer, and the read-only count of the section it left is decremented (numReadonlySignedAccountsfor a read-only signer,numReadonlyUnsignedAccountsfor a read-only non-signer);injectNonceAdvanceInstruction(), so when the fee payer is also the nonce authority it is already a signer and carries a single signature, withAdvanceNonceAccountstill instruction 0.EnterpriseFeePayerParams { feePayer: string }tosrc/lib/iface.tsas the named params type for sponsored builds.fromVersionedTransactionData()that wallet-platform must NOT set a fee payer for a versioned transaction a third party has already signed (the rewrite invalidates existing signatures); wallet-platform builds those wallet-pays.Why
customTx, WalletConnect) cannot be sponsored without this rewrite, because a versioned message's fee payer is whatever the caller put instaticAccountKeys[0]. The rewrite only happens when.feePayer()is called, so no bytes change for today's callers.injectNonceAdvanceInstruction()fixes): merged its branch into this one on a throwaway branch and the full module suite passes (783 tests, including all fee-payer tests). The tests deliberately assert viaindexOf-computed indexes instead of pinning nonce-injection header details, so fix(sdk-coin-sol): fix three bugs in injectNonceAdvanceInstruction #9846's fixes do not break them. The only merge conflict is textual in the test file (both PRs append adescribeblock at the same anchor); keeping both blocks resolves it.Stack
This PR is part 2 of 2 in a stack. Review and merge in order:
addFeePayerSignature()(CHALO-996 dependency surface; base:master)CHALO-1652-fee-payer-rewrite-versioned-tx-pt1) ← you are hereTest plan
npx mocha test/unit/transactionBuilder/customInstructionBuilder.ts: fee payer inserted at account 0 with correct header and remapped indexes (message compiles and round-trips); a real Jupiter swap proves lookup-table instructions still target the same accounts after the +1 shift; non-signer / read-only non-signer / read-only signer moves with the matching header adjustments and no duplicate keyAdvanceNonceAccountis instruction 0 with the authority at account 0addFeePayerSignature()produces byte-identical output to the native sign flow (slot 0); non-account-0 keys are rejectedfeePayer()(and withfeePayer()equal to the existing account 0) bytes are identical to a directMessageV0construction of the caller's datanpm run lintandtsc --buildclean inmodules/sdk-coin-solTicket: CHALO-1652