@swype-org/react-sdk 0.1.218 → 0.1.220
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 +792 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +76 -4
- package/dist/index.d.ts +76 -4
- package/dist/index.js +793 -17
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -9,6 +9,7 @@ var reactQuery = require('@tanstack/react-query');
|
|
|
9
9
|
var jsxRuntime = require('react/jsx-runtime');
|
|
10
10
|
var viem = require('viem');
|
|
11
11
|
var utils = require('viem/utils');
|
|
12
|
+
var actions = require('viem/actions');
|
|
12
13
|
|
|
13
14
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
14
15
|
var __defProp = Object.defineProperty;
|
|
@@ -157,6 +158,17 @@ function useBlinkDepositAmount() {
|
|
|
157
158
|
};
|
|
158
159
|
}
|
|
159
160
|
|
|
161
|
+
// node_modules/@wagmi/core/dist/esm/utils/getAction.js
|
|
162
|
+
function getAction(client, actionFn, name) {
|
|
163
|
+
const action_implicit = client[actionFn.name];
|
|
164
|
+
if (typeof action_implicit === "function")
|
|
165
|
+
return action_implicit;
|
|
166
|
+
const action_explicit = client[name];
|
|
167
|
+
if (typeof action_explicit === "function")
|
|
168
|
+
return action_explicit;
|
|
169
|
+
return (params) => actionFn(client, params);
|
|
170
|
+
}
|
|
171
|
+
|
|
160
172
|
// node_modules/@wagmi/core/dist/esm/version.js
|
|
161
173
|
var version = "2.22.1";
|
|
162
174
|
|
|
@@ -416,24 +428,57 @@ async function getWalletClient(config, parameters = {}) {
|
|
|
416
428
|
const client = await getConnectorClient(config, parameters);
|
|
417
429
|
return client.extend(viem.walletActions);
|
|
418
430
|
}
|
|
431
|
+
async function waitForTransactionReceipt(config, parameters) {
|
|
432
|
+
const { chainId, timeout = 0, ...rest } = parameters;
|
|
433
|
+
const client = config.getClient({ chainId });
|
|
434
|
+
const action = getAction(client, actions.waitForTransactionReceipt, "waitForTransactionReceipt");
|
|
435
|
+
const receipt = await action({ ...rest, timeout });
|
|
436
|
+
if (receipt.status === "reverted") {
|
|
437
|
+
const action_getTransaction = getAction(client, actions.getTransaction, "getTransaction");
|
|
438
|
+
const { from: account, ...txn } = await action_getTransaction({
|
|
439
|
+
hash: receipt.transactionHash
|
|
440
|
+
});
|
|
441
|
+
const action_call = getAction(client, actions.call, "call");
|
|
442
|
+
const code = await action_call({
|
|
443
|
+
...txn,
|
|
444
|
+
account,
|
|
445
|
+
data: txn.input,
|
|
446
|
+
gasPrice: txn.type !== "eip1559" ? txn.gasPrice : void 0,
|
|
447
|
+
maxFeePerGas: txn.type === "eip1559" ? txn.maxFeePerGas : void 0,
|
|
448
|
+
maxPriorityFeePerGas: txn.type === "eip1559" ? txn.maxPriorityFeePerGas : void 0
|
|
449
|
+
});
|
|
450
|
+
const reason = code?.data ? viem.hexToString(`0x${code.data.substring(138)}`) : "unknown reason";
|
|
451
|
+
throw new Error(reason);
|
|
452
|
+
}
|
|
453
|
+
return {
|
|
454
|
+
...receipt,
|
|
455
|
+
chainId: client.chain.id
|
|
456
|
+
};
|
|
457
|
+
}
|
|
419
458
|
|
|
420
459
|
// src/api.ts
|
|
421
460
|
var api_exports = {};
|
|
422
461
|
__export(api_exports, {
|
|
423
462
|
createAccount: () => createAccount,
|
|
424
463
|
createAccountAuthorizationSession: () => createAccountAuthorizationSession,
|
|
464
|
+
createGuestTransfer: () => createGuestTransfer,
|
|
425
465
|
createTransfer: () => createTransfer,
|
|
426
466
|
fetchAccount: () => fetchAccount,
|
|
427
467
|
fetchAccounts: () => fetchAccounts,
|
|
428
468
|
fetchAuthorizationSession: () => fetchAuthorizationSession,
|
|
429
469
|
fetchChains: () => fetchChains,
|
|
470
|
+
fetchGuestTransferBalances: () => fetchGuestTransferBalances,
|
|
430
471
|
fetchMerchantPublicKey: () => fetchMerchantPublicKey,
|
|
431
472
|
fetchProviders: () => fetchProviders,
|
|
432
473
|
fetchTransfer: () => fetchTransfer,
|
|
433
474
|
fetchUserConfig: () => fetchUserConfig,
|
|
475
|
+
getGuestTransfer: () => getGuestTransfer,
|
|
476
|
+
getTransferByGuestToken: () => getTransferByGuestToken,
|
|
434
477
|
registerPasskey: () => registerPasskey,
|
|
435
478
|
reportActionCompletion: () => reportActionCompletion,
|
|
436
479
|
reportPasskeyActivity: () => reportPasskeyActivity,
|
|
480
|
+
setTransferSender: () => setTransferSender,
|
|
481
|
+
signGuestTransfer: () => signGuestTransfer,
|
|
437
482
|
signTransfer: () => signTransfer,
|
|
438
483
|
updateUserConfig: () => updateUserConfig,
|
|
439
484
|
updateUserConfigBySession: () => updateUserConfigBySession
|
|
@@ -446,9 +491,11 @@ async function throwApiError(res) {
|
|
|
446
491
|
throw new Error(`${res.status} \u2014 ${code}: ${msg}`);
|
|
447
492
|
}
|
|
448
493
|
async function fetchProviders(apiBaseUrl, token) {
|
|
449
|
-
const
|
|
450
|
-
|
|
451
|
-
|
|
494
|
+
const headers = {};
|
|
495
|
+
if (token) {
|
|
496
|
+
headers.Authorization = `Bearer ${token}`;
|
|
497
|
+
}
|
|
498
|
+
const res = await fetch(`${apiBaseUrl}/v1/providers`, { headers });
|
|
452
499
|
if (!res.ok) await throwApiError(res);
|
|
453
500
|
const data = await res.json();
|
|
454
501
|
return data.items;
|
|
@@ -646,6 +693,79 @@ async function updateUserConfigBySession(apiBaseUrl, sessionId, config) {
|
|
|
646
693
|
);
|
|
647
694
|
if (!res.ok) await throwApiError(res);
|
|
648
695
|
}
|
|
696
|
+
async function createGuestTransfer(apiBaseUrl, params) {
|
|
697
|
+
const body = {
|
|
698
|
+
id: params.id ?? crypto.randomUUID(),
|
|
699
|
+
type: "guest",
|
|
700
|
+
merchantAuthorization: params.merchantAuthorization,
|
|
701
|
+
destinations: params.destinations,
|
|
702
|
+
amount: {
|
|
703
|
+
amount: params.amount,
|
|
704
|
+
currency: params.currency ?? "USD"
|
|
705
|
+
},
|
|
706
|
+
providerId: params.providerId
|
|
707
|
+
};
|
|
708
|
+
const res = await fetch(`${apiBaseUrl}/v1/transfers`, {
|
|
709
|
+
method: "POST",
|
|
710
|
+
headers: { "Content-Type": "application/json" },
|
|
711
|
+
body: JSON.stringify(body)
|
|
712
|
+
});
|
|
713
|
+
if (!res.ok) await throwApiError(res);
|
|
714
|
+
return await res.json();
|
|
715
|
+
}
|
|
716
|
+
async function getTransferByGuestToken(apiBaseUrl, guestToken) {
|
|
717
|
+
const params = new URLSearchParams({ guestToken });
|
|
718
|
+
const res = await fetch(`${apiBaseUrl}/v1/transfers?${params.toString()}`);
|
|
719
|
+
if (!res.ok) await throwApiError(res);
|
|
720
|
+
return await res.json();
|
|
721
|
+
}
|
|
722
|
+
async function setTransferSender(apiBaseUrl, transferId, guestSessionToken, senderAddress, sourceChainId, sourceToken) {
|
|
723
|
+
const res = await fetch(`${apiBaseUrl}/v1/transfers/${transferId}/sender`, {
|
|
724
|
+
method: "PUT",
|
|
725
|
+
headers: {
|
|
726
|
+
"Content-Type": "application/json",
|
|
727
|
+
"x-guest-session-token": guestSessionToken
|
|
728
|
+
},
|
|
729
|
+
body: JSON.stringify({ senderAddress, sourceChainId, sourceToken })
|
|
730
|
+
});
|
|
731
|
+
if (!res.ok) await throwApiError(res);
|
|
732
|
+
return await res.json();
|
|
733
|
+
}
|
|
734
|
+
async function signGuestTransfer(apiBaseUrl, transferId, guestSessionToken, originTxHash) {
|
|
735
|
+
const res = await fetch(`${apiBaseUrl}/v1/transfers/${transferId}`, {
|
|
736
|
+
method: "PATCH",
|
|
737
|
+
headers: {
|
|
738
|
+
"Content-Type": "application/json",
|
|
739
|
+
"x-guest-session-token": guestSessionToken
|
|
740
|
+
},
|
|
741
|
+
body: JSON.stringify({ originTxHash })
|
|
742
|
+
});
|
|
743
|
+
if (!res.ok) await throwApiError(res);
|
|
744
|
+
return await res.json();
|
|
745
|
+
}
|
|
746
|
+
async function getGuestTransfer(apiBaseUrl, transferId, guestSessionToken) {
|
|
747
|
+
const res = await fetch(`${apiBaseUrl}/v1/transfers/${transferId}`, {
|
|
748
|
+
headers: {
|
|
749
|
+
"x-guest-session-token": guestSessionToken
|
|
750
|
+
}
|
|
751
|
+
});
|
|
752
|
+
if (!res.ok) await throwApiError(res);
|
|
753
|
+
return await res.json();
|
|
754
|
+
}
|
|
755
|
+
async function fetchGuestTransferBalances(apiBaseUrl, transferId, guestSessionToken, walletAddress) {
|
|
756
|
+
const params = new URLSearchParams({ walletAddress });
|
|
757
|
+
const res = await fetch(
|
|
758
|
+
`${apiBaseUrl}/v1/transfers/${transferId}/balances?${params.toString()}`,
|
|
759
|
+
{
|
|
760
|
+
headers: {
|
|
761
|
+
"x-guest-session-token": guestSessionToken
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
);
|
|
765
|
+
if (!res.ok) await throwApiError(res);
|
|
766
|
+
const data = await res.json();
|
|
767
|
+
return data.items;
|
|
768
|
+
}
|
|
649
769
|
async function reportActionCompletion(apiBaseUrl, actionId, result) {
|
|
650
770
|
const res = await fetch(
|
|
651
771
|
`${apiBaseUrl}/v1/authorization-actions/${actionId}`,
|
|
@@ -1792,8 +1912,9 @@ function deriveSourceTypeAndId(state) {
|
|
|
1792
1912
|
return { sourceType: "accountId", sourceId: "" };
|
|
1793
1913
|
}
|
|
1794
1914
|
function createInitialState(config) {
|
|
1915
|
+
const isReturningUser = config.activeCredentialId != null;
|
|
1795
1916
|
return {
|
|
1796
|
-
step: "login",
|
|
1917
|
+
step: isReturningUser ? "login" : "wallet-picker",
|
|
1797
1918
|
error: null,
|
|
1798
1919
|
providers: [],
|
|
1799
1920
|
accounts: [],
|
|
@@ -1816,7 +1937,10 @@ function createInitialState(config) {
|
|
|
1816
1937
|
mobileFlow: false,
|
|
1817
1938
|
deeplinkUri: null,
|
|
1818
1939
|
increasingLimit: false,
|
|
1819
|
-
previousStep: null
|
|
1940
|
+
previousStep: null,
|
|
1941
|
+
isGuestFlow: false,
|
|
1942
|
+
guestTransferId: null,
|
|
1943
|
+
guestSessionToken: null
|
|
1820
1944
|
};
|
|
1821
1945
|
}
|
|
1822
1946
|
function paymentReducer(state, action) {
|
|
@@ -2039,6 +2163,27 @@ function paymentReducer(state, action) {
|
|
|
2039
2163
|
mobileFlow: true,
|
|
2040
2164
|
deeplinkUri: action.deeplinkUri
|
|
2041
2165
|
};
|
|
2166
|
+
// ── Guest checkout ────────────────────────────────────────────
|
|
2167
|
+
case "GUEST_PROVIDER_SELECTED":
|
|
2168
|
+
return {
|
|
2169
|
+
...state,
|
|
2170
|
+
isGuestFlow: true,
|
|
2171
|
+
selectedProviderId: action.providerId,
|
|
2172
|
+
guestTransferId: action.transferId,
|
|
2173
|
+
guestSessionToken: action.guestSessionToken,
|
|
2174
|
+
selectedAccountId: null,
|
|
2175
|
+
selectedWalletId: null,
|
|
2176
|
+
selectedTokenSymbol: null,
|
|
2177
|
+
step: "token-picker"
|
|
2178
|
+
};
|
|
2179
|
+
case "GUEST_TRANSFER_COMPLETED":
|
|
2180
|
+
return {
|
|
2181
|
+
...state,
|
|
2182
|
+
transfer: action.transfer,
|
|
2183
|
+
step: "success",
|
|
2184
|
+
mobileFlow: false,
|
|
2185
|
+
deeplinkUri: null
|
|
2186
|
+
};
|
|
2042
2187
|
// ── Navigation & error ───────────────────────────────────────
|
|
2043
2188
|
case "NAVIGATE":
|
|
2044
2189
|
return { ...state, step: action.step, previousStep: state.step, error: null };
|
|
@@ -2048,7 +2193,7 @@ function paymentReducer(state, action) {
|
|
|
2048
2193
|
case "NEW_PAYMENT":
|
|
2049
2194
|
return {
|
|
2050
2195
|
...state,
|
|
2051
|
-
step: "deposit",
|
|
2196
|
+
step: state.isGuestFlow ? "wallet-picker" : "deposit",
|
|
2052
2197
|
transfer: null,
|
|
2053
2198
|
error: null,
|
|
2054
2199
|
amount: action.depositAmount != null ? action.depositAmount.toString() : "",
|
|
@@ -2056,7 +2201,10 @@ function paymentReducer(state, action) {
|
|
|
2056
2201
|
deeplinkUri: null,
|
|
2057
2202
|
selectedProviderId: null,
|
|
2058
2203
|
selectedWalletId: null,
|
|
2059
|
-
selectedAccountId: action.firstAccountId
|
|
2204
|
+
selectedAccountId: action.firstAccountId,
|
|
2205
|
+
isGuestFlow: false,
|
|
2206
|
+
guestTransferId: null,
|
|
2207
|
+
guestSessionToken: null
|
|
2060
2208
|
};
|
|
2061
2209
|
case "LOGOUT":
|
|
2062
2210
|
return {
|
|
@@ -3239,7 +3387,9 @@ function WalletPickerScreen({
|
|
|
3239
3387
|
onSelectProvider,
|
|
3240
3388
|
onContinueConnection,
|
|
3241
3389
|
onBack,
|
|
3242
|
-
onLogout
|
|
3390
|
+
onLogout,
|
|
3391
|
+
onLogin,
|
|
3392
|
+
showLoginOption
|
|
3243
3393
|
}) {
|
|
3244
3394
|
const { tokens } = useBlinkConfig();
|
|
3245
3395
|
const [hoveredId, setHoveredId] = react.useState(null);
|
|
@@ -3394,6 +3544,18 @@ function WalletPickerScreen({
|
|
|
3394
3544
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: categoryRowStyle(tokens, false, true), children: [
|
|
3395
3545
|
/* @__PURE__ */ jsxRuntime.jsx("span", { style: categoryLabelStyle, children: "Bank Account" }),
|
|
3396
3546
|
/* @__PURE__ */ jsxRuntime.jsx("span", { style: comingSoonBadgeStyle(tokens), children: "Coming Soon" })
|
|
3547
|
+
] }),
|
|
3548
|
+
showLoginOption && onLogin && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: loginOptionStyle, children: [
|
|
3549
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: loginTextStyle(tokens.textSecondary), children: "Already have an account?" }),
|
|
3550
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3551
|
+
"button",
|
|
3552
|
+
{
|
|
3553
|
+
type: "button",
|
|
3554
|
+
onClick: onLogin,
|
|
3555
|
+
style: loginButtonStyle(tokens.accent),
|
|
3556
|
+
children: "Log in"
|
|
3557
|
+
}
|
|
3558
|
+
)
|
|
3397
3559
|
] })
|
|
3398
3560
|
]
|
|
3399
3561
|
}
|
|
@@ -3560,6 +3722,28 @@ var dividerTextStyle = (color) => ({
|
|
|
3560
3722
|
color,
|
|
3561
3723
|
whiteSpace: "nowrap"
|
|
3562
3724
|
});
|
|
3725
|
+
var loginOptionStyle = {
|
|
3726
|
+
display: "flex",
|
|
3727
|
+
alignItems: "center",
|
|
3728
|
+
justifyContent: "center",
|
|
3729
|
+
gap: 6,
|
|
3730
|
+
padding: "12px 0 4px"
|
|
3731
|
+
};
|
|
3732
|
+
var loginTextStyle = (color) => ({
|
|
3733
|
+
fontSize: "0.85rem",
|
|
3734
|
+
color
|
|
3735
|
+
});
|
|
3736
|
+
var loginButtonStyle = (accentColor) => ({
|
|
3737
|
+
fontSize: "0.85rem",
|
|
3738
|
+
fontWeight: 600,
|
|
3739
|
+
color: accentColor,
|
|
3740
|
+
background: "none",
|
|
3741
|
+
border: "none",
|
|
3742
|
+
cursor: "pointer",
|
|
3743
|
+
padding: 0,
|
|
3744
|
+
fontFamily: "inherit",
|
|
3745
|
+
textDecoration: "underline"
|
|
3746
|
+
});
|
|
3563
3747
|
var DEFAULT_MAX = 1e7;
|
|
3564
3748
|
var ABSOLUTE_MIN = 0.01;
|
|
3565
3749
|
var PRESETS = [100, 250, 1e3];
|
|
@@ -5397,6 +5581,179 @@ var selectCircleSelectedStyle = (color) => ({
|
|
|
5397
5581
|
justifyContent: "center",
|
|
5398
5582
|
flexShrink: 0
|
|
5399
5583
|
});
|
|
5584
|
+
function GuestTokenPickerScreen({
|
|
5585
|
+
entries,
|
|
5586
|
+
loading,
|
|
5587
|
+
setting,
|
|
5588
|
+
depositAmount,
|
|
5589
|
+
error,
|
|
5590
|
+
onSelect,
|
|
5591
|
+
onBack
|
|
5592
|
+
}) {
|
|
5593
|
+
const { tokens: t } = useBlinkConfig();
|
|
5594
|
+
if (loading) {
|
|
5595
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(ScreenLayout, { children: [
|
|
5596
|
+
/* @__PURE__ */ jsxRuntime.jsx(ScreenHeader, { title: "Select Token", onBack }),
|
|
5597
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: loadingWrapStyle, children: /* @__PURE__ */ jsxRuntime.jsx(Spinner, { label: "Loading balances..." }) })
|
|
5598
|
+
] });
|
|
5599
|
+
}
|
|
5600
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(ScreenLayout, { footer: /* @__PURE__ */ jsxRuntime.jsx(PoweredByFooter, {}), children: [
|
|
5601
|
+
/* @__PURE__ */ jsxRuntime.jsx(ScreenHeader, { title: "Select Token", onBack }),
|
|
5602
|
+
depositAmount != null && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: depositHeaderStyle, children: [
|
|
5603
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: depositLabelStyle3(t.textMuted), children: "Depositing" }),
|
|
5604
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: depositAmountStyle2(t.text), children: [
|
|
5605
|
+
"$",
|
|
5606
|
+
depositAmount.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })
|
|
5607
|
+
] })
|
|
5608
|
+
] }),
|
|
5609
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("p", { style: errorStyle3(t.error), children: error }),
|
|
5610
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: sectionLabelStyle2(t.textMuted), children: "Choose token to pay with" }),
|
|
5611
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: tokenListStyle3, children: entries.map((entry) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5612
|
+
"button",
|
|
5613
|
+
{
|
|
5614
|
+
type: "button",
|
|
5615
|
+
onClick: () => onSelect(entry),
|
|
5616
|
+
disabled: setting,
|
|
5617
|
+
style: tokenRowStyle3(t, setting),
|
|
5618
|
+
children: [
|
|
5619
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: tokenIconCircleStyle3(t, !!TOKEN_LOGOS[entry.tokenSymbol]), children: TOKEN_LOGOS[entry.tokenSymbol] ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: TOKEN_LOGOS[entry.tokenSymbol], alt: entry.tokenSymbol, style: tokenLogoImgStyle3 }) : /* @__PURE__ */ jsxRuntime.jsx("span", { style: tokenIconTextStyle3(t.textMuted), children: "$" }) }),
|
|
5620
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: tokenInfoStyle3, children: [
|
|
5621
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: tokenNameRowStyle2, children: [
|
|
5622
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: tokenSymbolTextStyle2(t.text), children: entry.tokenSymbol }),
|
|
5623
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: tokenChainDotStyle2(t.textMuted), children: "\xB7" }),
|
|
5624
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: tokenChainTextStyle2(t.textMuted), children: entry.chainName })
|
|
5625
|
+
] }),
|
|
5626
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { style: tokenBalanceStyle2(t.textMuted), children: [
|
|
5627
|
+
"$",
|
|
5628
|
+
entry.balance.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })
|
|
5629
|
+
] })
|
|
5630
|
+
] }),
|
|
5631
|
+
/* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", style: chevronStyle, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z", fill: t.textMuted }) })
|
|
5632
|
+
]
|
|
5633
|
+
},
|
|
5634
|
+
`${entry.chainId}-${entry.tokenAddress}`
|
|
5635
|
+
)) }),
|
|
5636
|
+
entries.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { style: emptyStyle(t.textMuted), children: "No supported tokens found in your wallet. Please ensure you have USDC or USDT." })
|
|
5637
|
+
] });
|
|
5638
|
+
}
|
|
5639
|
+
var loadingWrapStyle = {
|
|
5640
|
+
textAlign: "center",
|
|
5641
|
+
padding: "48px 0",
|
|
5642
|
+
flex: 1,
|
|
5643
|
+
display: "flex",
|
|
5644
|
+
alignItems: "center",
|
|
5645
|
+
justifyContent: "center"
|
|
5646
|
+
};
|
|
5647
|
+
var depositHeaderStyle = {
|
|
5648
|
+
marginBottom: 20
|
|
5649
|
+
};
|
|
5650
|
+
var depositLabelStyle3 = (color) => ({
|
|
5651
|
+
fontSize: "0.75rem",
|
|
5652
|
+
fontWeight: 500,
|
|
5653
|
+
color,
|
|
5654
|
+
marginBottom: 4
|
|
5655
|
+
});
|
|
5656
|
+
var depositAmountStyle2 = (color) => ({
|
|
5657
|
+
fontSize: "2.4rem",
|
|
5658
|
+
fontWeight: 700,
|
|
5659
|
+
letterSpacing: "-0.02em",
|
|
5660
|
+
color
|
|
5661
|
+
});
|
|
5662
|
+
var errorStyle3 = (color) => ({
|
|
5663
|
+
fontSize: "0.84rem",
|
|
5664
|
+
color,
|
|
5665
|
+
margin: "0 0 12px",
|
|
5666
|
+
lineHeight: 1.5
|
|
5667
|
+
});
|
|
5668
|
+
var sectionLabelStyle2 = (color) => ({
|
|
5669
|
+
fontSize: "0.84rem",
|
|
5670
|
+
fontWeight: 500,
|
|
5671
|
+
color,
|
|
5672
|
+
marginBottom: 12
|
|
5673
|
+
});
|
|
5674
|
+
var tokenListStyle3 = {
|
|
5675
|
+
display: "flex",
|
|
5676
|
+
flexDirection: "column",
|
|
5677
|
+
gap: 10
|
|
5678
|
+
};
|
|
5679
|
+
var tokenRowStyle3 = (tokens, disabled) => ({
|
|
5680
|
+
display: "flex",
|
|
5681
|
+
alignItems: "center",
|
|
5682
|
+
gap: 14,
|
|
5683
|
+
padding: "14px 16px",
|
|
5684
|
+
background: tokens.bgInput,
|
|
5685
|
+
border: `1px solid ${tokens.border}`,
|
|
5686
|
+
borderRadius: 16,
|
|
5687
|
+
cursor: disabled ? "default" : "pointer",
|
|
5688
|
+
fontFamily: "inherit",
|
|
5689
|
+
textAlign: "left",
|
|
5690
|
+
width: "100%",
|
|
5691
|
+
opacity: disabled ? 0.6 : 1,
|
|
5692
|
+
transition: "opacity 0.15s ease"
|
|
5693
|
+
});
|
|
5694
|
+
var tokenIconCircleStyle3 = (tokens, hasLogo) => ({
|
|
5695
|
+
width: 36,
|
|
5696
|
+
height: 36,
|
|
5697
|
+
borderRadius: "50%",
|
|
5698
|
+
border: hasLogo ? "none" : `1.5px solid ${tokens.border}`,
|
|
5699
|
+
display: "flex",
|
|
5700
|
+
alignItems: "center",
|
|
5701
|
+
justifyContent: "center",
|
|
5702
|
+
flexShrink: 0,
|
|
5703
|
+
overflow: "hidden"
|
|
5704
|
+
});
|
|
5705
|
+
var tokenLogoImgStyle3 = {
|
|
5706
|
+
width: 36,
|
|
5707
|
+
height: 36,
|
|
5708
|
+
borderRadius: "50%",
|
|
5709
|
+
objectFit: "cover"
|
|
5710
|
+
};
|
|
5711
|
+
var tokenIconTextStyle3 = (color) => ({
|
|
5712
|
+
fontSize: "1rem",
|
|
5713
|
+
fontWeight: 700,
|
|
5714
|
+
color
|
|
5715
|
+
});
|
|
5716
|
+
var tokenInfoStyle3 = {
|
|
5717
|
+
display: "flex",
|
|
5718
|
+
flexDirection: "column",
|
|
5719
|
+
gap: 2,
|
|
5720
|
+
flex: 1,
|
|
5721
|
+
minWidth: 0
|
|
5722
|
+
};
|
|
5723
|
+
var tokenNameRowStyle2 = {
|
|
5724
|
+
display: "flex",
|
|
5725
|
+
alignItems: "center",
|
|
5726
|
+
gap: 4
|
|
5727
|
+
};
|
|
5728
|
+
var tokenSymbolTextStyle2 = (color) => ({
|
|
5729
|
+
fontSize: "0.92rem",
|
|
5730
|
+
fontWeight: 600,
|
|
5731
|
+
color
|
|
5732
|
+
});
|
|
5733
|
+
var tokenChainDotStyle2 = (color) => ({
|
|
5734
|
+
fontSize: "0.8rem",
|
|
5735
|
+
color
|
|
5736
|
+
});
|
|
5737
|
+
var tokenChainTextStyle2 = (color) => ({
|
|
5738
|
+
fontSize: "0.84rem",
|
|
5739
|
+
fontWeight: 400,
|
|
5740
|
+
color
|
|
5741
|
+
});
|
|
5742
|
+
var tokenBalanceStyle2 = (color) => ({
|
|
5743
|
+
fontSize: "0.78rem",
|
|
5744
|
+
color
|
|
5745
|
+
});
|
|
5746
|
+
var chevronStyle = {
|
|
5747
|
+
flexShrink: 0,
|
|
5748
|
+
opacity: 0.4
|
|
5749
|
+
};
|
|
5750
|
+
var emptyStyle = (color) => ({
|
|
5751
|
+
fontSize: "0.88rem",
|
|
5752
|
+
color,
|
|
5753
|
+
textAlign: "center",
|
|
5754
|
+
padding: "32px 0",
|
|
5755
|
+
lineHeight: 1.5
|
|
5756
|
+
});
|
|
5400
5757
|
var LINK_STEPS = /* @__PURE__ */ new Set([
|
|
5401
5758
|
"create-passkey",
|
|
5402
5759
|
"verify-passkey",
|
|
@@ -5444,6 +5801,9 @@ function StepRendererContent({
|
|
|
5444
5801
|
selectSourceChoices,
|
|
5445
5802
|
selectSourceRecommended,
|
|
5446
5803
|
selectSourceAvailableBalance,
|
|
5804
|
+
guestTokenEntries,
|
|
5805
|
+
guestLoadingBalances,
|
|
5806
|
+
guestSettingSender,
|
|
5447
5807
|
authInput,
|
|
5448
5808
|
otpCode,
|
|
5449
5809
|
selectSourceChainName,
|
|
@@ -5525,6 +5885,7 @@ function StepRendererContent({
|
|
|
5525
5885
|
);
|
|
5526
5886
|
}
|
|
5527
5887
|
if (step === "wallet-picker") {
|
|
5888
|
+
const isEntryPoint = !state.isGuestFlow && !authenticated;
|
|
5528
5889
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5529
5890
|
WalletPickerScreen,
|
|
5530
5891
|
{
|
|
@@ -5537,8 +5898,10 @@ function StepRendererContent({
|
|
|
5537
5898
|
onPrepareProvider: handlers.onPrepareProvider,
|
|
5538
5899
|
onSelectProvider: handlers.onSelectProvider,
|
|
5539
5900
|
onContinueConnection: handlers.onContinueConnection,
|
|
5540
|
-
onBack: () => handlers.onNavigate(state.activeCredentialId ? "deposit" : "create-passkey"),
|
|
5541
|
-
onLogout: handlers.onLogout
|
|
5901
|
+
onBack: isEntryPoint ? onBack : () => handlers.onNavigate(state.activeCredentialId ? "deposit" : "create-passkey"),
|
|
5902
|
+
onLogout: authenticated ? handlers.onLogout : void 0,
|
|
5903
|
+
onLogin: handlers.onLogin,
|
|
5904
|
+
showLoginOption: isEntryPoint
|
|
5542
5905
|
}
|
|
5543
5906
|
);
|
|
5544
5907
|
}
|
|
@@ -5645,6 +6008,20 @@ function StepRendererContent({
|
|
|
5645
6008
|
);
|
|
5646
6009
|
}
|
|
5647
6010
|
if (step === "token-picker") {
|
|
6011
|
+
if (state.isGuestFlow) {
|
|
6012
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
6013
|
+
GuestTokenPickerScreen,
|
|
6014
|
+
{
|
|
6015
|
+
entries: guestTokenEntries,
|
|
6016
|
+
loading: guestLoadingBalances,
|
|
6017
|
+
setting: guestSettingSender,
|
|
6018
|
+
depositAmount: depositAmount ?? void 0,
|
|
6019
|
+
error: state.error,
|
|
6020
|
+
onSelect: handlers.onSelectGuestToken,
|
|
6021
|
+
onBack: () => handlers.onNavigate("wallet-picker")
|
|
6022
|
+
}
|
|
6023
|
+
);
|
|
6024
|
+
}
|
|
5648
6025
|
if (!selectedAccount) {
|
|
5649
6026
|
return /* @__PURE__ */ jsxRuntime.jsx(BlinkLoadingScreen, {});
|
|
5650
6027
|
}
|
|
@@ -6400,12 +6777,68 @@ function useSourceSelectionHandlers(dispatch, authExecutor) {
|
|
|
6400
6777
|
preSelectSourceStepRef
|
|
6401
6778
|
};
|
|
6402
6779
|
}
|
|
6403
|
-
function useMobileFlowHandlers(dispatch, polling, reloadAccounts, pollingTransferIdRef, stateTransfer, refs) {
|
|
6780
|
+
function useMobileFlowHandlers(dispatch, polling, reloadAccounts, pollingTransferIdRef, stateTransfer, refs, onComplete) {
|
|
6404
6781
|
const {
|
|
6405
6782
|
mobileSetupFlowRef,
|
|
6406
6783
|
handlingMobileReturnRef,
|
|
6407
6784
|
loadingDataRef
|
|
6408
6785
|
} = refs;
|
|
6786
|
+
const { apiBaseUrl } = useBlinkConfig();
|
|
6787
|
+
const onCompleteRef = react.useRef(onComplete);
|
|
6788
|
+
onCompleteRef.current = onComplete;
|
|
6789
|
+
const guestPollingActiveRef = react.useRef(false);
|
|
6790
|
+
react.useEffect(() => {
|
|
6791
|
+
const persisted = loadMobileFlowState();
|
|
6792
|
+
if (!persisted?.isGuestCheckout || !persisted.transferId || !persisted.guestSessionToken) return;
|
|
6793
|
+
if (guestPollingActiveRef.current) return;
|
|
6794
|
+
guestPollingActiveRef.current = true;
|
|
6795
|
+
const transferId = persisted.transferId;
|
|
6796
|
+
const guestSessionToken = persisted.guestSessionToken;
|
|
6797
|
+
let cancelled = false;
|
|
6798
|
+
const POLL_INTERVAL_MS = 3e3;
|
|
6799
|
+
dispatch({ type: "NAVIGATE", step: "processing" });
|
|
6800
|
+
const poll = async () => {
|
|
6801
|
+
if (cancelled) return;
|
|
6802
|
+
try {
|
|
6803
|
+
const transfer = await getGuestTransfer(apiBaseUrl, transferId, guestSessionToken);
|
|
6804
|
+
if (cancelled) return;
|
|
6805
|
+
if (transfer.status === "COMPLETED") {
|
|
6806
|
+
cancelled = true;
|
|
6807
|
+
guestPollingActiveRef.current = false;
|
|
6808
|
+
clearMobileFlowState();
|
|
6809
|
+
dispatch({ type: "GUEST_TRANSFER_COMPLETED", transfer });
|
|
6810
|
+
onCompleteRef.current?.(transfer);
|
|
6811
|
+
} else if (transfer.status === "FAILED") {
|
|
6812
|
+
cancelled = true;
|
|
6813
|
+
guestPollingActiveRef.current = false;
|
|
6814
|
+
clearMobileFlowState();
|
|
6815
|
+
dispatch({ type: "TRANSFER_FAILED", transfer, error: "Transfer failed." });
|
|
6816
|
+
}
|
|
6817
|
+
} catch {
|
|
6818
|
+
}
|
|
6819
|
+
};
|
|
6820
|
+
poll();
|
|
6821
|
+
const intervalId = window.setInterval(poll, POLL_INTERVAL_MS);
|
|
6822
|
+
const handleVisibility = () => {
|
|
6823
|
+
if (document.visibilityState === "visible" && !cancelled) {
|
|
6824
|
+
poll();
|
|
6825
|
+
}
|
|
6826
|
+
};
|
|
6827
|
+
const handlePageShow = (e) => {
|
|
6828
|
+
if (e.persisted && !cancelled) {
|
|
6829
|
+
poll();
|
|
6830
|
+
}
|
|
6831
|
+
};
|
|
6832
|
+
document.addEventListener("visibilitychange", handleVisibility);
|
|
6833
|
+
window.addEventListener("pageshow", handlePageShow);
|
|
6834
|
+
return () => {
|
|
6835
|
+
cancelled = true;
|
|
6836
|
+
guestPollingActiveRef.current = false;
|
|
6837
|
+
window.clearInterval(intervalId);
|
|
6838
|
+
document.removeEventListener("visibilitychange", handleVisibility);
|
|
6839
|
+
window.removeEventListener("pageshow", handlePageShow);
|
|
6840
|
+
};
|
|
6841
|
+
}, [apiBaseUrl, dispatch]);
|
|
6409
6842
|
const handleAuthorizedMobileReturn = react.useCallback(async (authorizedTransfer, isSetup) => {
|
|
6410
6843
|
if (handlingMobileReturnRef.current) return;
|
|
6411
6844
|
handlingMobileReturnRef.current = true;
|
|
@@ -6464,9 +6897,17 @@ function useProviderHandlers(deps) {
|
|
|
6464
6897
|
handlingMobileReturnRef,
|
|
6465
6898
|
setupAccountIdRef,
|
|
6466
6899
|
reauthSessionIdRef,
|
|
6467
|
-
reauthTokenRef
|
|
6900
|
+
reauthTokenRef,
|
|
6901
|
+
authenticated,
|
|
6902
|
+
merchantAuthorization,
|
|
6903
|
+
destination
|
|
6468
6904
|
} = deps;
|
|
6905
|
+
const wagmiConfig2 = wagmi.useConfig();
|
|
6906
|
+
const { connectAsync, connectors } = wagmi.useConnect();
|
|
6469
6907
|
const handlePrepareProvider = react.useCallback(async (providerId) => {
|
|
6908
|
+
if (!authenticated) {
|
|
6909
|
+
return null;
|
|
6910
|
+
}
|
|
6470
6911
|
if (!activeCredentialId) {
|
|
6471
6912
|
dispatch({ type: "SET_ERROR", error: "Create or verify a passkey on this device before continuing." });
|
|
6472
6913
|
dispatch({ type: "NAVIGATE", step: "create-passkey" });
|
|
@@ -6494,8 +6935,85 @@ function useProviderHandlers(deps) {
|
|
|
6494
6935
|
onError?.(msg);
|
|
6495
6936
|
return null;
|
|
6496
6937
|
}
|
|
6497
|
-
}, [activeCredentialId, providers, apiBaseUrl, getAccessToken, onError, dispatch]);
|
|
6938
|
+
}, [authenticated, activeCredentialId, providers, apiBaseUrl, getAccessToken, onError, dispatch]);
|
|
6939
|
+
const handleGuestSelectProvider = react.useCallback(async (providerId) => {
|
|
6940
|
+
if (!merchantAuthorization || !destination) {
|
|
6941
|
+
const msg = "Missing payment configuration for guest checkout.";
|
|
6942
|
+
dispatch({ type: "PAY_ERROR", error: msg, fallbackStep: "wallet-picker" });
|
|
6943
|
+
onError?.(msg);
|
|
6944
|
+
return;
|
|
6945
|
+
}
|
|
6946
|
+
const isMobile = !shouldUseWalletConnector({
|
|
6947
|
+
useWalletConnector: useWalletConnectorProp,
|
|
6948
|
+
userAgent: typeof navigator === "undefined" ? void 0 : navigator.userAgent
|
|
6949
|
+
});
|
|
6950
|
+
dispatch({ type: "SELECT_PROVIDER", providerId });
|
|
6951
|
+
try {
|
|
6952
|
+
const result = await createGuestTransfer(apiBaseUrl, {
|
|
6953
|
+
merchantAuthorization,
|
|
6954
|
+
destinations: [{
|
|
6955
|
+
chainId: destination.chainId,
|
|
6956
|
+
token: { address: destination.token.address },
|
|
6957
|
+
address: destination.address
|
|
6958
|
+
}],
|
|
6959
|
+
amount: depositAmount ?? 0,
|
|
6960
|
+
providerId
|
|
6961
|
+
});
|
|
6962
|
+
if (isMobile) {
|
|
6963
|
+
if (!result.uri) {
|
|
6964
|
+
dispatch({ type: "PAY_ERROR", error: "This wallet is not available on mobile.", fallbackStep: "wallet-picker" });
|
|
6965
|
+
return;
|
|
6966
|
+
}
|
|
6967
|
+
persistMobileFlowState({
|
|
6968
|
+
transferId: result.id,
|
|
6969
|
+
guestSessionToken: result.guestSessionToken,
|
|
6970
|
+
isGuestCheckout: true,
|
|
6971
|
+
deeplinkUri: result.uri,
|
|
6972
|
+
providerId,
|
|
6973
|
+
isSetup: false
|
|
6974
|
+
});
|
|
6975
|
+
triggerDeeplink(result.uri);
|
|
6976
|
+
dispatch({ type: "MOBILE_DEEPLINK_READY", deeplinkUri: result.uri });
|
|
6977
|
+
} else {
|
|
6978
|
+
const account = getAccount(wagmiConfig2);
|
|
6979
|
+
if (!account.isConnected) {
|
|
6980
|
+
const connector = connectors.find((c) => c.type === "injected") ?? connectors[0];
|
|
6981
|
+
if (!connector) {
|
|
6982
|
+
dispatch({ type: "PAY_ERROR", error: "No wallet extension found. Please install a supported wallet.", fallbackStep: "wallet-picker" });
|
|
6983
|
+
return;
|
|
6984
|
+
}
|
|
6985
|
+
await connectAsync({ connector });
|
|
6986
|
+
}
|
|
6987
|
+
dispatch({
|
|
6988
|
+
type: "GUEST_PROVIDER_SELECTED",
|
|
6989
|
+
providerId,
|
|
6990
|
+
transferId: result.id,
|
|
6991
|
+
guestSessionToken: result.guestSessionToken
|
|
6992
|
+
});
|
|
6993
|
+
}
|
|
6994
|
+
} catch (err) {
|
|
6995
|
+
captureException(err);
|
|
6996
|
+
const msg = err instanceof Error ? err.message : "Failed to start guest checkout";
|
|
6997
|
+
dispatch({ type: "PAY_ERROR", error: msg, fallbackStep: "wallet-picker" });
|
|
6998
|
+
onError?.(msg);
|
|
6999
|
+
}
|
|
7000
|
+
}, [
|
|
7001
|
+
merchantAuthorization,
|
|
7002
|
+
destination,
|
|
7003
|
+
apiBaseUrl,
|
|
7004
|
+
depositAmount,
|
|
7005
|
+
useWalletConnectorProp,
|
|
7006
|
+
wagmiConfig2,
|
|
7007
|
+
connectors,
|
|
7008
|
+
connectAsync,
|
|
7009
|
+
onError,
|
|
7010
|
+
dispatch
|
|
7011
|
+
]);
|
|
6498
7012
|
const handleSelectProvider = react.useCallback(async (providerId, preparedSession) => {
|
|
7013
|
+
if (!authenticated) {
|
|
7014
|
+
await handleGuestSelectProvider(providerId);
|
|
7015
|
+
return;
|
|
7016
|
+
}
|
|
6499
7017
|
dispatch({ type: "SELECT_PROVIDER", providerId });
|
|
6500
7018
|
if (!activeCredentialId) {
|
|
6501
7019
|
dispatch({ type: "SET_ERROR", error: "Create or verify a passkey on this device before continuing." });
|
|
@@ -6565,6 +7083,8 @@ function useProviderHandlers(deps) {
|
|
|
6565
7083
|
}
|
|
6566
7084
|
}
|
|
6567
7085
|
}, [
|
|
7086
|
+
authenticated,
|
|
7087
|
+
handleGuestSelectProvider,
|
|
6568
7088
|
activeCredentialId,
|
|
6569
7089
|
providers,
|
|
6570
7090
|
apiBaseUrl,
|
|
@@ -6800,6 +7320,217 @@ function useProviderHandlers(deps) {
|
|
|
6800
7320
|
handleAuthorizeToken
|
|
6801
7321
|
};
|
|
6802
7322
|
}
|
|
7323
|
+
|
|
7324
|
+
// src/guestTokens.ts
|
|
7325
|
+
function mapBalancesToGuestTokenEntries(options) {
|
|
7326
|
+
return options.map((opt) => ({
|
|
7327
|
+
chainId: opt.chainId,
|
|
7328
|
+
sourceChainId: opt.sourceChainId,
|
|
7329
|
+
chainName: opt.chainName,
|
|
7330
|
+
tokenSymbol: opt.tokenSymbol,
|
|
7331
|
+
tokenAddress: opt.tokenAddress,
|
|
7332
|
+
decimals: opt.decimals,
|
|
7333
|
+
rawBalance: opt.rawBalance,
|
|
7334
|
+
balance: Number(opt.rawBalance) / 10 ** opt.decimals
|
|
7335
|
+
})).filter((entry) => entry.balance > 0).sort((a, b) => b.balance - a.balance);
|
|
7336
|
+
}
|
|
7337
|
+
|
|
7338
|
+
// src/hooks/useGuestTransferHandlers.ts
|
|
7339
|
+
var GUEST_SIGN_POLL_MS = 2e3;
|
|
7340
|
+
var GUEST_SIGN_MAX_POLLS = 90;
|
|
7341
|
+
var GUEST_COMPLETION_POLL_MS = 3e3;
|
|
7342
|
+
var GUEST_COMPLETION_MAX_POLLS = 120;
|
|
7343
|
+
function isUserRejection2(msg) {
|
|
7344
|
+
const lower = msg.toLowerCase();
|
|
7345
|
+
return lower.includes("rejected") || lower.includes("denied") || lower.includes("cancelled");
|
|
7346
|
+
}
|
|
7347
|
+
function useGuestTransferHandlers(deps) {
|
|
7348
|
+
const {
|
|
7349
|
+
dispatch,
|
|
7350
|
+
isGuestFlow,
|
|
7351
|
+
guestTransferId,
|
|
7352
|
+
guestSessionToken,
|
|
7353
|
+
step,
|
|
7354
|
+
onComplete,
|
|
7355
|
+
onError
|
|
7356
|
+
} = deps;
|
|
7357
|
+
const { apiBaseUrl } = useBlinkConfig();
|
|
7358
|
+
const wagmiConfig2 = wagmi.useConfig();
|
|
7359
|
+
const { switchChainAsync } = wagmi.useSwitchChain();
|
|
7360
|
+
const [guestTokenEntries, setGuestTokenEntries] = react.useState([]);
|
|
7361
|
+
const [loadingBalances, setLoadingBalances] = react.useState(false);
|
|
7362
|
+
const [settingSender, setSettingSender] = react.useState(false);
|
|
7363
|
+
const executingBridgeRef = react.useRef(false);
|
|
7364
|
+
const fetchedRef = react.useRef(false);
|
|
7365
|
+
const selectedGuestTokenRef = react.useRef(null);
|
|
7366
|
+
react.useEffect(() => {
|
|
7367
|
+
if (!isGuestFlow || step !== "token-picker" || fetchedRef.current) return;
|
|
7368
|
+
if (!guestTransferId || !guestSessionToken) return;
|
|
7369
|
+
const account = getAccount(wagmiConfig2);
|
|
7370
|
+
if (!account.address) return;
|
|
7371
|
+
fetchedRef.current = true;
|
|
7372
|
+
setLoadingBalances(true);
|
|
7373
|
+
fetchGuestTransferBalances(apiBaseUrl, guestTransferId, guestSessionToken, account.address).then((options) => mapBalancesToGuestTokenEntries(options)).then((entries) => {
|
|
7374
|
+
setGuestTokenEntries(entries);
|
|
7375
|
+
if (entries.length === 0) {
|
|
7376
|
+
dispatch({ type: "SET_ERROR", error: "No supported tokens found in your wallet." });
|
|
7377
|
+
}
|
|
7378
|
+
}).catch((err) => {
|
|
7379
|
+
captureException(err);
|
|
7380
|
+
dispatch({ type: "SET_ERROR", error: "Failed to fetch token balances." });
|
|
7381
|
+
}).finally(() => setLoadingBalances(false));
|
|
7382
|
+
}, [isGuestFlow, step, guestTransferId, guestSessionToken, apiBaseUrl, wagmiConfig2, dispatch]);
|
|
7383
|
+
react.useEffect(() => {
|
|
7384
|
+
if (!isGuestFlow) {
|
|
7385
|
+
fetchedRef.current = false;
|
|
7386
|
+
selectedGuestTokenRef.current = null;
|
|
7387
|
+
setGuestTokenEntries([]);
|
|
7388
|
+
}
|
|
7389
|
+
}, [isGuestFlow]);
|
|
7390
|
+
const handleSelectGuestToken = react.useCallback(async (entry) => {
|
|
7391
|
+
if (!guestTransferId || !guestSessionToken) return;
|
|
7392
|
+
const account = getAccount(wagmiConfig2);
|
|
7393
|
+
if (!account.address) {
|
|
7394
|
+
dispatch({ type: "SET_ERROR", error: "Wallet not connected." });
|
|
7395
|
+
return;
|
|
7396
|
+
}
|
|
7397
|
+
setSettingSender(true);
|
|
7398
|
+
try {
|
|
7399
|
+
console.info(
|
|
7400
|
+
`[blink-sdk] type=guest Setting sender: address=${account.address}, chain=${entry.sourceChainId}, token=${entry.tokenSymbol}`
|
|
7401
|
+
);
|
|
7402
|
+
await setTransferSender(
|
|
7403
|
+
apiBaseUrl,
|
|
7404
|
+
guestTransferId,
|
|
7405
|
+
guestSessionToken,
|
|
7406
|
+
account.address,
|
|
7407
|
+
entry.sourceChainId,
|
|
7408
|
+
entry.tokenAddress
|
|
7409
|
+
);
|
|
7410
|
+
selectedGuestTokenRef.current = entry;
|
|
7411
|
+
dispatch({ type: "NAVIGATE", step: "processing" });
|
|
7412
|
+
} catch (err) {
|
|
7413
|
+
captureException(err);
|
|
7414
|
+
const msg = err instanceof Error ? err.message : "Failed to set transfer sender";
|
|
7415
|
+
dispatch({ type: "SET_ERROR", error: msg });
|
|
7416
|
+
onError?.(msg);
|
|
7417
|
+
} finally {
|
|
7418
|
+
setSettingSender(false);
|
|
7419
|
+
}
|
|
7420
|
+
}, [guestTransferId, guestSessionToken, wagmiConfig2, apiBaseUrl, dispatch, onError]);
|
|
7421
|
+
react.useEffect(() => {
|
|
7422
|
+
if (!isGuestFlow || step !== "processing" || !guestTransferId || !guestSessionToken) return;
|
|
7423
|
+
if (executingBridgeRef.current) return;
|
|
7424
|
+
executingBridgeRef.current = true;
|
|
7425
|
+
const execute = async () => {
|
|
7426
|
+
try {
|
|
7427
|
+
let signPayload = null;
|
|
7428
|
+
for (let i = 0; i < GUEST_SIGN_MAX_POLLS; i++) {
|
|
7429
|
+
const transfer = await getGuestTransfer(apiBaseUrl, guestTransferId, guestSessionToken);
|
|
7430
|
+
const payload = transfer.signPayload;
|
|
7431
|
+
if (payload?.bridgeSteps && payload.bridgeSteps.length > 0) {
|
|
7432
|
+
signPayload = payload;
|
|
7433
|
+
break;
|
|
7434
|
+
}
|
|
7435
|
+
if (transfer.status === "FAILED") {
|
|
7436
|
+
dispatch({ type: "PAY_ERROR", error: "Transfer failed.", fallbackStep: "wallet-picker" });
|
|
7437
|
+
return;
|
|
7438
|
+
}
|
|
7439
|
+
await new Promise((r) => setTimeout(r, GUEST_SIGN_POLL_MS));
|
|
7440
|
+
}
|
|
7441
|
+
if (!signPayload) {
|
|
7442
|
+
dispatch({
|
|
7443
|
+
type: "PAY_ERROR",
|
|
7444
|
+
error: "Timed out waiting for bridge quote. Please try again.",
|
|
7445
|
+
fallbackStep: "wallet-picker"
|
|
7446
|
+
});
|
|
7447
|
+
return;
|
|
7448
|
+
}
|
|
7449
|
+
console.info(
|
|
7450
|
+
`[blink-sdk] type=guest Bridge quote ready: ${signPayload.bridgeSteps.length} step(s), token=${signPayload.tokenSymbol}, chain=${signPayload.chainName}`
|
|
7451
|
+
);
|
|
7452
|
+
const selectedToken = selectedGuestTokenRef.current;
|
|
7453
|
+
const account = getAccount(wagmiConfig2);
|
|
7454
|
+
const targetChainId = selectedToken?.chainId;
|
|
7455
|
+
if (targetChainId) {
|
|
7456
|
+
const numericChainId = Number(targetChainId);
|
|
7457
|
+
if (!isNaN(numericChainId) && account.chainId !== numericChainId) {
|
|
7458
|
+
console.info(`[blink-sdk] type=guest Switching chain to ${numericChainId}`);
|
|
7459
|
+
await switchChainAsync({ chainId: numericChainId });
|
|
7460
|
+
}
|
|
7461
|
+
}
|
|
7462
|
+
const walletClient = await getWalletClient(wagmiConfig2);
|
|
7463
|
+
const sender = account.address;
|
|
7464
|
+
if (!sender) {
|
|
7465
|
+
dispatch({ type: "PAY_ERROR", error: "Wallet not connected.", fallbackStep: "wallet-picker" });
|
|
7466
|
+
return;
|
|
7467
|
+
}
|
|
7468
|
+
let lastTxHash = null;
|
|
7469
|
+
for (let stepIdx = 0; stepIdx < signPayload.bridgeSteps.length; stepIdx++) {
|
|
7470
|
+
const bridgeStep = signPayload.bridgeSteps[stepIdx];
|
|
7471
|
+
console.info(
|
|
7472
|
+
`[blink-sdk] type=guest Executing bridge step ${stepIdx + 1}/${signPayload.bridgeSteps.length} to=${bridgeStep.to}`
|
|
7473
|
+
);
|
|
7474
|
+
const txHash = await walletClient.request({
|
|
7475
|
+
method: "eth_sendTransaction",
|
|
7476
|
+
params: [{
|
|
7477
|
+
from: sender,
|
|
7478
|
+
to: bridgeStep.to,
|
|
7479
|
+
data: bridgeStep.data,
|
|
7480
|
+
value: bridgeStep.value
|
|
7481
|
+
}]
|
|
7482
|
+
});
|
|
7483
|
+
console.info(`[blink-sdk] type=guest Bridge step ${stepIdx + 1} tx sent: ${txHash}`);
|
|
7484
|
+
await waitForTransactionReceipt(wagmiConfig2, {
|
|
7485
|
+
hash: txHash
|
|
7486
|
+
});
|
|
7487
|
+
lastTxHash = txHash;
|
|
7488
|
+
}
|
|
7489
|
+
if (!lastTxHash) {
|
|
7490
|
+
dispatch({ type: "PAY_ERROR", error: "No bridge transactions were executed.", fallbackStep: "wallet-picker" });
|
|
7491
|
+
return;
|
|
7492
|
+
}
|
|
7493
|
+
console.info(`[blink-sdk] type=guest Submitting originTxHash: ${lastTxHash}`);
|
|
7494
|
+
await signGuestTransfer(apiBaseUrl, guestTransferId, guestSessionToken, lastTxHash);
|
|
7495
|
+
for (let i = 0; i < GUEST_COMPLETION_MAX_POLLS; i++) {
|
|
7496
|
+
const transfer = await getGuestTransfer(apiBaseUrl, guestTransferId, guestSessionToken);
|
|
7497
|
+
if (transfer.status === "COMPLETED") {
|
|
7498
|
+
console.info(`[blink-sdk] type=guest Transfer completed`);
|
|
7499
|
+
dispatch({ type: "GUEST_TRANSFER_COMPLETED", transfer });
|
|
7500
|
+
onComplete?.(transfer);
|
|
7501
|
+
return;
|
|
7502
|
+
}
|
|
7503
|
+
if (transfer.status === "FAILED") {
|
|
7504
|
+
dispatch({ type: "TRANSFER_FAILED", transfer, error: "Transfer failed." });
|
|
7505
|
+
return;
|
|
7506
|
+
}
|
|
7507
|
+
await new Promise((r) => setTimeout(r, GUEST_COMPLETION_POLL_MS));
|
|
7508
|
+
}
|
|
7509
|
+
dispatch({
|
|
7510
|
+
type: "PAY_ERROR",
|
|
7511
|
+
error: "Transfer is taking longer than expected. It may still complete.",
|
|
7512
|
+
fallbackStep: "wallet-picker"
|
|
7513
|
+
});
|
|
7514
|
+
} catch (err) {
|
|
7515
|
+
captureException(err);
|
|
7516
|
+
const msg = err instanceof Error ? err.message : "Bridge execution failed";
|
|
7517
|
+
console.error("[blink-sdk] type=guest Bridge execution error:", err);
|
|
7518
|
+
const displayMsg = isUserRejection2(msg) ? "You rejected the transaction. Please approve in your wallet to continue." : msg;
|
|
7519
|
+
dispatch({ type: "PAY_ERROR", error: displayMsg, fallbackStep: "wallet-picker" });
|
|
7520
|
+
onError?.(displayMsg);
|
|
7521
|
+
} finally {
|
|
7522
|
+
executingBridgeRef.current = false;
|
|
7523
|
+
}
|
|
7524
|
+
};
|
|
7525
|
+
execute();
|
|
7526
|
+
}, [isGuestFlow, step, guestTransferId, guestSessionToken, apiBaseUrl, wagmiConfig2, switchChainAsync, dispatch, onComplete, onError]);
|
|
7527
|
+
return {
|
|
7528
|
+
guestTokenEntries,
|
|
7529
|
+
loadingBalances,
|
|
7530
|
+
settingSender,
|
|
7531
|
+
handleSelectGuestToken
|
|
7532
|
+
};
|
|
7533
|
+
}
|
|
6803
7534
|
function useOneTapSetupHandlers(deps) {
|
|
6804
7535
|
const {
|
|
6805
7536
|
dispatch,
|
|
@@ -7262,6 +7993,32 @@ function usePaymentEffects(deps) {
|
|
|
7262
7993
|
state.selectedAccountId,
|
|
7263
7994
|
depositAmount
|
|
7264
7995
|
]);
|
|
7996
|
+
react.useEffect(() => {
|
|
7997
|
+
if (authenticated || state.providers.length > 0) return;
|
|
7998
|
+
if (state.step !== "wallet-picker") return;
|
|
7999
|
+
let cancelled = false;
|
|
8000
|
+
const loadProviders = async () => {
|
|
8001
|
+
try {
|
|
8002
|
+
const providers = await fetchProviders(apiBaseUrl);
|
|
8003
|
+
if (cancelled) return;
|
|
8004
|
+
dispatch({
|
|
8005
|
+
type: "DATA_LOADED",
|
|
8006
|
+
providers,
|
|
8007
|
+
accounts: state.accounts,
|
|
8008
|
+
chains: state.chains,
|
|
8009
|
+
defaults: null
|
|
8010
|
+
});
|
|
8011
|
+
} catch (err) {
|
|
8012
|
+
if (!cancelled) {
|
|
8013
|
+
captureException(err);
|
|
8014
|
+
}
|
|
8015
|
+
}
|
|
8016
|
+
};
|
|
8017
|
+
loadProviders();
|
|
8018
|
+
return () => {
|
|
8019
|
+
cancelled = true;
|
|
8020
|
+
};
|
|
8021
|
+
}, [authenticated, state.step, state.providers.length, apiBaseUrl]);
|
|
7265
8022
|
react.useEffect(() => {
|
|
7266
8023
|
if (!polling.transfer) return;
|
|
7267
8024
|
if (polling.transfer.status === "COMPLETED") {
|
|
@@ -7595,7 +8352,8 @@ function BlinkPaymentInner({
|
|
|
7595
8352
|
transfer.reloadAccounts,
|
|
7596
8353
|
transfer.pollingTransferIdRef,
|
|
7597
8354
|
state.transfer,
|
|
7598
|
-
mobileFlowRefs
|
|
8355
|
+
mobileFlowRefs,
|
|
8356
|
+
onComplete
|
|
7599
8357
|
);
|
|
7600
8358
|
const sourceSelection = useSourceSelectionHandlers(dispatch, authExecutor);
|
|
7601
8359
|
const provider = useProviderHandlers({
|
|
@@ -7618,7 +8376,10 @@ function BlinkPaymentInner({
|
|
|
7618
8376
|
handlingMobileReturnRef: mobileFlowRefs.handlingMobileReturnRef,
|
|
7619
8377
|
setupAccountIdRef: mobileFlowRefs.setupAccountIdRef,
|
|
7620
8378
|
reauthSessionIdRef: mobileFlowRefs.reauthSessionIdRef,
|
|
7621
|
-
reauthTokenRef: mobileFlowRefs.reauthTokenRef
|
|
8379
|
+
reauthTokenRef: mobileFlowRefs.reauthTokenRef,
|
|
8380
|
+
authenticated,
|
|
8381
|
+
merchantAuthorization,
|
|
8382
|
+
destination
|
|
7622
8383
|
});
|
|
7623
8384
|
const oneTapSetup = useOneTapSetupHandlers({
|
|
7624
8385
|
dispatch,
|
|
@@ -7628,6 +8389,15 @@ function BlinkPaymentInner({
|
|
|
7628
8389
|
selectSourceChainName: sourceSelection.selectSourceChainName,
|
|
7629
8390
|
selectSourceTokenSymbol: sourceSelection.selectSourceTokenSymbol
|
|
7630
8391
|
});
|
|
8392
|
+
const guestTransfer = useGuestTransferHandlers({
|
|
8393
|
+
dispatch,
|
|
8394
|
+
isGuestFlow: state.isGuestFlow,
|
|
8395
|
+
guestTransferId: state.guestTransferId,
|
|
8396
|
+
guestSessionToken: state.guestSessionToken,
|
|
8397
|
+
step: state.step,
|
|
8398
|
+
onComplete,
|
|
8399
|
+
onError
|
|
8400
|
+
});
|
|
7631
8401
|
const handleNewPayment = react.useCallback(() => {
|
|
7632
8402
|
clearMobileFlowState();
|
|
7633
8403
|
transfer.processingStartedAtRef.current = null;
|
|
@@ -7728,7 +8498,9 @@ function BlinkPaymentInner({
|
|
|
7728
8498
|
onSetupOneTap: oneTapSetup.handleSetupOneTap,
|
|
7729
8499
|
onSelectToken: provider.handleNavigateToTokenPicker,
|
|
7730
8500
|
onSelectAuthorizedToken: provider.handleSelectAuthorizedToken,
|
|
7731
|
-
onAuthorizeToken: provider.handleAuthorizeToken
|
|
8501
|
+
onAuthorizeToken: provider.handleAuthorizeToken,
|
|
8502
|
+
onSelectGuestToken: guestTransfer.handleSelectGuestToken,
|
|
8503
|
+
onLogin: () => dispatch({ type: "NAVIGATE", step: "login" })
|
|
7732
8504
|
}), [
|
|
7733
8505
|
auth,
|
|
7734
8506
|
passkey,
|
|
@@ -7737,6 +8509,7 @@ function BlinkPaymentInner({
|
|
|
7737
8509
|
mobileFlow,
|
|
7738
8510
|
sourceSelection,
|
|
7739
8511
|
oneTapSetup,
|
|
8512
|
+
guestTransfer,
|
|
7740
8513
|
handleLogout,
|
|
7741
8514
|
handleNewPayment
|
|
7742
8515
|
]);
|
|
@@ -7762,6 +8535,9 @@ function BlinkPaymentInner({
|
|
|
7762
8535
|
selectSourceChoices: sourceSelection.selectSourceChoices,
|
|
7763
8536
|
selectSourceRecommended: sourceSelection.selectSourceRecommended,
|
|
7764
8537
|
selectSourceAvailableBalance: sourceSelection.selectSourceAvailableBalance,
|
|
8538
|
+
guestTokenEntries: guestTransfer.guestTokenEntries,
|
|
8539
|
+
guestLoadingBalances: guestTransfer.loadingBalances,
|
|
8540
|
+
guestSettingSender: guestTransfer.settingSender,
|
|
7765
8541
|
authInput: auth.authInput,
|
|
7766
8542
|
otpCode: auth.otpCode,
|
|
7767
8543
|
selectSourceChainName: sourceSelection.selectSourceChainName,
|