@usdctofiat/offramp 0.2.1 → 1.0.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/dist/{chunk-AGP66RQ5.js → chunk-WQCLEJWY.js} +218 -444
- package/dist/chunk-WQCLEJWY.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 +264 -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 +253 -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,83 @@ 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
|
+
return (raw || []).find((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
|
+
const hasOurVault = d.rateManagerId === DELEGATE_RATE_MANAGER_ID;
|
|
335
|
+
return !hasOurVault;
|
|
336
|
+
}) ?? null;
|
|
337
|
+
} catch {
|
|
338
|
+
return null;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
async function offramp(walletClient, params, onProgress) {
|
|
498
342
|
const { amount, platform, currency, identifier } = params;
|
|
343
|
+
const platformId = platform.id;
|
|
344
|
+
const currencyCode = currency.code;
|
|
345
|
+
if (!walletClient.account?.address) {
|
|
346
|
+
throw new OfframpError("Wallet client has no account. Connect a wallet first.", "VALIDATION");
|
|
347
|
+
}
|
|
348
|
+
const walletAddress = walletClient.account.address;
|
|
499
349
|
const amt = parseFloat(amount);
|
|
500
350
|
if (!Number.isFinite(amt) || amt < MIN_DEPOSIT_USDC) {
|
|
501
351
|
throw new OfframpError(`Minimum deposit is ${MIN_DEPOSIT_USDC} USDC`, "VALIDATION");
|
|
502
352
|
}
|
|
503
|
-
if (!
|
|
504
|
-
throw new OfframpError(`${
|
|
353
|
+
if (!platform.currencies.includes(currencyCode)) {
|
|
354
|
+
throw new OfframpError(`${currencyCode} is not supported on ${platform.name}`, "UNSUPPORTED");
|
|
505
355
|
}
|
|
506
|
-
const validation =
|
|
356
|
+
const validation = platform.validate(identifier);
|
|
507
357
|
if (!validation.valid) {
|
|
508
358
|
throw new OfframpError(validation.error || "Invalid identifier", "VALIDATION");
|
|
509
359
|
}
|
|
510
360
|
const normalizedIdentifier = validation.normalized;
|
|
511
|
-
const methodHash = getPaymentMethodHash(
|
|
361
|
+
const methodHash = getPaymentMethodHash(platformId);
|
|
512
362
|
if (!methodHash) {
|
|
513
|
-
throw new OfframpError(`${platform} is not currently supported`, "UNSUPPORTED");
|
|
363
|
+
throw new OfframpError(`${platform.name} is not currently supported`, "UNSUPPORTED");
|
|
514
364
|
}
|
|
515
|
-
|
|
516
|
-
|
|
365
|
+
const existing = await findUndelegatedDeposit(walletAddress);
|
|
366
|
+
if (existing) {
|
|
367
|
+
onProgress?.({ step: "resuming", depositId: existing.depositId });
|
|
368
|
+
const client2 = createSdkClient(walletClient);
|
|
369
|
+
const txOverrides2 = { referrer: [REFERRER] };
|
|
370
|
+
try {
|
|
371
|
+
const result = await client2.setRateManager({
|
|
372
|
+
depositId: BigInt(existing.depositId),
|
|
373
|
+
rateManagerAddress: RATE_MANAGER_REGISTRY_ADDRESS,
|
|
374
|
+
rateManagerId: DELEGATE_RATE_MANAGER_ID,
|
|
375
|
+
escrowAddress: existing.escrowAddress,
|
|
376
|
+
txOverrides: txOverrides2
|
|
377
|
+
});
|
|
378
|
+
const txHash = extractTxHash(result);
|
|
379
|
+
onProgress?.({ step: "done", txHash, depositId: existing.depositId });
|
|
380
|
+
return { depositId: existing.depositId, txHash, resumed: true };
|
|
381
|
+
} catch (err) {
|
|
382
|
+
if (isUserCancellation(err)) throw new OfframpError("User cancelled", "USER_CANCELLED", "resuming", err);
|
|
383
|
+
throw new OfframpError(
|
|
384
|
+
"Found undelegated deposit but delegation failed. Try again.",
|
|
385
|
+
"DELEGATION_FAILED",
|
|
386
|
+
"resuming",
|
|
387
|
+
err,
|
|
388
|
+
{ depositId: existing.depositId, txHash: existing.txHash }
|
|
389
|
+
);
|
|
390
|
+
}
|
|
517
391
|
}
|
|
518
|
-
const walletAddress = walletClient.account.address;
|
|
519
392
|
const truncatedAmount = amt.toFixed(6).replace(/\.?0+$/, "");
|
|
520
393
|
const amountUnits = usdcToUnits(truncatedAmount);
|
|
521
394
|
const minUnits = usdcToUnits(String(MIN_ORDER_USDC));
|
|
@@ -530,10 +403,7 @@ async function createOfframpDeposit(walletClient, params, onProgress) {
|
|
|
530
403
|
});
|
|
531
404
|
if (balance < amountUnits) {
|
|
532
405
|
const available = Number(formatUnits(balance, 6));
|
|
533
|
-
throw new OfframpError(
|
|
534
|
-
`Insufficient USDC balance. Have ${available.toFixed(2)}, need ${truncatedAmount}.`,
|
|
535
|
-
"VALIDATION"
|
|
536
|
-
);
|
|
406
|
+
throw new OfframpError(`Insufficient USDC balance. Have ${available.toFixed(2)}, need ${truncatedAmount}.`, "VALIDATION");
|
|
537
407
|
}
|
|
538
408
|
} catch (err) {
|
|
539
409
|
if (err instanceof OfframpError) throw err;
|
|
@@ -557,15 +427,15 @@ async function createOfframpDeposit(walletClient, params, onProgress) {
|
|
|
557
427
|
onProgress?.({ step: "registering" });
|
|
558
428
|
let hashedOnchainId;
|
|
559
429
|
try {
|
|
560
|
-
const canonicalName =
|
|
561
|
-
const depositData = buildDepositData(
|
|
430
|
+
const canonicalName = platformId.startsWith("zelle") ? "zelle" : platformId;
|
|
431
|
+
const depositData = buildDepositData(platformId, normalizedIdentifier);
|
|
562
432
|
hashedOnchainId = await registerPayeeDetails(canonicalName, depositData);
|
|
563
433
|
} catch (err) {
|
|
564
434
|
throw new OfframpError("Payee registration failed", "REGISTRATION_FAILED", "registering", err);
|
|
565
435
|
}
|
|
566
436
|
onProgress?.({ step: "depositing" });
|
|
567
437
|
const conversionRates = [
|
|
568
|
-
[{ currency, conversionRate: "1" }]
|
|
438
|
+
[{ currency: currencyCode, conversionRate: "1" }]
|
|
569
439
|
];
|
|
570
440
|
const baseCurrenciesOverride = mapConversionRatesToOnchainMinRate(conversionRates, 1);
|
|
571
441
|
const currenciesOverride = attachOracleConfig(baseCurrenciesOverride, conversionRates);
|
|
@@ -576,8 +446,8 @@ async function createOfframpDeposit(walletClient, params, onProgress) {
|
|
|
576
446
|
amount: amountUnits,
|
|
577
447
|
retainOnEmpty: false,
|
|
578
448
|
intentAmountRange: { min: minUnits, max: maxUnits },
|
|
579
|
-
processorNames: [
|
|
580
|
-
depositData: [buildDepositData(
|
|
449
|
+
processorNames: [platformId],
|
|
450
|
+
depositData: [buildDepositData(platformId, normalizedIdentifier)],
|
|
581
451
|
conversionRates,
|
|
582
452
|
paymentMethodsOverride: [methodHash],
|
|
583
453
|
paymentMethodDataOverride: [{
|
|
@@ -607,29 +477,27 @@ async function createOfframpDeposit(walletClient, params, onProgress) {
|
|
|
607
477
|
}
|
|
608
478
|
}
|
|
609
479
|
if (!depositId) {
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
break;
|
|
622
|
-
}
|
|
623
|
-
} catch {
|
|
480
|
+
let delay = INDEXER_INITIAL_DELAY_MS;
|
|
481
|
+
for (let attempt = 0; attempt < INDEXER_MAX_ATTEMPTS && !depositId; attempt++) {
|
|
482
|
+
try {
|
|
483
|
+
const deps = await client.indexer.getDepositsWithRelations(
|
|
484
|
+
{ depositor: walletAddress },
|
|
485
|
+
{ limit: 25 }
|
|
486
|
+
);
|
|
487
|
+
const hit = deps.find((d) => (d?.txHash || "").toLowerCase() === hash.toLowerCase());
|
|
488
|
+
if (hit) {
|
|
489
|
+
depositId = String(hit.depositId);
|
|
490
|
+
break;
|
|
624
491
|
}
|
|
625
|
-
|
|
626
|
-
delay = Math.min(INDEXER_MAX_DELAY_MS, Math.floor(delay * 1.7));
|
|
492
|
+
} catch {
|
|
627
493
|
}
|
|
494
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
495
|
+
delay = Math.min(INDEXER_MAX_DELAY_MS, Math.floor(delay * 1.7));
|
|
628
496
|
}
|
|
629
497
|
}
|
|
630
498
|
if (!depositId) {
|
|
631
499
|
throw new OfframpError(
|
|
632
|
-
"Deposit created on-chain but could not confirm deposit ID. Your funds are safe.
|
|
500
|
+
"Deposit created on-chain but could not confirm deposit ID. Your funds are safe. Call offramp() again to resume delegation.",
|
|
633
501
|
"CONFIRMATION_FAILED",
|
|
634
502
|
"confirming",
|
|
635
503
|
void 0,
|
|
@@ -650,7 +518,7 @@ async function createOfframpDeposit(walletClient, params, onProgress) {
|
|
|
650
518
|
throw new OfframpError("User cancelled delegation", "USER_CANCELLED", "delegating", delegationError, { txHash: hash, depositId });
|
|
651
519
|
}
|
|
652
520
|
throw new OfframpError(
|
|
653
|
-
"Deposit created but delegation failed.
|
|
521
|
+
"Deposit created but delegation failed. Call offramp() again to resume delegation.",
|
|
654
522
|
"DELEGATION_FAILED",
|
|
655
523
|
"delegating",
|
|
656
524
|
delegationError,
|
|
@@ -658,18 +526,18 @@ async function createOfframpDeposit(walletClient, params, onProgress) {
|
|
|
658
526
|
);
|
|
659
527
|
}
|
|
660
528
|
onProgress?.({ step: "done", txHash: hash, depositId });
|
|
661
|
-
return { depositId, txHash: hash };
|
|
529
|
+
return { depositId, txHash: hash, resumed: false };
|
|
662
530
|
}
|
|
663
531
|
|
|
664
|
-
// src/
|
|
665
|
-
var
|
|
532
|
+
// src/queries.ts
|
|
533
|
+
var indexerService = null;
|
|
666
534
|
function getIndexerService() {
|
|
667
|
-
if (!
|
|
535
|
+
if (!indexerService) {
|
|
668
536
|
const endpoint = defaultIndexerEndpoint("PRODUCTION");
|
|
669
537
|
const client = new IndexerClient(endpoint);
|
|
670
|
-
|
|
538
|
+
indexerService = new IndexerDepositService(client);
|
|
671
539
|
}
|
|
672
|
-
return
|
|
540
|
+
return indexerService;
|
|
673
541
|
}
|
|
674
542
|
function toBigInt(value) {
|
|
675
543
|
try {
|
|
@@ -690,10 +558,10 @@ function resolveMethodNames(hashes) {
|
|
|
690
558
|
const names = /* @__PURE__ */ new Set();
|
|
691
559
|
for (const { paymentMethodHash } of hashes) {
|
|
692
560
|
const normalized = paymentMethodHash.toLowerCase();
|
|
693
|
-
for (const platform of PLATFORMS) {
|
|
694
|
-
const platformHashes = getPaymentMethodHashes(platform);
|
|
561
|
+
for (const platform of Object.values(PLATFORMS)) {
|
|
562
|
+
const platformHashes = getPaymentMethodHashes(platform.id);
|
|
695
563
|
if (platformHashes.some((h) => h.toLowerCase() === normalized)) {
|
|
696
|
-
names.add(
|
|
564
|
+
names.add(platform.name);
|
|
697
565
|
break;
|
|
698
566
|
}
|
|
699
567
|
}
|
|
@@ -726,134 +594,40 @@ function mapDeposit(d) {
|
|
|
726
594
|
escrowAddress: d.escrowAddress
|
|
727
595
|
};
|
|
728
596
|
}
|
|
729
|
-
function
|
|
597
|
+
function extractTxHash2(result) {
|
|
730
598
|
if (typeof result === "string") return result;
|
|
731
599
|
if (result && typeof result === "object" && "hash" in result) return result.hash;
|
|
732
600
|
if (result && typeof result === "object" && "transactionHash" in result) return result.transactionHash;
|
|
733
601
|
throw new Error("Unexpected transaction result format");
|
|
734
602
|
}
|
|
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
|
-
};
|
|
603
|
+
async function deposits(walletAddress) {
|
|
604
|
+
const service = getIndexerService();
|
|
605
|
+
const raw = await service.fetchDepositsWithRelations(
|
|
606
|
+
{ depositor: walletAddress },
|
|
607
|
+
{ limit: 100 }
|
|
608
|
+
);
|
|
609
|
+
const statusOrder = { active: 0, empty: 1, closed: 2 };
|
|
610
|
+
return (raw || []).map(mapDeposit).sort((a, b) => {
|
|
611
|
+
const diff = statusOrder[a.status] - statusOrder[b.status];
|
|
612
|
+
if (diff !== 0) return diff;
|
|
613
|
+
return Number(BigInt(b.depositId) - BigInt(a.depositId));
|
|
614
|
+
});
|
|
615
|
+
}
|
|
616
|
+
async function close(walletClient, depositId, escrowAddress) {
|
|
617
|
+
const client = createSdkClient(walletClient);
|
|
618
|
+
const result = await client.withdrawDeposit({
|
|
619
|
+
depositId: BigInt(depositId),
|
|
620
|
+
escrowAddress: escrowAddress || ESCROW_ADDRESS,
|
|
621
|
+
txOverrides: { referrer: [REFERRER] }
|
|
622
|
+
});
|
|
623
|
+
return extractTxHash2(result);
|
|
624
|
+
}
|
|
847
625
|
|
|
848
626
|
export {
|
|
849
|
-
|
|
850
|
-
SUPPORTED_CURRENCIES,
|
|
851
|
-
CURRENCIES,
|
|
852
|
-
getPlatforms,
|
|
853
|
-
getCurrencies,
|
|
854
|
-
validateIdentifier,
|
|
627
|
+
PLATFORMS,
|
|
855
628
|
OfframpError,
|
|
856
|
-
|
|
857
|
-
|
|
629
|
+
deposits,
|
|
630
|
+
close,
|
|
631
|
+
offramp
|
|
858
632
|
};
|
|
859
|
-
//# sourceMappingURL=chunk-
|
|
633
|
+
//# sourceMappingURL=chunk-WQCLEJWY.js.map
|