@swype-org/react-sdk 0.2.242 → 0.2.261
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1191 -1017
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -3
- package/dist/index.d.ts +12 -3
- package/dist/index.js +1192 -1018
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.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,692 @@ 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;
|
|
7410
|
-
}
|
|
7411
|
-
function getTransferStatus(polledTransfer, localTransfer) {
|
|
7412
|
-
const transfer = resolvePreferredTransfer(polledTransfer, localTransfer);
|
|
7413
|
-
return transfer?.status ?? "UNKNOWN";
|
|
7556
|
+
function feeCopy(_session) {
|
|
7557
|
+
return "No fees";
|
|
7414
7558
|
}
|
|
7415
|
-
function
|
|
7416
|
-
|
|
7417
|
-
|
|
7559
|
+
function toTransfer(session) {
|
|
7560
|
+
return {
|
|
7561
|
+
id: session.sessionId,
|
|
7562
|
+
status: session.status,
|
|
7563
|
+
amount: {
|
|
7564
|
+
amount: Number(session.deliveredAmountUsd ?? session.minAmountUsd),
|
|
7565
|
+
currency: "USD"
|
|
7566
|
+
},
|
|
7567
|
+
sources: [],
|
|
7568
|
+
destinations: [{
|
|
7569
|
+
id: session.sessionId,
|
|
7570
|
+
chainId: session.destination.chainId,
|
|
7571
|
+
address: session.destination.address,
|
|
7572
|
+
token: { address: session.destination.token.address, symbol: "" },
|
|
7573
|
+
amount: { amount: Number(session.deliveredAmountUsd ?? session.minAmountUsd), currency: "USD" }
|
|
7574
|
+
}],
|
|
7575
|
+
createDate: session.createDate,
|
|
7576
|
+
updateDate: session.updateDate
|
|
7577
|
+
};
|
|
7418
7578
|
}
|
|
7419
|
-
var
|
|
7420
|
-
|
|
7421
|
-
|
|
7422
|
-
|
|
7423
|
-
|
|
7424
|
-
|
|
7425
|
-
|
|
7426
|
-
}
|
|
7427
|
-
|
|
7428
|
-
return
|
|
7579
|
+
var SOLANA_CHAIN_ID = 792703809;
|
|
7580
|
+
var SOLANA_NATIVE_SOL_ADDRESS = "11111111111111111111111111111111";
|
|
7581
|
+
function formatDepositUri(address, chainId, depToken) {
|
|
7582
|
+
if (chainId === SOLANA_CHAIN_ID) {
|
|
7583
|
+
if (!depToken || depToken === SOLANA_NATIVE_SOL_ADDRESS) {
|
|
7584
|
+
return `solana:${address}`;
|
|
7585
|
+
}
|
|
7586
|
+
return `solana:${address}?spl-token=${depToken}`;
|
|
7587
|
+
}
|
|
7588
|
+
return address;
|
|
7429
7589
|
}
|
|
7430
|
-
|
|
7431
|
-
|
|
7432
|
-
|
|
7590
|
+
var dataUrlCache = /* @__PURE__ */ new Map();
|
|
7591
|
+
var inFlight = /* @__PURE__ */ new Map();
|
|
7592
|
+
function keyFor(uri, colors) {
|
|
7593
|
+
return `${uri}|${colors.dark}|${colors.light}`;
|
|
7594
|
+
}
|
|
7595
|
+
function getCachedQrDataUrl(uri, colors) {
|
|
7596
|
+
return dataUrlCache.get(keyFor(uri, colors)) ?? null;
|
|
7597
|
+
}
|
|
7598
|
+
function getOrRenderQrDataUrl(uri, colors) {
|
|
7599
|
+
const key = keyFor(uri, colors);
|
|
7600
|
+
const cached = dataUrlCache.get(key);
|
|
7601
|
+
if (cached) return Promise.resolve(cached);
|
|
7602
|
+
const pending = inFlight.get(key);
|
|
7603
|
+
if (pending) return pending;
|
|
7604
|
+
const promise = QRCode.toDataURL(uri, {
|
|
7605
|
+
errorCorrectionLevel: "H",
|
|
7606
|
+
margin: 1,
|
|
7607
|
+
width: 203,
|
|
7608
|
+
color: { dark: colors.dark, light: colors.light }
|
|
7609
|
+
}).then((url) => {
|
|
7610
|
+
dataUrlCache.set(key, url);
|
|
7611
|
+
inFlight.delete(key);
|
|
7612
|
+
return url;
|
|
7613
|
+
}).catch((err) => {
|
|
7614
|
+
inFlight.delete(key);
|
|
7615
|
+
throw err;
|
|
7616
|
+
});
|
|
7617
|
+
inFlight.set(key, promise);
|
|
7618
|
+
return promise;
|
|
7433
7619
|
}
|
|
7434
7620
|
|
|
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;
|
|
7621
|
+
// src/hooks/useManualTransferSession.ts
|
|
7622
|
+
function perTokenKey(chainId, tokenAddress) {
|
|
7623
|
+
return `${chainId}:${tokenAddress.toLowerCase()}`;
|
|
7462
7624
|
}
|
|
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
|
-
|
|
7625
|
+
function useManualTransferSession({
|
|
7626
|
+
destination,
|
|
7627
|
+
merchantAuthorization,
|
|
7628
|
+
idempotencyKey,
|
|
7629
|
+
onComplete,
|
|
7630
|
+
onError,
|
|
7631
|
+
pollEnabled = true
|
|
7632
|
+
}) {
|
|
7633
|
+
const { apiBaseUrl, tokens } = useBlinkConfig();
|
|
7634
|
+
const [sourceOptions, setSourceOptions] = useState(null);
|
|
7635
|
+
const [loadingSources, setLoadingSources] = useState(true);
|
|
7636
|
+
const [selectedToken, setSelectedToken] = useState("");
|
|
7637
|
+
const [selectedChainId, setSelectedChainId] = useState("");
|
|
7638
|
+
const [sessionsByFamily, setSessionsByFamily] = useState({});
|
|
7639
|
+
const [perTokenSessions, setPerTokenSessions] = useState({});
|
|
7640
|
+
const [loading, setLoading] = useState(false);
|
|
7641
|
+
const [error, setError] = useState(null);
|
|
7642
|
+
const [copiedAddress, setCopiedAddress] = useState(null);
|
|
7643
|
+
const completedRef = useRef(/* @__PURE__ */ new Set());
|
|
7644
|
+
const premintedFamiliesRef = useRef(/* @__PURE__ */ new Set());
|
|
7645
|
+
const inFlightPerTokenRef = useRef(/* @__PURE__ */ new Set());
|
|
7646
|
+
useEffect(() => {
|
|
7647
|
+
if (!merchantAuthorization) return;
|
|
7648
|
+
let cancelled = false;
|
|
7649
|
+
setLoadingSources(true);
|
|
7650
|
+
fetchManualTransferSources(apiBaseUrl, { merchantAuthorization, destination }).then((sources) => {
|
|
7651
|
+
if (cancelled) return;
|
|
7652
|
+
setSourceOptions(sources);
|
|
7653
|
+
setLoadingSources(false);
|
|
7654
|
+
const svmCanonical = sources.find((s) => s.canonical && s.chainFamily === "svm");
|
|
7655
|
+
const evmCanonical = sources.find((s) => s.canonical && s.chainFamily === "evm");
|
|
7656
|
+
const defaultOption = svmCanonical ?? evmCanonical ?? sources[0];
|
|
7657
|
+
if (defaultOption) {
|
|
7658
|
+
setSelectedToken(defaultOption.tokenSymbol);
|
|
7659
|
+
setSelectedChainId(String(defaultOption.chainId));
|
|
7660
|
+
}
|
|
7661
|
+
}).catch((err) => {
|
|
7662
|
+
if (!cancelled) {
|
|
7663
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
7664
|
+
setLoadingSources(false);
|
|
7665
|
+
}
|
|
7666
|
+
});
|
|
7667
|
+
return () => {
|
|
7668
|
+
cancelled = true;
|
|
7498
7669
|
};
|
|
7499
|
-
}
|
|
7500
|
-
|
|
7501
|
-
return
|
|
7502
|
-
|
|
7503
|
-
|
|
7504
|
-
|
|
7670
|
+
}, [apiBaseUrl, destination, merchantAuthorization]);
|
|
7671
|
+
useEffect(() => {
|
|
7672
|
+
if (!sourceOptions || !merchantAuthorization) return;
|
|
7673
|
+
const canonicals = sourceOptions.filter((s) => s.canonical);
|
|
7674
|
+
if (canonicals.length === 0) return;
|
|
7675
|
+
let cancelled = false;
|
|
7676
|
+
for (const opt of canonicals) {
|
|
7677
|
+
if (premintedFamiliesRef.current.has(opt.chainFamily)) continue;
|
|
7678
|
+
premintedFamiliesRef.current.add(opt.chainFamily);
|
|
7679
|
+
const family = opt.chainFamily;
|
|
7680
|
+
const run = async () => {
|
|
7681
|
+
try {
|
|
7682
|
+
const created = await createManualTransfer(apiBaseUrl, {
|
|
7683
|
+
merchantAuthorization,
|
|
7684
|
+
destination,
|
|
7685
|
+
idempotencyKey,
|
|
7686
|
+
source: { chainId: opt.chainId, tokenAddress: opt.tokenAddress }
|
|
7687
|
+
});
|
|
7688
|
+
if (cancelled) return;
|
|
7689
|
+
setSessionsByFamily((prev) => ({ ...prev, [family]: created }));
|
|
7690
|
+
const uri = formatDepositUri(created.depositAddress, opt.chainId, opt.tokenAddress);
|
|
7691
|
+
void getOrRenderQrDataUrl(uri, { dark: tokens.text, light: tokens.bg });
|
|
7692
|
+
} catch (err) {
|
|
7693
|
+
if (cancelled) return;
|
|
7694
|
+
premintedFamiliesRef.current.delete(family);
|
|
7695
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
7696
|
+
}
|
|
7697
|
+
};
|
|
7698
|
+
void run();
|
|
7699
|
+
}
|
|
7700
|
+
return () => {
|
|
7701
|
+
cancelled = true;
|
|
7505
7702
|
};
|
|
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
|
-
|
|
7703
|
+
}, [
|
|
7704
|
+
apiBaseUrl,
|
|
7705
|
+
destination,
|
|
7706
|
+
idempotencyKey,
|
|
7707
|
+
merchantAuthorization,
|
|
7708
|
+
sourceOptions,
|
|
7709
|
+
tokens.text,
|
|
7710
|
+
tokens.bg
|
|
7711
|
+
]);
|
|
7712
|
+
const tokenChoices = useMemo(
|
|
7713
|
+
() => Array.from(new Set((sourceOptions ?? []).map((opt) => opt.tokenSymbol))),
|
|
7714
|
+
[sourceOptions]
|
|
7715
|
+
);
|
|
7716
|
+
const chainChoices = useMemo(() => {
|
|
7717
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7718
|
+
return (sourceOptions ?? []).filter((opt) => {
|
|
7719
|
+
if (seen.has(opt.chainId)) return false;
|
|
7720
|
+
seen.add(opt.chainId);
|
|
7721
|
+
return true;
|
|
7722
|
+
});
|
|
7723
|
+
}, [sourceOptions]);
|
|
7724
|
+
const tokenLogoUriBySymbol = useMemo(() => {
|
|
7725
|
+
const out = {};
|
|
7726
|
+
for (const opt of sourceOptions ?? []) {
|
|
7727
|
+
if (out[opt.tokenSymbol] == null) {
|
|
7728
|
+
out[opt.tokenSymbol] = opt.tokenLogoUri;
|
|
7729
|
+
}
|
|
7730
|
+
}
|
|
7731
|
+
return out;
|
|
7732
|
+
}, [sourceOptions]);
|
|
7733
|
+
const selectedOption = useMemo(
|
|
7734
|
+
() => (sourceOptions ?? []).find(
|
|
7735
|
+
(opt) => opt.tokenSymbol === selectedToken && String(opt.chainId) === selectedChainId
|
|
7736
|
+
) ?? null,
|
|
7737
|
+
[sourceOptions, selectedToken, selectedChainId]
|
|
7738
|
+
);
|
|
7739
|
+
const tokensForSelectedChain = useMemo(() => {
|
|
7740
|
+
if (!selectedChainId) return null;
|
|
7741
|
+
return new Set(
|
|
7742
|
+
(sourceOptions ?? []).filter((opt) => String(opt.chainId) === selectedChainId).map((opt) => opt.tokenSymbol)
|
|
7743
|
+
);
|
|
7744
|
+
}, [sourceOptions, selectedChainId]);
|
|
7745
|
+
const chainsForSelectedToken = useMemo(() => {
|
|
7746
|
+
if (!selectedToken) return null;
|
|
7747
|
+
return new Set(
|
|
7748
|
+
(sourceOptions ?? []).filter((opt) => opt.tokenSymbol === selectedToken).map((opt) => opt.chainId)
|
|
7749
|
+
);
|
|
7750
|
+
}, [sourceOptions, selectedToken]);
|
|
7751
|
+
const session = useMemo(() => {
|
|
7752
|
+
if (!selectedOption) return null;
|
|
7753
|
+
const familySession = sessionsByFamily[selectedOption.chainFamily];
|
|
7754
|
+
if (familySession) return familySession;
|
|
7755
|
+
return perTokenSessions[perTokenKey(selectedOption.chainId, selectedOption.tokenAddress)] ?? null;
|
|
7756
|
+
}, [selectedOption, sessionsByFamily, perTokenSessions]);
|
|
7757
|
+
const depositAddress = session?.depositAddress;
|
|
7758
|
+
const qrReady = !!depositAddress;
|
|
7759
|
+
const lastFeeCopyRef = useRef(null);
|
|
7760
|
+
const nextFeeCopy = session ? feeCopy() : null;
|
|
7761
|
+
const sessionFeeCopy = nextFeeCopy === lastFeeCopyRef.current ? lastFeeCopyRef.current : lastFeeCopyRef.current = nextFeeCopy;
|
|
7762
|
+
const activeSessionId = session?.sessionId;
|
|
7763
|
+
const activeSessionStatus = session?.status;
|
|
7764
|
+
useEffect(() => {
|
|
7765
|
+
if (!pollEnabled) return;
|
|
7766
|
+
if (!activeSessionId) return;
|
|
7767
|
+
if (activeSessionStatus && ["completed", "failed", "refunded", "wrong_token"].includes(activeSessionStatus)) return;
|
|
7768
|
+
const timer = window.setInterval(() => {
|
|
7769
|
+
fetchManualTransferSession(apiBaseUrl, activeSessionId).then((updated) => {
|
|
7770
|
+
setSessionsByFamily((prev) => {
|
|
7771
|
+
for (const family of Object.keys(prev)) {
|
|
7772
|
+
if (prev[family]?.sessionId === updated.sessionId) {
|
|
7773
|
+
return { ...prev, [family]: updated };
|
|
7774
|
+
}
|
|
7775
|
+
}
|
|
7776
|
+
return prev;
|
|
7777
|
+
});
|
|
7778
|
+
setPerTokenSessions((prev) => {
|
|
7779
|
+
for (const key of Object.keys(prev)) {
|
|
7780
|
+
if (prev[key]?.sessionId === updated.sessionId) {
|
|
7781
|
+
return { ...prev, [key]: updated };
|
|
7782
|
+
}
|
|
7783
|
+
}
|
|
7784
|
+
return prev;
|
|
7785
|
+
});
|
|
7786
|
+
}).catch((err) => setError(err instanceof Error ? err.message : String(err)));
|
|
7787
|
+
}, 2e3);
|
|
7788
|
+
return () => window.clearInterval(timer);
|
|
7789
|
+
}, [apiBaseUrl, activeSessionId, activeSessionStatus, pollEnabled]);
|
|
7790
|
+
const completionSignature = useMemo(() => {
|
|
7791
|
+
const entries2 = [];
|
|
7792
|
+
for (const family of Object.keys(sessionsByFamily)) {
|
|
7793
|
+
const s = sessionsByFamily[family];
|
|
7794
|
+
if (s) entries2.push([s.sessionId, s.status]);
|
|
7795
|
+
}
|
|
7796
|
+
for (const key of Object.keys(perTokenSessions)) {
|
|
7797
|
+
const s = perTokenSessions[key];
|
|
7798
|
+
entries2.push([s.sessionId, s.status]);
|
|
7799
|
+
}
|
|
7800
|
+
entries2.sort((a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0);
|
|
7801
|
+
return JSON.stringify(entries2);
|
|
7802
|
+
}, [sessionsByFamily, perTokenSessions]);
|
|
7803
|
+
useEffect(() => {
|
|
7804
|
+
const all = [];
|
|
7805
|
+
for (const family of Object.keys(sessionsByFamily)) {
|
|
7806
|
+
const s = sessionsByFamily[family];
|
|
7807
|
+
if (s) all.push(s);
|
|
7808
|
+
}
|
|
7809
|
+
for (const key of Object.keys(perTokenSessions)) {
|
|
7810
|
+
all.push(perTokenSessions[key]);
|
|
7811
|
+
}
|
|
7812
|
+
for (const s of all) {
|
|
7813
|
+
if (s.status !== "completed") continue;
|
|
7814
|
+
if (completedRef.current.has(s.sessionId)) continue;
|
|
7815
|
+
completedRef.current.add(s.sessionId);
|
|
7816
|
+
onComplete?.(toTransfer(s));
|
|
7817
|
+
break;
|
|
7818
|
+
}
|
|
7819
|
+
}, [completionSignature, onComplete]);
|
|
7820
|
+
useEffect(() => {
|
|
7821
|
+
if (!error) return;
|
|
7822
|
+
onError?.(error);
|
|
7823
|
+
}, [error, onError]);
|
|
7824
|
+
const createSession = useCallback(async (option) => {
|
|
7825
|
+
if (!merchantAuthorization) return;
|
|
7826
|
+
setLoading(true);
|
|
7827
|
+
setError(null);
|
|
7828
|
+
try {
|
|
7829
|
+
const created = await createManualTransfer(apiBaseUrl, {
|
|
7830
|
+
merchantAuthorization,
|
|
7831
|
+
destination,
|
|
7832
|
+
idempotencyKey,
|
|
7833
|
+
source: { chainId: option.chainId, tokenAddress: option.tokenAddress }
|
|
7834
|
+
});
|
|
7835
|
+
const key = perTokenKey(option.chainId, option.tokenAddress);
|
|
7836
|
+
setPerTokenSessions((prev) => ({ ...prev, [key]: created }));
|
|
7837
|
+
const uri = formatDepositUri(created.depositAddress, option.chainId, option.tokenAddress);
|
|
7838
|
+
void getOrRenderQrDataUrl(uri, { dark: tokens.text, light: tokens.bg });
|
|
7839
|
+
} catch (err) {
|
|
7840
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
7841
|
+
} finally {
|
|
7842
|
+
setLoading(false);
|
|
7843
|
+
}
|
|
7844
|
+
}, [apiBaseUrl, destination, idempotencyKey, merchantAuthorization, tokens.text, tokens.bg]);
|
|
7845
|
+
useEffect(() => {
|
|
7846
|
+
if (!selectedOption) return;
|
|
7847
|
+
if (sessionsByFamily[selectedOption.chainFamily]) return;
|
|
7848
|
+
if (premintedFamiliesRef.current.has(selectedOption.chainFamily)) return;
|
|
7849
|
+
const key = perTokenKey(selectedOption.chainId, selectedOption.tokenAddress);
|
|
7850
|
+
if (perTokenSessions[key]) return;
|
|
7851
|
+
if (inFlightPerTokenRef.current.has(key)) return;
|
|
7852
|
+
inFlightPerTokenRef.current.add(key);
|
|
7853
|
+
void createSession(selectedOption).finally(() => {
|
|
7854
|
+
inFlightPerTokenRef.current.delete(key);
|
|
7855
|
+
});
|
|
7856
|
+
}, [selectedOption, sessionsByFamily, perTokenSessions, createSession]);
|
|
7857
|
+
const resetSessionForNewSelection = useCallback(() => {
|
|
7858
|
+
setError(null);
|
|
7859
|
+
}, []);
|
|
7860
|
+
const selectToken = useCallback((value) => {
|
|
7861
|
+
setSelectedToken(value);
|
|
7862
|
+
const pairValid = (sourceOptions ?? []).some(
|
|
7863
|
+
(opt) => opt.tokenSymbol === value && String(opt.chainId) === selectedChainId
|
|
7864
|
+
);
|
|
7865
|
+
if (!pairValid) {
|
|
7866
|
+
const firstChain = (sourceOptions ?? []).find(
|
|
7867
|
+
(opt) => opt.tokenSymbol === value
|
|
7868
|
+
);
|
|
7869
|
+
setSelectedChainId(
|
|
7870
|
+
firstChain ? String(firstChain.chainId) : ""
|
|
7871
|
+
);
|
|
7872
|
+
}
|
|
7873
|
+
}, [selectedChainId, sourceOptions]);
|
|
7874
|
+
const selectChainId = useCallback((value) => {
|
|
7875
|
+
setSelectedChainId(value);
|
|
7876
|
+
const pairValid = (sourceOptions ?? []).some(
|
|
7877
|
+
(opt) => opt.tokenSymbol === selectedToken && String(opt.chainId) === value
|
|
7878
|
+
);
|
|
7879
|
+
if (!pairValid) {
|
|
7880
|
+
const firstToken = (sourceOptions ?? []).find(
|
|
7881
|
+
(opt) => String(opt.chainId) === value
|
|
7882
|
+
);
|
|
7883
|
+
setSelectedToken(
|
|
7884
|
+
firstToken ? firstToken.tokenSymbol : ""
|
|
7885
|
+
);
|
|
7886
|
+
}
|
|
7887
|
+
}, [selectedToken, sourceOptions]);
|
|
7888
|
+
const screen = screenForSession(session);
|
|
7889
|
+
const copyDepositAddress = useCallback(async (address) => {
|
|
7890
|
+
try {
|
|
7891
|
+
await navigator.clipboard.writeText(address);
|
|
7892
|
+
} catch {
|
|
7893
|
+
const textarea = document.createElement("textarea");
|
|
7894
|
+
textarea.value = address;
|
|
7895
|
+
textarea.setAttribute("readonly", "");
|
|
7896
|
+
textarea.style.position = "absolute";
|
|
7897
|
+
textarea.style.opacity = "0";
|
|
7898
|
+
document.body.appendChild(textarea);
|
|
7899
|
+
textarea.select();
|
|
7900
|
+
try {
|
|
7901
|
+
document.execCommand("copy");
|
|
7902
|
+
} finally {
|
|
7903
|
+
document.body.removeChild(textarea);
|
|
7904
|
+
}
|
|
7905
|
+
}
|
|
7906
|
+
setCopiedAddress(address);
|
|
7907
|
+
window.setTimeout(() => setCopiedAddress((cur) => cur === address ? null : cur), 1500);
|
|
7908
|
+
}, []);
|
|
7909
|
+
const backToSourceSelector = useCallback(() => {
|
|
7910
|
+
setCopiedAddress(null);
|
|
7911
|
+
setError(null);
|
|
7912
|
+
if (!selectedOption) return;
|
|
7913
|
+
const family = selectedOption.chainFamily;
|
|
7914
|
+
setSessionsByFamily((prev) => {
|
|
7915
|
+
if (!prev[family]) return prev;
|
|
7916
|
+
const next = { ...prev };
|
|
7917
|
+
delete next[family];
|
|
7918
|
+
return next;
|
|
7919
|
+
});
|
|
7920
|
+
premintedFamiliesRef.current.delete(family);
|
|
7921
|
+
const ptKey = perTokenKey(selectedOption.chainId, selectedOption.tokenAddress);
|
|
7922
|
+
setPerTokenSessions((prev) => {
|
|
7923
|
+
if (!prev[ptKey]) return prev;
|
|
7924
|
+
const next = { ...prev };
|
|
7925
|
+
delete next[ptKey];
|
|
7926
|
+
return next;
|
|
7927
|
+
});
|
|
7928
|
+
}, [selectedOption]);
|
|
7561
7929
|
return {
|
|
7562
|
-
|
|
7563
|
-
|
|
7564
|
-
|
|
7565
|
-
|
|
7930
|
+
sourceOptions,
|
|
7931
|
+
loadingSources,
|
|
7932
|
+
selectedToken,
|
|
7933
|
+
selectedChainId,
|
|
7934
|
+
session,
|
|
7935
|
+
loading,
|
|
7936
|
+
error,
|
|
7937
|
+
qrReady,
|
|
7938
|
+
copiedAddress,
|
|
7939
|
+
tokenChoices,
|
|
7940
|
+
chainChoices,
|
|
7941
|
+
tokenLogoUriBySymbol,
|
|
7942
|
+
selectedOption,
|
|
7943
|
+
tokensForSelectedChain,
|
|
7944
|
+
chainsForSelectedToken,
|
|
7945
|
+
screen,
|
|
7946
|
+
sessionFeeCopy,
|
|
7947
|
+
depositAddress,
|
|
7948
|
+
createSession,
|
|
7949
|
+
copyDepositAddress,
|
|
7950
|
+
backToSourceSelector,
|
|
7951
|
+
resetSessionForNewSelection,
|
|
7952
|
+
selectToken,
|
|
7953
|
+
selectChainId
|
|
7566
7954
|
};
|
|
7567
7955
|
}
|
|
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
|
-
};
|
|
7956
|
+
var ManualTransferSessionContext = createContext(null);
|
|
7957
|
+
function ManualTransferSessionProvider({
|
|
7958
|
+
destination,
|
|
7959
|
+
merchantAuthorization,
|
|
7960
|
+
idempotencyKey,
|
|
7961
|
+
onComplete,
|
|
7962
|
+
onError,
|
|
7963
|
+
pollEnabled,
|
|
7964
|
+
children
|
|
7965
|
+
}) {
|
|
7966
|
+
const session = useManualTransferSession({
|
|
7967
|
+
destination,
|
|
7968
|
+
merchantAuthorization,
|
|
7969
|
+
idempotencyKey,
|
|
7970
|
+
onComplete,
|
|
7971
|
+
onError,
|
|
7972
|
+
pollEnabled
|
|
7973
|
+
});
|
|
7974
|
+
return /* @__PURE__ */ jsx(ManualTransferSessionContext.Provider, { value: session, children });
|
|
7613
7975
|
}
|
|
7614
|
-
function
|
|
7615
|
-
|
|
7616
|
-
|
|
7617
|
-
|
|
7618
|
-
|
|
7619
|
-
|
|
7620
|
-
|
|
7621
|
-
|
|
7622
|
-
|
|
7623
|
-
|
|
7624
|
-
|
|
7625
|
-
|
|
7626
|
-
|
|
7627
|
-
|
|
7628
|
-
|
|
7629
|
-
|
|
7630
|
-
|
|
7976
|
+
function useManualTransferSessionContext() {
|
|
7977
|
+
const ctx = useContext(ManualTransferSessionContext);
|
|
7978
|
+
if (!ctx) {
|
|
7979
|
+
throw new Error(
|
|
7980
|
+
"useManualTransferSessionContext must be used within a <ManualTransferSessionProvider>"
|
|
7981
|
+
);
|
|
7982
|
+
}
|
|
7983
|
+
return ctx;
|
|
7984
|
+
}
|
|
7985
|
+
|
|
7986
|
+
// src/processingStatus.ts
|
|
7987
|
+
var PROCESSING_TIMEOUT_MS = 18e4;
|
|
7988
|
+
var TERMINAL_TRANSFER_STATUSES = /* @__PURE__ */ new Set(["COMPLETED", "FAILED", "EXPIRED"]);
|
|
7989
|
+
var SIGNABLE_TRANSFER_STATUSES = /* @__PURE__ */ new Set(["CREATED", "AUTHORIZED"]);
|
|
7990
|
+
function isTerminalTransferStatus(status) {
|
|
7991
|
+
return TERMINAL_TRANSFER_STATUSES.has(status);
|
|
7992
|
+
}
|
|
7993
|
+
function isTransferSignable(transfer) {
|
|
7994
|
+
return transfer != null && SIGNABLE_TRANSFER_STATUSES.has(transfer.status);
|
|
7995
|
+
}
|
|
7996
|
+
function isTransferAwaitingCompletion(transfer) {
|
|
7997
|
+
if (!transfer) return false;
|
|
7998
|
+
return !isTerminalTransferStatus(transfer.status);
|
|
7999
|
+
}
|
|
8000
|
+
function resolvePreferredTransfer(polledTransfer, localTransfer) {
|
|
8001
|
+
return polledTransfer ?? localTransfer;
|
|
8002
|
+
}
|
|
8003
|
+
function getTransferStatus(polledTransfer, localTransfer) {
|
|
8004
|
+
const transfer = resolvePreferredTransfer(polledTransfer, localTransfer);
|
|
8005
|
+
return transfer?.status ?? "UNKNOWN";
|
|
8006
|
+
}
|
|
8007
|
+
function hasProcessingTimedOut(processingStartedAtMs, nowMs) {
|
|
8008
|
+
if (!processingStartedAtMs) return false;
|
|
8009
|
+
return nowMs - processingStartedAtMs >= PROCESSING_TIMEOUT_MS;
|
|
8010
|
+
}
|
|
8011
|
+
var STATUS_DISPLAY_LABELS = {
|
|
8012
|
+
CREATED: "created",
|
|
8013
|
+
AUTHORIZED: "authorized",
|
|
8014
|
+
SENDING: "sending",
|
|
8015
|
+
SENT: "confirming delivery",
|
|
8016
|
+
COMPLETED: "completed",
|
|
8017
|
+
FAILED: "failed"
|
|
8018
|
+
};
|
|
8019
|
+
function getStatusDisplayLabel(status) {
|
|
8020
|
+
return STATUS_DISPLAY_LABELS[status] ?? status;
|
|
8021
|
+
}
|
|
8022
|
+
function buildProcessingTimeoutMessage(status) {
|
|
8023
|
+
const label = getStatusDisplayLabel(status);
|
|
8024
|
+
return `Payment is taking longer than expected (status: ${label}). Please try again.`;
|
|
8025
|
+
}
|
|
8026
|
+
|
|
8027
|
+
// src/paymentResolvePhase.ts
|
|
8028
|
+
function hasActiveWallet(accounts) {
|
|
8029
|
+
return accounts.some((a) => a.wallets.some((w) => w.status === "ACTIVE"));
|
|
8030
|
+
}
|
|
8031
|
+
function resolveTerminalPhase(state) {
|
|
8032
|
+
if (state.amountTooLow != null) {
|
|
8033
|
+
return {
|
|
8034
|
+
step: "amount-too-low",
|
|
8035
|
+
minAmountUsd: state.amountTooLow.minAmountUsd
|
|
8036
|
+
};
|
|
8037
|
+
}
|
|
8038
|
+
const transferCompleted = state.transfer?.status === "COMPLETED";
|
|
8039
|
+
const needsPasskeyBootstrap = state.privyAuthenticated && !state.activeCredentialId;
|
|
8040
|
+
if (transferCompleted && !needsPasskeyBootstrap && !state.loginRequested) {
|
|
8041
|
+
return { step: "completed", transfer: state.transfer };
|
|
8042
|
+
}
|
|
8043
|
+
if (state.transfer?.status === "FAILED") {
|
|
8044
|
+
return {
|
|
8045
|
+
step: "failed",
|
|
8046
|
+
transfer: state.transfer,
|
|
8047
|
+
error: state.error ?? "Transfer failed."
|
|
8048
|
+
};
|
|
8049
|
+
}
|
|
8050
|
+
if (state.creatingTransfer || isTransferAwaitingCompletion(state.transfer)) {
|
|
8051
|
+
return { step: "processing", transfer: state.transfer };
|
|
8052
|
+
}
|
|
8053
|
+
return null;
|
|
8054
|
+
}
|
|
8055
|
+
function resolveStickyPhase(state) {
|
|
8056
|
+
const currentPhase = state.phase;
|
|
8057
|
+
if (currentPhase.step === "manual-transfer" && !state.loginRequested) {
|
|
8058
|
+
return currentPhase;
|
|
8059
|
+
}
|
|
8060
|
+
if (currentPhase.step === "deposit-options" && !state.loginRequested && !state.privyAuthenticated) {
|
|
8061
|
+
return currentPhase;
|
|
8062
|
+
}
|
|
8063
|
+
if (!state.loginRequested && state.setupFlowScreen === "one-tap-setup") {
|
|
8064
|
+
return { step: "one-tap-setup", action: null };
|
|
8065
|
+
}
|
|
8066
|
+
if (!state.loginRequested && state.setupFlowScreen === "deposit-confirm" && state.selectedAccountId != null) {
|
|
8067
|
+
return {
|
|
8068
|
+
step: "wallet-setup",
|
|
8069
|
+
mobile: null,
|
|
8070
|
+
accountId: state.selectedAccountId
|
|
8071
|
+
};
|
|
8072
|
+
}
|
|
8073
|
+
if (!state.loginRequested && state.mobileTokenAuthorizationPending) {
|
|
8074
|
+
return {
|
|
8075
|
+
step: "wallet-setup",
|
|
8076
|
+
mobile: { deeplinkUri: "", providerId: state.selectedProviderId },
|
|
8077
|
+
accountId: null
|
|
8078
|
+
};
|
|
8079
|
+
}
|
|
8080
|
+
const isFundingSourceSubflow = !state.loginRequested && (currentPhase.step === "token-picker" || currentPhase.step === "guest-source-picker" || currentPhase.step === "select-source" || currentPhase.step === "confirm-sign");
|
|
8081
|
+
if (isFundingSourceSubflow) {
|
|
8082
|
+
return currentPhase;
|
|
8083
|
+
}
|
|
8084
|
+
if ((state.standardDesktopInlineOpenWallet || state.desktopWait != null) && state.privyAuthenticated && state.activeCredentialId != null && state.selectedAccountId != null && !state.loginRequested) {
|
|
8085
|
+
return {
|
|
8086
|
+
step: "wallet-setup",
|
|
8087
|
+
mobile: null,
|
|
8088
|
+
desktopWait: state.desktopWait,
|
|
8089
|
+
accountId: state.selectedAccountId
|
|
8090
|
+
};
|
|
8091
|
+
}
|
|
8092
|
+
if (state.mobileFlow && state.deeplinkUri != null) {
|
|
8093
|
+
return {
|
|
8094
|
+
step: "wallet-setup",
|
|
8095
|
+
mobile: { deeplinkUri: state.deeplinkUri, providerId: state.selectedProviderId },
|
|
8096
|
+
accountId: null
|
|
8097
|
+
};
|
|
8098
|
+
}
|
|
8099
|
+
if (currentPhase.step === "wallet-picker" && currentPhase.reason === "switch" && !state.creatingTransfer && !(state.mobileFlow && state.deeplinkUri)) {
|
|
8100
|
+
return currentPhase;
|
|
8101
|
+
}
|
|
8102
|
+
return null;
|
|
8103
|
+
}
|
|
8104
|
+
function deriveFreshPhase(state) {
|
|
8105
|
+
if (!state.privyReady) {
|
|
8106
|
+
return { step: "initializing" };
|
|
8107
|
+
}
|
|
8108
|
+
if (state.privyAuthenticated && !state.activeCredentialId && !state.passkeyConfigLoaded) {
|
|
8109
|
+
return { step: "initializing" };
|
|
8110
|
+
}
|
|
8111
|
+
if (state.loginRequested) {
|
|
8112
|
+
return { step: "login" };
|
|
8113
|
+
}
|
|
8114
|
+
if (state.enableFullWidget && !state.privyAuthenticated) {
|
|
8115
|
+
return { step: "deposit-options" };
|
|
8116
|
+
}
|
|
8117
|
+
if (!state.privyAuthenticated) {
|
|
8118
|
+
return { step: "login" };
|
|
8119
|
+
}
|
|
8120
|
+
if (state.loadingData && state.activeCredentialId != null) {
|
|
8121
|
+
return { step: "data-loading" };
|
|
8122
|
+
}
|
|
8123
|
+
if (state.requireAmountEntry) {
|
|
8124
|
+
return { step: "enter-amount" };
|
|
8125
|
+
}
|
|
8126
|
+
if (state.activeCredentialId != null && !hasActiveWallet(state.accounts) && !state.mobileFlow) {
|
|
8127
|
+
return { step: "wallet-picker", reason: "link" };
|
|
8128
|
+
}
|
|
8129
|
+
if (state.activeCredentialId != null && hasActiveWallet(state.accounts) && !state.loadingData) {
|
|
8130
|
+
return { step: "deposit" };
|
|
8131
|
+
}
|
|
8132
|
+
return { step: "wallet-picker", reason: "entry" };
|
|
8133
|
+
}
|
|
8134
|
+
function resolvePhase(state) {
|
|
8135
|
+
return resolveTerminalPhase(state) ?? resolveStickyPhase(state) ?? deriveFreshPhase(state);
|
|
8136
|
+
}
|
|
8137
|
+
|
|
8138
|
+
// src/paymentReducer.ts
|
|
8139
|
+
var DEFAULT_ONE_TAP_LIMIT = 1e4;
|
|
8140
|
+
function deriveSourceTypeAndId(state) {
|
|
8141
|
+
if (state.selectedWalletId) {
|
|
8142
|
+
return { sourceType: "walletId", sourceId: state.selectedWalletId };
|
|
8143
|
+
}
|
|
8144
|
+
if (state.selectedAccountId) {
|
|
8145
|
+
return { sourceType: "accountId", sourceId: state.selectedAccountId };
|
|
8146
|
+
}
|
|
8147
|
+
return { sourceType: "accountId", sourceId: "" };
|
|
8148
|
+
}
|
|
8149
|
+
function clearStaleSelection(state) {
|
|
8150
|
+
if (state.selectedAccountId == null) return state;
|
|
8151
|
+
if (state.desktopWait != null) return state;
|
|
8152
|
+
const stillExists = state.accounts.some((a) => a.id === state.selectedAccountId);
|
|
8153
|
+
if (stillExists) return state;
|
|
8154
|
+
return {
|
|
8155
|
+
...state,
|
|
8156
|
+
selectedAccountId: null,
|
|
8157
|
+
selectedWalletId: null,
|
|
8158
|
+
selectedTokenSymbol: null
|
|
8159
|
+
};
|
|
8160
|
+
}
|
|
8161
|
+
function createInitialState(config) {
|
|
8162
|
+
return {
|
|
8163
|
+
phase: config.initialPhase ?? { step: "initializing" },
|
|
8164
|
+
error: null,
|
|
8165
|
+
setupFlowScreen: null,
|
|
8166
|
+
providers: [],
|
|
8167
|
+
accounts: [],
|
|
8168
|
+
chains: [],
|
|
8169
|
+
loadingData: false,
|
|
8170
|
+
depositSelectionRefreshing: false,
|
|
8171
|
+
selectedProviderId: null,
|
|
8172
|
+
selectedAccountId: null,
|
|
8173
|
+
selectedWalletId: null,
|
|
8174
|
+
selectedTokenSymbol: null,
|
|
8175
|
+
savedSelection: null,
|
|
8176
|
+
amount: config.depositAmount != null ? config.depositAmount.toString() : "",
|
|
8177
|
+
transfer: null,
|
|
8178
|
+
pendingTransferId: null,
|
|
8179
|
+
creatingTransfer: false,
|
|
8180
|
+
passkeyConfigLoaded: false,
|
|
8181
|
+
activeCredentialId: config.activeCredentialId,
|
|
8182
|
+
knownCredentialIds: [],
|
|
8183
|
+
oneTapLimit: DEFAULT_ONE_TAP_LIMIT,
|
|
8184
|
+
oneTapLimitSavedDuringSetup: false,
|
|
8185
|
+
mobileFlow: false,
|
|
8186
|
+
deeplinkUri: null,
|
|
8187
|
+
increasingLimit: false,
|
|
8188
|
+
activePublicKey: null,
|
|
8189
|
+
loginRequested: false,
|
|
8190
|
+
standardDesktopInlineOpenWallet: false,
|
|
8191
|
+
desktopWait: null,
|
|
8192
|
+
setupAuthorizationSessionId: null,
|
|
8193
|
+
mobileTokenAuthorizationPending: false,
|
|
8194
|
+
privyReady: false,
|
|
8195
|
+
privyAuthenticated: false,
|
|
8196
|
+
lastResumedAt: 0,
|
|
8197
|
+
setupDepositAmount: null,
|
|
8198
|
+
setupDepositToken: null,
|
|
8199
|
+
setupDepositConfirmed: false,
|
|
8200
|
+
guestWalletPrepared: null,
|
|
8201
|
+
guestWalletDeeplinksPreparing: false,
|
|
8202
|
+
amountTooLow: null,
|
|
8203
|
+
enableFullWidget: config.enableFullWidget ?? false,
|
|
8204
|
+
requireAmountEntry: config.depositAmount == null
|
|
8205
|
+
};
|
|
8206
|
+
}
|
|
8207
|
+
function clearAuthenticatedSessionState(state) {
|
|
8208
|
+
return {
|
|
8209
|
+
...state,
|
|
8210
|
+
error: null,
|
|
8211
|
+
setupFlowScreen: null,
|
|
8212
|
+
providers: [],
|
|
8213
|
+
accounts: [],
|
|
8214
|
+
chains: [],
|
|
8215
|
+
loadingData: false,
|
|
8216
|
+
depositSelectionRefreshing: false,
|
|
8217
|
+
selectedProviderId: null,
|
|
8218
|
+
selectedAccountId: null,
|
|
8219
|
+
selectedWalletId: null,
|
|
8220
|
+
selectedTokenSymbol: null,
|
|
8221
|
+
savedSelection: null,
|
|
8222
|
+
transfer: null,
|
|
8223
|
+
pendingTransferId: null,
|
|
7631
8224
|
creatingTransfer: false,
|
|
7632
8225
|
passkeyConfigLoaded: false,
|
|
7633
8226
|
activeCredentialId: null,
|
|
@@ -8071,552 +8664,118 @@ function applyAction(state, action) {
|
|
|
8071
8664
|
// unauthenticated path) preserves the flag implicitly via the
|
|
8072
8665
|
// surrounding `...state` spread, so no change is needed there.
|
|
8073
8666
|
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);
|
|
8667
|
+
};
|
|
8668
|
+
case "SYNC_PRIVY_SESSION":
|
|
8669
|
+
if (action.ready && !action.authenticated) {
|
|
8670
|
+
return {
|
|
8671
|
+
...clearAuthenticatedSessionState(state),
|
|
8672
|
+
privyReady: true,
|
|
8673
|
+
privyAuthenticated: false
|
|
8674
|
+
};
|
|
8482
8675
|
}
|
|
8676
|
+
return {
|
|
8677
|
+
...state,
|
|
8678
|
+
privyReady: action.ready,
|
|
8679
|
+
privyAuthenticated: action.authenticated,
|
|
8680
|
+
...action.authenticated ? { loginRequested: false } : {}
|
|
8681
|
+
};
|
|
8682
|
+
case "SYNC_AMOUNT":
|
|
8683
|
+
return {
|
|
8684
|
+
...state,
|
|
8685
|
+
amount: action.amount,
|
|
8686
|
+
requireAmountEntry: action.amount === "" ? state.requireAmountEntry : false
|
|
8687
|
+
};
|
|
8688
|
+
case "SET_AMOUNT_INPUT":
|
|
8689
|
+
return { ...state, amount: action.value };
|
|
8690
|
+
case "FINALIZE_AMOUNT":
|
|
8691
|
+
return { ...state, requireAmountEntry: false };
|
|
8692
|
+
case "PAGE_RESUMED":
|
|
8693
|
+
return { ...state, lastResumedAt: Date.now() };
|
|
8694
|
+
// ── Setup deposit (combined first-time flow) ────────────────
|
|
8695
|
+
case "SET_SETUP_DEPOSIT_AMOUNT":
|
|
8696
|
+
return { ...state, setupDepositAmount: action.amount };
|
|
8697
|
+
case "SET_SETUP_DEPOSIT_TOKEN":
|
|
8698
|
+
return {
|
|
8699
|
+
...state,
|
|
8700
|
+
setupDepositToken: {
|
|
8701
|
+
symbol: action.symbol,
|
|
8702
|
+
chainName: action.chainName,
|
|
8703
|
+
...action.walletId ? { walletId: action.walletId } : {},
|
|
8704
|
+
...action.tokenAddress ? { tokenAddress: action.tokenAddress } : {},
|
|
8705
|
+
...action.chainId != null ? { chainId: action.chainId } : {}
|
|
8706
|
+
}
|
|
8707
|
+
};
|
|
8708
|
+
case "CLEAR_SETUP_DEPOSIT_TOKEN":
|
|
8709
|
+
return { ...state, setupDepositToken: null };
|
|
8710
|
+
case "CONFIRM_SETUP_DEPOSIT":
|
|
8711
|
+
return { ...state, setupDepositConfirmed: true };
|
|
8712
|
+
default:
|
|
8713
|
+
return state;
|
|
8714
|
+
}
|
|
8715
|
+
}
|
|
8716
|
+
|
|
8717
|
+
// src/setupDepositConfirmation.ts
|
|
8718
|
+
function deriveEffectiveSetupSource(setupDepositToken, setupSelectedSourceOption) {
|
|
8719
|
+
if (setupDepositToken) return setupDepositToken;
|
|
8720
|
+
if (setupSelectedSourceOption) {
|
|
8721
|
+
return {
|
|
8722
|
+
symbol: setupSelectedSourceOption.tokenSymbol,
|
|
8723
|
+
chainName: setupSelectedSourceOption.chainName,
|
|
8724
|
+
walletId: setupSelectedSourceOption.walletId,
|
|
8725
|
+
tokenAddress: setupSelectedSourceOption.tokenAddress,
|
|
8726
|
+
chainId: setupSelectedSourceOption.chainId != null ? Number(setupSelectedSourceOption.chainId) : void 0
|
|
8727
|
+
};
|
|
8728
|
+
}
|
|
8729
|
+
return null;
|
|
8730
|
+
}
|
|
8731
|
+
function planConfirmSetupDeposit(input) {
|
|
8732
|
+
const effective = deriveEffectiveSetupSource(
|
|
8733
|
+
input.setupDepositToken,
|
|
8734
|
+
input.setupSelectedSourceOption
|
|
8735
|
+
);
|
|
8736
|
+
if (!effective) {
|
|
8737
|
+
return { kind: "error", error: "Select a source token before continuing." };
|
|
8738
|
+
}
|
|
8739
|
+
if (!effective.walletId) {
|
|
8740
|
+
return {
|
|
8741
|
+
kind: "error",
|
|
8742
|
+
error: "Selected source is not ready yet. Wait for wallet discovery to finish."
|
|
8743
|
+
};
|
|
8744
|
+
}
|
|
8745
|
+
const actions = [
|
|
8746
|
+
{ type: "SET_ERROR", error: null },
|
|
8747
|
+
{
|
|
8748
|
+
type: "SET_SETUP_DEPOSIT_TOKEN",
|
|
8749
|
+
symbol: effective.symbol,
|
|
8750
|
+
chainName: effective.chainName,
|
|
8751
|
+
walletId: effective.walletId,
|
|
8752
|
+
tokenAddress: effective.tokenAddress,
|
|
8753
|
+
chainId: effective.chainId
|
|
8483
8754
|
}
|
|
8484
|
-
|
|
8485
|
-
|
|
8486
|
-
|
|
8487
|
-
|
|
8488
|
-
|
|
8489
|
-
|
|
8490
|
-
|
|
8491
|
-
|
|
8492
|
-
|
|
8493
|
-
|
|
8494
|
-
|
|
8495
|
-
|
|
8755
|
+
];
|
|
8756
|
+
if (input.selectedAccountId) {
|
|
8757
|
+
actions.push({
|
|
8758
|
+
type: "SELECT_ACCOUNT",
|
|
8759
|
+
accountId: input.selectedAccountId,
|
|
8760
|
+
walletId: effective.walletId
|
|
8761
|
+
});
|
|
8762
|
+
actions.push({
|
|
8763
|
+
type: "SELECT_TOKEN",
|
|
8764
|
+
walletId: effective.walletId,
|
|
8765
|
+
tokenSymbol: effective.symbol
|
|
8766
|
+
});
|
|
8767
|
+
}
|
|
8768
|
+
actions.push({ type: "SET_SETUP_FLOW_SCREEN", screen: "one-tap-setup" });
|
|
8769
|
+
actions.push({ type: "CONFIRM_SETUP_DEPOSIT" });
|
|
8496
8770
|
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
|
|
8771
|
+
kind: "proceed",
|
|
8772
|
+
actions,
|
|
8773
|
+
resolveSource: {
|
|
8774
|
+
chainName: effective.chainName,
|
|
8775
|
+
tokenSymbol: effective.symbol
|
|
8776
|
+
}
|
|
8522
8777
|
};
|
|
8523
8778
|
}
|
|
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
8779
|
function ScreenLayout({ children, footer }) {
|
|
8621
8780
|
const { tokens, theme, isMobileApp } = useBlinkConfig();
|
|
8622
8781
|
const isRedesign = theme.endsWith("New");
|
|
@@ -10331,16 +10490,21 @@ function DepositQrCodeImpl({
|
|
|
10331
10490
|
depToken
|
|
10332
10491
|
}) {
|
|
10333
10492
|
const { tokens } = useBlinkConfig();
|
|
10334
|
-
const [dataUrl, setDataUrl] = useState(null);
|
|
10335
10493
|
const uri = formatDepositUri(address, chainId, depToken);
|
|
10494
|
+
const dark = tokens.text;
|
|
10495
|
+
const light = tokens.bg;
|
|
10496
|
+
const [dataUrl, setDataUrl] = useState(
|
|
10497
|
+
() => getCachedQrDataUrl(uri, { dark, light })
|
|
10498
|
+
);
|
|
10336
10499
|
useEffect(() => {
|
|
10500
|
+
const cached = getCachedQrDataUrl(uri, { dark, light });
|
|
10501
|
+
if (cached) {
|
|
10502
|
+
setDataUrl(cached);
|
|
10503
|
+
return;
|
|
10504
|
+
}
|
|
10337
10505
|
let cancelled = false;
|
|
10338
|
-
|
|
10339
|
-
|
|
10340
|
-
margin: 1,
|
|
10341
|
-
width: 203,
|
|
10342
|
-
color: { dark: tokens.text, light: tokens.bg }
|
|
10343
|
-
}).then((url) => {
|
|
10506
|
+
setDataUrl(null);
|
|
10507
|
+
getOrRenderQrDataUrl(uri, { dark, light }).then((url) => {
|
|
10344
10508
|
if (!cancelled) setDataUrl(url);
|
|
10345
10509
|
}).catch(() => {
|
|
10346
10510
|
if (!cancelled) setDataUrl(null);
|
|
@@ -10348,7 +10512,7 @@ function DepositQrCodeImpl({
|
|
|
10348
10512
|
return () => {
|
|
10349
10513
|
cancelled = true;
|
|
10350
10514
|
};
|
|
10351
|
-
}, [uri]);
|
|
10515
|
+
}, [uri, dark, light]);
|
|
10352
10516
|
return /* @__PURE__ */ jsx("div", { style: qrFrameStyle(tokens.bgCardTranslucent), children: dataUrl ? /* @__PURE__ */ jsxs("div", { style: qrContainerStyle, children: [
|
|
10353
10517
|
/* @__PURE__ */ jsx("img", { src: dataUrl, alt: "Deposit QR code", style: qrImageStyle }),
|
|
10354
10518
|
/* @__PURE__ */ jsx("img", { src: BLINK_QR_LOGO, alt: "", style: qrLogoStyle })
|
|
@@ -11436,7 +11600,7 @@ function EnterAmountScreen({
|
|
|
11436
11600
|
)
|
|
11437
11601
|
] }),
|
|
11438
11602
|
children: [
|
|
11439
|
-
/* @__PURE__ */ jsx(ScreenHeader, { right: headerRight }),
|
|
11603
|
+
/* @__PURE__ */ jsx(ScreenHeader, { title: "Deposit", right: headerRight }),
|
|
11440
11604
|
/* @__PURE__ */ jsxs("div", { style: contentStyle4(isDesktop), children: [
|
|
11441
11605
|
isDesktop ? /* @__PURE__ */ jsxs("div", { style: desktopHeroRowStyle(heroColor, getDesktopHeroFontSize(value)), children: [
|
|
11442
11606
|
/* @__PURE__ */ jsx("span", { "aria-hidden": "true", style: dollarStyle2(isZero), children: "$" }),
|
|
@@ -12777,7 +12941,8 @@ function SetupScreen({
|
|
|
12777
12941
|
onLogout,
|
|
12778
12942
|
loading,
|
|
12779
12943
|
loadingShimmersEnabled = false,
|
|
12780
|
-
error
|
|
12944
|
+
error,
|
|
12945
|
+
selectedTokenSymbol
|
|
12781
12946
|
}) {
|
|
12782
12947
|
const { tokens } = useBlinkConfig();
|
|
12783
12948
|
const [selectedPreset, setSelectedPreset] = useState(DEFAULT_MAX);
|
|
@@ -12886,7 +13051,8 @@ function SetupScreen({
|
|
|
12886
13051
|
style: illustrationStyle3
|
|
12887
13052
|
}
|
|
12888
13053
|
),
|
|
12889
|
-
/* @__PURE__ */ jsx("h2", { style: headingStyle7(tokens.text), children:
|
|
13054
|
+
/* @__PURE__ */ jsx("h2", { style: headingStyle7(tokens.text), children: `Next time deposit
|
|
13055
|
+
${selectedTokenSymbol ?? "USDC"} in one tap` }),
|
|
12890
13056
|
/* @__PURE__ */ jsx("p", { style: subtitleStyle5(tokens.textSecondary), children: "Set a cap for passkey deposits.\nYou always stay in control." }),
|
|
12891
13057
|
error && /* @__PURE__ */ jsx("div", { style: errorBannerStyle5(tokens), children: error }),
|
|
12892
13058
|
/* @__PURE__ */ jsx("div", { style: chipsRowStyle, children: PRESETS.map(({ label, value }) => {
|
|
@@ -12914,8 +13080,8 @@ var contentStyle9 = {
|
|
|
12914
13080
|
alignItems: "center",
|
|
12915
13081
|
justifyContent: "center",
|
|
12916
13082
|
textAlign: "center",
|
|
12917
|
-
gap:
|
|
12918
|
-
padding: "
|
|
13083
|
+
gap: 12,
|
|
13084
|
+
padding: "8px 0"
|
|
12919
13085
|
};
|
|
12920
13086
|
var shimmerContentStyle = {
|
|
12921
13087
|
display: "flex",
|
|
@@ -13286,7 +13452,7 @@ function SetupDepositScreen({
|
|
|
13286
13452
|
NotificationBanner,
|
|
13287
13453
|
{
|
|
13288
13454
|
variant: "negative",
|
|
13289
|
-
title: "Deposit amount exceeds balance",
|
|
13455
|
+
title: "Deposit amount exceeds stablecoin balance",
|
|
13290
13456
|
description: "Pick another asset or add more funds to your wallet"
|
|
13291
13457
|
}
|
|
13292
13458
|
) : /* @__PURE__ */ jsx(NotificationBanner, { title: "Something went wrong", description: error }) })
|
|
@@ -13904,7 +14070,7 @@ function DepositScreen({
|
|
|
13904
14070
|
NotificationBanner,
|
|
13905
14071
|
{
|
|
13906
14072
|
variant: "negative",
|
|
13907
|
-
title: "Deposit amount exceeds balance",
|
|
14073
|
+
title: "Deposit amount exceeds stablecoin balance",
|
|
13908
14074
|
description: "Pick another asset or add more funds to your wallet"
|
|
13909
14075
|
}
|
|
13910
14076
|
) : needsAuthorization ? /* @__PURE__ */ jsx(
|
|
@@ -14826,12 +14992,12 @@ function DepositAddressScreen({
|
|
|
14826
14992
|
),
|
|
14827
14993
|
/* @__PURE__ */ jsxs("div", { style: contentStyle16, children: [
|
|
14828
14994
|
/* @__PURE__ */ jsx("h2", { style: depositTitleStyle(tokens.text), children: "Deposit Address" }),
|
|
14829
|
-
qrReady && session ? /* @__PURE__ */ jsx(
|
|
14995
|
+
qrReady && session && selectedOption ? /* @__PURE__ */ jsx(
|
|
14830
14996
|
DepositQrCode,
|
|
14831
14997
|
{
|
|
14832
14998
|
address: session.depositAddress,
|
|
14833
|
-
chainId:
|
|
14834
|
-
depToken:
|
|
14999
|
+
chainId: selectedOption.chainId,
|
|
15000
|
+
depToken: selectedOption.tokenAddress
|
|
14835
15001
|
}
|
|
14836
15002
|
) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
14837
15003
|
/* @__PURE__ */ jsx("style", { children: `
|
|
@@ -15850,12 +16016,7 @@ var errorBannerStyle8 = (themeTokens) => ({
|
|
|
15850
16016
|
textAlign: "left"
|
|
15851
16017
|
});
|
|
15852
16018
|
function ManualTransferFlow({
|
|
15853
|
-
|
|
15854
|
-
merchantAuthorization,
|
|
15855
|
-
idempotencyKey,
|
|
15856
|
-
mock = false,
|
|
15857
|
-
onComplete,
|
|
15858
|
-
onError,
|
|
16019
|
+
hasMerchantAuthorization,
|
|
15859
16020
|
onCreatePasskey,
|
|
15860
16021
|
createPasskeyLoading = false,
|
|
15861
16022
|
createPasskeyError = null,
|
|
@@ -15884,17 +16045,9 @@ function ManualTransferFlow({
|
|
|
15884
16045
|
depositAddress,
|
|
15885
16046
|
copyDepositAddress,
|
|
15886
16047
|
backToSourceSelector,
|
|
15887
|
-
advanceMockStatus,
|
|
15888
16048
|
selectToken,
|
|
15889
16049
|
selectChainId
|
|
15890
|
-
} =
|
|
15891
|
-
destination,
|
|
15892
|
-
merchantAuthorization,
|
|
15893
|
-
idempotencyKey,
|
|
15894
|
-
mock,
|
|
15895
|
-
onComplete,
|
|
15896
|
-
onError
|
|
15897
|
-
});
|
|
16050
|
+
} = useManualTransferSessionContext();
|
|
15898
16051
|
const [passkeyCreated, setPasskeyCreated] = useState(false);
|
|
15899
16052
|
const prevPasskeyLoadingRef = useRef(false);
|
|
15900
16053
|
useEffect(() => {
|
|
@@ -15903,9 +16056,8 @@ function ManualTransferFlow({
|
|
|
15903
16056
|
}
|
|
15904
16057
|
prevPasskeyLoadingRef.current = createPasskeyLoading;
|
|
15905
16058
|
}, [createPasskeyLoading, createPasskeyError]);
|
|
15906
|
-
const DEV_MOCK_STATUS = mock;
|
|
15907
16059
|
let screenContent = null;
|
|
15908
|
-
if (!
|
|
16060
|
+
if (!hasMerchantAuthorization) {
|
|
15909
16061
|
screenContent = /* @__PURE__ */ jsxs(ScreenLayout, { footer: /* @__PURE__ */ jsx(PrimaryButton, { onClick: onBack, children: "Back" }), children: [
|
|
15910
16062
|
/* @__PURE__ */ jsx(ScreenHeader, { onBack }),
|
|
15911
16063
|
/* @__PURE__ */ jsxs("div", { style: contentStyle20, children: [
|
|
@@ -15975,17 +16127,7 @@ function ManualTransferFlow({
|
|
|
15975
16127
|
if (!screenContent) {
|
|
15976
16128
|
return null;
|
|
15977
16129
|
}
|
|
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
|
-
] });
|
|
16130
|
+
return screenContent;
|
|
15989
16131
|
}
|
|
15990
16132
|
var contentStyle20 = {
|
|
15991
16133
|
alignItems: "center",
|
|
@@ -16285,6 +16427,7 @@ function buildSetupDepositScreenProps({
|
|
|
16285
16427
|
function buildSetupScreenProps({
|
|
16286
16428
|
flow,
|
|
16287
16429
|
remote,
|
|
16430
|
+
derived,
|
|
16288
16431
|
forms,
|
|
16289
16432
|
handlers
|
|
16290
16433
|
}) {
|
|
@@ -16293,11 +16436,12 @@ function buildSetupScreenProps({
|
|
|
16293
16436
|
const waitingForDesktopWalletConnection = flow.isDesktop && remote.authExecutorExecuting && remote.pendingOneTapSetup == null && (remote.authExecutorCurrentAction == null || remote.authExecutorCurrentAction.type === "OPEN_PROVIDER");
|
|
16294
16437
|
return {
|
|
16295
16438
|
onSetupOneTap: handlers.onSetupOneTap,
|
|
16296
|
-
onBack: handlers.onBackFromSubflow,
|
|
16297
|
-
onLogout: handlers.onLogout,
|
|
16439
|
+
onBack: flow.isDesktop ? handlers.onBackFromSubflow : void 0,
|
|
16440
|
+
onLogout: flow.isDesktop ? handlers.onLogout : void 0,
|
|
16298
16441
|
loading: savingOneTapLimit,
|
|
16299
16442
|
loadingShimmersEnabled: waitingForDesktopWalletConnection,
|
|
16300
|
-
error: state.error
|
|
16443
|
+
error: state.error,
|
|
16444
|
+
selectedTokenSymbol: derived.selectedSource?.token.symbol
|
|
16301
16445
|
};
|
|
16302
16446
|
}
|
|
16303
16447
|
function buildConfirmSignScreenProps({
|
|
@@ -16574,12 +16718,7 @@ function StepRendererContent({
|
|
|
16574
16718
|
return /* @__PURE__ */ jsx(
|
|
16575
16719
|
ManualTransferFlow,
|
|
16576
16720
|
{
|
|
16577
|
-
|
|
16578
|
-
merchantAuthorization: flow.merchantAuthorization,
|
|
16579
|
-
idempotencyKey: flow.idempotencyKey,
|
|
16580
|
-
mock: flow.mock,
|
|
16581
|
-
onComplete: flow.onComplete,
|
|
16582
|
-
onError: flow.onError,
|
|
16721
|
+
hasMerchantAuthorization: flow.merchantAuthorization != null,
|
|
16583
16722
|
onCreatePasskey: handlers.onSignupWithPasskey,
|
|
16584
16723
|
createPasskeyLoading: flow.passkeyLoading,
|
|
16585
16724
|
createPasskeyError: flow.state.error,
|
|
@@ -18797,8 +18936,11 @@ function usePasskeyCheckEffect(deps) {
|
|
|
18797
18936
|
setupAccountIdRef,
|
|
18798
18937
|
reauthSessionIdRef,
|
|
18799
18938
|
reauthTokenRef,
|
|
18800
|
-
pollingTransferIdRef
|
|
18939
|
+
pollingTransferIdRef,
|
|
18940
|
+
reloadAccounts
|
|
18801
18941
|
} = deps;
|
|
18942
|
+
const reloadAccountsRef = useRef(reloadAccounts);
|
|
18943
|
+
reloadAccountsRef.current = reloadAccounts;
|
|
18802
18944
|
const { getAccessToken: privyGetAccessToken, user } = usePrivy();
|
|
18803
18945
|
const effectiveGetAccessToken = deps.getAccessToken ?? privyGetAccessToken;
|
|
18804
18946
|
const onCompleteRef = useRef(deps.onComplete);
|
|
@@ -18928,6 +19070,11 @@ function usePasskeyCheckEffect(deps) {
|
|
|
18928
19070
|
mobileSetupFlowRef.current = false;
|
|
18929
19071
|
setupAccountIdRef.current = null;
|
|
18930
19072
|
clearMobileFlowState();
|
|
19073
|
+
try {
|
|
19074
|
+
await reloadAccountsRef.current();
|
|
19075
|
+
} catch {
|
|
19076
|
+
}
|
|
19077
|
+
dispatch({ type: "MOBILE_SETUP_COMPLETE" });
|
|
18931
19078
|
return;
|
|
18932
19079
|
}
|
|
18933
19080
|
if (persisted.accountId && !persisted.transferId) {
|
|
@@ -18936,7 +19083,14 @@ function usePasskeyCheckEffect(deps) {
|
|
|
18936
19083
|
const session = await fetchAuthorizationSession(apiBaseUrl, persisted.sessionId);
|
|
18937
19084
|
if (cancelled) return;
|
|
18938
19085
|
if (session.status === "AUTHORIZED") {
|
|
19086
|
+
mobileSetupFlowRef.current = false;
|
|
19087
|
+
setupAccountIdRef.current = null;
|
|
18939
19088
|
clearMobileFlowState();
|
|
19089
|
+
try {
|
|
19090
|
+
await reloadAccountsRef.current();
|
|
19091
|
+
} catch {
|
|
19092
|
+
}
|
|
19093
|
+
dispatch({ type: "MOBILE_SETUP_COMPLETE" });
|
|
18940
19094
|
return;
|
|
18941
19095
|
}
|
|
18942
19096
|
} catch {
|
|
@@ -19401,25 +19555,24 @@ function useMobilePollingEffect(deps) {
|
|
|
19401
19555
|
dispatch({ type: "MOBILE_SETUP_COMPLETE" });
|
|
19402
19556
|
};
|
|
19403
19557
|
const pollWalletActive = async () => {
|
|
19558
|
+
if (setupSessionId) {
|
|
19559
|
+
try {
|
|
19560
|
+
const session = await fetchAuthorizationSession(apiBaseUrl, setupSessionId);
|
|
19561
|
+
if (cancelled) return;
|
|
19562
|
+
if (session.status === "AUTHORIZED") {
|
|
19563
|
+
await completeSetup();
|
|
19564
|
+
return;
|
|
19565
|
+
}
|
|
19566
|
+
} catch {
|
|
19567
|
+
}
|
|
19568
|
+
}
|
|
19404
19569
|
try {
|
|
19405
19570
|
const token = await getAccessTokenRef.current();
|
|
19406
19571
|
if (!token || cancelled) return;
|
|
19407
19572
|
const acct = await fetchAccount(apiBaseUrl, token, accountId, credentialId);
|
|
19408
19573
|
if (cancelled) return;
|
|
19409
|
-
|
|
19410
|
-
if (hasActive) {
|
|
19574
|
+
if (acct.wallets.some((w) => w.status === "ACTIVE")) {
|
|
19411
19575
|
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
19576
|
}
|
|
19424
19577
|
} catch {
|
|
19425
19578
|
}
|
|
@@ -19854,7 +20007,6 @@ function BlinkPayment(props) {
|
|
|
19854
20007
|
function BlinkPaymentInner({
|
|
19855
20008
|
destination,
|
|
19856
20009
|
initialScreen,
|
|
19857
|
-
mock,
|
|
19858
20010
|
onComplete,
|
|
19859
20011
|
onError,
|
|
19860
20012
|
useWalletConnector: useWalletConnectorProp,
|
|
@@ -19943,6 +20095,7 @@ function BlinkPaymentInner({
|
|
|
19943
20095
|
minTransferAmountUsd: effectiveMinDepositAmountUsd
|
|
19944
20096
|
});
|
|
19945
20097
|
const feeEstimateEnabled = effectiveAuthenticated && (state.phase.step === "deposit" || state.phase.step === "wallet-setup" || state.phase.step === "one-tap-setup");
|
|
20098
|
+
const manualTransferActive = screenForPhase(state.phase) === "manual-transfer";
|
|
19946
20099
|
const setupSelectedSourceOption = useMemo(() => {
|
|
19947
20100
|
const options = sourceSelection.pendingSelectSourceAction?.metadata?.options ?? [];
|
|
19948
20101
|
return resolveSelectSourceOption(
|
|
@@ -20089,13 +20242,14 @@ function BlinkPaymentInner({
|
|
|
20089
20242
|
idempotencyKey
|
|
20090
20243
|
});
|
|
20091
20244
|
const accountSwitchSessionId = state.setupAuthorizationSessionId;
|
|
20245
|
+
const accountSwitchListenerArmed = accountSwitchSessionId != null && state.desktopWait == null;
|
|
20092
20246
|
const handleProviderWalletAccountSwitch = provider.handleWalletAccountSwitch;
|
|
20093
20247
|
const onWalletAccountChanged = useCallback(async (change) => {
|
|
20094
20248
|
if (!accountSwitchSessionId) return;
|
|
20095
20249
|
await handleProviderWalletAccountSwitch(change, accountSwitchSessionId);
|
|
20096
20250
|
}, [handleProviderWalletAccountSwitch, accountSwitchSessionId]);
|
|
20097
20251
|
useWalletAccountSwitchEffect({
|
|
20098
|
-
enabled:
|
|
20252
|
+
enabled: accountSwitchListenerArmed,
|
|
20099
20253
|
isDesktop,
|
|
20100
20254
|
onAccountChanged: onWalletAccountChanged
|
|
20101
20255
|
});
|
|
@@ -20191,6 +20345,7 @@ function BlinkPaymentInner({
|
|
|
20191
20345
|
reauthTokenRef: mobileFlowRefs.reauthTokenRef,
|
|
20192
20346
|
pollingTransferIdRef: transfer.pollingTransferIdRef,
|
|
20193
20347
|
handleAuthorizedMobileReturn: mobileFlow.handleAuthorizedMobileReturn,
|
|
20348
|
+
reloadAccounts: transfer.reloadAccounts,
|
|
20194
20349
|
onComplete,
|
|
20195
20350
|
getAccessToken: effectiveGetAccessToken,
|
|
20196
20351
|
pendingTransferFlowKey
|
|
@@ -20357,15 +20512,18 @@ function BlinkPaymentInner({
|
|
|
20357
20512
|
dispatch,
|
|
20358
20513
|
orchestrator
|
|
20359
20514
|
]);
|
|
20360
|
-
const handleBackFromSetupDeposit = useCallback(() => {
|
|
20515
|
+
const handleBackFromSetupDeposit = useCallback(async () => {
|
|
20361
20516
|
orchestrator.cancelPendingFlow();
|
|
20362
20517
|
authExecutor.cancelPendingExecution();
|
|
20363
20518
|
clearScreenErrors();
|
|
20519
|
+
if (isDesktop) {
|
|
20520
|
+
await revokeAndDisconnectActiveWagmiConnector(wagmiConfig);
|
|
20521
|
+
}
|
|
20364
20522
|
dispatch({ type: "RESTORE_SELECTION" });
|
|
20365
20523
|
dispatch({ type: "CLEAR_SETUP_DEPOSIT_TOKEN" });
|
|
20366
20524
|
dispatch({ type: "SET_SETUP_FLOW_SCREEN", screen: null });
|
|
20367
20525
|
dispatch({ type: "SET_USER_INTENT", intent: { step: "wallet-picker", reason: "switch" } });
|
|
20368
|
-
}, [authExecutor, clearScreenErrors, orchestrator, dispatch]);
|
|
20526
|
+
}, [authExecutor, clearScreenErrors, orchestrator, dispatch, isDesktop, wagmiConfig]);
|
|
20369
20527
|
const handleAuthorizationRetry = useCallback(() => {
|
|
20370
20528
|
void (async () => {
|
|
20371
20529
|
try {
|
|
@@ -20405,6 +20563,11 @@ function BlinkPaymentInner({
|
|
|
20405
20563
|
clearScreenErrors();
|
|
20406
20564
|
dispatch({ type: "SET_SETUP_DEPOSIT_AMOUNT", amount });
|
|
20407
20565
|
dispatch({ type: "SET_USER_INTENT", intent: { step: "wallet-picker", reason: "switch" } });
|
|
20566
|
+
void (async () => {
|
|
20567
|
+
await revokeAndDisconnectActiveWagmiConnector(wagmiConfig);
|
|
20568
|
+
await authExecutor.resetWalletConnect().catch(() => {
|
|
20569
|
+
});
|
|
20570
|
+
})();
|
|
20408
20571
|
},
|
|
20409
20572
|
onBackFromSetupDeposit: handleBackFromSetupDeposit,
|
|
20410
20573
|
onBackFromSubflow: () => {
|
|
@@ -20453,65 +20616,76 @@ function BlinkPaymentInner({
|
|
|
20453
20616
|
handleSetDepositToken,
|
|
20454
20617
|
handleConfirmSetupDeposit,
|
|
20455
20618
|
handleBackFromSetupDeposit,
|
|
20456
|
-
handleAuthorizationRetry
|
|
20619
|
+
handleAuthorizationRetry,
|
|
20620
|
+
wagmiConfig
|
|
20457
20621
|
]);
|
|
20458
20622
|
return /* @__PURE__ */ jsx(EffectiveDepositAmountProvider, { value: effectiveDepositAmount, children: /* @__PURE__ */ jsx(
|
|
20459
|
-
|
|
20623
|
+
ManualTransferSessionProvider,
|
|
20460
20624
|
{
|
|
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
|
-
|
|
20625
|
+
destination,
|
|
20626
|
+
merchantAuthorization,
|
|
20627
|
+
idempotencyKey,
|
|
20628
|
+
onComplete,
|
|
20629
|
+
onError,
|
|
20630
|
+
pollEnabled: manualTransferActive,
|
|
20631
|
+
children: /* @__PURE__ */ jsx(
|
|
20632
|
+
StepRenderer,
|
|
20633
|
+
{
|
|
20634
|
+
flow: {
|
|
20635
|
+
state,
|
|
20636
|
+
authenticated: effectiveAuthenticated,
|
|
20637
|
+
passkeyLoading: auth.passkeyLoginStatus !== "initial" && auth.passkeyLoginStatus !== "done" && auth.passkeyLoginStatus !== "error" || auth.passkeySignupStatus !== "initial" && auth.passkeySignupStatus !== "done" && auth.passkeySignupStatus !== "error" || auth.passkeySignupPopupActive,
|
|
20638
|
+
isDesktop,
|
|
20639
|
+
isMobileApp: isMobileApp ?? false,
|
|
20640
|
+
merchantName,
|
|
20641
|
+
onBack,
|
|
20642
|
+
onDismiss,
|
|
20643
|
+
depositAmount,
|
|
20644
|
+
effectiveDepositAmount,
|
|
20645
|
+
minTransferAmountUsd,
|
|
20646
|
+
destination,
|
|
20647
|
+
merchantAuthorization,
|
|
20648
|
+
idempotencyKey,
|
|
20649
|
+
onComplete,
|
|
20650
|
+
onError
|
|
20651
|
+
},
|
|
20652
|
+
remote: {
|
|
20653
|
+
pollingTransfer: polling.transfer,
|
|
20654
|
+
pollingError: polling.error,
|
|
20655
|
+
authExecutorError: authExecutor.error,
|
|
20656
|
+
authExecutorExecuting: authExecutor.executing,
|
|
20657
|
+
authExecutorCurrentAction: authExecutor.currentAction,
|
|
20658
|
+
pendingOneTapSetup: orchestrator.pendingOneTapAction,
|
|
20659
|
+
setupAuthorizationComplete,
|
|
20660
|
+
transferSigningSigning: transferSigning.signing,
|
|
20661
|
+
transferSigningError: transferSigning.error,
|
|
20662
|
+
transferSigningPasskeyDismissed: transferSigning.passkeyDismissed,
|
|
20663
|
+
pendingSelectSource: orchestrator.pendingSelectSourceAction
|
|
20664
|
+
},
|
|
20665
|
+
derived: {
|
|
20666
|
+
pendingConnections: derived.pendingConnections,
|
|
20667
|
+
depositEligibleAccounts: derived.depositEligibleAccounts,
|
|
20668
|
+
sourceName: derived.sourceName,
|
|
20669
|
+
maxSourceBalance: derived.maxSourceBalance,
|
|
20670
|
+
tokenCount: derived.tokenCount,
|
|
20671
|
+
selectedAccount: derived.selectedAccount,
|
|
20672
|
+
selectedSource: derived.selectedSource,
|
|
20673
|
+
selectSourceChoices: sourceSelection.selectSourceChoices,
|
|
20674
|
+
selectSourceRecommended: sourceSelection.selectSourceRecommended,
|
|
20675
|
+
selectSourceAvailableBalance: sourceSelection.selectSourceAvailableBalance
|
|
20676
|
+
},
|
|
20677
|
+
forms: {
|
|
20678
|
+
selectSourceChainName: sourceSelection.selectSourceChainName,
|
|
20679
|
+
selectSourceTokenSymbol: sourceSelection.selectSourceTokenSymbol,
|
|
20680
|
+
savingOneTapLimit: oneTapSetup.savingOneTapLimit,
|
|
20681
|
+
depositQuoteId: depositFee.quoteId,
|
|
20682
|
+
depositQuoteFee: depositFee.quoteFee,
|
|
20683
|
+
depositQuoteLoading: depositFee.quoteLoading,
|
|
20684
|
+
depositQuoteError: depositFee.quoteError
|
|
20685
|
+
},
|
|
20686
|
+
handlers
|
|
20687
|
+
}
|
|
20688
|
+
)
|
|
20515
20689
|
}
|
|
20516
20690
|
) });
|
|
20517
20691
|
}
|