Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export function useNetworkData() {
const balances = useBalances()
const { isTestnet, chainId: walletChainId } = useNetworkInfo()
const l1Balances = useWalletStore((state) => state.balances.l1Chains)
const pChainAddress = useWalletStore((state) => state.pChainAddress)

// Extract individual balance values for backward compatibility
const { cChain: cChainBalance } = balances
Expand All @@ -19,11 +20,11 @@ export function useNetworkData() {

// Update all L1 balances when l1List changes or wallet connects
useEffect(() => {
if (walletEVMAddress && l1List && l1List.length > 0) {
if (walletEVMAddress && pChainAddress && l1List && l1List.length > 0) {
// Update balances for all L1s using the balance service
balanceService.updateAllBalancesWithAllL1s(l1List)
}
}, [l1List, walletEVMAddress])
}, [l1List, walletEVMAddress, pChainAddress])

// Determine current network and balance
const currentNetwork = useMemo(() => {
Expand Down
66 changes: 51 additions & 15 deletions components/toolbox/services/balanceService.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { getPChainBalance, getNativeTokenBalance, getChains } from '../coreViem/utils/glacier';
import { avalancheFuji, avalanche } from 'viem/chains';
import { networkIDs } from '@avalabs/avalanchejs';

// Local debounce function
function debounce<T extends (...args: any[]) => any>(
Expand Down Expand Up @@ -40,6 +41,7 @@ interface BalanceUpdateCallbacks {
walletChainId: number;
walletEVMAddress: string;
publicClient: any;
avalancheNetworkID?: number;
isLoading: {
pChain: boolean;
cChain: boolean;
Expand All @@ -51,6 +53,9 @@ interface BalanceUpdateCallbacks {
// Service class for managing balance operations
class BalanceService {
private callbacks: BalanceUpdateCallbacks | null = null;
private pChainRequestId = 0;
private cChainRequestId = 0;
private l1RequestIds = new Map<string, number>();


constructor(private debounceTime: number = 500) { }
Expand All @@ -67,27 +72,37 @@ class BalanceService {
if (!this.callbacks) return;
const state = this.callbacks.getState();

if (state.isLoading.pChain) return;
const requestId = ++this.pChainRequestId;

this.callbacks.setLoading('pChain', true);
try {
const balance = await this.fetchPChainBalance(state.isTestnet ?? false, state.pChainAddress);
this.callbacks.setBalance('pChain', balance);
if (!state.pChainAddress) {
return;
}

const network = this.resolvePChainNetwork(state);
const balance = await this.fetchPChainBalance(network, state.pChainAddress);
if (requestId === this.pChainRequestId) {
this.callbacks.setBalance('pChain', balance);
}
} finally {
this.callbacks.setLoading('pChain', false);
if (requestId === this.pChainRequestId) {
this.callbacks.setLoading('pChain', false);
}
}
}, this.debounceTime);

this.updatePChainBalance = async () => {
await debouncedPChainUpdate();
debouncedPChainUpdate();
};

// Create debounced L1 update function that takes chainId
const createDebouncedL1Update = (chainId: string) => debounce(async () => {
if (!this.callbacks) return;
const state = this.callbacks.getState();

if (state.isLoading.l1Chains[chainId]) return;
const currentRequestId = (this.l1RequestIds.get(chainId) || 0) + 1;
this.l1RequestIds.set(chainId, currentRequestId);

this.callbacks.setLoading(chainId, true);
try {
Expand All @@ -96,9 +111,13 @@ class BalanceService {
state.walletEVMAddress,
state.publicClient
);
this.callbacks.setBalance(chainId, balance);
if (currentRequestId === this.l1RequestIds.get(chainId)) {
this.callbacks.setBalance(chainId, balance);
}
} finally {
this.callbacks.setLoading(chainId, false);
if (currentRequestId === this.l1RequestIds.get(chainId)) {
this.callbacks.setLoading(chainId, false);
}
}
}, this.debounceTime);

Expand All @@ -109,35 +128,52 @@ class BalanceService {
if (!debouncedL1Updates.has(chainId)) {
debouncedL1Updates.set(chainId, createDebouncedL1Update(chainId));
}
await debouncedL1Updates.get(chainId)!();
debouncedL1Updates.get(chainId)!();
};

const debouncedCChainUpdate = debounce(async () => {
if (!this.callbacks) return;
const state = this.callbacks.getState();

if (state.isLoading.cChain) return;
const requestId = ++this.cChainRequestId;

this.callbacks.setLoading('cChain', true);
try {
const balance = await this.fetchCChainBalance(state.isTestnet ?? false, state.walletEVMAddress);
this.callbacks.setBalance('cChain', balance);
if (requestId === this.cChainRequestId) {
this.callbacks.setBalance('cChain', balance);
}
} finally {
this.callbacks.setLoading('cChain', false);
if (requestId === this.cChainRequestId) {
this.callbacks.setLoading('cChain', false);
}
}
}, this.debounceTime);

this.updateCChainBalance = async () => {
await debouncedCChainUpdate();
debouncedCChainUpdate();
};
}

// P-Chain balance fetching
async fetchPChainBalance(isTestnet: boolean, pChainAddress: string): Promise<number> {
private resolvePChainNetwork(state: ReturnType<BalanceUpdateCallbacks['getState']>): 'testnet' | 'mainnet' {
if (state.walletChainId === avalancheFuji.id) return 'testnet';
if (state.walletChainId === avalanche.id) return 'mainnet';

if (typeof state.isTestnet === 'boolean') {
return state.isTestnet ? 'testnet' : 'mainnet';
}

if (state.avalancheNetworkID === networkIDs.FujiID) return 'testnet';
if (state.avalancheNetworkID === networkIDs.MainnetID) return 'mainnet';

return 'mainnet';
}

async fetchPChainBalance(network: 'testnet' | 'mainnet', pChainAddress: string): Promise<number> {
if (!pChainAddress) return 0;

try {
const network = isTestnet ? "testnet" : "mainnet";
const response = await getPChainBalance(network, pChainAddress);
return Number(response.balances.unlockedUnstaked[0]?.amount || 0) / 1e9;
} catch (error) {
Expand Down