Skip to content

fix(swap): forward the quoted buy fee into the existing-currency swap transaction - #1277

Merged
bmc08gt merged 1 commit into
code/cashfrom
fix/buy-fee-instruction
Aug 20, 2026
Merged

fix(swap): forward the quoted buy fee into the existing-currency swap transaction#1277
bmc08gt merged 1 commit into
code/cashfrom
fix/buy-fee-instruction

Conversation

@bmc08gt

@bmc08gt bmc08gt commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

The bug

Every fee-bearing Get (buy) failed. DifferKt shows the server's transaction and the client's diverging on the VM instruction:

opcode accounts data
server 0x14 VM::TransferForSwapWithFee 0, 17, 3, 8, 7, 5, 16, 12 14 + 500000 + 5000 + bump (18 bytes)
client 0x11 VM::TransferForSwap 0, 16, 3, 8, 7, 5, 12 11 + 500000 + bump (10 bytes)

The server's account list carries one extra entry — the fee destination at index 16 — so every client index at or above 16 is shifted down by one. That accounts for every other mismatched line in the diff; the signatures can never match.

Root cause

The ExistingCurrency branch of IntentStatefulSwap.transaction() never forwarded request.feeAmount to TransactionBuilder.swap, so it silently took that function's feeAmount = 0 default. The client quoted the fee to the server in the initiate request (LocalToProtobuf.setFeeAmount), then built the no-fee instruction anyway.

Everything downstream was already correct and tested — the proto parsing of feeDestination, the with-fee instruction builder, and the selection logic in buildExistingCurrencyBuyInstructions. Only the one call site was wrong. The NewCurrency and Stablecoin branches immediately below it both forward the fee, which is why only existing-currency buys broke.

The change

  • Forward request.feeAmount?.underlyingTokenAmount?.quarks ?: 0 in the ExistingCurrency branch.
  • Drop TransactionBuilder.swap's feeAmount = 0 default. It has exactly one non-test caller, so the same omission is now a compile error instead of a silently fee-less transaction.
  • feeAmount is consumed only by the SwapRoute.Buy branch inside swapbuildSellInstructions and buildCrossCurrencyExistingSwapInstructions take no fee parameter — so this is a no-op for sells and cross-currency swaps.

Testing

ExistingCurrencyBuyFeeTest is a JVM unit test, so it runs in CI — the existing swap coverage lives in androidTest, which does not. The key case drives the real IntentStatefulSwap with a real StatefulSwapRequest at the amounts from the failing log (500000 swap / 5000 fee) and asserts the transaction carries opcode 0x14 with both amounts encoded.

… transaction

The `ExistingCurrency` branch of `IntentStatefulSwap.transaction()` never passed
`request.feeAmount` to `TransactionBuilder.swap`, so it silently took the old
`feeAmount = 0` default. The client quoted a fee to the server in the initiate
request, the server built `VM::TransferForSwapWithFee` (opcode 0x14, 8 accounts,
18 bytes) — and the client built the plain `VM::TransferForSwap` (0x11, 7
accounts, 10 bytes). The missing fee-destination account also shifted every
downstream account index by one, so the two transactions could never match and
every fee-bearing "Get" failed to sign.

The `NewCurrency` and `Stablecoin` branches directly below it both already
forwarded the fee, which is why only existing-currency buys broke.

`TransactionBuilder.swap` loses its `feeAmount = 0` default so the same omission
becomes a compile error rather than a silent no-fee transaction. `feeAmount` is
consumed only by the Buy route; sells and cross-currency swaps ignore it, so
this is a no-op for them.

Adds a regression test that drives the real `IntentStatefulSwap` and fails
without the fix.
@github-actions github-actions Bot added type: fix Bug fix area: crypto Solana, keys, encryption, signing area: network gRPC, connectivity, API, exchange rates area: intents Intent construction, submission, server-side state labels Aug 20, 2026
@bmc08gt
bmc08gt merged commit 42785b8 into code/cash Aug 20, 2026
3 checks passed
@bmc08gt
bmc08gt deleted the fix/buy-fee-instruction branch August 20, 2026 16:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: crypto Solana, keys, encryption, signing area: intents Intent construction, submission, server-side state area: network gRPC, connectivity, API, exchange rates type: fix Bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant