@usdctofiat/offramp 3.0.1 → 3.0.3

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/react.cjs CHANGED
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/react.ts
@@ -30,7 +40,7 @@ var import_react = require("react");
30
40
 
31
41
  // src/config.ts
32
42
  var import_sdk = require("@zkp2p/sdk");
33
- var SDK_VERSION = "3.0.1";
43
+ var SDK_VERSION = "3.0.3";
34
44
  var BASE_CHAIN_ID = 8453;
35
45
  var RUNTIME_ENV = "production";
36
46
  var API_BASE_URL = "https://api.zkp2p.xyz";
@@ -47,6 +57,7 @@ var GATING_SERVICE_ADDRESS = (0, import_sdk.getGatingServiceAddress)(
47
57
  var DELEGATE_RATE_MANAGER_ID = "0x8666d6fb0f6797c56e95339fd7ca82fdd348b9db200e10a4c4aa0a0b879fc41c";
48
58
  var RATE_MANAGER_REGISTRY_ADDRESS = "0xeed7db23e724ac4590d6db6f78fda6db203535f3";
49
59
  var DELEGATE_MANAGER_FEE_BPS = 10;
60
+ var DEFAULT_INTENT_GUARDIAN_ADDRESS = "0xe29a5BD4D0CEbA6C125A0361E7D20ab4eA275C2f";
50
61
  var REFERRER = "galleonlabs";
51
62
  var MIN_DEPOSIT_USDC = 1;
52
63
  var MIN_ORDER_USDC = 1;
@@ -149,7 +160,8 @@ var FALLBACK_CURRENCIES = {
149
160
  zelle: ["USD"],
150
161
  paypal: ["USD", "EUR", "GBP", "SGD", "NZD", "AUD", "CAD"],
151
162
  monzo: ["GBP"],
152
- n26: ["EUR"]
163
+ n26: ["EUR"],
164
+ luxon: ["USD", "EUR", "GBP"]
153
165
  };
154
166
  function gatherCatalogHashes(platform) {
155
167
  if (platform === "zelle") {
@@ -173,13 +185,39 @@ function resolveSupportedCurrencies(platform) {
173
185
  function normalizePaypalMeUsername(value) {
174
186
  const trimmed = value.trim();
175
187
  if (!trimmed) return "";
176
- const withoutProtocol = trimmed.replace(/^https?:\/\//i, "").replace(/^www\./i, "");
177
- if (/^paypal\.me(?:[?#].*)?$/i.test(withoutProtocol)) return "";
178
- const withoutDomain = withoutProtocol.replace(/^paypal\.me\//i, "");
179
- const [pathWithoutQuery] = withoutDomain.split(/[?#]/, 1);
188
+ const withoutProtocol = trimmed.replace(/^https?:\/\//i, "");
189
+ const [pathWithoutQuery] = withoutProtocol.split(/[?#]/, 1);
180
190
  const sanitizedPath = pathWithoutQuery.replace(/^\/+/, "");
181
- const [username] = sanitizedPath.split("/", 1);
182
- return username.replace(/^@+/, "").trim().toLowerCase();
191
+ const [host = "", ...pathSegments] = sanitizedPath.split("/");
192
+ const normalizedHost = host.toLowerCase().replace(/^www\./i, "");
193
+ if (normalizedHost === "paypal.me") {
194
+ const [username = ""] = pathSegments;
195
+ return username.replace(/^@+/, "").trim().toLowerCase();
196
+ }
197
+ if (normalizedHost === "paypal.com") {
198
+ const [paypalMePath = "", username = ""] = pathSegments;
199
+ if (paypalMePath.toLowerCase() !== "paypalme") return "";
200
+ return username.replace(/^@+/, "").trim().toLowerCase();
201
+ }
202
+ if (/^https?:\/\//i.test(trimmed) || trimmed.includes("/")) {
203
+ return trimmed;
204
+ }
205
+ return trimmed.replace(/^@+/, "").toLowerCase();
206
+ }
207
+ function isValidIBAN(iban) {
208
+ const upper = iban.toUpperCase();
209
+ if (!/^[A-Z]{2}[0-9]{2}[A-Z0-9]{11,30}$/.test(upper)) return false;
210
+ const rearranged = upper.slice(4) + upper.slice(0, 4);
211
+ const numeric = rearranged.split("").map((ch) => {
212
+ const code = ch.charCodeAt(0);
213
+ return code >= 65 && code <= 90 ? (code - 55).toString() : ch;
214
+ }).join("");
215
+ let remainder = numeric;
216
+ while (remainder.length > 2) {
217
+ const block = remainder.slice(0, 9);
218
+ remainder = (parseInt(block, 10) % 97).toString() + remainder.slice(block.length);
219
+ }
220
+ return parseInt(remainder, 10) % 97 === 1;
183
221
  }
184
222
  var BLUEPRINTS = {
185
223
  venmo: {
@@ -231,9 +269,9 @@ var BLUEPRINTS = {
231
269
  transform: (v) => v.replace(/^@+/, "").trim(),
232
270
  extensionRegistration: {
233
271
  providerId: "wise",
234
- requiredPrompt: "This Wisetag is not registered yet. Verify it in the Peer extension, then refresh and retry with the same Wisetag.",
235
- ctaLabel: "Install Peer Extension",
236
- minExtensionVersion: "0.4.12"
272
+ requiredPrompt: "This Wisetag is not registered yet. Register it with PeerAuth, then retry with the same Wisetag.",
273
+ ctaLabel: "Register Wisetag",
274
+ minExtensionVersion: "0.5.0"
237
275
  }
238
276
  },
239
277
  mercadopago: {
@@ -250,7 +288,11 @@ var BLUEPRINTS = {
250
288
  identifierLabel: "Email",
251
289
  placeholder: "email",
252
290
  helperText: "Registered Zelle email",
253
- validation: import_zod.z.string().email()
291
+ // Curator's ZelleProcessor rejects any non-lowercase email outright, so
292
+ // canonicalize to lowercase here rather than letting /v2/makers/create
293
+ // reject after the maker has already approved USDC + paid gas.
294
+ validation: import_zod.z.string().email(),
295
+ transform: (v) => v.trim().toLowerCase()
254
296
  },
255
297
  paypal: {
256
298
  id: "paypal",
@@ -258,14 +300,17 @@ var BLUEPRINTS = {
258
300
  identifierLabel: "PayPal.me Username",
259
301
  placeholder: "paypal.me/your-username",
260
302
  helperText: "Your PayPal.me username, not your email",
261
- validation: import_zod.z.string().min(1, "PayPal.me username is required").regex(/^[a-z0-9._-]+$/i, "Use your PayPal.me username (letters, numbers, . _ -)"),
303
+ validation: import_zod.z.string().min(1, "PayPal.me username is required").regex(
304
+ /^[a-z0-9._-]+$/i,
305
+ "Use your PayPal.me username or paypal.me link, not a shortened URL."
306
+ ),
262
307
  transform: normalizePaypalMeUsername,
263
308
  extensionRegistration: {
264
309
  providerId: "paypal",
265
- requiredPrompt: "This PayPal username is not registered yet. Verify it in the Peer extension, then refresh and retry with the same PayPal username.",
266
- ctaLabel: "Install Peer Extension",
310
+ requiredPrompt: "This PayPal username is not registered yet. Register it with PeerAuth, then retry with the same PayPal username.",
311
+ ctaLabel: "Register PayPal Username",
267
312
  ctaSubtext: "PayPal Business accounts are not supported at this time.",
268
- minExtensionVersion: "0.4.14"
313
+ minExtensionVersion: "0.5.0"
269
314
  }
270
315
  },
271
316
  monzo: {
@@ -282,8 +327,20 @@ var BLUEPRINTS = {
282
327
  identifierLabel: "IBAN",
283
328
  placeholder: "IBAN (e.g. DE89...)",
284
329
  helperText: "Your IBAN (spaces will be removed)",
285
- validation: import_zod.z.string().min(15).max(34).regex(/^[A-Z]{2}[0-9]{2}[A-Z0-9]+$/i),
330
+ // transform runs before validation, so the schema sees a spaceless,
331
+ // uppercased IBAN. The MOD-97 refine mirrors curator's N26Processor so a
332
+ // typo'd-but-well-formed IBAN fails here, not after USDC approval + gas.
333
+ validation: import_zod.z.string().regex(/^[A-Z]{2}[0-9]{2}[A-Z0-9]{11,30}$/, "Enter a valid IBAN").refine(isValidIBAN, "That IBAN looks wrong \u2014 its checksum doesn't match"),
286
334
  transform: (v) => v.replace(/\s/g, "").toUpperCase()
335
+ },
336
+ luxon: {
337
+ id: "luxon",
338
+ name: "Luxon",
339
+ identifierLabel: "Email",
340
+ placeholder: "your-luxon-email@example.com",
341
+ helperText: "Email address registered with Luxon",
342
+ validation: import_zod.z.string().email(),
343
+ transform: (v) => v.trim()
287
344
  }
288
345
  };
289
346
  function buildPlatformEntry(bp) {
@@ -322,7 +379,8 @@ var PLATFORMS = {
322
379
  ZELLE: buildPlatformEntry(BLUEPRINTS.zelle),
323
380
  PAYPAL: buildPlatformEntry(BLUEPRINTS.paypal),
324
381
  MONZO: buildPlatformEntry(BLUEPRINTS.monzo),
325
- N26: buildPlatformEntry(BLUEPRINTS.n26)
382
+ N26: buildPlatformEntry(BLUEPRINTS.n26),
383
+ LUXON: buildPlatformEntry(BLUEPRINTS.luxon)
326
384
  };
327
385
  function getPlatformById(id) {
328
386
  return Object.values(PLATFORMS).find((p) => p.id === id) ?? null;
@@ -432,349 +490,7 @@ function isUserCancellation(error) {
432
490
  // src/otc.ts
433
491
  var import_viem = require("viem");
434
492
  var import_chains = require("viem/chains");
435
-
436
- // ../../node_modules/@zkp2p/contracts-v2/abis/base/WhitelistPreIntentHook.json
437
- var WhitelistPreIntentHook_default = [
438
- {
439
- inputs: [
440
- {
441
- internalType: "address",
442
- name: "_orchestratorRegistry",
443
- type: "address"
444
- }
445
- ],
446
- stateMutability: "nonpayable",
447
- type: "constructor"
448
- },
449
- {
450
- inputs: [],
451
- name: "EmptyArray",
452
- type: "error"
453
- },
454
- {
455
- inputs: [
456
- {
457
- internalType: "address",
458
- name: "taker",
459
- type: "address"
460
- },
461
- {
462
- internalType: "address",
463
- name: "escrow",
464
- type: "address"
465
- },
466
- {
467
- internalType: "uint256",
468
- name: "depositId",
469
- type: "uint256"
470
- }
471
- ],
472
- name: "TakerNotInWhitelist",
473
- type: "error"
474
- },
475
- {
476
- inputs: [
477
- {
478
- internalType: "address",
479
- name: "taker",
480
- type: "address"
481
- },
482
- {
483
- internalType: "address",
484
- name: "escrow",
485
- type: "address"
486
- },
487
- {
488
- internalType: "uint256",
489
- name: "depositId",
490
- type: "uint256"
491
- }
492
- ],
493
- name: "TakerNotWhitelisted",
494
- type: "error"
495
- },
496
- {
497
- inputs: [
498
- {
499
- internalType: "address",
500
- name: "caller",
501
- type: "address"
502
- },
503
- {
504
- internalType: "address",
505
- name: "owner",
506
- type: "address"
507
- },
508
- {
509
- internalType: "address",
510
- name: "delegate",
511
- type: "address"
512
- }
513
- ],
514
- name: "UnauthorizedCallerOrDelegate",
515
- type: "error"
516
- },
517
- {
518
- inputs: [
519
- {
520
- internalType: "address",
521
- name: "caller",
522
- type: "address"
523
- }
524
- ],
525
- name: "UnauthorizedOrchestratorCaller",
526
- type: "error"
527
- },
528
- {
529
- inputs: [],
530
- name: "ZeroAddress",
531
- type: "error"
532
- },
533
- {
534
- anonymous: false,
535
- inputs: [
536
- {
537
- indexed: true,
538
- internalType: "address",
539
- name: "escrow",
540
- type: "address"
541
- },
542
- {
543
- indexed: true,
544
- internalType: "uint256",
545
- name: "depositId",
546
- type: "uint256"
547
- },
548
- {
549
- indexed: true,
550
- internalType: "address",
551
- name: "taker",
552
- type: "address"
553
- }
554
- ],
555
- name: "TakerRemovedFromWhitelist",
556
- type: "event"
557
- },
558
- {
559
- anonymous: false,
560
- inputs: [
561
- {
562
- indexed: true,
563
- internalType: "address",
564
- name: "escrow",
565
- type: "address"
566
- },
567
- {
568
- indexed: true,
569
- internalType: "uint256",
570
- name: "depositId",
571
- type: "uint256"
572
- },
573
- {
574
- indexed: true,
575
- internalType: "address",
576
- name: "taker",
577
- type: "address"
578
- }
579
- ],
580
- name: "TakerWhitelisted",
581
- type: "event"
582
- },
583
- {
584
- inputs: [
585
- {
586
- internalType: "address",
587
- name: "_escrow",
588
- type: "address"
589
- },
590
- {
591
- internalType: "uint256",
592
- name: "_depositId",
593
- type: "uint256"
594
- },
595
- {
596
- internalType: "address[]",
597
- name: "_takers",
598
- type: "address[]"
599
- }
600
- ],
601
- name: "addToWhitelist",
602
- outputs: [],
603
- stateMutability: "nonpayable",
604
- type: "function"
605
- },
606
- {
607
- inputs: [
608
- {
609
- internalType: "address",
610
- name: "_escrow",
611
- type: "address"
612
- },
613
- {
614
- internalType: "uint256",
615
- name: "_depositId",
616
- type: "uint256"
617
- },
618
- {
619
- internalType: "address",
620
- name: "_taker",
621
- type: "address"
622
- }
623
- ],
624
- name: "isWhitelisted",
625
- outputs: [
626
- {
627
- internalType: "bool",
628
- name: "",
629
- type: "bool"
630
- }
631
- ],
632
- stateMutability: "view",
633
- type: "function"
634
- },
635
- {
636
- inputs: [],
637
- name: "orchestratorRegistry",
638
- outputs: [
639
- {
640
- internalType: "contract IOrchestratorRegistry",
641
- name: "",
642
- type: "address"
643
- }
644
- ],
645
- stateMutability: "view",
646
- type: "function"
647
- },
648
- {
649
- inputs: [
650
- {
651
- internalType: "address",
652
- name: "_escrow",
653
- type: "address"
654
- },
655
- {
656
- internalType: "uint256",
657
- name: "_depositId",
658
- type: "uint256"
659
- },
660
- {
661
- internalType: "address[]",
662
- name: "_takers",
663
- type: "address[]"
664
- }
665
- ],
666
- name: "removeFromWhitelist",
667
- outputs: [],
668
- stateMutability: "nonpayable",
669
- type: "function"
670
- },
671
- {
672
- inputs: [
673
- {
674
- components: [
675
- {
676
- internalType: "address",
677
- name: "taker",
678
- type: "address"
679
- },
680
- {
681
- internalType: "address",
682
- name: "escrow",
683
- type: "address"
684
- },
685
- {
686
- internalType: "uint256",
687
- name: "depositId",
688
- type: "uint256"
689
- },
690
- {
691
- internalType: "uint256",
692
- name: "amount",
693
- type: "uint256"
694
- },
695
- {
696
- internalType: "address",
697
- name: "to",
698
- type: "address"
699
- },
700
- {
701
- internalType: "bytes32",
702
- name: "paymentMethod",
703
- type: "bytes32"
704
- },
705
- {
706
- internalType: "bytes32",
707
- name: "fiatCurrency",
708
- type: "bytes32"
709
- },
710
- {
711
- internalType: "uint256",
712
- name: "conversionRate",
713
- type: "uint256"
714
- },
715
- {
716
- components: [
717
- {
718
- internalType: "address",
719
- name: "recipient",
720
- type: "address"
721
- },
722
- {
723
- internalType: "uint256",
724
- name: "fee",
725
- type: "uint256"
726
- }
727
- ],
728
- internalType: "struct IReferralFee.ReferralFee[]",
729
- name: "referralFees",
730
- type: "tuple[]"
731
- },
732
- {
733
- internalType: "bytes",
734
- name: "preIntentHookData",
735
- type: "bytes"
736
- }
737
- ],
738
- internalType: "struct IPreIntentHook.PreIntentContext",
739
- name: "_ctx",
740
- type: "tuple"
741
- }
742
- ],
743
- name: "validateSignalIntent",
744
- outputs: [],
745
- stateMutability: "view",
746
- type: "function"
747
- },
748
- {
749
- inputs: [
750
- {
751
- internalType: "address",
752
- name: "",
753
- type: "address"
754
- },
755
- {
756
- internalType: "uint256",
757
- name: "",
758
- type: "uint256"
759
- },
760
- {
761
- internalType: "address",
762
- name: "",
763
- type: "address"
764
- }
765
- ],
766
- name: "whitelist",
767
- outputs: [
768
- {
769
- internalType: "bool",
770
- name: "",
771
- type: "bool"
772
- }
773
- ],
774
- stateMutability: "view",
775
- type: "function"
776
- }
777
- ];
493
+ var import_WhitelistPreIntentHook = __toESM(require("@zkp2p/contracts-v2/abis/base/WhitelistPreIntentHook.json"), 1);
778
494
 
779
495
  // src/sdk-client.ts
780
496
  var import_sdk4 = require("@zkp2p/sdk");
@@ -790,7 +506,7 @@ function createSdkClient(walletClient) {
790
506
 
791
507
  // src/otc.ts
792
508
  var WHITELIST_HOOK_ADDRESS = "0xda023Ea0d789A41BcF5866F7B6BBd2CaDF9b79B8";
793
- var OTC_BASE_URL = "https://usdctofiat.xyz";
509
+ var OTC_BASE_URL = "https://otc.usdctofiat.xyz";
794
510
  async function enableOtc(walletClient, depositId, takerAddress, escrowAddress) {
795
511
  if (!(0, import_viem.isAddress)(takerAddress)) {
796
512
  throw new OfframpError("Invalid taker address", "VALIDATION");
@@ -841,7 +557,7 @@ async function enableOtc(walletClient, depositId, takerAddress, escrowAddress) {
841
557
  }
842
558
  function getOtcLink(depositId, escrowAddress) {
843
559
  const escrow = escrowAddress || ESCROW_ADDRESS;
844
- return `${OTC_BASE_URL}/deposit/${escrow}/${depositId}`;
560
+ return `${OTC_BASE_URL}/d/${escrow}/${depositId}`;
845
561
  }
846
562
  async function writeContract(walletClient, functionName, args) {
847
563
  const wc = walletClient;
@@ -850,7 +566,7 @@ async function writeContract(walletClient, functionName, args) {
850
566
  }
851
567
  await wc.writeContract({
852
568
  address: WHITELIST_HOOK_ADDRESS,
853
- abi: WhitelistPreIntentHook_default,
569
+ abi: import_WhitelistPreIntentHook.default,
854
570
  functionName,
855
571
  args
856
572
  });
@@ -859,7 +575,7 @@ async function readIsWhitelisted(escrow, depositId, taker) {
859
575
  const publicClient = (0, import_viem.createPublicClient)({ chain: import_chains.base, transport: (0, import_viem.http)(BASE_RPC_URL) });
860
576
  return publicClient.readContract({
861
577
  address: WHITELIST_HOOK_ADDRESS,
862
- abi: WhitelistPreIntentHook_default,
578
+ abi: import_WhitelistPreIntentHook.default,
863
579
  functionName: "isWhitelisted",
864
580
  args: [escrow, depositId, taker]
865
581
  });
@@ -1147,6 +863,28 @@ async function registerPayeeDetails(processorName, payload) {
1147
863
  clearTimeout(timeout);
1148
864
  }
1149
865
  }
866
+ async function validatePayeeDetails(processorName, offchainId) {
867
+ const controller = new AbortController();
868
+ const timeout = setTimeout(() => controller.abort(), PAYEE_REGISTRATION_TIMEOUT_MS);
869
+ try {
870
+ const res = await fetch(`${API_BASE_URL}/v2/makers/validate`, {
871
+ method: "POST",
872
+ headers: { "Content-Type": "application/json" },
873
+ body: JSON.stringify({ processorName, offchainId }),
874
+ signal: controller.signal
875
+ });
876
+ if (!res.ok) return "unknown";
877
+ const json = await res.json();
878
+ if (typeof json.responseObject === "boolean") {
879
+ return json.responseObject ? "valid" : "invalid";
880
+ }
881
+ return "unknown";
882
+ } catch {
883
+ return "unknown";
884
+ } finally {
885
+ clearTimeout(timeout);
886
+ }
887
+ }
1150
888
  function attachOracleConfig(entries, conversionRates) {
1151
889
  return entries.map(
1152
890
  (group, gi) => group.map((entry, ci) => {
@@ -1318,6 +1056,17 @@ async function offramp(walletClient, params, onProgress, telemetryContext) {
1318
1056
  } catch (err) {
1319
1057
  if (err instanceof OfframpError) throw err;
1320
1058
  }
1059
+ const canonicalName = platformId.startsWith("zelle") ? "zelle" : platformId;
1060
+ if (!getPeerExtensionRegistrationInfo(platformId)) {
1061
+ const outcome = await validatePayeeDetails(canonicalName, normalizedIdentifier);
1062
+ if (outcome === "invalid") {
1063
+ throw new OfframpError(
1064
+ `Couldn't verify that ${platform.name} ${platform.identifier.label.toLowerCase()}. Double-check it and try again.`,
1065
+ "VALIDATION",
1066
+ "registering"
1067
+ );
1068
+ }
1069
+ }
1321
1070
  const client = createSdkClient(walletClient);
1322
1071
  const txOverrides = { referrer: [REFERRER] };
1323
1072
  emitProgress({ step: "approving" });
@@ -1342,7 +1091,6 @@ async function offramp(walletClient, params, onProgress, telemetryContext) {
1342
1091
  }
1343
1092
  emitProgress({ step: "registering" });
1344
1093
  let hashedOnchainId;
1345
- const canonicalName = platformId.startsWith("zelle") ? "zelle" : platformId;
1346
1094
  try {
1347
1095
  const payeePayload = buildDepositData(canonicalName, normalizedIdentifier);
1348
1096
  hashedOnchainId = await registerPayeeDetails(canonicalName, payeePayload);
@@ -1392,6 +1140,7 @@ async function offramp(walletClient, params, onProgress, telemetryContext) {
1392
1140
  data: "0x"
1393
1141
  })),
1394
1142
  currenciesOverride,
1143
+ intentGuardian: DEFAULT_INTENT_GUARDIAN_ADDRESS,
1395
1144
  escrowAddress: ESCROW_ADDRESS,
1396
1145
  txOverrides
1397
1146
  });