@swype-org/react-sdk 0.2.242 → 0.2.263
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/README.md +1 -0
- package/dist/index.cjs +1204 -1016
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -3
- package/dist/index.d.ts +12 -3
- package/dist/index.js +1205 -1017
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1154,12 +1154,225 @@ function useBlinkDepositAmount() {
|
|
|
1154
1154
|
};
|
|
1155
1155
|
}
|
|
1156
1156
|
|
|
1157
|
+
// src/walletConnectorResolver.ts
|
|
1158
|
+
function normalize(value) {
|
|
1159
|
+
return (value ?? "").trim().toLowerCase();
|
|
1160
|
+
}
|
|
1161
|
+
function buildTargetMatchers(target) {
|
|
1162
|
+
const values = [target.providerName, target.wagmiConnectorId].map(normalize).filter(Boolean);
|
|
1163
|
+
const aliases = new Set(values);
|
|
1164
|
+
for (const value of values) {
|
|
1165
|
+
if (value.includes("metamask")) {
|
|
1166
|
+
aliases.add("metamask");
|
|
1167
|
+
aliases.add("io.metamask");
|
|
1168
|
+
}
|
|
1169
|
+
if (value === "base" || value === "base account" || value === "base app" || value.includes("coinbase")) {
|
|
1170
|
+
aliases.add("base");
|
|
1171
|
+
aliases.add("coinbase");
|
|
1172
|
+
aliases.add("coinbasewalletsdk");
|
|
1173
|
+
}
|
|
1174
|
+
if (value.includes("trust")) {
|
|
1175
|
+
aliases.add("trust");
|
|
1176
|
+
aliases.add("trustwallet");
|
|
1177
|
+
}
|
|
1178
|
+
if (value.includes("okx")) {
|
|
1179
|
+
aliases.add("okx");
|
|
1180
|
+
aliases.add("okxwallet");
|
|
1181
|
+
aliases.add("com.okx.wallet");
|
|
1182
|
+
}
|
|
1183
|
+
if (value.includes("rabby")) {
|
|
1184
|
+
aliases.add("rabby");
|
|
1185
|
+
aliases.add("io.rabby");
|
|
1186
|
+
}
|
|
1187
|
+
if (value.includes("phantom")) {
|
|
1188
|
+
aliases.add("phantom");
|
|
1189
|
+
aliases.add("app.phantom");
|
|
1190
|
+
}
|
|
1191
|
+
if (value.includes("injected")) {
|
|
1192
|
+
aliases.add("injected");
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
return [...aliases];
|
|
1196
|
+
}
|
|
1197
|
+
function connectorMatchesWallet(connector, target) {
|
|
1198
|
+
if (!connector) {
|
|
1199
|
+
return false;
|
|
1200
|
+
}
|
|
1201
|
+
const connectorId = normalize(connector.id);
|
|
1202
|
+
const connectorName = normalize(connector.name);
|
|
1203
|
+
if (target.wagmiConnectorId) {
|
|
1204
|
+
const targetConnectorId = normalize(target.wagmiConnectorId);
|
|
1205
|
+
if (connectorId === targetConnectorId) {
|
|
1206
|
+
return true;
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
const matchers = buildTargetMatchers(target);
|
|
1210
|
+
if (matchers.length === 0) {
|
|
1211
|
+
return false;
|
|
1212
|
+
}
|
|
1213
|
+
return matchers.some(
|
|
1214
|
+
(matcher) => connectorId === matcher || connectorName === matcher || connectorId.includes(matcher) || connectorName.includes(matcher)
|
|
1215
|
+
);
|
|
1216
|
+
}
|
|
1217
|
+
function resolveWalletConnector(connectors, target) {
|
|
1218
|
+
if (target.wagmiConnectorId || target.providerName) {
|
|
1219
|
+
return connectors.find((connector) => connectorMatchesWallet(connector, target));
|
|
1220
|
+
}
|
|
1221
|
+
const metaMaskConnector = connectors.find((connector) => connectorMatchesWallet(
|
|
1222
|
+
connector,
|
|
1223
|
+
{ wagmiConnectorId: "metamask" }
|
|
1224
|
+
));
|
|
1225
|
+
return metaMaskConnector ?? connectors[0];
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
// src/wagmiRevokeAndDisconnect.ts
|
|
1229
|
+
var REVOKE_METHOD = "wallet_revokePermissions";
|
|
1230
|
+
var REVOKE_PARAMS = [{ eth_accounts: {} }];
|
|
1231
|
+
var EIP6963_DISCOVERY_MS = 200;
|
|
1232
|
+
async function tryRevoke(provider, context) {
|
|
1233
|
+
if (!provider?.request) return false;
|
|
1234
|
+
try {
|
|
1235
|
+
await provider.request({ method: REVOKE_METHOD, params: REVOKE_PARAMS });
|
|
1236
|
+
console.info("[blink-sdk][revoke] ok", context);
|
|
1237
|
+
return true;
|
|
1238
|
+
} catch (err) {
|
|
1239
|
+
const code = err?.code;
|
|
1240
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1241
|
+
console.info("[blink-sdk][revoke] failed", { ...context, code, message });
|
|
1242
|
+
return false;
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
async function getProviderForConnector(connector) {
|
|
1246
|
+
try {
|
|
1247
|
+
const provider = await connector.getProvider();
|
|
1248
|
+
return provider ?? null;
|
|
1249
|
+
} catch (err) {
|
|
1250
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1251
|
+
console.info("[blink-sdk][revoke] connector.getProvider() threw", {
|
|
1252
|
+
connectorId: connector.id,
|
|
1253
|
+
message
|
|
1254
|
+
});
|
|
1255
|
+
return null;
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
async function discoverEip6963Providers(windowImpl, timeoutMs) {
|
|
1259
|
+
return new Promise((resolve) => {
|
|
1260
|
+
const seen = /* @__PURE__ */ new Map();
|
|
1261
|
+
const onAnnounce = (event) => {
|
|
1262
|
+
const detail = event.detail;
|
|
1263
|
+
if (!detail || !detail.info?.uuid) return;
|
|
1264
|
+
seen.set(detail.info.uuid, detail);
|
|
1265
|
+
};
|
|
1266
|
+
windowImpl.addEventListener("eip6963:announceProvider", onAnnounce);
|
|
1267
|
+
try {
|
|
1268
|
+
windowImpl.dispatchEvent(new Event("eip6963:requestProvider"));
|
|
1269
|
+
} catch {
|
|
1270
|
+
}
|
|
1271
|
+
const timer = setTimeout(() => {
|
|
1272
|
+
windowImpl.removeEventListener(
|
|
1273
|
+
"eip6963:announceProvider",
|
|
1274
|
+
onAnnounce
|
|
1275
|
+
);
|
|
1276
|
+
resolve([...seen.values()]);
|
|
1277
|
+
}, timeoutMs);
|
|
1278
|
+
if (typeof timer.unref === "function") {
|
|
1279
|
+
timer.unref();
|
|
1280
|
+
}
|
|
1281
|
+
});
|
|
1282
|
+
}
|
|
1283
|
+
async function probeAccounts(provider) {
|
|
1284
|
+
if (!provider.request) return [];
|
|
1285
|
+
try {
|
|
1286
|
+
const accounts = await provider.request({ method: "eth_accounts" });
|
|
1287
|
+
return Array.isArray(accounts) ? accounts : [];
|
|
1288
|
+
} catch {
|
|
1289
|
+
return [];
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
async function revokeAndDisconnectConnector(deps) {
|
|
1293
|
+
const activeConnector = deps.getActiveConnector();
|
|
1294
|
+
if (activeConnector) {
|
|
1295
|
+
const provider = await getProviderForConnector(activeConnector);
|
|
1296
|
+
await tryRevoke(provider, {
|
|
1297
|
+
layer: 1,
|
|
1298
|
+
source: "wagmi-connector",
|
|
1299
|
+
rdns: activeConnector.id
|
|
1300
|
+
});
|
|
1301
|
+
await deps.disconnectFn(activeConnector).catch(() => {
|
|
1302
|
+
});
|
|
1303
|
+
return;
|
|
1304
|
+
}
|
|
1305
|
+
let recentRdns = null;
|
|
1306
|
+
try {
|
|
1307
|
+
recentRdns = await deps.getRecentConnectorId() ?? null;
|
|
1308
|
+
} catch {
|
|
1309
|
+
}
|
|
1310
|
+
if (recentRdns) {
|
|
1311
|
+
const matchedConnector = resolveWalletConnector(deps.listConnectors(), {
|
|
1312
|
+
wagmiConnectorId: recentRdns
|
|
1313
|
+
});
|
|
1314
|
+
if (matchedConnector) {
|
|
1315
|
+
const provider = await getProviderForConnector(matchedConnector);
|
|
1316
|
+
const revoked = await tryRevoke(provider, {
|
|
1317
|
+
layer: 2,
|
|
1318
|
+
source: "recent-connector",
|
|
1319
|
+
rdns: matchedConnector.id
|
|
1320
|
+
});
|
|
1321
|
+
await deps.disconnectFn(matchedConnector).catch(() => {
|
|
1322
|
+
});
|
|
1323
|
+
if (revoked) return;
|
|
1324
|
+
} else {
|
|
1325
|
+
console.info("[blink-sdk][revoke] recentConnectorId has no matching connector", {
|
|
1326
|
+
recentRdns
|
|
1327
|
+
});
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
const win = deps.windowImpl ?? (typeof window === "undefined" ? null : window);
|
|
1331
|
+
if (!win) {
|
|
1332
|
+
console.warn("[blink-sdk][revoke] no candidate found and no window for EIP-6963 fallback");
|
|
1333
|
+
return;
|
|
1334
|
+
}
|
|
1335
|
+
const announces = await discoverEip6963Providers(
|
|
1336
|
+
win,
|
|
1337
|
+
deps.eip6963TimeoutMs ?? EIP6963_DISCOVERY_MS
|
|
1338
|
+
);
|
|
1339
|
+
if (announces.length === 0) {
|
|
1340
|
+
console.warn("[blink-sdk][revoke] EIP-6963 enumeration found no providers");
|
|
1341
|
+
return;
|
|
1342
|
+
}
|
|
1343
|
+
let anyRevoked = false;
|
|
1344
|
+
for (const detail of announces) {
|
|
1345
|
+
const accounts = await probeAccounts(detail.provider);
|
|
1346
|
+
if (accounts.length === 0) continue;
|
|
1347
|
+
const ok = await tryRevoke(detail.provider, {
|
|
1348
|
+
layer: 3,
|
|
1349
|
+
source: "eip6963-broadcast",
|
|
1350
|
+
rdns: detail.info.rdns
|
|
1351
|
+
});
|
|
1352
|
+
if (ok) anyRevoked = true;
|
|
1353
|
+
}
|
|
1354
|
+
if (!anyRevoked) {
|
|
1355
|
+
console.warn("[blink-sdk][revoke] EIP-6963 enumeration found no providers with a grant");
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
async function revokeAndDisconnectActiveWagmiConnector(wagmiConfig) {
|
|
1359
|
+
await revokeAndDisconnectConnector({
|
|
1360
|
+
getActiveConnector: () => core.getAccount(wagmiConfig).connector,
|
|
1361
|
+
getRecentConnectorId: async () => {
|
|
1362
|
+
const value = await wagmiConfig.storage?.getItem("recentConnectorId");
|
|
1363
|
+
return typeof value === "string" ? value : null;
|
|
1364
|
+
},
|
|
1365
|
+
listConnectors: () => core.getConnectors(wagmiConfig),
|
|
1366
|
+
disconnectFn: (connector) => core.disconnect(wagmiConfig, { connector })
|
|
1367
|
+
});
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1157
1370
|
// src/otherWalletConnect.ts
|
|
1158
1371
|
function findWalletConnectConnector(connectors) {
|
|
1159
1372
|
return connectors.find((connector) => {
|
|
1160
|
-
const id =
|
|
1161
|
-
const name =
|
|
1162
|
-
const type =
|
|
1373
|
+
const id = normalize2(connector.id);
|
|
1374
|
+
const name = normalize2(connector.name);
|
|
1375
|
+
const type = normalize2(connector.type);
|
|
1163
1376
|
return id === "walletconnect" || id === "wallet-connect" || name === "walletconnect" || name === "wallet connect" || type === "walletconnect";
|
|
1164
1377
|
});
|
|
1165
1378
|
}
|
|
@@ -1176,9 +1389,9 @@ function findReownExtensionConnector(connectors, wallet) {
|
|
|
1176
1389
|
const eligible = connectors.filter((connector) => !findWalletConnectConnector([connector]));
|
|
1177
1390
|
const match = eligible.find((connector) => {
|
|
1178
1391
|
const connectorValues = [
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1392
|
+
normalize2(connector.id),
|
|
1393
|
+
normalize2(connector.name),
|
|
1394
|
+
normalize2(connector.type)
|
|
1182
1395
|
].filter(Boolean);
|
|
1183
1396
|
return targets.some(
|
|
1184
1397
|
(target) => connectorValues.some(
|
|
@@ -1207,8 +1420,8 @@ async function findReownExtensionConnectorAsync(connectors, wallet, bridgeClient
|
|
|
1207
1420
|
});
|
|
1208
1421
|
return void 0;
|
|
1209
1422
|
}
|
|
1210
|
-
const targetRdns =
|
|
1211
|
-
const match = connectors.find((connector) =>
|
|
1423
|
+
const targetRdns = normalize2(resolved.rdns);
|
|
1424
|
+
const match = connectors.find((connector) => normalize2(connector.id) === targetRdns);
|
|
1212
1425
|
console.info("[blink-bridge] findReownExtensionConnectorAsync \u2192 match", {
|
|
1213
1426
|
walletName: wallet.name,
|
|
1214
1427
|
flag: resolved.flag,
|
|
@@ -1226,84 +1439,59 @@ function getReownExtensionTargets(wallet) {
|
|
|
1226
1439
|
return [...targets];
|
|
1227
1440
|
}
|
|
1228
1441
|
function addTarget(targets, value) {
|
|
1229
|
-
const normalized =
|
|
1442
|
+
const normalized = normalize2(value);
|
|
1230
1443
|
if (normalized) {
|
|
1231
1444
|
targets.add(normalized);
|
|
1232
1445
|
}
|
|
1233
1446
|
}
|
|
1234
|
-
function
|
|
1447
|
+
function normalize2(value) {
|
|
1235
1448
|
return (value ?? "").trim().toLowerCase().replaceAll(/[^a-z0-9.]/g, "");
|
|
1236
1449
|
}
|
|
1237
1450
|
|
|
1238
|
-
// src/
|
|
1239
|
-
function
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
}
|
|
1282
|
-
const connectorId = normalize2(connector.id);
|
|
1283
|
-
const connectorName = normalize2(connector.name);
|
|
1284
|
-
if (target.wagmiConnectorId) {
|
|
1285
|
-
const targetConnectorId = normalize2(target.wagmiConnectorId);
|
|
1286
|
-
if (connectorId === targetConnectorId) {
|
|
1287
|
-
return true;
|
|
1288
|
-
}
|
|
1289
|
-
}
|
|
1290
|
-
const matchers = buildTargetMatchers(target);
|
|
1291
|
-
if (matchers.length === 0) {
|
|
1292
|
-
return false;
|
|
1293
|
-
}
|
|
1294
|
-
return matchers.some(
|
|
1295
|
-
(matcher) => connectorId === matcher || connectorName === matcher || connectorId.includes(matcher) || connectorName.includes(matcher)
|
|
1296
|
-
);
|
|
1297
|
-
}
|
|
1298
|
-
function resolveWalletConnector(connectors, target) {
|
|
1299
|
-
if (target.wagmiConnectorId || target.providerName) {
|
|
1300
|
-
return connectors.find((connector) => connectorMatchesWallet(connector, target));
|
|
1451
|
+
// src/resolveScreen.ts
|
|
1452
|
+
function screenForPhase(phase) {
|
|
1453
|
+
switch (phase.step) {
|
|
1454
|
+
case "initializing":
|
|
1455
|
+
case "data-loading":
|
|
1456
|
+
return "loading";
|
|
1457
|
+
case "manual-transfer":
|
|
1458
|
+
return "manual-transfer";
|
|
1459
|
+
case "login":
|
|
1460
|
+
return "login";
|
|
1461
|
+
case "deposit-options":
|
|
1462
|
+
return "deposit-options";
|
|
1463
|
+
case "wallet-picker":
|
|
1464
|
+
return "wallet-picker";
|
|
1465
|
+
case "wallet-setup":
|
|
1466
|
+
if (phase.mobile) {
|
|
1467
|
+
return "open-wallet";
|
|
1468
|
+
}
|
|
1469
|
+
if (phase.desktopWait) {
|
|
1470
|
+
return "open-wallet";
|
|
1471
|
+
}
|
|
1472
|
+
return "setup-deposit";
|
|
1473
|
+
case "select-source":
|
|
1474
|
+
return phase.isDesktop ? "setup" : "select-source";
|
|
1475
|
+
case "one-tap-setup":
|
|
1476
|
+
return "setup";
|
|
1477
|
+
case "token-picker":
|
|
1478
|
+
return "token-picker";
|
|
1479
|
+
case "guest-source-picker":
|
|
1480
|
+
return "guest-source-picker";
|
|
1481
|
+
case "deposit":
|
|
1482
|
+
return "deposit";
|
|
1483
|
+
case "processing":
|
|
1484
|
+
return "processing";
|
|
1485
|
+
case "confirm-sign":
|
|
1486
|
+
return "confirm-sign";
|
|
1487
|
+
case "completed":
|
|
1488
|
+
case "failed":
|
|
1489
|
+
return "success";
|
|
1490
|
+
case "amount-too-low":
|
|
1491
|
+
return "amount-too-low";
|
|
1492
|
+
case "enter-amount":
|
|
1493
|
+
return "enter-amount";
|
|
1301
1494
|
}
|
|
1302
|
-
const metaMaskConnector = connectors.find((connector) => connectorMatchesWallet(
|
|
1303
|
-
connector,
|
|
1304
|
-
{ wagmiConnectorId: "metamask" }
|
|
1305
|
-
));
|
|
1306
|
-
return metaMaskConnector ?? connectors[0];
|
|
1307
1495
|
}
|
|
1308
1496
|
|
|
1309
1497
|
// src/passkey-delegation.ts
|
|
@@ -1747,8 +1935,9 @@ async function fetchAccount(apiBaseUrl, token, accountId, credentialId) {
|
|
|
1747
1935
|
return await res.json();
|
|
1748
1936
|
}
|
|
1749
1937
|
async function createAccount(apiBaseUrl, token, params) {
|
|
1938
|
+
const provisionalId = params.id ?? crypto.randomUUID();
|
|
1750
1939
|
const body = {
|
|
1751
|
-
id:
|
|
1940
|
+
id: provisionalId,
|
|
1752
1941
|
name: params.name,
|
|
1753
1942
|
credentialId: params.credentialId
|
|
1754
1943
|
};
|
|
@@ -1776,7 +1965,8 @@ async function createAccount(apiBaseUrl, token, params) {
|
|
|
1776
1965
|
body: JSON.stringify(body)
|
|
1777
1966
|
});
|
|
1778
1967
|
if (!res.ok) await throwApiError(res);
|
|
1779
|
-
|
|
1968
|
+
const account = await res.json();
|
|
1969
|
+
return { ...account, id: account.id ?? provisionalId };
|
|
1780
1970
|
}
|
|
1781
1971
|
async function createAccountAuthorizationSession(apiBaseUrl, token, accountId, credentialId, options) {
|
|
1782
1972
|
const body = { credentialId };
|
|
@@ -7369,289 +7559,706 @@ function EffectiveDepositAmountProvider({
|
|
|
7369
7559
|
return /* @__PURE__ */ jsxRuntime.jsx(EffectiveDepositAmountContext.Provider, { value: memoValue, children });
|
|
7370
7560
|
}
|
|
7371
7561
|
|
|
7372
|
-
// src/
|
|
7373
|
-
function
|
|
7374
|
-
|
|
7375
|
-
|
|
7376
|
-
case "
|
|
7377
|
-
return "
|
|
7378
|
-
case "
|
|
7379
|
-
return "
|
|
7380
|
-
case "
|
|
7381
|
-
return "
|
|
7382
|
-
case "deposit-options":
|
|
7383
|
-
return "deposit-options";
|
|
7384
|
-
case "wallet-picker":
|
|
7385
|
-
return "wallet-picker";
|
|
7386
|
-
case "wallet-setup":
|
|
7387
|
-
if (phase.mobile) {
|
|
7388
|
-
return "open-wallet";
|
|
7389
|
-
}
|
|
7390
|
-
if (phase.desktopWait) {
|
|
7391
|
-
return "open-wallet";
|
|
7392
|
-
}
|
|
7393
|
-
return "setup-deposit";
|
|
7394
|
-
case "select-source":
|
|
7395
|
-
return phase.isDesktop ? "setup" : "select-source";
|
|
7396
|
-
case "one-tap-setup":
|
|
7397
|
-
return "setup";
|
|
7398
|
-
case "token-picker":
|
|
7399
|
-
return "token-picker";
|
|
7400
|
-
case "guest-source-picker":
|
|
7401
|
-
return "guest-source-picker";
|
|
7402
|
-
case "deposit":
|
|
7403
|
-
return "deposit";
|
|
7404
|
-
case "processing":
|
|
7405
|
-
return "processing";
|
|
7406
|
-
case "confirm-sign":
|
|
7407
|
-
return "confirm-sign";
|
|
7562
|
+
// src/manualTransferUtils.ts
|
|
7563
|
+
function screenForSession(session) {
|
|
7564
|
+
if (!session) return "source-selector";
|
|
7565
|
+
switch (session.status) {
|
|
7566
|
+
case "awaiting_deposit":
|
|
7567
|
+
return "awaiting-deposit";
|
|
7568
|
+
case "deposit_received":
|
|
7569
|
+
return "deposit-received";
|
|
7570
|
+
case "routing":
|
|
7571
|
+
return "deposit-routing";
|
|
7408
7572
|
case "completed":
|
|
7573
|
+
return "deposit-complete";
|
|
7574
|
+
case "refunded":
|
|
7409
7575
|
case "failed":
|
|
7410
|
-
|
|
7411
|
-
|
|
7412
|
-
return "amount-too-low";
|
|
7413
|
-
case "enter-amount":
|
|
7414
|
-
return "enter-amount";
|
|
7576
|
+
case "wrong_token":
|
|
7577
|
+
return "deposit-failed";
|
|
7415
7578
|
}
|
|
7416
7579
|
}
|
|
7417
|
-
|
|
7418
|
-
|
|
7419
|
-
var PROCESSING_TIMEOUT_MS = 18e4;
|
|
7420
|
-
var TERMINAL_TRANSFER_STATUSES = /* @__PURE__ */ new Set(["COMPLETED", "FAILED", "EXPIRED"]);
|
|
7421
|
-
var SIGNABLE_TRANSFER_STATUSES = /* @__PURE__ */ new Set(["CREATED", "AUTHORIZED"]);
|
|
7422
|
-
function isTerminalTransferStatus(status) {
|
|
7423
|
-
return TERMINAL_TRANSFER_STATUSES.has(status);
|
|
7424
|
-
}
|
|
7425
|
-
function isTransferSignable(transfer) {
|
|
7426
|
-
return transfer != null && SIGNABLE_TRANSFER_STATUSES.has(transfer.status);
|
|
7427
|
-
}
|
|
7428
|
-
function isTransferAwaitingCompletion(transfer) {
|
|
7429
|
-
if (!transfer) return false;
|
|
7430
|
-
return !isTerminalTransferStatus(transfer.status);
|
|
7431
|
-
}
|
|
7432
|
-
function resolvePreferredTransfer(polledTransfer, localTransfer) {
|
|
7433
|
-
return polledTransfer ?? localTransfer;
|
|
7580
|
+
function isSameChainSameTokenSelection(option, destination) {
|
|
7581
|
+
return option.chainId === destination.chainId && option.tokenAddress.toLowerCase() === destination.token.address.toLowerCase();
|
|
7434
7582
|
}
|
|
7435
|
-
function
|
|
7436
|
-
|
|
7437
|
-
return transfer?.status ?? "UNKNOWN";
|
|
7583
|
+
function feeCopy(_session) {
|
|
7584
|
+
return "No fees";
|
|
7438
7585
|
}
|
|
7439
|
-
function
|
|
7440
|
-
|
|
7441
|
-
|
|
7586
|
+
function toTransfer(session) {
|
|
7587
|
+
return {
|
|
7588
|
+
id: session.sessionId,
|
|
7589
|
+
status: session.status,
|
|
7590
|
+
amount: {
|
|
7591
|
+
amount: Number(session.deliveredAmountUsd ?? session.minAmountUsd),
|
|
7592
|
+
currency: "USD"
|
|
7593
|
+
},
|
|
7594
|
+
sources: [],
|
|
7595
|
+
destinations: [{
|
|
7596
|
+
id: session.sessionId,
|
|
7597
|
+
chainId: session.destination.chainId,
|
|
7598
|
+
address: session.destination.address,
|
|
7599
|
+
token: { address: session.destination.token.address, symbol: "" },
|
|
7600
|
+
amount: { amount: Number(session.deliveredAmountUsd ?? session.minAmountUsd), currency: "USD" }
|
|
7601
|
+
}],
|
|
7602
|
+
createDate: session.createDate,
|
|
7603
|
+
updateDate: session.updateDate
|
|
7604
|
+
};
|
|
7442
7605
|
}
|
|
7443
|
-
var
|
|
7444
|
-
|
|
7445
|
-
|
|
7446
|
-
|
|
7447
|
-
|
|
7448
|
-
|
|
7449
|
-
|
|
7450
|
-
}
|
|
7451
|
-
|
|
7452
|
-
return
|
|
7606
|
+
var SOLANA_CHAIN_ID = 792703809;
|
|
7607
|
+
var SOLANA_NATIVE_SOL_ADDRESS = "11111111111111111111111111111111";
|
|
7608
|
+
function formatDepositUri(address, chainId, depToken) {
|
|
7609
|
+
if (chainId === SOLANA_CHAIN_ID) {
|
|
7610
|
+
if (!depToken || depToken === SOLANA_NATIVE_SOL_ADDRESS) {
|
|
7611
|
+
return `solana:${address}`;
|
|
7612
|
+
}
|
|
7613
|
+
return `solana:${address}?spl-token=${depToken}`;
|
|
7614
|
+
}
|
|
7615
|
+
return address;
|
|
7453
7616
|
}
|
|
7454
|
-
|
|
7455
|
-
|
|
7456
|
-
|
|
7617
|
+
var dataUrlCache = /* @__PURE__ */ new Map();
|
|
7618
|
+
var inFlight = /* @__PURE__ */ new Map();
|
|
7619
|
+
function keyFor(uri, colors) {
|
|
7620
|
+
return `${uri}|${colors.dark}|${colors.light}`;
|
|
7621
|
+
}
|
|
7622
|
+
function getCachedQrDataUrl(uri, colors) {
|
|
7623
|
+
return dataUrlCache.get(keyFor(uri, colors)) ?? null;
|
|
7624
|
+
}
|
|
7625
|
+
function getOrRenderQrDataUrl(uri, colors) {
|
|
7626
|
+
const key = keyFor(uri, colors);
|
|
7627
|
+
const cached = dataUrlCache.get(key);
|
|
7628
|
+
if (cached) return Promise.resolve(cached);
|
|
7629
|
+
const pending = inFlight.get(key);
|
|
7630
|
+
if (pending) return pending;
|
|
7631
|
+
const promise = QRCode__namespace.toDataURL(uri, {
|
|
7632
|
+
errorCorrectionLevel: "H",
|
|
7633
|
+
margin: 1,
|
|
7634
|
+
width: 203,
|
|
7635
|
+
color: { dark: colors.dark, light: colors.light }
|
|
7636
|
+
}).then((url) => {
|
|
7637
|
+
dataUrlCache.set(key, url);
|
|
7638
|
+
inFlight.delete(key);
|
|
7639
|
+
return url;
|
|
7640
|
+
}).catch((err) => {
|
|
7641
|
+
inFlight.delete(key);
|
|
7642
|
+
throw err;
|
|
7643
|
+
});
|
|
7644
|
+
inFlight.set(key, promise);
|
|
7645
|
+
return promise;
|
|
7457
7646
|
}
|
|
7458
7647
|
|
|
7459
|
-
// src/
|
|
7460
|
-
function
|
|
7461
|
-
return
|
|
7462
|
-
}
|
|
7463
|
-
function resolveTerminalPhase(state) {
|
|
7464
|
-
if (state.amountTooLow != null) {
|
|
7465
|
-
return {
|
|
7466
|
-
step: "amount-too-low",
|
|
7467
|
-
minAmountUsd: state.amountTooLow.minAmountUsd
|
|
7468
|
-
};
|
|
7469
|
-
}
|
|
7470
|
-
const transferCompleted = state.transfer?.status === "COMPLETED";
|
|
7471
|
-
const needsPasskeyBootstrap = state.privyAuthenticated && !state.activeCredentialId;
|
|
7472
|
-
if (transferCompleted && !needsPasskeyBootstrap && !state.loginRequested) {
|
|
7473
|
-
return { step: "completed", transfer: state.transfer };
|
|
7474
|
-
}
|
|
7475
|
-
if (state.transfer?.status === "FAILED") {
|
|
7476
|
-
return {
|
|
7477
|
-
step: "failed",
|
|
7478
|
-
transfer: state.transfer,
|
|
7479
|
-
error: state.error ?? "Transfer failed."
|
|
7480
|
-
};
|
|
7481
|
-
}
|
|
7482
|
-
if (state.creatingTransfer || isTransferAwaitingCompletion(state.transfer)) {
|
|
7483
|
-
return { step: "processing", transfer: state.transfer };
|
|
7484
|
-
}
|
|
7485
|
-
return null;
|
|
7648
|
+
// src/hooks/useManualTransferSession.ts
|
|
7649
|
+
function perTokenKey(chainId, tokenAddress) {
|
|
7650
|
+
return `${chainId}:${tokenAddress.toLowerCase()}`;
|
|
7486
7651
|
}
|
|
7487
|
-
function
|
|
7488
|
-
|
|
7489
|
-
|
|
7490
|
-
|
|
7491
|
-
|
|
7492
|
-
|
|
7493
|
-
|
|
7494
|
-
|
|
7495
|
-
|
|
7496
|
-
|
|
7497
|
-
|
|
7498
|
-
|
|
7499
|
-
|
|
7500
|
-
|
|
7501
|
-
|
|
7502
|
-
|
|
7503
|
-
|
|
7504
|
-
|
|
7505
|
-
|
|
7506
|
-
|
|
7507
|
-
|
|
7508
|
-
|
|
7509
|
-
|
|
7510
|
-
|
|
7511
|
-
|
|
7512
|
-
|
|
7513
|
-
|
|
7514
|
-
|
|
7515
|
-
|
|
7516
|
-
|
|
7517
|
-
|
|
7518
|
-
|
|
7519
|
-
|
|
7520
|
-
|
|
7521
|
-
|
|
7652
|
+
function useManualTransferSession({
|
|
7653
|
+
destination,
|
|
7654
|
+
merchantAuthorization,
|
|
7655
|
+
idempotencyKey,
|
|
7656
|
+
onComplete,
|
|
7657
|
+
onError,
|
|
7658
|
+
pollEnabled = true
|
|
7659
|
+
}) {
|
|
7660
|
+
const { apiBaseUrl, tokens } = useBlinkConfig();
|
|
7661
|
+
const [sourceOptions, setSourceOptions] = react.useState(null);
|
|
7662
|
+
const [loadingSources, setLoadingSources] = react.useState(true);
|
|
7663
|
+
const [selectedToken, setSelectedToken] = react.useState("");
|
|
7664
|
+
const [selectedChainId, setSelectedChainId] = react.useState("");
|
|
7665
|
+
const [sessionsByFamily, setSessionsByFamily] = react.useState({});
|
|
7666
|
+
const [perTokenSessions, setPerTokenSessions] = react.useState({});
|
|
7667
|
+
const [loading, setLoading] = react.useState(false);
|
|
7668
|
+
const [error, setError] = react.useState(null);
|
|
7669
|
+
const [copiedAddress, setCopiedAddress] = react.useState(null);
|
|
7670
|
+
const completedRef = react.useRef(/* @__PURE__ */ new Set());
|
|
7671
|
+
const premintedFamiliesRef = react.useRef(/* @__PURE__ */ new Set());
|
|
7672
|
+
const inFlightPerTokenRef = react.useRef(/* @__PURE__ */ new Set());
|
|
7673
|
+
react.useEffect(() => {
|
|
7674
|
+
if (!merchantAuthorization) return;
|
|
7675
|
+
let cancelled = false;
|
|
7676
|
+
setLoadingSources(true);
|
|
7677
|
+
fetchManualTransferSources(apiBaseUrl, { merchantAuthorization, destination }).then((sources) => {
|
|
7678
|
+
if (cancelled) return;
|
|
7679
|
+
setSourceOptions(sources);
|
|
7680
|
+
setLoadingSources(false);
|
|
7681
|
+
const destTokenAddrLower = destination.token.address.toLowerCase();
|
|
7682
|
+
const destMatch = sources.find(
|
|
7683
|
+
(s) => s.chainId === destination.chainId && s.tokenAddress.toLowerCase() === destTokenAddrLower
|
|
7684
|
+
);
|
|
7685
|
+
const svmCanonical = sources.find((s) => s.canonical && s.chainFamily === "svm");
|
|
7686
|
+
const evmCanonical = sources.find((s) => s.canonical && s.chainFamily === "evm");
|
|
7687
|
+
const defaultOption = destMatch ?? svmCanonical ?? evmCanonical ?? sources[0];
|
|
7688
|
+
if (defaultOption) {
|
|
7689
|
+
setSelectedToken(defaultOption.tokenSymbol);
|
|
7690
|
+
setSelectedChainId(String(defaultOption.chainId));
|
|
7691
|
+
}
|
|
7692
|
+
}).catch((err) => {
|
|
7693
|
+
if (!cancelled) {
|
|
7694
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
7695
|
+
setLoadingSources(false);
|
|
7696
|
+
}
|
|
7697
|
+
});
|
|
7698
|
+
return () => {
|
|
7699
|
+
cancelled = true;
|
|
7522
7700
|
};
|
|
7523
|
-
}
|
|
7524
|
-
|
|
7525
|
-
return
|
|
7526
|
-
|
|
7527
|
-
|
|
7528
|
-
|
|
7701
|
+
}, [apiBaseUrl, destination, merchantAuthorization]);
|
|
7702
|
+
react.useEffect(() => {
|
|
7703
|
+
if (!sourceOptions || !merchantAuthorization) return;
|
|
7704
|
+
const canonicals = sourceOptions.filter((s) => s.canonical);
|
|
7705
|
+
if (canonicals.length === 0) return;
|
|
7706
|
+
let cancelled = false;
|
|
7707
|
+
for (const opt of canonicals) {
|
|
7708
|
+
if (premintedFamiliesRef.current.has(opt.chainFamily)) continue;
|
|
7709
|
+
premintedFamiliesRef.current.add(opt.chainFamily);
|
|
7710
|
+
const family = opt.chainFamily;
|
|
7711
|
+
const run = async () => {
|
|
7712
|
+
try {
|
|
7713
|
+
const created = await createManualTransfer(apiBaseUrl, {
|
|
7714
|
+
merchantAuthorization,
|
|
7715
|
+
destination,
|
|
7716
|
+
idempotencyKey,
|
|
7717
|
+
source: { chainId: opt.chainId, tokenAddress: opt.tokenAddress }
|
|
7718
|
+
});
|
|
7719
|
+
if (cancelled) return;
|
|
7720
|
+
setSessionsByFamily((prev) => ({ ...prev, [family]: created }));
|
|
7721
|
+
const uri = formatDepositUri(created.depositAddress, opt.chainId, opt.tokenAddress);
|
|
7722
|
+
void getOrRenderQrDataUrl(uri, { dark: tokens.text, light: tokens.bg });
|
|
7723
|
+
} catch (err) {
|
|
7724
|
+
if (cancelled) return;
|
|
7725
|
+
premintedFamiliesRef.current.delete(family);
|
|
7726
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
7727
|
+
}
|
|
7728
|
+
};
|
|
7729
|
+
void run();
|
|
7730
|
+
}
|
|
7731
|
+
return () => {
|
|
7732
|
+
cancelled = true;
|
|
7529
7733
|
};
|
|
7530
|
-
}
|
|
7531
|
-
|
|
7532
|
-
|
|
7533
|
-
|
|
7534
|
-
|
|
7535
|
-
|
|
7536
|
-
|
|
7537
|
-
|
|
7538
|
-
|
|
7539
|
-
|
|
7540
|
-
|
|
7541
|
-
|
|
7542
|
-
|
|
7543
|
-
|
|
7544
|
-
|
|
7545
|
-
|
|
7546
|
-
|
|
7547
|
-
|
|
7548
|
-
|
|
7549
|
-
|
|
7550
|
-
|
|
7551
|
-
|
|
7552
|
-
|
|
7553
|
-
|
|
7554
|
-
|
|
7555
|
-
|
|
7556
|
-
|
|
7557
|
-
|
|
7558
|
-
|
|
7559
|
-
|
|
7560
|
-
|
|
7561
|
-
|
|
7562
|
-
|
|
7563
|
-
|
|
7564
|
-
|
|
7565
|
-
|
|
7566
|
-
|
|
7567
|
-
|
|
7568
|
-
|
|
7569
|
-
|
|
7570
|
-
|
|
7571
|
-
|
|
7572
|
-
|
|
7573
|
-
|
|
7574
|
-
return
|
|
7575
|
-
|
|
7576
|
-
|
|
7577
|
-
|
|
7578
|
-
|
|
7579
|
-
|
|
7580
|
-
|
|
7581
|
-
|
|
7582
|
-
|
|
7583
|
-
|
|
7584
|
-
|
|
7734
|
+
}, [
|
|
7735
|
+
apiBaseUrl,
|
|
7736
|
+
destination,
|
|
7737
|
+
idempotencyKey,
|
|
7738
|
+
merchantAuthorization,
|
|
7739
|
+
sourceOptions,
|
|
7740
|
+
tokens.text,
|
|
7741
|
+
tokens.bg
|
|
7742
|
+
]);
|
|
7743
|
+
const tokenChoices = react.useMemo(
|
|
7744
|
+
() => Array.from(new Set((sourceOptions ?? []).map((opt) => opt.tokenSymbol))),
|
|
7745
|
+
[sourceOptions]
|
|
7746
|
+
);
|
|
7747
|
+
const chainChoices = react.useMemo(() => {
|
|
7748
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7749
|
+
return (sourceOptions ?? []).filter((opt) => {
|
|
7750
|
+
if (seen.has(opt.chainId)) return false;
|
|
7751
|
+
seen.add(opt.chainId);
|
|
7752
|
+
return true;
|
|
7753
|
+
});
|
|
7754
|
+
}, [sourceOptions]);
|
|
7755
|
+
const tokenLogoUriBySymbol = react.useMemo(() => {
|
|
7756
|
+
const out = {};
|
|
7757
|
+
for (const opt of sourceOptions ?? []) {
|
|
7758
|
+
if (out[opt.tokenSymbol] == null) {
|
|
7759
|
+
out[opt.tokenSymbol] = opt.tokenLogoUri;
|
|
7760
|
+
}
|
|
7761
|
+
}
|
|
7762
|
+
return out;
|
|
7763
|
+
}, [sourceOptions]);
|
|
7764
|
+
const selectedOption = react.useMemo(
|
|
7765
|
+
() => (sourceOptions ?? []).find(
|
|
7766
|
+
(opt) => opt.tokenSymbol === selectedToken && String(opt.chainId) === selectedChainId
|
|
7767
|
+
) ?? null,
|
|
7768
|
+
[sourceOptions, selectedToken, selectedChainId]
|
|
7769
|
+
);
|
|
7770
|
+
const tokensForSelectedChain = react.useMemo(() => {
|
|
7771
|
+
if (!selectedChainId) return null;
|
|
7772
|
+
return new Set(
|
|
7773
|
+
(sourceOptions ?? []).filter((opt) => String(opt.chainId) === selectedChainId).map((opt) => opt.tokenSymbol)
|
|
7774
|
+
);
|
|
7775
|
+
}, [sourceOptions, selectedChainId]);
|
|
7776
|
+
const chainsForSelectedToken = react.useMemo(() => {
|
|
7777
|
+
if (!selectedToken) return null;
|
|
7778
|
+
return new Set(
|
|
7779
|
+
(sourceOptions ?? []).filter((opt) => opt.tokenSymbol === selectedToken).map((opt) => opt.chainId)
|
|
7780
|
+
);
|
|
7781
|
+
}, [sourceOptions, selectedToken]);
|
|
7782
|
+
const session = react.useMemo(() => {
|
|
7783
|
+
if (!selectedOption) return null;
|
|
7784
|
+
const perToken = perTokenSessions[perTokenKey(selectedOption.chainId, selectedOption.tokenAddress)] ?? null;
|
|
7785
|
+
if (isSameChainSameTokenSelection(selectedOption, destination)) {
|
|
7786
|
+
return perToken ?? sessionsByFamily[selectedOption.chainFamily] ?? null;
|
|
7787
|
+
}
|
|
7788
|
+
const familySession = sessionsByFamily[selectedOption.chainFamily];
|
|
7789
|
+
if (familySession) return familySession;
|
|
7790
|
+
return perToken;
|
|
7791
|
+
}, [selectedOption, destination, sessionsByFamily, perTokenSessions]);
|
|
7792
|
+
const depositAddress = session?.depositAddress;
|
|
7793
|
+
const qrReady = !!depositAddress;
|
|
7794
|
+
const lastFeeCopyRef = react.useRef(null);
|
|
7795
|
+
const nextFeeCopy = session ? feeCopy() : null;
|
|
7796
|
+
const sessionFeeCopy = nextFeeCopy === lastFeeCopyRef.current ? lastFeeCopyRef.current : lastFeeCopyRef.current = nextFeeCopy;
|
|
7797
|
+
const activeSessionId = session?.sessionId;
|
|
7798
|
+
const activeSessionStatus = session?.status;
|
|
7799
|
+
react.useEffect(() => {
|
|
7800
|
+
if (!pollEnabled) return;
|
|
7801
|
+
if (!activeSessionId) return;
|
|
7802
|
+
if (activeSessionStatus && ["completed", "failed", "refunded", "wrong_token"].includes(activeSessionStatus)) return;
|
|
7803
|
+
const timer = window.setInterval(() => {
|
|
7804
|
+
fetchManualTransferSession(apiBaseUrl, activeSessionId).then((updated) => {
|
|
7805
|
+
setSessionsByFamily((prev) => {
|
|
7806
|
+
for (const family of Object.keys(prev)) {
|
|
7807
|
+
if (prev[family]?.sessionId === updated.sessionId) {
|
|
7808
|
+
return { ...prev, [family]: updated };
|
|
7809
|
+
}
|
|
7810
|
+
}
|
|
7811
|
+
return prev;
|
|
7812
|
+
});
|
|
7813
|
+
setPerTokenSessions((prev) => {
|
|
7814
|
+
for (const key of Object.keys(prev)) {
|
|
7815
|
+
if (prev[key]?.sessionId === updated.sessionId) {
|
|
7816
|
+
return { ...prev, [key]: updated };
|
|
7817
|
+
}
|
|
7818
|
+
}
|
|
7819
|
+
return prev;
|
|
7820
|
+
});
|
|
7821
|
+
}).catch((err) => setError(err instanceof Error ? err.message : String(err)));
|
|
7822
|
+
}, 2e3);
|
|
7823
|
+
return () => window.clearInterval(timer);
|
|
7824
|
+
}, [apiBaseUrl, activeSessionId, activeSessionStatus, pollEnabled]);
|
|
7825
|
+
const completionSignature = react.useMemo(() => {
|
|
7826
|
+
const entries2 = [];
|
|
7827
|
+
for (const family of Object.keys(sessionsByFamily)) {
|
|
7828
|
+
const s = sessionsByFamily[family];
|
|
7829
|
+
if (s) entries2.push([s.sessionId, s.status]);
|
|
7830
|
+
}
|
|
7831
|
+
for (const key of Object.keys(perTokenSessions)) {
|
|
7832
|
+
const s = perTokenSessions[key];
|
|
7833
|
+
entries2.push([s.sessionId, s.status]);
|
|
7834
|
+
}
|
|
7835
|
+
entries2.sort((a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0);
|
|
7836
|
+
return JSON.stringify(entries2);
|
|
7837
|
+
}, [sessionsByFamily, perTokenSessions]);
|
|
7838
|
+
react.useEffect(() => {
|
|
7839
|
+
const all = [];
|
|
7840
|
+
for (const family of Object.keys(sessionsByFamily)) {
|
|
7841
|
+
const s = sessionsByFamily[family];
|
|
7842
|
+
if (s) all.push(s);
|
|
7843
|
+
}
|
|
7844
|
+
for (const key of Object.keys(perTokenSessions)) {
|
|
7845
|
+
all.push(perTokenSessions[key]);
|
|
7846
|
+
}
|
|
7847
|
+
for (const s of all) {
|
|
7848
|
+
if (s.status !== "completed") continue;
|
|
7849
|
+
if (completedRef.current.has(s.sessionId)) continue;
|
|
7850
|
+
completedRef.current.add(s.sessionId);
|
|
7851
|
+
onComplete?.(toTransfer(s));
|
|
7852
|
+
break;
|
|
7853
|
+
}
|
|
7854
|
+
}, [completionSignature, onComplete]);
|
|
7855
|
+
react.useEffect(() => {
|
|
7856
|
+
if (!error) return;
|
|
7857
|
+
onError?.(error);
|
|
7858
|
+
}, [error, onError]);
|
|
7859
|
+
const createSession = react.useCallback(async (option) => {
|
|
7860
|
+
if (!merchantAuthorization) return;
|
|
7861
|
+
setLoading(true);
|
|
7862
|
+
setError(null);
|
|
7863
|
+
try {
|
|
7864
|
+
const created = await createManualTransfer(apiBaseUrl, {
|
|
7865
|
+
merchantAuthorization,
|
|
7866
|
+
destination,
|
|
7867
|
+
idempotencyKey,
|
|
7868
|
+
source: { chainId: option.chainId, tokenAddress: option.tokenAddress }
|
|
7869
|
+
});
|
|
7870
|
+
const key = perTokenKey(option.chainId, option.tokenAddress);
|
|
7871
|
+
setPerTokenSessions((prev) => ({ ...prev, [key]: created }));
|
|
7872
|
+
const uri = formatDepositUri(created.depositAddress, option.chainId, option.tokenAddress);
|
|
7873
|
+
void getOrRenderQrDataUrl(uri, { dark: tokens.text, light: tokens.bg });
|
|
7874
|
+
} catch (err) {
|
|
7875
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
7876
|
+
} finally {
|
|
7877
|
+
setLoading(false);
|
|
7878
|
+
}
|
|
7879
|
+
}, [apiBaseUrl, destination, idempotencyKey, merchantAuthorization, tokens.text, tokens.bg]);
|
|
7880
|
+
react.useEffect(() => {
|
|
7881
|
+
if (!selectedOption) return;
|
|
7882
|
+
const sameTokenSelection = isSameChainSameTokenSelection(selectedOption, destination);
|
|
7883
|
+
if (!sameTokenSelection) {
|
|
7884
|
+
if (sessionsByFamily[selectedOption.chainFamily]) return;
|
|
7885
|
+
if (premintedFamiliesRef.current.has(selectedOption.chainFamily)) return;
|
|
7886
|
+
}
|
|
7887
|
+
const key = perTokenKey(selectedOption.chainId, selectedOption.tokenAddress);
|
|
7888
|
+
if (perTokenSessions[key]) return;
|
|
7889
|
+
if (inFlightPerTokenRef.current.has(key)) return;
|
|
7890
|
+
inFlightPerTokenRef.current.add(key);
|
|
7891
|
+
void createSession(selectedOption).finally(() => {
|
|
7892
|
+
inFlightPerTokenRef.current.delete(key);
|
|
7893
|
+
});
|
|
7894
|
+
}, [selectedOption, destination, sessionsByFamily, perTokenSessions, createSession]);
|
|
7895
|
+
const resetSessionForNewSelection = react.useCallback(() => {
|
|
7896
|
+
setError(null);
|
|
7897
|
+
}, []);
|
|
7898
|
+
const selectToken = react.useCallback((value) => {
|
|
7899
|
+
setSelectedToken(value);
|
|
7900
|
+
const pairValid = (sourceOptions ?? []).some(
|
|
7901
|
+
(opt) => opt.tokenSymbol === value && String(opt.chainId) === selectedChainId
|
|
7902
|
+
);
|
|
7903
|
+
if (!pairValid) {
|
|
7904
|
+
const firstChain = (sourceOptions ?? []).find(
|
|
7905
|
+
(opt) => opt.tokenSymbol === value
|
|
7906
|
+
);
|
|
7907
|
+
setSelectedChainId(
|
|
7908
|
+
firstChain ? String(firstChain.chainId) : ""
|
|
7909
|
+
);
|
|
7910
|
+
}
|
|
7911
|
+
}, [selectedChainId, sourceOptions]);
|
|
7912
|
+
const selectChainId = react.useCallback((value) => {
|
|
7913
|
+
setSelectedChainId(value);
|
|
7914
|
+
const pairValid = (sourceOptions ?? []).some(
|
|
7915
|
+
(opt) => opt.tokenSymbol === selectedToken && String(opt.chainId) === value
|
|
7916
|
+
);
|
|
7917
|
+
if (!pairValid) {
|
|
7918
|
+
const firstToken = (sourceOptions ?? []).find(
|
|
7919
|
+
(opt) => String(opt.chainId) === value
|
|
7920
|
+
);
|
|
7921
|
+
setSelectedToken(
|
|
7922
|
+
firstToken ? firstToken.tokenSymbol : ""
|
|
7923
|
+
);
|
|
7924
|
+
}
|
|
7925
|
+
}, [selectedToken, sourceOptions]);
|
|
7926
|
+
const screen = screenForSession(session);
|
|
7927
|
+
const copyDepositAddress = react.useCallback(async (address) => {
|
|
7928
|
+
try {
|
|
7929
|
+
await navigator.clipboard.writeText(address);
|
|
7930
|
+
} catch {
|
|
7931
|
+
const textarea = document.createElement("textarea");
|
|
7932
|
+
textarea.value = address;
|
|
7933
|
+
textarea.setAttribute("readonly", "");
|
|
7934
|
+
textarea.style.position = "absolute";
|
|
7935
|
+
textarea.style.opacity = "0";
|
|
7936
|
+
document.body.appendChild(textarea);
|
|
7937
|
+
textarea.select();
|
|
7938
|
+
try {
|
|
7939
|
+
document.execCommand("copy");
|
|
7940
|
+
} finally {
|
|
7941
|
+
document.body.removeChild(textarea);
|
|
7942
|
+
}
|
|
7943
|
+
}
|
|
7944
|
+
setCopiedAddress(address);
|
|
7945
|
+
window.setTimeout(() => setCopiedAddress((cur) => cur === address ? null : cur), 1500);
|
|
7946
|
+
}, []);
|
|
7947
|
+
const backToSourceSelector = react.useCallback(() => {
|
|
7948
|
+
setCopiedAddress(null);
|
|
7949
|
+
setError(null);
|
|
7950
|
+
if (!selectedOption) return;
|
|
7951
|
+
const family = selectedOption.chainFamily;
|
|
7952
|
+
setSessionsByFamily((prev) => {
|
|
7953
|
+
if (!prev[family]) return prev;
|
|
7954
|
+
const next = { ...prev };
|
|
7955
|
+
delete next[family];
|
|
7956
|
+
return next;
|
|
7957
|
+
});
|
|
7958
|
+
premintedFamiliesRef.current.delete(family);
|
|
7959
|
+
const ptKey = perTokenKey(selectedOption.chainId, selectedOption.tokenAddress);
|
|
7960
|
+
setPerTokenSessions((prev) => {
|
|
7961
|
+
if (!prev[ptKey]) return prev;
|
|
7962
|
+
const next = { ...prev };
|
|
7963
|
+
delete next[ptKey];
|
|
7964
|
+
return next;
|
|
7965
|
+
});
|
|
7966
|
+
}, [selectedOption]);
|
|
7585
7967
|
return {
|
|
7586
|
-
|
|
7587
|
-
|
|
7588
|
-
|
|
7589
|
-
|
|
7968
|
+
sourceOptions,
|
|
7969
|
+
loadingSources,
|
|
7970
|
+
selectedToken,
|
|
7971
|
+
selectedChainId,
|
|
7972
|
+
session,
|
|
7973
|
+
loading,
|
|
7974
|
+
error,
|
|
7975
|
+
qrReady,
|
|
7976
|
+
copiedAddress,
|
|
7977
|
+
tokenChoices,
|
|
7978
|
+
chainChoices,
|
|
7979
|
+
tokenLogoUriBySymbol,
|
|
7980
|
+
selectedOption,
|
|
7981
|
+
tokensForSelectedChain,
|
|
7982
|
+
chainsForSelectedToken,
|
|
7983
|
+
screen,
|
|
7984
|
+
sessionFeeCopy,
|
|
7985
|
+
depositAddress,
|
|
7986
|
+
createSession,
|
|
7987
|
+
copyDepositAddress,
|
|
7988
|
+
backToSourceSelector,
|
|
7989
|
+
resetSessionForNewSelection,
|
|
7990
|
+
selectToken,
|
|
7991
|
+
selectChainId
|
|
7590
7992
|
};
|
|
7591
7993
|
}
|
|
7592
|
-
|
|
7593
|
-
|
|
7594
|
-
|
|
7595
|
-
|
|
7596
|
-
|
|
7597
|
-
|
|
7598
|
-
|
|
7599
|
-
|
|
7600
|
-
|
|
7601
|
-
|
|
7602
|
-
|
|
7603
|
-
|
|
7604
|
-
|
|
7605
|
-
|
|
7606
|
-
|
|
7607
|
-
|
|
7608
|
-
|
|
7609
|
-
|
|
7610
|
-
|
|
7611
|
-
passkeyConfigLoaded: false,
|
|
7612
|
-
activeCredentialId: config.activeCredentialId,
|
|
7613
|
-
knownCredentialIds: [],
|
|
7614
|
-
oneTapLimit: DEFAULT_ONE_TAP_LIMIT,
|
|
7615
|
-
oneTapLimitSavedDuringSetup: false,
|
|
7616
|
-
mobileFlow: false,
|
|
7617
|
-
deeplinkUri: null,
|
|
7618
|
-
increasingLimit: false,
|
|
7619
|
-
activePublicKey: null,
|
|
7620
|
-
loginRequested: false,
|
|
7621
|
-
standardDesktopInlineOpenWallet: false,
|
|
7622
|
-
desktopWait: null,
|
|
7623
|
-
setupAuthorizationSessionId: null,
|
|
7624
|
-
mobileTokenAuthorizationPending: false,
|
|
7625
|
-
privyReady: false,
|
|
7626
|
-
privyAuthenticated: false,
|
|
7627
|
-
lastResumedAt: 0,
|
|
7628
|
-
setupDepositAmount: null,
|
|
7629
|
-
setupDepositToken: null,
|
|
7630
|
-
setupDepositConfirmed: false,
|
|
7631
|
-
guestWalletPrepared: null,
|
|
7632
|
-
guestWalletDeeplinksPreparing: false,
|
|
7633
|
-
amountTooLow: null,
|
|
7634
|
-
enableFullWidget: config.enableFullWidget ?? false,
|
|
7635
|
-
requireAmountEntry: config.depositAmount == null
|
|
7636
|
-
};
|
|
7994
|
+
var ManualTransferSessionContext = react.createContext(null);
|
|
7995
|
+
function ManualTransferSessionProvider({
|
|
7996
|
+
destination,
|
|
7997
|
+
merchantAuthorization,
|
|
7998
|
+
idempotencyKey,
|
|
7999
|
+
onComplete,
|
|
8000
|
+
onError,
|
|
8001
|
+
pollEnabled,
|
|
8002
|
+
children
|
|
8003
|
+
}) {
|
|
8004
|
+
const session = useManualTransferSession({
|
|
8005
|
+
destination,
|
|
8006
|
+
merchantAuthorization,
|
|
8007
|
+
idempotencyKey,
|
|
8008
|
+
onComplete,
|
|
8009
|
+
onError,
|
|
8010
|
+
pollEnabled
|
|
8011
|
+
});
|
|
8012
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ManualTransferSessionContext.Provider, { value: session, children });
|
|
7637
8013
|
}
|
|
7638
|
-
function
|
|
7639
|
-
|
|
7640
|
-
|
|
7641
|
-
|
|
7642
|
-
|
|
7643
|
-
|
|
7644
|
-
|
|
7645
|
-
|
|
7646
|
-
|
|
7647
|
-
|
|
7648
|
-
|
|
7649
|
-
|
|
7650
|
-
|
|
7651
|
-
|
|
7652
|
-
|
|
7653
|
-
|
|
7654
|
-
|
|
8014
|
+
function useManualTransferSessionContext() {
|
|
8015
|
+
const ctx = react.useContext(ManualTransferSessionContext);
|
|
8016
|
+
if (!ctx) {
|
|
8017
|
+
throw new Error(
|
|
8018
|
+
"useManualTransferSessionContext must be used within a <ManualTransferSessionProvider>"
|
|
8019
|
+
);
|
|
8020
|
+
}
|
|
8021
|
+
return ctx;
|
|
8022
|
+
}
|
|
8023
|
+
|
|
8024
|
+
// src/processingStatus.ts
|
|
8025
|
+
var PROCESSING_TIMEOUT_MS = 18e4;
|
|
8026
|
+
var TERMINAL_TRANSFER_STATUSES = /* @__PURE__ */ new Set(["COMPLETED", "FAILED", "EXPIRED"]);
|
|
8027
|
+
var SIGNABLE_TRANSFER_STATUSES = /* @__PURE__ */ new Set(["CREATED", "AUTHORIZED"]);
|
|
8028
|
+
function isTerminalTransferStatus(status) {
|
|
8029
|
+
return TERMINAL_TRANSFER_STATUSES.has(status);
|
|
8030
|
+
}
|
|
8031
|
+
function isTransferSignable(transfer) {
|
|
8032
|
+
return transfer != null && SIGNABLE_TRANSFER_STATUSES.has(transfer.status);
|
|
8033
|
+
}
|
|
8034
|
+
function isTransferAwaitingCompletion(transfer) {
|
|
8035
|
+
if (!transfer) return false;
|
|
8036
|
+
return !isTerminalTransferStatus(transfer.status);
|
|
8037
|
+
}
|
|
8038
|
+
function resolvePreferredTransfer(polledTransfer, localTransfer) {
|
|
8039
|
+
return polledTransfer ?? localTransfer;
|
|
8040
|
+
}
|
|
8041
|
+
function getTransferStatus(polledTransfer, localTransfer) {
|
|
8042
|
+
const transfer = resolvePreferredTransfer(polledTransfer, localTransfer);
|
|
8043
|
+
return transfer?.status ?? "UNKNOWN";
|
|
8044
|
+
}
|
|
8045
|
+
function hasProcessingTimedOut(processingStartedAtMs, nowMs) {
|
|
8046
|
+
if (!processingStartedAtMs) return false;
|
|
8047
|
+
return nowMs - processingStartedAtMs >= PROCESSING_TIMEOUT_MS;
|
|
8048
|
+
}
|
|
8049
|
+
var STATUS_DISPLAY_LABELS = {
|
|
8050
|
+
CREATED: "created",
|
|
8051
|
+
AUTHORIZED: "authorized",
|
|
8052
|
+
SENDING: "sending",
|
|
8053
|
+
SENT: "confirming delivery",
|
|
8054
|
+
COMPLETED: "completed",
|
|
8055
|
+
FAILED: "failed"
|
|
8056
|
+
};
|
|
8057
|
+
function getStatusDisplayLabel(status) {
|
|
8058
|
+
return STATUS_DISPLAY_LABELS[status] ?? status;
|
|
8059
|
+
}
|
|
8060
|
+
function buildProcessingTimeoutMessage(status) {
|
|
8061
|
+
const label = getStatusDisplayLabel(status);
|
|
8062
|
+
return `Payment is taking longer than expected (status: ${label}). Please try again.`;
|
|
8063
|
+
}
|
|
8064
|
+
|
|
8065
|
+
// src/paymentResolvePhase.ts
|
|
8066
|
+
function hasActiveWallet(accounts) {
|
|
8067
|
+
return accounts.some((a) => a.wallets.some((w) => w.status === "ACTIVE"));
|
|
8068
|
+
}
|
|
8069
|
+
function resolveTerminalPhase(state) {
|
|
8070
|
+
if (state.amountTooLow != null) {
|
|
8071
|
+
return {
|
|
8072
|
+
step: "amount-too-low",
|
|
8073
|
+
minAmountUsd: state.amountTooLow.minAmountUsd
|
|
8074
|
+
};
|
|
8075
|
+
}
|
|
8076
|
+
const transferCompleted = state.transfer?.status === "COMPLETED";
|
|
8077
|
+
const needsPasskeyBootstrap = state.privyAuthenticated && !state.activeCredentialId;
|
|
8078
|
+
if (transferCompleted && !needsPasskeyBootstrap && !state.loginRequested) {
|
|
8079
|
+
return { step: "completed", transfer: state.transfer };
|
|
8080
|
+
}
|
|
8081
|
+
if (state.transfer?.status === "FAILED") {
|
|
8082
|
+
return {
|
|
8083
|
+
step: "failed",
|
|
8084
|
+
transfer: state.transfer,
|
|
8085
|
+
error: state.error ?? "Transfer failed."
|
|
8086
|
+
};
|
|
8087
|
+
}
|
|
8088
|
+
if (state.creatingTransfer || isTransferAwaitingCompletion(state.transfer)) {
|
|
8089
|
+
return { step: "processing", transfer: state.transfer };
|
|
8090
|
+
}
|
|
8091
|
+
return null;
|
|
8092
|
+
}
|
|
8093
|
+
function resolveStickyPhase(state) {
|
|
8094
|
+
const currentPhase = state.phase;
|
|
8095
|
+
if (currentPhase.step === "manual-transfer" && !state.loginRequested) {
|
|
8096
|
+
return currentPhase;
|
|
8097
|
+
}
|
|
8098
|
+
if (currentPhase.step === "deposit-options" && !state.loginRequested && !state.privyAuthenticated) {
|
|
8099
|
+
return currentPhase;
|
|
8100
|
+
}
|
|
8101
|
+
if (!state.loginRequested && state.setupFlowScreen === "one-tap-setup") {
|
|
8102
|
+
return { step: "one-tap-setup", action: null };
|
|
8103
|
+
}
|
|
8104
|
+
if (!state.loginRequested && state.setupFlowScreen === "deposit-confirm" && state.selectedAccountId != null) {
|
|
8105
|
+
return {
|
|
8106
|
+
step: "wallet-setup",
|
|
8107
|
+
mobile: null,
|
|
8108
|
+
accountId: state.selectedAccountId
|
|
8109
|
+
};
|
|
8110
|
+
}
|
|
8111
|
+
if (!state.loginRequested && state.mobileTokenAuthorizationPending) {
|
|
8112
|
+
return {
|
|
8113
|
+
step: "wallet-setup",
|
|
8114
|
+
mobile: { deeplinkUri: "", providerId: state.selectedProviderId },
|
|
8115
|
+
accountId: null
|
|
8116
|
+
};
|
|
8117
|
+
}
|
|
8118
|
+
const isFundingSourceSubflow = !state.loginRequested && (currentPhase.step === "token-picker" || currentPhase.step === "guest-source-picker" || currentPhase.step === "select-source" || currentPhase.step === "confirm-sign");
|
|
8119
|
+
if (isFundingSourceSubflow) {
|
|
8120
|
+
return currentPhase;
|
|
8121
|
+
}
|
|
8122
|
+
if ((state.standardDesktopInlineOpenWallet || state.desktopWait != null) && state.privyAuthenticated && state.activeCredentialId != null && state.selectedAccountId != null && !state.loginRequested) {
|
|
8123
|
+
return {
|
|
8124
|
+
step: "wallet-setup",
|
|
8125
|
+
mobile: null,
|
|
8126
|
+
desktopWait: state.desktopWait,
|
|
8127
|
+
accountId: state.selectedAccountId
|
|
8128
|
+
};
|
|
8129
|
+
}
|
|
8130
|
+
if (state.mobileFlow && state.deeplinkUri != null) {
|
|
8131
|
+
return {
|
|
8132
|
+
step: "wallet-setup",
|
|
8133
|
+
mobile: { deeplinkUri: state.deeplinkUri, providerId: state.selectedProviderId },
|
|
8134
|
+
accountId: null
|
|
8135
|
+
};
|
|
8136
|
+
}
|
|
8137
|
+
if (currentPhase.step === "wallet-picker" && currentPhase.reason === "switch" && !state.creatingTransfer && !(state.mobileFlow && state.deeplinkUri)) {
|
|
8138
|
+
return currentPhase;
|
|
8139
|
+
}
|
|
8140
|
+
return null;
|
|
8141
|
+
}
|
|
8142
|
+
function deriveFreshPhase(state) {
|
|
8143
|
+
if (!state.privyReady) {
|
|
8144
|
+
return { step: "initializing" };
|
|
8145
|
+
}
|
|
8146
|
+
if (state.privyAuthenticated && !state.activeCredentialId && !state.passkeyConfigLoaded) {
|
|
8147
|
+
return { step: "initializing" };
|
|
8148
|
+
}
|
|
8149
|
+
if (state.loginRequested) {
|
|
8150
|
+
return { step: "login" };
|
|
8151
|
+
}
|
|
8152
|
+
if (state.enableFullWidget && !state.privyAuthenticated) {
|
|
8153
|
+
return { step: "deposit-options" };
|
|
8154
|
+
}
|
|
8155
|
+
if (!state.privyAuthenticated) {
|
|
8156
|
+
return { step: "login" };
|
|
8157
|
+
}
|
|
8158
|
+
if (state.loadingData && state.activeCredentialId != null) {
|
|
8159
|
+
return { step: "data-loading" };
|
|
8160
|
+
}
|
|
8161
|
+
if (state.requireAmountEntry) {
|
|
8162
|
+
return { step: "enter-amount" };
|
|
8163
|
+
}
|
|
8164
|
+
if (state.activeCredentialId != null && !hasActiveWallet(state.accounts) && !state.mobileFlow) {
|
|
8165
|
+
return { step: "wallet-picker", reason: "link" };
|
|
8166
|
+
}
|
|
8167
|
+
if (state.activeCredentialId != null && hasActiveWallet(state.accounts) && !state.loadingData) {
|
|
8168
|
+
return { step: "deposit" };
|
|
8169
|
+
}
|
|
8170
|
+
return { step: "wallet-picker", reason: "entry" };
|
|
8171
|
+
}
|
|
8172
|
+
function resolvePhase(state) {
|
|
8173
|
+
return resolveTerminalPhase(state) ?? resolveStickyPhase(state) ?? deriveFreshPhase(state);
|
|
8174
|
+
}
|
|
8175
|
+
|
|
8176
|
+
// src/paymentReducer.ts
|
|
8177
|
+
var DEFAULT_ONE_TAP_LIMIT = 1e4;
|
|
8178
|
+
function deriveSourceTypeAndId(state) {
|
|
8179
|
+
if (state.selectedWalletId) {
|
|
8180
|
+
return { sourceType: "walletId", sourceId: state.selectedWalletId };
|
|
8181
|
+
}
|
|
8182
|
+
if (state.selectedAccountId) {
|
|
8183
|
+
return { sourceType: "accountId", sourceId: state.selectedAccountId };
|
|
8184
|
+
}
|
|
8185
|
+
return { sourceType: "accountId", sourceId: "" };
|
|
8186
|
+
}
|
|
8187
|
+
function clearStaleSelection(state) {
|
|
8188
|
+
if (state.selectedAccountId == null) return state;
|
|
8189
|
+
if (state.desktopWait != null) return state;
|
|
8190
|
+
const stillExists = state.accounts.some((a) => a.id === state.selectedAccountId);
|
|
8191
|
+
if (stillExists) return state;
|
|
8192
|
+
return {
|
|
8193
|
+
...state,
|
|
8194
|
+
selectedAccountId: null,
|
|
8195
|
+
selectedWalletId: null,
|
|
8196
|
+
selectedTokenSymbol: null
|
|
8197
|
+
};
|
|
8198
|
+
}
|
|
8199
|
+
function createInitialState(config) {
|
|
8200
|
+
return {
|
|
8201
|
+
phase: config.initialPhase ?? { step: "initializing" },
|
|
8202
|
+
error: null,
|
|
8203
|
+
setupFlowScreen: null,
|
|
8204
|
+
providers: [],
|
|
8205
|
+
accounts: [],
|
|
8206
|
+
chains: [],
|
|
8207
|
+
loadingData: false,
|
|
8208
|
+
depositSelectionRefreshing: false,
|
|
8209
|
+
selectedProviderId: null,
|
|
8210
|
+
selectedAccountId: null,
|
|
8211
|
+
selectedWalletId: null,
|
|
8212
|
+
selectedTokenSymbol: null,
|
|
8213
|
+
savedSelection: null,
|
|
8214
|
+
amount: config.depositAmount != null ? config.depositAmount.toString() : "",
|
|
8215
|
+
transfer: null,
|
|
8216
|
+
pendingTransferId: null,
|
|
8217
|
+
creatingTransfer: false,
|
|
8218
|
+
passkeyConfigLoaded: false,
|
|
8219
|
+
activeCredentialId: config.activeCredentialId,
|
|
8220
|
+
knownCredentialIds: [],
|
|
8221
|
+
oneTapLimit: DEFAULT_ONE_TAP_LIMIT,
|
|
8222
|
+
oneTapLimitSavedDuringSetup: false,
|
|
8223
|
+
mobileFlow: false,
|
|
8224
|
+
deeplinkUri: null,
|
|
8225
|
+
increasingLimit: false,
|
|
8226
|
+
activePublicKey: null,
|
|
8227
|
+
loginRequested: false,
|
|
8228
|
+
standardDesktopInlineOpenWallet: false,
|
|
8229
|
+
desktopWait: null,
|
|
8230
|
+
setupAuthorizationSessionId: null,
|
|
8231
|
+
mobileTokenAuthorizationPending: false,
|
|
8232
|
+
privyReady: false,
|
|
8233
|
+
privyAuthenticated: false,
|
|
8234
|
+
lastResumedAt: 0,
|
|
8235
|
+
setupDepositAmount: null,
|
|
8236
|
+
setupDepositToken: null,
|
|
8237
|
+
setupDepositConfirmed: false,
|
|
8238
|
+
guestWalletPrepared: null,
|
|
8239
|
+
guestWalletDeeplinksPreparing: false,
|
|
8240
|
+
amountTooLow: null,
|
|
8241
|
+
enableFullWidget: config.enableFullWidget ?? false,
|
|
8242
|
+
requireAmountEntry: config.depositAmount == null
|
|
8243
|
+
};
|
|
8244
|
+
}
|
|
8245
|
+
function clearAuthenticatedSessionState(state) {
|
|
8246
|
+
return {
|
|
8247
|
+
...state,
|
|
8248
|
+
error: null,
|
|
8249
|
+
setupFlowScreen: null,
|
|
8250
|
+
providers: [],
|
|
8251
|
+
accounts: [],
|
|
8252
|
+
chains: [],
|
|
8253
|
+
loadingData: false,
|
|
8254
|
+
depositSelectionRefreshing: false,
|
|
8255
|
+
selectedProviderId: null,
|
|
8256
|
+
selectedAccountId: null,
|
|
8257
|
+
selectedWalletId: null,
|
|
8258
|
+
selectedTokenSymbol: null,
|
|
8259
|
+
savedSelection: null,
|
|
8260
|
+
transfer: null,
|
|
8261
|
+
pendingTransferId: null,
|
|
7655
8262
|
creatingTransfer: false,
|
|
7656
8263
|
passkeyConfigLoaded: false,
|
|
7657
8264
|
activeCredentialId: null,
|
|
@@ -8095,552 +8702,118 @@ function applyAction(state, action) {
|
|
|
8095
8702
|
// unauthenticated path) preserves the flag implicitly via the
|
|
8096
8703
|
// surrounding `...state` spread, so no change is needed there.
|
|
8097
8704
|
enableFullWidget: state.enableFullWidget
|
|
8098
|
-
};
|
|
8099
|
-
case "SYNC_PRIVY_SESSION":
|
|
8100
|
-
if (action.ready && !action.authenticated) {
|
|
8101
|
-
return {
|
|
8102
|
-
...clearAuthenticatedSessionState(state),
|
|
8103
|
-
privyReady: true,
|
|
8104
|
-
privyAuthenticated: false
|
|
8105
|
-
};
|
|
8106
|
-
}
|
|
8107
|
-
return {
|
|
8108
|
-
...state,
|
|
8109
|
-
privyReady: action.ready,
|
|
8110
|
-
privyAuthenticated: action.authenticated,
|
|
8111
|
-
...action.authenticated ? { loginRequested: false } : {}
|
|
8112
|
-
};
|
|
8113
|
-
case "SYNC_AMOUNT":
|
|
8114
|
-
return {
|
|
8115
|
-
...state,
|
|
8116
|
-
amount: action.amount,
|
|
8117
|
-
requireAmountEntry: action.amount === "" ? state.requireAmountEntry : false
|
|
8118
|
-
};
|
|
8119
|
-
case "SET_AMOUNT_INPUT":
|
|
8120
|
-
return { ...state, amount: action.value };
|
|
8121
|
-
case "FINALIZE_AMOUNT":
|
|
8122
|
-
return { ...state, requireAmountEntry: false };
|
|
8123
|
-
case "PAGE_RESUMED":
|
|
8124
|
-
return { ...state, lastResumedAt: Date.now() };
|
|
8125
|
-
// ── Setup deposit (combined first-time flow) ────────────────
|
|
8126
|
-
case "SET_SETUP_DEPOSIT_AMOUNT":
|
|
8127
|
-
return { ...state, setupDepositAmount: action.amount };
|
|
8128
|
-
case "SET_SETUP_DEPOSIT_TOKEN":
|
|
8129
|
-
return {
|
|
8130
|
-
...state,
|
|
8131
|
-
setupDepositToken: {
|
|
8132
|
-
symbol: action.symbol,
|
|
8133
|
-
chainName: action.chainName,
|
|
8134
|
-
...action.walletId ? { walletId: action.walletId } : {},
|
|
8135
|
-
...action.tokenAddress ? { tokenAddress: action.tokenAddress } : {},
|
|
8136
|
-
...action.chainId != null ? { chainId: action.chainId } : {}
|
|
8137
|
-
}
|
|
8138
|
-
};
|
|
8139
|
-
case "CLEAR_SETUP_DEPOSIT_TOKEN":
|
|
8140
|
-
return { ...state, setupDepositToken: null };
|
|
8141
|
-
case "CONFIRM_SETUP_DEPOSIT":
|
|
8142
|
-
return { ...state, setupDepositConfirmed: true };
|
|
8143
|
-
default:
|
|
8144
|
-
return state;
|
|
8145
|
-
}
|
|
8146
|
-
}
|
|
8147
|
-
|
|
8148
|
-
// src/setupDepositConfirmation.ts
|
|
8149
|
-
function deriveEffectiveSetupSource(setupDepositToken, setupSelectedSourceOption) {
|
|
8150
|
-
if (setupDepositToken) return setupDepositToken;
|
|
8151
|
-
if (setupSelectedSourceOption) {
|
|
8152
|
-
return {
|
|
8153
|
-
symbol: setupSelectedSourceOption.tokenSymbol,
|
|
8154
|
-
chainName: setupSelectedSourceOption.chainName,
|
|
8155
|
-
walletId: setupSelectedSourceOption.walletId,
|
|
8156
|
-
tokenAddress: setupSelectedSourceOption.tokenAddress,
|
|
8157
|
-
chainId: setupSelectedSourceOption.chainId != null ? Number(setupSelectedSourceOption.chainId) : void 0
|
|
8158
|
-
};
|
|
8159
|
-
}
|
|
8160
|
-
return null;
|
|
8161
|
-
}
|
|
8162
|
-
function planConfirmSetupDeposit(input) {
|
|
8163
|
-
const effective = deriveEffectiveSetupSource(
|
|
8164
|
-
input.setupDepositToken,
|
|
8165
|
-
input.setupSelectedSourceOption
|
|
8166
|
-
);
|
|
8167
|
-
if (!effective) {
|
|
8168
|
-
return { kind: "error", error: "Select a source token before continuing." };
|
|
8169
|
-
}
|
|
8170
|
-
if (!effective.walletId) {
|
|
8171
|
-
return {
|
|
8172
|
-
kind: "error",
|
|
8173
|
-
error: "Selected source is not ready yet. Wait for wallet discovery to finish."
|
|
8174
|
-
};
|
|
8175
|
-
}
|
|
8176
|
-
const actions = [
|
|
8177
|
-
{ type: "SET_ERROR", error: null },
|
|
8178
|
-
{
|
|
8179
|
-
type: "SET_SETUP_DEPOSIT_TOKEN",
|
|
8180
|
-
symbol: effective.symbol,
|
|
8181
|
-
chainName: effective.chainName,
|
|
8182
|
-
walletId: effective.walletId,
|
|
8183
|
-
tokenAddress: effective.tokenAddress,
|
|
8184
|
-
chainId: effective.chainId
|
|
8185
|
-
}
|
|
8186
|
-
];
|
|
8187
|
-
if (input.selectedAccountId) {
|
|
8188
|
-
actions.push({
|
|
8189
|
-
type: "SELECT_ACCOUNT",
|
|
8190
|
-
accountId: input.selectedAccountId,
|
|
8191
|
-
walletId: effective.walletId
|
|
8192
|
-
});
|
|
8193
|
-
actions.push({
|
|
8194
|
-
type: "SELECT_TOKEN",
|
|
8195
|
-
walletId: effective.walletId,
|
|
8196
|
-
tokenSymbol: effective.symbol
|
|
8197
|
-
});
|
|
8198
|
-
}
|
|
8199
|
-
actions.push({ type: "SET_SETUP_FLOW_SCREEN", screen: "one-tap-setup" });
|
|
8200
|
-
actions.push({ type: "CONFIRM_SETUP_DEPOSIT" });
|
|
8201
|
-
return {
|
|
8202
|
-
kind: "proceed",
|
|
8203
|
-
actions,
|
|
8204
|
-
resolveSource: {
|
|
8205
|
-
chainName: effective.chainName,
|
|
8206
|
-
tokenSymbol: effective.symbol
|
|
8207
|
-
}
|
|
8208
|
-
};
|
|
8209
|
-
}
|
|
8210
|
-
|
|
8211
|
-
// src/manualTransferUtils.ts
|
|
8212
|
-
function screenForSession(session) {
|
|
8213
|
-
if (!session) return "source-selector";
|
|
8214
|
-
switch (session.status) {
|
|
8215
|
-
case "awaiting_deposit":
|
|
8216
|
-
return "awaiting-deposit";
|
|
8217
|
-
case "deposit_received":
|
|
8218
|
-
return "deposit-received";
|
|
8219
|
-
case "routing":
|
|
8220
|
-
return "deposit-routing";
|
|
8221
|
-
case "completed":
|
|
8222
|
-
return "deposit-complete";
|
|
8223
|
-
case "refunded":
|
|
8224
|
-
case "failed":
|
|
8225
|
-
case "wrong_token":
|
|
8226
|
-
return "deposit-failed";
|
|
8227
|
-
}
|
|
8228
|
-
}
|
|
8229
|
-
function feeCopy(_session) {
|
|
8230
|
-
return "No fees";
|
|
8231
|
-
}
|
|
8232
|
-
function toTransfer(session) {
|
|
8233
|
-
return {
|
|
8234
|
-
id: session.sessionId,
|
|
8235
|
-
status: session.status,
|
|
8236
|
-
amount: {
|
|
8237
|
-
amount: Number(session.deliveredAmountUsd ?? session.minAmountUsd),
|
|
8238
|
-
currency: "USD"
|
|
8239
|
-
},
|
|
8240
|
-
sources: [],
|
|
8241
|
-
destinations: [{
|
|
8242
|
-
id: session.sessionId,
|
|
8243
|
-
chainId: session.destination.chainId,
|
|
8244
|
-
address: session.destination.address,
|
|
8245
|
-
token: { address: session.destination.token.address, symbol: "" },
|
|
8246
|
-
amount: { amount: Number(session.deliveredAmountUsd ?? session.minAmountUsd), currency: "USD" }
|
|
8247
|
-
}],
|
|
8248
|
-
createDate: session.createDate,
|
|
8249
|
-
updateDate: session.updateDate
|
|
8250
|
-
};
|
|
8251
|
-
}
|
|
8252
|
-
var SOLANA_CHAIN_ID = 792703809;
|
|
8253
|
-
var SOLANA_NATIVE_SOL_ADDRESS = "11111111111111111111111111111111";
|
|
8254
|
-
function formatDepositUri(address, chainId, depToken) {
|
|
8255
|
-
if (chainId === SOLANA_CHAIN_ID) {
|
|
8256
|
-
if (!depToken || depToken === SOLANA_NATIVE_SOL_ADDRESS) {
|
|
8257
|
-
return `solana:${address}`;
|
|
8258
|
-
}
|
|
8259
|
-
return `solana:${address}?spl-token=${depToken}`;
|
|
8260
|
-
}
|
|
8261
|
-
return address;
|
|
8262
|
-
}
|
|
8263
|
-
|
|
8264
|
-
// src/hooks/useManualTransferSession.ts
|
|
8265
|
-
function useManualTransferSession({
|
|
8266
|
-
destination,
|
|
8267
|
-
merchantAuthorization,
|
|
8268
|
-
idempotencyKey,
|
|
8269
|
-
mock = false,
|
|
8270
|
-
onComplete,
|
|
8271
|
-
onError
|
|
8272
|
-
}) {
|
|
8273
|
-
const { apiBaseUrl } = useBlinkConfig();
|
|
8274
|
-
const [sourceOptions, setSourceOptions] = react.useState(null);
|
|
8275
|
-
const [loadingSources, setLoadingSources] = react.useState(true);
|
|
8276
|
-
const [selectedToken, setSelectedToken] = react.useState("");
|
|
8277
|
-
const [selectedChainId, setSelectedChainId] = react.useState("");
|
|
8278
|
-
const [session, setSession] = react.useState(null);
|
|
8279
|
-
const [loading, setLoading] = react.useState(false);
|
|
8280
|
-
const [error, setError] = react.useState(null);
|
|
8281
|
-
const [qrReady, setQrReady] = react.useState(false);
|
|
8282
|
-
const [copiedAddress, setCopiedAddress] = react.useState(null);
|
|
8283
|
-
const completedRef = react.useRef(null);
|
|
8284
|
-
const lastCreatedOptionRef = react.useRef(null);
|
|
8285
|
-
react.useEffect(() => {
|
|
8286
|
-
if (!merchantAuthorization) return;
|
|
8287
|
-
let cancelled = false;
|
|
8288
|
-
setLoadingSources(true);
|
|
8289
|
-
fetchManualTransferSources(apiBaseUrl, { merchantAuthorization, destination }).then((sources) => {
|
|
8290
|
-
if (!cancelled) {
|
|
8291
|
-
setSourceOptions(sources);
|
|
8292
|
-
setLoadingSources(false);
|
|
8293
|
-
const defaultOption = sources.find(
|
|
8294
|
-
(opt) => opt.tokenSymbol === "USDC" && opt.chainId === 792703809
|
|
8295
|
-
);
|
|
8296
|
-
if (defaultOption) {
|
|
8297
|
-
setSelectedToken("USDC");
|
|
8298
|
-
setSelectedChainId("792703809");
|
|
8299
|
-
}
|
|
8300
|
-
}
|
|
8301
|
-
}).catch((err) => {
|
|
8302
|
-
if (!cancelled) {
|
|
8303
|
-
setError(err instanceof Error ? err.message : String(err));
|
|
8304
|
-
setLoadingSources(false);
|
|
8305
|
-
}
|
|
8306
|
-
});
|
|
8307
|
-
return () => {
|
|
8308
|
-
cancelled = true;
|
|
8309
|
-
};
|
|
8310
|
-
}, [apiBaseUrl, destination, merchantAuthorization]);
|
|
8311
|
-
const depositAddress = session?.depositAddress;
|
|
8312
|
-
react.useEffect(() => {
|
|
8313
|
-
if (!depositAddress) {
|
|
8314
|
-
setQrReady(false);
|
|
8315
|
-
return;
|
|
8316
|
-
}
|
|
8317
|
-
const timer = window.setTimeout(() => setQrReady(true), 1200);
|
|
8318
|
-
return () => window.clearTimeout(timer);
|
|
8319
|
-
}, [depositAddress]);
|
|
8320
|
-
const lastFeeCopyRef = react.useRef(null);
|
|
8321
|
-
const nextFeeCopy = session ? feeCopy() : null;
|
|
8322
|
-
const sessionFeeCopy = nextFeeCopy === lastFeeCopyRef.current ? lastFeeCopyRef.current : lastFeeCopyRef.current = nextFeeCopy;
|
|
8323
|
-
const advanceMockStatus = react.useCallback((status) => {
|
|
8324
|
-
setSession((prev) => prev ? { ...prev, status } : prev);
|
|
8325
|
-
}, []);
|
|
8326
|
-
react.useEffect(() => {
|
|
8327
|
-
if (mock) return;
|
|
8328
|
-
if (!session?.sessionId || ["completed", "failed", "refunded", "wrong_token"].includes(session.status)) return;
|
|
8329
|
-
const timer = window.setInterval(() => {
|
|
8330
|
-
fetchManualTransferSession(apiBaseUrl, session.sessionId).then(setSession).catch((err) => setError(err instanceof Error ? err.message : String(err)));
|
|
8331
|
-
}, 2e3);
|
|
8332
|
-
return () => window.clearInterval(timer);
|
|
8333
|
-
}, [apiBaseUrl, mock, session?.sessionId, session?.status]);
|
|
8334
|
-
react.useEffect(() => {
|
|
8335
|
-
if (mock) return;
|
|
8336
|
-
if (!session?.sessionId || session.status !== "awaiting_deposit") return;
|
|
8337
|
-
const sessionId = session.sessionId;
|
|
8338
|
-
const timer = window.setInterval(() => {
|
|
8339
|
-
refreshManualTransferQuote(apiBaseUrl, sessionId).then(({ quoteValidUntil, minAmountUsd, slippage }) => {
|
|
8340
|
-
setSession(
|
|
8341
|
-
(prev) => prev && prev.sessionId === sessionId ? { ...prev, quoteValidUntil, minAmountUsd, slippage } : prev
|
|
8342
|
-
);
|
|
8343
|
-
}).catch((err) => {
|
|
8344
|
-
console.warn("[manual-transfer] refresh quote failed", err);
|
|
8345
|
-
});
|
|
8346
|
-
}, 1e4);
|
|
8347
|
-
return () => window.clearInterval(timer);
|
|
8348
|
-
}, [apiBaseUrl, mock, session?.sessionId, session?.status]);
|
|
8349
|
-
react.useEffect(() => {
|
|
8350
|
-
if (session?.status !== "completed") return;
|
|
8351
|
-
if (completedRef.current === session.sessionId) return;
|
|
8352
|
-
completedRef.current = session.sessionId;
|
|
8353
|
-
onComplete?.(toTransfer(session));
|
|
8354
|
-
}, [onComplete, session]);
|
|
8355
|
-
react.useEffect(() => {
|
|
8356
|
-
if (!error) return;
|
|
8357
|
-
onError?.(error);
|
|
8358
|
-
}, [error, onError]);
|
|
8359
|
-
const tokenChoices = react.useMemo(
|
|
8360
|
-
() => Array.from(new Set((sourceOptions ?? []).map((opt) => opt.tokenSymbol))),
|
|
8361
|
-
[sourceOptions]
|
|
8362
|
-
);
|
|
8363
|
-
const chainChoices = react.useMemo(() => {
|
|
8364
|
-
const seen = /* @__PURE__ */ new Set();
|
|
8365
|
-
return (sourceOptions ?? []).filter((opt) => {
|
|
8366
|
-
if (seen.has(opt.chainId)) return false;
|
|
8367
|
-
seen.add(opt.chainId);
|
|
8368
|
-
return true;
|
|
8369
|
-
});
|
|
8370
|
-
}, [sourceOptions]);
|
|
8371
|
-
const tokenLogoUriBySymbol = react.useMemo(() => {
|
|
8372
|
-
const out = {};
|
|
8373
|
-
for (const opt of sourceOptions ?? []) {
|
|
8374
|
-
if (out[opt.tokenSymbol] == null) {
|
|
8375
|
-
out[opt.tokenSymbol] = opt.tokenLogoUri;
|
|
8376
|
-
}
|
|
8377
|
-
}
|
|
8378
|
-
return out;
|
|
8379
|
-
}, [sourceOptions]);
|
|
8380
|
-
const selectedOption = react.useMemo(
|
|
8381
|
-
() => (sourceOptions ?? []).find(
|
|
8382
|
-
(opt) => opt.tokenSymbol === selectedToken && String(opt.chainId) === selectedChainId
|
|
8383
|
-
) ?? null,
|
|
8384
|
-
[sourceOptions, selectedToken, selectedChainId]
|
|
8385
|
-
);
|
|
8386
|
-
const tokensForSelectedChain = react.useMemo(() => {
|
|
8387
|
-
if (!selectedChainId) return null;
|
|
8388
|
-
return new Set(
|
|
8389
|
-
(sourceOptions ?? []).filter((opt) => String(opt.chainId) === selectedChainId).map((opt) => opt.tokenSymbol)
|
|
8390
|
-
);
|
|
8391
|
-
}, [sourceOptions, selectedChainId]);
|
|
8392
|
-
const chainsForSelectedToken = react.useMemo(() => {
|
|
8393
|
-
if (!selectedToken) return null;
|
|
8394
|
-
return new Set(
|
|
8395
|
-
(sourceOptions ?? []).filter((opt) => opt.tokenSymbol === selectedToken).map((opt) => opt.chainId)
|
|
8396
|
-
);
|
|
8397
|
-
}, [sourceOptions, selectedToken]);
|
|
8398
|
-
const createSession = react.useCallback(async (option) => {
|
|
8399
|
-
if (!merchantAuthorization) return;
|
|
8400
|
-
setLoading(true);
|
|
8401
|
-
setError(null);
|
|
8402
|
-
try {
|
|
8403
|
-
if (mock) {
|
|
8404
|
-
const mockSession = {
|
|
8405
|
-
sessionId: `mock-${Date.now()}`,
|
|
8406
|
-
idempotencyKey: idempotencyKey ?? `mock-idem-${Date.now()}`,
|
|
8407
|
-
merchantId: "mock-merchant",
|
|
8408
|
-
destination,
|
|
8409
|
-
source: {
|
|
8410
|
-
chainId: option.chainId,
|
|
8411
|
-
tokenAddress: option.tokenAddress,
|
|
8412
|
-
tokenSymbol: option.tokenSymbol
|
|
8413
|
-
},
|
|
8414
|
-
refundTo: null,
|
|
8415
|
-
depositAddress: "0x" + "a1b2c3d4e5f6".repeat(3).slice(0, 40),
|
|
8416
|
-
requestId: `mock-req-${Date.now()}`,
|
|
8417
|
-
status: "awaiting_deposit",
|
|
8418
|
-
minAmountUsd: option.minAmountUsd,
|
|
8419
|
-
quoteValidUntil: new Date(Date.now() + 36e5).toISOString(),
|
|
8420
|
-
depositTxHashes: [],
|
|
8421
|
-
destinationTxHash: null,
|
|
8422
|
-
refundTxHashes: [],
|
|
8423
|
-
deliveredAmountUsd: null,
|
|
8424
|
-
errorCode: null,
|
|
8425
|
-
errorMessage: null,
|
|
8426
|
-
slippage: null,
|
|
8427
|
-
createDate: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8428
|
-
updateDate: (/* @__PURE__ */ new Date()).toISOString()
|
|
8429
|
-
};
|
|
8430
|
-
setSession(mockSession);
|
|
8431
|
-
} else {
|
|
8432
|
-
const created = await createManualTransfer(apiBaseUrl, {
|
|
8433
|
-
merchantAuthorization,
|
|
8434
|
-
destination,
|
|
8435
|
-
idempotencyKey,
|
|
8436
|
-
source: {
|
|
8437
|
-
chainId: option.chainId,
|
|
8438
|
-
tokenAddress: option.tokenAddress
|
|
8439
|
-
}
|
|
8440
|
-
});
|
|
8441
|
-
setSession(created);
|
|
8442
|
-
}
|
|
8443
|
-
} catch (err) {
|
|
8444
|
-
setError(err instanceof Error ? err.message : String(err));
|
|
8445
|
-
} finally {
|
|
8446
|
-
setLoading(false);
|
|
8447
|
-
}
|
|
8448
|
-
}, [apiBaseUrl, destination, idempotencyKey, merchantAuthorization, mock]);
|
|
8449
|
-
const resetSessionForNewSelection = react.useCallback(() => {
|
|
8450
|
-
setSession(null);
|
|
8451
|
-
lastCreatedOptionRef.current = null;
|
|
8452
|
-
}, []);
|
|
8453
|
-
const selectToken = react.useCallback((value) => {
|
|
8454
|
-
setSelectedToken(value);
|
|
8455
|
-
resetSessionForNewSelection();
|
|
8456
|
-
const pairValid = (sourceOptions ?? []).some(
|
|
8457
|
-
(opt) => opt.tokenSymbol === value && String(opt.chainId) === selectedChainId
|
|
8458
|
-
);
|
|
8459
|
-
if (!pairValid) {
|
|
8460
|
-
const firstChain = (sourceOptions ?? []).find(
|
|
8461
|
-
(opt) => opt.tokenSymbol === value
|
|
8462
|
-
);
|
|
8463
|
-
setSelectedChainId(
|
|
8464
|
-
firstChain ? String(firstChain.chainId) : ""
|
|
8465
|
-
);
|
|
8466
|
-
}
|
|
8467
|
-
}, [resetSessionForNewSelection, selectedChainId, sourceOptions]);
|
|
8468
|
-
const selectChainId = react.useCallback((value) => {
|
|
8469
|
-
setSelectedChainId(value);
|
|
8470
|
-
resetSessionForNewSelection();
|
|
8471
|
-
const pairValid = (sourceOptions ?? []).some(
|
|
8472
|
-
(opt) => opt.tokenSymbol === selectedToken && String(opt.chainId) === value
|
|
8473
|
-
);
|
|
8474
|
-
if (!pairValid) {
|
|
8475
|
-
const firstToken = (sourceOptions ?? []).find(
|
|
8476
|
-
(opt) => String(opt.chainId) === value
|
|
8477
|
-
);
|
|
8478
|
-
setSelectedToken(
|
|
8479
|
-
firstToken ? firstToken.tokenSymbol : ""
|
|
8480
|
-
);
|
|
8481
|
-
}
|
|
8482
|
-
}, [resetSessionForNewSelection, selectedToken, sourceOptions]);
|
|
8483
|
-
react.useEffect(() => {
|
|
8484
|
-
if (!selectedOption) return;
|
|
8485
|
-
const optionKey = `${selectedOption.chainId}:${selectedOption.tokenAddress}`;
|
|
8486
|
-
if (lastCreatedOptionRef.current === optionKey) return;
|
|
8487
|
-
lastCreatedOptionRef.current = optionKey;
|
|
8488
|
-
void createSession(selectedOption);
|
|
8489
|
-
}, [selectedOption, createSession]);
|
|
8490
|
-
const screen = screenForSession(session);
|
|
8491
|
-
const copyDepositAddress = react.useCallback(async (address) => {
|
|
8492
|
-
try {
|
|
8493
|
-
await navigator.clipboard.writeText(address);
|
|
8494
|
-
} catch {
|
|
8495
|
-
const textarea = document.createElement("textarea");
|
|
8496
|
-
textarea.value = address;
|
|
8497
|
-
textarea.setAttribute("readonly", "");
|
|
8498
|
-
textarea.style.position = "absolute";
|
|
8499
|
-
textarea.style.opacity = "0";
|
|
8500
|
-
document.body.appendChild(textarea);
|
|
8501
|
-
textarea.select();
|
|
8502
|
-
try {
|
|
8503
|
-
document.execCommand("copy");
|
|
8504
|
-
} finally {
|
|
8505
|
-
document.body.removeChild(textarea);
|
|
8705
|
+
};
|
|
8706
|
+
case "SYNC_PRIVY_SESSION":
|
|
8707
|
+
if (action.ready && !action.authenticated) {
|
|
8708
|
+
return {
|
|
8709
|
+
...clearAuthenticatedSessionState(state),
|
|
8710
|
+
privyReady: true,
|
|
8711
|
+
privyAuthenticated: false
|
|
8712
|
+
};
|
|
8506
8713
|
}
|
|
8714
|
+
return {
|
|
8715
|
+
...state,
|
|
8716
|
+
privyReady: action.ready,
|
|
8717
|
+
privyAuthenticated: action.authenticated,
|
|
8718
|
+
...action.authenticated ? { loginRequested: false } : {}
|
|
8719
|
+
};
|
|
8720
|
+
case "SYNC_AMOUNT":
|
|
8721
|
+
return {
|
|
8722
|
+
...state,
|
|
8723
|
+
amount: action.amount,
|
|
8724
|
+
requireAmountEntry: action.amount === "" ? state.requireAmountEntry : false
|
|
8725
|
+
};
|
|
8726
|
+
case "SET_AMOUNT_INPUT":
|
|
8727
|
+
return { ...state, amount: action.value };
|
|
8728
|
+
case "FINALIZE_AMOUNT":
|
|
8729
|
+
return { ...state, requireAmountEntry: false };
|
|
8730
|
+
case "PAGE_RESUMED":
|
|
8731
|
+
return { ...state, lastResumedAt: Date.now() };
|
|
8732
|
+
// ── Setup deposit (combined first-time flow) ────────────────
|
|
8733
|
+
case "SET_SETUP_DEPOSIT_AMOUNT":
|
|
8734
|
+
return { ...state, setupDepositAmount: action.amount };
|
|
8735
|
+
case "SET_SETUP_DEPOSIT_TOKEN":
|
|
8736
|
+
return {
|
|
8737
|
+
...state,
|
|
8738
|
+
setupDepositToken: {
|
|
8739
|
+
symbol: action.symbol,
|
|
8740
|
+
chainName: action.chainName,
|
|
8741
|
+
...action.walletId ? { walletId: action.walletId } : {},
|
|
8742
|
+
...action.tokenAddress ? { tokenAddress: action.tokenAddress } : {},
|
|
8743
|
+
...action.chainId != null ? { chainId: action.chainId } : {}
|
|
8744
|
+
}
|
|
8745
|
+
};
|
|
8746
|
+
case "CLEAR_SETUP_DEPOSIT_TOKEN":
|
|
8747
|
+
return { ...state, setupDepositToken: null };
|
|
8748
|
+
case "CONFIRM_SETUP_DEPOSIT":
|
|
8749
|
+
return { ...state, setupDepositConfirmed: true };
|
|
8750
|
+
default:
|
|
8751
|
+
return state;
|
|
8752
|
+
}
|
|
8753
|
+
}
|
|
8754
|
+
|
|
8755
|
+
// src/setupDepositConfirmation.ts
|
|
8756
|
+
function deriveEffectiveSetupSource(setupDepositToken, setupSelectedSourceOption) {
|
|
8757
|
+
if (setupDepositToken) return setupDepositToken;
|
|
8758
|
+
if (setupSelectedSourceOption) {
|
|
8759
|
+
return {
|
|
8760
|
+
symbol: setupSelectedSourceOption.tokenSymbol,
|
|
8761
|
+
chainName: setupSelectedSourceOption.chainName,
|
|
8762
|
+
walletId: setupSelectedSourceOption.walletId,
|
|
8763
|
+
tokenAddress: setupSelectedSourceOption.tokenAddress,
|
|
8764
|
+
chainId: setupSelectedSourceOption.chainId != null ? Number(setupSelectedSourceOption.chainId) : void 0
|
|
8765
|
+
};
|
|
8766
|
+
}
|
|
8767
|
+
return null;
|
|
8768
|
+
}
|
|
8769
|
+
function planConfirmSetupDeposit(input) {
|
|
8770
|
+
const effective = deriveEffectiveSetupSource(
|
|
8771
|
+
input.setupDepositToken,
|
|
8772
|
+
input.setupSelectedSourceOption
|
|
8773
|
+
);
|
|
8774
|
+
if (!effective) {
|
|
8775
|
+
return { kind: "error", error: "Select a source token before continuing." };
|
|
8776
|
+
}
|
|
8777
|
+
if (!effective.walletId) {
|
|
8778
|
+
return {
|
|
8779
|
+
kind: "error",
|
|
8780
|
+
error: "Selected source is not ready yet. Wait for wallet discovery to finish."
|
|
8781
|
+
};
|
|
8782
|
+
}
|
|
8783
|
+
const actions = [
|
|
8784
|
+
{ type: "SET_ERROR", error: null },
|
|
8785
|
+
{
|
|
8786
|
+
type: "SET_SETUP_DEPOSIT_TOKEN",
|
|
8787
|
+
symbol: effective.symbol,
|
|
8788
|
+
chainName: effective.chainName,
|
|
8789
|
+
walletId: effective.walletId,
|
|
8790
|
+
tokenAddress: effective.tokenAddress,
|
|
8791
|
+
chainId: effective.chainId
|
|
8507
8792
|
}
|
|
8508
|
-
|
|
8509
|
-
|
|
8510
|
-
|
|
8511
|
-
|
|
8512
|
-
|
|
8513
|
-
|
|
8514
|
-
|
|
8515
|
-
|
|
8516
|
-
|
|
8517
|
-
|
|
8518
|
-
|
|
8519
|
-
|
|
8793
|
+
];
|
|
8794
|
+
if (input.selectedAccountId) {
|
|
8795
|
+
actions.push({
|
|
8796
|
+
type: "SELECT_ACCOUNT",
|
|
8797
|
+
accountId: input.selectedAccountId,
|
|
8798
|
+
walletId: effective.walletId
|
|
8799
|
+
});
|
|
8800
|
+
actions.push({
|
|
8801
|
+
type: "SELECT_TOKEN",
|
|
8802
|
+
walletId: effective.walletId,
|
|
8803
|
+
tokenSymbol: effective.symbol
|
|
8804
|
+
});
|
|
8805
|
+
}
|
|
8806
|
+
actions.push({ type: "SET_SETUP_FLOW_SCREEN", screen: "one-tap-setup" });
|
|
8807
|
+
actions.push({ type: "CONFIRM_SETUP_DEPOSIT" });
|
|
8520
8808
|
return {
|
|
8521
|
-
|
|
8522
|
-
|
|
8523
|
-
|
|
8524
|
-
|
|
8525
|
-
|
|
8526
|
-
|
|
8527
|
-
error,
|
|
8528
|
-
qrReady,
|
|
8529
|
-
copiedAddress,
|
|
8530
|
-
tokenChoices,
|
|
8531
|
-
chainChoices,
|
|
8532
|
-
tokenLogoUriBySymbol,
|
|
8533
|
-
selectedOption,
|
|
8534
|
-
tokensForSelectedChain,
|
|
8535
|
-
chainsForSelectedToken,
|
|
8536
|
-
screen,
|
|
8537
|
-
sessionFeeCopy,
|
|
8538
|
-
depositAddress,
|
|
8539
|
-
createSession,
|
|
8540
|
-
copyDepositAddress,
|
|
8541
|
-
backToSourceSelector,
|
|
8542
|
-
resetSessionForNewSelection,
|
|
8543
|
-
advanceMockStatus,
|
|
8544
|
-
selectToken,
|
|
8545
|
-
selectChainId
|
|
8809
|
+
kind: "proceed",
|
|
8810
|
+
actions,
|
|
8811
|
+
resolveSource: {
|
|
8812
|
+
chainName: effective.chainName,
|
|
8813
|
+
tokenSymbol: effective.symbol
|
|
8814
|
+
}
|
|
8546
8815
|
};
|
|
8547
8816
|
}
|
|
8548
|
-
var MOCK_STATUSES = [
|
|
8549
|
-
"awaiting_deposit",
|
|
8550
|
-
"deposit_received",
|
|
8551
|
-
"routing",
|
|
8552
|
-
"completed",
|
|
8553
|
-
"failed"
|
|
8554
|
-
];
|
|
8555
|
-
function DevMockPanel({
|
|
8556
|
-
status,
|
|
8557
|
-
onSetStatus,
|
|
8558
|
-
hasSession
|
|
8559
|
-
}) {
|
|
8560
|
-
const [collapsed, setCollapsed] = react.useState(true);
|
|
8561
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: devPanelContainerStyle, children: [
|
|
8562
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8563
|
-
"button",
|
|
8564
|
-
{
|
|
8565
|
-
type: "button",
|
|
8566
|
-
onClick: () => setCollapsed((c) => !c),
|
|
8567
|
-
style: devPanelToggleStyle,
|
|
8568
|
-
children: collapsed ? "DEV" : "\u2715"
|
|
8569
|
-
}
|
|
8570
|
-
),
|
|
8571
|
-
!collapsed && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: devPanelBodyStyle, children: [
|
|
8572
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style: devPanelLabelStyle, children: hasSession ? `Status: ${status}` : "No session" }),
|
|
8573
|
-
MOCK_STATUSES.map((s) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
8574
|
-
"button",
|
|
8575
|
-
{
|
|
8576
|
-
type: "button",
|
|
8577
|
-
disabled: !hasSession || status === s,
|
|
8578
|
-
onClick: () => onSetStatus(s),
|
|
8579
|
-
style: devPanelButtonStyle(status === s),
|
|
8580
|
-
children: s.replace(/_/g, " ")
|
|
8581
|
-
},
|
|
8582
|
-
s
|
|
8583
|
-
))
|
|
8584
|
-
] })
|
|
8585
|
-
] });
|
|
8586
|
-
}
|
|
8587
|
-
var devPanelContainerStyle = {
|
|
8588
|
-
position: "fixed",
|
|
8589
|
-
bottom: 16,
|
|
8590
|
-
right: 16,
|
|
8591
|
-
zIndex: 99999,
|
|
8592
|
-
display: "flex",
|
|
8593
|
-
flexDirection: "column",
|
|
8594
|
-
alignItems: "flex-end",
|
|
8595
|
-
gap: 8,
|
|
8596
|
-
fontFamily: "monospace",
|
|
8597
|
-
fontSize: 12
|
|
8598
|
-
};
|
|
8599
|
-
var devPanelToggleStyle = {
|
|
8600
|
-
background: "#1a1a1a",
|
|
8601
|
-
border: "1px solid #333",
|
|
8602
|
-
borderRadius: 8,
|
|
8603
|
-
color: "#0f0",
|
|
8604
|
-
cursor: "pointer",
|
|
8605
|
-
fontSize: 11,
|
|
8606
|
-
fontFamily: "monospace",
|
|
8607
|
-
fontWeight: 700,
|
|
8608
|
-
height: 36,
|
|
8609
|
-
width: 36,
|
|
8610
|
-
display: "flex",
|
|
8611
|
-
alignItems: "center",
|
|
8612
|
-
justifyContent: "center"
|
|
8613
|
-
};
|
|
8614
|
-
var devPanelBodyStyle = {
|
|
8615
|
-
background: "#1a1a1a",
|
|
8616
|
-
border: "1px solid #333",
|
|
8617
|
-
borderRadius: 10,
|
|
8618
|
-
display: "flex",
|
|
8619
|
-
flexDirection: "column",
|
|
8620
|
-
gap: 4,
|
|
8621
|
-
padding: 10,
|
|
8622
|
-
minWidth: 160
|
|
8623
|
-
};
|
|
8624
|
-
var devPanelLabelStyle = {
|
|
8625
|
-
color: "#888",
|
|
8626
|
-
fontSize: 10,
|
|
8627
|
-
marginBottom: 4,
|
|
8628
|
-
textTransform: "uppercase",
|
|
8629
|
-
letterSpacing: "0.05em"
|
|
8630
|
-
};
|
|
8631
|
-
var devPanelButtonStyle = (active) => ({
|
|
8632
|
-
background: active ? "#0f0" : "#2a2a2a",
|
|
8633
|
-
border: "1px solid #444",
|
|
8634
|
-
borderRadius: 6,
|
|
8635
|
-
color: active ? "#000" : "#ccc",
|
|
8636
|
-
cursor: active ? "default" : "pointer",
|
|
8637
|
-
fontFamily: "monospace",
|
|
8638
|
-
fontSize: 11,
|
|
8639
|
-
fontWeight: active ? 700 : 400,
|
|
8640
|
-
padding: "6px 10px",
|
|
8641
|
-
textAlign: "left",
|
|
8642
|
-
textTransform: "capitalize"
|
|
8643
|
-
});
|
|
8644
8817
|
function ScreenLayout({ children, footer }) {
|
|
8645
8818
|
const { tokens, theme, isMobileApp } = useBlinkConfig();
|
|
8646
8819
|
const isRedesign = theme.endsWith("New");
|
|
@@ -10355,16 +10528,21 @@ function DepositQrCodeImpl({
|
|
|
10355
10528
|
depToken
|
|
10356
10529
|
}) {
|
|
10357
10530
|
const { tokens } = useBlinkConfig();
|
|
10358
|
-
const [dataUrl, setDataUrl] = react.useState(null);
|
|
10359
10531
|
const uri = formatDepositUri(address, chainId, depToken);
|
|
10532
|
+
const dark = tokens.text;
|
|
10533
|
+
const light = tokens.bg;
|
|
10534
|
+
const [dataUrl, setDataUrl] = react.useState(
|
|
10535
|
+
() => getCachedQrDataUrl(uri, { dark, light })
|
|
10536
|
+
);
|
|
10360
10537
|
react.useEffect(() => {
|
|
10538
|
+
const cached = getCachedQrDataUrl(uri, { dark, light });
|
|
10539
|
+
if (cached) {
|
|
10540
|
+
setDataUrl(cached);
|
|
10541
|
+
return;
|
|
10542
|
+
}
|
|
10361
10543
|
let cancelled = false;
|
|
10362
|
-
|
|
10363
|
-
|
|
10364
|
-
margin: 1,
|
|
10365
|
-
width: 203,
|
|
10366
|
-
color: { dark: tokens.text, light: tokens.bg }
|
|
10367
|
-
}).then((url) => {
|
|
10544
|
+
setDataUrl(null);
|
|
10545
|
+
getOrRenderQrDataUrl(uri, { dark, light }).then((url) => {
|
|
10368
10546
|
if (!cancelled) setDataUrl(url);
|
|
10369
10547
|
}).catch(() => {
|
|
10370
10548
|
if (!cancelled) setDataUrl(null);
|
|
@@ -10372,7 +10550,7 @@ function DepositQrCodeImpl({
|
|
|
10372
10550
|
return () => {
|
|
10373
10551
|
cancelled = true;
|
|
10374
10552
|
};
|
|
10375
|
-
}, [uri]);
|
|
10553
|
+
}, [uri, dark, light]);
|
|
10376
10554
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: qrFrameStyle(tokens.bgCardTranslucent), children: dataUrl ? /* @__PURE__ */ jsxRuntime.jsxs("div", { style: qrContainerStyle, children: [
|
|
10377
10555
|
/* @__PURE__ */ jsxRuntime.jsx("img", { src: dataUrl, alt: "Deposit QR code", style: qrImageStyle }),
|
|
10378
10556
|
/* @__PURE__ */ jsxRuntime.jsx("img", { src: BLINK_QR_LOGO, alt: "", style: qrLogoStyle })
|
|
@@ -11460,7 +11638,7 @@ function EnterAmountScreen({
|
|
|
11460
11638
|
)
|
|
11461
11639
|
] }),
|
|
11462
11640
|
children: [
|
|
11463
|
-
/* @__PURE__ */ jsxRuntime.jsx(ScreenHeader, { right: headerRight }),
|
|
11641
|
+
/* @__PURE__ */ jsxRuntime.jsx(ScreenHeader, { title: "Deposit", right: headerRight }),
|
|
11464
11642
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: contentStyle4(isDesktop), children: [
|
|
11465
11643
|
isDesktop ? /* @__PURE__ */ jsxRuntime.jsxs("div", { style: desktopHeroRowStyle(heroColor, getDesktopHeroFontSize(value)), children: [
|
|
11466
11644
|
/* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", style: dollarStyle2(isZero), children: "$" }),
|
|
@@ -12801,7 +12979,8 @@ function SetupScreen({
|
|
|
12801
12979
|
onLogout,
|
|
12802
12980
|
loading,
|
|
12803
12981
|
loadingShimmersEnabled = false,
|
|
12804
|
-
error
|
|
12982
|
+
error,
|
|
12983
|
+
selectedTokenSymbol
|
|
12805
12984
|
}) {
|
|
12806
12985
|
const { tokens } = useBlinkConfig();
|
|
12807
12986
|
const [selectedPreset, setSelectedPreset] = react.useState(DEFAULT_MAX);
|
|
@@ -12910,7 +13089,8 @@ function SetupScreen({
|
|
|
12910
13089
|
style: illustrationStyle3
|
|
12911
13090
|
}
|
|
12912
13091
|
),
|
|
12913
|
-
/* @__PURE__ */ jsxRuntime.jsx("h2", { style: headingStyle7(tokens.text), children:
|
|
13092
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { style: headingStyle7(tokens.text), children: `Next time deposit
|
|
13093
|
+
${selectedTokenSymbol ?? "USDC"} in one tap` }),
|
|
12914
13094
|
/* @__PURE__ */ jsxRuntime.jsx("p", { style: subtitleStyle5(tokens.textSecondary), children: "Set a cap for passkey deposits.\nYou always stay in control." }),
|
|
12915
13095
|
error && /* @__PURE__ */ jsxRuntime.jsx("div", { style: errorBannerStyle5(tokens), children: error }),
|
|
12916
13096
|
/* @__PURE__ */ jsxRuntime.jsx("div", { style: chipsRowStyle, children: PRESETS.map(({ label, value }) => {
|
|
@@ -12938,8 +13118,8 @@ var contentStyle9 = {
|
|
|
12938
13118
|
alignItems: "center",
|
|
12939
13119
|
justifyContent: "center",
|
|
12940
13120
|
textAlign: "center",
|
|
12941
|
-
gap:
|
|
12942
|
-
padding: "
|
|
13121
|
+
gap: 12,
|
|
13122
|
+
padding: "8px 0"
|
|
12943
13123
|
};
|
|
12944
13124
|
var shimmerContentStyle = {
|
|
12945
13125
|
display: "flex",
|
|
@@ -13310,7 +13490,7 @@ function SetupDepositScreen({
|
|
|
13310
13490
|
NotificationBanner,
|
|
13311
13491
|
{
|
|
13312
13492
|
variant: "negative",
|
|
13313
|
-
title: "Deposit amount exceeds balance",
|
|
13493
|
+
title: "Deposit amount exceeds stablecoin balance",
|
|
13314
13494
|
description: "Pick another asset or add more funds to your wallet"
|
|
13315
13495
|
}
|
|
13316
13496
|
) : /* @__PURE__ */ jsxRuntime.jsx(NotificationBanner, { title: "Something went wrong", description: error }) })
|
|
@@ -13928,7 +14108,7 @@ function DepositScreen({
|
|
|
13928
14108
|
NotificationBanner,
|
|
13929
14109
|
{
|
|
13930
14110
|
variant: "negative",
|
|
13931
|
-
title: "Deposit amount exceeds balance",
|
|
14111
|
+
title: "Deposit amount exceeds stablecoin balance",
|
|
13932
14112
|
description: "Pick another asset or add more funds to your wallet"
|
|
13933
14113
|
}
|
|
13934
14114
|
) : needsAuthorization ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -14850,12 +15030,12 @@ function DepositAddressScreen({
|
|
|
14850
15030
|
),
|
|
14851
15031
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: contentStyle16, children: [
|
|
14852
15032
|
/* @__PURE__ */ jsxRuntime.jsx("h2", { style: depositTitleStyle(tokens.text), children: "Deposit Address" }),
|
|
14853
|
-
qrReady && session ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
15033
|
+
qrReady && session && selectedOption ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
14854
15034
|
DepositQrCode,
|
|
14855
15035
|
{
|
|
14856
15036
|
address: session.depositAddress,
|
|
14857
|
-
chainId:
|
|
14858
|
-
depToken:
|
|
15037
|
+
chainId: selectedOption.chainId,
|
|
15038
|
+
depToken: selectedOption.tokenAddress
|
|
14859
15039
|
}
|
|
14860
15040
|
) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
14861
15041
|
/* @__PURE__ */ jsxRuntime.jsx("style", { children: `
|
|
@@ -15874,12 +16054,7 @@ var errorBannerStyle8 = (themeTokens) => ({
|
|
|
15874
16054
|
textAlign: "left"
|
|
15875
16055
|
});
|
|
15876
16056
|
function ManualTransferFlow({
|
|
15877
|
-
|
|
15878
|
-
merchantAuthorization,
|
|
15879
|
-
idempotencyKey,
|
|
15880
|
-
mock = false,
|
|
15881
|
-
onComplete,
|
|
15882
|
-
onError,
|
|
16057
|
+
hasMerchantAuthorization,
|
|
15883
16058
|
onCreatePasskey,
|
|
15884
16059
|
createPasskeyLoading = false,
|
|
15885
16060
|
createPasskeyError = null,
|
|
@@ -15908,17 +16083,9 @@ function ManualTransferFlow({
|
|
|
15908
16083
|
depositAddress,
|
|
15909
16084
|
copyDepositAddress,
|
|
15910
16085
|
backToSourceSelector,
|
|
15911
|
-
advanceMockStatus,
|
|
15912
16086
|
selectToken,
|
|
15913
16087
|
selectChainId
|
|
15914
|
-
} =
|
|
15915
|
-
destination,
|
|
15916
|
-
merchantAuthorization,
|
|
15917
|
-
idempotencyKey,
|
|
15918
|
-
mock,
|
|
15919
|
-
onComplete,
|
|
15920
|
-
onError
|
|
15921
|
-
});
|
|
16088
|
+
} = useManualTransferSessionContext();
|
|
15922
16089
|
const [passkeyCreated, setPasskeyCreated] = react.useState(false);
|
|
15923
16090
|
const prevPasskeyLoadingRef = react.useRef(false);
|
|
15924
16091
|
react.useEffect(() => {
|
|
@@ -15927,9 +16094,8 @@ function ManualTransferFlow({
|
|
|
15927
16094
|
}
|
|
15928
16095
|
prevPasskeyLoadingRef.current = createPasskeyLoading;
|
|
15929
16096
|
}, [createPasskeyLoading, createPasskeyError]);
|
|
15930
|
-
const DEV_MOCK_STATUS = mock;
|
|
15931
16097
|
let screenContent = null;
|
|
15932
|
-
if (!
|
|
16098
|
+
if (!hasMerchantAuthorization) {
|
|
15933
16099
|
screenContent = /* @__PURE__ */ jsxRuntime.jsxs(ScreenLayout, { footer: /* @__PURE__ */ jsxRuntime.jsx(PrimaryButton, { onClick: onBack, children: "Back" }), children: [
|
|
15934
16100
|
/* @__PURE__ */ jsxRuntime.jsx(ScreenHeader, { onBack }),
|
|
15935
16101
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: contentStyle20, children: [
|
|
@@ -15999,17 +16165,7 @@ function ManualTransferFlow({
|
|
|
15999
16165
|
if (!screenContent) {
|
|
16000
16166
|
return null;
|
|
16001
16167
|
}
|
|
16002
|
-
return
|
|
16003
|
-
screenContent,
|
|
16004
|
-
DEV_MOCK_STATUS && merchantAuthorization && /* @__PURE__ */ jsxRuntime.jsx(
|
|
16005
|
-
DevMockPanel,
|
|
16006
|
-
{
|
|
16007
|
-
status: session?.status ?? null,
|
|
16008
|
-
onSetStatus: advanceMockStatus,
|
|
16009
|
-
hasSession: !!session
|
|
16010
|
-
}
|
|
16011
|
-
)
|
|
16012
|
-
] });
|
|
16168
|
+
return screenContent;
|
|
16013
16169
|
}
|
|
16014
16170
|
var contentStyle20 = {
|
|
16015
16171
|
alignItems: "center",
|
|
@@ -16309,6 +16465,7 @@ function buildSetupDepositScreenProps({
|
|
|
16309
16465
|
function buildSetupScreenProps({
|
|
16310
16466
|
flow,
|
|
16311
16467
|
remote,
|
|
16468
|
+
derived,
|
|
16312
16469
|
forms,
|
|
16313
16470
|
handlers
|
|
16314
16471
|
}) {
|
|
@@ -16317,11 +16474,12 @@ function buildSetupScreenProps({
|
|
|
16317
16474
|
const waitingForDesktopWalletConnection = flow.isDesktop && remote.authExecutorExecuting && remote.pendingOneTapSetup == null && (remote.authExecutorCurrentAction == null || remote.authExecutorCurrentAction.type === "OPEN_PROVIDER");
|
|
16318
16475
|
return {
|
|
16319
16476
|
onSetupOneTap: handlers.onSetupOneTap,
|
|
16320
|
-
onBack: handlers.onBackFromSubflow,
|
|
16321
|
-
onLogout: handlers.onLogout,
|
|
16477
|
+
onBack: flow.isDesktop ? handlers.onBackFromSubflow : void 0,
|
|
16478
|
+
onLogout: flow.isDesktop ? handlers.onLogout : void 0,
|
|
16322
16479
|
loading: savingOneTapLimit,
|
|
16323
16480
|
loadingShimmersEnabled: waitingForDesktopWalletConnection,
|
|
16324
|
-
error: state.error
|
|
16481
|
+
error: state.error,
|
|
16482
|
+
selectedTokenSymbol: derived.selectedSource?.token.symbol
|
|
16325
16483
|
};
|
|
16326
16484
|
}
|
|
16327
16485
|
function buildConfirmSignScreenProps({
|
|
@@ -16598,12 +16756,7 @@ function StepRendererContent({
|
|
|
16598
16756
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
16599
16757
|
ManualTransferFlow,
|
|
16600
16758
|
{
|
|
16601
|
-
|
|
16602
|
-
merchantAuthorization: flow.merchantAuthorization,
|
|
16603
|
-
idempotencyKey: flow.idempotencyKey,
|
|
16604
|
-
mock: flow.mock,
|
|
16605
|
-
onComplete: flow.onComplete,
|
|
16606
|
-
onError: flow.onError,
|
|
16759
|
+
hasMerchantAuthorization: flow.merchantAuthorization != null,
|
|
16607
16760
|
onCreatePasskey: handlers.onSignupWithPasskey,
|
|
16608
16761
|
createPasskeyLoading: flow.passkeyLoading,
|
|
16609
16762
|
createPasskeyError: flow.state.error,
|
|
@@ -18821,8 +18974,11 @@ function usePasskeyCheckEffect(deps) {
|
|
|
18821
18974
|
setupAccountIdRef,
|
|
18822
18975
|
reauthSessionIdRef,
|
|
18823
18976
|
reauthTokenRef,
|
|
18824
|
-
pollingTransferIdRef
|
|
18977
|
+
pollingTransferIdRef,
|
|
18978
|
+
reloadAccounts
|
|
18825
18979
|
} = deps;
|
|
18980
|
+
const reloadAccountsRef = react.useRef(reloadAccounts);
|
|
18981
|
+
reloadAccountsRef.current = reloadAccounts;
|
|
18826
18982
|
const { getAccessToken: privyGetAccessToken, user } = reactAuth.usePrivy();
|
|
18827
18983
|
const effectiveGetAccessToken = deps.getAccessToken ?? privyGetAccessToken;
|
|
18828
18984
|
const onCompleteRef = react.useRef(deps.onComplete);
|
|
@@ -18952,6 +19108,11 @@ function usePasskeyCheckEffect(deps) {
|
|
|
18952
19108
|
mobileSetupFlowRef.current = false;
|
|
18953
19109
|
setupAccountIdRef.current = null;
|
|
18954
19110
|
clearMobileFlowState();
|
|
19111
|
+
try {
|
|
19112
|
+
await reloadAccountsRef.current();
|
|
19113
|
+
} catch {
|
|
19114
|
+
}
|
|
19115
|
+
dispatch({ type: "MOBILE_SETUP_COMPLETE" });
|
|
18955
19116
|
return;
|
|
18956
19117
|
}
|
|
18957
19118
|
if (persisted.accountId && !persisted.transferId) {
|
|
@@ -18960,7 +19121,14 @@ function usePasskeyCheckEffect(deps) {
|
|
|
18960
19121
|
const session = await fetchAuthorizationSession(apiBaseUrl, persisted.sessionId);
|
|
18961
19122
|
if (cancelled) return;
|
|
18962
19123
|
if (session.status === "AUTHORIZED") {
|
|
19124
|
+
mobileSetupFlowRef.current = false;
|
|
19125
|
+
setupAccountIdRef.current = null;
|
|
18963
19126
|
clearMobileFlowState();
|
|
19127
|
+
try {
|
|
19128
|
+
await reloadAccountsRef.current();
|
|
19129
|
+
} catch {
|
|
19130
|
+
}
|
|
19131
|
+
dispatch({ type: "MOBILE_SETUP_COMPLETE" });
|
|
18964
19132
|
return;
|
|
18965
19133
|
}
|
|
18966
19134
|
} catch {
|
|
@@ -19425,25 +19593,24 @@ function useMobilePollingEffect(deps) {
|
|
|
19425
19593
|
dispatch({ type: "MOBILE_SETUP_COMPLETE" });
|
|
19426
19594
|
};
|
|
19427
19595
|
const pollWalletActive = async () => {
|
|
19596
|
+
if (setupSessionId) {
|
|
19597
|
+
try {
|
|
19598
|
+
const session = await fetchAuthorizationSession(apiBaseUrl, setupSessionId);
|
|
19599
|
+
if (cancelled) return;
|
|
19600
|
+
if (session.status === "AUTHORIZED") {
|
|
19601
|
+
await completeSetup();
|
|
19602
|
+
return;
|
|
19603
|
+
}
|
|
19604
|
+
} catch {
|
|
19605
|
+
}
|
|
19606
|
+
}
|
|
19428
19607
|
try {
|
|
19429
19608
|
const token = await getAccessTokenRef.current();
|
|
19430
19609
|
if (!token || cancelled) return;
|
|
19431
19610
|
const acct = await fetchAccount(apiBaseUrl, token, accountId, credentialId);
|
|
19432
19611
|
if (cancelled) return;
|
|
19433
|
-
|
|
19434
|
-
if (hasActive) {
|
|
19612
|
+
if (acct.wallets.some((w) => w.status === "ACTIVE")) {
|
|
19435
19613
|
await completeSetup();
|
|
19436
|
-
return;
|
|
19437
|
-
}
|
|
19438
|
-
if (setupSessionId) {
|
|
19439
|
-
try {
|
|
19440
|
-
const session = await fetchAuthorizationSession(apiBaseUrl, setupSessionId);
|
|
19441
|
-
if (cancelled) return;
|
|
19442
|
-
if (session.status === "AUTHORIZED") {
|
|
19443
|
-
await completeSetup();
|
|
19444
|
-
}
|
|
19445
|
-
} catch {
|
|
19446
|
-
}
|
|
19447
19614
|
}
|
|
19448
19615
|
} catch {
|
|
19449
19616
|
}
|
|
@@ -19878,7 +20045,6 @@ function BlinkPayment(props) {
|
|
|
19878
20045
|
function BlinkPaymentInner({
|
|
19879
20046
|
destination,
|
|
19880
20047
|
initialScreen,
|
|
19881
|
-
mock,
|
|
19882
20048
|
onComplete,
|
|
19883
20049
|
onError,
|
|
19884
20050
|
useWalletConnector: useWalletConnectorProp,
|
|
@@ -19967,6 +20133,7 @@ function BlinkPaymentInner({
|
|
|
19967
20133
|
minTransferAmountUsd: effectiveMinDepositAmountUsd
|
|
19968
20134
|
});
|
|
19969
20135
|
const feeEstimateEnabled = effectiveAuthenticated && (state.phase.step === "deposit" || state.phase.step === "wallet-setup" || state.phase.step === "one-tap-setup");
|
|
20136
|
+
const manualTransferActive = screenForPhase(state.phase) === "manual-transfer";
|
|
19970
20137
|
const setupSelectedSourceOption = react.useMemo(() => {
|
|
19971
20138
|
const options = sourceSelection.pendingSelectSourceAction?.metadata?.options ?? [];
|
|
19972
20139
|
return resolveSelectSourceOption(
|
|
@@ -20113,13 +20280,14 @@ function BlinkPaymentInner({
|
|
|
20113
20280
|
idempotencyKey
|
|
20114
20281
|
});
|
|
20115
20282
|
const accountSwitchSessionId = state.setupAuthorizationSessionId;
|
|
20283
|
+
const accountSwitchListenerArmed = accountSwitchSessionId != null && state.desktopWait == null;
|
|
20116
20284
|
const handleProviderWalletAccountSwitch = provider.handleWalletAccountSwitch;
|
|
20117
20285
|
const onWalletAccountChanged = react.useCallback(async (change) => {
|
|
20118
20286
|
if (!accountSwitchSessionId) return;
|
|
20119
20287
|
await handleProviderWalletAccountSwitch(change, accountSwitchSessionId);
|
|
20120
20288
|
}, [handleProviderWalletAccountSwitch, accountSwitchSessionId]);
|
|
20121
20289
|
useWalletAccountSwitchEffect({
|
|
20122
|
-
enabled:
|
|
20290
|
+
enabled: accountSwitchListenerArmed,
|
|
20123
20291
|
isDesktop,
|
|
20124
20292
|
onAccountChanged: onWalletAccountChanged
|
|
20125
20293
|
});
|
|
@@ -20215,6 +20383,7 @@ function BlinkPaymentInner({
|
|
|
20215
20383
|
reauthTokenRef: mobileFlowRefs.reauthTokenRef,
|
|
20216
20384
|
pollingTransferIdRef: transfer.pollingTransferIdRef,
|
|
20217
20385
|
handleAuthorizedMobileReturn: mobileFlow.handleAuthorizedMobileReturn,
|
|
20386
|
+
reloadAccounts: transfer.reloadAccounts,
|
|
20218
20387
|
onComplete,
|
|
20219
20388
|
getAccessToken: effectiveGetAccessToken,
|
|
20220
20389
|
pendingTransferFlowKey
|
|
@@ -20381,15 +20550,18 @@ function BlinkPaymentInner({
|
|
|
20381
20550
|
dispatch,
|
|
20382
20551
|
orchestrator
|
|
20383
20552
|
]);
|
|
20384
|
-
const handleBackFromSetupDeposit = react.useCallback(() => {
|
|
20553
|
+
const handleBackFromSetupDeposit = react.useCallback(async () => {
|
|
20385
20554
|
orchestrator.cancelPendingFlow();
|
|
20386
20555
|
authExecutor.cancelPendingExecution();
|
|
20387
20556
|
clearScreenErrors();
|
|
20557
|
+
if (isDesktop) {
|
|
20558
|
+
await revokeAndDisconnectActiveWagmiConnector(wagmiConfig);
|
|
20559
|
+
}
|
|
20388
20560
|
dispatch({ type: "RESTORE_SELECTION" });
|
|
20389
20561
|
dispatch({ type: "CLEAR_SETUP_DEPOSIT_TOKEN" });
|
|
20390
20562
|
dispatch({ type: "SET_SETUP_FLOW_SCREEN", screen: null });
|
|
20391
20563
|
dispatch({ type: "SET_USER_INTENT", intent: { step: "wallet-picker", reason: "switch" } });
|
|
20392
|
-
}, [authExecutor, clearScreenErrors, orchestrator, dispatch]);
|
|
20564
|
+
}, [authExecutor, clearScreenErrors, orchestrator, dispatch, isDesktop, wagmiConfig]);
|
|
20393
20565
|
const handleAuthorizationRetry = react.useCallback(() => {
|
|
20394
20566
|
void (async () => {
|
|
20395
20567
|
try {
|
|
@@ -20429,6 +20601,11 @@ function BlinkPaymentInner({
|
|
|
20429
20601
|
clearScreenErrors();
|
|
20430
20602
|
dispatch({ type: "SET_SETUP_DEPOSIT_AMOUNT", amount });
|
|
20431
20603
|
dispatch({ type: "SET_USER_INTENT", intent: { step: "wallet-picker", reason: "switch" } });
|
|
20604
|
+
void (async () => {
|
|
20605
|
+
await revokeAndDisconnectActiveWagmiConnector(wagmiConfig);
|
|
20606
|
+
await authExecutor.resetWalletConnect().catch(() => {
|
|
20607
|
+
});
|
|
20608
|
+
})();
|
|
20432
20609
|
},
|
|
20433
20610
|
onBackFromSetupDeposit: handleBackFromSetupDeposit,
|
|
20434
20611
|
onBackFromSubflow: () => {
|
|
@@ -20477,65 +20654,76 @@ function BlinkPaymentInner({
|
|
|
20477
20654
|
handleSetDepositToken,
|
|
20478
20655
|
handleConfirmSetupDeposit,
|
|
20479
20656
|
handleBackFromSetupDeposit,
|
|
20480
|
-
handleAuthorizationRetry
|
|
20657
|
+
handleAuthorizationRetry,
|
|
20658
|
+
wagmiConfig
|
|
20481
20659
|
]);
|
|
20482
20660
|
return /* @__PURE__ */ jsxRuntime.jsx(EffectiveDepositAmountProvider, { value: effectiveDepositAmount, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
20483
|
-
|
|
20661
|
+
ManualTransferSessionProvider,
|
|
20484
20662
|
{
|
|
20485
|
-
|
|
20486
|
-
|
|
20487
|
-
|
|
20488
|
-
|
|
20489
|
-
|
|
20490
|
-
|
|
20491
|
-
|
|
20492
|
-
|
|
20493
|
-
|
|
20494
|
-
|
|
20495
|
-
|
|
20496
|
-
|
|
20497
|
-
|
|
20498
|
-
|
|
20499
|
-
|
|
20500
|
-
|
|
20501
|
-
|
|
20502
|
-
|
|
20503
|
-
|
|
20504
|
-
|
|
20505
|
-
|
|
20506
|
-
|
|
20507
|
-
|
|
20508
|
-
|
|
20509
|
-
|
|
20510
|
-
|
|
20511
|
-
|
|
20512
|
-
|
|
20513
|
-
|
|
20514
|
-
|
|
20515
|
-
|
|
20516
|
-
|
|
20517
|
-
|
|
20518
|
-
|
|
20519
|
-
|
|
20520
|
-
|
|
20521
|
-
|
|
20522
|
-
|
|
20523
|
-
|
|
20524
|
-
|
|
20525
|
-
|
|
20526
|
-
|
|
20527
|
-
|
|
20528
|
-
|
|
20529
|
-
|
|
20530
|
-
|
|
20531
|
-
|
|
20532
|
-
|
|
20533
|
-
|
|
20534
|
-
|
|
20535
|
-
|
|
20536
|
-
|
|
20537
|
-
|
|
20538
|
-
|
|
20663
|
+
destination,
|
|
20664
|
+
merchantAuthorization,
|
|
20665
|
+
idempotencyKey,
|
|
20666
|
+
onComplete,
|
|
20667
|
+
onError,
|
|
20668
|
+
pollEnabled: manualTransferActive,
|
|
20669
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
20670
|
+
StepRenderer,
|
|
20671
|
+
{
|
|
20672
|
+
flow: {
|
|
20673
|
+
state,
|
|
20674
|
+
authenticated: effectiveAuthenticated,
|
|
20675
|
+
passkeyLoading: auth.passkeyLoginStatus !== "initial" && auth.passkeyLoginStatus !== "done" && auth.passkeyLoginStatus !== "error" || auth.passkeySignupStatus !== "initial" && auth.passkeySignupStatus !== "done" && auth.passkeySignupStatus !== "error" || auth.passkeySignupPopupActive,
|
|
20676
|
+
isDesktop,
|
|
20677
|
+
isMobileApp: isMobileApp ?? false,
|
|
20678
|
+
merchantName,
|
|
20679
|
+
onBack,
|
|
20680
|
+
onDismiss,
|
|
20681
|
+
depositAmount,
|
|
20682
|
+
effectiveDepositAmount,
|
|
20683
|
+
minTransferAmountUsd,
|
|
20684
|
+
destination,
|
|
20685
|
+
merchantAuthorization,
|
|
20686
|
+
idempotencyKey,
|
|
20687
|
+
onComplete,
|
|
20688
|
+
onError
|
|
20689
|
+
},
|
|
20690
|
+
remote: {
|
|
20691
|
+
pollingTransfer: polling.transfer,
|
|
20692
|
+
pollingError: polling.error,
|
|
20693
|
+
authExecutorError: authExecutor.error,
|
|
20694
|
+
authExecutorExecuting: authExecutor.executing,
|
|
20695
|
+
authExecutorCurrentAction: authExecutor.currentAction,
|
|
20696
|
+
pendingOneTapSetup: orchestrator.pendingOneTapAction,
|
|
20697
|
+
setupAuthorizationComplete,
|
|
20698
|
+
transferSigningSigning: transferSigning.signing,
|
|
20699
|
+
transferSigningError: transferSigning.error,
|
|
20700
|
+
transferSigningPasskeyDismissed: transferSigning.passkeyDismissed,
|
|
20701
|
+
pendingSelectSource: orchestrator.pendingSelectSourceAction
|
|
20702
|
+
},
|
|
20703
|
+
derived: {
|
|
20704
|
+
pendingConnections: derived.pendingConnections,
|
|
20705
|
+
depositEligibleAccounts: derived.depositEligibleAccounts,
|
|
20706
|
+
sourceName: derived.sourceName,
|
|
20707
|
+
maxSourceBalance: derived.maxSourceBalance,
|
|
20708
|
+
tokenCount: derived.tokenCount,
|
|
20709
|
+
selectedAccount: derived.selectedAccount,
|
|
20710
|
+
selectedSource: derived.selectedSource,
|
|
20711
|
+
selectSourceChoices: sourceSelection.selectSourceChoices,
|
|
20712
|
+
selectSourceRecommended: sourceSelection.selectSourceRecommended,
|
|
20713
|
+
selectSourceAvailableBalance: sourceSelection.selectSourceAvailableBalance
|
|
20714
|
+
},
|
|
20715
|
+
forms: {
|
|
20716
|
+
selectSourceChainName: sourceSelection.selectSourceChainName,
|
|
20717
|
+
selectSourceTokenSymbol: sourceSelection.selectSourceTokenSymbol,
|
|
20718
|
+
savingOneTapLimit: oneTapSetup.savingOneTapLimit,
|
|
20719
|
+
depositQuoteId: depositFee.quoteId,
|
|
20720
|
+
depositQuoteFee: depositFee.quoteFee,
|
|
20721
|
+
depositQuoteLoading: depositFee.quoteLoading,
|
|
20722
|
+
depositQuoteError: depositFee.quoteError
|
|
20723
|
+
},
|
|
20724
|
+
handlers
|
|
20725
|
+
}
|
|
20726
|
+
)
|
|
20539
20727
|
}
|
|
20540
20728
|
) });
|
|
20541
20729
|
}
|