diff --git a/alm/src/components/ConfirmationsContainer.tsx b/alm/src/components/ConfirmationsContainer.tsx index ead23412..f4995c44 100644 --- a/alm/src/components/ConfirmationsContainer.tsx +++ b/alm/src/components/ConfirmationsContainer.tsx @@ -11,6 +11,7 @@ import { getConfirmationsStatusDescription } from '../utils/networks' import { useStateProvider } from '../state/StateProvider' import { ExecutionConfirmation } from './ExecutionConfirmation' import { useValidatorContract } from '../hooks/useValidatorContract' +import { useBlockConfirmations } from '../hooks/useBlockConfirmations' const StatusLabel = styled.label` font-weight: bold; @@ -45,13 +46,15 @@ export const ConfirmationsContainer = ({ message, receipt, fromHome, timestamp } foreign: { name: foreignName } } = useStateProvider() const { requiredSignatures, validatorList } = useValidatorContract({ fromHome, receipt }) + const { blockConfirmations } = useBlockConfirmations({ fromHome, receipt }) const { confirmations, status, executionData, signatureCollected } = useMessageConfirmations({ message, receipt, fromHome, timestamp, requiredSignatures, - validatorList + validatorList, + blockConfirmations }) return ( diff --git a/alm/src/hooks/useBlockConfirmations.ts b/alm/src/hooks/useBlockConfirmations.ts new file mode 100644 index 00000000..438e9e5a --- /dev/null +++ b/alm/src/hooks/useBlockConfirmations.ts @@ -0,0 +1,38 @@ +import { useEffect, useState } from 'react' +import { TransactionReceipt } from 'web3-eth' +import { useStateProvider } from '../state/StateProvider' +import { Contract } from 'web3-eth-contract' +import { getRequiredBlockConfirmations } from '../utils/contract' + +export interface UseBlockConfirmationsParams { + fromHome: boolean + receipt: Maybe +} + +export const useBlockConfirmations = ({ receipt, fromHome }: UseBlockConfirmationsParams) => { + const [blockConfirmations, setBlockConfirmations] = useState(0) + + const { home, foreign } = useStateProvider() + + const callRequireBlockConfirmations = async ( + contract: Contract, + receipt: TransactionReceipt, + setResult: Function + ) => { + const result = await getRequiredBlockConfirmations(contract, receipt.blockNumber) + setResult(result) + } + + useEffect( + () => { + const bridgeContract = fromHome ? home.bridgeContract : foreign.bridgeContract + if (!bridgeContract || !receipt) return + callRequireBlockConfirmations(bridgeContract, receipt, setBlockConfirmations) + }, + [home.bridgeContract, foreign.bridgeContract, receipt, fromHome] + ) + + return { + blockConfirmations + } +} diff --git a/alm/src/hooks/useBridgeContracts.ts b/alm/src/hooks/useBridgeContracts.ts index 02baeeea..c27bd980 100644 --- a/alm/src/hooks/useBridgeContracts.ts +++ b/alm/src/hooks/useBridgeContracts.ts @@ -3,7 +3,6 @@ import { HOME_AMB_ABI, FOREIGN_AMB_ABI } from '../abis' import { FOREIGN_BRIDGE_ADDRESS, HOME_BRIDGE_ADDRESS } from '../config/constants' import { Contract } from 'web3-eth-contract' import Web3 from 'web3' -import { getRequiredBlockConfirmations } from '../utils/contract' export interface useBridgeContractsParams { homeWeb3: Web3 @@ -13,20 +12,11 @@ export interface useBridgeContractsParams { export const useBridgeContracts = ({ homeWeb3, foreignWeb3 }: useBridgeContractsParams) => { const [homeBridge, setHomeBridge] = useState>(null) const [foreignBridge, setForeignBridge] = useState>(null) - const [homeBlockConfirmations, setHomeBlockConfirmations] = useState(0) - const [foreignBlockConfirmations, setForeignBlockConfirmations] = useState(0) - - const callRequireBlockConfirmations = async (contract: Maybe, setResult: Function) => { - if (!contract) return - const result = await getRequiredBlockConfirmations(contract) - setResult(result) - } useEffect( () => { if (!homeWeb3) return const homeContract = new homeWeb3.eth.Contract(HOME_AMB_ABI, HOME_BRIDGE_ADDRESS) - callRequireBlockConfirmations(homeContract, setHomeBlockConfirmations) setHomeBridge(homeContract) }, [homeWeb3] @@ -36,7 +26,6 @@ export const useBridgeContracts = ({ homeWeb3, foreignWeb3 }: useBridgeContracts () => { if (!foreignWeb3) return const foreignContract = new foreignWeb3.eth.Contract(FOREIGN_AMB_ABI, FOREIGN_BRIDGE_ADDRESS) - callRequireBlockConfirmations(foreignContract, setForeignBlockConfirmations) setForeignBridge(foreignContract) }, [foreignWeb3] @@ -44,8 +33,6 @@ export const useBridgeContracts = ({ homeWeb3, foreignWeb3 }: useBridgeContracts return { homeBridge, - foreignBridge, - homeBlockConfirmations, - foreignBlockConfirmations + foreignBridge } } diff --git a/alm/src/hooks/useMessageConfirmations.ts b/alm/src/hooks/useMessageConfirmations.ts index 299bb387..9b27f010 100644 --- a/alm/src/hooks/useMessageConfirmations.ts +++ b/alm/src/hooks/useMessageConfirmations.ts @@ -32,6 +32,7 @@ export interface useMessageConfirmationsParams { timestamp: number requiredSignatures: number validatorList: string[] + blockConfirmations: number } export interface BasicConfirmationParam { @@ -58,7 +59,8 @@ export const useMessageConfirmations = ({ fromHome, timestamp, requiredSignatures, - validatorList + validatorList, + blockConfirmations }: useMessageConfirmationsParams) => { const { home, foreign } = useStateProvider() const [confirmations, setConfirmations] = useState>([]) @@ -84,7 +86,7 @@ export const useMessageConfirmations = ({ // Check if the validators are waiting for block confirmations to verify the message useEffect( () => { - if (!receipt) return + if (!receipt || !blockConfirmations) return const subscriptions: Array = [] @@ -99,8 +101,7 @@ export const useMessageConfirmations = ({ const web3 = fromHome ? home.web3 : foreign.web3 blockProvider.start(web3) - const requiredBlockConfirmations = fromHome ? home.blockConfirmations : foreign.blockConfirmations - const targetBlock = receipt.blockNumber + requiredBlockConfirmations + const targetBlock = receipt.blockNumber + blockConfirmations checkSignaturesWaitingForBLocks( targetBlock, @@ -118,7 +119,7 @@ export const useMessageConfirmations = ({ blockProvider.stop() } }, - [foreign.blockConfirmations, foreign.web3, fromHome, home.blockConfirmations, validatorList, home.web3, receipt] + [blockConfirmations, foreign.web3, fromHome, validatorList, home.web3, receipt] ) // The collected signature event is only fetched once the signatures are collected on tx from home to foreign, to calculate if @@ -164,7 +165,7 @@ export const useMessageConfirmations = ({ // This is executed if the message is in Home to Foreign direction only useEffect( () => { - if (!fromHome || !home.web3 || !receipt || !collectedSignaturesEvent) return + if (!fromHome || !home.web3 || !receipt || !collectedSignaturesEvent || !blockConfirmations) return const subscriptions: Array = [] @@ -175,7 +176,7 @@ export const useMessageConfirmations = ({ } homeBlockNumberProvider.start(home.web3) - const targetBlock = collectedSignaturesEvent.blockNumber + home.blockConfirmations + const targetBlock = collectedSignaturesEvent.blockNumber + blockConfirmations checkWaitingBlocksForExecution( homeBlockNumberProvider, @@ -193,7 +194,7 @@ export const useMessageConfirmations = ({ homeBlockNumberProvider.stop() } }, - [collectedSignaturesEvent, fromHome, home.blockConfirmations, home.web3, receipt] + [collectedSignaturesEvent, fromHome, blockConfirmations, home.web3, receipt] ) // Checks if validators verified the message diff --git a/alm/src/state/StateProvider.tsx b/alm/src/state/StateProvider.tsx index 3920c095..16762011 100644 --- a/alm/src/state/StateProvider.tsx +++ b/alm/src/state/StateProvider.tsx @@ -18,7 +18,6 @@ export interface BaseNetworkParams { web3: Maybe bridgeAddress: string bridgeContract: Maybe - blockConfirmations: number } export interface StateContext { @@ -33,16 +32,14 @@ const initialState = { name: '', web3: null, bridgeAddress: HOME_BRIDGE_ADDRESS, - bridgeContract: null, - blockConfirmations: 0 + bridgeContract: null }, foreign: { chainId: 0, name: '', web3: null, bridgeAddress: FOREIGN_BRIDGE_ADDRESS, - bridgeContract: null, - blockConfirmations: 0 + bridgeContract: null }, loading: true } @@ -52,7 +49,7 @@ const StateContext = createContext(initialState) export const StateProvider = ({ children }: { children: ReactNode }) => { const homeNetwork = useNetwork(HOME_RPC_URL) const foreignNetwork = useNetwork(FOREIGN_RPC_URL) - const { homeBridge, foreignBridge, homeBlockConfirmations, foreignBlockConfirmations } = useBridgeContracts({ + const { homeBridge, foreignBridge } = useBridgeContracts({ homeWeb3: homeNetwork.web3, foreignWeb3: foreignNetwork.web3 }) @@ -62,14 +59,12 @@ export const StateProvider = ({ children }: { children: ReactNode }) => { bridgeAddress: HOME_BRIDGE_ADDRESS, name: HOME_NETWORK_NAME, bridgeContract: homeBridge, - blockConfirmations: homeBlockConfirmations, ...homeNetwork }, foreign: { bridgeAddress: FOREIGN_BRIDGE_ADDRESS, name: FOREIGN_NETWORK_NAME, bridgeContract: foreignBridge, - blockConfirmations: foreignBlockConfirmations, ...foreignNetwork }, loading: homeNetwork.loading || foreignNetwork.loading diff --git a/alm/src/utils/contract.ts b/alm/src/utils/contract.ts index f1e6bd98..2b81c290 100644 --- a/alm/src/utils/contract.ts +++ b/alm/src/utils/contract.ts @@ -1,7 +1,21 @@ import { Contract } from 'web3-eth-contract' -export const getRequiredBlockConfirmations = async (contract: Contract) => { - const blockConfirmations = await contract.methods.requiredBlockConfirmations().call() +export const getRequiredBlockConfirmations = async (contract: Contract, blockNumber: number) => { + const events = await contract.getPastEvents('RequiredBlockConfirmationChanged', { + fromBlock: 0, + toBlock: blockNumber + }) + + let blockConfirmations + if (events.length > 0) { + // Use the value from last event before the transaction + const event = events[events.length - 1] + blockConfirmations = event.returnValues.requiredBlockConfirmations + } else { + // This is a special case where RequiredBlockConfirmationChanged was not emitted during initialization in early versions of AMB + // of Sokol - Kovan. In this case the current value is used. + blockConfirmations = await contract.methods.requiredBlockConfirmations().call() + } return parseInt(blockConfirmations) }