@swype-org/react-sdk 0.1.218 → 0.1.219

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.js CHANGED
@@ -5,8 +5,9 @@ import { mainnet, arbitrum, base, polygon, bsc } from 'wagmi/chains';
5
5
  import { injected } from 'wagmi/connectors';
6
6
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
7
7
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
- import { recoverTypedDataAddress, decodeAbiParameters, walletActions, createClient, custom } from 'viem';
8
+ import { recoverTypedDataAddress, decodeAbiParameters, walletActions, hexToString, createClient, custom } from 'viem';
9
9
  import { parseErc6492Signature, parseAccount, getAddress } from 'viem/utils';
10
+ import { waitForTransactionReceipt as waitForTransactionReceipt$1, getTransaction, call } from 'viem/actions';
10
11
 
11
12
  var __defProp = Object.defineProperty;
12
13
  var __export = (target, all) => {
@@ -154,6 +155,17 @@ function useBlinkDepositAmount() {
154
155
  };
155
156
  }
156
157
 
158
+ // node_modules/@wagmi/core/dist/esm/utils/getAction.js
159
+ function getAction(client, actionFn, name) {
160
+ const action_implicit = client[actionFn.name];
161
+ if (typeof action_implicit === "function")
162
+ return action_implicit;
163
+ const action_explicit = client[name];
164
+ if (typeof action_explicit === "function")
165
+ return action_explicit;
166
+ return (params) => actionFn(client, params);
167
+ }
168
+
157
169
  // node_modules/@wagmi/core/dist/esm/version.js
158
170
  var version = "2.22.1";
159
171
 
@@ -413,24 +425,57 @@ async function getWalletClient(config, parameters = {}) {
413
425
  const client = await getConnectorClient(config, parameters);
414
426
  return client.extend(walletActions);
415
427
  }
428
+ async function waitForTransactionReceipt(config, parameters) {
429
+ const { chainId, timeout = 0, ...rest } = parameters;
430
+ const client = config.getClient({ chainId });
431
+ const action = getAction(client, waitForTransactionReceipt$1, "waitForTransactionReceipt");
432
+ const receipt = await action({ ...rest, timeout });
433
+ if (receipt.status === "reverted") {
434
+ const action_getTransaction = getAction(client, getTransaction, "getTransaction");
435
+ const { from: account, ...txn } = await action_getTransaction({
436
+ hash: receipt.transactionHash
437
+ });
438
+ const action_call = getAction(client, call, "call");
439
+ const code = await action_call({
440
+ ...txn,
441
+ account,
442
+ data: txn.input,
443
+ gasPrice: txn.type !== "eip1559" ? txn.gasPrice : void 0,
444
+ maxFeePerGas: txn.type === "eip1559" ? txn.maxFeePerGas : void 0,
445
+ maxPriorityFeePerGas: txn.type === "eip1559" ? txn.maxPriorityFeePerGas : void 0
446
+ });
447
+ const reason = code?.data ? hexToString(`0x${code.data.substring(138)}`) : "unknown reason";
448
+ throw new Error(reason);
449
+ }
450
+ return {
451
+ ...receipt,
452
+ chainId: client.chain.id
453
+ };
454
+ }
416
455
 
417
456
  // src/api.ts
418
457
  var api_exports = {};
