Skip to content

Add CPI inner instruction scanning to charge scheme for smart wallet support#151

Open
0xultravioleta wants to merge 1 commit into
faremeter:mainfrom
0xultravioleta:feat/cpi-inner-instruction-scanning
Open

Add CPI inner instruction scanning to charge scheme for smart wallet support#151
0xultravioleta wants to merge 1 commit into
faremeter:mainfrom
0xultravioleta:feat/cpi-inner-instruction-scanning

Conversation

@0xultravioleta
Copy link
Copy Markdown

Summary

Smart wallets on Solana (Squads, Crossmint, SWIG) route SPL token transfers through cross-program invocations (CPI). The actual TransferChecked instruction lives inside an inner instruction, not at the top level of the transaction.

The @faremeter/x-solana-settlement scheme already handles this pattern — its isValidTransferTransaction, extractTransferData, and isValidMemo functions all scan transaction.meta.innerInstructions when top-level matching fails. This PR brings the same capability to the charge scheme in packages/payment-solana.

Changes

packages/payment-solana/src/charge/server.ts

  • fetchConfirmedTransaction() now returns innerInstructions and staticAccountKeys from the on-chain transaction meta alongside the decompiled message
  • The push-mode ("signature" payload) path passes inner instructions to verifyChargeTransaction

packages/payment-solana/src/charge/verify.ts

  • VerifyChargeTransactionArgs accepts optional innerInstructions and staticAccountKeys
  • New findTransferInInnerInstructions() function scans CPI inner instructions for TransferChecked as a fallback when no top-level match is found
  • Same security checks as the top-level path: mint must match, destination must be the correct ATA, amount must match, authority must not be the fee payer, exactly one matching transfer allowed
  • Supports both spl_token and spl_token_2022 programs

Backward compatibility

Existing top-level transfers still match first. The inner instruction path only activates as a fallback when the existing top-level scan returns no match. All existing exact/verify.test.ts tests pass unchanged (36/36).

Context

Smart wallets (Squads, Crossmint, SWIG) route SPL token transfers
through cross-program invocations. The TransferChecked instruction
lives inside an inner instruction, not at the top level.

The x-solana-settlement scheme already handles this pattern in its
isValidTransferTransaction and extractTransferData functions. This
commit brings the same capability to the charge scheme:

- fetchConfirmedTransaction now returns innerInstructions and
  staticAccountKeys from the on-chain transaction meta
- verifyChargeTransaction falls back to scanning inner instructions
  when no top-level TransferChecked matches
- Same security checks apply: mint, destination ATA, amount must
  match; authority must not be the fee payer; exactly one matching
  transfer allowed

Backward compatible: existing top-level transfers still match first.
The inner instruction path only activates as a fallback.

Ref: faremeter#150
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Extend CPI inner instruction scanning to exact and charge schemes for smart wallet support

1 participant