Compare commits

..

1 Commits

Author SHA1 Message Date
Kirill Fedoseev
c2429880ab Remove deprecated CHAI swap worker 2021-05-03 09:42:34 +03:00
205 changed files with 6917 additions and 12873 deletions

View File

@ -15,7 +15,7 @@ jobs:
steps: steps:
- uses: actions/setup-node@v1 - uses: actions/setup-node@v1
with: with:
node-version: 12 node-version: 10
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with: with:
submodules: true submodules: true
@ -48,7 +48,7 @@ jobs:
steps: steps:
- uses: actions/setup-node@v1 - uses: actions/setup-node@v1
with: with:
node-version: 12 node-version: 10
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with: with:
submodules: true submodules: true
@ -70,19 +70,19 @@ jobs:
- name: Evaluate e2e docker images tags - name: Evaluate e2e docker images tags
run: | run: |
git submodule status > submodule.status git submodule status > submodule.status
echo "E2E_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'Dockerfile.e2e', 'commons', 'oracle-e2e', 'monitor-e2e', 'e2e-commons') }}" >> $GITHUB_ENV echo "E2E_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'Dockerfile.e2e', 'commons', 'oracle-e2e', 'monitor-e2e') }}" >> $GITHUB_ENV
echo "ORACLE_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'oracle') }}" >> $GITHUB_ENV echo "ORACLE_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'oracle') }}" >> $GITHUB_ENV
echo "MONITOR_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'monitor') }}" >> $GITHUB_ENV echo "MONITOR_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'monitor') }}" >> $GITHUB_ENV
echo "ALM_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'alm') }}" >> $GITHUB_ENV echo "ALM_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'alm') }}" >> $GITHUB_ENV
- name: Rebuild and push updated images - name: Rebuild and push updated images
run: | run: |
function check_if_image_exists() { function check_if_image_exists() {
curl -fsSlL "https://${{ github.actor }}:${{ github.token }}@${DOCKER_REGISTRY}/v2/${DOCKER_REPO}/tokenbridge-e2e-$1/manifests/$2" > /dev/null curl -fsSlL -H 'Authorization: bearer ${{ github.token }}' "https://${DOCKER_REGISTRY}/v2/${DOCKER_REPO}/tokenbridge-e2e-$1/manifests/$2" > /dev/null
} }
updated=() updated=()
if ! check_if_image_exists e2e ${E2E_TAG}; then updated+=("e2e"); fi if ! check_if_image_exists e2e ${E2E_TAG}; then updated+=("e2e"); fi
if ! check_if_image_exists oracle ${ORACLE_TAG}; then updated+=("oracle-amb"); fi if ! check_if_image_exists oracle ${ORACLE_TAG}; then updated+=("oracle"); fi
if ! check_if_image_exists monitor ${MONITOR_TAG}; then updated+=("monitor-amb"); fi if ! check_if_image_exists monitor ${MONITOR_TAG}; then updated+=("monitor"); fi
if ! check_if_image_exists alm ${ALM_TAG}; then updated+=("alm"); fi if ! check_if_image_exists alm ${ALM_TAG}; then updated+=("alm"); fi
if [ ${#updated[@]} -gt 0 ]; then if [ ${#updated[@]} -gt 0 ]; then
echo "Updated services: ${updated[@]}" echo "Updated services: ${updated[@]}"
@ -104,7 +104,7 @@ jobs:
- name: Rebuild and push molecule runner e2e image - name: Rebuild and push molecule runner e2e image
run: | run: |
function check_if_image_exists() { function check_if_image_exists() {
curl -fsSlL "https://${{ github.actor }}:${{ github.token }}@${DOCKER_REGISTRY}/v2/${DOCKER_REPO}/tokenbridge-e2e-$1/manifests/$2" > /dev/null curl -fsSlL -H 'Authorization: bearer ${{ github.token }}' "https://${DOCKER_REGISTRY}/v2/${DOCKER_REPO}/tokenbridge-e2e-$1/manifests/$2" > /dev/null
} }
if check_if_image_exists molecule_runner ${MOLECULE_RUNNER_TAG}; then if check_if_image_exists molecule_runner ${MOLECULE_RUNNER_TAG}; then
echo "Image already exists" echo "Image already exists"
@ -133,7 +133,7 @@ jobs:
- name: Evaluate e2e docker images tags - name: Evaluate e2e docker images tags
run: | run: |
git submodule status > submodule.status git submodule status > submodule.status
echo "E2E_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'Dockerfile.e2e', 'commons', 'oracle-e2e', 'monitor-e2e', 'e2e-commons') }}" >> $GITHUB_ENV echo "E2E_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'Dockerfile.e2e', 'commons', 'oracle-e2e', 'monitor-e2e') }}" >> $GITHUB_ENV
echo "ORACLE_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'oracle') }}" >> $GITHUB_ENV echo "ORACLE_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'oracle') }}" >> $GITHUB_ENV
echo "MONITOR_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'monitor') }}" >> $GITHUB_ENV echo "MONITOR_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'monitor') }}" >> $GITHUB_ENV
echo "ALM_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'alm') }}" >> $GITHUB_ENV echo "ALM_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'alm') }}" >> $GITHUB_ENV
@ -149,12 +149,6 @@ jobs:
run: docker login ${DOCKER_REGISTRY} -u ${{ github.actor }} -p ${{ github.token }} run: docker login ${DOCKER_REGISTRY} -u ${{ github.actor }} -p ${{ github.token }}
- name: yarn run ${{ matrix.task }} - name: yarn run ${{ matrix.task }}
run: ${{ !matrix.use-cache || steps.cache-repo.outputs.cache-hit }} && yarn run ${{ matrix.task }} run: ${{ !matrix.use-cache || steps.cache-repo.outputs.cache-hit }} && yarn run ${{ matrix.task }}
- name: Upload logs
if: always()
uses: actions/upload-artifact@v2
with:
name: logs-${{ matrix.task }}
path: e2e-commons/logs
deployment: deployment:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: needs:
@ -182,7 +176,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
task: [amb, erc-to-native] task: [amb, erc-to-erc, erc-to-native, native-to-erc]
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with: with:
@ -190,7 +184,7 @@ jobs:
- name: Evaluate e2e docker images tags - name: Evaluate e2e docker images tags
run: | run: |
git submodule status > submodule.status git submodule status > submodule.status
echo "E2E_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'Dockerfile.e2e', 'commons', 'oracle-e2e', 'monitor-e2e', 'e2e-commons') }}" >> $GITHUB_ENV echo "E2E_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'Dockerfile.e2e', 'commons', 'oracle-e2e', 'monitor-e2e') }}" >> $GITHUB_ENV
echo "ORACLE_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'oracle') }}" >> $GITHUB_ENV echo "ORACLE_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'oracle') }}" >> $GITHUB_ENV
echo "MONITOR_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'monitor') }}" >> $GITHUB_ENV echo "MONITOR_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'monitor') }}" >> $GITHUB_ENV
echo "ALM_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'alm') }}" >> $GITHUB_ENV echo "ALM_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'alm') }}" >> $GITHUB_ENV
@ -205,10 +199,10 @@ jobs:
- name: Login to docker registry - name: Login to docker registry
run: docker login ${DOCKER_REGISTRY} -u ${{ github.actor }} -p ${{ github.token }} run: docker login ${DOCKER_REGISTRY} -u ${{ github.actor }} -p ${{ github.token }}
- name: Deploy contracts - name: Deploy contracts
run: ${{ steps.cache-repo.outputs.cache-hit }} && e2e-commons/up.sh deploy generate-amb-tx blocks run: ${{ steps.cache-repo.outputs.cache-hit }} && e2e-commons/up.sh deploy blocks
- name: Pull e2e oracle image - name: Pull e2e oracle image
run: | run: |
docker-compose -f ./e2e-commons/docker-compose.yml pull oracle-amb docker-compose -f ./e2e-commons/docker-compose.yml pull oracle
docker tag ${DOCKER_IMAGE_BASE}/tokenbridge-e2e-oracle:${ORACLE_TAG} poanetwork/tokenbridge-oracle:latest docker tag ${DOCKER_IMAGE_BASE}/tokenbridge-e2e-oracle:${ORACLE_TAG} poanetwork/tokenbridge-oracle:latest
- name: Deploy oracle - name: Deploy oracle
run: deployment-e2e/molecule.sh ultimate-${{ matrix.task }} run: deployment-e2e/molecule.sh ultimate-${{ matrix.task }}
@ -216,12 +210,3 @@ jobs:
run: sudo chown -R $USER:docker /var/run/docker.sock run: sudo chown -R $USER:docker /var/run/docker.sock
- name: Run oracle e2e tests - name: Run oracle e2e tests
run: docker-compose -f ./e2e-commons/docker-compose.yml run -e ULTIMATE=true e2e yarn workspace oracle-e2e run ${{ matrix.task }} run: docker-compose -f ./e2e-commons/docker-compose.yml run -e ULTIMATE=true e2e yarn workspace oracle-e2e run ${{ matrix.task }}
- name: Save logs
if: always()
run: e2e-commons/down.sh
- name: Upload logs
if: always()
uses: actions/upload-artifact@v2
with:
name: logs-ultimate-${{ matrix.task }}
path: e2e-commons/logs

2
.nvmrc
View File

@ -1 +1 @@
12.22 10.22

View File

@ -8,11 +8,11 @@ COMMON_HOME_RPC_URL | The HTTPS URL(s) used to communicate to the RPC nodes in t
COMMON_FOREIGN_RPC_URL | The HTTPS URL(s) used to communicate to the RPC nodes in the Foreign network. Several URLs can be specified, delimited by spaces. If the connection to one of these nodes is lost the next URL is used for connection. | URL(s) COMMON_FOREIGN_RPC_URL | The HTTPS URL(s) used to communicate to the RPC nodes in the Foreign network. Several URLs can be specified, delimited by spaces. If the connection to one of these nodes is lost the next URL is used for connection. | URL(s)
COMMON_HOME_BRIDGE_ADDRESS | The address of the bridge contract address in the Home network. It is used to listen to events from and send validators' transactions to the Home network. | hexidecimal beginning with "0x" COMMON_HOME_BRIDGE_ADDRESS | The address of the bridge contract address in the Home network. It is used to listen to events from and send validators' transactions to the Home network. | hexidecimal beginning with "0x"
COMMON_FOREIGN_BRIDGE_ADDRESS | The address of the bridge contract address in the Foreign network. It is used to listen to events from and send validators' transactions to the Foreign network. | hexidecimal beginning with "0x" COMMON_FOREIGN_BRIDGE_ADDRESS | The address of the bridge contract address in the Foreign network. It is used to listen to events from and send validators' transactions to the Foreign network. | hexidecimal beginning with "0x"
COMMON_HOME_GAS_PRICE_SUPPLIER_URL | The URL used to get a JSON response from the gas price prediction oracle for the Home network. The gas price provided by the oracle is used to send the validator's transactions to the RPC node. Since it is assumed that the Home network has a predefined gas price (e.g. the gas price in the Core of POA.Network is `1 GWei`), the gas price oracle parameter can be omitted for such networks. Set to `eip1559-gas-estimation` if you want to use EIP1559 RPC-based gas estimation. | URL COMMON_HOME_GAS_PRICE_SUPPLIER_URL | The URL used to get a JSON response from the gas price prediction oracle for the Home network. The gas price provided by the oracle is used to send the validator's transactions to the RPC node. Since it is assumed that the Home network has a predefined gas price (e.g. the gas price in the Core of POA.Network is `1 GWei`), the gas price oracle parameter can be omitted for such networks. | URL
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. Set to `eip1559-gas-estimation` if you want to use EIP1559 RPC-based gas estimation. | 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. 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_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
@ -22,7 +22,7 @@ COMMON_FOREIGN_GAS_PRICE_FACTOR | A value that will multiply the gas price of th
name | description | value name | description | value
--- | --- | --- --- | --- | ---
ORACLE_BRIDGE_MODE | The bridge mode. The bridge starts listening to a different set of events based on this parameter. | ERC_TO_NATIVE / ARBITRARY_MESSAGE ORACLE_BRIDGE_MODE | The bridge mode. The bridge starts listening to a different set of events based on this parameter. | NATIVE_TO_ERC / ERC_TO_ERC / ERC_TO_NATIVE / ARBITRARY_MESSAGE
ORACLE_ALLOW_HTTP_FOR_RPC | **Only use in test environments - must be omitted in production environments.**. If this parameter is specified and set to `yes`, RPC URLs can be specified in form of HTTP links. A warning that the connection is insecure will be written to the logs. | `yes` / `no` ORACLE_ALLOW_HTTP_FOR_RPC | **Only use in test environments - must be omitted in production environments.**. If this parameter is specified and set to `yes`, RPC URLs can be specified in form of HTTP links. A warning that the connection is insecure will be written to the logs. | `yes` / `no`
ORACLE_HOME_RPC_POLLING_INTERVAL | The interval in milliseconds used to request the RPC node in the Home network for new blocks. The interval should match the average production time for a new block. | integer ORACLE_HOME_RPC_POLLING_INTERVAL | The interval in milliseconds used to request the RPC node in the Home network for new blocks. The interval should match the average production time for a new block. | integer
ORACLE_FOREIGN_RPC_POLLING_INTERVAL | The interval in milliseconds used to request the RPC node in the Foreign network for new blocks. The interval should match the average production time for a new block. | integer ORACLE_FOREIGN_RPC_POLLING_INTERVAL | The interval in milliseconds used to request the RPC node in the Foreign network for new blocks. The interval should match the average production time for a new block. | integer
@ -47,20 +47,10 @@ ORACLE_FOREIGN_TX_RESEND_INTERVAL | Interval in milliseconds for automatic resen
ORACLE_SHUTDOWN_SERVICE_URL | Optional external URL to some other service/monitor/configuration manager that controls the remote shutdown process. GET request should return `application/json` message with the following schema: `{ shutdown: true/false }`. | URL ORACLE_SHUTDOWN_SERVICE_URL | Optional external URL to some other service/monitor/configuration manager that controls the remote shutdown process. GET request should return `application/json` message with the following schema: `{ shutdown: true/false }`. | URL
ORACLE_SHUTDOWN_SERVICE_POLLING_INTERVAL | Optional interval in milliseconds used to request the side RPC node or external shutdown service. Default is 120000. | integer ORACLE_SHUTDOWN_SERVICE_POLLING_INTERVAL | Optional interval in milliseconds used to request the side RPC node or external shutdown service. Default is 120000. | integer
ORACLE_SIDE_RPC_URL | Optional HTTPS URL(s) for communication with the external shutdown service or side RPC nodes, used for shutdown manager activities. Several URLs can be specified, delimited by spaces. If the connection to one of these nodes is lost the next URL is used for connection. | URL(s) ORACLE_SIDE_RPC_URL | Optional HTTPS URL(s) for communication with the external shutdown service or side RPC nodes, used for shutdown manager activities. Several URLs can be specified, delimited by spaces. If the connection to one of these nodes is lost the next URL is used for connection. | URL(s)
ORACLE_FOREIGN_ARCHIVE_RPC_URL | Optional HTTPS URL(s) for communication with the archive nodes on the foreign network. Only used in AMB bridge mode for async information request processing. Several URLs can be specified, delimited by spaces. If the connection to one of these nodes is lost the next URL is used for connection. | URL(s)
ORACLE_SHUTDOWN_CONTRACT_ADDRESS | Optional contract address in the side chain accessible through `ORACLE_SIDE_RPC_URL`, where the method passed in `ORACLE_SHUTDOWN_CONTRACT_METHOD` is implemented. | `address` ORACLE_SHUTDOWN_CONTRACT_ADDRESS | Optional contract address in the side chain accessible through `ORACLE_SIDE_RPC_URL`, where the method passed in `ORACLE_SHUTDOWN_CONTRACT_METHOD` is implemented. | `address`
ORACLE_SHUTDOWN_CONTRACT_METHOD | Method signature to be used in the side chain to identify the current shutdown status. Method should return boolean. Default value is `isShutdown()`. | `function signature` ORACLE_SHUTDOWN_CONTRACT_METHOD | Method signature to be used in the side chain to identify the current shutdown status. Method should return boolean. Default value is `isShutdown()`. | `function signature`
ORACLE_FOREIGN_RPC_BLOCK_POLLING_LIMIT | Max length for the block range used in `eth_getLogs` requests for polling contract events for the Foreign chain. Infinite, if not provided. | `integer` ORACLE_FOREIGN_RPC_BLOCK_POLLING_LIMIT | Max length for the block range used in `eth_getLogs` requests for polling contract events for the Foreign chain. Infinite, if not provided. | `integer`
ORACLE_HOME_RPC_BLOCK_POLLING_LIMIT | Max length for the block range used in `eth_getLogs` requests for polling contract events for the Home chain. Infinite, if not provided. | `integer` ORACLE_HOME_RPC_BLOCK_POLLING_LIMIT | Max length for the block range used in `eth_getLogs` requests for polling contract events for the Home chain. Infinite, if not provided. | `integer`
ORACLE_JSONRPC_ERROR_CODES | Override default JSON rpc error codes that can trigger RPC fallback to the next URL from the list (or a retry in case of a single RPC URL). Default is `-32603,-32002,-32005`. Should be a comma-separated list of negative integers. | `string`
ORACLE_HOME_EVENTS_REPROCESSING | If set to `true`, home events happened in the past will be refetched and processed once again, to ensure that nothing was missed on the first pass. | `bool`
ORACLE_HOME_EVENTS_REPROCESSING_BATCH_SIZE | Batch size for one `eth_getLogs` request when reprocessing old logs in the home chain. Defaults to `1000` | `integer`
ORACLE_HOME_EVENTS_REPROCESSING_BLOCK_DELAY | Block confirmations number, after which old logs are being reprocessed in the home chain. Defaults to `500` | `integer`
ORACLE_HOME_RPC_SYNC_STATE_CHECK_INTERVAL | Interval for checking JSON RPC sync state, by requesting the latest block number. Oracle will switch to the fallback JSON RPC in case sync process is stuck | `integer`
ORACLE_FOREIGN_EVENTS_REPROCESSING | If set to `true`, foreign events happened in the past will be refetched and processed once again, to ensure that nothing was missed on the first pass. | `bool`
ORACLE_FOREIGN_EVENTS_REPROCESSING_BATCH_SIZE | Batch size for one `eth_getLogs` request when reprocessing old logs in the foreign chain. Defaults to `500` | `integer`
ORACLE_FOREIGN_EVENTS_REPROCESSING_BLOCK_DELAY | Block confirmations number, after which old logs are being reprocessed in the foreign chain. Defaults to `250` | `integer`
ORACLE_FOREIGN_RPC_SYNC_STATE_CHECK_INTERVAL | Interval for checking JSON RPC sync state, by requesting the latest block number. Oracle will switch to the fallback JSON RPC in case sync process is stuck | `integer`
## Monitor configuration ## Monitor configuration

View File

@ -1,4 +1,4 @@
FROM node:12 as contracts FROM node:10 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:12 FROM node:10
WORKDIR /mono WORKDIR /mono
COPY package.json . COPY package.json .
@ -19,7 +19,6 @@ COPY --from=contracts /mono/contracts/build ./contracts/build
COPY commons/package.json ./commons/ 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/
COPY oracle/src/utils/constants.js ./oracle/src/utils/constants.js
COPY yarn.lock . COPY yarn.lock .
RUN NOYARNPOSTINSTALL=1 yarn install --frozen-lockfile --production RUN NOYARNPOSTINSTALL=1 yarn install --frozen-lockfile --production

View File

@ -19,7 +19,7 @@ Sub-repositories maintained within this monorepo are listed below.
| Sub-repository | Description | | Sub-repository | Description |
| --- | --- | | --- | --- |
| [Oracle](oracle/README.md) | Responsible for listening to bridge related events and authorizing asset transfers. | | [Oracle](oracle/README.md) | Oracle responsible for listening to bridge related events and authorizing asset transfers. |
| [Monitor](monitor/README.md) | Tool for checking balances and unprocessed events in bridged networks. | | [Monitor](monitor/README.md) | Tool for checking balances and unprocessed events in bridged networks. |
| [Deployment](deployment/README.md) | Ansible playbooks for deploying cross-chain bridges. | | [Deployment](deployment/README.md) | Ansible playbooks for deploying cross-chain bridges. |
| [Oracle-E2E](oracle-e2e/README.md) | End to end tests for the Oracle | | [Oracle-E2E](oracle-e2e/README.md) | End to end tests for the Oracle |
@ -54,6 +54,8 @@ Additionally there are [Smart Contracts](https://github.com/poanetwork/tokenbrid
The POA TokenBridge provides four operational modes: The POA TokenBridge provides four operational modes:
- [x] `Native-to-ERC20` **Coins** on a Home network can be converted to ERC20-compatible **tokens** on a Foreign network. Coins are locked on the Home side and the corresponding amount of ERC20 tokens are minted on the Foreign side. When the operation is reversed, tokens are burnt on the Foreign side and unlocked in the Home network. **More Information: [POA-to-POA20 Bridge](https://medium.com/poa-network/introducing-poa-bridge-and-poa20-55d8b78058ac)**
- [x] `ERC20-to-ERC20` ERC20-compatible tokens on the Foreign network are locked and minted as ERC20-compatible tokens (ERC677 tokens) on the Home network. When transferred from Home to Foreign, they are burnt on the Home side and unlocked in the Foreign network. This can be considered a form of atomic swap when a user swaps the token "X" in network "A" to the token "Y" in network "B". **More Information: [ERC20-to-ERC20](https://medium.com/poa-network/introducing-the-erc20-to-erc20-tokenbridge-ce266cc1a2d0)**
- [x] `ERC20-to-Native`: Pre-existing **tokens** in the Foreign network are locked and **coins** are minted in the `Home` network. In this mode, the Home network consensus engine invokes [Parity's Block Reward contract](https://wiki.parity.io/Block-Reward-Contract.html) to mint coins per the bridge contract request. **More Information: [xDai Chain](https://medium.com/poa-network/poa-network-partners-with-makerdao-on-xdai-chain-the-first-ever-usd-stable-blockchain-65a078c41e6a)** - [x] `ERC20-to-Native`: Pre-existing **tokens** in the Foreign network are locked and **coins** are minted in the `Home` network. In this mode, the Home network consensus engine invokes [Parity's Block Reward contract](https://wiki.parity.io/Block-Reward-Contract.html) to mint coins per the bridge contract request. **More Information: [xDai Chain](https://medium.com/poa-network/poa-network-partners-with-makerdao-on-xdai-chain-the-first-ever-usd-stable-blockchain-65a078c41e6a)**
- [x] `Arbitrary-Message`: Transfer arbitrary data between two networks as so the data could be interpreted as an arbitrary contract method invocation. - [x] `Arbitrary-Message`: Transfer arbitrary data between two networks as so the data could be interpreted as an arbitrary contract method invocation.

View File

@ -19,6 +19,6 @@
"eslint-plugin-jest": "^23.18.0" "eslint-plugin-jest": "^23.18.0"
}, },
"engines": { "engines": {
"node": ">= 12.22" "node": ">= 10.18"
} }
} }

View File

@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
cd $(dirname $0) cd $(dirname $0)
../e2e-commons/up.sh deploy generate-amb-tx blocks alm alm-e2e ../e2e-commons/up.sh deploy blocks alm alm-e2e
# run oracle amb e2e tests to generate transactions for alm # run oracle amb e2e tests to generate transactions for alm
docker-compose -f ../e2e-commons/docker-compose.yml run e2e yarn workspace oracle-e2e run alm docker-compose -f ../e2e-commons/docker-compose.yml run e2e yarn workspace oracle-e2e run alm

View File

@ -6,8 +6,8 @@ jest.setTimeout(60000)
const statusText = 'Success' const statusText = 'Success'
const statusSelector = 'label[data-id="status"]' const statusSelector = 'label[data-id="status"]'
const homeToForeignTxURL = 'http://localhost:3004/77/0x295efbe6ae98937ef35d939376c9bd752b4dc6f6899a9d5ddd6a57cea3d76c89' const homeToForeignTxURL = 'http://localhost:3004/77/0x58e7d63368335b9591d4dbb43889084f698fcee93ab7656fd7a39d8c66bc4b60'
const foreignToHomeTxURL = 'http://localhost:3004/42/0x7262f7dbe6c30599edded2137fbbe93c271b37f5c54dd27f713f0cf510e3b4dd' const foreignToHomeTxURL = 'http://localhost:3004/42/0x592bf28fc896419d2838f71cd0388775814b692688f1ecd5b1519081566b994a'
describe('ALM', () => { describe('ALM', () => {
let browser let browser

View File

@ -1,4 +1,4 @@
FROM node:12 as contracts FROM node:10 as contracts
WORKDIR /mono WORKDIR /mono

View File

@ -123,24 +123,6 @@ const abi: AbiItem[] = [
stateMutability: 'nonpayable', stateMutability: 'nonpayable',
type: 'function' type: 'function'
}, },
{
constant: false,
inputs: [
{
name: '_data',
type: 'bytes'
},
{
name: '_signatures',
type: 'bytes'
}
],
name: 'safeExecuteSignaturesWithAutoGasLimit',
outputs: [],
payable: false,
stateMutability: 'nonpayable',
type: 'function'
},
{ {
constant: true, constant: true,
inputs: [ inputs: [

View File

@ -1,9 +1,9 @@
import React, { useEffect, useState } from 'react' import React from 'react'
import { TransactionReceipt } from 'web3-eth' import { TransactionReceipt } from 'web3-eth'
import { useMessageConfirmations } from '../hooks/useMessageConfirmations' import { useMessageConfirmations } from '../hooks/useMessageConfirmations'
import { MessageObject } from '../utils/web3' import { MessageObject } from '../utils/web3'
import styled from 'styled-components' import styled from 'styled-components'
import { CONFIRMATIONS_STATUS, VALIDATOR_CONFIRMATION_STATUS } from '../config/constants' import { CONFIRMATIONS_STATUS } from '../config/constants'
import { CONFIRMATIONS_STATUS_LABEL, CONFIRMATIONS_STATUS_LABEL_HOME } from '../config/descriptions' import { CONFIRMATIONS_STATUS_LABEL, CONFIRMATIONS_STATUS_LABEL_HOME } from '../config/descriptions'
import { SimpleLoading } from './commons/Loading' import { SimpleLoading } from './commons/Loading'
import { ValidatorsConfirmations } from './ValidatorsConfirmations' import { ValidatorsConfirmations } from './ValidatorsConfirmations'
@ -54,9 +54,7 @@ export const ConfirmationsContainer = ({
home: { name: homeName }, home: { name: homeName },
foreign: { name: foreignName } foreign: { name: foreignName }
} = useStateProvider() } = useStateProvider()
const src = useValidatorContract(fromHome, receipt ? receipt.blockNumber : 0) const { requiredSignatures, validatorList } = useValidatorContract({ fromHome, receipt })
const [executionBlockNumber, setExecutionBlockNumber] = useState(0)
const dst = useValidatorContract(!fromHome, executionBlockNumber || 'latest')
const { blockConfirmations } = useBlockConfirmations({ fromHome, receipt }) const { blockConfirmations } = useBlockConfirmations({ fromHome, receipt })
const { const {
confirmations, confirmations,
@ -73,21 +71,11 @@ export const ConfirmationsContainer = ({
fromHome, fromHome,
homeStartBlock, homeStartBlock,
foreignStartBlock, foreignStartBlock,
requiredSignatures: src.requiredSignatures, requiredSignatures,
validatorList: src.validatorList, validatorList,
targetValidatorList: dst.validatorList,
blockConfirmations blockConfirmations
}) })
useEffect(
() => {
if (executionBlockNumber || executionData.status !== VALIDATOR_CONFIRMATION_STATUS.EXECUTION_SUCCESS) return
setExecutionBlockNumber(executionData.blockNumber)
},
[executionData.status, executionBlockNumber, executionData.blockNumber]
)
const statusLabel = fromHome ? CONFIRMATIONS_STATUS_LABEL_HOME : CONFIRMATIONS_STATUS_LABEL const statusLabel = fromHome ? CONFIRMATIONS_STATUS_LABEL_HOME : CONFIRMATIONS_STATUS_LABEL
const parseDescription = () => { const parseDescription = () => {
@ -126,22 +114,20 @@ export const ConfirmationsContainer = ({
</MultiLine> </MultiLine>
</StatusDescription> </StatusDescription>
<ValidatorsConfirmations <ValidatorsConfirmations
confirmations={fromHome ? confirmations.filter(c => dst.validatorList.includes(c.validator)) : confirmations} confirmations={confirmations}
requiredSignatures={dst.requiredSignatures} requiredSignatures={requiredSignatures}
validatorList={dst.validatorList} validatorList={validatorList}
waitingBlocksResolved={waitingBlocksResolved} waitingBlocksResolved={waitingBlocksResolved}
/> />
{signatureCollected && ( {signatureCollected && (
<ExecutionConfirmation <ExecutionConfirmation
message={message} messageData={message.data}
executionData={executionData} executionData={executionData}
isHome={!fromHome} isHome={!fromHome}
confirmations={confirmations} signatureCollected={signatureCollected}
setExecutionData={setExecutionData} setExecutionData={setExecutionData}
executionEventsFetched={executionEventsFetched} executionEventsFetched={executionEventsFetched}
setPendingExecution={setPendingExecution} setPendingExecution={setPendingExecution}
dstRequiredSignatures={dst.requiredSignatures}
dstValidatorList={dst.validatorList}
/> />
)} )}
</StyledConfirmationContainer> </StyledConfirmationContainer>

View File

@ -1,50 +1,38 @@
import React, { useEffect, useState } from 'react' import React from 'react'
import { formatTimestamp, formatTxHash, getExplorerTxUrl } from '../utils/networks' import { formatTimestamp, formatTxHash, getExplorerTxUrl } from '../utils/networks'
import { useWindowWidth } from '@react-hook/window-size' import { useWindowWidth } from '@react-hook/window-size'
import { SEARCHING_TX, VALIDATOR_CONFIRMATION_STATUS, ALM_HOME_TO_FOREIGN_MANUAL_EXECUTION } from '../config/constants' import { SEARCHING_TX, VALIDATOR_CONFIRMATION_STATUS, ALM_HOME_TO_FOREIGN_MANUAL_EXECUTION } from '../config/constants'
import { SimpleLoading } from './commons/Loading' import { SimpleLoading } from './commons/Loading'
import styled from 'styled-components' import styled from 'styled-components'
import { ConfirmationParam, ExecutionData } from '../hooks/useMessageConfirmations' import { ExecutionData } from '../hooks/useMessageConfirmations'
import { GreyLabel, RedLabel, SuccessLabel } from './commons/Labels' import { GreyLabel, RedLabel, SuccessLabel } from './commons/Labels'
import { ExplorerTxLink } from './commons/ExplorerTxLink' import { ExplorerTxLink } from './commons/ExplorerTxLink'
import { Thead, AgeTd, StatusTd } from './commons/Table' import { Thead, AgeTd, StatusTd } from './commons/Table'
import { ManualExecutionButton } from './ManualExecutionButton' import { ManualExecutionButton } from './ManualExecutionButton'
import { useStateProvider } from '../state/StateProvider'
import { matchesRule, MessageObject, WarnRule } from '../utils/web3'
import { WarningAlert } from './commons/WarningAlert'
import { ErrorAlert } from './commons/ErrorAlert'
const StyledExecutionConfirmation = styled.div` const StyledExecutionConfirmation = styled.div`
margin-top: 30px; margin-top: 30px;
` `
export interface ExecutionConfirmationParams { export interface ExecutionConfirmationParams {
message: MessageObject messageData: string
executionData: ExecutionData executionData: ExecutionData
setExecutionData: Function setExecutionData: Function
confirmations: ConfirmationParam[] signatureCollected: boolean | string[]
isHome: boolean isHome: boolean
executionEventsFetched: boolean executionEventsFetched: boolean
setPendingExecution: Function setPendingExecution: Function
dstRequiredSignatures: number
dstValidatorList: string[]
} }
export const ExecutionConfirmation = ({ export const ExecutionConfirmation = ({
message, messageData,
executionData, executionData,
setExecutionData, setExecutionData,
confirmations, signatureCollected,
isHome, isHome,
executionEventsFetched, executionEventsFetched,
setPendingExecution, setPendingExecution
dstRequiredSignatures,
dstValidatorList
}: ExecutionConfirmationParams) => { }: ExecutionConfirmationParams) => {
const { foreign } = useStateProvider()
const [safeExecutionAvailable, setSafeExecutionAvailable] = useState(false)
const [error, setError] = useState('')
const [warning, setWarning] = useState('')
const availableManualExecution = const availableManualExecution =
!isHome && !isHome &&
(executionData.status === VALIDATOR_CONFIRMATION_STATUS.WAITING || (executionData.status === VALIDATOR_CONFIRMATION_STATUS.WAITING ||
@ -60,43 +48,9 @@ export const ExecutionConfirmation = ({
const formattedValidator = const formattedValidator =
windowWidth < 850 && executionData.validator ? formatTxHash(executionData.validator) : executionData.validator windowWidth < 850 && executionData.validator ? formatTxHash(executionData.validator) : executionData.validator
useEffect(
() => {
if (!availableManualExecution || !foreign.bridgeContract) return
const p = foreign.bridgeContract.methods.getBridgeInterfacesVersion().call()
p.then(({ major, minor }: any) => {
major = parseInt(major, 10)
minor = parseInt(minor, 10)
if (major < 5 || (major === 5 && minor < 7)) return
setSafeExecutionAvailable(true)
})
},
[availableManualExecution, foreign.bridgeContract]
)
useEffect(
() => {
if (!message.data || !executionData || !availableManualExecution) return
try {
const fileName = 'warnRules'
const rules: WarnRule[] = require(`../snapshots/${fileName}.json`)
for (let rule of rules) {
if (matchesRule(rule, message)) {
setWarning(rule.message)
return
}
}
} catch (e) {}
},
[availableManualExecution, executionData, message, message.data, setWarning]
)
const getExecutionStatusElement = (validatorStatus = '') => { const getExecutionStatusElement = (validatorStatus = '') => {
switch (validatorStatus) { switch (validatorStatus) {
case VALIDATOR_CONFIRMATION_STATUS.EXECUTION_SUCCESS: case VALIDATOR_CONFIRMATION_STATUS.SUCCESS:
return <SuccessLabel>{validatorStatus}</SuccessLabel> return <SuccessLabel>{validatorStatus}</SuccessLabel>
case VALIDATOR_CONFIRMATION_STATUS.FAILED: case VALIDATOR_CONFIRMATION_STATUS.FAILED:
return <RedLabel>{validatorStatus}</RedLabel> return <RedLabel>{validatorStatus}</RedLabel>
@ -114,8 +68,6 @@ export const ExecutionConfirmation = ({
return ( return (
<StyledExecutionConfirmation> <StyledExecutionConfirmation>
{error && <ErrorAlert onClick={() => setError('')} error={error} />}
{warning && <WarningAlert onClick={() => setWarning('')} error={warning} />}
<table> <table>
<Thead> <Thead>
<tr> <tr>
@ -153,14 +105,10 @@ export const ExecutionConfirmation = ({
{availableManualExecution && ( {availableManualExecution && (
<td> <td>
<ManualExecutionButton <ManualExecutionButton
safeExecutionAvailable={safeExecutionAvailable} messageData={messageData}
messageData={message.data}
setExecutionData={setExecutionData} setExecutionData={setExecutionData}
confirmations={confirmations} signatureCollected={signatureCollected as string[]}
setPendingExecution={setPendingExecution} setPendingExecution={setPendingExecution}
setError={setError}
requiredSignatures={dstRequiredSignatures}
validatorList={dstValidatorList}
/> />
</td> </td>
)} )}

View File

@ -8,6 +8,7 @@ import { TransactionReceipt } from 'web3-eth'
import { InfoAlert } from './commons/InfoAlert' import { InfoAlert } from './commons/InfoAlert'
import { ExplorerTxLink } from './commons/ExplorerTxLink' import { ExplorerTxLink } from './commons/ExplorerTxLink'
import { FOREIGN_NETWORK_NAME, HOME_NETWORK_NAME } from '../config/constants' import { FOREIGN_NETWORK_NAME, HOME_NETWORK_NAME } from '../config/constants'
import { ErrorAlert } from './commons/ErrorAlert'
const StyledMainPage = styled.div` const StyledMainPage = styled.div`
text-align: center; text-align: center;
@ -51,7 +52,7 @@ export interface FormSubmitParams {
export const MainPage = () => { export const MainPage = () => {
const history = useHistory() const history = useHistory()
const { home, foreign } = useStateProvider() const { home, foreign, error, setError } = useStateProvider()
const [networkName, setNetworkName] = useState('') const [networkName, setNetworkName] = useState('')
const [receipt, setReceipt] = useState<Maybe<TransactionReceipt>>(null) const [receipt, setReceipt] = useState<Maybe<TransactionReceipt>>(null)
const [showInfoAlert, setShowInfoAlert] = useState(false) const [showInfoAlert, setShowInfoAlert] = useState(false)
@ -131,6 +132,7 @@ export const MainPage = () => {
</AlertP> </AlertP>
</InfoAlert> </InfoAlert>
)} )}
{error && <ErrorAlert onClick={() => setError('')} error={error} />}
<Route exact path={['/']} children={<Form onSubmit={onFormSubmit} />} /> <Route exact path={['/']} children={<Form onSubmit={onFormSubmit} />} />
<Route <Route
path={['/:chainId/:txHash/:messageIdParam', '/:chainId/:txHash']} path={['/:chainId/:txHash/:messageIdParam', '/:chainId/:txHash']}

View File

@ -14,92 +14,32 @@ import { useStateProvider } from '../state/StateProvider'
import { signatureToVRS, packSignatures } from '../utils/signatures' import { signatureToVRS, packSignatures } from '../utils/signatures'
import { getSuccessExecutionData } from '../utils/getFinalizationEvent' import { getSuccessExecutionData } from '../utils/getFinalizationEvent'
import { TransactionReceipt } from 'web3-eth' import { TransactionReceipt } from 'web3-eth'
import { ConfirmationParam } from '../hooks/useMessageConfirmations'
const ActionButton = styled.button` const StyledButton = styled.button`
color: var(--button-color); color: var(--button-color);
border-color: var(--font-color); border-color: var(--font-color);
margin-top: 10px; margin-top: 10px;
min-width: 120px;
padding: 1rem;
&:focus { &:focus {
outline: var(--button-color); outline: var(--button-color);
} }
` `
interface ManualExecutionButtonParams { interface ManualExecutionButtonParams {
safeExecutionAvailable: boolean
messageData: string messageData: string
setExecutionData: Function setExecutionData: Function
confirmations: ConfirmationParam[] signatureCollected: string[]
setPendingExecution: Function setPendingExecution: Function
setError: Function
requiredSignatures: number
validatorList: string[]
} }
export const ManualExecutionButton = ({ export const ManualExecutionButton = ({
safeExecutionAvailable,
messageData, messageData,
setExecutionData, setExecutionData,
confirmations, signatureCollected,
setPendingExecution, setPendingExecution
setError,
requiredSignatures,
validatorList
}: ManualExecutionButtonParams) => { }: ManualExecutionButtonParams) => {
const { foreign } = useStateProvider() const { foreign, setError } = useStateProvider()
const { library, activate, account, active } = useWeb3React() const { library, activate, account, active } = useWeb3React()
const [manualExecution, setManualExecution] = useState(false) const [manualExecution, setManualExecution] = useState(false)
const [allowFailures, setAllowFailures] = useState(false)
const [ready, setReady] = useState(false)
const [title, setTitle] = useState('Loading')
const [validSignatures, setValidSignatures] = useState<string[]>([])
useEffect(
() => {
if (
!foreign.bridgeContract ||
!foreign.web3 ||
!confirmations ||
!confirmations.length ||
!requiredSignatures ||
!validatorList ||
!validatorList.length
)
return
const signatures = []
for (let i = 0; i < confirmations.length && signatures.length < requiredSignatures; i++) {
const sig = confirmations[i].signature
if (!sig) {
continue
}
const { v, r, s } = signatureToVRS(sig)
const signer = foreign.web3.eth.accounts.recover(messageData, `0x${v}`, `0x${r}`, `0x${s}`)
if (validatorList.includes(signer)) {
signatures.push(sig)
}
}
if (signatures.length >= requiredSignatures) {
setValidSignatures(signatures.slice(0, requiredSignatures))
setTitle('Execute')
setReady(true)
} else {
setTitle('Unavailable')
}
},
[
foreign.bridgeContract,
foreign.web3,
validatorList,
requiredSignatures,
messageData,
setValidSignatures,
confirmations
]
)
useEffect( useEffect(
() => { () => {
@ -127,16 +67,12 @@ export const ManualExecutionButton = ({
return return
} }
if (!library || !foreign.bridgeContract || !foreign.web3 || !validSignatures || !validSignatures.length) return if (!library || !foreign.bridgeContract || !signatureCollected || !signatureCollected.length) return
const signatures = packSignatures(validSignatures.map(signatureToVRS)) const signatures = packSignatures(signatureCollected.map(signatureToVRS))
const messageId = messageData.slice(0, 66) const messageId = messageData.slice(0, 66)
const bridge = foreign.bridgeContract const bridge = foreign.bridgeContract
const executeMethod = const data = bridge.methods.executeSignatures(messageData, signatures).encodeABI()
safeExecutionAvailable && !allowFailures
? bridge.methods.safeExecuteSignaturesWithAutoGasLimit
: bridge.methods.executeSignatures
const data = executeMethod(messageData, signatures).encodeABI()
setManualExecution(false) setManualExecution(false)
library.eth library.eth
@ -194,38 +130,17 @@ export const ManualExecutionButton = ({
foreign.bridgeContract, foreign.bridgeContract,
setError, setError,
messageData, messageData,
signatureCollected,
setExecutionData, setExecutionData,
setPendingExecution, setPendingExecution
safeExecutionAvailable,
allowFailures,
foreign.web3,
validSignatures
] ]
) )
return ( return (
<div>
<div className="is-center"> <div className="is-center">
<ActionButton disabled={!ready} className="button outline" onClick={() => setManualExecution(true)}> <StyledButton className="button outline" onClick={() => setManualExecution(true)}>
{title} Execute
</ActionButton> </StyledButton>
</div>
{safeExecutionAvailable && (
<div
title="Allow executed message to fail and record its failure on-chain without reverting the whole transaction.
Use fixed gas limit for execution."
className="is-center"
style={{ paddingTop: 10 }}
>
<input
type="checkbox"
id="allow-failures"
checked={allowFailures}
onChange={e => setAllowFailures(e.target.checked)}
/>
<label htmlFor="allow-failures">Unsafe mode</label>
</div>
)}
</div> </div>
) )
} }

View File

@ -1,7 +1,7 @@
import React from 'react' import React from 'react'
import { formatTimestamp, formatTxHash, getExplorerTxUrl } from '../utils/networks' import { formatTimestamp, formatTxHash, getExplorerTxUrl } from '../utils/networks'
import { useWindowWidth } from '@react-hook/window-size' import { useWindowWidth } from '@react-hook/window-size'
import { RECENT_AGE, SEARCHING_TX, VALIDATOR_CONFIRMATION_STATUS } from '../config/constants' import { SEARCHING_TX, VALIDATOR_CONFIRMATION_STATUS } from '../config/constants'
import { SimpleLoading } from './commons/Loading' import { SimpleLoading } from './commons/Loading'
import styled from 'styled-components' import styled from 'styled-components'
import { ConfirmationParam } from '../hooks/useMessageConfirmations' import { ConfirmationParam } from '../hooks/useMessageConfirmations'
@ -31,9 +31,7 @@ export const ValidatorsConfirmations = ({
const getValidatorStatusElement = (validatorStatus = '') => { const getValidatorStatusElement = (validatorStatus = '') => {
switch (validatorStatus) { switch (validatorStatus) {
case VALIDATOR_CONFIRMATION_STATUS.SUCCESS: case VALIDATOR_CONFIRMATION_STATUS.SUCCESS:
case VALIDATOR_CONFIRMATION_STATUS.MANUAL: return <SuccessLabel>{validatorStatus}</SuccessLabel>
case VALIDATOR_CONFIRMATION_STATUS.FAILED_VALID:
return <SuccessLabel>{VALIDATOR_CONFIRMATION_STATUS.SUCCESS}</SuccessLabel>
case VALIDATOR_CONFIRMATION_STATUS.FAILED: case VALIDATOR_CONFIRMATION_STATUS.FAILED:
return <RedLabel>{validatorStatus}</RedLabel> return <RedLabel>{validatorStatus}</RedLabel>
case VALIDATOR_CONFIRMATION_STATUS.PENDING: case VALIDATOR_CONFIRMATION_STATUS.PENDING:
@ -60,28 +58,26 @@ export const ValidatorsConfirmations = ({
</tr> </tr>
</Thead> </Thead>
<tbody> <tbody>
{confirmations.map((confirmation, i) => { {validatorList.map((validator, i) => {
const displayedStatus = confirmation.status const filteredConfirmation = confirmations.filter(c => c.validator === validator)
const explorerLink = getExplorerTxUrl(confirmation.txHash, true) const confirmation = filteredConfirmation.length > 0 ? filteredConfirmation[0] : null
let elementIfNoTimestamp: any = <SimpleLoading /> const displayedStatus = confirmation && confirmation.status ? confirmation.status : ''
switch (displayedStatus) { const explorerLink = confirmation && confirmation.txHash ? getExplorerTxUrl(confirmation.txHash, true) : ''
case '': const elementIfNoTimestamp =
case VALIDATOR_CONFIRMATION_STATUS.UNDEFINED: displayedStatus !== VALIDATOR_CONFIRMATION_STATUS.WAITING &&
if (waitingBlocksResolved) { displayedStatus !== VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED ? (
elementIfNoTimestamp = SEARCHING_TX (displayedStatus === VALIDATOR_CONFIRMATION_STATUS.UNDEFINED || displayedStatus === '') &&
} waitingBlocksResolved ? (
break SEARCHING_TX
case VALIDATOR_CONFIRMATION_STATUS.WAITING: ) : (
case VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED: <SimpleLoading />
elementIfNoTimestamp = '' )
break ) : (
case VALIDATOR_CONFIRMATION_STATUS.MANUAL: ''
elementIfNoTimestamp = RECENT_AGE )
break
}
return ( return (
<tr key={i}> <tr key={i}>
<td>{windowWidth < 850 ? formatTxHash(confirmation.validator) : confirmation.validator}</td> <td>{windowWidth < 850 ? formatTxHash(validator) : validator}</td>
<StatusTd className="text-center">{getValidatorStatusElement(displayedStatus)}</StatusTd> <StatusTd className="text-center">{getValidatorStatusElement(displayedStatus)}</StatusTd>
<AgeTd className="text-center"> <AgeTd className="text-center">
{confirmation && confirmation.timestamp > 0 ? ( {confirmation && confirmation.timestamp > 0 ? (
@ -98,7 +94,7 @@ export const ValidatorsConfirmations = ({
</tbody> </tbody>
</table> </table>
<RequiredConfirmations> <RequiredConfirmations>
At least <strong>{requiredSignatures}</strong> of <strong>{validatorList.length}</strong> confirmations required {requiredSignatures} of {validatorList.length} confirmations required
</RequiredConfirmations> </RequiredConfirmations>
</div> </div>
) )

View File

@ -33,7 +33,7 @@ export const ErrorAlert = ({ onClick, error }: { onClick: () => void; error: str
} }
return ( return (
<div className="row is-center"> <div className="row is-center">
<StyledErrorAlert className="col-12 is-vertical-align row"> <StyledErrorAlert className="col-10 is-vertical-align row">
<InfoIcon color="var(--failed-color)" /> <InfoIcon color="var(--failed-color)" />
<TextContainer className="col-10"> <TextContainer className="col-10">
{text} {text}

View File

@ -1,34 +0,0 @@
import React from 'react'
import styled from 'styled-components'
import { InfoIcon } from './InfoIcon'
import { CloseIcon } from './CloseIcon'
const StyledErrorAlert = styled.div`
border: 1px solid var(--warning-color);
border-radius: 4px;
margin-bottom: 20px;
padding-top: 10px;
`
const CloseIconContainer = styled.div`
cursor: pointer;
`
const TextContainer = styled.div`
white-space: pre-wrap;
flex-direction: column;
`
export const WarningAlert = ({ onClick, error }: { onClick: () => void; error: string }) => {
return (
<div className="row is-center">
<StyledErrorAlert className="col-12 is-vertical-align row">
<InfoIcon color="var(--warning-color)" />
<TextContainer className="col-10">{error}</TextContainer>
<CloseIconContainer className="col-1 is-vertical-align is-center" onClick={onClick}>
<CloseIcon color="var(--warning-color)" />
</CloseIconContainer>
</StyledErrorAlert>
</div>
)
}

View File

@ -54,19 +54,14 @@ export const CONFIRMATIONS_STATUS = {
} }
export const VALIDATOR_CONFIRMATION_STATUS = { export const VALIDATOR_CONFIRMATION_STATUS = {
SUCCESS: 'Confirmed', SUCCESS: 'Success',
MANUAL: 'Manual',
EXECUTION_SUCCESS: 'Executed',
FAILED: 'Failed', FAILED: 'Failed',
FAILED_VALID: 'Failed valid',
PENDING: 'Pending', PENDING: 'Pending',
WAITING: 'Waiting', WAITING: 'Waiting',
NOT_REQUIRED: 'Not required', NOT_REQUIRED: 'Not required',
UNDEFINED: 'UNDEFINED' UNDEFINED: 'UNDEFINED'
} }
export const RECENT_AGE = 'Recent'
export const SEARCHING_TX = 'Searching Transaction...' export const SEARCHING_TX = 'Searching Transaction...'
export const INCORRECT_CHAIN_ERROR = `Incorrect chain chosen. Switch to ${FOREIGN_NETWORK_NAME} in the wallet.` export const INCORRECT_CHAIN_ERROR = `Incorrect chain chosen. Switch to ${FOREIGN_NETWORK_NAME} in the wallet.`

View File

@ -29,16 +29,17 @@ export interface useMessageConfirmationsParams {
foreignStartBlock: Maybe<number> foreignStartBlock: Maybe<number>
requiredSignatures: number requiredSignatures: number
validatorList: string[] validatorList: string[]
targetValidatorList: string[]
blockConfirmations: number blockConfirmations: number
} }
export interface ConfirmationParam { export interface BasicConfirmationParam {
validator: string validator: string
status: string status: string
}
export interface ConfirmationParam extends BasicConfirmationParam {
txHash: string txHash: string
timestamp: number timestamp: number
signature?: string
} }
export interface ExecutionData { export interface ExecutionData {
@ -47,7 +48,6 @@ export interface ExecutionData {
txHash: string txHash: string
timestamp: number timestamp: number
executionResult: boolean executionResult: boolean
blockNumber: number
} }
export const useMessageConfirmations = ({ export const useMessageConfirmations = ({
@ -58,7 +58,6 @@ export const useMessageConfirmations = ({
foreignStartBlock, foreignStartBlock,
requiredSignatures, requiredSignatures,
validatorList, validatorList,
targetValidatorList,
blockConfirmations blockConfirmations
}: useMessageConfirmationsParams) => { }: useMessageConfirmationsParams) => {
const { home, foreign } = useStateProvider() const { home, foreign } = useStateProvider()
@ -66,7 +65,7 @@ export const useMessageConfirmations = ({
const [status, setStatus] = useState(CONFIRMATIONS_STATUS.UNDEFINED) const [status, setStatus] = useState(CONFIRMATIONS_STATUS.UNDEFINED)
const [waitingBlocks, setWaitingBlocks] = useState(false) const [waitingBlocks, setWaitingBlocks] = useState(false)
const [waitingBlocksResolved, setWaitingBlocksResolved] = useState(false) const [waitingBlocksResolved, setWaitingBlocksResolved] = useState(false)
const [signatureCollected, setSignatureCollected] = useState(false) const [signatureCollected, setSignatureCollected] = useState<boolean | string[]>(false)
const [executionEventsFetched, setExecutionEventsFetched] = useState(false) const [executionEventsFetched, setExecutionEventsFetched] = useState(false)
const [collectedSignaturesEvent, setCollectedSignaturesEvent] = useState<Maybe<EventData>>(null) const [collectedSignaturesEvent, setCollectedSignaturesEvent] = useState<Maybe<EventData>>(null)
const [executionData, setExecutionData] = useState<ExecutionData>({ const [executionData, setExecutionData] = useState<ExecutionData>({
@ -74,8 +73,7 @@ export const useMessageConfirmations = ({
validator: '', validator: '',
txHash: '', txHash: '',
timestamp: 0, timestamp: 0,
executionResult: false, executionResult: false
blockNumber: 0
}) })
const [waitingBlocksForExecution, setWaitingBlocksForExecution] = useState(false) const [waitingBlocksForExecution, setWaitingBlocksForExecution] = useState(false)
const [waitingBlocksForExecutionResolved, setWaitingBlocksForExecutionResolved] = useState(false) const [waitingBlocksForExecutionResolved, setWaitingBlocksForExecutionResolved] = useState(false)
@ -142,9 +140,10 @@ export const useMessageConfirmations = ({
// The collected signature event is only fetched once the signatures are collected on tx from home to foreign, to calculate if // The collected signature event is only fetched once the signatures are collected on tx from home to foreign, to calculate if
// the execution tx on the foreign network is waiting for block confirmations // the execution tx on the foreign network is waiting for block confirmations
// This is executed if the message is in Home to Foreign direction only // This is executed if the message is in Home to Foreign direction only
const hasCollectedSignatures = !!signatureCollected // true or string[]
useEffect( useEffect(
() => { () => {
if (!fromHome || !receipt || !home.web3 || !home.bridgeContract || !signatureCollected) return if (!fromHome || !receipt || !home.web3 || !home.bridgeContract || !hasCollectedSignatures) return
let timeoutId: number let timeoutId: number
let isCancelled = false let isCancelled = false
@ -180,7 +179,7 @@ export const useMessageConfirmations = ({
isCancelled = true isCancelled = true
} }
}, },
[fromHome, home.bridgeContract, home.web3, message.data, receipt, signatureCollected] [fromHome, home.bridgeContract, home.web3, message.data, receipt, hasCollectedSignatures]
) )
// Check if the responsible validator is waiting for block confirmations to execute the message on foreign network // Check if the responsible validator is waiting for block confirmations to execute the message on foreign network
@ -253,35 +252,6 @@ export const useMessageConfirmations = ({
let timeoutId: number let timeoutId: number
let isCancelled = false let isCancelled = false
if (fromHome) {
if (!targetValidatorList || !targetValidatorList.length) return
const msgHash = home.web3.utils.sha3(message.data)!
const allValidators = [...validatorList, ...targetValidatorList].filter((v, i, s) => s.indexOf(v) === i)
const manualConfirmations = []
for (let i = 0; i < allValidators.length; i++) {
try {
const overrideSignatures: {
[key: string]: string
} = require(`../snapshots/signatures_${allValidators[i]}.json`)
if (overrideSignatures[msgHash]) {
console.log(`Adding manual signature from ${allValidators[i]}`)
manualConfirmations.push({
status: VALIDATOR_CONFIRMATION_STATUS.MANUAL,
validator: allValidators[i],
timestamp: 0,
txHash: '',
signature: overrideSignatures[msgHash]
})
} else {
console.log(`No manual signature from ${allValidators[i]} was found`)
}
} catch (e) {
console.log(`Signatures overrides are not present for ${allValidators[i]}`)
}
}
setConfirmations(manualConfirmations)
}
getConfirmationsForTx( getConfirmationsForTx(
message.data, message.data,
home.web3, home.web3,
@ -314,8 +284,7 @@ export const useMessageConfirmations = ({
home.bridgeContract, home.bridgeContract,
requiredSignatures, requiredSignatures,
waitingBlocksResolved, waitingBlocksResolved,
homeStartBlock, homeStartBlock
targetValidatorList
] ]
) )
@ -374,10 +343,7 @@ export const useMessageConfirmations = ({
// Sets the message status based in the collected information // Sets the message status based in the collected information
useEffect( useEffect(
() => { () => {
if ( if (executionData.status === VALIDATOR_CONFIRMATION_STATUS.SUCCESS && existsConfirmation(confirmations)) {
executionData.status === VALIDATOR_CONFIRMATION_STATUS.EXECUTION_SUCCESS &&
existsConfirmation(confirmations)
) {
const newStatus = executionData.executionResult const newStatus = executionData.executionResult
? CONFIRMATIONS_STATUS.SUCCESS ? CONFIRMATIONS_STATUS.SUCCESS
: CONFIRMATIONS_STATUS.SUCCESS_MESSAGE_FAILED : CONFIRMATIONS_STATUS.SUCCESS_MESSAGE_FAILED

View File

@ -4,13 +4,19 @@ import Web3 from 'web3'
import { getRequiredSignatures, getValidatorAddress, getValidatorList } from '../utils/contract' import { getRequiredSignatures, getValidatorAddress, getValidatorList } from '../utils/contract'
import { BRIDGE_VALIDATORS_ABI } from '../abis' import { BRIDGE_VALIDATORS_ABI } from '../abis'
import { useStateProvider } from '../state/StateProvider' import { useStateProvider } from '../state/StateProvider'
import { TransactionReceipt } from 'web3-eth'
import { foreignSnapshotProvider, homeSnapshotProvider, SnapshotProvider } from '../services/SnapshotProvider' import { foreignSnapshotProvider, homeSnapshotProvider, SnapshotProvider } from '../services/SnapshotProvider'
import { FOREIGN_EXPLORER_API, HOME_EXPLORER_API } from '../config/constants' import { FOREIGN_EXPLORER_API, HOME_EXPLORER_API } from '../config/constants'
export const useValidatorContract = (isHome: boolean, blockNumber: number | 'latest') => { export interface useValidatorContractParams {
fromHome: boolean
receipt: Maybe<TransactionReceipt>
}
export const useValidatorContract = ({ receipt, fromHome }: useValidatorContractParams) => {
const [validatorContract, setValidatorContract] = useState<Maybe<Contract>>(null) const [validatorContract, setValidatorContract] = useState<Maybe<Contract>>(null)
const [requiredSignatures, setRequiredSignatures] = useState(0) const [requiredSignatures, setRequiredSignatures] = useState(0)
const [validatorList, setValidatorList] = useState<string[]>([]) const [validatorList, setValidatorList] = useState([])
const { home, foreign } = useStateProvider() const { home, foreign } = useStateProvider()
@ -23,34 +29,34 @@ export const useValidatorContract = (isHome: boolean, blockNumber: number | 'lat
const callRequiredSignatures = async ( const callRequiredSignatures = async (
contract: Maybe<Contract>, contract: Maybe<Contract>,
blockNumber: number | 'latest', receipt: TransactionReceipt,
setResult: Function, setResult: Function,
snapshotProvider: SnapshotProvider, snapshotProvider: SnapshotProvider,
web3: Web3, web3: Web3,
api: string api: string
) => { ) => {
if (!contract) return if (!contract) return
const result = await getRequiredSignatures(contract, blockNumber, snapshotProvider, web3, api) const result = await getRequiredSignatures(contract, receipt.blockNumber, snapshotProvider, web3, api)
setResult(result) setResult(result)
} }
const callValidatorList = async ( const callValidatorList = async (
contract: Maybe<Contract>, contract: Maybe<Contract>,
blockNumber: number | 'latest', receipt: TransactionReceipt,
setResult: Function, setResult: Function,
snapshotProvider: SnapshotProvider, snapshotProvider: SnapshotProvider,
web3: Web3, web3: Web3,
api: string api: string
) => { ) => {
if (!contract) return if (!contract) return
const result = await getValidatorList(contract, blockNumber, snapshotProvider, web3, api) const result = await getValidatorList(contract, receipt.blockNumber, snapshotProvider, web3, api)
setResult(result) setResult(result)
} }
const web3 = isHome ? home.web3 : foreign.web3 const web3 = fromHome ? home.web3 : foreign.web3
const api = isHome ? HOME_EXPLORER_API : FOREIGN_EXPLORER_API const api = fromHome ? HOME_EXPLORER_API : FOREIGN_EXPLORER_API
const bridgeContract = isHome ? home.bridgeContract : foreign.bridgeContract const bridgeContract = fromHome ? home.bridgeContract : foreign.bridgeContract
const snapshotProvider = isHome ? homeSnapshotProvider : foreignSnapshotProvider const snapshotProvider = fromHome ? homeSnapshotProvider : foreignSnapshotProvider
useEffect( useEffect(
() => { () => {
@ -62,11 +68,11 @@ export const useValidatorContract = (isHome: boolean, blockNumber: number | 'lat
useEffect( useEffect(
() => { () => {
if (!web3 || !blockNumber) return if (!web3 || !receipt) return
callRequiredSignatures(validatorContract, blockNumber, setRequiredSignatures, snapshotProvider, web3, api) callRequiredSignatures(validatorContract, receipt, setRequiredSignatures, snapshotProvider, web3, api)
callValidatorList(validatorContract, blockNumber, setValidatorList, snapshotProvider, web3, api) callValidatorList(validatorContract, receipt, setValidatorList, snapshotProvider, web3, api)
}, },
[validatorContract, blockNumber, web3, snapshotProvider, api] [validatorContract, receipt, web3, snapshotProvider, api]
) )
return { return {

View File

@ -1,4 +1,4 @@
import React, { createContext, ReactNode } from 'react' import React, { createContext, ReactNode, useState } from 'react'
import { useNetwork } from '../hooks/useNetwork' import { useNetwork } from '../hooks/useNetwork'
import { import {
HOME_RPC_URL, HOME_RPC_URL,
@ -25,6 +25,8 @@ export interface StateContext {
home: BaseNetworkParams home: BaseNetworkParams
foreign: BaseNetworkParams foreign: BaseNetworkParams
loading: boolean loading: boolean
error: string
setError: Function
} }
const initialState = { const initialState = {
@ -42,7 +44,9 @@ const initialState = {
bridgeAddress: FOREIGN_BRIDGE_ADDRESS, bridgeAddress: FOREIGN_BRIDGE_ADDRESS,
bridgeContract: null bridgeContract: null
}, },
loading: true loading: true,
error: '',
setError: () => {}
} }
const StateContext = createContext<StateContext>(initialState) const StateContext = createContext<StateContext>(initialState)
@ -54,6 +58,7 @@ export const StateProvider = ({ children }: { children: ReactNode }) => {
homeWeb3: homeNetwork.web3, homeWeb3: homeNetwork.web3,
foreignWeb3: foreignNetwork.web3 foreignWeb3: foreignNetwork.web3
}) })
const [error, setError] = useState('')
const value = { const value = {
home: { home: {
@ -68,7 +73,9 @@ export const StateProvider = ({ children }: { children: ReactNode }) => {
bridgeContract: foreignBridge, bridgeContract: foreignBridge,
...foreignNetwork ...foreignNetwork
}, },
loading: homeNetwork.loading || foreignNetwork.loading loading: homeNetwork.loading || foreignNetwork.loading,
error,
setError
} }
return <StateContext.Provider value={value}>{children}</StateContext.Provider> return <StateContext.Provider value={value}>{children}</StateContext.Provider>

View File

@ -28,7 +28,5 @@ export const GlobalStyle = createGlobalStyle<{ theme: ThemeType }>`
--not-required-bg-color: ${props => props.theme.notRequired.backgroundColor}; --not-required-bg-color: ${props => props.theme.notRequired.backgroundColor};
--failed-color: ${props => props.theme.failed.textColor}; --failed-color: ${props => props.theme.failed.textColor};
--failed-bg-color: ${props => props.theme.failed.backgroundColor}; --failed-bg-color: ${props => props.theme.failed.backgroundColor};
--warning-color: ${props => props.theme.warning.textColor};
--warning-bg-color: ${props => props.theme.warning.backgroundColor};
} }
` `

View File

@ -17,10 +17,6 @@ const theme = {
failed: { failed: {
textColor: '#de4437', textColor: '#de4437',
backgroundColor: 'rgba(222,68,55,.1)' backgroundColor: 'rgba(222,68,55,.1)'
},
warning: {
textColor: '#ffa758',
backgroundColor: 'rgba(222,68,55,.1)'
} }
} }
export default theme export default theme

View File

@ -14,40 +14,37 @@ const messageData = '0x123456'
const OTHER_HASH = 'aabbccdd' const OTHER_HASH = 'aabbccdd'
const bridgeAddress = '0xFe446bEF1DbF7AFE24E81e05BC8B271C1BA9a560' const bridgeAddress = '0xFe446bEF1DbF7AFE24E81e05BC8B271C1BA9a560'
const otherAddress = '0xD4075FB57fCf038bFc702c915Ef9592534bED5c1' const otherAddress = '0xD4075FB57fCf038bFc702c915Ef9592534bED5c1'
const validator1 = '0x45b96809336A8b714BFbdAB3E4B5e0fe5d839908'
const validator2 = '0xAe8bFfc8BBc6AAa9E21ED1E4e4957fe798BEA25f'
const validator3 = '0x285A6eB779be4db94dA65e2F3518B1c5F0f71244'
describe('getFailedTransactions', () => { describe('getFailedTransactions', () => {
test('should only return failed transactions', async () => { test('should only return failed transactions', async () => {
const to = otherAddress const to = otherAddress
const transactions = [ const transactions = [
{ isError: '0', to, from: validator1 }, { isError: '0', to },
{ isError: '1', to, from: validator1 }, { isError: '1', to },
{ isError: '0', to, from: validator2 }, { isError: '0', to },
{ isError: '1', to, from: validator2 }, { isError: '1', to },
{ isError: '1', to, from: validator3 } { isError: '1', to }
] ]
const fetchAccountTransactions = jest.fn().mockImplementation(() => transactions) const fetchAccountTransactions = jest.fn().mockImplementation(() => transactions)
const result = await getFailedTransactions(validator1, to, 0, 1, '', fetchAccountTransactions) const result = await getFailedTransactions('', to, 0, 1, '', fetchAccountTransactions)
expect(result.length).toEqual(1) expect(result.length).toEqual(3)
}) })
}) })
describe('getSuccessTransactions', () => { describe('getSuccessTransactions', () => {
test('should only return success transactions', async () => { test('should only return success transactions', async () => {
const to = otherAddress const to = otherAddress
const transactions = [ const transactions = [
{ isError: '0', to, from: validator1 }, { isError: '0', to },
{ isError: '1', to, from: validator1 }, { isError: '1', to },
{ isError: '0', to, from: validator2 }, { isError: '0', to },
{ isError: '1', to, from: validator2 }, { isError: '1', to },
{ isError: '1', to, from: validator3 } { isError: '1', to }
] ]
const fetchAccountTransactions = jest.fn().mockImplementation(() => transactions) const fetchAccountTransactions = jest.fn().mockImplementation(() => transactions)
const result = await getSuccessTransactions(validator1, to, 0, 1, '', fetchAccountTransactions) const result = await getSuccessTransactions('', to, 0, 1, '', fetchAccountTransactions)
expect(result.length).toEqual(1) expect(result.length).toEqual(2)
}) })
}) })
describe('filterValidatorSignatureTransaction', () => { describe('filterValidatorSignatureTransaction', () => {

View File

@ -5,7 +5,7 @@ import Web3 from 'web3'
import { Contract } from 'web3-eth-contract' import { Contract } from 'web3-eth-contract'
import { APIPendingTransaction, APITransaction } from '../explorer' import { APIPendingTransaction, APITransaction } from '../explorer'
import { VALIDATOR_CONFIRMATION_STATUS } from '../../config/constants' import { VALIDATOR_CONFIRMATION_STATUS } from '../../config/constants'
import { ConfirmationParam } from '../../hooks/useMessageConfirmations' import { BasicConfirmationParam } from '../../hooks/useMessageConfirmations'
jest.mock('../validatorConfirmationHelpers') jest.mock('../validatorConfirmationHelpers')
@ -18,9 +18,6 @@ const messageData = '0x111111111'
const web3 = { const web3 = {
utils: { utils: {
soliditySha3Raw: (data: string) => `0xaaaa${data.replace('0x', '')}` soliditySha3Raw: (data: string) => `0xaaaa${data.replace('0x', '')}`
},
eth: {
accounts: new Web3().eth.accounts
} }
} as Web3 } as Web3
const validator1 = '0x45b96809336A8b714BFbdAB3E4B5e0fe5d839908' const validator1 = '0x45b96809336A8b714BFbdAB3E4B5e0fe5d839908'
@ -28,7 +25,7 @@ const validator2 = '0xAe8bFfc8BBc6AAa9E21ED1E4e4957fe798BEA25f'
const validator3 = '0x285A6eB779be4db94dA65e2F3518B1c5F0f71244' const validator3 = '0x285A6eB779be4db94dA65e2F3518B1c5F0f71244'
const validatorList = [validator1, validator2, validator3] const validatorList = [validator1, validator2, validator3]
const signature = const signature =
'0x6f5b74905669999f1abdb52e1e215506907e1849aac7b31854da458b33a5954e15b165007c3703cfd16e61ca46a96a56727ed11fa47be359d3834515accd016e1b' '0x519d704bceed17423daa79c20531cc34fc27a4be6e53fc5069a8023019188ca4519d704bceed17423daa79c20531cc34fc27a4be6e53fc5069a8023019188ca4'
const bridgeContract = { const bridgeContract = {
methods: { methods: {
signature: () => ({ signature: () => ({
@ -64,19 +61,19 @@ describe('getConfirmationsForTx', () => {
validator, validator,
status: validator !== validator3 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED status: validator !== validator3 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
})) }))
getSuccessExecutionTransaction.mockImplementation(() => async (validatorData: ConfirmationParam) => ({ getSuccessExecutionTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
validator: validatorData.validator, validator: validatorData.validator,
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
txHash: '', txHash: '',
timestamp: 0 timestamp: 0
})) }))
getValidatorFailedTransaction.mockImplementation(() => async (validatorData: ConfirmationParam) => ({ getValidatorFailedTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
validator: validatorData.validator, validator: validatorData.validator,
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
txHash: '', txHash: '',
timestamp: 0 timestamp: 0
})) }))
getValidatorPendingTransaction.mockImplementation(() => async (validatorData: ConfirmationParam) => ({ getValidatorPendingTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
validator: validatorData.validator, validator: validatorData.validator,
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
txHash: '', txHash: '',
@ -113,8 +110,9 @@ describe('getConfirmationsForTx', () => {
expect(setResult).toBeCalledTimes(2) expect(setResult).toBeCalledTimes(2)
expect(getValidatorConfirmation).toBeCalledTimes(1) expect(getValidatorConfirmation).toBeCalledTimes(1)
expect(getSuccessExecutionTransaction).toBeCalledTimes(1) expect(getSuccessExecutionTransaction).toBeCalledTimes(1)
expect(setSignatureCollected).toBeCalledTimes(1) expect(setSignatureCollected).toBeCalledTimes(2)
expect(setSignatureCollected.mock.calls[0][0]).toEqual(true) expect(setSignatureCollected.mock.calls[0][0]).toEqual(true)
expect(setSignatureCollected.mock.calls[1][0]).toEqual([signature, signature])
expect(getValidatorFailedTransaction).toBeCalledTimes(1) expect(getValidatorFailedTransaction).toBeCalledTimes(1)
expect(setFailedConfirmations).toBeCalledTimes(1) expect(setFailedConfirmations).toBeCalledTimes(1)
@ -137,7 +135,7 @@ describe('getConfirmationsForTx', () => {
expect.arrayContaining([ expect.arrayContaining([
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS }, { validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS }, { validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED, txHash: '', timestamp: 0 } { validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED }
]) ])
) )
}) })
@ -146,19 +144,19 @@ describe('getConfirmationsForTx', () => {
validator, validator,
status: validator === validator3 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED status: validator === validator3 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
})) }))
getSuccessExecutionTransaction.mockImplementation(() => async (validatorData: ConfirmationParam) => ({ getSuccessExecutionTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
validator: validatorData.validator, validator: validatorData.validator,
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
txHash: '', txHash: '',
timestamp: 0 timestamp: 0
})) }))
getValidatorFailedTransaction.mockImplementation(() => async (validatorData: ConfirmationParam) => ({ getValidatorFailedTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
validator: validatorData.validator, validator: validatorData.validator,
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
txHash: '', txHash: '',
timestamp: 0 timestamp: 0
})) }))
getValidatorPendingTransaction.mockImplementation(() => async (validatorData: ConfirmationParam) => ({ getValidatorPendingTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
validator: validatorData.validator, validator: validatorData.validator,
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
txHash: '', txHash: '',
@ -210,19 +208,19 @@ describe('getConfirmationsForTx', () => {
validator, validator,
status: validator !== validator3 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED status: validator !== validator3 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
})) }))
getSuccessExecutionTransaction.mockImplementation(() => async (validatorData: ConfirmationParam) => ({ getSuccessExecutionTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
validator: validatorData.validator, validator: validatorData.validator,
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
txHash: validatorData.validator !== validator3 ? '0x123' : '', txHash: validatorData.validator !== validator3 ? '0x123' : '',
timestamp: validatorData.validator !== validator3 ? 123 : 0 timestamp: validatorData.validator !== validator3 ? 123 : 0
})) }))
getValidatorFailedTransaction.mockImplementation(() => async (validatorData: ConfirmationParam) => ({ getValidatorFailedTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
validator: validatorData.validator, validator: validatorData.validator,
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
txHash: '', txHash: '',
timestamp: 0 timestamp: 0
})) }))
getValidatorPendingTransaction.mockImplementation(() => async (validatorData: ConfirmationParam) => ({ getValidatorPendingTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
validator: validatorData.validator, validator: validatorData.validator,
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
txHash: '', txHash: '',
@ -259,8 +257,9 @@ describe('getConfirmationsForTx', () => {
expect(setResult).toBeCalledTimes(3) expect(setResult).toBeCalledTimes(3)
expect(getValidatorConfirmation).toBeCalledTimes(1) expect(getValidatorConfirmation).toBeCalledTimes(1)
expect(getSuccessExecutionTransaction).toBeCalledTimes(1) expect(getSuccessExecutionTransaction).toBeCalledTimes(1)
expect(setSignatureCollected).toBeCalledTimes(1) expect(setSignatureCollected).toBeCalledTimes(2)
expect(setSignatureCollected.mock.calls[0][0]).toEqual(true) expect(setSignatureCollected.mock.calls[0][0]).toEqual(true)
expect(setSignatureCollected.mock.calls[1][0]).toEqual([signature, signature])
expect(getValidatorFailedTransaction).toBeCalledTimes(1) expect(getValidatorFailedTransaction).toBeCalledTimes(1)
expect(setFailedConfirmations).toBeCalledTimes(1) expect(setFailedConfirmations).toBeCalledTimes(1)
@ -282,16 +281,16 @@ describe('getConfirmationsForTx', () => {
) )
expect(res2).toEqual( expect(res2).toEqual(
expect.arrayContaining([ expect.arrayContaining([
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 }, { validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 }, { validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED } { validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED }
]) ])
) )
expect(res3).toEqual( expect(res3).toEqual(
expect.arrayContaining([ expect.arrayContaining([
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 }, { validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 }, { validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED, txHash: '', timestamp: 0 } { validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED }
]) ])
) )
}) })
@ -305,22 +304,22 @@ describe('getConfirmationsForTx', () => {
? VALIDATOR_CONFIRMATION_STATUS.SUCCESS ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS
: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
})) }))
getSuccessExecutionTransaction.mockImplementation(() => async (validatorData: ConfirmationParam) => ({ getSuccessExecutionTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
validator: validatorData.validator, validator: validatorData.validator,
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
txHash: validatorData.validator !== validator3 && validatorData.validator !== validator4 ? '0x123' : '', txHash: validatorData.validator !== validator3 && validatorData.validator !== validator4 ? '0x123' : '',
timestamp: validatorData.validator !== validator3 && validatorData.validator !== validator4 ? 123 : 0 timestamp: validatorData.validator !== validator3 && validatorData.validator !== validator4 ? 123 : 0
})) }))
getValidatorFailedTransaction.mockImplementation(() => async (validatorData: ConfirmationParam) => ({ getValidatorFailedTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
validator: validatorData.validator, validator: validatorData.validator,
status: status:
validatorData.validator === validator3 validatorData.validator === validator3
? VALIDATOR_CONFIRMATION_STATUS.FAILED_VALID ? VALIDATOR_CONFIRMATION_STATUS.FAILED
: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED, : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
txHash: validatorData.validator === validator3 ? '0x123' : '', txHash: validatorData.validator === validator3 ? '0x123' : '',
timestamp: validatorData.validator === validator3 ? 123 : 0 timestamp: validatorData.validator === validator3 ? 123 : 0
})) }))
getValidatorPendingTransaction.mockImplementation(() => async (validatorData: ConfirmationParam) => ({ getValidatorPendingTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
validator: validatorData.validator, validator: validatorData.validator,
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
txHash: '', txHash: '',
@ -357,8 +356,9 @@ describe('getConfirmationsForTx', () => {
expect(setResult).toBeCalledTimes(4) expect(setResult).toBeCalledTimes(4)
expect(getValidatorConfirmation).toBeCalledTimes(1) expect(getValidatorConfirmation).toBeCalledTimes(1)
expect(getSuccessExecutionTransaction).toBeCalledTimes(1) expect(getSuccessExecutionTransaction).toBeCalledTimes(1)
expect(setSignatureCollected).toBeCalledTimes(1) expect(setSignatureCollected).toBeCalledTimes(2)
expect(setSignatureCollected.mock.calls[0][0]).toEqual(true) expect(setSignatureCollected.mock.calls[0][0]).toEqual(true)
expect(setSignatureCollected.mock.calls[1][0]).toEqual([signature, signature])
expect(getValidatorFailedTransaction).toBeCalledTimes(1) expect(getValidatorFailedTransaction).toBeCalledTimes(1)
expect(setFailedConfirmations).toBeCalledTimes(1) expect(setFailedConfirmations).toBeCalledTimes(1)
@ -382,26 +382,26 @@ describe('getConfirmationsForTx', () => {
) )
expect(res2).toEqual( expect(res2).toEqual(
expect.arrayContaining([ expect.arrayContaining([
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 }, { validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 }, { validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED }, { validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
{ validator: validator4, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED } { validator: validator4, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED }
]) ])
) )
expect(res3).toEqual( expect(res3).toEqual(
expect.arrayContaining([ expect.arrayContaining([
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 }, { validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 }, { validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.FAILED_VALID, txHash: '0x123', timestamp: 123 }, { validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
{ validator: validator4, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED } { validator: validator4, status: VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED }
]) ])
) )
expect(res4).toEqual( expect(res4).toEqual(
expect.arrayContaining([ expect.arrayContaining([
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 }, { validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 }, { validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.FAILED_VALID, txHash: '0x123', timestamp: 123 }, { validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
{ validator: validator4, status: VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED, txHash: '', timestamp: 0 } { validator: validator4, status: VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED }
]) ])
) )
}) })
@ -414,22 +414,22 @@ describe('getConfirmationsForTx', () => {
validator, validator,
status: validator === validator1 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED status: validator === validator1 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
})) }))
getSuccessExecutionTransaction.mockImplementation(() => async (validatorData: ConfirmationParam) => ({ getSuccessExecutionTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
validator: validatorData.validator, validator: validatorData.validator,
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
txHash: validatorData.validator === validator1 ? '0x123' : '', txHash: validatorData.validator === validator1 ? '0x123' : '',
timestamp: validatorData.validator === validator1 ? 123 : 0 timestamp: validatorData.validator === validator1 ? 123 : 0
})) }))
getValidatorFailedTransaction.mockImplementation(() => async (validatorData: ConfirmationParam) => ({ getValidatorFailedTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
validator: validatorData.validator, validator: validatorData.validator,
status: status:
validatorData.validator === validator2 validatorData.validator === validator2
? VALIDATOR_CONFIRMATION_STATUS.FAILED_VALID ? VALIDATOR_CONFIRMATION_STATUS.FAILED
: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED, : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
txHash: validatorData.validator === validator2 ? '0x123' : '', txHash: validatorData.validator === validator2 ? '0x123' : '',
timestamp: validatorData.validator === validator2 ? 123 : 0 timestamp: validatorData.validator === validator2 ? 123 : 0
})) }))
getValidatorPendingTransaction.mockImplementation(() => async (validatorData: ConfirmationParam) => ({ getValidatorPendingTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
validator: validatorData.validator, validator: validatorData.validator,
status: status:
validatorData.validator === validator3 validatorData.validator === validator3
@ -492,22 +492,22 @@ describe('getConfirmationsForTx', () => {
) )
expect(res2).toEqual( expect(res2).toEqual(
expect.arrayContaining([ expect.arrayContaining([
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 }, { validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED }, { validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED },
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED } { validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.PENDING, txHash: '0x123', timestamp: 123 }
]) ])
) )
expect(res3).toEqual( expect(res3).toEqual(
expect.arrayContaining([ expect.arrayContaining([
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 }, { validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED }, { validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.PENDING, txHash: '0x123', timestamp: 123 } { validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.PENDING, txHash: '0x123', timestamp: 123 }
]) ])
) )
expect(res4).toEqual( expect(res4).toEqual(
expect.arrayContaining([ expect.arrayContaining([
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 }, { validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED_VALID, txHash: '0x123', timestamp: 123 }, { validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.PENDING, txHash: '0x123', timestamp: 123 } { validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.PENDING, txHash: '0x123', timestamp: 123 }
]) ])
) )
@ -521,13 +521,13 @@ describe('getConfirmationsForTx', () => {
validator, validator,
status: validator === validator1 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED status: validator === validator1 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
})) }))
getSuccessExecutionTransaction.mockImplementation(() => async (validatorData: ConfirmationParam) => ({ getSuccessExecutionTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
validator: validatorData.validator, validator: validatorData.validator,
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
txHash: validatorData.validator === validator1 ? '0x123' : '', txHash: validatorData.validator === validator1 ? '0x123' : '',
timestamp: validatorData.validator === validator1 ? 123 : 0 timestamp: validatorData.validator === validator1 ? 123 : 0
})) }))
getValidatorFailedTransaction.mockImplementation(() => async (validatorData: ConfirmationParam) => ({ getValidatorFailedTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
validator: validatorData.validator, validator: validatorData.validator,
status: status:
validatorData.validator !== validator1 validatorData.validator !== validator1
@ -536,7 +536,7 @@ describe('getConfirmationsForTx', () => {
txHash: validatorData.validator !== validator1 ? '0x123' : '', txHash: validatorData.validator !== validator1 ? '0x123' : '',
timestamp: validatorData.validator !== validator1 ? 123 : 0 timestamp: validatorData.validator !== validator1 ? 123 : 0
})) }))
getValidatorPendingTransaction.mockImplementation(() => async (validatorData: ConfirmationParam) => ({ getValidatorPendingTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
validator: validatorData.validator, validator: validatorData.validator,
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
txHash: '', txHash: '',
@ -596,9 +596,9 @@ describe('getConfirmationsForTx', () => {
) )
expect(res2).toEqual( expect(res2).toEqual(
expect.arrayContaining([ expect.arrayContaining([
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 }, { validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED }, { validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED } { validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 }
]) ])
) )
expect(res3).toEqual( expect(res3).toEqual(
@ -610,13 +610,9 @@ describe('getConfirmationsForTx', () => {
) )
}) })
test('should remove pending state after transaction mined', async () => { test('should remove pending state after transaction mined', async () => {
const validator4 = '0x9d2dC11C342F4eF3C5491A048D0f0eBCd2D8f7C3' // Validator1 success
const validatorList = [validator1, validator2, validator3, validator4] // Validator2 failed
// Validator3 Pending
// Validator1 success (ts=100)
// Validator2 failed (ts=200)
// Validator3 Pending (ts=300)
// Validator4 Excess confirmation (Failed) (ts=400)
getValidatorConfirmation getValidatorConfirmation
.mockImplementationOnce(() => async (validator: string) => ({ .mockImplementationOnce(() => async (validator: string) => ({
@ -627,57 +623,41 @@ describe('getConfirmationsForTx', () => {
.mockImplementation(() => async (validator: string) => ({ .mockImplementation(() => async (validator: string) => ({
validator, validator,
status: status:
validator === validator1 || validator === validator3 validator !== validator2 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
? VALIDATOR_CONFIRMATION_STATUS.SUCCESS
: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
})) }))
getSuccessExecutionTransaction getSuccessExecutionTransaction
.mockImplementationOnce(() => async (validatorData: ConfirmationParam) => ({ .mockImplementationOnce(() => async (validatorData: BasicConfirmationParam) => ({
validator: validatorData.validator, validator: validatorData.validator,
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
txHash: validatorData.validator === validator1 ? '0x100' : '', txHash: validatorData.validator === validator1 ? '0x123' : '',
timestamp: validatorData.validator === validator1 ? 100 : 0 timestamp: validatorData.validator === validator1 ? 123 : 0
})) }))
.mockImplementation(() => async (validatorData: ConfirmationParam) => ({ .mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
validator: validatorData.validator, validator: validatorData.validator,
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
txHash: txHash: validatorData.validator !== validator2 ? '0x123' : '',
validatorData.validator === validator1 ? '0x100' : validatorData.validator === validator3 ? '0x300' : '', timestamp: validatorData.validator !== validator2 ? 123 : 0
timestamp: validatorData.validator === validator1 ? 100 : validatorData.validator === validator3 ? 300 : ''
})) }))
getValidatorFailedTransaction getValidatorFailedTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
.mockImplementationOnce(() => async (validatorData: ConfirmationParam) => ({
validator: validatorData.validator, validator: validatorData.validator,
status: status:
validatorData.validator === validator2 validatorData.validator === validator2
? VALIDATOR_CONFIRMATION_STATUS.FAILED ? VALIDATOR_CONFIRMATION_STATUS.FAILED
: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED, : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
txHash: validatorData.validator === validator2 ? '0x200' : '', txHash: validatorData.validator === validator2 ? '0x123' : '',
timestamp: validatorData.validator === validator2 ? 200 : 0 timestamp: validatorData.validator === validator2 ? 123 : 0
}))
.mockImplementation(() => async (validatorData: ConfirmationParam) => ({
validator: validatorData.validator,
status:
validatorData.validator === validator2 || validatorData.validator === validator4
? validatorData.validator === validator2
? VALIDATOR_CONFIRMATION_STATUS.FAILED
: VALIDATOR_CONFIRMATION_STATUS.FAILED_VALID
: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
txHash:
validatorData.validator === validator2 ? '0x200' : validatorData.validator === validator4 ? '0x400' : '',
timestamp: validatorData.validator === validator2 ? 200 : validatorData.validator === validator4 ? 400 : ''
})) }))
getValidatorPendingTransaction getValidatorPendingTransaction
.mockImplementationOnce(() => async (validatorData: ConfirmationParam) => ({ .mockImplementationOnce(() => async (validatorData: BasicConfirmationParam) => ({
validator: validatorData.validator, validator: validatorData.validator,
status: status:
validatorData.validator === validator3 validatorData.validator === validator3
? VALIDATOR_CONFIRMATION_STATUS.PENDING ? VALIDATOR_CONFIRMATION_STATUS.PENDING
: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED, : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
txHash: validatorData.validator === validator3 ? '0x300' : '', txHash: validatorData.validator === validator3 ? '0x123' : '',
timestamp: validatorData.validator === validator3 ? 300 : 0 timestamp: validatorData.validator === validator3 ? 123 : 0
})) }))
.mockImplementationOnce(() => async (validatorData: ConfirmationParam) => ({ .mockImplementationOnce(() => async (validatorData: BasicConfirmationParam) => ({
validator: validatorData.validator, validator: validatorData.validator,
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
txHash: '', txHash: '',
@ -718,7 +698,7 @@ describe('getConfirmationsForTx', () => {
expect(getValidatorFailedTransaction).toBeCalledTimes(1) expect(getValidatorFailedTransaction).toBeCalledTimes(1)
expect(setFailedConfirmations).toBeCalledTimes(1) expect(setFailedConfirmations).toBeCalledTimes(1)
expect(setFailedConfirmations.mock.calls[0][0]).toEqual(true) expect(setFailedConfirmations.mock.calls[0][0]).toEqual(false)
expect(getValidatorPendingTransaction).toBeCalledTimes(1) expect(getValidatorPendingTransaction).toBeCalledTimes(1)
expect(setPendingConfirmations).toBeCalledTimes(1) expect(setPendingConfirmations).toBeCalledTimes(1)
@ -732,32 +712,28 @@ describe('getConfirmationsForTx', () => {
expect.arrayContaining([ expect.arrayContaining([
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS }, { validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED }, { validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED },
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED }, { validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED }
{ validator: validator4, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED }
]) ])
) )
expect(res2).toEqual( expect(res2).toEqual(
expect.arrayContaining([ expect.arrayContaining([
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x100', timestamp: 100 }, { validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED }, { validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED },
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED }, { validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.PENDING, txHash: '0x123', timestamp: 123 }
{ validator: validator4, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED }
]) ])
) )
expect(res3).toEqual( expect(res3).toEqual(
expect.arrayContaining([ expect.arrayContaining([
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x100', timestamp: 100 }, { validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED }, { validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.PENDING, txHash: '0x300', timestamp: 300 }, { validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.PENDING, txHash: '0x123', timestamp: 123 }
{ validator: validator4, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED }
]) ])
) )
expect(res4).toEqual( expect(res4).toEqual(
expect.arrayContaining([ expect.arrayContaining([
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x100', timestamp: 100 }, { validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x200', timestamp: 200 }, { validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.PENDING, txHash: '0x300', timestamp: 300 }, { validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.PENDING, txHash: '0x123', timestamp: 123 }
{ validator: validator4, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED }
]) ])
) )
@ -785,13 +761,14 @@ describe('getConfirmationsForTx', () => {
expect(setResult).toBeCalledTimes(7) expect(setResult).toBeCalledTimes(7)
expect(getValidatorConfirmation).toBeCalledTimes(2) expect(getValidatorConfirmation).toBeCalledTimes(2)
expect(getSuccessExecutionTransaction).toBeCalledTimes(2) expect(getSuccessExecutionTransaction).toBeCalledTimes(2)
expect(setSignatureCollected).toBeCalledTimes(2) expect(setSignatureCollected).toBeCalledTimes(3)
expect(setSignatureCollected.mock.calls[0][0]).toEqual(false) expect(setSignatureCollected.mock.calls[0][0]).toEqual(false)
expect(setSignatureCollected.mock.calls[1][0]).toEqual(true) expect(setSignatureCollected.mock.calls[1][0]).toEqual(true)
expect(setSignatureCollected.mock.calls[2][0]).toEqual([signature, signature])
expect(getValidatorFailedTransaction).toBeCalledTimes(2) expect(getValidatorFailedTransaction).toBeCalledTimes(2)
expect(setFailedConfirmations).toBeCalledTimes(2) expect(setFailedConfirmations).toBeCalledTimes(2)
expect(setFailedConfirmations.mock.calls[0][0]).toEqual(true) expect(setFailedConfirmations.mock.calls[0][0]).toEqual(false)
expect(setFailedConfirmations.mock.calls[1][0]).toEqual(false) expect(setFailedConfirmations.mock.calls[1][0]).toEqual(false)
expect(getValidatorPendingTransaction).toBeCalledTimes(1) expect(getValidatorPendingTransaction).toBeCalledTimes(1)
@ -804,26 +781,23 @@ describe('getConfirmationsForTx', () => {
const res7 = setResult.mock.calls[6][0](res6) const res7 = setResult.mock.calls[6][0](res6)
expect(res5).toEqual( expect(res5).toEqual(
expect.arrayContaining([ expect.arrayContaining([
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x100', timestamp: 100 }, { validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x200', timestamp: 200 }, { validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x300', timestamp: 300 }, { validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS }
{ validator: validator4, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED }
]) ])
) )
expect(res6).toEqual( expect(res6).toEqual(
expect.arrayContaining([ expect.arrayContaining([
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x100', timestamp: 100 }, { validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x200', timestamp: 200 }, { validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x300', timestamp: 300 }, { validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS }
{ validator: validator4, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED }
]) ])
) )
expect(res7).toEqual( expect(res7).toEqual(
expect.arrayContaining([ expect.arrayContaining([
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x100', timestamp: 100 }, { validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x200', timestamp: 200 }, { validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x300', timestamp: 300 }, { validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 }
{ validator: validator4, status: VALIDATOR_CONFIRMATION_STATUS.FAILED_VALID, txHash: '0x400', timestamp: 400 }
]) ])
) )
}) })

View File

@ -84,11 +84,10 @@ describe('getFinalizationEvent', () => {
expect(setResult).toBeCalledTimes(1) expect(setResult).toBeCalledTimes(1)
expect(setResult.mock.calls[0][0]).toEqual({ expect(setResult.mock.calls[0][0]).toEqual({
validator: validator1, validator: validator1,
status: VALIDATOR_CONFIRMATION_STATUS.EXECUTION_SUCCESS, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
txHash, txHash,
timestamp, timestamp,
executionResult: true, executionResult: true
blockNumber: 5523145
}) })
expect(getFailedExecution).toBeCalledTimes(0) expect(getFailedExecution).toBeCalledTimes(0)
@ -238,8 +237,7 @@ describe('getFinalizationEvent', () => {
status: VALIDATOR_CONFIRMATION_STATUS.PENDING, status: VALIDATOR_CONFIRMATION_STATUS.PENDING,
txHash, txHash,
timestamp: expect.any(Number), timestamp: expect.any(Number),
executionResult: false, executionResult: false
blockNumber: 0
}) })
expect(getFailedExecution).toBeCalledTimes(0) expect(getFailedExecution).toBeCalledTimes(0)
@ -296,8 +294,7 @@ describe('getFinalizationEvent', () => {
status: VALIDATOR_CONFIRMATION_STATUS.FAILED, status: VALIDATOR_CONFIRMATION_STATUS.FAILED,
txHash, txHash,
timestamp: expect.any(Number), timestamp: expect.any(Number),
executionResult: false, executionResult: false
blockNumber: expect.any(Number)
}) })
expect(getFailedExecution).toBeCalledTimes(1) expect(getFailedExecution).toBeCalledTimes(1)

View File

@ -22,16 +22,6 @@ export const getRequiredBlockConfirmations = async (
web3: Web3 | null = null, web3: Web3 | null = null,
api: string = '' api: string = ''
) => { ) => {
let blockConfirmations
try {
blockConfirmations = await contract.methods.requiredBlockConfirmations().call()
} catch {}
if (blockConfirmations) {
return parseInt(blockConfirmations)
}
const eventsFromSnapshot = snapshotProvider.requiredBlockConfirmationEvents(blockNumber) const eventsFromSnapshot = snapshotProvider.requiredBlockConfirmationEvents(blockNumber)
const snapshotBlockNumber = snapshotProvider.snapshotBlockNumber() const snapshotBlockNumber = snapshotProvider.snapshotBlockNumber()
@ -45,10 +35,16 @@ export const getRequiredBlockConfirmations = async (
const events = [...eventsFromSnapshot, ...contractEvents] const events = [...eventsFromSnapshot, ...contractEvents]
let blockConfirmations
if (events.length > 0) {
// Use the value from last event before the transaction // Use the value from last event before the transaction
const event = events[events.length - 1] const event = events[events.length - 1]
blockConfirmations = event.returnValues.requiredBlockConfirmations blockConfirmations = event.returnValues.requiredBlockConfirmations
} else {
// This is a special case where RequiredBlockConfirmationChanged was not emitted during initialization in early versions of AMB
// of Sokol - Kovan. In this case the current value is used.
blockConfirmations = await contract.methods.requiredBlockConfirmations().call()
}
return parseInt(blockConfirmations) return parseInt(blockConfirmations)
} }
@ -56,25 +52,11 @@ export const getValidatorAddress = (contract: Contract) => contract.methods.vali
export const getRequiredSignatures = async ( export const getRequiredSignatures = async (
contract: Contract, contract: Contract,
blockNumber: number | 'latest', blockNumber: number,
snapshotProvider: SnapshotProvider, snapshotProvider: SnapshotProvider,
web3: Web3 | null = null, web3: Web3 | null = null,
api: string = '' api: string = ''
) => { ) => {
let requiredSignatures
try {
requiredSignatures = await contract.methods.requiredSignatures().call()
} catch {}
if (requiredSignatures) {
return parseInt(requiredSignatures)
}
if (blockNumber === 'latest') {
return contract.methods.requiredSignatures().call()
}
const eventsFromSnapshot = snapshotProvider.requiredSignaturesEvents(blockNumber) const eventsFromSnapshot = snapshotProvider.requiredSignaturesEvents(blockNumber)
const snapshotBlockNumber = snapshotProvider.snapshotBlockNumber() const snapshotBlockNumber = snapshotProvider.snapshotBlockNumber()
@ -90,25 +72,17 @@ export const getRequiredSignatures = async (
// Use the value form last event before the transaction // Use the value form last event before the transaction
const event = events[events.length - 1] const event = events[events.length - 1]
;({ requiredSignatures } = event.returnValues) const { requiredSignatures } = event.returnValues
return parseInt(requiredSignatures) return parseInt(requiredSignatures)
} }
export const getValidatorList = async ( export const getValidatorList = async (
contract: Contract, contract: Contract,
blockNumber: number | 'latest', blockNumber: number,
snapshotProvider: SnapshotProvider, snapshotProvider: SnapshotProvider,
web3: Web3 | null = null, web3: Web3 | null = null,
api: string = '' api: string = ''
) => { ) => {
try {
const currentList = await contract.methods.validatorList().call()
if (currentList) {
return currentList
}
} catch {}
const addedEventsFromSnapshot = snapshotProvider.validatorAddedEvents(blockNumber) const addedEventsFromSnapshot = snapshotProvider.validatorAddedEvents(blockNumber)
const removedEventsFromSnapshot = snapshotProvider.validatorRemovedEvents(blockNumber) const removedEventsFromSnapshot = snapshotProvider.validatorRemovedEvents(blockNumber)
const snapshotBlockNumber = snapshotProvider.snapshotBlockNumber() const snapshotBlockNumber = snapshotProvider.snapshotBlockNumber()

View File

@ -12,7 +12,6 @@ import Web3 from 'web3'
import { Contract } from 'web3-eth-contract' import { Contract } from 'web3-eth-contract'
export interface APITransaction { export interface APITransaction {
from: string
timeStamp: string timeStamp: string
isError: string isError: string
input: string input: string
@ -55,7 +54,7 @@ export const fetchAccountTransactions = async ({ account, startBlock, endBlock,
url.searchParams.append('module', 'account') url.searchParams.append('module', 'account')
url.searchParams.append('action', 'txlist') url.searchParams.append('action', 'txlist')
url.searchParams.append('address', account) url.searchParams.append('address', account)
url.searchParams.append('filterby', 'to') url.searchParams.append('filterby', 'from')
url.searchParams.append('startblock', startBlock.toString()) url.searchParams.append('startblock', startBlock.toString())
url.searchParams.append('endblock', endBlock.toString()) url.searchParams.append('endblock', endBlock.toString())
@ -65,7 +64,7 @@ export const fetchAccountTransactions = async ({ account, startBlock, endBlock,
return [] return []
} }
return result.result || [] return result.result
} }
export const fetchPendingTransactions = async ({ export const fetchPendingTransactions = async ({
@ -181,12 +180,10 @@ export const getLogs = async (
if (topics[i] !== null) { if (topics[i] !== null) {
url.searchParams.append(`topic${i}`, topics[i] as string) url.searchParams.append(`topic${i}`, topics[i] as string)
for (let j = 0; j < i; j++) { for (let j = 0; j < i; j++) {
if (topics[j] !== null) {
url.searchParams.append(`topic${j}_${i}_opr`, 'and') url.searchParams.append(`topic${j}_${i}_opr`, 'and')
} }
} }
} }
}
const logs = await fetch(url.toString()).then(res => res.json()) const logs = await fetch(url.toString()).then(res => res.json())
@ -197,7 +194,7 @@ export const getLogs = async (
})) }))
} }
const filterSender = (from: string) => (tx: APITransaction) => tx.from.toLowerCase() === from.toLowerCase() const filterReceiver = (to: string) => (tx: APITransaction) => tx.to.toLowerCase() === to.toLowerCase()
export const getFailedTransactions = async ( export const getFailedTransactions = async (
account: string, account: string,
@ -207,9 +204,9 @@ export const getFailedTransactions = async (
api: string, api: string,
getAccountTransactionsMethod = getAccountTransactions getAccountTransactionsMethod = getAccountTransactions
): Promise<APITransaction[]> => { ): Promise<APITransaction[]> => {
const transactions = await getAccountTransactionsMethod({ account: to, startBlock, endBlock, api }) const transactions = await getAccountTransactionsMethod({ account, startBlock, endBlock, api })
return transactions.filter(t => t.isError !== '0').filter(filterSender(account)) return transactions.filter(t => t.isError !== '0').filter(filterReceiver(to))
} }
export const getSuccessTransactions = async ( export const getSuccessTransactions = async (
@ -220,9 +217,9 @@ export const getSuccessTransactions = async (
api: string, api: string,
getAccountTransactionsMethod = getAccountTransactions getAccountTransactionsMethod = getAccountTransactions
): Promise<APITransaction[]> => { ): Promise<APITransaction[]> => {
const transactions = await getAccountTransactionsMethod({ account: to, startBlock, endBlock, api }) const transactions = await getAccountTransactionsMethod({ account, startBlock, endBlock, api })
return transactions.filter(t => t.isError === '0').filter(filterSender(account)) return transactions.filter(t => t.isError === '0').filter(filterReceiver(to))
} }
export const filterValidatorSignatureTransaction = ( export const filterValidatorSignatureTransaction = (

View File

@ -2,37 +2,26 @@ import Web3 from 'web3'
import { Contract } from 'web3-eth-contract' import { Contract } from 'web3-eth-contract'
import { HOME_RPC_POLLING_INTERVAL, VALIDATOR_CONFIRMATION_STATUS } from '../config/constants' import { HOME_RPC_POLLING_INTERVAL, VALIDATOR_CONFIRMATION_STATUS } from '../config/constants'
import { GetTransactionParams, APITransaction, APIPendingTransaction, GetPendingTransactionParams } from './explorer' import { GetTransactionParams, APITransaction, APIPendingTransaction, GetPendingTransactionParams } from './explorer'
import { getAffirmationsSigned, getMessagesSigned } from './contract'
import { import {
getValidatorConfirmation, getValidatorConfirmation,
getValidatorFailedTransaction, getValidatorFailedTransaction,
getValidatorPendingTransaction, getValidatorPendingTransaction,
getSuccessExecutionTransaction getSuccessExecutionTransaction
} from './validatorConfirmationHelpers' } from './validatorConfirmationHelpers'
import { ConfirmationParam } from '../hooks/useMessageConfirmations' import { BasicConfirmationParam, ConfirmationParam } from '../hooks/useMessageConfirmations'
import { signatureToVRS } from './signatures'
const mergeConfirmations = (oldConfirmations: ConfirmationParam[], newConfirmations: ConfirmationParam[]) => { const mergeConfirmations = (oldConfirmations: BasicConfirmationParam[], newConfirmations: BasicConfirmationParam[]) => {
const confirmations = [...oldConfirmations] const confirmations = [...oldConfirmations]
newConfirmations.forEach(validatorData => { newConfirmations.forEach(validatorData => {
const index = confirmations.findIndex(e => e.validator === validatorData.validator) const index = confirmations.findIndex(e => e.validator === validatorData.validator)
if (index === -1) {
confirmations.push(validatorData)
return
}
const currentStatus = confirmations[index].status const currentStatus = confirmations[index].status
const newStatus = validatorData.status const newStatus = validatorData.status
if ( if (
validatorData.txHash || (validatorData as ConfirmationParam).txHash ||
!!validatorData.signature ||
(newStatus !== currentStatus && newStatus !== VALIDATOR_CONFIRMATION_STATUS.UNDEFINED) (newStatus !== currentStatus && newStatus !== VALIDATOR_CONFIRMATION_STATUS.UNDEFINED)
) { ) {
confirmations[index] = { confirmations[index] = validatorData
status: validatorData.status,
validator: validatorData.validator,
timestamp: confirmations[index].timestamp || validatorData.timestamp,
txHash: confirmations[index].txHash || validatorData.txHash,
signature: confirmations[index].signature || validatorData.signature
}
} }
}) })
return confirmations return confirmations
@ -56,17 +45,19 @@ export const getConfirmationsForTx = async (
setPendingConfirmations: Function, setPendingConfirmations: Function,
getSuccessTransactions: (args: GetTransactionParams) => Promise<APITransaction[]> getSuccessTransactions: (args: GetTransactionParams) => Promise<APITransaction[]>
) => { ) => {
const confirmationContractMethod = fromHome ? getMessagesSigned : getAffirmationsSigned
const hashMsg = web3.utils.soliditySha3Raw(messageData) const hashMsg = web3.utils.soliditySha3Raw(messageData)
let validatorConfirmations = await Promise.all( let validatorConfirmations = await Promise.all(
validatorList.map(getValidatorConfirmation(web3, hashMsg, bridgeContract, fromHome)) validatorList.map(getValidatorConfirmation(web3, hashMsg, bridgeContract, confirmationContractMethod))
) )
const updateConfirmations = (confirmations: ConfirmationParam[]) => { const updateConfirmations = (confirmations: BasicConfirmationParam[]) => {
if (confirmations.length === 0) { if (confirmations.length === 0) {
return return
} }
validatorConfirmations = mergeConfirmations(validatorConfirmations, confirmations) validatorConfirmations = mergeConfirmations(validatorConfirmations, confirmations)
setResult((currentConfirmations: ConfirmationParam[]) => { setResult((currentConfirmations: BasicConfirmationParam[]) => {
if (currentConfirmations && currentConfirmations.length) { if (currentConfirmations && currentConfirmations.length) {
return mergeConfirmations(currentConfirmations, confirmations) return mergeConfirmations(currentConfirmations, confirmations)
} }
@ -76,37 +67,11 @@ export const getConfirmationsForTx = async (
const successConfirmations = validatorConfirmations.filter(c => c.status === VALIDATOR_CONFIRMATION_STATUS.SUCCESS) const successConfirmations = validatorConfirmations.filter(c => c.status === VALIDATOR_CONFIRMATION_STATUS.SUCCESS)
const notSuccessConfirmations = validatorConfirmations.filter(c => c.status !== VALIDATOR_CONFIRMATION_STATUS.SUCCESS) const notSuccessConfirmations = validatorConfirmations.filter(c => c.status !== VALIDATOR_CONFIRMATION_STATUS.SUCCESS)
const hasEnoughSignatures = successConfirmations.length >= requiredSignatures const hasEnoughSignatures = successConfirmations.length === requiredSignatures
updateConfirmations(validatorConfirmations) updateConfirmations(validatorConfirmations)
setSignatureCollected(hasEnoughSignatures) setSignatureCollected(hasEnoughSignatures)
if (hasEnoughSignatures) {
setPendingConfirmations(false)
if (fromHome) {
// fetch collected signatures for possible manual processing
const signatures = await Promise.all(
Array.from(Array(requiredSignatures).keys()).map(i => bridgeContract.methods.signature(hashMsg, i).call())
)
const confirmations = signatures.flatMap(sig => {
const { v, r, s } = signatureToVRS(sig)
const address = web3.eth.accounts.recover(messageData, `0x${v}`, `0x${r}`, `0x${s}`)
return successConfirmations.filter(c => c.validator === address).map(c => ({ ...c, signature: sig }))
})
updateConfirmations(confirmations)
}
}
// get transactions from success signatures
const successConfirmationWithData = await Promise.all(
successConfirmations.map(
getSuccessExecutionTransaction(web3, bridgeContract, fromHome, messageData, startBlock, getSuccessTransactions)
)
)
const successConfirmationWithTxFound = successConfirmationWithData.filter(v => v.txHash !== '')
updateConfirmations(successConfirmationWithTxFound)
// If signatures not collected, look for pending transactions // If signatures not collected, look for pending transactions
if (!hasEnoughSignatures) { if (!hasEnoughSignatures) {
// Check if confirmation is pending // Check if confirmation is pending
@ -119,6 +84,8 @@ export const getConfirmationsForTx = async (
) )
updateConfirmations(validatorPendingConfirmations) updateConfirmations(validatorPendingConfirmations)
setPendingConfirmations(validatorPendingConfirmations.length > 0) setPendingConfirmations(validatorPendingConfirmations.length > 0)
} else {
setPendingConfirmations(false)
} }
const undefinedConfirmations = validatorConfirmations.filter( const undefinedConfirmations = validatorConfirmations.filter(
@ -128,27 +95,13 @@ export const getConfirmationsForTx = async (
// Check if confirmation failed // Check if confirmation failed
const validatorFailedConfirmationsChecks = await Promise.all( const validatorFailedConfirmationsChecks = await Promise.all(
undefinedConfirmations.map( undefinedConfirmations.map(
getValidatorFailedTransaction(web3, bridgeContract, messageData, startBlock, getFailedTransactions) getValidatorFailedTransaction(bridgeContract, messageData, startBlock, getFailedTransactions)
) )
) )
let validatorFailedConfirmations = validatorFailedConfirmationsChecks.filter( const validatorFailedConfirmations = validatorFailedConfirmationsChecks.filter(
c => c.status === VALIDATOR_CONFIRMATION_STATUS.FAILED || c.status === VALIDATOR_CONFIRMATION_STATUS.FAILED_VALID c => c.status === VALIDATOR_CONFIRMATION_STATUS.FAILED
)
if (hasEnoughSignatures && !fromHome) {
const lastTS = Math.max(...successConfirmationWithTxFound.map(c => c.timestamp || 0))
validatorFailedConfirmations = validatorFailedConfirmations.map(
c =>
c.timestamp < lastTS
? c
: {
...c,
status: VALIDATOR_CONFIRMATION_STATUS.FAILED_VALID
}
)
}
setFailedConfirmations(
!hasEnoughSignatures && validatorFailedConfirmations.some(c => c.status === VALIDATOR_CONFIRMATION_STATUS.FAILED)
) )
setFailedConfirmations(validatorFailedConfirmations.length > validatorList.length - requiredSignatures)
updateConfirmations(validatorFailedConfirmations) updateConfirmations(validatorFailedConfirmations)
const missingConfirmations = validatorConfirmations.filter( const missingConfirmations = validatorConfirmations.filter(
@ -159,12 +112,29 @@ export const getConfirmationsForTx = async (
// If signatures collected, it should set other signatures not found as not required // If signatures collected, it should set other signatures not found as not required
const notRequiredConfirmations = missingConfirmations.map(c => ({ const notRequiredConfirmations = missingConfirmations.map(c => ({
validator: c.validator, validator: c.validator,
status: VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED, status: VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED
timestamp: 0,
txHash: ''
})) }))
updateConfirmations(notRequiredConfirmations) updateConfirmations(notRequiredConfirmations)
if (fromHome) {
// fetch collected signatures for possible manual processing
setSignatureCollected(
await Promise.all(
Array.from(Array(requiredSignatures).keys()).map(i => bridgeContract.methods.signature(hashMsg, i).call())
)
)
} }
}
// get transactions from success signatures
const successConfirmationWithData = await Promise.all(
successConfirmations.map(
getSuccessExecutionTransaction(web3, bridgeContract, fromHome, messageData, startBlock, getSuccessTransactions)
)
)
const successConfirmationWithTxFound = successConfirmationWithData.filter(v => v.txHash !== '')
updateConfirmations(successConfirmationWithTxFound)
// retry if not all signatures are collected and some confirmations are still missing // retry if not all signatures are collected and some confirmations are still missing
// or some success transactions were not fetched successfully // or some success transactions were not fetched successfully

View File

@ -59,12 +59,11 @@ export const getSuccessExecutionData = async (
const validatorAddress = web3.utils.toChecksumAddress(txReceipt.from) const validatorAddress = web3.utils.toChecksumAddress(txReceipt.from)
return { return {
status: VALIDATOR_CONFIRMATION_STATUS.EXECUTION_SUCCESS, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
validator: validatorAddress, validator: validatorAddress,
txHash: event.transactionHash, txHash: event.transactionHash,
timestamp: blockTimestamp, timestamp: blockTimestamp,
executionResult: event.returnValues.status, executionResult: event.returnValues.status
blockNumber: event.blockNumber
} }
} }
return null return null
@ -116,8 +115,7 @@ export const getFinalizationEvent = async (
validator: validator, validator: validator,
txHash: pendingTx.hash, txHash: pendingTx.hash,
timestamp: nowTimestamp, timestamp: nowTimestamp,
executionResult: false, executionResult: false
blockNumber: 0
}) })
setPendingExecution(true) setPendingExecution(true)
} else { } else {
@ -146,8 +144,7 @@ export const getFinalizationEvent = async (
validator: validator, validator: validator,
txHash: failedTx.hash, txHash: failedTx.hash,
timestamp, timestamp,
executionResult: false, executionResult: false
blockNumber: parseInt(failedTx.blockNumber)
}) })
setFailedExecution(true) setFailedExecution(true)
} }

View File

@ -1,45 +1,38 @@
import Web3 from 'web3' import Web3 from 'web3'
import { Contract } from 'web3-eth-contract' import { Contract } from 'web3-eth-contract'
import { ConfirmationParam } from '../hooks/useMessageConfirmations' import { BasicConfirmationParam, ConfirmationParam } from '../hooks/useMessageConfirmations'
import validatorsCache from '../services/ValidatorsCache' import validatorsCache from '../services/ValidatorsCache'
import { CACHE_KEY_FAILED, CACHE_KEY_SUCCESS, VALIDATOR_CONFIRMATION_STATUS } from '../config/constants' import { CACHE_KEY_FAILED, CACHE_KEY_SUCCESS, VALIDATOR_CONFIRMATION_STATUS } from '../config/constants'
import { APIPendingTransaction, APITransaction, GetTransactionParams, GetPendingTransactionParams } from './explorer' import { APIPendingTransaction, APITransaction, GetTransactionParams, GetPendingTransactionParams } from './explorer'
import { homeBlockNumberProvider } from '../services/BlockNumberProvider' import { homeBlockNumberProvider } from '../services/BlockNumberProvider'
import { getAffirmationsSigned, getMessagesSigned } from './contract'
export const getValidatorConfirmation = ( export const getValidatorConfirmation = (
web3: Web3, web3: Web3,
hashMsg: string, hashMsg: string,
bridgeContract: Contract, bridgeContract: Contract,
fromHome: boolean confirmationContractMethod: Function
) => async (validator: string): Promise<ConfirmationParam> => { ) => async (validator: string): Promise<BasicConfirmationParam> => {
const hashSenderMsg = web3.utils.soliditySha3Raw(validator, hashMsg) const hashSenderMsg = web3.utils.soliditySha3Raw(validator, hashMsg)
const fromCache = validatorsCache.getData(hashSenderMsg) const signatureFromCache = validatorsCache.get(hashSenderMsg)
if (fromCache) { if (signatureFromCache) {
return fromCache return {
validator,
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS
}
} }
const confirmationContractMethod = fromHome ? getMessagesSigned : getAffirmationsSigned
const confirmed = await confirmationContractMethod(bridgeContract, hashSenderMsg) const confirmed = await confirmationContractMethod(bridgeContract, hashSenderMsg)
const status = confirmed ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
// If validator confirmed signature, we cache the result to avoid doing future requests for a result that won't change // If validator confirmed signature, we cache the result to avoid doing future requests for a result that won't change
if (confirmed) { if (confirmed) {
const confirmation: ConfirmationParam = { validatorsCache.set(hashSenderMsg, confirmed)
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
validator,
timestamp: 0,
txHash: ''
}
validatorsCache.setData(hashSenderMsg, confirmation)
return confirmation
} }
return { return {
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
validator, validator,
timestamp: 0, status
txHash: ''
} }
} }
@ -50,7 +43,7 @@ export const getSuccessExecutionTransaction = (
messageData: string, messageData: string,
startBlock: number, startBlock: number,
getSuccessTransactions: (args: GetTransactionParams) => Promise<APITransaction[]> getSuccessTransactions: (args: GetTransactionParams) => Promise<APITransaction[]>
) => async (validatorData: ConfirmationParam): Promise<ConfirmationParam> => { ) => async (validatorData: BasicConfirmationParam): Promise<ConfirmationParam> => {
const { validator } = validatorData const { validator } = validatorData
const validatorCacheKey = `${CACHE_KEY_SUCCESS}${validatorData.validator}-${messageData}` const validatorCacheKey = `${CACHE_KEY_SUCCESS}${validatorData.validator}-${messageData}`
const fromCache = validatorsCache.getData(validatorCacheKey) const fromCache = validatorsCache.getData(validatorCacheKey)
@ -94,12 +87,11 @@ export const getSuccessExecutionTransaction = (
} }
export const getValidatorFailedTransaction = ( export const getValidatorFailedTransaction = (
web3: Web3,
bridgeContract: Contract, bridgeContract: Contract,
messageData: string, messageData: string,
startBlock: number, startBlock: number,
getFailedTransactions: (args: GetTransactionParams) => Promise<APITransaction[]> getFailedTransactions: (args: GetTransactionParams) => Promise<APITransaction[]>
) => async (validatorData: ConfirmationParam): Promise<ConfirmationParam> => { ) => async (validatorData: BasicConfirmationParam): Promise<ConfirmationParam> => {
const validatorCacheKey = `${CACHE_KEY_FAILED}${validatorData.validator}-${messageData}` const validatorCacheKey = `${CACHE_KEY_FAILED}${validatorData.validator}-${messageData}`
const failedFromCache = validatorsCache.getData(validatorCacheKey) const failedFromCache = validatorsCache.getData(validatorCacheKey)
@ -114,33 +106,30 @@ export const getValidatorFailedTransaction = (
startBlock, startBlock,
endBlock: homeBlockNumberProvider.get() || 0 endBlock: homeBlockNumberProvider.get() || 0
}) })
const newStatus =
failedTransactions.length > 0 ? VALIDATOR_CONFIRMATION_STATUS.FAILED : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
let txHashTimestamp = 0
let txHash = ''
// If validator signature failed, we cache the result to avoid doing future requests for a result that won't change // If validator signature failed, we cache the result to avoid doing future requests for a result that won't change
if (failedTransactions.length > 0) { if (failedTransactions.length > 0) {
const failedTx = failedTransactions[0] const failedTx = failedTransactions[0]
const confirmation: ConfirmationParam = { txHashTimestamp = parseInt(failedTx.timeStamp)
status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash = failedTx.hash
validator: validatorData.validator,
txHash: failedTx.hash,
timestamp: parseInt(failedTx.timeStamp)
}
if (failedTx.input && failedTx.input.length > 10) { validatorsCache.setData(validatorCacheKey, {
try { validator: validatorData.validator,
const res = web3.eth.abi.decodeParameters(['bytes', 'bytes'], `0x${failedTx.input.slice(10)}`) status: newStatus,
confirmation.signature = res[0] txHash,
confirmation.status = VALIDATOR_CONFIRMATION_STATUS.FAILED_VALID timestamp: txHashTimestamp
console.log(`Adding manual signature from failed message from ${validatorData.validator}`) })
} catch {}
}
validatorsCache.setData(validatorCacheKey, confirmation)
return confirmation
} }
return { return {
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
validator: validatorData.validator, validator: validatorData.validator,
txHash: '', status: newStatus,
timestamp: 0 txHash,
timestamp: txHashTimestamp
} }
} }
@ -148,7 +137,7 @@ export const getValidatorPendingTransaction = (
bridgeContract: Contract, bridgeContract: Contract,
messageData: string, messageData: string,
getPendingTransactions: (args: GetPendingTransactionParams) => Promise<APIPendingTransaction[]> getPendingTransactions: (args: GetPendingTransactionParams) => Promise<APIPendingTransaction[]>
) => async (validatorData: ConfirmationParam): Promise<ConfirmationParam> => { ) => async (validatorData: BasicConfirmationParam): Promise<ConfirmationParam> => {
const failedTransactions = await getPendingTransactions({ const failedTransactions = await getPendingTransactions({
account: validatorData.validator, account: validatorData.validator,
to: bridgeContract.options.address, to: bridgeContract.options.address,

View File

@ -10,37 +10,6 @@ import { SnapshotProvider } from '../services/SnapshotProvider'
export interface MessageObject { export interface MessageObject {
id: string id: string
data: string data: string
sender?: string
executor?: string
obToken?: string
obReceiver?: string
}
export interface WarnRule {
message: string
sender?: string
executor?: string
obToken?: string
obReceiver?: string
}
export const matchesRule = (rule: WarnRule, msg: MessageObject) => {
if (!msg.executor || !msg.sender) {
return false
}
if (!!rule.executor && rule.executor.toLowerCase() !== msg.executor.toLowerCase()) {
return false
}
if (!!rule.sender && rule.sender.toLowerCase() !== msg.sender.toLowerCase()) {
return false
}
if (!!rule.obToken && (!msg.obToken || rule.obToken.toLowerCase() !== msg.obToken.toLowerCase())) {
return false
}
if (!!rule.obReceiver && (!msg.obReceiver || rule.obReceiver.toLowerCase() !== msg.obReceiver.toLowerCase())) {
return false
}
return true
} }
const rawGetWeb3 = (url: string) => new Web3(new Web3.providers.HttpProvider(url)) const rawGetWeb3 = (url: string) => new Web3(new Web3.providers.HttpProvider(url))
@ -57,33 +26,15 @@ export const filterEventsByAbi = (
const eventHash = web3.eth.abi.encodeEventSignature(eventAbi) const eventHash = web3.eth.abi.encodeEventSignature(eventAbi)
const events = txReceipt.logs.filter(e => e.address === bridgeAddress && e.topics[0] === eventHash) const events = txReceipt.logs.filter(e => e.address === bridgeAddress && e.topics[0] === eventHash)
if (!eventAbi || !eventAbi.inputs || !eventAbi.inputs.length) {
return []
}
const inputs = eventAbi.inputs
return events.map(e => { return events.map(e => {
const { messageId, encodedData } = web3.eth.abi.decodeLog(inputs, e.data, [e.topics[1]]) let decodedLogs: { [p: string]: string } = {
let sender, executor, obToken, obReceiver messageId: '',
if (encodedData.length >= 160) { encodedData: ''
sender = `0x${encodedData.slice(66, 106)}`
executor = `0x${encodedData.slice(106, 146)}`
const dataOffset =
160 + (parseInt(encodedData.slice(154, 156), 16) + parseInt(encodedData.slice(156, 158), 16)) * 2 + 8
if (encodedData.length >= dataOffset + 64) {
obToken = `0x${encodedData.slice(dataOffset + 24, dataOffset + 64)}`
} }
if (encodedData.length >= dataOffset + 128) { if (eventAbi && eventAbi.inputs && eventAbi.inputs.length) {
obReceiver = `0x${encodedData.slice(dataOffset + 88, dataOffset + 128)}` decodedLogs = web3.eth.abi.decodeLog(eventAbi.inputs, e.data, [e.topics[1]])
}
}
return {
id: messageId || '',
data: encodedData || '',
sender,
executor,
obToken,
obReceiver
} }
return { id: decodedLogs.messageId, data: decodedLogs.encodedData }
}) })
} }

View File

@ -1,7 +1,13 @@
const HOME_NATIVE_TO_ERC_ABI = require('../contracts/build/contracts/HomeBridgeNativeToErc').abi
const FOREIGN_NATIVE_TO_ERC_ABI = require('../contracts/build/contracts/ForeignBridgeNativeToErc').abi
const HOME_ERC_TO_ERC_ABI = require('../contracts/build/contracts/HomeBridgeErcToErc').abi
const FOREIGN_ERC_TO_ERC_ABI = require('../contracts/build/contracts/ForeignBridgeErc677ToErc677').abi
const HOME_ERC_TO_NATIVE_ABI = require('../contracts/build/contracts/HomeBridgeErcToNative').abi const HOME_ERC_TO_NATIVE_ABI = require('../contracts/build/contracts/HomeBridgeErcToNative').abi
const FOREIGN_ERC_TO_NATIVE_ABI = require('../contracts/build/contracts/XDaiForeignBridge.json').abi const FOREIGN_ERC_TO_NATIVE_ABI = require('../contracts/build/contracts/ForeignBridgeErcToNative').abi
const ERC20_ABI = require('../contracts/build/contracts/ERC20').abi const ERC20_ABI = require('../contracts/build/contracts/ERC20').abi
const BLOCK_REWARD_ABI = require('../contracts/build/contracts/BlockRewardMock').abi const ERC677_ABI = require('../contracts/build/contracts/ERC677').abi
const ERC677_BRIDGE_TOKEN_ABI = require('../contracts/build/contracts/ERC677BridgeToken').abi
const BLOCK_REWARD_ABI = require('../contracts/build/contracts/BlockReward').abi
const BRIDGE_VALIDATORS_ABI = require('../contracts/build/contracts/BridgeValidators').abi const BRIDGE_VALIDATORS_ABI = require('../contracts/build/contracts/BridgeValidators').abi
const REWARDABLE_VALIDATORS_ABI = require('../contracts/build/contracts/RewardableValidators').abi const REWARDABLE_VALIDATORS_ABI = require('../contracts/build/contracts/RewardableValidators').abi
const HOME_AMB_ABI = require('../contracts/build/contracts/HomeAMB').abi const HOME_AMB_ABI = require('../contracts/build/contracts/HomeAMB').abi
@ -9,9 +15,43 @@ 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 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 FOREIGN_STAKE_ERC_TO_ERC_ABI = require('../contracts/build/contracts/ForeignStakeTokenMediator').abi
const { HOME_V1_ABI, FOREIGN_V1_ABI } = require('./v1Abis')
const { BRIDGE_MODES } = require('./constants') const { BRIDGE_MODES } = require('./constants')
const ERC20_BYTES32_ABI = [
{
constant: true,
inputs: [],
name: 'name',
outputs: [
{
name: '',
type: 'bytes32'
}
],
payable: false,
stateMutability: 'view',
type: 'function'
},
{
constant: true,
inputs: [],
name: 'symbol',
outputs: [
{
name: '',
type: 'bytes32'
}
],
payable: false,
stateMutability: 'view',
type: 'function'
}
]
const OLD_AMB_USER_REQUEST_FOR_SIGNATURE_ABI = [ const OLD_AMB_USER_REQUEST_FOR_SIGNATURE_ABI = [
{ {
anonymous: false, anonymous: false,
@ -45,15 +85,27 @@ const OLD_AMB_USER_REQUEST_FOR_AFFIRMATION_ABI = [
function getBridgeABIs(bridgeMode) { function getBridgeABIs(bridgeMode) {
let HOME_ABI = null let HOME_ABI = null
let FOREIGN_ABI = null let FOREIGN_ABI = null
if (bridgeMode === BRIDGE_MODES.ERC_TO_NATIVE) { if (bridgeMode === BRIDGE_MODES.NATIVE_TO_ERC) {
HOME_ABI = HOME_NATIVE_TO_ERC_ABI
FOREIGN_ABI = FOREIGN_NATIVE_TO_ERC_ABI
} else if (bridgeMode === BRIDGE_MODES.ERC_TO_ERC) {
HOME_ABI = HOME_ERC_TO_ERC_ABI
FOREIGN_ABI = FOREIGN_ERC_TO_ERC_ABI
} else if (bridgeMode === BRIDGE_MODES.ERC_TO_NATIVE) {
HOME_ABI = HOME_ERC_TO_NATIVE_ABI HOME_ABI = HOME_ERC_TO_NATIVE_ABI
FOREIGN_ABI = FOREIGN_ERC_TO_NATIVE_ABI FOREIGN_ABI = FOREIGN_ERC_TO_NATIVE_ABI
} else if (bridgeMode === BRIDGE_MODES.NATIVE_TO_ERC_V1) {
HOME_ABI = HOME_V1_ABI
FOREIGN_ABI = FOREIGN_V1_ABI
} else if (bridgeMode === BRIDGE_MODES.ARBITRARY_MESSAGE) { } else if (bridgeMode === BRIDGE_MODES.ARBITRARY_MESSAGE) {
HOME_ABI = HOME_AMB_ABI HOME_ABI = HOME_AMB_ABI
FOREIGN_ABI = FOREIGN_AMB_ABI FOREIGN_ABI = FOREIGN_AMB_ABI
} else if (bridgeMode === BRIDGE_MODES.AMB_ERC_TO_ERC) { } else if (bridgeMode === BRIDGE_MODES.AMB_ERC_TO_ERC) {
HOME_ABI = HOME_AMB_ERC_TO_ERC_ABI HOME_ABI = HOME_AMB_ERC_TO_ERC_ABI
FOREIGN_ABI = FOREIGN_AMB_ERC_TO_ERC_ABI FOREIGN_ABI = FOREIGN_AMB_ERC_TO_ERC_ABI
} else if (bridgeMode === BRIDGE_MODES.STAKE_AMB_ERC_TO_ERC) {
HOME_ABI = HOME_STAKE_ERC_TO_ERC_ABI
FOREIGN_ABI = FOREIGN_STAKE_ERC_TO_ERC_ABI
} else { } else {
throw new Error(`Unrecognized bridge mode: ${bridgeMode}`) throw new Error(`Unrecognized bridge mode: ${bridgeMode}`)
} }
@ -63,15 +115,26 @@ function getBridgeABIs(bridgeMode) {
module.exports = { module.exports = {
getBridgeABIs, getBridgeABIs,
HOME_NATIVE_TO_ERC_ABI,
FOREIGN_NATIVE_TO_ERC_ABI,
HOME_ERC_TO_ERC_ABI,
FOREIGN_ERC_TO_ERC_ABI,
HOME_ERC_TO_NATIVE_ABI, HOME_ERC_TO_NATIVE_ABI,
FOREIGN_ERC_TO_NATIVE_ABI, FOREIGN_ERC_TO_NATIVE_ABI,
ERC20_ABI, ERC20_ABI,
ERC677_ABI,
ERC677_BRIDGE_TOKEN_ABI,
BLOCK_REWARD_ABI, BLOCK_REWARD_ABI,
BRIDGE_VALIDATORS_ABI, BRIDGE_VALIDATORS_ABI,
REWARDABLE_VALIDATORS_ABI, REWARDABLE_VALIDATORS_ABI,
HOME_V1_ABI,
FOREIGN_V1_ABI,
ERC20_BYTES32_ABI,
HOME_AMB_ABI, HOME_AMB_ABI,
FOREIGN_AMB_ABI, FOREIGN_AMB_ABI,
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,
HOME_STAKE_ERC_TO_ERC_ABI,
FOREIGN_STAKE_ERC_TO_ERC_ABI
} }

View File

@ -1,12 +1,30 @@
const BRIDGE_MODES = { const BRIDGE_MODES = {
NATIVE_TO_ERC: 'NATIVE_TO_ERC',
ERC_TO_ERC: 'ERC_TO_ERC',
ERC_TO_NATIVE: 'ERC_TO_NATIVE', ERC_TO_NATIVE: 'ERC_TO_NATIVE',
NATIVE_TO_ERC_V1: 'NATIVE_TO_ERC_V1',
ARBITRARY_MESSAGE: 'ARBITRARY_MESSAGE', ARBITRARY_MESSAGE: 'ARBITRARY_MESSAGE',
AMB_ERC_TO_ERC: 'AMB_ERC_TO_ERC' AMB_ERC_TO_ERC: 'AMB_ERC_TO_ERC',
STAKE_AMB_ERC_TO_ERC: 'STAKE_AMB_ERC_TO_ERC'
}
const ERC_TYPES = {
ERC20: 'ERC20',
ERC677: 'ERC677'
}
const FEE_MANAGER_MODE = {
ONE_DIRECTION: 'ONE_DIRECTION',
BOTH_DIRECTIONS: 'BOTH_DIRECTIONS',
ONE_DIRECTION_STAKE: 'ONE_DIRECTION_STAKE',
UNDEFINED: 'UNDEFINED'
} }
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000' const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
module.exports = { module.exports = {
BRIDGE_MODES, BRIDGE_MODES,
ERC_TYPES,
FEE_MANAGER_MODE,
ZERO_ADDRESS ZERO_ADDRESS
} }

View File

@ -1,5 +1,3 @@
const { soliditySha3 } = require('web3-utils')
function strip0x(input) { function strip0x(input) {
return input.replace(/^0x/, '') return input.replace(/^0x/, '')
} }
@ -41,35 +39,8 @@ const normalizeAMBMessageEvent = e => {
return parseAMBMessage(msgData) return parseAMBMessage(msgData)
} }
const ambInformationSignatures = [
'eth_call(address,bytes)',
'eth_call(address,bytes,uint256)',
'eth_call(address,address,uint256,bytes)',
'eth_blockNumber()',
'eth_getBlockByNumber()',
'eth_getBlockByNumber(uint256)',
'eth_getBlockByHash(bytes32)',
'eth_getBalance(address)',
'eth_getBalance(address,uint256)',
'eth_getTransactionCount(address)',
'eth_getTransactionCount(address,uint256)',
'eth_getTransactionByHash(bytes32)',
'eth_getTransactionReceipt(bytes32)',
'eth_getStorageAt(address,bytes32)',
'eth_getStorageAt(address,bytes32,uint256)'
]
const ambInformationSelectors = Object.fromEntries(ambInformationSignatures.map(sig => [soliditySha3(sig), sig]))
const normalizeAMBInfoRequest = e => ({
messageId: e.returnValues.messageId,
sender: e.returnValues.sender,
requestSelector: ambInformationSelectors[e.returnValues.requestSelector] || 'unknown',
data: e.returnValues.data
})
module.exports = { module.exports = {
strip0x, strip0x,
parseAMBMessage, parseAMBMessage,
normalizeAMBMessageEvent, normalizeAMBMessageEvent
ambInformationSignatures,
normalizeAMBInfoRequest
} }

View File

@ -8,10 +8,8 @@
"test": "NODE_ENV=test mocha" "test": "NODE_ENV=test mocha"
}, },
"dependencies": { "dependencies": {
"@mycrypto/gas-estimation": "^1.1.0",
"gas-price-oracle": "^0.1.5", "gas-price-oracle": "^0.1.5",
"web3-utils": "^1.3.0", "web3-utils": "1.0.0-beta.34"
"node-fetch": "^2.1.2"
}, },
"devDependencies": { "devDependencies": {
"bn-chai": "^1.0.1", "bn-chai": "^1.0.1",

View File

@ -1,8 +1,12 @@
const { expect } = require('chai') const { expect } = require('chai')
const { BRIDGE_MODES } = require('../constants') const { BRIDGE_MODES, ERC_TYPES } = require('../constants')
describe('constants', () => { describe('constants', () => {
it('should contain correct number of bridge types', () => { it('should contain correct number of bridge types', () => {
expect(Object.keys(BRIDGE_MODES).length).to.be.equal(3) expect(Object.keys(BRIDGE_MODES).length).to.be.equal(7)
})
it('should contain correct number of erc types', () => {
expect(Object.keys(ERC_TYPES).length).to.be.equal(2)
}) })
}) })

View File

@ -0,0 +1,159 @@
const { expect } = require('chai')
const { getTokenType, ERC_TYPES } = require('..')
describe('getTokenType', () => {
it('should return ERC677 if bridgeContract is equal to bridgeAddress', async () => {
// Given
const bridgeAddress = '0xCecBE80Ed3548dE11D7d2D922a36576eA40C4c26'
const contract = {
methods: {
bridgeContract: () => {
return {
call: () => Promise.resolve(bridgeAddress)
}
}
}
}
// When
const type = await getTokenType(contract, bridgeAddress)
// Then
expect(type).to.equal(ERC_TYPES.ERC677)
})
it('should return ERC20 if bridgeContract is not equal to bridgeAddress', async () => {
// Given
const bridgeAddress = '0xCecBE80Ed3548dE11D7d2D922a36576eA40C4c26'
const contract = {
methods: {
bridgeContract: () => {
return {
call: () => Promise.resolve('0xBFCb120F7B1de491262CA4D9D8Eba70438b6896E')
}
}
}
}
// When
const type = await getTokenType(contract, bridgeAddress)
// Then
expect(type).to.equal(ERC_TYPES.ERC20)
})
it('should return ERC20 if bridgeContract is not present', async () => {
// Given
const bridgeAddress = '0xCecBE80Ed3548dE11D7d2D922a36576eA40C4c26'
const contract = {
methods: {
bridgeContract: () => {
return {
call: () => Promise.reject()
}
}
}
}
// When
const type = await getTokenType(contract, bridgeAddress)
// Then
expect(type).to.equal(ERC_TYPES.ERC20)
})
it('should return ERC20 if bridgeContract and isBridge are not present', async () => {
// Given
const bridgeAddress = '0xCecBE80Ed3548dE11D7d2D922a36576eA40C4c26'
const contract = {
methods: {
bridgeContract: () => {
return {
call: () => Promise.reject()
}
},
isBridge: () => {
return {
call: () => Promise.reject()
}
}
}
}
// When
const type = await getTokenType(contract, bridgeAddress)
// Then
expect(type).to.equal(ERC_TYPES.ERC20)
})
it('should return ERC677 if isBridge returns true', async () => {
// Given
const bridgeAddress = '0xCecBE80Ed3548dE11D7d2D922a36576eA40C4c26'
const contract = {
methods: {
bridgeContract: () => {
return {
call: () => Promise.reject()
}
},
isBridge: () => {
return {
call: () => Promise.resolve(true)
}
}
}
}
// When
const type = await getTokenType(contract, bridgeAddress)
// Then
expect(type).to.equal(ERC_TYPES.ERC677)
})
it('should return ERC677 if isBridge returns true and bridgeContract not present', async () => {
// Given
const bridgeAddress = '0xCecBE80Ed3548dE11D7d2D922a36576eA40C4c26'
const contract = {
methods: {
isBridge: () => {
return {
call: () => Promise.resolve(true)
}
}
}
}
// When
const type = await getTokenType(contract, bridgeAddress)
// Then
expect(type).to.equal(ERC_TYPES.ERC677)
})
it('should return ERC20 if isBridge returns false', async () => {
// Given
const bridgeAddress = '0xCecBE80Ed3548dE11D7d2D922a36576eA40C4c26'
const contract = {
methods: {
bridgeContract: () => {
return {
call: () => Promise.reject()
}
},
isBridge: () => {
return {
call: () => Promise.resolve(false)
}
}
}
}
// When
const type = await getTokenType(contract, bridgeAddress)
// Then
expect(type).to.equal(ERC_TYPES.ERC20)
})
})

View File

@ -1,18 +1,22 @@
const { toWei, toBN, BN } = require('web3-utils') const { toWei, toBN, BN } = require('web3-utils')
const { GasPriceOracle } = require('gas-price-oracle') const { GasPriceOracle } = require('gas-price-oracle')
const { estimateFees } = require('@mycrypto/gas-estimation') const { BRIDGE_MODES, FEE_MANAGER_MODE, ERC_TYPES } = require('./constants')
const fetch = require('node-fetch')
const { BRIDGE_MODES } = require('./constants')
const { REWARDABLE_VALIDATORS_ABI } = require('./abis') const { REWARDABLE_VALIDATORS_ABI } = require('./abis')
const gasPriceOracle = new GasPriceOracle() const gasPriceOracle = new GasPriceOracle()
function decodeBridgeMode(bridgeModeHash) { function decodeBridgeMode(bridgeModeHash) {
switch (bridgeModeHash) { switch (bridgeModeHash) {
case '0x92a8d7fe':
return BRIDGE_MODES.NATIVE_TO_ERC
case '0xba4690f5':
return BRIDGE_MODES.ERC_TO_ERC
case '0x18762d46': case '0x18762d46':
return BRIDGE_MODES.ERC_TO_NATIVE return BRIDGE_MODES.ERC_TO_NATIVE
case '0x2544fbb9': case '0x2544fbb9':
return BRIDGE_MODES.ARBITRARY_MESSAGE return BRIDGE_MODES.ARBITRARY_MESSAGE
case '0x16ea01e9':
return BRIDGE_MODES.STAKE_AMB_ERC_TO_ERC
case '0x76595b56': case '0x76595b56':
return BRIDGE_MODES.AMB_ERC_TO_ERC return BRIDGE_MODES.AMB_ERC_TO_ERC
default: default:
@ -20,9 +24,80 @@ function decodeBridgeMode(bridgeModeHash) {
} }
} }
const decodeFeeManagerMode = managerModeHash => {
switch (managerModeHash) {
case '0xf2aed8f7':
return FEE_MANAGER_MODE.ONE_DIRECTION
case '0xd7de965f':
return FEE_MANAGER_MODE.BOTH_DIRECTIONS
default:
throw new Error(`Unrecognized fee manager mode hash: '${managerModeHash}'`)
}
}
async function getBridgeMode(contract) { async function getBridgeMode(contract) {
try {
const bridgeModeHash = await contract.methods.getBridgeMode().call() const bridgeModeHash = await contract.methods.getBridgeMode().call()
return decodeBridgeMode(bridgeModeHash) return decodeBridgeMode(bridgeModeHash)
} catch (e) {
return BRIDGE_MODES.NATIVE_TO_ERC_V1
}
}
const getTokenType = async (bridgeTokenContract, bridgeAddress) => {
try {
const resultBridgeAddress = await bridgeTokenContract.methods.bridgeContract().call()
if (resultBridgeAddress === bridgeAddress) {
return ERC_TYPES.ERC677
} else {
return ERC_TYPES.ERC20
}
} catch (e) {
try {
const isBridge = await bridgeTokenContract.methods.isBridge(bridgeAddress).call()
if (isBridge) {
return ERC_TYPES.ERC677
} else {
return ERC_TYPES.ERC20
}
} catch (e) {
return ERC_TYPES.ERC20
}
}
}
const isErcToErcMode = bridgeMode => {
return (
bridgeMode === BRIDGE_MODES.ERC_TO_ERC ||
bridgeMode === BRIDGE_MODES.AMB_ERC_TO_ERC ||
bridgeMode === BRIDGE_MODES.STAKE_AMB_ERC_TO_ERC
)
}
const isMediatorMode = bridgeMode => {
return bridgeMode === BRIDGE_MODES.AMB_ERC_TO_ERC || bridgeMode === BRIDGE_MODES.STAKE_AMB_ERC_TO_ERC
}
const getUnit = bridgeMode => {
let unitHome = null
let unitForeign = null
if (bridgeMode === BRIDGE_MODES.NATIVE_TO_ERC) {
unitHome = 'Native coins'
unitForeign = 'Tokens'
} else if (bridgeMode === BRIDGE_MODES.ERC_TO_ERC) {
unitHome = 'Tokens'
unitForeign = 'Tokens'
} else if (bridgeMode === BRIDGE_MODES.ERC_TO_NATIVE) {
unitHome = 'Native coins'
unitForeign = 'Tokens'
} else if (bridgeMode === BRIDGE_MODES.STAKE_AMB_ERC_TO_ERC) {
unitHome = 'Tokens'
unitForeign = 'Tokens'
} else {
throw new Error(`Unrecognized bridge mode: ${bridgeMode}`)
}
return { unitHome, unitForeign }
} }
const parseValidatorEvent = event => { const parseValidatorEvent = event => {
@ -177,27 +252,20 @@ const gasPriceWithinLimits = (gasPrice, limits) => {
const normalizeGasPrice = (oracleGasPrice, factor, limits = null) => { const normalizeGasPrice = (oracleGasPrice, factor, limits = null) => {
let gasPrice = oracleGasPrice * factor let gasPrice = oracleGasPrice * factor
gasPrice = gasPriceWithinLimits(gasPrice, limits) gasPrice = gasPriceWithinLimits(gasPrice, limits)
return toWei(gasPrice.toFixed(2).toString(), 'gwei') return toBN(toWei(gasPrice.toFixed(2).toString(), 'gwei'))
} }
const gasPriceFromSupplier = async (web3, url, options = {}) => { // fetchFn has to be supplied (instead of just url to oracle),
// because this utility function is shared between Browser and Node,
// we use built-in 'fetch' on browser side, and `node-fetch` package in Node.
const gasPriceFromSupplier = async (fetchFn, options = {}) => {
try { try {
let json let json
if (url === 'eip1559-gas-estimation') { if (fetchFn) {
const { maxFeePerGas, maxPriorityFeePerGas } = await estimateFees(web3) const response = await fetchFn()
const res = { maxFeePerGas: maxFeePerGas.toString(10), maxPriorityFeePerGas: maxPriorityFeePerGas.toString(10) }
options.logger &&
options.logger.debug &&
options.logger.debug(res, 'Gas price updated using eip1559-gas-estimation')
return res
}
if (url === 'gas-price-oracle') {
json = await gasPriceOracle.fetchGasPricesOffChain()
} else if (url) {
const response = await fetch(url, { timeout: 2000 })
json = await response.json() json = await response.json()
} else { } else {
return null json = await gasPriceOracle.fetchGasPricesOffChain()
} }
const oracleGasPrice = json[options.speedType] const oracleGasPrice = json[options.speedType]
@ -214,7 +282,7 @@ const gasPriceFromSupplier = async (web3, url, options = {}) => {
options.logger.debug && options.logger.debug &&
options.logger.debug({ oracleGasPrice, normalizedGasPrice }, 'Gas price updated using the API') options.logger.debug({ oracleGasPrice, normalizedGasPrice }, 'Gas price updated using the API')
return { gasPrice: normalizedGasPrice } return normalizedGasPrice
} catch (e) { } catch (e) {
options.logger && options.logger.error && options.logger.error(`Gas Price API is not available. ${e.message}`) options.logger && options.logger.error && options.logger.error(`Gas Price API is not available. ${e.message}`)
} }
@ -223,11 +291,11 @@ const gasPriceFromSupplier = async (web3, url, options = {}) => {
const gasPriceFromContract = async (bridgeContract, options = {}) => { const gasPriceFromContract = async (bridgeContract, options = {}) => {
try { try {
const gasPrice = (await bridgeContract.methods.gasPrice().call()).toString() const gasPrice = await bridgeContract.methods.gasPrice().call()
options.logger && options.logger &&
options.logger.debug && options.logger.debug &&
options.logger.debug({ gasPrice }, 'Gas price updated using the contracts') options.logger.debug({ gasPrice }, 'Gas price updated using the contracts')
return { gasPrice } return gasPrice
} catch (e) { } catch (e) {
options.logger && options.logger &&
options.logger.error && options.logger.error &&
@ -238,7 +306,10 @@ const gasPriceFromContract = async (bridgeContract, options = {}) => {
module.exports = { module.exports = {
decodeBridgeMode, decodeBridgeMode,
decodeFeeManagerMode,
getBridgeMode, getBridgeMode,
getTokenType,
getUnit,
parseValidatorEvent, parseValidatorEvent,
processValidatorsEvents, processValidatorsEvents,
getValidatorList, getValidatorList,
@ -247,5 +318,7 @@ module.exports = {
normalizeGasPrice, normalizeGasPrice,
gasPriceFromSupplier, gasPriceFromSupplier,
gasPriceFromContract, gasPriceFromContract,
gasPriceWithinLimits gasPriceWithinLimits,
isErcToErcMode,
isMediatorMode
} }

191
commons/v1Abis.js Normal file
View File

@ -0,0 +1,191 @@
const homeV1Abi = [
{
constant: true,
inputs: [],
name: 'validatorContract',
outputs: [
{
name: '',
type: 'address'
}
],
payable: false,
stateMutability: 'view',
type: 'function'
},
{
anonymous: false,
inputs: [
{
indexed: false,
name: 'recipient',
type: 'address'
},
{
indexed: false,
name: 'value',
type: 'uint256'
}
],
name: 'Deposit',
type: 'event'
},
{
anonymous: false,
inputs: [
{
indexed: false,
name: 'recipient',
type: 'address'
},
{
indexed: false,
name: 'value',
type: 'uint256'
},
{
indexed: false,
name: 'transactionHash',
type: 'bytes32'
}
],
name: 'Withdraw',
type: 'event'
},
{
constant: true,
inputs: [],
name: 'deployedAtBlock',
outputs: [
{
name: '',
type: 'uint256'
}
],
payable: false,
stateMutability: 'view',
type: 'function'
},
{
constant: true,
inputs: [],
name: 'requiredBlockConfirmations',
outputs: [
{
name: '',
type: 'uint256'
}
],
payable: false,
stateMutability: 'view',
type: 'function'
}
]
const foreignViAbi = [
{
constant: true,
inputs: [],
name: 'validatorContract',
outputs: [
{
name: '',
type: 'address'
}
],
payable: false,
stateMutability: 'view',
type: 'function'
},
{
anonymous: false,
inputs: [
{
indexed: false,
name: 'recipient',
type: 'address'
},
{
indexed: false,
name: 'value',
type: 'uint256'
},
{
indexed: false,
name: 'transactionHash',
type: 'bytes32'
}
],
name: 'Deposit',
type: 'event'
},
{
anonymous: false,
inputs: [
{
indexed: false,
name: 'recipient',
type: 'address'
},
{
indexed: false,
name: 'value',
type: 'uint256'
},
{
indexed: false,
name: 'homeGasPrice',
type: 'uint256'
}
],
name: 'Withdraw',
type: 'event'
},
{
constant: true,
inputs: [],
name: 'deployedAtBlock',
outputs: [
{
name: '',
type: 'uint256'
}
],
payable: false,
stateMutability: 'view',
type: 'function'
},
{
constant: true,
inputs: [],
name: 'erc677token',
outputs: [
{
name: '',
type: 'address'
}
],
payable: false,
stateMutability: 'view',
type: 'function'
},
{
constant: true,
inputs: [],
name: 'requiredBlockConfirmations',
outputs: [
{
name: '',
type: 'uint256'
}
],
payable: false,
stateMutability: 'view',
type: 'function'
}
]
module.exports = {
HOME_V1_ABI: homeV1Abi,
FOREIGN_V1_ABI: foreignViAbi
}

@ -1 +1 @@
Subproject commit 908a48107919d4ab127f9af07d44d47eac91547e Subproject commit c9377114f7bcf04cd12a30d9eca0a63362dcaedc

View File

@ -34,7 +34,7 @@ provisioner:
inventory: inventory:
host_vars: host_vars:
multiple-host: multiple-host:
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "6c48435bd464a53ed66ed62127c4dba8af75cf1a99a8ebe2680599948fbfbc6d" ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
MONITOR_PORT: 3003 MONITOR_PORT: 3003
syslog_server_port: "udp://127.0.0.1:514" syslog_server_port: "udp://127.0.0.1:514"
verifier: verifier:

View File

@ -33,7 +33,7 @@ provisioner:
inventory: inventory:
host_vars: host_vars:
oracle-host: oracle-host:
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "6c48435bd464a53ed66ed62127c4dba8af75cf1a99a8ebe2680599948fbfbc6d" ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
syslog_server_port: "udp://127.0.0.1:514" syslog_server_port: "udp://127.0.0.1:514"
verifier: verifier:
name: testinfra name: testinfra

View File

@ -9,17 +9,15 @@
- oracle_net_db_bridge_request - oracle_net_db_bridge_request
- oracle_net_db_bridge_collected - oracle_net_db_bridge_collected
- oracle_net_db_bridge_affirmation - oracle_net_db_bridge_affirmation
- oracle_net_db_bridge_information
- oracle_net_db_bridge_transfer - oracle_net_db_bridge_transfer
- oracle_net_db_bridge_senderhome - oracle_net_db_bridge_senderhome
- oracle_net_db_bridge_senderforeign - oracle_net_db_bridge_senderforeign
- oracle_net_db_bridge_shutdown
- oracle_net_rabbit_bridge_request - oracle_net_rabbit_bridge_request
- oracle_net_rabbit_bridge_collected - oracle_net_rabbit_bridge_collected
- oracle_net_rabbit_bridge_affirmation - oracle_net_rabbit_bridge_affirmation
- oracle_net_rabbit_bridge_information
- oracle_net_rabbit_bridge_transfer - oracle_net_rabbit_bridge_transfer
- oracle_net_rabbit_bridge_senderhome - oracle_net_rabbit_bridge_senderhome
- oracle_net_rabbit_bridge_senderforeign - oracle_net_rabbit_bridge_senderforeign
- oracle_net_rabbit_bridge_convert_to_chai_worker
delegate_to: 127.0.0.1 delegate_to: 127.0.0.1
become: false become: false

View File

@ -0,0 +1,14 @@
# Molecule managed
{% if item.registry is defined %}
FROM {{ item.registry.url }}/{{ item.image }}
{% else %}
FROM {{ item.image }}
{% endif %}
RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \
elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash && dnf clean all; \
elif [ $(command -v yum) ]; then yum makecache fast && yum install -y python sudo yum-plugin-ovl bash && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \
elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml && zypper clean -a; \
elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates; \
elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates && xbps-remove -O; fi

View File

@ -0,0 +1,38 @@
---
driver:
name: docker
platforms:
- name: oracle-erc-to-erc-host
groups:
- ultimate
- erc-to-erc
children:
- oracle
image: ubuntu:16.04
privileged: true
network_mode: host
volumes:
- /var/run/docker.sock:/var/run/docker.sock
provisioner:
name: ansible
playbooks:
prepare: ../prepare.yml
converge: ../ultimate-commons/converge.yml
inventory:
host_vars:
oracle-erc-to-erc-host:
ORACLE_VALIDATOR_ADDRESS: "0xaaB52d66283F7A1D5978bcFcB55721ACB467384b"
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
verifier:
name: testinfra
lint:
name: flake8
scenario:
name: ultimate-erc-to-erc
test_sequence:
- cleanup
- destroy
- syntax
- create
- prepare
- converge

View File

@ -0,0 +1,14 @@
# Molecule managed
{% if item.registry is defined %}
FROM {{ item.registry.url }}/{{ item.image }}
{% else %}
FROM {{ item.image }}
{% endif %}
RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \
elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash && dnf clean all; \
elif [ $(command -v yum) ]; then yum makecache fast && yum install -y python sudo yum-plugin-ovl bash && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \
elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml && zypper clean -a; \
elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates; \
elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates && xbps-remove -O; fi

View File

@ -0,0 +1,38 @@
---
driver:
name: docker
platforms:
- name: oracle-native-to-erc-host
groups:
- ultimate
- native-to-erc
children:
- oracle
image: ubuntu:16.04
privileged: true
network_mode: host
volumes:
- /var/run/docker.sock:/var/run/docker.sock
provisioner:
name: ansible
playbooks:
prepare: ../prepare.yml
converge: ../ultimate-commons/converge.yml
inventory:
host_vars:
oracle-native-to-erc-host:
ORACLE_VALIDATOR_ADDRESS: "0xaaB52d66283F7A1D5978bcFcB55721ACB467384b"
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
verifier:
name: testinfra
lint:
name: flake8
scenario:
name: ultimate-native-to-erc
test_sequence:
- cleanup
- destroy
- syntax
- create
- prepare
- converge

View File

@ -1,5 +1,5 @@
--- ---
ORACLE_BRIDGE_MODE: "ARBITRARY_MESSAGE" ORACLE_BRIDGE_MODE: "ARBITRARY_MESSAGE"
COMMON_HOME_BRIDGE_ADDRESS: "0x8397be90BCF57b0B71219f555Fe121b22e5a994C" COMMON_HOME_BRIDGE_ADDRESS: "0x0AEe1FCD12dDFab6265F7f8956e6E012A9Fe4Aa0"
COMMON_FOREIGN_BRIDGE_ADDRESS: "0x1feB40aD9420b186F019A717c37f5546165d411E" COMMON_FOREIGN_BRIDGE_ADDRESS: "0x0AEe1FCD12dDFab6265F7f8956e6E012A9Fe4Aa0"
MONITOR_PORT: 3013 MONITOR_PORT: 3013

View File

@ -0,0 +1,5 @@
---
ORACLE_BRIDGE_MODE: "ERC_TO_ERC"
COMMON_HOME_BRIDGE_ADDRESS: "0x1feB40aD9420b186F019A717c37f5546165d411E"
COMMON_FOREIGN_BRIDGE_ADDRESS: "0x4a58D6d8D416a5fBCAcf3dC52eb8bE8948E25127"
MONITOR_PORT: 3011

View File

@ -1,5 +1,5 @@
--- ---
ORACLE_BRIDGE_MODE: "ERC_TO_NATIVE" ORACLE_BRIDGE_MODE: "ERC_TO_NATIVE"
COMMON_HOME_BRIDGE_ADDRESS: "0x5118AC62AE912Dd5B51EEfF7338c4fcb0248Ba8c" COMMON_HOME_BRIDGE_ADDRESS: "0x488Af810997eD1730cB3a3918cD83b3216E6eAda"
COMMON_FOREIGN_BRIDGE_ADDRESS: "0x32198D570fffC7033641F8A9094FFDCaAEF42624" COMMON_FOREIGN_BRIDGE_ADDRESS: "0x488Af810997eD1730cB3a3918cD83b3216E6eAda"
MONITOR_PORT: 3012 MONITOR_PORT: 3012

View File

@ -1,17 +1,17 @@
--- ---
## General settings ## General settings
ORACLE_BRIDGE_MODE: "ARBITRARY_MESSAGE" ORACLE_BRIDGE_MODE: "NATIVE_TO_ERC"
ORACLE_LOG_LEVEL: debug ORACLE_LOG_LEVEL: debug
## Home contract ## Home contract
COMMON_HOME_RPC_URL: "https://sokol.poa.network" COMMON_HOME_RPC_URL: "https://sokol.poa.network"
COMMON_HOME_BRIDGE_ADDRESS: "0x59ba90A588ce732AB33FD32Aab1b58c21400A0f6" COMMON_HOME_BRIDGE_ADDRESS: "0x98aFdE294f1C46aA0a27Cc4049ED337F879d8976"
ORACLE_HOME_RPC_POLLING_INTERVAL: 5000 ORACLE_HOME_RPC_POLLING_INTERVAL: 5000
## Foreign contract ## Foreign contract
COMMON_FOREIGN_RPC_URL: "https://kovan.infura.io/v3/5d7bd94c50ed43fab1cb8e74f58678b0" COMMON_FOREIGN_RPC_URL: "https://sokol.poa.network"
COMMON_FOREIGN_BRIDGE_ADDRESS: "0xdA4a49a00F4fF4A5988b9AceE95f99e3b2c208b6" COMMON_FOREIGN_BRIDGE_ADDRESS: "0x5a584f4C30B36f282848dAc9a2b20E7BEF481981"
ORACLE_FOREIGN_RPC_POLLING_INTERVAL: 5000 ORACLE_FOREIGN_RPC_POLLING_INTERVAL: 1000
## Home Gasprice ## Home Gasprice
COMMON_HOME_GAS_PRICE_SUPPLIER_URL: "https://gasprice.poa.network/" COMMON_HOME_GAS_PRICE_SUPPLIER_URL: "https://gasprice.poa.network/"
@ -31,8 +31,8 @@ ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
MONITOR_BRIDGE_NAME: "bridge" MONITOR_BRIDGE_NAME: "bridge"
MONITOR_PORT: 3003 MONITOR_PORT: 3003
MONITOR_CACHE_EVENTS: "false" MONITOR_CACHE_EVENTS: "false"
MONITOR_HOME_START_BLOCK: 20821049 MONITOR_HOME_START_BLOCK: 0
MONITOR_FOREIGN_START_BLOCK: 24773297 MONITOR_FOREIGN_START_BLOCK: 0
MONITOR_VALIDATOR_HOME_TX_LIMIT: 300000 MONITOR_VALIDATOR_HOME_TX_LIMIT: 300000
MONITOR_VALIDATOR_FOREIGN_TX_LIMIT: 300000 MONITOR_VALIDATOR_FOREIGN_TX_LIMIT: 300000
MONITOR_TX_NUMBER_THRESHOLD: 100 MONITOR_TX_NUMBER_THRESHOLD: 100

View File

@ -0,0 +1,5 @@
---
ORACLE_BRIDGE_MODE: "NATIVE_TO_ERC"
COMMON_HOME_BRIDGE_ADDRESS: "0x32198D570fffC7033641F8A9094FFDCaAEF42624"
COMMON_FOREIGN_BRIDGE_ADDRESS: "0x2B6871b9B02F73fa24F4864322CdC78604207769"
MONITOR_PORT: 3010

View File

@ -0,0 +1,37 @@
---
## General settings
ORACLE_BRIDGE_MODE: "NATIVE_TO_ERC"
## Home contract
COMMON_HOME_RPC_URL: "https://www.ethercluster.com/etc"
COMMON_HOME_BRIDGE_ADDRESS: "0x073081832B4Ecdce79d4D6753565c85Ba4b3BeA9"
ORACLE_HOME_RPC_POLLING_INTERVAL: 7000
## Foreign contract
COMMON_FOREIGN_RPC_URL: "https://mainnet.infura.io/"
COMMON_FOREIGN_BRIDGE_ADDRESS: "0x0cB781EE62F815bdD9CD4c2210aE8600d43e7040"
ORACLE_FOREIGN_RPC_POLLING_INTERVAL: 7000
## Home Gasprice
COMMON_HOME_GAS_PRICE_SUPPLIER_URL: "https://gasprice-etc.poa.network/"
COMMON_HOME_GAS_PRICE_SPEED_TYPE: "standard"
COMMON_HOME_GAS_PRICE_FALLBACK: 15000000000 # in wei
ORACLE_HOME_GAS_PRICE_UPDATE_INTERVAL: 600000
COMMON_HOME_GAS_PRICE_FACTOR: 1
## Foreign Gasprice
COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL: "https://gasprice.poa.network/"
COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE: "standard"
COMMON_FOREIGN_GAS_PRICE_FALLBACK: 10000000000 # in wei
ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
COMMON_FOREIGN_GAS_PRICE_FACTOR: 1
## Monitor
MONITOR_BRIDGE_NAME: "wetc"
MONITOR_PORT: 3003
MONITOR_CACHE_EVENTS: "true"
MONITOR_HOME_START_BLOCK: 7703292
MONITOR_FOREIGN_START_BLOCK: 7412459
MONITOR_VALIDATOR_HOME_TX_LIMIT: 300000
MONITOR_VALIDATOR_FOREIGN_TX_LIMIT: 300000
MONITOR_TX_NUMBER_THRESHOLD: 100

View File

@ -1,6 +1,6 @@
/var/log/docker/*/docker.log { /var/log/docker/*/docker.log {
rotate 5 rotate 5
size 100M size 1G
compress compress
missingok missingok
delaycompress delaycompress
@ -8,7 +8,7 @@
} }
/var/log/docker/*.log { /var/log/docker/*.log {
rotate 5 rotate 5
size 100M size 1G
compress compress
missingok missingok
delaycompress delaycompress

View File

@ -3,11 +3,11 @@
with_items: with_items:
- docker-compose - docker-compose
- docker-compose-transfer - docker-compose-transfer
- docker-compose-amb - docker-compose-erc-native
loop_control: loop_control:
loop_var: file loop_var: file
- name: Set the oracle's containers local logs configuration file - name: Set the local container logs configuration file
template: template:
src: 31-oracle-docker.conf.j2 src: 31-oracle-docker.conf.j2
dest: /etc/rsyslog.d/31-oracle-docker.conf dest: /etc/rsyslog.d/31-oracle-docker.conf
@ -15,22 +15,6 @@
group: root group: root
mode: 0644 mode: 0644
- name: Set the redis container local logs configuration file
template:
src: 32-redis-docker.conf.j2
dest: /etc/rsyslog.d/32-redis-docker.conf
owner: root
group: root
mode: 0644
- name: Set the rabbit MQ container local logs configuration file
template:
src: 33-rabbit-docker.conf.j2
dest: /etc/rsyslog.d/33-rabbit-docker.conf
owner: root
group: root
mode: 0644
- name: Set the log configuration file to send container logs to remote server - name: Set the log configuration file to send container logs to remote server
template: template:
src: 36-oracle-remote-logging.conf.j2 src: 36-oracle-remote-logging.conf.j2

View File

@ -27,13 +27,24 @@
set_fact: set_fact:
ORACLE_VALIDATOR_ADDRESS: "{{ VADDRESS.stdout }}" ORACLE_VALIDATOR_ADDRESS: "{{ VADDRESS.stdout }}"
- name: Extend docker compose file for erc to native - name: Get foreign erc type
set_fact: composefileoverride="-f docker-compose-transfer.yml" become_user: "{{ compose_service_user }}"
when: ORACLE_BRIDGE_MODE == "ERC_TO_NATIVE" shell: docker-compose run --rm --entrypoint "node scripts/initialChecks.js" bridge_affirmation
args:
chdir: "{{ bridge_path }}/oracle"
register: ERCTYPE
- name: Extend docker compose file for amb - name: Set FOREIGN_ERC_TYPE variable
set_fact: composefileoverride="-f docker-compose-amb.yml" set_fact:
when: ORACLE_BRIDGE_MODE == "ARBITRARY_MESSAGE" FOREIGN_ERC_TYPE: "{{ (ERCTYPE.stdout).foreignERC | default('') }}"
- name: Extend docker compose file
set_fact: composefileoverride="-f docker-compose-transfer.yml"
when: ORACLE_BRIDGE_MODE == "ERC_TO_ERC" and FOREIGN_ERC_TYPE != "ERC677"
- name: Extend docker compose file for erc to native
set_fact: composefileoverride="-f docker-compose-erc-native.yml"
when: ORACLE_BRIDGE_MODE == "ERC_TO_NATIVE"
- name: Install .key config - name: Install .key config
template: template:

View File

@ -20,4 +20,4 @@
with_items: with_items:
- docker-compose.yml - docker-compose.yml
- docker-compose-transfer.yml - docker-compose-transfer.yml
- docker-compose-amb.yml - docker-compose-erc-native.yml

View File

@ -11,16 +11,9 @@ ORACLE_HOME_RPC_POLLING_INTERVAL={{ ORACLE_HOME_RPC_POLLING_INTERVAL }}
## Foreign contract ## Foreign contract
COMMON_FOREIGN_RPC_URL={{ COMMON_FOREIGN_RPC_URL }} COMMON_FOREIGN_RPC_URL={{ COMMON_FOREIGN_RPC_URL }}
{% if ORACLE_FOREIGN_ARCHIVE_RPC_URL | default('') != '' %}
ORACLE_FOREIGN_ARCHIVE_RPC_URL={{ ORACLE_FOREIGN_ARCHIVE_RPC_URL }}
{% endif %}
COMMON_FOREIGN_BRIDGE_ADDRESS={{ COMMON_FOREIGN_BRIDGE_ADDRESS }} COMMON_FOREIGN_BRIDGE_ADDRESS={{ COMMON_FOREIGN_BRIDGE_ADDRESS }}
ORACLE_FOREIGN_RPC_POLLING_INTERVAL={{ ORACLE_FOREIGN_RPC_POLLING_INTERVAL }} ORACLE_FOREIGN_RPC_POLLING_INTERVAL={{ ORACLE_FOREIGN_RPC_POLLING_INTERVAL }}
{% if ORACLE_TX_REDUNDANCY | default('') != '' %}
ORACLE_TX_REDUNDANCY={{ ORACLE_TX_REDUNDANCY }}
{% endif %}
## Gasprice ## Gasprice
{% if COMMON_HOME_GAS_PRICE_SUPPLIER_URL | default('') != '' %} {% if COMMON_HOME_GAS_PRICE_SUPPLIER_URL | default('') != '' %}
COMMON_HOME_GAS_PRICE_SUPPLIER_URL={{ COMMON_HOME_GAS_PRICE_SUPPLIER_URL }} COMMON_HOME_GAS_PRICE_SUPPLIER_URL={{ COMMON_HOME_GAS_PRICE_SUPPLIER_URL }}
@ -54,28 +47,8 @@ COMMON_FOREIGN_GAS_PRICE_FACTOR={{ COMMON_FOREIGN_GAS_PRICE_FACTOR }}
ORACLE_ALLOW_HTTP_FOR_RPC={{ "yes" if ORACLE_ALLOW_HTTP_FOR_RPC else "no" }} ORACLE_ALLOW_HTTP_FOR_RPC={{ "yes" if ORACLE_ALLOW_HTTP_FOR_RPC else "no" }}
ORACLE_QUEUE_URL={{ ORACLE_QUEUE_URL }} ORACLE_QUEUE_URL={{ ORACLE_QUEUE_URL }}
ORACLE_REDIS_URL={{ ORACLE_REDIS_URL }} ORACLE_REDIS_URL={{ ORACLE_REDIS_URL }}
{% if ORACLE_FOREIGN_TX_RESEND_INTERVAL | default('') != '' %} {% if ORACLE_TX_REDUNDANCY | default('') != '' %}
ORACLE_FOREIGN_TX_RESEND_INTERVAL={{ ORACLE_FOREIGN_TX_RESEND_INTERVAL }} ORACLE_TX_REDUNDANCY={{ ORACLE_TX_REDUNDANCY }}
{% endif %}
{% if ORACLE_HOME_TX_RESEND_INTERVAL | default('') != '' %}
ORACLE_HOME_TX_RESEND_INTERVAL={{ ORACLE_HOME_TX_RESEND_INTERVAL }}
{% endif %}
## Emergency shutdown configuration
{% if ORACLE_SHUTDOWN_SERVICE_URL | default('') != '' %}
ORACLE_SHUTDOWN_SERVICE_URL={{ ORACLE_SHUTDOWN_SERVICE_URL }}
{% endif %}
{% if ORACLE_SHUTDOWN_SERVICE_POLLING_INTERVAL | default('') != '' %}
ORACLE_SHUTDOWN_SERVICE_POLLING_INTERVAL={{ ORACLE_SHUTDOWN_SERVICE_POLLING_INTERVAL }}
{% endif %}
{% if ORACLE_SIDE_RPC_URL | default('') != '' %}
ORACLE_SIDE_RPC_URL={{ ORACLE_SIDE_RPC_URL }}
{% endif %}
{% if ORACLE_SHUTDOWN_CONTRACT_ADDRESS | default('') != '' %}
ORACLE_SHUTDOWN_CONTRACT_ADDRESS={{ ORACLE_SHUTDOWN_CONTRACT_ADDRESS }}
{% endif %}
{% if ORACLE_SHUTDOWN_CONTRACT_METHOD | default('') != '' %}
ORACLE_SHUTDOWN_CONTRACT_METHOD={{ ORACLE_SHUTDOWN_CONTRACT_METHOD }}
{% endif %} {% endif %}
{% if ORACLE_HOME_START_BLOCK | default('') != '' %} {% if ORACLE_HOME_START_BLOCK | default('') != '' %}

View File

@ -1,11 +0,0 @@
$FileCreateMode 0644
template(name="DockerLogFileName_Redis" type="list") {
constant(value="/var/log/docker/")
property(name="syslogtag" securepath="replace" regex.type="ERE" regex.submatch="1" regex.expression="oracle_(.*redis.*)\\/[a-zA-Z0-9]+\\[")
constant(value="/docker.log")
}
if $programname contains 'oracle' and $programname contains 'redis' then \
?DockerLogFileName_Redis
$FileCreateMode 0600

View File

@ -1,11 +0,0 @@
$FileCreateMode 0644
template(name="DockerLogFileName_Rabbit" type="list") {
constant(value="/var/log/docker/")
property(name="syslogtag" securepath="replace" regex.type="ERE" regex.submatch="1" regex.expression="oracle_(.*rabbit.*)\\/[a-zA-Z0-9]+\\[")
constant(value="/docker.log")
}
if $programname contains 'oracle' and $programname contains 'rabbit' then \
?DockerLogFileName_Rabbit
$FileCreateMode 0600

View File

@ -26,7 +26,9 @@ Shut down and cleans up containers, networks, services, running scripts:
| oracle-validator-3 | Launches Oracle containers for third validator | | oracle-validator-3 | Launches Oracle containers for third validator |
| blocks | Auto mines blocks | | blocks | Auto mines blocks |
| monitor | Launches Monitor containers | | monitor | Launches Monitor containers |
| native-to-erc | Creates infrastructure for ultimate e2e testing, for native-to-erc type of bridge |
| erc-to-native | Creates infrastructure for ultimate e2e testing, for erc-to-native type of bridge | | erc-to-native | Creates infrastructure for ultimate e2e testing, for erc-to-native type of bridge |
| erc-to-erc | Creates infrastructure for ultimate e2e testing, for erc-to-erc type of bridge |
| amb | Creates infrastructure for ultimate e2e testing, for arbitrary message type of bridge | | amb | Creates infrastructure for ultimate e2e testing, for arbitrary message type of bridge |
#### Ultimate e2e testing #### Ultimate e2e testing

View File

@ -4,7 +4,7 @@ Documentation regarding the Ultimate end-to-end tests.
## Overview ## Overview
The ultimate e2e test scenario covers erc-to-native and amb types of bridges. The ultimate e2e test scenario covers native-to-erc type of bridge.
It runs the e2e tests on components deployed using the deployment playbooks. It runs the e2e tests on components deployed using the deployment playbooks.
@ -16,14 +16,14 @@ Run the Parity nodes, deploy the bridge contracts, deploy Oracle using the deplo
```bash ```bash
./e2e-commons/up.sh deploy blocks ./e2e-commons/up.sh deploy blocks
./deployment-e2e/molecule.sh ultimate-erc-to-native ./deployment-e2e/molecule.sh ultimate-native-to-erc
``` ```
### 2. Run the E2E tests ### 2. Run the E2E tests
```bash ```bash
cd e2e-commons cd e2e-commons
docker-compose run -e ULTIMATE=true e2e yarn workspace oracle-e2e run erc-to-native docker-compose run -e ULTIMATE=true e2e yarn workspace oracle-e2e run native-to-erc
``` ```
## Diagram ## Diagram

View File

@ -1,2 +1,2 @@
0xc9e38bfdB9c635F0796ad83CC8705dc379F41c04 0xc9e38bfdB9c635F0796ad83CC8705dc379F41c04
0xF9698Eb93702dfdd0e2d802088d4c21822a8A977 0x6f359aC418a5f7538F7755A33C9c7dDf38785524

View File

@ -5,11 +5,9 @@ set -e # exit when any command fails
docker-compose build e2e docker-compose build e2e
while [ "$1" != "" ]; do while [ "$1" != "" ]; do
if [ "$1" == "oracle" ]; then if [ "$1" == "oracle" ]; then
docker-compose build oracle-amb docker-compose build oracle
elif [ "$1" == "alm-e2e" ]; then
docker-compose build oracle-amb
elif [ "$1" == "monitor" ]; then elif [ "$1" == "monitor" ]; then
docker-compose build monitor-amb docker-compose build monitor
elif [ "$1" == "alm" ]; then elif [ "$1" == "alm" ]; then
docker-compose build alm docker-compose build alm
fi fi

View File

@ -1,5 +1,5 @@
COMMON_HOME_BRIDGE_ADDRESS=0x8397be90BCF57b0B71219f555Fe121b22e5a994C COMMON_HOME_BRIDGE_ADDRESS=0x0AEe1FCD12dDFab6265F7f8956e6E012A9Fe4Aa0
COMMON_FOREIGN_BRIDGE_ADDRESS=0x1feB40aD9420b186F019A717c37f5546165d411E COMMON_FOREIGN_BRIDGE_ADDRESS=0x0AEe1FCD12dDFab6265F7f8956e6E012A9Fe4Aa0
COMMON_HOME_RPC_URL=http://localhost:8541 COMMON_HOME_RPC_URL=http://localhost:8541
COMMON_FOREIGN_RPC_URL=http://localhost:8542 COMMON_FOREIGN_RPC_URL=http://localhost:8542

View File

@ -1,7 +1,7 @@
COMMON_HOME_RPC_URL=http://parity1:8545 COMMON_HOME_RPC_URL=http://parity1:8545
COMMON_FOREIGN_RPC_URL=http://parity2:8545 COMMON_FOREIGN_RPC_URL=http://parity2:8545
COMMON_HOME_BRIDGE_ADDRESS=0x8397be90BCF57b0B71219f555Fe121b22e5a994C COMMON_HOME_BRIDGE_ADDRESS=0x0AEe1FCD12dDFab6265F7f8956e6E012A9Fe4Aa0
COMMON_FOREIGN_BRIDGE_ADDRESS=0x1feB40aD9420b186F019A717c37f5546165d411E COMMON_FOREIGN_BRIDGE_ADDRESS=0x0AEe1FCD12dDFab6265F7f8956e6E012A9Fe4Aa0
MONITOR_HOME_START_BLOCK=0 MONITOR_HOME_START_BLOCK=0
MONITOR_FOREIGN_START_BLOCK=0 MONITOR_FOREIGN_START_BLOCK=0
MONITOR_VALIDATOR_HOME_TX_LIMIT=300000 MONITOR_VALIDATOR_HOME_TX_LIMIT=300000

View File

@ -1,7 +1,7 @@
COMMON_HOME_RPC_URL=http://parity1:8545 COMMON_HOME_RPC_URL=http://parity1:8545
COMMON_FOREIGN_RPC_URL=http://parity2:8545 COMMON_FOREIGN_RPC_URL=http://parity2:8545
COMMON_HOME_BRIDGE_ADDRESS=0x5118AC62AE912Dd5B51EEfF7338c4fcb0248Ba8c COMMON_HOME_BRIDGE_ADDRESS=0x488Af810997eD1730cB3a3918cD83b3216E6eAda
COMMON_FOREIGN_BRIDGE_ADDRESS=0x32198D570fffC7033641F8A9094FFDCaAEF42624 COMMON_FOREIGN_BRIDGE_ADDRESS=0x488Af810997eD1730cB3a3918cD83b3216E6eAda
MONITOR_HOME_START_BLOCK=0 MONITOR_HOME_START_BLOCK=0
MONITOR_FOREIGN_START_BLOCK=0 MONITOR_FOREIGN_START_BLOCK=0
MONITOR_VALIDATOR_HOME_TX_LIMIT=300000 MONITOR_VALIDATOR_HOME_TX_LIMIT=300000

View File

@ -0,0 +1,20 @@
COMMON_HOME_RPC_URL=http://parity1:8545
COMMON_FOREIGN_RPC_URL=http://parity2:8545
COMMON_HOME_BRIDGE_ADDRESS=0x1feB40aD9420b186F019A717c37f5546165d411E
COMMON_FOREIGN_BRIDGE_ADDRESS=0x4a58D6d8D416a5fBCAcf3dC52eb8bE8948E25127
MONITOR_HOME_START_BLOCK=0
MONITOR_FOREIGN_START_BLOCK=0
MONITOR_VALIDATOR_HOME_TX_LIMIT=300000
COMMON_HOME_GAS_PRICE_SUPPLIER_URL=https://gasprice.poa.network/
COMMON_HOME_GAS_PRICE_SPEED_TYPE=standard
COMMON_HOME_GAS_PRICE_FALLBACK=1000000000
COMMON_HOME_GAS_PRICE_FACTOR=1
MONITOR_VALIDATOR_FOREIGN_TX_LIMIT=300000
COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL=https://gasprice.poa.network/
COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE=standard
COMMON_FOREIGN_GAS_PRICE_FALLBACK=1000000000
COMMON_FOREIGN_GAS_PRICE_FACTOR=1
MONITOR_TX_NUMBER_THRESHOLD=100
MONITOR_PORT=3011
MONITOR_BRIDGE_NAME=bridge
MONITOR_CACHE_EVENTS=false

View File

@ -0,0 +1,20 @@
COMMON_HOME_RPC_URL=http://parity1:8545
COMMON_FOREIGN_RPC_URL=http://parity2:8545
COMMON_HOME_BRIDGE_ADDRESS=0x32198D570fffC7033641F8A9094FFDCaAEF42624
COMMON_FOREIGN_BRIDGE_ADDRESS=0x2B6871b9B02F73fa24F4864322CdC78604207769
MONITOR_HOME_START_BLOCK=0
MONITOR_FOREIGN_START_BLOCK=0
MONITOR_VALIDATOR_HOME_TX_LIMIT=300000
COMMON_HOME_GAS_PRICE_SUPPLIER_URL=https://gasprice.poa.network/
COMMON_HOME_GAS_PRICE_SPEED_TYPE=standard
COMMON_HOME_GAS_PRICE_FALLBACK=1000000000
COMMON_HOME_GAS_PRICE_FACTOR=1
MONITOR_VALIDATOR_FOREIGN_TX_LIMIT=300000
COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL=https://gasprice.poa.network/
COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE=standard
COMMON_FOREIGN_GAS_PRICE_FALLBACK=1000000000
COMMON_FOREIGN_GAS_PRICE_FACTOR=1
MONITOR_TX_NUMBER_THRESHOLD=100
MONITOR_PORT=3010
MONITOR_BRIDGE_NAME=bridge
MONITOR_CACHE_EVENTS=false

View File

@ -4,14 +4,16 @@ ORACLE_QUEUE_URL=amqp://rabbit
ORACLE_REDIS_URL=redis://redis ORACLE_REDIS_URL=redis://redis
COMMON_HOME_RPC_URL=http://parity1:8545 COMMON_HOME_RPC_URL=http://parity1:8545
COMMON_FOREIGN_RPC_URL=http://parity2:8545 COMMON_FOREIGN_RPC_URL=http://parity2:8545
COMMON_HOME_BRIDGE_ADDRESS=0x8397be90BCF57b0B71219f555Fe121b22e5a994C COMMON_HOME_BRIDGE_ADDRESS=0x0AEe1FCD12dDFab6265F7f8956e6E012A9Fe4Aa0
COMMON_FOREIGN_BRIDGE_ADDRESS=0x1feB40aD9420b186F019A717c37f5546165d411E COMMON_FOREIGN_BRIDGE_ADDRESS=0x0AEe1FCD12dDFab6265F7f8956e6E012A9Fe4Aa0
COMMON_HOME_GAS_PRICE_SUPPLIER_URL= ORACLE_VALIDATOR_ADDRESS=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9
COMMON_HOME_GAS_PRICE_SUPPLIER_URL=https://gasprice.poa.network/
COMMON_HOME_GAS_PRICE_SPEED_TYPE=standard COMMON_HOME_GAS_PRICE_SPEED_TYPE=standard
COMMON_HOME_GAS_PRICE_FALLBACK=1000000000 COMMON_HOME_GAS_PRICE_FALLBACK=1000000000
ORACLE_HOME_GAS_PRICE_UPDATE_INTERVAL=600000 ORACLE_HOME_GAS_PRICE_UPDATE_INTERVAL=600000
COMMON_HOME_GAS_PRICE_FACTOR=1 COMMON_HOME_GAS_PRICE_FACTOR=1
COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL= COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL=https://gasprice.poa.network/
COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE=standard COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE=standard
COMMON_FOREIGN_GAS_PRICE_FALLBACK=10000000000 COMMON_FOREIGN_GAS_PRICE_FALLBACK=10000000000
ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL=600000 ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL=600000
@ -22,10 +24,3 @@ ORACLE_ALLOW_HTTP_FOR_RPC=yes
ORACLE_HOME_START_BLOCK=1 ORACLE_HOME_START_BLOCK=1
ORACLE_FOREIGN_START_BLOCK=1 ORACLE_FOREIGN_START_BLOCK=1
ORACLE_HOME_TO_FOREIGN_BLOCK_LIST=/mono/oracle/access-lists/block_list.txt ORACLE_HOME_TO_FOREIGN_BLOCK_LIST=/mono/oracle/access-lists/block_list.txt
ORACLE_FOREIGN_ARCHIVE_RPC_URL=http://parity2:8545
ORACLE_HOME_EVENTS_REPROCESSING=false
ORACLE_HOME_EVENTS_REPROCESSING_BATCH_SIZE=10
ORACLE_HOME_EVENTS_REPROCESSING_BLOCK_DELAY=10
ORACLE_FOREIGN_EVENTS_REPROCESSING=true
ORACLE_FOREIGN_EVENTS_REPROCESSING_BATCH_SIZE=10
ORACLE_FOREIGN_EVENTS_REPROCESSING_BLOCK_DELAY=10

View File

@ -4,8 +4,10 @@ ORACLE_QUEUE_URL=amqp://rabbit
ORACLE_REDIS_URL=redis://redis ORACLE_REDIS_URL=redis://redis
COMMON_HOME_RPC_URL=http://parity1:8545 COMMON_HOME_RPC_URL=http://parity1:8545
COMMON_FOREIGN_RPC_URL=http://parity2:8545 COMMON_FOREIGN_RPC_URL=http://parity2:8545
COMMON_HOME_BRIDGE_ADDRESS=0x5118AC62AE912Dd5B51EEfF7338c4fcb0248Ba8c COMMON_HOME_BRIDGE_ADDRESS=0x488Af810997eD1730cB3a3918cD83b3216E6eAda
COMMON_FOREIGN_BRIDGE_ADDRESS=0x32198D570fffC7033641F8A9094FFDCaAEF42624 COMMON_FOREIGN_BRIDGE_ADDRESS=0x488Af810997eD1730cB3a3918cD83b3216E6eAda
ORACLE_VALIDATOR_ADDRESS=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9
COMMON_HOME_GAS_PRICE_SUPPLIER_URL=https://gasprice.poa.network/ COMMON_HOME_GAS_PRICE_SUPPLIER_URL=https://gasprice.poa.network/
COMMON_HOME_GAS_PRICE_SPEED_TYPE=standard COMMON_HOME_GAS_PRICE_SPEED_TYPE=standard
COMMON_HOME_GAS_PRICE_FALLBACK=1 COMMON_HOME_GAS_PRICE_FALLBACK=1
@ -22,9 +24,3 @@ ORACLE_ALLOW_HTTP_FOR_RPC=yes
ORACLE_HOME_START_BLOCK=1 ORACLE_HOME_START_BLOCK=1
ORACLE_FOREIGN_START_BLOCK=1 ORACLE_FOREIGN_START_BLOCK=1
ORACLE_HOME_TO_FOREIGN_BLOCK_LIST=/mono/oracle/access-lists/block_list.txt ORACLE_HOME_TO_FOREIGN_BLOCK_LIST=/mono/oracle/access-lists/block_list.txt
ORACLE_HOME_EVENTS_REPROCESSING=true
ORACLE_HOME_EVENTS_REPROCESSING_BATCH_SIZE=10
ORACLE_HOME_EVENTS_REPROCESSING_BLOCK_DELAY=10
ORACLE_FOREIGN_EVENTS_REPROCESSING=true
ORACLE_FOREIGN_EVENTS_REPROCESSING_BATCH_SIZE=10
ORACLE_FOREIGN_EVENTS_REPROCESSING_BLOCK_DELAY=10

View File

@ -0,0 +1,25 @@
ORACLE_BRIDGE_MODE=ERC_TO_ERC
ORACLE_QUEUE_URL=amqp://rabbit
ORACLE_REDIS_URL=redis://redis
COMMON_HOME_RPC_URL=http://parity1:8545
COMMON_FOREIGN_RPC_URL=http://parity2:8545
COMMON_HOME_BRIDGE_ADDRESS=0x1feB40aD9420b186F019A717c37f5546165d411E
COMMON_FOREIGN_BRIDGE_ADDRESS=0x4a58D6d8D416a5fBCAcf3dC52eb8bE8948E25127
ORACLE_VALIDATOR_ADDRESS=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9
COMMON_HOME_GAS_PRICE_SUPPLIER_URL=https://gasprice.poa.network/
COMMON_HOME_GAS_PRICE_SPEED_TYPE=standard
COMMON_HOME_GAS_PRICE_FALLBACK=1
ORACLE_HOME_GAS_PRICE_UPDATE_INTERVAL=600000
COMMON_HOME_GAS_PRICE_FACTOR=1
COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL=https://gasprice.poa.network/
COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE=standard
COMMON_FOREIGN_GAS_PRICE_FALLBACK=1
ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL=600000
COMMON_FOREIGN_GAS_PRICE_FACTOR=0.1
ORACLE_HOME_RPC_POLLING_INTERVAL=500
ORACLE_FOREIGN_RPC_POLLING_INTERVAL=500
ORACLE_ALLOW_HTTP_FOR_RPC=yes
ORACLE_HOME_START_BLOCK=1
ORACLE_FOREIGN_START_BLOCK=1

View File

@ -0,0 +1,25 @@
ORACLE_BRIDGE_MODE=NATIVE_TO_ERC
ORACLE_QUEUE_URL=amqp://rabbit
ORACLE_REDIS_URL=redis://redis
COMMON_HOME_RPC_URL=http://parity1:8545
COMMON_FOREIGN_RPC_URL=http://parity2:8545
COMMON_HOME_BRIDGE_ADDRESS=0x32198D570fffC7033641F8A9094FFDCaAEF42624
COMMON_FOREIGN_BRIDGE_ADDRESS=0x2B6871b9B02F73fa24F4864322CdC78604207769
ORACLE_VALIDATOR_ADDRESS=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9
COMMON_HOME_GAS_PRICE_SUPPLIER_URL=https://gasprice.poa.network/
COMMON_HOME_GAS_PRICE_SPEED_TYPE=standard
COMMON_HOME_GAS_PRICE_FALLBACK=1
ORACLE_HOME_GAS_PRICE_UPDATE_INTERVAL=600000
COMMON_HOME_GAS_PRICE_FACTOR=1
COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL=https://gasprice.poa.network/
COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE=standard
COMMON_FOREIGN_GAS_PRICE_FALLBACK=1
ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL=600000
COMMON_FOREIGN_GAS_PRICE_FACTOR=0.1
ORACLE_HOME_RPC_POLLING_INTERVAL=500
ORACLE_FOREIGN_RPC_POLLING_INTERVAL=500
ORACLE_ALLOW_HTTP_FOR_RPC=yes
ORACLE_HOME_START_BLOCK=1
ORACLE_FOREIGN_START_BLOCK=1

View File

@ -35,26 +35,34 @@
"address": "0xB4579fd5AfEaB60B03Db3F408AAdD315035943f7", "address": "0xB4579fd5AfEaB60B03Db3F408AAdD315035943f7",
"privateKey": "0xd6143d390d8b28c33601bb0fe29392fb1c35c24ccfe8722c09c2bdd6ada2699f" "privateKey": "0xd6143d390d8b28c33601bb0fe29392fb1c35c24ccfe8722c09c2bdd6ada2699f"
}, },
"nativeToErcBridge": {
"home": "0x32198D570fffC7033641F8A9094FFDCaAEF42624",
"foreign": "0x2B6871b9B02F73fa24F4864322CdC78604207769",
"foreignToken": "0xdbeE25CbE97e4A5CC6c499875774dc7067E9426B",
"monitor": "http://monitor:3010/bridge"
},
"ercToErcBridge": {
"home": "0x1feB40aD9420b186F019A717c37f5546165d411E",
"foreign": "0x4a58D6d8D416a5fBCAcf3dC52eb8bE8948E25127",
"homeToken": "0x792455a6bCb62Ed4C4362D323E0590654CA4765c",
"foreignToken": "0x3C665A31199694Bf723fD08844AD290207B5797f",
"monitor": "http://monitor-erc20:3011/bridge"
},
"ercToNativeBridge": { "ercToNativeBridge": {
"home": "0x5118AC62AE912Dd5B51EEfF7338c4fcb0248Ba8c", "home": "0x488Af810997eD1730cB3a3918cD83b3216E6eAda",
"foreign": "0x32198D570fffC7033641F8A9094FFDCaAEF42624", "foreign": "0x488Af810997eD1730cB3a3918cD83b3216E6eAda",
"foreignToken": "0x6B175474E89094C44Da98b954EedeAC495271d0F", "foreignToken": "0x7cc4b1851c35959d34e635a470f6b5c43ba3c9c9",
"chaiToken": "0x06af07097c9eeb7fd685c692751d5c66db49c215",
"monitor": "http://monitor-erc20-native:3012/bridge" "monitor": "http://monitor-erc20-native:3012/bridge"
}, },
"amb": { "amb": {
"home": "0x8397be90BCF57b0B71219f555Fe121b22e5a994C", "home": "0x0AEe1FCD12dDFab6265F7f8956e6E012A9Fe4Aa0",
"foreign": "0x1feB40aD9420b186F019A717c37f5546165d411E", "foreign": "0x0AEe1FCD12dDFab6265F7f8956e6E012A9Fe4Aa0",
"homeBox": "0xb008E9076fCbDB2C3AF84225Bc07Eb35B2bE5ECD", "homeBox": "0x6C4EaAb8756d53Bf599FFe2347FAFF1123D6C8A1",
"foreignBox": "0x4a58D6d8D416a5fBCAcf3dC52eb8bE8948E25127", "foreignBox": "0x6C4EaAb8756d53Bf599FFe2347FAFF1123D6C8A1",
"blockedHomeBox": "0xF9698Eb93702dfdd0e2d802088d4c21822a8A977", "blockedHomeBox": "0x6f359aC418a5f7538F7755A33C9c7dDf38785524",
"monitor": "http://monitor-amb:3013/bridge" "monitor": "http://monitor-amb:3013/bridge"
}, },
"amb2": {
"home": "0x5A42E119990c3F3A80Fea20aAF4c3Ff4DB240Cc9",
"foreign": "0x897527391ad3837604973d78D3514f44c36AB9FC",
"homeBox": "0xb008E9076fCbDB2C3AF84225Bc07Eb35B2bE5ECD",
"foreignBox": "0x4a58D6d8D416a5fBCAcf3dC52eb8bE8948E25127"
},
"homeRPC": { "homeRPC": {
"URL": "http://parity1:8545", "URL": "http://parity1:8545",
"ID": "77" "ID": "77"

View File

@ -9,7 +9,7 @@ HOME_RPC_URL=http://parity1:8545
HOME_BRIDGE_OWNER=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b HOME_BRIDGE_OWNER=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
HOME_VALIDATORS_OWNER=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b HOME_VALIDATORS_OWNER=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
HOME_UPGRADEABLE_ADMIN=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b HOME_UPGRADEABLE_ADMIN=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
HOME_MAX_AMOUNT_PER_TX=2000000 HOME_MAX_AMOUNT_PER_TX=8000000
HOME_REQUIRED_BLOCK_CONFIRMATIONS=1 HOME_REQUIRED_BLOCK_CONFIRMATIONS=1
HOME_GAS_PRICE=1000000000 HOME_GAS_PRICE=1000000000
@ -17,7 +17,7 @@ FOREIGN_RPC_URL=http://parity2:8545
FOREIGN_BRIDGE_OWNER=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b FOREIGN_BRIDGE_OWNER=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
FOREIGN_VALIDATORS_OWNER=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b FOREIGN_VALIDATORS_OWNER=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
FOREIGN_UPGRADEABLE_ADMIN=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b FOREIGN_UPGRADEABLE_ADMIN=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
FOREIGN_MAX_AMOUNT_PER_TX=2000000 FOREIGN_MAX_AMOUNT_PER_TX=8000000
FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS=1 FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS=1
FOREIGN_GAS_PRICE=10000000000 FOREIGN_GAS_PRICE=10000000000

View File

@ -0,0 +1,40 @@
BRIDGE_MODE=ERC_TO_ERC
DEPLOYMENT_ACCOUNT_PRIVATE_KEY=8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9
HOME_DEPLOYMENT_GAS_PRICE=10000000000
FOREIGN_DEPLOYMENT_GAS_PRICE=10000000000
GET_RECEIPT_INTERVAL_IN_MILLISECONDS=50
DEPLOYMENT_GAS_LIMIT_EXTRA=0.2
DEPLOY_REWARDABLE_TOKEN=false
BRIDGEABLE_TOKEN_NAME="Your New Bridged Token"
BRIDGEABLE_TOKEN_SYMBOL="TEST"
BRIDGEABLE_TOKEN_DECIMALS="18"
HOME_RPC_URL=http://parity1:8545
HOME_BRIDGE_OWNER=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
HOME_VALIDATORS_OWNER=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
HOME_UPGRADEABLE_ADMIN=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
HOME_DAILY_LIMIT=30000000000000000000000000
HOME_MAX_AMOUNT_PER_TX=1500000000000000000000000
HOME_MIN_AMOUNT_PER_TX=10000000000000000
HOME_REQUIRED_BLOCK_CONFIRMATIONS=1
HOME_GAS_PRICE=1000000000
HOME_REWARDABLE=false
FOREIGN_RPC_URL=http://parity2:8545
FOREIGN_BRIDGE_OWNER=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
FOREIGN_VALIDATORS_OWNER=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
FOREIGN_UPGRADEABLE_ADMIN=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
FOREIGN_DAILY_LIMIT=15000000000000000000000000
FOREIGN_MAX_AMOUNT_PER_TX=750000000000000000000000
FOREIGN_MIN_AMOUNT_PER_TX=10000000000000000
FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS=1
FOREIGN_GAS_PRICE=10000000000
FOREIGN_REWARDABLE=false
ERC20_TOKEN_ADDRESS=0x3C665A31199694Bf723fD08844AD290207B5797f
REQUIRED_NUMBER_OF_VALIDATORS=1
VALIDATORS="0xaaB52d66283F7A1D5978bcFcB55721ACB467384b 0xdCC784657C78054aa61FbcFFd2605F32374816A4 0xDcef88209a20D52165230104B245803C3269454d"
BLOCK_REWARD_ADDRESS=0x0000000000000000000000000000000000000000
DPOS_STAKING_ADDRESS=0x0000000000000000000000000000000000000000
ERC20_EXTENDED_BY_ERC677=false

View File

@ -31,8 +31,8 @@ FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS=1
FOREIGN_GAS_PRICE=10000000000 FOREIGN_GAS_PRICE=10000000000
FOREIGN_REWARDABLE=false FOREIGN_REWARDABLE=false
BLOCK_REWARD_ADDRESS=0xdbeE25CbE97e4A5CC6c499875774dc7067E9426B BLOCK_REWARD_ADDRESS=0xF9698Eb93702dfdd0e2d802088d4c21822a8A977
ERC20_TOKEN_ADDRESS=0x6B175474E89094C44Da98b954EedeAC495271d0F ERC20_TOKEN_ADDRESS=0x7cc4b1851c35959d34e635a470f6b5c43ba3c9c9
REQUIRED_NUMBER_OF_VALIDATORS=1 REQUIRED_NUMBER_OF_VALIDATORS=1
VALIDATORS="0xaaB52d66283F7A1D5978bcFcB55721ACB467384b 0xdCC784657C78054aa61FbcFFd2605F32374816A4 0xDcef88209a20D52165230104B245803C3269454d" VALIDATORS="0xaaB52d66283F7A1D5978bcFcB55721ACB467384b 0xdCC784657C78054aa61FbcFFd2605F32374816A4 0xDcef88209a20D52165230104B245803C3269454d"

View File

@ -0,0 +1,38 @@
BRIDGE_MODE=NATIVE_TO_ERC
DEPLOYMENT_ACCOUNT_ADDRESS=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
DEPLOYMENT_ACCOUNT_PRIVATE_KEY=8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9
HOME_DEPLOYMENT_GAS_PRICE=10000000000
FOREIGN_DEPLOYMENT_GAS_PRICE=10000000000
GET_RECEIPT_INTERVAL_IN_MILLISECONDS=50
DEPLOYMENT_GAS_LIMIT_EXTRA=0.2
DEPLOY_REWARDABLE_TOKEN=false
BRIDGEABLE_TOKEN_NAME="Your New Bridged Token"
BRIDGEABLE_TOKEN_SYMBOL="TEST"
BRIDGEABLE_TOKEN_DECIMALS="18"
HOME_RPC_URL=http://parity1:8545
HOME_BRIDGE_OWNER=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
HOME_VALIDATORS_OWNER=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
HOME_UPGRADEABLE_ADMIN=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
HOME_DAILY_LIMIT=30000000000000000000000000
HOME_MAX_AMOUNT_PER_TX=1500000000000000000000000
HOME_MIN_AMOUNT_PER_TX=10000000000000000
HOME_REQUIRED_BLOCK_CONFIRMATIONS=1
HOME_GAS_PRICE=1000000000
HOME_REWARDABLE=false
FOREIGN_RPC_URL=http://parity2:8545
FOREIGN_BRIDGE_OWNER=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
FOREIGN_VALIDATORS_OWNER=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
FOREIGN_UPGRADEABLE_ADMIN=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
FOREIGN_DAILY_LIMIT=15000000000000000000000000
FOREIGN_MAX_AMOUNT_PER_TX=750000000000000000000000
FOREIGN_MIN_AMOUNT_PER_TX=10000000000000000
FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS=1
FOREIGN_GAS_PRICE=10000000000
FOREIGN_REWARDABLE=false
REQUIRED_NUMBER_OF_VALIDATORS=1
VALIDATORS="0xaaB52d66283F7A1D5978bcFcB55721ACB467384b 0xdCC784657C78054aa61FbcFFd2605F32374816A4 0xDcef88209a20D52165230104B245803C3269454d"
BLOCK_REWARD_ADDRESS=0x0000000000000000000000000000000000000000

View File

@ -27,6 +27,25 @@ services:
image: "rabbitmq:3-management" image: "rabbitmq:3-management"
networks: networks:
- ultimate - ultimate
oracle:
image: ${DOCKER_IMAGE_BASE:-tokenbridge}/tokenbridge-e2e-oracle:${ORACLE_TAG:-local}
build:
context: ..
dockerfile: oracle/Dockerfile
env_file: ../e2e-commons/components-envs/oracle.env
environment:
- NODE_ENV=production
command: "true"
networks:
- ultimate
oracle-erc20:
image: ${DOCKER_IMAGE_BASE:-tokenbridge}/tokenbridge-e2e-oracle:${ORACLE_TAG:-local}
env_file: ../e2e-commons/components-envs/oracle-erc20.env
environment:
- NODE_ENV=production
command: "true"
networks:
- ultimate
oracle-erc20-native: oracle-erc20-native:
image: ${DOCKER_IMAGE_BASE:-tokenbridge}/tokenbridge-e2e-oracle:${ORACLE_TAG:-local} image: ${DOCKER_IMAGE_BASE:-tokenbridge}/tokenbridge-e2e-oracle:${ORACLE_TAG:-local}
env_file: ../e2e-commons/components-envs/oracle-erc20-native.env env_file: ../e2e-commons/components-envs/oracle-erc20-native.env
@ -40,9 +59,6 @@ services:
- ultimate - ultimate
oracle-amb: oracle-amb:
image: ${DOCKER_IMAGE_BASE:-tokenbridge}/tokenbridge-e2e-oracle:${ORACLE_TAG:-local} image: ${DOCKER_IMAGE_BASE:-tokenbridge}/tokenbridge-e2e-oracle:${ORACLE_TAG:-local}
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
@ -62,6 +78,25 @@ services:
command: "true" command: "true"
networks: networks:
- ultimate - ultimate
monitor:
image: ${DOCKER_IMAGE_BASE:-tokenbridge}/tokenbridge-e2e-monitor:${MONITOR_TAG:-local}
build:
context: ..
dockerfile: monitor/Dockerfile
env_file: ../e2e-commons/components-envs/monitor.env
entrypoint: yarn check-and-start
ports:
- "3010:3010"
networks:
- ultimate
monitor-erc20:
image: ${DOCKER_IMAGE_BASE:-tokenbridge}/tokenbridge-e2e-monitor:${MONITOR_TAG:-local}
env_file: ../e2e-commons/components-envs/monitor-erc20.env
entrypoint: yarn check-and-start
ports:
- "3011:3011"
networks:
- ultimate
monitor-erc20-native: monitor-erc20-native:
image: ${DOCKER_IMAGE_BASE:-tokenbridge}/tokenbridge-e2e-monitor:${MONITOR_TAG:-local} image: ${DOCKER_IMAGE_BASE:-tokenbridge}/tokenbridge-e2e-monitor:${MONITOR_TAG:-local}
env_file: ../e2e-commons/components-envs/monitor-erc20-native.env env_file: ../e2e-commons/components-envs/monitor-erc20-native.env
@ -72,9 +107,6 @@ services:
- ultimate - ultimate
monitor-amb: monitor-amb:
image: ${DOCKER_IMAGE_BASE:-tokenbridge}/tokenbridge-e2e-monitor:${MONITOR_TAG:-local} image: ${DOCKER_IMAGE_BASE:-tokenbridge}/tokenbridge-e2e-monitor:${MONITOR_TAG:-local}
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:

View File

@ -1,37 +1,10 @@
#!/usr/bin/env bash #!/usr/bin/env bash
cd $(dirname $0) cd $(dirname $0)
if [ $CI ]; then if [ $CI ]; then exit $rc; fi
rm -rf logs || true
mkdir ./logs
for project in "" validator{1,2,3}; do
for container in $(docker-compose -p "$project" ps | tail -n +3 | awk '{print $1}') ; do
if [[ -z "$project" ]]; then
path="./logs/$container.log"
else
mkdir -p "./logs/$project"
path="./logs/$project/$container.log"
fi
docker logs "$container" > "$path" 2>&1
done
done
touch ../oracle/.env
for file in ../oracle/docker-compose-{amb,transfer}.yml; do
for container in $(docker-compose -f "$file" ps | tail -n +3 | awk '{print $1}') ; do
mkdir -p "./logs/oracle"
docker logs "$container" > "./logs/oracle/$container.log" 2>&1
done
done
exit $rc;
fi
ps | grep node | grep -v grep | grep -v yarn | awk '{print "kill " $1}' | /bin/bash ps | grep node | grep -v grep | grep -v yarn | awk '{print "kill " $1}' | /bin/bash
docker-compose down docker-compose down
docker-compose -p validator1 down
docker-compose -p validator2 down docker-compose -p validator2 down
docker-compose -p validator3 down docker-compose -p validator3 down
docker network rm ultimate || true docker network rm ultimate || true

View File

@ -5,11 +5,9 @@ set -e # exit when any command fails
docker-compose pull e2e docker-compose pull e2e
while [ "$1" != "" ]; do while [ "$1" != "" ]; do
if [ "$1" == "oracle" ]; then if [ "$1" == "oracle" ]; then
docker-compose pull oracle-amb docker-compose pull oracle
elif [ "$1" == "alm-e2e" ]; then
docker-compose pull oracle-amb
elif [ "$1" == "monitor" ]; then elif [ "$1" == "monitor" ]; then
docker-compose pull monitor-amb docker-compose pull monitor
elif [ "$1" == "alm" ]; then elif [ "$1" == "alm" ]; then
docker-compose pull alm docker-compose pull alm
fi fi

View File

@ -9,13 +9,26 @@ ENVS_PATH="../contracts-envs"
# mock bridge validators contract with the one with deterministic isValidatorDuty # mock bridge validators contract with the one with deterministic isValidatorDuty
mv "$CONTRACTS_PATH/build/contracts/BridgeValidatorsDeterministic.json" "$CONTRACTS_PATH/build/contracts/BridgeValidators.json" mv "$CONTRACTS_PATH/build/contracts/BridgeValidatorsDeterministic.json" "$CONTRACTS_PATH/build/contracts/BridgeValidators.json"
echo -e "\n\n############ Deploying native-to-erc ############\n"
cp "$ENVS_PATH/native-to-erc.env" "$DEPLOY_PATH/.env"
cd "$DEPLOY_PATH"
node deploy.js
cd - > /dev/null
echo -e "\n\n############ Deploying erc20 and erc-to-erc ############\n"
node deployERC20.js
cp "$ENVS_PATH/erc-to-erc.env" "$DEPLOY_PATH/.env"
cd "$DEPLOY_PATH"
node deploy.js
cd - > /dev/null
echo -e "\n\n############ Deploying block reward ############\n" echo -e "\n\n############ Deploying block reward ############\n"
cp "$ENVS_PATH/erc-to-native.env" "$DEPLOY_PATH/.env"
cd "$DEPLOY_PATH" cd "$DEPLOY_PATH"
node src/utils/deployBlockReward.js node src/utils/deployBlockReward.js
cd - > /dev/null cd - > /dev/null
echo -e "\n\n############ Deploying erc-to-native ############\n" echo -e "\n\n############ Deploying erc-to-native ############\n"
cp "$ENVS_PATH/erc-to-native.env" "$DEPLOY_PATH/.env"
cd "$DEPLOY_PATH" cd "$DEPLOY_PATH"
node deploy.js node deploy.js
cd - > /dev/null cd - > /dev/null
@ -35,9 +48,3 @@ echo -e "\n\n############ Deploying one more test contract for amb ############\
cd "$DEPLOY_PATH" cd "$DEPLOY_PATH"
node src/utils/deployTestBox.js node src/utils/deployTestBox.js
cd - > /dev/null cd - > /dev/null
echo -e "\n\n############ Deploying one more amb without oracle for confirm relay tests ############\n"
cp "$ENVS_PATH/amb.env" "$DEPLOY_PATH/.env"
cd "$DEPLOY_PATH"
node deploy.js
cd - > /dev/null

View File

@ -0,0 +1,43 @@
const path = require('path')
const { user } = require('../constants.json')
const contractsPath = '../../contracts'
require('dotenv').config({
path: path.join(__dirname, contractsPath, '/deploy/.env')
})
const { deployContract, sendRawTxHome, privateKeyToAddress } = require(`${contractsPath}/deploy/src/deploymentUtils`)
const { web3Home, deploymentPrivateKey } = require(`${contractsPath}/deploy/src/web3`)
const ERC677BridgeTokenRewardable = require(`${contractsPath}/build/contracts/ERC677BridgeTokenRewardable.json`)
const { DEPLOYMENT_ACCOUNT_PRIVATE_KEY } = process.env
const DEPLOYMENT_ACCOUNT_ADDRESS = privateKeyToAddress(DEPLOYMENT_ACCOUNT_PRIVATE_KEY)
async function deployBridgeTokenRewardable() {
try {
let homeNonce = await web3Home.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS)
console.log('\n[Home] Deploying ERC677BridgeTokenRewardable Test token')
const stakeToken = await deployContract(ERC677BridgeTokenRewardable, ['STAKE', 'STAKE', '18', '77'], {
from: DEPLOYMENT_ACCOUNT_ADDRESS,
network: 'home',
nonce: homeNonce
})
homeNonce++
console.log('[Home] Stake Token: ', stakeToken.options.address)
const mintData = await stakeToken.methods
.mint(user.address, '500000000000000000000')
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
await sendRawTxHome({
data: mintData,
nonce: homeNonce,
to: stakeToken.options.address,
privateKey: deploymentPrivateKey,
url: process.env.HOME_RPC_URL
})
} catch (e) {
console.log(e)
throw e
}
}
deployBridgeTokenRewardable()

View File

@ -0,0 +1,51 @@
/* eslint import/no-unresolved: 0 node/no-missing-require: 0 */
const path = require('path')
const {user} = require('../constants.json')
const contractsPath = '../../contracts';
require('dotenv').config({
path: path.join(__dirname, contractsPath, '/deploy/.env')
})
const {
deployContract,
sendRawTxForeign,
privateKeyToAddress
} = require(`${contractsPath}/deploy/src/deploymentUtils`)
const {
web3Foreign,
deploymentPrivateKey
} = require(`${contractsPath}/deploy/src/web3`)
const POA20 = require(`${contractsPath}/build/contracts/ERC677BridgeToken.json`)
const { DEPLOYMENT_ACCOUNT_PRIVATE_KEY } = process.env
const DEPLOYMENT_ACCOUNT_ADDRESS = privateKeyToAddress(DEPLOYMENT_ACCOUNT_PRIVATE_KEY)
async function deployErc20() {
try {
let foreignNonce = await web3Foreign.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS)
console.log('\n[Foreign] Deploying POA20 Test token')
const poa20foreign = await deployContract(POA20, ['POA ERC20 Test', 'POA20', 18], {
from: DEPLOYMENT_ACCOUNT_ADDRESS,
network: 'foreign',
nonce: foreignNonce
})
foreignNonce++
console.log('[Foreign] POA20 Test: ', poa20foreign.options.address)
const mintData = await poa20foreign.methods
.mint(user.address, '500000000000000000000')
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
await sendRawTxForeign({
data: mintData,
nonce: foreignNonce,
to: poa20foreign.options.address,
privateKey: deploymentPrivateKey,
url: process.env.FOREIGN_RPC_URL
})
} catch (e) {
console.log(e)
throw e;
}
}
deployErc20()

View File

@ -0,0 +1,43 @@
const path = require('path')
const { user } = require('../constants.json')
const contractsPath = '../../contracts'
require('dotenv').config({
path: path.join(__dirname, contractsPath, '/deploy/.env')
})
const { deployContract, sendRawTxForeign, privateKeyToAddress } = require(`${contractsPath}/deploy/src/deploymentUtils`)
const { web3Foreign, deploymentPrivateKey } = require(`${contractsPath}/deploy/src/web3`)
const ERC677MultiBridgeToken = require(`${contractsPath}/build/contracts/ERC677MultiBridgeToken.json`)
const { DEPLOYMENT_ACCOUNT_PRIVATE_KEY } = process.env
const DEPLOYMENT_ACCOUNT_ADDRESS = privateKeyToAddress(DEPLOYMENT_ACCOUNT_PRIVATE_KEY)
async function deployMultiBridgeToken() {
try {
let foreignNonce = await web3Foreign.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS)
console.log('\n[Foreign] Deploying ERC677MultiBridgeToken Test token')
const stakeToken = await deployContract(ERC677MultiBridgeToken, ['STAKE', 'STAKE', '18', '42'], {
from: DEPLOYMENT_ACCOUNT_ADDRESS,
network: 'foreign',
nonce: foreignNonce
})
foreignNonce++
console.log('[Foreign] Stake Token: ', stakeToken.options.address)
const mintData = await stakeToken.methods
.mint(user.address, '500000000000000000000')
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
await sendRawTxForeign({
data: mintData,
nonce: foreignNonce,
to: stakeToken.options.address,
privateKey: deploymentPrivateKey,
url: process.env.FOREIGN_RPC_URL
})
} catch (e) {
console.log(e)
throw e
}
}
deployMultiBridgeToken()

View File

@ -15,46 +15,64 @@ docker network create --driver bridge ultimate || true
docker-compose up -d parity1 parity2 e2e docker-compose up -d parity1 parity2 e2e
startValidator () { startValidator () {
db_env="-e ORACLE_QUEUE_URL=amqp://$3 -e ORACLE_REDIS_URL=redis://$2" docker-compose $1 run -d --name $4 redis
docker-compose $1 run -d --name $5 rabbit
docker-compose $1 run -d --name $2 redis if [[ -z "$MODE" || "$MODE" == native-to-erc ]]; then
docker-compose $1 run -d --name $3 rabbit docker-compose $1 run $2 $3 -d oracle yarn watcher:signature-request
docker-compose $1 run $2 $3 -d oracle yarn watcher:collected-signatures
docker-compose $1 run $2 $3 -d oracle yarn watcher:affirmation-request
fi
if [[ -z "$MODE" || "$MODE" == erc-to-erc ]]; then
docker-compose $1 run $2 $3 -d oracle-erc20 yarn watcher:signature-request
docker-compose $1 run $2 $3 -d oracle-erc20 yarn watcher:collected-signatures
docker-compose $1 run $2 $3 -d oracle-erc20 yarn watcher:affirmation-request
docker-compose $1 run $2 $3 -d oracle-erc20 yarn watcher:transfer
fi
if [[ -z "$MODE" || "$MODE" == erc-to-native ]]; then if [[ -z "$MODE" || "$MODE" == erc-to-native ]]; then
docker-compose $1 run $oraclePK $db_env -d oracle-erc20-native yarn watcher:signature-request docker-compose $1 run $2 $3 -d oracle-erc20-native yarn watcher:signature-request
docker-compose $1 run $oracleAddr $db_env -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 $oracleAddr $db_env -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 $oracleAddr $db_env -d oracle-erc20-native yarn watcher:transfer docker-compose $1 run $2 $3 -d oracle-erc20-native yarn watcher:transfer
docker-compose $1 run $2 $3 -d oracle-erc20-native yarn worker:convert-to-chai
fi fi
if [[ -z "$MODE" || "$MODE" == amb ]]; then if [[ -z "$MODE" || "$MODE" == amb ]]; then
docker-compose $1 run $oraclePK $db_env -d oracle-amb yarn watcher:signature-request docker-compose $1 run $2 $3 -d oracle-amb yarn watcher:signature-request
docker-compose $1 run $oracleAddr $db_env -d oracle-amb yarn watcher:collected-signatures docker-compose $1 run $2 $3 -d oracle-amb yarn watcher:collected-signatures
docker-compose $1 run $oracleAddr $db_env -d oracle-amb yarn watcher:affirmation-request docker-compose $1 run $2 $3 -d oracle-amb yarn watcher:affirmation-request
docker-compose $1 run $oracleAddr $db_env -d oracle-amb yarn watcher:information-request
fi fi
docker-compose $1 run $2 $3 -d oracle-erc20-native yarn sender:home
docker-compose $1 run $2 $3 -d oracle-erc20-native yarn sender:foreign
docker-compose $1 run $2 $3 -d oracle yarn manager:shutdown
}
docker-compose $1 run $oraclePK $db_env -d oracle-amb yarn sender:home startAMBValidator () {
docker-compose $1 run $oraclePK $db_env -d oracle-amb yarn sender:foreign docker-compose $1 run -d --name $4 redis
docker-compose $1 run $oracleAddr $db_env -d oracle-amb yarn manager:shutdown docker-compose $1 run -d --name $5 rabbit
docker-compose $1 run $2 $3 -d oracle-amb yarn watcher:signature-request
docker-compose $1 run $2 $3 -d oracle-amb yarn watcher:collected-signatures
docker-compose $1 run $2 $3 -d oracle-amb yarn watcher:affirmation-request
docker-compose $1 run $2 $3 -d oracle-amb yarn sender:home
docker-compose $1 run $2 $3 -d oracle-amb yarn sender:foreign
docker-compose $1 run $2 $3 -d oracle-amb yarn manager:shutdown
} }
while [ "$1" != "" ]; do while [ "$1" != "" ]; do
if [ "$1" == "oracle" ]; then if [ "$1" == "oracle" ]; then
oracleAddr="-e ORACLE_VALIDATOR_ADDRESS=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b" startValidator "" "" "" "redis" "rabbit"
oraclePK="-e ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
startValidator "-p validator1" redis rabbit
fi fi
if [ "$1" == "oracle-validator-2" ]; then if [ "$1" == "oracle-validator-2" ]; then
oracleAddr="-e ORACLE_VALIDATOR_ADDRESS=0xdCC784657C78054aa61FbcFFd2605F32374816A4" oracle2name="-p validator2"
oraclePK="-e ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=5a5c3645d0f04e9eb4f27f94ed4c244a225587405b8838e7456f7781ce3a9513" oracle2Values="-e ORACLE_VALIDATOR_ADDRESS=0xdCC784657C78054aa61FbcFFd2605F32374816A4 -e ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=5a5c3645d0f04e9eb4f27f94ed4c244a225587405b8838e7456f7781ce3a9513"
startValidator "-p validator2" redis2 rabbit2 oracle2comp="-e ORACLE_QUEUE_URL=amqp://rabbit2 -e ORACLE_REDIS_URL=redis://redis2"
startValidator "$oracle2name" "$oracle2Values" "$oracle2comp" "redis2" "rabbit2"
fi fi
if [ "$1" == "oracle-validator-3" ]; then if [ "$1" == "oracle-validator-3" ]; then
oracleAddr="-e ORACLE_VALIDATOR_ADDRESS=0xDcef88209a20D52165230104B245803C3269454d" oracle3name="-p validator3"
oraclePK="-e ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=f877f62a1c19f852cff1d29f0fb1ecac18821c0080d4cc0520c60c098293dca1" oracle3Values="-e ORACLE_VALIDATOR_ADDRESS=0xDcef88209a20D52165230104B245803C3269454d -e ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=f877f62a1c19f852cff1d29f0fb1ecac18821c0080d4cc0520c60c098293dca1"
startValidator "-p validator3" redis3 rabbit3 oracle3comp="-e ORACLE_QUEUE_URL=amqp://rabbit3 -e ORACLE_REDIS_URL=redis://redis3"
startValidator "$oracle3name" "$oracle3Values" "$oracle3comp" "redis3" "rabbit3"
fi fi
if [ "$1" == "alm" ]; then if [ "$1" == "alm" ]; then
@ -76,50 +94,33 @@ while [ "$1" != "" ]; do
amb) amb)
docker-compose up -d monitor-amb docker-compose up -d monitor-amb
;; ;;
native-to-erc)
docker-compose up -d monitor
;;
erc-to-erc)
docker-compose up -d monitor-erc20
;;
erc-to-native) erc-to-native)
docker-compose up -d monitor-erc20-native docker-compose up -d monitor-erc20-native
;; ;;
*) *)
docker-compose up -d monitor-erc20-native monitor-amb docker-compose up -d monitor monitor-erc20 monitor-erc20-native monitor-amb
;; ;;
esac esac
fi fi
if [ "$1" == "alm-e2e" ]; then if [ "$1" == "alm-e2e" ]; then
MODE=amb startAMBValidator "" "" "" "redis" "rabbit"
oracleAddr="-e ORACLE_VALIDATOR_ADDRESS=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b" oracle2name="-p validator2"
oraclePK="-e ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9" oracle2Values="-e ORACLE_VALIDATOR_ADDRESS=0xdCC784657C78054aa61FbcFFd2605F32374816A4 -e ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=5a5c3645d0f04e9eb4f27f94ed4c244a225587405b8838e7456f7781ce3a9513"
startValidator "-p validator1" redis rabbit oracle2comp="-e ORACLE_QUEUE_URL=amqp://rabbit2 -e ORACLE_REDIS_URL=redis://redis2"
startAMBValidator "$oracle2name" "$oracle2Values" "$oracle2comp" "redis2" "rabbit2"
oracleAddr="-e ORACLE_VALIDATOR_ADDRESS=0xdCC784657C78054aa61FbcFFd2605F32374816A4" oracle3name="-p validator3"
oraclePK="-e ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=5a5c3645d0f04e9eb4f27f94ed4c244a225587405b8838e7456f7781ce3a9513" oracle3Values="-e ORACLE_VALIDATOR_ADDRESS=0xDcef88209a20D52165230104B245803C3269454d -e ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=f877f62a1c19f852cff1d29f0fb1ecac18821c0080d4cc0520c60c098293dca1"
startValidator "-p validator2" redis2 rabbit2 oracle3comp="-e ORACLE_QUEUE_URL=amqp://rabbit3 -e ORACLE_REDIS_URL=redis://redis3"
startAMBValidator "$oracle3name" "$oracle3Values" "$oracle3comp" "redis3" "rabbit3"
oracleAddr="-e ORACLE_VALIDATOR_ADDRESS=0xDcef88209a20D52165230104B245803C3269454d"
oraclePK="-e ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=f877f62a1c19f852cff1d29f0fb1ecac18821c0080d4cc0520c60c098293dca1"
startValidator "-p validator3" redis3 rabbit3
fi
if [ "$1" == "generate-amb-tx" ]; then
docker-compose run e2e yarn workspace oracle-e2e run generate-amb-tx
fi
if [ "$1" == "manual-amb-relay" ]; then
oraclePK="-e ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
env="-e COMMON_HOME_BRIDGE_ADDRESS=0x5A42E119990c3F3A80Fea20aAF4c3Ff4DB240Cc9 -e COMMON_FOREIGN_BRIDGE_ADDRESS=0x897527391ad3837604973d78D3514f44c36AB9FC"
# these tx hash are hardcoded and need to be updated manually
# once e2e environment setup process is changed
echo '0xea625a823bc5018dc3a4efe349f623e5ebb8c987b55f44d50d6556f42af9a400' > txHashes.txt
docker-compose -p validator1 run -v $(pwd)/txHashes.txt:/tmp/txHashes.txt $oraclePK $env oracle-amb yarn confirm:affirmation-request \
/tmp/txHashes.txt \
0x031c42e44485002c9215a5b1b75e9516131485ce29884a58765bf7a0038538f9
docker-compose -p validator1 run $oraclePK $env oracle-amb yarn confirm:signature-request \
0x1506a18af91afe732167ccbc178b55fc2547da4a814d13c015b6f496cf171754 | tee .tmp.log
tx_hash=$(cat .tmp.log | grep generatedTransactionHash | jq -r .generatedTransactionHash)
rm .tmp.log
rm txHashes.txt
docker-compose -p validator1 run $oraclePK $env oracle-amb yarn confirm:collected-signatures $tx_hash
fi fi
shift # Shift all the parameters down by one shift # Shift all the parameters down by one

View File

@ -4,7 +4,7 @@
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"start": "mocha --timeout 120000 --exit", "start": "mocha --timeout 120000",
"lint": "eslint . --ignore-path ../.eslintignore" "lint": "eslint . --ignore-path ../.eslintignore"
}, },
"author": "", "author": "",
@ -14,7 +14,7 @@
"axios": "0.19.0" "axios": "0.19.0"
}, },
"engines": { "engines": {
"node": ">= 12.22" "node": ">= 10.18"
}, },
"devDependencies": {} "devDependencies": {}
} }

View File

@ -1,9 +1,15 @@
while true; do while true; do
docker-compose -f ../e2e-commons/docker-compose.yml exec -T monitor-erc20-native yarn check-all docker-compose -f ../e2e-commons/docker-compose.yml exec -T monitor yarn check-all
pid1=$! pid1=$!
docker-compose -f ../e2e-commons/docker-compose.yml exec -T monitor-amb yarn check-all docker-compose -f ../e2e-commons/docker-compose.yml exec -T monitor-erc20 yarn check-all
pid2=$! pid2=$!
docker-compose -f ../e2e-commons/docker-compose.yml exec -T monitor-erc20-native yarn check-all
pid3=$!
docker-compose -f ../e2e-commons/docker-compose.yml exec -T monitor-amb yarn check-all
pid4=$!
wait $pid1 wait $pid1
wait $pid2 wait $pid2
wait $pid3
wait $pid4
done done

View File

@ -5,6 +5,12 @@ case "$mode" in
amb) amb)
script=./test/amb.js script=./test/amb.js
;; ;;
native-to-erc)
script=./test/nativeToErc.js
;;
erc-to-erc)
script=./test/ercToErc.js
;;
erc-to-native) erc-to-native)
script=./test/ercToNative.js script=./test/ercToNative.js
;; ;;

View File

@ -1,8 +1,12 @@
const assert = require('assert') const assert = require('assert')
const axios = require('axios') const axios = require('axios')
const { ercToNativeBridge, validator } = require('../../e2e-commons/constants.json') const { nativeToErcBridge, ercToErcBridge, ercToNativeBridge, validator } = require('../../e2e-commons/constants.json')
const types = [{ description: 'ERC TO NATIVE', baseUrl: ercToNativeBridge.monitor }] const types = [
{ description: 'NATIVE TO ERC', baseUrl: nativeToErcBridge.monitor },
{ description: 'ERC TO ERC', baseUrl: ercToErcBridge.monitor },
{ description: 'ERC TO NATIVE', baseUrl: ercToNativeBridge.monitor }
]
types.forEach(type => { types.forEach(type => {
describe(type.description, () => { describe(type.description, () => {

View File

@ -0,0 +1,43 @@
const assert = require('assert')
const axios = require('axios')
const { ercToErcBridge, user, foreignRPC, validator } = require('../../e2e-commons/constants.json')
const { waitUntil, sendTokens, addValidator } = require('../utils')
const baseUrl = ercToErcBridge.monitor
describe('ERC TO ERC', () => {
let data
before(async () => {
;({ data } = await axios.get(`${baseUrl}`))
})
it('balance', () => assert(parseInt(data.foreign.erc20Balance, 10) >= 0))
it('should contain totalSupply', () => assert(data.home.totalSupply === '0'))
})
describe('ERC TO ERC with changing state of contracts', () => {
let data
before(async () => {
assert((await axios.get(`${baseUrl}`)).data.balanceDiff === 0)
assert((await axios.get(`${baseUrl}/validators`)).data.validatorsMatch === true)
})
it('should change balanceDiff', async () => {
await sendTokens(foreignRPC.URL, user, ercToErcBridge.foreignToken, ercToErcBridge.foreign)
await waitUntil(async () => {
;({ data } = await axios.get(`${baseUrl}`))
return data.balanceDiff !== 0
})
})
it('should change validatorsMatch', async () => {
await addValidator(foreignRPC.URL, validator, ercToErcBridge.foreign)
await waitUntil(async () => {
;({ data } = await axios.get(`${baseUrl}/validators`))
return data.validatorsMatch === false
})
})
})

View File

@ -1,7 +1,14 @@
const assert = require('assert') const assert = require('assert')
const axios = require('axios') const axios = require('axios')
const { ercToNativeBridge, user, foreignRPC, validator } = require('../../e2e-commons/constants.json') const { ercToNativeBridge, user, foreignRPC, validator } = require('../../e2e-commons/constants.json')
const { waitUntil, sendTokens, addValidator } = require('../utils') const {
waitUntil,
sendTokens,
addValidator,
initializeChaiToken,
convertDaiToChai,
setMinDaiTokenBalance
} = require('../utils')
const baseUrl = ercToNativeBridge.monitor const baseUrl = ercToNativeBridge.monitor
@ -45,4 +52,58 @@ describe('ERC TO NATIVE with changing state of contracts', () => {
return data.validatorsMatch === false return data.validatorsMatch === false
}) })
}) })
it('should consider chai token balance', async function() {
this.timeout(120000)
await initializeChaiToken(foreignRPC.URL, ercToNativeBridge.foreign)
await sendTokens(foreignRPC.URL, user, ercToNativeBridge.foreignToken, ercToNativeBridge.foreign)
await waitUntil(async () => {
;({ data } = await axios.get(`${baseUrl}`))
if (!data.foreign) {
return false
}
const { erc20Balance, investedErc20Balance, accumulatedInterest } = data.foreign
return (
data.balanceDiff === 0.02 &&
erc20Balance === '0.02' &&
investedErc20Balance === '0' &&
accumulatedInterest === '0.001' // value of dsrBalance() is initially defined in genesis block as 0.001
)
})
await setMinDaiTokenBalance(foreignRPC.URL, ercToNativeBridge.foreign, '0.01')
await convertDaiToChai(foreignRPC.URL, ercToNativeBridge.foreign)
await waitUntil(async () => {
;({ data } = await axios.get(`${baseUrl}`))
if (!data.foreign) {
return false
}
const { erc20Balance, investedErc20Balance, accumulatedInterest } = data.foreign
return (
data.balanceDiff === 0.02 &&
erc20Balance === '0.01' &&
investedErc20Balance === '0.01' &&
accumulatedInterest === '0.001'
)
})
await setMinDaiTokenBalance(foreignRPC.URL, ercToNativeBridge.foreign, '0.005')
await convertDaiToChai(foreignRPC.URL, ercToNativeBridge.foreign)
await waitUntil(async () => {
;({ data } = await axios.get(`${baseUrl}`))
if (!data.foreign) {
return false
}
const { erc20Balance, investedErc20Balance, accumulatedInterest } = data.foreign
return (
data.balanceDiff === 0.02 &&
erc20Balance === '0.005' &&
investedErc20Balance === '0.015' &&
accumulatedInterest === '0.001'
)
})
})
}) })

View File

@ -0,0 +1,43 @@
const assert = require('assert')
const axios = require('axios')
const { nativeToErcBridge, user, homeRPC, foreignRPC, validator } = require('../../e2e-commons/constants.json')
const { waitUntil, sendEther, addValidator } = require('../utils')
const baseUrl = nativeToErcBridge.monitor
describe('NATIVE TO ERC', () => {
let data
before(async () => {
;({ data } = await axios.get(`${baseUrl}`))
})
it('balance', () => assert(parseInt(data.home.balance, 10) >= 0))
it('should contain totalSupply', () => assert(data.foreign.totalSupply === '0'))
})
describe('NATIVE TO ERC with changing state of contracts', () => {
let data
before(async () => {
assert((await axios.get(`${baseUrl}`)).data.balanceDiff === 0)
assert((await axios.get(`${baseUrl}/validators`)).data.validatorsMatch === true)
})
it('should change balanceDiff', async () => {
await sendEther(homeRPC.URL, user, nativeToErcBridge.home)
await waitUntil(async () => {
;({ data } = await axios.get(`${baseUrl}`))
return data.balanceDiff !== 0
})
})
it('should change validatorsMatch', async () => {
await addValidator(foreignRPC.URL, validator, nativeToErcBridge.foreign)
await waitUntil(async () => {
;({ data } = await axios.get(`${baseUrl}/validators`))
return data.validatorsMatch === false
})
})
})

View File

@ -1,5 +1,12 @@
const Web3 = require('web3') const Web3 = require('web3')
const { ERC20_ABI, BRIDGE_VALIDATORS_ABI, FOREIGN_ERC_TO_NATIVE_ABI, BOX_ABI } = require('../commons') const {
ERC677_BRIDGE_TOKEN_ABI,
BRIDGE_VALIDATORS_ABI,
FOREIGN_NATIVE_TO_ERC_ABI,
FOREIGN_ERC_TO_NATIVE_ABI,
BOX_ABI
} = require('../commons')
const { validator } = require('../e2e-commons/constants')
const waitUntil = async (predicate, step = 100, timeout = 60000) => { const waitUntil = async (predicate, step = 100, timeout = 60000) => {
const stopTime = Date.now() + timeout const stopTime = Date.now() + timeout
@ -29,7 +36,7 @@ const sendEther = async (rpcUrl, account, to) => {
const sendTokens = async (rpcUrl, account, tokenAddress, recipientAddress) => { const sendTokens = async (rpcUrl, account, tokenAddress, recipientAddress) => {
const web3 = new Web3(new Web3.providers.HttpProvider(rpcUrl)) const web3 = new Web3(new Web3.providers.HttpProvider(rpcUrl))
web3.eth.accounts.wallet.add(account.privateKey) web3.eth.accounts.wallet.add(account.privateKey)
const erc20Token = new web3.eth.Contract(ERC20_ABI, tokenAddress) const erc20Token = new web3.eth.Contract(ERC677_BRIDGE_TOKEN_ABI, tokenAddress)
await erc20Token.methods.transfer(recipientAddress, web3.utils.toWei('0.01')).send({ await erc20Token.methods.transfer(recipientAddress, web3.utils.toWei('0.01')).send({
from: account.address, from: account.address,
@ -55,7 +62,7 @@ const sendAMBMessage = async (rpcUrl, account, boxAddress, bridgeAddress, boxOth
const addValidator = async (rpcUrl, account, bridgeAddress) => { const addValidator = async (rpcUrl, account, bridgeAddress) => {
const web3 = new Web3(new Web3.providers.HttpProvider(rpcUrl)) const web3 = new Web3(new Web3.providers.HttpProvider(rpcUrl))
web3.eth.accounts.wallet.add(account.privateKey) web3.eth.accounts.wallet.add(account.privateKey)
const bridgeContract = new web3.eth.Contract(FOREIGN_ERC_TO_NATIVE_ABI, bridgeAddress) const bridgeContract = new web3.eth.Contract(FOREIGN_NATIVE_TO_ERC_ABI, bridgeAddress)
const foreignValidatorsAddress = await bridgeContract.methods.validatorContract().call() const foreignValidatorsAddress = await bridgeContract.methods.validatorContract().call()
const foreignBridgeValidators = new web3.eth.Contract(BRIDGE_VALIDATORS_ABI, foreignValidatorsAddress) const foreignBridgeValidators = new web3.eth.Contract(BRIDGE_VALIDATORS_ABI, foreignValidatorsAddress)
await foreignBridgeValidators.methods.addValidator('0xE71FBa5db00172bb0C93d649362B006300000935').send({ await foreignBridgeValidators.methods.addValidator('0xE71FBa5db00172bb0C93d649362B006300000935').send({
@ -64,10 +71,46 @@ const addValidator = async (rpcUrl, account, bridgeAddress) => {
}) })
} }
const initializeChaiToken = async (rpcUrl, bridgeAddress) => {
const web3 = new Web3(new Web3.providers.HttpProvider(rpcUrl))
web3.eth.accounts.wallet.add(validator.privateKey)
const bridgeContract = new web3.eth.Contract(FOREIGN_ERC_TO_NATIVE_ABI, bridgeAddress)
await bridgeContract.methods.initializeChaiToken().send({
from: validator.address,
gas: '1000000'
})
}
const setMinDaiTokenBalance = async (rpcUrl, bridgeAddress, limit) => {
const web3 = new Web3(new Web3.providers.HttpProvider(rpcUrl))
web3.eth.accounts.wallet.add(validator.privateKey)
const bridgeContract = new web3.eth.Contract(FOREIGN_ERC_TO_NATIVE_ABI, bridgeAddress)
await bridgeContract.methods.setMinDaiTokenBalance(web3.utils.toWei(limit)).send({
from: validator.address,
gas: '1000000'
})
}
const convertDaiToChai = async (rpcUrl, bridgeAddress) => {
const web3 = new Web3(new Web3.providers.HttpProvider(rpcUrl))
web3.eth.accounts.wallet.add(validator.privateKey)
const bridgeContract = new web3.eth.Contract(FOREIGN_ERC_TO_NATIVE_ABI, bridgeAddress)
await bridgeContract.methods.convertDaiToChai().send({
from: validator.address,
gas: '1000000'
})
}
module.exports = { module.exports = {
waitUntil, waitUntil,
sendEther, sendEther,
sendTokens, sendTokens,
addValidator, addValidator,
sendAMBMessage sendAMBMessage,
initializeChaiToken,
setMinDaiTokenBalance,
convertDaiToChai
} }

View File

@ -6,6 +6,12 @@ check_files_exist() {
rc=0 rc=0
for f in "${FILES[@]}"; do for f in "${FILES[@]}"; do
command="test -f responses/bridge/$f" command="test -f responses/bridge/$f"
if [[ -z "$MODE" || "$MODE" == native-to-erc ]]; then
(docker-compose -f ../e2e-commons/docker-compose.yml exec -T monitor /bin/bash -c "$command") || rc=1
fi
if [[ -z "$MODE" || "$MODE" == erc-to-erc ]]; then
(docker-compose -f ../e2e-commons/docker-compose.yml exec -T monitor-erc20 /bin/bash -c "$command") || rc=1
fi
if [[ -z "$MODE" || "$MODE" == erc-to-native ]]; then if [[ -z "$MODE" || "$MODE" == erc-to-native ]]; then
(docker-compose -f ../e2e-commons/docker-compose.yml exec -T monitor-erc20-native /bin/bash -c "$command") || rc=1 (docker-compose -f ../e2e-commons/docker-compose.yml exec -T monitor-erc20-native /bin/bash -c "$command") || rc=1
fi fi

View File

@ -1,4 +1,4 @@
FROM node:12 as contracts FROM node:10 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:12 FROM node:10
WORKDIR /mono WORKDIR /mono
COPY package.json . COPY package.json .

View File

@ -12,12 +12,12 @@ const { web3Home } = require('./utils/web3')
const { COMMON_HOME_BRIDGE_ADDRESS, MONITOR_BRIDGE_NAME } = process.env const { COMMON_HOME_BRIDGE_ADDRESS, MONITOR_BRIDGE_NAME } = process.env
const { HOME_ERC_TO_NATIVE_ABI } = require('../commons') const { HOME_ERC_TO_ERC_ABI } = require('../commons')
async function checkWorker() { async function checkWorker() {
try { try {
createDir(`/responses/${MONITOR_BRIDGE_NAME}`) createDir(`/responses/${MONITOR_BRIDGE_NAME}`)
const homeBridge = new web3Home.eth.Contract(HOME_ERC_TO_NATIVE_ABI, COMMON_HOME_BRIDGE_ADDRESS) const homeBridge = new web3Home.eth.Contract(HOME_ERC_TO_ERC_ABI, COMMON_HOME_BRIDGE_ADDRESS)
const bridgeMode = await getBridgeMode(homeBridge) const bridgeMode = await getBridgeMode(homeBridge)
logger.debug('Bridge mode:', bridgeMode) logger.debug('Bridge mode:', bridgeMode)
logger.debug('calling getEventsInfo()') logger.debug('calling getEventsInfo()')

Some files were not shown because too many files have changed in this diff Show More