@zkp2p/cash 0.4.7 → 0.4.8
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 +12 -10
- package/README.md +26 -22
- package/dist/{chunk-SYE25ICW.js → chunk-CSDSJVI7.js} +16 -7
- package/dist/{createCashClient-CL1SCbqF.d.cts → createCashClient-BJmz3v4_.d.cts} +5 -8
- package/dist/{createCashClient-CL1SCbqF.d.ts → createCashClient-BJmz3v4_.d.ts} +5 -8
- package/dist/index.cjs +97 -22
- package/dist/index.d.cts +301 -13
- package/dist/index.d.ts +301 -13
- package/dist/index.js +83 -17
- 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 -11
- package/examples/node-cashout.ts +6 -5
- package/llms.txt +4 -0
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -9,9 +9,9 @@ can withdraw an unmatched deposit.
|
|
|
9
9
|
|
|
10
10
|
## Decision tree: pick your entry point
|
|
11
11
|
|
|
12
|
-
1. **You control a signer in-process** (viem `WalletClient`,
|
|
13
|
-
|
|
14
|
-
directly.
|
|
12
|
+
1. **You control a signer in-process** (any viem `WalletClient`, including a
|
|
13
|
+
local or externally connected EOA) → use `cashout()` / `topUp()` /
|
|
14
|
+
`withdraw()` directly. No Privy wallet is required.
|
|
15
15
|
2. **Signing happens elsewhere** (AA bundler, policy engine, custody service,
|
|
16
16
|
human approval step) → use `prepare()` / `prepareTopUp()` /
|
|
17
17
|
`prepareWithdraw()`. Each returns unsigned `txs[]`
|
|
@@ -34,11 +34,13 @@ deposit-level integration share instead of applying maker L1/L2.
|
|
|
34
34
|
|
|
35
35
|
**Platform caveats, all surfaced in `capabilities()`:**
|
|
36
36
|
|
|
37
|
-
- **Venmo, Cash App, and PayPal
|
|
38
|
-
`
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
37
|
+
- **Venmo, Cash App, and PayPal attach access groups by default.** Signed
|
|
38
|
+
`cashout()` confirms `createDeposit`, then submits and confirms the Plus, Pro,
|
|
39
|
+
Peer Makers, and Peer Pay policy using the same viem wallet. This is a
|
|
40
|
+
deliberate non-atomic follow-up with a brief unprotected interval. For
|
|
41
|
+
`prepare()`, check `accessPolicyRequired`; after `createDeposit` confirms,
|
|
42
|
+
finalize its receipt and submit `prepareAccessPolicy(depositId)` with the
|
|
43
|
+
depositor. Any viem EOA works; Privy is not required.
|
|
42
44
|
|
|
43
45
|
- **Wise and PayPal** carry `requiresIdentityAttestation: true`. A new curator
|
|
44
46
|
registration needs a signed maker identity attestation this SDK cannot mint
|
|
@@ -214,8 +216,8 @@ Every `CashError` carries `code`, `retryable`, `remediation`. Behavior:
|
|
|
214
216
|
| `INVALID_PAYOUT_PLATFORMS` | no | Pass one leg or an array of legs, using each platform at most once |
|
|
215
217
|
| `PAYEE_VERIFICATION_REQUIRED` | no | Register a new Wise/PayPal payee through Peer; an existing registered handle can be reused |
|
|
216
218
|
| `PAYEE_REGISTRATION_FAILED` | yes | Validate against `payeeHint`, then retry |
|
|
217
|
-
| `ATOMIC_ACCESS_POLICY_REQUIRED` | no |
|
|
218
|
-
| `ACCESS_POLICY_CONFIGURATION_FAILED` | no |
|
|
219
|
+
| `ATOMIC_ACCESS_POLICY_REQUIRED` | no | Deprecated compatibility code; current SDK flows never emit it |
|
|
220
|
+
| `ACCESS_POLICY_CONFIGURATION_FAILED` | no | Deposit exists; retry its policy with `recovery.depositId`, never create another cash-out |
|
|
219
221
|
| `SOURCE_ROUTE_UNSUPPORTED_IN_PREPARE` | no | Execute Relay with a signer first, then prepare a Base-USDC cashout |
|
|
220
222
|
| `SOURCE_RECIPIENT_MISMATCH` | no | Route Base USDC to the cashout depositor |
|
|
221
223
|
| `SOURCE_CAPABILITIES_FAILED` | yes | Retry discovery or fall back to Base USDC |
|
package/README.md
CHANGED
|
@@ -46,9 +46,9 @@ 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: 'venmo', currency: 'USD', payee: '@you' },
|
|
50
50
|
},
|
|
51
|
-
{ signer }, // any viem WalletClient on Base
|
|
51
|
+
{ signer }, // any viem WalletClient on Base, including an EOA
|
|
52
52
|
);
|
|
53
53
|
|
|
54
54
|
// One method can offer several currencies. The buyer chooses the fill
|
|
@@ -71,7 +71,7 @@ const widestReach = await cash.cashout(
|
|
|
71
71
|
{
|
|
72
72
|
amount: usdc(1000),
|
|
73
73
|
receive: [
|
|
74
|
-
{ platform: '
|
|
74
|
+
{ platform: 'venmo', 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: 'venmo', currency: 'USD', payee: { offchainId: '@you' } },
|
|
124
124
|
},
|
|
125
125
|
{ signer, sourceSigner },
|
|
126
126
|
);
|
|
@@ -141,9 +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 })` |
|
|
145
|
-
| `prepare(input)` / `finalizePreparedCashout(receipt)` | Prepare
|
|
146
|
-
| `prepareAccessPolicy(depositId)` |
|
|
144
|
+
| `cashout(input, { signer })` | Creates the order with any viem wallet; Venmo, Cash App, and PayPal then attach the canonical access groups |
|
|
145
|
+
| `prepare(input)` / `finalizePreparedCashout(receipt)` | Prepare external signing, resolve the deposit, then check `accessPolicyRequired` for the follow-up |
|
|
146
|
+
| `prepareAccessPolicy(depositId)` | Prepare the post-deposit Plus, Pro, Peer Makers, and Peer Pay policy transaction |
|
|
147
147
|
| `order(depositId)` / `orders(owner)` | Resume any order from its id alone; list all orders for a wallet |
|
|
148
148
|
| `watch(depositId)` | Async iterator: yields on every state change until terminal, abort, or timeout |
|
|
149
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) |
|
|
@@ -165,21 +165,22 @@ Peer Cash transaction, including approves, carries ERC-8021 attribution:
|
|
|
165
165
|
`peer-cash` first, optional `peer-ref-XXXXXX` from `referralCode` next, and your
|
|
166
166
|
analytics-only `referrer` code(s) after it.
|
|
167
167
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
`
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
`
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
168
|
+
No platform requires an atomic access-policy flow. `cashout()` and `prepare()`
|
|
169
|
+
work with any viem `WalletClient`, including a local or externally connected
|
|
170
|
+
EOA; no Privy wallet or signer API is required. The deprecated
|
|
171
|
+
`requiresAtomicAccessPolicy` capability remains for wire compatibility and is
|
|
172
|
+
always `false`.
|
|
173
|
+
|
|
174
|
+
Venmo, Cash App, and PayPal cash-outs attach Plus, Pro, Peer Makers, and Peer
|
|
175
|
+
Pay groups by default. Signed `cashout()` creates the deposit first, then uses
|
|
176
|
+
the same wallet to submit and confirm the policy transaction; this intentionally
|
|
177
|
+
leaves a brief non-atomic interval. Prepared integrations receive
|
|
178
|
+
`accessPolicyRequired: true` for those platforms and, after confirming
|
|
179
|
+
`createDeposit`, must call `finalizePreparedCashout(receipt)` followed by
|
|
180
|
+
`prepareAccessPolicy(depositId)`. Other platforms do not need the follow-up.
|
|
181
|
+
If policy attachment fails, `ACCESS_POLICY_CONFIGURATION_FAILED.recovery`
|
|
182
|
+
identifies the existing deposit and any submitted policy transaction. Do not
|
|
183
|
+
create another cash-out; resume the policy step with the same depositor wallet.
|
|
183
184
|
|
|
184
185
|
`capabilities()` presents Zelle as one platform. A cashout with
|
|
185
186
|
`receive.platform: 'zelle'` attaches only the generic Zelle payment method to
|
|
@@ -239,6 +240,9 @@ they are available. A source-routed result includes both a flat
|
|
|
239
240
|
- `TRANSACTION_SUBMISSION_UNKNOWN`: a Base-only cashout or another mutation
|
|
240
241
|
returned no hash. Treat it as potentially broadcast. Inspect recent Base
|
|
241
242
|
wallet activity and the supplied recovery action before any retry.
|
|
243
|
+
- `ACCESS_POLICY_CONFIGURATION_FAILED`: the deposit exists, but its required
|
|
244
|
+
Venmo, Cash App, or PayPal policy was not confirmed. Do not cash out again;
|
|
245
|
+
retry `prepareAccessPolicy(error.recovery.depositId)` with the depositor.
|
|
242
246
|
|
|
243
247
|
Wallet clients pinned to the wrong chain fail with `SIGNER_CHAIN_MISMATCH`
|
|
244
248
|
before a quote or transaction is submitted. Chainless wallets are checked
|
|
@@ -198,11 +198,12 @@ var errors = {
|
|
|
198
198
|
},
|
|
199
199
|
{ cause }
|
|
200
200
|
),
|
|
201
|
+
/** @deprecated Cash-outs no longer require an atomic access-policy flow. */
|
|
201
202
|
atomicAccessPolicyRequired: (platforms) => new CashError({
|
|
202
203
|
code: "ATOMIC_ACCESS_POLICY_REQUIRED",
|
|
203
|
-
message:
|
|
204
|
+
message: `Atomic access-policy enforcement for ${platforms.join(", ")} is deprecated.`,
|
|
204
205
|
retryable: false,
|
|
205
|
-
remediation: `
|
|
206
|
+
remediation: `Upgrade @zkp2p/cash; current cash-out flows do not require atomic access-policy configuration.`
|
|
206
207
|
}),
|
|
207
208
|
sourceRouteUnsupportedInPrepare: () => new CashError({
|
|
208
209
|
code: "SOURCE_ROUTE_UNSUPPORTED_IN_PREPARE",
|
|
@@ -405,20 +406,28 @@ var errors = {
|
|
|
405
406
|
},
|
|
406
407
|
{ cause }
|
|
407
408
|
),
|
|
408
|
-
accessPolicyConfigurationFailed: (depositId, groupIds,
|
|
409
|
+
accessPolicyConfigurationFailed: (depositId, groupIds, context = {}) => new CashError(
|
|
409
410
|
{
|
|
410
411
|
code: "ACCESS_POLICY_CONFIGURATION_FAILED",
|
|
411
|
-
message: `Cash-out deposit ${depositId} was created, but its
|
|
412
|
+
message: `Cash-out deposit ${depositId} was created, but its access policy could not be confirmed.`,
|
|
412
413
|
retryable: false,
|
|
413
|
-
remediation: `Do not
|
|
414
|
+
remediation: `Do not create another cash-out. Submit prepareAccessPolicy(recovery.depositId) with the same depositor wallet, then confirm that transaction.`,
|
|
414
415
|
recovery: {
|
|
415
416
|
kind: "configure-cashout-access-policy",
|
|
416
417
|
depositId,
|
|
417
418
|
groupIds: [...groupIds],
|
|
418
|
-
...transactionHash ? { transactionHash } : {}
|
|
419
|
+
...context.transactionHash ? { transactionHash: context.transactionHash } : {},
|
|
420
|
+
...context.source ? {
|
|
421
|
+
source: {
|
|
422
|
+
amount: context.source.amount.toString(),
|
|
423
|
+
...context.source.requestId ? { requestId: context.source.requestId } : {},
|
|
424
|
+
txHashes: context.source.txHashes,
|
|
425
|
+
...context.source.transactions ? { transactions: context.source.transactions } : {}
|
|
426
|
+
}
|
|
427
|
+
} : {}
|
|
419
428
|
}
|
|
420
429
|
},
|
|
421
|
-
{ cause }
|
|
430
|
+
{ cause: context.cause }
|
|
422
431
|
),
|
|
423
432
|
escrowPaused: () => new CashError({
|
|
424
433
|
code: "ESCROW_PAUSED",
|
|
@@ -311,10 +311,7 @@ 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
|
-
*/
|
|
314
|
+
/** @deprecated Always false. Restricted-platform policies are attached sequentially. */
|
|
318
315
|
requiresAtomicAccessPolicy: boolean;
|
|
319
316
|
}
|
|
320
317
|
interface CashCapabilities {
|
|
@@ -549,7 +546,7 @@ interface CashoutInput {
|
|
|
549
546
|
};
|
|
550
547
|
}
|
|
551
548
|
interface SignerOptions {
|
|
552
|
-
/**
|
|
549
|
+
/** Any viem WalletClient with a Base account, including a local or external EOA. */
|
|
553
550
|
signer: WalletClient;
|
|
554
551
|
}
|
|
555
552
|
interface CashoutOptions extends SignerOptions {
|
|
@@ -587,7 +584,7 @@ interface CashoutResult {
|
|
|
587
584
|
onchainDepositId: bigint;
|
|
588
585
|
/** Optimistic snapshot (`awaiting-buyer`); poll `order(depositId)` for live state. */
|
|
589
586
|
order: CashOrder;
|
|
590
|
-
/**
|
|
587
|
+
/** Confirmed access-policy transaction for Venmo, Cash App, or PayPal cash-outs. */
|
|
591
588
|
accessPolicyTxHash?: Hash;
|
|
592
589
|
/** Present when `cashout()` first routed a source asset through Relay. */
|
|
593
590
|
source?: {
|
|
@@ -615,7 +612,7 @@ interface PrepareResult {
|
|
|
615
612
|
register: {
|
|
616
613
|
hashedOnchainIds: string[];
|
|
617
614
|
};
|
|
618
|
-
/**
|
|
615
|
+
/** Whether the host must submit `prepareAccessPolicy(depositId)` after `createDeposit`. */
|
|
619
616
|
accessPolicyRequired: boolean;
|
|
620
617
|
}
|
|
621
618
|
/** Confirmed createDeposit receipt from an externally executed prepare() plan. */
|
|
@@ -679,7 +676,7 @@ interface CashClient {
|
|
|
679
676
|
prepare(input: CashoutInput): Promise<PrepareResult>;
|
|
680
677
|
/** Resolve an externally executed createDeposit receipt into resumable cash-out state. */
|
|
681
678
|
finalizePreparedCashout(receipt: PreparedCashoutReceipt): CashoutResult;
|
|
682
|
-
/**
|
|
679
|
+
/** Prepare the required four-group follow-up for a restricted cash-out. */
|
|
683
680
|
prepareAccessPolicy(depositId: string): PreparedTransaction;
|
|
684
681
|
/** 3 - Observe: resumable from `depositId` alone; no session state anywhere. */
|
|
685
682
|
order(depositId: string): Promise<CashOrder>;
|
|
@@ -311,10 +311,7 @@ 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
|
-
*/
|
|
314
|
+
/** @deprecated Always false. Restricted-platform policies are attached sequentially. */
|
|
318
315
|
requiresAtomicAccessPolicy: boolean;
|
|
319
316
|
}
|
|
320
317
|
interface CashCapabilities {
|
|
@@ -549,7 +546,7 @@ interface CashoutInput {
|
|
|
549
546
|
};
|
|
550
547
|
}
|
|
551
548
|
interface SignerOptions {
|
|
552
|
-
/**
|
|
549
|
+
/** Any viem WalletClient with a Base account, including a local or external EOA. */
|
|
553
550
|
signer: WalletClient;
|
|
554
551
|
}
|
|
555
552
|
interface CashoutOptions extends SignerOptions {
|
|
@@ -587,7 +584,7 @@ interface CashoutResult {
|
|
|
587
584
|
onchainDepositId: bigint;
|
|
588
585
|
/** Optimistic snapshot (`awaiting-buyer`); poll `order(depositId)` for live state. */
|
|
589
586
|
order: CashOrder;
|
|
590
|
-
/**
|
|
587
|
+
/** Confirmed access-policy transaction for Venmo, Cash App, or PayPal cash-outs. */
|
|
591
588
|
accessPolicyTxHash?: Hash;
|
|
592
589
|
/** Present when `cashout()` first routed a source asset through Relay. */
|
|
593
590
|
source?: {
|
|
@@ -615,7 +612,7 @@ interface PrepareResult {
|
|
|
615
612
|
register: {
|
|
616
613
|
hashedOnchainIds: string[];
|
|
617
614
|
};
|
|
618
|
-
/**
|
|
615
|
+
/** Whether the host must submit `prepareAccessPolicy(depositId)` after `createDeposit`. */
|
|
619
616
|
accessPolicyRequired: boolean;
|
|
620
617
|
}
|
|
621
618
|
/** Confirmed createDeposit receipt from an externally executed prepare() plan. */
|
|
@@ -679,7 +676,7 @@ interface CashClient {
|
|
|
679
676
|
prepare(input: CashoutInput): Promise<PrepareResult>;
|
|
680
677
|
/** Resolve an externally executed createDeposit receipt into resumable cash-out state. */
|
|
681
678
|
finalizePreparedCashout(receipt: PreparedCashoutReceipt): CashoutResult;
|
|
682
|
-
/**
|
|
679
|
+
/** Prepare the required four-group follow-up for a restricted cash-out. */
|
|
683
680
|
prepareAccessPolicy(depositId: string): PreparedTransaction;
|
|
684
681
|
/** 3 - Observe: resumable from `depositId` alone; no session state anywhere. */
|
|
685
682
|
order(depositId: string): Promise<CashOrder>;
|
package/dist/index.cjs
CHANGED
|
@@ -498,7 +498,7 @@ function buildCapabilities(environment) {
|
|
|
498
498
|
currencies: [...new Set(currencies2)].sort(),
|
|
499
499
|
payeeHint: PAYEE_HINTS[platform] ?? "Your payment handle for this platform",
|
|
500
500
|
requiresIdentityAttestation: IDENTITY_ATTESTATION_PLATFORMS.has(platform),
|
|
501
|
-
requiresAtomicAccessPolicy:
|
|
501
|
+
requiresAtomicAccessPolicy: false
|
|
502
502
|
};
|
|
503
503
|
}).filter((p) => p.currencies.length > 0).sort((a, b) => a.platform.localeCompare(b.platform));
|
|
504
504
|
const currencies = [...new Set(platforms.flatMap((p) => p.currencies))].sort();
|
|
@@ -680,11 +680,12 @@ var errors = {
|
|
|
680
680
|
},
|
|
681
681
|
{ cause }
|
|
682
682
|
),
|
|
683
|
+
/** @deprecated Cash-outs no longer require an atomic access-policy flow. */
|
|
683
684
|
atomicAccessPolicyRequired: (platforms) => new CashError({
|
|
684
685
|
code: "ATOMIC_ACCESS_POLICY_REQUIRED",
|
|
685
|
-
message:
|
|
686
|
+
message: `Atomic access-policy enforcement for ${platforms.join(", ")} is deprecated.`,
|
|
686
687
|
retryable: false,
|
|
687
|
-
remediation: `
|
|
688
|
+
remediation: `Upgrade @zkp2p/cash; current cash-out flows do not require atomic access-policy configuration.`
|
|
688
689
|
}),
|
|
689
690
|
sourceRouteUnsupportedInPrepare: () => new CashError({
|
|
690
691
|
code: "SOURCE_ROUTE_UNSUPPORTED_IN_PREPARE",
|
|
@@ -887,20 +888,28 @@ var errors = {
|
|
|
887
888
|
},
|
|
888
889
|
{ cause }
|
|
889
890
|
),
|
|
890
|
-
accessPolicyConfigurationFailed: (depositId, groupIds,
|
|
891
|
+
accessPolicyConfigurationFailed: (depositId, groupIds, context = {}) => new CashError(
|
|
891
892
|
{
|
|
892
893
|
code: "ACCESS_POLICY_CONFIGURATION_FAILED",
|
|
893
|
-
message: `Cash-out deposit ${depositId} was created, but its
|
|
894
|
+
message: `Cash-out deposit ${depositId} was created, but its access policy could not be confirmed.`,
|
|
894
895
|
retryable: false,
|
|
895
|
-
remediation: `Do not
|
|
896
|
+
remediation: `Do not create another cash-out. Submit prepareAccessPolicy(recovery.depositId) with the same depositor wallet, then confirm that transaction.`,
|
|
896
897
|
recovery: {
|
|
897
898
|
kind: "configure-cashout-access-policy",
|
|
898
899
|
depositId,
|
|
899
900
|
groupIds: [...groupIds],
|
|
900
|
-
...transactionHash ? { transactionHash } : {}
|
|
901
|
+
...context.transactionHash ? { transactionHash: context.transactionHash } : {},
|
|
902
|
+
...context.source ? {
|
|
903
|
+
source: {
|
|
904
|
+
amount: context.source.amount.toString(),
|
|
905
|
+
...context.source.requestId ? { requestId: context.source.requestId } : {},
|
|
906
|
+
txHashes: context.source.txHashes,
|
|
907
|
+
...context.source.transactions ? { transactions: context.source.transactions } : {}
|
|
908
|
+
}
|
|
909
|
+
} : {}
|
|
901
910
|
}
|
|
902
911
|
},
|
|
903
|
-
{ cause }
|
|
912
|
+
{ cause: context.cause }
|
|
904
913
|
),
|
|
905
914
|
escrowPaused: () => new CashError({
|
|
906
915
|
code: "ESCROW_PAUSED",
|
|
@@ -1786,6 +1795,11 @@ async function submitAndConfirm(client, verb, send) {
|
|
|
1786
1795
|
function isKnownPreBroadcastFailure(mapped) {
|
|
1787
1796
|
return mapped.code === "TRANSACTION_REJECTED" || mapped.code === "INSUFFICIENT_TOKEN_BALANCE" || mapped.code === "ALLOWANCE_NOT_VISIBLE" || mapped.code === "ESCROW_PAUSED";
|
|
1788
1797
|
}
|
|
1798
|
+
function requiresCashoutAccessPolicy(depositInput) {
|
|
1799
|
+
return depositInput.payouts.some(
|
|
1800
|
+
(payout) => CASH_RESTRICTED_PLATFORMS.has(payout.processorName.toLowerCase())
|
|
1801
|
+
);
|
|
1802
|
+
}
|
|
1789
1803
|
function depositOrderOptions(deposit) {
|
|
1790
1804
|
const remaining = toBigIntOrUndefined(deposit.remainingDeposits);
|
|
1791
1805
|
const outstanding = toBigIntOrUndefined(deposit.outstandingIntentAmount);
|
|
@@ -1917,12 +1931,6 @@ function createCashClient(options) {
|
|
|
1917
1931
|
...range ? { intentAmountRange: range } : {}
|
|
1918
1932
|
};
|
|
1919
1933
|
}
|
|
1920
|
-
function assertGenericCashoutSupported(payoutInput) {
|
|
1921
|
-
const restrictedPlatforms = payoutInput.payouts.map((payout) => payout.processorName.toLowerCase()).filter((platform) => CASH_RESTRICTED_PLATFORMS.has(platform));
|
|
1922
|
-
if (restrictedPlatforms.length > 0) {
|
|
1923
|
-
throw errors.atomicAccessPolicyRequired(restrictedPlatforms);
|
|
1924
|
-
}
|
|
1925
|
-
}
|
|
1926
1934
|
function isCashPayoutSet(payouts) {
|
|
1927
1935
|
return payouts.length > 0 && payouts.every((payout) => payout.pricing.marketRate && payout.pricing.spreadBps === 0);
|
|
1928
1936
|
}
|
|
@@ -2162,7 +2170,7 @@ function createCashClient(options) {
|
|
|
2162
2170
|
if (lastNonceError) throw lastNonceError;
|
|
2163
2171
|
throw new Error(`Signer provider did not observe Relay nonce ${afterRelay - 1}`);
|
|
2164
2172
|
}
|
|
2165
|
-
function prepareCashoutAccess(depositId, client = readClient) {
|
|
2173
|
+
function prepareCashoutAccess(depositId, client = readClient, source) {
|
|
2166
2174
|
const { compositeId, escrowAddress, onchainDepositId } = parseDepositId(depositId);
|
|
2167
2175
|
const groupIds = CASH_ACCESS_GROUP_IDS[environment];
|
|
2168
2176
|
try {
|
|
@@ -2181,9 +2189,50 @@ function createCashClient(options) {
|
|
|
2181
2189
|
chainId: prepared.chainId
|
|
2182
2190
|
};
|
|
2183
2191
|
} catch (err) {
|
|
2184
|
-
throw errors.accessPolicyConfigurationFailed(compositeId, groupIds,
|
|
2192
|
+
throw errors.accessPolicyConfigurationFailed(compositeId, groupIds, {
|
|
2193
|
+
cause: err,
|
|
2194
|
+
...source ? { source } : {}
|
|
2195
|
+
});
|
|
2185
2196
|
}
|
|
2186
2197
|
}
|
|
2198
|
+
async function configureCashoutAccess(client, signer, depositInput, depositId, source) {
|
|
2199
|
+
if (!requiresCashoutAccessPolicy(depositInput)) return void 0;
|
|
2200
|
+
const groupIds = CASH_ACCESS_GROUP_IDS[environment];
|
|
2201
|
+
const prepared = prepareCashoutAccess(depositId, client, source);
|
|
2202
|
+
let hash;
|
|
2203
|
+
try {
|
|
2204
|
+
hash = await signer.sendTransaction({
|
|
2205
|
+
account: signer.account,
|
|
2206
|
+
chain: signer.chain,
|
|
2207
|
+
to: prepared.to,
|
|
2208
|
+
data: prepared.data,
|
|
2209
|
+
value: prepared.value
|
|
2210
|
+
});
|
|
2211
|
+
} catch (err) {
|
|
2212
|
+
throw errors.accessPolicyConfigurationFailed(depositId, groupIds, {
|
|
2213
|
+
cause: err,
|
|
2214
|
+
...source ? { source } : {}
|
|
2215
|
+
});
|
|
2216
|
+
}
|
|
2217
|
+
let receipt;
|
|
2218
|
+
try {
|
|
2219
|
+
receipt = await client.publicClient.waitForTransactionReceipt({ hash });
|
|
2220
|
+
} catch (err) {
|
|
2221
|
+
throw errors.accessPolicyConfigurationFailed(depositId, groupIds, {
|
|
2222
|
+
cause: err,
|
|
2223
|
+
transactionHash: hash,
|
|
2224
|
+
...source ? { source } : {}
|
|
2225
|
+
});
|
|
2226
|
+
}
|
|
2227
|
+
if (receipt.status === "reverted") {
|
|
2228
|
+
throw errors.accessPolicyConfigurationFailed(depositId, groupIds, {
|
|
2229
|
+
cause: errors.transactionFailed(hash),
|
|
2230
|
+
transactionHash: hash,
|
|
2231
|
+
...source ? { source } : {}
|
|
2232
|
+
});
|
|
2233
|
+
}
|
|
2234
|
+
return hash;
|
|
2235
|
+
}
|
|
2187
2236
|
return {
|
|
2188
2237
|
capabilities,
|
|
2189
2238
|
async sourceCapabilities() {
|
|
@@ -2221,7 +2270,6 @@ function createCashClient(options) {
|
|
|
2221
2270
|
},
|
|
2222
2271
|
async cashout(input, opts) {
|
|
2223
2272
|
const payoutInput = validatePayout(input);
|
|
2224
|
-
assertGenericCashoutSupported(payoutInput);
|
|
2225
2273
|
const client = await signingClient("cashout", opts);
|
|
2226
2274
|
const owner = opts.signer.account.address;
|
|
2227
2275
|
let sourceResult;
|
|
@@ -2319,6 +2367,13 @@ function createCashClient(options) {
|
|
|
2319
2367
|
const abi2 = client.escrowV2Abi ?? client.escrowAbi;
|
|
2320
2368
|
const resolved2 = resolveCashDepositId({ logs: receipt2.logs, abi: abi2 });
|
|
2321
2369
|
if (!resolved2) throw errors.depositResolutionFailed(hash2);
|
|
2370
|
+
const accessPolicyTxHash2 = await configureCashoutAccess(
|
|
2371
|
+
client,
|
|
2372
|
+
opts.signer,
|
|
2373
|
+
depositInput2,
|
|
2374
|
+
resolved2.compositeId,
|
|
2375
|
+
routedSource
|
|
2376
|
+
);
|
|
2322
2377
|
const order2 = deriveCashOrder(resolved2.compositeId, [], {
|
|
2323
2378
|
remainingAmount: depositInput2.amount,
|
|
2324
2379
|
status: "ACTIVE"
|
|
@@ -2329,6 +2384,7 @@ function createCashClient(options) {
|
|
|
2329
2384
|
escrowAddress: resolved2.escrowAddress,
|
|
2330
2385
|
onchainDepositId: resolved2.onchainDepositId,
|
|
2331
2386
|
order: order2,
|
|
2387
|
+
...accessPolicyTxHash2 ? { accessPolicyTxHash: accessPolicyTxHash2 } : {},
|
|
2332
2388
|
source: routedSource
|
|
2333
2389
|
};
|
|
2334
2390
|
}
|
|
@@ -2373,6 +2429,12 @@ function createCashClient(options) {
|
|
|
2373
2429
|
const abi = client.escrowV2Abi ?? client.escrowAbi;
|
|
2374
2430
|
const resolved = resolveCashDepositId({ logs: receipt.logs, abi });
|
|
2375
2431
|
if (!resolved) throw errors.depositResolutionFailed(hash);
|
|
2432
|
+
const accessPolicyTxHash = await configureCashoutAccess(
|
|
2433
|
+
client,
|
|
2434
|
+
opts.signer,
|
|
2435
|
+
depositInput,
|
|
2436
|
+
resolved.compositeId
|
|
2437
|
+
);
|
|
2376
2438
|
const order = deriveCashOrder(resolved.compositeId, [], {
|
|
2377
2439
|
remainingAmount: depositInput.amount,
|
|
2378
2440
|
status: "ACTIVE"
|
|
@@ -2383,13 +2445,13 @@ function createCashClient(options) {
|
|
|
2383
2445
|
escrowAddress: resolved.escrowAddress,
|
|
2384
2446
|
onchainDepositId: resolved.onchainDepositId,
|
|
2385
2447
|
order,
|
|
2448
|
+
...accessPolicyTxHash ? { accessPolicyTxHash } : {},
|
|
2386
2449
|
...sourceResult ? { source: sourceResult } : {}
|
|
2387
2450
|
};
|
|
2388
2451
|
},
|
|
2389
2452
|
async prepare(input) {
|
|
2390
2453
|
if (input.source) throw errors.sourceRouteUnsupportedInPrepare();
|
|
2391
2454
|
const depositInput = validateDepositInput(input.amount, input);
|
|
2392
|
-
assertGenericCashoutSupported(depositInput);
|
|
2393
2455
|
const params = await buildDepositParams(readClient, depositInput);
|
|
2394
2456
|
const { prepared } = await readClient.prepareCreateDeposit({
|
|
2395
2457
|
...params,
|
|
@@ -2422,7 +2484,7 @@ function createCashClient(options) {
|
|
|
2422
2484
|
}
|
|
2423
2485
|
],
|
|
2424
2486
|
register: { hashedOnchainIds },
|
|
2425
|
-
accessPolicyRequired:
|
|
2487
|
+
accessPolicyRequired: requiresCashoutAccessPolicy(depositInput)
|
|
2426
2488
|
};
|
|
2427
2489
|
},
|
|
2428
2490
|
finalizePreparedCashout(receipt) {
|
|
@@ -3049,7 +3111,8 @@ var cashErrorRecoveryJsonSchema = zod.z.discriminatedUnion("kind", [
|
|
|
3049
3111
|
kind: zod.z.literal("configure-cashout-access-policy"),
|
|
3050
3112
|
depositId: zod.z.string(),
|
|
3051
3113
|
groupIds: zod.z.array(zod.z.string()),
|
|
3052
|
-
transactionHash: zod.z.string().optional()
|
|
3114
|
+
transactionHash: zod.z.string().optional(),
|
|
3115
|
+
source: zod.z.object(cashSourceRecoveryJsonShape).strict().optional()
|
|
3053
3116
|
}).strict()
|
|
3054
3117
|
]);
|
|
3055
3118
|
var cashErrorJsonSchema = zod.z.object({
|
|
@@ -3377,6 +3440,10 @@ function topUpResultFromJson(json) {
|
|
|
3377
3440
|
function capabilitiesToJson(caps) {
|
|
3378
3441
|
return {
|
|
3379
3442
|
...caps,
|
|
3443
|
+
platforms: caps.platforms.map((platform) => ({
|
|
3444
|
+
...platform,
|
|
3445
|
+
requiresAtomicAccessPolicy: false
|
|
3446
|
+
})),
|
|
3380
3447
|
amount: {
|
|
3381
3448
|
min: caps.amount.min.toString(),
|
|
3382
3449
|
recommendedMin: caps.amount.recommendedMin.toString(),
|
|
@@ -3395,7 +3462,7 @@ function capabilitiesFromJson(json) {
|
|
|
3395
3462
|
platforms: parsed.platforms.map((p) => ({
|
|
3396
3463
|
...p,
|
|
3397
3464
|
currencies: p.currencies,
|
|
3398
|
-
requiresAtomicAccessPolicy:
|
|
3465
|
+
requiresAtomicAccessPolicy: false
|
|
3399
3466
|
})),
|
|
3400
3467
|
currencies: parsed.currencies,
|
|
3401
3468
|
amount: {
|
|
@@ -3429,7 +3496,15 @@ function cashErrorFromJson(json) {
|
|
|
3429
3496
|
kind: parsed.recovery.kind,
|
|
3430
3497
|
depositId: parsed.recovery.depositId,
|
|
3431
3498
|
groupIds: parsed.recovery.groupIds,
|
|
3432
|
-
...parsed.recovery.transactionHash !== void 0 ? { transactionHash: parsed.recovery.transactionHash } : {}
|
|
3499
|
+
...parsed.recovery.transactionHash !== void 0 ? { transactionHash: parsed.recovery.transactionHash } : {},
|
|
3500
|
+
...parsed.recovery.source !== void 0 ? {
|
|
3501
|
+
source: {
|
|
3502
|
+
amount: parsed.recovery.source.amount,
|
|
3503
|
+
txHashes: parsed.recovery.source.txHashes,
|
|
3504
|
+
...parsed.recovery.source.requestId !== void 0 ? { requestId: parsed.recovery.source.requestId } : {},
|
|
3505
|
+
...parsed.recovery.source.transactions !== void 0 ? { transactions: parsed.recovery.source.transactions } : {}
|
|
3506
|
+
}
|
|
3507
|
+
} : {}
|
|
3433
3508
|
};
|
|
3434
3509
|
} else if (parsed.recovery.kind === "inspect-base-operation-submission") {
|
|
3435
3510
|
recovery = {
|