@algobright/solana-connector 0.1.1 → 0.1.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.
@@ -37,7 +37,8 @@ module.exports = __toCommonJS(WalletDropdown_exports);
37
37
 
38
38
  // src/components/WalletDropdown/WalletDropdown.tsx
39
39
  var import_react2 = require("react");
40
- var import_WalletDropdown = __toESM(require("./WalletDropdown.module-A6KHWKGK.module.css"));
40
+ var import_kit2 = require("@solana/kit");
41
+ var import_WalletDropdown = __toESM(require("./WalletDropdown.module-DOK7CUOQ.module.css"));
41
42
  var import_react3 = require("motion/react");
42
43
 
43
44
  // src/components/shared/Avatar/Avatar.tsx
@@ -97,9 +98,66 @@ 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
- var import_clsx = require("clsx");
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(mintPubkey).send();
139
+ const ownerProgram = (_a = mintInfo.value) == null ? void 0 : _a.owner;
140
+ if (!ownerProgram) {
141
+ throw new Error("Failed to fetch mint account info");
142
+ }
143
+ const tokenProgram = (0, import_connector.address)(ownerProgram);
144
+ const [tokenPDA] = await (0, import_token.findAssociatedTokenPda)({
145
+ mint: mintPubkey,
146
+ owner: pubkeyAddress,
147
+ tokenProgram
148
+ });
149
+ const tokenBalance = await rpc.getTokenAccountBalance(tokenPDA).send();
150
+ if (tokenBalance.value) {
151
+ balance = parseFloat(tokenBalance.value.uiAmountString);
152
+ }
153
+ } catch (error) {
154
+ console.error("Error fetching token balance:", error);
155
+ } finally {
156
+ return balance;
157
+ }
158
+ }
159
+
160
+ // src/components/WalletDropdown/WalletDropdown.tsx
103
161
  var import_jsx_runtime3 = require("react/jsx-runtime");
