Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0451d6e373 | ||
|
|
409044b8a5 | ||
|
|
5fc52f42d7 | ||
|
|
8a0d9f38b0 | ||
|
|
1aee0a84ef | ||
|
|
811b1a27f1 | ||
|
|
4d468ae107 | ||
|
|
4497a024b1 | ||
|
|
6ce98ff3dd | ||
|
|
04f66b243c | ||
|
|
21581b3c01 | ||
|
|
bbc68f9fa2 | ||
|
|
5327688a20 | ||
|
|
1122daf9a1 | ||
|
|
12269d7426 | ||
|
|
683fa0728d | ||
|
|
dd2075c351 | ||
|
|
ce29b95729 | ||
|
|
eb1069497a | ||
|
|
0228fc7d5f | ||
|
|
f8d85b14de | ||
|
|
5fa9d21246 | ||
|
|
611b8c539d | ||
|
|
389cea3c39 |
@@ -8,11 +8,16 @@
|
||||
**/docs
|
||||
**/*.md
|
||||
|
||||
monitor/**/*.env*
|
||||
oracle/**/*.env*
|
||||
!**/.env.example
|
||||
|
||||
contracts/test
|
||||
contracts/build
|
||||
oracle/test
|
||||
monitor/test
|
||||
monitor/responses
|
||||
monitor/cache/*
|
||||
commons/test
|
||||
oracle/**/*.png
|
||||
oracle/**/*.jpg
|
||||
|
||||
120
.github/workflows/main.yml
vendored
120
.github/workflows/main.yml
vendored
@@ -19,9 +19,11 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
- run: git submodule status > submodule.status
|
||||
- id: get_cache_key
|
||||
run: echo "::set-output name=cache_key::cache-repo-${{ hashFiles('yarn.lock', 'package.json', 'submodule.status') }}"
|
||||
- name: Set cache key
|
||||
id: get_cache_key
|
||||
run: |
|
||||
git submodule status > submodule.status
|
||||
echo "::set-output name=cache_key::cache-repo-${{ hashFiles('yarn.lock', 'package.json', 'submodule.status') }}"
|
||||
- uses: actions/cache@v2
|
||||
id: cache-repo
|
||||
with:
|
||||
@@ -29,7 +31,8 @@ jobs:
|
||||
**/node_modules
|
||||
contracts/build
|
||||
key: ${{ steps.get_cache_key.outputs.cache_key }}
|
||||
- if: ${{ !steps.cache-repo.outputs.cache-hit }}
|
||||
- name: Install dependencies and compile contracts
|
||||
if: ${{ !steps.cache-repo.outputs.cache-hit }}
|
||||
run: |
|
||||
yarn install --frozen-lockfile
|
||||
yarn run install:deploy
|
||||
@@ -56,7 +59,8 @@ jobs:
|
||||
**/node_modules
|
||||
contracts/build
|
||||
key: ${{ needs.initialize.outputs.cache_key }}
|
||||
- run: ${{ steps.cache-repo.outputs.cache-hit }} && yarn run ${{ matrix.task }}
|
||||
- name: yarn run ${{ matrix.task }}
|
||||
run: ${{ steps.cache-repo.outputs.cache-hit }} && yarn run ${{ matrix.task }}
|
||||
ui-coverage:
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
@@ -76,7 +80,8 @@ jobs:
|
||||
**/node_modules
|
||||
contracts/build
|
||||
key: ${{ needs.initialize.outputs.cache_key }}
|
||||
- run: ${{ steps.cache-repo.outputs.cache-hit }} && yarn workspace ui run coverage
|
||||
- name: yarn workspace ui run coverage
|
||||
run: ${{ steps.cache-repo.outputs.cache-hit }} && yarn workspace ui run coverage
|
||||
- uses: coverallsapp/github-action@master
|
||||
with:
|
||||
github-token: ${{ github.token }}
|
||||
@@ -87,14 +92,16 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
- run: |
|
||||
- name: Evaluate e2e docker images tags
|
||||
run: |
|
||||
git submodule status > submodule.status
|
||||
echo "::set-env name=E2E_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'Dockerfile.e2e', 'commons', 'oracle-e2e', 'monitor-e2e') }}"
|
||||
echo "::set-env name=ORACLE_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'oracle') }}"
|
||||
echo "::set-env name=MONITOR_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'monitor') }}"
|
||||
echo "::set-env name=UI_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'ui') }}"
|
||||
echo "::set-env name=ALM_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'alm') }}"
|
||||
- run: |
|
||||
echo "E2E_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'Dockerfile.e2e', 'commons', 'oracle-e2e', 'monitor-e2e') }}" >> $GITHUB_ENV
|
||||
echo "ORACLE_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'oracle') }}" >> $GITHUB_ENV
|
||||
echo "MONITOR_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'monitor') }}" >> $GITHUB_ENV
|
||||
echo "UI_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'ui') }}" >> $GITHUB_ENV
|
||||
echo "ALM_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'alm') }}" >> $GITHUB_ENV
|
||||
- name: Rebuild and push updated images
|
||||
run: |
|
||||
function check_if_image_exists() {
|
||||
curl -fsSlL -H 'Authorization: bearer ${{ github.token }}' "https://${DOCKER_REGISTRY}/v2/${DOCKER_REPO}/tokenbridge-e2e-$1/manifests/$2" > /dev/null
|
||||
}
|
||||
@@ -119,8 +126,10 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
- run: echo "::set-env name=MOLECULE_RUNNER_TAG::${{ hashFiles('./deployment-e2e/Dockerfile') }}"
|
||||
- run: |
|
||||
- name: Evaluate e2e molecule runner tag
|
||||
run: echo "MOLECULE_RUNNER_TAG=${{ hashFiles('./deployment-e2e/Dockerfile') }}" >> $GITHUB_ENV
|
||||
- name: Rebuild and push molecule runner e2e image
|
||||
run: |
|
||||
function check_if_image_exists() {
|
||||
curl -fsSlL -H 'Authorization: bearer ${{ github.token }}' "https://${DOCKER_REGISTRY}/v2/${DOCKER_REPO}/tokenbridge-e2e-$1/manifests/$2" > /dev/null
|
||||
}
|
||||
@@ -150,14 +159,15 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
- run: |
|
||||
- name: Evaluate e2e docker images tags
|
||||
run: |
|
||||
git submodule status > submodule.status
|
||||
echo "::set-env name=E2E_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'Dockerfile.e2e', 'commons', 'oracle-e2e', 'monitor-e2e') }}"
|
||||
echo "::set-env name=ORACLE_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'oracle') }}"
|
||||
echo "::set-env name=MONITOR_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'monitor') }}"
|
||||
echo "::set-env name=UI_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'ui') }}"
|
||||
echo "::set-env name=ALM_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'alm') }}"
|
||||
- if: ${{ matrix.use-cache }}
|
||||
echo "E2E_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'Dockerfile.e2e', 'commons', 'oracle-e2e', 'monitor-e2e') }}" >> $GITHUB_ENV
|
||||
echo "ORACLE_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'oracle') }}" >> $GITHUB_ENV
|
||||
echo "MONITOR_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'monitor') }}" >> $GITHUB_ENV
|
||||
echo "UI_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'ui') }}" >> $GITHUB_ENV
|
||||
echo "ALM_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'alm') }}" >> $GITHUB_ENV
|
||||
- if: ${{ matrix.use-cache }}
|
||||
uses: actions/cache@v2
|
||||
id: cache-repo
|
||||
with:
|
||||
@@ -165,11 +175,14 @@ jobs:
|
||||
**/node_modules
|
||||
contracts/build
|
||||
key: ${{ needs.initialize.outputs.cache_key }}
|
||||
- run: docker login ${DOCKER_REGISTRY} -u ${{ github.actor }} -p ${{ github.token }}
|
||||
- run: ${{ !matrix.use-cache || steps.cache-repo.outputs.cache-hit }} && yarn run ${{ matrix.task }}
|
||||
- name: Login to docker registry
|
||||
run: docker login ${DOCKER_REGISTRY} -u ${{ github.actor }} -p ${{ github.token }}
|
||||
- name: yarn run ${{ matrix.task }}
|
||||
run: ${{ !matrix.use-cache || steps.cache-repo.outputs.cache-hit }} && yarn run ${{ matrix.task }}
|
||||
deployment:
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- build-e2e-images
|
||||
- build-molecule-runner
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -179,15 +192,17 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
- run: echo "::set-env name=MOLECULE_RUNNER_TAG::${{ hashFiles('./deployment-e2e/Dockerfile') }}"
|
||||
- run: docker login ${DOCKER_REGISTRY} -u ${{ github.actor }} -p ${{ github.token }}
|
||||
- name: Evaluate e2e molecule runner tag
|
||||
run: echo "MOLECULE_RUNNER_TAG=${{ hashFiles('./deployment-e2e/Dockerfile') }}" >> $GITHUB_ENV
|
||||
- name: Login to docker registry
|
||||
run: docker login ${DOCKER_REGISTRY} -u ${{ github.actor }} -p ${{ github.token }}
|
||||
- run: deployment-e2e/molecule.sh ${{ matrix.task }}
|
||||
ultimate:
|
||||
if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/develop' || startsWith(github.ref, 'refs/tags') || contains(github.event.head_commit.message, 'ultimate')
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- initialize
|
||||
- build-e2e-images
|
||||
if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/develop' || startsWith(github.ref, 'refs/tags')
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -195,24 +210,29 @@ jobs:
|
||||
include:
|
||||
- task: erc-to-erc
|
||||
ui-e2e-grep: 'ERC TO ERC'
|
||||
ui-config: 'e2e-commons/components-envs/ui-erc20.env'
|
||||
- task: erc-to-native
|
||||
ui-e2e-grep: 'ERC TO NATIVE'
|
||||
ui-config: 'e2e-commons/components-envs/ui-erc20-native.env'
|
||||
- task: native-to-erc
|
||||
ui-e2e-grep: 'NATIVE TO ERC'
|
||||
ui-config: 'e2e-commons/components-envs/ui.env'
|
||||
- task: amb-stake-erc-to-erc
|
||||
ui-e2e-grep: 'AMB-STAKE-ERC-TO-ERC'
|
||||
ui-config: 'e2e-commons/components-envs/ui-amb-stake-erc20-erc20.env'
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
- run: |
|
||||
- name: Evaluate e2e docker images tags
|
||||
run: |
|
||||
git submodule status > submodule.status
|
||||
echo "::set-env name=E2E_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'Dockerfile.e2e', 'commons', 'oracle-e2e', 'monitor-e2e') }}"
|
||||
echo "::set-env name=ORACLE_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'oracle') }}"
|
||||
echo "::set-env name=MONITOR_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'monitor') }}"
|
||||
echo "::set-env name=UI_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'ui') }}"
|
||||
echo "::set-env name=ALM_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'alm') }}"
|
||||
echo "::set-env name=MOLECULE_RUNNER_TAG::${{ hashFiles('./deployment-e2e/Dockerfile') }}"
|
||||
echo "E2E_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'Dockerfile.e2e', 'commons', 'oracle-e2e', 'monitor-e2e') }}" >> $GITHUB_ENV
|
||||
echo "ORACLE_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'oracle') }}" >> $GITHUB_ENV
|
||||
echo "MONITOR_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'monitor') }}" >> $GITHUB_ENV
|
||||
echo "UI_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'ui') }}" >> $GITHUB_ENV
|
||||
echo "ALM_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'alm') }}" >> $GITHUB_ENV
|
||||
echo "MOLECULE_RUNNER_TAG=${{ hashFiles('./deployment-e2e/Dockerfile') }}" >> $GITHUB_ENV
|
||||
- uses: actions/cache@v2
|
||||
id: cache-repo
|
||||
with:
|
||||
@@ -220,12 +240,32 @@ jobs:
|
||||
**/node_modules
|
||||
contracts/build
|
||||
key: ${{ needs.initialize.outputs.cache_key }}
|
||||
- run: docker login ${DOCKER_REGISTRY} -u ${{ github.actor }} -p ${{ github.token }}
|
||||
- run: ${{ steps.cache-repo.outputs.cache-hit }} && e2e-commons/up.sh deploy blocks
|
||||
- run: docker-compose -f ./e2e-commons/docker-compose.yml pull oracle
|
||||
- run: deployment-e2e/molecule.sh ultimate-${{ matrix.task }}
|
||||
- run: sudo chown -R $USER:docker /var/run/docker.sock
|
||||
- name: Login to docker registry
|
||||
run: docker login ${DOCKER_REGISTRY} -u ${{ github.actor }} -p ${{ github.token }}
|
||||
- name: Deploy contracts
|
||||
run: ${{ steps.cache-repo.outputs.cache-hit }} && e2e-commons/up.sh deploy blocks
|
||||
- name: Pull e2e oracle image
|
||||
run: |
|
||||
docker-compose -f ./e2e-commons/docker-compose.yml pull oracle
|
||||
docker tag ${DOCKER_IMAGE_BASE}/tokenbridge-e2e-oracle:${ORACLE_TAG} poanetwork/tokenbridge-oracle:latest
|
||||
- if: ${{ matrix.ui-e2e-grep }}
|
||||
name: Pull e2e ui image
|
||||
run: |
|
||||
docker-compose -f ./e2e-commons/docker-compose.yml pull ui
|
||||
docker build \
|
||||
--build-arg DOCKER_IMAGE_BASE=${DOCKER_IMAGE_BASE} \
|
||||
--build-arg UI_TAG=${UI_TAG} \
|
||||
--build-arg DOT_ENV_PATH=${{ matrix.ui-config }} \
|
||||
-f ./e2e-commons/Dockerfile.ui \
|
||||
-t ui_ui:latest \
|
||||
.
|
||||
- name: Deploy oracle and ui
|
||||
run: deployment-e2e/molecule.sh ultimate-${{ matrix.task }}
|
||||
- name: Reset docker socket permissions
|
||||
run: sudo chown -R $USER:docker /var/run/docker.sock
|
||||
- name: Run ui e2e tests
|
||||
if: ${{ matrix.ui-e2e-grep }}
|
||||
run: cd ui-e2e && xvfb-run yarn mocha -g "${{ matrix.ui-e2e-grep }}" -b ./test.js
|
||||
- if: ${{ !matrix.ui-e2e-grep }}
|
||||
- name: Run oracle e2e tests
|
||||
if: ${{ !matrix.ui-e2e-grep }}
|
||||
run: docker-compose -f ./e2e-commons/docker-compose.yml run e2e yarn workspace oracle-e2e run ${{ matrix.task }}
|
||||
|
||||
13
.gitignore
vendored
13
.gitignore
vendored
@@ -10,11 +10,8 @@ dist
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
*.env*
|
||||
!.env.example
|
||||
.idea
|
||||
.nyc_output
|
||||
logs/
|
||||
@@ -49,5 +46,9 @@ __pycache__
|
||||
|
||||
#monitor
|
||||
monitor/responses/*
|
||||
monitor/configs/*.env
|
||||
monitor/cache/*
|
||||
!monitor/cache/.gitkeep
|
||||
!monitor/.gitkeep
|
||||
|
||||
# Local Netlify folder
|
||||
.netlify
|
||||
@@ -41,6 +41,7 @@ ORACLE_HOME_TO_FOREIGN_ALLOWANCE_LIST | Filename with a list of addresses, separ
|
||||
ORACLE_HOME_TO_FOREIGN_BLOCK_LIST | Filename with a list of addresses, separated by newlines. If set, determines the blocked set of accounts whose requests will not be automatically processed by the CollectedSignatures watcher. Has a lower priority than the `ORACLE_HOME_TO_FOREIGN_ALLOWANCE_LIST` | string
|
||||
ORACLE_HOME_TO_FOREIGN_CHECK_SENDER | If set to `true`, instructs the oracle to do an extra check for transaction origin in the block/allowance list. `false` by default. | `true` / `false`
|
||||
ORACLE_ALWAYS_RELAY_SIGNATURES | If set to `true`, the oracle will always relay signatures even if it was not the last who finilized the signatures collecting process. The default is `false`. | `true` / `false`
|
||||
ORACLE_RPC_REQUEST_TIMEOUT | Timeout in milliseconds for a single RPC request. Default value is `ORACLE_*_RPC_POLLING_INTERVAL * 2`. | integer
|
||||
|
||||
|
||||
## UI configuration
|
||||
@@ -78,3 +79,8 @@ MONITOR_TX_NUMBER_THRESHOLD | If estimated number of transaction is equal to or
|
||||
MONITOR_PORT | The port for the Monitor. | integer
|
||||
MONITOR_BRIDGE_NAME | The name to be used in the url path for the bridge | string
|
||||
MONITOR_CACHE_EVENTS | If set to true, monitor will cache obtained events for other workers runs | `true` / `false`
|
||||
MONITOR_HOME_TO_FOREIGN_ALLOWANCE_LIST | File with a list of addresses, separated by newlines. If set, determines the privileged set of accounts whose requests should be automatically processed by the CollectedSignatures watcher. | string
|
||||
MONITOR_HOME_TO_FOREIGN_BLOCK_LIST | File with a list of addresses, separated by newlines. If set, determines the set of accounts whose requests should be marked as unclaimed. Has a lower priority than the `MONITOR_HOME_TO_FOREIGN_ALLOWANCE_LIST`. | string
|
||||
MONITOR_HOME_TO_FOREIGN_CHECK_SENDER | If set to `true`, instructs the oracle to do an extra check for transaction origin in the block/allowance list. `false` by default. | `true` / `false`
|
||||
MONITOR_HOME_VALIDATORS_BALANCE_ENABLE | If set, defines the list of home validator addresses for which balance should be checked. | `string`
|
||||
MONITOR_FOREIGN_VALIDATORS_BALANCE_ENABLE | If set, defines the list of foreign validator addresses for which balance should be checked. | `string`
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@ethersproject/bignumber": ">=5.0.0-beta.130",
|
||||
"@react-hook/window-size": "^3.0.6",
|
||||
"@testing-library/jest-dom": "^4.2.4",
|
||||
"@testing-library/react": "^9.3.2",
|
||||
@@ -15,6 +16,8 @@
|
||||
"@types/react-router-dom": "^5.1.5",
|
||||
"@types/styled-components": "^5.1.0",
|
||||
"@use-it/interval": "^0.1.3",
|
||||
"@web3-react/core": "^6.1.1",
|
||||
"@web3-react/injected-connector": "^6.0.7",
|
||||
"customize-cra": "^1.0.0",
|
||||
"date-fns": "^2.14.0",
|
||||
"dotenv": "^8.2.0",
|
||||
@@ -27,8 +30,9 @@
|
||||
"react-scripts": "3.0.1",
|
||||
"styled-components": "^5.1.1",
|
||||
"typescript": "^3.5.2",
|
||||
"web3": "1.2.7",
|
||||
"web3-eth-contract": "1.2.7"
|
||||
"web3": "1.2.11",
|
||||
"web3-eth-contract": "1.2.11",
|
||||
"web3-utils": "1.2.11"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "yarn createSnapshots && ./load-env.sh react-app-rewired start",
|
||||
|
||||
1
alm/public/_redirects
Normal file
1
alm/public/_redirects
Normal file
@@ -0,0 +1 @@
|
||||
/* /index.html 200
|
||||
@@ -1,14 +1,18 @@
|
||||
import React from 'react'
|
||||
import { BrowserRouter } from 'react-router-dom'
|
||||
import { Web3ReactProvider } from '@web3-react/core'
|
||||
import Web3 from 'web3'
|
||||
import { MainPage } from './components/MainPage'
|
||||
import { StateProvider } from './state/StateProvider'
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<BrowserRouter>
|
||||
<StateProvider>
|
||||
<MainPage />
|
||||
</StateProvider>
|
||||
<Web3ReactProvider getLibrary={provider => new Web3(provider)}>
|
||||
<StateProvider>
|
||||
<MainPage />
|
||||
</StateProvider>
|
||||
</Web3ReactProvider>
|
||||
</BrowserRouter>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -49,7 +49,16 @@ export const ConfirmationsContainer = ({ message, receipt, fromHome, timestamp }
|
||||
} = useStateProvider()
|
||||
const { requiredSignatures, validatorList } = useValidatorContract({ fromHome, receipt })
|
||||
const { blockConfirmations } = useBlockConfirmations({ fromHome, receipt })
|
||||
const { confirmations, status, executionData, signatureCollected, waitingBlocksResolved } = useMessageConfirmations({
|
||||
const {
|
||||
confirmations,
|
||||
status,
|
||||
executionData,
|
||||
signatureCollected,
|
||||
waitingBlocksResolved,
|
||||
setExecutionData,
|
||||
executionEventsFetched,
|
||||
setPendingExecution
|
||||
} = useMessageConfirmations({
|
||||
message,
|
||||
receipt,
|
||||
fromHome,
|
||||
@@ -102,7 +111,17 @@ export const ConfirmationsContainer = ({ message, receipt, fromHome, timestamp }
|
||||
validatorList={validatorList}
|
||||
waitingBlocksResolved={waitingBlocksResolved}
|
||||
/>
|
||||
{signatureCollected && <ExecutionConfirmation executionData={executionData} isHome={!fromHome} />}
|
||||
{signatureCollected && (
|
||||
<ExecutionConfirmation
|
||||
messageData={message.data}
|
||||
executionData={executionData}
|
||||
isHome={!fromHome}
|
||||
signatureCollected={signatureCollected}
|
||||
setExecutionData={setExecutionData}
|
||||
executionEventsFetched={executionEventsFetched}
|
||||
setPendingExecution={setPendingExecution}
|
||||
/>
|
||||
)}
|
||||
</StyledConfirmationContainer>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -1,24 +1,45 @@
|
||||
import React from 'react'
|
||||
import { formatTimestamp, formatTxHash, getExplorerTxUrl } from '../utils/networks'
|
||||
import { useWindowWidth } from '@react-hook/window-size'
|
||||
import { SEARCHING_TX, VALIDATOR_CONFIRMATION_STATUS } from '../config/constants'
|
||||
import { SEARCHING_TX, VALIDATOR_CONFIRMATION_STATUS, ALM_HOME_TO_FOREIGN_MANUAL_EXECUTION } from '../config/constants'
|
||||
import { SimpleLoading } from './commons/Loading'
|
||||
import styled from 'styled-components'
|
||||
import { ExecutionData } from '../hooks/useMessageConfirmations'
|
||||
import { GreyLabel, RedLabel, SuccessLabel } from './commons/Labels'
|
||||
import { ExplorerTxLink } from './commons/ExplorerTxLink'
|
||||
import { Thead, AgeTd, StatusTd } from './commons/Table'
|
||||
import { ManualExecutionButton } from './ManualExecutionButton'
|
||||
|
||||
const StyledExecutionConfirmation = styled.div`
|
||||
margin-top: 30px;
|
||||
`
|
||||
|
||||
export interface ExecutionConfirmationParams {
|
||||
messageData: string
|
||||
executionData: ExecutionData
|
||||
setExecutionData: Function
|
||||
signatureCollected: boolean | string[]
|
||||
isHome: boolean
|
||||
executionEventsFetched: boolean
|
||||
setPendingExecution: Function
|
||||
}
|
||||
|
||||
export const ExecutionConfirmation = ({ executionData, isHome }: ExecutionConfirmationParams) => {
|
||||
export const ExecutionConfirmation = ({
|
||||
messageData,
|
||||
executionData,
|
||||
setExecutionData,
|
||||
signatureCollected,
|
||||
isHome,
|
||||
executionEventsFetched,
|
||||
setPendingExecution
|
||||
}: ExecutionConfirmationParams) => {
|
||||
const availableManualExecution =
|
||||
!isHome &&
|
||||
(executionData.status === VALIDATOR_CONFIRMATION_STATUS.WAITING ||
|
||||
(executionData.status === VALIDATOR_CONFIRMATION_STATUS.UNDEFINED &&
|
||||
executionEventsFetched &&
|
||||
!!executionData.validator))
|
||||
const requiredManualExecution = availableManualExecution && ALM_HOME_TO_FOREIGN_MANUAL_EXECUTION
|
||||
const windowWidth = useWindowWidth()
|
||||
|
||||
const txExplorerLink = getExplorerTxUrl(executionData.txHash, isHome)
|
||||
@@ -48,26 +69,47 @@ export const ExecutionConfirmation = ({ executionData, isHome }: ExecutionConfir
|
||||
<table>
|
||||
<Thead>
|
||||
<tr>
|
||||
<th>Executed by</th>
|
||||
<th>{requiredManualExecution ? 'Execution info' : 'Executed by'}</th>
|
||||
<th className="text-center">Status</th>
|
||||
<th className="text-center">Age</th>
|
||||
{!requiredManualExecution && <th className="text-center">Age</th>}
|
||||
{availableManualExecution && <th className="text-center">Actions</th>}
|
||||
</tr>
|
||||
</Thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{formattedValidator ? formattedValidator : <SimpleLoading />}</td>
|
||||
<StatusTd className="text-center">{getExecutionStatusElement(executionData.status)}</StatusTd>
|
||||
<AgeTd className="text-center">
|
||||
{executionData.timestamp > 0 ? (
|
||||
<ExplorerTxLink href={txExplorerLink} target="_blank">
|
||||
{formatTimestamp(executionData.timestamp)}
|
||||
</ExplorerTxLink>
|
||||
) : executionData.status === VALIDATOR_CONFIRMATION_STATUS.WAITING ? (
|
||||
''
|
||||
<td>
|
||||
{requiredManualExecution ? (
|
||||
'Manual user action is required to complete the operation'
|
||||
) : formattedValidator ? (
|
||||
formattedValidator
|
||||
) : (
|
||||
SEARCHING_TX
|
||||
<SimpleLoading />
|
||||
)}
|
||||
</AgeTd>
|
||||
</td>
|
||||
<StatusTd className="text-center">{getExecutionStatusElement(executionData.status)}</StatusTd>
|
||||
{!requiredManualExecution && (
|
||||
<AgeTd className="text-center">
|
||||
{executionData.timestamp > 0 ? (
|
||||
<ExplorerTxLink href={txExplorerLink} target="_blank">
|
||||
{formatTimestamp(executionData.timestamp)}
|
||||
</ExplorerTxLink>
|
||||
) : executionData.status === VALIDATOR_CONFIRMATION_STATUS.WAITING ? (
|
||||
''
|
||||
) : (
|
||||
SEARCHING_TX
|
||||
)}
|
||||
</AgeTd>
|
||||
)}
|
||||
{availableManualExecution && (
|
||||
<td>
|
||||
<ManualExecutionButton
|
||||
messageData={messageData}
|
||||
setExecutionData={setExecutionData}
|
||||
signatureCollected={signatureCollected as string[]}
|
||||
setPendingExecution={setPendingExecution}
|
||||
/>
|
||||
</td>
|
||||
)}
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -8,6 +8,7 @@ import { TransactionReceipt } from 'web3-eth'
|
||||
import { InfoAlert } from './commons/InfoAlert'
|
||||
import { ExplorerTxLink } from './commons/ExplorerTxLink'
|
||||
import { FOREIGN_NETWORK_NAME, HOME_NETWORK_NAME } from '../config/constants'
|
||||
import { ErrorAlert } from './commons/ErrorAlert'
|
||||
|
||||
const StyledMainPage = styled.div`
|
||||
text-align: center;
|
||||
@@ -51,7 +52,7 @@ export interface FormSubmitParams {
|
||||
|
||||
export const MainPage = () => {
|
||||
const history = useHistory()
|
||||
const { home, foreign } = useStateProvider()
|
||||
const { home, foreign, error, setError } = useStateProvider()
|
||||
const [networkName, setNetworkName] = useState('')
|
||||
const [receipt, setReceipt] = useState<Maybe<TransactionReceipt>>(null)
|
||||
const [showInfoAlert, setShowInfoAlert] = useState(false)
|
||||
@@ -131,6 +132,7 @@ export const MainPage = () => {
|
||||
</AlertP>
|
||||
</InfoAlert>
|
||||
)}
|
||||
{error && <ErrorAlert onClick={() => setError('')} error={error} />}
|
||||
<Route exact path={['/']} children={<Form onSubmit={onFormSubmit} />} />
|
||||
<Route
|
||||
path={['/:chainId/:txHash/:messageIdParam', '/:chainId/:txHash']}
|
||||
|
||||
109
alm/src/components/ManualExecutionButton.tsx
Normal file
109
alm/src/components/ManualExecutionButton.tsx
Normal file
@@ -0,0 +1,109 @@
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import styled from 'styled-components'
|
||||
import { InjectedConnector } from '@web3-react/injected-connector'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import { INCORRECT_CHAIN_ERROR, VALIDATOR_CONFIRMATION_STATUS } from '../config/constants'
|
||||
import { useStateProvider } from '../state/StateProvider'
|
||||
import { signatureToVRS, packSignatures } from '../utils/signatures'
|
||||
|
||||
const StyledButton = styled.button`
|
||||
color: var(--button-color);
|
||||
border-color: var(--font-color);
|
||||
margin-top: 10px;
|
||||
&:focus {
|
||||
outline: var(--button-color);
|
||||
}
|
||||
`
|
||||
|
||||
interface ManualExecutionButtonParams {
|
||||
messageData: string
|
||||
setExecutionData: Function
|
||||
signatureCollected: string[]
|
||||
setPendingExecution: Function
|
||||
}
|
||||
|
||||
export const ManualExecutionButton = ({
|
||||
messageData,
|
||||
setExecutionData,
|
||||
signatureCollected,
|
||||
setPendingExecution
|
||||
}: ManualExecutionButtonParams) => {
|
||||
const { foreign, setError } = useStateProvider()
|
||||
const { library, activate, account, active } = useWeb3React()
|
||||
const [manualExecution, setManualExecution] = useState(false)
|
||||
|
||||
useEffect(
|
||||
() => {
|
||||
if (!manualExecution || !foreign.chainId) return
|
||||
|
||||
if (!active) {
|
||||
activate(new InjectedConnector({ supportedChainIds: [foreign.chainId] }), e => {
|
||||
if (e.message.includes('Unsupported chain id')) {
|
||||
setError(INCORRECT_CHAIN_ERROR)
|
||||
const { ethereum } = window as any
|
||||
|
||||
// remove the error message after chain is correctly changed to the foreign one
|
||||
const listener = (chainId: string) => {
|
||||
if (parseInt(chainId.slice(2), 16) === foreign.chainId) {
|
||||
ethereum.removeListener('chainChanged', listener)
|
||||
setError((error: string) => (error === INCORRECT_CHAIN_ERROR ? '' : error))
|
||||
}
|
||||
}
|
||||
ethereum.on('chainChanged', listener)
|
||||
} else {
|
||||
setError(e.message)
|
||||
}
|
||||
setManualExecution(false)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (!library || !foreign.bridgeContract || !signatureCollected || !signatureCollected.length) return
|
||||
|
||||
const signatures = packSignatures(signatureCollected.map(signatureToVRS))
|
||||
const data = foreign.bridgeContract.methods.executeSignatures(messageData, signatures).encodeABI()
|
||||
setManualExecution(false)
|
||||
|
||||
library.eth
|
||||
.sendTransaction({
|
||||
from: account,
|
||||
to: foreign.bridgeAddress,
|
||||
data
|
||||
})
|
||||
.on('transactionHash', (txHash: string) => {
|
||||
setExecutionData({
|
||||
status: VALIDATOR_CONFIRMATION_STATUS.PENDING,
|
||||
validator: account,
|
||||
txHash,
|
||||
timestamp: Math.floor(new Date().getTime() / 1000.0),
|
||||
executionResult: false
|
||||
})
|
||||
setPendingExecution(true)
|
||||
})
|
||||
.on('error', (e: Error) => setError(e.message))
|
||||
},
|
||||
[
|
||||
manualExecution,
|
||||
library,
|
||||
activate,
|
||||
active,
|
||||
account,
|
||||
foreign.chainId,
|
||||
foreign.bridgeAddress,
|
||||
foreign.bridgeContract,
|
||||
setError,
|
||||
messageData,
|
||||
signatureCollected,
|
||||
setExecutionData,
|
||||
setPendingExecution
|
||||
]
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="is-center">
|
||||
<StyledButton className="button outline" onClick={() => setManualExecution(true)}>
|
||||
Execute
|
||||
</StyledButton>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react'
|
||||
|
||||
export const CloseIcon = () => (
|
||||
export const CloseIcon = ({ color }: { color?: string }) => (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
@@ -10,12 +10,9 @@ export const CloseIcon = () => (
|
||||
role="img"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 352 512"
|
||||
fill="#1890ff"
|
||||
fill={color || '#1890ff'}
|
||||
height="1em"
|
||||
>
|
||||
<path
|
||||
fill="#1890ff"
|
||||
d="M242.72 256l100.07-100.07c12.28-12.28 12.28-32.19 0-44.48l-22.24-22.24c-12.28-12.28-32.19-12.28-44.48 0L176 189.28 75.93 89.21c-12.28-12.28-32.19-12.28-44.48 0L9.21 111.45c-12.28 12.28-12.28 32.19 0 44.48L109.28 256 9.21 356.07c-12.28 12.28-12.28 32.19 0 44.48l22.24 22.24c12.28 12.28 32.2 12.28 44.48 0L176 322.72l100.07 100.07c12.28 12.28 32.2 12.28 44.48 0l22.24-22.24c12.28-12.28 12.28-32.19 0-44.48L242.72 256z"
|
||||
/>
|
||||
<path d="M242.72 256l100.07-100.07c12.28-12.28 12.28-32.19 0-44.48l-22.24-22.24c-12.28-12.28-32.19-12.28-44.48 0L176 189.28 75.93 89.21c-12.28-12.28-32.19-12.28-44.48 0L9.21 111.45c-12.28 12.28-12.28 32.19 0 44.48L109.28 256 9.21 356.07c-12.28 12.28-12.28 32.19 0 44.48l22.24 22.24c12.28 12.28 32.2 12.28 44.48 0L176 322.72l100.07 100.07c12.28 12.28 32.2 12.28 44.48 0l22.24-22.24c12.28-12.28 12.28-32.19 0-44.48L242.72 256z" />
|
||||
</svg>
|
||||
)
|
||||
|
||||
31
alm/src/components/commons/ErrorAlert.tsx
Normal file
31
alm/src/components/commons/ErrorAlert.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
import React from 'react'
|
||||
import styled from 'styled-components'
|
||||
import { InfoIcon } from './InfoIcon'
|
||||
import { CloseIcon } from './CloseIcon'
|
||||
|
||||
const StyledErrorAlert = styled.div`
|
||||
border: 1px solid var(--failed-color);
|
||||
border-radius: 4px;
|
||||
margin-bottom: 20px;
|
||||
padding-top: 10px;
|
||||
`
|
||||
|
||||
const CloseIconContainer = styled.div`
|
||||
cursor: pointer;
|
||||
`
|
||||
|
||||
const TextContainer = styled.div`
|
||||
flex-direction: column;
|
||||
`
|
||||
|
||||
export const ErrorAlert = ({ onClick, error }: { onClick: () => void; error: string }) => (
|
||||
<div className="row is-center">
|
||||
<StyledErrorAlert className="col-10 is-vertical-align row">
|
||||
<InfoIcon color="var(--failed-color)" />
|
||||
<TextContainer className="col-10">{error}</TextContainer>
|
||||
<CloseIconContainer className="col-1 is-vertical-align is-center" onClick={onClick}>
|
||||
<CloseIcon color="var(--failed-color)" />
|
||||
</CloseIconContainer>
|
||||
</StyledErrorAlert>
|
||||
</div>
|
||||
)
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react'
|
||||
|
||||
export const InfoIcon = () => (
|
||||
export const InfoIcon = ({ color }: { color?: string }) => (
|
||||
<svg
|
||||
className="col-1 is-left"
|
||||
viewBox="64 64 896 896"
|
||||
@@ -8,7 +8,7 @@ export const InfoIcon = () => (
|
||||
data-icon="info-circle"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="#1890ff"
|
||||
fill={color || '#1890ff'}
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm32 664c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8V456c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v272zm-32-344a48.01 48.01 0 010-96 48.01 48.01 0 010 96z" />
|
||||
|
||||
@@ -13,6 +13,9 @@ export const FOREIGN_EXPLORER_TX_TEMPLATE: string = process.env.REACT_APP_ALM_FO
|
||||
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 ALM_HOME_TO_FOREIGN_MANUAL_EXECUTION: boolean =
|
||||
(process.env.REACT_APP_ALM_HOME_TO_FOREIGN_MANUAL_EXECUTION || '').toLowerCase() === 'true'
|
||||
|
||||
export const HOME_RPC_POLLING_INTERVAL: number = 5000
|
||||
export const FOREIGN_RPC_POLLING_INTERVAL: number = 5000
|
||||
export const BLOCK_RANGE: number = 50
|
||||
@@ -61,3 +64,5 @@ export const VALIDATOR_CONFIRMATION_STATUS = {
|
||||
}
|
||||
|
||||
export const SEARCHING_TX = 'Searching Transaction...'
|
||||
|
||||
export const INCORRECT_CHAIN_ERROR = `Incorrect chain chosen. Switch to ${FOREIGN_NETWORK_NAME} in the wallet.`
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
// %t will be replaced by the time -> x minutes/hours/days ago
|
||||
import { ALM_HOME_TO_FOREIGN_MANUAL_EXECUTION } from './constants'
|
||||
|
||||
export const TRANSACTION_STATUS_DESCRIPTION: { [key: string]: string } = {
|
||||
SUCCESS_MULTIPLE_MESSAGES: 'was initiated %t and contains several bridge messages. Specify one of them:',
|
||||
SUCCESS_ONE_MESSAGE: 'was initiated %t',
|
||||
@@ -24,7 +26,7 @@ export const CONFIRMATIONS_STATUS_LABEL_HOME: { [key: string]: string } = {
|
||||
SUCCESS_MESSAGE_FAILED: 'Success',
|
||||
EXECUTION_FAILED: 'Execution failed',
|
||||
EXECUTION_PENDING: 'Execution pending',
|
||||
EXECUTION_WAITING: 'Execution waiting',
|
||||
EXECUTION_WAITING: ALM_HOME_TO_FOREIGN_MANUAL_EXECUTION ? 'Manual execution waiting' : 'Execution waiting',
|
||||
FAILED: 'Confirmation Failed',
|
||||
PENDING: 'Confirmation Pending',
|
||||
WAITING_VALIDATORS: 'Confirmation Waiting',
|
||||
@@ -55,11 +57,12 @@ export const CONFIRMATIONS_STATUS_DESCRIPTION_HOME: { [key: string]: string } =
|
||||
SUCCESS_MESSAGE_FAILED:
|
||||
'The specified transaction was included in a block,\nthe validators collected signatures and the cross-chain relay was executed correctly,\nbut the contained message execution failed.\nContact the support of the application you used to produce the transaction for the clarifications.',
|
||||
EXECUTION_FAILED:
|
||||
'The specified transaction was included in a block\nand the validators collected signatures. The\nvalidator’s transaction with collected signatures was\nsent but did not succeed. Contact to the validators by messaging\non %linkhttps://forum.poa.network/c/support',
|
||||
'The specified transaction was included in a block\nand the validators collected signatures. The\n transaction with collected signatures was\nsent but did not succeed. Contact to the validators by messaging\non %linkhttps://forum.poa.network/c/support',
|
||||
EXECUTION_PENDING:
|
||||
'The specified transaction was included in a block\nand the validators collected signatures. The\nvalidator’s transaction with collected signatures was\nsent but is not yet added to a block.',
|
||||
EXECUTION_WAITING:
|
||||
'The specified transaction was included in a block\nand the validators collected signatures. Either\n1. One of the validators is waiting for chain finalization.\n2. A validator skipped its duty to relay signatures.\n3. The execution transaction is still pending (e.g. due to the gas price spike).\nCheck status again after a few blocks. If the issue still persists contact to the validators by messaging on %linkhttps://forum.poa.network/c/support',
|
||||
'The specified transaction was included in a block\nand the validators collected signatures. The\n transaction with collected signatures was\nsent but is not yet added to a block.',
|
||||
EXECUTION_WAITING: ALM_HOME_TO_FOREIGN_MANUAL_EXECUTION
|
||||
? 'The specified transaction was included in a block\nand the validators collected signatures.\nNow the manual user action is required to complete message execution.\n Please, press the "Execute" button.'
|
||||
: 'The specified transaction was included in a block\nand the validators collected signatures. Either\n1. One of the validators is waiting for chain finalization.\n2. A validator skipped its duty to relay signatures.\n3. The execution transaction is still pending (e.g. due to the gas price spike).\nCheck status again after a few blocks or force execution by pressing the "Execute" button.\nIf the issue still persists contact to the validators by messaging on %linkhttps://forum.poa.network/c/support',
|
||||
FAILED:
|
||||
'The specified transaction was included in a block,\nbut transactions with signatures sent by a majority of\nvalidators failed. The cross-chain relay request will\nnot be processed. Contact to the validators by\nmessaging on %linkhttps://forum.poa.network/c/support',
|
||||
PENDING:
|
||||
|
||||
@@ -3,7 +3,6 @@ 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,
|
||||
@@ -63,11 +62,12 @@ export const useMessageConfirmations = ({
|
||||
blockConfirmations
|
||||
}: useMessageConfirmationsParams) => {
|
||||
const { home, foreign } = useStateProvider()
|
||||
const [confirmations, setConfirmations] = useState<Array<ConfirmationParam>>([])
|
||||
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 [executionEventsFetched, setExecutionEventsFetched] = useState(false)
|
||||
const [collectedSignaturesEvent, setCollectedSignaturesEvent] = useState<Maybe<EventData>>(null)
|
||||
const [executionData, setExecutionData] = useState<ExecutionData>({
|
||||
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
||||
@@ -93,7 +93,7 @@ export const useMessageConfirmations = ({
|
||||
// Check if the validators are waiting for block confirmations to verify the message
|
||||
useEffect(
|
||||
() => {
|
||||
if (!receipt || !blockConfirmations) return
|
||||
if (!receipt || !blockConfirmations || waitingBlocksResolved) return
|
||||
|
||||
const subscriptions: Array<number> = []
|
||||
|
||||
@@ -126,7 +126,16 @@ export const useMessageConfirmations = ({
|
||||
blockProvider.stop()
|
||||
}
|
||||
},
|
||||
[blockConfirmations, foreign.web3, fromHome, validatorList, home.web3, receipt]
|
||||
[
|
||||
blockConfirmations,
|
||||
foreign.web3,
|
||||
fromHome,
|
||||
validatorList,
|
||||
home.web3,
|
||||
receipt,
|
||||
setConfirmations,
|
||||
waitingBlocksResolved
|
||||
]
|
||||
)
|
||||
|
||||
// The collected signature event is only fetched once the signatures are collected on tx from home to foreign, to calculate if
|
||||
@@ -173,6 +182,7 @@ export const useMessageConfirmations = ({
|
||||
useEffect(
|
||||
() => {
|
||||
if (!fromHome || !home.web3 || !receipt || !collectedSignaturesEvent || !blockConfirmations) return
|
||||
if (waitingBlocksForExecutionResolved) return
|
||||
|
||||
const subscriptions: Array<number> = []
|
||||
|
||||
@@ -201,7 +211,7 @@ export const useMessageConfirmations = ({
|
||||
homeBlockNumberProvider.stop()
|
||||
}
|
||||
},
|
||||
[collectedSignaturesEvent, fromHome, blockConfirmations, home.web3, receipt]
|
||||
[collectedSignaturesEvent, fromHome, blockConfirmations, home.web3, receipt, waitingBlocksForExecutionResolved]
|
||||
)
|
||||
|
||||
// Checks if validators verified the message
|
||||
@@ -218,14 +228,12 @@ export const useMessageConfirmations = ({
|
||||
})
|
||||
}
|
||||
|
||||
const confirmationContractMethod = fromHome ? getMessagesSigned : getAffirmationsSigned
|
||||
|
||||
getConfirmationsForTx(
|
||||
message.data,
|
||||
home.web3,
|
||||
validatorList,
|
||||
home.bridgeContract,
|
||||
confirmationContractMethod,
|
||||
fromHome,
|
||||
setConfirmations,
|
||||
requiredSignatures,
|
||||
setSignatureCollected,
|
||||
@@ -251,7 +259,8 @@ export const useMessageConfirmations = ({
|
||||
home.bridgeContract,
|
||||
requiredSignatures,
|
||||
waitingBlocksResolved,
|
||||
timestamp
|
||||
timestamp,
|
||||
setConfirmations
|
||||
]
|
||||
)
|
||||
|
||||
@@ -289,7 +298,8 @@ export const useMessageConfirmations = ({
|
||||
getExecutionFailedTransactionForMessage,
|
||||
setFailedExecution,
|
||||
getExecutionPendingTransactionsForMessage,
|
||||
setPendingExecution
|
||||
setPendingExecution,
|
||||
setExecutionEventsFetched
|
||||
)
|
||||
|
||||
return () => {
|
||||
@@ -369,6 +379,9 @@ export const useMessageConfirmations = ({
|
||||
status,
|
||||
signatureCollected,
|
||||
executionData,
|
||||
waitingBlocksResolved
|
||||
setExecutionData,
|
||||
waitingBlocksResolved,
|
||||
executionEventsFetched,
|
||||
setPendingExecution
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { createContext, ReactNode } from 'react'
|
||||
import React, { createContext, ReactNode, useState } from 'react'
|
||||
import { useNetwork } from '../hooks/useNetwork'
|
||||
import {
|
||||
HOME_RPC_URL,
|
||||
@@ -25,6 +25,8 @@ export interface StateContext {
|
||||
home: BaseNetworkParams
|
||||
foreign: BaseNetworkParams
|
||||
loading: boolean
|
||||
error: string
|
||||
setError: Function
|
||||
}
|
||||
|
||||
const initialState = {
|
||||
@@ -42,7 +44,9 @@ const initialState = {
|
||||
bridgeAddress: FOREIGN_BRIDGE_ADDRESS,
|
||||
bridgeContract: null
|
||||
},
|
||||
loading: true
|
||||
loading: true,
|
||||
error: '',
|
||||
setError: () => {}
|
||||
}
|
||||
|
||||
const StateContext = createContext<StateContext>(initialState)
|
||||
@@ -54,6 +58,7 @@ export const StateProvider = ({ children }: { children: ReactNode }) => {
|
||||
homeWeb3: homeNetwork.web3,
|
||||
foreignWeb3: foreignNetwork.web3
|
||||
})
|
||||
const [error, setError] = useState('')
|
||||
|
||||
const value = {
|
||||
home: {
|
||||
@@ -68,7 +73,9 @@ export const StateProvider = ({ children }: { children: ReactNode }) => {
|
||||
bridgeContract: foreignBridge,
|
||||
...foreignNetwork
|
||||
},
|
||||
loading: homeNetwork.loading || foreignNetwork.loading
|
||||
loading: homeNetwork.loading || foreignNetwork.loading,
|
||||
error,
|
||||
setError
|
||||
}
|
||||
|
||||
return <StateContext.Provider value={value}>{children}</StateContext.Provider>
|
||||
|
||||
@@ -9,7 +9,7 @@ import { BasicConfirmationParam } from '../../hooks/useMessageConfirmations'
|
||||
|
||||
jest.mock('../validatorConfirmationHelpers')
|
||||
|
||||
const getValidatorSuccessTransaction = helpers.getValidatorSuccessTransaction as jest.Mock<any>
|
||||
const getSuccessExecutionTransaction = helpers.getSuccessExecutionTransaction as jest.Mock<any>
|
||||
const getValidatorConfirmation = helpers.getValidatorConfirmation as jest.Mock<any>
|
||||
const getValidatorFailedTransaction = helpers.getValidatorFailedTransaction as jest.Mock<any>
|
||||
const getValidatorPendingTransaction = helpers.getValidatorPendingTransaction as jest.Mock<any>
|
||||
@@ -24,8 +24,15 @@ const validator1 = '0x45b96809336A8b714BFbdAB3E4B5e0fe5d839908'
|
||||
const validator2 = '0xAe8bFfc8BBc6AAa9E21ED1E4e4957fe798BEA25f'
|
||||
const validator3 = '0x285A6eB779be4db94dA65e2F3518B1c5F0f71244'
|
||||
const validatorList = [validator1, validator2, validator3]
|
||||
const bridgeContract = {} as Contract
|
||||
const confirmationContractMethod = () => {}
|
||||
const signature =
|
||||
'0x519d704bceed17423daa79c20531cc34fc27a4be6e53fc5069a8023019188ca4519d704bceed17423daa79c20531cc34fc27a4be6e53fc5069a8023019188ca4'
|
||||
const bridgeContract = {
|
||||
methods: {
|
||||
signature: () => ({
|
||||
call: () => signature
|
||||
})
|
||||
}
|
||||
} as Contract
|
||||
const requiredSignatures = 2
|
||||
const waitingBlocksResolved = true
|
||||
let subscriptions: Array<number> = []
|
||||
@@ -42,7 +49,7 @@ const unsubscribe = () => {
|
||||
|
||||
beforeEach(() => {
|
||||
// Clear all instances and calls to constructor and all methods:
|
||||
getValidatorSuccessTransaction.mockClear()
|
||||
getSuccessExecutionTransaction.mockClear()
|
||||
getValidatorConfirmation.mockClear()
|
||||
getValidatorFailedTransaction.mockClear()
|
||||
getValidatorPendingTransaction.mockClear()
|
||||
@@ -54,7 +61,7 @@ describe('getConfirmationsForTx', () => {
|
||||
validator,
|
||||
status: validator !== validator3 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
||||
}))
|
||||
getValidatorSuccessTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
||||
getSuccessExecutionTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
||||
validator: validatorData.validator,
|
||||
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
||||
txHash: '',
|
||||
@@ -83,7 +90,7 @@ describe('getConfirmationsForTx', () => {
|
||||
web3,
|
||||
validatorList,
|
||||
bridgeContract,
|
||||
confirmationContractMethod,
|
||||
true,
|
||||
setResult,
|
||||
requiredSignatures,
|
||||
setSignatureCollected,
|
||||
@@ -102,9 +109,10 @@ describe('getConfirmationsForTx', () => {
|
||||
expect(subscriptions.length).toEqual(1)
|
||||
expect(setResult).toBeCalledTimes(2)
|
||||
expect(getValidatorConfirmation).toBeCalledTimes(1)
|
||||
expect(getValidatorSuccessTransaction).toBeCalledTimes(1)
|
||||
expect(setSignatureCollected).toBeCalledTimes(1)
|
||||
expect(getSuccessExecutionTransaction).toBeCalledTimes(1)
|
||||
expect(setSignatureCollected).toBeCalledTimes(2)
|
||||
expect(setSignatureCollected.mock.calls[0][0]).toEqual(true)
|
||||
expect(setSignatureCollected.mock.calls[1][0]).toEqual([signature, signature])
|
||||
|
||||
expect(getValidatorFailedTransaction).toBeCalledTimes(1)
|
||||
expect(setFailedConfirmations).toBeCalledTimes(1)
|
||||
@@ -114,14 +122,16 @@ describe('getConfirmationsForTx', () => {
|
||||
expect(setPendingConfirmations).toBeCalledTimes(1)
|
||||
expect(setPendingConfirmations.mock.calls[0][0]).toEqual(false)
|
||||
|
||||
expect(setResult.mock.calls[0][0]()).toEqual(
|
||||
const res1 = setResult.mock.calls[0][0]()
|
||||
const res2 = setResult.mock.calls[1][0](res1)
|
||||
expect(res1).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED }
|
||||
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED }
|
||||
])
|
||||
)
|
||||
expect(setResult.mock.calls[1][0]).toEqual(
|
||||
expect(res2).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||
@@ -134,7 +144,7 @@ describe('getConfirmationsForTx', () => {
|
||||
validator,
|
||||
status: validator === validator3 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
||||
}))
|
||||
getValidatorSuccessTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
||||
getSuccessExecutionTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
||||
validator: validatorData.validator,
|
||||
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
||||
txHash: '',
|
||||
@@ -163,7 +173,7 @@ describe('getConfirmationsForTx', () => {
|
||||
web3,
|
||||
validatorList,
|
||||
bridgeContract,
|
||||
confirmationContractMethod,
|
||||
true,
|
||||
setResult,
|
||||
requiredSignatures,
|
||||
setSignatureCollected,
|
||||
@@ -179,9 +189,9 @@ describe('getConfirmationsForTx', () => {
|
||||
|
||||
unsubscribe()
|
||||
|
||||
expect(setResult).toBeCalledTimes(2)
|
||||
expect(setResult).toBeCalledTimes(1)
|
||||
expect(getValidatorConfirmation).toBeCalledTimes(1)
|
||||
expect(getValidatorSuccessTransaction).toBeCalledTimes(1)
|
||||
expect(getSuccessExecutionTransaction).toBeCalledTimes(1)
|
||||
expect(setSignatureCollected).toBeCalledTimes(1)
|
||||
expect(setSignatureCollected.mock.calls[0][0]).toEqual(false)
|
||||
|
||||
@@ -198,7 +208,7 @@ describe('getConfirmationsForTx', () => {
|
||||
validator,
|
||||
status: validator !== validator3 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
||||
}))
|
||||
getValidatorSuccessTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
||||
getSuccessExecutionTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
||||
validator: validatorData.validator,
|
||||
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
||||
txHash: validatorData.validator !== validator3 ? '0x123' : '',
|
||||
@@ -227,7 +237,7 @@ describe('getConfirmationsForTx', () => {
|
||||
web3,
|
||||
validatorList,
|
||||
bridgeContract,
|
||||
confirmationContractMethod,
|
||||
true,
|
||||
setResult,
|
||||
requiredSignatures,
|
||||
setSignatureCollected,
|
||||
@@ -244,11 +254,12 @@ describe('getConfirmationsForTx', () => {
|
||||
unsubscribe()
|
||||
|
||||
expect(subscriptions.length).toEqual(0)
|
||||
expect(setResult).toBeCalledTimes(2)
|
||||
expect(setResult).toBeCalledTimes(3)
|
||||
expect(getValidatorConfirmation).toBeCalledTimes(1)
|
||||
expect(getValidatorSuccessTransaction).toBeCalledTimes(1)
|
||||
expect(setSignatureCollected).toBeCalledTimes(1)
|
||||
expect(getSuccessExecutionTransaction).toBeCalledTimes(1)
|
||||
expect(setSignatureCollected).toBeCalledTimes(2)
|
||||
expect(setSignatureCollected.mock.calls[0][0]).toEqual(true)
|
||||
expect(setSignatureCollected.mock.calls[1][0]).toEqual([signature, signature])
|
||||
|
||||
expect(getValidatorFailedTransaction).toBeCalledTimes(1)
|
||||
expect(setFailedConfirmations).toBeCalledTimes(1)
|
||||
@@ -258,14 +269,24 @@ describe('getConfirmationsForTx', () => {
|
||||
expect(setPendingConfirmations).toBeCalledTimes(1)
|
||||
expect(setPendingConfirmations.mock.calls[0][0]).toEqual(false)
|
||||
|
||||
expect(setResult.mock.calls[0][0]()).toEqual(
|
||||
const res1 = setResult.mock.calls[0][0]()
|
||||
const res2 = setResult.mock.calls[1][0](res1)
|
||||
const res3 = setResult.mock.calls[2][0](res2)
|
||||
expect(res1).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED }
|
||||
])
|
||||
)
|
||||
expect(res2).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED }
|
||||
])
|
||||
)
|
||||
expect(setResult.mock.calls[1][0]).toEqual(
|
||||
expect(res3).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
||||
@@ -283,7 +304,7 @@ describe('getConfirmationsForTx', () => {
|
||||
? VALIDATOR_CONFIRMATION_STATUS.SUCCESS
|
||||
: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
||||
}))
|
||||
getValidatorSuccessTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
||||
getSuccessExecutionTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
||||
validator: validatorData.validator,
|
||||
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
||||
txHash: validatorData.validator !== validator3 && validatorData.validator !== validator4 ? '0x123' : '',
|
||||
@@ -315,7 +336,7 @@ describe('getConfirmationsForTx', () => {
|
||||
web3,
|
||||
validatorList,
|
||||
bridgeContract,
|
||||
confirmationContractMethod,
|
||||
true,
|
||||
setResult,
|
||||
requiredSignatures,
|
||||
setSignatureCollected,
|
||||
@@ -332,11 +353,12 @@ describe('getConfirmationsForTx', () => {
|
||||
unsubscribe()
|
||||
|
||||
expect(subscriptions.length).toEqual(0)
|
||||
expect(setResult).toBeCalledTimes(2)
|
||||
expect(setResult).toBeCalledTimes(4)
|
||||
expect(getValidatorConfirmation).toBeCalledTimes(1)
|
||||
expect(getValidatorSuccessTransaction).toBeCalledTimes(1)
|
||||
expect(setSignatureCollected).toBeCalledTimes(1)
|
||||
expect(getSuccessExecutionTransaction).toBeCalledTimes(1)
|
||||
expect(setSignatureCollected).toBeCalledTimes(2)
|
||||
expect(setSignatureCollected.mock.calls[0][0]).toEqual(true)
|
||||
expect(setSignatureCollected.mock.calls[1][0]).toEqual([signature, signature])
|
||||
|
||||
expect(getValidatorFailedTransaction).toBeCalledTimes(1)
|
||||
expect(setFailedConfirmations).toBeCalledTimes(1)
|
||||
@@ -346,7 +368,27 @@ describe('getConfirmationsForTx', () => {
|
||||
expect(setPendingConfirmations).toBeCalledTimes(1)
|
||||
expect(setPendingConfirmations.mock.calls[0][0]).toEqual(false)
|
||||
|
||||
expect(setResult.mock.calls[0][0]()).toEqual(
|
||||
const res1 = setResult.mock.calls[0][0]()
|
||||
const res2 = setResult.mock.calls[1][0](res1)
|
||||
const res3 = setResult.mock.calls[2][0](res2)
|
||||
const res4 = setResult.mock.calls[3][0](res3)
|
||||
expect(res1).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED },
|
||||
{ validator: validator4, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED }
|
||||
])
|
||||
)
|
||||
expect(res2).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
|
||||
{ validator: validator4, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED }
|
||||
])
|
||||
)
|
||||
expect(res3).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||
@@ -354,7 +396,7 @@ describe('getConfirmationsForTx', () => {
|
||||
{ validator: validator4, status: VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED }
|
||||
])
|
||||
)
|
||||
expect(setResult.mock.calls[1][0]).toEqual(
|
||||
expect(res4).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
||||
@@ -372,7 +414,7 @@ describe('getConfirmationsForTx', () => {
|
||||
validator,
|
||||
status: validator === validator1 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
||||
}))
|
||||
getValidatorSuccessTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
||||
getSuccessExecutionTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
||||
validator: validatorData.validator,
|
||||
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
||||
txHash: validatorData.validator === validator1 ? '0x123' : '',
|
||||
@@ -407,7 +449,7 @@ describe('getConfirmationsForTx', () => {
|
||||
web3,
|
||||
validatorList,
|
||||
bridgeContract,
|
||||
confirmationContractMethod,
|
||||
true,
|
||||
setResult,
|
||||
requiredSignatures,
|
||||
setSignatureCollected,
|
||||
@@ -423,9 +465,9 @@ describe('getConfirmationsForTx', () => {
|
||||
|
||||
unsubscribe()
|
||||
|
||||
expect(setResult).toBeCalledTimes(2)
|
||||
expect(setResult).toBeCalledTimes(4)
|
||||
expect(getValidatorConfirmation).toBeCalledTimes(1)
|
||||
expect(getValidatorSuccessTransaction).toBeCalledTimes(1)
|
||||
expect(getSuccessExecutionTransaction).toBeCalledTimes(1)
|
||||
expect(setSignatureCollected).toBeCalledTimes(1)
|
||||
expect(setSignatureCollected.mock.calls[0][0]).toEqual(false)
|
||||
|
||||
@@ -437,14 +479,32 @@ describe('getConfirmationsForTx', () => {
|
||||
expect(setPendingConfirmations).toBeCalledTimes(1)
|
||||
expect(setPendingConfirmations.mock.calls[0][0]).toEqual(true)
|
||||
|
||||
expect(setResult.mock.calls[0][0]()).toEqual(
|
||||
const res1 = setResult.mock.calls[0][0]()
|
||||
const res2 = setResult.mock.calls[1][0](res1)
|
||||
const res3 = setResult.mock.calls[2][0](res2)
|
||||
const res4 = setResult.mock.calls[3][0](res3)
|
||||
expect(res1).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED },
|
||||
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED }
|
||||
])
|
||||
)
|
||||
expect(res2).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED },
|
||||
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.PENDING, txHash: '0x123', timestamp: 123 }
|
||||
])
|
||||
)
|
||||
expect(res3).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
|
||||
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.PENDING, txHash: '0x123', timestamp: 123 }
|
||||
])
|
||||
)
|
||||
expect(setResult.mock.calls[1][0]).toEqual(
|
||||
expect(res4).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
|
||||
@@ -461,7 +521,7 @@ describe('getConfirmationsForTx', () => {
|
||||
validator,
|
||||
status: validator === validator1 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
||||
}))
|
||||
getValidatorSuccessTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
||||
getSuccessExecutionTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
||||
validator: validatorData.validator,
|
||||
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
||||
txHash: validatorData.validator === validator1 ? '0x123' : '',
|
||||
@@ -493,7 +553,7 @@ describe('getConfirmationsForTx', () => {
|
||||
web3,
|
||||
validatorList,
|
||||
bridgeContract,
|
||||
confirmationContractMethod,
|
||||
true,
|
||||
setResult,
|
||||
requiredSignatures,
|
||||
setSignatureCollected,
|
||||
@@ -510,9 +570,9 @@ describe('getConfirmationsForTx', () => {
|
||||
unsubscribe()
|
||||
|
||||
expect(subscriptions.length).toEqual(0)
|
||||
expect(setResult).toBeCalledTimes(2)
|
||||
expect(setResult).toBeCalledTimes(3)
|
||||
expect(getValidatorConfirmation).toBeCalledTimes(1)
|
||||
expect(getValidatorSuccessTransaction).toBeCalledTimes(1)
|
||||
expect(getSuccessExecutionTransaction).toBeCalledTimes(1)
|
||||
expect(setSignatureCollected).toBeCalledTimes(1)
|
||||
expect(setSignatureCollected.mock.calls[0][0]).toEqual(false)
|
||||
|
||||
@@ -524,14 +584,24 @@ describe('getConfirmationsForTx', () => {
|
||||
expect(setPendingConfirmations).toBeCalledTimes(1)
|
||||
expect(setPendingConfirmations.mock.calls[0][0]).toEqual(false)
|
||||
|
||||
expect(setResult.mock.calls[0][0]()).toEqual(
|
||||
const res1 = setResult.mock.calls[0][0]()
|
||||
const res2 = setResult.mock.calls[1][0](res1)
|
||||
const res3 = setResult.mock.calls[2][0](res2)
|
||||
expect(res1).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED },
|
||||
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED }
|
||||
])
|
||||
)
|
||||
expect(res2).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
|
||||
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 }
|
||||
])
|
||||
)
|
||||
expect(setResult.mock.calls[1][0]).toEqual(
|
||||
expect(res3).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
|
||||
@@ -555,7 +625,7 @@ describe('getConfirmationsForTx', () => {
|
||||
status:
|
||||
validator !== validator2 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
||||
}))
|
||||
getValidatorSuccessTransaction
|
||||
getSuccessExecutionTransaction
|
||||
.mockImplementationOnce(() => async (validatorData: BasicConfirmationParam) => ({
|
||||
validator: validatorData.validator,
|
||||
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
||||
@@ -604,57 +674,7 @@ describe('getConfirmationsForTx', () => {
|
||||
web3,
|
||||
validatorList,
|
||||
bridgeContract,
|
||||
confirmationContractMethod,
|
||||
setResult,
|
||||
requiredSignatures,
|
||||
setSignatureCollected,
|
||||
waitingBlocksResolved,
|
||||
subscriptions,
|
||||
timestamp,
|
||||
getFailedTransactions,
|
||||
setFailedConfirmations,
|
||||
getPendingTransactions,
|
||||
setPendingConfirmations,
|
||||
getSuccessTransactions
|
||||
)
|
||||
|
||||
unsubscribe()
|
||||
|
||||
expect(setResult).toBeCalledTimes(2)
|
||||
expect(getValidatorConfirmation).toBeCalledTimes(1)
|
||||
expect(getValidatorSuccessTransaction).toBeCalledTimes(1)
|
||||
expect(setSignatureCollected).toBeCalledTimes(1)
|
||||
expect(setSignatureCollected.mock.calls[0][0]).toEqual(false)
|
||||
|
||||
expect(getValidatorFailedTransaction).toBeCalledTimes(1)
|
||||
expect(setFailedConfirmations).toBeCalledTimes(1)
|
||||
expect(setFailedConfirmations.mock.calls[0][0]).toEqual(false)
|
||||
|
||||
expect(getValidatorPendingTransaction).toBeCalledTimes(1)
|
||||
expect(setPendingConfirmations).toBeCalledTimes(1)
|
||||
expect(setPendingConfirmations.mock.calls[0][0]).toEqual(true)
|
||||
|
||||
expect(setResult.mock.calls[0][0]()).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
|
||||
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.PENDING, txHash: '0x123', timestamp: 123 }
|
||||
])
|
||||
)
|
||||
expect(setResult.mock.calls[1][0]).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
|
||||
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.PENDING, txHash: '0x123', timestamp: 123 }
|
||||
])
|
||||
)
|
||||
|
||||
await getConfirmationsForTx(
|
||||
messageData,
|
||||
web3,
|
||||
validatorList,
|
||||
bridgeContract,
|
||||
confirmationContractMethod,
|
||||
true,
|
||||
setResult,
|
||||
requiredSignatures,
|
||||
setSignatureCollected,
|
||||
@@ -671,11 +691,80 @@ describe('getConfirmationsForTx', () => {
|
||||
unsubscribe()
|
||||
|
||||
expect(setResult).toBeCalledTimes(4)
|
||||
expect(getValidatorConfirmation).toBeCalledTimes(1)
|
||||
expect(getSuccessExecutionTransaction).toBeCalledTimes(1)
|
||||
expect(setSignatureCollected).toBeCalledTimes(1)
|
||||
expect(setSignatureCollected.mock.calls[0][0]).toEqual(false)
|
||||
|
||||
expect(getValidatorFailedTransaction).toBeCalledTimes(1)
|
||||
expect(setFailedConfirmations).toBeCalledTimes(1)
|
||||
expect(setFailedConfirmations.mock.calls[0][0]).toEqual(false)
|
||||
|
||||
expect(getValidatorPendingTransaction).toBeCalledTimes(1)
|
||||
expect(setPendingConfirmations).toBeCalledTimes(1)
|
||||
expect(setPendingConfirmations.mock.calls[0][0]).toEqual(true)
|
||||
|
||||
const res1 = setResult.mock.calls[0][0]()
|
||||
const res2 = setResult.mock.calls[1][0](res1)
|
||||
const res3 = setResult.mock.calls[2][0](res2)
|
||||
const res4 = setResult.mock.calls[3][0](res3)
|
||||
expect(res1).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED },
|
||||
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED }
|
||||
])
|
||||
)
|
||||
expect(res2).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED },
|
||||
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.PENDING, txHash: '0x123', timestamp: 123 }
|
||||
])
|
||||
)
|
||||
expect(res3).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
|
||||
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.PENDING, txHash: '0x123', timestamp: 123 }
|
||||
])
|
||||
)
|
||||
expect(res4).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
|
||||
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.PENDING, txHash: '0x123', timestamp: 123 }
|
||||
])
|
||||
)
|
||||
|
||||
await getConfirmationsForTx(
|
||||
messageData,
|
||||
web3,
|
||||
validatorList,
|
||||
bridgeContract,
|
||||
true,
|
||||
setResult,
|
||||
requiredSignatures,
|
||||
setSignatureCollected,
|
||||
waitingBlocksResolved,
|
||||
subscriptions,
|
||||
timestamp,
|
||||
getFailedTransactions,
|
||||
setFailedConfirmations,
|
||||
getPendingTransactions,
|
||||
setPendingConfirmations,
|
||||
getSuccessTransactions
|
||||
)
|
||||
|
||||
unsubscribe()
|
||||
|
||||
expect(setResult).toBeCalledTimes(7)
|
||||
expect(getValidatorConfirmation).toBeCalledTimes(2)
|
||||
expect(getValidatorSuccessTransaction).toBeCalledTimes(2)
|
||||
expect(setSignatureCollected).toBeCalledTimes(2)
|
||||
expect(getSuccessExecutionTransaction).toBeCalledTimes(2)
|
||||
expect(setSignatureCollected).toBeCalledTimes(3)
|
||||
expect(setSignatureCollected.mock.calls[0][0]).toEqual(false)
|
||||
expect(setSignatureCollected.mock.calls[1][0]).toEqual(true)
|
||||
expect(setSignatureCollected.mock.calls[2][0]).toEqual([signature, signature])
|
||||
|
||||
expect(getValidatorFailedTransaction).toBeCalledTimes(2)
|
||||
expect(setFailedConfirmations).toBeCalledTimes(2)
|
||||
@@ -687,14 +776,24 @@ describe('getConfirmationsForTx', () => {
|
||||
expect(setPendingConfirmations.mock.calls[0][0]).toEqual(true)
|
||||
expect(setPendingConfirmations.mock.calls[1][0]).toEqual(false)
|
||||
|
||||
expect(setResult.mock.calls[2][0]()).toEqual(
|
||||
const res5 = setResult.mock.calls[4][0](res4)
|
||||
const res6 = setResult.mock.calls[5][0](res5)
|
||||
const res7 = setResult.mock.calls[6][0](res6)
|
||||
expect(res5).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
|
||||
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS }
|
||||
])
|
||||
)
|
||||
expect(setResult.mock.calls[3][0]).toEqual(
|
||||
expect(res6).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
|
||||
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS }
|
||||
])
|
||||
)
|
||||
expect(res7).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
|
||||
|
||||
@@ -61,6 +61,7 @@ describe('getFinalizationEvent', () => {
|
||||
const setFailedExecution = jest.fn()
|
||||
const getPendingExecution = jest.fn()
|
||||
const setPendingExecution = jest.fn()
|
||||
const setExecutionEventsFetched = jest.fn()
|
||||
|
||||
await getFinalizationEvent(
|
||||
contract,
|
||||
@@ -76,7 +77,8 @@ describe('getFinalizationEvent', () => {
|
||||
getFailedExecution,
|
||||
setFailedExecution,
|
||||
getPendingExecution,
|
||||
setPendingExecution
|
||||
setPendingExecution,
|
||||
setExecutionEventsFetched
|
||||
)
|
||||
|
||||
unsubscribe()
|
||||
@@ -110,6 +112,7 @@ describe('getFinalizationEvent', () => {
|
||||
const setFailedExecution = jest.fn()
|
||||
const getPendingExecution = jest.fn()
|
||||
const setPendingExecution = jest.fn()
|
||||
const setExecutionEventsFetched = jest.fn()
|
||||
|
||||
await getFinalizationEvent(
|
||||
contract,
|
||||
@@ -125,7 +128,8 @@ describe('getFinalizationEvent', () => {
|
||||
getFailedExecution,
|
||||
setFailedExecution,
|
||||
getPendingExecution,
|
||||
setPendingExecution
|
||||
setPendingExecution,
|
||||
setExecutionEventsFetched
|
||||
)
|
||||
|
||||
unsubscribe()
|
||||
@@ -159,6 +163,7 @@ describe('getFinalizationEvent', () => {
|
||||
const setFailedExecution = jest.fn()
|
||||
const getPendingExecution = jest.fn().mockResolvedValue([])
|
||||
const setPendingExecution = jest.fn()
|
||||
const setExecutionEventsFetched = jest.fn()
|
||||
|
||||
await getFinalizationEvent(
|
||||
contract,
|
||||
@@ -174,7 +179,8 @@ describe('getFinalizationEvent', () => {
|
||||
getFailedExecution,
|
||||
setFailedExecution,
|
||||
getPendingExecution,
|
||||
setPendingExecution
|
||||
setPendingExecution,
|
||||
setExecutionEventsFetched
|
||||
)
|
||||
|
||||
unsubscribe()
|
||||
@@ -208,6 +214,7 @@ describe('getFinalizationEvent', () => {
|
||||
const setFailedExecution = jest.fn()
|
||||
const getPendingExecution = jest.fn().mockResolvedValue([{ hash: txHash }])
|
||||
const setPendingExecution = jest.fn()
|
||||
const setExecutionEventsFetched = jest.fn()
|
||||
|
||||
await getFinalizationEvent(
|
||||
contract,
|
||||
@@ -223,7 +230,8 @@ describe('getFinalizationEvent', () => {
|
||||
getFailedExecution,
|
||||
setFailedExecution,
|
||||
getPendingExecution,
|
||||
setPendingExecution
|
||||
setPendingExecution,
|
||||
setExecutionEventsFetched
|
||||
)
|
||||
|
||||
unsubscribe()
|
||||
@@ -264,6 +272,7 @@ describe('getFinalizationEvent', () => {
|
||||
const setFailedExecution = jest.fn()
|
||||
const getPendingExecution = jest.fn().mockResolvedValue([])
|
||||
const setPendingExecution = jest.fn()
|
||||
const setExecutionEventsFetched = jest.fn()
|
||||
|
||||
await getFinalizationEvent(
|
||||
contract,
|
||||
@@ -279,7 +288,8 @@ describe('getFinalizationEvent', () => {
|
||||
getFailedExecution,
|
||||
setFailedExecution,
|
||||
getPendingExecution,
|
||||
setPendingExecution
|
||||
setPendingExecution,
|
||||
setExecutionEventsFetched
|
||||
)
|
||||
|
||||
unsubscribe()
|
||||
|
||||
@@ -15,13 +15,19 @@ export const checkWaitingBlocksForExecution = async (
|
||||
const currentBlock = blockProvider.get()
|
||||
|
||||
if (currentBlock && currentBlock >= targetBlock) {
|
||||
setExecutionData({
|
||||
const undefinedExecutionState = {
|
||||
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
||||
validator: collectedSignaturesEvent.returnValues.authorityResponsibleForRelay,
|
||||
txHash: '',
|
||||
timestamp: 0,
|
||||
executionResult: false
|
||||
})
|
||||
}
|
||||
setExecutionData(
|
||||
(data: any) =>
|
||||
data.status === VALIDATOR_CONFIRMATION_STATUS.UNDEFINED || data.status === VALIDATOR_CONFIRMATION_STATUS.WAITING
|
||||
? undefinedExecutionState
|
||||
: data
|
||||
)
|
||||
setWaitingBlocksForExecutionResolved(true)
|
||||
setWaitingBlocksForExecution(false)
|
||||
blockProvider.stop()
|
||||
@@ -31,13 +37,20 @@ export const checkWaitingBlocksForExecution = async (
|
||||
nextInterval = 500
|
||||
} else {
|
||||
setWaitingBlocksForExecution(true)
|
||||
setExecutionData({
|
||||
const waitingExecutionState = {
|
||||
status: VALIDATOR_CONFIRMATION_STATUS.WAITING,
|
||||
validator: collectedSignaturesEvent.returnValues.authorityResponsibleForRelay,
|
||||
txHash: '',
|
||||
timestamp: 0,
|
||||
executionResult: false
|
||||
})
|
||||
}
|
||||
setExecutionData(
|
||||
(data: any) =>
|
||||
data.status === VALIDATOR_CONFIRMATION_STATUS.UNDEFINED ||
|
||||
data.status === VALIDATOR_CONFIRMATION_STATUS.WAITING
|
||||
? waitingExecutionState
|
||||
: data
|
||||
)
|
||||
}
|
||||
const timeoutId = setTimeout(
|
||||
() =>
|
||||
|
||||
@@ -7,20 +7,37 @@ import {
|
||||
APIPendingTransaction,
|
||||
GetPendingTransactionParams
|
||||
} from './explorer'
|
||||
import { getAffirmationsSigned, getMessagesSigned } from './contract'
|
||||
import {
|
||||
getValidatorConfirmation,
|
||||
getValidatorFailedTransaction,
|
||||
getValidatorPendingTransaction,
|
||||
getValidatorSuccessTransaction
|
||||
getSuccessExecutionTransaction
|
||||
} from './validatorConfirmationHelpers'
|
||||
import { ConfirmationParam } from '../hooks/useMessageConfirmations'
|
||||
import { BasicConfirmationParam, ConfirmationParam } from '../hooks/useMessageConfirmations'
|
||||
|
||||
const mergeConfirmations = (oldConfirmations: BasicConfirmationParam[], newConfirmations: BasicConfirmationParam[]) => {
|
||||
const confirmations = [...oldConfirmations]
|
||||
newConfirmations.forEach(validatorData => {
|
||||
const index = confirmations.findIndex(e => e.validator === validatorData.validator)
|
||||
const currentStatus = confirmations[index].status
|
||||
const newStatus = validatorData.status
|
||||
if (
|
||||
(validatorData as ConfirmationParam).txHash ||
|
||||
(newStatus !== currentStatus && newStatus !== VALIDATOR_CONFIRMATION_STATUS.UNDEFINED)
|
||||
) {
|
||||
confirmations[index] = validatorData
|
||||
}
|
||||
})
|
||||
return confirmations
|
||||
}
|
||||
|
||||
export const getConfirmationsForTx = async (
|
||||
messageData: string,
|
||||
web3: Maybe<Web3>,
|
||||
validatorList: string[],
|
||||
bridgeContract: Maybe<Contract>,
|
||||
confirmationContractMethod: Function,
|
||||
fromHome: boolean,
|
||||
setResult: Function,
|
||||
requiredSignatures: number,
|
||||
setSignatureCollected: Function,
|
||||
@@ -35,48 +52,47 @@ export const getConfirmationsForTx = async (
|
||||
) => {
|
||||
if (!web3 || !validatorList || !validatorList.length || !bridgeContract || !waitingBlocksResolved) return
|
||||
|
||||
// If all the information was not collected, then it should retry
|
||||
let shouldRetry = false
|
||||
const confirmationContractMethod = fromHome ? getMessagesSigned : getAffirmationsSigned
|
||||
|
||||
const hashMsg = web3.utils.soliditySha3Raw(messageData)
|
||||
let validatorConfirmations = await Promise.all(
|
||||
validatorList.map(getValidatorConfirmation(web3, hashMsg, bridgeContract, confirmationContractMethod))
|
||||
)
|
||||
|
||||
const successConfirmations = validatorConfirmations.filter(c => c.status === VALIDATOR_CONFIRMATION_STATUS.SUCCESS)
|
||||
|
||||
setResult((prevConfirmations: ConfirmationParam[]) => {
|
||||
if (prevConfirmations && prevConfirmations.length) {
|
||||
successConfirmations.forEach(validatorData => {
|
||||
const index = prevConfirmations.findIndex(e => e.validator === validatorData.validator)
|
||||
validatorConfirmations[index] = validatorData
|
||||
})
|
||||
return prevConfirmations
|
||||
} else {
|
||||
return validatorConfirmations
|
||||
const updateConfirmations = (confirmations: BasicConfirmationParam[]) => {
|
||||
if (confirmations.length === 0) {
|
||||
return
|
||||
}
|
||||
})
|
||||
validatorConfirmations = mergeConfirmations(validatorConfirmations, confirmations)
|
||||
setResult((currentConfirmations: BasicConfirmationParam[]) => {
|
||||
if (currentConfirmations && currentConfirmations.length) {
|
||||
return mergeConfirmations(currentConfirmations, confirmations)
|
||||
}
|
||||
return confirmations
|
||||
})
|
||||
}
|
||||
|
||||
const successConfirmations = validatorConfirmations.filter(c => c.status === VALIDATOR_CONFIRMATION_STATUS.SUCCESS)
|
||||
const notSuccessConfirmations = validatorConfirmations.filter(c => c.status !== VALIDATOR_CONFIRMATION_STATUS.SUCCESS)
|
||||
const hasEnoughSignatures = successConfirmations.length === requiredSignatures
|
||||
|
||||
updateConfirmations(validatorConfirmations)
|
||||
setSignatureCollected(hasEnoughSignatures)
|
||||
|
||||
// If signatures not collected, look for pending transactions
|
||||
let pendingConfirmationsResult = false
|
||||
if (successConfirmations.length !== requiredSignatures) {
|
||||
if (!hasEnoughSignatures) {
|
||||
// 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) {
|
||||
pendingConfirmationsResult = true
|
||||
}
|
||||
updateConfirmations(validatorPendingConfirmations)
|
||||
setPendingConfirmations(validatorPendingConfirmations.length > 0)
|
||||
} else {
|
||||
setPendingConfirmations(false)
|
||||
}
|
||||
|
||||
const undefinedConfirmations = validatorConfirmations.filter(
|
||||
@@ -84,7 +100,6 @@ export const getConfirmationsForTx = async (
|
||||
)
|
||||
|
||||
// Check if confirmation failed
|
||||
let failedConfirmationsResult = false
|
||||
const validatorFailedConfirmationsChecks = await Promise.all(
|
||||
undefinedConfirmations.map(
|
||||
getValidatorFailedTransaction(bridgeContract, messageData, timestamp, getFailedTransactions)
|
||||
@@ -93,68 +108,47 @@ export const getConfirmationsForTx = async (
|
||||
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) {
|
||||
failedConfirmationsResult = true
|
||||
}
|
||||
setFailedConfirmations(validatorFailedConfirmations.length > validatorList.length - requiredSignatures)
|
||||
updateConfirmations(validatorFailedConfirmations)
|
||||
|
||||
const missingConfirmations = validatorConfirmations.filter(
|
||||
c => c.status === VALIDATOR_CONFIRMATION_STATUS.UNDEFINED || c.status === VALIDATOR_CONFIRMATION_STATUS.PENDING
|
||||
)
|
||||
|
||||
if (successConfirmations.length !== requiredSignatures && missingConfirmations.length > 0) {
|
||||
shouldRetry = true
|
||||
}
|
||||
|
||||
let signatureCollectedResult = false
|
||||
if (successConfirmations.length === requiredSignatures) {
|
||||
if (hasEnoughSignatures) {
|
||||
// If signatures collected, it should set other signatures not found as not required
|
||||
const notRequiredConfirmations = missingConfirmations.map(c => ({
|
||||
validator: c.validator,
|
||||
status: VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED
|
||||
}))
|
||||
updateConfirmations(notRequiredConfirmations)
|
||||
|
||||
notRequiredConfirmations.forEach(validatorData => {
|
||||
const index = validatorConfirmations.findIndex(e => e.validator === validatorData.validator)
|
||||
validatorConfirmations[index] = validatorData
|
||||
})
|
||||
signatureCollectedResult = true
|
||||
if (fromHome) {
|
||||
// fetch collected signatures for possible manual processing
|
||||
setSignatureCollected(
|
||||
await Promise.all(
|
||||
Array.from(Array(requiredSignatures).keys()).map(i => bridgeContract.methods.signature(hashMsg, i).call())
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
successConfirmations.map(
|
||||
getSuccessExecutionTransaction(web3, bridgeContract, fromHome, messageData, timestamp, getSuccessTransactions)
|
||||
)
|
||||
)
|
||||
|
||||
const successConfirmationWithTxFound = successConfirmationWithData.filter(v => v.txHash !== '')
|
||||
updateConfirmations(successConfirmationWithTxFound)
|
||||
|
||||
const updatedValidatorConfirmations = [...validatorConfirmations]
|
||||
|
||||
if (successConfirmationWithTxFound.length > 0) {
|
||||
successConfirmationWithTxFound.forEach(validatorData => {
|
||||
const index = updatedValidatorConfirmations.findIndex(e => e.validator === validatorData.validator)
|
||||
updatedValidatorConfirmations[index] = validatorData
|
||||
})
|
||||
}
|
||||
|
||||
// Set results
|
||||
setResult(updatedValidatorConfirmations)
|
||||
setFailedConfirmations(failedConfirmationsResult)
|
||||
setPendingConfirmations(pendingConfirmationsResult)
|
||||
setSignatureCollected(signatureCollectedResult)
|
||||
|
||||
// Retry if not all transaction were found for validator confirmations
|
||||
if (successConfirmationWithTxFound.length < successConfirmationWithData.length) {
|
||||
shouldRetry = true
|
||||
}
|
||||
|
||||
if (shouldRetry) {
|
||||
// retry if not all signatures are collected and some confirmations are still missing
|
||||
// or some success transactions were not fetched successfully
|
||||
if (
|
||||
(!hasEnoughSignatures && missingConfirmations.length > 0) ||
|
||||
successConfirmationWithTxFound.length < successConfirmationWithData.length
|
||||
) {
|
||||
const timeoutId = setTimeout(
|
||||
() =>
|
||||
getConfirmationsForTx(
|
||||
@@ -162,7 +156,7 @@ export const getConfirmationsForTx = async (
|
||||
web3,
|
||||
validatorList,
|
||||
bridgeContract,
|
||||
confirmationContractMethod,
|
||||
fromHome,
|
||||
setResult,
|
||||
requiredSignatures,
|
||||
setSignatureCollected,
|
||||
|
||||
@@ -25,7 +25,8 @@ export const getFinalizationEvent = async (
|
||||
getFailedExecution: (args: GetFailedTransactionParams) => Promise<APITransaction[]>,
|
||||
setFailedExecution: Function,
|
||||
getPendingExecution: (args: GetPendingTransactionParams) => Promise<APIPendingTransaction[]>,
|
||||
setPendingExecution: Function
|
||||
setPendingExecution: Function,
|
||||
setExecutionEventsFetched: Function
|
||||
) => {
|
||||
if (!contract || !web3 || !waitingBlocksResolved) return
|
||||
// Since it filters by the message id, only one event will be fetched
|
||||
@@ -55,6 +56,7 @@ export const getFinalizationEvent = async (
|
||||
executionResult: event.returnValues.status
|
||||
})
|
||||
} else {
|
||||
setExecutionEventsFetched(true)
|
||||
// If event is defined, it means it is a message from Home to Foreign
|
||||
if (collectedSignaturesEvent) {
|
||||
const validator = collectedSignaturesEvent.returnValues.authorityResponsibleForRelay
|
||||
@@ -128,7 +130,8 @@ export const getFinalizationEvent = async (
|
||||
getFailedExecution,
|
||||
setFailedExecution,
|
||||
getPendingExecution,
|
||||
setPendingExecution
|
||||
setPendingExecution,
|
||||
setExecutionEventsFetched
|
||||
),
|
||||
interval
|
||||
)
|
||||
|
||||
26
alm/src/utils/signatures.ts
Normal file
26
alm/src/utils/signatures.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import Web3 from 'web3'
|
||||
|
||||
function strip0x(s: string) {
|
||||
return Web3.utils.isHexStrict(s) ? s.substr(2) : s
|
||||
}
|
||||
|
||||
export interface Signature {
|
||||
v: string
|
||||
r: string
|
||||
s: string
|
||||
}
|
||||
|
||||
export function signatureToVRS(rawSignature: string): Signature {
|
||||
const signature = strip0x(rawSignature)
|
||||
const v = signature.substr(64 * 2)
|
||||
const r = signature.substr(0, 32 * 2)
|
||||
const s = signature.substr(32 * 2, 32 * 2)
|
||||
return { v, r, s }
|
||||
}
|
||||
|
||||
export function packSignatures(array: Array<Signature>): string {
|
||||
const length = strip0x(Web3.utils.toHex(array.length))
|
||||
const msgLength = length.length === 1 ? `0${length}` : length
|
||||
const [v, r, s] = array.reduce(([vs, rs, ss], { v, r, s }) => [vs + v, rs + r, ss + s], ['', '', ''])
|
||||
return `0x${msgLength}${v}${r}${s}`
|
||||
}
|
||||
@@ -45,8 +45,10 @@ export const getValidatorConfirmation = (
|
||||
}
|
||||
}
|
||||
|
||||
export const getValidatorSuccessTransaction = (
|
||||
export const getSuccessExecutionTransaction = (
|
||||
web3: Web3,
|
||||
bridgeContract: Contract,
|
||||
fromHome: boolean,
|
||||
messageData: string,
|
||||
timestamp: number,
|
||||
getSuccessTransactions: (args: GetFailedTransactionParams) => Promise<APITransaction[]>
|
||||
|
||||
Binary file not shown.
@@ -5,7 +5,8 @@
|
||||
],
|
||||
"rules": {
|
||||
"no-unused-expressions": "off",
|
||||
"import/no-extraneous-dependencies": "off"
|
||||
"import/no-extraneous-dependencies": "off",
|
||||
"no-bitwise": "off"
|
||||
},
|
||||
"env": {
|
||||
"mocha": true
|
||||
|
||||
@@ -2,9 +2,15 @@ function strip0x(input) {
|
||||
return input.replace(/^0x/, '')
|
||||
}
|
||||
|
||||
function addTxHashToData({ encodedData, transactionHash }) {
|
||||
return encodedData.slice(0, 2) + strip0x(transactionHash) + encodedData.slice(2)
|
||||
}
|
||||
/**
|
||||
* Decodes the datatype byte from the AMB message.
|
||||
* First (the most significant bit) denotes if the message should be forwarded to the manual lane.
|
||||
* @param dataType: number datatype of the received AMB message.
|
||||
* @return {{manualLane: boolean}}
|
||||
*/
|
||||
const decodeAMBDataType = dataType => ({
|
||||
manualLane: (dataType & 128) === 128
|
||||
})
|
||||
|
||||
function parseAMBMessage(message) {
|
||||
message = strip0x(message)
|
||||
@@ -12,16 +18,29 @@ function parseAMBMessage(message) {
|
||||
const messageId = `0x${message.slice(0, 64)}`
|
||||
const sender = `0x${message.slice(64, 104)}`
|
||||
const executor = `0x${message.slice(104, 144)}`
|
||||
const dataType = parseInt(message.slice(156, 158), 16)
|
||||
|
||||
return {
|
||||
sender,
|
||||
executor,
|
||||
messageId
|
||||
messageId,
|
||||
dataType,
|
||||
decodedDataType: decodeAMBDataType(dataType)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
addTxHashToData,
|
||||
parseAMBMessage,
|
||||
strip0x
|
||||
const normalizeAMBMessageEvent = e => {
|
||||
let msgData = e.returnValues.encodedData
|
||||
if (!e.returnValues.messageId) {
|
||||
// append tx hash to an old message, where message id was not used
|
||||
// for old messages, e.messageId is a corresponding transactionHash
|
||||
msgData = e.transactionHash + msgData.slice(2)
|
||||
}
|
||||
return parseAMBMessage(msgData)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
strip0x,
|
||||
parseAMBMessage,
|
||||
normalizeAMBMessageEvent
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const { BN } = require('web3-utils')
|
||||
const { expect } = require('chai').use(require('bn-chai')(BN))
|
||||
const { parseAMBMessage, strip0x, addTxHashToData } = require('../message')
|
||||
const { parseAMBMessage, strip0x } = require('../message')
|
||||
|
||||
describe('strip0x', () => {
|
||||
it('should remove 0x from input', () => {
|
||||
@@ -24,28 +24,6 @@ describe('strip0x', () => {
|
||||
expect(result).to.be.equal(input)
|
||||
})
|
||||
})
|
||||
describe('addTxHashToData', () => {
|
||||
it('should add txHash to encoded data at position 2', () => {
|
||||
// Given
|
||||
const msgSender = '0x003667154bb32e42bb9e1e6532f19d187fa0082e'
|
||||
const msgExecutor = '0xf4bef13f9f4f2b203faf0c3cbbaabe1afe056955'
|
||||
const msgGasLimit = '000000000000000000000000000000000000000000000000000000005b877705'
|
||||
const msgDataType = '00'
|
||||
const msgData = '0xb1591967aed668a4b27645ff40c444892d91bf5951b382995d4d4f6ee3a2ce03'
|
||||
const encodedData = `0x${strip0x(msgSender)}${strip0x(msgExecutor)}${msgGasLimit}${msgDataType}${strip0x(msgData)}`
|
||||
|
||||
const transactionHash = '0xbdceda9d8c94838aca10c687da1411a07b1390e88239c0638cb9cc264219cc10'
|
||||
const message = `0x${strip0x(transactionHash)}${strip0x(msgSender)}${strip0x(
|
||||
msgExecutor
|
||||
)}${msgGasLimit}${msgDataType}${strip0x(msgData)}`
|
||||
|
||||
// When
|
||||
const result = addTxHashToData({ encodedData, transactionHash })
|
||||
|
||||
// Then
|
||||
expect(result).to.be.equal(message)
|
||||
})
|
||||
})
|
||||
describe('parseAMBMessage', () => {
|
||||
it('should parse data type 00', () => {
|
||||
const msgSender = '0x003667154bb32e42bb9e1e6532f19d187fa0082e'
|
||||
|
||||
@@ -164,7 +164,7 @@ const getPastEvents = async (
|
||||
} catch (e) {
|
||||
if (e.message.includes('query returned more than') && toBlock !== 'latest') {
|
||||
const middle = toBN(fromBlock)
|
||||
.add(toBlock)
|
||||
.add(toBN(toBlock))
|
||||
.divRound(toBN(2))
|
||||
const middlePlusOne = middle.add(toBN(1))
|
||||
|
||||
|
||||
Submodule contracts updated: dd46135248...835742dfd8
@@ -32,8 +32,6 @@ provisioner:
|
||||
inventory:
|
||||
host_vars:
|
||||
oracle-amb-host:
|
||||
COMMON_HOME_RPC_URL: "http://parity1:8545"
|
||||
COMMON_FOREIGN_RPC_URL: "http://parity2:8545"
|
||||
ORACLE_VALIDATOR_ADDRESS: "0xaaB52d66283F7A1D5978bcFcB55721ACB467384b"
|
||||
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
|
||||
ui-amb-stake-erc-to-erc-host:
|
||||
|
||||
@@ -21,8 +21,6 @@ provisioner:
|
||||
inventory:
|
||||
host_vars:
|
||||
oracle-amb-host:
|
||||
COMMON_HOME_RPC_URL: "http://parity1:8545"
|
||||
COMMON_FOREIGN_RPC_URL: "http://parity2:8545"
|
||||
ORACLE_VALIDATOR_ADDRESS: "0xaaB52d66283F7A1D5978bcFcB55721ACB467384b"
|
||||
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
|
||||
verifier:
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
---
|
||||
- import_playbook: ../../../deployment/site.yml
|
||||
# The docker-compose files have to be modified, in order to join the docker containers over network with the parity containers
|
||||
- import_playbook: ./oracle-docker-compose.yml
|
||||
- import_playbook: ./ui-docker-compose.yml
|
||||
- import_playbook: ../../../deployment/site.yml
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
---
|
||||
- name: Slurp docker compose file
|
||||
slurp:
|
||||
src: "/home/poadocker/bridge/oracle/{{ file }}.yml"
|
||||
register: docker_compose_slurp
|
||||
- name: Parse docker compose file
|
||||
set_fact:
|
||||
docker_compose_parsed: "{{ docker_compose_slurp['content'] | b64decode | from_yaml }}"
|
||||
|
||||
- name: Add the external network used to connect to Parity nodes
|
||||
set_fact:
|
||||
docker_compose_parsed: "{{ docker_compose_parsed |combine({'networks': {'ultimate': {'external': 'true'}}}, recursive=True) }}"
|
||||
|
||||
- name: Add all Oracle containers to the network
|
||||
set_fact:
|
||||
docker_compose_parsed: "{{ docker_compose_parsed | combine({'services': {item: {'networks': docker_compose_parsed.services[item].networks | union(['ultimate'])}}}, recursive=True) }}"
|
||||
with_items: "{{ docker_compose_parsed.services }}"
|
||||
|
||||
- name: Expose Redis port to allow connecting from redis-cli
|
||||
set_fact:
|
||||
docker_compose_parsed: "{{ docker_compose_parsed | combine({'services': {'redis': {'ports': ['6379:6379']}}}, recursive=True) }}"
|
||||
|
||||
- name: Write updated docker file
|
||||
copy:
|
||||
content: "{{ docker_compose_parsed | to_yaml }}"
|
||||
dest: "/home/poadocker/bridge/oracle/{{ file }}.yml"
|
||||
@@ -1,33 +1,22 @@
|
||||
---
|
||||
- name: Overwrite Oracle the docker-compose
|
||||
- name: Prepare Oracle for ultimate tests
|
||||
hosts: oracle
|
||||
become: true
|
||||
tasks:
|
||||
- name: stop the service
|
||||
shell: service poabridge stop
|
||||
|
||||
- name: ReTag current oracle image
|
||||
shell: docker tag $(docker images --format '{{ '{{' }}.Repository{{ '}}' }}:{{ '{{' }}.Tag{{ '}}' }}' | grep -m 1 tokenbridge-e2e-oracle) oracle:ultimate-testing
|
||||
- name: Connect parity to oracle networks
|
||||
shell: "docker network create {{ item }} && docker network connect {{ item }} parity1 && docker network connect {{ item }} parity2"
|
||||
with_items:
|
||||
- oracle_net_db_bridge_request
|
||||
- oracle_net_db_bridge_collected
|
||||
- oracle_net_db_bridge_affirmation
|
||||
- oracle_net_db_bridge_transfer
|
||||
- oracle_net_db_bridge_senderhome
|
||||
- oracle_net_db_bridge_senderforeign
|
||||
- oracle_net_rabbit_bridge_request
|
||||
- oracle_net_rabbit_bridge_collected
|
||||
- oracle_net_rabbit_bridge_affirmation
|
||||
- oracle_net_rabbit_bridge_transfer
|
||||
- oracle_net_rabbit_bridge_senderhome
|
||||
- oracle_net_rabbit_bridge_senderforeign
|
||||
delegate_to: 127.0.0.1
|
||||
become: false
|
||||
|
||||
- name: Replace oracle image
|
||||
replace:
|
||||
path: "/home/poadocker/bridge/oracle/{{ item }}.yml"
|
||||
regexp: 'poanetwork/tokenbridge-oracle:latest'
|
||||
replace: "oracle:ultimate-testing"
|
||||
with_items:
|
||||
- docker-compose
|
||||
- docker-compose-transfer
|
||||
- docker-compose-erc-native
|
||||
|
||||
- include_tasks: oracle-add-docker-external-network.yml
|
||||
with_items:
|
||||
- docker-compose
|
||||
- docker-compose-transfer
|
||||
- docker-compose-erc-native
|
||||
loop_control:
|
||||
loop_var: file
|
||||
|
||||
- name: start the service
|
||||
shell: service poabridge start
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
---
|
||||
- name: Overwrite UI the docker-compose
|
||||
hosts: ui
|
||||
become: true
|
||||
tasks:
|
||||
- name: stop the service
|
||||
shell: service tokenbridge-ui stop
|
||||
|
||||
- name: Slurp docker compose file
|
||||
slurp:
|
||||
src: "/home/poadocker/bridge/ui/docker-compose.yml"
|
||||
register: docker_compose_slurp
|
||||
- name: Parse docker compose file
|
||||
set_fact:
|
||||
docker_compose_parsed: "{{ docker_compose_slurp['content'] | b64decode | from_yaml }}"
|
||||
|
||||
- name: Add the external network used to connect to Parity nodes
|
||||
set_fact:
|
||||
docker_compose_parsed: "{{ docker_compose_parsed |combine({'networks': {'ultimate': {'external': 'true'}}}, recursive=True) }}"
|
||||
|
||||
- name: Add all UI containers to the network
|
||||
set_fact:
|
||||
docker_compose_parsed: "{{ docker_compose_parsed | combine({'services': {item: {'networks': ['ultimate']}}}, recursive=True) }}"
|
||||
with_items: "{{ docker_compose_parsed.services }}"
|
||||
|
||||
- name: Write new docker-compose file
|
||||
copy:
|
||||
content: "{{ docker_compose_parsed | to_yaml }}"
|
||||
dest: "/home/poadocker/bridge/ui/docker-compose.yml"
|
||||
|
||||
- name: start the service
|
||||
shell: service tokenbridge-ui start
|
||||
@@ -32,8 +32,6 @@ provisioner:
|
||||
inventory:
|
||||
host_vars:
|
||||
oracle-erc-to-erc-host:
|
||||
COMMON_HOME_RPC_URL: "http://parity1:8545"
|
||||
COMMON_FOREIGN_RPC_URL: "http://parity2:8545"
|
||||
ORACLE_VALIDATOR_ADDRESS: "0xaaB52d66283F7A1D5978bcFcB55721ACB467384b"
|
||||
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
|
||||
ui-erc-to-erc-host:
|
||||
|
||||
@@ -32,8 +32,6 @@ provisioner:
|
||||
inventory:
|
||||
host_vars:
|
||||
oracle-erc-to-native-host:
|
||||
COMMON_HOME_RPC_URL: "http://parity1:8545"
|
||||
COMMON_FOREIGN_RPC_URL: "http://parity2:8545"
|
||||
ORACLE_VALIDATOR_ADDRESS: "0xaaB52d66283F7A1D5978bcFcB55721ACB467384b"
|
||||
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
|
||||
ORACLE_HOME_START_BLOCK: 1
|
||||
|
||||
@@ -32,8 +32,6 @@ provisioner:
|
||||
inventory:
|
||||
host_vars:
|
||||
oracle-native-to-erc-host:
|
||||
COMMON_HOME_RPC_URL: "http://parity1:8545"
|
||||
COMMON_FOREIGN_RPC_URL: "http://parity2:8545"
|
||||
ORACLE_VALIDATOR_ADDRESS: "0xaaB52d66283F7A1D5978bcFcB55721ACB467384b"
|
||||
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
|
||||
ui-native-to-erc-host:
|
||||
|
||||
@@ -5,13 +5,13 @@ ORACLE_ALLOW_HTTP_FOR_RPC: yes
|
||||
ORACLE_LOG_LEVEL: debug
|
||||
|
||||
## Home contract
|
||||
COMMON_HOME_RPC_URL: "https://sokol.poa.network"
|
||||
COMMON_HOME_RPC_URL: "http://parity1:8545"
|
||||
UI_HOME_NETWORK_DISPLAY_NAME: "POA Sokol"
|
||||
UI_HOME_WITHOUT_EVENTS: false
|
||||
ORACLE_HOME_RPC_POLLING_INTERVAL: 5000
|
||||
|
||||
## Foreign contract
|
||||
COMMON_FOREIGN_RPC_URL: "https://sokol.poa.network"
|
||||
COMMON_FOREIGN_RPC_URL: "http://parity2:8545"
|
||||
UI_FOREIGN_NETWORK_DISPLAY_NAME: "Kovan"
|
||||
UI_FOREIGN_WITHOUT_EVENTS: false
|
||||
ORACLE_FOREIGN_RPC_POLLING_INTERVAL: 1000
|
||||
@@ -52,3 +52,7 @@ MONITOR_FOREIGN_START_BLOCK: 0
|
||||
MONITOR_VALIDATOR_HOME_TX_LIMIT: 300000
|
||||
MONITOR_VALIDATOR_FOREIGN_TX_LIMIT: 300000
|
||||
MONITOR_TX_NUMBER_THRESHOLD: 100
|
||||
|
||||
# disable building and pulling of docker images from the Docker Hub
|
||||
skip_pull: true
|
||||
skip_build: true
|
||||
|
||||
@@ -3,3 +3,4 @@
|
||||
shell: docker-compose pull
|
||||
args:
|
||||
chdir: "{{ bridge_path }}/monitor"
|
||||
when: skip_pull is undefined
|
||||
|
||||
@@ -3,3 +3,4 @@
|
||||
shell: docker-compose pull
|
||||
args:
|
||||
chdir: "{{ bridge_path }}/oracle"
|
||||
when: skip_pull is undefined
|
||||
|
||||
@@ -3,3 +3,4 @@
|
||||
shell: docker-compose build
|
||||
args:
|
||||
chdir: "{{ bridge_path }}/ui"
|
||||
when: skip_build is undefined
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
0xc9e38bfdB9c635F0796ad83CC8705dc379F41c04
|
||||
0xc9e38bfdB9c635F0796ad83CC8705dc379F41c04
|
||||
0x612E8bd50A7b1F009F43f2b8679E9B8eD91eb5CE
|
||||
|
||||
@@ -23,3 +23,4 @@ ORACLE_FOREIGN_RPC_POLLING_INTERVAL=500
|
||||
ORACLE_ALLOW_HTTP_FOR_RPC=yes
|
||||
ORACLE_HOME_START_BLOCK=1
|
||||
ORACLE_FOREIGN_START_BLOCK=1
|
||||
ORACLE_HOME_TO_FOREIGN_BLOCK_LIST=/mono/oracle/access-lists/block_list.txt
|
||||
|
||||
@@ -19,5 +19,5 @@ COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE=standard
|
||||
COMMON_FOREIGN_GAS_PRICE_FALLBACK=5000000000
|
||||
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL=15000
|
||||
COMMON_FOREIGN_GAS_PRICE_FACTOR=1
|
||||
UI_PORT=3000
|
||||
UI_PORT=3003
|
||||
UI_STYLES=stake
|
||||
|
||||
@@ -19,5 +19,5 @@ COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE=standard
|
||||
COMMON_FOREIGN_GAS_PRICE_FALLBACK=5000000000
|
||||
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL=15000
|
||||
COMMON_FOREIGN_GAS_PRICE_FACTOR=1
|
||||
UI_PORT=3000
|
||||
UI_PORT=3002
|
||||
UI_STYLES=core
|
||||
|
||||
@@ -19,5 +19,5 @@ COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE=standard
|
||||
COMMON_FOREIGN_GAS_PRICE_FALLBACK=5000000000
|
||||
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL=15000
|
||||
COMMON_FOREIGN_GAS_PRICE_FACTOR=1
|
||||
UI_PORT=3000
|
||||
UI_PORT=3001
|
||||
UI_STYLES=core
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
"foreign": "0x0AEe1FCD12dDFab6265F7f8956e6E012A9Fe4Aa0",
|
||||
"homeBox": "0x6C4EaAb8756d53Bf599FFe2347FAFF1123D6C8A1",
|
||||
"foreignBox": "0x6C4EaAb8756d53Bf599FFe2347FAFF1123D6C8A1",
|
||||
"blockedHomeBox": "0x612E8bd50A7b1F009F43f2b8679E9B8eD91eb5CE",
|
||||
"monitor": "http://monitor-amb:3013/bridge"
|
||||
},
|
||||
"ambStakeErcToErc": {
|
||||
|
||||
@@ -4,12 +4,14 @@ networks:
|
||||
external: true
|
||||
services:
|
||||
parity1:
|
||||
container_name: parity1
|
||||
build: ../parity
|
||||
ports:
|
||||
- "8541:8545"
|
||||
networks:
|
||||
- ultimate
|
||||
parity2:
|
||||
container_name: parity2
|
||||
build:
|
||||
context: ../parity
|
||||
dockerfile: Dockerfile-foreign
|
||||
@@ -61,6 +63,9 @@ services:
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
command: "true"
|
||||
volumes:
|
||||
- '../e2e-commons/access-lists/block_list.txt:/mono/oracle/access-lists/block_list.txt'
|
||||
- '../e2e-commons/access-lists/allowance_list.txt:/mono/oracle/access-lists/allowance_list.txt'
|
||||
networks:
|
||||
- ultimate
|
||||
ui:
|
||||
|
||||
@@ -53,3 +53,8 @@ node deploy.js
|
||||
cd - > /dev/null
|
||||
node setupStakeTokens.js
|
||||
cd - > /dev/null
|
||||
|
||||
echo -e "\n\n############ Deploying one more test contract for amb ############\n"
|
||||
cd "$DEPLOY_PATH"
|
||||
node src/utils/deployTestBox.js
|
||||
cd - > /dev/null
|
||||
|
||||
@@ -17,21 +17,29 @@ docker-compose up -d parity1 parity2 e2e
|
||||
startValidator () {
|
||||
docker-compose $1 run -d --name $4 redis
|
||||
docker-compose $1 run -d --name $5 rabbit
|
||||
docker-compose $1 run $2 $3 -d oracle yarn watcher:signature-request
|
||||
docker-compose $1 run $2 $3 -d oracle yarn watcher:collected-signatures
|
||||
docker-compose $1 run $2 $3 -d oracle yarn watcher:affirmation-request
|
||||
docker-compose $1 run $2 $3 -d oracle-erc20 yarn watcher:signature-request
|
||||
docker-compose $1 run $2 $3 -d oracle-erc20 yarn watcher:collected-signatures
|
||||
docker-compose $1 run $2 $3 -d oracle-erc20 yarn watcher:affirmation-request
|
||||
docker-compose $1 run $2 $3 -d oracle-erc20 yarn watcher:transfer
|
||||
docker-compose $1 run $2 $3 -d oracle-erc20-native yarn watcher:signature-request
|
||||
docker-compose $1 run $2 $3 -d oracle-erc20-native yarn watcher:collected-signatures
|
||||
docker-compose $1 run $2 $3 -d oracle-erc20-native yarn watcher:affirmation-request
|
||||
docker-compose $1 run $2 $3 -d oracle-erc20-native yarn watcher:transfer
|
||||
docker-compose $1 run $2 $3 -d oracle-erc20-native yarn worker:convert-to-chai
|
||||
docker-compose $1 run $2 $3 -d oracle-amb yarn watcher:signature-request
|
||||
docker-compose $1 run $2 $3 -d oracle-amb yarn watcher:collected-signatures
|
||||
docker-compose $1 run $2 $3 -d oracle-amb yarn watcher:affirmation-request
|
||||
if [[ -z "$MODE" || "$MODE" == native-to-erc ]]; then
|
||||
docker-compose $1 run $2 $3 -d oracle yarn watcher:signature-request
|
||||
docker-compose $1 run $2 $3 -d oracle yarn watcher:collected-signatures
|
||||
docker-compose $1 run $2 $3 -d oracle yarn watcher:affirmation-request
|
||||
fi
|
||||
if [[ -z "$MODE" || "$MODE" == erc-to-erc ]]; then
|
||||
docker-compose $1 run $2 $3 -d oracle-erc20 yarn watcher:signature-request
|
||||
docker-compose $1 run $2 $3 -d oracle-erc20 yarn watcher:collected-signatures
|
||||
docker-compose $1 run $2 $3 -d oracle-erc20 yarn watcher:affirmation-request
|
||||
docker-compose $1 run $2 $3 -d oracle-erc20 yarn watcher:transfer
|
||||
fi
|
||||
if [[ -z "$MODE" || "$MODE" == erc-to-native ]]; then
|
||||
docker-compose $1 run $2 $3 -d oracle-erc20-native yarn watcher:signature-request
|
||||
docker-compose $1 run $2 $3 -d oracle-erc20-native yarn watcher:collected-signatures
|
||||
docker-compose $1 run $2 $3 -d oracle-erc20-native yarn watcher:affirmation-request
|
||||
docker-compose $1 run $2 $3 -d oracle-erc20-native yarn watcher:transfer
|
||||
docker-compose $1 run $2 $3 -d oracle-erc20-native yarn worker:convert-to-chai
|
||||
fi
|
||||
if [[ -z "$MODE" || "$MODE" == amb ]]; then
|
||||
docker-compose $1 run $2 $3 -d oracle-amb yarn watcher:signature-request
|
||||
docker-compose $1 run $2 $3 -d oracle-amb yarn watcher:collected-signatures
|
||||
docker-compose $1 run $2 $3 -d oracle-amb yarn watcher:affirmation-request
|
||||
fi
|
||||
docker-compose $1 run $2 $3 -d oracle-erc20-native yarn sender:home
|
||||
docker-compose $1 run $2 $3 -d oracle-erc20-native yarn sender:foreign
|
||||
}
|
||||
@@ -48,25 +56,7 @@ startAMBValidator () {
|
||||
|
||||
while [ "$1" != "" ]; do
|
||||
if [ "$1" == "oracle" ]; then
|
||||
docker-compose up -d redis rabbit
|
||||
|
||||
docker-compose run -d oracle yarn watcher:signature-request
|
||||
docker-compose run -d oracle yarn watcher:collected-signatures
|
||||
docker-compose run -d oracle yarn watcher:affirmation-request
|
||||
docker-compose run -d oracle-erc20 yarn watcher:signature-request
|
||||
docker-compose run -d oracle-erc20 yarn watcher:collected-signatures
|
||||
docker-compose run -d oracle-erc20 yarn watcher:affirmation-request
|
||||
docker-compose run -d oracle-erc20 yarn watcher:transfer
|
||||
docker-compose run -d oracle-erc20-native yarn watcher:signature-request
|
||||
docker-compose run -d oracle-erc20-native yarn watcher:collected-signatures
|
||||
docker-compose run -d oracle-erc20-native yarn watcher:affirmation-request
|
||||
docker-compose run -d oracle-erc20-native yarn watcher:transfer
|
||||
docker-compose run -d oracle-erc20-native yarn worker:convert-to-chai
|
||||
docker-compose run -d oracle-amb yarn watcher:signature-request
|
||||
docker-compose run -d oracle-amb yarn watcher:collected-signatures
|
||||
docker-compose run -d oracle-amb yarn watcher:affirmation-request
|
||||
docker-compose run -d oracle yarn sender:home
|
||||
docker-compose run -d oracle yarn sender:foreign
|
||||
startValidator "" "" "" "redis" "rabbit"
|
||||
fi
|
||||
|
||||
if [ "$1" == "oracle-validator-2" ]; then
|
||||
@@ -90,9 +80,9 @@ while [ "$1" != "" ]; do
|
||||
docker-compose up -d ui ui-erc20 ui-erc20-native ui-amb-stake-erc20-erc20
|
||||
|
||||
docker-compose run -d -p 3000:3000 ui yarn start
|
||||
docker-compose run -d -p 3001:3000 ui-erc20 yarn start
|
||||
docker-compose run -d -p 3002:3000 ui-erc20-native yarn start
|
||||
docker-compose run -d -p 3003:3000 ui-amb-stake-erc20-erc20 yarn start
|
||||
docker-compose run -d -p 3001:3001 ui-erc20 yarn start
|
||||
docker-compose run -d -p 3002:3002 ui-erc20-native yarn start
|
||||
docker-compose run -d -p 3003:3003 ui-amb-stake-erc20-erc20 yarn start
|
||||
fi
|
||||
|
||||
if [ "$1" == "alm" ]; then
|
||||
@@ -110,7 +100,23 @@ while [ "$1" != "" ]; do
|
||||
fi
|
||||
|
||||
if [ "$1" == "monitor" ]; then
|
||||
docker-compose up -d monitor monitor-erc20 monitor-erc20-native monitor-amb
|
||||
case "$MODE" in
|
||||
amb)
|
||||
docker-compose up -d monitor-amb
|
||||
;;
|
||||
native-to-erc)
|
||||
docker-compose up -d monitor
|
||||
;;
|
||||
erc-to-erc)
|
||||
docker-compose up -d monitor-erc20
|
||||
;;
|
||||
erc-to-native)
|
||||
docker-compose up -d monitor-erc20-native
|
||||
;;
|
||||
*)
|
||||
docker-compose up -d monitor monitor-erc20 monitor-erc20-native monitor-amb
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if [ "$1" == "alm-e2e" ]; then
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
while true; do
|
||||
sleep 5
|
||||
docker-compose -f ../e2e-commons/docker-compose.yml exec -d monitor yarn check-all
|
||||
docker-compose -f ../e2e-commons/docker-compose.yml exec -d monitor-erc20 yarn check-all
|
||||
docker-compose -f ../e2e-commons/docker-compose.yml exec -d monitor-erc20-native yarn check-all
|
||||
docker-compose -f ../e2e-commons/docker-compose.yml exec -d monitor-amb yarn check-all
|
||||
docker-compose -f ../e2e-commons/docker-compose.yml exec -T monitor yarn check-all
|
||||
pid1=$!
|
||||
docker-compose -f ../e2e-commons/docker-compose.yml exec -T monitor-erc20 yarn check-all
|
||||
pid2=$!
|
||||
docker-compose -f ../e2e-commons/docker-compose.yml exec -T monitor-erc20-native yarn check-all
|
||||
pid3=$!
|
||||
docker-compose -f ../e2e-commons/docker-compose.yml exec -T monitor-amb yarn check-all
|
||||
pid4=$!
|
||||
|
||||
wait $pid1
|
||||
wait $pid2
|
||||
wait $pid3
|
||||
wait $pid4
|
||||
done
|
||||
|
||||
@@ -1,12 +1,28 @@
|
||||
cd $(dirname $0)
|
||||
|
||||
../e2e-commons/up.sh deploy blocks monitor
|
||||
mode="$1"
|
||||
case "$mode" in
|
||||
amb)
|
||||
script=./test/amb.js
|
||||
;;
|
||||
native-to-erc)
|
||||
script=./test/nativeToErc.js
|
||||
;;
|
||||
erc-to-erc)
|
||||
script=./test/ercToErc.js
|
||||
;;
|
||||
erc-to-native)
|
||||
script=./test/ercToNative.js
|
||||
;;
|
||||
esac
|
||||
|
||||
./wait-for-monitor.sh
|
||||
MODE="$mode" ../e2e-commons/up.sh deploy blocks monitor
|
||||
|
||||
MODE="$mode" ./wait-for-monitor.sh
|
||||
nohup ./periodically-check-all.sh < /dev/null > /dev/null 2>&1 &
|
||||
checkPID=$!
|
||||
|
||||
docker-compose -f ../e2e-commons/docker-compose.yml run e2e yarn workspace monitor-e2e run start
|
||||
docker-compose -f ../e2e-commons/docker-compose.yml run e2e yarn workspace monitor-e2e run start $script
|
||||
rc=$?
|
||||
|
||||
../e2e-commons/down.sh
|
||||
|
||||
@@ -25,6 +25,7 @@ describe('AMB', () => {
|
||||
|
||||
describe('general', async () => {
|
||||
it('should contain fromHomeToForeignDiff', () => assert(data.fromHomeToForeignDiff === 0))
|
||||
it('should contain fromHomeToForeignPBUDiff', () => assert(data.fromHomeToForeignPBUDiff === 0))
|
||||
it('should contain fromForeignToHomeDiff', () => assert(data.fromForeignToHomeDiff === 0))
|
||||
it('should contain lastChecked', () => assert(data.lastChecked >= 0))
|
||||
it('should contain timeDiff', () => assert(data.timeDiff >= 0))
|
||||
@@ -114,7 +115,16 @@ describe('AMB', () => {
|
||||
|
||||
await waitUntil(async () => {
|
||||
;({ data } = await axios.get(`${baseUrl}`))
|
||||
return data.fromHomeToForeignDiff !== 0
|
||||
return data.fromHomeToForeignDiff === 1 && data.fromHomeToForeignPBUDiff === 0
|
||||
})
|
||||
})
|
||||
it('should change fromHomeToForeignPBUDiff', async () => {
|
||||
// send message
|
||||
await sendAMBMessage(homeRPC.URL, user, amb.homeBox, amb.home, amb.foreignBox, true)
|
||||
|
||||
await waitUntil(async () => {
|
||||
;({ data } = await axios.get(`${baseUrl}`))
|
||||
return data.fromHomeToForeignDiff === 1 && data.fromHomeToForeignPBUDiff === 1
|
||||
})
|
||||
})
|
||||
it('should change validatorsMatch', async () => {
|
||||
|
||||
@@ -54,16 +54,16 @@ describe('ERC TO NATIVE with changing state of contracts', () => {
|
||||
})
|
||||
|
||||
it('should consider chai token balance', async function() {
|
||||
this.timeout(60000)
|
||||
this.timeout(120000)
|
||||
await initializeChaiToken(foreignRPC.URL, ercToNativeBridge.foreign)
|
||||
await sendTokens(foreignRPC.URL, user, ercToNativeBridge.foreignToken, ercToNativeBridge.foreign)
|
||||
|
||||
await waitUntil(async () => {
|
||||
;({ data } = await axios.get(`${baseUrl}`))
|
||||
const { erc20Balance, investedErc20Balance, accumulatedInterest } = data.foreign
|
||||
if (!data.foreign) {
|
||||
return false
|
||||
}
|
||||
const { erc20Balance, investedErc20Balance, accumulatedInterest } = data.foreign
|
||||
return (
|
||||
data.balanceDiff === 0.02 &&
|
||||
erc20Balance === '0.02' &&
|
||||
@@ -77,10 +77,10 @@ describe('ERC TO NATIVE with changing state of contracts', () => {
|
||||
|
||||
await waitUntil(async () => {
|
||||
;({ data } = await axios.get(`${baseUrl}`))
|
||||
const { erc20Balance, investedErc20Balance, accumulatedInterest } = data.foreign
|
||||
if (!data.foreign) {
|
||||
return false
|
||||
}
|
||||
const { erc20Balance, investedErc20Balance, accumulatedInterest } = data.foreign
|
||||
return (
|
||||
data.balanceDiff === 0.02 &&
|
||||
erc20Balance === '0.01' &&
|
||||
@@ -94,10 +94,10 @@ describe('ERC TO NATIVE with changing state of contracts', () => {
|
||||
|
||||
await waitUntil(async () => {
|
||||
;({ data } = await axios.get(`${baseUrl}`))
|
||||
const { erc20Balance, investedErc20Balance, accumulatedInterest } = data.foreign
|
||||
if (!data.foreign) {
|
||||
return false
|
||||
}
|
||||
const { erc20Balance, investedErc20Balance, accumulatedInterest } = data.foreign
|
||||
return (
|
||||
data.balanceDiff === 0.02 &&
|
||||
erc20Balance === '0.005' &&
|
||||
|
||||
@@ -44,12 +44,16 @@ const sendTokens = async (rpcUrl, account, tokenAddress, recipientAddress) => {
|
||||
})
|
||||
}
|
||||
|
||||
const sendAMBMessage = async (rpcUrl, account, boxAddress, bridgeAddress, boxOtherSideAddress) => {
|
||||
const sendAMBMessage = async (rpcUrl, account, boxAddress, bridgeAddress, boxOtherSideAddress, manualLane = false) => {
|
||||
const web3 = new Web3(new Web3.providers.HttpProvider(rpcUrl))
|
||||
web3.eth.accounts.wallet.add(account.privateKey)
|
||||
const homeBox = new web3.eth.Contract(BOX_ABI, boxAddress)
|
||||
|
||||
await homeBox.methods.setValueOnOtherNetwork(3, bridgeAddress, boxOtherSideAddress).send({
|
||||
await homeBox.methods[manualLane ? 'setValueOnOtherNetworkUsingManualLane' : 'setValueOnOtherNetwork'](
|
||||
3,
|
||||
bridgeAddress,
|
||||
boxOtherSideAddress
|
||||
).send({
|
||||
from: account.address,
|
||||
gas: '400000'
|
||||
})
|
||||
|
||||
@@ -6,10 +6,18 @@ check_files_exist() {
|
||||
rc=0
|
||||
for f in "${FILES[@]}"; do
|
||||
command="test -f responses/bridge/$f"
|
||||
(docker-compose -f ../e2e-commons/docker-compose.yml exec -T monitor /bin/bash -c "$command") || rc=1
|
||||
(docker-compose -f ../e2e-commons/docker-compose.yml exec -T monitor-erc20 /bin/bash -c "$command") || rc=1
|
||||
(docker-compose -f ../e2e-commons/docker-compose.yml exec -T monitor-erc20-native /bin/bash -c "$command") || rc=1
|
||||
(docker-compose -f ../e2e-commons/docker-compose.yml exec -T monitor-amb /bin/bash -c "$command") || rc=1
|
||||
if [[ -z "$MODE" || "$MODE" == native-to-erc ]]; then
|
||||
(docker-compose -f ../e2e-commons/docker-compose.yml exec -T monitor /bin/bash -c "$command") || rc=1
|
||||
fi
|
||||
if [[ -z "$MODE" || "$MODE" == erc-to-erc ]]; then
|
||||
(docker-compose -f ../e2e-commons/docker-compose.yml exec -T monitor-erc20 /bin/bash -c "$command") || rc=1
|
||||
fi
|
||||
if [[ -z "$MODE" || "$MODE" == erc-to-native ]]; then
|
||||
(docker-compose -f ../e2e-commons/docker-compose.yml exec -T monitor-erc20-native /bin/bash -c "$command") || rc=1
|
||||
fi
|
||||
if [[ -z "$MODE" || "$MODE" == amb ]]; then
|
||||
(docker-compose -f ../e2e-commons/docker-compose.yml exec -T monitor-amb /bin/bash -c "$command") || rc=1
|
||||
fi
|
||||
done
|
||||
return $rc
|
||||
}
|
||||
|
||||
@@ -22,3 +22,9 @@ COMMON_FOREIGN_GAS_PRICE_FACTOR=1
|
||||
MONITOR_TX_NUMBER_THRESHOLD=100
|
||||
MONITOR_PORT=3003
|
||||
MONITOR_CACHE_EVENTS=true
|
||||
|
||||
MONITOR_HOME_TO_FOREIGN_ALLOWANCE_LIST=
|
||||
MONITOR_HOME_TO_FOREIGN_BLOCK_LIST=
|
||||
|
||||
# MONITOR_HOME_VALIDATORS_BALANCE_ENABLE=0x... 0x... 0x...
|
||||
# MONITOR_FOREIGN_VALIDATORS_BALANCE_ENABLE=0x... 0x... 0x...
|
||||
|
||||
@@ -1,18 +1,9 @@
|
||||
require('dotenv').config()
|
||||
const Web3 = require('web3')
|
||||
const logger = require('./logger')('alerts')
|
||||
const eventsInfo = require('./utils/events')
|
||||
const { getBlockNumber } = require('./utils/contract')
|
||||
const { processedMsgNotDelivered, eventWithoutReference } = require('./utils/message')
|
||||
const { BRIDGE_MODES } = require('../commons')
|
||||
|
||||
const { COMMON_HOME_RPC_URL, COMMON_FOREIGN_RPC_URL } = process.env
|
||||
|
||||
const homeProvider = new Web3.providers.HttpProvider(COMMON_HOME_RPC_URL)
|
||||
const web3Home = new Web3(homeProvider)
|
||||
|
||||
const foreignProvider = new Web3.providers.HttpProvider(COMMON_FOREIGN_RPC_URL)
|
||||
const web3Foreign = new Web3(foreignProvider)
|
||||
const { web3Home, web3Foreign, getHomeBlockNumber, getForeignBlockNumber } = require('./utils/web3')
|
||||
|
||||
async function main() {
|
||||
const {
|
||||
@@ -33,7 +24,8 @@ async function main() {
|
||||
xAffirmations = foreignToHomeConfirmations.filter(eventWithoutReference(foreignToHomeRequests))
|
||||
}
|
||||
logger.debug('building misbehavior blocks')
|
||||
const [homeBlockNumber, foreignBlockNumber] = await getBlockNumber(web3Home, web3Foreign)
|
||||
const homeBlockNumber = await getHomeBlockNumber()
|
||||
const foreignBlockNumber = await getForeignBlockNumber()
|
||||
|
||||
const baseRange = [false, false, false, false, false]
|
||||
const xSignaturesMisbehavior = buildRangesObject(
|
||||
@@ -73,21 +65,21 @@ async function main() {
|
||||
|
||||
/**
|
||||
* Finds the location for the blockNumber in a specific range starting from currentBlockNumber
|
||||
* @param {BN} currentBlockNumber
|
||||
* @param {Number} currentBlockNumber
|
||||
* @returns {function({blockNumber?: *}): boolean[]}
|
||||
*/
|
||||
const findMisbehaviorRange = currentBlockNumber => ({ blockNumber }) => {
|
||||
const minus60 = currentBlockNumber.sub(Web3.utils.toBN(60))
|
||||
const minus180 = currentBlockNumber.sub(Web3.utils.toBN(180))
|
||||
const minus720 = currentBlockNumber.sub(Web3.utils.toBN(720))
|
||||
const minus17280 = currentBlockNumber.sub(Web3.utils.toBN(17280))
|
||||
const minus60 = currentBlockNumber - 60
|
||||
const minus180 = currentBlockNumber - 180
|
||||
const minus720 = currentBlockNumber - 720
|
||||
const minus17280 = currentBlockNumber - 17280
|
||||
|
||||
return [
|
||||
minus60.lte(blockNumber),
|
||||
minus180.lte(blockNumber) && minus60.gt(blockNumber),
|
||||
minus720.lte(blockNumber) && minus180.gt(blockNumber),
|
||||
minus17280.lte(blockNumber) && minus720.gt(blockNumber),
|
||||
minus17280.gt(blockNumber)
|
||||
minus60 <= blockNumber,
|
||||
minus180 <= blockNumber && minus60 > blockNumber,
|
||||
minus720 <= blockNumber && minus180 > blockNumber,
|
||||
minus17280 <= blockNumber && minus720 > blockNumber,
|
||||
minus17280 > blockNumber
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
0
monitor/cache/.gitkeep
vendored
Normal file
0
monitor/cache/.gitkeep
vendored
Normal file
@@ -1,20 +1,16 @@
|
||||
require('dotenv').config()
|
||||
const Web3 = require('web3')
|
||||
const BN = require('bignumber.js')
|
||||
const logger = require('./logger')('checkWorker')
|
||||
const { getBridgeMode } = require('../commons')
|
||||
const getBalances = require('./getBalances')
|
||||
const getShortEventStats = require('./getShortEventStats')
|
||||
const validators = require('./validators')
|
||||
const getEventsInfo = require('./utils/events')
|
||||
const { writeFile, createDir } = require('./utils/file')
|
||||
const { saveCache } = require('./utils/web3Cache')
|
||||
const { web3Home } = require('./utils/web3')
|
||||
|
||||
const { COMMON_HOME_BRIDGE_ADDRESS, COMMON_HOME_RPC_URL, MONITOR_BRIDGE_NAME } = process.env
|
||||
|
||||
const MONITOR_VALIDATOR_HOME_TX_LIMIT = Number(process.env.MONITOR_VALIDATOR_HOME_TX_LIMIT) || 0
|
||||
const MONITOR_VALIDATOR_FOREIGN_TX_LIMIT = Number(process.env.MONITOR_VALIDATOR_FOREIGN_TX_LIMIT) || 0
|
||||
const MONITOR_TX_NUMBER_THRESHOLD = Number(process.env.MONITOR_TX_NUMBER_THRESHOLD) || 100
|
||||
|
||||
const homeProvider = new Web3.providers.HttpProvider(COMMON_HOME_RPC_URL)
|
||||
const web3Home = new Web3(homeProvider)
|
||||
const { COMMON_HOME_BRIDGE_ADDRESS, MONITOR_BRIDGE_NAME } = process.env
|
||||
|
||||
const { HOME_ERC_TO_ERC_ABI } = require('../commons')
|
||||
|
||||
@@ -24,42 +20,27 @@ async function checkWorker() {
|
||||
const homeBridge = new web3Home.eth.Contract(HOME_ERC_TO_ERC_ABI, COMMON_HOME_BRIDGE_ADDRESS)
|
||||
const bridgeMode = await getBridgeMode(homeBridge)
|
||||
logger.debug('Bridge mode:', bridgeMode)
|
||||
logger.debug('calling getEventsInfo()')
|
||||
const eventsInfo = await getEventsInfo(bridgeMode)
|
||||
logger.debug('calling getBalances()')
|
||||
const balances = await getBalances(bridgeMode)
|
||||
const balances = await getBalances(bridgeMode, eventsInfo)
|
||||
logger.debug('calling getShortEventStats()')
|
||||
const events = await getShortEventStats(bridgeMode)
|
||||
const events = await getShortEventStats(bridgeMode, eventsInfo)
|
||||
const home = Object.assign({}, balances.home, events.home)
|
||||
const foreign = Object.assign({}, balances.foreign, events.foreign)
|
||||
const status = Object.assign({}, balances, events, { home }, { foreign })
|
||||
if (status.balanceDiff && status.unclaimedBalance) {
|
||||
status.balanceDiff = new BN(status.balanceDiff).minus(status.unclaimedBalance).toFixed()
|
||||
}
|
||||
if (!status) throw new Error('status is empty: ' + JSON.stringify(status))
|
||||
status.health = true
|
||||
writeFile(`/responses/${MONITOR_BRIDGE_NAME}/getBalances.json`, status)
|
||||
saveCache()
|
||||
|
||||
logger.debug('calling validators()')
|
||||
const vBalances = await validators(bridgeMode)
|
||||
if (!vBalances) throw new Error('vBalances is empty: ' + JSON.stringify(vBalances))
|
||||
|
||||
vBalances.homeOk = true
|
||||
vBalances.foreignOk = true
|
||||
|
||||
if (MONITOR_VALIDATOR_HOME_TX_LIMIT) {
|
||||
for (const hv in vBalances.home.validators) {
|
||||
if (vBalances.home.validators[hv].leftTx < MONITOR_TX_NUMBER_THRESHOLD) {
|
||||
vBalances.homeOk = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (MONITOR_VALIDATOR_FOREIGN_TX_LIMIT) {
|
||||
for (const hv in vBalances.foreign.validators) {
|
||||
if (vBalances.foreign.validators[hv].leftTx < MONITOR_TX_NUMBER_THRESHOLD) {
|
||||
vBalances.foreignOk = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vBalances.ok = vBalances.homeOk && vBalances.foreignOk
|
||||
vBalances.health = true
|
||||
writeFile(`/responses/${MONITOR_BRIDGE_NAME}/validators.json`, vBalances)
|
||||
|
||||
@@ -3,6 +3,7 @@ const logger = require('./logger')('checkWorker2')
|
||||
const eventsStats = require('./eventsStats')
|
||||
const alerts = require('./alerts')
|
||||
const { writeFile, createDir } = require('./utils/file')
|
||||
const { saveCache } = require('./utils/web3Cache')
|
||||
|
||||
const { MONITOR_BRIDGE_NAME } = process.env
|
||||
|
||||
@@ -26,6 +27,7 @@ async function checkWorker2() {
|
||||
_alerts.ok = !_alerts.executeAffirmations.mostRecentTxHash && !_alerts.executeSignatures.mostRecentTxHash
|
||||
_alerts.health = true
|
||||
writeFile(`/responses/${MONITOR_BRIDGE_NAME}/alerts.json`, _alerts)
|
||||
saveCache()
|
||||
logger.debug('Done x2')
|
||||
} catch (e) {
|
||||
logger.error(e)
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
require('dotenv').config()
|
||||
const Web3 = require('web3')
|
||||
const logger = require('./logger')('checkWorker3')
|
||||
const stuckTransfers = require('./stuckTransfers')
|
||||
const detectMediators = require('./detectMediators')
|
||||
const { writeFile, createDir } = require('./utils/file')
|
||||
const { web3Home } = require('./utils/web3')
|
||||
const { saveCache } = require('./utils/web3Cache')
|
||||
|
||||
const { MONITOR_BRIDGE_NAME, COMMON_HOME_BRIDGE_ADDRESS, COMMON_HOME_RPC_URL } = process.env
|
||||
const { MONITOR_BRIDGE_NAME, COMMON_HOME_BRIDGE_ADDRESS } = process.env
|
||||
const { getBridgeMode, HOME_NATIVE_TO_ERC_ABI, BRIDGE_MODES } = require('../commons')
|
||||
|
||||
const homeProvider = new Web3.providers.HttpProvider(COMMON_HOME_RPC_URL)
|
||||
const web3Home = new Web3(homeProvider)
|
||||
|
||||
async function checkWorker3() {
|
||||
try {
|
||||
const homeBridge = new web3Home.eth.Contract(HOME_NATIVE_TO_ERC_ABI, COMMON_HOME_BRIDGE_ADDRESS)
|
||||
@@ -23,6 +22,15 @@ async function checkWorker3() {
|
||||
transfers.health = true
|
||||
writeFile(`/responses/${MONITOR_BRIDGE_NAME}/stuckTransfers.json`, transfers)
|
||||
logger.debug('Done')
|
||||
} else if (bridgeMode === BRIDGE_MODES.ARBITRARY_MESSAGE) {
|
||||
createDir(`/responses/${MONITOR_BRIDGE_NAME}`)
|
||||
logger.debug('calling detectMediators()')
|
||||
const mediators = await detectMediators(bridgeMode)
|
||||
mediators.ok = true
|
||||
mediators.health = true
|
||||
writeFile(`/responses/${MONITOR_BRIDGE_NAME}/mediators.json`, mediators)
|
||||
saveCache()
|
||||
logger.debug('Done')
|
||||
}
|
||||
} catch (e) {
|
||||
logger.error('checkWorker3.js', e)
|
||||
|
||||
148
monitor/detectMediators.js
Normal file
148
monitor/detectMediators.js
Normal file
@@ -0,0 +1,148 @@
|
||||
require('dotenv').config()
|
||||
const logger = require('./logger')('stuckTransfers.js')
|
||||
const { isHomeContract, isForeignContract } = require('./utils/web3Cache')
|
||||
const eventsInfo = require('./utils/events')
|
||||
const { getHomeTxSender, getForeignTxSender } = require('./utils/web3Cache')
|
||||
const { addExecutionStatus } = require('./utils/message')
|
||||
const { normalizeAMBMessageEvent } = require('../commons')
|
||||
|
||||
function countInteractions(requests) {
|
||||
const stats = {}
|
||||
requests.forEach(msg => {
|
||||
if (!stats[msg.sender]) {
|
||||
stats[msg.sender] = {}
|
||||
}
|
||||
if (!stats[msg.sender][msg.executor]) {
|
||||
stats[msg.sender][msg.executor] = 0
|
||||
}
|
||||
stats[msg.sender][msg.executor] += 1
|
||||
})
|
||||
return stats
|
||||
}
|
||||
|
||||
const normalize = event => ({
|
||||
...normalizeAMBMessageEvent(event),
|
||||
txHash: event.transactionHash,
|
||||
logIndex: event.transactionLogIndex
|
||||
})
|
||||
|
||||
const flat = arrays => Array.prototype.concat.apply([], arrays)
|
||||
|
||||
function findPermanentMediators(homeToForeignC2C, foreignToHomeC2C) {
|
||||
return flat(
|
||||
Object.entries(homeToForeignC2C).map(([homeMediator, homeStats]) =>
|
||||
Object.entries(foreignToHomeC2C)
|
||||
.map(([foreignMediator, foreignStats]) => ({
|
||||
homeMediator,
|
||||
foreignMediator,
|
||||
homeToForeignRequests: homeStats[foreignMediator],
|
||||
foreignToHomeRequests: foreignStats[homeMediator]
|
||||
}))
|
||||
.filter(stats => stats.homeToForeignRequests && stats.foreignToHomeRequests)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
function findFloatingMediators(homeToForeignC2C, foreignToHomeC2C) {
|
||||
return Object.entries(homeToForeignC2C)
|
||||
.map(([homeMediator, homeStats]) => {
|
||||
const noResponses = ([executor]) => !foreignToHomeC2C[executor] || !foreignToHomeC2C[executor][homeMediator]
|
||||
const executorRequestPairs = Object.entries(homeStats).filter(noResponses)
|
||||
return {
|
||||
mediator: homeMediator,
|
||||
executors: executorRequestPairs.map(pair => pair[0]),
|
||||
requests: executorRequestPairs.map(pair => pair[1])
|
||||
}
|
||||
})
|
||||
.filter(stats => stats.executors.length > 0)
|
||||
}
|
||||
|
||||
function findRemotelyControlledMediators(statsU2C) {
|
||||
return Object.entries(statsU2C).map(([user, stats]) => ({
|
||||
user,
|
||||
executors: Object.keys(stats),
|
||||
requests: Object.values(stats)
|
||||
}))
|
||||
}
|
||||
|
||||
function findUnknown(statsA2U) {
|
||||
return Object.entries(statsA2U).map(([sender, stats]) => ({
|
||||
sender,
|
||||
executors: Object.keys(stats),
|
||||
requests: Object.values(stats)
|
||||
}))
|
||||
}
|
||||
|
||||
async function main(mode) {
|
||||
const {
|
||||
homeToForeignRequests,
|
||||
foreignToHomeRequests,
|
||||
homeToForeignConfirmations,
|
||||
foreignToHomeConfirmations
|
||||
} = await eventsInfo(mode)
|
||||
const homeToForeign = homeToForeignRequests
|
||||
.map(normalize)
|
||||
.map(addExecutionStatus(homeToForeignConfirmations))
|
||||
.filter(x => typeof x.status === 'boolean')
|
||||
const foreignToHome = foreignToHomeRequests
|
||||
.map(normalize)
|
||||
.map(addExecutionStatus(foreignToHomeConfirmations))
|
||||
.filter(x => typeof x.status === 'boolean')
|
||||
|
||||
for (const event of homeToForeign) {
|
||||
// AMB contract emits a single UserRequestForSignature event for every home->foreign request.
|
||||
// If index of such event in logs is not equal to 0x0, then some other events occurred before it,
|
||||
// meaning that the sender was a contract.
|
||||
// Alternatively, the sender is a contract, if the message sender is not equal to tx.origin.
|
||||
event.isSenderAContract = event.logIndex !== '0x0' || (await getHomeTxSender(event.txHash)) !== event.sender
|
||||
|
||||
// Executor is definitely a contract if a message execution failed, since message calls to EOA always succeed.
|
||||
// Alternatively, the executor is checked to be a contract by looking at its bytecode size.
|
||||
event.isExecutorAContract = !event.status || (await isForeignContract(event.executor))
|
||||
}
|
||||
for (const event of foreignToHome) {
|
||||
// AMB contract emits a single UserRequestForAffirmation event for every foreign->home request.
|
||||
// If index of such event in logs is not equal to 0x0, then some other events occurred before it,
|
||||
// meaning that the sender was a contract.
|
||||
// Alternatively, the sender is a contract, if the message sender is not equal to tx.origin.
|
||||
event.isSenderAContract = event.logIndex !== '0x0' || (await getForeignTxSender(event.txHash)) !== event.sender
|
||||
|
||||
// Executor is definitely a contract if a message execution failed, since message calls to EOA always succeed.
|
||||
// Alternatively, the executor is checked to be a contract by looking at its bytecode size.
|
||||
event.isExecutorAContract = !event.status || (await isHomeContract(event.executor))
|
||||
}
|
||||
const C2C = event => event.isSenderAContract && event.isExecutorAContract
|
||||
const U2C = event => !event.isSenderAContract && event.isExecutorAContract
|
||||
const A2U = event => !event.isExecutorAContract
|
||||
|
||||
const homeToForeignC2C = countInteractions(homeToForeign.filter(C2C))
|
||||
const foreignToHomeC2C = countInteractions(foreignToHome.filter(C2C))
|
||||
const homeToForeignU2C = countInteractions(homeToForeign.filter(U2C))
|
||||
const foreignToHomeU2C = countInteractions(foreignToHome.filter(U2C))
|
||||
const homeToForeignA2U = countInteractions(homeToForeign.filter(A2U))
|
||||
const foreignToHomeA2U = countInteractions(foreignToHome.filter(A2U))
|
||||
|
||||
const permanentMediators = findPermanentMediators(homeToForeignC2C, foreignToHomeC2C)
|
||||
const floatingMediators = {
|
||||
home: findFloatingMediators(homeToForeignC2C, foreignToHomeC2C),
|
||||
foreign: findFloatingMediators(foreignToHomeC2C, homeToForeignC2C)
|
||||
}
|
||||
const remotelyControlledMediators = {
|
||||
home: findRemotelyControlledMediators(homeToForeignU2C),
|
||||
foreign: findRemotelyControlledMediators(foreignToHomeU2C)
|
||||
}
|
||||
const unknown = {
|
||||
home: findUnknown(homeToForeignA2U),
|
||||
foreign: findUnknown(foreignToHomeA2U)
|
||||
}
|
||||
|
||||
logger.debug('Done')
|
||||
return {
|
||||
permanentMediators,
|
||||
floatingMediators,
|
||||
remotelyControlledMediators,
|
||||
unknown,
|
||||
lastChecked: Math.floor(Date.now() / 1000)
|
||||
}
|
||||
}
|
||||
module.exports = main
|
||||
@@ -4,11 +4,12 @@ services:
|
||||
monitor:
|
||||
image: poanetwork/tokenbridge-monitor:latest
|
||||
ports:
|
||||
- "${MONITOR_PORT}:${MONITOR_PORT}"
|
||||
- "${MONITOR_PORT}:${MONITOR_PORT}"
|
||||
env_file: ./.env
|
||||
environment:
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
volumes:
|
||||
- ./responses:/mono/monitor/responses
|
||||
- ./cache:/mono/monitor/cache
|
||||
restart: unless-stopped
|
||||
entrypoint: "yarn start"
|
||||
|
||||
@@ -1,8 +1,20 @@
|
||||
require('dotenv').config()
|
||||
const eventsInfo = require('./utils/events')
|
||||
const { processedMsgNotDelivered, deliveredMsgNotProcessed, eventWithoutReference } = require('./utils/message')
|
||||
const {
|
||||
processedMsgNotDelivered,
|
||||
deliveredMsgNotProcessed,
|
||||
eventWithoutReference,
|
||||
unclaimedHomeToForeignRequests
|
||||
} = require('./utils/message')
|
||||
const { getHomeTxSender } = require('./utils/web3Cache')
|
||||
const { BRIDGE_MODES } = require('../commons')
|
||||
|
||||
const {
|
||||
MONITOR_HOME_TO_FOREIGN_ALLOWANCE_LIST,
|
||||
MONITOR_HOME_TO_FOREIGN_BLOCK_LIST,
|
||||
MONITOR_HOME_TO_FOREIGN_CHECK_SENDER
|
||||
} = process.env
|
||||
|
||||
async function main() {
|
||||
const {
|
||||
homeToForeignRequests,
|
||||
@@ -33,17 +45,30 @@ async function main() {
|
||||
lastChecked: Math.floor(Date.now() / 1000)
|
||||
}
|
||||
} else {
|
||||
const onlyInHomeDeposits = homeToForeignRequests.filter(eventWithoutReference(homeToForeignConfirmations))
|
||||
let onlyInHomeDeposits = homeToForeignRequests.filter(eventWithoutReference(homeToForeignConfirmations))
|
||||
const onlyInForeignDeposits = homeToForeignConfirmations.filter(eventWithoutReference(homeToForeignRequests))
|
||||
|
||||
const onlyInHomeWithdrawals = foreignToHomeConfirmations.filter(eventWithoutReference(foreignToHomeRequests))
|
||||
const onlyInForeignWithdrawals = foreignToHomeRequests.filter(eventWithoutReference(foreignToHomeConfirmations))
|
||||
|
||||
const unclaimedStats = {}
|
||||
if (MONITOR_HOME_TO_FOREIGN_ALLOWANCE_LIST || MONITOR_HOME_TO_FOREIGN_BLOCK_LIST) {
|
||||
const unclaimedFilter = unclaimedHomeToForeignRequests()
|
||||
if (MONITOR_HOME_TO_FOREIGN_CHECK_SENDER === 'true') {
|
||||
for (let i = 0; i < onlyInHomeDeposits.length; i++) {
|
||||
onlyInHomeDeposits[i].sender = await getHomeTxSender(onlyInHomeDeposits[i].transactionHash)
|
||||
}
|
||||
}
|
||||
unclaimedStats.unclaimedHomeDeposits = onlyInHomeDeposits.filter(unclaimedFilter)
|
||||
onlyInHomeDeposits = onlyInHomeDeposits.filter(e => !unclaimedFilter(e))
|
||||
}
|
||||
|
||||
return {
|
||||
onlyInHomeDeposits,
|
||||
onlyInForeignDeposits,
|
||||
onlyInHomeWithdrawals,
|
||||
onlyInForeignWithdrawals,
|
||||
...unclaimedStats,
|
||||
lastChecked: Math.floor(Date.now() / 1000)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +1,11 @@
|
||||
require('dotenv').config()
|
||||
const BN = require('bignumber.js')
|
||||
const Web3 = require('web3')
|
||||
const Web3Utils = require('web3').utils
|
||||
const logger = require('./logger')('getBalances')
|
||||
const { BRIDGE_MODES } = require('../commons')
|
||||
const { web3Home, web3Foreign, getHomeBlockNumber } = require('./utils/web3')
|
||||
|
||||
const Web3Utils = Web3.utils
|
||||
|
||||
const {
|
||||
COMMON_HOME_RPC_URL,
|
||||
COMMON_FOREIGN_RPC_URL,
|
||||
COMMON_HOME_BRIDGE_ADDRESS,
|
||||
COMMON_FOREIGN_BRIDGE_ADDRESS
|
||||
} = process.env
|
||||
|
||||
const homeProvider = new Web3.providers.HttpProvider(COMMON_HOME_RPC_URL)
|
||||
const web3Home = new Web3(homeProvider)
|
||||
|
||||
const foreignProvider = new Web3.providers.HttpProvider(COMMON_FOREIGN_RPC_URL)
|
||||
const web3Foreign = new Web3(foreignProvider)
|
||||
const { COMMON_HOME_BRIDGE_ADDRESS, COMMON_FOREIGN_BRIDGE_ADDRESS } = process.env
|
||||
|
||||
const {
|
||||
ERC20_ABI,
|
||||
@@ -30,21 +18,50 @@ const {
|
||||
FOREIGN_NATIVE_TO_ERC_ABI
|
||||
} = require('../commons')
|
||||
|
||||
async function main(bridgeMode) {
|
||||
async function main(bridgeMode, eventsInfo) {
|
||||
const {
|
||||
homeToForeignConfirmations,
|
||||
foreignToHomeConfirmations,
|
||||
homeDelayedBlockNumber,
|
||||
foreignDelayedBlockNumber
|
||||
} = eventsInfo
|
||||
|
||||
// Events in the ./utils/events.js are fetched for different block ranges,
|
||||
// In order to be consistent with the balance values, the following values might be needed
|
||||
|
||||
// Foreign balance should represent all UserRequestForAffirmation events up to block `N - requiredBlockConfirmation()`
|
||||
// and all RelayedMessage events up to block `N`.
|
||||
// This constant tells the difference between bridge balance at block `N - requiredBlockConfirmation() + 1`
|
||||
// and the actual value monitor is interested in.
|
||||
const lateForeignConfirmationsTotalValue = BN.sum(
|
||||
0,
|
||||
...homeToForeignConfirmations.filter(e => e.blockNumber > foreignDelayedBlockNumber).map(e => e.value)
|
||||
)
|
||||
// Home balance should represent all UserRequestForSignature events up to block `M - requiredBlockConfirmation()`
|
||||
// and all AffirmationCompleted events up to block `M`.
|
||||
// This constant tells the difference between bridge balance at block `M - requiredBlockConfirmation() + 1`
|
||||
// and the actual value monitor is interested in.
|
||||
const lateHomeConfirmationsTotalValue = BN.sum(
|
||||
0,
|
||||
...foreignToHomeConfirmations.filter(e => e.blockNumber > homeDelayedBlockNumber).map(e => e.value)
|
||||
)
|
||||
|
||||
if (bridgeMode === BRIDGE_MODES.ERC_TO_ERC) {
|
||||
const foreignBridge = new web3Foreign.eth.Contract(FOREIGN_ERC_TO_ERC_ABI, COMMON_FOREIGN_BRIDGE_ADDRESS)
|
||||
const erc20Address = await foreignBridge.methods.erc20token().call()
|
||||
const erc20Contract = new web3Foreign.eth.Contract(ERC20_ABI, erc20Address)
|
||||
logger.debug('calling erc20Contract.methods.balanceOf')
|
||||
const foreignErc20Balance = await erc20Contract.methods.balanceOf(COMMON_FOREIGN_BRIDGE_ADDRESS).call()
|
||||
const foreignErc20Balance = await erc20Contract.methods
|
||||
.balanceOf(COMMON_FOREIGN_BRIDGE_ADDRESS)
|
||||
.call({}, foreignDelayedBlockNumber)
|
||||
const homeBridge = new web3Home.eth.Contract(HOME_ERC_TO_ERC_ABI, COMMON_HOME_BRIDGE_ADDRESS)
|
||||
logger.debug('calling homeBridge.methods.erc677token')
|
||||
const tokenAddress = await homeBridge.methods.erc677token().call()
|
||||
const tokenContract = new web3Home.eth.Contract(ERC677_ABI, tokenAddress)
|
||||
logger.debug('calling tokenContract.methods.totalSupply()')
|
||||
const totalSupply = await tokenContract.methods.totalSupply().call()
|
||||
const foreignBalanceBN = new BN(foreignErc20Balance)
|
||||
const foreignTotalSupplyBN = new BN(totalSupply)
|
||||
const totalSupply = await tokenContract.methods.totalSupply().call({}, homeDelayedBlockNumber)
|
||||
const foreignBalanceBN = new BN(foreignErc20Balance).plus(lateForeignConfirmationsTotalValue)
|
||||
const foreignTotalSupplyBN = new BN(totalSupply).plus(lateHomeConfirmationsTotalValue)
|
||||
const diff = foreignBalanceBN.minus(foreignTotalSupplyBN).toString(10)
|
||||
logger.debug('Done')
|
||||
return {
|
||||
@@ -61,12 +78,12 @@ async function main(bridgeMode) {
|
||||
logger.debug('calling web3Home.eth.getBalance')
|
||||
const foreignBridge = new web3Foreign.eth.Contract(FOREIGN_NATIVE_TO_ERC_ABI, COMMON_FOREIGN_BRIDGE_ADDRESS)
|
||||
const erc20Address = await foreignBridge.methods.erc677token().call()
|
||||
const homeBalance = await web3Home.eth.getBalance(COMMON_HOME_BRIDGE_ADDRESS)
|
||||
const homeBalance = await web3Home.eth.getBalance(COMMON_HOME_BRIDGE_ADDRESS, homeDelayedBlockNumber)
|
||||
const tokenContract = new web3Foreign.eth.Contract(ERC20_ABI, erc20Address)
|
||||
logger.debug('calling tokenContract.methods.totalSupply()')
|
||||
const totalSupply = await tokenContract.methods.totalSupply().call()
|
||||
const homeBalanceBN = new BN(homeBalance)
|
||||
const foreignTotalSupplyBN = new BN(totalSupply)
|
||||
const totalSupply = await tokenContract.methods.totalSupply().call({}, foreignDelayedBlockNumber)
|
||||
const homeBalanceBN = new BN(homeBalance).plus(lateHomeConfirmationsTotalValue)
|
||||
const foreignTotalSupplyBN = new BN(totalSupply).plus(lateForeignConfirmationsTotalValue)
|
||||
const diff = homeBalanceBN.minus(foreignTotalSupplyBN).toString(10)
|
||||
logger.debug('Done')
|
||||
return {
|
||||
@@ -103,21 +120,25 @@ async function main(bridgeMode) {
|
||||
}
|
||||
|
||||
logger.debug('calling erc20Contract.methods.balanceOf')
|
||||
const foreignErc20Balance = await erc20Contract.methods.balanceOf(COMMON_FOREIGN_BRIDGE_ADDRESS).call()
|
||||
const foreignErc20Balance = await erc20Contract.methods
|
||||
.balanceOf(COMMON_FOREIGN_BRIDGE_ADDRESS)
|
||||
.call({}, foreignDelayedBlockNumber)
|
||||
|
||||
const homeBridge = new web3Home.eth.Contract(HOME_ERC_TO_NATIVE_ABI, COMMON_HOME_BRIDGE_ADDRESS)
|
||||
logger.debug('calling homeBridge.methods.blockRewardContract')
|
||||
const blockRewardAddress = await homeBridge.methods.blockRewardContract().call()
|
||||
const blockRewardContract = new web3Home.eth.Contract(BLOCK_REWARD_ABI, blockRewardAddress)
|
||||
const homeBlockNumber = await getHomeBlockNumber()
|
||||
logger.debug('calling blockReward.methods.mintedTotally')
|
||||
const mintedCoins = await blockRewardContract.methods.mintedTotallyByBridge(COMMON_HOME_BRIDGE_ADDRESS).call()
|
||||
const mintedCoins = await blockRewardContract.methods
|
||||
.mintedTotallyByBridge(COMMON_HOME_BRIDGE_ADDRESS)
|
||||
.call({}, homeBlockNumber)
|
||||
logger.debug('calling homeBridge.methods.totalBurntCoins')
|
||||
const burntCoins = await homeBridge.methods.totalBurntCoins().call()
|
||||
|
||||
const burntCoins = await homeBridge.methods.totalBurntCoins().call({}, homeDelayedBlockNumber)
|
||||
const mintedCoinsBN = new BN(mintedCoins)
|
||||
const burntCoinsBN = new BN(burntCoins)
|
||||
const totalSupplyBN = mintedCoinsBN.minus(burntCoinsBN)
|
||||
const foreignErc20BalanceBN = new BN(foreignErc20Balance)
|
||||
const foreignErc20BalanceBN = new BN(foreignErc20Balance).plus(lateForeignConfirmationsTotalValue)
|
||||
const investedAmountInDaiBN = new BN(investedAmountInDai)
|
||||
const bridgeDsrBalanceBN = new BN(bridgeDsrBalance)
|
||||
|
||||
|
||||
@@ -1,18 +1,36 @@
|
||||
require('dotenv').config()
|
||||
const eventsInfo = require('./utils/events')
|
||||
const BN = require('bignumber.js')
|
||||
const Web3Utils = require('web3').utils
|
||||
const {
|
||||
eventWithoutReference,
|
||||
deliveredMsgNotProcessed,
|
||||
unclaimedHomeToForeignRequests,
|
||||
manuallyProcessedAMBHomeToForeignRequests
|
||||
} = require('./utils/message')
|
||||
const { BRIDGE_MODES } = require('../commons')
|
||||
const { getHomeTxSender } = require('./utils/web3Cache')
|
||||
|
||||
async function main(bridgeMode) {
|
||||
const {
|
||||
MONITOR_HOME_TO_FOREIGN_ALLOWANCE_LIST,
|
||||
MONITOR_HOME_TO_FOREIGN_BLOCK_LIST,
|
||||
MONITOR_HOME_TO_FOREIGN_CHECK_SENDER
|
||||
} = process.env
|
||||
|
||||
async function main(bridgeMode, eventsInfo) {
|
||||
const {
|
||||
homeToForeignConfirmations,
|
||||
homeToForeignRequests,
|
||||
foreignToHomeConfirmations,
|
||||
foreignToHomeRequests
|
||||
} = await eventsInfo(bridgeMode)
|
||||
} = eventsInfo
|
||||
|
||||
if (bridgeMode === BRIDGE_MODES.ARBITRARY_MESSAGE) {
|
||||
const onlyInHomeRequests = homeToForeignRequests.filter(deliveredMsgNotProcessed(homeToForeignConfirmations))
|
||||
const manuallyProcessedRequests = onlyInHomeRequests.filter(manuallyProcessedAMBHomeToForeignRequests())
|
||||
return {
|
||||
fromHomeToForeignDiff: homeToForeignRequests.length - homeToForeignConfirmations.length,
|
||||
fromHomeToForeignDiff:
|
||||
homeToForeignRequests.length - homeToForeignConfirmations.length - manuallyProcessedRequests.length,
|
||||
fromHomeToForeignPBUDiff: manuallyProcessedRequests.length,
|
||||
fromForeignToHomeDiff: foreignToHomeConfirmations.length - foreignToHomeRequests.length,
|
||||
home: {
|
||||
toForeign: homeToForeignRequests.length,
|
||||
@@ -24,9 +42,26 @@ async function main(bridgeMode) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
const stats = {
|
||||
depositsDiff: homeToForeignRequests.length - homeToForeignConfirmations.length,
|
||||
withdrawalDiff: foreignToHomeConfirmations.length - foreignToHomeRequests.length,
|
||||
withdrawalDiff: foreignToHomeConfirmations.length - foreignToHomeRequests.length
|
||||
}
|
||||
if (MONITOR_HOME_TO_FOREIGN_ALLOWANCE_LIST || MONITOR_HOME_TO_FOREIGN_BLOCK_LIST) {
|
||||
const onlyInHomeDeposits = homeToForeignRequests.filter(eventWithoutReference(homeToForeignConfirmations))
|
||||
if (MONITOR_HOME_TO_FOREIGN_CHECK_SENDER === 'true') {
|
||||
for (let i = 0; i < onlyInHomeDeposits.length; i++) {
|
||||
onlyInHomeDeposits[i].sender = await getHomeTxSender(onlyInHomeDeposits[i].transactionHash)
|
||||
}
|
||||
}
|
||||
|
||||
const unclaimedPool = onlyInHomeDeposits.filter(unclaimedHomeToForeignRequests())
|
||||
|
||||
stats.depositsDiff -= unclaimedPool.length
|
||||
stats.unclaimedDiff = unclaimedPool.length
|
||||
stats.unclaimedBalance = Web3Utils.fromWei(BN.sum(0, ...unclaimedPool.map(e => e.value)).toFixed())
|
||||
}
|
||||
return {
|
||||
...stats,
|
||||
home: {
|
||||
deposits: homeToForeignRequests.length,
|
||||
withdrawals: foreignToHomeConfirmations.length
|
||||
|
||||
@@ -50,6 +50,16 @@ bridgeRouter.get('/alerts', async (req, res, next) => {
|
||||
}
|
||||
})
|
||||
|
||||
bridgeRouter.get('/mediators', async (req, res, next) => {
|
||||
try {
|
||||
const results = await readFile(`./responses/${req.params.bridgeName}/mediators.json`)
|
||||
res.json(results)
|
||||
} catch (e) {
|
||||
// this will eventually be handled by your error handling middleware
|
||||
next(e)
|
||||
}
|
||||
})
|
||||
|
||||
bridgeRouter.get('/stuckTransfers', async (req, res, next) => {
|
||||
try {
|
||||
const results = await readFile(`./responses/${req.params.bridgeName}/stuckTransfers.json`)
|
||||
|
||||
@@ -14,12 +14,12 @@
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"bignumber.js": "^6.0.0",
|
||||
"bignumber.js": "^9.0.1",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^5.0.1",
|
||||
"express": "^4.16.3",
|
||||
"node-fetch": "^2.1.2",
|
||||
"web3": "1.0.0-beta.34"
|
||||
"web3": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.18"
|
||||
|
||||
@@ -2,17 +2,21 @@
|
||||
|
||||
CONFIGDIR="configs"
|
||||
RESPONSESDIR="responses"
|
||||
ACLDIR="access-lists"
|
||||
ALLOWANCEFILE="allowance_list.txt"
|
||||
BLOCKFILE="block_list.txt"
|
||||
CACHEDIR="cache"
|
||||
IMAGETAG="latest"
|
||||
|
||||
cd $(dirname $0)/..
|
||||
|
||||
if /usr/local/bin/docker-compose ps | grep -q -i 'monitor'; then
|
||||
tstart=`date +"%s"`
|
||||
|
||||
|
||||
for file in ${CONFIGDIR}/*.env
|
||||
do
|
||||
echo "${file} handling..."
|
||||
|
||||
|
||||
bridgename=`source ${file} && echo ${MONITOR_BRIDGE_NAME}`
|
||||
reportdir=${RESPONSESDIR}"/"${bridgename}
|
||||
if [ ! -d ${reportdir} ]; then
|
||||
@@ -26,10 +30,18 @@ if /usr/local/bin/docker-compose ps | grep -q -i 'monitor'; then
|
||||
fi
|
||||
done
|
||||
|
||||
alist=`source ${file} && echo ${MONITOR_HOME_TO_FOREIGN_ALLOWANCE_LIST}`
|
||||
blist=`source ${file} && echo ${MONITOR_HOME_TO_FOREIGN_BLOCK_LIST}`
|
||||
al_param="$(pwd)/${ACLDIR}/${bridgename}/${ALLOWANCEFILE}:/mono/monitor/access-lists/allowance_list.txt"
|
||||
bl_param="$(pwd)/${ACLDIR}/${bridgename}/${BLOCKFILE}:/mono/monitor/access-lists/block_list.txt"
|
||||
|
||||
containername=${bridgename}"-checker"
|
||||
docker container stats --no-stream ${containername} 2>/dev/null 1>&2
|
||||
if [ ! "$?" == "0" ]; then
|
||||
mkdir -p "$(pwd)/$CACHEDIR/$bridgename"
|
||||
docker run --rm --env-file $file -v $(pwd)/${RESPONSESDIR}:/mono/monitor/responses \
|
||||
${alist:+"-v"} ${alist:+"$al_param"} ${blist:+"-v"} ${blist:+"$bl_param"} \
|
||||
-v $(pwd)/${CACHEDIR}/${bridgename}:/mono/monitor/cache/${bridgename} \
|
||||
--name ${containername} poanetwork/tokenbridge-monitor:${IMAGETAG} \
|
||||
/bin/bash -c 'yarn check-all'
|
||||
shasum -a 256 -s -c ${checksumfile}
|
||||
@@ -46,15 +58,15 @@ if /usr/local/bin/docker-compose ps | grep -q -i 'monitor'; then
|
||||
else
|
||||
echo "${containername} have not finished yet" >&2
|
||||
fi
|
||||
|
||||
|
||||
rm ${checksumfile}
|
||||
echo "========================================"
|
||||
done
|
||||
|
||||
|
||||
tend=`date +"%s"`
|
||||
tdiff=`expr ${tend} - ${tstart}`
|
||||
echo "Total time to run: ${tdiff}"
|
||||
|
||||
else
|
||||
echo "Monitor is not running, skipping checks."
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
require('dotenv').config()
|
||||
const Web3 = require('web3')
|
||||
const logger = require('./logger')('stuckTransfers.js')
|
||||
const { FOREIGN_V1_ABI } = require('../commons/abis')
|
||||
const { web3Foreign, getForeignBlockNumber } = require('./utils/web3')
|
||||
const { getPastEvents } = require('./utils/web3Cache')
|
||||
|
||||
const { COMMON_FOREIGN_RPC_URL, COMMON_FOREIGN_BRIDGE_ADDRESS } = process.env
|
||||
const { COMMON_FOREIGN_BRIDGE_ADDRESS } = process.env
|
||||
const MONITOR_FOREIGN_START_BLOCK = Number(process.env.MONITOR_FOREIGN_START_BLOCK) || 0
|
||||
|
||||
const foreignProvider = new Web3.providers.HttpProvider(COMMON_FOREIGN_RPC_URL)
|
||||
const web3Foreign = new Web3(foreignProvider)
|
||||
|
||||
const ABITransferWithoutData = [
|
||||
{
|
||||
anonymous: false,
|
||||
@@ -64,38 +62,39 @@ const ABIWithData = [
|
||||
}
|
||||
]
|
||||
|
||||
function compareTransfers(transfersNormal) {
|
||||
return withData => {
|
||||
return (
|
||||
transfersNormal.filter(normal => {
|
||||
return normal.transactionHash === withData.transactionHash
|
||||
}).length === 0
|
||||
)
|
||||
}
|
||||
function transferWithoutCallback(transfersNormal) {
|
||||
const txHashes = new Set()
|
||||
transfersNormal.forEach(transfer => txHashes.add(transfer.transactionHash))
|
||||
return withData => !txHashes.has(withData.transactionHash)
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const foreignBridge = new web3Foreign.eth.Contract(FOREIGN_V1_ABI, COMMON_FOREIGN_BRIDGE_ADDRESS)
|
||||
logger.debug('calling foreignBridge.methods.erc677token')
|
||||
const erc20Address = await foreignBridge.methods.erc677token().call()
|
||||
const tokenContract = new web3Foreign.eth.Contract(ABITransferWithoutData, erc20Address)
|
||||
const tokenContractWithData = new web3Foreign.eth.Contract(ABIWithData, erc20Address)
|
||||
logger.debug('getting last block number')
|
||||
const foreignBlockNumber = await getForeignBlockNumber()
|
||||
const foreignConfirmations = await foreignBridge.methods.requiredBlockConfirmations().call()
|
||||
const foreignDelayedBlockNumber = foreignBlockNumber - foreignConfirmations
|
||||
logger.debug('calling tokenContract.getPastEvents Transfer')
|
||||
const transfersNormal = await tokenContract.getPastEvents('Transfer', {
|
||||
filter: {
|
||||
to: COMMON_FOREIGN_BRIDGE_ADDRESS
|
||||
const options = {
|
||||
event: 'Transfer',
|
||||
options: {
|
||||
filter: {
|
||||
to: COMMON_FOREIGN_BRIDGE_ADDRESS
|
||||
}
|
||||
},
|
||||
fromBlock: MONITOR_FOREIGN_START_BLOCK,
|
||||
toBlock: 'latest'
|
||||
})
|
||||
toBlock: foreignBlockNumber,
|
||||
chain: 'foreign',
|
||||
safeToBlock: foreignDelayedBlockNumber
|
||||
}
|
||||
const transfersNormal = await getPastEvents(tokenContract, options)
|
||||
logger.debug('calling tokenContractWithData.getPastEvents Transfer')
|
||||
const transfersWithData = await tokenContractWithData.getPastEvents('Transfer', {
|
||||
filter: {
|
||||
to: COMMON_FOREIGN_BRIDGE_ADDRESS
|
||||
},
|
||||
fromBlock: MONITOR_FOREIGN_START_BLOCK,
|
||||
toBlock: 'latest'
|
||||
})
|
||||
const stuckTransfers = transfersNormal.filter(compareTransfers(transfersWithData))
|
||||
const transfersWithData = await getPastEvents(tokenContractWithData, options)
|
||||
const stuckTransfers = transfersNormal.filter(transferWithoutCallback(transfersWithData))
|
||||
logger.debug('Done')
|
||||
return {
|
||||
stuckTransfers,
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
const { toBN } = require('web3').utils
|
||||
|
||||
const getBlockNumberCall = web3 => web3.eth.getBlockNumber()
|
||||
|
||||
async function getBlockNumber(web3Home, web3Foreign) {
|
||||
return (await Promise.all([web3Home, web3Foreign].map(getBlockNumberCall))).map(toBN)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getBlockNumber
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
require('dotenv').config()
|
||||
const Web3 = require('web3')
|
||||
const { toBN } = require('web3').utils
|
||||
const logger = require('../logger')('eventsUtils')
|
||||
const {
|
||||
BRIDGE_MODES,
|
||||
@@ -11,7 +9,6 @@ const {
|
||||
ERC20_ABI,
|
||||
ERC677_BRIDGE_TOKEN_ABI,
|
||||
getTokenType,
|
||||
getPastEvents,
|
||||
ZERO_ADDRESS,
|
||||
OLD_AMB_USER_REQUEST_FOR_SIGNATURE_ABI,
|
||||
OLD_AMB_USER_REQUEST_FOR_AFFIRMATION_ABI
|
||||
@@ -19,24 +16,12 @@ const {
|
||||
const { normalizeEventInformation } = require('./message')
|
||||
const { filterTransferBeforeES } = require('./tokenUtils')
|
||||
const { writeFile, readCacheFile } = require('./file')
|
||||
const { web3Home, web3Foreign, getHomeBlockNumber, getForeignBlockNumber } = require('./web3')
|
||||
const { getPastEvents } = require('./web3Cache')
|
||||
|
||||
const {
|
||||
COMMON_HOME_RPC_URL,
|
||||
COMMON_FOREIGN_RPC_URL,
|
||||
COMMON_HOME_BRIDGE_ADDRESS,
|
||||
COMMON_FOREIGN_BRIDGE_ADDRESS,
|
||||
MONITOR_CACHE_EVENTS
|
||||
} = process.env
|
||||
const MONITOR_HOME_START_BLOCK = toBN(Number(process.env.MONITOR_HOME_START_BLOCK) || 0)
|
||||
const MONITOR_FOREIGN_START_BLOCK = toBN(Number(process.env.MONITOR_FOREIGN_START_BLOCK) || 0)
|
||||
|
||||
const homeProvider = new Web3.providers.HttpProvider(COMMON_HOME_RPC_URL)
|
||||
const web3Home = new Web3(homeProvider)
|
||||
|
||||
const foreignProvider = new Web3.providers.HttpProvider(COMMON_FOREIGN_RPC_URL)
|
||||
const web3Foreign = new Web3(foreignProvider)
|
||||
|
||||
const { getBlockNumber } = require('./contract')
|
||||
const { COMMON_HOME_BRIDGE_ADDRESS, COMMON_FOREIGN_BRIDGE_ADDRESS, MONITOR_CACHE_EVENTS } = process.env
|
||||
const MONITOR_HOME_START_BLOCK = Number(process.env.MONITOR_HOME_START_BLOCK) || 0
|
||||
const MONITOR_FOREIGN_START_BLOCK = Number(process.env.MONITOR_FOREIGN_START_BLOCK) || 0
|
||||
|
||||
const cacheFilePath = '/tmp/cachedEvents.json'
|
||||
async function main(mode) {
|
||||
@@ -73,11 +58,12 @@ async function main(mode) {
|
||||
}
|
||||
|
||||
logger.debug('getting last block numbers')
|
||||
const [homeBlockNumber, foreignBlockNumber] = await getBlockNumber(web3Home, web3Foreign)
|
||||
const homeConfirmations = toBN(await homeBridge.methods.requiredBlockConfirmations().call())
|
||||
const foreignConfirmations = toBN(await foreignBridge.methods.requiredBlockConfirmations().call())
|
||||
const homeDelayedBlockNumber = homeBlockNumber.sub(homeConfirmations)
|
||||
const foreignDelayedBlockNumber = foreignBlockNumber.sub(foreignConfirmations)
|
||||
const homeBlockNumber = await getHomeBlockNumber()
|
||||
const foreignBlockNumber = await getForeignBlockNumber()
|
||||
const homeConfirmations = await homeBridge.methods.requiredBlockConfirmations().call()
|
||||
const foreignConfirmations = await foreignBridge.methods.requiredBlockConfirmations().call()
|
||||
const homeDelayedBlockNumber = homeBlockNumber - homeConfirmations
|
||||
const foreignDelayedBlockNumber = foreignBlockNumber - foreignConfirmations
|
||||
|
||||
let homeToForeignRequests = []
|
||||
let foreignToHomeRequests = []
|
||||
@@ -95,22 +81,24 @@ async function main(mode) {
|
||||
homeToForeignRequests = (await getPastEvents(oldHomeBridge, {
|
||||
event: 'UserRequestForSignature',
|
||||
fromBlock: MONITOR_HOME_START_BLOCK,
|
||||
toBlock: homeDelayedBlockNumber
|
||||
toBlock: homeDelayedBlockNumber,
|
||||
chain: 'home'
|
||||
})).map(normalizeEvent)
|
||||
logger.debug(`found ${homeToForeignRequests.length} events`)
|
||||
if (homeToForeignRequests.length > 0) {
|
||||
homeMigrationBlock = toBN(Math.max(...homeToForeignRequests.map(x => x.blockNumber)))
|
||||
homeMigrationBlock = Math.max(...homeToForeignRequests.map(x => x.blockNumber))
|
||||
}
|
||||
|
||||
logger.debug("calling oldForeignBridge.getPastEvents('UserRequestForAffirmation(bytes)')")
|
||||
foreignToHomeRequests = (await getPastEvents(oldForeignBridge, {
|
||||
event: 'UserRequestForAffirmation',
|
||||
fromBlock: MONITOR_FOREIGN_START_BLOCK,
|
||||
toBlock: foreignDelayedBlockNumber
|
||||
toBlock: foreignDelayedBlockNumber,
|
||||
chain: 'foreign'
|
||||
})).map(normalizeEvent)
|
||||
logger.debug(`found ${foreignToHomeRequests.length} events`)
|
||||
if (foreignToHomeRequests.length > 0) {
|
||||
foreignMigrationBlock = toBN(Math.max(...foreignToHomeRequests.map(x => x.blockNumber)))
|
||||
foreignMigrationBlock = Math.max(...foreignToHomeRequests.map(x => x.blockNumber))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +106,8 @@ async function main(mode) {
|
||||
const homeToForeignRequestsNew = (await getPastEvents(homeBridge, {
|
||||
event: v1Bridge ? 'Deposit' : 'UserRequestForSignature',
|
||||
fromBlock: homeMigrationBlock,
|
||||
toBlock: homeDelayedBlockNumber
|
||||
toBlock: homeDelayedBlockNumber,
|
||||
chain: 'home'
|
||||
})).map(normalizeEvent)
|
||||
homeToForeignRequests = [...homeToForeignRequests, ...homeToForeignRequestsNew]
|
||||
|
||||
@@ -126,21 +115,26 @@ async function main(mode) {
|
||||
const homeToForeignConfirmations = (await getPastEvents(foreignBridge, {
|
||||
event: v1Bridge ? 'Deposit' : 'RelayedMessage',
|
||||
fromBlock: MONITOR_FOREIGN_START_BLOCK,
|
||||
toBlock: foreignBlockNumber
|
||||
toBlock: foreignBlockNumber,
|
||||
chain: 'foreign',
|
||||
safeToBlock: foreignDelayedBlockNumber
|
||||
})).map(normalizeEvent)
|
||||
|
||||
logger.debug("calling homeBridge.getPastEvents('AffirmationCompleted')")
|
||||
const foreignToHomeConfirmations = (await getPastEvents(homeBridge, {
|
||||
event: v1Bridge ? 'Withdraw' : 'AffirmationCompleted',
|
||||
fromBlock: MONITOR_HOME_START_BLOCK,
|
||||
toBlock: homeBlockNumber
|
||||
toBlock: homeBlockNumber,
|
||||
chain: 'home',
|
||||
safeToBlock: homeDelayedBlockNumber
|
||||
})).map(normalizeEvent)
|
||||
|
||||
logger.debug("calling foreignBridge.getPastEvents('UserRequestForAffirmation')")
|
||||
const foreignToHomeRequestsNew = (await getPastEvents(foreignBridge, {
|
||||
event: v1Bridge ? 'Withdraw' : 'UserRequestForAffirmation',
|
||||
fromBlock: foreignMigrationBlock,
|
||||
toBlock: foreignDelayedBlockNumber
|
||||
toBlock: foreignDelayedBlockNumber,
|
||||
chain: 'foreign'
|
||||
})).map(normalizeEvent)
|
||||
foreignToHomeRequests = [...foreignToHomeRequests, ...foreignToHomeRequestsNew]
|
||||
|
||||
@@ -152,7 +146,8 @@ async function main(mode) {
|
||||
toBlock: foreignDelayedBlockNumber,
|
||||
options: {
|
||||
filter: { to: COMMON_FOREIGN_BRIDGE_ADDRESS }
|
||||
}
|
||||
},
|
||||
chain: 'foreign'
|
||||
})).map(normalizeEvent)
|
||||
|
||||
let directTransfers = transferEvents
|
||||
@@ -163,7 +158,9 @@ async function main(mode) {
|
||||
const tokensSwappedEvents = await getPastEvents(foreignBridge, {
|
||||
event: 'TokensSwapped',
|
||||
fromBlock: MONITOR_FOREIGN_START_BLOCK,
|
||||
toBlock: foreignBlockNumber
|
||||
toBlock: foreignBlockNumber,
|
||||
chain: 'foreign',
|
||||
safeToBlock: foreignDelayedBlockNumber
|
||||
})
|
||||
|
||||
// Get token swap events emitted by foreign bridge
|
||||
@@ -202,7 +199,8 @@ async function main(mode) {
|
||||
toBlock: foreignDelayedBlockNumber,
|
||||
options: {
|
||||
filter: { to: COMMON_FOREIGN_BRIDGE_ADDRESS }
|
||||
}
|
||||
},
|
||||
chain: 'foreign'
|
||||
})).map(normalizeEvent)
|
||||
|
||||
// Remove events after the ES
|
||||
@@ -237,7 +235,9 @@ async function main(mode) {
|
||||
foreignToHomeConfirmations,
|
||||
foreignToHomeRequests,
|
||||
isExternalErc20,
|
||||
bridgeMode
|
||||
bridgeMode,
|
||||
homeDelayedBlockNumber,
|
||||
foreignDelayedBlockNumber
|
||||
}
|
||||
|
||||
if (MONITOR_CACHE_EVENTS === 'true') {
|
||||
|
||||
@@ -38,9 +38,25 @@ function readCacheFile(filePath) {
|
||||
}
|
||||
}
|
||||
|
||||
function writeCacheFile(filePath, object) {
|
||||
fs.mkdirSync(path.dirname(filePath), { recursive: true })
|
||||
fs.writeFileSync(filePath, JSON.stringify(object))
|
||||
}
|
||||
|
||||
function readAccessListFile(filePath) {
|
||||
const data = fs.readFileSync(filePath)
|
||||
return data
|
||||
.toString()
|
||||
.split('\n')
|
||||
.map(addr => addr.trim().toLowerCase())
|
||||
.filter(addr => addr.length === 42)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
readFile,
|
||||
writeFile,
|
||||
createDir,
|
||||
readCacheFile
|
||||
readCacheFile,
|
||||
writeCacheFile,
|
||||
readAccessListFile
|
||||
}
|
||||
|
||||
93
monitor/utils/getValidatorsList.js
Normal file
93
monitor/utils/getValidatorsList.js
Normal file
@@ -0,0 +1,93 @@
|
||||
const { REWARDABLE_VALIDATORS_ABI, processValidatorsEvents } = require('../../commons')
|
||||
const { getPastEvents } = require('./web3Cache')
|
||||
|
||||
const VALIDATORS_INDEXED_EVENTS_ABI = [
|
||||
{
|
||||
anonymous: false,
|
||||
inputs: [
|
||||
{
|
||||
indexed: true,
|
||||
name: 'validator',
|
||||
type: 'address'
|
||||
}
|
||||
],
|
||||
name: 'ValidatorRemoved',
|
||||
type: 'event'
|
||||
},
|
||||
{
|
||||
anonymous: false,
|
||||
inputs: [
|
||||
{
|
||||
indexed: true,
|
||||
name: 'validator',
|
||||
type: 'address'
|
||||
}
|
||||
],
|
||||
name: 'ValidatorAdded',
|
||||
type: 'event'
|
||||
},
|
||||
{
|
||||
anonymous: false,
|
||||
inputs: [
|
||||
{
|
||||
indexed: true,
|
||||
name: 'validator',
|
||||
type: 'address'
|
||||
},
|
||||
{
|
||||
indexed: true,
|
||||
name: 'reward',
|
||||
type: 'address'
|
||||
}
|
||||
],
|
||||
name: 'ValidatorAdded',
|
||||
type: 'event'
|
||||
}
|
||||
]
|
||||
|
||||
const tryCall = async (method, fallbackValue) => {
|
||||
try {
|
||||
return await method.call()
|
||||
} catch (e) {
|
||||
return fallbackValue
|
||||
}
|
||||
}
|
||||
|
||||
const getValidatorList = async (address, eth, options) => {
|
||||
const { logger } = options
|
||||
logger.debug('getting validatorList')
|
||||
|
||||
const validatorsContract = new eth.Contract(REWARDABLE_VALIDATORS_ABI, address) // in monitor, BRIDGE_VALIDATORS_ABI was used
|
||||
const validators = await tryCall(validatorsContract.methods.validatorList(), [])
|
||||
|
||||
if (validators.length) {
|
||||
return validators
|
||||
}
|
||||
|
||||
logger.debug('getting validatorsEvents')
|
||||
|
||||
options.fromBlock = Number(await tryCall(validatorsContract.methods.deployedAtBlock(), 0))
|
||||
|
||||
const contract = new eth.Contract(VALIDATORS_INDEXED_EVENTS_ABI, address)
|
||||
|
||||
const validatorsEvents = [
|
||||
...(await getPastEvents(contract, {
|
||||
event: 'ValidatorAdded(address)',
|
||||
...options
|
||||
})),
|
||||
...(await getPastEvents(contract, {
|
||||
event: 'ValidatorAdded(address,address)',
|
||||
...options
|
||||
})),
|
||||
...(await getPastEvents(contract, {
|
||||
event: 'ValidatorRemoved(address)',
|
||||
...options
|
||||
}))
|
||||
].sort((a, b) => a.blockNumber - b.blockNumber || a.transactionIndex - b.transactionIndex)
|
||||
|
||||
return processValidatorsEvents(validatorsEvents)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getValidatorList
|
||||
}
|
||||
@@ -1,44 +1,31 @@
|
||||
const web3Utils = require('web3').utils
|
||||
const { parseAMBMessage } = require('../../commons')
|
||||
const { normalizeAMBMessageEvent } = require('../../commons')
|
||||
const { readAccessListFile } = require('./file')
|
||||
|
||||
const { MONITOR_HOME_TO_FOREIGN_ALLOWANCE_LIST, MONITOR_HOME_TO_FOREIGN_BLOCK_LIST } = process.env
|
||||
|
||||
const keyAMB = e => [e.messageId, e.sender, e.executor].join(',').toLowerCase()
|
||||
|
||||
function deliveredMsgNotProcessed(processedList) {
|
||||
return deliveredMsg => {
|
||||
let msgData = deliveredMsg.returnValues.encodedData
|
||||
if (!deliveredMsg.returnValues.messageId) {
|
||||
// append tx hash to an old message, where message id was not used
|
||||
msgData = deliveredMsg.transactionHash + msgData.slice(2)
|
||||
}
|
||||
const msg = parseAMBMessage(msgData)
|
||||
return (
|
||||
processedList.filter(processedMsg => {
|
||||
return messageEqualsEvent(msg, processedMsg.returnValues)
|
||||
}).length === 0
|
||||
)
|
||||
}
|
||||
const keys = new Set()
|
||||
processedList.forEach(processedMsg => keys.add(keyAMB(processedMsg.returnValues)))
|
||||
return deliveredMsg => !keys.has(keyAMB(normalizeAMBMessageEvent(deliveredMsg)))
|
||||
}
|
||||
|
||||
function processedMsgNotDelivered(deliveredList) {
|
||||
return processedMsg => {
|
||||
return (
|
||||
deliveredList.filter(deliveredMsg => {
|
||||
let msgData = deliveredMsg.returnValues.encodedData
|
||||
if (!deliveredMsg.returnValues.messageId) {
|
||||
// append tx hash to an old message, where message id was not used
|
||||
msgData = deliveredMsg.transactionHash + msgData.slice(2)
|
||||
}
|
||||
const msg = parseAMBMessage(msgData)
|
||||
return messageEqualsEvent(msg, processedMsg.returnValues)
|
||||
}).length === 0
|
||||
)
|
||||
}
|
||||
const keys = new Set()
|
||||
deliveredList.forEach(deliveredMsg => keys.add(keyAMB(normalizeAMBMessageEvent(deliveredMsg))))
|
||||
return processedMsg => !keys.has(keyAMB(processedMsg.returnValues))
|
||||
}
|
||||
|
||||
function messageEqualsEvent(parsedMsg, event) {
|
||||
return (
|
||||
web3Utils.toChecksumAddress(parsedMsg.sender) === event.sender &&
|
||||
web3Utils.toChecksumAddress(parsedMsg.executor) === event.executor &&
|
||||
parsedMsg.messageId === event.messageId // for an old messages, event.messageId is actually a transactionHash
|
||||
)
|
||||
function addExecutionStatus(processedList) {
|
||||
const statuses = {}
|
||||
processedList.forEach(processedMsg => {
|
||||
statuses[keyAMB(processedMsg.returnValues)] = processedMsg.returnValues.status
|
||||
})
|
||||
return deliveredMsg => {
|
||||
deliveredMsg.status = statuses[keyAMB(deliveredMsg)]
|
||||
return deliveredMsg
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -60,13 +47,50 @@ const normalizeEventInformation = event => ({
|
||||
value: event.returnValues.value
|
||||
})
|
||||
|
||||
const eventWithoutReference = otherSideEvents => e =>
|
||||
otherSideEvents.filter(a => a.referenceTx === e.referenceTx && a.recipient === e.recipient && a.value === e.value)
|
||||
.length === 0
|
||||
const key = e => [e.referenceTx, e.recipient, e.value].join(',').toLowerCase()
|
||||
|
||||
const eventWithoutReference = otherSideEvents => {
|
||||
const keys = new Set()
|
||||
otherSideEvents.forEach(e => keys.add(key(e)))
|
||||
return e => !keys.has(key(e))
|
||||
}
|
||||
|
||||
const unclaimedHomeToForeignRequests = () => {
|
||||
if (MONITOR_HOME_TO_FOREIGN_ALLOWANCE_LIST) {
|
||||
const allowanceList = readAccessListFile(MONITOR_HOME_TO_FOREIGN_ALLOWANCE_LIST)
|
||||
return e => !allowanceList.includes(e.recipient.toLowerCase()) && !(e.sender && allowanceList.includes(e.sender))
|
||||
} else if (MONITOR_HOME_TO_FOREIGN_BLOCK_LIST) {
|
||||
const blockList = readAccessListFile(MONITOR_HOME_TO_FOREIGN_BLOCK_LIST)
|
||||
return e => blockList.includes(e.recipient.toLowerCase()) || (e.sender && blockList.includes(e.sender))
|
||||
} else {
|
||||
return () => false
|
||||
}
|
||||
}
|
||||
|
||||
const manuallyProcessedAMBHomeToForeignRequests = () => {
|
||||
if (MONITOR_HOME_TO_FOREIGN_ALLOWANCE_LIST) {
|
||||
const allowanceList = readAccessListFile(MONITOR_HOME_TO_FOREIGN_ALLOWANCE_LIST)
|
||||
return e => {
|
||||
const { sender, executor, decodedDataType } = normalizeAMBMessageEvent(e)
|
||||
return (!allowanceList.includes(sender) && !allowanceList.includes(executor)) || decodedDataType.manualLane
|
||||
}
|
||||
} else if (MONITOR_HOME_TO_FOREIGN_BLOCK_LIST) {
|
||||
const blockList = readAccessListFile(MONITOR_HOME_TO_FOREIGN_BLOCK_LIST)
|
||||
return e => {
|
||||
const { sender, executor, decodedDataType } = normalizeAMBMessageEvent(e)
|
||||
return blockList.includes(sender) || blockList.includes(executor) || decodedDataType.manualLane
|
||||
}
|
||||
} else {
|
||||
return e => normalizeAMBMessageEvent(e).decodedDataType.manualLane
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
deliveredMsgNotProcessed,
|
||||
processedMsgNotDelivered,
|
||||
addExecutionStatus,
|
||||
normalizeEventInformation,
|
||||
eventWithoutReference
|
||||
eventWithoutReference,
|
||||
unclaimedHomeToForeignRequests,
|
||||
manuallyProcessedAMBHomeToForeignRequests
|
||||
}
|
||||
|
||||
27
monitor/utils/web3.js
Normal file
27
monitor/utils/web3.js
Normal file
@@ -0,0 +1,27 @@
|
||||
require('dotenv').config()
|
||||
const Web3 = require('web3')
|
||||
|
||||
const { COMMON_HOME_RPC_URL, COMMON_FOREIGN_RPC_URL } = process.env
|
||||
|
||||
const homeProvider = new Web3.providers.HttpProvider(COMMON_HOME_RPC_URL)
|
||||
const web3Home = new Web3(homeProvider)
|
||||
|
||||
const foreignProvider = new Web3.providers.HttpProvider(COMMON_FOREIGN_RPC_URL)
|
||||
const web3Foreign = new Web3(foreignProvider)
|
||||
|
||||
function blockNumberWrapper(web3) {
|
||||
let blockNumber = null
|
||||
return async () => {
|
||||
if (!blockNumber) {
|
||||
blockNumber = await web3.eth.getBlockNumber()
|
||||
}
|
||||
return blockNumber
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
web3Home,
|
||||
web3Foreign,
|
||||
getHomeBlockNumber: blockNumberWrapper(web3Home),
|
||||
getForeignBlockNumber: blockNumberWrapper(web3Foreign)
|
||||
}
|
||||
171
monitor/utils/web3Cache.js
Normal file
171
monitor/utils/web3Cache.js
Normal file
@@ -0,0 +1,171 @@
|
||||
const logger = require('../logger')('web3Cache')
|
||||
const { readCacheFile, writeCacheFile } = require('./file')
|
||||
const { web3Home, web3Foreign } = require('./web3')
|
||||
const { getPastEvents: commonGetPastEvents } = require('../../commons')
|
||||
|
||||
const { MONITOR_BRIDGE_NAME, MONITOR_CACHE_EVENTS } = process.env
|
||||
|
||||
let isDirty = false
|
||||
|
||||
const homeTxSendersCacheFile = `./cache/${MONITOR_BRIDGE_NAME}/home/txSenders.json`
|
||||
const cachedHomeTxSenders = readCacheFile(homeTxSendersCacheFile) || {}
|
||||
const foreignTxSendersCacheFile = `./cache/${MONITOR_BRIDGE_NAME}/foreign/txSenders.json`
|
||||
const cachedForeignTxSenders = readCacheFile(foreignTxSendersCacheFile) || {}
|
||||
const homeIsContractCacheFile = `./cache/${MONITOR_BRIDGE_NAME}/home/isContract.json`
|
||||
const cachedHomeIsContract = readCacheFile(homeIsContractCacheFile) || {}
|
||||
const foreignIsContractCacheFile = `./cache/${MONITOR_BRIDGE_NAME}/foreign/isContract.json`
|
||||
const cachedForeignIsContract = readCacheFile(foreignIsContractCacheFile) || {}
|
||||
|
||||
async function getHomeTxSender(txHash) {
|
||||
if (!cachedHomeTxSenders[txHash]) {
|
||||
logger.debug(`Fetching sender for home tx ${txHash}`)
|
||||
cachedHomeTxSenders[txHash] = (await web3Home.eth.getTransaction(txHash)).from.toLowerCase()
|
||||
isDirty = true
|
||||
}
|
||||
return cachedHomeTxSenders[txHash]
|
||||
}
|
||||
|
||||
async function getForeignTxSender(txHash) {
|
||||
if (!cachedForeignTxSenders[txHash]) {
|
||||
logger.debug(`Fetching sender for foreign tx ${txHash}`)
|
||||
cachedForeignTxSenders[txHash] = (await web3Foreign.eth.getTransaction(txHash)).from.toLowerCase()
|
||||
isDirty = true
|
||||
}
|
||||
return cachedForeignTxSenders[txHash]
|
||||
}
|
||||
|
||||
async function isHomeContract(address) {
|
||||
if (typeof cachedHomeIsContract[address] !== 'boolean') {
|
||||
logger.debug(`Fetching home contract code size for tx ${address}`)
|
||||
cachedHomeIsContract[address] = (await web3Home.eth.getCode(address)).length > 2
|
||||
isDirty = true
|
||||
}
|
||||
return cachedHomeIsContract[address]
|
||||
}
|
||||
|
||||
async function isForeignContract(address) {
|
||||
if (typeof cachedForeignIsContract[address] !== 'boolean') {
|
||||
logger.debug(`Fetching foreign contract code size for tx ${address}`)
|
||||
cachedForeignIsContract[address] = (await web3Foreign.eth.getCode(address)).length > 2
|
||||
isDirty = true
|
||||
}
|
||||
return cachedForeignIsContract[address]
|
||||
}
|
||||
|
||||
async function getPastEvents(contract, options) {
|
||||
if (MONITOR_CACHE_EVENTS !== 'true') {
|
||||
return commonGetPastEvents(contract, options)
|
||||
}
|
||||
|
||||
const contractAddr = contract.options.address
|
||||
|
||||
let eventSignature
|
||||
if (options.event.includes('(')) {
|
||||
eventSignature = options.event
|
||||
options.event = web3Home.utils.sha3(eventSignature)
|
||||
const eventABI = contract.options.jsonInterface.find(e => e.type === 'event' && e.signature === options.event)
|
||||
if (!eventABI) {
|
||||
throw new Error(`Event ${eventSignature} not found`)
|
||||
}
|
||||
} else {
|
||||
const eventABI = contract.options.jsonInterface.find(
|
||||
e => e.type === 'event' && (e.name === options.event || e.signature === options.event)
|
||||
)
|
||||
if (!eventABI) {
|
||||
throw new Error(`Event ${options.event} not found`)
|
||||
}
|
||||
eventSignature = `${eventABI.name}(${eventABI.inputs.map(i => i.type).join(',')})`
|
||||
}
|
||||
|
||||
const cacheFile = `./cache/${MONITOR_BRIDGE_NAME}/${options.chain}/${contractAddr}/${eventSignature}.json`
|
||||
|
||||
const { fromBlock, toBlock } = options
|
||||
const { fromBlock: cachedFromBlock, toBlock: cachedToBlock, events: cachedEvents } = readCacheFile(cacheFile) || {
|
||||
fromBlock: 0,
|
||||
toBlock: 0,
|
||||
events: []
|
||||
}
|
||||
|
||||
let result
|
||||
if (cachedFromBlock > toBlock || fromBlock > cachedToBlock) {
|
||||
// requested: A...B
|
||||
// cached: C...D
|
||||
// OR
|
||||
// requested: A...B
|
||||
// cached: C...D
|
||||
logger.debug(`Fetching events for blocks ${fromBlock}...${toBlock}`)
|
||||
result = await commonGetPastEvents(contract, options)
|
||||
} else if (fromBlock < cachedFromBlock && toBlock <= cachedToBlock) {
|
||||
// requested: A...B
|
||||
// cached: C...D
|
||||
logger.debug(`Cache hit for blocks ${cachedFromBlock}...${toBlock}`)
|
||||
logger.debug(`Fetching events for blocks ${fromBlock}...${cachedFromBlock - 1}`)
|
||||
result = [
|
||||
...(await commonGetPastEvents(contract, { ...options, toBlock: cachedFromBlock - 1 })),
|
||||
...cachedEvents.filter(e => e.blockNumber <= toBlock)
|
||||
]
|
||||
} else if (fromBlock < cachedFromBlock && cachedToBlock < toBlock) {
|
||||
// requested: A.....B
|
||||
// cached: C.D
|
||||
logger.debug(`Cache hit for blocks ${cachedFromBlock}...${cachedToBlock}`)
|
||||
logger.debug(`Fetching events for blocks ${fromBlock}...${cachedFromBlock - 1}`)
|
||||
logger.debug(`Fetching events for blocks ${cachedToBlock + 1}...${toBlock}`)
|
||||
result = [
|
||||
...(await commonGetPastEvents(contract, { ...options, toBlock: cachedFromBlock - 1 })),
|
||||
...cachedEvents,
|
||||
...(await commonGetPastEvents(contract, { ...options, fromBlock: cachedToBlock + 1 }))
|
||||
]
|
||||
} else if (cachedFromBlock <= fromBlock && toBlock <= cachedToBlock) {
|
||||
// requested: A.B
|
||||
// cached: C.....D
|
||||
logger.debug(`Cache hit for blocks ${fromBlock}...${toBlock}`)
|
||||
result = cachedEvents.filter(e => fromBlock <= e.blockNumber && e.blockNumber <= toBlock)
|
||||
} else if (fromBlock >= cachedFromBlock && toBlock > cachedToBlock) {
|
||||
// requested: A...B
|
||||
// cached: C...D
|
||||
logger.debug(`Cache hit for blocks ${fromBlock}...${cachedToBlock}`)
|
||||
logger.debug(`Fetching events for blocks ${cachedToBlock + 1}...${toBlock}`)
|
||||
result = [
|
||||
...cachedEvents.filter(e => e.blockNumber >= fromBlock),
|
||||
...(await commonGetPastEvents(contract, { ...options, fromBlock: cachedToBlock + 1 }))
|
||||
]
|
||||
} else {
|
||||
throw new Error(
|
||||
`Something is broken with cache resolution for getPastEvents,
|
||||
requested blocks ${fromBlock}...${toBlock},
|
||||
cached blocks ${cachedFromBlock}...${cachedToBlock}`
|
||||
)
|
||||
}
|
||||
|
||||
// it is not safe to cache events with too low block confirmations
|
||||
// so, only events from finalized blocks are included into the cache
|
||||
const safeToBlock = options.safeToBlock || toBlock
|
||||
const cacheToSave = result.filter(e => e.blockNumber <= safeToBlock)
|
||||
logger.debug(
|
||||
`Saving events cache for ${MONITOR_BRIDGE_NAME}/${options.chain}/${contractAddr}/${eventSignature} on disk`
|
||||
)
|
||||
writeCacheFile(cacheFile, {
|
||||
fromBlock,
|
||||
toBlock: safeToBlock,
|
||||
events: cacheToSave
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
function saveCache() {
|
||||
if (isDirty) {
|
||||
logger.debug('Saving cache on disk')
|
||||
writeCacheFile(homeTxSendersCacheFile, cachedHomeTxSenders)
|
||||
writeCacheFile(homeIsContractCacheFile, cachedHomeIsContract)
|
||||
writeCacheFile(foreignIsContractCacheFile, cachedForeignIsContract)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getHomeTxSender,
|
||||
getForeignTxSender,
|
||||
isHomeContract,
|
||||
isForeignContract,
|
||||
getPastEvents,
|
||||
saveCache
|
||||
}
|
||||
@@ -1,13 +1,12 @@
|
||||
require('dotenv').config()
|
||||
const Web3 = require('web3')
|
||||
const Web3Utils = require('web3').utils
|
||||
const fetch = require('node-fetch')
|
||||
const logger = require('./logger')('validators')
|
||||
const { getBridgeABIs, BRIDGE_VALIDATORS_ABI, getValidatorList, gasPriceFromSupplier } = require('../commons')
|
||||
const { getBlockNumber } = require('./utils/contract')
|
||||
const { getBridgeABIs, BRIDGE_VALIDATORS_ABI, gasPriceFromSupplier } = require('../commons')
|
||||
const { web3Home, web3Foreign, getHomeBlockNumber, getForeignBlockNumber } = require('./utils/web3')
|
||||
const { getValidatorList } = require('./utils/getValidatorsList')
|
||||
|
||||
const {
|
||||
COMMON_HOME_RPC_URL,
|
||||
COMMON_FOREIGN_RPC_URL,
|
||||
COMMON_HOME_BRIDGE_ADDRESS,
|
||||
COMMON_FOREIGN_BRIDGE_ADDRESS,
|
||||
COMMON_HOME_GAS_PRICE_SUPPLIER_URL,
|
||||
@@ -17,20 +16,13 @@ const {
|
||||
COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL,
|
||||
COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE,
|
||||
COMMON_FOREIGN_GAS_PRICE_FALLBACK,
|
||||
COMMON_FOREIGN_GAS_PRICE_FACTOR
|
||||
COMMON_FOREIGN_GAS_PRICE_FACTOR,
|
||||
MONITOR_FOREIGN_VALIDATORS_BALANCE_ENABLE,
|
||||
MONITOR_HOME_VALIDATORS_BALANCE_ENABLE
|
||||
} = process.env
|
||||
const MONITOR_HOME_START_BLOCK = Number(process.env.MONITOR_HOME_START_BLOCK) || 0
|
||||
const MONITOR_FOREIGN_START_BLOCK = Number(process.env.MONITOR_FOREIGN_START_BLOCK) || 0
|
||||
const MONITOR_VALIDATOR_HOME_TX_LIMIT = Number(process.env.MONITOR_VALIDATOR_HOME_TX_LIMIT) || 0
|
||||
const MONITOR_VALIDATOR_FOREIGN_TX_LIMIT = Number(process.env.MONITOR_VALIDATOR_FOREIGN_TX_LIMIT) || 0
|
||||
|
||||
const Web3Utils = Web3.utils
|
||||
|
||||
const homeProvider = new Web3.providers.HttpProvider(COMMON_HOME_RPC_URL)
|
||||
const web3Home = new Web3(homeProvider)
|
||||
|
||||
const foreignProvider = new Web3.providers.HttpProvider(COMMON_FOREIGN_RPC_URL)
|
||||
const web3Foreign = new Web3(foreignProvider)
|
||||
const MONITOR_TX_NUMBER_THRESHOLD = Number(process.env.MONITOR_TX_NUMBER_THRESHOLD) || 100
|
||||
|
||||
const homeGasPriceSupplierOpts = {
|
||||
speedType: COMMON_HOME_GAS_PRICE_SPEED_TYPE,
|
||||
@@ -44,12 +36,6 @@ const foreignGasPriceSupplierOpts = {
|
||||
logger
|
||||
}
|
||||
|
||||
const asyncForEach = async (array, callback) => {
|
||||
for (let index = 0; index < array.length; index++) {
|
||||
await callback(array[index], index, array)
|
||||
}
|
||||
}
|
||||
|
||||
async function main(bridgeMode) {
|
||||
const { HOME_ABI, FOREIGN_ABI } = getBridgeABIs(bridgeMode)
|
||||
const homeBridge = new web3Home.eth.Contract(HOME_ABI, COMMON_HOME_BRIDGE_ADDRESS)
|
||||
@@ -58,7 +44,12 @@ async function main(bridgeMode) {
|
||||
const homeBridgeValidators = new web3Home.eth.Contract(BRIDGE_VALIDATORS_ABI, homeValidatorsAddress)
|
||||
|
||||
logger.debug('getting last block numbers')
|
||||
const [homeBlockNumber, foreignBlockNumber] = await getBlockNumber(web3Home, web3Foreign)
|
||||
const homeBlockNumber = await getHomeBlockNumber()
|
||||
const foreignBlockNumber = await getForeignBlockNumber()
|
||||
const homeConfirmations = await homeBridge.methods.requiredBlockConfirmations().call()
|
||||
const foreignConfirmations = await foreignBridge.methods.requiredBlockConfirmations().call()
|
||||
const homeDelayedBlockNumber = homeBlockNumber - homeConfirmations
|
||||
const foreignDelayedBlockNumber = foreignBlockNumber - foreignConfirmations
|
||||
|
||||
logger.debug('calling foreignBridge.methods.validatorContract().call()')
|
||||
const foreignValidatorsAddress = await foreignBridge.methods.validatorContract().call()
|
||||
@@ -66,16 +57,18 @@ async function main(bridgeMode) {
|
||||
|
||||
logger.debug('calling foreignBridgeValidators getValidatorList()')
|
||||
const foreignValidators = (await getValidatorList(foreignValidatorsAddress, web3Foreign.eth, {
|
||||
from: MONITOR_FOREIGN_START_BLOCK,
|
||||
to: foreignBlockNumber,
|
||||
logger
|
||||
toBlock: foreignBlockNumber,
|
||||
logger,
|
||||
chain: 'foreign',
|
||||
safeToBlock: foreignDelayedBlockNumber
|
||||
})).map(web3Foreign.utils.toChecksumAddress)
|
||||
|
||||
logger.debug('calling homeBridgeValidators getValidatorList()')
|
||||
const homeValidators = (await getValidatorList(homeValidatorsAddress, web3Home.eth, {
|
||||
from: MONITOR_HOME_START_BLOCK,
|
||||
to: homeBlockNumber,
|
||||
logger
|
||||
toBlock: homeBlockNumber,
|
||||
logger,
|
||||
chain: 'home',
|
||||
safeToBlock: homeDelayedBlockNumber
|
||||
})).map(web3Home.utils.toChecksumAddress)
|
||||
|
||||
const foreignVBalances = {}
|
||||
@@ -113,53 +106,61 @@ async function main(bridgeMode) {
|
||||
}
|
||||
|
||||
let validatorsMatch = true
|
||||
logger.debug('calling asyncForEach foreignValidators foreignVBalances')
|
||||
await asyncForEach(foreignValidators, async v => {
|
||||
const balance = await web3Foreign.eth.getBalance(v)
|
||||
if (MONITOR_VALIDATOR_FOREIGN_TX_LIMIT) {
|
||||
const leftTx = Web3Utils.toBN(balance)
|
||||
.div(foreignTxCost)
|
||||
.toString(10)
|
||||
foreignVBalances[v] = {
|
||||
balance: Web3Utils.fromWei(balance),
|
||||
leftTx: Number(leftTx),
|
||||
gasPrice: Number(foreignGasPriceGwei)
|
||||
const foreignValidatorsWithBalanceCheck =
|
||||
typeof MONITOR_FOREIGN_VALIDATORS_BALANCE_ENABLE === 'string'
|
||||
? MONITOR_FOREIGN_VALIDATORS_BALANCE_ENABLE.split(' ')
|
||||
: foreignValidators
|
||||
logger.debug('getting foreignValidators balances')
|
||||
await Promise.all(
|
||||
foreignValidators.map(async v => {
|
||||
foreignVBalances[v] = {}
|
||||
if (foreignValidatorsWithBalanceCheck.includes(v)) {
|
||||
const balance = await web3Foreign.eth.getBalance(v)
|
||||
foreignVBalances[v].balance = Web3Utils.fromWei(balance)
|
||||
if (MONITOR_VALIDATOR_FOREIGN_TX_LIMIT) {
|
||||
foreignVBalances[v].leftTx = Number(
|
||||
Web3Utils.toBN(balance)
|
||||
.div(foreignTxCost)
|
||||
.toString(10)
|
||||
)
|
||||
foreignVBalances[v].gasPrice = parseFloat(foreignGasPriceGwei)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
foreignVBalances[v] = {
|
||||
balance: Web3Utils.fromWei(balance)
|
||||
}
|
||||
}
|
||||
|
||||
if (!homeValidators.includes(v)) {
|
||||
validatorsMatch = false
|
||||
foreignVBalances[v].onlyOnForeign = true
|
||||
}
|
||||
})
|
||||
|
||||
logger.debug('calling asyncForEach homeValidators homeVBalances')
|
||||
await asyncForEach(homeValidators, async v => {
|
||||
const balance = await web3Home.eth.getBalance(v)
|
||||
if (MONITOR_VALIDATOR_HOME_TX_LIMIT) {
|
||||
const leftTx = Web3Utils.toBN(balance)
|
||||
.div(homeTxCost)
|
||||
.toString(10)
|
||||
homeVBalances[v] = {
|
||||
balance: Web3Utils.fromWei(balance),
|
||||
leftTx: Number(leftTx),
|
||||
gasPrice: Number(homeGasPriceGwei)
|
||||
if (!homeValidators.includes(v)) {
|
||||
validatorsMatch = false
|
||||
foreignVBalances[v].onlyOnForeign = true
|
||||
}
|
||||
} else {
|
||||
homeVBalances[v] = {
|
||||
balance: Web3Utils.fromWei(balance)
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
if (!foreignValidators.includes(v)) {
|
||||
validatorsMatch = false
|
||||
homeVBalances[v].onlyOnHome = true
|
||||
}
|
||||
})
|
||||
const homeValidatorsWithBalanceCheck =
|
||||
typeof MONITOR_HOME_VALIDATORS_BALANCE_ENABLE === 'string'
|
||||
? MONITOR_HOME_VALIDATORS_BALANCE_ENABLE.split(' ')
|
||||
: homeValidators
|
||||
logger.debug('calling homeValidators balances')
|
||||
await Promise.all(
|
||||
homeValidators.map(async v => {
|
||||
homeVBalances[v] = {}
|
||||
if (homeValidatorsWithBalanceCheck.includes(v)) {
|
||||
const balance = await web3Home.eth.getBalance(v)
|
||||
homeVBalances[v].balance = Web3Utils.fromWei(balance)
|
||||
if (MONITOR_VALIDATOR_HOME_TX_LIMIT) {
|
||||
homeVBalances[v].leftTx = Number(
|
||||
Web3Utils.toBN(balance)
|
||||
.div(homeTxCost)
|
||||
.toString(10)
|
||||
)
|
||||
homeVBalances[v].gasPrice = parseFloat(homeGasPriceGwei)
|
||||
}
|
||||
}
|
||||
|
||||
if (!foreignValidators.includes(v)) {
|
||||
validatorsMatch = false
|
||||
homeVBalances[v].onlyOnHome = true
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
logger.debug('calling homeBridgeValidators.methods.requiredSignatures().call()')
|
||||
const reqSigHome = await homeBridgeValidators.methods.requiredSignatures().call()
|
||||
@@ -168,20 +169,22 @@ async function main(bridgeMode) {
|
||||
logger.debug('Done')
|
||||
return {
|
||||
home: {
|
||||
validators: {
|
||||
...homeVBalances
|
||||
},
|
||||
validators: homeVBalances,
|
||||
requiredSignatures: Number(reqSigHome)
|
||||
},
|
||||
foreign: {
|
||||
validators: {
|
||||
...foreignVBalances
|
||||
},
|
||||
validators: foreignVBalances,
|
||||
requiredSignatures: Number(reqSigForeign)
|
||||
},
|
||||
requiredSignaturesMatch: reqSigHome === reqSigForeign,
|
||||
validatorsMatch,
|
||||
lastChecked: Math.floor(Date.now() / 1000)
|
||||
lastChecked: Math.floor(Date.now() / 1000),
|
||||
homeOk: Object.values(homeVBalances)
|
||||
.filter(vb => typeof vb.leftTx === 'number')
|
||||
.every(vb => vb.leftTx >= MONITOR_TX_NUMBER_THRESHOLD),
|
||||
foreignOk: Object.values(foreignVBalances)
|
||||
.filter(vb => typeof vb.leftTx === 'number')
|
||||
.every(vb => vb.leftTx >= MONITOR_TX_NUMBER_THRESHOLD)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,24 @@
|
||||
cd $(dirname $0)
|
||||
|
||||
../e2e-commons/up.sh deploy blocks oracle oracle-validator-2 oracle-validator-3
|
||||
mode="$1"
|
||||
case "$mode" in
|
||||
amb)
|
||||
script=./test/amb.js
|
||||
;;
|
||||
native-to-erc)
|
||||
script=./test/nativeToErc.js
|
||||
;;
|
||||
erc-to-erc)
|
||||
script=./test/ercToErc.js
|
||||
;;
|
||||
erc-to-native)
|
||||
script=./test/ercToNative.js
|
||||
;;
|
||||
esac
|
||||
|
||||
docker-compose -f ../e2e-commons/docker-compose.yml run e2e yarn workspace oracle-e2e run start
|
||||
MODE="$mode" ../e2e-commons/up.sh deploy blocks oracle oracle-validator-2 oracle-validator-3
|
||||
|
||||
docker-compose -f ../e2e-commons/docker-compose.yml run e2e yarn workspace oracle-e2e run start $script
|
||||
rc=$?
|
||||
|
||||
../e2e-commons/down.sh
|
||||
|
||||
@@ -3,7 +3,7 @@ const assert = require('assert')
|
||||
const { user, homeRPC, foreignRPC, amb, validator } = require('../../e2e-commons/constants.json')
|
||||
const { uniformRetry } = require('../../e2e-commons/utils')
|
||||
const { BOX_ABI, HOME_AMB_ABI, FOREIGN_AMB_ABI } = require('../../commons')
|
||||
const { setRequiredSignatures } = require('./utils')
|
||||
const { delay, setRequiredSignatures } = require('./utils')
|
||||
|
||||
const { toBN } = Web3.utils
|
||||
|
||||
@@ -19,14 +19,17 @@ foreignWeb3.eth.accounts.wallet.add(user.privateKey)
|
||||
foreignWeb3.eth.accounts.wallet.add(validator.privateKey)
|
||||
|
||||
const homeBox = new homeWeb3.eth.Contract(BOX_ABI, amb.homeBox)
|
||||
const blockHomeBox = new homeWeb3.eth.Contract(BOX_ABI, amb.blockedHomeBox)
|
||||
const foreignBox = new foreignWeb3.eth.Contract(BOX_ABI, amb.foreignBox)
|
||||
const homeBridge = new homeWeb3.eth.Contract(HOME_AMB_ABI, COMMON_HOME_BRIDGE_ADDRESS)
|
||||
const foreignBridge = new foreignWeb3.eth.Contract(FOREIGN_AMB_ABI, COMMON_FOREIGN_BRIDGE_ADDRESS)
|
||||
|
||||
describe('arbitrary message bridging', () => {
|
||||
let requiredSignatures = 1
|
||||
before(async () => {
|
||||
// Only 1 validator is used in ultimate tests
|
||||
if (process.env.ULTIMATE !== 'true') {
|
||||
requiredSignatures = 2
|
||||
// Set 2 required signatures for home bridge
|
||||
await setRequiredSignatures({
|
||||
bridgeContract: homeBridge,
|
||||
@@ -76,6 +79,85 @@ describe('arbitrary message bridging', () => {
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// allowance/block lists files are not mounted to the host during the ultimate test
|
||||
if (process.env.ULTIMATE !== 'true') {
|
||||
it('should confirm but not relay message from blocked contract', async () => {
|
||||
const newValue = 4
|
||||
|
||||
const initialValue = await foreignBox.methods.value().call()
|
||||
assert(!toBN(initialValue).eq(toBN(newValue)), 'initial value should be different from new value')
|
||||
|
||||
const signatures = await homeBridge.getPastEvents('SignedForUserRequest', {
|
||||
fromBlock: 0,
|
||||
toBlock: 'latest'
|
||||
})
|
||||
|
||||
await blockHomeBox.methods
|
||||
.setValueOnOtherNetwork(newValue, amb.home, amb.foreignBox)
|
||||
.send({
|
||||
from: user.address,
|
||||
gas: '400000'
|
||||
})
|
||||
.catch(e => {
|
||||
console.error(e)
|
||||
})
|
||||
|
||||
await delay(5000)
|
||||
|
||||
const newSignatures = await homeBridge.getPastEvents('SignedForUserRequest', {
|
||||
fromBlock: 0,
|
||||
toBlock: 'latest'
|
||||
})
|
||||
|
||||
assert(
|
||||
newSignatures.length === signatures.length + requiredSignatures,
|
||||
`Incorrect amount of signatures submitted, got ${newSignatures.length}, expected ${signatures.length +
|
||||
requiredSignatures}`
|
||||
)
|
||||
|
||||
const value = await foreignBox.methods.value().call()
|
||||
assert(!toBN(value).eq(toBN(newValue)), 'Message should not be relayed by oracle automatically')
|
||||
})
|
||||
}
|
||||
|
||||
it('should confirm but not relay message from manual lane', async () => {
|
||||
const newValue = 5
|
||||
|
||||
const initialValue = await foreignBox.methods.value().call()
|
||||
assert(!toBN(initialValue).eq(toBN(newValue)), 'initial value should be different from new value')
|
||||
|
||||
const signatures = await homeBridge.getPastEvents('SignedForUserRequest', {
|
||||
fromBlock: 0,
|
||||
toBlock: 'latest'
|
||||
})
|
||||
|
||||
await homeBox.methods
|
||||
.setValueOnOtherNetworkUsingManualLane(newValue, amb.home, amb.foreignBox)
|
||||
.send({
|
||||
from: user.address,
|
||||
gas: '400000'
|
||||
})
|
||||
.catch(e => {
|
||||
console.error(e)
|
||||
})
|
||||
|
||||
await delay(10000)
|
||||
|
||||
const newSignatures = await homeBridge.getPastEvents('SignedForUserRequest', {
|
||||
fromBlock: 0,
|
||||
toBlock: 'latest'
|
||||
})
|
||||
|
||||
assert(
|
||||
newSignatures.length === signatures.length + requiredSignatures,
|
||||
`Incorrect amount of signatures submitted, got ${newSignatures.length}, expected ${signatures.length +
|
||||
requiredSignatures}`
|
||||
)
|
||||
|
||||
const value = await foreignBox.methods.value().call()
|
||||
assert(!toBN(value).eq(toBN(newValue)), 'Message should not be relayed by oracle automatically')
|
||||
})
|
||||
})
|
||||
})
|
||||
describe('Foreign to Home', () => {
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
const { BRIDGE_VALIDATORS_ABI } = require('../../commons')
|
||||
|
||||
async function delay(ms) {
|
||||
return new Promise(res => setTimeout(res, ms))
|
||||
}
|
||||
|
||||
const setRequiredSignatures = async ({ bridgeContract, web3, requiredSignatures, options }) => {
|
||||
const validatorAddress = await bridgeContract.methods.validatorContract().call()
|
||||
const validatorContract = new web3.eth.Contract(BRIDGE_VALIDATORS_ABI, validatorAddress)
|
||||
@@ -8,5 +12,6 @@ const setRequiredSignatures = async ({ bridgeContract, web3, requiredSignatures,
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
delay,
|
||||
setRequiredSignatures
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ ORACLE_FOREIGN_START_BLOCK=
|
||||
|
||||
ORACLE_LOG_LEVEL=debug
|
||||
ORACLE_MAX_PROCESSING_TIME=20000
|
||||
ORACLE_RPC_REQUEST_TIMEOUT=5000
|
||||
|
||||
ORACLE_HOME_TO_FOREIGN_ALLOWANCE_LIST=access-lists/allowance_list.txt
|
||||
ORACLE_HOME_TO_FOREIGN_BLOCK_LIST=access-lists/block_list.txt
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const baseConfig = require('./base.config')
|
||||
|
||||
const { web3Foreign } = require('../src/services/web3')
|
||||
const { web3Foreign, web3ForeignRedundant, web3ForeignFallback } = require('../src/services/web3')
|
||||
|
||||
module.exports = {
|
||||
...baseConfig.bridgeConfig,
|
||||
@@ -8,5 +8,7 @@ module.exports = {
|
||||
oldQueue: 'foreign',
|
||||
id: 'foreign',
|
||||
name: 'sender-foreign',
|
||||
web3: web3Foreign
|
||||
web3: web3Foreign,
|
||||
web3Redundant: web3ForeignRedundant,
|
||||
web3Fallback: web3ForeignFallback
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const baseConfig = require('./base.config')
|
||||
|
||||
const { web3Home } = require('../src/services/web3')
|
||||
const { web3Home, web3HomeRedundant, web3HomeFallback } = require('../src/services/web3')
|
||||
|
||||
module.exports = {
|
||||
...baseConfig.bridgeConfig,
|
||||
@@ -8,5 +8,7 @@ module.exports = {
|
||||
oldQueue: 'home',
|
||||
id: 'home',
|
||||
name: 'sender-home',
|
||||
web3: web3Home
|
||||
web3: web3Home,
|
||||
web3Redundant: web3HomeRedundant,
|
||||
web3Fallback: web3HomeFallback
|
||||
}
|
||||
|
||||
@@ -26,15 +26,13 @@
|
||||
"amqplib": "^0.5.2",
|
||||
"bignumber.js": "^7.2.1",
|
||||
"dotenv": "^5.0.1",
|
||||
"http-list-provider": "0.0.5",
|
||||
"ioredis": "^3.2.2",
|
||||
"node-fetch": "^2.1.2",
|
||||
"pino": "^4.17.3",
|
||||
"pino-pretty": "^2.0.1",
|
||||
"promise-limit": "^2.7.0",
|
||||
"promise-retry": "^1.1.1",
|
||||
"web3": "1.0.0-beta.34",
|
||||
"web3-utils": "1.0.0-beta.34"
|
||||
"web3": "^1.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"bn-chai": "^1.0.1",
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
require('../../env')
|
||||
const Web3 = require('web3')
|
||||
const Web3Utils = require('web3-utils')
|
||||
const rpcUrlsManager = require('../../src/services/getRpcUrlsManager')
|
||||
const { sendTx, sendRawTx } = require('../../src/tx/sendTx')
|
||||
const { toWei } = require('web3').utils
|
||||
const { web3Foreign } = require('../../src/services/web3')
|
||||
const { sendTx } = require('../../src/tx/sendTx')
|
||||
const { ERC20_ABI } = require('../../../commons')
|
||||
|
||||
const {
|
||||
@@ -17,37 +16,23 @@ const NUMBER_OF_DEPOSITS_TO_SEND = process.argv[2] || process.env.NUMBER_OF_DEPO
|
||||
|
||||
const { FOREIGN_ERC_TO_ERC_ABI } = require('../../../commons')
|
||||
|
||||
const foreignRpcUrl = rpcUrlsManager.foreignUrls[0]
|
||||
const foreignProvider = new Web3.providers.HttpProvider(foreignRpcUrl)
|
||||
const web3Foreign = new Web3(foreignProvider)
|
||||
|
||||
async function main() {
|
||||
const bridge = new web3Foreign.eth.Contract(FOREIGN_ERC_TO_ERC_ABI, COMMON_FOREIGN_BRIDGE_ADDRESS)
|
||||
const bridgeableTokenAddress = await bridge.methods.erc20token().call()
|
||||
const poa20 = new web3Foreign.eth.Contract(ERC20_ABI, bridgeableTokenAddress)
|
||||
|
||||
try {
|
||||
const foreignChainId = await sendRawTx({
|
||||
chain: 'foreign',
|
||||
params: [],
|
||||
method: 'net_version'
|
||||
})
|
||||
let nonce = await sendRawTx({
|
||||
chain: 'foreign',
|
||||
method: 'eth_getTransactionCount',
|
||||
params: [USER_ADDRESS, 'latest']
|
||||
})
|
||||
nonce = Web3Utils.hexToNumber(nonce)
|
||||
const foreignChainId = await web3Foreign.eth.getChainId()
|
||||
let nonce = await web3Foreign.eth.getTransactionCount(USER_ADDRESS)
|
||||
let actualSent = 0
|
||||
for (let i = 0; i < Number(NUMBER_OF_DEPOSITS_TO_SEND); i++) {
|
||||
const gasLimit = await poa20.methods
|
||||
.transfer(COMMON_FOREIGN_BRIDGE_ADDRESS, Web3Utils.toWei(FOREIGN_MIN_AMOUNT_PER_TX))
|
||||
.transfer(COMMON_FOREIGN_BRIDGE_ADDRESS, toWei(FOREIGN_MIN_AMOUNT_PER_TX))
|
||||
.estimateGas({ from: USER_ADDRESS })
|
||||
const data = await poa20.methods
|
||||
.transfer(COMMON_FOREIGN_BRIDGE_ADDRESS, Web3Utils.toWei(FOREIGN_MIN_AMOUNT_PER_TX))
|
||||
.transfer(COMMON_FOREIGN_BRIDGE_ADDRESS, toWei(FOREIGN_MIN_AMOUNT_PER_TX))
|
||||
.encodeABI({ from: USER_ADDRESS })
|
||||
const txHash = await sendTx({
|
||||
chain: 'foreign',
|
||||
privateKey: USER_ADDRESS_PRIVATE_KEY,
|
||||
data,
|
||||
nonce,
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
require('../../env')
|
||||
const Web3 = require('web3')
|
||||
const Web3Utils = require('web3-utils')
|
||||
const rpcUrlsManager = require('../../src/services/getRpcUrlsManager')
|
||||
const { sendTx, sendRawTx } = require('../../src/tx/sendTx')
|
||||
const { toWei } = require('web3').utils
|
||||
const { web3Home } = require('../../src/services/web3')
|
||||
const { sendTx } = require('../../src/tx/sendTx')
|
||||
const { isValidAmount } = require('../utils/utils')
|
||||
const { HOME_ERC_TO_ERC_ABI } = require('../../../commons')
|
||||
|
||||
@@ -46,10 +45,6 @@ const BRIDGEABLE_TOKEN_ABI = [
|
||||
}
|
||||
]
|
||||
|
||||
const homeRpcUrl = rpcUrlsManager.homeUrls[0]
|
||||
const homeProvider = new Web3.providers.HttpProvider(homeRpcUrl)
|
||||
const web3Home = new Web3(homeProvider)
|
||||
|
||||
async function main() {
|
||||
const bridge = new web3Home.eth.Contract(HOME_ERC_TO_ERC_ABI, COMMON_HOME_BRIDGE_ADDRESS)
|
||||
const BRIDGEABLE_TOKEN_ADDRESS = await bridge.methods.erc677token().call()
|
||||
@@ -58,27 +53,17 @@ async function main() {
|
||||
try {
|
||||
await isValidAmount(HOME_MIN_AMOUNT_PER_TX, bridge)
|
||||
|
||||
const homeChainId = await sendRawTx({
|
||||
chain: 'home',
|
||||
params: [],
|
||||
method: 'net_version'
|
||||
})
|
||||
let nonce = await sendRawTx({
|
||||
chain: 'home',
|
||||
method: 'eth_getTransactionCount',
|
||||
params: [USER_ADDRESS, 'latest']
|
||||
})
|
||||
nonce = Web3Utils.hexToNumber(nonce)
|
||||
const homeChainId = await web3Home.eth.getChainId()
|
||||
let nonce = await web3Home.eth.getTransactionCount(USER_ADDRESS)
|
||||
let actualSent = 0
|
||||
for (let i = 0; i < Number(NUMBER_OF_WITHDRAWALS_TO_SEND); i++) {
|
||||
const gasLimit = await erc677.methods
|
||||
.transferAndCall(COMMON_HOME_BRIDGE_ADDRESS, Web3Utils.toWei(HOME_MIN_AMOUNT_PER_TX), '0x')
|
||||
.transferAndCall(COMMON_HOME_BRIDGE_ADDRESS, toWei(HOME_MIN_AMOUNT_PER_TX), '0x')
|
||||
.estimateGas({ from: USER_ADDRESS })
|
||||
const data = await erc677.methods
|
||||
.transferAndCall(COMMON_HOME_BRIDGE_ADDRESS, Web3Utils.toWei(HOME_MIN_AMOUNT_PER_TX), '0x')
|
||||
.transferAndCall(COMMON_HOME_BRIDGE_ADDRESS, toWei(HOME_MIN_AMOUNT_PER_TX), '0x')
|
||||
.encodeABI({ from: USER_ADDRESS })
|
||||
const txHash = await sendTx({
|
||||
chain: 'home',
|
||||
privateKey: USER_ADDRESS_PRIVATE_KEY,
|
||||
data,
|
||||
nonce,
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
require('../../env')
|
||||
const Web3 = require('web3')
|
||||
const Web3Utils = require('web3-utils')
|
||||
const rpcUrlsManager = require('../../src/services/getRpcUrlsManager')
|
||||
const { sendTx, sendRawTx } = require('../../src/tx/sendTx')
|
||||
const { toWei } = require('web3').utils
|
||||
const { web3Foreign } = require('../../src/services/web3')
|
||||
const { sendTx } = require('../../src/tx/sendTx')
|
||||
|
||||
const {
|
||||
USER_ADDRESS,
|
||||
@@ -16,37 +15,23 @@ const NUMBER_OF_DEPOSITS_TO_SEND = process.argv[2] || process.env.NUMBER_OF_DEPO
|
||||
|
||||
const { ERC20_ABI, FOREIGN_ERC_TO_NATIVE_ABI } = require('../../../commons')
|
||||
|
||||
const foreignRpcUrl = rpcUrlsManager.foreignUrls[0]
|
||||
const foreignProvider = new Web3.providers.HttpProvider(foreignRpcUrl)
|
||||
const web3Foreign = new Web3(foreignProvider)
|
||||
|
||||
async function main() {
|
||||
const bridge = new web3Foreign.eth.Contract(FOREIGN_ERC_TO_NATIVE_ABI, COMMON_FOREIGN_BRIDGE_ADDRESS)
|
||||
const bridgeableTokenAddress = await bridge.methods.erc20token().call()
|
||||
const poa20 = new web3Foreign.eth.Contract(ERC20_ABI, bridgeableTokenAddress)
|
||||
|
||||
try {
|
||||
const foreignChainId = await sendRawTx({
|
||||
chain: 'foreign',
|
||||
params: [],
|
||||
method: 'net_version'
|
||||
})
|
||||
let nonce = await sendRawTx({
|
||||
chain: 'foreign',
|
||||
method: 'eth_getTransactionCount',
|
||||
params: [USER_ADDRESS, 'latest']
|
||||
})
|
||||
nonce = Web3Utils.hexToNumber(nonce)
|
||||
const foreignChainId = await web3Foreign.eth.getChainId()
|
||||
let nonce = await web3Foreign.eth.getTransactionCount(USER_ADDRESS)
|
||||
let actualSent = 0
|
||||
for (let i = 0; i < Number(NUMBER_OF_DEPOSITS_TO_SEND); i++) {
|
||||
const gasLimit = await poa20.methods
|
||||
.transfer(COMMON_FOREIGN_BRIDGE_ADDRESS, Web3Utils.toWei(FOREIGN_MIN_AMOUNT_PER_TX))
|
||||
.transfer(COMMON_FOREIGN_BRIDGE_ADDRESS, toWei(FOREIGN_MIN_AMOUNT_PER_TX))
|
||||
.estimateGas({ from: USER_ADDRESS })
|
||||
const data = await poa20.methods
|
||||
.transfer(COMMON_FOREIGN_BRIDGE_ADDRESS, Web3Utils.toWei(FOREIGN_MIN_AMOUNT_PER_TX))
|
||||
.transfer(COMMON_FOREIGN_BRIDGE_ADDRESS, toWei(FOREIGN_MIN_AMOUNT_PER_TX))
|
||||
.encodeABI({ from: USER_ADDRESS })
|
||||
const txHash = await sendTx({
|
||||
chain: 'foreign',
|
||||
privateKey: USER_ADDRESS_PRIVATE_KEY,
|
||||
data,
|
||||
nonce,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
require('../../env')
|
||||
const Web3Utils = require('web3-utils')
|
||||
const { web3Home } = require('../../src/services/web3')
|
||||
const { sendTx, sendRawTx } = require('../../src/tx/sendTx')
|
||||
const { sendTx } = require('../../src/tx/sendTx')
|
||||
const { isValidAmount } = require('../utils/utils')
|
||||
const { HOME_ERC_TO_NATIVE_ABI } = require('../../../commons')
|
||||
|
||||
@@ -21,21 +20,11 @@ async function main() {
|
||||
try {
|
||||
await isValidAmount(HOME_MIN_AMOUNT_PER_TX, bridge)
|
||||
|
||||
const homeChainId = await sendRawTx({
|
||||
chain: 'home',
|
||||
params: [],
|
||||
method: 'net_version'
|
||||
})
|
||||
let nonce = await sendRawTx({
|
||||
chain: 'home',
|
||||
method: 'eth_getTransactionCount',
|
||||
params: [USER_ADDRESS, 'latest']
|
||||
})
|
||||
nonce = Web3Utils.hexToNumber(nonce)
|
||||
const homeChainId = await web3Home.eth.getChainId()
|
||||
let nonce = await web3Home.eth.getTransactionCount(USER_ADDRESS)
|
||||
let actualSent = 0
|
||||
for (let i = 0; i < Number(NUMBER_OF_DEPOSITS_TO_SEND); i++) {
|
||||
const txHash = await sendTx({
|
||||
chain: 'home',
|
||||
privateKey: USER_ADDRESS_PRIVATE_KEY,
|
||||
data: '0x',
|
||||
nonce,
|
||||
|
||||
@@ -1,23 +1,20 @@
|
||||
require('../env')
|
||||
const Web3 = require('web3')
|
||||
|
||||
const { BRIDGE_VALIDATORS_ABI } = require('../../commons')
|
||||
const rpcUrlsManager = require('../src/services/getRpcUrlsManager')
|
||||
const { web3Home, web3Foreign } = require('../src/services/web3')
|
||||
const { bridgeConfig } = require('../config/base.config')
|
||||
|
||||
const homeABI = bridgeConfig.homeBridgeAbi
|
||||
const foreignABI = bridgeConfig.foreignBridgeAbi
|
||||
|
||||
async function getStartBlock(rpcUrl, bridgeAddress, bridgeAbi) {
|
||||
async function getStartBlock(web3, bridgeAddress, bridgeAbi) {
|
||||
try {
|
||||
const web3Provider = new Web3.providers.HttpProvider(rpcUrl)
|
||||
const web3Instance = new Web3(web3Provider)
|
||||
const bridgeContract = new web3Instance.eth.Contract(bridgeAbi, bridgeAddress)
|
||||
const bridgeContract = new web3.eth.Contract(bridgeAbi, bridgeAddress)
|
||||
|
||||
const deployedAtBlock = await bridgeContract.methods.deployedAtBlock().call()
|
||||
|
||||
const validatorContractAddress = await bridgeContract.methods.validatorContract().call()
|
||||
const validatorContract = new web3Instance.eth.Contract(BRIDGE_VALIDATORS_ABI, validatorContractAddress)
|
||||
const validatorContract = new web3.eth.Contract(BRIDGE_VALIDATORS_ABI, validatorContractAddress)
|
||||
|
||||
const validatorDeployedAtBlock = await validatorContract.methods.deployedAtBlock().call()
|
||||
|
||||
@@ -35,10 +32,8 @@ async function getStartBlock(rpcUrl, bridgeAddress, bridgeAbi) {
|
||||
async function main() {
|
||||
const { COMMON_HOME_BRIDGE_ADDRESS, COMMON_FOREIGN_BRIDGE_ADDRESS } = process.env
|
||||
|
||||
const homeRpcUrl = rpcUrlsManager.homeUrls[0]
|
||||
const foreignRpcUrl = rpcUrlsManager.foreignUrls[0]
|
||||
const homeStartBlock = await getStartBlock(homeRpcUrl, COMMON_HOME_BRIDGE_ADDRESS, homeABI)
|
||||
const foreignStartBlock = await getStartBlock(foreignRpcUrl, COMMON_FOREIGN_BRIDGE_ADDRESS, foreignABI)
|
||||
const homeStartBlock = await getStartBlock(web3Home, COMMON_HOME_BRIDGE_ADDRESS, homeABI)
|
||||
const foreignStartBlock = await getStartBlock(web3Foreign, COMMON_FOREIGN_BRIDGE_ADDRESS, foreignABI)
|
||||
const result = {
|
||||
homeStartBlock,
|
||||
foreignStartBlock
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
require('../env')
|
||||
const Web3 = require('web3')
|
||||
const { getTokensState } = require('../src/utils/tokenState')
|
||||
const {
|
||||
ERC677_BRIDGE_TOKEN_ABI,
|
||||
@@ -7,6 +6,7 @@ const {
|
||||
FOREIGN_ERC_TO_NATIVE_ABI,
|
||||
getTokenType
|
||||
} = require('../../commons')
|
||||
const { web3Foreign } = require('../src/services/web3')
|
||||
|
||||
const emptyLogger = {
|
||||
debug: () => {},
|
||||
@@ -14,26 +14,25 @@ const emptyLogger = {
|
||||
}
|
||||
|
||||
async function initialChecks() {
|
||||
const { ORACLE_BRIDGE_MODE, COMMON_FOREIGN_RPC_URL, COMMON_FOREIGN_BRIDGE_ADDRESS } = process.env
|
||||
const { ORACLE_BRIDGE_MODE, COMMON_FOREIGN_BRIDGE_ADDRESS } = process.env
|
||||
let result = {}
|
||||
const foreignWeb3 = new Web3(new Web3.providers.HttpProvider(COMMON_FOREIGN_RPC_URL))
|
||||
|
||||
if (ORACLE_BRIDGE_MODE === 'ERC_TO_ERC') {
|
||||
const bridge = new foreignWeb3.eth.Contract(FOREIGN_ERC_TO_ERC_ABI, COMMON_FOREIGN_BRIDGE_ADDRESS)
|
||||
const bridge = new web3Foreign.eth.Contract(FOREIGN_ERC_TO_ERC_ABI, COMMON_FOREIGN_BRIDGE_ADDRESS)
|
||||
result.bridgeableTokenAddress = await bridge.methods.erc20token().call()
|
||||
} else if (ORACLE_BRIDGE_MODE === 'ERC_TO_NATIVE') {
|
||||
const bridge = new foreignWeb3.eth.Contract(FOREIGN_ERC_TO_NATIVE_ABI, COMMON_FOREIGN_BRIDGE_ADDRESS)
|
||||
const bridge = new web3Foreign.eth.Contract(FOREIGN_ERC_TO_NATIVE_ABI, COMMON_FOREIGN_BRIDGE_ADDRESS)
|
||||
result = await getTokensState(bridge, emptyLogger)
|
||||
}
|
||||
|
||||
if (ORACLE_BRIDGE_MODE === 'ERC_TO_ERC') {
|
||||
const bridgeTokenContract = new foreignWeb3.eth.Contract(ERC677_BRIDGE_TOKEN_ABI, result.bridgeableTokenAddress)
|
||||
const bridgeTokenContract = new web3Foreign.eth.Contract(ERC677_BRIDGE_TOKEN_ABI, result.bridgeableTokenAddress)
|
||||
result.foreignERC = await getTokenType(bridgeTokenContract, COMMON_FOREIGN_BRIDGE_ADDRESS)
|
||||
}
|
||||
console.log(JSON.stringify(result))
|
||||
return result
|
||||
}
|
||||
|
||||
initialChecks()
|
||||
const result = initialChecks()
|
||||
|
||||
module.exports = initialChecks
|
||||
module.exports = result
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
require('../../env')
|
||||
const Web3Utils = require('web3-utils')
|
||||
const { toWei } = require('web3').utils
|
||||
const { web3Foreign } = require('../../src/services/web3')
|
||||
const { sendTx, sendRawTx } = require('../../src/tx/sendTx')
|
||||
const { sendTx } = require('../../src/tx/sendTx')
|
||||
const { isValidAmount } = require('../utils/utils')
|
||||
const { FOREIGN_NATIVE_TO_ERC_ABI } = require('../../../commons')
|
||||
|
||||
@@ -53,27 +53,17 @@ async function main() {
|
||||
try {
|
||||
await isValidAmount(FOREIGN_MIN_AMOUNT_PER_TX, bridge)
|
||||
|
||||
const foreignChainId = await sendRawTx({
|
||||
chain: 'foreign',
|
||||
params: [],
|
||||
method: 'net_version'
|
||||
})
|
||||
let nonce = await sendRawTx({
|
||||
chain: 'foreign',
|
||||
method: 'eth_getTransactionCount',
|
||||
params: [USER_ADDRESS, 'latest']
|
||||
})
|
||||
nonce = Web3Utils.hexToNumber(nonce)
|
||||
const foreignChainId = await web3Foreign.eth.getChainId()
|
||||
let nonce = await web3Foreign.eth.getTransactionCount(USER_ADDRESS)
|
||||
let actualSent = 0
|
||||
for (let i = 0; i < Number(NUMBER_OF_WITHDRAWALS_TO_SEND); i++) {
|
||||
const gasLimit = await poa20.methods
|
||||
.transferAndCall(COMMON_FOREIGN_BRIDGE_ADDRESS, Web3Utils.toWei(FOREIGN_MIN_AMOUNT_PER_TX), '0x')
|
||||
.transferAndCall(COMMON_FOREIGN_BRIDGE_ADDRESS, toWei(FOREIGN_MIN_AMOUNT_PER_TX), '0x')
|
||||
.estimateGas({ from: USER_ADDRESS })
|
||||
const data = await poa20.methods
|
||||
.transferAndCall(COMMON_FOREIGN_BRIDGE_ADDRESS, Web3Utils.toWei(FOREIGN_MIN_AMOUNT_PER_TX), '0x')
|
||||
.transferAndCall(COMMON_FOREIGN_BRIDGE_ADDRESS, toWei(FOREIGN_MIN_AMOUNT_PER_TX), '0x')
|
||||
.encodeABI({ from: USER_ADDRESS })
|
||||
const txHash = await sendTx({
|
||||
chain: 'foreign',
|
||||
privateKey: USER_ADDRESS_PRIVATE_KEY,
|
||||
data,
|
||||
nonce,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
require('../../env')
|
||||
const Web3Utils = require('web3-utils')
|
||||
const { web3Home } = require('../../src/services/web3')
|
||||
const { sendTx, sendRawTx } = require('../../src/tx/sendTx')
|
||||
const { sendTx } = require('../../src/tx/sendTx')
|
||||
const { isValidAmount } = require('../utils/utils')
|
||||
const { HOME_NATIVE_TO_ERC_ABI } = require('../../../commons')
|
||||
|
||||
@@ -21,21 +20,11 @@ async function main() {
|
||||
try {
|
||||
await isValidAmount(HOME_MIN_AMOUNT_PER_TX, bridge)
|
||||
|
||||
const homeChainId = await sendRawTx({
|
||||
chain: 'home',
|
||||
params: [],
|
||||
method: 'net_version'
|
||||
})
|
||||
let nonce = await sendRawTx({
|
||||
chain: 'home',
|
||||
method: 'eth_getTransactionCount',
|
||||
params: [USER_ADDRESS, 'latest']
|
||||
})
|
||||
nonce = Web3Utils.hexToNumber(nonce)
|
||||
const homeChainId = await web3Home.eth.getChainId()
|
||||
let nonce = await web3Home.eth.getTransactionCount(USER_ADDRESS)
|
||||
let actualSent = 0
|
||||
for (let i = 0; i < Number(NUMBER_OF_DEPOSITS_TO_SEND); i++) {
|
||||
const txHash = await sendTx({
|
||||
chain: 'home',
|
||||
privateKey: USER_ADDRESS_PRIVATE_KEY,
|
||||
data: '0x',
|
||||
nonce,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
const Web3Utils = require('web3-utils')
|
||||
const { fromWei } = require('web3').utils
|
||||
|
||||
async function getMinPerTxLimit(bridge) {
|
||||
const minPerTx = await bridge.methods.minPerTx().call()
|
||||
return Web3Utils.fromWei(minPerTx)
|
||||
return fromWei(minPerTx)
|
||||
}
|
||||
|
||||
async function isValidAmount(amount, bridge) {
|
||||
|
||||
@@ -3,7 +3,6 @@ const path = require('path')
|
||||
const { isAttached, connectWatcherToQueue, connection } = require('./services/amqpClient')
|
||||
const logger = require('./services/logger')
|
||||
const GasPrice = require('./services/gasPrice')
|
||||
const rpcUrlsManager = require('./services/getRpcUrlsManager')
|
||||
const { getNonce, getChainId, getEventsFromTx } = require('./tx/web3')
|
||||
const { sendTx } = require('./tx/sendTx')
|
||||
const { checkHTTPS, watchdog, syncForEach, addExtraGas } = require('./utils/utils')
|
||||
@@ -37,8 +36,7 @@ async function initialize() {
|
||||
try {
|
||||
const checkHttps = checkHTTPS(ORACLE_ALLOW_HTTP_FOR_RPC, logger)
|
||||
|
||||
rpcUrlsManager.homeUrls.forEach(checkHttps('home'))
|
||||
rpcUrlsManager.foreignUrls.forEach(checkHttps('foreign'))
|
||||
web3Instance.currentProvider.urls.forEach(checkHttps(config.chain))
|
||||
|
||||
attached = await isAttached()
|
||||
if (attached) {
|
||||
@@ -139,7 +137,7 @@ async function main({ sendJob, txHash }) {
|
||||
|
||||
async function sendJobTx(jobs) {
|
||||
const gasPrice = await GasPrice.start(config.chain, true)
|
||||
const chainId = await getChainId(config.chain)
|
||||
const chainId = await getChainId(web3Instance)
|
||||
let nonce = await getNonce(web3Instance, ORACLE_VALIDATOR_ADDRESS)
|
||||
|
||||
await syncForEach(jobs, async job => {
|
||||
@@ -153,7 +151,6 @@ async function sendJobTx(jobs) {
|
||||
try {
|
||||
logger.info(`Sending transaction with nonce ${nonce}`)
|
||||
const txHash = await sendTx({
|
||||
chain: config.chain,
|
||||
data: job.data,
|
||||
nonce,
|
||||
gasPrice: gasPrice.toString(10),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { HttpListProviderError } = require('http-list-provider')
|
||||
const { HttpListProviderError } = require('../../services/HttpListProvider')
|
||||
const { AlreadyProcessedError, AlreadySignedError, InvalidValidatorError } = require('../../utils/errors')
|
||||
const logger = require('../../services/logger').child({
|
||||
module: 'processAffirmationRequests:estimateGas'
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user