This commit is contained in:
zramsay 2025-03-25 14:39:33 -04:00
parent 919f99b86d
commit cc685f9796
2 changed files with 117 additions and 43 deletions

View File

@ -19,7 +19,9 @@ export default function WalletPage() {
const [tokenBalance, setTokenBalance] = useState<number>(0)
const [contributions, setContributions] = useState<AnimalRecordResult[]>([])
const [loading, setLoading] = useState(true)
const [balanceLoading, setBalanceLoading] = useState(true) // Separate loading state for token balance
const [error, setError] = useState<string | null>(null)
const [balanceError, setBalanceError] = useState<string | null>(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() {
<div className="flex flex-col items-end">
<div className="flex items-center text-emerald-300">
<Coins className="w-8 h-8 mr-2" />
<span className="text-4xl font-bold">{tokenBalance}</span>
<span className="ml-2 text-lg">WILD</span>
{balanceLoading ? (
<div className="flex items-center">
<span className="text-4xl font-bold animate-pulse">...</span>
<span className="ml-2 text-lg">WILD</span>
</div>
) : balanceError ? (
<div className="flex flex-col">
<div className="flex items-center">
<span className="text-amber-400 text-lg">Balance Error</span>
<button
onClick={async () => {
// Retry loading the balance
setBalanceLoading(true);
setBalanceError(null);
try {
const balance = await getTokenBalance();
setTokenBalance(balance);
} catch (error) {
console.error('Error reloading token balance:', error);
setBalanceError(error instanceof Error ? error.message : 'Failed to load token balance');
} finally {
setBalanceLoading(false);
}
}}
className="ml-2 text-xs bg-amber-800/30 text-amber-300 hover:bg-amber-700/30 px-2 py-1 rounded"
>
Retry
</button>
</div>
<span className="text-amber-300 text-xs max-w-[200px] truncate">{balanceError}</span>
</div>
) : (
<>
<span className="text-4xl font-bold">{tokenBalance}</span>
<span className="ml-2 text-lg">WILD</span>
</>
)}
</div>
{/* 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`}

View File

@ -378,8 +378,8 @@ export const sendWildTokens = async (amount: number): Promise<boolean> => {
/**
* 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<number> => {
// Add environment check at the top level to prevent unnecessary calls
@ -389,39 +389,57 @@ export const getTokenBalance = async (): Promise<number> => {
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');
}
};