@zkp2p/cash 0.1.1 → 0.1.3

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 CHANGED
@@ -1,10 +1,11 @@
1
1
  # @zkp2p/cash - agent integration manual
2
2
 
3
- You are integrating Peer Cash: an offramp that converts Base USDC to fiat
4
- (Venmo, Revolut, Wise, Zelle, ...) at the live Chainlink market rate. The user
5
- whose USDC you manage is the **maker**; a buyer pays them fiat and proves it
6
- with TEE-TLS; the protocol releases the USDC. Funds are held by the protocol,
7
- and only the maker can withdraw an unmatched deposit.
3
+ You are integrating Peer Cash: an offramp that routes any Relay-supported EVM
4
+ source asset into Base USDC, then converts Base USDC to fiat (Venmo, Revolut,
5
+ Wise, Zelle, ...) at the live Chainlink market rate. The user whose USDC you
6
+ manage is the **maker**; a buyer pays them fiat and proves it with TEE-TLS; the
7
+ protocol releases the USDC. Funds are held by the protocol, and only the maker
8
+ can withdraw an unmatched deposit.
8
9
 
9
10
  ## Decision tree: pick your entry point
10
11
 
@@ -17,8 +18,9 @@ and only the maker can withdraw an unmatched deposit.
17
18
  (`{ to, data, value, chainId }`) plus same-index `steps[]` labels; inspect
18
19
  the plan, submit the transactions in order, and wait for each receipt.
19
20
  3. **You are a tool-use host** (MCP server, CLI) → import the manifest from
20
- `@zkp2p/cash/tools` and map the tool names to the verbs above. Mutating
21
- tools return unsigned transactions; keep signing host-side.
21
+ `@zkp2p/cash/tools` and map the tool names to the verbs above. Base-USDC
22
+ mutating tools return unsigned transactions; source routing should use
23
+ `cash_source_quote` / `cash_source_status`, then a Base-USDC cashout.
22
24
 
23
25
  Every transaction (including approves) carries ERC-8021 attribution:
24
26
  `peer-cash`, then any `referrer` codes from `createCashClient` options, then
@@ -41,10 +43,12 @@ import { createCashClient, usdc, isCashError } from '@zkp2p/cash';
41
43
 
42
44
  const cash = createCashClient({ environment: 'production' });
43
45
 
44
- // 1. Discover - static and side-effect free, do this once.
46
+ // 1. Discover - Base USDC default path is sync.
45
47
  const caps = cash.capabilities();
48
+ // Optional: live Relay EVM source chains/tokens.
49
+ const relayCaps = await cash.capabilities({ includeRelaySources: true });
46
50
 
47
- // 2. Estimate - idempotent, cacheable, no side effects.
51
+ // 2. Estimate - idempotent, cacheable, no side effects. Includes rolling ETA.
48
52
  const est = await cash.estimate({ amount: usdc(500), currency: 'EUR' });
49
53
 
50
54
  // 3. Execute.
