@usdctofiat/offramp 3.0.2 → 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 +21 -0
- package/README.md +129 -24
- package/dist/{chunk-F7DVUBMT.js → chunk-XQ7HOLLB.js} +390 -445
- package/dist/chunk-XQ7HOLLB.js.map +1 -0
- package/dist/errors-DzTiflBh.d.cts +409 -0
- package/dist/errors-DzTiflBh.d.ts +409 -0
- package/dist/index.cjs +408 -441
- 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 +15 -3
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +481 -460
- 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 +5 -3
- package/dist/chunk-F7DVUBMT.js.map +0 -1
- package/dist/errors-DKQ2N_ih.d.cts +0 -217
- package/dist/errors-DKQ2N_ih.d.ts +0 -217
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
// src/config.ts
|
|
2
2
|
import { getContracts, getGatingServiceAddress } from "@zkp2p/sdk";
|
|
3
|
-
var SDK_VERSION = "3.0
|
|
3
|
+
var SDK_VERSION = "3.1.0";
|
|
4
4
|
var BASE_CHAIN_ID = 8453;
|
|
5
5
|
var RUNTIME_ENV = "production";
|
|
6
6
|
var API_BASE_URL = "https://api.zkp2p.xyz";
|
|
7
7
|
var BASE_RPC_URL = "https://mainnet.base.org";
|
|
8
|
+
function resolveApiBaseUrl(override) {
|
|
9
|
+
const trimmed = override?.trim();
|
|
10
|
+
return (trimmed && trimmed.length > 0 ? trimmed : API_BASE_URL).replace(/\/$/, "");
|
|
11
|
+
}
|
|
8
12
|
var contracts = getContracts(BASE_CHAIN_ID, RUNTIME_ENV);
|
|
9
13
|
var addresses = contracts.addresses;
|
|
10
14
|
var addrs = addresses;
|
|
@@ -21,11 +25,45 @@ var DEFAULT_INTENT_GUARDIAN_ADDRESS = "0xe29a5BD4D0CEbA6C125A0361E7D20ab4eA275C2
|
|
|
21
25
|
var REFERRER = "galleonlabs";
|
|
22
26
|
var MIN_DEPOSIT_USDC = 1;
|
|
23
27
|
var MIN_ORDER_USDC = 1;
|
|
28
|
+
var MAX_ORDER_USDC = 2500;
|
|
24
29
|
var INDEXER_MAX_ATTEMPTS = 12;
|
|
25
30
|
var INDEXER_INITIAL_DELAY_MS = 1e3;
|
|
26
31
|
var INDEXER_MAX_DELAY_MS = 1e4;
|
|
27
32
|
var PAYEE_REGISTRATION_TIMEOUT_MS = 8e3;
|
|
28
33
|
|
|
34
|
+
// src/errors.ts
|
|
35
|
+
var MakersCreateError = class extends Error {
|
|
36
|
+
status;
|
|
37
|
+
body;
|
|
38
|
+
constructor(message, status, body) {
|
|
39
|
+
super(message);
|
|
40
|
+
this.name = "MakersCreateError";
|
|
41
|
+
this.status = status;
|
|
42
|
+
this.body = body;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
var OfframpError = class extends Error {
|
|
46
|
+
code;
|
|
47
|
+
step;
|
|
48
|
+
cause;
|
|
49
|
+
txHash;
|
|
50
|
+
depositId;
|
|
51
|
+
constructor(message, code, step, cause, details) {
|
|
52
|
+
super(message);
|
|
53
|
+
this.name = "OfframpError";
|
|
54
|
+
this.code = code;
|
|
55
|
+
this.step = step;
|
|
56
|
+
this.cause = cause;
|
|
57
|
+
this.txHash = details?.txHash;
|
|
58
|
+
this.depositId = details?.depositId;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
function isUserCancellation(error) {
|
|
62
|
+
if (!(error instanceof Error)) return false;
|
|
63
|
+
const msg = error.message.toLowerCase();
|
|
64
|
+
return msg.includes("user rejected") || msg.includes("user denied") || msg.includes("user cancelled") || msg.includes("rejected the request") || msg.includes("action_rejected");
|
|
65
|
+
}
|
|
66
|
+
|
|
29
67
|
// src/platforms.ts
|
|
30
68
|
import {
|
|
31
69
|
currencyInfo,
|
|
@@ -102,7 +140,8 @@ var FALLBACK_CURRENCIES = {
|
|
|
102
140
|
zelle: ["USD"],
|
|
103
141
|
paypal: ["USD", "EUR", "GBP", "SGD", "NZD", "AUD", "CAD"],
|
|
104
142
|
monzo: ["GBP"],
|
|
105
|
-
n26: ["EUR"]
|
|
143
|
+
n26: ["EUR"],
|
|
144
|
+
luxon: ["USD", "EUR", "GBP"]
|
|
106
145
|
};
|
|
107
146
|
function gatherCatalogHashes(platform) {
|
|
108
147
|
if (platform === "zelle") {
|
|
@@ -126,13 +165,39 @@ function resolveSupportedCurrencies(platform) {
|
|
|
126
165
|
function normalizePaypalMeUsername(value) {
|
|
127
166
|
const trimmed = value.trim();
|
|
128
167
|
if (!trimmed) return "";
|
|
129
|
-
const withoutProtocol = trimmed.replace(/^https?:\/\//i, "")
|
|
130
|
-
|
|
131
|
-
const withoutDomain = withoutProtocol.replace(/^paypal\.me\//i, "");
|
|
132
|
-
const [pathWithoutQuery] = withoutDomain.split(/[?#]/, 1);
|
|
168
|
+
const withoutProtocol = trimmed.replace(/^https?:\/\//i, "");
|
|
169
|
+
const [pathWithoutQuery] = withoutProtocol.split(/[?#]/, 1);
|
|
133
170
|
const sanitizedPath = pathWithoutQuery.replace(/^\/+/, "");
|
|
134
|
-
const [
|
|
135
|
-
|
|
171
|
+
const [host = "", ...pathSegments] = sanitizedPath.split("/");
|
|
172
|
+
const normalizedHost = host.toLowerCase().replace(/^www\./i, "");
|
|
173
|
+
if (normalizedHost === "paypal.me") {
|
|
174
|
+
const [username = ""] = pathSegments;
|
|
175
|
+
return username.replace(/^@+/, "").trim().toLowerCase();
|
|
176
|
+
}
|
|
177
|
+
if (normalizedHost === "paypal.com") {
|
|
178
|
+
const [paypalMePath = "", username = ""] = pathSegments;
|
|
179
|
+
if (paypalMePath.toLowerCase() !== "paypalme") return "";
|
|
180
|
+
return username.replace(/^@+/, "").trim().toLowerCase();
|
|
181
|
+
}
|
|
182
|
+
if (/^https?:\/\//i.test(trimmed) || trimmed.includes("/")) {
|
|
183
|
+
return trimmed;
|
|
184
|
+
}
|
|
185
|
+
return trimmed.replace(/^@+/, "").toLowerCase();
|
|
186
|
+
}
|
|
187
|
+
function isValidIBAN(iban) {
|
|
188
|
+
const upper = iban.toUpperCase();
|
|
189
|
+
if (!/^[A-Z]{2}[0-9]{2}[A-Z0-9]{11,30}$/.test(upper)) return false;
|
|
190
|
+
const rearranged = upper.slice(4) + upper.slice(0, 4);
|
|
191
|
+
const numeric = rearranged.split("").map((ch) => {
|
|
192
|
+
const code = ch.charCodeAt(0);
|
|
193
|
+
return code >= 65 && code <= 90 ? (code - 55).toString() : ch;
|
|
194
|
+
}).join("");
|
|
195
|
+
let remainder = numeric;
|
|
196
|
+
while (remainder.length > 2) {
|
|
197
|
+
const block = remainder.slice(0, 9);
|
|
198
|
+
remainder = (parseInt(block, 10) % 97).toString() + remainder.slice(block.length);
|
|
199
|
+
}
|
|
200
|
+
return parseInt(remainder, 10) % 97 === 1;
|
|
136
201
|
}
|
|
137
202
|
var BLUEPRINTS = {
|
|
138
203
|
venmo: {
|
|
@@ -184,9 +249,9 @@ var BLUEPRINTS = {
|
|
|
184
249
|
transform: (v) => v.replace(/^@+/, "").trim(),
|
|
185
250
|
extensionRegistration: {
|
|
186
251
|
providerId: "wise",
|
|
187
|
-
requiredPrompt: "This Wisetag is not registered yet.
|
|
188
|
-
ctaLabel: "
|
|
189
|
-
minExtensionVersion: "0.
|
|
252
|
+
requiredPrompt: "This Wisetag is not registered yet. Register it with PeerAuth, then retry with the same Wisetag.",
|
|
253
|
+
ctaLabel: "Register Wisetag",
|
|
254
|
+
minExtensionVersion: "0.5.0"
|
|
190
255
|
}
|
|
191
256
|
},
|
|
192
257
|
mercadopago: {
|
|
@@ -203,7 +268,11 @@ var BLUEPRINTS = {
|
|
|
203
268
|
identifierLabel: "Email",
|
|
204
269
|
placeholder: "email",
|
|
205
270
|
helperText: "Registered Zelle email",
|
|
206
|
-
|
|
271
|
+
// Curator's ZelleProcessor rejects any non-lowercase email outright, so
|
|
272
|
+
// canonicalize to lowercase here rather than letting /v2/makers/create
|
|
273
|
+
// reject after the maker has already approved USDC + paid gas.
|
|
274
|
+
validation: z.string().email(),
|
|
275
|
+
transform: (v) => v.trim().toLowerCase()
|
|
207
276
|
},
|
|
208
277
|
paypal: {
|
|
209
278
|
id: "paypal",
|
|
@@ -211,14 +280,17 @@ var BLUEPRINTS = {
|
|
|
211
280
|
identifierLabel: "PayPal.me Username",
|
|
212
281
|
placeholder: "paypal.me/your-username",
|
|
213
282
|
helperText: "Your PayPal.me username, not your email",
|
|
214
|
-
validation: z.string().min(1, "PayPal.me username is required").regex(
|
|
283
|
+
validation: z.string().min(1, "PayPal.me username is required").regex(
|
|
284
|
+
/^[a-z0-9._-]+$/i,
|
|
285
|
+
"Use your PayPal.me username or paypal.me link, not a shortened URL."
|
|
286
|
+
),
|
|
215
287
|
transform: normalizePaypalMeUsername,
|
|
216
288
|
extensionRegistration: {
|
|
217
289
|
providerId: "paypal",
|
|
218
|
-
requiredPrompt: "This PayPal username is not registered yet.
|
|
219
|
-
ctaLabel: "
|
|
290
|
+
requiredPrompt: "This PayPal username is not registered yet. Register it with PeerAuth, then retry with the same PayPal username.",
|
|
291
|
+
ctaLabel: "Register PayPal Username",
|
|
220
292
|
ctaSubtext: "PayPal Business accounts are not supported at this time.",
|
|
221
|
-
minExtensionVersion: "0.
|
|
293
|
+
minExtensionVersion: "0.5.0"
|
|
222
294
|
}
|
|
223
295
|
},
|
|
224
296
|
monzo: {
|
|
@@ -235,8 +307,20 @@ var BLUEPRINTS = {
|
|
|
235
307
|
identifierLabel: "IBAN",
|
|
236
308
|
placeholder: "IBAN (e.g. DE89...)",
|
|
237
309
|
helperText: "Your IBAN (spaces will be removed)",
|
|
238
|
-
validation
|
|
310
|
+
// transform runs before validation, so the schema sees a spaceless,
|
|
311
|
+
// uppercased IBAN. The MOD-97 refine mirrors curator's N26Processor so a
|
|
312
|
+
// typo'd-but-well-formed IBAN fails here, not after USDC approval + gas.
|
|
313
|
+
validation: 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"),
|
|
239
314
|
transform: (v) => v.replace(/\s/g, "").toUpperCase()
|
|
315
|
+
},
|
|
316
|
+
luxon: {
|
|
317
|
+
id: "luxon",
|
|
318
|
+
name: "Luxon",
|
|
319
|
+
identifierLabel: "Email",
|
|
320
|
+
placeholder: "your-luxon-email@example.com",
|
|
321
|
+
helperText: "Email address registered with Luxon",
|
|
322
|
+
validation: z.string().email(),
|
|
323
|
+
transform: (v) => v.trim()
|
|
240
324
|
}
|
|
241
325
|
};
|
|
242
326
|
function buildPlatformEntry(bp) {
|
|
@@ -275,8 +359,18 @@ var PLATFORMS = {
|
|
|
275
359
|
ZELLE: buildPlatformEntry(BLUEPRINTS.zelle),
|
|
276
360
|
PAYPAL: buildPlatformEntry(BLUEPRINTS.paypal),
|
|
277
361
|
MONZO: buildPlatformEntry(BLUEPRINTS.monzo),
|
|
278
|
-
N26: buildPlatformEntry(BLUEPRINTS.n26)
|
|
362
|
+
N26: buildPlatformEntry(BLUEPRINTS.n26),
|
|
363
|
+
LUXON: buildPlatformEntry(BLUEPRINTS.luxon)
|
|
364
|
+
};
|
|
365
|
+
var PLATFORM_LIMITS = {
|
|
366
|
+
venmo: { platformCapUsd: 5e3 },
|
|
367
|
+
n26: { platformCapUsd: 1e4 },
|
|
368
|
+
paypal: { minTier: "PLUS" }
|
|
279
369
|
};
|
|
370
|
+
function getPlatformLimits(platform) {
|
|
371
|
+
const id = platform.trim().toLowerCase();
|
|
372
|
+
return PLATFORM_LIMITS[id] ?? null;
|
|
373
|
+
}
|
|
280
374
|
function getPlatformById(id) {
|
|
281
375
|
return Object.values(PLATFORMS).find((p) => p.id === id) ?? null;
|
|
282
376
|
}
|
|
@@ -338,6 +432,146 @@ function getPeerExtensionRegistrationInfo(platform) {
|
|
|
338
432
|
const entry = getPlatformById(platform);
|
|
339
433
|
return entry?.extensionRegistration ?? null;
|
|
340
434
|
}
|
|
435
|
+
function getPeerExtensionRegistrationAuthParams(platform, options = {}) {
|
|
436
|
+
const info = getPeerExtensionRegistrationInfo(platform);
|
|
437
|
+
if (!info) return null;
|
|
438
|
+
const params = {
|
|
439
|
+
actionType: `transfer_${info.providerId}`,
|
|
440
|
+
captureMode: "sellerCredential",
|
|
441
|
+
platform: info.providerId
|
|
442
|
+
};
|
|
443
|
+
if (options.attestationServiceUrl) {
|
|
444
|
+
params.attestationServiceUrl = options.attestationServiceUrl;
|
|
445
|
+
}
|
|
446
|
+
return params;
|
|
447
|
+
}
|
|
448
|
+
function resolveRegistrationProcessor(platform) {
|
|
449
|
+
const info = getPeerExtensionRegistrationInfo(platform.id);
|
|
450
|
+
if (info?.providerId === "paypal" || info?.providerId === "wise") {
|
|
451
|
+
return info.providerId;
|
|
452
|
+
}
|
|
453
|
+
throw new Error(`${platform.name} does not require Peer extension registration.`);
|
|
454
|
+
}
|
|
455
|
+
async function postMakerCreate(processorName, payload, apiBaseUrl = API_BASE_URL) {
|
|
456
|
+
const controller = new AbortController();
|
|
457
|
+
const timeout = setTimeout(() => controller.abort(), PAYEE_REGISTRATION_TIMEOUT_MS);
|
|
458
|
+
try {
|
|
459
|
+
const res = await fetch(`${apiBaseUrl}/v2/makers/create`, {
|
|
460
|
+
method: "POST",
|
|
461
|
+
headers: { "Content-Type": "application/json" },
|
|
462
|
+
body: JSON.stringify({ processorName, ...payload }),
|
|
463
|
+
signal: controller.signal
|
|
464
|
+
});
|
|
465
|
+
if (!res.ok) {
|
|
466
|
+
const txt = await res.text().catch(() => "");
|
|
467
|
+
let detail = txt || res.statusText;
|
|
468
|
+
try {
|
|
469
|
+
const parsed = JSON.parse(txt);
|
|
470
|
+
if (typeof parsed.message === "string" && parsed.message.trim()) {
|
|
471
|
+
detail = parsed.message;
|
|
472
|
+
}
|
|
473
|
+
} catch {
|
|
474
|
+
}
|
|
475
|
+
throw new MakersCreateError(
|
|
476
|
+
`makers/create failed (${res.status}): ${detail}`,
|
|
477
|
+
res.status,
|
|
478
|
+
txt
|
|
479
|
+
);
|
|
480
|
+
}
|
|
481
|
+
const json = await res.json();
|
|
482
|
+
if (!json.success || !json.responseObject?.hashedOnchainId) {
|
|
483
|
+
throw new MakersCreateError(
|
|
484
|
+
json.message || "makers/create returned no hashedOnchainId",
|
|
485
|
+
json.statusCode ?? null,
|
|
486
|
+
""
|
|
487
|
+
);
|
|
488
|
+
}
|
|
489
|
+
return json.responseObject.hashedOnchainId;
|
|
490
|
+
} finally {
|
|
491
|
+
clearTimeout(timeout);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
function requireSarCredentialCapture(capturedMetadata) {
|
|
495
|
+
const capture = capturedMetadata.sarCredentialCapture;
|
|
496
|
+
if (!capture?.credentialBundle) {
|
|
497
|
+
throw new Error("Peer metadata did not include a seller credential bundle.");
|
|
498
|
+
}
|
|
499
|
+
if (!capture.offchainId) {
|
|
500
|
+
throw new Error("Peer metadata did not include seller credential offchainId.");
|
|
501
|
+
}
|
|
502
|
+
return capture;
|
|
503
|
+
}
|
|
504
|
+
async function uploadSellerCredentialBundle(processorName, payeeHash, bundle) {
|
|
505
|
+
const controller = new AbortController();
|
|
506
|
+
const timeout = setTimeout(() => controller.abort(), PAYEE_REGISTRATION_TIMEOUT_MS);
|
|
507
|
+
try {
|
|
508
|
+
const res = await fetch(
|
|
509
|
+
`${API_BASE_URL}/v2/makers/${encodeURIComponent(processorName)}/${encodeURIComponent(payeeHash)}/seller-credential`,
|
|
510
|
+
{
|
|
511
|
+
method: "POST",
|
|
512
|
+
headers: { "Content-Type": "application/json" },
|
|
513
|
+
body: JSON.stringify(bundle),
|
|
514
|
+
signal: controller.signal
|
|
515
|
+
}
|
|
516
|
+
);
|
|
517
|
+
if (!res.ok) {
|
|
518
|
+
const txt = await res.text().catch(() => "");
|
|
519
|
+
let detail = txt || res.statusText;
|
|
520
|
+
try {
|
|
521
|
+
const parsed = JSON.parse(txt);
|
|
522
|
+
if (typeof parsed.message === "string" && parsed.message.trim()) {
|
|
523
|
+
detail = parsed.message;
|
|
524
|
+
}
|
|
525
|
+
} catch {
|
|
526
|
+
}
|
|
527
|
+
throw new Error(`seller-credential upload failed (${res.status}): ${detail}`);
|
|
528
|
+
}
|
|
529
|
+
const json = await res.json();
|
|
530
|
+
if (!json.success || !json.responseObject) {
|
|
531
|
+
throw new Error(json.message || "seller-credential upload returned no status.");
|
|
532
|
+
}
|
|
533
|
+
return json;
|
|
534
|
+
} finally {
|
|
535
|
+
clearTimeout(timeout);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
async function completePeerExtensionRegistration(input) {
|
|
539
|
+
const processorName = resolveRegistrationProcessor(input.platform);
|
|
540
|
+
if (input.capturedMetadata.platform !== processorName) {
|
|
541
|
+
throw new Error(
|
|
542
|
+
`Peer metadata is for ${input.capturedMetadata.platform}, not ${processorName}.`
|
|
543
|
+
);
|
|
544
|
+
}
|
|
545
|
+
const sarCredentialCapture = requireSarCredentialCapture(input.capturedMetadata);
|
|
546
|
+
const bundle = sarCredentialCapture.credentialBundle;
|
|
547
|
+
if (bundle.platform.toLowerCase() !== processorName) {
|
|
548
|
+
throw new Error("Seller credential bundle platform does not match registration platform.");
|
|
549
|
+
}
|
|
550
|
+
const validation = input.platform.validate(input.identifier);
|
|
551
|
+
if (!validation.valid) {
|
|
552
|
+
throw new Error(validation.error || "Invalid identifier");
|
|
553
|
+
}
|
|
554
|
+
const payload = buildDepositData(processorName, sarCredentialCapture.offchainId);
|
|
555
|
+
if (payload.offchainId !== validation.normalized) {
|
|
556
|
+
throw new Error("Seller credential offchainId does not match registration identifier.");
|
|
557
|
+
}
|
|
558
|
+
const hashedOnchainId = processorName === "wise" ? bundle.payeeIdHash : await postMakerCreate(processorName, payload);
|
|
559
|
+
if (hashedOnchainId.toLowerCase() !== bundle.payeeIdHash.toLowerCase()) {
|
|
560
|
+
throw new Error("Seller credential payee hash does not match registered payee details.");
|
|
561
|
+
}
|
|
562
|
+
const sellerCredentialResponse = await uploadSellerCredentialBundle(
|
|
563
|
+
processorName,
|
|
564
|
+
hashedOnchainId,
|
|
565
|
+
bundle
|
|
566
|
+
);
|
|
567
|
+
return {
|
|
568
|
+
processorName,
|
|
569
|
+
offchainId: payload.offchainId,
|
|
570
|
+
hashedOnchainId,
|
|
571
|
+
sellerCredentialResponse,
|
|
572
|
+
sellerCredentialStatus: sellerCredentialResponse.responseObject
|
|
573
|
+
};
|
|
574
|
+
}
|
|
341
575
|
var EXTENSION_REGISTRATION_ERROR_PATTERNS = ["creating the maker", "create the maker"];
|
|
342
576
|
function isPeerExtensionRegistrationError(platform, message, statusCode) {
|
|
343
577
|
const info = getPeerExtensionRegistrationInfo(platform);
|
|
@@ -349,401 +583,26 @@ function isPeerExtensionRegistrationError(platform, message, statusCode) {
|
|
|
349
583
|
return EXTENSION_REGISTRATION_ERROR_PATTERNS.some((p) => lower.includes(p));
|
|
350
584
|
}
|
|
351
585
|
|
|
352
|
-
// src/errors.ts
|
|
353
|
-
var MakersCreateError = class extends Error {
|
|
354
|
-
status;
|
|
355
|
-
body;
|
|
356
|
-
constructor(message, status, body) {
|
|
357
|
-
super(message);
|
|
358
|
-
this.name = "MakersCreateError";
|
|
359
|
-
this.status = status;
|
|
360
|
-
this.body = body;
|
|
361
|
-
}
|
|
362
|
-
};
|
|
363
|
-
var OfframpError = class extends Error {
|
|
364
|
-
code;
|
|
365
|
-
step;
|
|
366
|
-
cause;
|
|
367
|
-
txHash;
|
|
368
|
-
depositId;
|
|
369
|
-
constructor(message, code, step, cause, details) {
|
|
370
|
-
super(message);
|
|
371
|
-
this.name = "OfframpError";
|
|
372
|
-
this.code = code;
|
|
373
|
-
this.step = step;
|
|
374
|
-
this.cause = cause;
|
|
375
|
-
this.txHash = details?.txHash;
|
|
376
|
-
this.depositId = details?.depositId;
|
|
377
|
-
}
|
|
378
|
-
};
|
|
379
|
-
function isUserCancellation(error) {
|
|
380
|
-
if (!(error instanceof Error)) return false;
|
|
381
|
-
const msg = error.message.toLowerCase();
|
|
382
|
-
return msg.includes("user rejected") || msg.includes("user denied") || msg.includes("user cancelled") || msg.includes("rejected the request") || msg.includes("action_rejected");
|
|
383
|
-
}
|
|
384
|
-
|
|
385
586
|
// src/otc.ts
|
|
386
587
|
import { createPublicClient, http, isAddress, zeroAddress } from "viem";
|
|
387
588
|
import { base } from "viem/chains";
|
|
388
|
-
|
|
389
|
-
// ../../node_modules/@zkp2p/contracts-v2/abis/base/WhitelistPreIntentHook.json
|
|
390
|
-
var WhitelistPreIntentHook_default = [
|
|
391
|
-
{
|
|
392
|
-
inputs: [
|
|
393
|
-
{
|
|
394
|
-
internalType: "address",
|
|
395
|
-
name: "_orchestratorRegistry",
|
|
396
|
-
type: "address"
|
|
397
|
-
}
|
|
398
|
-
],
|
|
399
|
-
stateMutability: "nonpayable",
|
|
400
|
-
type: "constructor"
|
|
401
|
-
},
|
|
402
|
-
{
|
|
403
|
-
inputs: [],
|
|
404
|
-
name: "EmptyArray",
|
|
405
|
-
type: "error"
|
|
406
|
-
},
|
|
407
|
-
{
|
|
408
|
-
inputs: [
|
|
409
|
-
{
|
|
410
|
-
internalType: "address",
|
|
411
|
-
name: "taker",
|
|
412
|
-
type: "address"
|
|
413
|
-
},
|
|
414
|
-
{
|
|
415
|
-
internalType: "address",
|
|
416
|
-
name: "escrow",
|
|
417
|
-
type: "address"
|
|
418
|
-
},
|
|
419
|
-
{
|
|
420
|
-
internalType: "uint256",
|
|
421
|
-
name: "depositId",
|
|
422
|
-
type: "uint256"
|
|
423
|
-
}
|
|
424
|
-
],
|
|
425
|
-
name: "TakerNotInWhitelist",
|
|
426
|
-
type: "error"
|
|
427
|
-
},
|
|
428
|
-
{
|
|
429
|
-
inputs: [
|
|
430
|
-
{
|
|
431
|
-
internalType: "address",
|
|
432
|
-
name: "taker",
|
|
433
|
-
type: "address"
|
|
434
|
-
},
|
|
435
|
-
{
|
|
436
|
-
internalType: "address",
|
|
437
|
-
name: "escrow",
|
|
438
|
-
type: "address"
|
|
439
|
-
},
|
|
440
|
-
{
|
|
441
|
-
internalType: "uint256",
|
|
442
|
-
name: "depositId",
|
|
443
|
-
type: "uint256"
|
|
444
|
-
}
|
|
445
|
-
],
|
|
446
|
-
name: "TakerNotWhitelisted",
|
|
447
|
-
type: "error"
|
|
448
|
-
},
|
|
449
|
-
{
|
|
450
|
-
inputs: [
|
|
451
|
-
{
|
|
452
|
-
internalType: "address",
|
|
453
|
-
name: "caller",
|
|
454
|
-
type: "address"
|
|
455
|
-
},
|
|
456
|
-
{
|
|
457
|
-
internalType: "address",
|
|
458
|
-
name: "owner",
|
|
459
|
-
type: "address"
|
|
460
|
-
},
|
|
461
|
-
{
|
|
462
|
-
internalType: "address",
|
|
463
|
-
name: "delegate",
|
|
464
|
-
type: "address"
|
|
465
|
-
}
|
|
466
|
-
],
|
|
467
|
-
name: "UnauthorizedCallerOrDelegate",
|
|
468
|
-
type: "error"
|
|
469
|
-
},
|
|
470
|
-
{
|
|
471
|
-
inputs: [
|
|
472
|
-
{
|
|
473
|
-
internalType: "address",
|
|
474
|
-
name: "caller",
|
|
475
|
-
type: "address"
|
|
476
|
-
}
|
|
477
|
-
],
|
|
478
|
-
name: "UnauthorizedOrchestratorCaller",
|
|
479
|
-
type: "error"
|
|
480
|
-
},
|
|
481
|
-
{
|
|
482
|
-
inputs: [],
|
|
483
|
-
name: "ZeroAddress",
|
|
484
|
-
type: "error"
|
|
485
|
-
},
|
|
486
|
-
{
|
|
487
|
-
anonymous: false,
|
|
488
|
-
inputs: [
|
|
489
|
-
{
|
|
490
|
-
indexed: true,
|
|
491
|
-
internalType: "address",
|
|
492
|
-
name: "escrow",
|
|
493
|
-
type: "address"
|
|
494
|
-
},
|
|
495
|
-
{
|
|
496
|
-
indexed: true,
|
|
497
|
-
internalType: "uint256",
|
|
498
|
-
name: "depositId",
|
|
499
|
-
type: "uint256"
|
|
500
|
-
},
|
|
501
|
-
{
|
|
502
|
-
indexed: true,
|
|
503
|
-
internalType: "address",
|
|
504
|
-
name: "taker",
|
|
505
|
-
type: "address"
|
|
506
|
-
}
|
|
507
|
-
],
|
|
508
|
-
name: "TakerRemovedFromWhitelist",
|
|
509
|
-
type: "event"
|
|
510
|
-
},
|
|
511
|
-
{
|
|
512
|
-
anonymous: false,
|
|
513
|
-
inputs: [
|
|
514
|
-
{
|
|
515
|
-
indexed: true,
|
|
516
|
-
internalType: "address",
|
|
517
|
-
name: "escrow",
|
|
518
|
-
type: "address"
|
|
519
|
-
},
|
|
520
|
-
{
|
|
521
|
-
indexed: true,
|
|
522
|
-
internalType: "uint256",
|
|
523
|
-
name: "depositId",
|
|
524
|
-
type: "uint256"
|
|
525
|
-
},
|
|
526
|
-
{
|
|
527
|
-
indexed: true,
|
|
528
|
-
internalType: "address",
|
|
529
|
-
name: "taker",
|
|
530
|
-
type: "address"
|
|
531
|
-
}
|
|
532
|
-
],
|
|
533
|
-
name: "TakerWhitelisted",
|
|
534
|
-
type: "event"
|
|
535
|
-
},
|
|
536
|
-
{
|
|
537
|
-
inputs: [
|
|
538
|
-
{
|
|
539
|
-
internalType: "address",
|
|
540
|
-
name: "_escrow",
|
|
541
|
-
type: "address"
|
|
542
|
-
},
|
|
543
|
-
{
|
|
544
|
-
internalType: "uint256",
|
|
545
|
-
name: "_depositId",
|
|
546
|
-
type: "uint256"
|
|
547
|
-
},
|
|
548
|
-
{
|
|
549
|
-
internalType: "address[]",
|
|
550
|
-
name: "_takers",
|
|
551
|
-
type: "address[]"
|
|
552
|
-
}
|
|
553
|
-
],
|
|
554
|
-
name: "addToWhitelist",
|
|
555
|
-
outputs: [],
|
|
556
|
-
stateMutability: "nonpayable",
|
|
557
|
-
type: "function"
|
|
558
|
-
},
|
|
559
|
-
{
|
|
560
|
-
inputs: [
|
|
561
|
-
{
|
|
562
|
-
internalType: "address",
|
|
563
|
-
name: "_escrow",
|
|
564
|
-
type: "address"
|
|
565
|
-
},
|
|
566
|
-
{
|
|
567
|
-
internalType: "uint256",
|
|
568
|
-
name: "_depositId",
|
|
569
|
-
type: "uint256"
|
|
570
|
-
},
|
|
571
|
-
{
|
|
572
|
-
internalType: "address",
|
|
573
|
-
name: "_taker",
|
|
574
|
-
type: "address"
|
|
575
|
-
}
|
|
576
|
-
],
|
|
577
|
-
name: "isWhitelisted",
|
|
578
|
-
outputs: [
|
|
579
|
-
{
|
|
580
|
-
internalType: "bool",
|
|
581
|
-
name: "",
|
|
582
|
-
type: "bool"
|
|
583
|
-
}
|
|
584
|
-
],
|
|
585
|
-
stateMutability: "view",
|
|
586
|
-
type: "function"
|
|
587
|
-
},
|
|
588
|
-
{
|
|
589
|
-
inputs: [],
|
|
590
|
-
name: "orchestratorRegistry",
|
|
591
|
-
outputs: [
|
|
592
|
-
{
|
|
593
|
-
internalType: "contract IOrchestratorRegistry",
|
|
594
|
-
name: "",
|
|
595
|
-
type: "address"
|
|
596
|
-
}
|
|
597
|
-
],
|
|
598
|
-
stateMutability: "view",
|
|
599
|
-
type: "function"
|
|
600
|
-
},
|
|
601
|
-
{
|
|
602
|
-
inputs: [
|
|
603
|
-
{
|
|
604
|
-
internalType: "address",
|
|
605
|
-
name: "_escrow",
|
|
606
|
-
type: "address"
|
|
607
|
-
},
|
|
608
|
-
{
|
|
609
|
-
internalType: "uint256",
|
|
610
|
-
name: "_depositId",
|
|
611
|
-
type: "uint256"
|
|
612
|
-
},
|
|
613
|
-
{
|
|
614
|
-
internalType: "address[]",
|
|
615
|
-
name: "_takers",
|
|
616
|
-
type: "address[]"
|
|
617
|
-
}
|
|
618
|
-
],
|
|
619
|
-
name: "removeFromWhitelist",
|
|
620
|
-
outputs: [],
|
|
621
|
-
stateMutability: "nonpayable",
|
|
622
|
-
type: "function"
|
|
623
|
-
},
|
|
624
|
-
{
|
|
625
|
-
inputs: [
|
|
626
|
-
{
|
|
627
|
-
components: [
|
|
628
|
-
{
|
|
629
|
-
internalType: "address",
|
|
630
|
-
name: "taker",
|
|
631
|
-
type: "address"
|
|
632
|
-
},
|
|
633
|
-
{
|
|
634
|
-
internalType: "address",
|
|
635
|
-
name: "escrow",
|
|
636
|
-
type: "address"
|
|
637
|
-
},
|
|
638
|
-
{
|
|
639
|
-
internalType: "uint256",
|
|
640
|
-
name: "depositId",
|
|
641
|
-
type: "uint256"
|
|
642
|
-
},
|
|
643
|
-
{
|
|
644
|
-
internalType: "uint256",
|
|
645
|
-
name: "amount",
|
|
646
|
-
type: "uint256"
|
|
647
|
-
},
|
|
648
|
-
{
|
|
649
|
-
internalType: "address",
|
|
650
|
-
name: "to",
|
|
651
|
-
type: "address"
|
|
652
|
-
},
|
|
653
|
-
{
|
|
654
|
-
internalType: "bytes32",
|
|
655
|
-
name: "paymentMethod",
|
|
656
|
-
type: "bytes32"
|
|
657
|
-
},
|
|
658
|
-
{
|
|
659
|
-
internalType: "bytes32",
|
|
660
|
-
name: "fiatCurrency",
|
|
661
|
-
type: "bytes32"
|
|
662
|
-
},
|
|
663
|
-
{
|
|
664
|
-
internalType: "uint256",
|
|
665
|
-
name: "conversionRate",
|
|
666
|
-
type: "uint256"
|
|
667
|
-
},
|
|
668
|
-
{
|
|
669
|
-
components: [
|
|
670
|
-
{
|
|
671
|
-
internalType: "address",
|
|
672
|
-
name: "recipient",
|
|
673
|
-
type: "address"
|
|
674
|
-
},
|
|
675
|
-
{
|
|
676
|
-
internalType: "uint256",
|
|
677
|
-
name: "fee",
|
|
678
|
-
type: "uint256"
|
|
679
|
-
}
|
|
680
|
-
],
|
|
681
|
-
internalType: "struct IReferralFee.ReferralFee[]",
|
|
682
|
-
name: "referralFees",
|
|
683
|
-
type: "tuple[]"
|
|
684
|
-
},
|
|
685
|
-
{
|
|
686
|
-
internalType: "bytes",
|
|
687
|
-
name: "preIntentHookData",
|
|
688
|
-
type: "bytes"
|
|
689
|
-
}
|
|
690
|
-
],
|
|
691
|
-
internalType: "struct IPreIntentHook.PreIntentContext",
|
|
692
|
-
name: "_ctx",
|
|
693
|
-
type: "tuple"
|
|
694
|
-
}
|
|
695
|
-
],
|
|
696
|
-
name: "validateSignalIntent",
|
|
697
|
-
outputs: [],
|
|
698
|
-
stateMutability: "view",
|
|
699
|
-
type: "function"
|
|
700
|
-
},
|
|
701
|
-
{
|
|
702
|
-
inputs: [
|
|
703
|
-
{
|
|
704
|
-
internalType: "address",
|
|
705
|
-
name: "",
|
|
706
|
-
type: "address"
|
|
707
|
-
},
|
|
708
|
-
{
|
|
709
|
-
internalType: "uint256",
|
|
710
|
-
name: "",
|
|
711
|
-
type: "uint256"
|
|
712
|
-
},
|
|
713
|
-
{
|
|
714
|
-
internalType: "address",
|
|
715
|
-
name: "",
|
|
716
|
-
type: "address"
|
|
717
|
-
}
|
|
718
|
-
],
|
|
719
|
-
name: "whitelist",
|
|
720
|
-
outputs: [
|
|
721
|
-
{
|
|
722
|
-
internalType: "bool",
|
|
723
|
-
name: "",
|
|
724
|
-
type: "bool"
|
|
725
|
-
}
|
|
726
|
-
],
|
|
727
|
-
stateMutability: "view",
|
|
728
|
-
type: "function"
|
|
729
|
-
}
|
|
730
|
-
];
|
|
589
|
+
import WhitelistPreIntentHookABI from "@zkp2p/contracts-v2/abis/base/WhitelistPreIntentHook.json";
|
|
731
590
|
|
|
732
591
|
// src/sdk-client.ts
|
|
733
592
|
import { OfframpClient } from "@zkp2p/sdk";
|
|
734
|
-
function createSdkClient(walletClient) {
|
|
593
|
+
function createSdkClient(walletClient, apiBaseUrl = API_BASE_URL) {
|
|
735
594
|
return new OfframpClient({
|
|
736
595
|
walletClient,
|
|
737
596
|
chainId: BASE_CHAIN_ID,
|
|
738
597
|
runtimeEnv: RUNTIME_ENV,
|
|
739
598
|
rpcUrl: BASE_RPC_URL,
|
|
740
|
-
baseApiUrl:
|
|
599
|
+
baseApiUrl: apiBaseUrl
|
|
741
600
|
});
|
|
742
601
|
}
|
|
743
602
|
|
|
744
603
|
// src/otc.ts
|
|
745
604
|
var WHITELIST_HOOK_ADDRESS = "0xda023Ea0d789A41BcF5866F7B6BBd2CaDF9b79B8";
|
|
746
|
-
var OTC_BASE_URL = "https://usdctofiat.xyz";
|
|
605
|
+
var OTC_BASE_URL = "https://otc.usdctofiat.xyz";
|
|
747
606
|
async function enableOtc(walletClient, depositId, takerAddress, escrowAddress) {
|
|
748
607
|
if (!isAddress(takerAddress)) {
|
|
749
608
|
throw new OfframpError("Invalid taker address", "VALIDATION");
|
|
@@ -815,7 +674,7 @@ async function disableOtc(walletClient, depositId, escrowAddress) {
|
|
|
815
674
|
}
|
|
816
675
|
function getOtcLink(depositId, escrowAddress) {
|
|
817
676
|
const escrow = escrowAddress || ESCROW_ADDRESS;
|
|
818
|
-
return `${OTC_BASE_URL}/
|
|
677
|
+
return `${OTC_BASE_URL}/d/${escrow}/${depositId}`;
|
|
819
678
|
}
|
|
820
679
|
async function writeContract(walletClient, functionName, args) {
|
|
821
680
|
const wc = walletClient;
|
|
@@ -824,7 +683,7 @@ async function writeContract(walletClient, functionName, args) {
|
|
|
824
683
|
}
|
|
825
684
|
await wc.writeContract({
|
|
826
685
|
address: WHITELIST_HOOK_ADDRESS,
|
|
827
|
-
abi:
|
|
686
|
+
abi: WhitelistPreIntentHookABI,
|
|
828
687
|
functionName,
|
|
829
688
|
args
|
|
830
689
|
});
|
|
@@ -833,7 +692,7 @@ async function readIsWhitelisted(escrow, depositId, taker) {
|
|
|
833
692
|
const publicClient = createPublicClient({ chain: base, transport: http(BASE_RPC_URL) });
|
|
834
693
|
return publicClient.readContract({
|
|
835
694
|
address: WHITELIST_HOOK_ADDRESS,
|
|
836
|
-
abi:
|
|
695
|
+
abi: WhitelistPreIntentHookABI,
|
|
837
696
|
functionName: "isWhitelisted",
|
|
838
697
|
args: [escrow, depositId, taker]
|
|
839
698
|
});
|
|
@@ -1161,41 +1020,24 @@ function extractDepositIdFromLogs(logs) {
|
|
|
1161
1020
|
}
|
|
1162
1021
|
return null;
|
|
1163
1022
|
}
|
|
1164
|
-
async function
|
|
1023
|
+
async function validatePayeeDetails(processorName, offchainId, apiBaseUrl = API_BASE_URL) {
|
|
1165
1024
|
const controller = new AbortController();
|
|
1166
1025
|
const timeout = setTimeout(() => controller.abort(), PAYEE_REGISTRATION_TIMEOUT_MS);
|
|
1167
1026
|
try {
|
|
1168
|
-
const res = await fetch(`${
|
|
1027
|
+
const res = await fetch(`${apiBaseUrl}/v2/makers/validate`, {
|
|
1169
1028
|
method: "POST",
|
|
1170
1029
|
headers: { "Content-Type": "application/json" },
|
|
1171
|
-
body: JSON.stringify({ processorName,
|
|
1030
|
+
body: JSON.stringify({ processorName, offchainId }),
|
|
1172
1031
|
signal: controller.signal
|
|
1173
1032
|
});
|
|
1174
|
-
if (!res.ok)
|
|
1175
|
-
const txt = await res.text().catch(() => "");
|
|
1176
|
-
let detail = txt || res.statusText;
|
|
1177
|
-
try {
|
|
1178
|
-
const parsed = JSON.parse(txt);
|
|
1179
|
-
if (typeof parsed.message === "string" && parsed.message.trim()) {
|
|
1180
|
-
detail = parsed.message;
|
|
1181
|
-
}
|
|
1182
|
-
} catch {
|
|
1183
|
-
}
|
|
1184
|
-
throw new MakersCreateError(
|
|
1185
|
-
`makers/create failed (${res.status}): ${detail}`,
|
|
1186
|
-
res.status,
|
|
1187
|
-
txt
|
|
1188
|
-
);
|
|
1189
|
-
}
|
|
1033
|
+
if (!res.ok) return "unknown";
|
|
1190
1034
|
const json = await res.json();
|
|
1191
|
-
if (
|
|
1192
|
-
|
|
1193
|
-
json.message || "makers/create returned no hashedOnchainId",
|
|
1194
|
-
json.statusCode ?? null,
|
|
1195
|
-
""
|
|
1196
|
-
);
|
|
1035
|
+
if (typeof json.responseObject === "boolean") {
|
|
1036
|
+
return json.responseObject ? "valid" : "invalid";
|
|
1197
1037
|
}
|
|
1198
|
-
return
|
|
1038
|
+
return "unknown";
|
|
1039
|
+
} catch {
|
|
1040
|
+
return "unknown";
|
|
1199
1041
|
} finally {
|
|
1200
1042
|
clearTimeout(timeout);
|
|
1201
1043
|
}
|
|
@@ -1260,10 +1102,11 @@ async function findUndelegatedDeposit(walletAddress) {
|
|
|
1260
1102
|
return null;
|
|
1261
1103
|
}
|
|
1262
1104
|
}
|
|
1263
|
-
async function offramp(walletClient, params, onProgress, telemetryContext) {
|
|
1105
|
+
async function offramp(walletClient, params, onProgress, telemetryContext, apiBaseUrl) {
|
|
1264
1106
|
const { amount, platform, currency, identifier } = params;
|
|
1265
1107
|
const platformId = platform.id;
|
|
1266
1108
|
const currencyCode = currency.code;
|
|
1109
|
+
const resolvedApiBaseUrl = resolveApiBaseUrl(apiBaseUrl);
|
|
1267
1110
|
const telemetry = telemetryContext ?? createTelemetryContext({
|
|
1268
1111
|
sdkVersion: SDK_VERSION,
|
|
1269
1112
|
telemetry: true,
|
|
@@ -1308,7 +1151,7 @@ async function offramp(walletClient, params, onProgress, telemetryContext) {
|
|
|
1308
1151
|
const existing = await findUndelegatedDeposit(walletAddress);
|
|
1309
1152
|
if (existing) {
|
|
1310
1153
|
emitProgress({ step: "resuming", depositId: existing.depositId });
|
|
1311
|
-
const client2 = createSdkClient(walletClient);
|
|
1154
|
+
const client2 = createSdkClient(walletClient, resolvedApiBaseUrl);
|
|
1312
1155
|
const txOverrides2 = { referrer: [REFERRER] };
|
|
1313
1156
|
try {
|
|
1314
1157
|
const result2 = await client2.setRateManager({
|
|
@@ -1344,7 +1187,7 @@ async function offramp(walletClient, params, onProgress, telemetryContext) {
|
|
|
1344
1187
|
const truncatedAmount = amt.toFixed(6).replace(/\.?0+$/, "");
|
|
1345
1188
|
const amountUnits = usdcToUnits(truncatedAmount);
|
|
1346
1189
|
const minUnits = usdcToUnits(String(MIN_ORDER_USDC));
|
|
1347
|
-
const maxUnits = usdcToUnits(String(Math.min(amt,
|
|
1190
|
+
const maxUnits = usdcToUnits(String(Math.min(amt, MAX_ORDER_USDC)));
|
|
1348
1191
|
try {
|
|
1349
1192
|
const publicClient = createPublicClient3({ chain: base3, transport: http3(BASE_RPC_URL) });
|
|
1350
1193
|
const balance = await publicClient.readContract({
|
|
@@ -1371,7 +1214,22 @@ async function offramp(walletClient, params, onProgress, telemetryContext) {
|
|
|
1371
1214
|
} catch (err) {
|
|
1372
1215
|
if (err instanceof OfframpError) throw err;
|
|
1373
1216
|
}
|
|
1374
|
-
const
|
|
1217
|
+
const canonicalName = platformId.startsWith("zelle") ? "zelle" : platformId;
|
|
1218
|
+
if (!getPeerExtensionRegistrationInfo(platformId)) {
|
|
1219
|
+
const outcome = await validatePayeeDetails(
|
|
1220
|
+
canonicalName,
|
|
1221
|
+
normalizedIdentifier,
|
|
1222
|
+
resolvedApiBaseUrl
|
|
1223
|
+
);
|
|
1224
|
+
if (outcome === "invalid") {
|
|
1225
|
+
throw new OfframpError(
|
|
1226
|
+
`Couldn't verify that ${platform.name} ${platform.identifier.label.toLowerCase()}. Double-check it and try again.`,
|
|
1227
|
+
"VALIDATION",
|
|
1228
|
+
"registering"
|
|
1229
|
+
);
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
const client = createSdkClient(walletClient, resolvedApiBaseUrl);
|
|
1375
1233
|
const txOverrides = { referrer: [REFERRER] };
|
|
1376
1234
|
emitProgress({ step: "approving" });
|
|
1377
1235
|
try {
|
|
@@ -1395,16 +1253,15 @@ async function offramp(walletClient, params, onProgress, telemetryContext) {
|
|
|
1395
1253
|
}
|
|
1396
1254
|
emitProgress({ step: "registering" });
|
|
1397
1255
|
let hashedOnchainId;
|
|
1398
|
-
const canonicalName = platformId.startsWith("zelle") ? "zelle" : platformId;
|
|
1399
1256
|
try {
|
|
1400
1257
|
const payeePayload = buildDepositData(canonicalName, normalizedIdentifier);
|
|
1401
|
-
hashedOnchainId = await
|
|
1258
|
+
hashedOnchainId = await postMakerCreate(canonicalName, payeePayload, resolvedApiBaseUrl);
|
|
1402
1259
|
} catch (err) {
|
|
1403
1260
|
const status = err instanceof MakersCreateError ? err.status : null;
|
|
1404
1261
|
const message = err instanceof Error ? err.message : String(err);
|
|
1405
1262
|
if (isPeerExtensionRegistrationError(canonicalName, message, status)) {
|
|
1406
1263
|
throw new OfframpError(
|
|
1407
|
-
`${platform.name} maker is not yet registered in the Peer extension.
|
|
1264
|
+
`${platform.name} maker is not yet registered in the Peer extension. Register this handle with Peer, then retry.`,
|
|
1408
1265
|
"EXTENSION_REGISTRATION_REQUIRED",
|
|
1409
1266
|
"registering",
|
|
1410
1267
|
err
|
|
@@ -1596,6 +1453,14 @@ var CURRENCIES = buildCurrencies();
|
|
|
1596
1453
|
// src/offramp.ts
|
|
1597
1454
|
var IDEMPOTENCY_TTL_MS = 10 * 60 * 1e3;
|
|
1598
1455
|
var IDEMPOTENCY_STORAGE_PREFIX = "offramp:idempotency:";
|
|
1456
|
+
var warnedIdempotencyUnavailable = false;
|
|
1457
|
+
function warnIdempotencyUnavailableOnce() {
|
|
1458
|
+
if (warnedIdempotencyUnavailable) return;
|
|
1459
|
+
warnedIdempotencyUnavailable = true;
|
|
1460
|
+
console.warn(
|
|
1461
|
+
"[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."
|
|
1462
|
+
);
|
|
1463
|
+
}
|
|
1599
1464
|
function getWalletAddress(walletClient) {
|
|
1600
1465
|
const address = walletClient.account?.address;
|
|
1601
1466
|
if (!address) {
|
|
@@ -1666,8 +1531,10 @@ function buildCurrencyGroups() {
|
|
|
1666
1531
|
var Offramp = class {
|
|
1667
1532
|
walletClient;
|
|
1668
1533
|
telemetry;
|
|
1534
|
+
apiBaseUrl;
|
|
1669
1535
|
constructor(options) {
|
|
1670
1536
|
this.walletClient = options.walletClient;
|
|
1537
|
+
this.apiBaseUrl = options.apiBaseUrl;
|
|
1671
1538
|
this.telemetry = createTelemetryContext({
|
|
1672
1539
|
sdkVersion: SDK_VERSION,
|
|
1673
1540
|
telemetry: options.telemetry,
|
|
@@ -1690,6 +1557,9 @@ var Offramp = class {
|
|
|
1690
1557
|
referralId: flowTelemetry.referralId
|
|
1691
1558
|
};
|
|
1692
1559
|
const sanitizedKey = sanitizeAttributionId(params.idempotencyKey);
|
|
1560
|
+
if (sanitizedKey && typeof sessionStorage === "undefined") {
|
|
1561
|
+
warnIdempotencyUnavailableOnce();
|
|
1562
|
+
}
|
|
1693
1563
|
const walletAddress = sanitizedKey ? getWalletAddress(this.walletClient) : null;
|
|
1694
1564
|
const storageKey = walletAddress && sanitizedKey ? getIdempotencyStorageKey(walletAddress, sanitizedKey) : null;
|
|
1695
1565
|
if (storageKey) {
|
|
@@ -1700,7 +1570,8 @@ var Offramp = class {
|
|
|
1700
1570
|
this.walletClient,
|
|
1701
1571
|
sanitizedParams,
|
|
1702
1572
|
onProgress,
|
|
1703
|
-
flowTelemetry
|
|
1573
|
+
flowTelemetry,
|
|
1574
|
+
this.apiBaseUrl
|
|
1704
1575
|
);
|
|
1705
1576
|
if (storageKey) {
|
|
1706
1577
|
writeIdempotencyResult(storageKey, result);
|
|
@@ -1749,21 +1620,94 @@ function createOfframp(options) {
|
|
|
1749
1620
|
// src/extension.ts
|
|
1750
1621
|
import {
|
|
1751
1622
|
PEER_EXTENSION_CHROME_URL,
|
|
1752
|
-
|
|
1753
|
-
createPeerExtensionSdk,
|
|
1754
|
-
isPeerExtensionAvailable,
|
|
1755
|
-
openPeerExtensionInstallPage,
|
|
1756
|
-
getPeerExtensionState
|
|
1623
|
+
createPeerExtensionSdk as createLegacyPeerExtensionSdk
|
|
1757
1624
|
} from "@zkp2p/sdk";
|
|
1625
|
+
var resolveWindow = (options) => {
|
|
1626
|
+
if (options?.window) {
|
|
1627
|
+
return options.window;
|
|
1628
|
+
}
|
|
1629
|
+
if (typeof window === "undefined") {
|
|
1630
|
+
return void 0;
|
|
1631
|
+
}
|
|
1632
|
+
return window;
|
|
1633
|
+
};
|
|
1634
|
+
var requirePeer = (options) => {
|
|
1635
|
+
const resolvedWindow = resolveWindow(options);
|
|
1636
|
+
if (!resolvedWindow) {
|
|
1637
|
+
throw new Error("Peer extension SDK requires a browser window.");
|
|
1638
|
+
}
|
|
1639
|
+
if (!resolvedWindow.peer) {
|
|
1640
|
+
throw new Error("Peer extension not available. Install or enable the Peer extension.");
|
|
1641
|
+
}
|
|
1642
|
+
return resolvedWindow.peer;
|
|
1643
|
+
};
|
|
1644
|
+
var isPeerExtensionAvailable = (options) => {
|
|
1645
|
+
const resolvedWindow = resolveWindow(options);
|
|
1646
|
+
return Boolean(resolvedWindow?.peer);
|
|
1647
|
+
};
|
|
1648
|
+
var hasHeadlessMetadataBridge = (peer) => typeof peer.authenticate === "function" && typeof peer.onMetadataMessage === "function";
|
|
1649
|
+
var requirePeerMetadataBridge = (options) => {
|
|
1650
|
+
const peer = requirePeer(options);
|
|
1651
|
+
if (!hasHeadlessMetadataBridge(peer)) {
|
|
1652
|
+
throw new Error("Peer extension metadata bridge unavailable. Install or update Peer.");
|
|
1653
|
+
}
|
|
1654
|
+
return peer;
|
|
1655
|
+
};
|
|
1656
|
+
var isPeerExtensionMetadataBridgeAvailable = (options) => {
|
|
1657
|
+
const resolvedWindow = resolveWindow(options);
|
|
1658
|
+
return Boolean(resolvedWindow?.peer && hasHeadlessMetadataBridge(resolvedWindow.peer));
|
|
1659
|
+
};
|
|
1660
|
+
var openPeerExtensionInstallPage = (options) => {
|
|
1661
|
+
const resolvedWindow = resolveWindow(options);
|
|
1662
|
+
if (!resolvedWindow) {
|
|
1663
|
+
throw new Error("Peer extension SDK requires a browser window.");
|
|
1664
|
+
}
|
|
1665
|
+
resolvedWindow.open(PEER_EXTENSION_CHROME_URL, "_blank", "noopener,noreferrer");
|
|
1666
|
+
};
|
|
1667
|
+
var getPeerExtensionState = async (options) => {
|
|
1668
|
+
if (!isPeerExtensionAvailable(options)) {
|
|
1669
|
+
return "needs_install";
|
|
1670
|
+
}
|
|
1671
|
+
try {
|
|
1672
|
+
const status = await requirePeer(options).checkConnectionStatus();
|
|
1673
|
+
return status === "connected" ? "ready" : "needs_connection";
|
|
1674
|
+
} catch {
|
|
1675
|
+
return "needs_connection";
|
|
1676
|
+
}
|
|
1677
|
+
};
|
|
1678
|
+
var createPeerExtensionSdk = (options = {}) => {
|
|
1679
|
+
const legacySdk = createLegacyPeerExtensionSdk(
|
|
1680
|
+
options
|
|
1681
|
+
);
|
|
1682
|
+
return {
|
|
1683
|
+
isAvailable: () => isPeerExtensionAvailable(options),
|
|
1684
|
+
requestConnection: () => requirePeer(options).requestConnection(),
|
|
1685
|
+
checkConnectionStatus: () => requirePeer(options).checkConnectionStatus(),
|
|
1686
|
+
getVersion: () => requirePeer(options).getVersion(),
|
|
1687
|
+
authenticate: (params) => requirePeerMetadataBridge(options).authenticate(params),
|
|
1688
|
+
onMetadataMessage: (callback) => requirePeerMetadataBridge(options).onMetadataMessage(callback),
|
|
1689
|
+
openSidebar: (route) => legacySdk.openSidebar(route),
|
|
1690
|
+
onramp: (params, callback) => legacySdk.onramp(params, callback),
|
|
1691
|
+
getOnrampTransaction: (intentHash) => legacySdk.getOnrampTransaction(intentHash),
|
|
1692
|
+
openInstallPage: () => openPeerExtensionInstallPage(options),
|
|
1693
|
+
getState: () => getPeerExtensionState(options)
|
|
1694
|
+
};
|
|
1695
|
+
};
|
|
1696
|
+
var peerExtensionSdk = createPeerExtensionSdk();
|
|
1758
1697
|
|
|
1759
1698
|
export {
|
|
1760
1699
|
ESCROW_ADDRESS,
|
|
1700
|
+
MakersCreateError,
|
|
1701
|
+
OfframpError,
|
|
1761
1702
|
normalizePaypalMeUsername,
|
|
1703
|
+
isValidIBAN,
|
|
1762
1704
|
PLATFORMS,
|
|
1705
|
+
PLATFORM_LIMITS,
|
|
1706
|
+
getPlatformLimits,
|
|
1763
1707
|
getPeerExtensionRegistrationInfo,
|
|
1708
|
+
getPeerExtensionRegistrationAuthParams,
|
|
1709
|
+
completePeerExtensionRegistration,
|
|
1764
1710
|
isPeerExtensionRegistrationError,
|
|
1765
|
-
MakersCreateError,
|
|
1766
|
-
OfframpError,
|
|
1767
1711
|
enableOtc,
|
|
1768
1712
|
disableOtc,
|
|
1769
1713
|
getOtcLink,
|
|
@@ -1780,10 +1724,11 @@ export {
|
|
|
1780
1724
|
Offramp,
|
|
1781
1725
|
createOfframp,
|
|
1782
1726
|
PEER_EXTENSION_CHROME_URL,
|
|
1783
|
-
peerExtensionSdk,
|
|
1784
|
-
createPeerExtensionSdk,
|
|
1785
1727
|
isPeerExtensionAvailable,
|
|
1728
|
+
isPeerExtensionMetadataBridgeAvailable,
|
|
1786
1729
|
openPeerExtensionInstallPage,
|
|
1787
|
-
getPeerExtensionState
|
|
1730
|
+
getPeerExtensionState,
|
|
1731
|
+
createPeerExtensionSdk,
|
|
1732
|
+
peerExtensionSdk
|
|
1788
1733
|
};
|
|
1789
|
-
//# sourceMappingURL=chunk-
|
|
1734
|
+
//# sourceMappingURL=chunk-XQ7HOLLB.js.map
|