@swype-org/react-sdk 0.2.242 → 0.2.263
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/index.cjs +1204 -1016
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -3
- package/dist/index.d.ts +12 -3
- package/dist/index.js +1205 -1017
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import { mainnet, arbitrum, base, polygon, bsc, megaeth, monad, hyperliquid, bas
|
|
|
6
6
|
import { injected, coinbaseWallet } from 'wagmi/connectors';
|
|
7
7
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
8
8
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
9
|
-
import { getAccount, disconnect, reconnect, getWalletClient } from '@wagmi/core';
|
|
9
|
+
import { getAccount, disconnect, reconnect, getWalletClient, getConnectors } from '@wagmi/core';
|
|
10
10
|
import { encodeFunctionData, recoverTypedDataAddress, decodeAbiParameters } from 'viem';
|
|
11
11
|
import { parseErc6492Signature } from 'viem/utils';
|
|
12
12
|
import * as QRCode from 'qrcode';
|
|
@@ -1130,12 +1130,225 @@ function useBlinkDepositAmount() {
|
|
|
1130
1130
|
};
|
|
1131
1131
|
}
|
|
1132
1132
|
|
|
1133
|
+
// src/walletConnectorResolver.ts
|
|
1134
|
+
function normalize(value) {
|
|
1135
|
+
return (value ?? "").trim().toLowerCase();
|
|
1136
|
+
}
|
|
1137
|
+
function buildTargetMatchers(target) {
|
|
1138
|
+
const values = [target.providerName, target.wagmiConnectorId].map(normalize).filter(Boolean);
|
|
1139
|
+
const aliases = new Set(values);
|
|
1140
|
+
for (const value of values) {
|
|
1141
|
+
if (value.includes("metamask")) {
|
|
1142
|
+
aliases.add("metamask");
|
|
1143
|
+
aliases.add("io.metamask");
|
|
1144
|
+
}
|
|
1145
|
+
if (value === "base" || value === "base account" || value === "base app" || value.includes("coinbase")) {
|
|
1146
|
+
aliases.add("base");
|
|
1147
|
+
aliases.add("coinbase");
|
|
1148
|
+
aliases.add("coinbasewalletsdk");
|
|
1149
|
+
}
|
|
1150
|
+
if (value.includes("trust")) {
|
|
1151
|
+
aliases.add("trust");
|
|
1152
|
+
aliases.add("trustwallet");
|
|
1153
|
+
}
|
|
1154
|
+
if (value.includes("okx")) {
|
|
1155
|
+
aliases.add("okx");
|
|
1156
|
+
aliases.add("okxwallet");
|
|
1157
|
+
aliases.add("com.okx.wallet");
|
|
1158
|
+
}
|
|
1159
|
+
if (value.includes("rabby")) {
|
|
1160
|
+
aliases.add("rabby");
|
|
1161
|
+
aliases.add("io.rabby");
|
|
1162
|
+
}
|
|
1163
|
+
if (value.includes("phantom")) {
|
|
1164
|
+
aliases.add("phantom");
|
|
1165
|
+
aliases.add("app.phantom");
|
|
1166
|
+
}
|
|
1167
|
+
if (value.includes("injected")) {
|
|
1168
|
+
aliases.add("injected");
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
return [...aliases];
|
|
1172
|
+
}
|
|
1173
|
+
function connectorMatchesWallet(connector, target) {
|
|
1174
|
+
if (!connector) {
|
|
1175
|
+
return false;
|
|
1176
|
+
}
|
|
1177
|
+
const connectorId = normalize(connector.id);
|
|
1178
|
+
const connectorName = normalize(connector.name);
|
|
1179
|
+
if (target.wagmiConnectorId) {
|
|
1180
|
+
const targetConnectorId = normalize(target.wagmiConnectorId);
|
|
1181
|
+
if (connectorId === targetConnectorId) {
|
|
1182
|
+
return true;
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
const matchers = buildTargetMatchers(target);
|
|
1186
|
+
if (matchers.length === 0) {
|
|
1187
|
+
return false;
|
|
1188
|
+
}
|
|
1189
|
+
return matchers.some(
|
|
1190
|
+
(matcher) => connectorId === matcher || connectorName === matcher || connectorId.includes(matcher) || connectorName.includes(matcher)
|
|
1191
|
+
);
|
|
1192
|
+
}
|
|
1193
|
+
function resolveWalletConnector(connectors, target) {
|
|
1194
|
+
if (target.wagmiConnectorId || target.providerName) {
|
|
1195
|
+
return connectors.find((connector) => connectorMatchesWallet(connector, target));
|
|
1196
|
+
}
|
|
1197
|
+
const metaMaskConnector = connectors.find((connector) => connectorMatchesWallet(
|
|
1198
|
+
connector,
|
|
1199
|
+
{ wagmiConnectorId: "metamask" }
|
|
1200
|
+
));
|
|
1201
|
+
return metaMaskConnector ?? connectors[0];
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
// src/wagmiRevokeAndDisconnect.ts
|
|
1205
|
+
var REVOKE_METHOD = "wallet_revokePermissions";
|
|
1206
|
+
var REVOKE_PARAMS = [{ eth_accounts: {} }];
|
|
1207
|
+
var EIP6963_DISCOVERY_MS = 200;
|
|
1208
|
+
async function tryRevoke(provider, context) {
|
|
1209
|
+
if (!provider?.request) return false;
|
|
1210
|
+
try {
|
|
1211
|
+
await provider.request({ method: REVOKE_METHOD, params: REVOKE_PARAMS });
|
|
1212
|
+
console.info("[blink-sdk][revoke] ok", context);
|
|
1213
|
+
return true;
|
|
1214
|
+
} catch (err) {
|
|
1215
|
+
const code = err?.code;
|
|
1216
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1217
|
+
console.info("[blink-sdk][revoke] failed", { ...context, code, message });
|
|
1218
|
+
return false;
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
async function getProviderForConnector(connector) {
|
|
1222
|
+
try {
|
|
1223
|
+
const provider = await connector.getProvider();
|
|
1224
|
+
return provider ?? null;
|
|
1225
|
+
} catch (err) {
|
|
1226
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1227
|
+
console.info("[blink-sdk][revoke] connector.getProvider() threw", {
|
|
1228
|
+
connectorId: connector.id,
|
|
1229
|
+
message
|
|
1230
|
+
});
|
|
1231
|
+
return null;
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
async function discoverEip6963Providers(windowImpl, timeoutMs) {
|
|
1235
|
+
return new Promise((resolve) => {
|
|
1236
|
+
const seen = /* @__PURE__ */ new Map();
|
|
1237
|
+
const onAnnounce = (event) => {
|
|
1238
|
+
const detail = event.detail;
|
|
1239
|
+
if (!detail || !detail.info?.uuid) return;
|
|
1240
|
+
seen.set(detail.info.uuid, detail);
|
|
1241
|
+
};
|
|
1242
|
+
windowImpl.addEventListener("eip6963:announceProvider", onAnnounce);
|
|
1243
|
+
try {
|
|
1244
|
+
windowImpl.dispatchEvent(new Event("eip6963:requestProvider"));
|
|
1245
|
+
} catch {
|
|
1246
|
+
}
|
|
1247
|
+
const timer = setTimeout(() => {
|
|
1248
|
+
windowImpl.removeEventListener(
|
|
1249
|
+
"eip6963:announceProvider",
|
|
1250
|
+
onAnnounce
|
|
1251
|
+
);
|
|
1252
|
+
resolve([...seen.values()]);
|
|
1253
|
+
}, timeoutMs);
|
|
1254
|
+
if (typeof timer.unref === "function") {
|
|
1255
|
+
timer.unref();
|
|
1256
|
+
}
|
|
1257
|
+
});
|
|
1258
|
+
}
|
|
1259
|
+
async function probeAccounts(provider) {
|
|
1260
|
+
if (!provider.request) return [];
|
|
1261
|
+
try {
|
|
1262
|
+
const accounts = await provider.request({ method: "eth_accounts" });
|
|
1263
|
+
return Array.isArray(accounts) ? accounts : [];
|
|
1264
|
+
} catch {
|
|
1265
|
+
return [];
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
async function revokeAndDisconnectConnector(deps) {
|
|
1269
|
+
const activeConnector = deps.getActiveConnector();
|
|
1270
|
+
if (activeConnector) {
|
|
1271
|
+
const provider = await getProviderForConnector(activeConnector);
|
|
1272
|
+
await tryRevoke(provider, {
|
|
1273
|
+
layer: 1,
|
|
1274
|
+
source: "wagmi-connector",
|
|
1275
|
+
rdns: activeConnector.id
|
|
1276
|
+
});
|
|
1277
|
+
await deps.disconnectFn(activeConnector).catch(() => {
|
|
1278
|
+
});
|
|
1279
|
+
return;
|
|
1280
|
+
}
|
|
1281
|
+
let recentRdns = null;
|
|
1282
|
+
try {
|
|
1283
|
+
recentRdns = await deps.getRecentConnectorId() ?? null;
|
|
1284
|
+
} catch {
|
|
1285
|
+
}
|
|
1286
|
+
if (recentRdns) {
|
|
1287
|
+
const matchedConnector = resolveWalletConnector(deps.listConnectors(), {
|
|
1288
|
+
wagmiConnectorId: recentRdns
|
|
1289
|
+
});
|
|
1290
|
+
if (matchedConnector) {
|
|
1291
|
+
const provider = await getProviderForConnector(matchedConnector);
|
|
1292
|
+
const revoked = await tryRevoke(provider, {
|
|
1293
|
+
layer: 2,
|
|
1294
|
+
source: "recent-connector",
|
|
1295
|
+
rdns: matchedConnector.id
|
|
1296
|
+
});
|
|
1297
|
+
await deps.disconnectFn(matchedConnector).catch(() => {
|
|
1298
|
+
});
|
|
1299
|
+
if (revoked) return;
|
|
1300
|
+
} else {
|
|
1301
|
+
console.info("[blink-sdk][revoke] recentConnectorId has no matching connector", {
|
|
1302
|
+
recentRdns
|
|
1303
|
+
});
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
const win = deps.windowImpl ?? (typeof window === "undefined" ? null : window);
|
|
1307
|
+
if (!win) {
|
|
1308
|
+
console.warn("[blink-sdk][revoke] no candidate found and no window for EIP-6963 fallback");
|
|
1309
|
+
return;
|
|
1310
|
+
}
|
|
1311
|
+
const announces = await discoverEip6963Providers(
|
|
1312
|
+
win,
|
|
1313
|
+
deps.eip6963TimeoutMs ?? EIP6963_DISCOVERY_MS
|
|
1314
|
+
);
|
|
1315
|
+
if (announces.length === 0) {
|
|
1316
|
+
console.warn("[blink-sdk][revoke] EIP-6963 enumeration found no providers");
|
|
1317
|
+
return;
|
|
1318
|
+
}
|
|
1319
|
+
let anyRevoked = false;
|
|
1320
|
+
for (const detail of announces) {
|
|
1321
|
+
const accounts = await probeAccounts(detail.provider);
|
|
1322
|
+
if (accounts.length === 0) continue;
|
|
1323
|
+
const ok = await tryRevoke(detail.provider, {
|
|
1324
|
+
layer: 3,
|
|
1325
|
+
source: "eip6963-broadcast",
|
|
1326
|
+
rdns: detail.info.rdns
|
|
1327
|
+
});
|
|
1328
|
+
if (ok) anyRevoked = true;
|
|
1329
|
+
}
|
|
1330
|
+
if (!anyRevoked) {
|
|
1331
|
+
console.warn("[blink-sdk][revoke] EIP-6963 enumeration found no providers with a grant");
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
async function revokeAndDisconnectActiveWagmiConnector(wagmiConfig) {
|
|
1335
|
+
await revokeAndDisconnectConnector({
|
|
1336
|
+
getActiveConnector: () => getAccount(wagmiConfig).connector,
|
|
1337
|
+
getRecentConnectorId: async () => {
|
|
1338
|
+
const value = await wagmiConfig.storage?.getItem("recentConnectorId");
|
|
1339
|
+
return typeof value === "string" ? value : null;
|
|
1340
|
+
},
|
|
1341
|
+
listConnectors: () => getConnectors(wagmiConfig),
|
|
1342
|
+
disconnectFn: (connector) => disconnect(wagmiConfig, { connector })
|
|
1343
|
+
});
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1133
1346
|
// src/otherWalletConnect.ts
|
|
1134
1347
|
function findWalletConnectConnector(connectors) {
|
|
1135
1348
|
return connectors.find((connector) => {
|
|
1136
|
-
const id =
|
|
1137
|
-
const name =
|
|
1138
|
-
const type =
|
|
1349
|
+
const id = normalize2(connector.id);
|
|
1350
|
+
const name = normalize2(connector.name);
|
|
1351
|
+
const type = normalize2(connector.type);
|
|
1139
1352
|
return id === "walletconnect" || id === "wallet-connect" || name === "walletconnect" || name === "wallet connect" || type === "walletconnect";
|
|
1140
1353
|
});
|
|
1141
1354
|
}
|
|
@@ -1152,9 +1365,9 @@ function findReownExtensionConnector(connectors, wallet) {
|
|
|
1152
1365
|
const eligible = connectors.filter((connector) => !findWalletConnectConnector([connector]));
|
|
1153
1366
|
const match = eligible.find((connector) => {
|
|
1154
1367
|
const connectorValues = [
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1368
|
+
normalize2(connector.id),
|
|
1369
|
+
normalize2(connector.name),
|
|
1370
|
+
normalize2(connector.type)
|
|
1158
1371
|
].filter(Boolean);
|
|
1159
1372
|
return targets.some(
|
|
1160
1373
|
(target) => connectorValues.some(
|
|
@@ -1183,8 +1396,8 @@ async function findReownExtensionConnectorAsync(connectors, wallet, bridgeClient
|
|
|
1183
1396
|
});
|
|
1184
1397
|
return void 0;
|
|
1185
1398
|
}
|
|
1186
|
-
const targetRdns =
|
|
1187
|
-
const match = connectors.find((connector) =>
|
|
1399
|
+
const targetRdns = normalize2(resolved.rdns);
|
|
1400
|
+
const match = connectors.find((connector) => normalize2(connector.id) === targetRdns);
|
|
1188
1401
|
console.info("[blink-bridge] findReownExtensionConnectorAsync \u2192 match", {
|
|
1189
1402
|
walletName: wallet.name,
|
|
1190
1403
|
flag: resolved.flag,
|
|
@@ -1202,84 +1415,59 @@ function getReownExtensionTargets(wallet) {
|
|
|
1202
1415
|
return [...targets];
|
|
1203
1416
|
}
|
|
1204
1417
|
function addTarget(targets, value) {
|
|
1205
|
-
const normalized =
|
|
1418
|
+
const normalized = normalize2(value);
|
|
1206
1419
|
if (normalized) {
|
|
1207
1420
|
targets.add(normalized);
|
|
1208
1421
|
}
|
|
1209
1422
|
}
|
|
1210
|
-
function
|
|
1423
|
+
function normalize2(value) {
|
|
1211
1424
|
return (value ?? "").trim().toLowerCase().replaceAll(/[^a-z0-9.]/g, "");
|
|
1212
1425
|
}
|
|
1213
1426
|
|
|
1214
|
-
// src/
|
|
1215
|
-
function
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
}
|
|
1258
|
-
const connectorId = normalize2(connector.id);
|
|
1259
|
-
const connectorName = normalize2(connector.name);
|
|
1260
|
-
if (target.wagmiConnectorId) {
|
|
1261
|
-
const targetConnectorId = normalize2(target.wagmiConnectorId);
|
|
1262
|
-
if (connectorId === targetConnectorId) {
|
|
1263
|
-
return true;
|
|
1264
|
-
}
|
|
1265
|
-
}
|
|
1266
|
-
const matchers = buildTargetMatchers(target);
|
|
1267
|
-
if (matchers.length === 0) {
|
|
1268
|
-
return false;
|
|
1269
|
-
}
|
|
1270
|
-
return matchers.some(
|
|
1271
|
-
(matcher) => connectorId === matcher || connectorName === matcher || connectorId.includes(matcher) || connectorName.includes(matcher)
|
|
1272
|
-
);
|
|
1273
|
-
}
|
|
1274
|
-
function resolveWalletConnector(connectors, target) {
|
|
1275
|
-
if (target.wagmiConnectorId || target.providerName) {
|
|
1276
|
-
return connectors.find((connector) => connectorMatchesWallet(connector, target));
|
|
1427
|
+
// src/resolveScreen.ts
|
|
1428
|
+
function screenForPhase(phase) {
|
|
1429
|
+
switch (phase.step) {
|
|
1430
|
+
case "initializing":
|
|
1431
|
+
case "data-loading":
|
|
1432
|
+
return "loading";
|
|
1433
|
+
case "manual-transfer":
|
|
1434
|
+
return "manual-transfer";
|
|
1435
|
+
case "login":
|
|
1436
|
+
return "login";
|
|
1437
|
+
case "deposit-options":
|
|
1438
|
+
return "deposit-options";
|
|
1439
|
+
case "wallet-picker":
|
|
1440
|
+
return "wallet-picker";
|
|
1441
|
+
case "wallet-setup":
|
|
1442
|
+
if (phase.mobile) {
|
|
1443
|
+
return "open-wallet";
|
|
1444
|
+
}
|
|
1445
|
+
if (phase.desktopWait) {
|
|
1446
|
+
return "open-wallet";
|
|
1447
|
+
}
|
|
1448
|
+
return "setup-deposit";
|
|
1449
|
+
case "select-source":
|
|
1450
|
+
return phase.isDesktop ? "setup" : "select-source";
|
|
1451
|
+
case "one-tap-setup":
|
|
1452
|
+
return "setup";
|
|
1453
|
+
case "token-picker":
|
|
1454
|
+
return "token-picker";
|
|
1455
|
+
case "guest-source-picker":
|
|
1456
|
+
return "guest-source-picker";
|
|
1457
|
+
case "deposit":
|
|
1458
|
+
return "deposit";
|
|
1459
|
+
case "processing":
|
|
1460
|
+
return "processing";
|
|
1461
|
+
case "confirm-sign":
|
|
1462
|
+
return "confirm-sign";
|
|
1463
|
+
case "completed":
|
|
1464
|
+
case "failed":
|
|
1465
|
+
return "success";
|
|
1466
|
+
case "amount-too-low":
|
|
1467
|
+
return "amount-too-low";
|
|
1468
|
+
case "enter-amount":
|
|
1469
|
+
return "enter-amount";
|
|
1277
1470
|
}
|
|
1278
|
-
const metaMaskConnector = connectors.find((connector) => connectorMatchesWallet(
|
|
1279
|
-
connector,
|
|
1280
|
-
{ wagmiConnectorId: "metamask" }
|
|
1281
|
-
));
|
|
1282
|
-
return metaMaskConnector ?? connectors[0];
|
|
1283
1471
|
}
|
|
1284
1472
|
|
|
1285
1473
|
// src/passkey-delegation.ts
|
|
@@ -1723,8 +1911,9 @@ async function fetchAccount(apiBaseUrl, token, accountId, credentialId) {
|
|
|
1723
1911
|
return await res.json();
|
|
1724
1912
|
}
|
|
1725
1913
|
async function createAccount(apiBaseUrl, token, params) {
|
|
1914
|
+
const provisionalId = params.id ?? crypto.randomUUID();
|
|
1726
1915
|
const body = {
|
|
1727
|
-
id:
|
|
1916
|
+
id: provisionalId,
|
|
1728
1917
|
name: params.name,
|
|
1729
1918
|
credentialId: params.credentialId
|
|
1730
1919
|
};
|
|
@@ -1752,7 +1941,8 @@ async function createAccount(apiBaseUrl, token, params) {
|
|
|
1752
1941
|
body: JSON.stringify(body)
|
|
1753
1942
|
});
|
|
1754
1943
|
if (!res.ok) await throwApiError(res);
|
|
1755
|
-
|
|
1944
|
+
const account = await res.json();
|
|
1945
|
+
return { ...account, id: account.id ?? provisionalId };
|
|
1756
1946
|
}
|
|
1757
1947
|
async function createAccountAuthorizationSession(apiBaseUrl, token, accountId, credentialId, options) {
|
|
1758
1948
|
const body = { credentialId };
|
|
@@ -7345,289 +7535,706 @@ function EffectiveDepositAmountProvider({
|
|
|
7345
7535
|
return /* @__PURE__ */ jsx(EffectiveDepositAmountContext.Provider, { value: memoValue, children });
|
|
7346
7536
|
}
|
|
7347
7537
|
|
|
7348
|
-
// src/
|
|
7349
|
-
function
|
|
7350
|
-
|
|
7351
|
-
|
|
7352
|
-
case "
|
|
7353
|
-
return "
|
|
7354
|
-
case "
|
|
7355
|
-
return "
|
|
7356
|
-
case "
|
|
7357
|
-
return "
|
|
7358
|
-
case "deposit-options":
|
|
7359
|
-
return "deposit-options";
|
|
7360
|
-
case "wallet-picker":
|
|
7361
|
-
return "wallet-picker";
|
|
7362
|
-
case "wallet-setup":
|
|
7363
|
-
if (phase.mobile) {
|
|
7364
|
-
return "open-wallet";
|
|
7365
|
-
}
|
|
7366
|
-
if (phase.desktopWait) {
|
|
7367
|
-
return "open-wallet";
|
|
7368
|
-
}
|
|
7369
|
-
return "setup-deposit";
|
|
7370
|
-
case "select-source":
|
|
7371
|
-
return phase.isDesktop ? "setup" : "select-source";
|
|
7372
|
-
case "one-tap-setup":
|
|
7373
|
-
return "setup";
|
|
7374
|
-
case "token-picker":
|
|
7375
|
-
return "token-picker";
|
|
7376
|
-
case "guest-source-picker":
|
|
7377
|
-
return "guest-source-picker";
|
|
7378
|
-
case "deposit":
|
|
7379
|
-
return "deposit";
|
|
7380
|
-
case "processing":
|
|
7381
|
-
return "processing";
|
|
7382
|
-
case "confirm-sign":
|
|
7383
|
-
return "confirm-sign";
|
|
7538
|
+
// src/manualTransferUtils.ts
|
|
7539
|
+
function screenForSession(session) {
|
|
7540
|
+
if (!session) return "source-selector";
|
|
7541
|
+
switch (session.status) {
|
|
7542
|
+
case "awaiting_deposit":
|
|
7543
|
+
return "awaiting-deposit";
|
|
7544
|
+
case "deposit_received":
|
|
7545
|
+
return "deposit-received";
|
|
7546
|
+
case "routing":
|
|
7547
|
+
return "deposit-routing";
|
|
7384
7548
|
case "completed":
|
|
7549
|
+
return "deposit-complete";
|
|
7550
|
+
case "refunded":
|
|
7385
7551
|
case "failed":
|
|
7386
|
-
|
|
7387
|
-
|
|
7388
|
-
return "amount-too-low";
|
|
7389
|
-
case "enter-amount":
|
|
7390
|
-
return "enter-amount";
|
|
7552
|
+
case "wrong_token":
|
|
7553
|
+
return "deposit-failed";
|
|
7391
7554
|
}
|
|
7392
7555
|
}
|
|
7393
|
-
|
|
7394
|
-
|
|
7395
|
-
var PROCESSING_TIMEOUT_MS = 18e4;
|
|
7396
|
-
var TERMINAL_TRANSFER_STATUSES = /* @__PURE__ */ new Set(["COMPLETED", "FAILED", "EXPIRED"]);
|
|
7397
|
-
var SIGNABLE_TRANSFER_STATUSES = /* @__PURE__ */ new Set(["CREATED", "AUTHORIZED"]);
|
|
7398
|
-
function isTerminalTransferStatus(status) {
|
|
7399
|
-
return TERMINAL_TRANSFER_STATUSES.has(status);
|
|
7400
|
-
}
|
|
7401
|
-
function isTransferSignable(transfer) {
|
|
7402
|
-
return transfer != null && SIGNABLE_TRANSFER_STATUSES.has(transfer.status);
|
|
7403
|
-
}
|
|
7404
|
-
function isTransferAwaitingCompletion(transfer) {
|
|
7405
|
-
if (!transfer) return false;
|
|
7406
|
-
return !isTerminalTransferStatus(transfer.status);
|
|
7407
|
-
}
|
|
7408
|
-
function resolvePreferredTransfer(polledTransfer, localTransfer) {
|
|
7409
|
-
return polledTransfer ?? localTransfer;
|
|
7556
|
+
function isSameChainSameTokenSelection(option, destination) {
|
|
7557
|
+
return option.chainId === destination.chainId && option.tokenAddress.toLowerCase() === destination.token.address.toLowerCase();
|
|
7410
7558
|
}
|
|
7411
|
-
function
|
|
7412
|
-
|
|
7413
|
-
return transfer?.status ?? "UNKNOWN";
|
|
7559
|
+
function feeCopy(_session) {
|
|
7560
|
+
return "No fees";
|
|
7414
7561
|
}
|
|
7415
|
-
function
|
|
7416
|
-
|
|
7417
|
-
|
|
7562
|
+
function toTransfer(session) {
|
|
7563
|
+
return {
|
|
7564
|
+
id: session.sessionId,
|
|
7565
|
+
status: session.status,
|
|
7566
|
+
amount: {
|
|
7567
|
+
amount: Number(session.deliveredAmountUsd ?? session.minAmountUsd),
|
|
7568
|
+
currency: "USD"
|
|
7569
|
+
},
|
|
7570
|
+
sources: [],
|
|
7571
|
+
destinations: [{
|
|
7572
|
+
id: session.sessionId,
|
|
7573
|
+
chainId: session.destination.chainId,
|
|
7574
|
+
address: session.destination.address,
|
|
7575
|
+
token: { address: session.destination.token.address, symbol: "" },
|
|
7576
|
+
amount: { amount: Number(session.deliveredAmountUsd ?? session.minAmountUsd), currency: "USD" }
|
|
7577
|
+
}],
|
|
7578
|
+
createDate: session.createDate,
|
|
7579
|
+
updateDate: session.updateDate
|
|
7580
|
+
};
|
|
7418
7581
|
}
|
|
7419
|
-
var
|
|
7420
|
-
|
|
7421
|
-
|
|
7422
|
-
|
|
7423
|
-
|
|
7424
|
-
|
|
7425
|
-
|
|
7426
|
-
}
|
|
7427
|
-
|
|
7428
|
-
return
|
|
7582
|
+
var SOLANA_CHAIN_ID = 792703809;
|
|
7583
|
+
var SOLANA_NATIVE_SOL_ADDRESS = "11111111111111111111111111111111";
|
|
7584
|
+
function formatDepositUri(address, chainId, depToken) {
|
|
7585
|
+
if (chainId === SOLANA_CHAIN_ID) {
|
|
7586
|
+
if (!depToken || depToken === SOLANA_NATIVE_SOL_ADDRESS) {
|
|
7587
|
+
return `solana:${address}`;
|
|
7588
|
+
}
|
|
7589
|
+
return `solana:${address}?spl-token=${depToken}`;
|
|
7590
|
+
}
|
|
7591
|
+
return address;
|
|
7429
7592
|
}
|
|
7430
|
-
|
|
7431
|
-
|
|
7432
|
-
|
|
7593
|
+
var dataUrlCache = /* @__PURE__ */ new Map();
|
|
7594
|
+
var inFlight = /* @__PURE__ */ new Map();
|
|
7595
|
+
function keyFor(uri, colors) {
|
|
7596
|
+
return `${uri}|${colors.dark}|${colors.light}`;
|
|
7597
|
+
}
|
|
7598
|
+
function getCachedQrDataUrl(uri, colors) {
|
|
7599
|
+
return dataUrlCache.get(keyFor(uri, colors)) ?? null;
|
|
7600
|
+
}
|
|
7601
|
+
function getOrRenderQrDataUrl(uri, colors) {
|
|
7602
|
+
const key = keyFor(uri, colors);
|
|
7603
|
+
const cached = dataUrlCache.get(key);
|
|
7604
|
+
if (cached) return Promise.resolve(cached);
|
|
7605
|
+
const pending = inFlight.get(key);
|
|
7606
|
+
if (pending) return pending;
|
|
7607
|
+
const promise = QRCode.toDataURL(uri, {
|
|
7608
|
+
errorCorrectionLevel: "H",
|
|
7609
|
+
margin: 1,
|
|
7610
|
+
width: 203,
|
|
7611
|
+
color: { dark: colors.dark, light: colors.light }
|
|
7612
|
+
}).then((url) => {
|
|
7613
|
+
dataUrlCache.set(key, url);
|
|
7614
|
+
inFlight.delete(key);
|
|
7615
|
+
return url;
|
|
7616
|
+
}).catch((err) => {
|
|
7617
|
+
inFlight.delete(key);
|
|
7618
|
+
throw err;
|
|
7619
|
+
});
|
|
7620
|
+
inFlight.set(key, promise);
|
|
7621
|
+
return promise;
|
|
7433
7622
|
}
|
|
7434
7623
|
|
|
7435
|
-
// src/
|
|
7436
|
-
function
|
|
7437
|
-
return
|
|
7438
|
-
}
|
|
7439
|
-
function resolveTerminalPhase(state) {
|
|
7440
|
-
if (state.amountTooLow != null) {
|
|
7441
|
-
return {
|
|
7442
|
-
step: "amount-too-low",
|
|
7443
|
-
minAmountUsd: state.amountTooLow.minAmountUsd
|
|
7444
|
-
};
|
|
7445
|
-
}
|
|
7446
|
-
const transferCompleted = state.transfer?.status === "COMPLETED";
|
|
7447
|
-
const needsPasskeyBootstrap = state.privyAuthenticated && !state.activeCredentialId;
|
|
7448
|
-
if (transferCompleted && !needsPasskeyBootstrap && !state.loginRequested) {
|
|
7449
|
-
return { step: "completed", transfer: state.transfer };
|
|
7450
|
-
}
|
|
7451
|
-
if (state.transfer?.status === "FAILED") {
|
|
7452
|
-
return {
|
|
7453
|
-
step: "failed",
|
|
7454
|
-
transfer: state.transfer,
|
|
7455
|
-
error: state.error ?? "Transfer failed."
|
|
7456
|
-
};
|
|
7457
|
-
}
|
|
7458
|
-
if (state.creatingTransfer || isTransferAwaitingCompletion(state.transfer)) {
|
|
7459
|
-
return { step: "processing", transfer: state.transfer };
|
|
7460
|
-
}
|
|
7461
|
-
return null;
|
|
7624
|
+
// src/hooks/useManualTransferSession.ts
|
|
7625
|
+
function perTokenKey(chainId, tokenAddress) {
|
|
7626
|
+
return `${chainId}:${tokenAddress.toLowerCase()}`;
|
|
7462
7627
|
}
|
|
7463
|
-
function
|
|
7464
|
-
|
|
7465
|
-
|
|
7466
|
-
|
|
7467
|
-
|
|
7468
|
-
|
|
7469
|
-
|
|
7470
|
-
|
|
7471
|
-
|
|
7472
|
-
|
|
7473
|
-
|
|
7474
|
-
|
|
7475
|
-
|
|
7476
|
-
|
|
7477
|
-
|
|
7478
|
-
|
|
7479
|
-
|
|
7480
|
-
|
|
7481
|
-
|
|
7482
|
-
|
|
7483
|
-
|
|
7484
|
-
|
|
7485
|
-
|
|
7486
|
-
|
|
7487
|
-
|
|
7488
|
-
|
|
7489
|
-
|
|
7490
|
-
|
|
7491
|
-
|
|
7492
|
-
|
|
7493
|
-
|
|
7494
|
-
|
|
7495
|
-
|
|
7496
|
-
|
|
7497
|
-
|
|
7628
|
+
function useManualTransferSession({
|
|
7629
|
+
destination,
|
|
7630
|
+
merchantAuthorization,
|
|
7631
|
+
idempotencyKey,
|
|
7632
|
+
onComplete,
|
|
7633
|
+
onError,
|
|
7634
|
+
pollEnabled = true
|
|
7635
|
+
}) {
|
|
7636
|
+
const { apiBaseUrl, tokens } = useBlinkConfig();
|
|
7637
|
+
const [sourceOptions, setSourceOptions] = useState(null);
|
|
7638
|
+
const [loadingSources, setLoadingSources] = useState(true);
|
|
7639
|
+
const [selectedToken, setSelectedToken] = useState("");
|
|
7640
|
+
const [selectedChainId, setSelectedChainId] = useState("");
|
|
7641
|
+
const [sessionsByFamily, setSessionsByFamily] = useState({});
|
|
7642
|
+
const [perTokenSessions, setPerTokenSessions] = useState({});
|
|
7643
|
+
const [loading, setLoading] = useState(false);
|
|
7644
|
+
const [error, setError] = useState(null);
|
|
7645
|
+
const [copiedAddress, setCopiedAddress] = useState(null);
|
|
7646
|
+
const completedRef = useRef(/* @__PURE__ */ new Set());
|
|
7647
|
+
const premintedFamiliesRef = useRef(/* @__PURE__ */ new Set());
|
|
7648
|
+
const inFlightPerTokenRef = useRef(/* @__PURE__ */ new Set());
|
|
7649
|
+
useEffect(() => {
|
|
7650
|
+
if (!merchantAuthorization) return;
|
|
7651
|
+
let cancelled = false;
|
|
7652
|
+
setLoadingSources(true);
|
|
7653
|
+
fetchManualTransferSources(apiBaseUrl, { merchantAuthorization, destination }).then((sources) => {
|
|
7654
|
+
if (cancelled) return;
|
|
7655
|
+
setSourceOptions(sources);
|
|
7656
|
+
setLoadingSources(false);
|
|
7657
|
+
const destTokenAddrLower = destination.token.address.toLowerCase();
|
|
7658
|
+
const destMatch = sources.find(
|
|
7659
|
+
(s) => s.chainId === destination.chainId && s.tokenAddress.toLowerCase() === destTokenAddrLower
|
|
7660
|
+
);
|
|
7661
|
+
const svmCanonical = sources.find((s) => s.canonical && s.chainFamily === "svm");
|
|
7662
|
+
const evmCanonical = sources.find((s) => s.canonical && s.chainFamily === "evm");
|
|
7663
|
+
const defaultOption = destMatch ?? svmCanonical ?? evmCanonical ?? sources[0];
|
|
7664
|
+
if (defaultOption) {
|
|
7665
|
+
setSelectedToken(defaultOption.tokenSymbol);
|
|
7666
|
+
setSelectedChainId(String(defaultOption.chainId));
|
|
7667
|
+
}
|
|
7668
|
+
}).catch((err) => {
|
|
7669
|
+
if (!cancelled) {
|
|
7670
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
7671
|
+
setLoadingSources(false);
|
|
7672
|
+
}
|
|
7673
|
+
});
|
|
7674
|
+
return () => {
|
|
7675
|
+
cancelled = true;
|
|
7498
7676
|
};
|
|
7499
|
-
}
|
|
7500
|
-
|
|
7501
|
-
return
|
|
7502
|
-
|
|
7503
|
-
|
|
7504
|
-
|
|
7677
|
+
}, [apiBaseUrl, destination, merchantAuthorization]);
|
|
7678
|
+
useEffect(() => {
|
|
7679
|
+
if (!sourceOptions || !merchantAuthorization) return;
|
|
7680
|
+
const canonicals = sourceOptions.filter((s) => s.canonical);
|
|
7681
|
+
if (canonicals.length === 0) return;
|
|
7682
|
+
let cancelled = false;
|
|
7683
|
+
for (const opt of canonicals) {
|
|
7684
|
+
if (premintedFamiliesRef.current.has(opt.chainFamily)) continue;
|
|
7685
|
+
premintedFamiliesRef.current.add(opt.chainFamily);
|
|
7686
|
+
const family = opt.chainFamily;
|
|
7687
|
+
const run = async () => {
|
|
7688
|
+
try {
|
|
7689
|
+
const created = await createManualTransfer(apiBaseUrl, {
|
|
7690
|
+
merchantAuthorization,
|
|
7691
|
+
destination,
|
|
7692
|
+
idempotencyKey,
|
|
7693
|
+
source: { chainId: opt.chainId, tokenAddress: opt.tokenAddress }
|
|
7694
|
+
});
|
|
7695
|
+
if (cancelled) return;
|
|
7696
|
+
setSessionsByFamily((prev) => ({ ...prev, [family]: created }));
|
|
7697
|
+
const uri = formatDepositUri(created.depositAddress, opt.chainId, opt.tokenAddress);
|
|
7698
|
+
void getOrRenderQrDataUrl(uri, { dark: tokens.text, light: tokens.bg });
|
|
7699
|
+
} catch (err) {
|
|
7700
|
+
if (cancelled) return;
|
|
7701
|
+
premintedFamiliesRef.current.delete(family);
|
|
7702
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
7703
|
+
}
|
|
7704
|
+
};
|
|
7705
|
+
void run();
|
|
7706
|
+
}
|
|
7707
|
+
return () => {
|
|
7708
|
+
cancelled = true;
|
|
7505
7709
|
};
|
|
7506
|
-
}
|
|
7507
|
-
|
|
7508
|
-
|
|
7509
|
-
|
|
7510
|
-
|
|
7511
|
-
|
|
7512
|
-
|
|
7513
|
-
|
|
7514
|
-
|
|
7515
|
-
|
|
7516
|
-
|
|
7517
|
-
|
|
7518
|
-
|
|
7519
|
-
|
|
7520
|
-
|
|
7521
|
-
|
|
7522
|
-
|
|
7523
|
-
|
|
7524
|
-
|
|
7525
|
-
|
|
7526
|
-
|
|
7527
|
-
|
|
7528
|
-
|
|
7529
|
-
|
|
7530
|
-
|
|
7531
|
-
|
|
7532
|
-
|
|
7533
|
-
|
|
7534
|
-
|
|
7535
|
-
|
|
7536
|
-
|
|
7537
|
-
|
|
7538
|
-
|
|
7539
|
-
|
|
7540
|
-
|
|
7541
|
-
|
|
7542
|
-
|
|
7543
|
-
|
|
7544
|
-
|
|
7545
|
-
|
|
7546
|
-
|
|
7547
|
-
|
|
7548
|
-
|
|
7549
|
-
|
|
7550
|
-
return
|
|
7551
|
-
|
|
7552
|
-
|
|
7553
|
-
|
|
7554
|
-
|
|
7555
|
-
|
|
7556
|
-
|
|
7557
|
-
|
|
7558
|
-
|
|
7559
|
-
|
|
7560
|
-
|
|
7710
|
+
}, [
|
|
7711
|
+
apiBaseUrl,
|
|
7712
|
+
destination,
|
|
7713
|
+
idempotencyKey,
|
|
7714
|
+
merchantAuthorization,
|
|
7715
|
+
sourceOptions,
|
|
7716
|
+
tokens.text,
|
|
7717
|
+
tokens.bg
|
|
7718
|
+
]);
|
|
7719
|
+
const tokenChoices = useMemo(
|
|
7720
|
+
() => Array.from(new Set((sourceOptions ?? []).map((opt) => opt.tokenSymbol))),
|
|
7721
|
+
[sourceOptions]
|
|
7722
|
+
);
|
|
7723
|
+
const chainChoices = useMemo(() => {
|
|
7724
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7725
|
+
return (sourceOptions ?? []).filter((opt) => {
|
|
7726
|
+
if (seen.has(opt.chainId)) return false;
|
|
7727
|
+
seen.add(opt.chainId);
|
|
7728
|
+
return true;
|
|
7729
|
+
});
|
|
7730
|
+
}, [sourceOptions]);
|
|
7731
|
+
const tokenLogoUriBySymbol = useMemo(() => {
|
|
7732
|
+
const out = {};
|
|
7733
|
+
for (const opt of sourceOptions ?? []) {
|
|
7734
|
+
if (out[opt.tokenSymbol] == null) {
|
|
7735
|
+
out[opt.tokenSymbol] = opt.tokenLogoUri;
|
|
7736
|
+
}
|
|
7737
|
+
}
|
|
7738
|
+
return out;
|
|
7739
|
+
}, [sourceOptions]);
|
|
7740
|
+
const selectedOption = useMemo(
|
|
7741
|
+
() => (sourceOptions ?? []).find(
|
|
7742
|
+
(opt) => opt.tokenSymbol === selectedToken && String(opt.chainId) === selectedChainId
|
|
7743
|
+
) ?? null,
|
|
7744
|
+
[sourceOptions, selectedToken, selectedChainId]
|
|
7745
|
+
);
|
|
7746
|
+
const tokensForSelectedChain = useMemo(() => {
|
|
7747
|
+
if (!selectedChainId) return null;
|
|
7748
|
+
return new Set(
|
|
7749
|
+
(sourceOptions ?? []).filter((opt) => String(opt.chainId) === selectedChainId).map((opt) => opt.tokenSymbol)
|
|
7750
|
+
);
|
|
7751
|
+
}, [sourceOptions, selectedChainId]);
|
|
7752
|
+
const chainsForSelectedToken = useMemo(() => {
|
|
7753
|
+
if (!selectedToken) return null;
|
|
7754
|
+
return new Set(
|
|
7755
|
+
(sourceOptions ?? []).filter((opt) => opt.tokenSymbol === selectedToken).map((opt) => opt.chainId)
|
|
7756
|
+
);
|
|
7757
|
+
}, [sourceOptions, selectedToken]);
|
|
7758
|
+
const session = useMemo(() => {
|
|
7759
|
+
if (!selectedOption) return null;
|
|
7760
|
+
const perToken = perTokenSessions[perTokenKey(selectedOption.chainId, selectedOption.tokenAddress)] ?? null;
|
|
7761
|
+
if (isSameChainSameTokenSelection(selectedOption, destination)) {
|
|
7762
|
+
return perToken ?? sessionsByFamily[selectedOption.chainFamily] ?? null;
|
|
7763
|
+
}
|
|
7764
|
+
const familySession = sessionsByFamily[selectedOption.chainFamily];
|
|
7765
|
+
if (familySession) return familySession;
|
|
7766
|
+
return perToken;
|
|
7767
|
+
}, [selectedOption, destination, sessionsByFamily, perTokenSessions]);
|
|
7768
|
+
const depositAddress = session?.depositAddress;
|
|
7769
|
+
const qrReady = !!depositAddress;
|
|
7770
|
+
const lastFeeCopyRef = useRef(null);
|
|
7771
|
+
const nextFeeCopy = session ? feeCopy() : null;
|
|
7772
|
+
const sessionFeeCopy = nextFeeCopy === lastFeeCopyRef.current ? lastFeeCopyRef.current : lastFeeCopyRef.current = nextFeeCopy;
|
|
7773
|
+
const activeSessionId = session?.sessionId;
|
|
7774
|
+
const activeSessionStatus = session?.status;
|
|
7775
|
+
useEffect(() => {
|
|
7776
|
+
if (!pollEnabled) return;
|
|
7777
|
+
if (!activeSessionId) return;
|
|
7778
|
+
if (activeSessionStatus && ["completed", "failed", "refunded", "wrong_token"].includes(activeSessionStatus)) return;
|
|
7779
|
+
const timer = window.setInterval(() => {
|
|
7780
|
+
fetchManualTransferSession(apiBaseUrl, activeSessionId).then((updated) => {
|
|
7781
|
+
setSessionsByFamily((prev) => {
|
|
7782
|
+
for (const family of Object.keys(prev)) {
|
|
7783
|
+
if (prev[family]?.sessionId === updated.sessionId) {
|
|
7784
|
+
return { ...prev, [family]: updated };
|
|
7785
|
+
}
|
|
7786
|
+
}
|
|
7787
|
+
return prev;
|
|
7788
|
+
});
|
|
7789
|
+
setPerTokenSessions((prev) => {
|
|
7790
|
+
for (const key of Object.keys(prev)) {
|
|
7791
|
+
if (prev[key]?.sessionId === updated.sessionId) {
|
|
7792
|
+
return { ...prev, [key]: updated };
|
|
7793
|
+
}
|
|
7794
|
+
}
|
|
7795
|
+
return prev;
|
|
7796
|
+
});
|
|
7797
|
+
}).catch((err) => setError(err instanceof Error ? err.message : String(err)));
|
|
7798
|
+
}, 2e3);
|
|
7799
|
+
return () => window.clearInterval(timer);
|
|
7800
|
+
}, [apiBaseUrl, activeSessionId, activeSessionStatus, pollEnabled]);
|
|
7801
|
+
const completionSignature = useMemo(() => {
|
|
7802
|
+
const entries2 = [];
|
|
7803
|
+
for (const family of Object.keys(sessionsByFamily)) {
|
|
7804
|
+
const s = sessionsByFamily[family];
|
|
7805
|
+
if (s) entries2.push([s.sessionId, s.status]);
|
|
7806
|
+
}
|
|
7807
|
+
for (const key of Object.keys(perTokenSessions)) {
|
|
7808
|
+
const s = perTokenSessions[key];
|
|
7809
|
+
entries2.push([s.sessionId, s.status]);
|
|
7810
|
+
}
|
|
7811
|
+
entries2.sort((a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0);
|
|
7812
|
+
return JSON.stringify(entries2);
|
|
7813
|
+
}, [sessionsByFamily, perTokenSessions]);
|
|
7814
|
+
useEffect(() => {
|
|
7815
|
+
const all = [];
|
|
7816
|
+
for (const family of Object.keys(sessionsByFamily)) {
|
|
7817
|
+
const s = sessionsByFamily[family];
|
|
7818
|
+
if (s) all.push(s);
|
|
7819
|
+
}
|
|
7820
|
+
for (const key of Object.keys(perTokenSessions)) {
|
|
7821
|
+
all.push(perTokenSessions[key]);
|
|
7822
|
+
}
|
|
7823
|
+
for (const s of all) {
|
|
7824
|
+
if (s.status !== "completed") continue;
|
|
7825
|
+
if (completedRef.current.has(s.sessionId)) continue;
|
|
7826
|
+
completedRef.current.add(s.sessionId);
|
|
7827
|
+
onComplete?.(toTransfer(s));
|
|
7828
|
+
break;
|
|
7829
|
+
}
|
|
7830
|
+
}, [completionSignature, onComplete]);
|
|
7831
|
+
useEffect(() => {
|
|
7832
|
+
if (!error) return;
|
|
7833
|
+
onError?.(error);
|
|
7834
|
+
}, [error, onError]);
|
|
7835
|
+
const createSession = useCallback(async (option) => {
|
|
7836
|
+
if (!merchantAuthorization) return;
|
|
7837
|
+
setLoading(true);
|
|
7838
|
+
setError(null);
|
|
7839
|
+
try {
|
|
7840
|
+
const created = await createManualTransfer(apiBaseUrl, {
|
|
7841
|
+
merchantAuthorization,
|
|
7842
|
+
destination,
|
|
7843
|
+
idempotencyKey,
|
|
7844
|
+
source: { chainId: option.chainId, tokenAddress: option.tokenAddress }
|
|
7845
|
+
});
|
|
7846
|
+
const key = perTokenKey(option.chainId, option.tokenAddress);
|
|
7847
|
+
setPerTokenSessions((prev) => ({ ...prev, [key]: created }));
|
|
7848
|
+
const uri = formatDepositUri(created.depositAddress, option.chainId, option.tokenAddress);
|
|
7849
|
+
void getOrRenderQrDataUrl(uri, { dark: tokens.text, light: tokens.bg });
|
|
7850
|
+
} catch (err) {
|
|
7851
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
7852
|
+
} finally {
|
|
7853
|
+
setLoading(false);
|
|
7854
|
+
}
|
|
7855
|
+
}, [apiBaseUrl, destination, idempotencyKey, merchantAuthorization, tokens.text, tokens.bg]);
|
|
7856
|
+
useEffect(() => {
|
|
7857
|
+
if (!selectedOption) return;
|
|
7858
|
+
const sameTokenSelection = isSameChainSameTokenSelection(selectedOption, destination);
|
|
7859
|
+
if (!sameTokenSelection) {
|
|
7860
|
+
if (sessionsByFamily[selectedOption.chainFamily]) return;
|
|
7861
|
+
if (premintedFamiliesRef.current.has(selectedOption.chainFamily)) return;
|
|
7862
|
+
}
|
|
7863
|
+
const key = perTokenKey(selectedOption.chainId, selectedOption.tokenAddress);
|
|
7864
|
+
if (perTokenSessions[key]) return;
|
|
7865
|
+
if (inFlightPerTokenRef.current.has(key)) return;
|
|
7866
|
+
inFlightPerTokenRef.current.add(key);
|
|
7867
|
+
void createSession(selectedOption).finally(() => {
|
|
7868
|
+
inFlightPerTokenRef.current.delete(key);
|
|
7869
|
+
});
|
|
7870
|
+
}, [selectedOption, destination, sessionsByFamily, perTokenSessions, createSession]);
|
|
7871
|
+
const resetSessionForNewSelection = useCallback(() => {
|
|
7872
|
+
setError(null);
|
|
7873
|
+
}, []);
|
|
7874
|
+
const selectToken = useCallback((value) => {
|
|
7875
|
+
setSelectedToken(value);
|
|
7876
|
+
const pairValid = (sourceOptions ?? []).some(
|
|
7877
|
+
(opt) => opt.tokenSymbol === value && String(opt.chainId) === selectedChainId
|
|
7878
|
+
);
|
|
7879
|
+
if (!pairValid) {
|
|
7880
|
+
const firstChain = (sourceOptions ?? []).find(
|
|
7881
|
+
(opt) => opt.tokenSymbol === value
|
|
7882
|
+
);
|
|
7883
|
+
setSelectedChainId(
|
|
7884
|
+
firstChain ? String(firstChain.chainId) : ""
|
|
7885
|
+
);
|
|
7886
|
+
}
|
|
7887
|
+
}, [selectedChainId, sourceOptions]);
|
|
7888
|
+
const selectChainId = useCallback((value) => {
|
|
7889
|
+
setSelectedChainId(value);
|
|
7890
|
+
const pairValid = (sourceOptions ?? []).some(
|
|
7891
|
+
(opt) => opt.tokenSymbol === selectedToken && String(opt.chainId) === value
|
|
7892
|
+
);
|
|
7893
|
+
if (!pairValid) {
|
|
7894
|
+
const firstToken = (sourceOptions ?? []).find(
|
|
7895
|
+
(opt) => String(opt.chainId) === value
|
|
7896
|
+
);
|
|
7897
|
+
setSelectedToken(
|
|
7898
|
+
firstToken ? firstToken.tokenSymbol : ""
|
|
7899
|
+
);
|
|
7900
|
+
}
|
|
7901
|
+
}, [selectedToken, sourceOptions]);
|
|
7902
|
+
const screen = screenForSession(session);
|
|
7903
|
+
const copyDepositAddress = useCallback(async (address) => {
|
|
7904
|
+
try {
|
|
7905
|
+
await navigator.clipboard.writeText(address);
|
|
7906
|
+
} catch {
|
|
7907
|
+
const textarea = document.createElement("textarea");
|
|
7908
|
+
textarea.value = address;
|
|
7909
|
+
textarea.setAttribute("readonly", "");
|
|
7910
|
+
textarea.style.position = "absolute";
|
|
7911
|
+
textarea.style.opacity = "0";
|
|
7912
|
+
document.body.appendChild(textarea);
|
|
7913
|
+
textarea.select();
|
|
7914
|
+
try {
|
|
7915
|
+
document.execCommand("copy");
|
|
7916
|
+
} finally {
|
|
7917
|
+
document.body.removeChild(textarea);
|
|
7918
|
+
}
|
|
7919
|
+
}
|
|
7920
|
+
setCopiedAddress(address);
|
|
7921
|
+
window.setTimeout(() => setCopiedAddress((cur) => cur === address ? null : cur), 1500);
|
|
7922
|
+
}, []);
|
|
7923
|
+
const backToSourceSelector = useCallback(() => {
|
|
7924
|
+
setCopiedAddress(null);
|
|
7925
|
+
setError(null);
|
|
7926
|
+
if (!selectedOption) return;
|
|
7927
|
+
const family = selectedOption.chainFamily;
|
|
7928
|
+
setSessionsByFamily((prev) => {
|
|
7929
|
+
if (!prev[family]) return prev;
|
|
7930
|
+
const next = { ...prev };
|
|
7931
|
+
delete next[family];
|
|
7932
|
+
return next;
|
|
7933
|
+
});
|
|
7934
|
+
premintedFamiliesRef.current.delete(family);
|
|
7935
|
+
const ptKey = perTokenKey(selectedOption.chainId, selectedOption.tokenAddress);
|
|
7936
|
+
setPerTokenSessions((prev) => {
|
|
7937
|
+
if (!prev[ptKey]) return prev;
|
|
7938
|
+
const next = { ...prev };
|
|
7939
|
+
delete next[ptKey];
|
|
7940
|
+
return next;
|
|
7941
|
+
});
|
|
7942
|
+
}, [selectedOption]);
|
|
7561
7943
|
return {
|
|
7562
|
-
|
|
7563
|
-
|
|
7564
|
-
|
|
7565
|
-
|
|
7944
|
+
sourceOptions,
|
|
7945
|
+
loadingSources,
|
|
7946
|
+
selectedToken,
|
|
7947
|
+
selectedChainId,
|
|
7948
|
+
session,
|
|
7949
|
+
loading,
|
|
7950
|
+
error,
|
|
7951
|
+
qrReady,
|
|
7952
|
+
copiedAddress,
|
|
7953
|
+
tokenChoices,
|
|
7954
|
+
chainChoices,
|
|
7955
|
+
tokenLogoUriBySymbol,
|
|
7956
|
+
selectedOption,
|
|
7957
|
+
tokensForSelectedChain,
|
|
7958
|
+
chainsForSelectedToken,
|
|
7959
|
+
screen,
|
|
7960
|
+
sessionFeeCopy,
|
|
7961
|
+
depositAddress,
|
|
7962
|
+
createSession,
|
|
7963
|
+
copyDepositAddress,
|
|
7964
|
+
backToSourceSelector,
|
|
7965
|
+
resetSessionForNewSelection,
|
|
7966
|
+
selectToken,
|
|
7967
|
+
selectChainId
|
|
7566
7968
|
};
|
|
7567
7969
|
}
|
|
7568
|
-
|
|
7569
|
-
|
|
7570
|
-
|
|
7571
|
-
|
|
7572
|
-
|
|
7573
|
-
|
|
7574
|
-
|
|
7575
|
-
|
|
7576
|
-
|
|
7577
|
-
|
|
7578
|
-
|
|
7579
|
-
|
|
7580
|
-
|
|
7581
|
-
|
|
7582
|
-
|
|
7583
|
-
|
|
7584
|
-
|
|
7585
|
-
|
|
7586
|
-
|
|
7587
|
-
passkeyConfigLoaded: false,
|
|
7588
|
-
activeCredentialId: config.activeCredentialId,
|
|
7589
|
-
knownCredentialIds: [],
|
|
7590
|
-
oneTapLimit: DEFAULT_ONE_TAP_LIMIT,
|
|
7591
|
-
oneTapLimitSavedDuringSetup: false,
|
|
7592
|
-
mobileFlow: false,
|
|
7593
|
-
deeplinkUri: null,
|
|
7594
|
-
increasingLimit: false,
|
|
7595
|
-
activePublicKey: null,
|
|
7596
|
-
loginRequested: false,
|
|
7597
|
-
standardDesktopInlineOpenWallet: false,
|
|
7598
|
-
desktopWait: null,
|
|
7599
|
-
setupAuthorizationSessionId: null,
|
|
7600
|
-
mobileTokenAuthorizationPending: false,
|
|
7601
|
-
privyReady: false,
|
|
7602
|
-
privyAuthenticated: false,
|
|
7603
|
-
lastResumedAt: 0,
|
|
7604
|
-
setupDepositAmount: null,
|
|
7605
|
-
setupDepositToken: null,
|
|
7606
|
-
setupDepositConfirmed: false,
|
|
7607
|
-
guestWalletPrepared: null,
|
|
7608
|
-
guestWalletDeeplinksPreparing: false,
|
|
7609
|
-
amountTooLow: null,
|
|
7610
|
-
enableFullWidget: config.enableFullWidget ?? false,
|
|
7611
|
-
requireAmountEntry: config.depositAmount == null
|
|
7612
|
-
};
|
|
7970
|
+
var ManualTransferSessionContext = createContext(null);
|
|
7971
|
+
function ManualTransferSessionProvider({
|
|
7972
|
+
destination,
|
|
7973
|
+
merchantAuthorization,
|
|
7974
|
+
idempotencyKey,
|
|
7975
|
+
onComplete,
|
|
7976
|
+
onError,
|
|
7977
|
+
pollEnabled,
|
|
7978
|
+
children
|
|
7979
|
+
}) {
|
|
7980
|
+
const session = useManualTransferSession({
|
|
7981
|
+
destination,
|
|
7982
|
+
merchantAuthorization,
|
|
7983
|
+
idempotencyKey,
|
|
7984
|
+
onComplete,
|
|
7985
|
+
onError,
|
|
7986
|
+
pollEnabled
|
|
7987
|
+
});
|
|
7988
|
+
return /* @__PURE__ */ jsx(ManualTransferSessionContext.Provider, { value: session, children });
|
|
7613
7989
|
}
|
|
7614
|
-
function
|
|
7615
|
-
|
|
7616
|
-
|
|
7617
|
-
|
|
7618
|
-
|
|
7619
|
-
|
|
7620
|
-
|
|
7621
|
-
|
|
7622
|
-
|
|
7623
|
-
|
|
7624
|
-
|
|
7625
|
-
|
|
7626
|
-
|
|
7627
|
-
|
|
7628
|
-
|
|
7629
|
-
|
|
7630
|
-
|
|
7990
|
+
function useManualTransferSessionContext() {
|
|
7991
|
+
const ctx = useContext(ManualTransferSessionContext);
|
|
7992
|
+
if (!ctx) {
|
|
7993
|
+
throw new Error(
|
|
7994
|
+
"useManualTransferSessionContext must be used within a <ManualTransferSessionProvider>"
|
|
7995
|
+
);
|
|
7996
|
+
}
|
|
7997
|
+
return ctx;
|
|
7998
|
+
}
|
|
7999
|
+
|
|
8000
|
+
// src/processingStatus.ts
|
|
8001
|
+
var PROCESSING_TIMEOUT_MS = 18e4;
|
|
8002
|
+
var TERMINAL_TRANSFER_STATUSES = /* @__PURE__ */ new Set(["COMPLETED", "FAILED", "EXPIRED"]);
|
|
8003
|
+
var SIGNABLE_TRANSFER_STATUSES = /* @__PURE__ */ new Set(["CREATED", "AUTHORIZED"]);
|
|
8004
|
+
function isTerminalTransferStatus(status) {
|
|
8005
|
+
return TERMINAL_TRANSFER_STATUSES.has(status);
|
|
8006
|
+
}
|
|
8007
|
+
function isTransferSignable(transfer) {
|
|
8008
|
+
return transfer != null && SIGNABLE_TRANSFER_STATUSES.has(transfer.status);
|
|
8009
|
+
}
|
|
8010
|
+
function isTransferAwaitingCompletion(transfer) {
|
|
8011
|
+
if (!transfer) return false;
|
|
8012
|
+
return !isTerminalTransferStatus(transfer.status);
|
|
8013
|
+
}
|
|
8014
|
+
function resolvePreferredTransfer(polledTransfer, localTransfer) {
|
|
8015
|
+
return polledTransfer ?? localTransfer;
|
|
8016
|
+
}
|
|
8017
|
+
function getTransferStatus(polledTransfer, localTransfer) {
|
|
8018
|
+
const transfer = resolvePreferredTransfer(polledTransfer, localTransfer);
|
|
8019
|
+
return transfer?.status ?? "UNKNOWN";
|
|
8020
|
+
}
|
|
8021
|
+
function hasProcessingTimedOut(processingStartedAtMs, nowMs) {
|
|
8022
|
+
if (!processingStartedAtMs) return false;
|
|
8023
|
+
return nowMs - processingStartedAtMs >= PROCESSING_TIMEOUT_MS;
|
|
8024
|
+
}
|
|
8025
|
+
var STATUS_DISPLAY_LABELS = {
|
|
8026
|
+
CREATED: "created",
|
|
8027
|
+
AUTHORIZED: "authorized",
|
|
8028
|
+
SENDING: "sending",
|
|
8029
|
+
SENT: "confirming delivery",
|
|
8030
|
+
COMPLETED: "completed",
|
|
8031
|
+
FAILED: "failed"
|
|
8032
|
+
};
|
|
8033
|
+
function getStatusDisplayLabel(status) {
|
|
8034
|
+
return STATUS_DISPLAY_LABELS[status] ?? status;
|
|
8035
|
+
}
|
|
8036
|
+
function buildProcessingTimeoutMessage(status) {
|
|
8037
|
+
const label = getStatusDisplayLabel(status);
|
|
8038
|
+
return `Payment is taking longer than expected (status: ${label}). Please try again.`;
|
|
8039
|
+
}
|
|
8040
|
+
|
|
8041
|
+
// src/paymentResolvePhase.ts
|
|
8042
|
+
function hasActiveWallet(accounts) {
|
|
8043
|
+
return accounts.some((a) => a.wallets.some((w) => w.status === "ACTIVE"));
|
|
8044
|
+
}
|
|
8045
|
+
function resolveTerminalPhase(state) {
|
|
8046
|
+
if (state.amountTooLow != null) {
|
|
8047
|
+
return {
|
|
8048
|
+
step: "amount-too-low",
|
|
8049
|
+
minAmountUsd: state.amountTooLow.minAmountUsd
|
|
8050
|
+
};
|
|
8051
|
+
}
|
|
8052
|
+
const transferCompleted = state.transfer?.status === "COMPLETED";
|
|
8053
|
+
const needsPasskeyBootstrap = state.privyAuthenticated && !state.activeCredentialId;
|
|
8054
|
+
if (transferCompleted && !needsPasskeyBootstrap && !state.loginRequested) {
|
|
8055
|
+
return { step: "completed", transfer: state.transfer };
|
|
8056
|
+
}
|
|
8057
|
+
if (state.transfer?.status === "FAILED") {
|
|
8058
|
+
return {
|
|
8059
|
+
step: "failed",
|
|
8060
|
+
transfer: state.transfer,
|
|
8061
|
+
error: state.error ?? "Transfer failed."
|
|
8062
|
+
};
|
|
8063
|
+
}
|
|
8064
|
+
if (state.creatingTransfer || isTransferAwaitingCompletion(state.transfer)) {
|
|
8065
|
+
return { step: "processing", transfer: state.transfer };
|
|
8066
|
+
}
|
|
8067
|
+
return null;
|
|
8068
|
+
}
|
|
8069
|
+
function resolveStickyPhase(state) {
|
|
8070
|
+
const currentPhase = state.phase;
|
|
8071
|
+
if (currentPhase.step === "manual-transfer" && !state.loginRequested) {
|
|
8072
|
+
return currentPhase;
|
|
8073
|
+
}
|
|
8074
|
+
if (currentPhase.step === "deposit-options" && !state.loginRequested && !state.privyAuthenticated) {
|
|
8075
|
+
return currentPhase;
|
|
8076
|
+
}
|
|
8077
|
+
if (!state.loginRequested && state.setupFlowScreen === "one-tap-setup") {
|
|
8078
|
+
return { step: "one-tap-setup", action: null };
|
|
8079
|
+
}
|
|
8080
|
+
if (!state.loginRequested && state.setupFlowScreen === "deposit-confirm" && state.selectedAccountId != null) {
|
|
8081
|
+
return {
|
|
8082
|
+
step: "wallet-setup",
|
|
8083
|
+
mobile: null,
|
|
8084
|
+
accountId: state.selectedAccountId
|
|
8085
|
+
};
|
|
8086
|
+
}
|
|
8087
|
+
if (!state.loginRequested && state.mobileTokenAuthorizationPending) {
|
|
8088
|
+
return {
|
|
8089
|
+
step: "wallet-setup",
|
|
8090
|
+
mobile: { deeplinkUri: "", providerId: state.selectedProviderId },
|
|
8091
|
+
accountId: null
|
|
8092
|
+
};
|
|
8093
|
+
}
|
|
8094
|
+
const isFundingSourceSubflow = !state.loginRequested && (currentPhase.step === "token-picker" || currentPhase.step === "guest-source-picker" || currentPhase.step === "select-source" || currentPhase.step === "confirm-sign");
|
|
8095
|
+
if (isFundingSourceSubflow) {
|
|
8096
|
+
return currentPhase;
|
|
8097
|
+
}
|
|
8098
|
+
if ((state.standardDesktopInlineOpenWallet || state.desktopWait != null) && state.privyAuthenticated && state.activeCredentialId != null && state.selectedAccountId != null && !state.loginRequested) {
|
|
8099
|
+
return {
|
|
8100
|
+
step: "wallet-setup",
|
|
8101
|
+
mobile: null,
|
|
8102
|
+
desktopWait: state.desktopWait,
|
|
8103
|
+
accountId: state.selectedAccountId
|
|
8104
|
+
};
|
|
8105
|
+
}
|
|
8106
|
+
if (state.mobileFlow && state.deeplinkUri != null) {
|
|
8107
|
+
return {
|
|
8108
|
+
step: "wallet-setup",
|
|
8109
|
+
mobile: { deeplinkUri: state.deeplinkUri, providerId: state.selectedProviderId },
|
|
8110
|
+
accountId: null
|
|
8111
|
+
};
|
|
8112
|
+
}
|
|
8113
|
+
if (currentPhase.step === "wallet-picker" && currentPhase.reason === "switch" && !state.creatingTransfer && !(state.mobileFlow && state.deeplinkUri)) {
|
|
8114
|
+
return currentPhase;
|
|
8115
|
+
}
|
|
8116
|
+
return null;
|
|
8117
|
+
}
|
|
8118
|
+
function deriveFreshPhase(state) {
|
|
8119
|
+
if (!state.privyReady) {
|
|
8120
|
+
return { step: "initializing" };
|
|
8121
|
+
}
|
|
8122
|
+
if (state.privyAuthenticated && !state.activeCredentialId && !state.passkeyConfigLoaded) {
|
|
8123
|
+
return { step: "initializing" };
|
|
8124
|
+
}
|
|
8125
|
+
if (state.loginRequested) {
|
|
8126
|
+
return { step: "login" };
|
|
8127
|
+
}
|
|
8128
|
+
if (state.enableFullWidget && !state.privyAuthenticated) {
|
|
8129
|
+
return { step: "deposit-options" };
|
|
8130
|
+
}
|
|
8131
|
+
if (!state.privyAuthenticated) {
|
|
8132
|
+
return { step: "login" };
|
|
8133
|
+
}
|
|
8134
|
+
if (state.loadingData && state.activeCredentialId != null) {
|
|
8135
|
+
return { step: "data-loading" };
|
|
8136
|
+
}
|
|
8137
|
+
if (state.requireAmountEntry) {
|
|
8138
|
+
return { step: "enter-amount" };
|
|
8139
|
+
}
|
|
8140
|
+
if (state.activeCredentialId != null && !hasActiveWallet(state.accounts) && !state.mobileFlow) {
|
|
8141
|
+
return { step: "wallet-picker", reason: "link" };
|
|
8142
|
+
}
|
|
8143
|
+
if (state.activeCredentialId != null && hasActiveWallet(state.accounts) && !state.loadingData) {
|
|
8144
|
+
return { step: "deposit" };
|
|
8145
|
+
}
|
|
8146
|
+
return { step: "wallet-picker", reason: "entry" };
|
|
8147
|
+
}
|
|
8148
|
+
function resolvePhase(state) {
|
|
8149
|
+
return resolveTerminalPhase(state) ?? resolveStickyPhase(state) ?? deriveFreshPhase(state);
|
|
8150
|
+
}
|
|
8151
|
+
|
|
8152
|
+
// src/paymentReducer.ts
|
|
8153
|
+
var DEFAULT_ONE_TAP_LIMIT = 1e4;
|
|
8154
|
+
function deriveSourceTypeAndId(state) {
|
|
8155
|
+
if (state.selectedWalletId) {
|
|
8156
|
+
return { sourceType: "walletId", sourceId: state.selectedWalletId };
|
|
8157
|
+
}
|
|
8158
|
+
if (state.selectedAccountId) {
|
|
8159
|
+
return { sourceType: "accountId", sourceId: state.selectedAccountId };
|
|
8160
|
+
}
|
|
8161
|
+
return { sourceType: "accountId", sourceId: "" };
|
|
8162
|
+
}
|
|
8163
|
+
function clearStaleSelection(state) {
|
|
8164
|
+
if (state.selectedAccountId == null) return state;
|
|
8165
|
+
if (state.desktopWait != null) return state;
|
|
8166
|
+
const stillExists = state.accounts.some((a) => a.id === state.selectedAccountId);
|
|
8167
|
+
if (stillExists) return state;
|
|
8168
|
+
return {
|
|
8169
|
+
...state,
|
|
8170
|
+
selectedAccountId: null,
|
|
8171
|
+
selectedWalletId: null,
|
|
8172
|
+
selectedTokenSymbol: null
|
|
8173
|
+
};
|
|
8174
|
+
}
|
|
8175
|
+
function createInitialState(config) {
|
|
8176
|
+
return {
|
|
8177
|
+
phase: config.initialPhase ?? { step: "initializing" },
|
|
8178
|
+
error: null,
|
|
8179
|
+
setupFlowScreen: null,
|
|
8180
|
+
providers: [],
|
|
8181
|
+
accounts: [],
|
|
8182
|
+
chains: [],
|
|
8183
|
+
loadingData: false,
|
|
8184
|
+
depositSelectionRefreshing: false,
|
|
8185
|
+
selectedProviderId: null,
|
|
8186
|
+
selectedAccountId: null,
|
|
8187
|
+
selectedWalletId: null,
|
|
8188
|
+
selectedTokenSymbol: null,
|
|
8189
|
+
savedSelection: null,
|
|
8190
|
+
amount: config.depositAmount != null ? config.depositAmount.toString() : "",
|
|
8191
|
+
transfer: null,
|
|
8192
|
+
pendingTransferId: null,
|
|
8193
|
+
creatingTransfer: false,
|
|
8194
|
+
passkeyConfigLoaded: false,
|
|
8195
|
+
activeCredentialId: config.activeCredentialId,
|
|
8196
|
+
knownCredentialIds: [],
|
|
8197
|
+
oneTapLimit: DEFAULT_ONE_TAP_LIMIT,
|
|
8198
|
+
oneTapLimitSavedDuringSetup: false,
|
|
8199
|
+
mobileFlow: false,
|
|
8200
|
+
deeplinkUri: null,
|
|
8201
|
+
increasingLimit: false,
|
|
8202
|
+
activePublicKey: null,
|
|
8203
|
+
loginRequested: false,
|
|
8204
|
+
standardDesktopInlineOpenWallet: false,
|
|
8205
|
+
desktopWait: null,
|
|
8206
|
+
setupAuthorizationSessionId: null,
|
|
8207
|
+
mobileTokenAuthorizationPending: false,
|
|
8208
|
+
privyReady: false,
|
|
8209
|
+
privyAuthenticated: false,
|
|
8210
|
+
lastResumedAt: 0,
|
|
8211
|
+
setupDepositAmount: null,
|
|
8212
|
+
setupDepositToken: null,
|
|
8213
|
+
setupDepositConfirmed: false,
|
|
8214
|
+
guestWalletPrepared: null,
|
|
8215
|
+
guestWalletDeeplinksPreparing: false,
|
|
8216
|
+
amountTooLow: null,
|
|
8217
|
+
enableFullWidget: config.enableFullWidget ?? false,
|
|
8218
|
+
requireAmountEntry: config.depositAmount == null
|
|
8219
|
+
};
|
|
8220
|
+
}
|
|
8221
|
+
function clearAuthenticatedSessionState(state) {
|
|
8222
|
+
return {
|
|
8223
|
+
...state,
|
|
8224
|
+
error: null,
|
|
8225
|
+
setupFlowScreen: null,
|
|
8226
|
+
providers: [],
|
|
8227
|
+
accounts: [],
|
|
8228
|
+
chains: [],
|
|
8229
|
+
loadingData: false,
|
|
8230
|
+
depositSelectionRefreshing: false,
|
|
8231
|
+
selectedProviderId: null,
|
|
8232
|
+
selectedAccountId: null,
|
|
8233
|
+
selectedWalletId: null,
|
|
8234
|
+
selectedTokenSymbol: null,
|
|
8235
|
+
savedSelection: null,
|
|
8236
|
+
transfer: null,
|
|
8237
|
+
pendingTransferId: null,
|
|
7631
8238
|
creatingTransfer: false,
|
|
7632
8239
|
passkeyConfigLoaded: false,
|
|
7633
8240
|
activeCredentialId: null,
|
|
@@ -8071,552 +8678,118 @@ function applyAction(state, action) {
|
|
|
8071
8678
|
// unauthenticated path) preserves the flag implicitly via the
|
|
8072
8679
|
// surrounding `...state` spread, so no change is needed there.
|
|
8073
8680
|
enableFullWidget: state.enableFullWidget
|
|
8074
|
-
};
|
|
8075
|
-
case "SYNC_PRIVY_SESSION":
|
|
8076
|
-
if (action.ready && !action.authenticated) {
|
|
8077
|
-
return {
|
|
8078
|
-
...clearAuthenticatedSessionState(state),
|
|
8079
|
-
privyReady: true,
|
|
8080
|
-
privyAuthenticated: false
|
|
8081
|
-
};
|
|
8082
|
-
}
|
|
8083
|
-
return {
|
|
8084
|
-
...state,
|
|
8085
|
-
privyReady: action.ready,
|
|
8086
|
-
privyAuthenticated: action.authenticated,
|
|
8087
|
-
...action.authenticated ? { loginRequested: false } : {}
|
|
8088
|
-
};
|
|
8089
|
-
case "SYNC_AMOUNT":
|
|
8090
|
-
return {
|
|
8091
|
-
...state,
|
|
8092
|
-
amount: action.amount,
|
|
8093
|
-
requireAmountEntry: action.amount === "" ? state.requireAmountEntry : false
|
|
8094
|
-
};
|
|
8095
|
-
case "SET_AMOUNT_INPUT":
|
|
8096
|
-
return { ...state, amount: action.value };
|
|
8097
|
-
case "FINALIZE_AMOUNT":
|
|
8098
|
-
return { ...state, requireAmountEntry: false };
|
|
8099
|
-
case "PAGE_RESUMED":
|
|
8100
|
-
return { ...state, lastResumedAt: Date.now() };
|
|
8101
|
-
// ── Setup deposit (combined first-time flow) ────────────────
|
|
8102
|
-
case "SET_SETUP_DEPOSIT_AMOUNT":
|
|
8103
|
-
return { ...state, setupDepositAmount: action.amount };
|
|
8104
|
-
case "SET_SETUP_DEPOSIT_TOKEN":
|
|
8105
|
-
return {
|
|
8106
|
-
...state,
|
|
8107
|
-
setupDepositToken: {
|
|
8108
|
-
symbol: action.symbol,
|
|
8109
|
-
chainName: action.chainName,
|
|
8110
|
-
...action.walletId ? { walletId: action.walletId } : {},
|
|
8111
|
-
...action.tokenAddress ? { tokenAddress: action.tokenAddress } : {},
|
|
8112
|
-
...action.chainId != null ? { chainId: action.chainId } : {}
|
|
8113
|
-
}
|
|
8114
|
-
};
|
|
8115
|
-
case "CLEAR_SETUP_DEPOSIT_TOKEN":
|
|
8116
|
-
return { ...state, setupDepositToken: null };
|
|
8117
|
-
case "CONFIRM_SETUP_DEPOSIT":
|
|
8118
|
-
return { ...state, setupDepositConfirmed: true };
|
|
8119
|
-
default:
|
|
8120
|
-
return state;
|
|
8121
|
-
}
|
|
8122
|
-
}
|
|
8123
|
-
|
|
8124
|
-
// src/setupDepositConfirmation.ts
|
|
8125
|
-
function deriveEffectiveSetupSource(setupDepositToken, setupSelectedSourceOption) {
|
|
8126
|
-
if (setupDepositToken) return setupDepositToken;
|
|
8127
|
-
if (setupSelectedSourceOption) {
|
|
8128
|
-
return {
|
|
8129
|
-
symbol: setupSelectedSourceOption.tokenSymbol,
|
|
8130
|
-
chainName: setupSelectedSourceOption.chainName,
|
|
8131
|
-
walletId: setupSelectedSourceOption.walletId,
|
|
8132
|
-
tokenAddress: setupSelectedSourceOption.tokenAddress,
|
|
8133
|
-
chainId: setupSelectedSourceOption.chainId != null ? Number(setupSelectedSourceOption.chainId) : void 0
|
|
8134
|
-
};
|
|
8135
|
-
}
|
|
8136
|
-
return null;
|
|
8137
|
-
}
|
|
8138
|
-
function planConfirmSetupDeposit(input) {
|
|
8139
|
-
const effective = deriveEffectiveSetupSource(
|
|
8140
|
-
input.setupDepositToken,
|
|
8141
|
-
input.setupSelectedSourceOption
|
|
8142
|
-
);
|
|
8143
|
-
if (!effective) {
|
|
8144
|
-
return { kind: "error", error: "Select a source token before continuing." };
|
|
8145
|
-
}
|
|
8146
|
-
if (!effective.walletId) {
|
|
8147
|
-
return {
|
|
8148
|
-
kind: "error",
|
|
8149
|
-
error: "Selected source is not ready yet. Wait for wallet discovery to finish."
|
|
8150
|
-
};
|
|
8151
|
-
}
|
|
8152
|
-
const actions = [
|
|
8153
|
-
{ type: "SET_ERROR", error: null },
|
|
8154
|
-
{
|
|
8155
|
-
type: "SET_SETUP_DEPOSIT_TOKEN",
|
|
8156
|
-
symbol: effective.symbol,
|
|
8157
|
-
chainName: effective.chainName,
|
|
8158
|
-
walletId: effective.walletId,
|
|
8159
|
-
tokenAddress: effective.tokenAddress,
|
|
8160
|
-
chainId: effective.chainId
|
|
8161
|
-
}
|
|
8162
|
-
];
|
|
8163
|
-
if (input.selectedAccountId) {
|
|
8164
|
-
actions.push({
|
|
8165
|
-
type: "SELECT_ACCOUNT",
|
|
8166
|
-
accountId: input.selectedAccountId,
|
|
8167
|
-
walletId: effective.walletId
|
|
8168
|
-
});
|
|
8169
|
-
actions.push({
|
|
8170
|
-
type: "SELECT_TOKEN",
|
|
8171
|
-
walletId: effective.walletId,
|
|
8172
|
-
tokenSymbol: effective.symbol
|
|
8173
|
-
});
|
|
8174
|
-
}
|
|
8175
|
-
actions.push({ type: "SET_SETUP_FLOW_SCREEN", screen: "one-tap-setup" });
|
|
8176
|
-
actions.push({ type: "CONFIRM_SETUP_DEPOSIT" });
|
|
8177
|
-
return {
|
|
8178
|
-
kind: "proceed",
|
|
8179
|
-
actions,
|
|
8180
|
-
resolveSource: {
|
|
8181
|
-
chainName: effective.chainName,
|
|
8182
|
-
tokenSymbol: effective.symbol
|
|
8183
|
-
}
|
|
8184
|
-
};
|
|
8185
|
-
}
|
|
8186
|
-
|
|
8187
|
-
// src/manualTransferUtils.ts
|
|
8188
|
-
function screenForSession(session) {
|
|
8189
|
-
if (!session) return "source-selector";
|
|
8190
|
-
switch (session.status) {
|
|
8191
|
-
case "awaiting_deposit":
|
|
8192
|
-
return "awaiting-deposit";
|
|
8193
|
-
case "deposit_received":
|
|
8194
|
-
return "deposit-received";
|
|
8195
|
-
case "routing":
|
|
8196
|
-
return "deposit-routing";
|
|
8197
|
-
case "completed":
|
|
8198
|
-
return "deposit-complete";
|
|
8199
|
-
case "refunded":
|
|
8200
|
-
case "failed":
|
|
8201
|
-
case "wrong_token":
|
|
8202
|
-
return "deposit-failed";
|
|
8203
|
-
}
|
|
8204
|
-
}
|
|
8205
|
-
function feeCopy(_session) {
|
|
8206
|
-
return "No fees";
|
|
8207
|
-
}
|
|
8208
|
-
function toTransfer(session) {
|
|
8209
|
-
return {
|
|
8210
|
-
id: session.sessionId,
|
|
8211
|
-
status: session.status,
|
|
8212
|
-
amount: {
|
|
8213
|
-
amount: Number(session.deliveredAmountUsd ?? session.minAmountUsd),
|
|
8214
|
-
currency: "USD"
|
|
8215
|
-
},
|
|
8216
|
-
sources: [],
|
|
8217
|
-
destinations: [{
|
|
8218
|
-
id: session.sessionId,
|
|
8219
|
-
chainId: session.destination.chainId,
|
|
8220
|
-
address: session.destination.address,
|
|
8221
|
-
token: { address: session.destination.token.address, symbol: "" },
|
|
8222
|
-
amount: { amount: Number(session.deliveredAmountUsd ?? session.minAmountUsd), currency: "USD" }
|
|
8223
|
-
}],
|
|
8224
|
-
createDate: session.createDate,
|
|
8225
|
-
updateDate: session.updateDate
|
|
8226
|
-
};
|
|
8227
|
-
}
|
|
8228
|
-
var SOLANA_CHAIN_ID = 792703809;
|
|
8229
|
-
var SOLANA_NATIVE_SOL_ADDRESS = "11111111111111111111111111111111";
|
|
8230
|
-
function formatDepositUri(address, chainId, depToken) {
|
|
8231
|
-
if (chainId === SOLANA_CHAIN_ID) {
|
|
8232
|
-
if (!depToken || depToken === SOLANA_NATIVE_SOL_ADDRESS) {
|
|
8233
|
-
return `solana:${address}`;
|
|
8234
|
-
}
|
|
8235
|
-
return `solana:${address}?spl-token=${depToken}`;
|
|
8236
|
-
}
|
|
8237
|
-
return address;
|
|
8238
|
-
}
|
|
8239
|
-
|
|
8240
|
-
// src/hooks/useManualTransferSession.ts
|
|
8241
|
-
function useManualTransferSession({
|
|
8242
|
-
destination,
|
|
8243
|
-
merchantAuthorization,
|
|
8244
|
-
idempotencyKey,
|
|
8245
|
-
mock = false,
|
|
8246
|
-
onComplete,
|
|
8247
|
-
onError
|
|
8248
|
-
}) {
|
|
8249
|
-
const { apiBaseUrl } = useBlinkConfig();
|
|
8250
|
-
const [sourceOptions, setSourceOptions] = useState(null);
|
|
8251
|
-
const [loadingSources, setLoadingSources] = useState(true);
|
|
8252
|
-
const [selectedToken, setSelectedToken] = useState("");
|
|
8253
|
-
const [selectedChainId, setSelectedChainId] = useState("");
|
|
8254
|
-
const [session, setSession] = useState(null);
|
|
8255
|
-
const [loading, setLoading] = useState(false);
|
|
8256
|
-
const [error, setError] = useState(null);
|
|
8257
|
-
const [qrReady, setQrReady] = useState(false);
|
|
8258
|
-
const [copiedAddress, setCopiedAddress] = useState(null);
|
|
8259
|
-
const completedRef = useRef(null);
|
|
8260
|
-
const lastCreatedOptionRef = useRef(null);
|
|
8261
|
-
useEffect(() => {
|
|
8262
|
-
if (!merchantAuthorization) return;
|
|
8263
|
-
let cancelled = false;
|
|
8264
|
-
setLoadingSources(true);
|
|
8265
|
-
fetchManualTransferSources(apiBaseUrl, { merchantAuthorization, destination }).then((sources) => {
|
|
8266
|
-
if (!cancelled) {
|
|
8267
|
-
setSourceOptions(sources);
|
|
8268
|
-
setLoadingSources(false);
|
|
8269
|
-
const defaultOption = sources.find(
|
|
8270
|
-
(opt) => opt.tokenSymbol === "USDC" && opt.chainId === 792703809
|
|
8271
|
-
);
|
|
8272
|
-
if (defaultOption) {
|
|
8273
|
-
setSelectedToken("USDC");
|
|
8274
|
-
setSelectedChainId("792703809");
|
|
8275
|
-
}
|
|
8276
|
-
}
|
|
8277
|
-
}).catch((err) => {
|
|
8278
|
-
if (!cancelled) {
|
|
8279
|
-
setError(err instanceof Error ? err.message : String(err));
|
|
8280
|
-
setLoadingSources(false);
|
|
8281
|
-
}
|
|
8282
|
-
});
|
|
8283
|
-
return () => {
|
|
8284
|
-
cancelled = true;
|
|
8285
|
-
};
|
|
8286
|
-
}, [apiBaseUrl, destination, merchantAuthorization]);
|
|
8287
|
-
const depositAddress = session?.depositAddress;
|
|
8288
|
-
useEffect(() => {
|
|
8289
|
-
if (!depositAddress) {
|
|
8290
|
-
setQrReady(false);
|
|
8291
|
-
return;
|
|
8292
|
-
}
|
|
8293
|
-
const timer = window.setTimeout(() => setQrReady(true), 1200);
|
|
8294
|
-
return () => window.clearTimeout(timer);
|
|
8295
|
-
}, [depositAddress]);
|
|
8296
|
-
const lastFeeCopyRef = useRef(null);
|
|
8297
|
-
const nextFeeCopy = session ? feeCopy() : null;
|
|
8298
|
-
const sessionFeeCopy = nextFeeCopy === lastFeeCopyRef.current ? lastFeeCopyRef.current : lastFeeCopyRef.current = nextFeeCopy;
|
|
8299
|
-
const advanceMockStatus = useCallback((status) => {
|
|
8300
|
-
setSession((prev) => prev ? { ...prev, status } : prev);
|
|
8301
|
-
}, []);
|
|
8302
|
-
useEffect(() => {
|
|
8303
|
-
if (mock) return;
|
|
8304
|
-
if (!session?.sessionId || ["completed", "failed", "refunded", "wrong_token"].includes(session.status)) return;
|
|
8305
|
-
const timer = window.setInterval(() => {
|
|
8306
|
-
fetchManualTransferSession(apiBaseUrl, session.sessionId).then(setSession).catch((err) => setError(err instanceof Error ? err.message : String(err)));
|
|
8307
|
-
}, 2e3);
|
|
8308
|
-
return () => window.clearInterval(timer);
|
|
8309
|
-
}, [apiBaseUrl, mock, session?.sessionId, session?.status]);
|
|
8310
|
-
useEffect(() => {
|
|
8311
|
-
if (mock) return;
|
|
8312
|
-
if (!session?.sessionId || session.status !== "awaiting_deposit") return;
|
|
8313
|
-
const sessionId = session.sessionId;
|
|
8314
|
-
const timer = window.setInterval(() => {
|
|
8315
|
-
refreshManualTransferQuote(apiBaseUrl, sessionId).then(({ quoteValidUntil, minAmountUsd, slippage }) => {
|
|
8316
|
-
setSession(
|
|
8317
|
-
(prev) => prev && prev.sessionId === sessionId ? { ...prev, quoteValidUntil, minAmountUsd, slippage } : prev
|
|
8318
|
-
);
|
|
8319
|
-
}).catch((err) => {
|
|
8320
|
-
console.warn("[manual-transfer] refresh quote failed", err);
|
|
8321
|
-
});
|
|
8322
|
-
}, 1e4);
|
|
8323
|
-
return () => window.clearInterval(timer);
|
|
8324
|
-
}, [apiBaseUrl, mock, session?.sessionId, session?.status]);
|
|
8325
|
-
useEffect(() => {
|
|
8326
|
-
if (session?.status !== "completed") return;
|
|
8327
|
-
if (completedRef.current === session.sessionId) return;
|
|
8328
|
-
completedRef.current = session.sessionId;
|
|
8329
|
-
onComplete?.(toTransfer(session));
|
|
8330
|
-
}, [onComplete, session]);
|
|
8331
|
-
useEffect(() => {
|
|
8332
|
-
if (!error) return;
|
|
8333
|
-
onError?.(error);
|
|
8334
|
-
}, [error, onError]);
|
|
8335
|
-
const tokenChoices = useMemo(
|
|
8336
|
-
() => Array.from(new Set((sourceOptions ?? []).map((opt) => opt.tokenSymbol))),
|
|
8337
|
-
[sourceOptions]
|
|
8338
|
-
);
|
|
8339
|
-
const chainChoices = useMemo(() => {
|
|
8340
|
-
const seen = /* @__PURE__ */ new Set();
|
|
8341
|
-
return (sourceOptions ?? []).filter((opt) => {
|
|
8342
|
-
if (seen.has(opt.chainId)) return false;
|
|
8343
|
-
seen.add(opt.chainId);
|
|
8344
|
-
return true;
|
|
8345
|
-
});
|
|
8346
|
-
}, [sourceOptions]);
|
|
8347
|
-
const tokenLogoUriBySymbol = useMemo(() => {
|
|
8348
|
-
const out = {};
|
|
8349
|
-
for (const opt of sourceOptions ?? []) {
|
|
8350
|
-
if (out[opt.tokenSymbol] == null) {
|
|
8351
|
-
out[opt.tokenSymbol] = opt.tokenLogoUri;
|
|
8352
|
-
}
|
|
8353
|
-
}
|
|
8354
|
-
return out;
|
|
8355
|
-
}, [sourceOptions]);
|
|
8356
|
-
const selectedOption = useMemo(
|
|
8357
|
-
() => (sourceOptions ?? []).find(
|
|
8358
|
-
(opt) => opt.tokenSymbol === selectedToken && String(opt.chainId) === selectedChainId
|
|
8359
|
-
) ?? null,
|
|
8360
|
-
[sourceOptions, selectedToken, selectedChainId]
|
|
8361
|
-
);
|
|
8362
|
-
const tokensForSelectedChain = useMemo(() => {
|
|
8363
|
-
if (!selectedChainId) return null;
|
|
8364
|
-
return new Set(
|
|
8365
|
-
(sourceOptions ?? []).filter((opt) => String(opt.chainId) === selectedChainId).map((opt) => opt.tokenSymbol)
|
|
8366
|
-
);
|
|
8367
|
-
}, [sourceOptions, selectedChainId]);
|
|
8368
|
-
const chainsForSelectedToken = useMemo(() => {
|
|
8369
|
-
if (!selectedToken) return null;
|
|
8370
|
-
return new Set(
|
|
8371
|
-
(sourceOptions ?? []).filter((opt) => opt.tokenSymbol === selectedToken).map((opt) => opt.chainId)
|
|
8372
|
-
);
|
|
8373
|
-
}, [sourceOptions, selectedToken]);
|
|
8374
|
-
const createSession = useCallback(async (option) => {
|
|
8375
|
-
if (!merchantAuthorization) return;
|
|
8376
|
-
setLoading(true);
|
|
8377
|
-
setError(null);
|
|
8378
|
-
try {
|
|
8379
|
-
if (mock) {
|
|
8380
|
-
const mockSession = {
|
|
8381
|
-
sessionId: `mock-${Date.now()}`,
|
|
8382
|
-
idempotencyKey: idempotencyKey ?? `mock-idem-${Date.now()}`,
|
|
8383
|
-
merchantId: "mock-merchant",
|
|
8384
|
-
destination,
|
|
8385
|
-
source: {
|
|
8386
|
-
chainId: option.chainId,
|
|
8387
|
-
tokenAddress: option.tokenAddress,
|
|
8388
|
-
tokenSymbol: option.tokenSymbol
|
|
8389
|
-
},
|
|
8390
|
-
refundTo: null,
|
|
8391
|
-
depositAddress: "0x" + "a1b2c3d4e5f6".repeat(3).slice(0, 40),
|
|
8392
|
-
requestId: `mock-req-${Date.now()}`,
|
|
8393
|
-
status: "awaiting_deposit",
|
|
8394
|
-
minAmountUsd: option.minAmountUsd,
|
|
8395
|
-
quoteValidUntil: new Date(Date.now() + 36e5).toISOString(),
|
|
8396
|
-
depositTxHashes: [],
|
|
8397
|
-
destinationTxHash: null,
|
|
8398
|
-
refundTxHashes: [],
|
|
8399
|
-
deliveredAmountUsd: null,
|
|
8400
|
-
errorCode: null,
|
|
8401
|
-
errorMessage: null,
|
|
8402
|
-
slippage: null,
|
|
8403
|
-
createDate: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8404
|
-
updateDate: (/* @__PURE__ */ new Date()).toISOString()
|
|
8405
|
-
};
|
|
8406
|
-
setSession(mockSession);
|
|
8407
|
-
} else {
|
|
8408
|
-
const created = await createManualTransfer(apiBaseUrl, {
|
|
8409
|
-
merchantAuthorization,
|
|
8410
|
-
destination,
|
|
8411
|
-
idempotencyKey,
|
|
8412
|
-
source: {
|
|
8413
|
-
chainId: option.chainId,
|
|
8414
|
-
tokenAddress: option.tokenAddress
|
|
8415
|
-
}
|
|
8416
|
-
});
|
|
8417
|
-
setSession(created);
|
|
8418
|
-
}
|
|
8419
|
-
} catch (err) {
|
|
8420
|
-
setError(err instanceof Error ? err.message : String(err));
|
|
8421
|
-
} finally {
|
|
8422
|
-
setLoading(false);
|
|
8423
|
-
}
|
|
8424
|
-
}, [apiBaseUrl, destination, idempotencyKey, merchantAuthorization, mock]);
|
|
8425
|
-
const resetSessionForNewSelection = useCallback(() => {
|
|
8426
|
-
setSession(null);
|
|
8427
|
-
lastCreatedOptionRef.current = null;
|
|
8428
|
-
}, []);
|
|
8429
|
-
const selectToken = useCallback((value) => {
|
|
8430
|
-
setSelectedToken(value);
|
|
8431
|
-
resetSessionForNewSelection();
|
|
8432
|
-
const pairValid = (sourceOptions ?? []).some(
|
|
8433
|
-
(opt) => opt.tokenSymbol === value && String(opt.chainId) === selectedChainId
|
|
8434
|
-
);
|
|
8435
|
-
if (!pairValid) {
|
|
8436
|
-
const firstChain = (sourceOptions ?? []).find(
|
|
8437
|
-
(opt) => opt.tokenSymbol === value
|
|
8438
|
-
);
|
|
8439
|
-
setSelectedChainId(
|
|
8440
|
-
firstChain ? String(firstChain.chainId) : ""
|
|
8441
|
-
);
|
|
8442
|
-
}
|
|
8443
|
-
}, [resetSessionForNewSelection, selectedChainId, sourceOptions]);
|
|
8444
|
-
const selectChainId = useCallback((value) => {
|
|
8445
|
-
setSelectedChainId(value);
|
|
8446
|
-
resetSessionForNewSelection();
|
|
8447
|
-
const pairValid = (sourceOptions ?? []).some(
|
|
8448
|
-
(opt) => opt.tokenSymbol === selectedToken && String(opt.chainId) === value
|
|
8449
|
-
);
|
|
8450
|
-
if (!pairValid) {
|
|
8451
|
-
const firstToken = (sourceOptions ?? []).find(
|
|
8452
|
-
(opt) => String(opt.chainId) === value
|
|
8453
|
-
);
|
|
8454
|
-
setSelectedToken(
|
|
8455
|
-
firstToken ? firstToken.tokenSymbol : ""
|
|
8456
|
-
);
|
|
8457
|
-
}
|
|
8458
|
-
}, [resetSessionForNewSelection, selectedToken, sourceOptions]);
|
|
8459
|
-
useEffect(() => {
|
|
8460
|
-
if (!selectedOption) return;
|
|
8461
|
-
const optionKey = `${selectedOption.chainId}:${selectedOption.tokenAddress}`;
|
|
8462
|
-
if (lastCreatedOptionRef.current === optionKey) return;
|
|
8463
|
-
lastCreatedOptionRef.current = optionKey;
|
|
8464
|
-
void createSession(selectedOption);
|
|
8465
|
-
}, [selectedOption, createSession]);
|
|
8466
|
-
const screen = screenForSession(session);
|
|
8467
|
-
const copyDepositAddress = useCallback(async (address) => {
|
|
8468
|
-
try {
|
|
8469
|
-
await navigator.clipboard.writeText(address);
|
|
8470
|
-
} catch {
|
|
8471
|
-
const textarea = document.createElement("textarea");
|
|
8472
|
-
textarea.value = address;
|
|
8473
|
-
textarea.setAttribute("readonly", "");
|
|
8474
|
-
textarea.style.position = "absolute";
|
|
8475
|
-
textarea.style.opacity = "0";
|
|
8476
|
-
document.body.appendChild(textarea);
|
|
8477
|
-
textarea.select();
|
|
8478
|
-
try {
|
|
8479
|
-
document.execCommand("copy");
|
|
8480
|
-
} finally {
|
|
8481
|
-
document.body.removeChild(textarea);
|
|
8681
|
+
};
|
|
8682
|
+
case "SYNC_PRIVY_SESSION":
|
|
8683
|
+
if (action.ready && !action.authenticated) {
|
|
8684
|
+
return {
|
|
8685
|
+
...clearAuthenticatedSessionState(state),
|
|
8686
|
+
privyReady: true,
|
|
8687
|
+
privyAuthenticated: false
|
|
8688
|
+
};
|
|
8482
8689
|
}
|
|
8690
|
+
return {
|
|
8691
|
+
...state,
|
|
8692
|
+
privyReady: action.ready,
|
|
8693
|
+
privyAuthenticated: action.authenticated,
|
|
8694
|
+
...action.authenticated ? { loginRequested: false } : {}
|
|
8695
|
+
};
|
|
8696
|
+
case "SYNC_AMOUNT":
|
|
8697
|
+
return {
|
|
8698
|
+
...state,
|
|
8699
|
+
amount: action.amount,
|
|
8700
|
+
requireAmountEntry: action.amount === "" ? state.requireAmountEntry : false
|
|
8701
|
+
};
|
|
8702
|
+
case "SET_AMOUNT_INPUT":
|
|
8703
|
+
return { ...state, amount: action.value };
|
|
8704
|
+
case "FINALIZE_AMOUNT":
|
|
8705
|
+
return { ...state, requireAmountEntry: false };
|
|
8706
|
+
case "PAGE_RESUMED":
|
|
8707
|
+
return { ...state, lastResumedAt: Date.now() };
|
|
8708
|
+
// ── Setup deposit (combined first-time flow) ────────────────
|
|
8709
|
+
case "SET_SETUP_DEPOSIT_AMOUNT":
|
|
8710
|
+
return { ...state, setupDepositAmount: action.amount };
|
|
8711
|
+
case "SET_SETUP_DEPOSIT_TOKEN":
|
|
8712
|
+
return {
|
|
8713
|
+
...state,
|
|
8714
|
+
setupDepositToken: {
|
|
8715
|
+
symbol: action.symbol,
|
|
8716
|
+
chainName: action.chainName,
|
|
8717
|
+
...action.walletId ? { walletId: action.walletId } : {},
|
|
8718
|
+
...action.tokenAddress ? { tokenAddress: action.tokenAddress } : {},
|
|
8719
|
+
...action.chainId != null ? { chainId: action.chainId } : {}
|
|
8720
|
+
}
|
|
8721
|
+
};
|
|
8722
|
+
case "CLEAR_SETUP_DEPOSIT_TOKEN":
|
|
8723
|
+
return { ...state, setupDepositToken: null };
|
|
8724
|
+
case "CONFIRM_SETUP_DEPOSIT":
|
|
8725
|
+
return { ...state, setupDepositConfirmed: true };
|
|
8726
|
+
default:
|
|
8727
|
+
return state;
|
|
8728
|
+
}
|
|
8729
|
+
}
|
|
8730
|
+
|
|
8731
|
+
// src/setupDepositConfirmation.ts
|
|
8732
|
+
function deriveEffectiveSetupSource(setupDepositToken, setupSelectedSourceOption) {
|
|
8733
|
+
if (setupDepositToken) return setupDepositToken;
|
|
8734
|
+
if (setupSelectedSourceOption) {
|
|
8735
|
+
return {
|
|
8736
|
+
symbol: setupSelectedSourceOption.tokenSymbol,
|
|
8737
|
+
chainName: setupSelectedSourceOption.chainName,
|
|
8738
|
+
walletId: setupSelectedSourceOption.walletId,
|
|
8739
|
+
tokenAddress: setupSelectedSourceOption.tokenAddress,
|
|
8740
|
+
chainId: setupSelectedSourceOption.chainId != null ? Number(setupSelectedSourceOption.chainId) : void 0
|
|
8741
|
+
};
|
|
8742
|
+
}
|
|
8743
|
+
return null;
|
|
8744
|
+
}
|
|
8745
|
+
function planConfirmSetupDeposit(input) {
|
|
8746
|
+
const effective = deriveEffectiveSetupSource(
|
|
8747
|
+
input.setupDepositToken,
|
|
8748
|
+
input.setupSelectedSourceOption
|
|
8749
|
+
);
|
|
8750
|
+
if (!effective) {
|
|
8751
|
+
return { kind: "error", error: "Select a source token before continuing." };
|
|
8752
|
+
}
|
|
8753
|
+
if (!effective.walletId) {
|
|
8754
|
+
return {
|
|
8755
|
+
kind: "error",
|
|
8756
|
+
error: "Selected source is not ready yet. Wait for wallet discovery to finish."
|
|
8757
|
+
};
|
|
8758
|
+
}
|
|
8759
|
+
const actions = [
|
|
8760
|
+
{ type: "SET_ERROR", error: null },
|
|
8761
|
+
{
|
|
8762
|
+
type: "SET_SETUP_DEPOSIT_TOKEN",
|
|
8763
|
+
symbol: effective.symbol,
|
|
8764
|
+
chainName: effective.chainName,
|
|
8765
|
+
walletId: effective.walletId,
|
|
8766
|
+
tokenAddress: effective.tokenAddress,
|
|
8767
|
+
chainId: effective.chainId
|
|
8483
8768
|
}
|
|
8484
|
-
|
|
8485
|
-
|
|
8486
|
-
|
|
8487
|
-
|
|
8488
|
-
|
|
8489
|
-
|
|
8490
|
-
|
|
8491
|
-
|
|
8492
|
-
|
|
8493
|
-
|
|
8494
|
-
|
|
8495
|
-
|
|
8769
|
+
];
|
|
8770
|
+
if (input.selectedAccountId) {
|
|
8771
|
+
actions.push({
|
|
8772
|
+
type: "SELECT_ACCOUNT",
|
|
8773
|
+
accountId: input.selectedAccountId,
|
|
8774
|
+
walletId: effective.walletId
|
|
8775
|
+
});
|
|
8776
|
+
actions.push({
|
|
8777
|
+
type: "SELECT_TOKEN",
|
|
8778
|
+
walletId: effective.walletId,
|
|
8779
|
+
tokenSymbol: effective.symbol
|
|
8780
|
+
});
|
|
8781
|
+
}
|
|
8782
|
+
actions.push({ type: "SET_SETUP_FLOW_SCREEN", screen: "one-tap-setup" });
|
|
8783
|
+
actions.push({ type: "CONFIRM_SETUP_DEPOSIT" });
|
|
8496
8784
|
return {
|
|
8497
|
-
|
|
8498
|
-
|
|
8499
|
-
|
|
8500
|
-
|
|
8501
|
-
|
|
8502
|
-
|
|
8503
|
-
error,
|
|
8504
|
-
qrReady,
|
|
8505
|
-
copiedAddress,
|
|
8506
|
-
tokenChoices,
|
|
8507
|
-
chainChoices,
|
|
8508
|
-
tokenLogoUriBySymbol,
|
|
8509
|
-
selectedOption,
|
|
8510
|
-
tokensForSelectedChain,
|
|
8511
|
-
chainsForSelectedToken,
|
|
8512
|
-
screen,
|
|
8513
|
-
sessionFeeCopy,
|
|
8514
|
-
depositAddress,
|
|
8515
|
-
createSession,
|
|
8516
|
-
copyDepositAddress,
|
|
8517
|
-
backToSourceSelector,
|
|
8518
|
-
resetSessionForNewSelection,
|
|
8519
|
-
advanceMockStatus,
|
|
8520
|
-
selectToken,
|
|
8521
|
-
selectChainId
|
|
8785
|
+
kind: "proceed",
|
|
8786
|
+
actions,
|
|
8787
|
+
resolveSource: {
|
|
8788
|
+
chainName: effective.chainName,
|
|
8789
|
+
tokenSymbol: effective.symbol
|
|
8790
|
+
}
|
|
8522
8791
|
};
|
|
8523
8792
|
}
|
|
8524
|
-
var MOCK_STATUSES = [
|
|
8525
|
-
"awaiting_deposit",
|
|
8526
|
-
"deposit_received",
|
|
8527
|
-
"routing",
|
|
8528
|
-
"completed",
|
|
8529
|
-
"failed"
|
|
8530
|
-
];
|
|
8531
|
-
function DevMockPanel({
|
|
8532
|
-
status,
|
|
8533
|
-
onSetStatus,
|
|
8534
|
-
hasSession
|
|
8535
|
-
}) {
|
|
8536
|
-
const [collapsed, setCollapsed] = useState(true);
|
|
8537
|
-
return /* @__PURE__ */ jsxs("div", { style: devPanelContainerStyle, children: [
|
|
8538
|
-
/* @__PURE__ */ jsx(
|
|
8539
|
-
"button",
|
|
8540
|
-
{
|
|
8541
|
-
type: "button",
|
|
8542
|
-
onClick: () => setCollapsed((c) => !c),
|
|
8543
|
-
style: devPanelToggleStyle,
|
|
8544
|
-
children: collapsed ? "DEV" : "\u2715"
|
|
8545
|
-
}
|
|
8546
|
-
),
|
|
8547
|
-
!collapsed && /* @__PURE__ */ jsxs("div", { style: devPanelBodyStyle, children: [
|
|
8548
|
-
/* @__PURE__ */ jsx("span", { style: devPanelLabelStyle, children: hasSession ? `Status: ${status}` : "No session" }),
|
|
8549
|
-
MOCK_STATUSES.map((s) => /* @__PURE__ */ jsx(
|
|
8550
|
-
"button",
|
|
8551
|
-
{
|
|
8552
|
-
type: "button",
|
|
8553
|
-
disabled: !hasSession || status === s,
|
|
8554
|
-
onClick: () => onSetStatus(s),
|
|
8555
|
-
style: devPanelButtonStyle(status === s),
|
|
8556
|
-
children: s.replace(/_/g, " ")
|
|
8557
|
-
},
|
|
8558
|
-
s
|
|
8559
|
-
))
|
|
8560
|
-
] })
|
|
8561
|
-
] });
|
|
8562
|
-
}
|
|
8563
|
-
var devPanelContainerStyle = {
|
|
8564
|
-
position: "fixed",
|
|
8565
|
-
bottom: 16,
|
|
8566
|
-
right: 16,
|
|
8567
|
-
zIndex: 99999,
|
|
8568
|
-
display: "flex",
|
|
8569
|
-
flexDirection: "column",
|
|
8570
|
-
alignItems: "flex-end",
|
|
8571
|
-
gap: 8,
|
|
8572
|
-
fontFamily: "monospace",
|
|
8573
|
-
fontSize: 12
|
|
8574
|
-
};
|
|
8575
|
-
var devPanelToggleStyle = {
|
|
8576
|
-
background: "#1a1a1a",
|
|
8577
|
-
border: "1px solid #333",
|
|
8578
|
-
borderRadius: 8,
|
|
8579
|
-
color: "#0f0",
|
|
8580
|
-
cursor: "pointer",
|
|
8581
|
-
fontSize: 11,
|
|
8582
|
-
fontFamily: "monospace",
|
|
8583
|
-
fontWeight: 700,
|
|
8584
|
-
height: 36,
|
|
8585
|
-
width: 36,
|
|
8586
|
-
display: "flex",
|
|
8587
|
-
alignItems: "center",
|
|
8588
|
-
justifyContent: "center"
|
|
8589
|
-
};
|
|
8590
|
-
var devPanelBodyStyle = {
|
|
8591
|
-
background: "#1a1a1a",
|
|
8592
|
-
border: "1px solid #333",
|
|
8593
|
-
borderRadius: 10,
|
|
8594
|
-
display: "flex",
|
|
8595
|
-
flexDirection: "column",
|
|
8596
|
-
gap: 4,
|
|
8597
|
-
padding: 10,
|
|
8598
|
-
minWidth: 160
|
|
8599
|
-
};
|
|
8600
|
-
var devPanelLabelStyle = {
|
|
8601
|
-
color: "#888",
|
|
8602
|
-
fontSize: 10,
|
|
8603
|
-
marginBottom: 4,
|
|
8604
|
-
textTransform: "uppercase",
|
|
8605
|
-
letterSpacing: "0.05em"
|
|
8606
|
-
};
|
|
8607
|
-
var devPanelButtonStyle = (active) => ({
|
|
8608
|
-
background: active ? "#0f0" : "#2a2a2a",
|
|
8609
|
-
border: "1px solid #444",
|
|
8610
|
-
borderRadius: 6,
|
|
8611
|
-
color: active ? "#000" : "#ccc",
|
|
8612
|
-
cursor: active ? "default" : "pointer",
|
|
8613
|
-
fontFamily: "monospace",
|
|
8614
|
-
fontSize: 11,
|
|
8615
|
-
fontWeight: active ? 700 : 400,
|
|
8616
|
-
padding: "6px 10px",
|
|
8617
|
-
textAlign: "left",
|
|
8618
|
-
textTransform: "capitalize"
|
|
8619
|
-
});
|
|
8620
8793
|
function ScreenLayout({ children, footer }) {
|
|
8621
8794
|
const { tokens, theme, isMobileApp } = useBlinkConfig();
|
|
8622
8795
|
const isRedesign = theme.endsWith("New");
|
|
@@ -10331,16 +10504,21 @@ function DepositQrCodeImpl({
|
|
|
10331
10504
|
depToken
|
|
10332
10505
|
}) {
|
|
10333
10506
|
const { tokens } = useBlinkConfig();
|
|
10334
|
-
const [dataUrl, setDataUrl] = useState(null);
|
|
10335
10507
|
const uri = formatDepositUri(address, chainId, depToken);
|
|
10508
|
+
const dark = tokens.text;
|
|
10509
|
+
const light = tokens.bg;
|
|
10510
|
+
const [dataUrl, setDataUrl] = useState(
|
|
10511
|
+
() => getCachedQrDataUrl(uri, { dark, light })
|
|
10512
|
+
);
|
|
10336
10513
|
useEffect(() => {
|
|
10514
|
+
const cached = getCachedQrDataUrl(uri, { dark, light });
|
|
10515
|
+
if (cached) {
|
|
10516
|
+
setDataUrl(cached);
|
|
10517
|
+
return;
|
|
10518
|
+
}
|
|
10337
10519
|
let cancelled = false;
|
|
10338
|
-
|
|
10339
|
-
|
|
10340
|
-
margin: 1,
|
|
10341
|
-
width: 203,
|
|
10342
|
-
color: { dark: tokens.text, light: tokens.bg }
|
|
10343
|
-
}).then((url) => {
|
|
10520
|
+
setDataUrl(null);
|
|
10521
|
+
getOrRenderQrDataUrl(uri, { dark, light }).then((url) => {
|
|
10344
10522
|
if (!cancelled) setDataUrl(url);
|
|
10345
10523
|
}).catch(() => {
|
|
10346
10524
|
if (!cancelled) setDataUrl(null);
|
|
@@ -10348,7 +10526,7 @@ function DepositQrCodeImpl({
|
|
|
10348
10526
|
return () => {
|
|
10349
10527
|
cancelled = true;
|
|
10350
10528
|
};
|
|
10351
|
-
}, [uri]);
|
|
10529
|
+
}, [uri, dark, light]);
|
|
10352
10530
|
return /* @__PURE__ */ jsx("div", { style: qrFrameStyle(tokens.bgCardTranslucent), children: dataUrl ? /* @__PURE__ */ jsxs("div", { style: qrContainerStyle, children: [
|
|
10353
10531
|
/* @__PURE__ */ jsx("img", { src: dataUrl, alt: "Deposit QR code", style: qrImageStyle }),
|
|
10354
10532
|
/* @__PURE__ */ jsx("img", { src: BLINK_QR_LOGO, alt: "", style: qrLogoStyle })
|
|
@@ -11436,7 +11614,7 @@ function EnterAmountScreen({
|
|
|
11436
11614
|
)
|
|
11437
11615
|
] }),
|
|
11438
11616
|
children: [
|
|
11439
|
-
/* @__PURE__ */ jsx(ScreenHeader, { right: headerRight }),
|
|
11617
|
+
/* @__PURE__ */ jsx(ScreenHeader, { title: "Deposit", right: headerRight }),
|
|
11440
11618
|
/* @__PURE__ */ jsxs("div", { style: contentStyle4(isDesktop), children: [
|
|
11441
11619
|
isDesktop ? /* @__PURE__ */ jsxs("div", { style: desktopHeroRowStyle(heroColor, getDesktopHeroFontSize(value)), children: [
|
|
11442
11620
|
/* @__PURE__ */ jsx("span", { "aria-hidden": "true", style: dollarStyle2(isZero), children: "$" }),
|
|
@@ -12777,7 +12955,8 @@ function SetupScreen({
|
|
|
12777
12955
|
onLogout,
|
|
12778
12956
|
loading,
|
|
12779
12957
|
loadingShimmersEnabled = false,
|
|
12780
|
-
error
|
|
12958
|
+
error,
|
|
12959
|
+
selectedTokenSymbol
|
|
12781
12960
|
}) {
|
|
12782
12961
|
const { tokens } = useBlinkConfig();
|
|
12783
12962
|
const [selectedPreset, setSelectedPreset] = useState(DEFAULT_MAX);
|
|
@@ -12886,7 +13065,8 @@ function SetupScreen({
|
|
|
12886
13065
|
style: illustrationStyle3
|
|
12887
13066
|
}
|
|
12888
13067
|
),
|
|
12889
|
-
/* @__PURE__ */ jsx("h2", { style: headingStyle7(tokens.text), children:
|
|
13068
|
+
/* @__PURE__ */ jsx("h2", { style: headingStyle7(tokens.text), children: `Next time deposit
|
|
13069
|
+
${selectedTokenSymbol ?? "USDC"} in one tap` }),
|
|
12890
13070
|
/* @__PURE__ */ jsx("p", { style: subtitleStyle5(tokens.textSecondary), children: "Set a cap for passkey deposits.\nYou always stay in control." }),
|
|
12891
13071
|
error && /* @__PURE__ */ jsx("div", { style: errorBannerStyle5(tokens), children: error }),
|
|
12892
13072
|
/* @__PURE__ */ jsx("div", { style: chipsRowStyle, children: PRESETS.map(({ label, value }) => {
|
|
@@ -12914,8 +13094,8 @@ var contentStyle9 = {
|
|
|
12914
13094
|
alignItems: "center",
|
|
12915
13095
|
justifyContent: "center",
|
|
12916
13096
|
textAlign: "center",
|
|
12917
|
-
gap:
|
|
12918
|
-
padding: "
|
|
13097
|
+
gap: 12,
|
|
13098
|
+
padding: "8px 0"
|
|
12919
13099
|
};
|
|
12920
13100
|
var shimmerContentStyle = {
|
|
12921
13101
|
display: "flex",
|
|
@@ -13286,7 +13466,7 @@ function SetupDepositScreen({
|
|
|
13286
13466
|
NotificationBanner,
|
|
13287
13467
|
{
|
|
13288
13468
|
variant: "negative",
|
|
13289
|
-
title: "Deposit amount exceeds balance",
|
|
13469
|
+
title: "Deposit amount exceeds stablecoin balance",
|
|
13290
13470
|
description: "Pick another asset or add more funds to your wallet"
|
|
13291
13471
|
}
|
|
13292
13472
|
) : /* @__PURE__ */ jsx(NotificationBanner, { title: "Something went wrong", description: error }) })
|
|
@@ -13904,7 +14084,7 @@ function DepositScreen({
|
|
|
13904
14084
|
NotificationBanner,
|
|
13905
14085
|
{
|
|
13906
14086
|
variant: "negative",
|
|
13907
|
-
title: "Deposit amount exceeds balance",
|
|
14087
|
+
title: "Deposit amount exceeds stablecoin balance",
|
|
13908
14088
|
description: "Pick another asset or add more funds to your wallet"
|
|
13909
14089
|
}
|
|
13910
14090
|
) : needsAuthorization ? /* @__PURE__ */ jsx(
|
|
@@ -14826,12 +15006,12 @@ function DepositAddressScreen({
|
|
|
14826
15006
|
),
|
|
14827
15007
|
/* @__PURE__ */ jsxs("div", { style: contentStyle16, children: [
|
|
14828
15008
|
/* @__PURE__ */ jsx("h2", { style: depositTitleStyle(tokens.text), children: "Deposit Address" }),
|
|
14829
|
-
qrReady && session ? /* @__PURE__ */ jsx(
|
|
15009
|
+
qrReady && session && selectedOption ? /* @__PURE__ */ jsx(
|
|
14830
15010
|
DepositQrCode,
|
|
14831
15011
|
{
|
|
14832
15012
|
address: session.depositAddress,
|
|
14833
|
-
chainId:
|
|
14834
|
-
depToken:
|
|
15013
|
+
chainId: selectedOption.chainId,
|
|
15014
|
+
depToken: selectedOption.tokenAddress
|
|
14835
15015
|
}
|
|
14836
15016
|
) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
14837
15017
|
/* @__PURE__ */ jsx("style", { children: `
|
|
@@ -15850,12 +16030,7 @@ var errorBannerStyle8 = (themeTokens) => ({
|
|
|
15850
16030
|
textAlign: "left"
|
|
15851
16031
|
});
|
|
15852
16032
|
function ManualTransferFlow({
|
|
15853
|
-
|
|
15854
|
-
merchantAuthorization,
|
|
15855
|
-
idempotencyKey,
|
|
15856
|
-
mock = false,
|
|
15857
|
-
onComplete,
|
|
15858
|
-
onError,
|
|
16033
|
+
hasMerchantAuthorization,
|
|
15859
16034
|
onCreatePasskey,
|
|
15860
16035
|
createPasskeyLoading = false,
|
|
15861
16036
|
createPasskeyError = null,
|
|
@@ -15884,17 +16059,9 @@ function ManualTransferFlow({
|
|
|
15884
16059
|
depositAddress,
|
|
15885
16060
|
copyDepositAddress,
|
|
15886
16061
|
backToSourceSelector,
|
|
15887
|
-
advanceMockStatus,
|
|
15888
16062
|
selectToken,
|
|
15889
16063
|
selectChainId
|
|
15890
|
-
} =
|
|
15891
|
-
destination,
|
|
15892
|
-
merchantAuthorization,
|
|
15893
|
-
idempotencyKey,
|
|
15894
|
-
mock,
|
|
15895
|
-
onComplete,
|
|
15896
|
-
onError
|
|
15897
|
-
});
|
|
16064
|
+
} = useManualTransferSessionContext();
|
|
15898
16065
|
const [passkeyCreated, setPasskeyCreated] = useState(false);
|
|
15899
16066
|
const prevPasskeyLoadingRef = useRef(false);
|
|
15900
16067
|
useEffect(() => {
|
|
@@ -15903,9 +16070,8 @@ function ManualTransferFlow({
|
|
|
15903
16070
|
}
|
|
15904
16071
|
prevPasskeyLoadingRef.current = createPasskeyLoading;
|
|
15905
16072
|
}, [createPasskeyLoading, createPasskeyError]);
|
|
15906
|
-
const DEV_MOCK_STATUS = mock;
|
|
15907
16073
|
let screenContent = null;
|
|
15908
|
-
if (!
|
|
16074
|
+
if (!hasMerchantAuthorization) {
|
|
15909
16075
|
screenContent = /* @__PURE__ */ jsxs(ScreenLayout, { footer: /* @__PURE__ */ jsx(PrimaryButton, { onClick: onBack, children: "Back" }), children: [
|
|
15910
16076
|
/* @__PURE__ */ jsx(ScreenHeader, { onBack }),
|
|
15911
16077
|
/* @__PURE__ */ jsxs("div", { style: contentStyle20, children: [
|
|
@@ -15975,17 +16141,7 @@ function ManualTransferFlow({
|
|
|
15975
16141
|
if (!screenContent) {
|
|
15976
16142
|
return null;
|
|
15977
16143
|
}
|
|
15978
|
-
return
|
|
15979
|
-
screenContent,
|
|
15980
|
-
DEV_MOCK_STATUS && merchantAuthorization && /* @__PURE__ */ jsx(
|
|
15981
|
-
DevMockPanel,
|
|
15982
|
-
{
|
|
15983
|
-
status: session?.status ?? null,
|
|
15984
|
-
onSetStatus: advanceMockStatus,
|
|
15985
|
-
hasSession: !!session
|
|
15986
|
-
}
|
|
15987
|
-
)
|
|
15988
|
-
] });
|
|
16144
|
+
return screenContent;
|
|
15989
16145
|
}
|
|
15990
16146
|
var contentStyle20 = {
|
|
15991
16147
|
alignItems: "center",
|
|
@@ -16285,6 +16441,7 @@ function buildSetupDepositScreenProps({
|
|
|
16285
16441
|
function buildSetupScreenProps({
|
|
16286
16442
|
flow,
|
|
16287
16443
|
remote,
|
|
16444
|
+
derived,
|
|
16288
16445
|
forms,
|
|
16289
16446
|
handlers
|
|
16290
16447
|
}) {
|
|
@@ -16293,11 +16450,12 @@ function buildSetupScreenProps({
|
|
|
16293
16450
|
const waitingForDesktopWalletConnection = flow.isDesktop && remote.authExecutorExecuting && remote.pendingOneTapSetup == null && (remote.authExecutorCurrentAction == null || remote.authExecutorCurrentAction.type === "OPEN_PROVIDER");
|
|
16294
16451
|
return {
|
|
16295
16452
|
onSetupOneTap: handlers.onSetupOneTap,
|
|
16296
|
-
onBack: handlers.onBackFromSubflow,
|
|
16297
|
-
onLogout: handlers.onLogout,
|
|
16453
|
+
onBack: flow.isDesktop ? handlers.onBackFromSubflow : void 0,
|
|
16454
|
+
onLogout: flow.isDesktop ? handlers.onLogout : void 0,
|
|
16298
16455
|
loading: savingOneTapLimit,
|
|
16299
16456
|
loadingShimmersEnabled: waitingForDesktopWalletConnection,
|
|
16300
|
-
error: state.error
|
|
16457
|
+
error: state.error,
|
|
16458
|
+
selectedTokenSymbol: derived.selectedSource?.token.symbol
|
|
16301
16459
|
};
|
|
16302
16460
|
}
|
|
16303
16461
|
function buildConfirmSignScreenProps({
|
|
@@ -16574,12 +16732,7 @@ function StepRendererContent({
|
|
|
16574
16732
|
return /* @__PURE__ */ jsx(
|
|
16575
16733
|
ManualTransferFlow,
|
|
16576
16734
|
{
|
|
16577
|
-
|
|
16578
|
-
merchantAuthorization: flow.merchantAuthorization,
|
|
16579
|
-
idempotencyKey: flow.idempotencyKey,
|
|
16580
|
-
mock: flow.mock,
|
|
16581
|
-
onComplete: flow.onComplete,
|
|
16582
|
-
onError: flow.onError,
|
|
16735
|
+
hasMerchantAuthorization: flow.merchantAuthorization != null,
|
|
16583
16736
|
onCreatePasskey: handlers.onSignupWithPasskey,
|
|
16584
16737
|
createPasskeyLoading: flow.passkeyLoading,
|
|
16585
16738
|
createPasskeyError: flow.state.error,
|
|
@@ -18797,8 +18950,11 @@ function usePasskeyCheckEffect(deps) {
|
|
|
18797
18950
|
setupAccountIdRef,
|
|
18798
18951
|
reauthSessionIdRef,
|
|
18799
18952
|
reauthTokenRef,
|
|
18800
|
-
pollingTransferIdRef
|
|
18953
|
+
pollingTransferIdRef,
|
|
18954
|
+
reloadAccounts
|
|
18801
18955
|
} = deps;
|
|
18956
|
+
const reloadAccountsRef = useRef(reloadAccounts);
|
|
18957
|
+
reloadAccountsRef.current = reloadAccounts;
|
|
18802
18958
|
const { getAccessToken: privyGetAccessToken, user } = usePrivy();
|
|
18803
18959
|
const effectiveGetAccessToken = deps.getAccessToken ?? privyGetAccessToken;
|
|
18804
18960
|
const onCompleteRef = useRef(deps.onComplete);
|
|
@@ -18928,6 +19084,11 @@ function usePasskeyCheckEffect(deps) {
|
|
|
18928
19084
|
mobileSetupFlowRef.current = false;
|
|
18929
19085
|
setupAccountIdRef.current = null;
|
|
18930
19086
|
clearMobileFlowState();
|
|
19087
|
+
try {
|
|
19088
|
+
await reloadAccountsRef.current();
|
|
19089
|
+
} catch {
|
|
19090
|
+
}
|
|
19091
|
+
dispatch({ type: "MOBILE_SETUP_COMPLETE" });
|
|
18931
19092
|
return;
|
|
18932
19093
|
}
|
|
18933
19094
|
if (persisted.accountId && !persisted.transferId) {
|
|
@@ -18936,7 +19097,14 @@ function usePasskeyCheckEffect(deps) {
|
|
|
18936
19097
|
const session = await fetchAuthorizationSession(apiBaseUrl, persisted.sessionId);
|
|
18937
19098
|
if (cancelled) return;
|
|
18938
19099
|
if (session.status === "AUTHORIZED") {
|
|
19100
|
+
mobileSetupFlowRef.current = false;
|
|
19101
|
+
setupAccountIdRef.current = null;
|
|
18939
19102
|
clearMobileFlowState();
|
|
19103
|
+
try {
|
|
19104
|
+
await reloadAccountsRef.current();
|
|
19105
|
+
} catch {
|
|
19106
|
+
}
|
|
19107
|
+
dispatch({ type: "MOBILE_SETUP_COMPLETE" });
|
|
18940
19108
|
return;
|
|
18941
19109
|
}
|
|
18942
19110
|
} catch {
|
|
@@ -19401,25 +19569,24 @@ function useMobilePollingEffect(deps) {
|
|
|
19401
19569
|
dispatch({ type: "MOBILE_SETUP_COMPLETE" });
|
|
19402
19570
|
};
|
|
19403
19571
|
const pollWalletActive = async () => {
|
|
19572
|
+
if (setupSessionId) {
|
|
19573
|
+
try {
|
|
19574
|
+
const session = await fetchAuthorizationSession(apiBaseUrl, setupSessionId);
|
|
19575
|
+
if (cancelled) return;
|
|
19576
|
+
if (session.status === "AUTHORIZED") {
|
|
19577
|
+
await completeSetup();
|
|
19578
|
+
return;
|
|
19579
|
+
}
|
|
19580
|
+
} catch {
|
|
19581
|
+
}
|
|
19582
|
+
}
|
|
19404
19583
|
try {
|
|
19405
19584
|
const token = await getAccessTokenRef.current();
|
|
19406
19585
|
if (!token || cancelled) return;
|
|
19407
19586
|
const acct = await fetchAccount(apiBaseUrl, token, accountId, credentialId);
|
|
19408
19587
|
if (cancelled) return;
|
|
19409
|
-
|
|
19410
|
-
if (hasActive) {
|
|
19588
|
+
if (acct.wallets.some((w) => w.status === "ACTIVE")) {
|
|
19411
19589
|
await completeSetup();
|
|
19412
|
-
return;
|
|
19413
|
-
}
|
|
19414
|
-
if (setupSessionId) {
|
|
19415
|
-
try {
|
|
19416
|
-
const session = await fetchAuthorizationSession(apiBaseUrl, setupSessionId);
|
|
19417
|
-
if (cancelled) return;
|
|
19418
|
-
if (session.status === "AUTHORIZED") {
|
|
19419
|
-
await completeSetup();
|
|
19420
|
-
}
|
|
19421
|
-
} catch {
|
|
19422
|
-
}
|
|
19423
19590
|
}
|
|
19424
19591
|
} catch {
|
|
19425
19592
|
}
|
|
@@ -19854,7 +20021,6 @@ function BlinkPayment(props) {
|
|
|
19854
20021
|
function BlinkPaymentInner({
|
|
19855
20022
|
destination,
|
|
19856
20023
|
initialScreen,
|
|
19857
|
-
mock,
|
|
19858
20024
|
onComplete,
|
|
19859
20025
|
onError,
|
|
19860
20026
|
useWalletConnector: useWalletConnectorProp,
|
|
@@ -19943,6 +20109,7 @@ function BlinkPaymentInner({
|
|
|
19943
20109
|
minTransferAmountUsd: effectiveMinDepositAmountUsd
|
|
19944
20110
|
});
|
|
19945
20111
|
const feeEstimateEnabled = effectiveAuthenticated && (state.phase.step === "deposit" || state.phase.step === "wallet-setup" || state.phase.step === "one-tap-setup");
|
|
20112
|
+
const manualTransferActive = screenForPhase(state.phase) === "manual-transfer";
|
|
19946
20113
|
const setupSelectedSourceOption = useMemo(() => {
|
|
19947
20114
|
const options = sourceSelection.pendingSelectSourceAction?.metadata?.options ?? [];
|
|
19948
20115
|
return resolveSelectSourceOption(
|
|
@@ -20089,13 +20256,14 @@ function BlinkPaymentInner({
|
|
|
20089
20256
|
idempotencyKey
|
|
20090
20257
|
});
|
|
20091
20258
|
const accountSwitchSessionId = state.setupAuthorizationSessionId;
|
|
20259
|
+
const accountSwitchListenerArmed = accountSwitchSessionId != null && state.desktopWait == null;
|
|
20092
20260
|
const handleProviderWalletAccountSwitch = provider.handleWalletAccountSwitch;
|
|
20093
20261
|
const onWalletAccountChanged = useCallback(async (change) => {
|
|
20094
20262
|
if (!accountSwitchSessionId) return;
|
|
20095
20263
|
await handleProviderWalletAccountSwitch(change, accountSwitchSessionId);
|
|
20096
20264
|
}, [handleProviderWalletAccountSwitch, accountSwitchSessionId]);
|
|
20097
20265
|
useWalletAccountSwitchEffect({
|
|
20098
|
-
enabled:
|
|
20266
|
+
enabled: accountSwitchListenerArmed,
|
|
20099
20267
|
isDesktop,
|
|
20100
20268
|
onAccountChanged: onWalletAccountChanged
|
|
20101
20269
|
});
|
|
@@ -20191,6 +20359,7 @@ function BlinkPaymentInner({
|
|
|
20191
20359
|
reauthTokenRef: mobileFlowRefs.reauthTokenRef,
|
|
20192
20360
|
pollingTransferIdRef: transfer.pollingTransferIdRef,
|
|
20193
20361
|
handleAuthorizedMobileReturn: mobileFlow.handleAuthorizedMobileReturn,
|
|
20362
|
+
reloadAccounts: transfer.reloadAccounts,
|
|
20194
20363
|
onComplete,
|
|
20195
20364
|
getAccessToken: effectiveGetAccessToken,
|
|
20196
20365
|
pendingTransferFlowKey
|
|
@@ -20357,15 +20526,18 @@ function BlinkPaymentInner({
|
|
|
20357
20526
|
dispatch,
|
|
20358
20527
|
orchestrator
|
|
20359
20528
|
]);
|
|
20360
|
-
const handleBackFromSetupDeposit = useCallback(() => {
|
|
20529
|
+
const handleBackFromSetupDeposit = useCallback(async () => {
|
|
20361
20530
|
orchestrator.cancelPendingFlow();
|
|
20362
20531
|
authExecutor.cancelPendingExecution();
|
|
20363
20532
|
clearScreenErrors();
|
|
20533
|
+
if (isDesktop) {
|
|
20534
|
+
await revokeAndDisconnectActiveWagmiConnector(wagmiConfig);
|
|
20535
|
+
}
|
|
20364
20536
|
dispatch({ type: "RESTORE_SELECTION" });
|
|
20365
20537
|
dispatch({ type: "CLEAR_SETUP_DEPOSIT_TOKEN" });
|
|
20366
20538
|
dispatch({ type: "SET_SETUP_FLOW_SCREEN", screen: null });
|
|
20367
20539
|
dispatch({ type: "SET_USER_INTENT", intent: { step: "wallet-picker", reason: "switch" } });
|
|
20368
|
-
}, [authExecutor, clearScreenErrors, orchestrator, dispatch]);
|
|
20540
|
+
}, [authExecutor, clearScreenErrors, orchestrator, dispatch, isDesktop, wagmiConfig]);
|
|
20369
20541
|
const handleAuthorizationRetry = useCallback(() => {
|
|
20370
20542
|
void (async () => {
|
|
20371
20543
|
try {
|
|
@@ -20405,6 +20577,11 @@ function BlinkPaymentInner({
|
|
|
20405
20577
|
clearScreenErrors();
|
|
20406
20578
|
dispatch({ type: "SET_SETUP_DEPOSIT_AMOUNT", amount });
|
|
20407
20579
|
dispatch({ type: "SET_USER_INTENT", intent: { step: "wallet-picker", reason: "switch" } });
|
|
20580
|
+
void (async () => {
|
|
20581
|
+
await revokeAndDisconnectActiveWagmiConnector(wagmiConfig);
|
|
20582
|
+
await authExecutor.resetWalletConnect().catch(() => {
|
|
20583
|
+
});
|
|
20584
|
+
})();
|
|
20408
20585
|
},
|
|
20409
20586
|
onBackFromSetupDeposit: handleBackFromSetupDeposit,
|
|
20410
20587
|
onBackFromSubflow: () => {
|
|
@@ -20453,65 +20630,76 @@ function BlinkPaymentInner({
|
|
|
20453
20630
|
handleSetDepositToken,
|
|
20454
20631
|
handleConfirmSetupDeposit,
|
|
20455
20632
|
handleBackFromSetupDeposit,
|
|
20456
|
-
handleAuthorizationRetry
|
|
20633
|
+
handleAuthorizationRetry,
|
|
20634
|
+
wagmiConfig
|
|
20457
20635
|
]);
|
|
20458
20636
|
return /* @__PURE__ */ jsx(EffectiveDepositAmountProvider, { value: effectiveDepositAmount, children: /* @__PURE__ */ jsx(
|
|
20459
|
-
|
|
20637
|
+
ManualTransferSessionProvider,
|
|
20460
20638
|
{
|
|
20461
|
-
|
|
20462
|
-
|
|
20463
|
-
|
|
20464
|
-
|
|
20465
|
-
|
|
20466
|
-
|
|
20467
|
-
|
|
20468
|
-
|
|
20469
|
-
|
|
20470
|
-
|
|
20471
|
-
|
|
20472
|
-
|
|
20473
|
-
|
|
20474
|
-
|
|
20475
|
-
|
|
20476
|
-
|
|
20477
|
-
|
|
20478
|
-
|
|
20479
|
-
|
|
20480
|
-
|
|
20481
|
-
|
|
20482
|
-
|
|
20483
|
-
|
|
20484
|
-
|
|
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
|
-
|
|
20639
|
+
destination,
|
|
20640
|
+
merchantAuthorization,
|
|
20641
|
+
idempotencyKey,
|
|
20642
|
+
onComplete,
|
|
20643
|
+
onError,
|
|
20644
|
+
pollEnabled: manualTransferActive,
|
|
20645
|
+
children: /* @__PURE__ */ jsx(
|
|
20646
|
+
StepRenderer,
|
|
20647
|
+
{
|
|
20648
|
+
flow: {
|
|
20649
|
+
state,
|
|
20650
|
+
authenticated: effectiveAuthenticated,
|
|
20651
|
+
passkeyLoading: auth.passkeyLoginStatus !== "initial" && auth.passkeyLoginStatus !== "done" && auth.passkeyLoginStatus !== "error" || auth.passkeySignupStatus !== "initial" && auth.passkeySignupStatus !== "done" && auth.passkeySignupStatus !== "error" || auth.passkeySignupPopupActive,
|
|
20652
|
+
isDesktop,
|
|
20653
|
+
isMobileApp: isMobileApp ?? false,
|
|
20654
|
+
merchantName,
|
|
20655
|
+
onBack,
|
|
20656
|
+
onDismiss,
|
|
20657
|
+
depositAmount,
|
|
20658
|
+
effectiveDepositAmount,
|
|
20659
|
+
minTransferAmountUsd,
|
|
20660
|
+
destination,
|
|
20661
|
+
merchantAuthorization,
|
|
20662
|
+
idempotencyKey,
|
|
20663
|
+
onComplete,
|
|
20664
|
+
onError
|
|
20665
|
+
},
|
|
20666
|
+
remote: {
|
|
20667
|
+
pollingTransfer: polling.transfer,
|
|
20668
|
+
pollingError: polling.error,
|
|
20669
|
+
authExecutorError: authExecutor.error,
|
|
20670
|
+
authExecutorExecuting: authExecutor.executing,
|
|
20671
|
+
authExecutorCurrentAction: authExecutor.currentAction,
|
|
20672
|
+
pendingOneTapSetup: orchestrator.pendingOneTapAction,
|
|
20673
|
+
setupAuthorizationComplete,
|
|
20674
|
+
transferSigningSigning: transferSigning.signing,
|
|
20675
|
+
transferSigningError: transferSigning.error,
|
|
20676
|
+
transferSigningPasskeyDismissed: transferSigning.passkeyDismissed,
|
|
20677
|
+
pendingSelectSource: orchestrator.pendingSelectSourceAction
|
|
20678
|
+
},
|
|
20679
|
+
derived: {
|
|
20680
|
+
pendingConnections: derived.pendingConnections,
|
|
20681
|
+
depositEligibleAccounts: derived.depositEligibleAccounts,
|
|
20682
|
+
sourceName: derived.sourceName,
|
|
20683
|
+
maxSourceBalance: derived.maxSourceBalance,
|
|
20684
|
+
tokenCount: derived.tokenCount,
|
|
20685
|
+
selectedAccount: derived.selectedAccount,
|
|
20686
|
+
selectedSource: derived.selectedSource,
|
|
20687
|
+
selectSourceChoices: sourceSelection.selectSourceChoices,
|
|
20688
|
+
selectSourceRecommended: sourceSelection.selectSourceRecommended,
|
|
20689
|
+
selectSourceAvailableBalance: sourceSelection.selectSourceAvailableBalance
|
|
20690
|
+
},
|
|
20691
|
+
forms: {
|
|
20692
|
+
selectSourceChainName: sourceSelection.selectSourceChainName,
|
|
20693
|
+
selectSourceTokenSymbol: sourceSelection.selectSourceTokenSymbol,
|
|
20694
|
+
savingOneTapLimit: oneTapSetup.savingOneTapLimit,
|
|
20695
|
+
depositQuoteId: depositFee.quoteId,
|
|
20696
|
+
depositQuoteFee: depositFee.quoteFee,
|
|
20697
|
+
depositQuoteLoading: depositFee.quoteLoading,
|
|
20698
|
+
depositQuoteError: depositFee.quoteError
|
|
20699
|
+
},
|
|
20700
|
+
handlers
|
|
20701
|
+
}
|
|
20702
|
+
)
|
|
20515
20703
|
}
|
|
20516
20704
|
) });
|
|
20517
20705
|
}
|