@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.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
@@ -646,6 +691,79 @@ async function updateUserConfigBySession(apiBaseUrl, sessionId, config) {
646
691
  );
647
692
  if (!res.ok) await throwApiError(res);
648
693
  }
694
+ async function createGuestTransfer(apiBaseUrl, params) {
695
+ const body = {
696
+ id: params.id ?? crypto.randomUUID(),
697
+ type: "guest",
698
+ merchantAuthorization: params.merchantAuthorization,
699
+ destinations: params.destinations,
700
+ amount: {
701
+ amount: params.amount,
702
+ currency: params.currency ?? "USD"
703
+ },
704
+ providerId: params.providerId
705
+ };
706
+ const res = await fetch(`${apiBaseUrl}/v1/transfers`, {
707
+ method: "POST",
708
+ headers: { "Content-Type": "application/json" },
709
+ body: JSON.stringify(body)
710
+ });
711
+ if (!res.ok) await throwApiError(res);
712
+ return await res.json();
713
+ }
714
+ async function getTransferByGuestToken(apiBaseUrl, guestToken) {
715
+ const params = new URLSearchParams({ guestToken });
716
+ const res = await fetch(`${apiBaseUrl}/v1/transfers?${params.toString()}`);
717
+ if (!res.ok) await throwApiError(res);
718
+ return await res.json();
719
+ }
720
+ async function setTransferSender(apiBaseUrl, transferId, guestSessionToken, senderAddress, sourceChainId, sourceToken) {
721
+ const res = await fetch(`${apiBaseUrl}/v1/transfers/${transferId}/sender`, {
722
+ method: "PUT",
723
+ headers: {
724
+ "Content-Type": "application/json",
725
+ "x-guest-session-token": guestSessionToken
726
+ },
727
+ body: JSON.stringify({ senderAddress, sourceChainId, sourceToken })
728
+ });
729
+ if (!res.ok) await throwApiError(res);
730
+ return await res.json();
731
+ }
732
+ async function signGuestTransfer(apiBaseUrl, transferId, guestSessionToken, originTxHash) {
733
+ const res = await fetch(`${apiBaseUrl}/v1/transfers/${transferId}`, {
734
+ method: "PATCH",
735
+ headers: {
736
+ "Content-Type": "application/json",
737
+ "x-guest-session-token": guestSessionToken
738
+ },
739
+ body: JSON.stringify({ originTxHash })
740
+ });
741
+ if (!res.ok) await throwApiError(res);
742
+ return await res.json();
743
+ }
744
+ async function getGuestTransfer(apiBaseUrl, transferId, guestSessionToken) {
745
+ const res = await fetch(`${apiBaseUrl}/v1/transfers/${transferId}`, {
746
+ headers: {
747
+ "x-guest-session-token": guestSessionToken
748
+ }
749
+ });
750
+ if (!res.ok) await throwApiError(res);
751
+ return await res.json();
752
+ }
753
+ async function fetchGuestTransferBalances(apiBaseUrl, transferId, guestSessionToken, walletAddress) {
754
+ const params = new URLSearchParams({ walletAddress });
755
+ const res = await fetch(
756
+ `${apiBaseUrl}/v1/transfers/${transferId}/balances?${params.toString()}`,
757
+ {
758
+ headers: {
759
+ "x-guest-session-token": guestSessionToken
760
+ }
761
+ }
762
+ );
763
+ if (!res.ok) await throwApiError(res);
764
+ const data = await res.json();
765
+ return data.items;
766
+ }
649
767
  async function reportActionCompletion(apiBaseUrl, actionId, result) {
650
768
  const res = await fetch(
651
769
  `${apiBaseUrl}/v1/authorization-actions/${actionId}`,
@@ -1792,8 +1910,9 @@ function deriveSourceTypeAndId(state) {
1792
1910
  return { sourceType: "accountId", sourceId: "" };
1793
1911
  }
1794
1912
  function createInitialState(config) {
1913
+ const isReturningUser = config.activeCredentialId != null;
1795
1914
  return {
1796
- step: "login",
1915
+ step: isReturningUser ? "login" : "wallet-picker",
1797
1916
  error: null,
1798
1917
  providers: [],
1799
1918
  accounts: [],
@@ -1816,7 +1935,10 @@ function createInitialState(config) {
1816
1935
  mobileFlow: false,
1817
1936
  deeplinkUri: null,
1818
1937
  increasingLimit: false,
1819
- previousStep: null
1938
+ previousStep: null,
1939
+ isGuestFlow: false,
1940
+ guestTransferId: null,
1941
+ guestSessionToken: null
1820
1942
  };
1821
1943
  }
1822
1944
  function paymentReducer(state, action) {
@@ -2039,6 +2161,27 @@ function paymentReducer(state, action) {
2039
2161
  mobileFlow: true,
2040
2162
  deeplinkUri: action.deeplinkUri
2041
2163
  };
2164
+ // ── Guest checkout ────────────────────────────────────────────
2165
+ case "GUEST_PROVIDER_SELECTED":
2166
+ return {
2167
+ ...state,
2168
+ isGuestFlow: true,
2169
+ selectedProviderId: action.providerId,
2170
+ guestTransferId: action.transferId,
2171
+ guestSessionToken: action.guestSessionToken,
2172
+ selectedAccountId: null,
2173
+ selectedWalletId: null,
2174
+ selectedTokenSymbol: null,
2175
+ step: "token-picker"
2176
+ };
2177
+ case "GUEST_TRANSFER_COMPLETED":
2178
+ return {
2179
+ ...state,
2180
+ transfer: action.transfer,
2181
+ step: "success",
2182
+ mobileFlow: false,
2183
+ deeplinkUri: null
2184
+ };
2042
2185
  // ── Navigation & error ───────────────────────────────────────
2043
2186
  case "NAVIGATE":
2044
2187
  return { ...state, step: action.step, previousStep: state.step, error: null };
@@ -2048,7 +2191,7 @@ function paymentReducer(state, action) {
2048
2191
  case "NEW_PAYMENT":
2049
2192
  return {
2050
2193
  ...state,
2051
- step: "deposit",
2194
+ step: state.isGuestFlow ? "wallet-picker" : "deposit",
2052
2195
  transfer: null,
2053
2196
  error: null,
2054
2197
  amount: action.depositAmount != null ? action.depositAmount.toString() : "",
@@ -2056,7 +2199,10 @@ function paymentReducer(state, action) {
2056
2199
  deeplinkUri: null,
2057
2200
  selectedProviderId: null,
2058
2201
  selectedWalletId: null,
2059
- selectedAccountId: action.firstAccountId
2202
+ selectedAccountId: action.firstAccountId,
2203
+ isGuestFlow: false,
2204
+ guestTransferId: null,
2205
+ guestSessionToken: null
2060
2206
  };
2061
2207
  case "LOGOUT":
2062
2208
  return {
@@ -3239,7 +3385,9 @@ function WalletPickerScreen({
3239
3385
  onSelectProvider,
3240
3386
  onContinueConnection,
3241
3387
  onBack,
3242
- onLogout
3388
+ onLogout,
3389
+ onLogin,
3390
+ showLoginOption
3243
3391
  }) {
3244
3392
  const { tokens } = useBlinkConfig();
3245
3393
  const [hoveredId, setHoveredId] = react.useState(null);
@@ -3394,6 +3542,18 @@ function WalletPickerScreen({
3394
3542
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: categoryRowStyle(tokens, false, true), children: [
3395
3543
  /* @__PURE__ */ jsxRuntime.jsx("span", { style: categoryLabelStyle, children: "Bank Account" }),
3396
3544
  /* @__PURE__ */ jsxRuntime.jsx("span", { style: comingSoonBadgeStyle(tokens), children: "Coming Soon" })
3545
+ ] }),
3546
+ showLoginOption && onLogin && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: loginOptionStyle, children: [
3547
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: loginTextStyle(tokens.textSecondary), children: "Already have an account?" }),
3548
+ /* @__PURE__ */ jsxRuntime.jsx(
3549
+ "button",
3550
+ {
3551
+ type: "button",
3552
+ onClick: onLogin,
3553
+ style: loginButtonStyle(tokens.accent),
3554
+ children: "Log in"
3555
+ }
3556
+ )
3397
3557
  ] })
3398
3558
  ]
3399
3559
  }
@@ -3560,6 +3720,28 @@ var dividerTextStyle = (color) => ({
3560
3720
  color,
3561
3721
  whiteSpace: "nowrap"
3562
3722
  });
3723
+ var loginOptionStyle = {
3724
+ display: "flex",
3725
+ alignItems: "center",
3726
+ justifyContent: "center",
3727
+ gap: 6,
3728
+ padding: "12px 0 4px"
3729
+ };
3730
+ var loginTextStyle = (color) => ({
3731
+ fontSize: "0.85rem",
3732
+ color
3733
+ });
3734
+ var loginButtonStyle = (accentColor) => ({
3735
+ fontSize: "0.85rem",
3736
+ fontWeight: 600,
3737
+ color: accentColor,
3738
+ background: "none",
3739
+ border: "none",
3740
+ cursor: "pointer",
3741
+ padding: 0,
3742
+ fontFamily: "inherit",
3743
+ textDecoration: "underline"
3744
+ });
3563
3745
  var DEFAULT_MAX = 1e7;
3564
3746
  var ABSOLUTE_MIN = 0.01;
3565
3747
  var PRESETS = [100, 250, 1e3];
@@ -5397,6 +5579,179 @@ var selectCircleSelectedStyle = (color) => ({
5397
5579
  justifyContent: "center",
5398
5580
  flexShrink: 0
5399
5581
  });
5582
+ function GuestTokenPickerScreen({
5583
+ entries,
5584
+ loading,
5585
+ setting,
5586
+ depositAmount,
5587
+ error,
5588
+ onSelect,
5589
+ onBack
5590
+ }) {
5591
+ const { tokens: t } = useBlinkConfig();
5592
+ if (loading) {
5593
+ return /* @__PURE__ */ jsxRuntime.jsxs(ScreenLayout, { children: [
5594
+ /* @__PURE__ */ jsxRuntime.jsx(ScreenHeader, { title: "Select Token", onBack }),
5595
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: loadingWrapStyle, children: /* @__PURE__ */ jsxRuntime.jsx(Spinner, { label: "Loading balances..." }) })
5596
+ ] });
5597
+ }
5598
+ return /* @__PURE__ */ jsxRuntime.jsxs(ScreenLayout, { footer: /* @__PURE__ */ jsxRuntime.jsx(PoweredByFooter, {}), children: [
5599
+ /* @__PURE__ */ jsxRuntime.jsx(ScreenHeader, { title: "Select Token", onBack }),
5600
+ depositAmount != null && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: depositHeaderStyle, children: [
5601
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: depositLabelStyle3(t.textMuted), children: "Depositing" }),
5602
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: depositAmountStyle2(t.text), children: [
5603
+ "$",
5604
+ depositAmount.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })
5605
+ ] })
5606
+ ] }),
5607
+ error && /* @__PURE__ */ jsxRuntime.jsx("p", { style: errorStyle3(t.error), children: error }),
5608
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: sectionLabelStyle2(t.textMuted), children: "Choose token to pay with" }),
5609
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: tokenListStyle3, children: entries.map((entry) => /* @__PURE__ */ jsxRuntime.jsxs(
5610
+ "button",
5611
+ {
5612
+ type: "button",
5613
+ onClick: () => onSelect(entry),
5614
+ disabled: setting,
5615
+ style: tokenRowStyle3(t, setting),
5616
+ children: [
5617
+ /* @__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: "$" }) }),
5618
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: tokenInfoStyle3, children: [
5619
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: tokenNameRowStyle2, children: [
5620
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: tokenSymbolTextStyle2(t.text), children: entry.tokenSymbol }),
5621
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: tokenChainDotStyle2(t.textMuted), children: "\xB7" }),
5622
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: tokenChainTextStyle2(t.textMuted), children: entry.chainName })
5623
+ ] }),
5624
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: tokenBalanceStyle2(t.textMuted), children: [
5625
+ "$",
5626
+ entry.balance.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })
5627
+ ] })
5628
+ ] }),
5629
+ /* @__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 }) })
5630
+ ]
5631
+ },
5632
+ `${entry.chainId}-${entry.tokenAddress}`
5633
+ )) }),
5634
+ 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." })
5635
+ ] });
5636
+ }
5637
+ var loadingWrapStyle = {
5638
+ textAlign: "center",
5639
+ padding: "48px 0",
5640
+ flex: 1,
5641
+ display: "flex",
5642
+ alignItems: "center",
5643
+ justifyContent: "center"
5644
+ };
5645
+ var depositHeaderStyle = {
5646
+ marginBottom: 20
5647
+ };
5648
+ var depositLabelStyle3 = (color) => ({
5649
+ fontSize: "0.75rem",
5650
+ fontWeight: 500,
5651
+ color,
5652
+ marginBottom: 4
5653
+ });
5654
+ var depositAmountStyle2 = (color) => ({
5655
+ fontSize: "2.4rem",
5656
+ fontWeight: 700,
5657
+ letterSpacing: "-0.02em",
5658
+ color
5659
+ });
5660
+ var errorStyle3 = (color) => ({
5661
+ fontSize: "0.84rem",
5662
+ color,
5663
+ margin: "0 0 12px",
5664
+ lineHeight: 1.5
5665
+ });
5666
+ var sectionLabelStyle2 = (color) => ({
5667
+ fontSize: "0.84rem",
5668
+ fontWeight: 500,
5669
+ color,
5670
+ marginBottom: 12
5671
+ });
5672
+ var tokenListStyle3 = {
5673
+ display: "flex",
5674
+ flexDirection: "column",
5675
+ gap: 10
5676
+ };
5677
+ var tokenRowStyle3 = (tokens, disabled) => ({
5678
+ display: "flex",
5679
+ alignItems: "center",
5680
+ gap: 14,
5681
+ padding: "14px 16px",
5682
+ background: tokens.bgInput,
5683
+ border: `1px solid ${tokens.border}`,
5684
+ borderRadius: 16,
5685
+ cursor: disabled ? "default" : "pointer",
5686
+ fontFamily: "inherit",
5687
+ textAlign: "left",
5688
+ width: "100%",
5689
+ opacity: disabled ? 0.6 : 1,
5690
+ transition: "opacity 0.15s ease"
5691
+ });
5692
+ var tokenIconCircleStyle3 = (tokens, hasLogo) => ({
5693
+ width: 36,
5694
+ height: 36,
5695
+ borderRadius: "50%",
5696
+ border: hasLogo ? "none" : `1.5px solid ${tokens.border}`,
5697
+ display: "flex",
5698
+ alignItems: "center",
5699
+ justifyContent: "center",
5700
+ flexShrink: 0,
5701
+ overflow: "hidden"
5702
+ });
5703
+ var tokenLogoImgStyle3 = {
5704
+ width: 36,
5705
+ height: 36,
5706
+ borderRadius: "50%",
5707
+ objectFit: "cover"
5708
+ };
5709
+ var tokenIconTextStyle3 = (color) => ({
5710
+ fontSize: "1rem",
5711
+ fontWeight: 700,
5712
+ color
5713
+ });
5714
+ var tokenInfoStyle3 = {
5715
+ display: "flex",
5716
+ flexDirection: "column",
5717
+ gap: 2,
5718
+ flex: 1,
5719
+ minWidth: 0
5720
+ };
5721
+ var tokenNameRowStyle2 = {
5722
+ display: "flex",
5723
+ alignItems: "center",
5724
+ gap: 4
5725
+ };
5726
+ var tokenSymbolTextStyle2 = (color) => ({
5727
+ fontSize: "0.92rem",
5728
+ fontWeight: 600,
5729
+ color
5730
+ });
5731
+ var tokenChainDotStyle2 = (color) => ({
5732
+ fontSize: "0.8rem",
5733
+ color
5734
+ });
5735
+ var tokenChainTextStyle2 = (color) => ({
5736
+ fontSize: "0.84rem",
5737
+ fontWeight: 400,
5738
+ color
5739
+ });
5740
+ var tokenBalanceStyle2 = (color) => ({
5741
+ fontSize: "0.78rem",
5742
+ color
5743
+ });
5744
+ var chevronStyle = {
5745
+ flexShrink: 0,
5746
+ opacity: 0.4
5747
+ };
5748
+ var emptyStyle = (color) => ({
5749
+ fontSize: "0.88rem",
5750
+ color,
5751
+ textAlign: "center",
5752
+ padding: "32px 0",
5753
+ lineHeight: 1.5
5754
+ });
5400
5755
  var LINK_STEPS = /* @__PURE__ */ new Set([
5401
5756
  "create-passkey",
5402
5757
  "verify-passkey",
@@ -5444,6 +5799,9 @@ function StepRendererContent({
5444
5799
  selectSourceChoices,
5445
5800
  selectSourceRecommended,
5446
5801
  selectSourceAvailableBalance,
5802
+ guestTokenEntries,
5803
+ guestLoadingBalances,
5804
+ guestSettingSender,
5447
5805
  authInput,
5448
5806
  otpCode,
5449
5807
  selectSourceChainName,
@@ -5525,6 +5883,7 @@ function StepRendererContent({
5525
5883
  );
5526
5884
  }
5527
5885
  if (step === "wallet-picker") {
5886
+ const isEntryPoint = !state.isGuestFlow && !authenticated;
5528
5887
  return /* @__PURE__ */ jsxRuntime.jsx(
5529
5888
  WalletPickerScreen,
5530
5889
  {
@@ -5537,8 +5896,10 @@ function StepRendererContent({
5537
5896
  onPrepareProvider: handlers.onPrepareProvider,
5538
5897
  onSelectProvider: handlers.onSelectProvider,
5539
5898
  onContinueConnection: handlers.onContinueConnection,
5540
- onBack: () => handlers.onNavigate(state.activeCredentialId ? "deposit" : "create-passkey"),
5541
- onLogout: handlers.onLogout
5899
+ onBack: isEntryPoint ? onBack : () => handlers.onNavigate(state.activeCredentialId ? "deposit" : "create-passkey"),
5900
+ onLogout: authenticated ? handlers.onLogout : void 0,
5901
+ onLogin: handlers.onLogin,
5902
+ showLoginOption: isEntryPoint
5542
5903
  }
5543
5904
  );
5544
5905
  }
@@ -5645,6 +6006,20 @@ function StepRendererContent({
5645
6006
  );
5646
6007
  }
5647
6008
  if (step === "token-picker") {
6009
+ if (state.isGuestFlow) {
6010
+ return /* @__PURE__ */ jsxRuntime.jsx(
6011
+ GuestTokenPickerScreen,
6012
+ {
6013
+ entries: guestTokenEntries,
6014
+ loading: guestLoadingBalances,
6015
+ setting: guestSettingSender,
6016
+ depositAmount: depositAmount ?? void 0,
6017
+ error: state.error,
6018
+ onSelect: handlers.onSelectGuestToken,
6019
+ onBack: () => handlers.onNavigate("wallet-picker")
6020
+ }
6021
+ );
6022
+ }
5648
6023
  if (!selectedAccount) {
5649
6024
  return /* @__PURE__ */ jsxRuntime.jsx(BlinkLoadingScreen, {});
5650
6025
  }
@@ -6400,12 +6775,68 @@ function useSourceSelectionHandlers(dispatch, authExecutor) {
6400
6775
  preSelectSourceStepRef
6401
6776
  };
6402
6777
  }
6403
- function useMobileFlowHandlers(dispatch, polling, reloadAccounts, pollingTransferIdRef, stateTransfer, refs) {
6778
+ function useMobileFlowHandlers(dispatch, polling, reloadAccounts, pollingTransferIdRef, stateTransfer, refs, onComplete) {
6404
6779
  const {
6405
6780
  mobileSetupFlowRef,
6406
6781
  handlingMobileReturnRef,
6407
6782
  loadingDataRef
6408
6783
  } = refs;
6784
+ const { apiBaseUrl } = useBlinkConfig();
6785
+ const onCompleteRef = react.useRef(onComplete);
6786
+ onCompleteRef.current = onComplete;
6787
+ const guestPollingActiveRef = react.useRef(false);
6788
+ react.useEffect(() => {
6789
+ const persisted = loadMobileFlowState();
6790
+ if (!persisted?.isGuestCheckout || !persisted.transferId || !persisted.guestSessionToken) return;
6791
+ if (guestPollingActiveRef.current) return;
6792
+ guestPollingActiveRef.current = true;
6793
+ const transferId = persisted.transferId;
6794
+ const guestSessionToken = persisted.guestSessionToken;
6795
+ let cancelled = false;
6796
+ const POLL_INTERVAL_MS = 3e3;
6797
+ dispatch({ type: "NAVIGATE", step: "processing" });
6798
+ const poll = async () => {
6799
+ if (cancelled) return;
6800
+ try {
6801
+ const transfer = await getGuestTransfer(apiBaseUrl, transferId, guestSessionToken);
6802
+ if (cancelled) return;
6803
+ if (transfer.status === "COMPLETED") {
6804
+ cancelled = true;
6805
+ guestPollingActiveRef.current = false;
6806
+ clearMobileFlowState();
6807
+ dispatch({ type: "GUEST_TRANSFER_COMPLETED", transfer });
6808
+ onCompleteRef.current?.(transfer);
6809
+ } else if (transfer.status === "FAILED") {
6810
+ cancelled = true;
6811
+ guestPollingActiveRef.current = false;
6812
+ clearMobileFlowState();
6813
+ dispatch({ type: "TRANSFER_FAILED", transfer, error: "Transfer failed." });
6814
+ }
6815
+ } catch {
6816
+ }
6817
+ };
6818
+ poll();
6819
+ const intervalId = window.setInterval(poll, POLL_INTERVAL_MS);
6820
+ const handleVisibility = () => {
6821
+ if (document.visibilityState === "visible" && !cancelled) {
6822
+ poll();
6823
+ }
6824
+ };
6825
+ const handlePageShow = (e) => {
6826
+ if (e.persisted && !cancelled) {
6827
+ poll();
6828
+ }
6829
+ };
6830
+ document.addEventListener("visibilitychange", handleVisibility);
6831
+ window.addEventListener("pageshow", handlePageShow);
6832
+ return () => {
6833
+ cancelled = true;
6834
+ guestPollingActiveRef.current = false;
6835
+ window.clearInterval(intervalId);
6836
+ document.removeEventListener("visibilitychange", handleVisibility);
6837
+ window.removeEventListener("pageshow", handlePageShow);
6838
+ };
6839
+ }, [apiBaseUrl, dispatch]);
6409
6840
  const handleAuthorizedMobileReturn = react.useCallback(async (authorizedTransfer, isSetup) => {
6410
6841
  if (handlingMobileReturnRef.current) return;
6411
6842
  handlingMobileReturnRef.current = true;
@@ -6464,9 +6895,17 @@ function useProviderHandlers(deps) {
6464
6895
  handlingMobileReturnRef,
6465
6896
  setupAccountIdRef,
6466
6897
  reauthSessionIdRef,
6467
- reauthTokenRef
6898
+ reauthTokenRef,
6899
+ authenticated,
6900
+ merchantAuthorization,
6901
+ destination
6468
6902
  } = deps;
6903
+ const wagmiConfig2 = wagmi.useConfig();
6904
+ const { connectAsync, connectors } = wagmi.useConnect();
6469
6905
  const handlePrepareProvider = react.useCallback(async (providerId) => {
6906
+ if (!authenticated) {
6907
+ return null;
6908
+ }
6470
6909
  if (!activeCredentialId) {
6471
6910
  dispatch({ type: "SET_ERROR", error: "Create or verify a passkey on this device before continuing." });
6472
6911
  dispatch({ type: "NAVIGATE", step: "create-passkey" });
@@ -6494,8 +6933,85 @@ function useProviderHandlers(deps) {
6494
6933
  onError?.(msg);
6495
6934
  return null;
6496
6935
  }
6497
- }, [activeCredentialId, providers, apiBaseUrl, getAccessToken, onError, dispatch]);
6936
+ }, [authenticated, activeCredentialId, providers, apiBaseUrl, getAccessToken, onError, dispatch]);
6937
+ const handleGuestSelectProvider = react.useCallback(async (providerId) => {
6938
+ if (!merchantAuthorization || !destination) {
6939
+ const msg = "Missing payment configuration for guest checkout.";
6940
+ dispatch({ type: "PAY_ERROR", error: msg, fallbackStep: "wallet-picker" });
6941
+ onError?.(msg);
6942
+ return;
6943
+ }
6944
+ const isMobile = !shouldUseWalletConnector({
6945
+ useWalletConnector: useWalletConnectorProp,
6946
+ userAgent: typeof navigator === "undefined" ? void 0 : navigator.userAgent
6947
+ });
6948
+ dispatch({ type: "SELECT_PROVIDER", providerId });
6949
+ try {
6950
+ const result = await createGuestTransfer(apiBaseUrl, {
6951
+ merchantAuthorization,
6952
+ destinations: [{
6953
+ chainId: destination.chainId,
6954
+ token: { address: destination.token.address },
6955
+ address: destination.address
6956
+ }],
6957
+ amount: depositAmount ?? 0,
6958
+ providerId
6959
+ });
6960
+ if (isMobile) {
6961
+ if (!result.uri) {
6962
+ dispatch({ type: "PAY_ERROR", error: "This wallet is not available on mobile.", fallbackStep: "wallet-picker" });
6963
+ return;
6964
+ }
6965
+ persistMobileFlowState({
6966
+ transferId: result.id,
6967
+ guestSessionToken: result.guestSessionToken,
6968
+ isGuestCheckout: true,
6969
+ deeplinkUri: result.uri,
6970
+ providerId,
6971
+ isSetup: false
6972
+ });
6973
+ triggerDeeplink(result.uri);
6974
+ dispatch({ type: "MOBILE_DEEPLINK_READY", deeplinkUri: result.uri });
6975
+ } else {
6976
+ const account = getAccount(wagmiConfig2);
6977
+ if (!account.isConnected) {
6978
+ const connector = connectors.find((c) => c.type === "injected") ?? connectors[0];
6979
+ if (!connector) {
6980
+ dispatch({ type: "PAY_ERROR", error: "No wallet extension found. Please install a supported wallet.", fallbackStep: "wallet-picker" });
6981
+ return;
6982
+ }
6983
+ await connectAsync({ connector });
6984
+ }
6985
+ dispatch({
6986
+ type: "GUEST_PROVIDER_SELECTED",
6987
+ providerId,
6988
+ transferId: result.id,
6989
+ guestSessionToken: result.guestSessionToken
6990
+ });
6991
+ }
6992
+ } catch (err) {
6993
+ captureException(err);
6994
+ const msg = err instanceof Error ? err.message : "Failed to start guest checkout";
6995
+ dispatch({ type: "PAY_ERROR", error: msg, fallbackStep: "wallet-picker" });
6996
+ onError?.(msg);
6997
+ }
6998
+ }, [
6999
+ merchantAuthorization,
7000
+ destination,
7001
+ apiBaseUrl,
7002
+ depositAmount,
7003
+ useWalletConnectorProp,
7004
+ wagmiConfig2,
7005
+ connectors,
7006
+ connectAsync,
7007
+ onError,
7008
+ dispatch
7009
+ ]);
6498
7010
  const handleSelectProvider = react.useCallback(async (providerId, preparedSession) => {
7011
+ if (!authenticated) {
7012
+ await handleGuestSelectProvider(providerId);
7013
+ return;
7014
+ }
6499
7015
  dispatch({ type: "SELECT_PROVIDER", providerId });
6500
7016
  if (!activeCredentialId) {
6501
7017
  dispatch({ type: "SET_ERROR", error: "Create or verify a passkey on this device before continuing." });
@@ -6565,6 +7081,8 @@ function useProviderHandlers(deps) {
6565
7081
  }
6566
7082
  }
6567
7083
  }, [
7084
+ authenticated,
7085
+ handleGuestSelectProvider,
6568
7086
  activeCredentialId,
6569
7087
  providers,
6570
7088
  apiBaseUrl,
@@ -6800,6 +7318,217 @@ function useProviderHandlers(deps) {
6800
7318
  handleAuthorizeToken
6801
7319
  };
6802
7320
  }
7321
+
7322
+ // src/guestTokens.ts
7323
+ function mapBalancesToGuestTokenEntries(options) {
7324
+ return options.map((opt) => ({
7325
+ chainId: opt.chainId,
7326
+ sourceChainId: opt.sourceChainId,
7327
+ chainName: opt.chainName,
7328
+ tokenSymbol: opt.tokenSymbol,
7329
+ tokenAddress: opt.tokenAddress,
7330
+ decimals: opt.decimals,
7331
+ rawBalance: opt.rawBalance,
7332
+ balance: Number(opt.rawBalance) / 10 ** opt.decimals
7333
+ })).filter((entry) => entry.balance > 0).sort((a, b) => b.balance - a.balance);
7334
+ }
7335
+
7336
+ // src/hooks/useGuestTransferHandlers.ts
7337
+ var GUEST_SIGN_POLL_MS = 2e3;
7338
+ var GUEST_SIGN_MAX_POLLS = 90;
7339
+ var GUEST_COMPLETION_POLL_MS = 3e3;
7340
+ var GUEST_COMPLETION_MAX_POLLS = 120;
7341
+ function isUserRejection2(msg) {
7342
+ const lower = msg.toLowerCase();
7343
+ return lower.includes("rejected") || lower.includes("denied") || lower.includes("cancelled");
7344
+ }
7345
+ function useGuestTransferHandlers(deps) {
7346
+ const {
7347
+ dispatch,
7348
+ isGuestFlow,
7349
+ guestTransferId,
7350
+ guestSessionToken,
7351
+ step,
7352
+ onComplete,
7353
+ onError
7354
+ } = deps;
7355
+ const { apiBaseUrl } = useBlinkConfig();
7356
+ const wagmiConfig2 = wagmi.useConfig();
7357
+ const { switchChainAsync } = wagmi.useSwitchChain();
7358
+ const [guestTokenEntries, setGuestTokenEntries] = react.useState([]);
7359
+ const [loadingBalances, setLoadingBalances] = react.useState(false);
7360
+ const [settingSender, setSettingSender] = react.useState(false);
7361
+ const executingBridgeRef = react.useRef(false);
7362
+ const fetchedRef = react.useRef(false);
7363
+ const selectedGuestTokenRef = react.useRef(null);
7364
+ react.useEffect(() => {
7365
+ if (!isGuestFlow || step !== "token-picker" || fetchedRef.current) return;
7366
+ if (!guestTransferId || !guestSessionToken) return;
7367
+ const account = getAccount(wagmiConfig2);
7368
+ if (!account.address) return;
7369
+ fetchedRef.current = true;
7370
+ setLoadingBalances(true);
7371
+ fetchGuestTransferBalances(apiBaseUrl, guestTransferId, guestSessionToken, account.address).then((options) => mapBalancesToGuestTokenEntries(options)).then((entries) => {
7372
+ setGuestTokenEntries(entries);
7373
+ if (entries.length === 0) {
7374
+ dispatch({ type: "SET_ERROR", error: "No supported tokens found in your wallet." });
7375
+ }
7376
+ }).catch((err) => {
7377
+ captureException(err);
7378
+ dispatch({ type: "SET_ERROR", error: "Failed to fetch token balances." });
7379
+ }).finally(() => setLoadingBalances(false));
7380
+ }, [isGuestFlow, step, guestTransferId, guestSessionToken, apiBaseUrl, wagmiConfig2, dispatch]);
7381
+ react.useEffect(() => {
7382
+ if (!isGuestFlow) {
7383
+ fetchedRef.current = false;
7384
+ selectedGuestTokenRef.current = null;
7385
+ setGuestTokenEntries([]);
7386
+ }
7387
+ }, [isGuestFlow]);
7388
+ const handleSelectGuestToken = react.useCallback(async (entry) => {
7389
+ if (!guestTransferId || !guestSessionToken) return;
7390
+ const account = getAccount(wagmiConfig2);
7391
+ if (!account.address) {
7392
+ dispatch({ type: "SET_ERROR", error: "Wallet not connected." });
7393
+ return;
7394
+ }
7395
+ setSettingSender(true);
7396
+ try {
7397
+ console.info(
7398
+ `[blink-sdk] type=guest Setting sender: address=${account.address}, chain=${entry.sourceChainId}, token=${entry.tokenSymbol}`
7399
+ );
7400
+ await setTransferSender(
7401
+ apiBaseUrl,
7402
+ guestTransferId,
7403
+ guestSessionToken,
7404
+ account.address,
7405
+ entry.sourceChainId,
7406
+ entry.tokenAddress
7407
+ );
7408
+ selectedGuestTokenRef.current = entry;
7409
+ dispatch({ type: "NAVIGATE", step: "processing" });
7410
+ } catch (err) {
7411
+ captureException(err);
7412
+ const msg = err instanceof Error ? err.message : "Failed to set transfer sender";
7413
+ dispatch({ type: "SET_ERROR", error: msg });
7414
+ onError?.(msg);
7415
+ } finally {
7416
+ setSettingSender(false);
7417
+ }
7418
+ }, [guestTransferId, guestSessionToken, wagmiConfig2, apiBaseUrl, dispatch, onError]);
7419
+ react.useEffect(() => {
7420
+ if (!isGuestFlow || step !== "processing" || !guestTransferId || !guestSessionToken) return;
7421
+ if (executingBridgeRef.current) return;
7422
+ executingBridgeRef.current = true;
7423
+ const execute = async () => {
7424
+ try {
7425
+ let signPayload = null;
7426
+ for (let i = 0; i < GUEST_SIGN_MAX_POLLS; i++) {
7427
+ const transfer = await getGuestTransfer(apiBaseUrl, guestTransferId, guestSessionToken);
7428
+ const payload = transfer.signPayload;
7429
+ if (payload?.bridgeSteps && payload.bridgeSteps.length > 0) {
7430
+ signPayload = payload;
7431
+ break;
7432
+ }
7433
+ if (transfer.status === "FAILED") {
7434
+ dispatch({ type: "PAY_ERROR", error: "Transfer failed.", fallbackStep: "wallet-picker" });
7435
+ return;
7436
+ }
7437
+ await new Promise((r) => setTimeout(r, GUEST_SIGN_POLL_MS));
7438
+ }
7439
+ if (!signPayload) {
7440
+ dispatch({
7441
+ type: "PAY_ERROR",
7442
+ error: "Timed out waiting for bridge quote. Please try again.",
7443
+ fallbackStep: "wallet-picker"
7444
+ });
7445
+ return;
7446
+ }
7447
+ console.info(
7448
+ `[blink-sdk] type=guest Bridge quote ready: ${signPayload.bridgeSteps.length} step(s), token=${signPayload.tokenSymbol}, chain=${signPayload.chainName}`
7449
+ );
7450
+ const selectedToken = selectedGuestTokenRef.current;
7451
+ const account = getAccount(wagmiConfig2);
7452
+ const targetChainId = selectedToken?.chainId;
7453
+ if (targetChainId) {
7454
+ const numericChainId = Number(targetChainId);
7455
+ if (!isNaN(numericChainId) && account.chainId !== numericChainId) {
7456
+ console.info(`[blink-sdk] type=guest Switching chain to ${numericChainId}`);
7457
+ await switchChainAsync({ chainId: numericChainId });
7458
+ }
7459
+ }
7460
+ const walletClient = await getWalletClient(wagmiConfig2);
7461
+ const sender = account.address;
7462
+ if (!sender) {
7463
+ dispatch({ type: "PAY_ERROR", error: "Wallet not connected.", fallbackStep: "wallet-picker" });
7464
+ return;
7465
+ }
7466
+ let lastTxHash = null;
7467
+ for (let stepIdx = 0; stepIdx < signPayload.bridgeSteps.length; stepIdx++) {
7468
+ const bridgeStep = signPayload.bridgeSteps[stepIdx];
7469
+ console.info(
7470
+ `[blink-sdk] type=guest Executing bridge step ${stepIdx + 1}/${signPayload.bridgeSteps.length} to=${bridgeStep.to}`
7471
+ );
7472
+ const txHash = await walletClient.request({
7473
+ method: "eth_sendTransaction",
7474
+ params: [{
7475
+ from: sender,
7476
+ to: bridgeStep.to,
7477
+ data: bridgeStep.data,
7478
+ value: bridgeStep.value
7479
+ }]
7480
+ });
7481
+ console.info(`[blink-sdk] type=guest Bridge step ${stepIdx + 1} tx sent: ${txHash}`);
7482
+ await waitForTransactionReceipt(wagmiConfig2, {
7483
+ hash: txHash
7484
+ });
7485
+ lastTxHash = txHash;
7486
+ }
7487
+ if (!lastTxHash) {
7488
+ dispatch({ type: "PAY_ERROR", error: "No bridge transactions were executed.", fallbackStep: "wallet-picker" });
7489
+ return;
7490
+ }
7491
+ console.info(`[blink-sdk] type=guest Submitting originTxHash: ${lastTxHash}`);
7492
+ await signGuestTransfer(apiBaseUrl, guestTransferId, guestSessionToken, lastTxHash);
7493
+ for (let i = 0; i < GUEST_COMPLETION_MAX_POLLS; i++) {
7494
+ const transfer = await getGuestTransfer(apiBaseUrl, guestTransferId, guestSessionToken);
7495
+ if (transfer.status === "COMPLETED") {
7496
+ console.info(`[blink-sdk] type=guest Transfer completed`);
7497
+ dispatch({ type: "GUEST_TRANSFER_COMPLETED", transfer });
7498
+ onComplete?.(transfer);
7499
+ return;
7500
+ }
7501
+ if (transfer.status === "FAILED") {
7502
+ dispatch({ type: "TRANSFER_FAILED", transfer, error: "Transfer failed." });
7503
+ return;
7504
+ }
7505
+ await new Promise((r) => setTimeout(r, GUEST_COMPLETION_POLL_MS));
7506
+ }
7507
+ dispatch({
7508
+ type: "PAY_ERROR",
7509
+ error: "Transfer is taking longer than expected. It may still complete.",
7510
+ fallbackStep: "wallet-picker"
7511
+ });
7512
+ } catch (err) {
7513
+ captureException(err);
7514
+ const msg = err instanceof Error ? err.message : "Bridge execution failed";
7515
+ console.error("[blink-sdk] type=guest Bridge execution error:", err);
7516
+ const displayMsg = isUserRejection2(msg) ? "You rejected the transaction. Please approve in your wallet to continue." : msg;
7517
+ dispatch({ type: "PAY_ERROR", error: displayMsg, fallbackStep: "wallet-picker" });
7518
+ onError?.(displayMsg);
7519
+ } finally {
7520
+ executingBridgeRef.current = false;
7521
+ }
7522
+ };
7523
+ execute();
7524
+ }, [isGuestFlow, step, guestTransferId, guestSessionToken, apiBaseUrl, wagmiConfig2, switchChainAsync, dispatch, onComplete, onError]);
7525
+ return {
7526
+ guestTokenEntries,
7527
+ loadingBalances,
7528
+ settingSender,
7529
+ handleSelectGuestToken
7530
+ };
7531
+ }
6803
7532
  function useOneTapSetupHandlers(deps) {
6804
7533
  const {
6805
7534
  dispatch,
@@ -7595,7 +8324,8 @@ function BlinkPaymentInner({
7595
8324
  transfer.reloadAccounts,
7596
8325
  transfer.pollingTransferIdRef,
7597
8326
  state.transfer,
7598
- mobileFlowRefs
8327
+ mobileFlowRefs,
8328
+ onComplete
7599
8329
  );
7600
8330
  const sourceSelection = useSourceSelectionHandlers(dispatch, authExecutor);
7601
8331
  const provider = useProviderHandlers({
@@ -7618,7 +8348,10 @@ function BlinkPaymentInner({
7618
8348
  handlingMobileReturnRef: mobileFlowRefs.handlingMobileReturnRef,
7619
8349
  setupAccountIdRef: mobileFlowRefs.setupAccountIdRef,
7620
8350
  reauthSessionIdRef: mobileFlowRefs.reauthSessionIdRef,
7621
- reauthTokenRef: mobileFlowRefs.reauthTokenRef
8351
+ reauthTokenRef: mobileFlowRefs.reauthTokenRef,
8352
+ authenticated,
8353
+ merchantAuthorization,
8354
+ destination
7622
8355
  });
7623
8356
  const oneTapSetup = useOneTapSetupHandlers({
7624
8357
  dispatch,
@@ -7628,6 +8361,15 @@ function BlinkPaymentInner({
7628
8361
  selectSourceChainName: sourceSelection.selectSourceChainName,
7629
8362
  selectSourceTokenSymbol: sourceSelection.selectSourceTokenSymbol
7630
8363
  });
8364
+ const guestTransfer = useGuestTransferHandlers({
8365
+ dispatch,
8366
+ isGuestFlow: state.isGuestFlow,
8367
+ guestTransferId: state.guestTransferId,
8368
+ guestSessionToken: state.guestSessionToken,
8369
+ step: state.step,
8370
+ onComplete,
8371
+ onError
8372
+ });
7631
8373
  const handleNewPayment = react.useCallback(() => {
7632
8374
  clearMobileFlowState();
7633
8375
  transfer.processingStartedAtRef.current = null;
@@ -7728,7 +8470,9 @@ function BlinkPaymentInner({
7728
8470
  onSetupOneTap: oneTapSetup.handleSetupOneTap,
7729
8471
  onSelectToken: provider.handleNavigateToTokenPicker,
7730
8472
  onSelectAuthorizedToken: provider.handleSelectAuthorizedToken,
7731
- onAuthorizeToken: provider.handleAuthorizeToken
8473
+ onAuthorizeToken: provider.handleAuthorizeToken,
8474
+ onSelectGuestToken: guestTransfer.handleSelectGuestToken,
8475
+ onLogin: () => dispatch({ type: "NAVIGATE", step: "login" })
7732
8476
  }), [
7733
8477
  auth,
7734
8478
  passkey,
@@ -7737,6 +8481,7 @@ function BlinkPaymentInner({
7737
8481
  mobileFlow,
7738
8482
  sourceSelection,
7739
8483
  oneTapSetup,
8484
+ guestTransfer,
7740
8485
  handleLogout,
7741
8486
  handleNewPayment
7742
8487
  ]);
@@ -7762,6 +8507,9 @@ function BlinkPaymentInner({
7762
8507
  selectSourceChoices: sourceSelection.selectSourceChoices,
7763
8508
  selectSourceRecommended: sourceSelection.selectSourceRecommended,
7764
8509
  selectSourceAvailableBalance: sourceSelection.selectSourceAvailableBalance,
8510
+ guestTokenEntries: guestTransfer.guestTokenEntries,
8511
+ guestLoadingBalances: guestTransfer.loadingBalances,
8512
+ guestSettingSender: guestTransfer.settingSender,
7765
8513
  authInput: auth.authInput,
7766
8514
  otpCode: auth.otpCode,
7767
8515
  selectSourceChainName: sourceSelection.selectSourceChainName,