From bcdf691000c3eaa1f4a656641a2369377e356298 Mon Sep 17 00:00:00 2001
From: Gerardo Nardelli
Date: Tue, 9 Jun 2020 10:37:43 -0300
Subject: [PATCH 01/13] Add Alm project structure and transaction form (#353)
---
alm/.env.example | 6 +
alm/package.json | 10 +-
alm/public/index.html | 3 +-
alm/public/logo192.png | Bin 5347 -> 0 bytes
alm/public/logo512.png | Bin 9664 -> 0 bytes
alm/public/manifest.json | 14 +-
alm/src/App.css | 14 -
alm/src/App.tsx | 11 +-
alm/src/components/Form.tsx | 90 +++
alm/src/components/MainPage.tsx | 48 ++
alm/src/components/MessageSelector.tsx | 46 ++
alm/src/components/StatusContainer.tsx | 76 +++
alm/src/components/commons/Button.tsx | 5 +
alm/src/components/commons/ExplorerTxLink.tsx | 6 +
alm/src/components/commons/Loading.tsx | 153 +++++
alm/src/components/commons/RadioButton.tsx | 9 +
alm/src/config/constants.ts | 19 +
alm/src/config/descriptions.ts | 8 +
alm/src/global.d.ts | 1 +
alm/src/hooks/useNetwork.ts | 27 +
alm/src/hooks/useTransactionStatus.ts | 99 +++
alm/src/index.css | 8 -
alm/src/index.tsx | 9 +-
alm/src/state/StateProvider.tsx | 67 ++
alm/src/themes/Dark.tsx | 9 +
alm/src/themes/GlobalStyle.tsx | 25 +
alm/src/utils/networks.ts | 32 +
alm/src/utils/web3.ts | 36 +
ui/package.json | 4 +-
yarn.lock | 645 +++++++++++++++++-
30 files changed, 1400 insertions(+), 80 deletions(-)
delete mode 100644 alm/public/logo192.png
delete mode 100644 alm/public/logo512.png
delete mode 100644 alm/src/App.css
create mode 100644 alm/src/components/Form.tsx
create mode 100644 alm/src/components/MainPage.tsx
create mode 100644 alm/src/components/MessageSelector.tsx
create mode 100644 alm/src/components/StatusContainer.tsx
create mode 100644 alm/src/components/commons/Button.tsx
create mode 100644 alm/src/components/commons/ExplorerTxLink.tsx
create mode 100644 alm/src/components/commons/Loading.tsx
create mode 100644 alm/src/components/commons/RadioButton.tsx
create mode 100644 alm/src/config/constants.ts
create mode 100644 alm/src/config/descriptions.ts
create mode 100644 alm/src/global.d.ts
create mode 100644 alm/src/hooks/useNetwork.ts
create mode 100644 alm/src/hooks/useTransactionStatus.ts
delete mode 100644 alm/src/index.css
create mode 100644 alm/src/state/StateProvider.tsx
create mode 100644 alm/src/themes/Dark.tsx
create mode 100644 alm/src/themes/GlobalStyle.tsx
create mode 100644 alm/src/utils/networks.ts
create mode 100644 alm/src/utils/web3.ts
diff --git a/alm/.env.example b/alm/.env.example
index 36568a102..1fb92664e 100644
--- a/alm/.env.example
+++ b/alm/.env.example
@@ -3,3 +3,9 @@ COMMON_FOREIGN_BRIDGE_ADDRESS=0xFe446bEF1DbF7AFE24E81e05BC8B271C1BA9a560
COMMON_HOME_RPC_URL=https://sokol.poa.network
COMMON_FOREIGN_RPC_URL=https://kovan.infura.io/v3/
+
+ALM_HOME_NETWORK_NAME=Sokol Testnet
+ALM_FOREIGN_NETWORK_NAME=Kovan Testnet
+
+ALM_HOME_EXPLORER_TX_TEMPLATE=https://blockscout.com/poa/sokol/tx/%s
+ALM_FOREIGN_EXPLORER_TX_TEMPLATE=https://blockscout.com/eth/kovan/tx/%s
diff --git a/alm/package.json b/alm/package.json
index 784ca2193..2c8cc44db 100644
--- a/alm/package.json
+++ b/alm/package.json
@@ -3,6 +3,7 @@
"version": "0.1.0",
"private": true,
"dependencies": {
+ "@react-hook/window-size": "^3.0.6",
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2",
@@ -10,12 +11,19 @@
"@types/node": "^12.0.0",
"@types/react": "^16.9.0",
"@types/react-dom": "^16.9.0",
+ "@types/react-router-dom": "^5.1.5",
+ "@types/styled-components": "^5.1.0",
"customize-cra": "^1.0.0",
+ "date-fns": "^2.14.0",
+ "fast-memoize": "^2.5.2",
"react": "^16.13.1",
"react-app-rewired": "^2.1.6",
"react-dom": "^16.13.1",
+ "react-router-dom": "^5.2.0",
"react-scripts": "3.0.1",
- "typescript": "^3.5.2"
+ "styled-components": "^5.1.1",
+ "typescript": "^3.5.2",
+ "web3": "^1.2.8"
},
"scripts": {
"start": "./load-env.sh react-app-rewired start",
diff --git a/alm/public/index.html b/alm/public/index.html
index aa069f27c..bc20b244c 100644
--- a/alm/public/index.html
+++ b/alm/public/index.html
@@ -7,8 +7,9 @@
+
- React App
+ AMB Live Monitoring
diff --git a/alm/src/App.test.tsx b/alm/src/App.test.tsx
index a2949045e..fe49a358e 100644
--- a/alm/src/App.test.tsx
+++ b/alm/src/App.test.tsx
@@ -1,9 +1,5 @@
import React from 'react'
-import { render } from '@testing-library/react'
-import App from './App'
test('renders learn react link', () => {
- const { getByText } = render()
- const linkElement = getByText(/AMB Live Monitoring/i)
- expect(linkElement).toBeInTheDocument()
+ // Removed basic test from setup. Keeping this so CI passes until we add unit tests.
})
diff --git a/alm/src/components/ConfirmationsContainer.tsx b/alm/src/components/ConfirmationsContainer.tsx
new file mode 100644
index 000000000..3fcee5a2f
--- /dev/null
+++ b/alm/src/components/ConfirmationsContainer.tsx
@@ -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
+ 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 (
+
+
+
+ Status:
+
+ {status !== CONFIRMATIONS_STATUS.UNDEFINED ? CONFIRMATIONS_STATUS_LABEL[status] : }
+
+
+
+
+ {status !== CONFIRMATIONS_STATUS.UNDEFINED
+ ? getConfirmationsStatusDescription(status, homeName, foreignName)
+ : ''}
+
+
+
+ {signatureCollected && }
+
+
+ )
+}
diff --git a/alm/src/components/ExecutionConfirmation.tsx b/alm/src/components/ExecutionConfirmation.tsx
new file mode 100644
index 000000000..755e6c99e
--- /dev/null
+++ b/alm/src/components/ExecutionConfirmation.tsx
@@ -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 {validatorStatus}
+ case VALIDATOR_CONFIRMATION_STATUS.WAITING:
+ return {validatorStatus}
+ default:
+ return
+ }
+ }
+
+ return (
+
+
+
+
+ Executed by |
+ Status |
+ Age |
+
+
+
+
+ {formattedValidator ? formattedValidator : } |
+ {getExecutionStatusElement(executionData.status)} |
+
+
+ {executionData.timestamp > 0 ? formatTimestamp(executionData.timestamp) : ''}
+
+ |
+
+
+
+
+ )
+}
diff --git a/alm/src/components/Form.tsx b/alm/src/components/Form.tsx
index 7f8e2ab73..9576c1c3f 100644
--- a/alm/src/components/Form.tsx
+++ b/alm/src/components/Form.tsx
@@ -14,6 +14,7 @@ const LabelText = styled.label`
const Input = styled.input`
background-color: var(--color-primary);
color: var(--font-color);
+ max-width: 100%;
`
export const Form = ({ onSubmit }: { onSubmit: ({ chainId, txHash }: FormSubmitParams) => void }) => {
diff --git a/alm/src/components/MainPage.tsx b/alm/src/components/MainPage.tsx
index 21fcfae5f..9eeec8361 100644
--- a/alm/src/components/MainPage.tsx
+++ b/alm/src/components/MainPage.tsx
@@ -1,6 +1,6 @@
import React from 'react'
import styled from 'styled-components'
-import { Route, useHistory } from 'react-router-dom'
+import { Route, useHistory, Link } from 'react-router-dom'
import { Form } from './Form'
import { StatusContainer } from './StatusContainer'
import { StateProvider } from '../state/StateProvider'
@@ -18,6 +18,10 @@ const Header = styled.header`
font-size: calc(10px + 2vmin);
`
+const Title = styled.p`
+ color: var(--font-color);
+`
+
export interface FormSubmitParams {
chainId: number
txHash: string
@@ -33,13 +37,12 @@ export const MainPage = () => {
- AMB Live Monitoring
+
+ AMB Live Monitoring
+
- }
- />
+ } />
} />
diff --git a/alm/src/components/MessageSelector.tsx b/alm/src/components/MessageSelector.tsx
index 1e192f6b5..32aaa3eca 100644
--- a/alm/src/components/MessageSelector.tsx
+++ b/alm/src/components/MessageSelector.tsx
@@ -3,9 +3,10 @@ import { Button } from './commons/Button'
import { RadioButtonLabel, RadioButtonContainer } from './commons/RadioButton'
import { useWindowWidth } from '@react-hook/window-size'
import { formatTxHashExtended } from '../utils/networks'
+import { MessageObject } from '../utils/web3'
export interface MessageSelectorParams {
- messages: Array
+ messages: Array
onMessageSelected: (index: number) => void
}
@@ -31,7 +32,7 @@ export const MessageSelector = ({ messages, onMessageSelected }: MessageSelector
onChange={() => setMessageIndex(i)}
/>
- {windowWidth < 700 ? formatTxHashExtended(message) : message}
+ {windowWidth < 700 ? formatTxHashExtended(message.id) : message.id}
))}
diff --git a/alm/src/components/StatusContainer.tsx b/alm/src/components/StatusContainer.tsx
index 4491f6c7d..6d9591199 100644
--- a/alm/src/components/StatusContainer.tsx
+++ b/alm/src/components/StatusContainer.tsx
@@ -7,6 +7,7 @@ import { MessageSelector } from './MessageSelector'
import { Loading } from './commons/Loading'
import { useStateProvider } from '../state/StateProvider'
import { ExplorerTxLink } from './commons/ExplorerTxLink'
+import { ConfirmationsContainer } from './ConfirmationsContainer'
export const StatusContainer = () => {
const { home, foreign } = useStateProvider()
@@ -15,15 +16,14 @@ export const StatusContainer = () => {
const validChainId = chainId === home.chainId.toString() || chainId === foreign.chainId.toString()
const validParameters = validChainId && validTxHash(txHash)
- const { messagesId, status, description, timestamp, loading } = useTransactionStatus({
+ const { messages, receipt, status, description, timestamp, loading } = useTransactionStatus({
txHash: validParameters ? txHash : '',
chainId: validParameters ? parseInt(chainId) : 0
})
- const selectedMessageId =
- messageIdParam === undefined || messagesId[messageIdParam] === undefined ? -1 : messageIdParam
+ const selectedMessageId = messageIdParam === undefined || messages[messageIdParam] === undefined ? -1 : messageIdParam
- if (!validParameters) {
+ if (!validParameters && home.chainId && foreign.chainId) {
return (
@@ -43,7 +43,7 @@ export const StatusContainer = () => {
const displayMessageSelector = status === TRANSACTION_STATUS.SUCCESS_MULTIPLE_MESSAGES && selectedMessageId === -1
const multiMessageSelected = status === TRANSACTION_STATUS.SUCCESS_MULTIPLE_MESSAGES && selectedMessageId !== -1
- const displayReference = multiMessageSelected ? messagesId[selectedMessageId] : txHash
+ const displayReference = multiMessageSelected ? messages[selectedMessageId].id : txHash
const formattedMessageId = formatTxHash(displayReference)
const displayedDescription = multiMessageSelected
@@ -54,6 +54,9 @@ export const StatusContainer = () => {
const txExplorerLink = getExplorerTxUrl(txHash, isHome)
const displayExplorerLink = status !== TRANSACTION_STATUS.NOT_FOUND
+ const displayConfirmations = status === TRANSACTION_STATUS.SUCCESS_ONE_MESSAGE || multiMessageSelected
+ const messageToConfirm =
+ messages.length > 1 ? messages[selectedMessageId] : messages.length > 0 ? messages[0] : { id: '', data: '' }
return (
{status && (
@@ -70,7 +73,10 @@ export const StatusContainer = () => {
{displayedDescription}
)}
- {displayMessageSelector && }
+ {displayMessageSelector && }
+ {displayConfirmations && (
+
+ )}
)
}
diff --git a/alm/src/components/ValidatorsConfirmations.tsx b/alm/src/components/ValidatorsConfirmations.tsx
new file mode 100644
index 000000000..4bff387d4
--- /dev/null
+++ b/alm/src/components/ValidatorsConfirmations.tsx
@@ -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
+}
+
+export const ValidatorsConfirmations = ({ confirmations }: ValidatorsConfirmationsParams) => {
+ const {
+ home: { requiredSignatures, validatorList }
+ } = useStateProvider()
+ const windowWidth = useWindowWidth()
+
+ const getValidatorStatusElement = (validatorStatus = '') => {
+ switch (validatorStatus) {
+ case VALIDATOR_CONFIRMATION_STATUS.SUCCESS:
+ return {validatorStatus}
+ case VALIDATOR_CONFIRMATION_STATUS.WAITING:
+ case VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED:
+ return {validatorStatus}
+ default:
+ return
+ }
+ }
+
+ return (
+
+
+
+
+ Validator |
+ Confirmations |
+
+
+
+ {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 (
+
+ {windowWidth < 850 ? formatTxHashExtended(validator) : validator} |
+ {getValidatorStatusElement(displayedStatus)} |
+
+ )
+ })}
+
+
+
+ {requiredSignatures} of {validatorList.length} confirmations required
+
+
+ )
+}
diff --git a/alm/src/components/commons/Labels.tsx b/alm/src/components/commons/Labels.tsx
new file mode 100644
index 000000000..282031220
--- /dev/null
+++ b/alm/src/components/commons/Labels.tsx
@@ -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;
+`
diff --git a/alm/src/components/commons/Loading.tsx b/alm/src/components/commons/Loading.tsx
index def8626db..8519ede21 100644
--- a/alm/src/components/commons/Loading.tsx
+++ b/alm/src/components/commons/Loading.tsx
@@ -1,12 +1,18 @@
import React from 'react'
-export const Loading = () => (
+export interface LoadingParams {
+ width?: string
+ height?: string
+ displayMessage?: boolean
+}
+
+export const Loading = ({ width = '50px', height = '50px', displayMessage = true }: LoadingParams) => (
-
+ {displayMessage && }
)
+
+export const SimpleLoading = () =>
diff --git a/alm/src/config/constants.ts b/alm/src/config/constants.ts
index 88df9ba2b..fef4e53c2 100644
--- a/alm/src/config/constants.ts
+++ b/alm/src/config/constants.ts
@@ -10,6 +10,10 @@ export const FOREIGN_NETWORK_NAME: string = process.env.REACT_APP_ALM_FOREIGN_NE
export const HOME_EXPLORER_TX_TEMPLATE: string = process.env.REACT_APP_ALM_HOME_EXPLORER_TX_TEMPLATE || ''
export const FOREIGN_EXPLORER_TX_TEMPLATE: string = process.env.REACT_APP_ALM_FOREIGN_EXPLORER_TX_TEMPLATE || ''
+export const HOME_RPC_POLLING_INTERVAL: number = 5000
+export const FOREIGN_RPC_POLLING_INTERVAL: number = 15000
+export const BLOCK_RANGE: number = 50
+
export const TRANSACTION_STATUS = {
SUCCESS_MULTIPLE_MESSAGES: 'SUCCESS_MULTIPLE_MESSAGES',
SUCCESS_ONE_MESSAGE: 'SUCCESS_ONE_MESSAGE',
@@ -17,3 +21,24 @@ export const TRANSACTION_STATUS = {
FAILED: 'FAILED',
NOT_FOUND: 'NOT_FOUND'
}
+
+export const CONFIRMATIONS_STATUS = {
+ SUCCESS: 'SUCCESS',
+ SUCCESS_MESSAGE_FAILED: 'SUCCESS_MESSAGE_FAILED',
+ EXECUTION_FAILED: 'EXECUTION_FAILED',
+ EXECUTION_PENDING: 'EXECUTION_PENDING',
+ EXECUTION_WAITING: 'EXECUTION_WAITING',
+ FAILED: 'FAILED',
+ PENDING: 'PENDING',
+ WAITING: 'WAITING',
+ UNDEFINED: 'UNDEFINED'
+}
+
+export const VALIDATOR_CONFIRMATION_STATUS = {
+ SUCCESS: 'Success',
+ FAILED: 'Failed',
+ PENDING: 'Pending',
+ WAITING: 'Waiting',
+ NOT_REQUIRED: 'Not required',
+ UNDEFINED: 'UNDEFINED'
+}
diff --git a/alm/src/config/descriptions.ts b/alm/src/config/descriptions.ts
index b28906fe0..fb395555a 100644
--- a/alm/src/config/descriptions.ts
+++ b/alm/src/config/descriptions.ts
@@ -6,3 +6,31 @@ export const TRANSACTION_STATUS_DESCRIPTION: { [key: string]: string } = {
FAILED: 'failed %t',
NOT_FOUND: 'was not found'
}
+
+export const CONFIRMATIONS_STATUS_LABEL: { [key: string]: string } = {
+ SUCCESS: 'Success',
+ SUCCESS_MESSAGE_FAILED: 'Success',
+ EXECUTION_FAILED: 'Execution failed',
+ EXECUTION_PENDING: 'Execution pending',
+ EXECUTION_WAITING: 'Execution waiting',
+ FAILED: 'Failed',
+ PENDING: 'Pending',
+ WAITING: 'Waiting'
+}
+
+// %homeChain will be replaced by the home network name
+// %foreignChain will be replaced by the foreign network name
+export const CONFIRMATIONS_STATUS_DESCRIPTION: { [key: string]: string } = {
+ SUCCESS: '',
+ SUCCESS_MESSAGE_FAILED:
+ 'Signatures have been collected in the %homeChain and they were successfully sent to the %foreignChain but the contained message execution failed.',
+ EXECUTION_FAILED:
+ 'Signatures have been collected in the %homeChain and they were sent to the %foreignChain but the transaction with signatures failed',
+ EXECUTION_PENDING:
+ 'Signatures have been collected in the %homeChain and they were sent to the %foreignChain but the transaction is in the pending state (transactions congestion or low gas price)',
+ EXECUTION_WAITING: 'Execution waiting',
+ FAILED:
+ 'Some validators sent improper transactions as so they were failed, collected confirmations are not enough to execute the relay request',
+ PENDING: 'Some confirmations are in pending state',
+ WAITING: 'Validators are waiting for the chain finalization'
+}
diff --git a/alm/src/hooks/useBridgeContracts.ts b/alm/src/hooks/useBridgeContracts.ts
new file mode 100644
index 000000000..4e253eec7
--- /dev/null
+++ b/alm/src/hooks/useBridgeContracts.ts
@@ -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>(null)
+ const [foreignBridge, setForeignBridge] = useState>(null)
+ const [homeBlockConfirmations, setHomeBlockConfirmations] = useState(0)
+ const [foreignBlockConfirmations, setForeignBlockConfirmations] = useState(0)
+ const [homeValidatorContract, setHomeValidatorContract] = useState>(null)
+ const [homeRequiredSignatures, setHomeRequiredSignatures] = useState(0)
+ const [homeValidatorList, setHomeValidatorList] = useState([])
+
+ const callRequireBlockConfirmations = async (contract: Maybe, setResult: Function) => {
+ if (!contract) return
+ const result = await getRequiredBlockConfirmations(contract)
+ setResult(result)
+ }
+
+ const callValidatorContract = async (bridgeContract: Maybe, 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, setResult: Function) => {
+ if (!contract) return
+ const result = await getRequiredSignatures(contract)
+ setResult(result)
+ }
+
+ const callValidatorList = async (contract: Maybe, 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
+ }
+}
diff --git a/alm/src/hooks/useMessageConfirmations.ts b/alm/src/hooks/useMessageConfirmations.ts
new file mode 100644
index 000000000..4615b15b1
--- /dev/null
+++ b/alm/src/hooks/useMessageConfirmations.ts
@@ -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
+ 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>([])
+ 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>(null)
+ const [executionData, setExecutionData] = useState({
+ 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 = []
+
+ 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 = []
+
+ 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 = []
+
+ 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 = []
+
+ 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 = []
+
+ 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
+ }
+}
diff --git a/alm/src/hooks/useTransactionStatus.ts b/alm/src/hooks/useTransactionStatus.ts
index 0a70b1d43..9a981744c 100644
--- a/alm/src/hooks/useTransactionStatus.ts
+++ b/alm/src/hooks/useTransactionStatus.ts
@@ -1,13 +1,13 @@
import { useEffect, useState } from 'react'
import { TransactionReceipt } from 'web3-eth'
-import { TRANSACTION_STATUS } from '../config/constants'
+import { HOME_RPC_POLLING_INTERVAL, TRANSACTION_STATUS } from '../config/constants'
import { getTransactionStatusDescription } from '../utils/networks'
import { useStateProvider } from '../state/StateProvider'
-import { getHomeMessagesFromReceipt, getForeignMessagesFromReceipt } from '../utils/web3'
+import { getHomeMessagesFromReceipt, getForeignMessagesFromReceipt, MessageObject } from '../utils/web3'
export const useTransactionStatus = ({ txHash, chainId }: { txHash: string; chainId: number }) => {
const { home, foreign } = useStateProvider()
- const [messagesId, setMessagesId] = useState>([])
+ const [messages, setMessages] = useState>([])
const [status, setStatus] = useState('')
const [description, setDescription] = useState('')
const [receipt, setReceipt] = useState>(null)
@@ -36,8 +36,8 @@ export const useTransactionStatus = ({ txHash, chainId }: { txHash: string; chai
if (!txReceipt) {
setStatus(TRANSACTION_STATUS.NOT_FOUND)
setDescription(getTransactionStatusDescription(TRANSACTION_STATUS.NOT_FOUND))
- setMessagesId([txHash])
- const timeoutId = setTimeout(() => getReceipt(), 5000)
+ setMessages([{ id: txHash, data: '' }])
+ const timeoutId = setTimeout(() => getReceipt(), HOME_RPC_POLLING_INTERVAL)
subscriptions.push(timeoutId)
} else {
const blockNumber = txReceipt.blockNumber
@@ -46,23 +46,23 @@ export const useTransactionStatus = ({ txHash, chainId }: { txHash: string; chai
setTimestamp(blockTimestamp)
if (txReceipt.status) {
- let bridgeMessagesId
+ let bridgeMessages: Array
if (isHome) {
- bridgeMessagesId = getHomeMessagesFromReceipt(txReceipt, home.web3, home.bridgeAddress)
+ bridgeMessages = getHomeMessagesFromReceipt(txReceipt, home.web3, home.bridgeAddress)
} else {
- bridgeMessagesId = getForeignMessagesFromReceipt(txReceipt, foreign.web3, foreign.bridgeAddress)
+ bridgeMessages = getForeignMessagesFromReceipt(txReceipt, foreign.web3, foreign.bridgeAddress)
}
- if (bridgeMessagesId.length === 0) {
- setMessagesId([txHash])
+ if (bridgeMessages.length === 0) {
+ setMessages([{ id: txHash, data: '' }])
setStatus(TRANSACTION_STATUS.SUCCESS_NO_MESSAGES)
setDescription(getTransactionStatusDescription(TRANSACTION_STATUS.SUCCESS_NO_MESSAGES, blockTimestamp))
- } else if (bridgeMessagesId.length === 1) {
- setMessagesId(bridgeMessagesId)
+ } else if (bridgeMessages.length === 1) {
+ setMessages(bridgeMessages)
setStatus(TRANSACTION_STATUS.SUCCESS_ONE_MESSAGE)
setDescription(getTransactionStatusDescription(TRANSACTION_STATUS.SUCCESS_ONE_MESSAGE, blockTimestamp))
} else {
- setMessagesId(bridgeMessagesId)
+ setMessages(bridgeMessages)
setStatus(TRANSACTION_STATUS.SUCCESS_MULTIPLE_MESSAGES)
setDescription(
getTransactionStatusDescription(TRANSACTION_STATUS.SUCCESS_MULTIPLE_MESSAGES, blockTimestamp)
@@ -89,7 +89,7 @@ export const useTransactionStatus = ({ txHash, chainId }: { txHash: string; chai
)
return {
- messagesId,
+ messages,
status,
description,
receipt,
diff --git a/alm/src/services/BlockNumberProvider.ts b/alm/src/services/BlockNumberProvider.ts
new file mode 100644
index 000000000..a6606c87d
--- /dev/null
+++ b/alm/src/services/BlockNumberProvider.ts
@@ -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
+ private ref: number | undefined
+ private value: Maybe
+ private lastValueTimestamp: Maybe
+ 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) {
+ 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)
diff --git a/alm/src/services/ValidatorsCache.ts b/alm/src/services/ValidatorsCache.ts
new file mode 100644
index 000000000..a3406943e
--- /dev/null
+++ b/alm/src/services/ValidatorsCache.ts
@@ -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()
diff --git a/alm/src/state/StateProvider.tsx b/alm/src/state/StateProvider.tsx
index 54f3307b3..0c5172581 100644
--- a/alm/src/state/StateProvider.tsx
+++ b/alm/src/state/StateProvider.tsx
@@ -9,17 +9,27 @@ import {
FOREIGN_NETWORK_NAME
} from '../config/constants'
import Web3 from 'web3'
+import { useBridgeContracts } from '../hooks/useBridgeContracts'
+import { Contract } from 'web3-eth-contract'
-export interface NetworkParams {
+export interface BaseNetworkParams {
chainId: number
name: string
web3: Maybe
bridgeAddress: string
+ bridgeContract: Maybe
+ blockConfirmations: number
+}
+
+export interface HomeNetworkParams extends BaseNetworkParams {
+ validatorContract: Maybe
+ requiredSignatures: number
+ validatorList: Array
}
export interface StateContext {
- home: NetworkParams
- foreign: NetworkParams
+ home: HomeNetworkParams
+ foreign: BaseNetworkParams
loading: boolean
}
@@ -28,13 +38,20 @@ const initialState = {
chainId: 0,
name: '',
web3: null,
- bridgeAddress: HOME_BRIDGE_ADDRESS
+ bridgeAddress: HOME_BRIDGE_ADDRESS,
+ bridgeContract: null,
+ blockConfirmations: 0,
+ validatorContract: null,
+ requiredSignatures: 0,
+ validatorList: []
},
foreign: {
chainId: 0,
name: '',
web3: null,
- bridgeAddress: FOREIGN_BRIDGE_ADDRESS
+ bridgeAddress: FOREIGN_BRIDGE_ADDRESS,
+ bridgeContract: null,
+ blockConfirmations: 0
},
loading: true
}
@@ -44,16 +61,35 @@ const StateContext = createContext(initialState)
export const StateProvider = ({ children }: { children: ReactNode }) => {
const homeNetwork = useNetwork(HOME_RPC_URL)
const foreignNetwork = useNetwork(FOREIGN_RPC_URL)
+ const {
+ homeBridge,
+ foreignBridge,
+ homeBlockConfirmations,
+ foreignBlockConfirmations,
+ homeValidatorContract,
+ homeRequiredSignatures,
+ homeValidatorList
+ } = useBridgeContracts({
+ homeWeb3: homeNetwork.web3,
+ foreignWeb3: foreignNetwork.web3
+ })
const value = {
home: {
bridgeAddress: HOME_BRIDGE_ADDRESS,
name: HOME_NETWORK_NAME,
+ bridgeContract: homeBridge,
+ blockConfirmations: homeBlockConfirmations,
+ validatorContract: homeValidatorContract,
+ requiredSignatures: homeRequiredSignatures,
+ validatorList: homeValidatorList,
...homeNetwork
},
foreign: {
bridgeAddress: FOREIGN_BRIDGE_ADDRESS,
name: FOREIGN_NETWORK_NAME,
+ bridgeContract: foreignBridge,
+ blockConfirmations: foreignBlockConfirmations,
...foreignNetwork
},
loading: homeNetwork.loading || foreignNetwork.loading
diff --git a/alm/src/themes/Dark.tsx b/alm/src/themes/Dark.tsx
index 26797df93..07a4e0f46 100644
--- a/alm/src/themes/Dark.tsx
+++ b/alm/src/themes/Dark.tsx
@@ -4,6 +4,14 @@ const theme = {
colorPrimary: '#272727',
colorGrey: '#272727',
colorLightGrey: '#272727',
- linkColor: '#ffffff'
+ linkColor: '#ffffff',
+ success: {
+ textColor: '#00c9a7',
+ backgroundColor: '#004d40'
+ },
+ notRequired: {
+ textColor: '#bdbdbd',
+ backgroundColor: '#424242'
+ }
}
export default theme
diff --git a/alm/src/themes/GlobalStyle.tsx b/alm/src/themes/GlobalStyle.tsx
index 13f4e62f4..d10ea42d1 100644
--- a/alm/src/themes/GlobalStyle.tsx
+++ b/alm/src/themes/GlobalStyle.tsx
@@ -20,6 +20,10 @@ export const GlobalStyle = createGlobalStyle<{ theme: ThemeType }>`
--color-primary: ${props => props.theme.colorPrimary};
--color-grey: ${props => props.theme.colorGrey};
--color-lightGrey: ${props => props.theme.colorLightGrey};
- --link-color: ${props => props.theme.linkColor}
+ --link-color: ${props => props.theme.linkColor};
+ --success-color: ${props => props.theme.success.textColor};
+ --success-bg-color: ${props => props.theme.success.backgroundColor};
+ --not-required-color: ${props => props.theme.notRequired.textColor};
+ --not-required-bg-color: ${props => props.theme.notRequired.backgroundColor};
}
`
diff --git a/alm/src/utils/contract.ts b/alm/src/utils/contract.ts
new file mode 100644
index 000000000..278713d4c
--- /dev/null
+++ b/alm/src/utils/contract.ts
@@ -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()
diff --git a/alm/src/utils/executionWaitingForBlocks.ts b/alm/src/utils/executionWaitingForBlocks.ts
new file mode 100644
index 000000000..612284913
--- /dev/null
+++ b/alm/src/utils/executionWaitingForBlocks.ts
@@ -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)
+ }
+}
diff --git a/alm/src/utils/getCollectedSignaturesEvent.ts b/alm/src/utils/getCollectedSignaturesEvent.ts
new file mode 100644
index 000000000..312c1a5f8
--- /dev/null
+++ b/alm/src/utils/getCollectedSignaturesEvent.ts
@@ -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,
+ contract: Maybe,
+ 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)
+ }
+}
diff --git a/alm/src/utils/getConfirmationsForTx.ts b/alm/src/utils/getConfirmationsForTx.ts
new file mode 100644
index 000000000..e5b29097e
--- /dev/null
+++ b/alm/src/utils/getConfirmationsForTx.ts
@@ -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,
+ validatorList: string[],
+ bridgeContract: Maybe,
+ 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)
+}
diff --git a/alm/src/utils/getFinalizationEvent.ts b/alm/src/utils/getFinalizationEvent.ts
new file mode 100644
index 000000000..a391ebb5f
--- /dev/null
+++ b/alm/src/utils/getFinalizationEvent.ts
@@ -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,
+ eventName: string,
+ web3: Maybe,
+ setResult: React.Dispatch>,
+ 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)
+ }
+}
diff --git a/alm/src/utils/networks.ts b/alm/src/utils/networks.ts
index b74fdda51..2b58df767 100644
--- a/alm/src/utils/networks.ts
+++ b/alm/src/utils/networks.ts
@@ -1,5 +1,5 @@
import { formatDistance } from 'date-fns'
-import { TRANSACTION_STATUS_DESCRIPTION } from '../config/descriptions'
+import { CONFIRMATIONS_STATUS_DESCRIPTION, TRANSACTION_STATUS_DESCRIPTION } from '../config/descriptions'
import { FOREIGN_EXPLORER_TX_TEMPLATE, HOME_EXPLORER_TX_TEMPLATE } from '../config/constants'
export const validTxHash = (txHash: string) => /^0x[a-fA-F0-9]{64}$/.test(txHash)
@@ -30,3 +30,12 @@ export const getTransactionStatusDescription = (status: string, timestamp: Maybe
return description
}
+
+export const getConfirmationsStatusDescription = (status: string, home: string, foreign: string) => {
+ let description = CONFIRMATIONS_STATUS_DESCRIPTION[status]
+
+ description = description.replace('%homeChain', home)
+ description = description.replace('%foreignChain', foreign)
+
+ return description
+}
diff --git a/alm/src/utils/signatureWaitingForBlocks.ts b/alm/src/utils/signatureWaitingForBlocks.ts
new file mode 100644
index 000000000..74f768ff3
--- /dev/null
+++ b/alm/src/utils/signatureWaitingForBlocks.ts
@@ -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)
+ }
+}
diff --git a/alm/src/utils/web3.ts b/alm/src/utils/web3.ts
index ad9bdabd2..d35dd3648 100644
--- a/alm/src/utils/web3.ts
+++ b/alm/src/utils/web3.ts
@@ -4,6 +4,11 @@ import { AbiItem } from 'web3-utils'
import memoize from 'fast-memoize'
import { HOME_AMB_ABI, FOREIGN_AMB_ABI } from '../../../commons'
+export interface MessageObject {
+ id: string
+ data: string
+}
+
const rawGetWeb3 = (url: string) => new Web3(new Web3.providers.HttpProvider(url))
const memoized = memoize(rawGetWeb3)
@@ -14,11 +19,20 @@ export const filterEventsByAbi = (
web3: Web3,
bridgeAddress: string,
eventAbi: AbiItem
-) => {
+): MessageObject[] => {
const eventHash = web3.eth.abi.encodeEventSignature(eventAbi)
const events = txReceipt.logs.filter(e => e.address === bridgeAddress && e.topics[0] === eventHash)
- return events.map(e => e.topics[1])
+ return events.map(e => {
+ let decodedLogs: { [p: string]: string } = {
+ messageId: '',
+ encodedData: ''
+ }
+ if (eventAbi && eventAbi.inputs && eventAbi.inputs.length) {
+ decodedLogs = web3.eth.abi.decodeLog(eventAbi.inputs, e.data, [e.topics[1]])
+ }
+ return { id: decodedLogs.messageId, data: decodedLogs.encodedData }
+ })
}
export const getHomeMessagesFromReceipt = (txReceipt: TransactionReceipt, web3: Web3, bridgeAddress: string) => {
diff --git a/yarn.lock b/yarn.lock
index 21d23b325..b90bd96b8 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1304,21 +1304,6 @@
"@ethersproject/properties" ">=5.0.0-beta.131"
"@ethersproject/strings" ">=5.0.0-beta.130"
-"@ethersproject/abi@5.0.0-beta.153":
- version "5.0.0-beta.153"
- resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.0.0-beta.153.tgz#43a37172b33794e4562999f6e2d555b7599a8eee"
- integrity sha512-aXweZ1Z7vMNzJdLpR1CZUAIgnwjrZeUSvN9syCwlBaEBUFJmFY+HHnfuTI5vIhVs/mRkfJVrbEyl51JZQqyjAg==
- dependencies:
- "@ethersproject/address" ">=5.0.0-beta.128"
- "@ethersproject/bignumber" ">=5.0.0-beta.130"
- "@ethersproject/bytes" ">=5.0.0-beta.129"
- "@ethersproject/constants" ">=5.0.0-beta.128"
- "@ethersproject/hash" ">=5.0.0-beta.128"
- "@ethersproject/keccak256" ">=5.0.0-beta.127"
- "@ethersproject/logger" ">=5.0.0-beta.129"
- "@ethersproject/properties" ">=5.0.0-beta.131"
- "@ethersproject/strings" ">=5.0.0-beta.130"
-
"@ethersproject/address@>=5.0.0-beta.128":
version "5.0.0-beta.134"
resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.0.0-beta.134.tgz#9c1790c87b763dc547ac12e2dbc9fa78d0799a71"
@@ -4868,7 +4853,7 @@ balanced-match@^1.0.0:
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
-base-x@^3.0.2, base-x@^3.0.8:
+base-x@^3.0.2:
version "3.0.8"
resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.8.tgz#1e1106c2537f0162e8b52474a557ebb09000018d"
integrity sha512-Rl/1AWP4J/zRrk54hhlxH4drNxPJXYUaKffODVI53/dAsV4t9fBxyxYKAVPU1XBHxYwOWP9h9H0hM2MVw4YfJA==
@@ -5804,17 +5789,6 @@ ci-info@^2.0.0:
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46"
integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==
-cids@^0.7.1:
- version "0.7.5"
- resolved "https://registry.yarnpkg.com/cids/-/cids-0.7.5.tgz#60a08138a99bfb69b6be4ceb63bfef7a396b28b2"
- integrity sha512-zT7mPeghoWAu+ppn8+BS1tQ5qGmbMfB4AregnQjA/qHY3GC1m1ptI9GkWNlgeu38r7CuRdXB47uY2XgAYt6QVA==
- dependencies:
- buffer "^5.5.0"
- class-is "^1.1.0"
- multibase "~0.6.0"
- multicodec "^1.0.0"
- multihashes "~0.4.15"
-
cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
version "1.0.4"
resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de"
@@ -5823,11 +5797,6 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
inherits "^2.0.1"
safe-buffer "^5.0.1"
-class-is@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/class-is/-/class-is-1.1.0.tgz#9d3c0fba0440d211d843cec3dedfa48055005825"
- integrity sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw==
-
class-utils@^0.3.5:
version "0.3.6"
resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
@@ -6293,15 +6262,6 @@ content-disposition@0.5.3:
dependencies:
safe-buffer "5.1.2"
-content-hash@^2.5.2:
- version "2.5.2"
- resolved "https://registry.yarnpkg.com/content-hash/-/content-hash-2.5.2.tgz#bbc2655e7c21f14fd3bfc7b7d4bfe6e454c9e211"
- integrity sha512-FvIQKy0S1JaWV10sMsA7TRx8bpU+pqPkhbsfvOJAdjRXvYxEckAwQWGwtRjiaJfh+E0DvcWUGqcdjwMGFjsSdw==
- dependencies:
- cids "^0.7.1"
- multicodec "^0.5.5"
- multihashes "^0.4.15"
-
content-type@~1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
@@ -13821,22 +13781,6 @@ ms@^2.0.0:
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
-multibase@^0.7.0:
- version "0.7.0"
- resolved "https://registry.yarnpkg.com/multibase/-/multibase-0.7.0.tgz#1adfc1c50abe05eefeb5091ac0c2728d6b84581b"
- integrity sha512-TW8q03O0f6PNFTQDvh3xxH03c8CjGaaYrjkl9UQPG6rz53TQzzxJVCIWVjzcbN/Q5Y53Zd0IBQBMVktVgNx4Fg==
- dependencies:
- base-x "^3.0.8"
- buffer "^5.5.0"
-
-multibase@~0.6.0:
- version "0.6.1"
- resolved "https://registry.yarnpkg.com/multibase/-/multibase-0.6.1.tgz#b76df6298536cc17b9f6a6db53ec88f85f8cc12b"
- integrity sha512-pFfAwyTjbbQgNc3G7D48JkJxWtoJoBMaR4xQUOuB8RnCgRqaYmWNFeJTTvrJ2w51bjLq2zTby6Rqj9TQ9elSUw==
- dependencies:
- base-x "^3.0.8"
- buffer "^5.5.0"
-
multicast-dns-service-types@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901"
@@ -13850,30 +13794,6 @@ multicast-dns@^6.0.1:
dns-packet "^1.3.1"
thunky "^1.0.2"
-multicodec@^0.5.5:
- version "0.5.7"
- resolved "https://registry.yarnpkg.com/multicodec/-/multicodec-0.5.7.tgz#1fb3f9dd866a10a55d226e194abba2dcc1ee9ffd"
- integrity sha512-PscoRxm3f+88fAtELwUnZxGDkduE2HD9Q6GHUOywQLjOGT/HAdhjLDYNZ1e7VR0s0TP0EwZ16LNUTFpoBGivOA==
- dependencies:
- varint "^5.0.0"
-
-multicodec@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/multicodec/-/multicodec-1.0.1.tgz#4e2812d726b9f7c7d615d3ebc5787d36a08680f9"
- integrity sha512-yrrU/K8zHyAH2B0slNVeq3AiwluflHpgQ3TAzwNJcuO2AoPyXgBT2EDkdbP1D8B/yFOY+S2hDYmFlI1vhVFkQw==
- dependencies:
- buffer "^5.5.0"
- varint "^5.0.0"
-
-multihashes@^0.4.15, multihashes@~0.4.15:
- version "0.4.19"
- resolved "https://registry.yarnpkg.com/multihashes/-/multihashes-0.4.19.tgz#d7493cf028e48747122f350908ea13d12d204813"
- integrity sha512-ej74GAfA20imjj00RO5h34aY3pGUFyzn9FJZFWwdeUHlHTkKmv90FrNpvYT4jYf1XXCy5O/5EjVnxTaESgOM6A==
- dependencies:
- buffer "^5.5.0"
- multibase "^0.7.0"
- varint "^5.0.0"
-
multimatch@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-3.0.0.tgz#0e2534cc6bc238d9ab67e1b9cd5fcd85a6dbf70b"
@@ -20113,11 +20033,6 @@ value-or-function@^3.0.0:
resolved "https://registry.yarnpkg.com/value-or-function/-/value-or-function-3.0.0.tgz#1c243a50b595c1be54a754bfece8563b9ff8d813"
integrity sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM=
-varint@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/varint/-/varint-5.0.0.tgz#d826b89f7490732fabc0c0ed693ed475dcb29ebf"
- integrity sha1-2Ca4n3SQcy+rwMDtaT7Uddyynr8=
-
vary@^1, vary@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
@@ -20324,10 +20239,10 @@ web3-bzz@1.2.4:
swarm-js "0.1.39"
underscore "1.9.1"
-web3-bzz@1.2.8:
- version "1.2.8"
- resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.2.8.tgz#7ff2c2de362f82ae3825e48c70ec63b3aca2b8ef"
- integrity sha512-jbi24/s2tT7FYuN+ktRvTa5em0GxhqcIYQ8FnD3Zb/ZoEPi+/7rH0Hh+WDol0pSZL+wdz/iM+Z2C9NE42z6EmQ==
+web3-bzz@1.2.7:
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.2.7.tgz#aa0f3d162f0777a5f35367dc5b70012dd1e129d0"
+ integrity sha512-iTIWBR+Z+Bn09WprtKm46LmyNOasg2lUn++AjXkBTB8UNxlUybxtza84yl2ETTZUs0zuFzdSSAEgbjhygG+9oA==
dependencies:
"@types/node" "^10.12.18"
got "9.6.0"
@@ -20361,14 +20276,14 @@ web3-core-helpers@1.2.4:
web3-eth-iban "1.2.4"
web3-utils "1.2.4"
-web3-core-helpers@1.2.8:
- version "1.2.8"
- resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.2.8.tgz#86776d8f658b63bb630c84a314686661e599aa68"
- integrity sha512-Wrl7ZPKn3Xyg0Hl5+shDnJcLP+EtTfThmQ1eCJLcg/BZqvLUR1SkOslNlhEojcYeBwhhymAKs8dfQbtYi+HMnw==
+web3-core-helpers@1.2.7:
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.2.7.tgz#522f859775ea0d15e7e40359c46d4efc5da92aee"
+ integrity sha512-bdU++9QATGeCetVrMp8pV97aQtVkN5oLBf/TWu/qumC6jK/YqrvLlBJLdwbz0QveU8zOSap6GCvJbqKvmmbV2A==
dependencies:
underscore "1.9.1"
- web3-eth-iban "1.2.8"
- web3-utils "1.2.8"
+ web3-eth-iban "1.2.7"
+ web3-utils "1.2.7"
web3-core-method@1.0.0-beta.30:
version "1.0.0-beta.30"
@@ -20403,16 +20318,16 @@ web3-core-method@1.2.4:
web3-core-subscriptions "1.2.4"
web3-utils "1.2.4"
-web3-core-method@1.2.8:
- version "1.2.8"
- resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.2.8.tgz#f28a79935432aebfa019e4a50f9b6ae6c9ef4297"
- integrity sha512-69qbvOgx0Frw46dXvEKzYgtaPXpUaQAlQmczgb0ZUBHsEU2K7jTtFgBy6kVBgAwsXDvoZ99AX4SjpY2dTMwPkw==
+web3-core-method@1.2.7:
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.2.7.tgz#73fd80d2bf0765ff6efc454db49ac83d1769a45e"
+ integrity sha512-e1TI0QUnByDMbQ8QHwnjxfjKw0LIgVRY4TYrlPijET9ebqUJU1HCayn/BHIMpV6LKyR1fQj9EldWyT64wZQXkg==
dependencies:
underscore "1.9.1"
- web3-core-helpers "1.2.8"
- web3-core-promievent "1.2.8"
- web3-core-subscriptions "1.2.8"
- web3-utils "1.2.8"
+ web3-core-helpers "1.2.7"
+ web3-core-promievent "1.2.7"
+ web3-core-subscriptions "1.2.7"
+ web3-utils "1.2.7"
web3-core-promievent@1.0.0-beta.30:
version "1.0.0-beta.30"
@@ -20438,10 +20353,10 @@ web3-core-promievent@1.2.4:
any-promise "1.3.0"
eventemitter3 "3.1.2"
-web3-core-promievent@1.2.8:
- version "1.2.8"
- resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.2.8.tgz#a93ca2a19cae8b60883412619e04e69e11804eb5"
- integrity sha512-3EdRieaHpBVVhfGjoREQfdoCM3xC0WwWjXXzT6oTldotfYC38kwk/GW8c8txYiLP/KxhslAN1cJSlXNOJjKSog==
+web3-core-promievent@1.2.7:
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.2.7.tgz#fc7fa489f4cf76a040800f3dfd4b45c51bd3a39f"
+ integrity sha512-jNmsM/czCeMGQqKKwM9/HZVTJVIF96hdMVNN/V9TGvp+EEE7vDhB4pUocDnc/QF9Z/5QFBCVmvNWttlRgZmU0A==
dependencies:
eventemitter3 "3.1.2"
@@ -20478,16 +20393,16 @@ web3-core-requestmanager@1.2.4:
web3-providers-ipc "1.2.4"
web3-providers-ws "1.2.4"
-web3-core-requestmanager@1.2.8:
- version "1.2.8"
- resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.2.8.tgz#da7259e72a433858d04c59b999c5116bfb797c09"
- integrity sha512-bwc2ABG6yzgTy28fv4t59g+tf6+UmTRMoF8HqTeiNDffoMKP2akyKFZeu1oD2gE7j/7GA75TAUjwJ7pH9ek1MA==
+web3-core-requestmanager@1.2.7:
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.2.7.tgz#9da0efce898ead7004d4ac50f748f5131cfe4d79"
+ integrity sha512-HJb/txjHixu1dxIebiZQKBoJCaNu4gsh7mq/uj6Z/w6tIHbybL90s/7ADyMED353yyJ2tDWtYJqeMVAR+KtdaA==
dependencies:
underscore "1.9.1"
- web3-core-helpers "1.2.8"
- web3-providers-http "1.2.8"
- web3-providers-ipc "1.2.8"
- web3-providers-ws "1.2.8"
+ web3-core-helpers "1.2.7"
+ web3-providers-http "1.2.7"
+ web3-providers-ipc "1.2.7"
+ web3-providers-ws "1.2.7"
web3-core-subscriptions@1.0.0-beta.30:
version "1.0.0-beta.30"
@@ -20516,14 +20431,14 @@ web3-core-subscriptions@1.2.4:
underscore "1.9.1"
web3-core-helpers "1.2.4"
-web3-core-subscriptions@1.2.8:
- version "1.2.8"
- resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.2.8.tgz#50945498fb0bd655f842cbcc13873d96956aa93e"
- integrity sha512-wmsRJ4ipwoF1mlOR+Oo8JdKigpkoVNQtqiRUuyQrTVhJx7GBuSaAIenpBYlkucC+RgByoGybR7Q3tTNJ6z/2tQ==
+web3-core-subscriptions@1.2.7:
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.2.7.tgz#30c64aede03182832883b17c77e21cbb0933c86e"
+ integrity sha512-W/CzQYOUawdMDvkgA/fmLsnG5aMpbjrs78LZMbc0MFXLpH3ofqAgO2by4QZrrTShUUTeWS0ZuEkFFL/iFrSObw==
dependencies:
eventemitter3 "3.1.2"
underscore "1.9.1"
- web3-core-helpers "1.2.8"
+ web3-core-helpers "1.2.7"
web3-core@1.0.0-beta.30:
version "1.0.0-beta.30"
@@ -20558,18 +20473,18 @@ web3-core@1.2.4:
web3-core-requestmanager "1.2.4"
web3-utils "1.2.4"
-web3-core@1.2.8:
- version "1.2.8"
- resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.2.8.tgz#2a488bb11519b71e7738265329bddc00fc200dd3"
- integrity sha512-hvlYWyE1UcLoGa6qF1GoxGgi1quFsZOdwIUIVsAp+sp0plXp/Nqva2lAjJ+FFyWtVKbC7Zq+qwTJ4iP1aN0vTg==
+web3-core@1.2.7:
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.2.7.tgz#9248b04331e458c76263d758c51b0cc612953900"
+ integrity sha512-QA0MTae0gXcr3KHe3cQ4x56+Wh43ZKWfMwg1gfCc3NNxPRM1jJ8qudzyptCAUcxUGXWpDG8syLIn1APDz5J8BQ==
dependencies:
"@types/bn.js" "^4.11.4"
"@types/node" "^12.6.1"
bignumber.js "^9.0.0"
- web3-core-helpers "1.2.8"
- web3-core-method "1.2.8"
- web3-core-requestmanager "1.2.8"
- web3-utils "1.2.8"
+ web3-core-helpers "1.2.7"
+ web3-core-method "1.2.7"
+ web3-core-requestmanager "1.2.7"
+ web3-utils "1.2.7"
web3-eth-abi@1.0.0-beta.30:
version "1.0.0-beta.30"
@@ -20600,14 +20515,14 @@ web3-eth-abi@1.2.4:
underscore "1.9.1"
web3-utils "1.2.4"
-web3-eth-abi@1.2.8:
- version "1.2.8"
- resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.2.8.tgz#7537138f3e5cd1ccf98233fa07f388aa8dc1fff1"
- integrity sha512-OKp/maLdKHPpQxZhEd0HgnCJFQajsGe42WOG6SVftlgzyR8Jjv4KNm46TKvb3hv5OJTKZWU7nZIxkEG+fyI58w==
+web3-eth-abi@1.2.7:
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.2.7.tgz#6f3471b578649fddd844a14d397a3dd430fc44a5"
+ integrity sha512-4FnlT1q+D0XBkxSMXlIb/eG337uQeMaUdtVQ4PZ3XzxqpcoDuMgXm4o+3NRxnWmr4AMm6QKjM+hcC7c0mBKcyg==
dependencies:
- "@ethersproject/abi" "5.0.0-beta.153"
+ ethers "4.0.0-beta.3"
underscore "1.9.1"
- web3-utils "1.2.8"
+ web3-utils "1.2.7"
web3-eth-abi@^1.0.0-beta.24:
version "1.2.6"
@@ -20668,10 +20583,10 @@ web3-eth-accounts@1.2.4:
web3-core-method "1.2.4"
web3-utils "1.2.4"
-web3-eth-accounts@1.2.8:
- version "1.2.8"
- resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.2.8.tgz#e63afc6d4902f2beb0cf60e6b755c86fa5b5ccd7"
- integrity sha512-QODqSD4SZN/1oWfvlvsuum6Ud9+2FUTW4VTPJh245YTewCpa0M5+Fzug3UTeUZNv88STwC//dV72zReITNh4ZQ==
+web3-eth-accounts@1.2.7:
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.2.7.tgz#087f55d04a01b815b93151aac2fc1677436b9c59"
+ integrity sha512-AE7QWi/iIQIjXwlAPtlMabm/OPFF0a1PhxT1EiTckpYNP8fYs6jW7lYxEtJPPJIKqfMjoi1xkEqTVR1YZQ88lg==
dependencies:
"@web3-js/scrypt-shim" "^0.1.0"
crypto-browserify "3.12.0"
@@ -20680,10 +20595,10 @@ web3-eth-accounts@1.2.8:
ethereumjs-tx "^2.1.1"
underscore "1.9.1"
uuid "3.3.2"
- web3-core "1.2.8"
- web3-core-helpers "1.2.8"
- web3-core-method "1.2.8"
- web3-utils "1.2.8"
+ web3-core "1.2.7"
+ web3-core-helpers "1.2.7"
+ web3-core-method "1.2.7"
+ web3-utils "1.2.7"
web3-eth-contract@1.0.0-beta.30:
version "1.0.0-beta.30"
@@ -20728,20 +20643,20 @@ web3-eth-contract@1.2.4:
web3-eth-abi "1.2.4"
web3-utils "1.2.4"
-web3-eth-contract@1.2.8:
- version "1.2.8"
- resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.2.8.tgz#ff75920ac698a70781edcebbf75287a6d0f14499"
- integrity sha512-EWRLVhZksbzGAyHd7RaOsakjCJBA2BREWiJmBDlrxDBqw8HltXFzKdkRug/mwVNa5ZYMabKSRF/MMh0Sx06CFw==
+web3-eth-contract@1.2.7:
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.2.7.tgz#13d7f6003d6221f9a5fd61c2d3b5d039477c9674"
+ integrity sha512-uW23Y0iL7XroRNbf9fWZ1N6OYhEYTJX8gTuYASuRnpYrISN5QGiQML6pq/NCzqypR1bl5E0fuINZQSK/xefIVw==
dependencies:
"@types/bn.js" "^4.11.4"
underscore "1.9.1"
- web3-core "1.2.8"
- web3-core-helpers "1.2.8"
- web3-core-method "1.2.8"
- web3-core-promievent "1.2.8"
- web3-core-subscriptions "1.2.8"
- web3-eth-abi "1.2.8"
- web3-utils "1.2.8"
+ web3-core "1.2.7"
+ web3-core-helpers "1.2.7"
+ web3-core-method "1.2.7"
+ web3-core-promievent "1.2.7"
+ web3-core-subscriptions "1.2.7"
+ web3-eth-abi "1.2.7"
+ web3-utils "1.2.7"
web3-eth-ens@1.2.4:
version "1.2.4"
@@ -20757,20 +20672,19 @@ web3-eth-ens@1.2.4:
web3-eth-contract "1.2.4"
web3-utils "1.2.4"
-web3-eth-ens@1.2.8:
- version "1.2.8"
- resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.2.8.tgz#247daddfdbf7533adb0f45cd2f75c75e52f7e678"
- integrity sha512-zsFXY26BMGkihPkEO5qj9AEqyxPH4mclbzYs1dyrw7sHFmrUvhZc+jLGT9WyQGoujq37RN2l/tlOpCaFVVR8ng==
+web3-eth-ens@1.2.7:
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.2.7.tgz#0bfa7d4b6c7753abbb31a2eb01a364b538f4c860"
+ integrity sha512-SPRnvUNWQ0CnnTDBteGIJkvFWEizJcAHlVsrFLICwcwFZu+appjX1UOaoGu2h3GXWtc/XZlu7B451Gi+Os2cTg==
dependencies:
- content-hash "^2.5.2"
eth-ens-namehash "2.0.8"
underscore "1.9.1"
- web3-core "1.2.8"
- web3-core-helpers "1.2.8"
- web3-core-promievent "1.2.8"
- web3-eth-abi "1.2.8"
- web3-eth-contract "1.2.8"
- web3-utils "1.2.8"
+ web3-core "1.2.7"
+ web3-core-helpers "1.2.7"
+ web3-core-promievent "1.2.7"
+ web3-eth-abi "1.2.7"
+ web3-eth-contract "1.2.7"
+ web3-utils "1.2.7"
web3-eth-iban@1.0.0-beta.30:
version "1.0.0-beta.30"
@@ -20796,13 +20710,13 @@ web3-eth-iban@1.2.4:
bn.js "4.11.8"
web3-utils "1.2.4"
-web3-eth-iban@1.2.8:
- version "1.2.8"
- resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.2.8.tgz#414e80a7fb2d1ea16490bc2c8fc29a996aec5612"
- integrity sha512-xgPUOuDOQJYloUS334/wot6jvp6K8JBz8UvQ1tAxU9LO2v2DW+IDTJ5gQ6TdutTmzdDi97KdwhwnQwhQh5Z1PA==
+web3-eth-iban@1.2.7:
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.2.7.tgz#832809c28586be3c667a713b77a2bcba11b7970f"
+ integrity sha512-2NrClz1PoQ3nSJBd+91ylCOVga9qbTxjRofq/oSCoHVAEvz3WZyttx9k5DC+0rWqwJF1h69ufFvdHAAlmN/4lg==
dependencies:
bn.js "4.11.8"
- web3-utils "1.2.8"
+ web3-utils "1.2.7"
web3-eth-personal@1.0.0-beta.30:
version "1.0.0-beta.30"
@@ -20838,17 +20752,17 @@ web3-eth-personal@1.2.4:
web3-net "1.2.4"
web3-utils "1.2.4"
-web3-eth-personal@1.2.8:
- version "1.2.8"
- resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.2.8.tgz#8ebb27210b4c9c9555a30c5bb2ce8db12f84cd24"
- integrity sha512-sWhxF1cpF9pB1wMISrOSy/i8IB1NWtvoXT9dfkWtvByGf3JfC2DlnllLaA1f9ohyvxnR+QTgPKgOQDknmqDstw==
+web3-eth-personal@1.2.7:
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.2.7.tgz#322cc2b14c37737b21772a53e4185686a04bf9be"
+ integrity sha512-2OAa1Spz0uB29dwCM8+1y0So7E47A4gKznjBEwXIYEcUIsvwT5X7ofFhC2XxyRpqlIWZSQAxRSSJFyupRRXzyw==
dependencies:
"@types/node" "^12.6.1"
- web3-core "1.2.8"
- web3-core-helpers "1.2.8"
- web3-core-method "1.2.8"
- web3-net "1.2.8"
- web3-utils "1.2.8"
+ web3-core "1.2.7"
+ web3-core-helpers "1.2.7"
+ web3-core-method "1.2.7"
+ web3-net "1.2.7"
+ web3-utils "1.2.7"
web3-eth@1.0.0-beta.30:
version "1.0.0-beta.30"
@@ -20905,24 +20819,24 @@ web3-eth@1.2.4:
web3-net "1.2.4"
web3-utils "1.2.4"
-web3-eth@1.2.8:
- version "1.2.8"
- resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.2.8.tgz#cf6a16fae4d7c12b90cfb6ef570cb1a2acc34c1b"
- integrity sha512-CEnVIIR1zZQ9vQh/kPFAUbvbbHYkC84y15jdhRUDDGR6bs4FxO2NNWR2YDtNe038lrz747tZahsC9kEiGkJFZQ==
+web3-eth@1.2.7:
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.2.7.tgz#9427daefd3641200679c2946f77fc184dbfb5b4c"
+ integrity sha512-ljLd0oB4IjWkzFGVan4HkYhJXhSXgn9iaSaxdJixKGntZPgWMJfxeA+uLwTrlxrWzhvy4f+39WnT7wCh5e9TGg==
dependencies:
underscore "1.9.1"
- web3-core "1.2.8"
- web3-core-helpers "1.2.8"
- web3-core-method "1.2.8"
- web3-core-subscriptions "1.2.8"
- web3-eth-abi "1.2.8"
- web3-eth-accounts "1.2.8"
- web3-eth-contract "1.2.8"
- web3-eth-ens "1.2.8"
- web3-eth-iban "1.2.8"
- web3-eth-personal "1.2.8"
- web3-net "1.2.8"
- web3-utils "1.2.8"
+ web3-core "1.2.7"
+ web3-core-helpers "1.2.7"
+ web3-core-method "1.2.7"
+ web3-core-subscriptions "1.2.7"
+ web3-eth-abi "1.2.7"
+ web3-eth-accounts "1.2.7"
+ web3-eth-contract "1.2.7"
+ web3-eth-ens "1.2.7"
+ web3-eth-iban "1.2.7"
+ web3-eth-personal "1.2.7"
+ web3-net "1.2.7"
+ web3-utils "1.2.7"
web3-net@1.0.0-beta.30:
version "1.0.0-beta.30"
@@ -20951,14 +20865,14 @@ web3-net@1.2.4:
web3-core-method "1.2.4"
web3-utils "1.2.4"
-web3-net@1.2.8:
- version "1.2.8"
- resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.2.8.tgz#582fc2d4ba32c2e5c7761624e4be7c5434142d66"
- integrity sha512-Nsq6qgncvvThOjC+sQ+NfDH8L7jclQCFzLFYa9wsd5J6HJ6f5gJl/mv6rsZQX9iDEYDPKkDfyqHktynOBgKWMQ==
+web3-net@1.2.7:
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.2.7.tgz#c355621a8769c9c1a967c801e7db90c92a0e3808"
+ integrity sha512-j9qeZrS1FNyCeA0BfdLojkxOZQz3FKa1DJI+Dw9fEVhZS68vLOFANu2RB96gR9BoPHo5+k5D3NsKOoxt1gw3Gg==
dependencies:
- web3-core "1.2.8"
- web3-core-method "1.2.8"
- web3-utils "1.2.8"
+ web3-core "1.2.7"
+ web3-core-method "1.2.7"
+ web3-utils "1.2.7"
web3-provider-engine@14.0.6:
version "14.0.6"
@@ -21037,12 +20951,12 @@ web3-providers-http@1.2.4:
web3-core-helpers "1.2.4"
xhr2-cookies "1.1.0"
-web3-providers-http@1.2.8:
- version "1.2.8"
- resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.2.8.tgz#cd7fc4d49df6980b5dd0fb1b5a808bc4b6a0069d"
- integrity sha512-Esj4SpgabmBDOR4QD3qYapzwFYWHigcdgdjvt/VWT5/7TD10o52hr+Nsvp3/XV5AFrcCMdY+lzKFLVH24u0sww==
+web3-providers-http@1.2.7:
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.2.7.tgz#31eb15390c103169b3d7d31bdb1ccae9e3f1629d"
+ integrity sha512-vazGx5onuH/zogrwkUaLFJwFcJ6CckP65VFSHoiV+GTQdkOqgoDIha7StKkslvDz4XJ2FuY/zOZHbtuOYeltXQ==
dependencies:
- web3-core-helpers "1.2.8"
+ web3-core-helpers "1.2.7"
xhr2-cookies "1.1.0"
web3-providers-ipc@1.0.0-beta.30:
@@ -21072,14 +20986,14 @@ web3-providers-ipc@1.2.4:
underscore "1.9.1"
web3-core-helpers "1.2.4"
-web3-providers-ipc@1.2.8:
- version "1.2.8"
- resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.2.8.tgz#47be918ddd077999aa14703169b76c807f45d894"
- integrity sha512-ts3/UXCTRADPASdJ27vBVmcfM+lfG9QVBxGedY6+oNIo5EPxBUtsz94R32sfvFd6ofPsz6gOhK/M/ZKiJoi1sg==
+web3-providers-ipc@1.2.7:
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.2.7.tgz#4e6716e8723d431df3d6bfa1acd2f7c04e7071ad"
+ integrity sha512-/zc0y724H2zbkV4UbGGMhsEiLfafjagIzfrsWZnyTZUlSB0OGRmmFm2EkLJAgtXrLiodaHHyXKM0vB8S24bxdA==
dependencies:
oboe "2.1.4"
underscore "1.9.1"
- web3-core-helpers "1.2.8"
+ web3-core-helpers "1.2.7"
web3-providers-ws@1.0.0-beta.30:
version "1.0.0-beta.30"
@@ -21108,15 +21022,15 @@ web3-providers-ws@1.2.4:
underscore "1.9.1"
web3-core-helpers "1.2.4"
-web3-providers-ws@1.2.8:
- version "1.2.8"
- resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.2.8.tgz#9e6454edc82d753d398c8d1e044632c234434a46"
- integrity sha512-Gcm0n82wd/XVeGFGTx+v56UqyrV9EyB2r1QFaBx4mS+VHbW2MCOdiRbNDfoZQslflnCWl8oHsivJ8Tya9kqlTQ==
+web3-providers-ws@1.2.7:
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.2.7.tgz#95b1cc5dc25e9b9d6630d6754f9354313b62f532"
+ integrity sha512-b5XzqDpRkNVe6MFs5K6iqOEyjQikHtg3KuU2/ClCDV37hm0WN4xCRVMC0LwegulbDXZej3zT9+1CYzGaGFREzA==
dependencies:
"@web3-js/websocket" "^1.0.29"
eventemitter3 "^4.0.0"
underscore "1.9.1"
- web3-core-helpers "1.2.8"
+ web3-core-helpers "1.2.7"
web3-shh@1.0.0-beta.30:
version "1.0.0-beta.30"
@@ -21148,15 +21062,15 @@ web3-shh@1.2.4:
web3-core-subscriptions "1.2.4"
web3-net "1.2.4"
-web3-shh@1.2.8:
- version "1.2.8"
- resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.2.8.tgz#5162d9d13bc6838d390df1cd39e5f87235c1c2ae"
- integrity sha512-e29qKSfuZWDmxCG/uB48Nth6DCFFr2h2U+uI/fHEuhEjAEkBHopPNLc3ixrCTc6pqMocfJRPHJq/yET9PYN3oQ==
+web3-shh@1.2.7:
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.2.7.tgz#5382c7bc2f39539eb2841c4576d23ade25720461"
+ integrity sha512-f6PAgcpG0ZAo98KqCmeHoDEx5qzm3d5plet18DkT4U6WIeYowKdec8vZaLPRR7c2XreXFJ2gQf45CB7oqR7U/w==
dependencies:
- web3-core "1.2.8"
- web3-core-method "1.2.8"
- web3-core-subscriptions "1.2.8"
- web3-net "1.2.8"
+ web3-core "1.2.7"
+ web3-core-method "1.2.7"
+ web3-core-subscriptions "1.2.7"
+ web3-net "1.2.7"
web3-utils@1.0.0-beta.30:
version "1.0.0-beta.30"
@@ -21212,10 +21126,10 @@ web3-utils@1.2.6:
underscore "1.9.1"
utf8 "3.0.0"
-web3-utils@1.2.8:
- version "1.2.8"
- resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.2.8.tgz#5321d91715cd4c0869005705a33c4c042a532b18"
- integrity sha512-9SIVGFLajwlmo5joC4DGxuy2OeDkRCXVWT8JWcDQ+BayNVHyAWGvn0oGkQ0ys14Un0KK6bjjKoD0xYs4k+FaVw==
+web3-utils@1.2.7:
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.2.7.tgz#b68e232917e4376f81cf38ef79878e5903d18e93"
+ integrity sha512-FBh/CPJND+eiPeUF9KVbTyTZtXNWxPWtByBaWS6e2x4ACazPX711EeNaZaChIOGSLGe6se2n7kg6wnawe/MjuQ==
dependencies:
bn.js "4.11.8"
eth-lib "0.2.7"
@@ -21266,18 +21180,18 @@ web3@1.2.4:
web3-shh "1.2.4"
web3-utils "1.2.4"
-web3@^1.2.8:
- version "1.2.8"
- resolved "https://registry.yarnpkg.com/web3/-/web3-1.2.8.tgz#20b24baa769e0224a708ef5bf196a5b83d19540b"
- integrity sha512-rXUn16VKxn2aIe9v0KX+bSm2JXdq/Vnj3lZ0Rub2Q5YUSycHdCBaDtJRukl/jB5ygAdyr5/cUwvJzhNDJSYsGw==
- dependencies:
- web3-bzz "1.2.8"
- web3-core "1.2.8"
- web3-eth "1.2.8"
- web3-eth-personal "1.2.8"
- web3-net "1.2.8"
- web3-shh "1.2.8"
- web3-utils "1.2.8"
+web3@1.2.7:
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/web3/-/web3-1.2.7.tgz#fcb83571036c1c6f475bc984785982a444e8d78e"
+ integrity sha512-jAAJHMfUlTps+jH2li1ckDFEpPrEEriU/ubegSTGRl3KRdNhEqT93+3kd7FHJTn3NgjcyURo2+f7Da1YcZL8Mw==
+ dependencies:
+ web3-bzz "1.2.7"
+ web3-core "1.2.7"
+ web3-eth "1.2.7"
+ web3-eth-personal "1.2.7"
+ web3-net "1.2.7"
+ web3-shh "1.2.7"
+ web3-utils "1.2.7"
webidl-conversions@^4.0.2:
version "4.0.2"
From d2606997a35a719d9bde90ad9436d32f22cd13d8 Mon Sep 17 00:00:00 2001
From: Gerardo Nardelli
Date: Tue, 23 Jun 2020 10:48:58 -0300
Subject: [PATCH 03/13] Add ALM failed validator transactions detection (#357)
---
alm/.env.example | 3 +
alm/package.json | 2 +
alm/src/components/ConfirmationsContainer.tsx | 6 +-
alm/src/components/ExecutionConfirmation.tsx | 4 +-
alm/src/components/StatusContainer.tsx | 2 +-
.../components/ValidatorsConfirmations.tsx | 4 +-
alm/src/components/commons/Labels.tsx | 7 +
alm/src/config/constants.ts | 12 ++
alm/src/hooks/useMessageConfirmations.ts | 46 +++--
alm/src/hooks/useTransactionStatus.ts | 4 +-
alm/src/themes/Dark.tsx | 4 +
alm/src/themes/GlobalStyle.tsx | 2 +
alm/src/utils/executionWaitingForBlocks.ts | 7 +
alm/src/utils/explorer.ts | 164 +++++++++++++++++
alm/src/utils/getConfirmationsForTx.ts | 170 +++++++++++++-----
alm/src/utils/getFinalizationEvent.ts | 60 ++++++-
alm/src/utils/web3.ts | 13 ++
yarn.lock | 30 ++++
18 files changed, 471 insertions(+), 69 deletions(-)
create mode 100644 alm/src/utils/explorer.ts
diff --git a/alm/.env.example b/alm/.env.example
index 1fb92664e..16ae54928 100644
--- a/alm/.env.example
+++ b/alm/.env.example
@@ -9,3 +9,6 @@ ALM_FOREIGN_NETWORK_NAME=Kovan Testnet
ALM_HOME_EXPLORER_TX_TEMPLATE=https://blockscout.com/poa/sokol/tx/%s
ALM_FOREIGN_EXPLORER_TX_TEMPLATE=https://blockscout.com/eth/kovan/tx/%s
+
+ALM_HOME_EXPLORER_API=https://blockscout.com/poa/sokol/api
+ALM_FOREIGN_EXPLORER_API=https://kovan.etherscan.io/api
diff --git a/alm/package.json b/alm/package.json
index bafc9ef26..8d45f626c 100644
--- a/alm/package.json
+++ b/alm/package.json
@@ -9,6 +9,7 @@
"@testing-library/user-event": "^7.1.2",
"@types/jest": "^24.0.0",
"@types/node": "^12.0.0",
+ "@types/promise-retry": "^1.1.3",
"@types/react": "^16.9.0",
"@types/react-dom": "^16.9.0",
"@types/react-router-dom": "^5.1.5",
@@ -16,6 +17,7 @@
"customize-cra": "^1.0.0",
"date-fns": "^2.14.0",
"fast-memoize": "^2.5.2",
+ "promise-retry": "^2.0.1",
"react": "^16.13.1",
"react-app-rewired": "^2.1.6",
"react-dom": "^16.13.1",
diff --git a/alm/src/components/ConfirmationsContainer.tsx b/alm/src/components/ConfirmationsContainer.tsx
index 3fcee5a2f..34cdb1f00 100644
--- a/alm/src/components/ConfirmationsContainer.tsx
+++ b/alm/src/components/ConfirmationsContainer.tsx
@@ -35,9 +35,10 @@ export interface ConfirmationsContainerParams {
message: MessageObject
receipt: Maybe
fromHome: boolean
+ timestamp: number
}
-export const ConfirmationsContainer = ({ message, receipt, fromHome }: ConfirmationsContainerParams) => {
+export const ConfirmationsContainer = ({ message, receipt, fromHome, timestamp }: ConfirmationsContainerParams) => {
const {
home: { name: homeName },
foreign: { name: foreignName }
@@ -45,7 +46,8 @@ export const ConfirmationsContainer = ({ message, receipt, fromHome }: Confirmat
const { confirmations, status, executionData, signatureCollected } = useMessageConfirmations({
message,
receipt,
- fromHome
+ fromHome,
+ timestamp
})
return (
diff --git a/alm/src/components/ExecutionConfirmation.tsx b/alm/src/components/ExecutionConfirmation.tsx
index 755e6c99e..54b658e62 100644
--- a/alm/src/components/ExecutionConfirmation.tsx
+++ b/alm/src/components/ExecutionConfirmation.tsx
@@ -5,7 +5,7 @@ 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 { GreyLabel, RedLabel, SuccessLabel } from './commons/Labels'
import { ExplorerTxLink } from './commons/ExplorerTxLink'
const Thead = styled.thead`
@@ -32,6 +32,8 @@ export const ExecutionConfirmation = ({ executionData, isHome }: ExecutionConfir
switch (validatorStatus) {
case VALIDATOR_CONFIRMATION_STATUS.SUCCESS:
return {validatorStatus}
+ case VALIDATOR_CONFIRMATION_STATUS.FAILED:
+ return {validatorStatus}
case VALIDATOR_CONFIRMATION_STATUS.WAITING:
return {validatorStatus}
default:
diff --git a/alm/src/components/StatusContainer.tsx b/alm/src/components/StatusContainer.tsx
index 6d9591199..0f3ebc56c 100644
--- a/alm/src/components/StatusContainer.tsx
+++ b/alm/src/components/StatusContainer.tsx
@@ -75,7 +75,7 @@ export const StatusContainer = () => {
)}
{displayMessageSelector && }
{displayConfirmations && (
-
+
)}
)
diff --git a/alm/src/components/ValidatorsConfirmations.tsx b/alm/src/components/ValidatorsConfirmations.tsx
index 4bff387d4..1cbd2103a 100644
--- a/alm/src/components/ValidatorsConfirmations.tsx
+++ b/alm/src/components/ValidatorsConfirmations.tsx
@@ -6,7 +6,7 @@ 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'
+import { GreyLabel, RedLabel, SuccessLabel } from './commons/Labels'
const Thead = styled.thead`
border-bottom: 2px solid #9e9e9e;
@@ -30,6 +30,8 @@ export const ValidatorsConfirmations = ({ confirmations }: ValidatorsConfirmatio
switch (validatorStatus) {
case VALIDATOR_CONFIRMATION_STATUS.SUCCESS:
return {validatorStatus}
+ case VALIDATOR_CONFIRMATION_STATUS.FAILED:
+ return {validatorStatus}
case VALIDATOR_CONFIRMATION_STATUS.WAITING:
case VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED:
return {validatorStatus}
diff --git a/alm/src/components/commons/Labels.tsx b/alm/src/components/commons/Labels.tsx
index 282031220..579745b9d 100644
--- a/alm/src/components/commons/Labels.tsx
+++ b/alm/src/components/commons/Labels.tsx
@@ -13,3 +13,10 @@ export const GreyLabel = styled.label`
padding: 0.4rem 0.7rem;
border-radius: 4px;
`
+
+export const RedLabel = styled.label`
+ color: var(--failed-color);
+ background-color: var(--failed-bg-color);
+ padding: 0.4rem 0.7rem;
+ border-radius: 4px;
+`
diff --git a/alm/src/config/constants.ts b/alm/src/config/constants.ts
index fef4e53c2..505a9cd5b 100644
--- a/alm/src/config/constants.ts
+++ b/alm/src/config/constants.ts
@@ -10,9 +10,21 @@ export const FOREIGN_NETWORK_NAME: string = process.env.REACT_APP_ALM_FOREIGN_NE
export const HOME_EXPLORER_TX_TEMPLATE: string = process.env.REACT_APP_ALM_HOME_EXPLORER_TX_TEMPLATE || ''
export const FOREIGN_EXPLORER_TX_TEMPLATE: string = process.env.REACT_APP_ALM_FOREIGN_EXPLORER_TX_TEMPLATE || ''
+export const HOME_EXPLORER_API: string = process.env.REACT_APP_ALM_HOME_EXPLORER_API || ''
+export const FOREIGN_EXPLORER_API: string = process.env.REACT_APP_ALM_FOREIGN_EXPLORER_API || ''
+
export const HOME_RPC_POLLING_INTERVAL: number = 5000
export const FOREIGN_RPC_POLLING_INTERVAL: number = 15000
export const BLOCK_RANGE: number = 50
+export const ONE_DAY_TIMESTAMP: number = 86400
+export const THREE_DAYS_TIMESTAMP: number = 259200
+
+export const EXECUTE_AFFIRMATION_HASH = 'e7a2c01f'
+export const SUBMIT_SIGNATURE_HASH = '630cea8e'
+export const EXECUTE_SIGNATURES_HASH = '3f7658fd'
+
+export const CACHE_KEY_FAILED = 'failed-confirmation-validator-'
+export const CACHE_KEY_EXECUTION_FAILED = 'failed-execution-validator-'
export const TRANSACTION_STATUS = {
SUCCESS_MULTIPLE_MESSAGES: 'SUCCESS_MULTIPLE_MESSAGES',
diff --git a/alm/src/hooks/useMessageConfirmations.ts b/alm/src/hooks/useMessageConfirmations.ts
index 4615b15b1..d93f15674 100644
--- a/alm/src/hooks/useMessageConfirmations.ts
+++ b/alm/src/hooks/useMessageConfirmations.ts
@@ -17,11 +17,13 @@ import { getCollectedSignaturesEvent } from '../utils/getCollectedSignaturesEven
import { checkWaitingBlocksForExecution } from '../utils/executionWaitingForBlocks'
import { getConfirmationsForTx } from '../utils/getConfirmationsForTx'
import { getFinalizationEvent } from '../utils/getFinalizationEvent'
+import { getValidatorFailedTransactionsForMessage, getExecutionFailedTransactionForMessage } from '../utils/explorer'
export interface useMessageConfirmationsParams {
message: MessageObject
receipt: Maybe
fromHome: boolean
+ timestamp: number
}
export interface ConfirmationParam {
@@ -37,7 +39,7 @@ export interface ExecutionData {
executionResult: boolean
}
-export const useMessageConfirmations = ({ message, receipt, fromHome }: useMessageConfirmationsParams) => {
+export const useMessageConfirmations = ({ message, receipt, fromHome, timestamp }: useMessageConfirmationsParams) => {
const { home, foreign } = useStateProvider()
const [confirmations, setConfirmations] = useState>([])
const [status, setStatus] = useState(CONFIRMATIONS_STATUS.UNDEFINED)
@@ -54,6 +56,8 @@ export const useMessageConfirmations = ({ message, receipt, fromHome }: useMessa
})
const [waitingBlocksForExecution, setWaitingBlocksForExecution] = useState(false)
const [waitingBlocksForExecutionResolved, setWaitingBlocksForExecutionResolved] = useState(false)
+ const [failedConfirmations, setFailedConfirmations] = useState(false)
+ const [failedExecution, setFailedExecution] = useState(false)
// Check if the validators are waiting for block confirmations to verify the message
useEffect(
@@ -182,7 +186,7 @@ export const useMessageConfirmations = ({ message, receipt, fromHome }: useMessa
// To avoid making extra requests, this is only executed when validators finished waiting for blocks confirmations
useEffect(
() => {
- if (!waitingBlocksResolved) return
+ if (!waitingBlocksResolved || !timestamp) return
const subscriptions: Array = []
@@ -204,7 +208,10 @@ export const useMessageConfirmations = ({ message, receipt, fromHome }: useMessa
home.requiredSignatures,
setSignatureCollected,
waitingBlocksResolved,
- subscriptions
+ subscriptions,
+ timestamp,
+ getValidatorFailedTransactionsForMessage,
+ setFailedConfirmations
)
return () => {
@@ -218,7 +225,8 @@ export const useMessageConfirmations = ({ message, receipt, fromHome }: useMessa
home.validatorList,
home.bridgeContract,
home.requiredSignatures,
- waitingBlocksResolved
+ waitingBlocksResolved,
+ timestamp
]
)
@@ -248,9 +256,13 @@ export const useMessageConfirmations = ({ message, receipt, fromHome }: useMessa
providedWeb3,
setExecutionData,
waitingBlocksResolved,
- message.id,
+ message,
interval,
- subscriptions
+ subscriptions,
+ timestamp,
+ collectedSignaturesEvent,
+ getExecutionFailedTransactionForMessage,
+ setFailedExecution
)
return () => {
@@ -261,18 +273,20 @@ export const useMessageConfirmations = ({ message, receipt, fromHome }: useMessa
fromHome,
foreign.bridgeContract,
home.bridgeContract,
- message.id,
+ message,
foreign.web3,
home.web3,
waitingBlocksResolved,
- waitingBlocksForExecutionResolved
+ waitingBlocksForExecutionResolved,
+ timestamp,
+ collectedSignaturesEvent
]
)
// Sets the message status based in the collected information
useEffect(
() => {
- if (executionData.txHash) {
+ if (executionData.status === VALIDATOR_CONFIRMATION_STATUS.SUCCESS) {
const newStatus = executionData.executionResult
? CONFIRMATIONS_STATUS.SUCCESS
: CONFIRMATIONS_STATUS.SUCCESS_MESSAGE_FAILED
@@ -281,6 +295,8 @@ export const useMessageConfirmations = ({ message, receipt, fromHome }: useMessa
if (fromHome) {
if (waitingBlocksForExecution) {
setStatus(CONFIRMATIONS_STATUS.EXECUTION_WAITING)
+ } else if (failedExecution) {
+ setStatus(CONFIRMATIONS_STATUS.EXECUTION_FAILED)
} else {
setStatus(CONFIRMATIONS_STATUS.UNDEFINED)
}
@@ -289,11 +305,21 @@ export const useMessageConfirmations = ({ message, receipt, fromHome }: useMessa
}
} else if (waitingBlocks) {
setStatus(CONFIRMATIONS_STATUS.WAITING)
+ } else if (failedConfirmations) {
+ setStatus(CONFIRMATIONS_STATUS.FAILED)
} else {
setStatus(CONFIRMATIONS_STATUS.UNDEFINED)
}
},
- [executionData, fromHome, signatureCollected, waitingBlocks, waitingBlocksForExecution]
+ [
+ executionData,
+ fromHome,
+ signatureCollected,
+ waitingBlocks,
+ waitingBlocksForExecution,
+ failedConfirmations,
+ failedExecution
+ ]
)
return {
diff --git a/alm/src/hooks/useTransactionStatus.ts b/alm/src/hooks/useTransactionStatus.ts
index 9a981744c..c6ad73e2a 100644
--- a/alm/src/hooks/useTransactionStatus.ts
+++ b/alm/src/hooks/useTransactionStatus.ts
@@ -3,7 +3,7 @@ import { TransactionReceipt } from 'web3-eth'
import { HOME_RPC_POLLING_INTERVAL, TRANSACTION_STATUS } from '../config/constants'
import { getTransactionStatusDescription } from '../utils/networks'
import { useStateProvider } from '../state/StateProvider'
-import { getHomeMessagesFromReceipt, getForeignMessagesFromReceipt, MessageObject } from '../utils/web3'
+import { getHomeMessagesFromReceipt, getForeignMessagesFromReceipt, MessageObject, getBlock } from '../utils/web3'
export const useTransactionStatus = ({ txHash, chainId }: { txHash: string; chainId: number }) => {
const { home, foreign } = useStateProvider()
@@ -41,7 +41,7 @@ export const useTransactionStatus = ({ txHash, chainId }: { txHash: string; chai
subscriptions.push(timeoutId)
} else {
const blockNumber = txReceipt.blockNumber
- const block = await web3.eth.getBlock(blockNumber)
+ const block = await getBlock(web3, blockNumber)
const blockTimestamp = typeof block.timestamp === 'string' ? parseInt(block.timestamp) : block.timestamp
setTimestamp(blockTimestamp)
diff --git a/alm/src/themes/Dark.tsx b/alm/src/themes/Dark.tsx
index 07a4e0f46..4bb635313 100644
--- a/alm/src/themes/Dark.tsx
+++ b/alm/src/themes/Dark.tsx
@@ -12,6 +12,10 @@ const theme = {
notRequired: {
textColor: '#bdbdbd',
backgroundColor: '#424242'
+ },
+ failed: {
+ textColor: '#EF5350',
+ backgroundColor: '#4E342E'
}
}
export default theme
diff --git a/alm/src/themes/GlobalStyle.tsx b/alm/src/themes/GlobalStyle.tsx
index d10ea42d1..04485df09 100644
--- a/alm/src/themes/GlobalStyle.tsx
+++ b/alm/src/themes/GlobalStyle.tsx
@@ -25,5 +25,7 @@ export const GlobalStyle = createGlobalStyle<{ theme: ThemeType }>`
--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};
+ --failed-color: ${props => props.theme.failed.textColor};
+ --failed-bg-color: ${props => props.theme.failed.backgroundColor};
}
`
diff --git a/alm/src/utils/executionWaitingForBlocks.ts b/alm/src/utils/executionWaitingForBlocks.ts
index 612284913..958348266 100644
--- a/alm/src/utils/executionWaitingForBlocks.ts
+++ b/alm/src/utils/executionWaitingForBlocks.ts
@@ -15,6 +15,13 @@ export const checkWaitingBlocksForExecution = async (
const currentBlock = blockProvider.get()
if (currentBlock && currentBlock >= targetBlock) {
+ setExecutionData({
+ status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
+ validator: collectedSignaturesEvent.returnValues.authorityResponsibleForRelay,
+ txHash: '',
+ timestamp: 0,
+ executionResult: false
+ })
setWaitingBlocksForExecution(false)
setWaitingBlocksForExecutionResolved(true)
blockProvider.stop()
diff --git a/alm/src/utils/explorer.ts b/alm/src/utils/explorer.ts
new file mode 100644
index 000000000..a6ba84ac0
--- /dev/null
+++ b/alm/src/utils/explorer.ts
@@ -0,0 +1,164 @@
+import {
+ EXECUTE_AFFIRMATION_HASH,
+ EXECUTE_SIGNATURES_HASH,
+ FOREIGN_EXPLORER_API,
+ HOME_EXPLORER_API,
+ SUBMIT_SIGNATURE_HASH
+} from '../config/constants'
+
+export interface APITransaction {
+ timeStamp: string
+ isError: string
+ input: string
+ to: string
+ hash: string
+}
+
+export interface AccountTransactionsParams {
+ account: string
+ to: string
+ startTimestamp: number
+ endTimestamp: number
+ api: string
+}
+
+export interface GetFailedTransactionParams {
+ account: string
+ to: string
+ messageData: string
+ startTimestamp: number
+ endTimestamp: number
+}
+
+export const fetchAccountTransactionsFromBlockscout = async ({
+ account,
+ to,
+ startTimestamp,
+ endTimestamp,
+ api
+}: AccountTransactionsParams): Promise => {
+ const url = `${api}?module=account&action=txlist&address=${account}&filterby=from=${account}&to=${to}&starttimestamp=${startTimestamp}&endtimestamp=${endTimestamp}`
+
+ try {
+ const result = await fetch(url).then(res => res.json())
+ if (result.status === '0') {
+ return []
+ }
+
+ return result.result
+ } catch (e) {
+ console.log(e)
+ return []
+ }
+}
+
+export const getBlockByTimestampUrl = (api: string, timestamp: number) =>
+ `${api}?module=block&action=getblocknobytime×tamp=${timestamp}&closest=before`
+
+export const fetchAccountTransactionsFromEtherscan = async ({
+ account,
+ to,
+ startTimestamp,
+ endTimestamp,
+ api
+}: AccountTransactionsParams): Promise => {
+ const startBlockUrl = getBlockByTimestampUrl(api, startTimestamp)
+ const endBlockUrl = getBlockByTimestampUrl(api, endTimestamp)
+ let fromBlock = 0
+ let toBlock = 9999999999999
+ try {
+ const [fromBlockResult, toBlockResult] = await Promise.all([
+ fetch(startBlockUrl).then(res => res.json()),
+ fetch(endBlockUrl).then(res => res.json())
+ ])
+
+ if (fromBlockResult.status !== '0') {
+ fromBlock = parseInt(fromBlockResult.result)
+ }
+
+ if (toBlockResult.status !== '0') {
+ toBlock = parseInt(toBlockResult.result)
+ }
+ } catch (e) {
+ console.log(e)
+ return []
+ }
+
+ const url = `${api}?module=account&action=txlist&address=${account}&startblock=${fromBlock}&endblock=${toBlock}`
+
+ try {
+ const result = await fetch(url).then(res => res.json())
+
+ if (result.status === '0') {
+ return []
+ }
+
+ const toAddressLowerCase = to.toLowerCase()
+ const transactions: APITransaction[] = result.result
+ return transactions.filter(t => t.to.toLowerCase() === toAddressLowerCase)
+ } catch (e) {
+ console.log(e)
+ return []
+ }
+}
+
+export const fetchAccountTransactions = (api: string) => {
+ return api.includes('blockscout') ? fetchAccountTransactionsFromBlockscout : fetchAccountTransactionsFromEtherscan
+}
+
+export const getFailedTransactions = async (
+ account: string,
+ to: string,
+ startTimestamp: number,
+ endTimestamp: number,
+ api: string,
+ fetchAccountTransactions: (args: AccountTransactionsParams) => Promise
+): Promise => {
+ const transactions = await fetchAccountTransactions({ account, to, startTimestamp, endTimestamp, api })
+
+ return transactions.filter(t => t.isError !== '0')
+}
+
+export const getValidatorFailedTransactionsForMessage = async ({
+ account,
+ to,
+ messageData,
+ startTimestamp,
+ endTimestamp
+}: GetFailedTransactionParams): Promise => {
+ const failedTransactions = await getFailedTransactions(
+ account,
+ to,
+ startTimestamp,
+ endTimestamp,
+ HOME_EXPLORER_API,
+ fetchAccountTransactionsFromBlockscout
+ )
+
+ const messageDataValue = messageData.replace('0x', '')
+ return failedTransactions.filter(
+ t =>
+ (t.input.includes(SUBMIT_SIGNATURE_HASH) || t.input.includes(EXECUTE_AFFIRMATION_HASH)) &&
+ t.input.includes(messageDataValue)
+ )
+}
+
+export const getExecutionFailedTransactionForMessage = async ({
+ account,
+ to,
+ messageData,
+ startTimestamp,
+ endTimestamp
+}: GetFailedTransactionParams): Promise => {
+ const failedTransactions = await getFailedTransactions(
+ account,
+ to,
+ startTimestamp,
+ endTimestamp,
+ FOREIGN_EXPLORER_API,
+ fetchAccountTransactions(FOREIGN_EXPLORER_API)
+ )
+
+ const messageDataValue = messageData.replace('0x', '')
+ return failedTransactions.filter(t => t.input.includes(EXECUTE_SIGNATURES_HASH) && t.input.includes(messageDataValue))
+}
diff --git a/alm/src/utils/getConfirmationsForTx.ts b/alm/src/utils/getConfirmationsForTx.ts
index e5b29097e..009ad46ee 100644
--- a/alm/src/utils/getConfirmationsForTx.ts
+++ b/alm/src/utils/getConfirmationsForTx.ts
@@ -1,7 +1,81 @@
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'
+import {
+ CACHE_KEY_FAILED,
+ HOME_RPC_POLLING_INTERVAL,
+ ONE_DAY_TIMESTAMP,
+ VALIDATOR_CONFIRMATION_STATUS
+} from '../config/constants'
+import { GetFailedTransactionParams, APITransaction } from './explorer'
+import { ConfirmationParam } from '../hooks/useMessageConfirmations'
+
+export const getValidatorConfirmation = (
+ web3: Web3,
+ hashMsg: string,
+ bridgeContract: Contract,
+ confirmationContractMethod: Function
+) => async (validator: string): Promise => {
+ 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
+ }
+}
+
+export const getValidatorFailedTransaction = (
+ bridgeContract: Contract,
+ messageData: string,
+ timestamp: number,
+ getFailedTransactions: (args: GetFailedTransactionParams) => Promise
+) => async (validatorData: ConfirmationParam): Promise => {
+ const validatorCacheKey = `${CACHE_KEY_FAILED}${validatorData.validator}`
+ const failedFromCache = validatorsCache.get(validatorCacheKey)
+
+ if (failedFromCache) {
+ return {
+ validator: validatorData.validator,
+ status: VALIDATOR_CONFIRMATION_STATUS.FAILED
+ }
+ }
+
+ const failedTransactions = await getFailedTransactions({
+ account: validatorData.validator,
+ to: bridgeContract.options.address,
+ messageData,
+ startTimestamp: timestamp,
+ endTimestamp: timestamp + ONE_DAY_TIMESTAMP
+ })
+ const newStatus =
+ failedTransactions.length > 0 ? VALIDATOR_CONFIRMATION_STATUS.FAILED : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
+
+ // If validator signature failed, we cache the result to avoid doing future requests for a result that won't change
+ if (failedTransactions.length > 0) {
+ validatorsCache.set(validatorCacheKey, true)
+ }
+
+ return {
+ validator: validatorData.validator,
+ status: newStatus
+ }
+}
export const getConfirmationsForTx = async (
messageData: string,
@@ -13,63 +87,69 @@ export const getConfirmationsForTx = async (
requiredSignatures: number,
setSignatureCollected: Function,
waitingBlocksResolved: boolean,
- subscriptions: number[]
+ subscriptions: number[],
+ timestamp: number,
+ getFailedTransactions: (args: GetFailedTransactionParams) => Promise,
+ setFailedConfirmations: Function
) => {
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
- }
- })
+ validatorList.map(getValidatorConfirmation(web3, hashMsg, bridgeContract, confirmationContractMethod))
)
const successConfirmations = validatorConfirmations.filter(c => c.status === VALIDATOR_CONFIRMATION_STATUS.SUCCESS)
+ const notSuccessConfirmations = 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
+ // Check if confirmation failed
+ const validatorFailedConfirmationsChecks = await Promise.all(
+ notSuccessConfirmations.map(
+ getValidatorFailedTransaction(bridgeContract, messageData, timestamp, getFailedTransactions)
+ )
)
- subscriptions.push(timeoutId)
+ const validatorFailedConfirmations = validatorFailedConfirmationsChecks.filter(
+ c => c.status === VALIDATOR_CONFIRMATION_STATUS.FAILED
+ )
+ validatorFailedConfirmations.forEach(validatorData => {
+ const index = validatorConfirmations.findIndex(e => e.validator === validatorData.validator)
+ validatorConfirmations[index] = validatorData
+ })
+ const messageConfirmationsFailed = validatorFailedConfirmations.length > validatorList.length - requiredSignatures
+ if (messageConfirmationsFailed) {
+ setFailedConfirmations(true)
+ }
+
+ const missingConfirmations = validatorConfirmations.filter(
+ c => c.status === VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
+ )
+
+ if (missingConfirmations.length > 0) {
+ const timeoutId = setTimeout(
+ () =>
+ getConfirmationsForTx(
+ messageData,
+ web3,
+ validatorList,
+ bridgeContract,
+ confirmationContractMethod,
+ setResult,
+ requiredSignatures,
+ setSignatureCollected,
+ waitingBlocksResolved,
+ subscriptions,
+ timestamp,
+ getFailedTransactions,
+ setFailedConfirmations
+ ),
+ 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
diff --git a/alm/src/utils/getFinalizationEvent.ts b/alm/src/utils/getFinalizationEvent.ts
index a391ebb5f..b87e15ed4 100644
--- a/alm/src/utils/getFinalizationEvent.ts
+++ b/alm/src/utils/getFinalizationEvent.ts
@@ -1,7 +1,10 @@
import { Contract, EventData } from 'web3-eth-contract'
import Web3 from 'web3'
-import { VALIDATOR_CONFIRMATION_STATUS } from '../config/constants'
+import { CACHE_KEY_EXECUTION_FAILED, THREE_DAYS_TIMESTAMP, VALIDATOR_CONFIRMATION_STATUS } from '../config/constants'
import { ExecutionData } from '../hooks/useMessageConfirmations'
+import { APITransaction, GetFailedTransactionParams } from './explorer'
+import { getBlock, MessageObject } from './web3'
+import validatorsCache from '../services/ValidatorsCache'
export const getFinalizationEvent = async (
contract: Maybe,
@@ -9,9 +12,13 @@ export const getFinalizationEvent = async (
web3: Maybe,
setResult: React.Dispatch>,
waitingBlocksResolved: boolean,
- messageId: string,
+ message: MessageObject,
interval: number,
- subscriptions: number[]
+ subscriptions: number[],
+ timestamp: number,
+ collectedSignaturesEvent: Maybe,
+ getFailedExecution: (args: GetFailedTransactionParams) => Promise,
+ setFailedExecution: Function
) => {
if (!contract || !web3 || !waitingBlocksResolved) return
// Since it filters by the message id, only one event will be fetched
@@ -20,14 +27,14 @@ export const getFinalizationEvent = async (
fromBlock: 0,
toBlock: 'latest',
filter: {
- messageId
+ messageId: message.id
}
})
if (events.length > 0) {
const event = events[0]
const [txReceipt, block] = await Promise.all([
web3.eth.getTransactionReceipt(event.transactionHash),
- web3.eth.getBlock(event.blockNumber)
+ getBlock(web3, event.blockNumber)
])
const blockTimestamp = typeof block.timestamp === 'string' ? parseInt(block.timestamp) : block.timestamp
@@ -41,6 +48,41 @@ export const getFinalizationEvent = async (
executionResult: event.returnValues.status
})
} else {
+ // If event is defined, it means it is a message from Home to Foreign
+ if (collectedSignaturesEvent) {
+ const validator = collectedSignaturesEvent.returnValues.authorityResponsibleForRelay
+
+ const validatorExecutionCacheKey = `${CACHE_KEY_EXECUTION_FAILED}${validator}`
+ const failedFromCache = validatorsCache.get(validatorExecutionCacheKey)
+
+ if (!failedFromCache) {
+ const failedTransactions = await getFailedExecution({
+ account: validator,
+ to: contract.options.address,
+ messageData: message.data,
+ startTimestamp: timestamp,
+ endTimestamp: timestamp + THREE_DAYS_TIMESTAMP
+ })
+
+ if (failedTransactions.length > 0) {
+ const failedTx = failedTransactions[0]
+
+ // If validator execution failed, we cache the result to avoid doing future requests for a result that won't change
+ validatorsCache.set(validatorExecutionCacheKey, true)
+
+ const timestamp = parseInt(failedTx.timeStamp)
+ setResult({
+ status: VALIDATOR_CONFIRMATION_STATUS.FAILED,
+ validator: validator,
+ txHash: failedTx.hash,
+ timestamp,
+ executionResult: false
+ })
+ setFailedExecution(true)
+ }
+ }
+ }
+
const timeoutId = setTimeout(
() =>
getFinalizationEvent(
@@ -49,9 +91,13 @@ export const getFinalizationEvent = async (
web3,
setResult,
waitingBlocksResolved,
- messageId,
+ message,
interval,
- subscriptions
+ subscriptions,
+ timestamp,
+ collectedSignaturesEvent,
+ getFailedExecution,
+ setFailedExecution
),
interval
)
diff --git a/alm/src/utils/web3.ts b/alm/src/utils/web3.ts
index d35dd3648..db91d59ec 100644
--- a/alm/src/utils/web3.ts
+++ b/alm/src/utils/web3.ts
@@ -1,7 +1,9 @@
import Web3 from 'web3'
+import { BlockTransactionString } from 'web3-eth'
import { TransactionReceipt } from 'web3-eth'
import { AbiItem } from 'web3-utils'
import memoize from 'fast-memoize'
+import promiseRetry from 'promise-retry'
import { HOME_AMB_ABI, FOREIGN_AMB_ABI } from '../../../commons'
export interface MessageObject {
@@ -48,3 +50,14 @@ export const getForeignMessagesFromReceipt = (txReceipt: TransactionReceipt, web
)[0]
return filterEventsByAbi(txReceipt, web3, bridgeAddress, userRequestForAffirmationAbi)
}
+
+// In some rare cases the block data is not available yet for the block of a new event detected
+// so this logic retry to get the block in case it fails
+export const getBlock = async (web3: Web3, blockNumber: number): Promise =>
+ promiseRetry(async retry => {
+ const result = await web3.eth.getBlock(blockNumber)
+ if (!result) {
+ return retry('Error getting block data')
+ }
+ return result
+ })
diff --git a/yarn.lock b/yarn.lock
index b90bd96b8..20ab80397 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2980,6 +2980,13 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.59.tgz#9e34261f30183f9777017a13d185dfac6b899e04"
integrity sha512-8RkBivJrDCyPpBXhVZcjh7cQxVBSmRk9QM7hOketZzp6Tg79c0N8kkpAIito9bnJ3HCVCHVYz+KHTEbfQNfeVQ==
+"@types/promise-retry@^1.1.3":
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/@types/promise-retry/-/promise-retry-1.1.3.tgz#baab427419da9088a1d2f21bf56249c21b3dd43c"
+ integrity sha512-LxIlEpEX6frE3co3vCO2EUJfHIta1IOmhDlcAsR4GMMv9hev1iTI9VwberVGkePJAuLZs5rMucrV8CziCfuJMw==
+ dependencies:
+ "@types/retry" "*"
+
"@types/prop-types@*":
version "15.7.3"
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7"
@@ -3042,6 +3049,11 @@
"@types/prop-types" "*"
csstype "^2.2.0"
+"@types/retry@*":
+ version "0.12.0"
+ resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d"
+ integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==
+
"@types/solidity-parser-antlr@^0.2.3":
version "0.2.3"
resolved "https://registry.yarnpkg.com/@types/solidity-parser-antlr/-/solidity-parser-antlr-0.2.3.tgz#bb2d9c6511bf483afe4fc3e2714da8a924e59e3f"
@@ -7712,6 +7724,11 @@ err-code@^1.0.0:
resolved "https://registry.yarnpkg.com/err-code/-/err-code-1.1.2.tgz#06e0116d3028f6aef4806849eb0ea6a748ae6960"
integrity sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA=
+err-code@^2.0.2:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9"
+ integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==
+
errno@^0.1.3, errno@~0.1.1, errno@~0.1.7:
version "0.1.7"
resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618"
@@ -16100,6 +16117,14 @@ promise-retry@^1.1.1:
err-code "^1.0.0"
retry "^0.10.0"
+promise-retry@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22"
+ integrity sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==
+ dependencies:
+ err-code "^2.0.2"
+ retry "^0.12.0"
+
promise-to-callback@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/promise-to-callback/-/promise-to-callback-1.0.0.tgz#5d2a749010bfb67d963598fcd3960746a68feef7"
@@ -17410,6 +17435,11 @@ retry@^0.10.0:
resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4"
integrity sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=
+retry@^0.12.0:
+ version "0.12.0"
+ resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b"
+ integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=
+
rgb-regex@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/rgb-regex/-/rgb-regex-1.0.1.tgz#c0e0d6882df0e23be254a475e8edd41915feaeb1"
From d228bb7ea9eaa0d7461aee92f5ec205cd417a1ef Mon Sep 17 00:00:00 2001
From: Gerardo Nardelli
Date: Tue, 23 Jun 2020 10:49:59 -0300
Subject: [PATCH 04/13] Add button to search another transaction in ALM (#364)
---
alm/src/components/StatusContainer.tsx | 25 +++++++++++++++++++++++-
alm/src/components/commons/LeftArrow.tsx | 20 +++++++++++++++++++
2 files changed, 44 insertions(+), 1 deletion(-)
create mode 100644 alm/src/components/commons/LeftArrow.tsx
diff --git a/alm/src/components/StatusContainer.tsx b/alm/src/components/StatusContainer.tsx
index 0f3ebc56c..a8d0d000c 100644
--- a/alm/src/components/StatusContainer.tsx
+++ b/alm/src/components/StatusContainer.tsx
@@ -1,5 +1,5 @@
import React from 'react'
-import { useHistory, useParams } from 'react-router-dom'
+import { Link, useHistory, useParams } from 'react-router-dom'
import { useTransactionStatus } from '../hooks/useTransactionStatus'
import { formatTxHash, getExplorerTxUrl, getTransactionStatusDescription, validTxHash } from '../utils/networks'
import { TRANSACTION_STATUS } from '../config/constants'
@@ -8,6 +8,19 @@ import { Loading } from './commons/Loading'
import { useStateProvider } from '../state/StateProvider'
import { ExplorerTxLink } from './commons/ExplorerTxLink'
import { ConfirmationsContainer } from './ConfirmationsContainer'
+import { LeftArrow } from './commons/LeftArrow'
+import styled from 'styled-components'
+
+const BackButton = styled.button`
+ color: var(--font-color);
+ border-color: var(--font-color);
+ margin-top: 10px;
+`
+
+const BackLabel = styled.label`
+ margin-left: 5px;
+ cursor: pointer;
+`
export const StatusContainer = () => {
const { home, foreign } = useStateProvider()
@@ -77,6 +90,16 @@ export const StatusContainer = () => {
{displayConfirmations && (
)}
+
+
+
+
+
+ Search another transaction
+
+
+
+
)
}
diff --git a/alm/src/components/commons/LeftArrow.tsx b/alm/src/components/commons/LeftArrow.tsx
new file mode 100644
index 000000000..1700297a7
--- /dev/null
+++ b/alm/src/components/commons/LeftArrow.tsx
@@ -0,0 +1,20 @@
+import React from 'react'
+import { useContext } from 'react'
+import { ThemeContext } from 'styled-components'
+
+export const LeftArrow = () => {
+ const themeContext = useContext(ThemeContext)
+ return (
+
+ )
+}
From 9e9e891db8feec5fefc5b43a55514caa38c3a47d Mon Sep 17 00:00:00 2001
From: Gerardo Nardelli
Date: Tue, 23 Jun 2020 11:24:10 -0300
Subject: [PATCH 05/13] Add ALM Pending validator transactions detection (#363)
---
alm/src/components/ExecutionConfirmation.tsx | 1 +
.../components/ValidatorsConfirmations.tsx | 1 +
alm/src/config/constants.ts | 2 +-
alm/src/hooks/useMessageConfirmations.ts | 25 +++++-
alm/src/utils/explorer.ts | 77 ++++++++++++++++++
alm/src/utils/getConfirmationsForTx.ts | 59 ++++++++++++--
alm/src/utils/getFinalizationEvent.ts | 81 +++++++++++++------
7 files changed, 211 insertions(+), 35 deletions(-)
diff --git a/alm/src/components/ExecutionConfirmation.tsx b/alm/src/components/ExecutionConfirmation.tsx
index 54b658e62..5bc40ea5b 100644
--- a/alm/src/components/ExecutionConfirmation.tsx
+++ b/alm/src/components/ExecutionConfirmation.tsx
@@ -34,6 +34,7 @@ export const ExecutionConfirmation = ({ executionData, isHome }: ExecutionConfir
return {validatorStatus}
case VALIDATOR_CONFIRMATION_STATUS.FAILED:
return {validatorStatus}
+ case VALIDATOR_CONFIRMATION_STATUS.PENDING:
case VALIDATOR_CONFIRMATION_STATUS.WAITING:
return {validatorStatus}
default:
diff --git a/alm/src/components/ValidatorsConfirmations.tsx b/alm/src/components/ValidatorsConfirmations.tsx
index 1cbd2103a..94bdd17bb 100644
--- a/alm/src/components/ValidatorsConfirmations.tsx
+++ b/alm/src/components/ValidatorsConfirmations.tsx
@@ -32,6 +32,7 @@ export const ValidatorsConfirmations = ({ confirmations }: ValidatorsConfirmatio
return {validatorStatus}
case VALIDATOR_CONFIRMATION_STATUS.FAILED:
return {validatorStatus}
+ case VALIDATOR_CONFIRMATION_STATUS.PENDING:
case VALIDATOR_CONFIRMATION_STATUS.WAITING:
case VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED:
return {validatorStatus}
diff --git a/alm/src/config/constants.ts b/alm/src/config/constants.ts
index 505a9cd5b..5fe96bc9d 100644
--- a/alm/src/config/constants.ts
+++ b/alm/src/config/constants.ts
@@ -14,7 +14,7 @@ export const HOME_EXPLORER_API: string = process.env.REACT_APP_ALM_HOME_EXPLORER
export const FOREIGN_EXPLORER_API: string = process.env.REACT_APP_ALM_FOREIGN_EXPLORER_API || ''
export const HOME_RPC_POLLING_INTERVAL: number = 5000
-export const FOREIGN_RPC_POLLING_INTERVAL: number = 15000
+export const FOREIGN_RPC_POLLING_INTERVAL: number = 5000
export const BLOCK_RANGE: number = 50
export const ONE_DAY_TIMESTAMP: number = 86400
export const THREE_DAYS_TIMESTAMP: number = 259200
diff --git a/alm/src/hooks/useMessageConfirmations.ts b/alm/src/hooks/useMessageConfirmations.ts
index d93f15674..fd6a17749 100644
--- a/alm/src/hooks/useMessageConfirmations.ts
+++ b/alm/src/hooks/useMessageConfirmations.ts
@@ -17,7 +17,12 @@ import { getCollectedSignaturesEvent } from '../utils/getCollectedSignaturesEven
import { checkWaitingBlocksForExecution } from '../utils/executionWaitingForBlocks'
import { getConfirmationsForTx } from '../utils/getConfirmationsForTx'
import { getFinalizationEvent } from '../utils/getFinalizationEvent'
-import { getValidatorFailedTransactionsForMessage, getExecutionFailedTransactionForMessage } from '../utils/explorer'
+import {
+ getValidatorFailedTransactionsForMessage,
+ getExecutionFailedTransactionForMessage,
+ getValidatorPendingTransactionsForMessage,
+ getExecutionPendingTransactionsForMessage
+} from '../utils/explorer'
export interface useMessageConfirmationsParams {
message: MessageObject
@@ -58,6 +63,8 @@ export const useMessageConfirmations = ({ message, receipt, fromHome, timestamp
const [waitingBlocksForExecutionResolved, setWaitingBlocksForExecutionResolved] = useState(false)
const [failedConfirmations, setFailedConfirmations] = useState(false)
const [failedExecution, setFailedExecution] = useState(false)
+ const [pendingConfirmations, setPendingConfirmations] = useState(false)
+ const [pendingExecution, setPendingExecution] = useState(false)
// Check if the validators are waiting for block confirmations to verify the message
useEffect(
@@ -211,7 +218,9 @@ export const useMessageConfirmations = ({ message, receipt, fromHome, timestamp
subscriptions,
timestamp,
getValidatorFailedTransactionsForMessage,
- setFailedConfirmations
+ setFailedConfirmations,
+ getValidatorPendingTransactionsForMessage,
+ setPendingConfirmations
)
return () => {
@@ -262,7 +271,9 @@ export const useMessageConfirmations = ({ message, receipt, fromHome, timestamp
timestamp,
collectedSignaturesEvent,
getExecutionFailedTransactionForMessage,
- setFailedExecution
+ setFailedExecution,
+ getExecutionPendingTransactionsForMessage,
+ setPendingExecution
)
return () => {
@@ -297,6 +308,8 @@ export const useMessageConfirmations = ({ message, receipt, fromHome, timestamp
setStatus(CONFIRMATIONS_STATUS.EXECUTION_WAITING)
} else if (failedExecution) {
setStatus(CONFIRMATIONS_STATUS.EXECUTION_FAILED)
+ } else if (pendingExecution) {
+ setStatus(CONFIRMATIONS_STATUS.EXECUTION_PENDING)
} else {
setStatus(CONFIRMATIONS_STATUS.UNDEFINED)
}
@@ -307,6 +320,8 @@ export const useMessageConfirmations = ({ message, receipt, fromHome, timestamp
setStatus(CONFIRMATIONS_STATUS.WAITING)
} else if (failedConfirmations) {
setStatus(CONFIRMATIONS_STATUS.FAILED)
+ } else if (pendingConfirmations) {
+ setStatus(CONFIRMATIONS_STATUS.PENDING)
} else {
setStatus(CONFIRMATIONS_STATUS.UNDEFINED)
}
@@ -318,7 +333,9 @@ export const useMessageConfirmations = ({ message, receipt, fromHome, timestamp
waitingBlocks,
waitingBlocksForExecution,
failedConfirmations,
- failedExecution
+ failedExecution,
+ pendingConfirmations,
+ pendingExecution
]
)
diff --git a/alm/src/utils/explorer.ts b/alm/src/utils/explorer.ts
index a6ba84ac0..8d745c58e 100644
--- a/alm/src/utils/explorer.ts
+++ b/alm/src/utils/explorer.ts
@@ -14,6 +14,17 @@ export interface APITransaction {
hash: string
}
+export interface APIPendingTransaction {
+ input: string
+ to: string
+ hash: string
+}
+
+export interface PendingTransactionsParams {
+ account: string
+ api: string
+}
+
export interface AccountTransactionsParams {
account: string
to: string
@@ -30,6 +41,12 @@ export interface GetFailedTransactionParams {
endTimestamp: number
}
+export interface GetPendingTransactionParams {
+ account: string
+ to: string
+ messageData: string
+}
+
export const fetchAccountTransactionsFromBlockscout = async ({
account,
to,
@@ -106,6 +123,24 @@ export const fetchAccountTransactions = (api: string) => {
return api.includes('blockscout') ? fetchAccountTransactionsFromBlockscout : fetchAccountTransactionsFromEtherscan
}
+export const fetchPendingTransactions = async ({
+ account,
+ api
+}: PendingTransactionsParams): Promise => {
+ const url = `${api}?module=account&action=pendingtxlist&address=${account}`
+
+ try {
+ const result = await fetch(url).then(res => res.json())
+ if (result.status === '0') {
+ return []
+ }
+
+ return result.result
+ } catch (e) {
+ return []
+ }
+}
+
export const getFailedTransactions = async (
account: string,
to: string,
@@ -162,3 +197,45 @@ export const getExecutionFailedTransactionForMessage = async ({
const messageDataValue = messageData.replace('0x', '')
return failedTransactions.filter(t => t.input.includes(EXECUTE_SIGNATURES_HASH) && t.input.includes(messageDataValue))
}
+
+export const getValidatorPendingTransactionsForMessage = async ({
+ account,
+ to,
+ messageData
+}: GetPendingTransactionParams): Promise => {
+ const pendingTransactions = await fetchPendingTransactions({
+ account,
+ api: HOME_EXPLORER_API
+ })
+
+ const toAddressLowerCase = to.toLowerCase()
+ const messageDataValue = messageData.replace('0x', '')
+
+ return pendingTransactions.filter(
+ t =>
+ t.to.toLowerCase() === toAddressLowerCase &&
+ (t.input.includes(SUBMIT_SIGNATURE_HASH) || t.input.includes(EXECUTE_AFFIRMATION_HASH)) &&
+ t.input.includes(messageDataValue)
+ )
+}
+
+export const getExecutionPendingTransactionsForMessage = async ({
+ account,
+ to,
+ messageData
+}: GetPendingTransactionParams): Promise => {
+ const pendingTransactions = await fetchPendingTransactions({
+ account,
+ api: FOREIGN_EXPLORER_API
+ })
+
+ const toAddressLowerCase = to.toLowerCase()
+ const messageDataValue = messageData.replace('0x', '')
+
+ return pendingTransactions.filter(
+ t =>
+ t.to.toLowerCase() === toAddressLowerCase &&
+ t.input.includes(EXECUTE_SIGNATURES_HASH) &&
+ t.input.includes(messageDataValue)
+ )
+}
diff --git a/alm/src/utils/getConfirmationsForTx.ts b/alm/src/utils/getConfirmationsForTx.ts
index 009ad46ee..f570c6b06 100644
--- a/alm/src/utils/getConfirmationsForTx.ts
+++ b/alm/src/utils/getConfirmationsForTx.ts
@@ -7,7 +7,12 @@ import {
ONE_DAY_TIMESTAMP,
VALIDATOR_CONFIRMATION_STATUS
} from '../config/constants'
-import { GetFailedTransactionParams, APITransaction } from './explorer'
+import {
+ GetFailedTransactionParams,
+ APITransaction,
+ APIPendingTransaction,
+ GetPendingTransactionParams
+} from './explorer'
import { ConfirmationParam } from '../hooks/useMessageConfirmations'
export const getValidatorConfirmation = (
@@ -77,6 +82,26 @@ export const getValidatorFailedTransaction = (
}
}
+export const getValidatorPendingTransaction = (
+ bridgeContract: Contract,
+ messageData: string,
+ getPendingTransactions: (args: GetPendingTransactionParams) => Promise
+) => async (validatorData: ConfirmationParam): Promise => {
+ const failedTransactions = await getPendingTransactions({
+ account: validatorData.validator,
+ to: bridgeContract.options.address,
+ messageData
+ })
+
+ const newStatus =
+ failedTransactions.length > 0 ? VALIDATOR_CONFIRMATION_STATUS.PENDING : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
+
+ return {
+ validator: validatorData.validator,
+ status: newStatus
+ }
+}
+
export const getConfirmationsForTx = async (
messageData: string,
web3: Maybe,
@@ -90,7 +115,9 @@ export const getConfirmationsForTx = async (
subscriptions: number[],
timestamp: number,
getFailedTransactions: (args: GetFailedTransactionParams) => Promise,
- setFailedConfirmations: Function
+ setFailedConfirmations: Function,
+ getPendingTransactions: (args: GetPendingTransactionParams) => Promise,
+ setPendingConfirmations: Function
) => {
if (!web3 || !validatorList || !bridgeContract || !waitingBlocksResolved) return
const hashMsg = web3.utils.soliditySha3Raw(messageData)
@@ -104,9 +131,29 @@ export const getConfirmationsForTx = async (
// If signatures not collected, it needs to retry in the next blocks
if (successConfirmations.length !== requiredSignatures) {
+ // Check if confirmation is pending
+ const validatorPendingConfirmationsChecks = await Promise.all(
+ notSuccessConfirmations.map(getValidatorPendingTransaction(bridgeContract, messageData, getPendingTransactions))
+ )
+ const validatorPendingConfirmations = validatorPendingConfirmationsChecks.filter(
+ c => c.status === VALIDATOR_CONFIRMATION_STATUS.PENDING
+ )
+
+ validatorPendingConfirmations.forEach(validatorData => {
+ const index = validatorConfirmations.findIndex(e => e.validator === validatorData.validator)
+ validatorConfirmations[index] = validatorData
+ })
+
+ if (validatorPendingConfirmations.length > 0) {
+ setPendingConfirmations(true)
+ }
+
+ const undefinedConfirmations = validatorConfirmations.filter(
+ c => c.status === VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
+ )
// Check if confirmation failed
const validatorFailedConfirmationsChecks = await Promise.all(
- notSuccessConfirmations.map(
+ undefinedConfirmations.map(
getValidatorFailedTransaction(bridgeContract, messageData, timestamp, getFailedTransactions)
)
)
@@ -123,7 +170,7 @@ export const getConfirmationsForTx = async (
}
const missingConfirmations = validatorConfirmations.filter(
- c => c.status === VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
+ c => c.status === VALIDATOR_CONFIRMATION_STATUS.UNDEFINED || c.status === VALIDATOR_CONFIRMATION_STATUS.PENDING
)
if (missingConfirmations.length > 0) {
@@ -142,7 +189,9 @@ export const getConfirmationsForTx = async (
subscriptions,
timestamp,
getFailedTransactions,
- setFailedConfirmations
+ setFailedConfirmations,
+ getPendingTransactions,
+ setPendingConfirmations
),
HOME_RPC_POLLING_INTERVAL
)
diff --git a/alm/src/utils/getFinalizationEvent.ts b/alm/src/utils/getFinalizationEvent.ts
index b87e15ed4..1407b2acc 100644
--- a/alm/src/utils/getFinalizationEvent.ts
+++ b/alm/src/utils/getFinalizationEvent.ts
@@ -2,7 +2,12 @@ import { Contract, EventData } from 'web3-eth-contract'
import Web3 from 'web3'
import { CACHE_KEY_EXECUTION_FAILED, THREE_DAYS_TIMESTAMP, VALIDATOR_CONFIRMATION_STATUS } from '../config/constants'
import { ExecutionData } from '../hooks/useMessageConfirmations'
-import { APITransaction, GetFailedTransactionParams } from './explorer'
+import {
+ APIPendingTransaction,
+ APITransaction,
+ GetFailedTransactionParams,
+ GetPendingTransactionParams
+} from './explorer'
import { getBlock, MessageObject } from './web3'
import validatorsCache from '../services/ValidatorsCache'
@@ -18,7 +23,9 @@ export const getFinalizationEvent = async (
timestamp: number,
collectedSignaturesEvent: Maybe,
getFailedExecution: (args: GetFailedTransactionParams) => Promise,
- setFailedExecution: Function
+ setFailedExecution: Function,
+ getPendingExecution: (args: GetPendingTransactionParams) => Promise,
+ setPendingExecution: Function
) => {
if (!contract || !web3 || !waitingBlocksResolved) return
// Since it filters by the message id, only one event will be fetched
@@ -52,33 +59,55 @@ export const getFinalizationEvent = async (
if (collectedSignaturesEvent) {
const validator = collectedSignaturesEvent.returnValues.authorityResponsibleForRelay
- const validatorExecutionCacheKey = `${CACHE_KEY_EXECUTION_FAILED}${validator}`
- const failedFromCache = validatorsCache.get(validatorExecutionCacheKey)
+ const pendingTransactions = await getPendingExecution({
+ account: validator,
+ messageData: message.data,
+ to: contract.options.address
+ })
- if (!failedFromCache) {
- const failedTransactions = await getFailedExecution({
- account: validator,
- to: contract.options.address,
- messageData: message.data,
- startTimestamp: timestamp,
- endTimestamp: timestamp + THREE_DAYS_TIMESTAMP
- })
+ // If the transaction is pending it sets the status and avoid making the request for failed transactions
+ if (pendingTransactions.length > 0) {
+ const pendingTx = pendingTransactions[0]
- if (failedTransactions.length > 0) {
- const failedTx = failedTransactions[0]
+ const nowTimestamp = Math.floor(new Date().getTime() / 1000.0)
- // If validator execution failed, we cache the result to avoid doing future requests for a result that won't change
- validatorsCache.set(validatorExecutionCacheKey, true)
+ setResult({
+ status: VALIDATOR_CONFIRMATION_STATUS.PENDING,
+ validator: validator,
+ txHash: pendingTx.hash,
+ timestamp: nowTimestamp,
+ executionResult: false
+ })
+ setPendingExecution(true)
+ } else {
+ const validatorExecutionCacheKey = `${CACHE_KEY_EXECUTION_FAILED}${validator}`
+ const failedFromCache = validatorsCache.get(validatorExecutionCacheKey)
- const timestamp = parseInt(failedTx.timeStamp)
- setResult({
- status: VALIDATOR_CONFIRMATION_STATUS.FAILED,
- validator: validator,
- txHash: failedTx.hash,
- timestamp,
- executionResult: false
+ if (!failedFromCache) {
+ const failedTransactions = await getFailedExecution({
+ account: validator,
+ to: contract.options.address,
+ messageData: message.data,
+ startTimestamp: timestamp,
+ endTimestamp: timestamp + THREE_DAYS_TIMESTAMP
})
- setFailedExecution(true)
+
+ if (failedTransactions.length > 0) {
+ const failedTx = failedTransactions[0]
+
+ // If validator execution failed, we cache the result to avoid doing future requests for a result that won't change
+ validatorsCache.set(validatorExecutionCacheKey, true)
+
+ const timestamp = parseInt(failedTx.timeStamp)
+ setResult({
+ status: VALIDATOR_CONFIRMATION_STATUS.FAILED,
+ validator: validator,
+ txHash: failedTx.hash,
+ timestamp,
+ executionResult: false
+ })
+ setFailedExecution(true)
+ }
}
}
}
@@ -97,7 +126,9 @@ export const getFinalizationEvent = async (
timestamp,
collectedSignaturesEvent,
getFailedExecution,
- setFailedExecution
+ setFailedExecution,
+ getPendingExecution,
+ setPendingExecution
),
interval
)
From 0eb7c4127878ae278e356db394677853d43a6a82 Mon Sep 17 00:00:00 2001
From: Gerardo Nardelli
Date: Wed, 24 Jun 2020 14:47:12 -0300
Subject: [PATCH 06/13] Build the list of validators and required signatures at
the moment of the transaction (#367)
---
alm/src/components/ConfirmationsContainer.tsx | 12 +++-
.../components/ValidatorsConfirmations.tsx | 12 ++--
alm/src/hooks/useBridgeContracts.ts | 45 +-----------
alm/src/hooks/useMessageConfirmations.ts | 31 +++++----
alm/src/hooks/useValidatorContract.ts | 68 +++++++++++++++++++
alm/src/state/StateProvider.tsx | 26 +------
alm/src/utils/contract.ts | 40 ++++++++++-
7 files changed, 144 insertions(+), 90 deletions(-)
create mode 100644 alm/src/hooks/useValidatorContract.ts
diff --git a/alm/src/components/ConfirmationsContainer.tsx b/alm/src/components/ConfirmationsContainer.tsx
index 34cdb1f00..94272c2b8 100644
--- a/alm/src/components/ConfirmationsContainer.tsx
+++ b/alm/src/components/ConfirmationsContainer.tsx
@@ -10,6 +10,7 @@ import { ValidatorsConfirmations } from './ValidatorsConfirmations'
import { getConfirmationsStatusDescription } from '../utils/networks'
import { useStateProvider } from '../state/StateProvider'
import { ExecutionConfirmation } from './ExecutionConfirmation'
+import { useValidatorContract } from '../hooks/useValidatorContract'
const StatusLabel = styled.label`
font-weight: bold;
@@ -43,11 +44,14 @@ export const ConfirmationsContainer = ({ message, receipt, fromHome, timestamp }
home: { name: homeName },
foreign: { name: foreignName }
} = useStateProvider()
+ const { requiredSignatures, validatorList } = useValidatorContract({ fromHome, receipt })
const { confirmations, status, executionData, signatureCollected } = useMessageConfirmations({
message,
receipt,
fromHome,
- timestamp
+ timestamp,
+ requiredSignatures,
+ validatorList
})
return (
@@ -66,7 +70,11 @@ export const ConfirmationsContainer = ({ message, receipt, fromHome, timestamp }
: ''}
-
+
{signatureCollected && }
diff --git a/alm/src/components/ValidatorsConfirmations.tsx b/alm/src/components/ValidatorsConfirmations.tsx
index 94bdd17bb..fa53a2f27 100644
--- a/alm/src/components/ValidatorsConfirmations.tsx
+++ b/alm/src/components/ValidatorsConfirmations.tsx
@@ -1,6 +1,5 @@
import React from 'react'
import { formatTxHashExtended } from '../utils/networks'
-import { useStateProvider } from '../state/StateProvider'
import { useWindowWidth } from '@react-hook/window-size'
import { VALIDATOR_CONFIRMATION_STATUS } from '../config/constants'
import { SimpleLoading } from './commons/Loading'
@@ -18,12 +17,15 @@ const RequiredConfirmations = styled.label`
export interface ValidatorsConfirmationsParams {
confirmations: Array
+ requiredSignatures: number
+ validatorList: string[]
}
-export const ValidatorsConfirmations = ({ confirmations }: ValidatorsConfirmationsParams) => {
- const {
- home: { requiredSignatures, validatorList }
- } = useStateProvider()
+export const ValidatorsConfirmations = ({
+ confirmations,
+ requiredSignatures,
+ validatorList
+}: ValidatorsConfirmationsParams) => {
const windowWidth = useWindowWidth()
const getValidatorStatusElement = (validatorStatus = '') => {
diff --git a/alm/src/hooks/useBridgeContracts.ts b/alm/src/hooks/useBridgeContracts.ts
index 4e253eec7..e82edff19 100644
--- a/alm/src/hooks/useBridgeContracts.ts
+++ b/alm/src/hooks/useBridgeContracts.ts
@@ -1,14 +1,9 @@
import { useEffect, useState } from 'react'
-import { HOME_AMB_ABI, FOREIGN_AMB_ABI, BRIDGE_VALIDATORS_ABI } from '../../../commons'
+import { HOME_AMB_ABI, FOREIGN_AMB_ABI } from '../../../commons'
import { FOREIGN_BRIDGE_ADDRESS, HOME_BRIDGE_ADDRESS } from '../config/constants'
import { Contract } from 'web3-eth-contract'
import Web3 from 'web3'
-import {
- getRequiredBlockConfirmations,
- getRequiredSignatures,
- getValidatorAddress,
- getValidatorList
-} from '../utils/contract'
+import { getRequiredBlockConfirmations } from '../utils/contract'
export interface useBridgeContractsParams {
homeWeb3: Web3
@@ -20,9 +15,6 @@ export const useBridgeContracts = ({ homeWeb3, foreignWeb3 }: useBridgeContracts
const [foreignBridge, setForeignBridge] = useState>(null)
const [homeBlockConfirmations, setHomeBlockConfirmations] = useState(0)
const [foreignBlockConfirmations, setForeignBlockConfirmations] = useState(0)
- const [homeValidatorContract, setHomeValidatorContract] = useState>(null)
- const [homeRequiredSignatures, setHomeRequiredSignatures] = useState(0)
- const [homeValidatorList, setHomeValidatorList] = useState([])
const callRequireBlockConfirmations = async (contract: Maybe, setResult: Function) => {
if (!contract) return
@@ -30,31 +22,11 @@ export const useBridgeContracts = ({ homeWeb3, foreignWeb3 }: useBridgeContracts
setResult(result)
}
- const callValidatorContract = async (bridgeContract: Maybe, 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, setResult: Function) => {
- if (!contract) return
- const result = await getRequiredSignatures(contract)
- setResult(result)
- }
-
- const callValidatorList = async (contract: Maybe, setResult: Function) => {
- if (!contract) return
- const result = await getValidatorList(contract)
- setResult(result)
- }
-
useEffect(
() => {
if (!homeWeb3) return
const homeContract = new homeWeb3.eth.Contract(HOME_AMB_ABI, HOME_BRIDGE_ADDRESS)
callRequireBlockConfirmations(homeContract, setHomeBlockConfirmations)
- callValidatorContract(homeContract, homeWeb3, setHomeValidatorContract)
setHomeBridge(homeContract)
},
[homeWeb3]
@@ -70,21 +42,10 @@ export const useBridgeContracts = ({ homeWeb3, foreignWeb3 }: useBridgeContracts
[foreignWeb3]
)
- useEffect(
- () => {
- callRequiredSignatures(homeValidatorContract, setHomeRequiredSignatures)
- callValidatorList(homeValidatorContract, setHomeValidatorList)
- },
- [homeValidatorContract]
- )
-
return {
homeBridge,
foreignBridge,
homeBlockConfirmations,
- foreignBlockConfirmations,
- homeValidatorContract,
- homeRequiredSignatures,
- homeValidatorList
+ foreignBlockConfirmations
}
}
diff --git a/alm/src/hooks/useMessageConfirmations.ts b/alm/src/hooks/useMessageConfirmations.ts
index fd6a17749..6faaef2ad 100644
--- a/alm/src/hooks/useMessageConfirmations.ts
+++ b/alm/src/hooks/useMessageConfirmations.ts
@@ -29,6 +29,8 @@ export interface useMessageConfirmationsParams {
receipt: Maybe
fromHome: boolean
timestamp: number
+ requiredSignatures: number
+ validatorList: string[]
}
export interface ConfirmationParam {
@@ -44,7 +46,14 @@ export interface ExecutionData {
executionResult: boolean
}
-export const useMessageConfirmations = ({ message, receipt, fromHome, timestamp }: useMessageConfirmationsParams) => {
+export const useMessageConfirmations = ({
+ message,
+ receipt,
+ fromHome,
+ timestamp,
+ requiredSignatures,
+ validatorList
+}: useMessageConfirmationsParams) => {
const { home, foreign } = useStateProvider()
const [confirmations, setConfirmations] = useState>([])
const [status, setStatus] = useState(CONFIRMATIONS_STATUS.UNDEFINED)
@@ -91,7 +100,7 @@ export const useMessageConfirmations = ({ message, receipt, fromHome, timestamp
targetBlock,
setWaitingBlocks,
setWaitingBlocksResolved,
- home.validatorList,
+ validatorList,
setConfirmations,
blockProvider,
interval,
@@ -103,15 +112,7 @@ export const useMessageConfirmations = ({ message, receipt, fromHome, timestamp
blockProvider.stop()
}
},
- [
- foreign.blockConfirmations,
- foreign.web3,
- fromHome,
- home.blockConfirmations,
- home.validatorList,
- home.web3,
- receipt
- ]
+ [foreign.blockConfirmations, foreign.web3, fromHome, home.blockConfirmations, validatorList, home.web3, receipt]
)
// The collected signature event is only fetched once the signatures are collected on tx from home to foreign, to calculate if
@@ -208,11 +209,11 @@ export const useMessageConfirmations = ({ message, receipt, fromHome, timestamp
getConfirmationsForTx(
message.data,
home.web3,
- home.validatorList,
+ validatorList,
home.bridgeContract,
confirmationContractMethod,
setConfirmations,
- home.requiredSignatures,
+ requiredSignatures,
setSignatureCollected,
waitingBlocksResolved,
subscriptions,
@@ -231,9 +232,9 @@ export const useMessageConfirmations = ({ message, receipt, fromHome, timestamp
fromHome,
message.data,
home.web3,
- home.validatorList,
+ validatorList,
home.bridgeContract,
- home.requiredSignatures,
+ requiredSignatures,
waitingBlocksResolved,
timestamp
]
diff --git a/alm/src/hooks/useValidatorContract.ts b/alm/src/hooks/useValidatorContract.ts
new file mode 100644
index 000000000..c48635741
--- /dev/null
+++ b/alm/src/hooks/useValidatorContract.ts
@@ -0,0 +1,68 @@
+import { useEffect, useState } from 'react'
+import { Contract } from 'web3-eth-contract'
+import Web3 from 'web3'
+import { getRequiredSignatures, getValidatorAddress, getValidatorList } from '../utils/contract'
+import { BRIDGE_VALIDATORS_ABI } from '../../../commons'
+import { useStateProvider } from '../state/StateProvider'
+import { TransactionReceipt } from 'web3-eth'
+
+export interface useValidatorContractParams {
+ fromHome: boolean
+ receipt: Maybe
+}
+
+export const useValidatorContract = ({ receipt, fromHome }: useValidatorContractParams) => {
+ const [validatorContract, setValidatorContract] = useState>(null)
+ const [requiredSignatures, setRequiredSignatures] = useState(0)
+ const [validatorList, setValidatorList] = useState([])
+
+ const { home, foreign } = useStateProvider()
+
+ const callValidatorContract = async (bridgeContract: Maybe, 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,
+ receipt: TransactionReceipt,
+ setResult: Function
+ ) => {
+ if (!contract) return
+ const result = await getRequiredSignatures(contract, receipt.blockNumber)
+ setResult(result)
+ }
+
+ const callValidatorList = async (contract: Maybe, receipt: TransactionReceipt, setResult: Function) => {
+ if (!contract) return
+ const result = await getValidatorList(contract, receipt.blockNumber)
+ setResult(result)
+ }
+
+ useEffect(
+ () => {
+ const web3 = fromHome ? home.web3 : foreign.web3
+ const bridgeContract = fromHome ? home.bridgeContract : foreign.bridgeContract
+
+ if (!web3 || !bridgeContract) return
+ callValidatorContract(bridgeContract, web3, setValidatorContract)
+ },
+ [home.web3, foreign.web3, home.bridgeContract, foreign.bridgeContract, fromHome]
+ )
+
+ useEffect(
+ () => {
+ if (!receipt) return
+ callRequiredSignatures(validatorContract, receipt, setRequiredSignatures)
+ callValidatorList(validatorContract, receipt, setValidatorList)
+ },
+ [validatorContract, receipt]
+ )
+
+ return {
+ requiredSignatures,
+ validatorList
+ }
+}
diff --git a/alm/src/state/StateProvider.tsx b/alm/src/state/StateProvider.tsx
index 0c5172581..3920c0953 100644
--- a/alm/src/state/StateProvider.tsx
+++ b/alm/src/state/StateProvider.tsx
@@ -21,14 +21,8 @@ export interface BaseNetworkParams {
blockConfirmations: number
}
-export interface HomeNetworkParams extends BaseNetworkParams {
- validatorContract: Maybe
- requiredSignatures: number
- validatorList: Array
-}
-
export interface StateContext {
- home: HomeNetworkParams
+ home: BaseNetworkParams
foreign: BaseNetworkParams
loading: boolean
}
@@ -40,10 +34,7 @@ const initialState = {
web3: null,
bridgeAddress: HOME_BRIDGE_ADDRESS,
bridgeContract: null,
- blockConfirmations: 0,
- validatorContract: null,
- requiredSignatures: 0,
- validatorList: []
+ blockConfirmations: 0
},
foreign: {
chainId: 0,
@@ -61,15 +52,7 @@ const StateContext = createContext(initialState)
export const StateProvider = ({ children }: { children: ReactNode }) => {
const homeNetwork = useNetwork(HOME_RPC_URL)
const foreignNetwork = useNetwork(FOREIGN_RPC_URL)
- const {
- homeBridge,
- foreignBridge,
- homeBlockConfirmations,
- foreignBlockConfirmations,
- homeValidatorContract,
- homeRequiredSignatures,
- homeValidatorList
- } = useBridgeContracts({
+ const { homeBridge, foreignBridge, homeBlockConfirmations, foreignBlockConfirmations } = useBridgeContracts({
homeWeb3: homeNetwork.web3,
foreignWeb3: foreignNetwork.web3
})
@@ -80,9 +63,6 @@ export const StateProvider = ({ children }: { children: ReactNode }) => {
name: HOME_NETWORK_NAME,
bridgeContract: homeBridge,
blockConfirmations: homeBlockConfirmations,
- validatorContract: homeValidatorContract,
- requiredSignatures: homeRequiredSignatures,
- validatorList: homeValidatorList,
...homeNetwork
},
foreign: {
diff --git a/alm/src/utils/contract.ts b/alm/src/utils/contract.ts
index 278713d4c..f1e6bd98f 100644
--- a/alm/src/utils/contract.ts
+++ b/alm/src/utils/contract.ts
@@ -7,12 +7,46 @@ export const getRequiredBlockConfirmations = async (contract: Contract) => {
export const getValidatorAddress = (contract: Contract) => contract.methods.validatorContract().call()
-export const getRequiredSignatures = async (contract: Contract) => {
- const requiredSignatures = await contract.methods.requiredSignatures().call()
+export const getRequiredSignatures = async (contract: Contract, blockNumber: number) => {
+ const events = await contract.getPastEvents('RequiredSignaturesChanged', {
+ fromBlock: 0,
+ toBlock: blockNumber
+ })
+
+ // Use the value form last event before the transaction
+ const event = events[events.length - 1]
+ const { requiredSignatures } = event.returnValues
return parseInt(requiredSignatures)
}
-export const getValidatorList = (contract: Contract) => contract.methods.validatorList().call()
+export const getValidatorList = async (contract: Contract, blockNumber: number) => {
+ let currentList: string[] = await contract.methods.validatorList().call()
+ const [added, removed] = await Promise.all([
+ contract.getPastEvents('ValidatorAdded', {
+ fromBlock: blockNumber
+ }),
+ contract.getPastEvents('ValidatorRemoved', {
+ fromBlock: blockNumber
+ })
+ ])
+
+ // Ordered desc
+ const orderedEvents = [...added, ...removed].sort(({ blockNumber: prev }, { blockNumber: next }) => next - prev)
+
+ // Stored as a Set to avoid duplicates
+ const validatorList = new Set(currentList)
+
+ orderedEvents.forEach(e => {
+ const { validator } = e.returnValues
+ if (e.event === 'ValidatorRemoved') {
+ validatorList.add(validator)
+ } else if (e.event === 'ValidatorAdded') {
+ validatorList.delete(validator)
+ }
+ })
+
+ return Array.from(validatorList)
+}
export const getMessagesSigned = (contract: Contract, hash: string) => contract.methods.messagesSigned(hash).call()
From 2ca07e998ad6f1e100cb4cd3c1eb8b3a9e42abaa Mon Sep 17 00:00:00 2001
From: Gerardo Nardelli
Date: Thu, 25 Jun 2020 18:18:54 -0300
Subject: [PATCH 07/13] Display Age field for validator signatures in ALM
(#371)
---
alm/package.json | 1 +
alm/src/components/ExecutionConfirmation.tsx | 2 +-
.../components/ValidatorsConfirmations.tsx | 23 ++-
alm/src/config/constants.ts | 1 +
alm/src/hooks/useMessageConfirmations.ts | 13 +-
alm/src/hooks/useTransactionStatus.ts | 7 +
alm/src/services/ValidatorsCache.ts | 12 ++
alm/src/utils/explorer.ts | 49 ++++-
alm/src/utils/getConfirmationsForTx.ts | 179 ++++++++++++++----
yarn.lock | 5 +
10 files changed, 244 insertions(+), 48 deletions(-)
diff --git a/alm/package.json b/alm/package.json
index 8d45f626c..651193518 100644
--- a/alm/package.json
+++ b/alm/package.json
@@ -14,6 +14,7 @@
"@types/react-dom": "^16.9.0",
"@types/react-router-dom": "^5.1.5",
"@types/styled-components": "^5.1.0",
+ "@use-it/interval": "^0.1.3",
"customize-cra": "^1.0.0",
"date-fns": "^2.14.0",
"fast-memoize": "^2.5.2",
diff --git a/alm/src/components/ExecutionConfirmation.tsx b/alm/src/components/ExecutionConfirmation.tsx
index 5bc40ea5b..d2f5fee5f 100644
--- a/alm/src/components/ExecutionConfirmation.tsx
+++ b/alm/src/components/ExecutionConfirmation.tsx
@@ -57,7 +57,7 @@ export const ExecutionConfirmation = ({ executionData, isHome }: ExecutionConfir
{formattedValidator ? formattedValidator : } |
{getExecutionStatusElement(executionData.status)} |
-
+
{executionData.timestamp > 0 ? formatTimestamp(executionData.timestamp) : ''}
|
diff --git a/alm/src/components/ValidatorsConfirmations.tsx b/alm/src/components/ValidatorsConfirmations.tsx
index fa53a2f27..df8d94def 100644
--- a/alm/src/components/ValidatorsConfirmations.tsx
+++ b/alm/src/components/ValidatorsConfirmations.tsx
@@ -1,11 +1,12 @@
import React from 'react'
-import { formatTxHashExtended } from '../utils/networks'
+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 { ConfirmationParam } from '../hooks/useMessageConfirmations'
import { GreyLabel, RedLabel, SuccessLabel } from './commons/Labels'
+import { ExplorerTxLink } from './commons/ExplorerTxLink'
const Thead = styled.thead`
border-bottom: 2px solid #9e9e9e;
@@ -49,7 +50,8 @@ export const ValidatorsConfirmations = ({
Validator |
- Confirmations |
+ Status |
+ Age |
@@ -57,10 +59,25 @@ export const ValidatorsConfirmations = ({
const filteredConfirmation = confirmations.filter(c => c.validator === validator)
const confirmation = filteredConfirmation.length > 0 ? filteredConfirmation[0] : null
const displayedStatus = confirmation && confirmation.status ? confirmation.status : ''
+ const explorerLink = confirmation && confirmation.txHash ? getExplorerTxUrl(confirmation.txHash, true) : ''
+ const elementIfNoTimestamp =
+ displayedStatus !== VALIDATOR_CONFIRMATION_STATUS.WAITING &&
+ displayedStatus !== VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED ? (
+
+ ) : (
+ ''
+ )
return (
- {windowWidth < 850 ? formatTxHashExtended(validator) : validator} |
+ {windowWidth < 850 ? formatTxHash(validator) : validator} |
{getValidatorStatusElement(displayedStatus)} |
+
+
+ {confirmation && confirmation.timestamp > 0
+ ? formatTimestamp(confirmation.timestamp)
+ : elementIfNoTimestamp}
+
+ |
)
})}
diff --git a/alm/src/config/constants.ts b/alm/src/config/constants.ts
index 5fe96bc9d..09fcb5c6f 100644
--- a/alm/src/config/constants.ts
+++ b/alm/src/config/constants.ts
@@ -23,6 +23,7 @@ export const EXECUTE_AFFIRMATION_HASH = 'e7a2c01f'
export const SUBMIT_SIGNATURE_HASH = '630cea8e'
export const EXECUTE_SIGNATURES_HASH = '3f7658fd'
+export const CACHE_KEY_SUCCESS = 'success-confirmation-validator-'
export const CACHE_KEY_FAILED = 'failed-confirmation-validator-'
export const CACHE_KEY_EXECUTION_FAILED = 'failed-execution-validator-'
diff --git a/alm/src/hooks/useMessageConfirmations.ts b/alm/src/hooks/useMessageConfirmations.ts
index 6faaef2ad..b63457c60 100644
--- a/alm/src/hooks/useMessageConfirmations.ts
+++ b/alm/src/hooks/useMessageConfirmations.ts
@@ -21,7 +21,8 @@ import {
getValidatorFailedTransactionsForMessage,
getExecutionFailedTransactionForMessage,
getValidatorPendingTransactionsForMessage,
- getExecutionPendingTransactionsForMessage
+ getExecutionPendingTransactionsForMessage,
+ getValidatorSuccessTransactionsForMessage
} from '../utils/explorer'
export interface useMessageConfirmationsParams {
@@ -33,11 +34,16 @@ export interface useMessageConfirmationsParams {
validatorList: string[]
}
-export interface ConfirmationParam {
+export interface BasicConfirmationParam {
validator: string
status: string
}
+export interface ConfirmationParam extends BasicConfirmationParam {
+ txHash: string
+ timestamp: number
+}
+
export interface ExecutionData {
status: string
validator: string
@@ -221,7 +227,8 @@ export const useMessageConfirmations = ({
getValidatorFailedTransactionsForMessage,
setFailedConfirmations,
getValidatorPendingTransactionsForMessage,
- setPendingConfirmations
+ setPendingConfirmations,
+ getValidatorSuccessTransactionsForMessage
)
return () => {
diff --git a/alm/src/hooks/useTransactionStatus.ts b/alm/src/hooks/useTransactionStatus.ts
index c6ad73e2a..4c20d5def 100644
--- a/alm/src/hooks/useTransactionStatus.ts
+++ b/alm/src/hooks/useTransactionStatus.ts
@@ -4,6 +4,7 @@ import { HOME_RPC_POLLING_INTERVAL, TRANSACTION_STATUS } from '../config/constan
import { getTransactionStatusDescription } from '../utils/networks'
import { useStateProvider } from '../state/StateProvider'
import { getHomeMessagesFromReceipt, getForeignMessagesFromReceipt, MessageObject, getBlock } from '../utils/web3'
+import useInterval from '@use-it/interval'
export const useTransactionStatus = ({ txHash, chainId }: { txHash: string; chainId: number }) => {
const { home, foreign } = useStateProvider()
@@ -14,6 +15,12 @@ export const useTransactionStatus = ({ txHash, chainId }: { txHash: string; chai
const [timestamp, setTimestamp] = useState(0)
const [loading, setLoading] = useState(true)
+ // Update description so the time displayed is accurate
+ useInterval(() => {
+ if (!status || !timestamp || !description) return
+ setDescription(getTransactionStatusDescription(status, timestamp))
+ }, 30000)
+
useEffect(
() => {
const subscriptions: Array = []
diff --git a/alm/src/services/ValidatorsCache.ts b/alm/src/services/ValidatorsCache.ts
index a3406943e..9708edf3a 100644
--- a/alm/src/services/ValidatorsCache.ts
+++ b/alm/src/services/ValidatorsCache.ts
@@ -1,8 +1,12 @@
+import { ConfirmationParam } from '../hooks/useMessageConfirmations'
+
class ValidatorsCache {
private readonly store: { [key: string]: boolean }
+ private readonly dataStore: { [key: string]: ConfirmationParam }
constructor() {
this.store = {}
+ this.dataStore = {}
}
get(key: string) {
@@ -12,6 +16,14 @@ class ValidatorsCache {
set(key: string, value: boolean) {
this.store[key] = value
}
+
+ getData(key: string) {
+ return this.dataStore[key]
+ }
+
+ setData(key: string, value: ConfirmationParam) {
+ this.dataStore[key] = value
+ }
}
export default new ValidatorsCache()
diff --git a/alm/src/utils/explorer.ts b/alm/src/utils/explorer.ts
index 8d745c58e..8561a6ab5 100644
--- a/alm/src/utils/explorer.ts
+++ b/alm/src/utils/explorer.ts
@@ -154,6 +154,31 @@ export const getFailedTransactions = async (
return transactions.filter(t => t.isError !== '0')
}
+export const getSuccessTransactions = async (
+ account: string,
+ to: string,
+ startTimestamp: number,
+ endTimestamp: number,
+ api: string,
+ fetchAccountTransactions: (args: AccountTransactionsParams) => Promise
+): Promise => {
+ const transactions = await fetchAccountTransactions({ account, to, startTimestamp, endTimestamp, api })
+
+ return transactions.filter(t => t.isError === '0')
+}
+
+export const filterValidatorSignatureTransaction = (
+ transactions: APITransaction[],
+ messageData: string
+): APITransaction[] => {
+ const messageDataValue = messageData.replace('0x', '')
+ return transactions.filter(
+ t =>
+ (t.input.includes(SUBMIT_SIGNATURE_HASH) || t.input.includes(EXECUTE_AFFIRMATION_HASH)) &&
+ t.input.includes(messageDataValue)
+ )
+}
+
export const getValidatorFailedTransactionsForMessage = async ({
account,
to,
@@ -170,12 +195,26 @@ export const getValidatorFailedTransactionsForMessage = async ({
fetchAccountTransactionsFromBlockscout
)
- const messageDataValue = messageData.replace('0x', '')
- return failedTransactions.filter(
- t =>
- (t.input.includes(SUBMIT_SIGNATURE_HASH) || t.input.includes(EXECUTE_AFFIRMATION_HASH)) &&
- t.input.includes(messageDataValue)
+ return filterValidatorSignatureTransaction(failedTransactions, messageData)
+}
+
+export const getValidatorSuccessTransactionsForMessage = async ({
+ account,
+ to,
+ messageData,
+ startTimestamp,
+ endTimestamp
+}: GetFailedTransactionParams): Promise => {
+ const transactions = await getSuccessTransactions(
+ account,
+ to,
+ startTimestamp,
+ endTimestamp,
+ HOME_EXPLORER_API,
+ fetchAccountTransactionsFromBlockscout
)
+
+ return filterValidatorSignatureTransaction(transactions, messageData)
}
export const getExecutionFailedTransactionForMessage = async ({
diff --git a/alm/src/utils/getConfirmationsForTx.ts b/alm/src/utils/getConfirmationsForTx.ts
index f570c6b06..1fa2d7c2e 100644
--- a/alm/src/utils/getConfirmationsForTx.ts
+++ b/alm/src/utils/getConfirmationsForTx.ts
@@ -3,6 +3,7 @@ import { Contract } from 'web3-eth-contract'
import validatorsCache from '../services/ValidatorsCache'
import {
CACHE_KEY_FAILED,
+ CACHE_KEY_SUCCESS,
HOME_RPC_POLLING_INTERVAL,
ONE_DAY_TIMESTAMP,
VALIDATOR_CONFIRMATION_STATUS
@@ -13,14 +14,14 @@ import {
APIPendingTransaction,
GetPendingTransactionParams
} from './explorer'
-import { ConfirmationParam } from '../hooks/useMessageConfirmations'
+import { BasicConfirmationParam, ConfirmationParam } from '../hooks/useMessageConfirmations'
export const getValidatorConfirmation = (
web3: Web3,
hashMsg: string,
bridgeContract: Contract,
confirmationContractMethod: Function
-) => async (validator: string): Promise => {
+) => async (validator: string): Promise => {
const hashSenderMsg = web3.utils.soliditySha3Raw(validator, hashMsg)
const signatureFromCache = validatorsCache.get(hashSenderMsg)
@@ -45,20 +46,65 @@ export const getValidatorConfirmation = (
}
}
+export const getValidatorSuccessTransaction = (
+ bridgeContract: Contract,
+ messageData: string,
+ timestamp: number,
+ getSuccessTransactions: (args: GetFailedTransactionParams) => Promise
+) => async (validatorData: BasicConfirmationParam): Promise => {
+ const { validator } = validatorData
+ const validatorCacheKey = `${CACHE_KEY_SUCCESS}${validatorData.validator}`
+ const fromCache = validatorsCache.getData(validatorCacheKey)
+
+ if (fromCache && fromCache.txHash) {
+ return fromCache
+ }
+
+ const transactions = await getSuccessTransactions({
+ account: validatorData.validator,
+ to: bridgeContract.options.address,
+ messageData,
+ startTimestamp: timestamp,
+ endTimestamp: timestamp + ONE_DAY_TIMESTAMP
+ })
+
+ let txHashTimestamp = 0
+ let txHash = ''
+ const status = VALIDATOR_CONFIRMATION_STATUS.SUCCESS
+
+ if (transactions.length > 0) {
+ const tx = transactions[0]
+ txHashTimestamp = parseInt(tx.timeStamp)
+ txHash = tx.hash
+
+ // cache the result
+ validatorsCache.setData(validatorCacheKey, {
+ validator,
+ status,
+ txHash,
+ timestamp: txHashTimestamp
+ })
+ }
+
+ return {
+ validator,
+ status,
+ txHash,
+ timestamp: txHashTimestamp
+ }
+}
+
export const getValidatorFailedTransaction = (
bridgeContract: Contract,
messageData: string,
timestamp: number,
getFailedTransactions: (args: GetFailedTransactionParams) => Promise
-) => async (validatorData: ConfirmationParam): Promise => {
+) => async (validatorData: BasicConfirmationParam): Promise => {
const validatorCacheKey = `${CACHE_KEY_FAILED}${validatorData.validator}`
- const failedFromCache = validatorsCache.get(validatorCacheKey)
+ const failedFromCache = validatorsCache.getData(validatorCacheKey)
- if (failedFromCache) {
- return {
- validator: validatorData.validator,
- status: VALIDATOR_CONFIRMATION_STATUS.FAILED
- }
+ if (failedFromCache && failedFromCache.txHash) {
+ return failedFromCache
}
const failedTransactions = await getFailedTransactions({
@@ -71,14 +117,27 @@ export const getValidatorFailedTransaction = (
const newStatus =
failedTransactions.length > 0 ? VALIDATOR_CONFIRMATION_STATUS.FAILED : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
+ let txHashTimestamp = 0
+ let txHash = ''
// If validator signature failed, we cache the result to avoid doing future requests for a result that won't change
if (failedTransactions.length > 0) {
- validatorsCache.set(validatorCacheKey, true)
+ const failedTx = failedTransactions[0]
+ txHashTimestamp = parseInt(failedTx.timeStamp)
+ txHash = failedTx.hash
+
+ validatorsCache.setData(validatorCacheKey, {
+ validator: validatorData.validator,
+ status: newStatus,
+ txHash,
+ timestamp: txHashTimestamp
+ })
}
return {
validator: validatorData.validator,
- status: newStatus
+ status: newStatus,
+ txHash,
+ timestamp: txHashTimestamp
}
}
@@ -86,7 +145,7 @@ export const getValidatorPendingTransaction = (
bridgeContract: Contract,
messageData: string,
getPendingTransactions: (args: GetPendingTransactionParams) => Promise
-) => async (validatorData: ConfirmationParam): Promise => {
+) => async (validatorData: BasicConfirmationParam): Promise => {
const failedTransactions = await getPendingTransactions({
account: validatorData.validator,
to: bridgeContract.options.address,
@@ -96,9 +155,20 @@ export const getValidatorPendingTransaction = (
const newStatus =
failedTransactions.length > 0 ? VALIDATOR_CONFIRMATION_STATUS.PENDING : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
+ let timestamp = 0
+ let txHash = ''
+
+ if (failedTransactions.length > 0) {
+ const failedTx = failedTransactions[0]
+ timestamp = Math.floor(new Date().getTime() / 1000.0)
+ txHash = failedTx.hash
+ }
+
return {
validator: validatorData.validator,
- status: newStatus
+ status: newStatus,
+ txHash,
+ timestamp
}
}
@@ -117,9 +187,14 @@ export const getConfirmationsForTx = async (
getFailedTransactions: (args: GetFailedTransactionParams) => Promise,
setFailedConfirmations: Function,
getPendingTransactions: (args: GetPendingTransactionParams) => Promise,
- setPendingConfirmations: Function
+ setPendingConfirmations: Function,
+ getSuccessTransactions: (args: GetFailedTransactionParams) => Promise
) => {
if (!web3 || !validatorList || !bridgeContract || !waitingBlocksResolved) return
+
+ // If all the information was not collected, then it should retry
+ let shouldRetry = false
+
const hashMsg = web3.utils.soliditySha3Raw(messageData)
let validatorConfirmations = await Promise.all(
validatorList.map(getValidatorConfirmation(web3, hashMsg, bridgeContract, confirmationContractMethod))
@@ -174,28 +249,7 @@ export const getConfirmationsForTx = async (
)
if (missingConfirmations.length > 0) {
- const timeoutId = setTimeout(
- () =>
- getConfirmationsForTx(
- messageData,
- web3,
- validatorList,
- bridgeContract,
- confirmationContractMethod,
- setResult,
- requiredSignatures,
- setSignatureCollected,
- waitingBlocksResolved,
- subscriptions,
- timestamp,
- getFailedTransactions,
- setFailedConfirmations,
- getPendingTransactions,
- setPendingConfirmations
- ),
- HOME_RPC_POLLING_INTERVAL
- )
- subscriptions.push(timeoutId)
+ shouldRetry = true
}
} else {
// If signatures collected, it should set other signatures as not required
@@ -207,5 +261,58 @@ export const getConfirmationsForTx = async (
validatorConfirmations = [...successConfirmations, ...notRequiredConfirmations]
setSignatureCollected(true)
}
+
+ // Set confirmations to update UI and continue requesting the transactions for the signatures
setResult(validatorConfirmations)
+
+ // get transactions from success signatures
+ const successConfirmationWithData = await Promise.all(
+ validatorConfirmations
+ .filter(c => c.status === VALIDATOR_CONFIRMATION_STATUS.SUCCESS)
+ .map(getValidatorSuccessTransaction(bridgeContract, messageData, timestamp, getSuccessTransactions))
+ )
+
+ const successConfirmationWithTxFound = successConfirmationWithData.filter(v => v.txHash !== '')
+
+ const updatedValidatorConfirmations = [...validatorConfirmations]
+
+ if (successConfirmationWithTxFound.length > 0) {
+ successConfirmationWithTxFound.forEach(validatorData => {
+ const index = updatedValidatorConfirmations.findIndex(e => e.validator === validatorData.validator)
+ updatedValidatorConfirmations[index] = validatorData
+ })
+ }
+
+ setResult(updatedValidatorConfirmations)
+
+ // Retry if not all transaction were found for validator confirmations
+ if (successConfirmationWithTxFound.length < successConfirmationWithData.length) {
+ shouldRetry = true
+ }
+
+ if (shouldRetry) {
+ const timeoutId = setTimeout(
+ () =>
+ getConfirmationsForTx(
+ messageData,
+ web3,
+ validatorList,
+ bridgeContract,
+ confirmationContractMethod,
+ setResult,
+ requiredSignatures,
+ setSignatureCollected,
+ waitingBlocksResolved,
+ subscriptions,
+ timestamp,
+ getFailedTransactions,
+ setFailedConfirmations,
+ getPendingTransactions,
+ setPendingConfirmations,
+ getSuccessTransactions
+ ),
+ HOME_RPC_POLLING_INTERVAL
+ )
+ subscriptions.push(timeoutId)
+ }
}
diff --git a/yarn.lock b/yarn.lock
index 20ab80397..4edd5fa56 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3220,6 +3220,11 @@
lodash.unescape "4.0.1"
semver "5.5.0"
+"@use-it/interval@^0.1.3":
+ version "0.1.3"
+ resolved "https://registry.yarnpkg.com/@use-it/interval/-/interval-0.1.3.tgz#5d1096b2295d7a5dda8e8022f3abb5f9d9ef27f8"
+ integrity sha512-chshdtDZTFoWA9aszBz1Cc04Ca9NBD2JTi/GMjdJ+HGm4q7Vy1v71+2mm22r7Kfb2nYW+lTRsPcEHdB/VFVHsQ==
+
"@web3-js/scrypt-shim@^0.1.0":
version "0.1.0"
resolved "https://registry.yarnpkg.com/@web3-js/scrypt-shim/-/scrypt-shim-0.1.0.tgz#0bf7529ab6788311d3e07586f7d89107c3bea2cc"
From 4a727dc15954532a9689017b1be2279b8470f537 Mon Sep 17 00:00:00 2001
From: Gerardo Nardelli
Date: Fri, 26 Jun 2020 12:47:45 -0300
Subject: [PATCH 08/13] Add ALM new styles (#373)
---
.eslintignore | 1 +
alm/public/index.html | 1 +
alm/src/App.tsx | 5 +-
alm/src/abis/BridgeValidators.ts | 319 +++++++
alm/src/abis/ForeignAMB.ts | 589 +++++++++++++
alm/src/abis/HomeAMB.ts | 777 ++++++++++++++++++
alm/src/abis/index.ts | 3 +
alm/src/components/ConfirmationsContainer.tsx | 2 +-
alm/src/components/Form.tsx | 24 +-
alm/src/components/MainPage.tsx | 76 +-
alm/src/components/MessageSelector.tsx | 2 +-
alm/src/components/StatusContainer.tsx | 40 +-
alm/src/components/commons/Button.tsx | 5 +
alm/src/components/commons/ExplorerTxLink.tsx | 1 +
alm/src/components/commons/LeftArrow.tsx | 2 +-
alm/src/components/commons/Loading.tsx | 308 +++----
alm/src/hooks/useBridgeContracts.ts | 2 +-
alm/src/hooks/useMessageConfirmations.ts | 2 +-
alm/src/hooks/useValidatorContract.ts | 2 +-
alm/src/index.tsx | 4 +-
alm/src/themes/Dark.tsx | 1 +
alm/src/themes/GlobalStyle.tsx | 3 +-
alm/src/themes/Light.ts | 22 +
alm/src/utils/getConfirmationsForTx.ts | 3 +-
alm/src/utils/web3.ts | 2 +-
25 files changed, 1990 insertions(+), 206 deletions(-)
create mode 100644 alm/src/abis/BridgeValidators.ts
create mode 100644 alm/src/abis/ForeignAMB.ts
create mode 100644 alm/src/abis/HomeAMB.ts
create mode 100644 alm/src/abis/index.ts
create mode 100644 alm/src/themes/Light.ts
diff --git a/.eslintignore b/.eslintignore
index 08d0d3d48..2fc7af035 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -3,3 +3,4 @@ submodules
coverage
lib
dist
+build
diff --git a/alm/public/index.html b/alm/public/index.html
index 89efacd59..36f04479a 100644
--- a/alm/public/index.html
+++ b/alm/public/index.html
@@ -25,6 +25,7 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
+
AMB Live Monitoring
diff --git a/alm/src/App.tsx b/alm/src/App.tsx
index 524c6e653..3ab3eaf66 100644
--- a/alm/src/App.tsx
+++ b/alm/src/App.tsx
@@ -1,11 +1,14 @@
import React from 'react'
import { BrowserRouter } from 'react-router-dom'
import { MainPage } from './components/MainPage'
+import { StateProvider } from './state/StateProvider'
function App() {
return (
-
+
+
+
)
}
diff --git a/alm/src/abis/BridgeValidators.ts b/alm/src/abis/BridgeValidators.ts
new file mode 100644
index 000000000..10fa0b52e
--- /dev/null
+++ b/alm/src/abis/BridgeValidators.ts
@@ -0,0 +1,319 @@
+import { AbiItem } from 'web3-utils'
+
+const abi: AbiItem[] = [
+ {
+ constant: true,
+ inputs: [],
+ name: 'validatorCount',
+ outputs: [
+ {
+ name: '',
+ type: 'uint256'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'getBridgeValidatorsInterfacesVersion',
+ outputs: [
+ {
+ name: 'major',
+ type: 'uint64'
+ },
+ {
+ name: 'minor',
+ type: 'uint64'
+ },
+ {
+ name: 'patch',
+ type: 'uint64'
+ }
+ ],
+ payable: false,
+ stateMutability: 'pure',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'isInitialized',
+ outputs: [
+ {
+ name: '',
+ type: 'bool'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'validatorList',
+ outputs: [
+ {
+ name: '',
+ type: 'address[]'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: '_requiredSignatures',
+ type: 'uint256'
+ }
+ ],
+ name: 'setRequiredSignatures',
+ outputs: [],
+ payable: false,
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'requiredSignatures',
+ outputs: [
+ {
+ name: '',
+ type: 'uint256'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [
+ {
+ name: '_address',
+ type: 'address'
+ }
+ ],
+ name: 'getNextValidator',
+ outputs: [
+ {
+ name: '',
+ type: 'address'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'owner',
+ outputs: [
+ {
+ name: '',
+ type: 'address'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [
+ {
+ name: '_validator',
+ type: 'address'
+ }
+ ],
+ name: 'isValidatorDuty',
+ outputs: [
+ {
+ name: '',
+ type: 'bool'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'deployedAtBlock',
+ outputs: [
+ {
+ name: '',
+ type: 'uint256'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'F_ADDR',
+ outputs: [
+ {
+ name: '',
+ type: 'address'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: 'newOwner',
+ type: 'address'
+ }
+ ],
+ name: 'transferOwnership',
+ outputs: [],
+ payable: false,
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [
+ {
+ name: '_validator',
+ type: 'address'
+ }
+ ],
+ name: 'isValidator',
+ outputs: [
+ {
+ name: '',
+ type: 'bool'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ name: 'validator',
+ type: 'address'
+ }
+ ],
+ name: 'ValidatorAdded',
+ type: 'event'
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ name: 'validator',
+ type: 'address'
+ }
+ ],
+ name: 'ValidatorRemoved',
+ type: 'event'
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ name: 'requiredSignatures',
+ type: 'uint256'
+ }
+ ],
+ name: 'RequiredSignaturesChanged',
+ type: 'event'
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ name: 'previousOwner',
+ type: 'address'
+ },
+ {
+ indexed: false,
+ name: 'newOwner',
+ type: 'address'
+ }
+ ],
+ name: 'OwnershipTransferred',
+ type: 'event'
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: '_requiredSignatures',
+ type: 'uint256'
+ },
+ {
+ name: '_initialValidators',
+ type: 'address[]'
+ },
+ {
+ name: '_owner',
+ type: 'address'
+ }
+ ],
+ name: 'initialize',
+ outputs: [
+ {
+ name: '',
+ type: 'bool'
+ }
+ ],
+ payable: false,
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: '_validator',
+ type: 'address'
+ }
+ ],
+ name: 'addValidator',
+ outputs: [],
+ payable: false,
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: '_validator',
+ type: 'address'
+ }
+ ],
+ name: 'removeValidator',
+ outputs: [],
+ payable: false,
+ stateMutability: 'nonpayable',
+ type: 'function'
+ }
+]
+
+export default abi
diff --git a/alm/src/abis/ForeignAMB.ts b/alm/src/abis/ForeignAMB.ts
new file mode 100644
index 000000000..d49572e69
--- /dev/null
+++ b/alm/src/abis/ForeignAMB.ts
@@ -0,0 +1,589 @@
+import { AbiItem } from 'web3-utils'
+
+const abi: AbiItem[] = [
+ {
+ constant: true,
+ inputs: [],
+ name: 'transactionHash',
+ outputs: [
+ {
+ name: '',
+ type: 'bytes32'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [
+ {
+ name: '_txHash',
+ type: 'bytes32'
+ }
+ ],
+ name: 'relayedMessages',
+ outputs: [
+ {
+ name: '',
+ type: 'bool'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: '_sourceChainId',
+ type: 'uint256'
+ },
+ {
+ name: '_destinationChainId',
+ type: 'uint256'
+ },
+ {
+ name: '_validatorContract',
+ type: 'address'
+ },
+ {
+ name: '_maxGasPerTx',
+ type: 'uint256'
+ },
+ {
+ name: '_gasPrice',
+ type: 'uint256'
+ },
+ {
+ name: '_requiredBlockConfirmations',
+ type: 'uint256'
+ },
+ {
+ name: '_owner',
+ type: 'address'
+ }
+ ],
+ name: 'initialize',
+ outputs: [
+ {
+ name: '',
+ type: 'bool'
+ }
+ ],
+ payable: false,
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'isInitialized',
+ outputs: [
+ {
+ name: '',
+ type: 'bool'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'requiredBlockConfirmations',
+ outputs: [
+ {
+ name: '',
+ type: 'uint256'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: '_data',
+ type: 'bytes'
+ },
+ {
+ name: '_signatures',
+ type: 'bytes'
+ }
+ ],
+ name: 'executeSignatures',
+ outputs: [],
+ payable: false,
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [
+ {
+ name: '_data',
+ type: 'bytes'
+ }
+ ],
+ name: 'getMinimumGasUsage',
+ outputs: [
+ {
+ name: 'gas',
+ type: 'uint256'
+ }
+ ],
+ payable: false,
+ stateMutability: 'pure',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [
+ {
+ name: '_messageId',
+ type: 'bytes32'
+ }
+ ],
+ name: 'failedMessageReceiver',
+ outputs: [
+ {
+ name: '',
+ type: 'address'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'getBridgeMode',
+ outputs: [
+ {
+ name: '_data',
+ type: 'bytes4'
+ }
+ ],
+ payable: false,
+ stateMutability: 'pure',
+ type: 'function'
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: '_sourceChainId',
+ type: 'uint256'
+ },
+ {
+ name: '_destinationChainId',
+ type: 'uint256'
+ }
+ ],
+ name: 'setChainIds',
+ outputs: [],
+ payable: false,
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [
+ {
+ name: '_messageId',
+ type: 'bytes32'
+ }
+ ],
+ name: 'failedMessageSender',
+ outputs: [
+ {
+ name: '',
+ type: 'address'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'messageId',
+ outputs: [
+ {
+ name: '',
+ type: 'bytes32'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: '_token',
+ type: 'address'
+ },
+ {
+ name: '_to',
+ type: 'address'
+ }
+ ],
+ name: 'claimTokens',
+ outputs: [],
+ payable: false,
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: '_maxGasPerTx',
+ type: 'uint256'
+ }
+ ],
+ name: 'setMaxGasPerTx',
+ outputs: [],
+ payable: false,
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'requiredSignatures',
+ outputs: [
+ {
+ name: '',
+ type: 'uint256'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'owner',
+ outputs: [
+ {
+ name: '',
+ type: 'address'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'validatorContract',
+ outputs: [
+ {
+ name: '',
+ type: 'address'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'deployedAtBlock',
+ outputs: [
+ {
+ name: '',
+ type: 'uint256'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'getBridgeInterfacesVersion',
+ outputs: [
+ {
+ name: 'major',
+ type: 'uint64'
+ },
+ {
+ name: 'minor',
+ type: 'uint64'
+ },
+ {
+ name: 'patch',
+ type: 'uint64'
+ }
+ ],
+ payable: false,
+ stateMutability: 'pure',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'messageSourceChainId',
+ outputs: [
+ {
+ name: '',
+ type: 'uint256'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: '_blockConfirmations',
+ type: 'uint256'
+ }
+ ],
+ name: 'setRequiredBlockConfirmations',
+ outputs: [],
+ payable: false,
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: '_gasPrice',
+ type: 'uint256'
+ }
+ ],
+ name: 'setGasPrice',
+ outputs: [],
+ payable: false,
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [
+ {
+ name: '_messageId',
+ type: 'bytes32'
+ }
+ ],
+ name: 'messageCallStatus',
+ outputs: [
+ {
+ name: '',
+ type: 'bool'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'messageSender',
+ outputs: [
+ {
+ name: '',
+ type: 'address'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: '_contract',
+ type: 'address'
+ },
+ {
+ name: '_data',
+ type: 'bytes'
+ },
+ {
+ name: '_gas',
+ type: 'uint256'
+ }
+ ],
+ name: 'requireToPassMessage',
+ outputs: [
+ {
+ name: '',
+ type: 'bytes32'
+ }
+ ],
+ payable: false,
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [
+ {
+ name: '_messageId',
+ type: 'bytes32'
+ }
+ ],
+ name: 'failedMessageDataHash',
+ outputs: [
+ {
+ name: '',
+ type: 'bytes32'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'maxGasPerTx',
+ outputs: [
+ {
+ name: '',
+ type: 'uint256'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: 'newOwner',
+ type: 'address'
+ }
+ ],
+ name: 'transferOwnership',
+ outputs: [],
+ payable: false,
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'gasPrice',
+ outputs: [
+ {
+ name: '',
+ type: 'uint256'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ name: 'messageId',
+ type: 'bytes32'
+ },
+ {
+ indexed: false,
+ name: 'encodedData',
+ type: 'bytes'
+ }
+ ],
+ name: 'UserRequestForAffirmation',
+ type: 'event'
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ name: 'sender',
+ type: 'address'
+ },
+ {
+ indexed: true,
+ name: 'executor',
+ type: 'address'
+ },
+ {
+ indexed: true,
+ name: 'messageId',
+ type: 'bytes32'
+ },
+ {
+ indexed: false,
+ name: 'status',
+ type: 'bool'
+ }
+ ],
+ name: 'RelayedMessage',
+ type: 'event'
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ name: 'gasPrice',
+ type: 'uint256'
+ }
+ ],
+ name: 'GasPriceChanged',
+ type: 'event'
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ name: 'requiredBlockConfirmations',
+ type: 'uint256'
+ }
+ ],
+ name: 'RequiredBlockConfirmationChanged',
+ type: 'event'
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ name: 'previousOwner',
+ type: 'address'
+ },
+ {
+ indexed: false,
+ name: 'newOwner',
+ type: 'address'
+ }
+ ],
+ name: 'OwnershipTransferred',
+ type: 'event'
+ }
+]
+
+export default abi
diff --git a/alm/src/abis/HomeAMB.ts b/alm/src/abis/HomeAMB.ts
new file mode 100644
index 000000000..8236299c6
--- /dev/null
+++ b/alm/src/abis/HomeAMB.ts
@@ -0,0 +1,777 @@
+import { AbiItem } from 'web3-utils'
+
+const abi: AbiItem[] = [
+ {
+ constant: true,
+ inputs: [],
+ name: 'transactionHash',
+ outputs: [
+ {
+ name: '',
+ type: 'bytes32'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [
+ {
+ name: '_message',
+ type: 'bytes32'
+ }
+ ],
+ name: 'numMessagesSigned',
+ outputs: [
+ {
+ name: '',
+ type: 'uint256'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [
+ {
+ name: '_hash',
+ type: 'bytes32'
+ },
+ {
+ name: '_index',
+ type: 'uint256'
+ }
+ ],
+ name: 'signature',
+ outputs: [
+ {
+ name: '',
+ type: 'bytes'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: '_sourceChainId',
+ type: 'uint256'
+ },
+ {
+ name: '_destinationChainId',
+ type: 'uint256'
+ },
+ {
+ name: '_validatorContract',
+ type: 'address'
+ },
+ {
+ name: '_maxGasPerTx',
+ type: 'uint256'
+ },
+ {
+ name: '_gasPrice',
+ type: 'uint256'
+ },
+ {
+ name: '_requiredBlockConfirmations',
+ type: 'uint256'
+ },
+ {
+ name: '_owner',
+ type: 'address'
+ }
+ ],
+ name: 'initialize',
+ outputs: [
+ {
+ name: '',
+ type: 'bool'
+ }
+ ],
+ payable: false,
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'isInitialized',
+ outputs: [
+ {
+ name: '',
+ type: 'bool'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'requiredBlockConfirmations',
+ outputs: [
+ {
+ name: '',
+ type: 'uint256'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [
+ {
+ name: '_data',
+ type: 'bytes'
+ }
+ ],
+ name: 'getMinimumGasUsage',
+ outputs: [
+ {
+ name: 'gas',
+ type: 'uint256'
+ }
+ ],
+ payable: false,
+ stateMutability: 'pure',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [
+ {
+ name: '_messageId',
+ type: 'bytes32'
+ }
+ ],
+ name: 'failedMessageReceiver',
+ outputs: [
+ {
+ name: '',
+ type: 'address'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'getBridgeMode',
+ outputs: [
+ {
+ name: '_data',
+ type: 'bytes4'
+ }
+ ],
+ payable: false,
+ stateMutability: 'pure',
+ type: 'function'
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: '_sourceChainId',
+ type: 'uint256'
+ },
+ {
+ name: '_destinationChainId',
+ type: 'uint256'
+ }
+ ],
+ name: 'setChainIds',
+ outputs: [],
+ payable: false,
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [
+ {
+ name: '_hash',
+ type: 'bytes32'
+ }
+ ],
+ name: 'message',
+ outputs: [
+ {
+ name: '',
+ type: 'bytes'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [
+ {
+ name: '_messageId',
+ type: 'bytes32'
+ }
+ ],
+ name: 'failedMessageSender',
+ outputs: [
+ {
+ name: '',
+ type: 'address'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: 'signature',
+ type: 'bytes'
+ },
+ {
+ name: 'message',
+ type: 'bytes'
+ }
+ ],
+ name: 'submitSignature',
+ outputs: [],
+ payable: false,
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'messageId',
+ outputs: [
+ {
+ name: '',
+ type: 'bytes32'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: '_token',
+ type: 'address'
+ },
+ {
+ name: '_to',
+ type: 'address'
+ }
+ ],
+ name: 'claimTokens',
+ outputs: [],
+ payable: false,
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [
+ {
+ name: '_hash',
+ type: 'bytes32'
+ }
+ ],
+ name: 'numAffirmationsSigned',
+ outputs: [
+ {
+ name: '',
+ type: 'uint256'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [
+ {
+ name: '_hash',
+ type: 'bytes32'
+ }
+ ],
+ name: 'affirmationsSigned',
+ outputs: [
+ {
+ name: '',
+ type: 'bool'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: '_maxGasPerTx',
+ type: 'uint256'
+ }
+ ],
+ name: 'setMaxGasPerTx',
+ outputs: [],
+ payable: false,
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'requiredSignatures',
+ outputs: [
+ {
+ name: '',
+ type: 'uint256'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'owner',
+ outputs: [
+ {
+ name: '',
+ type: 'address'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [
+ {
+ name: '_message',
+ type: 'bytes32'
+ }
+ ],
+ name: 'messagesSigned',
+ outputs: [
+ {
+ name: '',
+ type: 'bool'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'validatorContract',
+ outputs: [
+ {
+ name: '',
+ type: 'address'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'deployedAtBlock',
+ outputs: [
+ {
+ name: '',
+ type: 'uint256'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'getBridgeInterfacesVersion',
+ outputs: [
+ {
+ name: 'major',
+ type: 'uint64'
+ },
+ {
+ name: 'minor',
+ type: 'uint64'
+ },
+ {
+ name: 'patch',
+ type: 'uint64'
+ }
+ ],
+ payable: false,
+ stateMutability: 'pure',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'messageSourceChainId',
+ outputs: [
+ {
+ name: '',
+ type: 'uint256'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: '_blockConfirmations',
+ type: 'uint256'
+ }
+ ],
+ name: 'setRequiredBlockConfirmations',
+ outputs: [],
+ payable: false,
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: '_gasPrice',
+ type: 'uint256'
+ }
+ ],
+ name: 'setGasPrice',
+ outputs: [],
+ payable: false,
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [
+ {
+ name: '_messageId',
+ type: 'bytes32'
+ }
+ ],
+ name: 'messageCallStatus',
+ outputs: [
+ {
+ name: '',
+ type: 'bool'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'messageSender',
+ outputs: [
+ {
+ name: '',
+ type: 'address'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: '_contract',
+ type: 'address'
+ },
+ {
+ name: '_data',
+ type: 'bytes'
+ },
+ {
+ name: '_gas',
+ type: 'uint256'
+ }
+ ],
+ name: 'requireToPassMessage',
+ outputs: [
+ {
+ name: '',
+ type: 'bytes32'
+ }
+ ],
+ payable: false,
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [
+ {
+ name: '_messageId',
+ type: 'bytes32'
+ }
+ ],
+ name: 'failedMessageDataHash',
+ outputs: [
+ {
+ name: '',
+ type: 'bytes32'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'maxGasPerTx',
+ outputs: [
+ {
+ name: '',
+ type: 'uint256'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: 'message',
+ type: 'bytes'
+ }
+ ],
+ name: 'executeAffirmation',
+ outputs: [],
+ payable: false,
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: 'newOwner',
+ type: 'address'
+ }
+ ],
+ name: 'transferOwnership',
+ outputs: [],
+ payable: false,
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'gasPrice',
+ outputs: [
+ {
+ name: '',
+ type: 'uint256'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [
+ {
+ name: '_number',
+ type: 'uint256'
+ }
+ ],
+ name: 'isAlreadyProcessed',
+ outputs: [
+ {
+ name: '',
+ type: 'bool'
+ }
+ ],
+ payable: false,
+ stateMutability: 'pure',
+ type: 'function'
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ name: 'messageId',
+ type: 'bytes32'
+ },
+ {
+ indexed: false,
+ name: 'encodedData',
+ type: 'bytes'
+ }
+ ],
+ name: 'UserRequestForSignature',
+ type: 'event'
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ name: 'sender',
+ type: 'address'
+ },
+ {
+ indexed: true,
+ name: 'executor',
+ type: 'address'
+ },
+ {
+ indexed: true,
+ name: 'messageId',
+ type: 'bytes32'
+ },
+ {
+ indexed: false,
+ name: 'status',
+ type: 'bool'
+ }
+ ],
+ name: 'AffirmationCompleted',
+ type: 'event'
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ name: 'signer',
+ type: 'address'
+ },
+ {
+ indexed: false,
+ name: 'messageHash',
+ type: 'bytes32'
+ }
+ ],
+ name: 'SignedForUserRequest',
+ type: 'event'
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ name: 'signer',
+ type: 'address'
+ },
+ {
+ indexed: false,
+ name: 'messageHash',
+ type: 'bytes32'
+ }
+ ],
+ name: 'SignedForAffirmation',
+ type: 'event'
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ name: 'authorityResponsibleForRelay',
+ type: 'address'
+ },
+ {
+ indexed: false,
+ name: 'messageHash',
+ type: 'bytes32'
+ },
+ {
+ indexed: false,
+ name: 'NumberOfCollectedSignatures',
+ type: 'uint256'
+ }
+ ],
+ name: 'CollectedSignatures',
+ type: 'event'
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ name: 'gasPrice',
+ type: 'uint256'
+ }
+ ],
+ name: 'GasPriceChanged',
+ type: 'event'
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ name: 'requiredBlockConfirmations',
+ type: 'uint256'
+ }
+ ],
+ name: 'RequiredBlockConfirmationChanged',
+ type: 'event'
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ name: 'previousOwner',
+ type: 'address'
+ },
+ {
+ indexed: false,
+ name: 'newOwner',
+ type: 'address'
+ }
+ ],
+ name: 'OwnershipTransferred',
+ type: 'event'
+ }
+]
+
+export default abi
diff --git a/alm/src/abis/index.ts b/alm/src/abis/index.ts
new file mode 100644
index 000000000..b49359630
--- /dev/null
+++ b/alm/src/abis/index.ts
@@ -0,0 +1,3 @@
+export { default as HOME_AMB_ABI } from './HomeAMB'
+export { default as FOREIGN_AMB_ABI } from './ForeignAMB'
+export { default as BRIDGE_VALIDATORS_ABI } from './BridgeValidators'
diff --git a/alm/src/components/ConfirmationsContainer.tsx b/alm/src/components/ConfirmationsContainer.tsx
index 94272c2b8..ead23412d 100644
--- a/alm/src/components/ConfirmationsContainer.tsx
+++ b/alm/src/components/ConfirmationsContainer.tsx
@@ -23,7 +23,7 @@ const StatusResultLabel = styled.label`
`
const StyledConfirmationContainer = styled.div`
- background-color: var(--color-primary);
+ background-color: var(--bg-color);
padding: 10px;
border-radius: 4px;
`
diff --git a/alm/src/components/Form.tsx b/alm/src/components/Form.tsx
index 9576c1c3f..222dd4477 100644
--- a/alm/src/components/Form.tsx
+++ b/alm/src/components/Form.tsx
@@ -12,27 +12,39 @@ const LabelText = styled.label`
`
const Input = styled.input`
- background-color: var(--color-primary);
+ background-color: var(--bg-color);
color: var(--font-color);
max-width: 100%;
+ border-color: var(--color-primary) !important;
+ &:hover,
+ &:active,
+ &:focus {
+ border-color: var(--button-color) !important;
+ }
`
-export const Form = ({ onSubmit }: { onSubmit: ({ chainId, txHash }: FormSubmitParams) => void }) => {
+export const Form = ({
+ onSubmit,
+ lastUsedChain
+}: {
+ onSubmit: ({ chainId, txHash }: FormSubmitParams) => void
+ lastUsedChain: number
+}) => {
const { home, foreign, loading } = useStateProvider()
const { chainId: paramChainId, txHash: paramTxHash } = useParams()
- const [chainId, setChainId] = useState(0)
+ const [chainId, setChainId] = useState(lastUsedChain)
const [txHash, setTxHash] = useState('')
useEffect(
() => {
if (!paramChainId) {
- setChainId(foreign.chainId)
+ setChainId(lastUsedChain > 0 ? lastUsedChain : foreign.chainId)
} else {
setChainId(parseInt(paramChainId))
setTxHash(paramTxHash)
}
},
- [foreign.chainId, paramChainId, paramTxHash]
+ [foreign.chainId, paramChainId, paramTxHash, lastUsedChain]
)
const formSubmit = (e: FormEvent) => {
@@ -55,7 +67,7 @@ export const Form = ({ onSubmit }: { onSubmit: ({ chainId, txHash }: FormSubmitP
/>
-
diff --git a/alm/src/components/MainPage.tsx b/alm/src/components/MainPage.tsx
index 9eeec8361..61867b6e9 100644
--- a/alm/src/components/MainPage.tsx
+++ b/alm/src/components/MainPage.tsx
@@ -1,9 +1,9 @@
-import React from 'react'
+import React, { useState } from 'react'
import styled from 'styled-components'
-import { Route, useHistory, Link } from 'react-router-dom'
+import { Route, useHistory } from 'react-router-dom'
import { Form } from './Form'
import { StatusContainer } from './StatusContainer'
-import { StateProvider } from '../state/StateProvider'
+import { useStateProvider } from '../state/StateProvider'
const StyledMainPage = styled.div`
text-align: center;
@@ -11,15 +11,24 @@ const StyledMainPage = styled.div`
`
const Header = styled.header`
+ background-color: #001529;
+ color: #ffffff;
+ margin-bottom: 50px;
+`
+
+const HeaderContainer = styled.header`
display: flex;
- flex-direction: column;
+ flex-direction: row;
align-items: center;
- justify-content: center;
- font-size: calc(10px + 2vmin);
-`
+ justify-content: space-between;
+ font-size: 16px;
+ height: 64px;
+ line-height: 64px;
+ padding: 0 50px;
-const Title = styled.p`
- color: var(--font-color);
+ @media (max-width: 600px) {
+ padding: 0 20px;
+ }
`
export interface FormSubmitParams {
@@ -29,23 +38,46 @@ export interface FormSubmitParams {
export const MainPage = () => {
const history = useHistory()
+ const { home, foreign } = useStateProvider()
+ const [selectedChainId, setSelectedChainId] = useState(0)
+ const [networkName, setNetworkName] = useState('')
+
+ const setNetworkData = (chainId: number) => {
+ const network = chainId === home.chainId ? home.name : foreign.name
+
+ setNetworkName(network)
+ setSelectedChainId(chainId)
+ }
+
const onFormSubmit = ({ chainId, txHash }: FormSubmitParams) => {
+ setNetworkData(chainId)
+
history.push(`/${chainId}/${txHash}`)
}
+ const resetNetworkHeader = () => {
+ setNetworkName('')
+ }
+
+ const setNetworkFromParams = (chainId: number) => {
+ setNetworkData(chainId)
+ }
+
return (
-
-
-
-
- AMB Live Monitoring
-
-
-
- } />
- } />
-
-
-
+
+
+
+ AMB Live Monitoring
+ {networkName}
+
+
+
+ } />
+ }
+ />
+
+
)
}
diff --git a/alm/src/components/MessageSelector.tsx b/alm/src/components/MessageSelector.tsx
index 32aaa3eca..7332e2b25 100644
--- a/alm/src/components/MessageSelector.tsx
+++ b/alm/src/components/MessageSelector.tsx
@@ -38,7 +38,7 @@ export const MessageSelector = ({ messages, onMessageSelected }: MessageSelector
))}
-
+
Select
diff --git a/alm/src/components/StatusContainer.tsx b/alm/src/components/StatusContainer.tsx
index a8d0d000c..99e1d8a28 100644
--- a/alm/src/components/StatusContainer.tsx
+++ b/alm/src/components/StatusContainer.tsx
@@ -1,4 +1,4 @@
-import React from 'react'
+import React, { useEffect } from 'react'
import { Link, useHistory, useParams } from 'react-router-dom'
import { useTransactionStatus } from '../hooks/useTransactionStatus'
import { formatTxHash, getExplorerTxUrl, getTransactionStatusDescription, validTxHash } from '../utils/networks'
@@ -12,9 +12,12 @@ import { LeftArrow } from './commons/LeftArrow'
import styled from 'styled-components'
const BackButton = styled.button`
- color: var(--font-color);
+ color: var(--button-color);
border-color: var(--font-color);
margin-top: 10px;
+ &:focus {
+ outline: var(--button-color);
+ }
`
const BackLabel = styled.label`
@@ -22,7 +25,12 @@ const BackLabel = styled.label`
cursor: pointer;
`
-export const StatusContainer = () => {
+export interface StatusContainerParam {
+ onBackToMain: () => void
+ setNetworkFromParams: (chainId: number) => void
+}
+
+export const StatusContainer = ({ onBackToMain, setNetworkFromParams }: StatusContainerParam) => {
const { home, foreign } = useStateProvider()
const history = useHistory()
const { chainId, txHash, messageIdParam } = useParams()
@@ -36,6 +44,15 @@ export const StatusContainer = () => {
const selectedMessageId = messageIdParam === undefined || messages[messageIdParam] === undefined ? -1 : messageIdParam
+ useEffect(
+ () => {
+ if (validChainId) {
+ setNetworkFromParams(parseInt(chainId))
+ }
+ },
+ [validChainId, chainId, setNetworkFromParams]
+ )
+
if (!validParameters && home.chainId && foreign.chainId) {
return (
@@ -75,15 +92,12 @@ export const StatusContainer = () => {
{status && (
The request{' '}
-
- {displayExplorerLink && (
-
- {formattedMessageId}
-
- )}
- {!displayExplorerLink && }
- {' '}
- {displayedDescription}
+ {displayExplorerLink && (
+
+ {formattedMessageId}
+
+ )}
+ {!displayExplorerLink && } {displayedDescription}
)}
{displayMessageSelector &&
}
@@ -92,7 +106,7 @@ export const StatusContainer = () => {
)}
-
+
Search another transaction
diff --git a/alm/src/components/commons/Button.tsx b/alm/src/components/commons/Button.tsx
index faeecbb6f..248590e93 100644
--- a/alm/src/components/commons/Button.tsx
+++ b/alm/src/components/commons/Button.tsx
@@ -2,4 +2,9 @@ import styled from 'styled-components'
export const Button = styled.button`
height: 36px;
+ color: var(--button-color);
+ border-color: var(--button-color);
+ &:focus {
+ outline: var(--button-color);
+ }
`
diff --git a/alm/src/components/commons/ExplorerTxLink.tsx b/alm/src/components/commons/ExplorerTxLink.tsx
index fd23a405d..6c69383dc 100644
--- a/alm/src/components/commons/ExplorerTxLink.tsx
+++ b/alm/src/components/commons/ExplorerTxLink.tsx
@@ -3,4 +3,5 @@ import styled from 'styled-components'
export const ExplorerTxLink = styled.a`
color: var(--link-color);
text-decoration: underline;
+ font-weight: bold;
`
diff --git a/alm/src/components/commons/LeftArrow.tsx b/alm/src/components/commons/LeftArrow.tsx
index 1700297a7..abef676c0 100644
--- a/alm/src/components/commons/LeftArrow.tsx
+++ b/alm/src/components/commons/LeftArrow.tsx
@@ -12,7 +12,7 @@ export const LeftArrow = () => {
width="24"
height="24"
viewBox="0 0 24 24"
- fill={themeContext.fontColor}
+ fill={themeContext.buttonColor}
>
diff --git a/alm/src/components/commons/Loading.tsx b/alm/src/components/commons/Loading.tsx
index 8519ede21..7adfc6c9c 100644
--- a/alm/src/components/commons/Loading.tsx
+++ b/alm/src/components/commons/Loading.tsx
@@ -1,4 +1,5 @@
-import React from 'react'
+import React, { useContext } from 'react'
+import { ThemeContext } from 'styled-components'
export interface LoadingParams {
width?: string
@@ -6,156 +7,159 @@ export interface LoadingParams {
displayMessage?: boolean
}
-export const Loading = ({ width = '50px', height = '50px', displayMessage = true }: LoadingParams) => (
-
-
- {displayMessage &&
}
-
-)
+export const Loading = ({ width = '50px', height = '50px', displayMessage = true }: LoadingParams) => {
+ const themeContext = useContext(ThemeContext)
+ return (
+
+
+ {displayMessage &&
}
+
+ )
+}
export const SimpleLoading = () =>
diff --git a/alm/src/hooks/useBridgeContracts.ts b/alm/src/hooks/useBridgeContracts.ts
index e82edff19..02baeeea3 100644
--- a/alm/src/hooks/useBridgeContracts.ts
+++ b/alm/src/hooks/useBridgeContracts.ts
@@ -1,5 +1,5 @@
import { useEffect, useState } from 'react'
-import { HOME_AMB_ABI, FOREIGN_AMB_ABI } from '../../../commons'
+import { HOME_AMB_ABI, FOREIGN_AMB_ABI } from '../abis'
import { FOREIGN_BRIDGE_ADDRESS, HOME_BRIDGE_ADDRESS } from '../config/constants'
import { Contract } from 'web3-eth-contract'
import Web3 from 'web3'
diff --git a/alm/src/hooks/useMessageConfirmations.ts b/alm/src/hooks/useMessageConfirmations.ts
index b63457c60..299bb3876 100644
--- a/alm/src/hooks/useMessageConfirmations.ts
+++ b/alm/src/hooks/useMessageConfirmations.ts
@@ -200,7 +200,7 @@ export const useMessageConfirmations = ({
// To avoid making extra requests, this is only executed when validators finished waiting for blocks confirmations
useEffect(
() => {
- if (!waitingBlocksResolved || !timestamp) return
+ if (!waitingBlocksResolved || !timestamp || !requiredSignatures) return
const subscriptions: Array = []
diff --git a/alm/src/hooks/useValidatorContract.ts b/alm/src/hooks/useValidatorContract.ts
index c48635741..07ea7cfb2 100644
--- a/alm/src/hooks/useValidatorContract.ts
+++ b/alm/src/hooks/useValidatorContract.ts
@@ -2,7 +2,7 @@ import { useEffect, useState } from 'react'
import { Contract } from 'web3-eth-contract'
import Web3 from 'web3'
import { getRequiredSignatures, getValidatorAddress, getValidatorList } from '../utils/contract'
-import { BRIDGE_VALIDATORS_ABI } from '../../../commons'
+import { BRIDGE_VALIDATORS_ABI } from '../abis'
import { useStateProvider } from '../state/StateProvider'
import { TransactionReceipt } from 'web3-eth'
diff --git a/alm/src/index.tsx b/alm/src/index.tsx
index fdfebe3fa..11563b055 100644
--- a/alm/src/index.tsx
+++ b/alm/src/index.tsx
@@ -3,11 +3,11 @@ import ReactDOM from 'react-dom'
import { ThemeProvider } from 'styled-components'
import { GlobalStyle } from './themes/GlobalStyle'
import App from './App'
-import Dark from './themes/Dark'
+import Light from './themes/Light'
ReactDOM.render(
-
+
diff --git a/alm/src/themes/Dark.tsx b/alm/src/themes/Dark.tsx
index 4bb635313..425e26583 100644
--- a/alm/src/themes/Dark.tsx
+++ b/alm/src/themes/Dark.tsx
@@ -1,6 +1,7 @@
const theme = {
backgroundColor: '#121212',
fontColor: '#f5f5f5',
+ buttonColor: '#f5f5f5',
colorPrimary: '#272727',
colorGrey: '#272727',
colorLightGrey: '#272727',
diff --git a/alm/src/themes/GlobalStyle.tsx b/alm/src/themes/GlobalStyle.tsx
index 04485df09..a8e62da9a 100644
--- a/alm/src/themes/GlobalStyle.tsx
+++ b/alm/src/themes/GlobalStyle.tsx
@@ -1,6 +1,6 @@
import { createGlobalStyle } from 'styled-components'
-import theme from './Dark'
+import theme from './Light'
type ThemeType = typeof theme
@@ -17,6 +17,7 @@ export const GlobalStyle = createGlobalStyle<{ theme: ThemeType }>`
:root {
--bg-color: ${props => props.theme.backgroundColor};
--font-color: ${props => props.theme.fontColor};
+ --button-color: ${props => props.theme.buttonColor};
--color-primary: ${props => props.theme.colorPrimary};
--color-grey: ${props => props.theme.colorGrey};
--color-lightGrey: ${props => props.theme.colorLightGrey};
diff --git a/alm/src/themes/Light.ts b/alm/src/themes/Light.ts
new file mode 100644
index 000000000..0c972e841
--- /dev/null
+++ b/alm/src/themes/Light.ts
@@ -0,0 +1,22 @@
+const theme = {
+ backgroundColor: '#FFFFFF',
+ fontColor: 'rgba(0, 0, 0, 0.65)',
+ buttonColor: '#1890ff',
+ colorPrimary: '#BDBDBD',
+ colorGrey: '#1890ff',
+ colorLightGrey: '#1890ff',
+ linkColor: '#1890ff',
+ success: {
+ textColor: '#388E3C',
+ backgroundColor: 'rgba(0,201,167,.1)'
+ },
+ notRequired: {
+ textColor: '#77838f',
+ backgroundColor: 'rgba(119,131,143,.1)'
+ },
+ failed: {
+ textColor: '#de4437',
+ backgroundColor: 'rgba(222,68,55,.1)'
+ }
+}
+export default theme
diff --git a/alm/src/utils/getConfirmationsForTx.ts b/alm/src/utils/getConfirmationsForTx.ts
index 1fa2d7c2e..58e1ce626 100644
--- a/alm/src/utils/getConfirmationsForTx.ts
+++ b/alm/src/utils/getConfirmationsForTx.ts
@@ -190,11 +190,10 @@ export const getConfirmationsForTx = async (
setPendingConfirmations: Function,
getSuccessTransactions: (args: GetFailedTransactionParams) => Promise
) => {
- if (!web3 || !validatorList || !bridgeContract || !waitingBlocksResolved) return
+ if (!web3 || !validatorList || !validatorList.length || !bridgeContract || !waitingBlocksResolved) return
// If all the information was not collected, then it should retry
let shouldRetry = false
-
const hashMsg = web3.utils.soliditySha3Raw(messageData)
let validatorConfirmations = await Promise.all(
validatorList.map(getValidatorConfirmation(web3, hashMsg, bridgeContract, confirmationContractMethod))
diff --git a/alm/src/utils/web3.ts b/alm/src/utils/web3.ts
index db91d59ec..0ed56a0a0 100644
--- a/alm/src/utils/web3.ts
+++ b/alm/src/utils/web3.ts
@@ -4,7 +4,7 @@ import { TransactionReceipt } from 'web3-eth'
import { AbiItem } from 'web3-utils'
import memoize from 'fast-memoize'
import promiseRetry from 'promise-retry'
-import { HOME_AMB_ABI, FOREIGN_AMB_ABI } from '../../../commons'
+import { HOME_AMB_ABI, FOREIGN_AMB_ABI } from '../abis'
export interface MessageObject {
id: string
From 691e4294aeac84f329dc37196f8c7cdde061c49c Mon Sep 17 00:00:00 2001
From: Gerardo Nardelli
Date: Mon, 29 Jun 2020 09:39:31 -0300
Subject: [PATCH 09/13] Automatically detect network by searching the
transaction in both chains (#377)
---
alm/src/components/Form.tsx | 67 ++++---------------
alm/src/components/MainPage.tsx | 19 ++++--
.../components/NetworkTransactionSelector.tsx | 47 +++++++++++++
alm/src/components/StatusContainer.tsx | 7 +-
alm/src/components/TransactionSelector.tsx | 47 +++++++++++++
alm/src/config/constants.ts | 4 +-
alm/src/hooks/useTransactionFinder.ts | 56 ++++++++++++++++
alm/src/hooks/useTransactionStatus.ts | 31 ++++++++-
alm/src/utils/getConfirmationsForTx.ts | 4 +-
alm/src/utils/getFinalizationEvent.ts | 2 +-
10 files changed, 216 insertions(+), 68 deletions(-)
create mode 100644 alm/src/components/NetworkTransactionSelector.tsx
create mode 100644 alm/src/components/TransactionSelector.tsx
create mode 100644 alm/src/hooks/useTransactionFinder.ts
diff --git a/alm/src/components/Form.tsx b/alm/src/components/Form.tsx
index 222dd4477..c438915b7 100644
--- a/alm/src/components/Form.tsx
+++ b/alm/src/components/Form.tsx
@@ -1,10 +1,9 @@
-import React, { useState, FormEvent, useEffect } from 'react'
+import React, { useState, FormEvent } from 'react'
import styled from 'styled-components'
import { FormSubmitParams } from './MainPage'
-import { useStateProvider } from '../state/StateProvider'
-import { useParams } from 'react-router-dom'
import { Button } from './commons/Button'
-import { RadioButtonLabel, RadioButtonContainer } from './commons/RadioButton'
+import { TransactionSelector } from './TransactionSelector'
+import { TransactionReceipt } from 'web3-eth'
const LabelText = styled.label`
line-height: 36px;
@@ -23,33 +22,21 @@ const Input = styled.input`
}
`
-export const Form = ({
- onSubmit,
- lastUsedChain
-}: {
- onSubmit: ({ chainId, txHash }: FormSubmitParams) => void
- lastUsedChain: number
-}) => {
- const { home, foreign, loading } = useStateProvider()
- const { chainId: paramChainId, txHash: paramTxHash } = useParams()
- const [chainId, setChainId] = useState(lastUsedChain)
+export const Form = ({ onSubmit }: { onSubmit: ({ chainId, txHash, receipt }: FormSubmitParams) => void }) => {
const [txHash, setTxHash] = useState('')
-
- useEffect(
- () => {
- if (!paramChainId) {
- setChainId(lastUsedChain > 0 ? lastUsedChain : foreign.chainId)
- } else {
- setChainId(parseInt(paramChainId))
- setTxHash(paramTxHash)
- }
- },
- [foreign.chainId, paramChainId, paramTxHash, lastUsedChain]
- )
+ const [searchTx, setSearchTx] = useState(false)
const formSubmit = (e: FormEvent) => {
e.preventDefault()
- onSubmit({ chainId, txHash })
+ setSearchTx(true)
+ }
+
+ const onSelected = (chainId: number, receipt: TransactionReceipt) => {
+ onSubmit({ chainId, txHash, receipt })
+ }
+
+ if (searchTx) {
+ return
}
return (
@@ -72,32 +59,6 @@ export const Form = ({
- {!loading && (
-
- setChainId(foreign.chainId)}>
- setChainId(foreign.chainId)}
- />
- {foreign.name}
-
- setChainId(home.chainId)}>
- setChainId(home.chainId)}
- />
- {home.name}
-
-
- )}
)
}
diff --git a/alm/src/components/MainPage.tsx b/alm/src/components/MainPage.tsx
index 61867b6e9..d84a85dc3 100644
--- a/alm/src/components/MainPage.tsx
+++ b/alm/src/components/MainPage.tsx
@@ -4,6 +4,7 @@ import { Route, useHistory } from 'react-router-dom'
import { Form } from './Form'
import { StatusContainer } from './StatusContainer'
import { useStateProvider } from '../state/StateProvider'
+import { TransactionReceipt } from 'web3-eth'
const StyledMainPage = styled.div`
text-align: center;
@@ -34,24 +35,24 @@ const HeaderContainer = styled.header`
export interface FormSubmitParams {
chainId: number
txHash: string
+ receipt: TransactionReceipt
}
export const MainPage = () => {
const history = useHistory()
const { home, foreign } = useStateProvider()
- const [selectedChainId, setSelectedChainId] = useState(0)
const [networkName, setNetworkName] = useState('')
+ const [receipt, setReceipt] = useState
>(null)
const setNetworkData = (chainId: number) => {
const network = chainId === home.chainId ? home.name : foreign.name
setNetworkName(network)
- setSelectedChainId(chainId)
}
- const onFormSubmit = ({ chainId, txHash }: FormSubmitParams) => {
+ const onFormSubmit = ({ chainId, txHash, receipt }: FormSubmitParams) => {
setNetworkData(chainId)
-
+ setReceipt(receipt)
history.push(`/${chainId}/${txHash}`)
}
@@ -72,10 +73,16 @@ export const MainPage = () => {
- } />
+ } />
}
+ children={
+
+ }
/>
diff --git a/alm/src/components/NetworkTransactionSelector.tsx b/alm/src/components/NetworkTransactionSelector.tsx
new file mode 100644
index 000000000..5c4fdb9bc
--- /dev/null
+++ b/alm/src/components/NetworkTransactionSelector.tsx
@@ -0,0 +1,47 @@
+import React, { useState } from 'react'
+import { Button } from './commons/Button'
+import { RadioButtonLabel, RadioButtonContainer } from './commons/RadioButton'
+import { useStateProvider } from '../state/StateProvider'
+
+export const NetworkTransactionSelector = ({ onNetworkSelected }: { onNetworkSelected: (chainId: number) => void }) => {
+ const { home, foreign } = useStateProvider()
+ const [chainId, setChainId] = useState(home.chainId)
+
+ const networks = [home, foreign]
+
+ const onSelect = () => {
+ onNetworkSelected(chainId)
+ }
+
+ return (
+
+
The transaction was found in both networks, please select one:
+
+
+ {networks.map((network, i) => (
+ setChainId(network.chainId)}
+ >
+ setChainId(network.chainId)}
+ />
+ {network.name}
+
+ ))}
+
+
+
+ Select
+
+
+
+
+ )
+}
diff --git a/alm/src/components/StatusContainer.tsx b/alm/src/components/StatusContainer.tsx
index 99e1d8a28..c2a4b4842 100644
--- a/alm/src/components/StatusContainer.tsx
+++ b/alm/src/components/StatusContainer.tsx
@@ -10,6 +10,7 @@ import { ExplorerTxLink } from './commons/ExplorerTxLink'
import { ConfirmationsContainer } from './ConfirmationsContainer'
import { LeftArrow } from './commons/LeftArrow'
import styled from 'styled-components'
+import { TransactionReceipt } from 'web3-eth'
const BackButton = styled.button`
color: var(--button-color);
@@ -28,9 +29,10 @@ const BackLabel = styled.label`
export interface StatusContainerParam {
onBackToMain: () => void
setNetworkFromParams: (chainId: number) => void
+ receiptParam: Maybe
}
-export const StatusContainer = ({ onBackToMain, setNetworkFromParams }: StatusContainerParam) => {
+export const StatusContainer = ({ onBackToMain, setNetworkFromParams, receiptParam }: StatusContainerParam) => {
const { home, foreign } = useStateProvider()
const history = useHistory()
const { chainId, txHash, messageIdParam } = useParams()
@@ -39,7 +41,8 @@ export const StatusContainer = ({ onBackToMain, setNetworkFromParams }: StatusCo
const { messages, receipt, status, description, timestamp, loading } = useTransactionStatus({
txHash: validParameters ? txHash : '',
- chainId: validParameters ? parseInt(chainId) : 0
+ chainId: validParameters ? parseInt(chainId) : 0,
+ receiptParam
})
const selectedMessageId = messageIdParam === undefined || messages[messageIdParam] === undefined ? -1 : messageIdParam
diff --git a/alm/src/components/TransactionSelector.tsx b/alm/src/components/TransactionSelector.tsx
new file mode 100644
index 000000000..846ff3c4a
--- /dev/null
+++ b/alm/src/components/TransactionSelector.tsx
@@ -0,0 +1,47 @@
+import React, { useEffect } from 'react'
+import { useTransactionFinder } from '../hooks/useTransactionFinder'
+import { useStateProvider } from '../state/StateProvider'
+import { TRANSACTION_STATUS } from '../config/constants'
+import { TransactionReceipt } from 'web3-eth'
+import { Loading } from './commons/Loading'
+import { NetworkTransactionSelector } from './NetworkTransactionSelector'
+
+export const TransactionSelector = ({
+ txHash,
+ onSelected
+}: {
+ txHash: string
+ onSelected: (chainId: number, receipt: TransactionReceipt) => void
+}) => {
+ const { home, foreign } = useStateProvider()
+ const { receipt: homeReceipt, status: homeStatus } = useTransactionFinder({ txHash, web3: home.web3 })
+ const { receipt: foreignReceipt, status: foreignStatus } = useTransactionFinder({ txHash, web3: foreign.web3 })
+
+ useEffect(
+ () => {
+ if (!home.chainId || !foreign.chainId) return
+ if (homeStatus === TRANSACTION_STATUS.FOUND && foreignStatus === TRANSACTION_STATUS.NOT_FOUND) {
+ if (!homeReceipt) return
+ onSelected(home.chainId, homeReceipt)
+ } else if (foreignStatus === TRANSACTION_STATUS.FOUND && homeStatus === TRANSACTION_STATUS.NOT_FOUND) {
+ if (!foreignReceipt) return
+ onSelected(foreign.chainId, foreignReceipt)
+ }
+ },
+ [homeReceipt, homeStatus, foreignReceipt, foreignStatus, home.chainId, foreign.chainId, onSelected]
+ )
+
+ const onSelectedNetwork = (chainId: number) => {
+ const chain = chainId === home.chainId ? home.chainId : foreign.chainId
+ const receipt = chainId === home.chainId ? homeReceipt : foreignReceipt
+
+ if (!receipt) return
+ onSelected(chain, receipt)
+ }
+
+ if (foreignStatus === TRANSACTION_STATUS.FOUND && homeStatus === TRANSACTION_STATUS.FOUND) {
+ return
+ }
+
+ return
+}
diff --git a/alm/src/config/constants.ts b/alm/src/config/constants.ts
index 09fcb5c6f..5543c5370 100644
--- a/alm/src/config/constants.ts
+++ b/alm/src/config/constants.ts
@@ -32,7 +32,9 @@ export const TRANSACTION_STATUS = {
SUCCESS_ONE_MESSAGE: 'SUCCESS_ONE_MESSAGE',
SUCCESS_NO_MESSAGES: 'SUCCESS_NO_MESSAGES',
FAILED: 'FAILED',
- NOT_FOUND: 'NOT_FOUND'
+ FOUND: 'FOUND',
+ NOT_FOUND: 'NOT_FOUND',
+ UNDEFINED: 'UNDEFINED'
}
export const CONFIRMATIONS_STATUS = {
diff --git a/alm/src/hooks/useTransactionFinder.ts b/alm/src/hooks/useTransactionFinder.ts
new file mode 100644
index 000000000..80611d623
--- /dev/null
+++ b/alm/src/hooks/useTransactionFinder.ts
@@ -0,0 +1,56 @@
+import { useEffect, useState } from 'react'
+import { TransactionReceipt } from 'web3-eth'
+import { HOME_RPC_POLLING_INTERVAL, TRANSACTION_STATUS } from '../config/constants'
+import Web3 from 'web3'
+
+export const useTransactionFinder = ({ txHash, web3 }: { txHash: string; web3: Maybe }) => {
+ const [status, setStatus] = useState(TRANSACTION_STATUS.UNDEFINED)
+ const [receipt, setReceipt] = useState>(null)
+
+ useEffect(
+ () => {
+ if (!txHash || !web3) return
+
+ const subscriptions: number[] = []
+
+ const unsubscribe = () => {
+ subscriptions.forEach(s => {
+ clearTimeout(s)
+ })
+ }
+
+ const getReceipt = async (
+ web3: Web3,
+ txHash: string,
+ setReceipt: Function,
+ setStatus: Function,
+ subscriptions: number[]
+ ) => {
+ const txReceipt = await web3.eth.getTransactionReceipt(txHash)
+ setReceipt(txReceipt)
+
+ if (!txReceipt) {
+ setStatus(TRANSACTION_STATUS.NOT_FOUND)
+ const timeoutId = setTimeout(
+ () => getReceipt(web3, txHash, setReceipt, setStatus, subscriptions),
+ HOME_RPC_POLLING_INTERVAL
+ )
+ subscriptions.push(timeoutId)
+ } else {
+ setStatus(TRANSACTION_STATUS.FOUND)
+ }
+ }
+
+ getReceipt(web3, txHash, setReceipt, setStatus, subscriptions)
+ return () => {
+ unsubscribe()
+ }
+ },
+ [txHash, web3]
+ )
+
+ return {
+ status,
+ receipt
+ }
+}
diff --git a/alm/src/hooks/useTransactionStatus.ts b/alm/src/hooks/useTransactionStatus.ts
index 4c20d5def..44763f541 100644
--- a/alm/src/hooks/useTransactionStatus.ts
+++ b/alm/src/hooks/useTransactionStatus.ts
@@ -6,7 +6,15 @@ import { useStateProvider } from '../state/StateProvider'
import { getHomeMessagesFromReceipt, getForeignMessagesFromReceipt, MessageObject, getBlock } from '../utils/web3'
import useInterval from '@use-it/interval'
-export const useTransactionStatus = ({ txHash, chainId }: { txHash: string; chainId: number }) => {
+export const useTransactionStatus = ({
+ txHash,
+ chainId,
+ receiptParam
+}: {
+ txHash: string
+ chainId: number
+ receiptParam: Maybe
+}) => {
const { home, foreign } = useStateProvider()
const [messages, setMessages] = useState>([])
const [status, setStatus] = useState('')
@@ -37,7 +45,14 @@ export const useTransactionStatus = ({ txHash, chainId }: { txHash: string; chai
const isHome = chainId === home.chainId
const web3 = isHome ? home.web3 : foreign.web3
- const txReceipt = await web3.eth.getTransactionReceipt(txHash)
+ let txReceipt
+
+ if (receiptParam) {
+ txReceipt = receiptParam
+ } else {
+ txReceipt = await web3.eth.getTransactionReceipt(txHash)
+ }
+
setReceipt(txReceipt)
if (!txReceipt) {
@@ -92,7 +107,17 @@ export const useTransactionStatus = ({ txHash, chainId }: { txHash: string; chai
unsubscribe()
}
},
- [txHash, chainId, home.chainId, foreign.chainId, home.web3, foreign.web3, home.bridgeAddress, foreign.bridgeAddress]
+ [
+ txHash,
+ chainId,
+ home.chainId,
+ foreign.chainId,
+ home.web3,
+ foreign.web3,
+ home.bridgeAddress,
+ foreign.bridgeAddress,
+ receiptParam
+ ]
)
return {
diff --git a/alm/src/utils/getConfirmationsForTx.ts b/alm/src/utils/getConfirmationsForTx.ts
index 58e1ce626..d9cc3d62f 100644
--- a/alm/src/utils/getConfirmationsForTx.ts
+++ b/alm/src/utils/getConfirmationsForTx.ts
@@ -53,7 +53,7 @@ export const getValidatorSuccessTransaction = (
getSuccessTransactions: (args: GetFailedTransactionParams) => Promise
) => async (validatorData: BasicConfirmationParam): Promise => {
const { validator } = validatorData
- const validatorCacheKey = `${CACHE_KEY_SUCCESS}${validatorData.validator}`
+ const validatorCacheKey = `${CACHE_KEY_SUCCESS}${validatorData.validator}-${messageData}`
const fromCache = validatorsCache.getData(validatorCacheKey)
if (fromCache && fromCache.txHash) {
@@ -100,7 +100,7 @@ export const getValidatorFailedTransaction = (
timestamp: number,
getFailedTransactions: (args: GetFailedTransactionParams) => Promise
) => async (validatorData: BasicConfirmationParam): Promise => {
- const validatorCacheKey = `${CACHE_KEY_FAILED}${validatorData.validator}`
+ const validatorCacheKey = `${CACHE_KEY_FAILED}${validatorData.validator}-${messageData}`
const failedFromCache = validatorsCache.getData(validatorCacheKey)
if (failedFromCache && failedFromCache.txHash) {
diff --git a/alm/src/utils/getFinalizationEvent.ts b/alm/src/utils/getFinalizationEvent.ts
index 1407b2acc..72bca3e9e 100644
--- a/alm/src/utils/getFinalizationEvent.ts
+++ b/alm/src/utils/getFinalizationEvent.ts
@@ -80,7 +80,7 @@ export const getFinalizationEvent = async (
})
setPendingExecution(true)
} else {
- const validatorExecutionCacheKey = `${CACHE_KEY_EXECUTION_FAILED}${validator}`
+ const validatorExecutionCacheKey = `${CACHE_KEY_EXECUTION_FAILED}${validator}-${message.id}`
const failedFromCache = validatorsCache.get(validatorExecutionCacheKey)
if (!failedFromCache) {
From ab814f831c73aa65dd866cef41338e805154b470 Mon Sep 17 00:00:00 2001
From: Gerardo Nardelli
Date: Tue, 30 Jun 2020 17:41:19 -0300
Subject: [PATCH 10/13] Get required block confirmation at the moment of the
transaction (#379)
---
alm/src/components/ConfirmationsContainer.tsx | 5 ++-
alm/src/hooks/useBlockConfirmations.ts | 38 +++++++++++++++++++
alm/src/hooks/useBridgeContracts.ts | 15 +-------
alm/src/hooks/useMessageConfirmations.ts | 17 +++++----
alm/src/state/StateProvider.tsx | 11 ++----
alm/src/utils/contract.ts | 18 ++++++++-
6 files changed, 71 insertions(+), 33 deletions(-)
create mode 100644 alm/src/hooks/useBlockConfirmations.ts
diff --git a/alm/src/components/ConfirmationsContainer.tsx b/alm/src/components/ConfirmationsContainer.tsx
index ead23412d..f4995c446 100644
--- a/alm/src/components/ConfirmationsContainer.tsx
+++ b/alm/src/components/ConfirmationsContainer.tsx
@@ -11,6 +11,7 @@ import { getConfirmationsStatusDescription } from '../utils/networks'
import { useStateProvider } from '../state/StateProvider'
import { ExecutionConfirmation } from './ExecutionConfirmation'
import { useValidatorContract } from '../hooks/useValidatorContract'
+import { useBlockConfirmations } from '../hooks/useBlockConfirmations'
const StatusLabel = styled.label`
font-weight: bold;
@@ -45,13 +46,15 @@ export const ConfirmationsContainer = ({ message, receipt, fromHome, timestamp }
foreign: { name: foreignName }
} = useStateProvider()
const { requiredSignatures, validatorList } = useValidatorContract({ fromHome, receipt })
+ const { blockConfirmations } = useBlockConfirmations({ fromHome, receipt })
const { confirmations, status, executionData, signatureCollected } = useMessageConfirmations({
message,
receipt,
fromHome,
timestamp,
requiredSignatures,
- validatorList
+ validatorList,
+ blockConfirmations
})
return (
diff --git a/alm/src/hooks/useBlockConfirmations.ts b/alm/src/hooks/useBlockConfirmations.ts
new file mode 100644
index 000000000..438e9e5af
--- /dev/null
+++ b/alm/src/hooks/useBlockConfirmations.ts
@@ -0,0 +1,38 @@
+import { useEffect, useState } from 'react'
+import { TransactionReceipt } from 'web3-eth'
+import { useStateProvider } from '../state/StateProvider'
+import { Contract } from 'web3-eth-contract'
+import { getRequiredBlockConfirmations } from '../utils/contract'
+
+export interface UseBlockConfirmationsParams {
+ fromHome: boolean
+ receipt: Maybe
+}
+
+export const useBlockConfirmations = ({ receipt, fromHome }: UseBlockConfirmationsParams) => {
+ const [blockConfirmations, setBlockConfirmations] = useState(0)
+
+ const { home, foreign } = useStateProvider()
+
+ const callRequireBlockConfirmations = async (
+ contract: Contract,
+ receipt: TransactionReceipt,
+ setResult: Function
+ ) => {
+ const result = await getRequiredBlockConfirmations(contract, receipt.blockNumber)
+ setResult(result)
+ }
+
+ useEffect(
+ () => {
+ const bridgeContract = fromHome ? home.bridgeContract : foreign.bridgeContract
+ if (!bridgeContract || !receipt) return
+ callRequireBlockConfirmations(bridgeContract, receipt, setBlockConfirmations)
+ },
+ [home.bridgeContract, foreign.bridgeContract, receipt, fromHome]
+ )
+
+ return {
+ blockConfirmations
+ }
+}
diff --git a/alm/src/hooks/useBridgeContracts.ts b/alm/src/hooks/useBridgeContracts.ts
index 02baeeea3..c27bd980d 100644
--- a/alm/src/hooks/useBridgeContracts.ts
+++ b/alm/src/hooks/useBridgeContracts.ts
@@ -3,7 +3,6 @@ import { HOME_AMB_ABI, FOREIGN_AMB_ABI } from '../abis'
import { FOREIGN_BRIDGE_ADDRESS, HOME_BRIDGE_ADDRESS } from '../config/constants'
import { Contract } from 'web3-eth-contract'
import Web3 from 'web3'
-import { getRequiredBlockConfirmations } from '../utils/contract'
export interface useBridgeContractsParams {
homeWeb3: Web3
@@ -13,20 +12,11 @@ export interface useBridgeContractsParams {
export const useBridgeContracts = ({ homeWeb3, foreignWeb3 }: useBridgeContractsParams) => {
const [homeBridge, setHomeBridge] = useState>(null)
const [foreignBridge, setForeignBridge] = useState>(null)
- const [homeBlockConfirmations, setHomeBlockConfirmations] = useState(0)
- const [foreignBlockConfirmations, setForeignBlockConfirmations] = useState(0)
-
- const callRequireBlockConfirmations = async (contract: Maybe, setResult: Function) => {
- if (!contract) return
- const result = await getRequiredBlockConfirmations(contract)
- setResult(result)
- }
useEffect(
() => {
if (!homeWeb3) return
const homeContract = new homeWeb3.eth.Contract(HOME_AMB_ABI, HOME_BRIDGE_ADDRESS)
- callRequireBlockConfirmations(homeContract, setHomeBlockConfirmations)
setHomeBridge(homeContract)
},
[homeWeb3]
@@ -36,7 +26,6 @@ export const useBridgeContracts = ({ homeWeb3, foreignWeb3 }: useBridgeContracts
() => {
if (!foreignWeb3) return
const foreignContract = new foreignWeb3.eth.Contract(FOREIGN_AMB_ABI, FOREIGN_BRIDGE_ADDRESS)
- callRequireBlockConfirmations(foreignContract, setForeignBlockConfirmations)
setForeignBridge(foreignContract)
},
[foreignWeb3]
@@ -44,8 +33,6 @@ export const useBridgeContracts = ({ homeWeb3, foreignWeb3 }: useBridgeContracts
return {
homeBridge,
- foreignBridge,
- homeBlockConfirmations,
- foreignBlockConfirmations
+ foreignBridge
}
}
diff --git a/alm/src/hooks/useMessageConfirmations.ts b/alm/src/hooks/useMessageConfirmations.ts
index 299bb3876..9b27f010e 100644
--- a/alm/src/hooks/useMessageConfirmations.ts
+++ b/alm/src/hooks/useMessageConfirmations.ts
@@ -32,6 +32,7 @@ export interface useMessageConfirmationsParams {
timestamp: number
requiredSignatures: number
validatorList: string[]
+ blockConfirmations: number
}
export interface BasicConfirmationParam {
@@ -58,7 +59,8 @@ export const useMessageConfirmations = ({
fromHome,
timestamp,
requiredSignatures,
- validatorList
+ validatorList,
+ blockConfirmations
}: useMessageConfirmationsParams) => {
const { home, foreign } = useStateProvider()
const [confirmations, setConfirmations] = useState>([])
@@ -84,7 +86,7 @@ export const useMessageConfirmations = ({
// Check if the validators are waiting for block confirmations to verify the message
useEffect(
() => {
- if (!receipt) return
+ if (!receipt || !blockConfirmations) return
const subscriptions: Array = []
@@ -99,8 +101,7 @@ export const useMessageConfirmations = ({
const web3 = fromHome ? home.web3 : foreign.web3
blockProvider.start(web3)
- const requiredBlockConfirmations = fromHome ? home.blockConfirmations : foreign.blockConfirmations
- const targetBlock = receipt.blockNumber + requiredBlockConfirmations
+ const targetBlock = receipt.blockNumber + blockConfirmations
checkSignaturesWaitingForBLocks(
targetBlock,
@@ -118,7 +119,7 @@ export const useMessageConfirmations = ({
blockProvider.stop()
}
},
- [foreign.blockConfirmations, foreign.web3, fromHome, home.blockConfirmations, validatorList, home.web3, receipt]
+ [blockConfirmations, foreign.web3, fromHome, validatorList, home.web3, receipt]
)
// The collected signature event is only fetched once the signatures are collected on tx from home to foreign, to calculate if
@@ -164,7 +165,7 @@ export const useMessageConfirmations = ({
// This is executed if the message is in Home to Foreign direction only
useEffect(
() => {
- if (!fromHome || !home.web3 || !receipt || !collectedSignaturesEvent) return
+ if (!fromHome || !home.web3 || !receipt || !collectedSignaturesEvent || !blockConfirmations) return
const subscriptions: Array = []
@@ -175,7 +176,7 @@ export const useMessageConfirmations = ({
}
homeBlockNumberProvider.start(home.web3)
- const targetBlock = collectedSignaturesEvent.blockNumber + home.blockConfirmations
+ const targetBlock = collectedSignaturesEvent.blockNumber + blockConfirmations
checkWaitingBlocksForExecution(
homeBlockNumberProvider,
@@ -193,7 +194,7 @@ export const useMessageConfirmations = ({
homeBlockNumberProvider.stop()
}
},
- [collectedSignaturesEvent, fromHome, home.blockConfirmations, home.web3, receipt]
+ [collectedSignaturesEvent, fromHome, blockConfirmations, home.web3, receipt]
)
// Checks if validators verified the message
diff --git a/alm/src/state/StateProvider.tsx b/alm/src/state/StateProvider.tsx
index 3920c0953..16762011d 100644
--- a/alm/src/state/StateProvider.tsx
+++ b/alm/src/state/StateProvider.tsx
@@ -18,7 +18,6 @@ export interface BaseNetworkParams {
web3: Maybe
bridgeAddress: string
bridgeContract: Maybe
- blockConfirmations: number
}
export interface StateContext {
@@ -33,16 +32,14 @@ const initialState = {
name: '',
web3: null,
bridgeAddress: HOME_BRIDGE_ADDRESS,
- bridgeContract: null,
- blockConfirmations: 0
+ bridgeContract: null
},
foreign: {
chainId: 0,
name: '',
web3: null,
bridgeAddress: FOREIGN_BRIDGE_ADDRESS,
- bridgeContract: null,
- blockConfirmations: 0
+ bridgeContract: null
},
loading: true
}
@@ -52,7 +49,7 @@ const StateContext = createContext(initialState)
export const StateProvider = ({ children }: { children: ReactNode }) => {
const homeNetwork = useNetwork(HOME_RPC_URL)
const foreignNetwork = useNetwork(FOREIGN_RPC_URL)
- const { homeBridge, foreignBridge, homeBlockConfirmations, foreignBlockConfirmations } = useBridgeContracts({
+ const { homeBridge, foreignBridge } = useBridgeContracts({
homeWeb3: homeNetwork.web3,
foreignWeb3: foreignNetwork.web3
})
@@ -62,14 +59,12 @@ export const StateProvider = ({ children }: { children: ReactNode }) => {
bridgeAddress: HOME_BRIDGE_ADDRESS,
name: HOME_NETWORK_NAME,
bridgeContract: homeBridge,
- blockConfirmations: homeBlockConfirmations,
...homeNetwork
},
foreign: {
bridgeAddress: FOREIGN_BRIDGE_ADDRESS,
name: FOREIGN_NETWORK_NAME,
bridgeContract: foreignBridge,
- blockConfirmations: foreignBlockConfirmations,
...foreignNetwork
},
loading: homeNetwork.loading || foreignNetwork.loading
diff --git a/alm/src/utils/contract.ts b/alm/src/utils/contract.ts
index f1e6bd98f..2b81c2900 100644
--- a/alm/src/utils/contract.ts
+++ b/alm/src/utils/contract.ts
@@ -1,7 +1,21 @@
import { Contract } from 'web3-eth-contract'
-export const getRequiredBlockConfirmations = async (contract: Contract) => {
- const blockConfirmations = await contract.methods.requiredBlockConfirmations().call()
+export const getRequiredBlockConfirmations = async (contract: Contract, blockNumber: number) => {
+ const events = await contract.getPastEvents('RequiredBlockConfirmationChanged', {
+ fromBlock: 0,
+ toBlock: blockNumber
+ })
+
+ let blockConfirmations
+ if (events.length > 0) {
+ // Use the value from last event before the transaction
+ const event = events[events.length - 1]
+ blockConfirmations = event.returnValues.requiredBlockConfirmations
+ } else {
+ // This is a special case where RequiredBlockConfirmationChanged was not emitted during initialization in early versions of AMB
+ // of Sokol - Kovan. In this case the current value is used.
+ blockConfirmations = await contract.methods.requiredBlockConfirmations().call()
+ }
return parseInt(blockConfirmations)
}
From dc27bd6caa0ce56e98c26f262fe0487ada86d4e9 Mon Sep 17 00:00:00 2001
From: Gerardo Nardelli
Date: Wed, 1 Jul 2020 18:34:27 -0300
Subject: [PATCH 11/13] ALM docker improvements (#380)
---
alm/.env.example | 3 ++-
alm/Dockerfile | 12 +++++++++---
alm/docker-compose.yml | 4 +++-
alm/package.json | 3 ++-
alm/src/utils/explorer.ts | 4 ++--
5 files changed, 18 insertions(+), 8 deletions(-)
diff --git a/alm/.env.example b/alm/.env.example
index 16ae54928..2110b1f89 100644
--- a/alm/.env.example
+++ b/alm/.env.example
@@ -11,4 +11,5 @@ ALM_HOME_EXPLORER_TX_TEMPLATE=https://blockscout.com/poa/sokol/tx/%s
ALM_FOREIGN_EXPLORER_TX_TEMPLATE=https://blockscout.com/eth/kovan/tx/%s
ALM_HOME_EXPLORER_API=https://blockscout.com/poa/sokol/api
-ALM_FOREIGN_EXPLORER_API=https://kovan.etherscan.io/api
+ALM_FOREIGN_EXPLORER_API=https://kovan.etherscan.io/api?apikey=YourApiKeyToken
+PORT=8080
diff --git a/alm/Dockerfile b/alm/Dockerfile
index 22e65fe8b..bcd293f06 100644
--- a/alm/Dockerfile
+++ b/alm/Dockerfile
@@ -1,4 +1,4 @@
-FROM node:12
+FROM node:12 as alm-builder
WORKDIR /mono
COPY package.json .
@@ -19,5 +19,11 @@ ARG DOT_ENV_PATH=./alm/.env
COPY ${DOT_ENV_PATH} ./alm/.env
WORKDIR /mono/alm
-CMD echo "To start the application run:" \
- "yarn start"
+RUN yarn run build
+
+
+FROM node:12 as alm-production
+RUN yarn global add serve
+WORKDIR /app
+COPY --from=alm-builder /mono/alm/build .
+CMD serve -p $PORT -s .
diff --git a/alm/docker-compose.yml b/alm/docker-compose.yml
index 22c9d8c41..cc76c9ac8 100644
--- a/alm/docker-compose.yml
+++ b/alm/docker-compose.yml
@@ -5,8 +5,10 @@ services:
build:
context: ..
dockerfile: alm/Dockerfile
+ ports:
+ - "${PORT}:${PORT}"
env_file: ./.env
environment:
- NODE_ENV=production
restart: unless-stopped
- entrypoint: yarn start
+ entrypoint: serve -p ${PORT} -s .
diff --git a/alm/package.json b/alm/package.json
index 651193518..16b6d3297 100644
--- a/alm/package.json
+++ b/alm/package.json
@@ -26,7 +26,8 @@
"react-scripts": "3.0.1",
"styled-components": "^5.1.1",
"typescript": "^3.5.2",
- "web3": "1.2.7"
+ "web3": "1.2.7",
+ "web3-eth-contract": "1.2.7"
},
"scripts": {
"start": "./load-env.sh react-app-rewired start",
diff --git a/alm/src/utils/explorer.ts b/alm/src/utils/explorer.ts
index 8561a6ab5..d57bf926c 100644
--- a/alm/src/utils/explorer.ts
+++ b/alm/src/utils/explorer.ts
@@ -70,7 +70,7 @@ export const fetchAccountTransactionsFromBlockscout = async ({
}
export const getBlockByTimestampUrl = (api: string, timestamp: number) =>
- `${api}?module=block&action=getblocknobytime×tamp=${timestamp}&closest=before`
+ `${api}&module=block&action=getblocknobytime×tamp=${timestamp}&closest=before`
export const fetchAccountTransactionsFromEtherscan = async ({
account,
@@ -101,7 +101,7 @@ export const fetchAccountTransactionsFromEtherscan = async ({
return []
}
- const url = `${api}?module=account&action=txlist&address=${account}&startblock=${fromBlock}&endblock=${toBlock}`
+ const url = `${api}&module=account&action=txlist&address=${account}&startblock=${fromBlock}&endblock=${toBlock}`
try {
const result = await fetch(url).then(res => res.json())
From d5d0c8f56ab2d6e6804e950b7a8ffe623ab36c19 Mon Sep 17 00:00:00 2001
From: Kirill Fedoseev
Date: Thu, 2 Jul 2020 02:37:19 +0500
Subject: [PATCH 12/13] Extend burner wallet plugin with support of
erc-to-native mediator (#378)
---
burner-wallet-plugin/testing/package.json | 3 +-
.../testing/src/LocalhostGateway.ts | 53 ++
burner-wallet-plugin/testing/src/index.tsx | 78 ++-
burner-wallet-plugin/testing/tsconfig.json | 1 +
.../assets/BridgeableERC20Asset.ts | 51 ++
.../src/burner-wallet/assets/ERC677Asset.ts | 5 +-
.../src/burner-wallet/index.ts | 2 +
.../pairs/MediatorErcToNative.ts | 48 ++
.../tokenbridge-bw-exchange/src/index.ts | 12 +-
.../tokenbridge-bw-exchange/src/utils/abis.ts | 1 +
.../src/utils/abis/Mediator.ts | 18 +
.../src/utils/abis/MediatorErcToNative.ts | 44 ++
.../src/utils/index.ts | 3 +-
.../src/utils/utils.ts | 6 +-
burner-wallet-plugin/yarn.lock | 460 +-----------------
15 files changed, 310 insertions(+), 475 deletions(-)
create mode 100644 burner-wallet-plugin/testing/src/LocalhostGateway.ts
create mode 100644 burner-wallet-plugin/tokenbridge-bw-exchange/src/burner-wallet/assets/BridgeableERC20Asset.ts
create mode 100644 burner-wallet-plugin/tokenbridge-bw-exchange/src/burner-wallet/pairs/MediatorErcToNative.ts
create mode 100644 burner-wallet-plugin/tokenbridge-bw-exchange/src/utils/abis/MediatorErcToNative.ts
diff --git a/burner-wallet-plugin/testing/package.json b/burner-wallet-plugin/testing/package.json
index 8c2364cf4..23cefda49 100644
--- a/burner-wallet-plugin/testing/package.json
+++ b/burner-wallet-plugin/testing/package.json
@@ -16,8 +16,7 @@
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-scripts": "3.0.1",
- "typescript": "3.5.1",
- "web3": "1.0.0-beta.55"
+ "typescript": "3.5.1"
},
"scripts": {
"start": "react-scripts start",
diff --git a/burner-wallet-plugin/testing/src/LocalhostGateway.ts b/burner-wallet-plugin/testing/src/LocalhostGateway.ts
new file mode 100644
index 000000000..43ff964f4
--- /dev/null
+++ b/burner-wallet-plugin/testing/src/LocalhostGateway.ts
@@ -0,0 +1,53 @@
+import { Gateway } from '@burner-wallet/core/gateways'
+import Web3 from 'web3'
+
+export default class LocalhostGateway extends Gateway {
+ private readonly providers: object
+ private readonly providerStrings: { [id: string]: string }
+ constructor() {
+ super()
+ this.providerStrings = {
+ '111': 'http://localhost:8545',
+ '1337': 'http://localhost:8546'
+ }
+ this.providers = {}
+ }
+
+ isAvailable() {
+ return true
+ }
+
+ getNetworks() {
+ return ['111', '1337']
+ }
+
+ _provider(network) {
+ if (!this.providers[network]) {
+ this._makeProvider(network)
+ }
+ return this.providers[network]
+ }
+
+ _makeProvider(network) {
+ if (!this.providerStrings[network]) {
+ throw new Error(`Network ${network} not supported by LocalhostGateway`)
+ }
+
+ this.providers[network] = new Web3.providers.HttpProvider(this.providerStrings[network])
+ }
+
+ send(network, payload) {
+ return new Promise((resolve, reject) => {
+ if (this.getNetworks().indexOf(network) === -1) {
+ return reject(new Error('LocalhostGateway does not support this network'))
+ }
+
+ this._provider(network).send(payload, (err, response) => {
+ if (err) {
+ return reject(err)
+ }
+ return resolve(response.result)
+ })
+ })
+ }
+}
diff --git a/burner-wallet-plugin/testing/src/index.tsx b/burner-wallet-plugin/testing/src/index.tsx
index 02754f25b..11ef314bc 100644
--- a/burner-wallet-plugin/testing/src/index.tsx
+++ b/burner-wallet-plugin/testing/src/index.tsx
@@ -6,13 +6,23 @@ import { InjectedSigner, LocalSigner } from '@burner-wallet/core/signers'
import { InfuraGateway, InjectedGateway } from '@burner-wallet/core/gateways'
import ModernUI from '@burner-wallet/modern-ui'
import Exchange from '@burner-wallet/exchange'
-import { Mediator, sPOA, ERC677Asset, TokenBridgeGateway } from '@poanet/tokenbridge-bw-exchange'
+import {
+ Mediator,
+ sPOA,
+ ERC677Asset,
+ TokenBridgeGateway,
+ NativeMediatorAsset,
+ MediatorErcToNative,
+ BridgeableERC20Asset
+} from '@poanet/tokenbridge-bw-exchange'
import MetamaskPlugin from '@burner-wallet/metamask-plugin'
+import LocalhostGateway from './LocalhostGateway'
let assetIdAtHome = 'assetAtHome'
const assetIdAtForeign = 'assetAtForeign'
let assetAtHome: Asset
let assetAtForeign: Asset
+let testBridge: Mediator
if (process.env.REACT_APP_MODE === 'AMB_NATIVE_TO_ERC677') {
sPOA.setMediatorAddress(process.env.REACT_APP_HOME_MEDIATOR_ADDRESS)
@@ -28,8 +38,16 @@ if (process.env.REACT_APP_MODE === 'AMB_NATIVE_TO_ERC677') {
// @ts-ignore
address: process.env.REACT_APP_FOREIGN_TOKEN_ADDRESS
})
-} else {
- // process.env.REACT_APP_MODE === 'AMB_ERC677_TO_ERC677'
+
+ testBridge = new Mediator({
+ assetA: assetIdAtHome,
+ // @ts-ignore
+ assetABridge: process.env.REACT_APP_HOME_MEDIATOR_ADDRESS,
+ assetB: assetIdAtForeign,
+ // @ts-ignore
+ assetBBridge: process.env.REACT_APP_FOREIGN_MEDIATOR_ADDRESS
+ })
+} else if (process.env.REACT_APP_MODE === 'AMB_ERC677_TO_ERC677') {
assetAtHome = new ERC677Asset({
id: 'assetAtHome',
// @ts-ignore
@@ -49,20 +67,54 @@ if (process.env.REACT_APP_MODE === 'AMB_NATIVE_TO_ERC677') {
// @ts-ignore
address: process.env.REACT_APP_FOREIGN_TOKEN_ADDRESS
})
-}
-const testBridge = new Mediator({
- assetA: assetIdAtHome,
- // @ts-ignore
- assetABridge: process.env.REACT_APP_HOME_MEDIATOR_ADDRESS,
- assetB: assetIdAtForeign,
- // @ts-ignore
- assetBBridge: process.env.REACT_APP_FOREIGN_MEDIATOR_ADDRESS
-})
+ testBridge = new Mediator({
+ assetA: assetIdAtHome,
+ // @ts-ignore
+ assetABridge: process.env.REACT_APP_HOME_MEDIATOR_ADDRESS,
+ assetB: assetIdAtForeign,
+ // @ts-ignore
+ assetBBridge: process.env.REACT_APP_FOREIGN_MEDIATOR_ADDRESS
+ })
+} else {
+ // process.env.REACT_APP_MODE === 'AMB_ERC20_TO_NATIVE'
+ assetAtHome = new NativeMediatorAsset({
+ id: assetIdAtHome,
+ name: 'qDAI',
+ network: process.env.REACT_APP_HOME_NETWORK as string,
+ mediatorAddress: process.env.REACT_APP_HOME_MEDIATOR_ADDRESS
+ })
+
+ assetAtForeign = new BridgeableERC20Asset({
+ id: 'assetAtForeign',
+ // @ts-ignore
+ name: process.env.REACT_APP_FOREIGN_TOKEN_NAME,
+ // @ts-ignore
+ network: process.env.REACT_APP_FOREIGN_NETWORK,
+ // @ts-ignore
+ address: process.env.REACT_APP_FOREIGN_TOKEN_ADDRESS,
+ // @ts-ignore
+ bridgeAddress: process.env.REACT_APP_FOREIGN_MEDIATOR_ADDRESS
+ })
+
+ testBridge = new MediatorErcToNative({
+ assetA: assetIdAtHome,
+ // @ts-ignore
+ assetABridge: process.env.REACT_APP_HOME_MEDIATOR_ADDRESS,
+ assetB: assetIdAtForeign,
+ // @ts-ignore
+ assetBBridge: process.env.REACT_APP_FOREIGN_MEDIATOR_ADDRESS
+ })
+}
const core = new BurnerCore({
signers: [new InjectedSigner(), new LocalSigner({ privateKey: process.env.REACT_APP_PK, saveKey: false })],
- gateways: [new InjectedGateway(), new TokenBridgeGateway(), new InfuraGateway(process.env.REACT_APP_INFURA_KEY)],
+ gateways: [
+ new InjectedGateway(),
+ new LocalhostGateway(),
+ new TokenBridgeGateway(),
+ new InfuraGateway(process.env.REACT_APP_INFURA_KEY)
+ ],
assets: [assetAtHome, assetAtForeign]
})
diff --git a/burner-wallet-plugin/testing/tsconfig.json b/burner-wallet-plugin/testing/tsconfig.json
index 0980b23fa..0aab7c650 100644
--- a/burner-wallet-plugin/testing/tsconfig.json
+++ b/burner-wallet-plugin/testing/tsconfig.json
@@ -17,6 +17,7 @@
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
+ "noImplicitAny": false,
"jsx": "preserve"
},
"include": [
diff --git a/burner-wallet-plugin/tokenbridge-bw-exchange/src/burner-wallet/assets/BridgeableERC20Asset.ts b/burner-wallet-plugin/tokenbridge-bw-exchange/src/burner-wallet/assets/BridgeableERC20Asset.ts
new file mode 100644
index 000000000..e1175cef0
--- /dev/null
+++ b/burner-wallet-plugin/tokenbridge-bw-exchange/src/burner-wallet/assets/BridgeableERC20Asset.ts
@@ -0,0 +1,51 @@
+import { ERC20Asset } from '@burner-wallet/assets'
+import { MEDIATOR_ABI, constants } from '../../utils'
+import { toBN } from 'web3-utils'
+
+interface BridgeableERC20Constructor {
+ abi?: object
+ address: string
+ id: string
+ name: string
+ network: string
+ bridgeAddress: string
+}
+
+export default class BridgeableERC20Asset extends ERC20Asset {
+ protected bridgeAddress: string
+ private _bridge
+
+ constructor({ bridgeAddress, ...params }: BridgeableERC20Constructor) {
+ super({ ...params })
+ this.bridgeAddress = bridgeAddress.toLowerCase()
+ }
+
+ getBridgeContract() {
+ if (!this._bridge) {
+ const Contract = this.getWeb3().eth.Contract
+ this._bridge = new Contract(MEDIATOR_ABI, this.bridgeAddress)
+ }
+ return this._bridge
+ }
+
+ async _send({ from, to, value }) {
+ if (to.toLowerCase() === this.bridgeAddress) {
+ const allowance = await this.allowance(from, to)
+ if (toBN(allowance).lt(toBN(value))) {
+ await this.approve(from, to, value)
+ }
+ const receipt = await this.getBridgeContract()
+ .methods.relayTokens(from, value)
+ .send({ from })
+ const transferLog = Object.values(receipt.events as object).find(
+ e => e.raw.topics[0] === constants.TRANSFER_TOPIC
+ )
+ return {
+ ...receipt,
+ txHash: receipt.transactionHash,
+ id: `${receipt.transactionHash}-${transferLog.logIndex}`
+ }
+ }
+ return super._send({ from, to, value })
+ }
+}
diff --git a/burner-wallet-plugin/tokenbridge-bw-exchange/src/burner-wallet/assets/ERC677Asset.ts b/burner-wallet-plugin/tokenbridge-bw-exchange/src/burner-wallet/assets/ERC677Asset.ts
index 3f4ad00d1..ecd5364bb 100644
--- a/burner-wallet-plugin/tokenbridge-bw-exchange/src/burner-wallet/assets/ERC677Asset.ts
+++ b/burner-wallet-plugin/tokenbridge-bw-exchange/src/burner-wallet/assets/ERC677Asset.ts
@@ -1,7 +1,6 @@
import { ERC20Asset } from '@burner-wallet/assets'
-import { ERC677_ABI } from '../../utils'
+import { ERC677_ABI, constants } from '../../utils'
-const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'
const BLOCK_LOOKBACK = 250
interface ERC677Constructor {
@@ -45,7 +44,7 @@ export default class ERC677Asset extends ERC20Asset {
const allTransferEvents = await this.getContract().getPastEvents('allEvents', {
fromBlock: block,
toBlock: currentBlock,
- topics: [TRANSFER_TOPIC]
+ topics: [constants.TRANSFER_TOPIC]
})
// Manually filter `to` parameter because `filter` option does not work with allEvents
const events = allTransferEvents.filter(e => e.returnValues.to.toLowerCase() === address.toLowerCase())
diff --git a/burner-wallet-plugin/tokenbridge-bw-exchange/src/burner-wallet/index.ts b/burner-wallet-plugin/tokenbridge-bw-exchange/src/burner-wallet/index.ts
index 4b3c3222f..90af23751 100644
--- a/burner-wallet-plugin/tokenbridge-bw-exchange/src/burner-wallet/index.ts
+++ b/burner-wallet-plugin/tokenbridge-bw-exchange/src/burner-wallet/index.ts
@@ -2,6 +2,8 @@ export { default as sPOA } from './assets/sPOA'
export { default as Etc } from './assets/Etc'
export { default as Wetc } from './assets/Wetc'
export { default as ERC677Asset } from './assets/ERC677Asset'
+export { default as BridgeableERC20Asset } from './assets/BridgeableERC20Asset'
export { default as NativeMediatorAsset } from './assets/NativeMediatorAsset'
export { default as TokenBridgeGateway } from './gateways/TokenBridgeGateway'
export { default as Mediator } from './pairs/Mediator'
+export { default as MediatorErcToNative } from './pairs/MediatorErcToNative'
diff --git a/burner-wallet-plugin/tokenbridge-bw-exchange/src/burner-wallet/pairs/MediatorErcToNative.ts b/burner-wallet-plugin/tokenbridge-bw-exchange/src/burner-wallet/pairs/MediatorErcToNative.ts
new file mode 100644
index 000000000..7ee007ca2
--- /dev/null
+++ b/burner-wallet-plugin/tokenbridge-bw-exchange/src/burner-wallet/pairs/MediatorErcToNative.ts
@@ -0,0 +1,48 @@
+import BN from 'bn.js'
+import { EstimateReturn, ValueTypes } from '@burner-wallet/exchange'
+import { constants } from '../../utils'
+import { MEDIATOR_ERC_TO_NATIVE_ABI } from '../../utils'
+import { default as Mediator } from './Mediator'
+import { fromWei, toBN } from 'web3-utils'
+
+export default class MediatorErcToNative extends Mediator {
+ constructor(params) {
+ super(params)
+ }
+
+ async estimateAtoB(value: ValueTypes): Promise {
+ return this.estimateWithFee(constants.HOME_TO_FOREIGN_FEE_TYPE, value)
+ }
+
+ async estimateBtoA(value: ValueTypes): Promise {
+ return this.estimateWithFee(constants.FOREIGN_TO_HOME_FEE_TYPE, value)
+ }
+
+ async estimateWithFee(feeType: string, value: ValueTypes): Promise {
+ const web3 = this.getExchange()
+ .getAsset(this.assetA)
+ .getWeb3()
+
+ const userAmount = this._getValue(value)
+
+ const contract = new web3.eth.Contract(MEDIATOR_ERC_TO_NATIVE_ABI, this.assetABridge)
+ const { feeAmount, feePercentage } = await this.getFee(feeType, contract, userAmount)
+ const finalAmount = toBN(userAmount).sub(feeAmount)
+ const estimateInfo = feeAmount.isZero() ? null : `${constants.ESTIMATE_FEE_MESSAGE} Fee: ${feePercentage}%`
+
+ return {
+ estimate: finalAmount.toString(),
+ estimateInfo
+ }
+ }
+
+ async getFee(feeType, contract, value): Promise<{ feeAmount: BN; feePercentage: number }> {
+ const fee = toBN(await contract.methods.getFee(feeType).call())
+ const feePercentage = Number(fromWei(fee, 'ether')) * 100
+ const feeAmount = toBN(await contract.methods.calculateFee(feeType, value).call())
+ return {
+ feeAmount,
+ feePercentage
+ }
+ }
+}
diff --git a/burner-wallet-plugin/tokenbridge-bw-exchange/src/index.ts b/burner-wallet-plugin/tokenbridge-bw-exchange/src/index.ts
index 29df51fbf..f43b67b1d 100644
--- a/burner-wallet-plugin/tokenbridge-bw-exchange/src/index.ts
+++ b/burner-wallet-plugin/tokenbridge-bw-exchange/src/index.ts
@@ -1,2 +1,12 @@
-export { ERC677Asset, NativeMediatorAsset, sPOA, Etc, Wetc, TokenBridgeGateway, Mediator } from './burner-wallet'
+export {
+ ERC677Asset,
+ BridgeableERC20Asset,
+ NativeMediatorAsset,
+ sPOA,
+ Etc,
+ Wetc,
+ TokenBridgeGateway,
+ Mediator,
+ MediatorErcToNative
+} from './burner-wallet'
export { WETCBridge } from './wetc-bridge'
diff --git a/burner-wallet-plugin/tokenbridge-bw-exchange/src/utils/abis.ts b/burner-wallet-plugin/tokenbridge-bw-exchange/src/utils/abis.ts
index c7c5a4122..dceeb2e2e 100644
--- a/burner-wallet-plugin/tokenbridge-bw-exchange/src/utils/abis.ts
+++ b/burner-wallet-plugin/tokenbridge-bw-exchange/src/utils/abis.ts
@@ -3,3 +3,4 @@ export { default as FOREIGN_NATIVE_TO_ERC_ABI } from './abis/ForeignBridgeNative
export { default as HOME_NATIVE_TO_ERC_ABI } from './abis/HomeBridgeNativeToErc'
export { default as MEDIATOR_ABI } from './abis/Mediator'
export { default as MEDIATOR_FEE_MANAGER_ABI } from './abis/MediatorFeeManager'
+export { default as MEDIATOR_ERC_TO_NATIVE_ABI } from './abis/MediatorErcToNative'
diff --git a/burner-wallet-plugin/tokenbridge-bw-exchange/src/utils/abis/Mediator.ts b/burner-wallet-plugin/tokenbridge-bw-exchange/src/utils/abis/Mediator.ts
index 7c391a0e7..f52a578e2 100644
--- a/burner-wallet-plugin/tokenbridge-bw-exchange/src/utils/abis/Mediator.ts
+++ b/burner-wallet-plugin/tokenbridge-bw-exchange/src/utils/abis/Mediator.ts
@@ -34,5 +34,23 @@ export default [
payable: false,
stateMutability: 'view',
type: 'function'
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: '',
+ type: 'address'
+ },
+ {
+ name: '',
+ type: 'uint256'
+ }
+ ],
+ name: 'relayTokens',
+ outputs: [],
+ payable: false,
+ stateMutability: 'nonpayable',
+ type: 'function'
}
]
diff --git a/burner-wallet-plugin/tokenbridge-bw-exchange/src/utils/abis/MediatorErcToNative.ts b/burner-wallet-plugin/tokenbridge-bw-exchange/src/utils/abis/MediatorErcToNative.ts
new file mode 100644
index 000000000..6954f959d
--- /dev/null
+++ b/burner-wallet-plugin/tokenbridge-bw-exchange/src/utils/abis/MediatorErcToNative.ts
@@ -0,0 +1,44 @@
+export default [
+ {
+ constant: true,
+ inputs: [
+ {
+ name: '',
+ type: 'bytes32'
+ }
+ ],
+ name: 'getFee',
+ outputs: [
+ {
+ name: '',
+ type: 'uint256'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [
+ {
+ name: '',
+ type: 'bytes32'
+ },
+ {
+ name: '',
+ type: 'uint256'
+ }
+ ],
+ name: 'calculateFee',
+ outputs: [
+ {
+ name: '',
+ type: 'uint256'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ }
+]
diff --git a/burner-wallet-plugin/tokenbridge-bw-exchange/src/utils/index.ts b/burner-wallet-plugin/tokenbridge-bw-exchange/src/utils/index.ts
index 52d3593c1..dad1b86cb 100644
--- a/burner-wallet-plugin/tokenbridge-bw-exchange/src/utils/index.ts
+++ b/burner-wallet-plugin/tokenbridge-bw-exchange/src/utils/index.ts
@@ -4,5 +4,6 @@ export {
FOREIGN_NATIVE_TO_ERC_ABI,
HOME_NATIVE_TO_ERC_ABI,
MEDIATOR_ABI,
- MEDIATOR_FEE_MANAGER_ABI
+ MEDIATOR_FEE_MANAGER_ABI,
+ MEDIATOR_ERC_TO_NATIVE_ABI
} from './abis'
diff --git a/burner-wallet-plugin/tokenbridge-bw-exchange/src/utils/utils.ts b/burner-wallet-plugin/tokenbridge-bw-exchange/src/utils/utils.ts
index 2bf0aa343..766087da1 100644
--- a/burner-wallet-plugin/tokenbridge-bw-exchange/src/utils/utils.ts
+++ b/burner-wallet-plugin/tokenbridge-bw-exchange/src/utils/utils.ts
@@ -7,7 +7,11 @@ export const constants = {
EXCHANGE_TIMEOUT: 300000,
MAX_FEE: toWei('1', 'ether'),
ESTIMATE_FEE_MESSAGE: 'Estimation takes fee charges into consideration.',
- ZERO_ADDRESS: '0x0000000000000000000000000000000000000000'
+ ZERO_ADDRESS: '0x0000000000000000000000000000000000000000',
+ TRANSFER_TOPIC: '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
+ // fee types are taken from contracts/upgradeable_contracts/amb_erc20_to_native/HomeFeeManagerAMBErc20ToNative.sol
+ HOME_TO_FOREIGN_FEE_TYPE: '0x741ede137d0537e88e0ea0ff25b1f22d837903dbbee8980b4a06e8523247ee26',
+ FOREIGN_TO_HOME_FEE_TYPE: '0x03be2b2875cb41e0e77355e802a16769bb8dfcf825061cde185c73bf94f12625'
}
export const waitForEvent = async (web3, contract: Contract, event: string, callback: Function) => {
diff --git a/burner-wallet-plugin/yarn.lock b/burner-wallet-plugin/yarn.lock
index 06d25d262..ed7454802 100644
--- a/burner-wallet-plugin/yarn.lock
+++ b/burner-wallet-plugin/yarn.lock
@@ -2600,11 +2600,6 @@
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
-"@types/mocha@^7.0.2":
- version "7.0.2"
- resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-7.0.2.tgz#b17f16cf933597e10d6d78eae3251e692ce8b0ce"
- integrity sha512-ZvO2tAcjmMi8V/5Z3JsyofMe3hasRcaw88cto5etSVMwVQfeivGAlEYmaQgceUSVYFofVjT+ioHsATjdWcFt1w==
-
"@types/node@*", "@types/node@>= 8":
version "13.11.0"
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.11.0.tgz#390ea202539c61c8fa6ba4428b57e05bc36dc47b"
@@ -3220,11 +3215,6 @@ are-we-there-yet@~1.1.2:
delegates "^1.0.0"
readable-stream "^2.0.6"
-arg@^4.1.0:
- version "4.1.3"
- resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089"
- integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
-
argparse@^1.0.7:
version "1.0.10"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
@@ -3350,11 +3340,6 @@ assert@^1.1.1:
object-assign "^4.1.1"
util "0.10.3"
-assertion-error@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b"
- integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==
-
assign-symbols@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
@@ -3450,13 +3435,6 @@ axios@^0.18.0:
follow-redirects "1.5.10"
is-buffer "^2.0.2"
-axios@^0.19.0:
- version "0.19.2"
- resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27"
- integrity sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==
- dependencies:
- follow-redirects "1.5.10"
-
axobject-query@^2.0.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.1.2.tgz#2bdffc0371e643e5f03ba99065d5179b9ca79799"
@@ -3821,11 +3799,6 @@ browser-resolve@^1.11.3:
dependencies:
resolve "1.1.7"
-browser-stdout@1.3.1:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60"
- integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==
-
browserify-aes@^1.0.0, browserify-aes@^1.0.4, browserify-aes@^1.0.6:
version "1.2.0"
resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48"
@@ -3838,7 +3811,7 @@ browserify-aes@^1.0.0, browserify-aes@^1.0.4, browserify-aes@^1.0.6:
inherits "^2.0.1"
safe-buffer "^5.0.1"
-browserify-cipher@^1.0.0, browserify-cipher@^1.0.1:
+browserify-cipher@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0"
integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==
@@ -4215,18 +4188,6 @@ caseless@~0.12.0:
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
-chai@^4.2.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/chai/-/chai-4.2.0.tgz#760aa72cf20e3795e84b12877ce0e83737aa29e5"
- integrity sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==
- dependencies:
- assertion-error "^1.1.0"
- check-error "^1.0.2"
- deep-eql "^3.0.1"
- get-func-name "^2.0.0"
- pathval "^1.1.0"
- type-detect "^4.0.5"
-
chalk@2.4.2, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.1, chalk@^2.4.1, chalk@^2.4.2:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
@@ -4252,11 +4213,6 @@ chardet@^0.7.0:
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
-check-error@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82"
- integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=
-
check-types@^8.0.3:
version "8.0.3"
resolved "https://registry.yarnpkg.com/check-types/-/check-types-8.0.3.tgz#3356cca19c889544f2d7a95ed49ce508a0ecf552"
@@ -4490,11 +4446,6 @@ combined-stream@^1.0.6, combined-stream@~1.0.6:
dependencies:
delayed-stream "~1.0.0"
-commander@2.15.1:
- version "2.15.1"
- resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f"
- integrity sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==
-
commander@2.17.x:
version "2.17.1"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf"
@@ -5290,13 +5241,6 @@ dedent@^0.7.0:
resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c"
integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=
-deep-eql@^3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df"
- integrity sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==
- dependencies:
- type-detect "^4.0.0"
-
deep-equal@^1.0.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a"
@@ -5469,16 +5413,6 @@ diff-sequences@^24.9.0:
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.9.0.tgz#5715d6244e2aa65f48bba0bc972db0b0b11e95b5"
integrity sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==
-diff@3.5.0:
- version "3.5.0"
- resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
- integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==
-
-diff@^4.0.1:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
- integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
-
diffie-hellman@^5.0.0:
version "5.0.3"
resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875"
@@ -6531,7 +6465,7 @@ ethers@4.0.44:
uuid "2.0.1"
xmlhttprequest "1.8.0"
-ethers@^4.0.27, ethers@~4.0.4:
+ethers@~4.0.4:
version "4.0.46"
resolved "https://registry.yarnpkg.com/ethers/-/ethers-4.0.46.tgz#13cd3ed099487f43ece00194b89a8a8781f71507"
integrity sha512-/dPMzzpInhtiip4hKFvsDiJKeRk64IhyA+Po7CtNXneQFSOCYXg8eBFt+jXbxUQyApgWnWOtYxWdfn9+CvvxDA==
@@ -6546,7 +6480,7 @@ ethers@^4.0.27, ethers@~4.0.4:
uuid "2.0.1"
xmlhttprequest "1.8.0"
-ethjs-unit@0.1.6, ethjs-unit@^0.1.6:
+ethjs-unit@0.1.6:
version "0.1.6"
resolved "https://registry.yarnpkg.com/ethjs-unit/-/ethjs-unit-0.1.6.tgz#c665921e476e87bce2a9d588a6fe0405b2c41699"
integrity sha1-xmWSHkduh7ziqdWIpv4EBbLEFpk=
@@ -6562,11 +6496,6 @@ ethjs-util@0.1.6, ethjs-util@^0.1.3:
is-hex-prefixed "1.0.0"
strip-hex-prefix "1.0.0"
-eventemitter3@3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.0.tgz#090b4d6cdbd645ed10bf750d4b5407942d7ba163"
- integrity sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==
-
eventemitter3@3.1.2, eventemitter3@^3.1.0:
version "3.1.2"
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7"
@@ -7164,11 +7093,6 @@ get-caller-file@^2.0.1:
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
-get-func-name@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41"
- integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=
-
get-own-enumerable-property-symbols@^3.0.0:
version "3.0.2"
resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664"
@@ -7303,18 +7227,6 @@ glob-to-regexp@^0.3.0:
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab"
integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=
-glob@7.1.2:
- version "7.1.2"
- resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
- integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==
- dependencies:
- fs.realpath "^1.0.0"
- inflight "^1.0.4"
- inherits "2"
- minimatch "^3.0.4"
- once "^1.3.0"
- path-is-absolute "^1.0.0"
-
glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4:
version "7.1.6"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
@@ -7448,11 +7360,6 @@ graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.
resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725"
integrity sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=
-growl@1.10.5:
- version "1.10.5"
- resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e"
- integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==
-
growly@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
@@ -7611,11 +7518,6 @@ hdkey@^1.1.1:
safe-buffer "^5.1.1"
secp256k1 "^3.0.1"
-he@1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
- integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0=
-
he@1.2.x:
version "1.2.0"
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
@@ -9690,11 +9592,6 @@ make-dir@^2.0.0, make-dir@^2.1.0:
pify "^4.0.1"
semver "^5.6.0"
-make-error@^1.1.1:
- version "1.3.6"
- resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
- integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
-
make-fetch-happen@^5.0.0:
version "5.0.2"
resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-5.0.2.tgz#aa8387104f2687edca01c8687ee45013d02d19bd"
@@ -10046,11 +9943,6 @@ minimist-options@^3.0.1:
arrify "^1.0.1"
is-plain-obj "^1.1.0"
-minimist@0.0.8:
- version "0.0.8"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
- integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=
-
minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5:
version "1.2.5"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
@@ -10115,13 +10007,6 @@ mkdirp@*:
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
-mkdirp@0.5.1:
- version "0.5.1"
- resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
- integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=
- dependencies:
- minimist "0.0.8"
-
mkdirp@^0.5.0, mkdirp@^0.5.1:
version "0.5.5"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
@@ -10136,23 +10021,6 @@ mkdirp@~0.5.0, mkdirp@~0.5.1:
dependencies:
minimist "^1.2.5"
-mocha@^5.2.0:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.2.0.tgz#6d8ae508f59167f940f2b5b3c4a612ae50c90ae6"
- integrity sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==
- dependencies:
- browser-stdout "1.3.1"
- commander "2.15.1"
- debug "3.1.0"
- diff "3.5.0"
- escape-string-regexp "1.0.5"
- glob "7.1.2"
- growl "1.10.5"
- he "1.1.1"
- minimatch "3.0.4"
- mkdirp "0.5.1"
- supports-color "5.4.0"
-
mock-fs@^4.1.0:
version "4.11.0"
resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.11.0.tgz#0828107e4b843a6ba855ecebfe3c6e073b69db92"
@@ -10237,7 +10105,7 @@ nan@2.13.2:
resolved "https://registry.yarnpkg.com/nan/-/nan-2.13.2.tgz#f51dc7ae66ba7d5d55e1e6d4d8092e802c9aefe7"
integrity sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw==
-nan@2.14.0, nan@^2.0.8, nan@^2.12.1, nan@^2.14.0, nan@^2.2.1:
+nan@2.14.0, nan@^2.12.1, nan@^2.14.0, nan@^2.2.1:
version "2.14.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
@@ -11099,12 +10967,7 @@ path-type@^4.0.0:
resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
-pathval@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0"
- integrity sha1-uULm1L3mUwBe9rcTYd74cn0GReA=
-
-pbkdf2@^3.0.17, pbkdf2@^3.0.3:
+pbkdf2@^3.0.3:
version "3.0.17"
resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.17.tgz#976c206530617b14ebb32114239f7b09336e93a6"
integrity sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==
@@ -12127,7 +11990,7 @@ querystring@0.2.0:
resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=
-querystringify@^2.0.0, querystringify@^2.1.1:
+querystringify@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.1.tgz#60e5a5fd64a7f8bfa4d2ab2ed6fdf4c85bad154e"
integrity sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==
@@ -12970,29 +12833,6 @@ scrypt-js@2.0.4:
resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-2.0.4.tgz#32f8c5149f0797672e551c07e230f834b6af5f16"
integrity sha512-4KsaGcPnuhtCZQCxFxN3GVYIhKFPTdLd8PLC552XwbMndtD0cjRFAhDuuydXQ0h08ZfPgzqe6EKHozpuH74iDw==
-scrypt.js@0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/scrypt.js/-/scrypt.js-0.3.0.tgz#6c62d61728ad533c8c376a2e5e3e86d41a95c4c0"
- integrity sha512-42LTc1nyFsyv/o0gcHtDztrn+aqpkaCNt5Qh7ATBZfhEZU7IC/0oT/qbBH+uRNoAPvs2fwiOId68FDEoSRA8/A==
- dependencies:
- scryptsy "^1.2.1"
- optionalDependencies:
- scrypt "^6.0.2"
-
-scrypt@^6.0.2:
- version "6.0.3"
- resolved "https://registry.yarnpkg.com/scrypt/-/scrypt-6.0.3.tgz#04e014a5682b53fa50c2d5cce167d719c06d870d"
- integrity sha1-BOAUpWgrU/pQwtXM4WfXGcBthw0=
- dependencies:
- nan "^2.0.8"
-
-scryptsy@^1.2.1:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/scryptsy/-/scryptsy-1.2.1.tgz#a3225fa4b2524f802700761e2855bdf3b2d92163"
- integrity sha1-oyJfpLJST4AnAHYeKFW987LZIWM=
- dependencies:
- pbkdf2 "^3.0.3"
-
scryptsy@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/scryptsy/-/scryptsy-2.1.0.tgz#8d1e8d0c025b58fdd25b6fa9a0dc905ee8faa790"
@@ -13872,13 +13712,6 @@ stylis@^3.5.0:
resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.5.4.tgz#f665f25f5e299cf3d64654ab949a57c768b73fbe"
integrity sha512-8/3pSmthWM7lsPBKv7NXkzn2Uc9W7NotcwGNpJaa3k7WMM1XDCA4MgT5k/8BIexd5ydZdboXtU90XH9Ec4Bv/Q==
-supports-color@5.4.0:
- version "5.4.0"
- resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54"
- integrity sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==
- dependencies:
- has-flag "^3.0.0"
-
supports-color@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
@@ -14243,17 +14076,6 @@ tryer@^1.0.1:
resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8"
integrity sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==
-ts-node@^8.8.2:
- version "8.8.2"
- resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.8.2.tgz#0b39e690bee39ea5111513a9d2bcdc0bc121755f"
- integrity sha512-duVj6BpSpUpD/oM4MfhO98ozgkp3Gt9qIp3jGxwU2DFvl/3IRaEAvbLa8G60uS7C77457e/m5TMowjedeRxI1Q==
- dependencies:
- arg "^4.1.0"
- diff "^4.0.1"
- make-error "^1.1.1"
- source-map-support "^0.5.6"
- yn "3.1.1"
-
ts-pnp@1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.1.2.tgz#be8e4bfce5d00f0f58e0666a82260c34a57af552"
@@ -14300,11 +14122,6 @@ type-check@~0.3.2:
dependencies:
prelude-ls "~1.1.2"
-type-detect@^4.0.0, type-detect@^4.0.5:
- version "4.0.8"
- resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
- integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
-
type-fest@^0.3.0:
version "0.3.1"
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.3.1.tgz#63d00d204e059474fe5e1b7c011112bbd1dc29e1"
@@ -14350,11 +14167,6 @@ typescript@3.5.3:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.3.tgz#c830f657f93f1ea846819e929092f5fe5983e977"
integrity sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==
-typescript@^3.5.2:
- version "3.8.3"
- resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061"
- integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==
-
uglify-js@3.4.x:
version "3.4.10"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.10.tgz#9ad9563d8eb3acdfb8d38597d2af1d815f6a755f"
@@ -14538,14 +14350,6 @@ url-parse-lax@^3.0.0:
dependencies:
prepend-http "^2.0.0"
-url-parse@1.4.4:
- version "1.4.4"
- resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.4.tgz#cac1556e95faa0303691fec5cf9d5a1bc34648f8"
- integrity sha512-/92DTTorg4JjktLNLe6GPS2/RvAd/RGr6LuktmWSMLEOa6rjnlrFXNgSbSmkNvCoL2T028A0a1JaJLzRMlFoHg==
- dependencies:
- querystringify "^2.0.0"
- requires-port "^1.0.0"
-
url-parse@^1.4.3:
version "1.4.7"
resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.7.tgz#a8a83535e8c00a316e403a5db4ac1b9b853ae278"
@@ -14577,11 +14381,6 @@ use@^3.1.0:
resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==
-utf8@2.1.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/utf8/-/utf8-2.1.1.tgz#2e01db02f7d8d0944f77104f1609eb0c304cf768"
- integrity sha1-LgHbAvfY0JRPdxBPFgnrDDBM92g=
-
utf8@3.0.0, utf8@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1"
@@ -14771,17 +14570,6 @@ web3-bzz@1.2.6:
swarm-js "0.1.39"
underscore "1.9.1"
-web3-core-helpers@1.0.0-beta.55:
- version "1.0.0-beta.55"
- resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.0.0-beta.55.tgz#832b8499889f9f514b1d174f00172fd3683d63de"
- integrity sha512-suj9Xy/lIqajaYLJTEjr2rlFgu6hGYwChHmf8+qNrC2luZA6kirTamtB9VThWMxbywx7p0bqQFjW6zXogAgWhg==
- dependencies:
- "@babel/runtime" "^7.3.1"
- lodash "^4.17.11"
- web3-core "1.0.0-beta.55"
- web3-eth-iban "1.0.0-beta.55"
- web3-utils "1.0.0-beta.55"
-
web3-core-helpers@1.2.6:
version "1.2.6"
resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.2.6.tgz#7aacd25bf8015adcdfc0f3243d0dcfdff0373f7d"
@@ -14791,20 +14579,6 @@ web3-core-helpers@1.2.6:
web3-eth-iban "1.2.6"
web3-utils "1.2.6"
-web3-core-method@1.0.0-beta.55:
- version "1.0.0-beta.55"
- resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.0.0-beta.55.tgz#0af994295ac2dd64ccd53305b7df8da76e11da49"
- integrity sha512-w1cW/s2ji9qGELHk2uMJCn1ooay0JJLVoPD1nvmsW6OTRWcVjxa62nJrFQhe6P5lEb83Xk9oHgmCxZoVUHibOw==
- dependencies:
- "@babel/runtime" "^7.3.1"
- eventemitter3 "3.1.0"
- lodash "^4.17.11"
- rxjs "^6.4.0"
- web3-core "1.0.0-beta.55"
- web3-core-helpers "1.0.0-beta.55"
- web3-core-subscriptions "1.0.0-beta.55"
- web3-utils "1.0.0-beta.55"
-
web3-core-method@1.2.6:
version "1.2.6"
resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.2.6.tgz#f5a3e4d304abaf382923c8ab88ec8eeef45c1b3b"
@@ -14835,15 +14609,6 @@ web3-core-requestmanager@1.2.6:
web3-providers-ipc "1.2.6"
web3-providers-ws "1.2.6"
-web3-core-subscriptions@1.0.0-beta.55:
- version "1.0.0-beta.55"
- resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.0.0-beta.55.tgz#105902c13db53466fc17d07a981ad3d41c700f76"
- integrity sha512-pb3oQbUzK7IoyXwag8TYInQddg0rr7BHxKc+Pbs/92hVNQ5ps4iGMVJKezdrjlQ1IJEEUiDIglXl4LZ1hIuMkw==
- dependencies:
- "@babel/runtime" "^7.3.1"
- eventemitter3 "^3.1.0"
- lodash "^4.17.11"
-
web3-core-subscriptions@1.2.6:
version "1.2.6"
resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.2.6.tgz#9d44189e2321f8f1abc31f6c09103b5283461b57"
@@ -14853,19 +14618,6 @@ web3-core-subscriptions@1.2.6:
underscore "1.9.1"
web3-core-helpers "1.2.6"
-web3-core@1.0.0-beta.55:
- version "1.0.0-beta.55"
- resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.0.0-beta.55.tgz#26b9abbf1bc1837c9cc90f06ecbc4ed714f89b53"
- integrity sha512-AMMp7TLEtE7u8IJAu/THrRhBTZyZzeo7Y6GiWYNwb5+KStC9hIGLr9cI1KX9R6ZioTOLRHrqT7awDhnJ1ku2mg==
- dependencies:
- "@babel/runtime" "^7.3.1"
- "@types/bn.js" "^4.11.4"
- "@types/node" "^10.12.18"
- lodash "^4.17.11"
- web3-core-method "1.0.0-beta.55"
- web3-providers "1.0.0-beta.55"
- web3-utils "1.0.0-beta.55"
-
web3-core@1.2.6:
version "1.2.6"
resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.2.6.tgz#bb42a1d7ae49a7258460f0d95ddb00906f59ef92"
@@ -14878,16 +14630,6 @@ web3-core@1.2.6:
web3-core-requestmanager "1.2.6"
web3-utils "1.2.6"
-web3-eth-abi@1.0.0-beta.55:
- version "1.0.0-beta.55"
- resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.0.0-beta.55.tgz#69250420039346105a3d0f899c0a8a53be926f97"
- integrity sha512-3h1xnm/vYmKUXTOYAOP0OsB5uijQV76pNNRGKOB6Dq6GR1pbcbD3WrB/4I643YA8l91t5FRzFzUiA3S77R2iqw==
- dependencies:
- "@babel/runtime" "^7.3.1"
- ethers "^4.0.27"
- lodash "^4.17.11"
- web3-utils "1.0.0-beta.55"
-
web3-eth-abi@1.2.6, web3-eth-abi@^1.2.1:
version "1.2.6"
resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.2.6.tgz#b495383cc5c0d8e2857b26e7fe25606685983b25"
@@ -14897,25 +14639,6 @@ web3-eth-abi@1.2.6, web3-eth-abi@^1.2.1:
underscore "1.9.1"
web3-utils "1.2.6"
-web3-eth-accounts@1.0.0-beta.55:
- version "1.0.0-beta.55"
- resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.0.0-beta.55.tgz#ba734ffdc1e3cc8ac0ea01de5241323a0c2f69f3"
- integrity sha512-VfzvwpSDHXqRVelIxsBVhgbV9BkFvhJ/q+bKhnVUUXV0JAhMK/7uC92TsqKk4EBYuqpHyZ1jjqrL4n03fMU7zw==
- dependencies:
- "@babel/runtime" "^7.3.1"
- browserify-cipher "^1.0.1"
- eth-lib "0.2.8"
- lodash "^4.17.11"
- pbkdf2 "^3.0.17"
- randombytes "^2.1.0"
- scrypt.js "0.3.0"
- uuid "3.3.2"
- web3-core "1.0.0-beta.55"
- web3-core-helpers "1.0.0-beta.55"
- web3-core-method "1.0.0-beta.55"
- web3-providers "1.0.0-beta.55"
- web3-utils "1.0.0-beta.55"
-
web3-eth-accounts@1.2.6:
version "1.2.6"
resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.2.6.tgz#a1ba4bf75fa8102a3ec6cddd0eccd72462262720"
@@ -14934,23 +14657,6 @@ web3-eth-accounts@1.2.6:
web3-core-method "1.2.6"
web3-utils "1.2.6"
-web3-eth-contract@1.0.0-beta.55:
- version "1.0.0-beta.55"
- resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.0.0-beta.55.tgz#cd9e6727ff73d648ebe7cae17516e8aec5873c65"
- integrity sha512-v6oB1wfH039/A5sTb4ZTKX++fcBTHEkuQGpq50ATIDoxP/UTz2+6S+iL+3sCJTsByPw2/Bni/HM7NmLkXqzg/Q==
- dependencies:
- "@babel/runtime" "^7.3.1"
- "@types/bn.js" "^4.11.4"
- lodash "^4.17.11"
- web3-core "1.0.0-beta.55"
- web3-core-helpers "1.0.0-beta.55"
- web3-core-method "1.0.0-beta.55"
- web3-core-subscriptions "1.0.0-beta.55"
- web3-eth-abi "1.0.0-beta.55"
- web3-eth-accounts "1.0.0-beta.55"
- web3-providers "1.0.0-beta.55"
- web3-utils "1.0.0-beta.55"
-
web3-eth-contract@1.2.6:
version "1.2.6"
resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.2.6.tgz#39111543960035ed94c597a239cf5aa1da796741"
@@ -14966,24 +14672,6 @@ web3-eth-contract@1.2.6:
web3-eth-abi "1.2.6"
web3-utils "1.2.6"
-web3-eth-ens@1.0.0-beta.55:
- version "1.0.0-beta.55"
- resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.0.0-beta.55.tgz#4341434a3406728212d411ae7f22d4cf5b8642fe"
- integrity sha512-jEL17coO0FJXb7KYq4+7DhVXj0Rh+wHfZ86jOvFUvJsRaUHfqK2TlMatuhD2mbrmxpBYb6oMPnXVnNK9bnD5Rg==
- dependencies:
- "@babel/runtime" "^7.3.1"
- eth-ens-namehash "2.0.8"
- lodash "^4.17.11"
- web3-core "1.0.0-beta.55"
- web3-core-helpers "1.0.0-beta.55"
- web3-core-method "1.0.0-beta.55"
- web3-eth-abi "1.0.0-beta.55"
- web3-eth-accounts "1.0.0-beta.55"
- web3-eth-contract "1.0.0-beta.55"
- web3-net "1.0.0-beta.55"
- web3-providers "1.0.0-beta.55"
- web3-utils "1.0.0-beta.55"
-
web3-eth-ens@1.2.6:
version "1.2.6"
resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.2.6.tgz#bf86a624c4c72bc59913c2345180d3ea947e110d"
@@ -14998,15 +14686,6 @@ web3-eth-ens@1.2.6:
web3-eth-contract "1.2.6"
web3-utils "1.2.6"
-web3-eth-iban@1.0.0-beta.55:
- version "1.0.0-beta.55"
- resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.0.0-beta.55.tgz#15146a69de21addc99e7dbfb2920555b1e729637"
- integrity sha512-a2Fxsb5Mssa+jiXgjUdIzJipE0175IcQXJbZLpKft2+zeSJWNTbaa3PQD2vPPpIM4W789q06N+f9Zc0Fyls+1g==
- dependencies:
- "@babel/runtime" "^7.3.1"
- bn.js "4.11.8"
- web3-utils "1.0.0-beta.55"
-
web3-eth-iban@1.2.6:
version "1.2.6"
resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.2.6.tgz#0b22191fd1aa6e27f7ef0820df75820bfb4ed46b"
@@ -15015,20 +14694,6 @@ web3-eth-iban@1.2.6:
bn.js "4.11.8"
web3-utils "1.2.6"
-web3-eth-personal@1.0.0-beta.55:
- version "1.0.0-beta.55"
- resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.0.0-beta.55.tgz#76e9d2da1501ee3c686751e7c7df63cc11793a1d"
- integrity sha512-H0mahLQx6Oj7lpgTamKAswr3rHChRUZijeWAar2Hj7BABQlLRKwx8n09nYhxggvvLYQNQS90JjvQue7rAo2LQQ==
- dependencies:
- "@babel/runtime" "^7.3.1"
- web3-core "1.0.0-beta.55"
- web3-core-helpers "1.0.0-beta.55"
- web3-core-method "1.0.0-beta.55"
- web3-eth-accounts "1.0.0-beta.55"
- web3-net "1.0.0-beta.55"
- web3-providers "1.0.0-beta.55"
- web3-utils "1.0.0-beta.55"
-
web3-eth-personal@1.2.6:
version "1.2.6"
resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.2.6.tgz#47a0a0657ec04dd77f95451a6869d4751d324b6b"
@@ -15041,28 +14706,6 @@ web3-eth-personal@1.2.6:
web3-net "1.2.6"
web3-utils "1.2.6"
-web3-eth@1.0.0-beta.55:
- version "1.0.0-beta.55"
- resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.0.0-beta.55.tgz#bb52150df0a77bd13511449a53793d4eb23ade6e"
- integrity sha512-F3zJ9I1gOgQdNGfi2Dy2lmj6OqCMJoRN01XHhQZagq0HY1JYMfObtfMi5E3L+qsegsSddHbqp4YY57tKx6uxpA==
- dependencies:
- "@babel/runtime" "^7.3.1"
- ethereumjs-tx "^1.3.7"
- rxjs "^6.4.0"
- web3-core "1.0.0-beta.55"
- web3-core-helpers "1.0.0-beta.55"
- web3-core-method "1.0.0-beta.55"
- web3-core-subscriptions "1.0.0-beta.55"
- web3-eth-abi "1.0.0-beta.55"
- web3-eth-accounts "1.0.0-beta.55"
- web3-eth-contract "1.0.0-beta.55"
- web3-eth-ens "1.0.0-beta.55"
- web3-eth-iban "1.0.0-beta.55"
- web3-eth-personal "1.0.0-beta.55"
- web3-net "1.0.0-beta.55"
- web3-providers "1.0.0-beta.55"
- web3-utils "1.0.0-beta.55"
-
web3-eth@1.2.6:
version "1.2.6"
resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.2.6.tgz#15a8c65fdde0727872848cae506758d302d8d046"
@@ -15082,19 +14725,6 @@ web3-eth@1.2.6:
web3-net "1.2.6"
web3-utils "1.2.6"
-web3-net@1.0.0-beta.55:
- version "1.0.0-beta.55"
- resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.0.0-beta.55.tgz#daf24323df16a890a0bac6c6eda48b6e8c7e96ef"
- integrity sha512-do2WY8+/GArJSWX7k/zZ7nBnV9Y3n6LhPYkwT3LeFqDzD515bKwlomaNC8hOaTc6UQyXIoPprYTK2FevL7jrZw==
- dependencies:
- "@babel/runtime" "^7.3.1"
- lodash "^4.17.11"
- web3-core "1.0.0-beta.55"
- web3-core-helpers "1.0.0-beta.55"
- web3-core-method "1.0.0-beta.55"
- web3-providers "1.0.0-beta.55"
- web3-utils "1.0.0-beta.55"
-
web3-net@1.2.6:
version "1.2.6"
resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.2.6.tgz#035ca0fbe55282fda848ca17ebb4c8966147e5ea"
@@ -15158,37 +14788,6 @@ web3-providers-ws@1.2.6:
underscore "1.9.1"
web3-core-helpers "1.2.6"
-web3-providers@1.0.0-beta.55:
- version "1.0.0-beta.55"
- resolved "https://registry.yarnpkg.com/web3-providers/-/web3-providers-1.0.0-beta.55.tgz#639503517741b69baaa82f1f940630df6a25992b"
- integrity sha512-MNifc7W+iF6rykpbDR1MuX152jshWdZXHAU9Dk0Ja2/23elhIs4nCWs7wOX9FHrKgdrQbscPoq0uy+0aGzyWVQ==
- dependencies:
- "@babel/runtime" "^7.3.1"
- "@types/node" "^10.12.18"
- eventemitter3 "3.1.0"
- lodash "^4.17.11"
- url-parse "1.4.4"
- web3-core "1.0.0-beta.55"
- web3-core-helpers "1.0.0-beta.55"
- web3-core-method "1.0.0-beta.55"
- web3-utils "1.0.0-beta.55"
- websocket "^1.0.28"
- xhr2-cookies "1.1.0"
-
-web3-shh@1.0.0-beta.55:
- version "1.0.0-beta.55"
- resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.0.0-beta.55.tgz#56f152ebcefb791dab86d2e6f1c296f8c1553644"
- integrity sha512-lGP2HQ/1ThNnfoU8677aL48KsTx4Ht+2KQIn39dGpxVZqysQmovQIltbymVnAr4h8wofwcEz46iNHGa+PAyNzA==
- dependencies:
- "@babel/runtime" "^7.3.1"
- web3-core "1.0.0-beta.55"
- web3-core-helpers "1.0.0-beta.55"
- web3-core-method "1.0.0-beta.55"
- web3-core-subscriptions "1.0.0-beta.55"
- web3-net "1.0.0-beta.55"
- web3-providers "1.0.0-beta.55"
- web3-utils "1.0.0-beta.55"
-
web3-shh@1.2.6:
version "1.2.6"
resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.2.6.tgz#2492616da4cac32d4c7534b890f43bac63190c14"
@@ -15199,22 +14798,6 @@ web3-shh@1.2.6:
web3-core-subscriptions "1.2.6"
web3-net "1.2.6"
-web3-utils@1.0.0-beta.55:
- version "1.0.0-beta.55"
- resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.0.0-beta.55.tgz#beb40926b7c04208b752d36a9bc959d27a04b308"
- integrity sha512-ASWqUi8gtWK02Tp8ZtcoAbHenMpQXNvHrakgzvqTNNZn26wgpv+Q4mdPi0KOR6ZgHFL8R/9b5BBoUTglS1WPpg==
- dependencies:
- "@babel/runtime" "^7.3.1"
- "@types/bn.js" "^4.11.4"
- "@types/node" "^10.12.18"
- bn.js "4.11.8"
- eth-lib "0.2.8"
- ethjs-unit "^0.1.6"
- lodash "^4.17.11"
- number-to-bn "1.7.0"
- randombytes "^2.1.0"
- utf8 "2.1.1"
-
web3-utils@1.2.6, web3-utils@^1.2.1, web3-utils@^1.2.2:
version "1.2.6"
resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.2.6.tgz#b9a25432da00976457fcc1094c4af8ac6d486db9"
@@ -15229,21 +14812,6 @@ web3-utils@1.2.6, web3-utils@^1.2.1, web3-utils@^1.2.2:
underscore "1.9.1"
utf8 "3.0.0"
-web3@1.0.0-beta.55:
- version "1.0.0-beta.55"
- resolved "https://registry.yarnpkg.com/web3/-/web3-1.0.0-beta.55.tgz#8845075129299da172c2eb41a748c8a87c2a2b5a"
- integrity sha512-yJpwy4IUA3T/F9hWzYQVn0GbJCrAaZ0KTIO3iuqkhaYH0Y09KV7k4GzFi4hN7hT4cFTj4yIKaeVCwQ5kzvi2Vg==
- dependencies:
- "@babel/runtime" "^7.3.1"
- "@types/node" "^10.12.18"
- web3-core "1.0.0-beta.55"
- web3-eth "1.0.0-beta.55"
- web3-eth-personal "1.0.0-beta.55"
- web3-net "1.0.0-beta.55"
- web3-providers "1.0.0-beta.55"
- web3-shh "1.0.0-beta.55"
- web3-utils "1.0.0-beta.55"
-
web3@^1.2.1, web3@^1.2.2:
version "1.2.6"
resolved "https://registry.yarnpkg.com/web3/-/web3-1.2.6.tgz#c497dcb14cdd8d6d9fb6b445b3b68ff83f8ccf68"
@@ -15406,17 +14974,6 @@ websocket-extensions@>=0.1.1:
resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29"
integrity sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==
-websocket@^1.0.28:
- version "1.0.31"
- resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.31.tgz#e5d0f16c3340ed87670e489ecae6144c79358730"
- integrity sha512-VAouplvGKPiKFDTeCCO65vYHsyay8DqoBSlzIO3fayrfOgU94lQN5a1uWVnFrMLceTJw/+fQXR5PGbUVRaHshQ==
- dependencies:
- debug "^2.2.0"
- es5-ext "^0.10.50"
- nan "^2.14.0"
- typedarray-to-buffer "^3.1.5"
- yaeti "^0.0.6"
-
whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3, whatwg-encoding@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0"
@@ -15924,8 +15481,3 @@ yauzl@^2.4.2:
dependencies:
buffer-crc32 "~0.2.3"
fd-slicer "~1.1.0"
-
-yn@3.1.1:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
- integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==
From caf2e2b4d316777f3c7bcc373b6d486bc9afb731 Mon Sep 17 00:00:00 2001
From: Alexander Kolotov
Date: Sun, 5 Jul 2020 00:01:42 +0300
Subject: [PATCH 13/13] Update the contract's submodule to the release 5.1.0
(#381)
---
contracts | 2 +-
e2e-commons/scripts/setupStakeTokens.js | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/contracts b/contracts
index 56c2c3972..d67761d93 160000
--- a/contracts
+++ b/contracts
@@ -1 +1 @@
-Subproject commit 56c2c39722be96381084834db68f8d7acc4805fa
+Subproject commit d67761d93855a2693b719dd619a400b9302b8952
diff --git a/e2e-commons/scripts/setupStakeTokens.js b/e2e-commons/scripts/setupStakeTokens.js
index 07844bbe5..7c878e501 100644
--- a/e2e-commons/scripts/setupStakeTokens.js
+++ b/e2e-commons/scripts/setupStakeTokens.js
@@ -6,7 +6,7 @@ require('dotenv').config({
})
const { sendRawTxHome, sendRawTxForeign, privateKeyToAddress } = require(`${contractsPath}/deploy/src/deploymentUtils`)
const { web3Home, web3Foreign, deploymentPrivateKey } = require(`${contractsPath}/deploy/src/web3`)
-const BlockReward = require(`${contractsPath}/build/contracts/BlockReward.json`)
+const BlockReward = require(`${contractsPath}/build/contracts/BlockRewardMock.json`)
const ERC677BridgeTokenRewardable = require(`${contractsPath}/build/contracts/ERC677BridgeTokenRewardable.json`)
const ERC677MultiBridgeToken = require(`${contractsPath}/build/contracts/ERC677MultiBridgeToken.json`)