@openfort/react 1.6.0 → 1.6.2

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.
Files changed (56) hide show
  1. package/build/components/Common/Modal/index.js +14 -0
  2. package/build/components/Common/Modal/index.js.map +1 -1
  3. package/build/components/Openfort/types.d.ts +1 -1
  4. package/build/components/Pages/AssetInventory/SolanaAssetInventory.js +47 -8
  5. package/build/components/Pages/AssetInventory/SolanaAssetInventory.js.map +1 -1
  6. package/build/components/Pages/AssetInventory/index.js +50 -6
  7. package/build/components/Pages/AssetInventory/index.js.map +1 -1
  8. package/build/components/Pages/Connected/EthereumConnected.js +2 -5
  9. package/build/components/Pages/Connected/EthereumConnected.js.map +1 -1
  10. package/build/components/Pages/DepositWallet/index.js +15 -10
  11. package/build/components/Pages/DepositWallet/index.js.map +1 -1
  12. package/build/components/Pages/ExportKey/index.js +44 -4
  13. package/build/components/Pages/ExportKey/index.js.map +1 -1
  14. package/build/components/Pages/ExportKey/styles.d.ts +5 -0
  15. package/build/components/Pages/ExportKey/styles.js +47 -0
  16. package/build/components/Pages/ExportKey/styles.js.map +1 -0
  17. package/build/components/Pages/Receive/index.js +2 -2
  18. package/build/components/Pages/SelectToken/SolanaSelectToken.js +7 -7
  19. package/build/components/Pages/SelectToken/index.js +7 -3
  20. package/build/components/Pages/SelectToken/index.js.map +1 -1
  21. package/build/components/Pages/Send/EthereumSend.js +25 -5
  22. package/build/components/Pages/Send/EthereumSend.js.map +1 -1
  23. package/build/components/Pages/Send/SolanaSend.js +23 -4
  24. package/build/components/Pages/Send/SolanaSend.js.map +1 -1
  25. package/build/components/Pages/Send/styles.d.ts +17 -11
  26. package/build/components/Pages/Send/styles.js +104 -49
  27. package/build/components/Pages/Send/styles.js.map +1 -1
  28. package/build/components/Pages/SendConfirmation/ConfirmationSummary.d.ts +3 -1
  29. package/build/components/Pages/SendConfirmation/ConfirmationSummary.js +2 -2
  30. package/build/components/Pages/SendConfirmation/EstimatedFees.d.ts +3 -1
  31. package/build/components/Pages/SendConfirmation/EstimatedFees.js +22 -15
  32. package/build/components/Pages/SendConfirmation/EstimatedFees.js.map +1 -1
  33. package/build/components/Pages/SendConfirmation/SolanaSendConfirmation.js +17 -5
  34. package/build/components/Pages/SendConfirmation/SolanaSendConfirmation.js.map +1 -1
  35. package/build/components/Pages/SendConfirmation/index.js +11 -5
  36. package/build/components/Pages/SendConfirmation/index.js.map +1 -1
  37. package/build/components/Pages/SendConfirmation/styles.d.ts +3 -1
  38. package/build/components/Pages/SendConfirmation/styles.js +20 -6
  39. package/build/components/Pages/SendConfirmation/styles.js.map +1 -1
  40. package/build/components/Pages/SignMessage/index.js +44 -19
  41. package/build/components/Pages/SignMessage/index.js.map +1 -1
  42. package/build/components/Pages/SignMessage/styles.d.ts +2 -3
  43. package/build/components/Pages/SignMessage/styles.js +19 -2
  44. package/build/components/Pages/SignMessage/styles.js.map +1 -1
  45. package/build/constants/defaultAssets.d.ts +18 -0
  46. package/build/constants/defaultAssets.js +70 -0
  47. package/build/constants/defaultAssets.js.map +1 -0
  48. package/build/hooks/openfort/useSignMessage.d.ts +2 -2
  49. package/build/hooks/openfort/useUI.js +4 -2
  50. package/build/hooks/openfort/useUI.js.map +1 -1
  51. package/build/solana/transfer.d.ts +12 -0
  52. package/build/solana/transfer.js +29 -1
  53. package/build/solana/transfer.js.map +1 -1
  54. package/build/version.d.ts +1 -1
  55. package/build/version.js +1 -1
  56. package/package.json +1 -1
@@ -2,6 +2,7 @@ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
2
  import { AnimatePresence, motion } from 'framer-motion';
3
3
  import { useEffect, useState, useCallback, useRef } from 'react';
4
4
  import { useTransition } from 'react-transition-state';
5
+ import ResizeObserver from 'resize-observer-polyfill';
5
6
  import { useConnectionStrategy } from '../../../core/ConnectionStrategyContext.js';
6
7
  import { useEthereumBridge } from '../../../ethereum/OpenfortEthereumBridgeContext.js';
7
8
  import FocusTrap from '../../../hooks/useFocusTrap.js';
@@ -107,6 +108,7 @@ onInfo, }) => {
107
108
  };
108
109
  let blockTimeout;
109
110
  const contentRef = useCallback((node) => {
111
+ var _a;
110
112
  if (!node)
111
113
  return;
112
114
  ref.current = node;
@@ -116,6 +118,16 @@ onInfo, }) => {
116
118
  blockTimeout = setTimeout(() => setInTransition(false), 360);
117
119
  // Calculate new content bounds
118
120
  updateBounds(node);
121
+ // Auto-fit: re-measure whenever the active page's content size changes, so
122
+ // every page — and any new one — sizes the modal correctly without having
123
+ // to call triggerResize() itself.
124
+ (_a = resizeObserverRef.current) === null || _a === void 0 ? void 0 : _a.disconnect();
125
+ const observer = new ResizeObserver(() => {
126
+ if (ref.current === node)
127
+ updateBounds(node);
128
+ });
129
+ observer.observe(node);
130
+ resizeObserverRef.current = observer;
119
131
  }, [open, inTransition]);
120
132
  // Update layout on chain/network switch to avoid clipping
121
133
  const strategy = useConnectionStrategy();