104
162
  var networkColor = {
105
163
  "solana:mainnet": "#00c950",
@@ -108,13 +166,25 @@ var networkColor = {
108
166
  "solana:localnet": "#ff3b3b"
109
167
  };
110
168
  function WalletDropdown(props) {
111
- const client = (0, import_connector.useConnectorClient)();
112
- const { CN_ConnectButton, selectedAccount, walletIcon, walletName, theme, allowNetworkSwitch, showSolBalance } = props;
169
+ const client = (0, import_connector2.useConnectorClient)();
170
+ const {
171
+ CN_ConnectButton,
172
+ selectedAccount,
173
+ walletIcon,
174
+ walletName,
175
+ theme,
176
+ allowNetworkSwitch,
177
+ showSolBalance,
178
+ showDefaultToken
179
+ } = props;
113
180
  const [view, setView] = (0, import_react2.useState)("wallet");
114
181
  const [copied, setCopied] = (0, import_react2.useState)(false);
115
- const fetching = (0, import_react2.useRef)(false);
182
+ const fetchingSolBalance = (0, import_react2.useRef)(false);
116
183
  const [isFetchingBalance, setIsFetchingBalance] = (0, import_react2.useState)(false);
184
+ const fetchingDefaultToken = (0, import_react2.useRef)(false);
185
+ const [isFetchingDefaultTokenBalance, setIsFetchingDefaultTokenBalance] = (0, import_react2.useState)(false);
117
186
  const [solBalance, setSolBalance] = (0, import_react2.useState)(null);
187
+ const [defaultTokenBalance, setDefaultTokenBalance] = (0, import_react2.useState)(null);
118
188
  const shortAddress = `${selectedAccount.slice(0, 4)}...${selectedAccount.slice(-4)}`;
119
189
  async function handleCopy() {
120
190
  try {
@@ -127,29 +197,36 @@ function WalletDropdown(props) {
127
197
  }
128
198
  }
129
199
  async function fetchSolBalance() {
130
- if (!client || fetching.current) return;
200
+ if (!client || fetchingSolBalance.current) return;
131
201
  setIsFetchingBalance(true);
132
- fetching.current = true;
133
- try {
134
- const rpcUrl = client.getRpcUrl();
135
- const pubkey = (0, import_connector.address)(selectedAccount);
136
- if (!rpcUrl) throw new Error("No RPC endpoint configured");
137
- const rpc = (0, import_kit.createSolanaRpc)(rpcUrl);
138
- const solLamports = (await rpc.getBalance(pubkey).send()).value || 0;
139
- const sol = (0, import_connector.lamportsToSol)(solLamports);
140
- setSolBalance(sol);
141
- } catch (error) {
142
- setSolBalance(0);
143
- } finally {
144
- setIsFetchingBalance(false);
145
- fetching.current = false;
202
+ fetchingSolBalance.current = true;
203
+ const solBalance2 = await getSolBalance(client, selectedAccount);
204
+ setSolBalance(solBalance2);
205
+ setIsFetchingBalance(false);
206
+ fetchingSolBalance.current = false;
207
+ }
208
+ async function fetchDefaultTokenBalance() {
209
+ if (!showDefaultToken || !showDefaultToken.address || !client || fetchingDefaultToken.current) return;
210
+ const isValidAddress = (0, import_kit2.isAddress)(showDefaultToken.address);
211
+ if (!isValidAddress) {
212
+ console.error("Invalid default token address:", showDefaultToken);
213
+ return;
146
214
  }
215
+ setIsFetchingDefaultTokenBalance(true);
216
+ fetchingDefaultToken.current = true;
217
+ const tokenBalance = await getTokenBalance(client, selectedAccount, showDefaultToken.address);
218
+ setDefaultTokenBalance(tokenBalance);
219
+ setIsFetchingDefaultTokenBalance(false);
220
+ fetchingDefaultToken.current = false;
147
221
  }
148
222
  (0, import_react2.useEffect)(() => {
149
223
  if (showSolBalance && selectedAccount && client) {
150
224
  fetchSolBalance();
151
225
  }
152
- }, [selectedAccount, client, showSolBalance]);
226
+ if (showDefaultToken && selectedAccount && client) {
227
+ fetchDefaultTokenBalance();
228
+ }
229
+ }, [selectedAccount, client, showSolBalance, showDefaultToken]);
153
230
  if (view === "wallet") {
154
231
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
155
232
  import_react3.motion.div,
@@ -191,7 +268,7 @@ function WalletDropdown(props) {
191
268
  }
192
269
  ),
193
270
  allowNetworkSwitch && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
194
- import_connector.ClusterElement,
271
+ import_connector2.ClusterElement,
195
272
  {
196
273
  render: ({ cluster }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
197
274
  Button_default2,
@@ -243,10 +320,38 @@ function WalletDropdown(props) {
243
320
  ]
244
321
  }
245
322
  ),
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" })
323
+ /* @__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" })
324
+ ] }),
325
+ showDefaultToken && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: import_WalletDropdown.default.balanceSection, children: [
326
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
327
+ "div",
328
+ {
329
+ className: import_WalletDropdown.default.balanceHeader,
330
+ children: [
331
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: import_WalletDropdown.default.balanceLabel, children: "Balance" }),
332
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
333
+ "button",
334
+ {
335
+ onClick: () => fetchDefaultTokenBalance(),
336
+ disabled: isFetchingDefaultTokenBalance,
337
+ title: "Refresh balance",
338
+ className: import_WalletDropdown.default.refreshButton,
339
+ "data-loading": isFetchingDefaultTokenBalance,
340
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
341
+ import_lucide_react2.RefreshCw,
342
+ {
343
+ className: import_WalletDropdown.default.refreshIcon
344
+ }
345
+ )
346
+ }
347
+ )
348
+ ]
349
+ }
350
+ ),
351
+ /* @__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
352
  ] }),
248
353
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
249
- import_connector.DisconnectElement,
354
+ import_connector2.DisconnectElement,
250
355
  {
251
356
  render: ({ disconnect, disconnecting }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
252
357
  Button_default2,
@@ -268,7 +373,6 @@ function WalletDropdown(props) {
268
373
  );
269
374
  }
270
375
  if (view === "network") {
271
- console.count("Network view rendered");
272
376
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
273
377
  import_react3.motion.div,
274
378
  {
@@ -295,7 +399,7 @@ function WalletDropdown(props) {
295
399
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: "Network Settings" })
296
400
  ] }),
297
401
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
298
- import_connector.ClusterElement,
402
+ import_connector2.ClusterElement,
299
403
  {
300
404
  render: ({ cluster, clusters, setCluster }) => {
301
405
  const currentClusterId = (cluster == null ? void 0 : cluster.id) || "solana:mainnet";
@@ -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 { createSolanaRpc, isAddress } from '@solana/kit';\nimport { findAssociatedTokenPda, TOKEN_PROGRAM_ADDRESS } from '@solana-program/token';\nimport { TOKEN_2022_PROGRAM_ADDRESS } from '@solana-program/token-2022';\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, ClusterElement, DisconnectElement, lamportsToSol, useConnectorClient } from '@solana/connector';\nimport { clsx } from 'clsx';\nimport { getSolBalance, getTokenBalance } from 'src/utils/fetchBalance';\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 showDefaultToken?: {\n address: string;\n symbol: string;\n }\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,\n selectedAccount,\n walletIcon,\n walletName,\n theme,\n allowNetworkSwitch,\n showSolBalance,\n showDefaultToken\n } = props\n\n const [view, setView] = useState<DropdownView>('wallet');\n const [copied, setCopied] = useState(false);\n\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 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_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} 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_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;","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(mintPubkey).send();\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\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_jsx_runtime","BaseButton","styles","Button_default","import_connector","import_jsx_runtime","solBalance","styles","Button_default","WalletDropdown_default"]}
@@ -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 styles3 from "./WalletDropdown.module-A6KHWKGK.module.css";
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
@@ -62,9 +63,66 @@ var Button_default = Button;
62
63
  var Button_default2 = Button_default;
63
64
 
64
65
  // src/components/WalletDropdown/WalletDropdown.tsx
65
- import { address, ClusterElement, DisconnectElement, lamportsToSol, useConnectorClient } from "@solana/connector";
66
- import { createSolanaRpc } from "@solana/kit";
66
+ import { ClusterElement, DisconnectElement, 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(mintPubkey).send();
104
+ const ownerProgram = (_a = mintInfo.value) == null ? void 0 : _a.owner;
105
+ if (!ownerProgram) {
106
+ throw new Error("Failed to fetch mint account info");
107
+ }
108
+ const tokenProgram = address(ownerProgram);
109
+ const [tokenPDA] = await findAssociatedTokenPda({
110
+ mint: mintPubkey,
111
+ owner: pubkeyAddress,
112
+ tokenProgram
113
+ });
114
+ const tokenBalance = await rpc.getTokenAccountBalance(tokenPDA).send();
115
+ if (tokenBalance.value) {
116
+ balance = parseFloat(tokenBalance.value.uiAmountString);
117
+ }
118
+ } catch (error) {
119
+ console.error("Error fetching token balance:", error);
120
+ } finally {
121
+ return balance;
122
+ }
123
+ }
124
+
125
+ // src/components/WalletDropdown/WalletDropdown.tsx
68
126
  import { jsx as jsx3, jsxs } from "react/jsx-runtime";
69
127
  var networkColor = {
70
128
  "solana:mainnet": "#00c950",
@@ -74,12 +132,24 @@ var networkColor = {
74
132
  };
75
133
  function WalletDropdown(props) {
76
134
  const client = useConnectorClient();
77
- const { CN_ConnectButton, selectedAccount, walletIcon, walletName, theme, allowNetworkSwitch, showSolBalance } = props;
135
+ const {
136
+ CN_ConnectButton,
137
+ selectedAccount,
138
+ walletIcon,
139
+ walletName,
140
+ theme,
141
+ allowNetworkSwitch,
142
+ showSolBalance,
143
+ showDefaultToken
144
+ } = props;
78
145
  const [view, setView] = useState2("wallet");
79
146
  const [copied, setCopied] = useState2(false);
80
- const fetching = useRef(false);
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);
83
153
  const shortAddress = `${selectedAccount.slice(0, 4)}...${selectedAccount.slice(-4)}`;
84
154
  async function handleCopy() {
85
155
  try {
@@ -92,29 +162,36 @@ function WalletDropdown(props) {
92
162
  }
93
163
  }
94
164
  async function fetchSolBalance() {
95
- if (!client || fetching.current) return;
165
+ if (!client || fetchingSolBalance.current) return;
96
166
  setIsFetchingBalance(true);
97
- fetching.current = true;
98
- try {
99
- const rpcUrl = client.getRpcUrl();
100
- const pubkey = address(selectedAccount);
101
- if (!rpcUrl) throw new Error("No RPC endpoint configured");
102
- const rpc = createSolanaRpc(rpcUrl);
103
- const solLamports = (await rpc.getBalance(pubkey).send()).value || 0;
104
- const sol = lamportsToSol(solLamports);
105
- setSolBalance(sol);
106
- } catch (error) {
107
- setSolBalance(0);
108
- } finally {
109
- setIsFetchingBalance(false);
110
- fetching.current = false;
167
+ fetchingSolBalance.current = true;
168
+ const solBalance2 = await getSolBalance(client, selectedAccount);
169
+ setSolBalance(solBalance2);
170
+ setIsFetchingBalance(false);
171
+ fetchingSolBalance.current = false;
172
+ }
173
+ async function fetchDefaultTokenBalance() {
174
+ if (!showDefaultToken || !showDefaultToken.address || !client || fetchingDefaultToken.current) return;
175
+ const isValidAddress = isAddress(showDefaultToken.address);
176
+ if (!isValidAddress) {
177
+ console.error("Invalid default token address:", showDefaultToken);
178
+ return;
111
179
  }
180
+ setIsFetchingDefaultTokenBalance(true);
181
+ fetchingDefaultToken.current = true;
182
+ const tokenBalance = await getTokenBalance(client, selectedAccount, showDefaultToken.address);
183
+ setDefaultTokenBalance(tokenBalance);
184
+ setIsFetchingDefaultTokenBalance(false);
185
+ fetchingDefaultToken.current = false;
112
186
  }
113
187
  useEffect(() => {
114
188
  if (showSolBalance && selectedAccount && client) {
115
189
  fetchSolBalance();
116
190
  }
117
- }, [selectedAccount, client, showSolBalance]);
191
+ if (showDefaultToken && selectedAccount && client) {
192
+ fetchDefaultTokenBalance();
193
+ }
194
+ }, [selectedAccount, client, showSolBalance, showDefaultToken]);
118
195
  if (view === "wallet") {
119
196
  return /* @__PURE__ */ jsxs(
120
197
  motion.div,
@@ -208,7 +285,35 @@ function WalletDropdown(props) {
208
285
  ]
209
286
  }
210
287
  ),
211
- /* @__PURE__ */ jsx3("div", { className: styles3.balanceValue, children: isFetchingBalance ? /* @__PURE__ */ jsx3("div", { className: styles3.balanceLoading }) : solBalance !== null ? `${solBalance.toFixed(4)} SOL` : "-- SOL" })
288
+ /* @__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" })
289
+ ] }),
290
+ showDefaultToken && /* @__PURE__ */ jsxs("div", { className: styles3.balanceSection, children: [
291
+ /* @__PURE__ */ jsxs(
292
+ "div",
293
+ {
294
+ className: styles3.balanceHeader,
295
+ children: [
296
+ /* @__PURE__ */ jsx3("span", { className: styles3.balanceLabel, children: "Balance" }),
297
+ /* @__PURE__ */ jsx3(
298
+ "button",
299
+ {
300
+ onClick: () => fetchDefaultTokenBalance(),
301
+ disabled: isFetchingDefaultTokenBalance,
302
+ title: "Refresh balance",
303
+ className: styles3.refreshButton,
304
+ "data-loading": isFetchingDefaultTokenBalance,
305
+ children: /* @__PURE__ */ jsx3(
306
+ RefreshCw,
307
+ {
308
+ className: styles3.refreshIcon
309
+ }
310
+ )
311
+ }
312
+ )
313
+ ]
314
+ }
315
+ ),
316
+ /* @__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
317
  ] }),
213
318
  /* @__PURE__ */ jsx3(
214
319
  DisconnectElement,
@@ -233,7 +338,6 @@ function WalletDropdown(props) {
233
338
  );
234
339
  }
235
340
  if (view === "network") {
236
- console.count("Network view rendered");
237
341
  return /* @__PURE__ */ jsxs(
238
342
  motion.div,
239
343
  {