@usdctofiat/offramp 3.0.2 → 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.2";
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";
@@ -150,7 +160,8 @@ var FALLBACK_CURRENCIES = {
150
160
  zelle: ["USD"],
151
161
  paypal: ["USD", "EUR", "GBP", "SGD", "NZD", "AUD", "CAD"],
152
162
  monzo: ["GBP"],
153
- n26: ["EUR"]
163
+ n26: ["EUR"],
164
+ luxon: ["USD", "EUR", "GBP"]
154
165
  };
155
166
  function gatherCatalogHashes(platform) {
156
167
  if (platform === "zelle") {
@@ -174,13 +185,39 @@ function resolveSupportedCurrencies(platform) {
174
185
  function normalizePaypalMeUsername(value) {
175
186
  const trimmed = value.trim();
176
187
  if (!trimmed) return "";
177
- const withoutProtocol = trimmed.replace(/^https?:\/\//i, "").replace(/^www\./i, "");
178
- if (/^paypal\.me(?:[?#].*)?$/i.test(withoutProtocol)) return "";
179
- const withoutDomain = withoutProtocol.replace(/^paypal\.me\//i, "");
180
- const [pathWithoutQuery] = withoutDomain.split(/[?#]/, 1);
188
+ const withoutProtocol = trimmed.replace(/^https?:\/\//i, "");
189
+ const [pathWithoutQuery] = withoutProtocol.split(/[?#]/, 1);
181
190
  const sanitizedPath = pathWithoutQuery.replace(/^\/+/, "");
182
- const [username] = sanitizedPath.split("/", 1);
183
- 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;
184
221
  }
185
222
  var BLUEPRINTS = {
186
223
  venmo: {
@@ -232,9 +269,9 @@ var BLUEPRINTS = {
232
269
  transform: (v) => v.replace(/^@+/, "").trim(),
233
270
  extensionRegistration: {
234
271
  providerId: "wise",
235
- requiredPrompt: "This Wisetag is not registered yet. Verify it in the Peer extension, then refresh and retry with the same Wisetag.",
236
- ctaLabel: "Install Peer Extension",
237
- 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"
238
275
  }
239
276
  },
240
277
  mercadopago: {
@@ -251,7 +288,11 @@ var BLUEPRINTS = {
251
288
  identifierLabel: "Email",
252
289
  placeholder: "email",
253
290
  helperText: "Registered Zelle email",
254
- 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()
255
296
  },
256
297
  paypal: {
257
298
  id: "paypal",
@@ -259,14 +300,17 @@ var BLUEPRINTS = {
259
300
  identifierLabel: "PayPal.me Username",
260
301
  placeholder: "paypal.me/your-username",
261
302
  helperText: "Your PayPal.me username, not your email",
262
- 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
+ ),
263
307
  transform: normalizePaypalMeUsername,
264
308
  extensionRegistration: {
265
309
  providerId: "paypal",
266
- requiredPrompt: "This PayPal username is not registered yet. Verify it in the Peer extension, then refresh and retry with the same PayPal username.",
267
- 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",
268
312
  ctaSubtext: "PayPal Business accounts are not supported at this time.",
269
- minExtensionVersion: "0.4.14"
313
+ minExtensionVersion: "0.5.0"
270
314
  }
271
315
  },
272
316
  monzo: {
@@ -283,8 +327,20 @@ var BLUEPRINTS = {
283
327
  identifierLabel: "IBAN",
284
328
  placeholder: "IBAN (e.g. DE89...)",
285
329
  helperText: "Your IBAN (spaces will be removed)",
286
- 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"),
287
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()
288
344
  }
289
345
  };
290
346
  function buildPlatformEntry(bp) {
@@ -323,7 +379,8 @@ var PLATFORMS = {
323
379
  ZELLE: buildPlatformEntry(BLUEPRINTS.zelle),
324
380
  PAYPAL: buildPlatformEntry(BLUEPRINTS.paypal),
325
381
  MONZO: buildPlatformEntry(BLUEPRINTS.monzo),
326
- N26: buildPlatformEntry(BLUEPRINTS.n26)
382
+ N26: buildPlatformEntry(BLUEPRINTS.n26),
383
+ LUXON: buildPlatformEntry(BLUEPRINTS.luxon)
327
384
  };
328
385
  function getPlatformById(id) {
329
386
  return Object.values(PLATFORMS).find((p) => p.id === id) ?? null;
@@ -433,349 +490,7 @@ function isUserCancellation(error) {
433
490
  // src/otc.ts
434
491
  var import_viem = require("viem");
435
492
  var import_chains = require("viem/chains");
436
-
437
- // ../../node_modules/@zkp2p/contracts-v2/abis/base/WhitelistPreIntentHook.json
438
- var WhitelistPreIntentHook_default = [
439
- {
440
- inputs: [
441
- {
442
- internalType: "address",
443
- name: "_orchestratorRegistry",
444
- type: "address"
445
- }
446
- ],
447
- stateMutability: "nonpayable",
448
- type: "constructor"
449
- },
450
- {
451
- inputs: [],
452
- name: "EmptyArray",
453
- type: "error"
454
- },
455
- {
456
- inputs: [
457
- {
458
- internalType: "address",
459
- name: "taker",
460
- type: "address"
461
- },
462
- {
463
- internalType: "address",
464
- name: "escrow",
465
- type: "address"
466
- },
467
- {
468
- internalType: "uint256",
469
- name: "depositId",
470
- type: "uint256"
471
- }
472
- ],
473
- name: "TakerNotInWhitelist",
474
- type: "error"
475
- },
476
- {
477
- inputs: [
478
- {
479
- internalType: "address",
480
- name: "taker",
481
- type: "address"
482
- },
483
- {
484
- internalType: "address",
485
- name: "escrow",
486
- type: "address"
487
- },
488
- {
489
- internalType: "uint256",
490
- name: "depositId",
491
- type: "uint256"
492
- }
493
- ],
494
- name: "TakerNotWhitelisted",
495
- type: "error"
496
- },
497
- {
498
- inputs: [
499
- {
500
- internalType: "address",
501
- name: "caller",
502
- type: "address"
503
- },
504
- {
505
- internalType: "address",
506
- name: "owner",
507
- type: "address"
508
- },
509
- {
510
- internalType: "address",
511
- name: "delegate",
512
- type: "address"
513
- }
514
- ],
515
- name: "UnauthorizedCallerOrDelegate",
516
- type: "error"
517
- },
518
- {
519
- inputs: [
520
- {
521
- internalType: "address",
522
- name: "caller",
523
- type: "address"
524
- }
525
- ],
526
- name: "UnauthorizedOrchestratorCaller",
527
- type: "error"
528
- },
529
- {
530
- inputs: [],
531
- name: "ZeroAddress",
532
- type: "error"
533
- },
534
- {
535
- anonymous: false,
536
- inputs: [
537
- {
538
- indexed: true,
539
- internalType: "address",
540
- name: "escrow",
541
- type: "address"
542
- },
543
- {
544
- indexed: true,
545
- internalType: "uint256",
546
- name: "depositId",
547
- type: "uint256"
548
- },
549
- {
550
- indexed: true,
551
- internalType: "address",
552
- name: "taker",
553
- type: "address"
554
- }
555
- ],
556
- name: "TakerRemovedFromWhitelist",
557
- type: "event"
558
- },
559
- {
560
- anonymous: false,
561
- inputs: [
562
- {
563
- indexed: true,
564
- internalType: "address",
565
- name: "escrow",
566
- type: "address"
567
- },
568
- {
569
- indexed: true,
570
- internalType: "uint256",
571
- name: "depositId",
572
- type: "uint256"
573
- },
574
- {
575
- indexed: true,
576
- internalType: "address",
577
- name: "taker",
578
- type: "address"
579
- }
580
- ],
581
- name: "TakerWhitelisted",
582
- type: "event"
583
- },
584
- {
585
- inputs: [
586
- {
587
- internalType: "address",
588
- name: "_escrow",
589
- type: "address"
590
- },
591
- {
592
- internalType: "uint256",
593
- name: "_depositId",
594
- type: "uint256"
595
- },
596
- {
597
- internalType: "address[]",
598
- name: "_takers",
599
- type: "address[]"
600
- }
601
- ],
602
- name: "addToWhitelist",
603
- outputs: [],
604
- stateMutability: "nonpayable",
605
- type: "function"
606
- },
607
- {
608
- inputs: [
609
- {
610
- internalType: "address",
611
- name: "_escrow",
612
- type: "address"
613
- },
614
- {
615
- internalType: "uint256",
616
- name: "_depositId",
617
- type: "uint256"
618
- },
619
- {
620
- internalType: "address",
621
- name: "_taker",
622
- type: "address"
623
- }
624
- ],
625
- name: "isWhitelisted",
626
- outputs: [
627
- {
628
- internalType: "bool",
629
- name: "",
630
- type: "bool"
631
- }
632
- ],
633
- stateMutability: "view",
634
- type: "function"
635
- },
636
- {
637
- inputs: [],
638
- name: "orchestratorRegistry",
639
- outputs: [
640
- {
641
- internalType: "contract IOrchestratorRegistry",
642
- name: "",
643
- type: "address"
644
- }
645
- ],
646
- stateMutability: "view",
647
- type: "function"
648
- },
649
- {
650
- inputs: [
651
- {
652
- internalType: "address",
653
- name: "_escrow",
654
- type: "address"
655
- },
656
- {
657
- internalType: "uint256",
658
- name: "_depositId",
659
- type: "uint256"
660
- },
661
- {
662
- internalType: "address[]",
663
- name: "_takers",
664
- type: "address[]"
665
- }
666
- ],
667
- name: "removeFromWhitelist",
668
- outputs: [],
669
- stateMutability: "nonpayable",
670
- type: "function"
671
- },
672
- {
673
- inputs: [
674
- {
675
- components: [
676
- {
677
- internalType: "address",
678
- name: "taker",
679
- type: "address"
680
- },
681
- {
682
- internalType: "address",
683
- name: "escrow",
684
- type: "address"
685
- },
686
- {
687
- internalType: "uint256",
688
- name: "depositId",
689
- type: "uint256"
690
- },
691
- {
692
- internalType: "uint256",
693
- name: "amount",
694
- type: "uint256"
695
- },
696
- {
697
- internalType: "address",
698
- name: "to",
699
- type: "address"
700
- },
701
- {
702
- internalType: "bytes32",
703
- name: "paymentMethod",
704
- type: "bytes32"
705
- },
706
- {
707
- internalType: "bytes32",
708
- name: "fiatCurrency",
709
- type: "bytes32"
710
- },
711
- {
712
- internalType: "uint256",
713
- name: "conversionRate",
714
- type: "uint256"
715
- },
716
- {
717
- components: [
718
- {
719
- internalType: "address",
720
- name: "recipient",
721
- type: "address"
722
- },
723
- {
724
- internalType: "uint256",
725
- name: "fee",
726
- type: "uint256"
727
- }
728
- ],
729
- internalType: "struct IReferralFee.ReferralFee[]",
730
- name: "referralFees",
731
- type: "tuple[]"
732
- },
733
- {
734
- internalType: "bytes",
735
- name: "preIntentHookData",
736
- type: "bytes"
737
- }
738
- ],
739
- internalType: "struct IPreIntentHook.PreIntentContext",
740
- name: "_ctx",
741
- type: "tuple"
742
- }
743
- ],
744
- name: "validateSignalIntent",
745
- outputs: [],
746
- stateMutability: "view",
747
- type: "function"
748
- },
749
- {
750
- inputs: [
751
- {
752
- internalType: "address",
753
- name: "",
754
- type: "address"
755
- },
756
- {
757
- internalType: "uint256",
758
- name: "",
759
- type: "uint256"
760
- },
761
- {
762
- internalType: "address",
763
- name: "",
764
- type: "address"
765
- }
766
- ],
767
- name: "whitelist",
768
- outputs: [
769
- {
770
- internalType: "bool",
771
- name: "",
772
- type: "bool"
773
- }
774
- ],
775
- stateMutability: "view",
776
- type: "function"
777
- }
778
- ];
493
+ var import_WhitelistPreIntentHook = __toESM(require("@zkp2p/contracts-v2/abis/base/WhitelistPreIntentHook.json"), 1);
779
494
 
780
495
  // src/sdk-client.ts
781
496
  var import_sdk4 = require("@zkp2p/sdk");
@@ -791,7 +506,7 @@ function createSdkClient(walletClient) {
791
506
 
792
507
  // src/otc.ts
793
508
  var WHITELIST_HOOK_ADDRESS = "0xda023Ea0d789A41BcF5866F7B6BBd2CaDF9b79B8";
794
- var OTC_BASE_URL = "https://usdctofiat.xyz";
509
+ var OTC_BASE_URL = "https://otc.usdctofiat.xyz";
795
510
  async function enableOtc(walletClient, depositId, takerAddress, escrowAddress) {
796
511
  if (!(0, import_viem.isAddress)(takerAddress)) {
797
512
  throw new OfframpError("Invalid taker address", "VALIDATION");
@@ -842,7 +557,7 @@ async function enableOtc(walletClient, depositId, takerAddress, escrowAddress) {
842
557
  }
843
558
  function getOtcLink(depositId, escrowAddress) {
844
559
  const escrow = escrowAddress || ESCROW_ADDRESS;
845
- return `${OTC_BASE_URL}/deposit/${escrow}/${depositId}`;
560
+ return `${OTC_BASE_URL}/d/${escrow}/${depositId}`;
846
561
  }
847
562
  async function writeContract(walletClient, functionName, args) {
848
563
  const wc = walletClient;
@@ -851,7 +566,7 @@ async function writeContract(walletClient, functionName, args) {
851
566
  }
852
567
  await wc.writeContract({
853
568
  address: WHITELIST_HOOK_ADDRESS,
854
- abi: WhitelistPreIntentHook_default,
569
+ abi: import_WhitelistPreIntentHook.default,
855
570
  functionName,
856
571
  args
857
572
  });
@@ -860,7 +575,7 @@ async function readIsWhitelisted(escrow, depositId, taker) {
860
575
  const publicClient = (0, import_viem.createPublicClient)({ chain: import_chains.base, transport: (0, import_viem.http)(BASE_RPC_URL) });
861
576
  return publicClient.readContract({
862
577
  address: WHITELIST_HOOK_ADDRESS,
863
- abi: WhitelistPreIntentHook_default,
578
+ abi: import_WhitelistPreIntentHook.default,
864
579
  functionName: "isWhitelisted",
865
580
  args: [escrow, depositId, taker]
866
581
  });
@@ -1148,6 +863,28 @@ async function registerPayeeDetails(processorName, payload) {
1148
863
  clearTimeout(timeout);
1149
864
  }
1150
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
+ }
1151
888
  function attachOracleConfig(entries, conversionRates) {
1152
889
  return entries.map(
1153
890
  (group, gi) => group.map((entry, ci) => {
@@ -1319,6 +1056,17 @@ async function offramp(walletClient, params, onProgress, telemetryContext) {
1319
1056
  } catch (err) {
1320
1057
  if (err instanceof OfframpError) throw err;
1321
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
+ }
1322
1070
  const client = createSdkClient(walletClient);
1323
1071
  const txOverrides = { referrer: [REFERRER] };
1324
1072
  emitProgress({ step: "approving" });
@@ -1343,7 +1091,6 @@ async function offramp(walletClient, params, onProgress, telemetryContext) {
1343
1091
  }
1344
1092
  emitProgress({ step: "registering" });
1345
1093
  let hashedOnchainId;
1346
- const canonicalName = platformId.startsWith("zelle") ? "zelle" : platformId;
1347
1094
  try {
1348
1095
  const payeePayload = buildDepositData(canonicalName, normalizedIdentifier);
1349
1096
  hashedOnchainId = await registerPayeeDetails(canonicalName, payeePayload);