Build the list of validators and required signatures at the moment of the transaction (#367)
This commit is contained in:
parent
9e9e891db8
commit
0eb7c41278
@ -10,6 +10,7 @@ import { ValidatorsConfirmations } from './ValidatorsConfirmations'
|
||||
import { getConfirmationsStatusDescription } from '../utils/networks'
|
||||
import { useStateProvider } from '../state/StateProvider'
|
||||
import { ExecutionConfirmation } from './ExecutionConfirmation'
|
||||
import { useValidatorContract } from '../hooks/useValidatorContract'
|
||||
|
||||
const StatusLabel = styled.label`
|
||||
font-weight: bold;
|
||||
@ -43,11 +44,14 @@ export const ConfirmationsContainer = ({ message, receipt, fromHome, timestamp }
|
||||
home: { name: homeName },
|
||||
foreign: { name: foreignName }
|
||||
} = useStateProvider()
|
||||
const { requiredSignatures, validatorList } = useValidatorContract({ fromHome, receipt })
|
||||
const { confirmations, status, executionData, signatureCollected } = useMessageConfirmations({
|
||||
message,
|
||||
receipt,
|
||||
fromHome,
|
||||
timestamp
|
||||
timestamp,
|
||||
requiredSignatures,
|
||||
validatorList
|
||||
})
|
||||
|
||||
return (
|
||||
@ -66,7 +70,11 @@ export const ConfirmationsContainer = ({ message, receipt, fromHome, timestamp }
|
||||
: ''}
|
||||
</p>
|
||||
</StatusDescription>
|
||||
<ValidatorsConfirmations confirmations={confirmations} />
|
||||
<ValidatorsConfirmations
|
||||
confirmations={confirmations}
|
||||
requiredSignatures={requiredSignatures}
|
||||
validatorList={validatorList}
|
||||
/>
|
||||
{signatureCollected && <ExecutionConfirmation executionData={executionData} isHome={!fromHome} />}
|
||||
</StyledConfirmationContainer>
|
||||
</div>
|
||||
|
@ -1,6 +1,5 @@
|
||||
import React from 'react'
|
||||
import { formatTxHashExtended } from '../utils/networks'
|
||||
import { useStateProvider } from '../state/StateProvider'
|
||||
import { useWindowWidth } from '@react-hook/window-size'
|
||||
import { VALIDATOR_CONFIRMATION_STATUS } from '../config/constants'
|
||||
import { SimpleLoading } from './commons/Loading'
|
||||
@ -18,12 +17,15 @@ const RequiredConfirmations = styled.label`
|
||||
|
||||
export interface ValidatorsConfirmationsParams {
|
||||
confirmations: Array<ConfirmationParam>
|
||||
requiredSignatures: number
|
||||
validatorList: string[]
|
||||
}
|
||||
|
||||
export const ValidatorsConfirmations = ({ confirmations }: ValidatorsConfirmationsParams) => {
|
||||
const {
|
||||
home: { requiredSignatures, validatorList }
|
||||
} = useStateProvider()
|
||||
export const ValidatorsConfirmations = ({
|
||||
confirmations,
|
||||
requiredSignatures,
|
||||
validatorList
|
||||
}: ValidatorsConfirmationsParams) => {
|
||||
const windowWidth = useWindowWidth()
|
||||
|
||||
const getValidatorStatusElement = (validatorStatus = '') => {
|
||||
|
@ -1,14 +1,9 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { HOME_AMB_ABI, FOREIGN_AMB_ABI, BRIDGE_VALIDATORS_ABI } from '../../../commons'
|
||||
import { HOME_AMB_ABI, FOREIGN_AMB_ABI } from '../../../commons'
|
||||
import { FOREIGN_BRIDGE_ADDRESS, HOME_BRIDGE_ADDRESS } from '../config/constants'
|
||||
import { Contract } from 'web3-eth-contract'
|
||||
import Web3 from 'web3'
|
||||
import {
|
||||
getRequiredBlockConfirmations,
|
||||
getRequiredSignatures,
|
||||
getValidatorAddress,
|
||||
getValidatorList
|
||||
} from '../utils/contract'
|
||||
import { getRequiredBlockConfirmations } from '../utils/contract'
|
||||
|
||||
export interface useBridgeContractsParams {
|
||||
homeWeb3: Web3
|
||||
@ -20,9 +15,6 @@ export const useBridgeContracts = ({ homeWeb3, foreignWeb3 }: useBridgeContracts
|
||||
const [foreignBridge, setForeignBridge] = useState<Maybe<Contract>>(null)
|
||||
const [homeBlockConfirmations, setHomeBlockConfirmations] = useState(0)
|
||||
const [foreignBlockConfirmations, setForeignBlockConfirmations] = useState(0)
|
||||
const [homeValidatorContract, setHomeValidatorContract] = useState<Maybe<Contract>>(null)
|
||||
const [homeRequiredSignatures, setHomeRequiredSignatures] = useState(0)
|
||||
const [homeValidatorList, setHomeValidatorList] = useState([])
|
||||
|
||||
const callRequireBlockConfirmations = async (contract: Maybe<Contract>, setResult: Function) => {
|
||||
if (!contract) return
|
||||
@ -30,31 +22,11 @@ export const useBridgeContracts = ({ homeWeb3, foreignWeb3 }: useBridgeContracts
|
||||
setResult(result)
|
||||
}
|
||||
|
||||
const callValidatorContract = async (bridgeContract: Maybe<Contract>, web3: Web3, setValidatorContract: Function) => {
|
||||
if (!web3 || !bridgeContract) return
|
||||
const address = await getValidatorAddress(bridgeContract)
|
||||
const contract = new web3.eth.Contract(BRIDGE_VALIDATORS_ABI, address)
|
||||
setValidatorContract(contract)
|
||||
}
|
||||
|
||||
const callRequiredSignatures = async (contract: Maybe<Contract>, setResult: Function) => {
|
||||
if (!contract) return
|
||||
const result = await getRequiredSignatures(contract)
|
||||
setResult(result)
|
||||
}
|
||||
|
||||
const callValidatorList = async (contract: Maybe<Contract>, setResult: Function) => {
|
||||
if (!contract) return
|
||||
const result = await getValidatorList(contract)
|
||||
setResult(result)
|
||||
}
|
||||
|
||||
useEffect(
|
||||
() => {
|
||||
if (!homeWeb3) return
|
||||
const homeContract = new homeWeb3.eth.Contract(HOME_AMB_ABI, HOME_BRIDGE_ADDRESS)
|
||||
callRequireBlockConfirmations(homeContract, setHomeBlockConfirmations)
|
||||
callValidatorContract(homeContract, homeWeb3, setHomeValidatorContract)
|
||||
setHomeBridge(homeContract)
|
||||
},
|
||||
[homeWeb3]
|
||||
@ -70,21 +42,10 @@ export const useBridgeContracts = ({ homeWeb3, foreignWeb3 }: useBridgeContracts
|
||||
[foreignWeb3]
|
||||
)
|
||||
|
||||
useEffect(
|
||||
() => {
|
||||
callRequiredSignatures(homeValidatorContract, setHomeRequiredSignatures)
|
||||
callValidatorList(homeValidatorContract, setHomeValidatorList)
|
||||
},
|
||||
[homeValidatorContract]
|
||||
)
|
||||
|
||||
return {
|
||||
homeBridge,
|
||||
foreignBridge,
|
||||
homeBlockConfirmations,
|
||||
foreignBlockConfirmations,
|
||||
homeValidatorContract,
|
||||
homeRequiredSignatures,
|
||||
homeValidatorList
|
||||
foreignBlockConfirmations
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +29,8 @@ export interface useMessageConfirmationsParams {
|
||||
receipt: Maybe<TransactionReceipt>
|
||||
fromHome: boolean
|
||||
timestamp: number
|
||||
requiredSignatures: number
|
||||
validatorList: string[]
|
||||
}
|
||||
|
||||
export interface ConfirmationParam {
|
||||
@ -44,7 +46,14 @@ export interface ExecutionData {
|
||||
executionResult: boolean
|
||||
}
|
||||
|
||||
export const useMessageConfirmations = ({ message, receipt, fromHome, timestamp }: useMessageConfirmationsParams) => {
|
||||
export const useMessageConfirmations = ({
|
||||
message,
|
||||
receipt,
|
||||
fromHome,
|
||||
timestamp,
|
||||
requiredSignatures,
|
||||
validatorList
|
||||
}: useMessageConfirmationsParams) => {
|
||||
const { home, foreign } = useStateProvider()
|
||||
const [confirmations, setConfirmations] = useState<Array<ConfirmationParam>>([])
|
||||
const [status, setStatus] = useState(CONFIRMATIONS_STATUS.UNDEFINED)
|
||||
@ -91,7 +100,7 @@ export const useMessageConfirmations = ({ message, receipt, fromHome, timestamp
|
||||
targetBlock,
|
||||
setWaitingBlocks,
|
||||
setWaitingBlocksResolved,
|
||||
home.validatorList,
|
||||
validatorList,
|
||||
setConfirmations,
|
||||
blockProvider,
|
||||
interval,
|
||||
@ -103,15 +112,7 @@ export const useMessageConfirmations = ({ message, receipt, fromHome, timestamp
|
||||
blockProvider.stop()
|
||||
}
|
||||
},
|
||||
[
|
||||
foreign.blockConfirmations,
|
||||
foreign.web3,
|
||||
fromHome,
|
||||
home.blockConfirmations,
|
||||
home.validatorList,
|
||||
home.web3,
|
||||
receipt
|
||||
]
|
||||
[foreign.blockConfirmations, foreign.web3, fromHome, home.blockConfirmations, 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
|
||||
@ -208,11 +209,11 @@ export const useMessageConfirmations = ({ message, receipt, fromHome, timestamp
|
||||
getConfirmationsForTx(
|
||||
message.data,
|
||||
home.web3,
|
||||
home.validatorList,
|
||||
validatorList,
|
||||
home.bridgeContract,
|
||||
confirmationContractMethod,
|
||||
setConfirmations,
|
||||
home.requiredSignatures,
|
||||
requiredSignatures,
|
||||
setSignatureCollected,
|
||||
waitingBlocksResolved,
|
||||
subscriptions,
|
||||
@ -231,9 +232,9 @@ export const useMessageConfirmations = ({ message, receipt, fromHome, timestamp
|
||||
fromHome,
|
||||
message.data,
|
||||
home.web3,
|
||||
home.validatorList,
|
||||
validatorList,
|
||||
home.bridgeContract,
|
||||
home.requiredSignatures,
|
||||
requiredSignatures,
|
||||
waitingBlocksResolved,
|
||||
timestamp
|
||||
]
|
||||
|
68
alm/src/hooks/useValidatorContract.ts
Normal file
68
alm/src/hooks/useValidatorContract.ts
Normal file
@ -0,0 +1,68 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { Contract } from 'web3-eth-contract'
|
||||
import Web3 from 'web3'
|
||||
import { getRequiredSignatures, getValidatorAddress, getValidatorList } from '../utils/contract'
|
||||
import { BRIDGE_VALIDATORS_ABI } from '../../../commons'
|
||||
import { useStateProvider } from '../state/StateProvider'
|
||||
import { TransactionReceipt } from 'web3-eth'
|
||||
|
||||
export interface useValidatorContractParams {
|
||||
fromHome: boolean
|
||||
receipt: Maybe<TransactionReceipt>
|
||||
}
|
||||
|
||||
export const useValidatorContract = ({ receipt, fromHome }: useValidatorContractParams) => {
|
||||
const [validatorContract, setValidatorContract] = useState<Maybe<Contract>>(null)
|
||||
const [requiredSignatures, setRequiredSignatures] = useState(0)
|
||||
const [validatorList, setValidatorList] = useState([])
|
||||
|
||||
const { home, foreign } = useStateProvider()
|
||||
|
||||
const callValidatorContract = async (bridgeContract: Maybe<Contract>, web3: Web3, setValidatorContract: Function) => {
|
||||
if (!web3 || !bridgeContract) return
|
||||
const address = await getValidatorAddress(bridgeContract)
|
||||
const contract = new web3.eth.Contract(BRIDGE_VALIDATORS_ABI, address)
|
||||
setValidatorContract(contract)
|
||||
}
|
||||
|
||||
const callRequiredSignatures = async (
|
||||
contract: Maybe<Contract>,
|
||||
receipt: TransactionReceipt,
|
||||
setResult: Function
|
||||
) => {
|
||||
if (!contract) return
|
||||
const result = await getRequiredSignatures(contract, receipt.blockNumber)
|
||||
setResult(result)
|
||||
}
|
||||
|
||||
const callValidatorList = async (contract: Maybe<Contract>, receipt: TransactionReceipt, setResult: Function) => {
|
||||
if (!contract) return
|
||||
const result = await getValidatorList(contract, receipt.blockNumber)
|
||||
setResult(result)
|
||||
}
|
||||
|
||||
useEffect(
|
||||
() => {
|
||||
const web3 = fromHome ? home.web3 : foreign.web3
|
||||
const bridgeContract = fromHome ? home.bridgeContract : foreign.bridgeContract
|
||||
|
||||
if (!web3 || !bridgeContract) return
|
||||
callValidatorContract(bridgeContract, web3, setValidatorContract)
|
||||
},
|
||||
[home.web3, foreign.web3, home.bridgeContract, foreign.bridgeContract, fromHome]
|
||||
)
|
||||
|
||||
useEffect(
|
||||
() => {
|
||||
if (!receipt) return
|
||||
callRequiredSignatures(validatorContract, receipt, setRequiredSignatures)
|
||||
callValidatorList(validatorContract, receipt, setValidatorList)
|
||||
},
|
||||
[validatorContract, receipt]
|
||||
)
|
||||
|
||||
return {
|
||||
requiredSignatures,
|
||||
validatorList
|
||||
}
|
||||
}
|
@ -21,14 +21,8 @@ export interface BaseNetworkParams {
|
||||
blockConfirmations: number
|
||||
}
|
||||
|
||||
export interface HomeNetworkParams extends BaseNetworkParams {
|
||||
validatorContract: Maybe<Contract>
|
||||
requiredSignatures: number
|
||||
validatorList: Array<string>
|
||||
}
|
||||
|
||||
export interface StateContext {
|
||||
home: HomeNetworkParams
|
||||
home: BaseNetworkParams
|
||||
foreign: BaseNetworkParams
|
||||
loading: boolean
|
||||
}
|
||||
@ -40,10 +34,7 @@ const initialState = {
|
||||
web3: null,
|
||||
bridgeAddress: HOME_BRIDGE_ADDRESS,
|
||||
bridgeContract: null,
|
||||
blockConfirmations: 0,
|
||||
validatorContract: null,
|
||||
requiredSignatures: 0,
|
||||
validatorList: []
|
||||
blockConfirmations: 0
|
||||
},
|
||||
foreign: {
|
||||
chainId: 0,
|
||||
@ -61,15 +52,7 @@ const StateContext = createContext<StateContext>(initialState)
|
||||
export const StateProvider = ({ children }: { children: ReactNode }) => {
|
||||
const homeNetwork = useNetwork(HOME_RPC_URL)
|
||||
const foreignNetwork = useNetwork(FOREIGN_RPC_URL)
|
||||
const {
|
||||
homeBridge,
|
||||
foreignBridge,
|
||||
homeBlockConfirmations,
|
||||
foreignBlockConfirmations,
|
||||
homeValidatorContract,
|
||||
homeRequiredSignatures,
|
||||
homeValidatorList
|
||||
} = useBridgeContracts({
|
||||
const { homeBridge, foreignBridge, homeBlockConfirmations, foreignBlockConfirmations } = useBridgeContracts({
|
||||
homeWeb3: homeNetwork.web3,
|
||||
foreignWeb3: foreignNetwork.web3
|
||||
})
|
||||
@ -80,9 +63,6 @@ export const StateProvider = ({ children }: { children: ReactNode }) => {
|
||||
name: HOME_NETWORK_NAME,
|
||||
bridgeContract: homeBridge,
|
||||
blockConfirmations: homeBlockConfirmations,
|
||||
validatorContract: homeValidatorContract,
|
||||
requiredSignatures: homeRequiredSignatures,
|
||||
validatorList: homeValidatorList,
|
||||
...homeNetwork
|
||||
},
|
||||
foreign: {
|
||||
|
@ -7,12 +7,46 @@ export const getRequiredBlockConfirmations = async (contract: Contract) => {
|
||||
|
||||
export const getValidatorAddress = (contract: Contract) => contract.methods.validatorContract().call()
|
||||
|
||||
export const getRequiredSignatures = async (contract: Contract) => {
|
||||
const requiredSignatures = await contract.methods.requiredSignatures().call()
|
||||
export const getRequiredSignatures = async (contract: Contract, blockNumber: number) => {
|
||||
const events = await contract.getPastEvents('RequiredSignaturesChanged', {
|
||||
fromBlock: 0,
|
||||
toBlock: blockNumber
|
||||
})
|
||||
|
||||
// Use the value form last event before the transaction
|
||||
const event = events[events.length - 1]
|
||||
const { requiredSignatures } = event.returnValues
|
||||
return parseInt(requiredSignatures)
|
||||
}
|
||||
|
||||
export const getValidatorList = (contract: Contract) => contract.methods.validatorList().call()
|
||||
export const getValidatorList = async (contract: Contract, blockNumber: number) => {
|
||||
let currentList: string[] = await contract.methods.validatorList().call()
|
||||
const [added, removed] = await Promise.all([
|
||||
contract.getPastEvents('ValidatorAdded', {
|
||||
fromBlock: blockNumber
|
||||
}),
|
||||
contract.getPastEvents('ValidatorRemoved', {
|
||||
fromBlock: blockNumber
|
||||
})
|
||||
])
|
||||
|
||||
// Ordered desc
|
||||
const orderedEvents = [...added, ...removed].sort(({ blockNumber: prev }, { blockNumber: next }) => next - prev)
|
||||
|
||||
// Stored as a Set to avoid duplicates
|
||||
const validatorList = new Set(currentList)
|
||||
|
||||
orderedEvents.forEach(e => {
|
||||
const { validator } = e.returnValues
|
||||
if (e.event === 'ValidatorRemoved') {
|
||||
validatorList.add(validator)
|
||||
} else if (e.event === 'ValidatorAdded') {
|
||||
validatorList.delete(validator)
|
||||
}
|
||||
})
|
||||
|
||||
return Array.from(validatorList)
|
||||
}
|
||||
|
||||
export const getMessagesSigned = (contract: Contract, hash: string) => contract.methods.messagesSigned(hash).call()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user