@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.
@@ -1,146 +1,11 @@
1
- // src/types.ts
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
- OfframpClient,
141
- getSpreadOracleConfig,
142
- mapConversionRatesToOnchainMinRate
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 BLUEPRINT = {
209
- venmo: {
210
- id: "venmo",
211
- name: "Venmo",
212
- identifierLabel: "Username",
213
- placeholder: "venmo username (no @)",
214
- helperText: "Username without @ (publicly discoverable)",
215
- validation: z.string().min(1).regex(/^[a-zA-Z0-9_-]+$/),
216
- transform: (v) => v.replace(/^@+/, "")
217
- },
218
- cashapp: {
219
- id: "cashapp",
220
- name: "Cash App",
221
- identifierLabel: "Cashtag",
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
- var CONFIGS = Object.fromEntries(
300
- Object.entries(BLUEPRINT).map(([p, bp]) => {
301
- const key = p;
302
- return [key, { ...bp, currencies: resolveSupportedCurrencies(key) }];
303
- })
304
- );
305
- function getPlatformConfig(platform) {
306
- return CONFIGS[platform];
307
- }
308
- function getPlatforms() {
309
- return PLATFORMS.map((id) => {
310
- const cfg = CONFIGS[id];
311
- return {
312
- id,
313
- name: cfg.name,
314
- currencies: cfg.currencies,
315
- identifierLabel: cfg.identifierLabel,
316
- identifierPlaceholder: cfg.placeholder,
317
- helperText: cfg.helperText
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
- return PLATFORMS.includes(normalized) ? normalized : null;
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 createOfframpDeposit(walletClient, params, onProgress) {
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 (!isSupportedCurrency(platform, currency)) {
504
- throw new OfframpError(`${currency} is not supported on ${platform}`, "UNSUPPORTED");
353
+ if (!platform.currencies.includes(currencyCode)) {
354
+ throw new OfframpError(`${currencyCode} is not supported on ${platform.name}`, "UNSUPPORTED");
505
355
  }
506
- const validation = validateIdentifier(platform, identifier);
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(platform);
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
- if (!walletClient.account?.address) {
516
- throw new OfframpError("Wallet client has no account. Connect a wallet first.", "VALIDATION");
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 = platform.startsWith("zelle") ? "zelle" : platform;
561
- const depositData = buildDepositData(platform, normalizedIdentifier);
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: [platform],
580
- depositData: [buildDepositData(platform, normalizedIdentifier)],
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
- let delay = INDEXER_INITIAL_DELAY_MS;
612
- for (let attempt = 0; attempt < INDEXER_MAX_ATTEMPTS && !depositId; attempt++) {
613
- try {
614
- const deposits = await client.indexer.getDepositsWithRelations(
615
- { depositor: walletAddress },
616
- { limit: 25 }
617
- );
618
- const hit = deposits.find((d) => (d?.txHash || "").toLowerCase() === hash.toLowerCase());
619
- if (hit) {
620
- depositId = String(hit.depositId);
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
- await new Promise((r) => setTimeout(r, delay));
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. Use the transaction hash to locate your deposit.",
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. Visit usdctofiat.xyz to manage your deposit manually.",
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/client.ts
665
- var indexerClient = null;
532
+ // src/queries.ts
533
+ var indexerService = null;
666
534
  function getIndexerService() {
667
- if (!indexerClient) {
535
+ if (!indexerService) {
668
536
  const endpoint = defaultIndexerEndpoint("PRODUCTION");
669
537
  const client = new IndexerClient(endpoint);
670
- indexerClient = new IndexerDepositService(client);
538
+ indexerService = new IndexerDepositService(client);
671
539
  }
672
- return indexerClient;
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(getPlatformConfig(platform).name);
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 extractTxHash(result) {
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
- var Offramp = class {
736
- /**
737
- * Create an offramp deposit: approve USDC, register payee, create deposit,
738
- * confirm on-chain, and delegate to the vault. All in one call.
739
- *
740
- * @param walletClient - viem WalletClient with an account
741
- * @param params - Deposit parameters (amount, platform, currency, identifier)
742
- * @param onProgress - Optional callback for step-by-step progress updates
743
- */
744
- async createDeposit(walletClient, params, onProgress) {
745
- return createOfframpDeposit(walletClient, params, onProgress);
746
- }
747
- /**
748
- * Fetch all deposits for a wallet address. Read-only, no wallet needed.
749
- * Returns active, empty, and closed deposits sorted by status then recency.
750
- */
751
- async getDeposits(walletAddress) {
752
- const service = getIndexerService();
753
- const raw = await service.fetchDepositsWithRelations(
754
- { depositor: walletAddress },
755
- { limit: 100 }
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
- PAYMENT_PLATFORMS,
850
- SUPPORTED_CURRENCIES,
851
- CURRENCIES,
852
- getPlatforms,
853
- getCurrencies,
854
- validateIdentifier,
627
+ PLATFORMS,
855
628
  OfframpError,
856
- createOfframpDeposit,
857
- Offramp
629
+ deposits,
630
+ close,
631
+ offramp
858
632
  };
859
- //# sourceMappingURL=chunk-AGP66RQ5.js.map
633
+ //# sourceMappingURL=chunk-WQCLEJWY.js.map