@zkp2p/cash 0.1.8 → 0.1.9
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 +6 -1
- package/README.md +12 -2
- package/dist/{createCashClient-BIzOLHjF.d.cts → createCashClient-BhOytyHE.d.cts} +9 -2
- package/dist/{createCashClient-BIzOLHjF.d.ts → createCashClient-BhOytyHE.d.ts} +9 -2
- package/dist/index.cjs +37 -11
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +37 -11
- package/dist/react.cjs +14 -10
- package/dist/react.d.cts +4 -2
- package/dist/react.d.ts +4 -2
- package/dist/react.js +14 -10
- package/dist/tools.cjs +1 -1
- package/dist/tools.js +1 -1
- package/docs/lifecycle-and-recovery.md +5 -0
- package/llms.txt +5 -0
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -54,6 +54,9 @@ const relayCaps = await cash.capabilities({ includeRelaySources: true });
|
|
|
54
54
|
// 2. Estimate - idempotent, cacheable, no side effects. Includes rolling ETA.
|
|
55
55
|
const est = await cash.estimate({ amount: usdc(500), currency: 'EUR' });
|
|
56
56
|
|
|
57
|
+
// Progressive UI: do not let indexer-backed history hold up the oracle rate.
|
|
58
|
+
const rateOnly = await cash.estimate({ amount: usdc(500), currency: 'EUR' }, { includeEta: false });
|
|
59
|
+
|
|
57
60
|
// Optional: raw demand + speed evidence per offered platform:currency pair.
|
|
58
61
|
const stats = await cash.fillStats();
|
|
59
62
|
|
|
@@ -106,7 +109,9 @@ console.log(routed.source?.transactions?.origin, routed.source?.transactions?.de
|
|
|
106
109
|
- **Do not invent an ETA.** Use `estimate().eta`: `{ seconds, label }` backed
|
|
107
110
|
by the same rolling 30-day, intent-attributed pair sample as `fillStats()`,
|
|
108
111
|
measured from deposit creation to first fill. Use `order.explain()` for live
|
|
109
|
-
order state.
|
|
112
|
+
order state. For progressive UIs, call `estimate(..., { includeEta: false })`
|
|
113
|
+
and load `fillStats()["platform:CURRENCY"]` separately. The SDK caches the
|
|
114
|
+
raw snapshot for 15 minutes, but never substitutes another pair's data.
|
|
110
115
|
- **Do not hardcode Relay source assets.** Use Relay SDK-backed EVM
|
|
111
116
|
`capabilities({ includeRelaySources: true })` and `cashout({ source, ... })`.
|
|
112
117
|
Destination is always Base USDC. Non-Base source chains require
|
package/README.md
CHANGED
|
@@ -34,6 +34,13 @@ const est = await cash.estimate({ amount: usdc(1000), currency: 'USD' });
|
|
|
34
34
|
// { rate: 1, receiveAmount: 1000, kind: 'oracle-estimate', eta: { seconds, label } }
|
|
35
35
|
// "≈", never a locked quote. Base USDC remains the default source.
|
|
36
36
|
|
|
37
|
+
// Progressive UI: render rate/receive first, then resolve the exact pair ETA.
|
|
38
|
+
const rateOnly = await cash.estimate(
|
|
39
|
+
{ amount: usdc(1000), currency: 'USD' },
|
|
40
|
+
{ includeEta: false },
|
|
41
|
+
);
|
|
42
|
+
const pairStats = (await cash.fillStats())['venmo:USD'];
|
|
43
|
+
|
|
37
44
|
const { depositId } = await cash.cashout(
|
|
38
45
|
{
|
|
39
46
|
amount: usdc(1000),
|
|
@@ -76,10 +83,10 @@ console.log(source?.transactions?.origin, source?.transactions?.destination);
|
|
|
76
83
|
| -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
|
77
84
|
| `capabilities()` | Sync discovery: Base USDC destination/default source, platforms × currencies × payee hints × amount bounds |
|
|
78
85
|
| `capabilities({ includeRelaySources: true })` | Async discovery: adds live Relay SDK EVM source chains/tokens |
|
|
79
|
-
| `fillStats()` |
|
|
86
|
+
| `fillStats()` | Cached 30-day fill counts and median first-fill time per exact `platform:currency` pair |
|
|
80
87
|
| `quoteSource(input)` / `executeSourceQuote(quote, { signer })` | Relay SDK EVM source routing into Base USDC before cashout |
|
|
81
88
|
| `relayStatus(requestId)` | Relay request status from the Relay SDK request path |
|
|
82
|
-
| `estimate({ amount, currency })`
|
|
89
|
+
| `estimate({ amount, currency }, { includeEta? })` | Base USDC oracle estimate; optionally skip the historical ETA for progressive rendering |
|
|
83
90
|
| `cashout(input, { signer })` | Registers your payee, creates the protocol-held order, returns the `depositId` |
|
|
84
91
|
| `order(depositId)` / `orders(owner)` | Resume any order from its id alone; list all orders for a wallet |
|
|
85
92
|
| `watch(depositId)` | Async iterator: yields on every state change until terminal, abort, or timeout |
|
|
@@ -180,6 +187,9 @@ awaiting-buyer ──────────► matched ───────
|
|
|
180
187
|
- **ETA is historical.** `estimate().eta` is just `{ seconds, label }`, backed
|
|
181
188
|
by the same rolling 30-day, intent-attributed pair sampler as `fillStats()`,
|
|
182
189
|
measured from deposit creation to the first fulfilled fill through the pair.
|
|
190
|
+
The raw snapshot is cached for 15 minutes per client and each ETA is still
|
|
191
|
+
resolved from its exact normalized `platform:currency` key. Use
|
|
192
|
+
`{ includeEta: false }` when rate and receive amount should render first.
|
|
183
193
|
- **Availability thresholds belong to the consumer.** `fillStats()` returns raw
|
|
184
194
|
evidence. A recommended gate is `fills >= 10 && medianFillSeconds <= 48h`.
|
|
185
195
|
Fail open to the full `capabilities()` catalog when stats are unavailable or
|
|
@@ -401,6 +401,13 @@ interface EstimateInput {
|
|
|
401
401
|
tradeType?: 'EXACT_INPUT' | 'EXACT_OUTPUT' | 'EXPECTED_OUTPUT';
|
|
402
402
|
};
|
|
403
403
|
}
|
|
404
|
+
interface EstimateOptions {
|
|
405
|
+
/**
|
|
406
|
+
* Include the historical indexer-backed ETA. Disable for progressive UIs
|
|
407
|
+
* that render the oracle rate first and load pair fill stats separately.
|
|
408
|
+
*/
|
|
409
|
+
includeEta?: boolean;
|
|
410
|
+
}
|
|
404
411
|
interface CashEstimate {
|
|
405
412
|
/** Always `'oracle-estimate'` - there is no committed quote in Peer Cash. */
|
|
406
413
|
kind: 'oracle-estimate';
|
|
@@ -612,7 +619,7 @@ interface CashClient {
|
|
|
612
619
|
/** Track Relay execution status by quote/request id. */
|
|
613
620
|
relayStatus(requestId: string): Promise<RelayStatus>;
|
|
614
621
|
/** 1 - Estimate: currency + amount only. No payee, no side effects, no expiry. */
|
|
615
|
-
estimate(input: EstimateInput): Promise<CashEstimate>;
|
|
622
|
+
estimate(input: EstimateInput, options?: EstimateOptions): Promise<CashEstimate>;
|
|
616
623
|
/** 2 - Cash out: payee registration + deposit params + submission happen here. */
|
|
617
624
|
cashout(input: CashoutInput, opts: CashoutOptions): Promise<CashoutResult>;
|
|
618
625
|
/** 2b - Unsigned path: `txs[]` for agent wallets, AA, server keys, policy layers. */
|
|
@@ -655,4 +662,4 @@ interface CashClient {
|
|
|
655
662
|
}
|
|
656
663
|
declare function createCashClient(options: CashClientOptions): CashClient;
|
|
657
664
|
|
|
658
|
-
export { type CashPlatformCapability as A, type CashPreparedStepKind as B, type CashPayoutInfo as C, type CashoutInput as D, type CashoutOptions as E, type CuratorPayeeDataInput as F, type EstimateInput as G,
|
|
665
|
+
export { type CashPlatformCapability as A, type CashPreparedStepKind as B, type CashPayoutInfo as C, type CashoutInput as D, type CashoutOptions as E, type CuratorPayeeDataInput as F, type EstimateInput as G, type EstimateOptions as H, type IntentStatus as I, RECOMMENDED_MIN_CASHOUT_AMOUNT as J, type RelayOptions as K, type RelayQuoteInput as L, MIN_CASHOUT_AMOUNT as M, type RelaySourceInput as N, type OrdersOptions as O, type PrepareResult as P, type RelayTransaction as Q, type RelayExecutionResult as R, type SignerOptions as S, type TopUpResult as T, type WatchOptions as U, type WithdrawOptions as V, type WithdrawResult as W, buildCapabilities as X, createCashClient as Y, 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 CashFillStats as j, type CashPreparedStep as k, type RelayQuote as l, type RelayStatus as m, type CashSourceCapabilities as n, CASH_ATTRIBUTION_CODE as o, type CashAsset as p, type CashChain as q, type CashClient as r, type CashClientOptions as s, type CashFillEta as t, type CashLeg as u, type CashNextAction as v, type CashOrderState as w, type CashPairFillStats as x, type CashPayout as y, type CashPayoutPricing as z };
|
|
@@ -401,6 +401,13 @@ interface EstimateInput {
|
|
|
401
401
|
tradeType?: 'EXACT_INPUT' | 'EXACT_OUTPUT' | 'EXPECTED_OUTPUT';
|
|
402
402
|
};
|
|
403
403
|
}
|
|
404
|
+
interface EstimateOptions {
|
|
405
|
+
/**
|
|
406
|
+
* Include the historical indexer-backed ETA. Disable for progressive UIs
|
|
407
|
+
* that render the oracle rate first and load pair fill stats separately.
|
|
408
|
+
*/
|
|
409
|
+
includeEta?: boolean;
|
|
410
|
+
}
|
|
404
411
|
interface CashEstimate {
|
|
405
412
|
/** Always `'oracle-estimate'` - there is no committed quote in Peer Cash. */
|
|
406
413
|
kind: 'oracle-estimate';
|
|
@@ -612,7 +619,7 @@ interface CashClient {
|
|
|
612
619
|
/** Track Relay execution status by quote/request id. */
|
|
613
620
|
relayStatus(requestId: string): Promise<RelayStatus>;
|
|
614
621
|
/** 1 - Estimate: currency + amount only. No payee, no side effects, no expiry. */
|
|
615
|
-
estimate(input: EstimateInput): Promise<CashEstimate>;
|
|
622
|
+
estimate(input: EstimateInput, options?: EstimateOptions): Promise<CashEstimate>;
|
|
616
623
|
/** 2 - Cash out: payee registration + deposit params + submission happen here. */
|
|
617
624
|
cashout(input: CashoutInput, opts: CashoutOptions): Promise<CashoutResult>;
|
|
618
625
|
/** 2b - Unsigned path: `txs[]` for agent wallets, AA, server keys, policy layers. */
|
|
@@ -655,4 +662,4 @@ interface CashClient {
|
|
|
655
662
|
}
|
|
656
663
|
declare function createCashClient(options: CashClientOptions): CashClient;
|
|
657
664
|
|
|
658
|
-
export { type CashPlatformCapability as A, type CashPreparedStepKind as B, type CashPayoutInfo as C, type CashoutInput as D, type CashoutOptions as E, type CuratorPayeeDataInput as F, type EstimateInput as G,
|
|
665
|
+
export { type CashPlatformCapability as A, type CashPreparedStepKind as B, type CashPayoutInfo as C, type CashoutInput as D, type CashoutOptions as E, type CuratorPayeeDataInput as F, type EstimateInput as G, type EstimateOptions as H, type IntentStatus as I, RECOMMENDED_MIN_CASHOUT_AMOUNT as J, type RelayOptions as K, type RelayQuoteInput as L, MIN_CASHOUT_AMOUNT as M, type RelaySourceInput as N, type OrdersOptions as O, type PrepareResult as P, type RelayTransaction as Q, type RelayExecutionResult as R, type SignerOptions as S, type TopUpResult as T, type WatchOptions as U, type WithdrawOptions as V, type WithdrawResult as W, buildCapabilities as X, createCashClient as Y, 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 CashFillStats as j, type CashPreparedStep as k, type RelayQuote as l, type RelayStatus as m, type CashSourceCapabilities as n, CASH_ATTRIBUTION_CODE as o, type CashAsset as p, type CashChain as q, type CashClient as r, type CashClientOptions as s, type CashFillEta as t, type CashLeg as u, type CashNextAction as v, type CashOrderState as w, type CashPairFillStats as x, type CashPayout as y, type CashPayoutPricing as z };
|
package/dist/index.cjs
CHANGED
|
@@ -959,11 +959,7 @@ async function readFillStatsSample(client, environment) {
|
|
|
959
959
|
}
|
|
960
960
|
return computeFillStatsSample(deposits, now, environment);
|
|
961
961
|
}
|
|
962
|
-
|
|
963
|
-
return (await readFillStatsSample(client, environment)).stats;
|
|
964
|
-
}
|
|
965
|
-
async function readFillEta(client, input) {
|
|
966
|
-
const sample = await readFillStatsSample(client, input.environment);
|
|
962
|
+
function fillEtaFromSample(sample, input) {
|
|
967
963
|
const currency = input.currency.toUpperCase();
|
|
968
964
|
const seconds = input.platform ? sample.stats[`${basePlatformForMethod(input.platform)}:${currency}`]?.medianFillSeconds : sample.medianFillSecondsByCurrency.get(currency);
|
|
969
965
|
return {
|
|
@@ -971,6 +967,10 @@ async function readFillEta(client, input) {
|
|
|
971
967
|
label: etaLabel(seconds)
|
|
972
968
|
};
|
|
973
969
|
}
|
|
970
|
+
async function readFillEta(client, input) {
|
|
971
|
+
const sample = await readFillStatsSample(client, input.environment);
|
|
972
|
+
return fillEtaFromSample(sample, input);
|
|
973
|
+
}
|
|
974
974
|
var RELAY_API_URL = relaySdk.MAINNET_RELAY_API;
|
|
975
975
|
var NATIVE_TOKEN_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
976
976
|
var BASE_USDC_ASSET = {
|
|
@@ -1506,13 +1506,18 @@ async function readEstimate(publicClient, input, context = {}) {
|
|
|
1506
1506
|
}
|
|
1507
1507
|
} : {}
|
|
1508
1508
|
};
|
|
1509
|
-
if (context.
|
|
1509
|
+
if (context.includeEta !== false && context.environment) {
|
|
1510
1510
|
try {
|
|
1511
|
-
|
|
1511
|
+
const etaInput = {
|
|
1512
1512
|
environment: context.environment,
|
|
1513
1513
|
currency,
|
|
1514
1514
|
...input.platform ? { platform: input.platform } : {}
|
|
1515
|
-
}
|
|
1515
|
+
};
|
|
1516
|
+
if (context.etaReader) {
|
|
1517
|
+
estimate.eta = await context.etaReader(etaInput);
|
|
1518
|
+
} else if (context.indexerClient) {
|
|
1519
|
+
estimate.eta = await readFillEta(context.indexerClient, etaInput);
|
|
1520
|
+
}
|
|
1516
1521
|
} catch {
|
|
1517
1522
|
}
|
|
1518
1523
|
}
|
|
@@ -1521,6 +1526,7 @@ async function readEstimate(publicClient, input, context = {}) {
|
|
|
1521
1526
|
|
|
1522
1527
|
// src/client/createCashClient.ts
|
|
1523
1528
|
var DEFAULT_RPC_URL = "https://mainnet.base.org";
|
|
1529
|
+
var FILL_STATS_CACHE_MS = 15 * 60 * 1e3;
|
|
1524
1530
|
var CASH_ATTRIBUTION_CODE = "peer-cash";
|
|
1525
1531
|
var DEFAULT_CURATOR_URLS = {
|
|
1526
1532
|
preproduction: "https://api-preprod.zkp2p.xyz",
|
|
@@ -1619,6 +1625,25 @@ function createCashClient(options) {
|
|
|
1619
1625
|
});
|
|
1620
1626
|
}
|
|
1621
1627
|
const readClient = buildSdkClient(viem.createWalletClient({ chain: chains.base, transport }));
|
|
1628
|
+
let fillStatsCache = null;
|
|
1629
|
+
let fillStatsRequest = null;
|
|
1630
|
+
async function getFillStatsSample() {
|
|
1631
|
+
if (fillStatsCache && fillStatsCache.expiresAt > Date.now()) {
|
|
1632
|
+
return fillStatsCache.sample;
|
|
1633
|
+
}
|
|
1634
|
+
if (fillStatsRequest) return fillStatsRequest;
|
|
1635
|
+
fillStatsRequest = readFillStatsSample(readClient, environment);
|
|
1636
|
+
try {
|
|
1637
|
+
const sample = await fillStatsRequest;
|
|
1638
|
+
fillStatsCache = {
|
|
1639
|
+
sample,
|
|
1640
|
+
expiresAt: Date.now() + FILL_STATS_CACHE_MS
|
|
1641
|
+
};
|
|
1642
|
+
return sample;
|
|
1643
|
+
} finally {
|
|
1644
|
+
fillStatsRequest = null;
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1622
1647
|
const signingClients = /* @__PURE__ */ new WeakMap();
|
|
1623
1648
|
async function signingClient(verb, opts) {
|
|
1624
1649
|
const signer = opts?.signer;
|
|
@@ -1921,16 +1946,17 @@ function createCashClient(options) {
|
|
|
1921
1946
|
async relayStatus(requestId) {
|
|
1922
1947
|
return readRelayStatus(requestId, options.relay);
|
|
1923
1948
|
},
|
|
1924
|
-
async estimate(input) {
|
|
1949
|
+
async estimate(input, estimateOptions) {
|
|
1925
1950
|
return readEstimate(readClient.publicClient, input, {
|
|
1926
|
-
indexerClient: readClient,
|
|
1927
1951
|
environment,
|
|
1952
|
+
...estimateOptions?.includeEta !== void 0 ? { includeEta: estimateOptions.includeEta } : {},
|
|
1953
|
+
etaReader: async (etaInput) => fillEtaFromSample(await getFillStatsSample(), etaInput),
|
|
1928
1954
|
...options.relay ? { relay: options.relay } : {}
|
|
1929
1955
|
});
|
|
1930
1956
|
},
|
|
1931
1957
|
async fillStats() {
|
|
1932
1958
|
try {
|
|
1933
|
-
return await
|
|
1959
|
+
return (await getFillStatsSample()).stats;
|
|
1934
1960
|
} catch (err) {
|
|
1935
1961
|
throw errors.indexerUnavailable("fill stats", err);
|
|
1936
1962
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { I as IntentStatus, C as CashPayoutInfo, a as IntentEntity, b as CashBuyerProfile, c as CashDepositInput, d as CreateDepositParamsArg, e as CashOrder, f as CashFill, g as CashCapabilities, h as CashoutResult, i as CashEstimate, j as CashFillStats, P as PrepareResult, k as CashPreparedStep, R as RelayExecutionResult, l as RelayQuote, m as RelayStatus, n as CashSourceCapabilities, T as TopUpResult, W as WithdrawResult } from './createCashClient-
|
|
2
|
-
export { o as CASH_ATTRIBUTION_CODE, p as CashAsset, q as CashChain, r as CashClient, s as CashClientOptions, t as CashFillEta, u as CashLeg, v as CashNextAction, w as CashOrderState, x as CashPairFillStats, y as CashPayout, z as CashPayoutPricing, A as CashPlatformCapability, B as CashPreparedStepKind, D as CashoutInput, E as CashoutOptions, F as CuratorPayeeDataInput, G as EstimateInput, M as MIN_CASHOUT_AMOUNT, O as OrdersOptions,
|
|
1
|
+
import { I as IntentStatus, C as CashPayoutInfo, a as IntentEntity, b as CashBuyerProfile, c as CashDepositInput, d as CreateDepositParamsArg, e as CashOrder, f as CashFill, g as CashCapabilities, h as CashoutResult, i as CashEstimate, j as CashFillStats, P as PrepareResult, k as CashPreparedStep, R as RelayExecutionResult, l as RelayQuote, m as RelayStatus, n as CashSourceCapabilities, T as TopUpResult, W as WithdrawResult } from './createCashClient-BhOytyHE.cjs';
|
|
2
|
+
export { o as CASH_ATTRIBUTION_CODE, p as CashAsset, q as CashChain, r as CashClient, s as CashClientOptions, t as CashFillEta, u as CashLeg, v as CashNextAction, w as CashOrderState, x as CashPairFillStats, y as CashPayout, z as CashPayoutPricing, A as CashPlatformCapability, B as CashPreparedStepKind, D as CashoutInput, E as CashoutOptions, F as CuratorPayeeDataInput, G as EstimateInput, H as EstimateOptions, M as MIN_CASHOUT_AMOUNT, O as OrdersOptions, J as RECOMMENDED_MIN_CASHOUT_AMOUNT, K as RelayOptions, L as RelayQuoteInput, N as RelaySourceInput, Q as RelayTransaction, S as SignerOptions, U as WatchOptions, V as WithdrawOptions, X as buildCapabilities, Y as createCashClient } from './createCashClient-BhOytyHE.cjs';
|
|
3
3
|
import { PaymentMethodCatalog, CurrencyType, OracleAdapterOverrides, OnchainCurrency, Zkp2pClient, PreparedTransaction } from '@zkp2p/sdk';
|
|
4
4
|
export { CurrencyType, PreparedTransaction, RuntimeEnv } from '@zkp2p/sdk';
|
|
5
5
|
import { Log, Abi } from 'viem';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { I as IntentStatus, C as CashPayoutInfo, a as IntentEntity, b as CashBuyerProfile, c as CashDepositInput, d as CreateDepositParamsArg, e as CashOrder, f as CashFill, g as CashCapabilities, h as CashoutResult, i as CashEstimate, j as CashFillStats, P as PrepareResult, k as CashPreparedStep, R as RelayExecutionResult, l as RelayQuote, m as RelayStatus, n as CashSourceCapabilities, T as TopUpResult, W as WithdrawResult } from './createCashClient-
|
|
2
|
-
export { o as CASH_ATTRIBUTION_CODE, p as CashAsset, q as CashChain, r as CashClient, s as CashClientOptions, t as CashFillEta, u as CashLeg, v as CashNextAction, w as CashOrderState, x as CashPairFillStats, y as CashPayout, z as CashPayoutPricing, A as CashPlatformCapability, B as CashPreparedStepKind, D as CashoutInput, E as CashoutOptions, F as CuratorPayeeDataInput, G as EstimateInput, M as MIN_CASHOUT_AMOUNT, O as OrdersOptions,
|
|
1
|
+
import { I as IntentStatus, C as CashPayoutInfo, a as IntentEntity, b as CashBuyerProfile, c as CashDepositInput, d as CreateDepositParamsArg, e as CashOrder, f as CashFill, g as CashCapabilities, h as CashoutResult, i as CashEstimate, j as CashFillStats, P as PrepareResult, k as CashPreparedStep, R as RelayExecutionResult, l as RelayQuote, m as RelayStatus, n as CashSourceCapabilities, T as TopUpResult, W as WithdrawResult } from './createCashClient-BhOytyHE.js';
|
|
2
|
+
export { o as CASH_ATTRIBUTION_CODE, p as CashAsset, q as CashChain, r as CashClient, s as CashClientOptions, t as CashFillEta, u as CashLeg, v as CashNextAction, w as CashOrderState, x as CashPairFillStats, y as CashPayout, z as CashPayoutPricing, A as CashPlatformCapability, B as CashPreparedStepKind, D as CashoutInput, E as CashoutOptions, F as CuratorPayeeDataInput, G as EstimateInput, H as EstimateOptions, M as MIN_CASHOUT_AMOUNT, O as OrdersOptions, J as RECOMMENDED_MIN_CASHOUT_AMOUNT, K as RelayOptions, L as RelayQuoteInput, N as RelaySourceInput, Q as RelayTransaction, S as SignerOptions, U as WatchOptions, V as WithdrawOptions, X as buildCapabilities, Y as createCashClient } from './createCashClient-BhOytyHE.js';
|
|
3
3
|
import { PaymentMethodCatalog, CurrencyType, OracleAdapterOverrides, OnchainCurrency, Zkp2pClient, PreparedTransaction } from '@zkp2p/sdk';
|
|
4
4
|
export { CurrencyType, PreparedTransaction, RuntimeEnv } from '@zkp2p/sdk';
|
|
5
5
|
import { Log, Abi } from 'viem';
|
package/dist/index.js
CHANGED
|
@@ -580,11 +580,7 @@ async function readFillStatsSample(client, environment) {
|
|
|
580
580
|
}
|
|
581
581
|
return computeFillStatsSample(deposits, now, environment);
|
|
582
582
|
}
|
|
583
|
-
|
|
584
|
-
return (await readFillStatsSample(client, environment)).stats;
|
|
585
|
-
}
|
|
586
|
-
async function readFillEta(client, input) {
|
|
587
|
-
const sample = await readFillStatsSample(client, input.environment);
|
|
583
|
+
function fillEtaFromSample(sample, input) {
|
|
588
584
|
const currency = input.currency.toUpperCase();
|
|
589
585
|
const seconds = input.platform ? sample.stats[`${basePlatformForMethod(input.platform)}:${currency}`]?.medianFillSeconds : sample.medianFillSecondsByCurrency.get(currency);
|
|
590
586
|
return {
|
|
@@ -592,6 +588,10 @@ async function readFillEta(client, input) {
|
|
|
592
588
|
label: etaLabel(seconds)
|
|
593
589
|
};
|
|
594
590
|
}
|
|
591
|
+
async function readFillEta(client, input) {
|
|
592
|
+
const sample = await readFillStatsSample(client, input.environment);
|
|
593
|
+
return fillEtaFromSample(sample, input);
|
|
594
|
+
}
|
|
595
595
|
var RELAY_API_URL = MAINNET_RELAY_API;
|
|
596
596
|
var NATIVE_TOKEN_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
597
597
|
var BASE_USDC_ASSET = {
|
|
@@ -1127,13 +1127,18 @@ async function readEstimate(publicClient, input, context = {}) {
|
|
|
1127
1127
|
}
|
|
1128
1128
|
} : {}
|
|
1129
1129
|
};
|
|
1130
|
-
if (context.
|
|
1130
|
+
if (context.includeEta !== false && context.environment) {
|
|
1131
1131
|
try {
|
|
1132
|
-
|
|
1132
|
+
const etaInput = {
|
|
1133
1133
|
environment: context.environment,
|
|
1134
1134
|
currency,
|
|
1135
1135
|
...input.platform ? { platform: input.platform } : {}
|
|
1136
|
-
}
|
|
1136
|
+
};
|
|
1137
|
+
if (context.etaReader) {
|
|
1138
|
+
estimate.eta = await context.etaReader(etaInput);
|
|
1139
|
+
} else if (context.indexerClient) {
|
|
1140
|
+
estimate.eta = await readFillEta(context.indexerClient, etaInput);
|
|
1141
|
+
}
|
|
1137
1142
|
} catch {
|
|
1138
1143
|
}
|
|
1139
1144
|
}
|
|
@@ -1142,6 +1147,7 @@ async function readEstimate(publicClient, input, context = {}) {
|
|
|
1142
1147
|
|
|
1143
1148
|
// src/client/createCashClient.ts
|
|
1144
1149
|
var DEFAULT_RPC_URL = "https://mainnet.base.org";
|
|
1150
|
+
var FILL_STATS_CACHE_MS = 15 * 60 * 1e3;
|
|
1145
1151
|
var CASH_ATTRIBUTION_CODE = "peer-cash";
|
|
1146
1152
|
var DEFAULT_CURATOR_URLS = {
|
|
1147
1153
|
preproduction: "https://api-preprod.zkp2p.xyz",
|
|
@@ -1240,6 +1246,25 @@ function createCashClient(options) {
|
|
|
1240
1246
|
});
|
|
1241
1247
|
}
|
|
1242
1248
|
const readClient = buildSdkClient(createWalletClient({ chain: base, transport }));
|
|
1249
|
+
let fillStatsCache = null;
|
|
1250
|
+
let fillStatsRequest = null;
|
|
1251
|
+
async function getFillStatsSample() {
|
|
1252
|
+
if (fillStatsCache && fillStatsCache.expiresAt > Date.now()) {
|
|
1253
|
+
return fillStatsCache.sample;
|
|
1254
|
+
}
|
|
1255
|
+
if (fillStatsRequest) return fillStatsRequest;
|
|
1256
|
+
fillStatsRequest = readFillStatsSample(readClient, environment);
|
|
1257
|
+
try {
|
|
1258
|
+
const sample = await fillStatsRequest;
|
|
1259
|
+
fillStatsCache = {
|
|
1260
|
+
sample,
|
|
1261
|
+
expiresAt: Date.now() + FILL_STATS_CACHE_MS
|
|
1262
|
+
};
|
|
1263
|
+
return sample;
|
|
1264
|
+
} finally {
|
|
1265
|
+
fillStatsRequest = null;
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1243
1268
|
const signingClients = /* @__PURE__ */ new WeakMap();
|
|
1244
1269
|
async function signingClient(verb, opts) {
|
|
1245
1270
|
const signer = opts?.signer;
|
|
@@ -1542,16 +1567,17 @@ function createCashClient(options) {
|
|
|
1542
1567
|
async relayStatus(requestId) {
|
|
1543
1568
|
return readRelayStatus(requestId, options.relay);
|
|
1544
1569
|
},
|
|
1545
|
-
async estimate(input) {
|
|
1570
|
+
async estimate(input, estimateOptions) {
|
|
1546
1571
|
return readEstimate(readClient.publicClient, input, {
|
|
1547
|
-
indexerClient: readClient,
|
|
1548
1572
|
environment,
|
|
1573
|
+
...estimateOptions?.includeEta !== void 0 ? { includeEta: estimateOptions.includeEta } : {},
|
|
1574
|
+
etaReader: async (etaInput) => fillEtaFromSample(await getFillStatsSample(), etaInput),
|
|
1549
1575
|
...options.relay ? { relay: options.relay } : {}
|
|
1550
1576
|
});
|
|
1551
1577
|
},
|
|
1552
1578
|
async fillStats() {
|
|
1553
1579
|
try {
|
|
1554
|
-
return await
|
|
1580
|
+
return (await getFillStatsSample()).stats;
|
|
1555
1581
|
} catch (err) {
|
|
1556
1582
|
throw errors.indexerUnavailable("fill stats", err);
|
|
1557
1583
|
}
|
package/dist/react.cjs
CHANGED
|
@@ -9,6 +9,7 @@ function useEstimate({
|
|
|
9
9
|
currency,
|
|
10
10
|
platform,
|
|
11
11
|
source,
|
|
12
|
+
includeEta = true,
|
|
12
13
|
refreshIntervalMs = 0
|
|
13
14
|
}) {
|
|
14
15
|
const [estimate, setEstimate] = react.useState(null);
|
|
@@ -34,7 +35,7 @@ function useEstimate({
|
|
|
34
35
|
}
|
|
35
36
|
return;
|
|
36
37
|
}
|
|
37
|
-
const identity = { client, amount, currency, platform, source };
|
|
38
|
+
const identity = { client, amount, currency, platform, source, includeEta };
|
|
38
39
|
if (isCurrent()) {
|
|
39
40
|
loadingIdentityRef.current = identity;
|
|
40
41
|
errorIdentityRef.current = null;
|
|
@@ -42,12 +43,15 @@ function useEstimate({
|
|
|
42
43
|
setError(null);
|
|
43
44
|
}
|
|
44
45
|
try {
|
|
45
|
-
const result = await client.estimate(
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
const result = await client.estimate(
|
|
47
|
+
{
|
|
48
|
+
amount,
|
|
49
|
+
currency,
|
|
50
|
+
...platform ? { platform } : {},
|
|
51
|
+
...source ? { source } : {}
|
|
52
|
+
},
|
|
53
|
+
{ includeEta }
|
|
54
|
+
);
|
|
51
55
|
if (isCurrent()) {
|
|
52
56
|
estimateIdentityRef.current = identity;
|
|
53
57
|
setEstimate(result);
|
|
@@ -63,7 +67,7 @@ function useEstimate({
|
|
|
63
67
|
} finally {
|
|
64
68
|
if (isCurrent()) setIsLoading(false);
|
|
65
69
|
}
|
|
66
|
-
}, [client, currency, amount, platform, source]);
|
|
70
|
+
}, [client, currency, amount, platform, source, includeEta]);
|
|
67
71
|
react.useEffect(() => {
|
|
68
72
|
latestRequestRef.current += 1;
|
|
69
73
|
estimateIdentityRef.current = null;
|
|
@@ -72,7 +76,7 @@ function useEstimate({
|
|
|
72
76
|
setEstimate(null);
|
|
73
77
|
setIsLoading(false);
|
|
74
78
|
setError(null);
|
|
75
|
-
}, [client, amount, currency, platform, source]);
|
|
79
|
+
}, [client, amount, currency, platform, source, includeEta]);
|
|
76
80
|
react.useEffect(() => {
|
|
77
81
|
mountedRef.current = true;
|
|
78
82
|
void refresh();
|
|
@@ -85,7 +89,7 @@ function useEstimate({
|
|
|
85
89
|
if (timerRef.current) clearInterval(timerRef.current);
|
|
86
90
|
};
|
|
87
91
|
}, [refresh, refreshIntervalMs]);
|
|
88
|
-
const matchesCurrentIdentity = (identity) => identity?.client === client && identity.amount === amount && identity.currency === currency && identity.platform === platform && identity.source === source;
|
|
92
|
+
const matchesCurrentIdentity = (identity) => identity?.client === client && identity.amount === amount && identity.currency === currency && identity.platform === platform && identity.source === source && identity.includeEta === includeEta;
|
|
89
93
|
return {
|
|
90
94
|
estimate: matchesCurrentIdentity(estimateIdentityRef.current) ? estimate : null,
|
|
91
95
|
isLoading: matchesCurrentIdentity(loadingIdentityRef.current) ? isLoading : false,
|
package/dist/react.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CurrencyType } from '@zkp2p/sdk';
|
|
2
|
-
import { r as CashClient, G as EstimateInput, i as CashEstimate, E as CashoutOptions, h as CashoutResult, D as CashoutInput, T as TopUpResult, W as WithdrawResult, e as CashOrder } from './createCashClient-
|
|
2
|
+
import { r as CashClient, G as EstimateInput, i as CashEstimate, E as CashoutOptions, h as CashoutResult, D as CashoutInput, T as TopUpResult, W as WithdrawResult, e as CashOrder } from './createCashClient-BhOytyHE.cjs';
|
|
3
3
|
import { WalletClient } from 'viem';
|
|
4
4
|
import '@relayprotocol/relay-sdk';
|
|
5
5
|
|
|
@@ -12,6 +12,8 @@ interface UseEstimateOptions {
|
|
|
12
12
|
platform?: string | null | undefined;
|
|
13
13
|
/** Optional Relay source. Omit for the Base USDC default path. */
|
|
14
14
|
source?: EstimateInput['source'] | null | undefined;
|
|
15
|
+
/** Disable to render the oracle rate before loading pair fill stats separately. */
|
|
16
|
+
includeEta?: boolean;
|
|
15
17
|
/** Re-fetch interval (ms) so the displayed rate tracks the market. 0 = no auto-refresh. */
|
|
16
18
|
refreshIntervalMs?: number;
|
|
17
19
|
}
|
|
@@ -20,7 +22,7 @@ interface UseEstimateOptions {
|
|
|
20
22
|
* estimate; the binding rate resolves at the Chainlink oracle when a buyer
|
|
21
23
|
* fills - there is no committed quote to show.
|
|
22
24
|
*/
|
|
23
|
-
declare function useEstimate({ client, amount, currency, platform, source, refreshIntervalMs, }: UseEstimateOptions): {
|
|
25
|
+
declare function useEstimate({ client, amount, currency, platform, source, includeEta, refreshIntervalMs, }: UseEstimateOptions): {
|
|
24
26
|
estimate: CashEstimate | null;
|
|
25
27
|
isLoading: boolean;
|
|
26
28
|
error: Error | null;
|
package/dist/react.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CurrencyType } from '@zkp2p/sdk';
|
|
2
|
-
import { r as CashClient, G as EstimateInput, i as CashEstimate, E as CashoutOptions, h as CashoutResult, D as CashoutInput, T as TopUpResult, W as WithdrawResult, e as CashOrder } from './createCashClient-
|
|
2
|
+
import { r as CashClient, G as EstimateInput, i as CashEstimate, E as CashoutOptions, h as CashoutResult, D as CashoutInput, T as TopUpResult, W as WithdrawResult, e as CashOrder } from './createCashClient-BhOytyHE.js';
|
|
3
3
|
import { WalletClient } from 'viem';
|
|
4
4
|
import '@relayprotocol/relay-sdk';
|
|
5
5
|
|
|
@@ -12,6 +12,8 @@ interface UseEstimateOptions {
|
|
|
12
12
|
platform?: string | null | undefined;
|
|
13
13
|
/** Optional Relay source. Omit for the Base USDC default path. */
|
|
14
14
|
source?: EstimateInput['source'] | null | undefined;
|
|
15
|
+
/** Disable to render the oracle rate before loading pair fill stats separately. */
|
|
16
|
+
includeEta?: boolean;
|
|
15
17
|
/** Re-fetch interval (ms) so the displayed rate tracks the market. 0 = no auto-refresh. */
|
|
16
18
|
refreshIntervalMs?: number;
|
|
17
19
|
}
|
|
@@ -20,7 +22,7 @@ interface UseEstimateOptions {
|
|
|
20
22
|
* estimate; the binding rate resolves at the Chainlink oracle when a buyer
|
|
21
23
|
* fills - there is no committed quote to show.
|
|
22
24
|
*/
|
|
23
|
-
declare function useEstimate({ client, amount, currency, platform, source, refreshIntervalMs, }: UseEstimateOptions): {
|
|
25
|
+
declare function useEstimate({ client, amount, currency, platform, source, includeEta, refreshIntervalMs, }: UseEstimateOptions): {
|
|
24
26
|
estimate: CashEstimate | null;
|
|
25
27
|
isLoading: boolean;
|
|
26
28
|
error: Error | null;
|
package/dist/react.js
CHANGED
|
@@ -7,6 +7,7 @@ function useEstimate({
|
|
|
7
7
|
currency,
|
|
8
8
|
platform,
|
|
9
9
|
source,
|
|
10
|
+
includeEta = true,
|
|
10
11
|
refreshIntervalMs = 0
|
|
11
12
|
}) {
|
|
12
13
|
const [estimate, setEstimate] = useState(null);
|
|
@@ -32,7 +33,7 @@ function useEstimate({
|
|
|
32
33
|
}
|
|
33
34
|
return;
|
|
34
35
|
}
|
|
35
|
-
const identity = { client, amount, currency, platform, source };
|
|
36
|
+
const identity = { client, amount, currency, platform, source, includeEta };
|
|
36
37
|
if (isCurrent()) {
|
|
37
38
|
loadingIdentityRef.current = identity;
|
|
38
39
|
errorIdentityRef.current = null;
|
|
@@ -40,12 +41,15 @@ function useEstimate({
|
|
|
40
41
|
setError(null);
|
|
41
42
|
}
|
|
42
43
|
try {
|
|
43
|
-
const result = await client.estimate(
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
const result = await client.estimate(
|
|
45
|
+
{
|
|
46
|
+
amount,
|
|
47
|
+
currency,
|
|
48
|
+
...platform ? { platform } : {},
|
|
49
|
+
...source ? { source } : {}
|
|
50
|
+
},
|
|
51
|
+
{ includeEta }
|
|
52
|
+
);
|
|
49
53
|
if (isCurrent()) {
|
|
50
54
|
estimateIdentityRef.current = identity;
|
|
51
55
|
setEstimate(result);
|
|
@@ -61,7 +65,7 @@ function useEstimate({
|
|
|
61
65
|
} finally {
|
|
62
66
|
if (isCurrent()) setIsLoading(false);
|
|
63
67
|
}
|
|
64
|
-
}, [client, currency, amount, platform, source]);
|
|
68
|
+
}, [client, currency, amount, platform, source, includeEta]);
|
|
65
69
|
useEffect(() => {
|
|
66
70
|
latestRequestRef.current += 1;
|
|
67
71
|
estimateIdentityRef.current = null;
|
|
@@ -70,7 +74,7 @@ function useEstimate({
|
|
|
70
74
|
setEstimate(null);
|
|
71
75
|
setIsLoading(false);
|
|
72
76
|
setError(null);
|
|
73
|
-
}, [client, amount, currency, platform, source]);
|
|
77
|
+
}, [client, amount, currency, platform, source, includeEta]);
|
|
74
78
|
useEffect(() => {
|
|
75
79
|
mountedRef.current = true;
|
|
76
80
|
void refresh();
|
|
@@ -83,7 +87,7 @@ function useEstimate({
|
|
|
83
87
|
if (timerRef.current) clearInterval(timerRef.current);
|
|
84
88
|
};
|
|
85
89
|
}, [refresh, refreshIntervalMs]);
|
|
86
|
-
const matchesCurrentIdentity = (identity) => identity?.client === client && identity.amount === amount && identity.currency === currency && identity.platform === platform && identity.source === source;
|
|
90
|
+
const matchesCurrentIdentity = (identity) => identity?.client === client && identity.amount === amount && identity.currency === currency && identity.platform === platform && identity.source === source && identity.includeEta === includeEta;
|
|
87
91
|
return {
|
|
88
92
|
estimate: matchesCurrentIdentity(estimateIdentityRef.current) ? estimate : null,
|
|
89
93
|
isLoading: matchesCurrentIdentity(loadingIdentityRef.current) ? isLoading : false,
|
package/dist/tools.cjs
CHANGED
package/dist/tools.js
CHANGED
|
@@ -135,6 +135,11 @@ methods aggregate to `zelle:USD`. Consumers own thresholding; the recommended
|
|
|
135
135
|
gate is `fills >= 10 && medianFillSeconds <= 48h`, with a fail-open fallback to
|
|
136
136
|
the full capability catalog when the read fails or filtering would empty it.
|
|
137
137
|
Medians are per-deposit first-fill latencies, never means or censored cohorts.
|
|
138
|
+
The client caches one raw environment snapshot for 15 minutes and de-duplicates
|
|
139
|
+
concurrent reads; ETA resolution still uses only the requested normalized
|
|
140
|
+
`platform:currency` key. A progressive UI can call
|
|
141
|
+
`estimate(input, { includeEta: false })` to render rate/receive immediately,
|
|
142
|
+
then read that pair from `fillStats()` without coupling the two loading states.
|
|
138
143
|
|
|
139
144
|
- **Buyer arrival time is market-driven.** A deposit at market rate should
|
|
140
145
|
fill fast, but the ETA is only a recent historical sample.
|
package/llms.txt
CHANGED
|
@@ -24,6 +24,11 @@ Key facts:
|
|
|
24
24
|
- fillStats() returns raw `{ fills, medianFillSeconds? }` evidence keyed by
|
|
25
25
|
`platform:currency`. Recommended consumer gate: fills >= 10 and median <=
|
|
26
26
|
48h; fail open to capabilities() if unavailable or filtering empties it.
|
|
27
|
+
Its raw environment snapshot is cached for 15 minutes, while lookups remain
|
|
28
|
+
exact to the normalized platform:currency pair.
|
|
29
|
+
- Progressive UIs can call estimate(input, { includeEta: false }) so the
|
|
30
|
+
oracle rate is not blocked by indexer history, then load the exact pair from
|
|
31
|
+
fillStats() separately.
|
|
27
32
|
- capabilities() exposes one Zelle platform. A zelle cashout internally attaches
|
|
28
33
|
the generic method plus Chase, Bank of America, and Citi buyer routes.
|
|
29
34
|
- Resume any order from its depositId alone (composite escrow_onchainId).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zkp2p/cash",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
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)",
|