Compare commits
1 Commits
2.5.0
...
amb-altern
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d229840830 |
382
.circleci/config.yml
Normal file
382
.circleci/config.yml
Normal file
@@ -0,0 +1,382 @@
|
|||||||
|
version: 2.1
|
||||||
|
|
||||||
|
orbs:
|
||||||
|
tokenbridge-orb:
|
||||||
|
commands:
|
||||||
|
install-chrome:
|
||||||
|
steps:
|
||||||
|
- run:
|
||||||
|
name: Update dpkg
|
||||||
|
command: |
|
||||||
|
sudo apt-get clean
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install dpkg
|
||||||
|
- run:
|
||||||
|
name: Install Chrome
|
||||||
|
command: |
|
||||||
|
wget -O chrome.deb https://dl.google.com/linux/chrome/deb/pool/main/g/google-chrome-stable/google-chrome-stable_77.0.3865.120-1_amd64.deb
|
||||||
|
sudo dpkg -i chrome.deb
|
||||||
|
install-node:
|
||||||
|
steps:
|
||||||
|
- run:
|
||||||
|
name: Install Node
|
||||||
|
command: |
|
||||||
|
export NVM_DIR="/opt/circleci/.nvm"
|
||||||
|
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
|
||||||
|
|
||||||
|
nvm install 10.16.3 && nvm alias default 10.16.3
|
||||||
|
|
||||||
|
echo 'export NVM_DIR="/opt/circleci/.nvm"' >> $BASH_ENV
|
||||||
|
echo ' [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"' >> $BASH_ENV
|
||||||
|
install-yarn:
|
||||||
|
steps:
|
||||||
|
- run:
|
||||||
|
name: Install Yarn
|
||||||
|
command: |
|
||||||
|
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
|
||||||
|
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
|
||||||
|
sudo apt-get update && sudo apt-get -y install yarn
|
||||||
|
wait-for-oracle:
|
||||||
|
parameters:
|
||||||
|
redis-key:
|
||||||
|
type: string
|
||||||
|
steps:
|
||||||
|
- run:
|
||||||
|
name: Install redis tools
|
||||||
|
command: sudo apt-get install -y redis-tools
|
||||||
|
- run:
|
||||||
|
name: Wait for the Oracle to start
|
||||||
|
command: |
|
||||||
|
set +e
|
||||||
|
i=0
|
||||||
|
while [[ $(redis-cli GET << parameters.redis-key >> ) ]]; do
|
||||||
|
((i++))
|
||||||
|
if [ "$i" -gt 30 ]
|
||||||
|
then
|
||||||
|
exit -1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Sleeping..."
|
||||||
|
sleep 3
|
||||||
|
done
|
||||||
|
init-repo:
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
- run: git submodule update --init
|
||||||
|
executors:
|
||||||
|
docker-node:
|
||||||
|
docker:
|
||||||
|
- image: circleci/node:10.15
|
||||||
|
machine-with-dlc:
|
||||||
|
machine:
|
||||||
|
image: ubuntu-1604:202007-01
|
||||||
|
docker_layer_caching: true
|
||||||
|
classic-machine-without-dlc:
|
||||||
|
machine:
|
||||||
|
image: circleci/classic:latest
|
||||||
|
machine-without-dlc:
|
||||||
|
machine:
|
||||||
|
image: ubuntu-1604:202007-01
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
initialize:
|
||||||
|
executor: tokenbridge-orb/docker-node
|
||||||
|
steps:
|
||||||
|
- tokenbridge-orb/init-repo
|
||||||
|
- restore_cache:
|
||||||
|
name: Restore Yarn Package Cache
|
||||||
|
keys:
|
||||||
|
- yarn-{{ checksum "package.json" }}-{{ checksum "yarn.lock" }}
|
||||||
|
- run: git submodule status > submodule.status
|
||||||
|
- restore_cache:
|
||||||
|
name: Restore contracts submodule with compiled contracts
|
||||||
|
keys:
|
||||||
|
- contracts-{{ checksum "submodule.status" }}
|
||||||
|
- run: yarn install --frozen-lockfile
|
||||||
|
- save_cache:
|
||||||
|
name: Save Yarn Package Cache
|
||||||
|
key: yarn-{{ checksum "package.json" }}-{{ checksum "yarn.lock" }}
|
||||||
|
paths:
|
||||||
|
- ~/.cache/yarn
|
||||||
|
- run: touch install_deploy.log; test -d contracts/build/contracts || yarn install:deploy &> install_deploy.log
|
||||||
|
- store_artifacts:
|
||||||
|
path: install_deploy.log
|
||||||
|
- run: test -d contracts/build/contracts || yarn compile:contracts
|
||||||
|
- save_cache:
|
||||||
|
name: Save contracts submodule with compiled contracts
|
||||||
|
key: contracts-{{ checksum "submodule.status" }}
|
||||||
|
paths:
|
||||||
|
- contracts
|
||||||
|
- save_cache:
|
||||||
|
name: Save initialized project for subsequent jobs
|
||||||
|
key: initialize-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
|
paths:
|
||||||
|
- ~/project
|
||||||
|
initialize-root:
|
||||||
|
executor: tokenbridge-orb/docker-node
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
- run: sudo su - -c 'export CI=true && cd /home/circleci/project && yarn initialize && yarn test'
|
||||||
|
build:
|
||||||
|
executor: tokenbridge-orb/docker-node
|
||||||
|
steps:
|
||||||
|
- restore_cache:
|
||||||
|
key: initialize-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
|
- run: yarn run build
|
||||||
|
lint:
|
||||||
|
executor: tokenbridge-orb/docker-node
|
||||||
|
steps:
|
||||||
|
- restore_cache:
|
||||||
|
key: initialize-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
|
- run: yarn run lint
|
||||||
|
test:
|
||||||
|
executor: tokenbridge-orb/docker-node
|
||||||
|
steps:
|
||||||
|
- restore_cache:
|
||||||
|
key: initialize-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
|
- run: yarn run test
|
||||||
|
build-e2e-images:
|
||||||
|
executor: tokenbridge-orb/machine-without-dlc
|
||||||
|
steps:
|
||||||
|
- tokenbridge-orb/init-repo
|
||||||
|
- run:
|
||||||
|
command: |
|
||||||
|
docker login -u ${DOCKER_LOGIN} -p ${DOCKER_PASSWORD}
|
||||||
|
cd e2e-commons
|
||||||
|
docker-compose build oracle monitor ui alm e2e molecule_runner
|
||||||
|
docker-compose push oracle monitor ui alm e2e molecule_runner
|
||||||
|
oracle-e2e:
|
||||||
|
executor: tokenbridge-orb/machine-without-dlc
|
||||||
|
steps:
|
||||||
|
- tokenbridge-orb/init-repo
|
||||||
|
- run: ./oracle-e2e/run-tests.sh
|
||||||
|
ui-e2e:
|
||||||
|
executor: tokenbridge-orb/machine-without-dlc
|
||||||
|
steps:
|
||||||
|
- tokenbridge-orb/install-node
|
||||||
|
- tokenbridge-orb/install-yarn
|
||||||
|
- tokenbridge-orb/install-chrome
|
||||||
|
- restore_cache:
|
||||||
|
key: initialize-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
|
- run: yarn run ui-e2e
|
||||||
|
monitor-e2e:
|
||||||
|
executor: tokenbridge-orb/machine-without-dlc
|
||||||
|
steps:
|
||||||
|
- tokenbridge-orb/init-repo
|
||||||
|
- run: ./monitor-e2e/run-tests.sh
|
||||||
|
alm-e2e:
|
||||||
|
executor: tokenbridge-orb/machine-without-dlc
|
||||||
|
steps:
|
||||||
|
- tokenbridge-orb/install-node
|
||||||
|
- tokenbridge-orb/install-yarn
|
||||||
|
- restore_cache:
|
||||||
|
key: initialize-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
|
- run: yarn run alm-e2e
|
||||||
|
cover:
|
||||||
|
executor: tokenbridge-orb/docker-node
|
||||||
|
steps:
|
||||||
|
- restore_cache:
|
||||||
|
key: initialize-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
|
- run: yarn workspace ui run coverage
|
||||||
|
- run: yarn workspace ui run coveralls
|
||||||
|
deployment-oracle:
|
||||||
|
executor: tokenbridge-orb/machine-without-dlc
|
||||||
|
steps:
|
||||||
|
- tokenbridge-orb/init-repo
|
||||||
|
- run:
|
||||||
|
name: Run the scenario
|
||||||
|
command: deployment-e2e/molecule.sh oracle
|
||||||
|
no_output_timeout: 40m
|
||||||
|
deployment-ui:
|
||||||
|
executor: tokenbridge-orb/machine-without-dlc
|
||||||
|
steps:
|
||||||
|
- tokenbridge-orb/init-repo
|
||||||
|
- run:
|
||||||
|
name: Run the scenario
|
||||||
|
command: deployment-e2e/molecule.sh ui
|
||||||
|
no_output_timeout: 40m
|
||||||
|
deployment-monitor:
|
||||||
|
executor: tokenbridge-orb/machine-without-dlc
|
||||||
|
steps:
|
||||||
|
- tokenbridge-orb/init-repo
|
||||||
|
- run:
|
||||||
|
name: Run the scenario
|
||||||
|
command: deployment-e2e/molecule.sh monitor
|
||||||
|
no_output_timeout: 40m
|
||||||
|
deployment-repo:
|
||||||
|
executor: tokenbridge-orb/machine-without-dlc
|
||||||
|
steps:
|
||||||
|
- tokenbridge-orb/init-repo
|
||||||
|
- run:
|
||||||
|
name: Run the scenario
|
||||||
|
command: deployment-e2e/molecule.sh repo
|
||||||
|
no_output_timeout: 40m
|
||||||
|
deployment-multiple:
|
||||||
|
executor: tokenbridge-orb/machine-without-dlc
|
||||||
|
steps:
|
||||||
|
- tokenbridge-orb/init-repo
|
||||||
|
- run:
|
||||||
|
name: Run the scenario
|
||||||
|
command: deployment-e2e/molecule.sh multiple
|
||||||
|
no_output_timeout: 40m
|
||||||
|
ultimate:
|
||||||
|
executor: tokenbridge-orb/classic-machine-without-dlc
|
||||||
|
parameters:
|
||||||
|
scenario-name:
|
||||||
|
description: "Molecule scenario name used to create the infrastructure"
|
||||||
|
type: string
|
||||||
|
redis-key:
|
||||||
|
description: "Redis key checked for non-emptiness to assert if Oracle is running"
|
||||||
|
type: string
|
||||||
|
ui-e2e-grep:
|
||||||
|
description: "Mocha grep string used to run ui-e2e tests specific to given type of bridge"
|
||||||
|
default: ''
|
||||||
|
type: string
|
||||||
|
oracle-e2e-script:
|
||||||
|
description: "Yarn script string used to run oracle-e2e tests specific to given type of bridge"
|
||||||
|
default: ''
|
||||||
|
type: string
|
||||||
|
steps:
|
||||||
|
- tokenbridge-orb/install-node
|
||||||
|
- tokenbridge-orb/install-chrome
|
||||||
|
- tokenbridge-orb/install-yarn
|
||||||
|
- restore_cache:
|
||||||
|
key: initialize-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
|
- run:
|
||||||
|
name: Prepare the infrastructure
|
||||||
|
command: e2e-commons/up.sh deploy << parameters.scenario-name >> blocks
|
||||||
|
no_output_timeout: 50m
|
||||||
|
- tokenbridge-orb/wait-for-oracle:
|
||||||
|
redis-key: << parameters.redis-key >>
|
||||||
|
- when:
|
||||||
|
condition: << parameters.ui-e2e-grep >>
|
||||||
|
steps:
|
||||||
|
- run:
|
||||||
|
name: Run the ui-e2e tests
|
||||||
|
command: |
|
||||||
|
nvm use default;
|
||||||
|
cd ui-e2e; yarn mocha -g "<< parameters.ui-e2e-grep >>" -b ./test.js
|
||||||
|
- when:
|
||||||
|
condition: << parameters.oracle-e2e-script >>
|
||||||
|
steps:
|
||||||
|
- run:
|
||||||
|
name: Run the oracle-e2e tests
|
||||||
|
command: cd e2e-commons && docker-compose run e2e yarn workspace oracle-e2e run << parameters.oracle-e2e-script >>
|
||||||
|
workflows:
|
||||||
|
tokenbridge:
|
||||||
|
jobs:
|
||||||
|
- initialize
|
||||||
|
- initialize-root:
|
||||||
|
filters:
|
||||||
|
branches:
|
||||||
|
only: master
|
||||||
|
- build:
|
||||||
|
requires:
|
||||||
|
- initialize
|
||||||
|
- lint:
|
||||||
|
requires:
|
||||||
|
- initialize
|
||||||
|
- test:
|
||||||
|
requires:
|
||||||
|
- initialize
|
||||||
|
- cover:
|
||||||
|
requires:
|
||||||
|
- initialize
|
||||||
|
filters:
|
||||||
|
branches:
|
||||||
|
only: master
|
||||||
|
- build-e2e-images
|
||||||
|
- oracle-e2e:
|
||||||
|
requires:
|
||||||
|
- build-e2e-images
|
||||||
|
- ui-e2e:
|
||||||
|
requires:
|
||||||
|
- build-e2e-images
|
||||||
|
- initialize
|
||||||
|
- monitor-e2e:
|
||||||
|
requires:
|
||||||
|
- build-e2e-images
|
||||||
|
- alm-e2e:
|
||||||
|
requires:
|
||||||
|
- build-e2e-images
|
||||||
|
- initialize
|
||||||
|
- deployment-oracle:
|
||||||
|
requires:
|
||||||
|
- build-e2e-images
|
||||||
|
- deployment-ui:
|
||||||
|
requires:
|
||||||
|
- build-e2e-images
|
||||||
|
- deployment-monitor:
|
||||||
|
requires:
|
||||||
|
- build-e2e-images
|
||||||
|
- deployment-repo:
|
||||||
|
requires:
|
||||||
|
- build-e2e-images
|
||||||
|
- deployment-multiple:
|
||||||
|
requires:
|
||||||
|
- build-e2e-images
|
||||||
|
- ultimate:
|
||||||
|
requires:
|
||||||
|
- build-e2e-images
|
||||||
|
- initialize
|
||||||
|
filters:
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- master
|
||||||
|
- develop
|
||||||
|
name: "ultimate: native to erc"
|
||||||
|
scenario-name: native-to-erc
|
||||||
|
redis-key: native-erc-collected-signatures:lastProcessedBlock
|
||||||
|
ui-e2e-grep: "NATIVE TO ERC"
|
||||||
|
- ultimate:
|
||||||
|
requires:
|
||||||
|
- build-e2e-images
|
||||||
|
- initialize
|
||||||
|
filters:
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- master
|
||||||
|
- develop
|
||||||
|
name: "ultimate: erc to native"
|
||||||
|
scenario-name: erc-to-native
|
||||||
|
redis-key: erc-native-collected-signatures:lastProcessedBlock
|
||||||
|
ui-e2e-grep: "ERC TO NATIVE"
|
||||||
|
- ultimate:
|
||||||
|
requires:
|
||||||
|
- build-e2e-images
|
||||||
|
- initialize
|
||||||
|
filters:
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- master
|
||||||
|
- develop
|
||||||
|
name: "ultimate: erc to erc"
|
||||||
|
scenario-name: erc-to-erc
|
||||||
|
redis-key: erc-erc-collected-signatures:lastProcessedBlock
|
||||||
|
ui-e2e-grep: "ERC TO ERC"
|
||||||
|
- ultimate:
|
||||||
|
requires:
|
||||||
|
- build-e2e-images
|
||||||
|
- initialize
|
||||||
|
filters:
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- master
|
||||||
|
- develop
|
||||||
|
name: "ultimate: amb"
|
||||||
|
scenario-name: amb
|
||||||
|
redis-key: amb-collected-signatures:lastProcessedBlock
|
||||||
|
oracle-e2e-script: "amb"
|
||||||
|
- ultimate:
|
||||||
|
requires:
|
||||||
|
- build-e2e-images
|
||||||
|
- initialize
|
||||||
|
filters:
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- master
|
||||||
|
- develop
|
||||||
|
name: "ultimate: amb stake erc to erc"
|
||||||
|
scenario-name: ultimate-amb-stake-erc-to-erc
|
||||||
|
redis-key: amb-collected-signatures:lastProcessedBlock
|
||||||
|
ui-e2e-grep: "AMB-STAKE-ERC-TO-ERC"
|
||||||
@@ -11,9 +11,6 @@
|
|||||||
contracts/test
|
contracts/test
|
||||||
contracts/build
|
contracts/build
|
||||||
oracle/test
|
oracle/test
|
||||||
monitor/test
|
|
||||||
monitor/responses
|
|
||||||
commons/test
|
|
||||||
oracle/**/*.png
|
oracle/**/*.png
|
||||||
oracle/**/*.jpg
|
oracle/**/*.jpg
|
||||||
audit
|
audit
|
||||||
|
|||||||
231
.github/workflows/main.yml
vendored
231
.github/workflows/main.yml
vendored
@@ -1,231 +0,0 @@
|
|||||||
name: tokenbridge
|
|
||||||
|
|
||||||
on: [push]
|
|
||||||
|
|
||||||
env:
|
|
||||||
DOCKER_REGISTRY: docker.pkg.github.com
|
|
||||||
DOCKER_REPO: poanetwork/tokenbridge
|
|
||||||
DOCKER_IMAGE_BASE: docker.pkg.github.com/poanetwork/tokenbridge
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
initialize:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
outputs:
|
|
||||||
cache_key: ${{ steps.get_cache_key.outputs.cache_key }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/setup-node@v1
|
|
||||||
with:
|
|
||||||
node-version: 10
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
submodules: true
|
|
||||||
- run: git submodule status > submodule.status
|
|
||||||
- id: get_cache_key
|
|
||||||
run: echo "::set-output name=cache_key::cache-repo-${{ hashFiles('yarn.lock', 'package.json', 'submodule.status') }}"
|
|
||||||
- uses: actions/cache@v2
|
|
||||||
id: cache-repo
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
**/node_modules
|
|
||||||
contracts/build
|
|
||||||
key: ${{ steps.get_cache_key.outputs.cache_key }}
|
|
||||||
- if: ${{ !steps.cache-repo.outputs.cache-hit }}
|
|
||||||
run: |
|
|
||||||
yarn install --frozen-lockfile
|
|
||||||
yarn run install:deploy
|
|
||||||
yarn run compile:contracts
|
|
||||||
validate:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs:
|
|
||||||
- initialize
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
task: [build, lint, test]
|
|
||||||
steps:
|
|
||||||
- uses: actions/setup-node@v1
|
|
||||||
with:
|
|
||||||
node-version: 10
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
submodules: true
|
|
||||||
- uses: actions/cache@v2
|
|
||||||
id: cache-repo
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
**/node_modules
|
|
||||||
contracts/build
|
|
||||||
key: ${{ needs.initialize.outputs.cache_key }}
|
|
||||||
- run: ${{ steps.cache-repo.outputs.cache-hit }} && yarn run ${{ matrix.task }}
|
|
||||||
ui-coverage:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs:
|
|
||||||
- initialize
|
|
||||||
if: github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags')
|
|
||||||
steps:
|
|
||||||
- uses: actions/setup-node@v1
|
|
||||||
with:
|
|
||||||
node-version: 10
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
submodules: true
|
|
||||||
- uses: actions/cache@v2
|
|
||||||
id: cache-repo
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
**/node_modules
|
|
||||||
contracts/build
|
|
||||||
key: ${{ needs.initialize.outputs.cache_key }}
|
|
||||||
- run: ${{ steps.cache-repo.outputs.cache-hit }} && yarn workspace ui run coverage
|
|
||||||
- uses: coverallsapp/github-action@master
|
|
||||||
with:
|
|
||||||
github-token: ${{ github.token }}
|
|
||||||
path-to-lcov: ./ui/coverage/lcov.info
|
|
||||||
build-e2e-images:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
submodules: true
|
|
||||||
- run: |
|
|
||||||
git submodule status > submodule.status
|
|
||||||
echo "::set-env name=E2E_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'Dockerfile.e2e', 'commons', 'oracle-e2e', 'monitor-e2e') }}"
|
|
||||||
echo "::set-env name=ORACLE_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'oracle') }}"
|
|
||||||
echo "::set-env name=MONITOR_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'monitor') }}"
|
|
||||||
echo "::set-env name=UI_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'ui') }}"
|
|
||||||
echo "::set-env name=ALM_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'alm') }}"
|
|
||||||
- run: |
|
|
||||||
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
|
|
||||||
}
|
|
||||||
updated=()
|
|
||||||
if ! check_if_image_exists e2e ${E2E_TAG}; then updated+=("e2e"); fi
|
|
||||||
if ! check_if_image_exists oracle ${ORACLE_TAG}; then updated+=("oracle"); fi
|
|
||||||
if ! check_if_image_exists monitor ${MONITOR_TAG}; then updated+=("monitor"); fi
|
|
||||||
if ! check_if_image_exists ui ${UI_TAG}; then updated+=("ui"); fi
|
|
||||||
if ! check_if_image_exists alm ${ALM_TAG}; then updated+=("alm"); fi
|
|
||||||
if [ ${#updated[@]} -gt 0 ]; then
|
|
||||||
echo "Updated services: ${updated[@]}"
|
|
||||||
cd e2e-commons
|
|
||||||
docker login ${DOCKER_REGISTRY} -u ${{ github.actor }} -p ${{ github.token }}
|
|
||||||
docker-compose build ${updated[@]}
|
|
||||||
docker-compose push ${updated[@]}
|
|
||||||
else
|
|
||||||
echo "Nothing relevant was changed in the source"
|
|
||||||
fi
|
|
||||||
build-molecule-runner:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
submodules: true
|
|
||||||
- run: echo "::set-env name=MOLECULE_RUNNER_TAG::${{ hashFiles('./deployment-e2e/Dockerfile') }}"
|
|
||||||
- run: |
|
|
||||||
function check_if_image_exists() {
|
|
||||||
curl -fsSlL -H 'Authorization: bearer ${{ github.token }}' "https://${DOCKER_REGISTRY}/v2/${DOCKER_REPO}/tokenbridge-e2e-$1/manifests/$2" > /dev/null
|
|
||||||
}
|
|
||||||
if check_if_image_exists molecule_runner ${MOLECULE_RUNNER_TAG}; then
|
|
||||||
echo "Image already exists"
|
|
||||||
else
|
|
||||||
cd e2e-commons
|
|
||||||
docker login ${DOCKER_REGISTRY} -u ${{ github.actor }} -p ${{ github.token }}
|
|
||||||
docker-compose build molecule_runner
|
|
||||||
docker-compose push molecule_runner
|
|
||||||
fi
|
|
||||||
e2e:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs:
|
|
||||||
- initialize
|
|
||||||
- build-e2e-images
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
task: [oracle-e2e, monitor-e2e, alm-e2e, 'ui-e2e:ci']
|
|
||||||
include:
|
|
||||||
- task: alm-e2e
|
|
||||||
use-cache: true
|
|
||||||
- task: 'ui-e2e:ci'
|
|
||||||
use-cache: true
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
submodules: true
|
|
||||||
- run: |
|
|
||||||
git submodule status > submodule.status
|
|
||||||
echo "::set-env name=E2E_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'Dockerfile.e2e', 'commons', 'oracle-e2e', 'monitor-e2e') }}"
|
|
||||||
echo "::set-env name=ORACLE_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'oracle') }}"
|
|
||||||
echo "::set-env name=MONITOR_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'monitor') }}"
|
|
||||||
echo "::set-env name=UI_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'ui') }}"
|
|
||||||
echo "::set-env name=ALM_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'alm') }}"
|
|
||||||
- if: ${{ matrix.use-cache }}
|
|
||||||
uses: actions/cache@v2
|
|
||||||
id: cache-repo
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
**/node_modules
|
|
||||||
contracts/build
|
|
||||||
key: ${{ needs.initialize.outputs.cache_key }}
|
|
||||||
- run: docker login ${DOCKER_REGISTRY} -u ${{ github.actor }} -p ${{ github.token }}
|
|
||||||
- run: ${{ !matrix.use-cache || steps.cache-repo.outputs.cache-hit }} && yarn run ${{ matrix.task }}
|
|
||||||
deployment:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs:
|
|
||||||
- build-molecule-runner
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
task: [oracle, ui, monitor, multiple, repo]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
submodules: true
|
|
||||||
- run: echo "::set-env name=MOLECULE_RUNNER_TAG::${{ hashFiles('./deployment-e2e/Dockerfile') }}"
|
|
||||||
- run: docker login ${DOCKER_REGISTRY} -u ${{ github.actor }} -p ${{ github.token }}
|
|
||||||
- run: deployment-e2e/molecule.sh ${{ matrix.task }}
|
|
||||||
ultimate:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs:
|
|
||||||
- initialize
|
|
||||||
- build-e2e-images
|
|
||||||
if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/develop' || startsWith(github.ref, 'refs/tags')
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
task: [amb, erc-to-erc, erc-to-native, native-to-erc, amb-stake-erc-to-erc]
|
|
||||||
include:
|
|
||||||
- task: erc-to-erc
|
|
||||||
ui-e2e-grep: 'ERC TO ERC'
|
|
||||||
- task: erc-to-native
|
|
||||||
ui-e2e-grep: 'ERC TO NATIVE'
|
|
||||||
- task: native-to-erc
|
|
||||||
ui-e2e-grep: 'NATIVE TO ERC'
|
|
||||||
- task: amb-stake-erc-to-erc
|
|
||||||
ui-e2e-grep: 'AMB-STAKE-ERC-TO-ERC'
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
submodules: true
|
|
||||||
- run: |
|
|
||||||
git submodule status > submodule.status
|
|
||||||
echo "::set-env name=E2E_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'Dockerfile.e2e', 'commons', 'oracle-e2e', 'monitor-e2e') }}"
|
|
||||||
echo "::set-env name=ORACLE_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'oracle') }}"
|
|
||||||
echo "::set-env name=MONITOR_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'monitor') }}"
|
|
||||||
echo "::set-env name=UI_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'ui') }}"
|
|
||||||
echo "::set-env name=ALM_TAG::${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'alm') }}"
|
|
||||||
echo "::set-env name=MOLECULE_RUNNER_TAG::${{ hashFiles('./deployment-e2e/Dockerfile') }}"
|
|
||||||
- uses: actions/cache@v2
|
|
||||||
id: cache-repo
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
**/node_modules
|
|
||||||
contracts/build
|
|
||||||
key: ${{ needs.initialize.outputs.cache_key }}
|
|
||||||
- run: docker login ${DOCKER_REGISTRY} -u ${{ github.actor }} -p ${{ github.token }}
|
|
||||||
- run: ${{ steps.cache-repo.outputs.cache-hit }} && e2e-commons/up.sh deploy blocks
|
|
||||||
- run: docker-compose -f ./e2e-commons/docker-compose.yml pull oracle
|
|
||||||
- run: deployment-e2e/molecule.sh ultimate-${{ matrix.task }}
|
|
||||||
- run: sudo chown -R $USER:docker /var/run/docker.sock
|
|
||||||
- if: ${{ matrix.ui-e2e-grep }}
|
|
||||||
run: cd ui-e2e && xvfb-run yarn mocha -g "${{ matrix.ui-e2e-grep }}" -b ./test.js
|
|
||||||
- if: ${{ !matrix.ui-e2e-grep }}
|
|
||||||
run: docker-compose -f ./e2e-commons/docker-compose.yml run e2e yarn workspace oracle-e2e run ${{ matrix.task }}
|
|
||||||
@@ -12,7 +12,7 @@ COMMON_HOME_GAS_PRICE_SUPPLIER_URL | The URL used to get a JSON response from th
|
|||||||
COMMON_HOME_GAS_PRICE_SPEED_TYPE | Assuming the gas price oracle responds with the following JSON structure: `{"fast": 20.0, "block_time": 12.834, "health": true, "standard": 6.0, "block_number": 6470469, "instant": 71.0, "slow": 1.889}`, this parameter specifies the desirable transaction speed. The speed type can be omitted when `COMMON_HOME_GAS_PRICE_SUPPLIER_URL` is not used. | `instant` / `fast` / `standard` / `slow`
|
COMMON_HOME_GAS_PRICE_SPEED_TYPE | Assuming the gas price oracle responds with the following JSON structure: `{"fast": 20.0, "block_time": 12.834, "health": true, "standard": 6.0, "block_number": 6470469, "instant": 71.0, "slow": 1.889}`, this parameter specifies the desirable transaction speed. The speed type can be omitted when `COMMON_HOME_GAS_PRICE_SUPPLIER_URL` is not used. | `instant` / `fast` / `standard` / `slow`
|
||||||
COMMON_HOME_GAS_PRICE_FALLBACK | The gas price (in Wei) that is used if both the oracle and the fall back gas price specified in the Home Bridge contract are not available. | integer
|
COMMON_HOME_GAS_PRICE_FALLBACK | The gas price (in Wei) that is used if both the oracle and the fall back gas price specified in the Home Bridge contract are not available. | integer
|
||||||
COMMON_HOME_GAS_PRICE_FACTOR | A value that will multiply the gas price of the oracle to convert it to gwei. If the oracle API returns gas prices in gwei then this can be set to `1`. Also, it could be used to intentionally pay more gas than suggested by the oracle to guarantee the transaction verification. E.g. `1.25` or `1.5`. | integer
|
COMMON_HOME_GAS_PRICE_FACTOR | A value that will multiply the gas price of the oracle to convert it to gwei. If the oracle API returns gas prices in gwei then this can be set to `1`. Also, it could be used to intentionally pay more gas than suggested by the oracle to guarantee the transaction verification. E.g. `1.25` or `1.5`. | integer
|
||||||
COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL | The URL used to get a JSON response from the gas price prediction oracle for the Foreign network. The provided gas price is used to send the validator's transactions to the RPC node. If the Foreign network is Ethereum Foundation mainnet, the oracle URL can be: https://gasprice.poa.network. Otherwise this parameter can be omitted. Set to `gas-price-oracle` if you want to use npm `gas-price-oracle` package for retrieving gas price from multiple sources. | URL
|
COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL | The URL used to get a JSON response from the gas price prediction oracle for the Foreign network. The provided gas price is used to send the validator's transactions to the RPC node. If the Foreign network is Ethereum Foundation mainnet, the oracle URL can be: https://gasprice.poa.network. Otherwise this parameter can be omitted. | URL
|
||||||
COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE | Assuming the gas price oracle responds with the following JSON structure: `{"fast": 20.0, "block_time": 12.834, "health": true, "standard": 6.0, "block_number": 6470469, "instant": 71.0, "slow": 1.889}`, this parameter specifies the desirable transaction speed. The speed type can be omitted when `COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL`is not used. | `instant` / `fast` / `standard` / `slow`
|
COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE | Assuming the gas price oracle responds with the following JSON structure: `{"fast": 20.0, "block_time": 12.834, "health": true, "standard": 6.0, "block_number": 6470469, "instant": 71.0, "slow": 1.889}`, this parameter specifies the desirable transaction speed. The speed type can be omitted when `COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL`is not used. | `instant` / `fast` / `standard` / `slow`
|
||||||
COMMON_FOREIGN_GAS_PRICE_FALLBACK | The gas price (in Wei) used if both the oracle and fall back gas price specified in the Foreign Bridge contract are not available. | integer
|
COMMON_FOREIGN_GAS_PRICE_FALLBACK | The gas price (in Wei) used if both the oracle and fall back gas price specified in the Foreign Bridge contract are not available. | integer
|
||||||
COMMON_FOREIGN_GAS_PRICE_FACTOR | A value that will multiply the gas price of the oracle to convert it to gwei. If the oracle API returns gas prices in gwei then this can be set to `1`. Also, it could be used to intentionally pay more gas than suggested by the oracle to guarantee the transaction verification. E.g. `1.25` or `1.5`. | integer
|
COMMON_FOREIGN_GAS_PRICE_FACTOR | A value that will multiply the gas price of the oracle to convert it to gwei. If the oracle API returns gas prices in gwei then this can be set to `1`. Also, it could be used to intentionally pay more gas than suggested by the oracle to guarantee the transaction verification. E.g. `1.25` or `1.5`. | integer
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM node:10 as contracts
|
FROM node:8 as contracts
|
||||||
|
|
||||||
WORKDIR /mono
|
WORKDIR /mono
|
||||||
|
|
||||||
@@ -11,12 +11,11 @@ COPY ./contracts/truffle-config.js ./
|
|||||||
COPY ./contracts/contracts ./contracts
|
COPY ./contracts/contracts ./contracts
|
||||||
RUN npm run compile
|
RUN npm run compile
|
||||||
|
|
||||||
FROM node:10
|
FROM node:8
|
||||||
|
|
||||||
WORKDIR /mono
|
WORKDIR /mono
|
||||||
COPY package.json .
|
COPY package.json .
|
||||||
COPY --from=contracts /mono/contracts/build ./contracts/build
|
COPY --from=contracts /mono/contracts/build ./contracts/build
|
||||||
COPY commons/package.json ./commons/
|
|
||||||
COPY oracle-e2e/package.json ./oracle-e2e/
|
COPY oracle-e2e/package.json ./oracle-e2e/
|
||||||
COPY monitor-e2e/package.json ./monitor-e2e/
|
COPY monitor-e2e/package.json ./monitor-e2e/
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||

|
[](https://circleci.com/gh/poanetwork/tokenbridge)
|
||||||
[](https://gitter.im/poanetwork/poa-bridge?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
[](https://gitter.im/poanetwork/poa-bridge?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
[](https://www.gnu.org/licenses/lgpl-3.0)
|
[](https://www.gnu.org/licenses/lgpl-3.0)
|
||||||
|
|
||||||
@@ -110,4 +110,4 @@ This project is licensed under the GNU Lesser General Public License v3.0. See t
|
|||||||
|
|
||||||
## References
|
## References
|
||||||
|
|
||||||
* [TokenBridge Documentation](https://docs.tokenbridge.net/)
|
* [TokenBridge Documentation](http://www.tokenbridge.net/)
|
||||||
|
|||||||
0
alm-e2e/run-tests.sh
Executable file → Normal file
0
alm-e2e/run-tests.sh
Executable file → Normal file
@@ -1,4 +1,4 @@
|
|||||||
FROM node:10 as contracts
|
FROM node:8 as contracts
|
||||||
|
|
||||||
WORKDIR /mono
|
WORKDIR /mono
|
||||||
|
|
||||||
|
|||||||
@@ -64,6 +64,10 @@ 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 displayedDescription = multiMessageSelected
|
||||||
|
? getTransactionStatusDescription(TRANSACTION_STATUS.SUCCESS_ONE_MESSAGE, timestamp)
|
||||||
|
: description
|
||||||
|
|
||||||
const isHome = chainId === home.chainId.toString()
|
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
|
||||||
@@ -71,32 +75,17 @@ export const StatusContainer = ({ onBackToMain, setNetworkFromParams, receiptPar
|
|||||||
const displayConfirmations = status === TRANSACTION_STATUS.SUCCESS_ONE_MESSAGE || multiMessageSelected
|
const displayConfirmations = status === TRANSACTION_STATUS.SUCCESS_ONE_MESSAGE || multiMessageSelected
|
||||||
const messageToConfirm =
|
const messageToConfirm =
|
||||||
messages.length > 1 ? messages[selectedMessageId] : messages.length > 0 ? messages[0] : { id: '', data: '' }
|
messages.length > 1 ? messages[selectedMessageId] : messages.length > 0 ? messages[0] : { id: '', data: '' }
|
||||||
|
|
||||||
let displayedDescription: string = multiMessageSelected
|
|
||||||
? getTransactionStatusDescription(TRANSACTION_STATUS.SUCCESS_ONE_MESSAGE, timestamp)
|
|
||||||
: description
|
|
||||||
let link
|
|
||||||
const descArray = displayedDescription.split('%link')
|
|
||||||
if (descArray.length > 1) {
|
|
||||||
displayedDescription = descArray[0]
|
|
||||||
link = (
|
|
||||||
<ExplorerTxLink href={descArray[1]} target="_blank" rel="noopener noreferrer">
|
|
||||||
{descArray[1]}
|
|
||||||
</ExplorerTxLink>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{status && (
|
{status && (
|
||||||
<p>
|
<p>
|
||||||
The transaction{' '}
|
The request{' '}
|
||||||
{displayExplorerLink && (
|
{displayExplorerLink && (
|
||||||
<ExplorerTxLink href={txExplorerLink} target="_blank">
|
<ExplorerTxLink href={txExplorerLink} target="_blank">
|
||||||
{formattedMessageId}
|
{formattedMessageId}
|
||||||
</ExplorerTxLink>
|
</ExplorerTxLink>
|
||||||
)}
|
)}
|
||||||
{!displayExplorerLink && <label>{formattedMessageId}</label>} {displayedDescription} {link}
|
{!displayExplorerLink && <label>{formattedMessageId}</label>} {displayedDescription}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
{displayMessageSelector && <MessageSelector messages={messages} onMessageSelected={onMessageSelected} />}
|
{displayMessageSelector && <MessageSelector messages={messages} onMessageSelected={onMessageSelected} />}
|
||||||
|
|||||||
@@ -2,8 +2,7 @@
|
|||||||
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',
|
||||||
SUCCESS_NO_MESSAGES:
|
SUCCESS_NO_MESSAGES: 'execution succeeded %t but it does not contain any bridge messages',
|
||||||
'successfully mined %t but it does not seem to contain any request to the bridge, \nso nothing needs to be confirmed by the validators. \nIf you are sure that the transaction should contain a request to the bridge,\ncontact to the validators by \nmessaging on %linkhttps://forum.poa.network/c/support',
|
|
||||||
FAILED: 'failed %t',
|
FAILED: 'failed %t',
|
||||||
NOT_FOUND:
|
NOT_FOUND:
|
||||||
'Transaction not found. \n1. Check that the transaction hash is correct. \n2. Wait several blocks for the transaction to be\nmined, gas price affects mining speed.'
|
'Transaction not found. \n1. Check that the transaction hash is correct. \n2. Wait several blocks for the transaction to be\nmined, gas price affects mining speed.'
|
||||||
|
|||||||
@@ -351,7 +351,7 @@ describe('getConfirmationsForTx', () => {
|
|||||||
{ 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.FAILED, txHash: '0x123', timestamp: 123 },
|
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
|
||||||
{ validator: validator4, status: VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED }
|
{ validator: validator4, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED }
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
expect(setResult.mock.calls[1][0]).toEqual(
|
expect(setResult.mock.calls[1][0]).toEqual(
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ const REWARDABLE_VALIDATORS_ABI = require('../contracts/build/contracts/Rewardab
|
|||||||
const HOME_AMB_ABI = require('../contracts/build/contracts/HomeAMB').abi
|
const HOME_AMB_ABI = require('../contracts/build/contracts/HomeAMB').abi
|
||||||
const FOREIGN_AMB_ABI = require('../contracts/build/contracts/ForeignAMB').abi
|
const FOREIGN_AMB_ABI = require('../contracts/build/contracts/ForeignAMB').abi
|
||||||
const BOX_ABI = require('../contracts/build/contracts/Box').abi
|
const BOX_ABI = require('../contracts/build/contracts/Box').abi
|
||||||
|
const SAI_TOP = require('../contracts/build/contracts/SaiTopMock').abi
|
||||||
const HOME_AMB_ERC_TO_ERC_ABI = require('../contracts/build/contracts/HomeAMBErc677ToErc677').abi
|
const HOME_AMB_ERC_TO_ERC_ABI = require('../contracts/build/contracts/HomeAMBErc677ToErc677').abi
|
||||||
const FOREIGN_AMB_ERC_TO_ERC_ABI = require('../contracts/build/contracts/ForeignAMBErc677ToErc677').abi
|
const FOREIGN_AMB_ERC_TO_ERC_ABI = require('../contracts/build/contracts/ForeignAMBErc677ToErc677').abi
|
||||||
const HOME_STAKE_ERC_TO_ERC_ABI = require('../contracts/build/contracts/HomeStakeTokenMediator').abi
|
const HOME_STAKE_ERC_TO_ERC_ABI = require('../contracts/build/contracts/HomeStakeTokenMediator').abi
|
||||||
@@ -135,6 +136,7 @@ module.exports = {
|
|||||||
OLD_AMB_USER_REQUEST_FOR_AFFIRMATION_ABI,
|
OLD_AMB_USER_REQUEST_FOR_AFFIRMATION_ABI,
|
||||||
OLD_AMB_USER_REQUEST_FOR_SIGNATURE_ABI,
|
OLD_AMB_USER_REQUEST_FOR_SIGNATURE_ABI,
|
||||||
BOX_ABI,
|
BOX_ABI,
|
||||||
|
SAI_TOP,
|
||||||
HOME_STAKE_ERC_TO_ERC_ABI,
|
HOME_STAKE_ERC_TO_ERC_ABI,
|
||||||
FOREIGN_STAKE_ERC_TO_ERC_ABI
|
FOREIGN_STAKE_ERC_TO_ERC_ABI
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
"test": "NODE_ENV=test mocha"
|
"test": "NODE_ENV=test mocha"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"gas-price-oracle": "^0.1.5",
|
|
||||||
"web3-utils": "1.0.0-beta.34"
|
"web3-utils": "1.0.0-beta.34"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
const { toWei, toBN } = require('web3-utils')
|
const { toWei, toBN } = require('web3-utils')
|
||||||
const { GasPriceOracle } = require('gas-price-oracle')
|
|
||||||
const { BRIDGE_MODES, FEE_MANAGER_MODE, ERC_TYPES } = require('./constants')
|
const { BRIDGE_MODES, FEE_MANAGER_MODE, ERC_TYPES } = require('./constants')
|
||||||
const { REWARDABLE_VALIDATORS_ABI } = require('./abis')
|
const { REWARDABLE_VALIDATORS_ABI } = require('./abis')
|
||||||
|
|
||||||
const gasPriceOracle = new GasPriceOracle()
|
|
||||||
|
|
||||||
function decodeBridgeMode(bridgeModeHash) {
|
function decodeBridgeMode(bridgeModeHash) {
|
||||||
switch (bridgeModeHash) {
|
switch (bridgeModeHash) {
|
||||||
case '0x92a8d7fe':
|
case '0x92a8d7fe':
|
||||||
@@ -238,13 +235,8 @@ const normalizeGasPrice = (oracleGasPrice, factor, limits = null) => {
|
|||||||
// we use built-in 'fetch' on browser side, and `node-fetch` package in Node.
|
// we use built-in 'fetch' on browser side, and `node-fetch` package in Node.
|
||||||
const gasPriceFromSupplier = async (fetchFn, options = {}) => {
|
const gasPriceFromSupplier = async (fetchFn, options = {}) => {
|
||||||
try {
|
try {
|
||||||
let json
|
const response = await fetchFn()
|
||||||
if (fetchFn) {
|
const json = await response.json()
|
||||||
const response = await fetchFn()
|
|
||||||
json = await response.json()
|
|
||||||
} else {
|
|
||||||
json = await gasPriceOracle.fetchGasPricesOffChain()
|
|
||||||
}
|
|
||||||
const oracleGasPrice = json[options.speedType]
|
const oracleGasPrice = json[options.speedType]
|
||||||
|
|
||||||
if (!oracleGasPrice) {
|
if (!oracleGasPrice) {
|
||||||
|
|||||||
Submodule contracts updated: dd46135248...f405ba9e56
@@ -13,7 +13,7 @@ git push
|
|||||||
Alternatively, if there are no changes except the playbooks, you can use the `master` branch:
|
Alternatively, if there are no changes except the playbooks, you can use the `master` branch:
|
||||||
|
|
||||||
```
|
```
|
||||||
./molecule.sh <scenario_name>
|
CIRCLE_BRANCH=master ./molecule.sh <scenario_name>
|
||||||
```
|
```
|
||||||
|
|
||||||
In this case `master` branch will be used as a codebase for Monitor, UI, Oracle and Contracts deployed by your local playbook.
|
In this case `master` branch will be used as a codebase for Monitor, UI, Oracle and Contracts deployed by your local playbook.
|
||||||
@@ -21,7 +21,7 @@ In this case `master` branch will be used as a codebase for Monitor, UI, Oracle
|
|||||||
## Run the tests
|
## Run the tests
|
||||||
|
|
||||||
```
|
```
|
||||||
./molecule.sh <scenario_name>
|
CIRCLE_BRANCH=master ./molecule.sh <scenario_name>
|
||||||
```
|
```
|
||||||
|
|
||||||
Available scenarios:
|
Available scenarios:
|
||||||
|
|||||||
@@ -2,11 +2,7 @@
|
|||||||
cd ./e2e-commons
|
cd ./e2e-commons
|
||||||
set -e # exit when any command fails
|
set -e # exit when any command fails
|
||||||
|
|
||||||
if [ -z "$CI" ]; then
|
docker-compose pull molecule_runner
|
||||||
docker-compose build molecule_runner
|
|
||||||
else
|
|
||||||
docker-compose pull molecule_runner
|
|
||||||
fi
|
|
||||||
docker network create --driver bridge ultimate || true
|
docker network create --driver bridge ultimate || true
|
||||||
while [ "$1" != "" ]; do
|
while [ "$1" != "" ]; do
|
||||||
docker-compose run molecule_runner /bin/bash -c "molecule test --scenario-name $1"
|
docker-compose run molecule_runner /bin/bash -c "molecule test --scenario-name $1"
|
||||||
|
|||||||
@@ -6,10 +6,12 @@
|
|||||||
- name: stop the service
|
- name: stop the service
|
||||||
shell: service poabridge stop
|
shell: service poabridge stop
|
||||||
|
|
||||||
- name: ReTag current oracle image
|
- name: Build current oracle image
|
||||||
shell: docker tag $(docker images --format '{{ '{{' }}.Repository{{ '}}' }}:{{ '{{' }}.Tag{{ '}}' }}' | grep -m 1 tokenbridge-e2e-oracle) oracle:ultimate-testing
|
shell: docker build -t oracle:ultimate-testing --file oracle/Dockerfile .
|
||||||
delegate_to: 127.0.0.1
|
delegate_to: 127.0.0.1
|
||||||
become: false
|
become: false
|
||||||
|
args:
|
||||||
|
chdir: "{{ lookup('env', 'PWD') }}/.."
|
||||||
|
|
||||||
- name: Replace oracle image
|
- name: Replace oracle image
|
||||||
replace:
|
replace:
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
copy:
|
copy:
|
||||||
src: ../../../../{{ item }}
|
src: ../../../../{{ item }}
|
||||||
dest: "{{ bridge_path }}/"
|
dest: "{{ bridge_path }}/"
|
||||||
mode: '0640'
|
|
||||||
with_items:
|
with_items:
|
||||||
- monorepo.tar.gz
|
- monorepo.tar.gz
|
||||||
- contracts.tar.gz
|
- contracts.tar.gz
|
||||||
|
|||||||
@@ -24,8 +24,6 @@
|
|||||||
template:
|
template:
|
||||||
src: .env.j2
|
src: .env.j2
|
||||||
dest: "{{ bridge_path }}/monitor/.env"
|
dest: "{{ bridge_path }}/monitor/.env"
|
||||||
owner: "{{ compose_service_user }}"
|
|
||||||
mode: '0640'
|
|
||||||
when: skip_task != true
|
when: skip_task != true
|
||||||
|
|
||||||
- name: Copy docker-compose file
|
- name: Copy docker-compose file
|
||||||
@@ -47,5 +45,3 @@
|
|||||||
template:
|
template:
|
||||||
src: config.env.j2
|
src: config.env.j2
|
||||||
dest: "{{ bridge_path }}/monitor/configs/{{ MONITOR_BRIDGE_NAME }}.env"
|
dest: "{{ bridge_path }}/monitor/configs/{{ MONITOR_BRIDGE_NAME }}.env"
|
||||||
owner: "{{ compose_service_user }}"
|
|
||||||
mode: '0640'
|
|
||||||
|
|||||||
@@ -9,8 +9,6 @@
|
|||||||
template:
|
template:
|
||||||
src: .env.j2
|
src: .env.j2
|
||||||
dest: "{{ bridge_path }}/oracle/.env"
|
dest: "{{ bridge_path }}/oracle/.env"
|
||||||
owner: "{{ compose_service_user }}"
|
|
||||||
mode: '0640'
|
|
||||||
|
|
||||||
- name: Copy docker-compose files
|
- name: Copy docker-compose files
|
||||||
copy:
|
copy:
|
||||||
|
|||||||
@@ -3,5 +3,3 @@
|
|||||||
template:
|
template:
|
||||||
src: .env.j2
|
src: .env.j2
|
||||||
dest: "{{ bridge_path }}/ui/.env"
|
dest: "{{ bridge_path }}/ui/.env"
|
||||||
owner: "{{ compose_service_user }}"
|
|
||||||
mode: '0640'
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
ARG DOCKER_IMAGE_BASE
|
ARG DOCKER_LOGIN
|
||||||
ARG UI_TAG
|
ARG CIRCLE_BRANCH
|
||||||
FROM ${DOCKER_IMAGE_BASE}/tokenbridge-e2e-ui:${UI_TAG}
|
FROM ${DOCKER_LOGIN}/tokenbridge-e2e-ui:${CIRCLE_BRANCH}
|
||||||
|
|
||||||
ARG DOT_ENV_PATH
|
ARG DOT_ENV_PATH
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
cd $(dirname $0)
|
|
||||||
set -e # exit when any command fails
|
|
||||||
|
|
||||||
docker-compose build e2e
|
|
||||||
while [ "$1" != "" ]; do
|
|
||||||
if [ "$1" == "oracle" ]; then
|
|
||||||
docker-compose build oracle
|
|
||||||
elif [ "$1" == "monitor" ]; then
|
|
||||||
docker-compose build monitor
|
|
||||||
elif [ "$1" == "ui" ]; then
|
|
||||||
docker-compose build ui
|
|
||||||
elif [ "$1" == "alm" ]; then
|
|
||||||
docker-compose build alm
|
|
||||||
fi
|
|
||||||
shift
|
|
||||||
done
|
|
||||||
@@ -50,6 +50,8 @@
|
|||||||
"home": "0x488Af810997eD1730cB3a3918cD83b3216E6eAda",
|
"home": "0x488Af810997eD1730cB3a3918cD83b3216E6eAda",
|
||||||
"foreign": "0x488Af810997eD1730cB3a3918cD83b3216E6eAda",
|
"foreign": "0x488Af810997eD1730cB3a3918cD83b3216E6eAda",
|
||||||
"foreignToken": "0x7cc4b1851c35959d34e635a470f6b5c43ba3c9c9",
|
"foreignToken": "0x7cc4b1851c35959d34e635a470f6b5c43ba3c9c9",
|
||||||
|
"halfDuplexToken": "0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359",
|
||||||
|
"saiTop": "0x9b0ccf7C8994E19F39b2B4CF708e0A7DF65fA8a3",
|
||||||
"chaiToken": "0x06af07097c9eeb7fd685c692751d5c66db49c215",
|
"chaiToken": "0x06af07097c9eeb7fd685c692751d5c66db49c215",
|
||||||
"ui": "http://localhost:3002",
|
"ui": "http://localhost:3002",
|
||||||
"monitor": "http://monitor-erc20-native:3012/bridge"
|
"monitor": "http://monitor-erc20-native:3012/bridge"
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
version: '3.8'
|
---
|
||||||
|
version: '3'
|
||||||
networks:
|
networks:
|
||||||
ultimate:
|
ultimate:
|
||||||
external: true
|
external: true
|
||||||
@@ -26,7 +27,7 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- ultimate
|
- ultimate
|
||||||
oracle:
|
oracle:
|
||||||
image: ${DOCKER_IMAGE_BASE:-tokenbridge}/tokenbridge-e2e-oracle:${ORACLE_TAG:-local}
|
image: ${DOCKER_LOGIN}/tokenbridge-e2e-oracle:${CIRCLE_BRANCH}
|
||||||
build:
|
build:
|
||||||
context: ..
|
context: ..
|
||||||
dockerfile: oracle/Dockerfile
|
dockerfile: oracle/Dockerfile
|
||||||
@@ -37,7 +38,10 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- ultimate
|
- ultimate
|
||||||
oracle-erc20:
|
oracle-erc20:
|
||||||
image: ${DOCKER_IMAGE_BASE:-tokenbridge}/tokenbridge-e2e-oracle:${ORACLE_TAG:-local}
|
image: ${DOCKER_LOGIN}/tokenbridge-e2e-oracle:${CIRCLE_BRANCH}
|
||||||
|
build:
|
||||||
|
context: ..
|
||||||
|
dockerfile: oracle/Dockerfile
|
||||||
env_file: ../e2e-commons/components-envs/oracle-erc20.env
|
env_file: ../e2e-commons/components-envs/oracle-erc20.env
|
||||||
environment:
|
environment:
|
||||||
- NODE_ENV=production
|
- NODE_ENV=production
|
||||||
@@ -45,7 +49,10 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- ultimate
|
- ultimate
|
||||||
oracle-erc20-native:
|
oracle-erc20-native:
|
||||||
image: ${DOCKER_IMAGE_BASE:-tokenbridge}/tokenbridge-e2e-oracle:${ORACLE_TAG:-local}
|
image: ${DOCKER_LOGIN}/tokenbridge-e2e-oracle:${CIRCLE_BRANCH}
|
||||||
|
build:
|
||||||
|
context: ..
|
||||||
|
dockerfile: oracle/Dockerfile
|
||||||
env_file: ../e2e-commons/components-envs/oracle-erc20-native.env
|
env_file: ../e2e-commons/components-envs/oracle-erc20-native.env
|
||||||
environment:
|
environment:
|
||||||
- NODE_ENV=production
|
- NODE_ENV=production
|
||||||
@@ -53,7 +60,10 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- ultimate
|
- ultimate
|
||||||
oracle-amb:
|
oracle-amb:
|
||||||
image: ${DOCKER_IMAGE_BASE:-tokenbridge}/tokenbridge-e2e-oracle:${ORACLE_TAG:-local}
|
image: ${DOCKER_LOGIN}/tokenbridge-e2e-oracle:${CIRCLE_BRANCH}
|
||||||
|
build:
|
||||||
|
context: ..
|
||||||
|
dockerfile: oracle/Dockerfile
|
||||||
env_file: ../e2e-commons/components-envs/oracle-amb.env
|
env_file: ../e2e-commons/components-envs/oracle-amb.env
|
||||||
environment:
|
environment:
|
||||||
- NODE_ENV=production
|
- NODE_ENV=production
|
||||||
@@ -61,7 +71,7 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- ultimate
|
- ultimate
|
||||||
ui:
|
ui:
|
||||||
image: ${DOCKER_IMAGE_BASE:-tokenbridge}/tokenbridge-e2e-ui:${UI_TAG:-local}
|
image: ${DOCKER_LOGIN}/tokenbridge-e2e-ui:${CIRCLE_BRANCH}
|
||||||
build:
|
build:
|
||||||
context: ..
|
context: ..
|
||||||
dockerfile: ui/Dockerfile
|
dockerfile: ui/Dockerfile
|
||||||
@@ -75,8 +85,8 @@ services:
|
|||||||
context: ..
|
context: ..
|
||||||
dockerfile: e2e-commons/Dockerfile.ui
|
dockerfile: e2e-commons/Dockerfile.ui
|
||||||
args:
|
args:
|
||||||
DOCKER_IMAGE_BASE: ${DOCKER_IMAGE_BASE:-tokenbridge}
|
DOCKER_LOGIN: ${DOCKER_LOGIN}
|
||||||
UI_TAG: ${UI_TAG:-local}
|
CIRCLE_BRANCH: ${CIRCLE_BRANCH}
|
||||||
DOT_ENV_PATH: e2e-commons/components-envs/ui-erc20.env
|
DOT_ENV_PATH: e2e-commons/components-envs/ui-erc20.env
|
||||||
command: "true"
|
command: "true"
|
||||||
networks:
|
networks:
|
||||||
@@ -86,8 +96,8 @@ services:
|
|||||||
context: ..
|
context: ..
|
||||||
dockerfile: e2e-commons/Dockerfile.ui
|
dockerfile: e2e-commons/Dockerfile.ui
|
||||||
args:
|
args:
|
||||||
DOCKER_IMAGE_BASE: ${DOCKER_IMAGE_BASE:-tokenbridge}
|
DOCKER_LOGIN: ${DOCKER_LOGIN}
|
||||||
UI_TAG: ${UI_TAG:-local}
|
CIRCLE_BRANCH: ${CIRCLE_BRANCH}
|
||||||
DOT_ENV_PATH: e2e-commons/components-envs/ui-erc20-native.env
|
DOT_ENV_PATH: e2e-commons/components-envs/ui-erc20-native.env
|
||||||
command: "true"
|
command: "true"
|
||||||
networks:
|
networks:
|
||||||
@@ -97,14 +107,14 @@ services:
|
|||||||
context: ..
|
context: ..
|
||||||
dockerfile: e2e-commons/Dockerfile.ui
|
dockerfile: e2e-commons/Dockerfile.ui
|
||||||
args:
|
args:
|
||||||
DOCKER_IMAGE_BASE: ${DOCKER_IMAGE_BASE:-tokenbridge}
|
DOCKER_LOGIN: ${DOCKER_LOGIN}
|
||||||
UI_TAG: ${UI_TAG:-local}
|
CIRCLE_BRANCH: ${CIRCLE_BRANCH}
|
||||||
DOT_ENV_PATH: e2e-commons/components-envs/ui-amb-stake-erc20-erc20.env
|
DOT_ENV_PATH: e2e-commons/components-envs/ui-amb-stake-erc20-erc20.env
|
||||||
command: "true"
|
command: "true"
|
||||||
networks:
|
networks:
|
||||||
- ultimate
|
- ultimate
|
||||||
alm:
|
alm:
|
||||||
image: ${DOCKER_IMAGE_BASE:-tokenbridge}/tokenbridge-e2e-alm:${ALM_TAG:-local}
|
image: ${DOCKER_LOGIN}/tokenbridge-e2e-alm:${CIRCLE_BRANCH}
|
||||||
build:
|
build:
|
||||||
context: ..
|
context: ..
|
||||||
dockerfile: alm/Dockerfile
|
dockerfile: alm/Dockerfile
|
||||||
@@ -114,7 +124,7 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- ultimate
|
- ultimate
|
||||||
monitor:
|
monitor:
|
||||||
image: ${DOCKER_IMAGE_BASE:-tokenbridge}/tokenbridge-e2e-monitor:${MONITOR_TAG:-local}
|
image: ${DOCKER_LOGIN}/tokenbridge-e2e-monitor:${CIRCLE_BRANCH}
|
||||||
build:
|
build:
|
||||||
context: ..
|
context: ..
|
||||||
dockerfile: monitor/Dockerfile
|
dockerfile: monitor/Dockerfile
|
||||||
@@ -125,7 +135,10 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- ultimate
|
- ultimate
|
||||||
monitor-erc20:
|
monitor-erc20:
|
||||||
image: ${DOCKER_IMAGE_BASE:-tokenbridge}/tokenbridge-e2e-monitor:${MONITOR_TAG:-local}
|
image: ${DOCKER_LOGIN}/tokenbridge-e2e-monitor:${CIRCLE_BRANCH}
|
||||||
|
build:
|
||||||
|
context: ..
|
||||||
|
dockerfile: monitor/Dockerfile
|
||||||
env_file: ../e2e-commons/components-envs/monitor-erc20.env
|
env_file: ../e2e-commons/components-envs/monitor-erc20.env
|
||||||
entrypoint: yarn check-and-start
|
entrypoint: yarn check-and-start
|
||||||
ports:
|
ports:
|
||||||
@@ -133,7 +146,10 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- ultimate
|
- ultimate
|
||||||
monitor-erc20-native:
|
monitor-erc20-native:
|
||||||
image: ${DOCKER_IMAGE_BASE:-tokenbridge}/tokenbridge-e2e-monitor:${MONITOR_TAG:-local}
|
image: ${DOCKER_LOGIN}/tokenbridge-e2e-monitor:${CIRCLE_BRANCH}
|
||||||
|
build:
|
||||||
|
context: ..
|
||||||
|
dockerfile: monitor/Dockerfile
|
||||||
env_file: ../e2e-commons/components-envs/monitor-erc20-native.env
|
env_file: ../e2e-commons/components-envs/monitor-erc20-native.env
|
||||||
entrypoint: yarn check-and-start
|
entrypoint: yarn check-and-start
|
||||||
ports:
|
ports:
|
||||||
@@ -141,7 +157,10 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- ultimate
|
- ultimate
|
||||||
monitor-amb:
|
monitor-amb:
|
||||||
image: ${DOCKER_IMAGE_BASE:-tokenbridge}/tokenbridge-e2e-monitor:${MONITOR_TAG:-local}
|
image: ${DOCKER_LOGIN}/tokenbridge-e2e-monitor:${CIRCLE_BRANCH}
|
||||||
|
build:
|
||||||
|
context: ..
|
||||||
|
dockerfile: monitor/Dockerfile
|
||||||
env_file: ../e2e-commons/components-envs/monitor-amb.env
|
env_file: ../e2e-commons/components-envs/monitor-amb.env
|
||||||
entrypoint: yarn check-and-start
|
entrypoint: yarn check-and-start
|
||||||
ports:
|
ports:
|
||||||
@@ -149,7 +168,7 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- ultimate
|
- ultimate
|
||||||
e2e:
|
e2e:
|
||||||
image: ${DOCKER_IMAGE_BASE:-tokenbridge}/tokenbridge-e2e-e2e:${E2E_TAG:-local}
|
image: ${DOCKER_LOGIN}/tokenbridge-e2e-e2e:${CIRCLE_BRANCH}
|
||||||
build:
|
build:
|
||||||
context: ..
|
context: ..
|
||||||
dockerfile: Dockerfile.e2e
|
dockerfile: Dockerfile.e2e
|
||||||
@@ -157,12 +176,15 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- ultimate
|
- ultimate
|
||||||
blocks:
|
blocks:
|
||||||
image: ${DOCKER_IMAGE_BASE:-tokenbridge}/tokenbridge-e2e-e2e:${E2E_TAG:-local}
|
image: ${DOCKER_LOGIN}/tokenbridge-e2e-e2e:${CIRCLE_BRANCH}
|
||||||
|
build:
|
||||||
|
context: ..
|
||||||
|
dockerfile: Dockerfile.e2e
|
||||||
entrypoint: node e2e-commons/scripts/blocks.js
|
entrypoint: node e2e-commons/scripts/blocks.js
|
||||||
networks:
|
networks:
|
||||||
- ultimate
|
- ultimate
|
||||||
molecule_runner:
|
molecule_runner:
|
||||||
image: ${DOCKER_IMAGE_BASE:-tokenbridge}/tokenbridge-e2e-molecule_runner:${MOLECULE_RUNNER_TAG:-local}
|
image: ${DOCKER_LOGIN}/tokenbridge-e2e-molecule_runner:${CIRCLE_BRANCH}
|
||||||
build:
|
build:
|
||||||
context: ..
|
context: ..
|
||||||
dockerfile: deployment-e2e/Dockerfile
|
dockerfile: deployment-e2e/Dockerfile
|
||||||
|
|||||||
@@ -4,13 +4,7 @@ set -e # exit when any command fails
|
|||||||
|
|
||||||
./down.sh
|
./down.sh
|
||||||
docker-compose build parity1 parity2
|
docker-compose build parity1 parity2
|
||||||
|
test -n "$NODOCKERPULL" || ./pull.sh $@
|
||||||
if [ -z "$CI" ]; then
|
|
||||||
./build.sh $@
|
|
||||||
else
|
|
||||||
./pull.sh $@
|
|
||||||
fi
|
|
||||||
|
|
||||||
docker network create --driver bridge ultimate || true
|
docker network create --driver bridge ultimate || true
|
||||||
docker-compose up -d parity1 parity2 e2e
|
docker-compose up -d parity1 parity2 e2e
|
||||||
|
|
||||||
@@ -28,6 +22,8 @@ startValidator () {
|
|||||||
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 watcher:half-duplex-transfer
|
||||||
|
docker-compose $1 run $2 $3 -d oracle-erc20-native yarn worker:swap-tokens
|
||||||
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
|
||||||
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
|
||||||
@@ -61,6 +57,8 @@ while [ "$1" != "" ]; do
|
|||||||
docker-compose run -d oracle-erc20-native yarn watcher:collected-signatures
|
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:affirmation-request
|
||||||
docker-compose run -d oracle-erc20-native yarn watcher:transfer
|
docker-compose run -d oracle-erc20-native yarn watcher:transfer
|
||||||
|
docker-compose run -d oracle-erc20-native yarn watcher:half-duplex-transfer
|
||||||
|
docker-compose run -d oracle-erc20-native yarn worker:swap-tokens
|
||||||
docker-compose run -d oracle-erc20-native yarn worker:convert-to-chai
|
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:signature-request
|
||||||
docker-compose run -d oracle-amb yarn watcher:collected-signatures
|
docker-compose run -d oracle-amb yarn watcher:collected-signatures
|
||||||
@@ -113,6 +111,26 @@ while [ "$1" != "" ]; do
|
|||||||
docker-compose up -d monitor monitor-erc20 monitor-erc20-native monitor-amb
|
docker-compose up -d monitor monitor-erc20 monitor-erc20-native monitor-amb
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ "$1" == "native-to-erc" ]; then
|
||||||
|
../deployment-e2e/molecule.sh ultimate-native-to-erc
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$1" == "erc-to-native" ]; then
|
||||||
|
../deployment-e2e/molecule.sh ultimate-erc-to-native
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$1" == "erc-to-erc" ]; then
|
||||||
|
../deployment-e2e/molecule.sh ultimate-erc-to-erc
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$1" == "amb" ]; then
|
||||||
|
../deployment-e2e/molecule.sh ultimate-amb
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$1" == "ultimate-amb-stake-erc-to-erc" ]; then
|
||||||
|
../deployment-e2e/molecule.sh ultimate-amb-stake-erc-to-erc
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "$1" == "alm-e2e" ]; then
|
if [ "$1" == "alm-e2e" ]; then
|
||||||
docker-compose up -d redis rabbit
|
docker-compose up -d redis rabbit
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "mocha --timeout 120000",
|
"start": "mocha --timeout 30000",
|
||||||
"lint": "eslint . --ignore-path ../.eslintignore"
|
"lint": "eslint . --ignore-path ../.eslintignore"
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
while true; do
|
while true; do
|
||||||
sleep 5
|
sleep 3
|
||||||
docker-compose -f ../e2e-commons/docker-compose.yml exec -d monitor yarn check-all
|
COMPOSE_INTERACTIVE_NO_CLI=1 nohup docker-compose -f ../e2e-commons/docker-compose.yml exec monitor yarn check-all
|
||||||
docker-compose -f ../e2e-commons/docker-compose.yml exec -d monitor-erc20 yarn check-all
|
COMPOSE_INTERACTIVE_NO_CLI=1 nohup docker-compose -f ../e2e-commons/docker-compose.yml exec monitor-erc20 yarn check-all
|
||||||
docker-compose -f ../e2e-commons/docker-compose.yml exec -d monitor-erc20-native yarn check-all
|
COMPOSE_INTERACTIVE_NO_CLI=1 nohup docker-compose -f ../e2e-commons/docker-compose.yml exec monitor-erc20-native yarn check-all
|
||||||
docker-compose -f ../e2e-commons/docker-compose.yml exec -d monitor-amb yarn check-all
|
COMPOSE_INTERACTIVE_NO_CLI=1 nohup docker-compose -f ../e2e-commons/docker-compose.yml exec monitor-amb yarn check-all
|
||||||
done
|
done
|
||||||
|
|||||||
@@ -37,9 +37,6 @@ 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}`))
|
||||||
if (!data.foreign) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
const { erc20Balance, investedErc20Balance } = data.foreign
|
const { erc20Balance, investedErc20Balance } = data.foreign
|
||||||
return data.balanceDiff === 0.01 && erc20Balance === '0.01' && investedErc20Balance === undefined
|
return data.balanceDiff === 0.01 && erc20Balance === '0.01' && investedErc20Balance === undefined
|
||||||
})
|
})
|
||||||
@@ -61,9 +58,6 @@ 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
|
const { erc20Balance, investedErc20Balance, accumulatedInterest } = data.foreign
|
||||||
if (!data.foreign) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
data.balanceDiff === 0.02 &&
|
data.balanceDiff === 0.02 &&
|
||||||
erc20Balance === '0.02' &&
|
erc20Balance === '0.02' &&
|
||||||
@@ -78,9 +72,6 @@ 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
|
const { erc20Balance, investedErc20Balance, accumulatedInterest } = data.foreign
|
||||||
if (!data.foreign) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
data.balanceDiff === 0.02 &&
|
data.balanceDiff === 0.02 &&
|
||||||
erc20Balance === '0.01' &&
|
erc20Balance === '0.01' &&
|
||||||
@@ -95,9 +86,6 @@ 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
|
const { erc20Balance, investedErc20Balance, accumulatedInterest } = data.foreign
|
||||||
if (!data.foreign) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
data.balanceDiff === 0.02 &&
|
data.balanceDiff === 0.02 &&
|
||||||
erc20Balance === '0.005' &&
|
erc20Balance === '0.005' &&
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ const {
|
|||||||
} = require('../commons')
|
} = require('../commons')
|
||||||
const { validator } = require('../e2e-commons/constants')
|
const { validator } = require('../e2e-commons/constants')
|
||||||
|
|
||||||
const waitUntil = async (predicate, step = 100, timeout = 60000) => {
|
const waitUntil = async (predicate, step = 100, timeout = 20000) => {
|
||||||
const stopTime = Date.now() + timeout
|
const stopTime = Date.now() + timeout
|
||||||
while (Date.now() <= stopTime) {
|
while (Date.now() <= stopTime) {
|
||||||
const result = await predicate()
|
const result = await predicate()
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
FILES=(getBalances.json validators.json eventsStats.json alerts.json)
|
FILES=(getBalances.json validators.json eventsStats.json alerts.json)
|
||||||
|
|
||||||
check_files_exist() {
|
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"
|
||||||
(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 monitor /bin/bash -c "$command") || rc=1
|
||||||
(docker-compose -f ../e2e-commons/docker-compose.yml exec -T monitor-erc20 /bin/bash -c "$command") || rc=1
|
(docker-compose -f ../e2e-commons/docker-compose.yml exec monitor-erc20 /bin/bash -c "$command") || rc=1
|
||||||
(docker-compose -f ../e2e-commons/docker-compose.yml exec -T monitor-erc20-native /bin/bash -c "$command") || rc=1
|
(docker-compose -f ../e2e-commons/docker-compose.yml exec monitor-erc20-native /bin/bash -c "$command") || rc=1
|
||||||
(docker-compose -f ../e2e-commons/docker-compose.yml exec -T monitor-amb /bin/bash -c "$command") || rc=1
|
(docker-compose -f ../e2e-commons/docker-compose.yml exec monitor-amb /bin/bash -c "$command") || rc=1
|
||||||
done
|
done
|
||||||
return $rc
|
return $rc
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM node:10 as contracts
|
FROM node:8 as contracts
|
||||||
|
|
||||||
WORKDIR /mono
|
WORKDIR /mono
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@ COPY ./contracts/truffle-config.js ./
|
|||||||
COPY ./contracts/contracts ./contracts
|
COPY ./contracts/contracts ./contracts
|
||||||
RUN npm run compile
|
RUN npm run compile
|
||||||
|
|
||||||
FROM node:10
|
FROM node:8
|
||||||
|
|
||||||
WORKDIR /mono
|
WORKDIR /mono
|
||||||
COPY package.json .
|
COPY package.json .
|
||||||
|
|||||||
@@ -3,6 +3,4 @@ version: '2.4'
|
|||||||
services:
|
services:
|
||||||
monitor:
|
monitor:
|
||||||
image: poanetwork/tokenbridge-monitor
|
image: poanetwork/tokenbridge-monitor
|
||||||
build:
|
build: .
|
||||||
context: ..
|
|
||||||
dockerfile: ./monitor/Dockerfile
|
|
||||||
|
|||||||
@@ -100,13 +100,8 @@ async function main(bridgeMode) {
|
|||||||
|
|
||||||
if (MONITOR_VALIDATOR_FOREIGN_TX_LIMIT) {
|
if (MONITOR_VALIDATOR_FOREIGN_TX_LIMIT) {
|
||||||
logger.debug('calling foreign getGasPrices')
|
logger.debug('calling foreign getGasPrices')
|
||||||
const fetchFn =
|
|
||||||
COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL === 'gas-price-oracle'
|
|
||||||
? null
|
|
||||||
: () => fetch(COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL)
|
|
||||||
|
|
||||||
foreignGasPrice =
|
foreignGasPrice =
|
||||||
(await gasPriceFromSupplier(fetchFn, foreignGasPriceSupplierOpts)) ||
|
(await gasPriceFromSupplier(() => fetch(COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL), foreignGasPriceSupplierOpts)) ||
|
||||||
Web3Utils.toBN(COMMON_FOREIGN_GAS_PRICE_FALLBACK)
|
Web3Utils.toBN(COMMON_FOREIGN_GAS_PRICE_FALLBACK)
|
||||||
foreignGasPriceGwei = Web3Utils.fromWei(foreignGasPrice.toString(), 'gwei')
|
foreignGasPriceGwei = Web3Utils.fromWei(foreignGasPrice.toString(), 'gwei')
|
||||||
foreignTxCost = foreignGasPrice.mul(Web3Utils.toBN(MONITOR_VALIDATOR_FOREIGN_TX_LIMIT))
|
foreignTxCost = foreignGasPrice.mul(Web3Utils.toBN(MONITOR_VALIDATOR_FOREIGN_TX_LIMIT))
|
||||||
|
|||||||
@@ -31,7 +31,12 @@ const foreignBridge = new foreignWeb3.eth.Contract(FOREIGN_ERC_TO_NATIVE_ABI, CO
|
|||||||
const homeBridge = new homeWeb3.eth.Contract(HOME_ERC_TO_NATIVE_ABI, COMMON_HOME_BRIDGE_ADDRESS)
|
const homeBridge = new homeWeb3.eth.Contract(HOME_ERC_TO_NATIVE_ABI, COMMON_HOME_BRIDGE_ADDRESS)
|
||||||
|
|
||||||
describe('erc to native', () => {
|
describe('erc to native', () => {
|
||||||
|
let halfDuplexTokenAddress
|
||||||
|
let halfDuplexToken
|
||||||
before(async () => {
|
before(async () => {
|
||||||
|
halfDuplexTokenAddress = await foreignBridge.methods.halfDuplexErc20token().call()
|
||||||
|
halfDuplexToken = new foreignWeb3.eth.Contract(ERC677_BRIDGE_TOKEN_ABI, halfDuplexTokenAddress)
|
||||||
|
|
||||||
// Set 2 required signatures for home bridge
|
// Set 2 required signatures for home bridge
|
||||||
await setRequiredSignatures({
|
await setRequiredSignatures({
|
||||||
bridgeContract: homeBridge,
|
bridgeContract: homeBridge,
|
||||||
@@ -54,6 +59,85 @@ describe('erc to native', () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
it('should not convert half duplex tokens to native tokens in home', async () => {
|
||||||
|
const originalBalanceOnHome = await homeWeb3.eth.getBalance(user.address)
|
||||||
|
|
||||||
|
const transferValue = homeWeb3.utils.toWei('0.01')
|
||||||
|
|
||||||
|
// send tokens to foreign bridge
|
||||||
|
await halfDuplexToken.methods
|
||||||
|
.transfer(COMMON_FOREIGN_BRIDGE_ADDRESS, transferValue)
|
||||||
|
.send({
|
||||||
|
from: user.address,
|
||||||
|
gas: '1000000'
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
console.error(e)
|
||||||
|
})
|
||||||
|
|
||||||
|
// check that balance does not increases
|
||||||
|
await promiseRetry(async (retry, number) => {
|
||||||
|
const balance = await homeWeb3.eth.getBalance(user.address)
|
||||||
|
// retry at least 4 times to check transfer is not processed
|
||||||
|
if (toBN(balance).eq(toBN(originalBalanceOnHome)) && number < 4) {
|
||||||
|
retry()
|
||||||
|
} else {
|
||||||
|
assert(toBN(balance).eq(toBN(originalBalanceOnHome)), 'User balance should not be increased')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// send tokens to foreign bridge
|
||||||
|
await erc20Token.methods
|
||||||
|
.transfer(COMMON_FOREIGN_BRIDGE_ADDRESS, transferValue)
|
||||||
|
.send({
|
||||||
|
from: user.address,
|
||||||
|
gas: '1000000'
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
console.error(e)
|
||||||
|
})
|
||||||
|
|
||||||
|
// check that balance increases
|
||||||
|
await promiseRetry(async (retry, number) => {
|
||||||
|
const balance = await homeWeb3.eth.getBalance(user.address)
|
||||||
|
// retry at least 4 times to check transfer is not double processed by the two watchers
|
||||||
|
if (toBN(balance).lte(toBN(originalBalanceOnHome)) || number < 4) {
|
||||||
|
retry()
|
||||||
|
} else {
|
||||||
|
assert(
|
||||||
|
toBN(balance).eq(toBN(originalBalanceOnHome).add(toBN(transferValue))),
|
||||||
|
'User balance should be increased only by second transfer'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const afterTransferBalance = await homeWeb3.eth.getBalance(user.address)
|
||||||
|
|
||||||
|
// send tokens to foreign bridge
|
||||||
|
await erc20Token.methods
|
||||||
|
.transfer(COMMON_FOREIGN_BRIDGE_ADDRESS, transferValue)
|
||||||
|
.send({
|
||||||
|
from: user.address,
|
||||||
|
gas: '1000000'
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
console.error(e)
|
||||||
|
})
|
||||||
|
|
||||||
|
// check that balance increases
|
||||||
|
await promiseRetry(async (retry, number) => {
|
||||||
|
const balance = await homeWeb3.eth.getBalance(user.address)
|
||||||
|
// retry at least 4 times to check transfer is not double processed by the two watchers
|
||||||
|
if (toBN(balance).lte(toBN(afterTransferBalance)) || number < 4) {
|
||||||
|
retry()
|
||||||
|
} else {
|
||||||
|
assert(
|
||||||
|
toBN(balance).eq(toBN(afterTransferBalance).add(toBN(transferValue))),
|
||||||
|
'User balance should be increased'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
it('should convert tokens in foreign to coins in home', async () => {
|
it('should convert tokens in foreign to coins in home', async () => {
|
||||||
const balance = await erc20Token.methods.balanceOf(user.address).call()
|
const balance = await erc20Token.methods.balanceOf(user.address).call()
|
||||||
const originalBalanceOnHome = await homeWeb3.eth.getBalance(user.address)
|
const originalBalanceOnHome = await homeWeb3.eth.getBalance(user.address)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM node:10 as contracts
|
FROM node:8 as contracts
|
||||||
|
|
||||||
WORKDIR /mono
|
WORKDIR /mono
|
||||||
|
|
||||||
@@ -11,11 +11,14 @@ COPY ./contracts/truffle-config.js ./
|
|||||||
COPY ./contracts/contracts ./contracts
|
COPY ./contracts/contracts ./contracts
|
||||||
RUN npm run compile
|
RUN npm run compile
|
||||||
|
|
||||||
FROM node:10
|
FROM node:8
|
||||||
|
|
||||||
RUN apt-get update && \
|
RUN apt-get update
|
||||||
apt-get install -y build-essential libc6-dev libc6-dev-i386 wget && \
|
RUN apt-get install -y build-essential
|
||||||
apt-get clean
|
RUN apt-get install -y libc6-dev
|
||||||
|
RUN apt-get install -y libc6-dev-i386
|
||||||
|
RUN apt-get install -y wget
|
||||||
|
RUN apt-get clean
|
||||||
|
|
||||||
WORKDIR /mono
|
WORKDIR /mono
|
||||||
COPY package.json .
|
COPY package.json .
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ module.exports = {
|
|||||||
...baseConfig.bridgeConfig,
|
...baseConfig.bridgeConfig,
|
||||||
...baseConfig.foreignConfig,
|
...baseConfig.foreignConfig,
|
||||||
event: 'UserRequestForAffirmation',
|
event: 'UserRequestForAffirmation',
|
||||||
queue: 'home-prioritized',
|
queue: 'home',
|
||||||
name: `watcher-${id}`,
|
name: `watcher-${id}`,
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,7 +73,6 @@ const bridgeConfig = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const homeConfig = {
|
const homeConfig = {
|
||||||
chain: 'home',
|
|
||||||
eventContractAddress: process.env.COMMON_HOME_BRIDGE_ADDRESS,
|
eventContractAddress: process.env.COMMON_HOME_BRIDGE_ADDRESS,
|
||||||
eventAbi: homeAbi,
|
eventAbi: homeAbi,
|
||||||
bridgeContractAddress: process.env.COMMON_HOME_BRIDGE_ADDRESS,
|
bridgeContractAddress: process.env.COMMON_HOME_BRIDGE_ADDRESS,
|
||||||
@@ -84,7 +83,6 @@ const homeConfig = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const foreignConfig = {
|
const foreignConfig = {
|
||||||
chain: 'foreign',
|
|
||||||
eventContractAddress: process.env.COMMON_FOREIGN_BRIDGE_ADDRESS,
|
eventContractAddress: process.env.COMMON_FOREIGN_BRIDGE_ADDRESS,
|
||||||
eventAbi: foreignAbi,
|
eventAbi: foreignAbi,
|
||||||
bridgeContractAddress: process.env.COMMON_FOREIGN_BRIDGE_ADDRESS,
|
bridgeContractAddress: process.env.COMMON_FOREIGN_BRIDGE_ADDRESS,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ module.exports = {
|
|||||||
...baseConfig.bridgeConfig,
|
...baseConfig.bridgeConfig,
|
||||||
...baseConfig.homeConfig,
|
...baseConfig.homeConfig,
|
||||||
event: 'CollectedSignatures',
|
event: 'CollectedSignatures',
|
||||||
queue: 'foreign-prioritized',
|
queue: 'foreign',
|
||||||
name: `watcher-${id}`,
|
name: `watcher-${id}`,
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ module.exports = {
|
|||||||
...baseConfig.bridgeConfig,
|
...baseConfig.bridgeConfig,
|
||||||
...baseConfig.foreignConfig,
|
...baseConfig.foreignConfig,
|
||||||
workerQueue: 'convert-to-chai',
|
workerQueue: 'convert-to-chai',
|
||||||
senderQueue: 'foreign-prioritized',
|
senderQueue: 'foreign',
|
||||||
name: `worker-${id}`,
|
name: `worker-${id}`,
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ const { web3Foreign } = require('../src/services/web3')
|
|||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
...baseConfig.bridgeConfig,
|
...baseConfig.bridgeConfig,
|
||||||
queue: 'foreign-prioritized',
|
queue: 'foreign',
|
||||||
oldQueue: 'foreign',
|
|
||||||
id: 'foreign',
|
id: 'foreign',
|
||||||
name: 'sender-foreign',
|
name: 'sender-foreign',
|
||||||
web3: web3Foreign
|
web3: web3Foreign
|
||||||
|
|||||||
39
oracle/config/half-duplex-transfer-watcher.config.js
Normal file
39
oracle/config/half-duplex-transfer-watcher.config.js
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
const baseConfig = require('./base.config')
|
||||||
|
const { ERC20_ABI } = require('../../commons')
|
||||||
|
const { EXIT_CODES } = require('../src/utils/constants')
|
||||||
|
|
||||||
|
const initialChecksJson = process.argv[3]
|
||||||
|
|
||||||
|
if (!initialChecksJson) {
|
||||||
|
throw new Error('initial check parameter was not provided.')
|
||||||
|
}
|
||||||
|
|
||||||
|
let initialChecks
|
||||||
|
try {
|
||||||
|
initialChecks = JSON.parse(initialChecksJson)
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error('Error on decoding values from initial checks.')
|
||||||
|
}
|
||||||
|
|
||||||
|
const id = `${baseConfig.id}-half-duplex-transfer`
|
||||||
|
|
||||||
|
const transferWatcherRequired = baseConfig.id === 'erc-native'
|
||||||
|
|
||||||
|
if (!transferWatcherRequired) {
|
||||||
|
console.error(`Transfer watcher not required for bridge mode ${process.env.ORACLE_BRIDGE_MODE}`)
|
||||||
|
process.exit(EXIT_CODES.WATCHER_NOT_REQUIRED)
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
...baseConfig.bridgeConfig,
|
||||||
|
...baseConfig.foreignConfig,
|
||||||
|
event: 'Transfer',
|
||||||
|
eventContractAddress: initialChecks.halfDuplexTokenAddress,
|
||||||
|
eventAbi: ERC20_ABI,
|
||||||
|
eventFilter: { to: process.env.COMMON_FOREIGN_BRIDGE_ADDRESS },
|
||||||
|
queue: 'home',
|
||||||
|
workerQueue: 'swap-tokens',
|
||||||
|
name: `watcher-${id}`,
|
||||||
|
id,
|
||||||
|
idle: initialChecks.idle
|
||||||
|
}
|
||||||
@@ -4,8 +4,7 @@ const { web3Home } = require('../src/services/web3')
|
|||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
...baseConfig.bridgeConfig,
|
...baseConfig.bridgeConfig,
|
||||||
queue: 'home-prioritized',
|
queue: 'home',
|
||||||
oldQueue: 'home',
|
|
||||||
id: 'home',
|
id: 'home',
|
||||||
name: 'sender-home',
|
name: 'sender-home',
|
||||||
web3: web3Home
|
web3: web3Home
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ module.exports = {
|
|||||||
...baseConfig.bridgeConfig,
|
...baseConfig.bridgeConfig,
|
||||||
...baseConfig.homeConfig,
|
...baseConfig.homeConfig,
|
||||||
event: 'UserRequestForSignature',
|
event: 'UserRequestForSignature',
|
||||||
queue: 'home-prioritized',
|
queue: 'home',
|
||||||
name: `watcher-${id}`,
|
name: `watcher-${id}`,
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
|||||||
20
oracle/config/swap-tokens-worker.config.js
Normal file
20
oracle/config/swap-tokens-worker.config.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
const baseConfig = require('./base.config')
|
||||||
|
const { EXIT_CODES } = require('../src/utils/constants')
|
||||||
|
|
||||||
|
const id = `${baseConfig.id}-swap-tokens`
|
||||||
|
|
||||||
|
const workerRequired = baseConfig.id === 'erc-native'
|
||||||
|
|
||||||
|
if (!workerRequired) {
|
||||||
|
console.error(`Swap tokens worker not required for bridge mode ${process.env.ORACLE_BRIDGE_MODE}`)
|
||||||
|
process.exit(EXIT_CODES.WATCHER_NOT_REQUIRED)
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
...baseConfig.bridgeConfig,
|
||||||
|
...baseConfig.foreignConfig,
|
||||||
|
workerQueue: 'swap-tokens',
|
||||||
|
senderQueue: 'foreign',
|
||||||
|
name: `worker-${id}`,
|
||||||
|
id
|
||||||
|
}
|
||||||
@@ -41,7 +41,7 @@ module.exports = {
|
|||||||
eventContractAddress: initialChecks.bridgeableTokenAddress,
|
eventContractAddress: initialChecks.bridgeableTokenAddress,
|
||||||
eventAbi: ERC20_ABI,
|
eventAbi: ERC20_ABI,
|
||||||
eventFilter: { to: process.env.COMMON_FOREIGN_BRIDGE_ADDRESS },
|
eventFilter: { to: process.env.COMMON_FOREIGN_BRIDGE_ADDRESS },
|
||||||
queue: 'home-prioritized',
|
queue: 'home',
|
||||||
...workerQueueConfig,
|
...workerQueueConfig,
|
||||||
name: `watcher-${id}`,
|
name: `watcher-${id}`,
|
||||||
id
|
id
|
||||||
|
|||||||
@@ -3,6 +3,4 @@ version: '2.4'
|
|||||||
services:
|
services:
|
||||||
oracle:
|
oracle:
|
||||||
image: poanetwork/tokenbridge-oracle
|
image: poanetwork/tokenbridge-oracle
|
||||||
build:
|
build: .
|
||||||
context: ..
|
|
||||||
dockerfile: ./oracle/Dockerfile
|
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ services:
|
|||||||
service: rabbit
|
service: rabbit
|
||||||
networks:
|
networks:
|
||||||
- net_rabbit_bridge_transfer
|
- net_rabbit_bridge_transfer
|
||||||
|
- net_rabbit_bridge_half_duplex_transfer
|
||||||
|
- net_rabbit_bridge_swap_tokens_worker
|
||||||
- net_rabbit_bridge_convert_to_chai_worker
|
- net_rabbit_bridge_convert_to_chai_worker
|
||||||
redis:
|
redis:
|
||||||
extends:
|
extends:
|
||||||
@@ -14,6 +16,7 @@ services:
|
|||||||
service: redis
|
service: redis
|
||||||
networks:
|
networks:
|
||||||
- net_db_bridge_transfer
|
- net_db_bridge_transfer
|
||||||
|
- net_db_bridge_half_duplex_transfer
|
||||||
bridge_request:
|
bridge_request:
|
||||||
extends:
|
extends:
|
||||||
file: docker-compose.yml
|
file: docker-compose.yml
|
||||||
@@ -48,6 +51,31 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- net_db_bridge_transfer
|
- net_db_bridge_transfer
|
||||||
- net_rabbit_bridge_transfer
|
- net_rabbit_bridge_transfer
|
||||||
|
bridge_half_duplex_transfer:
|
||||||
|
cpus: 0.1
|
||||||
|
mem_limit: 500m
|
||||||
|
image: poanetwork/tokenbridge-oracle:latest
|
||||||
|
env_file: ./.env
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=production
|
||||||
|
- ORACLE_VALIDATOR_ADDRESS=${ORACLE_VALIDATOR_ADDRESS}
|
||||||
|
restart: unless-stopped
|
||||||
|
entrypoint: yarn watcher:half-duplex-transfer
|
||||||
|
networks:
|
||||||
|
- net_db_bridge_half_duplex_transfer
|
||||||
|
- net_rabbit_bridge_half_duplex_transfer
|
||||||
|
bridge_swap_tokens_worker:
|
||||||
|
cpus: 0.1
|
||||||
|
mem_limit: 500m
|
||||||
|
image: poanetwork/tokenbridge-oracle:latest
|
||||||
|
env_file: ./.env
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=production
|
||||||
|
- ORACLE_VALIDATOR_ADDRESS=${ORACLE_VALIDATOR_ADDRESS}
|
||||||
|
restart: unless-stopped
|
||||||
|
entrypoint: yarn worker:swap-tokens
|
||||||
|
networks:
|
||||||
|
- net_rabbit_bridge_swap_tokens_worker
|
||||||
bridge_convert_to_chai_worker:
|
bridge_convert_to_chai_worker:
|
||||||
cpus: 0.1
|
cpus: 0.1
|
||||||
mem_limit: 500m
|
mem_limit: 500m
|
||||||
@@ -84,6 +112,8 @@ networks:
|
|||||||
driver: bridge
|
driver: bridge
|
||||||
net_db_bridge_transfer:
|
net_db_bridge_transfer:
|
||||||
driver: bridge
|
driver: bridge
|
||||||
|
net_db_bridge_half_duplex_transfer:
|
||||||
|
driver: bridge
|
||||||
net_db_bridge_senderhome:
|
net_db_bridge_senderhome:
|
||||||
driver: bridge
|
driver: bridge
|
||||||
net_db_bridge_senderforeign:
|
net_db_bridge_senderforeign:
|
||||||
@@ -96,6 +126,10 @@ networks:
|
|||||||
driver: bridge
|
driver: bridge
|
||||||
net_rabbit_bridge_transfer:
|
net_rabbit_bridge_transfer:
|
||||||
driver: bridge
|
driver: bridge
|
||||||
|
net_rabbit_bridge_half_duplex_transfer:
|
||||||
|
driver: bridge
|
||||||
|
net_rabbit_bridge_swap_tokens_worker:
|
||||||
|
driver: bridge
|
||||||
net_rabbit_bridge_senderhome:
|
net_rabbit_bridge_senderhome:
|
||||||
driver: bridge
|
driver: bridge
|
||||||
net_rabbit_bridge_senderforeign:
|
net_rabbit_bridge_senderforeign:
|
||||||
|
|||||||
@@ -9,11 +9,13 @@
|
|||||||
"watcher:collected-signatures": "./scripts/start-worker.sh watcher collected-signatures-watcher",
|
"watcher:collected-signatures": "./scripts/start-worker.sh watcher collected-signatures-watcher",
|
||||||
"watcher:affirmation-request": "./scripts/start-worker.sh watcher affirmation-request-watcher",
|
"watcher:affirmation-request": "./scripts/start-worker.sh watcher affirmation-request-watcher",
|
||||||
"watcher:transfer": "./scripts/start-worker.sh watcher transfer-watcher",
|
"watcher:transfer": "./scripts/start-worker.sh watcher transfer-watcher",
|
||||||
|
"watcher:half-duplex-transfer": "./scripts/start-worker.sh watcher half-duplex-transfer-watcher",
|
||||||
|
"worker:swap-tokens": "./scripts/start-worker.sh worker swap-tokens-worker",
|
||||||
"worker:convert-to-chai": "./scripts/start-worker.sh worker convert-to-chai-worker",
|
"worker:convert-to-chai": "./scripts/start-worker.sh worker convert-to-chai-worker",
|
||||||
"sender:home": "./scripts/start-worker.sh sender home-sender",
|
"sender:home": "./scripts/start-worker.sh sender home-sender",
|
||||||
"sender:foreign": "./scripts/start-worker.sh sender foreign-sender",
|
"sender:foreign": "./scripts/start-worker.sh sender foreign-sender",
|
||||||
"confirm:transfer": "./scripts/start-worker.sh confirmRelay transfer-watcher",
|
"confirm:transfer": "./scripts/start-worker.sh confirmRelay transfer-watcher",
|
||||||
"dev": "concurrently -n 'watcher:signature-request,watcher:collected-signatures,watcher:affirmation-request,watcher:transfer, sender:home,sender:foreign' -c 'red,green,yellow,blue,magenta,cyan' 'yarn watcher:signature-request' 'yarn watcher:collected-signatures' 'yarn watcher:affirmation-request' 'yarn watcher:transfer' 'yarn sender:home' 'yarn sender:foreign'",
|
"dev": "concurrently -n 'watcher:signature-request,watcher:collected-signatures,watcher:affirmation-request,watcher:transfer,watcher:half-duplex-transfer, worker:swap-tokens, sender:home,sender:foreign' -c 'red,green,yellow,blue,white,gray,magenta,cyan' 'yarn watcher:signature-request' 'yarn watcher:collected-signatures' 'yarn watcher:affirmation-request' 'yarn watcher:transfer' 'yarn watcher:half-duplex-transfer' 'yarn worker:swap-tokens' 'yarn sender:home' 'yarn sender:foreign'",
|
||||||
"test": "NODE_ENV=test mocha",
|
"test": "NODE_ENV=test mocha",
|
||||||
"test:watch": "NODE_ENV=test mocha --watch --reporter=min",
|
"test:watch": "NODE_ENV=test mocha --watch --reporter=min",
|
||||||
"coverage": "NODE_ENV=test nyc --reporter=text --reporter=html mocha",
|
"coverage": "NODE_ENV=test nyc --reporter=text --reporter=html mocha",
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ const rpcUrlsManager = require('./services/getRpcUrlsManager')
|
|||||||
const { getNonce, getChainId, getEventsFromTx } = require('./tx/web3')
|
const { getNonce, getChainId, getEventsFromTx } = require('./tx/web3')
|
||||||
const { sendTx } = require('./tx/sendTx')
|
const { sendTx } = require('./tx/sendTx')
|
||||||
const { checkHTTPS, watchdog, syncForEach, addExtraGas } = require('./utils/utils')
|
const { checkHTTPS, watchdog, syncForEach, addExtraGas } = require('./utils/utils')
|
||||||
const { EXIT_CODES, EXTRA_GAS_PERCENTAGE, MAX_GAS_LIMIT } = require('./utils/constants')
|
const { EXIT_CODES, EXTRA_GAS_PERCENTAGE } = require('./utils/constants')
|
||||||
|
|
||||||
const { ORACLE_VALIDATOR_ADDRESS, ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY, ORACLE_ALLOW_HTTP_FOR_RPC } = process.env
|
const { ORACLE_VALIDATOR_ADDRESS, ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY, ORACLE_ALLOW_HTTP_FOR_RPC } = process.env
|
||||||
|
|
||||||
@@ -138,22 +138,17 @@ async function main({ sendJob, txHash }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function sendJobTx(jobs) {
|
async function sendJobTx(jobs) {
|
||||||
const gasPrice = await GasPrice.start(config.chain, true)
|
const gasPrice = await GasPrice.start(config.queue, true)
|
||||||
const chainId = await getChainId(config.chain)
|
const chainId = await getChainId(config.queue)
|
||||||
let nonce = await getNonce(web3Instance, ORACLE_VALIDATOR_ADDRESS)
|
let nonce = await getNonce(web3Instance, ORACLE_VALIDATOR_ADDRESS)
|
||||||
|
|
||||||
await syncForEach(jobs, async job => {
|
await syncForEach(jobs, async job => {
|
||||||
let gasLimit
|
const gasLimit = addExtraGas(job.gasEstimate, EXTRA_GAS_PERCENTAGE)
|
||||||
if (typeof job.extraGas === 'number') {
|
|
||||||
gasLimit = addExtraGas(job.gasEstimate + job.extraGas, 0, MAX_GAS_LIMIT)
|
|
||||||
} else {
|
|
||||||
gasLimit = addExtraGas(job.gasEstimate, EXTRA_GAS_PERCENTAGE, MAX_GAS_LIMIT)
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
logger.info(`Sending transaction with nonce ${nonce}`)
|
logger.info(`Sending transaction with nonce ${nonce}`)
|
||||||
const txHash = await sendTx({
|
const txHash = await sendTx({
|
||||||
chain: config.chain,
|
chain: config.queue,
|
||||||
data: job.data,
|
data: job.data,
|
||||||
nonce,
|
nonce,
|
||||||
gasPrice: gasPrice.toString(10),
|
gasPrice: gasPrice.toString(10),
|
||||||
|
|||||||
@@ -4,11 +4,6 @@ const logger = require('../../services/logger').child({
|
|||||||
module: 'processAffirmationRequests:estimateGas'
|
module: 'processAffirmationRequests:estimateGas'
|
||||||
})
|
})
|
||||||
const { parseAMBHeader } = require('../../utils/message')
|
const { parseAMBHeader } = require('../../utils/message')
|
||||||
const { strip0x } = require('../../../../commons')
|
|
||||||
const {
|
|
||||||
AMB_AFFIRMATION_REQUEST_EXTRA_GAS_ESTIMATOR: estimateExtraGas,
|
|
||||||
MIN_AMB_HEADER_LENGTH
|
|
||||||
} = require('../../utils/constants')
|
|
||||||
|
|
||||||
async function estimateGas({ web3, homeBridge, validatorContract, message, address }) {
|
async function estimateGas({ web3, homeBridge, validatorContract, message, address }) {
|
||||||
try {
|
try {
|
||||||
@@ -16,10 +11,10 @@ async function estimateGas({ web3, homeBridge, validatorContract, message, addre
|
|||||||
from: address
|
from: address
|
||||||
})
|
})
|
||||||
const msgGasLimit = parseAMBHeader(message).gasLimit
|
const msgGasLimit = parseAMBHeader(message).gasLimit
|
||||||
// message length in bytes
|
|
||||||
const len = strip0x(message).length / 2 - MIN_AMB_HEADER_LENGTH
|
|
||||||
|
|
||||||
return gasEstimate + msgGasLimit + estimateExtraGas(len)
|
logger.info({ gasEstimate, msgGasLimit }, 'Gas consumption parameters')
|
||||||
|
|
||||||
|
return gasEstimate + msgGasLimit + ( message.length * 32 )
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof HttpListProviderError) {
|
if (e instanceof HttpListProviderError) {
|
||||||
throw e
|
throw e
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ const promiseLimit = require('promise-limit')
|
|||||||
const rootLogger = require('../../services/logger')
|
const rootLogger = require('../../services/logger')
|
||||||
const { web3Home } = require('../../services/web3')
|
const { web3Home } = require('../../services/web3')
|
||||||
const bridgeValidatorsABI = require('../../../../contracts/build/contracts/BridgeValidators').abi
|
const bridgeValidatorsABI = require('../../../../contracts/build/contracts/BridgeValidators').abi
|
||||||
const { EXIT_CODES, MAX_CONCURRENT_EVENTS, EXTRA_GAS_ABSOLUTE } = require('../../utils/constants')
|
const { EXIT_CODES, MAX_CONCURRENT_EVENTS } = require('../../utils/constants')
|
||||||
const estimateGas = require('./estimateGas')
|
const estimateGas = require('./estimateGas')
|
||||||
const { parseAMBMessage } = require('../../../../commons')
|
const { parseAMBMessage } = require('../../../../commons')
|
||||||
const { AlreadyProcessedError, AlreadySignedError, InvalidValidatorError } = require('../../utils/errors')
|
const { AlreadyProcessedError, AlreadySignedError, InvalidValidatorError } = require('../../utils/errors')
|
||||||
@@ -75,7 +75,6 @@ function processAffirmationRequestsBuilder(config) {
|
|||||||
txToSend.push({
|
txToSend.push({
|
||||||
data,
|
data,
|
||||||
gasEstimate,
|
gasEstimate,
|
||||||
extraGas: EXTRA_GAS_ABSOLUTE,
|
|
||||||
transactionReference: affirmationRequest.transactionHash,
|
transactionReference: affirmationRequest.transactionHash,
|
||||||
to: config.homeBridgeAddress
|
to: config.homeBridgeAddress
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -27,10 +27,9 @@ async function estimateGas({
|
|||||||
})
|
})
|
||||||
const msgGasLimit = parseAMBHeader(message).gasLimit
|
const msgGasLimit = parseAMBHeader(message).gasLimit
|
||||||
|
|
||||||
// + estimateExtraGas(len)
|
logger.info({ gasEstimate, msgGasLimit }, 'Gas consumption parameters')
|
||||||
// is not needed here, since estimateGas will already take into account gas
|
|
||||||
// needed for memory expansion, message processing, etc.
|
return gasEstimate + msgGasLimit + ( message.length * 32 )
|
||||||
return gasEstimate + msgGasLimit
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof HttpListProviderError) {
|
if (e instanceof HttpListProviderError) {
|
||||||
throw e
|
throw e
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ const { signatureToVRS, packSignatures } = require('../../utils/message')
|
|||||||
const { parseAMBMessage } = require('../../../../commons')
|
const { parseAMBMessage } = require('../../../../commons')
|
||||||
const estimateGas = require('./estimateGas')
|
const estimateGas = require('./estimateGas')
|
||||||
const { AlreadyProcessedError, IncompatibleContractError, InvalidValidatorError } = require('../../utils/errors')
|
const { AlreadyProcessedError, IncompatibleContractError, InvalidValidatorError } = require('../../utils/errors')
|
||||||
const { MAX_CONCURRENT_EVENTS, EXTRA_GAS_ABSOLUTE } = require('../../utils/constants')
|
const { MAX_CONCURRENT_EVENTS } = require('../../utils/constants')
|
||||||
|
|
||||||
const limit = promiseLimit(MAX_CONCURRENT_EVENTS)
|
const limit = promiseLimit(MAX_CONCURRENT_EVENTS)
|
||||||
|
|
||||||
@@ -107,7 +107,6 @@ function processCollectedSignaturesBuilder(config) {
|
|||||||
txToSend.push({
|
txToSend.push({
|
||||||
data,
|
data,
|
||||||
gasEstimate,
|
gasEstimate,
|
||||||
extraGas: EXTRA_GAS_ABSOLUTE,
|
|
||||||
transactionReference: colSignature.transactionHash,
|
transactionReference: colSignature.transactionHash,
|
||||||
to: config.foreignBridgeAddress
|
to: config.foreignBridgeAddress
|
||||||
})
|
})
|
||||||
|
|||||||
134
oracle/src/events/processHalfDuplexTransfers/index.js
Normal file
134
oracle/src/events/processHalfDuplexTransfers/index.js
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
require('../../../env')
|
||||||
|
const promiseLimit = require('promise-limit')
|
||||||
|
const { HttpListProviderError } = require('http-list-provider')
|
||||||
|
const { BRIDGE_VALIDATORS_ABI, ZERO_ADDRESS } = require('../../../../commons')
|
||||||
|
const rootLogger = require('../../services/logger')
|
||||||
|
const { web3Home, web3Foreign } = require('../../services/web3')
|
||||||
|
const { AlreadyProcessedError, AlreadySignedError, InvalidValidatorError } = require('../../utils/errors')
|
||||||
|
const { EXIT_CODES, MAX_CONCURRENT_EVENTS } = require('../../utils/constants')
|
||||||
|
const estimateGas = require('../processAffirmationRequests/estimateGas')
|
||||||
|
|
||||||
|
const limit = promiseLimit(MAX_CONCURRENT_EVENTS)
|
||||||
|
|
||||||
|
let validatorContract = null
|
||||||
|
|
||||||
|
function processTransfersBuilder(config) {
|
||||||
|
const homeBridge = new web3Home.eth.Contract(config.homeBridgeAbi, config.homeBridgeAddress)
|
||||||
|
const foreignBridge = new web3Foreign.eth.Contract(config.foreignBridgeAbi, config.foreignBridgeAddress)
|
||||||
|
const userRequestForAffirmationAbi = config.foreignBridgeAbi.filter(
|
||||||
|
e => e.type === 'event' && e.name === 'UserRequestForAffirmation'
|
||||||
|
)[0]
|
||||||
|
const tokensSwappedAbi = config.foreignBridgeAbi.filter(e => e.type === 'event' && e.name === 'TokensSwapped')[0]
|
||||||
|
const userRequestForAffirmationHash = web3Home.eth.abi.encodeEventSignature(userRequestForAffirmationAbi)
|
||||||
|
const tokensSwappedHash = tokensSwappedAbi ? web3Home.eth.abi.encodeEventSignature(tokensSwappedAbi) : '0x'
|
||||||
|
|
||||||
|
return async function processTransfers(transfers, blockNumber) {
|
||||||
|
const txToSend = []
|
||||||
|
|
||||||
|
if (validatorContract === null) {
|
||||||
|
rootLogger.debug('Getting validator contract address')
|
||||||
|
const validatorContractAddress = await homeBridge.methods.validatorContract().call()
|
||||||
|
rootLogger.debug({ validatorContractAddress }, 'Validator contract address obtained')
|
||||||
|
|
||||||
|
validatorContract = new web3Home.eth.Contract(BRIDGE_VALIDATORS_ABI, validatorContractAddress)
|
||||||
|
}
|
||||||
|
|
||||||
|
rootLogger.debug(`Processing ${transfers.length} Transfer events`)
|
||||||
|
const callbacks = transfers
|
||||||
|
.map(transfer => async () => {
|
||||||
|
const { from, value } = transfer.returnValues
|
||||||
|
|
||||||
|
const logger = rootLogger.child({
|
||||||
|
eventTransactionHash: transfer.transactionHash
|
||||||
|
})
|
||||||
|
|
||||||
|
logger.info({ from, value }, `Processing transfer ${transfer.transactionHash}`)
|
||||||
|
|
||||||
|
const block = await web3Foreign.eth.getBlock(blockNumber)
|
||||||
|
logger.debug({ blockNumber, timestamp: block.timestamp }, `Block obtained`)
|
||||||
|
|
||||||
|
const tokenSwapAllowed = await foreignBridge.methods.isTokenSwapAllowed(block.timestamp).call()
|
||||||
|
|
||||||
|
if (!tokenSwapAllowed) {
|
||||||
|
logger.info(
|
||||||
|
`Transfer event discarded because SCD Emergency Shutdown has happened ${transfer.transactionHash}`
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const receipt = await web3Foreign.eth.getTransactionReceipt(transfer.transactionHash)
|
||||||
|
|
||||||
|
const existsAffirmationEvent = receipt.logs.some(
|
||||||
|
e => e.address === config.foreignBridgeAddress && e.topics[0] === userRequestForAffirmationHash
|
||||||
|
)
|
||||||
|
|
||||||
|
if (existsAffirmationEvent) {
|
||||||
|
logger.info(
|
||||||
|
`Transfer event discarded because a transaction with alternative receiver detected in transaction ${
|
||||||
|
transfer.transactionHash
|
||||||
|
}`
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const existsTokensSwappedEvent = tokensSwappedAbi
|
||||||
|
? receipt.logs.some(e => e.address === config.foreignBridgeAddress && e.topics[0] === tokensSwappedHash)
|
||||||
|
: false
|
||||||
|
|
||||||
|
if (from === ZERO_ADDRESS && existsTokensSwappedEvent) {
|
||||||
|
logger.info(
|
||||||
|
`Transfer event discarded because token swap is detected in transaction ${transfer.transactionHash}`
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let gasEstimate
|
||||||
|
try {
|
||||||
|
logger.debug('Estimate gas')
|
||||||
|
gasEstimate = await estimateGas({
|
||||||
|
web3: web3Home,
|
||||||
|
homeBridge,
|
||||||
|
validatorContract,
|
||||||
|
recipient: from,
|
||||||
|
value,
|
||||||
|
txHash: transfer.transactionHash,
|
||||||
|
address: config.validatorAddress
|
||||||
|
})
|
||||||
|
logger.debug({ gasEstimate }, 'Gas estimated')
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof HttpListProviderError) {
|
||||||
|
throw new Error('RPC Connection Error: submitSignature Gas Estimate cannot be obtained.')
|
||||||
|
} else if (e instanceof InvalidValidatorError) {
|
||||||
|
logger.fatal({ address: config.validatorAddress }, 'Invalid validator')
|
||||||
|
process.exit(EXIT_CODES.INCOMPATIBILITY)
|
||||||
|
} else if (e instanceof AlreadySignedError) {
|
||||||
|
logger.info(`Already signed transfer ${transfer.transactionHash}`)
|
||||||
|
return
|
||||||
|
} else if (e instanceof AlreadyProcessedError) {
|
||||||
|
logger.info(`transfer ${transfer.transactionHash} was already processed by other validators`)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
logger.error(e, 'Unknown error while processing transaction')
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await homeBridge.methods
|
||||||
|
.executeAffirmation(from, value, transfer.transactionHash)
|
||||||
|
.encodeABI({ from: config.validatorAddress })
|
||||||
|
|
||||||
|
txToSend.push({
|
||||||
|
data,
|
||||||
|
gasEstimate,
|
||||||
|
transactionReference: transfer.transactionHash,
|
||||||
|
to: config.homeBridgeAddress
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.map(promise => limit(promise))
|
||||||
|
|
||||||
|
await Promise.all(callbacks)
|
||||||
|
return txToSend
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = processTransfersBuilder
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
require('../env')
|
require('../env')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const { toBN } = require('web3-utils')
|
|
||||||
const { connectSenderToQueue } = require('./services/amqpClient')
|
const { connectSenderToQueue } = require('./services/amqpClient')
|
||||||
const { redis } = require('./services/redisClient')
|
const { redis } = require('./services/redisClient')
|
||||||
const GasPrice = require('./services/gasPrice')
|
const GasPrice = require('./services/gasPrice')
|
||||||
@@ -17,7 +16,7 @@ const {
|
|||||||
watchdog,
|
watchdog,
|
||||||
nonceError
|
nonceError
|
||||||
} = require('./utils/utils')
|
} = require('./utils/utils')
|
||||||
const { EXIT_CODES, EXTRA_GAS_PERCENTAGE, MAX_GAS_LIMIT } = require('./utils/constants')
|
const { EXIT_CODES, EXTRA_GAS_ABSOLUTE } = require('./utils/constants')
|
||||||
|
|
||||||
const { ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY } = process.env
|
const { ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY } = process.env
|
||||||
|
|
||||||
@@ -46,7 +45,6 @@ async function initialize() {
|
|||||||
chainId = await getChainId(config.id)
|
chainId = await getChainId(config.id)
|
||||||
connectSenderToQueue({
|
connectSenderToQueue({
|
||||||
queueName: config.queue,
|
queueName: config.queue,
|
||||||
oldQueueName: config.oldQueue,
|
|
||||||
cb: options => {
|
cb: options => {
|
||||||
if (config.maxProcessingTime) {
|
if (config.maxProcessingTime) {
|
||||||
return watchdog(() => main(options), config.maxProcessingTime, () => {
|
return watchdog(() => main(options), config.maxProcessingTime, () => {
|
||||||
@@ -90,7 +88,7 @@ function updateNonce(nonce) {
|
|||||||
return redis.set(nonceKey, nonce)
|
return redis.set(nonceKey, nonce)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function main({ msg, ackMsg, nackMsg, channel, scheduleForRetry, scheduleTransactionResend }) {
|
async function main({ msg, ackMsg, nackMsg, channel, scheduleForRetry }) {
|
||||||
try {
|
try {
|
||||||
if (redis.status !== 'ready') {
|
if (redis.status !== 'ready') {
|
||||||
nackMsg(msg)
|
nackMsg(msg)
|
||||||
@@ -105,55 +103,17 @@ async function main({ msg, ackMsg, nackMsg, channel, scheduleForRetry, scheduleT
|
|||||||
let insufficientFunds = false
|
let insufficientFunds = false
|
||||||
let minimumBalance = null
|
let minimumBalance = null
|
||||||
const failedTx = []
|
const failedTx = []
|
||||||
const sentTx = []
|
|
||||||
|
|
||||||
const isResend = txArray.length > 0 && !!txArray[0].txHash
|
logger.debug(`Sending ${txArray.length} transactions`)
|
||||||
|
|
||||||
if (isResend) {
|
|
||||||
logger.debug(`Checking status of ${txArray.length} transactions`)
|
|
||||||
} else {
|
|
||||||
logger.debug(`Sending ${txArray.length} transactions`)
|
|
||||||
}
|
|
||||||
await syncForEach(txArray, async job => {
|
await syncForEach(txArray, async job => {
|
||||||
let gasLimit
|
const gasLimit = addExtraGas(job.gasEstimate, EXTRA_GAS_ABSOLUTE, logger)
|
||||||
if (typeof job.extraGas === 'number') {
|
|
||||||
gasLimit = addExtraGas(job.gasEstimate + job.extraGas, 0, MAX_GAS_LIMIT)
|
|
||||||
} else {
|
|
||||||
gasLimit = addExtraGas(job.gasEstimate, EXTRA_GAS_PERCENTAGE, MAX_GAS_LIMIT)
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let txNonce
|
logger.info(`Sending transaction with nonce ${nonce}`)
|
||||||
if (isResend) {
|
|
||||||
const tx = await web3Instance.eth.getTransaction(job.txHash)
|
|
||||||
|
|
||||||
if (tx === null) {
|
|
||||||
logger.info(`Transaction ${job.txHash} was not found, dropping it`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (tx.blockNumber !== null) {
|
|
||||||
logger.info(`Transaction ${job.txHash} was successfully mined`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.info(
|
|
||||||
`Previously sent transaction is stuck, updating gasPrice: ${tx.gasPrice} -> ${gasPrice.toString(10)}`
|
|
||||||
)
|
|
||||||
if (toBN(tx.gasPrice).gte(toBN(gasPrice))) {
|
|
||||||
logger.info("Gas price returned from the oracle didn't increase, will reinspect this transaction later")
|
|
||||||
sentTx.push(job)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
txNonce = tx.nonce
|
|
||||||
} else {
|
|
||||||
txNonce = nonce++
|
|
||||||
}
|
|
||||||
logger.info(`Sending transaction with nonce ${txNonce}`)
|
|
||||||
const txHash = await sendTx({
|
const txHash = await sendTx({
|
||||||
chain: config.id,
|
chain: config.id,
|
||||||
data: job.data,
|
data: job.data,
|
||||||
nonce: txNonce,
|
nonce,
|
||||||
gasPrice: gasPrice.toString(10),
|
gasPrice: gasPrice.toString(10),
|
||||||
amount: '0',
|
amount: '0',
|
||||||
gasLimit,
|
gasLimit,
|
||||||
@@ -162,11 +122,8 @@ async function main({ msg, ackMsg, nackMsg, channel, scheduleForRetry, scheduleT
|
|||||||
chainId,
|
chainId,
|
||||||
web3: web3Instance
|
web3: web3Instance
|
||||||
})
|
})
|
||||||
sentTx.push({
|
|
||||||
...job,
|
|
||||||
txHash
|
|
||||||
})
|
|
||||||
|
|
||||||
|
nonce++
|
||||||
logger.info(
|
logger.info(
|
||||||
{ eventTransactionHash: job.transactionReference, generatedTransactionHash: txHash },
|
{ eventTransactionHash: job.transactionReference, generatedTransactionHash: txHash },
|
||||||
`Tx generated ${txHash} for event Tx ${job.transactionReference}`
|
`Tx generated ${txHash} for event Tx ${job.transactionReference}`
|
||||||
@@ -201,10 +158,6 @@ async function main({ msg, ackMsg, nackMsg, channel, scheduleForRetry, scheduleT
|
|||||||
logger.info(`Sending ${failedTx.length} Failed Tx to Queue`)
|
logger.info(`Sending ${failedTx.length} Failed Tx to Queue`)
|
||||||
await scheduleForRetry(failedTx, msg.properties.headers['x-retries'])
|
await scheduleForRetry(failedTx, msg.properties.headers['x-retries'])
|
||||||
}
|
}
|
||||||
if (sentTx.length) {
|
|
||||||
logger.info(`Sending ${sentTx.length} Tx Delayed Resend Requests to Queue`)
|
|
||||||
await scheduleTransactionResend(sentTx)
|
|
||||||
}
|
|
||||||
ackMsg(msg)
|
ackMsg(msg)
|
||||||
logger.debug(`Finished processing msg`)
|
logger.debug(`Finished processing msg`)
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ function RpcUrlsManager(homeUrls, foreignUrls) {
|
|||||||
throw new Error(`Invalid foreignUrls: '${foreignUrls}'`)
|
throw new Error(`Invalid foreignUrls: '${foreignUrls}'`)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.homeUrls = homeUrls.split(' ')
|
this.homeUrls = homeUrls.split(',')
|
||||||
this.foreignUrls = foreignUrls.split(' ')
|
this.foreignUrls = foreignUrls.split(',')
|
||||||
}
|
}
|
||||||
|
|
||||||
RpcUrlsManager.prototype.tryEach = async function(chain, f, redundant = false) {
|
RpcUrlsManager.prototype.tryEach = async function(chain, f, redundant = false) {
|
||||||
|
|||||||
@@ -4,12 +4,6 @@ const dns = require('dns')
|
|||||||
const connection = require('amqp-connection-manager').connect(process.env.ORACLE_QUEUE_URL)
|
const connection = require('amqp-connection-manager').connect(process.env.ORACLE_QUEUE_URL)
|
||||||
const logger = require('./logger')
|
const logger = require('./logger')
|
||||||
const { getRetrySequence } = require('../utils/utils')
|
const { getRetrySequence } = require('../utils/utils')
|
||||||
const {
|
|
||||||
TRANSACTION_RESEND_TIMEOUT,
|
|
||||||
SENDER_QUEUE_MAX_PRIORITY,
|
|
||||||
SENDER_QUEUE_SEND_PRIORITY,
|
|
||||||
SENDER_QUEUE_CHECK_STATUS_PRIORITY
|
|
||||||
} = require('../utils/constants')
|
|
||||||
|
|
||||||
connection.on('connect', () => {
|
connection.on('connect', () => {
|
||||||
logger.info('Connected to amqp Broker')
|
logger.info('Connected to amqp Broker')
|
||||||
@@ -28,18 +22,16 @@ async function isAttached() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function connectWatcherToQueue({ queueName, workerQueue, cb }) {
|
function connectWatcherToQueue({ queueName, workerQueue, cb }) {
|
||||||
|
const queueList = workerQueue ? [queueName, workerQueue] : [queueName]
|
||||||
|
|
||||||
const channelWrapper = connection.createChannel({
|
const channelWrapper = connection.createChannel({
|
||||||
json: true,
|
json: true,
|
||||||
async setup(channel) {
|
setup(channel) {
|
||||||
await channel.assertQueue(queueName, { durable: true, maxPriority: SENDER_QUEUE_MAX_PRIORITY })
|
return Promise.all(queueList.map(queue => channel.assertQueue(queue, { durable: true })))
|
||||||
if (workerQueue) {
|
|
||||||
await channel.assertQueue(workerQueue, { durable: true })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const sendToQueue = data =>
|
const sendToQueue = data => channelWrapper.sendToQueue(queueName, data, { persistent: true })
|
||||||
channelWrapper.sendToQueue(queueName, data, { persistent: true, priority: SENDER_QUEUE_SEND_PRIORITY })
|
|
||||||
let sendToWorker
|
let sendToWorker
|
||||||
if (workerQueue) {
|
if (workerQueue) {
|
||||||
sendToWorker = data => channelWrapper.sendToQueue(workerQueue, data, { persistent: true })
|
sendToWorker = data => channelWrapper.sendToQueue(workerQueue, data, { persistent: true })
|
||||||
@@ -48,60 +40,38 @@ function connectWatcherToQueue({ queueName, workerQueue, cb }) {
|
|||||||
cb({ sendToQueue, sendToWorker, channel: channelWrapper })
|
cb({ sendToQueue, sendToWorker, channel: channelWrapper })
|
||||||
}
|
}
|
||||||
|
|
||||||
function connectSenderToQueue({ queueName, oldQueueName, cb }) {
|
function connectSenderToQueue({ queueName, cb }) {
|
||||||
const deadLetterExchange = `${queueName}-retry`
|
const deadLetterExchange = `${queueName}-retry`
|
||||||
|
|
||||||
async function resendMessagesToNewQueue(channel) {
|
|
||||||
logger.info(`Trying to check messages in the old non-priority queue ${queueName}`)
|
|
||||||
while (true) {
|
|
||||||
const msg = await channel.get(oldQueueName)
|
|
||||||
if (msg === false) {
|
|
||||||
logger.info(`No messages in the old queue ${oldQueueName} left`)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
logger.debug(`Message in the old queue ${oldQueueName} was found, redirecting it to the new queue ${queueName}`)
|
|
||||||
await channel.sendToQueue(queueName, msg.content, { persistent: true, priority: SENDER_QUEUE_SEND_PRIORITY })
|
|
||||||
await channel.ack(msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const channelWrapper = connection.createChannel({
|
const channelWrapper = connection.createChannel({
|
||||||
json: true
|
json: true
|
||||||
})
|
})
|
||||||
|
|
||||||
channelWrapper.addSetup(async channel => {
|
channelWrapper.addSetup(channel => {
|
||||||
await channel.assertExchange(deadLetterExchange, 'fanout', { durable: true })
|
return Promise.all([
|
||||||
await channel.assertQueue(queueName, { durable: true, maxPriority: SENDER_QUEUE_MAX_PRIORITY })
|
channel.assertExchange(deadLetterExchange, 'fanout', { durable: true }),
|
||||||
await channel.assertQueue(oldQueueName, { durable: true }).then(() => resendMessagesToNewQueue(channel))
|
channel.assertQueue(queueName, { durable: true }),
|
||||||
await channel.bindQueue(queueName, deadLetterExchange)
|
channel.bindQueue(queueName, deadLetterExchange),
|
||||||
await channel.prefetch(1)
|
channel.prefetch(1),
|
||||||
await channel.consume(queueName, msg =>
|
channel.consume(queueName, msg =>
|
||||||
cb({
|
cb({
|
||||||
msg,
|
msg,
|
||||||
channel: channelWrapper,
|
channel: channelWrapper,
|
||||||
ackMsg: job => channelWrapper.ack(job),
|
ackMsg: job => channelWrapper.ack(job),
|
||||||
nackMsg: job => channelWrapper.nack(job, false, true),
|
nackMsg: job => channelWrapper.nack(job, false, true),
|
||||||
scheduleForRetry: async (data, msgRetries = 0) => {
|
scheduleForRetry: async (data, msgRetries = 0) => {
|
||||||
await generateRetry({
|
await generateRetry({
|
||||||
data,
|
data,
|
||||||
msgRetries,
|
msgRetries,
|
||||||
channelWrapper,
|
channelWrapper,
|
||||||
channel,
|
channel,
|
||||||
queueName,
|
queueName,
|
||||||
deadLetterExchange
|
deadLetterExchange
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
scheduleTransactionResend: async data => {
|
})
|
||||||
await generateTransactionResend({
|
)
|
||||||
data,
|
])
|
||||||
channelWrapper,
|
|
||||||
channel,
|
|
||||||
queueName,
|
|
||||||
deadLetterExchange
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,73 +82,52 @@ function connectWorkerToQueue({ queueName, senderQueue, cb }) {
|
|||||||
json: true
|
json: true
|
||||||
})
|
})
|
||||||
|
|
||||||
channelWrapper.addSetup(async channel => {
|
channelWrapper.addSetup(channel => {
|
||||||
await channel.assertExchange(deadLetterExchange, 'fanout', { durable: true })
|
return Promise.all([
|
||||||
await channel.assertQueue(queueName, { durable: true })
|
channel.assertExchange(deadLetterExchange, 'fanout', { durable: true }),
|
||||||
await channel.assertQueue(senderQueue, { durable: true, maxPriority: SENDER_QUEUE_MAX_PRIORITY })
|
channel.assertQueue(queueName, { durable: true }),
|
||||||
await channel.bindQueue(queueName, deadLetterExchange)
|
channel.assertQueue(senderQueue, { durable: true }),
|
||||||
await channel.prefetch(1)
|
channel.bindQueue(queueName, deadLetterExchange),
|
||||||
await channel.consume(queueName, msg =>
|
channel.prefetch(1),
|
||||||
cb({
|
channel.consume(queueName, msg =>
|
||||||
msg,
|
cb({
|
||||||
channel: channelWrapper,
|
msg,
|
||||||
ackMsg: job => channelWrapper.ack(job),
|
channel: channelWrapper,
|
||||||
nackMsg: job => channelWrapper.nack(job, false, true),
|
ackMsg: job => channelWrapper.ack(job),
|
||||||
sendToSenderQueue: data =>
|
nackMsg: job => channelWrapper.nack(job, false, true),
|
||||||
channelWrapper.sendToQueue(senderQueue, data, { persistent: true, priority: SENDER_QUEUE_SEND_PRIORITY }),
|
sendToSenderQueue: data => channelWrapper.sendToQueue(senderQueue, data, { persistent: true }),
|
||||||
scheduleForRetry: async (data, msgRetries = 0) => {
|
scheduleForRetry: async (data, msgRetries = 0) => {
|
||||||
await generateRetry({
|
await generateRetry({
|
||||||
data,
|
data,
|
||||||
msgRetries,
|
msgRetries,
|
||||||
channelWrapper,
|
channelWrapper,
|
||||||
channel,
|
channel,
|
||||||
queueName,
|
queueName,
|
||||||
deadLetterExchange
|
deadLetterExchange
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
])
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function generateRetry({ data, msgRetries, channelWrapper, channel, queueName, deadLetterExchange }) {
|
async function generateRetry({ data, msgRetries, channelWrapper, channel, queueName, deadLetterExchange }) {
|
||||||
const retries = msgRetries + 1
|
const retries = msgRetries + 1
|
||||||
const delay = getRetrySequence(retries) * 1000
|
const delay = getRetrySequence(retries) * 1000
|
||||||
|
|
||||||
// New retry queue is created, and one message is send to it.
|
|
||||||
// Nobody consumes messages from this queue, so eventually the message will be dropped.
|
|
||||||
// `messageTtl` defines a timeout after which the message will be dropped out of the queue.
|
|
||||||
// When message is dropped, it will be resend into the specified `deadLetterExchange` with the updated `x-retries` header.
|
|
||||||
const retryQueue = `${queueName}-retry-${delay}`
|
const retryQueue = `${queueName}-retry-${delay}`
|
||||||
await channel.assertQueue(retryQueue, {
|
await channel.assertQueue(retryQueue, {
|
||||||
durable: true,
|
durable: true,
|
||||||
deadLetterExchange,
|
deadLetterExchange,
|
||||||
messageTtl: delay,
|
messageTtl: delay,
|
||||||
expires: delay * 10,
|
expires: delay * 10
|
||||||
maxPriority: SENDER_QUEUE_MAX_PRIORITY
|
|
||||||
})
|
})
|
||||||
await channelWrapper.sendToQueue(retryQueue, data, {
|
await channelWrapper.sendToQueue(retryQueue, data, {
|
||||||
persistent: true,
|
persistent: true,
|
||||||
priority: SENDER_QUEUE_SEND_PRIORITY,
|
|
||||||
headers: { 'x-retries': retries }
|
headers: { 'x-retries': retries }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function generateTransactionResend({ data, channelWrapper, channel, queueName, deadLetterExchange }) {
|
|
||||||
const retryQueue = `${queueName}-check-tx-status`
|
|
||||||
await channel.assertQueue(retryQueue, {
|
|
||||||
durable: true,
|
|
||||||
deadLetterExchange,
|
|
||||||
messageTtl: TRANSACTION_RESEND_TIMEOUT,
|
|
||||||
expires: TRANSACTION_RESEND_TIMEOUT * 10,
|
|
||||||
maxPriority: SENDER_QUEUE_MAX_PRIORITY
|
|
||||||
})
|
|
||||||
await channelWrapper.sendToQueue(retryQueue, data, {
|
|
||||||
priority: SENDER_QUEUE_CHECK_STATUS_PRIORITY,
|
|
||||||
persistent: true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
isAttached,
|
isAttached,
|
||||||
connectWatcherToQueue,
|
connectWatcherToQueue,
|
||||||
|
|||||||
@@ -73,14 +73,13 @@ async function start(chainId, fetchOnce) {
|
|||||||
throw new Error(`Unrecognized chainId '${chainId}'`)
|
throw new Error(`Unrecognized chainId '${chainId}'`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const fetchFn = gasPriceSupplierUrl === 'gas-price-oracle' ? null : () => fetch(gasPriceSupplierUrl)
|
|
||||||
if (fetchOnce) {
|
if (fetchOnce) {
|
||||||
await fetchGasPrice(speedType, factor, bridgeContract, fetchFn)
|
await fetchGasPrice(speedType, factor, bridgeContract, () => fetch(gasPriceSupplierUrl))
|
||||||
return getPrice()
|
return getPrice()
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchGasPriceInterval = setIntervalAndRun(
|
fetchGasPriceInterval = setIntervalAndRun(
|
||||||
() => fetchGasPrice(speedType, factor, bridgeContract, fetchFn),
|
() => fetchGasPrice(speedType, factor, bridgeContract, () => fetch(gasPriceSupplierUrl)),
|
||||||
updateInterval
|
updateInterval
|
||||||
)
|
)
|
||||||
return null
|
return null
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
EXTRA_GAS_PERCENTAGE: 4,
|
EXTRA_GAS_PERCENTAGE: 2,
|
||||||
EXTRA_GAS_ABSOLUTE: 200000,
|
EXTRA_GAS_ABSOLUTE: 500000,
|
||||||
AMB_AFFIRMATION_REQUEST_EXTRA_GAS_ESTIMATOR: len => Math.floor(0.0035 * len ** 2 + 40 * len),
|
|
||||||
MIN_AMB_HEADER_LENGTH: 32 + 20 + 20 + 4 + 2 + 1 + 2,
|
|
||||||
MAX_GAS_LIMIT: 10000000,
|
|
||||||
MAX_CONCURRENT_EVENTS: 50,
|
MAX_CONCURRENT_EVENTS: 50,
|
||||||
RETRY_CONFIG: {
|
RETRY_CONFIG: {
|
||||||
retries: 20,
|
retries: 20,
|
||||||
@@ -22,9 +19,5 @@ module.exports = {
|
|||||||
GAS_PRICE_BOUNDARIES: {
|
GAS_PRICE_BOUNDARIES: {
|
||||||
MIN: 1,
|
MIN: 1,
|
||||||
MAX: 250
|
MAX: 250
|
||||||
},
|
}
|
||||||
TRANSACTION_RESEND_TIMEOUT: 20 * 60 * 1000,
|
|
||||||
SENDER_QUEUE_MAX_PRIORITY: 10,
|
|
||||||
SENDER_QUEUE_SEND_PRIORITY: 5,
|
|
||||||
SENDER_QUEUE_CHECK_STATUS_PRIORITY: 1
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,21 @@ async function getTokensState(bridgeContract, logger) {
|
|||||||
throw new Error(`Bridgeable token address cannot be obtained`)
|
throw new Error(`Bridgeable token address cannot be obtained`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
logger.debug('Getting Half Duplex token address')
|
||||||
|
const halfDuplexErc20tokenAddress = await bridgeContract.methods.halfDuplexErc20token().call()
|
||||||
|
logger.debug({ address: halfDuplexErc20tokenAddress }, 'Half Duplex token address obtained')
|
||||||
|
if (halfDuplexErc20tokenAddress !== context.bridgeableTokenAddress) {
|
||||||
|
context.halfDuplexTokenAddress = halfDuplexErc20tokenAddress
|
||||||
|
} else {
|
||||||
|
logger.info('Migration to support two tokens was not applied')
|
||||||
|
context.idle = true
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
logger.info('Old version of contracts is used')
|
||||||
|
context.idle = true
|
||||||
|
}
|
||||||
|
|
||||||
return context
|
return context
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ async function waitForFunds(web3, address, minimumBalance, cb, logger) {
|
|||||||
async retry => {
|
async retry => {
|
||||||
logger.debug('Getting balance of validator account')
|
logger.debug('Getting balance of validator account')
|
||||||
const newBalance = web3.utils.toBN(await web3.eth.getBalance(address))
|
const newBalance = web3.utils.toBN(await web3.eth.getBalance(address))
|
||||||
if (newBalance.gte(web3.utils.toBN(minimumBalance.toString(10)))) {
|
if (newBalance.gte(minimumBalance)) {
|
||||||
logger.debug({ balance: newBalance, minimumBalance }, 'Validator has minimum necessary balance')
|
logger.debug({ balance: newBalance, minimumBalance }, 'Validator has minimum necessary balance')
|
||||||
cb(newBalance)
|
cb(newBalance)
|
||||||
} else {
|
} else {
|
||||||
@@ -48,13 +48,13 @@ async function waitForFunds(web3, address, minimumBalance, cb, logger) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function addExtraGas(gas, extraPercentage, maxGasLimit = Infinity) {
|
function addExtraGas(gas, extra, logger) {
|
||||||
gas = BigNumber(gas)
|
gas = BigNumber(gas)
|
||||||
extraPercentage = BigNumber(1 + extraPercentage)
|
const gasWithExtra = gas.plus(extra).toFixed(0)
|
||||||
|
|
||||||
const gasWithExtra = gas.multipliedBy(extraPercentage).toFixed(0)
|
logger.info({ gasEstimated: gasWithExtra }, 'Gas Limit used')
|
||||||
|
|
||||||
return BigNumber.min(maxGasLimit, gasWithExtra)
|
return BigNumber(gasWithExtra)
|
||||||
}
|
}
|
||||||
|
|
||||||
function setIntervalAndRun(f, interval) {
|
function setIntervalAndRun(f, interval) {
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ const processSignatureRequests = require('./events/processSignatureRequests')(co
|
|||||||
const processCollectedSignatures = require('./events/processCollectedSignatures')(config)
|
const processCollectedSignatures = require('./events/processCollectedSignatures')(config)
|
||||||
const processAffirmationRequests = require('./events/processAffirmationRequests')(config)
|
const processAffirmationRequests = require('./events/processAffirmationRequests')(config)
|
||||||
const processTransfers = require('./events/processTransfers')(config)
|
const processTransfers = require('./events/processTransfers')(config)
|
||||||
|
const processHalfDuplexTransfers = require('./events/processHalfDuplexTransfers')(config)
|
||||||
const processAMBSignatureRequests = require('./events/processAMBSignatureRequests')(config)
|
const processAMBSignatureRequests = require('./events/processAMBSignatureRequests')(config)
|
||||||
const processAMBCollectedSignatures = require('./events/processAMBCollectedSignatures')(config)
|
const processAMBCollectedSignatures = require('./events/processAMBCollectedSignatures')(config)
|
||||||
const processAMBAffirmationRequests = require('./events/processAMBAffirmationRequests')(config)
|
const processAMBAffirmationRequests = require('./events/processAMBAffirmationRequests')(config)
|
||||||
@@ -35,6 +36,7 @@ const web3Instance = config.web3
|
|||||||
const bridgeContract = new web3Instance.eth.Contract(config.bridgeAbi, config.bridgeContractAddress)
|
const bridgeContract = new web3Instance.eth.Contract(config.bridgeAbi, config.bridgeContractAddress)
|
||||||
let { eventContractAddress } = config
|
let { eventContractAddress } = config
|
||||||
let eventContract = new web3Instance.eth.Contract(config.eventAbi, eventContractAddress)
|
let eventContract = new web3Instance.eth.Contract(config.eventAbi, eventContractAddress)
|
||||||
|
let skipEvents = config.idle
|
||||||
const lastBlockRedisKey = `${config.id}:lastProcessedBlock`
|
const lastBlockRedisKey = `${config.id}:lastProcessedBlock`
|
||||||
let lastProcessedBlock = BN.max(config.startBlock.sub(ONE), ZERO)
|
let lastProcessedBlock = BN.max(config.startBlock.sub(ONE), ZERO)
|
||||||
|
|
||||||
@@ -89,7 +91,7 @@ function updateLastProcessedBlock(lastBlockNumber) {
|
|||||||
return redis.set(lastBlockRedisKey, lastProcessedBlock.toString())
|
return redis.set(lastBlockRedisKey, lastProcessedBlock.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
function processEvents(events) {
|
function processEvents(events, blockNumber) {
|
||||||
switch (config.id) {
|
switch (config.id) {
|
||||||
case 'native-erc-signature-request':
|
case 'native-erc-signature-request':
|
||||||
case 'erc-erc-signature-request':
|
case 'erc-erc-signature-request':
|
||||||
@@ -107,6 +109,8 @@ function processEvents(events) {
|
|||||||
case 'erc-erc-transfer':
|
case 'erc-erc-transfer':
|
||||||
case 'erc-native-transfer':
|
case 'erc-native-transfer':
|
||||||
return processTransfers(events)
|
return processTransfers(events)
|
||||||
|
case 'erc-native-half-duplex-transfer':
|
||||||
|
return processHalfDuplexTransfers(events, blockNumber)
|
||||||
case 'amb-signature-request':
|
case 'amb-signature-request':
|
||||||
return processAMBSignatureRequests(events)
|
return processAMBSignatureRequests(events)
|
||||||
case 'amb-collected-signatures':
|
case 'amb-collected-signatures':
|
||||||
@@ -126,6 +130,12 @@ async function checkConditions() {
|
|||||||
state = await getTokensState(bridgeContract, logger)
|
state = await getTokensState(bridgeContract, logger)
|
||||||
updateEventContract(state.bridgeableTokenAddress)
|
updateEventContract(state.bridgeableTokenAddress)
|
||||||
break
|
break
|
||||||
|
case 'erc-native-half-duplex-transfer':
|
||||||
|
logger.debug('Getting Half Duplex token address to listen Transfer events')
|
||||||
|
state = await getTokensState(bridgeContract, logger)
|
||||||
|
skipEvents = state.idle
|
||||||
|
updateEventContract(state.halfDuplexTokenAddress)
|
||||||
|
break
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -161,6 +171,11 @@ async function main({ sendToQueue, sendToWorker }) {
|
|||||||
try {
|
try {
|
||||||
await checkConditions()
|
await checkConditions()
|
||||||
|
|
||||||
|
if (skipEvents) {
|
||||||
|
logger.debug('Watcher in idle mode, skipping getting events')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const lastBlockToProcess = await getLastBlockToProcess()
|
const lastBlockToProcess = await getLastBlockToProcess()
|
||||||
|
|
||||||
if (lastBlockToProcess.lte(lastProcessedBlock)) {
|
if (lastBlockToProcess.lte(lastProcessedBlock)) {
|
||||||
@@ -185,7 +200,7 @@ async function main({ sendToQueue, sendToWorker }) {
|
|||||||
await sendToWorker({ blockNumber: toBlock.toString() })
|
await sendToWorker({ blockNumber: toBlock.toString() })
|
||||||
}
|
}
|
||||||
|
|
||||||
const job = await processEvents(events)
|
const job = await processEvents(events, toBlock.toString())
|
||||||
logger.info('Transactions to send:', job.length)
|
logger.info('Transactions to send:', job.length)
|
||||||
|
|
||||||
if (job.length) {
|
if (job.length) {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ const { connectWorkerToQueue } = require('./services/amqpClient')
|
|||||||
|
|
||||||
const config = require(path.join('../config/', process.argv[2]))
|
const config = require(path.join('../config/', process.argv[2]))
|
||||||
|
|
||||||
|
const swapTokens = require('./workers/swapTokens')(config)
|
||||||
const convertToChai = require('./workers/convertToChai')(config)
|
const convertToChai = require('./workers/convertToChai')(config)
|
||||||
|
|
||||||
async function initialize() {
|
async function initialize() {
|
||||||
@@ -37,7 +38,9 @@ async function initialize() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function run(blockNumber) {
|
async function run(blockNumber) {
|
||||||
if (config.id === 'erc-native-convert-to-chai') {
|
if (config.id === 'erc-native-swap-tokens') {
|
||||||
|
return swapTokens(blockNumber)
|
||||||
|
} else if (config.id === 'erc-native-convert-to-chai') {
|
||||||
return convertToChai(blockNumber)
|
return convertToChai(blockNumber)
|
||||||
} else {
|
} else {
|
||||||
return []
|
return []
|
||||||
|
|||||||
111
oracle/src/workers/swapTokens.js
Normal file
111
oracle/src/workers/swapTokens.js
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
require('../../env')
|
||||||
|
const { HttpListProviderError } = require('http-list-provider')
|
||||||
|
const rootLogger = require('../services/logger')
|
||||||
|
const { web3Foreign } = require('../services/web3')
|
||||||
|
|
||||||
|
const { BRIDGE_VALIDATORS_ABI, ERC20_ABI } = require('../../../commons')
|
||||||
|
|
||||||
|
let validatorContract = null
|
||||||
|
let halfDuplexTokenContract = null
|
||||||
|
|
||||||
|
function swapTokensBuilder(config) {
|
||||||
|
const foreignBridge = new web3Foreign.eth.Contract(config.foreignBridgeAbi, config.foreignBridgeAddress)
|
||||||
|
|
||||||
|
return async function swapTokens(blockNumber) {
|
||||||
|
const txToSend = []
|
||||||
|
|
||||||
|
const logger = rootLogger.child({
|
||||||
|
blockNumber: blockNumber.toString()
|
||||||
|
})
|
||||||
|
|
||||||
|
logger.debug(`Starting swap tokens operation`)
|
||||||
|
|
||||||
|
if (validatorContract === null) {
|
||||||
|
logger.debug('Getting validator contract address')
|
||||||
|
const validatorContractAddress = await foreignBridge.methods.validatorContract().call()
|
||||||
|
logger.debug({ validatorContractAddress }, 'Validator contract address obtained')
|
||||||
|
|
||||||
|
validatorContract = new web3Foreign.eth.Contract(BRIDGE_VALIDATORS_ABI, validatorContractAddress)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debug(`Checking if is validator duty`)
|
||||||
|
const validatorDuty = await validatorContract.methods.isValidatorDuty(config.validatorAddress).call()
|
||||||
|
|
||||||
|
if (!validatorDuty) {
|
||||||
|
logger.info(`Token swap discarded because is not validator duty`)
|
||||||
|
return txToSend
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debug(`Checking if half duplex token balance is above the threshold`)
|
||||||
|
const hdTokenBalanceAboveMinBalance = await foreignBridge.methods.isHDTokenBalanceAboveMinBalance().call()
|
||||||
|
|
||||||
|
if (!hdTokenBalanceAboveMinBalance) {
|
||||||
|
logger.info(`Token swap discarded because half duplex balance is below the threshold`)
|
||||||
|
return txToSend
|
||||||
|
}
|
||||||
|
|
||||||
|
const block = await web3Foreign.eth.getBlock(blockNumber)
|
||||||
|
logger.debug({ timestamp: block.timestamp }, `Block obtained`)
|
||||||
|
|
||||||
|
logger.debug(`Checking if SCD Emergency Shutdown has happened`)
|
||||||
|
const tokenSwapAllowed = await foreignBridge.methods.isTokenSwapAllowed(block.timestamp).call()
|
||||||
|
|
||||||
|
if (!tokenSwapAllowed) {
|
||||||
|
logger.info(`Token swap discarded because SCD Emergency Shutdown has happened`)
|
||||||
|
return txToSend
|
||||||
|
}
|
||||||
|
|
||||||
|
let gasEstimate
|
||||||
|
|
||||||
|
try {
|
||||||
|
logger.debug(`Estimate gas`)
|
||||||
|
gasEstimate = await foreignBridge.methods.swapTokens().estimateGas({
|
||||||
|
from: config.validatorAddress
|
||||||
|
})
|
||||||
|
|
||||||
|
logger.debug({ gasEstimate }, 'Gas estimated')
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof HttpListProviderError) {
|
||||||
|
const errorMsg = 'RPC Connection Error: swapTokens Gas Estimate cannot be obtained.'
|
||||||
|
logger.error(e, errorMsg)
|
||||||
|
throw new Error(errorMsg)
|
||||||
|
} else {
|
||||||
|
if (halfDuplexTokenContract === null) {
|
||||||
|
logger.debug('Getting half duplex token contract address')
|
||||||
|
const halfDuplexErc20Token = await foreignBridge.methods.halfDuplexErc20token().call()
|
||||||
|
logger.debug({ halfDuplexErc20Token }, 'Half duplex token contract address obtained')
|
||||||
|
|
||||||
|
halfDuplexTokenContract = new web3Foreign.eth.Contract(ERC20_ABI, halfDuplexErc20Token)
|
||||||
|
}
|
||||||
|
|
||||||
|
const balance = web3Foreign.utils.toBN(
|
||||||
|
await halfDuplexTokenContract.methods.balanceOf(config.foreignBridgeAddress).call()
|
||||||
|
)
|
||||||
|
logger.debug({ balance: balance.toString() }, 'Half duplex token bridge balance obtained')
|
||||||
|
|
||||||
|
if (balance.isZero()) {
|
||||||
|
logger.info(`Gas estimate failed because half duplex token balance is zero. Tokens swap is discarded.`)
|
||||||
|
return txToSend
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.error(e, 'Unknown error while processing transaction')
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate data
|
||||||
|
const data = await foreignBridge.methods.swapTokens().encodeABI()
|
||||||
|
|
||||||
|
// push to job
|
||||||
|
txToSend.push({
|
||||||
|
data,
|
||||||
|
gasEstimate,
|
||||||
|
transactionReference: `swap tokens operation for block number ${blockNumber.toString()}`,
|
||||||
|
to: config.foreignBridgeAddress
|
||||||
|
})
|
||||||
|
|
||||||
|
return txToSend
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = swapTokensBuilder
|
||||||
@@ -73,7 +73,7 @@ describe('gasPrice', () => {
|
|||||||
await gasPrice.start('home')
|
await gasPrice.start('home')
|
||||||
|
|
||||||
// when
|
// when
|
||||||
await gasPrice.fetchGasPrice('standard', 1, null, () => null)
|
await gasPrice.fetchGasPrice('standard', 1, null, null)
|
||||||
|
|
||||||
// then
|
// then
|
||||||
expect(gasPrice.getPrice()).to.equal('101000000000')
|
expect(gasPrice.getPrice()).to.equal('101000000000')
|
||||||
@@ -113,7 +113,7 @@ describe('gasPrice', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// when
|
// when
|
||||||
await gasPrice.fetchGasPrice('standard', 1, bridgeContractMock, () => {})
|
await gasPrice.fetchGasPrice('standard', 1, bridgeContractMock, null)
|
||||||
|
|
||||||
// then
|
// then
|
||||||
expect(gasPrice.getPrice().toString()).to.equal('102000000000')
|
expect(gasPrice.getPrice().toString()).to.equal('102000000000')
|
||||||
@@ -156,7 +156,7 @@ describe('gasPrice', () => {
|
|||||||
await gasPrice.start('home')
|
await gasPrice.start('home')
|
||||||
|
|
||||||
// when
|
// when
|
||||||
await gasPrice.fetchGasPrice('standard', 1, null, () => {})
|
await gasPrice.fetchGasPrice('standard', 1, null, null)
|
||||||
|
|
||||||
// then
|
// then
|
||||||
expect(fakeLogger.error.calledTwice).to.equal(true) // two errors
|
expect(fakeLogger.error.calledTwice).to.equal(true) // two errors
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
const { BN, toBN } = require('web3').utils
|
const { BN, toBN } = require('web3').utils
|
||||||
const { expect } = require('chai').use(require('bn-chai')(BN))
|
const { expect } = require('chai').use(require('bn-chai')(BN))
|
||||||
const { createMessage, parseMessage, signatureToVRS, parseAMBHeader } = require('../src/utils/message')
|
const { createMessage, parseMessage, signatureToVRS } = require('../src/utils/message')
|
||||||
|
|
||||||
describe('message utils', () => {
|
describe('message utils', () => {
|
||||||
const expectedMessageLength = 104
|
const expectedMessageLength = 104
|
||||||
@@ -288,19 +288,4 @@ describe('message utils', () => {
|
|||||||
expect(signatureThunk).to.throw()
|
expect(signatureThunk).to.throw()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
describe('parseAMBHeader', () => {
|
|
||||||
it('should return correct values for parsed headers', () => {
|
|
||||||
// given
|
|
||||||
const message =
|
|
||||||
'0x000500009a6ff99b356dd998260582be7d95a4d08b2132600000000000000061339d0e6f308a410f18888932bdf661636a0f538f34718200957aeadd6bece186e61b95618e73a6dc000f42400101002a4d2fb102cf00000000000000000000000081c770bbe8f5f41b4642ed575e630c911c94e4070000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000002e516d543162324178466b6643456a6f715861547148734370666f724a4c66765667434853516e513847575a347662000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002e516d5a7543586f693378487338486e4c325a423539316674466f4c454471516b473655746e47324d6d513147614e000000000000000000000000000000000000'
|
|
||||||
|
|
||||||
const { messageId, sender, executor, gasLimit } = parseAMBHeader(message)
|
|
||||||
|
|
||||||
// then
|
|
||||||
expect(messageId).to.equal('0x000500009a6ff99b356dd998260582be7d95a4d08b2132600000000000000061')
|
|
||||||
expect(sender).to.equal('0x339d0e6f308a410f18888932bdf661636a0f538f')
|
|
||||||
expect(executor).to.equal('0x34718200957aeadd6bece186e61b95618e73a6dc')
|
|
||||||
expect(gasLimit).to.equal(1000000)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -34,14 +34,6 @@ describe('utils', () => {
|
|||||||
|
|
||||||
expect(result.toString()).to.equal('225')
|
expect(result.toString()).to.equal('225')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should handle maxGasLimit', () => {
|
|
||||||
const result1 = addExtraGas(new BigNumber(100), 0.25, 110)
|
|
||||||
const result2 = addExtraGas(new BigNumber(100), 0.25, 150)
|
|
||||||
|
|
||||||
expect(result1.toString()).to.equal('110')
|
|
||||||
expect(result2.toString()).to.equal('125')
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('checkHTTPS', () => {
|
describe('checkHTTPS', () => {
|
||||||
|
|||||||
@@ -43,7 +43,6 @@
|
|||||||
"test": "yarn wsrun --exclude oracle-e2e --exclude ui-e2e --exclude monitor-e2e --exclude alm-e2e test",
|
"test": "yarn wsrun --exclude oracle-e2e --exclude ui-e2e --exclude monitor-e2e --exclude alm-e2e test",
|
||||||
"oracle-e2e": "./oracle-e2e/run-tests.sh",
|
"oracle-e2e": "./oracle-e2e/run-tests.sh",
|
||||||
"ui-e2e": "./ui-e2e/run-tests.sh",
|
"ui-e2e": "./ui-e2e/run-tests.sh",
|
||||||
"ui-e2e:ci": "xvfb-run yarn ui-e2e",
|
|
||||||
"monitor-e2e": "./monitor-e2e/run-tests.sh",
|
"monitor-e2e": "./monitor-e2e/run-tests.sh",
|
||||||
"alm-e2e": "./alm-e2e/run-tests.sh",
|
"alm-e2e": "./alm-e2e/run-tests.sh",
|
||||||
"clean": "rm -rf ./node_modules ./**/node_modules ./**/**/node_modules ./**/build ./**/**/dist",
|
"clean": "rm -rf ./node_modules ./**/node_modules ./**/**/node_modules ./**/build ./**/**/dist",
|
||||||
|
|||||||
Binary file not shown.
@@ -3,7 +3,7 @@ const { By } = require('selenium-webdriver/lib/by')
|
|||||||
const { Page } = require('./Page.js')
|
const { Page } = require('./Page.js')
|
||||||
const { homeRPC, foreignRPC } = require('../e2e-commons/constants.json')
|
const { homeRPC, foreignRPC } = require('../e2e-commons/constants.json')
|
||||||
|
|
||||||
const IDMetaMask = 'hccmbhdehlhjhkenmcjnbcahkmljpife'
|
const IDMetaMask = 'dapggmdndodedfoaljbglbkaicfpmkkm'
|
||||||
const URL = 'chrome-extension://' + IDMetaMask + '//popup.html'
|
const URL = 'chrome-extension://' + IDMetaMask + '//popup.html'
|
||||||
const buttonSubmit = By.className('confirm btn-green')
|
const buttonSubmit = By.className('confirm btn-green')
|
||||||
const buttonAccept = By.xpath('//*[@id="app-content"]/div/div[4]/div/button')
|
const buttonAccept = By.xpath('//*[@id="app-content"]/div/div[4]/div/button')
|
||||||
|
|||||||
@@ -46,11 +46,8 @@ class Utils {
|
|||||||
static async startBrowserWithMetamask() {
|
static async startBrowserWithMetamask() {
|
||||||
const source = './MetaMask.crx'
|
const source = './MetaMask.crx'
|
||||||
const options = new chrome.Options()
|
const options = new chrome.Options()
|
||||||
await options.addArguments('--no-sandbox')
|
|
||||||
await options.addArguments('--disable-gpu')
|
|
||||||
await options.addArguments('--disable-dev-shm-usage')
|
|
||||||
await options.addArguments('disable-popup-blocking')
|
|
||||||
await options.addExtensions(source)
|
await options.addExtensions(source)
|
||||||
|
await options.addArguments('disable-popup-blocking')
|
||||||
const driver = await new webdriver.Builder().withCapabilities(options.toCapabilities()).build()
|
const driver = await new webdriver.Builder().withCapabilities(options.toCapabilities()).build()
|
||||||
await driver.sleep(5000)
|
await driver.sleep(5000)
|
||||||
return driver
|
return driver
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"private": true,
|
"private": true,
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"chromedriver": "^77.0.0",
|
||||||
"mocha": "^5.2.0",
|
"mocha": "^5.2.0",
|
||||||
"selenium-webdriver": "3.6.0"
|
"selenium-webdriver": "3.6.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
cd $(dirname $0)
|
cd $(dirname $0)
|
||||||
|
|
||||||
../e2e-commons/up.sh deploy oracle ui blocks
|
../e2e-commons/up.sh deploy oracle ui blocks
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ test.describe('e2e-test for bridge.poa, version 1.5.0', async function() {
|
|||||||
const shouldBe = homeBalanceBefore - maxAmountPerTransactionLimit
|
const shouldBe = homeBalanceBefore - maxAmountPerTransactionLimit
|
||||||
console.log('newHomeBalance = ' + newHomeBalance)
|
console.log('newHomeBalance = ' + newHomeBalance)
|
||||||
console.log('shouldBe = ' + shouldBe)
|
console.log('shouldBe = ' + shouldBe)
|
||||||
const result = Math.abs(shouldBe - newHomeBalance) < maxAmountPerTransactionLimit / 10
|
const result = Math.abs(shouldBe - newHomeBalance) < maxAmountPerTransactionLimit / 100
|
||||||
homeBalanceBefore = newHomeBalance
|
homeBalanceBefore = newHomeBalance
|
||||||
return await assert.strictEqual(result, true, 'Test FAILED.Home POA balance is not correct after transaction')
|
return await assert.strictEqual(result, true, 'Test FAILED.Home POA balance is not correct after transaction')
|
||||||
})
|
})
|
||||||
@@ -95,7 +95,7 @@ test.describe('e2e-test for bridge.poa, version 1.5.0', async function() {
|
|||||||
console.log('newForeignBalance = ' + newForeignBalance)
|
console.log('newForeignBalance = ' + newForeignBalance)
|
||||||
console.log('shouldBe = ' + shouldBe)
|
console.log('shouldBe = ' + shouldBe)
|
||||||
|
|
||||||
const result = Math.abs(shouldBe - newForeignBalance) < maxAmountPerTransactionLimit / 10
|
const result = Math.abs(shouldBe - newForeignBalance) < maxAmountPerTransactionLimit / 100
|
||||||
return await assert.strictEqual(result, true, 'Test FAILED. Foreign POA balance is not correct after transaction')
|
return await assert.strictEqual(result, true, 'Test FAILED. Foreign POA balance is not correct after transaction')
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -115,7 +115,7 @@ test.describe('e2e-test for bridge.poa, version 1.5.0', async function() {
|
|||||||
const shouldBe = foreignBalanceBefore - maxAmountPerTransactionLimit
|
const shouldBe = foreignBalanceBefore - maxAmountPerTransactionLimit
|
||||||
console.log('newForeignBalance = ' + newForeignBalance)
|
console.log('newForeignBalance = ' + newForeignBalance)
|
||||||
console.log('shouldBe = ' + shouldBe)
|
console.log('shouldBe = ' + shouldBe)
|
||||||
const result = Math.abs(shouldBe - newForeignBalance) < maxAmountPerTransactionLimit / 10
|
const result = Math.abs(shouldBe - newForeignBalance) < maxAmountPerTransactionLimit / 100
|
||||||
return await assert.strictEqual(result, true, 'Test FAILED.Foreign POA balance is not correct after transaction')
|
return await assert.strictEqual(result, true, 'Test FAILED.Foreign POA balance is not correct after transaction')
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -124,7 +124,7 @@ test.describe('e2e-test for bridge.poa, version 1.5.0', async function() {
|
|||||||
const shouldBe = homeBalanceBefore + maxAmountPerTransactionLimit
|
const shouldBe = homeBalanceBefore + maxAmountPerTransactionLimit
|
||||||
console.log('newHomeBalance = ' + newHomeBalance)
|
console.log('newHomeBalance = ' + newHomeBalance)
|
||||||
console.log('shouldBe = ' + shouldBe)
|
console.log('shouldBe = ' + shouldBe)
|
||||||
const result = Math.abs(shouldBe - newHomeBalance) < maxAmountPerTransactionLimit / 10
|
const result = Math.abs(shouldBe - newHomeBalance) < maxAmountPerTransactionLimit / 100
|
||||||
return await assert.strictEqual(result, true, 'Test FAILED.Home POA balance is not correct after transaction')
|
return await assert.strictEqual(result, true, 'Test FAILED.Home POA balance is not correct after transaction')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -173,7 +173,7 @@ test.describe('e2e-test for bridge.poa, version 1.5.0', async function() {
|
|||||||
const shouldBe = foreignBalanceBefore - maxAmountPerTransactionLimit
|
const shouldBe = foreignBalanceBefore - maxAmountPerTransactionLimit
|
||||||
console.log('newForeignBalance = ' + newForeignBalance)
|
console.log('newForeignBalance = ' + newForeignBalance)
|
||||||
console.log('shouldBe = ' + shouldBe)
|
console.log('shouldBe = ' + shouldBe)
|
||||||
const result = Math.abs(shouldBe - newForeignBalance) < maxAmountPerTransactionLimit / 10
|
const result = Math.abs(shouldBe - newForeignBalance) < maxAmountPerTransactionLimit / 100
|
||||||
return await assert.strictEqual(result, true, 'Test FAILED.Foreign POA balance is not correct after transaction')
|
return await assert.strictEqual(result, true, 'Test FAILED.Foreign POA balance is not correct after transaction')
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -182,7 +182,7 @@ test.describe('e2e-test for bridge.poa, version 1.5.0', async function() {
|
|||||||
const shouldBe = homeBalanceBefore + maxAmountPerTransactionLimit
|
const shouldBe = homeBalanceBefore + maxAmountPerTransactionLimit
|
||||||
console.log('newHomeBalance = ' + newHomeBalance)
|
console.log('newHomeBalance = ' + newHomeBalance)
|
||||||
console.log('shouldBe = ' + shouldBe)
|
console.log('shouldBe = ' + shouldBe)
|
||||||
const result = Math.abs(shouldBe - newHomeBalance) < maxAmountPerTransactionLimit / 10
|
const result = Math.abs(shouldBe - newHomeBalance) < maxAmountPerTransactionLimit / 100
|
||||||
return await assert.strictEqual(result, true, 'Test FAILED.Home POA balance is not correct after transaction')
|
return await assert.strictEqual(result, true, 'Test FAILED.Home POA balance is not correct after transaction')
|
||||||
})
|
})
|
||||||
test.it('User is able to send tokens from Home account to Foreign account ', async () => {
|
test.it('User is able to send tokens from Home account to Foreign account ', async () => {
|
||||||
@@ -202,7 +202,7 @@ test.describe('e2e-test for bridge.poa, version 1.5.0', async function() {
|
|||||||
const shouldBe = homeBalanceBefore - maxAmountPerTransactionLimit
|
const shouldBe = homeBalanceBefore - maxAmountPerTransactionLimit
|
||||||
console.log('newHomeBalance = ' + newHomeBalance)
|
console.log('newHomeBalance = ' + newHomeBalance)
|
||||||
console.log('shouldBe = ' + shouldBe)
|
console.log('shouldBe = ' + shouldBe)
|
||||||
const result = Math.abs(shouldBe - newHomeBalance) < maxAmountPerTransactionLimit / 10
|
const result = Math.abs(shouldBe - newHomeBalance) < maxAmountPerTransactionLimit / 100
|
||||||
homeBalanceBefore = newHomeBalance
|
homeBalanceBefore = newHomeBalance
|
||||||
return await assert.strictEqual(result, true, 'Test FAILED.Home POA balance is not correct after transaction')
|
return await assert.strictEqual(result, true, 'Test FAILED.Home POA balance is not correct after transaction')
|
||||||
})
|
})
|
||||||
@@ -214,7 +214,7 @@ test.describe('e2e-test for bridge.poa, version 1.5.0', async function() {
|
|||||||
console.log('newForeignBalance = ' + newForeignBalance)
|
console.log('newForeignBalance = ' + newForeignBalance)
|
||||||
console.log('shouldBe = ' + shouldBe)
|
console.log('shouldBe = ' + shouldBe)
|
||||||
|
|
||||||
const result = Math.abs(shouldBe - newForeignBalance) < maxAmountPerTransactionLimit / 10
|
const result = Math.abs(shouldBe - newForeignBalance) < maxAmountPerTransactionLimit / 100
|
||||||
return await assert.strictEqual(result, true, 'Test FAILED. Foreign POA balance is not correct after transaction')
|
return await assert.strictEqual(result, true, 'Test FAILED. Foreign POA balance is not correct after transaction')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -263,7 +263,7 @@ test.describe('e2e-test for bridge.poa, version 1.5.0', async function() {
|
|||||||
const shouldBe = foreignBalanceBefore - maxAmountPerTransactionLimit
|
const shouldBe = foreignBalanceBefore - maxAmountPerTransactionLimit
|
||||||
console.log('newForeignBalance = ' + newForeignBalance)
|
console.log('newForeignBalance = ' + newForeignBalance)
|
||||||
console.log('shouldBe = ' + shouldBe)
|
console.log('shouldBe = ' + shouldBe)
|
||||||
const result = Math.abs(shouldBe - newForeignBalance) < maxAmountPerTransactionLimit / 10
|
const result = Math.abs(shouldBe - newForeignBalance) < maxAmountPerTransactionLimit / 100
|
||||||
return await assert.strictEqual(result, true, 'Test FAILED.Foreign POA balance is not correct after transaction')
|
return await assert.strictEqual(result, true, 'Test FAILED.Foreign POA balance is not correct after transaction')
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -272,7 +272,7 @@ test.describe('e2e-test for bridge.poa, version 1.5.0', async function() {
|
|||||||
const shouldBe = homeBalanceBefore + maxAmountPerTransactionLimit
|
const shouldBe = homeBalanceBefore + maxAmountPerTransactionLimit
|
||||||
console.log('newHomeBalance = ' + newHomeBalance)
|
console.log('newHomeBalance = ' + newHomeBalance)
|
||||||
console.log('shouldBe = ' + shouldBe)
|
console.log('shouldBe = ' + shouldBe)
|
||||||
const result = Math.abs(shouldBe - newHomeBalance) < maxAmountPerTransactionLimit / 10
|
const result = Math.abs(shouldBe - newHomeBalance) < maxAmountPerTransactionLimit / 100
|
||||||
return await assert.strictEqual(result, true, 'Test FAILED.Home POA balance is not correct after transaction')
|
return await assert.strictEqual(result, true, 'Test FAILED.Home POA balance is not correct after transaction')
|
||||||
})
|
})
|
||||||
test.it('User is able to send tokens from Home account to Foreign account', async () => {
|
test.it('User is able to send tokens from Home account to Foreign account', async () => {
|
||||||
@@ -292,7 +292,7 @@ test.describe('e2e-test for bridge.poa, version 1.5.0', async function() {
|
|||||||
const shouldBe = homeBalanceBefore - maxAmountPerTransactionLimit
|
const shouldBe = homeBalanceBefore - maxAmountPerTransactionLimit
|
||||||
console.log('newHomeBalance = ' + newHomeBalance)
|
console.log('newHomeBalance = ' + newHomeBalance)
|
||||||
console.log('shouldBe = ' + shouldBe)
|
console.log('shouldBe = ' + shouldBe)
|
||||||
const result = Math.abs(shouldBe - newHomeBalance) < maxAmountPerTransactionLimit / 10
|
const result = Math.abs(shouldBe - newHomeBalance) < maxAmountPerTransactionLimit / 100
|
||||||
homeBalanceBefore = newHomeBalance
|
homeBalanceBefore = newHomeBalance
|
||||||
return await assert.strictEqual(result, true, 'Test FAILED.Home POA balance is not correct after transaction')
|
return await assert.strictEqual(result, true, 'Test FAILED.Home POA balance is not correct after transaction')
|
||||||
})
|
})
|
||||||
@@ -304,7 +304,7 @@ test.describe('e2e-test for bridge.poa, version 1.5.0', async function() {
|
|||||||
console.log('newForeignBalance = ' + newForeignBalance)
|
console.log('newForeignBalance = ' + newForeignBalance)
|
||||||
console.log('shouldBe = ' + shouldBe)
|
console.log('shouldBe = ' + shouldBe)
|
||||||
|
|
||||||
const result = Math.abs(shouldBe - newForeignBalance) < maxAmountPerTransactionLimit / 10
|
const result = Math.abs(shouldBe - newForeignBalance) < maxAmountPerTransactionLimit / 100
|
||||||
return await assert.strictEqual(result, true, 'Test FAILED. Foreign POA balance is not correct after transaction')
|
return await assert.strictEqual(result, true, 'Test FAILED. Foreign POA balance is not correct after transaction')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -353,7 +353,7 @@ test.describe('e2e-test for bridge.poa, version 1.5.0', async function() {
|
|||||||
const shouldBe = foreignBalanceBefore - maxAmountPerTransactionLimit
|
const shouldBe = foreignBalanceBefore - maxAmountPerTransactionLimit
|
||||||
console.log('newForeignBalance = ' + newForeignBalance)
|
console.log('newForeignBalance = ' + newForeignBalance)
|
||||||
console.log('shouldBe = ' + shouldBe)
|
console.log('shouldBe = ' + shouldBe)
|
||||||
const result = Math.abs(shouldBe - newForeignBalance) < maxAmountPerTransactionLimit / 10
|
const result = Math.abs(shouldBe - newForeignBalance) < maxAmountPerTransactionLimit / 100
|
||||||
return await assert.strictEqual(result, true, 'Test FAILED.Foreign POA balance is not correct after transaction')
|
return await assert.strictEqual(result, true, 'Test FAILED.Foreign POA balance is not correct after transaction')
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -362,7 +362,7 @@ test.describe('e2e-test for bridge.poa, version 1.5.0', async function() {
|
|||||||
const shouldBe = homeBalanceBefore + maxAmountPerTransactionLimit
|
const shouldBe = homeBalanceBefore + maxAmountPerTransactionLimit
|
||||||
console.log('newHomeBalance = ' + newHomeBalance)
|
console.log('newHomeBalance = ' + newHomeBalance)
|
||||||
console.log('shouldBe = ' + shouldBe)
|
console.log('shouldBe = ' + shouldBe)
|
||||||
const result = Math.abs(shouldBe - newHomeBalance) < maxAmountPerTransactionLimit / 10
|
const result = Math.abs(shouldBe - newHomeBalance) < maxAmountPerTransactionLimit / 100
|
||||||
return await assert.strictEqual(result, true, 'Test FAILED.Home POA balance is not correct after transaction')
|
return await assert.strictEqual(result, true, 'Test FAILED.Home POA balance is not correct after transaction')
|
||||||
})
|
})
|
||||||
test.it('User is able to send tokens from Home account to Foreign account', async () => {
|
test.it('User is able to send tokens from Home account to Foreign account', async () => {
|
||||||
@@ -382,7 +382,7 @@ test.describe('e2e-test for bridge.poa, version 1.5.0', async function() {
|
|||||||
const shouldBe = homeBalanceBefore - maxAmountPerTransactionLimit
|
const shouldBe = homeBalanceBefore - maxAmountPerTransactionLimit
|
||||||
console.log('newHomeBalance = ' + newHomeBalance)
|
console.log('newHomeBalance = ' + newHomeBalance)
|
||||||
console.log('shouldBe = ' + shouldBe)
|
console.log('shouldBe = ' + shouldBe)
|
||||||
const result = Math.abs(shouldBe - newHomeBalance) < maxAmountPerTransactionLimit / 10
|
const result = Math.abs(shouldBe - newHomeBalance) < maxAmountPerTransactionLimit / 100
|
||||||
homeBalanceBefore = newHomeBalance
|
homeBalanceBefore = newHomeBalance
|
||||||
return await assert.strictEqual(result, true, 'Test FAILED.Home POA balance is not correct after transaction')
|
return await assert.strictEqual(result, true, 'Test FAILED.Home POA balance is not correct after transaction')
|
||||||
})
|
})
|
||||||
@@ -394,7 +394,7 @@ test.describe('e2e-test for bridge.poa, version 1.5.0', async function() {
|
|||||||
console.log('newForeignBalance = ' + newForeignBalance)
|
console.log('newForeignBalance = ' + newForeignBalance)
|
||||||
console.log('shouldBe = ' + shouldBe)
|
console.log('shouldBe = ' + shouldBe)
|
||||||
|
|
||||||
const result = Math.abs(shouldBe - newForeignBalance) < maxAmountPerTransactionLimit / 10
|
const result = Math.abs(shouldBe - newForeignBalance) < maxAmountPerTransactionLimit / 100
|
||||||
return await assert.strictEqual(result, true, 'Test FAILED. Foreign POA balance is not correct after transaction')
|
return await assert.strictEqual(result, true, 'Test FAILED. Foreign POA balance is not correct after transaction')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM node:10 as contracts
|
FROM node:8 as contracts
|
||||||
|
|
||||||
WORKDIR /mono
|
WORKDIR /mono
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@ COPY ./contracts/truffle-config.js ./
|
|||||||
COPY ./contracts/contracts ./contracts
|
COPY ./contracts/contracts ./contracts
|
||||||
RUN npm run compile
|
RUN npm run compile
|
||||||
|
|
||||||
FROM node:10
|
FROM node:8
|
||||||
|
|
||||||
WORKDIR /mono
|
WORKDIR /mono
|
||||||
COPY package.json .
|
COPY package.json .
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/plugin-proposal-decorators": "^7.4.0",
|
"@babel/plugin-proposal-decorators": "^7.4.0",
|
||||||
"bignumber.js": "^6.0.0",
|
"bignumber.js": "^6.0.0",
|
||||||
|
"coveralls": "^3.0.0",
|
||||||
"customize-cra": "^0.2.12",
|
"customize-cra": "^0.2.12",
|
||||||
"date-fns": "^2.13.0",
|
"date-fns": "^2.13.0",
|
||||||
"dotenv": "^7.0.0",
|
"dotenv": "^7.0.0",
|
||||||
@@ -36,6 +37,7 @@
|
|||||||
"test": "react-app-rewired test --env=jsdom --no-watch",
|
"test": "react-app-rewired test --env=jsdom --no-watch",
|
||||||
"test:watch": "react-app-rewired test --env=jsdom",
|
"test:watch": "react-app-rewired test --env=jsdom",
|
||||||
"coverage": "react-app-rewired test --env=jsdom --coverage",
|
"coverage": "react-app-rewired test --env=jsdom --coverage",
|
||||||
|
"coveralls": "cat ./coverage/lcov.info | node node_modules/.bin/coveralls",
|
||||||
"eject": "react-app-rewired eject",
|
"eject": "react-app-rewired eject",
|
||||||
"postinstall": "(cp lib/web3-eth/index.js ../node_modules/web3-eth/src; cp lib/web3-eth/index.js ./node_modules/web3-eth/src) || :"
|
"postinstall": "(cp lib/web3-eth/index.js ../node_modules/web3-eth/src; cp lib/web3-eth/index.js ./node_modules/web3-eth/src) || :"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -53,8 +53,7 @@ class GasPriceStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const oracleOptions = { speedType: this.speedType, factor: this.factor, logger: console }
|
const oracleOptions = { speedType: this.speedType, factor: this.factor, logger: console }
|
||||||
const fetchFn = this.gasPriceSupplierUrl === 'gas-price-oracle' ? null : () => fetch(this.gasPriceSupplierUrl)
|
this.gasPrice = (await gasPriceFromSupplier(() => fetch(this.gasPriceSupplierUrl), oracleOptions)) || this.gasPrice
|
||||||
this.gasPrice = (await gasPriceFromSupplier(fetchFn, oracleOptions)) || this.gasPrice
|
|
||||||
|
|
||||||
setTimeout(() => this.updateGasPrice(), this.updateInterval)
|
setTimeout(() => this.updateGasPrice(), this.updateInterval)
|
||||||
}
|
}
|
||||||
|
|||||||
140
yarn.lock
140
yarn.lock
@@ -4209,13 +4209,6 @@ axios@0.19.0:
|
|||||||
follow-redirects "1.5.10"
|
follow-redirects "1.5.10"
|
||||||
is-buffer "^2.0.2"
|
is-buffer "^2.0.2"
|
||||||
|
|
||||||
axios@^0.19.2:
|
|
||||||
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.0.2"
|
version "2.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.0.2.tgz#ea187abe5b9002b377f925d8bf7d1c561adf38f9"
|
resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.0.2.tgz#ea187abe5b9002b377f925d8bf7d1c561adf38f9"
|
||||||
@@ -5847,6 +5840,17 @@ chrome-trace-event@^1.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
tslib "^1.9.0"
|
tslib "^1.9.0"
|
||||||
|
|
||||||
|
chromedriver@^77.0.0:
|
||||||
|
version "77.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-77.0.0.tgz#bd916cc87a0ccb7a6e4fb4b43cb2368bc54db6a0"
|
||||||
|
integrity sha512-mZa1IVx4HD8rDaItWbnS470mmypgiWsDiu98r0NkiT4uLm3qrANl4vOU6no6vtWtLQiW5kt1POcIbjeNpsLbXA==
|
||||||
|
dependencies:
|
||||||
|
del "^4.1.1"
|
||||||
|
extract-zip "^1.6.7"
|
||||||
|
mkdirp "^0.5.1"
|
||||||
|
request "^2.88.0"
|
||||||
|
tcp-port-used "^1.0.1"
|
||||||
|
|
||||||
ci-info@^1.5.0:
|
ci-info@^1.5.0:
|
||||||
version "1.6.0"
|
version "1.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497"
|
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497"
|
||||||
@@ -6231,7 +6235,7 @@ concat-map@0.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||||
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
|
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
|
||||||
|
|
||||||
concat-stream@^1.5.0, concat-stream@^1.5.1, concat-stream@^1.6.0, concat-stream@^1.6.2:
|
concat-stream@1.6.2, concat-stream@^1.5.0, concat-stream@^1.5.1, concat-stream@^1.6.0, concat-stream@^1.6.2:
|
||||||
version "1.6.2"
|
version "1.6.2"
|
||||||
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
|
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
|
||||||
integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==
|
integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==
|
||||||
@@ -6546,6 +6550,18 @@ cosmiconfig@^5.0.0, cosmiconfig@^5.0.7, cosmiconfig@^5.1.0, cosmiconfig@^5.2.0:
|
|||||||
js-yaml "^3.13.1"
|
js-yaml "^3.13.1"
|
||||||
parse-json "^4.0.0"
|
parse-json "^4.0.0"
|
||||||
|
|
||||||
|
coveralls@^3.0.0:
|
||||||
|
version "3.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/coveralls/-/coveralls-3.0.3.tgz#83b1c64aea1c6afa69beaf50b55ac1bc4d13e2b8"
|
||||||
|
integrity sha512-viNfeGlda2zJr8Gj1zqXpDMRjw9uM54p7wzZdvLRyOgnAfCe974Dq4veZkjJdxQXbmdppu6flEajFYseHYaUhg==
|
||||||
|
dependencies:
|
||||||
|
growl "~> 1.10.0"
|
||||||
|
js-yaml "^3.11.0"
|
||||||
|
lcov-parse "^0.0.10"
|
||||||
|
log-driver "^1.2.7"
|
||||||
|
minimist "^1.2.0"
|
||||||
|
request "^2.86.0"
|
||||||
|
|
||||||
coveralls@^3.0.6:
|
coveralls@^3.0.6:
|
||||||
version "3.0.11"
|
version "3.0.11"
|
||||||
resolved "https://registry.yarnpkg.com/coveralls/-/coveralls-3.0.11.tgz#e141da0922b632fcc66620f334460c3f0026a4ce"
|
resolved "https://registry.yarnpkg.com/coveralls/-/coveralls-3.0.11.tgz#e141da0922b632fcc66620f334460c3f0026a4ce"
|
||||||
@@ -7038,6 +7054,13 @@ debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
ms "^2.1.1"
|
ms "^2.1.1"
|
||||||
|
|
||||||
|
debug@4.1.0:
|
||||||
|
version "4.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.0.tgz#373687bffa678b38b1cd91f861b63850035ddc87"
|
||||||
|
integrity sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==
|
||||||
|
dependencies:
|
||||||
|
ms "^2.1.1"
|
||||||
|
|
||||||
debuglog@^1.0.1:
|
debuglog@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492"
|
resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492"
|
||||||
@@ -7169,7 +7192,7 @@ deep-extend@^0.6.0:
|
|||||||
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
|
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
|
||||||
integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
|
integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
|
||||||
|
|
||||||
deep-is@~0.1.3:
|
deep-is@^0.1.3, deep-is@~0.1.3:
|
||||||
version "0.1.3"
|
version "0.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
|
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
|
||||||
integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=
|
integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=
|
||||||
@@ -7279,6 +7302,19 @@ del@^3.0.0:
|
|||||||
pify "^3.0.0"
|
pify "^3.0.0"
|
||||||
rimraf "^2.2.8"
|
rimraf "^2.2.8"
|
||||||
|
|
||||||
|
del@^4.1.1:
|
||||||
|
version "4.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/del/-/del-4.1.1.tgz#9e8f117222ea44a31ff3a156c049b99052a9f0b4"
|
||||||
|
integrity sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==
|
||||||
|
dependencies:
|
||||||
|
"@types/glob" "^7.1.1"
|
||||||
|
globby "^6.1.0"
|
||||||
|
is-path-cwd "^2.0.0"
|
||||||
|
is-path-in-cwd "^2.0.0"
|
||||||
|
p-map "^2.0.0"
|
||||||
|
pify "^4.0.1"
|
||||||
|
rimraf "^2.6.3"
|
||||||
|
|
||||||
delayed-stream@~1.0.0:
|
delayed-stream@~1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
|
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
|
||||||
@@ -9065,6 +9101,16 @@ extract-comments@^1.1.0:
|
|||||||
esprima-extract-comments "^1.1.0"
|
esprima-extract-comments "^1.1.0"
|
||||||
parse-code-context "^1.0.0"
|
parse-code-context "^1.0.0"
|
||||||
|
|
||||||
|
extract-zip@^1.6.7:
|
||||||
|
version "1.6.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.7.tgz#a840b4b8af6403264c8db57f4f1a74333ef81fe9"
|
||||||
|
integrity sha1-qEC0uK9kAyZMjbV/Txp0Mz74H+k=
|
||||||
|
dependencies:
|
||||||
|
concat-stream "1.6.2"
|
||||||
|
debug "2.6.9"
|
||||||
|
mkdirp "0.5.1"
|
||||||
|
yauzl "2.4.1"
|
||||||
|
|
||||||
extract-zip@^2.0.0:
|
extract-zip@^2.0.0:
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a"
|
resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a"
|
||||||
@@ -9181,6 +9227,13 @@ fb-watchman@^2.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
bser "^2.0.0"
|
bser "^2.0.0"
|
||||||
|
|
||||||
|
fd-slicer@~1.0.1:
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65"
|
||||||
|
integrity sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=
|
||||||
|
dependencies:
|
||||||
|
pend "~1.2.0"
|
||||||
|
|
||||||
fd-slicer@~1.1.0:
|
fd-slicer@~1.1.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e"
|
resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e"
|
||||||
@@ -9769,14 +9822,6 @@ ganache-core@^2.6.0:
|
|||||||
ethereumjs-wallet "0.6.3"
|
ethereumjs-wallet "0.6.3"
|
||||||
web3 "1.2.4"
|
web3 "1.2.4"
|
||||||
|
|
||||||
gas-price-oracle@^0.1.5:
|
|
||||||
version "0.1.5"
|
|
||||||
resolved "https://registry.yarnpkg.com/gas-price-oracle/-/gas-price-oracle-0.1.5.tgz#09dd0d9806465c2f5e63b682e6742f96f6eb525c"
|
|
||||||
integrity sha512-fkaTXnxJcSVco/tMPEcN5gieoUNs8O6JYMXflGLN2+3YeGZAucUI0fgCliazM3nRVAk//bBEm9819/Zb83xhrw==
|
|
||||||
dependencies:
|
|
||||||
axios "^0.19.2"
|
|
||||||
bignumber.js "^9.0.0"
|
|
||||||
|
|
||||||
gauge@~2.7.3:
|
gauge@~2.7.3:
|
||||||
version "2.7.4"
|
version "2.7.4"
|
||||||
resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
|
resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
|
||||||
@@ -10271,7 +10316,7 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.6:
|
|||||||
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:
|
growl@1.10.5, "growl@~> 1.10.0":
|
||||||
version "1.10.5"
|
version "1.10.5"
|
||||||
resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e"
|
resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e"
|
||||||
integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==
|
integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==
|
||||||
@@ -11511,6 +11556,11 @@ is-path-cwd@^1.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d"
|
resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d"
|
||||||
integrity sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=
|
integrity sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=
|
||||||
|
|
||||||
|
is-path-cwd@^2.0.0:
|
||||||
|
version "2.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb"
|
||||||
|
integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==
|
||||||
|
|
||||||
is-path-in-cwd@^1.0.0:
|
is-path-in-cwd@^1.0.0:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz#5ac48b345ef675339bd6c7a48a912110b241cf52"
|
resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz#5ac48b345ef675339bd6c7a48a912110b241cf52"
|
||||||
@@ -11518,6 +11568,13 @@ is-path-in-cwd@^1.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
is-path-inside "^1.0.0"
|
is-path-inside "^1.0.0"
|
||||||
|
|
||||||
|
is-path-in-cwd@^2.0.0:
|
||||||
|
version "2.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz#bfe2dca26c69f397265a4009963602935a053acb"
|
||||||
|
integrity sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==
|
||||||
|
dependencies:
|
||||||
|
is-path-inside "^2.1.0"
|
||||||
|
|
||||||
is-path-inside@^1.0.0:
|
is-path-inside@^1.0.0:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036"
|
resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036"
|
||||||
@@ -11525,6 +11582,13 @@ is-path-inside@^1.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
path-is-inside "^1.0.1"
|
path-is-inside "^1.0.1"
|
||||||
|
|
||||||
|
is-path-inside@^2.1.0:
|
||||||
|
version "2.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-2.1.0.tgz#7c9810587d659a40d27bcdb4d5616eab059494b2"
|
||||||
|
integrity sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==
|
||||||
|
dependencies:
|
||||||
|
path-is-inside "^1.0.2"
|
||||||
|
|
||||||
is-plain-obj@^1.0.0, is-plain-obj@^1.1.0:
|
is-plain-obj@^1.0.0, is-plain-obj@^1.1.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
|
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
|
||||||
@@ -11655,6 +11719,11 @@ is-unc-path@^1.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
unc-path-regex "^0.1.2"
|
unc-path-regex "^0.1.2"
|
||||||
|
|
||||||
|
is-url@^1.2.2:
|
||||||
|
version "1.2.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/is-url/-/is-url-1.2.4.tgz#04a4df46d28c4cff3d73d01ff06abeb318a1aa52"
|
||||||
|
integrity sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==
|
||||||
|
|
||||||
is-utf8@^0.2.0, is-utf8@^0.2.1:
|
is-utf8@^0.2.0, is-utf8@^0.2.1:
|
||||||
version "0.2.1"
|
version "0.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
|
resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
|
||||||
@@ -11680,6 +11749,15 @@ is-wsl@^1.1.0:
|
|||||||
resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d"
|
resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d"
|
||||||
integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=
|
integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=
|
||||||
|
|
||||||
|
is2@2.0.1:
|
||||||
|
version "2.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/is2/-/is2-2.0.1.tgz#8ac355644840921ce435d94f05d3a94634d3481a"
|
||||||
|
integrity sha512-+WaJvnaA7aJySz2q/8sLjMb2Mw14KTplHmSwcSpZ/fWJPkUmqw3YTzSWbPJ7OAwRvdYTWF2Wg+yYJ1AdP5Z8CA==
|
||||||
|
dependencies:
|
||||||
|
deep-is "^0.1.3"
|
||||||
|
ip-regex "^2.1.0"
|
||||||
|
is-url "^1.2.2"
|
||||||
|
|
||||||
isarray@0.0.1:
|
isarray@0.0.1:
|
||||||
version "0.0.1"
|
version "0.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
|
resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
|
||||||
@@ -12345,7 +12423,7 @@ js-tokens@^3.0.0, js-tokens@^3.0.2:
|
|||||||
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
|
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
|
||||||
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
|
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
|
||||||
|
|
||||||
js-yaml@3.x, js-yaml@^3.12.0, js-yaml@^3.13.0, js-yaml@^3.13.1, js-yaml@^3.9.0:
|
js-yaml@3.x, js-yaml@^3.11.0, js-yaml@^3.12.0, js-yaml@^3.13.0, js-yaml@^3.13.1, js-yaml@^3.9.0:
|
||||||
version "3.13.1"
|
version "3.13.1"
|
||||||
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847"
|
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847"
|
||||||
integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==
|
integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==
|
||||||
@@ -12733,6 +12811,11 @@ lcid@^2.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
invert-kv "^2.0.0"
|
invert-kv "^2.0.0"
|
||||||
|
|
||||||
|
lcov-parse@^0.0.10:
|
||||||
|
version "0.0.10"
|
||||||
|
resolved "https://registry.yarnpkg.com/lcov-parse/-/lcov-parse-0.0.10.tgz#1b0b8ff9ac9c7889250582b70b71315d9da6d9a3"
|
||||||
|
integrity sha1-GwuP+ayceIklBYK3C3ExXZ2m2aM=
|
||||||
|
|
||||||
lcov-parse@^1.0.0:
|
lcov-parse@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/lcov-parse/-/lcov-parse-1.0.0.tgz#eb0d46b54111ebc561acb4c408ef9363bdc8f7e0"
|
resolved "https://registry.yarnpkg.com/lcov-parse/-/lcov-parse-1.0.0.tgz#eb0d46b54111ebc561acb4c408ef9363bdc8f7e0"
|
||||||
@@ -14982,7 +15065,7 @@ p-map@^1.1.1:
|
|||||||
resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.2.0.tgz#e4e94f311eabbc8633a1e79908165fca26241b6b"
|
resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.2.0.tgz#e4e94f311eabbc8633a1e79908165fca26241b6b"
|
||||||
integrity sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==
|
integrity sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==
|
||||||
|
|
||||||
p-map@^2.1.0:
|
p-map@^2.0.0, p-map@^2.1.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175"
|
resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175"
|
||||||
integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==
|
integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==
|
||||||
@@ -17442,7 +17525,7 @@ request@^2.67.0, request@^2.85.0, request@^2.87.0, request@^2.88.0:
|
|||||||
tunnel-agent "^0.6.0"
|
tunnel-agent "^0.6.0"
|
||||||
uuid "^3.3.2"
|
uuid "^3.3.2"
|
||||||
|
|
||||||
request@^2.79.0:
|
request@^2.79.0, request@^2.86.0:
|
||||||
version "2.88.0"
|
version "2.88.0"
|
||||||
resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef"
|
resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef"
|
||||||
integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==
|
integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==
|
||||||
@@ -19284,6 +19367,14 @@ tar@^4.0.2, tar@^4.4.10, tar@^4.4.12, tar@^4.4.8:
|
|||||||
safe-buffer "^5.1.2"
|
safe-buffer "^5.1.2"
|
||||||
yallist "^3.0.3"
|
yallist "^3.0.3"
|
||||||
|
|
||||||
|
tcp-port-used@^1.0.1:
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/tcp-port-used/-/tcp-port-used-1.0.1.tgz#46061078e2d38c73979a2c2c12b5a674e6689d70"
|
||||||
|
integrity sha512-rwi5xJeU6utXoEIiMvVBMc9eJ2/ofzB+7nLOdnZuFTmNCLqRiQh2sMG9MqCxHU/69VC/Fwp5dV9306Qd54ll1Q==
|
||||||
|
dependencies:
|
||||||
|
debug "4.1.0"
|
||||||
|
is2 "2.0.1"
|
||||||
|
|
||||||
temp-dir@^1.0.0:
|
temp-dir@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d"
|
resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d"
|
||||||
@@ -22327,6 +22418,13 @@ yargs@^7.0.0, yargs@^7.1.0:
|
|||||||
y18n "^3.2.1"
|
y18n "^3.2.1"
|
||||||
yargs-parser "^5.0.0"
|
yargs-parser "^5.0.0"
|
||||||
|
|
||||||
|
yauzl@2.4.1:
|
||||||
|
version "2.4.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005"
|
||||||
|
integrity sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=
|
||||||
|
dependencies:
|
||||||
|
fd-slicer "~1.0.1"
|
||||||
|
|
||||||
yauzl@^2.10.0, yauzl@^2.4.2:
|
yauzl@^2.10.0, yauzl@^2.4.2:
|
||||||
version "2.10.0"
|
version "2.10.0"
|
||||||
resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9"
|
resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9"
|
||||||
|
|||||||
Reference in New Issue
Block a user