@usdctofiat/offramp 3.0.3 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/README.md +128 -23
- package/dist/{chunk-4KKKDDES.js → chunk-XQ7HOLLB.js} +292 -96
- package/dist/chunk-XQ7HOLLB.js.map +1 -0
- package/dist/{errors-D9bV_DWE.d.cts → errors-DzTiflBh.d.cts} +161 -6
- package/dist/{errors-D9bV_DWE.d.ts → errors-DzTiflBh.d.ts} +161 -6
- package/dist/index.cjs +297 -92
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -5
- package/dist/index.d.ts +9 -5
- package/dist/index.js +9 -3
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +385 -111
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +23 -13
- package/dist/react.d.ts +23 -13
- package/dist/react.js +106 -27
- package/dist/react.js.map +1 -1
- package/package.json +2 -2
- package/dist/chunk-4KKKDDES.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -40,8 +40,9 @@ __export(index_exports, {
|
|
|
40
40
|
PLATFORMS: () => PLATFORMS,
|
|
41
41
|
PLATFORM_LIMITS: () => PLATFORM_LIMITS,
|
|
42
42
|
close: () => close,
|
|
43
|
+
completePeerExtensionRegistration: () => completePeerExtensionRegistration,
|
|
43
44
|
createOfframp: () => createOfframp,
|
|
44
|
-
createPeerExtensionSdk: () =>
|
|
45
|
+
createPeerExtensionSdk: () => createPeerExtensionSdk,
|
|
45
46
|
createTelemetryContext: () => createTelemetryContext,
|
|
46
47
|
delegate: () => delegate,
|
|
47
48
|
deposits: () => deposits,
|
|
@@ -49,16 +50,18 @@ __export(index_exports, {
|
|
|
49
50
|
emitEvent: () => emitEvent,
|
|
50
51
|
enableOtc: () => enableOtc,
|
|
51
52
|
getOtcLink: () => getOtcLink,
|
|
53
|
+
getPeerExtensionRegistrationAuthParams: () => getPeerExtensionRegistrationAuthParams,
|
|
52
54
|
getPeerExtensionRegistrationInfo: () => getPeerExtensionRegistrationInfo,
|
|
53
|
-
getPeerExtensionState: () =>
|
|
55
|
+
getPeerExtensionState: () => getPeerExtensionState,
|
|
54
56
|
getPlatformLimits: () => getPlatformLimits,
|
|
55
|
-
isPeerExtensionAvailable: () =>
|
|
57
|
+
isPeerExtensionAvailable: () => isPeerExtensionAvailable,
|
|
58
|
+
isPeerExtensionMetadataBridgeAvailable: () => isPeerExtensionMetadataBridgeAvailable,
|
|
56
59
|
isPeerExtensionRegistrationError: () => isPeerExtensionRegistrationError,
|
|
57
60
|
isValidIBAN: () => isValidIBAN,
|
|
58
61
|
normalizePaypalMeUsername: () => normalizePaypalMeUsername,
|
|
59
62
|
offramp: () => offramp,
|
|
60
|
-
openPeerExtensionInstallPage: () =>
|
|
61
|
-
peerExtensionSdk: () =>
|
|
63
|
+
openPeerExtensionInstallPage: () => openPeerExtensionInstallPage,
|
|
64
|
+
peerExtensionSdk: () => peerExtensionSdk,
|
|
62
65
|
sanitizeAttributionId: () => sanitizeAttributionId,
|
|
63
66
|
sendTelemetryEvent: () => sendTelemetryEvent,
|
|
64
67
|
undelegate: () => undelegate
|
|
@@ -72,11 +75,15 @@ var import_sdk5 = require("@zkp2p/sdk");
|
|
|
72
75
|
|
|
73
76
|
// src/config.ts
|
|
74
77
|
var import_sdk = require("@zkp2p/sdk");
|
|
75
|
-
var SDK_VERSION = "3.0
|
|
78
|
+
var SDK_VERSION = "3.1.0";
|
|
76
79
|
var BASE_CHAIN_ID = 8453;
|
|
77
80
|
var RUNTIME_ENV = "production";
|
|
78
81
|
var API_BASE_URL = "https://api.zkp2p.xyz";
|
|
79
82
|
var BASE_RPC_URL = "https://mainnet.base.org";
|
|
83
|
+
function resolveApiBaseUrl(override) {
|
|
84
|
+
const trimmed = override?.trim();
|
|
85
|
+
return (trimmed && trimmed.length > 0 ? trimmed : API_BASE_URL).replace(/\/$/, "");
|
|
86
|
+
}
|
|
80
87
|
var contracts = (0, import_sdk.getContracts)(BASE_CHAIN_ID, RUNTIME_ENV);
|
|
81
88
|
var addresses = contracts.addresses;
|
|
82
89
|
var addrs = addresses;
|
|
@@ -93,6 +100,7 @@ var DEFAULT_INTENT_GUARDIAN_ADDRESS = "0xe29a5BD4D0CEbA6C125A0361E7D20ab4eA275C2
|
|
|
93
100
|
var REFERRER = "galleonlabs";
|
|
94
101
|
var MIN_DEPOSIT_USDC = 1;
|
|
95
102
|
var MIN_ORDER_USDC = 1;
|
|
103
|
+
var MAX_ORDER_USDC = 2500;
|
|
96
104
|
var INDEXER_MAX_ATTEMPTS = 12;
|
|
97
105
|
var INDEXER_INITIAL_DELAY_MS = 1e3;
|
|
98
106
|
var INDEXER_MAX_DELAY_MS = 1e4;
|
|
@@ -101,6 +109,41 @@ var PAYEE_REGISTRATION_TIMEOUT_MS = 8e3;
|
|
|
101
109
|
// src/platforms.ts
|
|
102
110
|
var import_sdk2 = require("@zkp2p/sdk");
|
|
103
111
|
var import_zod = require("zod");
|
|
112
|
+
|
|
113
|
+
// src/errors.ts
|
|
114
|
+
var MakersCreateError = class extends Error {
|
|
115
|
+
status;
|
|
116
|
+
body;
|
|
117
|
+
constructor(message, status, body) {
|
|
118
|
+
super(message);
|
|
119
|
+
this.name = "MakersCreateError";
|
|
120
|
+
this.status = status;
|
|
121
|
+
this.body = body;
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
var OfframpError = class extends Error {
|
|
125
|
+
code;
|
|
126
|
+
step;
|
|
127
|
+
cause;
|
|
128
|
+
txHash;
|
|
129
|
+
depositId;
|
|
130
|
+
constructor(message, code, step, cause, details) {
|
|
131
|
+
super(message);
|
|
132
|
+
this.name = "OfframpError";
|
|
133
|
+
this.code = code;
|
|
134
|
+
this.step = step;
|
|
135
|
+
this.cause = cause;
|
|
136
|
+
this.txHash = details?.txHash;
|
|
137
|
+
this.depositId = details?.depositId;
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
function isUserCancellation(error) {
|
|
141
|
+
if (!(error instanceof Error)) return false;
|
|
142
|
+
const msg = error.message.toLowerCase();
|
|
143
|
+
return msg.includes("user rejected") || msg.includes("user denied") || msg.includes("user cancelled") || msg.includes("rejected the request") || msg.includes("action_rejected");
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// src/platforms.ts
|
|
104
147
|
var PAYMENT_CATALOG = (0, import_sdk2.getPaymentMethodsCatalog)(BASE_CHAIN_ID, RUNTIME_ENV);
|
|
105
148
|
var ZELLE_HASH_LOOKUP_NAMES = ["zelle", "zelle-bofa", "zelle-chase", "zelle-citi"];
|
|
106
149
|
var FALLBACK_CURRENCIES = {
|
|
@@ -461,6 +504,146 @@ function getPeerExtensionRegistrationInfo(platform) {
|
|
|
461
504
|
const entry = getPlatformById(platform);
|
|
462
505
|
return entry?.extensionRegistration ?? null;
|
|
463
506
|
}
|
|
507
|
+
function getPeerExtensionRegistrationAuthParams(platform, options = {}) {
|
|
508
|
+
const info = getPeerExtensionRegistrationInfo(platform);
|
|
509
|
+
if (!info) return null;
|
|
510
|
+
const params = {
|
|
511
|
+
actionType: `transfer_${info.providerId}`,
|
|
512
|
+
captureMode: "sellerCredential",
|
|
513
|
+
platform: info.providerId
|
|
514
|
+
};
|
|
515
|
+
if (options.attestationServiceUrl) {
|
|
516
|
+
params.attestationServiceUrl = options.attestationServiceUrl;
|
|
517
|
+
}
|
|
518
|
+
return params;
|
|
519
|
+
}
|
|
520
|
+
function resolveRegistrationProcessor(platform) {
|
|
521
|
+
const info = getPeerExtensionRegistrationInfo(platform.id);
|
|
522
|
+
if (info?.providerId === "paypal" || info?.providerId === "wise") {
|
|
523
|
+
return info.providerId;
|
|
524
|
+
}
|
|
525
|
+
throw new Error(`${platform.name} does not require Peer extension registration.`);
|
|
526
|
+
}
|
|
527
|
+
async function postMakerCreate(processorName, payload, apiBaseUrl = API_BASE_URL) {
|
|
528
|
+
const controller = new AbortController();
|
|
529
|
+
const timeout = setTimeout(() => controller.abort(), PAYEE_REGISTRATION_TIMEOUT_MS);
|
|
530
|
+
try {
|
|
531
|
+
const res = await fetch(`${apiBaseUrl}/v2/makers/create`, {
|
|
532
|
+
method: "POST",
|
|
533
|
+
headers: { "Content-Type": "application/json" },
|
|
534
|
+
body: JSON.stringify({ processorName, ...payload }),
|
|
535
|
+
signal: controller.signal
|
|
536
|
+
});
|
|
537
|
+
if (!res.ok) {
|
|
538
|
+
const txt = await res.text().catch(() => "");
|
|
539
|
+
let detail = txt || res.statusText;
|
|
540
|
+
try {
|
|
541
|
+
const parsed = JSON.parse(txt);
|
|
542
|
+
if (typeof parsed.message === "string" && parsed.message.trim()) {
|
|
543
|
+
detail = parsed.message;
|
|
544
|
+
}
|
|
545
|
+
} catch {
|
|
546
|
+
}
|
|
547
|
+
throw new MakersCreateError(
|
|
548
|
+
`makers/create failed (${res.status}): ${detail}`,
|
|
549
|
+
res.status,
|
|
550
|
+
txt
|
|
551
|
+
);
|
|
552
|
+
}
|
|
553
|
+
const json = await res.json();
|
|
554
|
+
if (!json.success || !json.responseObject?.hashedOnchainId) {
|
|
555
|
+
throw new MakersCreateError(
|
|
556
|
+
json.message || "makers/create returned no hashedOnchainId",
|
|
557
|
+
json.statusCode ?? null,
|
|
558
|
+
""
|
|
559
|
+
);
|
|
560
|
+
}
|
|
561
|
+
return json.responseObject.hashedOnchainId;
|
|
562
|
+
} finally {
|
|
563
|
+
clearTimeout(timeout);
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
function requireSarCredentialCapture(capturedMetadata) {
|
|
567
|
+
const capture = capturedMetadata.sarCredentialCapture;
|
|
568
|
+
if (!capture?.credentialBundle) {
|
|
569
|
+
throw new Error("Peer metadata did not include a seller credential bundle.");
|
|
570
|
+
}
|
|
571
|
+
if (!capture.offchainId) {
|
|
572
|
+
throw new Error("Peer metadata did not include seller credential offchainId.");
|
|
573
|
+
}
|
|
574
|
+
return capture;
|
|
575
|
+
}
|
|
576
|
+
async function uploadSellerCredentialBundle(processorName, payeeHash, bundle) {
|
|
577
|
+
const controller = new AbortController();
|
|
578
|
+
const timeout = setTimeout(() => controller.abort(), PAYEE_REGISTRATION_TIMEOUT_MS);
|
|
579
|
+
try {
|
|
580
|
+
const res = await fetch(
|
|
581
|
+
`${API_BASE_URL}/v2/makers/${encodeURIComponent(processorName)}/${encodeURIComponent(payeeHash)}/seller-credential`,
|
|
582
|
+
{
|
|
583
|
+
method: "POST",
|
|
584
|
+
headers: { "Content-Type": "application/json" },
|
|
585
|
+
body: JSON.stringify(bundle),
|
|
586
|
+
signal: controller.signal
|
|
587
|
+
}
|
|
588
|
+
);
|
|
589
|
+
if (!res.ok) {
|
|
590
|
+
const txt = await res.text().catch(() => "");
|
|
591
|
+
let detail = txt || res.statusText;
|
|
592
|
+
try {
|
|
593
|
+
const parsed = JSON.parse(txt);
|
|
594
|
+
if (typeof parsed.message === "string" && parsed.message.trim()) {
|
|
595
|
+
detail = parsed.message;
|
|
596
|
+
}
|
|
597
|
+
} catch {
|
|
598
|
+
}
|
|
599
|
+
throw new Error(`seller-credential upload failed (${res.status}): ${detail}`);
|
|
600
|
+
}
|
|
601
|
+
const json = await res.json();
|
|
602
|
+
if (!json.success || !json.responseObject) {
|
|
603
|
+
throw new Error(json.message || "seller-credential upload returned no status.");
|
|
604
|
+
}
|
|
605
|
+
return json;
|
|
606
|
+
} finally {
|
|
607
|
+
clearTimeout(timeout);
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
async function completePeerExtensionRegistration(input) {
|
|
611
|
+
const processorName = resolveRegistrationProcessor(input.platform);
|
|
612
|
+
if (input.capturedMetadata.platform !== processorName) {
|
|
613
|
+
throw new Error(
|
|
614
|
+
`Peer metadata is for ${input.capturedMetadata.platform}, not ${processorName}.`
|
|
615
|
+
);
|
|
616
|
+
}
|
|
617
|
+
const sarCredentialCapture = requireSarCredentialCapture(input.capturedMetadata);
|
|
618
|
+
const bundle = sarCredentialCapture.credentialBundle;
|
|
619
|
+
if (bundle.platform.toLowerCase() !== processorName) {
|
|
620
|
+
throw new Error("Seller credential bundle platform does not match registration platform.");
|
|
621
|
+
}
|
|
622
|
+
const validation = input.platform.validate(input.identifier);
|
|
623
|
+
if (!validation.valid) {
|
|
624
|
+
throw new Error(validation.error || "Invalid identifier");
|
|
625
|
+
}
|
|
626
|
+
const payload = buildDepositData(processorName, sarCredentialCapture.offchainId);
|
|
627
|
+
if (payload.offchainId !== validation.normalized) {
|
|
628
|
+
throw new Error("Seller credential offchainId does not match registration identifier.");
|
|
629
|
+
}
|
|
630
|
+
const hashedOnchainId = processorName === "wise" ? bundle.payeeIdHash : await postMakerCreate(processorName, payload);
|
|
631
|
+
if (hashedOnchainId.toLowerCase() !== bundle.payeeIdHash.toLowerCase()) {
|
|
632
|
+
throw new Error("Seller credential payee hash does not match registered payee details.");
|
|
633
|
+
}
|
|
634
|
+
const sellerCredentialResponse = await uploadSellerCredentialBundle(
|
|
635
|
+
processorName,
|
|
636
|
+
hashedOnchainId,
|
|
637
|
+
bundle
|
|
638
|
+
);
|
|
639
|
+
return {
|
|
640
|
+
processorName,
|
|
641
|
+
offchainId: payload.offchainId,
|
|
642
|
+
hashedOnchainId,
|
|
643
|
+
sellerCredentialResponse,
|
|
644
|
+
sellerCredentialStatus: sellerCredentialResponse.responseObject
|
|
645
|
+
};
|
|
646
|
+
}
|
|
464
647
|
var EXTENSION_REGISTRATION_ERROR_PATTERNS = ["creating the maker", "create the maker"];
|
|
465
648
|
function isPeerExtensionRegistrationError(platform, message, statusCode) {
|
|
466
649
|
const info = getPeerExtensionRegistrationInfo(platform);
|
|
@@ -472,39 +655,6 @@ function isPeerExtensionRegistrationError(platform, message, statusCode) {
|
|
|
472
655
|
return EXTENSION_REGISTRATION_ERROR_PATTERNS.some((p) => lower.includes(p));
|
|
473
656
|
}
|
|
474
657
|
|
|
475
|
-
// src/errors.ts
|
|
476
|
-
var MakersCreateError = class extends Error {
|
|
477
|
-
status;
|
|
478
|
-
body;
|
|
479
|
-
constructor(message, status, body) {
|
|
480
|
-
super(message);
|
|
481
|
-
this.name = "MakersCreateError";
|
|
482
|
-
this.status = status;
|
|
483
|
-
this.body = body;
|
|
484
|
-
}
|
|
485
|
-
};
|
|
486
|
-
var OfframpError = class extends Error {
|
|
487
|
-
code;
|
|
488
|
-
step;
|
|
489
|
-
cause;
|
|
490
|
-
txHash;
|
|
491
|
-
depositId;
|
|
492
|
-
constructor(message, code, step, cause, details) {
|
|
493
|
-
super(message);
|
|
494
|
-
this.name = "OfframpError";
|
|
495
|
-
this.code = code;
|
|
496
|
-
this.step = step;
|
|
497
|
-
this.cause = cause;
|
|
498
|
-
this.txHash = details?.txHash;
|
|
499
|
-
this.depositId = details?.depositId;
|
|
500
|
-
}
|
|
501
|
-
};
|
|
502
|
-
function isUserCancellation(error) {
|
|
503
|
-
if (!(error instanceof Error)) return false;
|
|
504
|
-
const msg = error.message.toLowerCase();
|
|
505
|
-
return msg.includes("user rejected") || msg.includes("user denied") || msg.includes("user cancelled") || msg.includes("rejected the request") || msg.includes("action_rejected");
|
|
506
|
-
}
|
|
507
|
-
|
|
508
658
|
// src/otc.ts
|
|
509
659
|
var import_viem = require("viem");
|
|
510
660
|
var import_chains = require("viem/chains");
|
|
@@ -512,13 +662,13 @@ var import_WhitelistPreIntentHook = __toESM(require("@zkp2p/contracts-v2/abis/ba
|
|
|
512
662
|
|
|
513
663
|
// src/sdk-client.ts
|
|
514
664
|
var import_sdk3 = require("@zkp2p/sdk");
|
|
515
|
-
function createSdkClient(walletClient) {
|
|
665
|
+
function createSdkClient(walletClient, apiBaseUrl = API_BASE_URL) {
|
|
516
666
|
return new import_sdk3.OfframpClient({
|
|
517
667
|
walletClient,
|
|
518
668
|
chainId: BASE_CHAIN_ID,
|
|
519
669
|
runtimeEnv: RUNTIME_ENV,
|
|
520
670
|
rpcUrl: BASE_RPC_URL,
|
|
521
|
-
baseApiUrl:
|
|
671
|
+
baseApiUrl: apiBaseUrl
|
|
522
672
|
});
|
|
523
673
|
}
|
|
524
674
|
|
|
@@ -929,50 +1079,11 @@ function extractDepositIdFromLogs(logs) {
|
|
|
929
1079
|
}
|
|
930
1080
|
return null;
|
|
931
1081
|
}
|
|
932
|
-
async function
|
|
1082
|
+
async function validatePayeeDetails(processorName, offchainId, apiBaseUrl = API_BASE_URL) {
|
|
933
1083
|
const controller = new AbortController();
|
|
934
1084
|
const timeout = setTimeout(() => controller.abort(), PAYEE_REGISTRATION_TIMEOUT_MS);
|
|
935
1085
|
try {
|
|
936
|
-
const res = await fetch(`${
|
|
937
|
-
method: "POST",
|
|
938
|
-
headers: { "Content-Type": "application/json" },
|
|
939
|
-
body: JSON.stringify({ processorName, ...payload }),
|
|
940
|
-
signal: controller.signal
|
|
941
|
-
});
|
|
942
|
-
if (!res.ok) {
|
|
943
|
-
const txt = await res.text().catch(() => "");
|
|
944
|
-
let detail = txt || res.statusText;
|
|
945
|
-
try {
|
|
946
|
-
const parsed = JSON.parse(txt);
|
|
947
|
-
if (typeof parsed.message === "string" && parsed.message.trim()) {
|
|
948
|
-
detail = parsed.message;
|
|
949
|
-
}
|
|
950
|
-
} catch {
|
|
951
|
-
}
|
|
952
|
-
throw new MakersCreateError(
|
|
953
|
-
`makers/create failed (${res.status}): ${detail}`,
|
|
954
|
-
res.status,
|
|
955
|
-
txt
|
|
956
|
-
);
|
|
957
|
-
}
|
|
958
|
-
const json = await res.json();
|
|
959
|
-
if (!json.success || !json.responseObject?.hashedOnchainId) {
|
|
960
|
-
throw new MakersCreateError(
|
|
961
|
-
json.message || "makers/create returned no hashedOnchainId",
|
|
962
|
-
json.statusCode ?? null,
|
|
963
|
-
""
|
|
964
|
-
);
|
|
965
|
-
}
|
|
966
|
-
return json.responseObject.hashedOnchainId;
|
|
967
|
-
} finally {
|
|
968
|
-
clearTimeout(timeout);
|
|
969
|
-
}
|
|
970
|
-
}
|
|
971
|
-
async function validatePayeeDetails(processorName, offchainId) {
|
|
972
|
-
const controller = new AbortController();
|
|
973
|
-
const timeout = setTimeout(() => controller.abort(), PAYEE_REGISTRATION_TIMEOUT_MS);
|
|
974
|
-
try {
|
|
975
|
-
const res = await fetch(`${API_BASE_URL}/v2/makers/validate`, {
|
|
1086
|
+
const res = await fetch(`${apiBaseUrl}/v2/makers/validate`, {
|
|
976
1087
|
method: "POST",
|
|
977
1088
|
headers: { "Content-Type": "application/json" },
|
|
978
1089
|
body: JSON.stringify({ processorName, offchainId }),
|
|
@@ -1050,10 +1161,11 @@ async function findUndelegatedDeposit(walletAddress) {
|
|
|
1050
1161
|
return null;
|
|
1051
1162
|
}
|
|
1052
1163
|
}
|
|
1053
|
-
async function offramp(walletClient, params, onProgress, telemetryContext) {
|
|
1164
|
+
async function offramp(walletClient, params, onProgress, telemetryContext, apiBaseUrl) {
|
|
1054
1165
|
const { amount, platform, currency, identifier } = params;
|
|
1055
1166
|
const platformId = platform.id;
|
|
1056
1167
|
const currencyCode = currency.code;
|
|
1168
|
+
const resolvedApiBaseUrl = resolveApiBaseUrl(apiBaseUrl);
|
|
1057
1169
|
const telemetry = telemetryContext ?? createTelemetryContext({
|
|
1058
1170
|
sdkVersion: SDK_VERSION,
|
|
1059
1171
|
telemetry: true,
|
|
@@ -1098,7 +1210,7 @@ async function offramp(walletClient, params, onProgress, telemetryContext) {
|
|
|
1098
1210
|
const existing = await findUndelegatedDeposit(walletAddress);
|
|
1099
1211
|
if (existing) {
|
|
1100
1212
|
emitProgress({ step: "resuming", depositId: existing.depositId });
|
|
1101
|
-
const client2 = createSdkClient(walletClient);
|
|
1213
|
+
const client2 = createSdkClient(walletClient, resolvedApiBaseUrl);
|
|
1102
1214
|
const txOverrides2 = { referrer: [REFERRER] };
|
|
1103
1215
|
try {
|
|
1104
1216
|
const result2 = await client2.setRateManager({
|
|
@@ -1134,7 +1246,7 @@ async function offramp(walletClient, params, onProgress, telemetryContext) {
|
|
|
1134
1246
|
const truncatedAmount = amt.toFixed(6).replace(/\.?0+$/, "");
|
|
1135
1247
|
const amountUnits = usdcToUnits(truncatedAmount);
|
|
1136
1248
|
const minUnits = usdcToUnits(String(MIN_ORDER_USDC));
|
|
1137
|
-
const maxUnits = usdcToUnits(String(Math.min(amt,
|
|
1249
|
+
const maxUnits = usdcToUnits(String(Math.min(amt, MAX_ORDER_USDC)));
|
|
1138
1250
|
try {
|
|
1139
1251
|
const publicClient = (0, import_viem3.createPublicClient)({ chain: import_chains3.base, transport: (0, import_viem3.http)(BASE_RPC_URL) });
|
|
1140
1252
|
const balance = await publicClient.readContract({
|
|
@@ -1163,7 +1275,11 @@ async function offramp(walletClient, params, onProgress, telemetryContext) {
|
|
|
1163
1275
|
}
|
|
1164
1276
|
const canonicalName = platformId.startsWith("zelle") ? "zelle" : platformId;
|
|
1165
1277
|
if (!getPeerExtensionRegistrationInfo(platformId)) {
|
|
1166
|
-
const outcome = await validatePayeeDetails(
|
|
1278
|
+
const outcome = await validatePayeeDetails(
|
|
1279
|
+
canonicalName,
|
|
1280
|
+
normalizedIdentifier,
|
|
1281
|
+
resolvedApiBaseUrl
|
|
1282
|
+
);
|
|
1167
1283
|
if (outcome === "invalid") {
|
|
1168
1284
|
throw new OfframpError(
|
|
1169
1285
|
`Couldn't verify that ${platform.name} ${platform.identifier.label.toLowerCase()}. Double-check it and try again.`,
|
|
@@ -1172,7 +1288,7 @@ async function offramp(walletClient, params, onProgress, telemetryContext) {
|
|
|
1172
1288
|
);
|
|
1173
1289
|
}
|
|
1174
1290
|
}
|
|
1175
|
-
const client = createSdkClient(walletClient);
|
|
1291
|
+
const client = createSdkClient(walletClient, resolvedApiBaseUrl);
|
|
1176
1292
|
const txOverrides = { referrer: [REFERRER] };
|
|
1177
1293
|
emitProgress({ step: "approving" });
|
|
1178
1294
|
try {
|
|
@@ -1198,13 +1314,13 @@ async function offramp(walletClient, params, onProgress, telemetryContext) {
|
|
|
1198
1314
|
let hashedOnchainId;
|
|
1199
1315
|
try {
|
|
1200
1316
|
const payeePayload = buildDepositData(canonicalName, normalizedIdentifier);
|
|
1201
|
-
hashedOnchainId = await
|
|
1317
|
+
hashedOnchainId = await postMakerCreate(canonicalName, payeePayload, resolvedApiBaseUrl);
|
|
1202
1318
|
} catch (err) {
|
|
1203
1319
|
const status = err instanceof MakersCreateError ? err.status : null;
|
|
1204
1320
|
const message = err instanceof Error ? err.message : String(err);
|
|
1205
1321
|
if (isPeerExtensionRegistrationError(canonicalName, message, status)) {
|
|
1206
1322
|
throw new OfframpError(
|
|
1207
|
-
`${platform.name} maker is not yet registered in the Peer extension.
|
|
1323
|
+
`${platform.name} maker is not yet registered in the Peer extension. Register this handle with Peer, then retry.`,
|
|
1208
1324
|
"EXTENSION_REGISTRATION_REQUIRED",
|
|
1209
1325
|
"registering",
|
|
1210
1326
|
err
|
|
@@ -1396,6 +1512,14 @@ var CURRENCIES = buildCurrencies();
|
|
|
1396
1512
|
// src/offramp.ts
|
|
1397
1513
|
var IDEMPOTENCY_TTL_MS = 10 * 60 * 1e3;
|
|
1398
1514
|
var IDEMPOTENCY_STORAGE_PREFIX = "offramp:idempotency:";
|
|
1515
|
+
var warnedIdempotencyUnavailable = false;
|
|
1516
|
+
function warnIdempotencyUnavailableOnce() {
|
|
1517
|
+
if (warnedIdempotencyUnavailable) return;
|
|
1518
|
+
warnedIdempotencyUnavailable = true;
|
|
1519
|
+
console.warn(
|
|
1520
|
+
"[offramp] idempotencyKey was provided but sessionStorage is unavailable (Node/worker runtime). The idempotency cache is browser-only and no-ops here, so retries can create duplicate deposits. For server-side dedup, call deposits(walletAddress) and reuse an existing open deposit before creating one."
|
|
1521
|
+
);
|
|
1522
|
+
}
|
|
1399
1523
|
function getWalletAddress(walletClient) {
|
|
1400
1524
|
const address = walletClient.account?.address;
|
|
1401
1525
|
if (!address) {
|
|
@@ -1466,8 +1590,10 @@ function buildCurrencyGroups() {
|
|
|
1466
1590
|
var Offramp = class {
|
|
1467
1591
|
walletClient;
|
|
1468
1592
|
telemetry;
|
|
1593
|
+
apiBaseUrl;
|
|
1469
1594
|
constructor(options) {
|
|
1470
1595
|
this.walletClient = options.walletClient;
|
|
1596
|
+
this.apiBaseUrl = options.apiBaseUrl;
|
|
1471
1597
|
this.telemetry = createTelemetryContext({
|
|
1472
1598
|
sdkVersion: SDK_VERSION,
|
|
1473
1599
|
telemetry: options.telemetry,
|
|
@@ -1490,6 +1616,9 @@ var Offramp = class {
|
|
|
1490
1616
|
referralId: flowTelemetry.referralId
|
|
1491
1617
|
};
|
|
1492
1618
|
const sanitizedKey = sanitizeAttributionId(params.idempotencyKey);
|
|
1619
|
+
if (sanitizedKey && typeof sessionStorage === "undefined") {
|
|
1620
|
+
warnIdempotencyUnavailableOnce();
|
|
1621
|
+
}
|
|
1493
1622
|
const walletAddress = sanitizedKey ? getWalletAddress(this.walletClient) : null;
|
|
1494
1623
|
const storageKey = walletAddress && sanitizedKey ? getIdempotencyStorageKey(walletAddress, sanitizedKey) : null;
|
|
1495
1624
|
if (storageKey) {
|
|
@@ -1500,7 +1629,8 @@ var Offramp = class {
|
|
|
1500
1629
|
this.walletClient,
|
|
1501
1630
|
sanitizedParams,
|
|
1502
1631
|
onProgress,
|
|
1503
|
-
flowTelemetry
|
|
1632
|
+
flowTelemetry,
|
|
1633
|
+
this.apiBaseUrl
|
|
1504
1634
|
);
|
|
1505
1635
|
if (storageKey) {
|
|
1506
1636
|
writeIdempotencyResult(storageKey, result);
|
|
@@ -1556,8 +1686,8 @@ var OFFRAMP_ERROR_CODES = {
|
|
|
1556
1686
|
* handle in the Peer extension yet. Thrown from `offramp()` for PayPal
|
|
1557
1687
|
* and Wise when `/v2/makers/create` returns 400 or a "creating the maker"
|
|
1558
1688
|
* message. Recover by prompting the user through the Peer extension via
|
|
1559
|
-
* `usePeerExtensionRegistration(platform)` (React) or
|
|
1560
|
-
*
|
|
1689
|
+
* `usePeerExtensionRegistration(platform)` (React) or
|
|
1690
|
+
* `completePeerExtensionRegistration(...)`, then retrying `offramp()`.
|
|
1561
1691
|
*/
|
|
1562
1692
|
EXTENSION_REGISTRATION_REQUIRED: "EXTENSION_REGISTRATION_REQUIRED",
|
|
1563
1693
|
DEPOSIT_FAILED: "DEPOSIT_FAILED",
|
|
@@ -1569,6 +1699,78 @@ var OFFRAMP_ERROR_CODES = {
|
|
|
1569
1699
|
|
|
1570
1700
|
// src/extension.ts
|
|
1571
1701
|
var import_sdk7 = require("@zkp2p/sdk");
|
|
1702
|
+
var resolveWindow = (options) => {
|
|
1703
|
+
if (options?.window) {
|
|
1704
|
+
return options.window;
|
|
1705
|
+
}
|
|
1706
|
+
if (typeof window === "undefined") {
|
|
1707
|
+
return void 0;
|
|
1708
|
+
}
|
|
1709
|
+
return window;
|
|
1710
|
+
};
|
|
1711
|
+
var requirePeer = (options) => {
|
|
1712
|
+
const resolvedWindow = resolveWindow(options);
|
|
1713
|
+
if (!resolvedWindow) {
|
|
1714
|
+
throw new Error("Peer extension SDK requires a browser window.");
|
|
1715
|
+
}
|
|
1716
|
+
if (!resolvedWindow.peer) {
|
|
1717
|
+
throw new Error("Peer extension not available. Install or enable the Peer extension.");
|
|
1718
|
+
}
|
|
1719
|
+
return resolvedWindow.peer;
|
|
1720
|
+
};
|
|
1721
|
+
var isPeerExtensionAvailable = (options) => {
|
|
1722
|
+
const resolvedWindow = resolveWindow(options);
|
|
1723
|
+
return Boolean(resolvedWindow?.peer);
|
|
1724
|
+
};
|
|
1725
|
+
var hasHeadlessMetadataBridge = (peer) => typeof peer.authenticate === "function" && typeof peer.onMetadataMessage === "function";
|
|
1726
|
+
var requirePeerMetadataBridge = (options) => {
|
|
1727
|
+
const peer = requirePeer(options);
|
|
1728
|
+
if (!hasHeadlessMetadataBridge(peer)) {
|
|
1729
|
+
throw new Error("Peer extension metadata bridge unavailable. Install or update Peer.");
|
|
1730
|
+
}
|
|
1731
|
+
return peer;
|
|
1732
|
+
};
|
|
1733
|
+
var isPeerExtensionMetadataBridgeAvailable = (options) => {
|
|
1734
|
+
const resolvedWindow = resolveWindow(options);
|
|
1735
|
+
return Boolean(resolvedWindow?.peer && hasHeadlessMetadataBridge(resolvedWindow.peer));
|
|
1736
|
+
};
|
|
1737
|
+
var openPeerExtensionInstallPage = (options) => {
|
|
1738
|
+
const resolvedWindow = resolveWindow(options);
|
|
1739
|
+
if (!resolvedWindow) {
|
|
1740
|
+
throw new Error("Peer extension SDK requires a browser window.");
|
|
1741
|
+
}
|
|
1742
|
+
resolvedWindow.open(import_sdk7.PEER_EXTENSION_CHROME_URL, "_blank", "noopener,noreferrer");
|
|
1743
|
+
};
|
|
1744
|
+
var getPeerExtensionState = async (options) => {
|
|
1745
|
+
if (!isPeerExtensionAvailable(options)) {
|
|
1746
|
+
return "needs_install";
|
|
1747
|
+
}
|
|
1748
|
+
try {
|
|
1749
|
+
const status = await requirePeer(options).checkConnectionStatus();
|
|
1750
|
+
return status === "connected" ? "ready" : "needs_connection";
|
|
1751
|
+
} catch {
|
|
1752
|
+
return "needs_connection";
|
|
1753
|
+
}
|
|
1754
|
+
};
|
|
1755
|
+
var createPeerExtensionSdk = (options = {}) => {
|
|
1756
|
+
const legacySdk = (0, import_sdk7.createPeerExtensionSdk)(
|
|
1757
|
+
options
|
|
1758
|
+
);
|
|
1759
|
+
return {
|
|
1760
|
+
isAvailable: () => isPeerExtensionAvailable(options),
|
|
1761
|
+
requestConnection: () => requirePeer(options).requestConnection(),
|
|
1762
|
+
checkConnectionStatus: () => requirePeer(options).checkConnectionStatus(),
|
|
1763
|
+
getVersion: () => requirePeer(options).getVersion(),
|
|
1764
|
+
authenticate: (params) => requirePeerMetadataBridge(options).authenticate(params),
|
|
1765
|
+
onMetadataMessage: (callback) => requirePeerMetadataBridge(options).onMetadataMessage(callback),
|
|
1766
|
+
openSidebar: (route) => legacySdk.openSidebar(route),
|
|
1767
|
+
onramp: (params, callback) => legacySdk.onramp(params, callback),
|
|
1768
|
+
getOnrampTransaction: (intentHash) => legacySdk.getOnrampTransaction(intentHash),
|
|
1769
|
+
openInstallPage: () => openPeerExtensionInstallPage(options),
|
|
1770
|
+
getState: () => getPeerExtensionState(options)
|
|
1771
|
+
};
|
|
1772
|
+
};
|
|
1773
|
+
var peerExtensionSdk = createPeerExtensionSdk();
|
|
1572
1774
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1573
1775
|
0 && (module.exports = {
|
|
1574
1776
|
CURRENCIES,
|
|
@@ -1581,6 +1783,7 @@ var import_sdk7 = require("@zkp2p/sdk");
|
|
|
1581
1783
|
PLATFORMS,
|
|
1582
1784
|
PLATFORM_LIMITS,
|
|
1583
1785
|
close,
|
|
1786
|
+
completePeerExtensionRegistration,
|
|
1584
1787
|
createOfframp,
|
|
1585
1788
|
createPeerExtensionSdk,
|
|
1586
1789
|
createTelemetryContext,
|
|
@@ -1590,10 +1793,12 @@ var import_sdk7 = require("@zkp2p/sdk");
|
|
|
1590
1793
|
emitEvent,
|
|
1591
1794
|
enableOtc,
|
|
1592
1795
|
getOtcLink,
|
|
1796
|
+
getPeerExtensionRegistrationAuthParams,
|
|
1593
1797
|
getPeerExtensionRegistrationInfo,
|
|
1594
1798
|
getPeerExtensionState,
|
|
1595
1799
|
getPlatformLimits,
|
|
1596
1800
|
isPeerExtensionAvailable,
|
|
1801
|
+
isPeerExtensionMetadataBridgeAvailable,
|
|
1597
1802
|
isPeerExtensionRegistrationError,
|
|
1598
1803
|
isValidIBAN,
|
|
1599
1804
|
normalizePaypalMeUsername,
|