This release captures the changes that extend the React Native CLI wallet's WalletConnect Pay reference implementation to support Solana payments end-to-end, alongside the existing EVM flows. It is intended as a documentation/reference checkpoint for other wallet teams adding Solana to their WCPay integration — this repo has no semver product stream and uses these release tags purely as integration milestones.
Scope is intentionally narrow: only the single PR listed under Included PRs below. Unrelated CI, dependabot, and other-wallet changes on main are not part of this release. See the attached patch for the exact diff.
Prerequisites. This release assumes your wallet already has:
- A working WCPay action-chain executor for EVM — see the
rn-cli-wallet-wcpay-usdtrelease if you have not implemented that yet. - A general Solana signing capability — an ed25519 keypair and a
signTransactionfunction that takes an unsigned base64 transaction and returns a fully signed base64 transaction. The reference wallet usesSolanaLib(added in #500), but any equivalent signer works.
Everything below is purely the WCPay-flow integration on top of those two prerequisites.
What this enables
- SOL-native payments via WCPay. When a Pay link's merchant supports Solana, the wallet now surfaces a SOL payment option in the picker, signs the backend-returned transaction with the user's Solana key, and forwards the signed blob to
confirmPayment. The backend broadcasts; the wallet never touches a Solana RPC for this flow. - Mixed-namespace option lists. A single Pay link can return EVM and Solana options side-by-side. The wallet sends both
eip155:…:0x…andsolana:…:<pubkey>entries inaccounts[], lets the user pick, and routes the chosen action chain to the correct signer at execution time. - Per-action wallet resolution. The Pay action executor no longer assumes one wallet type per payment. Each returned action is dispatched by its CAIP-2 namespace, so future namespaces (Sui, TON, etc.) can be added in the same handler without restructuring it.
Implementation requirements for other wallets
These are the wallet-integration contracts other implementers must follow to add Solana to WCPay. They are the public takeaway from this release. The EVM contracts from the previous release (rn-cli-wallet-wcpay-usdt) still apply — these are additive.
- Advertise Solana accounts in
getPaymentOptions. Include the user's Solana account(s) in theaccounts[]array as CAIP-10 strings —solana:<chainReference>:<base58Pubkey>— alongside any EVM entries. Without this, the backend cannot return SOL-denominated options even when the merchant supports them. Mainnet reference issolana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp. - Resolve the signing wallet per action by CAIP-2 namespace — not once per payment. The wallet for action
iis determined byactions[i].walletRpc.chainId.split(':')[0]. An eager EVM-wallet lookup at the top ofapprovePaymentis incorrect: it will throw on Solana-only payments even when the Solana wallet is initialized, and it will pick the wrong key on mixed-namespace payments. - Implement the
solana_signTransactionmethod. Sign the transaction with the user's Solana key and append the signed transaction blob, base64-encoded, to thesignatures[]array. This is the same array used for EVM tx hashes and typed-data signatures — keep ordering: indexiofsignaturescorresponds to actioni. - Do NOT submit the bs58 detached signature. The Solana backend expects the fully signed transaction, base64-encoded, and broadcasts it server-side. Submitting the bs58 signature from
nacl.sign.detachedwill fail with a validation error. Most Solana signer libraries return both — be explicit about which one you forward. - Do NOT implement
solana_signAndSendTransactionfor the Pay flow. It is intentionally out of scope: the backend broadcasts. If your wallet's generic session_request handler implements it for non-Pay requests, that is fine, but the Pay action executor should not call it. solana_signTransactionparams are array-wrapped. The Pay backend sends params as a single-element array wrapping the payload —[{ transaction }]— matching the WC-style array invariant used by EVM methods. Thetransactionfield is the unsigned tx, base64-encoded.- Defensively validate the signer at action-execution time. Even though a Solana action will only be returned when your wallet advertised a Solana account in
accounts[], the wallet's signer state may have changed between option fetch and action execution (e.g. the user cleared keys, switched profiles). Guard the action handler against a missing signer and surface an error rather than silently skipping the action — the backend will reject a shortsignatures[]array regardless. - Reject unknown wallet-RPC methods. Same rule as the EVM contract: throw rather than skip. Partial result arrays will be rejected.
Reference implementation (all in PR #501):
- Per-action namespace dispatch:
PaymentStore.approvePayment— see theswitch (namespace)block that resolves eitherevmWalletorsolanaWalletper action. solana_signTransactioncase: same file, theSOLANA_SIGNING_METHODS.SOLANA_SIGN_TRANSACTIONbranch — notesignatures.push(signedTransaction), the base64 blob, not the bs58signature.- Account advertisement:
usePairing.handlePaymentLink—accounts[]is concatenated from EVM and Solana chain maps.
End-to-end flow
- User → Wallet: paste a Pay link.
- Wallet → Pay backend:
getPaymentOptions({ accounts: ["eip155:…:0x…", "solana:…:<pubkey>"] }). - Pay backend → Wallet: options list, including SOL-denominated options.
- User → Wallet: tap Pay on the SOL option.
- Wallet → Pay backend:
getRequiredPaymentActions({ paymentId, optionId }). - Pay backend → Wallet:
[{ chainId: "solana:…", method: "solana_signTransaction", params: [{ transaction }] }]. - Wallet → Solana signer:
signTransaction({ transaction }). - Solana signer → Wallet:
{ transaction: <signedB64>, signature: <bs58> }. - Wallet → Pay backend:
confirmPayment({ signatures: [<signedB64>] })— forwarding the base64 signed transaction, not the bs58 signature. - Pay backend → Wallet:
succeeded(backend broadcasts server-side).
Validate your integration
Run your wallet through these flows to confirm Solana support implements the contracts above correctly:
- SOL-only Pay link: merchant supports only Solana; SOL option appears in the picker;
solana_signTransactionaction signs andconfirmPaymentreturnssucceeded. Inspect thesignatures[]payload and confirm it is the base64 signed-transaction blob, not the bs58 signature. - Mixed EVM+SOL Pay link: both EVM and SOL options appear; picking SOL completes via the Solana signer; picking the EVM option still completes via the EVM action chain. Both should work in the same wallet session without restarting.
- EVM regression: existing Permit2 / USDT / native-token flows from the
rn-cli-wallet-wcpay-usdtrelease continue to work end-to-end. The per-action namespace dispatch must not regress EVM behavior. - No Solana account → no SOL option: if the wallet has not generated/imported a Solana key, it must not advertise a
solana:…entry inaccounts[]. A merchant that supports only Solana should result in the Pay backend returning no compatible options (or the wallet's "no options" empty state), never a SOL option the user cannot complete. - Param parsing: confirm your wallet correctly unwraps the array-wrapped
params = [{ transaction }]shape sent by the Pay backend and feeds the innertransactionstring into your signer. See the array-wrapped Solana case inPaymentStore.test.ts.
Included PRs
This release contains exactly this one merged PR and nothing else. The patch is attached to this release for verification.
- #501 — feat(rn_cli_wallet): add Solana support in WalletConnect Pay (merge
b4e7cb57).usePairingadvertises Solana accounts ingetPaymentOptions,PaymentStore.approvePaymentresolves the wallet per action by CAIP-2 namespace, and adds thesolana_signTransactioncase which unwraps the backend's array-wrapped[{ transaction }]params and forwards the base64 signed blob (not the bs58 signature) toconfirmPayment. Three new unit tests cover the Solana action path. AndroidversionCodebumped 65 → 66.
Tagged at b4e7cb57 on origin/main.