UNPKG

@shogun-sdk/one-shot

Version:

Shogun SDK - One Shot: React Components and hooks for cross-chain swaps

99 lines 4.08 kB
import { compareAddresses, getRpcUrls, getSolanaProvider, isEVMChain, isNativeToken, isSolanaChain, SOL_NATIVE, } from '@shogun-sdk/money-legos'; import { TOKEN_2022_PROGRAM_ID, TOKEN_PROGRAM_ID } from '@solana/spl-token'; import { PublicKey } from '@solana/web3.js'; import { useQuery } from '@tanstack/react-query'; import { ethers } from 'ethers'; import { useCallback } from 'react'; // ERC20 ABI for token balance queries const ERC20_ABI = ['function balanceOf(address owner) view returns (uint256)']; // Constants const REFETCH_INTERVAL = 5000; // 5 seconds // Function to get EVM provider based on chainId const getEVMProvider = (chainId) => { const urls = getRpcUrls(); const rpcUrl = urls[chainId]?.rpc[0]; if (!rpcUrl) { throw new Error(`No RPC URL configured for chain ID ${chainId}`); } return new ethers.JsonRpcProvider(rpcUrl); }; // Function to fetch EVM balance const fetchEVMBalance = async (address, tokenAddress, chainId) => { if (!address.startsWith('0x')) { return BigInt(0); } const provider = getEVMProvider(chainId); if (isNativeToken(tokenAddress)) { const balance = await provider.getBalance(address); return BigInt(balance.toString()); } else { const tokenContract = new ethers.Contract(tokenAddress, ERC20_ABI, provider); if (!tokenContract) { return BigInt(0); } const balance = await tokenContract.balanceOf?.(address); return BigInt(balance.toString()); } }; // Function to fetch Solana balance const fetchSolanaBalance = async (address, tokenAddress) => { try { const ownerPublicKey = new PublicKey(address); const solanaProvider = await getSolanaProvider(); if (compareAddresses(tokenAddress, SOL_NATIVE)) { const balance = await solanaProvider.getBalance(ownerPublicKey); return BigInt(balance); } else { const ownerPubKey = new PublicKey(address); const mintPubKey = new PublicKey(tokenAddress); const tokenAccounts = await Promise.all([ solanaProvider.getParsedTokenAccountsByOwner(ownerPubKey, { programId: TOKEN_PROGRAM_ID }), solanaProvider.getParsedTokenAccountsByOwner(ownerPubKey, { programId: TOKEN_2022_PROGRAM_ID }), ]); const mint58 = mintPubKey.toBase58(); const flatAccounts = tokenAccounts.flatMap((accounts) => accounts.value); const tokenAccount = flatAccounts.find((account) => account?.account?.data?.parsed?.info?.mint === mint58); if (!tokenAccount) { return BigInt(0); } return BigInt(tokenAccount.account.data.parsed.info.tokenAmount.amount); } } catch (error) { console.error('Solana balance fetch error:', error); return BigInt(0); } }; export const useBalance = (userChainAddress, tokenAddress, chainId) => { const address = userChainAddress; const fetchBalance = useCallback(async () => { try { // Return 0n if no address is available if (!address) return BigInt(0); if (isEVMChain(chainId)) { return await fetchEVMBalance(address, tokenAddress, chainId); } else if (isSolanaChain(chainId)) { return await fetchSolanaBalance(address, tokenAddress); } else { throw new Error('Unsupported chain'); } } catch (err) { console.error('Balance fetch error:', err); return BigInt(0); } }, [address, tokenAddress, chainId]); const { data: balance, isLoading: loading, error, } = useQuery({ queryKey: ['userAccountBalance', address, tokenAddress, chainId], queryFn: fetchBalance, refetchInterval: REFETCH_INTERVAL, enabled: !!address && !!tokenAddress && !!chainId, }); return { balance, loading, error: error }; }; //# sourceMappingURL=useBalance.js.map