@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.
- package/AGENTS.md +57 -14
- package/README.md +92 -23
- package/dist/{chunk-4LPWKZMW.js → chunk-JRJLMQS4.js} +23 -28
- package/dist/{createCashClient-Br7uu4lQ.d.cts → createCashClient-BD8YNt-E.d.cts} +203 -8
- package/dist/{createCashClient-Br7uu4lQ.d.ts → createCashClient-BD8YNt-E.d.ts} +203 -8
- package/dist/index.cjs +1886 -1222
- package/dist/index.d.cts +352 -51
- package/dist/index.d.ts +352 -51
- package/dist/index.js +1837 -1202
- package/dist/react.d.cts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +1 -1
- package/dist/tools.cjs +86 -4
- package/dist/tools.d.cts +99 -3
- package/dist/tools.d.ts +99 -3
- package/dist/tools.js +86 -4
- package/docs/lifecycle-and-recovery.md +35 -12
- package/examples/agent-tool-use.ts +51 -9
- package/examples/carpe-diem-provider-cashout/README.md +75 -0
- package/examples/carpe-diem-provider-cashout/cashout.ts +65 -0
- package/examples/mpp-merchant-cashout/README.md +76 -0
- package/examples/mpp-merchant-cashout/app.ts +159 -0
- package/examples/mpp-merchant-cashout/revenue.ts +57 -0
- package/examples/mpp-merchant-cashout/server.ts +52 -0
- package/examples/node-cashout.ts +3 -1
- package/examples/onchain-demo/README.md +106 -0
- package/examples/onchain-demo/package.json +15 -0
- package/examples/onchain-demo/script/boot-test.mjs +86 -0
- package/examples/onchain-demo/script/build.mjs +55 -0
- package/examples/onchain-demo/script/check-deployer.mjs +15 -0
- package/examples/onchain-demo/script/compile.mjs +51 -0
- package/examples/onchain-demo/script/deploy.mjs +228 -0
- package/examples/onchain-demo/script/gen-key.mjs +16 -0
- package/examples/onchain-demo/script/lib.mjs +30 -0
- package/examples/onchain-demo/script/test-contract.mjs +127 -0
- package/examples/onchain-demo/src/PeerCashPage.sol +122 -0
- package/examples/onchain-demo/src/app.js +593 -0
- package/examples/onchain-demo/src/shell.html +159 -0
- package/examples/onchain-demo/src/stubs/viem-chains.mjs +7 -0
- package/examples/onchain-demo/src/stubs/zod-locales.mjs +3 -0
- package/llms.txt +22 -13
- package/package.json +8 -4
- 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
|
|
8
|
-
|
|
9
|
-
Wise, Zelle, ...) at the live Chainlink
|
|
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
|
-
`
|
|
27
|
-
`prepareAccessPolicy(depositId)` with the depositor
|
|
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.
|
|
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
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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, `
|
|
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
|
|
4
|
-
fiat on Venmo, Revolut, Wise, Zelle, and more at the
|
|
5
|
-
rate, with zero spread and no centralized off-ramp
|
|
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,
|
|
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,
|
|
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;
|
|
108
|
-
| `prepare(input)` / `finalizePreparedCashout(receipt)` | Prepare external signing, resolve the deposit, then
|
|
109
|
-
| `prepareAccessPolicy(depositId)`
|
|
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 |
|
|
141
|
-
| PayPal | Same
|
|
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
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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
|
-
`
|
|
157
|
-
`finalizePreparedCashout(receipt)
|
|
158
|
-
`prepareAccessPolicy(depositId)
|
|
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
|
|
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,
|
|
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(
|
|
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)`
|
|
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
|
|
329
|
-
|
|
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
|
-
|
|
8
|
-
|
|
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:
|
|
208
|
+
message: `${provider} source discovery failed.`,
|
|
224
209
|
retryable: true,
|
|
225
|
-
remediation: `Retry
|
|
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:
|
|
217
|
+
message: `${provider} did not return a valid route to canonical Base USDC.`,
|
|
233
218
|
retryable: true,
|
|
234
|
-
remediation: `Refresh source capabilities and
|
|
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
|
-
|
|
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:
|
|
258
|
+
message: `${provider} status is unavailable for route ${requestId}.`,
|
|
265
259
|
retryable: true,
|
|
266
|
-
remediation: `Retry
|
|
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: {
|