@zkp2p/cash 0.1.5 → 0.1.7
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 +13 -2
- package/README.md +29 -5
- package/dist/{chunk-P3KYZ2FX.js → chunk-TR6JVYYF.js} +6 -0
- package/dist/index.cjs +43 -7
- package/dist/index.d.cts +5 -4
- package/dist/index.d.ts +5 -4
- package/dist/index.js +39 -9
- package/dist/react.js +1 -1
- package/dist/tools.cjs +1 -1
- package/dist/tools.js +1 -1
- package/docs/lifecycle-and-recovery.md +21 -2
- package/llms.txt +3 -4
- package/package.json +21 -14
package/AGENTS.md
CHANGED
|
@@ -110,10 +110,19 @@ console.log(routed.source?.transactions?.origin, routed.source?.transactions?.de
|
|
|
110
110
|
`sourceSigner`. Use `EXACT_INPUT` in high-level cash-out flows so `amount`
|
|
111
111
|
remains source-token base units. `source.amount` is Relay's guaranteed
|
|
112
112
|
minimum output and the exact Base USDC deposit amount.
|
|
113
|
+
- **Use a nonce-managed source signer for routed cashouts.** Relay routes
|
|
114
|
+
with more than one source-chain transaction (approve, then route) are
|
|
115
|
+
refused preflight with `SOURCE_NONCE_MANAGER_REQUIRED` on plain local
|
|
116
|
+
accounts - create the source signer with
|
|
117
|
+
`privateKeyToAccount(pk, { nonceManager })`. Browser (`json-rpc`) wallets
|
|
118
|
+
are unaffected.
|
|
113
119
|
- **Persist source evidence.** A routed result carries `requestId`, flat
|
|
114
120
|
`txHashes`, and chain-aware `transactions.origin` / `.destination` arrays.
|
|
115
121
|
- **Never repeat a completed or uncertain route.** On `SOURCE_EXECUTION_FAILED`,
|
|
116
|
-
inspect its Relay request and transaction recovery evidence.
|
|
122
|
+
inspect its Relay request and transaction recovery evidence. A failed
|
|
123
|
+
approval-only route can sit in `relayStatus` `waiting` indefinitely - decide
|
|
124
|
+
from the recovery payload and origin transactions, never by waiting for a
|
|
125
|
+
terminal Relay status. On
|
|
117
126
|
`SOURCE_ROUTE_COMPLETED_CASHOUT_FAILED`, retry without `source` using
|
|
118
127
|
`BigInt(err.recovery.amount)`. On `SOURCE_CASHOUT_SUBMISSION_UNKNOWN`, inspect
|
|
119
128
|
Base wallet activity and `orders(err.recovery.depositor)`. On
|
|
@@ -128,7 +137,8 @@ console.log(routed.source?.transactions?.origin, routed.source?.transactions?.de
|
|
|
128
137
|
deposit. The tx receipt you hold is the truth. Retry; `watch()` absorbs
|
|
129
138
|
this automatically.
|
|
130
139
|
- **Unwind with `withdraw()` only.** It is state-aware (prunes expired
|
|
131
|
-
intents first). Do not call escrow functions directly.
|
|
140
|
+
intents first). Do not call escrow functions directly. Partial withdrawals
|
|
141
|
+
increment `returnedAmount`; `totalAmount` is historical and never shrinks.
|
|
132
142
|
- **Read fills as receipts.** `fiatOwed` is the buyer's obligation at the
|
|
133
143
|
locked rate; after the proof, `fiatPaid`/`paymentId`/`releasedAmount` are
|
|
134
144
|
the verified outcome. Reconcile against those, not your own math.
|
|
@@ -161,6 +171,7 @@ Every `CashError` carries `code`, `retryable`, `remediation`. Behavior:
|
|
|
161
171
|
| `SOURCE_RECIPIENT_MISMATCH` | no | Route Base USDC to the cashout depositor |
|
|
162
172
|
| `SOURCE_CAPABILITIES_FAILED` | yes | Retry discovery or fall back to Base USDC |
|
|
163
173
|
| `SOURCE_QUOTE_FAILED` | yes | Refresh capabilities and request a new canonical Base-USDC quote |
|
|
174
|
+
| `SOURCE_NONCE_MANAGER_REQUIRED` | no | Preflight; recreate the source signer with viem's `nonceManager`, then quote again |
|
|
164
175
|
| `SOURCE_EXECUTION_FAILED` | no | Inspect source transactions and Relay status before any retry |
|
|
165
176
|
| `SOURCE_STATUS_FAILED` | yes | Retry only the status read |
|
|
166
177
|
| `SOURCE_ROUTE_COMPLETED_CASHOUT_FAILED` | no | Do not route again; retry Base-only with `recovery.amount` |
|
package/README.md
CHANGED
|
@@ -5,12 +5,25 @@ on Venmo, Revolut, Wise, Zelle, and more at the live Chainlink market rate,
|
|
|
5
5
|
with zero spread and no centralized off-ramp provider.
|
|
6
6
|
|
|
7
7
|
Peer Cash is an **offramp-only** SDK for the [ZKP2P](https://peer.xyz)
|
|
8
|
-
protocol. The cashing-out user is the maker: their USDC becomes a
|
|
9
|
-
protocol
|
|
10
|
-
integrator a small set of typed verbs plus readable order state.
|
|
11
|
-
widget, no provider custody, no quote engine to maintain.
|
|
8
|
+
protocol. The cashing-out user is the maker: their USDC becomes a deposit in
|
|
9
|
+
the protocol contracts, a buyer pays them fiat and proves the payment, and the
|
|
10
|
+
SDK gives the integrator a small set of typed verbs plus readable order state.
|
|
11
|
+
No hosted widget, no provider custody, no quote engine to maintain.
|
|
12
12
|
|
|
13
|
-
**[
|
|
13
|
+
**[npm](https://www.npmjs.com/package/@zkp2p/cash)** · **[Lifecycle and recovery](docs/lifecycle-and-recovery.md)** · **[Agent integration manual](AGENTS.md)**
|
|
14
|
+
|
|
15
|
+
## Pick the right SDK
|
|
16
|
+
|
|
17
|
+
Peer Cash and the general ZKP2P SDK serve different integration depths:
|
|
18
|
+
|
|
19
|
+
| Package | Use it when | Boundary |
|
|
20
|
+
| ------------- | ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
21
|
+
| `@zkp2p/cash` | Cash-out is the product | Offramp only. The user is always the maker, the destination is Base USDC, pricing is the live Chainlink rate at fill with zero spread, and the SDK owns the resumable order lifecycle. |
|
|
22
|
+
| `@zkp2p/sdk` | You are composing directly with the Peer protocol | General maker and taker operations, deposits, intents, proofs, quotes, vaults, rate managers, referrals, hooks, and API helpers. Your application owns the workflow and protocol choices. |
|
|
23
|
+
|
|
24
|
+
Peer Cash is a narrow facade over `@zkp2p/sdk`, not a replacement for it. It
|
|
25
|
+
cannot express custom spreads, buyer-side proof flows, vaults, disputes, or
|
|
26
|
+
arbitrary protocol operations.
|
|
14
27
|
|
|
15
28
|
```ts
|
|
16
29
|
import { createCashClient, usdc } from '@zkp2p/cash';
|
|
@@ -94,6 +107,13 @@ The destination is always canonical Base USDC
|
|
|
94
107
|
discovered and quoted by `@relayprotocol/relay-sdk`, not a static token
|
|
95
108
|
allowlist.
|
|
96
109
|
|
|
110
|
+
Routes that submit more than one source-chain transaction (approve, then
|
|
111
|
+
route) require a nonce-managed source signer -
|
|
112
|
+
`privateKeyToAccount(pk, { nonceManager })` from viem. Without one the SDK
|
|
113
|
+
refuses the route preflight with `SOURCE_NONCE_MANAGER_REQUIRED` instead of
|
|
114
|
+
letting the route transaction reuse the approval's nonce and revert
|
|
115
|
+
mid-route. Browser wallets are unaffected.
|
|
116
|
+
|
|
97
117
|
`capabilities()` tells you which platforms need a verified identity for a new
|
|
98
118
|
payee registration (`requiresIdentityAttestation` - Wise and PayPal today).
|
|
99
119
|
An already-registered Wise or PayPal handle can be reused with bare payee data.
|
|
@@ -107,6 +127,10 @@ they are available. A source-routed result includes both a flat
|
|
|
107
127
|
`source.txHashes` list and chain-aware `source.transactions.origin` /
|
|
108
128
|
`.destination` entries.
|
|
109
129
|
|
|
130
|
+
- `SOURCE_EXECUTION_FAILED` where only the approval landed: the Relay request
|
|
131
|
+
can stay in `relayStatus` `waiting` indefinitely. Decide from the error's
|
|
132
|
+
recovery payload and origin transactions, never by waiting for a terminal
|
|
133
|
+
Relay status.
|
|
110
134
|
- `SOURCE_ROUTE_COMPLETED_CASHOUT_FAILED`: Relay completed, but the Base
|
|
111
135
|
cashout was not created. Do not route again. Retry a Base-USDC-only
|
|
112
136
|
`cashout()` with `BigInt(error.recovery.amount)`.
|
|
@@ -189,6 +189,12 @@ var errors = {
|
|
|
189
189
|
},
|
|
190
190
|
{ cause }
|
|
191
191
|
),
|
|
192
|
+
sourceNonceManagerRequired: (transactionCount) => new CashError({
|
|
193
|
+
code: "SOURCE_NONCE_MANAGER_REQUIRED",
|
|
194
|
+
message: `This Relay route submits ${transactionCount} source-chain transactions, but the local signer has no nonce manager; the route transaction would reuse the approval nonce and revert.`,
|
|
195
|
+
retryable: false,
|
|
196
|
+
remediation: `Create the source signer with viem's nonce manager - privateKeyToAccount(pk, { nonceManager }) - then request a fresh quote and retry. No transaction was submitted.`
|
|
197
|
+
}),
|
|
192
198
|
sourceExecutionFailed: (cause, evidence) => new CashError(
|
|
193
199
|
{
|
|
194
200
|
code: "SOURCE_EXECUTION_FAILED",
|
package/dist/index.cjs
CHANGED
|
@@ -623,6 +623,12 @@ var errors = {
|
|
|
623
623
|
},
|
|
624
624
|
{ cause }
|
|
625
625
|
),
|
|
626
|
+
sourceNonceManagerRequired: (transactionCount) => new CashError({
|
|
627
|
+
code: "SOURCE_NONCE_MANAGER_REQUIRED",
|
|
628
|
+
message: `This Relay route submits ${transactionCount} source-chain transactions, but the local signer has no nonce manager; the route transaction would reuse the approval nonce and revert.`,
|
|
629
|
+
retryable: false,
|
|
630
|
+
remediation: `Create the source signer with viem's nonce manager - privateKeyToAccount(pk, { nonceManager }) - then request a fresh quote and retry. No transaction was submitted.`
|
|
631
|
+
}),
|
|
626
632
|
sourceExecutionFailed: (cause, evidence) => new CashError(
|
|
627
633
|
{
|
|
628
634
|
code: "SOURCE_EXECUTION_FAILED",
|
|
@@ -1048,6 +1054,14 @@ async function assertRelayExecutionIdentity(quote, wallet, expectedRecipient) {
|
|
|
1048
1054
|
throw new Error("Relay quote recipient does not match the expected Base recipient");
|
|
1049
1055
|
}
|
|
1050
1056
|
}
|
|
1057
|
+
function assertRelayNonceManagement(quote, wallet) {
|
|
1058
|
+
const account = wallet.account;
|
|
1059
|
+
if (!account || account.type !== "local" || account.nonceManager !== void 0) return;
|
|
1060
|
+
const transactionCount = quote.steps.flatMap(
|
|
1061
|
+
(step) => step.items.filter((item) => asString(asRecord(item.data).to) !== void 0)
|
|
1062
|
+
).length;
|
|
1063
|
+
if (transactionCount > 1) throw errors.sourceNonceManagerRequired(transactionCount);
|
|
1064
|
+
}
|
|
1051
1065
|
function isRelaySecretKey(key) {
|
|
1052
1066
|
const normalized = key.toLowerCase();
|
|
1053
1067
|
return normalized === "headers" || normalized === "apikey";
|
|
@@ -1249,6 +1263,7 @@ async function executeRelayQuote(quote, wallet, options = {}) {
|
|
|
1249
1263
|
observedRequestId = quoteRequestId(rawQuote);
|
|
1250
1264
|
assertCanonicalRelayDestination(rawQuote);
|
|
1251
1265
|
await assertRelayExecutionIdentity(rawQuote, wallet, options.recipient);
|
|
1266
|
+
assertRelayNonceManagement(rawQuote, wallet);
|
|
1252
1267
|
const client = relayClient(options.relay);
|
|
1253
1268
|
const sourceChainId = quoteSourceChainId(rawQuote);
|
|
1254
1269
|
if (sourceChainId !== void 0 && !(client.chains ?? []).some((chain) => chain.id === sourceChainId)) {
|
|
@@ -1717,32 +1732,51 @@ function createCashClient(options) {
|
|
|
1717
1732
|
(transaction) => transaction.chainId === BASE_CHAIN_ID
|
|
1718
1733
|
);
|
|
1719
1734
|
const batchIds = baseTransactions.filter((transaction) => transaction.isBatchTx === true).map((transaction) => transaction.hash);
|
|
1735
|
+
const batchExecutionFailed = (cause) => errors.sourceExecutionFailed(cause, {
|
|
1736
|
+
...executed.requestId ? { requestId: executed.requestId } : {},
|
|
1737
|
+
txHashes: executed.txHashes,
|
|
1738
|
+
...executed.transactions ? { transactions: executed.transactions } : {}
|
|
1739
|
+
});
|
|
1720
1740
|
let batchTransactionHashes = [];
|
|
1721
1741
|
if (batchIds.length > 0) {
|
|
1722
1742
|
let batchError;
|
|
1723
1743
|
let batchesComplete = false;
|
|
1744
|
+
let batchesSucceededWithoutReceipts = false;
|
|
1724
1745
|
for (let attempt = 0; attempt < 20; attempt++) {
|
|
1725
1746
|
try {
|
|
1726
1747
|
const statuses = await Promise.all(
|
|
1727
1748
|
batchIds.map((id) => sourceSigner.getCallsStatus({ id }))
|
|
1728
1749
|
);
|
|
1729
1750
|
if (statuses.some((status) => status.status === "failure")) {
|
|
1730
|
-
throw new Error("Relay wallet call bundle failed");
|
|
1751
|
+
throw batchExecutionFailed(new Error("Relay wallet call bundle failed"));
|
|
1731
1752
|
}
|
|
1732
1753
|
if (statuses.every((status) => status.status === "success")) {
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1754
|
+
const receiptGroups = statuses.map((status) => status.receipts ?? []);
|
|
1755
|
+
if (receiptGroups.some((receipts) => receipts.length === 0)) {
|
|
1756
|
+
batchError = new Error(
|
|
1757
|
+
"Relay wallet call bundle did not include transaction receipts"
|
|
1758
|
+
);
|
|
1759
|
+
batchesSucceededWithoutReceipts = true;
|
|
1760
|
+
break;
|
|
1761
|
+
} else {
|
|
1762
|
+
batchTransactionHashes = receiptGroups.flatMap(
|
|
1763
|
+
(receipts) => receipts.map((receipt) => receipt.transactionHash)
|
|
1764
|
+
);
|
|
1765
|
+
batchesComplete = true;
|
|
1766
|
+
break;
|
|
1767
|
+
}
|
|
1738
1768
|
}
|
|
1739
1769
|
} catch (err) {
|
|
1770
|
+
if (isCashError(err)) throw err;
|
|
1740
1771
|
batchError = err;
|
|
1741
1772
|
}
|
|
1742
1773
|
await sleep(250);
|
|
1743
1774
|
}
|
|
1744
1775
|
if (!batchesComplete) {
|
|
1745
|
-
|
|
1776
|
+
if (batchesSucceededWithoutReceipts) throw batchError;
|
|
1777
|
+
throw batchExecutionFailed(
|
|
1778
|
+
batchError ?? new Error("Relay wallet call bundle did not complete")
|
|
1779
|
+
);
|
|
1746
1780
|
}
|
|
1747
1781
|
}
|
|
1748
1782
|
const hashes = [
|
|
@@ -1864,6 +1898,7 @@ function createCashClient(options) {
|
|
|
1864
1898
|
executed
|
|
1865
1899
|
);
|
|
1866
1900
|
} catch (err) {
|
|
1901
|
+
if (isCashError(err)) throw err;
|
|
1867
1902
|
throw errors.sourceRouteCompletedCashoutFailed(
|
|
1868
1903
|
routedSource,
|
|
1869
1904
|
mapChainError("resolve same-chain Relay nonce", err)
|
|
@@ -2539,6 +2574,7 @@ var CASH_ERROR_CODES = defineCashErrorCodes([
|
|
|
2539
2574
|
"SOURCE_RECIPIENT_MISMATCH",
|
|
2540
2575
|
"SOURCE_CAPABILITIES_FAILED",
|
|
2541
2576
|
"SOURCE_QUOTE_FAILED",
|
|
2577
|
+
"SOURCE_NONCE_MANAGER_REQUIRED",
|
|
2542
2578
|
"SOURCE_EXECUTION_FAILED",
|
|
2543
2579
|
"SOURCE_STATUS_FAILED",
|
|
2544
2580
|
"SOURCE_ROUTE_COMPLETED_CASHOUT_FAILED",
|
package/dist/index.d.cts
CHANGED
|
@@ -10,7 +10,7 @@ import '@relayprotocol/relay-sdk';
|
|
|
10
10
|
* Typed errors - every failure carries a `code`, whether it is `retryable`,
|
|
11
11
|
* and a `remediation` sentence so agents can self-drive recovery.
|
|
12
12
|
*/
|
|
13
|
-
type CashErrorCode = 'ORACLE_UNSUPPORTED_CURRENCY' | 'ORACLE_READ_FAILED' | 'UNSUPPORTED_PLATFORM' | 'UNSUPPORTED_PLATFORM_CURRENCY' | 'AMOUNT_BELOW_MINIMUM' | 'INVALID_INTENT_AMOUNT_RANGE' | 'ACTIVE_INTENT_BLOCKS_WITHDRAWAL' | 'NOTHING_TO_WITHDRAW' | 'INSUFFICIENT_AVAILABLE_FUNDS' | 'INSUFFICIENT_TOKEN_BALANCE' | 'ORDER_NOT_ACTIVE' | 'INVALID_DEPOSIT_ID' | 'ESCROW_PAUSED' | 'INDEXER_LAG' | 'INDEXER_UNAVAILABLE' | 'ORDER_NOT_FOUND' | 'PAYEE_REGISTRATION_FAILED' | 'PAYEE_VERIFICATION_REQUIRED' | 'SOURCE_ROUTE_UNSUPPORTED_IN_PREPARE' | 'SOURCE_RECIPIENT_MISMATCH' | 'SOURCE_CAPABILITIES_FAILED' | 'SOURCE_QUOTE_FAILED' | 'SOURCE_EXECUTION_FAILED' | 'SOURCE_STATUS_FAILED' | 'SOURCE_ROUTE_COMPLETED_CASHOUT_FAILED' | 'SOURCE_CASHOUT_SUBMISSION_UNKNOWN' | 'SOURCE_CASHOUT_STATUS_UNKNOWN' | 'DEPOSIT_RESOLUTION_FAILED' | 'ALLOWANCE_NOT_VISIBLE' | 'SIGNER_REQUIRED' | 'SIGNER_CHAIN_MISMATCH' | 'SIGNER_CHAIN_UNAVAILABLE' | 'WATCH_TIMEOUT' | 'TRANSACTION_FAILED' | 'TRANSACTION_SUBMISSION_UNKNOWN' | 'TRANSACTION_STATUS_UNKNOWN';
|
|
13
|
+
type CashErrorCode = 'ORACLE_UNSUPPORTED_CURRENCY' | 'ORACLE_READ_FAILED' | 'UNSUPPORTED_PLATFORM' | 'UNSUPPORTED_PLATFORM_CURRENCY' | 'AMOUNT_BELOW_MINIMUM' | 'INVALID_INTENT_AMOUNT_RANGE' | 'ACTIVE_INTENT_BLOCKS_WITHDRAWAL' | 'NOTHING_TO_WITHDRAW' | 'INSUFFICIENT_AVAILABLE_FUNDS' | 'INSUFFICIENT_TOKEN_BALANCE' | 'ORDER_NOT_ACTIVE' | 'INVALID_DEPOSIT_ID' | 'ESCROW_PAUSED' | 'INDEXER_LAG' | 'INDEXER_UNAVAILABLE' | 'ORDER_NOT_FOUND' | 'PAYEE_REGISTRATION_FAILED' | 'PAYEE_VERIFICATION_REQUIRED' | 'SOURCE_ROUTE_UNSUPPORTED_IN_PREPARE' | 'SOURCE_RECIPIENT_MISMATCH' | 'SOURCE_CAPABILITIES_FAILED' | 'SOURCE_QUOTE_FAILED' | 'SOURCE_NONCE_MANAGER_REQUIRED' | 'SOURCE_EXECUTION_FAILED' | 'SOURCE_STATUS_FAILED' | 'SOURCE_ROUTE_COMPLETED_CASHOUT_FAILED' | 'SOURCE_CASHOUT_SUBMISSION_UNKNOWN' | 'SOURCE_CASHOUT_STATUS_UNKNOWN' | 'DEPOSIT_RESOLUTION_FAILED' | 'ALLOWANCE_NOT_VISIBLE' | 'SIGNER_REQUIRED' | 'SIGNER_CHAIN_MISMATCH' | 'SIGNER_CHAIN_UNAVAILABLE' | 'WATCH_TIMEOUT' | 'TRANSACTION_FAILED' | 'TRANSACTION_SUBMISSION_UNKNOWN' | 'TRANSACTION_STATUS_UNKNOWN';
|
|
14
14
|
interface CashErrorShape {
|
|
15
15
|
code: CashErrorCode;
|
|
16
16
|
message: string;
|
|
@@ -92,6 +92,7 @@ declare const errors: {
|
|
|
92
92
|
sourceRecipientMismatch: (recipient: string, owner: string) => CashError;
|
|
93
93
|
sourceCapabilitiesFailed: (cause?: unknown) => CashError;
|
|
94
94
|
sourceQuoteFailed: (cause?: unknown) => CashError;
|
|
95
|
+
sourceNonceManagerRequired: (transactionCount: number) => CashError;
|
|
95
96
|
sourceExecutionFailed: (cause?: unknown, evidence?: {
|
|
96
97
|
requestId?: string;
|
|
97
98
|
txHashes: string[];
|
|
@@ -3153,7 +3154,7 @@ declare const cashErrorRecoveryJsonSchema: z.ZodDiscriminatedUnion<"kind", [z.Zo
|
|
|
3153
3154
|
operation: string;
|
|
3154
3155
|
}>]>;
|
|
3155
3156
|
declare const cashErrorJsonSchema: z.ZodObject<{
|
|
3156
|
-
code: z.ZodEnum<["ORACLE_UNSUPPORTED_CURRENCY", "ORACLE_READ_FAILED", "UNSUPPORTED_PLATFORM", "UNSUPPORTED_PLATFORM_CURRENCY", "AMOUNT_BELOW_MINIMUM", "INVALID_INTENT_AMOUNT_RANGE", "ACTIVE_INTENT_BLOCKS_WITHDRAWAL", "NOTHING_TO_WITHDRAW", "INSUFFICIENT_AVAILABLE_FUNDS", "INSUFFICIENT_TOKEN_BALANCE", "ORDER_NOT_ACTIVE", "INVALID_DEPOSIT_ID", "ESCROW_PAUSED", "INDEXER_LAG", "INDEXER_UNAVAILABLE", "ORDER_NOT_FOUND", "PAYEE_REGISTRATION_FAILED", "PAYEE_VERIFICATION_REQUIRED", "SOURCE_ROUTE_UNSUPPORTED_IN_PREPARE", "SOURCE_RECIPIENT_MISMATCH", "SOURCE_CAPABILITIES_FAILED", "SOURCE_QUOTE_FAILED", "SOURCE_EXECUTION_FAILED", "SOURCE_STATUS_FAILED", "SOURCE_ROUTE_COMPLETED_CASHOUT_FAILED", "SOURCE_CASHOUT_SUBMISSION_UNKNOWN", "SOURCE_CASHOUT_STATUS_UNKNOWN", "DEPOSIT_RESOLUTION_FAILED", "ALLOWANCE_NOT_VISIBLE", "SIGNER_REQUIRED", "SIGNER_CHAIN_MISMATCH", "SIGNER_CHAIN_UNAVAILABLE", "WATCH_TIMEOUT", "TRANSACTION_FAILED", "TRANSACTION_SUBMISSION_UNKNOWN", "TRANSACTION_STATUS_UNKNOWN"]>;
|
|
3157
|
+
code: z.ZodEnum<["ORACLE_UNSUPPORTED_CURRENCY", "ORACLE_READ_FAILED", "UNSUPPORTED_PLATFORM", "UNSUPPORTED_PLATFORM_CURRENCY", "AMOUNT_BELOW_MINIMUM", "INVALID_INTENT_AMOUNT_RANGE", "ACTIVE_INTENT_BLOCKS_WITHDRAWAL", "NOTHING_TO_WITHDRAW", "INSUFFICIENT_AVAILABLE_FUNDS", "INSUFFICIENT_TOKEN_BALANCE", "ORDER_NOT_ACTIVE", "INVALID_DEPOSIT_ID", "ESCROW_PAUSED", "INDEXER_LAG", "INDEXER_UNAVAILABLE", "ORDER_NOT_FOUND", "PAYEE_REGISTRATION_FAILED", "PAYEE_VERIFICATION_REQUIRED", "SOURCE_ROUTE_UNSUPPORTED_IN_PREPARE", "SOURCE_RECIPIENT_MISMATCH", "SOURCE_CAPABILITIES_FAILED", "SOURCE_QUOTE_FAILED", "SOURCE_NONCE_MANAGER_REQUIRED", "SOURCE_EXECUTION_FAILED", "SOURCE_STATUS_FAILED", "SOURCE_ROUTE_COMPLETED_CASHOUT_FAILED", "SOURCE_CASHOUT_SUBMISSION_UNKNOWN", "SOURCE_CASHOUT_STATUS_UNKNOWN", "DEPOSIT_RESOLUTION_FAILED", "ALLOWANCE_NOT_VISIBLE", "SIGNER_REQUIRED", "SIGNER_CHAIN_MISMATCH", "SIGNER_CHAIN_UNAVAILABLE", "WATCH_TIMEOUT", "TRANSACTION_FAILED", "TRANSACTION_SUBMISSION_UNKNOWN", "TRANSACTION_STATUS_UNKNOWN"]>;
|
|
3157
3158
|
message: z.ZodString;
|
|
3158
3159
|
retryable: z.ZodBoolean;
|
|
3159
3160
|
remediation: z.ZodString;
|
|
@@ -3540,7 +3541,7 @@ declare const cashErrorJsonSchema: z.ZodObject<{
|
|
|
3540
3541
|
}>]>>;
|
|
3541
3542
|
}, "strict", z.ZodTypeAny, {
|
|
3542
3543
|
message: string;
|
|
3543
|
-
code: "ORACLE_UNSUPPORTED_CURRENCY" | "ORACLE_READ_FAILED" | "UNSUPPORTED_PLATFORM" | "UNSUPPORTED_PLATFORM_CURRENCY" | "AMOUNT_BELOW_MINIMUM" | "INVALID_INTENT_AMOUNT_RANGE" | "ACTIVE_INTENT_BLOCKS_WITHDRAWAL" | "NOTHING_TO_WITHDRAW" | "INSUFFICIENT_AVAILABLE_FUNDS" | "INSUFFICIENT_TOKEN_BALANCE" | "ORDER_NOT_ACTIVE" | "INVALID_DEPOSIT_ID" | "ESCROW_PAUSED" | "INDEXER_LAG" | "INDEXER_UNAVAILABLE" | "ORDER_NOT_FOUND" | "PAYEE_REGISTRATION_FAILED" | "PAYEE_VERIFICATION_REQUIRED" | "SOURCE_ROUTE_UNSUPPORTED_IN_PREPARE" | "SOURCE_RECIPIENT_MISMATCH" | "SOURCE_CAPABILITIES_FAILED" | "SOURCE_QUOTE_FAILED" | "SOURCE_EXECUTION_FAILED" | "SOURCE_STATUS_FAILED" | "SOURCE_ROUTE_COMPLETED_CASHOUT_FAILED" | "SOURCE_CASHOUT_SUBMISSION_UNKNOWN" | "SOURCE_CASHOUT_STATUS_UNKNOWN" | "DEPOSIT_RESOLUTION_FAILED" | "ALLOWANCE_NOT_VISIBLE" | "SIGNER_REQUIRED" | "SIGNER_CHAIN_MISMATCH" | "SIGNER_CHAIN_UNAVAILABLE" | "WATCH_TIMEOUT" | "TRANSACTION_FAILED" | "TRANSACTION_SUBMISSION_UNKNOWN" | "TRANSACTION_STATUS_UNKNOWN";
|
|
3544
|
+
code: "ORACLE_UNSUPPORTED_CURRENCY" | "ORACLE_READ_FAILED" | "UNSUPPORTED_PLATFORM" | "UNSUPPORTED_PLATFORM_CURRENCY" | "AMOUNT_BELOW_MINIMUM" | "INVALID_INTENT_AMOUNT_RANGE" | "ACTIVE_INTENT_BLOCKS_WITHDRAWAL" | "NOTHING_TO_WITHDRAW" | "INSUFFICIENT_AVAILABLE_FUNDS" | "INSUFFICIENT_TOKEN_BALANCE" | "ORDER_NOT_ACTIVE" | "INVALID_DEPOSIT_ID" | "ESCROW_PAUSED" | "INDEXER_LAG" | "INDEXER_UNAVAILABLE" | "ORDER_NOT_FOUND" | "PAYEE_REGISTRATION_FAILED" | "PAYEE_VERIFICATION_REQUIRED" | "SOURCE_ROUTE_UNSUPPORTED_IN_PREPARE" | "SOURCE_RECIPIENT_MISMATCH" | "SOURCE_CAPABILITIES_FAILED" | "SOURCE_QUOTE_FAILED" | "SOURCE_NONCE_MANAGER_REQUIRED" | "SOURCE_EXECUTION_FAILED" | "SOURCE_STATUS_FAILED" | "SOURCE_ROUTE_COMPLETED_CASHOUT_FAILED" | "SOURCE_CASHOUT_SUBMISSION_UNKNOWN" | "SOURCE_CASHOUT_STATUS_UNKNOWN" | "DEPOSIT_RESOLUTION_FAILED" | "ALLOWANCE_NOT_VISIBLE" | "SIGNER_REQUIRED" | "SIGNER_CHAIN_MISMATCH" | "SIGNER_CHAIN_UNAVAILABLE" | "WATCH_TIMEOUT" | "TRANSACTION_FAILED" | "TRANSACTION_SUBMISSION_UNKNOWN" | "TRANSACTION_STATUS_UNKNOWN";
|
|
3544
3545
|
retryable: boolean;
|
|
3545
3546
|
remediation: string;
|
|
3546
3547
|
recovery?: {
|
|
@@ -3622,7 +3623,7 @@ declare const cashErrorJsonSchema: z.ZodObject<{
|
|
|
3622
3623
|
} | undefined;
|
|
3623
3624
|
}, {
|
|
3624
3625
|
message: string;
|
|
3625
|
-
code: "ORACLE_UNSUPPORTED_CURRENCY" | "ORACLE_READ_FAILED" | "UNSUPPORTED_PLATFORM" | "UNSUPPORTED_PLATFORM_CURRENCY" | "AMOUNT_BELOW_MINIMUM" | "INVALID_INTENT_AMOUNT_RANGE" | "ACTIVE_INTENT_BLOCKS_WITHDRAWAL" | "NOTHING_TO_WITHDRAW" | "INSUFFICIENT_AVAILABLE_FUNDS" | "INSUFFICIENT_TOKEN_BALANCE" | "ORDER_NOT_ACTIVE" | "INVALID_DEPOSIT_ID" | "ESCROW_PAUSED" | "INDEXER_LAG" | "INDEXER_UNAVAILABLE" | "ORDER_NOT_FOUND" | "PAYEE_REGISTRATION_FAILED" | "PAYEE_VERIFICATION_REQUIRED" | "SOURCE_ROUTE_UNSUPPORTED_IN_PREPARE" | "SOURCE_RECIPIENT_MISMATCH" | "SOURCE_CAPABILITIES_FAILED" | "SOURCE_QUOTE_FAILED" | "SOURCE_EXECUTION_FAILED" | "SOURCE_STATUS_FAILED" | "SOURCE_ROUTE_COMPLETED_CASHOUT_FAILED" | "SOURCE_CASHOUT_SUBMISSION_UNKNOWN" | "SOURCE_CASHOUT_STATUS_UNKNOWN" | "DEPOSIT_RESOLUTION_FAILED" | "ALLOWANCE_NOT_VISIBLE" | "SIGNER_REQUIRED" | "SIGNER_CHAIN_MISMATCH" | "SIGNER_CHAIN_UNAVAILABLE" | "WATCH_TIMEOUT" | "TRANSACTION_FAILED" | "TRANSACTION_SUBMISSION_UNKNOWN" | "TRANSACTION_STATUS_UNKNOWN";
|
|
3626
|
+
code: "ORACLE_UNSUPPORTED_CURRENCY" | "ORACLE_READ_FAILED" | "UNSUPPORTED_PLATFORM" | "UNSUPPORTED_PLATFORM_CURRENCY" | "AMOUNT_BELOW_MINIMUM" | "INVALID_INTENT_AMOUNT_RANGE" | "ACTIVE_INTENT_BLOCKS_WITHDRAWAL" | "NOTHING_TO_WITHDRAW" | "INSUFFICIENT_AVAILABLE_FUNDS" | "INSUFFICIENT_TOKEN_BALANCE" | "ORDER_NOT_ACTIVE" | "INVALID_DEPOSIT_ID" | "ESCROW_PAUSED" | "INDEXER_LAG" | "INDEXER_UNAVAILABLE" | "ORDER_NOT_FOUND" | "PAYEE_REGISTRATION_FAILED" | "PAYEE_VERIFICATION_REQUIRED" | "SOURCE_ROUTE_UNSUPPORTED_IN_PREPARE" | "SOURCE_RECIPIENT_MISMATCH" | "SOURCE_CAPABILITIES_FAILED" | "SOURCE_QUOTE_FAILED" | "SOURCE_NONCE_MANAGER_REQUIRED" | "SOURCE_EXECUTION_FAILED" | "SOURCE_STATUS_FAILED" | "SOURCE_ROUTE_COMPLETED_CASHOUT_FAILED" | "SOURCE_CASHOUT_SUBMISSION_UNKNOWN" | "SOURCE_CASHOUT_STATUS_UNKNOWN" | "DEPOSIT_RESOLUTION_FAILED" | "ALLOWANCE_NOT_VISIBLE" | "SIGNER_REQUIRED" | "SIGNER_CHAIN_MISMATCH" | "SIGNER_CHAIN_UNAVAILABLE" | "WATCH_TIMEOUT" | "TRANSACTION_FAILED" | "TRANSACTION_SUBMISSION_UNKNOWN" | "TRANSACTION_STATUS_UNKNOWN";
|
|
3626
3627
|
retryable: boolean;
|
|
3627
3628
|
remediation: string;
|
|
3628
3629
|
recovery?: {
|
package/dist/index.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ import '@relayprotocol/relay-sdk';
|
|
|
10
10
|
* Typed errors - every failure carries a `code`, whether it is `retryable`,
|
|
11
11
|
* and a `remediation` sentence so agents can self-drive recovery.
|
|
12
12
|
*/
|
|
13
|
-
type CashErrorCode = 'ORACLE_UNSUPPORTED_CURRENCY' | 'ORACLE_READ_FAILED' | 'UNSUPPORTED_PLATFORM' | 'UNSUPPORTED_PLATFORM_CURRENCY' | 'AMOUNT_BELOW_MINIMUM' | 'INVALID_INTENT_AMOUNT_RANGE' | 'ACTIVE_INTENT_BLOCKS_WITHDRAWAL' | 'NOTHING_TO_WITHDRAW' | 'INSUFFICIENT_AVAILABLE_FUNDS' | 'INSUFFICIENT_TOKEN_BALANCE' | 'ORDER_NOT_ACTIVE' | 'INVALID_DEPOSIT_ID' | 'ESCROW_PAUSED' | 'INDEXER_LAG' | 'INDEXER_UNAVAILABLE' | 'ORDER_NOT_FOUND' | 'PAYEE_REGISTRATION_FAILED' | 'PAYEE_VERIFICATION_REQUIRED' | 'SOURCE_ROUTE_UNSUPPORTED_IN_PREPARE' | 'SOURCE_RECIPIENT_MISMATCH' | 'SOURCE_CAPABILITIES_FAILED' | 'SOURCE_QUOTE_FAILED' | 'SOURCE_EXECUTION_FAILED' | 'SOURCE_STATUS_FAILED' | 'SOURCE_ROUTE_COMPLETED_CASHOUT_FAILED' | 'SOURCE_CASHOUT_SUBMISSION_UNKNOWN' | 'SOURCE_CASHOUT_STATUS_UNKNOWN' | 'DEPOSIT_RESOLUTION_FAILED' | 'ALLOWANCE_NOT_VISIBLE' | 'SIGNER_REQUIRED' | 'SIGNER_CHAIN_MISMATCH' | 'SIGNER_CHAIN_UNAVAILABLE' | 'WATCH_TIMEOUT' | 'TRANSACTION_FAILED' | 'TRANSACTION_SUBMISSION_UNKNOWN' | 'TRANSACTION_STATUS_UNKNOWN';
|
|
13
|
+
type CashErrorCode = 'ORACLE_UNSUPPORTED_CURRENCY' | 'ORACLE_READ_FAILED' | 'UNSUPPORTED_PLATFORM' | 'UNSUPPORTED_PLATFORM_CURRENCY' | 'AMOUNT_BELOW_MINIMUM' | 'INVALID_INTENT_AMOUNT_RANGE' | 'ACTIVE_INTENT_BLOCKS_WITHDRAWAL' | 'NOTHING_TO_WITHDRAW' | 'INSUFFICIENT_AVAILABLE_FUNDS' | 'INSUFFICIENT_TOKEN_BALANCE' | 'ORDER_NOT_ACTIVE' | 'INVALID_DEPOSIT_ID' | 'ESCROW_PAUSED' | 'INDEXER_LAG' | 'INDEXER_UNAVAILABLE' | 'ORDER_NOT_FOUND' | 'PAYEE_REGISTRATION_FAILED' | 'PAYEE_VERIFICATION_REQUIRED' | 'SOURCE_ROUTE_UNSUPPORTED_IN_PREPARE' | 'SOURCE_RECIPIENT_MISMATCH' | 'SOURCE_CAPABILITIES_FAILED' | 'SOURCE_QUOTE_FAILED' | 'SOURCE_NONCE_MANAGER_REQUIRED' | 'SOURCE_EXECUTION_FAILED' | 'SOURCE_STATUS_FAILED' | 'SOURCE_ROUTE_COMPLETED_CASHOUT_FAILED' | 'SOURCE_CASHOUT_SUBMISSION_UNKNOWN' | 'SOURCE_CASHOUT_STATUS_UNKNOWN' | 'DEPOSIT_RESOLUTION_FAILED' | 'ALLOWANCE_NOT_VISIBLE' | 'SIGNER_REQUIRED' | 'SIGNER_CHAIN_MISMATCH' | 'SIGNER_CHAIN_UNAVAILABLE' | 'WATCH_TIMEOUT' | 'TRANSACTION_FAILED' | 'TRANSACTION_SUBMISSION_UNKNOWN' | 'TRANSACTION_STATUS_UNKNOWN';
|
|
14
14
|
interface CashErrorShape {
|
|
15
15
|
code: CashErrorCode;
|
|
16
16
|
message: string;
|
|
@@ -92,6 +92,7 @@ declare const errors: {
|
|
|
92
92
|
sourceRecipientMismatch: (recipient: string, owner: string) => CashError;
|
|
93
93
|
sourceCapabilitiesFailed: (cause?: unknown) => CashError;
|
|
94
94
|
sourceQuoteFailed: (cause?: unknown) => CashError;
|
|
95
|
+
sourceNonceManagerRequired: (transactionCount: number) => CashError;
|
|
95
96
|
sourceExecutionFailed: (cause?: unknown, evidence?: {
|
|
96
97
|
requestId?: string;
|
|
97
98
|
txHashes: string[];
|
|
@@ -3153,7 +3154,7 @@ declare const cashErrorRecoveryJsonSchema: z.ZodDiscriminatedUnion<"kind", [z.Zo
|
|
|
3153
3154
|
operation: string;
|
|
3154
3155
|
}>]>;
|
|
3155
3156
|
declare const cashErrorJsonSchema: z.ZodObject<{
|
|
3156
|
-
code: z.ZodEnum<["ORACLE_UNSUPPORTED_CURRENCY", "ORACLE_READ_FAILED", "UNSUPPORTED_PLATFORM", "UNSUPPORTED_PLATFORM_CURRENCY", "AMOUNT_BELOW_MINIMUM", "INVALID_INTENT_AMOUNT_RANGE", "ACTIVE_INTENT_BLOCKS_WITHDRAWAL", "NOTHING_TO_WITHDRAW", "INSUFFICIENT_AVAILABLE_FUNDS", "INSUFFICIENT_TOKEN_BALANCE", "ORDER_NOT_ACTIVE", "INVALID_DEPOSIT_ID", "ESCROW_PAUSED", "INDEXER_LAG", "INDEXER_UNAVAILABLE", "ORDER_NOT_FOUND", "PAYEE_REGISTRATION_FAILED", "PAYEE_VERIFICATION_REQUIRED", "SOURCE_ROUTE_UNSUPPORTED_IN_PREPARE", "SOURCE_RECIPIENT_MISMATCH", "SOURCE_CAPABILITIES_FAILED", "SOURCE_QUOTE_FAILED", "SOURCE_EXECUTION_FAILED", "SOURCE_STATUS_FAILED", "SOURCE_ROUTE_COMPLETED_CASHOUT_FAILED", "SOURCE_CASHOUT_SUBMISSION_UNKNOWN", "SOURCE_CASHOUT_STATUS_UNKNOWN", "DEPOSIT_RESOLUTION_FAILED", "ALLOWANCE_NOT_VISIBLE", "SIGNER_REQUIRED", "SIGNER_CHAIN_MISMATCH", "SIGNER_CHAIN_UNAVAILABLE", "WATCH_TIMEOUT", "TRANSACTION_FAILED", "TRANSACTION_SUBMISSION_UNKNOWN", "TRANSACTION_STATUS_UNKNOWN"]>;
|
|
3157
|
+
code: z.ZodEnum<["ORACLE_UNSUPPORTED_CURRENCY", "ORACLE_READ_FAILED", "UNSUPPORTED_PLATFORM", "UNSUPPORTED_PLATFORM_CURRENCY", "AMOUNT_BELOW_MINIMUM", "INVALID_INTENT_AMOUNT_RANGE", "ACTIVE_INTENT_BLOCKS_WITHDRAWAL", "NOTHING_TO_WITHDRAW", "INSUFFICIENT_AVAILABLE_FUNDS", "INSUFFICIENT_TOKEN_BALANCE", "ORDER_NOT_ACTIVE", "INVALID_DEPOSIT_ID", "ESCROW_PAUSED", "INDEXER_LAG", "INDEXER_UNAVAILABLE", "ORDER_NOT_FOUND", "PAYEE_REGISTRATION_FAILED", "PAYEE_VERIFICATION_REQUIRED", "SOURCE_ROUTE_UNSUPPORTED_IN_PREPARE", "SOURCE_RECIPIENT_MISMATCH", "SOURCE_CAPABILITIES_FAILED", "SOURCE_QUOTE_FAILED", "SOURCE_NONCE_MANAGER_REQUIRED", "SOURCE_EXECUTION_FAILED", "SOURCE_STATUS_FAILED", "SOURCE_ROUTE_COMPLETED_CASHOUT_FAILED", "SOURCE_CASHOUT_SUBMISSION_UNKNOWN", "SOURCE_CASHOUT_STATUS_UNKNOWN", "DEPOSIT_RESOLUTION_FAILED", "ALLOWANCE_NOT_VISIBLE", "SIGNER_REQUIRED", "SIGNER_CHAIN_MISMATCH", "SIGNER_CHAIN_UNAVAILABLE", "WATCH_TIMEOUT", "TRANSACTION_FAILED", "TRANSACTION_SUBMISSION_UNKNOWN", "TRANSACTION_STATUS_UNKNOWN"]>;
|
|
3157
3158
|
message: z.ZodString;
|
|
3158
3159
|
retryable: z.ZodBoolean;
|
|
3159
3160
|
remediation: z.ZodString;
|
|
@@ -3540,7 +3541,7 @@ declare const cashErrorJsonSchema: z.ZodObject<{
|
|
|
3540
3541
|
}>]>>;
|
|
3541
3542
|
}, "strict", z.ZodTypeAny, {
|
|
3542
3543
|
message: string;
|
|
3543
|
-
code: "ORACLE_UNSUPPORTED_CURRENCY" | "ORACLE_READ_FAILED" | "UNSUPPORTED_PLATFORM" | "UNSUPPORTED_PLATFORM_CURRENCY" | "AMOUNT_BELOW_MINIMUM" | "INVALID_INTENT_AMOUNT_RANGE" | "ACTIVE_INTENT_BLOCKS_WITHDRAWAL" | "NOTHING_TO_WITHDRAW" | "INSUFFICIENT_AVAILABLE_FUNDS" | "INSUFFICIENT_TOKEN_BALANCE" | "ORDER_NOT_ACTIVE" | "INVALID_DEPOSIT_ID" | "ESCROW_PAUSED" | "INDEXER_LAG" | "INDEXER_UNAVAILABLE" | "ORDER_NOT_FOUND" | "PAYEE_REGISTRATION_FAILED" | "PAYEE_VERIFICATION_REQUIRED" | "SOURCE_ROUTE_UNSUPPORTED_IN_PREPARE" | "SOURCE_RECIPIENT_MISMATCH" | "SOURCE_CAPABILITIES_FAILED" | "SOURCE_QUOTE_FAILED" | "SOURCE_EXECUTION_FAILED" | "SOURCE_STATUS_FAILED" | "SOURCE_ROUTE_COMPLETED_CASHOUT_FAILED" | "SOURCE_CASHOUT_SUBMISSION_UNKNOWN" | "SOURCE_CASHOUT_STATUS_UNKNOWN" | "DEPOSIT_RESOLUTION_FAILED" | "ALLOWANCE_NOT_VISIBLE" | "SIGNER_REQUIRED" | "SIGNER_CHAIN_MISMATCH" | "SIGNER_CHAIN_UNAVAILABLE" | "WATCH_TIMEOUT" | "TRANSACTION_FAILED" | "TRANSACTION_SUBMISSION_UNKNOWN" | "TRANSACTION_STATUS_UNKNOWN";
|
|
3544
|
+
code: "ORACLE_UNSUPPORTED_CURRENCY" | "ORACLE_READ_FAILED" | "UNSUPPORTED_PLATFORM" | "UNSUPPORTED_PLATFORM_CURRENCY" | "AMOUNT_BELOW_MINIMUM" | "INVALID_INTENT_AMOUNT_RANGE" | "ACTIVE_INTENT_BLOCKS_WITHDRAWAL" | "NOTHING_TO_WITHDRAW" | "INSUFFICIENT_AVAILABLE_FUNDS" | "INSUFFICIENT_TOKEN_BALANCE" | "ORDER_NOT_ACTIVE" | "INVALID_DEPOSIT_ID" | "ESCROW_PAUSED" | "INDEXER_LAG" | "INDEXER_UNAVAILABLE" | "ORDER_NOT_FOUND" | "PAYEE_REGISTRATION_FAILED" | "PAYEE_VERIFICATION_REQUIRED" | "SOURCE_ROUTE_UNSUPPORTED_IN_PREPARE" | "SOURCE_RECIPIENT_MISMATCH" | "SOURCE_CAPABILITIES_FAILED" | "SOURCE_QUOTE_FAILED" | "SOURCE_NONCE_MANAGER_REQUIRED" | "SOURCE_EXECUTION_FAILED" | "SOURCE_STATUS_FAILED" | "SOURCE_ROUTE_COMPLETED_CASHOUT_FAILED" | "SOURCE_CASHOUT_SUBMISSION_UNKNOWN" | "SOURCE_CASHOUT_STATUS_UNKNOWN" | "DEPOSIT_RESOLUTION_FAILED" | "ALLOWANCE_NOT_VISIBLE" | "SIGNER_REQUIRED" | "SIGNER_CHAIN_MISMATCH" | "SIGNER_CHAIN_UNAVAILABLE" | "WATCH_TIMEOUT" | "TRANSACTION_FAILED" | "TRANSACTION_SUBMISSION_UNKNOWN" | "TRANSACTION_STATUS_UNKNOWN";
|
|
3544
3545
|
retryable: boolean;
|
|
3545
3546
|
remediation: string;
|
|
3546
3547
|
recovery?: {
|
|
@@ -3622,7 +3623,7 @@ declare const cashErrorJsonSchema: z.ZodObject<{
|
|
|
3622
3623
|
} | undefined;
|
|
3623
3624
|
}, {
|
|
3624
3625
|
message: string;
|
|
3625
|
-
code: "ORACLE_UNSUPPORTED_CURRENCY" | "ORACLE_READ_FAILED" | "UNSUPPORTED_PLATFORM" | "UNSUPPORTED_PLATFORM_CURRENCY" | "AMOUNT_BELOW_MINIMUM" | "INVALID_INTENT_AMOUNT_RANGE" | "ACTIVE_INTENT_BLOCKS_WITHDRAWAL" | "NOTHING_TO_WITHDRAW" | "INSUFFICIENT_AVAILABLE_FUNDS" | "INSUFFICIENT_TOKEN_BALANCE" | "ORDER_NOT_ACTIVE" | "INVALID_DEPOSIT_ID" | "ESCROW_PAUSED" | "INDEXER_LAG" | "INDEXER_UNAVAILABLE" | "ORDER_NOT_FOUND" | "PAYEE_REGISTRATION_FAILED" | "PAYEE_VERIFICATION_REQUIRED" | "SOURCE_ROUTE_UNSUPPORTED_IN_PREPARE" | "SOURCE_RECIPIENT_MISMATCH" | "SOURCE_CAPABILITIES_FAILED" | "SOURCE_QUOTE_FAILED" | "SOURCE_EXECUTION_FAILED" | "SOURCE_STATUS_FAILED" | "SOURCE_ROUTE_COMPLETED_CASHOUT_FAILED" | "SOURCE_CASHOUT_SUBMISSION_UNKNOWN" | "SOURCE_CASHOUT_STATUS_UNKNOWN" | "DEPOSIT_RESOLUTION_FAILED" | "ALLOWANCE_NOT_VISIBLE" | "SIGNER_REQUIRED" | "SIGNER_CHAIN_MISMATCH" | "SIGNER_CHAIN_UNAVAILABLE" | "WATCH_TIMEOUT" | "TRANSACTION_FAILED" | "TRANSACTION_SUBMISSION_UNKNOWN" | "TRANSACTION_STATUS_UNKNOWN";
|
|
3626
|
+
code: "ORACLE_UNSUPPORTED_CURRENCY" | "ORACLE_READ_FAILED" | "UNSUPPORTED_PLATFORM" | "UNSUPPORTED_PLATFORM_CURRENCY" | "AMOUNT_BELOW_MINIMUM" | "INVALID_INTENT_AMOUNT_RANGE" | "ACTIVE_INTENT_BLOCKS_WITHDRAWAL" | "NOTHING_TO_WITHDRAW" | "INSUFFICIENT_AVAILABLE_FUNDS" | "INSUFFICIENT_TOKEN_BALANCE" | "ORDER_NOT_ACTIVE" | "INVALID_DEPOSIT_ID" | "ESCROW_PAUSED" | "INDEXER_LAG" | "INDEXER_UNAVAILABLE" | "ORDER_NOT_FOUND" | "PAYEE_REGISTRATION_FAILED" | "PAYEE_VERIFICATION_REQUIRED" | "SOURCE_ROUTE_UNSUPPORTED_IN_PREPARE" | "SOURCE_RECIPIENT_MISMATCH" | "SOURCE_CAPABILITIES_FAILED" | "SOURCE_QUOTE_FAILED" | "SOURCE_NONCE_MANAGER_REQUIRED" | "SOURCE_EXECUTION_FAILED" | "SOURCE_STATUS_FAILED" | "SOURCE_ROUTE_COMPLETED_CASHOUT_FAILED" | "SOURCE_CASHOUT_SUBMISSION_UNKNOWN" | "SOURCE_CASHOUT_STATUS_UNKNOWN" | "DEPOSIT_RESOLUTION_FAILED" | "ALLOWANCE_NOT_VISIBLE" | "SIGNER_REQUIRED" | "SIGNER_CHAIN_MISMATCH" | "SIGNER_CHAIN_UNAVAILABLE" | "WATCH_TIMEOUT" | "TRANSACTION_FAILED" | "TRANSACTION_SUBMISSION_UNKNOWN" | "TRANSACTION_STATUS_UNKNOWN";
|
|
3626
3627
|
retryable: boolean;
|
|
3627
3628
|
remediation: string;
|
|
3628
3629
|
recovery?: {
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { MARKET_SPREAD_BPS, ORACLE_MIN_CONVERSION_RATE_SENTINEL, CASH_RETAIN_ON_EMPTY, BASE_USDC_ADDRESS, USDC_DECIMALS, BASE_CHAIN_ID, errors, isCashError, CASH_ORDER_STATUSES, mapChainError, CashError } from './chunk-
|
|
2
|
-
export { BASE_CHAIN_ID, BASE_USDC_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 } from './chunk-
|
|
1
|
+
import { MARKET_SPREAD_BPS, ORACLE_MIN_CONVERSION_RATE_SENTINEL, CASH_RETAIN_ON_EMPTY, BASE_USDC_ADDRESS, USDC_DECIMALS, BASE_CHAIN_ID, errors, isCashError, CASH_ORDER_STATUSES, mapChainError, CashError } from './chunk-TR6JVYYF.js';
|
|
2
|
+
export { BASE_CHAIN_ID, BASE_USDC_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 } from './chunk-TR6JVYYF.js';
|
|
3
3
|
import { parseAbi, parseEventLogs, isAddress, http, createWalletClient, encodeFunctionData } from 'viem';
|
|
4
4
|
import { base } from 'viem/chains';
|
|
5
5
|
import { getSpreadOracleConfig, currencyInfo, getPaymentMethodsCatalog, getGatingServiceAddress, resolvePaymentMethodHashFromCatalog, resolvePaymentMethodNameFromHash, getCurrencyCodeFromHash, createCompositeDepositId, appendAttributionToCalldata, Zkp2pClient, CHAINLINK_ORACLE_FEEDS } from '@zkp2p/sdk';
|
|
@@ -675,6 +675,14 @@ async function assertRelayExecutionIdentity(quote, wallet, expectedRecipient) {
|
|
|
675
675
|
throw new Error("Relay quote recipient does not match the expected Base recipient");
|
|
676
676
|
}
|
|
677
677
|
}
|
|
678
|
+
function assertRelayNonceManagement(quote, wallet) {
|
|
679
|
+
const account = wallet.account;
|
|
680
|
+
if (!account || account.type !== "local" || account.nonceManager !== void 0) return;
|
|
681
|
+
const transactionCount = quote.steps.flatMap(
|
|
682
|
+
(step) => step.items.filter((item) => asString(asRecord(item.data).to) !== void 0)
|
|
683
|
+
).length;
|
|
684
|
+
if (transactionCount > 1) throw errors.sourceNonceManagerRequired(transactionCount);
|
|
685
|
+
}
|
|
678
686
|
function isRelaySecretKey(key) {
|
|
679
687
|
const normalized = key.toLowerCase();
|
|
680
688
|
return normalized === "headers" || normalized === "apikey";
|
|
@@ -876,6 +884,7 @@ async function executeRelayQuote(quote, wallet, options = {}) {
|
|
|
876
884
|
observedRequestId = quoteRequestId(rawQuote);
|
|
877
885
|
assertCanonicalRelayDestination(rawQuote);
|
|
878
886
|
await assertRelayExecutionIdentity(rawQuote, wallet, options.recipient);
|
|
887
|
+
assertRelayNonceManagement(rawQuote, wallet);
|
|
879
888
|
const client = relayClient(options.relay);
|
|
880
889
|
const sourceChainId = quoteSourceChainId(rawQuote);
|
|
881
890
|
if (sourceChainId !== void 0 && !(client.chains ?? []).some((chain) => chain.id === sourceChainId)) {
|
|
@@ -1344,32 +1353,51 @@ function createCashClient(options) {
|
|
|
1344
1353
|
(transaction) => transaction.chainId === BASE_CHAIN_ID
|
|
1345
1354
|
);
|
|
1346
1355
|
const batchIds = baseTransactions.filter((transaction) => transaction.isBatchTx === true).map((transaction) => transaction.hash);
|
|
1356
|
+
const batchExecutionFailed = (cause) => errors.sourceExecutionFailed(cause, {
|
|
1357
|
+
...executed.requestId ? { requestId: executed.requestId } : {},
|
|
1358
|
+
txHashes: executed.txHashes,
|
|
1359
|
+
...executed.transactions ? { transactions: executed.transactions } : {}
|
|
1360
|
+
});
|
|
1347
1361
|
let batchTransactionHashes = [];
|
|
1348
1362
|
if (batchIds.length > 0) {
|
|
1349
1363
|
let batchError;
|
|
1350
1364
|
let batchesComplete = false;
|
|
1365
|
+
let batchesSucceededWithoutReceipts = false;
|
|
1351
1366
|
for (let attempt = 0; attempt < 20; attempt++) {
|
|
1352
1367
|
try {
|
|
1353
1368
|
const statuses = await Promise.all(
|
|
1354
1369
|
batchIds.map((id) => sourceSigner.getCallsStatus({ id }))
|
|
1355
1370
|
);
|
|
1356
1371
|
if (statuses.some((status) => status.status === "failure")) {
|
|
1357
|
-
throw new Error("Relay wallet call bundle failed");
|
|
1372
|
+
throw batchExecutionFailed(new Error("Relay wallet call bundle failed"));
|
|
1358
1373
|
}
|
|
1359
1374
|
if (statuses.every((status) => status.status === "success")) {
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1375
|
+
const receiptGroups = statuses.map((status) => status.receipts ?? []);
|
|
1376
|
+
if (receiptGroups.some((receipts) => receipts.length === 0)) {
|
|
1377
|
+
batchError = new Error(
|
|
1378
|
+
"Relay wallet call bundle did not include transaction receipts"
|
|
1379
|
+
);
|
|
1380
|
+
batchesSucceededWithoutReceipts = true;
|
|
1381
|
+
break;
|
|
1382
|
+
} else {
|
|
1383
|
+
batchTransactionHashes = receiptGroups.flatMap(
|
|
1384
|
+
(receipts) => receipts.map((receipt) => receipt.transactionHash)
|
|
1385
|
+
);
|
|
1386
|
+
batchesComplete = true;
|
|
1387
|
+
break;
|
|
1388
|
+
}
|
|
1365
1389
|
}
|
|
1366
1390
|
} catch (err) {
|
|
1391
|
+
if (isCashError(err)) throw err;
|
|
1367
1392
|
batchError = err;
|
|
1368
1393
|
}
|
|
1369
1394
|
await sleep(250);
|
|
1370
1395
|
}
|
|
1371
1396
|
if (!batchesComplete) {
|
|
1372
|
-
|
|
1397
|
+
if (batchesSucceededWithoutReceipts) throw batchError;
|
|
1398
|
+
throw batchExecutionFailed(
|
|
1399
|
+
batchError ?? new Error("Relay wallet call bundle did not complete")
|
|
1400
|
+
);
|
|
1373
1401
|
}
|
|
1374
1402
|
}
|
|
1375
1403
|
const hashes = [
|
|
@@ -1491,6 +1519,7 @@ function createCashClient(options) {
|
|
|
1491
1519
|
executed
|
|
1492
1520
|
);
|
|
1493
1521
|
} catch (err) {
|
|
1522
|
+
if (isCashError(err)) throw err;
|
|
1494
1523
|
throw errors.sourceRouteCompletedCashoutFailed(
|
|
1495
1524
|
routedSource,
|
|
1496
1525
|
mapChainError("resolve same-chain Relay nonce", err)
|
|
@@ -2166,6 +2195,7 @@ var CASH_ERROR_CODES = defineCashErrorCodes([
|
|
|
2166
2195
|
"SOURCE_RECIPIENT_MISMATCH",
|
|
2167
2196
|
"SOURCE_CAPABILITIES_FAILED",
|
|
2168
2197
|
"SOURCE_QUOTE_FAILED",
|
|
2198
|
+
"SOURCE_NONCE_MANAGER_REQUIRED",
|
|
2169
2199
|
"SOURCE_EXECUTION_FAILED",
|
|
2170
2200
|
"SOURCE_STATUS_FAILED",
|
|
2171
2201
|
"SOURCE_ROUTE_COMPLETED_CASHOUT_FAILED",
|
package/dist/react.js
CHANGED
package/dist/tools.cjs
CHANGED
package/dist/tools.js
CHANGED
|
@@ -36,6 +36,16 @@ For any other EVM source asset, Peer Cash uses `@relayprotocol/relay-sdk`:
|
|
|
36
36
|
`executeSourceQuote()` remains available for apps that want a separate
|
|
37
37
|
bridge step.
|
|
38
38
|
|
|
39
|
+
Routes that need more than one source-chain transaction (an ERC-20 `approve`,
|
|
40
|
+
then the route transaction) are submitted back-to-back by the Relay SDK. On a
|
|
41
|
+
plain local account the route transaction reuses the approval's nonce and
|
|
42
|
+
reverts mid-route, so `executeSourceQuote()` and `cashout({ source })` refuse
|
|
43
|
+
multi-transaction routes up front with `SOURCE_NONCE_MANAGER_REQUIRED` unless
|
|
44
|
+
the source signer carries a viem nonce manager:
|
|
45
|
+
`privateKeyToAccount(pk, { nonceManager })`. The check fires before anything
|
|
46
|
+
is submitted. Browser (`json-rpc`) wallets are unaffected - the node
|
|
47
|
+
allocates their nonces.
|
|
48
|
+
|
|
39
49
|
Cash-out interfaces should use `tradeType: 'EXACT_INPUT'` (also the default),
|
|
40
50
|
so `amount` always means source-token base units. A `RelayQuote.outputAmount`
|
|
41
51
|
is the guaranteed minimum Base USDC output. The same value becomes
|
|
@@ -62,10 +72,16 @@ destination constant.
|
|
|
62
72
|
|
|
63
73
|
Do not retry a source route merely because the Base cashout did not finish:
|
|
64
74
|
|
|
75
|
+
- `SOURCE_NONCE_MANAGER_REQUIRED` is preflight: nothing was submitted.
|
|
76
|
+
Recreate the source signer with viem's nonce manager and execute a fresh
|
|
77
|
+
quote.
|
|
65
78
|
- `SOURCE_EXECUTION_FAILED` means Relay execution did not report success. Check
|
|
66
79
|
its `inspect-relay-route` recovery evidence, submitted wallet transactions,
|
|
67
80
|
and `relayStatus(requestId)` before taking another action; a blind retry can
|
|
68
|
-
route twice.
|
|
81
|
+
route twice. A failed route whose only landed transaction is the approval
|
|
82
|
+
can sit in `relayStatus` `waiting` indefinitely - it never becomes terminal,
|
|
83
|
+
so decide from the persisted recovery payload and the origin transactions,
|
|
84
|
+
not from Relay reaching a final status.
|
|
69
85
|
- `SOURCE_ROUTE_COMPLETED_CASHOUT_FAILED` means Relay completed, but the Base
|
|
70
86
|
cashout was not created. Its recovery payload has
|
|
71
87
|
`kind: 'retry-base-usdc-cashout'`, the guaranteed Base USDC `amount`, Relay
|
|
@@ -132,7 +148,9 @@ UI built on this SDK is a bug in that UI.
|
|
|
132
148
|
- **Partial withdrawal** - `withdraw(depositId, { amount })` pulls part of
|
|
133
149
|
the _unlocked_ balance back out. A live buyer intent does not block it
|
|
134
150
|
(their locked portion is untouched); asking for more than the unlocked
|
|
135
|
-
balance fails with `INSUFFICIENT_AVAILABLE_FUNDS`.
|
|
151
|
+
balance fails with `INSUFFICIENT_AVAILABLE_FUNDS`. Accounting note: a
|
|
152
|
+
partial withdrawal increments `returnedAmount`; `totalAmount` records
|
|
153
|
+
everything the order has ever held and does not shrink.
|
|
136
154
|
- There is no retain-on-empty or rate knob to manage - a cash order cleans
|
|
137
155
|
itself up when fully filled, and the market rate is not configurable.
|
|
138
156
|
|
|
@@ -252,6 +270,7 @@ explicit override.
|
|
|
252
270
|
| `SOURCE_RECIPIENT_MISMATCH` | no | Relay output recipient differs from the cashout depositor. Use the depositor address. |
|
|
253
271
|
| `SOURCE_CAPABILITIES_FAILED` | yes | Relay source discovery failed. Retry or use Base USDC. |
|
|
254
272
|
| `SOURCE_QUOTE_FAILED` | yes | Relay returned no valid canonical Base-USDC route. Refresh capabilities and quote again. |
|
|
273
|
+
| `SOURCE_NONCE_MANAGER_REQUIRED` | no | Preflight; nothing was submitted. Recreate the source signer with viem's `nonceManager` and execute a fresh quote. |
|
|
255
274
|
| `SOURCE_EXECUTION_FAILED` | no | Route execution did not report success. Inspect source transactions and Relay status before retrying. |
|
|
256
275
|
| `SOURCE_STATUS_FAILED` | yes | Relay status is temporarily unavailable. Retry the status read without resubmitting. |
|
|
257
276
|
| `SOURCE_ROUTE_COMPLETED_CASHOUT_FAILED` | no | Relay completed but no Base cashout was created. Use the recovery amount for a Base-USDC-only retry; never repeat Relay. |
|
package/llms.txt
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
> Offramp-only SDK for the ZKP2P protocol: route any Relay-supported EVM source
|
|
4
4
|
> asset to Base USDC, then cash out to fiat (Venmo, Revolut, Wise, Zelle, ...)
|
|
5
5
|
> at the live Chainlink oracle market rate with zero spread and no centralized
|
|
6
|
-
> off-ramp provider. The user is the maker,
|
|
7
|
-
> SDK exposes readable order state.
|
|
6
|
+
> off-ramp provider. The user is the maker, a buyer pays them fiat and proves
|
|
7
|
+
> the payment, and the SDK exposes readable order state.
|
|
8
8
|
> Base-USDC flows are serializable through prepare paths; source-routed cashout
|
|
9
9
|
> uses Relay execution first. React apps, Node services, and agent hosts use the
|
|
10
10
|
> same typed surface.
|
|
@@ -59,9 +59,8 @@ Key facts:
|
|
|
59
59
|
|
|
60
60
|
## Links
|
|
61
61
|
|
|
62
|
-
- Live demo: https://react-cashout-demo.vercel.app
|
|
63
|
-
- Product page: https://peer.xyz/cash
|
|
64
62
|
- npm: https://www.npmjs.com/package/@zkp2p/cash
|
|
63
|
+
- Source: https://github.com/zkp2p/peer-cash
|
|
65
64
|
|
|
66
65
|
## Docs
|
|
67
66
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zkp2p/cash",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "Peer Cash - offramp-only SDK for routing crypto to Base USDC, then cashing out to fiat at the live oracle market rate.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Peer (https://peer.xyz)",
|
|
@@ -12,7 +12,14 @@
|
|
|
12
12
|
"publishConfig": {
|
|
13
13
|
"access": "public"
|
|
14
14
|
},
|
|
15
|
-
"homepage": "https://
|
|
15
|
+
"homepage": "https://github.com/zkp2p/peer-cash#readme",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/zkp2p/peer-cash.git"
|
|
19
|
+
},
|
|
20
|
+
"bugs": {
|
|
21
|
+
"url": "https://github.com/zkp2p/peer-cash/issues"
|
|
22
|
+
},
|
|
16
23
|
"keywords": [
|
|
17
24
|
"zkp2p",
|
|
18
25
|
"peer",
|
|
@@ -98,7 +105,7 @@
|
|
|
98
105
|
"dependencies": {
|
|
99
106
|
"@relayprotocol/relay-sdk": "^6.1.3",
|
|
100
107
|
"@zkp2p/sdk": "^0.8.1",
|
|
101
|
-
"zod": "^3.
|
|
108
|
+
"zod": "^3.25.76"
|
|
102
109
|
},
|
|
103
110
|
"peerDependencies": {
|
|
104
111
|
"react": ">=18",
|
|
@@ -110,19 +117,19 @@
|
|
|
110
117
|
}
|
|
111
118
|
},
|
|
112
119
|
"devDependencies": {
|
|
113
|
-
"@eslint/js": "^9.
|
|
114
|
-
"@types/node": "^22.
|
|
115
|
-
"@types/react": "^19.
|
|
120
|
+
"@eslint/js": "^9.39.5",
|
|
121
|
+
"@types/node": "^22.20.1",
|
|
122
|
+
"@types/react": "^19.2.17",
|
|
116
123
|
"@types/react-test-renderer": "19.1.0",
|
|
117
|
-
"eslint": "^9.
|
|
118
|
-
"eslint-config-prettier": "^9.1.
|
|
119
|
-
"prettier": "^3.
|
|
120
|
-
"react": "^19.
|
|
124
|
+
"eslint": "^9.39.5",
|
|
125
|
+
"eslint-config-prettier": "^9.1.2",
|
|
126
|
+
"prettier": "^3.9.5",
|
|
127
|
+
"react": "^19.2.7",
|
|
121
128
|
"react-test-renderer": "19.2.7",
|
|
122
|
-
"tsup": "^8.
|
|
123
|
-
"typescript": "^5.
|
|
124
|
-
"typescript-eslint": "^8.
|
|
125
|
-
"viem": "^2.55.
|
|
129
|
+
"tsup": "^8.5.1",
|
|
130
|
+
"typescript": "^5.9.3",
|
|
131
|
+
"typescript-eslint": "^8.63.0",
|
|
132
|
+
"viem": "^2.55.1",
|
|
126
133
|
"vitest": "^4.1.10"
|
|
127
134
|
}
|
|
128
135
|
}
|