Skip to content

Commit

Permalink
get Execute Withdrawal to show up
Browse files Browse the repository at this point in the history
  • Loading branch information
0age committed Dec 7, 2024
1 parent 74663be commit 3f5c60d
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 87 deletions.
5 changes: 3 additions & 2 deletions frontend/src/components/BalanceDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,8 @@ export function BalanceDisplay(): JSX.Element | null {
const now = Math.floor(Date.now() / 1000);
const withdrawableAt = parseInt(balance.withdrawableAt || '0');
const canExecuteWithdrawal =
balance.withdrawalStatus === 2 && withdrawableAt <= now;
parseInt(balance.withdrawalStatus.toString()) !== 0 &&
withdrawableAt <= now;
const withdrawalTimeRemaining = formatTimeRemaining(withdrawableAt);

return (
Expand Down Expand Up @@ -280,7 +281,7 @@ export function BalanceDisplay(): JSX.Element | null {
});
setIsExecuteDialogOpen(true);
}}
className="mt-2 py-2 px-4 bg-[#DC2626] text-white rounded-lg font-medium hover:opacity-90 transition-colors"
className="mt-2 py-2 px-4 bg-[#F97316] text-white rounded-lg font-medium hover:opacity-90 transition-colors"
>
Execute Withdrawal
</button>
Expand Down
191 changes: 106 additions & 85 deletions frontend/src/hooks/useBalances.ts
Original file line number Diff line number Diff line change
@@ -1,151 +1,172 @@
import { useState, useEffect, useRef, useCallback } from 'react'
import { useAccount } from 'wagmi'
import { useResourceLocks } from './useResourceLocks'
import { formatUnits } from 'viem'
import { useState, useEffect, useRef, useCallback } from 'react';
import { useAccount } from 'wagmi';
import { useResourceLocks } from './useResourceLocks';
import { formatUnits } from 'viem';

interface Token {
tokenAddress: string
name: string
symbol: string
decimals: number
tokenAddress: string;
name: string;
symbol: string;
decimals: number;
}

interface ResourceLock {
resetPeriod: number
isMultichain: boolean
resetPeriod: number;
isMultichain: boolean;
}

interface Balance {
chainId: string
lockId: string
allocatableBalance: string
allocatedBalance: string
balanceAvailableToAllocate: string
withdrawalStatus: number
withdrawableAt: string
chainId: string;
lockId: string;
allocatableBalance: string;
allocatedBalance: string;
balanceAvailableToAllocate: string;
withdrawalStatus: number;
withdrawableAt: string;
// Token details from indexer
token?: Token
token?: Token;
// Resource lock details from indexer
resourceLock?: ResourceLock
resourceLock?: ResourceLock;
// Formatted balances using token decimals
formattedAllocatableBalance?: string
formattedAllocatedBalance?: string
formattedAvailableBalance?: string
formattedAllocatableBalance?: string;
formattedAllocatedBalance?: string;
formattedAvailableBalance?: string;
}

interface UseBalancesResult {
balances: Balance[]
error: string | null
isLoading: boolean
balances: Balance[];
error: string | null;
isLoading: boolean;
}

interface ResourceLockItem {
chainId: string;
resourceLock: {
lockId: string
token: Token
resetPeriod: number
isMultichain: boolean
}
lockId: string;
token: Token;
resetPeriod: number;
isMultichain: boolean;
};
}

