@usdctofiat/offramp 0.2.1 → 1.0.1
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/README.md +37 -85
- package/dist/{chunk-AGP66RQ5.js → chunk-2UENKRGX.js} +219 -444
- package/dist/chunk-2UENKRGX.js.map +1 -0
- package/dist/errors-A8NBr_Iw.d.cts +101 -0
- package/dist/errors-A8NBr_Iw.d.ts +101 -0
- package/dist/index.cjs +265 -470
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +24 -64
- package/dist/index.d.ts +24 -64
- package/dist/index.js +25 -8
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +254 -398
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +5 -20
- package/dist/react.d.ts +5 -20
- package/dist/react.js +10 -27
- package/dist/react.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-AGP66RQ5.js.map +0 -1
- package/dist/errors-DQqv1xfX.d.cts +0 -124
- package/dist/errors-DQqv1xfX.d.ts +0 -124
|
@@ -1,146 +1,11 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
var PLATFORMS = [
|
|
3
|
-
"venmo",
|
|
4
|
-
"cashapp",
|
|
5
|
-
"chime",
|
|
6
|
-
"revolut",
|
|
7
|
-
"wise",
|
|
8
|
-
"mercadopago",
|
|
9
|
-
"zelle",
|
|
10
|
-
"paypal",
|
|
11
|
-
"monzo",
|
|
12
|
-
"n26"
|
|
13
|
-
];
|
|
14
|
-
var PAYMENT_PLATFORMS = {
|
|
15
|
-
VENMO: "venmo",
|
|
16
|
-
CASHAPP: "cashapp",
|
|
17
|
-
CHIME: "chime",
|
|
18
|
-
REVOLUT: "revolut",
|
|
19
|
-
WISE: "wise",
|
|
20
|
-
MERCADO_PAGO: "mercadopago",
|
|
21
|
-
ZELLE: "zelle",
|
|
22
|
-
PAYPAL: "paypal",
|
|
23
|
-
MONZO: "monzo",
|
|
24
|
-
N26: "n26"
|
|
25
|
-
};
|
|
26
|
-
var SUPPORTED_CURRENCIES = [
|
|
27
|
-
"AED",
|
|
28
|
-
"ARS",
|
|
29
|
-
"AUD",
|
|
30
|
-
"BRL",
|
|
31
|
-
"CAD",
|
|
32
|
-
"CHF",
|
|
33
|
-
"CLP",
|
|
34
|
-
"CNY",
|
|
35
|
-
"COP",
|
|
36
|
-
"CZK",
|
|
37
|
-
"DKK",
|
|
38
|
-
"EUR",
|
|
39
|
-
"GBP",
|
|
40
|
-
"HKD",
|
|
41
|
-
"HUF",
|
|
42
|
-
"IDR",
|
|
43
|
-
"ILS",
|
|
44
|
-
"INR",
|
|
45
|
-
"JPY",
|
|
46
|
-
"KES",
|
|
47
|
-
"KRW",
|
|
48
|
-
"MXN",
|
|
49
|
-
"MYR",
|
|
50
|
-
"NOK",
|
|
51
|
-
"NZD",
|
|
52
|
-
"PEN",
|
|
53
|
-
"PHP",
|
|
54
|
-
"PLN",
|
|
55
|
-
"RON",
|
|
56
|
-
"SAR",
|
|
57
|
-
"SEK",
|
|
58
|
-
"SGD",
|
|
59
|
-
"THB",
|
|
60
|
-
"TRY",
|
|
61
|
-
"TWD",
|
|
62
|
-
"UGX",
|
|
63
|
-
"USD",
|
|
64
|
-
"VND",
|
|
65
|
-
"ZAR"
|
|
66
|
-
];
|
|
67
|
-
var CURRENCIES = {
|
|
68
|
-
AED: "AED",
|
|
69
|
-
ARS: "ARS",
|
|
70
|
-
AUD: "AUD",
|
|
71
|
-
BRL: "BRL",
|
|
72
|
-
CAD: "CAD",
|
|
73
|
-
CHF: "CHF",
|
|
74
|
-
CLP: "CLP",
|
|
75
|
-
CNY: "CNY",
|
|
76
|
-
COP: "COP",
|
|
77
|
-
CZK: "CZK",
|
|
78
|
-
DKK: "DKK",
|
|
79
|
-
EUR: "EUR",
|
|
80
|
-
GBP: "GBP",
|
|
81
|
-
HKD: "HKD",
|
|
82
|
-
HUF: "HUF",
|
|
83
|
-
IDR: "IDR",
|
|
84
|
-
ILS: "ILS",
|
|
85
|
-
INR: "INR",
|
|
86
|
-
JPY: "JPY",
|
|
87
|
-
KES: "KES",
|
|
88
|
-
KRW: "KRW",
|
|
89
|
-
MXN: "MXN",
|
|
90
|
-
MYR: "MYR",
|
|
91
|
-
NOK: "NOK",
|
|
92
|
-
NZD: "NZD",
|
|
93
|
-
PEN: "PEN",
|
|
94
|
-
PHP: "PHP",
|
|
95
|
-
PLN: "PLN",
|
|
96
|
-
RON: "RON",
|
|
97
|
-
SAR: "SAR",
|
|
98
|
-
SEK: "SEK",
|
|
99
|
-
SGD: "SGD",
|
|
100
|
-
THB: "THB",
|
|
101
|
-
TRY: "TRY",
|
|
102
|
-
TWD: "TWD",
|
|
103
|
-
UGX: "UGX",
|
|
104
|
-
USD: "USD",
|
|
105
|
-
VND: "VND",
|
|
106
|
-
ZAR: "ZAR"
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
// src/errors.ts
|
|
110
|
-
var OfframpError = class extends Error {
|
|
111
|
-
code;
|
|
112
|
-
step;
|
|
113
|
-
cause;
|
|
114
|
-
txHash;
|
|
115
|
-
depositId;
|
|
116
|
-
constructor(message, code, step, cause, details) {
|
|
117
|
-
super(message);
|
|
118
|
-
this.name = "OfframpError";
|
|
119
|
-
this.code = code;
|
|
120
|
-
this.step = step;
|
|
121
|
-
this.cause = cause;
|
|
122
|
-
this.txHash = details?.txHash;
|
|
123
|
-
this.depositId = details?.depositId;
|
|
124
|
-
}
|
|
125
|
-
};
|
|
126
|
-
function isUserCancellation(error) {
|
|
127
|
-
if (!(error instanceof Error)) return false;
|
|
128
|
-
const msg = error.message.toLowerCase();
|
|
129
|
-
return msg.includes("user rejected") || msg.includes("user denied") || msg.includes("user cancelled") || msg.includes("rejected the request") || msg.includes("action_rejected");
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// src/client.ts
|
|
133
|
-
import { formatUnits as formatUnits2 } from "viem";
|
|
134
|
-
import { classifyDelegationState, currencyInfo as currencyInfo2, defaultIndexerEndpoint, getCurrencyInfoFromHash as getCurrencyInfoFromHash2, IndexerClient, IndexerDepositService } from "@zkp2p/sdk";
|
|
135
|
-
|
|
136
|
-
// src/deposit.ts
|
|
137
|
-
import { createPublicClient, decodeEventLog, formatUnits, http, parseUnits } from "viem";
|
|
138
|
-
import { base } from "viem/chains";
|
|
1
|
+
// src/platforms.ts
|
|
139
2
|
import {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
3
|
+
currencyInfo,
|
|
4
|
+
getCurrencyInfoFromHash,
|
|
5
|
+
getPaymentMethodsCatalog,
|
|
6
|
+
resolvePaymentMethodHash
|
|
143
7
|
} from "@zkp2p/sdk";
|
|
8
|
+
import { z } from "zod";
|
|
144
9
|
|
|
145
10
|
// src/config.ts
|
|
146
11
|
import { getContracts, getGatingServiceAddress } from "@zkp2p/sdk";
|
|
@@ -165,15 +30,8 @@ var INDEXER_MAX_DELAY_MS = 1e4;
|
|
|
165
30
|
var PAYEE_REGISTRATION_TIMEOUT_MS = 8e3;
|
|
166
31
|
|
|
167
32
|
// src/platforms.ts
|
|
168
|
-
import {
|
|
169
|
-
currencyInfo,
|
|
170
|
-
getCurrencyInfoFromHash,
|
|
171
|
-
getPaymentMethodsCatalog,
|
|
172
|
-
resolvePaymentMethodHash
|
|
173
|
-
} from "@zkp2p/sdk";
|
|
174
|
-
import { z } from "zod";
|
|
175
|
-
var ZELLE_HASH_LOOKUP_NAMES = ["zelle", "zelle-bofa", "zelle-chase", "zelle-citi"];
|
|
176
33
|
var PAYMENT_CATALOG = getPaymentMethodsCatalog(BASE_CHAIN_ID, RUNTIME_ENV);
|
|
34
|
+
var ZELLE_HASH_LOOKUP_NAMES = ["zelle", "zelle-bofa", "zelle-chase", "zelle-citi"];
|
|
177
35
|
var FALLBACK_CURRENCIES = {
|
|
178
36
|
venmo: ["USD"],
|
|
179
37
|
cashapp: ["USD"],
|
|
@@ -205,142 +63,62 @@ function resolveSupportedCurrencies(platform) {
|
|
|
205
63
|
}
|
|
206
64
|
return Array.from(codes).sort();
|
|
207
65
|
}
|
|
208
|
-
var
|
|
209
|
-
venmo: {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
},
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
placeholder: "cashtag (no $)",
|
|
223
|
-
helperText: "Cashtag without $ (publicly discoverable)",
|
|
224
|
-
validation: z.string().min(1).regex(/^[a-zA-Z0-9]+$/),
|
|
225
|
-
transform: (v) => v.replace(/^\$+/, "")
|
|
226
|
-
},
|
|
227
|
-
chime: {
|
|
228
|
-
id: "chime",
|
|
229
|
-
name: "Chime",
|
|
230
|
-
identifierLabel: "ChimeSign",
|
|
231
|
-
placeholder: "$chimesign",
|
|
232
|
-
helperText: "ChimeSign with $ (must be discoverable)",
|
|
233
|
-
validation: z.string().min(2).regex(/^\$[a-zA-Z0-9]+$/),
|
|
234
|
-
transform: (v) => {
|
|
235
|
-
const t = v.trim().toLowerCase();
|
|
236
|
-
return t.startsWith("$") ? t : `$${t}`;
|
|
237
|
-
}
|
|
238
|
-
},
|
|
239
|
-
revolut: {
|
|
240
|
-
id: "revolut",
|
|
241
|
-
name: "Revolut",
|
|
242
|
-
identifierLabel: "Revtag",
|
|
243
|
-
placeholder: "revtag (no @)",
|
|
244
|
-
helperText: "Revtag without @ (must be public)",
|
|
245
|
-
validation: z.string().min(1).regex(/^[a-zA-Z0-9]+$/),
|
|
246
|
-
transform: (v) => v.replace(/^@+/, "").trim()
|
|
247
|
-
},
|
|
248
|
-
wise: {
|
|
249
|
-
id: "wise",
|
|
250
|
-
name: "Wise",
|
|
251
|
-
identifierLabel: "Wisetag",
|
|
252
|
-
placeholder: "wisetag (no @)",
|
|
253
|
-
helperText: "Your Wise @wisetag (no @)",
|
|
254
|
-
validation: z.string().min(1).regex(/^[a-zA-Z0-9_-]+$/),
|
|
255
|
-
transform: (v) => v.replace(/^@+/, "").trim()
|
|
256
|
-
},
|
|
257
|
-
mercadopago: {
|
|
258
|
-
id: "mercadopago",
|
|
259
|
-
name: "Mercado Pago",
|
|
260
|
-
identifierLabel: "CVU",
|
|
261
|
-
placeholder: "22-digit CVU",
|
|
262
|
-
helperText: "CVU must be exactly 22 digits",
|
|
263
|
-
validation: z.string().length(22).regex(/^\d{22}$/)
|
|
264
|
-
},
|
|
265
|
-
zelle: {
|
|
266
|
-
id: "zelle",
|
|
267
|
-
name: "Zelle",
|
|
268
|
-
identifierLabel: "Email",
|
|
269
|
-
placeholder: "email",
|
|
270
|
-
helperText: "Registered Zelle email",
|
|
271
|
-
validation: z.string().email()
|
|
272
|
-
},
|
|
273
|
-
paypal: {
|
|
274
|
-
id: "paypal",
|
|
275
|
-
name: "PayPal",
|
|
276
|
-
identifierLabel: "Email",
|
|
277
|
-
placeholder: "email",
|
|
278
|
-
helperText: "Email linked to PayPal account",
|
|
279
|
-
validation: z.string().email()
|
|
280
|
-
},
|
|
281
|
-
monzo: {
|
|
282
|
-
id: "monzo",
|
|
283
|
-
name: "Monzo",
|
|
284
|
-
identifierLabel: "Username",
|
|
285
|
-
placeholder: "monzo.me username",
|
|
286
|
-
helperText: "Your Monzo.me username",
|
|
287
|
-
validation: z.string().min(1).regex(/^[a-zA-Z0-9_-]+$/)
|
|
288
|
-
},
|
|
289
|
-
n26: {
|
|
290
|
-
id: "n26",
|
|
291
|
-
name: "N26",
|
|
292
|
-
identifierLabel: "IBAN",
|
|
293
|
-
placeholder: "IBAN (e.g. DE89...)",
|
|
294
|
-
helperText: "Your IBAN (spaces will be removed)",
|
|
295
|
-
validation: z.string().min(15).max(34).regex(/^[A-Z]{2}[0-9]{2}[A-Z0-9]+$/i),
|
|
296
|
-
transform: (v) => v.replace(/\s/g, "").toUpperCase()
|
|
297
|
-
}
|
|
66
|
+
var BLUEPRINTS = {
|
|
67
|
+
venmo: { id: "venmo", name: "Venmo", identifierLabel: "Username", placeholder: "venmo username (no @)", helperText: "Username without @ (publicly discoverable)", validation: z.string().min(1).regex(/^[a-zA-Z0-9_-]+$/), transform: (v) => v.replace(/^@+/, "") },
|
|
68
|
+
cashapp: { id: "cashapp", name: "Cash App", identifierLabel: "Cashtag", placeholder: "cashtag (no $)", helperText: "Cashtag without $ (publicly discoverable)", validation: z.string().min(1).regex(/^[a-zA-Z0-9]+$/), transform: (v) => v.replace(/^\$+/, "") },
|
|
69
|
+
chime: { id: "chime", name: "Chime", identifierLabel: "ChimeSign", placeholder: "$chimesign", helperText: "ChimeSign with $ (must be discoverable)", validation: z.string().min(2).regex(/^\$[a-zA-Z0-9]+$/), transform: (v) => {
|
|
70
|
+
const t = v.trim().toLowerCase();
|
|
71
|
+
return t.startsWith("$") ? t : `$${t}`;
|
|
72
|
+
} },
|
|
73
|
+
revolut: { id: "revolut", name: "Revolut", identifierLabel: "Revtag", placeholder: "revtag (no @)", helperText: "Revtag without @ (must be public)", validation: z.string().min(1).regex(/^[a-zA-Z0-9]+$/), transform: (v) => v.replace(/^@+/, "").trim() },
|
|
74
|
+
wise: { id: "wise", name: "Wise", identifierLabel: "Wisetag", placeholder: "wisetag (no @)", helperText: "Your Wise @wisetag (no @)", validation: z.string().min(1).regex(/^[a-zA-Z0-9_-]+$/), transform: (v) => v.replace(/^@+/, "").trim() },
|
|
75
|
+
mercadopago: { id: "mercadopago", name: "Mercado Pago", identifierLabel: "CVU", placeholder: "22-digit CVU", helperText: "CVU must be exactly 22 digits", validation: z.string().length(22).regex(/^\d{22}$/) },
|
|
76
|
+
zelle: { id: "zelle", name: "Zelle", identifierLabel: "Email", placeholder: "email", helperText: "Registered Zelle email", validation: z.string().email() },
|
|
77
|
+
paypal: { id: "paypal", name: "PayPal", identifierLabel: "Email", placeholder: "email", helperText: "Email linked to PayPal account", validation: z.string().email() },
|
|
78
|
+
monzo: { id: "monzo", name: "Monzo", identifierLabel: "Username", placeholder: "monzo.me username", helperText: "Your Monzo.me username", validation: z.string().min(1).regex(/^[a-zA-Z0-9_-]+$/) },
|
|
79
|
+
n26: { id: "n26", name: "N26", identifierLabel: "IBAN", placeholder: "IBAN (e.g. DE89...)", helperText: "Your IBAN (spaces will be removed)", validation: z.string().min(15).max(34).regex(/^[A-Z]{2}[0-9]{2}[A-Z0-9]+$/i), transform: (v) => v.replace(/\s/g, "").toUpperCase() }
|
|
298
80
|
};
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
});
|
|
320
|
-
}
|
|
321
|
-
function getCurrencies(platform) {
|
|
322
|
-
return CONFIGS[platform]?.currencies ?? [];
|
|
323
|
-
}
|
|
324
|
-
function validateIdentifier(platform, value) {
|
|
325
|
-
const cfg = CONFIGS[platform];
|
|
326
|
-
if (!cfg) return { valid: false, normalized: value, error: "Unsupported platform" };
|
|
327
|
-
const transformed = cfg.transform ? cfg.transform(value) : value;
|
|
328
|
-
const result = cfg.validation.safeParse(transformed);
|
|
329
|
-
if (!result.success) {
|
|
330
|
-
return { valid: false, normalized: transformed, error: result.error.issues[0]?.message || "Invalid input" };
|
|
331
|
-
}
|
|
332
|
-
return { valid: true, normalized: transformed };
|
|
333
|
-
}
|
|
334
|
-
function isSupportedCurrency(platform, currency) {
|
|
335
|
-
return CONFIGS[platform]?.currencies.includes(currency) ?? false;
|
|
81
|
+
function buildPlatformEntry(bp) {
|
|
82
|
+
const currencies = resolveSupportedCurrencies(bp.id);
|
|
83
|
+
return {
|
|
84
|
+
id: bp.id,
|
|
85
|
+
name: bp.name,
|
|
86
|
+
currencies,
|
|
87
|
+
identifier: {
|
|
88
|
+
label: bp.identifierLabel,
|
|
89
|
+
placeholder: bp.placeholder,
|
|
90
|
+
help: bp.helperText
|
|
91
|
+
},
|
|
92
|
+
validate(input) {
|
|
93
|
+
const transformed = bp.transform ? bp.transform(input) : input;
|
|
94
|
+
const result = bp.validation.safeParse(transformed);
|
|
95
|
+
if (!result.success) {
|
|
96
|
+
return { valid: false, normalized: transformed, error: result.error.issues[0]?.message || "Invalid input" };
|
|
97
|
+
}
|
|
98
|
+
return { valid: true, normalized: transformed };
|
|
99
|
+
}
|
|
100
|
+
};
|
|
336
101
|
}
|
|
102
|
+
var PLATFORMS = {
|
|
103
|
+
VENMO: buildPlatformEntry(BLUEPRINTS.venmo),
|
|
104
|
+
CASHAPP: buildPlatformEntry(BLUEPRINTS.cashapp),
|
|
105
|
+
CHIME: buildPlatformEntry(BLUEPRINTS.chime),
|
|
106
|
+
REVOLUT: buildPlatformEntry(BLUEPRINTS.revolut),
|
|
107
|
+
WISE: buildPlatformEntry(BLUEPRINTS.wise),
|
|
108
|
+
MERCADO_PAGO: buildPlatformEntry(BLUEPRINTS.mercadopago),
|
|
109
|
+
ZELLE: buildPlatformEntry(BLUEPRINTS.zelle),
|
|
110
|
+
PAYPAL: buildPlatformEntry(BLUEPRINTS.paypal),
|
|
111
|
+
MONZO: buildPlatformEntry(BLUEPRINTS.monzo),
|
|
112
|
+
N26: buildPlatformEntry(BLUEPRINTS.n26)
|
|
113
|
+
};
|
|
337
114
|
function normalizePaymentMethodLookupName(platform) {
|
|
338
115
|
const normalized = platform.trim().toLowerCase();
|
|
339
116
|
if (!normalized) return null;
|
|
340
117
|
if (ZELLE_HASH_LOOKUP_NAMES.includes(normalized)) {
|
|
341
118
|
return normalized;
|
|
342
119
|
}
|
|
343
|
-
|
|
120
|
+
const ids = Object.values(PLATFORMS).map((p) => p.id);
|
|
121
|
+
return ids.includes(normalized) ? normalized : null;
|
|
344
122
|
}
|
|
345
123
|
function resolveCanonicalZelleHash() {
|
|
346
124
|
const direct = PAYMENT_CATALOG.zelle?.paymentMethodHash;
|
|
@@ -403,7 +181,41 @@ function buildDepositData(platform, identifier) {
|
|
|
403
181
|
}
|
|
404
182
|
}
|
|
405
183
|
|
|
184
|
+
// src/errors.ts
|
|
185
|
+
var OfframpError = class extends Error {
|
|
186
|
+
code;
|
|
187
|
+
step;
|
|
188
|
+
cause;
|
|
189
|
+
txHash;
|
|
190
|
+
depositId;
|
|
191
|
+
constructor(message, code, step, cause, details) {
|
|
192
|
+
super(message);
|
|
193
|
+
this.name = "OfframpError";
|
|
194
|
+
this.code = code;
|
|
195
|
+
this.step = step;
|
|
196
|
+
this.cause = cause;
|
|
197
|
+
this.txHash = details?.txHash;
|
|
198
|
+
this.depositId = details?.depositId;
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
function isUserCancellation(error) {
|
|
202
|
+
if (!(error instanceof Error)) return false;
|
|
203
|
+
const msg = error.message.toLowerCase();
|
|
204
|
+
return msg.includes("user rejected") || msg.includes("user denied") || msg.includes("user cancelled") || msg.includes("rejected the request") || msg.includes("action_rejected");
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// src/queries.ts
|
|
208
|
+
import { formatUnits as formatUnits2 } from "viem";
|
|
209
|
+
import { classifyDelegationState, defaultIndexerEndpoint, getCurrencyInfoFromHash as getCurrencyInfoFromHash2, IndexerClient, IndexerDepositService } from "@zkp2p/sdk";
|
|
210
|
+
|
|
406
211
|
// src/deposit.ts
|
|
212
|
+
import { createPublicClient, decodeEventLog, formatUnits, http, parseUnits } from "viem";
|
|
213
|
+
import { base } from "viem/chains";
|
|
214
|
+
import {
|
|
215
|
+
OfframpClient,
|
|
216
|
+
getSpreadOracleConfig,
|
|
217
|
+
mapConversionRatesToOnchainMinRate
|
|
218
|
+
} from "@zkp2p/sdk";
|
|
407
219
|
function usdcToUnits(amount) {
|
|
408
220
|
return parseUnits(amount, 6);
|
|
409
221
|
}
|
|
@@ -485,6 +297,12 @@ function attachOracleConfig(entries, conversionRates) {
|
|
|
485
297
|
})
|
|
486
298
|
);
|
|
487
299
|
}
|
|
300
|
+
function extractTxHash(result) {
|
|
301
|
+
if (typeof result === "string") return result;
|
|
302
|
+
if (result && typeof result === "object" && "hash" in result) return result.hash;
|
|
303
|
+
if (result && typeof result === "object" && "transactionHash" in result) return result.transactionHash;
|
|
304
|
+
throw new Error("Unexpected transaction result format");
|
|
305
|
+
}
|
|
488
306
|
function createSdkClient(walletClient) {
|
|
489
307
|
return new OfframpClient({
|
|
490
308
|
walletClient,
|
|
@@ -494,28 +312,84 @@ function createSdkClient(walletClient) {
|
|
|
494
312
|
baseApiUrl: API_BASE_URL
|
|
495
313
|
});
|
|
496
314
|
}
|
|
497
|
-
async function
|
|
315
|
+
async function findUndelegatedDeposit(walletAddress) {
|
|
316
|
+
try {
|
|
317
|
+
const service = getIndexerService();
|
|
318
|
+
const raw = await service.fetchDepositsWithRelations(
|
|
319
|
+
{ depositor: walletAddress },
|
|
320
|
+
{ limit: 50 }
|
|
321
|
+
);
|
|
322
|
+
const escrowLower = ESCROW_ADDRESS.toLowerCase();
|
|
323
|
+
const undelegated = (raw || []).filter((d) => {
|
|
324
|
+
if (d.status === "CLOSED") return false;
|
|
325
|
+
if (d.escrowAddress.toLowerCase() !== escrowLower) return false;
|
|
326
|
+
const remaining = (() => {
|
|
327
|
+
try {
|
|
328
|
+
return BigInt(d.remainingDeposits || "0");
|
|
329
|
+
} catch {
|
|
330
|
+
return 0n;
|
|
331
|
+
}
|
|
332
|
+
})();
|
|
333
|
+
if (remaining === 0n) return false;
|
|
334
|
+
return d.rateManagerId !== DELEGATE_RATE_MANAGER_ID;
|
|
335
|
+
});
|
|
336
|
+
undelegated.sort((a, b) => Number(BigInt(b.depositId) - BigInt(a.depositId)));
|
|
337
|
+
return undelegated[0] ?? null;
|
|
338
|
+
} catch {
|
|
339
|
+
return null;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
async function offramp(walletClient, params, onProgress) {
|
|
498
343
|
const { amount, platform, currency, identifier } = params;
|
|
344
|
+
const platformId = platform.id;
|
|
345
|
+
const currencyCode = currency.code;
|
|
346
|
+
if (!walletClient.account?.address) {
|
|
347
|
+
throw new OfframpError("Wallet client has no account. Connect a wallet first.", "VALIDATION");
|
|
348
|
+
}
|
|
349
|
+
const walletAddress = walletClient.account.address;
|
|
499
350
|
const amt = parseFloat(amount);
|
|
500
351
|
if (!Number.isFinite(amt) || amt < MIN_DEPOSIT_USDC) {
|
|
501
352
|
throw new OfframpError(`Minimum deposit is ${MIN_DEPOSIT_USDC} USDC`, "VALIDATION");
|
|
502
353
|
}
|
|
503
|
-
if (!
|
|
504
|
-
throw new OfframpError(`${
|
|
354
|
+
if (!platform.currencies.includes(currencyCode)) {
|
|
355
|
+
throw new OfframpError(`${currencyCode} is not supported on ${platform.name}`, "UNSUPPORTED");
|
|
505
356
|
}
|
|
506
|
-
const validation =
|
|
357
|
+
const validation = platform.validate(identifier);
|
|
507
358
|
if (!validation.valid) {
|
|
508
359
|
throw new OfframpError(validation.error || "Invalid identifier", "VALIDATION");
|
|
509
360
|
}
|
|
510
361
|
const normalizedIdentifier = validation.normalized;
|
|
511
|
-
const methodHash = getPaymentMethodHash(
|
|
362
|
+
const methodHash = getPaymentMethodHash(platformId);
|
|
512
363
|
if (!methodHash) {
|
|
513
|
-
throw new OfframpError(`${platform} is not currently supported`, "UNSUPPORTED");
|
|
364
|
+
throw new OfframpError(`${platform.name} is not currently supported`, "UNSUPPORTED");
|
|
514
365
|
}
|
|
515
|
-
|
|
516
|
-
|
|
366
|
+
const existing = await findUndelegatedDeposit(walletAddress);
|
|
367
|
+
if (existing) {
|
|
368
|
+
onProgress?.({ step: "resuming", depositId: existing.depositId });
|
|
369
|
+
const client2 = createSdkClient(walletClient);
|
|
370
|
+
const txOverrides2 = { referrer: [REFERRER] };
|
|
371
|
+
try {
|
|
372
|
+
const result = await client2.setRateManager({
|
|
373
|
+
depositId: BigInt(existing.depositId),
|
|
374
|
+
rateManagerAddress: RATE_MANAGER_REGISTRY_ADDRESS,
|
|
375
|
+
rateManagerId: DELEGATE_RATE_MANAGER_ID,
|
|
376
|
+
escrowAddress: existing.escrowAddress,
|
|
377
|
+
txOverrides: txOverrides2
|
|
378
|
+
});
|
|
379
|
+
const txHash = extractTxHash(result);
|
|
380
|
+
onProgress?.({ step: "done", txHash, depositId: existing.depositId });
|
|
381
|
+
return { depositId: existing.depositId, txHash, resumed: true };
|
|
382
|
+
} catch (err) {
|
|
383
|
+
if (isUserCancellation(err)) throw new OfframpError("User cancelled", "USER_CANCELLED", "resuming", err);
|
|
384
|
+
throw new OfframpError(
|
|
385
|
+
"Found undelegated deposit but delegation failed. Try again.",
|
|
386
|
+
"DELEGATION_FAILED",
|
|
387
|
+
"resuming",
|
|
388
|
+
err,
|
|
389
|
+
{ depositId: existing.depositId, txHash: existing.txHash }
|
|
390
|
+
);
|
|
391
|
+
}
|
|
517
392
|
}
|
|
518
|
-
const walletAddress = walletClient.account.address;
|
|
519
393
|
const truncatedAmount = amt.toFixed(6).replace(/\.?0+$/, "");
|
|
520
394
|
const amountUnits = usdcToUnits(truncatedAmount);
|
|
521
395
|
const minUnits = usdcToUnits(String(MIN_ORDER_USDC));
|
|
@@ -530,10 +404,7 @@ async function createOfframpDeposit(walletClient, params, onProgress) {
|
|
|
530
404
|
});
|
|
531
405
|
if (balance < amountUnits) {
|
|
532
406
|
const available = Number(formatUnits(balance, 6));
|
|
533
|
-
throw new OfframpError(
|
|
534
|
-
`Insufficient USDC balance. Have ${available.toFixed(2)}, need ${truncatedAmount}.`,
|
|
535
|
-
"VALIDATION"
|
|
536
|
-
);
|
|
407
|
+
throw new OfframpError(`Insufficient USDC balance. Have ${available.toFixed(2)}, need ${truncatedAmount}.`, "VALIDATION");
|
|
537
408
|
}
|
|
538
409
|
} catch (err) {
|
|
539
410
|
if (err instanceof OfframpError) throw err;
|
|
@@ -557,15 +428,15 @@ async function createOfframpDeposit(walletClient, params, onProgress) {
|
|
|
557
428
|
onProgress?.({ step: "registering" });
|
|
558
429
|
let hashedOnchainId;
|
|
559
430
|
try {
|
|
560
|
-
const canonicalName =
|
|
561
|
-
const depositData = buildDepositData(
|
|
431
|
+
const canonicalName = platformId.startsWith("zelle") ? "zelle" : platformId;
|
|
432
|
+
const depositData = buildDepositData(platformId, normalizedIdentifier);
|
|
562
433
|
hashedOnchainId = await registerPayeeDetails(canonicalName, depositData);
|
|
563
434
|
} catch (err) {
|
|
564
435
|
throw new OfframpError("Payee registration failed", "REGISTRATION_FAILED", "registering", err);
|
|
565
436
|
}
|
|
566
437
|
onProgress?.({ step: "depositing" });
|
|
567
438
|
const conversionRates = [
|
|
568
|
-
[{ currency, conversionRate: "1" }]
|
|
439
|
+
[{ currency: currencyCode, conversionRate: "1" }]
|
|
569
440
|
];
|
|
570
441
|
const baseCurrenciesOverride = mapConversionRatesToOnchainMinRate(conversionRates, 1);
|
|
571
442
|
const currenciesOverride = attachOracleConfig(baseCurrenciesOverride, conversionRates);
|
|
@@ -576,8 +447,8 @@ async function createOfframpDeposit(walletClient, params, onProgress) {
|
|
|
576
447
|
amount: amountUnits,
|
|
577
448
|
retainOnEmpty: false,
|
|
578
449
|
intentAmountRange: { min: minUnits, max: maxUnits },
|
|
579
|
-
processorNames: [
|
|
580
|
-
depositData: [buildDepositData(
|
|
450
|
+
processorNames: [platformId],
|
|
451
|
+
depositData: [buildDepositData(platformId, normalizedIdentifier)],
|
|
581
452
|
conversionRates,
|
|
582
453
|
paymentMethodsOverride: [methodHash],
|
|
583
454
|
paymentMethodDataOverride: [{
|
|
@@ -607,29 +478,27 @@ async function createOfframpDeposit(walletClient, params, onProgress) {
|
|
|
607
478
|
}
|
|
608
479
|
}
|
|
609
480
|
if (!depositId) {
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
break;
|
|
622
|
-
}
|
|
623
|
-
} catch {
|
|
481
|
+
let delay = INDEXER_INITIAL_DELAY_MS;
|
|
482
|
+
for (let attempt = 0; attempt < INDEXER_MAX_ATTEMPTS && !depositId; attempt++) {
|
|
483
|
+
try {
|
|
484
|
+
const deps = await client.indexer.getDepositsWithRelations(
|
|
485
|
+
{ depositor: walletAddress },
|
|
486
|
+
{ limit: 25 }
|
|
487
|
+
);
|
|
488
|
+
const hit = deps.find((d) => (d?.txHash || "").toLowerCase() === hash.toLowerCase());
|
|
489
|
+
if (hit) {
|
|
490
|
+
depositId = String(hit.depositId);
|
|
491
|
+
break;
|
|
624
492
|
}
|
|
625
|
-
|
|
626
|
-
delay = Math.min(INDEXER_MAX_DELAY_MS, Math.floor(delay * 1.7));
|
|
493
|
+
} catch {
|
|
627
494
|
}
|
|
495
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
496
|
+
delay = Math.min(INDEXER_MAX_DELAY_MS, Math.floor(delay * 1.7));
|
|
628
497
|
}
|
|
629
498
|
}
|
|
630
499
|
if (!depositId) {
|
|
631
500
|
throw new OfframpError(
|
|
632
|
-
"Deposit created on-chain but could not confirm deposit ID. Your funds are safe.
|
|
501
|
+
"Deposit created on-chain but could not confirm deposit ID. Your funds are safe. Call offramp() again to resume delegation.",
|
|
633
502
|
"CONFIRMATION_FAILED",
|
|
634
503
|
"confirming",
|
|
635
504
|
void 0,
|
|
@@ -650,7 +519,7 @@ async function createOfframpDeposit(walletClient, params, onProgress) {
|
|
|
650
519
|
throw new OfframpError("User cancelled delegation", "USER_CANCELLED", "delegating", delegationError, { txHash: hash, depositId });
|
|
651
520
|
}
|
|
652
521
|
throw new OfframpError(
|
|
653
|
-
"Deposit created but delegation failed.
|
|
522
|
+
"Deposit created but delegation failed. Call offramp() again to resume delegation.",
|
|
654
523
|
"DELEGATION_FAILED",
|
|
655
524
|
"delegating",
|
|
656
525
|
delegationError,
|
|
@@ -658,18 +527,18 @@ async function createOfframpDeposit(walletClient, params, onProgress) {
|
|
|
658
527
|
);
|
|
659
528
|
}
|
|
660
529
|
onProgress?.({ step: "done", txHash: hash, depositId });
|
|
661
|
-
return { depositId, txHash: hash };
|
|
530
|
+
return { depositId, txHash: hash, resumed: false };
|
|
662
531
|
}
|
|
663
532
|
|
|
664
|
-
// src/
|
|
665
|
-
var
|
|
533
|
+
// src/queries.ts
|
|
534
|
+
var indexerService = null;
|
|
666
535
|
function getIndexerService() {
|
|
667
|
-
if (!
|
|
536
|
+
if (!indexerService) {
|
|
668
537
|
const endpoint = defaultIndexerEndpoint("PRODUCTION");
|
|
669
538
|
const client = new IndexerClient(endpoint);
|
|
670
|
-
|
|
539
|
+
indexerService = new IndexerDepositService(client);
|
|
671
540
|
}
|
|
672
|
-
return
|
|
541
|
+
return indexerService;
|
|
673
542
|
}
|
|
674
543
|
function toBigInt(value) {
|
|
675
544
|
try {
|
|
@@ -690,10 +559,10 @@ function resolveMethodNames(hashes) {
|
|
|
690
559
|
const names = /* @__PURE__ */ new Set();
|
|
691
560
|
for (const { paymentMethodHash } of hashes) {
|
|
692
561
|
const normalized = paymentMethodHash.toLowerCase();
|
|
693
|
-
for (const platform of PLATFORMS) {
|
|
694
|
-
const platformHashes = getPaymentMethodHashes(platform);
|
|
562
|
+
for (const platform of Object.values(PLATFORMS)) {
|
|
563
|
+
const platformHashes = getPaymentMethodHashes(platform.id);
|
|
695
564
|
if (platformHashes.some((h) => h.toLowerCase() === normalized)) {
|
|
696
|
-
names.add(
|
|
565
|
+
names.add(platform.name);
|
|
697
566
|
break;
|
|
698
567
|
}
|
|
699
568
|
}
|
|
@@ -726,134 +595,40 @@ function mapDeposit(d) {
|
|
|
726
595
|
escrowAddress: d.escrowAddress
|
|
727
596
|
};
|
|
728
597
|
}
|
|
729
|
-
function
|
|
598
|
+
function extractTxHash2(result) {
|
|
730
599
|
if (typeof result === "string") return result;
|
|
731
600
|
if (result && typeof result === "object" && "hash" in result) return result.hash;
|
|
732
601
|
if (result && typeof result === "object" && "transactionHash" in result) return result.transactionHash;
|
|
733
602
|
throw new Error("Unexpected transaction result format");
|
|
734
603
|
}
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
return
|
|
746
|
-
}
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
const statusOrder = { active: 0, empty: 1, closed: 2 };
|
|
758
|
-
return (raw || []).map(mapDeposit).sort((a, b) => {
|
|
759
|
-
const diff = statusOrder[a.status] - statusOrder[b.status];
|
|
760
|
-
if (diff !== 0) return diff;
|
|
761
|
-
return Number(BigInt(b.depositId) - BigInt(a.depositId));
|
|
762
|
-
});
|
|
763
|
-
}
|
|
764
|
-
/**
|
|
765
|
-
* Find a deposit by its transaction hash. Useful for recovering from
|
|
766
|
-
* CONFIRMATION_FAILED errors where you have a txHash but no depositId.
|
|
767
|
-
*
|
|
768
|
-
* @param walletAddress - The depositor's wallet address
|
|
769
|
-
* @param txHash - The transaction hash from createDeposit
|
|
770
|
-
*/
|
|
771
|
-
async getDepositByTxHash(walletAddress, txHash) {
|
|
772
|
-
const deposits = await this.getDeposits(walletAddress);
|
|
773
|
-
const normalized = txHash.toLowerCase();
|
|
774
|
-
return deposits.find((d) => d.txHash?.toLowerCase() === normalized) ?? null;
|
|
775
|
-
}
|
|
776
|
-
/**
|
|
777
|
-
* Delegate an existing deposit to the Delegate vault. Use this to:
|
|
778
|
-
* - Retry after a DELEGATION_FAILED error
|
|
779
|
-
* - Delegate a deposit created outside the SDK
|
|
780
|
-
* - Delegate a deposit created via usdctofiat.xyz
|
|
781
|
-
*
|
|
782
|
-
* @param walletClient - viem WalletClient with the deposit owner's account
|
|
783
|
-
* @param depositId - The numeric deposit ID (not the composite escrow_id format)
|
|
784
|
-
*/
|
|
785
|
-
async delegateDeposit(walletClient, depositId, escrowAddress) {
|
|
786
|
-
const client = createSdkClient(walletClient);
|
|
787
|
-
const result = await client.setRateManager({
|
|
788
|
-
depositId: BigInt(depositId),
|
|
789
|
-
rateManagerAddress: RATE_MANAGER_REGISTRY_ADDRESS,
|
|
790
|
-
rateManagerId: DELEGATE_RATE_MANAGER_ID,
|
|
791
|
-
escrowAddress: escrowAddress || ESCROW_ADDRESS,
|
|
792
|
-
txOverrides: { referrer: [REFERRER] }
|
|
793
|
-
});
|
|
794
|
-
return extractTxHash(result);
|
|
795
|
-
}
|
|
796
|
-
/**
|
|
797
|
-
* Withdraw remaining USDC and close a deposit.
|
|
798
|
-
*
|
|
799
|
-
* @param walletClient - viem WalletClient with the deposit owner's account
|
|
800
|
-
* @param depositId - The numeric deposit ID (not the composite escrow_id format)
|
|
801
|
-
*/
|
|
802
|
-
async withdrawDeposit(walletClient, depositId, escrowAddress) {
|
|
803
|
-
const client = createSdkClient(walletClient);
|
|
804
|
-
const result = await client.withdrawDeposit({
|
|
805
|
-
depositId: BigInt(depositId),
|
|
806
|
-
escrowAddress: escrowAddress || ESCROW_ADDRESS,
|
|
807
|
-
txOverrides: { referrer: [REFERRER] }
|
|
808
|
-
});
|
|
809
|
-
return extractTxHash(result);
|
|
810
|
-
}
|
|
811
|
-
/** List available payment platforms with currencies, labels, and format requirements. */
|
|
812
|
-
getPlatforms() {
|
|
813
|
-
return getPlatforms();
|
|
814
|
-
}
|
|
815
|
-
/** Get supported currencies for a specific platform. */
|
|
816
|
-
getCurrencies(platform) {
|
|
817
|
-
return getCurrencies(platform);
|
|
818
|
-
}
|
|
819
|
-
/**
|
|
820
|
-
* Get currency metadata for UI rendering.
|
|
821
|
-
* @returns Symbol (€), full name (Euro), and country code (eu), or null if unsupported.
|
|
822
|
-
*/
|
|
823
|
-
getCurrencyInfo(code) {
|
|
824
|
-
const info = currencyInfo2[code];
|
|
825
|
-
if (!info) return null;
|
|
826
|
-
return {
|
|
827
|
-
code: info.currencyCode ?? code,
|
|
828
|
-
name: info.currencyName ?? code,
|
|
829
|
-
symbol: info.currencySymbol ?? code,
|
|
830
|
-
countryCode: info.countryCode ?? ""
|
|
831
|
-
};
|
|
832
|
-
}
|
|
833
|
-
/** Get all supported currencies with metadata. */
|
|
834
|
-
getAllCurrencies() {
|
|
835
|
-
return Object.keys(currencyInfo2).map((code) => {
|
|
836
|
-
return this.getCurrencyInfo(code);
|
|
837
|
-
}).filter(Boolean);
|
|
838
|
-
}
|
|
839
|
-
/**
|
|
840
|
-
* Validate and normalize a payment identifier for a platform.
|
|
841
|
-
* Strips leading @/$ characters, validates format (email, IBAN, etc).
|
|
842
|
-
*/
|
|
843
|
-
validateIdentifier(platform, identifier) {
|
|
844
|
-
return validateIdentifier(platform, identifier);
|
|
845
|
-
}
|
|
846
|
-
};
|
|
604
|
+
async function deposits(walletAddress) {
|
|
605
|
+
const service = getIndexerService();
|
|
606
|
+
const raw = await service.fetchDepositsWithRelations(
|
|
607
|
+
{ depositor: walletAddress },
|
|
608
|
+
{ limit: 100 }
|
|
609
|
+
);
|
|
610
|
+
const statusOrder = { active: 0, empty: 1, closed: 2 };
|
|
611
|
+
return (raw || []).map(mapDeposit).sort((a, b) => {
|
|
612
|
+
const diff = statusOrder[a.status] - statusOrder[b.status];
|
|
613
|
+
if (diff !== 0) return diff;
|
|
614
|
+
return Number(BigInt(b.depositId) - BigInt(a.depositId));
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
async function close(walletClient, depositId, escrowAddress) {
|
|
618
|
+
const client = createSdkClient(walletClient);
|
|
619
|
+
const result = await client.withdrawDeposit({
|
|
620
|
+
depositId: BigInt(depositId),
|
|
621
|
+
escrowAddress: escrowAddress || ESCROW_ADDRESS,
|
|
622
|
+
txOverrides: { referrer: [REFERRER] }
|
|
623
|
+
});
|
|
624
|
+
return extractTxHash2(result);
|
|
625
|
+
}
|
|
847
626
|
|
|
848
627
|
export {
|
|
849
|
-
|
|
850
|
-
SUPPORTED_CURRENCIES,
|
|
851
|
-
CURRENCIES,
|
|
852
|
-
getPlatforms,
|
|
853
|
-
getCurrencies,
|
|
854
|
-
validateIdentifier,
|
|
628
|
+
PLATFORMS,
|
|
855
629
|
OfframpError,
|
|
856
|
-
|
|
857
|
-
|
|
630
|
+
deposits,
|
|
631
|
+
close,
|
|
632
|
+
offramp
|
|
858
633
|
};
|
|
859
|
-
//# sourceMappingURL=chunk-
|
|
634
|
+
//# sourceMappingURL=chunk-2UENKRGX.js.map
|