@zkp2p/cash 0.4.10 → 0.4.11-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/AGENTS.md +57 -14
  2. package/README.md +92 -23
  3. package/dist/{chunk-4LPWKZMW.js → chunk-JRJLMQS4.js} +23 -28
  4. package/dist/{createCashClient-Br7uu4lQ.d.cts → createCashClient-BD8YNt-E.d.cts} +203 -8
  5. package/dist/{createCashClient-Br7uu4lQ.d.ts → createCashClient-BD8YNt-E.d.ts} +203 -8
  6. package/dist/index.cjs +1886 -1222
  7. package/dist/index.d.cts +352 -51
  8. package/dist/index.d.ts +352 -51
  9. package/dist/index.js +1837 -1202
  10. package/dist/react.d.cts +1 -1
  11. package/dist/react.d.ts +1 -1
  12. package/dist/react.js +1 -1
  13. package/dist/tools.cjs +86 -4
  14. package/dist/tools.d.cts +99 -3
  15. package/dist/tools.d.ts +99 -3
  16. package/dist/tools.js +86 -4
  17. package/docs/lifecycle-and-recovery.md +35 -12
  18. package/examples/agent-tool-use.ts +51 -9
  19. package/examples/carpe-diem-provider-cashout/README.md +75 -0
  20. package/examples/carpe-diem-provider-cashout/cashout.ts +65 -0
  21. package/examples/mpp-merchant-cashout/README.md +76 -0
  22. package/examples/mpp-merchant-cashout/app.ts +159 -0
  23. package/examples/mpp-merchant-cashout/revenue.ts +57 -0
  24. package/examples/mpp-merchant-cashout/server.ts +52 -0
  25. package/examples/node-cashout.ts +3 -1
  26. package/examples/onchain-demo/README.md +106 -0
  27. package/examples/onchain-demo/package.json +15 -0
  28. package/examples/onchain-demo/script/boot-test.mjs +86 -0
  29. package/examples/onchain-demo/script/build.mjs +55 -0
  30. package/examples/onchain-demo/script/check-deployer.mjs +15 -0
  31. package/examples/onchain-demo/script/compile.mjs +51 -0
  32. package/examples/onchain-demo/script/deploy.mjs +228 -0
  33. package/examples/onchain-demo/script/gen-key.mjs +16 -0
  34. package/examples/onchain-demo/script/lib.mjs +30 -0
  35. package/examples/onchain-demo/script/test-contract.mjs +127 -0
  36. package/examples/onchain-demo/src/PeerCashPage.sol +122 -0
  37. package/examples/onchain-demo/src/app.js +593 -0
  38. package/examples/onchain-demo/src/shell.html +159 -0
  39. package/examples/onchain-demo/src/stubs/viem-chains.mjs +7 -0
  40. package/examples/onchain-demo/src/stubs/zod-locales.mjs +3 -0
  41. package/llms.txt +22 -13
  42. package/package.json +8 -4
  43. package/skills/peer-cash-integration/SKILL.md +47 -12
package/AGENTS.md CHANGED
@@ -4,9 +4,10 @@
4
4
  > contribute to the SDK itself (layout, ground rules, CI, releasing), start at
