@zkp2p/cash 0.4.3 → 0.4.5
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 +10 -2
- package/README.md +21 -28
- package/dist/{chunk-IHEOGLAS.js → chunk-YD5VHZXR.js} +43 -1
- package/dist/{createCashClient-CYSM84-K.d.cts → createCashClient-CL1SCbqF.d.cts} +11 -0
- package/dist/{createCashClient-CYSM84-K.d.ts → createCashClient-CL1SCbqF.d.ts} +11 -0
- package/dist/index.cjs +105 -7
- package/dist/index.d.cts +64 -6
- package/dist/index.d.ts +64 -6
- package/dist/index.js +65 -9
- package/dist/react.d.cts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +1 -1
- package/dist/tools.cjs +2 -2
- package/dist/tools.d.cts +1 -1
- package/dist/tools.d.ts +1 -1
- package/dist/tools.js +2 -2
- package/docs/lifecycle-and-recovery.md +12 -0
- package/examples/agent-tool-use.ts +9 -3
- package/examples/node-cashout.ts +6 -4
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -32,7 +32,13 @@ Every transaction (including approves) carries ERC-8021 attribution:
|
|
|
32
32
|
code. The namespaced referral marker gives its Peer Privy wallet the direct
|
|
33
33
|
deposit-level integration share instead of applying maker L1/L2.
|
|
34
34
|
|
|
35
|
-
**
|
|
35
|
+
**Platform caveats, all surfaced in `capabilities()`:**
|
|
36
|
+
|
|
37
|
+
- **Venmo, Cash App, and PayPal** carry
|
|
38
|
+
`requiresAtomicAccessPolicy: true`. Generic `cashout()` and `prepare()` reject
|
|
39
|
+
them with `ATOMIC_ACCESS_POLICY_REQUIRED` before any side effect. Use Peer
|
|
40
|
+
web's Curator-backed atomic flow or a host with the same atomic guarantee;
|
|
41
|
+
never create the deposit and attach the group policy sequentially.
|
|
36
42
|
|
|
37
43
|
- **Wise and PayPal** carry `requiresIdentityAttestation: true`. A new curator
|
|
38
44
|
registration needs a signed maker identity attestation this SDK cannot mint
|
|
@@ -93,7 +99,7 @@ const multiPlatform = await cash.cashout(
|
|
|
93
99
|
{
|
|
94
100
|
amount: usdc(500),
|
|
95
101
|
receive: [
|
|
96
|
-
{ platform: '
|
|
102
|
+
{ platform: 'chime', currency: 'USD', payee: '$handle' },
|
|
97
103
|
{ platform: 'revolut', currencies: ['EUR', 'GBP'], payee: { offchainId: 'revtag' } },
|
|
98
104
|
],
|
|
99
105
|
},
|
|
@@ -208,6 +214,8 @@ Every `CashError` carries `code`, `retryable`, `remediation`. Behavior:
|
|
|
208
214
|
| `INVALID_PAYOUT_PLATFORMS` | no | Pass one leg or an array of legs, using each platform at most once |
|
|
209
215
|
| `PAYEE_VERIFICATION_REQUIRED` | no | Register a new Wise/PayPal payee through Peer; an existing registered handle can be reused |
|
|
210
216
|
| `PAYEE_REGISTRATION_FAILED` | yes | Validate against `payeeHint`, then retry |
|
|
217
|
+
| `ATOMIC_ACCESS_POLICY_REQUIRED` | no | Use Peer web or an equivalent atomic host for Venmo, Cash App, or PayPal; nothing moved |
|
|
218
|
+
| `ACCESS_POLICY_CONFIGURATION_FAILED` | no | Recover an existing `0.4.4` deposit from its policy recovery data; do not create it again |
|
|
211
219
|
| `SOURCE_ROUTE_UNSUPPORTED_IN_PREPARE` | no | Execute Relay with a signer first, then prepare a Base-USDC cashout |
|
|
212
220
|
| `SOURCE_RECIPIENT_MISMATCH` | no | Route Base USDC to the cashout depositor |
|
|
213
221
|
| `SOURCE_CAPABILITIES_FAILED` | yes | Retry discovery or fall back to Base USDC |
|
package/README.md
CHANGED
|
@@ -46,7 +46,7 @@ const multiCurrencyStats = fillStats['revolut:EUR+GBP+USD'];
|
|
|
46
46
|
const { depositId } = await cash.cashout(
|
|
47
47
|
{
|
|
48
48
|
amount: usdc(1000),
|
|
49
|
-
receive: { platform: '
|
|
49
|
+
receive: { platform: 'chime', currency: 'USD', payee: '$you' },
|
|
50
50
|
},
|
|
51
51
|
{ signer }, // any viem WalletClient on Base
|
|
52
52
|
);
|
|
@@ -71,7 +71,7 @@ const widestReach = await cash.cashout(
|
|
|
71
71
|
{
|
|
72
72
|
amount: usdc(1000),
|
|
73
73
|
receive: [
|
|
74
|
-
{ platform: '
|
|
74
|
+
{ platform: 'chime', currency: 'USD', payee: '$you' },
|
|
75
75
|
{ platform: 'revolut', currencies: ['EUR', 'GBP'], payee: { offchainId: 'revtag' } },
|
|
76
76
|
],
|
|
77
77
|
},
|
|
@@ -120,7 +120,7 @@ const { depositId, source } = await cash.cashout(
|
|
|
120
120
|
currency: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
|
121
121
|
tradeType: 'EXACT_INPUT',
|
|
122
122
|
},
|
|
123
|
-
receive: { platform: '
|
|
123
|
+
receive: { platform: 'chime', currency: 'USD', payee: { offchainId: '$you' } },
|
|
124
124
|
},
|
|
125
125
|
{ signer, sourceSigner },
|
|
126
126
|
);
|
|
@@ -141,8 +141,9 @@ console.log(source?.transactions?.origin, source?.transactions?.destination);
|
|
|
141
141
|
| `quoteSource(input)` / `executeSourceQuote(quote, { signer })` | Relay SDK EVM source routing into Base USDC before cashout |
|
|
142
142
|
| `relayStatus(requestId)` | Relay request status from the Relay SDK request path |
|
|
143
143
|
| `estimate({ amount, currency }, { includeEta? })` | Base USDC oracle estimate; optionally skip the historical ETA for progressive rendering |
|
|
144
|
-
| `cashout(input, { signer })` | Registers
|
|
145
|
-
| `prepare(input)` / `finalizePreparedCashout(receipt)` | Prepare external signing, then resolve the confirmed createDeposit receipt into
|
|
144
|
+
| `cashout(input, { signer })` | Registers the payee and creates an unrestricted-rail order; protected rails fail before any side effect |
|
|
145
|
+
| `prepare(input)` / `finalizePreparedCashout(receipt)` | Prepare unrestricted-rail external signing, then resolve the confirmed createDeposit receipt into resumable state |
|
|
146
|
+
| `prepareAccessPolicy(depositId)` | Recover a restricted-rail deposit created by the unsafe `0.4.4` sequential flow; never use it to create a new order |
|
|
146
147
|
| `order(depositId)` / `orders(owner)` | Resume any order from its id alone; list all orders for a wallet |
|
|
147
148
|
| `watch(depositId)` | Async iterator: yields on every state change until terminal, abort, or timeout |
|
|
148
149
|
| `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) |
|
|
@@ -164,29 +165,21 @@ Peer Cash transaction, including approves, carries ERC-8021 attribution:
|
|
|
164
165
|
`peer-cash` first, optional `peer-ref-XXXXXX` from `referralCode` next, and your
|
|
165
166
|
analytics-only `referrer` code(s) after it.
|
|
166
167
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
if (!createDepositReceipt) throw new Error('createDeposit receipt missing');
|
|
185
|
-
|
|
186
|
-
const result = cash.finalizePreparedCashout(createDepositReceipt);
|
|
187
|
-
await persistDepositId(result.depositId);
|
|
188
|
-
const liveOrder = await cash.order(result.depositId);
|
|
189
|
-
```
|
|
168
|
+
Venmo, Cash App, and PayPal must attach Plus, Pro, Peer Makers, and Peer Pay in
|
|
169
|
+
the same atomic operation that creates the deposit. A create-then-configure
|
|
170
|
+
sequence leaves a public interval in which an unapproved taker can signal an
|
|
171
|
+
intent. The generic `cashout()` and `prepare()` paths therefore throw
|
|
172
|
+
`ATOMIC_ACCESS_POLICY_REQUIRED` before wallet access, Relay quoting, payee
|
|
173
|
+
registration, allowance, or deposit submission. Peer web supports these rails
|
|
174
|
+
through its atomic Curator-backed flow. Other hosts must provide an equivalent
|
|
175
|
+
atomic batch rather than composing the two public SDK calls sequentially.
|
|
176
|
+
`capabilities()` marks these platforms with
|
|
177
|
+
`requiresAtomicAccessPolicy: true`.
|
|
178
|
+
|
|
179
|
+
`prepareAccessPolicy(depositId)` remains available only to recover a restricted
|
|
180
|
+
deposit already created by `0.4.4`. Configure that existing deposit immediately;
|
|
181
|
+
do not call `cashout()` again and do not use this recovery helper as a new-order
|
|
182
|
+
flow.
|
|
190
183
|
|
|
191
184
|
`capabilities()` presents Zelle as one platform. A cashout with
|
|
192
185
|
`receive.platform: 'zelle'` attaches only the generic Zelle payment method to
|
|
@@ -2,6 +2,27 @@
|
|
|
2
2
|
var BASE_CHAIN_ID = 8453;
|
|
3
3
|
var BASE_USDC_ADDRESS = "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913";
|
|
4
4
|
var CASH_INTENT_GUARDIAN_ADDRESS = "0x83671606454fA72ba1e2831E18C5090D25629414";
|
|
5
|
+
var CASH_RESTRICTED_PLATFORMS = /* @__PURE__ */ new Set(["venmo", "cashapp", "paypal"]);
|
|
6
|
+
var CASH_ACCESS_GROUP_IDS = {
|
|
7
|
+
production: [
|
|
8
|
+
"0xb8747401b308d4891385620071b5916e9c61284f25c4611541c529703de5babf",
|
|
9
|
+
"0xf030f72e772f954059ca28f94974088aaf6ba37bb1f264df48843a3d0c221dc3",
|
|
10
|
+
"0xdf1c64c54745aa1ce00642a5874f97e3183bf5e993c1f559d0a37a4df0b803c7",
|
|
11
|
+
"0x174b8a29536721a3eae290bfd55651b85a53fc334b971d993fa93ed8dde15e48"
|
|
12
|
+
],
|
|
13
|
+
preproduction: [
|
|
14
|
+
"0xb8747401b308d4891385620071b5916e9c61284f25c4611541c529703de5babf",
|
|
15
|
+
"0xf030f72e772f954059ca28f94974088aaf6ba37bb1f264df48843a3d0c221dc3",
|
|
16
|
+
"0xdf1c64c54745aa1ce00642a5874f97e3183bf5e993c1f559d0a37a4df0b803c7",
|
|
17
|
+
"0x174b8a29536721a3eae290bfd55651b85a53fc334b971d993fa93ed8dde15e48"
|
|
18
|
+
],
|
|
19
|
+
staging: [
|
|
20
|
+
"0xf6133c227eab8ae7da1ee143945bf7f31204394f3ba801dc9691f8af6ca8efa5",
|
|
21
|
+
"0xa6beb459bc621e7b050e431736c1c3298da26356d7095719185e859d68f70d9e",
|
|
22
|
+
"0x9cded1332f25c3ee0a9a822a4c827d3fbd081a8d7b2ba39c49917ec1983b8d6c",
|
|
23
|
+
"0xc82c20c00033046a2f017b65532d7148a337282f17c73296663a530e49ba00f7"
|
|
24
|
+
]
|
|
25
|
+
};
|
|
5
26
|
var USDC_DECIMALS = 6;
|
|
6
27
|
var MARKET_SPREAD_BPS = 0;
|
|
7
28
|
var ORACLE_MIN_CONVERSION_RATE_SENTINEL = 1n;
|
|
@@ -178,6 +199,12 @@ var errors = {
|
|
|
178
199
|
},
|
|
179
200
|
{ cause }
|
|
180
201
|
),
|
|
202
|
+
atomicAccessPolicyRequired: (platforms) => new CashError({
|
|
203
|
+
code: "ATOMIC_ACCESS_POLICY_REQUIRED",
|
|
204
|
+
message: `${platforms.join(", ")} cash-outs require atomic deposit creation and access-policy configuration.`,
|
|
205
|
+
retryable: false,
|
|
206
|
+
remediation: `Use Peer web or a host that atomically batches guard-before, createDeposit, guard-after, and configureDeposit. Nothing was submitted by this call.`
|
|
207
|
+
}),
|
|
181
208
|
sourceRouteUnsupportedInPrepare: () => new CashError({
|
|
182
209
|
code: "SOURCE_ROUTE_UNSUPPORTED_IN_PREPARE",
|
|
183
210
|
message: `prepare() cannot execute a Relay source route before creating the Base USDC cash-out.`,
|
|
@@ -379,6 +406,21 @@ var errors = {
|
|
|
379
406
|
},
|
|
380
407
|
{ cause }
|
|
381
408
|
),
|
|
409
|
+
accessPolicyConfigurationFailed: (depositId, groupIds, cause, transactionHash) => new CashError(
|
|
410
|
+
{
|
|
411
|
+
code: "ACCESS_POLICY_CONFIGURATION_FAILED",
|
|
412
|
+
message: `Cash-out deposit ${depositId} was created, but its required access policy was not confirmed.`,
|
|
413
|
+
retryable: false,
|
|
414
|
+
remediation: `Do not call cashout() again. Inspect the existing deposit and any access-policy transaction, then configure that deposit with recovery.groupIds through @zkp2p/sdk accessPolicy.`,
|
|
415
|
+
recovery: {
|
|
416
|
+
kind: "configure-cashout-access-policy",
|
|
417
|
+
depositId,
|
|
418
|
+
groupIds: [...groupIds],
|
|
419
|
+
...transactionHash ? { transactionHash } : {}
|
|
420
|
+
}
|
|
421
|
+
},
|
|
422
|
+
{ cause }
|
|
423
|
+
),
|
|
382
424
|
escrowPaused: () => new CashError({
|
|
383
425
|
code: "ESCROW_PAUSED",
|
|
384
426
|
message: `The escrow contract is paused; deposits are temporarily disabled.`,
|
|
@@ -446,4 +488,4 @@ function isUserRejectedError(value) {
|
|
|
446
488
|
return text.some(hasUserRejectionText);
|
|
447
489
|
}
|
|
448
490
|
|
|
449
|
-
export { BASE_CHAIN_ID, BASE_USDC_ADDRESS, CASH_INTENT_GUARDIAN_ADDRESS, CASH_ORDER_POLL_INTERVAL_MS, CASH_ORDER_STATUSES, CASH_RETAIN_ON_EMPTY, CashError, MARKET_SPREAD_BPS, ORACLE_MIN_CONVERSION_RATE_SENTINEL, USDC_DECIMALS, errors, isCashError, isUserRejectedError, mapChainError };
|
|
491
|
+
export { BASE_CHAIN_ID, BASE_USDC_ADDRESS, CASH_ACCESS_GROUP_IDS, CASH_INTENT_GUARDIAN_ADDRESS, CASH_ORDER_POLL_INTERVAL_MS, CASH_ORDER_STATUSES, CASH_RESTRICTED_PLATFORMS, CASH_RETAIN_ON_EMPTY, CashError, MARKET_SPREAD_BPS, ORACLE_MIN_CONVERSION_RATE_SENTINEL, USDC_DECIMALS, errors, isCashError, isUserRejectedError, mapChainError };
|
|
@@ -311,6 +311,11 @@ interface CashPlatformCapability {
|
|
|
311
311
|
* `PAYEE_VERIFICATION_REQUIRED`.
|
|
312
312
|
*/
|
|
313
313
|
requiresIdentityAttestation: boolean;
|
|
314
|
+
/**
|
|
315
|
+
* When true, the platform needs deposit creation and access-policy setup in
|
|
316
|
+
* one atomic host operation. Generic `cashout()` and `prepare()` fail closed.
|
|
317
|
+
*/
|
|
318
|
+
requiresAtomicAccessPolicy: boolean;
|
|
314
319
|
}
|
|
315
320
|
interface CashCapabilities {
|
|
316
321
|
chainId: number;
|
|
@@ -582,6 +587,8 @@ interface CashoutResult {
|
|
|
582
587
|
onchainDepositId: bigint;
|
|
583
588
|
/** Optimistic snapshot (`awaiting-buyer`); poll `order(depositId)` for live state. */
|
|
584
589
|
order: CashOrder;
|
|
590
|
+
/** @deprecated Only present in recovery data produced by the unsafe 0.4.4 sequential flow. */
|
|
591
|
+
accessPolicyTxHash?: Hash;
|
|
585
592
|
/** Present when `cashout()` first routed a source asset through Relay. */
|
|
586
593
|
source?: {
|
|
587
594
|
/** Conservative Base USDC amount deposited (Relay's guaranteed minimum output). */
|
|
@@ -608,6 +615,8 @@ interface PrepareResult {
|
|
|
608
615
|
register: {
|
|
609
616
|
hashedOnchainIds: string[];
|
|
610
617
|
};
|
|
618
|
+
/** @deprecated Always false for new plans; restricted rails require an atomic host flow. */
|
|
619
|
+
accessPolicyRequired: boolean;
|
|
611
620
|
}
|
|
612
621
|
/** Confirmed createDeposit receipt from an externally executed prepare() plan. */
|
|
613
622
|
interface PreparedCashoutReceipt {
|
|
@@ -670,6 +679,8 @@ interface CashClient {
|
|
|
670
679
|
prepare(input: CashoutInput): Promise<PrepareResult>;
|
|
671
680
|
/** Resolve an externally executed createDeposit receipt into resumable cash-out state. */
|
|
672
681
|
finalizePreparedCashout(receipt: PreparedCashoutReceipt): CashoutResult;
|
|
682
|
+
/** Recover an existing 0.4.4 restricted-rail deposit by preparing its four-group policy. */
|
|
683
|
+
prepareAccessPolicy(depositId: string): PreparedTransaction;
|
|
673
684
|
/** 3 - Observe: resumable from `depositId` alone; no session state anywhere. */
|
|
674
685
|
order(depositId: string): Promise<CashOrder>;
|
|
675
686
|
/**
|
|
@@ -311,6 +311,11 @@ interface CashPlatformCapability {
|
|
|
311
311
|
* `PAYEE_VERIFICATION_REQUIRED`.
|
|
312
312
|
*/
|
|
313
313
|
requiresIdentityAttestation: boolean;
|
|
314
|
+
/**
|
|
315
|
+
* When true, the platform needs deposit creation and access-policy setup in
|
|
316
|
+
* one atomic host operation. Generic `cashout()` and `prepare()` fail closed.
|
|
317
|
+
*/
|
|
318
|
+
requiresAtomicAccessPolicy: boolean;
|
|
314
319
|
}
|
|
315
320
|
interface CashCapabilities {
|
|
316
321
|
chainId: number;
|
|
@@ -582,6 +587,8 @@ interface CashoutResult {
|
|
|
582
587
|
onchainDepositId: bigint;
|
|
583
588
|
/** Optimistic snapshot (`awaiting-buyer`); poll `order(depositId)` for live state. */
|
|
584
589
|
order: CashOrder;
|
|
590
|
+
/** @deprecated Only present in recovery data produced by the unsafe 0.4.4 sequential flow. */
|
|
591
|
+
accessPolicyTxHash?: Hash;
|
|
585
592
|
/** Present when `cashout()` first routed a source asset through Relay. */
|
|
586
593
|
source?: {
|
|
587
594
|
/** Conservative Base USDC amount deposited (Relay's guaranteed minimum output). */
|
|
@@ -608,6 +615,8 @@ interface PrepareResult {
|
|
|
608
615
|
register: {
|
|
609
616
|
hashedOnchainIds: string[];
|
|
610
617
|
};
|
|
618
|
+
/** @deprecated Always false for new plans; restricted rails require an atomic host flow. */
|
|
619
|
+
accessPolicyRequired: boolean;
|
|
611
620
|
}
|
|
612
621
|
/** Confirmed createDeposit receipt from an externally executed prepare() plan. */
|
|
613
622
|
interface PreparedCashoutReceipt {
|
|
@@ -670,6 +679,8 @@ interface CashClient {
|
|
|
670
679
|
prepare(input: CashoutInput): Promise<PrepareResult>;
|
|
671
680
|
/** Resolve an externally executed createDeposit receipt into resumable cash-out state. */
|
|
672
681
|
finalizePreparedCashout(receipt: PreparedCashoutReceipt): CashoutResult;
|
|
682
|
+
/** Recover an existing 0.4.4 restricted-rail deposit by preparing its four-group policy. */
|
|
683
|
+
prepareAccessPolicy(depositId: string): PreparedTransaction;
|
|
673
684
|
/** 3 - Observe: resumable from `depositId` alone; no session state anywhere. */
|
|
674
685
|
order(depositId: string): Promise<CashOrder>;
|
|
675
686
|
/**
|
package/dist/index.cjs
CHANGED
|
@@ -13,6 +13,27 @@ var zod = require('zod');
|
|
|
13
13
|
var BASE_CHAIN_ID = 8453;
|
|
14
14
|
var BASE_USDC_ADDRESS = "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913";
|
|
15
15
|
var CASH_INTENT_GUARDIAN_ADDRESS = "0x83671606454fA72ba1e2831E18C5090D25629414";
|
|
16
|
+
var CASH_RESTRICTED_PLATFORMS = /* @__PURE__ */ new Set(["venmo", "cashapp", "paypal"]);
|
|
17
|
+
var CASH_ACCESS_GROUP_IDS = {
|
|
18
|
+
production: [
|
|
19
|
+
"0xb8747401b308d4891385620071b5916e9c61284f25c4611541c529703de5babf",
|
|
20
|
+
"0xf030f72e772f954059ca28f94974088aaf6ba37bb1f264df48843a3d0c221dc3",
|
|
21
|
+
"0xdf1c64c54745aa1ce00642a5874f97e3183bf5e993c1f559d0a37a4df0b803c7",
|
|
22
|
+
"0x174b8a29536721a3eae290bfd55651b85a53fc334b971d993fa93ed8dde15e48"
|
|
23
|
+
],
|
|
24
|
+
preproduction: [
|
|
25
|
+
"0xb8747401b308d4891385620071b5916e9c61284f25c4611541c529703de5babf",
|
|
26
|
+
"0xf030f72e772f954059ca28f94974088aaf6ba37bb1f264df48843a3d0c221dc3",
|
|
27
|
+
"0xdf1c64c54745aa1ce00642a5874f97e3183bf5e993c1f559d0a37a4df0b803c7",
|
|
28
|
+
"0x174b8a29536721a3eae290bfd55651b85a53fc334b971d993fa93ed8dde15e48"
|
|
29
|
+
],
|
|
30
|
+
staging: [
|
|
31
|
+
"0xf6133c227eab8ae7da1ee143945bf7f31204394f3ba801dc9691f8af6ca8efa5",
|
|
32
|
+
"0xa6beb459bc621e7b050e431736c1c3298da26356d7095719185e859d68f70d9e",
|
|
33
|
+
"0x9cded1332f25c3ee0a9a822a4c827d3fbd081a8d7b2ba39c49917ec1983b8d6c",
|
|
34
|
+
"0xc82c20c00033046a2f017b65532d7148a337282f17c73296663a530e49ba00f7"
|
|
35
|
+
]
|
|
36
|
+
};
|
|
16
37
|
var USDC_DECIMALS = 6;
|
|
17
38
|
var MARKET_SPREAD_BPS = 0;
|
|
18
39
|
var ORACLE_MIN_CONVERSION_RATE_SENTINEL = 1n;
|
|
@@ -478,7 +499,8 @@ function buildCapabilities(environment) {
|
|
|
478
499
|
platform,
|
|
479
500
|
currencies: [...new Set(currencies2)].sort(),
|
|
480
501
|
payeeHint: PAYEE_HINTS[platform] ?? "Your payment handle for this platform",
|
|
481
|
-
requiresIdentityAttestation: IDENTITY_ATTESTATION_PLATFORMS.has(platform)
|
|
502
|
+
requiresIdentityAttestation: IDENTITY_ATTESTATION_PLATFORMS.has(platform),
|
|
503
|
+
requiresAtomicAccessPolicy: CASH_RESTRICTED_PLATFORMS.has(platform)
|
|
482
504
|
};
|
|
483
505
|
}).filter((p) => p.currencies.length > 0).sort((a, b) => a.platform.localeCompare(b.platform));
|
|
484
506
|
const currencies = [...new Set(platforms.flatMap((p) => p.currencies))].sort();
|
|
@@ -660,6 +682,12 @@ var errors = {
|
|
|
660
682
|
},
|
|
661
683
|
{ cause }
|
|
662
684
|
),
|
|
685
|
+
atomicAccessPolicyRequired: (platforms) => new CashError({
|
|
686
|
+
code: "ATOMIC_ACCESS_POLICY_REQUIRED",
|
|
687
|
+
message: `${platforms.join(", ")} cash-outs require atomic deposit creation and access-policy configuration.`,
|
|
688
|
+
retryable: false,
|
|
689
|
+
remediation: `Use Peer web or a host that atomically batches guard-before, createDeposit, guard-after, and configureDeposit. Nothing was submitted by this call.`
|
|
690
|
+
}),
|
|
663
691
|
sourceRouteUnsupportedInPrepare: () => new CashError({
|
|
664
692
|
code: "SOURCE_ROUTE_UNSUPPORTED_IN_PREPARE",
|
|
665
693
|
message: `prepare() cannot execute a Relay source route before creating the Base USDC cash-out.`,
|
|
@@ -861,6 +889,21 @@ var errors = {
|
|
|
861
889
|
},
|
|
862
890
|
{ cause }
|
|
863
891
|
),
|
|
892
|
+
accessPolicyConfigurationFailed: (depositId, groupIds, cause, transactionHash) => new CashError(
|
|
893
|
+
{
|
|
894
|
+
code: "ACCESS_POLICY_CONFIGURATION_FAILED",
|
|
895
|
+
message: `Cash-out deposit ${depositId} was created, but its required access policy was not confirmed.`,
|
|
896
|
+
retryable: false,
|
|
897
|
+
remediation: `Do not call cashout() again. Inspect the existing deposit and any access-policy transaction, then configure that deposit with recovery.groupIds through @zkp2p/sdk accessPolicy.`,
|
|
898
|
+
recovery: {
|
|
899
|
+
kind: "configure-cashout-access-policy",
|
|
900
|
+
depositId,
|
|
901
|
+
groupIds: [...groupIds],
|
|
902
|
+
...transactionHash ? { transactionHash } : {}
|
|
903
|
+
}
|
|
904
|
+
},
|
|
905
|
+
{ cause }
|
|
906
|
+
),
|
|
864
907
|
escrowPaused: () => new CashError({
|
|
865
908
|
code: "ESCROW_PAUSED",
|
|
866
909
|
message: `The escrow contract is paused; deposits are temporarily disabled.`,
|
|
@@ -1876,6 +1919,12 @@ function createCashClient(options) {
|
|
|
1876
1919
|
...range ? { intentAmountRange: range } : {}
|
|
1877
1920
|
};
|
|
1878
1921
|
}
|
|
1922
|
+
function assertGenericCashoutSupported(payoutInput) {
|
|
1923
|
+
const restrictedPlatforms = payoutInput.payouts.map((payout) => payout.processorName.toLowerCase()).filter((platform) => CASH_RESTRICTED_PLATFORMS.has(platform));
|
|
1924
|
+
if (restrictedPlatforms.length > 0) {
|
|
1925
|
+
throw errors.atomicAccessPolicyRequired(restrictedPlatforms);
|
|
1926
|
+
}
|
|
1927
|
+
}
|
|
1879
1928
|
function isCashPayoutSet(payouts) {
|
|
1880
1929
|
return payouts.length > 0 && payouts.every((payout) => payout.pricing.marketRate && payout.pricing.spreadBps === 0);
|
|
1881
1930
|
}
|
|
@@ -2115,6 +2164,28 @@ function createCashClient(options) {
|
|
|
2115
2164
|
if (lastNonceError) throw lastNonceError;
|
|
2116
2165
|
throw new Error(`Signer provider did not observe Relay nonce ${afterRelay - 1}`);
|
|
2117
2166
|
}
|
|
2167
|
+
function prepareCashoutAccess(depositId, client = readClient) {
|
|
2168
|
+
const { compositeId, escrowAddress, onchainDepositId } = parseDepositId(depositId);
|
|
2169
|
+
const groupIds = CASH_ACCESS_GROUP_IDS[environment];
|
|
2170
|
+
try {
|
|
2171
|
+
const prepared = client.accessPolicy.prepareConfigureDeposit({
|
|
2172
|
+
escrow: escrowAddress,
|
|
2173
|
+
depositId: onchainDepositId,
|
|
2174
|
+
enabled: true,
|
|
2175
|
+
groupIds,
|
|
2176
|
+
takers: [],
|
|
2177
|
+
txOverrides: attribution
|
|
2178
|
+
});
|
|
2179
|
+
return {
|
|
2180
|
+
to: prepared.to,
|
|
2181
|
+
data: prepared.data,
|
|
2182
|
+
value: prepared.value,
|
|
2183
|
+
chainId: prepared.chainId
|
|
2184
|
+
};
|
|
2185
|
+
} catch (err) {
|
|
2186
|
+
throw errors.accessPolicyConfigurationFailed(compositeId, groupIds, err);
|
|
2187
|
+
}
|
|
2188
|
+
}
|
|
2118
2189
|
return {
|
|
2119
2190
|
capabilities,
|
|
2120
2191
|
async sourceCapabilities() {
|
|
@@ -2152,6 +2223,7 @@ function createCashClient(options) {
|
|
|
2152
2223
|
},
|
|
2153
2224
|
async cashout(input, opts) {
|
|
2154
2225
|
const payoutInput = validatePayout(input);
|
|
2226
|
+
assertGenericCashoutSupported(payoutInput);
|
|
2155
2227
|
const client = await signingClient("cashout", opts);
|
|
2156
2228
|
const owner = opts.signer.account.address;
|
|
2157
2229
|
let sourceResult;
|
|
@@ -2319,6 +2391,7 @@ function createCashClient(options) {
|
|
|
2319
2391
|
async prepare(input) {
|
|
2320
2392
|
if (input.source) throw errors.sourceRouteUnsupportedInPrepare();
|
|
2321
2393
|
const depositInput = validateDepositInput(input.amount, input);
|
|
2394
|
+
assertGenericCashoutSupported(depositInput);
|
|
2322
2395
|
const params = await buildDepositParams(readClient, depositInput);
|
|
2323
2396
|
const { prepared } = await readClient.prepareCreateDeposit({
|
|
2324
2397
|
...params,
|
|
@@ -2350,7 +2423,8 @@ function createCashClient(options) {
|
|
|
2350
2423
|
description: "Create the protocol-held cash-out order."
|
|
2351
2424
|
}
|
|
2352
2425
|
],
|
|
2353
|
-
register: { hashedOnchainIds }
|
|
2426
|
+
register: { hashedOnchainIds },
|
|
2427
|
+
accessPolicyRequired: false
|
|
2354
2428
|
};
|
|
2355
2429
|
},
|
|
2356
2430
|
finalizePreparedCashout(receipt) {
|
|
@@ -2379,6 +2453,7 @@ function createCashClient(options) {
|
|
|
2379
2453
|
})
|
|
2380
2454
|
};
|
|
2381
2455
|
},
|
|
2456
|
+
prepareAccessPolicy: prepareCashoutAccess,
|
|
2382
2457
|
async order(depositId) {
|
|
2383
2458
|
return fetchOrder(depositId);
|
|
2384
2459
|
},
|
|
@@ -2833,6 +2908,7 @@ var cashoutResultJsonSchema = zod.z.object({
|
|
|
2833
2908
|
escrowAddress: zod.z.string(),
|
|
2834
2909
|
onchainDepositId: nonNegativeBigintString,
|
|
2835
2910
|
order: cashOrderJsonSchema,
|
|
2911
|
+
accessPolicyTxHash: zod.z.string().optional(),
|
|
2836
2912
|
source: zod.z.object({
|
|
2837
2913
|
amount: nonNegativeBigintString,
|
|
2838
2914
|
requestId: zod.z.string().optional(),
|
|
@@ -2843,7 +2919,8 @@ var cashoutResultJsonSchema = zod.z.object({
|
|
|
2843
2919
|
var prepareResultJsonSchema = zod.z.object({
|
|
2844
2920
|
txs: zod.z.array(preparedTransactionJsonSchema),
|
|
2845
2921
|
steps: zod.z.array(cashPreparedStepJsonSchema),
|
|
2846
|
-
register: zod.z.object({ hashedOnchainIds: zod.z.array(zod.z.string()) })
|
|
2922
|
+
register: zod.z.object({ hashedOnchainIds: zod.z.array(zod.z.string()) }),
|
|
2923
|
+
accessPolicyRequired: zod.z.boolean()
|
|
2847
2924
|
});
|
|
2848
2925
|
var withdrawResultJsonSchema = zod.z.object({
|
|
2849
2926
|
depositId: zod.z.string(),
|
|
@@ -2874,7 +2951,8 @@ var cashCapabilitiesJsonSchema = zod.z.object({
|
|
|
2874
2951
|
platform: zod.z.string(),
|
|
2875
2952
|
currencies: zod.z.array(zod.z.string()),
|
|
2876
2953
|
payeeHint: zod.z.string(),
|
|
2877
|
-
requiresIdentityAttestation: zod.z.boolean()
|
|
2954
|
+
requiresIdentityAttestation: zod.z.boolean(),
|
|
2955
|
+
requiresAtomicAccessPolicy: zod.z.boolean().optional()
|
|
2878
2956
|
})
|
|
2879
2957
|
),
|
|
2880
2958
|
currencies: zod.z.array(zod.z.string()),
|
|
@@ -2910,6 +2988,7 @@ var CASH_ERROR_CODES = defineCashErrorCodes([
|
|
|
2910
2988
|
"ORDER_NOT_FOUND",
|
|
2911
2989
|
"PAYEE_REGISTRATION_FAILED",
|
|
2912
2990
|
"PAYEE_VERIFICATION_REQUIRED",
|
|
2991
|
+
"ATOMIC_ACCESS_POLICY_REQUIRED",
|
|
2913
2992
|
"SOURCE_ROUTE_UNSUPPORTED_IN_PREPARE",
|
|
2914
2993
|
"SOURCE_RECIPIENT_MISMATCH",
|
|
2915
2994
|
"SOURCE_CAPABILITIES_FAILED",
|
|
@@ -2921,6 +3000,7 @@ var CASH_ERROR_CODES = defineCashErrorCodes([
|
|
|
2921
3000
|
"SOURCE_CASHOUT_SUBMISSION_UNKNOWN",
|
|
2922
3001
|
"SOURCE_CASHOUT_STATUS_UNKNOWN",
|
|
2923
3002
|
"DEPOSIT_RESOLUTION_FAILED",
|
|
3003
|
+
"ACCESS_POLICY_CONFIGURATION_FAILED",
|
|
2924
3004
|
"ALLOWANCE_NOT_VISIBLE",
|
|
2925
3005
|
"SIGNER_REQUIRED",
|
|
2926
3006
|
"SIGNER_CHAIN_MISMATCH",
|
|
@@ -2966,6 +3046,12 @@ var cashErrorRecoveryJsonSchema = zod.z.discriminatedUnion("kind", [
|
|
|
2966
3046
|
kind: zod.z.literal("inspect-base-transaction"),
|
|
2967
3047
|
transactionHash: zod.z.string(),
|
|
2968
3048
|
operation: zod.z.string()
|
|
3049
|
+
}).strict(),
|
|
3050
|
+
zod.z.object({
|
|
3051
|
+
kind: zod.z.literal("configure-cashout-access-policy"),
|
|
3052
|
+
depositId: zod.z.string(),
|
|
3053
|
+
groupIds: zod.z.array(zod.z.string()),
|
|
3054
|
+
transactionHash: zod.z.string().optional()
|
|
2969
3055
|
}).strict()
|
|
2970
3056
|
]);
|
|
2971
3057
|
var cashErrorJsonSchema = zod.z.object({
|
|
@@ -3223,6 +3309,7 @@ function cashoutResultToJson(result) {
|
|
|
3223
3309
|
escrowAddress: result.escrowAddress,
|
|
3224
3310
|
onchainDepositId: result.onchainDepositId.toString(),
|
|
3225
3311
|
order: orderToJson(result.order),
|
|
3312
|
+
accessPolicyTxHash: result.accessPolicyTxHash,
|
|
3226
3313
|
source: result.source ? {
|
|
3227
3314
|
...result.source,
|
|
3228
3315
|
amount: result.source.amount.toString()
|
|
@@ -3237,6 +3324,7 @@ function cashoutResultFromJson(json) {
|
|
|
3237
3324
|
escrowAddress: parsed.escrowAddress,
|
|
3238
3325
|
onchainDepositId: BigInt(parsed.onchainDepositId),
|
|
3239
3326
|
order: orderFromJson(parsed.order),
|
|
3327
|
+
accessPolicyTxHash: parsed.accessPolicyTxHash,
|
|
3240
3328
|
source: parsed.source ? {
|
|
3241
3329
|
...parsed.source,
|
|
3242
3330
|
amount: BigInt(parsed.source.amount)
|
|
@@ -3247,7 +3335,8 @@ function prepareResultToJson(result) {
|
|
|
3247
3335
|
return {
|
|
3248
3336
|
txs: result.txs.map(preparedTxToJson),
|
|
3249
3337
|
steps: result.steps.map(preparedStepToJson),
|
|
3250
|
-
register: result.register
|
|
3338
|
+
register: result.register,
|
|
3339
|
+
accessPolicyRequired: result.accessPolicyRequired
|
|
3251
3340
|
};
|
|
3252
3341
|
}
|
|
3253
3342
|
function prepareResultFromJson(json) {
|
|
@@ -3255,7 +3344,8 @@ function prepareResultFromJson(json) {
|
|
|
3255
3344
|
return {
|
|
3256
3345
|
txs: parsed.txs.map(preparedTxFromJson),
|
|
3257
3346
|
steps: parsed.steps.map(preparedStepFromJson),
|
|
3258
|
-
register: parsed.register
|
|
3347
|
+
register: parsed.register,
|
|
3348
|
+
accessPolicyRequired: parsed.accessPolicyRequired
|
|
3259
3349
|
};
|
|
3260
3350
|
}
|
|
3261
3351
|
function withdrawResultToJson(result) {
|
|
@@ -3306,7 +3396,8 @@ function capabilitiesFromJson(json) {
|
|
|
3306
3396
|
},
|
|
3307
3397
|
platforms: parsed.platforms.map((p) => ({
|
|
3308
3398
|
...p,
|
|
3309
|
-
currencies: p.currencies
|
|
3399
|
+
currencies: p.currencies,
|
|
3400
|
+
requiresAtomicAccessPolicy: p.requiresAtomicAccessPolicy ?? CASH_RESTRICTED_PLATFORMS.has(p.platform)
|
|
3310
3401
|
})),
|
|
3311
3402
|
currencies: parsed.currencies,
|
|
3312
3403
|
amount: {
|
|
@@ -3335,6 +3426,13 @@ function cashErrorFromJson(json) {
|
|
|
3335
3426
|
transactionHash: parsed.recovery.transactionHash,
|
|
3336
3427
|
operation: parsed.recovery.operation
|
|
3337
3428
|
};
|
|
3429
|
+
} else if (parsed.recovery.kind === "configure-cashout-access-policy") {
|
|
3430
|
+
recovery = {
|
|
3431
|
+
kind: parsed.recovery.kind,
|
|
3432
|
+
depositId: parsed.recovery.depositId,
|
|
3433
|
+
groupIds: parsed.recovery.groupIds,
|
|
3434
|
+
...parsed.recovery.transactionHash !== void 0 ? { transactionHash: parsed.recovery.transactionHash } : {}
|
|
3435
|
+
};
|
|
3338
3436
|
} else if (parsed.recovery.kind === "inspect-base-operation-submission") {
|
|
3339
3437
|
recovery = {
|
|
3340
3438
|
kind: parsed.recovery.kind,
|