@swype-org/react-sdk 0.2.242 → 0.2.261
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1191 -1017
- 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 +1192 -1018
- 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,692 @@ 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;
|
|
7434
|
-
}
|
|
7435
|
-
function getTransferStatus(polledTransfer, localTransfer) {
|
|
7436
|
-
const transfer = resolvePreferredTransfer(polledTransfer, localTransfer);
|
|
7437
|
-
return transfer?.status ?? "UNKNOWN";
|
|
7580
|
+
function feeCopy(_session) {
|
|
7581
|
+
return "No fees";
|
|
7438
7582
|
}
|
|
7439
|
-
function
|
|
7440
|
-
|
|
7441
|
-
|
|
7583
|
+
function toTransfer(session) {
|
|
7584
|
+
return {
|
|
7585
|
+
id: session.sessionId,
|
|
7586
|
+
status: session.status,
|
|
7587
|
+
amount: {
|
|
7588
|
+
amount: Number(session.deliveredAmountUsd ?? session.minAmountUsd),
|
|
7589
|
+
currency: "USD"
|
|
7590
|
+
},
|
|
7591
|
+
sources: [],
|
|
7592
|
+
destinations: [{
|
|
7593
|
+
id: session.sessionId,
|
|
7594
|
+
chainId: session.destination.chainId,
|
|
7595
|
+
address: session.destination.address,
|
|
7596
|
+
token: { address: session.destination.token.address, symbol: "" },
|
|
7597
|
+
amount: { amount: Number(session.deliveredAmountUsd ?? session.minAmountUsd), currency: "USD" }
|
|
7598
|
+
}],
|
|
7599
|
+
createDate: session.createDate,
|
|
7600
|
+
updateDate: session.updateDate
|
|
7601
|
+
};
|
|
7442
7602
|
}
|
|
7443
|
-
var
|
|
7444
|
-
|
|
7445
|
-
|
|
7446
|
-
|
|
7447
|
-
|
|
7448
|
-
|
|
7449
|
-
|
|
7450
|
-
}
|
|
7451
|
-
|
|
7452
|
-
return
|
|
7603
|
+
var SOLANA_CHAIN_ID = 792703809;
|
|
7604
|
+
var SOLANA_NATIVE_SOL_ADDRESS = "11111111111111111111111111111111";
|
|
7605
|
+
function formatDepositUri(address, chainId, depToken) {
|
|
7606
|
+
if (chainId === SOLANA_CHAIN_ID) {
|
|
7607
|
+
if (!depToken || depToken === SOLANA_NATIVE_SOL_ADDRESS) {
|
|
7608
|
+
return `solana:${address}`;
|
|
7609
|
+
}
|
|
7610
|
+
return `solana:${address}?spl-token=${depToken}`;
|
|
7611
|
+
}
|
|
7612
|
+
return address;
|
|
7453
7613
|
}
|
|
7454
|
-
|
|
7455
|
-
|
|
7456
|
-
|
|
7614
|
+
var dataUrlCache = /* @__PURE__ */ new Map();
|
|
7615
|
+
var inFlight = /* @__PURE__ */ new Map();
|
|
7616
|
+
function keyFor(uri, colors) {
|
|
7617
|
+
return `${uri}|${colors.dark}|${colors.light}`;
|
|
7618
|
+
}
|
|
7619
|
+
function getCachedQrDataUrl(uri, colors) {
|
|
7620
|
+
return dataUrlCache.get(keyFor(uri, colors)) ?? null;
|
|
7621
|
+
}
|
|
7622
|
+
function getOrRenderQrDataUrl(uri, colors) {
|
|
7623
|
+
const key = keyFor(uri, colors);
|
|
7624
|
+
const cached = dataUrlCache.get(key);
|
|
7625
|
+
if (cached) return Promise.resolve(cached);
|
|
7626
|
+
const pending = inFlight.get(key);
|
|
7627
|
+
if (pending) return pending;
|
|
7628
|
+
const promise = QRCode__namespace.toDataURL(uri, {
|
|
7629
|
+
errorCorrectionLevel: "H",
|
|
7630
|
+
margin: 1,
|
|
7631
|
+
width: 203,
|
|
7632
|
+
color: { dark: colors.dark, light: colors.light }
|
|
7633
|
+
}).then((url) => {
|
|
7634
|
+
dataUrlCache.set(key, url);
|
|
7635
|
+
inFlight.delete(key);
|
|
7636
|
+
return url;
|
|
7637
|
+
}).catch((err) => {
|
|
7638
|
+
inFlight.delete(key);
|
|
7639
|
+
throw err;
|
|
7640
|
+
});
|
|
7641
|
+
inFlight.set(key, promise);
|
|
7642
|
+
return promise;
|
|
7457
7643
|
}
|
|
7458
7644
|
|
|
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;
|
|
7645
|
+
// src/hooks/useManualTransferSession.ts
|
|
7646
|
+
function perTokenKey(chainId, tokenAddress) {
|
|
7647
|
+
return `${chainId}:${tokenAddress.toLowerCase()}`;
|
|
7486
7648
|
}
|
|
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
|
-
|
|
7649
|
+
function useManualTransferSession({
|
|
7650
|
+
destination,
|
|
7651
|
+
merchantAuthorization,
|
|
7652
|
+
idempotencyKey,
|
|
7653
|
+
onComplete,
|
|
7654
|
+
onError,
|
|
7655
|
+
pollEnabled = true
|
|
7656
|
+
}) {
|
|
7657
|
+
const { apiBaseUrl, tokens } = useBlinkConfig();
|
|
7658
|
+
const [sourceOptions, setSourceOptions] = react.useState(null);
|
|
7659
|
+
const [loadingSources, setLoadingSources] = react.useState(true);
|
|
7660
|
+
const [selectedToken, setSelectedToken] = react.useState("");
|
|
7661
|
+
const [selectedChainId, setSelectedChainId] = react.useState("");
|
|
7662
|
+
const [sessionsByFamily, setSessionsByFamily] = react.useState({});
|
|
7663
|
+
const [perTokenSessions, setPerTokenSessions] = react.useState({});
|
|
7664
|
+
const [loading, setLoading] = react.useState(false);
|
|
7665
|
+
const [error, setError] = react.useState(null);
|
|
7666
|
+
const [copiedAddress, setCopiedAddress] = react.useState(null);
|
|
7667
|
+
const completedRef = react.useRef(/* @__PURE__ */ new Set());
|
|
7668
|
+
const premintedFamiliesRef = react.useRef(/* @__PURE__ */ new Set());
|
|
7669
|
+
const inFlightPerTokenRef = react.useRef(/* @__PURE__ */ new Set());
|
|
7670
|
+
react.useEffect(() => {
|
|
7671
|
+
if (!merchantAuthorization) return;
|
|
7672
|
+
let cancelled = false;
|
|
7673
|
+
setLoadingSources(true);
|
|
7674
|
+
fetchManualTransferSources(apiBaseUrl, { merchantAuthorization, destination }).then((sources) => {
|
|
7675
|
+
if (cancelled) return;
|
|
7676
|
+
setSourceOptions(sources);
|
|
7677
|
+
setLoadingSources(false);
|
|
7678
|
+
const svmCanonical = sources.find((s) => s.canonical && s.chainFamily === "svm");
|
|
7679
|
+
const evmCanonical = sources.find((s) => s.canonical && s.chainFamily === "evm");
|
|
7680
|
+
const defaultOption = svmCanonical ?? evmCanonical ?? sources[0];
|
|
7681
|
+
if (defaultOption) {
|
|
7682
|
+
setSelectedToken(defaultOption.tokenSymbol);
|
|
7683
|
+
setSelectedChainId(String(defaultOption.chainId));
|
|
7684
|
+
}
|
|
7685
|
+
}).catch((err) => {
|
|
7686
|
+
if (!cancelled) {
|
|
7687
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
7688
|
+
setLoadingSources(false);
|
|
7689
|
+
}
|
|
7690
|
+
});
|
|
7691
|
+
return () => {
|
|
7692
|
+
cancelled = true;
|
|
7522
7693
|
};
|
|
7523
|
-
}
|
|
7524
|
-
|
|
7525
|
-
return
|
|
7526
|
-
|
|
7527
|
-
|
|
7528
|
-
|
|
7694
|
+
}, [apiBaseUrl, destination, merchantAuthorization]);
|
|
7695
|
+
react.useEffect(() => {
|
|
7696
|
+
if (!sourceOptions || !merchantAuthorization) return;
|
|
7697
|
+
const canonicals = sourceOptions.filter((s) => s.canonical);
|
|
7698
|
+
if (canonicals.length === 0) return;
|
|
7699
|
+
let cancelled = false;
|
|
7700
|
+
for (const opt of canonicals) {
|
|
7701
|
+
if (premintedFamiliesRef.current.has(opt.chainFamily)) continue;
|
|
7702
|
+
premintedFamiliesRef.current.add(opt.chainFamily);
|
|
7703
|
+
const family = opt.chainFamily;
|
|
7704
|
+
const run = async () => {
|
|
7705
|
+
try {
|
|
7706
|
+
const created = await createManualTransfer(apiBaseUrl, {
|
|
7707
|
+
merchantAuthorization,
|
|
7708
|
+
destination,
|
|
7709
|
+
idempotencyKey,
|
|
7710
|
+
source: { chainId: opt.chainId, tokenAddress: opt.tokenAddress }
|
|
7711
|
+
});
|
|
7712
|
+
if (cancelled) return;
|
|
7713
|
+
setSessionsByFamily((prev) => ({ ...prev, [family]: created }));
|
|
7714
|
+
const uri = formatDepositUri(created.depositAddress, opt.chainId, opt.tokenAddress);
|
|
7715
|
+
void getOrRenderQrDataUrl(uri, { dark: tokens.text, light: tokens.bg });
|
|
7716
|
+
} catch (err) {
|
|
7717
|
+
if (cancelled) return;
|
|
7718
|
+
premintedFamiliesRef.current.delete(family);
|
|
7719
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
7720
|
+
}
|
|
7721
|
+
};
|
|
7722
|
+
void run();
|
|
7723
|
+
}
|
|
7724
|
+
return () => {
|
|
7725
|
+
cancelled = true;
|
|
7529
7726
|
};
|
|
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
|
-
|
|
7727
|
+
}, [
|
|
7728
|
+
apiBaseUrl,
|
|
7729
|
+
destination,
|
|
7730
|
+
idempotencyKey,
|
|
7731
|
+
merchantAuthorization,
|
|
7732
|
+
sourceOptions,
|
|
7733
|
+
tokens.text,
|
|
7734
|
+
tokens.bg
|
|
7735
|
+
]);
|
|
7736
|
+
const tokenChoices = react.useMemo(
|
|
7737
|
+
() => Array.from(new Set((sourceOptions ?? []).map((opt) => opt.tokenSymbol))),
|
|
7738
|
+
[sourceOptions]
|
|
7739
|
+
);
|
|
7740
|
+
const chainChoices = react.useMemo(() => {
|
|
7741
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7742
|
+
return (sourceOptions ?? []).filter((opt) => {
|
|
7743
|
+
if (seen.has(opt.chainId)) return false;
|
|
7744
|
+
seen.add(opt.chainId);
|
|
7745
|
+
return true;
|
|
7746
|
+
});
|
|
7747
|
+
}, [sourceOptions]);
|
|
7748
|
+
const tokenLogoUriBySymbol = react.useMemo(() => {
|
|
7749
|
+
const out = {};
|
|
7750
|
+
for (const opt of sourceOptions ?? []) {
|
|
7751
|
+
if (out[opt.tokenSymbol] == null) {
|
|
7752
|
+
out[opt.tokenSymbol] = opt.tokenLogoUri;
|
|
7753
|
+
}
|
|
7754
|
+
}
|
|
7755
|
+
return out;
|
|
7756
|
+
}, [sourceOptions]);
|
|
7757
|
+
const selectedOption = react.useMemo(
|
|
7758
|
+
() => (sourceOptions ?? []).find(
|
|
7759
|
+
(opt) => opt.tokenSymbol === selectedToken && String(opt.chainId) === selectedChainId
|
|
7760
|
+
) ?? null,
|
|
7761
|
+
[sourceOptions, selectedToken, selectedChainId]
|
|
7762
|
+
);
|
|
7763
|
+
const tokensForSelectedChain = react.useMemo(() => {
|
|
7764
|
+
if (!selectedChainId) return null;
|
|
7765
|
+
return new Set(
|
|
7766
|
+
(sourceOptions ?? []).filter((opt) => String(opt.chainId) === selectedChainId).map((opt) => opt.tokenSymbol)
|
|
7767
|
+
);
|
|
7768
|
+
}, [sourceOptions, selectedChainId]);
|
|
7769
|
+
const chainsForSelectedToken = react.useMemo(() => {
|
|
7770
|
+
if (!selectedToken) return null;
|
|
7771
|
+
return new Set(
|
|
7772
|
+
(sourceOptions ?? []).filter((opt) => opt.tokenSymbol === selectedToken).map((opt) => opt.chainId)
|
|
7773
|
+
);
|
|
7774
|
+
}, [sourceOptions, selectedToken]);
|
|
7775
|
+
const session = react.useMemo(() => {
|
|
7776
|
+
if (!selectedOption) return null;
|
|
7777
|
+
const familySession = sessionsByFamily[selectedOption.chainFamily];
|
|
7778
|
+
if (familySession) return familySession;
|
|
7779
|
+
return perTokenSessions[perTokenKey(selectedOption.chainId, selectedOption.tokenAddress)] ?? null;
|
|
7780
|
+
}, [selectedOption, sessionsByFamily, perTokenSessions]);
|
|
7781
|
+
const depositAddress = session?.depositAddress;
|
|
7782
|
+
const qrReady = !!depositAddress;
|
|
7783
|
+
const lastFeeCopyRef = react.useRef(null);
|
|
7784
|
+
const nextFeeCopy = session ? feeCopy() : null;
|
|
7785
|
+
const sessionFeeCopy = nextFeeCopy === lastFeeCopyRef.current ? lastFeeCopyRef.current : lastFeeCopyRef.current = nextFeeCopy;
|
|
7786
|
+
const activeSessionId = session?.sessionId;
|
|
7787
|
+
const activeSessionStatus = session?.status;
|
|
7788
|
+
react.useEffect(() => {
|
|
7789
|
+
if (!pollEnabled) return;
|
|
7790
|
+
if (!activeSessionId) return;
|
|
7791
|
+
if (activeSessionStatus && ["completed", "failed", "refunded", "wrong_token"].includes(activeSessionStatus)) return;
|
|
7792
|
+
const timer = window.setInterval(() => {
|
|
7793
|
+
fetchManualTransferSession(apiBaseUrl, activeSessionId).then((updated) => {
|
|
7794
|
+
setSessionsByFamily((prev) => {
|
|
7795
|
+
for (const family of Object.keys(prev)) {
|
|
7796
|
+
if (prev[family]?.sessionId === updated.sessionId) {
|
|
7797
|
+
return { ...prev, [family]: updated };
|
|
7798
|
+
}
|
|
7799
|
+
}
|
|
7800
|
+
return prev;
|
|
7801
|
+
});
|
|
7802
|
+
setPerTokenSessions((prev) => {
|
|
7803
|
+
for (const key of Object.keys(prev)) {
|
|
7804
|
+
if (prev[key]?.sessionId === updated.sessionId) {
|
|
7805
|
+
return { ...prev, [key]: updated };
|
|
7806
|
+
}
|
|
7807
|
+
}
|
|
7808
|
+
return prev;
|
|
7809
|
+
});
|
|
7810
|
+
}).catch((err) => setError(err instanceof Error ? err.message : String(err)));
|
|
7811
|
+
}, 2e3);
|
|
7812
|
+
return () => window.clearInterval(timer);
|
|
7813
|
+
}, [apiBaseUrl, activeSessionId, activeSessionStatus, pollEnabled]);
|
|
7814
|
+
const completionSignature = react.useMemo(() => {
|
|
7815
|
+
const entries2 = [];
|
|
7816
|
+
for (const family of Object.keys(sessionsByFamily)) {
|
|
7817
|
+
const s = sessionsByFamily[family];
|
|
7818
|
+
if (s) entries2.push([s.sessionId, s.status]);
|
|
7819
|
+
}
|
|
7820
|
+
for (const key of Object.keys(perTokenSessions)) {
|
|
7821
|
+
const s = perTokenSessions[key];
|
|
7822
|
+
entries2.push([s.sessionId, s.status]);
|
|
7823
|
+
}
|
|
7824
|
+
entries2.sort((a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0);
|
|
7825
|
+
return JSON.stringify(entries2);
|
|
7826
|
+
}, [sessionsByFamily, perTokenSessions]);
|
|
7827
|
+
react.useEffect(() => {
|
|
7828
|
+
const all = [];
|
|
7829
|
+
for (const family of Object.keys(sessionsByFamily)) {
|
|
7830
|
+
const s = sessionsByFamily[family];
|
|
7831
|
+
if (s) all.push(s);
|
|
7832
|
+
}
|
|
7833
|
+
for (const key of Object.keys(perTokenSessions)) {
|
|
7834
|
+
all.push(perTokenSessions[key]);
|
|
7835
|
+
}
|
|
7836
|
+
for (const s of all) {
|
|
7837
|
+
if (s.status !== "completed") continue;
|
|
7838
|
+
if (completedRef.current.has(s.sessionId)) continue;
|
|
7839
|
+
completedRef.current.add(s.sessionId);
|
|
7840
|
+
onComplete?.(toTransfer(s));
|
|
7841
|
+
break;
|
|
7842
|
+
}
|
|
7843
|
+
}, [completionSignature, onComplete]);
|
|
7844
|
+
react.useEffect(() => {
|
|
7845
|
+
if (!error) return;
|
|
7846
|
+
onError?.(error);
|
|
7847
|
+
}, [error, onError]);
|
|
7848
|
+
const createSession = react.useCallback(async (option) => {
|
|
7849
|
+
if (!merchantAuthorization) return;
|
|
7850
|
+
setLoading(true);
|
|
7851
|
+
setError(null);
|
|
7852
|
+
try {
|
|
7853
|
+
const created = await createManualTransfer(apiBaseUrl, {
|
|
7854
|
+
merchantAuthorization,
|
|
7855
|
+
destination,
|
|
7856
|
+
idempotencyKey,
|
|
7857
|
+
source: { chainId: option.chainId, tokenAddress: option.tokenAddress }
|
|
7858
|
+
});
|
|
7859
|
+
const key = perTokenKey(option.chainId, option.tokenAddress);
|
|
7860
|
+
setPerTokenSessions((prev) => ({ ...prev, [key]: created }));
|
|
7861
|
+
const uri = formatDepositUri(created.depositAddress, option.chainId, option.tokenAddress);
|
|
7862
|
+
void getOrRenderQrDataUrl(uri, { dark: tokens.text, light: tokens.bg });
|
|
7863
|
+
} catch (err) {
|
|
7864
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
7865
|
+
} finally {
|
|
7866
|
+
setLoading(false);
|
|
7867
|
+
}
|
|
7868
|
+
}, [apiBaseUrl, destination, idempotencyKey, merchantAuthorization, tokens.text, tokens.bg]);
|
|
7869
|
+
react.useEffect(() => {
|
|
7870
|
+
if (!selectedOption) return;
|
|
7871
|
+
if (sessionsByFamily[selectedOption.chainFamily]) return;
|
|
7872
|
+
if (premintedFamiliesRef.current.has(selectedOption.chainFamily)) return;
|
|
7873
|
+
const key = perTokenKey(selectedOption.chainId, selectedOption.tokenAddress);
|
|
7874
|
+
if (perTokenSessions[key]) return;
|
|
7875
|
+
if (inFlightPerTokenRef.current.has(key)) return;
|
|
7876
|
+
inFlightPerTokenRef.current.add(key);
|
|
7877
|
+
void createSession(selectedOption).finally(() => {
|
|
7878
|
+
inFlightPerTokenRef.current.delete(key);
|
|
7879
|
+
});
|
|
7880
|
+
}, [selectedOption, sessionsByFamily, perTokenSessions, createSession]);
|
|
7881
|
+
const resetSessionForNewSelection = react.useCallback(() => {
|
|
7882
|
+
setError(null);
|
|
7883
|
+
}, []);
|
|
7884
|
+
const selectToken = react.useCallback((value) => {
|
|
7885
|
+
setSelectedToken(value);
|
|
7886
|
+
const pairValid = (sourceOptions ?? []).some(
|
|
7887
|
+
(opt) => opt.tokenSymbol === value && String(opt.chainId) === selectedChainId
|
|
7888
|
+
);
|
|
7889
|
+
if (!pairValid) {
|
|
7890
|
+
const firstChain = (sourceOptions ?? []).find(
|
|
7891
|
+
(opt) => opt.tokenSymbol === value
|
|
7892
|
+
);
|
|
7893
|
+
setSelectedChainId(
|
|
7894
|
+
firstChain ? String(firstChain.chainId) : ""
|
|
7895
|
+
);
|
|
7896
|
+
}
|
|
7897
|
+
}, [selectedChainId, sourceOptions]);
|
|
7898
|
+
const selectChainId = react.useCallback((value) => {
|
|
7899
|
+
setSelectedChainId(value);
|
|
7900
|
+
const pairValid = (sourceOptions ?? []).some(
|
|
7901
|
+
(opt) => opt.tokenSymbol === selectedToken && String(opt.chainId) === value
|
|
7902
|
+
);
|
|
7903
|
+
if (!pairValid) {
|
|
7904
|
+
const firstToken = (sourceOptions ?? []).find(
|
|
7905
|
+
(opt) => String(opt.chainId) === value
|
|
7906
|
+
);
|
|
7907
|
+
setSelectedToken(
|
|
7908
|
+
firstToken ? firstToken.tokenSymbol : ""
|
|
7909
|
+
);
|
|
7910
|
+
}
|
|
7911
|
+
}, [selectedToken, sourceOptions]);
|
|
7912
|
+
const screen = screenForSession(session);
|
|
7913
|
+
const copyDepositAddress = react.useCallback(async (address) => {
|
|
7914
|
+
try {
|
|
7915
|
+
await navigator.clipboard.writeText(address);
|
|
7916
|
+
} catch {
|
|
7917
|
+
const textarea = document.createElement("textarea");
|
|
7918
|
+
textarea.value = address;
|
|
7919
|
+
textarea.setAttribute("readonly", "");
|
|
7920
|
+
textarea.style.position = "absolute";
|
|
7921
|
+
textarea.style.opacity = "0";
|
|
7922
|
+
document.body.appendChild(textarea);
|
|
7923
|
+
textarea.select();
|
|
7924
|
+
try {
|
|
7925
|
+
document.execCommand("copy");
|
|
7926
|
+
} finally {
|
|
7927
|
+
document.body.removeChild(textarea);
|
|
7928
|
+
}
|
|
7929
|
+
}
|
|
7930
|
+
setCopiedAddress(address);
|
|
7931
|
+
window.setTimeout(() => setCopiedAddress((cur) => cur === address ? null : cur), 1500);
|
|
7932
|
+
}, []);
|
|
7933
|
+
const backToSourceSelector = react.useCallback(() => {
|
|
7934
|
+
setCopiedAddress(null);
|
|
7935
|
+
setError(null);
|
|
7936
|
+
if (!selectedOption) return;
|
|
7937
|
+
const family = selectedOption.chainFamily;
|
|
7938
|
+
setSessionsByFamily((prev) => {
|
|
7939
|
+
if (!prev[family]) return prev;
|
|
7940
|
+
const next = { ...prev };
|
|
7941
|
+
delete next[family];
|
|
7942
|
+
return next;
|
|
7943
|
+
});
|
|
7944
|
+
premintedFamiliesRef.current.delete(family);
|
|
7945
|
+
const ptKey = perTokenKey(selectedOption.chainId, selectedOption.tokenAddress);
|
|
7946
|
+
setPerTokenSessions((prev) => {
|
|
7947
|
+
if (!prev[ptKey]) return prev;
|
|
7948
|
+
const next = { ...prev };
|
|
7949
|
+
delete next[ptKey];
|
|
7950
|
+
return next;
|
|
7951
|
+
});
|
|
7952
|
+
}, [selectedOption]);
|
|
7585
7953
|
return {
|
|
7586
|
-
|
|
7587
|
-
|
|
7588
|
-
|
|
7589
|
-
|
|
7954
|
+
sourceOptions,
|
|
7955
|
+
loadingSources,
|
|
7956
|
+
selectedToken,
|
|
7957
|
+
selectedChainId,
|
|
7958
|
+
session,
|
|
7959
|
+
loading,
|
|
7960
|
+
error,
|
|
7961
|
+
qrReady,
|
|
7962
|
+
copiedAddress,
|
|
7963
|
+
tokenChoices,
|
|
7964
|
+
chainChoices,
|
|
7965
|
+
tokenLogoUriBySymbol,
|
|
7966
|
+
selectedOption,
|
|
7967
|
+
tokensForSelectedChain,
|
|
7968
|
+
chainsForSelectedToken,
|
|
7969
|
+
screen,
|
|
7970
|
+
sessionFeeCopy,
|
|
7971
|
+
depositAddress,
|
|
7972
|
+
createSession,
|
|
7973
|
+
copyDepositAddress,
|
|
7974
|
+
backToSourceSelector,
|
|
7975
|
+
resetSessionForNewSelection,
|
|
7976
|
+
selectToken,
|
|
7977
|
+
selectChainId
|
|
7590
7978
|
};
|
|
7591
7979
|
}
|
|
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
|
-
};
|
|
7980
|
+
var ManualTransferSessionContext = react.createContext(null);
|
|
7981
|
+
function ManualTransferSessionProvider({
|
|
7982
|
+
destination,
|
|
7983
|
+
merchantAuthorization,
|
|
7984
|
+
idempotencyKey,
|
|
7985
|
+
onComplete,
|
|
7986
|
+
onError,
|
|
7987
|
+
pollEnabled,
|
|
7988
|
+
children
|
|
7989
|
+
}) {
|
|
7990
|
+
const session = useManualTransferSession({
|
|
7991
|
+
destination,
|
|
7992
|
+
merchantAuthorization,
|
|
7993
|
+
idempotencyKey,
|
|
7994
|
+
onComplete,
|
|
7995
|
+
onError,
|
|
7996
|
+
pollEnabled
|
|
7997
|
+
});
|
|
7998
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ManualTransferSessionContext.Provider, { value: session, children });
|
|
7637
7999
|
}
|
|
7638
|
-
function
|
|
7639
|
-
|
|
7640
|
-
|
|
7641
|
-
|
|
7642
|
-
|
|
7643
|
-
|
|
7644
|
-
|
|
7645
|
-
|
|
7646
|
-
|
|
7647
|
-
|
|
7648
|
-
|
|
7649
|
-
|
|
7650
|
-
|
|
7651
|
-
|
|
7652
|
-
|
|
7653
|
-
|
|
7654
|
-
|
|
8000
|
+
function useManualTransferSessionContext() {
|
|
8001
|
+
const ctx = react.useContext(ManualTransferSessionContext);
|
|
8002
|
+
if (!ctx) {
|
|
8003
|
+
throw new Error(
|
|
8004
|
+
"useManualTransferSessionContext must be used within a <ManualTransferSessionProvider>"
|
|
8005
|
+
);
|
|
8006
|
+
}
|
|
8007
|
+
return ctx;
|
|
8008
|
+
}
|
|
8009
|
+
|
|
8010
|
+
// src/processingStatus.ts
|
|
8011
|
+
var PROCESSING_TIMEOUT_MS = 18e4;
|
|
8012
|
+
var TERMINAL_TRANSFER_STATUSES = /* @__PURE__ */ new Set(["COMPLETED", "FAILED", "EXPIRED"]);
|
|
8013
|
+
var SIGNABLE_TRANSFER_STATUSES = /* @__PURE__ */ new Set(["CREATED", "AUTHORIZED"]);
|
|
8014
|
+
function isTerminalTransferStatus(status) {
|
|
8015
|
+
return TERMINAL_TRANSFER_STATUSES.has(status);
|
|
8016
|
+
}
|
|
8017
|
+
function isTransferSignable(transfer) {
|
|
8018
|
+
return transfer != null && SIGNABLE_TRANSFER_STATUSES.has(transfer.status);
|
|
8019
|
+
}
|
|
8020
|
+
function isTransferAwaitingCompletion(transfer) {
|
|
8021
|
+
if (!transfer) return false;
|
|
8022
|
+
return !isTerminalTransferStatus(transfer.status);
|
|
8023
|
+
}
|
|
8024
|
+
function resolvePreferredTransfer(polledTransfer, localTransfer) {
|
|
8025
|
+
return polledTransfer ?? localTransfer;
|
|
8026
|
+
}
|
|
8027
|
+
function getTransferStatus(polledTransfer, localTransfer) {
|
|
8028
|
+
const transfer = resolvePreferredTransfer(polledTransfer, localTransfer);
|
|
8029
|
+
return transfer?.status ?? "UNKNOWN";
|
|
8030
|
+
}
|
|
8031
|
+
function hasProcessingTimedOut(processingStartedAtMs, nowMs) {
|
|
8032
|
+
if (!processingStartedAtMs) return false;
|
|
8033
|
+
return nowMs - processingStartedAtMs >= PROCESSING_TIMEOUT_MS;
|
|
8034
|
+
}
|
|
8035
|
+
var STATUS_DISPLAY_LABELS = {
|
|
8036
|
+
CREATED: "created",
|
|
8037
|
+
AUTHORIZED: "authorized",
|
|
8038
|
+
SENDING: "sending",
|
|
8039
|
+
SENT: "confirming delivery",
|
|
8040
|
+
COMPLETED: "completed",
|
|
8041
|
+
FAILED: "failed"
|
|
8042
|
+
};
|
|
8043
|
+
function getStatusDisplayLabel(status) {
|
|
8044
|
+
return STATUS_DISPLAY_LABELS[status] ?? status;
|
|
8045
|
+
}
|
|
8046
|
+
function buildProcessingTimeoutMessage(status) {
|
|
8047
|
+
const label = getStatusDisplayLabel(status);
|
|
8048
|
+
return `Payment is taking longer than expected (status: ${label}). Please try again.`;
|
|
8049
|
+
}
|
|
8050
|
+
|
|
8051
|
+
// src/paymentResolvePhase.ts
|
|
8052
|
+
function hasActiveWallet(accounts) {
|
|
8053
|
+
return accounts.some((a) => a.wallets.some((w) => w.status === "ACTIVE"));
|
|
8054
|
+
}
|
|
8055
|
+
function resolveTerminalPhase(state) {
|
|
8056
|
+
if (state.amountTooLow != null) {
|
|
8057
|
+
return {
|
|
8058
|
+
step: "amount-too-low",
|
|
8059
|
+
minAmountUsd: state.amountTooLow.minAmountUsd
|
|
8060
|
+
};
|
|
8061
|
+
}
|
|
8062
|
+
const transferCompleted = state.transfer?.status === "COMPLETED";
|
|
8063
|
+
const needsPasskeyBootstrap = state.privyAuthenticated && !state.activeCredentialId;
|
|
8064
|
+
if (transferCompleted && !needsPasskeyBootstrap && !state.loginRequested) {
|
|
8065
|
+
return { step: "completed", transfer: state.transfer };
|
|
8066
|
+
}
|
|
8067
|
+
if (state.transfer?.status === "FAILED") {
|
|
8068
|
+
return {
|
|
8069
|
+
step: "failed",
|
|
8070
|
+
transfer: state.transfer,
|
|
8071
|
+
error: state.error ?? "Transfer failed."
|
|
8072
|
+
};
|
|
8073
|
+
}
|
|
8074
|
+
if (state.creatingTransfer || isTransferAwaitingCompletion(state.transfer)) {
|
|
8075
|
+
return { step: "processing", transfer: state.transfer };
|
|
8076
|
+
}
|
|
8077
|
+
return null;
|
|
8078
|
+
}
|
|
8079
|
+
function resolveStickyPhase(state) {
|
|
8080
|
+
const currentPhase = state.phase;
|
|
8081
|
+
if (currentPhase.step === "manual-transfer" && !state.loginRequested) {
|
|
8082
|
+
return currentPhase;
|
|
8083
|
+
}
|
|
8084
|
+
if (currentPhase.step === "deposit-options" && !state.loginRequested && !state.privyAuthenticated) {
|
|
8085
|
+
return currentPhase;
|
|
8086
|
+
}
|
|
8087
|
+
if (!state.loginRequested && state.setupFlowScreen === "one-tap-setup") {
|
|
8088
|
+
return { step: "one-tap-setup", action: null };
|
|
8089
|
+
}
|
|
8090
|
+
if (!state.loginRequested && state.setupFlowScreen === "deposit-confirm" && state.selectedAccountId != null) {
|
|
8091
|
+
return {
|
|
8092
|
+
step: "wallet-setup",
|
|
8093
|
+
mobile: null,
|
|
8094
|
+
accountId: state.selectedAccountId
|
|
8095
|
+
};
|
|
8096
|
+
}
|
|
8097
|
+
if (!state.loginRequested && state.mobileTokenAuthorizationPending) {
|
|
8098
|
+
return {
|
|
8099
|
+
step: "wallet-setup",
|
|
8100
|
+
mobile: { deeplinkUri: "", providerId: state.selectedProviderId },
|
|
8101
|
+
accountId: null
|
|
8102
|
+
};
|
|
8103
|
+
}
|
|
8104
|
+
const isFundingSourceSubflow = !state.loginRequested && (currentPhase.step === "token-picker" || currentPhase.step === "guest-source-picker" || currentPhase.step === "select-source" || currentPhase.step === "confirm-sign");
|
|
8105
|
+
if (isFundingSourceSubflow) {
|
|
8106
|
+
return currentPhase;
|
|
8107
|
+
}
|
|
8108
|
+
if ((state.standardDesktopInlineOpenWallet || state.desktopWait != null) && state.privyAuthenticated && state.activeCredentialId != null && state.selectedAccountId != null && !state.loginRequested) {
|
|
8109
|
+
return {
|
|
8110
|
+
step: "wallet-setup",
|
|
8111
|
+
mobile: null,
|
|
8112
|
+
desktopWait: state.desktopWait,
|
|
8113
|
+
accountId: state.selectedAccountId
|
|
8114
|
+
};
|
|
8115
|
+
}
|
|
8116
|
+
if (state.mobileFlow && state.deeplinkUri != null) {
|
|
8117
|
+
return {
|
|
8118
|
+
step: "wallet-setup",
|
|
8119
|
+
mobile: { deeplinkUri: state.deeplinkUri, providerId: state.selectedProviderId },
|
|
8120
|
+
accountId: null
|
|
8121
|
+
};
|
|
8122
|
+
}
|
|
8123
|
+
if (currentPhase.step === "wallet-picker" && currentPhase.reason === "switch" && !state.creatingTransfer && !(state.mobileFlow && state.deeplinkUri)) {
|
|
8124
|
+
return currentPhase;
|
|
8125
|
+
}
|
|
8126
|
+
return null;
|
|
8127
|
+
}
|
|
8128
|
+
function deriveFreshPhase(state) {
|
|
8129
|
+
if (!state.privyReady) {
|
|
8130
|
+
return { step: "initializing" };
|
|
8131
|
+
}
|
|
8132
|
+
if (state.privyAuthenticated && !state.activeCredentialId && !state.passkeyConfigLoaded) {
|
|
8133
|
+
return { step: "initializing" };
|
|
8134
|
+
}
|
|
8135
|
+
if (state.loginRequested) {
|
|
8136
|
+
return { step: "login" };
|
|
8137
|
+
}
|
|
8138
|
+
if (state.enableFullWidget && !state.privyAuthenticated) {
|
|
8139
|
+
return { step: "deposit-options" };
|
|
8140
|
+
}
|
|
8141
|
+
if (!state.privyAuthenticated) {
|
|
8142
|
+
return { step: "login" };
|
|
8143
|
+
}
|
|
8144
|
+
if (state.loadingData && state.activeCredentialId != null) {
|
|
8145
|
+
return { step: "data-loading" };
|
|
8146
|
+
}
|
|
8147
|
+
if (state.requireAmountEntry) {
|
|
8148
|
+
return { step: "enter-amount" };
|
|
8149
|
+
}
|
|
8150
|
+
if (state.activeCredentialId != null && !hasActiveWallet(state.accounts) && !state.mobileFlow) {
|
|
8151
|
+
return { step: "wallet-picker", reason: "link" };
|
|
8152
|
+
}
|
|
8153
|
+
if (state.activeCredentialId != null && hasActiveWallet(state.accounts) && !state.loadingData) {
|
|
8154
|
+
return { step: "deposit" };
|
|
8155
|
+
}
|
|
8156
|
+
return { step: "wallet-picker", reason: "entry" };
|
|
8157
|
+
}
|
|
8158
|
+
function resolvePhase(state) {
|
|
8159
|
+
return resolveTerminalPhase(state) ?? resolveStickyPhase(state) ?? deriveFreshPhase(state);
|
|
8160
|
+
}
|
|
8161
|
+
|
|
8162
|
+
// src/paymentReducer.ts
|
|
8163
|
+
var DEFAULT_ONE_TAP_LIMIT = 1e4;
|
|
8164
|
+
function deriveSourceTypeAndId(state) {
|
|
8165
|
+
if (state.selectedWalletId) {
|
|
8166
|
+
return { sourceType: "walletId", sourceId: state.selectedWalletId };
|
|
8167
|
+
}
|
|
8168
|
+
if (state.selectedAccountId) {
|
|
8169
|
+
return { sourceType: "accountId", sourceId: state.selectedAccountId };
|
|
8170
|
+
}
|
|
8171
|
+
return { sourceType: "accountId", sourceId: "" };
|
|
8172
|
+
}
|
|
8173
|
+
function clearStaleSelection(state) {
|
|
8174
|
+
if (state.selectedAccountId == null) return state;
|
|
8175
|
+
if (state.desktopWait != null) return state;
|
|
8176
|
+
const stillExists = state.accounts.some((a) => a.id === state.selectedAccountId);
|
|
8177
|
+
if (stillExists) return state;
|
|
8178
|
+
return {
|
|
8179
|
+
...state,
|
|
8180
|
+
selectedAccountId: null,
|
|
8181
|
+
selectedWalletId: null,
|
|
8182
|
+
selectedTokenSymbol: null
|
|
8183
|
+
};
|
|
8184
|
+
}
|
|
8185
|
+
function createInitialState(config) {
|
|
8186
|
+
return {
|
|
8187
|
+
phase: config.initialPhase ?? { step: "initializing" },
|
|
8188
|
+
error: null,
|
|
8189
|
+
setupFlowScreen: null,
|
|
8190
|
+
providers: [],
|
|
8191
|
+
accounts: [],
|
|
8192
|
+
chains: [],
|
|
8193
|
+
loadingData: false,
|
|
8194
|
+
depositSelectionRefreshing: false,
|
|
8195
|
+
selectedProviderId: null,
|
|
8196
|
+
selectedAccountId: null,
|
|
8197
|
+
selectedWalletId: null,
|
|
8198
|
+
selectedTokenSymbol: null,
|
|
8199
|
+
savedSelection: null,
|
|
8200
|
+
amount: config.depositAmount != null ? config.depositAmount.toString() : "",
|
|
8201
|
+
transfer: null,
|
|
8202
|
+
pendingTransferId: null,
|
|
8203
|
+
creatingTransfer: false,
|
|
8204
|
+
passkeyConfigLoaded: false,
|
|
8205
|
+
activeCredentialId: config.activeCredentialId,
|
|
8206
|
+
knownCredentialIds: [],
|
|
8207
|
+
oneTapLimit: DEFAULT_ONE_TAP_LIMIT,
|
|
8208
|
+
oneTapLimitSavedDuringSetup: false,
|
|
8209
|
+
mobileFlow: false,
|
|
8210
|
+
deeplinkUri: null,
|
|
8211
|
+
increasingLimit: false,
|
|
8212
|
+
activePublicKey: null,
|
|
8213
|
+
loginRequested: false,
|
|
8214
|
+
standardDesktopInlineOpenWallet: false,
|
|
8215
|
+
desktopWait: null,
|
|
8216
|
+
setupAuthorizationSessionId: null,
|
|
8217
|
+
mobileTokenAuthorizationPending: false,
|
|
8218
|
+
privyReady: false,
|
|
8219
|
+
privyAuthenticated: false,
|
|
8220
|
+
lastResumedAt: 0,
|
|
8221
|
+
setupDepositAmount: null,
|
|
8222
|
+
setupDepositToken: null,
|
|
8223
|
+
setupDepositConfirmed: false,
|
|
8224
|
+
guestWalletPrepared: null,
|
|
8225
|
+
guestWalletDeeplinksPreparing: false,
|
|
8226
|
+
amountTooLow: null,
|
|
8227
|
+
enableFullWidget: config.enableFullWidget ?? false,
|
|
8228
|
+
requireAmountEntry: config.depositAmount == null
|
|
8229
|
+
};
|
|
8230
|
+
}
|
|
8231
|
+
function clearAuthenticatedSessionState(state) {
|
|
8232
|
+
return {
|
|
8233
|
+
...state,
|
|
8234
|
+
error: null,
|
|
8235
|
+
setupFlowScreen: null,
|
|
8236
|
+
providers: [],
|
|
8237
|
+
accounts: [],
|
|
8238
|
+
chains: [],
|
|
8239
|
+
loadingData: false,
|
|
8240
|
+
depositSelectionRefreshing: false,
|
|
8241
|
+
selectedProviderId: null,
|
|
8242
|
+
selectedAccountId: null,
|
|
8243
|
+
selectedWalletId: null,
|
|
8244
|
+
selectedTokenSymbol: null,
|
|
8245
|
+
savedSelection: null,
|
|
8246
|
+
transfer: null,
|
|
8247
|
+
pendingTransferId: null,
|
|
7655
8248
|
creatingTransfer: false,
|
|
7656
8249
|
passkeyConfigLoaded: false,
|
|
7657
8250
|
activeCredentialId: null,
|
|
@@ -8095,552 +8688,118 @@ function applyAction(state, action) {
|
|
|
8095
8688
|
// unauthenticated path) preserves the flag implicitly via the
|
|
8096
8689
|
// surrounding `...state` spread, so no change is needed there.
|
|
8097
8690
|
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);
|
|
8691
|
+
};
|
|
8692
|
+
case "SYNC_PRIVY_SESSION":
|
|
8693
|
+
if (action.ready && !action.authenticated) {
|
|
8694
|
+
return {
|
|
8695
|
+
...clearAuthenticatedSessionState(state),
|
|
8696
|
+
privyReady: true,
|
|
8697
|
+
privyAuthenticated: false
|
|
8698
|
+
};
|
|
8506
8699
|
}
|
|
8700
|
+
return {
|
|
8701
|
+
...state,
|
|
8702
|
+
privyReady: action.ready,
|
|
8703
|
+
privyAuthenticated: action.authenticated,
|
|
8704
|
+
...action.authenticated ? { loginRequested: false } : {}
|
|
8705
|
+
};
|
|
8706
|
+
case "SYNC_AMOUNT":
|
|
8707
|
+
return {
|
|
8708
|
+
...state,
|
|
8709
|
+
amount: action.amount,
|
|
8710
|
+
requireAmountEntry: action.amount === "" ? state.requireAmountEntry : false
|
|
8711
|
+
};
|
|
8712
|
+
case "SET_AMOUNT_INPUT":
|
|
8713
|
+
return { ...state, amount: action.value };
|
|
8714
|
+
case "FINALIZE_AMOUNT":
|
|
8715
|
+
return { ...state, requireAmountEntry: false };
|
|
8716
|
+
case "PAGE_RESUMED":
|
|
8717
|
+
return { ...state, lastResumedAt: Date.now() };
|
|
8718
|
+
// ── Setup deposit (combined first-time flow) ────────────────
|
|
8719
|
+
case "SET_SETUP_DEPOSIT_AMOUNT":
|
|
8720
|
+
return { ...state, setupDepositAmount: action.amount };
|
|
8721
|
+
case "SET_SETUP_DEPOSIT_TOKEN":
|
|
8722
|
+
return {
|
|
8723
|
+
...state,
|
|
8724
|
+
setupDepositToken: {
|
|
8725
|
+
symbol: action.symbol,
|
|
8726
|
+
chainName: action.chainName,
|
|
8727
|
+
...action.walletId ? { walletId: action.walletId } : {},
|
|
8728
|
+
...action.tokenAddress ? { tokenAddress: action.tokenAddress } : {},
|
|
8729
|
+
...action.chainId != null ? { chainId: action.chainId } : {}
|
|
8730
|
+
}
|
|
8731
|
+
};
|
|
8732
|
+
case "CLEAR_SETUP_DEPOSIT_TOKEN":
|
|
8733
|
+
return { ...state, setupDepositToken: null };
|
|
8734
|
+
case "CONFIRM_SETUP_DEPOSIT":
|
|
8735
|
+
return { ...state, setupDepositConfirmed: true };
|
|
8736
|
+
default:
|
|
8737
|
+
return state;
|
|
8738
|
+
}
|
|
8739
|
+
}
|
|
8740
|
+
|
|
8741
|
+
// src/setupDepositConfirmation.ts
|
|
8742
|
+
function deriveEffectiveSetupSource(setupDepositToken, setupSelectedSourceOption) {
|
|
8743
|
+
if (setupDepositToken) return setupDepositToken;
|
|
8744
|
+
if (setupSelectedSourceOption) {
|
|
8745
|
+
return {
|
|
8746
|
+
symbol: setupSelectedSourceOption.tokenSymbol,
|
|
8747
|
+
chainName: setupSelectedSourceOption.chainName,
|
|
8748
|
+
walletId: setupSelectedSourceOption.walletId,
|
|
8749
|
+
tokenAddress: setupSelectedSourceOption.tokenAddress,
|
|
8750
|
+
chainId: setupSelectedSourceOption.chainId != null ? Number(setupSelectedSourceOption.chainId) : void 0
|
|
8751
|
+
};
|
|
8752
|
+
}
|
|
8753
|
+
return null;
|
|
8754
|
+
}
|
|
8755
|
+
function planConfirmSetupDeposit(input) {
|
|
8756
|
+
const effective = deriveEffectiveSetupSource(
|
|
8757
|
+
input.setupDepositToken,
|
|
8758
|
+
input.setupSelectedSourceOption
|
|
8759
|
+
);
|
|
8760
|
+
if (!effective) {
|
|
8761
|
+
return { kind: "error", error: "Select a source token before continuing." };
|
|
8762
|
+
}
|
|
8763
|
+
if (!effective.walletId) {
|
|
8764
|
+
return {
|
|
8765
|
+
kind: "error",
|
|
8766
|
+
error: "Selected source is not ready yet. Wait for wallet discovery to finish."
|
|
8767
|
+
};
|
|
8768
|
+
}
|
|
8769
|
+
const actions = [
|
|
8770
|
+
{ type: "SET_ERROR", error: null },
|
|
8771
|
+
{
|
|
8772
|
+
type: "SET_SETUP_DEPOSIT_TOKEN",
|
|
8773
|
+
symbol: effective.symbol,
|
|
8774
|
+
chainName: effective.chainName,
|
|
8775
|
+
walletId: effective.walletId,
|
|
8776
|
+
tokenAddress: effective.tokenAddress,
|
|
8777
|
+
chainId: effective.chainId
|
|
8507
8778
|
}
|
|
8508
|
-
|
|
8509
|
-
|
|
8510
|
-
|
|
8511
|
-
|
|
8512
|
-
|
|
8513
|
-
|
|
8514
|
-
|
|
8515
|
-
|
|
8516
|
-
|
|
8517
|
-
|
|
8518
|
-
|
|
8519
|
-
|
|
8779
|
+
];
|
|
8780
|
+
if (input.selectedAccountId) {
|
|
8781
|
+
actions.push({
|
|
8782
|
+
type: "SELECT_ACCOUNT",
|
|
8783
|
+
accountId: input.selectedAccountId,
|
|
8784
|
+
walletId: effective.walletId
|
|
8785
|
+
});
|
|
8786
|
+
actions.push({
|
|
8787
|
+
type: "SELECT_TOKEN",
|
|
8788
|
+
walletId: effective.walletId,
|
|
8789
|
+
tokenSymbol: effective.symbol
|
|
8790
|
+
});
|
|
8791
|
+
}
|
|
8792
|
+
actions.push({ type: "SET_SETUP_FLOW_SCREEN", screen: "one-tap-setup" });
|
|
8793
|
+
actions.push({ type: "CONFIRM_SETUP_DEPOSIT" });
|
|
8520
8794
|
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
|
|
8795
|
+
kind: "proceed",
|
|
8796
|
+
actions,
|
|
8797
|
+
resolveSource: {
|
|
8798
|
+
chainName: effective.chainName,
|
|
8799
|
+
tokenSymbol: effective.symbol
|
|
8800
|
+
}
|
|
8546
8801
|
};
|
|
8547
8802
|
}
|
|
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
8803
|
function ScreenLayout({ children, footer }) {
|
|
8645
8804
|
const { tokens, theme, isMobileApp } = useBlinkConfig();
|
|
8646
8805
|
const isRedesign = theme.endsWith("New");
|
|
@@ -10355,16 +10514,21 @@ function DepositQrCodeImpl({
|
|
|
10355
10514
|
depToken
|
|
10356
10515
|
}) {
|
|
10357
10516
|
const { tokens } = useBlinkConfig();
|
|
10358
|
-
const [dataUrl, setDataUrl] = react.useState(null);
|
|
10359
10517
|
const uri = formatDepositUri(address, chainId, depToken);
|
|
10518
|
+
const dark = tokens.text;
|
|
10519
|
+
const light = tokens.bg;
|
|
10520
|
+
const [dataUrl, setDataUrl] = react.useState(
|
|
10521
|
+
() => getCachedQrDataUrl(uri, { dark, light })
|
|
10522
|
+
);
|
|
10360
10523
|
react.useEffect(() => {
|
|
10524
|
+
const cached = getCachedQrDataUrl(uri, { dark, light });
|
|
10525
|
+
if (cached) {
|
|
10526
|
+
setDataUrl(cached);
|
|
10527
|
+
return;
|
|
10528
|
+
}
|
|
10361
10529
|
let cancelled = false;
|
|
10362
|
-
|
|
10363
|
-
|
|
10364
|
-
margin: 1,
|
|
10365
|
-
width: 203,
|
|
10366
|
-
color: { dark: tokens.text, light: tokens.bg }
|
|
10367
|
-
}).then((url) => {
|
|
10530
|
+
setDataUrl(null);
|
|
10531
|
+
getOrRenderQrDataUrl(uri, { dark, light }).then((url) => {
|
|
10368
10532
|
if (!cancelled) setDataUrl(url);
|
|
10369
10533
|
}).catch(() => {
|
|
10370
10534
|
if (!cancelled) setDataUrl(null);
|
|
@@ -10372,7 +10536,7 @@ function DepositQrCodeImpl({
|
|
|
10372
10536
|
return () => {
|
|
10373
10537
|
cancelled = true;
|
|
10374
10538
|
};
|
|
10375
|
-
}, [uri]);
|
|
10539
|
+
}, [uri, dark, light]);
|
|
10376
10540
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: qrFrameStyle(tokens.bgCardTranslucent), children: dataUrl ? /* @__PURE__ */ jsxRuntime.jsxs("div", { style: qrContainerStyle, children: [
|
|
10377
10541
|
/* @__PURE__ */ jsxRuntime.jsx("img", { src: dataUrl, alt: "Deposit QR code", style: qrImageStyle }),
|
|
10378
10542
|
/* @__PURE__ */ jsxRuntime.jsx("img", { src: BLINK_QR_LOGO, alt: "", style: qrLogoStyle })
|
|
@@ -11460,7 +11624,7 @@ function EnterAmountScreen({
|
|
|
11460
11624
|
)
|
|
11461
11625
|
] }),
|
|
11462
11626
|
children: [
|
|
11463
|
-
/* @__PURE__ */ jsxRuntime.jsx(ScreenHeader, { right: headerRight }),
|
|
11627
|
+
/* @__PURE__ */ jsxRuntime.jsx(ScreenHeader, { title: "Deposit", right: headerRight }),
|
|
11464
11628
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: contentStyle4(isDesktop), children: [
|
|
11465
11629
|
isDesktop ? /* @__PURE__ */ jsxRuntime.jsxs("div", { style: desktopHeroRowStyle(heroColor, getDesktopHeroFontSize(value)), children: [
|
|
11466
11630
|
/* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", style: dollarStyle2(isZero), children: "$" }),
|
|
@@ -12801,7 +12965,8 @@ function SetupScreen({
|
|
|
12801
12965
|
onLogout,
|
|
12802
12966
|
loading,
|
|
12803
12967
|
loadingShimmersEnabled = false,
|
|
12804
|
-
error
|
|
12968
|
+
error,
|
|
12969
|
+
selectedTokenSymbol
|
|
12805
12970
|
}) {
|
|
12806
12971
|
const { tokens } = useBlinkConfig();
|
|
12807
12972
|
const [selectedPreset, setSelectedPreset] = react.useState(DEFAULT_MAX);
|
|
@@ -12910,7 +13075,8 @@ function SetupScreen({
|
|
|
12910
13075
|
style: illustrationStyle3
|
|
12911
13076
|
}
|
|
12912
13077
|
),
|
|
12913
|
-
/* @__PURE__ */ jsxRuntime.jsx("h2", { style: headingStyle7(tokens.text), children:
|
|
13078
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { style: headingStyle7(tokens.text), children: `Next time deposit
|
|
13079
|
+
${selectedTokenSymbol ?? "USDC"} in one tap` }),
|
|
12914
13080
|
/* @__PURE__ */ jsxRuntime.jsx("p", { style: subtitleStyle5(tokens.textSecondary), children: "Set a cap for passkey deposits.\nYou always stay in control." }),
|
|
12915
13081
|
error && /* @__PURE__ */ jsxRuntime.jsx("div", { style: errorBannerStyle5(tokens), children: error }),
|
|
12916
13082
|
/* @__PURE__ */ jsxRuntime.jsx("div", { style: chipsRowStyle, children: PRESETS.map(({ label, value }) => {
|
|
@@ -12938,8 +13104,8 @@ var contentStyle9 = {
|
|
|
12938
13104
|
alignItems: "center",
|
|
12939
13105
|
justifyContent: "center",
|
|
12940
13106
|
textAlign: "center",
|
|
12941
|
-
gap:
|
|
12942
|
-
padding: "
|
|
13107
|
+
gap: 12,
|
|
13108
|
+
padding: "8px 0"
|
|
12943
13109
|
};
|
|
12944
13110
|
var shimmerContentStyle = {
|
|
12945
13111
|
display: "flex",
|
|
@@ -13310,7 +13476,7 @@ function SetupDepositScreen({
|
|
|
13310
13476
|
NotificationBanner,
|
|
13311
13477
|
{
|
|
13312
13478
|
variant: "negative",
|
|
13313
|
-
title: "Deposit amount exceeds balance",
|
|
13479
|
+
title: "Deposit amount exceeds stablecoin balance",
|
|
13314
13480
|
description: "Pick another asset or add more funds to your wallet"
|
|
13315
13481
|
}
|
|
13316
13482
|
) : /* @__PURE__ */ jsxRuntime.jsx(NotificationBanner, { title: "Something went wrong", description: error }) })
|
|
@@ -13928,7 +14094,7 @@ function DepositScreen({
|
|
|
13928
14094
|
NotificationBanner,
|
|
13929
14095
|
{
|
|
13930
14096
|
variant: "negative",
|
|
13931
|
-
title: "Deposit amount exceeds balance",
|
|
14097
|
+
title: "Deposit amount exceeds stablecoin balance",
|
|
13932
14098
|
description: "Pick another asset or add more funds to your wallet"
|
|
13933
14099
|
}
|
|
13934
14100
|
) : needsAuthorization ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -14850,12 +15016,12 @@ function DepositAddressScreen({
|
|
|
14850
15016
|
),
|
|
14851
15017
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: contentStyle16, children: [
|
|
14852
15018
|
/* @__PURE__ */ jsxRuntime.jsx("h2", { style: depositTitleStyle(tokens.text), children: "Deposit Address" }),
|
|
14853
|
-
qrReady && session ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
15019
|
+
qrReady && session && selectedOption ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
14854
15020
|
DepositQrCode,
|
|
14855
15021
|
{
|
|
14856
15022
|
address: session.depositAddress,
|
|
14857
|
-
chainId:
|
|
14858
|
-
depToken:
|
|
15023
|
+
chainId: selectedOption.chainId,
|
|
15024
|
+
depToken: selectedOption.tokenAddress
|
|
14859
15025
|
}
|
|
14860
15026
|
) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
14861
15027
|
/* @__PURE__ */ jsxRuntime.jsx("style", { children: `
|
|
@@ -15874,12 +16040,7 @@ var errorBannerStyle8 = (themeTokens) => ({
|
|
|
15874
16040
|
textAlign: "left"
|
|
15875
16041
|
});
|
|
15876
16042
|
function ManualTransferFlow({
|
|
15877
|
-
|
|
15878
|
-
merchantAuthorization,
|
|
15879
|
-
idempotencyKey,
|
|
15880
|
-
mock = false,
|
|
15881
|
-
onComplete,
|
|
15882
|
-
onError,
|
|
16043
|
+
hasMerchantAuthorization,
|
|
15883
16044
|
onCreatePasskey,
|
|
15884
16045
|
createPasskeyLoading = false,
|
|
15885
16046
|
createPasskeyError = null,
|
|
@@ -15908,17 +16069,9 @@ function ManualTransferFlow({
|
|
|
15908
16069
|
depositAddress,
|
|
15909
16070
|
copyDepositAddress,
|
|
15910
16071
|
backToSourceSelector,
|
|
15911
|
-
advanceMockStatus,
|
|
15912
16072
|
selectToken,
|
|
15913
16073
|
selectChainId
|
|
15914
|
-
} =
|
|
15915
|
-
destination,
|
|
15916
|
-
merchantAuthorization,
|
|
15917
|
-
idempotencyKey,
|
|
15918
|
-
mock,
|
|
15919
|
-
onComplete,
|
|
15920
|
-
onError
|
|
15921
|
-
});
|
|
16074
|
+
} = useManualTransferSessionContext();
|
|
15922
16075
|
const [passkeyCreated, setPasskeyCreated] = react.useState(false);
|
|
15923
16076
|
const prevPasskeyLoadingRef = react.useRef(false);
|
|
15924
16077
|
react.useEffect(() => {
|
|
@@ -15927,9 +16080,8 @@ function ManualTransferFlow({
|
|
|
15927
16080
|
}
|
|
15928
16081
|
prevPasskeyLoadingRef.current = createPasskeyLoading;
|
|
15929
16082
|
}, [createPasskeyLoading, createPasskeyError]);
|
|
15930
|
-
const DEV_MOCK_STATUS = mock;
|
|
15931
16083
|
let screenContent = null;
|
|
15932
|
-
if (!
|
|
16084
|
+
if (!hasMerchantAuthorization) {
|
|
15933
16085
|
screenContent = /* @__PURE__ */ jsxRuntime.jsxs(ScreenLayout, { footer: /* @__PURE__ */ jsxRuntime.jsx(PrimaryButton, { onClick: onBack, children: "Back" }), children: [
|
|
15934
16086
|
/* @__PURE__ */ jsxRuntime.jsx(ScreenHeader, { onBack }),
|
|
15935
16087
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: contentStyle20, children: [
|
|
@@ -15999,17 +16151,7 @@ function ManualTransferFlow({
|
|
|
15999
16151
|
if (!screenContent) {
|
|
16000
16152
|
return null;
|
|
16001
16153
|
}
|
|
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
|
-
] });
|
|
16154
|
+
return screenContent;
|
|
16013
16155
|
}
|
|
16014
16156
|
var contentStyle20 = {
|
|
16015
16157
|
alignItems: "center",
|
|
@@ -16309,6 +16451,7 @@ function buildSetupDepositScreenProps({
|
|
|
16309
16451
|
function buildSetupScreenProps({
|
|
16310
16452
|
flow,
|
|
16311
16453
|
remote,
|
|
16454
|
+
derived,
|
|
16312
16455
|
forms,
|
|
16313
16456
|
handlers
|
|
16314
16457
|
}) {
|
|
@@ -16317,11 +16460,12 @@ function buildSetupScreenProps({
|
|
|
16317
16460
|
const waitingForDesktopWalletConnection = flow.isDesktop && remote.authExecutorExecuting && remote.pendingOneTapSetup == null && (remote.authExecutorCurrentAction == null || remote.authExecutorCurrentAction.type === "OPEN_PROVIDER");
|
|
16318
16461
|
return {
|
|
16319
16462
|
onSetupOneTap: handlers.onSetupOneTap,
|
|
16320
|
-
onBack: handlers.onBackFromSubflow,
|
|
16321
|
-
onLogout: handlers.onLogout,
|
|
16463
|
+
onBack: flow.isDesktop ? handlers.onBackFromSubflow : void 0,
|
|
16464
|
+
onLogout: flow.isDesktop ? handlers.onLogout : void 0,
|
|
16322
16465
|
loading: savingOneTapLimit,
|
|
16323
16466
|
loadingShimmersEnabled: waitingForDesktopWalletConnection,
|
|
16324
|
-
error: state.error
|
|
16467
|
+
error: state.error,
|
|
16468
|
+
selectedTokenSymbol: derived.selectedSource?.token.symbol
|
|
16325
16469
|
};
|
|
16326
16470
|
}
|
|
16327
16471
|
function buildConfirmSignScreenProps({
|
|
@@ -16598,12 +16742,7 @@ function StepRendererContent({
|
|
|
16598
16742
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
16599
16743
|
ManualTransferFlow,
|
|
16600
16744
|
{
|
|
16601
|
-
|
|
16602
|
-
merchantAuthorization: flow.merchantAuthorization,
|
|
16603
|
-
idempotencyKey: flow.idempotencyKey,
|
|
16604
|
-
mock: flow.mock,
|
|
16605
|
-
onComplete: flow.onComplete,
|
|
16606
|
-
onError: flow.onError,
|
|
16745
|
+
hasMerchantAuthorization: flow.merchantAuthorization != null,
|
|
16607
16746
|
onCreatePasskey: handlers.onSignupWithPasskey,
|
|
16608
16747
|
createPasskeyLoading: flow.passkeyLoading,
|
|
16609
16748
|
createPasskeyError: flow.state.error,
|
|
@@ -18821,8 +18960,11 @@ function usePasskeyCheckEffect(deps) {
|
|
|
18821
18960
|
setupAccountIdRef,
|
|
18822
18961
|
reauthSessionIdRef,
|
|
18823
18962
|
reauthTokenRef,
|
|
18824
|
-
pollingTransferIdRef
|
|
18963
|
+
pollingTransferIdRef,
|
|
18964
|
+
reloadAccounts
|
|
18825
18965
|
} = deps;
|
|
18966
|
+
const reloadAccountsRef = react.useRef(reloadAccounts);
|
|
18967
|
+
reloadAccountsRef.current = reloadAccounts;
|
|
18826
18968
|
const { getAccessToken: privyGetAccessToken, user } = reactAuth.usePrivy();
|
|
18827
18969
|
const effectiveGetAccessToken = deps.getAccessToken ?? privyGetAccessToken;
|
|
18828
18970
|
const onCompleteRef = react.useRef(deps.onComplete);
|
|
@@ -18952,6 +19094,11 @@ function usePasskeyCheckEffect(deps) {
|
|
|
18952
19094
|
mobileSetupFlowRef.current = false;
|
|
18953
19095
|
setupAccountIdRef.current = null;
|
|
18954
19096
|
clearMobileFlowState();
|
|
19097
|
+
try {
|
|
19098
|
+
await reloadAccountsRef.current();
|
|
19099
|
+
} catch {
|
|
19100
|
+
}
|
|
19101
|
+
dispatch({ type: "MOBILE_SETUP_COMPLETE" });
|
|
18955
19102
|
return;
|
|
18956
19103
|
}
|
|
18957
19104
|
if (persisted.accountId && !persisted.transferId) {
|
|
@@ -18960,7 +19107,14 @@ function usePasskeyCheckEffect(deps) {
|
|
|
18960
19107
|
const session = await fetchAuthorizationSession(apiBaseUrl, persisted.sessionId);
|
|
18961
19108
|
if (cancelled) return;
|
|
18962
19109
|
if (session.status === "AUTHORIZED") {
|
|
19110
|
+
mobileSetupFlowRef.current = false;
|
|
19111
|
+
setupAccountIdRef.current = null;
|
|
18963
19112
|
clearMobileFlowState();
|
|
19113
|
+
try {
|
|
19114
|
+
await reloadAccountsRef.current();
|
|
19115
|
+
} catch {
|
|
19116
|
+
}
|
|
19117
|
+
dispatch({ type: "MOBILE_SETUP_COMPLETE" });
|
|
18964
19118
|
return;
|
|
18965
19119
|
}
|
|
18966
19120
|
} catch {
|
|
@@ -19425,25 +19579,24 @@ function useMobilePollingEffect(deps) {
|
|
|
19425
19579
|
dispatch({ type: "MOBILE_SETUP_COMPLETE" });
|
|
19426
19580
|
};
|
|
19427
19581
|
const pollWalletActive = async () => {
|
|
19582
|
+
if (setupSessionId) {
|
|
19583
|
+
try {
|
|
19584
|
+
const session = await fetchAuthorizationSession(apiBaseUrl, setupSessionId);
|
|
19585
|
+
if (cancelled) return;
|
|
19586
|
+
if (session.status === "AUTHORIZED") {
|
|
19587
|
+
await completeSetup();
|
|
19588
|
+
return;
|
|
19589
|
+
}
|
|
19590
|
+
} catch {
|
|
19591
|
+
}
|
|
19592
|
+
}
|
|
19428
19593
|
try {
|
|
19429
19594
|
const token = await getAccessTokenRef.current();
|
|
19430
19595
|
if (!token || cancelled) return;
|
|
19431
19596
|
const acct = await fetchAccount(apiBaseUrl, token, accountId, credentialId);
|
|
19432
19597
|
if (cancelled) return;
|
|
19433
|
-
|
|
19434
|
-
if (hasActive) {
|
|
19598
|
+
if (acct.wallets.some((w) => w.status === "ACTIVE")) {
|
|
19435
19599
|
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
19600
|
}
|
|
19448
19601
|
} catch {
|
|
19449
19602
|
}
|
|
@@ -19878,7 +20031,6 @@ function BlinkPayment(props) {
|
|
|
19878
20031
|
function BlinkPaymentInner({
|
|
19879
20032
|
destination,
|
|
19880
20033
|
initialScreen,
|
|
19881
|
-
mock,
|
|
19882
20034
|
onComplete,
|
|
19883
20035
|
onError,
|
|
19884
20036
|
useWalletConnector: useWalletConnectorProp,
|
|
@@ -19967,6 +20119,7 @@ function BlinkPaymentInner({
|
|
|
19967
20119
|
minTransferAmountUsd: effectiveMinDepositAmountUsd
|
|
19968
20120
|
});
|
|
19969
20121
|
const feeEstimateEnabled = effectiveAuthenticated && (state.phase.step === "deposit" || state.phase.step === "wallet-setup" || state.phase.step === "one-tap-setup");
|
|
20122
|
+
const manualTransferActive = screenForPhase(state.phase) === "manual-transfer";
|
|
19970
20123
|
const setupSelectedSourceOption = react.useMemo(() => {
|
|
19971
20124
|
const options = sourceSelection.pendingSelectSourceAction?.metadata?.options ?? [];
|
|
19972
20125
|
return resolveSelectSourceOption(
|
|
@@ -20113,13 +20266,14 @@ function BlinkPaymentInner({
|
|
|
20113
20266
|
idempotencyKey
|
|
20114
20267
|
});
|
|
20115
20268
|
const accountSwitchSessionId = state.setupAuthorizationSessionId;
|
|
20269
|
+
const accountSwitchListenerArmed = accountSwitchSessionId != null && state.desktopWait == null;
|
|
20116
20270
|
const handleProviderWalletAccountSwitch = provider.handleWalletAccountSwitch;
|
|
20117
20271
|
const onWalletAccountChanged = react.useCallback(async (change) => {
|
|
20118
20272
|
if (!accountSwitchSessionId) return;
|
|
20119
20273
|
await handleProviderWalletAccountSwitch(change, accountSwitchSessionId);
|
|
20120
20274
|
}, [handleProviderWalletAccountSwitch, accountSwitchSessionId]);
|
|
20121
20275
|
useWalletAccountSwitchEffect({
|
|
20122
|
-
enabled:
|
|
20276
|
+
enabled: accountSwitchListenerArmed,
|
|
20123
20277
|
isDesktop,
|
|
20124
20278
|
onAccountChanged: onWalletAccountChanged
|
|
20125
20279
|
});
|
|
@@ -20215,6 +20369,7 @@ function BlinkPaymentInner({
|
|
|
20215
20369
|
reauthTokenRef: mobileFlowRefs.reauthTokenRef,
|
|
20216
20370
|
pollingTransferIdRef: transfer.pollingTransferIdRef,
|
|
20217
20371
|
handleAuthorizedMobileReturn: mobileFlow.handleAuthorizedMobileReturn,
|
|
20372
|
+
reloadAccounts: transfer.reloadAccounts,
|
|
20218
20373
|
onComplete,
|
|
20219
20374
|
getAccessToken: effectiveGetAccessToken,
|
|
20220
20375
|
pendingTransferFlowKey
|
|
@@ -20381,15 +20536,18 @@ function BlinkPaymentInner({
|
|
|
20381
20536
|
dispatch,
|
|
20382
20537
|
orchestrator
|
|
20383
20538
|
]);
|
|
20384
|
-
const handleBackFromSetupDeposit = react.useCallback(() => {
|
|
20539
|
+
const handleBackFromSetupDeposit = react.useCallback(async () => {
|
|
20385
20540
|
orchestrator.cancelPendingFlow();
|
|
20386
20541
|
authExecutor.cancelPendingExecution();
|
|
20387
20542
|
clearScreenErrors();
|
|
20543
|
+
if (isDesktop) {
|
|
20544
|
+
await revokeAndDisconnectActiveWagmiConnector(wagmiConfig);
|
|
20545
|
+
}
|
|
20388
20546
|
dispatch({ type: "RESTORE_SELECTION" });
|
|
20389
20547
|
dispatch({ type: "CLEAR_SETUP_DEPOSIT_TOKEN" });
|
|
20390
20548
|
dispatch({ type: "SET_SETUP_FLOW_SCREEN", screen: null });
|
|
20391
20549
|
dispatch({ type: "SET_USER_INTENT", intent: { step: "wallet-picker", reason: "switch" } });
|
|
20392
|
-
}, [authExecutor, clearScreenErrors, orchestrator, dispatch]);
|
|
20550
|
+
}, [authExecutor, clearScreenErrors, orchestrator, dispatch, isDesktop, wagmiConfig]);
|
|
20393
20551
|
const handleAuthorizationRetry = react.useCallback(() => {
|
|
20394
20552
|
void (async () => {
|
|
20395
20553
|
try {
|
|
@@ -20429,6 +20587,11 @@ function BlinkPaymentInner({
|
|
|
20429
20587
|
clearScreenErrors();
|
|
20430
20588
|
dispatch({ type: "SET_SETUP_DEPOSIT_AMOUNT", amount });
|
|
20431
20589
|
dispatch({ type: "SET_USER_INTENT", intent: { step: "wallet-picker", reason: "switch" } });
|
|
20590
|
+
void (async () => {
|
|
20591
|
+
await revokeAndDisconnectActiveWagmiConnector(wagmiConfig);
|
|
20592
|
+
await authExecutor.resetWalletConnect().catch(() => {
|
|
20593
|
+
});
|
|
20594
|
+
})();
|
|
20432
20595
|
},
|
|
20433
20596
|
onBackFromSetupDeposit: handleBackFromSetupDeposit,
|
|
20434
20597
|
onBackFromSubflow: () => {
|
|
@@ -20477,65 +20640,76 @@ function BlinkPaymentInner({
|
|
|
20477
20640
|
handleSetDepositToken,
|
|
20478
20641
|
handleConfirmSetupDeposit,
|
|
20479
20642
|
handleBackFromSetupDeposit,
|
|
20480
|
-
handleAuthorizationRetry
|
|
20643
|
+
handleAuthorizationRetry,
|
|
20644
|
+
wagmiConfig
|
|
20481
20645
|
]);
|
|
20482
20646
|
return /* @__PURE__ */ jsxRuntime.jsx(EffectiveDepositAmountProvider, { value: effectiveDepositAmount, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
20483
|
-
|
|
20647
|
+
ManualTransferSessionProvider,
|
|
20484
20648
|
{
|
|
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
|
-
|
|
20649
|
+
destination,
|
|
20650
|
+
merchantAuthorization,
|
|
20651
|
+
idempotencyKey,
|
|
20652
|
+
onComplete,
|
|
20653
|
+
onError,
|
|
20654
|
+
pollEnabled: manualTransferActive,
|
|
20655
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
20656
|
+
StepRenderer,
|
|
20657
|
+
{
|
|
20658
|
+
flow: {
|
|
20659
|
+
state,
|
|
20660
|
+
authenticated: effectiveAuthenticated,
|
|
20661
|
+
passkeyLoading: auth.passkeyLoginStatus !== "initial" && auth.passkeyLoginStatus !== "done" && auth.passkeyLoginStatus !== "error" || auth.passkeySignupStatus !== "initial" && auth.passkeySignupStatus !== "done" && auth.passkeySignupStatus !== "error" || auth.passkeySignupPopupActive,
|
|
20662
|
+
isDesktop,
|
|
20663
|
+
isMobileApp: isMobileApp ?? false,
|
|
20664
|
+
merchantName,
|
|
20665
|
+
onBack,
|
|
20666
|
+
onDismiss,
|
|
20667
|
+
depositAmount,
|
|
20668
|
+
effectiveDepositAmount,
|
|
20669
|
+
minTransferAmountUsd,
|
|
20670
|
+
destination,
|
|
20671
|
+
merchantAuthorization,
|
|
20672
|
+
idempotencyKey,
|
|
20673
|
+
onComplete,
|
|
20674
|
+
onError
|
|
20675
|
+
},
|
|
20676
|
+
remote: {
|
|
20677
|
+
pollingTransfer: polling.transfer,
|
|
20678
|
+
pollingError: polling.error,
|
|
20679
|
+
authExecutorError: authExecutor.error,
|
|
20680
|
+
authExecutorExecuting: authExecutor.executing,
|
|
20681
|
+
authExecutorCurrentAction: authExecutor.currentAction,
|
|
20682
|
+
pendingOneTapSetup: orchestrator.pendingOneTapAction,
|
|
20683
|
+
setupAuthorizationComplete,
|
|
20684
|
+
transferSigningSigning: transferSigning.signing,
|
|
20685
|
+
transferSigningError: transferSigning.error,
|
|
20686
|
+
transferSigningPasskeyDismissed: transferSigning.passkeyDismissed,
|
|
20687
|
+
pendingSelectSource: orchestrator.pendingSelectSourceAction
|
|
20688
|
+
},
|
|
20689
|
+
derived: {
|
|
20690
|
+
pendingConnections: derived.pendingConnections,
|
|
20691
|
+
depositEligibleAccounts: derived.depositEligibleAccounts,
|
|
20692
|
+
sourceName: derived.sourceName,
|
|
20693
|
+
maxSourceBalance: derived.maxSourceBalance,
|
|
20694
|
+
tokenCount: derived.tokenCount,
|
|
20695
|
+
selectedAccount: derived.selectedAccount,
|
|
20696
|
+
selectedSource: derived.selectedSource,
|
|
20697
|
+
selectSourceChoices: sourceSelection.selectSourceChoices,
|
|
20698
|
+
selectSourceRecommended: sourceSelection.selectSourceRecommended,
|
|
20699
|
+
selectSourceAvailableBalance: sourceSelection.selectSourceAvailableBalance
|
|
20700
|
+
},
|
|
20701
|
+
forms: {
|
|
20702
|
+
selectSourceChainName: sourceSelection.selectSourceChainName,
|
|
20703
|
+
selectSourceTokenSymbol: sourceSelection.selectSourceTokenSymbol,
|
|
20704
|
+
savingOneTapLimit: oneTapSetup.savingOneTapLimit,
|
|
20705
|
+
depositQuoteId: depositFee.quoteId,
|
|
20706
|
+
depositQuoteFee: depositFee.quoteFee,
|
|
20707
|
+
depositQuoteLoading: depositFee.quoteLoading,
|
|
20708
|
+
depositQuoteError: depositFee.quoteError
|
|
20709
|
+
},
|
|
20710
|
+
handlers
|
|
20711
|
+
}
|
|
20712
|
+
)
|
|
20539
20713
|
}
|
|
20540
20714
|
) });
|
|
20541
20715
|
}
|