Compare commits
1 Commits
2.7.0-rc1
...
fix-bw-plu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c02ecad8fd |
@@ -8,16 +8,11 @@
|
|||||||
**/docs
|
**/docs
|
||||||
**/*.md
|
**/*.md
|
||||||
|
|
||||||
monitor/**/*.env*
|
|
||||||
oracle/**/*.env*
|
|
||||||
!**/.env.example
|
|
||||||
|
|
||||||
contracts/test
|
contracts/test
|
||||||
contracts/build
|
contracts/build
|
||||||
oracle/test
|
oracle/test
|
||||||
monitor/test
|
monitor/test
|
||||||
monitor/responses
|
monitor/responses
|
||||||
monitor/cache/*
|
|
||||||
commons/test
|
commons/test
|
||||||
oracle/**/*.png
|
oracle/**/*.png
|
||||||
oracle/**/*.jpg
|
oracle/**/*.jpg
|
||||||
|
|||||||
118
.github/workflows/main.yml
vendored
118
.github/workflows/main.yml
vendored
@@ -19,11 +19,9 @@ jobs:
|
|||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Set cache key
|
- run: git submodule status > submodule.status
|
||||||
id: get_cache_key
|
- id: get_cache_key
|
||||||
run: |
|
run: echo "::set-output name=cache_key::cache-repo-${{ hashFiles('yarn.lock', 'package.json', 'submodule.status') }}"
|
||||||
git submodule status > submodule.status
|
|
||||||
echo "::set-output name=cache_key::cache-repo-${{ hashFiles('yarn.lock', 'package.json', 'submodule.status') }}"
|
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v2
|
||||||
id: cache-repo
|
id: cache-repo
|
||||||
with:
|
with:
|
||||||
@@ -31,8 +29,7 @@ jobs:
|
|||||||
**/node_modules
|
**/node_modules
|
||||||
contracts/build
|
contracts/build
|
||||||
key: ${{ steps.get_cache_key.outputs.cache_key }}
|
key: ${{ steps.get_cache_key.outputs.cache_key }}
|
||||||
- name: Install dependencies and compile contracts
|
- if: ${{ !steps.cache-repo.outputs.cache-hit }}
|
||||||
if: ${{ !steps.cache-repo.outputs.cache-hit }}
|
|
||||||
run: |
|
run: |
|
||||||
yarn install --frozen-lockfile
|
yarn install --frozen-lockfile
|
||||||
yarn run install:deploy
|
yarn run install:deploy
|
||||||
@@ -59,8 +56,7 @@ jobs:
|
|||||||
**/node_modules
|
**/node_modules
|
||||||
contracts/build
|
contracts/build
|
||||||
key: ${{ needs.initialize.outputs.cache_key }}
|
key: ${{ needs.initialize.outputs.cache_key }}
|
||||||
- name: yarn run ${{ matrix.task }}
|
- run: ${{ steps.cache-repo.outputs.cache-hit }} && yarn run ${{ matrix.task }}
|
||||||
run: ${{ steps.cache-repo.outputs.cache-hit }} && yarn run ${{ matrix.task }}
|
|
||||||
ui-coverage:
|
ui-coverage:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs:
|
needs:
|
||||||
@@ -80,8 +76,7 @@ jobs:
|
|||||||
**/node_modules
|
**/node_modules
|
||||||
contracts/build
|
contracts/build
|
||||||
key: ${{ needs.initialize.outputs.cache_key }}
|
key: ${{ needs.initialize.outputs.cache_key }}
|
||||||
- name: yarn workspace ui run coverage
|
- run: ${{ steps.cache-repo.outputs.cache-hit }} && yarn workspace ui run coverage
|
||||||
run: ${{ steps.cache-repo.outputs.cache-hit }} && yarn workspace ui run coverage
|
|
||||||
- uses: coverallsapp/github-action@master
|
- uses: coverallsapp/github-action@master
|
||||||
with:
|
with:
|
||||||
github-token: ${{ github.token }}
|
github-token: ${{ github.token }}
|
||||||
@@ -92,16 +87,14 @@ jobs:
|
|||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Evaluate e2e docker images tags
|
- run: |
|
||||||
run: |
|
|
||||||
git submodule status > submodule.status
|
git submodule status > submodule.status
|
||||||
echo "E2E_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'Dockerfile.e2e', 'commons', 'oracle-e2e', 'monitor-e2e') }}" >> $GITHUB_ENV
|
echo "::set-env name=E2E_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'Dockerfile.e2e', 'commons', 'oracle-e2e', 'monitor-e2e') }}"
|
||||||
echo "ORACLE_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'oracle') }}" >> $GITHUB_ENV
|
echo "::set-env name=ORACLE_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'oracle') }}"
|
||||||
echo "MONITOR_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'monitor') }}" >> $GITHUB_ENV
|
echo "::set-env name=MONITOR_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'monitor') }}"
|
||||||
echo "UI_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'ui') }}" >> $GITHUB_ENV
|
echo "::set-env name=UI_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'ui') }}"
|
||||||
echo "ALM_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'alm') }}" >> $GITHUB_ENV
|
echo "::set-env name=ALM_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'alm') }}"
|
||||||
- name: Rebuild and push updated images
|
- run: |
|
||||||
run: |
|
|
||||||
function check_if_image_exists() {
|
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
|
curl -fsSlL -H 'Authorization: bearer ${{ github.token }}' "https://${DOCKER_REGISTRY}/v2/${DOCKER_REPO}/tokenbridge-e2e-$1/manifests/$2" > /dev/null
|
||||||
}
|
}
|
||||||
@@ -126,10 +119,8 @@ jobs:
|
|||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Evaluate e2e molecule runner tag
|
- run: echo "::set-env name=MOLECULE_RUNNER_TAG::${{ hashFiles('./deployment-e2e/Dockerfile') }}"
|
||||||
run: echo "MOLECULE_RUNNER_TAG=${{ hashFiles('./deployment-e2e/Dockerfile') }}" >> $GITHUB_ENV
|
- run: |
|
||||||
- name: Rebuild and push molecule runner e2e image
|
|
||||||
run: |
|
|
||||||
function check_if_image_exists() {
|
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
|
curl -fsSlL -H 'Authorization: bearer ${{ github.token }}' "https://${DOCKER_REGISTRY}/v2/${DOCKER_REPO}/tokenbridge-e2e-$1/manifests/$2" > /dev/null
|
||||||
}
|
}
|
||||||
@@ -159,14 +150,13 @@ jobs:
|
|||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Evaluate e2e docker images tags
|
- run: |
|
||||||
run: |
|
|
||||||
git submodule status > submodule.status
|
git submodule status > submodule.status
|
||||||
echo "E2E_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'Dockerfile.e2e', 'commons', 'oracle-e2e', 'monitor-e2e') }}" >> $GITHUB_ENV
|
echo "::set-env name=E2E_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'Dockerfile.e2e', 'commons', 'oracle-e2e', 'monitor-e2e') }}"
|
||||||
echo "ORACLE_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'oracle') }}" >> $GITHUB_ENV
|
echo "::set-env name=ORACLE_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'oracle') }}"
|
||||||
echo "MONITOR_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'monitor') }}" >> $GITHUB_ENV
|
echo "::set-env name=MONITOR_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'monitor') }}"
|
||||||
echo "UI_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'ui') }}" >> $GITHUB_ENV
|
echo "::set-env name=UI_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'ui') }}"
|
||||||
echo "ALM_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'alm') }}" >> $GITHUB_ENV
|
echo "::set-env name=ALM_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'alm') }}"
|
||||||
- if: ${{ matrix.use-cache }}
|
- if: ${{ matrix.use-cache }}
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v2
|
||||||
id: cache-repo
|
id: cache-repo
|
||||||
@@ -175,14 +165,11 @@ jobs:
|
|||||||
**/node_modules
|
**/node_modules
|
||||||
contracts/build
|
contracts/build
|
||||||
key: ${{ needs.initialize.outputs.cache_key }}
|
key: ${{ needs.initialize.outputs.cache_key }}
|
||||||
- name: Login to docker registry
|
- run: docker login ${DOCKER_REGISTRY} -u ${{ github.actor }} -p ${{ github.token }}
|
||||||
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: yarn run ${{ matrix.task }}
|
|
||||||
run: ${{ !matrix.use-cache || steps.cache-repo.outputs.cache-hit }} && yarn run ${{ matrix.task }}
|
|
||||||
deployment:
|
deployment:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs:
|
needs:
|
||||||
- build-e2e-images
|
|
||||||
- build-molecule-runner
|
- build-molecule-runner
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
@@ -192,17 +179,15 @@ jobs:
|
|||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Evaluate e2e molecule runner tag
|
- run: echo "::set-env name=MOLECULE_RUNNER_TAG::${{ hashFiles('./deployment-e2e/Dockerfile') }}"
|
||||||
run: echo "MOLECULE_RUNNER_TAG=${{ hashFiles('./deployment-e2e/Dockerfile') }}" >> $GITHUB_ENV
|
- run: docker login ${DOCKER_REGISTRY} -u ${{ github.actor }} -p ${{ github.token }}
|
||||||
- name: Login to docker registry
|
|
||||||
run: docker login ${DOCKER_REGISTRY} -u ${{ github.actor }} -p ${{ github.token }}
|
|
||||||
- run: deployment-e2e/molecule.sh ${{ matrix.task }}
|
- run: deployment-e2e/molecule.sh ${{ matrix.task }}
|
||||||
ultimate:
|
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
|
runs-on: ubuntu-latest
|
||||||
needs:
|
needs:
|
||||||
- initialize
|
- initialize
|
||||||
- build-e2e-images
|
- build-e2e-images
|
||||||
|
if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/develop' || startsWith(github.ref, 'refs/tags')
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
@@ -210,29 +195,24 @@ jobs:
|
|||||||
include:
|
include:
|
||||||
- task: erc-to-erc
|
- task: erc-to-erc
|
||||||
ui-e2e-grep: 'ERC TO ERC'
|
ui-e2e-grep: 'ERC TO ERC'
|
||||||
ui-config: 'e2e-commons/components-envs/ui-erc20.env'
|
|
||||||
- task: erc-to-native
|
- task: erc-to-native
|
||||||
ui-e2e-grep: 'ERC TO NATIVE'
|
ui-e2e-grep: 'ERC TO NATIVE'
|
||||||
ui-config: 'e2e-commons/components-envs/ui-erc20-native.env'
|
|
||||||
- task: native-to-erc
|
- task: native-to-erc
|
||||||
ui-e2e-grep: 'NATIVE TO ERC'
|
ui-e2e-grep: 'NATIVE TO ERC'
|
||||||
ui-config: 'e2e-commons/components-envs/ui.env'
|
|
||||||
- task: amb-stake-erc-to-erc
|
- task: amb-stake-erc-to-erc
|
||||||
ui-e2e-grep: '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:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Evaluate e2e docker images tags
|
- run: |
|
||||||
run: |
|
|
||||||
git submodule status > submodule.status
|
git submodule status > submodule.status
|
||||||
echo "E2E_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'Dockerfile.e2e', 'commons', 'oracle-e2e', 'monitor-e2e') }}" >> $GITHUB_ENV
|
echo "::set-env name=E2E_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'Dockerfile.e2e', 'commons', 'oracle-e2e', 'monitor-e2e') }}"
|
||||||
echo "ORACLE_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'oracle') }}" >> $GITHUB_ENV
|
echo "::set-env name=ORACLE_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'oracle') }}"
|
||||||
echo "MONITOR_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'monitor') }}" >> $GITHUB_ENV
|
echo "::set-env name=MONITOR_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'monitor') }}"
|
||||||
echo "UI_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'ui') }}" >> $GITHUB_ENV
|
echo "::set-env name=UI_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'ui') }}"
|
||||||
echo "ALM_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'alm') }}" >> $GITHUB_ENV
|
echo "::set-env name=ALM_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'alm') }}"
|
||||||
echo "MOLECULE_RUNNER_TAG=${{ hashFiles('./deployment-e2e/Dockerfile') }}" >> $GITHUB_ENV
|
echo "::set-env name=MOLECULE_RUNNER_TAG::${{ hashFiles('./deployment-e2e/Dockerfile') }}"
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v2
|
||||||
id: cache-repo
|
id: cache-repo
|
||||||
with:
|
with:
|
||||||
@@ -240,32 +220,12 @@ jobs:
|
|||||||
**/node_modules
|
**/node_modules
|
||||||
contracts/build
|
contracts/build
|
||||||
key: ${{ needs.initialize.outputs.cache_key }}
|
key: ${{ needs.initialize.outputs.cache_key }}
|
||||||
- name: Login to docker registry
|
- run: docker login ${DOCKER_REGISTRY} -u ${{ github.actor }} -p ${{ github.token }}
|
||||||
run: docker login ${DOCKER_REGISTRY} -u ${{ github.actor }} -p ${{ github.token }}
|
- run: ${{ steps.cache-repo.outputs.cache-hit }} && e2e-commons/up.sh deploy blocks
|
||||||
- name: Deploy contracts
|
- run: docker-compose -f ./e2e-commons/docker-compose.yml pull oracle
|
||||||
run: ${{ steps.cache-repo.outputs.cache-hit }} && e2e-commons/up.sh deploy blocks
|
- run: deployment-e2e/molecule.sh ultimate-${{ matrix.task }}
|
||||||
- name: Pull e2e oracle image
|
- run: sudo chown -R $USER:docker /var/run/docker.sock
|
||||||
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 }}
|
- 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
|
run: cd ui-e2e && xvfb-run yarn mocha -g "${{ matrix.ui-e2e-grep }}" -b ./test.js
|
||||||
- name: Run oracle e2e tests
|
- if: ${{ !matrix.ui-e2e-grep }}
|
||||||
if: ${{ !matrix.ui-e2e-grep }}
|
|
||||||
run: docker-compose -f ./e2e-commons/docker-compose.yml run e2e yarn workspace oracle-e2e run ${{ matrix.task }}
|
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,8 +10,11 @@ dist
|
|||||||
|
|
||||||
# misc
|
# misc
|
||||||
.DS_Store
|
.DS_Store
|
||||||
*.env*
|
.env
|
||||||
!.env.example
|
.env.local
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
.env.production.local
|
||||||
.idea
|
.idea
|
||||||
.nyc_output
|
.nyc_output
|
||||||
logs/
|
logs/
|
||||||
@@ -46,9 +49,5 @@ __pycache__
|
|||||||
|
|
||||||
#monitor
|
#monitor
|
||||||
monitor/responses/*
|
monitor/responses/*
|
||||||
monitor/cache/*
|
monitor/configs/*.env
|
||||||
!monitor/cache/.gitkeep
|
|
||||||
!monitor/.gitkeep
|
!monitor/.gitkeep
|
||||||
|
|
||||||
# Local Netlify folder
|
|
||||||
.netlify
|
|
||||||
@@ -41,14 +41,6 @@ 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_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_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_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
|
|
||||||
ORACLE_HOME_TX_RESEND_INTERVAL | Interval in milliseconds for automatic resending of stuck transactions for Home sender service. Defaults to 20 minutes. | integer
|
|
||||||
ORACLE_FOREIGN_TX_RESEND_INTERVAL | Interval in milliseconds for automatic resending of stuck transactions for Foreign sender service. Defaults to 20 minutes. | integer
|
|
||||||
ORACLE_SHUTDOWN_SERVICE_URL | Optional external URL to some other service/monitor/configuration manager that controls the remote shutdown process. GET request should return `application/json` message with the following schema: `{ shutdown: true/false }`. | URL
|
|
||||||
ORACLE_SHUTDOWN_SERVICE_POLLING_INTERVAL | Optional interval in milliseconds used to request the side RPC node or external shutdown service. Default is 120000. | integer
|
|
||||||
ORACLE_SIDE_RPC_URL | Optional HTTPS URL(s) for communication with the external shutdown service or side RPC nodes, used for shutdown manager activities. Several URLs can be specified, delimited by spaces. If the connection to one of these nodes is lost the next URL is used for connection. | URL(s)
|
|
||||||
ORACLE_SHUTDOWN_CONTRACT_ADDRESS | Optional contract address in the side chain accessible through `ORACLE_SIDE_RPC_URL`, where the method passed in `ORACLE_SHUTDOWN_CONTRACT_METHOD` is implemented. | `address`
|
|
||||||
ORACLE_SHUTDOWN_CONTRACT_METHOD | Method signature to be used in the side chain to identify the current shutdown status. Method should return boolean. Default value is `isShutdown()`. | `function signature`
|
|
||||||
|
|
||||||
|
|
||||||
## UI configuration
|
## UI configuration
|
||||||
@@ -85,9 +77,4 @@ MONITOR_VALIDATOR_FOREIGN_TX_LIMIT | Average gas usage of a transaction sent by
|
|||||||
MONITOR_TX_NUMBER_THRESHOLD | If estimated number of transaction is equal to or below this value, the monitor will report that the validator has less funds than it is required. | integer
|
MONITOR_TX_NUMBER_THRESHOLD | If estimated number of transaction is equal to or below this value, the monitor will report that the validator has less funds than it is required. | integer
|
||||||
MONITOR_PORT | The port for the Monitor. | integer
|
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_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_CACHE_EVENTS | If set to true, monitor will cache obtained events for other workers runs
|
||||||
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`
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ COPY --from=contracts /mono/contracts/build ./contracts/build
|
|||||||
COPY commons/package.json ./commons/
|
COPY commons/package.json ./commons/
|
||||||
COPY alm/package.json ./alm/
|
COPY alm/package.json ./alm/
|
||||||
COPY yarn.lock .
|
COPY yarn.lock .
|
||||||
RUN NOYARNPOSTINSTALL=1 yarn install --frozen-lockfile
|
RUN NOYARNPOSTINSTALL=1 yarn install --frozen-lockfile --production
|
||||||
|
|
||||||
COPY ./commons ./commons
|
COPY ./commons ./commons
|
||||||
COPY ./alm ./alm
|
COPY ./alm ./alm
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ethersproject/bignumber": ">=5.0.0-beta.130",
|
|
||||||
"@react-hook/window-size": "^3.0.6",
|
"@react-hook/window-size": "^3.0.6",
|
||||||
"@testing-library/jest-dom": "^4.2.4",
|
"@testing-library/jest-dom": "^4.2.4",
|
||||||
"@testing-library/react": "^9.3.2",
|
"@testing-library/react": "^9.3.2",
|
||||||
@@ -16,8 +15,6 @@
|
|||||||
"@types/react-router-dom": "^5.1.5",
|
"@types/react-router-dom": "^5.1.5",
|
||||||
"@types/styled-components": "^5.1.0",
|
"@types/styled-components": "^5.1.0",
|
||||||
"@use-it/interval": "^0.1.3",
|
"@use-it/interval": "^0.1.3",
|
||||||
"@web3-react/core": "^6.1.1",
|
|
||||||
"@web3-react/injected-connector": "^6.0.7",
|
|
||||||
"customize-cra": "^1.0.0",
|
"customize-cra": "^1.0.0",
|
||||||
"date-fns": "^2.14.0",
|
"date-fns": "^2.14.0",
|
||||||
"dotenv": "^8.2.0",
|
"dotenv": "^8.2.0",
|
||||||
@@ -30,9 +27,8 @@
|
|||||||
"react-scripts": "3.0.1",
|
"react-scripts": "3.0.1",
|
||||||
"styled-components": "^5.1.1",
|
"styled-components": "^5.1.1",
|
||||||
"typescript": "^3.5.2",
|
"typescript": "^3.5.2",
|
||||||
"web3": "1.2.11",
|
"web3": "1.2.7",
|
||||||
"web3-eth-contract": "1.2.11",
|
"web3-eth-contract": "1.2.7"
|
||||||
"web3-utils": "1.2.11"
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "yarn createSnapshots && ./load-env.sh react-app-rewired start",
|
"start": "yarn createSnapshots && ./load-env.sh react-app-rewired start",
|
||||||
@@ -58,7 +54,6 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"eslint-plugin-prettier": "^3.1.3",
|
"eslint-plugin-prettier": "^3.1.3"
|
||||||
"node-fetch": "^2.6.1"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
/* /index.html 200
|
|
||||||
@@ -3,8 +3,6 @@ const { BRIDGE_VALIDATORS_ABI, HOME_AMB_ABI } = require('commons')
|
|||||||
const path = require('path')
|
const path = require('path')
|
||||||
require('dotenv').config()
|
require('dotenv').config()
|
||||||
const Web3 = require('web3')
|
const Web3 = require('web3')
|
||||||
const fetch = require('node-fetch')
|
|
||||||
const { URL } = require('url')
|
|
||||||
|
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
|
|
||||||
@@ -12,9 +10,7 @@ const {
|
|||||||
COMMON_HOME_RPC_URL,
|
COMMON_HOME_RPC_URL,
|
||||||
COMMON_HOME_BRIDGE_ADDRESS,
|
COMMON_HOME_BRIDGE_ADDRESS,
|
||||||
COMMON_FOREIGN_RPC_URL,
|
COMMON_FOREIGN_RPC_URL,
|
||||||
COMMON_FOREIGN_BRIDGE_ADDRESS,
|
COMMON_FOREIGN_BRIDGE_ADDRESS
|
||||||
ALM_FOREIGN_EXPLORER_API,
|
|
||||||
ALM_HOME_EXPLORER_API
|
|
||||||
} = process.env
|
} = process.env
|
||||||
|
|
||||||
const generateSnapshot = async (side, url, bridgeAddress) => {
|
const generateSnapshot = async (side, url, bridgeAddress) => {
|
||||||
@@ -23,31 +19,6 @@ const generateSnapshot = async (side, url, bridgeAddress) => {
|
|||||||
const snapshot = {}
|
const snapshot = {}
|
||||||
|
|
||||||
const web3 = new Web3(new Web3.providers.HttpProvider(url))
|
const web3 = new Web3(new Web3.providers.HttpProvider(url))
|
||||||
const api = side === 'home' ? ALM_HOME_EXPLORER_API : ALM_FOREIGN_EXPLORER_API
|
|
||||||
|
|
||||||
const getPastEventsWithFallback = (contract, eventName, options) =>
|
|
||||||
contract.getPastEvents(eventName, options).catch(async e => {
|
|
||||||
if (e.message.includes('exceed maximum block range')) {
|
|
||||||
const abi = contract.options.jsonInterface.find(abi => abi.type === 'event' && abi.name === eventName)
|
|
||||||
|
|
||||||
const url = new URL(api)
|
|
||||||
url.searchParams.append('module', 'logs')
|
|
||||||
url.searchParams.append('action', 'getLogs')
|
|
||||||
url.searchParams.append('address', contract.options.address)
|
|
||||||
url.searchParams.append('fromBlock', options.fromBlock)
|
|
||||||
url.searchParams.append('toBlock', options.toBlock || 'latest')
|
|
||||||
url.searchParams.append('topic0', web3.eth.abi.encodeEventSignature(abi))
|
|
||||||
|
|
||||||
const logs = await fetch(url).then(res => res.json())
|
|
||||||
|
|
||||||
return logs.result.map(log => ({
|
|
||||||
transactionHash: log.transactionHash,
|
|
||||||
blockNumber: parseInt(log.blockNumber.slice(2), 16),
|
|
||||||
returnValues: web3.eth.abi.decodeLog(abi.inputs, log.data, log.topics.slice(1))
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
throw e
|
|
||||||
})
|
|
||||||
|
|
||||||
const currentBlockNumber = await web3.eth.getBlockNumber()
|
const currentBlockNumber = await web3.eth.getBlockNumber()
|
||||||
snapshot.snapshotBlockNumber = currentBlockNumber
|
snapshot.snapshotBlockNumber = currentBlockNumber
|
||||||
@@ -58,14 +29,10 @@ const generateSnapshot = async (side, url, bridgeAddress) => {
|
|||||||
const bridgeContract = new web3.eth.Contract(HOME_AMB_ABI, bridgeAddress)
|
const bridgeContract = new web3.eth.Contract(HOME_AMB_ABI, bridgeAddress)
|
||||||
|
|
||||||
// Save RequiredBlockConfirmationChanged events
|
// Save RequiredBlockConfirmationChanged events
|
||||||
let requiredBlockConfirmationChangedEvents = await getPastEventsWithFallback(
|
let requiredBlockConfirmationChangedEvents = await bridgeContract.getPastEvents('RequiredBlockConfirmationChanged', {
|
||||||
bridgeContract,
|
|
||||||
'RequiredBlockConfirmationChanged',
|
|
||||||
{
|
|
||||||
fromBlock: 0,
|
fromBlock: 0,
|
||||||
toBlock: currentBlockNumber
|
toBlock: currentBlockNumber
|
||||||
}
|
})
|
||||||
)
|
|
||||||
|
|
||||||
// In case RequiredBlockConfirmationChanged was not emitted during initialization in early versions of AMB
|
// In case RequiredBlockConfirmationChanged was not emitted during initialization in early versions of AMB
|
||||||
// manually generate an event for this. Example Sokol - Kovan bridge
|
// manually generate an event for this. Example Sokol - Kovan bridge
|
||||||
@@ -92,14 +59,10 @@ const generateSnapshot = async (side, url, bridgeAddress) => {
|
|||||||
const validatorContract = new web3.eth.Contract(BRIDGE_VALIDATORS_ABI, validatorAddress)
|
const validatorContract = new web3.eth.Contract(BRIDGE_VALIDATORS_ABI, validatorAddress)
|
||||||
|
|
||||||
// Save RequiredSignaturesChanged events
|
// Save RequiredSignaturesChanged events
|
||||||
const RequiredSignaturesChangedEvents = await getPastEventsWithFallback(
|
const RequiredSignaturesChangedEvents = await validatorContract.getPastEvents('RequiredSignaturesChanged', {
|
||||||
validatorContract,
|
|
||||||
'RequiredSignaturesChanged',
|
|
||||||
{
|
|
||||||
fromBlock: 0,
|
fromBlock: 0,
|
||||||
toBlock: currentBlockNumber
|
toBlock: currentBlockNumber
|
||||||
}
|
})
|
||||||
)
|
|
||||||
snapshot.RequiredSignaturesChanged = RequiredSignaturesChangedEvents.map(e => ({
|
snapshot.RequiredSignaturesChanged = RequiredSignaturesChangedEvents.map(e => ({
|
||||||
blockNumber: e.blockNumber,
|
blockNumber: e.blockNumber,
|
||||||
returnValues: {
|
returnValues: {
|
||||||
@@ -108,7 +71,7 @@ const generateSnapshot = async (side, url, bridgeAddress) => {
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
// Save ValidatorAdded events
|
// Save ValidatorAdded events
|
||||||
const validatorAddedEvents = await getPastEventsWithFallback(validatorContract, 'ValidatorAdded', {
|
const validatorAddedEvents = await validatorContract.getPastEvents('ValidatorAdded', {
|
||||||
fromBlock: 0,
|
fromBlock: 0,
|
||||||
toBlock: currentBlockNumber
|
toBlock: currentBlockNumber
|
||||||
})
|
})
|
||||||
@@ -122,7 +85,7 @@ const generateSnapshot = async (side, url, bridgeAddress) => {
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
// Save ValidatorRemoved events
|
// Save ValidatorRemoved events
|
||||||
const validatorRemovedEvents = await getPastEventsWithFallback(validatorContract, 'ValidatorRemoved', {
|
const validatorRemovedEvents = await validatorContract.getPastEvents('ValidatorRemoved', {
|
||||||
fromBlock: 0,
|
fromBlock: 0,
|
||||||
toBlock: currentBlockNumber
|
toBlock: currentBlockNumber
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,18 +1,14 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { BrowserRouter } from 'react-router-dom'
|
import { BrowserRouter } from 'react-router-dom'
|
||||||
import { Web3ReactProvider } from '@web3-react/core'
|
|
||||||
import Web3 from 'web3'
|
|
||||||
import { MainPage } from './components/MainPage'
|
import { MainPage } from './components/MainPage'
|
||||||
import { StateProvider } from './state/StateProvider'
|
import { StateProvider } from './state/StateProvider'
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<Web3ReactProvider getLibrary={provider => new Web3(provider)}>
|
|
||||||
<StateProvider>
|
<StateProvider>
|
||||||
<MainPage />
|
<MainPage />
|
||||||
</StateProvider>
|
</StateProvider>
|
||||||
</Web3ReactProvider>
|
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,38 +39,21 @@ export interface ConfirmationsContainerParams {
|
|||||||
message: MessageObject
|
message: MessageObject
|
||||||
receipt: Maybe<TransactionReceipt>
|
receipt: Maybe<TransactionReceipt>
|
||||||
fromHome: boolean
|
fromHome: boolean
|
||||||
homeStartBlock: Maybe<number>
|
timestamp: number
|
||||||
foreignStartBlock: Maybe<number>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ConfirmationsContainer = ({
|
export const ConfirmationsContainer = ({ message, receipt, fromHome, timestamp }: ConfirmationsContainerParams) => {
|
||||||
message,
|
|
||||||
receipt,
|
|
||||||
fromHome,
|
|
||||||
homeStartBlock,
|
|
||||||
foreignStartBlock
|
|
||||||
}: ConfirmationsContainerParams) => {
|
|
||||||
const {
|
const {
|
||||||
home: { name: homeName },
|
home: { name: homeName },
|
||||||
foreign: { name: foreignName }
|
foreign: { name: foreignName }
|
||||||
} = useStateProvider()
|
} = useStateProvider()
|
||||||
const { requiredSignatures, validatorList } = useValidatorContract({ fromHome, receipt })
|
const { requiredSignatures, validatorList } = useValidatorContract({ fromHome, receipt })
|
||||||
const { blockConfirmations } = useBlockConfirmations({ fromHome, receipt })
|
const { blockConfirmations } = useBlockConfirmations({ fromHome, receipt })
|
||||||
const {
|
const { confirmations, status, executionData, signatureCollected, waitingBlocksResolved } = useMessageConfirmations({
|
||||||
confirmations,
|
|
||||||
status,
|
|
||||||
executionData,
|
|
||||||
signatureCollected,
|
|
||||||
waitingBlocksResolved,
|
|
||||||
setExecutionData,
|
|
||||||
executionEventsFetched,
|
|
||||||
setPendingExecution
|
|
||||||
} = useMessageConfirmations({
|
|
||||||
message,
|
message,
|
||||||
receipt,
|
receipt,
|
||||||
fromHome,
|
fromHome,
|
||||||
homeStartBlock,
|
timestamp,
|
||||||
foreignStartBlock,
|
|
||||||
requiredSignatures,
|
requiredSignatures,
|
||||||
validatorList,
|
validatorList,
|
||||||
blockConfirmations
|
blockConfirmations
|
||||||
@@ -119,17 +102,7 @@ export const ConfirmationsContainer = ({
|
|||||||
validatorList={validatorList}
|
validatorList={validatorList}
|
||||||
waitingBlocksResolved={waitingBlocksResolved}
|
waitingBlocksResolved={waitingBlocksResolved}
|
||||||
/>
|
/>
|
||||||
{signatureCollected && (
|
{signatureCollected && <ExecutionConfirmation executionData={executionData} isHome={!fromHome} />}
|
||||||
<ExecutionConfirmation
|
|
||||||
messageData={message.data}
|
|
||||||
executionData={executionData}
|
|
||||||
isHome={!fromHome}
|
|
||||||
signatureCollected={signatureCollected}
|
|
||||||
setExecutionData={setExecutionData}
|
|
||||||
executionEventsFetched={executionEventsFetched}
|
|
||||||
setPendingExecution={setPendingExecution}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</StyledConfirmationContainer>
|
</StyledConfirmationContainer>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,47 +1,24 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { formatTimestamp, formatTxHash, getExplorerTxUrl } from '../utils/networks'
|
import { formatTimestamp, formatTxHash, getExplorerTxUrl } from '../utils/networks'
|
||||||
import { useWindowWidth } from '@react-hook/window-size'
|
import { useWindowWidth } from '@react-hook/window-size'
|
||||||
import { SEARCHING_TX, VALIDATOR_CONFIRMATION_STATUS, ALM_HOME_TO_FOREIGN_MANUAL_EXECUTION } from '../config/constants'
|
import { SEARCHING_TX, VALIDATOR_CONFIRMATION_STATUS } from '../config/constants'
|
||||||
import { SimpleLoading } from './commons/Loading'
|
import { SimpleLoading } from './commons/Loading'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { ExecutionData } from '../hooks/useMessageConfirmations'
|
import { ExecutionData } from '../hooks/useMessageConfirmations'
|
||||||
import { GreyLabel, RedLabel, SuccessLabel } from './commons/Labels'
|
import { GreyLabel, RedLabel, SuccessLabel } from './commons/Labels'
|
||||||
import { ExplorerTxLink } from './commons/ExplorerTxLink'
|
import { ExplorerTxLink } from './commons/ExplorerTxLink'
|
||||||
import { Thead, AgeTd, StatusTd } from './commons/Table'
|
import { Thead, AgeTd, StatusTd } from './commons/Table'
|
||||||
import { ManualExecutionButton } from './ManualExecutionButton'
|
|
||||||
|
|
||||||
const StyledExecutionConfirmation = styled.div`
|
const StyledExecutionConfirmation = styled.div`
|
||||||
margin-top: 30px;
|
margin-top: 30px;
|
||||||
`
|
`
|
||||||
|
|
||||||
export interface ExecutionConfirmationParams {
|
export interface ExecutionConfirmationParams {
|
||||||
messageData: string
|
|
||||||
executionData: ExecutionData
|
executionData: ExecutionData
|
||||||
setExecutionData: Function
|
|
||||||
signatureCollected: boolean | string[]
|
|
||||||
isHome: boolean
|
isHome: boolean
|
||||||
executionEventsFetched: boolean
|
|
||||||
setPendingExecution: Function
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ExecutionConfirmation = ({
|
export const ExecutionConfirmation = ({ executionData, isHome }: ExecutionConfirmationParams) => {
|
||||||
messageData,
|
|
||||||
executionData,
|
|
||||||
setExecutionData,
|
|
||||||
signatureCollected,
|
|
||||||
isHome,
|
|
||||||
executionEventsFetched,
|
|
||||||
setPendingExecution
|
|
||||||
}: ExecutionConfirmationParams) => {
|
|
||||||
const availableManualExecution =
|
|
||||||
!isHome &&
|
|
||||||
(executionData.status === VALIDATOR_CONFIRMATION_STATUS.WAITING ||
|
|
||||||
executionData.status === VALIDATOR_CONFIRMATION_STATUS.FAILED ||
|
|
||||||
(executionData.status === VALIDATOR_CONFIRMATION_STATUS.UNDEFINED &&
|
|
||||||
executionEventsFetched &&
|
|
||||||
!!executionData.validator))
|
|
||||||
const requiredManualExecution = availableManualExecution && ALM_HOME_TO_FOREIGN_MANUAL_EXECUTION
|
|
||||||
const showAgeColumn = !requiredManualExecution || executionData.status === VALIDATOR_CONFIRMATION_STATUS.FAILED
|
|
||||||
const windowWidth = useWindowWidth()
|
const windowWidth = useWindowWidth()
|
||||||
|
|
||||||
const txExplorerLink = getExplorerTxUrl(executionData.txHash, isHome)
|
const txExplorerLink = getExplorerTxUrl(executionData.txHash, isHome)
|
||||||
@@ -71,25 +48,15 @@ export const ExecutionConfirmation = ({
|
|||||||
<table>
|
<table>
|
||||||
<Thead>
|
<Thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{requiredManualExecution ? 'Execution info' : 'Executed by'}</th>
|
<th>Executed by</th>
|
||||||
<th className="text-center">Status</th>
|
<th className="text-center">Status</th>
|
||||||
{showAgeColumn && <th className="text-center">Age</th>}
|
<th className="text-center">Age</th>
|
||||||
{availableManualExecution && <th className="text-center">Actions</th>}
|
|
||||||
</tr>
|
</tr>
|
||||||
</Thead>
|
</Thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>{formattedValidator ? formattedValidator : <SimpleLoading />}</td>
|
||||||
{requiredManualExecution ? (
|
|
||||||
'Manual user action is required to complete the operation'
|
|
||||||
) : formattedValidator ? (
|
|
||||||
formattedValidator
|
|
||||||
) : (
|
|
||||||
<SimpleLoading />
|
|
||||||
)}
|
|
||||||
</td>
|
|
||||||
<StatusTd className="text-center">{getExecutionStatusElement(executionData.status)}</StatusTd>
|
<StatusTd className="text-center">{getExecutionStatusElement(executionData.status)}</StatusTd>
|
||||||
{showAgeColumn && (
|
|
||||||
<AgeTd className="text-center">
|
<AgeTd className="text-center">
|
||||||
{executionData.timestamp > 0 ? (
|
{executionData.timestamp > 0 ? (
|
||||||
<ExplorerTxLink href={txExplorerLink} target="_blank">
|
<ExplorerTxLink href={txExplorerLink} target="_blank">
|
||||||
@@ -101,17 +68,6 @@ export const ExecutionConfirmation = ({
|
|||||||
SEARCHING_TX
|
SEARCHING_TX
|
||||||
)}
|
)}
|
||||||
</AgeTd>
|
</AgeTd>
|
||||||
)}
|
|
||||||
{availableManualExecution && (
|
|
||||||
<td>
|
|
||||||
<ManualExecutionButton
|
|
||||||
messageData={messageData}
|
|
||||||
setExecutionData={setExecutionData}
|
|
||||||
signatureCollected={signatureCollected as string[]}
|
|
||||||
setPendingExecution={setPendingExecution}
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
)}
|
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import { TransactionReceipt } from 'web3-eth'
|
|||||||
import { InfoAlert } from './commons/InfoAlert'
|
import { InfoAlert } from './commons/InfoAlert'
|
||||||
import { ExplorerTxLink } from './commons/ExplorerTxLink'
|
import { ExplorerTxLink } from './commons/ExplorerTxLink'
|
||||||
import { FOREIGN_NETWORK_NAME, HOME_NETWORK_NAME } from '../config/constants'
|
import { FOREIGN_NETWORK_NAME, HOME_NETWORK_NAME } from '../config/constants'
|
||||||
import { ErrorAlert } from './commons/ErrorAlert'
|
|
||||||
|
|
||||||
const StyledMainPage = styled.div`
|
const StyledMainPage = styled.div`
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@@ -52,7 +51,7 @@ export interface FormSubmitParams {
|
|||||||
|
|
||||||
export const MainPage = () => {
|
export const MainPage = () => {
|
||||||
const history = useHistory()
|
const history = useHistory()
|
||||||
const { home, foreign, error, setError } = useStateProvider()
|
const { home, foreign } = useStateProvider()
|
||||||
const [networkName, setNetworkName] = useState('')
|
const [networkName, setNetworkName] = useState('')
|
||||||
const [receipt, setReceipt] = useState<Maybe<TransactionReceipt>>(null)
|
const [receipt, setReceipt] = useState<Maybe<TransactionReceipt>>(null)
|
||||||
const [showInfoAlert, setShowInfoAlert] = useState(false)
|
const [showInfoAlert, setShowInfoAlert] = useState(false)
|
||||||
@@ -132,7 +131,6 @@ export const MainPage = () => {
|
|||||||
</AlertP>
|
</AlertP>
|
||||||
</InfoAlert>
|
</InfoAlert>
|
||||||
)}
|
)}
|
||||||
{error && <ErrorAlert onClick={() => setError('')} error={error} />}
|
|
||||||
<Route exact path={['/']} children={<Form onSubmit={onFormSubmit} />} />
|
<Route exact path={['/']} children={<Form onSubmit={onFormSubmit} />} />
|
||||||
<Route
|
<Route
|
||||||
path={['/:chainId/:txHash/:messageIdParam', '/:chainId/:txHash']}
|
path={['/:chainId/:txHash/:messageIdParam', '/:chainId/:txHash']}
|
||||||
|
|||||||
@@ -1,146 +0,0 @@
|
|||||||
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 {
|
|
||||||
DOUBLE_EXECUTION_ATTEMPT_ERROR,
|
|
||||||
EXECUTION_FAILED_ERROR,
|
|
||||||
EXECUTION_OUT_OF_GAS_ERROR,
|
|
||||||
FOREIGN_EXPLORER_API,
|
|
||||||
INCORRECT_CHAIN_ERROR,
|
|
||||||
VALIDATOR_CONFIRMATION_STATUS
|
|
||||||
} from '../config/constants'
|
|
||||||
import { useStateProvider } from '../state/StateProvider'
|
|
||||||
import { signatureToVRS, packSignatures } from '../utils/signatures'
|
|
||||||
import { getSuccessExecutionData } from '../utils/getFinalizationEvent'
|
|
||||||
import { TransactionReceipt } from 'web3-eth'
|
|
||||||
|
|
||||||
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 messageId = messageData.slice(0, 66)
|
|
||||||
const bridge = foreign.bridgeContract
|
|
||||||
const data = bridge.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', async (e: Error, receipt: TransactionReceipt) => {
|
|
||||||
if (e.message.includes('Transaction has been reverted by the EVM')) {
|
|
||||||
const successExecutionData = await getSuccessExecutionData(
|
|
||||||
bridge,
|
|
||||||
'RelayedMessage',
|
|
||||||
library,
|
|
||||||
messageId,
|
|
||||||
FOREIGN_EXPLORER_API
|
|
||||||
)
|
|
||||||
if (successExecutionData) {
|
|
||||||
setExecutionData(successExecutionData)
|
|
||||||
setError(DOUBLE_EXECUTION_ATTEMPT_ERROR)
|
|
||||||
} else {
|
|
||||||
const { gas } = await library.eth.getTransaction(receipt.transactionHash)
|
|
||||||
setExecutionData({
|
|
||||||
status: VALIDATOR_CONFIRMATION_STATUS.FAILED,
|
|
||||||
validator: account,
|
|
||||||
txHash: receipt.transactionHash,
|
|
||||||
timestamp: Math.floor(new Date().getTime() / 1000.0),
|
|
||||||
executionResult: false
|
|
||||||
})
|
|
||||||
setError(gas === receipt.gasUsed ? EXECUTION_OUT_OF_GAS_ERROR : EXECUTION_FAILED_ERROR)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
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>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -10,7 +10,6 @@ import { ExplorerTxLink } from './commons/ExplorerTxLink'
|
|||||||
import { ConfirmationsContainer } from './ConfirmationsContainer'
|
import { ConfirmationsContainer } from './ConfirmationsContainer'
|
||||||
import { TransactionReceipt } from 'web3-eth'
|
import { TransactionReceipt } from 'web3-eth'
|
||||||
import { BackButton } from './commons/BackButton'
|
import { BackButton } from './commons/BackButton'
|
||||||
import { useClosestBlock } from '../hooks/useClosestBlock'
|
|
||||||
|
|
||||||
export interface StatusContainerParam {
|
export interface StatusContainerParam {
|
||||||
onBackToMain: () => void
|
onBackToMain: () => void
|
||||||
@@ -24,15 +23,12 @@ export const StatusContainer = ({ onBackToMain, setNetworkFromParams, receiptPar
|
|||||||
const { chainId, txHash, messageIdParam } = useParams()
|
const { chainId, txHash, messageIdParam } = useParams()
|
||||||
const validChainId = chainId === home.chainId.toString() || chainId === foreign.chainId.toString()
|
const validChainId = chainId === home.chainId.toString() || chainId === foreign.chainId.toString()
|
||||||
const validParameters = validChainId && validTxHash(txHash)
|
const validParameters = validChainId && validTxHash(txHash)
|
||||||
const isHome = chainId === home.chainId.toString()
|
|
||||||
|
|
||||||
const { messages, receipt, status, description, timestamp, loading } = useTransactionStatus({
|
const { messages, receipt, status, description, timestamp, loading } = useTransactionStatus({
|
||||||
txHash: validParameters ? txHash : '',
|
txHash: validParameters ? txHash : '',
|
||||||
chainId: validParameters ? parseInt(chainId) : 0,
|
chainId: validParameters ? parseInt(chainId) : 0,
|
||||||
receiptParam
|
receiptParam
|
||||||
})
|
})
|
||||||
const homeStartBlock = useClosestBlock(true, isHome, receipt, timestamp)
|
|
||||||
const foreignStartBlock = useClosestBlock(false, isHome, receipt, timestamp)
|
|
||||||
|
|
||||||
const selectedMessageId = messageIdParam === undefined || messages[messageIdParam] === undefined ? -1 : messageIdParam
|
const selectedMessageId = messageIdParam === undefined || messages[messageIdParam] === undefined ? -1 : messageIdParam
|
||||||
|
|
||||||
@@ -68,6 +64,7 @@ export const StatusContainer = ({ onBackToMain, setNetworkFromParams, receiptPar
|
|||||||
const displayReference = multiMessageSelected ? messages[selectedMessageId].id : txHash
|
const displayReference = multiMessageSelected ? messages[selectedMessageId].id : txHash
|
||||||
const formattedMessageId = formatTxHash(displayReference)
|
const formattedMessageId = formatTxHash(displayReference)
|
||||||
|
|
||||||
|
const isHome = chainId === home.chainId.toString()
|
||||||
const txExplorerLink = getExplorerTxUrl(txHash, isHome)
|
const txExplorerLink = getExplorerTxUrl(txHash, isHome)
|
||||||
const displayExplorerLink = status !== TRANSACTION_STATUS.NOT_FOUND
|
const displayExplorerLink = status !== TRANSACTION_STATUS.NOT_FOUND
|
||||||
|
|
||||||
@@ -104,13 +101,7 @@ export const StatusContainer = ({ onBackToMain, setNetworkFromParams, receiptPar
|
|||||||
)}
|
)}
|
||||||
{displayMessageSelector && <MessageSelector messages={messages} onMessageSelected={onMessageSelected} />}
|
{displayMessageSelector && <MessageSelector messages={messages} onMessageSelected={onMessageSelected} />}
|
||||||
{displayConfirmations && (
|
{displayConfirmations && (
|
||||||
<ConfirmationsContainer
|
<ConfirmationsContainer message={messageToConfirm} receipt={receipt} fromHome={isHome} timestamp={timestamp} />
|
||||||
message={messageToConfirm}
|
|
||||||
receipt={receipt}
|
|
||||||
fromHome={isHome}
|
|
||||||
homeStartBlock={homeStartBlock}
|
|
||||||
foreignStartBlock={foreignStartBlock}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
<BackButton onBackToMain={onBackToMain} />
|
<BackButton onBackToMain={onBackToMain} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
export const CloseIcon = ({ color }: { color?: string }) => (
|
export const CloseIcon = () => (
|
||||||
<svg
|
<svg
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
focusable="false"
|
focusable="false"
|
||||||
@@ -10,9 +10,12 @@ export const CloseIcon = ({ color }: { color?: string }) => (
|
|||||||
role="img"
|
role="img"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
viewBox="0 0 352 512"
|
viewBox="0 0 352 512"
|
||||||
fill={color || '#1890ff'}
|
fill="#1890ff"
|
||||||
height="1em"
|
height="1em"
|
||||||
>
|
>
|
||||||
<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" />
|
<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"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,48 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
import styled from 'styled-components'
|
|
||||||
import { InfoIcon } from './InfoIcon'
|
|
||||||
import { CloseIcon } from './CloseIcon'
|
|
||||||
import { ExplorerTxLink } from './ExplorerTxLink'
|
|
||||||
|
|
||||||
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`
|
|
||||||
white-space: pre-wrap;
|
|
||||||
flex-direction: column;
|
|
||||||
`
|
|
||||||
|
|
||||||
export const ErrorAlert = ({ onClick, error }: { onClick: () => void; error: string }) => {
|
|
||||||
const errorArray = error.split('%link')
|
|
||||||
const text = errorArray[0]
|
|
||||||
let link
|
|
||||||
if (errorArray.length > 1) {
|
|
||||||
link = (
|
|
||||||
<ExplorerTxLink href={errorArray[1]} target="_blank" rel="noopener noreferrer">
|
|
||||||
{errorArray[1]}
|
|
||||||
</ExplorerTxLink>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div className="row is-center">
|
|
||||||
<StyledErrorAlert className="col-10 is-vertical-align row">
|
|
||||||
<InfoIcon color="var(--failed-color)" />
|
|
||||||
<TextContainer className="col-10">
|
|
||||||
{text}
|
|
||||||
{link}
|
|
||||||
</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'
|
import React from 'react'
|
||||||
|
|
||||||
export const InfoIcon = ({ color }: { color?: string }) => (
|
export const InfoIcon = () => (
|
||||||
<svg
|
<svg
|
||||||
className="col-1 is-left"
|
className="col-1 is-left"
|
||||||
viewBox="64 64 896 896"
|
viewBox="64 64 896 896"
|
||||||
@@ -8,7 +8,7 @@ export const InfoIcon = ({ color }: { color?: string }) => (
|
|||||||
data-icon="info-circle"
|
data-icon="info-circle"
|
||||||
width="1em"
|
width="1em"
|
||||||
height="1em"
|
height="1em"
|
||||||
fill={color || '#1890ff'}
|
fill="#1890ff"
|
||||||
aria-hidden="true"
|
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" />
|
<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,13 +13,11 @@ 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 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 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 HOME_RPC_POLLING_INTERVAL: number = 5000
|
||||||
export const FOREIGN_RPC_POLLING_INTERVAL: number = 5000
|
export const FOREIGN_RPC_POLLING_INTERVAL: number = 5000
|
||||||
export const BLOCK_RANGE: number = 500
|
export const BLOCK_RANGE: number = 50
|
||||||
export const MAX_TX_SEARCH_BLOCK_RANGE: number = 10000
|
export const ONE_DAY_TIMESTAMP: number = 86400
|
||||||
|
export const THREE_DAYS_TIMESTAMP: number = 259200
|
||||||
|
|
||||||
export const EXECUTE_AFFIRMATION_HASH = 'e7a2c01f'
|
export const EXECUTE_AFFIRMATION_HASH = 'e7a2c01f'
|
||||||
export const SUBMIT_SIGNATURE_HASH = '630cea8e'
|
export const SUBMIT_SIGNATURE_HASH = '630cea8e'
|
||||||
@@ -63,14 +61,3 @@ export const VALIDATOR_CONFIRMATION_STATUS = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const SEARCHING_TX = 'Searching Transaction...'
|
export const SEARCHING_TX = 'Searching Transaction...'
|
||||||
|
|
||||||
export const INCORRECT_CHAIN_ERROR = `Incorrect chain chosen. Switch to ${FOREIGN_NETWORK_NAME} in the wallet.`
|
|
||||||
|
|
||||||
export const DOUBLE_EXECUTION_ATTEMPT_ERROR = `Your execution transaction has been reverted.
|
|
||||||
However, the execution completed successfully in the transaction sent by a different party.`
|
|
||||||
|
|
||||||
export const EXECUTION_FAILED_ERROR = `Your execution transaction has been reverted.
|
|
||||||
Please, contact the support by messaging on %linkhttps://forum.poa.network/c/support`
|
|
||||||
|
|
||||||
export const EXECUTION_OUT_OF_GAS_ERROR = `Your execution transaction has been reverted due to Out-of-Gas error.
|
|
||||||
Please, resend the transaction and provide more gas to it.`
|
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
// %t will be replaced by the time -> x minutes/hours/days ago
|
// %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 } = {
|
export const TRANSACTION_STATUS_DESCRIPTION: { [key: string]: string } = {
|
||||||
SUCCESS_MULTIPLE_MESSAGES: 'was initiated %t and contains several bridge messages. Specify one of them:',
|
SUCCESS_MULTIPLE_MESSAGES: 'was initiated %t and contains several bridge messages. Specify one of them:',
|
||||||
SUCCESS_ONE_MESSAGE: 'was initiated %t',
|
SUCCESS_ONE_MESSAGE: 'was initiated %t',
|
||||||
@@ -26,7 +24,7 @@ export const CONFIRMATIONS_STATUS_LABEL_HOME: { [key: string]: string } = {
|
|||||||
SUCCESS_MESSAGE_FAILED: 'Success',
|
SUCCESS_MESSAGE_FAILED: 'Success',
|
||||||
EXECUTION_FAILED: 'Execution failed',
|
EXECUTION_FAILED: 'Execution failed',
|
||||||
EXECUTION_PENDING: 'Execution pending',
|
EXECUTION_PENDING: 'Execution pending',
|
||||||
EXECUTION_WAITING: ALM_HOME_TO_FOREIGN_MANUAL_EXECUTION ? 'Manual execution waiting' : 'Execution waiting',
|
EXECUTION_WAITING: 'Execution waiting',
|
||||||
FAILED: 'Confirmation Failed',
|
FAILED: 'Confirmation Failed',
|
||||||
PENDING: 'Confirmation Pending',
|
PENDING: 'Confirmation Pending',
|
||||||
WAITING_VALIDATORS: 'Confirmation Waiting',
|
WAITING_VALIDATORS: 'Confirmation Waiting',
|
||||||
@@ -57,12 +55,11 @@ export const CONFIRMATIONS_STATUS_DESCRIPTION_HOME: { [key: string]: string } =
|
|||||||
SUCCESS_MESSAGE_FAILED:
|
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.',
|
'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:
|
EXECUTION_FAILED:
|
||||||
'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',
|
'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',
|
||||||
EXECUTION_PENDING:
|
EXECUTION_PENDING:
|
||||||
'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.',
|
'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: ALM_HOME_TO_FOREIGN_MANUAL_EXECUTION
|
EXECUTION_WAITING:
|
||||||
? '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. 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. 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:
|
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',
|
'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:
|
PENDING:
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ import { useStateProvider } from '../state/StateProvider'
|
|||||||
import { Contract } from 'web3-eth-contract'
|
import { Contract } from 'web3-eth-contract'
|
||||||
import { getRequiredBlockConfirmations } from '../utils/contract'
|
import { getRequiredBlockConfirmations } from '../utils/contract'
|
||||||
import { foreignSnapshotProvider, homeSnapshotProvider, SnapshotProvider } from '../services/SnapshotProvider'
|
import { foreignSnapshotProvider, homeSnapshotProvider, SnapshotProvider } from '../services/SnapshotProvider'
|
||||||
import Web3 from 'web3'
|
|
||||||
import { FOREIGN_EXPLORER_API, HOME_EXPLORER_API } from '../config/constants'
|
|
||||||
|
|
||||||
export interface UseBlockConfirmationsParams {
|
export interface UseBlockConfirmationsParams {
|
||||||
fromHome: boolean
|
fromHome: boolean
|
||||||
@@ -21,11 +19,9 @@ export const useBlockConfirmations = ({ receipt, fromHome }: UseBlockConfirmatio
|
|||||||
contract: Contract,
|
contract: Contract,
|
||||||
receipt: TransactionReceipt,
|
receipt: TransactionReceipt,
|
||||||
setResult: Function,
|
setResult: Function,
|
||||||
snapshotProvider: SnapshotProvider,
|
snapshotProvider: SnapshotProvider
|
||||||
web3: Web3,
|
|
||||||
api: string
|
|
||||||
) => {
|
) => {
|
||||||
const result = await getRequiredBlockConfirmations(contract, receipt.blockNumber, snapshotProvider, web3, api)
|
const result = await getRequiredBlockConfirmations(contract, receipt.blockNumber, snapshotProvider)
|
||||||
setResult(result)
|
setResult(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,12 +29,10 @@ export const useBlockConfirmations = ({ receipt, fromHome }: UseBlockConfirmatio
|
|||||||
() => {
|
() => {
|
||||||
const bridgeContract = fromHome ? home.bridgeContract : foreign.bridgeContract
|
const bridgeContract = fromHome ? home.bridgeContract : foreign.bridgeContract
|
||||||
const snapshotProvider = fromHome ? homeSnapshotProvider : foreignSnapshotProvider
|
const snapshotProvider = fromHome ? homeSnapshotProvider : foreignSnapshotProvider
|
||||||
const web3 = fromHome ? home.web3 : foreign.web3
|
if (!bridgeContract || !receipt) return
|
||||||
const api = fromHome ? HOME_EXPLORER_API : FOREIGN_EXPLORER_API
|
callRequireBlockConfirmations(bridgeContract, receipt, setBlockConfirmations, snapshotProvider)
|
||||||
if (!bridgeContract || !receipt || !web3) return
|
|
||||||
callRequireBlockConfirmations(bridgeContract, receipt, setBlockConfirmations, snapshotProvider, web3, api)
|
|
||||||
},
|
},
|
||||||
[home.bridgeContract, foreign.bridgeContract, receipt, fromHome, home.web3, foreign.web3]
|
[home.bridgeContract, foreign.bridgeContract, receipt, fromHome]
|
||||||
)
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,68 +0,0 @@
|
|||||||
import { useEffect, useState } from 'react'
|
|
||||||
import { TransactionReceipt } from 'web3-eth'
|
|
||||||
import { useStateProvider } from '../state/StateProvider'
|
|
||||||
import { FOREIGN_EXPLORER_API, HOME_EXPLORER_API } from '../config/constants'
|
|
||||||
import { getClosestBlockByTimestamp } from '../utils/explorer'
|
|
||||||
|
|
||||||
export function useClosestBlock(
|
|
||||||
searchHome: boolean,
|
|
||||||
fromHome: boolean,
|
|
||||||
receipt: Maybe<TransactionReceipt>,
|
|
||||||
timestamp: number
|
|
||||||
) {
|
|
||||||
const { home, foreign } = useStateProvider()
|
|
||||||
const [blockNumber, setBlockNumber] = useState<number | null>(null)
|
|
||||||
|
|
||||||
useEffect(
|
|
||||||
() => {
|
|
||||||
if (!receipt || blockNumber || !timestamp) return
|
|
||||||
|
|
||||||
if (fromHome === searchHome) {
|
|
||||||
setBlockNumber(receipt.blockNumber)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const web3 = searchHome ? home.web3 : foreign.web3
|
|
||||||
if (!web3) return
|
|
||||||
|
|
||||||
const getBlock = async () => {
|
|
||||||
// try to fast-fetch closest block number from the chain explorer
|
|
||||||
try {
|
|
||||||
const api = searchHome ? HOME_EXPLORER_API : FOREIGN_EXPLORER_API
|
|
||||||
setBlockNumber(await getClosestBlockByTimestamp(api, timestamp))
|
|
||||||
return
|
|
||||||
} catch {}
|
|
||||||
|
|
||||||
const lastBlock = await web3.eth.getBlock('latest')
|
|
||||||
if (lastBlock.timestamp <= timestamp) {
|
|
||||||
setBlockNumber(lastBlock.number)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const oldBlock = await web3.eth.getBlock(Math.max(lastBlock.number - 10000, 1))
|
|
||||||
const blockDiff = lastBlock.number - oldBlock.number
|
|
||||||
const timeDiff = (lastBlock.timestamp as number) - (oldBlock.timestamp as number)
|
|
||||||
const averageBlockTime = timeDiff / blockDiff
|
|
||||||
let currentBlock = lastBlock
|
|
||||||
|
|
||||||
let prevBlockDiff = Infinity
|
|
||||||
while (true) {
|
|
||||||
const timeDiff = (currentBlock.timestamp as number) - timestamp
|
|
||||||
const blockDiff = Math.ceil(timeDiff / averageBlockTime)
|
|
||||||
if (Math.abs(blockDiff) < 5 || Math.abs(blockDiff) >= Math.abs(prevBlockDiff)) {
|
|
||||||
setBlockNumber(currentBlock.number - blockDiff - 5)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
prevBlockDiff = blockDiff
|
|
||||||
currentBlock = await web3.eth.getBlock(currentBlock.number - blockDiff)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getBlock()
|
|
||||||
},
|
|
||||||
[blockNumber, foreign.web3, fromHome, home.web3, receipt, searchHome, timestamp]
|
|
||||||
)
|
|
||||||
|
|
||||||
return blockNumber
|
|
||||||
}
|
|
||||||
@@ -3,6 +3,7 @@ import { TransactionReceipt } from 'web3-eth'
|
|||||||
import { MessageObject } from '../utils/web3'
|
import { MessageObject } from '../utils/web3'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { EventData } from 'web3-eth-contract'
|
import { EventData } from 'web3-eth-contract'
|
||||||
|
import { getAffirmationsSigned, getMessagesSigned } from '../utils/contract'
|
||||||
import {
|
import {
|
||||||
BLOCK_RANGE,
|
BLOCK_RANGE,
|
||||||
CONFIRMATIONS_STATUS,
|
CONFIRMATIONS_STATUS,
|
||||||
@@ -11,6 +12,9 @@ import {
|
|||||||
VALIDATOR_CONFIRMATION_STATUS
|
VALIDATOR_CONFIRMATION_STATUS
|
||||||
} from '../config/constants'
|
} from '../config/constants'
|
||||||
import { homeBlockNumberProvider, foreignBlockNumberProvider } from '../services/BlockNumberProvider'
|
import { homeBlockNumberProvider, foreignBlockNumberProvider } from '../services/BlockNumberProvider'
|
||||||
|
import { checkSignaturesWaitingForBLocks } from '../utils/signatureWaitingForBlocks'
|
||||||
|
import { getCollectedSignaturesEvent } from '../utils/getCollectedSignaturesEvent'
|
||||||
|
import { checkWaitingBlocksForExecution } from '../utils/executionWaitingForBlocks'
|
||||||
import { getConfirmationsForTx } from '../utils/getConfirmationsForTx'
|
import { getConfirmationsForTx } from '../utils/getConfirmationsForTx'
|
||||||
import { getFinalizationEvent } from '../utils/getFinalizationEvent'
|
import { getFinalizationEvent } from '../utils/getFinalizationEvent'
|
||||||
import {
|
import {
|
||||||
@@ -25,8 +29,7 @@ export interface useMessageConfirmationsParams {
|
|||||||
message: MessageObject
|
message: MessageObject
|
||||||
receipt: Maybe<TransactionReceipt>
|
receipt: Maybe<TransactionReceipt>
|
||||||
fromHome: boolean
|
fromHome: boolean
|
||||||
homeStartBlock: Maybe<number>
|
timestamp: number
|
||||||
foreignStartBlock: Maybe<number>
|
|
||||||
requiredSignatures: number
|
requiredSignatures: number
|
||||||
validatorList: string[]
|
validatorList: string[]
|
||||||
blockConfirmations: number
|
blockConfirmations: number
|
||||||
@@ -54,19 +57,17 @@ export const useMessageConfirmations = ({
|
|||||||
message,
|
message,
|
||||||
receipt,
|
receipt,
|
||||||
fromHome,
|
fromHome,
|
||||||
homeStartBlock,
|
timestamp,
|
||||||
foreignStartBlock,
|
|
||||||
requiredSignatures,
|
requiredSignatures,
|
||||||
validatorList,
|
validatorList,
|
||||||
blockConfirmations
|
blockConfirmations
|
||||||
}: useMessageConfirmationsParams) => {
|
}: useMessageConfirmationsParams) => {
|
||||||
const { home, foreign } = useStateProvider()
|
const { home, foreign } = useStateProvider()
|
||||||
const [confirmations, setConfirmations] = useState<ConfirmationParam[]>([])
|
const [confirmations, setConfirmations] = useState<Array<ConfirmationParam>>([])
|
||||||
const [status, setStatus] = useState(CONFIRMATIONS_STATUS.UNDEFINED)
|
const [status, setStatus] = useState(CONFIRMATIONS_STATUS.UNDEFINED)
|
||||||
const [waitingBlocks, setWaitingBlocks] = useState(false)
|
const [waitingBlocks, setWaitingBlocks] = useState(false)
|
||||||
const [waitingBlocksResolved, setWaitingBlocksResolved] = useState(false)
|
const [waitingBlocksResolved, setWaitingBlocksResolved] = useState(false)
|
||||||
const [signatureCollected, setSignatureCollected] = useState<boolean | string[]>(false)
|
const [signatureCollected, setSignatureCollected] = useState(false)
|
||||||
const [executionEventsFetched, setExecutionEventsFetched] = useState(false)
|
|
||||||
const [collectedSignaturesEvent, setCollectedSignaturesEvent] = useState<Maybe<EventData>>(null)
|
const [collectedSignaturesEvent, setCollectedSignaturesEvent] = useState<Maybe<EventData>>(null)
|
||||||
const [executionData, setExecutionData] = useState<ExecutionData>({
|
const [executionData, setExecutionData] = useState<ExecutionData>({
|
||||||
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
||||||
@@ -82,188 +83,155 @@ export const useMessageConfirmations = ({
|
|||||||
const [pendingConfirmations, setPendingConfirmations] = useState(false)
|
const [pendingConfirmations, setPendingConfirmations] = useState(false)
|
||||||
const [pendingExecution, setPendingExecution] = useState(false)
|
const [pendingExecution, setPendingExecution] = useState(false)
|
||||||
|
|
||||||
const existsConfirmation = (confirmationArray: ConfirmationParam[]) =>
|
const existsConfirmation = (confirmationArray: ConfirmationParam[]) => {
|
||||||
confirmationArray.some(
|
const filteredList = confirmationArray.filter(
|
||||||
c => c.status !== VALIDATOR_CONFIRMATION_STATUS.UNDEFINED && c.status !== VALIDATOR_CONFIRMATION_STATUS.WAITING
|
c => c.status !== VALIDATOR_CONFIRMATION_STATUS.UNDEFINED && c.status !== VALIDATOR_CONFIRMATION_STATUS.WAITING
|
||||||
)
|
)
|
||||||
|
return filteredList.length > 0
|
||||||
// start watching blocks at the start
|
}
|
||||||
useEffect(
|
|
||||||
() => {
|
|
||||||
if (!home.web3 || !foreign.web3) return
|
|
||||||
|
|
||||||
homeBlockNumberProvider.start(home.web3)
|
|
||||||
foreignBlockNumberProvider.start(foreign.web3)
|
|
||||||
},
|
|
||||||
[foreign.web3, home.web3]
|
|
||||||
)
|
|
||||||
|
|
||||||
// Check if the validators are waiting for block confirmations to verify the message
|
// Check if the validators are waiting for block confirmations to verify the message
|
||||||
useEffect(
|
useEffect(
|
||||||
() => {
|
() => {
|
||||||
if (!receipt || !blockConfirmations || waitingBlocksResolved) return
|
if (!receipt || !blockConfirmations) return
|
||||||
|
|
||||||
let timeoutId: number
|
const subscriptions: Array<number> = []
|
||||||
|
|
||||||
|
const unsubscribe = () => {
|
||||||
|
subscriptions.forEach(s => {
|
||||||
|
clearTimeout(s)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const blockProvider = fromHome ? homeBlockNumberProvider : foreignBlockNumberProvider
|
const blockProvider = fromHome ? homeBlockNumberProvider : foreignBlockNumberProvider
|
||||||
const interval = fromHome ? HOME_RPC_POLLING_INTERVAL : FOREIGN_RPC_POLLING_INTERVAL
|
const interval = fromHome ? HOME_RPC_POLLING_INTERVAL : FOREIGN_RPC_POLLING_INTERVAL
|
||||||
|
const web3 = fromHome ? home.web3 : foreign.web3
|
||||||
|
blockProvider.start(web3)
|
||||||
|
|
||||||
const targetBlock = receipt.blockNumber + blockConfirmations
|
const targetBlock = receipt.blockNumber + blockConfirmations
|
||||||
const validatorsWaiting = validatorList.map(validator => ({
|
|
||||||
validator,
|
|
||||||
status: VALIDATOR_CONFIRMATION_STATUS.WAITING,
|
|
||||||
txHash: '',
|
|
||||||
timestamp: 0
|
|
||||||
}))
|
|
||||||
|
|
||||||
const checkSignaturesWaitingForBLocks = () => {
|
checkSignaturesWaitingForBLocks(
|
||||||
const currentBlock = blockProvider.get()
|
targetBlock,
|
||||||
|
setWaitingBlocks,
|
||||||
|
setWaitingBlocksResolved,
|
||||||
|
validatorList,
|
||||||
|
setConfirmations,
|
||||||
|
blockProvider,
|
||||||
|
interval,
|
||||||
|
subscriptions
|
||||||
|
)
|
||||||
|
|
||||||
if (currentBlock && currentBlock >= targetBlock) {
|
return () => {
|
||||||
setWaitingBlocksResolved(true)
|
unsubscribe()
|
||||||
setWaitingBlocks(false)
|
blockProvider.stop()
|
||||||
} else if (currentBlock) {
|
|
||||||
setWaitingBlocks(true)
|
|
||||||
setConfirmations(validatorsWaiting)
|
|
||||||
timeoutId = setTimeout(checkSignaturesWaitingForBLocks, interval)
|
|
||||||
} else {
|
|
||||||
timeoutId = setTimeout(checkSignaturesWaitingForBLocks, 500)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
checkSignaturesWaitingForBLocks()
|
|
||||||
|
|
||||||
return () => clearTimeout(timeoutId)
|
|
||||||
},
|
},
|
||||||
[blockConfirmations, fromHome, receipt, validatorList, waitingBlocksResolved]
|
[blockConfirmations, foreign.web3, fromHome, validatorList, home.web3, receipt]
|
||||||
)
|
)
|
||||||
|
|
||||||
// The collected signature event is only fetched once the signatures are collected on tx from home to foreign, to calculate if
|
// The collected signature event is only fetched once the signatures are collected on tx from home to foreign, to calculate if
|
||||||
// the execution tx on the foreign network is waiting for block confirmations
|
// the execution tx on the foreign network is waiting for block confirmations
|
||||||
// This is executed if the message is in Home to Foreign direction only
|
// This is executed if the message is in Home to Foreign direction only
|
||||||
const hasCollectedSignatures = !!signatureCollected // true or string[]
|
|
||||||
useEffect(
|
useEffect(
|
||||||
() => {
|
() => {
|
||||||
if (!fromHome || !receipt || !home.web3 || !home.bridgeContract || !hasCollectedSignatures) return
|
if (!fromHome || !receipt || !home.web3 || !signatureCollected) return
|
||||||
|
|
||||||
let timeoutId: number
|
const subscriptions: Array<number> = []
|
||||||
let isCancelled = false
|
|
||||||
|
|
||||||
const messageHash = home.web3.utils.soliditySha3Raw(message.data)
|
const unsubscribe = () => {
|
||||||
const contract = home.bridgeContract
|
subscriptions.forEach(s => {
|
||||||
|
clearTimeout(s)
|
||||||
const getCollectedSignaturesEvent = async (fromBlock: number, toBlock: number) => {
|
|
||||||
const currentBlock = homeBlockNumberProvider.get()
|
|
||||||
|
|
||||||
if (currentBlock) {
|
|
||||||
// prevent errors if the toBlock parameter is bigger than the latest
|
|
||||||
const securedToBlock = toBlock >= currentBlock ? currentBlock : toBlock
|
|
||||||
const events = await contract.getPastEvents('CollectedSignatures', {
|
|
||||||
fromBlock,
|
|
||||||
toBlock: securedToBlock
|
|
||||||
})
|
})
|
||||||
const event = events.find(e => e.returnValues.messageHash === messageHash)
|
|
||||||
if (event) {
|
|
||||||
setCollectedSignaturesEvent(event)
|
|
||||||
} else if (!isCancelled) {
|
|
||||||
timeoutId = setTimeout(() => getCollectedSignaturesEvent(securedToBlock, securedToBlock + BLOCK_RANGE), 500)
|
|
||||||
}
|
|
||||||
} else if (!isCancelled) {
|
|
||||||
timeoutId = setTimeout(() => getCollectedSignaturesEvent(fromBlock, toBlock), 500)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getCollectedSignaturesEvent(receipt.blockNumber, receipt.blockNumber + BLOCK_RANGE)
|
homeBlockNumberProvider.start(home.web3)
|
||||||
|
|
||||||
|
const fromBlock = receipt.blockNumber
|
||||||
|
const toBlock = fromBlock + BLOCK_RANGE
|
||||||
|
const messageHash = home.web3.utils.soliditySha3Raw(message.data)
|
||||||
|
|
||||||
|
getCollectedSignaturesEvent(
|
||||||
|
home.web3,
|
||||||
|
home.bridgeContract,
|
||||||
|
fromBlock,
|
||||||
|
toBlock,
|
||||||
|
messageHash,
|
||||||
|
setCollectedSignaturesEvent,
|
||||||
|
subscriptions
|
||||||
|
)
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
clearTimeout(timeoutId)
|
unsubscribe()
|
||||||
isCancelled = true
|
homeBlockNumberProvider.stop()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[fromHome, home.bridgeContract, home.web3, message.data, receipt, hasCollectedSignatures]
|
[fromHome, home.bridgeContract, home.web3, message.data, receipt, signatureCollected]
|
||||||
)
|
)
|
||||||
|
|
||||||
// Check if the responsible validator is waiting for block confirmations to execute the message on foreign network
|
// Check if the responsible validator is waiting for block confirmations to execute the message on foreign network
|
||||||
// This is executed if the message is in Home to Foreign direction only
|
// This is executed if the message is in Home to Foreign direction only
|
||||||
useEffect(
|
useEffect(
|
||||||
() => {
|
() => {
|
||||||
if (!fromHome || !home.web3 || !collectedSignaturesEvent || !blockConfirmations) return
|
if (!fromHome || !home.web3 || !receipt || !collectedSignaturesEvent || !blockConfirmations) return
|
||||||
if (waitingBlocksForExecutionResolved) return
|
|
||||||
|
|
||||||
let timeoutId: number
|
const subscriptions: Array<number> = []
|
||||||
|
|
||||||
|
const unsubscribe = () => {
|
||||||
|
subscriptions.forEach(s => {
|
||||||
|
clearTimeout(s)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
homeBlockNumberProvider.start(home.web3)
|
||||||
const targetBlock = collectedSignaturesEvent.blockNumber + blockConfirmations
|
const targetBlock = collectedSignaturesEvent.blockNumber + blockConfirmations
|
||||||
|
|
||||||
const checkWaitingBlocksForExecution = () => {
|
checkWaitingBlocksForExecution(
|
||||||
const currentBlock = homeBlockNumberProvider.get()
|
homeBlockNumberProvider,
|
||||||
|
HOME_RPC_POLLING_INTERVAL,
|
||||||
if (currentBlock && currentBlock >= targetBlock) {
|
targetBlock,
|
||||||
const undefinedExecutionState = {
|
collectedSignaturesEvent,
|
||||||
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
setWaitingBlocksForExecution,
|
||||||
validator: collectedSignaturesEvent.returnValues.authorityResponsibleForRelay,
|
setWaitingBlocksForExecutionResolved,
|
||||||
txHash: '',
|
setExecutionData,
|
||||||
timestamp: 0,
|
subscriptions
|
||||||
executionResult: false
|
|
||||||
}
|
|
||||||
setExecutionData(
|
|
||||||
(data: any) =>
|
|
||||||
data.status === VALIDATOR_CONFIRMATION_STATUS.UNDEFINED ||
|
|
||||||
data.status === VALIDATOR_CONFIRMATION_STATUS.WAITING
|
|
||||||
? undefinedExecutionState
|
|
||||||
: data
|
|
||||||
)
|
)
|
||||||
setWaitingBlocksForExecutionResolved(true)
|
|
||||||
setWaitingBlocksForExecution(false)
|
|
||||||
} else if (currentBlock) {
|
|
||||||
setWaitingBlocksForExecution(true)
|
|
||||||
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
|
|
||||||
)
|
|
||||||
timeoutId = setTimeout(() => checkWaitingBlocksForExecution(), HOME_RPC_POLLING_INTERVAL)
|
|
||||||
} else {
|
|
||||||
timeoutId = setTimeout(() => checkWaitingBlocksForExecution(), 500)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
checkWaitingBlocksForExecution()
|
return () => {
|
||||||
|
unsubscribe()
|
||||||
return () => clearTimeout(timeoutId)
|
homeBlockNumberProvider.stop()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[collectedSignaturesEvent, fromHome, blockConfirmations, home.web3, waitingBlocksForExecutionResolved]
|
[collectedSignaturesEvent, fromHome, blockConfirmations, home.web3, receipt]
|
||||||
)
|
)
|
||||||
|
|
||||||
// Checks if validators verified the message
|
// Checks if validators verified the message
|
||||||
// To avoid making extra requests, this is only executed when validators finished waiting for blocks confirmations
|
// To avoid making extra requests, this is only executed when validators finished waiting for blocks confirmations
|
||||||
useEffect(
|
useEffect(
|
||||||
() => {
|
() => {
|
||||||
if (!waitingBlocksResolved || !homeStartBlock || !requiredSignatures || !home.web3 || !home.bridgeContract) return
|
if (!waitingBlocksResolved || !timestamp || !requiredSignatures) return
|
||||||
if (!validatorList || !validatorList.length) return
|
|
||||||
|
|
||||||
let timeoutId: number
|
const subscriptions: Array<number> = []
|
||||||
let isCancelled = false
|
|
||||||
|
const unsubscribe = () => {
|
||||||
|
subscriptions.forEach(s => {
|
||||||
|
clearTimeout(s)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const confirmationContractMethod = fromHome ? getMessagesSigned : getAffirmationsSigned
|
||||||
|
|
||||||
getConfirmationsForTx(
|
getConfirmationsForTx(
|
||||||
message.data,
|
message.data,
|
||||||
home.web3,
|
home.web3,
|
||||||
validatorList,
|
validatorList,
|
||||||
home.bridgeContract,
|
home.bridgeContract,
|
||||||
fromHome,
|
confirmationContractMethod,
|
||||||
setConfirmations,
|
setConfirmations,
|
||||||
requiredSignatures,
|
requiredSignatures,
|
||||||
setSignatureCollected,
|
setSignatureCollected,
|
||||||
id => (timeoutId = id),
|
waitingBlocksResolved,
|
||||||
() => isCancelled,
|
subscriptions,
|
||||||
homeStartBlock,
|
timestamp,
|
||||||
getValidatorFailedTransactionsForMessage,
|
getValidatorFailedTransactionsForMessage,
|
||||||
setFailedConfirmations,
|
setFailedConfirmations,
|
||||||
getValidatorPendingTransactionsForMessage,
|
getValidatorPendingTransactionsForMessage,
|
||||||
@@ -272,8 +240,7 @@ export const useMessageConfirmations = ({
|
|||||||
)
|
)
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
clearTimeout(timeoutId)
|
unsubscribe()
|
||||||
isCancelled = true
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
@@ -284,7 +251,7 @@ export const useMessageConfirmations = ({
|
|||||||
home.bridgeContract,
|
home.bridgeContract,
|
||||||
requiredSignatures,
|
requiredSignatures,
|
||||||
waitingBlocksResolved,
|
waitingBlocksResolved,
|
||||||
homeStartBlock
|
timestamp
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -295,34 +262,38 @@ export const useMessageConfirmations = ({
|
|||||||
() => {
|
() => {
|
||||||
if ((fromHome && !waitingBlocksForExecutionResolved) || (!fromHome && !waitingBlocksResolved)) return
|
if ((fromHome && !waitingBlocksForExecutionResolved) || (!fromHome && !waitingBlocksResolved)) return
|
||||||
|
|
||||||
const bridgeContract = fromHome ? foreign.bridgeContract : home.bridgeContract
|
const subscriptions: Array<number> = []
|
||||||
const web3 = fromHome ? foreign.web3 : home.web3
|
|
||||||
const startBlock = fromHome ? foreignStartBlock : homeStartBlock
|
|
||||||
if (!startBlock || !bridgeContract || !web3) return
|
|
||||||
|
|
||||||
let timeoutId: number
|
const unsubscribe = () => {
|
||||||
let isCancelled = false
|
subscriptions.forEach(s => {
|
||||||
|
clearTimeout(s)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const contractEvent = fromHome ? 'RelayedMessage' : 'AffirmationCompleted'
|
||||||
|
const bridgeContract = fromHome ? foreign.bridgeContract : home.bridgeContract
|
||||||
|
const providedWeb3 = fromHome ? foreign.web3 : home.web3
|
||||||
|
const interval = fromHome ? FOREIGN_RPC_POLLING_INTERVAL : HOME_RPC_POLLING_INTERVAL
|
||||||
|
|
||||||
getFinalizationEvent(
|
getFinalizationEvent(
|
||||||
fromHome,
|
|
||||||
bridgeContract,
|
bridgeContract,
|
||||||
web3,
|
contractEvent,
|
||||||
|
providedWeb3,
|
||||||
setExecutionData,
|
setExecutionData,
|
||||||
|
waitingBlocksResolved,
|
||||||
message,
|
message,
|
||||||
id => (timeoutId = id),
|
interval,
|
||||||
() => isCancelled,
|
subscriptions,
|
||||||
startBlock,
|
timestamp,
|
||||||
collectedSignaturesEvent,
|
collectedSignaturesEvent,
|
||||||
getExecutionFailedTransactionForMessage,
|
getExecutionFailedTransactionForMessage,
|
||||||
setFailedExecution,
|
setFailedExecution,
|
||||||
getExecutionPendingTransactionsForMessage,
|
getExecutionPendingTransactionsForMessage,
|
||||||
setPendingExecution,
|
setPendingExecution
|
||||||
setExecutionEventsFetched
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
clearTimeout(timeoutId)
|
unsubscribe()
|
||||||
isCancelled = true
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
@@ -334,9 +305,8 @@ export const useMessageConfirmations = ({
|
|||||||
home.web3,
|
home.web3,
|
||||||
waitingBlocksResolved,
|
waitingBlocksResolved,
|
||||||
waitingBlocksForExecutionResolved,
|
waitingBlocksForExecutionResolved,
|
||||||
collectedSignaturesEvent,
|
timestamp,
|
||||||
foreignStartBlock,
|
collectedSignaturesEvent
|
||||||
homeStartBlock
|
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -348,9 +318,6 @@ export const useMessageConfirmations = ({
|
|||||||
? CONFIRMATIONS_STATUS.SUCCESS
|
? CONFIRMATIONS_STATUS.SUCCESS
|
||||||
: CONFIRMATIONS_STATUS.SUCCESS_MESSAGE_FAILED
|
: CONFIRMATIONS_STATUS.SUCCESS_MESSAGE_FAILED
|
||||||
setStatus(newStatus)
|
setStatus(newStatus)
|
||||||
|
|
||||||
foreignBlockNumberProvider.stop()
|
|
||||||
homeBlockNumberProvider.stop()
|
|
||||||
} else if (signatureCollected) {
|
} else if (signatureCollected) {
|
||||||
if (fromHome) {
|
if (fromHome) {
|
||||||
if (waitingBlocksForExecution) {
|
if (waitingBlocksForExecution) {
|
||||||
@@ -402,9 +369,6 @@ export const useMessageConfirmations = ({
|
|||||||
status,
|
status,
|
||||||
signatureCollected,
|
signatureCollected,
|
||||||
executionData,
|
executionData,
|
||||||
setExecutionData,
|
waitingBlocksResolved
|
||||||
waitingBlocksResolved,
|
|
||||||
executionEventsFetched,
|
|
||||||
setPendingExecution
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,23 +11,40 @@ export const useTransactionFinder = ({ txHash, web3 }: { txHash: string; web3: M
|
|||||||
() => {
|
() => {
|
||||||
if (!txHash || !web3) return
|
if (!txHash || !web3) return
|
||||||
|
|
||||||
let timeoutId: number
|
const subscriptions: number[] = []
|
||||||
|
|
||||||
const getReceipt = async () => {
|
const unsubscribe = () => {
|
||||||
|
subscriptions.forEach(s => {
|
||||||
|
clearTimeout(s)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const getReceipt = async (
|
||||||
|
web3: Web3,
|
||||||
|
txHash: string,
|
||||||
|
setReceipt: Function,
|
||||||
|
setStatus: Function,
|
||||||
|
subscriptions: number[]
|
||||||
|
) => {
|
||||||
const txReceipt = await web3.eth.getTransactionReceipt(txHash)
|
const txReceipt = await web3.eth.getTransactionReceipt(txHash)
|
||||||
setReceipt(txReceipt)
|
setReceipt(txReceipt)
|
||||||
|
|
||||||
if (!txReceipt) {
|
if (!txReceipt) {
|
||||||
setStatus(TRANSACTION_STATUS.NOT_FOUND)
|
setStatus(TRANSACTION_STATUS.NOT_FOUND)
|
||||||
timeoutId = setTimeout(getReceipt, HOME_RPC_POLLING_INTERVAL)
|
const timeoutId = setTimeout(
|
||||||
|
() => getReceipt(web3, txHash, setReceipt, setStatus, subscriptions),
|
||||||
|
HOME_RPC_POLLING_INTERVAL
|
||||||
|
)
|
||||||
|
subscriptions.push(timeoutId)
|
||||||
} else {
|
} else {
|
||||||
setStatus(TRANSACTION_STATUS.FOUND)
|
setStatus(TRANSACTION_STATUS.FOUND)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getReceipt()
|
getReceipt(web3, txHash, setReceipt, setStatus, subscriptions)
|
||||||
|
return () => {
|
||||||
return () => clearTimeout(timeoutId)
|
unsubscribe()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[txHash, web3]
|
[txHash, web3]
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -31,14 +31,19 @@ export const useTransactionStatus = ({
|
|||||||
|
|
||||||
useEffect(
|
useEffect(
|
||||||
() => {
|
() => {
|
||||||
if (!chainId || !txHash || !home.chainId || !foreign.chainId || !home.web3 || !foreign.web3) return
|
const subscriptions: Array<number> = []
|
||||||
const isHome = chainId === home.chainId
|
|
||||||
const web3 = isHome ? home.web3 : foreign.web3
|
|
||||||
|
|
||||||
let timeoutId: number
|
const unsubscribe = () => {
|
||||||
|
subscriptions.forEach(s => {
|
||||||
|
clearTimeout(s)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const getReceipt = async () => {
|
const getReceipt = async () => {
|
||||||
|
if (!chainId || !txHash || !home.chainId || !foreign.chainId || !home.web3 || !foreign.web3) return
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
|
const isHome = chainId === home.chainId
|
||||||
|
const web3 = isHome ? home.web3 : foreign.web3
|
||||||
|
|
||||||
let txReceipt
|
let txReceipt
|
||||||
|
|
||||||
@@ -54,7 +59,8 @@ export const useTransactionStatus = ({
|
|||||||
setStatus(TRANSACTION_STATUS.NOT_FOUND)
|
setStatus(TRANSACTION_STATUS.NOT_FOUND)
|
||||||
setDescription(getTransactionStatusDescription(TRANSACTION_STATUS.NOT_FOUND))
|
setDescription(getTransactionStatusDescription(TRANSACTION_STATUS.NOT_FOUND))
|
||||||
setMessages([{ id: txHash, data: '' }])
|
setMessages([{ id: txHash, data: '' }])
|
||||||
timeoutId = setTimeout(() => getReceipt(), HOME_RPC_POLLING_INTERVAL)
|
const timeoutId = setTimeout(() => getReceipt(), HOME_RPC_POLLING_INTERVAL)
|
||||||
|
subscriptions.push(timeoutId)
|
||||||
} else {
|
} else {
|
||||||
const blockNumber = txReceipt.blockNumber
|
const blockNumber = txReceipt.blockNumber
|
||||||
const block = await getBlock(web3, blockNumber)
|
const block = await getBlock(web3, blockNumber)
|
||||||
@@ -64,9 +70,9 @@ export const useTransactionStatus = ({
|
|||||||
if (txReceipt.status) {
|
if (txReceipt.status) {
|
||||||
let bridgeMessages: Array<MessageObject>
|
let bridgeMessages: Array<MessageObject>
|
||||||
if (isHome) {
|
if (isHome) {
|
||||||
bridgeMessages = getHomeMessagesFromReceipt(txReceipt, web3, home.bridgeAddress)
|
bridgeMessages = getHomeMessagesFromReceipt(txReceipt, home.web3, home.bridgeAddress)
|
||||||
} else {
|
} else {
|
||||||
bridgeMessages = getForeignMessagesFromReceipt(txReceipt, web3, foreign.bridgeAddress)
|
bridgeMessages = getForeignMessagesFromReceipt(txReceipt, foreign.web3, foreign.bridgeAddress)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bridgeMessages.length === 0) {
|
if (bridgeMessages.length === 0) {
|
||||||
@@ -92,9 +98,14 @@ export const useTransactionStatus = ({
|
|||||||
setLoading(false)
|
setLoading(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
getReceipt()
|
// unsubscribe from previous txHash
|
||||||
|
unsubscribe()
|
||||||
|
|
||||||
return () => clearTimeout(timeoutId)
|
getReceipt()
|
||||||
|
return () => {
|
||||||
|
// unsubscribe when unmount component
|
||||||
|
unsubscribe()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
txHash,
|
txHash,
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import { BRIDGE_VALIDATORS_ABI } from '../abis'
|
|||||||
import { useStateProvider } from '../state/StateProvider'
|
import { useStateProvider } from '../state/StateProvider'
|
||||||
import { TransactionReceipt } from 'web3-eth'
|
import { TransactionReceipt } from 'web3-eth'
|
||||||
import { foreignSnapshotProvider, homeSnapshotProvider, SnapshotProvider } from '../services/SnapshotProvider'
|
import { foreignSnapshotProvider, homeSnapshotProvider, SnapshotProvider } from '../services/SnapshotProvider'
|
||||||
import { FOREIGN_EXPLORER_API, HOME_EXPLORER_API } from '../config/constants'
|
|
||||||
|
|
||||||
export interface useValidatorContractParams {
|
export interface useValidatorContractParams {
|
||||||
fromHome: boolean
|
fromHome: boolean
|
||||||
@@ -31,12 +30,10 @@ export const useValidatorContract = ({ receipt, fromHome }: useValidatorContract
|
|||||||
contract: Maybe<Contract>,
|
contract: Maybe<Contract>,
|
||||||
receipt: TransactionReceipt,
|
receipt: TransactionReceipt,
|
||||||
setResult: Function,
|
setResult: Function,
|
||||||
snapshotProvider: SnapshotProvider,
|
snapshotProvider: SnapshotProvider
|
||||||
web3: Web3,
|
|
||||||
api: string
|
|
||||||
) => {
|
) => {
|
||||||
if (!contract) return
|
if (!contract) return
|
||||||
const result = await getRequiredSignatures(contract, receipt.blockNumber, snapshotProvider, web3, api)
|
const result = await getRequiredSignatures(contract, receipt.blockNumber, snapshotProvider)
|
||||||
setResult(result)
|
setResult(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,35 +41,32 @@ export const useValidatorContract = ({ receipt, fromHome }: useValidatorContract
|
|||||||
contract: Maybe<Contract>,
|
contract: Maybe<Contract>,
|
||||||
receipt: TransactionReceipt,
|
receipt: TransactionReceipt,
|
||||||
setResult: Function,
|
setResult: Function,
|
||||||
snapshotProvider: SnapshotProvider,
|
snapshotProvider: SnapshotProvider
|
||||||
web3: Web3,
|
|
||||||
api: string
|
|
||||||
) => {
|
) => {
|
||||||
if (!contract) return
|
if (!contract) return
|
||||||
const result = await getValidatorList(contract, receipt.blockNumber, snapshotProvider, web3, api)
|
const result = await getValidatorList(contract, receipt.blockNumber, snapshotProvider)
|
||||||
setResult(result)
|
setResult(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
const web3 = fromHome ? home.web3 : foreign.web3
|
|
||||||
const api = fromHome ? HOME_EXPLORER_API : FOREIGN_EXPLORER_API
|
|
||||||
const bridgeContract = fromHome ? home.bridgeContract : foreign.bridgeContract
|
|
||||||
const snapshotProvider = fromHome ? homeSnapshotProvider : foreignSnapshotProvider
|
|
||||||
|
|
||||||
useEffect(
|
useEffect(
|
||||||
() => {
|
() => {
|
||||||
|
const web3 = fromHome ? home.web3 : foreign.web3
|
||||||
|
const bridgeContract = fromHome ? home.bridgeContract : foreign.bridgeContract
|
||||||
|
|
||||||
if (!web3 || !bridgeContract) return
|
if (!web3 || !bridgeContract) return
|
||||||
callValidatorContract(bridgeContract, web3, setValidatorContract)
|
callValidatorContract(bridgeContract, web3, setValidatorContract)
|
||||||
},
|
},
|
||||||
[web3, bridgeContract]
|
[home.web3, foreign.web3, home.bridgeContract, foreign.bridgeContract, fromHome]
|
||||||
)
|
)
|
||||||
|
|
||||||
useEffect(
|
useEffect(
|
||||||
() => {
|
() => {
|
||||||
if (!web3 || !receipt) return
|
if (!receipt) return
|
||||||
callRequiredSignatures(validatorContract, receipt, setRequiredSignatures, snapshotProvider, web3, api)
|
const snapshotProvider = fromHome ? homeSnapshotProvider : foreignSnapshotProvider
|
||||||
callValidatorList(validatorContract, receipt, setValidatorList, snapshotProvider, web3, api)
|
callRequiredSignatures(validatorContract, receipt, setRequiredSignatures, snapshotProvider)
|
||||||
|
callValidatorList(validatorContract, receipt, setValidatorList, snapshotProvider)
|
||||||
},
|
},
|
||||||
[validatorContract, receipt, web3, snapshotProvider, api]
|
[validatorContract, receipt, fromHome]
|
||||||
)
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import Web3 from 'web3'
|
import Web3 from 'web3'
|
||||||
import differenceInMilliseconds from 'date-fns/differenceInMilliseconds'
|
import differenceInMilliseconds from 'date-fns/differenceInMilliseconds'
|
||||||
import { FOREIGN_RPC_POLLING_INTERVAL, HOME_RPC_POLLING_INTERVAL } from '../config/constants'
|
import { HOME_RPC_POLLING_INTERVAL } from '../config/constants'
|
||||||
|
|
||||||
export class BlockNumberProvider {
|
export class BlockNumberProvider {
|
||||||
private running: number
|
private running: number
|
||||||
@@ -61,4 +61,4 @@ export class BlockNumberProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const homeBlockNumberProvider = new BlockNumberProvider(HOME_RPC_POLLING_INTERVAL)
|
export const homeBlockNumberProvider = new BlockNumberProvider(HOME_RPC_POLLING_INTERVAL)
|
||||||
export const foreignBlockNumberProvider = new BlockNumberProvider(FOREIGN_RPC_POLLING_INTERVAL)
|
export const foreignBlockNumberProvider = new BlockNumberProvider(HOME_RPC_POLLING_INTERVAL)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { createContext, ReactNode, useState } from 'react'
|
import React, { createContext, ReactNode } from 'react'
|
||||||
import { useNetwork } from '../hooks/useNetwork'
|
import { useNetwork } from '../hooks/useNetwork'
|
||||||
import {
|
import {
|
||||||
HOME_RPC_URL,
|
HOME_RPC_URL,
|
||||||
@@ -25,8 +25,6 @@ export interface StateContext {
|
|||||||
home: BaseNetworkParams
|
home: BaseNetworkParams
|
||||||
foreign: BaseNetworkParams
|
foreign: BaseNetworkParams
|
||||||
loading: boolean
|
loading: boolean
|
||||||
error: string
|
|
||||||
setError: Function
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
@@ -44,9 +42,7 @@ const initialState = {
|
|||||||
bridgeAddress: FOREIGN_BRIDGE_ADDRESS,
|
bridgeAddress: FOREIGN_BRIDGE_ADDRESS,
|
||||||
bridgeContract: null
|
bridgeContract: null
|
||||||
},
|
},
|
||||||
loading: true,
|
loading: true
|
||||||
error: '',
|
|
||||||
setError: () => {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const StateContext = createContext<StateContext>(initialState)
|
const StateContext = createContext<StateContext>(initialState)
|
||||||
@@ -58,7 +54,6 @@ export const StateProvider = ({ children }: { children: ReactNode }) => {
|
|||||||
homeWeb3: homeNetwork.web3,
|
homeWeb3: homeNetwork.web3,
|
||||||
foreignWeb3: foreignNetwork.web3
|
foreignWeb3: foreignNetwork.web3
|
||||||
})
|
})
|
||||||
const [error, setError] = useState('')
|
|
||||||
|
|
||||||
const value = {
|
const value = {
|
||||||
home: {
|
home: {
|
||||||
@@ -73,9 +68,7 @@ export const StateProvider = ({ children }: { children: ReactNode }) => {
|
|||||||
bridgeContract: foreignBridge,
|
bridgeContract: foreignBridge,
|
||||||
...foreignNetwork
|
...foreignNetwork
|
||||||
},
|
},
|
||||||
loading: homeNetwork.loading || foreignNetwork.loading,
|
loading: homeNetwork.loading || foreignNetwork.loading
|
||||||
error,
|
|
||||||
setError
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return <StateContext.Provider value={value}>{children}</StateContext.Provider>
|
return <StateContext.Provider value={value}>{children}</StateContext.Provider>
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ describe('getRequiredBlockConfirmations', () => {
|
|||||||
|
|
||||||
test('Should call requiredBlockConfirmations method if no events present', async () => {
|
test('Should call requiredBlockConfirmations method if no events present', async () => {
|
||||||
const contract = ({
|
const contract = ({
|
||||||
getPastEvents: async () => {
|
getPastEvents: () => {
|
||||||
return []
|
return []
|
||||||
},
|
},
|
||||||
methods: methodsBuilder('1')
|
methods: methodsBuilder('1')
|
||||||
@@ -37,7 +37,7 @@ describe('getRequiredBlockConfirmations', () => {
|
|||||||
})
|
})
|
||||||
test('Should not call to get events if block number was included in the snapshot', async () => {
|
test('Should not call to get events if block number was included in the snapshot', async () => {
|
||||||
const contract = ({
|
const contract = ({
|
||||||
getPastEvents: jest.fn().mockImplementation(async () => []),
|
getPastEvents: jest.fn().mockImplementation(() => []),
|
||||||
methods: methodsBuilder('3')
|
methods: methodsBuilder('3')
|
||||||
} as unknown) as Contract
|
} as unknown) as Contract
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ describe('getRequiredBlockConfirmations', () => {
|
|||||||
})
|
})
|
||||||
test('Should call to get events if block number was not included in the snapshot', async () => {
|
test('Should call to get events if block number was not included in the snapshot', async () => {
|
||||||
const contract = ({
|
const contract = ({
|
||||||
getPastEvents: jest.fn().mockImplementation(async () => [
|
getPastEvents: jest.fn().mockImplementation(() => [
|
||||||
{
|
{
|
||||||
blockNumber: 9,
|
blockNumber: 9,
|
||||||
returnValues: {
|
returnValues: {
|
||||||
@@ -102,7 +102,7 @@ describe('getRequiredBlockConfirmations', () => {
|
|||||||
})
|
})
|
||||||
test('Should use the most updated event', async () => {
|
test('Should use the most updated event', async () => {
|
||||||
const contract = ({
|
const contract = ({
|
||||||
getPastEvents: jest.fn().mockImplementation(async () => [
|
getPastEvents: jest.fn().mockImplementation(() => [
|
||||||
{
|
{
|
||||||
blockNumber: 9,
|
blockNumber: 9,
|
||||||
returnValues: {
|
returnValues: {
|
||||||
@@ -141,7 +141,7 @@ describe('getRequiredBlockConfirmations', () => {
|
|||||||
describe('getRequiredSignatures', () => {
|
describe('getRequiredSignatures', () => {
|
||||||
test('Should not call to get events if block number was included in the snapshot', async () => {
|
test('Should not call to get events if block number was included in the snapshot', async () => {
|
||||||
const contract = ({
|
const contract = ({
|
||||||
getPastEvents: jest.fn().mockImplementation(async () => [])
|
getPastEvents: jest.fn().mockImplementation(() => [])
|
||||||
} as unknown) as Contract
|
} as unknown) as Contract
|
||||||
|
|
||||||
const snapshotProvider = ({
|
const snapshotProvider = ({
|
||||||
@@ -173,7 +173,7 @@ describe('getRequiredSignatures', () => {
|
|||||||
})
|
})
|
||||||
test('Should call to get events if block number is higher than the snapshot block number', async () => {
|
test('Should call to get events if block number is higher than the snapshot block number', async () => {
|
||||||
const contract = ({
|
const contract = ({
|
||||||
getPastEvents: jest.fn().mockImplementation(async () => [
|
getPastEvents: jest.fn().mockImplementation(() => [
|
||||||
{
|
{
|
||||||
blockNumber: 15,
|
blockNumber: 15,
|
||||||
returnValues: {
|
returnValues: {
|
||||||
@@ -216,7 +216,7 @@ describe('getRequiredSignatures', () => {
|
|||||||
})
|
})
|
||||||
test('Should use the most updated event before the block number', async () => {
|
test('Should use the most updated event before the block number', async () => {
|
||||||
const contract = ({
|
const contract = ({
|
||||||
getPastEvents: jest.fn().mockImplementation(async () => [
|
getPastEvents: jest.fn().mockImplementation(() => [
|
||||||
{
|
{
|
||||||
blockNumber: 15,
|
blockNumber: 15,
|
||||||
returnValues: {
|
returnValues: {
|
||||||
@@ -270,7 +270,7 @@ describe('getValidatorList', () => {
|
|||||||
test('Should return the current validator list if no events found', async () => {
|
test('Should return the current validator list if no events found', async () => {
|
||||||
const currentValidators = [validator1, validator2, validator3]
|
const currentValidators = [validator1, validator2, validator3]
|
||||||
const contract = ({
|
const contract = ({
|
||||||
getPastEvents: jest.fn().mockImplementation(async () => []),
|
getPastEvents: jest.fn().mockImplementation(() => []),
|
||||||
methods: methodsBuilder(currentValidators)
|
methods: methodsBuilder(currentValidators)
|
||||||
} as unknown) as Contract
|
} as unknown) as Contract
|
||||||
|
|
||||||
@@ -301,7 +301,7 @@ describe('getValidatorList', () => {
|
|||||||
test('If validator was added later from snapshot it should not include it', async () => {
|
test('If validator was added later from snapshot it should not include it', async () => {
|
||||||
const currentValidators = [validator1, validator2, validator3]
|
const currentValidators = [validator1, validator2, validator3]
|
||||||
const contract = ({
|
const contract = ({
|
||||||
getPastEvents: jest.fn().mockImplementation(async () => []),
|
getPastEvents: jest.fn().mockImplementation(() => []),
|
||||||
methods: methodsBuilder(currentValidators)
|
methods: methodsBuilder(currentValidators)
|
||||||
} as unknown) as Contract
|
} as unknown) as Contract
|
||||||
|
|
||||||
@@ -340,7 +340,7 @@ describe('getValidatorList', () => {
|
|||||||
test('If validator was added later from chain it should not include it', async () => {
|
test('If validator was added later from chain it should not include it', async () => {
|
||||||
const currentValidators = [validator1, validator2, validator3]
|
const currentValidators = [validator1, validator2, validator3]
|
||||||
const contract = ({
|
const contract = ({
|
||||||
getPastEvents: jest.fn().mockImplementation(async event => {
|
getPastEvents: jest.fn().mockImplementation(event => {
|
||||||
if (event === 'ValidatorAdded') {
|
if (event === 'ValidatorAdded') {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
@@ -385,7 +385,7 @@ describe('getValidatorList', () => {
|
|||||||
test('If validator was removed later from snapshot it should include it', async () => {
|
test('If validator was removed later from snapshot it should include it', async () => {
|
||||||
const currentValidators = [validator1, validator2]
|
const currentValidators = [validator1, validator2]
|
||||||
const contract = ({
|
const contract = ({
|
||||||
getPastEvents: jest.fn().mockImplementation(async () => []),
|
getPastEvents: jest.fn().mockImplementation(() => []),
|
||||||
methods: methodsBuilder(currentValidators)
|
methods: methodsBuilder(currentValidators)
|
||||||
} as unknown) as Contract
|
} as unknown) as Contract
|
||||||
|
|
||||||
@@ -424,7 +424,7 @@ describe('getValidatorList', () => {
|
|||||||
test('If validator was removed later from chain it should include it', async () => {
|
test('If validator was removed later from chain it should include it', async () => {
|
||||||
const currentValidators = [validator1, validator2]
|
const currentValidators = [validator1, validator2]
|
||||||
const contract = ({
|
const contract = ({
|
||||||
getPastEvents: jest.fn().mockImplementation(async event => {
|
getPastEvents: jest.fn().mockImplementation(event => {
|
||||||
if (event === 'ValidatorRemoved') {
|
if (event === 'ValidatorRemoved') {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -17,33 +17,19 @@ const otherAddress = '0xD4075FB57fCf038bFc702c915Ef9592534bED5c1'
|
|||||||
|
|
||||||
describe('getFailedTransactions', () => {
|
describe('getFailedTransactions', () => {
|
||||||
test('should only return failed transactions', async () => {
|
test('should only return failed transactions', async () => {
|
||||||
const to = otherAddress
|
const transactions = [{ isError: '0' }, { isError: '1' }, { isError: '0' }, { isError: '1' }, { isError: '1' }]
|
||||||
const transactions = [
|
|
||||||
{ isError: '0', to },
|
|
||||||
{ isError: '1', to },
|
|
||||||
{ isError: '0', to },
|
|
||||||
{ isError: '1', to },
|
|
||||||
{ isError: '1', to }
|
|
||||||
]
|
|
||||||
|
|
||||||
const fetchAccountTransactions = jest.fn().mockImplementation(() => transactions)
|
const fetchAccountTransactions = jest.fn().mockImplementation(() => transactions)
|
||||||
const result = await getFailedTransactions('', to, 0, 1, '', fetchAccountTransactions)
|
const result = await getFailedTransactions('', '', 0, 1, '', fetchAccountTransactions)
|
||||||
expect(result.length).toEqual(3)
|
expect(result.length).toEqual(3)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
describe('getSuccessTransactions', () => {
|
describe('getSuccessTransactions', () => {
|
||||||
test('should only return success transactions', async () => {
|
test('should only return success transactions', async () => {
|
||||||
const to = otherAddress
|
const transactions = [{ isError: '0' }, { isError: '1' }, { isError: '0' }, { isError: '1' }, { isError: '1' }]
|
||||||
const transactions = [
|
|
||||||
{ isError: '0', to },
|
|
||||||
{ isError: '1', to },
|
|
||||||
{ isError: '0', to },
|
|
||||||
{ isError: '1', to },
|
|
||||||
{ isError: '1', to }
|
|
||||||
]
|
|
||||||
|
|
||||||
const fetchAccountTransactions = jest.fn().mockImplementation(() => transactions)
|
const fetchAccountTransactions = jest.fn().mockImplementation(() => transactions)
|
||||||
const result = await getSuccessTransactions('', to, 0, 1, '', fetchAccountTransactions)
|
const result = await getSuccessTransactions('', '', 0, 1, '', fetchAccountTransactions)
|
||||||
expect(result.length).toEqual(2)
|
expect(result.length).toEqual(2)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -88,8 +74,8 @@ describe('getExecutionFailedTransactionForMessage', () => {
|
|||||||
account: '',
|
account: '',
|
||||||
to: '',
|
to: '',
|
||||||
messageData,
|
messageData,
|
||||||
startBlock: 0,
|
startTimestamp: 0,
|
||||||
endBlock: 1
|
endTimestamp: 1
|
||||||
},
|
},
|
||||||
fetchAccountTransactions
|
fetchAccountTransactions
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { BasicConfirmationParam } from '../../hooks/useMessageConfirmations'
|
|||||||
|
|
||||||
jest.mock('../validatorConfirmationHelpers')
|
jest.mock('../validatorConfirmationHelpers')
|
||||||
|
|
||||||
const getSuccessExecutionTransaction = helpers.getSuccessExecutionTransaction as jest.Mock<any>
|
const getValidatorSuccessTransaction = helpers.getValidatorSuccessTransaction as jest.Mock<any>
|
||||||
const getValidatorConfirmation = helpers.getValidatorConfirmation as jest.Mock<any>
|
const getValidatorConfirmation = helpers.getValidatorConfirmation as jest.Mock<any>
|
||||||
const getValidatorFailedTransaction = helpers.getValidatorFailedTransaction as jest.Mock<any>
|
const getValidatorFailedTransaction = helpers.getValidatorFailedTransaction as jest.Mock<any>
|
||||||
const getValidatorPendingTransaction = helpers.getValidatorPendingTransaction as jest.Mock<any>
|
const getValidatorPendingTransaction = helpers.getValidatorPendingTransaction as jest.Mock<any>
|
||||||
@@ -24,17 +24,10 @@ const validator1 = '0x45b96809336A8b714BFbdAB3E4B5e0fe5d839908'
|
|||||||
const validator2 = '0xAe8bFfc8BBc6AAa9E21ED1E4e4957fe798BEA25f'
|
const validator2 = '0xAe8bFfc8BBc6AAa9E21ED1E4e4957fe798BEA25f'
|
||||||
const validator3 = '0x285A6eB779be4db94dA65e2F3518B1c5F0f71244'
|
const validator3 = '0x285A6eB779be4db94dA65e2F3518B1c5F0f71244'
|
||||||
const validatorList = [validator1, validator2, validator3]
|
const validatorList = [validator1, validator2, validator3]
|
||||||
const signature =
|
const bridgeContract = {} as Contract
|
||||||
'0x519d704bceed17423daa79c20531cc34fc27a4be6e53fc5069a8023019188ca4519d704bceed17423daa79c20531cc34fc27a4be6e53fc5069a8023019188ca4'
|
const confirmationContractMethod = () => {}
|
||||||
const bridgeContract = {
|
|
||||||
methods: {
|
|
||||||
signature: () => ({
|
|
||||||
call: () => signature
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} as Contract
|
|
||||||
const requiredSignatures = 2
|
const requiredSignatures = 2
|
||||||
const isCancelled = () => false
|
const waitingBlocksResolved = true
|
||||||
let subscriptions: Array<number> = []
|
let subscriptions: Array<number> = []
|
||||||
const timestamp = 1594045859
|
const timestamp = 1594045859
|
||||||
const getFailedTransactions = (): Promise<APITransaction[]> => Promise.resolve([])
|
const getFailedTransactions = (): Promise<APITransaction[]> => Promise.resolve([])
|
||||||
@@ -49,7 +42,7 @@ const unsubscribe = () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
// Clear all instances and calls to constructor and all methods:
|
// Clear all instances and calls to constructor and all methods:
|
||||||
getSuccessExecutionTransaction.mockClear()
|
getValidatorSuccessTransaction.mockClear()
|
||||||
getValidatorConfirmation.mockClear()
|
getValidatorConfirmation.mockClear()
|
||||||
getValidatorFailedTransaction.mockClear()
|
getValidatorFailedTransaction.mockClear()
|
||||||
getValidatorPendingTransaction.mockClear()
|
getValidatorPendingTransaction.mockClear()
|
||||||
@@ -61,7 +54,7 @@ describe('getConfirmationsForTx', () => {
|
|||||||
validator,
|
validator,
|
||||||
status: validator !== validator3 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
status: validator !== validator3 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
||||||
}))
|
}))
|
||||||
getSuccessExecutionTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
getValidatorSuccessTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
||||||
validator: validatorData.validator,
|
validator: validatorData.validator,
|
||||||
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
||||||
txHash: '',
|
txHash: '',
|
||||||
@@ -90,12 +83,12 @@ describe('getConfirmationsForTx', () => {
|
|||||||
web3,
|
web3,
|
||||||
validatorList,
|
validatorList,
|
||||||
bridgeContract,
|
bridgeContract,
|
||||||
true,
|
confirmationContractMethod,
|
||||||
setResult,
|
setResult,
|
||||||
requiredSignatures,
|
requiredSignatures,
|
||||||
setSignatureCollected,
|
setSignatureCollected,
|
||||||
subscriptions.push.bind(subscriptions),
|
waitingBlocksResolved,
|
||||||
isCancelled,
|
subscriptions,
|
||||||
timestamp,
|
timestamp,
|
||||||
getFailedTransactions,
|
getFailedTransactions,
|
||||||
setFailedConfirmations,
|
setFailedConfirmations,
|
||||||
@@ -109,10 +102,9 @@ describe('getConfirmationsForTx', () => {
|
|||||||
expect(subscriptions.length).toEqual(1)
|
expect(subscriptions.length).toEqual(1)
|
||||||
expect(setResult).toBeCalledTimes(2)
|
expect(setResult).toBeCalledTimes(2)
|
||||||
expect(getValidatorConfirmation).toBeCalledTimes(1)
|
expect(getValidatorConfirmation).toBeCalledTimes(1)
|
||||||
expect(getSuccessExecutionTransaction).toBeCalledTimes(1)
|
expect(getValidatorSuccessTransaction).toBeCalledTimes(1)
|
||||||
expect(setSignatureCollected).toBeCalledTimes(2)
|
expect(setSignatureCollected).toBeCalledTimes(1)
|
||||||
expect(setSignatureCollected.mock.calls[0][0]).toEqual(true)
|
expect(setSignatureCollected.mock.calls[0][0]).toEqual(true)
|
||||||
expect(setSignatureCollected.mock.calls[1][0]).toEqual([signature, signature])
|
|
||||||
|
|
||||||
expect(getValidatorFailedTransaction).toBeCalledTimes(1)
|
expect(getValidatorFailedTransaction).toBeCalledTimes(1)
|
||||||
expect(setFailedConfirmations).toBeCalledTimes(1)
|
expect(setFailedConfirmations).toBeCalledTimes(1)
|
||||||
@@ -122,16 +114,14 @@ describe('getConfirmationsForTx', () => {
|
|||||||
expect(setPendingConfirmations).toBeCalledTimes(1)
|
expect(setPendingConfirmations).toBeCalledTimes(1)
|
||||||
expect(setPendingConfirmations.mock.calls[0][0]).toEqual(false)
|
expect(setPendingConfirmations.mock.calls[0][0]).toEqual(false)
|
||||||
|
|
||||||
const res1 = setResult.mock.calls[0][0]()
|
expect(setResult.mock.calls[0][0]()).toEqual(
|
||||||
const res2 = setResult.mock.calls[1][0](res1)
|
|
||||||
expect(res1).toEqual(
|
|
||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||||
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED }
|
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED }
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
expect(res2).toEqual(
|
expect(setResult.mock.calls[1][0]).toEqual(
|
||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||||
@@ -144,7 +134,7 @@ describe('getConfirmationsForTx', () => {
|
|||||||
validator,
|
validator,
|
||||||
status: validator === validator3 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
status: validator === validator3 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
||||||
}))
|
}))
|
||||||
getSuccessExecutionTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
getValidatorSuccessTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
||||||
validator: validatorData.validator,
|
validator: validatorData.validator,
|
||||||
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
||||||
txHash: '',
|
txHash: '',
|
||||||
@@ -173,12 +163,12 @@ describe('getConfirmationsForTx', () => {
|
|||||||
web3,
|
web3,
|
||||||
validatorList,
|
validatorList,
|
||||||
bridgeContract,
|
bridgeContract,
|
||||||
true,
|
confirmationContractMethod,
|
||||||
setResult,
|
setResult,
|
||||||
requiredSignatures,
|
requiredSignatures,
|
||||||
setSignatureCollected,
|
setSignatureCollected,
|
||||||
subscriptions.push.bind(subscriptions),
|
waitingBlocksResolved,
|
||||||
isCancelled,
|
subscriptions,
|
||||||
timestamp,
|
timestamp,
|
||||||
getFailedTransactions,
|
getFailedTransactions,
|
||||||
setFailedConfirmations,
|
setFailedConfirmations,
|
||||||
@@ -189,9 +179,9 @@ describe('getConfirmationsForTx', () => {
|
|||||||
|
|
||||||
unsubscribe()
|
unsubscribe()
|
||||||
|
|
||||||
expect(setResult).toBeCalledTimes(1)
|
expect(setResult).toBeCalledTimes(2)
|
||||||
expect(getValidatorConfirmation).toBeCalledTimes(1)
|
expect(getValidatorConfirmation).toBeCalledTimes(1)
|
||||||
expect(getSuccessExecutionTransaction).toBeCalledTimes(1)
|
expect(getValidatorSuccessTransaction).toBeCalledTimes(1)
|
||||||
expect(setSignatureCollected).toBeCalledTimes(1)
|
expect(setSignatureCollected).toBeCalledTimes(1)
|
||||||
expect(setSignatureCollected.mock.calls[0][0]).toEqual(false)
|
expect(setSignatureCollected.mock.calls[0][0]).toEqual(false)
|
||||||
|
|
||||||
@@ -208,7 +198,7 @@ describe('getConfirmationsForTx', () => {
|
|||||||
validator,
|
validator,
|
||||||
status: validator !== validator3 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
status: validator !== validator3 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
||||||
}))
|
}))
|
||||||
getSuccessExecutionTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
getValidatorSuccessTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
||||||
validator: validatorData.validator,
|
validator: validatorData.validator,
|
||||||
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
||||||
txHash: validatorData.validator !== validator3 ? '0x123' : '',
|
txHash: validatorData.validator !== validator3 ? '0x123' : '',
|
||||||
@@ -237,12 +227,12 @@ describe('getConfirmationsForTx', () => {
|
|||||||
web3,
|
web3,
|
||||||
validatorList,
|
validatorList,
|
||||||
bridgeContract,
|
bridgeContract,
|
||||||
true,
|
confirmationContractMethod,
|
||||||
setResult,
|
setResult,
|
||||||
requiredSignatures,
|
requiredSignatures,
|
||||||
setSignatureCollected,
|
setSignatureCollected,
|
||||||
subscriptions.push.bind(subscriptions),
|
waitingBlocksResolved,
|
||||||
isCancelled,
|
subscriptions,
|
||||||
timestamp,
|
timestamp,
|
||||||
getFailedTransactions,
|
getFailedTransactions,
|
||||||
setFailedConfirmations,
|
setFailedConfirmations,
|
||||||
@@ -254,12 +244,11 @@ describe('getConfirmationsForTx', () => {
|
|||||||
unsubscribe()
|
unsubscribe()
|
||||||
|
|
||||||
expect(subscriptions.length).toEqual(0)
|
expect(subscriptions.length).toEqual(0)
|
||||||
expect(setResult).toBeCalledTimes(3)
|
expect(setResult).toBeCalledTimes(2)
|
||||||
expect(getValidatorConfirmation).toBeCalledTimes(1)
|
expect(getValidatorConfirmation).toBeCalledTimes(1)
|
||||||
expect(getSuccessExecutionTransaction).toBeCalledTimes(1)
|
expect(getValidatorSuccessTransaction).toBeCalledTimes(1)
|
||||||
expect(setSignatureCollected).toBeCalledTimes(2)
|
expect(setSignatureCollected).toBeCalledTimes(1)
|
||||||
expect(setSignatureCollected.mock.calls[0][0]).toEqual(true)
|
expect(setSignatureCollected.mock.calls[0][0]).toEqual(true)
|
||||||
expect(setSignatureCollected.mock.calls[1][0]).toEqual([signature, signature])
|
|
||||||
|
|
||||||
expect(getValidatorFailedTransaction).toBeCalledTimes(1)
|
expect(getValidatorFailedTransaction).toBeCalledTimes(1)
|
||||||
expect(setFailedConfirmations).toBeCalledTimes(1)
|
expect(setFailedConfirmations).toBeCalledTimes(1)
|
||||||
@@ -269,24 +258,14 @@ describe('getConfirmationsForTx', () => {
|
|||||||
expect(setPendingConfirmations).toBeCalledTimes(1)
|
expect(setPendingConfirmations).toBeCalledTimes(1)
|
||||||
expect(setPendingConfirmations.mock.calls[0][0]).toEqual(false)
|
expect(setPendingConfirmations.mock.calls[0][0]).toEqual(false)
|
||||||
|
|
||||||
const res1 = setResult.mock.calls[0][0]()
|
expect(setResult.mock.calls[0][0]()).toEqual(
|
||||||
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([
|
expect.arrayContaining([
|
||||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||||
{ validator: validator2, 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.NOT_REQUIRED }
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
expect(res3).toEqual(
|
expect(setResult.mock.calls[1][0]).toEqual(
|
||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
||||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
||||||
@@ -304,7 +283,7 @@ describe('getConfirmationsForTx', () => {
|
|||||||
? VALIDATOR_CONFIRMATION_STATUS.SUCCESS
|
? VALIDATOR_CONFIRMATION_STATUS.SUCCESS
|
||||||
: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
||||||
}))
|
}))
|
||||||
getSuccessExecutionTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
getValidatorSuccessTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
||||||
validator: validatorData.validator,
|
validator: validatorData.validator,
|
||||||
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
||||||
txHash: validatorData.validator !== validator3 && validatorData.validator !== validator4 ? '0x123' : '',
|
txHash: validatorData.validator !== validator3 && validatorData.validator !== validator4 ? '0x123' : '',
|
||||||
@@ -336,12 +315,12 @@ describe('getConfirmationsForTx', () => {
|
|||||||
web3,
|
web3,
|
||||||
validatorList,
|
validatorList,
|
||||||
bridgeContract,
|
bridgeContract,
|
||||||
true,
|
confirmationContractMethod,
|
||||||
setResult,
|
setResult,
|
||||||
requiredSignatures,
|
requiredSignatures,
|
||||||
setSignatureCollected,
|
setSignatureCollected,
|
||||||
subscriptions.push.bind(subscriptions),
|
waitingBlocksResolved,
|
||||||
isCancelled,
|
subscriptions,
|
||||||
timestamp,
|
timestamp,
|
||||||
getFailedTransactions,
|
getFailedTransactions,
|
||||||
setFailedConfirmations,
|
setFailedConfirmations,
|
||||||
@@ -353,12 +332,11 @@ describe('getConfirmationsForTx', () => {
|
|||||||
unsubscribe()
|
unsubscribe()
|
||||||
|
|
||||||
expect(subscriptions.length).toEqual(0)
|
expect(subscriptions.length).toEqual(0)
|
||||||
expect(setResult).toBeCalledTimes(4)
|
expect(setResult).toBeCalledTimes(2)
|
||||||
expect(getValidatorConfirmation).toBeCalledTimes(1)
|
expect(getValidatorConfirmation).toBeCalledTimes(1)
|
||||||
expect(getSuccessExecutionTransaction).toBeCalledTimes(1)
|
expect(getValidatorSuccessTransaction).toBeCalledTimes(1)
|
||||||
expect(setSignatureCollected).toBeCalledTimes(2)
|
expect(setSignatureCollected).toBeCalledTimes(1)
|
||||||
expect(setSignatureCollected.mock.calls[0][0]).toEqual(true)
|
expect(setSignatureCollected.mock.calls[0][0]).toEqual(true)
|
||||||
expect(setSignatureCollected.mock.calls[1][0]).toEqual([signature, signature])
|
|
||||||
|
|
||||||
expect(getValidatorFailedTransaction).toBeCalledTimes(1)
|
expect(getValidatorFailedTransaction).toBeCalledTimes(1)
|
||||||
expect(setFailedConfirmations).toBeCalledTimes(1)
|
expect(setFailedConfirmations).toBeCalledTimes(1)
|
||||||
@@ -368,27 +346,7 @@ describe('getConfirmationsForTx', () => {
|
|||||||
expect(setPendingConfirmations).toBeCalledTimes(1)
|
expect(setPendingConfirmations).toBeCalledTimes(1)
|
||||||
expect(setPendingConfirmations.mock.calls[0][0]).toEqual(false)
|
expect(setPendingConfirmations.mock.calls[0][0]).toEqual(false)
|
||||||
|
|
||||||
const res1 = setResult.mock.calls[0][0]()
|
expect(setResult.mock.calls[0][0]()).toEqual(
|
||||||
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([
|
expect.arrayContaining([
|
||||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||||
@@ -396,7 +354,7 @@ describe('getConfirmationsForTx', () => {
|
|||||||
{ validator: validator4, status: VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED }
|
{ validator: validator4, status: VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED }
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
expect(res4).toEqual(
|
expect(setResult.mock.calls[1][0]).toEqual(
|
||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
||||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
||||||
@@ -414,7 +372,7 @@ describe('getConfirmationsForTx', () => {
|
|||||||
validator,
|
validator,
|
||||||
status: validator === validator1 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
status: validator === validator1 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
||||||
}))
|
}))
|
||||||
getSuccessExecutionTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
getValidatorSuccessTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
||||||
validator: validatorData.validator,
|
validator: validatorData.validator,
|
||||||
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
||||||
txHash: validatorData.validator === validator1 ? '0x123' : '',
|
txHash: validatorData.validator === validator1 ? '0x123' : '',
|
||||||
@@ -449,12 +407,12 @@ describe('getConfirmationsForTx', () => {
|
|||||||
web3,
|
web3,
|
||||||
validatorList,
|
validatorList,
|
||||||
bridgeContract,
|
bridgeContract,
|
||||||
true,
|
confirmationContractMethod,
|
||||||
setResult,
|
setResult,
|
||||||
requiredSignatures,
|
requiredSignatures,
|
||||||
setSignatureCollected,
|
setSignatureCollected,
|
||||||
subscriptions.push.bind(subscriptions),
|
waitingBlocksResolved,
|
||||||
isCancelled,
|
subscriptions,
|
||||||
timestamp,
|
timestamp,
|
||||||
getFailedTransactions,
|
getFailedTransactions,
|
||||||
setFailedConfirmations,
|
setFailedConfirmations,
|
||||||
@@ -465,9 +423,9 @@ describe('getConfirmationsForTx', () => {
|
|||||||
|
|
||||||
unsubscribe()
|
unsubscribe()
|
||||||
|
|
||||||
expect(setResult).toBeCalledTimes(4)
|
expect(setResult).toBeCalledTimes(2)
|
||||||
expect(getValidatorConfirmation).toBeCalledTimes(1)
|
expect(getValidatorConfirmation).toBeCalledTimes(1)
|
||||||
expect(getSuccessExecutionTransaction).toBeCalledTimes(1)
|
expect(getValidatorSuccessTransaction).toBeCalledTimes(1)
|
||||||
expect(setSignatureCollected).toBeCalledTimes(1)
|
expect(setSignatureCollected).toBeCalledTimes(1)
|
||||||
expect(setSignatureCollected.mock.calls[0][0]).toEqual(false)
|
expect(setSignatureCollected.mock.calls[0][0]).toEqual(false)
|
||||||
|
|
||||||
@@ -479,32 +437,14 @@ describe('getConfirmationsForTx', () => {
|
|||||||
expect(setPendingConfirmations).toBeCalledTimes(1)
|
expect(setPendingConfirmations).toBeCalledTimes(1)
|
||||||
expect(setPendingConfirmations.mock.calls[0][0]).toEqual(true)
|
expect(setPendingConfirmations.mock.calls[0][0]).toEqual(true)
|
||||||
|
|
||||||
const res1 = setResult.mock.calls[0][0]()
|
expect(setResult.mock.calls[0][0]()).toEqual(
|
||||||
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([
|
expect.arrayContaining([
|
||||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, 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 }
|
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.PENDING, txHash: '0x123', timestamp: 123 }
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
expect(res4).toEqual(
|
expect(setResult.mock.calls[1][0]).toEqual(
|
||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
||||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
|
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
|
||||||
@@ -521,7 +461,7 @@ describe('getConfirmationsForTx', () => {
|
|||||||
validator,
|
validator,
|
||||||
status: validator === validator1 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
status: validator === validator1 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
||||||
}))
|
}))
|
||||||
getSuccessExecutionTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
getValidatorSuccessTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
||||||
validator: validatorData.validator,
|
validator: validatorData.validator,
|
||||||
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
||||||
txHash: validatorData.validator === validator1 ? '0x123' : '',
|
txHash: validatorData.validator === validator1 ? '0x123' : '',
|
||||||
@@ -553,12 +493,12 @@ describe('getConfirmationsForTx', () => {
|
|||||||
web3,
|
web3,
|
||||||
validatorList,
|
validatorList,
|
||||||
bridgeContract,
|
bridgeContract,
|
||||||
true,
|
confirmationContractMethod,
|
||||||
setResult,
|
setResult,
|
||||||
requiredSignatures,
|
requiredSignatures,
|
||||||
setSignatureCollected,
|
setSignatureCollected,
|
||||||
subscriptions.push.bind(subscriptions),
|
waitingBlocksResolved,
|
||||||
isCancelled,
|
subscriptions,
|
||||||
timestamp,
|
timestamp,
|
||||||
getFailedTransactions,
|
getFailedTransactions,
|
||||||
setFailedConfirmations,
|
setFailedConfirmations,
|
||||||
@@ -570,9 +510,9 @@ describe('getConfirmationsForTx', () => {
|
|||||||
unsubscribe()
|
unsubscribe()
|
||||||
|
|
||||||
expect(subscriptions.length).toEqual(0)
|
expect(subscriptions.length).toEqual(0)
|
||||||
expect(setResult).toBeCalledTimes(3)
|
expect(setResult).toBeCalledTimes(2)
|
||||||
expect(getValidatorConfirmation).toBeCalledTimes(1)
|
expect(getValidatorConfirmation).toBeCalledTimes(1)
|
||||||
expect(getSuccessExecutionTransaction).toBeCalledTimes(1)
|
expect(getValidatorSuccessTransaction).toBeCalledTimes(1)
|
||||||
expect(setSignatureCollected).toBeCalledTimes(1)
|
expect(setSignatureCollected).toBeCalledTimes(1)
|
||||||
expect(setSignatureCollected.mock.calls[0][0]).toEqual(false)
|
expect(setSignatureCollected.mock.calls[0][0]).toEqual(false)
|
||||||
|
|
||||||
@@ -584,24 +524,14 @@ describe('getConfirmationsForTx', () => {
|
|||||||
expect(setPendingConfirmations).toBeCalledTimes(1)
|
expect(setPendingConfirmations).toBeCalledTimes(1)
|
||||||
expect(setPendingConfirmations.mock.calls[0][0]).toEqual(false)
|
expect(setPendingConfirmations.mock.calls[0][0]).toEqual(false)
|
||||||
|
|
||||||
const res1 = setResult.mock.calls[0][0]()
|
expect(setResult.mock.calls[0][0]()).toEqual(
|
||||||
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([
|
expect.arrayContaining([
|
||||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
|
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
|
||||||
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 }
|
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 }
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
expect(res3).toEqual(
|
expect(setResult.mock.calls[1][0]).toEqual(
|
||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
||||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
|
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
|
||||||
@@ -625,7 +555,7 @@ describe('getConfirmationsForTx', () => {
|
|||||||
status:
|
status:
|
||||||
validator !== validator2 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
validator !== validator2 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
||||||
}))
|
}))
|
||||||
getSuccessExecutionTransaction
|
getValidatorSuccessTransaction
|
||||||
.mockImplementationOnce(() => async (validatorData: BasicConfirmationParam) => ({
|
.mockImplementationOnce(() => async (validatorData: BasicConfirmationParam) => ({
|
||||||
validator: validatorData.validator,
|
validator: validatorData.validator,
|
||||||
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
||||||
@@ -674,12 +604,12 @@ describe('getConfirmationsForTx', () => {
|
|||||||
web3,
|
web3,
|
||||||
validatorList,
|
validatorList,
|
||||||
bridgeContract,
|
bridgeContract,
|
||||||
true,
|
confirmationContractMethod,
|
||||||
setResult,
|
setResult,
|
||||||
requiredSignatures,
|
requiredSignatures,
|
||||||
setSignatureCollected,
|
setSignatureCollected,
|
||||||
subscriptions.push.bind(subscriptions),
|
waitingBlocksResolved,
|
||||||
isCancelled,
|
subscriptions,
|
||||||
timestamp,
|
timestamp,
|
||||||
getFailedTransactions,
|
getFailedTransactions,
|
||||||
setFailedConfirmations,
|
setFailedConfirmations,
|
||||||
@@ -690,9 +620,9 @@ describe('getConfirmationsForTx', () => {
|
|||||||
|
|
||||||
unsubscribe()
|
unsubscribe()
|
||||||
|
|
||||||
expect(setResult).toBeCalledTimes(4)
|
expect(setResult).toBeCalledTimes(2)
|
||||||
expect(getValidatorConfirmation).toBeCalledTimes(1)
|
expect(getValidatorConfirmation).toBeCalledTimes(1)
|
||||||
expect(getSuccessExecutionTransaction).toBeCalledTimes(1)
|
expect(getValidatorSuccessTransaction).toBeCalledTimes(1)
|
||||||
expect(setSignatureCollected).toBeCalledTimes(1)
|
expect(setSignatureCollected).toBeCalledTimes(1)
|
||||||
expect(setSignatureCollected.mock.calls[0][0]).toEqual(false)
|
expect(setSignatureCollected.mock.calls[0][0]).toEqual(false)
|
||||||
|
|
||||||
@@ -704,32 +634,14 @@ describe('getConfirmationsForTx', () => {
|
|||||||
expect(setPendingConfirmations).toBeCalledTimes(1)
|
expect(setPendingConfirmations).toBeCalledTimes(1)
|
||||||
expect(setPendingConfirmations.mock.calls[0][0]).toEqual(true)
|
expect(setPendingConfirmations.mock.calls[0][0]).toEqual(true)
|
||||||
|
|
||||||
const res1 = setResult.mock.calls[0][0]()
|
expect(setResult.mock.calls[0][0]()).toEqual(
|
||||||
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([
|
expect.arrayContaining([
|
||||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, 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 }
|
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.PENDING, txHash: '0x123', timestamp: 123 }
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
expect(res4).toEqual(
|
expect(setResult.mock.calls[1][0]).toEqual(
|
||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
||||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
|
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
|
||||||
@@ -742,12 +654,12 @@ describe('getConfirmationsForTx', () => {
|
|||||||
web3,
|
web3,
|
||||||
validatorList,
|
validatorList,
|
||||||
bridgeContract,
|
bridgeContract,
|
||||||
true,
|
confirmationContractMethod,
|
||||||
setResult,
|
setResult,
|
||||||
requiredSignatures,
|
requiredSignatures,
|
||||||
setSignatureCollected,
|
setSignatureCollected,
|
||||||
subscriptions.push.bind(subscriptions),
|
waitingBlocksResolved,
|
||||||
isCancelled,
|
subscriptions,
|
||||||
timestamp,
|
timestamp,
|
||||||
getFailedTransactions,
|
getFailedTransactions,
|
||||||
setFailedConfirmations,
|
setFailedConfirmations,
|
||||||
@@ -758,13 +670,12 @@ describe('getConfirmationsForTx', () => {
|
|||||||
|
|
||||||
unsubscribe()
|
unsubscribe()
|
||||||
|
|
||||||
expect(setResult).toBeCalledTimes(7)
|
expect(setResult).toBeCalledTimes(4)
|
||||||
expect(getValidatorConfirmation).toBeCalledTimes(2)
|
expect(getValidatorConfirmation).toBeCalledTimes(2)
|
||||||
expect(getSuccessExecutionTransaction).toBeCalledTimes(2)
|
expect(getValidatorSuccessTransaction).toBeCalledTimes(2)
|
||||||
expect(setSignatureCollected).toBeCalledTimes(3)
|
expect(setSignatureCollected).toBeCalledTimes(2)
|
||||||
expect(setSignatureCollected.mock.calls[0][0]).toEqual(false)
|
expect(setSignatureCollected.mock.calls[0][0]).toEqual(false)
|
||||||
expect(setSignatureCollected.mock.calls[1][0]).toEqual(true)
|
expect(setSignatureCollected.mock.calls[1][0]).toEqual(true)
|
||||||
expect(setSignatureCollected.mock.calls[2][0]).toEqual([signature, signature])
|
|
||||||
|
|
||||||
expect(getValidatorFailedTransaction).toBeCalledTimes(2)
|
expect(getValidatorFailedTransaction).toBeCalledTimes(2)
|
||||||
expect(setFailedConfirmations).toBeCalledTimes(2)
|
expect(setFailedConfirmations).toBeCalledTimes(2)
|
||||||
@@ -776,24 +687,14 @@ describe('getConfirmationsForTx', () => {
|
|||||||
expect(setPendingConfirmations.mock.calls[0][0]).toEqual(true)
|
expect(setPendingConfirmations.mock.calls[0][0]).toEqual(true)
|
||||||
expect(setPendingConfirmations.mock.calls[1][0]).toEqual(false)
|
expect(setPendingConfirmations.mock.calls[1][0]).toEqual(false)
|
||||||
|
|
||||||
const res5 = setResult.mock.calls[4][0](res4)
|
expect(setResult.mock.calls[2][0]()).toEqual(
|
||||||
const res6 = setResult.mock.calls[5][0](res5)
|
|
||||||
const res7 = setResult.mock.calls[6][0](res6)
|
|
||||||
expect(res5).toEqual(
|
|
||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
|
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
|
||||||
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS }
|
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS }
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
expect(res6).toEqual(
|
expect(setResult.mock.calls[3][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.SUCCESS }
|
|
||||||
])
|
|
||||||
)
|
|
||||||
expect(res7).toEqual(
|
|
||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
||||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
|
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import Web3 from 'web3'
|
|||||||
import { getFinalizationEvent } from '../getFinalizationEvent'
|
import { getFinalizationEvent } from '../getFinalizationEvent'
|
||||||
import { VALIDATOR_CONFIRMATION_STATUS } from '../../config/constants'
|
import { VALIDATOR_CONFIRMATION_STATUS } from '../../config/constants'
|
||||||
|
|
||||||
|
const eventName = 'RelayedMessage'
|
||||||
const timestamp = 1594045859
|
const timestamp = 1594045859
|
||||||
const validator1 = '0x45b96809336A8b714BFbdAB3E4B5e0fe5d839908'
|
const validator1 = '0x45b96809336A8b714BFbdAB3E4B5e0fe5d839908'
|
||||||
const txHash = '0xdab36c9210e7e45fb82af10ffe4960461e41661dce0c9cd36b2843adaa1df156'
|
const txHash = '0xdab36c9210e7e45fb82af10ffe4960461e41661dce0c9cd36b2843adaa1df156'
|
||||||
@@ -19,11 +20,12 @@ const web3 = ({
|
|||||||
toChecksumAddress: (a: string) => a
|
toChecksumAddress: (a: string) => a
|
||||||
}
|
}
|
||||||
} as unknown) as Web3
|
} as unknown) as Web3
|
||||||
|
const waitingBlocksResolved = true
|
||||||
const message = {
|
const message = {
|
||||||
id: '0x123',
|
id: '0x123',
|
||||||
data: '0x123456789'
|
data: '0x123456789'
|
||||||
}
|
}
|
||||||
const isCancelled = () => false
|
const interval = 10000
|
||||||
let subscriptions: Array<number> = []
|
let subscriptions: Array<number> = []
|
||||||
|
|
||||||
const event = {
|
const event = {
|
||||||
@@ -48,7 +50,7 @@ beforeEach(() => {
|
|||||||
describe('getFinalizationEvent', () => {
|
describe('getFinalizationEvent', () => {
|
||||||
test('should get finalization event and not try to get failed or pending transactions', async () => {
|
test('should get finalization event and not try to get failed or pending transactions', async () => {
|
||||||
const contract = ({
|
const contract = ({
|
||||||
getPastEvents: async () => {
|
getPastEvents: () => {
|
||||||
return [event]
|
return [event]
|
||||||
}
|
}
|
||||||
} as unknown) as Contract
|
} as unknown) as Contract
|
||||||
@@ -59,23 +61,22 @@ describe('getFinalizationEvent', () => {
|
|||||||
const setFailedExecution = jest.fn()
|
const setFailedExecution = jest.fn()
|
||||||
const getPendingExecution = jest.fn()
|
const getPendingExecution = jest.fn()
|
||||||
const setPendingExecution = jest.fn()
|
const setPendingExecution = jest.fn()
|
||||||
const setExecutionEventsFetched = jest.fn()
|
|
||||||
|
|
||||||
await getFinalizationEvent(
|
await getFinalizationEvent(
|
||||||
true,
|
|
||||||
contract,
|
contract,
|
||||||
|
eventName,
|
||||||
web3,
|
web3,
|
||||||
setResult,
|
setResult,
|
||||||
|
waitingBlocksResolved,
|
||||||
message,
|
message,
|
||||||
subscriptions.push.bind(subscriptions),
|
interval,
|
||||||
isCancelled,
|
subscriptions,
|
||||||
timestamp,
|
timestamp,
|
||||||
collectedSignaturesEvent,
|
collectedSignaturesEvent,
|
||||||
getFailedExecution,
|
getFailedExecution,
|
||||||
setFailedExecution,
|
setFailedExecution,
|
||||||
getPendingExecution,
|
getPendingExecution,
|
||||||
setPendingExecution,
|
setPendingExecution
|
||||||
setExecutionEventsFetched
|
|
||||||
)
|
)
|
||||||
|
|
||||||
unsubscribe()
|
unsubscribe()
|
||||||
@@ -98,7 +99,7 @@ describe('getFinalizationEvent', () => {
|
|||||||
})
|
})
|
||||||
test('should retry to get finalization event and not try to get failed or pending transactions if foreign to home transaction', async () => {
|
test('should retry to get finalization event and not try to get failed or pending transactions if foreign to home transaction', async () => {
|
||||||
const contract = ({
|
const contract = ({
|
||||||
getPastEvents: async () => {
|
getPastEvents: () => {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
} as unknown) as Contract
|
} as unknown) as Contract
|
||||||
@@ -109,23 +110,22 @@ describe('getFinalizationEvent', () => {
|
|||||||
const setFailedExecution = jest.fn()
|
const setFailedExecution = jest.fn()
|
||||||
const getPendingExecution = jest.fn()
|
const getPendingExecution = jest.fn()
|
||||||
const setPendingExecution = jest.fn()
|
const setPendingExecution = jest.fn()
|
||||||
const setExecutionEventsFetched = jest.fn()
|
|
||||||
|
|
||||||
await getFinalizationEvent(
|
await getFinalizationEvent(
|
||||||
true,
|
|
||||||
contract,
|
contract,
|
||||||
|
eventName,
|
||||||
web3,
|
web3,
|
||||||
setResult,
|
setResult,
|
||||||
|
waitingBlocksResolved,
|
||||||
message,
|
message,
|
||||||
subscriptions.push.bind(subscriptions),
|
interval,
|
||||||
isCancelled,
|
subscriptions,
|
||||||
timestamp,
|
timestamp,
|
||||||
collectedSignaturesEvent,
|
collectedSignaturesEvent,
|
||||||
getFailedExecution,
|
getFailedExecution,
|
||||||
setFailedExecution,
|
setFailedExecution,
|
||||||
getPendingExecution,
|
getPendingExecution,
|
||||||
setPendingExecution,
|
setPendingExecution
|
||||||
setExecutionEventsFetched
|
|
||||||
)
|
)
|
||||||
|
|
||||||
unsubscribe()
|
unsubscribe()
|
||||||
@@ -141,7 +141,7 @@ describe('getFinalizationEvent', () => {
|
|||||||
})
|
})
|
||||||
test('should retry to get finalization event and try to get failed and pending transactions if home to foreign transaction', async () => {
|
test('should retry to get finalization event and try to get failed and pending transactions if home to foreign transaction', async () => {
|
||||||
const contract = ({
|
const contract = ({
|
||||||
getPastEvents: async () => {
|
getPastEvents: () => {
|
||||||
return []
|
return []
|
||||||
},
|
},
|
||||||
options: {
|
options: {
|
||||||
@@ -159,23 +159,22 @@ describe('getFinalizationEvent', () => {
|
|||||||
const setFailedExecution = jest.fn()
|
const setFailedExecution = jest.fn()
|
||||||
const getPendingExecution = jest.fn().mockResolvedValue([])
|
const getPendingExecution = jest.fn().mockResolvedValue([])
|
||||||
const setPendingExecution = jest.fn()
|
const setPendingExecution = jest.fn()
|
||||||
const setExecutionEventsFetched = jest.fn()
|
|
||||||
|
|
||||||
await getFinalizationEvent(
|
await getFinalizationEvent(
|
||||||
true,
|
|
||||||
contract,
|
contract,
|
||||||
|
eventName,
|
||||||
web3,
|
web3,
|
||||||
setResult,
|
setResult,
|
||||||
|
waitingBlocksResolved,
|
||||||
message,
|
message,
|
||||||
subscriptions.push.bind(subscriptions),
|
interval,
|
||||||
isCancelled,
|
subscriptions,
|
||||||
timestamp,
|
timestamp,
|
||||||
collectedSignaturesEvent,
|
collectedSignaturesEvent,
|
||||||
getFailedExecution,
|
getFailedExecution,
|
||||||
setFailedExecution,
|
setFailedExecution,
|
||||||
getPendingExecution,
|
getPendingExecution,
|
||||||
setPendingExecution,
|
setPendingExecution
|
||||||
setExecutionEventsFetched
|
|
||||||
)
|
)
|
||||||
|
|
||||||
unsubscribe()
|
unsubscribe()
|
||||||
@@ -191,7 +190,7 @@ describe('getFinalizationEvent', () => {
|
|||||||
})
|
})
|
||||||
test('should retry to get finalization event and not to try to get failed transaction if pending transactions found if home to foreign transaction', async () => {
|
test('should retry to get finalization event and not to try to get failed transaction if pending transactions found if home to foreign transaction', async () => {
|
||||||
const contract = ({
|
const contract = ({
|
||||||
getPastEvents: async () => {
|
getPastEvents: () => {
|
||||||
return []
|
return []
|
||||||
},
|
},
|
||||||
options: {
|
options: {
|
||||||
@@ -209,23 +208,22 @@ describe('getFinalizationEvent', () => {
|
|||||||
const setFailedExecution = jest.fn()
|
const setFailedExecution = jest.fn()
|
||||||
const getPendingExecution = jest.fn().mockResolvedValue([{ hash: txHash }])
|
const getPendingExecution = jest.fn().mockResolvedValue([{ hash: txHash }])
|
||||||
const setPendingExecution = jest.fn()
|
const setPendingExecution = jest.fn()
|
||||||
const setExecutionEventsFetched = jest.fn()
|
|
||||||
|
|
||||||
await getFinalizationEvent(
|
await getFinalizationEvent(
|
||||||
true,
|
|
||||||
contract,
|
contract,
|
||||||
|
eventName,
|
||||||
web3,
|
web3,
|
||||||
setResult,
|
setResult,
|
||||||
|
waitingBlocksResolved,
|
||||||
message,
|
message,
|
||||||
subscriptions.push.bind(subscriptions),
|
interval,
|
||||||
isCancelled,
|
subscriptions,
|
||||||
timestamp,
|
timestamp,
|
||||||
collectedSignaturesEvent,
|
collectedSignaturesEvent,
|
||||||
getFailedExecution,
|
getFailedExecution,
|
||||||
setFailedExecution,
|
setFailedExecution,
|
||||||
getPendingExecution,
|
getPendingExecution,
|
||||||
setPendingExecution,
|
setPendingExecution
|
||||||
setExecutionEventsFetched
|
|
||||||
)
|
)
|
||||||
|
|
||||||
unsubscribe()
|
unsubscribe()
|
||||||
@@ -248,7 +246,7 @@ describe('getFinalizationEvent', () => {
|
|||||||
})
|
})
|
||||||
test('should retry to get finalization event even if failed transaction found if home to foreign transaction', async () => {
|
test('should retry to get finalization event even if failed transaction found if home to foreign transaction', async () => {
|
||||||
const contract = ({
|
const contract = ({
|
||||||
getPastEvents: async () => {
|
getPastEvents: () => {
|
||||||
return []
|
return []
|
||||||
},
|
},
|
||||||
options: {
|
options: {
|
||||||
@@ -266,23 +264,22 @@ describe('getFinalizationEvent', () => {
|
|||||||
const setFailedExecution = jest.fn()
|
const setFailedExecution = jest.fn()
|
||||||
const getPendingExecution = jest.fn().mockResolvedValue([])
|
const getPendingExecution = jest.fn().mockResolvedValue([])
|
||||||
const setPendingExecution = jest.fn()
|
const setPendingExecution = jest.fn()
|
||||||
const setExecutionEventsFetched = jest.fn()
|
|
||||||
|
|
||||||
await getFinalizationEvent(
|
await getFinalizationEvent(
|
||||||
true,
|
|
||||||
contract,
|
contract,
|
||||||
|
eventName,
|
||||||
web3,
|
web3,
|
||||||
setResult,
|
setResult,
|
||||||
|
waitingBlocksResolved,
|
||||||
message,
|
message,
|
||||||
subscriptions.push.bind(subscriptions),
|
interval,
|
||||||
isCancelled,
|
subscriptions,
|
||||||
timestamp,
|
timestamp,
|
||||||
collectedSignaturesEvent,
|
collectedSignaturesEvent,
|
||||||
getFailedExecution,
|
getFailedExecution,
|
||||||
setFailedExecution,
|
setFailedExecution,
|
||||||
getPendingExecution,
|
getPendingExecution,
|
||||||
setPendingExecution,
|
setPendingExecution
|
||||||
setExecutionEventsFetched
|
|
||||||
)
|
)
|
||||||
|
|
||||||
unsubscribe()
|
unsubscribe()
|
||||||
|
|||||||
@@ -1,33 +1,18 @@
|
|||||||
import { Contract } from 'web3-eth-contract'
|
import { Contract } from 'web3-eth-contract'
|
||||||
import { EventData } from 'web3-eth-contract'
|
import { EventData } from 'web3-eth-contract'
|
||||||
import { SnapshotProvider } from '../services/SnapshotProvider'
|
import { SnapshotProvider } from '../services/SnapshotProvider'
|
||||||
import { getLogs } from './explorer'
|
|
||||||
import Web3 from 'web3'
|
|
||||||
|
|
||||||
const getPastEventsWithFallback = (
|
|
||||||
api: string,
|
|
||||||
web3: Web3 | null,
|
|
||||||
contract: Contract,
|
|
||||||
eventName: string,
|
|
||||||
options: any
|
|
||||||
) =>
|
|
||||||
contract
|
|
||||||
.getPastEvents(eventName, options)
|
|
||||||
.catch(() => (api && web3 ? getLogs(api, web3, contract, eventName, options) : []))
|
|
||||||
|
|
||||||
export const getRequiredBlockConfirmations = async (
|
export const getRequiredBlockConfirmations = async (
|
||||||
contract: Contract,
|
contract: Contract,
|
||||||
blockNumber: number,
|
blockNumber: number,
|
||||||
snapshotProvider: SnapshotProvider,
|
snapshotProvider: SnapshotProvider
|
||||||
web3: Web3 | null = null,
|
|
||||||
api: string = ''
|
|
||||||
) => {
|
) => {
|
||||||
const eventsFromSnapshot = snapshotProvider.requiredBlockConfirmationEvents(blockNumber)
|
const eventsFromSnapshot = snapshotProvider.requiredBlockConfirmationEvents(blockNumber)
|
||||||
const snapshotBlockNumber = snapshotProvider.snapshotBlockNumber()
|
const snapshotBlockNumber = snapshotProvider.snapshotBlockNumber()
|
||||||
|
|
||||||
let contractEvents: EventData[] = []
|
let contractEvents: EventData[] = []
|
||||||
if (blockNumber > snapshotBlockNumber) {
|
if (blockNumber > snapshotBlockNumber) {
|
||||||
contractEvents = await getPastEventsWithFallback(api, web3, contract, 'RequiredBlockConfirmationChanged', {
|
contractEvents = await contract.getPastEvents('RequiredBlockConfirmationChanged', {
|
||||||
fromBlock: snapshotBlockNumber + 1,
|
fromBlock: snapshotBlockNumber + 1,
|
||||||
toBlock: blockNumber
|
toBlock: blockNumber
|
||||||
})
|
})
|
||||||
@@ -53,16 +38,14 @@ export const getValidatorAddress = (contract: Contract) => contract.methods.vali
|
|||||||
export const getRequiredSignatures = async (
|
export const getRequiredSignatures = async (
|
||||||
contract: Contract,
|
contract: Contract,
|
||||||
blockNumber: number,
|
blockNumber: number,
|
||||||
snapshotProvider: SnapshotProvider,
|
snapshotProvider: SnapshotProvider
|
||||||
web3: Web3 | null = null,
|
|
||||||
api: string = ''
|
|
||||||
) => {
|
) => {
|
||||||
const eventsFromSnapshot = snapshotProvider.requiredSignaturesEvents(blockNumber)
|
const eventsFromSnapshot = snapshotProvider.requiredSignaturesEvents(blockNumber)
|
||||||
const snapshotBlockNumber = snapshotProvider.snapshotBlockNumber()
|
const snapshotBlockNumber = snapshotProvider.snapshotBlockNumber()
|
||||||
|
|
||||||
let contractEvents: EventData[] = []
|
let contractEvents: EventData[] = []
|
||||||
if (blockNumber > snapshotBlockNumber) {
|
if (blockNumber > snapshotBlockNumber) {
|
||||||
contractEvents = await getPastEventsWithFallback(api, web3, contract, 'RequiredSignaturesChanged', {
|
contractEvents = await contract.getPastEvents('RequiredSignaturesChanged', {
|
||||||
fromBlock: snapshotBlockNumber + 1,
|
fromBlock: snapshotBlockNumber + 1,
|
||||||
toBlock: blockNumber
|
toBlock: blockNumber
|
||||||
})
|
})
|
||||||
@@ -76,13 +59,7 @@ export const getRequiredSignatures = async (
|
|||||||
return parseInt(requiredSignatures)
|
return parseInt(requiredSignatures)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getValidatorList = async (
|
export const getValidatorList = async (contract: Contract, blockNumber: number, snapshotProvider: SnapshotProvider) => {
|
||||||
contract: Contract,
|
|
||||||
blockNumber: number,
|
|
||||||
snapshotProvider: SnapshotProvider,
|
|
||||||
web3: Web3 | null = null,
|
|
||||||
api: string = ''
|
|
||||||
) => {
|
|
||||||
const addedEventsFromSnapshot = snapshotProvider.validatorAddedEvents(blockNumber)
|
const addedEventsFromSnapshot = snapshotProvider.validatorAddedEvents(blockNumber)
|
||||||
const removedEventsFromSnapshot = snapshotProvider.validatorRemovedEvents(blockNumber)
|
const removedEventsFromSnapshot = snapshotProvider.validatorRemovedEvents(blockNumber)
|
||||||
const snapshotBlockNumber = snapshotProvider.snapshotBlockNumber()
|
const snapshotBlockNumber = snapshotProvider.snapshotBlockNumber()
|
||||||
@@ -90,10 +67,10 @@ export const getValidatorList = async (
|
|||||||
const fromBlock = snapshotBlockNumber > blockNumber ? snapshotBlockNumber + 1 : blockNumber
|
const fromBlock = snapshotBlockNumber > blockNumber ? snapshotBlockNumber + 1 : blockNumber
|
||||||
const [currentList, added, removed] = await Promise.all([
|
const [currentList, added, removed] = await Promise.all([
|
||||||
contract.methods.validatorList().call(),
|
contract.methods.validatorList().call(),
|
||||||
getPastEventsWithFallback(api, web3, contract, 'ValidatorAdded', {
|
contract.getPastEvents('ValidatorAdded', {
|
||||||
fromBlock
|
fromBlock
|
||||||
}),
|
}),
|
||||||
getPastEventsWithFallback(api, web3, contract, 'ValidatorRemoved', {
|
contract.getPastEvents('ValidatorRemoved', {
|
||||||
fromBlock
|
fromBlock
|
||||||
})
|
})
|
||||||
])
|
])
|
||||||
|
|||||||
58
alm/src/utils/executionWaitingForBlocks.ts
Normal file
58
alm/src/utils/executionWaitingForBlocks.ts
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import { BlockNumberProvider } from '../services/BlockNumberProvider'
|
||||||
|
import { VALIDATOR_CONFIRMATION_STATUS } from '../config/constants'
|
||||||
|
import { EventData } from 'web3-eth-contract'
|
||||||
|
|
||||||
|
export const checkWaitingBlocksForExecution = async (
|
||||||
|
blockProvider: BlockNumberProvider,
|
||||||
|
interval: number,
|
||||||
|
targetBlock: number,
|
||||||
|
collectedSignaturesEvent: EventData,
|
||||||
|
setWaitingBlocksForExecution: Function,
|
||||||
|
setWaitingBlocksForExecutionResolved: Function,
|
||||||
|
setExecutionData: Function,
|
||||||
|
subscriptions: number[]
|
||||||
|
) => {
|
||||||
|
const currentBlock = blockProvider.get()
|
||||||
|
|
||||||
|
if (currentBlock && currentBlock >= targetBlock) {
|
||||||
|
setExecutionData({
|
||||||
|
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
||||||
|
validator: collectedSignaturesEvent.returnValues.authorityResponsibleForRelay,
|
||||||
|
txHash: '',
|
||||||
|
timestamp: 0,
|
||||||
|
executionResult: false
|
||||||
|
})
|
||||||
|
setWaitingBlocksForExecutionResolved(true)
|
||||||
|
setWaitingBlocksForExecution(false)
|
||||||
|
blockProvider.stop()
|
||||||
|
} else {
|
||||||
|
let nextInterval = interval
|
||||||
|
if (!currentBlock) {
|
||||||
|
nextInterval = 500
|
||||||
|
} else {
|
||||||
|
setWaitingBlocksForExecution(true)
|
||||||
|
setExecutionData({
|
||||||
|
status: VALIDATOR_CONFIRMATION_STATUS.WAITING,
|
||||||
|
validator: collectedSignaturesEvent.returnValues.authorityResponsibleForRelay,
|
||||||
|
txHash: '',
|
||||||
|
timestamp: 0,
|
||||||
|
executionResult: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const timeoutId = setTimeout(
|
||||||
|
() =>
|
||||||
|
checkWaitingBlocksForExecution(
|
||||||
|
blockProvider,
|
||||||
|
interval,
|
||||||
|
targetBlock,
|
||||||
|
collectedSignaturesEvent,
|
||||||
|
setWaitingBlocksForExecution,
|
||||||
|
setWaitingBlocksForExecutionResolved,
|
||||||
|
setExecutionData,
|
||||||
|
subscriptions
|
||||||
|
),
|
||||||
|
nextInterval
|
||||||
|
)
|
||||||
|
subscriptions.push(timeoutId)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +1,10 @@
|
|||||||
import {
|
import {
|
||||||
BLOCK_RANGE,
|
|
||||||
EXECUTE_AFFIRMATION_HASH,
|
EXECUTE_AFFIRMATION_HASH,
|
||||||
EXECUTE_SIGNATURES_HASH,
|
EXECUTE_SIGNATURES_HASH,
|
||||||
FOREIGN_EXPLORER_API,
|
FOREIGN_EXPLORER_API,
|
||||||
HOME_EXPLORER_API,
|
HOME_EXPLORER_API,
|
||||||
MAX_TX_SEARCH_BLOCK_RANGE,
|
|
||||||
SUBMIT_SIGNATURE_HASH
|
SUBMIT_SIGNATURE_HASH
|
||||||
} from '../config/constants'
|
} from '../config/constants'
|
||||||
import { AbiItem } from 'web3-utils'
|
|
||||||
import Web3 from 'web3'
|
|
||||||
import { Contract } from 'web3-eth-contract'
|
|
||||||
|
|
||||||
export interface APITransaction {
|
export interface APITransaction {
|
||||||
timeStamp: string
|
timeStamp: string
|
||||||
@@ -17,7 +12,6 @@ export interface APITransaction {
|
|||||||
input: string
|
input: string
|
||||||
to: string
|
to: string
|
||||||
hash: string
|
hash: string
|
||||||
blockNumber: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface APIPendingTransaction {
|
export interface APIPendingTransaction {
|
||||||
@@ -33,54 +27,110 @@ export interface PendingTransactionsParams {
|
|||||||
|
|
||||||
export interface AccountTransactionsParams {
|
export interface AccountTransactionsParams {
|
||||||
account: string
|
account: string
|
||||||
startBlock: number
|
to: string
|
||||||
endBlock: number
|
startTimestamp: number
|
||||||
|
endTimestamp: number
|
||||||
api: string
|
api: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface GetFailedTransactionParams {
|
||||||
|
account: string
|
||||||
|
to: string
|
||||||
|
messageData: string
|
||||||
|
startTimestamp: number
|
||||||
|
endTimestamp: number
|
||||||
|
}
|
||||||
|
|
||||||
export interface GetPendingTransactionParams {
|
export interface GetPendingTransactionParams {
|
||||||
account: string
|
account: string
|
||||||
to: string
|
to: string
|
||||||
messageData: string
|
messageData: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GetTransactionParams extends GetPendingTransactionParams {
|
export const fetchAccountTransactionsFromBlockscout = async ({
|
||||||
startBlock: number
|
account,
|
||||||
endBlock: number
|
to,
|
||||||
}
|
startTimestamp,
|
||||||
|
endTimestamp,
|
||||||
|
api
|
||||||
|
}: AccountTransactionsParams): Promise<APITransaction[]> => {
|
||||||
|
const url = `${api}?module=account&action=txlist&address=${account}&filterby=from=${account}&to=${to}&starttimestamp=${startTimestamp}&endtimestamp=${endTimestamp}`
|
||||||
|
|
||||||
export const fetchAccountTransactions = async ({ account, startBlock, endBlock, api }: AccountTransactionsParams) => {
|
try {
|
||||||
const url = new URL(api)
|
const result = await fetch(url).then(res => res.json())
|
||||||
url.searchParams.append('module', 'account')
|
if (result.status === '0') {
|
||||||
url.searchParams.append('action', 'txlist')
|
|
||||||
url.searchParams.append('address', account)
|
|
||||||
url.searchParams.append('filterby', 'from')
|
|
||||||
url.searchParams.append('startblock', startBlock.toString())
|
|
||||||
url.searchParams.append('endblock', endBlock.toString())
|
|
||||||
|
|
||||||
const result = await fetch(url.toString()).then(res => res.json())
|
|
||||||
|
|
||||||
if (result.message === 'No transactions found') {
|
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.result
|
return result.result
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getBlockByTimestampUrl = (api: string, timestamp: number) =>
|
||||||
|
`${api}&module=block&action=getblocknobytime×tamp=${timestamp}&closest=before`
|
||||||
|
|
||||||
|
export const fetchAccountTransactionsFromEtherscan = async ({
|
||||||
|
account,
|
||||||
|
to,
|
||||||
|
startTimestamp,
|
||||||
|
endTimestamp,
|
||||||
|
api
|
||||||
|
}: AccountTransactionsParams): Promise<APITransaction[]> => {
|
||||||
|
const startBlockUrl = getBlockByTimestampUrl(api, startTimestamp)
|
||||||
|
const endBlockUrl = getBlockByTimestampUrl(api, endTimestamp)
|
||||||
|
let fromBlock = 0
|
||||||
|
let toBlock = 9999999999999
|
||||||
|
try {
|
||||||
|
const [fromBlockResult, toBlockResult] = await Promise.all([
|
||||||
|
fetch(startBlockUrl).then(res => res.json()),
|
||||||
|
fetch(endBlockUrl).then(res => res.json())
|
||||||
|
])
|
||||||
|
|
||||||
|
if (fromBlockResult.status !== '0') {
|
||||||
|
fromBlock = parseInt(fromBlockResult.result)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toBlockResult.status !== '0') {
|
||||||
|
toBlock = parseInt(toBlockResult.result)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = `${api}&module=account&action=txlist&address=${account}&startblock=${fromBlock}&endblock=${toBlock}`
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await fetch(url).then(res => res.json())
|
||||||
|
|
||||||
|
if (result.status === '0') {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
const toAddressLowerCase = to.toLowerCase()
|
||||||
|
const transactions: APITransaction[] = result.result
|
||||||
|
return transactions.filter(t => t.to.toLowerCase() === toAddressLowerCase)
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const fetchAccountTransactions = (api: string) => {
|
||||||
|
return api.includes('blockscout') ? fetchAccountTransactionsFromBlockscout : fetchAccountTransactionsFromEtherscan
|
||||||
}
|
}
|
||||||
|
|
||||||
export const fetchPendingTransactions = async ({
|
export const fetchPendingTransactions = async ({
|
||||||
account,
|
account,
|
||||||
api
|
api
|
||||||
}: PendingTransactionsParams): Promise<APIPendingTransaction[]> => {
|
}: PendingTransactionsParams): Promise<APIPendingTransaction[]> => {
|
||||||
if (!api.includes('blockscout')) {
|
const url = `${api}?module=account&action=pendingtxlist&address=${account}`
|
||||||
return []
|
|
||||||
}
|
|
||||||
const url = new URL(api)
|
|
||||||
url.searchParams.append('module', 'account')
|
|
||||||
url.searchParams.append('action', 'pendingtxlist')
|
|
||||||
url.searchParams.append('address', account)
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await fetch(url.toString()).then(res => res.json())
|
const result = await fetch(url).then(res => res.json())
|
||||||
if (result.status === '0') {
|
if (result.status === '0') {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
@@ -91,135 +141,30 @@ export const fetchPendingTransactions = async ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getClosestBlockByTimestamp = async (api: string, timestamp: number): Promise<number> => {
|
|
||||||
if (api.includes('blockscout')) {
|
|
||||||
throw new Error('Blockscout does not support getblocknobytime')
|
|
||||||
}
|
|
||||||
|
|
||||||
const url = new URL(api)
|
|
||||||
url.searchParams.append('module', 'block')
|
|
||||||
url.searchParams.append('action', 'getblocknobytime')
|
|
||||||
url.searchParams.append('timestamp', timestamp.toString())
|
|
||||||
url.searchParams.append('closest', 'before')
|
|
||||||
|
|
||||||
const blockNumber = await fetch(url.toString()).then(res => res.json())
|
|
||||||
|
|
||||||
return parseInt(blockNumber.result)
|
|
||||||
}
|
|
||||||
|
|
||||||
// fast version of fetchAccountTransactions
|
|
||||||
// sequentially fetches transactions in small batches
|
|
||||||
// caches the result
|
|
||||||
const transactionsCache: { [key: string]: { lastBlock: number; transactions: APITransaction[] } } = {}
|
|
||||||
export const getAccountTransactions = async ({
|
|
||||||
account,
|
|
||||||
startBlock,
|
|
||||||
endBlock,
|
|
||||||
api
|
|
||||||
}: AccountTransactionsParams): Promise<APITransaction[]> => {
|
|
||||||
const key = `${account}-${startBlock}-${api}`
|
|
||||||
|
|
||||||
// initialize empty cache if it doesn't exist yet
|
|
||||||
if (!transactionsCache[key]) {
|
|
||||||
transactionsCache[key] = { lastBlock: startBlock - 1, transactions: [] }
|
|
||||||
}
|
|
||||||
|
|
||||||
// if cache contains events up to block X,
|
|
||||||
// new batch is fetched for range [X + 1, X + 1 + BLOCK_RANGE]
|
|
||||||
const newStartBlock = transactionsCache[key].lastBlock + 1
|
|
||||||
const newEndBlock = newStartBlock + BLOCK_RANGE
|
|
||||||
|
|
||||||
// search for new transactions only if max allowed block range is not yet exceeded
|
|
||||||
if (newEndBlock <= startBlock + MAX_TX_SEARCH_BLOCK_RANGE) {
|
|
||||||
const newTransactions = await fetchAccountTransactions({
|
|
||||||
account,
|
|
||||||
startBlock: newStartBlock,
|
|
||||||
endBlock: newEndBlock,
|
|
||||||
api
|
|
||||||
})
|
|
||||||
|
|
||||||
const transactions = transactionsCache[key].transactions.concat(...newTransactions)
|
|
||||||
|
|
||||||
// cache updated transactions list
|
|
||||||
transactionsCache[key].transactions = transactions
|
|
||||||
|
|
||||||
// enbBlock is assumed to be the current block number of the chain
|
|
||||||
// if the whole range is finalized, last block can be safely updated to the end of the range
|
|
||||||
// this works even if there are no transactions in the list
|
|
||||||
if (newEndBlock < endBlock) {
|
|
||||||
transactionsCache[key].lastBlock = newEndBlock
|
|
||||||
} else if (transactions.length > 0) {
|
|
||||||
transactionsCache[key].lastBlock = parseInt(transactions[transactions.length - 1].blockNumber, 10)
|
|
||||||
}
|
|
||||||
|
|
||||||
return transactions
|
|
||||||
}
|
|
||||||
|
|
||||||
console.warn(`Reached max transaction searching range, returning previously cached transactions for ${account}`)
|
|
||||||
return transactionsCache[key].transactions
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getLogs = async (
|
|
||||||
api: string,
|
|
||||||
web3: Web3,
|
|
||||||
contract: Contract,
|
|
||||||
event: string,
|
|
||||||
options: { fromBlock: number; toBlock: number | 'latest'; topics: (string | null)[] }
|
|
||||||
) => {
|
|
||||||
const abi = contract.options.jsonInterface.find((abi: AbiItem) => abi.type === 'event' && abi.name === event)!
|
|
||||||
|
|
||||||
const url = new URL(api)
|
|
||||||
url.searchParams.append('module', 'logs')
|
|
||||||
url.searchParams.append('action', 'getLogs')
|
|
||||||
url.searchParams.append('address', contract.options.address)
|
|
||||||
url.searchParams.append('fromBlock', options.fromBlock.toString())
|
|
||||||
url.searchParams.append('toBlock', (options.toBlock || 'latest').toString())
|
|
||||||
|
|
||||||
const topics = [web3.eth.abi.encodeEventSignature(abi), ...(options.topics || [])]
|
|
||||||
for (let i = 0; i < topics.length; i++) {
|
|
||||||
if (topics[i] !== null) {
|
|
||||||
url.searchParams.append(`topic${i}`, topics[i] as string)
|
|
||||||
for (let j = 0; j < i; j++) {
|
|
||||||
url.searchParams.append(`topic${j}_${i}_opr`, 'and')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const logs = await fetch(url.toString()).then(res => res.json())
|
|
||||||
|
|
||||||
return logs.result.map((log: any) => ({
|
|
||||||
transactionHash: log.transactionHash,
|
|
||||||
blockNumber: parseInt(log.blockNumber.slice(2), 16),
|
|
||||||
returnValues: web3.eth.abi.decodeLog(abi.inputs!, log.data, log.topics.slice(1))
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
const filterReceiver = (to: string) => (tx: APITransaction) => tx.to.toLowerCase() === to.toLowerCase()
|
|
||||||
|
|
||||||
export const getFailedTransactions = async (
|
export const getFailedTransactions = async (
|
||||||
account: string,
|
account: string,
|
||||||
to: string,
|
to: string,
|
||||||
startBlock: number,
|
startTimestamp: number,
|
||||||
endBlock: number,
|
endTimestamp: number,
|
||||||
api: string,
|
api: string,
|
||||||
getAccountTransactionsMethod = getAccountTransactions
|
fetchAccountTransactions: (args: AccountTransactionsParams) => Promise<APITransaction[]>
|
||||||
): Promise<APITransaction[]> => {
|
): Promise<APITransaction[]> => {
|
||||||
const transactions = await getAccountTransactionsMethod({ account, startBlock, endBlock, api })
|
const transactions = await fetchAccountTransactions({ account, to, startTimestamp, endTimestamp, api })
|
||||||
|
|
||||||
return transactions.filter(t => t.isError !== '0').filter(filterReceiver(to))
|
return transactions.filter(t => t.isError !== '0')
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getSuccessTransactions = async (
|
export const getSuccessTransactions = async (
|
||||||
account: string,
|
account: string,
|
||||||
to: string,
|
to: string,
|
||||||
startBlock: number,
|
startTimestamp: number,
|
||||||
endBlock: number,
|
endTimestamp: number,
|
||||||
api: string,
|
api: string,
|
||||||
getAccountTransactionsMethod = getAccountTransactions
|
fetchAccountTransactions: (args: AccountTransactionsParams) => Promise<APITransaction[]>
|
||||||
): Promise<APITransaction[]> => {
|
): Promise<APITransaction[]> => {
|
||||||
const transactions = await getAccountTransactionsMethod({ account, startBlock, endBlock, api })
|
const transactions = await fetchAccountTransactions({ account, to, startTimestamp, endTimestamp, api })
|
||||||
|
|
||||||
return transactions.filter(t => t.isError === '0').filter(filterReceiver(to))
|
return transactions.filter(t => t.isError === '0')
|
||||||
}
|
}
|
||||||
|
|
||||||
export const filterValidatorSignatureTransaction = (
|
export const filterValidatorSignatureTransaction = (
|
||||||
@@ -238,10 +183,17 @@ export const getValidatorFailedTransactionsForMessage = async ({
|
|||||||
account,
|
account,
|
||||||
to,
|
to,
|
||||||
messageData,
|
messageData,
|
||||||
startBlock,
|
startTimestamp,
|
||||||
endBlock
|
endTimestamp
|
||||||
}: GetTransactionParams): Promise<APITransaction[]> => {
|
}: GetFailedTransactionParams): Promise<APITransaction[]> => {
|
||||||
const failedTransactions = await getFailedTransactions(account, to, startBlock, endBlock, HOME_EXPLORER_API)
|
const failedTransactions = await getFailedTransactions(
|
||||||
|
account,
|
||||||
|
to,
|
||||||
|
startTimestamp,
|
||||||
|
endTimestamp,
|
||||||
|
HOME_EXPLORER_API,
|
||||||
|
fetchAccountTransactionsFromBlockscout
|
||||||
|
)
|
||||||
|
|
||||||
return filterValidatorSignatureTransaction(failedTransactions, messageData)
|
return filterValidatorSignatureTransaction(failedTransactions, messageData)
|
||||||
}
|
}
|
||||||
@@ -250,19 +202,33 @@ export const getValidatorSuccessTransactionsForMessage = async ({
|
|||||||
account,
|
account,
|
||||||
to,
|
to,
|
||||||
messageData,
|
messageData,
|
||||||
startBlock,
|
startTimestamp,
|
||||||
endBlock
|
endTimestamp
|
||||||
}: GetTransactionParams): Promise<APITransaction[]> => {
|
}: GetFailedTransactionParams): Promise<APITransaction[]> => {
|
||||||
const transactions = await getSuccessTransactions(account, to, startBlock, endBlock, HOME_EXPLORER_API)
|
const transactions = await getSuccessTransactions(
|
||||||
|
account,
|
||||||
|
to,
|
||||||
|
startTimestamp,
|
||||||
|
endTimestamp,
|
||||||
|
HOME_EXPLORER_API,
|
||||||
|
fetchAccountTransactionsFromBlockscout
|
||||||
|
)
|
||||||
|
|
||||||
return filterValidatorSignatureTransaction(transactions, messageData)
|
return filterValidatorSignatureTransaction(transactions, messageData)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getExecutionFailedTransactionForMessage = async (
|
export const getExecutionFailedTransactionForMessage = async (
|
||||||
{ account, to, messageData, startBlock, endBlock }: GetTransactionParams,
|
{ account, to, messageData, startTimestamp, endTimestamp }: GetFailedTransactionParams,
|
||||||
getFailedTransactionsMethod = getFailedTransactions
|
getFailedTransactionsMethod = getFailedTransactions
|
||||||
): Promise<APITransaction[]> => {
|
): Promise<APITransaction[]> => {
|
||||||
const failedTransactions = await getFailedTransactionsMethod(account, to, startBlock, endBlock, FOREIGN_EXPLORER_API)
|
const failedTransactions = await getFailedTransactionsMethod(
|
||||||
|
account,
|
||||||
|
to,
|
||||||
|
startTimestamp,
|
||||||
|
endTimestamp,
|
||||||
|
FOREIGN_EXPLORER_API,
|
||||||
|
fetchAccountTransactions(FOREIGN_EXPLORER_API)
|
||||||
|
)
|
||||||
|
|
||||||
const messageDataValue = messageData.replace('0x', '')
|
const messageDataValue = messageData.replace('0x', '')
|
||||||
return failedTransactions.filter(t => t.input.includes(EXECUTE_SIGNATURES_HASH) && t.input.includes(messageDataValue))
|
return failedTransactions.filter(t => t.input.includes(EXECUTE_SIGNATURES_HASH) && t.input.includes(messageDataValue))
|
||||||
|
|||||||
53
alm/src/utils/getCollectedSignaturesEvent.ts
Normal file
53
alm/src/utils/getCollectedSignaturesEvent.ts
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import Web3 from 'web3'
|
||||||
|
import { Contract, EventData } from 'web3-eth-contract'
|
||||||
|
import { homeBlockNumberProvider } from '../services/BlockNumberProvider'
|
||||||
|
import { BLOCK_RANGE } from '../config/constants'
|
||||||
|
|
||||||
|
export const getCollectedSignaturesEvent = async (
|
||||||
|
web3: Maybe<Web3>,
|
||||||
|
contract: Maybe<Contract>,
|
||||||
|
fromBlock: number,
|
||||||
|
toBlock: number,
|
||||||
|
messageHash: string,
|
||||||
|
setCollectedSignaturesEvent: Function,
|
||||||
|
subscriptions: number[]
|
||||||
|
) => {
|
||||||
|
if (!web3 || !contract) return
|
||||||
|
const currentBlock = homeBlockNumberProvider.get()
|
||||||
|
|
||||||
|
let events: EventData[] = []
|
||||||
|
let securedToBlock = toBlock
|
||||||
|
if (currentBlock) {
|
||||||
|
// prevent errors if the toBlock parameter is bigger than the latest
|
||||||
|
securedToBlock = toBlock >= currentBlock ? currentBlock : toBlock
|
||||||
|
events = await contract.getPastEvents('CollectedSignatures', {
|
||||||
|
fromBlock,
|
||||||
|
toBlock: securedToBlock
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const filteredEvents = events.filter(e => e.returnValues.messageHash === messageHash)
|
||||||
|
|
||||||
|
if (filteredEvents.length) {
|
||||||
|
const event = filteredEvents[0]
|
||||||
|
setCollectedSignaturesEvent(event)
|
||||||
|
homeBlockNumberProvider.stop()
|
||||||
|
} else {
|
||||||
|
const newFromBlock = currentBlock ? securedToBlock : fromBlock
|
||||||
|
const newToBlock = currentBlock ? toBlock + BLOCK_RANGE : toBlock
|
||||||
|
const timeoutId = setTimeout(
|
||||||
|
() =>
|
||||||
|
getCollectedSignaturesEvent(
|
||||||
|
web3,
|
||||||
|
contract,
|
||||||
|
newFromBlock,
|
||||||
|
newToBlock,
|
||||||
|
messageHash,
|
||||||
|
setCollectedSignaturesEvent,
|
||||||
|
subscriptions
|
||||||
|
),
|
||||||
|
500
|
||||||
|
)
|
||||||
|
subscriptions.push(timeoutId)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,91 +1,82 @@
|
|||||||
import Web3 from 'web3'
|
import Web3 from 'web3'
|
||||||
import { Contract } from 'web3-eth-contract'
|
import { Contract } from 'web3-eth-contract'
|
||||||
import { HOME_RPC_POLLING_INTERVAL, VALIDATOR_CONFIRMATION_STATUS } from '../config/constants'
|
import { HOME_RPC_POLLING_INTERVAL, VALIDATOR_CONFIRMATION_STATUS } from '../config/constants'
|
||||||
import { GetTransactionParams, APITransaction, APIPendingTransaction, GetPendingTransactionParams } from './explorer'
|
import {
|
||||||
import { getAffirmationsSigned, getMessagesSigned } from './contract'
|
GetFailedTransactionParams,
|
||||||
|
APITransaction,
|
||||||
|
APIPendingTransaction,
|
||||||
|
GetPendingTransactionParams
|
||||||
|
} from './explorer'
|
||||||
import {
|
import {
|
||||||
getValidatorConfirmation,
|
getValidatorConfirmation,
|
||||||
getValidatorFailedTransaction,
|
getValidatorFailedTransaction,
|
||||||
getValidatorPendingTransaction,
|
getValidatorPendingTransaction,
|
||||||
getSuccessExecutionTransaction
|
getValidatorSuccessTransaction
|
||||||
} from './validatorConfirmationHelpers'
|
} from './validatorConfirmationHelpers'
|
||||||
import { BasicConfirmationParam, ConfirmationParam } from '../hooks/useMessageConfirmations'
|
import { 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 (
|
export const getConfirmationsForTx = async (
|
||||||
messageData: string,
|
messageData: string,
|
||||||
web3: Web3,
|
web3: Maybe<Web3>,
|
||||||
validatorList: string[],
|
validatorList: string[],
|
||||||
bridgeContract: Contract,
|
bridgeContract: Maybe<Contract>,
|
||||||
fromHome: boolean,
|
confirmationContractMethod: Function,
|
||||||
setResult: Function,
|
setResult: Function,
|
||||||
requiredSignatures: number,
|
requiredSignatures: number,
|
||||||
setSignatureCollected: Function,
|
setSignatureCollected: Function,
|
||||||
setTimeoutId: (timeoutId: number) => void,
|
waitingBlocksResolved: boolean,
|
||||||
isCancelled: () => boolean,
|
subscriptions: number[],
|
||||||
startBlock: number,
|
timestamp: number,
|
||||||
getFailedTransactions: (args: GetTransactionParams) => Promise<APITransaction[]>,
|
getFailedTransactions: (args: GetFailedTransactionParams) => Promise<APITransaction[]>,
|
||||||
setFailedConfirmations: Function,
|
setFailedConfirmations: Function,
|
||||||
getPendingTransactions: (args: GetPendingTransactionParams) => Promise<APIPendingTransaction[]>,
|
getPendingTransactions: (args: GetPendingTransactionParams) => Promise<APIPendingTransaction[]>,
|
||||||
setPendingConfirmations: Function,
|
setPendingConfirmations: Function,
|
||||||
getSuccessTransactions: (args: GetTransactionParams) => Promise<APITransaction[]>
|
getSuccessTransactions: (args: GetFailedTransactionParams) => Promise<APITransaction[]>
|
||||||
) => {
|
) => {
|
||||||
const confirmationContractMethod = fromHome ? getMessagesSigned : getAffirmationsSigned
|
if (!web3 || !validatorList || !validatorList.length || !bridgeContract || !waitingBlocksResolved) return
|
||||||
|
|
||||||
|
// If all the information was not collected, then it should retry
|
||||||
|
let shouldRetry = false
|
||||||
const hashMsg = web3.utils.soliditySha3Raw(messageData)
|
const hashMsg = web3.utils.soliditySha3Raw(messageData)
|
||||||
let validatorConfirmations = await Promise.all(
|
let validatorConfirmations = await Promise.all(
|
||||||
validatorList.map(getValidatorConfirmation(web3, hashMsg, bridgeContract, confirmationContractMethod))
|
validatorList.map(getValidatorConfirmation(web3, hashMsg, bridgeContract, confirmationContractMethod))
|
||||||
)
|
)
|
||||||
|
|
||||||
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 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)
|
setResult((prevConfirmations: ConfirmationParam[]) => {
|
||||||
setSignatureCollected(hasEnoughSignatures)
|
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 notSuccessConfirmations = validatorConfirmations.filter(c => c.status !== VALIDATOR_CONFIRMATION_STATUS.SUCCESS)
|
||||||
|
|
||||||
// If signatures not collected, look for pending transactions
|
// If signatures not collected, look for pending transactions
|
||||||
if (!hasEnoughSignatures) {
|
let pendingConfirmationsResult = false
|
||||||
|
if (successConfirmations.length !== requiredSignatures) {
|
||||||
// Check if confirmation is pending
|
// Check if confirmation is pending
|
||||||
const validatorPendingConfirmationsChecks = await Promise.all(
|
const validatorPendingConfirmationsChecks = await Promise.all(
|
||||||
notSuccessConfirmations.map(getValidatorPendingTransaction(bridgeContract, messageData, getPendingTransactions))
|
notSuccessConfirmations.map(getValidatorPendingTransaction(bridgeContract, messageData, getPendingTransactions))
|
||||||
)
|
)
|
||||||
|
|
||||||
const validatorPendingConfirmations = validatorPendingConfirmationsChecks.filter(
|
const validatorPendingConfirmations = validatorPendingConfirmationsChecks.filter(
|
||||||
c => c.status === VALIDATOR_CONFIRMATION_STATUS.PENDING
|
c => c.status === VALIDATOR_CONFIRMATION_STATUS.PENDING
|
||||||
)
|
)
|
||||||
updateConfirmations(validatorPendingConfirmations)
|
|
||||||
setPendingConfirmations(validatorPendingConfirmations.length > 0)
|
validatorPendingConfirmations.forEach(validatorData => {
|
||||||
} else {
|
const index = validatorConfirmations.findIndex(e => e.validator === validatorData.validator)
|
||||||
setPendingConfirmations(false)
|
validatorConfirmations[index] = validatorData
|
||||||
|
})
|
||||||
|
|
||||||
|
if (validatorPendingConfirmations.length > 0) {
|
||||||
|
pendingConfirmationsResult = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const undefinedConfirmations = validatorConfirmations.filter(
|
const undefinedConfirmations = validatorConfirmations.filter(
|
||||||
@@ -93,56 +84,77 @@ export const getConfirmationsForTx = async (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Check if confirmation failed
|
// Check if confirmation failed
|
||||||
|
let failedConfirmationsResult = false
|
||||||
const validatorFailedConfirmationsChecks = await Promise.all(
|
const validatorFailedConfirmationsChecks = await Promise.all(
|
||||||
undefinedConfirmations.map(
|
undefinedConfirmations.map(
|
||||||
getValidatorFailedTransaction(bridgeContract, messageData, startBlock, getFailedTransactions)
|
getValidatorFailedTransaction(bridgeContract, messageData, timestamp, getFailedTransactions)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
const validatorFailedConfirmations = validatorFailedConfirmationsChecks.filter(
|
const validatorFailedConfirmations = validatorFailedConfirmationsChecks.filter(
|
||||||
c => c.status === VALIDATOR_CONFIRMATION_STATUS.FAILED
|
c => c.status === VALIDATOR_CONFIRMATION_STATUS.FAILED
|
||||||
)
|
)
|
||||||
setFailedConfirmations(validatorFailedConfirmations.length > validatorList.length - requiredSignatures)
|
validatorFailedConfirmations.forEach(validatorData => {
|
||||||
updateConfirmations(validatorFailedConfirmations)
|
const index = validatorConfirmations.findIndex(e => e.validator === validatorData.validator)
|
||||||
|
validatorConfirmations[index] = validatorData
|
||||||
|
})
|
||||||
|
const messageConfirmationsFailed = validatorFailedConfirmations.length > validatorList.length - requiredSignatures
|
||||||
|
if (messageConfirmationsFailed) {
|
||||||
|
failedConfirmationsResult = true
|
||||||
|
}
|
||||||
|
|
||||||
const missingConfirmations = validatorConfirmations.filter(
|
const missingConfirmations = validatorConfirmations.filter(
|
||||||
c => c.status === VALIDATOR_CONFIRMATION_STATUS.UNDEFINED || c.status === VALIDATOR_CONFIRMATION_STATUS.PENDING
|
c => c.status === VALIDATOR_CONFIRMATION_STATUS.UNDEFINED || c.status === VALIDATOR_CONFIRMATION_STATUS.PENDING
|
||||||
)
|
)
|
||||||
|
|
||||||
if (hasEnoughSignatures) {
|
if (successConfirmations.length !== requiredSignatures && missingConfirmations.length > 0) {
|
||||||
|
shouldRetry = true
|
||||||
|
}
|
||||||
|
|
||||||
|
let signatureCollectedResult = false
|
||||||
|
if (successConfirmations.length === requiredSignatures) {
|
||||||
// If signatures collected, it should set other signatures not found as not required
|
// If signatures collected, it should set other signatures not found as not required
|
||||||
const notRequiredConfirmations = missingConfirmations.map(c => ({
|
const notRequiredConfirmations = missingConfirmations.map(c => ({
|
||||||
validator: c.validator,
|
validator: c.validator,
|
||||||
status: VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED
|
status: VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED
|
||||||
}))
|
}))
|
||||||
updateConfirmations(notRequiredConfirmations)
|
|
||||||
|
|
||||||
if (fromHome) {
|
notRequiredConfirmations.forEach(validatorData => {
|
||||||
// fetch collected signatures for possible manual processing
|
const index = validatorConfirmations.findIndex(e => e.validator === validatorData.validator)
|
||||||
setSignatureCollected(
|
validatorConfirmations[index] = validatorData
|
||||||
await Promise.all(
|
})
|
||||||
Array.from(Array(requiredSignatures).keys()).map(i => bridgeContract.methods.signature(hashMsg, i).call())
|
signatureCollectedResult = true
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// get transactions from success signatures
|
// get transactions from success signatures
|
||||||
const successConfirmationWithData = await Promise.all(
|
const successConfirmationWithData = await Promise.all(
|
||||||
successConfirmations.map(
|
validatorConfirmations
|
||||||
getSuccessExecutionTransaction(web3, bridgeContract, fromHome, messageData, startBlock, getSuccessTransactions)
|
.filter(c => c.status === VALIDATOR_CONFIRMATION_STATUS.SUCCESS)
|
||||||
)
|
.map(getValidatorSuccessTransaction(bridgeContract, messageData, timestamp, getSuccessTransactions))
|
||||||
)
|
)
|
||||||
|
|
||||||
const successConfirmationWithTxFound = successConfirmationWithData.filter(v => v.txHash !== '')
|
const successConfirmationWithTxFound = successConfirmationWithData.filter(v => v.txHash !== '')
|
||||||
updateConfirmations(successConfirmationWithTxFound)
|
|
||||||
|
|
||||||
// retry if not all signatures are collected and some confirmations are still missing
|
const updatedValidatorConfirmations = [...validatorConfirmations]
|
||||||
// or some success transactions were not fetched successfully
|
|
||||||
if (
|
if (successConfirmationWithTxFound.length > 0) {
|
||||||
(!hasEnoughSignatures && missingConfirmations.length > 0) ||
|
successConfirmationWithTxFound.forEach(validatorData => {
|
||||||
successConfirmationWithTxFound.length < successConfirmationWithData.length
|
const index = updatedValidatorConfirmations.findIndex(e => e.validator === validatorData.validator)
|
||||||
) {
|
updatedValidatorConfirmations[index] = validatorData
|
||||||
if (!isCancelled()) {
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
const timeoutId = setTimeout(
|
const timeoutId = setTimeout(
|
||||||
() =>
|
() =>
|
||||||
getConfirmationsForTx(
|
getConfirmationsForTx(
|
||||||
@@ -150,13 +162,13 @@ export const getConfirmationsForTx = async (
|
|||||||
web3,
|
web3,
|
||||||
validatorList,
|
validatorList,
|
||||||
bridgeContract,
|
bridgeContract,
|
||||||
fromHome,
|
confirmationContractMethod,
|
||||||
setResult,
|
setResult,
|
||||||
requiredSignatures,
|
requiredSignatures,
|
||||||
setSignatureCollected,
|
setSignatureCollected,
|
||||||
setTimeoutId,
|
waitingBlocksResolved,
|
||||||
isCancelled,
|
subscriptions,
|
||||||
startBlock,
|
timestamp,
|
||||||
getFailedTransactions,
|
getFailedTransactions,
|
||||||
setFailedConfirmations,
|
setFailedConfirmations,
|
||||||
getPendingTransactions,
|
getPendingTransactions,
|
||||||
@@ -165,7 +177,6 @@ export const getConfirmationsForTx = async (
|
|||||||
),
|
),
|
||||||
HOME_RPC_POLLING_INTERVAL
|
HOME_RPC_POLLING_INTERVAL
|
||||||
)
|
)
|
||||||
setTimeoutId(timeoutId)
|
subscriptions.push(timeoutId)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,51 +1,40 @@
|
|||||||
import { Contract, EventData } from 'web3-eth-contract'
|
import { Contract, EventData } from 'web3-eth-contract'
|
||||||
import Web3 from 'web3'
|
import Web3 from 'web3'
|
||||||
import {
|
import { CACHE_KEY_EXECUTION_FAILED, THREE_DAYS_TIMESTAMP, VALIDATOR_CONFIRMATION_STATUS } from '../config/constants'
|
||||||
CACHE_KEY_EXECUTION_FAILED,
|
|
||||||
FOREIGN_EXPLORER_API,
|
|
||||||
FOREIGN_RPC_POLLING_INTERVAL,
|
|
||||||
HOME_EXPLORER_API,
|
|
||||||
HOME_RPC_POLLING_INTERVAL,
|
|
||||||
VALIDATOR_CONFIRMATION_STATUS
|
|
||||||
} from '../config/constants'
|
|
||||||
import { ExecutionData } from '../hooks/useMessageConfirmations'
|
import { ExecutionData } from '../hooks/useMessageConfirmations'
|
||||||
import {
|
import {
|
||||||
APIPendingTransaction,
|
APIPendingTransaction,
|
||||||
APITransaction,
|
APITransaction,
|
||||||
GetTransactionParams,
|
GetFailedTransactionParams,
|
||||||
GetPendingTransactionParams,
|
GetPendingTransactionParams
|
||||||
getLogs
|
|
||||||
} from './explorer'
|
} from './explorer'
|
||||||
import { getBlock, MessageObject } from './web3'
|
import { getBlock, MessageObject } from './web3'
|
||||||
import validatorsCache from '../services/ValidatorsCache'
|
import validatorsCache from '../services/ValidatorsCache'
|
||||||
import { foreignBlockNumberProvider, homeBlockNumberProvider } from '../services/BlockNumberProvider'
|
|
||||||
|
|
||||||
const getPastEventsWithFallback = (api: string, web3: Web3, contract: Contract, eventName: string, options: any) =>
|
export const getFinalizationEvent = async (
|
||||||
contract.getPastEvents(eventName, options).catch(
|
contract: Maybe<Contract>,
|
||||||
() =>
|
|
||||||
api
|
|
||||||
? getLogs(api, web3, contract, eventName, {
|
|
||||||
fromBlock: options.fromBlock,
|
|
||||||
toBlock: options.toBlock,
|
|
||||||
topics: [null, null, options.filter.messageId]
|
|
||||||
})
|
|
||||||
: []
|
|
||||||
)
|
|
||||||
|
|
||||||
export const getSuccessExecutionData = async (
|
|
||||||
contract: Contract,
|
|
||||||
eventName: string,
|
eventName: string,
|
||||||
web3: Web3,
|
web3: Maybe<Web3>,
|
||||||
messageId: string,
|
setResult: React.Dispatch<React.SetStateAction<ExecutionData>>,
|
||||||
api: string = ''
|
waitingBlocksResolved: boolean,
|
||||||
|
message: MessageObject,
|
||||||
|
interval: number,
|
||||||
|
subscriptions: number[],
|
||||||
|
timestamp: number,
|
||||||
|
collectedSignaturesEvent: Maybe<EventData>,
|
||||||
|
getFailedExecution: (args: GetFailedTransactionParams) => Promise<APITransaction[]>,
|
||||||
|
setFailedExecution: Function,
|
||||||
|
getPendingExecution: (args: GetPendingTransactionParams) => Promise<APIPendingTransaction[]>,
|
||||||
|
setPendingExecution: Function
|
||||||
) => {
|
) => {
|
||||||
|
if (!contract || !web3 || !waitingBlocksResolved) return
|
||||||
// Since it filters by the message id, only one event will be fetched
|
// Since it filters by the message id, only one event will be fetched
|
||||||
// so there is no need to limit the range of the block to reduce the network traffic
|
// so there is no need to limit the range of the block to reduce the network traffic
|
||||||
const events: EventData[] = await getPastEventsWithFallback(api, web3, contract, eventName, {
|
const events: EventData[] = await contract.getPastEvents(eventName, {
|
||||||
fromBlock: 0,
|
fromBlock: 0,
|
||||||
toBlock: 'latest',
|
toBlock: 'latest',
|
||||||
filter: {
|
filter: {
|
||||||
messageId
|
messageId: message.id
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if (events.length > 0) {
|
if (events.length > 0) {
|
||||||
@@ -58,42 +47,14 @@ export const getSuccessExecutionData = async (
|
|||||||
const blockTimestamp = typeof block.timestamp === 'string' ? parseInt(block.timestamp) : block.timestamp
|
const blockTimestamp = typeof block.timestamp === 'string' ? parseInt(block.timestamp) : block.timestamp
|
||||||
const validatorAddress = web3.utils.toChecksumAddress(txReceipt.from)
|
const validatorAddress = web3.utils.toChecksumAddress(txReceipt.from)
|
||||||
|
|
||||||
return {
|
setResult({
|
||||||
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
||||||
validator: validatorAddress,
|
validator: validatorAddress,
|
||||||
txHash: event.transactionHash,
|
txHash: event.transactionHash,
|
||||||
timestamp: blockTimestamp,
|
timestamp: blockTimestamp,
|
||||||
executionResult: event.returnValues.status
|
executionResult: event.returnValues.status
|
||||||
}
|
})
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getFinalizationEvent = async (
|
|
||||||
fromHome: boolean,
|
|
||||||
contract: Contract,
|
|
||||||
web3: Web3,
|
|
||||||
setResult: React.Dispatch<React.SetStateAction<ExecutionData>>,
|
|
||||||
message: MessageObject,
|
|
||||||
setTimeoutId: (timeoutId: number) => void,
|
|
||||||
isCancelled: () => boolean,
|
|
||||||
startBlock: number,
|
|
||||||
collectedSignaturesEvent: Maybe<EventData>,
|
|
||||||
getFailedExecution: (args: GetTransactionParams) => Promise<APITransaction[]>,
|
|
||||||
setFailedExecution: Function,
|
|
||||||
getPendingExecution: (args: GetPendingTransactionParams) => Promise<APIPendingTransaction[]>,
|
|
||||||
setPendingExecution: Function,
|
|
||||||
setExecutionEventsFetched: Function
|
|
||||||
) => {
|
|
||||||
const eventName = fromHome ? 'RelayedMessage' : 'AffirmationCompleted'
|
|
||||||
const api = fromHome ? FOREIGN_EXPLORER_API : HOME_EXPLORER_API
|
|
||||||
|
|
||||||
const successExecutionData = await getSuccessExecutionData(contract, eventName, web3, message.id, api)
|
|
||||||
|
|
||||||
if (successExecutionData) {
|
|
||||||
setResult(successExecutionData)
|
|
||||||
} else {
|
} else {
|
||||||
setExecutionEventsFetched(true)
|
|
||||||
// If event is defined, it means it is a message from Home to Foreign
|
// If event is defined, it means it is a message from Home to Foreign
|
||||||
if (collectedSignaturesEvent) {
|
if (collectedSignaturesEvent) {
|
||||||
const validator = collectedSignaturesEvent.returnValues.authorityResponsibleForRelay
|
const validator = collectedSignaturesEvent.returnValues.authorityResponsibleForRelay
|
||||||
@@ -121,15 +82,14 @@ export const getFinalizationEvent = async (
|
|||||||
} else {
|
} else {
|
||||||
const validatorExecutionCacheKey = `${CACHE_KEY_EXECUTION_FAILED}${validator}-${message.id}`
|
const validatorExecutionCacheKey = `${CACHE_KEY_EXECUTION_FAILED}${validator}-${message.id}`
|
||||||
const failedFromCache = validatorsCache.get(validatorExecutionCacheKey)
|
const failedFromCache = validatorsCache.get(validatorExecutionCacheKey)
|
||||||
const blockProvider = fromHome ? foreignBlockNumberProvider : homeBlockNumberProvider
|
|
||||||
|
|
||||||
if (!failedFromCache) {
|
if (!failedFromCache) {
|
||||||
const failedTransactions = await getFailedExecution({
|
const failedTransactions = await getFailedExecution({
|
||||||
account: validator,
|
account: validator,
|
||||||
to: contract.options.address,
|
to: contract.options.address,
|
||||||
messageData: message.data,
|
messageData: message.data,
|
||||||
startBlock,
|
startTimestamp: timestamp,
|
||||||
endBlock: blockProvider.get() || 0
|
endTimestamp: timestamp + THREE_DAYS_TIMESTAMP
|
||||||
})
|
})
|
||||||
|
|
||||||
if (failedTransactions.length > 0) {
|
if (failedTransactions.length > 0) {
|
||||||
@@ -152,28 +112,26 @@ export const getFinalizationEvent = async (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isCancelled()) {
|
|
||||||
const timeoutId = setTimeout(
|
const timeoutId = setTimeout(
|
||||||
() =>
|
() =>
|
||||||
getFinalizationEvent(
|
getFinalizationEvent(
|
||||||
fromHome,
|
|
||||||
contract,
|
contract,
|
||||||
|
eventName,
|
||||||
web3,
|
web3,
|
||||||
setResult,
|
setResult,
|
||||||
|
waitingBlocksResolved,
|
||||||
message,
|
message,
|
||||||
setTimeoutId,
|
interval,
|
||||||
isCancelled,
|
subscriptions,
|
||||||
startBlock,
|
timestamp,
|
||||||
collectedSignaturesEvent,
|
collectedSignaturesEvent,
|
||||||
getFailedExecution,
|
getFailedExecution,
|
||||||
setFailedExecution,
|
setFailedExecution,
|
||||||
getPendingExecution,
|
getPendingExecution,
|
||||||
setPendingExecution,
|
setPendingExecution
|
||||||
setExecutionEventsFetched
|
|
||||||
),
|
),
|
||||||
fromHome ? FOREIGN_RPC_POLLING_INTERVAL : HOME_RPC_POLLING_INTERVAL
|
interval
|
||||||
)
|
)
|
||||||
setTimeoutId(timeoutId)
|
subscriptions.push(timeoutId)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
50
alm/src/utils/signatureWaitingForBlocks.ts
Normal file
50
alm/src/utils/signatureWaitingForBlocks.ts
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import { VALIDATOR_CONFIRMATION_STATUS } from '../config/constants'
|
||||||
|
import { BlockNumberProvider } from '../services/BlockNumberProvider'
|
||||||
|
|
||||||
|
export const checkSignaturesWaitingForBLocks = async (
|
||||||
|
targetBlock: number,
|
||||||
|
setWaitingStatus: Function,
|
||||||
|
setWaitingBlocksResolved: Function,
|
||||||
|
validatorList: string[],
|
||||||
|
setConfirmations: Function,
|
||||||
|
blockProvider: BlockNumberProvider,
|
||||||
|
interval: number,
|
||||||
|
subscriptions: number[]
|
||||||
|
) => {
|
||||||
|
const currentBlock = blockProvider.get()
|
||||||
|
|
||||||
|
if (currentBlock && currentBlock >= targetBlock) {
|
||||||
|
setWaitingBlocksResolved(true)
|
||||||
|
setWaitingStatus(false)
|
||||||
|
blockProvider.stop()
|
||||||
|
} else {
|
||||||
|
let nextInterval = interval
|
||||||
|
if (!currentBlock) {
|
||||||
|
nextInterval = 500
|
||||||
|
} else {
|
||||||
|
const validatorsWaiting = validatorList.map(validator => {
|
||||||
|
return {
|
||||||
|
validator,
|
||||||
|
status: VALIDATOR_CONFIRMATION_STATUS.WAITING
|
||||||
|
}
|
||||||
|
})
|
||||||
|
setWaitingStatus(true)
|
||||||
|
setConfirmations(validatorsWaiting)
|
||||||
|
}
|
||||||
|
const timeoutId = setTimeout(
|
||||||
|
() =>
|
||||||
|
checkSignaturesWaitingForBLocks(
|
||||||
|
targetBlock,
|
||||||
|
setWaitingStatus,
|
||||||
|
setWaitingBlocksResolved,
|
||||||
|
validatorList,
|
||||||
|
setConfirmations,
|
||||||
|
blockProvider,
|
||||||
|
interval,
|
||||||
|
subscriptions
|
||||||
|
),
|
||||||
|
nextInterval
|
||||||
|
)
|
||||||
|
subscriptions.push(timeoutId)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
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}`
|
|
||||||
}
|
|
||||||
@@ -2,9 +2,18 @@ import Web3 from 'web3'
|
|||||||
import { Contract } from 'web3-eth-contract'
|
import { Contract } from 'web3-eth-contract'
|
||||||
import { BasicConfirmationParam, ConfirmationParam } from '../hooks/useMessageConfirmations'
|
import { BasicConfirmationParam, ConfirmationParam } from '../hooks/useMessageConfirmations'
|
||||||
import validatorsCache from '../services/ValidatorsCache'
|
import validatorsCache from '../services/ValidatorsCache'
|
||||||
import { CACHE_KEY_FAILED, CACHE_KEY_SUCCESS, VALIDATOR_CONFIRMATION_STATUS } from '../config/constants'
|
import {
|
||||||
import { APIPendingTransaction, APITransaction, GetTransactionParams, GetPendingTransactionParams } from './explorer'
|
CACHE_KEY_FAILED,
|
||||||
import { homeBlockNumberProvider } from '../services/BlockNumberProvider'
|
CACHE_KEY_SUCCESS,
|
||||||
|
ONE_DAY_TIMESTAMP,
|
||||||
|
VALIDATOR_CONFIRMATION_STATUS
|
||||||
|
} from '../config/constants'
|
||||||
|
import {
|
||||||
|
APIPendingTransaction,
|
||||||
|
APITransaction,
|
||||||
|
GetFailedTransactionParams,
|
||||||
|
GetPendingTransactionParams
|
||||||
|
} from './explorer'
|
||||||
|
|
||||||
export const getValidatorConfirmation = (
|
export const getValidatorConfirmation = (
|
||||||
web3: Web3,
|
web3: Web3,
|
||||||
@@ -36,13 +45,11 @@ export const getValidatorConfirmation = (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getSuccessExecutionTransaction = (
|
export const getValidatorSuccessTransaction = (
|
||||||
web3: Web3,
|
|
||||||
bridgeContract: Contract,
|
bridgeContract: Contract,
|
||||||
fromHome: boolean,
|
|
||||||
messageData: string,
|
messageData: string,
|
||||||
startBlock: number,
|
timestamp: number,
|
||||||
getSuccessTransactions: (args: GetTransactionParams) => Promise<APITransaction[]>
|
getSuccessTransactions: (args: GetFailedTransactionParams) => Promise<APITransaction[]>
|
||||||
) => async (validatorData: BasicConfirmationParam): Promise<ConfirmationParam> => {
|
) => async (validatorData: BasicConfirmationParam): Promise<ConfirmationParam> => {
|
||||||
const { validator } = validatorData
|
const { validator } = validatorData
|
||||||
const validatorCacheKey = `${CACHE_KEY_SUCCESS}${validatorData.validator}-${messageData}`
|
const validatorCacheKey = `${CACHE_KEY_SUCCESS}${validatorData.validator}-${messageData}`
|
||||||
@@ -56,8 +63,8 @@ export const getSuccessExecutionTransaction = (
|
|||||||
account: validatorData.validator,
|
account: validatorData.validator,
|
||||||
to: bridgeContract.options.address,
|
to: bridgeContract.options.address,
|
||||||
messageData,
|
messageData,
|
||||||
startBlock,
|
startTimestamp: timestamp,
|
||||||
endBlock: homeBlockNumberProvider.get() || 0
|
endTimestamp: timestamp + ONE_DAY_TIMESTAMP
|
||||||
})
|
})
|
||||||
|
|
||||||
let txHashTimestamp = 0
|
let txHashTimestamp = 0
|
||||||
@@ -89,8 +96,8 @@ export const getSuccessExecutionTransaction = (
|
|||||||
export const getValidatorFailedTransaction = (
|
export const getValidatorFailedTransaction = (
|
||||||
bridgeContract: Contract,
|
bridgeContract: Contract,
|
||||||
messageData: string,
|
messageData: string,
|
||||||
startBlock: number,
|
timestamp: number,
|
||||||
getFailedTransactions: (args: GetTransactionParams) => Promise<APITransaction[]>
|
getFailedTransactions: (args: GetFailedTransactionParams) => Promise<APITransaction[]>
|
||||||
) => async (validatorData: BasicConfirmationParam): Promise<ConfirmationParam> => {
|
) => async (validatorData: BasicConfirmationParam): Promise<ConfirmationParam> => {
|
||||||
const validatorCacheKey = `${CACHE_KEY_FAILED}${validatorData.validator}-${messageData}`
|
const validatorCacheKey = `${CACHE_KEY_FAILED}${validatorData.validator}-${messageData}`
|
||||||
const failedFromCache = validatorsCache.getData(validatorCacheKey)
|
const failedFromCache = validatorsCache.getData(validatorCacheKey)
|
||||||
@@ -103,8 +110,8 @@ export const getValidatorFailedTransaction = (
|
|||||||
account: validatorData.validator,
|
account: validatorData.validator,
|
||||||
to: bridgeContract.options.address,
|
to: bridgeContract.options.address,
|
||||||
messageData,
|
messageData,
|
||||||
startBlock,
|
startTimestamp: timestamp,
|
||||||
endBlock: homeBlockNumberProvider.get() || 0
|
endTimestamp: timestamp + ONE_DAY_TIMESTAMP
|
||||||
})
|
})
|
||||||
const newStatus =
|
const newStatus =
|
||||||
failedTransactions.length > 0 ? VALIDATOR_CONFIRMATION_STATUS.FAILED : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
failedTransactions.length > 0 ? VALIDATOR_CONFIRMATION_STATUS.FAILED : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
||||||
|
|||||||
Binary file not shown.
@@ -51,6 +51,9 @@ export const isBridgeContract = async (contract: Contract, allowedModes?: string
|
|||||||
}
|
}
|
||||||
return allowedModes.includes(mode)
|
return allowedModes.includes(mode)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
if (e.message.includes("Returned values aren't valid")) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
throw e
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2600,11 +2600,6 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
|
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
|
||||||
integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
|
integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
|
||||||
|
|
||||||
"@types/mocha@^7.0.2":
|
|
||||||
version "7.0.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-7.0.2.tgz#b17f16cf933597e10d6d78eae3251e692ce8b0ce"
|
|
||||||
integrity sha512-ZvO2tAcjmMi8V/5Z3JsyofMe3hasRcaw88cto5etSVMwVQfeivGAlEYmaQgceUSVYFofVjT+ioHsATjdWcFt1w==
|
|
||||||
|
|
||||||
"@types/node@*", "@types/node@>= 8":
|
"@types/node@*", "@types/node@>= 8":
|
||||||
version "13.11.0"
|
version "13.11.0"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.11.0.tgz#390ea202539c61c8fa6ba4428b57e05bc36dc47b"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.11.0.tgz#390ea202539c61c8fa6ba4428b57e05bc36dc47b"
|
||||||
@@ -3220,11 +3215,6 @@ are-we-there-yet@~1.1.2:
|
|||||||
delegates "^1.0.0"
|
delegates "^1.0.0"
|
||||||
readable-stream "^2.0.6"
|
readable-stream "^2.0.6"
|
||||||
|
|
||||||
arg@^4.1.0:
|
|
||||||
version "4.1.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089"
|
|
||||||
integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
|
|
||||||
|
|
||||||
argparse@^1.0.7:
|
argparse@^1.0.7:
|
||||||
version "1.0.10"
|
version "1.0.10"
|
||||||
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
|
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
|
||||||
@@ -3350,11 +3340,6 @@ assert@^1.1.1:
|
|||||||
object-assign "^4.1.1"
|
object-assign "^4.1.1"
|
||||||
util "0.10.3"
|
util "0.10.3"
|
||||||
|
|
||||||
assertion-error@^1.1.0:
|
|
||||||
version "1.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b"
|
|
||||||
integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==
|
|
||||||
|
|
||||||
assign-symbols@^1.0.0:
|
assign-symbols@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
|
resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
|
||||||
@@ -3450,13 +3435,6 @@ axios@^0.18.0:
|
|||||||
follow-redirects "1.5.10"
|
follow-redirects "1.5.10"
|
||||||
is-buffer "^2.0.2"
|
is-buffer "^2.0.2"
|
||||||
|
|
||||||
axios@^0.19.0:
|
|
||||||
version "0.19.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27"
|
|
||||||
integrity sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==
|
|
||||||
dependencies:
|
|
||||||
follow-redirects "1.5.10"
|
|
||||||
|
|
||||||
axobject-query@^2.0.2:
|
axobject-query@^2.0.2:
|
||||||
version "2.1.2"
|
version "2.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.1.2.tgz#2bdffc0371e643e5f03ba99065d5179b9ca79799"
|
resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.1.2.tgz#2bdffc0371e643e5f03ba99065d5179b9ca79799"
|
||||||
@@ -3821,11 +3799,6 @@ browser-resolve@^1.11.3:
|
|||||||
dependencies:
|
dependencies:
|
||||||
resolve "1.1.7"
|
resolve "1.1.7"
|
||||||
|
|
||||||
browser-stdout@1.3.1:
|
|
||||||
version "1.3.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60"
|
|
||||||
integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==
|
|
||||||
|
|
||||||
browserify-aes@^1.0.0, browserify-aes@^1.0.4, browserify-aes@^1.0.6:
|
browserify-aes@^1.0.0, browserify-aes@^1.0.4, browserify-aes@^1.0.6:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48"
|
resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48"
|
||||||
@@ -4215,18 +4188,6 @@ caseless@~0.12.0:
|
|||||||
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
|
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
|
||||||
integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
|
integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
|
||||||
|
|
||||||
chai@^4.2.0:
|
|
||||||
version "4.2.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/chai/-/chai-4.2.0.tgz#760aa72cf20e3795e84b12877ce0e83737aa29e5"
|
|
||||||
integrity sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==
|
|
||||||
dependencies:
|
|
||||||
assertion-error "^1.1.0"
|
|
||||||
check-error "^1.0.2"
|
|
||||||
deep-eql "^3.0.1"
|
|
||||||
get-func-name "^2.0.0"
|
|
||||||
pathval "^1.1.0"
|
|
||||||
type-detect "^4.0.5"
|
|
||||||
|
|
||||||
chalk@2.4.2, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.1, chalk@^2.4.1, chalk@^2.4.2:
|
chalk@2.4.2, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.1, chalk@^2.4.1, chalk@^2.4.2:
|
||||||
version "2.4.2"
|
version "2.4.2"
|
||||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
|
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
|
||||||
@@ -4252,11 +4213,6 @@ chardet@^0.7.0:
|
|||||||
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
|
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
|
||||||
integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
|
integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
|
||||||
|
|
||||||
check-error@^1.0.2:
|
|
||||||
version "1.0.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82"
|
|
||||||
integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=
|
|
||||||
|
|
||||||
check-types@^8.0.3:
|
check-types@^8.0.3:
|
||||||
version "8.0.3"
|
version "8.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/check-types/-/check-types-8.0.3.tgz#3356cca19c889544f2d7a95ed49ce508a0ecf552"
|
resolved "https://registry.yarnpkg.com/check-types/-/check-types-8.0.3.tgz#3356cca19c889544f2d7a95ed49ce508a0ecf552"
|
||||||
@@ -4490,11 +4446,6 @@ combined-stream@^1.0.6, combined-stream@~1.0.6:
|
|||||||
dependencies:
|
dependencies:
|
||||||
delayed-stream "~1.0.0"
|
delayed-stream "~1.0.0"
|
||||||
|
|
||||||
commander@2.15.1:
|
|
||||||
version "2.15.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f"
|
|
||||||
integrity sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==
|
|
||||||
|
|
||||||
commander@2.17.x:
|
commander@2.17.x:
|
||||||
version "2.17.1"
|
version "2.17.1"
|
||||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf"
|
resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf"
|
||||||
@@ -5290,13 +5241,6 @@ dedent@^0.7.0:
|
|||||||
resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c"
|
resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c"
|
||||||
integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=
|
integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=
|
||||||
|
|
||||||
deep-eql@^3.0.1:
|
|
||||||
version "3.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df"
|
|
||||||
integrity sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==
|
|
||||||
dependencies:
|
|
||||||
type-detect "^4.0.0"
|
|
||||||
|
|
||||||
deep-equal@^1.0.1:
|
deep-equal@^1.0.1:
|
||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a"
|
resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a"
|
||||||
@@ -5469,16 +5413,6 @@ diff-sequences@^24.9.0:
|
|||||||
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.9.0.tgz#5715d6244e2aa65f48bba0bc972db0b0b11e95b5"
|
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.9.0.tgz#5715d6244e2aa65f48bba0bc972db0b0b11e95b5"
|
||||||
integrity sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==
|
integrity sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==
|
||||||
|
|
||||||
diff@3.5.0:
|
|
||||||
version "3.5.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
|
|
||||||
integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==
|
|
||||||
|
|
||||||
diff@^4.0.1:
|
|
||||||
version "4.0.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
|
|
||||||
integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
|
|
||||||
|
|
||||||
diffie-hellman@^5.0.0:
|
diffie-hellman@^5.0.0:
|
||||||
version "5.0.3"
|
version "5.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875"
|
resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875"
|
||||||
@@ -7159,11 +7093,6 @@ get-caller-file@^2.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
|
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
|
||||||
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
|
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
|
||||||
|
|
||||||
get-func-name@^2.0.0:
|
|
||||||
version "2.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41"
|
|
||||||
integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=
|
|
||||||
|
|
||||||
get-own-enumerable-property-symbols@^3.0.0:
|
get-own-enumerable-property-symbols@^3.0.0:
|
||||||
version "3.0.2"
|
version "3.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664"
|
resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664"
|
||||||
@@ -7298,18 +7227,6 @@ glob-to-regexp@^0.3.0:
|
|||||||
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab"
|
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab"
|
||||||
integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=
|
integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=
|
||||||
|
|
||||||
glob@7.1.2:
|
|
||||||
version "7.1.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
|
|
||||||
integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==
|
|
||||||
dependencies:
|
|
||||||
fs.realpath "^1.0.0"
|
|
||||||
inflight "^1.0.4"
|
|
||||||
inherits "2"
|
|
||||||
minimatch "^3.0.4"
|
|
||||||
once "^1.3.0"
|
|
||||||
path-is-absolute "^1.0.0"
|
|
||||||
|
|
||||||
glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4:
|
glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4:
|
||||||
version "7.1.6"
|
version "7.1.6"
|
||||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
|
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
|
||||||
@@ -7443,11 +7360,6 @@ graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.
|
|||||||
resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725"
|
resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725"
|
||||||
integrity sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=
|
integrity sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=
|
||||||
|
|
||||||
growl@1.10.5:
|
|
||||||
version "1.10.5"
|
|
||||||
resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e"
|
|
||||||
integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==
|
|
||||||
|
|
||||||
growly@^1.3.0:
|
growly@^1.3.0:
|
||||||
version "1.3.0"
|
version "1.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
|
resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
|
||||||
@@ -7606,11 +7518,6 @@ hdkey@^1.1.1:
|
|||||||
safe-buffer "^5.1.1"
|
safe-buffer "^5.1.1"
|
||||||
secp256k1 "^3.0.1"
|
secp256k1 "^3.0.1"
|
||||||
|
|
||||||
he@1.1.1:
|
|
||||||
version "1.1.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
|
|
||||||
integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0=
|
|
||||||
|
|
||||||
he@1.2.x:
|
he@1.2.x:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
|
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
|
||||||
@@ -9685,11 +9592,6 @@ make-dir@^2.0.0, make-dir@^2.1.0:
|
|||||||
pify "^4.0.1"
|
pify "^4.0.1"
|
||||||
semver "^5.6.0"
|
semver "^5.6.0"
|
||||||
|
|
||||||
make-error@^1.1.1:
|
|
||||||
version "1.3.6"
|
|
||||||
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
|
|
||||||
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
|
|
||||||
|
|
||||||
make-fetch-happen@^5.0.0:
|
make-fetch-happen@^5.0.0:
|
||||||
version "5.0.2"
|
version "5.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-5.0.2.tgz#aa8387104f2687edca01c8687ee45013d02d19bd"
|
resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-5.0.2.tgz#aa8387104f2687edca01c8687ee45013d02d19bd"
|
||||||
@@ -10041,11 +9943,6 @@ minimist-options@^3.0.1:
|
|||||||
arrify "^1.0.1"
|
arrify "^1.0.1"
|
||||||
is-plain-obj "^1.1.0"
|
is-plain-obj "^1.1.0"
|
||||||
|
|
||||||
minimist@0.0.8:
|
|
||||||
version "0.0.8"
|
|
||||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
|
|
||||||
integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=
|
|
||||||
|
|
||||||
minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5:
|
minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5:
|
||||||
version "1.2.5"
|
version "1.2.5"
|
||||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
|
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
|
||||||
@@ -10110,13 +10007,6 @@ mkdirp@*:
|
|||||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
|
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
|
||||||
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
|
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
|
||||||
|
|
||||||
mkdirp@0.5.1:
|
|
||||||
version "0.5.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
|
|
||||||
integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=
|
|
||||||
dependencies:
|
|
||||||
minimist "0.0.8"
|
|
||||||
|
|
||||||
mkdirp@^0.5.0, mkdirp@^0.5.1:
|
mkdirp@^0.5.0, mkdirp@^0.5.1:
|
||||||
version "0.5.5"
|
version "0.5.5"
|
||||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
|
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
|
||||||
@@ -10131,23 +10021,6 @@ mkdirp@~0.5.0, mkdirp@~0.5.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
minimist "^1.2.5"
|
minimist "^1.2.5"
|
||||||
|
|
||||||
mocha@^5.2.0:
|
|
||||||
version "5.2.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.2.0.tgz#6d8ae508f59167f940f2b5b3c4a612ae50c90ae6"
|
|
||||||
integrity sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==
|
|
||||||
dependencies:
|
|
||||||
browser-stdout "1.3.1"
|
|
||||||
commander "2.15.1"
|
|
||||||
debug "3.1.0"
|
|
||||||
diff "3.5.0"
|
|
||||||
escape-string-regexp "1.0.5"
|
|
||||||
glob "7.1.2"
|
|
||||||
growl "1.10.5"
|
|
||||||
he "1.1.1"
|
|
||||||
minimatch "3.0.4"
|
|
||||||
mkdirp "0.5.1"
|
|
||||||
supports-color "5.4.0"
|
|
||||||
|
|
||||||
mock-fs@^4.1.0:
|
mock-fs@^4.1.0:
|
||||||
version "4.11.0"
|
version "4.11.0"
|
||||||
resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.11.0.tgz#0828107e4b843a6ba855ecebfe3c6e073b69db92"
|
resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.11.0.tgz#0828107e4b843a6ba855ecebfe3c6e073b69db92"
|
||||||
@@ -11094,11 +10967,6 @@ path-type@^4.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
|
resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
|
||||||
integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
|
integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
|
||||||
|
|
||||||
pathval@^1.1.0:
|
|
||||||
version "1.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0"
|
|
||||||
integrity sha1-uULm1L3mUwBe9rcTYd74cn0GReA=
|
|
||||||
|
|
||||||
pbkdf2@^3.0.3:
|
pbkdf2@^3.0.3:
|
||||||
version "3.0.17"
|
version "3.0.17"
|
||||||
resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.17.tgz#976c206530617b14ebb32114239f7b09336e93a6"
|
resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.17.tgz#976c206530617b14ebb32114239f7b09336e93a6"
|
||||||
@@ -13403,14 +13271,6 @@ source-map-support@0.5.6:
|
|||||||
buffer-from "^1.0.0"
|
buffer-from "^1.0.0"
|
||||||
source-map "^0.6.0"
|
source-map "^0.6.0"
|
||||||
|
|
||||||
source-map-support@^0.5.17:
|
|
||||||
version "0.5.19"
|
|
||||||
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61"
|
|
||||||
integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==
|
|
||||||
dependencies:
|
|
||||||
buffer-from "^1.0.0"
|
|
||||||
source-map "^0.6.0"
|
|
||||||
|
|
||||||
source-map-support@^0.5.6, source-map-support@~0.5.10, source-map-support@~0.5.12:
|
source-map-support@^0.5.6, source-map-support@~0.5.10, source-map-support@~0.5.12:
|
||||||
version "0.5.16"
|
version "0.5.16"
|
||||||
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042"
|
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042"
|
||||||
@@ -13852,13 +13712,6 @@ stylis@^3.5.0:
|
|||||||
resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.5.4.tgz#f665f25f5e299cf3d64654ab949a57c768b73fbe"
|
resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.5.4.tgz#f665f25f5e299cf3d64654ab949a57c768b73fbe"
|
||||||
integrity sha512-8/3pSmthWM7lsPBKv7NXkzn2Uc9W7NotcwGNpJaa3k7WMM1XDCA4MgT5k/8BIexd5ydZdboXtU90XH9Ec4Bv/Q==
|
integrity sha512-8/3pSmthWM7lsPBKv7NXkzn2Uc9W7NotcwGNpJaa3k7WMM1XDCA4MgT5k/8BIexd5ydZdboXtU90XH9Ec4Bv/Q==
|
||||||
|
|
||||||
supports-color@5.4.0:
|
|
||||||
version "5.4.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54"
|
|
||||||
integrity sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==
|
|
||||||
dependencies:
|
|
||||||
has-flag "^3.0.0"
|
|
||||||
|
|
||||||
supports-color@^2.0.0:
|
supports-color@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
|
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
|
||||||
@@ -14223,17 +14076,6 @@ tryer@^1.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8"
|
resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8"
|
||||||
integrity sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==
|
integrity sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==
|
||||||
|
|
||||||
ts-node@^8.8.2:
|
|
||||||
version "8.10.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.10.2.tgz#eee03764633b1234ddd37f8db9ec10b75ec7fb8d"
|
|
||||||
integrity sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA==
|
|
||||||
dependencies:
|
|
||||||
arg "^4.1.0"
|
|
||||||
diff "^4.0.1"
|
|
||||||
make-error "^1.1.1"
|
|
||||||
source-map-support "^0.5.17"
|
|
||||||
yn "3.1.1"
|
|
||||||
|
|
||||||
ts-pnp@1.1.2:
|
ts-pnp@1.1.2:
|
||||||
version "1.1.2"
|
version "1.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.1.2.tgz#be8e4bfce5d00f0f58e0666a82260c34a57af552"
|
resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.1.2.tgz#be8e4bfce5d00f0f58e0666a82260c34a57af552"
|
||||||
@@ -14280,11 +14122,6 @@ type-check@~0.3.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
prelude-ls "~1.1.2"
|
prelude-ls "~1.1.2"
|
||||||
|
|
||||||
type-detect@^4.0.0, type-detect@^4.0.5:
|
|
||||||
version "4.0.8"
|
|
||||||
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
|
|
||||||
integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
|
|
||||||
|
|
||||||
type-fest@^0.3.0:
|
type-fest@^0.3.0:
|
||||||
version "0.3.1"
|
version "0.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.3.1.tgz#63d00d204e059474fe5e1b7c011112bbd1dc29e1"
|
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.3.1.tgz#63d00d204e059474fe5e1b7c011112bbd1dc29e1"
|
||||||
@@ -14330,11 +14167,6 @@ typescript@3.5.3:
|
|||||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.3.tgz#c830f657f93f1ea846819e929092f5fe5983e977"
|
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.3.tgz#c830f657f93f1ea846819e929092f5fe5983e977"
|
||||||
integrity sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==
|
integrity sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==
|
||||||
|
|
||||||
typescript@^3.5.2:
|
|
||||||
version "3.9.7"
|
|
||||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa"
|
|
||||||
integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==
|
|
||||||
|
|
||||||
uglify-js@3.4.x:
|
uglify-js@3.4.x:
|
||||||
version "3.4.10"
|
version "3.4.10"
|
||||||
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.10.tgz#9ad9563d8eb3acdfb8d38597d2af1d815f6a755f"
|
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.10.tgz#9ad9563d8eb3acdfb8d38597d2af1d815f6a755f"
|
||||||
@@ -15649,8 +15481,3 @@ yauzl@^2.4.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
buffer-crc32 "~0.2.3"
|
buffer-crc32 "~0.2.3"
|
||||||
fd-slicer "~1.1.0"
|
fd-slicer "~1.1.0"
|
||||||
|
|
||||||
yn@3.1.1:
|
|
||||||
version "3.1.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
|
|
||||||
integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==
|
|
||||||
|
|||||||
@@ -5,8 +5,7 @@
|
|||||||
],
|
],
|
||||||
"rules": {
|
"rules": {
|
||||||
"no-unused-expressions": "off",
|
"no-unused-expressions": "off",
|
||||||
"import/no-extraneous-dependencies": "off",
|
"import/no-extraneous-dependencies": "off"
|
||||||
"no-bitwise": "off"
|
|
||||||
},
|
},
|
||||||
"env": {
|
"env": {
|
||||||
"mocha": true
|
"mocha": true
|
||||||
|
|||||||
@@ -2,15 +2,9 @@ function strip0x(input) {
|
|||||||
return input.replace(/^0x/, '')
|
return input.replace(/^0x/, '')
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
function addTxHashToData({ encodedData, transactionHash }) {
|
||||||
* Decodes the datatype byte from the AMB message.
|
return encodedData.slice(0, 2) + strip0x(transactionHash) + encodedData.slice(2)
|
||||||
* 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) {
|
function parseAMBMessage(message) {
|
||||||
message = strip0x(message)
|
message = strip0x(message)
|
||||||
@@ -18,29 +12,16 @@ function parseAMBMessage(message) {
|
|||||||
const messageId = `0x${message.slice(0, 64)}`
|
const messageId = `0x${message.slice(0, 64)}`
|
||||||
const sender = `0x${message.slice(64, 104)}`
|
const sender = `0x${message.slice(64, 104)}`
|
||||||
const executor = `0x${message.slice(104, 144)}`
|
const executor = `0x${message.slice(104, 144)}`
|
||||||
const dataType = parseInt(message.slice(156, 158), 16)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
sender,
|
sender,
|
||||||
executor,
|
executor,
|
||||||
messageId,
|
messageId
|
||||||
dataType,
|
|
||||||
decodedDataType: decodeAMBDataType(dataType)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 = {
|
module.exports = {
|
||||||
strip0x,
|
addTxHashToData,
|
||||||
parseAMBMessage,
|
parseAMBMessage,
|
||||||
normalizeAMBMessageEvent
|
strip0x
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
const { BN } = require('web3-utils')
|
const { BN } = require('web3-utils')
|
||||||
const { expect } = require('chai').use(require('bn-chai')(BN))
|
const { expect } = require('chai').use(require('bn-chai')(BN))
|
||||||
const { parseAMBMessage, strip0x } = require('../message')
|
const { parseAMBMessage, strip0x, addTxHashToData } = require('../message')
|
||||||
|
|
||||||
describe('strip0x', () => {
|
describe('strip0x', () => {
|
||||||
it('should remove 0x from input', () => {
|
it('should remove 0x from input', () => {
|
||||||
@@ -24,6 +24,28 @@ describe('strip0x', () => {
|
|||||||
expect(result).to.be.equal(input)
|
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', () => {
|
describe('parseAMBMessage', () => {
|
||||||
it('should parse data type 00', () => {
|
it('should parse data type 00', () => {
|
||||||
const msgSender = '0x003667154bb32e42bb9e1e6532f19d187fa0082e'
|
const msgSender = '0x003667154bb32e42bb9e1e6532f19d187fa0082e'
|
||||||
|
|||||||
@@ -164,18 +164,18 @@ const getPastEvents = async (
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.message.includes('query returned more than') && toBlock !== 'latest') {
|
if (e.message.includes('query returned more than') && toBlock !== 'latest') {
|
||||||
const middle = toBN(fromBlock)
|
const middle = toBN(fromBlock)
|
||||||
.add(toBN(toBlock))
|
.add(toBlock)
|
||||||
.divRound(toBN(2))
|
.divRound(toBN(2))
|
||||||
const middlePlusOne = middle.add(toBN(1))
|
const middlePlusOne = middle.add(toBN(1))
|
||||||
|
|
||||||
const firstHalfEvents = await getPastEvents(contract, {
|
const firstHalfEvents = await getPastEvents(contract, {
|
||||||
options,
|
...options,
|
||||||
event,
|
event,
|
||||||
fromBlock,
|
fromBlock,
|
||||||
toBlock: middle
|
toBlock: middle
|
||||||
})
|
})
|
||||||
const secondHalfEvents = await getPastEvents(contract, {
|
const secondHalfEvents = await getPastEvents(contract, {
|
||||||
options,
|
...options,
|
||||||
event,
|
event,
|
||||||
fromBlock: middlePlusOne,
|
fromBlock: middlePlusOne,
|
||||||
toBlock
|
toBlock
|
||||||
|
|||||||
@@ -65,20 +65,6 @@ const homeV1Abi = [
|
|||||||
payable: false,
|
payable: false,
|
||||||
stateMutability: 'view',
|
stateMutability: 'view',
|
||||||
type: 'function'
|
type: 'function'
|
||||||
},
|
|
||||||
{
|
|
||||||
constant: true,
|
|
||||||
inputs: [],
|
|
||||||
name: 'requiredBlockConfirmations',
|
|
||||||
outputs: [
|
|
||||||
{
|
|
||||||
name: '',
|
|
||||||
type: 'uint256'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
payable: false,
|
|
||||||
stateMutability: 'view',
|
|
||||||
type: 'function'
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -168,20 +154,6 @@ const foreignViAbi = [
|
|||||||
payable: false,
|
payable: false,
|
||||||
stateMutability: 'view',
|
stateMutability: 'view',
|
||||||
type: 'function'
|
type: 'function'
|
||||||
},
|
|
||||||
{
|
|
||||||
constant: true,
|
|
||||||
inputs: [],
|
|
||||||
name: 'requiredBlockConfirmations',
|
|
||||||
outputs: [
|
|
||||||
{
|
|
||||||
name: '',
|
|
||||||
type: 'uint256'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
payable: false,
|
|
||||||
stateMutability: 'view',
|
|
||||||
type: 'function'
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
Submodule contracts updated: 835742dfd8...dd46135248
@@ -24,7 +24,6 @@ def test_services(host, service):
|
|||||||
("oracle_bridge_affirmation_1"),
|
("oracle_bridge_affirmation_1"),
|
||||||
("oracle_bridge_senderhome_1"),
|
("oracle_bridge_senderhome_1"),
|
||||||
("oracle_bridge_senderforeign_1"),
|
("oracle_bridge_senderforeign_1"),
|
||||||
("oracle_bridge_shutdown_1"),
|
|
||||||
("ui_ui_1"),
|
("ui_ui_1"),
|
||||||
("monitor_monitor_1")
|
("monitor_monitor_1")
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
|
|||||||
("oracle_bridge_affirmation_1"),
|
("oracle_bridge_affirmation_1"),
|
||||||
("oracle_bridge_senderhome_1"),
|
("oracle_bridge_senderhome_1"),
|
||||||
("oracle_bridge_senderforeign_1"),
|
("oracle_bridge_senderforeign_1"),
|
||||||
("oracle_bridge_shutdown_1"),
|
|
||||||
])
|
])
|
||||||
def test_docker_containers(host, name):
|
def test_docker_containers(host, name):
|
||||||
container = host.docker(name)
|
container = host.docker(name)
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ provisioner:
|
|||||||
inventory:
|
inventory:
|
||||||
host_vars:
|
host_vars:
|
||||||
oracle-amb-host:
|
oracle-amb-host:
|
||||||
|
COMMON_HOME_RPC_URL: "http://parity1:8545"
|
||||||
|
COMMON_FOREIGN_RPC_URL: "http://parity2:8545"
|
||||||
ORACLE_VALIDATOR_ADDRESS: "0xaaB52d66283F7A1D5978bcFcB55721ACB467384b"
|
ORACLE_VALIDATOR_ADDRESS: "0xaaB52d66283F7A1D5978bcFcB55721ACB467384b"
|
||||||
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
|
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
|
||||||
ui-amb-stake-erc-to-erc-host:
|
ui-amb-stake-erc-to-erc-host:
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ provisioner:
|
|||||||
inventory:
|
inventory:
|
||||||
host_vars:
|
host_vars:
|
||||||
oracle-amb-host:
|
oracle-amb-host:
|
||||||
|
COMMON_HOME_RPC_URL: "http://parity1:8545"
|
||||||
|
COMMON_FOREIGN_RPC_URL: "http://parity2:8545"
|
||||||
ORACLE_VALIDATOR_ADDRESS: "0xaaB52d66283F7A1D5978bcFcB55721ACB467384b"
|
ORACLE_VALIDATOR_ADDRESS: "0xaaB52d66283F7A1D5978bcFcB55721ACB467384b"
|
||||||
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
|
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
|
||||||
verifier:
|
verifier:
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
---
|
---
|
||||||
- import_playbook: ./oracle-docker-compose.yml
|
|
||||||
- import_playbook: ../../../deployment/site.yml
|
- 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
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
---
|
||||||
|
- 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,22 +1,33 @@
|
|||||||
---
|
---
|
||||||
- name: Prepare Oracle for ultimate tests
|
- name: Overwrite Oracle the docker-compose
|
||||||
hosts: oracle
|
hosts: oracle
|
||||||
become: true
|
become: true
|
||||||
tasks:
|
tasks:
|
||||||
- name: Connect parity to oracle networks
|
- name: stop the service
|
||||||
shell: "docker network create {{ item }} && docker network connect {{ item }} parity1 && docker network connect {{ item }} parity2"
|
shell: service poabridge stop
|
||||||
with_items:
|
|
||||||
- oracle_net_db_bridge_request
|
- name: ReTag current oracle image
|
||||||
- oracle_net_db_bridge_collected
|
shell: docker tag $(docker images --format '{{ '{{' }}.Repository{{ '}}' }}:{{ '{{' }}.Tag{{ '}}' }}' | grep -m 1 tokenbridge-e2e-oracle) oracle:ultimate-testing
|
||||||
- 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
|
delegate_to: 127.0.0.1
|
||||||
become: false
|
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
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
---
|
||||||
|
- 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,6 +32,8 @@ provisioner:
|
|||||||
inventory:
|
inventory:
|
||||||
host_vars:
|
host_vars:
|
||||||
oracle-erc-to-erc-host:
|
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: "0xaaB52d66283F7A1D5978bcFcB55721ACB467384b"
|
||||||
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
|
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
|
||||||
ui-erc-to-erc-host:
|
ui-erc-to-erc-host:
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ provisioner:
|
|||||||
inventory:
|
inventory:
|
||||||
host_vars:
|
host_vars:
|
||||||
oracle-erc-to-native-host:
|
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: "0xaaB52d66283F7A1D5978bcFcB55721ACB467384b"
|
||||||
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
|
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
|
||||||
ORACLE_HOME_START_BLOCK: 1
|
ORACLE_HOME_START_BLOCK: 1
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ provisioner:
|
|||||||
inventory:
|
inventory:
|
||||||
host_vars:
|
host_vars:
|
||||||
oracle-native-to-erc-host:
|
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: "0xaaB52d66283F7A1D5978bcFcB55721ACB467384b"
|
||||||
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
|
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
|
||||||
ui-native-to-erc-host:
|
ui-native-to-erc-host:
|
||||||
|
|||||||
@@ -5,13 +5,13 @@ ORACLE_ALLOW_HTTP_FOR_RPC: yes
|
|||||||
ORACLE_LOG_LEVEL: debug
|
ORACLE_LOG_LEVEL: debug
|
||||||
|
|
||||||
## Home contract
|
## Home contract
|
||||||
COMMON_HOME_RPC_URL: "http://parity1:8545"
|
COMMON_HOME_RPC_URL: "https://sokol.poa.network"
|
||||||
UI_HOME_NETWORK_DISPLAY_NAME: "POA Sokol"
|
UI_HOME_NETWORK_DISPLAY_NAME: "POA Sokol"
|
||||||
UI_HOME_WITHOUT_EVENTS: false
|
UI_HOME_WITHOUT_EVENTS: false
|
||||||
ORACLE_HOME_RPC_POLLING_INTERVAL: 5000
|
ORACLE_HOME_RPC_POLLING_INTERVAL: 5000
|
||||||
|
|
||||||
## Foreign contract
|
## Foreign contract
|
||||||
COMMON_FOREIGN_RPC_URL: "http://parity2:8545"
|
COMMON_FOREIGN_RPC_URL: "https://sokol.poa.network"
|
||||||
UI_FOREIGN_NETWORK_DISPLAY_NAME: "Kovan"
|
UI_FOREIGN_NETWORK_DISPLAY_NAME: "Kovan"
|
||||||
UI_FOREIGN_WITHOUT_EVENTS: false
|
UI_FOREIGN_WITHOUT_EVENTS: false
|
||||||
ORACLE_FOREIGN_RPC_POLLING_INTERVAL: 1000
|
ORACLE_FOREIGN_RPC_POLLING_INTERVAL: 1000
|
||||||
@@ -52,7 +52,3 @@ MONITOR_FOREIGN_START_BLOCK: 0
|
|||||||
MONITOR_VALIDATOR_HOME_TX_LIMIT: 300000
|
MONITOR_VALIDATOR_HOME_TX_LIMIT: 300000
|
||||||
MONITOR_VALIDATOR_FOREIGN_TX_LIMIT: 300000
|
MONITOR_VALIDATOR_FOREIGN_TX_LIMIT: 300000
|
||||||
MONITOR_TX_NUMBER_THRESHOLD: 100
|
MONITOR_TX_NUMBER_THRESHOLD: 100
|
||||||
|
|
||||||
# disable building and pulling of docker images from the Docker Hub
|
|
||||||
skip_pull: true
|
|
||||||
skip_build: true
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
mode: "0755"
|
mode: "0755"
|
||||||
|
|
||||||
- name: Upgrade pip version
|
- name: Upgrade pip version
|
||||||
shell: pip3 install --upgrade pip==19.3.1
|
shell: pip3 install --upgrade pip
|
||||||
|
|
||||||
- name: Install python docker library
|
- name: Install python docker library
|
||||||
shell: pip3 install docker docker-compose setuptools
|
shell: pip3 install docker docker-compose setuptools
|
||||||
|
|||||||
@@ -3,4 +3,3 @@
|
|||||||
shell: docker-compose pull
|
shell: docker-compose pull
|
||||||
args:
|
args:
|
||||||
chdir: "{{ bridge_path }}/monitor"
|
chdir: "{{ bridge_path }}/monitor"
|
||||||
when: skip_pull is undefined
|
|
||||||
|
|||||||
@@ -3,4 +3,3 @@
|
|||||||
shell: docker-compose pull
|
shell: docker-compose pull
|
||||||
args:
|
args:
|
||||||
chdir: "{{ bridge_path }}/oracle"
|
chdir: "{{ bridge_path }}/oracle"
|
||||||
when: skip_pull is undefined
|
|
||||||
|
|||||||
@@ -3,4 +3,3 @@
|
|||||||
shell: docker-compose build
|
shell: docker-compose build
|
||||||
args:
|
args:
|
||||||
chdir: "{{ bridge_path }}/ui"
|
chdir: "{{ bridge_path }}/ui"
|
||||||
when: skip_build is undefined
|
|
||||||
|
|||||||
@@ -1,2 +1 @@
|
|||||||
0xc9e38bfdB9c635F0796ad83CC8705dc379F41c04
|
0xc9e38bfdB9c635F0796ad83CC8705dc379F41c04
|
||||||
0x612E8bd50A7b1F009F43f2b8679E9B8eD91eb5CE
|
|
||||||
|
|||||||
@@ -23,4 +23,3 @@ ORACLE_FOREIGN_RPC_POLLING_INTERVAL=500
|
|||||||
ORACLE_ALLOW_HTTP_FOR_RPC=yes
|
ORACLE_ALLOW_HTTP_FOR_RPC=yes
|
||||||
ORACLE_HOME_START_BLOCK=1
|
ORACLE_HOME_START_BLOCK=1
|
||||||
ORACLE_FOREIGN_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
|
COMMON_FOREIGN_GAS_PRICE_FALLBACK=5000000000
|
||||||
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL=15000
|
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL=15000
|
||||||
COMMON_FOREIGN_GAS_PRICE_FACTOR=1
|
COMMON_FOREIGN_GAS_PRICE_FACTOR=1
|
||||||
UI_PORT=3003
|
UI_PORT=3000
|
||||||
UI_STYLES=stake
|
UI_STYLES=stake
|
||||||
|
|||||||
@@ -19,5 +19,5 @@ COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE=standard
|
|||||||
COMMON_FOREIGN_GAS_PRICE_FALLBACK=5000000000
|
COMMON_FOREIGN_GAS_PRICE_FALLBACK=5000000000
|
||||||
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL=15000
|
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL=15000
|
||||||
COMMON_FOREIGN_GAS_PRICE_FACTOR=1
|
COMMON_FOREIGN_GAS_PRICE_FACTOR=1
|
||||||
UI_PORT=3002
|
UI_PORT=3000
|
||||||
UI_STYLES=core
|
UI_STYLES=core
|
||||||
|
|||||||
@@ -19,5 +19,5 @@ COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE=standard
|
|||||||
COMMON_FOREIGN_GAS_PRICE_FALLBACK=5000000000
|
COMMON_FOREIGN_GAS_PRICE_FALLBACK=5000000000
|
||||||
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL=15000
|
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL=15000
|
||||||
COMMON_FOREIGN_GAS_PRICE_FACTOR=1
|
COMMON_FOREIGN_GAS_PRICE_FACTOR=1
|
||||||
UI_PORT=3001
|
UI_PORT=3000
|
||||||
UI_STYLES=core
|
UI_STYLES=core
|
||||||
|
|||||||
@@ -63,7 +63,6 @@
|
|||||||
"foreign": "0x0AEe1FCD12dDFab6265F7f8956e6E012A9Fe4Aa0",
|
"foreign": "0x0AEe1FCD12dDFab6265F7f8956e6E012A9Fe4Aa0",
|
||||||
"homeBox": "0x6C4EaAb8756d53Bf599FFe2347FAFF1123D6C8A1",
|
"homeBox": "0x6C4EaAb8756d53Bf599FFe2347FAFF1123D6C8A1",
|
||||||
"foreignBox": "0x6C4EaAb8756d53Bf599FFe2347FAFF1123D6C8A1",
|
"foreignBox": "0x6C4EaAb8756d53Bf599FFe2347FAFF1123D6C8A1",
|
||||||
"blockedHomeBox": "0x612E8bd50A7b1F009F43f2b8679E9B8eD91eb5CE",
|
|
||||||
"monitor": "http://monitor-amb:3013/bridge"
|
"monitor": "http://monitor-amb:3013/bridge"
|
||||||
},
|
},
|
||||||
"ambStakeErcToErc": {
|
"ambStakeErcToErc": {
|
||||||
|
|||||||
@@ -4,14 +4,12 @@ networks:
|
|||||||
external: true
|
external: true
|
||||||
services:
|
services:
|
||||||
parity1:
|
parity1:
|
||||||
container_name: parity1
|
|
||||||
build: ../parity
|
build: ../parity
|
||||||
ports:
|
ports:
|
||||||
- "8541:8545"
|
- "8541:8545"
|
||||||
networks:
|
networks:
|
||||||
- ultimate
|
- ultimate
|
||||||
parity2:
|
parity2:
|
||||||
container_name: parity2
|
|
||||||
build:
|
build:
|
||||||
context: ../parity
|
context: ../parity
|
||||||
dockerfile: Dockerfile-foreign
|
dockerfile: Dockerfile-foreign
|
||||||
@@ -63,9 +61,6 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
- NODE_ENV=production
|
- NODE_ENV=production
|
||||||
command: "true"
|
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:
|
networks:
|
||||||
- ultimate
|
- ultimate
|
||||||
ui:
|
ui:
|
||||||
|
|||||||
@@ -53,8 +53,3 @@ node deploy.js
|
|||||||
cd - > /dev/null
|
cd - > /dev/null
|
||||||
node setupStakeTokens.js
|
node setupStakeTokens.js
|
||||||
cd - > /dev/null
|
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,32 +17,23 @@ docker-compose up -d parity1 parity2 e2e
|
|||||||
startValidator () {
|
startValidator () {
|
||||||
docker-compose $1 run -d --name $4 redis
|
docker-compose $1 run -d --name $4 redis
|
||||||
docker-compose $1 run -d --name $5 rabbit
|
docker-compose $1 run -d --name $5 rabbit
|
||||||
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:signature-request
|
||||||
docker-compose $1 run $2 $3 -d oracle yarn watcher:collected-signatures
|
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 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: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: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:affirmation-request
|
||||||
docker-compose $1 run $2 $3 -d oracle-erc20 yarn watcher:transfer
|
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: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: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: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 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-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: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:collected-signatures
|
||||||
docker-compose $1 run $2 $3 -d oracle-amb yarn watcher:affirmation-request
|
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:home
|
||||||
docker-compose $1 run $2 $3 -d oracle-erc20-native yarn sender:foreign
|
docker-compose $1 run $2 $3 -d oracle-erc20-native yarn sender:foreign
|
||||||
docker-compose $1 run $2 $3 -d oracle yarn manager:shutdown
|
|
||||||
}
|
}
|
||||||
|
|
||||||
startAMBValidator () {
|
startAMBValidator () {
|
||||||
@@ -53,12 +44,29 @@ startAMBValidator () {
|
|||||||
docker-compose $1 run $2 $3 -d oracle-amb yarn watcher:affirmation-request
|
docker-compose $1 run $2 $3 -d oracle-amb yarn watcher:affirmation-request
|
||||||
docker-compose $1 run $2 $3 -d oracle-amb yarn sender:home
|
docker-compose $1 run $2 $3 -d oracle-amb yarn sender:home
|
||||||
docker-compose $1 run $2 $3 -d oracle-amb yarn sender:foreign
|
docker-compose $1 run $2 $3 -d oracle-amb yarn sender:foreign
|
||||||
docker-compose $1 run $2 $3 -d oracle-amb yarn manager:shutdown
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while [ "$1" != "" ]; do
|
while [ "$1" != "" ]; do
|
||||||
if [ "$1" == "oracle" ]; then
|
if [ "$1" == "oracle" ]; then
|
||||||
startValidator "" "" "" "redis" "rabbit"
|
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
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$1" == "oracle-validator-2" ]; then
|
if [ "$1" == "oracle-validator-2" ]; then
|
||||||
@@ -82,9 +90,9 @@ while [ "$1" != "" ]; do
|
|||||||
docker-compose up -d ui ui-erc20 ui-erc20-native ui-amb-stake-erc20-erc20
|
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 3000:3000 ui yarn start
|
||||||
docker-compose run -d -p 3001:3001 ui-erc20 yarn start
|
docker-compose run -d -p 3001:3000 ui-erc20 yarn start
|
||||||
docker-compose run -d -p 3002:3002 ui-erc20-native yarn start
|
docker-compose run -d -p 3002:3000 ui-erc20-native yarn start
|
||||||
docker-compose run -d -p 3003:3003 ui-amb-stake-erc20-erc20 yarn start
|
docker-compose run -d -p 3003:3000 ui-amb-stake-erc20-erc20 yarn start
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$1" == "alm" ]; then
|
if [ "$1" == "alm" ]; then
|
||||||
@@ -102,27 +110,17 @@ while [ "$1" != "" ]; do
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$1" == "monitor" ]; then
|
if [ "$1" == "monitor" ]; then
|
||||||
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
|
docker-compose up -d monitor monitor-erc20 monitor-erc20-native monitor-amb
|
||||||
;;
|
|
||||||
esac
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$1" == "alm-e2e" ]; then
|
if [ "$1" == "alm-e2e" ]; then
|
||||||
startAMBValidator "" "" "" "redis" "rabbit"
|
docker-compose up -d redis rabbit
|
||||||
|
|
||||||
|
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-amb yarn sender:home
|
||||||
|
docker-compose run -d oracle-amb yarn sender:foreign
|
||||||
|
|
||||||
oracle2name="-p validator2"
|
oracle2name="-p validator2"
|
||||||
oracle2Values="-e ORACLE_VALIDATOR_ADDRESS=0xdCC784657C78054aa61FbcFFd2605F32374816A4 -e ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=5a5c3645d0f04e9eb4f27f94ed4c244a225587405b8838e7456f7781ce3a9513"
|
oracle2Values="-e ORACLE_VALIDATOR_ADDRESS=0xdCC784657C78054aa61FbcFFd2605F32374816A4 -e ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=5a5c3645d0f04e9eb4f27f94ed4c244a225587405b8838e7456f7781ce3a9513"
|
||||||
|
|||||||
@@ -1,15 +1,7 @@
|
|||||||
while true; do
|
while true; do
|
||||||
docker-compose -f ../e2e-commons/docker-compose.yml exec -T monitor yarn check-all
|
sleep 5
|
||||||
pid1=$!
|
docker-compose -f ../e2e-commons/docker-compose.yml exec -d monitor yarn check-all
|
||||||
docker-compose -f ../e2e-commons/docker-compose.yml exec -T monitor-erc20 yarn check-all
|
docker-compose -f ../e2e-commons/docker-compose.yml exec -d monitor-erc20 yarn check-all
|
||||||
pid2=$!
|
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 -T monitor-erc20-native yarn check-all
|
docker-compose -f ../e2e-commons/docker-compose.yml exec -d monitor-amb 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
|
done
|
||||||
|
|||||||
@@ -1,28 +1,12 @@
|
|||||||
cd $(dirname $0)
|
cd $(dirname $0)
|
||||||
|
|
||||||
mode="$1"
|
../e2e-commons/up.sh deploy blocks monitor
|
||||||
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
|
|
||||||
|
|
||||||
MODE="$mode" ../e2e-commons/up.sh deploy blocks monitor
|
./wait-for-monitor.sh
|
||||||
|
|
||||||
MODE="$mode" ./wait-for-monitor.sh
|
|
||||||
nohup ./periodically-check-all.sh < /dev/null > /dev/null 2>&1 &
|
nohup ./periodically-check-all.sh < /dev/null > /dev/null 2>&1 &
|
||||||
checkPID=$!
|
checkPID=$!
|
||||||
|
|
||||||
docker-compose -f ../e2e-commons/docker-compose.yml run e2e yarn workspace monitor-e2e run start $script
|
docker-compose -f ../e2e-commons/docker-compose.yml run e2e yarn workspace monitor-e2e run start
|
||||||
rc=$?
|
rc=$?
|
||||||
|
|
||||||
../e2e-commons/down.sh
|
../e2e-commons/down.sh
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ describe('AMB', () => {
|
|||||||
|
|
||||||
describe('general', async () => {
|
describe('general', async () => {
|
||||||
it('should contain fromHomeToForeignDiff', () => assert(data.fromHomeToForeignDiff === 0))
|
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 fromForeignToHomeDiff', () => assert(data.fromForeignToHomeDiff === 0))
|
||||||
it('should contain lastChecked', () => assert(data.lastChecked >= 0))
|
it('should contain lastChecked', () => assert(data.lastChecked >= 0))
|
||||||
it('should contain timeDiff', () => assert(data.timeDiff >= 0))
|
it('should contain timeDiff', () => assert(data.timeDiff >= 0))
|
||||||
@@ -115,16 +114,7 @@ describe('AMB', () => {
|
|||||||
|
|
||||||
await waitUntil(async () => {
|
await waitUntil(async () => {
|
||||||
;({ data } = await axios.get(`${baseUrl}`))
|
;({ data } = await axios.get(`${baseUrl}`))
|
||||||
return data.fromHomeToForeignDiff === 1 && data.fromHomeToForeignPBUDiff === 0
|
return data.fromHomeToForeignDiff !== 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 () => {
|
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() {
|
it('should consider chai token balance', async function() {
|
||||||
this.timeout(120000)
|
this.timeout(60000)
|
||||||
await initializeChaiToken(foreignRPC.URL, ercToNativeBridge.foreign)
|
await initializeChaiToken(foreignRPC.URL, ercToNativeBridge.foreign)
|
||||||
await sendTokens(foreignRPC.URL, user, ercToNativeBridge.foreignToken, ercToNativeBridge.foreign)
|
await sendTokens(foreignRPC.URL, user, ercToNativeBridge.foreignToken, ercToNativeBridge.foreign)
|
||||||
|
|
||||||
await waitUntil(async () => {
|
await waitUntil(async () => {
|
||||||
;({ data } = await axios.get(`${baseUrl}`))
|
;({ data } = await axios.get(`${baseUrl}`))
|
||||||
|
const { erc20Balance, investedErc20Balance, accumulatedInterest } = data.foreign
|
||||||
if (!data.foreign) {
|
if (!data.foreign) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
const { erc20Balance, investedErc20Balance, accumulatedInterest } = data.foreign
|
|
||||||
return (
|
return (
|
||||||
data.balanceDiff === 0.02 &&
|
data.balanceDiff === 0.02 &&
|
||||||
erc20Balance === '0.02' &&
|
erc20Balance === '0.02' &&
|
||||||
@@ -77,10 +77,10 @@ describe('ERC TO NATIVE with changing state of contracts', () => {
|
|||||||
|
|
||||||
await waitUntil(async () => {
|
await waitUntil(async () => {
|
||||||
;({ data } = await axios.get(`${baseUrl}`))
|
;({ data } = await axios.get(`${baseUrl}`))
|
||||||
|
const { erc20Balance, investedErc20Balance, accumulatedInterest } = data.foreign
|
||||||
if (!data.foreign) {
|
if (!data.foreign) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
const { erc20Balance, investedErc20Balance, accumulatedInterest } = data.foreign
|
|
||||||
return (
|
return (
|
||||||
data.balanceDiff === 0.02 &&
|
data.balanceDiff === 0.02 &&
|
||||||
erc20Balance === '0.01' &&
|
erc20Balance === '0.01' &&
|
||||||
@@ -94,10 +94,10 @@ describe('ERC TO NATIVE with changing state of contracts', () => {
|
|||||||
|
|
||||||
await waitUntil(async () => {
|
await waitUntil(async () => {
|
||||||
;({ data } = await axios.get(`${baseUrl}`))
|
;({ data } = await axios.get(`${baseUrl}`))
|
||||||
|
const { erc20Balance, investedErc20Balance, accumulatedInterest } = data.foreign
|
||||||
if (!data.foreign) {
|
if (!data.foreign) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
const { erc20Balance, investedErc20Balance, accumulatedInterest } = data.foreign
|
|
||||||
return (
|
return (
|
||||||
data.balanceDiff === 0.02 &&
|
data.balanceDiff === 0.02 &&
|
||||||
erc20Balance === '0.005' &&
|
erc20Balance === '0.005' &&
|
||||||
|
|||||||
@@ -44,16 +44,12 @@ const sendTokens = async (rpcUrl, account, tokenAddress, recipientAddress) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const sendAMBMessage = async (rpcUrl, account, boxAddress, bridgeAddress, boxOtherSideAddress, manualLane = false) => {
|
const sendAMBMessage = async (rpcUrl, account, boxAddress, bridgeAddress, boxOtherSideAddress) => {
|
||||||
const web3 = new Web3(new Web3.providers.HttpProvider(rpcUrl))
|
const web3 = new Web3(new Web3.providers.HttpProvider(rpcUrl))
|
||||||
web3.eth.accounts.wallet.add(account.privateKey)
|
web3.eth.accounts.wallet.add(account.privateKey)
|
||||||
const homeBox = new web3.eth.Contract(BOX_ABI, boxAddress)
|
const homeBox = new web3.eth.Contract(BOX_ABI, boxAddress)
|
||||||
|
|
||||||
await homeBox.methods[manualLane ? 'setValueOnOtherNetworkUsingManualLane' : 'setValueOnOtherNetwork'](
|
await homeBox.methods.setValueOnOtherNetwork(3, bridgeAddress, boxOtherSideAddress).send({
|
||||||
3,
|
|
||||||
bridgeAddress,
|
|
||||||
boxOtherSideAddress
|
|
||||||
).send({
|
|
||||||
from: account.address,
|
from: account.address,
|
||||||
gas: '400000'
|
gas: '400000'
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -6,18 +6,10 @@ check_files_exist() {
|
|||||||
rc=0
|
rc=0
|
||||||
for f in "${FILES[@]}"; do
|
for f in "${FILES[@]}"; do
|
||||||
command="test -f responses/bridge/$f"
|
command="test -f responses/bridge/$f"
|
||||||
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
|
(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
|
(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
|
(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
|
(docker-compose -f ../e2e-commons/docker-compose.yml exec -T monitor-amb /bin/bash -c "$command") || rc=1
|
||||||
fi
|
|
||||||
done
|
done
|
||||||
return $rc
|
return $rc
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,9 +22,3 @@ COMMON_FOREIGN_GAS_PRICE_FACTOR=1
|
|||||||
MONITOR_TX_NUMBER_THRESHOLD=100
|
MONITOR_TX_NUMBER_THRESHOLD=100
|
||||||
MONITOR_PORT=3003
|
MONITOR_PORT=3003
|
||||||
MONITOR_CACHE_EVENTS=true
|
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,19 +1,27 @@
|
|||||||
require('dotenv').config()
|
require('dotenv').config()
|
||||||
|
const Web3 = require('web3')
|
||||||
const logger = require('./logger')('alerts')
|
const logger = require('./logger')('alerts')
|
||||||
|
const eventsInfo = require('./utils/events')
|
||||||
|
const { getBlockNumber } = require('./utils/contract')
|
||||||
const { processedMsgNotDelivered, eventWithoutReference } = require('./utils/message')
|
const { processedMsgNotDelivered, eventWithoutReference } = require('./utils/message')
|
||||||
const { BRIDGE_MODES } = require('../commons')
|
const { BRIDGE_MODES } = require('../commons')
|
||||||
const { web3Home, web3Foreign } = require('./utils/web3')
|
|
||||||
|
|
||||||
async function main(eventsInfo) {
|
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)
|
||||||
|
|
||||||
|
async function main() {
|
||||||
const {
|
const {
|
||||||
homeBlockNumber,
|
|
||||||
foreignBlockNumber,
|
|
||||||
homeToForeignRequests,
|
homeToForeignRequests,
|
||||||
homeToForeignConfirmations,
|
homeToForeignConfirmations,
|
||||||
foreignToHomeConfirmations,
|
foreignToHomeConfirmations,
|
||||||
foreignToHomeRequests,
|
foreignToHomeRequests,
|
||||||
bridgeMode
|
bridgeMode
|
||||||
} = eventsInfo
|
} = await eventsInfo()
|
||||||
|
|
||||||
let xSignatures
|
let xSignatures
|
||||||
let xAffirmations
|
let xAffirmations
|
||||||
@@ -25,6 +33,7 @@ async function main(eventsInfo) {
|
|||||||
xAffirmations = foreignToHomeConfirmations.filter(eventWithoutReference(foreignToHomeRequests))
|
xAffirmations = foreignToHomeConfirmations.filter(eventWithoutReference(foreignToHomeRequests))
|
||||||
}
|
}
|
||||||
logger.debug('building misbehavior blocks')
|
logger.debug('building misbehavior blocks')
|
||||||
|
const [homeBlockNumber, foreignBlockNumber] = await getBlockNumber(web3Home, web3Foreign)
|
||||||
|
|
||||||
const baseRange = [false, false, false, false, false]
|
const baseRange = [false, false, false, false, false]
|
||||||
const xSignaturesMisbehavior = buildRangesObject(
|
const xSignaturesMisbehavior = buildRangesObject(
|
||||||
@@ -64,21 +73,21 @@ async function main(eventsInfo) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds the location for the blockNumber in a specific range starting from currentBlockNumber
|
* Finds the location for the blockNumber in a specific range starting from currentBlockNumber
|
||||||
* @param {Number} currentBlockNumber
|
* @param {BN} currentBlockNumber
|
||||||
* @returns {function({blockNumber?: *}): boolean[]}
|
* @returns {function({blockNumber?: *}): boolean[]}
|
||||||
*/
|
*/
|
||||||
const findMisbehaviorRange = currentBlockNumber => ({ blockNumber }) => {
|
const findMisbehaviorRange = currentBlockNumber => ({ blockNumber }) => {
|
||||||
const minus60 = currentBlockNumber - 60
|
const minus60 = currentBlockNumber.sub(Web3.utils.toBN(60))
|
||||||
const minus180 = currentBlockNumber - 180
|
const minus180 = currentBlockNumber.sub(Web3.utils.toBN(180))
|
||||||
const minus720 = currentBlockNumber - 720
|
const minus720 = currentBlockNumber.sub(Web3.utils.toBN(720))
|
||||||
const minus17280 = currentBlockNumber - 17280
|
const minus17280 = currentBlockNumber.sub(Web3.utils.toBN(17280))
|
||||||
|
|
||||||
return [
|
return [
|
||||||
minus60 <= blockNumber,
|
minus60.lte(blockNumber),
|
||||||
minus180 <= blockNumber && minus60 > blockNumber,
|
minus180.lte(blockNumber) && minus60.gt(blockNumber),
|
||||||
minus720 <= blockNumber && minus180 > blockNumber,
|
minus720.lte(blockNumber) && minus180.gt(blockNumber),
|
||||||
minus17280 <= blockNumber && minus720 > blockNumber,
|
minus17280.lte(blockNumber) && minus720.gt(blockNumber),
|
||||||
minus17280 > blockNumber
|
minus17280.gt(blockNumber)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
0
monitor/cache/.gitkeep
vendored
0
monitor/cache/.gitkeep
vendored
@@ -1,16 +1,20 @@
|
|||||||
require('dotenv').config()
|
require('dotenv').config()
|
||||||
const BN = require('bignumber.js')
|
const Web3 = require('web3')
|
||||||
const logger = require('./logger')('checkWorker')
|
const logger = require('./logger')('checkWorker')
|
||||||
const { getBridgeMode } = require('../commons')
|
const { getBridgeMode } = require('../commons')
|
||||||
const getBalances = require('./getBalances')
|
const getBalances = require('./getBalances')
|
||||||
const getShortEventStats = require('./getShortEventStats')
|
const getShortEventStats = require('./getShortEventStats')
|
||||||
const validators = require('./validators')
|
const validators = require('./validators')
|
||||||
const getEventsInfo = require('./utils/events')
|
|
||||||
const { writeFile, createDir } = require('./utils/file')
|
const { writeFile, createDir } = require('./utils/file')
|
||||||
const { saveCache } = require('./utils/web3Cache')
|
|
||||||
const { web3Home } = require('./utils/web3')
|
|
||||||
|
|
||||||
const { COMMON_HOME_BRIDGE_ADDRESS, MONITOR_BRIDGE_NAME } = process.env
|
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 { HOME_ERC_TO_ERC_ABI } = require('../commons')
|
const { HOME_ERC_TO_ERC_ABI } = require('../commons')
|
||||||
|
|
||||||
@@ -20,27 +24,42 @@ async function checkWorker() {
|
|||||||
const homeBridge = new web3Home.eth.Contract(HOME_ERC_TO_ERC_ABI, COMMON_HOME_BRIDGE_ADDRESS)
|
const homeBridge = new web3Home.eth.Contract(HOME_ERC_TO_ERC_ABI, COMMON_HOME_BRIDGE_ADDRESS)
|
||||||
const bridgeMode = await getBridgeMode(homeBridge)
|
const bridgeMode = await getBridgeMode(homeBridge)
|
||||||
logger.debug('Bridge mode:', bridgeMode)
|
logger.debug('Bridge mode:', bridgeMode)
|
||||||
logger.debug('calling getEventsInfo()')
|
|
||||||
const eventsInfo = await getEventsInfo(bridgeMode)
|
|
||||||
logger.debug('calling getBalances()')
|
logger.debug('calling getBalances()')
|
||||||
const balances = await getBalances(bridgeMode, eventsInfo)
|
const balances = await getBalances(bridgeMode)
|
||||||
logger.debug('calling getShortEventStats()')
|
logger.debug('calling getShortEventStats()')
|
||||||
const events = await getShortEventStats(bridgeMode, eventsInfo)
|
const events = await getShortEventStats(bridgeMode)
|
||||||
const home = Object.assign({}, balances.home, events.home)
|
const home = Object.assign({}, balances.home, events.home)
|
||||||
const foreign = Object.assign({}, balances.foreign, events.foreign)
|
const foreign = Object.assign({}, balances.foreign, events.foreign)
|
||||||
const status = Object.assign({}, balances, events, { home }, { 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))
|
if (!status) throw new Error('status is empty: ' + JSON.stringify(status))
|
||||||
status.health = true
|
status.health = true
|
||||||
writeFile(`/responses/${MONITOR_BRIDGE_NAME}/getBalances.json`, status)
|
writeFile(`/responses/${MONITOR_BRIDGE_NAME}/getBalances.json`, status)
|
||||||
saveCache()
|
|
||||||
|
|
||||||
logger.debug('calling validators()')
|
logger.debug('calling validators()')
|
||||||
const vBalances = await validators(bridgeMode)
|
const vBalances = await validators(bridgeMode)
|
||||||
if (!vBalances) throw new Error('vBalances is empty: ' + JSON.stringify(vBalances))
|
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.ok = vBalances.homeOk && vBalances.foreignOk
|
||||||
vBalances.health = true
|
vBalances.health = true
|
||||||
writeFile(`/responses/${MONITOR_BRIDGE_NAME}/validators.json`, vBalances)
|
writeFile(`/responses/${MONITOR_BRIDGE_NAME}/validators.json`, vBalances)
|
||||||
|
|||||||
@@ -1,20 +1,16 @@
|
|||||||
require('dotenv').config()
|
require('dotenv').config()
|
||||||
const logger = require('./logger')('checkWorker2')
|
const logger = require('./logger')('checkWorker2')
|
||||||
const eventsStats = require('./eventsStats')
|
const eventsStats = require('./eventsStats')
|
||||||
const getEventsInfo = require('./utils/events')
|
|
||||||
const alerts = require('./alerts')
|
const alerts = require('./alerts')
|
||||||
const { writeFile, createDir } = require('./utils/file')
|
const { writeFile, createDir } = require('./utils/file')
|
||||||
const { saveCache } = require('./utils/web3Cache')
|
|
||||||
|
|
||||||
const { MONITOR_BRIDGE_NAME } = process.env
|
const { MONITOR_BRIDGE_NAME } = process.env
|
||||||
|
|
||||||
async function checkWorker2() {
|
async function checkWorker2() {
|
||||||
try {
|
try {
|
||||||
createDir(`/responses/${MONITOR_BRIDGE_NAME}`)
|
createDir(`/responses/${MONITOR_BRIDGE_NAME}`)
|
||||||
logger.debug('calling getEventsInfo()')
|
|
||||||
const eventsInfo = await getEventsInfo()
|
|
||||||
logger.debug('calling eventsStats()')
|
logger.debug('calling eventsStats()')
|
||||||
const evStats = await eventsStats(eventsInfo)
|
const evStats = await eventsStats()
|
||||||
if (!evStats) throw new Error('evStats is empty: ' + JSON.stringify(evStats))
|
if (!evStats) throw new Error('evStats is empty: ' + JSON.stringify(evStats))
|
||||||
evStats.ok =
|
evStats.ok =
|
||||||
(evStats.onlyInHomeDeposits || evStats.home.deliveredMsgNotProcessedInForeign).length === 0 &&
|
(evStats.onlyInHomeDeposits || evStats.home.deliveredMsgNotProcessedInForeign).length === 0 &&
|
||||||
@@ -25,12 +21,11 @@ async function checkWorker2() {
|
|||||||
writeFile(`/responses/${MONITOR_BRIDGE_NAME}/eventsStats.json`, evStats)
|
writeFile(`/responses/${MONITOR_BRIDGE_NAME}/eventsStats.json`, evStats)
|
||||||
|
|
||||||
logger.debug('calling alerts()')
|
logger.debug('calling alerts()')
|
||||||
const _alerts = await alerts(eventsInfo)
|
const _alerts = await alerts()
|
||||||
if (!_alerts) throw new Error('alerts is empty: ' + JSON.stringify(_alerts))
|
if (!_alerts) throw new Error('alerts is empty: ' + JSON.stringify(_alerts))
|
||||||
_alerts.ok = !_alerts.executeAffirmations.mostRecentTxHash && !_alerts.executeSignatures.mostRecentTxHash
|
_alerts.ok = !_alerts.executeAffirmations.mostRecentTxHash && !_alerts.executeSignatures.mostRecentTxHash
|
||||||
_alerts.health = true
|
_alerts.health = true
|
||||||
writeFile(`/responses/${MONITOR_BRIDGE_NAME}/alerts.json`, _alerts)
|
writeFile(`/responses/${MONITOR_BRIDGE_NAME}/alerts.json`, _alerts)
|
||||||
saveCache()
|
|
||||||
logger.debug('Done x2')
|
logger.debug('Done x2')
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error(e)
|
logger.error(e)
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
require('dotenv').config()
|
require('dotenv').config()
|
||||||
|
const Web3 = require('web3')
|
||||||
const logger = require('./logger')('checkWorker3')
|
const logger = require('./logger')('checkWorker3')
|
||||||
const stuckTransfers = require('./stuckTransfers')
|
const stuckTransfers = require('./stuckTransfers')
|
||||||
const detectMediators = require('./detectMediators')
|
|
||||||
const detectFailures = require('./detectFailures')
|
|
||||||
const { writeFile, createDir } = require('./utils/file')
|
const { writeFile, createDir } = require('./utils/file')
|
||||||
const { web3Home } = require('./utils/web3')
|
|
||||||
const { saveCache } = require('./utils/web3Cache')
|
|
||||||
|
|
||||||
const { MONITOR_BRIDGE_NAME, COMMON_HOME_BRIDGE_ADDRESS } = process.env
|
const { MONITOR_BRIDGE_NAME, COMMON_HOME_BRIDGE_ADDRESS, COMMON_HOME_RPC_URL } = process.env
|
||||||
const { getBridgeMode, HOME_NATIVE_TO_ERC_ABI, BRIDGE_MODES } = require('../commons')
|
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() {
|
async function checkWorker3() {
|
||||||
try {
|
try {
|
||||||
const homeBridge = new web3Home.eth.Contract(HOME_NATIVE_TO_ERC_ABI, COMMON_HOME_BRIDGE_ADDRESS)
|
const homeBridge = new web3Home.eth.Contract(HOME_NATIVE_TO_ERC_ABI, COMMON_HOME_BRIDGE_ADDRESS)
|
||||||
@@ -23,23 +23,6 @@ async function checkWorker3() {
|
|||||||
transfers.health = true
|
transfers.health = true
|
||||||
writeFile(`/responses/${MONITOR_BRIDGE_NAME}/stuckTransfers.json`, transfers)
|
writeFile(`/responses/${MONITOR_BRIDGE_NAME}/stuckTransfers.json`, transfers)
|
||||||
logger.debug('Done')
|
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)
|
|
||||||
|
|
||||||
logger.debug('calling detectFailures()')
|
|
||||||
const failures = await detectFailures(bridgeMode)
|
|
||||||
failures.ok = true
|
|
||||||
failures.health = true
|
|
||||||
writeFile(`/responses/${MONITOR_BRIDGE_NAME}/failures.json`, failures)
|
|
||||||
|
|
||||||
saveCache()
|
|
||||||
logger.debug('Done')
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error('checkWorker3.js', e)
|
logger.error('checkWorker3.js', e)
|
||||||
|
|||||||
@@ -1,86 +0,0 @@
|
|||||||
require('dotenv').config()
|
|
||||||
const logger = require('./logger')('alerts')
|
|
||||||
const eventsInfo = require('./utils/events')
|
|
||||||
const { normalizeAMBMessageEvent } = require('../commons')
|
|
||||||
const { getHomeBlockNumber, getForeignBlockNumber } = require('./utils/web3')
|
|
||||||
|
|
||||||
function normalize(events) {
|
|
||||||
const requests = {}
|
|
||||||
events.forEach(event => {
|
|
||||||
const request = normalizeAMBMessageEvent(event)
|
|
||||||
request.requestTx = event.transactionHash
|
|
||||||
requests[request.messageId] = request
|
|
||||||
})
|
|
||||||
return confirmation => {
|
|
||||||
const request = requests[confirmation.returnValues.messageId] || {}
|
|
||||||
return {
|
|
||||||
...request,
|
|
||||||
status: false,
|
|
||||||
executionTx: confirmation.transactionHash,
|
|
||||||
executionBlockNumber: confirmation.blockNumber
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function main(mode) {
|
|
||||||
const {
|
|
||||||
homeToForeignRequests,
|
|
||||||
homeToForeignConfirmations,
|
|
||||||
foreignToHomeConfirmations,
|
|
||||||
foreignToHomeRequests
|
|
||||||
} = await eventsInfo(mode)
|
|
||||||
const hasFailed = event => !event.returnValues.status
|
|
||||||
const cmp = (a, b) => b.executionBlockNumber - a.executionBlockNumber
|
|
||||||
const failedForeignToHomeMessages = foreignToHomeConfirmations
|
|
||||||
.filter(hasFailed)
|
|
||||||
.map(normalize(foreignToHomeRequests))
|
|
||||||
.sort(cmp)
|
|
||||||
const failedHomeToForeignMessages = homeToForeignConfirmations
|
|
||||||
.filter(hasFailed)
|
|
||||||
.map(normalize(homeToForeignRequests))
|
|
||||||
.sort(cmp)
|
|
||||||
|
|
||||||
const homeBlockNumber = await getHomeBlockNumber()
|
|
||||||
const foreignBlockNumber = await getForeignBlockNumber()
|
|
||||||
|
|
||||||
const blockRanges = [1000, 10000, 100000, 1000000]
|
|
||||||
const rangeNames = [
|
|
||||||
`last${blockRanges[0]}blocks`,
|
|
||||||
...blockRanges.slice(0, blockRanges.length - 1).map((n, i) => `last${n}to${blockRanges[i + 1]}blocks`),
|
|
||||||
`before${blockRanges[blockRanges.length - 1]}blocks`
|
|
||||||
]
|
|
||||||
|
|
||||||
const countFailures = (failedMessages, lastBlockNumber) => {
|
|
||||||
const result = {}
|
|
||||||
rangeNames.forEach(name => {
|
|
||||||
result[name] = 0
|
|
||||||
})
|
|
||||||
failedMessages.forEach(message => {
|
|
||||||
const blockAge = lastBlockNumber - message.executionBlockNumber
|
|
||||||
let rangeIndex = blockRanges.findIndex(n => n > blockAge)
|
|
||||||
if (rangeIndex === -1) {
|
|
||||||
rangeIndex = blockRanges.length
|
|
||||||
}
|
|
||||||
result[rangeNames[rangeIndex]] += 1
|
|
||||||
})
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.debug('Done')
|
|
||||||
|
|
||||||
return {
|
|
||||||
homeToForeign: {
|
|
||||||
total: failedHomeToForeignMessages.length,
|
|
||||||
stats: countFailures(failedHomeToForeignMessages, foreignBlockNumber),
|
|
||||||
lastFailures: failedHomeToForeignMessages.slice(0, 5)
|
|
||||||
},
|
|
||||||
foreignToHome: {
|
|
||||||
total: failedForeignToHomeMessages.length,
|
|
||||||
stats: countFailures(failedForeignToHomeMessages, homeBlockNumber),
|
|
||||||
lastFailures: failedForeignToHomeMessages.slice(0, 5)
|
|
||||||
},
|
|
||||||
lastChecked: Math.floor(Date.now() / 1000)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = main
|
|
||||||
@@ -1,148 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -10,6 +10,5 @@ services:
|
|||||||
- NODE_ENV=production
|
- NODE_ENV=production
|
||||||
volumes:
|
volumes:
|
||||||
- ./responses:/mono/monitor/responses
|
- ./responses:/mono/monitor/responses
|
||||||
- ./cache:/mono/monitor/cache
|
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
entrypoint: "yarn start"
|
entrypoint: "yarn start"
|
||||||
|
|||||||
@@ -1,27 +1,16 @@
|
|||||||
require('dotenv').config()
|
require('dotenv').config()
|
||||||
const {
|
const eventsInfo = require('./utils/events')
|
||||||
processedMsgNotDelivered,
|
const { processedMsgNotDelivered, deliveredMsgNotProcessed, eventWithoutReference } = require('./utils/message')
|
||||||
deliveredMsgNotProcessed,
|
|
||||||
eventWithoutReference,
|
|
||||||
unclaimedHomeToForeignRequests
|
|
||||||
} = require('./utils/message')
|
|
||||||
const { getHomeTxSender } = require('./utils/web3Cache')
|
|
||||||
const { BRIDGE_MODES } = require('../commons')
|
const { BRIDGE_MODES } = require('../commons')
|
||||||
|
|
||||||
const {
|
async function main() {
|
||||||
MONITOR_HOME_TO_FOREIGN_ALLOWANCE_LIST,
|
|
||||||
MONITOR_HOME_TO_FOREIGN_BLOCK_LIST,
|
|
||||||
MONITOR_HOME_TO_FOREIGN_CHECK_SENDER
|
|
||||||
} = process.env
|
|
||||||
|
|
||||||
async function main(eventsInfo) {
|
|
||||||
const {
|
const {
|
||||||
homeToForeignRequests,
|
homeToForeignRequests,
|
||||||
homeToForeignConfirmations,
|
homeToForeignConfirmations,
|
||||||
foreignToHomeConfirmations,
|
foreignToHomeConfirmations,
|
||||||
foreignToHomeRequests,
|
foreignToHomeRequests,
|
||||||
bridgeMode
|
bridgeMode
|
||||||
} = eventsInfo
|
} = await eventsInfo()
|
||||||
|
|
||||||
if (bridgeMode === BRIDGE_MODES.ARBITRARY_MESSAGE) {
|
if (bridgeMode === BRIDGE_MODES.ARBITRARY_MESSAGE) {
|
||||||
return {
|
return {
|
||||||
@@ -44,30 +33,17 @@ async function main(eventsInfo) {
|
|||||||
lastChecked: Math.floor(Date.now() / 1000)
|
lastChecked: Math.floor(Date.now() / 1000)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let onlyInHomeDeposits = homeToForeignRequests.filter(eventWithoutReference(homeToForeignConfirmations))
|
const onlyInHomeDeposits = homeToForeignRequests.filter(eventWithoutReference(homeToForeignConfirmations))
|
||||||
const onlyInForeignDeposits = homeToForeignConfirmations.filter(eventWithoutReference(homeToForeignRequests))
|
const onlyInForeignDeposits = homeToForeignConfirmations.filter(eventWithoutReference(homeToForeignRequests))
|
||||||
|
|
||||||
const onlyInHomeWithdrawals = foreignToHomeConfirmations.filter(eventWithoutReference(foreignToHomeRequests))
|
const onlyInHomeWithdrawals = foreignToHomeConfirmations.filter(eventWithoutReference(foreignToHomeRequests))
|
||||||
const onlyInForeignWithdrawals = foreignToHomeRequests.filter(eventWithoutReference(foreignToHomeConfirmations))
|
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 {
|
return {
|
||||||
onlyInHomeDeposits,
|
onlyInHomeDeposits,
|
||||||
onlyInForeignDeposits,
|
onlyInForeignDeposits,
|
||||||
onlyInHomeWithdrawals,
|
onlyInHomeWithdrawals,
|
||||||
onlyInForeignWithdrawals,
|
onlyInForeignWithdrawals,
|
||||||
...unclaimedStats,
|
|
||||||
lastChecked: Math.floor(Date.now() / 1000)
|
lastChecked: Math.floor(Date.now() / 1000)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,24 @@
|
|||||||
require('dotenv').config()
|
require('dotenv').config()
|
||||||
const BN = require('bignumber.js')
|
const BN = require('bignumber.js')
|
||||||
const Web3Utils = require('web3').utils
|
const Web3 = require('web3')
|
||||||
const logger = require('./logger')('getBalances')
|
const logger = require('./logger')('getBalances')
|
||||||
const { BRIDGE_MODES } = require('../commons')
|
const { BRIDGE_MODES } = require('../commons')
|
||||||
const { web3Home, web3Foreign, getHomeBlockNumber } = require('./utils/web3')
|
|
||||||
|
const Web3Utils = Web3.utils
|
||||||
|
|
||||||
const {
|
const {
|
||||||
MONITOR_HOME_START_BLOCK,
|
COMMON_HOME_RPC_URL,
|
||||||
MONITOR_FOREIGN_START_BLOCK,
|
COMMON_FOREIGN_RPC_URL,
|
||||||
COMMON_HOME_BRIDGE_ADDRESS,
|
COMMON_HOME_BRIDGE_ADDRESS,
|
||||||
COMMON_FOREIGN_BRIDGE_ADDRESS
|
COMMON_FOREIGN_BRIDGE_ADDRESS
|
||||||
} = process.env
|
} = 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 {
|
const {
|
||||||
ERC20_ABI,
|
ERC20_ABI,
|
||||||
ERC677_ABI,
|
ERC677_ABI,
|
||||||
@@ -23,59 +30,21 @@ const {
|
|||||||
FOREIGN_NATIVE_TO_ERC_ABI
|
FOREIGN_NATIVE_TO_ERC_ABI
|
||||||
} = require('../commons')
|
} = require('../commons')
|
||||||
|
|
||||||
async function main(bridgeMode, eventsInfo) {
|
async function main(bridgeMode) {
|
||||||
const {
|
|
||||||
homeBlockNumber,
|
|
||||||
foreignBlockNumber,
|
|
||||||
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)
|
|
||||||
)
|
|
||||||
|
|
||||||
const blockRanges = {
|
|
||||||
startBlockHome: MONITOR_HOME_START_BLOCK,
|
|
||||||
endBlockHome: homeBlockNumber,
|
|
||||||
startBlockForeign: MONITOR_FOREIGN_START_BLOCK,
|
|
||||||
endBlockForeign: foreignBlockNumber
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bridgeMode === BRIDGE_MODES.ERC_TO_ERC) {
|
if (bridgeMode === BRIDGE_MODES.ERC_TO_ERC) {
|
||||||
const foreignBridge = new web3Foreign.eth.Contract(FOREIGN_ERC_TO_ERC_ABI, COMMON_FOREIGN_BRIDGE_ADDRESS)
|
const foreignBridge = new web3Foreign.eth.Contract(FOREIGN_ERC_TO_ERC_ABI, COMMON_FOREIGN_BRIDGE_ADDRESS)
|
||||||
const erc20Address = await foreignBridge.methods.erc20token().call()
|
const erc20Address = await foreignBridge.methods.erc20token().call()
|
||||||
const erc20Contract = new web3Foreign.eth.Contract(ERC20_ABI, erc20Address)
|
const erc20Contract = new web3Foreign.eth.Contract(ERC20_ABI, erc20Address)
|
||||||
logger.debug('calling erc20Contract.methods.balanceOf')
|
logger.debug('calling erc20Contract.methods.balanceOf')
|
||||||
const foreignErc20Balance = await erc20Contract.methods
|
const foreignErc20Balance = await erc20Contract.methods.balanceOf(COMMON_FOREIGN_BRIDGE_ADDRESS).call()
|
||||||
.balanceOf(COMMON_FOREIGN_BRIDGE_ADDRESS)
|
|
||||||
.call({}, foreignDelayedBlockNumber)
|
|
||||||
const homeBridge = new web3Home.eth.Contract(HOME_ERC_TO_ERC_ABI, COMMON_HOME_BRIDGE_ADDRESS)
|
const homeBridge = new web3Home.eth.Contract(HOME_ERC_TO_ERC_ABI, COMMON_HOME_BRIDGE_ADDRESS)
|
||||||
logger.debug('calling homeBridge.methods.erc677token')
|
logger.debug('calling homeBridge.methods.erc677token')
|
||||||
const tokenAddress = await homeBridge.methods.erc677token().call()
|
const tokenAddress = await homeBridge.methods.erc677token().call()
|
||||||
const tokenContract = new web3Home.eth.Contract(ERC677_ABI, tokenAddress)
|
const tokenContract = new web3Home.eth.Contract(ERC677_ABI, tokenAddress)
|
||||||
logger.debug('calling tokenContract.methods.totalSupply()')
|
logger.debug('calling tokenContract.methods.totalSupply()')
|
||||||
const totalSupply = await tokenContract.methods.totalSupply().call({}, homeDelayedBlockNumber)
|
const totalSupply = await tokenContract.methods.totalSupply().call()
|
||||||
const foreignBalanceBN = new BN(foreignErc20Balance).plus(lateForeignConfirmationsTotalValue)
|
const foreignBalanceBN = new BN(foreignErc20Balance)
|
||||||
const foreignTotalSupplyBN = new BN(totalSupply).plus(lateHomeConfirmationsTotalValue)
|
const foreignTotalSupplyBN = new BN(totalSupply)
|
||||||
const diff = foreignBalanceBN.minus(foreignTotalSupplyBN).toString(10)
|
const diff = foreignBalanceBN.minus(foreignTotalSupplyBN).toString(10)
|
||||||
logger.debug('Done')
|
logger.debug('Done')
|
||||||
return {
|
return {
|
||||||
@@ -86,19 +55,18 @@ async function main(bridgeMode, eventsInfo) {
|
|||||||
erc20Balance: Web3Utils.fromWei(foreignErc20Balance)
|
erc20Balance: Web3Utils.fromWei(foreignErc20Balance)
|
||||||
},
|
},
|
||||||
balanceDiff: Number(Web3Utils.fromWei(diff)),
|
balanceDiff: Number(Web3Utils.fromWei(diff)),
|
||||||
...blockRanges,
|
|
||||||
lastChecked: Math.floor(Date.now() / 1000)
|
lastChecked: Math.floor(Date.now() / 1000)
|
||||||
}
|
}
|
||||||
} else if (bridgeMode === BRIDGE_MODES.NATIVE_TO_ERC || bridgeMode === BRIDGE_MODES.NATIVE_TO_ERC_V1) {
|
} else if (bridgeMode === BRIDGE_MODES.NATIVE_TO_ERC || bridgeMode === BRIDGE_MODES.NATIVE_TO_ERC_V1) {
|
||||||
logger.debug('calling web3Home.eth.getBalance')
|
logger.debug('calling web3Home.eth.getBalance')
|
||||||
const foreignBridge = new web3Foreign.eth.Contract(FOREIGN_NATIVE_TO_ERC_ABI, COMMON_FOREIGN_BRIDGE_ADDRESS)
|
const foreignBridge = new web3Foreign.eth.Contract(FOREIGN_NATIVE_TO_ERC_ABI, COMMON_FOREIGN_BRIDGE_ADDRESS)
|
||||||
const erc20Address = await foreignBridge.methods.erc677token().call()
|
const erc20Address = await foreignBridge.methods.erc677token().call()
|
||||||
const homeBalance = await web3Home.eth.getBalance(COMMON_HOME_BRIDGE_ADDRESS, homeDelayedBlockNumber)
|
const homeBalance = await web3Home.eth.getBalance(COMMON_HOME_BRIDGE_ADDRESS)
|
||||||
const tokenContract = new web3Foreign.eth.Contract(ERC20_ABI, erc20Address)
|
const tokenContract = new web3Foreign.eth.Contract(ERC20_ABI, erc20Address)
|
||||||
logger.debug('calling tokenContract.methods.totalSupply()')
|
logger.debug('calling tokenContract.methods.totalSupply()')
|
||||||
const totalSupply = await tokenContract.methods.totalSupply().call({}, foreignDelayedBlockNumber)
|
const totalSupply = await tokenContract.methods.totalSupply().call()
|
||||||
const homeBalanceBN = new BN(homeBalance).plus(lateHomeConfirmationsTotalValue)
|
const homeBalanceBN = new BN(homeBalance)
|
||||||
const foreignTotalSupplyBN = new BN(totalSupply).plus(lateForeignConfirmationsTotalValue)
|
const foreignTotalSupplyBN = new BN(totalSupply)
|
||||||
const diff = homeBalanceBN.minus(foreignTotalSupplyBN).toString(10)
|
const diff = homeBalanceBN.minus(foreignTotalSupplyBN).toString(10)
|
||||||
logger.debug('Done')
|
logger.debug('Done')
|
||||||
return {
|
return {
|
||||||
@@ -109,7 +77,6 @@ async function main(bridgeMode, eventsInfo) {
|
|||||||
totalSupply: Web3Utils.fromWei(totalSupply)
|
totalSupply: Web3Utils.fromWei(totalSupply)
|
||||||
},
|
},
|
||||||
balanceDiff: Number(Web3Utils.fromWei(diff)),
|
balanceDiff: Number(Web3Utils.fromWei(diff)),
|
||||||
...blockRanges,
|
|
||||||
lastChecked: Math.floor(Date.now() / 1000)
|
lastChecked: Math.floor(Date.now() / 1000)
|
||||||
}
|
}
|
||||||
} else if (bridgeMode === BRIDGE_MODES.ERC_TO_NATIVE) {
|
} else if (bridgeMode === BRIDGE_MODES.ERC_TO_NATIVE) {
|
||||||
@@ -136,25 +103,21 @@ async function main(bridgeMode, eventsInfo) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logger.debug('calling erc20Contract.methods.balanceOf')
|
logger.debug('calling erc20Contract.methods.balanceOf')
|
||||||
const foreignErc20Balance = await erc20Contract.methods
|
const foreignErc20Balance = await erc20Contract.methods.balanceOf(COMMON_FOREIGN_BRIDGE_ADDRESS).call()
|
||||||
.balanceOf(COMMON_FOREIGN_BRIDGE_ADDRESS)
|
|
||||||
.call({}, foreignDelayedBlockNumber)
|
|
||||||
|
|
||||||
const homeBridge = new web3Home.eth.Contract(HOME_ERC_TO_NATIVE_ABI, COMMON_HOME_BRIDGE_ADDRESS)
|
const homeBridge = new web3Home.eth.Contract(HOME_ERC_TO_NATIVE_ABI, COMMON_HOME_BRIDGE_ADDRESS)
|
||||||
logger.debug('calling homeBridge.methods.blockRewardContract')
|
logger.debug('calling homeBridge.methods.blockRewardContract')
|
||||||
const blockRewardAddress = await homeBridge.methods.blockRewardContract().call()
|
const blockRewardAddress = await homeBridge.methods.blockRewardContract().call()
|
||||||
const blockRewardContract = new web3Home.eth.Contract(BLOCK_REWARD_ABI, blockRewardAddress)
|
const blockRewardContract = new web3Home.eth.Contract(BLOCK_REWARD_ABI, blockRewardAddress)
|
||||||
const homeBlockNumber = await getHomeBlockNumber()
|
|
||||||
logger.debug('calling blockReward.methods.mintedTotally')
|
logger.debug('calling blockReward.methods.mintedTotally')
|
||||||
const mintedCoins = await blockRewardContract.methods
|
const mintedCoins = await blockRewardContract.methods.mintedTotallyByBridge(COMMON_HOME_BRIDGE_ADDRESS).call()
|
||||||
.mintedTotallyByBridge(COMMON_HOME_BRIDGE_ADDRESS)
|
|
||||||
.call({}, homeBlockNumber)
|
|
||||||
logger.debug('calling homeBridge.methods.totalBurntCoins')
|
logger.debug('calling homeBridge.methods.totalBurntCoins')
|
||||||
const burntCoins = await homeBridge.methods.totalBurntCoins().call({}, homeDelayedBlockNumber)
|
const burntCoins = await homeBridge.methods.totalBurntCoins().call()
|
||||||
|
|
||||||
const mintedCoinsBN = new BN(mintedCoins)
|
const mintedCoinsBN = new BN(mintedCoins)
|
||||||
const burntCoinsBN = new BN(burntCoins)
|
const burntCoinsBN = new BN(burntCoins)
|
||||||
const totalSupplyBN = mintedCoinsBN.minus(burntCoinsBN)
|
const totalSupplyBN = mintedCoinsBN.minus(burntCoinsBN)
|
||||||
const foreignErc20BalanceBN = new BN(foreignErc20Balance).plus(lateForeignConfirmationsTotalValue)
|
const foreignErc20BalanceBN = new BN(foreignErc20Balance)
|
||||||
const investedAmountInDaiBN = new BN(investedAmountInDai)
|
const investedAmountInDaiBN = new BN(investedAmountInDai)
|
||||||
const bridgeDsrBalanceBN = new BN(bridgeDsrBalance)
|
const bridgeDsrBalanceBN = new BN(bridgeDsrBalance)
|
||||||
|
|
||||||
@@ -179,14 +142,12 @@ async function main(bridgeMode, eventsInfo) {
|
|||||||
},
|
},
|
||||||
foreign,
|
foreign,
|
||||||
balanceDiff: Number(Web3Utils.fromWei(diff)),
|
balanceDiff: Number(Web3Utils.fromWei(diff)),
|
||||||
...blockRanges,
|
|
||||||
lastChecked: Math.floor(Date.now() / 1000)
|
lastChecked: Math.floor(Date.now() / 1000)
|
||||||
}
|
}
|
||||||
} else if (bridgeMode === BRIDGE_MODES.ARBITRARY_MESSAGE) {
|
} else if (bridgeMode === BRIDGE_MODES.ARBITRARY_MESSAGE) {
|
||||||
return {
|
return {
|
||||||
home: {},
|
home: {},
|
||||||
foreign: {},
|
foreign: {},
|
||||||
...blockRanges,
|
|
||||||
lastChecked: Math.floor(Date.now() / 1000)
|
lastChecked: Math.floor(Date.now() / 1000)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,36 +1,18 @@
|
|||||||
require('dotenv').config()
|
require('dotenv').config()
|
||||||
const BN = require('bignumber.js')
|
const eventsInfo = require('./utils/events')
|
||||||
const Web3Utils = require('web3').utils
|
|
||||||
const {
|
|
||||||
eventWithoutReference,
|
|
||||||
deliveredMsgNotProcessed,
|
|
||||||
unclaimedHomeToForeignRequests,
|
|
||||||
manuallyProcessedAMBHomeToForeignRequests
|
|
||||||
} = require('./utils/message')
|
|
||||||
const { BRIDGE_MODES } = require('../commons')
|
const { BRIDGE_MODES } = require('../commons')
|
||||||
const { getHomeTxSender } = require('./utils/web3Cache')
|
|
||||||
|
|
||||||
const {
|
async function main(bridgeMode) {
|
||||||
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 {
|
const {
|
||||||
homeToForeignConfirmations,
|
homeToForeignConfirmations,
|
||||||
homeToForeignRequests,
|
homeToForeignRequests,
|
||||||
foreignToHomeConfirmations,
|
foreignToHomeConfirmations,
|
||||||
foreignToHomeRequests
|
foreignToHomeRequests
|
||||||
} = eventsInfo
|
} = await eventsInfo(bridgeMode)
|
||||||
|
|
||||||
if (bridgeMode === BRIDGE_MODES.ARBITRARY_MESSAGE) {
|
if (bridgeMode === BRIDGE_MODES.ARBITRARY_MESSAGE) {
|
||||||
const onlyInHomeRequests = homeToForeignRequests.filter(deliveredMsgNotProcessed(homeToForeignConfirmations))
|
|
||||||
const manuallyProcessedRequests = onlyInHomeRequests.filter(manuallyProcessedAMBHomeToForeignRequests())
|
|
||||||
return {
|
return {
|
||||||
fromHomeToForeignDiff:
|
fromHomeToForeignDiff: homeToForeignRequests.length - homeToForeignConfirmations.length,
|
||||||
homeToForeignRequests.length - homeToForeignConfirmations.length - manuallyProcessedRequests.length,
|
|
||||||
fromHomeToForeignPBUDiff: manuallyProcessedRequests.length,
|
|
||||||
fromForeignToHomeDiff: foreignToHomeConfirmations.length - foreignToHomeRequests.length,
|
fromForeignToHomeDiff: foreignToHomeConfirmations.length - foreignToHomeRequests.length,
|
||||||
home: {
|
home: {
|
||||||
toForeign: homeToForeignRequests.length,
|
toForeign: homeToForeignRequests.length,
|
||||||
@@ -42,26 +24,9 @@ async function main(bridgeMode, eventsInfo) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const stats = {
|
|
||||||
depositsDiff: homeToForeignRequests.length - homeToForeignConfirmations.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 {
|
return {
|
||||||
...stats,
|
depositsDiff: homeToForeignRequests.length - homeToForeignConfirmations.length,
|
||||||
|
withdrawalDiff: foreignToHomeConfirmations.length - foreignToHomeRequests.length,
|
||||||
home: {
|
home: {
|
||||||
deposits: homeToForeignRequests.length,
|
deposits: homeToForeignRequests.length,
|
||||||
withdrawals: foreignToHomeConfirmations.length
|
withdrawals: foreignToHomeConfirmations.length
|
||||||
|
|||||||
@@ -1,20 +1,16 @@
|
|||||||
require('dotenv').config()
|
require('dotenv').config()
|
||||||
const express = require('express')
|
const express = require('express')
|
||||||
const cors = require('cors')
|
|
||||||
const { readFile } = require('./utils/file')
|
const { readFile } = require('./utils/file')
|
||||||
|
|
||||||
const app = express()
|
const app = express()
|
||||||
const bridgeRouter = express.Router({ mergeParams: true })
|
const bridgeRouter = express.Router({ mergeParams: true })
|
||||||
|
|
||||||
app.use(cors())
|
|
||||||
|
|
||||||
app.get('/favicon.ico', (req, res) => res.sendStatus(204))
|
app.get('/favicon.ico', (req, res) => res.sendStatus(204))
|
||||||
app.use('/:bridgeName', bridgeRouter)
|
app.use('/:bridgeName', bridgeRouter)
|
||||||
|
|
||||||
bridgeRouter.get('/:file(validators|eventsStats|alerts|mediators|stuckTransfers|failures)?', (req, res, next) => {
|
bridgeRouter.get('/', async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
const { bridgeName, file } = req.params
|
const results = await readFile(`./responses/${req.params.bridgeName}/getBalances.json`)
|
||||||
const results = readFile(`./responses/${bridgeName}/${file || 'getBalances'}.json`)
|
|
||||||
res.json(results)
|
res.json(results)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// this will eventually be handled by your error handling middleware
|
// this will eventually be handled by your error handling middleware
|
||||||
@@ -22,11 +18,39 @@ bridgeRouter.get('/:file(validators|eventsStats|alerts|mediators|stuckTransfers|
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
bridgeRouter.get('/metrics', (req, res, next) => {
|
bridgeRouter.get('/validators', async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
const { bridgeName } = req.params
|
const results = await readFile(`./responses/${req.params.bridgeName}/validators.json`)
|
||||||
const metrics = readFile(`./responses/${bridgeName}/metrics.txt`, false)
|
res.json(results)
|
||||||
res.type('text').send(metrics)
|
} catch (e) {
|
||||||
|
// this will eventually be handled by your error handling middleware
|
||||||
|
next(e)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
bridgeRouter.get('/eventsStats', async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const results = await readFile(`./responses/${req.params.bridgeName}/eventsStats.json`)
|
||||||
|
res.json(results)
|
||||||
|
} catch (e) {
|
||||||
|
// this will eventually be handled by your error handling middleware
|
||||||
|
next(e)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
bridgeRouter.get('/alerts', async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const results = await readFile(`./responses/${req.params.bridgeName}/alerts.json`)
|
||||||
|
res.json(results)
|
||||||
|
} catch (e) {
|
||||||
|
next(e)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
bridgeRouter.get('/stuckTransfers', async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const results = await readFile(`./responses/${req.params.bridgeName}/stuckTransfers.json`)
|
||||||
|
res.json(results)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
next(e)
|
next(e)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
require('dotenv').config()
|
|
||||||
const logger = require('./logger')('metricsWorker')
|
|
||||||
const { writeFile, createDir } = require('./utils/file')
|
|
||||||
const getPrometheusMetrics = require('./prometheusMetrics')
|
|
||||||
|
|
||||||
const { MONITOR_BRIDGE_NAME } = process.env
|
|
||||||
|
|
||||||
async function metricsWorker() {
|
|
||||||
try {
|
|
||||||
createDir(`/responses/${MONITOR_BRIDGE_NAME}`)
|
|
||||||
logger.debug('calling getPrometheusMetrics()')
|
|
||||||
const metrics = await getPrometheusMetrics(MONITOR_BRIDGE_NAME)
|
|
||||||
if (!metrics) throw new Error('metrics is empty: ' + JSON.stringify(metrics))
|
|
||||||
writeFile(`/responses/${MONITOR_BRIDGE_NAME}/metrics.txt`, metrics, { stringify: false })
|
|
||||||
logger.debug('Done')
|
|
||||||
} catch (e) {
|
|
||||||
logger.error(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
metricsWorker()
|
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"check-all": "timeout -s 9 5m node checkWorker.js && timeout -s 9 5m node checkWorker2.js && timeout -s 9 5m node checkWorker3.js && timeout -s 9 10s node metricsWorker.js",
|
"check-all": "timeout -s 9 5m node checkWorker.js && timeout -s 9 5m node checkWorker2.js && timeout -s 9 5m node checkWorker3.js",
|
||||||
"start": "node index.js",
|
"start": "node index.js",
|
||||||
"check-and-start": "yarn check-all && yarn start",
|
"check-and-start": "yarn check-all && yarn start",
|
||||||
"lint": "eslint . --ignore-path ../.eslintignore",
|
"lint": "eslint . --ignore-path ../.eslintignore",
|
||||||
@@ -14,12 +14,11 @@
|
|||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bignumber.js": "^9.0.1",
|
"bignumber.js": "^6.0.0",
|
||||||
"cors": "^2.8.5",
|
|
||||||
"dotenv": "^5.0.1",
|
"dotenv": "^5.0.1",
|
||||||
"express": "^4.16.3",
|
"express": "^4.16.3",
|
||||||
"node-fetch": "^2.1.2",
|
"node-fetch": "^2.1.2",
|
||||||
"web3": "^1.3.0"
|
"web3": "1.0.0-beta.34"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 10.18"
|
"node": ">= 10.18"
|
||||||
|
|||||||
@@ -1,137 +0,0 @@
|
|||||||
require('dotenv').config()
|
|
||||||
const logger = require('./logger')('getBalances')
|
|
||||||
const { readFile } = require('./utils/file')
|
|
||||||
|
|
||||||
const {
|
|
||||||
MONITOR_HOME_START_BLOCK,
|
|
||||||
MONITOR_FOREIGN_START_BLOCK,
|
|
||||||
MONITOR_HOME_VALIDATORS_BALANCE_ENABLE,
|
|
||||||
MONITOR_FOREIGN_VALIDATORS_BALANCE_ENABLE
|
|
||||||
} = process.env
|
|
||||||
|
|
||||||
function BridgeConf(type, validatorsBalanceEnable, alertTargetFunc, failureDirection) {
|
|
||||||
this.type = type
|
|
||||||
this.validatorsBalanceEnable = validatorsBalanceEnable
|
|
||||||
this.alertTargetFunc = alertTargetFunc
|
|
||||||
this.failureDirection = failureDirection
|
|
||||||
}
|
|
||||||
|
|
||||||
const BRIDGE_CONFS = [
|
|
||||||
new BridgeConf('home', MONITOR_HOME_VALIDATORS_BALANCE_ENABLE, 'executeAffirmations', 'homeToForeign'),
|
|
||||||
new BridgeConf('foreign', MONITOR_FOREIGN_VALIDATORS_BALANCE_ENABLE, 'executeSignatures', 'foreignToHome')
|
|
||||||
]
|
|
||||||
|
|
||||||
function hasError(obj) {
|
|
||||||
return 'error' in obj
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to collect all metrics from JSON responses and then
|
|
||||||
// discard all unsuccessfully retrieved ones
|
|
||||||
async function getPrometheusMetrics(bridgeName) {
|
|
||||||
const responsePath = jsonName => `./responses/${bridgeName}/${jsonName}.json`
|
|
||||||
|
|
||||||
const metrics = {}
|
|
||||||
|
|
||||||
// Balance metrics
|
|
||||||
const balancesFile = readFile(responsePath('getBalances'))
|
|
||||||
|
|
||||||
if (!hasError(balancesFile)) {
|
|
||||||
const { home, foreign, ...commonBalances } = balancesFile
|
|
||||||
|
|
||||||
const balanceMetrics = {
|
|
||||||
// ERC_TO_ERC or ERC_TO_NATIVE mode
|
|
||||||
balances_home_value: home.totalSupply,
|
|
||||||
balances_home_txs_deposit: home.deposits,
|
|
||||||
balances_home_txs_withdrawal: home.withdrawals,
|
|
||||||
balances_foreign_value: foreign.erc20Balance,
|
|
||||||
balances_foreign_txs_deposit: foreign.deposits,
|
|
||||||
balances_foreign_txs_withdrawal: foreign.withdrawals,
|
|
||||||
|
|
||||||
// Not ARBITRARY_MESSAGE mode
|
|
||||||
balances_diff_value: commonBalances.balanceDiff,
|
|
||||||
balances_diff_deposit: commonBalances.depositsDiff,
|
|
||||||
balances_diff_withdrawal: commonBalances.withdrawalDiff,
|
|
||||||
|
|
||||||
// MONITOR_HOME_TO_FOREIGN_ALLOWANCE_LIST or MONITOR_HOME_TO_FOREIGN_BLOCK_LIST is set
|
|
||||||
balances_unclaimed_txs: commonBalances.unclaimedDiff,
|
|
||||||
balances_unclaimed_value: commonBalances.unclaimedBalance,
|
|
||||||
|
|
||||||
// ARBITRARY_MESSAGE mode
|
|
||||||
txs_home_out: home.toForeign,
|
|
||||||
txs_home_in: home.fromForeign,
|
|
||||||
txs_foreign_out: foreign.toHome,
|
|
||||||
txs_foreign_in: foreign.fromHome,
|
|
||||||
txs_diff_home_out_oracles: commonBalances.fromHomeToForeignDiff,
|
|
||||||
txs_diff_home_out_users: commonBalances.fromHomeToForeignPBUDiff,
|
|
||||||
txs_diff_foreign_out: commonBalances.fromForeignToHomeDiff
|
|
||||||
}
|
|
||||||
|
|
||||||
const blockRanges = {
|
|
||||||
state_startblock_home: commonBalances.startBlockHome || MONITOR_HOME_START_BLOCK,
|
|
||||||
state_startblock_foreign: commonBalances.startBlockForeign || MONITOR_FOREIGN_START_BLOCK,
|
|
||||||
state_endblock_home: commonBalances.endBlockHome,
|
|
||||||
state_endblock_foreign: commonBalances.endBlockForeign
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.assign(metrics, blockRanges, balanceMetrics)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validator metrics
|
|
||||||
const validatorsFile = readFile(responsePath('validators'))
|
|
||||||
|
|
||||||
if (!hasError(validatorsFile)) {
|
|
||||||
for (const bridge of BRIDGE_CONFS) {
|
|
||||||
const allValidators = validatorsFile[bridge.type].validators
|
|
||||||
const validatorAddressesWithBalanceCheck =
|
|
||||||
typeof bridge.validatorsBalanceEnable === 'string'
|
|
||||||
? bridge.validatorsBalanceEnable.split(' ')
|
|
||||||
: Object.keys(allValidators)
|
|
||||||
|
|
||||||
validatorAddressesWithBalanceCheck.forEach((addr, ind) => {
|
|
||||||
if (addr in allValidators) {
|
|
||||||
metrics[`validators_balances_${bridge.type}${ind}{address="${addr}"}`] = allValidators[addr].balance
|
|
||||||
} else {
|
|
||||||
logger.debug(`Nonexistent validator address ${addr}`)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Alert metrics
|
|
||||||
const alertsFile = readFile(responsePath('alerts'))
|
|
||||||
|
|
||||||
if (!hasError(alertsFile)) {
|
|
||||||
for (const bridge of BRIDGE_CONFS) {
|
|
||||||
Object.entries(alertsFile[bridge.alertTargetFunc].misbehavior).forEach(([period, val]) => {
|
|
||||||
metrics[`misbehavior_${bridge.type}_${period}`] = val
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Failure metrics
|
|
||||||
const failureFile = readFile(responsePath('failures'))
|
|
||||||
|
|
||||||
if (!hasError(failureFile)) {
|
|
||||||
for (const bridge of BRIDGE_CONFS) {
|
|
||||||
const dir = bridge.failureDirection
|
|
||||||
const failures = failureFile[dir]
|
|
||||||
metrics[`failures_${dir}_total`] = failures.total
|
|
||||||
Object.entries(failures.stats).forEach(([period, count]) => {
|
|
||||||
metrics[`failures_${dir}_${period}`] = count
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pack metrcis into a plain text
|
|
||||||
return Object.entries(metrics).reduceRight(
|
|
||||||
// Prometheus supports `Nan` and possibly signed `Infinity`
|
|
||||||
// in case cast to `Number` fails
|
|
||||||
(acc, [key, val]) => {
|
|
||||||
if (typeof val === 'undefined') return acc
|
|
||||||
else return `${key} ${Number(val)}\n${acc}`
|
|
||||||
},
|
|
||||||
''
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = getPrometheusMetrics
|
|
||||||
@@ -2,10 +2,6 @@
|
|||||||
|
|
||||||
CONFIGDIR="configs"
|
CONFIGDIR="configs"
|
||||||
RESPONSESDIR="responses"
|
RESPONSESDIR="responses"
|
||||||
ACLDIR="access-lists"
|
|
||||||
ALLOWANCEFILE="allowance_list.txt"
|
|
||||||
BLOCKFILE="block_list.txt"
|
|
||||||
CACHEDIR="cache"
|
|
||||||
IMAGETAG="latest"
|
IMAGETAG="latest"
|
||||||
|
|
||||||
cd $(dirname $0)/..
|
cd $(dirname $0)/..
|
||||||
@@ -30,18 +26,10 @@ if /usr/local/bin/docker-compose ps | grep -q -i 'monitor'; then
|
|||||||
fi
|
fi
|
||||||
done
|
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"
|
containername=${bridgename}"-checker"
|
||||||
docker container stats --no-stream ${containername} 2>/dev/null 1>&2
|
docker container stats --no-stream ${containername} 2>/dev/null 1>&2
|
||||||
if [ ! "$?" == "0" ]; then
|
if [ ! "$?" == "0" ]; then
|
||||||
mkdir -p "$(pwd)/$CACHEDIR/$bridgename"
|
|
||||||
docker run --rm --env-file $file -v $(pwd)/${RESPONSESDIR}:/mono/monitor/responses \
|
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} \
|
--name ${containername} poanetwork/tokenbridge-monitor:${IMAGETAG} \
|
||||||
/bin/bash -c 'yarn check-all'
|
/bin/bash -c 'yarn check-all'
|
||||||
shasum -a 256 -s -c ${checksumfile}
|
shasum -a 256 -s -c ${checksumfile}
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
require('dotenv').config()
|
require('dotenv').config()
|
||||||
|
const Web3 = require('web3')
|
||||||
const logger = require('./logger')('stuckTransfers.js')
|
const logger = require('./logger')('stuckTransfers.js')
|
||||||
const { FOREIGN_V1_ABI } = require('../commons/abis')
|
const { FOREIGN_V1_ABI } = require('../commons/abis')
|
||||||
const { web3Foreign, getForeignBlockNumber } = require('./utils/web3')
|
|
||||||
const { getPastEvents } = require('./utils/web3Cache')
|
|
||||||
|
|
||||||
const { COMMON_FOREIGN_BRIDGE_ADDRESS } = process.env
|
const { COMMON_FOREIGN_RPC_URL, COMMON_FOREIGN_BRIDGE_ADDRESS } = process.env
|
||||||
const MONITOR_FOREIGN_START_BLOCK = Number(process.env.MONITOR_FOREIGN_START_BLOCK) || 0
|
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 = [
|
const ABITransferWithoutData = [
|
||||||
{
|
{
|
||||||
anonymous: false,
|
anonymous: false,
|
||||||
@@ -62,39 +64,38 @@ const ABIWithData = [
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
function transferWithoutCallback(transfersNormal) {
|
function compareTransfers(transfersNormal) {
|
||||||
const txHashes = new Set()
|
return withData => {
|
||||||
transfersNormal.forEach(transfer => txHashes.add(transfer.transactionHash))
|
return (
|
||||||
return withData => !txHashes.has(withData.transactionHash)
|
transfersNormal.filter(normal => {
|
||||||
|
return normal.transactionHash === withData.transactionHash
|
||||||
|
}).length === 0
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
const foreignBridge = new web3Foreign.eth.Contract(FOREIGN_V1_ABI, COMMON_FOREIGN_BRIDGE_ADDRESS)
|
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 erc20Address = await foreignBridge.methods.erc677token().call()
|
||||||
const tokenContract = new web3Foreign.eth.Contract(ABITransferWithoutData, erc20Address)
|
const tokenContract = new web3Foreign.eth.Contract(ABITransferWithoutData, erc20Address)
|
||||||
const tokenContractWithData = new web3Foreign.eth.Contract(ABIWithData, 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')
|
logger.debug('calling tokenContract.getPastEvents Transfer')
|
||||||
const options = {
|
const transfersNormal = await tokenContract.getPastEvents('Transfer', {
|
||||||
event: 'Transfer',
|
|
||||||
options: {
|
|
||||||
filter: {
|
filter: {
|
||||||
to: COMMON_FOREIGN_BRIDGE_ADDRESS
|
to: COMMON_FOREIGN_BRIDGE_ADDRESS
|
||||||
}
|
|
||||||
},
|
},
|
||||||
fromBlock: MONITOR_FOREIGN_START_BLOCK,
|
fromBlock: MONITOR_FOREIGN_START_BLOCK,
|
||||||
toBlock: foreignBlockNumber,
|
toBlock: 'latest'
|
||||||
chain: 'foreign',
|
})
|
||||||
safeToBlock: foreignDelayedBlockNumber
|
|
||||||
}
|
|
||||||
const transfersNormal = await getPastEvents(tokenContract, options)
|
|
||||||
logger.debug('calling tokenContractWithData.getPastEvents Transfer')
|
logger.debug('calling tokenContractWithData.getPastEvents Transfer')
|
||||||
const transfersWithData = await getPastEvents(tokenContractWithData, options)
|
const transfersWithData = await tokenContractWithData.getPastEvents('Transfer', {
|
||||||
const stuckTransfers = transfersNormal.filter(transferWithoutCallback(transfersWithData))
|
filter: {
|
||||||
|
to: COMMON_FOREIGN_BRIDGE_ADDRESS
|
||||||
|
},
|
||||||
|
fromBlock: MONITOR_FOREIGN_START_BLOCK,
|
||||||
|
toBlock: 'latest'
|
||||||
|
})
|
||||||
|
const stuckTransfers = transfersNormal.filter(compareTransfers(transfersWithData))
|
||||||
logger.debug('Done')
|
logger.debug('Done')
|
||||||
return {
|
return {
|
||||||
stuckTransfers,
|
stuckTransfers,
|
||||||
|
|||||||
11
monitor/utils/contract.js
Normal file
11
monitor/utils/contract.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
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,4 +1,6 @@
|
|||||||
require('dotenv').config()
|
require('dotenv').config()
|
||||||
|
const Web3 = require('web3')
|
||||||
|
const { toBN } = require('web3').utils
|
||||||
const logger = require('../logger')('eventsUtils')
|
const logger = require('../logger')('eventsUtils')
|
||||||
const {
|
const {
|
||||||
BRIDGE_MODES,
|
BRIDGE_MODES,
|
||||||
@@ -9,6 +11,7 @@ const {
|
|||||||
ERC20_ABI,
|
ERC20_ABI,
|
||||||
ERC677_BRIDGE_TOKEN_ABI,
|
ERC677_BRIDGE_TOKEN_ABI,
|
||||||
getTokenType,
|
getTokenType,
|
||||||
|
getPastEvents,
|
||||||
ZERO_ADDRESS,
|
ZERO_ADDRESS,
|
||||||
OLD_AMB_USER_REQUEST_FOR_SIGNATURE_ABI,
|
OLD_AMB_USER_REQUEST_FOR_SIGNATURE_ABI,
|
||||||
OLD_AMB_USER_REQUEST_FOR_AFFIRMATION_ABI
|
OLD_AMB_USER_REQUEST_FOR_AFFIRMATION_ABI
|
||||||
@@ -16,12 +19,24 @@ const {
|
|||||||
const { normalizeEventInformation } = require('./message')
|
const { normalizeEventInformation } = require('./message')
|
||||||
const { filterTransferBeforeES } = require('./tokenUtils')
|
const { filterTransferBeforeES } = require('./tokenUtils')
|
||||||
const { writeFile, readCacheFile } = require('./file')
|
const { writeFile, readCacheFile } = require('./file')
|
||||||
const { web3Home, web3Foreign, getHomeBlockNumber, getForeignBlockNumber } = require('./web3')
|
|
||||||
const { getPastEvents } = require('./web3Cache')
|
|
||||||
|
|
||||||
const { COMMON_HOME_BRIDGE_ADDRESS, COMMON_FOREIGN_BRIDGE_ADDRESS, MONITOR_CACHE_EVENTS } = process.env
|
const {
|
||||||
const MONITOR_HOME_START_BLOCK = Number(process.env.MONITOR_HOME_START_BLOCK) || 0
|
COMMON_HOME_RPC_URL,
|
||||||
const MONITOR_FOREIGN_START_BLOCK = Number(process.env.MONITOR_FOREIGN_START_BLOCK) || 0
|
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 cacheFilePath = '/tmp/cachedEvents.json'
|
const cacheFilePath = '/tmp/cachedEvents.json'
|
||||||
async function main(mode) {
|
async function main(mode) {
|
||||||
@@ -58,13 +73,7 @@ async function main(mode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logger.debug('getting last block numbers')
|
logger.debug('getting last block numbers')
|
||||||
const homeBlockNumber = await getHomeBlockNumber()
|
const [homeBlockNumber, foreignBlockNumber] = await getBlockNumber(web3Home, web3Foreign)
|
||||||
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 homeToForeignRequests = []
|
||||||
let foreignToHomeRequests = []
|
let foreignToHomeRequests = []
|
||||||
let homeMigrationBlock = MONITOR_HOME_START_BLOCK
|
let homeMigrationBlock = MONITOR_HOME_START_BLOCK
|
||||||
@@ -81,24 +90,22 @@ async function main(mode) {
|
|||||||
homeToForeignRequests = (await getPastEvents(oldHomeBridge, {
|
homeToForeignRequests = (await getPastEvents(oldHomeBridge, {
|
||||||
event: 'UserRequestForSignature',
|
event: 'UserRequestForSignature',
|
||||||
fromBlock: MONITOR_HOME_START_BLOCK,
|
fromBlock: MONITOR_HOME_START_BLOCK,
|
||||||
toBlock: homeDelayedBlockNumber,
|
toBlock: homeBlockNumber
|
||||||
chain: 'home'
|
|
||||||
})).map(normalizeEvent)
|
})).map(normalizeEvent)
|
||||||
logger.debug(`found ${homeToForeignRequests.length} events`)
|
logger.debug(`found ${homeToForeignRequests.length} events`)
|
||||||
if (homeToForeignRequests.length > 0) {
|
if (homeToForeignRequests.length > 0) {
|
||||||
homeMigrationBlock = Math.max(...homeToForeignRequests.map(x => x.blockNumber))
|
homeMigrationBlock = toBN(Math.max(...homeToForeignRequests.map(x => x.blockNumber)))
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug("calling oldForeignBridge.getPastEvents('UserRequestForAffirmation(bytes)')")
|
logger.debug("calling oldForeignBridge.getPastEvents('UserRequestForAffirmation(bytes)')")
|
||||||
foreignToHomeRequests = (await getPastEvents(oldForeignBridge, {
|
foreignToHomeRequests = (await getPastEvents(oldForeignBridge, {
|
||||||
event: 'UserRequestForAffirmation',
|
event: 'UserRequestForAffirmation',
|
||||||
fromBlock: MONITOR_FOREIGN_START_BLOCK,
|
fromBlock: MONITOR_FOREIGN_START_BLOCK,
|
||||||
toBlock: foreignDelayedBlockNumber,
|
toBlock: foreignBlockNumber
|
||||||
chain: 'foreign'
|
|
||||||
})).map(normalizeEvent)
|
})).map(normalizeEvent)
|
||||||
logger.debug(`found ${foreignToHomeRequests.length} events`)
|
logger.debug(`found ${foreignToHomeRequests.length} events`)
|
||||||
if (foreignToHomeRequests.length > 0) {
|
if (foreignToHomeRequests.length > 0) {
|
||||||
foreignMigrationBlock = Math.max(...foreignToHomeRequests.map(x => x.blockNumber))
|
foreignMigrationBlock = toBN(Math.max(...foreignToHomeRequests.map(x => x.blockNumber)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,8 +113,7 @@ async function main(mode) {
|
|||||||
const homeToForeignRequestsNew = (await getPastEvents(homeBridge, {
|
const homeToForeignRequestsNew = (await getPastEvents(homeBridge, {
|
||||||
event: v1Bridge ? 'Deposit' : 'UserRequestForSignature',
|
event: v1Bridge ? 'Deposit' : 'UserRequestForSignature',
|
||||||
fromBlock: homeMigrationBlock,
|
fromBlock: homeMigrationBlock,
|
||||||
toBlock: homeDelayedBlockNumber,
|
toBlock: homeBlockNumber
|
||||||
chain: 'home'
|
|
||||||
})).map(normalizeEvent)
|
})).map(normalizeEvent)
|
||||||
homeToForeignRequests = [...homeToForeignRequests, ...homeToForeignRequestsNew]
|
homeToForeignRequests = [...homeToForeignRequests, ...homeToForeignRequestsNew]
|
||||||
|
|
||||||
@@ -115,26 +121,21 @@ async function main(mode) {
|
|||||||
const homeToForeignConfirmations = (await getPastEvents(foreignBridge, {
|
const homeToForeignConfirmations = (await getPastEvents(foreignBridge, {
|
||||||
event: v1Bridge ? 'Deposit' : 'RelayedMessage',
|
event: v1Bridge ? 'Deposit' : 'RelayedMessage',
|
||||||
fromBlock: MONITOR_FOREIGN_START_BLOCK,
|
fromBlock: MONITOR_FOREIGN_START_BLOCK,
|
||||||
toBlock: foreignBlockNumber,
|
toBlock: foreignBlockNumber
|
||||||
chain: 'foreign',
|
|
||||||
safeToBlock: foreignDelayedBlockNumber
|
|
||||||
})).map(normalizeEvent)
|
})).map(normalizeEvent)
|
||||||
|
|
||||||
logger.debug("calling homeBridge.getPastEvents('AffirmationCompleted')")
|
logger.debug("calling homeBridge.getPastEvents('AffirmationCompleted')")
|
||||||
const foreignToHomeConfirmations = (await getPastEvents(homeBridge, {
|
const foreignToHomeConfirmations = (await getPastEvents(homeBridge, {
|
||||||
event: v1Bridge ? 'Withdraw' : 'AffirmationCompleted',
|
event: v1Bridge ? 'Withdraw' : 'AffirmationCompleted',
|
||||||
fromBlock: MONITOR_HOME_START_BLOCK,
|
fromBlock: MONITOR_HOME_START_BLOCK,
|
||||||
toBlock: homeBlockNumber,
|
toBlock: homeBlockNumber
|
||||||
chain: 'home',
|
|
||||||
safeToBlock: homeDelayedBlockNumber
|
|
||||||
})).map(normalizeEvent)
|
})).map(normalizeEvent)
|
||||||
|
|
||||||
logger.debug("calling foreignBridge.getPastEvents('UserRequestForAffirmation')")
|
logger.debug("calling foreignBridge.getPastEvents('UserRequestForAffirmation')")
|
||||||
const foreignToHomeRequestsNew = (await getPastEvents(foreignBridge, {
|
const foreignToHomeRequestsNew = (await getPastEvents(foreignBridge, {
|
||||||
event: v1Bridge ? 'Withdraw' : 'UserRequestForAffirmation',
|
event: v1Bridge ? 'Withdraw' : 'UserRequestForAffirmation',
|
||||||
fromBlock: foreignMigrationBlock,
|
fromBlock: foreignMigrationBlock,
|
||||||
toBlock: foreignDelayedBlockNumber,
|
toBlock: foreignBlockNumber
|
||||||
chain: 'foreign'
|
|
||||||
})).map(normalizeEvent)
|
})).map(normalizeEvent)
|
||||||
foreignToHomeRequests = [...foreignToHomeRequests, ...foreignToHomeRequestsNew]
|
foreignToHomeRequests = [...foreignToHomeRequests, ...foreignToHomeRequestsNew]
|
||||||
|
|
||||||
@@ -143,11 +144,10 @@ async function main(mode) {
|
|||||||
let transferEvents = (await getPastEvents(erc20Contract, {
|
let transferEvents = (await getPastEvents(erc20Contract, {
|
||||||
event: 'Transfer',
|
event: 'Transfer',
|
||||||
fromBlock: MONITOR_FOREIGN_START_BLOCK,
|
fromBlock: MONITOR_FOREIGN_START_BLOCK,
|
||||||
toBlock: foreignDelayedBlockNumber,
|
toBlock: foreignBlockNumber,
|
||||||
options: {
|
options: {
|
||||||
filter: { to: COMMON_FOREIGN_BRIDGE_ADDRESS }
|
filter: { to: COMMON_FOREIGN_BRIDGE_ADDRESS }
|
||||||
},
|
}
|
||||||
chain: 'foreign'
|
|
||||||
})).map(normalizeEvent)
|
})).map(normalizeEvent)
|
||||||
|
|
||||||
let directTransfers = transferEvents
|
let directTransfers = transferEvents
|
||||||
@@ -158,9 +158,7 @@ async function main(mode) {
|
|||||||
const tokensSwappedEvents = await getPastEvents(foreignBridge, {
|
const tokensSwappedEvents = await getPastEvents(foreignBridge, {
|
||||||
event: 'TokensSwapped',
|
event: 'TokensSwapped',
|
||||||
fromBlock: MONITOR_FOREIGN_START_BLOCK,
|
fromBlock: MONITOR_FOREIGN_START_BLOCK,
|
||||||
toBlock: foreignBlockNumber,
|
toBlock: foreignBlockNumber
|
||||||
chain: 'foreign',
|
|
||||||
safeToBlock: foreignDelayedBlockNumber
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// Get token swap events emitted by foreign bridge
|
// Get token swap events emitted by foreign bridge
|
||||||
@@ -196,11 +194,10 @@ async function main(mode) {
|
|||||||
const halfDuplexTransferEvents = (await getPastEvents(halfDuplexTokenContract, {
|
const halfDuplexTransferEvents = (await getPastEvents(halfDuplexTokenContract, {
|
||||||
event: 'Transfer',
|
event: 'Transfer',
|
||||||
fromBlock: MONITOR_FOREIGN_START_BLOCK,
|
fromBlock: MONITOR_FOREIGN_START_BLOCK,
|
||||||
toBlock: foreignDelayedBlockNumber,
|
toBlock: foreignBlockNumber,
|
||||||
options: {
|
options: {
|
||||||
filter: { to: COMMON_FOREIGN_BRIDGE_ADDRESS }
|
filter: { to: COMMON_FOREIGN_BRIDGE_ADDRESS }
|
||||||
},
|
}
|
||||||
chain: 'foreign'
|
|
||||||
})).map(normalizeEvent)
|
})).map(normalizeEvent)
|
||||||
|
|
||||||
// Remove events after the ES
|
// Remove events after the ES
|
||||||
@@ -235,16 +232,12 @@ async function main(mode) {
|
|||||||
foreignToHomeConfirmations,
|
foreignToHomeConfirmations,
|
||||||
foreignToHomeRequests,
|
foreignToHomeRequests,
|
||||||
isExternalErc20,
|
isExternalErc20,
|
||||||
bridgeMode,
|
bridgeMode
|
||||||
homeBlockNumber,
|
|
||||||
foreignBlockNumber,
|
|
||||||
homeDelayedBlockNumber,
|
|
||||||
foreignDelayedBlockNumber
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MONITOR_CACHE_EVENTS === 'true') {
|
if (MONITOR_CACHE_EVENTS === 'true') {
|
||||||
logger.debug('saving obtained events into cache file')
|
logger.debug('saving obtained events into cache file')
|
||||||
writeFile(cacheFilePath, result, { useCwd: false })
|
writeFile(cacheFilePath, result, false)
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user