Repository navigation
feat(wallet-sdk): receive cashu token slice (step 12) - #1185
Merged
Merged
Conversation
Implement sdk.receive.cashuToken.{createQuotes, claim} and flip the web
cross-account token quote hook and the protected token route auto-claim
off @agicash/wallet-sdk/temporary. The placeholder contract member
getQuote is renamed createQuotes because it persists (contract
conventions: get* = preview, create* = persists).
Plan + applied plan-attack corrections:
docs/superpowers/plans/2026-09-21-wallet-sdk-receive-cashu-token-slice.md
Gates: fix:all 0, typecheck 0, SDK 206 pass, web 38 pass. Smoke: guest
auto-claim of a testnut token through sdk.receive.cashuToken.claim.
Pre-squash commits: 87d82e5 (plan), e3d2b69 (attack corrections),
7aebc4e (slice), 526f4581 (review nit).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
jbojcic1
approved these changes
Sep 23, 2026
This branch was successfully 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.
Step 12 of the no-cache wallet-SDK extraction (spec:
docs/superpowers/specs/2026-06-24-wallet-sdk-no-cache-production-design.md). Implements thereceive.cashuTokensub-namespace and flips the web cross-account token-quote hook and the protected token route's auto-claim off@agicash/wallet-sdk/temporary.Plan (full spec, incl. the applied plan-attack corrections):
docs/superpowers/plans/2026-09-21-wallet-sdk-receive-cashu-token-slice.md.What changed
domain/sdk/receive.ts): the step-4 placeholder membercashuToken.getQuoteis renamedcreateQuotes— it persists (RPCcreate_cashu_receive_quote/create_spark_receive_quote), and the contract conventions sayget*= stateless preview,create*= persists. Plural because it persists a receive quote plus its melt quote (CrossAccountReceiveQuotesResult). New types:CreateReceiveCashuTokenQuotesParams,ReceiveCashuTokenQuotes,ClaimCashuTokenParams,ClaimCashuTokenResult(= the service'sClaimTokenResult, so the route applies cache upserts with no extra reads).sdk.receive.cashuToken.createQuotes({ token, sourceAccount, destinationAccount, exchangeRate })wrapsReceiveCashuTokenQuoteService.createCrossAccountReceiveQuotes;sdk.receive.cashuToken.claim({ token, claimTo, accounts, user })wrapsClaimCashuTokenService.claimToken. Both follow the step-9/10/11 fence template (requireUserId→ capturesessionSignal→ await builder → re-check → call with{ abortSignal }→ re-check). Caller-supplied domain objects throughout (feat(wallet-sdk): cashu receive quote slice (step 9) #1176 param precedent); the SDK builds the service graph internally from session keys + theaccounts.getRepositorybridge — the web route'sgetServices()is deleted.createCrossAccountReceiveQuotesandclaimTokengain an optionaloptions?: { abortSignal? }last param, threaded to the writes that already accept it (in-package callers updated in the same PR).useCreateCrossAccountReceiveQuotesbody →sdk.receive.cashuToken.createQuotes(FX still fetched in the hook via TanStack and passed as a string);_protected.receive.cashu_.token.tsxloader →sdk.receive.cashuToken.claim. Hook/route external APIs unchanged;receive-cashu-token.tsxuntouched.ReceiveCashuTokenQuoteService+ClaimCashuTokenServicefromtemporary.ts(zero importers left outside the package). Page-load account discovery, public placeholders, processors and change handlers stay on/temporary(step-18 boundary; no host/processing split).receive-api.test.tscases (a–k), incl. abort-signal identity through the real default token-quote service (j) and a spark-destination cashu-seed non-access test with the real default cashu service (k). Net +10 (the throwing-getter test is deleted).Foreground parity
Zero added network requests on every runnable path (accounting tables A–E in the plan). Two deltas exist only on paths unreachable with test mints, documented in the plan (decision 3 / table E): on a cross-currency
?claimTo=auto-claim with a warm TanStack FX cache the SDK's uncachedexchangeRateServicecan add one provider GET; andcryptography.getPrivateKeyis not memoized SDK-side (only the cross-cashu in-bandcompleteReceivereaches it).Gates (local, this branch)
bun run fix:allbun run typecheckpackages/wallet-sdkbun testapps/web-walletbun testSmoke (local stack, chrome-devtools, isolated context)
21-sat testnut token → public page shows ₿21 → Claim as Guest → terms → guest signup → loader auto-claim via
sdk.receive.cashuToken.claim→ home shows ₿20, transactions list shows "+₿20 Received", 0 console errors/warnings. Network for the claim: 1×create_cashu_receive_swap, 1× mint/v1/swap, 1×complete_cashu_receive_swap, zeroaccounts/usersselects inside the claim (table E, same-mint row). The interactive cross-accountcreateQuotespath andclaimTo=sparkneed a non-test mint that can pay Lightning and were not run locally (plan "Paths that need a real Lightning payment").Process
Built with the step-10/11 delegation pattern (maxplayer contribution jobs): plan (grok-4.6) → two cross-model plan-attacks (grok delivered NOT READY 2C/4I/2M/1N — all verified locally and applied before any code: the
createQuotesrename, tests (j)/(k) rewritten to the real harness, FX/getPrivateKeyparity caveats,getExchangeRateimport prune; the claude-harness attack never delivered) → one whole-slice implementation (grok-4.6; file set = the plan's 8 files exactly) → adversarial review (grok-4.6: READY, 0 Critical/0 Important/0 Minor/2 Nit; reviewer ran all gates green). Nit 2 (JSDoc for the newoptionsparam) applied; Nit 1 ((b)/(g) assert the abort signal is defined rather than identical to the session signal) declined for consistency with the sibling namespace tests — identity is locked by (j). The codex-harness reviewer was unavailable; the claude-harness review did not deliver.For the maintainer
getQuote → createQuotesonReceiveApi.cashuTokenis the one contract-surface decision in this slice; the contract-proposal doc's representative sketch is left untouched.claimtakes the walletUser(needed bygetExtendedAccounts);requireUserId()is the session fence and the persisted user id isparams.user.id, same implicit trust as master's loader (no runtime equality check added).🤖 Generated with Claude Code