@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.
@@ -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,84 @@ 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
+ 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 (!isSupportedCurrency(platform, currency)) {
504
- throw new OfframpError(`${currency} is not supported on ${platform}`, "UNSUPPORTED");
354
+ if (!platform.currencies.includes(currencyCode)) {
355
+ throw new OfframpError(`${currencyCode} is not supported on ${platform.name}`, "UNSUPPORTED");
505
356
  }
506
- const validation = validateIdentifier(platform, identifier);
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(platform);
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
- if (!walletClient.account?.address) {
516
- throw new OfframpError("Wallet client has no account. Connect a wallet first.", "VALIDATION");
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 = platform.startsWith("zelle") ? "zelle" : platform;
561
- const depositData = buildDepositData(platform, normalizedIdentifier);
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: [platform],
580
- depositData: [buildDepositData(platform, normalizedIdentifier)],
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
- 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 {
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
- await new Promise((r) => setTimeout(r, delay));
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. Use the transaction hash to locate your deposit.",
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. Visit usdctofiat.xyz to manage your deposit manually.",
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/client.ts
665
- var indexerClient = null;
533
+ // src/queries.ts
534
+ var indexerService = null;
666
535
  function getIndexerService() {
667
- if (!indexerClient) {
536
+ if (!indexerService) {
668
537
  const endpoint = defaultIndexerEndpoint("PRODUCTION");
669
538
  const client = new IndexerClient(endpoint);
670
- indexerClient = new IndexerDepositService(client);
539
+ indexerService = new IndexerDepositService(client);
671
540
  }
672
- return indexerClient;
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(getPlatformConfig(platform).name);
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 extractTxHash(result) {
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
- 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
- };
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
- PAYMENT_PLATFORMS,
850
- SUPPORTED_CURRENCIES,
851
- CURRENCIES,
852
- getPlatforms,
853
- getCurrencies,
854
- validateIdentifier,
628
+ PLATFORMS,
855
629
  OfframpError,
856
- createOfframpDeposit,
857
- Offramp
630
+ deposits,
631
+ close,
632
+ offramp
858
633
  };
859
- //# sourceMappingURL=chunk-AGP66RQ5.js.map
634
+ //# sourceMappingURL=chunk-2UENKRGX.js.map