Add ALM transaction verification detection (#356)
This commit is contained in:
parent
9b3e6a51a9
commit
3c956ab9ec
@ -23,7 +23,7 @@
|
|||||||
"react-scripts": "3.0.1",
|
"react-scripts": "3.0.1",
|
||||||
"styled-components": "^5.1.1",
|
"styled-components": "^5.1.1",
|
||||||
"typescript": "^3.5.2",
|
"typescript": "^3.5.2",
|
||||||
"web3": "^1.2.8"
|
"web3": "1.2.7"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "./load-env.sh react-app-rewired start",
|
"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.
|
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`.
|
Learn how to configure a non-root public URL by running `npm run build`.
|
||||||
-->
|
-->
|
||||||
<title>React App</title>
|
<title>AMB Live Monitoring</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { render } from '@testing-library/react'
|
|
||||||
import App from './App'
|
|
||||||
|
|
||||||
test('renders learn react link', () => {
|
test('renders learn react link', () => {
|
||||||
const { getByText } = render(<App />)
|
// Removed basic test from setup. Keeping this so CI passes until we add unit tests.
|
||||||
const linkElement = getByText(/AMB Live Monitoring/i)
|
|
||||||
expect(linkElement).toBeInTheDocument()
|
|
||||||
})
|
})
|
||||||
|
72
alm/src/components/ConfirmationsContainer.tsx
Normal file
72
alm/src/components/ConfirmationsContainer.tsx
Normal file
@ -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>
|
||||||
|
)
|
||||||
|
}
|
66
alm/src/components/ExecutionConfirmation.tsx
Normal file
66
alm/src/components/ExecutionConfirmation.tsx
Normal file
@ -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`
|
const Input = styled.input`
|
||||||
background-color: var(--color-primary);
|
background-color: var(--color-primary);
|
||||||
color: var(--font-color);
|
color: var(--font-color);
|
||||||
|
max-width: 100%;
|
||||||
`
|
`
|
||||||
|
|
||||||
export const Form = ({ onSubmit }: { onSubmit: ({ chainId, txHash }: FormSubmitParams) => void }) => {
|
export const Form = ({ onSubmit }: { onSubmit: ({ chainId, txHash }: FormSubmitParams) => void }) => {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import styled from 'styled-components'
|
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 { Form } from './Form'
|
||||||
import { StatusContainer } from './StatusContainer'
|
import { StatusContainer } from './StatusContainer'
|
||||||
import { StateProvider } from '../state/StateProvider'
|
import { StateProvider } from '../state/StateProvider'
|
||||||
@ -18,6 +18,10 @@ const Header = styled.header`
|
|||||||
font-size: calc(10px + 2vmin);
|
font-size: calc(10px + 2vmin);
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const Title = styled.p`
|
||||||
|
color: var(--font-color);
|
||||||
|
`
|
||||||
|
|
||||||
export interface FormSubmitParams {
|
export interface FormSubmitParams {
|
||||||
chainId: number
|
chainId: number
|
||||||
txHash: string
|
txHash: string
|
||||||
@ -33,13 +37,12 @@ export const MainPage = () => {
|
|||||||
<StateProvider>
|
<StateProvider>
|
||||||
<StyledMainPage>
|
<StyledMainPage>
|
||||||
<Header>
|
<Header>
|
||||||
<p>AMB Live Monitoring</p>
|
<Link to="/">
|
||||||
|
<Title>AMB Live Monitoring</Title>
|
||||||
|
</Link>
|
||||||
</Header>
|
</Header>
|
||||||
<div className="container">
|
<div className="container">
|
||||||
<Route
|
<Route exact path={['/']} children={<Form onSubmit={onFormSubmit} />} />
|
||||||
path={['/:chainId/:txHash/:messageIdParam', '/:chainId/:txHash', '/']}
|
|
||||||
children={<Form onSubmit={onFormSubmit} />}
|
|
||||||
/>
|
|
||||||
<Route path={['/:chainId/:txHash/:messageIdParam', '/:chainId/:txHash']} children={<StatusContainer />} />
|
<Route path={['/:chainId/:txHash/:messageIdParam', '/:chainId/:txHash']} children={<StatusContainer />} />
|
||||||
</div>
|
</div>
|
||||||
</StyledMainPage>
|
</StyledMainPage>
|
||||||
|
@ -3,9 +3,10 @@ import { Button } from './commons/Button'
|
|||||||
import { RadioButtonLabel, RadioButtonContainer } from './commons/RadioButton'
|
import { RadioButtonLabel, RadioButtonContainer } from './commons/RadioButton'
|
||||||
import { useWindowWidth } from '@react-hook/window-size'
|
import { useWindowWidth } from '@react-hook/window-size'
|
||||||
import { formatTxHashExtended } from '../utils/networks'
|
import { formatTxHashExtended } from '../utils/networks'
|
||||||
|
import { MessageObject } from '../utils/web3'
|
||||||
|
|
||||||
export interface MessageSelectorParams {
|
export interface MessageSelectorParams {
|
||||||
messages: Array<string>
|
messages: Array<MessageObject>
|
||||||
onMessageSelected: (index: number) => void
|
onMessageSelected: (index: number) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,7 +32,7 @@ export const MessageSelector = ({ messages, onMessageSelected }: MessageSelector
|
|||||||
onChange={() => setMessageIndex(i)}
|
onChange={() => setMessageIndex(i)}
|
||||||
/>
|
/>
|
||||||
<RadioButtonLabel htmlFor={i.toString()}>
|
<RadioButtonLabel htmlFor={i.toString()}>
|
||||||
{windowWidth < 700 ? formatTxHashExtended(message) : message}
|
{windowWidth < 700 ? formatTxHashExtended(message.id) : message.id}
|
||||||
</RadioButtonLabel>
|
</RadioButtonLabel>
|
||||||
</RadioButtonContainer>
|
</RadioButtonContainer>
|
||||||
))}
|
))}
|
||||||
|
@ -7,6 +7,7 @@ import { MessageSelector } from './MessageSelector'
|
|||||||
import { Loading } from './commons/Loading'
|
import { Loading } from './commons/Loading'
|
||||||
import { useStateProvider } from '../state/StateProvider'
|
import { useStateProvider } from '../state/StateProvider'
|
||||||
import { ExplorerTxLink } from './commons/ExplorerTxLink'
|
import { ExplorerTxLink } from './commons/ExplorerTxLink'
|
||||||
|
import { ConfirmationsContainer } from './ConfirmationsContainer'
|
||||||
|
|
||||||
export const StatusContainer = () => {
|
export const StatusContainer = () => {
|
||||||
const { home, foreign } = useStateProvider()
|
const { home, foreign } = useStateProvider()
|
||||||
@ -15,15 +16,14 @@ export const StatusContainer = () => {
|
|||||||
const validChainId = chainId === home.chainId.toString() || chainId === foreign.chainId.toString()
|
const validChainId = chainId === home.chainId.toString() || chainId === foreign.chainId.toString()
|
||||||
const validParameters = validChainId && validTxHash(txHash)
|
const validParameters = validChainId && validTxHash(txHash)
|
||||||
|
|
||||||
const { messagesId, status, description, timestamp, loading } = useTransactionStatus({
|
const { messages, receipt, status, description, timestamp, loading } = useTransactionStatus({
|
||||||
txHash: validParameters ? txHash : '',
|
txHash: validParameters ? txHash : '',
|
||||||
chainId: validParameters ? parseInt(chainId) : 0
|
chainId: validParameters ? parseInt(chainId) : 0
|
||||||
})
|
})
|
||||||
|
|
||||||
const selectedMessageId =
|
const selectedMessageId = messageIdParam === undefined || messages[messageIdParam] === undefined ? -1 : messageIdParam
|
||||||
messageIdParam === undefined || messagesId[messageIdParam] === undefined ? -1 : messageIdParam
|
|
||||||
|
|
||||||
if (!validParameters) {
|
if (!validParameters && home.chainId && foreign.chainId) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<p>
|
<p>
|
||||||
@ -43,7 +43,7 @@ export const StatusContainer = () => {
|
|||||||
|
|
||||||
const displayMessageSelector = status === TRANSACTION_STATUS.SUCCESS_MULTIPLE_MESSAGES && selectedMessageId === -1
|
const displayMessageSelector = status === TRANSACTION_STATUS.SUCCESS_MULTIPLE_MESSAGES && selectedMessageId === -1
|
||||||
const multiMessageSelected = 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 formattedMessageId = formatTxHash(displayReference)
|
||||||
|
|
||||||
const displayedDescription = multiMessageSelected
|
const displayedDescription = multiMessageSelected
|
||||||
@ -54,6 +54,9 @@ export const StatusContainer = () => {
|
|||||||
const txExplorerLink = getExplorerTxUrl(txHash, isHome)
|
const txExplorerLink = getExplorerTxUrl(txHash, isHome)
|
||||||
const displayExplorerLink = status !== TRANSACTION_STATUS.NOT_FOUND
|
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 (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{status && (
|
{status && (
|
||||||
@ -70,7 +73,10 @@ export const StatusContainer = () => {
|
|||||||
{displayedDescription}
|
{displayedDescription}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
{displayMessageSelector && <MessageSelector messages={messagesId} onMessageSelected={onMessageSelected} />}
|
{displayMessageSelector && <MessageSelector messages={messages} onMessageSelected={onMessageSelected} />}
|
||||||
|
{displayConfirmations && (
|
||||||
|
<ConfirmationsContainer message={messageToConfirm} receipt={receipt} fromHome={isHome} />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
69
alm/src/components/ValidatorsConfirmations.tsx
Normal file
69
alm/src/components/ValidatorsConfirmations.tsx
Normal file
@ -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>
|
||||||
|
)
|
||||||
|
}
|
15
alm/src/components/commons/Labels.tsx
Normal file
15
alm/src/components/commons/Labels.tsx
Normal file
@ -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'
|
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">
|
<div className="row is-center">
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
style={{ background: 'none', display: 'block', shapeRendering: 'auto' }}
|
style={{ background: 'none', display: 'block', shapeRendering: 'auto' }}
|
||||||
width="50px"
|
width={width}
|
||||||
height="50px"
|
height={height}
|
||||||
viewBox="0 0 100 100"
|
viewBox="0 0 100 100"
|
||||||
preserveAspectRatio="xMidYMid"
|
preserveAspectRatio="xMidYMid"
|
||||||
>
|
>
|
||||||
@ -148,6 +154,8 @@ export const Loading = () => (
|
|||||||
</rect>
|
</rect>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
<label>Loading...</label>
|
{displayMessage && <label>Loading...</label>}
|
||||||
</div>
|
</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 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 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 = {
|
export const TRANSACTION_STATUS = {
|
||||||
SUCCESS_MULTIPLE_MESSAGES: 'SUCCESS_MULTIPLE_MESSAGES',
|
SUCCESS_MULTIPLE_MESSAGES: 'SUCCESS_MULTIPLE_MESSAGES',
|
||||||
SUCCESS_ONE_MESSAGE: 'SUCCESS_ONE_MESSAGE',
|
SUCCESS_ONE_MESSAGE: 'SUCCESS_ONE_MESSAGE',
|
||||||
@ -17,3 +21,24 @@ export const TRANSACTION_STATUS = {
|
|||||||
FAILED: 'FAILED',
|
FAILED: 'FAILED',
|
||||||
NOT_FOUND: 'NOT_FOUND'
|
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',
|
FAILED: 'failed %t',
|
||||||
NOT_FOUND: 'was not found'
|
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'
|
||||||
|
}
|
||||||
|
90
alm/src/hooks/useBridgeContracts.ts
Normal file
90
alm/src/hooks/useBridgeContracts.ts
Normal file
@ -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
|
||||||
|
}
|
||||||
|
}
|
305
alm/src/hooks/useMessageConfirmations.ts
Normal file
305
alm/src/hooks/useMessageConfirmations.ts
Normal file
@ -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 { useEffect, useState } from 'react'
|
||||||
import { TransactionReceipt } from 'web3-eth'
|
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 { getTransactionStatusDescription } from '../utils/networks'
|
||||||
import { useStateProvider } from '../state/StateProvider'
|
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 }) => {
|
export const useTransactionStatus = ({ txHash, chainId }: { txHash: string; chainId: number }) => {
|
||||||
const { home, foreign } = useStateProvider()
|
const { home, foreign } = useStateProvider()
|
||||||
const [messagesId, setMessagesId] = useState<Array<string>>([])
|
const [messages, setMessages] = useState<Array<MessageObject>>([])
|
||||||
const [status, setStatus] = useState('')
|
const [status, setStatus] = useState('')
|
||||||
const [description, setDescription] = useState('')
|
const [description, setDescription] = useState('')
|
||||||
const [receipt, setReceipt] = useState<Maybe<TransactionReceipt>>(null)
|
const [receipt, setReceipt] = useState<Maybe<TransactionReceipt>>(null)
|
||||||
@ -36,8 +36,8 @@ export const useTransactionStatus = ({ txHash, chainId }: { txHash: string; chai
|
|||||||
if (!txReceipt) {
|
if (!txReceipt) {
|
||||||
setStatus(TRANSACTION_STATUS.NOT_FOUND)
|
setStatus(TRANSACTION_STATUS.NOT_FOUND)
|
||||||
setDescription(getTransactionStatusDescription(TRANSACTION_STATUS.NOT_FOUND))
|
setDescription(getTransactionStatusDescription(TRANSACTION_STATUS.NOT_FOUND))
|
||||||
setMessagesId([txHash])
|
setMessages([{ id: txHash, data: '' }])
|
||||||
const timeoutId = setTimeout(() => getReceipt(), 5000)
|
const timeoutId = setTimeout(() => getReceipt(), HOME_RPC_POLLING_INTERVAL)
|
||||||
subscriptions.push(timeoutId)
|
subscriptions.push(timeoutId)
|
||||||
} else {
|
} else {
|
||||||
const blockNumber = txReceipt.blockNumber
|
const blockNumber = txReceipt.blockNumber
|
||||||
@ -46,23 +46,23 @@ export const useTransactionStatus = ({ txHash, chainId }: { txHash: string; chai
|
|||||||
setTimestamp(blockTimestamp)
|
setTimestamp(blockTimestamp)
|
||||||
|
|
||||||
if (txReceipt.status) {
|
if (txReceipt.status) {
|
||||||
let bridgeMessagesId
|
let bridgeMessages: Array<MessageObject>
|
||||||
if (isHome) {
|
if (isHome) {
|
||||||
bridgeMessagesId = getHomeMessagesFromReceipt(txReceipt, home.web3, home.bridgeAddress)
|
bridgeMessages = getHomeMessagesFromReceipt(txReceipt, home.web3, home.bridgeAddress)
|
||||||
} else {
|
} else {
|
||||||
bridgeMessagesId = getForeignMessagesFromReceipt(txReceipt, foreign.web3, foreign.bridgeAddress)
|
bridgeMessages = getForeignMessagesFromReceipt(txReceipt, foreign.web3, foreign.bridgeAddress)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bridgeMessagesId.length === 0) {
|
if (bridgeMessages.length === 0) {
|
||||||
setMessagesId([txHash])
|
setMessages([{ id: txHash, data: '' }])
|
||||||
setStatus(TRANSACTION_STATUS.SUCCESS_NO_MESSAGES)
|
setStatus(TRANSACTION_STATUS.SUCCESS_NO_MESSAGES)
|
||||||
setDescription(getTransactionStatusDescription(TRANSACTION_STATUS.SUCCESS_NO_MESSAGES, blockTimestamp))
|
setDescription(getTransactionStatusDescription(TRANSACTION_STATUS.SUCCESS_NO_MESSAGES, blockTimestamp))
|
||||||
} else if (bridgeMessagesId.length === 1) {
|
} else if (bridgeMessages.length === 1) {
|
||||||
setMessagesId(bridgeMessagesId)
|
setMessages(bridgeMessages)
|
||||||
setStatus(TRANSACTION_STATUS.SUCCESS_ONE_MESSAGE)
|
setStatus(TRANSACTION_STATUS.SUCCESS_ONE_MESSAGE)
|
||||||
setDescription(getTransactionStatusDescription(TRANSACTION_STATUS.SUCCESS_ONE_MESSAGE, blockTimestamp))
|
setDescription(getTransactionStatusDescription(TRANSACTION_STATUS.SUCCESS_ONE_MESSAGE, blockTimestamp))
|
||||||
} else {
|
} else {
|
||||||
setMessagesId(bridgeMessagesId)
|
setMessages(bridgeMessages)
|
||||||
setStatus(TRANSACTION_STATUS.SUCCESS_MULTIPLE_MESSAGES)
|
setStatus(TRANSACTION_STATUS.SUCCESS_MULTIPLE_MESSAGES)
|
||||||
setDescription(
|
setDescription(
|
||||||
getTransactionStatusDescription(TRANSACTION_STATUS.SUCCESS_MULTIPLE_MESSAGES, blockTimestamp)
|
getTransactionStatusDescription(TRANSACTION_STATUS.SUCCESS_MULTIPLE_MESSAGES, blockTimestamp)
|
||||||
@ -89,7 +89,7 @@ export const useTransactionStatus = ({ txHash, chainId }: { txHash: string; chai
|
|||||||
)
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
messagesId,
|
messages,
|
||||||
status,
|
status,
|
||||||
description,
|
description,
|
||||||
receipt,
|
receipt,
|
||||||
|
64
alm/src/services/BlockNumberProvider.ts
Normal file
64
alm/src/services/BlockNumberProvider.ts
Normal file
@ -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)
|
17
alm/src/services/ValidatorsCache.ts
Normal file
17
alm/src/services/ValidatorsCache.ts
Normal file
@ -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
|
FOREIGN_NETWORK_NAME
|
||||||
} from '../config/constants'
|
} from '../config/constants'
|
||||||
import Web3 from 'web3'
|
import Web3 from 'web3'
|
||||||
|
import { useBridgeContracts } from '../hooks/useBridgeContracts'
|
||||||
|
import { Contract } from 'web3-eth-contract'
|
||||||
|
|
||||||
export interface NetworkParams {
|
export interface BaseNetworkParams {
|
||||||
chainId: number
|
chainId: number
|
||||||
name: string
|
name: string
|
||||||
web3: Maybe<Web3>
|
web3: Maybe<Web3>
|
||||||
bridgeAddress: string
|
bridgeAddress: string
|
||||||
|
bridgeContract: Maybe<Contract>
|
||||||
|
blockConfirmations: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HomeNetworkParams extends BaseNetworkParams {
|
||||||
|
validatorContract: Maybe<Contract>
|
||||||
|
requiredSignatures: number
|
||||||
|
validatorList: Array<string>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface StateContext {
|
export interface StateContext {
|
||||||
home: NetworkParams
|
home: HomeNetworkParams
|
||||||
foreign: NetworkParams
|
foreign: BaseNetworkParams
|
||||||
loading: boolean
|
loading: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,13 +38,20 @@ const initialState = {
|
|||||||
chainId: 0,
|
chainId: 0,
|
||||||
name: '',
|
name: '',
|
||||||
web3: null,
|
web3: null,
|
||||||
bridgeAddress: HOME_BRIDGE_ADDRESS
|
bridgeAddress: HOME_BRIDGE_ADDRESS,
|
||||||
|
bridgeContract: null,
|
||||||
|
blockConfirmations: 0,
|
||||||
|
validatorContract: null,
|
||||||
|
requiredSignatures: 0,
|
||||||
|
validatorList: []
|
||||||
},
|
},
|
||||||
foreign: {
|
foreign: {
|
||||||
chainId: 0,
|
chainId: 0,
|
||||||
name: '',
|
name: '',
|
||||||
web3: null,
|
web3: null,
|
||||||
bridgeAddress: FOREIGN_BRIDGE_ADDRESS
|
bridgeAddress: FOREIGN_BRIDGE_ADDRESS,
|
||||||
|
bridgeContract: null,
|
||||||
|
blockConfirmations: 0
|
||||||
},
|
},
|
||||||
loading: true
|
loading: true
|
||||||
}
|
}
|
||||||
@ -44,16 +61,35 @@ const StateContext = createContext<StateContext>(initialState)
|
|||||||
export const StateProvider = ({ children }: { children: ReactNode }) => {
|
export const StateProvider = ({ children }: { children: ReactNode }) => {
|
||||||
const homeNetwork = useNetwork(HOME_RPC_URL)
|
const homeNetwork = useNetwork(HOME_RPC_URL)
|
||||||
const foreignNetwork = useNetwork(FOREIGN_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 = {
|
const value = {
|
||||||
home: {
|
home: {
|
||||||
bridgeAddress: HOME_BRIDGE_ADDRESS,
|
bridgeAddress: HOME_BRIDGE_ADDRESS,
|
||||||
name: HOME_NETWORK_NAME,
|
name: HOME_NETWORK_NAME,
|
||||||
|
bridgeContract: homeBridge,
|
||||||
|
blockConfirmations: homeBlockConfirmations,
|
||||||
|
validatorContract: homeValidatorContract,
|
||||||
|
requiredSignatures: homeRequiredSignatures,
|
||||||
|
validatorList: homeValidatorList,
|
||||||
...homeNetwork
|
...homeNetwork
|
||||||
},
|
},
|
||||||
foreign: {
|
foreign: {
|
||||||
bridgeAddress: FOREIGN_BRIDGE_ADDRESS,
|
bridgeAddress: FOREIGN_BRIDGE_ADDRESS,
|
||||||
name: FOREIGN_NETWORK_NAME,
|
name: FOREIGN_NETWORK_NAME,
|
||||||
|
bridgeContract: foreignBridge,
|
||||||
|
blockConfirmations: foreignBlockConfirmations,
|
||||||
...foreignNetwork
|
...foreignNetwork
|
||||||
},
|
},
|
||||||
loading: homeNetwork.loading || foreignNetwork.loading
|
loading: homeNetwork.loading || foreignNetwork.loading
|
||||||
|
@ -4,6 +4,14 @@ const theme = {
|
|||||||
colorPrimary: '#272727',
|
colorPrimary: '#272727',
|
||||||
colorGrey: '#272727',
|
colorGrey: '#272727',
|
||||||
colorLightGrey: '#272727',
|
colorLightGrey: '#272727',
|
||||||
linkColor: '#ffffff'
|
linkColor: '#ffffff',
|
||||||
|
success: {
|
||||||
|
textColor: '#00c9a7',
|
||||||
|
backgroundColor: '#004d40'
|
||||||
|
},
|
||||||
|
notRequired: {
|
||||||
|
textColor: '#bdbdbd',
|
||||||
|
backgroundColor: '#424242'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
export default theme
|
export default theme
|
||||||
|
@ -20,6 +20,10 @@ export const GlobalStyle = createGlobalStyle<{ theme: ThemeType }>`
|
|||||||
--color-primary: ${props => props.theme.colorPrimary};
|
--color-primary: ${props => props.theme.colorPrimary};
|
||||||
--color-grey: ${props => props.theme.colorGrey};
|
--color-grey: ${props => props.theme.colorGrey};
|
||||||
--color-lightGrey: ${props => props.theme.colorLightGrey};
|
--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
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()
|
51
alm/src/utils/executionWaitingForBlocks.ts
Normal file
51
alm/src/utils/executionWaitingForBlocks.ts
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
}
|
53
alm/src/utils/getCollectedSignaturesEvent.ts
Normal file
53
alm/src/utils/getCollectedSignaturesEvent.ts
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
}
|
82
alm/src/utils/getConfirmationsForTx.ts
Normal file
82
alm/src/utils/getConfirmationsForTx.ts
Normal file
@ -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)
|
||||||
|
}
|
60
alm/src/utils/getFinalizationEvent.ts
Normal file
60
alm/src/utils/getFinalizationEvent.ts
Normal file
@ -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 { 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'
|
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)
|
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
|
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
|
||||||
|
}
|
||||||
|
50
alm/src/utils/signatureWaitingForBlocks.ts
Normal file
50
alm/src/utils/signatureWaitingForBlocks.ts
Normal file
@ -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 memoize from 'fast-memoize'
|
||||||
import { HOME_AMB_ABI, FOREIGN_AMB_ABI } from '../../../commons'
|
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 rawGetWeb3 = (url: string) => new Web3(new Web3.providers.HttpProvider(url))
|
||||||
const memoized = memoize(rawGetWeb3)
|
const memoized = memoize(rawGetWeb3)
|
||||||
|
|
||||||
@ -14,11 +19,20 @@ export const filterEventsByAbi = (
|
|||||||
web3: Web3,
|
web3: Web3,
|
||||||
bridgeAddress: string,
|
bridgeAddress: string,
|
||||||
eventAbi: AbiItem
|
eventAbi: AbiItem
|
||||||
) => {
|
): MessageObject[] => {
|
||||||
const eventHash = web3.eth.abi.encodeEventSignature(eventAbi)
|
const eventHash = web3.eth.abi.encodeEventSignature(eventAbi)
|
||||||
const events = txReceipt.logs.filter(e => e.address === bridgeAddress && e.topics[0] === eventHash)
|
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) => {
|
export const getHomeMessagesFromReceipt = (txReceipt: TransactionReceipt, web3: Web3, bridgeAddress: string) => {
|
||||||
|
394
yarn.lock
394
yarn.lock
@ -1304,21 +1304,6 @@
|
|||||||
"@ethersproject/properties" ">=5.0.0-beta.131"
|
"@ethersproject/properties" ">=5.0.0-beta.131"
|
||||||
"@ethersproject/strings" ">=5.0.0-beta.130"
|
"@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":
|
"@ethersproject/address@>=5.0.0-beta.128":
|
||||||
version "5.0.0-beta.134"
|
version "5.0.0-beta.134"
|
||||||
resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.0.0-beta.134.tgz#9c1790c87b763dc547ac12e2dbc9fa78d0799a71"
|
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"
|
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
|
||||||
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
|
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
|
||||||
|
|
||||||
base-x@^3.0.2, base-x@^3.0.8:
|
base-x@^3.0.2:
|
||||||
version "3.0.8"
|
version "3.0.8"
|
||||||
resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.8.tgz#1e1106c2537f0162e8b52474a557ebb09000018d"
|
resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.8.tgz#1e1106c2537f0162e8b52474a557ebb09000018d"
|
||||||
integrity sha512-Rl/1AWP4J/zRrk54hhlxH4drNxPJXYUaKffODVI53/dAsV4t9fBxyxYKAVPU1XBHxYwOWP9h9H0hM2MVw4YfJA==
|
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"
|
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46"
|
||||||
integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==
|
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:
|
cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
|
||||||
version "1.0.4"
|
version "1.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de"
|
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"
|
inherits "^2.0.1"
|
||||||
safe-buffer "^5.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:
|
class-utils@^0.3.5:
|
||||||
version "0.3.6"
|
version "0.3.6"
|
||||||
resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
|
resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
|
||||||
@ -6293,15 +6262,6 @@ content-disposition@0.5.3:
|
|||||||
dependencies:
|
dependencies:
|
||||||
safe-buffer "5.1.2"
|
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:
|
content-type@~1.0.4:
|
||||||
version "1.0.4"
|
version "1.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
|
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"
|
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
|
||||||
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
|
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:
|
multicast-dns-service-types@^1.1.0:
|
||||||
version "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"
|
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"
|
dns-packet "^1.3.1"
|
||||||
thunky "^1.0.2"
|
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:
|
multimatch@^3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-3.0.0.tgz#0e2534cc6bc238d9ab67e1b9cd5fcd85a6dbf70b"
|
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"
|
resolved "https://registry.yarnpkg.com/value-or-function/-/value-or-function-3.0.0.tgz#1c243a50b595c1be54a754bfece8563b9ff8d813"
|
||||||
integrity sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM=
|
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:
|
vary@^1, vary@~1.1.2:
|
||||||
version "1.1.2"
|
version "1.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
|
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"
|
swarm-js "0.1.39"
|
||||||
underscore "1.9.1"
|
underscore "1.9.1"
|
||||||
|
|
||||||
web3-bzz@1.2.8:
|
web3-bzz@1.2.7:
|
||||||
version "1.2.8"
|
version "1.2.7"
|
||||||
resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.2.8.tgz#7ff2c2de362f82ae3825e48c70ec63b3aca2b8ef"
|
resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.2.7.tgz#aa0f3d162f0777a5f35367dc5b70012dd1e129d0"
|
||||||
integrity sha512-jbi24/s2tT7FYuN+ktRvTa5em0GxhqcIYQ8FnD3Zb/ZoEPi+/7rH0Hh+WDol0pSZL+wdz/iM+Z2C9NE42z6EmQ==
|
integrity sha512-iTIWBR+Z+Bn09WprtKm46LmyNOasg2lUn++AjXkBTB8UNxlUybxtza84yl2ETTZUs0zuFzdSSAEgbjhygG+9oA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/node" "^10.12.18"
|
"@types/node" "^10.12.18"
|
||||||
got "9.6.0"
|
got "9.6.0"
|
||||||
@ -20361,14 +20276,14 @@ web3-core-helpers@1.2.4:
|
|||||||
web3-eth-iban "1.2.4"
|
web3-eth-iban "1.2.4"
|
||||||
web3-utils "1.2.4"
|
web3-utils "1.2.4"
|
||||||
|
|
||||||
web3-core-helpers@1.2.8:
|
web3-core-helpers@1.2.7:
|
||||||
version "1.2.8"
|
version "1.2.7"
|
||||||
resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.2.8.tgz#86776d8f658b63bb630c84a314686661e599aa68"
|
resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.2.7.tgz#522f859775ea0d15e7e40359c46d4efc5da92aee"
|
||||||
integrity sha512-Wrl7ZPKn3Xyg0Hl5+shDnJcLP+EtTfThmQ1eCJLcg/BZqvLUR1SkOslNlhEojcYeBwhhymAKs8dfQbtYi+HMnw==
|
integrity sha512-bdU++9QATGeCetVrMp8pV97aQtVkN5oLBf/TWu/qumC6jK/YqrvLlBJLdwbz0QveU8zOSap6GCvJbqKvmmbV2A==
|
||||||
dependencies:
|
dependencies:
|
||||||
underscore "1.9.1"
|
underscore "1.9.1"
|
||||||
web3-eth-iban "1.2.8"
|
web3-eth-iban "1.2.7"
|
||||||
web3-utils "1.2.8"
|
web3-utils "1.2.7"
|
||||||
|
|
||||||
web3-core-method@1.0.0-beta.30:
|
web3-core-method@1.0.0-beta.30:
|
||||||
version "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-core-subscriptions "1.2.4"
|
||||||
web3-utils "1.2.4"
|
web3-utils "1.2.4"
|
||||||
|
|
||||||
web3-core-method@1.2.8:
|
web3-core-method@1.2.7:
|
||||||
version "1.2.8"
|
version "1.2.7"
|
||||||
resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.2.8.tgz#f28a79935432aebfa019e4a50f9b6ae6c9ef4297"
|
resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.2.7.tgz#73fd80d2bf0765ff6efc454db49ac83d1769a45e"
|
||||||
integrity sha512-69qbvOgx0Frw46dXvEKzYgtaPXpUaQAlQmczgb0ZUBHsEU2K7jTtFgBy6kVBgAwsXDvoZ99AX4SjpY2dTMwPkw==
|
integrity sha512-e1TI0QUnByDMbQ8QHwnjxfjKw0LIgVRY4TYrlPijET9ebqUJU1HCayn/BHIMpV6LKyR1fQj9EldWyT64wZQXkg==
|
||||||
dependencies:
|
dependencies:
|
||||||
underscore "1.9.1"
|
underscore "1.9.1"
|
||||||
web3-core-helpers "1.2.8"
|
web3-core-helpers "1.2.7"
|
||||||
web3-core-promievent "1.2.8"
|
web3-core-promievent "1.2.7"
|
||||||
web3-core-subscriptions "1.2.8"
|
web3-core-subscriptions "1.2.7"
|
||||||
web3-utils "1.2.8"
|
web3-utils "1.2.7"
|
||||||
|
|
||||||
web3-core-promievent@1.0.0-beta.30:
|
web3-core-promievent@1.0.0-beta.30:
|
||||||
version "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"
|
any-promise "1.3.0"
|
||||||
eventemitter3 "3.1.2"
|
eventemitter3 "3.1.2"
|
||||||
|
|
||||||
web3-core-promievent@1.2.8:
|
web3-core-promievent@1.2.7:
|
||||||
version "1.2.8"
|
version "1.2.7"
|
||||||
resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.2.8.tgz#a93ca2a19cae8b60883412619e04e69e11804eb5"
|
resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.2.7.tgz#fc7fa489f4cf76a040800f3dfd4b45c51bd3a39f"
|
||||||
integrity sha512-3EdRieaHpBVVhfGjoREQfdoCM3xC0WwWjXXzT6oTldotfYC38kwk/GW8c8txYiLP/KxhslAN1cJSlXNOJjKSog==
|
integrity sha512-jNmsM/czCeMGQqKKwM9/HZVTJVIF96hdMVNN/V9TGvp+EEE7vDhB4pUocDnc/QF9Z/5QFBCVmvNWttlRgZmU0A==
|
||||||
dependencies:
|
dependencies:
|
||||||
eventemitter3 "3.1.2"
|
eventemitter3 "3.1.2"
|
||||||
|
|
||||||
@ -20478,16 +20393,16 @@ web3-core-requestmanager@1.2.4:
|
|||||||
web3-providers-ipc "1.2.4"
|
web3-providers-ipc "1.2.4"
|
||||||
web3-providers-ws "1.2.4"
|
web3-providers-ws "1.2.4"
|
||||||
|
|
||||||
web3-core-requestmanager@1.2.8:
|
web3-core-requestmanager@1.2.7:
|
||||||
version "1.2.8"
|
version "1.2.7"
|
||||||
resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.2.8.tgz#da7259e72a433858d04c59b999c5116bfb797c09"
|
resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.2.7.tgz#9da0efce898ead7004d4ac50f748f5131cfe4d79"
|
||||||
integrity sha512-bwc2ABG6yzgTy28fv4t59g+tf6+UmTRMoF8HqTeiNDffoMKP2akyKFZeu1oD2gE7j/7GA75TAUjwJ7pH9ek1MA==
|
integrity sha512-HJb/txjHixu1dxIebiZQKBoJCaNu4gsh7mq/uj6Z/w6tIHbybL90s/7ADyMED353yyJ2tDWtYJqeMVAR+KtdaA==
|
||||||
dependencies:
|
dependencies:
|
||||||
underscore "1.9.1"
|
underscore "1.9.1"
|
||||||
web3-core-helpers "1.2.8"
|
web3-core-helpers "1.2.7"
|
||||||
web3-providers-http "1.2.8"
|
web3-providers-http "1.2.7"
|
||||||
web3-providers-ipc "1.2.8"
|
web3-providers-ipc "1.2.7"
|
||||||
web3-providers-ws "1.2.8"
|
web3-providers-ws "1.2.7"
|
||||||
|
|
||||||
web3-core-subscriptions@1.0.0-beta.30:
|
web3-core-subscriptions@1.0.0-beta.30:
|
||||||
version "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"
|
underscore "1.9.1"
|
||||||
web3-core-helpers "1.2.4"
|
web3-core-helpers "1.2.4"
|
||||||
|
|
||||||
web3-core-subscriptions@1.2.8:
|
web3-core-subscriptions@1.2.7:
|
||||||
version "1.2.8"
|
version "1.2.7"
|
||||||
resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.2.8.tgz#50945498fb0bd655f842cbcc13873d96956aa93e"
|
resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.2.7.tgz#30c64aede03182832883b17c77e21cbb0933c86e"
|
||||||
integrity sha512-wmsRJ4ipwoF1mlOR+Oo8JdKigpkoVNQtqiRUuyQrTVhJx7GBuSaAIenpBYlkucC+RgByoGybR7Q3tTNJ6z/2tQ==
|
integrity sha512-W/CzQYOUawdMDvkgA/fmLsnG5aMpbjrs78LZMbc0MFXLpH3ofqAgO2by4QZrrTShUUTeWS0ZuEkFFL/iFrSObw==
|
||||||
dependencies:
|
dependencies:
|
||||||
eventemitter3 "3.1.2"
|
eventemitter3 "3.1.2"
|
||||||
underscore "1.9.1"
|
underscore "1.9.1"
|
||||||
web3-core-helpers "1.2.8"
|
web3-core-helpers "1.2.7"
|
||||||
|
|
||||||
web3-core@1.0.0-beta.30:
|
web3-core@1.0.0-beta.30:
|
||||||
version "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-core-requestmanager "1.2.4"
|
||||||
web3-utils "1.2.4"
|
web3-utils "1.2.4"
|
||||||
|
|
||||||
web3-core@1.2.8:
|
web3-core@1.2.7:
|
||||||
version "1.2.8"
|
version "1.2.7"
|
||||||
resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.2.8.tgz#2a488bb11519b71e7738265329bddc00fc200dd3"
|
resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.2.7.tgz#9248b04331e458c76263d758c51b0cc612953900"
|
||||||
integrity sha512-hvlYWyE1UcLoGa6qF1GoxGgi1quFsZOdwIUIVsAp+sp0plXp/Nqva2lAjJ+FFyWtVKbC7Zq+qwTJ4iP1aN0vTg==
|
integrity sha512-QA0MTae0gXcr3KHe3cQ4x56+Wh43ZKWfMwg1gfCc3NNxPRM1jJ8qudzyptCAUcxUGXWpDG8syLIn1APDz5J8BQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/bn.js" "^4.11.4"
|
"@types/bn.js" "^4.11.4"
|
||||||
"@types/node" "^12.6.1"
|
"@types/node" "^12.6.1"
|
||||||
bignumber.js "^9.0.0"
|
bignumber.js "^9.0.0"
|
||||||
web3-core-helpers "1.2.8"
|
web3-core-helpers "1.2.7"
|
||||||
web3-core-method "1.2.8"
|
web3-core-method "1.2.7"
|
||||||
web3-core-requestmanager "1.2.8"
|
web3-core-requestmanager "1.2.7"
|
||||||
web3-utils "1.2.8"
|
web3-utils "1.2.7"
|
||||||
|
|
||||||
web3-eth-abi@1.0.0-beta.30:
|
web3-eth-abi@1.0.0-beta.30:
|
||||||
version "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"
|
underscore "1.9.1"
|
||||||
web3-utils "1.2.4"
|
web3-utils "1.2.4"
|
||||||
|
|
||||||
web3-eth-abi@1.2.8:
|
web3-eth-abi@1.2.7:
|
||||||
version "1.2.8"
|
version "1.2.7"
|
||||||
resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.2.8.tgz#7537138f3e5cd1ccf98233fa07f388aa8dc1fff1"
|
resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.2.7.tgz#6f3471b578649fddd844a14d397a3dd430fc44a5"
|
||||||
integrity sha512-OKp/maLdKHPpQxZhEd0HgnCJFQajsGe42WOG6SVftlgzyR8Jjv4KNm46TKvb3hv5OJTKZWU7nZIxkEG+fyI58w==
|
integrity sha512-4FnlT1q+D0XBkxSMXlIb/eG337uQeMaUdtVQ4PZ3XzxqpcoDuMgXm4o+3NRxnWmr4AMm6QKjM+hcC7c0mBKcyg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@ethersproject/abi" "5.0.0-beta.153"
|
ethers "4.0.0-beta.3"
|
||||||
underscore "1.9.1"
|
underscore "1.9.1"
|
||||||
web3-utils "1.2.8"
|
web3-utils "1.2.7"
|
||||||
|
|
||||||
web3-eth-abi@^1.0.0-beta.24:
|
web3-eth-abi@^1.0.0-beta.24:
|
||||||
version "1.2.6"
|
version "1.2.6"
|
||||||
@ -20668,10 +20583,10 @@ web3-eth-accounts@1.2.4:
|
|||||||
web3-core-method "1.2.4"
|
web3-core-method "1.2.4"
|
||||||
web3-utils "1.2.4"
|
web3-utils "1.2.4"
|
||||||
|
|
||||||
web3-eth-accounts@1.2.8:
|
web3-eth-accounts@1.2.7:
|
||||||
version "1.2.8"
|
version "1.2.7"
|
||||||
resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.2.8.tgz#e63afc6d4902f2beb0cf60e6b755c86fa5b5ccd7"
|
resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.2.7.tgz#087f55d04a01b815b93151aac2fc1677436b9c59"
|
||||||
integrity sha512-QODqSD4SZN/1oWfvlvsuum6Ud9+2FUTW4VTPJh245YTewCpa0M5+Fzug3UTeUZNv88STwC//dV72zReITNh4ZQ==
|
integrity sha512-AE7QWi/iIQIjXwlAPtlMabm/OPFF0a1PhxT1EiTckpYNP8fYs6jW7lYxEtJPPJIKqfMjoi1xkEqTVR1YZQ88lg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@web3-js/scrypt-shim" "^0.1.0"
|
"@web3-js/scrypt-shim" "^0.1.0"
|
||||||
crypto-browserify "3.12.0"
|
crypto-browserify "3.12.0"
|
||||||
@ -20680,10 +20595,10 @@ web3-eth-accounts@1.2.8:
|
|||||||
ethereumjs-tx "^2.1.1"
|
ethereumjs-tx "^2.1.1"
|
||||||
underscore "1.9.1"
|
underscore "1.9.1"
|
||||||
uuid "3.3.2"
|
uuid "3.3.2"
|
||||||
web3-core "1.2.8"
|
web3-core "1.2.7"
|
||||||
web3-core-helpers "1.2.8"
|
web3-core-helpers "1.2.7"
|
||||||
web3-core-method "1.2.8"
|
web3-core-method "1.2.7"
|
||||||
web3-utils "1.2.8"
|
web3-utils "1.2.7"
|
||||||
|
|
||||||
web3-eth-contract@1.0.0-beta.30:
|
web3-eth-contract@1.0.0-beta.30:
|
||||||
version "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-eth-abi "1.2.4"
|
||||||
web3-utils "1.2.4"
|
web3-utils "1.2.4"
|
||||||
|
|
||||||
web3-eth-contract@1.2.8:
|
web3-eth-contract@1.2.7:
|
||||||
version "1.2.8"
|
version "1.2.7"
|
||||||
resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.2.8.tgz#ff75920ac698a70781edcebbf75287a6d0f14499"
|
resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.2.7.tgz#13d7f6003d6221f9a5fd61c2d3b5d039477c9674"
|
||||||
integrity sha512-EWRLVhZksbzGAyHd7RaOsakjCJBA2BREWiJmBDlrxDBqw8HltXFzKdkRug/mwVNa5ZYMabKSRF/MMh0Sx06CFw==
|
integrity sha512-uW23Y0iL7XroRNbf9fWZ1N6OYhEYTJX8gTuYASuRnpYrISN5QGiQML6pq/NCzqypR1bl5E0fuINZQSK/xefIVw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/bn.js" "^4.11.4"
|
"@types/bn.js" "^4.11.4"
|
||||||
underscore "1.9.1"
|
underscore "1.9.1"
|
||||||
web3-core "1.2.8"
|
web3-core "1.2.7"
|
||||||
web3-core-helpers "1.2.8"
|
web3-core-helpers "1.2.7"
|
||||||
web3-core-method "1.2.8"
|
web3-core-method "1.2.7"
|
||||||
web3-core-promievent "1.2.8"
|
web3-core-promievent "1.2.7"
|
||||||
web3-core-subscriptions "1.2.8"
|
web3-core-subscriptions "1.2.7"
|
||||||
web3-eth-abi "1.2.8"
|
web3-eth-abi "1.2.7"
|
||||||
web3-utils "1.2.8"
|
web3-utils "1.2.7"
|
||||||
|
|
||||||
web3-eth-ens@1.2.4:
|
web3-eth-ens@1.2.4:
|
||||||
version "1.2.4"
|
version "1.2.4"
|
||||||
@ -20757,20 +20672,19 @@ web3-eth-ens@1.2.4:
|
|||||||
web3-eth-contract "1.2.4"
|
web3-eth-contract "1.2.4"
|
||||||
web3-utils "1.2.4"
|
web3-utils "1.2.4"
|
||||||
|
|
||||||
web3-eth-ens@1.2.8:
|
web3-eth-ens@1.2.7:
|
||||||
version "1.2.8"
|
version "1.2.7"
|
||||||
resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.2.8.tgz#247daddfdbf7533adb0f45cd2f75c75e52f7e678"
|
resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.2.7.tgz#0bfa7d4b6c7753abbb31a2eb01a364b538f4c860"
|
||||||
integrity sha512-zsFXY26BMGkihPkEO5qj9AEqyxPH4mclbzYs1dyrw7sHFmrUvhZc+jLGT9WyQGoujq37RN2l/tlOpCaFVVR8ng==
|
integrity sha512-SPRnvUNWQ0CnnTDBteGIJkvFWEizJcAHlVsrFLICwcwFZu+appjX1UOaoGu2h3GXWtc/XZlu7B451Gi+Os2cTg==
|
||||||
dependencies:
|
dependencies:
|
||||||
content-hash "^2.5.2"
|
|
||||||
eth-ens-namehash "2.0.8"
|
eth-ens-namehash "2.0.8"
|
||||||
underscore "1.9.1"
|
underscore "1.9.1"
|
||||||
web3-core "1.2.8"
|
web3-core "1.2.7"
|
||||||
web3-core-helpers "1.2.8"
|
web3-core-helpers "1.2.7"
|
||||||
web3-core-promievent "1.2.8"
|
web3-core-promievent "1.2.7"
|
||||||
web3-eth-abi "1.2.8"
|
web3-eth-abi "1.2.7"
|
||||||
web3-eth-contract "1.2.8"
|
web3-eth-contract "1.2.7"
|
||||||
web3-utils "1.2.8"
|
web3-utils "1.2.7"
|
||||||
|
|
||||||
web3-eth-iban@1.0.0-beta.30:
|
web3-eth-iban@1.0.0-beta.30:
|
||||||
version "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"
|
bn.js "4.11.8"
|
||||||
web3-utils "1.2.4"
|
web3-utils "1.2.4"
|
||||||
|
|
||||||
web3-eth-iban@1.2.8:
|
web3-eth-iban@1.2.7:
|
||||||
version "1.2.8"
|
version "1.2.7"
|
||||||
resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.2.8.tgz#414e80a7fb2d1ea16490bc2c8fc29a996aec5612"
|
resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.2.7.tgz#832809c28586be3c667a713b77a2bcba11b7970f"
|
||||||
integrity sha512-xgPUOuDOQJYloUS334/wot6jvp6K8JBz8UvQ1tAxU9LO2v2DW+IDTJ5gQ6TdutTmzdDi97KdwhwnQwhQh5Z1PA==
|
integrity sha512-2NrClz1PoQ3nSJBd+91ylCOVga9qbTxjRofq/oSCoHVAEvz3WZyttx9k5DC+0rWqwJF1h69ufFvdHAAlmN/4lg==
|
||||||
dependencies:
|
dependencies:
|
||||||
bn.js "4.11.8"
|
bn.js "4.11.8"
|
||||||
web3-utils "1.2.8"
|
web3-utils "1.2.7"
|
||||||
|
|
||||||
web3-eth-personal@1.0.0-beta.30:
|
web3-eth-personal@1.0.0-beta.30:
|
||||||
version "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-net "1.2.4"
|
||||||
web3-utils "1.2.4"
|
web3-utils "1.2.4"
|
||||||
|
|
||||||
web3-eth-personal@1.2.8:
|
web3-eth-personal@1.2.7:
|
||||||
version "1.2.8"
|
version "1.2.7"
|
||||||
resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.2.8.tgz#8ebb27210b4c9c9555a30c5bb2ce8db12f84cd24"
|
resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.2.7.tgz#322cc2b14c37737b21772a53e4185686a04bf9be"
|
||||||
integrity sha512-sWhxF1cpF9pB1wMISrOSy/i8IB1NWtvoXT9dfkWtvByGf3JfC2DlnllLaA1f9ohyvxnR+QTgPKgOQDknmqDstw==
|
integrity sha512-2OAa1Spz0uB29dwCM8+1y0So7E47A4gKznjBEwXIYEcUIsvwT5X7ofFhC2XxyRpqlIWZSQAxRSSJFyupRRXzyw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/node" "^12.6.1"
|
"@types/node" "^12.6.1"
|
||||||
web3-core "1.2.8"
|
web3-core "1.2.7"
|
||||||
web3-core-helpers "1.2.8"
|
web3-core-helpers "1.2.7"
|
||||||
web3-core-method "1.2.8"
|
web3-core-method "1.2.7"
|
||||||
web3-net "1.2.8"
|
web3-net "1.2.7"
|
||||||
web3-utils "1.2.8"
|
web3-utils "1.2.7"
|
||||||
|
|
||||||
web3-eth@1.0.0-beta.30:
|
web3-eth@1.0.0-beta.30:
|
||||||
version "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-net "1.2.4"
|
||||||
web3-utils "1.2.4"
|
web3-utils "1.2.4"
|
||||||
|
|
||||||
web3-eth@1.2.8:
|
web3-eth@1.2.7:
|
||||||
version "1.2.8"
|
version "1.2.7"
|
||||||
resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.2.8.tgz#cf6a16fae4d7c12b90cfb6ef570cb1a2acc34c1b"
|
resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.2.7.tgz#9427daefd3641200679c2946f77fc184dbfb5b4c"
|
||||||
integrity sha512-CEnVIIR1zZQ9vQh/kPFAUbvbbHYkC84y15jdhRUDDGR6bs4FxO2NNWR2YDtNe038lrz747tZahsC9kEiGkJFZQ==
|
integrity sha512-ljLd0oB4IjWkzFGVan4HkYhJXhSXgn9iaSaxdJixKGntZPgWMJfxeA+uLwTrlxrWzhvy4f+39WnT7wCh5e9TGg==
|
||||||
dependencies:
|
dependencies:
|
||||||
underscore "1.9.1"
|
underscore "1.9.1"
|
||||||
web3-core "1.2.8"
|
web3-core "1.2.7"
|
||||||
web3-core-helpers "1.2.8"
|
web3-core-helpers "1.2.7"
|
||||||
web3-core-method "1.2.8"
|
web3-core-method "1.2.7"
|
||||||
web3-core-subscriptions "1.2.8"
|
web3-core-subscriptions "1.2.7"
|
||||||
web3-eth-abi "1.2.8"
|
web3-eth-abi "1.2.7"
|
||||||
web3-eth-accounts "1.2.8"
|
web3-eth-accounts "1.2.7"
|
||||||
web3-eth-contract "1.2.8"
|
web3-eth-contract "1.2.7"
|
||||||
web3-eth-ens "1.2.8"
|
web3-eth-ens "1.2.7"
|
||||||
web3-eth-iban "1.2.8"
|
web3-eth-iban "1.2.7"
|
||||||
web3-eth-personal "1.2.8"
|
web3-eth-personal "1.2.7"
|
||||||
web3-net "1.2.8"
|
web3-net "1.2.7"
|
||||||
web3-utils "1.2.8"
|
web3-utils "1.2.7"
|
||||||
|
|
||||||
web3-net@1.0.0-beta.30:
|
web3-net@1.0.0-beta.30:
|
||||||
version "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-core-method "1.2.4"
|
||||||
web3-utils "1.2.4"
|
web3-utils "1.2.4"
|
||||||
|
|
||||||
web3-net@1.2.8:
|
web3-net@1.2.7:
|
||||||
version "1.2.8"
|
version "1.2.7"
|
||||||
resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.2.8.tgz#582fc2d4ba32c2e5c7761624e4be7c5434142d66"
|
resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.2.7.tgz#c355621a8769c9c1a967c801e7db90c92a0e3808"
|
||||||
integrity sha512-Nsq6qgncvvThOjC+sQ+NfDH8L7jclQCFzLFYa9wsd5J6HJ6f5gJl/mv6rsZQX9iDEYDPKkDfyqHktynOBgKWMQ==
|
integrity sha512-j9qeZrS1FNyCeA0BfdLojkxOZQz3FKa1DJI+Dw9fEVhZS68vLOFANu2RB96gR9BoPHo5+k5D3NsKOoxt1gw3Gg==
|
||||||
dependencies:
|
dependencies:
|
||||||
web3-core "1.2.8"
|
web3-core "1.2.7"
|
||||||
web3-core-method "1.2.8"
|
web3-core-method "1.2.7"
|
||||||
web3-utils "1.2.8"
|
web3-utils "1.2.7"
|
||||||
|
|
||||||
web3-provider-engine@14.0.6:
|
web3-provider-engine@14.0.6:
|
||||||
version "14.0.6"
|
version "14.0.6"
|
||||||
@ -21037,12 +20951,12 @@ web3-providers-http@1.2.4:
|
|||||||
web3-core-helpers "1.2.4"
|
web3-core-helpers "1.2.4"
|
||||||
xhr2-cookies "1.1.0"
|
xhr2-cookies "1.1.0"
|
||||||
|
|
||||||
web3-providers-http@1.2.8:
|
web3-providers-http@1.2.7:
|
||||||
version "1.2.8"
|
version "1.2.7"
|
||||||
resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.2.8.tgz#cd7fc4d49df6980b5dd0fb1b5a808bc4b6a0069d"
|
resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.2.7.tgz#31eb15390c103169b3d7d31bdb1ccae9e3f1629d"
|
||||||
integrity sha512-Esj4SpgabmBDOR4QD3qYapzwFYWHigcdgdjvt/VWT5/7TD10o52hr+Nsvp3/XV5AFrcCMdY+lzKFLVH24u0sww==
|
integrity sha512-vazGx5onuH/zogrwkUaLFJwFcJ6CckP65VFSHoiV+GTQdkOqgoDIha7StKkslvDz4XJ2FuY/zOZHbtuOYeltXQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
web3-core-helpers "1.2.8"
|
web3-core-helpers "1.2.7"
|
||||||
xhr2-cookies "1.1.0"
|
xhr2-cookies "1.1.0"
|
||||||
|
|
||||||
web3-providers-ipc@1.0.0-beta.30:
|
web3-providers-ipc@1.0.0-beta.30:
|
||||||
@ -21072,14 +20986,14 @@ web3-providers-ipc@1.2.4:
|
|||||||
underscore "1.9.1"
|
underscore "1.9.1"
|
||||||
web3-core-helpers "1.2.4"
|
web3-core-helpers "1.2.4"
|
||||||
|
|
||||||
web3-providers-ipc@1.2.8:
|
web3-providers-ipc@1.2.7:
|
||||||
version "1.2.8"
|
version "1.2.7"
|
||||||
resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.2.8.tgz#47be918ddd077999aa14703169b76c807f45d894"
|
resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.2.7.tgz#4e6716e8723d431df3d6bfa1acd2f7c04e7071ad"
|
||||||
integrity sha512-ts3/UXCTRADPASdJ27vBVmcfM+lfG9QVBxGedY6+oNIo5EPxBUtsz94R32sfvFd6ofPsz6gOhK/M/ZKiJoi1sg==
|
integrity sha512-/zc0y724H2zbkV4UbGGMhsEiLfafjagIzfrsWZnyTZUlSB0OGRmmFm2EkLJAgtXrLiodaHHyXKM0vB8S24bxdA==
|
||||||
dependencies:
|
dependencies:
|
||||||
oboe "2.1.4"
|
oboe "2.1.4"
|
||||||
underscore "1.9.1"
|
underscore "1.9.1"
|
||||||
web3-core-helpers "1.2.8"
|
web3-core-helpers "1.2.7"
|
||||||
|
|
||||||
web3-providers-ws@1.0.0-beta.30:
|
web3-providers-ws@1.0.0-beta.30:
|
||||||
version "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"
|
underscore "1.9.1"
|
||||||
web3-core-helpers "1.2.4"
|
web3-core-helpers "1.2.4"
|
||||||
|
|
||||||
web3-providers-ws@1.2.8:
|
web3-providers-ws@1.2.7:
|
||||||
version "1.2.8"
|
version "1.2.7"
|
||||||
resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.2.8.tgz#9e6454edc82d753d398c8d1e044632c234434a46"
|
resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.2.7.tgz#95b1cc5dc25e9b9d6630d6754f9354313b62f532"
|
||||||
integrity sha512-Gcm0n82wd/XVeGFGTx+v56UqyrV9EyB2r1QFaBx4mS+VHbW2MCOdiRbNDfoZQslflnCWl8oHsivJ8Tya9kqlTQ==
|
integrity sha512-b5XzqDpRkNVe6MFs5K6iqOEyjQikHtg3KuU2/ClCDV37hm0WN4xCRVMC0LwegulbDXZej3zT9+1CYzGaGFREzA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@web3-js/websocket" "^1.0.29"
|
"@web3-js/websocket" "^1.0.29"
|
||||||
eventemitter3 "^4.0.0"
|
eventemitter3 "^4.0.0"
|
||||||
underscore "1.9.1"
|
underscore "1.9.1"
|
||||||
web3-core-helpers "1.2.8"
|
web3-core-helpers "1.2.7"
|
||||||
|
|
||||||
web3-shh@1.0.0-beta.30:
|
web3-shh@1.0.0-beta.30:
|
||||||
version "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-core-subscriptions "1.2.4"
|
||||||
web3-net "1.2.4"
|
web3-net "1.2.4"
|
||||||
|
|
||||||
web3-shh@1.2.8:
|
web3-shh@1.2.7:
|
||||||
version "1.2.8"
|
version "1.2.7"
|
||||||
resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.2.8.tgz#5162d9d13bc6838d390df1cd39e5f87235c1c2ae"
|
resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.2.7.tgz#5382c7bc2f39539eb2841c4576d23ade25720461"
|
||||||
integrity sha512-e29qKSfuZWDmxCG/uB48Nth6DCFFr2h2U+uI/fHEuhEjAEkBHopPNLc3ixrCTc6pqMocfJRPHJq/yET9PYN3oQ==
|
integrity sha512-f6PAgcpG0ZAo98KqCmeHoDEx5qzm3d5plet18DkT4U6WIeYowKdec8vZaLPRR7c2XreXFJ2gQf45CB7oqR7U/w==
|
||||||
dependencies:
|
dependencies:
|
||||||
web3-core "1.2.8"
|
web3-core "1.2.7"
|
||||||
web3-core-method "1.2.8"
|
web3-core-method "1.2.7"
|
||||||
web3-core-subscriptions "1.2.8"
|
web3-core-subscriptions "1.2.7"
|
||||||
web3-net "1.2.8"
|
web3-net "1.2.7"
|
||||||
|
|
||||||
web3-utils@1.0.0-beta.30:
|
web3-utils@1.0.0-beta.30:
|
||||||
version "1.0.0-beta.30"
|
version "1.0.0-beta.30"
|
||||||
@ -21212,10 +21126,10 @@ web3-utils@1.2.6:
|
|||||||
underscore "1.9.1"
|
underscore "1.9.1"
|
||||||
utf8 "3.0.0"
|
utf8 "3.0.0"
|
||||||
|
|
||||||
web3-utils@1.2.8:
|
web3-utils@1.2.7:
|
||||||
version "1.2.8"
|
version "1.2.7"
|
||||||
resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.2.8.tgz#5321d91715cd4c0869005705a33c4c042a532b18"
|
resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.2.7.tgz#b68e232917e4376f81cf38ef79878e5903d18e93"
|
||||||
integrity sha512-9SIVGFLajwlmo5joC4DGxuy2OeDkRCXVWT8JWcDQ+BayNVHyAWGvn0oGkQ0ys14Un0KK6bjjKoD0xYs4k+FaVw==
|
integrity sha512-FBh/CPJND+eiPeUF9KVbTyTZtXNWxPWtByBaWS6e2x4ACazPX711EeNaZaChIOGSLGe6se2n7kg6wnawe/MjuQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
bn.js "4.11.8"
|
bn.js "4.11.8"
|
||||||
eth-lib "0.2.7"
|
eth-lib "0.2.7"
|
||||||
@ -21266,18 +21180,18 @@ web3@1.2.4:
|
|||||||
web3-shh "1.2.4"
|
web3-shh "1.2.4"
|
||||||
web3-utils "1.2.4"
|
web3-utils "1.2.4"
|
||||||
|
|
||||||
web3@^1.2.8:
|
web3@1.2.7:
|
||||||
version "1.2.8"
|
version "1.2.7"
|
||||||
resolved "https://registry.yarnpkg.com/web3/-/web3-1.2.8.tgz#20b24baa769e0224a708ef5bf196a5b83d19540b"
|
resolved "https://registry.yarnpkg.com/web3/-/web3-1.2.7.tgz#fcb83571036c1c6f475bc984785982a444e8d78e"
|
||||||
integrity sha512-rXUn16VKxn2aIe9v0KX+bSm2JXdq/Vnj3lZ0Rub2Q5YUSycHdCBaDtJRukl/jB5ygAdyr5/cUwvJzhNDJSYsGw==
|
integrity sha512-jAAJHMfUlTps+jH2li1ckDFEpPrEEriU/ubegSTGRl3KRdNhEqT93+3kd7FHJTn3NgjcyURo2+f7Da1YcZL8Mw==
|
||||||
dependencies:
|
dependencies:
|
||||||
web3-bzz "1.2.8"
|
web3-bzz "1.2.7"
|
||||||
web3-core "1.2.8"
|
web3-core "1.2.7"
|
||||||
web3-eth "1.2.8"
|
web3-eth "1.2.7"
|
||||||
web3-eth-personal "1.2.8"
|
web3-eth-personal "1.2.7"
|
||||||
web3-net "1.2.8"
|
web3-net "1.2.7"
|
||||||
web3-shh "1.2.8"
|
web3-shh "1.2.7"
|
||||||
web3-utils "1.2.8"
|
web3-utils "1.2.7"
|
||||||
|
|
||||||
webidl-conversions@^4.0.2:
|
webidl-conversions@^4.0.2:
|
||||||
version "4.0.2"
|
version "4.0.2"
|
||||||
|
Loading…
Reference in New Issue
Block a user