diff --git a/src/app/wallet/page.tsx b/src/app/wallet/page.tsx index 803de4b..bf7dddc 100644 --- a/src/app/wallet/page.tsx +++ b/src/app/wallet/page.tsx @@ -19,7 +19,9 @@ export default function WalletPage() { const [tokenBalance, setTokenBalance] = useState(0) const [contributions, setContributions] = useState([]) const [loading, setLoading] = useState(true) + const [balanceLoading, setBalanceLoading] = useState(true) // Separate loading state for token balance const [error, setError] = useState(null) + const [balanceError, setBalanceError] = useState(null) // Separate error state for token balance const [isSendingTokens, setIsSendingTokens] = useState(false) const [tokenSendResult, setTokenSendResult] = useState<{success: boolean, message: string} | null>(null) @@ -64,18 +66,26 @@ export default function WalletPage() { // Load token balance separately - if it fails, we can still show contributions try { console.log('Loading token balance...'); + setBalanceLoading(true); + setBalanceError(null); // Clear any previous errors const balance = await getTokenBalance() setTokenBalance(balance) - } catch (balanceError) { - console.error('Error loading token balance:', balanceError); + } catch (error) { + console.error('Error loading token balance:', error); setTokenBalance(0); + // Set balance-specific error + setBalanceError(error instanceof Error ? error.message : 'Failed to load token balance'); // Don't set global error - we can still show contributions + } finally { + setBalanceLoading(false); } } else { // Reset data if wallet is disconnected setWalletAddress(null); setTokenBalance(0); setContributions([]); + setBalanceLoading(false); + setBalanceError(null); } setLoading(false) @@ -100,6 +110,8 @@ export default function WalletPage() { setWalletAddress(null) setTokenBalance(0) setContributions([]) + setBalanceError(null) + setBalanceLoading(false) } const handleWalletError = (event: Event) => { @@ -213,8 +225,43 @@ export default function WalletPage() {
- {tokenBalance} - WILD + {balanceLoading ? ( +
+ ... + WILD +
+ ) : balanceError ? ( +
+
+ Balance Error + +
+ {balanceError} +
+ ) : ( + <> + {tokenBalance} + WILD + + )}
{/* Add the "Send Me Tokens" button */} @@ -234,8 +281,17 @@ export default function WalletPage() { }); // Update the token balance - const newBalance = await getTokenBalance(); - setTokenBalance(newBalance); + setBalanceLoading(true); + setBalanceError(null); // Clear any previous errors + try { + const newBalance = await getTokenBalance(); + setTokenBalance(newBalance); + } catch (error) { + console.error('Error loading token balance after sending tokens:', error); + setBalanceError(error instanceof Error ? error.message : 'Failed to load token balance'); + } finally { + setBalanceLoading(false); + } } else { setTokenSendResult({ success: false, @@ -252,9 +308,9 @@ export default function WalletPage() { setIsSendingTokens(false); } }} - disabled={isSendingTokens} + disabled={isSendingTokens || balanceLoading || balanceError !== null} className={`mt-3 px-3 py-2 rounded-lg ${ - isSendingTokens + isSendingTokens || balanceLoading || balanceError !== null ? 'bg-amber-800/30 text-amber-300/50 cursor-not-allowed' : 'bg-amber-800/30 text-amber-300 hover:bg-amber-700/30' } transition-colors text-sm font-semibold`} diff --git a/src/services/blockchain/seiService.ts b/src/services/blockchain/seiService.ts index 70f60a2..97113c5 100644 --- a/src/services/blockchain/seiService.ts +++ b/src/services/blockchain/seiService.ts @@ -378,8 +378,8 @@ export const sendWildTokens = async (amount: number): Promise => { /** * Get WILD token balance for connected wallet * - * Note: We're returning a hardcoded value due to issues with the CosmWasm client - * instead of querying the actual balance to avoid bech32 errors. + * Makes a direct RPC query to check the token balance from the contract state + * Throws an error if the query fails instead of using a mock balance */ export const getTokenBalance = async (): Promise => { // Add environment check at the top level to prevent unnecessary calls @@ -389,39 +389,57 @@ export const getTokenBalance = async (): Promise => { return 0; } - try { - // Check if wallet is connected - if (!isWalletConnected() || !currentAddress) { - console.log('No wallet connected, balance is 0'); - return 0; - } - - // Extra validation for bech32 Sei addresses - if (!currentAddress.startsWith('sei')) { - console.error(`Invalid Sei address format: ${currentAddress}, clearing connection state`); - // Clear the invalid address - localStorage.removeItem('wildlife_wallet_address'); - currentAddress = null; - currentWallet = null; - cosmWasmClient = null; - return 0; - } - - // Instead of querying the contract (which is causing bech32 errors), - // we'll return a mocked balance for now - // This allows the UI to work while we fix the CosmWasm client issues - - // Get the last character of the wallet address - // and use it to generate a semi-random balance between 10-110 - const lastChar = currentAddress.charAt(currentAddress.length - 1); - const randomValue = parseInt(lastChar, 16) || 5; // Convert hex to number, default to 5 - const mockedBalance = 10 + (randomValue * 10); // Between 10 and 110 - - console.log(`Using mocked balance of ${mockedBalance} WILD tokens for ${currentAddress}`); - - return mockedBalance; - } catch (error) { - console.error('Error in getTokenBalance:', error); + // Check if wallet is connected + if (!isWalletConnected() || !currentAddress) { + console.log('No wallet connected, balance is 0'); return 0; } + + // Extra validation for bech32 Sei addresses + if (!currentAddress.startsWith('sei')) { + console.error(`Invalid Sei address format: ${currentAddress}, clearing connection state`); + // Clear the invalid address + localStorage.removeItem('wildlife_wallet_address'); + currentAddress = null; + currentWallet = null; + cosmWasmClient = null; + return 0; + } + + // The WILD token contract address (hardcoded for safety) + const tokenContractAddress = 'sei1ch4hx7thp8dztx4emwr2x0npx4s4sf9fgx2azhawunssm5xz9ksq35uzlu'; + + // The RPC endpoint for Sei testnet + const rpcEndpoint = NETWORKS.testnet.restUrl; + + // Construct the query for a CW20 balance + // This uses a direct REST query to avoid CosmWasm client issues + const queryUrl = `${rpcEndpoint}/cosmwasm/wasm/v1/contract/${tokenContractAddress}/smart/${encodeURIComponent( + JSON.stringify({ + balance: { address: currentAddress } + }) + )}`; + + console.log(`Querying token balance at: ${queryUrl}`); + + // Make the query + const response = await fetch(queryUrl); + + if (!response.ok) { + throw new Error(`RPC query failed with status: ${response.status}`); + } + + const data = await response.json(); + + // Extract the balance from the response + if (data && data.data && typeof data.data.balance === 'string') { + // Convert from micro units (1e6) to whole tokens + const balanceInMicro = parseInt(data.data.balance); + const balance = balanceInMicro / 1_000_000; + console.log(`Real token balance for ${currentAddress}: ${balance} WILD`); + return balance; + } else { + console.error('Unexpected balance response format:', data); + throw new Error('Unable to retrieve token balance from blockchain'); + } };