@usdctofiat/offramp 1.1.4 → 1.3.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/dist/{chunk-OJY6DE3I.js → chunk-JQBKGGI2.js} +555 -213
- package/dist/chunk-JQBKGGI2.js.map +1 -0
- package/dist/{errors-Dtzrl98J.d.cts → errors-CfZrDly0.d.cts} +42 -2
- package/dist/{errors-Dtzrl98J.d.ts → errors-CfZrDly0.d.ts} +42 -2
- package/dist/index.cjs +556 -213
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +37 -4
- package/dist/index.d.ts +37 -4
- package/dist/index.js +26 -18
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +591 -240
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +5 -2
- package/dist/react.d.ts +5 -2
- package/dist/react.js +33 -14
- package/dist/react.js.map +1 -1
- package/package.json +16 -6
- package/dist/chunk-OJY6DE3I.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -22,15 +22,22 @@ var index_exports = {};
|
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
CURRENCIES: () => CURRENCIES,
|
|
24
24
|
ESCROW_ADDRESS: () => ESCROW_ADDRESS,
|
|
25
|
+
OFFRAMP_ERROR_CODES: () => OFFRAMP_ERROR_CODES,
|
|
26
|
+
Offramp: () => Offramp,
|
|
25
27
|
OfframpError: () => OfframpError,
|
|
26
28
|
PLATFORMS: () => PLATFORMS,
|
|
27
29
|
close: () => close,
|
|
30
|
+
createOfframp: () => createOfframp,
|
|
31
|
+
createTelemetryContext: () => createTelemetryContext,
|
|
28
32
|
delegate: () => delegate,
|
|
29
33
|
deposits: () => deposits,
|
|
30
34
|
disableOtc: () => disableOtc,
|
|
35
|
+
emitEvent: () => emitEvent,
|
|
31
36
|
enableOtc: () => enableOtc,
|
|
32
37
|
getOtcLink: () => getOtcLink,
|
|
33
38
|
offramp: () => offramp,
|
|
39
|
+
sanitizeAttributionId: () => sanitizeAttributionId,
|
|
40
|
+
sendTelemetryEvent: () => sendTelemetryEvent,
|
|
34
41
|
undelegate: () => undelegate
|
|
35
42
|
});
|
|
36
43
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -42,6 +49,7 @@ var import_sdk5 = require("@zkp2p/sdk");
|
|
|
42
49
|
|
|
43
50
|
// src/config.ts
|
|
44
51
|
var import_sdk = require("@zkp2p/sdk");
|
|
52
|
+
var SDK_VERSION = "1.2.0";
|
|
45
53
|
var BASE_CHAIN_ID = 8453;
|
|
46
54
|
var RUNTIME_ENV = "production";
|
|
47
55
|
var API_BASE_URL = "https://api.zkp2p.xyz";
|
|
@@ -57,6 +65,7 @@ var GATING_SERVICE_ADDRESS = (0, import_sdk.getGatingServiceAddress)(
|
|
|
57
65
|
);
|
|
58
66
|
var DELEGATE_RATE_MANAGER_ID = "0x8666d6fb0f6797c56e95339fd7ca82fdd348b9db200e10a4c4aa0a0b879fc41c";
|
|
59
67
|
var RATE_MANAGER_REGISTRY_ADDRESS = "0xeed7db23e724ac4590d6db6f78fda6db203535f3";
|
|
68
|
+
var DELEGATE_MANAGER_FEE_BPS = 10;
|
|
60
69
|
var REFERRER = "galleonlabs";
|
|
61
70
|
var MIN_DEPOSIT_USDC = 1;
|
|
62
71
|
var MIN_ORDER_USDC = 1;
|
|
@@ -997,6 +1006,108 @@ async function undelegate(walletClient, depositId, escrowAddress) {
|
|
|
997
1006
|
return hash;
|
|
998
1007
|
}
|
|
999
1008
|
|
|
1009
|
+
// src/telemetry.ts
|
|
1010
|
+
var SDK_EVENTS_ENDPOINT = "https://usdctofiat.xyz/api/sdk-events";
|
|
1011
|
+
var MAX_BATCH_SIZE = 50;
|
|
1012
|
+
var FLUSH_DELAY_MS = 180;
|
|
1013
|
+
var TELEMETRY_TIMEOUT_MS = 2e3;
|
|
1014
|
+
var queuedEvents = [];
|
|
1015
|
+
var flushTimer = null;
|
|
1016
|
+
var flushInFlight = false;
|
|
1017
|
+
function sanitizeAttributionId(raw) {
|
|
1018
|
+
if (typeof raw !== "string") return void 0;
|
|
1019
|
+
const stripped = raw.trim().replace(/[^a-zA-Z0-9_-]/g, "");
|
|
1020
|
+
if (!stripped) return void 0;
|
|
1021
|
+
if (stripped.length > 64) return void 0;
|
|
1022
|
+
return stripped;
|
|
1023
|
+
}
|
|
1024
|
+
function scheduleFlush() {
|
|
1025
|
+
if (flushTimer != null) return;
|
|
1026
|
+
flushTimer = setTimeout(() => {
|
|
1027
|
+
flushTimer = null;
|
|
1028
|
+
void flushQueue();
|
|
1029
|
+
}, FLUSH_DELAY_MS);
|
|
1030
|
+
}
|
|
1031
|
+
async function postBatch(batch) {
|
|
1032
|
+
if (!batch.length) return;
|
|
1033
|
+
const body = JSON.stringify(batch);
|
|
1034
|
+
try {
|
|
1035
|
+
if (typeof navigator !== "undefined" && typeof navigator.sendBeacon === "function") {
|
|
1036
|
+
const blob = new Blob([body], { type: "application/json" });
|
|
1037
|
+
const accepted = navigator.sendBeacon(SDK_EVENTS_ENDPOINT, blob);
|
|
1038
|
+
if (accepted) return;
|
|
1039
|
+
}
|
|
1040
|
+
} catch {
|
|
1041
|
+
}
|
|
1042
|
+
try {
|
|
1043
|
+
const controller = typeof AbortController !== "undefined" ? new AbortController() : null;
|
|
1044
|
+
const timeout = controller ? setTimeout(() => controller.abort(), TELEMETRY_TIMEOUT_MS) : null;
|
|
1045
|
+
await fetch(SDK_EVENTS_ENDPOINT, {
|
|
1046
|
+
method: "POST",
|
|
1047
|
+
headers: { "Content-Type": "application/json" },
|
|
1048
|
+
body,
|
|
1049
|
+
keepalive: true,
|
|
1050
|
+
signal: controller?.signal
|
|
1051
|
+
}).catch(() => {
|
|
1052
|
+
});
|
|
1053
|
+
if (timeout) clearTimeout(timeout);
|
|
1054
|
+
} catch {
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
async function flushQueue() {
|
|
1058
|
+
if (flushInFlight) return;
|
|
1059
|
+
if (!queuedEvents.length) return;
|
|
1060
|
+
flushInFlight = true;
|
|
1061
|
+
try {
|
|
1062
|
+
while (queuedEvents.length > 0) {
|
|
1063
|
+
const batch = queuedEvents.slice(0, MAX_BATCH_SIZE);
|
|
1064
|
+
queuedEvents = queuedEvents.slice(batch.length);
|
|
1065
|
+
await postBatch(batch);
|
|
1066
|
+
}
|
|
1067
|
+
} finally {
|
|
1068
|
+
flushInFlight = false;
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
function emitEvent(name, payload) {
|
|
1072
|
+
try {
|
|
1073
|
+
queuedEvents.push({
|
|
1074
|
+
name,
|
|
1075
|
+
payload,
|
|
1076
|
+
ts: Date.now()
|
|
1077
|
+
});
|
|
1078
|
+
if (queuedEvents.length >= MAX_BATCH_SIZE) {
|
|
1079
|
+
void flushQueue();
|
|
1080
|
+
return;
|
|
1081
|
+
}
|
|
1082
|
+
scheduleFlush();
|
|
1083
|
+
} catch {
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
function sendTelemetryEvent(name, payload) {
|
|
1087
|
+
emitEvent(name, payload);
|
|
1088
|
+
}
|
|
1089
|
+
function createTelemetryContext(options) {
|
|
1090
|
+
const integratorId = sanitizeAttributionId(options.integratorId);
|
|
1091
|
+
const referralId = sanitizeAttributionId(options.referralId);
|
|
1092
|
+
const enabled = options.telemetry !== false;
|
|
1093
|
+
const sdkVersion = options.sdkVersion;
|
|
1094
|
+
return {
|
|
1095
|
+
enabled,
|
|
1096
|
+
sdkVersion,
|
|
1097
|
+
integratorId,
|
|
1098
|
+
referralId,
|
|
1099
|
+
emit(name, payload = {}) {
|
|
1100
|
+
if (!enabled) return;
|
|
1101
|
+
emitEvent(name, {
|
|
1102
|
+
sdkVersion,
|
|
1103
|
+
integratorId,
|
|
1104
|
+
referralId,
|
|
1105
|
+
...payload
|
|
1106
|
+
});
|
|
1107
|
+
}
|
|
1108
|
+
};
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1000
1111
|
// src/deposit.ts
|
|
1001
1112
|
function usdcToUnits(amount) {
|
|
1002
1113
|
return (0, import_viem3.parseUnits)(amount, 6);
|
|
@@ -1114,256 +1225,316 @@ async function findUndelegatedDeposit(walletAddress) {
|
|
|
1114
1225
|
if (remaining === 0n) return false;
|
|
1115
1226
|
return (d.rateManagerId ?? "").toLowerCase() !== delegateIdLower;
|
|
1116
1227
|
});
|
|
1117
|
-
undelegated.sort((a, b) =>
|
|
1228
|
+
undelegated.sort((a, b) => {
|
|
1229
|
+
const left = BigInt(a.depositId);
|
|
1230
|
+
const right = BigInt(b.depositId);
|
|
1231
|
+
if (left === right) return 0;
|
|
1232
|
+
return left > right ? -1 : 1;
|
|
1233
|
+
});
|
|
1118
1234
|
return undelegated[0] ?? null;
|
|
1119
1235
|
} catch {
|
|
1120
1236
|
return null;
|
|
1121
1237
|
}
|
|
1122
1238
|
}
|
|
1123
|
-
async function offramp(walletClient, params, onProgress) {
|
|
1239
|
+
async function offramp(walletClient, params, onProgress, telemetryContext) {
|
|
1124
1240
|
const { amount, platform, currency, identifier } = params;
|
|
1125
1241
|
const platformId = platform.id;
|
|
1126
1242
|
const currencyCode = currency.code;
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1243
|
+
const telemetry = telemetryContext ?? createTelemetryContext({
|
|
1244
|
+
sdkVersion: SDK_VERSION,
|
|
1245
|
+
telemetry: true,
|
|
1246
|
+
integratorId: params.integratorId,
|
|
1247
|
+
referralId: params.referralId
|
|
1248
|
+
});
|
|
1249
|
+
const flowStartMs = Date.now();
|
|
1250
|
+
const emitProgress = (progress) => {
|
|
1251
|
+
onProgress?.(progress);
|
|
1252
|
+
telemetry.emit("sdk.createDeposit.progress", {
|
|
1253
|
+
step: progress.step,
|
|
1254
|
+
txHash: progress.txHash
|
|
1255
|
+
});
|
|
1256
|
+
};
|
|
1257
|
+
try {
|
|
1258
|
+
if (!walletClient.account?.address) {
|
|
1259
|
+
throw new OfframpError("Wallet client has no account. Connect a wallet first.", "VALIDATION");
|
|
1260
|
+
}
|
|
1261
|
+
const walletAddress = walletClient.account.address.toLowerCase();
|
|
1262
|
+
telemetry.emit("sdk.createDeposit.start", {
|
|
1263
|
+
platform: platformId,
|
|
1264
|
+
currency: currencyCode,
|
|
1265
|
+
amount,
|
|
1266
|
+
wallet: walletAddress
|
|
1267
|
+
});
|
|
1268
|
+
const amt = parseFloat(amount);
|
|
1269
|
+
if (!Number.isFinite(amt) || amt < MIN_DEPOSIT_USDC) {
|
|
1270
|
+
throw new OfframpError(`Minimum deposit is ${MIN_DEPOSIT_USDC} USDC`, "VALIDATION");
|
|
1271
|
+
}
|
|
1272
|
+
if (!platform.currencies.includes(currencyCode)) {
|
|
1273
|
+
throw new OfframpError(`${currencyCode} is not supported on ${platform.name}`, "UNSUPPORTED");
|
|
1274
|
+
}
|
|
1275
|
+
const validation = platform.validate(identifier);
|
|
1276
|
+
if (!validation.valid) {
|
|
1277
|
+
throw new OfframpError(validation.error || "Invalid identifier", "VALIDATION");
|
|
1278
|
+
}
|
|
1279
|
+
const normalizedIdentifier = validation.normalized;
|
|
1280
|
+
const methodHash = getPaymentMethodHash(platformId);
|
|
1281
|
+
if (!methodHash) {
|
|
1282
|
+
throw new OfframpError(`${platform.name} is not currently supported`, "UNSUPPORTED");
|
|
1283
|
+
}
|
|
1284
|
+
const existing = await findUndelegatedDeposit(walletAddress);
|
|
1285
|
+
if (existing) {
|
|
1286
|
+
emitProgress({ step: "resuming", depositId: existing.depositId });
|
|
1287
|
+
const client2 = createSdkClient(walletClient);
|
|
1288
|
+
const txOverrides2 = { referrer: [REFERRER] };
|
|
1289
|
+
try {
|
|
1290
|
+
const result2 = await client2.setRateManager({
|
|
1291
|
+
depositId: BigInt(existing.depositId),
|
|
1292
|
+
rateManagerAddress: RATE_MANAGER_REGISTRY_ADDRESS,
|
|
1293
|
+
rateManagerId: DELEGATE_RATE_MANAGER_ID,
|
|
1294
|
+
escrowAddress: existing.escrowAddress,
|
|
1295
|
+
txOverrides: txOverrides2
|
|
1296
|
+
});
|
|
1297
|
+
const txHash = extractTxHash2(result2);
|
|
1298
|
+
emitProgress({ step: "done", txHash, depositId: existing.depositId });
|
|
1299
|
+
const resumedResult = { depositId: existing.depositId, txHash, resumed: true };
|
|
1300
|
+
telemetry.emit("sdk.createDeposit.success", {
|
|
1301
|
+
depositId: resumedResult.depositId,
|
|
1302
|
+
txHash: resumedResult.txHash,
|
|
1303
|
+
wallet: walletAddress,
|
|
1304
|
+
resumed: true,
|
|
1305
|
+
wallDurationMs: Date.now() - flowStartMs
|
|
1306
|
+
});
|
|
1307
|
+
return resumedResult;
|
|
1308
|
+
} catch (err) {
|
|
1309
|
+
if (isUserCancellation(err))
|
|
1310
|
+
throw new OfframpError("User cancelled", "USER_CANCELLED", "resuming", err);
|
|
1311
|
+
throw new OfframpError(
|
|
1312
|
+
"Found undelegated deposit but delegation failed. Try again.",
|
|
1313
|
+
"DELEGATION_FAILED",
|
|
1314
|
+
"resuming",
|
|
1315
|
+
err,
|
|
1316
|
+
{ depositId: existing.depositId, txHash: existing.txHash }
|
|
1317
|
+
);
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
const truncatedAmount = amt.toFixed(6).replace(/\.?0+$/, "");
|
|
1321
|
+
const amountUnits = usdcToUnits(truncatedAmount);
|
|
1322
|
+
const minUnits = usdcToUnits(String(MIN_ORDER_USDC));
|
|
1323
|
+
const maxUnits = usdcToUnits(String(Math.min(amt, 2500)));
|
|
1152
1324
|
try {
|
|
1153
|
-
const
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1325
|
+
const publicClient = (0, import_viem3.createPublicClient)({ chain: import_chains3.base, transport: (0, import_viem3.http)(BASE_RPC_URL) });
|
|
1326
|
+
const balance = await publicClient.readContract({
|
|
1327
|
+
address: USDC_ADDRESS,
|
|
1328
|
+
abi: [
|
|
1329
|
+
{
|
|
1330
|
+
name: "balanceOf",
|
|
1331
|
+
type: "function",
|
|
1332
|
+
stateMutability: "view",
|
|
1333
|
+
inputs: [{ name: "account", type: "address" }],
|
|
1334
|
+
outputs: [{ name: "", type: "uint256" }]
|
|
1335
|
+
}
|
|
1336
|
+
],
|
|
1337
|
+
functionName: "balanceOf",
|
|
1338
|
+
args: [walletAddress]
|
|
1339
|
+
});
|
|
1340
|
+
if (balance < amountUnits) {
|
|
1341
|
+
const available = Number((0, import_viem3.formatUnits)(balance, 6));
|
|
1342
|
+
throw new OfframpError(
|
|
1343
|
+
`Insufficient USDC balance. Have ${available.toFixed(2)}, need ${truncatedAmount}.`,
|
|
1344
|
+
"VALIDATION"
|
|
1345
|
+
);
|
|
1346
|
+
}
|
|
1347
|
+
} catch (err) {
|
|
1348
|
+
if (err instanceof OfframpError) throw err;
|
|
1349
|
+
}
|
|
1350
|
+
const client = createSdkClient(walletClient);
|
|
1351
|
+
const txOverrides = { referrer: [REFERRER] };
|
|
1352
|
+
emitProgress({ step: "approving" });
|
|
1353
|
+
try {
|
|
1354
|
+
await client.ensureAllowance({
|
|
1355
|
+
token: USDC_ADDRESS,
|
|
1356
|
+
amount: amountUnits,
|
|
1357
|
+
escrowAddress: ESCROW_ADDRESS,
|
|
1358
|
+
maxApprove: false,
|
|
1359
|
+
txOverrides
|
|
1159
1360
|
});
|
|
1160
|
-
const txHash = extractTxHash2(result);
|
|
1161
|
-
onProgress?.({ step: "done", txHash, depositId: existing.depositId });
|
|
1162
|
-
return { depositId: existing.depositId, txHash, resumed: true };
|
|
1163
1361
|
} catch (err) {
|
|
1164
1362
|
if (isUserCancellation(err))
|
|
1165
|
-
throw new OfframpError("User cancelled", "USER_CANCELLED", "
|
|
1363
|
+
throw new OfframpError("User cancelled", "USER_CANCELLED", "approving", err);
|
|
1364
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
1166
1365
|
throw new OfframpError(
|
|
1167
|
-
|
|
1168
|
-
"
|
|
1169
|
-
"
|
|
1170
|
-
err
|
|
1171
|
-
{ depositId: existing.depositId, txHash: existing.txHash }
|
|
1366
|
+
`USDC approval failed: ${detail}`,
|
|
1367
|
+
"APPROVAL_FAILED",
|
|
1368
|
+
"approving",
|
|
1369
|
+
err
|
|
1172
1370
|
);
|
|
1173
1371
|
}
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
const balance = await publicClient.readContract({
|
|
1182
|
-
address: USDC_ADDRESS,
|
|
1183
|
-
abi: [
|
|
1184
|
-
{
|
|
1185
|
-
name: "balanceOf",
|
|
1186
|
-
type: "function",
|
|
1187
|
-
stateMutability: "view",
|
|
1188
|
-
inputs: [{ name: "account", type: "address" }],
|
|
1189
|
-
outputs: [{ name: "", type: "uint256" }]
|
|
1190
|
-
}
|
|
1191
|
-
],
|
|
1192
|
-
functionName: "balanceOf",
|
|
1193
|
-
args: [walletAddress]
|
|
1194
|
-
});
|
|
1195
|
-
if (balance < amountUnits) {
|
|
1196
|
-
const available = Number((0, import_viem3.formatUnits)(balance, 6));
|
|
1372
|
+
emitProgress({ step: "registering" });
|
|
1373
|
+
let hashedOnchainId;
|
|
1374
|
+
try {
|
|
1375
|
+
const canonicalName = platformId.startsWith("zelle") ? "zelle" : platformId;
|
|
1376
|
+
const depositData = buildDepositData(platformId, normalizedIdentifier);
|
|
1377
|
+
hashedOnchainId = await registerPayeeDetails(canonicalName, depositData);
|
|
1378
|
+
} catch (err) {
|
|
1197
1379
|
throw new OfframpError(
|
|
1198
|
-
|
|
1199
|
-
"
|
|
1380
|
+
"Payee registration failed",
|
|
1381
|
+
"REGISTRATION_FAILED",
|
|
1382
|
+
"registering",
|
|
1383
|
+
err
|
|
1200
1384
|
);
|
|
1201
1385
|
}
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
await client.ensureAllowance({
|
|
1210
|
-
token: USDC_ADDRESS,
|
|
1211
|
-
amount: amountUnits,
|
|
1212
|
-
escrowAddress: ESCROW_ADDRESS,
|
|
1213
|
-
maxApprove: false,
|
|
1214
|
-
txOverrides
|
|
1215
|
-
});
|
|
1216
|
-
} catch (err) {
|
|
1217
|
-
if (isUserCancellation(err))
|
|
1218
|
-
throw new OfframpError("User cancelled", "USER_CANCELLED", "approving", err);
|
|
1219
|
-
const detail = err instanceof Error ? err.message : String(err);
|
|
1220
|
-
throw new OfframpError(`USDC approval failed: ${detail}`, "APPROVAL_FAILED", "approving", err);
|
|
1221
|
-
}
|
|
1222
|
-
onProgress?.({ step: "registering" });
|
|
1223
|
-
let hashedOnchainId;
|
|
1224
|
-
try {
|
|
1225
|
-
const canonicalName = platformId.startsWith("zelle") ? "zelle" : platformId;
|
|
1226
|
-
const depositData = buildDepositData(platformId, normalizedIdentifier);
|
|
1227
|
-
hashedOnchainId = await registerPayeeDetails(canonicalName, depositData);
|
|
1228
|
-
} catch (err) {
|
|
1229
|
-
throw new OfframpError("Payee registration failed", "REGISTRATION_FAILED", "registering", err);
|
|
1230
|
-
}
|
|
1231
|
-
onProgress?.({ step: "depositing" });
|
|
1232
|
-
const conversionRates = [
|
|
1233
|
-
[{ currency: currencyCode, conversionRate: "1" }]
|
|
1234
|
-
];
|
|
1235
|
-
const baseCurrenciesOverride = (0, import_sdk5.mapConversionRatesToOnchainMinRate)(conversionRates, 1);
|
|
1236
|
-
const currenciesOverride = attachOracleConfig(baseCurrenciesOverride, conversionRates);
|
|
1237
|
-
let hash;
|
|
1238
|
-
try {
|
|
1239
|
-
const result = await client.createDeposit({
|
|
1240
|
-
token: USDC_ADDRESS,
|
|
1241
|
-
amount: amountUnits,
|
|
1242
|
-
retainOnEmpty: false,
|
|
1243
|
-
intentAmountRange: { min: minUnits, max: maxUnits },
|
|
1244
|
-
processorNames: [platformId],
|
|
1245
|
-
conversionRates,
|
|
1246
|
-
payeeDetailsHashes: [hashedOnchainId],
|
|
1247
|
-
paymentMethodsOverride: [methodHash],
|
|
1248
|
-
paymentMethodDataOverride: [
|
|
1249
|
-
{
|
|
1250
|
-
intentGatingService: GATING_SERVICE_ADDRESS,
|
|
1251
|
-
payeeDetails: hashedOnchainId,
|
|
1252
|
-
data: "0x"
|
|
1253
|
-
}
|
|
1254
|
-
],
|
|
1255
|
-
currenciesOverride,
|
|
1256
|
-
escrowAddress: ESCROW_ADDRESS,
|
|
1257
|
-
txOverrides
|
|
1258
|
-
});
|
|
1259
|
-
if (!result?.hash) throw new Error("No transaction hash returned");
|
|
1260
|
-
hash = result.hash;
|
|
1261
|
-
} catch (err) {
|
|
1262
|
-
if (isUserCancellation(err))
|
|
1263
|
-
throw new OfframpError("User cancelled", "USER_CANCELLED", "depositing", err);
|
|
1264
|
-
const detail = err instanceof Error ? err.message : String(err);
|
|
1265
|
-
throw new OfframpError(
|
|
1266
|
-
`Deposit transaction failed: ${detail}`,
|
|
1267
|
-
"DEPOSIT_FAILED",
|
|
1268
|
-
"depositing",
|
|
1269
|
-
err
|
|
1270
|
-
);
|
|
1271
|
-
}
|
|
1272
|
-
onProgress?.({ step: "confirming", txHash: hash });
|
|
1273
|
-
let depositId = "";
|
|
1274
|
-
const receiptClient = client;
|
|
1275
|
-
if (typeof receiptClient.waitForTransactionReceipt === "function") {
|
|
1386
|
+
emitProgress({ step: "depositing" });
|
|
1387
|
+
const conversionRates = [
|
|
1388
|
+
[{ currency: currencyCode, conversionRate: "1" }]
|
|
1389
|
+
];
|
|
1390
|
+
const baseCurrenciesOverride = (0, import_sdk5.mapConversionRatesToOnchainMinRate)(conversionRates, 1);
|
|
1391
|
+
const currenciesOverride = attachOracleConfig(baseCurrenciesOverride, conversionRates);
|
|
1392
|
+
let hash;
|
|
1276
1393
|
try {
|
|
1277
|
-
const
|
|
1278
|
-
|
|
1279
|
-
|
|
1394
|
+
const result2 = await client.createDeposit({
|
|
1395
|
+
token: USDC_ADDRESS,
|
|
1396
|
+
amount: amountUnits,
|
|
1397
|
+
retainOnEmpty: false,
|
|
1398
|
+
intentAmountRange: { min: minUnits, max: maxUnits },
|
|
1399
|
+
processorNames: [platformId],
|
|
1400
|
+
conversionRates,
|
|
1401
|
+
payeeDetailsHashes: [hashedOnchainId],
|
|
1402
|
+
paymentMethodsOverride: [methodHash],
|
|
1403
|
+
paymentMethodDataOverride: [
|
|
1404
|
+
{
|
|
1405
|
+
intentGatingService: GATING_SERVICE_ADDRESS,
|
|
1406
|
+
payeeDetails: hashedOnchainId,
|
|
1407
|
+
data: "0x"
|
|
1408
|
+
}
|
|
1409
|
+
],
|
|
1410
|
+
currenciesOverride,
|
|
1411
|
+
escrowAddress: ESCROW_ADDRESS,
|
|
1412
|
+
txOverrides
|
|
1413
|
+
});
|
|
1414
|
+
if (!result2?.hash) throw new Error("No transaction hash returned");
|
|
1415
|
+
hash = result2.hash;
|
|
1416
|
+
} catch (err) {
|
|
1417
|
+
if (isUserCancellation(err))
|
|
1418
|
+
throw new OfframpError("User cancelled", "USER_CANCELLED", "depositing", err);
|
|
1419
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
1420
|
+
throw new OfframpError(
|
|
1421
|
+
`Deposit transaction failed: ${detail}`,
|
|
1422
|
+
"DEPOSIT_FAILED",
|
|
1423
|
+
"depositing",
|
|
1424
|
+
err
|
|
1425
|
+
);
|
|
1280
1426
|
}
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1427
|
+
emitProgress({ step: "confirming", txHash: hash });
|
|
1428
|
+
let depositId = "";
|
|
1429
|
+
const receiptClient = client;
|
|
1430
|
+
if (typeof receiptClient.waitForTransactionReceipt === "function") {
|
|
1285
1431
|
try {
|
|
1286
|
-
const
|
|
1287
|
-
|
|
1288
|
-
{ limit: 25 }
|
|
1289
|
-
);
|
|
1290
|
-
const hit = deps.find((d) => (d?.txHash || "").toLowerCase() === hash.toLowerCase());
|
|
1291
|
-
if (hit) {
|
|
1292
|
-
depositId = String(hit.depositId);
|
|
1293
|
-
break;
|
|
1294
|
-
}
|
|
1432
|
+
const receipt = await receiptClient.waitForTransactionReceipt({ hash, confirmations: 1 });
|
|
1433
|
+
depositId = extractDepositIdFromLogs(receipt.logs) || "";
|
|
1295
1434
|
} catch {
|
|
1296
1435
|
}
|
|
1297
|
-
await new Promise((r) => setTimeout(r, delay));
|
|
1298
|
-
delay = Math.min(INDEXER_MAX_DELAY_MS, Math.floor(delay * 1.7));
|
|
1299
1436
|
}
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
}
|
|
1319
|
-
|
|
1320
|
-
if (isUserCancellation(delegationError)) {
|
|
1437
|
+
if (!depositId) {
|
|
1438
|
+
let delay = INDEXER_INITIAL_DELAY_MS;
|
|
1439
|
+
for (let attempt = 0; attempt < INDEXER_MAX_ATTEMPTS && !depositId; attempt++) {
|
|
1440
|
+
try {
|
|
1441
|
+
const deps = await client.indexer.getDepositsWithRelations(
|
|
1442
|
+
{ depositor: walletAddress },
|
|
1443
|
+
{ limit: 25 }
|
|
1444
|
+
);
|
|
1445
|
+
const hit = deps.find((d) => (d?.txHash || "").toLowerCase() === hash.toLowerCase());
|
|
1446
|
+
if (hit) {
|
|
1447
|
+
depositId = String(hit.depositId);
|
|
1448
|
+
break;
|
|
1449
|
+
}
|
|
1450
|
+
} catch {
|
|
1451
|
+
}
|
|
1452
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
1453
|
+
delay = Math.min(INDEXER_MAX_DELAY_MS, Math.floor(delay * 1.7));
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
if (!depositId) {
|
|
1321
1457
|
throw new OfframpError(
|
|
1322
|
-
"
|
|
1323
|
-
"
|
|
1324
|
-
"
|
|
1325
|
-
|
|
1326
|
-
{ txHash: hash
|
|
1458
|
+
"Deposit created on-chain but could not confirm deposit ID. Your funds are safe. Call offramp() again to resume delegation.",
|
|
1459
|
+
"CONFIRMATION_FAILED",
|
|
1460
|
+
"confirming",
|
|
1461
|
+
void 0,
|
|
1462
|
+
{ txHash: hash }
|
|
1327
1463
|
);
|
|
1328
1464
|
}
|
|
1329
|
-
|
|
1330
|
-
"Deposit created but delegation failed. Call offramp() again to resume delegation.",
|
|
1331
|
-
"DELEGATION_FAILED",
|
|
1332
|
-
"delegating",
|
|
1333
|
-
delegationError,
|
|
1334
|
-
{ txHash: hash, depositId }
|
|
1335
|
-
);
|
|
1336
|
-
}
|
|
1337
|
-
let otcLink;
|
|
1338
|
-
if (params.otcTaker) {
|
|
1339
|
-
onProgress?.({ step: "restricting", txHash: hash, depositId });
|
|
1465
|
+
emitProgress({ step: "delegating", txHash: hash, depositId });
|
|
1340
1466
|
try {
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1467
|
+
await client.setRateManager({
|
|
1468
|
+
depositId: BigInt(depositId),
|
|
1469
|
+
rateManagerAddress: RATE_MANAGER_REGISTRY_ADDRESS,
|
|
1470
|
+
rateManagerId: DELEGATE_RATE_MANAGER_ID,
|
|
1471
|
+
escrowAddress: ESCROW_ADDRESS,
|
|
1472
|
+
txOverrides
|
|
1473
|
+
});
|
|
1474
|
+
} catch (delegationError) {
|
|
1475
|
+
if (isUserCancellation(delegationError)) {
|
|
1345
1476
|
throw new OfframpError(
|
|
1346
|
-
"User cancelled
|
|
1477
|
+
"User cancelled delegation",
|
|
1347
1478
|
"USER_CANCELLED",
|
|
1348
|
-
"
|
|
1349
|
-
|
|
1350
|
-
{
|
|
1351
|
-
txHash: hash,
|
|
1352
|
-
depositId
|
|
1353
|
-
}
|
|
1479
|
+
"delegating",
|
|
1480
|
+
delegationError,
|
|
1481
|
+
{ txHash: hash, depositId }
|
|
1354
1482
|
);
|
|
1355
1483
|
}
|
|
1356
1484
|
throw new OfframpError(
|
|
1357
|
-
"Deposit created
|
|
1358
|
-
"
|
|
1359
|
-
"
|
|
1360
|
-
|
|
1485
|
+
"Deposit created but delegation failed. Call offramp() again to resume delegation.",
|
|
1486
|
+
"DELEGATION_FAILED",
|
|
1487
|
+
"delegating",
|
|
1488
|
+
delegationError,
|
|
1361
1489
|
{ txHash: hash, depositId }
|
|
1362
1490
|
);
|
|
1363
1491
|
}
|
|
1492
|
+
let otcLink;
|
|
1493
|
+
if (params.otcTaker) {
|
|
1494
|
+
emitProgress({ step: "restricting", txHash: hash, depositId });
|
|
1495
|
+
try {
|
|
1496
|
+
const otcResult = await enableOtc(walletClient, depositId, params.otcTaker);
|
|
1497
|
+
otcLink = otcResult.otcLink;
|
|
1498
|
+
} catch (otcError) {
|
|
1499
|
+
if (isUserCancellation(otcError)) {
|
|
1500
|
+
throw new OfframpError(
|
|
1501
|
+
"User cancelled OTC restriction",
|
|
1502
|
+
"USER_CANCELLED",
|
|
1503
|
+
"restricting",
|
|
1504
|
+
otcError,
|
|
1505
|
+
{
|
|
1506
|
+
txHash: hash,
|
|
1507
|
+
depositId
|
|
1508
|
+
}
|
|
1509
|
+
);
|
|
1510
|
+
}
|
|
1511
|
+
throw new OfframpError(
|
|
1512
|
+
"Deposit created and delegated but OTC restriction failed. Use enableOtc() to retry.",
|
|
1513
|
+
"DEPOSIT_FAILED",
|
|
1514
|
+
"restricting",
|
|
1515
|
+
otcError,
|
|
1516
|
+
{ txHash: hash, depositId }
|
|
1517
|
+
);
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
emitProgress({ step: "done", txHash: hash, depositId });
|
|
1521
|
+
const result = { depositId, txHash: hash, resumed: false, otcLink };
|
|
1522
|
+
telemetry.emit("sdk.createDeposit.success", {
|
|
1523
|
+
depositId: result.depositId,
|
|
1524
|
+
txHash: result.txHash,
|
|
1525
|
+
wallet: walletAddress,
|
|
1526
|
+
resumed: false,
|
|
1527
|
+
wallDurationMs: Date.now() - flowStartMs
|
|
1528
|
+
});
|
|
1529
|
+
return result;
|
|
1530
|
+
} catch (error) {
|
|
1531
|
+
const known = error instanceof OfframpError ? error : null;
|
|
1532
|
+
telemetry.emit("sdk.createDeposit.error", {
|
|
1533
|
+
code: known?.code ?? "DEPOSIT_FAILED",
|
|
1534
|
+
step: known?.step ?? "unknown"
|
|
1535
|
+
});
|
|
1536
|
+
throw error;
|
|
1364
1537
|
}
|
|
1365
|
-
onProgress?.({ step: "done", txHash: hash, depositId });
|
|
1366
|
-
return { depositId, txHash: hash, resumed: false, otcLink };
|
|
1367
1538
|
}
|
|
1368
1539
|
|
|
1369
1540
|
// src/currencies.ts
|
|
@@ -1383,19 +1554,191 @@ function buildCurrencies() {
|
|
|
1383
1554
|
return entries;
|
|
1384
1555
|
}
|
|
1385
1556
|
var CURRENCIES = buildCurrencies();
|
|
1557
|
+
|
|
1558
|
+
// src/offramp.ts
|
|
1559
|
+
var IDEMPOTENCY_TTL_MS = 10 * 60 * 1e3;
|
|
1560
|
+
var IDEMPOTENCY_STORAGE_PREFIX = "offramp:idempotency:";
|
|
1561
|
+
function getWalletAddress(walletClient) {
|
|
1562
|
+
const address = walletClient.account?.address;
|
|
1563
|
+
if (!address) {
|
|
1564
|
+
throw new OfframpError("Wallet client has no account. Connect a wallet first.", "VALIDATION");
|
|
1565
|
+
}
|
|
1566
|
+
return address.toLowerCase();
|
|
1567
|
+
}
|
|
1568
|
+
function getIdempotencyStorageKey(walletAddress, idempotencyKey) {
|
|
1569
|
+
return `${IDEMPOTENCY_STORAGE_PREFIX}${walletAddress}:${idempotencyKey}`;
|
|
1570
|
+
}
|
|
1571
|
+
function readIdempotencyResult(storageKey) {
|
|
1572
|
+
if (typeof sessionStorage === "undefined") return null;
|
|
1573
|
+
try {
|
|
1574
|
+
const raw = sessionStorage.getItem(storageKey);
|
|
1575
|
+
if (!raw) return null;
|
|
1576
|
+
const parsed = JSON.parse(raw);
|
|
1577
|
+
const expiresAt = typeof parsed.expiresAt === "number" && Number.isFinite(parsed.expiresAt) ? parsed.expiresAt : 0;
|
|
1578
|
+
if (expiresAt <= Date.now()) {
|
|
1579
|
+
sessionStorage.removeItem(storageKey);
|
|
1580
|
+
return null;
|
|
1581
|
+
}
|
|
1582
|
+
const result = parsed.result;
|
|
1583
|
+
if (!result?.depositId || !result.txHash) {
|
|
1584
|
+
sessionStorage.removeItem(storageKey);
|
|
1585
|
+
return null;
|
|
1586
|
+
}
|
|
1587
|
+
return result;
|
|
1588
|
+
} catch {
|
|
1589
|
+
return null;
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1592
|
+
function writeIdempotencyResult(storageKey, result) {
|
|
1593
|
+
if (typeof sessionStorage === "undefined") return;
|
|
1594
|
+
try {
|
|
1595
|
+
const record = {
|
|
1596
|
+
result,
|
|
1597
|
+
expiresAt: Date.now() + IDEMPOTENCY_TTL_MS
|
|
1598
|
+
};
|
|
1599
|
+
sessionStorage.setItem(storageKey, JSON.stringify(record));
|
|
1600
|
+
} catch {
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
function createPerFlowTelemetry(base4, integratorId, referralId) {
|
|
1604
|
+
return createTelemetryContext({
|
|
1605
|
+
sdkVersion: base4.sdkVersion,
|
|
1606
|
+
telemetry: base4.enabled,
|
|
1607
|
+
integratorId: sanitizeAttributionId(integratorId) ?? base4.integratorId,
|
|
1608
|
+
referralId: sanitizeAttributionId(referralId) ?? base4.referralId
|
|
1609
|
+
});
|
|
1610
|
+
}
|
|
1611
|
+
function normalizeCurrencyEntry(code) {
|
|
1612
|
+
const fromCatalog = CURRENCIES[code];
|
|
1613
|
+
if (fromCatalog) return fromCatalog;
|
|
1614
|
+
return {
|
|
1615
|
+
code,
|
|
1616
|
+
name: code,
|
|
1617
|
+
symbol: code,
|
|
1618
|
+
countryCode: ""
|
|
1619
|
+
};
|
|
1620
|
+
}
|
|
1621
|
+
function buildCurrencyGroups() {
|
|
1622
|
+
const grouped = {};
|
|
1623
|
+
for (const platform of Object.values(PLATFORMS)) {
|
|
1624
|
+
grouped[platform.id] = platform.currencies.map(normalizeCurrencyEntry);
|
|
1625
|
+
}
|
|
1626
|
+
return grouped;
|
|
1627
|
+
}
|
|
1628
|
+
var Offramp = class {
|
|
1629
|
+
walletClient;
|
|
1630
|
+
telemetry;
|
|
1631
|
+
constructor(options) {
|
|
1632
|
+
this.walletClient = options.walletClient;
|
|
1633
|
+
this.telemetry = createTelemetryContext({
|
|
1634
|
+
sdkVersion: SDK_VERSION,
|
|
1635
|
+
telemetry: options.telemetry,
|
|
1636
|
+
integratorId: options.integratorId,
|
|
1637
|
+
referralId: options.referralId
|
|
1638
|
+
});
|
|
1639
|
+
this.telemetry.emit("sdk.init", {
|
|
1640
|
+
userAgent: typeof navigator !== "undefined" ? navigator.userAgent : "unknown"
|
|
1641
|
+
});
|
|
1642
|
+
}
|
|
1643
|
+
async createDeposit(params, onProgress) {
|
|
1644
|
+
const flowTelemetry = createPerFlowTelemetry(
|
|
1645
|
+
this.telemetry,
|
|
1646
|
+
params.integratorId,
|
|
1647
|
+
params.referralId
|
|
1648
|
+
);
|
|
1649
|
+
const sanitizedParams = {
|
|
1650
|
+
...params,
|
|
1651
|
+
integratorId: flowTelemetry.integratorId,
|
|
1652
|
+
referralId: flowTelemetry.referralId
|
|
1653
|
+
};
|
|
1654
|
+
const sanitizedKey = sanitizeAttributionId(params.idempotencyKey);
|
|
1655
|
+
const walletAddress = sanitizedKey ? getWalletAddress(this.walletClient) : null;
|
|
1656
|
+
const storageKey = walletAddress && sanitizedKey ? getIdempotencyStorageKey(walletAddress, sanitizedKey) : null;
|
|
1657
|
+
if (storageKey) {
|
|
1658
|
+
const existing = readIdempotencyResult(storageKey);
|
|
1659
|
+
if (existing) return existing;
|
|
1660
|
+
}
|
|
1661
|
+
const result = await offramp(
|
|
1662
|
+
this.walletClient,
|
|
1663
|
+
sanitizedParams,
|
|
1664
|
+
onProgress,
|
|
1665
|
+
flowTelemetry
|
|
1666
|
+
);
|
|
1667
|
+
if (storageKey) {
|
|
1668
|
+
writeIdempotencyResult(storageKey, result);
|
|
1669
|
+
}
|
|
1670
|
+
return result;
|
|
1671
|
+
}
|
|
1672
|
+
getQuote(input) {
|
|
1673
|
+
const amountUsdc = Number(input.amount);
|
|
1674
|
+
if (!Number.isFinite(amountUsdc) || amountUsdc <= 0) {
|
|
1675
|
+
throw new OfframpError("Amount must be a positive number", "VALIDATION");
|
|
1676
|
+
}
|
|
1677
|
+
if (!input.platform.currencies.includes(input.currency.code)) {
|
|
1678
|
+
throw new OfframpError(
|
|
1679
|
+
`${input.currency.code} is not supported on ${input.platform.name}`,
|
|
1680
|
+
"UNSUPPORTED"
|
|
1681
|
+
);
|
|
1682
|
+
}
|
|
1683
|
+
const vaultSpreadBps = 0;
|
|
1684
|
+
const spreadFactor = Math.max(0, 1 - vaultSpreadBps / 1e4);
|
|
1685
|
+
const expectedFiat = amountUsdc * spreadFactor;
|
|
1686
|
+
const effectiveRate = amountUsdc === 0 ? 0 : expectedFiat / amountUsdc;
|
|
1687
|
+
return {
|
|
1688
|
+
amountUsdc,
|
|
1689
|
+
expectedFiat,
|
|
1690
|
+
effectiveRate,
|
|
1691
|
+
vaultSpreadBps
|
|
1692
|
+
};
|
|
1693
|
+
}
|
|
1694
|
+
getVaultStatus() {
|
|
1695
|
+
return {
|
|
1696
|
+
rateManagerId: DELEGATE_RATE_MANAGER_ID,
|
|
1697
|
+
rateManagerAddress: RATE_MANAGER_REGISTRY_ADDRESS,
|
|
1698
|
+
feeRateBps: DELEGATE_MANAGER_FEE_BPS,
|
|
1699
|
+
escrow: ESCROW_ADDRESS,
|
|
1700
|
+
isActive: true
|
|
1701
|
+
};
|
|
1702
|
+
}
|
|
1703
|
+
listCurrencies() {
|
|
1704
|
+
return buildCurrencyGroups();
|
|
1705
|
+
}
|
|
1706
|
+
};
|
|
1707
|
+
function createOfframp(options) {
|
|
1708
|
+
return new Offramp(options);
|
|
1709
|
+
}
|
|
1710
|
+
|
|
1711
|
+
// src/types.ts
|
|
1712
|
+
var OFFRAMP_ERROR_CODES = {
|
|
1713
|
+
VALIDATION: "VALIDATION",
|
|
1714
|
+
APPROVAL_FAILED: "APPROVAL_FAILED",
|
|
1715
|
+
REGISTRATION_FAILED: "REGISTRATION_FAILED",
|
|
1716
|
+
DEPOSIT_FAILED: "DEPOSIT_FAILED",
|
|
1717
|
+
CONFIRMATION_FAILED: "CONFIRMATION_FAILED",
|
|
1718
|
+
DELEGATION_FAILED: "DELEGATION_FAILED",
|
|
1719
|
+
USER_CANCELLED: "USER_CANCELLED",
|
|
1720
|
+
UNSUPPORTED: "UNSUPPORTED"
|
|
1721
|
+
};
|
|
1386
1722
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1387
1723
|
0 && (module.exports = {
|
|
1388
1724
|
CURRENCIES,
|
|
1389
1725
|
ESCROW_ADDRESS,
|
|
1726
|
+
OFFRAMP_ERROR_CODES,
|
|
1727
|
+
Offramp,
|
|
1390
1728
|
OfframpError,
|
|
1391
1729
|
PLATFORMS,
|
|
1392
1730
|
close,
|
|
1731
|
+
createOfframp,
|
|
1732
|
+
createTelemetryContext,
|
|
1393
1733
|
delegate,
|
|
1394
1734
|
deposits,
|
|
1395
1735
|
disableOtc,
|
|
1736
|
+
emitEvent,
|
|
1396
1737
|
enableOtc,
|
|
1397
1738
|
getOtcLink,
|
|
1398
1739
|
offramp,
|
|
1740
|
+
sanitizeAttributionId,
|
|
1741
|
+
sendTelemetryEvent,
|
|
1399
1742
|
undelegate
|
|
1400
1743
|
});
|
|
1401
1744
|
//# sourceMappingURL=index.cjs.map
|