@@ -123,10 +135,12 @@ onInfo, }) => {
123
135
  const chainId = (_j = (_f = strategy === null || strategy === void 0 ? void 0 : strategy.getChainId()) !== null && _f !== void 0 ? _f : (_h = (_g = bridge === null || bridge === void 0 ? void 0 : bridge.account) === null || _g === void 0 ? void 0 : _g.chain) === null || _h === void 0 ? void 0 : _h.id) !== null && _j !== void 0 ? _j : bridge === null || bridge === void 0 ? void 0 : bridge.chainId;
124
136
  const switchChain = (_k = bridge === null || bridge === void 0 ? void 0 : bridge.switchChain) === null || _k === void 0 ? void 0 : _k.switchChain;
125
137
  const ref = useRef(null);
138
+ const resizeObserverRef = useRef(null);
126
139
  useEffect(() => {
127
140
  if (ref.current)
128
141
  updateBounds(ref.current);
129
142
  }, [chainId, switchChain, mobile, context.uiConfig, context.resize]);
143
+ useEffect(() => () => { var _a; return (_a = resizeObserverRef.current) === null || _a === void 0 ? void 0 : _a.disconnect(); }, []);
130
144
  useEffect(() => {
131
145
  if (!mounted) {
132
146
  setDimensions({
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -492,7 +492,7 @@ export type SignRequest = ({
492
492
  kind: 'typedData';
493
493
  typedData: SignTypedDataPayload;
494
494
  }) & {
495
- resolve: (signature: `0x${string}`) => void;
495
+ resolve: (signature: string) => void;
496
496
  reject: (reason?: unknown) => void;
497
497
  };
498
498
  export type BuyProviderId = 'moonpay' | 'coinbase' | 'stripe';
@@ -1,19 +1,51 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
- import { useEffect, useState } from 'react';
2
+ import { useEffect, useMemo } from 'react';
3
3
  import { formatUnits } from 'viem';
4
- import { TOKEN_LOGO, symbolToColor } from '../../../constants/logos.js';
4
+ import { currencyLogoUrl } from '../../../constants/logos.js';
5
+ import { useSolanaEmbeddedWallet } from '../../../solana/hooks/useSolanaEmbeddedWallet.js';
5
6
  import { useSolanaWalletAssets } from '../../../solana/hooks/useSolanaWalletAssets.js';
6
7
  import { ModalHeading } from '../../Common/Modal/styles.js';
7
8
  import { routes } from '../../Openfort/types.js';
8
9
  import { useOpenfort } from '../../Openfort/useOpenfort.js';
9
- import { SelectTokenContent, EmptyState, ContentWrapper, TokenList, TokenContainer, TokenLeftGroup, TokenInfo, TokenSymbol, TokenName, TokenLogoArea, TokenLogoImg, TokenLogoFallback } from '../SelectToken/styles.js';
10
+ import { AssetChainLogo } from '../Deposit/AssetChainLogo.js';
11
+ import { SelectTokenContent, EmptyState, ContentWrapper, TokenList, TokenContainer, TokenLeftGroup, TokenInfo, TokenSymbol, TokenName, TokenLogoArea } from '../SelectToken/styles.js';
10
12
 
11
13
  const ZERO = BigInt(0);
14
+ const USDC_MINT_MAINNET = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v';
15
+ const USDC_MINT_DEVNET = '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU';
16
+ const USDT_MINT_MAINNET = 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB';
17
+ /**
18
+ * Default tokens to surface at zero balance: native SOL plus the stablecoins we
19
+ * ship verified mints for (USDC on the active cluster, USDT on mainnet). Skips any
20
+ * already held.
21
+ */
22
+ function buildSolanaDefaults(cluster, held) {
23
+ const isMainnet = cluster === 'mainnet-beta' || cluster === 'mainnet';
24
+ const heldMints = new Set(held.map((t) => t.mint));
25
+ const defaults = [];
26
+ if (!heldMints.has('native')) {
27
+ defaults.push({ mint: 'native', symbol: 'SOL', name: 'Solana', amount: ZERO, decimals: 9, isNative: true });
28
+ }
29
+ const usdcMint = isMainnet ? USDC_MINT_MAINNET : USDC_MINT_DEVNET;
30
+ if (!heldMints.has(usdcMint)) {
31
+ defaults.push({ mint: usdcMint, symbol: 'USDC', name: 'USD Coin', amount: ZERO, decimals: 6, isNative: false });
32
+ }
33
+ if (isMainnet && !heldMints.has(USDT_MINT_MAINNET)) {
34
+ defaults.push({
35
+ mint: USDT_MINT_MAINNET,
36
+ symbol: 'USDT',
37
+ name: 'Tether USD',
38
+ amount: ZERO,
39
+ decimals: 6,
40
+ isNative: false,
41
+ });
42
+ }
43
+ return defaults;
44
+ }
45
+ /** Token logo with the Solana chain badge, matching the EVM inventory. */
12
46
  function SolanaTokenLogo({ symbol }) {
13
- var _a;
14
- const [imgError, setImgError] = useState(false);
15
- const url = (_a = TOKEN_LOGO[symbol.toUpperCase()]) !== null && _a !== void 0 ? _a : null;
16
- return (jsx(TokenLogoArea, { children: url && !imgError ? (jsx(TokenLogoImg, { src: url, alt: symbol, onError: () => setImgError(true) })) : (jsx(TokenLogoFallback, { "$bg": symbolToColor(symbol), children: symbol.charAt(0).toUpperCase() })) }));
47
+ var _a, _b;
48
+ return (jsx(TokenLogoArea, { children: jsx(AssetChainLogo, { assetLogo: (_a = currencyLogoUrl(symbol)) !== null && _a !== void 0 ? _a : '', chainLogo: (_b = currencyLogoUrl('SOL')) !== null && _b !== void 0 ? _b : '', symbol: symbol }) }));
17
49
  }
18
50
  /**
19
51
  * SVM counterpart of {@link AssetInventory}: lists the connected Solana wallet's
@@ -23,11 +55,18 @@ function SolanaTokenLogo({ symbol }) {
23
55
  const SolanaAssetInventory = () => {
24
56
  const { data, isLoading } = useSolanaWalletAssets();
25
57
  const { triggerResize } = useOpenfort();
58
+ const wallet = useSolanaEmbeddedWallet();
59
+ const cluster = wallet.cluster;
26
60
  useEffect(() => {
27
61
  if (!isLoading)
28
62
  triggerResize();
29
63
  }, [isLoading, triggerResize]);
30
- const tokens = (data !== null && data !== void 0 ? data : []).filter((t) => t.amount > ZERO);
64
+ // Held tokens first, then default zero-balance tokens (SOL + stablecoins) so the
65
+ // list is never empty.
66
+ const tokens = useMemo(() => {
67
+ const held = (data !== null && data !== void 0 ? data : []).filter((t) => t.amount > ZERO);
68
+ return [...held, ...buildSolanaDefaults(cluster, held)];
69
+ }, [data, cluster]);
31
70
  if (isLoading) {
32
71
  return (jsxs(SelectTokenContent, { onBack: routes.SOL_CONNECTED, children: [jsx(ModalHeading, { children: "Your assets" }), jsx(EmptyState, { children: "Loading balances..." })] }));
33
72
  }
@@ -1 +1 @@
1
- {"version":3,"file":"SolanaAssetInventory.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"SolanaAssetInventory.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -2,8 +2,11 @@ import { jsxs, jsx } from 'react/jsx-runtime';
2
2
  import { motion } from 'framer-motion';
3
3
  import { useState, useEffect, useMemo } from 'react';
4
4
  import { formatUnits } from 'viem';
5
+ import { DEFAULT_ASSETS, isStableSymbol } from '../../../constants/defaultAssets.js';
5
6
  import { TOKEN_LOGO, symbolToColor } from '../../../constants/logos.js';
7
+ import { useEthereumEmbeddedWallet } from '../../../ethereum/hooks/useEthereumEmbeddedWallet.js';
6
8
  import { useEthereumWalletAssets } from '../../../ethereum/hooks/useEthereumWalletAssets.js';
9
+ import { getNativeCurrency } from '../../../utils/rpc.js';
7
10
  import Chain from '../../Common/Chain/index.js';
8
11
  import { ModalHeading } from '../../Common/Modal/styles.js';
9
12
  import { useOpenfort } from '../../Openfort/useOpenfort.js';
@@ -23,6 +26,44 @@ const priceFormatter = new Intl.NumberFormat('en-US', {
23
26
  minimumFractionDigits: 2,
24
27
  maximumFractionDigits: 4,
25
28
  });
29
+ /**
30
+ * Default tokens to surface at zero balance so the inventory is never empty: the
31
+ * active chain's native token plus the documented default ERC-20s for that chain
32
+ * (USDC / USDT / DAI / wrapped native). Skips any already held.
33
+ */
34
+ function buildDefaultTokens(chainId, held) {
35
+ var _a;
36
+ if (chainId === undefined)
37
+ return [];
38
+ const heldKeys = new Set(held.map((t) => (t.type === 'erc20' ? `${t.chainId}-${t.address.toLowerCase()}` : `${t.chainId}-native`)));
39
+ const defaults = [];
40
+ if (!heldKeys.has(`${chainId}-native`)) {
41
+ const native = getNativeCurrency(chainId);
42
+ defaults.push({
43
+ type: 'native',
44
+ chainId,
45
+ balance: ZERO,
46
+ metadata: { symbol: native.symbol, decimals: native.decimals, fiat: { value: 0, currency: 'USD' } },
47
+ });
48
+ }
49
+ for (const token of (_a = DEFAULT_ASSETS[chainId]) !== null && _a !== void 0 ? _a : []) {
50
+ if (heldKeys.has(`${chainId}-${token.address.toLowerCase()}`))
51
+ continue;
52
+ defaults.push({
53
+ type: 'erc20',
54
+ chainId,
55
+ address: token.address,
56
+ balance: ZERO,
57
+ metadata: {
58
+ symbol: token.symbol,
59
+ name: token.name,
60
+ decimals: token.decimals,
61
+ fiat: isStableSymbol(token.symbol) ? { value: 1, currency: 'USD' } : undefined,
62
+ },
63
+ });
64
+ }
65
+ return defaults;
66
+ }
26
67
  function getTokenLogoUrl(token) {
27
68
  var _a;
28
69
  const symbol = getAssetSymbol(token).toUpperCase();
@@ -35,7 +76,7 @@ function TokenLogo({ token }) {
35
76
  return (jsxs(TokenLogoArea, { children: [logoUrl && !imgError ? (jsx(TokenLogoImg, { src: logoUrl, alt: symbol, onError: () => setImgError(true) })) : (jsx(TokenLogoFallback, { "$bg": symbolToColor(symbol), children: symbol.charAt(0).toUpperCase() })), jsx(ChainBadge, { children: jsx(Chain, { id: token.chainId, unsupported: false, size: 14 }) })] }));
36
77
  }
37
78
  function renderTokenRow(token) {
38
- var _a, _b, _c, _d;
79
+ var _a, _b, _c;
39
80
  const key = token.type === 'erc20' ? `${token.chainId}-${token.address}` : `${token.chainId}-native`;
40
81
  const displaySymbol = getAssetSymbol(token);
41
82
  const displayName = ((_a = token.metadata) === null || _a === void 0 ? void 0 : _a.name) || displaySymbol || 'Unknown Token';
@@ -45,9 +86,6 @@ function renderTokenRow(token) {
45
86
  let balanceNum = '';
46
87
  let priceDisplay = null;
47
88
  const isBalanceLoaded = token.balance !== undefined;
48
- const hasZeroBalance = isBalanceLoaded && ((_d = token.balance) !== null && _d !== void 0 ? _d : ZERO) <= ZERO;
49
- if (hasZeroBalance)
50
- return null;
51
89
  if (isBalanceLoaded && token.balance !== undefined) {
52
90
  const amount = parseFloat(formatUnits(token.balance, decimals));
53
91
  if (Number.isFinite(amount)) {
@@ -101,6 +139,7 @@ const AssetInventory = () => {
101
139
  var _a;
102
140
  const { data, multiChain, isLoading: isBalancesLoading } = useEthereumWalletAssets({ multiChain: true });
103
141
  const { triggerResize, chains } = useOpenfort();
142
+ const { chainId } = useEthereumEmbeddedWallet();
104
143
  const [showDetails, setShowDetails] = useState(false);
105
144
  useEffect(() => {
106
145
  if (!isBalancesLoading)
@@ -110,7 +149,12 @@ const AssetInventory = () => {
110
149
  triggerResize();
111
150
  }, [showDetails]);
112
151
  const tokens = (_a = (multiChain ? data : null)) !== null && _a !== void 0 ? _a : [];
113
- const hasBalance = tokens.some((t) => t.balance > ZERO);
152
+ // Held tokens (any chain) first, then default zero-balance tokens for the active
153
+ // chain so the list is never empty and always shows the chain's essentials.
154
+ const displayTokens = useMemo(() => {
155
+ const held = tokens.filter((t) => t.balance > ZERO);
156
+ return [...held, ...buildDefaultTokens(chainId, held)];
157
+ }, [tokens, chainId]);
114
158
  const chainNameMap = useMemo(() => {
115
159
  const map = new Map();
116
160
  for (const c of chains)
@@ -138,7 +182,7 @@ const AssetInventory = () => {
138
182
  setShowDetails(false);
139
183
  }, children: [jsx(ModalHeading, { children: "Configured assets" }), jsx(motion.div, { initial: { opacity: 0, scale: 1.1 }, animate: { opacity: 1, scale: 1 }, transition: { duration: 0.2, ease: [0.26, 0.08, 0.25, 1] }, style: { display: 'flex', flexDirection: 'column', flex: 1, minHeight: 0 }, children: jsx(ContentWrapper, { style: { overflowY: 'auto', maxHeight: 400 }, children: Array.from(groupedByChain.entries()).map(([chainId, assets]) => (jsxs(ChainGroup, { children: [jsxs(ChainGroupHeader, { children: [jsx(Chain, { id: chainId, unsupported: false, size: 18 }), chainNameMap.get(chainId) || `Chain ${chainId}`] }), assets.map((a) => (jsxs(TokenPill, { children: [jsx(PillLogo, { symbol: a.symbol }), jsx(TokenPillSymbol, { children: a.symbol }), a.name !== a.symbol && a.name] }, `${chainId}-${a.symbol}`)))] }, chainId))) }) })] }, "details"));
140
184
  }
141
- return (jsxs(SelectTokenContent, { children: [jsx(ModalHeading, { children: "Your assets" }), jsxs(ContentWrapper, { children: [jsxs(InfoLink, { type: "button", onClick: () => setShowDetails(true), children: [jsxs("svg", { role: "img", "aria-label": "Info", width: "12", height: "12", viewBox: "0 0 14 14", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [jsx("circle", { cx: "7", cy: "7", r: "6", stroke: "currentColor", strokeWidth: "1.25" }), jsx("path", { d: "M7 6.25V10", stroke: "currentColor", strokeWidth: "1.25", strokeLinecap: "round" }), jsx("circle", { cx: "7", cy: "4.25", r: "0.75", fill: "currentColor" })] }), "Only configured chains and tokens are shown"] }), jsx(TokenList, { children: hasBalance ? tokens.map(renderTokenRow) : jsx(EmptyState, { children: "No assets found" }) })] })] }, "assets"));
185
+ return (jsxs(SelectTokenContent, { children: [jsx(ModalHeading, { children: "Your assets" }), jsxs(ContentWrapper, { children: [jsxs(InfoLink, { type: "button", onClick: () => setShowDetails(true), children: [jsxs("svg", { role: "img", "aria-label": "Info", width: "12", height: "12", viewBox: "0 0 14 14", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [jsx("circle", { cx: "7", cy: "7", r: "6", stroke: "currentColor", strokeWidth: "1.25" }), jsx("path", { d: "M7 6.25V10", stroke: "currentColor", strokeWidth: "1.25", strokeLinecap: "round" }), jsx("circle", { cx: "7", cy: "4.25", r: "0.75", fill: "currentColor" })] }), "Only configured chains and tokens are shown"] }), jsx(TokenList, { children: displayTokens.length > 0 ? displayTokens.map(renderTokenRow) : jsx(EmptyState, { children: "No assets found" }) })] })] }, "assets"));
142
186
  };
143
187
 
144
188
  export { AssetInventory };
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -106,11 +106,8 @@ const EthereumConnected = () => {
106
106
  : undefined;
107
107
  const locales = useLocales();
108
108
  const balanceNode = assets && !isLoading ? (jsx(TextLinkButton, { type: "button", onClick: () => {
109
- const firstBalanceAsset = getFirstBalanceAsset(assets);
110
- if (!firstBalanceAsset) {
111
- setRoute(routes.NO_ASSETS_AVAILABLE);
112
- return;
113
- }
109
+ // The inventory always shows the chain's native token + stablecoin
110
+ // defaults, so there's no empty state to gate on.
114
111
  setRoute(routes.ASSET_INVENTORY);
115
112
  }, children: jsxs(Balance, { initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, transition: { duration: 0.2 }, children: ["$", nFormatter(totalBalanceUsd)] }, `chain-${chain === null || chain === void 0 ? void 0 : chain.id}`) })) : null;
116
113
  const noWalletFallback = hasEthereumWallets ? (jsx(Button, { onClick: () => context.setRoute(routes.SELECT_WALLET_TO_RECOVER), children: "Manage wallets" })) : (jsx(Button, { onClick: () => context.setRoute({ route: routes.CONNECTORS, connectType: 'link' }), icon: jsx(Unsupported, { initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, children: jsxs("svg", { width: "130", height: "120", viewBox: "0 0 13 12", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [jsx("title", { children: "Unsupported wallet icon" }), jsx("path", { d: "M2.61317 11.2501H9.46246C10.6009 11.2501 11.3256 10.3506 11.3256 9.3549C11.3256 9.05145 11.255 8.73244 11.0881 8.43303L7.65903 2.14708C7.659 2.14702 7.65897 2.14696 7.65893 2.1469C7.65889 2.14682 7.65884 2.14673 7.65879 2.14664C7.31045 1.50746 6.6741 1.17871 6.04 1.17871C5.41478 1.17871 4.763 1.50043 4.41518 2.14968L0.993416 8.43476C0.828865 8.72426 0.75 9.04297 0.75 9.3549C0.75 10.3506 1.47471 11.2501 2.61317 11.2501Z", fill: "currentColor", stroke: "var(--ck-body-background, #fff)", strokeWidth: "1.5" }), jsx("path", { d: "M6.03258 7.43916C5.77502 7.43916 5.63096 7.29153 5.62223 7.02311L5.55675 4.96973C5.54802 4.69684 5.74446 4.5 6.02821 4.5C6.3076 4.5 6.51277 4.70131 6.50404 4.9742L6.43856 7.01864C6.42546 7.29153 6.2814 7.43916 6.03258 7.43916ZM6.03258 9.11676C5.7401 9.11676 5.5 8.9065 5.5 8.60677C5.5 8.30704 5.7401 8.09678 6.03258 8.09678C6.32506 8.09678 6.56515 8.30256 6.56515 8.60677C6.56515 8.91097 6.32069 9.11676 6.03258 9.11676Z", fill: "white" })] }) }), children: "Connect wallet" }));
@@ -1 +1 @@
1
- {"version":3,"file":"EthereumConnected.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"EthereumConnected.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -6,6 +6,7 @@ import { useEthereumBridge } from '../../../ethereum/OpenfortEthereumBridgeConte
6
6
  import useIsMobile from '../../../hooks/useIsMobile.js';
7
7
  import styled from '../../../styles/styled/index.js';
8
8
  import { isIOS } from '../../../utils/index.js';
9
+ import { TextLinkButton } from '../../Common/Button/styles.js';
9
10
  import { ModalHeading, ModalBody } from '../../Common/Modal/styles.js';
10
11
  import { ScrollArea } from '../../Common/ScrollArea/index.js';
11
12
  import { routes } from '../../Openfort/types.js';
@@ -83,6 +84,8 @@ const DepositWallet = () => {
83
84
  // (the funding deposit-address mint uses a fixed nominal amount regardless).
84
85
  const [amount, setAmount] = useState('1');
85
86
  const [pressedPreset, setPressedPreset] = useState(null);
87
+ // Collapse the wallet list to keep the picker short on mobile; "Show more" reveals the rest.
88
+ const [showAllWallets, setShowAllWallets] = useState(false);
86
89
  const depositPageUrl = (_b = (_a = uiConfig.funding) === null || _a === void 0 ? void 0 : _a.depositPageUrl) !== null && _b !== void 0 ? _b : OPENFORT_DEPOSIT_PAGE_URL;
87
90
  // Solana sources have no numeric chain id and no desktop EVM-extension send, so
88
91
  // they route through the deeplink (Phantom) on every platform instead of the
@@ -125,20 +128,22 @@ const DepositWallet = () => {
125
128
  // Trust's in-app dApp browser was removed on iOS (Apple, 2021) — the link
126
129
  // dead-ends there, so hide it on iOS while keeping it on Android.
127
130
  const deeplinks = isIOS() ? allDeeplinks.filter((d) => d.app !== 'trust') : allDeeplinks;
131
+ const WALLET_LIMIT = 3;
132
+ const visibleDeeplinks = showAllWallets ? deeplinks : deeplinks.slice(0, WALLET_LIMIT);
128
133
  useEffect(() => {
129
134
  triggerResize();
130
- }, [route.receiverAddress, route.loading, route.status, deeplinks.length, triggerResize]);
135
+ }, [route.receiverAddress, route.loading, route.status, deeplinks.length, showAllWallets, triggerResize]);
131
136
  if (isDepositFlowActive(route.status))
132
137
  return jsx(DepositProgress, { status: route.status });
133
- return (jsxs(PageContent, { onBack: routes.DEPOSIT, children: [jsx(ModalHeading, { children: "Transfer from wallet" }), jsx(TestnetNotice, {}), route.targetUnsupported && (jsx(UnsupportedNetworkNotice, { targetChain: route.target.chain, railChains: route.railChains })), !route.targetUnsupported && route.accountUnusableOnTarget && (jsx(AccountChainNotice, { targetChain: route.target.chain })), !route.targetUnsupported && !route.accountUnusableOnTarget && (jsxs(Layout, { children: [jsxs(TopFixed, { children: [jsx(RouteSelectors, { chains: route.chains, chain: route.chain, currency: route.currency, chainLabel: "Supported chain", onChainChange: route.setChain, onCurrencyChange: route.setCurrency }), !route.isAvailable && jsx(ModalBody, { children: "Funding isn't available right now." }), jsxs(Section, { children: [jsx(SectionLabel, { children: "Amount" }), jsxs(AmountCard, { children: [jsx(CurrencySymbol, { children: (_m = (_l = route.activeCurrency) === null || _l === void 0 ? void 0 : _l.symbol) !== null && _m !== void 0 ? _m : '' }), jsx(AmountInput, { value: amount, onChange: handleAmountChange, placeholder: "0.00", inputMode: "decimal", autoComplete: "off" })] }), jsx(PresetList, { children: PRESETS.map((preset) => (jsx(PresetButton, { type: "button", "$active": pressedPreset === preset, onClick: () => handlePreset(preset), children: preset }, preset))) })] }), jsx(StepDivider, { children: "Then select the wallet you want to use" })] }), jsx(ProvidersRegion, { children: isMobile || isSolanaSrc || !bridge ? (jsxs(Fragment, { children: [!depositPageUrl && (jsx(ModalBody, { style: { marginTop: 12 }, children: "Use a deposit address below to fund from your wallet." })), route.loading && !route.pm && (jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 8 }, children: [jsx(Skeleton, { "$h": "44px", "$r": "10px" }), jsx(Skeleton, { "$h": "44px", "$r": "10px" }), jsx(Skeleton, { "$h": "44px", "$r": "10px" })] })), deeplinks.length > 0 && (jsx(ScrollArea, { fill: true, children: jsx("div", { style: { display: 'flex', flexDirection: 'column', gap: 8 }, children: deeplinks.map((d) => (jsxs("a", { href: amountValid ? d.url : undefined, "aria-disabled": !amountValid, target: "_blank", rel: "noreferrer", style: {
134
- ...walletListBtn,
135
- display: 'flex',
136
- alignItems: 'center',
137
- justifyContent: 'center',
138
- gap: 8,
139
- opacity: amountValid ? 1 : 0.55,
140
- pointerEvents: amountValid ? 'auto' : 'none',
141
- }, children: [WALLET_LOGO[d.app] && jsx(ButtonLogo, { children: WALLET_LOGO[d.app] }), d.label, " \u2197"] }, d.app))) }) }))] })) : (jsx(DepositWalletDesktop, { receiverAddress: route.receiverAddress, activeChain: route.activeChain, activeCurrency: route.activeCurrency, loading: route.loading, amount: amount })) }), jsxs(FixedFooter, { children: [jsx(AddressPageLink, { label: "Or send to a deposit address" }), route.error && jsx(ModalBody, { style: { color: '#dc2626', marginTop: 12 }, children: route.error.message })] })] }))] }));
138
+ return (jsxs(PageContent, { onBack: routes.DEPOSIT, children: [jsx(ModalHeading, { children: "Transfer from wallet" }), jsx(TestnetNotice, {}), route.targetUnsupported && (jsx(UnsupportedNetworkNotice, { targetChain: route.target.chain, railChains: route.railChains })), !route.targetUnsupported && route.accountUnusableOnTarget && (jsx(AccountChainNotice, { targetChain: route.target.chain })), !route.targetUnsupported && !route.accountUnusableOnTarget && (jsxs(Layout, { children: [jsxs(TopFixed, { children: [jsx(RouteSelectors, { chains: route.chains, chain: route.chain, currency: route.currency, chainLabel: "Supported chain", onChainChange: route.setChain, onCurrencyChange: route.setCurrency }), !route.isAvailable && jsx(ModalBody, { children: "Funding isn't available right now." }), jsxs(Section, { children: [jsx(SectionLabel, { children: "Amount" }), jsxs(AmountCard, { children: [jsx(CurrencySymbol, { children: (_m = (_l = route.activeCurrency) === null || _l === void 0 ? void 0 : _l.symbol) !== null && _m !== void 0 ? _m : '' }), jsx(AmountInput, { value: amount, onChange: handleAmountChange, placeholder: "0.00", inputMode: "decimal", autoComplete: "off" })] }), jsx(PresetList, { children: PRESETS.map((preset) => (jsx(PresetButton, { type: "button", "$active": pressedPreset === preset, onClick: () => handlePreset(preset), children: preset }, preset))) })] }), jsx(StepDivider, { children: "Then select the wallet you want to use" })] }), jsx(ProvidersRegion, { children: isMobile || isSolanaSrc || !bridge ? (jsxs(Fragment, { children: [!depositPageUrl && (jsx(ModalBody, { style: { marginTop: 12 }, children: "Use a deposit address below to fund from your wallet." })), route.loading && !route.pm && (jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 8 }, children: [jsx(Skeleton, { "$h": "44px", "$r": "10px" }), jsx(Skeleton, { "$h": "44px", "$r": "10px" }), jsx(Skeleton, { "$h": "44px", "$r": "10px" })] })), deeplinks.length > 0 && (jsx(ScrollArea, { fill: true, children: jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 8 }, children: [visibleDeeplinks.map((d) => (jsxs("a", { href: amountValid ? d.url : undefined, "aria-disabled": !amountValid, target: "_blank", rel: "noreferrer", style: {
139
+ ...walletListBtn,
140
+ display: 'flex',
141
+ alignItems: 'center',
142
+ justifyContent: 'center',
143
+ gap: 8,
144
+ opacity: amountValid ? 1 : 0.55,
145
+ pointerEvents: amountValid ? 'auto' : 'none',
146
+ }, children: [WALLET_LOGO[d.app] && jsx(ButtonLogo, { children: WALLET_LOGO[d.app] }), d.label, " \u2197"] }, d.app))), deeplinks.length > WALLET_LIMIT && (jsx(TextLinkButton, { type: "button", onClick: () => setShowAllWallets((v) => !v), style: { alignSelf: 'center', marginTop: 2 }, children: showAllWallets ? 'Show less' : `Show ${deeplinks.length - WALLET_LIMIT} more` }))] }) }))] })) : (jsx(DepositWalletDesktop, { receiverAddress: route.receiverAddress, activeChain: route.activeChain, activeCurrency: route.activeCurrency, loading: route.loading, amount: amount })) }), jsxs(FixedFooter, { children: [jsx(AddressPageLink, { label: "Or send to a deposit address" }), route.error && jsx(ModalBody, { style: { color: '#dc2626', marginTop: 12 }, children: route.error.message })] })] }))] }));
142
147
  };
143
148
 
144
149
  export { DepositWallet as default };
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -1,14 +1,16 @@
1
1
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
- import { useState, useEffect } from 'react';
2
+ import { useState, useRef, useCallback, useEffect } from 'react';
3
3
  import { KeyIcon } from '../../../assets/icons.js';
4
4
  import { useEthereumEmbeddedWallet } from '../../../ethereum/hooks/useEthereumEmbeddedWallet.js';
5
- import Button from '../../Common/Button/index.js';
6
- import { CopyText } from '../../Common/CopyToClipboard/CopyText.js';
5
+ import { CopyIconButton } from '../../Common/CopyToClipboard/CopyIconButton.js';
7
6
  import { ModalHeading, ModalContent, ModalBody } from '../../Common/Modal/styles.js';
8
7
  import { FloatingGraphic } from '../../FloatingGraphic/index.js';
9
8
  import { PageContent } from '../../PageContent/index.js';
9
+ import { Label, AddressRow, AddressField } from '../Receive/styles.js';
10
+ import { HoldButton, HoldFill, HoldLabel, KeyReveal } from './styles.js';
10
11
 
11
12
  // TODO: Localize
13
+ const HOLD_MS = 5000;
12
14
  const ExportKey = () => {
13
15
  var _a, _b;
14
16
  const wallet = useEthereumEmbeddedWallet();
@@ -22,6 +24,42 @@ const ExportKey = () => {
22
24
  const [exportedKey, setExportedKey] = useState(null);
23
25
  const [exportError, setExportError] = useState(null);
24
26
  const [showExportedKey, setShowExportedKey] = useState(false);
27
+ // Press-and-hold gate: the key only reveals after a deliberate 5s hold.
28
+ const [progress, setProgress] = useState(0);
29
+ const holdingRef = useRef(false);
30
+ const rafRef = useRef(null);
31
+ const startRef = useRef(0);
32
+ const stopHold = useCallback(() => {
33
+ holdingRef.current = false;
34
+ if (rafRef.current !== null) {
35
+ cancelAnimationFrame(rafRef.current);
36
+ rafRef.current = null;
37
+ }
38
+ setProgress((p) => (p >= 1 ? p : 0));
39
+ }, []);
40
+ const startHold = useCallback(() => {
41
+ if (showExportedKey || holdingRef.current)
42
+ return;
43
+ holdingRef.current = true;
44
+ startRef.current = performance.now();
45
+ const tick = (now) => {
46
+ if (!holdingRef.current)
47
+ return;
48
+ const p = Math.min(1, (now - startRef.current) / HOLD_MS);
49
+ setProgress(p);
50
+ if (p >= 1) {
51
+ holdingRef.current = false;
52
+ setShowExportedKey(true);
53
+ return;
54
+ }
55
+ rafRef.current = requestAnimationFrame(tick);
56
+ };
57
+ rafRef.current = requestAnimationFrame(tick);
58
+ }, [showExportedKey]);
59
+ useEffect(() => () => {
60
+ if (rafRef.current !== null)
61
+ cancelAnimationFrame(rafRef.current);
62
+ }, []);
25
63
  useEffect(() => {
26
64
  const asyncExportKey = async () => {
27
65
  try {
@@ -45,7 +83,9 @@ const ExportKey = () => {
45
83
  logo: jsx(KeyIcon, {}),
46
84
  }, logoBottomLeft: {
47
85
  logo: jsx(KeyIcon, {}),
48
- } }), jsxs(ModalContent, { children: [jsxs(ModalBody, { children: [isSmartAccount ? (jsxs("p", { style: { marginBottom: 6 }, children: ["This is your account's ", jsx("strong", { children: "owner (signer) key" }), " \u2014 not the account itself. Your smart account", accountAddress ? ` (${accountAddress.slice(0, 6)}…${accountAddress.slice(-4)})` : '', " is a contract with no private key, so importing this key into another wallet shows the owner address,", ' ', jsx("strong", { children: "not your funds" }), ". To move funds, use Send to withdraw to another wallet."] })) : (jsx("p", { style: { marginBottom: 6 }, children: "With your private key, you can access your account outside this application." })), jsx("p", { children: "Keep it safe and never share it with anyone you don't trust." })] }), !showExportedKey ? (jsx(Button, { onClick: () => setShowExportedKey(true), style: { marginTop: 12 }, children: "Export key" })) : exportError ? (jsx(ModalBody, { style: { marginTop: 12 }, "$error": true, children: exportError })) : exportedKey ? (jsx("div", { style: { marginTop: 12 }, children: jsxs(CopyText, { value: exportedKey, children: [exportedKey.slice(0, 10), "...", exportedKey.slice(-10)] }) })) : (jsx(Fragment, { children: "Loading..." }))] })] }));
86
+ } }), jsxs(ModalContent, { children: [jsxs(ModalBody, { children: [isSmartAccount ? (jsxs("p", { style: { marginBottom: 6 }, children: ["This is your account's ", jsx("strong", { children: "owner (signer) key" }), " \u2014 not the account itself. Your smart account", accountAddress ? ` (${accountAddress.slice(0, 6)}…${accountAddress.slice(-4)})` : '', " is a contract with no private key, so importing this key into another wallet shows the owner address,", ' ', jsx("strong", { children: "not your funds" }), ". To move funds, use Send to withdraw to another wallet."] })) : (jsx("p", { style: { marginBottom: 6 }, children: "With your private key, you can access your account outside this application." })), jsx("p", { children: "Keep it safe and never share it with anyone you don't trust." })] }), !showExportedKey ? (jsxs(HoldButton, { type: "button", onPointerDown: startHold, onPointerUp: stopHold, onPointerLeave: stopHold, onPointerCancel: stopHold, style: { marginTop: 12 }, children: [jsx(HoldFill, { style: { width: `${progress * 100}%` } }), jsx(HoldLabel, { children: progress > 0
87
+ ? `Hold to reveal… ${Math.ceil((1 - progress) * (HOLD_MS / 1000))}s`
88
+ : 'Hold 5s to reveal key' })] })) : exportError ? (jsx(ModalBody, { style: { marginTop: 12 }, "$error": true, children: exportError })) : exportedKey ? (jsxs(KeyReveal, { children: [jsx(Label, { children: "Your private key" }), jsxs(AddressRow, { children: [jsx(AddressField, { style: { fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace' }, children: exportedKey }), jsx(CopyIconButton, { value: exportedKey })] })] })) : (jsx(Fragment, { children: "Loading..." }))] })] }));
49
89
  };
50
90
 
51
91
  export { ExportKey as default };
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -0,0 +1,5 @@
1
+ /** Press-and-hold reveal button: a fill grows left→right over the hold duration. */
2
+ export declare const HoldButton: import("styled-components").StyledComponent<"button", any, {}, never>;
3
+ export declare const HoldFill: import("styled-components").StyledComponent<"div", any, {}, never>;
4
+ export declare const HoldLabel: import("styled-components").StyledComponent<"span", any, {}, never>;
5
+ export declare const KeyReveal: import("styled-components").StyledComponent<"div", any, {}, never>;
@@ -0,0 +1,47 @@
1
+ import styled from '../../../styles/styled/index.js';
2
+
3
+ /** Press-and-hold reveal button: a fill grows left→right over the hold duration. */
4
+ const HoldButton = styled.button `
5
+ position: relative;
6
+ overflow: hidden;
7
+ width: 100%;
8
+ padding: 14px 16px;
9
+ border-radius: var(--ck-primary-button-border-radius, 16px);
10
+ border: 1px solid var(--ck-body-divider);
11
+ background: var(--ck-secondary-button-background);
12
+ color: var(--ck-body-color);
13
+ font-size: 16px;
14
+ font-weight: 600;
15
+ cursor: pointer;
16
+ user-select: none;
17
+ -webkit-user-select: none;
18
+ touch-action: none;
19
+ transition: border-color 150ms ease;
20
+
21
+ &:hover {
22
+ border-color: var(--ck-body-color-muted);
23
+ }
24
+ `;
25
+ const HoldFill = styled.div `
26
+ position: absolute;
27
+ top: 0;
28
+ left: 0;
29
+ bottom: 0;
30
+ background: var(--ck-focus-color, #1a88f8);
31
+ opacity: 0.22;
32
+ pointer-events: none;
33
+ `;
34
+ const HoldLabel = styled.span `
35
+ position: relative;
36
+ z-index: 1;
37
+ `;
38
+ const KeyReveal = styled.div `
39
+ display: flex;
40
+ flex-direction: column;
41
+ gap: 10px;
42
+ margin-top: 12px;
43
+ text-align: left;
44
+ `;
45
+
46
+ export { HoldButton, HoldFill, HoldLabel, KeyReveal };
47
+ //# sourceMappingURL=styles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styles.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -8,7 +8,7 @@ import { useOpenfortCore } from '../../../openfort/useOpenfort.js';
8
8
  import { useSolanaEmbeddedWallet } from '../../../solana/hooks/useSolanaEmbeddedWallet.js';
9
9
  import { CopyIconButton } from '../../Common/CopyToClipboard/CopyIconButton.js';
10
10
  import CustomQRCode from '../../Common/CustomQRCode/index.js';
11
- import { ModalHeading, ModalBody } from '../../Common/Modal/styles.js';
11
+ import { ModalHeading } from '../../Common/Modal/styles.js';
12
12
  import { routes } from '../../Openfort/types.js';
13
13
  import { useOpenfort } from '../../Openfort/useOpenfort.js';
14
14
  import { PageContent } from '../../PageContent/index.js';
@@ -63,7 +63,7 @@ const Receive = () => {
63
63
  const timer = setTimeout(() => context.triggerResize(), 100);
64
64
  return () => clearTimeout(timer);
65
65
  }, [address, context]);
66
- return (jsx(PageContent, { onBack: isSolanaRoute ? routes.SOL_CONNECTED : routes.CONNECTED, children: jsxs(ReceiveContent, { children: [jsx(ModalHeading, { children: "Receive funds" }), jsx(ModalBody, { children: "Scan the QR code or copy your wallet details." }), address && (jsx(QRWrapper, { children: jsx(CustomQRCode, { value: qrValue, image: jsx("div", { style: { padding: 10 }, children: renderLogo() }) }) })), jsxs(AddressSection, { children: [jsx(Label, { children: "Your wallet address" }), jsxs(AddressRow, { children: [jsx(AddressField, { children: address !== null && address !== void 0 ? address : '--' }), jsx(CopyIconButton, { value: address !== null && address !== void 0 ? address : '' })] })] }), networkLabel && jsxs(NetworkInfo, { children: ["Network: ", networkLabel] })] }) }));
66
+ return (jsx(PageContent, { onBack: isSolanaRoute ? routes.SOL_CONNECTED : routes.CONNECTED, children: jsxs(ReceiveContent, { children: [jsx(ModalHeading, { children: "Receive money" }), address && (jsx(QRWrapper, { children: jsx(CustomQRCode, { value: qrValue, image: jsx("div", { style: { padding: 10 }, children: renderLogo() }) }) })), jsxs(AddressSection, { children: [jsx(Label, { children: "Your wallet address" }), jsxs(AddressRow, { children: [jsx(AddressField, { children: address !== null && address !== void 0 ? address : '--' }), jsx(CopyIconButton, { value: address !== null && address !== void 0 ? address : '' })] })] }), networkLabel && jsxs(NetworkInfo, { children: ["Network: ", networkLabel] })] }) }));
67
67
  };
68
68
 
69
69
  export { Receive as default };
@@ -1,19 +1,19 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
- import { useEffect, useState } from 'react';
2
+ import { useEffect } from 'react';
3
3
  import { formatUnits } from 'viem';
4
- import { TOKEN_LOGO, symbolToColor } from '../../../constants/logos.js';
4
+ import { currencyLogoUrl } from '../../../constants/logos.js';
5
5
  import { useSolanaWalletAssets } from '../../../solana/hooks/useSolanaWalletAssets.js';
6
6
  import { ModalHeading } from '../../Common/Modal/styles.js';
7
7
  import { routes } from '../../Openfort/types.js';
8
8
  import { useOpenfort } from '../../Openfort/useOpenfort.js';
9
- import { SelectTokenContent, EmptyState, TokenList, TokenButton, TokenLeftGroup, TokenInfo, TokenSymbol, TokenName, TokenBalance, TokenLogoArea, TokenLogoImg, TokenLogoFallback } from './styles.js';
9
+ import { AssetChainLogo } from '../Deposit/AssetChainLogo.js';
10
+ import { SelectTokenContent, EmptyState, TokenList, TokenButton, TokenLeftGroup, TokenInfo, TokenSymbol, TokenName, TokenBalance, TokenLogoArea } from './styles.js';
10
11
 
11
12
  const ZERO = BigInt(0);
13
+ /** Token logo with the Solana chain badge, matching the EVM picker. */
12
14
  function SolanaTokenLogo({ symbol }) {
13
- var _a;
14
- const [imgError, setImgError] = useState(false);
15
- const url = (_a = TOKEN_LOGO[symbol.toUpperCase()]) !== null && _a !== void 0 ? _a : null;
16
- return (jsx(TokenLogoArea, { children: url && !imgError ? (jsx(TokenLogoImg, { src: url, alt: symbol, onError: () => setImgError(true) })) : (jsx(TokenLogoFallback, { "$bg": symbolToColor(symbol), children: symbol.charAt(0).toUpperCase() })) }));
15
+ var _a, _b;
16
+ return (jsx(TokenLogoArea, { children: jsx(AssetChainLogo, { assetLogo: (_a = currencyLogoUrl(symbol)) !== null && _a !== void 0 ? _a : '', chainLogo: (_b = currencyLogoUrl('SOL')) !== null && _b !== void 0 ? _b : '', symbol: symbol }) }));
17
17
  }
18
18
  const SolanaSelectToken = () => {
19
19
  const { setSendForm, setRoute, triggerResize } = useOpenfort();
@@ -2,6 +2,8 @@ import { jsxs, jsx } from 'react/jsx-runtime';
2
2
  import { ChainTypeEnum } from '@openfort/openfort-js';
3
3
  import { useState, useEffect } from 'react';
4
4
  import { formatUnits } from 'viem';
5
+ import { currencyLogoUrl, chainLogoUrl } from '../../../constants/logos.js';
6
+ import { useEthereumEmbeddedWallet } from '../../../ethereum/hooks/useEthereumEmbeddedWallet.js';
5
7
  import { useEthereumWalletAssets } from '../../../ethereum/hooks/useEthereumWalletAssets.js';
6
8
  import { useOpenfortCore } from '../../../openfort/useOpenfort.js';
7
9
  import { Arrow, ArrowChevron, TextLinkButton } from '../../Common/Button/styles.js';
@@ -10,8 +12,9 @@ import { routes } from '../../Openfort/types.js';
10
12
  import { useOpenfort } from '../../Openfort/useOpenfort.js';
11
13
  import { EVM_BUY_CURRENCIES } from '../Buy/evmCurrencies.js';
12
14
  import { SOLANA_BUY_CURRENCIES } from '../Buy/solanaCurrencies.js';
15
+ import { AssetChainLogo } from '../Deposit/AssetChainLogo.js';
13
16
  import { getAssetSymbol, getAssetDecimals, formatBalanceWithSymbol } from '../Send/utils.js';
14
- import { SelectTokenContent, EmptyState, TokenList, TokenButton, TokenInfo, TokenSymbol, TokenName, TokenBalance } from './styles.js';
17
+ import { SelectTokenContent, EmptyState, TokenList, TokenButton, TokenLeftGroup, TokenLogoArea, TokenInfo, TokenSymbol, TokenName, TokenBalance } from './styles.js';
15
18
 
16
19
  const ZERO = BigInt(0);
17
20
  const usdFormatter = new Intl.NumberFormat('en-US', {
@@ -27,6 +30,7 @@ const SelectToken = ({ isBuyFlow }) => {
27
30
  triggerResize();
28
31
  }, [viewAllAssets]);
29
32
  const { chainType } = useOpenfortCore();
33
+ const { chainId } = useEthereumEmbeddedWallet();
30
34
  const { data: walletAssets, isLoading: isBalancesLoading } = useEthereumWalletAssets();
31
35
  // Buys pick from a fixed buyable-currency list (USDC first, then native) per
32
36
  // chain family, so the picker always has options even for a fresh wallet with no
@@ -68,7 +72,7 @@ const SelectToken = ({ isBuyFlow }) => {
68
72
  return jsx(EmptyState, { children: "No supported tokens found for this network yet." });
69
73
  }
70
74
  return (jsxs(TokenList, { children: [selectableTokens.map((token) => {
71
- var _a, _b, _c, _d, _e;
75
+ var _a, _b, _c, _d, _e, _f, _g;
72
76
  const key = token.type === 'erc20' ? token.address : 'native';
73
77
  const displaySymbol = getAssetSymbol(token);
74
78
  const displayName = ((_a = token.metadata) === null || _a === void 0 ? void 0 : _a.name) || displaySymbol || 'Unknown Token';
@@ -101,7 +105,7 @@ const SelectToken = ({ isBuyFlow }) => {
101
105
  }
102
106
  }
103
107
  }
104
- return (jsxs(TokenButton, { type: "button", onClick: () => handleSelect(token), style: { opacity: isDisabled ? 0.4 : 1, cursor: isDisabled ? 'not-allowed' : 'pointer' }, children: [jsxs(TokenInfo, { children: [jsx(TokenSymbol, { children: displayName }), isBuyFlow && jsx(TokenName, { children: displaySymbol })] }), isBuyFlow ? (jsx(Arrow, { width: "13", height: "12", viewBox: "0 0 13 12", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: jsx(ArrowChevron, { stroke: "currentColor", d: "M7.51431 1.5L11.757 5.74264M7.5 10.4858L11.7426 6.24314" }) })) : (jsxs(TokenInfo, { children: [jsx(TokenBalance, { children: balanceDisplay }), usdValue ? jsx(TokenName, { style: { textAlign: 'end' }, children: usdValue }) : null] }))] }, key));
108
+ return (jsxs(TokenButton, { type: "button", onClick: () => handleSelect(token), style: { opacity: isDisabled ? 0.4 : 1, cursor: isDisabled ? 'not-allowed' : 'pointer' }, children: [jsxs(TokenLeftGroup, { children: [jsx(TokenLogoArea, { children: jsx(AssetChainLogo, { assetLogo: (_f = currencyLogoUrl(displaySymbol)) !== null && _f !== void 0 ? _f : '', chainLogo: (_g = chainLogoUrl(chainId)) !== null && _g !== void 0 ? _g : '', symbol: displaySymbol }) }), jsxs(TokenInfo, { children: [jsx(TokenSymbol, { children: displayName }), isBuyFlow && jsx(TokenName, { children: displaySymbol })] })] }), isBuyFlow ? (jsx(Arrow, { width: "13", height: "12", viewBox: "0 0 13 12", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: jsx(ArrowChevron, { stroke: "currentColor", d: "M7.51431 1.5L11.757 5.74264M7.5 10.4858L11.7426 6.24314" }) })) : (jsxs(TokenInfo, { children: [jsx(TokenBalance, { children: balanceDisplay }), usdValue ? jsx(TokenName, { style: { textAlign: 'end' }, children: usdValue }) : null] }))] }, key));
105
109
  }), !isBuyFlow && (jsx(TextLinkButton, { type: "button", onClick: () => {
106
110
  setViewAllAssets(!viewAllAssets);
107
111
  }, children: viewAllAssets ? 'View less assets' : 'View all assets' }))] }));
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}