419
458
  __export(api_exports, {
420
459
  createAccount: () => createAccount,
421
460
  createAccountAuthorizationSession: () => createAccountAuthorizationSession,
461
+ createGuestTransfer: () => createGuestTransfer,
422
462
  createTransfer: () => createTransfer,
423
463
  fetchAccount: () => fetchAccount,
424
464
  fetchAccounts: () => fetchAccounts,
425
465
  fetchAuthorizationSession: () => fetchAuthorizationSession,
426
466
  fetchChains: () => fetchChains,
467
+ fetchGuestTransferBalances: () => fetchGuestTransferBalances,
427
468
  fetchMerchantPublicKey: () => fetchMerchantPublicKey,
428
469
  fetchProviders: () => fetchProviders,
429
470
  fetchTransfer: () => fetchTransfer,
430
471
  fetchUserConfig: () => fetchUserConfig,
472
+ getGuestTransfer: () => getGuestTransfer,
473
+ getTransferByGuestToken: () => getTransferByGuestToken,
431
474
  registerPasskey: () => registerPasskey,
432
475
  reportActionCompletion: () => reportActionCompletion,
433
476
  reportPasskeyActivity: () => reportPasskeyActivity,
477
+ setTransferSender: () => setTransferSender,
478
+ signGuestTransfer: () => signGuestTransfer,
434
479
  signTransfer: () => signTransfer,
435
480
  updateUserConfig: () => updateUserConfig,
436
481
  updateUserConfigBySession: () => updateUserConfigBySession
@@ -643,6 +688,79 @@ async function updateUserConfigBySession(apiBaseUrl, sessionId, config) {
643
688
  );
644
689
  if (!res.ok) await throwApiError(res);
645
690
  }
691
+ async function createGuestTransfer(apiBaseUrl, params) {
692
+ const body = {
693
+ id: params.id ?? crypto.randomUUID(),
694
+ type: "guest",
695
+ merchantAuthorization: params.merchantAuthorization,
696
+ destinations: params.destinations,
697
+ amount: {
698
+ amount: params.amount,
699
+ currency: params.currency ?? "USD"
700
+ },
701
+ providerId: params.providerId
702
+ };
703
+ const res = await fetch(`${apiBaseUrl}/v1/transfers`, {
704
+ method: "POST",
705
+ headers: { "Content-Type": "application/json" },
706
+ body: JSON.stringify(body)
707
+ });
708
+ if (!res.ok) await throwApiError(res);
709
+ return await res.json();
710
+ }
711
+ async function getTransferByGuestToken(apiBaseUrl, guestToken) {
712
+ const params = new URLSearchParams({ guestToken });
713
+ const res = await fetch(`${apiBaseUrl}/v1/transfers?${params.toString()}`);
714
+ if (!res.ok) await throwApiError(res);
715
+ return await res.json();
716
+ }
717
+ async function setTransferSender(apiBaseUrl, transferId, guestSessionToken, senderAddress, sourceChainId, sourceToken) {
718
+ const res = await fetch(`${apiBaseUrl}/v1/transfers/${transferId}/sender`, {
719
+ method: "PUT",
720
+ headers: {
721
+ "Content-Type": "application/json",
722
+ "x-guest-session-token": guestSessionToken
723
+ },
724
+ body: JSON.stringify({ senderAddress, sourceChainId, sourceToken })
725
+ });
726
+ if (!res.ok) await throwApiError(res);
727
+ return await res.json();
728
+ }
729
+ async function signGuestTransfer(apiBaseUrl, transferId, guestSessionToken, originTxHash) {
730
+ const res = await fetch(`${apiBaseUrl}/v1/transfers/${transferId}`, {
731
+ method: "PATCH",
732
+ headers: {
733
+ "Content-Type": "application/json",
734
+ "x-guest-session-token": guestSessionToken
735
+ },
736
+ body: JSON.stringify({ originTxHash })
737
+ });
738
+ if (!res.ok) await throwApiError(res);
739
+ return await res.json();
740
+ }
741
+ async function getGuestTransfer(apiBaseUrl, transferId, guestSessionToken) {
742
+ const res = await fetch(`${apiBaseUrl}/v1/transfers/${transferId}`, {
743
+ headers: {
744
+ "x-guest-session-token": guestSessionToken
745
+ }
746
+ });
747
+ if (!res.ok) await throwApiError(res);
748
+ return await res.json();
749
+ }
750
+ async function fetchGuestTransferBalances(apiBaseUrl, transferId, guestSessionToken, walletAddress) {
751
+ const params = new URLSearchParams({ walletAddress });
752
+ const res = await fetch(
753
+ `${apiBaseUrl}/v1/transfers/${transferId}/balances?${params.toString()}`,
754
+ {
755
+ headers: {
756
+ "x-guest-session-token": guestSessionToken
757
+ }
758
+ }
759
+ );
760
+ if (!res.ok) await throwApiError(res);
761
+ const data = await res.json();
762
+ return data.items;
763
+ }
646
764
  async function reportActionCompletion(apiBaseUrl, actionId, result) {
647
765
  const res = await fetch(
648
766
  `${apiBaseUrl}/v1/authorization-actions/${actionId}`,
@@ -1789,8 +1907,9 @@ function deriveSourceTypeAndId(state) {
1789
1907
  return { sourceType: "accountId", sourceId: "" };
1790
1908
  }
1791
1909
  function createInitialState(config) {
1910
+ const isReturningUser = config.activeCredentialId != null;
1792
1911
  return {
1793
- step: "login",
1912
+ step: isReturningUser ? "login" : "wallet-picker",
1794
1913
  error: null,
1795
1914
  providers: [],
1796
1915
  accounts: [],
@@ -1813,7 +1932,10 @@ function createInitialState(config) {
1813
1932
  mobileFlow: false,
1814
1933
  deeplinkUri: null,
1815
1934
  increasingLimit: false,
1816
- previousStep: null
1935
+ previousStep: null,
1936
+ isGuestFlow: false,
1937
+ guestTransferId: null,
1938
+ guestSessionToken: null
1817
1939
  };
1818
1940
  }
1819
1941
  function paymentReducer(state, action) {
@@ -2036,6 +2158,27 @@ function paymentReducer(state, action) {
2036
2158
  mobileFlow: true,
2037
2159
  deeplinkUri: action.deeplinkUri
2038
2160
  };
2161
+ // ── Guest checkout ────────────────────────────────────────────
2162
+ case "GUEST_PROVIDER_SELECTED":
2163
+ return {
2164
+ ...state,
2165
+ isGuestFlow: true,
2166
+ selectedProviderId: action.providerId,
2167
+ guestTransferId: action.transferId,
2168
+ guestSessionToken: action.guestSessionToken,
2169
+ selectedAccountId: null,
2170
+ selectedWalletId: null,
2171
+ selectedTokenSymbol: null,
2172
+ step: "token-picker"
2173
+ };
2174
+ case "GUEST_TRANSFER_COMPLETED":
2175
+ return {
2176
+ ...state,
2177
+ transfer: action.transfer,
2178
+ step: "success",
2179
+ mobileFlow: false,
2180
+ deeplinkUri: null
2181
+ };
2039
2182
  // ── Navigation & error ───────────────────────────────────────
2040
2183
  case "NAVIGATE":
2041
2184
  return { ...state, step: action.step, previousStep: state.step, error: null };
@@ -2045,7 +2188,7 @@ function paymentReducer(state, action) {
2045
2188
  case "NEW_PAYMENT":
2046
2189
  return {
2047
2190
  ...state,
2048
- step: "deposit",
2191
+ step: state.isGuestFlow ? "wallet-picker" : "deposit",
2049
2192
  transfer: null,
2050
2193
  error: null,
2051
2194
  amount: action.depositAmount != null ? action.depositAmount.toString() : "",
@@ -2053,7 +2196,10 @@ function paymentReducer(state, action) {
2053
2196
  deeplinkUri: null,
2054
2197
  selectedProviderId: null,
2055
2198
  selectedWalletId: null,
2056
- selectedAccountId: action.firstAccountId
2199
+ selectedAccountId: action.firstAccountId,
2200
+ isGuestFlow: false,
2201
+ guestTransferId: null,
2202
+ guestSessionToken: null
2057
2203
  };
2058
2204
  case "LOGOUT":
2059
2205
  return {
@@ -3236,7 +3382,9 @@ function WalletPickerScreen({
3236
3382
  onSelectProvider,
3237
3383
  onContinueConnection,
3238
3384
  onBack,
3239
- onLogout
3385
+ onLogout,
3386
+ onLogin,
3387
+ showLoginOption
3240
3388
  }) {
3241
3389
  const { tokens } = useBlinkConfig();
3242
3390
  const [hoveredId, setHoveredId] = useState(null);
@@ -3391,6 +3539,18 @@ function WalletPickerScreen({
3391
3539
  /* @__PURE__ */ jsxs("div", { style: categoryRowStyle(tokens, false, true), children: [
3392
3540
  /* @__PURE__ */ jsx("span", { style: categoryLabelStyle, children: "Bank Account" }),
3393
3541
  /* @__PURE__ */ jsx("span", { style: comingSoonBadgeStyle(tokens), children: "Coming Soon" })
3542
+ ] }),
3543
+ showLoginOption && onLogin && /* @__PURE__ */ jsxs("div", { style: loginOptionStyle, children: [
3544
+ /* @__PURE__ */ jsx("span", { style: loginTextStyle(tokens.textSecondary), children: "Already have an account?" }),
3545
+ /* @__PURE__ */ jsx(
3546
+ "button",
3547
+ {
3548
+ type: "button",
3549
+ onClick: onLogin,
3550
+ style: loginButtonStyle(tokens.accent),
3551
+ children: "Log in"
3552
+ }
3553
+ )
3394
3554
  ] })
3395
3555
  ]
3396
3556
  }
@@ -3557,6 +3717,28 @@ var dividerTextStyle = (color) => ({
3557
3717
  color,
3558
3718
  whiteSpace: "nowrap"
3559
3719
  });
3720
+ var loginOptionStyle = {
3721
+ display: "flex",
3722
+ alignItems: "center",
3723
+ justifyContent: "center",
3724
+ gap: 6,
3725
+ padding: "12px 0 4px"
3726
+ };
3727
+ var loginTextStyle = (color) => ({
3728
+ fontSize: "0.85rem",
3729
+ color
3730
+ });
3731
+ var loginButtonStyle = (accentColor) => ({
3732
+ fontSize: "0.85rem",
3733
+ fontWeight: 600,
3734
+ color: accentColor,
3735
+ background: "none",
3736
+ border: "none",
3737
+ cursor: "pointer",
3738
+ padding: 0,
3739
+ fontFamily: "inherit",
3740
+ textDecoration: "underline"
3741
+ });
3560
3742
  var DEFAULT_MAX = 1e7;
3561
3743
  var ABSOLUTE_MIN = 0.01;
3562
3744
  var PRESETS = [100, 250, 1e3];
@@ -5394,6 +5576,179 @@ var selectCircleSelectedStyle = (color) => ({
5394
5576
  justifyContent: "center",
5395
5577
  flexShrink: 0
5396
5578
  });
5579
+ function GuestTokenPickerScreen({
5580
+ entries,
5581
+ loading,
5582
+ setting,
5583
+ depositAmount,
5584
+ error,
5585
+ onSelect,
5586
+ onBack
5587
+ }) {
5588
+ const { tokens: t } = useBlinkConfig();
5589
+ if (loading) {
5590
+ return /* @__PURE__ */ jsxs(ScreenLayout, { children: [
5591
+ /* @__PURE__ */ jsx(ScreenHeader, { title: "Select Token", onBack }),
5592
+ /* @__PURE__ */ jsx("div", { style: loadingWrapStyle, children: /* @__PURE__ */ jsx(Spinner, { label: "Loading balances..." }) })
5593
+ ] });
5594
+ }
5595
+ return /* @__PURE__ */ jsxs(ScreenLayout, { footer: /* @__PURE__ */ jsx(PoweredByFooter, {}), children: [
5596
+ /* @__PURE__ */ jsx(ScreenHeader, { title: "Select Token", onBack }),
5597
+ depositAmount != null && /* @__PURE__ */ jsxs("div", { style: depositHeaderStyle, children: [
5598
+ /* @__PURE__ */ jsx("div", { style: depositLabelStyle3(t.textMuted), children: "Depositing" }),
5599
+ /* @__PURE__ */ jsxs("div", { style: depositAmountStyle2(t.text), children: [
5600
+ "$",
5601
+ depositAmount.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })
5602
+ ] })
5603
+ ] }),
5604
+ error && /* @__PURE__ */ jsx("p", { style: errorStyle3(t.error), children: error }),
5605
+ /* @__PURE__ */ jsx("div", { style: sectionLabelStyle2(t.textMuted), children: "Choose token to pay with" }),
5606
+ /* @__PURE__ */ jsx("div", { style: tokenListStyle3, children: entries.map((entry) => /* @__PURE__ */ jsxs(
5607
+ "button",
5608
+ {
5609
+ type: "button",
5610
+ onClick: () => onSelect(entry),
5611
+ disabled: setting,
5612
+ style: tokenRowStyle3(t, setting),
5613
+ children: [
5614
+ /* @__PURE__ */ jsx("div", { style: tokenIconCircleStyle3(t, !!TOKEN_LOGOS[entry.tokenSymbol]), children: TOKEN_LOGOS[entry.tokenSymbol] ? /* @__PURE__ */ jsx("img", { src: TOKEN_LOGOS[entry.tokenSymbol], alt: entry.tokenSymbol, style: tokenLogoImgStyle3 }) : /* @__PURE__ */ jsx("span", { style: tokenIconTextStyle3(t.textMuted), children: "$" }) }),
5615
+ /* @__PURE__ */ jsxs("div", { style: tokenInfoStyle3, children: [
5616
+ /* @__PURE__ */ jsxs("div", { style: tokenNameRowStyle2, children: [
5617
+ /* @__PURE__ */ jsx("span", { style: tokenSymbolTextStyle2(t.text), children: entry.tokenSymbol }),
5618
+ /* @__PURE__ */ jsx("span", { style: tokenChainDotStyle2(t.textMuted), children: "\xB7" }),
5619
+ /* @__PURE__ */ jsx("span", { style: tokenChainTextStyle2(t.textMuted), children: entry.chainName })
5620
+ ] }),
5621
+ /* @__PURE__ */ jsxs("span", { style: tokenBalanceStyle2(t.textMuted), children: [
5622
+ "$",
5623
+ entry.balance.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })
5624
+ ] })
5625
+ ] }),
5626
+ /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", style: chevronStyle, children: /* @__PURE__ */ 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 }) })
5627
+ ]
5628
+ },
5629
+ `${entry.chainId}-${entry.tokenAddress}`
5630
+ )) }),
5631
+ entries.length === 0 && /* @__PURE__ */ jsx("p", { style: emptyStyle(t.textMuted), children: "No supported tokens found in your wallet. Please ensure you have USDC or USDT." })
5632
+ ] });
5633
+ }
5634
+ var loadingWrapStyle = {
5635
+ textAlign: "center",
5636
+ padding: "48px 0",
5637
+ flex: 1,
5638
+ display: "flex",
5639
+ alignItems: "center",
5640
+ justifyContent: "center"
5641
+ };
5642
+ var depositHeaderStyle = {
5643
+ marginBottom: 20
5644
+ };
5645
+ var depositLabelStyle3 = (color) => ({
5646
+ fontSize: "0.75rem",
5647
+ fontWeight: 500,
5648
+ color,
5649
+ marginBottom: 4
5650
+ });
5651
+ var depositAmountStyle2 = (color) => ({
5652
+ fontSize: "2.4rem",
5653
+ fontWeight: 700,
5654
+ letterSpacing: "-0.02em",
5655
+ color
5656
+ });
5657
+ var errorStyle3 = (color) => ({
5658
+ fontSize: "0.84rem",
5659
+ color,
5660
+ margin: "0 0 12px",
5661
+ lineHeight: 1.5
5662
+ });
5663
+ var sectionLabelStyle2 = (color) => ({
5664
+ fontSize: "0.84rem",
5665
+ fontWeight: 500,
5666
+ color,
5667
+ marginBottom: 12
5668
+ });
5669
+ var tokenListStyle3 = {
5670
+ display: "flex",
5671
+ flexDirection: "column",
5672
+ gap: 10
5673
+ };
5674
+ var tokenRowStyle3 = (tokens, disabled) => ({
5675
+ display: "flex",
5676
+ alignItems: "center",
5677
+ gap: 14,
5678
+ padding: "14px 16px",
5679
+ background: tokens.bgInput,
5680
+ border: `1px solid ${tokens.border}`,
5681
+ borderRadius: 16,
5682
+ cursor: disabled ? "default" : "pointer",
5683
+ fontFamily: "inherit",
5684
+ textAlign: "left",
5685
+ width: "100%",
5686
+ opacity: disabled ? 0.6 : 1,
5687
+ transition: "opacity 0.15s ease"
5688
+ });
5689
+ var tokenIconCircleStyle3 = (tokens, hasLogo) => ({
5690
+ width: 36,
5691
+ height: 36,
5692
+ borderRadius: "50%",
5693
+ border: hasLogo ? "none" : `1.5px solid ${tokens.border}`,
5694
+ display: "flex",
5695
+ alignItems: "center",
5696
+ justifyContent: "center",
5697
+ flexShrink: 0,
5698
+ overflow: "hidden"
5699
+ });
5700
+ var tokenLogoImgStyle3 = {
5701
+ width: 36,
5702
+ height: 36,
5703
+ borderRadius: "50%",
5704
+ objectFit: "cover"
5705
+ };
5706
+ var tokenIconTextStyle3 = (color) => ({
5707
+ fontSize: "1rem",
5708
+ fontWeight: 700,
5709
+ color
5710
+ });
5711
+ var tokenInfoStyle3 = {
5712
+ display: "flex",
5713
+ flexDirection: "column",
5714
+ gap: 2,
5715
+ flex: 1,
5716
+ minWidth: 0
5717
+ };
5718
+ var tokenNameRowStyle2 = {
5719
+ display: "flex",
5720
+ alignItems: "center",
5721
+ gap: 4
5722
+ };
5723
+ var tokenSymbolTextStyle2 = (color) => ({
5724
+ fontSize: "0.92rem",
5725
+ fontWeight: 600,
5726
+ color
5727
+ });
5728
+ var tokenChainDotStyle2 = (color) => ({
5729
+ fontSize: "0.8rem",
5730
+ color
5731
+ });
5732
+ var tokenChainTextStyle2 = (color) => ({
5733
+ fontSize: "0.84rem",
5734
+ fontWeight: 400,
5735
+ color
5736
+ });
5737
+ var tokenBalanceStyle2 = (color) => ({
5738
+ fontSize: "0.78rem",
5739
+ color
5740
+ });
5741
+ var chevronStyle = {
5742
+ flexShrink: 0,
5743
+ opacity: 0.4
5744
+ };
5745
+ var emptyStyle = (color) => ({
5746
+ fontSize: "0.88rem",
5747
+ color,
5748
+ textAlign: "center",
5749
+ padding: "32px 0",
5750
+ lineHeight: 1.5
5751
+ });
5397
5752
  var LINK_STEPS = /* @__PURE__ */ new Set([
5398
5753
  "create-passkey",
5399
5754
  "verify-passkey",
@@ -5441,6 +5796,9 @@ function StepRendererContent({
5441
5796
  selectSourceChoices,
5442
5797
  selectSourceRecommended,
5443
5798
  selectSourceAvailableBalance,
5799
+ guestTokenEntries,
5800
+ guestLoadingBalances,
5801
+ guestSettingSender,
5444
5802
  authInput,
5445
5803
  otpCode,
5446
5804
  selectSourceChainName,
@@ -5522,6 +5880,7 @@ function StepRendererContent({
5522
5880
  );
5523
5881
  }
5524
5882
  if (step === "wallet-picker") {
5883
+ const isEntryPoint = !state.isGuestFlow && !authenticated;
5525
5884
  return /* @__PURE__ */ jsx(
5526
5885
  WalletPickerScreen,
5527
5886
  {
@@ -5534,8 +5893,10 @@ function StepRendererContent({
5534
5893
  onPrepareProvider: handlers.onPrepareProvider,
5535
5894
  onSelectProvider: handlers.onSelectProvider,
5536
5895
  onContinueConnection: handlers.onContinueConnection,
5537
- onBack: () => handlers.onNavigate(state.activeCredentialId ? "deposit" : "create-passkey"),
5538
- onLogout: handlers.onLogout
5896
+ onBack: isEntryPoint ? onBack : () => handlers.onNavigate(state.activeCredentialId ? "deposit" : "create-passkey"),
5897
+ onLogout: authenticated ? handlers.onLogout : void 0,
5898
+ onLogin: handlers.onLogin,
5899
+ showLoginOption: isEntryPoint
5539
5900
  }
5540
5901
  );
5541
5902
  }
@@ -5642,6 +6003,20 @@ function StepRendererContent({
5642
6003
  );
5643
6004
  }
5644
6005
  if (step === "token-picker") {
6006
+ if (state.isGuestFlow) {
6007
+ return /* @__PURE__ */ jsx(
6008
+ GuestTokenPickerScreen,
6009
+ {
6010
+ entries: guestTokenEntries,
6011
+ loading: guestLoadingBalances,
6012
+ setting: guestSettingSender,
6013
+ depositAmount: depositAmount ?? void 0,
6014
+ error: state.error,
6015
+ onSelect: handlers.onSelectGuestToken,
6016
+ onBack: () => handlers.onNavigate("wallet-picker")
6017
+ }
6018
+ );
6019
+ }
5645
6020
  if (!selectedAccount) {
5646
6021
  return /* @__PURE__ */ jsx(BlinkLoadingScreen, {});
5647
6022
  }
@@ -6397,12 +6772,68 @@ function useSourceSelectionHandlers(dispatch, authExecutor) {
6397
6772
  preSelectSourceStepRef
6398
6773
  };
6399
6774
  }
6400
- function useMobileFlowHandlers(dispatch, polling, reloadAccounts, pollingTransferIdRef, stateTransfer, refs) {
6775
+ function useMobileFlowHandlers(dispatch, polling, reloadAccounts, pollingTransferIdRef, stateTransfer, refs, onComplete) {
6401
6776
  const {
6402
6777
  mobileSetupFlowRef,
6403
6778
  handlingMobileReturnRef,
6404
6779
  loadingDataRef
6405
6780
  } = refs;
6781
+ const { apiBaseUrl } = useBlinkConfig();
6782
+ const onCompleteRef = useRef(onComplete);
6783
+ onCompleteRef.current = onComplete;
6784
+ const guestPollingActiveRef = useRef(false);
6785
+ useEffect(() => {
6786
+ const persisted = loadMobileFlowState();
6787
+ if (!persisted?.isGuestCheckout || !persisted.transferId || !persisted.guestSessionToken) return;
6788
+ if (guestPollingActiveRef.current) return;
6789
+ guestPollingActiveRef.current = true;
6790
+ const transferId = persisted.transferId;
6791
+ const guestSessionToken = persisted.guestSessionToken;
6792
+ let cancelled = false;
6793
+ const POLL_INTERVAL_MS = 3e3;
6794
+ dispatch({ type: "NAVIGATE", step: "processing" });
6795
+ const poll = async () => {
6796
+ if (cancelled) return;
6797
+ try {
6798
+ const transfer = await getGuestTransfer(apiBaseUrl, transferId, guestSessionToken);
6799
+ if (cancelled) return;
6800
+ if (transfer.status === "COMPLETED") {
6801
+ cancelled = true;
6802
+ guestPollingActiveRef.current = false;
6803
+ clearMobileFlowState();
6804
+ dispatch({ type: "GUEST_TRANSFER_COMPLETED", transfer });
6805
+ onCompleteRef.current?.(transfer);
6806
+ } else if (transfer.status === "FAILED") {
6807
+ cancelled = true;
6808
+ guestPollingActiveRef.current = false;
6809
+ clearMobileFlowState();
6810
+ dispatch({ type: "TRANSFER_FAILED", transfer, error: "Transfer failed." });
6811
+ }
6812
+ } catch {
6813
+ }
6814
+ };
6815
+ poll();
6816
+ const intervalId = window.setInterval(poll, POLL_INTERVAL_MS);
6817
+ const handleVisibility = () => {
6818
+ if (document.visibilityState === "visible" && !cancelled) {
6819
+ poll();
6820
+ }
6821
+ };
6822
+ const handlePageShow = (e) => {
6823
+ if (e.persisted && !cancelled) {
6824
+ poll();
6825
+ }
6826
+ };
6827
+ document.addEventListener("visibilitychange", handleVisibility);
6828
+ window.addEventListener("pageshow", handlePageShow);
6829
+ return () => {
6830
+ cancelled = true;
6831
+ guestPollingActiveRef.current = false;
6832
+ window.clearInterval(intervalId);
6833
+ document.removeEventListener("visibilitychange", handleVisibility);
6834
+ window.removeEventListener("pageshow", handlePageShow);
6835
+ };
6836
+ }, [apiBaseUrl, dispatch]);
6406
6837
  const handleAuthorizedMobileReturn = useCallback(async (authorizedTransfer, isSetup) => {
6407
6838
  if (handlingMobileReturnRef.current) return;
6408
6839
  handlingMobileReturnRef.current = true;
@@ -6461,9 +6892,17 @@ function useProviderHandlers(deps) {
6461
6892
  handlingMobileReturnRef,
6462
6893
  setupAccountIdRef,
6463
6894
  reauthSessionIdRef,
6464
- reauthTokenRef
6895
+ reauthTokenRef,
6896
+ authenticated,
6897
+ merchantAuthorization,
6898
+ destination
6465
6899
  } = deps;
6900
+ const wagmiConfig2 = useConfig();
6901
+ const { connectAsync, connectors } = useConnect();
6466
6902
  const handlePrepareProvider = useCallback(async (providerId) => {
6903
+ if (!authenticated) {
6904
+ return null;
6905
+ }
6467
6906
  if (!activeCredentialId) {
6468
6907
  dispatch({ type: "SET_ERROR", error: "Create or verify a passkey on this device before continuing." });
6469
6908
  dispatch({ type: "NAVIGATE", step: "create-passkey" });
@@ -6491,8 +6930,85 @@ function useProviderHandlers(deps) {
6491
6930
  onError?.(msg);
6492
6931
  return null;
6493
6932
  }
6494
- }, [activeCredentialId, providers, apiBaseUrl, getAccessToken, onError, dispatch]);
6933
+ }, [authenticated, activeCredentialId, providers, apiBaseUrl, getAccessToken, onError, dispatch]);
6934
+ const handleGuestSelectProvider = useCallback(async (providerId) => {
6935
+ if (!merchantAuthorization || !destination) {
6936
+ const msg = "Missing payment configuration for guest checkout.";
6937
+ dispatch({ type: "PAY_ERROR", error: msg, fallbackStep: "wallet-picker" });
6938
+ onError?.(msg);
6939
+ return;
6940
+ }
6941
+ const isMobile = !shouldUseWalletConnector({
6942
+ useWalletConnector: useWalletConnectorProp,
6943
+ userAgent: typeof navigator === "undefined" ? void 0 : navigator.userAgent
6944
+ });
6945
+ dispatch({ type: "SELECT_PROVIDER", providerId });
6946
+ try {
6947
+ const result = await createGuestTransfer(apiBaseUrl, {
6948
+ merchantAuthorization,
6949
+ destinations: [{
6950
+ chainId: destination.chainId,
6951
+ token: { address: destination.token.address },
6952
+ address: destination.address
6953
+ }],
6954
+ amount: depositAmount ?? 0,
6955
+ providerId
6956
+ });
6957
+ if (isMobile) {
6958
+ if (!result.uri) {
6959
+ dispatch({ type: "PAY_ERROR", error: "This wallet is not available on mobile.", fallbackStep: "wallet-picker" });
6960
+ return;
6961
+ }
6962
+ persistMobileFlowState({
6963
+ transferId: result.id,
6964
+ guestSessionToken: result.guestSessionToken,
6965
+ isGuestCheckout: true,
6966
+ deeplinkUri: result.uri,
6967
+ providerId,
6968
+ isSetup: false
6969
+ });
6970
+ triggerDeeplink(result.uri);
6971
+ dispatch({ type: "MOBILE_DEEPLINK_READY", deeplinkUri: result.uri });
6972
+ } else {
6973
+ const account = getAccount(wagmiConfig2);
6974
+ if (!account.isConnected) {
6975
+ const connector = connectors.find((c) => c.type === "injected") ?? connectors[0];
6976
+ if (!connector) {
6977
+ dispatch({ type: "PAY_ERROR", error: "No wallet extension found. Please install a supported wallet.", fallbackStep: "wallet-picker" });
6978
+ return;
6979
+ }
6980
+ await connectAsync({ connector });
6981
+ }
6982
+ dispatch({
6983
+ type: "GUEST_PROVIDER_SELECTED",
6984
+ providerId,
6985
+ transferId: result.id,
6986
+ guestSessionToken: result.guestSessionToken
6987
+ });
6988
+ }
6989
+ } catch (err) {
6990
+ captureException(err);
6991
+ const msg = err instanceof Error ? err.message : "Failed to start guest checkout";
6992
+ dispatch({ type: "PAY_ERROR", error: msg, fallbackStep: "wallet-picker" });
6993
+ onError?.(msg);
6994
+ }
6995
+ }, [
6996
+ merchantAuthorization,
6997
+ destination,
6998
+ apiBaseUrl,
6999
+ depositAmount,
7000
+ useWalletConnectorProp,
7001
+ wagmiConfig2,
7002
+ connectors,
7003
+ connectAsync,
7004
+ onError,
7005
+ dispatch
7006
+ ]);
6495
7007
  const handleSelectProvider = useCallback(async (providerId, preparedSession) => {
7008
+ if (!authenticated) {
7009
+ await handleGuestSelectProvider(providerId);
7010
+ return;
7011
+ }
6496
7012
  dispatch({ type: "SELECT_PROVIDER", providerId });
6497
7013
  if (!activeCredentialId) {
6498
7014
  dispatch({ type: "SET_ERROR", error: "Create or verify a passkey on this device before continuing." });
@@ -6562,6 +7078,8 @@ function useProviderHandlers(deps) {
6562
7078
  }
6563
7079
  }
6564
7080
  }, [
7081
+ authenticated,
7082
+ handleGuestSelectProvider,
6565
7083
  activeCredentialId,
6566
7084
  providers,
6567
7085
  apiBaseUrl,
@@ -6797,6 +7315,217 @@ function useProviderHandlers(deps) {
6797
7315
  handleAuthorizeToken
6798
7316
  };
6799
7317
  }
7318
+
7319
+ // src/guestTokens.ts
7320
+ function mapBalancesToGuestTokenEntries(options) {
7321
+ return options.map((opt) => ({
7322
+ chainId: opt.chainId,
7323
+ sourceChainId: opt.sourceChainId,
7324
+ chainName: opt.chainName,
7325
+ tokenSymbol: opt.tokenSymbol,
7326
+ tokenAddress: opt.tokenAddress,
7327
+ decimals: opt.decimals,
7328
+ rawBalance: opt.rawBalance,
7329
+ balance: Number(opt.rawBalance) / 10 ** opt.decimals
7330
+ })).filter((entry) => entry.balance > 0).sort((a, b) => b.balance - a.balance);
7331
+ }
7332
+
7333
+ // src/hooks/useGuestTransferHandlers.ts
7334
+ var GUEST_SIGN_POLL_MS = 2e3;
7335
+ var GUEST_SIGN_MAX_POLLS = 90;
7336
+ var GUEST_COMPLETION_POLL_MS = 3e3;
7337
+ var GUEST_COMPLETION_MAX_POLLS = 120;
7338
+ function isUserRejection2(msg) {
7339
+ const lower = msg.toLowerCase();
7340
+ return lower.includes("rejected") || lower.includes("denied") || lower.includes("cancelled");
7341
+ }
7342
+ function useGuestTransferHandlers(deps) {
7343
+ const {
7344
+ dispatch,
7345
+ isGuestFlow,
7346
+ guestTransferId,
7347
+ guestSessionToken,
7348
+ step,
7349
+ onComplete,
7350
+ onError
7351
+ } = deps;
7352
+ const { apiBaseUrl } = useBlinkConfig();
7353
+ const wagmiConfig2 = useConfig();
7354
+ const { switchChainAsync } = useSwitchChain();
7355
+ const [guestTokenEntries, setGuestTokenEntries] = useState([]);
7356
+ const [loadingBalances, setLoadingBalances] = useState(false);
7357
+ const [settingSender, setSettingSender] = useState(false);
7358
+ const executingBridgeRef = useRef(false);
7359
+ const fetchedRef = useRef(false);
7360
+ const selectedGuestTokenRef = useRef(null);
7361
+ useEffect(() => {
7362
+ if (!isGuestFlow || step !== "token-picker" || fetchedRef.current) return;
7363
+ if (!guestTransferId || !guestSessionToken) return;
7364
+ const account = getAccount(wagmiConfig2);
7365
+ if (!account.address) return;
7366
+ fetchedRef.current = true;
7367
+ setLoadingBalances(true);
7368
+ fetchGuestTransferBalances(apiBaseUrl, guestTransferId, guestSessionToken, account.address).then((options) => mapBalancesToGuestTokenEntries(options)).then((entries) => {
7369
+ setGuestTokenEntries(entries);
7370
+ if (entries.length === 0) {
7371
+ dispatch({ type: "SET_ERROR", error: "No supported tokens found in your wallet." });
7372
+ }
7373
+ }).catch((err) => {
7374
+ captureException(err);
7375
+ dispatch({ type: "SET_ERROR", error: "Failed to fetch token balances." });
7376
+ }).finally(() => setLoadingBalances(false));
7377
+ }, [isGuestFlow, step, guestTransferId, guestSessionToken, apiBaseUrl, wagmiConfig2, dispatch]);
7378
+ useEffect(() => {
7379
+ if (!isGuestFlow) {
7380
+ fetchedRef.current = false;
7381
+ selectedGuestTokenRef.current = null;
7382
+ setGuestTokenEntries([]);
7383
+ }
7384
+ }, [isGuestFlow]);
7385
+ const handleSelectGuestToken = useCallback(async (entry) => {
7386
+ if (!guestTransferId || !guestSessionToken) return;
7387
+ const account = getAccount(wagmiConfig2);
7388
+ if (!account.address) {
7389
+ dispatch({ type: "SET_ERROR", error: "Wallet not connected." });
7390
+ return;
7391
+ }
7392
+ setSettingSender(true);
7393
+ try {
7394
+ console.info(
7395
+ `[blink-sdk] type=guest Setting sender: address=${account.address}, chain=${entry.sourceChainId}, token=${entry.tokenSymbol}`
7396
+ );
7397
+ await setTransferSender(
7398
+ apiBaseUrl,
7399
+ guestTransferId,
7400
+ guestSessionToken,
7401
+ account.address,
7402
+ entry.sourceChainId,
7403
+ entry.tokenAddress
7404
+ );
7405
+ selectedGuestTokenRef.current = entry;
7406
+ dispatch({ type: "NAVIGATE", step: "processing" });
7407
+ } catch (err) {
7408
+ captureException(err);
7409
+ const msg = err instanceof Error ? err.message : "Failed to set transfer sender";
7410
+ dispatch({ type: "SET_ERROR", error: msg });
7411
+ onError?.(msg);
7412
+ } finally {
7413
+ setSettingSender(false);
7414
+ }
7415
+ }, [guestTransferId, guestSessionToken, wagmiConfig2, apiBaseUrl, dispatch, onError]);
7416
+ useEffect(() => {
7417
+ if (!isGuestFlow || step !== "processing" || !guestTransferId || !guestSessionToken) return;
7418
+ if (executingBridgeRef.current) return;
7419
+ executingBridgeRef.current = true;
7420
+ const execute = async () => {
7421
+ try {
7422
+ let signPayload = null;
7423
+ for (let i = 0; i < GUEST_SIGN_MAX_POLLS; i++) {
7424
+ const transfer = await getGuestTransfer(apiBaseUrl, guestTransferId, guestSessionToken);
7425
+ const payload = transfer.signPayload;
7426
+ if (payload?.bridgeSteps && payload.bridgeSteps.length > 0) {
7427
+ signPayload = payload;
7428
+ break;
7429
+ }
7430
+ if (transfer.status === "FAILED") {
7431
+ dispatch({ type: "PAY_ERROR", error: "Transfer failed.", fallbackStep: "wallet-picker" });
7432
+ return;
7433
+ }
7434
+ await new Promise((r) => setTimeout(r, GUEST_SIGN_POLL_MS));
7435
+ }
7436
+ if (!signPayload) {
7437
+ dispatch({
7438
+ type: "PAY_ERROR",
7439
+ error: "Timed out waiting for bridge quote. Please try again.",
7440
+ fallbackStep: "wallet-picker"
7441
+ });
7442
+ return;
7443
+ }
7444
+ console.info(
7445
+ `[blink-sdk] type=guest Bridge quote ready: ${signPayload.bridgeSteps.length} step(s), token=${signPayload.tokenSymbol}, chain=${signPayload.chainName}`
7446
+ );
7447
+ const selectedToken = selectedGuestTokenRef.current;
7448
+ const account = getAccount(wagmiConfig2);
7449
+ const targetChainId = selectedToken?.chainId;
7450
+ if (targetChainId) {
7451
+ const numericChainId = Number(targetChainId);
7452
+ if (!isNaN(numericChainId) && account.chainId !== numericChainId) {
7453
+ console.info(`[blink-sdk] type=guest Switching chain to ${numericChainId}`);
7454
+ await switchChainAsync({ chainId: numericChainId });
7455
+ }
7456
+ }
7457
+ const walletClient = await getWalletClient(wagmiConfig2);
7458
+ const sender = account.address;
7459
+ if (!sender) {
7460
+ dispatch({ type: "PAY_ERROR", error: "Wallet not connected.", fallbackStep: "wallet-picker" });
7461
+ return;
7462
+ }
7463
+ let lastTxHash = null;
7464
+ for (let stepIdx = 0; stepIdx < signPayload.bridgeSteps.length; stepIdx++) {
7465
+ const bridgeStep = signPayload.bridgeSteps[stepIdx];
7466
+ console.info(
7467
+ `[blink-sdk] type=guest Executing bridge step ${stepIdx + 1}/${signPayload.bridgeSteps.length} to=${bridgeStep.to}`
7468
+ );
7469
+ const txHash = await walletClient.request({
7470
+ method: "eth_sendTransaction",
7471
+ params: [{
7472
+ from: sender,
7473
+ to: bridgeStep.to,
7474
+ data: bridgeStep.data,
7475
+ value: bridgeStep.value
7476
+ }]
7477
+ });
7478
+ console.info(`[blink-sdk] type=guest Bridge step ${stepIdx + 1} tx sent: ${txHash}`);
7479
+ await waitForTransactionReceipt(wagmiConfig2, {
7480
+ hash: txHash
7481
+ });
7482
+ lastTxHash = txHash;
7483
+ }
7484
+ if (!lastTxHash) {
7485
+ dispatch({ type: "PAY_ERROR", error: "No bridge transactions were executed.", fallbackStep: "wallet-picker" });
7486
+ return;
7487
+ }
7488
+ console.info(`[blink-sdk] type=guest Submitting originTxHash: ${lastTxHash}`);
7489
+ await signGuestTransfer(apiBaseUrl, guestTransferId, guestSessionToken, lastTxHash);
7490
+ for (let i = 0; i < GUEST_COMPLETION_MAX_POLLS; i++) {
7491
+ const transfer = await getGuestTransfer(apiBaseUrl, guestTransferId, guestSessionToken);
7492
+ if (transfer.status === "COMPLETED") {
7493
+ console.info(`[blink-sdk] type=guest Transfer completed`);
7494
+ dispatch({ type: "GUEST_TRANSFER_COMPLETED", transfer });
7495
+ onComplete?.(transfer);
7496
+ return;
7497
+ }
7498
+ if (transfer.status === "FAILED") {
7499
+ dispatch({ type: "TRANSFER_FAILED", transfer, error: "Transfer failed." });
7500
+ return;
7501
+ }
7502
+ await new Promise((r) => setTimeout(r, GUEST_COMPLETION_POLL_MS));
7503
+ }
7504
+ dispatch({
7505
+ type: "PAY_ERROR",
7506
+ error: "Transfer is taking longer than expected. It may still complete.",
7507
+ fallbackStep: "wallet-picker"
7508
+ });
7509
+ } catch (err) {
7510
+ captureException(err);
7511
+ const msg = err instanceof Error ? err.message : "Bridge execution failed";
7512
+ console.error("[blink-sdk] type=guest Bridge execution error:", err);
7513
+ const displayMsg = isUserRejection2(msg) ? "You rejected the transaction. Please approve in your wallet to continue." : msg;
7514
+ dispatch({ type: "PAY_ERROR", error: displayMsg, fallbackStep: "wallet-picker" });
7515
+ onError?.(displayMsg);
7516
+ } finally {
7517
+ executingBridgeRef.current = false;
7518
+ }
7519
+ };
7520
+ execute();
7521
+ }, [isGuestFlow, step, guestTransferId, guestSessionToken, apiBaseUrl, wagmiConfig2, switchChainAsync, dispatch, onComplete, onError]);
7522
+ return {
7523
+ guestTokenEntries,
7524
+ loadingBalances,
7525
+ settingSender,
7526
+ handleSelectGuestToken
7527
+ };
7528
+ }
6800
7529
  function useOneTapSetupHandlers(deps) {
6801
7530
  const {
6802
7531
  dispatch,
@@ -7592,7 +8321,8 @@ function BlinkPaymentInner({
7592
8321
  transfer.reloadAccounts,
7593
8322
  transfer.pollingTransferIdRef,
7594
8323
  state.transfer,
7595
- mobileFlowRefs
8324
+ mobileFlowRefs,
8325
+ onComplete
7596
8326
  );
7597
8327
  const sourceSelection = useSourceSelectionHandlers(dispatch, authExecutor);
7598
8328
  const provider = useProviderHandlers({
@@ -7615,7 +8345,10 @@ function BlinkPaymentInner({
7615
8345
  handlingMobileReturnRef: mobileFlowRefs.handlingMobileReturnRef,
7616
8346
  setupAccountIdRef: mobileFlowRefs.setupAccountIdRef,
7617
8347
  reauthSessionIdRef: mobileFlowRefs.reauthSessionIdRef,
7618
- reauthTokenRef: mobileFlowRefs.reauthTokenRef
8348
+ reauthTokenRef: mobileFlowRefs.reauthTokenRef,
8349
+ authenticated,
8350
+ merchantAuthorization,
8351
+ destination
7619
8352
  });
7620
8353
  const oneTapSetup = useOneTapSetupHandlers({
7621
8354
  dispatch,
@@ -7625,6 +8358,15 @@ function BlinkPaymentInner({
7625
8358
  selectSourceChainName: sourceSelection.selectSourceChainName,
7626
8359
  selectSourceTokenSymbol: sourceSelection.selectSourceTokenSymbol
7627
8360
  });
8361
+ const guestTransfer = useGuestTransferHandlers({
8362
+ dispatch,
8363
+ isGuestFlow: state.isGuestFlow,
8364
+ guestTransferId: state.guestTransferId,
8365
+ guestSessionToken: state.guestSessionToken,
8366
+ step: state.step,
8367
+ onComplete,
8368
+ onError
8369
+ });
7628
8370
  const handleNewPayment = useCallback(() => {
7629
8371
  clearMobileFlowState();
7630
8372
  transfer.processingStartedAtRef.current = null;
@@ -7725,7 +8467,9 @@ function BlinkPaymentInner({
7725
8467
  onSetupOneTap: oneTapSetup.handleSetupOneTap,
7726
8468
  onSelectToken: provider.handleNavigateToTokenPicker,
7727
8469
  onSelectAuthorizedToken: provider.handleSelectAuthorizedToken,
7728
- onAuthorizeToken: provider.handleAuthorizeToken
8470
+ onAuthorizeToken: provider.handleAuthorizeToken,
8471
+ onSelectGuestToken: guestTransfer.handleSelectGuestToken,
8472
+ onLogin: () => dispatch({ type: "NAVIGATE", step: "login" })
7729
8473
  }), [
7730
8474
  auth,
7731
8475
  passkey,
@@ -7734,6 +8478,7 @@ function BlinkPaymentInner({
7734
8478
  mobileFlow,
7735
8479
  sourceSelection,
7736
8480
  oneTapSetup,
8481
+ guestTransfer,
7737
8482
  handleLogout,
7738
8483
  handleNewPayment
7739
8484
  ]);
@@ -7759,6 +8504,9 @@ function BlinkPaymentInner({
7759
8504
  selectSourceChoices: sourceSelection.selectSourceChoices,
7760
8505
  selectSourceRecommended: sourceSelection.selectSourceRecommended,
7761
8506
  selectSourceAvailableBalance: sourceSelection.selectSourceAvailableBalance,
8507
+ guestTokenEntries: guestTransfer.guestTokenEntries,
8508
+ guestLoadingBalances: guestTransfer.loadingBalances,
8509
+ guestSettingSender: guestTransfer.settingSender,
7762
8510
  authInput: auth.authInput,
7763
8511
  otpCode: auth.otpCode,
7764
8512
  selectSourceChainName: sourceSelection.selectSourceChainName,