@algobright/solana-connector 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{Button.module-HQNNX6IB.module.css → Button.module-QCTUNBHA.module.css} +1 -0
- package/dist/ConnectButton.d.mts +28 -0
- package/dist/ConnectButton.d.ts +28 -0
- package/dist/ConnectButton.js +191 -89
- package/dist/ConnectButton.js.map +1 -1
- package/dist/ConnectButton.mjs +164 -62
- package/dist/ConnectButton.mjs.map +1 -1
- package/dist/{ConnectButton.module-O3M32YJK.module.css → ConnectButton.module-AR6WQXQS.module.css} +0 -3
- package/dist/WalletDropdown.d.mts +23 -4
- package/dist/WalletDropdown.d.ts +23 -4
- package/dist/WalletDropdown.js +148 -41
- package/dist/WalletDropdown.js.map +1 -1
- package/dist/WalletDropdown.mjs +136 -29
- package/dist/WalletDropdown.mjs.map +1 -1
- package/dist/{WalletDropdown.module-A6KHWKGK.module.css → WalletDropdown.module-DOK7CUOQ.module.css} +1 -0
- package/dist/WalletModal.d.mts +13 -2
- package/dist/WalletModal.d.ts +13 -2
- package/dist/WalletModal.js +28 -30
- package/dist/WalletModal.js.map +1 -1
- package/dist/WalletModal.mjs +15 -17
- package/dist/WalletModal.mjs.map +1 -1
- package/package.json +8 -1
package/dist/WalletDropdown.js
CHANGED
|
@@ -36,9 +36,10 @@ __export(WalletDropdown_exports, {
|
|
|
36
36
|
module.exports = __toCommonJS(WalletDropdown_exports);
|
|
37
37
|
|
|
38
38
|
// src/components/WalletDropdown/WalletDropdown.tsx
|
|
39
|
-
var
|
|
40
|
-
var
|
|
41
|
-
var
|
|
39
|
+
var import_react3 = require("react");
|
|
40
|
+
var import_kit2 = require("@solana/kit");
|
|
41
|
+
var import_WalletDropdown = __toESM(require("./WalletDropdown.module-DOK7CUOQ.module.css"));
|
|
42
|
+
var import_react4 = require("motion/react");
|
|
42
43
|
|
|
43
44
|
// src/components/shared/Avatar/Avatar.tsx
|
|
44
45
|
var import_react = require("react");
|
|
@@ -72,11 +73,11 @@ var Avatar_default = Avatar;
|
|
|
72
73
|
var import_lucide_react2 = require("lucide-react");
|
|
73
74
|
|
|
74
75
|
// src/components/shared/Button/Button.tsx
|
|
75
|
-
var
|
|
76
|
+
var import_react2 = require("react");
|
|
76
77
|
var import_button = require("@base-ui/react/button");
|
|
77
|
-
var import_Button = __toESM(require("./Button.module-
|
|
78
|
+
var import_Button = __toESM(require("./Button.module-QCTUNBHA.module.css"));
|
|
78
79
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
79
|
-
var Button =
|
|
80
|
+
var Button = (0, import_react2.forwardRef)(
|
|
80
81
|
({ className, variant = "default", size = "default", ...props }, ref) => {
|
|
81
82
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
82
83
|
import_button.Button,
|
|
@@ -97,9 +98,68 @@ var Button_default = Button;
|
|
|
97
98
|
var Button_default2 = Button_default;
|
|
98
99
|
|
|
99
100
|
// src/components/WalletDropdown/WalletDropdown.tsx
|
|
101
|
+
var import_connector2 = require("@solana/connector");
|
|
102
|
+
var import_clsx = require("clsx");
|
|
103
|
+
|
|
104
|
+
// src/utils/fetchBalance.tsx
|
|
105
|
+
var import_token = require("@solana-program/token");
|
|
100
106
|
var import_connector = require("@solana/connector");
|
|
101
107
|
var import_kit = require("@solana/kit");
|
|
102
|
-
|
|
108
|
+
async function getSolBalance(client, pubkey) {
|
|
109
|
+
let balance = 0;
|
|
110
|
+
try {
|
|
111
|
+
const rpcUrl = client.getRpcUrl();
|
|
112
|
+
if (!rpcUrl) {
|
|
113
|
+
console.error("RPC URL is not available from the ConnectorClient.");
|
|
114
|
+
return 0;
|
|
115
|
+
}
|
|
116
|
+
const pubkeyAddress = (0, import_connector.address)(pubkey);
|
|
117
|
+
const rpc = (0, import_kit.createSolanaRpc)(rpcUrl);
|
|
118
|
+
const balanceResponse = await rpc.getBalance(pubkeyAddress).send();
|
|
119
|
+
balance = (0, import_connector.lamportsToSol)(balanceResponse.value);
|
|
120
|
+
} catch (error) {
|
|
121
|
+
console.error("Error fetching SOL balance:", error);
|
|
122
|
+
} finally {
|
|
123
|
+
return balance;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
async function getTokenBalance(client, pubkey, mintAddress) {
|
|
127
|
+
var _a;
|
|
128
|
+
let balance = 0;
|
|
129
|
+
try {
|
|
130
|
+
const rpcUrl = client.getRpcUrl();
|
|
131
|
+
if (!rpcUrl) {
|
|
132
|
+
console.error("RPC URL is not available from the ConnectorClient.");
|
|
133
|
+
return 0;
|
|
134
|
+
}
|
|
135
|
+
const pubkeyAddress = (0, import_connector.address)(pubkey);
|
|
136
|
+
const mintPubkey = (0, import_connector.address)(mintAddress);
|
|
137
|
+
const rpc = (0, import_kit.createSolanaRpc)(rpcUrl);
|
|
138
|
+
const mintInfo = await rpc.getAccountInfo(
|
|
139
|
+
mintPubkey,
|
|
140
|
+
{ encoding: "base64" }
|
|
141
|
+
).send();
|
|
142
|
+
const ownerProgram = (_a = mintInfo.value) == null ? void 0 : _a.owner;
|
|
143
|
+
if (!ownerProgram) {
|
|
144
|
+
throw new Error("Failed to fetch mint account info");
|
|
145
|
+
}
|
|
146
|
+
const tokenProgram = (0, import_connector.address)(ownerProgram);
|
|
147
|
+
const [tokenPDA] = await (0, import_token.findAssociatedTokenPda)({
|
|
148
|
+
mint: mintPubkey,
|
|
149
|
+
owner: pubkeyAddress,
|
|
150
|
+
tokenProgram
|
|
151
|
+
});
|
|
152
|
+
const tokenBalance = await rpc.getTokenAccountBalance(tokenPDA).send();
|
|
153
|
+
if (tokenBalance.value) {
|
|
154
|
+
balance = parseFloat(tokenBalance.value.uiAmountString);
|
|
155
|
+
}
|
|
156
|
+
} catch (error) {
|
|
157
|
+
} finally {
|
|
158
|
+
return balance;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// src/components/WalletDropdown/WalletDropdown.tsx
|
|
103
163
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
104
164
|
var networkColor = {
|
|
105
165
|
"solana:mainnet": "#00c950",
|
|
@@ -108,13 +168,26 @@ var networkColor = {
|
|
|
108
168
|
"solana:localnet": "#ff3b3b"
|
|
109
169
|
};
|
|
110
170
|
function WalletDropdown(props) {
|
|
111
|
-
const client = (0,
|
|
112
|
-
const {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
171
|
+
const client = (0, import_connector2.useConnectorClient)();
|
|
172
|
+
const {
|
|
173
|
+
CN_DropdownMenu,
|
|
174
|
+
theme = "light",
|
|
175
|
+
allowNetworkSwitch = true,
|
|
176
|
+
showSolBalance = true,
|
|
177
|
+
showDefaultToken
|
|
178
|
+
} = props;
|
|
179
|
+
const [view, setView] = (0, import_react3.useState)("wallet");
|
|
180
|
+
const [copied, setCopied] = (0, import_react3.useState)(false);
|
|
181
|
+
const { account, connector } = (0, import_connector2.useConnector)();
|
|
182
|
+
const fetchingSolBalance = (0, import_react3.useRef)(false);
|
|
183
|
+
const [isFetchingBalance, setIsFetchingBalance] = (0, import_react3.useState)(false);
|
|
184
|
+
const fetchingDefaultToken = (0, import_react3.useRef)(false);
|
|
185
|
+
const [isFetchingDefaultTokenBalance, setIsFetchingDefaultTokenBalance] = (0, import_react3.useState)(false);
|
|
186
|
+
const [solBalance, setSolBalance] = (0, import_react3.useState)(null);
|
|
187
|
+
const [defaultTokenBalance, setDefaultTokenBalance] = (0, import_react3.useState)(null);
|
|
188
|
+
const selectedAccount = account || "";
|
|
189
|
+
const walletName = (connector == null ? void 0 : connector.name) || "Unknown Wallet";
|
|
190
|
+
const walletIcon = (connector == null ? void 0 : connector.icon) || void 0;
|
|
118
191
|
const shortAddress = `${selectedAccount.slice(0, 4)}...${selectedAccount.slice(-4)}`;
|
|
119
192
|
async function handleCopy() {
|
|
120
193
|
try {
|
|
@@ -127,38 +200,45 @@ function WalletDropdown(props) {
|
|
|
127
200
|
}
|
|
128
201
|
}
|
|
129
202
|
async function fetchSolBalance() {
|
|
130
|
-
if (!client ||
|
|
203
|
+
if (!client || fetchingSolBalance.current) return;
|
|
131
204
|
setIsFetchingBalance(true);
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
setIsFetchingBalance(false);
|
|
145
|
-
fetching.current = false;
|
|
205
|
+
fetchingSolBalance.current = true;
|
|
206
|
+
const solBalance2 = await getSolBalance(client, selectedAccount);
|
|
207
|
+
setSolBalance(solBalance2);
|
|
208
|
+
setIsFetchingBalance(false);
|
|
209
|
+
fetchingSolBalance.current = false;
|
|
210
|
+
}
|
|
211
|
+
async function fetchDefaultTokenBalance() {
|
|
212
|
+
if (!showDefaultToken || !showDefaultToken.address || !client || fetchingDefaultToken.current) return;
|
|
213
|
+
const isValidAddress = (0, import_kit2.isAddress)(showDefaultToken.address);
|
|
214
|
+
if (!isValidAddress) {
|
|
215
|
+
console.error("Invalid default token address:", showDefaultToken);
|
|
216
|
+
return;
|
|
146
217
|
}
|
|
218
|
+
setIsFetchingDefaultTokenBalance(true);
|
|
219
|
+
fetchingDefaultToken.current = true;
|
|
220
|
+
const tokenBalance = await getTokenBalance(client, selectedAccount, showDefaultToken.address);
|
|
221
|
+
setDefaultTokenBalance(tokenBalance);
|
|
222
|
+
setIsFetchingDefaultTokenBalance(false);
|
|
223
|
+
fetchingDefaultToken.current = false;
|
|
147
224
|
}
|
|
148
|
-
(0,
|
|
225
|
+
(0, import_react3.useEffect)(() => {
|
|
149
226
|
if (showSolBalance && selectedAccount && client) {
|
|
150
227
|
fetchSolBalance();
|
|
151
228
|
}
|
|
152
|
-
|
|
229
|
+
if (showDefaultToken && selectedAccount && client) {
|
|
230
|
+
fetchDefaultTokenBalance();
|
|
231
|
+
}
|
|
232
|
+
}, [selectedAccount, client, showSolBalance, showDefaultToken]);
|
|
153
233
|
if (view === "wallet") {
|
|
154
234
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
155
|
-
|
|
235
|
+
import_react4.motion.div,
|
|
156
236
|
{
|
|
157
237
|
initial: { opacity: 0 },
|
|
158
238
|
animate: { opacity: 1 },
|
|
159
239
|
exit: { opacity: 0 },
|
|
160
240
|
transition: { duration: 0.2 },
|
|
161
|
-
className: (0, import_clsx.clsx)(import_WalletDropdown.default.WalletDropdown,
|
|
241
|
+
className: (0, import_clsx.clsx)(import_WalletDropdown.default.WalletDropdown, CN_DropdownMenu),
|
|
162
242
|
"data-theme": theme,
|
|
163
243
|
children: [
|
|
164
244
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: import_WalletDropdown.default.Header, children: [
|
|
@@ -191,7 +271,7 @@ function WalletDropdown(props) {
|
|
|
191
271
|
}
|
|
192
272
|
),
|
|
193
273
|
allowNetworkSwitch && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
194
|
-
|
|
274
|
+
import_connector2.ClusterElement,
|
|
195
275
|
{
|
|
196
276
|
render: ({ cluster }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
197
277
|
Button_default2,
|
|
@@ -243,10 +323,38 @@ function WalletDropdown(props) {
|
|
|
243
323
|
]
|
|
244
324
|
}
|
|
245
325
|
),
|
|
246
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: import_WalletDropdown.default.balanceValue, children: isFetchingBalance ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: import_WalletDropdown.default.balanceLoading }) : solBalance !== null ? `${solBalance.toFixed(4)} SOL` : "-- SOL" })
|
|
326
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: import_WalletDropdown.default.balanceValue, title: String(solBalance) || "0", children: isFetchingBalance ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: import_WalletDropdown.default.balanceLoading }) : solBalance !== null ? `${solBalance.toFixed(4)} SOL` : "-- SOL" })
|
|
327
|
+
] }),
|
|
328
|
+
showDefaultToken && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: import_WalletDropdown.default.balanceSection, children: [
|
|
329
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
330
|
+
"div",
|
|
331
|
+
{
|
|
332
|
+
className: import_WalletDropdown.default.balanceHeader,
|
|
333
|
+
children: [
|
|
334
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: import_WalletDropdown.default.balanceLabel, children: "Balance" }),
|
|
335
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
336
|
+
"button",
|
|
337
|
+
{
|
|
338
|
+
onClick: () => fetchDefaultTokenBalance(),
|
|
339
|
+
disabled: isFetchingDefaultTokenBalance,
|
|
340
|
+
title: "Refresh balance",
|
|
341
|
+
className: import_WalletDropdown.default.refreshButton,
|
|
342
|
+
"data-loading": isFetchingDefaultTokenBalance,
|
|
343
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
344
|
+
import_lucide_react2.RefreshCw,
|
|
345
|
+
{
|
|
346
|
+
className: import_WalletDropdown.default.refreshIcon
|
|
347
|
+
}
|
|
348
|
+
)
|
|
349
|
+
}
|
|
350
|
+
)
|
|
351
|
+
]
|
|
352
|
+
}
|
|
353
|
+
),
|
|
354
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: import_WalletDropdown.default.balanceValue, title: String(defaultTokenBalance) || "0", children: isFetchingDefaultTokenBalance ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: import_WalletDropdown.default.balanceLoading }) : defaultTokenBalance !== null ? `${defaultTokenBalance.toFixed(4)} ${(showDefaultToken == null ? void 0 : showDefaultToken.symbol) || ""}` : `-- ${(showDefaultToken == null ? void 0 : showDefaultToken.symbol) || ""}` })
|
|
247
355
|
] }),
|
|
248
356
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
249
|
-
|
|
357
|
+
import_connector2.DisconnectElement,
|
|
250
358
|
{
|
|
251
359
|
render: ({ disconnect, disconnecting }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
252
360
|
Button_default2,
|
|
@@ -268,15 +376,14 @@ function WalletDropdown(props) {
|
|
|
268
376
|
);
|
|
269
377
|
}
|
|
270
378
|
if (view === "network") {
|
|
271
|
-
console.count("Network view rendered");
|
|
272
379
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
273
|
-
|
|
380
|
+
import_react4.motion.div,
|
|
274
381
|
{
|
|
275
382
|
initial: { opacity: 0 },
|
|
276
383
|
animate: { opacity: 1 },
|
|
277
384
|
exit: { opacity: 0 },
|
|
278
385
|
transition: { duration: 0.2 },
|
|
279
|
-
className: (0, import_clsx.clsx)(import_WalletDropdown.default.WalletDropdown,
|
|
386
|
+
className: (0, import_clsx.clsx)(import_WalletDropdown.default.WalletDropdown, CN_DropdownMenu),
|
|
280
387
|
"data-theme": theme,
|
|
281
388
|
children: [
|
|
282
389
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: import_WalletDropdown.default.NetworkHeader, children: [
|
|
@@ -295,11 +402,11 @@ function WalletDropdown(props) {
|
|
|
295
402
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: "Network Settings" })
|
|
296
403
|
] }),
|
|
297
404
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
298
|
-
|
|
405
|
+
import_connector2.ClusterElement,
|
|
299
406
|
{
|
|
300
407
|
render: ({ cluster, clusters, setCluster }) => {
|
|
301
408
|
const currentClusterId = (cluster == null ? void 0 : cluster.id) || "solana:mainnet";
|
|
302
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: import_WalletDropdown.default.networkOptions, children: clusters.map((network
|
|
409
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: import_WalletDropdown.default.networkOptions, children: clusters.map((network) => {
|
|
303
410
|
const isSelected = currentClusterId === network.id;
|
|
304
411
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
305
412
|
"div",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/WalletDropdown/index.ts","../src/components/WalletDropdown/WalletDropdown.tsx","../src/components/shared/Avatar/Avatar.tsx","../src/components/shared/Avatar/index.ts","../src/components/shared/Button/Button.tsx","../src/components/shared/Button/index.ts"],"sourcesContent":["import WalletDropdown from './WalletDropdown';\n\n\nexport default WalletDropdown","import { useEffect, useRef, useState } from 'react'\nimport styles from './WalletDropdown.module.css'\nimport { motion } from 'motion/react';\nimport Avatar from '@shared/Avatar';\nimport { Check, ChevronLeft, Copy, Globe, LogOut, RefreshCw } from 'lucide-react';\nimport Button from '@shared/Button';\nimport { address, BalanceElement, ClusterElement, DisconnectElement, lamportsToSol, useCluster, useConnectorClient } from '@solana/connector';\nimport { createSolanaRpc } from '@solana/kit';\nimport { clsx } from 'clsx';\n\ninterface WalletDropdownProps {\n CN_ConnectButton?: string;\n selectedAccount: string;\n walletIcon?: string;\n walletName: string;\n theme?: 'light' | 'dark';\n\n allowNetworkSwitch?: boolean;\n showSolBalance?: boolean;\n}\n\ntype DropdownView = 'wallet' | 'network';\n\nconst networkColor: Record<string, string> = {\n 'solana:mainnet': '#00c950',\n 'solana:devnet': '#2b7fff',\n 'solana:testnet': '#f0b100',\n 'solana:localnet': '#ff3b3b',\n};\n\nexport function WalletDropdown(props: WalletDropdownProps) {\n const client = useConnectorClient();\n\n const { CN_ConnectButton, selectedAccount, walletIcon, walletName, theme, allowNetworkSwitch, showSolBalance } = props\n\n const [view, setView] = useState<DropdownView>('wallet');\n const [copied, setCopied] = useState(false);\n\n const fetching = useRef(false);\n const [isFetchingBalance, setIsFetchingBalance] = useState(false);\n const [solBalance, setSolBalance] = useState<number | null>(null);\n\n const shortAddress = `${selectedAccount.slice(0, 4)}...${selectedAccount.slice(-4)}`;\n\n async function handleCopy() {\n try {\n await navigator.clipboard.writeText(selectedAccount);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n } catch (error) {\n setCopied(false);\n console.error('Failed to copy to clipboard:', error);\n }\n }\n\n async function fetchSolBalance() {\n if (!client || fetching.current) return;\n setIsFetchingBalance(true);\n fetching.current = true;\n try {\n const rpcUrl = client.getRpcUrl();\n const pubkey = address(selectedAccount);\n if (!rpcUrl) throw new Error('No RPC endpoint configured');\n const rpc = createSolanaRpc(rpcUrl);\n const solLamports = (await rpc.getBalance(pubkey).send()).value || 0;\n const sol = lamportsToSol(solLamports);\n setSolBalance(sol);\n\n } catch (error) {\n setSolBalance(0);\n } finally {\n setIsFetchingBalance(false);\n fetching.current = false;\n }\n }\n\n useEffect(() => {\n if (showSolBalance && selectedAccount && client) {\n fetchSolBalance();\n }\n }, [selectedAccount, client, showSolBalance]);\n\n if (view === 'wallet') {\n return (\n <motion.div\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={{ duration: 0.2 }}\n className={clsx(styles.WalletDropdown, CN_ConnectButton)}\n data-theme={theme}\n >\n {/* Header with Avatar and Address */}\n <div className={styles.Header}>\n <div className={styles.addressAndAvatar}>\n <Avatar\n width={48}\n height={48}\n src={walletIcon}\n alt={walletName}\n />\n <div className={styles.address}>\n <span className={styles.shortAddress}>{shortAddress}</span>\n <span className={styles.walletName}>{walletName}</span>\n </div>\n </div>\n\n <div className={styles.actions}>\n <Button\n type=\"button\"\n onClick={handleCopy}\n variant=\"outline\"\n size=\"icon\"\n className=\"rounded-full\"\n title={copied ? 'Copied!' : 'Copy address'}\n >\n {copied ?\n <Check className={styles.checkIcon} /> :\n <Copy />\n }\n </Button>\n\n {/* Network Selector Globe Button */}\n {allowNetworkSwitch && (\n <ClusterElement\n render={({ cluster }) => (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"icon\"\n onClick={() => setView('network')}\n title={`Network: ${cluster?.label || 'Unknown'}`}\n >\n <Globe />\n <span\n className={styles.networkIndicator}\n style={{ background: networkColor[cluster?.id || 'solana:mainnet'] }}\n />\n </Button>\n )}\n />\n )}\n </div>\n </div>\n\n {showSolBalance && (\n <div className={styles.balanceSection}>\n <div\n className={styles.balanceHeader}\n >\n <span className={styles.balanceLabel}>Balance</span>\n <button\n onClick={() => fetchSolBalance()}\n disabled={isFetchingBalance}\n title=\"Refresh balance\"\n className={styles.refreshButton}\n data-loading={isFetchingBalance}\n >\n <RefreshCw\n className={styles.refreshIcon}\n />\n </button>\n </div>\n <div className={styles.balanceValue}>\n {isFetchingBalance ? (\n <div className={styles.balanceLoading} />\n ) : solBalance !== null ? (\n `${solBalance.toFixed(4)} SOL`\n ) : (\n '-- SOL'\n )}\n </div>\n </div>\n )}\n\n <DisconnectElement\n render={({ disconnect, disconnecting }) => (\n <Button\n variant=\"default\"\n className={styles.disconnectButton}\n onClick={disconnect}\n disabled={disconnecting}\n >\n <LogOut className={styles.disconnectIcon} />\n {disconnecting ? 'Disconnecting...' : 'Disconnect'}\n </Button>\n )}\n />\n </motion.div>\n )\n }\n\n //network switch view\n if (view === 'network') {\n console.count('Network view rendered');\n return (\n <motion.div\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={{ duration: 0.2 }}\n className={clsx(styles.WalletDropdown, CN_ConnectButton)}\n data-theme={theme}\n >\n {/* Header */}\n <div className={styles.NetworkHeader}>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"icon\"\n onClick={() => setView('wallet')}\n title={`Network: Back to Wallet`}\n className={styles.backButton}\n >\n <ChevronLeft />\n </Button>\n <span>Network Settings</span>\n </div>\n\n {/* Network Options */}\n <ClusterElement\n render={({ cluster, clusters, setCluster }) => {\n const currentClusterId = (cluster as { id?: string })?.id || 'solana:mainnet';\n return (\n <div className={styles.networkOptions}>\n {clusters.map((network, index) => {\n const isSelected = currentClusterId === network.id;\n return (\n <div\n key={network.id}\n role=\"button\"\n tabIndex={0}\n onClick={() => setCluster(network.id)}\n onKeyDown={e => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n setCluster(network.id);\n }\n }}\n className={styles.networkButton}\n >\n <div className={styles.networkName}>\n <span\n className={styles.networkColor}\n style={{ background: networkColor[network.id] }}\n />\n <span className={styles.networkLabel}>{network.label}</span>\n </div>\n <div className={styles.checkMark} data-selected={isSelected}>\n {isSelected && <Check />}\n </div>\n </div>\n );\n })}\n </div>\n );\n }}\n />\n </motion.div>\n )\n }\n}\n\nexport default WalletDropdown","import { useState } from 'react';\nimport styles from './Avatar.module.css';\nimport { Wallet } from 'lucide-react';\ninterface AvatarProps {\n height?: number | string;\n width?: number | string;\n src?: string;\n alt?: string;\n theme?: 'light' | 'dark';\n}\nexport function Avatar({\n height,\n width,\n src,\n alt,\n theme = 'light',\n}: AvatarProps) {\n const [hasError, setHasError] = useState(false);\n return (\n <div className={styles.avatar} data-theme={theme}>\n {src && !hasError ? (\n <img\n height={height}\n width={width}\n src={src}\n alt={alt || \"Avatar\"}\n onError={() => setHasError(true)}\n />\n ) : (\n <div className={styles.fallback} style={{ height, width }}>\n <Wallet />\n </div>\n )}\n </div>\n );\n}\n","import { Avatar } from './Avatar';\n\nexport default Avatar;","'use client';\n\nimport * as React from 'react';\nimport { Button as BaseButton } from '@base-ui/react/button';\nimport styles from './Button.module.css';\n\n// 1. Define Types\ntype ButtonVariant = 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link';\ntype ButtonSize = 'default' | 'sm' | 'lg' | 'icon';\n\nexport interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n variant?: ButtonVariant;\n size?: ButtonSize;\n}\n\n// 2. The Component\nconst Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant = 'default', size = 'default', ...props }, ref) => {\n return (\n <BaseButton\n ref={ref}\n\n className={`${styles.button} ${className || ''}`}\n data-variant={variant}\n data-size={size}\n\n {...props}\n />\n );\n }\n);\nButton.displayName = 'Button';\n\nexport default Button;","import Button from \"./Button\";\n\nexport default Button;"],"mappings":"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","names":["WalletDropdown_default","import_react","styles","import_lucide_react","import_jsx_runtime","BaseButton","styles","Button_default","import_jsx_runtime","styles","Button_default","WalletDropdown_default"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/WalletDropdown/index.ts","../src/components/WalletDropdown/WalletDropdown.tsx","../src/components/shared/Avatar/Avatar.tsx","../src/components/shared/Avatar/index.ts","../src/components/shared/Button/Button.tsx","../src/components/shared/Button/index.ts","../src/utils/fetchBalance.tsx"],"sourcesContent":["import WalletDropdown from './WalletDropdown';\n\n\nexport default WalletDropdown","import { useEffect, useRef, useState } from 'react'\nimport { isAddress } from '@solana/kit';\nimport styles from './WalletDropdown.module.css'\nimport { motion } from 'motion/react';\nimport Avatar from '@shared/Avatar';\nimport { Check, ChevronLeft, Copy, Globe, LogOut, RefreshCw } from 'lucide-react';\nimport Button from '@shared/Button';\nimport { ClusterElement, DisconnectElement, useConnector, useConnectorClient } from '@solana/connector';\nimport { clsx } from 'clsx';\nimport { getSolBalance, getTokenBalance } from 'src/utils/fetchBalance';\n\n/**\n * Props for the WalletDropdown component.\n */\ninterface WalletDropdownProps {\n /** * Custom CSS class for the dropdown menu container. \n * If not passed, the component uses default absolute positioning.\n */\n CN_DropdownMenu?: string;\n\n /** * Visual theme for the dropdown items. \n * @default 'light'\n */\n theme?: 'light' | 'dark';\n\n /** * Enables the option to switch between Solana clusters. \n * @default true\n */\n allowNetworkSwitch?: boolean;\n\n /** * Displays the user's SOL balance inside the dropdown header. \n * @default true\n */\n showSolBalance?: boolean;\n\n /** * Configuration to display a specific SPL token balance. \n * If not provided, this defaults to false (hidden).\n */\n showDefaultToken?: {\n address: string;\n symbol: string;\n } | undefined;\n}\n\ntype DropdownView = 'wallet' | 'network';\n\nconst networkColor: Record<string, string> = {\n 'solana:mainnet': '#00c950',\n 'solana:devnet': '#2b7fff',\n 'solana:testnet': '#f0b100',\n 'solana:localnet': '#ff3b3b',\n};\n\nexport function WalletDropdown(props: WalletDropdownProps) {\n const client = useConnectorClient();\n\n const { CN_DropdownMenu,\n theme = 'light',\n allowNetworkSwitch = true,\n showSolBalance = true,\n showDefaultToken\n } = props\n\n const [view, setView] = useState<DropdownView>('wallet');\n const [copied, setCopied] = useState(false);\n\n const { account, connector } = useConnector();\n const fetchingSolBalance = useRef(false);\n const [isFetchingBalance, setIsFetchingBalance] = useState(false);\n\n const fetchingDefaultToken = useRef(false);\n const [isFetchingDefaultTokenBalance, setIsFetchingDefaultTokenBalance] = useState(false);\n\n const [solBalance, setSolBalance] = useState<number | null>(null);\n const [defaultTokenBalance, setDefaultTokenBalance] = useState<number | null>(null);\n\n const selectedAccount = account || '';\n const walletName = connector?.name || 'Unknown Wallet';\n const walletIcon = connector?.icon || undefined;\n const shortAddress = `${selectedAccount.slice(0, 4)}...${selectedAccount.slice(-4)}`;\n\n async function handleCopy() {\n try {\n await navigator.clipboard.writeText(selectedAccount);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n } catch (error) {\n setCopied(false);\n console.error('Failed to copy to clipboard:', error);\n }\n }\n\n async function fetchSolBalance() {\n if (!client || fetchingSolBalance.current) return;\n setIsFetchingBalance(true);\n fetchingSolBalance.current = true;\n\n const solBalance = await getSolBalance(client, selectedAccount);\n setSolBalance(solBalance);\n\n setIsFetchingBalance(false);\n fetchingSolBalance.current = false;\n }\n\n async function fetchDefaultTokenBalance() {\n if (!showDefaultToken || !showDefaultToken.address || !client || fetchingDefaultToken.current) return;\n\n const isValidAddress = isAddress(showDefaultToken.address);\n if (!isValidAddress) {\n console.error('Invalid default token address:', showDefaultToken);\n return\n }\n\n setIsFetchingDefaultTokenBalance(true);\n fetchingDefaultToken.current = true;\n\n const tokenBalance = await getTokenBalance(client, selectedAccount, showDefaultToken.address);\n setDefaultTokenBalance(tokenBalance);\n\n setIsFetchingDefaultTokenBalance(false);\n fetchingDefaultToken.current = false;\n }\n\n useEffect(() => {\n if (showSolBalance && selectedAccount && client) {\n fetchSolBalance();\n }\n if (showDefaultToken && selectedAccount && client) {\n fetchDefaultTokenBalance();\n }\n }, [selectedAccount, client, showSolBalance, showDefaultToken]);\n\n if (view === 'wallet') {\n return (\n <motion.div\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={{ duration: 0.2 }}\n className={clsx(styles.WalletDropdown, CN_DropdownMenu)}\n data-theme={theme}\n >\n {/* Header with Avatar and Address */}\n <div className={styles.Header}>\n <div className={styles.addressAndAvatar}>\n <Avatar\n width={48}\n height={48}\n src={walletIcon}\n alt={walletName}\n />\n <div className={styles.address}>\n <span className={styles.shortAddress}>{shortAddress}</span>\n <span className={styles.walletName}>{walletName}</span>\n </div>\n </div>\n\n <div className={styles.actions}>\n <Button\n type=\"button\"\n onClick={handleCopy}\n variant=\"outline\"\n size=\"icon\"\n className=\"rounded-full\"\n title={copied ? 'Copied!' : 'Copy address'}\n >\n {copied ?\n <Check className={styles.checkIcon} /> :\n <Copy />\n }\n </Button>\n\n {/* Network Selector Globe Button */}\n {allowNetworkSwitch && (\n <ClusterElement\n render={({ cluster }) => (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"icon\"\n onClick={() => setView('network')}\n title={`Network: ${cluster?.label || 'Unknown'}`}\n >\n <Globe />\n <span\n className={styles.networkIndicator}\n style={{ background: networkColor[cluster?.id || 'solana:mainnet'] }}\n />\n </Button>\n )}\n />\n )}\n </div>\n </div>\n\n {showSolBalance && (\n <div className={styles.balanceSection}>\n <div\n className={styles.balanceHeader}\n >\n <span className={styles.balanceLabel}>Balance</span>\n <button\n onClick={() => fetchSolBalance()}\n disabled={isFetchingBalance}\n title=\"Refresh balance\"\n className={styles.refreshButton}\n data-loading={isFetchingBalance}\n >\n <RefreshCw\n className={styles.refreshIcon}\n />\n </button>\n </div>\n <div className={styles.balanceValue} title={String(solBalance) || \"0\"}>\n {isFetchingBalance ? (\n <div className={styles.balanceLoading} />\n ) : solBalance !== null ? (\n `${solBalance.toFixed(4)} SOL`\n ) : (\n '-- SOL'\n )}\n </div>\n </div>\n )}\n\n {showDefaultToken && (\n <div className={styles.balanceSection}>\n <div\n className={styles.balanceHeader}\n >\n <span className={styles.balanceLabel}>Balance</span>\n <button\n onClick={() => fetchDefaultTokenBalance()}\n disabled={isFetchingDefaultTokenBalance}\n title=\"Refresh balance\"\n className={styles.refreshButton}\n data-loading={isFetchingDefaultTokenBalance}\n >\n <RefreshCw\n className={styles.refreshIcon}\n />\n </button>\n </div>\n <div className={styles.balanceValue} title={String(defaultTokenBalance) || \"0\"}>\n {isFetchingDefaultTokenBalance ? (\n <div className={styles.balanceLoading} />\n ) : defaultTokenBalance !== null ? (\n `${defaultTokenBalance.toFixed(4)} ${showDefaultToken?.symbol || ''}`\n ) : (\n `-- ${showDefaultToken?.symbol || ''}`\n )}\n </div>\n </div>\n )}\n\n <DisconnectElement\n render={({ disconnect, disconnecting }) => (\n <Button\n variant=\"default\"\n className={styles.disconnectButton}\n onClick={disconnect}\n disabled={disconnecting}\n >\n <LogOut className={styles.disconnectIcon} />\n {disconnecting ? 'Disconnecting...' : 'Disconnect'}\n </Button>\n )}\n />\n </motion.div>\n )\n }\n\n //network switch view\n if (view === 'network') {\n return (\n <motion.div\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={{ duration: 0.2 }}\n className={clsx(styles.WalletDropdown, CN_DropdownMenu)}\n data-theme={theme}\n >\n {/* Header */}\n <div className={styles.NetworkHeader}>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"icon\"\n onClick={() => setView('wallet')}\n title={`Network: Back to Wallet`}\n className={styles.backButton}\n >\n <ChevronLeft />\n </Button>\n <span>Network Settings</span>\n </div>\n\n {/* Network Options */}\n <ClusterElement\n render={({ cluster, clusters, setCluster }) => {\n const currentClusterId = (cluster as { id?: string })?.id || 'solana:mainnet';\n return (\n <div className={styles.networkOptions}>\n {clusters.map((network) => {\n const isSelected = currentClusterId === network.id;\n return (\n <div\n key={network.id}\n role=\"button\"\n tabIndex={0}\n onClick={() => setCluster(network.id)}\n onKeyDown={e => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n setCluster(network.id);\n }\n }}\n className={styles.networkButton}\n >\n <div className={styles.networkName}>\n <span\n className={styles.networkColor}\n style={{ background: networkColor[network.id] }}\n />\n <span className={styles.networkLabel}>{network.label}</span>\n </div>\n <div className={styles.checkMark} data-selected={isSelected}>\n {isSelected && <Check />}\n </div>\n </div>\n );\n })}\n </div>\n );\n }}\n />\n </motion.div>\n )\n }\n}\n\nexport default WalletDropdown","import { useState } from 'react';\nimport styles from './Avatar.module.css';\nimport { Wallet } from 'lucide-react';\ninterface AvatarProps {\n height?: number | string;\n width?: number | string;\n src?: string;\n alt?: string;\n theme?: 'light' | 'dark';\n}\nexport function Avatar({\n height,\n width,\n src,\n alt,\n theme = 'light',\n}: AvatarProps) {\n const [hasError, setHasError] = useState(false);\n return (\n <div className={styles.avatar} data-theme={theme}>\n {src && !hasError ? (\n <img\n height={height}\n width={width}\n src={src}\n alt={alt || \"Avatar\"}\n onError={() => setHasError(true)}\n />\n ) : (\n <div className={styles.fallback} style={{ height, width }}>\n <Wallet />\n </div>\n )}\n </div>\n );\n}\n","import { Avatar } from './Avatar';\n\nexport default Avatar;","'use client';\n\nimport { forwardRef } from 'react';\nimport { Button as BaseButton } from '@base-ui/react/button';\nimport styles from './Button.module.css';\n\n// 1. Define Types\ntype ButtonVariant = 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link';\ntype ButtonSize = 'default' | 'sm' | 'lg' | 'icon';\n\nexport interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n variant?: ButtonVariant;\n size?: ButtonSize;\n}\n\n// 2. The Component\nconst Button = forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant = 'default', size = 'default', ...props }, ref) => {\n return (\n <BaseButton\n ref={ref}\n\n className={`${styles.button} ${className || ''}`}\n data-variant={variant}\n data-size={size}\n\n {...props}\n />\n );\n }\n);\nButton.displayName = 'Button';\n\nexport default Button;","import Button from \"./Button\";\n\nexport default Button;","import { findAssociatedTokenPda } from \"@solana-program/token\";\nimport { address, ConnectorClient, lamportsToSol } from \"@solana/connector\";\nimport { createSolanaRpc } from \"@solana/kit\";\n\nexport async function getSolBalance(\n client: ConnectorClient,\n pubkey: string\n): Promise<number> {\n let balance = 0;\n try {\n const rpcUrl = client.getRpcUrl();\n if (!rpcUrl) {\n console.error(\"RPC URL is not available from the ConnectorClient.\");\n return 0;\n }\n const pubkeyAddress = address(pubkey);\n const rpc = createSolanaRpc(rpcUrl);\n const balanceResponse = await rpc.getBalance(pubkeyAddress).send();\n balance = lamportsToSol(balanceResponse.value);\n } catch (error) {\n console.error(\"Error fetching SOL balance:\", error);\n } finally {\n return balance;\n }\n}\n\nexport async function getTokenBalance(\n client: ConnectorClient,\n pubkey: string,\n mintAddress: string\n): Promise<number> {\n let balance = 0;\n try {\n const rpcUrl = client.getRpcUrl();\n if (!rpcUrl) {\n console.error(\"RPC URL is not available from the ConnectorClient.\");\n return 0;\n }\n const pubkeyAddress = address(pubkey);\n const mintPubkey = address(mintAddress);\n const rpc = createSolanaRpc(rpcUrl);\n\n const mintInfo = await rpc.getAccountInfo(\n mintPubkey,\n { encoding: \"base64\" }\n ).send();\n\n const ownerProgram = mintInfo.value?.owner;\n if (!ownerProgram) {\n throw new Error('Failed to fetch mint account info');\n }\n const tokenProgram = address(ownerProgram)\n const [tokenPDA] = await findAssociatedTokenPda({\n mint: mintPubkey,\n owner: pubkeyAddress,\n tokenProgram: tokenProgram\n });\n const tokenBalance = await rpc.getTokenAccountBalance(tokenPDA).send();\n if (tokenBalance.value) {\n balance = parseFloat(tokenBalance.value.uiAmountString);\n }\n } catch (error) {\n // console.error(\"Error fetching token balance:\", error);\n } finally {\n return balance;\n }\n}"],"mappings":"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","names":["WalletDropdown_default","import_react","import_kit","styles","import_lucide_react","import_react","import_jsx_runtime","BaseButton","styles","Button_default","import_connector","import_jsx_runtime","solBalance","styles","Button_default","WalletDropdown_default"]}
|
package/dist/WalletDropdown.mjs
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
// src/components/WalletDropdown/WalletDropdown.tsx
|
|
4
4
|
import { useEffect, useRef, useState as useState2 } from "react";
|
|
5
|
-
import
|
|
5
|
+
import { isAddress } from "@solana/kit";
|
|
6
|
+
import styles3 from "./WalletDropdown.module-DOK7CUOQ.module.css";
|
|
6
7
|
import { motion } from "motion/react";
|
|
7
8
|
|
|
8
9
|
// src/components/shared/Avatar/Avatar.tsx
|
|
@@ -37,11 +38,11 @@ var Avatar_default = Avatar;
|
|
|
37
38
|
import { Check, ChevronLeft, Copy, Globe, LogOut, RefreshCw } from "lucide-react";
|
|
38
39
|
|
|
39
40
|
// src/components/shared/Button/Button.tsx
|
|
40
|
-
import
|
|
41
|
+
import { forwardRef } from "react";
|
|
41
42
|
import { Button as BaseButton } from "@base-ui/react/button";
|
|
42
|
-
import styles2 from "./Button.module-
|
|
43
|
+
import styles2 from "./Button.module-QCTUNBHA.module.css";
|
|
43
44
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
44
|
-
var Button =
|
|
45
|
+
var Button = forwardRef(
|
|
45
46
|
({ className, variant = "default", size = "default", ...props }, ref) => {
|
|
46
47
|
return /* @__PURE__ */ jsx2(
|
|
47
48
|
BaseButton,
|
|
@@ -62,9 +63,68 @@ var Button_default = Button;
|
|
|
62
63
|
var Button_default2 = Button_default;
|
|
63
64
|
|
|
64
65
|
// src/components/WalletDropdown/WalletDropdown.tsx
|
|
65
|
-
import {
|
|
66
|
-
import { createSolanaRpc } from "@solana/kit";
|
|
66
|
+
import { ClusterElement, DisconnectElement, useConnector, useConnectorClient } from "@solana/connector";
|
|
67
67
|
import { clsx } from "clsx";
|
|
68
|
+
|
|
69
|
+
// src/utils/fetchBalance.tsx
|
|
70
|
+
import { findAssociatedTokenPda } from "@solana-program/token";
|
|
71
|
+
import { address, lamportsToSol } from "@solana/connector";
|
|
72
|
+
import { createSolanaRpc } from "@solana/kit";
|
|
73
|
+
async function getSolBalance(client, pubkey) {
|
|
74
|
+
let balance = 0;
|
|
75
|
+
try {
|
|
76
|
+
const rpcUrl = client.getRpcUrl();
|
|
77
|
+
if (!rpcUrl) {
|
|
78
|
+
console.error("RPC URL is not available from the ConnectorClient.");
|
|
79
|
+
return 0;
|
|
80
|
+
}
|
|
81
|
+
const pubkeyAddress = address(pubkey);
|
|
82
|
+
const rpc = createSolanaRpc(rpcUrl);
|
|
83
|
+
const balanceResponse = await rpc.getBalance(pubkeyAddress).send();
|
|
84
|
+
balance = lamportsToSol(balanceResponse.value);
|
|
85
|
+
} catch (error) {
|
|
86
|
+
console.error("Error fetching SOL balance:", error);
|
|
87
|
+
} finally {
|
|
88
|
+
return balance;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
async function getTokenBalance(client, pubkey, mintAddress) {
|
|
92
|
+
var _a;
|
|
93
|
+
let balance = 0;
|
|
94
|
+
try {
|
|
95
|
+
const rpcUrl = client.getRpcUrl();
|
|
96
|
+
if (!rpcUrl) {
|
|
97
|
+
console.error("RPC URL is not available from the ConnectorClient.");
|
|
98
|
+
return 0;
|
|
99
|
+
}
|
|
100
|
+
const pubkeyAddress = address(pubkey);
|
|
101
|
+
const mintPubkey = address(mintAddress);
|
|
102
|
+
const rpc = createSolanaRpc(rpcUrl);
|
|
103
|
+
const mintInfo = await rpc.getAccountInfo(
|
|
104
|
+
mintPubkey,
|
|
105
|
+
{ encoding: "base64" }
|
|
106
|
+
).send();
|
|
107
|
+
const ownerProgram = (_a = mintInfo.value) == null ? void 0 : _a.owner;
|
|
108
|
+
if (!ownerProgram) {
|
|
109
|
+
throw new Error("Failed to fetch mint account info");
|
|
110
|
+
}
|
|
111
|
+
const tokenProgram = address(ownerProgram);
|
|
112
|
+
const [tokenPDA] = await findAssociatedTokenPda({
|
|
113
|
+
mint: mintPubkey,
|
|
114
|
+
owner: pubkeyAddress,
|
|
115
|
+
tokenProgram
|
|
116
|
+
});
|
|
117
|
+
const tokenBalance = await rpc.getTokenAccountBalance(tokenPDA).send();
|
|
118
|
+
if (tokenBalance.value) {
|
|
119
|
+
balance = parseFloat(tokenBalance.value.uiAmountString);
|
|
120
|
+
}
|
|
121
|
+
} catch (error) {
|
|
122
|
+
} finally {
|
|
123
|
+
return balance;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// src/components/WalletDropdown/WalletDropdown.tsx
|
|
68
128
|
import { jsx as jsx3, jsxs } from "react/jsx-runtime";
|
|
69
129
|
var networkColor = {
|
|
70
130
|
"solana:mainnet": "#00c950",
|
|
@@ -74,12 +134,25 @@ var networkColor = {
|
|
|
74
134
|
};
|
|
75
135
|
function WalletDropdown(props) {
|
|
76
136
|
const client = useConnectorClient();
|
|
77
|
-
const {
|
|
137
|
+
const {
|
|
138
|
+
CN_DropdownMenu,
|
|
139
|
+
theme = "light",
|
|
140
|
+
allowNetworkSwitch = true,
|
|
141
|
+
showSolBalance = true,
|
|
142
|
+
showDefaultToken
|
|
143
|
+
} = props;
|
|
78
144
|
const [view, setView] = useState2("wallet");
|
|
79
145
|
const [copied, setCopied] = useState2(false);
|
|
80
|
-
const
|
|
146
|
+
const { account, connector } = useConnector();
|
|
147
|
+
const fetchingSolBalance = useRef(false);
|
|
81
148
|
const [isFetchingBalance, setIsFetchingBalance] = useState2(false);
|
|
149
|
+
const fetchingDefaultToken = useRef(false);
|
|
150
|
+
const [isFetchingDefaultTokenBalance, setIsFetchingDefaultTokenBalance] = useState2(false);
|
|
82
151
|
const [solBalance, setSolBalance] = useState2(null);
|
|
152
|
+
const [defaultTokenBalance, setDefaultTokenBalance] = useState2(null);
|
|
153
|
+
const selectedAccount = account || "";
|
|
154
|
+
const walletName = (connector == null ? void 0 : connector.name) || "Unknown Wallet";
|
|
155
|
+
const walletIcon = (connector == null ? void 0 : connector.icon) || void 0;
|
|
83
156
|
const shortAddress = `${selectedAccount.slice(0, 4)}...${selectedAccount.slice(-4)}`;
|
|
84
157
|
async function handleCopy() {
|
|
85
158
|
try {
|
|
@@ -92,29 +165,36 @@ function WalletDropdown(props) {
|
|
|
92
165
|
}
|
|
93
166
|
}
|
|
94
167
|
async function fetchSolBalance() {
|
|
95
|
-
if (!client ||
|
|
168
|
+
if (!client || fetchingSolBalance.current) return;
|
|
96
169
|
setIsFetchingBalance(true);
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
setIsFetchingBalance(false);
|
|
110
|
-
fetching.current = false;
|
|
170
|
+
fetchingSolBalance.current = true;
|
|
171
|
+
const solBalance2 = await getSolBalance(client, selectedAccount);
|
|
172
|
+
setSolBalance(solBalance2);
|
|
173
|
+
setIsFetchingBalance(false);
|
|
174
|
+
fetchingSolBalance.current = false;
|
|
175
|
+
}
|
|
176
|
+
async function fetchDefaultTokenBalance() {
|
|
177
|
+
if (!showDefaultToken || !showDefaultToken.address || !client || fetchingDefaultToken.current) return;
|
|
178
|
+
const isValidAddress = isAddress(showDefaultToken.address);
|
|
179
|
+
if (!isValidAddress) {
|
|
180
|
+
console.error("Invalid default token address:", showDefaultToken);
|
|
181
|
+
return;
|
|
111
182
|
}
|
|
183
|
+
setIsFetchingDefaultTokenBalance(true);
|
|
184
|
+
fetchingDefaultToken.current = true;
|
|
185
|
+
const tokenBalance = await getTokenBalance(client, selectedAccount, showDefaultToken.address);
|
|
186
|
+
setDefaultTokenBalance(tokenBalance);
|
|
187
|
+
setIsFetchingDefaultTokenBalance(false);
|
|
188
|
+
fetchingDefaultToken.current = false;
|
|
112
189
|
}
|
|
113
190
|
useEffect(() => {
|
|
114
191
|
if (showSolBalance && selectedAccount && client) {
|
|
115
192
|
fetchSolBalance();
|
|
116
193
|
}
|
|
117
|
-
|
|
194
|
+
if (showDefaultToken && selectedAccount && client) {
|
|
195
|
+
fetchDefaultTokenBalance();
|
|
196
|
+
}
|
|
197
|
+
}, [selectedAccount, client, showSolBalance, showDefaultToken]);
|
|
118
198
|
if (view === "wallet") {
|
|
119
199
|
return /* @__PURE__ */ jsxs(
|
|
120
200
|
motion.div,
|
|
@@ -123,7 +203,7 @@ function WalletDropdown(props) {
|
|
|
123
203
|
animate: { opacity: 1 },
|
|
124
204
|
exit: { opacity: 0 },
|
|
125
205
|
transition: { duration: 0.2 },
|
|
126
|
-
className: clsx(styles3.WalletDropdown,
|
|
206
|
+
className: clsx(styles3.WalletDropdown, CN_DropdownMenu),
|
|
127
207
|
"data-theme": theme,
|
|
128
208
|
children: [
|
|
129
209
|
/* @__PURE__ */ jsxs("div", { className: styles3.Header, children: [
|
|
@@ -208,7 +288,35 @@ function WalletDropdown(props) {
|
|
|
208
288
|
]
|
|
209
289
|
}
|
|
210
290
|
),
|
|
211
|
-
/* @__PURE__ */ jsx3("div", { className: styles3.balanceValue, children: isFetchingBalance ? /* @__PURE__ */ jsx3("div", { className: styles3.balanceLoading }) : solBalance !== null ? `${solBalance.toFixed(4)} SOL` : "-- SOL" })
|
|
291
|
+
/* @__PURE__ */ jsx3("div", { className: styles3.balanceValue, title: String(solBalance) || "0", children: isFetchingBalance ? /* @__PURE__ */ jsx3("div", { className: styles3.balanceLoading }) : solBalance !== null ? `${solBalance.toFixed(4)} SOL` : "-- SOL" })
|
|
292
|
+
] }),
|
|
293
|
+
showDefaultToken && /* @__PURE__ */ jsxs("div", { className: styles3.balanceSection, children: [
|
|
294
|
+
/* @__PURE__ */ jsxs(
|
|
295
|
+
"div",
|
|
296
|
+
{
|
|
297
|
+
className: styles3.balanceHeader,
|
|
298
|
+
children: [
|
|
299
|
+
/* @__PURE__ */ jsx3("span", { className: styles3.balanceLabel, children: "Balance" }),
|
|
300
|
+
/* @__PURE__ */ jsx3(
|
|
301
|
+
"button",
|
|
302
|
+
{
|
|
303
|
+
onClick: () => fetchDefaultTokenBalance(),
|
|
304
|
+
disabled: isFetchingDefaultTokenBalance,
|
|
305
|
+
title: "Refresh balance",
|
|
306
|
+
className: styles3.refreshButton,
|
|
307
|
+
"data-loading": isFetchingDefaultTokenBalance,
|
|
308
|
+
children: /* @__PURE__ */ jsx3(
|
|
309
|
+
RefreshCw,
|
|
310
|
+
{
|
|
311
|
+
className: styles3.refreshIcon
|
|
312
|
+
}
|
|
313
|
+
)
|
|
314
|
+
}
|
|
315
|
+
)
|
|
316
|
+
]
|
|
317
|
+
}
|
|
318
|
+
),
|
|
319
|
+
/* @__PURE__ */ jsx3("div", { className: styles3.balanceValue, title: String(defaultTokenBalance) || "0", children: isFetchingDefaultTokenBalance ? /* @__PURE__ */ jsx3("div", { className: styles3.balanceLoading }) : defaultTokenBalance !== null ? `${defaultTokenBalance.toFixed(4)} ${(showDefaultToken == null ? void 0 : showDefaultToken.symbol) || ""}` : `-- ${(showDefaultToken == null ? void 0 : showDefaultToken.symbol) || ""}` })
|
|
212
320
|
] }),
|
|
213
321
|
/* @__PURE__ */ jsx3(
|
|
214
322
|
DisconnectElement,
|
|
@@ -233,7 +341,6 @@ function WalletDropdown(props) {
|
|
|
233
341
|
);
|
|
234
342
|
}
|
|
235
343
|
if (view === "network") {
|
|
236
|
-
console.count("Network view rendered");
|
|
237
344
|
return /* @__PURE__ */ jsxs(
|
|
238
345
|
motion.div,
|
|
239
346
|
{
|
|
@@ -241,7 +348,7 @@ function WalletDropdown(props) {
|
|
|
241
348
|
animate: { opacity: 1 },
|
|
242
349
|
exit: { opacity: 0 },
|
|
243
350
|
transition: { duration: 0.2 },
|
|
244
|
-
className: clsx(styles3.WalletDropdown,
|
|
351
|
+
className: clsx(styles3.WalletDropdown, CN_DropdownMenu),
|
|
245
352
|
"data-theme": theme,
|
|
246
353
|
children: [
|
|
247
354
|
/* @__PURE__ */ jsxs("div", { className: styles3.NetworkHeader, children: [
|
|
@@ -264,7 +371,7 @@ function WalletDropdown(props) {
|
|
|
264
371
|
{
|
|
265
372
|
render: ({ cluster, clusters, setCluster }) => {
|
|
266
373
|
const currentClusterId = (cluster == null ? void 0 : cluster.id) || "solana:mainnet";
|
|
267
|
-
return /* @__PURE__ */ jsx3("div", { className: styles3.networkOptions, children: clusters.map((network
|
|
374
|
+
return /* @__PURE__ */ jsx3("div", { className: styles3.networkOptions, children: clusters.map((network) => {
|
|
268
375
|
const isSelected = currentClusterId === network.id;
|
|
269
376
|
return /* @__PURE__ */ jsxs(
|
|
270
377
|
"div",
|