@openfort/react 1.0.3 → 1.0.4
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/Openfort/types.d.ts +3 -0
- package/build/components/Pages/AssetInventory/index.js +127 -48
- package/build/components/Pages/AssetInventory/index.js.map +1 -1
- package/build/components/Pages/SelectToken/styles.d.ts +13 -0
- package/build/components/Pages/SelectToken/styles.js +103 -1
- package/build/components/Pages/SelectToken/styles.js.map +1 -1
- package/build/components/Pages/SendConfirmation/index.js +7 -0
- package/build/components/Pages/SendConfirmation/index.js.map +1 -1
- package/build/constants/logos.d.ts +2 -0
- package/build/constants/logos.js +58 -0
- package/build/constants/logos.js.map +1 -0
- package/build/ethereum/hooks/useEthereumWalletAssets.d.ts +25 -11
- package/build/ethereum/hooks/useEthereumWalletAssets.js +134 -14
- package/build/ethereum/hooks/useEthereumWalletAssets.js.map +1 -1
- package/build/index.d.ts +1 -1
- package/build/utils/index.d.ts +1 -1
- package/build/version.d.ts +1 -1
- package/build/version.js +1 -1
- package/package.json +1 -1
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { motion } from 'framer-motion';
|
|
3
|
+
import { useState, useEffect, useMemo } from 'react';
|
|
2
4
|
import { formatUnits } from 'viem';
|
|
5
|
+
import { TOKEN_LOGO, symbolToColor } from '../../../constants/logos.js';
|
|
3
6
|
import { useEthereumWalletAssets } from '../../../ethereum/hooks/useEthereumWalletAssets.js';
|
|
7
|
+
import Chain from '../../Common/Chain/index.js';
|
|
4
8
|
import { ModalHeading } from '../../Common/Modal/styles.js';
|
|
5
|
-
import {
|
|
6
|
-
import { SelectTokenContent, TokenList, TokenContainer, TokenInfo, TokenSymbol, TokenBalance,
|
|
7
|
-
import { getAssetSymbol, getAssetDecimals
|
|
9
|
+
import { useOpenfort } from '../../Openfort/useOpenfort.js';
|
|
10
|
+
import { SelectTokenContent, EmptyState, ContentWrapper, ChainGroup, ChainGroupHeader, TokenPill, TokenPillSymbol, InfoLink, TokenList, TokenContainer, TokenLeftGroup, TokenInfo, TokenSymbol, TokenName, TokenBalance, TokenLogoArea, TokenLogoImg, TokenLogoFallback, ChainBadge } from '../SelectToken/styles.js';
|
|
11
|
+
import { getAssetSymbol, getAssetDecimals } from '../Send/utils.js';
|
|
8
12
|
|
|
9
13
|
const ZERO = BigInt(0);
|
|
10
14
|
const usdFormatter = new Intl.NumberFormat('en-US', {
|
|
@@ -13,53 +17,128 @@ const usdFormatter = new Intl.NumberFormat('en-US', {
|
|
|
13
17
|
minimumFractionDigits: 2,
|
|
14
18
|
maximumFractionDigits: 2,
|
|
15
19
|
});
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
const priceFormatter = new Intl.NumberFormat('en-US', {
|
|
21
|
+
style: 'currency',
|
|
22
|
+
currency: 'USD',
|
|
23
|
+
minimumFractionDigits: 2,
|
|
24
|
+
maximumFractionDigits: 4,
|
|
25
|
+
});
|
|
26
|
+
function getTokenLogoUrl(token) {
|
|
27
|
+
var _a;
|
|
28
|
+
const symbol = getAssetSymbol(token).toUpperCase();
|
|
29
|
+
return (_a = TOKEN_LOGO[symbol]) !== null && _a !== void 0 ? _a : null;
|
|
30
|
+
}
|
|
31
|
+
function TokenLogo({ token }) {
|
|
32
|
+
const [imgError, setImgError] = useState(false);
|
|
33
|
+
const symbol = getAssetSymbol(token);
|
|
34
|
+
const logoUrl = getTokenLogoUrl(token);
|
|
35
|
+
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
|
+
}
|
|
37
|
+
function renderTokenRow(token) {
|
|
38
|
+
var _a, _b, _c, _d;
|
|
39
|
+
const key = token.type === 'erc20' ? `${token.chainId}-${token.address}` : `${token.chainId}-native`;
|
|
40
|
+
const displaySymbol = getAssetSymbol(token);
|
|
41
|
+
const displayName = ((_a = token.metadata) === null || _a === void 0 ? void 0 : _a.name) || displaySymbol || 'Unknown Token';
|
|
42
|
+
const decimals = getAssetDecimals(token);
|
|
43
|
+
const pricePerToken = (_c = (_b = token.metadata) === null || _b === void 0 ? void 0 : _b.fiat) === null || _c === void 0 ? void 0 : _c.value;
|
|
44
|
+
let usdValue = null;
|
|
45
|
+
let balanceNum = '';
|
|
46
|
+
let priceDisplay = null;
|
|
47
|
+
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
|
+
if (isBalanceLoaded && token.balance !== undefined) {
|
|
52
|
+
const amount = parseFloat(formatUnits(token.balance, decimals));
|
|
53
|
+
if (Number.isFinite(amount)) {
|
|
54
|
+
balanceNum = `${amount.toLocaleString('en-US', { minimumFractionDigits: 0, maximumFractionDigits: 4 })} ${displaySymbol}`;
|
|
55
|
+
if (pricePerToken !== undefined) {
|
|
56
|
+
const totalUsd = amount * pricePerToken;
|
|
57
|
+
if (totalUsd >= 0.01) {
|
|
58
|
+
usdValue = usdFormatter.format(totalUsd);
|
|
59
|
+
}
|
|
60
|
+
else if (totalUsd > 0) {
|
|
61
|
+
usdValue = '<$0.01';
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
usdValue = usdFormatter.format(0);
|
|
65
|
+
}
|
|
66
|
+
priceDisplay = `@${priceFormatter.format(pricePerToken)}`;
|
|
24
67
|
}
|
|
25
|
-
return jsx(EmptyState, { children: "No supported tokens found for this network yet." });
|
|
26
68
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
};
|
|
62
|
-
|
|
69
|
+
}
|
|
70
|
+
return (jsxs(TokenContainer, { children: [jsxs(TokenLeftGroup, { children: [jsx(TokenLogo, { token: token }), jsxs(TokenInfo, { style: { textAlign: 'left' }, children: [jsx(TokenSymbol, { children: displayName }), jsx(TokenName, { children: balanceNum || 'Loading...' })] })] }), jsxs(TokenInfo, { children: [usdValue ? jsx(TokenBalance, { children: usdValue }) : null, priceDisplay ? jsx(TokenName, { style: { textAlign: 'end' }, children: priceDisplay }) : null] })] }, key));
|
|
71
|
+
}
|
|
72
|
+
const PILL_LOGO_SIZE = 16;
|
|
73
|
+
function PillLogo({ symbol }) {
|
|
74
|
+
var _a;
|
|
75
|
+
const [imgError, setImgError] = useState(false);
|
|
76
|
+
const url = (_a = TOKEN_LOGO[symbol.toUpperCase()]) !== null && _a !== void 0 ? _a : null;
|
|
77
|
+
if (!url || imgError) {
|
|
78
|
+
return (jsx("span", { style: {
|
|
79
|
+
width: PILL_LOGO_SIZE,
|
|
80
|
+
height: PILL_LOGO_SIZE,
|
|
81
|
+
borderRadius: '50%',
|
|
82
|
+
background: symbolToColor(symbol),
|
|
83
|
+
display: 'inline-flex',
|
|
84
|
+
alignItems: 'center',
|
|
85
|
+
justifyContent: 'center',
|
|
86
|
+
fontSize: 9,
|
|
87
|
+
fontWeight: 700,
|
|
88
|
+
color: '#fff',
|
|
89
|
+
flexShrink: 0,
|
|
90
|
+
}, children: symbol.charAt(0).toUpperCase() }));
|
|
91
|
+
}
|
|
92
|
+
return (jsx("img", { src: url, alt: symbol, onError: () => setImgError(true), style: {
|
|
93
|
+
width: PILL_LOGO_SIZE,
|
|
94
|
+
height: PILL_LOGO_SIZE,
|
|
95
|
+
borderRadius: '50%',
|
|
96
|
+
objectFit: 'cover',
|
|
97
|
+
flexShrink: 0,
|
|
98
|
+
} }));
|
|
99
|
+
}
|
|
100
|
+
const AssetInventory = () => {
|
|
101
|
+
var _a;
|
|
102
|
+
const { data, multiChain, isLoading: isBalancesLoading } = useEthereumWalletAssets({ multiChain: true });
|
|
103
|
+
const { triggerResize, chains } = useOpenfort();
|
|
104
|
+
const [showDetails, setShowDetails] = useState(false);
|
|
105
|
+
useEffect(() => {
|
|
106
|
+
if (!isBalancesLoading)
|
|
107
|
+
triggerResize();
|
|
108
|
+
}, [isBalancesLoading]);
|
|
109
|
+
useEffect(() => {
|
|
110
|
+
triggerResize();
|
|
111
|
+
}, [showDetails]);
|
|
112
|
+
const tokens = (_a = (multiChain ? data : null)) !== null && _a !== void 0 ? _a : [];
|
|
113
|
+
const hasBalance = tokens.some((t) => t.balance > ZERO);
|
|
114
|
+
const chainNameMap = useMemo(() => {
|
|
115
|
+
const map = new Map();
|
|
116
|
+
for (const c of chains)
|
|
117
|
+
map.set(c.id, c.name);
|
|
118
|
+
return map;
|
|
119
|
+
}, [chains]);
|
|
120
|
+
const groupedByChain = useMemo(() => {
|
|
121
|
+
var _a;
|
|
122
|
+
const groups = new Map();
|
|
123
|
+
for (const t of tokens) {
|
|
124
|
+
if (!groups.has(t.chainId))
|
|
125
|
+
groups.set(t.chainId, []);
|
|
126
|
+
groups.get(t.chainId).push({
|
|
127
|
+
symbol: getAssetSymbol(t),
|
|
128
|
+
name: ((_a = t.metadata) === null || _a === void 0 ? void 0 : _a.name) || getAssetSymbol(t),
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
return groups;
|
|
132
|
+
}, [tokens]);
|
|
133
|
+
if (isBalancesLoading) {
|
|
134
|
+
return (jsxs(SelectTokenContent, { children: [jsx(ModalHeading, { children: "Your assets" }), jsx(EmptyState, { children: "Loading balances..." })] }));
|
|
135
|
+
}
|
|
136
|
+
if (showDetails) {
|
|
137
|
+
return (jsxs(SelectTokenContent, { onBack: () => {
|
|
138
|
+
setShowDetails(false);
|
|
139
|
+
}, 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
|
+
}
|
|
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"));
|
|
63
142
|
};
|
|
64
143
|
|
|
65
144
|
export { AssetInventory };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -12,4 +12,17 @@ export declare const TokenInfo: import("styled-components").StyledComponent<"div
|
|
|
12
12
|
export declare const TokenSymbol: import("styled-components").StyledComponent<"span", any, {}, never>;
|
|
13
13
|
export declare const TokenName: import("styled-components").StyledComponent<"span", any, {}, never>;
|
|
14
14
|
export declare const TokenBalance: import("styled-components").StyledComponent<"span", any, {}, never>;
|
|
15
|
+
export declare const TokenLeftGroup: import("styled-components").StyledComponent<"div", any, {}, never>;
|
|
16
|
+
export declare const TokenLogoArea: import("styled-components").StyledComponent<"div", any, {}, never>;
|
|
17
|
+
export declare const TokenLogoFallback: import("styled-components").StyledComponent<"div", any, {
|
|
18
|
+
$bg: string;
|
|
19
|
+
}, never>;
|
|
20
|
+
export declare const TokenLogoImg: import("styled-components").StyledComponent<"img", any, {}, never>;
|
|
21
|
+
export declare const ChainBadge: import("styled-components").StyledComponent<"div", any, {}, never>;
|
|
15
22
|
export declare const EmptyState: import("styled-components").StyledComponent<"div", any, {}, never>;
|
|
23
|
+
export declare const InfoLink: import("styled-components").StyledComponent<"button", any, {}, never>;
|
|
24
|
+
export declare const ContentWrapper: import("styled-components").StyledComponent<"div", any, {}, never>;
|
|
25
|
+
export declare const ChainGroup: import("styled-components").StyledComponent<"div", any, {}, never>;
|
|
26
|
+
export declare const ChainGroupHeader: import("styled-components").StyledComponent<"div", any, {}, never>;
|
|
27
|
+
export declare const TokenPill: import("styled-components").StyledComponent<"div", any, {}, never>;
|
|
28
|
+
export declare const TokenPillSymbol: import("styled-components").StyledComponent<"span", any, {}, never>;
|
|
@@ -67,12 +67,114 @@ const TokenBalance = styled.span `
|
|
|
67
67
|
font-weight: 600;
|
|
68
68
|
color: var(--ck-body-color);
|
|
69
69
|
`;
|
|
70
|
+
const TokenLeftGroup = styled.div `
|
|
71
|
+
display: flex;
|
|
72
|
+
align-items: center;
|
|
73
|
+
gap: 10px;
|
|
74
|
+
min-width: 0;
|
|
75
|
+
`;
|
|
76
|
+
const TokenLogoArea = styled.div `
|
|
77
|
+
position: relative;
|
|
78
|
+
width: 40px;
|
|
79
|
+
height: 40px;
|
|
80
|
+
flex-shrink: 0;
|
|
81
|
+
`;
|
|
82
|
+
const TokenLogoFallback = styled.div `
|
|
83
|
+
width: 40px;
|
|
84
|
+
height: 40px;
|
|
85
|
+
border-radius: 50%;
|
|
86
|
+
background: ${(p) => p.$bg};
|
|
87
|
+
display: flex;
|
|
88
|
+
align-items: center;
|
|
89
|
+
justify-content: center;
|
|
90
|
+
font-size: 16px;
|
|
91
|
+
font-weight: 700;
|
|
92
|
+
color: #fff;
|
|
93
|
+
user-select: none;
|
|
94
|
+
`;
|
|
95
|
+
const TokenLogoImg = styled.img `
|
|
96
|
+
width: 40px;
|
|
97
|
+
height: 40px;
|
|
98
|
+
border-radius: 50%;
|
|
99
|
+
object-fit: cover;
|
|
100
|
+
`;
|
|
101
|
+
const ChainBadge = styled.div `
|
|
102
|
+
position: absolute;
|
|
103
|
+
bottom: -2px;
|
|
104
|
+
right: -2px;
|
|
105
|
+
width: 18px;
|
|
106
|
+
height: 18px;
|
|
107
|
+
border-radius: 50%;
|
|
108
|
+
background: var(--ck-body-background);
|
|
109
|
+
display: flex;
|
|
110
|
+
align-items: center;
|
|
111
|
+
justify-content: center;
|
|
112
|
+
box-shadow: 0 0 0 0.7px var(--ck-body-background);
|
|
113
|
+
`;
|
|
70
114
|
const EmptyState = styled.div `
|
|
71
115
|
margin-top: 28px;
|
|
72
116
|
font-size: 13px;
|
|
73
117
|
color: var(--ck-body-color-muted);
|
|
74
118
|
text-align: center;
|
|
75
119
|
`;
|
|
120
|
+
const InfoLink = styled.button `
|
|
121
|
+
all: unset;
|
|
122
|
+
display: flex;
|
|
123
|
+
align-items: center;
|
|
124
|
+
justify-content: center;
|
|
125
|
+
gap: 5px;
|
|
126
|
+
width: 100%;
|
|
127
|
+
font-size: 13px;
|
|
128
|
+
font-weight: 400;
|
|
129
|
+
color: var(--ck-body-color-muted, rgba(255, 255, 255, 0.4));
|
|
130
|
+
padding: 0 0 8px;
|
|
131
|
+
cursor: pointer;
|
|
132
|
+
transition: color 0.15s ease;
|
|
133
|
+
svg { opacity: 0.6; }
|
|
134
|
+
&:hover {
|
|
135
|
+
color: var(--ck-body-color, #fff);
|
|
136
|
+
svg { opacity: 1; }
|
|
137
|
+
}
|
|
138
|
+
`;
|
|
139
|
+
const ContentWrapper = styled.div `
|
|
140
|
+
position: relative;
|
|
141
|
+
display: flex;
|
|
142
|
+
flex-direction: column;
|
|
143
|
+
flex: 1;
|
|
144
|
+
min-height: 0;
|
|
145
|
+
`;
|
|
146
|
+
const ChainGroup = styled.div `
|
|
147
|
+
&:not(:first-child) {
|
|
148
|
+
margin-top: 16px;
|
|
149
|
+
}
|
|
150
|
+
`;
|
|
151
|
+
const ChainGroupHeader = styled.div `
|
|
152
|
+
display: flex;
|
|
153
|
+
align-items: center;
|
|
154
|
+
gap: 8px;
|
|
155
|
+
font-size: 14px;
|
|
156
|
+
font-weight: 600;
|
|
157
|
+
color: var(--ck-body-color, #fff);
|
|
158
|
+
margin-bottom: 8px;
|
|
159
|
+
`;
|
|
160
|
+
const TokenPill = styled.div `
|
|
161
|
+
display: flex;
|
|
162
|
+
align-items: center;
|
|
163
|
+
gap: 6px;
|
|
164
|
+
padding: 6px 10px;
|
|
165
|
+
border-radius: 10px;
|
|
166
|
+
background: var(--ck-body-background-secondary, rgba(255, 255, 255, 0.06));
|
|
167
|
+
font-size: 13px;
|
|
168
|
+
font-weight: 500;
|
|
169
|
+
color: var(--ck-body-color-muted, rgba(255, 255, 255, 0.6));
|
|
170
|
+
&:not(:last-child) {
|
|
171
|
+
margin-bottom: 4px;
|
|
172
|
+
}
|
|
173
|
+
`;
|
|
174
|
+
const TokenPillSymbol = styled.span `
|
|
175
|
+
color: var(--ck-body-color, #fff);
|
|
176
|
+
font-weight: 600;
|
|
177
|
+
`;
|
|
76
178
|
|
|
77
|
-
export { EmptyState, SelectTokenContent, TokenBalance, TokenButton, TokenContainer, TokenInfo, TokenList, TokenName, TokenSymbol };
|
|
179
|
+
export { ChainBadge, ChainGroup, ChainGroupHeader, ContentWrapper, EmptyState, InfoLink, SelectTokenContent, TokenBalance, TokenButton, TokenContainer, TokenInfo, TokenLeftGroup, TokenList, TokenLogoArea, TokenLogoFallback, TokenLogoImg, TokenName, TokenPill, TokenPillSymbol, TokenSymbol };
|
|
78
180
|
//# sourceMappingURL=styles.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"styles.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"styles.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -116,6 +116,7 @@ const SendConfirmation = () => {
|
|
|
116
116
|
const [isPollingBalance, setIsPollingBalance] = useState(false);
|
|
117
117
|
const originalBalanceRef = useRef(undefined);
|
|
118
118
|
const pollingIntervalRef = useRef(null);
|
|
119
|
+
const submittingRef = useRef(false);
|
|
119
120
|
// Inline transaction state management (replaces useEthereumSendTransaction + useEthereumWriteContract)
|
|
120
121
|
const [nativeTxHash, setNativeTxHash] = useState(undefined);
|
|
121
122
|
const [isNativePending, setIsNativePending] = useState(false);
|
|
@@ -255,8 +256,11 @@ const SendConfirmation = () => {
|
|
|
255
256
|
}
|
|
256
257
|
}, [isPollingBalance, currentBalance]);
|
|
257
258
|
const handleConfirm = async () => {
|
|
259
|
+
if (submittingRef.current)
|
|
260
|
+
return;
|
|
258
261
|
if (!recipientAddress || !parsedAmount || parsedAmount <= BigInt(0) || insufficientBalance)
|
|
259
262
|
return;
|
|
263
|
+
submittingRef.current = true;
|
|
260
264
|
try {
|
|
261
265
|
if (token.type === 'native') {
|
|
262
266
|
await sendTransactionAsync({
|
|
@@ -278,6 +282,9 @@ const SendConfirmation = () => {
|
|
|
278
282
|
catch (_error) {
|
|
279
283
|
// Errors are surfaced through mutation hooks
|
|
280
284
|
}
|
|
285
|
+
finally {
|
|
286
|
+
submittingRef.current = false;
|
|
287
|
+
}
|
|
281
288
|
};
|
|
282
289
|
const handleCancel = () => {
|
|
283
290
|
// Keep the current token, amount, and recipient when going back - don't reset
|
|
@@ -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,58 @@
|
|
|
1
|
+
const TW = 'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains';
|
|
2
|
+
// Unified symbol -> logo URL map (works for both native and ERC20)
|
|
3
|
+
const TOKEN_LOGO = {
|
|
4
|
+
// Native tokens (chain logos from Trust Wallet info/)
|
|
5
|
+
ETH: `${TW}/ethereum/info/logo.png`,
|
|
6
|
+
BNB: `${TW}/smartchain/info/logo.png`,
|
|
7
|
+
TBNB: `${TW}/smartchain/info/logo.png`,
|
|
8
|
+
MATIC: `${TW}/polygon/info/logo.png`,
|
|
9
|
+
POL: `${TW}/polygon/info/logo.png`,
|
|
10
|
+
AVAX: `${TW}/avalanchec/info/logo.png`,
|
|
11
|
+
FTM: `${TW}/fantom/info/logo.png`,
|
|
12
|
+
CELO: `${TW}/celo/info/logo.png`,
|
|
13
|
+
FIL: `${TW}/filecoin/info/logo.png`,
|
|
14
|
+
METIS: `${TW}/metis/info/logo.png`,
|
|
15
|
+
IOTX: `${TW}/iotex/info/logo.png`,
|
|
16
|
+
EVMOS: `${TW}/evmos/info/logo.png`,
|
|
17
|
+
XDAI: `${TW}/xdai/info/logo.png`,
|
|
18
|
+
FLR: `${TW}/flare/info/logo.png`,
|
|
19
|
+
TLOS: `${TW}/telos/info/logo.png`,
|
|
20
|
+
// ERC20 tokens (using mainnet Ethereum addresses)
|
|
21
|
+
USDC: `${TW}/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png`,
|
|
22
|
+
USDT: `${TW}/ethereum/assets/0xdAC17F958D2ee523a2206206994597C13D831ec7/logo.png`,
|
|
23
|
+
DAI: `${TW}/ethereum/assets/0x6B175474E89094C44Da98b954EedeAC495271d0F/logo.png`,
|
|
24
|
+
WETH: `${TW}/ethereum/assets/0xC02aaA39b223FE8D0A0e5c4F27eAD9083C756Cc2/logo.png`,
|
|
25
|
+
WBTC: `${TW}/ethereum/assets/0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599/logo.png`,
|
|
26
|
+
LINK: `${TW}/ethereum/assets/0x514910771AF9Ca656af840dff83E8264EcF986CA/logo.png`,
|
|
27
|
+
UNI: `${TW}/ethereum/assets/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984/logo.png`,
|
|
28
|
+
AAVE: `${TW}/ethereum/assets/0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9/logo.png`,
|
|
29
|
+
MKR: `${TW}/ethereum/assets/0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2/logo.png`,
|
|
30
|
+
CRV: `${TW}/ethereum/assets/0xD533a949740bb3306d119CC777fa900bA034cd52/logo.png`,
|
|
31
|
+
LDO: `${TW}/ethereum/assets/0x5A98FcBEA516Cf06857215779Fd812CA3beF1B32/logo.png`,
|
|
32
|
+
SHIB: `${TW}/ethereum/assets/0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE/logo.png`,
|
|
33
|
+
ARB: `${TW}/arbitrum/assets/0x912CE59144191C1204E64559FE8253a0e49E6548/logo.png`,
|
|
34
|
+
OP: `${TW}/optimism/assets/0x4200000000000000000000000000000000000042/logo.png`,
|
|
35
|
+
STETH: `${TW}/ethereum/assets/0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84/logo.png`,
|
|
36
|
+
CBETH: `${TW}/ethereum/assets/0xBe9895146f7AF43049ca1c1AE358B0541Ea49704/logo.png`,
|
|
37
|
+
RETH: `${TW}/ethereum/assets/0xae78736Cd615f374D3085123A210448E74Fc6393/logo.png`,
|
|
38
|
+
GRT: `${TW}/ethereum/assets/0xc944E90C64B2c07662A292be6244BDf05Cda44a7/logo.png`,
|
|
39
|
+
SNX: `${TW}/ethereum/assets/0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F/logo.png`,
|
|
40
|
+
COMP: `${TW}/ethereum/assets/0xc00e94Cb662C3520282E6f5717214004A7f26888/logo.png`,
|
|
41
|
+
PEPE: `${TW}/ethereum/assets/0x6982508145454Ce325dDbE47a25d4ec3d2311933/logo.png`,
|
|
42
|
+
SUSHI: `${TW}/ethereum/assets/0x6B3595068778DD592e39A122f4f5a5cF09C90fE2/logo.png`,
|
|
43
|
+
DYDX: `${TW}/ethereum/assets/0x92D6C1e31e14520e676a687F0a93788B716BEff5/logo.png`,
|
|
44
|
+
BEAM: `${TW}/ethereum/assets/0x62D0A8458eD7719FDAF978fe5929C6D342B0bFcE/logo.png`,
|
|
45
|
+
EUL: `${TW}/ethereum/assets/0xd9Fcd98c322942075A5C3860693e9f4f03AAE07b/logo.png`,
|
|
46
|
+
};
|
|
47
|
+
// Deterministic color from symbol string (only used if no logo is found)
|
|
48
|
+
function symbolToColor(symbol) {
|
|
49
|
+
let hash = 0;
|
|
50
|
+
for (let i = 0; i < symbol.length; i++) {
|
|
51
|
+
hash = symbol.charCodeAt(i) + ((hash << 5) - hash);
|
|
52
|
+
}
|
|
53
|
+
const h = ((hash % 360) + 360) % 360;
|
|
54
|
+
return `hsl(${h}, 55%, 50%)`;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export { TOKEN_LOGO, symbolToColor };
|
|
58
|
+
//# sourceMappingURL=logos.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logos.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -1,29 +1,43 @@
|
|
|
1
|
-
import type { Asset } from '../../components/Openfort/types';
|
|
1
|
+
import type { Asset, MultiChainAsset } from '../../components/Openfort/types';
|
|
2
2
|
import { OpenfortError } from '../../core/errors';
|
|
3
3
|
import type { EthereumConfig } from '../../ethereum/types';
|
|
4
4
|
type UseEthereumWalletAssetsOptions = {
|
|
5
5
|
assets?: EthereumConfig['assets'];
|
|
6
|
+
/** When true, fetches assets for all configured chains and returns MultiChainAsset[]. */
|
|
7
|
+
multiChain?: boolean;
|
|
6
8
|
staleTime?: number;
|
|
7
9
|
};
|
|
10
|
+
type WalletAssetsReturnBase = {
|
|
11
|
+
isLoading: boolean;
|
|
12
|
+
isError: boolean;
|
|
13
|
+
isSuccess: boolean;
|
|
14
|
+
isIdle: boolean;
|
|
15
|
+
error: OpenfortError | undefined;
|
|
16
|
+
refetch: () => Promise<unknown>;
|
|
17
|
+
};
|
|
18
|
+
type UseEthereumWalletAssetsResult = (WalletAssetsReturnBase & {
|
|
19
|
+
multiChain: true;
|
|
20
|
+
data: readonly MultiChainAsset[] | null;
|
|
21
|
+
}) | (WalletAssetsReturnBase & {
|
|
22
|
+
multiChain: false;
|
|
23
|
+
data: readonly Asset[] | null;
|
|
24
|
+
});
|
|
8
25
|
/**
|
|
9
26
|
* Returns wallet assets (tokens, NFTs) for the connected Ethereum address.
|
|
10
27
|
* Uses ERC-7811 via Openfort's authenticated RPC proxy.
|
|
11
28
|
*
|
|
12
|
-
*
|
|
29
|
+
* When `multiChain` is true, fetches assets across all configured chains
|
|
30
|
+
* via `wallet_getAssets` and returns `MultiChainAsset[]` (assets tagged with `chainId`).
|
|
31
|
+
*
|
|
32
|
+
* @param options - Optional custom assets config, multiChain flag, and staleTime
|
|
13
33
|
* @returns assets, isLoading, error, refetch
|
|
14
34
|
*
|
|
15
35
|
* @example
|
|
16
36
|
* ```tsx
|
|
17
37
|
* const { data: assets, isLoading } = useEthereumWalletAssets()
|
|
38
|
+
* // Multi-chain:
|
|
39
|
+
* const { data, multiChain } = useEthereumWalletAssets({ multiChain: true })
|
|
18
40
|
* ```
|
|
19
41
|
*/
|
|
20
|
-
export declare const useEthereumWalletAssets: ({ assets: hookCustomAssets, staleTime, }?: UseEthereumWalletAssetsOptions) =>
|
|
21
|
-
data: readonly Asset[] | null;
|
|
22
|
-
isLoading: boolean;
|
|
23
|
-
isError: boolean;
|
|
24
|
-
isSuccess: boolean;
|
|
25
|
-
isIdle: boolean;
|
|
26
|
-
error: OpenfortError | undefined;
|
|
27
|
-
refetch: () => Promise<readonly Asset[] | undefined>;
|
|
28
|
-
};
|
|
42
|
+
export declare const useEthereumWalletAssets: ({ assets: hookCustomAssets, multiChain, staleTime, }?: UseEthereumWalletAssetsOptions) => UseEthereumWalletAssetsResult;
|
|
29
43
|
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useCallback, useMemo } from 'react';
|
|
2
|
-
import { custom, createWalletClient,
|
|
2
|
+
import { numberToHex, custom, createWalletClient, formatUnits } from 'viem';
|
|
3
3
|
import { erc7811Actions } from 'viem/experimental';
|
|
4
4
|
import { useOpenfort } from '../../components/Openfort/useOpenfort.js';
|
|
5
5
|
import { OpenfortError, OpenfortReactErrorType } from '../../types.js';
|
|
@@ -8,20 +8,34 @@ import { openfortKeys } from '../../query/queryKeys.js';
|
|
|
8
8
|
import { useAsyncData } from '../../shared/hooks/useAsyncData.js';
|
|
9
9
|
import { useEthereumEmbeddedWallet } from './useEthereumEmbeddedWallet.js';
|
|
10
10
|
|
|
11
|
+
function getUsdValue(asset) {
|
|
12
|
+
var _a, _b, _c;
|
|
13
|
+
const fiat = (_a = asset.metadata) === null || _a === void 0 ? void 0 : _a.fiat;
|
|
14
|
+
if (!(fiat === null || fiat === void 0 ? void 0 : fiat.value) || asset.balance === undefined)
|
|
15
|
+
return 0;
|
|
16
|
+
const decimals = (_c = (_b = asset.metadata) === null || _b === void 0 ? void 0 : _b.decimals) !== null && _c !== void 0 ? _c : 18;
|
|
17
|
+
const amount = Number.parseFloat(formatUnits(asset.balance, decimals));
|
|
18
|
+
return Number.isFinite(amount) ? amount * fiat.value : 0;
|
|
19
|
+
}
|
|
11
20
|
/**
|
|
12
21
|
* Returns wallet assets (tokens, NFTs) for the connected Ethereum address.
|
|
13
22
|
* Uses ERC-7811 via Openfort's authenticated RPC proxy.
|
|
14
23
|
*
|
|
15
|
-
*
|
|
24
|
+
* When `multiChain` is true, fetches assets across all configured chains
|
|
25
|
+
* via `wallet_getAssets` and returns `MultiChainAsset[]` (assets tagged with `chainId`).
|
|
26
|
+
*
|
|
27
|
+
* @param options - Optional custom assets config, multiChain flag, and staleTime
|
|
16
28
|
* @returns assets, isLoading, error, refetch
|
|
17
29
|
*
|
|
18
30
|
* @example
|
|
19
31
|
* ```tsx
|
|
20
32
|
* const { data: assets, isLoading } = useEthereumWalletAssets()
|
|
33
|
+
* // Multi-chain:
|
|
34
|
+
* const { data, multiChain } = useEthereumWalletAssets({ multiChain: true })
|
|
21
35
|
* ```
|
|
22
36
|
*/
|
|
23
|
-
const useEthereumWalletAssets = ({ assets: hookCustomAssets, staleTime = 30000, } = {}) => {
|
|
24
|
-
var _a;
|
|
37
|
+
const useEthereumWalletAssets = ({ assets: hookCustomAssets, multiChain = false, staleTime = 30000, } = {}) => {
|
|
38
|
+
var _a, _b;
|
|
25
39
|
const wallet = useEthereumEmbeddedWallet();
|
|
26
40
|
const isConnected = wallet.status === 'connected';
|
|
27
41
|
const address = isConnected ? wallet.address : undefined;
|
|
@@ -29,6 +43,7 @@ const useEthereumWalletAssets = ({ assets: hookCustomAssets, staleTime = 30000,
|
|
|
29
43
|
const { walletConfig, publishableKey, overrides, thirdPartyAuth, chains } = useOpenfort();
|
|
30
44
|
const { getAccessToken } = useUser();
|
|
31
45
|
const chain = chains.find((c) => c.id === chainId);
|
|
46
|
+
const backendUrl = (overrides === null || overrides === void 0 ? void 0 : overrides.backendUrl) || 'https://api.openfort.io';
|
|
32
47
|
const buildHeaders = useCallback(async () => {
|
|
33
48
|
if (thirdPartyAuth) {
|
|
34
49
|
const accessToken = await thirdPartyAuth.getAccessToken();
|
|
@@ -51,10 +66,25 @@ const useEthereumWalletAssets = ({ assets: hookCustomAssets, staleTime = 30000,
|
|
|
51
66
|
};
|
|
52
67
|
return headers;
|
|
53
68
|
}, [publishableKey, getAccessToken, thirdPartyAuth]);
|
|
69
|
+
/** For multiChain: walletConfig.ethereum.assets as backend assetFilter format (hex chainId -> [{ address, type }]). */
|
|
70
|
+
const customAssetsMultiChain = useMemo(() => {
|
|
71
|
+
var _a;
|
|
72
|
+
if (!multiChain)
|
|
73
|
+
return undefined;
|
|
74
|
+
const configAssets = (_a = walletConfig === null || walletConfig === void 0 ? void 0 : walletConfig.ethereum) === null || _a === void 0 ? void 0 : _a.assets;
|
|
75
|
+
if (!configAssets)
|
|
76
|
+
return undefined;
|
|
77
|
+
const mapped = {};
|
|
78
|
+
for (const [cid, addresses] of Object.entries(configAssets)) {
|
|
79
|
+
const hexChainId = numberToHex(Number(cid));
|
|
80
|
+
mapped[hexChainId] = addresses.map((addr) => ({ address: addr, type: 'erc20' }));
|
|
81
|
+
}
|
|
82
|
+
return Object.keys(mapped).length > 0 ? mapped : undefined;
|
|
83
|
+
}, [multiChain, (_a = walletConfig === null || walletConfig === void 0 ? void 0 : walletConfig.ethereum) === null || _a === void 0 ? void 0 : _a.assets]);
|
|
54
84
|
const customTransport = useMemo(() => () => {
|
|
55
85
|
return custom({
|
|
56
86
|
async request({ method, params }) {
|
|
57
|
-
const res = await fetch(`${
|
|
87
|
+
const res = await fetch(`${backendUrl}/rpc`, {
|
|
58
88
|
method: 'POST',
|
|
59
89
|
headers: await buildHeaders(),
|
|
60
90
|
body: JSON.stringify({
|
|
@@ -71,7 +101,7 @@ const useEthereumWalletAssets = ({ assets: hookCustomAssets, staleTime = 30000,
|
|
|
71
101
|
return data.result;
|
|
72
102
|
},
|
|
73
103
|
});
|
|
74
|
-
}, [buildHeaders,
|
|
104
|
+
}, [buildHeaders, backendUrl]);
|
|
75
105
|
const customAssetsToFetch = useMemo(() => {
|
|
76
106
|
var _a;
|
|
77
107
|
if (!chainId)
|
|
@@ -80,11 +110,101 @@ const useEthereumWalletAssets = ({ assets: hookCustomAssets, staleTime = 30000,
|
|
|
80
110
|
const assetsFromHook = hookCustomAssets ? hookCustomAssets[chainId] || [] : [];
|
|
81
111
|
const allAssets = [...assetsFromConfig, ...assetsFromHook];
|
|
82
112
|
return allAssets;
|
|
83
|
-
}, [(
|
|
113
|
+
}, [(_b = walletConfig === null || walletConfig === void 0 ? void 0 : walletConfig.ethereum) === null || _b === void 0 ? void 0 : _b.assets, hookCustomAssets, chainId]);
|
|
84
114
|
const { data, error, isLoading, refetch } = useAsyncData({
|
|
85
|
-
queryKey:
|
|
115
|
+
queryKey: multiChain
|
|
116
|
+
? ['wallet-assets', 'multi', address, customAssetsMultiChain]
|
|
117
|
+
: [...openfortKeys.walletAssets(chainId, customAssetsToFetch, address)],
|
|
86
118
|
queryFn: async () => {
|
|
87
|
-
var _a, _b, _c, _d;
|
|
119
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
|
|
120
|
+
if (multiChain) {
|
|
121
|
+
if (!address) {
|
|
122
|
+
throw new OpenfortError('No wallet address available', OpenfortReactErrorType.UNEXPECTED_ERROR);
|
|
123
|
+
}
|
|
124
|
+
const headers = await buildHeaders();
|
|
125
|
+
const defaultRequest = fetch(`${backendUrl}/rpc`, {
|
|
126
|
+
method: 'POST',
|
|
127
|
+
headers,
|
|
128
|
+
body: JSON.stringify({
|
|
129
|
+
method: 'wallet_getAssets',
|
|
130
|
+
params: { account: address },
|
|
131
|
+
id: 1,
|
|
132
|
+
jsonrpc: '2.0',
|
|
133
|
+
}),
|
|
134
|
+
});
|
|
135
|
+
const customRequest = customAssetsMultiChain
|
|
136
|
+
? fetch(`${backendUrl}/rpc`, {
|
|
137
|
+
method: 'POST',
|
|
138
|
+
headers,
|
|
139
|
+
body: JSON.stringify({
|
|
140
|
+
method: 'wallet_getAssets',
|
|
141
|
+
params: { account: address, assetFilter: customAssetsMultiChain },
|
|
142
|
+
id: 2,
|
|
143
|
+
jsonrpc: '2.0',
|
|
144
|
+
}),
|
|
145
|
+
})
|
|
146
|
+
: null;
|
|
147
|
+
const responses = await Promise.all([defaultRequest, customRequest].filter(Boolean));
|
|
148
|
+
const [defaultData, customData] = await Promise.all(responses.map((r) => r.json()));
|
|
149
|
+
const result = { ...((_a = defaultData.result) !== null && _a !== void 0 ? _a : {}) };
|
|
150
|
+
if ((customData === null || customData === void 0 ? void 0 : customData.result) && typeof customData.result === 'object') {
|
|
151
|
+
for (const [chainKey, assets] of Object.entries(customData.result)) {
|
|
152
|
+
if (!Array.isArray(assets))
|
|
153
|
+
continue;
|
|
154
|
+
if (!result[chainKey]) {
|
|
155
|
+
result[chainKey] = assets;
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
const existing = new Map(result[chainKey].map((a) => { var _a; return [(_a = a.address) !== null && _a !== void 0 ? _a : '', a]; }));
|
|
159
|
+
for (const asset of assets) {
|
|
160
|
+
existing.set((_b = asset.address) !== null && _b !== void 0 ? _b : '', asset);
|
|
161
|
+
}
|
|
162
|
+
result[chainKey] = Array.from(existing.values());
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
const allAssets = [];
|
|
167
|
+
for (const [chainIdKey, assets] of Object.entries(result)) {
|
|
168
|
+
const cid = Number(chainIdKey);
|
|
169
|
+
if (!Array.isArray(assets))
|
|
170
|
+
continue;
|
|
171
|
+
for (const a of assets) {
|
|
172
|
+
if (a.type === 'erc20') {
|
|
173
|
+
const asset = {
|
|
174
|
+
type: 'erc20',
|
|
175
|
+
address: ((_c = a.address) !== null && _c !== void 0 ? _c : '0x0'),
|
|
176
|
+
balance: BigInt((_d = a.balance) !== null && _d !== void 0 ? _d : 0),
|
|
177
|
+
metadata: {
|
|
178
|
+
name: ((_e = a.metadata) === null || _e === void 0 ? void 0 : _e.name) || 'Unknown Token',
|
|
179
|
+
symbol: ((_f = a.metadata) === null || _f === void 0 ? void 0 : _f.symbol) || 'UNKNOWN',
|
|
180
|
+
decimals: (_g = a.metadata) === null || _g === void 0 ? void 0 : _g.decimals,
|
|
181
|
+
fiat: (_h = a.metadata) === null || _h === void 0 ? void 0 : _h.fiat,
|
|
182
|
+
},
|
|
183
|
+
raw: a,
|
|
184
|
+
};
|
|
185
|
+
allAssets.push({ ...asset, chainId: cid });
|
|
186
|
+
}
|
|
187
|
+
else if (a.type === 'native') {
|
|
188
|
+
const meta = ((_j = a.metadata) !== null && _j !== void 0 ? _j : {});
|
|
189
|
+
const asset = {
|
|
190
|
+
type: 'native',
|
|
191
|
+
address: 'native',
|
|
192
|
+
balance: BigInt((_k = a.balance) !== null && _k !== void 0 ? _k : 0),
|
|
193
|
+
metadata: {
|
|
194
|
+
symbol: meta.symbol || 'ETH',
|
|
195
|
+
decimals: meta.decimals,
|
|
196
|
+
fiat: (_l = meta.fiat) !== null && _l !== void 0 ? _l : { value: 0, currency: 'USD' },
|
|
197
|
+
},
|
|
198
|
+
raw: a,
|
|
199
|
+
};
|
|
200
|
+
allAssets.push({ ...asset, chainId: cid });
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
allAssets.sort((a, b) => getUsdValue(b) - getUsdValue(a));
|
|
205
|
+
return allAssets;
|
|
206
|
+
}
|
|
207
|
+
// Single-chain path
|
|
88
208
|
if (!address || !chainId || !chain) {
|
|
89
209
|
throw new OpenfortError('Wallet not connected', OpenfortReactErrorType.UNEXPECTED_ERROR, {
|
|
90
210
|
error: new Error('Address, chainId, or chain not available'),
|
|
@@ -115,8 +235,8 @@ const useEthereumWalletAssets = ({ assets: hookCustomAssets, staleTime = 30000,
|
|
|
115
235
|
// ERC-7811 response keys may be hex (e.g. "0x14a34") or numeric depending on the RPC
|
|
116
236
|
const rawByChain = defaultAssetsRaw;
|
|
117
237
|
const customByChain = customAssets;
|
|
118
|
-
const rawChainAssets = (
|
|
119
|
-
const customChainAssets = (
|
|
238
|
+
const rawChainAssets = (_o = (_m = rawByChain[hexChainId]) !== null && _m !== void 0 ? _m : rawByChain[String(chainId)]) !== null && _o !== void 0 ? _o : [];
|
|
239
|
+
const customChainAssets = (_q = (_p = customByChain[hexChainId]) !== null && _p !== void 0 ? _p : customByChain[String(chainId)]) !== null && _q !== void 0 ? _q : [];
|
|
120
240
|
const defaultAssets = rawChainAssets.map((a) => {
|
|
121
241
|
var _a;
|
|
122
242
|
let asset;
|
|
@@ -153,7 +273,6 @@ const useEthereumWalletAssets = ({ assets: hookCustomAssets, staleTime = 30000,
|
|
|
153
273
|
const mergedAssets = [...defaultAssets];
|
|
154
274
|
const customAssetsForChain = customChainAssets.flatMap((asset) => {
|
|
155
275
|
var _a, _b;
|
|
156
|
-
// Custom assets are explicitly requested as erc20; skip if the API returns something unexpected.
|
|
157
276
|
if (asset.type !== 'erc20')
|
|
158
277
|
return [];
|
|
159
278
|
if (!((_a = walletConfig === null || walletConfig === void 0 ? void 0 : walletConfig.ethereum) === null || _a === void 0 ? void 0 : _a.assets))
|
|
@@ -178,7 +297,7 @@ const useEthereumWalletAssets = ({ assets: hookCustomAssets, staleTime = 30000,
|
|
|
178
297
|
});
|
|
179
298
|
return mergedAssets;
|
|
180
299
|
},
|
|
181
|
-
enabled: isConnected && !!chainId && !!chain && !!address,
|
|
300
|
+
enabled: multiChain ? isConnected && !!address : isConnected && !!chainId && !!chain && !!address,
|
|
182
301
|
staleTime,
|
|
183
302
|
});
|
|
184
303
|
const mappedError = useMemo(() => {
|
|
@@ -191,10 +310,11 @@ const useEthereumWalletAssets = ({ assets: hookCustomAssets, staleTime = 30000,
|
|
|
191
310
|
}, [error]);
|
|
192
311
|
return {
|
|
193
312
|
data: data !== null && data !== void 0 ? data : null,
|
|
313
|
+
multiChain,
|
|
194
314
|
isLoading,
|
|
195
315
|
isError: !!error,
|
|
196
316
|
isSuccess: !!data && !error,
|
|
197
|
-
isIdle: !isConnected || !chainId || !chain,
|
|
317
|
+
isIdle: multiChain ? !address : !isConnected || !chainId || !chain,
|
|
198
318
|
error: mappedError,
|
|
199
319
|
refetch,
|
|
200
320
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useEthereumWalletAssets.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useEthereumWalletAssets.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
package/build/index.d.ts
CHANGED
|
@@ -44,7 +44,7 @@ export { default as Avatar } from './components/Common/Avatar';
|
|
|
44
44
|
export { default as ChainIcon } from './components/Common/Chain';
|
|
45
45
|
export { OpenfortButton } from './components/ConnectButton';
|
|
46
46
|
export { OpenfortProvider } from './components/Openfort/OpenfortProvider';
|
|
47
|
-
export type { CustomizableRoutes } from './components/Openfort/types';
|
|
47
|
+
export type { CustomizableRoutes, MultiChainAsset } from './components/Openfort/types';
|
|
48
48
|
export { LinkWalletOnSignUpOption, UIAuthProvider as AuthProvider } from './components/Openfort/types';
|
|
49
49
|
export { embeddedWalletId } from './constants/openfort';
|
|
50
50
|
export { OpenfortError, OpenfortReactErrorType, OpenfortReactErrorType as OpenfortErrorType, } from './core/errors';
|
package/build/utils/index.d.ts
CHANGED
|
@@ -9,4 +9,4 @@ declare function flattenChildren(children: React.ReactNode): ReactChildArray;
|
|
|
9
9
|
export declare const isWalletConnectConnector: (connectorId?: string) => connectorId is "walletConnect";
|
|
10
10
|
export declare const isCoinbaseWalletConnector: (connectorId?: string) => connectorId is "coinbaseWalletSDK";
|
|
11
11
|
export declare const isInjectedConnector: (connectorId?: string) => connectorId is "injected";
|
|
12
|
-
export {
|
|
12
|
+
export { detectBrowser, flattenChildren, isAndroid, isMobile, nFormatter, truncateEthAddress, truncateSolanaAddress };
|
package/build/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const OPENFORT_VERSION = "1.0.
|
|
1
|
+
export declare const OPENFORT_VERSION = "1.0.4";
|
package/build/version.js
CHANGED