@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.
- package/build/components/Common/Modal/index.js +14 -0
- package/build/components/Common/Modal/index.js.map +1 -1
- package/build/components/Openfort/types.d.ts +1 -1
- package/build/components/Pages/AssetInventory/SolanaAssetInventory.js +47 -8
- package/build/components/Pages/AssetInventory/SolanaAssetInventory.js.map +1 -1
- package/build/components/Pages/AssetInventory/index.js +50 -6
- package/build/components/Pages/AssetInventory/index.js.map +1 -1
- package/build/components/Pages/Connected/EthereumConnected.js +2 -5
- package/build/components/Pages/Connected/EthereumConnected.js.map +1 -1
- package/build/components/Pages/DepositWallet/index.js +15 -10
- package/build/components/Pages/DepositWallet/index.js.map +1 -1
- package/build/components/Pages/ExportKey/index.js +44 -4
- package/build/components/Pages/ExportKey/index.js.map +1 -1
- package/build/components/Pages/ExportKey/styles.d.ts +5 -0
- package/build/components/Pages/ExportKey/styles.js +47 -0
- package/build/components/Pages/ExportKey/styles.js.map +1 -0
- package/build/components/Pages/Receive/index.js +2 -2
- package/build/components/Pages/SelectToken/SolanaSelectToken.js +7 -7
- package/build/components/Pages/SelectToken/index.js +7 -3
- package/build/components/Pages/SelectToken/index.js.map +1 -1
- package/build/components/Pages/Send/EthereumSend.js +25 -5
- package/build/components/Pages/Send/EthereumSend.js.map +1 -1
- package/build/components/Pages/Send/SolanaSend.js +23 -4
- package/build/components/Pages/Send/SolanaSend.js.map +1 -1
- package/build/components/Pages/Send/styles.d.ts +17 -11
- package/build/components/Pages/Send/styles.js +104 -49
- package/build/components/Pages/Send/styles.js.map +1 -1
- package/build/components/Pages/SendConfirmation/ConfirmationSummary.d.ts +3 -1
- package/build/components/Pages/SendConfirmation/ConfirmationSummary.js +2 -2
- package/build/components/Pages/SendConfirmation/EstimatedFees.d.ts +3 -1
- package/build/components/Pages/SendConfirmation/EstimatedFees.js +22 -15
- package/build/components/Pages/SendConfirmation/EstimatedFees.js.map +1 -1
- package/build/components/Pages/SendConfirmation/SolanaSendConfirmation.js +17 -5
- package/build/components/Pages/SendConfirmation/SolanaSendConfirmation.js.map +1 -1
- package/build/components/Pages/SendConfirmation/index.js +11 -5
- package/build/components/Pages/SendConfirmation/index.js.map +1 -1
- package/build/components/Pages/SendConfirmation/styles.d.ts +3 -1
- package/build/components/Pages/SendConfirmation/styles.js +20 -6
- package/build/components/Pages/SendConfirmation/styles.js.map +1 -1
- package/build/components/Pages/SignMessage/index.js +44 -19
- package/build/components/Pages/SignMessage/index.js.map +1 -1
- package/build/components/Pages/SignMessage/styles.d.ts +2 -3
- package/build/components/Pages/SignMessage/styles.js +19 -2
- package/build/components/Pages/SignMessage/styles.js.map +1 -1
- package/build/constants/defaultAssets.d.ts +18 -0
- package/build/constants/defaultAssets.js +70 -0
- package/build/constants/defaultAssets.js.map +1 -0
- package/build/hooks/openfort/useSignMessage.d.ts +2 -2
- package/build/hooks/openfort/useUI.js +4 -2
- package/build/hooks/openfort/useUI.js.map +1 -1
- package/build/solana/transfer.d.ts +12 -0
- package/build/solana/transfer.js +29 -1
- package/build/solana/transfer.js.map +1 -1
- package/build/version.d.ts +1 -1
- package/build/version.js +1 -1
- 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:
|
|
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,
|
|
2
|
+
import { useEffect, useMemo } from 'react';
|
|
3
3
|
import { formatUnits } from 'viem';
|
|
4
|
-
import {
|
|
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 {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
110
|
-
|
|
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:
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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
|
|
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 ? (
|
|
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
|
|
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
|
|
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
|
|
2
|
+
import { useEffect } from 'react';
|
|
3
3
|
import { formatUnits } from 'viem';
|
|
4
|
-
import {
|
|
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 {
|
|
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
|
-
|
|
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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|