Add ALM transaction verification detection (#356)

This commit is contained in:
Gerardo Nardelli 2020-06-22 15:52:10 -03:00 committed by GitHub
parent 9b3e6a51a9
commit 3c956ab9ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 1356 additions and 289 deletions

@ -23,7 +23,7 @@
"react-scripts": "3.0.1",
"styled-components": "^5.1.1",
"typescript": "^3.5.2",
"web3": "^1.2.8"
"web3": "1.2.7"
},
"scripts": {
"start": "./load-env.sh react-app-rewired start",

@ -25,7 +25,7 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
<title>AMB Live Monitoring</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>

@ -1,9 +1,5 @@
import React from 'react'
import { render } from '@testing-library/react'
import App from './App'
test('renders learn react link', () => {
const { getByText } = render(<App />)
const linkElement = getByText(/AMB Live Monitoring/i)
expect(linkElement).toBeInTheDocument()
// Removed basic test from setup. Keeping this so CI passes until we add unit tests.
})

@ -0,0 +1,72 @@
import React from 'react'
import { TransactionReceipt } from 'web3-eth'
import { useMessageConfirmations } from '../hooks/useMessageConfirmations'
import { MessageObject } from '../utils/web3'
import styled from 'styled-components'
import { CONFIRMATIONS_STATUS } from '../config/constants'
import { CONFIRMATIONS_STATUS_LABEL } from '../config/descriptions'
import { SimpleLoading } from './commons/Loading'
import { ValidatorsConfirmations } from './ValidatorsConfirmations'
import { getConfirmationsStatusDescription } from '../utils/networks'
import { useStateProvider } from '../state/StateProvider'
import { ExecutionConfirmation } from './ExecutionConfirmation'
const StatusLabel = styled.label`
font-weight: bold;
font-size: 18px;
`
const StatusResultLabel = styled.label`
font-size: 18px;
padding-left: 10px;
`
const StyledConfirmationContainer = styled.div`
background-color: var(--color-primary);
padding: 10px;
border-radius: 4px;
`
const StatusDescription = styled.div`
padding-top: 10px;
`
export interface ConfirmationsContainerParams {
message: MessageObject
receipt: Maybe<TransactionReceipt>
fromHome: boolean
}
export const ConfirmationsContainer = ({ message, receipt, fromHome }: ConfirmationsContainerParams) => {
const {
home: { name: homeName },
foreign: { name: foreignName }
} = useStateProvider()
const { confirmations, status, executionData, signatureCollected } = useMessageConfirmations({
message,
receipt,
fromHome
})
return (
<div className="row is-center">
<StyledConfirmationContainer className="col-9">
<div className="row is-center">
<StatusLabel>Status:</StatusLabel>
<StatusResultLabel>
{status !== CONFIRMATIONS_STATUS.UNDEFINED ? CONFIRMATIONS_STATUS_LABEL[status] : <SimpleLoading />}
</StatusResultLabel>
</div>
<StatusDescription className="row is-center">
<p className="col-10">
{status !== CONFIRMATIONS_STATUS.UNDEFINED
? getConfirmationsStatusDescription(status, homeName, foreignName)
: ''}
</p>
</StatusDescription>
<ValidatorsConfirmations confirmations={confirmations} />
{signatureCollected && <ExecutionConfirmation executionData={executionData} isHome={!fromHome} />}
</StyledConfirmationContainer>
</div>
)
}

@ -0,0 +1,66 @@
import React from 'react'
import { formatTimestamp, formatTxHash, getExplorerTxUrl } from '../utils/networks'
import { useWindowWidth } from '@react-hook/window-size'
import { VALIDATOR_CONFIRMATION_STATUS } from '../config/constants'
import { SimpleLoading } from './commons/Loading'
import styled from 'styled-components'
import { ExecutionData } from '../hooks/useMessageConfirmations'
import { GreyLabel, SuccessLabel } from './commons/Labels'
import { ExplorerTxLink } from './commons/ExplorerTxLink'
const Thead = styled.thead`
border-bottom: 2px solid #9e9e9e;
`
const StyledExecutionConfirmation = styled.div`
margin-top: 30px;
`
export interface ExecutionConfirmationParams {
executionData: ExecutionData
isHome: boolean
}
export const ExecutionConfirmation = ({ executionData, isHome }: ExecutionConfirmationParams) => {
const windowWidth = useWindowWidth()
const txExplorerLink = getExplorerTxUrl(executionData.txHash, isHome)
const formattedValidator =
windowWidth < 850 && executionData.validator ? formatTxHash(executionData.validator) : executionData.validator
const getExecutionStatusElement = (validatorStatus = '') => {
switch (validatorStatus) {
case VALIDATOR_CONFIRMATION_STATUS.SUCCESS:
return <SuccessLabel>{validatorStatus}</SuccessLabel>
case VALIDATOR_CONFIRMATION_STATUS.WAITING:
return <GreyLabel>{validatorStatus}</GreyLabel>
default:
return <SimpleLoading />
}
}
return (
<StyledExecutionConfirmation>
<table>
<Thead>
<tr>
<th>Executed by</th>
<th className="text-center">Status</th>
<th className="text-center">Age</th>
</tr>
</Thead>
<tbody>
<tr>
<td>{formattedValidator ? formattedValidator : <SimpleLoading />}</td>
<td className="text-center">{getExecutionStatusElement(executionData.status)}</td>
<td className="text-center">
<ExplorerTxLink href={txExplorerLink} target="blank">
{executionData.timestamp > 0 ? formatTimestamp(executionData.timestamp) : ''}
</ExplorerTxLink>
</td>
</tr>
</tbody>
</table>
</StyledExecutionConfirmation>
)
}

@ -14,6 +14,7 @@ const LabelText = styled.label`
const Input = styled.input`
background-color: var(--color-primary);
color: var(--font-color);
max-width: 100%;
`
export const Form = ({ onSubmit }: { onSubmit: ({ chainId, txHash }: FormSubmitParams) => void }) => {

@ -1,6 +1,6 @@
import React from 'react'
import styled from 'styled-components'
import { Route, useHistory } from 'react-router-dom'
import { Route, useHistory, Link } from 'react-router-dom'
import { Form } from './Form'
import { StatusContainer } from './StatusContainer'
import { StateProvider } from '../state/StateProvider'
@ -18,6 +18,10 @@ const Header = styled.header`
font-size: calc(10px + 2vmin);
`
const Title = styled.p`
color: var(--font-color);
`
export interface FormSubmitParams {
chainId: number
txHash: string
@ -33,13 +37,12 @@ export const MainPage = () => {
<StateProvider>
<StyledMainPage>
<Header>
<p>AMB Live Monitoring</p>
<Link to="/">
<Title>AMB Live Monitoring</Title>
</Link>
</Header>
<div className="container">
<Route
path={['/:chainId/:txHash/:messageIdParam', '/:chainId/:txHash', '/']}
children={<Form onSubmit={onFormSubmit} />}
/>
<Route exact path={['/']} children={<Form onSubmit={onFormSubmit} />} />
<Route path={['/:chainId/:txHash/:messageIdParam', '/:chainId/:txHash']} children={<StatusContainer />} />
</div>
</StyledMainPage>

@ -3,9 +3,10 @@ import { Button } from './commons/Button'
import { RadioButtonLabel, RadioButtonContainer } from './commons/RadioButton'
import { useWindowWidth } from '@react-hook/window-size'
import { formatTxHashExtended } from '../utils/networks'
import { MessageObject } from '../utils/web3'
export interface MessageSelectorParams {
messages: Array<string>
messages: Array<MessageObject>
onMessageSelected: (index: number) => void
}
@ -31,7 +32,7 @@ export const MessageSelector = ({ messages, onMessageSelected }: MessageSelector
onChange={() => setMessageIndex(i)}
/>
<RadioButtonLabel htmlFor={i.toString()}>
{windowWidth < 700 ? formatTxHashExtended(message) : message}
{windowWidth < 700 ? formatTxHashExtended(message.id) : message.id}
</RadioButtonLabel>
</RadioButtonContainer>
))}

@ -7,6 +7,7 @@ import { MessageSelector } from './MessageSelector'
import { Loading } from './commons/Loading'
import { useStateProvider } from '../state/StateProvider'
import { ExplorerTxLink } from './commons/ExplorerTxLink'
import { ConfirmationsContainer } from './ConfirmationsContainer'
export const StatusContainer = () => {
const { home, foreign } = useStateProvider()
@ -15,15 +16,14 @@ export const StatusContainer = () => {
const validChainId = chainId === home.chainId.toString() || chainId === foreign.chainId.toString()
const validParameters = validChainId && validTxHash(txHash)
const { messagesId, status, description, timestamp, loading } = useTransactionStatus({
const { messages, receipt, status, description, timestamp, loading } = useTransactionStatus({
txHash: validParameters ? txHash : '',
chainId: validParameters ? parseInt(chainId) : 0
})
const selectedMessageId =
messageIdParam === undefined || messagesId[messageIdParam] === undefined ? -1 : messageIdParam
const selectedMessageId = messageIdParam === undefined || messages[messageIdParam] === undefined ? -1 : messageIdParam
if (!validParameters) {
if (!validParameters && home.chainId && foreign.chainId) {
return (
<div>
<p>
@ -43,7 +43,7 @@ export const StatusContainer = () => {
const displayMessageSelector = status === TRANSACTION_STATUS.SUCCESS_MULTIPLE_MESSAGES && selectedMessageId === -1
const multiMessageSelected = status === TRANSACTION_STATUS.SUCCESS_MULTIPLE_MESSAGES && selectedMessageId !== -1
const displayReference = multiMessageSelected ? messagesId[selectedMessageId] : txHash
const displayReference = multiMessageSelected ? messages[selectedMessageId].id : txHash
const formattedMessageId = formatTxHash(displayReference)
const displayedDescription = multiMessageSelected
@ -54,6 +54,9 @@ export const StatusContainer = () => {
const txExplorerLink = getExplorerTxUrl(txHash, isHome)
const displayExplorerLink = status !== TRANSACTION_STATUS.NOT_FOUND
const displayConfirmations = status === TRANSACTION_STATUS.SUCCESS_ONE_MESSAGE || multiMessageSelected
const messageToConfirm =
messages.length > 1 ? messages[selectedMessageId] : messages.length > 0 ? messages[0] : { id: '', data: '' }
return (
<div>
{status && (
@ -70,7 +73,10 @@ export const StatusContainer = () => {
{displayedDescription}
</p>
)}
{displayMessageSelector && <MessageSelector messages={messagesId} onMessageSelected={onMessageSelected} />}
{displayMessageSelector && <MessageSelector messages={messages} onMessageSelected={onMessageSelected} />}
{displayConfirmations && (
<ConfirmationsContainer message={messageToConfirm} receipt={receipt} fromHome={isHome} />
)}
</div>
)
}

@ -0,0 +1,69 @@
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'
import styled from 'styled-components'
import { ConfirmationParam } from '../hooks/useMessageConfirmations'
import { GreyLabel, SuccessLabel } from './commons/Labels'
const Thead = styled.thead`
border-bottom: 2px solid #9e9e9e;
`
const RequiredConfirmations = styled.label`
font-size: 14px;
`
export interface ValidatorsConfirmationsParams {
confirmations: Array<ConfirmationParam>
}
export const ValidatorsConfirmations = ({ confirmations }: ValidatorsConfirmationsParams) => {
const {
home: { requiredSignatures, validatorList }
} = useStateProvider()
const windowWidth = useWindowWidth()
const getValidatorStatusElement = (validatorStatus = '') => {
switch (validatorStatus) {
case VALIDATOR_CONFIRMATION_STATUS.SUCCESS:
return <SuccessLabel>{validatorStatus}</SuccessLabel>
case VALIDATOR_CONFIRMATION_STATUS.WAITING:
case VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED:
return <GreyLabel>{validatorStatus}</GreyLabel>
default:
return <SimpleLoading />
}
}
return (
<div>
<table>
<Thead>
<tr>
<th>Validator</th>
<th className="is-center">Confirmations</th>
</tr>
</Thead>
<tbody>
{validatorList.map((validator, i) => {
const filteredConfirmation = confirmations.filter(c => c.validator === validator)
const confirmation = filteredConfirmation.length > 0 ? filteredConfirmation[0] : null
const displayedStatus = confirmation && confirmation.status ? confirmation.status : ''
return (
<tr key={i}>
<td>{windowWidth < 850 ? formatTxHashExtended(validator) : validator}</td>
<td className="text-center">{getValidatorStatusElement(displayedStatus)}</td>
</tr>
)
})}
</tbody>
</table>
<RequiredConfirmations>
{requiredSignatures} of {validatorList.length} confirmations required
</RequiredConfirmations>
</div>
)
}

@ -0,0 +1,15 @@
import styled from 'styled-components'
export const SuccessLabel = styled.label`
color: var(--success-color);
background-color: var(--success-bg-color);
padding: 0.4rem 0.7rem;
border-radius: 4px;
`
export const GreyLabel = styled.label`
color: var(--not-required-color);
background-color: var(--not-required-bg-color);
padding: 0.4rem 0.7rem;
border-radius: 4px;
`

@ -1,12 +1,18 @@
import React from 'react'
export const Loading = () => (
export interface LoadingParams {
width?: string
height?: string
displayMessage?: boolean
}
export const Loading = ({ width = '50px', height = '50px', displayMessage = true }: LoadingParams) => (
<div className="row is-center">
<svg
xmlns="http://www.w3.org/2000/svg"
style={{ background: 'none', display: 'block', shapeRendering: 'auto' }}
width="50px"
height="50px"
width={width}
height={height}
viewBox="0 0 100 100"
preserveAspectRatio="xMidYMid"
>
@ -148,6 +154,8 @@ export const Loading = () => (
</rect>
</g>
</svg>
<label>Loading...</label>
{displayMessage && <label>Loading...</label>}
</div>
)
export const SimpleLoading = () => <Loading width="30px" height="30px" displayMessage={false} />

@ -10,6 +10,10 @@ export const FOREIGN_NETWORK_NAME: string = process.env.REACT_APP_ALM_FOREIGN_NE
export const HOME_EXPLORER_TX_TEMPLATE: string = process.env.REACT_APP_ALM_HOME_EXPLORER_TX_TEMPLATE || ''
export const FOREIGN_EXPLORER_TX_TEMPLATE: string = process.env.REACT_APP_ALM_FOREIGN_EXPLORER_TX_TEMPLATE || ''
export const HOME_RPC_POLLING_INTERVAL: number = 5000
export const FOREIGN_RPC_POLLING_INTERVAL: number = 15000
export const BLOCK_RANGE: number = 50
export const TRANSACTION_STATUS = {
SUCCESS_MULTIPLE_MESSAGES: 'SUCCESS_MULTIPLE_MESSAGES',
SUCCESS_ONE_MESSAGE: 'SUCCESS_ONE_MESSAGE',
@ -17,3 +21,24 @@ export const TRANSACTION_STATUS = {
FAILED: 'FAILED',
NOT_FOUND: 'NOT_FOUND'
}
export const CONFIRMATIONS_STATUS = {
SUCCESS: 'SUCCESS',
SUCCESS_MESSAGE_FAILED: 'SUCCESS_MESSAGE_FAILED',
EXECUTION_FAILED: 'EXECUTION_FAILED',
EXECUTION_PENDING: 'EXECUTION_PENDING',
EXECUTION_WAITING: 'EXECUTION_WAITING',
FAILED: 'FAILED',
PENDING: 'PENDING',
WAITING: 'WAITING',
UNDEFINED: 'UNDEFINED'
}
export const VALIDATOR_CONFIRMATION_STATUS = {
SUCCESS: 'Success',
FAILED: 'Failed',
PENDING: 'Pending',
WAITING: 'Waiting',
NOT_REQUIRED: 'Not required',
UNDEFINED: 'UNDEFINED'
}

@ -6,3 +6,31 @@ export const TRANSACTION_STATUS_DESCRIPTION: { [key: string]: string } = {
FAILED: 'failed %t',
NOT_FOUND: 'was not found'
}
export const CONFIRMATIONS_STATUS_LABEL: { [key: string]: string } = {
SUCCESS: 'Success',
SUCCESS_MESSAGE_FAILED: 'Success',
EXECUTION_FAILED: 'Execution failed',
EXECUTION_PENDING: 'Execution pending',
EXECUTION_WAITING: 'Execution waiting',
FAILED: 'Failed',
PENDING: 'Pending',
WAITING: 'Waiting'
}
// %homeChain will be replaced by the home network name
// %foreignChain will be replaced by the foreign network name
export const CONFIRMATIONS_STATUS_DESCRIPTION: { [key: string]: string } = {
SUCCESS: '',
SUCCESS_MESSAGE_FAILED:
'Signatures have been collected in the %homeChain and they were successfully sent to the %foreignChain but the contained message execution failed.',
EXECUTION_FAILED:
'Signatures have been collected in the %homeChain and they were sent to the %foreignChain but the transaction with signatures failed',
EXECUTION_PENDING:
'Signatures have been collected in the %homeChain and they were sent to the %foreignChain but the transaction is in the pending state (transactions congestion or low gas price)',
EXECUTION_WAITING: 'Execution waiting',
FAILED:
'Some validators sent improper transactions as so they were failed, collected confirmations are not enough to execute the relay request',
PENDING: 'Some confirmations are in pending state',
WAITING: 'Validators are waiting for the chain finalization'
}

@ -0,0 +1,90 @@
import { useEffect, useState } from 'react'
import { HOME_AMB_ABI, FOREIGN_AMB_ABI, BRIDGE_VALIDATORS_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'
export interface useBridgeContractsParams {
homeWeb3: Web3
foreignWeb3: Web3
}
export const useBridgeContracts = ({ homeWeb3, foreignWeb3 }: useBridgeContractsParams) => {
const [homeBridge, setHomeBridge] = useState<Maybe<Contract>>(null)
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
const result = await getRequiredBlockConfirmations(contract)
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]
)
useEffect(
() => {
if (!foreignWeb3) return
const foreignContract = new foreignWeb3.eth.Contract(FOREIGN_AMB_ABI, FOREIGN_BRIDGE_ADDRESS)
callRequireBlockConfirmations(foreignContract, setForeignBlockConfirmations)
setForeignBridge(foreignContract)
},
[foreignWeb3]
)
useEffect(
() => {
callRequiredSignatures(homeValidatorContract, setHomeRequiredSignatures)
callValidatorList(homeValidatorContract, setHomeValidatorList)
},
[homeValidatorContract]
)
return {
homeBridge,
foreignBridge,
homeBlockConfirmations,
foreignBlockConfirmations,
homeValidatorContract,
homeRequiredSignatures,
homeValidatorList
}
}

@ -0,0 +1,305 @@
import { useStateProvider } from '../state/StateProvider'
import { TransactionReceipt } from 'web3-eth'
import { MessageObject } from '../utils/web3'
import { useEffect, useState } from 'react'
import { EventData } from 'web3-eth-contract'
import { getAffirmationsSigned, getMessagesSigned } from '../utils/contract'
import {
BLOCK_RANGE,
CONFIRMATIONS_STATUS,
FOREIGN_RPC_POLLING_INTERVAL,
HOME_RPC_POLLING_INTERVAL,
VALIDATOR_CONFIRMATION_STATUS
} from '../config/constants'
import { homeBlockNumberProvider, foreignBlockNumberProvider } from '../services/BlockNumberProvider'
import { checkSignaturesWaitingForBLocks } from '../utils/signatureWaitingForBlocks'
import { getCollectedSignaturesEvent } from '../utils/getCollectedSignaturesEvent'
import { checkWaitingBlocksForExecution } from '../utils/executionWaitingForBlocks'
import { getConfirmationsForTx } from '../utils/getConfirmationsForTx'
import { getFinalizationEvent } from '../utils/getFinalizationEvent'
export interface useMessageConfirmationsParams {
message: MessageObject
receipt: Maybe<TransactionReceipt>
fromHome: boolean
}
export interface ConfirmationParam {
validator: string
status: string
}
export interface ExecutionData {
status: string
validator: string
txHash: string
timestamp: number
executionResult: boolean
}
export const useMessageConfirmations = ({ message, receipt, fromHome }: useMessageConfirmationsParams) => {
const { home, foreign } = useStateProvider()
const [confirmations, setConfirmations] = useState<Array<ConfirmationParam>>([])
const [status, setStatus] = useState(CONFIRMATIONS_STATUS.UNDEFINED)
const [waitingBlocks, setWaitingBlocks] = useState(false)
const [waitingBlocksResolved, setWaitingBlocksResolved] = useState(false)
const [signatureCollected, setSignatureCollected] = useState(false)
const [collectedSignaturesEvent, setCollectedSignaturesEvent] = useState<Maybe<EventData>>(null)
const [executionData, setExecutionData] = useState<ExecutionData>({
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
validator: '',
txHash: '',
timestamp: 0,
executionResult: false
})
const [waitingBlocksForExecution, setWaitingBlocksForExecution] = useState(false)
const [waitingBlocksForExecutionResolved, setWaitingBlocksForExecutionResolved] = useState(false)
// Check if the validators are waiting for block confirmations to verify the message
useEffect(
() => {
if (!receipt) return
const subscriptions: Array<number> = []
const unsubscribe = () => {
subscriptions.forEach(s => {
clearTimeout(s)
})
}
const blockProvider = fromHome ? homeBlockNumberProvider : foreignBlockNumberProvider
const interval = fromHome ? HOME_RPC_POLLING_INTERVAL : FOREIGN_RPC_POLLING_INTERVAL
const web3 = fromHome ? home.web3 : foreign.web3
blockProvider.start(web3)
const requiredBlockConfirmations = fromHome ? home.blockConfirmations : foreign.blockConfirmations
const targetBlock = receipt.blockNumber + requiredBlockConfirmations
checkSignaturesWaitingForBLocks(
targetBlock,
setWaitingBlocks,
setWaitingBlocksResolved,
home.validatorList,
setConfirmations,
blockProvider,
interval,
subscriptions
)
return () => {
unsubscribe()
blockProvider.stop()
}
},
[
foreign.blockConfirmations,
foreign.web3,
fromHome,
home.blockConfirmations,
home.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
// the execution tx on the foreign network is waiting for block confirmations
// This is executed if the message is in Home to Foreign direction only
useEffect(
() => {
if (!fromHome || !receipt || !home.web3 || !signatureCollected) return
const subscriptions: Array<number> = []
const unsubscribe = () => {
subscriptions.forEach(s => {
clearTimeout(s)
})
}
homeBlockNumberProvider.start(home.web3)
const fromBlock = receipt.blockNumber
const toBlock = fromBlock + BLOCK_RANGE
const messageHash = home.web3.utils.soliditySha3Raw(message.data)
getCollectedSignaturesEvent(
home.web3,
home.bridgeContract,
fromBlock,
toBlock,
messageHash,
setCollectedSignaturesEvent,
subscriptions
)
return () => {
unsubscribe()
homeBlockNumberProvider.stop()
}
},
[fromHome, home.bridgeContract, home.web3, message.data, receipt, signatureCollected]
)
// Check if the responsible validator is waiting for block confirmations to execute the message on foreign network
// This is executed if the message is in Home to Foreign direction only
useEffect(
() => {
if (!fromHome || !home.web3 || !receipt || !collectedSignaturesEvent) return
const subscriptions: Array<number> = []
const unsubscribe = () => {
subscriptions.forEach(s => {
clearTimeout(s)
})
}
homeBlockNumberProvider.start(home.web3)
const targetBlock = collectedSignaturesEvent.blockNumber + home.blockConfirmations
checkWaitingBlocksForExecution(
homeBlockNumberProvider,
HOME_RPC_POLLING_INTERVAL,
targetBlock,
collectedSignaturesEvent,
setWaitingBlocksForExecution,
setWaitingBlocksForExecutionResolved,
setExecutionData,
subscriptions
)
return () => {
unsubscribe()
homeBlockNumberProvider.stop()
}
},
[collectedSignaturesEvent, fromHome, home.blockConfirmations, home.web3, receipt]
)
// Checks if validators verified the message
// To avoid making extra requests, this is only executed when validators finished waiting for blocks confirmations
useEffect(
() => {
if (!waitingBlocksResolved) return
const subscriptions: Array<number> = []
const unsubscribe = () => {
subscriptions.forEach(s => {
clearTimeout(s)
})
}
const confirmationContractMethod = fromHome ? getMessagesSigned : getAffirmationsSigned
getConfirmationsForTx(
message.data,
home.web3,
home.validatorList,
home.bridgeContract,
confirmationContractMethod,
setConfirmations,
home.requiredSignatures,
setSignatureCollected,
waitingBlocksResolved,
subscriptions
)
return () => {
unsubscribe()
}
},
[
fromHome,
message.data,
home.web3,
home.validatorList,
home.bridgeContract,
home.requiredSignatures,
waitingBlocksResolved
]
)
// Gets finalization event to display the information about the execution of the message
// In a message from Home to Foreign it will be executed after finishing waiting for block confirmations for the execution transaction on Foreign
// In a message from Foreign to Home it will be executed after finishing waiting for block confirmations of the message request
useEffect(
() => {
if ((fromHome && !waitingBlocksForExecutionResolved) || (!fromHome && !waitingBlocksResolved)) return
const subscriptions: Array<number> = []
const unsubscribe = () => {
subscriptions.forEach(s => {
clearTimeout(s)
})
}
const contractEvent = fromHome ? 'RelayedMessage' : 'AffirmationCompleted'
const bridgeContract = fromHome ? foreign.bridgeContract : home.bridgeContract
const providedWeb3 = fromHome ? foreign.web3 : home.web3
const interval = fromHome ? FOREIGN_RPC_POLLING_INTERVAL : HOME_RPC_POLLING_INTERVAL
getFinalizationEvent(
bridgeContract,
contractEvent,
providedWeb3,
setExecutionData,
waitingBlocksResolved,
message.id,
interval,
subscriptions
)
return () => {
unsubscribe()
}
},
[
fromHome,
foreign.bridgeContract,
home.bridgeContract,
message.id,
foreign.web3,
home.web3,
waitingBlocksResolved,
waitingBlocksForExecutionResolved
]
)
// Sets the message status based in the collected information
useEffect(
() => {
if (executionData.txHash) {
const newStatus = executionData.executionResult
? CONFIRMATIONS_STATUS.SUCCESS
: CONFIRMATIONS_STATUS.SUCCESS_MESSAGE_FAILED
setStatus(newStatus)
} else if (signatureCollected) {
if (fromHome) {
if (waitingBlocksForExecution) {
setStatus(CONFIRMATIONS_STATUS.EXECUTION_WAITING)
} else {
setStatus(CONFIRMATIONS_STATUS.UNDEFINED)
}
} else {
setStatus(CONFIRMATIONS_STATUS.UNDEFINED)
}
} else if (waitingBlocks) {
setStatus(CONFIRMATIONS_STATUS.WAITING)
} else {
setStatus(CONFIRMATIONS_STATUS.UNDEFINED)
}
},
[executionData, fromHome, signatureCollected, waitingBlocks, waitingBlocksForExecution]
)
return {
confirmations,
status,
signatureCollected,
executionData
}
}

@ -1,13 +1,13 @@
import { useEffect, useState } from 'react'
import { TransactionReceipt } from 'web3-eth'
import { TRANSACTION_STATUS } from '../config/constants'
import { HOME_RPC_POLLING_INTERVAL, TRANSACTION_STATUS } from '../config/constants'
import { getTransactionStatusDescription } from '../utils/networks'
import { useStateProvider } from '../state/StateProvider'
import { getHomeMessagesFromReceipt, getForeignMessagesFromReceipt } from '../utils/web3'
import { getHomeMessagesFromReceipt, getForeignMessagesFromReceipt, MessageObject } from '../utils/web3'
export const useTransactionStatus = ({ txHash, chainId }: { txHash: string; chainId: number }) => {
const { home, foreign } = useStateProvider()
const [messagesId, setMessagesId] = useState<Array<string>>([])
const [messages, setMessages] = useState<Array<MessageObject>>([])
const [status, setStatus] = useState('')
const [description, setDescription] = useState('')
const [receipt, setReceipt] = useState<Maybe<TransactionReceipt>>(null)
@ -36,8 +36,8 @@ export const useTransactionStatus = ({ txHash, chainId }: { txHash: string; chai
if (!txReceipt) {
setStatus(TRANSACTION_STATUS.NOT_FOUND)
setDescription(getTransactionStatusDescription(TRANSACTION_STATUS.NOT_FOUND))
setMessagesId([txHash])
const timeoutId = setTimeout(() => getReceipt(), 5000)
setMessages([{ id: txHash, data: '' }])
const timeoutId = setTimeout(() => getReceipt(), HOME_RPC_POLLING_INTERVAL)
subscriptions.push(timeoutId)
} else {
const blockNumber = txReceipt.blockNumber
@ -46,23 +46,23 @@ export const useTransactionStatus = ({ txHash, chainId }: { txHash: string; chai
setTimestamp(blockTimestamp)
if (txReceipt.status) {
let bridgeMessagesId
let bridgeMessages: Array<MessageObject>
if (isHome) {
bridgeMessagesId = getHomeMessagesFromReceipt(txReceipt, home.web3, home.bridgeAddress)
bridgeMessages = getHomeMessagesFromReceipt(txReceipt, home.web3, home.bridgeAddress)
} else {
bridgeMessagesId = getForeignMessagesFromReceipt(txReceipt, foreign.web3, foreign.bridgeAddress)
bridgeMessages = getForeignMessagesFromReceipt(txReceipt, foreign.web3, foreign.bridgeAddress)
}
if (bridgeMessagesId.length === 0) {
setMessagesId([txHash])
if (bridgeMessages.length === 0) {
setMessages([{ id: txHash, data: '' }])
setStatus(TRANSACTION_STATUS.SUCCESS_NO_MESSAGES)
setDescription(getTransactionStatusDescription(TRANSACTION_STATUS.SUCCESS_NO_MESSAGES, blockTimestamp))
} else if (bridgeMessagesId.length === 1) {
setMessagesId(bridgeMessagesId)
} else if (bridgeMessages.length === 1) {
setMessages(bridgeMessages)
setStatus(TRANSACTION_STATUS.SUCCESS_ONE_MESSAGE)
setDescription(getTransactionStatusDescription(TRANSACTION_STATUS.SUCCESS_ONE_MESSAGE, blockTimestamp))
} else {
setMessagesId(bridgeMessagesId)
setMessages(bridgeMessages)
setStatus(TRANSACTION_STATUS.SUCCESS_MULTIPLE_MESSAGES)
setDescription(
getTransactionStatusDescription(TRANSACTION_STATUS.SUCCESS_MULTIPLE_MESSAGES, blockTimestamp)
@ -89,7 +89,7 @@ export const useTransactionStatus = ({ txHash, chainId }: { txHash: string; chai
)
return {
messagesId,
messages,
status,
description,
receipt,

@ -0,0 +1,64 @@
import Web3 from 'web3'
import differenceInMilliseconds from 'date-fns/differenceInMilliseconds'
import { HOME_RPC_POLLING_INTERVAL } from '../config/constants'
export class BlockNumberProvider {
private running: number
private web3: Maybe<Web3>
private ref: number | undefined
private value: Maybe<number>
private lastValueTimestamp: Maybe<Date>
private readonly interval: number
constructor(interval = 5000) {
this.running = 0
this.web3 = null
this.ref = undefined
this.value = null
this.lastValueTimestamp = null
this.interval = interval
return this
}
start(web3: Maybe<Web3>) {
if (!this.running) {
clearTimeout(this.ref)
this.web3 = web3
this.running = this.running + 1
this.fetchLastBlock()
} else {
this.running = this.running + 1
}
}
stop() {
this.running = this.running - 1
if (!this.running) {
clearTimeout(this.ref)
this.ref = undefined
this.web3 = null
}
}
get() {
return this.value
}
private async fetchLastBlock() {
if (!this.web3) return
const now = new Date()
const distance = differenceInMilliseconds(now, this.lastValueTimestamp || 0)
if (distance >= this.interval) {
this.value = await this.web3.eth.getBlockNumber()
this.lastValueTimestamp = now
}
this.ref = setTimeout(() => this.fetchLastBlock(), this.interval)
}
}
export const homeBlockNumberProvider = new BlockNumberProvider(HOME_RPC_POLLING_INTERVAL)
export const foreignBlockNumberProvider = new BlockNumberProvider(HOME_RPC_POLLING_INTERVAL)

@ -0,0 +1,17 @@
class ValidatorsCache {
private readonly store: { [key: string]: boolean }
constructor() {
this.store = {}
}
get(key: string) {
return this.store[key]
}
set(key: string, value: boolean) {
this.store[key] = value
}
}
export default new ValidatorsCache()

@ -9,17 +9,27 @@ import {
FOREIGN_NETWORK_NAME
} from '../config/constants'
import Web3 from 'web3'
import { useBridgeContracts } from '../hooks/useBridgeContracts'
import { Contract } from 'web3-eth-contract'
export interface NetworkParams {
export interface BaseNetworkParams {
chainId: number
name: string
web3: Maybe<Web3>
bridgeAddress: string
bridgeContract: Maybe<Contract>
blockConfirmations: number
}
export interface HomeNetworkParams extends BaseNetworkParams {
validatorContract: Maybe<Contract>
requiredSignatures: number
validatorList: Array<string>
}
export interface StateContext {
home: NetworkParams
foreign: NetworkParams
home: HomeNetworkParams
foreign: BaseNetworkParams
loading: boolean
}
@ -28,13 +38,20 @@ const initialState = {
chainId: 0,
name: '',
web3: null,
bridgeAddress: HOME_BRIDGE_ADDRESS
bridgeAddress: HOME_BRIDGE_ADDRESS,
bridgeContract: null,
blockConfirmations: 0,
validatorContract: null,
requiredSignatures: 0,
validatorList: []
},
foreign: {
chainId: 0,
name: '',
web3: null,
bridgeAddress: FOREIGN_BRIDGE_ADDRESS
bridgeAddress: FOREIGN_BRIDGE_ADDRESS,
bridgeContract: null,
blockConfirmations: 0
},
loading: true
}
@ -44,16 +61,35 @@ 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({
homeWeb3: homeNetwork.web3,
foreignWeb3: foreignNetwork.web3
})
const value = {
home: {
bridgeAddress: HOME_BRIDGE_ADDRESS,
name: HOME_NETWORK_NAME,
bridgeContract: homeBridge,
blockConfirmations: homeBlockConfirmations,
validatorContract: homeValidatorContract,
requiredSignatures: homeRequiredSignatures,
validatorList: homeValidatorList,
...homeNetwork
},
foreign: {
bridgeAddress: FOREIGN_BRIDGE_ADDRESS,
name: FOREIGN_NETWORK_NAME,
bridgeContract: foreignBridge,
blockConfirmations: foreignBlockConfirmations,
...foreignNetwork
},
loading: homeNetwork.loading || foreignNetwork.loading

@ -4,6 +4,14 @@ const theme = {
colorPrimary: '#272727',
colorGrey: '#272727',
colorLightGrey: '#272727',
linkColor: '#ffffff'
linkColor: '#ffffff',
success: {
textColor: '#00c9a7',
backgroundColor: '#004d40'
},
notRequired: {
textColor: '#bdbdbd',
backgroundColor: '#424242'
}
}
export default theme

@ -20,6 +20,10 @@ export const GlobalStyle = createGlobalStyle<{ theme: ThemeType }>`
--color-primary: ${props => props.theme.colorPrimary};
--color-grey: ${props => props.theme.colorGrey};
--color-lightGrey: ${props => props.theme.colorLightGrey};
--link-color: ${props => props.theme.linkColor}
--link-color: ${props => props.theme.linkColor};
--success-color: ${props => props.theme.success.textColor};
--success-bg-color: ${props => props.theme.success.backgroundColor};
--not-required-color: ${props => props.theme.notRequired.textColor};
--not-required-bg-color: ${props => props.theme.notRequired.backgroundColor};
}
`

20
alm/src/utils/contract.ts Normal file

@ -0,0 +1,20 @@
import { Contract } from 'web3-eth-contract'
export const getRequiredBlockConfirmations = async (contract: Contract) => {
const blockConfirmations = await contract.methods.requiredBlockConfirmations().call()
return parseInt(blockConfirmations)
}
export const getValidatorAddress = (contract: Contract) => contract.methods.validatorContract().call()
export const getRequiredSignatures = async (contract: Contract) => {
const requiredSignatures = await contract.methods.requiredSignatures().call()
return parseInt(requiredSignatures)
}
export const getValidatorList = (contract: Contract) => contract.methods.validatorList().call()
export const getMessagesSigned = (contract: Contract, hash: string) => contract.methods.messagesSigned(hash).call()
export const getAffirmationsSigned = (contract: Contract, hash: string) =>
contract.methods.affirmationsSigned(hash).call()

@ -0,0 +1,51 @@
import { BlockNumberProvider } from '../services/BlockNumberProvider'
import { VALIDATOR_CONFIRMATION_STATUS } from '../config/constants'
import { EventData } from 'web3-eth-contract'
export const checkWaitingBlocksForExecution = async (
blockProvider: BlockNumberProvider,
interval: number,
targetBlock: number,
collectedSignaturesEvent: EventData,
setWaitingBlocksForExecution: Function,
setWaitingBlocksForExecutionResolved: Function,
setExecutionData: Function,
subscriptions: number[]
) => {
const currentBlock = blockProvider.get()
if (currentBlock && currentBlock >= targetBlock) {
setWaitingBlocksForExecution(false)
setWaitingBlocksForExecutionResolved(true)
blockProvider.stop()
} else {
let nextInterval = interval
if (!currentBlock) {
nextInterval = 500
} else {
setWaitingBlocksForExecution(true)
setExecutionData({
status: VALIDATOR_CONFIRMATION_STATUS.WAITING,
validator: collectedSignaturesEvent.returnValues.authorityResponsibleForRelay,
txHash: '',
timestamp: 0,
executionResult: false
})
}
const timeoutId = setTimeout(
() =>
checkWaitingBlocksForExecution(
blockProvider,
interval,
targetBlock,
collectedSignaturesEvent,
setWaitingBlocksForExecution,
setWaitingBlocksForExecutionResolved,
setExecutionData,
subscriptions
),
nextInterval
)
subscriptions.push(timeoutId)
}
}

@ -0,0 +1,53 @@
import Web3 from 'web3'
import { Contract, EventData } from 'web3-eth-contract'
import { homeBlockNumberProvider } from '../services/BlockNumberProvider'
import { BLOCK_RANGE } from '../config/constants'
export const getCollectedSignaturesEvent = async (
web3: Maybe<Web3>,
contract: Maybe<Contract>,
fromBlock: number,
toBlock: number,
messageHash: string,
setCollectedSignaturesEvent: Function,
subscriptions: number[]
) => {
if (!web3 || !contract) return
const currentBlock = homeBlockNumberProvider.get()
let events: EventData[] = []
let securedToBlock = toBlock
if (currentBlock) {
// prevent errors if the toBlock parameter is bigger than the latest
securedToBlock = toBlock >= currentBlock ? currentBlock : toBlock
events = await contract.getPastEvents('CollectedSignatures', {
fromBlock,
toBlock: securedToBlock
})
}
const filteredEvents = events.filter(e => e.returnValues.messageHash === messageHash)
if (filteredEvents.length) {
const event = filteredEvents[0]
setCollectedSignaturesEvent(event)
homeBlockNumberProvider.stop()
} else {
const newFromBlock = currentBlock ? securedToBlock : fromBlock
const newToBlock = currentBlock ? toBlock + BLOCK_RANGE : toBlock
const timeoutId = setTimeout(
() =>
getCollectedSignaturesEvent(
web3,
contract,
newFromBlock,
newToBlock,
messageHash,
setCollectedSignaturesEvent,
subscriptions
),
500
)
subscriptions.push(timeoutId)
}
}

@ -0,0 +1,82 @@
import Web3 from 'web3'
import { Contract } from 'web3-eth-contract'
import validatorsCache from '../services/ValidatorsCache'
import { HOME_RPC_POLLING_INTERVAL, VALIDATOR_CONFIRMATION_STATUS } from '../config/constants'
export const getConfirmationsForTx = async (
messageData: string,
web3: Maybe<Web3>,
validatorList: string[],
bridgeContract: Maybe<Contract>,
confirmationContractMethod: Function,
setResult: Function,
requiredSignatures: number,
setSignatureCollected: Function,
waitingBlocksResolved: boolean,
subscriptions: number[]
) => {
if (!web3 || !validatorList || !bridgeContract || !waitingBlocksResolved) return
const hashMsg = web3.utils.soliditySha3Raw(messageData)
let validatorConfirmations = await Promise.all(
validatorList.map(async validator => {
const hashSenderMsg = web3.utils.soliditySha3Raw(validator, hashMsg)
const signatureFromCache = validatorsCache.get(hashSenderMsg)
if (signatureFromCache) {
return {
validator,
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS
}
}
const confirmed = await confirmationContractMethod(bridgeContract, hashSenderMsg)
const status = confirmed ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
// If validator confirmed signature, we cache the result to avoid doing future requests for a result that won't change
if (confirmed) {
validatorsCache.set(hashSenderMsg, confirmed)
}
return {
validator,
status
}
})
)
const successConfirmations = validatorConfirmations.filter(c => c.status === VALIDATOR_CONFIRMATION_STATUS.SUCCESS)
// If signatures not collected, it needs to retry in the next blocks
if (successConfirmations.length !== requiredSignatures) {
const timeoutId = setTimeout(
() =>
getConfirmationsForTx(
messageData,
web3,
validatorList,
bridgeContract,
confirmationContractMethod,
setResult,
requiredSignatures,
setSignatureCollected,
waitingBlocksResolved,
subscriptions
),
HOME_RPC_POLLING_INTERVAL
)
subscriptions.push(timeoutId)
} else {
// If signatures collected, it should set other signatures as not required
const notSuccessConfirmations = validatorConfirmations.filter(
c => c.status !== VALIDATOR_CONFIRMATION_STATUS.SUCCESS
)
const notRequiredConfirmations = notSuccessConfirmations.map(c => ({
validator: c.validator,
status: VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED
}))
validatorConfirmations = [...successConfirmations, ...notRequiredConfirmations]
setSignatureCollected(true)
}
setResult(validatorConfirmations)
}

@ -0,0 +1,60 @@
import { Contract, EventData } from 'web3-eth-contract'
import Web3 from 'web3'
import { VALIDATOR_CONFIRMATION_STATUS } from '../config/constants'
import { ExecutionData } from '../hooks/useMessageConfirmations'
export const getFinalizationEvent = async (
contract: Maybe<Contract>,
eventName: string,
web3: Maybe<Web3>,
setResult: React.Dispatch<React.SetStateAction<ExecutionData>>,
waitingBlocksResolved: boolean,
messageId: string,
interval: number,
subscriptions: number[]
) => {
if (!contract || !web3 || !waitingBlocksResolved) return
// Since it filters by the message id, only one event will be fetched
// so there is no need to limit the range of the block to reduce the network traffic
const events: EventData[] = await contract.getPastEvents(eventName, {
fromBlock: 0,
toBlock: 'latest',
filter: {
messageId
}
})
if (events.length > 0) {
const event = events[0]
const [txReceipt, block] = await Promise.all([
web3.eth.getTransactionReceipt(event.transactionHash),
web3.eth.getBlock(event.blockNumber)
])
const blockTimestamp = typeof block.timestamp === 'string' ? parseInt(block.timestamp) : block.timestamp
const validatorAddress = web3.utils.toChecksumAddress(txReceipt.from)
setResult({
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
validator: validatorAddress,
txHash: event.transactionHash,
timestamp: blockTimestamp,
executionResult: event.returnValues.status
})
} else {
const timeoutId = setTimeout(
() =>
getFinalizationEvent(
contract,
eventName,
web3,
setResult,
waitingBlocksResolved,
messageId,
interval,
subscriptions
),
interval
)
subscriptions.push(timeoutId)
}
}

@ -1,5 +1,5 @@
import { formatDistance } from 'date-fns'
import { TRANSACTION_STATUS_DESCRIPTION } from '../config/descriptions'
import { CONFIRMATIONS_STATUS_DESCRIPTION, TRANSACTION_STATUS_DESCRIPTION } from '../config/descriptions'
import { FOREIGN_EXPLORER_TX_TEMPLATE, HOME_EXPLORER_TX_TEMPLATE } from '../config/constants'
export const validTxHash = (txHash: string) => /^0x[a-fA-F0-9]{64}$/.test(txHash)
@ -30,3 +30,12 @@ export const getTransactionStatusDescription = (status: string, timestamp: Maybe
return description
}
export const getConfirmationsStatusDescription = (status: string, home: string, foreign: string) => {
let description = CONFIRMATIONS_STATUS_DESCRIPTION[status]
description = description.replace('%homeChain', home)
description = description.replace('%foreignChain', foreign)
return description
}

@ -0,0 +1,50 @@
import { VALIDATOR_CONFIRMATION_STATUS } from '../config/constants'
import { BlockNumberProvider } from '../services/BlockNumberProvider'
export const checkSignaturesWaitingForBLocks = async (
targetBlock: number,
setWaitingStatus: Function,
setWaitingBlocksResolved: Function,
validatorList: string[],
setConfirmations: Function,
blockProvider: BlockNumberProvider,
interval: number,
subscriptions: number[]
) => {
const currentBlock = blockProvider.get()
if (currentBlock && currentBlock >= targetBlock) {
setWaitingStatus(false)
setWaitingBlocksResolved(true)
blockProvider.stop()
} else {
let nextInterval = interval
if (!currentBlock) {
nextInterval = 500
} else {
const validatorsWaiting = validatorList.map(validator => {
return {
validator,
status: VALIDATOR_CONFIRMATION_STATUS.WAITING
}
})
setWaitingStatus(true)
setConfirmations(validatorsWaiting)
}
const timeoutId = setTimeout(
() =>
checkSignaturesWaitingForBLocks(
targetBlock,
setWaitingStatus,
setWaitingBlocksResolved,
validatorList,
setConfirmations,
blockProvider,
interval,
subscriptions
),
nextInterval
)
subscriptions.push(timeoutId)
}
}

@ -4,6 +4,11 @@ import { AbiItem } from 'web3-utils'
import memoize from 'fast-memoize'
import { HOME_AMB_ABI, FOREIGN_AMB_ABI } from '../../../commons'
export interface MessageObject {
id: string
data: string
}
const rawGetWeb3 = (url: string) => new Web3(new Web3.providers.HttpProvider(url))
const memoized = memoize(rawGetWeb3)
@ -14,11 +19,20 @@ export const filterEventsByAbi = (
web3: Web3,
bridgeAddress: string,
eventAbi: AbiItem
) => {
): MessageObject[] => {
const eventHash = web3.eth.abi.encodeEventSignature(eventAbi)
const events = txReceipt.logs.filter(e => e.address === bridgeAddress && e.topics[0] === eventHash)
return events.map(e => e.topics[1])
return events.map(e => {
let decodedLogs: { [p: string]: string } = {
messageId: '',
encodedData: ''
}
if (eventAbi && eventAbi.inputs && eventAbi.inputs.length) {
decodedLogs = web3.eth.abi.decodeLog(eventAbi.inputs, e.data, [e.topics[1]])
}
return { id: decodedLogs.messageId, data: decodedLogs.encodedData }
})
}
export const getHomeMessagesFromReceipt = (txReceipt: TransactionReceipt, web3: Web3, bridgeAddress: string) => {

394
yarn.lock

@ -1304,21 +1304,6 @@
"@ethersproject/properties" ">=5.0.0-beta.131"
"@ethersproject/strings" ">=5.0.0-beta.130"
"@ethersproject/abi@5.0.0-beta.153":
version "5.0.0-beta.153"
resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.0.0-beta.153.tgz#43a37172b33794e4562999f6e2d555b7599a8eee"
integrity sha512-aXweZ1Z7vMNzJdLpR1CZUAIgnwjrZeUSvN9syCwlBaEBUFJmFY+HHnfuTI5vIhVs/mRkfJVrbEyl51JZQqyjAg==
dependencies:
"@ethersproject/address" ">=5.0.0-beta.128"
"@ethersproject/bignumber" ">=5.0.0-beta.130"
"@ethersproject/bytes" ">=5.0.0-beta.129"
"@ethersproject/constants" ">=5.0.0-beta.128"
"@ethersproject/hash" ">=5.0.0-beta.128"
"@ethersproject/keccak256" ">=5.0.0-beta.127"
"@ethersproject/logger" ">=5.0.0-beta.129"
"@ethersproject/properties" ">=5.0.0-beta.131"
"@ethersproject/strings" ">=5.0.0-beta.130"
"@ethersproject/address@>=5.0.0-beta.128":
version "5.0.0-beta.134"
resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.0.0-beta.134.tgz#9c1790c87b763dc547ac12e2dbc9fa78d0799a71"
@ -4868,7 +4853,7 @@ balanced-match@^1.0.0:
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
base-x@^3.0.2, base-x@^3.0.8:
base-x@^3.0.2:
version "3.0.8"
resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.8.tgz#1e1106c2537f0162e8b52474a557ebb09000018d"
integrity sha512-Rl/1AWP4J/zRrk54hhlxH4drNxPJXYUaKffODVI53/dAsV4t9fBxyxYKAVPU1XBHxYwOWP9h9H0hM2MVw4YfJA==
@ -5804,17 +5789,6 @@ ci-info@^2.0.0:
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46"
integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==
cids@^0.7.1:
version "0.7.5"
resolved "https://registry.yarnpkg.com/cids/-/cids-0.7.5.tgz#60a08138a99bfb69b6be4ceb63bfef7a396b28b2"
integrity sha512-zT7mPeghoWAu+ppn8+BS1tQ5qGmbMfB4AregnQjA/qHY3GC1m1ptI9GkWNlgeu38r7CuRdXB47uY2XgAYt6QVA==
dependencies:
buffer "^5.5.0"
class-is "^1.1.0"
multibase "~0.6.0"
multicodec "^1.0.0"
multihashes "~0.4.15"
cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
version "1.0.4"
resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de"
@ -5823,11 +5797,6 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
inherits "^2.0.1"
safe-buffer "^5.0.1"
class-is@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/class-is/-/class-is-1.1.0.tgz#9d3c0fba0440d211d843cec3dedfa48055005825"
integrity sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw==
class-utils@^0.3.5:
version "0.3.6"
resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
@ -6293,15 +6262,6 @@ content-disposition@0.5.3:
dependencies:
safe-buffer "5.1.2"
content-hash@^2.5.2:
version "2.5.2"
resolved "https://registry.yarnpkg.com/content-hash/-/content-hash-2.5.2.tgz#bbc2655e7c21f14fd3bfc7b7d4bfe6e454c9e211"
integrity sha512-FvIQKy0S1JaWV10sMsA7TRx8bpU+pqPkhbsfvOJAdjRXvYxEckAwQWGwtRjiaJfh+E0DvcWUGqcdjwMGFjsSdw==
dependencies:
cids "^0.7.1"
multicodec "^0.5.5"
multihashes "^0.4.15"
content-type@~1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
@ -13821,22 +13781,6 @@ ms@^2.0.0:
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
multibase@^0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/multibase/-/multibase-0.7.0.tgz#1adfc1c50abe05eefeb5091ac0c2728d6b84581b"
integrity sha512-TW8q03O0f6PNFTQDvh3xxH03c8CjGaaYrjkl9UQPG6rz53TQzzxJVCIWVjzcbN/Q5Y53Zd0IBQBMVktVgNx4Fg==
dependencies:
base-x "^3.0.8"
buffer "^5.5.0"
multibase@~0.6.0:
version "0.6.1"
resolved "https://registry.yarnpkg.com/multibase/-/multibase-0.6.1.tgz#b76df6298536cc17b9f6a6db53ec88f85f8cc12b"
integrity sha512-pFfAwyTjbbQgNc3G7D48JkJxWtoJoBMaR4xQUOuB8RnCgRqaYmWNFeJTTvrJ2w51bjLq2zTby6Rqj9TQ9elSUw==
dependencies:
base-x "^3.0.8"
buffer "^5.5.0"
multicast-dns-service-types@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901"
@ -13850,30 +13794,6 @@ multicast-dns@^6.0.1:
dns-packet "^1.3.1"
thunky "^1.0.2"
multicodec@^0.5.5:
version "0.5.7"
resolved "https://registry.yarnpkg.com/multicodec/-/multicodec-0.5.7.tgz#1fb3f9dd866a10a55d226e194abba2dcc1ee9ffd"
integrity sha512-PscoRxm3f+88fAtELwUnZxGDkduE2HD9Q6GHUOywQLjOGT/HAdhjLDYNZ1e7VR0s0TP0EwZ16LNUTFpoBGivOA==
dependencies:
varint "^5.0.0"
multicodec@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/multicodec/-/multicodec-1.0.1.tgz#4e2812d726b9f7c7d615d3ebc5787d36a08680f9"
integrity sha512-yrrU/K8zHyAH2B0slNVeq3AiwluflHpgQ3TAzwNJcuO2AoPyXgBT2EDkdbP1D8B/yFOY+S2hDYmFlI1vhVFkQw==
dependencies:
buffer "^5.5.0"
varint "^5.0.0"
multihashes@^0.4.15, multihashes@~0.4.15:
version "0.4.19"
resolved "https://registry.yarnpkg.com/multihashes/-/multihashes-0.4.19.tgz#d7493cf028e48747122f350908ea13d12d204813"
integrity sha512-ej74GAfA20imjj00RO5h34aY3pGUFyzn9FJZFWwdeUHlHTkKmv90FrNpvYT4jYf1XXCy5O/5EjVnxTaESgOM6A==
dependencies:
buffer "^5.5.0"
multibase "^0.7.0"
varint "^5.0.0"
multimatch@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-3.0.0.tgz#0e2534cc6bc238d9ab67e1b9cd5fcd85a6dbf70b"
@ -20113,11 +20033,6 @@ value-or-function@^3.0.0:
resolved "https://registry.yarnpkg.com/value-or-function/-/value-or-function-3.0.0.tgz#1c243a50b595c1be54a754bfece8563b9ff8d813"
integrity sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM=
varint@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/varint/-/varint-5.0.0.tgz#d826b89f7490732fabc0c0ed693ed475dcb29ebf"
integrity sha1-2Ca4n3SQcy+rwMDtaT7Uddyynr8=
vary@^1, vary@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
@ -20324,10 +20239,10 @@ web3-bzz@1.2.4:
swarm-js "0.1.39"
underscore "1.9.1"
web3-bzz@1.2.8:
version "1.2.8"
resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.2.8.tgz#7ff2c2de362f82ae3825e48c70ec63b3aca2b8ef"
integrity sha512-jbi24/s2tT7FYuN+ktRvTa5em0GxhqcIYQ8FnD3Zb/ZoEPi+/7rH0Hh+WDol0pSZL+wdz/iM+Z2C9NE42z6EmQ==
web3-bzz@1.2.7:
version "1.2.7"
resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.2.7.tgz#aa0f3d162f0777a5f35367dc5b70012dd1e129d0"
integrity sha512-iTIWBR+Z+Bn09WprtKm46LmyNOasg2lUn++AjXkBTB8UNxlUybxtza84yl2ETTZUs0zuFzdSSAEgbjhygG+9oA==
dependencies:
"@types/node" "^10.12.18"
got "9.6.0"
@ -20361,14 +20276,14 @@ web3-core-helpers@1.2.4:
web3-eth-iban "1.2.4"
web3-utils "1.2.4"
web3-core-helpers@1.2.8:
version "1.2.8"
resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.2.8.tgz#86776d8f658b63bb630c84a314686661e599aa68"
integrity sha512-Wrl7ZPKn3Xyg0Hl5+shDnJcLP+EtTfThmQ1eCJLcg/BZqvLUR1SkOslNlhEojcYeBwhhymAKs8dfQbtYi+HMnw==
web3-core-helpers@1.2.7:
version "1.2.7"
resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.2.7.tgz#522f859775ea0d15e7e40359c46d4efc5da92aee"
integrity sha512-bdU++9QATGeCetVrMp8pV97aQtVkN5oLBf/TWu/qumC6jK/YqrvLlBJLdwbz0QveU8zOSap6GCvJbqKvmmbV2A==
dependencies:
underscore "1.9.1"
web3-eth-iban "1.2.8"
web3-utils "1.2.8"
web3-eth-iban "1.2.7"
web3-utils "1.2.7"
web3-core-method@1.0.0-beta.30:
version "1.0.0-beta.30"
@ -20403,16 +20318,16 @@ web3-core-method@1.2.4:
web3-core-subscriptions "1.2.4"
web3-utils "1.2.4"
web3-core-method@1.2.8:
version "1.2.8"
resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.2.8.tgz#f28a79935432aebfa019e4a50f9b6ae6c9ef4297"
integrity sha512-69qbvOgx0Frw46dXvEKzYgtaPXpUaQAlQmczgb0ZUBHsEU2K7jTtFgBy6kVBgAwsXDvoZ99AX4SjpY2dTMwPkw==
web3-core-method@1.2.7:
version "1.2.7"
resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.2.7.tgz#73fd80d2bf0765ff6efc454db49ac83d1769a45e"
integrity sha512-e1TI0QUnByDMbQ8QHwnjxfjKw0LIgVRY4TYrlPijET9ebqUJU1HCayn/BHIMpV6LKyR1fQj9EldWyT64wZQXkg==
dependencies:
underscore "1.9.1"
web3-core-helpers "1.2.8"
web3-core-promievent "1.2.8"
web3-core-subscriptions "1.2.8"
web3-utils "1.2.8"
web3-core-helpers "1.2.7"
web3-core-promievent "1.2.7"
web3-core-subscriptions "1.2.7"
web3-utils "1.2.7"
web3-core-promievent@1.0.0-beta.30:
version "1.0.0-beta.30"
@ -20438,10 +20353,10 @@ web3-core-promievent@1.2.4:
any-promise "1.3.0"
eventemitter3 "3.1.2"
web3-core-promievent@1.2.8:
version "1.2.8"
resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.2.8.tgz#a93ca2a19cae8b60883412619e04e69e11804eb5"
integrity sha512-3EdRieaHpBVVhfGjoREQfdoCM3xC0WwWjXXzT6oTldotfYC38kwk/GW8c8txYiLP/KxhslAN1cJSlXNOJjKSog==
web3-core-promievent@1.2.7:
version "1.2.7"
resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.2.7.tgz#fc7fa489f4cf76a040800f3dfd4b45c51bd3a39f"
integrity sha512-jNmsM/czCeMGQqKKwM9/HZVTJVIF96hdMVNN/V9TGvp+EEE7vDhB4pUocDnc/QF9Z/5QFBCVmvNWttlRgZmU0A==
dependencies:
eventemitter3 "3.1.2"
@ -20478,16 +20393,16 @@ web3-core-requestmanager@1.2.4:
web3-providers-ipc "1.2.4"
web3-providers-ws "1.2.4"
web3-core-requestmanager@1.2.8:
version "1.2.8"
resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.2.8.tgz#da7259e72a433858d04c59b999c5116bfb797c09"
integrity sha512-bwc2ABG6yzgTy28fv4t59g+tf6+UmTRMoF8HqTeiNDffoMKP2akyKFZeu1oD2gE7j/7GA75TAUjwJ7pH9ek1MA==
web3-core-requestmanager@1.2.7:
version "1.2.7"
resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.2.7.tgz#9da0efce898ead7004d4ac50f748f5131cfe4d79"
integrity sha512-HJb/txjHixu1dxIebiZQKBoJCaNu4gsh7mq/uj6Z/w6tIHbybL90s/7ADyMED353yyJ2tDWtYJqeMVAR+KtdaA==
dependencies:
underscore "1.9.1"
web3-core-helpers "1.2.8"
web3-providers-http "1.2.8"
web3-providers-ipc "1.2.8"
web3-providers-ws "1.2.8"
web3-core-helpers "1.2.7"
web3-providers-http "1.2.7"
web3-providers-ipc "1.2.7"
web3-providers-ws "1.2.7"
web3-core-subscriptions@1.0.0-beta.30:
version "1.0.0-beta.30"
@ -20516,14 +20431,14 @@ web3-core-subscriptions@1.2.4:
underscore "1.9.1"
web3-core-helpers "1.2.4"
web3-core-subscriptions@1.2.8:
version "1.2.8"
resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.2.8.tgz#50945498fb0bd655f842cbcc13873d96956aa93e"
integrity sha512-wmsRJ4ipwoF1mlOR+Oo8JdKigpkoVNQtqiRUuyQrTVhJx7GBuSaAIenpBYlkucC+RgByoGybR7Q3tTNJ6z/2tQ==
web3-core-subscriptions@1.2.7:
version "1.2.7"
resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.2.7.tgz#30c64aede03182832883b17c77e21cbb0933c86e"
integrity sha512-W/CzQYOUawdMDvkgA/fmLsnG5aMpbjrs78LZMbc0MFXLpH3ofqAgO2by4QZrrTShUUTeWS0ZuEkFFL/iFrSObw==
dependencies:
eventemitter3 "3.1.2"
underscore "1.9.1"
web3-core-helpers "1.2.8"
web3-core-helpers "1.2.7"
web3-core@1.0.0-beta.30:
version "1.0.0-beta.30"
@ -20558,18 +20473,18 @@ web3-core@1.2.4:
web3-core-requestmanager "1.2.4"
web3-utils "1.2.4"
web3-core@1.2.8:
version "1.2.8"
resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.2.8.tgz#2a488bb11519b71e7738265329bddc00fc200dd3"
integrity sha512-hvlYWyE1UcLoGa6qF1GoxGgi1quFsZOdwIUIVsAp+sp0plXp/Nqva2lAjJ+FFyWtVKbC7Zq+qwTJ4iP1aN0vTg==
web3-core@1.2.7:
version "1.2.7"
resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.2.7.tgz#9248b04331e458c76263d758c51b0cc612953900"
integrity sha512-QA0MTae0gXcr3KHe3cQ4x56+Wh43ZKWfMwg1gfCc3NNxPRM1jJ8qudzyptCAUcxUGXWpDG8syLIn1APDz5J8BQ==
dependencies:
"@types/bn.js" "^4.11.4"
"@types/node" "^12.6.1"
bignumber.js "^9.0.0"
web3-core-helpers "1.2.8"
web3-core-method "1.2.8"
web3-core-requestmanager "1.2.8"
web3-utils "1.2.8"
web3-core-helpers "1.2.7"
web3-core-method "1.2.7"
web3-core-requestmanager "1.2.7"
web3-utils "1.2.7"
web3-eth-abi@1.0.0-beta.30:
version "1.0.0-beta.30"
@ -20600,14 +20515,14 @@ web3-eth-abi@1.2.4:
underscore "1.9.1"
web3-utils "1.2.4"
web3-eth-abi@1.2.8:
version "1.2.8"
resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.2.8.tgz#7537138f3e5cd1ccf98233fa07f388aa8dc1fff1"
integrity sha512-OKp/maLdKHPpQxZhEd0HgnCJFQajsGe42WOG6SVftlgzyR8Jjv4KNm46TKvb3hv5OJTKZWU7nZIxkEG+fyI58w==
web3-eth-abi@1.2.7:
version "1.2.7"
resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.2.7.tgz#6f3471b578649fddd844a14d397a3dd430fc44a5"
integrity sha512-4FnlT1q+D0XBkxSMXlIb/eG337uQeMaUdtVQ4PZ3XzxqpcoDuMgXm4o+3NRxnWmr4AMm6QKjM+hcC7c0mBKcyg==
dependencies:
"@ethersproject/abi" "5.0.0-beta.153"
ethers "4.0.0-beta.3"
underscore "1.9.1"
web3-utils "1.2.8"
web3-utils "1.2.7"
web3-eth-abi@^1.0.0-beta.24:
version "1.2.6"
@ -20668,10 +20583,10 @@ web3-eth-accounts@1.2.4:
web3-core-method "1.2.4"
web3-utils "1.2.4"
web3-eth-accounts@1.2.8:
version "1.2.8"
resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.2.8.tgz#e63afc6d4902f2beb0cf60e6b755c86fa5b5ccd7"
integrity sha512-QODqSD4SZN/1oWfvlvsuum6Ud9+2FUTW4VTPJh245YTewCpa0M5+Fzug3UTeUZNv88STwC//dV72zReITNh4ZQ==
web3-eth-accounts@1.2.7:
version "1.2.7"
resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.2.7.tgz#087f55d04a01b815b93151aac2fc1677436b9c59"
integrity sha512-AE7QWi/iIQIjXwlAPtlMabm/OPFF0a1PhxT1EiTckpYNP8fYs6jW7lYxEtJPPJIKqfMjoi1xkEqTVR1YZQ88lg==
dependencies:
"@web3-js/scrypt-shim" "^0.1.0"
crypto-browserify "3.12.0"
@ -20680,10 +20595,10 @@ web3-eth-accounts@1.2.8:
ethereumjs-tx "^2.1.1"
underscore "1.9.1"
uuid "3.3.2"
web3-core "1.2.8"
web3-core-helpers "1.2.8"
web3-core-method "1.2.8"
web3-utils "1.2.8"
web3-core "1.2.7"
web3-core-helpers "1.2.7"
web3-core-method "1.2.7"
web3-utils "1.2.7"
web3-eth-contract@1.0.0-beta.30:
version "1.0.0-beta.30"
@ -20728,20 +20643,20 @@ web3-eth-contract@1.2.4:
web3-eth-abi "1.2.4"
web3-utils "1.2.4"
web3-eth-contract@1.2.8:
version "1.2.8"
resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.2.8.tgz#ff75920ac698a70781edcebbf75287a6d0f14499"
integrity sha512-EWRLVhZksbzGAyHd7RaOsakjCJBA2BREWiJmBDlrxDBqw8HltXFzKdkRug/mwVNa5ZYMabKSRF/MMh0Sx06CFw==
web3-eth-contract@1.2.7:
version "1.2.7"
resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.2.7.tgz#13d7f6003d6221f9a5fd61c2d3b5d039477c9674"
integrity sha512-uW23Y0iL7XroRNbf9fWZ1N6OYhEYTJX8gTuYASuRnpYrISN5QGiQML6pq/NCzqypR1bl5E0fuINZQSK/xefIVw==
dependencies:
"@types/bn.js" "^4.11.4"
underscore "1.9.1"
web3-core "1.2.8"
web3-core-helpers "1.2.8"
web3-core-method "1.2.8"
web3-core-promievent "1.2.8"
web3-core-subscriptions "1.2.8"
web3-eth-abi "1.2.8"
web3-utils "1.2.8"
web3-core "1.2.7"
web3-core-helpers "1.2.7"
web3-core-method "1.2.7"
web3-core-promievent "1.2.7"
web3-core-subscriptions "1.2.7"
web3-eth-abi "1.2.7"
web3-utils "1.2.7"
web3-eth-ens@1.2.4:
version "1.2.4"
@ -20757,20 +20672,19 @@ web3-eth-ens@1.2.4:
web3-eth-contract "1.2.4"
web3-utils "1.2.4"
web3-eth-ens@1.2.8:
version "1.2.8"
resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.2.8.tgz#247daddfdbf7533adb0f45cd2f75c75e52f7e678"
integrity sha512-zsFXY26BMGkihPkEO5qj9AEqyxPH4mclbzYs1dyrw7sHFmrUvhZc+jLGT9WyQGoujq37RN2l/tlOpCaFVVR8ng==
web3-eth-ens@1.2.7:
version "1.2.7"
resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.2.7.tgz#0bfa7d4b6c7753abbb31a2eb01a364b538f4c860"
integrity sha512-SPRnvUNWQ0CnnTDBteGIJkvFWEizJcAHlVsrFLICwcwFZu+appjX1UOaoGu2h3GXWtc/XZlu7B451Gi+Os2cTg==
dependencies:
content-hash "^2.5.2"
eth-ens-namehash "2.0.8"
underscore "1.9.1"
web3-core "1.2.8"
web3-core-helpers "1.2.8"
web3-core-promievent "1.2.8"
web3-eth-abi "1.2.8"
web3-eth-contract "1.2.8"
web3-utils "1.2.8"
web3-core "1.2.7"
web3-core-helpers "1.2.7"
web3-core-promievent "1.2.7"
web3-eth-abi "1.2.7"
web3-eth-contract "1.2.7"
web3-utils "1.2.7"
web3-eth-iban@1.0.0-beta.30:
version "1.0.0-beta.30"
@ -20796,13 +20710,13 @@ web3-eth-iban@1.2.4:
bn.js "4.11.8"
web3-utils "1.2.4"
web3-eth-iban@1.2.8:
version "1.2.8"
resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.2.8.tgz#414e80a7fb2d1ea16490bc2c8fc29a996aec5612"
integrity sha512-xgPUOuDOQJYloUS334/wot6jvp6K8JBz8UvQ1tAxU9LO2v2DW+IDTJ5gQ6TdutTmzdDi97KdwhwnQwhQh5Z1PA==
web3-eth-iban@1.2.7:
version "1.2.7"
resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.2.7.tgz#832809c28586be3c667a713b77a2bcba11b7970f"
integrity sha512-2NrClz1PoQ3nSJBd+91ylCOVga9qbTxjRofq/oSCoHVAEvz3WZyttx9k5DC+0rWqwJF1h69ufFvdHAAlmN/4lg==
dependencies:
bn.js "4.11.8"
web3-utils "1.2.8"
web3-utils "1.2.7"
web3-eth-personal@1.0.0-beta.30:
version "1.0.0-beta.30"
@ -20838,17 +20752,17 @@ web3-eth-personal@1.2.4:
web3-net "1.2.4"
web3-utils "1.2.4"
web3-eth-personal@1.2.8:
version "1.2.8"
resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.2.8.tgz#8ebb27210b4c9c9555a30c5bb2ce8db12f84cd24"
integrity sha512-sWhxF1cpF9pB1wMISrOSy/i8IB1NWtvoXT9dfkWtvByGf3JfC2DlnllLaA1f9ohyvxnR+QTgPKgOQDknmqDstw==
web3-eth-personal@1.2.7:
version "1.2.7"
resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.2.7.tgz#322cc2b14c37737b21772a53e4185686a04bf9be"
integrity sha512-2OAa1Spz0uB29dwCM8+1y0So7E47A4gKznjBEwXIYEcUIsvwT5X7ofFhC2XxyRpqlIWZSQAxRSSJFyupRRXzyw==
dependencies:
"@types/node" "^12.6.1"
web3-core "1.2.8"
web3-core-helpers "1.2.8"
web3-core-method "1.2.8"
web3-net "1.2.8"
web3-utils "1.2.8"
web3-core "1.2.7"
web3-core-helpers "1.2.7"
web3-core-method "1.2.7"
web3-net "1.2.7"
web3-utils "1.2.7"
web3-eth@1.0.0-beta.30:
version "1.0.0-beta.30"
@ -20905,24 +20819,24 @@ web3-eth@1.2.4:
web3-net "1.2.4"
web3-utils "1.2.4"
web3-eth@1.2.8:
version "1.2.8"
resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.2.8.tgz#cf6a16fae4d7c12b90cfb6ef570cb1a2acc34c1b"
integrity sha512-CEnVIIR1zZQ9vQh/kPFAUbvbbHYkC84y15jdhRUDDGR6bs4FxO2NNWR2YDtNe038lrz747tZahsC9kEiGkJFZQ==
web3-eth@1.2.7:
version "1.2.7"
resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.2.7.tgz#9427daefd3641200679c2946f77fc184dbfb5b4c"
integrity sha512-ljLd0oB4IjWkzFGVan4HkYhJXhSXgn9iaSaxdJixKGntZPgWMJfxeA+uLwTrlxrWzhvy4f+39WnT7wCh5e9TGg==
dependencies:
underscore "1.9.1"
web3-core "1.2.8"
web3-core-helpers "1.2.8"
web3-core-method "1.2.8"
web3-core-subscriptions "1.2.8"
web3-eth-abi "1.2.8"
web3-eth-accounts "1.2.8"
web3-eth-contract "1.2.8"
web3-eth-ens "1.2.8"
web3-eth-iban "1.2.8"
web3-eth-personal "1.2.8"
web3-net "1.2.8"
web3-utils "1.2.8"
web3-core "1.2.7"
web3-core-helpers "1.2.7"
web3-core-method "1.2.7"
web3-core-subscriptions "1.2.7"
web3-eth-abi "1.2.7"
web3-eth-accounts "1.2.7"
web3-eth-contract "1.2.7"
web3-eth-ens "1.2.7"
web3-eth-iban "1.2.7"
web3-eth-personal "1.2.7"
web3-net "1.2.7"
web3-utils "1.2.7"
web3-net@1.0.0-beta.30:
version "1.0.0-beta.30"
@ -20951,14 +20865,14 @@ web3-net@1.2.4:
web3-core-method "1.2.4"
web3-utils "1.2.4"
web3-net@1.2.8:
version "1.2.8"
resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.2.8.tgz#582fc2d4ba32c2e5c7761624e4be7c5434142d66"
integrity sha512-Nsq6qgncvvThOjC+sQ+NfDH8L7jclQCFzLFYa9wsd5J6HJ6f5gJl/mv6rsZQX9iDEYDPKkDfyqHktynOBgKWMQ==
web3-net@1.2.7:
version "1.2.7"
resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.2.7.tgz#c355621a8769c9c1a967c801e7db90c92a0e3808"
integrity sha512-j9qeZrS1FNyCeA0BfdLojkxOZQz3FKa1DJI+Dw9fEVhZS68vLOFANu2RB96gR9BoPHo5+k5D3NsKOoxt1gw3Gg==
dependencies:
web3-core "1.2.8"
web3-core-method "1.2.8"
web3-utils "1.2.8"
web3-core "1.2.7"
web3-core-method "1.2.7"
web3-utils "1.2.7"
web3-provider-engine@14.0.6:
version "14.0.6"
@ -21037,12 +20951,12 @@ web3-providers-http@1.2.4:
web3-core-helpers "1.2.4"
xhr2-cookies "1.1.0"
web3-providers-http@1.2.8:
version "1.2.8"
resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.2.8.tgz#cd7fc4d49df6980b5dd0fb1b5a808bc4b6a0069d"
integrity sha512-Esj4SpgabmBDOR4QD3qYapzwFYWHigcdgdjvt/VWT5/7TD10o52hr+Nsvp3/XV5AFrcCMdY+lzKFLVH24u0sww==
web3-providers-http@1.2.7:
version "1.2.7"
resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.2.7.tgz#31eb15390c103169b3d7d31bdb1ccae9e3f1629d"
integrity sha512-vazGx5onuH/zogrwkUaLFJwFcJ6CckP65VFSHoiV+GTQdkOqgoDIha7StKkslvDz4XJ2FuY/zOZHbtuOYeltXQ==
dependencies:
web3-core-helpers "1.2.8"
web3-core-helpers "1.2.7"
xhr2-cookies "1.1.0"
web3-providers-ipc@1.0.0-beta.30:
@ -21072,14 +20986,14 @@ web3-providers-ipc@1.2.4:
underscore "1.9.1"
web3-core-helpers "1.2.4"
web3-providers-ipc@1.2.8:
version "1.2.8"
resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.2.8.tgz#47be918ddd077999aa14703169b76c807f45d894"
integrity sha512-ts3/UXCTRADPASdJ27vBVmcfM+lfG9QVBxGedY6+oNIo5EPxBUtsz94R32sfvFd6ofPsz6gOhK/M/ZKiJoi1sg==
web3-providers-ipc@1.2.7:
version "1.2.7"
resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.2.7.tgz#4e6716e8723d431df3d6bfa1acd2f7c04e7071ad"
integrity sha512-/zc0y724H2zbkV4UbGGMhsEiLfafjagIzfrsWZnyTZUlSB0OGRmmFm2EkLJAgtXrLiodaHHyXKM0vB8S24bxdA==
dependencies:
oboe "2.1.4"
underscore "1.9.1"
web3-core-helpers "1.2.8"
web3-core-helpers "1.2.7"
web3-providers-ws@1.0.0-beta.30:
version "1.0.0-beta.30"
@ -21108,15 +21022,15 @@ web3-providers-ws@1.2.4:
underscore "1.9.1"
web3-core-helpers "1.2.4"
web3-providers-ws@1.2.8:
version "1.2.8"
resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.2.8.tgz#9e6454edc82d753d398c8d1e044632c234434a46"
integrity sha512-Gcm0n82wd/XVeGFGTx+v56UqyrV9EyB2r1QFaBx4mS+VHbW2MCOdiRbNDfoZQslflnCWl8oHsivJ8Tya9kqlTQ==
web3-providers-ws@1.2.7:
version "1.2.7"
resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.2.7.tgz#95b1cc5dc25e9b9d6630d6754f9354313b62f532"
integrity sha512-b5XzqDpRkNVe6MFs5K6iqOEyjQikHtg3KuU2/ClCDV37hm0WN4xCRVMC0LwegulbDXZej3zT9+1CYzGaGFREzA==
dependencies:
"@web3-js/websocket" "^1.0.29"
eventemitter3 "^4.0.0"
underscore "1.9.1"
web3-core-helpers "1.2.8"
web3-core-helpers "1.2.7"
web3-shh@1.0.0-beta.30:
version "1.0.0-beta.30"
@ -21148,15 +21062,15 @@ web3-shh@1.2.4:
web3-core-subscriptions "1.2.4"
web3-net "1.2.4"
web3-shh@1.2.8:
version "1.2.8"
resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.2.8.tgz#5162d9d13bc6838d390df1cd39e5f87235c1c2ae"
integrity sha512-e29qKSfuZWDmxCG/uB48Nth6DCFFr2h2U+uI/fHEuhEjAEkBHopPNLc3ixrCTc6pqMocfJRPHJq/yET9PYN3oQ==
web3-shh@1.2.7:
version "1.2.7"
resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.2.7.tgz#5382c7bc2f39539eb2841c4576d23ade25720461"
integrity sha512-f6PAgcpG0ZAo98KqCmeHoDEx5qzm3d5plet18DkT4U6WIeYowKdec8vZaLPRR7c2XreXFJ2gQf45CB7oqR7U/w==
dependencies:
web3-core "1.2.8"
web3-core-method "1.2.8"
web3-core-subscriptions "1.2.8"
web3-net "1.2.8"
web3-core "1.2.7"
web3-core-method "1.2.7"
web3-core-subscriptions "1.2.7"
web3-net "1.2.7"
web3-utils@1.0.0-beta.30:
version "1.0.0-beta.30"
@ -21212,10 +21126,10 @@ web3-utils@1.2.6:
underscore "1.9.1"
utf8 "3.0.0"
web3-utils@1.2.8:
version "1.2.8"
resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.2.8.tgz#5321d91715cd4c0869005705a33c4c042a532b18"
integrity sha512-9SIVGFLajwlmo5joC4DGxuy2OeDkRCXVWT8JWcDQ+BayNVHyAWGvn0oGkQ0ys14Un0KK6bjjKoD0xYs4k+FaVw==
web3-utils@1.2.7:
version "1.2.7"
resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.2.7.tgz#b68e232917e4376f81cf38ef79878e5903d18e93"
integrity sha512-FBh/CPJND+eiPeUF9KVbTyTZtXNWxPWtByBaWS6e2x4ACazPX711EeNaZaChIOGSLGe6se2n7kg6wnawe/MjuQ==
dependencies:
bn.js "4.11.8"
eth-lib "0.2.7"
@ -21266,18 +21180,18 @@ web3@1.2.4:
web3-shh "1.2.4"
web3-utils "1.2.4"
web3@^1.2.8:
version "1.2.8"
resolved "https://registry.yarnpkg.com/web3/-/web3-1.2.8.tgz#20b24baa769e0224a708ef5bf196a5b83d19540b"
integrity sha512-rXUn16VKxn2aIe9v0KX+bSm2JXdq/Vnj3lZ0Rub2Q5YUSycHdCBaDtJRukl/jB5ygAdyr5/cUwvJzhNDJSYsGw==
web3@1.2.7:
version "1.2.7"
resolved "https://registry.yarnpkg.com/web3/-/web3-1.2.7.tgz#fcb83571036c1c6f475bc984785982a444e8d78e"
integrity sha512-jAAJHMfUlTps+jH2li1ckDFEpPrEEriU/ubegSTGRl3KRdNhEqT93+3kd7FHJTn3NgjcyURo2+f7Da1YcZL8Mw==
dependencies:
web3-bzz "1.2.8"
web3-core "1.2.8"
web3-eth "1.2.8"
web3-eth-personal "1.2.8"
web3-net "1.2.8"
web3-shh "1.2.8"
web3-utils "1.2.8"
web3-bzz "1.2.7"
web3-core "1.2.7"
web3-eth "1.2.7"
web3-eth-personal "1.2.7"
web3-net "1.2.7"
web3-shh "1.2.7"
web3-utils "1.2.7"
webidl-conversions@^4.0.2:
version "4.0.2"