import React from 'react'; import type { ethers } from 'ethers'; import * as Sentry from '@sentry/react'; import { addDecimal } from '@vegaprotocol/utils'; import type { StakingBridge, TokenVesting, } from '@vegaprotocol/smart-contracts'; import { useAppState } from '../contexts/app-state/app-state-context'; import BigNumber from 'bignumber.js'; import { useBalances } from '../lib/balances/balances-store'; export enum StakingEventType { Stake_Removed = 'Stake_Removed', Stake_Deposited = 'Stake_Deposited', } export function useGetAssociationBreakdown( ethAddress: string, staking: StakingBridge, vesting: TokenVesting ): () => Promise { const { appState: { decimals }, } = useAppState(); const { setAssociationBreakdown } = useBalances(); const getAssociationBreakdown = React.useCallback(async () => { try { const [stakingAssociations, vestingAssociations] = await Promise.all([ userTotalStakedByVegaKey(staking, ethAddress, decimals), userTotalStakedByVegaKey(vesting, ethAddress, decimals), ]); setAssociationBreakdown({ stakingAssociations, vestingAssociations, }); } catch (err) { Sentry.captureException(err); } }, [ethAddress, staking, vesting, decimals, setAssociationBreakdown]); return getAssociationBreakdown; } async function userTotalStakedByVegaKey( contract: StakingBridge | TokenVesting, ethereumAccount: string, decimals: number ): Promise<{ [vegaKey: string]: BigNumber }> { const addFilter = contract.contract.filters.Stake_Deposited(ethereumAccount); const removeFilter = contract.contract.filters.Stake_Removed(ethereumAccount); const addEvents = await contract.contract.queryFilter(addFilter); const removeEvents = await contract.contract.queryFilter(removeFilter); const res = combineStakeEventsByVegaKey( [...addEvents, ...removeEvents], decimals ); return res; } function combineStakeEventsByVegaKey( events: ethers.Event[], decimals: number ): { [vegaKey: string]: BigNumber } { const res = events.reduce((obj, e) => { const vegaKey = e.args?.vega_public_key; const amount = parseEventAmount(e, decimals); const isDeposit = e.event === StakingEventType.Stake_Deposited; const isRemove = e.event === StakingEventType.Stake_Removed; if (!isDeposit && !isRemove) return obj; if (Object.prototype.hasOwnProperty.call(obj, vegaKey)) { if (isDeposit) { obj[vegaKey] = obj[vegaKey].plus(amount); } else { obj[vegaKey] = obj[vegaKey].minus(amount); } } else { if (isDeposit) { obj[vegaKey] = amount; } else { obj[vegaKey] = new BigNumber(0); } } return obj; }, {} as { [vegaKey: string]: BigNumber }); return res; } function parseEventAmount(e: ethers.Event, decimals: number) { const rawAmount = new BigNumber(e.args?.amount.toString() || 0); return new BigNumber(addDecimal(rawAmount.toString(), decimals)); }