@@ -72,8 +76,13 @@ if (order.nextActions.includes('withdraw') && shouldUnwind) {
72
76
  - **Never promise a rate.** `estimate()` is `kind: 'oracle-estimate'`; the
73
77
  binding rate resolves at the oracle when a buyer fills. Do not display or
74
78
  log it as a locked price.
75
- - **Never invent an ETA.** Use `order.explain()` - one honest sentence from
76
- live data. Buyer arrival time is not knowable.
79
+ - **Do not invent an ETA.** Use `estimate().eta`: `{ seconds, label }` backed
80
+ by rolling 30-day indexer data from zero-spread (`spreadBps: 0`) market-rate
81
+ deposits in the same payout corridor, measured from deposit creation to first
82
+ fill. Use `order.explain()` for live order state.
83
+ - **Do not hardcode Relay source assets.** Use Relay SDK-backed EVM
84
+ `capabilities({ includeRelaySources: true })` and `cashout({ source, ... })`.
85
+ Destination is always Base USDC. Non-Base source chains require `sourceSigner`.
77
86
  - **`ORDER_NOT_FOUND` seconds after `cashout()` is indexer lag**, not a lost
78
87
  deposit. The tx receipt you hold is the truth. Retry; `watch()` absorbs
79
88
  this automatically.
@@ -93,25 +102,26 @@ if (order.nextActions.includes('withdraw') && shouldUnwind) {
93
102
 
94
103
  Every `CashError` carries `code`, `retryable`, `remediation`. Behavior:
95
104
 
96
- | Code | Retryable | Agent action |
97
- | --------------------------------- | --------- | ----------------------------------------------------------------------------------------------- |
98
- | `ORACLE_UNSUPPORTED_CURRENCY` | no | Re-pick currency from `capabilities()` |
99
- | `UNSUPPORTED_PLATFORM` | no | Re-pick platform from `capabilities()` |
100
- | `AMOUNT_BELOW_MINIMUM` | no | Raise amount (hard floor $0.01, recommended ≥ 1 USDC) |
101
- | `PAYEE_VERIFICATION_REQUIRED` | no | Wise/PayPal need a signed identity attestation - register the payee via the Peer app first |
102
- | `PAYEE_REGISTRATION_FAILED` | yes | Validate handle against `payeeHint`, retry with backoff (curator caps at 20 registrations/min) |
103
- | `ALLOWANCE_NOT_VISIBLE` | yes | Approve mined but a stale RPC replica hid it; retry the same call in a few seconds |
104
- | `TRANSACTION_FAILED` | no | The on-chain call reverted or was mapped from a raw error; surface to operator; funds unchanged |
105
- | `DEPOSIT_RESOLUTION_FAILED` | no | Extract depositId from the `DepositReceived` log in the receipt |
106
- | `ORDER_NOT_FOUND` | yes | Retry (indexer lag) unless the id is provably wrong |
107
- | `INDEXER_LAG` | yes | Retry after a few seconds |
108
- | `ACTIVE_INTENT_BLOCKS_WITHDRAWAL` | yes | Wait; retry full `withdraw()` after intent expiry (or withdraw the unlocked part with `amount`) |
109
- | `INSUFFICIENT_AVAILABLE_FUNDS` | yes | Partial amount exceeds the unlocked balance; lower it or close fully later |
110
- | `NOTHING_TO_WITHDRAW` | no | Order is terminal; reconcile your records |
111
- | `ORDER_NOT_ACTIVE` | no | Top-up target is closed; start a new `cashout()` instead |
112
- | `SIGNER_REQUIRED` | no | Provide `{ signer }` or switch to the prepare path |
113
- | `WATCH_TIMEOUT` | yes | Resume `watch(depositId)` whenever convenient |
114
- | `ESCROW_PAUSED` | yes | Back off; existing funds remain withdrawable |
105
+ | Code | Retryable | Agent action |
106
+ | ------------------------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------- |
107
+ | `ORACLE_UNSUPPORTED_CURRENCY` | no | Re-pick currency from `capabilities()` |
108
+ | `UNSUPPORTED_PLATFORM` | no | Re-pick platform from `capabilities()` |
109
+ | `AMOUNT_BELOW_MINIMUM` | no | Raise amount (hard floor $0.01, recommended ≥ 1 USDC) |
110
+ | `PAYEE_VERIFICATION_REQUIRED` | no | Wise/PayPal need a signed identity attestation - register the payee via the Peer app first |
111
+ | `SOURCE_ROUTE_UNSUPPORTED_IN_PREPARE` | no | Use signer-backed `cashout({ source })` with a source signer, or bridge with Relay first and then `prepare()` Base USDC |
112
+ | `PAYEE_REGISTRATION_FAILED` | yes | Validate handle against `payeeHint`, retry with backoff (curator caps at 20 registrations/min) |
113
+ | `ALLOWANCE_NOT_VISIBLE` | yes | Approve mined but a stale RPC replica hid it; retry the same call in a few seconds |
114
+ | `TRANSACTION_FAILED` | no | The on-chain call reverted or was mapped from a raw error; surface to operator; funds unchanged |
115
+ | `DEPOSIT_RESOLUTION_FAILED` | no | Extract depositId from the `DepositReceived` log in the receipt |
116
+ | `ORDER_NOT_FOUND` | yes | Retry (indexer lag) unless the id is provably wrong |
117
+ | `INDEXER_LAG` | yes | Retry after a few seconds |
118
+ | `ACTIVE_INTENT_BLOCKS_WITHDRAWAL` | yes | Wait; retry full `withdraw()` after intent expiry (or withdraw the unlocked part with `amount`) |
119
+ | `INSUFFICIENT_AVAILABLE_FUNDS` | yes | Partial amount exceeds the unlocked balance; lower it or close fully later |
120
+ | `NOTHING_TO_WITHDRAW` | no | Order is terminal; reconcile your records |
121
+ | `ORDER_NOT_ACTIVE` | no | Top-up target is closed; start a new `cashout()` instead |
122
+ | `SIGNER_REQUIRED` | no | Provide `{ signer }` or switch to the prepare path |
123
+ | `WATCH_TIMEOUT` | yes | Resume `watch(depositId)` whenever convenient |
124
+ | `ESCROW_PAUSED` | yes | Back off; existing funds remain withdrawable |
115
125
 
116
126
  `isCashError(err)` narrows unknown errors; `err.toJSON()` is safe for logs
117
127
  and tool results.
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # @zkp2p/cash
2
2
 
3
- Cash out Base USDC to fiat on Venmo, Revolut, Wise, Zelle, and more at the
4
- live Chainlink market rate, with zero spread and no centralized off-ramp
5
- provider.
3
+ Route any Relay-supported EVM source asset into Base USDC, then cash out to fiat
4
+ on Venmo, Revolut, Wise, Zelle, and more at the live Chainlink market rate,
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
8
  protocol. The cashing-out user is the maker: their USDC becomes a
@@ -18,7 +18,8 @@ import { createCashClient, usdc } from '@zkp2p/cash';
18
18
  const cash = createCashClient({ environment: 'production' });
19
19
 
20
20
  const est = await cash.estimate({ amount: usdc(1000), currency: 'USD' });
21
- // { rate: 1, receiveAmount: 1000, kind: 'oracle-estimate' } - "≈", never a locked quote
21
+ // { rate: 1, receiveAmount: 1000, kind: 'oracle-estimate', eta: { seconds, label } }
22
+ // "≈", never a locked quote. Base USDC remains the default source.
22
23
 
23
24
  const { depositId } = await cash.cashout(
24
25
  {
@@ -34,26 +35,53 @@ for await (const order of cash.watch(depositId)) {
34
35
  }
35
36
  ```
36
37
 
37
- ## The eight verbs
38
-
39
- | Verb | What it does |
40
- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------- |
41
- | `capabilities()` | Sync discovery: platforms × currencies × payee format hints × amount bounds |
42
- | `estimate({ amount, currency })` | Live oracle rate - no payee, no side effects, idempotent |
43
- | `cashout(input, { signer })` | Registers your payee, creates the protocol-held order, returns the `depositId` |
44
- | `order(depositId)` / `orders(owner)` | Resume any order from its id alone; list all orders for a wallet |
45
- | `watch(depositId)` | Async iterator: yields on every state change until terminal, abort, or timeout |
46
- | `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) |
47
- | `topUp(depositId, amount, { signer })` | Add USDC to a live order - same payee, same market rate |
48
- | `buyer(address)` | A buyer's track record from their intent history - who just matched your order? |
49
-
50
- Every mutating verb has an unsigned counterpart (`prepare`, `prepareWithdraw`,
51
- `prepareTopUp`). The unsigned path returns raw `txs[]` plus a same-index
52
- `steps[]` plan such as `approve`, `createDeposit`, or `withdrawDeposit`, so
53
- wallets, AA systems, and agents can show what each transaction does before
54
- signing. Every transaction - including approves - carries ERC-8021
55
- attribution: `peer-cash` first, your own `referrer` code(s) after it, so
56
- onchain analytics can segment cash flow end to end.
38
+ Source asset path:
39
+
40
+ ```ts
41
+ const { depositId, source } = await cash.cashout(
42
+ {
43
+ amount: 100000n, // source-token base units
44
+ source: { chainId: 1, currency: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48' },
45
+ receive: { platform: 'venmo', currency: 'USD', payee: { offchainId: '@you' } },
46
+ },
47
+ { signer, sourceSigner },
48
+ );
49
+ // source.amount is the Base USDC amount Relay delivered before the cash-out order.
50
+ ```
51
+
52
+ ## The core verbs
53
+
54
+ | Verb | What it does |
55
+ | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
56
+ | `capabilities()` | Sync discovery: Base USDC destination/default source, platforms × currencies × payee hints × amount bounds |
57
+ | `capabilities({ includeRelaySources: true })` | Async discovery: adds live Relay SDK EVM source chains/tokens |
58
+ | `quoteSource(input)` / `executeSourceQuote(quote, { signer })` | Relay SDK EVM source routing into Base USDC before cashout |
59
+ | `relayStatus(requestId)` | Relay request status from the Relay SDK request path |
60
+ | `estimate({ amount, currency })` | Base USDC oracle estimate plus simple recent-fill ETA |
61
+ | `cashout(input, { signer })` | Registers your payee, creates the protocol-held order, returns the `depositId` |
62
+ | `order(depositId)` / `orders(owner)` | Resume any order from its id alone; list all orders for a wallet |
63
+ | `watch(depositId)` | Async iterator: yields on every state change until terminal, abort, or timeout |
64
+ | `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) |
65
+ | `topUp(depositId, amount, { signer })` | Add USDC to a live order - same payee, same market rate |
66
+ | `buyer(address)` | A buyer's track record from their intent history - who just matched your order? |
67
+
68
+ Base-USDC cashout, withdraw, and top-up have unsigned counterparts (`prepare`,
69
+ `prepareWithdraw`, `prepareTopUp`). The unsigned path returns raw `txs[]` plus
70
+ a same-index `steps[]` plan such as `approve`, `createDeposit`, or
71
+ `withdrawDeposit`, so wallets, AA systems, and agents can show what each
72
+ transaction does before signing. Source-routed cashout runs Relay first, so it
73
+ uses the signed `cashout({ source }, { signer, sourceSigner })` path for
74
+ non-Base sources or an explicit `quoteSource()` / `executeSourceQuote()` pre-step. Every Peer Cash transaction
75
+ including approves carries ERC-8021 attribution: `peer-cash` first, your own
76
+ `referrer` code(s) after it.
77
+
78
+ The default/minimal flow is unchanged: pass Base USDC base units to
79
+ `estimate()` and `cashout()`. For any other source asset, pass `source` to
80
+ `cashout()` with a source-chain signer and the SDK first executes the Relay route into Base USDC, then
81
+ creates the Peer Cash order. The destination is always canonical Base USDC
82
+ (`8453:0x833589fcd6edb6e08f4c7c32d4f71b54bda02913`); source support is
83
+ discovered and quoted by `@relayprotocol/relay-sdk`, not a static token
84
+ allowlist.
57
85
 
58
86
  `capabilities()` tells you which platforms need a verified identity to
59
87
  register a payee (`requiresIdentityAttestation` - Wise and PayPal today); a
@@ -76,6 +104,10 @@ awaiting-buyer ──────────► matched ───────
76
104
  - **There is no quote.** The binding rate resolves at the oracle when a buyer
77
105
  fills. `estimate()` says "approximately"; nothing in this API pretends to
78
106
  lock a price.
107
+ - **ETA is historical.** `estimate().eta` is just `{ seconds, label }`, backed
108
+ by rolling 30-day indexer data from zero-spread (`spreadBps: 0`) market-rate
109
+ deposits in the same payout corridor, measured from deposit creation to first
110
+ fulfilled fill.
79
111
  - **Everything is resumable.** An order is reconstructed from the chain by
80
112
  `depositId` alone. Close the tab, switch devices, crash the process - then
81
113
  call `order(depositId)`.
@@ -116,8 +148,9 @@ React is an optional peer dependency - the root entry never imports it.
116
148
  ## Environments
117
149
 
118
150
  `production` | `preproduction` | `staging` - selects contracts, curator, and
119
- indexer. Indexer and curator URLs are overridable via `createCashClient`
120
- options. v1 is same-chain only: Base USDC in.
151
+ indexer. Indexer, curator, and Relay options are overridable via
152
+ `createCashClient` options. Base USDC on Base is the default source and the
153
+ only destination asset for cashout orders.
121
154
 
122
155
  ## Install
123
156
 
@@ -111,6 +111,18 @@ var errors = {
111
111
  },
112
112
  { cause }
113
113
  ),
114
+ sourceRouteUnsupportedInPrepare: () => new CashError({
115
+ code: "SOURCE_ROUTE_UNSUPPORTED_IN_PREPARE",
116
+ message: `prepare() cannot execute a Relay source route before creating the Base USDC cash-out.`,
117
+ retryable: false,
118
+ remediation: `Use cashout(inputWithSource, { signer }) for the one-call bridge-then-cashout flow, or call quoteSource()/executeSourceQuote() first and then prepare() a Base USDC cash-out.`
119
+ }),
120
+ sourceRecipientMismatch: (recipient, owner) => new CashError({
121
+ code: "SOURCE_RECIPIENT_MISMATCH",
122
+ message: `Source recipient ${recipient} does not match the cash-out depositor ${owner}.`,
123
+ retryable: false,
124
+ remediation: `For one-call source cashout, deliver Relay output to the depositor address. For a different recipient, bridge first and then cash out from that recipient's signer.`
125
+ }),
114
126
  allowanceNotVisible: (amount) => new CashError({
115
127
  code: "ALLOWANCE_NOT_VISIBLE",
116
128
  message: `USDC approval for ${amount} base units did not become visible on the read path in time.`,
@@ -172,5 +184,5 @@ function mapChainError(verb, err) {
172
184
  }
173
185
 
174
186
  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, mapChainError };
175
- //# sourceMappingURL=chunk-4DRZRWWS.js.map
176
- //# sourceMappingURL=chunk-4DRZRWWS.js.map
187
+ //# sourceMappingURL=chunk-FKVPZVFH.js.map
188
+ //# sourceMappingURL=chunk-FKVPZVFH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/engine/constants.ts","../src/client/errors.ts"],"names":[],"mappings":"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","file":"chunk-FKVPZVFH.js","sourcesContent":["/**\n * Peer Cash - engine constants.\n *\n * Peer Cash is an async crypto→fiat offramp built on the maker/deposit side of\n * the protocol: the cashing-out user IS the maker. They create a deposit at the\n * live oracle/market rate (0% spread); a buyer (a standard taker) signals an\n * intent, pays fiat, and proves it via the standard TEE-TLS flow, releasing the\n * user's crypto. The protocol is reused in its existing direction - no proof\n * inversion, no sell-side quote.\n */\nimport type { IntentStatus } from '../sdk-types';\n\n/** Base chain id - Peer Cash settles in Base USDC. */\nexport const BASE_CHAIN_ID = 8453;\n\n/** Canonical USDC on Base (6 decimals). The deposit asset for every cash-out. */\nexport const BASE_USDC_ADDRESS = '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913' as const;\n\n/** USDC has 6 decimals. */\nexport const USDC_DECIMALS = 6;\n\n/**\n * Market rate = the live Chainlink oracle with **zero spread**. The user sets no\n * rate; selling at market is the fast-fill incentive (the deposit is the best\n * deal on the book, so buyers have reason to take it quickly).\n */\nexport const MARKET_SPREAD_BPS = 0;\n\n/**\n * EscrowV2 rejects a zero `minConversionRate` even when an oracle-backed rate\n * config is attached. Use the smallest non-zero sentinel so the oracle rate\n * still fully determines pricing while satisfying the on-chain invariant.\n */\nexport const ORACLE_MIN_CONVERSION_RATE_SENTINEL = 1n;\n\n/**\n * The full intent-status set a cash-out order can pass through. The indexer's\n * `getIntentsForDeposits` defaults to `['SIGNALED']` only - passing this\n * explicit set is REQUIRED, otherwise `delivered`/`returned` states are\n * silently filtered out.\n */\nexport const CASH_ORDER_STATUSES: IntentStatus[] = [\n 'SIGNALED',\n 'FULFILLED',\n 'PRUNED',\n 'MANUALLY_RELEASED',\n];\n\n/** Default polling cadence for an in-flight order (ms). Matches the protocol's active-intent polling. */\nexport const CASH_ORDER_POLL_INTERVAL_MS = 5_000;\n\n/**\n * Default deposit config for every Peer Cash deposit: a one-shot cash-out\n * cleans up when fully filled rather than lingering empty.\n */\nexport const CASH_RETAIN_ON_EMPTY = false;\n","/**\n * Typed errors - every failure carries a `code`, whether it is `retryable`,\n * and a `remediation` sentence so agents can self-drive recovery.\n */\nexport type CashErrorCode =\n | 'ORACLE_UNSUPPORTED_CURRENCY'\n | 'UNSUPPORTED_PLATFORM'\n | 'AMOUNT_BELOW_MINIMUM'\n | 'ACTIVE_INTENT_BLOCKS_WITHDRAWAL'\n | 'NOTHING_TO_WITHDRAW'\n | 'INSUFFICIENT_AVAILABLE_FUNDS'\n | 'ORDER_NOT_ACTIVE'\n | 'ESCROW_PAUSED'\n | 'INDEXER_LAG'\n | 'ORDER_NOT_FOUND'\n | 'PAYEE_REGISTRATION_FAILED'\n | 'PAYEE_VERIFICATION_REQUIRED'\n | 'SOURCE_ROUTE_UNSUPPORTED_IN_PREPARE'\n | 'SOURCE_RECIPIENT_MISMATCH'\n | 'DEPOSIT_RESOLUTION_FAILED'\n | 'ALLOWANCE_NOT_VISIBLE'\n | 'SIGNER_REQUIRED'\n | 'WATCH_TIMEOUT'\n | 'TRANSACTION_FAILED';\n\nexport interface CashErrorShape {\n code: CashErrorCode;\n message: string;\n retryable: boolean;\n remediation: string;\n}\n\nexport class CashError extends Error implements CashErrorShape {\n readonly code: CashErrorCode;\n readonly retryable: boolean;\n readonly remediation: string;\n\n constructor(shape: CashErrorShape, options?: { cause?: unknown }) {\n super(shape.message, options);\n this.name = 'CashError';\n this.code = shape.code;\n this.retryable = shape.retryable;\n this.remediation = shape.remediation;\n }\n\n /** Serializable view (for tool results and logs). */\n toJSON(): CashErrorShape {\n return {\n code: this.code,\n message: this.message,\n retryable: this.retryable,\n remediation: this.remediation,\n };\n }\n}\n\nexport function isCashError(value: unknown): value is CashError {\n return value instanceof CashError;\n}\n\n/** Factory helpers keep call sites one-liners and remediation copy consistent. */\nexport const errors = {\n oracleUnsupportedCurrency: (currency: string) =>\n new CashError({\n code: 'ORACLE_UNSUPPORTED_CURRENCY',\n message: `${currency} has no live Chainlink oracle feed; Peer Cash is market-rate only.`,\n retryable: false,\n remediation: `Pick a currency listed in capabilities() - each one is priced by a live oracle feed.`,\n }),\n unsupportedPlatform: (platform: string) =>\n new CashError({\n code: 'UNSUPPORTED_PLATFORM',\n message: `'${platform}' is not a supported payout platform in this environment.`,\n retryable: false,\n remediation: `Pick a platform listed in capabilities().`,\n }),\n amountBelowMinimum: (amount: bigint, min: bigint) =>\n new CashError({\n code: 'AMOUNT_BELOW_MINIMUM',\n message: `Amount ${amount} is below the minimum cash-out of ${min} USDC base units.`,\n retryable: false,\n remediation: `Increase the amount to at least ${min} base units (${Number(min) / 1e6} USDC).`,\n }),\n activeIntentBlocksWithdrawal: (depositId: string) =>\n new CashError({\n code: 'ACTIVE_INTENT_BLOCKS_WITHDRAWAL',\n message: `Order ${depositId} has a live buyer intent; escrow blocks withdrawal while a buyer may still deliver.`,\n retryable: true,\n remediation: `Wait for the buyer to complete or for their intent to expire, then call withdraw() again - it prunes expired intents automatically.`,\n }),\n insufficientAvailableFunds: (depositId: string, requested: bigint, available: bigint) =>\n new CashError({\n code: 'INSUFFICIENT_AVAILABLE_FUNDS',\n message: `Order ${depositId} has ${available} base units available; ${requested} requested.`,\n retryable: true,\n remediation: `Withdraw at most the available (unlocked) amount, or omit the amount to close the order fully once no buyer intent is live.`,\n }),\n orderNotActive: (depositId: string) =>\n new CashError({\n code: 'ORDER_NOT_ACTIVE',\n message: `Order ${depositId} is closed (delivered or returned); it cannot be topped up.`,\n retryable: false,\n remediation: `Start a new cash-out with cashout() instead.`,\n }),\n nothingToWithdraw: (depositId: string) =>\n new CashError({\n code: 'NOTHING_TO_WITHDRAW',\n message: `Order ${depositId} holds no withdrawable funds (already delivered or returned).`,\n retryable: false,\n remediation: `Check order(depositId).state - this order is terminal.`,\n }),\n indexerLag: (depositId: string) =>\n new CashError({\n code: 'INDEXER_LAG',\n message: `Order ${depositId} is not indexed yet (the deposit may be seconds old).`,\n retryable: true,\n remediation: `Retry in a few seconds; on-chain state is ahead of the indexer right after a transaction.`,\n }),\n orderNotFound: (depositId: string) =>\n new CashError({\n code: 'ORDER_NOT_FOUND',\n message: `No deposit found for id ${depositId}.`,\n retryable: true,\n remediation: `Verify the composite depositId (escrow_onchainId). If the deposit was created seconds ago this is indexer lag - retry shortly.`,\n }),\n payeeRegistrationFailed: (cause: unknown) =>\n new CashError(\n {\n code: 'PAYEE_REGISTRATION_FAILED',\n message: `Registering payee details with the curator failed.`,\n retryable: true,\n remediation: `Check the payee handle format for the platform (see capabilities() hints) and retry.`,\n },\n { cause },\n ),\n payeeVerificationRequired: (platform: string, cause?: unknown) =>\n new CashError(\n {\n code: 'PAYEE_VERIFICATION_REQUIRED',\n message: `${platform} requires a verified maker identity attestation to register a payee; a bare handle is not accepted.`,\n retryable: false,\n remediation: `Register this ${platform} payee through the ZKP2P app / extension (which produces the signed identity attestation) before cashing out. capabilities() flags such platforms with requiresIdentityAttestation: true.`,\n },\n { cause },\n ),\n sourceRouteUnsupportedInPrepare: () =>\n new CashError({\n code: 'SOURCE_ROUTE_UNSUPPORTED_IN_PREPARE',\n message: `prepare() cannot execute a Relay source route before creating the Base USDC cash-out.`,\n retryable: false,\n remediation: `Use cashout(inputWithSource, { signer }) for the one-call bridge-then-cashout flow, or call quoteSource()/executeSourceQuote() first and then prepare() a Base USDC cash-out.`,\n }),\n sourceRecipientMismatch: (recipient: string, owner: string) =>\n new CashError({\n code: 'SOURCE_RECIPIENT_MISMATCH',\n message: `Source recipient ${recipient} does not match the cash-out depositor ${owner}.`,\n retryable: false,\n remediation: `For one-call source cashout, deliver Relay output to the depositor address. For a different recipient, bridge first and then cash out from that recipient's signer.`,\n }),\n allowanceNotVisible: (amount: bigint) =>\n new CashError({\n code: 'ALLOWANCE_NOT_VISIBLE',\n message: `USDC approval for ${amount} base units did not become visible on the read path in time.`,\n retryable: true,\n remediation: `The approve transaction mined but a load-balanced RPC is serving stale state. Retry the same call in a few seconds.`,\n }),\n depositResolutionFailed: (txHash: string) =>\n new CashError({\n code: 'DEPOSIT_RESOLUTION_FAILED',\n message: `Deposit transaction ${txHash} succeeded but no DepositReceived event was found in the receipt.`,\n retryable: false,\n remediation: `Inspect the transaction on Basescan; recover the depositId from the DepositReceived log manually, then resume with order(depositId).`,\n }),\n signerRequired: (verb: string) =>\n new CashError({\n code: 'SIGNER_REQUIRED',\n message: `${verb}() mutates on-chain state and needs a signer.`,\n retryable: false,\n remediation: `Pass { signer } (a viem WalletClient with an account), or use prepare() and submit the returned txs with your own signing infrastructure.`,\n }),\n watchTimeout: (depositId: string, timeoutMs: number) =>\n new CashError({\n code: 'WATCH_TIMEOUT',\n message: `watch(${depositId}) exceeded ${timeoutMs}ms without reaching a terminal state.`,\n retryable: true,\n remediation: `The order is still live - resume any time with watch(depositId) or order(depositId).`,\n }),\n transactionFailed: (txHash: string, cause?: unknown) =>\n new CashError(\n {\n code: 'TRANSACTION_FAILED',\n message: `Transaction ${txHash} reverted.`,\n retryable: false,\n remediation: `Inspect the transaction on Basescan; the deposit state is unchanged if the revert happened before escrow accepted funds.`,\n },\n { cause },\n ),\n escrowPaused: () =>\n new CashError({\n code: 'ESCROW_PAUSED',\n message: `The escrow contract is paused; deposits are temporarily disabled.`,\n retryable: true,\n remediation: `Wait for the protocol to unpause and retry. Existing funds remain withdrawable.`,\n }),\n /** Generic fallback for an on-chain call that failed for an unrecognized reason. */\n chainCallFailed: (verb: string, cause?: unknown) =>\n new CashError(\n {\n code: 'TRANSACTION_FAILED',\n message: `The on-chain ${verb} call failed.`,\n retryable: false,\n remediation: `Inspect the error cause and the wallet on Basescan. Deposit state is unchanged if the call reverted before escrow accepted funds.`,\n },\n { cause },\n ),\n};\n\n/**\n * Map a raw SDK/RPC/viem error from a mutating on-chain call to a typed\n * `CashError`, so the package's error contract holds even when the underlying\n * call reverts. Recognized reverts get specific codes; everything else falls\n * back to a wrapped `TRANSACTION_FAILED` (never a raw error to the consumer).\n */\nexport function mapChainError(verb: string, err: unknown): CashError {\n if (isCashError(err)) return err;\n const message = err instanceof Error ? err.message : String(err);\n if (/\\bpaused\\b/i.test(message)) return errors.escrowPaused();\n if (/exceeds allowance|insufficient allowance|transfer amount exceeds/i.test(message)) {\n return errors.allowanceNotVisible(0n);\n }\n return errors.chainCallFailed(verb, err);\n}\n"]}
@@ -1,5 +1,6 @@
1
1
  import { Address, WalletClient, Hash, Transport } from 'viem';
2
- import { IndexerIntentStatus, Zkp2pClient, IndexerIntent, CurrencyType, RuntimeEnv, PreparedTransaction } from '@zkp2p/sdk';
2
+ import { IndexerIntentStatus, Zkp2pClient, IndexerIntent, CurrencyType, PreparedTransaction, RuntimeEnv } from '@zkp2p/sdk';
3
+ import { Execute, RelayClient, RelayChain, ProgressData } from '@relayprotocol/relay-sdk';
3
4
 
4
5
  /**
5
6
  * Name-mapping shim over the published `@zkp2p/sdk` (^0.8).
@@ -201,6 +202,78 @@ interface CashDepositInput {
201
202
  };
202
203
  }
203
204
 
205
+ interface CashAsset {
206
+ chainId: number;
207
+ address: string;
208
+ symbol: string;
209
+ decimals: number;
210
+ name?: string;
211
+ isNative?: boolean;
212
+ }
213
+ interface CashChain {
214
+ id: number;
215
+ name: string;
216
+ displayName: string;
217
+ disabled: boolean;
218
+ depositEnabled: boolean;
219
+ blockProductionLagging: boolean;
220
+ vmType?: string;
221
+ tokens: CashAsset[];
222
+ }
223
+ interface CashSourceCapabilities {
224
+ destination: CashAsset;
225
+ chains: CashChain[];
226
+ source: 'relay-sdk';
227
+ asOf: number;
228
+ }
229
+ interface RelayOptions {
230
+ apiUrl?: string;
231
+ apiKey?: string;
232
+ source?: string;
233
+ client?: RelayClient;
234
+ chains?: RelayChain[];
235
+ }
236
+ interface RelaySourceInput {
237
+ chainId: number;
238
+ currency: string;
239
+ }
240
+ interface RelayQuoteInput {
241
+ user: string;
242
+ amount: bigint;
243
+ source: RelaySourceInput;
244
+ recipient?: string;
245
+ tradeType?: 'EXACT_INPUT' | 'EXACT_OUTPUT' | 'EXPECTED_OUTPUT';
246
+ }
247
+ interface RelayQuote {
248
+ requestId?: string;
249
+ source: CashAsset;
250
+ destination: CashAsset;
251
+ inputAmount: bigint;
252
+ outputAmount: bigint;
253
+ rate?: number;
254
+ timeEstimateSeconds?: number;
255
+ fees?: unknown;
256
+ txs: PreparedTransaction[];
257
+ raw: Execute;
258
+ }
259
+ interface RelayExecutionResult {
260
+ requestId?: string;
261
+ txHashes: string[];
262
+ quote: Execute;
263
+ }
264
+ interface RelayStatus {
265
+ requestId: string;
266
+ status: 'refund' | 'waiting' | 'depositing' | 'failure' | 'pending' | 'submitted' | 'success';
267
+ details?: string;
268
+ inTxHashes: string[];
269
+ txHashes: string[];
270
+ updatedAt?: number;
271
+ originChainId?: number;
272
+ destinationChainId?: number;
273
+ quoteCreatedAt?: number;
274
+ raw: unknown;
275
+ }
276
+
204
277
  /** Hard floor: below one cent a deposit is dust and can never fill. */
205
278
  declare const MIN_CASHOUT_AMOUNT = 10000n;
206
279
  /** Recommended floor: sub-1-USDC deposits force min==max fills and starve matching. */
@@ -228,6 +301,30 @@ interface CashCapabilities {
228
301
  decimals: number;
229
302
  };
230
303
  environment: RuntimeEnv;
304
+ /** Destination asset for every Peer Cash order. */
305
+ destination: {
306
+ chainId: number;
307
+ token: {
308
+ address: string;
309
+ symbol: 'USDC';
310
+ decimals: number;
311
+ };
312
+ };
313
+ /**
314
+ * Source discovery. The sync default is Base USDC only; pass
315
+ * `{ includeRelaySources: true }` to `capabilities()` for live Relay EVM sources.
316
+ */
317
+ source: {
318
+ default: {
319
+ chainId: number;
320
+ token: {
321
+ address: string;
322
+ symbol: 'USDC';
323
+ decimals: number;
324
+ };
325
+ };
326
+ relay?: CashSourceCapabilities;
327
+ };
231
328
  /** Every payout corridor: platform × oracle-priced currencies. */
232
329
  platforms: CashPlatformCapability[];
233
330
  /** All oracle-priced (market-rate) currencies across platforms. */
@@ -246,6 +343,13 @@ interface CashCapabilities {
246
343
  }
247
344
  declare function buildCapabilities(environment: RuntimeEnv): CashCapabilities;
248
345
 
346
+ interface CashFillEta {
347
+ /** Simple headline ETA from recent deposits. Undefined when no recent sample exists. */
348
+ seconds?: number;
349
+ /** Display-ready copy. Historical, not a guarantee. */
350
+ label: string;
351
+ }
352
+
249
353
  /**
250
354
  * Estimate - currency + amount only. No payee, no side effects, no expiry,
251
355
  * idempotent, cacheable. "≈ at whatever the oracle says when a buyer fills."
@@ -256,16 +360,26 @@ declare function buildCapabilities(environment: RuntimeEnv): CashCapabilities;
256
360
  */
257
361
 
258
362
  interface EstimateInput {
259
- /** Amount to cash out, USDC base units (6 decimals). Use `usdc()` to build it. */
363
+ /** Amount to cash out. Defaults to Base USDC base units; when `source` is set it is source-token base units. */
260
364
  amount: bigint;
261
365
  /** Target fiat currency. */
262
366
  currency: CurrencyType;
367
+ /** Optional payout platform for platform-specific fill ETA sampling. */
368
+ platform?: string;
369
+ /** Optional Relay EVM source asset. Omit for the current Base USDC default path. */
370
+ source?: RelaySourceInput & {
371
+ /** Source wallet that will submit Relay's origin transaction. Required by Relay quote. */
372
+ user: string;
373
+ /** Base recipient for bridged USDC; defaults to `user`. */
374
+ recipient?: string;
375
+ tradeType?: 'EXACT_INPUT' | 'EXACT_OUTPUT' | 'EXPECTED_OUTPUT';
376
+ };
263
377
  }
264
378
  interface CashEstimate {
265
379
  /** Always `'oracle-estimate'` - there is no committed quote in Peer Cash. */
266
380
  kind: 'oracle-estimate';
267
381
  currency: CurrencyType;
268
- /** The input amount, USDC base units. */
382
+ /** Base USDC amount that Peer Cash would deposit after any source routing. */
269
383
  amount: bigint;
270
384
  /** Target-currency units per 1 USDC at the time of the read. */
271
385
  rate: number;
@@ -277,6 +391,15 @@ interface CashEstimate {
277
391
  oracleUpdatedAt?: number;
278
392
  /** True when the feed reading is older than a day - treat the rate with caution. */
279
393
  stale?: boolean;
394
+ /** Optional source asset route. Absent means same-chain Base USDC. */
395
+ source?: {
396
+ kind: 'relay';
397
+ asset: CashAsset;
398
+ inputAmount: bigint;
399
+ relayQuote: RelayQuote;
400
+ };
401
+ /** Simple recent-fill ETA from indexer history. */
402
+ eta?: CashFillEta;
280
403
  }
281
404
 
282
405
  /**
@@ -310,6 +433,8 @@ interface CashClientOptions {
310
433
  curatorUrl?: string;
311
434
  /** Optional ZKP2P API key. */
312
435
  apiKey?: string;
436
+ /** Relay API configuration for source assets outside Base USDC. */
437
+ relay?: RelayOptions;
313
438
  /**
314
439
  * Your own ERC-8021 attribution code(s), appended after
315
440
  * {@link CASH_ATTRIBUTION_CODE} on every transaction (e.g. `'acme-app'`).
@@ -326,8 +451,17 @@ interface CashLeg {
326
451
  payee: CuratorPayeeDataInput;
327
452
  }
328
453
  interface CashoutInput {
329
- /** Amount to cash out, USDC base units. Use `usdc()` to build it. */
454
+ /**
455
+ * Amount to cash out. Defaults to Base USDC base units. When `source` is set,
456
+ * this is source-token base units and Relay routes it into Base USDC first.
457
+ */
330
458
  amount: bigint;
459
+ /** Optional Relay source asset. Omit for the Base USDC default path. */
460
+ source?: RelaySourceInput & {
461
+ /** Base recipient for bridged USDC; defaults to the signer address. */
462
+ recipient?: string;
463
+ tradeType?: 'EXACT_INPUT' | 'EXACT_OUTPUT' | 'EXPECTED_OUTPUT';
464
+ };
331
465
  /** Where the fiat should arrive. Multi-payout is a deliberate v1 cut. */
332
466
  receive: CashLeg;
333
467
  /** Per-order min/max override (USDC base units). */
@@ -340,6 +474,14 @@ interface SignerOptions {
340
474
  /** A viem WalletClient with an account, on Base. */
341
475
  signer: WalletClient;
342
476
  }
477
+ interface CashoutOptions extends SignerOptions {
478
+ /** Source-chain signer for Relay. Required when `input.source.chainId` is not Base. */
479
+ sourceSigner?: WalletClient;
480
+ /** Relay execution progress callback when `input.source` is present. */
481
+ onSourceProgress?: (data: ProgressData) => void;
482
+ /** Forwarded to Relay SDK for wallets with broken EIP-5792 capability calls. */
483
+ disableSourceCapabilitiesCheck?: boolean;
484
+ }
343
485
  interface WithdrawOptions extends SignerOptions {
344
486
  /**
345
487
  * Partial amount to withdraw (USDC base units). Only unlocked funds are
@@ -367,6 +509,12 @@ interface CashoutResult {
367
509
  onchainDepositId: bigint;
368
510
  /** Optimistic snapshot (`awaiting-buyer`); poll `order(depositId)` for live state. */
369
511
  order: CashOrder;
512
+ /** Present when `cashout()` first routed a source asset through Relay. */
513
+ source?: {
514
+ amount: bigint;
515
+ requestId?: string;
516
+ txHashes: string[];
517
+ };
370
518
  }
371
519
  interface PrepareResult {
372
520
  /**
@@ -402,10 +550,25 @@ interface OrdersOptions {
402
550
  interface CashClient {
403
551
  /** 0 - Discovery: sync, static. */
404
552
  capabilities(): CashCapabilities;
553
+ /** 0b - Discovery with live Relay-supported EVM source chains/tokens. */
554
+ capabilities(options: {
555
+ includeRelaySources: true;
556
+ }): Promise<CashCapabilities>;
557
+ /** Relay-only source discovery helper. */
558
+ sourceCapabilities(): Promise<CashSourceCapabilities>;
559
+ /** Quote any Relay-supported EVM source asset into Base USDC. */
560
+ quoteSource(input: RelayQuoteInput): Promise<RelayQuote>;
561
+ /** Execute a Relay SDK quote into Base USDC before starting the Peer Cash order. */
562
+ executeSourceQuote(quote: Execute, opts: SignerOptions & {
563
+ onProgress?: (data: ProgressData) => void;
564
+ disableCapabilitiesCheck?: boolean;
565
+ }): Promise<RelayExecutionResult>;
566
+ /** Track Relay execution status by quote/request id. */
567
+ relayStatus(requestId: string): Promise<RelayStatus>;
405
568
  /** 1 - Estimate: currency + amount only. No payee, no side effects, no expiry. */
406
569
  estimate(input: EstimateInput): Promise<CashEstimate>;
407
570
  /** 2 - Cash out: payee registration + deposit params + submission happen here. */
408
- cashout(input: CashoutInput, opts: SignerOptions): Promise<CashoutResult>;
571
+ cashout(input: CashoutInput, opts: CashoutOptions): Promise<CashoutResult>;
409
572
  /** 2b - Unsigned path: `txs[]` for agent wallets, AA, server keys, policy layers. */
410
573
  prepare(input: CashoutInput): Promise<PrepareResult>;
411
574
  /** 3 - Observe: resumable from `depositId` alone; no session state anywhere. */
@@ -446,4 +609,4 @@ interface CashClient {
446
609
  }
447
610
  declare function createCashClient(options: CashClientOptions): CashClient;
448
611
 
449
- export { type CashPayoutInfo as C, type EstimateInput as E, type IntentStatus as I, MIN_CASHOUT_AMOUNT as M, type OrdersOptions as O, type PrepareResult as P, RECOMMENDED_MIN_CASHOUT_AMOUNT as R, type SignerOptions as S, type TopUpResult as T, type WithdrawResult as W, type IntentEntity as a, type CashBuyerProfile as b, type CashDepositInput as c, type CreateDepositParamsArg as d, type CashOrder as e, type CashFill as f, type CashCapabilities as g, type CashoutResult as h, type CashEstimate as i, type CashPreparedStep as j, CASH_ATTRIBUTION_CODE as k, type CashClient as l, type CashClientOptions as m, type CashLeg as n, type CashNextAction as o, type CashOrderState as p, type CashPayout as q, type CashPayoutPricing as r, type CashPlatformCapability as s, type CashPreparedStepKind as t, type CashoutInput as u, type CuratorPayeeDataInput as v, type WatchOptions as w, type WithdrawOptions as x, buildCapabilities as y, createCashClient as z };
612
+ export { type CuratorPayeeDataInput as A, type RelayExecutionResult as B, type CashPayoutInfo as C, type RelayOptions as D, type EstimateInput as E, type RelayQuote as F, type RelayQuoteInput as G, type RelaySourceInput as H, type IntentStatus as I, type RelayStatus as J, type WatchOptions as K, type WithdrawOptions as L, MIN_CASHOUT_AMOUNT as M, buildCapabilities as N, type OrdersOptions as O, type PrepareResult as P, createCashClient as Q, RECOMMENDED_MIN_CASHOUT_AMOUNT as R, type SignerOptions as S, type TopUpResult as T, type WithdrawResult as W, type IntentEntity as a, type CashBuyerProfile as b, type CashDepositInput as c, type CreateDepositParamsArg as d, type CashOrder as e, type CashFill as f, type CashCapabilities as g, type CashoutResult as h, type CashEstimate as i, type CashPreparedStep as j, CASH_ATTRIBUTION_CODE as k, type CashAsset as l, type CashChain as m, type CashClient as n, type CashClientOptions as o, type CashFillEta as p, type CashLeg as q, type CashNextAction as r, type CashOrderState as s, type CashPayout as t, type CashPayoutPricing as u, type CashPlatformCapability as v, type CashPreparedStepKind as w, type CashSourceCapabilities as x, type CashoutInput as y, type CashoutOptions as z };