@zkp2p/cash 0.1.0-dev.0
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 +131 -0
- package/LICENSE +21 -0
- package/README.md +138 -0
- package/dist/chunk-4DRZRWWS.js +176 -0
- package/dist/chunk-4DRZRWWS.js.map +1 -0
- package/dist/createCashClient-DpAx9A1A.d.cts +449 -0
- package/dist/createCashClient-DpAx9A1A.d.ts +449 -0
- package/dist/index.cjs +1572 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1367 -0
- package/dist/index.d.ts +1367 -0
- package/dist/index.js +1322 -0
- package/dist/index.js.map +1 -0
- package/dist/react.cjs +292 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.cts +97 -0
- package/dist/react.d.ts +97 -0
- package/dist/react.js +258 -0
- package/dist/react.js.map +1 -0
- package/dist/tools.cjs +148 -0
- package/dist/tools.cjs.map +1 -0
- package/dist/tools.d.cts +31 -0
- package/dist/tools.d.ts +31 -0
- package/dist/tools.js +145 -0
- package/dist/tools.js.map +1 -0
- package/package.json +89 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1322 @@
|
|
|
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 } from './chunk-4DRZRWWS.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-4DRZRWWS.js';
|
|
3
|
+
import { parseAbi, parseEventLogs, http, createWalletClient, encodeFunctionData } from 'viem';
|
|
4
|
+
import { base } from 'viem/chains';
|
|
5
|
+
import { getSpreadOracleConfig, currencyInfo, getPaymentMethodsCatalog, getGatingServiceAddress, resolvePaymentMethodHashFromCatalog, resolvePaymentMethodNameFromHash, getCurrencyCodeFromHash, createCompositeDepositId, appendAttributionToCalldata, Zkp2pClient, CHAINLINK_ORACLE_FEEDS } from '@zkp2p/sdk';
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
|
|
8
|
+
function isMarketRateSupported(currency, adapters) {
|
|
9
|
+
return getSpreadOracleConfig(currency, adapters) != null;
|
|
10
|
+
}
|
|
11
|
+
function buildMarketRateCurrencyOverride(currency, adapters) {
|
|
12
|
+
const code = currencyInfo[currency]?.currencyCodeHash;
|
|
13
|
+
const oracle = getSpreadOracleConfig(currency, adapters);
|
|
14
|
+
if (!code || !oracle) return null;
|
|
15
|
+
return {
|
|
16
|
+
code,
|
|
17
|
+
minConversionRate: ORACLE_MIN_CONVERSION_RATE_SENTINEL,
|
|
18
|
+
oracleRateConfig: {
|
|
19
|
+
adapter: oracle.adapter,
|
|
20
|
+
adapterConfig: oracle.adapterConfig,
|
|
21
|
+
spreadBps: MARKET_SPREAD_BPS,
|
|
22
|
+
maxStaleness: oracle.maxStaleness
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
var DEFAULT_MIN_ORDER_FLOOR = 1000000n;
|
|
27
|
+
function buildIntentAmountRange(amount) {
|
|
28
|
+
if (amount <= 0n) throw new Error("Cash-out amount must be positive");
|
|
29
|
+
const min = amount < DEFAULT_MIN_ORDER_FLOOR ? amount : DEFAULT_MIN_ORDER_FLOOR;
|
|
30
|
+
return { min, max: amount };
|
|
31
|
+
}
|
|
32
|
+
async function prepareCashDepositParams(client, input, adapters) {
|
|
33
|
+
const { payouts } = input;
|
|
34
|
+
if (!payouts.length) throw new Error("At least one payout is required");
|
|
35
|
+
const chainId = client.chainId;
|
|
36
|
+
const runtimeEnv = client.runtimeEnv;
|
|
37
|
+
const catalog = getPaymentMethodsCatalog(chainId, runtimeEnv);
|
|
38
|
+
const intentGatingService = getGatingServiceAddress(chainId, runtimeEnv);
|
|
39
|
+
for (const payout of payouts) {
|
|
40
|
+
if (!isMarketRateSupported(payout.currency, adapters)) {
|
|
41
|
+
throw new Error(
|
|
42
|
+
`${payout.currency} has no live market-rate oracle feed; Peer Cash supports market-rate currencies only.`
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const processorNames = payouts.map((p) => p.processorName);
|
|
47
|
+
const { hashedOnchainIds } = await client.registerPayeeDetails({
|
|
48
|
+
processorNames,
|
|
49
|
+
payeeData: payouts.map((p) => p.payeeData)
|
|
50
|
+
});
|
|
51
|
+
if (hashedOnchainIds.length !== payouts.length) {
|
|
52
|
+
throw new Error("Payee registration returned an unexpected number of hashes");
|
|
53
|
+
}
|
|
54
|
+
const paymentMethodsOverride = processorNames.map(
|
|
55
|
+
(name) => resolvePaymentMethodHashFromCatalog(name, catalog)
|
|
56
|
+
);
|
|
57
|
+
const paymentMethodDataOverride = hashedOnchainIds.map((hid) => ({
|
|
58
|
+
intentGatingService,
|
|
59
|
+
payeeDetails: hid,
|
|
60
|
+
data: "0x"
|
|
61
|
+
}));
|
|
62
|
+
const currenciesOverride = payouts.map((p) => {
|
|
63
|
+
const tuple = buildMarketRateCurrencyOverride(p.currency, adapters);
|
|
64
|
+
if (!tuple) throw new Error(`Failed to build market-rate config for ${p.currency}`);
|
|
65
|
+
return [tuple];
|
|
66
|
+
});
|
|
67
|
+
const conversionRates = payouts.map((p) => [
|
|
68
|
+
{ currency: p.currency, conversionRate: ORACLE_MIN_CONVERSION_RATE_SENTINEL.toString() }
|
|
69
|
+
]);
|
|
70
|
+
const intentAmountRange = input.intentAmountRange ?? buildIntentAmountRange(input.amount);
|
|
71
|
+
return {
|
|
72
|
+
token: input.token ?? BASE_USDC_ADDRESS,
|
|
73
|
+
amount: input.amount,
|
|
74
|
+
intentAmountRange,
|
|
75
|
+
processorNames,
|
|
76
|
+
conversionRates,
|
|
77
|
+
paymentMethodsOverride,
|
|
78
|
+
paymentMethodDataOverride,
|
|
79
|
+
currenciesOverride,
|
|
80
|
+
retainOnEmpty: CASH_RETAIN_ON_EMPTY
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// src/internal/convert.ts
|
|
85
|
+
function toBigInt(value) {
|
|
86
|
+
return toBigIntOrUndefined(value) ?? 0n;
|
|
87
|
+
}
|
|
88
|
+
function toBigIntOrUndefined(value) {
|
|
89
|
+
if (value === null || value === void 0 || value === "") return void 0;
|
|
90
|
+
try {
|
|
91
|
+
return BigInt(typeof value === "number" ? Math.trunc(value) : String(value));
|
|
92
|
+
} catch {
|
|
93
|
+
return void 0;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// src/engine/amounts.ts
|
|
98
|
+
function usdc(amount) {
|
|
99
|
+
const text = typeof amount === "number" ? amount.toString() : amount.trim();
|
|
100
|
+
if (!/^\d+(\.\d+)?$/.test(text)) {
|
|
101
|
+
throw new Error(`Invalid USDC amount: '${amount}'`);
|
|
102
|
+
}
|
|
103
|
+
const [whole = "0", frac = ""] = text.split(".");
|
|
104
|
+
if (frac.length > USDC_DECIMALS) {
|
|
105
|
+
throw new Error(`USDC has ${USDC_DECIMALS} decimals; '${amount}' has too many`);
|
|
106
|
+
}
|
|
107
|
+
return BigInt(whole) * 10n ** BigInt(USDC_DECIMALS) + BigInt(frac.padEnd(USDC_DECIMALS, "0") || "0");
|
|
108
|
+
}
|
|
109
|
+
function formatUsdc(amount) {
|
|
110
|
+
const negative = amount < 0n;
|
|
111
|
+
const abs = negative ? -amount : amount;
|
|
112
|
+
const whole = abs / 10n ** BigInt(USDC_DECIMALS);
|
|
113
|
+
const frac = (abs % 10n ** BigInt(USDC_DECIMALS)).toString().padStart(USDC_DECIMALS, "0");
|
|
114
|
+
const trimmed = frac.replace(/0+$/, "");
|
|
115
|
+
return `${negative ? "-" : ""}${whole}${trimmed ? `.${trimmed}` : ""}`;
|
|
116
|
+
}
|
|
117
|
+
var RATE_PRECISION = 10n ** 18n;
|
|
118
|
+
function fiatFromUsdc(amount, conversionRate) {
|
|
119
|
+
const raw = amount * conversionRate / RATE_PRECISION;
|
|
120
|
+
const penny = 10n ** BigInt(USDC_DECIMALS - 2);
|
|
121
|
+
const remainder = raw % penny;
|
|
122
|
+
return remainder > 0n ? raw - remainder + penny : raw;
|
|
123
|
+
}
|
|
124
|
+
function rateToNumber(conversionRate) {
|
|
125
|
+
return Number(conversionRate) / 1e18;
|
|
126
|
+
}
|
|
127
|
+
function fiatToNumber(fiat) {
|
|
128
|
+
return Number(fiat) / 10 ** USDC_DECIMALS;
|
|
129
|
+
}
|
|
130
|
+
function centsToNumber(cents) {
|
|
131
|
+
return Number(cents) / 100;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// src/engine/orderState.ts
|
|
135
|
+
var DUST_THRESHOLD = 10000n;
|
|
136
|
+
function toUnixSeconds(value) {
|
|
137
|
+
if (value === null || value === void 0 || value === "") return void 0;
|
|
138
|
+
const n = Number(value);
|
|
139
|
+
return Number.isFinite(n) && n > 0 ? n : void 0;
|
|
140
|
+
}
|
|
141
|
+
var FULFILLED_STATUSES = /* @__PURE__ */ new Set([
|
|
142
|
+
"FULFILLED",
|
|
143
|
+
"MANUALLY_RELEASED"
|
|
144
|
+
]);
|
|
145
|
+
function toFill(intent) {
|
|
146
|
+
const signaledAt = toUnixSeconds(intent.signalTimestamp);
|
|
147
|
+
const expiresAt = toUnixSeconds(intent.expiryTime);
|
|
148
|
+
const fulfilledAt = toUnixSeconds(intent.fulfillTimestamp);
|
|
149
|
+
const prunedAt = toUnixSeconds(intent.prunedTimestamp ?? intent.pruneTimestamp);
|
|
150
|
+
const paidAt = toUnixSeconds(intent.paymentTimestamp);
|
|
151
|
+
const amount = toBigInt(intent.amount);
|
|
152
|
+
const conversionRate = toBigIntOrUndefined(intent.conversionRate);
|
|
153
|
+
const currency = intent.fiatCurrency != null ? getCurrencyCodeFromHash(intent.fiatCurrency) : void 0;
|
|
154
|
+
const paidCurrency = intent.paymentCurrency != null ? getCurrencyCodeFromHash(intent.paymentCurrency) : void 0;
|
|
155
|
+
const paymentCents = toBigIntOrUndefined(intent.paymentAmount);
|
|
156
|
+
const releasedAmount = toBigIntOrUndefined(intent.releasedAmount);
|
|
157
|
+
const fillLatencySeconds = signaledAt !== void 0 && fulfilledAt !== void 0 && fulfilledAt >= signaledAt ? fulfilledAt - signaledAt : void 0;
|
|
158
|
+
return {
|
|
159
|
+
intentHash: intent.intentHash,
|
|
160
|
+
status: intent.status,
|
|
161
|
+
amount,
|
|
162
|
+
buyer: (intent.owner ?? "").toLowerCase(),
|
|
163
|
+
...currency !== void 0 ? { currency } : {},
|
|
164
|
+
...intent.fiatCurrency != null ? { currencyHash: intent.fiatCurrency } : {},
|
|
165
|
+
...conversionRate !== void 0 && conversionRate > 0n ? {
|
|
166
|
+
conversionRate,
|
|
167
|
+
rate: rateToNumber(conversionRate),
|
|
168
|
+
fiatOwed: fiatToNumber(fiatFromUsdc(amount, conversionRate))
|
|
169
|
+
} : {},
|
|
170
|
+
...paymentCents !== void 0 && paymentCents > 0n ? { fiatPaid: centsToNumber(paymentCents) } : {},
|
|
171
|
+
...paidCurrency !== void 0 ? { paidCurrency } : {},
|
|
172
|
+
...intent.paymentId != null && intent.paymentId !== "" ? { paymentId: intent.paymentId } : {},
|
|
173
|
+
...paidAt !== void 0 ? { paidAt } : {},
|
|
174
|
+
...releasedAmount !== void 0 && releasedAmount > 0n ? { releasedAmount } : {},
|
|
175
|
+
...fillLatencySeconds !== void 0 ? { fillLatencySeconds } : {},
|
|
176
|
+
...intent.isExpired != null ? { isExpired: intent.isExpired } : {},
|
|
177
|
+
...signaledAt !== void 0 ? { signaledAt } : {},
|
|
178
|
+
...expiresAt !== void 0 ? { expiresAt } : {},
|
|
179
|
+
...fulfilledAt !== void 0 ? { fulfilledAt } : {},
|
|
180
|
+
...prunedAt !== void 0 ? { prunedAt } : {}
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
function isFillLive(fill, nowSeconds) {
|
|
184
|
+
if (fill.status !== "SIGNALED") return false;
|
|
185
|
+
if (fill.isExpired === true) return false;
|
|
186
|
+
return fill.expiresAt === void 0 || fill.expiresAt > nowSeconds;
|
|
187
|
+
}
|
|
188
|
+
function fmtUsdc(amount) {
|
|
189
|
+
return `${formatUsdc(amount)} USDC`;
|
|
190
|
+
}
|
|
191
|
+
function explainOrder(order) {
|
|
192
|
+
switch (order.state) {
|
|
193
|
+
case "awaiting-buyer":
|
|
194
|
+
return `Your ${fmtUsdc(order.totalAmount)} cash-out is live and waiting for a buyer; you can withdraw it any time before a buyer commits.`;
|
|
195
|
+
case "matched":
|
|
196
|
+
return `A buyer committed to ${fmtUsdc(order.pendingAmount)} and is sending fiat now; funds release automatically once their payment is proven.`;
|
|
197
|
+
case "delivering":
|
|
198
|
+
return `${fmtUsdc(order.filledAmount)} of ${fmtUsdc(order.totalAmount)} has been delivered; the rest is ${order.pendingAmount > 0n ? "locked by an active buyer" : "still waiting for a buyer"}.`;
|
|
199
|
+
case "delivered":
|
|
200
|
+
return `Cash-out complete: ${fmtUsdc(order.filledAmount)} was delivered to ${order.fills.filter((f) => f.fulfilledAt !== void 0).length || "your"} buyer fill(s).`;
|
|
201
|
+
case "returned":
|
|
202
|
+
return order.filledAmount > 0n ? `${fmtUsdc(order.filledAmount)} was delivered and the remaining ${fmtUsdc(order.returnedAmount)} was returned to your wallet.` : `No buyer delivered; ${fmtUsdc(order.returnedAmount)} was returned to your wallet.`;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
function withExplain(data) {
|
|
206
|
+
return { ...data, explain: () => explainOrder(data) };
|
|
207
|
+
}
|
|
208
|
+
function deriveNextActions(state, hasLiveIntent) {
|
|
209
|
+
if (state === "delivered" || state === "returned") return [];
|
|
210
|
+
if (state === "awaiting-buyer") return ["wait", "withdraw"];
|
|
211
|
+
return hasLiveIntent ? ["wait"] : ["wait", "withdraw"];
|
|
212
|
+
}
|
|
213
|
+
function deriveCashOrder(depositId, intents, options = {}) {
|
|
214
|
+
const fills = intents.map(toFill);
|
|
215
|
+
const taken = options.takenAmount ?? fills.filter((f) => FULFILLED_STATUSES.has(f.status)).reduce((a, f) => a + f.amount, 0n);
|
|
216
|
+
const outstanding = options.outstandingAmount ?? fills.filter((f) => f.status === "SIGNALED").reduce((a, f) => a + f.amount, 0n);
|
|
217
|
+
const withdrawn = options.withdrawnAmount ?? 0n;
|
|
218
|
+
const remaining = options.remainingAmount ?? 0n;
|
|
219
|
+
const total = options.totalAmount ?? remaining + outstanding + taken + withdrawn;
|
|
220
|
+
const status = options.status;
|
|
221
|
+
const isTerminal = status === "CLOSED" || status === "WITHDRAWN";
|
|
222
|
+
const hasLiveFunds = remaining > DUST_THRESHOLD || outstanding > 0n;
|
|
223
|
+
let state;
|
|
224
|
+
if (outstanding > 0n) {
|
|
225
|
+
state = taken > 0n ? "delivering" : "matched";
|
|
226
|
+
} else if (taken > 0n && !hasLiveFunds) {
|
|
227
|
+
state = "delivered";
|
|
228
|
+
} else if (taken > 0n && hasLiveFunds) {
|
|
229
|
+
state = "delivering";
|
|
230
|
+
} else if (!hasLiveFunds && (withdrawn > 0n || isTerminal)) {
|
|
231
|
+
state = "returned";
|
|
232
|
+
} else if (hasLiveFunds) {
|
|
233
|
+
state = "awaiting-buyer";
|
|
234
|
+
} else {
|
|
235
|
+
state = taken > 0n ? "delivered" : "returned";
|
|
236
|
+
}
|
|
237
|
+
let matchedAt;
|
|
238
|
+
let deliveredAt;
|
|
239
|
+
for (const fill of fills) {
|
|
240
|
+
if (fill.signaledAt && (!matchedAt || fill.signaledAt < matchedAt)) matchedAt = fill.signaledAt;
|
|
241
|
+
if (FULFILLED_STATUSES.has(fill.status) && fill.fulfilledAt) {
|
|
242
|
+
if (!deliveredAt || fill.fulfilledAt > deliveredAt) deliveredAt = fill.fulfilledAt;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
const primary = fills.find((f) => f.status === "SIGNALED") ?? fills.find((f) => FULFILLED_STATUSES.has(f.status)) ?? fills[0];
|
|
246
|
+
const isInFlight = state === "awaiting-buyer" || state === "matched" || state === "delivering";
|
|
247
|
+
const nowSeconds = options.nowSeconds ?? Math.floor(Date.now() / 1e3);
|
|
248
|
+
const fillsIncluded = options.fillsIncluded ?? fills.length > 0;
|
|
249
|
+
const hasLiveIntent = fillsIncluded ? fills.some((f) => isFillLive(f, nowSeconds)) : outstanding > 0n;
|
|
250
|
+
return withExplain({
|
|
251
|
+
depositId,
|
|
252
|
+
state,
|
|
253
|
+
fills,
|
|
254
|
+
totalAmount: total,
|
|
255
|
+
filledAmount: taken,
|
|
256
|
+
pendingAmount: outstanding,
|
|
257
|
+
returnedAmount: withdrawn,
|
|
258
|
+
nextActions: deriveNextActions(state, hasLiveIntent),
|
|
259
|
+
...primary?.intentHash !== void 0 ? { primaryIntentHash: primary.intentHash } : {},
|
|
260
|
+
...matchedAt !== void 0 ? { matchedAt } : {},
|
|
261
|
+
...deliveredAt !== void 0 ? { deliveredAt } : {},
|
|
262
|
+
...options.updatedAt !== void 0 ? { updatedAt: options.updatedAt } : {},
|
|
263
|
+
intentCount: options.intentCount ?? fills.length,
|
|
264
|
+
...options.payouts !== void 0 ? { payouts: options.payouts } : {},
|
|
265
|
+
...options.successRateBps !== void 0 ? { successRateBps: options.successRateBps } : {},
|
|
266
|
+
isInFlight,
|
|
267
|
+
withdrawn: isTerminal
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
var ORACLE_KINDS = /* @__PURE__ */ new Set(["oracle_chainlink", "oracle_pyth"]);
|
|
271
|
+
function toPricing(tuple) {
|
|
272
|
+
if (!tuple) return { marketRate: false };
|
|
273
|
+
const spreadBps = tuple.spreadBps != null ? Number(tuple.spreadBps) : void 0;
|
|
274
|
+
const oracleRate = toBigIntOrUndefined(tuple.oracleRate);
|
|
275
|
+
const lastOracleUpdatedAt = tuple.lastOracleUpdatedAt != null ? Number(tuple.lastOracleUpdatedAt) : void 0;
|
|
276
|
+
return {
|
|
277
|
+
...spreadBps !== void 0 && Number.isFinite(spreadBps) ? { spreadBps } : {},
|
|
278
|
+
...tuple.kind != null ? { kind: tuple.kind } : {},
|
|
279
|
+
...tuple.rateSource != null ? { rateSource: tuple.rateSource } : {},
|
|
280
|
+
...oracleRate !== void 0 && oracleRate > 0n ? { oracleRate: rateToNumber(oracleRate) } : {},
|
|
281
|
+
...lastOracleUpdatedAt !== void 0 && Number.isFinite(lastOracleUpdatedAt) ? { lastOracleUpdatedAt } : {},
|
|
282
|
+
marketRate: spreadBps === 0 && tuple.kind != null && ORACLE_KINDS.has(tuple.kind)
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
function derivePayouts(paymentMethods, currencies, catalog) {
|
|
286
|
+
return paymentMethods.flatMap((method) => {
|
|
287
|
+
const platformHash = method.paymentMethodHash ?? "";
|
|
288
|
+
if (!platformHash) return [];
|
|
289
|
+
let platform;
|
|
290
|
+
try {
|
|
291
|
+
platform = resolvePaymentMethodNameFromHash(platformHash, catalog);
|
|
292
|
+
} catch {
|
|
293
|
+
platform = void 0;
|
|
294
|
+
}
|
|
295
|
+
const tuples = currencies.filter(
|
|
296
|
+
(c) => (c.paymentMethodHash ?? "").toLowerCase() === platformHash.toLowerCase()
|
|
297
|
+
);
|
|
298
|
+
const base2 = {
|
|
299
|
+
...platform !== void 0 ? { platform } : {},
|
|
300
|
+
platformHash,
|
|
301
|
+
payeeHash: method.payeeDetailsHash ?? "",
|
|
302
|
+
active: method.active ?? true
|
|
303
|
+
};
|
|
304
|
+
if (tuples.length === 0) return [{ ...base2, pricing: toPricing(void 0) }];
|
|
305
|
+
return tuples.map((tuple) => {
|
|
306
|
+
const currency = tuple.currencyCode != null ? getCurrencyCodeFromHash(tuple.currencyCode) : void 0;
|
|
307
|
+
return {
|
|
308
|
+
...base2,
|
|
309
|
+
...currency !== void 0 ? { currency } : {},
|
|
310
|
+
...tuple.currencyCode != null ? { currencyHash: tuple.currencyCode } : {},
|
|
311
|
+
pricing: toPricing(tuple)
|
|
312
|
+
};
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// src/engine/buyerProfile.ts
|
|
318
|
+
function toSeconds(value) {
|
|
319
|
+
if (value === null || value === void 0 || value === "") return void 0;
|
|
320
|
+
const n = Number(value);
|
|
321
|
+
return Number.isFinite(n) && n > 0 ? n : void 0;
|
|
322
|
+
}
|
|
323
|
+
function deriveBuyerProfile(address, intents) {
|
|
324
|
+
let fulfilled = 0;
|
|
325
|
+
let pruned = 0;
|
|
326
|
+
let signaled = 0;
|
|
327
|
+
let firstSeenAt;
|
|
328
|
+
let lastSeenAt;
|
|
329
|
+
for (const intent of intents) {
|
|
330
|
+
const status = intent.status ?? "";
|
|
331
|
+
if (status === "FULFILLED" || status === "MANUALLY_RELEASED") fulfilled += 1;
|
|
332
|
+
else if (status === "PRUNED") pruned += 1;
|
|
333
|
+
else if (status === "SIGNALED") signaled += 1;
|
|
334
|
+
const at = toSeconds(intent.signalTimestamp);
|
|
335
|
+
if (at !== void 0) {
|
|
336
|
+
if (firstSeenAt === void 0 || at < firstSeenAt) firstSeenAt = at;
|
|
337
|
+
if (lastSeenAt === void 0 || at > lastSeenAt) lastSeenAt = at;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
const settled = fulfilled + pruned;
|
|
341
|
+
return {
|
|
342
|
+
address: address.toLowerCase(),
|
|
343
|
+
totalIntents: intents.length,
|
|
344
|
+
fulfilled,
|
|
345
|
+
pruned,
|
|
346
|
+
signaled,
|
|
347
|
+
...settled > 0 ? { successRateBps: Math.round(fulfilled / settled * 1e4) } : {},
|
|
348
|
+
...firstSeenAt !== void 0 ? { firstSeenAt } : {},
|
|
349
|
+
...lastSeenAt !== void 0 ? { lastSeenAt } : {}
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
function resolveCashDepositId(params) {
|
|
353
|
+
let events;
|
|
354
|
+
try {
|
|
355
|
+
events = parseEventLogs({
|
|
356
|
+
abi: params.abi,
|
|
357
|
+
eventName: "DepositReceived",
|
|
358
|
+
logs: params.logs
|
|
359
|
+
});
|
|
360
|
+
} catch {
|
|
361
|
+
return null;
|
|
362
|
+
}
|
|
363
|
+
const event = events[0];
|
|
364
|
+
if (!event) return null;
|
|
365
|
+
const rawId = event.args.depositId;
|
|
366
|
+
if (rawId === void 0 || rawId === null) return null;
|
|
367
|
+
const onchainDepositId = BigInt(rawId);
|
|
368
|
+
const escrowAddress = event.address.toLowerCase();
|
|
369
|
+
return {
|
|
370
|
+
onchainDepositId,
|
|
371
|
+
escrowAddress,
|
|
372
|
+
compositeId: createCompositeDepositId(escrowAddress, onchainDepositId)
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
function parseCompositeDepositId(compositeId) {
|
|
376
|
+
const idx = compositeId.lastIndexOf("_");
|
|
377
|
+
if (idx === -1) {
|
|
378
|
+
return { escrowAddress: "", onchainDepositId: BigInt(compositeId) };
|
|
379
|
+
}
|
|
380
|
+
const escrowAddress = compositeId.slice(0, idx);
|
|
381
|
+
const onchainDepositId = BigInt(compositeId.slice(idx + 1) || "0");
|
|
382
|
+
return { escrowAddress, onchainDepositId };
|
|
383
|
+
}
|
|
384
|
+
var MIN_CASHOUT_AMOUNT = 10000n;
|
|
385
|
+
var RECOMMENDED_MIN_CASHOUT_AMOUNT = 1000000n;
|
|
386
|
+
var PAYEE_HINTS = {
|
|
387
|
+
venmo: "Venmo username, with or without the leading @ (e.g. @andrew-w)",
|
|
388
|
+
cashapp: "Cashtag, with or without the leading $ (e.g. $andrew)",
|
|
389
|
+
revolut: "Revtag (e.g. andrew1abc)",
|
|
390
|
+
wise: "Wisetag or the email on the Wise account",
|
|
391
|
+
zelle: "Email address or US phone number enrolled with Zelle",
|
|
392
|
+
paypal: "PayPal.Me handle or account email",
|
|
393
|
+
mercadopago: "Mercado Pago alias or CVU",
|
|
394
|
+
monzo: "Monzo.me username",
|
|
395
|
+
chime: "ChimeSign (e.g. $andrew)",
|
|
396
|
+
luxon: "Luxon Pay ID or account email",
|
|
397
|
+
n26: "MoneyBeam email or phone number"
|
|
398
|
+
};
|
|
399
|
+
var IDENTITY_ATTESTATION_PLATFORMS = /* @__PURE__ */ new Set(["wise", "paypal"]);
|
|
400
|
+
function platformRequiresIdentityAttestation(platform) {
|
|
401
|
+
return IDENTITY_ATTESTATION_PLATFORMS.has(platform);
|
|
402
|
+
}
|
|
403
|
+
function buildCapabilities(environment) {
|
|
404
|
+
const catalog = getPaymentMethodsCatalog(BASE_CHAIN_ID, environment);
|
|
405
|
+
const platforms = Object.entries(catalog).map(([platform, entry]) => {
|
|
406
|
+
const currencies2 = (entry.currencies ?? []).map((hash) => getCurrencyCodeFromHash(hash)).filter(
|
|
407
|
+
(code) => code != null && isMarketRateSupported(code)
|
|
408
|
+
);
|
|
409
|
+
return {
|
|
410
|
+
platform,
|
|
411
|
+
currencies: [...new Set(currencies2)],
|
|
412
|
+
payeeHint: PAYEE_HINTS[platform] ?? "Your payment handle for this platform",
|
|
413
|
+
requiresIdentityAttestation: IDENTITY_ATTESTATION_PLATFORMS.has(platform)
|
|
414
|
+
};
|
|
415
|
+
}).filter((p) => p.currencies.length > 0).sort((a, b) => a.platform.localeCompare(b.platform));
|
|
416
|
+
const currencies = [...new Set(platforms.flatMap((p) => p.currencies))].sort();
|
|
417
|
+
return {
|
|
418
|
+
chainId: BASE_CHAIN_ID,
|
|
419
|
+
token: { address: BASE_USDC_ADDRESS, symbol: "USDC", decimals: USDC_DECIMALS },
|
|
420
|
+
environment,
|
|
421
|
+
platforms,
|
|
422
|
+
currencies,
|
|
423
|
+
amount: { min: MIN_CASHOUT_AMOUNT, recommendedMin: RECOMMENDED_MIN_CASHOUT_AMOUNT, max: null },
|
|
424
|
+
pricing: { kind: "oracle-market-rate", spreadBps: 0 }
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
428
|
+
var CHAINLINK_LATEST_ROUND_ABI = [
|
|
429
|
+
{
|
|
430
|
+
name: "latestRoundData",
|
|
431
|
+
type: "function",
|
|
432
|
+
stateMutability: "view",
|
|
433
|
+
inputs: [],
|
|
434
|
+
outputs: [
|
|
435
|
+
{ name: "roundId", type: "uint80" },
|
|
436
|
+
{ name: "answer", type: "int256" },
|
|
437
|
+
{ name: "startedAt", type: "uint256" },
|
|
438
|
+
{ name: "updatedAt", type: "uint256" },
|
|
439
|
+
{ name: "answeredInRound", type: "uint80" }
|
|
440
|
+
]
|
|
441
|
+
}
|
|
442
|
+
];
|
|
443
|
+
var DEFAULT_MAX_STALENESS_SECONDS = 86400;
|
|
444
|
+
async function readEstimate(publicClient, input) {
|
|
445
|
+
const { amount, currency } = input;
|
|
446
|
+
if (amount < MIN_CASHOUT_AMOUNT) {
|
|
447
|
+
throw errors.amountBelowMinimum(amount, MIN_CASHOUT_AMOUNT);
|
|
448
|
+
}
|
|
449
|
+
if (!isMarketRateSupported(currency)) {
|
|
450
|
+
throw errors.oracleUnsupportedCurrency(currency);
|
|
451
|
+
}
|
|
452
|
+
const feedConfig = CHAINLINK_ORACLE_FEEDS[currency];
|
|
453
|
+
const asOf = Math.floor(Date.now() / 1e3);
|
|
454
|
+
let rate;
|
|
455
|
+
let oracleUpdatedAt;
|
|
456
|
+
if (!feedConfig || feedConfig.feed.toLowerCase() === ZERO_ADDRESS) {
|
|
457
|
+
rate = 1;
|
|
458
|
+
} else {
|
|
459
|
+
const result = await publicClient.readContract({
|
|
460
|
+
address: feedConfig.feed,
|
|
461
|
+
abi: CHAINLINK_LATEST_ROUND_ABI,
|
|
462
|
+
functionName: "latestRoundData"
|
|
463
|
+
});
|
|
464
|
+
const answer = Number(result[1]);
|
|
465
|
+
const price = answer / 10 ** feedConfig.decimals;
|
|
466
|
+
if (!Number.isFinite(price) || price <= 0) {
|
|
467
|
+
throw errors.oracleUnsupportedCurrency(currency);
|
|
468
|
+
}
|
|
469
|
+
const updatedAt = Number(result[3]);
|
|
470
|
+
if (Number.isFinite(updatedAt) && updatedAt > 0) oracleUpdatedAt = updatedAt;
|
|
471
|
+
rate = feedConfig.invert ? 1 / price : price;
|
|
472
|
+
}
|
|
473
|
+
const stale = oracleUpdatedAt !== void 0 && asOf - oracleUpdatedAt > DEFAULT_MAX_STALENESS_SECONDS;
|
|
474
|
+
return {
|
|
475
|
+
kind: "oracle-estimate",
|
|
476
|
+
currency,
|
|
477
|
+
amount,
|
|
478
|
+
rate,
|
|
479
|
+
receiveAmount: Number(amount) / 10 ** USDC_DECIMALS * rate,
|
|
480
|
+
asOf,
|
|
481
|
+
...oracleUpdatedAt !== void 0 ? { oracleUpdatedAt } : {},
|
|
482
|
+
...stale ? { stale: true } : {}
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// src/client/createCashClient.ts
|
|
487
|
+
var DEFAULT_RPC_URL = "https://mainnet.base.org";
|
|
488
|
+
var CASH_ATTRIBUTION_CODE = "peer-cash";
|
|
489
|
+
var DEFAULT_CURATOR_URLS = {
|
|
490
|
+
staging: "https://api-staging.zkp2p.xyz"
|
|
491
|
+
};
|
|
492
|
+
var ERC20_APPROVE_ABI = parseAbi([
|
|
493
|
+
"function approve(address spender, uint256 amount) returns (bool)"
|
|
494
|
+
]);
|
|
495
|
+
var ERC20_ALLOWANCE_ABI = parseAbi([
|
|
496
|
+
"function allowance(address owner, address spender) view returns (uint256)"
|
|
497
|
+
]);
|
|
498
|
+
function sleep(ms, signal) {
|
|
499
|
+
return new Promise((resolve) => {
|
|
500
|
+
const timer = setTimeout(done, ms);
|
|
501
|
+
function done() {
|
|
502
|
+
signal?.removeEventListener("abort", done);
|
|
503
|
+
clearTimeout(timer);
|
|
504
|
+
resolve();
|
|
505
|
+
}
|
|
506
|
+
signal?.addEventListener("abort", done, { once: true });
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
function orderFingerprint(order) {
|
|
510
|
+
return [
|
|
511
|
+
order.state,
|
|
512
|
+
order.filledAmount,
|
|
513
|
+
order.pendingAmount,
|
|
514
|
+
order.returnedAmount,
|
|
515
|
+
order.intentCount ?? 0,
|
|
516
|
+
order.nextActions.join("+")
|
|
517
|
+
].join("|");
|
|
518
|
+
}
|
|
519
|
+
async function submitAndConfirm(client, verb, send) {
|
|
520
|
+
let hash;
|
|
521
|
+
try {
|
|
522
|
+
hash = await send();
|
|
523
|
+
} catch (err) {
|
|
524
|
+
throw mapChainError(verb, err);
|
|
525
|
+
}
|
|
526
|
+
const receipt = await client.publicClient.waitForTransactionReceipt({ hash });
|
|
527
|
+
if (receipt.status === "reverted") throw errors.transactionFailed(hash);
|
|
528
|
+
return hash;
|
|
529
|
+
}
|
|
530
|
+
function depositOrderOptions(deposit) {
|
|
531
|
+
const remaining = toBigIntOrUndefined(deposit.remainingDeposits);
|
|
532
|
+
const outstanding = toBigIntOrUndefined(deposit.outstandingIntentAmount);
|
|
533
|
+
const taken = toBigIntOrUndefined(deposit.totalAmountTaken);
|
|
534
|
+
const withdrawn = toBigIntOrUndefined(deposit.totalWithdrawn);
|
|
535
|
+
const updatedAt = deposit.updatedAt != null ? Number(deposit.updatedAt) : void 0;
|
|
536
|
+
return {
|
|
537
|
+
...remaining !== void 0 ? { remainingAmount: remaining } : {},
|
|
538
|
+
...outstanding !== void 0 ? { outstandingAmount: outstanding } : {},
|
|
539
|
+
...taken !== void 0 ? { takenAmount: taken } : {},
|
|
540
|
+
...withdrawn !== void 0 ? { withdrawnAmount: withdrawn } : {},
|
|
541
|
+
...deposit.status != null ? { status: deposit.status } : {},
|
|
542
|
+
...deposit.totalIntents != null ? { intentCount: deposit.totalIntents } : {},
|
|
543
|
+
...deposit.successRateBps != null ? { successRateBps: deposit.successRateBps } : {},
|
|
544
|
+
...updatedAt !== void 0 && Number.isFinite(updatedAt) ? { updatedAt } : {}
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
function createCashClient(options) {
|
|
548
|
+
const { environment } = options;
|
|
549
|
+
const transport = options.transport ?? http(options.rpcUrl ?? DEFAULT_RPC_URL);
|
|
550
|
+
const referrerCodes = [
|
|
551
|
+
CASH_ATTRIBUTION_CODE,
|
|
552
|
+
...options.referrer === void 0 ? [] : Array.isArray(options.referrer) ? options.referrer : [options.referrer]
|
|
553
|
+
];
|
|
554
|
+
const attribution = { referrer: referrerCodes };
|
|
555
|
+
function buildSdkClient(walletClient) {
|
|
556
|
+
return new Zkp2pClient({
|
|
557
|
+
walletClient,
|
|
558
|
+
chainId: BASE_CHAIN_ID,
|
|
559
|
+
runtimeEnv: environment,
|
|
560
|
+
rpcTransport: transport,
|
|
561
|
+
...options.rpcUrl ? { rpcUrl: options.rpcUrl } : {},
|
|
562
|
+
...options.indexerUrl ? { indexerUrl: options.indexerUrl } : {},
|
|
563
|
+
...options.curatorUrl ?? DEFAULT_CURATOR_URLS[environment] ? { baseApiUrl: options.curatorUrl ?? DEFAULT_CURATOR_URLS[environment] } : {},
|
|
564
|
+
...options.apiKey ? { apiKey: options.apiKey } : {}
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
const readClient = buildSdkClient(createWalletClient({ chain: base, transport }));
|
|
568
|
+
const signingClients = /* @__PURE__ */ new WeakMap();
|
|
569
|
+
function signingClient(verb, opts) {
|
|
570
|
+
const signer = opts?.signer;
|
|
571
|
+
if (!signer?.account) throw errors.signerRequired(verb);
|
|
572
|
+
let client = signingClients.get(signer);
|
|
573
|
+
if (!client) {
|
|
574
|
+
client = buildSdkClient(signer);
|
|
575
|
+
signingClients.set(signer, client);
|
|
576
|
+
}
|
|
577
|
+
return client;
|
|
578
|
+
}
|
|
579
|
+
function validateInput(input) {
|
|
580
|
+
const { amount, receive } = input;
|
|
581
|
+
if (amount < MIN_CASHOUT_AMOUNT) throw errors.amountBelowMinimum(amount, MIN_CASHOUT_AMOUNT);
|
|
582
|
+
const catalog = getPaymentMethodsCatalog(BASE_CHAIN_ID, environment);
|
|
583
|
+
if (!catalog[receive.platform]) throw errors.unsupportedPlatform(receive.platform);
|
|
584
|
+
if (!isMarketRateSupported(receive.currency)) {
|
|
585
|
+
throw errors.oracleUnsupportedCurrency(receive.currency);
|
|
586
|
+
}
|
|
587
|
+
if (platformRequiresIdentityAttestation(receive.platform) && !receive.payee.identityAttestation) {
|
|
588
|
+
throw errors.payeeVerificationRequired(receive.platform);
|
|
589
|
+
}
|
|
590
|
+
return {
|
|
591
|
+
amount,
|
|
592
|
+
payouts: [
|
|
593
|
+
{
|
|
594
|
+
processorName: receive.platform,
|
|
595
|
+
currency: receive.currency,
|
|
596
|
+
payeeData: receive.payee
|
|
597
|
+
}
|
|
598
|
+
],
|
|
599
|
+
...input.intentAmountRange ? { intentAmountRange: input.intentAmountRange } : {}
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
async function buildDepositParams(client, depositInput) {
|
|
603
|
+
try {
|
|
604
|
+
return await prepareCashDepositParams(client, depositInput);
|
|
605
|
+
} catch (err) {
|
|
606
|
+
if (isCashError(err)) throw err;
|
|
607
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
608
|
+
if (/identityAttestation is required|identity attestation/i.test(message)) {
|
|
609
|
+
const platform = depositInput.payouts[0]?.processorName ?? "this platform";
|
|
610
|
+
throw errors.payeeVerificationRequired(platform, err);
|
|
611
|
+
}
|
|
612
|
+
throw errors.payeeRegistrationFailed(err);
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
async function fetchOrder(depositId) {
|
|
616
|
+
const deposits = await readClient.indexer.getDepositsByIdsWithRelations([depositId], {
|
|
617
|
+
includeIntents: true,
|
|
618
|
+
intentStatuses: CASH_ORDER_STATUSES
|
|
619
|
+
});
|
|
620
|
+
const deposit = deposits[0];
|
|
621
|
+
if (!deposit) {
|
|
622
|
+
const intents = await readClient.indexer.getIntentsForDeposits(
|
|
623
|
+
[depositId],
|
|
624
|
+
CASH_ORDER_STATUSES
|
|
625
|
+
);
|
|
626
|
+
if (intents.length === 0) throw errors.orderNotFound(depositId);
|
|
627
|
+
return deriveCashOrder(depositId, intents);
|
|
628
|
+
}
|
|
629
|
+
const payouts = derivePayouts(
|
|
630
|
+
deposit.paymentMethods ?? [],
|
|
631
|
+
deposit.currencies ?? [],
|
|
632
|
+
getPaymentMethodsCatalog(BASE_CHAIN_ID, environment)
|
|
633
|
+
);
|
|
634
|
+
return deriveCashOrder(depositId, deposit.intents ?? [], {
|
|
635
|
+
...depositOrderOptions(deposit),
|
|
636
|
+
...payouts.length > 0 ? { payouts } : {}
|
|
637
|
+
});
|
|
638
|
+
}
|
|
639
|
+
function escrowContext(depositId) {
|
|
640
|
+
const { escrowAddress, onchainDepositId } = parseCompositeDepositId(depositId);
|
|
641
|
+
return {
|
|
642
|
+
onchainDepositId,
|
|
643
|
+
escrowArg: escrowAddress ? { escrowAddress } : {}
|
|
644
|
+
};
|
|
645
|
+
}
|
|
646
|
+
function availableAmount(order) {
|
|
647
|
+
return order.totalAmount - order.filledAmount - order.pendingAmount - order.returnedAmount;
|
|
648
|
+
}
|
|
649
|
+
async function withdrawContext(depositId) {
|
|
650
|
+
const order = await fetchOrder(depositId);
|
|
651
|
+
const nowSeconds = Math.floor(Date.now() / 1e3);
|
|
652
|
+
const signaled = order.fills.filter((f) => f.status === "SIGNALED");
|
|
653
|
+
const liveIntent = signaled.some((f) => isFillLive(f, nowSeconds));
|
|
654
|
+
const expiredIntent = signaled.length > 0 && !liveIntent;
|
|
655
|
+
if (order.pendingAmount > 0n && liveIntent) {
|
|
656
|
+
throw errors.activeIntentBlocksWithdrawal(depositId);
|
|
657
|
+
}
|
|
658
|
+
if (availableAmount(order) <= 0n && order.pendingAmount === 0n) {
|
|
659
|
+
throw errors.nothingToWithdraw(depositId);
|
|
660
|
+
}
|
|
661
|
+
return { expiredIntent, ...escrowContext(depositId) };
|
|
662
|
+
}
|
|
663
|
+
async function partialWithdrawContext(depositId, amount) {
|
|
664
|
+
if (amount <= 0n) throw errors.amountBelowMinimum(amount, 1n);
|
|
665
|
+
const order = await fetchOrder(depositId);
|
|
666
|
+
const available = availableAmount(order);
|
|
667
|
+
if (amount > available) {
|
|
668
|
+
throw errors.insufficientAvailableFunds(depositId, amount, available);
|
|
669
|
+
}
|
|
670
|
+
return escrowContext(depositId);
|
|
671
|
+
}
|
|
672
|
+
async function topUpContext(depositId, amount) {
|
|
673
|
+
if (amount < MIN_CASHOUT_AMOUNT) throw errors.amountBelowMinimum(amount, MIN_CASHOUT_AMOUNT);
|
|
674
|
+
const order = await fetchOrder(depositId);
|
|
675
|
+
if (!order.isInFlight) throw errors.orderNotActive(depositId);
|
|
676
|
+
return escrowContext(depositId);
|
|
677
|
+
}
|
|
678
|
+
async function settleAllowance(client, token, owner, escrow, amount) {
|
|
679
|
+
let allowance;
|
|
680
|
+
try {
|
|
681
|
+
allowance = await client.ensureAllowance({
|
|
682
|
+
token,
|
|
683
|
+
amount,
|
|
684
|
+
spender: escrow,
|
|
685
|
+
txOverrides: attribution
|
|
686
|
+
});
|
|
687
|
+
} catch (err) {
|
|
688
|
+
throw mapChainError("approve", err);
|
|
689
|
+
}
|
|
690
|
+
if (allowance.hadAllowance || !allowance.hash) return;
|
|
691
|
+
const receipt = await client.publicClient.waitForTransactionReceipt({ hash: allowance.hash });
|
|
692
|
+
if (receipt.status === "reverted") throw errors.transactionFailed(allowance.hash);
|
|
693
|
+
for (let attempt = 0; attempt < 15; attempt++) {
|
|
694
|
+
const visible = await client.publicClient.readContract({
|
|
695
|
+
address: token,
|
|
696
|
+
abi: ERC20_ALLOWANCE_ABI,
|
|
697
|
+
functionName: "allowance",
|
|
698
|
+
args: [owner, escrow]
|
|
699
|
+
});
|
|
700
|
+
if (visible >= amount) return;
|
|
701
|
+
await sleep(1e3);
|
|
702
|
+
}
|
|
703
|
+
throw errors.allowanceNotVisible(amount);
|
|
704
|
+
}
|
|
705
|
+
return {
|
|
706
|
+
capabilities() {
|
|
707
|
+
return buildCapabilities(environment);
|
|
708
|
+
},
|
|
709
|
+
async estimate(input) {
|
|
710
|
+
return readEstimate(readClient.publicClient, input);
|
|
711
|
+
},
|
|
712
|
+
async cashout(input, opts) {
|
|
713
|
+
const depositInput = validateInput(input);
|
|
714
|
+
const client = signingClient("cashout", opts);
|
|
715
|
+
const params = await buildDepositParams(client, depositInput);
|
|
716
|
+
const escrow = client.escrowV2Address ?? client.escrowAddress;
|
|
717
|
+
const owner = opts.signer.account.address;
|
|
718
|
+
await settleAllowance(client, params.token, owner, escrow, depositInput.amount);
|
|
719
|
+
const attributedParams = { ...params, txOverrides: attribution };
|
|
720
|
+
const send = async () => {
|
|
721
|
+
try {
|
|
722
|
+
return (await client.createDeposit(attributedParams)).hash;
|
|
723
|
+
} catch (err) {
|
|
724
|
+
if (err instanceof Error && /exceeds allowance/i.test(err.message)) {
|
|
725
|
+
await sleep(2e3);
|
|
726
|
+
return (await client.createDeposit(attributedParams)).hash;
|
|
727
|
+
}
|
|
728
|
+
throw err;
|
|
729
|
+
}
|
|
730
|
+
};
|
|
731
|
+
let hash;
|
|
732
|
+
try {
|
|
733
|
+
hash = await send();
|
|
734
|
+
} catch (err) {
|
|
735
|
+
throw mapChainError("createDeposit", err);
|
|
736
|
+
}
|
|
737
|
+
const receipt = await client.publicClient.waitForTransactionReceipt({ hash });
|
|
738
|
+
if (receipt.status === "reverted") throw errors.transactionFailed(hash);
|
|
739
|
+
const abi = client.escrowV2Abi ?? client.escrowAbi;
|
|
740
|
+
const resolved = resolveCashDepositId({ logs: receipt.logs, abi });
|
|
741
|
+
if (!resolved) throw errors.depositResolutionFailed(hash);
|
|
742
|
+
const order = deriveCashOrder(resolved.compositeId, [], {
|
|
743
|
+
remainingAmount: depositInput.amount,
|
|
744
|
+
status: "ACTIVE"
|
|
745
|
+
});
|
|
746
|
+
return {
|
|
747
|
+
depositId: resolved.compositeId,
|
|
748
|
+
txHash: hash,
|
|
749
|
+
escrowAddress: resolved.escrowAddress,
|
|
750
|
+
onchainDepositId: resolved.onchainDepositId,
|
|
751
|
+
order
|
|
752
|
+
};
|
|
753
|
+
},
|
|
754
|
+
async prepare(input) {
|
|
755
|
+
const depositInput = validateInput(input);
|
|
756
|
+
const params = await buildDepositParams(readClient, depositInput);
|
|
757
|
+
const { prepared } = await readClient.prepareCreateDeposit({
|
|
758
|
+
...params,
|
|
759
|
+
txOverrides: attribution
|
|
760
|
+
});
|
|
761
|
+
const approve = {
|
|
762
|
+
to: params.token,
|
|
763
|
+
data: appendAttributionToCalldata(
|
|
764
|
+
encodeFunctionData({
|
|
765
|
+
abi: ERC20_APPROVE_ABI,
|
|
766
|
+
functionName: "approve",
|
|
767
|
+
args: [prepared.to, depositInput.amount]
|
|
768
|
+
}),
|
|
769
|
+
referrerCodes
|
|
770
|
+
),
|
|
771
|
+
value: 0n,
|
|
772
|
+
chainId: BASE_CHAIN_ID
|
|
773
|
+
};
|
|
774
|
+
const hashedOnchainIds = (params.paymentMethodDataOverride ?? []).map((d) => d.payeeDetails);
|
|
775
|
+
return {
|
|
776
|
+
txs: [approve, prepared],
|
|
777
|
+
steps: [
|
|
778
|
+
{
|
|
779
|
+
kind: "approve",
|
|
780
|
+
description: "Approve Base USDC for the Peer Cash escrow."
|
|
781
|
+
},
|
|
782
|
+
{
|
|
783
|
+
kind: "createDeposit",
|
|
784
|
+
description: "Create the protocol-held cash-out order."
|
|
785
|
+
}
|
|
786
|
+
],
|
|
787
|
+
register: { hashedOnchainIds }
|
|
788
|
+
};
|
|
789
|
+
},
|
|
790
|
+
async order(depositId) {
|
|
791
|
+
return fetchOrder(depositId);
|
|
792
|
+
},
|
|
793
|
+
async buyer(address) {
|
|
794
|
+
const intents = await readClient.indexer.getOwnerIntents(address, CASH_ORDER_STATUSES);
|
|
795
|
+
return deriveBuyerProfile(address, intents);
|
|
796
|
+
},
|
|
797
|
+
async orders(owner, opts = {}) {
|
|
798
|
+
const { inFlight = false, limit = 100 } = opts;
|
|
799
|
+
const deposits = await readClient.indexer.getDeposits({ depositor: owner }, { limit });
|
|
800
|
+
const derived = deposits.map((d) => deriveCashOrder(d.id, [], { ...depositOrderOptions(d), fillsIncluded: false })).filter((o) => o.totalAmount > 10000n).sort((a, b) => (b.updatedAt ?? 0) - (a.updatedAt ?? 0));
|
|
801
|
+
return inFlight ? derived.filter((o) => o.isInFlight) : derived;
|
|
802
|
+
},
|
|
803
|
+
async *watch(depositId, opts = {}) {
|
|
804
|
+
const { signal, pollIntervalMs = 5e3, timeoutMs } = opts;
|
|
805
|
+
const startedAt = Date.now();
|
|
806
|
+
let lastFingerprint;
|
|
807
|
+
while (true) {
|
|
808
|
+
if (signal?.aborted) return;
|
|
809
|
+
if (timeoutMs !== void 0 && Date.now() - startedAt >= timeoutMs) {
|
|
810
|
+
throw errors.watchTimeout(depositId, timeoutMs);
|
|
811
|
+
}
|
|
812
|
+
let order = null;
|
|
813
|
+
try {
|
|
814
|
+
order = await fetchOrder(depositId);
|
|
815
|
+
} catch (err) {
|
|
816
|
+
if (!(isCashError(err) && err.code === "ORDER_NOT_FOUND")) throw err;
|
|
817
|
+
}
|
|
818
|
+
if (order) {
|
|
819
|
+
const fingerprint = orderFingerprint(order);
|
|
820
|
+
if (fingerprint !== lastFingerprint) {
|
|
821
|
+
lastFingerprint = fingerprint;
|
|
822
|
+
yield order;
|
|
823
|
+
}
|
|
824
|
+
if (!order.isInFlight) return;
|
|
825
|
+
}
|
|
826
|
+
await sleep(pollIntervalMs, signal);
|
|
827
|
+
}
|
|
828
|
+
},
|
|
829
|
+
async withdraw(depositId, opts) {
|
|
830
|
+
const client = signingClient("withdraw", opts);
|
|
831
|
+
if (opts.amount !== void 0) {
|
|
832
|
+
const { onchainDepositId: onchainDepositId2, escrowArg: escrowArg2 } = await partialWithdrawContext(
|
|
833
|
+
depositId,
|
|
834
|
+
opts.amount
|
|
835
|
+
);
|
|
836
|
+
const withdrawTxHash2 = await submitAndConfirm(
|
|
837
|
+
client,
|
|
838
|
+
"removeFunds",
|
|
839
|
+
() => client.removeFunds({
|
|
840
|
+
depositId: onchainDepositId2,
|
|
841
|
+
amount: opts.amount,
|
|
842
|
+
...escrowArg2,
|
|
843
|
+
txOverrides: attribution
|
|
844
|
+
})
|
|
845
|
+
);
|
|
846
|
+
return { depositId, withdrawTxHash: withdrawTxHash2 };
|
|
847
|
+
}
|
|
848
|
+
const { expiredIntent, onchainDepositId, escrowArg } = await withdrawContext(depositId);
|
|
849
|
+
let pruneTxHash;
|
|
850
|
+
if (expiredIntent) {
|
|
851
|
+
pruneTxHash = await submitAndConfirm(
|
|
852
|
+
client,
|
|
853
|
+
"pruneExpiredIntents",
|
|
854
|
+
() => client.pruneExpiredIntents({
|
|
855
|
+
depositId: onchainDepositId,
|
|
856
|
+
...escrowArg,
|
|
857
|
+
txOverrides: attribution
|
|
858
|
+
})
|
|
859
|
+
);
|
|
860
|
+
}
|
|
861
|
+
const withdrawTxHash = await submitAndConfirm(
|
|
862
|
+
client,
|
|
863
|
+
"withdrawDeposit",
|
|
864
|
+
() => client.withdrawDeposit({
|
|
865
|
+
depositId: onchainDepositId,
|
|
866
|
+
...escrowArg,
|
|
867
|
+
txOverrides: attribution
|
|
868
|
+
})
|
|
869
|
+
);
|
|
870
|
+
return {
|
|
871
|
+
depositId,
|
|
872
|
+
...pruneTxHash !== void 0 ? { pruneTxHash } : {},
|
|
873
|
+
withdrawTxHash
|
|
874
|
+
};
|
|
875
|
+
},
|
|
876
|
+
async prepareWithdraw(depositId, opts = {}) {
|
|
877
|
+
if (opts.amount !== void 0) {
|
|
878
|
+
const { onchainDepositId: onchainDepositId2, escrowArg: escrowArg2 } = await partialWithdrawContext(
|
|
879
|
+
depositId,
|
|
880
|
+
opts.amount
|
|
881
|
+
);
|
|
882
|
+
const tx = await readClient.removeFunds.prepare({
|
|
883
|
+
depositId: onchainDepositId2,
|
|
884
|
+
amount: opts.amount,
|
|
885
|
+
...escrowArg2,
|
|
886
|
+
txOverrides: attribution
|
|
887
|
+
});
|
|
888
|
+
return {
|
|
889
|
+
txs: [tx],
|
|
890
|
+
steps: [
|
|
891
|
+
{
|
|
892
|
+
kind: "removeFunds",
|
|
893
|
+
description: "Withdraw the requested unlocked USDC amount."
|
|
894
|
+
}
|
|
895
|
+
]
|
|
896
|
+
};
|
|
897
|
+
}
|
|
898
|
+
const { expiredIntent, onchainDepositId, escrowArg } = await withdrawContext(depositId);
|
|
899
|
+
const txs = [];
|
|
900
|
+
const steps = [];
|
|
901
|
+
if (expiredIntent) {
|
|
902
|
+
txs.push(
|
|
903
|
+
await readClient.pruneExpiredIntents.prepare({
|
|
904
|
+
depositId: onchainDepositId,
|
|
905
|
+
...escrowArg,
|
|
906
|
+
txOverrides: attribution
|
|
907
|
+
})
|
|
908
|
+
);
|
|
909
|
+
steps.push({
|
|
910
|
+
kind: "pruneExpiredIntents",
|
|
911
|
+
description: "Prune expired buyer intents so the locked amount becomes withdrawable."
|
|
912
|
+
});
|
|
913
|
+
}
|
|
914
|
+
txs.push(
|
|
915
|
+
await readClient.withdrawDeposit.prepare({
|
|
916
|
+
depositId: onchainDepositId,
|
|
917
|
+
...escrowArg,
|
|
918
|
+
txOverrides: attribution
|
|
919
|
+
})
|
|
920
|
+
);
|
|
921
|
+
steps.push({
|
|
922
|
+
kind: "withdrawDeposit",
|
|
923
|
+
description: "Close the order and withdraw all remaining USDC."
|
|
924
|
+
});
|
|
925
|
+
return { txs, steps };
|
|
926
|
+
},
|
|
927
|
+
async topUp(depositId, amount, opts) {
|
|
928
|
+
const client = signingClient("topUp", opts);
|
|
929
|
+
const { onchainDepositId, escrowArg } = await topUpContext(depositId, amount);
|
|
930
|
+
const owner = opts.signer.account.address;
|
|
931
|
+
const escrow = escrowArg.escrowAddress ?? client.escrowV2Address ?? client.escrowAddress;
|
|
932
|
+
await settleAllowance(client, BASE_USDC_ADDRESS, owner, escrow, amount);
|
|
933
|
+
const txHash = await submitAndConfirm(
|
|
934
|
+
client,
|
|
935
|
+
"addFunds",
|
|
936
|
+
() => client.addFunds({
|
|
937
|
+
depositId: onchainDepositId,
|
|
938
|
+
amount,
|
|
939
|
+
...escrowArg,
|
|
940
|
+
txOverrides: attribution
|
|
941
|
+
})
|
|
942
|
+
);
|
|
943
|
+
return { depositId, txHash };
|
|
944
|
+
},
|
|
945
|
+
async prepareTopUp(depositId, amount) {
|
|
946
|
+
const { onchainDepositId, escrowArg } = await topUpContext(depositId, amount);
|
|
947
|
+
const prepared = await readClient.addFunds.prepare({
|
|
948
|
+
depositId: onchainDepositId,
|
|
949
|
+
amount,
|
|
950
|
+
...escrowArg,
|
|
951
|
+
txOverrides: attribution
|
|
952
|
+
});
|
|
953
|
+
const approve = {
|
|
954
|
+
to: BASE_USDC_ADDRESS,
|
|
955
|
+
data: appendAttributionToCalldata(
|
|
956
|
+
encodeFunctionData({
|
|
957
|
+
abi: ERC20_APPROVE_ABI,
|
|
958
|
+
functionName: "approve",
|
|
959
|
+
args: [prepared.to, amount]
|
|
960
|
+
}),
|
|
961
|
+
referrerCodes
|
|
962
|
+
),
|
|
963
|
+
value: 0n,
|
|
964
|
+
chainId: BASE_CHAIN_ID
|
|
965
|
+
};
|
|
966
|
+
return {
|
|
967
|
+
txs: [approve, prepared],
|
|
968
|
+
steps: [
|
|
969
|
+
{
|
|
970
|
+
kind: "approve",
|
|
971
|
+
description: "Approve additional Base USDC for the Peer Cash escrow."
|
|
972
|
+
},
|
|
973
|
+
{
|
|
974
|
+
kind: "addFunds",
|
|
975
|
+
description: "Add USDC to the live cash-out order."
|
|
976
|
+
}
|
|
977
|
+
]
|
|
978
|
+
};
|
|
979
|
+
}
|
|
980
|
+
};
|
|
981
|
+
}
|
|
982
|
+
var bigintString = z.string().regex(/^-?\d+$/, "expected a decimal bigint string");
|
|
983
|
+
var cashOrderStateSchema = z.enum([
|
|
984
|
+
"awaiting-buyer",
|
|
985
|
+
"matched",
|
|
986
|
+
"delivering",
|
|
987
|
+
"delivered",
|
|
988
|
+
"returned"
|
|
989
|
+
]);
|
|
990
|
+
var cashNextActionSchema = z.enum(["wait", "withdraw"]);
|
|
991
|
+
var intentStatusSchema = z.enum(["SIGNALED", "FULFILLED", "PRUNED", "MANUALLY_RELEASED"]);
|
|
992
|
+
var cashFillJsonSchema = z.object({
|
|
993
|
+
intentHash: z.string(),
|
|
994
|
+
status: intentStatusSchema,
|
|
995
|
+
amount: bigintString,
|
|
996
|
+
buyer: z.string(),
|
|
997
|
+
currency: z.string().optional(),
|
|
998
|
+
currencyHash: z.string().optional(),
|
|
999
|
+
rate: z.number().optional(),
|
|
1000
|
+
conversionRate: bigintString.optional(),
|
|
1001
|
+
fiatOwed: z.number().optional(),
|
|
1002
|
+
fiatPaid: z.number().optional(),
|
|
1003
|
+
paidCurrency: z.string().optional(),
|
|
1004
|
+
paymentId: z.string().optional(),
|
|
1005
|
+
paidAt: z.number().optional(),
|
|
1006
|
+
releasedAmount: bigintString.optional(),
|
|
1007
|
+
fillLatencySeconds: z.number().optional(),
|
|
1008
|
+
isExpired: z.boolean().optional(),
|
|
1009
|
+
signaledAt: z.number().optional(),
|
|
1010
|
+
expiresAt: z.number().optional(),
|
|
1011
|
+
fulfilledAt: z.number().optional(),
|
|
1012
|
+
prunedAt: z.number().optional()
|
|
1013
|
+
});
|
|
1014
|
+
var cashPayoutPricingJsonSchema = z.object({
|
|
1015
|
+
spreadBps: z.number().optional(),
|
|
1016
|
+
kind: z.string().optional(),
|
|
1017
|
+
rateSource: z.string().optional(),
|
|
1018
|
+
oracleRate: z.number().optional(),
|
|
1019
|
+
lastOracleUpdatedAt: z.number().optional(),
|
|
1020
|
+
marketRate: z.boolean()
|
|
1021
|
+
});
|
|
1022
|
+
var cashPayoutInfoJsonSchema = z.object({
|
|
1023
|
+
platform: z.string().optional(),
|
|
1024
|
+
platformHash: z.string(),
|
|
1025
|
+
currency: z.string().optional(),
|
|
1026
|
+
currencyHash: z.string().optional(),
|
|
1027
|
+
payeeHash: z.string(),
|
|
1028
|
+
active: z.boolean(),
|
|
1029
|
+
pricing: cashPayoutPricingJsonSchema
|
|
1030
|
+
});
|
|
1031
|
+
var cashBuyerProfileJsonSchema = z.object({
|
|
1032
|
+
address: z.string(),
|
|
1033
|
+
totalIntents: z.number(),
|
|
1034
|
+
fulfilled: z.number(),
|
|
1035
|
+
pruned: z.number(),
|
|
1036
|
+
signaled: z.number(),
|
|
1037
|
+
successRateBps: z.number().optional(),
|
|
1038
|
+
firstSeenAt: z.number().optional(),
|
|
1039
|
+
lastSeenAt: z.number().optional()
|
|
1040
|
+
});
|
|
1041
|
+
var cashOrderJsonSchema = z.object({
|
|
1042
|
+
depositId: z.string(),
|
|
1043
|
+
state: cashOrderStateSchema,
|
|
1044
|
+
fills: z.array(cashFillJsonSchema),
|
|
1045
|
+
totalAmount: bigintString,
|
|
1046
|
+
filledAmount: bigintString,
|
|
1047
|
+
pendingAmount: bigintString,
|
|
1048
|
+
returnedAmount: bigintString,
|
|
1049
|
+
nextActions: z.array(cashNextActionSchema),
|
|
1050
|
+
primaryIntentHash: z.string().optional(),
|
|
1051
|
+
matchedAt: z.number().optional(),
|
|
1052
|
+
deliveredAt: z.number().optional(),
|
|
1053
|
+
updatedAt: z.number().optional(),
|
|
1054
|
+
intentCount: z.number().optional(),
|
|
1055
|
+
payouts: z.array(cashPayoutInfoJsonSchema).optional(),
|
|
1056
|
+
successRateBps: z.number().optional(),
|
|
1057
|
+
isInFlight: z.boolean(),
|
|
1058
|
+
withdrawn: z.boolean().optional()
|
|
1059
|
+
});
|
|
1060
|
+
var cashEstimateJsonSchema = z.object({
|
|
1061
|
+
kind: z.literal("oracle-estimate"),
|
|
1062
|
+
currency: z.string(),
|
|
1063
|
+
amount: bigintString,
|
|
1064
|
+
rate: z.number(),
|
|
1065
|
+
receiveAmount: z.number(),
|
|
1066
|
+
asOf: z.number(),
|
|
1067
|
+
oracleUpdatedAt: z.number().optional(),
|
|
1068
|
+
stale: z.boolean().optional()
|
|
1069
|
+
});
|
|
1070
|
+
var preparedTransactionJsonSchema = z.object({
|
|
1071
|
+
to: z.string(),
|
|
1072
|
+
data: z.string(),
|
|
1073
|
+
value: bigintString,
|
|
1074
|
+
chainId: z.number()
|
|
1075
|
+
});
|
|
1076
|
+
var cashPreparedStepJsonSchema = z.object({
|
|
1077
|
+
kind: z.enum([
|
|
1078
|
+
"approve",
|
|
1079
|
+
"createDeposit",
|
|
1080
|
+
"pruneExpiredIntents",
|
|
1081
|
+
"withdrawDeposit",
|
|
1082
|
+
"removeFunds",
|
|
1083
|
+
"addFunds"
|
|
1084
|
+
]),
|
|
1085
|
+
description: z.string()
|
|
1086
|
+
});
|
|
1087
|
+
var cashoutResultJsonSchema = z.object({
|
|
1088
|
+
depositId: z.string(),
|
|
1089
|
+
txHash: z.string(),
|
|
1090
|
+
escrowAddress: z.string(),
|
|
1091
|
+
onchainDepositId: bigintString,
|
|
1092
|
+
order: cashOrderJsonSchema
|
|
1093
|
+
});
|
|
1094
|
+
var prepareResultJsonSchema = z.object({
|
|
1095
|
+
txs: z.array(preparedTransactionJsonSchema),
|
|
1096
|
+
steps: z.array(cashPreparedStepJsonSchema),
|
|
1097
|
+
register: z.object({ hashedOnchainIds: z.array(z.string()) })
|
|
1098
|
+
});
|
|
1099
|
+
var withdrawResultJsonSchema = z.object({
|
|
1100
|
+
depositId: z.string(),
|
|
1101
|
+
pruneTxHash: z.string().optional(),
|
|
1102
|
+
withdrawTxHash: z.string()
|
|
1103
|
+
});
|
|
1104
|
+
var topUpResultJsonSchema = z.object({
|
|
1105
|
+
depositId: z.string(),
|
|
1106
|
+
txHash: z.string()
|
|
1107
|
+
});
|
|
1108
|
+
var cashCapabilitiesJsonSchema = z.object({
|
|
1109
|
+
chainId: z.number(),
|
|
1110
|
+
token: z.object({ address: z.string(), symbol: z.literal("USDC"), decimals: z.number() }),
|
|
1111
|
+
environment: z.enum(["production", "preproduction", "staging"]),
|
|
1112
|
+
platforms: z.array(
|
|
1113
|
+
z.object({
|
|
1114
|
+
platform: z.string(),
|
|
1115
|
+
currencies: z.array(z.string()),
|
|
1116
|
+
payeeHint: z.string(),
|
|
1117
|
+
requiresIdentityAttestation: z.boolean()
|
|
1118
|
+
})
|
|
1119
|
+
),
|
|
1120
|
+
currencies: z.array(z.string()),
|
|
1121
|
+
amount: z.object({ min: bigintString, recommendedMin: bigintString, max: z.null() }),
|
|
1122
|
+
pricing: z.object({ kind: z.literal("oracle-market-rate"), spreadBps: z.literal(0) })
|
|
1123
|
+
});
|
|
1124
|
+
var cashErrorJsonSchema = z.object({
|
|
1125
|
+
code: z.string(),
|
|
1126
|
+
message: z.string(),
|
|
1127
|
+
retryable: z.boolean(),
|
|
1128
|
+
remediation: z.string()
|
|
1129
|
+
});
|
|
1130
|
+
|
|
1131
|
+
// src/codecs/json.ts
|
|
1132
|
+
function omitUndefined(obj) {
|
|
1133
|
+
return Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== void 0));
|
|
1134
|
+
}
|
|
1135
|
+
function fillToJson(fill) {
|
|
1136
|
+
return omitUndefined({
|
|
1137
|
+
intentHash: fill.intentHash,
|
|
1138
|
+
status: fill.status,
|
|
1139
|
+
amount: fill.amount.toString(),
|
|
1140
|
+
buyer: fill.buyer,
|
|
1141
|
+
currency: fill.currency,
|
|
1142
|
+
currencyHash: fill.currencyHash,
|
|
1143
|
+
rate: fill.rate,
|
|
1144
|
+
conversionRate: fill.conversionRate?.toString(),
|
|
1145
|
+
fiatOwed: fill.fiatOwed,
|
|
1146
|
+
fiatPaid: fill.fiatPaid,
|
|
1147
|
+
paidCurrency: fill.paidCurrency,
|
|
1148
|
+
paymentId: fill.paymentId,
|
|
1149
|
+
paidAt: fill.paidAt,
|
|
1150
|
+
releasedAmount: fill.releasedAmount?.toString(),
|
|
1151
|
+
fillLatencySeconds: fill.fillLatencySeconds,
|
|
1152
|
+
isExpired: fill.isExpired,
|
|
1153
|
+
signaledAt: fill.signaledAt,
|
|
1154
|
+
expiresAt: fill.expiresAt,
|
|
1155
|
+
fulfilledAt: fill.fulfilledAt,
|
|
1156
|
+
prunedAt: fill.prunedAt
|
|
1157
|
+
});
|
|
1158
|
+
}
|
|
1159
|
+
function fillFromJson(json) {
|
|
1160
|
+
return omitUndefined({
|
|
1161
|
+
...json,
|
|
1162
|
+
amount: BigInt(json.amount),
|
|
1163
|
+
conversionRate: json.conversionRate !== void 0 ? BigInt(json.conversionRate) : void 0,
|
|
1164
|
+
releasedAmount: json.releasedAmount !== void 0 ? BigInt(json.releasedAmount) : void 0
|
|
1165
|
+
});
|
|
1166
|
+
}
|
|
1167
|
+
function orderToJson(order) {
|
|
1168
|
+
return omitUndefined({
|
|
1169
|
+
depositId: order.depositId,
|
|
1170
|
+
state: order.state,
|
|
1171
|
+
fills: order.fills.map(fillToJson),
|
|
1172
|
+
totalAmount: order.totalAmount.toString(),
|
|
1173
|
+
filledAmount: order.filledAmount.toString(),
|
|
1174
|
+
pendingAmount: order.pendingAmount.toString(),
|
|
1175
|
+
returnedAmount: order.returnedAmount.toString(),
|
|
1176
|
+
nextActions: order.nextActions,
|
|
1177
|
+
primaryIntentHash: order.primaryIntentHash,
|
|
1178
|
+
matchedAt: order.matchedAt,
|
|
1179
|
+
deliveredAt: order.deliveredAt,
|
|
1180
|
+
updatedAt: order.updatedAt,
|
|
1181
|
+
intentCount: order.intentCount,
|
|
1182
|
+
payouts: order.payouts?.map(
|
|
1183
|
+
(p) => omitUndefined({ ...p, pricing: omitUndefined({ ...p.pricing }) })
|
|
1184
|
+
),
|
|
1185
|
+
successRateBps: order.successRateBps,
|
|
1186
|
+
isInFlight: order.isInFlight,
|
|
1187
|
+
withdrawn: order.withdrawn
|
|
1188
|
+
});
|
|
1189
|
+
}
|
|
1190
|
+
function orderFromJson(json) {
|
|
1191
|
+
const parsed = cashOrderJsonSchema.parse(json);
|
|
1192
|
+
const data = omitUndefined({
|
|
1193
|
+
...parsed,
|
|
1194
|
+
fills: parsed.fills.map(fillFromJson),
|
|
1195
|
+
totalAmount: BigInt(parsed.totalAmount),
|
|
1196
|
+
filledAmount: BigInt(parsed.filledAmount),
|
|
1197
|
+
pendingAmount: BigInt(parsed.pendingAmount),
|
|
1198
|
+
returnedAmount: BigInt(parsed.returnedAmount)
|
|
1199
|
+
});
|
|
1200
|
+
return withExplain(data);
|
|
1201
|
+
}
|
|
1202
|
+
function estimateToJson(estimate) {
|
|
1203
|
+
return { ...estimate, amount: estimate.amount.toString() };
|
|
1204
|
+
}
|
|
1205
|
+
function estimateFromJson(json) {
|
|
1206
|
+
const parsed = cashEstimateJsonSchema.parse(json);
|
|
1207
|
+
return omitUndefined({
|
|
1208
|
+
...parsed,
|
|
1209
|
+
currency: parsed.currency,
|
|
1210
|
+
amount: BigInt(parsed.amount)
|
|
1211
|
+
});
|
|
1212
|
+
}
|
|
1213
|
+
function preparedTxToJson(tx) {
|
|
1214
|
+
return { to: tx.to, data: tx.data, value: tx.value.toString(), chainId: tx.chainId };
|
|
1215
|
+
}
|
|
1216
|
+
function preparedTxFromJson(json) {
|
|
1217
|
+
const parsed = preparedTransactionJsonSchema.parse(json);
|
|
1218
|
+
return {
|
|
1219
|
+
to: parsed.to,
|
|
1220
|
+
data: parsed.data,
|
|
1221
|
+
value: BigInt(parsed.value),
|
|
1222
|
+
chainId: parsed.chainId
|
|
1223
|
+
};
|
|
1224
|
+
}
|
|
1225
|
+
function preparedStepToJson(step) {
|
|
1226
|
+
return { kind: step.kind, description: step.description };
|
|
1227
|
+
}
|
|
1228
|
+
function preparedStepFromJson(json) {
|
|
1229
|
+
return cashPreparedStepJsonSchema.parse(json);
|
|
1230
|
+
}
|
|
1231
|
+
function cashoutResultToJson(result) {
|
|
1232
|
+
return {
|
|
1233
|
+
depositId: result.depositId,
|
|
1234
|
+
txHash: result.txHash,
|
|
1235
|
+
escrowAddress: result.escrowAddress,
|
|
1236
|
+
onchainDepositId: result.onchainDepositId.toString(),
|
|
1237
|
+
order: orderToJson(result.order)
|
|
1238
|
+
};
|
|
1239
|
+
}
|
|
1240
|
+
function cashoutResultFromJson(json) {
|
|
1241
|
+
const parsed = cashoutResultJsonSchema.parse(json);
|
|
1242
|
+
return {
|
|
1243
|
+
depositId: parsed.depositId,
|
|
1244
|
+
txHash: parsed.txHash,
|
|
1245
|
+
escrowAddress: parsed.escrowAddress,
|
|
1246
|
+
onchainDepositId: BigInt(parsed.onchainDepositId),
|
|
1247
|
+
order: orderFromJson(parsed.order)
|
|
1248
|
+
};
|
|
1249
|
+
}
|
|
1250
|
+
function prepareResultToJson(result) {
|
|
1251
|
+
return {
|
|
1252
|
+
txs: result.txs.map(preparedTxToJson),
|
|
1253
|
+
steps: result.steps.map(preparedStepToJson),
|
|
1254
|
+
register: result.register
|
|
1255
|
+
};
|
|
1256
|
+
}
|
|
1257
|
+
function prepareResultFromJson(json) {
|
|
1258
|
+
const parsed = prepareResultJsonSchema.parse(json);
|
|
1259
|
+
return {
|
|
1260
|
+
txs: parsed.txs.map(preparedTxFromJson),
|
|
1261
|
+
steps: parsed.steps.map(preparedStepFromJson),
|
|
1262
|
+
register: parsed.register
|
|
1263
|
+
};
|
|
1264
|
+
}
|
|
1265
|
+
function withdrawResultToJson(result) {
|
|
1266
|
+
return omitUndefined({
|
|
1267
|
+
depositId: result.depositId,
|
|
1268
|
+
pruneTxHash: result.pruneTxHash,
|
|
1269
|
+
withdrawTxHash: result.withdrawTxHash
|
|
1270
|
+
});
|
|
1271
|
+
}
|
|
1272
|
+
function withdrawResultFromJson(json) {
|
|
1273
|
+
const parsed = withdrawResultJsonSchema.parse(json);
|
|
1274
|
+
return omitUndefined({
|
|
1275
|
+
depositId: parsed.depositId,
|
|
1276
|
+
pruneTxHash: parsed.pruneTxHash,
|
|
1277
|
+
withdrawTxHash: parsed.withdrawTxHash
|
|
1278
|
+
});
|
|
1279
|
+
}
|
|
1280
|
+
function buyerProfileToJson(profile) {
|
|
1281
|
+
return omitUndefined({ ...profile });
|
|
1282
|
+
}
|
|
1283
|
+
function buyerProfileFromJson(json) {
|
|
1284
|
+
return omitUndefined(cashBuyerProfileJsonSchema.parse(json));
|
|
1285
|
+
}
|
|
1286
|
+
function topUpResultToJson(result) {
|
|
1287
|
+
return { depositId: result.depositId, txHash: result.txHash };
|
|
1288
|
+
}
|
|
1289
|
+
function topUpResultFromJson(json) {
|
|
1290
|
+
const parsed = topUpResultJsonSchema.parse(json);
|
|
1291
|
+
return { depositId: parsed.depositId, txHash: parsed.txHash };
|
|
1292
|
+
}
|
|
1293
|
+
function capabilitiesToJson(caps) {
|
|
1294
|
+
return {
|
|
1295
|
+
...caps,
|
|
1296
|
+
amount: {
|
|
1297
|
+
min: caps.amount.min.toString(),
|
|
1298
|
+
recommendedMin: caps.amount.recommendedMin.toString(),
|
|
1299
|
+
max: null
|
|
1300
|
+
}
|
|
1301
|
+
};
|
|
1302
|
+
}
|
|
1303
|
+
function capabilitiesFromJson(json) {
|
|
1304
|
+
const parsed = cashCapabilitiesJsonSchema.parse(json);
|
|
1305
|
+
return {
|
|
1306
|
+
...parsed,
|
|
1307
|
+
platforms: parsed.platforms.map((p) => ({
|
|
1308
|
+
...p,
|
|
1309
|
+
currencies: p.currencies
|
|
1310
|
+
})),
|
|
1311
|
+
currencies: parsed.currencies,
|
|
1312
|
+
amount: {
|
|
1313
|
+
min: BigInt(parsed.amount.min),
|
|
1314
|
+
recommendedMin: BigInt(parsed.amount.recommendedMin),
|
|
1315
|
+
max: null
|
|
1316
|
+
}
|
|
1317
|
+
};
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
export { CASH_ATTRIBUTION_CODE, MIN_CASHOUT_AMOUNT, RATE_PRECISION, RECOMMENDED_MIN_CASHOUT_AMOUNT, bigintString, buildCapabilities, buildIntentAmountRange, buildMarketRateCurrencyOverride, buyerProfileFromJson, buyerProfileToJson, capabilitiesFromJson, capabilitiesToJson, cashBuyerProfileJsonSchema, cashCapabilitiesJsonSchema, cashErrorJsonSchema, cashEstimateJsonSchema, cashFillJsonSchema, cashNextActionSchema, cashOrderJsonSchema, cashOrderStateSchema, cashPayoutInfoJsonSchema, cashPayoutPricingJsonSchema, cashPreparedStepJsonSchema, cashoutResultFromJson, cashoutResultJsonSchema, cashoutResultToJson, centsToNumber, createCashClient, deriveBuyerProfile, deriveCashOrder, derivePayouts, estimateFromJson, estimateToJson, explainOrder, fiatFromUsdc, fiatToNumber, fillFromJson, fillToJson, formatUsdc, intentStatusSchema, isFillLive, isMarketRateSupported, orderFromJson, orderToJson, parseCompositeDepositId, prepareCashDepositParams, prepareResultFromJson, prepareResultJsonSchema, prepareResultToJson, preparedStepFromJson, preparedStepToJson, preparedTransactionJsonSchema, preparedTxFromJson, preparedTxToJson, rateToNumber, resolveCashDepositId, topUpResultFromJson, topUpResultJsonSchema, topUpResultToJson, usdc, withExplain, withdrawResultFromJson, withdrawResultJsonSchema, withdrawResultToJson };
|
|
1321
|
+
//# sourceMappingURL=index.js.map
|
|
1322
|
+
//# sourceMappingURL=index.js.map
|