export function useBalances(): UseBalancesResult {
const { address, isConnected } = useAccount()
const [balances, setBalances] = useState<Balance[]>([])
const [error, setError] = useState<string | null>(null)
const [isLoading, setIsLoading] = useState(false)
const isFetchingRef = useRef(false)
const { address, isConnected } = useAccount();
const [balances, setBalances] = useState<Balance[]>([]);
const [error, setError] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState(false);
const isFetchingRef = useRef(false);

// Get resource lock details from indexer
const { data: resourceLocksData, error: resourceLocksError, isLoading: resourceLocksLoading } = useResourceLocks()
const {
data: resourceLocksData,
error: resourceLocksError,
isLoading: resourceLocksLoading,
} = useResourceLocks();

const fetchBalances = useCallback(async (): Promise<void> => {
if (!isConnected || !address || isFetchingRef.current) return
isFetchingRef.current = true
if (!isConnected || !address || isFetchingRef.current) return;

isFetchingRef.current = true;

try {
const sessionId = localStorage.getItem(`session-${address}`)
const sessionId = localStorage.getItem(`session-${address}`);
if (!sessionId) {
throw new Error('No session ID found')
throw new Error('No session ID found');
}

const response = await fetch('/balances', {
headers: {
'x-session-id': sessionId
}
})
if (!response.ok) throw new Error('Failed to fetch balances.')
const data = await response.json()
'x-session-id': sessionId,
},
});

if (!response.ok) throw new Error('Failed to fetch balances.');

const data = await response.json();

// Only update state if data has actually changed
setBalances(prevBalances => {
setBalances((prevBalances) => {
const newBalances = data.balances.map((balance: Balance) => {
// Find matching resource lock from indexer data
const resourceLock = resourceLocksData?.resourceLocks.items.find(
(item: ResourceLockItem) => item.resourceLock.lockId === balance.lockId
)
(item: ResourceLockItem) =>
item.resourceLock.lockId === balance.lockId &&
item.chainId === balance.chainId
);

if (resourceLock) {
const token = resourceLock.resourceLock.token
const decimals = token.decimals
const token = resourceLock.resourceLock.token;
const decimals = token.decimals;

return {
...balance,
token,
resourceLock: {
resetPeriod: resourceLock.resourceLock.resetPeriod,
isMultichain: resourceLock.resourceLock.isMultichain
isMultichain: resourceLock.resourceLock.isMultichain,
},
formattedAllocatableBalance: formatUnits(BigInt(balance.allocatableBalance), decimals),
formattedAllocatedBalance: formatUnits(BigInt(balance.allocatedBalance), decimals),
formattedAvailableBalance: formatUnits(BigInt(balance.balanceAvailableToAllocate), decimals)
}
formattedAllocatableBalance: formatUnits(
BigInt(balance.allocatableBalance),
decimals
),
formattedAllocatedBalance: formatUnits(
BigInt(balance.allocatedBalance),
decimals
),
formattedAvailableBalance: formatUnits(
BigInt(balance.balanceAvailableToAllocate),
decimals
),
};
}

return balance
})
return balance;
});

const hasChanged = JSON.stringify(prevBalances) !== JSON.stringify(newBalances)
return hasChanged ? newBalances : prevBalances
})

setError(null)
const hasChanged =
JSON.stringify(prevBalances) !== JSON.stringify(newBalances);
return hasChanged ? newBalances : prevBalances;
});

setError(null);
} catch (err) {
setError(err instanceof Error ? err.message : 'Failed to fetch balances')
setError(err instanceof Error ? err.message : 'Failed to fetch balances');
} finally {
isFetchingRef.current = false
isFetchingRef.current = false;
}
}, [isConnected, address, resourceLocksData])
}, [isConnected, address, resourceLocksData]);

useEffect(() => {
// Initial load should show loading state
if (isConnected && address) {
setIsLoading(true)
void fetchBalances().finally(() => setIsLoading(false))
setIsLoading(true);
void fetchBalances().finally(() => setIsLoading(false));
}

// Set up polling interval
const intervalId = setInterval(() => void fetchBalances(), 1000) // Poll every second
const intervalId = setInterval(() => void fetchBalances(), 1000); // Poll every second

// Cleanup on unmount or address change
return () => {
clearInterval(intervalId)
isFetchingRef.current = false
}
}, [fetchBalances, isConnected, address])
clearInterval(intervalId);
isFetchingRef.current = false;
};
}, [fetchBalances, isConnected, address]);

// Set error from resource locks if present
useEffect(() => {
if (resourceLocksError) {
setError(resourceLocksError instanceof Error ? resourceLocksError.message : 'Failed to fetch resource locks')
setError(
resourceLocksError instanceof Error
? resourceLocksError.message
: 'Failed to fetch resource locks'
);
}
}, [resourceLocksError])
}, [resourceLocksError]);

return {
balances,
error,
isLoading: isLoading || resourceLocksLoading
}
return {
balances,
error,
isLoading: isLoading || resourceLocksLoading,
};
}

0 comments on commit 3f5c60d

Please sign in to comment.