fix(cash-wallet): route recipient wallet ids in intraledger send mutations - #470
Merged
islandbitcoin merged 3 commits intoAug 8, 2026
Merged
Conversation
…tions Post-cutover, intraLedgerUsdPaymentSend routed only the sender's wallet through cash-wallet routing while passing the recipient wallet id raw. A legacy client (no x-flash-client-capabilities header) resolves a recipient via accountDefaultWallet, receives the legacy USD wallet id, and every send then fails deterministically with MismatchedCurrencyForWalletError (USDT sender wallet vs USD recipient wallet) — seen repeatedly in the ops activity feed. Wire resolveCashWalletRecipientMutationWalletId (already used by lnUsdInvoiceCreateOnBehalfOfRecipient) into intraLedgerUsdPaymentSend and intraLedgerPaymentSend so legacy USD recipient ids resolve to the recipient account's active settlement (USDT) wallet, matching the read-side aliasing of balances and history. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AP1XZs5anZjsHYgGRGVyDT
…s on routing failures Review follow-ups: - Add a composition test exercising the real recipient resolver through the real presentation/routing logic (repos stubbed): a legacy-compat client submitting a legacy USD recipient id post-cutover resolves to the USDT settlement wallet — the exact production incident scenario. - Emit an ops-feed event when sender/recipient cash-wallet routing fails in the intraledger mutations, so routing failures stay visible in the #flash-activity feed instead of returning to the client silently. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AP1XZs5anZjsHYgGRGVyDT
Review follow-up: the BTC intraledger call mixed the raw GraphQL input (senderWalletId: walletId) with checked/routed ids; use the validated senderWalletId from checkedToWalletId like the rest of the call. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AP1XZs5anZjsHYgGRGVyDT
bobodread876
approved these changes
Aug 8, 2026
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.
Problem
Repeated
Transfer — failedevents in the #flash-activity ops feed:MismatchedCurrencyForWalletError, always the same wallet pair, small USD amounts,reason: error-return.Root cause: post-cutover,
intraLedgerUsdPaymentSendroutes the sender's wallet through cash-wallet routing (resolveCashWalletMutationWalletIdForAccount, legacy USD → USDT) but passes the recipient's wallet id through raw. A client that doesn't sendx-flash-client-capabilities: cash-wallet-usdt-v1(pre-0.6.0 app, scripts, or any hop that strips the header) resolves a recipient viaaccountDefaultWalletand gets handed the recipient's legacy USD wallet id by the compat presentation. The send then arrives as USDT sender wallet → USD recipient wallet and is rejected deterministically atsend-intraledger.ts(senderWallet.currency !== recipientWallet.currency). Every intraledger send from a legacy client fails, 100% of the time.Fix
Wire
resolveCashWalletRecipientMutationWalletId— already used bylnUsdInvoiceCreateOnBehalfOfRecipient— into:intraLedgerUsdPaymentSendintraLedgerPaymentSendIt resolves a legacy USD recipient wallet id to the recipient account's active settlement (USDT) wallet, so funds settle where the compat read-side already points: the
UsdWallet.balanceandtransactionsresolvers alias the legacy wallet to the settlement wallet, so legacy-app recipients see the funds. Current-client ids pass through unchanged (no-op).Tests
ln-usd-invoice-create-on-behalf-of-recipient.spec.ts):Payments.intraledgerPaymentSendWalletIdFor{Usd,Btc}Walletstatus: failedwithout initiating a paymentyarn tsc-checkclean, eslint clean, unit suites green.🤖 Generated with Claude Code
https://claude.ai/code/session_01AP1XZs5anZjsHYgGRGVyDT