5
5
  > [CLAUDE.md](https://github.com/zkp2p/peer-cash/blob/main/CLAUDE.md).
6
6
 
7
- You are integrating Peer Cash: an offramp that routes any Relay-supported EVM
8
- source asset into Base USDC, then converts Base USDC to fiat (Venmo, Revolut,
9
- Wise, Zelle, ...) at the live Chainlink market rate. The user whose USDC you
7
+ You are integrating Peer Cash: an offramp that routes Relay-supported EVM
8
+ assets or NEAR Intents 1Click external deposits into Base USDC, then converts
9
+ Base USDC to fiat (Venmo, Revolut, Wise, Zelle, ...) at the live Chainlink
10
+ market rate. The user whose USDC you
10
11
  manage is the **maker**; a buyer pays them fiat and proves it with TEE-TLS; the
11
12
  protocol releases the USDC. Funds are held by the protocol, and only the maker
12
13
  can withdraw an unmatched deposit.
@@ -23,14 +24,18 @@ can withdraw an unmatched deposit.
23
24
  the plan, submit the transactions in order, and wait for each receipt. After
24
25
  `createDeposit` confirms, pass its receipt to `finalizePreparedCashout()` and
25
26
  persist the returned `depositId`. If the original plan set
26
- `accessPolicyRequired: true`, submit and confirm
27
- `prepareAccessPolicy(depositId)` with the depositor next.
27
+ a non-empty `accessPolicyPaymentMethods`, submit and confirm
28
+ `prepareAccessPolicy(depositId, paymentMethod)` with the depositor for each
29
+ returned method.
28
30
  3. **You are a tool-use host** (MCP server, CLI) → import the manifest from
29
31
  `@zkp2p/cash/tools` and map the tool names to the verbs above. Base-USDC
30
32
  mutating tools return unsigned transactions. `cash_source_quote` is a quote,
31
33
  not an execution tool; the host must execute and confirm Relay through its
32
34
  signer/runtime, use `cash_source_status` to monitor it, then call the
33
- Base-USDC `cash_cashout` tool. Never pass `source` into `prepare()`.
35
+ Base-USDC `cash_cashout` tool. For NEAR Intents, persist
36
+ `cash_near_intents_quote`, fund its deposit address externally exactly once,
37
+ and poll `cash_near_intents_status` to `SUCCESS` before the Base cash-out.
38
+ Never pass `source` into `prepare()`.
34
39
 
35
40
  Every transaction (including approves) carries ERC-8021 attribution:
36
41
  `peer-cash`, then optional `peer-ref-XXXXXX` from the six-character
@@ -41,13 +46,13 @@ deposit-level integration share instead of applying maker L1/L2.
41
46
  **Platform caveats:**
42
47
 
43
48
  - **Venmo, Cash App, and PayPal restrict who can signal intents by default.**
44
- If any payout leg uses one of these platforms, signed
45
- `cashout()` confirms `createDeposit`, then submits and confirms the Plus, Pro,
46
- Peer Makers, and Peer Pay policy using the same viem wallet. This is a
47
- deliberate non-atomic follow-up with a brief unprotected interval. For
48
- `prepare()`, check `accessPolicyRequired`; after `createDeposit` confirms,
49
- finalize its receipt and submit `prepareAccessPolicy(depositId)` with the
50
- depositor. Any viem EOA works; Privy is not required.
49
+ Signed `cashout()` confirms `createDeposit`, then submits and confirms a
50
+ method-scoped Peer Pay merchant policy for every restricted payout leg using
51
+ the same viem wallet. This is a deliberate non-atomic follow-up with a brief
52
+ unprotected interval. For `prepare()`, read `accessPolicyPaymentMethods`;
53
+ after `createDeposit` confirms, finalize its receipt and submit
54
+ `prepareAccessPolicy(depositId, paymentMethod)` for every returned method.
55
+ Any viem EOA works; Privy is not required.
51
56
 
52
57
  - **Wise and PayPal** carry `requiresIdentityAttestation: true`. A new curator
53
58
  registration needs a signed maker identity attestation this SDK cannot mint
@@ -70,6 +75,8 @@ const cash = createCashClient({ environment: 'production' });
70
75
  const caps = cash.capabilities();
71
76
  // Optional: live Relay EVM source chains/tokens.
72
77
  const relayCaps = await cash.capabilities({ includeRelaySources: true });
78
+ // Optional: live NEAR Intents 1Click external-deposit assets.
79
+ const nearCaps = await cash.capabilities({ includeNearIntentsSources: true });
73
80
 
74
81
  // 2. Estimate - idempotent, cacheable, no side effects. Includes rolling ETA.
75
82
  const est = await cash.estimate({ amount: usdc(500), currency: 'EUR' });
@@ -148,6 +155,32 @@ console.log(routed.source?.amount);
148
155
  console.log(routed.source?.transactions?.origin, routed.source?.transactions?.destination);
149
156
  ```
150
157
 
158
+ External-deposit source route (NEAR Intents / Zcash example):
159
+
160
+ ```ts
161
+ const quote = await cash.quoteNearIntentsSource({
162
+ sourceAsset: 'nep141:zec.omft.near',
163
+ amount: usdc(1), // EXACT_OUTPUT is denominated in Base USDC units
164
+ recipient: signer.account.address,
165
+ refundTo: transparentZcashAddress,
166
+ tradeType: 'EXACT_OUTPUT',
167
+ deadline: new Date(Date.now() + 3 * 60_000).toISOString(),
168
+ });
169
+ persist(quote); // do this before the origin send
170
+ const txHash = await zcashWallet.send(quote.depositAddress!, quote.inputAmount);
171
+ await cash.submitNearIntentsDeposit({
172
+ depositAddress: quote.depositAddress!,
173
+ ...(quote.depositMemo ? { depositMemo: quote.depositMemo } : {}),
174
+ txHash,
175
+ });
176
+ const route = await cash.nearIntentsStatus({
177
+ depositAddress: quote.depositAddress!,
178
+ ...(quote.depositMemo ? { depositMemo: quote.depositMemo } : {}),
179
+ expectedQuote: quote,
180
+ });
181
+ // Reconcile the Base receipt/output when route.status === 'SUCCESS', then cash out Base-only.
182
+ ```
183
+
151
184
  ## Rules that prevent wrong behavior
152
185
 
153
186
  - **Never promise a rate.** `estimate()` is `kind: 'oracle-estimate'`; the
@@ -165,6 +198,15 @@ console.log(routed.source?.transactions?.origin, routed.source?.transactions?.de
165
198
  `sourceSigner`. Use `EXACT_INPUT` in high-level cash-out flows so `amount`
166
199
  remains source-token base units. `source.amount` is Relay's guaranteed
167
200
  minimum output and the exact Base USDC deposit amount.
201
+ - **Treat NEAR Intents as an external-deposit route.** Discover asset ids with
202
+ `capabilities({ includeNearIntentsSources: true })`. Persist the signed quote,
203
+ deposit address, optional memo, and deadline before sending. Browser code
204
+ uses a same-origin proxy so the 1Click JWT remains server-side. Never reuse
205
+ an expired route or resend after an uncertain wallet submission.
206
+ - **A failed NEAR deposit notification is not a failed send.** Retry only
207
+ `submitNearIntentsDeposit()` with the same address and hash; 1Click also
208
+ detects source deposits on-chain. Wait for `nearIntentsStatus()` `SUCCESS`
209
+ and reconcile its destination evidence before a Base-only cash-out.
168
210
  - **Use a nonce-managed source signer for routed cashouts.** Relay routes
169
211
  with more than one source-chain transaction (approve, then route) are
170
212
  refused preflight with `SOURCE_NONCE_MANAGER_REQUIRED` on plain local
@@ -236,6 +278,7 @@ Every `CashError` carries `code`, `retryable`, `remediation`. Behavior:
236
278
  | `SOURCE_QUOTE_FAILED` | yes | Refresh capabilities and request a new canonical Base-USDC quote |
237
279
  | `SOURCE_NONCE_MANAGER_REQUIRED` | no | Preflight; recreate the source signer with viem's `nonceManager`, then quote again |
238
280
  | `SOURCE_EXECUTION_FAILED` | no | Inspect source transactions and Relay status before any retry |
281
+ | `SOURCE_DEPOSIT_SUBMISSION_FAILED` | yes | Retry only the 1Click notification; never resend source funds |
239
282
  | `SOURCE_STATUS_FAILED` | yes | Retry only the status read |
240
283
  | `SOURCE_ROUTE_COMPLETED_CASHOUT_FAILED` | no | Do not route again; retry Base-only with `recovery.amount` |
241
284
  | `SOURCE_CASHOUT_SUBMISSION_UNKNOWN` | no | Inspect Base activity and orders; prove no deposit exists before retrying |
@@ -270,7 +313,7 @@ Prove your integration against `environment: 'staging'` with a funded test
270
313
  wallet. Never wait on a buyer - buyer-side is out of your scope:
271
314
 
272
315
  1. `cashout()` a small amount (1–2 USDC) → capture `depositId` and, for a
273
- restricted payout, `accessPolicyTxHash`.
316
+ restricted payout, every entry in `accessPolicyTxHashes`.
274
317
  2. `order(depositId)` shows `awaiting-buyer` (retry through indexer lag).
275
318
  3. `orders(owner)` includes the deposit.
276
319
  4. `withdraw(depositId)` → transaction succeeds.
package/README.md CHANGED
@@ -1,8 +1,9 @@
1
1
  # @zkp2p/cash
2
2
 
3
- Route any Relay-supported EVM source asset into Base USDC, then cash out to
4
- fiat on Venmo, Revolut, Wise, Zelle, and more at the live Chainlink market
5
- rate, with zero spread and no centralized off-ramp provider.
3
+ Route Relay-supported EVM assets or NEAR Intents 1Click external deposits into
4
+ Base USDC, then cash out to fiat on Venmo, Revolut, Wise, Zelle, and more at the
5
+ live Chainlink market rate, with zero spread and no centralized off-ramp
6
+ provider.
6
7
 
7
8
  Peer Cash is an **offramp-only** SDK for the [ZKP2P](https://peer.xyz)
8
9
  protocol. The cashing-out user is the maker: their USDC becomes a deposit in
@@ -38,7 +39,7 @@ const fillStats = await cash.fillStats();
38
39
  const pairStats = fillStats['venmo:USD'];
39
40
  const multiCurrencyStats = fillStats['revolut:EUR+GBP+USD'];
40
41
 
41
- const { depositId, accessPolicyTxHash } = await cash.cashout(
42
+ const { depositId, accessPolicyTxHashes } = await cash.cashout(
42
43
  {
43
44
  amount: usdc(1000),
44
45
  receive: { platform: 'venmo', currency: 'USD', payee: '@you' },
@@ -46,7 +47,7 @@ const { depositId, accessPolicyTxHash } = await cash.cashout(
46
47
  { signer }, // any viem WalletClient on Base, including an EOA
47
48
  );
48
49
  // Venmo, Cash App, and PayPal return only after their access policy confirms.
49
- console.log(depositId, accessPolicyTxHash);
50
+ console.log(depositId, accessPolicyTxHashes);
50
51
 
51
52
  // One method can offer several currencies. The buyer chooses the fill
52
53
  // currency, and each option resolves at its own live oracle rate.
@@ -100,13 +101,16 @@ arbitrary protocol operations.
100
101
  | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
101
102
  | `capabilities()` | Sync discovery: Base USDC destination/default source, platforms × currencies × payee hints × amount bounds |
102
103
  | `capabilities({ includeRelaySources: true })` | Async discovery: adds live Relay SDK EVM source chains/tokens |
104
+ | `capabilities({ includeNearIntentsSources: true })` | Async discovery: adds live NEAR Intents 1Click source assets |
103
105
  | `fillStats()` | Cached 30-day fill counts and median first-fill time per exact `platform:currency` pair or sorted multi-currency set |
104
106
  | `quoteSource(input)` / `executeSourceQuote(quote, { signer })` | Relay SDK EVM source routing into Base USDC before cashout |
105
107
  | `relayStatus(requestId)` | Relay request status from the Relay SDK request path |
108
+ | `quoteNearIntentsSource(input)` | Signed 1Click quote with an origin-chain deposit address and optional memo |
109
+ | `submitNearIntentsDeposit(input)` / `nearIntentsStatus(input)` | Optionally register an origin tx, then track 1Click delivery/refund evidence |
106
110
  | `estimate({ amount, currency }, { includeEta? })` | Base USDC oracle estimate; optionally skip the historical ETA for progressive rendering |
107
- | `cashout(input, { signer })` | Creates the order with any viem wallet; Venmo, Cash App, and PayPal then attach the canonical access groups |
108
- | `prepare(input)` / `finalizePreparedCashout(receipt)` | Prepare external signing, resolve the deposit, then check `accessPolicyRequired` for the follow-up |
109
- | `prepareAccessPolicy(depositId)` | Prepare the post-deposit Plus, Pro, Peer Makers, and Peer Pay policy transaction |
111
+ | `cashout(input, { signer })` | Creates the order with any viem wallet; restricted methods then attach the Peer Pay merchant policy |
112
+ | `prepare(input)` / `finalizePreparedCashout(receipt)` | Prepare external signing, resolve the deposit, then iterate `accessPolicyPaymentMethods` for follow-ups |
113
+ | `prepareAccessPolicy(depositId, paymentMethod)` | Prepare one post-deposit, method-scoped Peer Pay merchant policy transaction |
110
114
  | `order(depositId)` / `orders(owner)` | Resume any order from its id alone; list all orders for a wallet |
111
115
  | `watch(depositId)` | Async iterator: yields on every state change until terminal, abort, or timeout |
112
116
  | `withdraw(depositId, { signer, amount? })` | The ONE unwind verb - partial with an `amount` (live intents don't block it), full close without (prunes expired intents first) |
@@ -137,8 +141,8 @@ mixed historical deposit.
137
141
 
138
142
  | Payout rail | Access-policy behavior | New payee registration |
139
143
  | --------------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
140
- | Venmo / Cash App | Four groups attach after deposit confirmation | Curator validates the live handle |
141
- | PayPal | Same four-group follow-up | Requires a Peer TEE browser-extension identity attestation |
144
+ | Venmo / Cash App | Peer Pay merchant policy attaches for that payment method | Curator validates the live handle |
145
+ | PayPal | Same method-scoped Peer Pay follow-up | Requires a Peer TEE browser-extension identity attestation |
142
146
  | Wise | No access-policy follow-up | Requires a Peer TEE browser-extension identity attestation |
143
147
  | Other supported rails | No access-policy follow-up; use `capabilities()` for currencies and format | Follow the `payeeHint`; live-validation behavior is described in the integration guide |
144
148
 
@@ -148,14 +152,15 @@ EOA; no Privy wallet or signer API is required. The deprecated
148
152
  `requiresAtomicAccessPolicy` capability remains for wire compatibility and is
149
153
  always `false`.
150
154
 
151
- Venmo, Cash App, and PayPal cash-outs restrict intent signaling to Plus, Pro,
152
- Peer Makers, and Peer Pay groups by default. If any payout leg uses one of
153
- those platforms, signed `cashout()` creates the deposit first, then uses the
154
- same wallet to submit and confirm the policy transaction; this intentionally
155
+ Venmo, Cash App, and PayPal cash-outs restrict intent signaling to the Peer Pay
156
+ merchant group by default. Each restricted payout method gets its own policy.
157
+ Signed `cashout()` creates the deposit first, then uses the same wallet to
158
+ submit and confirm every required policy transaction; this intentionally
155
159
  leaves a brief non-atomic interval. Prepared integrations receive
156
- `accessPolicyRequired: true` and, after confirming `createDeposit`, must call
157
- `finalizePreparedCashout(receipt)` followed by
158
- `prepareAccessPolicy(depositId)`. Other platforms do not need the follow-up.
160
+ `accessPolicyPaymentMethods`; after confirming `createDeposit`, call
161
+ `finalizePreparedCashout(receipt)`, then submit
162
+ `prepareAccessPolicy(depositId, paymentMethod)` once for every returned method.
163
+ Other platforms do not need the follow-up.
159
164
 
160
165
  If policy attachment fails, `ACCESS_POLICY_CONFIGURATION_FAILED.recovery`
161
166
  identifies the existing deposit and any submitted policy transaction. Never
@@ -176,7 +181,9 @@ extension. An already-registered Wise or PayPal handle can be reused with bare
176
181
  payee data. A new handle without its signed attestation fails during curator
177
182
  registration with `PAYEE_VERIFICATION_REQUIRED`, before funds move on-chain.
178
183
 
179
- ## Source routing (any EVM asset in)
184
+ ## Source routing
185
+
186
+ ### Relay (signed EVM route)
180
187
 
181
188
  The default/minimal flow is unchanged: pass Base USDC base units to
182
189
  `estimate()` and `cashout()`. For any other source asset, pass `source` to
@@ -189,7 +196,7 @@ discovered and quoted by `@relayprotocol/relay-sdk`, not a static token
189
196
  allowlist.
190
197
 
191
198
  ```ts
192
- const { depositId, accessPolicyTxHash, source } = await cash.cashout(
199
+ const { depositId, accessPolicyTxHashes, source } = await cash.cashout(
193
200
  {
194
201
  amount: 10_000_000n, // exact input: 10 USDC in source-token base units
195
202
  source: {
@@ -206,7 +213,7 @@ const { depositId, accessPolicyTxHash, source } = await cash.cashout(
206
213
  // amount deposited into the cash-out order. It is not the route's actual output.
207
214
  console.log(source?.amount, source?.requestId);
208
215
  console.log(source?.transactions?.origin, source?.transactions?.destination);
209
- console.log(accessPolicyTxHash); // present because this example uses Venmo
216
+ console.log(accessPolicyTxHashes); // one entry because this example uses Venmo
210
217
  ```
211
218
 
212
219
  Routes that submit more than one source-chain transaction (approve, then
@@ -216,6 +223,58 @@ refuses the route preflight with `SOURCE_NONCE_MANAGER_REQUIRED` instead of
216
223
  letting the route transaction reuse the approval's nonce and revert
217
224
  mid-route. Browser wallets are unaffected.
218
225
 
226
+ ### NEAR Intents (external-deposit route)
227
+
228
+ NEAR Intents 1Click supports non-EVM origins such as Zcash, so the SDK does
229
+ not pretend a viem wallet can execute the source transfer. It returns a signed
230
+ quote with an origin-chain `depositAddress` and optional `depositMemo`; your
231
+ wallet sends exactly once, then the SDK tracks the provider route into
232
+ canonical Base USDC. Use `EXACT_OUTPUT` when the Peer order amount must be
233
+ known before the origin send.
234
+
235
+ ```ts
236
+ const cash = createCashClient({
237
+ environment: 'production',
238
+ nearIntents: {
239
+ // Browser-safe same-origin proxy; it keeps the 1Click JWT server-side.
240
+ apiUrl: '/api/v1/near',
241
+ transport: 'proxy',
242
+ },
243
+ });
244
+
245
+ const sources = await cash.capabilities({ includeNearIntentsSources: true });
246
+ const zec = sources.source.nearIntents?.assets.find((asset) => asset.symbol === 'ZEC');
247
+ const quote = await cash.quoteNearIntentsSource({
248
+ sourceAsset: zec!.assetId,
249
+ amount: 1_000_000n, // exact 1 Base USDC output
250
+ recipient: baseSigner.account.address,
251
+ refundTo: transparentZcashRefundAddress,
252
+ tradeType: 'EXACT_OUTPUT',
253
+ deadline: new Date(Date.now() + 3 * 60_000).toISOString(),
254
+ });
255
+
256
+ persist(quote); // before sending: address, memo, signed response, deadline
257
+ const originTxHash = await zcashWallet.send(quote.depositAddress!, quote.inputAmount);
258
+ await cash.submitNearIntentsDeposit({
259
+ depositAddress: quote.depositAddress!,
260
+ ...(quote.depositMemo ? { depositMemo: quote.depositMemo } : {}),
261
+ txHash: originTxHash,
262
+ });
263
+ const route = await cash.nearIntentsStatus({
264
+ depositAddress: quote.depositAddress!,
265
+ ...(quote.depositMemo ? { depositMemo: quote.depositMemo } : {}),
266
+ expectedQuote: quote,
267
+ });
268
+ // On SUCCESS, reconcile the Base receipt/balance, then call Base-only cashout().
269
+ ```
270
+
271
+ Direct server integrations may pass `nearIntents: { token }`. Browser code
272
+ must use a same-origin proxy and must never receive the 1Click JWT. Never reuse
273
+ an expired deposit address, resend funds after an uncertain wallet submission,
274
+ or infer success from a wallet-wide balance alone. If optional deposit
275
+ registration fails, retry only `submitNearIntentsDeposit()` with the same hash;
276
+ 1Click can also detect the transfer on-chain.
277
+
219
278
  ## Source-route recovery
220
279
 
221
280
  Persist `depositId`, transaction hashes, and the Relay `requestId` as soon as
@@ -227,6 +286,9 @@ they are available. A source-routed result includes both a flat
227
286
  can stay in `relayStatus` `waiting` indefinitely. Decide from the error's
228
287
  recovery payload and origin transactions, never by waiting for a terminal
229
288
  Relay status.
289
+ - `SOURCE_DEPOSIT_SUBMISSION_FAILED`: the NEAR Intents origin transaction may
290
+ already be final. Retry only the provider notification with the same address
291
+ and hash; never resend source funds.
230
292
  - `SOURCE_ROUTE_COMPLETED_CASHOUT_FAILED`: Relay completed, but the Base
231
293
  cashout was not created. Do not route again. Retry a Base-USDC-only
232
294
  `cashout()` with `BigInt(error.recovery.amount)`.
@@ -244,7 +306,8 @@ they are available. A source-routed result includes both a flat
244
306
  - `ACCESS_POLICY_CONFIGURATION_FAILED`: the deposit exists, but its required
245
307
  Venmo, Cash App, or PayPal policy was not confirmed. Do not cash out again;
246
308
  inspect `recovery.transactionHash` when present, then retry
247
- `prepareAccessPolicy(error.recovery.depositId)` only if the prior policy
309
+ `prepareAccessPolicy(error.recovery.depositId, error.recovery.paymentMethod)`
310
+ only if the prior policy
248
311
  transaction did not succeed.
249
312
 
250
313
  Wallet clients pinned to the wrong chain fail with `SIGNER_CHAIN_MISMATCH`
@@ -325,8 +388,10 @@ analytics-only ERC-8021 codes such as `acme-app`.
325
388
  - Mutating tool calls return unsigned transactions by default; signing stays
326
389
  with the host that owns custody, policy, and user approval.
327
390
  - After a prepared restricted cash-out confirms, the host adapter must call
328
- `finalizePreparedCashout(receipt)` and `prepareAccessPolicy(depositId)`; these
329
- receipt/signing operations are `CashClient` methods, not built-in tool calls.
391
+ `finalizePreparedCashout(receipt)` and submit
392
+ `prepareAccessPolicy(depositId, paymentMethod)` for every value in
393
+ `accessPolicyPaymentMethods`; these receipt/signing operations are
394
+ `CashClient` methods, not built-in tool calls.
330
395
  - Every error carries `code`, `retryable`, and a `remediation` sentence.
331
396
  - Every order carries `nextActions: ('wait' | 'withdraw')[]` - no heuristics.
332
397
  - Every wire type has a zod schema + JSON codec - state crosses process
@@ -363,6 +428,10 @@ Runnable first-party examples in [`examples/`](examples):
363
428
 
364
429
  - [`node-cashout.ts`](examples/node-cashout.ts) - server-side cash-out with a private-key signer, plus order tracking.
365
430
  - [`agent-tool-use.ts`](examples/agent-tool-use.ts) - wiring the verbs into an agent tool-use loop with host-side signing.
431
+ - [`carpe-diem-provider-cashout`](examples/carpe-diem-provider-cashout) - cash out confirmed Carpe Diem provider DIEM revenue through the connected Base wallet.
432
+ - [`mpp-merchant-cashout`](examples/mpp-merchant-cashout) - turn confirmed MPP merchant revenue into an unsigned Peer Cash plan while the merchant keeps custody and signing.
433
+ - [`onchain-demo`](examples/onchain-demo) - the Peer Cash Demo: the express sell flow as one page that bundles the SDK and is stored on Base as contract bytecode, served by an immutable ERC-5219 wrapper,
434
+ [live on Base](https://basescan.org/address/0x6d6c7af86bfc6f49f32761e1718cf982224cf343).
366
435
 
367
436
  ## Trust model, honestly
368
437
 
@@ -3,24 +3,9 @@ var BASE_CHAIN_ID = 8453;
3
3
  var BASE_USDC_ADDRESS = "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913";
4
4
  var CASH_RESTRICTED_PLATFORMS = /* @__PURE__ */ new Set(["venmo", "cashapp", "paypal"]);
5
5
  var CASH_ACCESS_GROUP_IDS = {
6
- production: [
7
- "0xb8747401b308d4891385620071b5916e9c61284f25c4611541c529703de5babf",
8
- "0xf030f72e772f954059ca28f94974088aaf6ba37bb1f264df48843a3d0c221dc3",
9
- "0xdf1c64c54745aa1ce00642a5874f97e3183bf5e993c1f559d0a37a4df0b803c7",
10
- "0x174b8a29536721a3eae290bfd55651b85a53fc334b971d993fa93ed8dde15e48"
11
- ],
12
- preproduction: [
13
- "0xb8747401b308d4891385620071b5916e9c61284f25c4611541c529703de5babf",
14
- "0xf030f72e772f954059ca28f94974088aaf6ba37bb1f264df48843a3d0c221dc3",
15
- "0xdf1c64c54745aa1ce00642a5874f97e3183bf5e993c1f559d0a37a4df0b803c7",
16
- "0x174b8a29536721a3eae290bfd55651b85a53fc334b971d993fa93ed8dde15e48"
17
- ],
18
- staging: [
19
- "0xf6133c227eab8ae7da1ee143945bf7f31204394f3ba801dc9691f8af6ca8efa5",
20
- "0xa6beb459bc621e7b050e431736c1c3298da26356d7095719185e859d68f70d9e",
21
- "0x9cded1332f25c3ee0a9a822a4c827d3fbd081a8d7b2ba39c49917ec1983b8d6c",
22
- "0xc82c20c00033046a2f017b65532d7148a337282f17c73296663a530e49ba00f7"
23
- ]
6
+ production: ["0x174b8a29536721a3eae290bfd55651b85a53fc334b971d993fa93ed8dde15e48"],
7
+ preproduction: ["0x174b8a29536721a3eae290bfd55651b85a53fc334b971d993fa93ed8dde15e48"],
8
+ staging: ["0xc82c20c00033046a2f017b65532d7148a337282f17c73296663a530e49ba00f7"]
24
9
  };
25
10
  var USDC_DECIMALS = 6;
26
11
  var MARKET_SPREAD_BPS = 0;
@@ -217,21 +202,21 @@ var errors = {
217
202
  retryable: false,
218
203
  remediation: `For one-call source cashout, deliver Relay output to the depositor address. For a different recipient, bridge first and then cash out from that recipient's signer.`
219
204
  }),
220
- sourceCapabilitiesFailed: (cause) => new CashError(
205
+ sourceCapabilitiesFailed: (cause, provider = "Relay", capabilityMethod = "sourceCapabilities") => new CashError(
221
206
  {
222
207
  code: "SOURCE_CAPABILITIES_FAILED",
223
- message: `Relay source-chain discovery failed.`,
208
+ message: `${provider} source discovery failed.`,
224
209
  retryable: true,
225
- remediation: `Retry sourceCapabilities() shortly, or use the default Base USDC path.`
210
+ remediation: `Retry ${capabilityMethod}() shortly, or use the default Base USDC path.`
226
211
  },
227
212
  { cause }
228
213
  ),
229
- sourceQuoteFailed: (cause) => new CashError(
214
+ sourceQuoteFailed: (cause, provider = "Relay", quoteMethod = "quoteSource") => new CashError(
230
215
  {
231
216
  code: "SOURCE_QUOTE_FAILED",
232
- message: `Relay did not return a valid route to canonical Base USDC.`,
217
+ message: `${provider} did not return a valid route to canonical Base USDC.`,
233
218
  retryable: true,
234
- remediation: `Refresh source capabilities and request a new quote. Do not submit transactions from this response.`
219
+ remediation: `Refresh source capabilities and call ${quoteMethod}() again. Do not submit transactions from this response.`
235
220
  },
236
221
  { cause }
237
222
  ),
@@ -258,12 +243,21 @@ var errors = {
258
243
  },
259
244
  { cause }
260
245
  ),
261
- sourceStatusFailed: (requestId, cause) => new CashError(
246
+ sourceDepositSubmissionFailed: (depositAddress, cause) => new CashError(
247
+ {
248
+ code: "SOURCE_DEPOSIT_SUBMISSION_FAILED",
249
+ message: `NEAR Intents could not register the origin transaction for deposit ${depositAddress}.`,
250
+ retryable: true,
251
+ remediation: `Retry only submitNearIntentsDeposit() with the same deposit address and origin transaction hash. Never resend the source funds; 1Click can also detect the deposit on-chain.`
252
+ },
253
+ { cause }
254
+ ),
255
+ sourceStatusFailed: (requestId, cause, provider = "Relay", statusMethod = "relayStatus") => new CashError(
262
256
  {
263
257
  code: "SOURCE_STATUS_FAILED",
264
- message: `Relay status is unavailable for request ${requestId}.`,
258
+ message: `${provider} status is unavailable for route ${requestId}.`,
265
259
  retryable: true,
266
- remediation: `Retry relayStatus(requestId) shortly; keep the request id and transaction hashes for recovery.`
260
+ remediation: `Retry ${statusMethod}() shortly; keep the route identifier and transaction hashes for recovery.`
267
261
  },
268
262
  { cause }
269
263
  ),
@@ -411,11 +405,12 @@ var errors = {
411
405
  code: "ACCESS_POLICY_CONFIGURATION_FAILED",
412
406
  message: `Cash-out deposit ${depositId} was created, but its access policy could not be confirmed.`,
413
407
  retryable: false,
414
- remediation: `Do not create another cash-out. If recovery.transactionHash is present, inspect that policy transaction first. Otherwise, or if it is confirmed reverted, submit and confirm prepareAccessPolicy(recovery.depositId) with the same depositor wallet.`,
408
+ remediation: `Do not create another cash-out. If recovery.transactionHash is present, inspect that policy transaction first. Otherwise, or if it is confirmed reverted, submit and confirm prepareAccessPolicy(recovery.depositId, recovery.paymentMethod) with the same depositor wallet.`,
415
409
  recovery: {
416
410
  kind: "configure-cashout-access-policy",
417
411
  depositId,
418
412
  groupIds: [...groupIds],
413
+ ...context.paymentMethod ? { paymentMethod: context.paymentMethod } : {},
419
414
  ...context.transactionHash ? { transactionHash: context.transactionHash } : {},
420
415
  ...context.source ? {
421
416
  source: {