Compare commits
37 Commits
2.1.0
...
amb-defray
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9d4dea9823 | ||
|
|
2357d787a6 | ||
|
|
065956e94e | ||
|
|
7e651a86c4 | ||
|
|
411c35d873 | ||
|
|
3ff096ef55 | ||
|
|
7f15733ad3 | ||
|
|
d22a3e8bae | ||
|
|
43609d739d | ||
|
|
ab5166b895 | ||
|
|
383e22cb58 | ||
|
|
e1f20b8686 | ||
|
|
4b59f18d29 | ||
|
|
2d42c236d7 | ||
|
|
ee4a6c8f5c | ||
|
|
55f8443c55 | ||
|
|
e5ce665656 | ||
|
|
751b885f73 | ||
|
|
3d0f68fad9 | ||
|
|
08d2c46a03 | ||
|
|
48620a8d01 | ||
|
|
35c2e642ee | ||
|
|
a056a75932 | ||
|
|
e8a179bc19 | ||
|
|
aa32f2cc0c | ||
|
|
473b6a3e46 | ||
|
|
8cf97aea3c | ||
|
|
ac6775bd6e | ||
|
|
478b30b2ed | ||
|
|
70d03c1a93 | ||
|
|
0694fc24e9 | ||
|
|
80940a0a82 | ||
|
|
a2603701b6 | ||
|
|
e006443f50 | ||
|
|
0326745684 | ||
|
|
95f4a0acc6 | ||
|
|
7ca3b0079c |
@@ -5,16 +5,10 @@ orbs:
|
||||
commands:
|
||||
install-chrome:
|
||||
steps:
|
||||
- run:
|
||||
name: Update dpkg
|
||||
command: |
|
||||
sudo apt-get clean
|
||||
sudo apt-get update
|
||||
sudo apt-get install dpkg
|
||||
- run:
|
||||
- run:
|
||||
name: Install Chrome
|
||||
command: |
|
||||
wget -O chrome.deb https://dl.google.com/linux/chrome/deb/pool/main/g/google-chrome-stable/google-chrome-stable_77.0.3865.120-1_amd64.deb
|
||||
wget -O chrome.deb https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
|
||||
sudo dpkg -i chrome.deb
|
||||
install-node:
|
||||
steps:
|
||||
@@ -24,7 +18,7 @@ orbs:
|
||||
export NVM_DIR="/opt/circleci/.nvm"
|
||||
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
|
||||
|
||||
nvm install 10.16.3 && nvm alias default 10.16.3
|
||||
nvm install 11.4.0 && nvm alias default 11.4.0
|
||||
|
||||
echo 'export NVM_DIR="/opt/circleci/.nvm"' >> $BASH_ENV
|
||||
echo ' [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"' >> $BASH_ENV
|
||||
@@ -89,29 +83,29 @@ jobs:
|
||||
- checkout
|
||||
- run: git submodule update --init
|
||||
- restore_cache:
|
||||
name: Restore Yarn Package Cache
|
||||
keys:
|
||||
- yarn-{{ checksum "package.json" }}-{{ checksum "yarn.lock" }}
|
||||
- run: git submodule status > submodule.status
|
||||
name: Restore Yarn Package Cache
|
||||
keys:
|
||||
- yarn-{{ checksum "package.json" }}-{{ checksum "yarn.lock" }}
|
||||
- run: git submodule status > submodule.status
|
||||
- restore_cache:
|
||||
name: Restore contracts submodule with compiled contracts
|
||||
keys:
|
||||
- contracts-{{ checksum "submodule.status" }}
|
||||
name: Restore contracts submodule with compiled contracts
|
||||
keys:
|
||||
- contracts-{{ checksum "submodule.status" }}
|
||||
- run: yarn install --frozen-lockfile
|
||||
- save_cache:
|
||||
name: Save Yarn Package Cache
|
||||
key: yarn-{{ checksum "package.json" }}-{{ checksum "yarn.lock" }}
|
||||
paths:
|
||||
- ~/.cache/yarn
|
||||
name: Save Yarn Package Cache
|
||||
key: yarn-{{ checksum "package.json" }}-{{ checksum "yarn.lock" }}
|
||||
paths:
|
||||
- ~/.cache/yarn
|
||||
- run: touch install_deploy.log; test -d contracts/build/contracts || yarn install:deploy &> install_deploy.log
|
||||
- store_artifacts:
|
||||
path: install_deploy.log
|
||||
- run: test -d contracts/build/contracts || yarn compile:contracts
|
||||
- save_cache:
|
||||
name: Save contracts submodule with compiled contracts
|
||||
key: contracts-{{ checksum "submodule.status" }}
|
||||
paths:
|
||||
- contracts
|
||||
name: Save contracts submodule with compiled contracts
|
||||
key: contracts-{{ checksum "submodule.status" }}
|
||||
paths:
|
||||
- contracts
|
||||
- save_cache:
|
||||
name: Save initialized project for subsequent jobs
|
||||
key: initialize-{{ .Environment.CIRCLE_SHA1 }}
|
||||
@@ -143,11 +137,11 @@ jobs:
|
||||
oracle-e2e:
|
||||
executor: tokenbridge-orb/docker-node
|
||||
steps:
|
||||
- checkout
|
||||
- run: git submodule update --init
|
||||
- setup_remote_docker:
|
||||
docker_layer_caching: true
|
||||
- run: yarn run oracle-e2e
|
||||
- checkout
|
||||
- run: git submodule update --init
|
||||
- setup_remote_docker:
|
||||
docker_layer_caching: true
|
||||
- run: yarn run oracle-e2e
|
||||
ui-e2e:
|
||||
executor: tokenbridge-orb/machine-with-docker-caching
|
||||
steps:
|
||||
@@ -161,9 +155,9 @@ jobs:
|
||||
monitor-e2e:
|
||||
executor: tokenbridge-orb/machine-with-docker-caching
|
||||
steps:
|
||||
- checkout
|
||||
- run: git submodule update --init
|
||||
- run: ./monitor-e2e/run-tests.sh
|
||||
- checkout
|
||||
- run: git submodule update --init
|
||||
- run: ./monitor-e2e/run-tests.sh
|
||||
cover:
|
||||
executor: tokenbridge-orb/docker-node
|
||||
steps:
|
||||
@@ -175,50 +169,17 @@ jobs:
|
||||
executor: tokenbridge-orb/machine-with-docker-caching
|
||||
steps:
|
||||
- checkout
|
||||
- run: git submodule update --init
|
||||
- run:
|
||||
name: Run the scenario
|
||||
command: deployment-e2e/molecule.sh oracle
|
||||
no_output_timeout: 40m
|
||||
- run: deployment/molecule/molecule.sh oracle
|
||||
deployment-ui:
|
||||
executor: tokenbridge-orb/machine-with-docker-caching
|
||||
steps:
|
||||
- checkout
|
||||
- run: git submodule update --init
|
||||
- run:
|
||||
name: Run the scenario
|
||||
command: deployment-e2e/molecule.sh ui
|
||||
no_output_timeout: 40m
|
||||
- run: deployment/molecule/molecule.sh ui
|
||||
deployment-monitor:
|
||||
executor: tokenbridge-orb/machine-with-docker-caching
|
||||
steps:
|
||||
- checkout
|
||||
- run: git submodule update --init
|
||||
- run:
|
||||
name: Run the scenario
|
||||
command: deployment-e2e/molecule.sh monitor
|
||||
no_output_timeout: 40m
|
||||
deployment-repo:
|
||||
executor: tokenbridge-orb/machine-with-docker-caching
|
||||
steps:
|
||||
- checkout
|
||||
- run: git submodule update --init
|
||||
- tokenbridge-orb/install-node
|
||||
- tokenbridge-orb/install-yarn
|
||||
- tokenbridge-orb/yarn-install-cached-on-machine
|
||||
- run:
|
||||
name: Run the scenario
|
||||
command: deployment-e2e/molecule.sh repo
|
||||
no_output_timeout: 40m
|
||||
deployment-multiple:
|
||||
executor: tokenbridge-orb/machine-with-docker-caching
|
||||
steps:
|
||||
- checkout
|
||||
- run: git submodule update --init
|
||||
- run:
|
||||
name: Run the scenario
|
||||
command: deployment-e2e/molecule.sh multiple
|
||||
no_output_timeout: 40m
|
||||
- run: deployment/molecule/molecule.sh monitor
|
||||
ultimate:
|
||||
executor: tokenbridge-orb/machine-with-docker-caching
|
||||
parameters:
|
||||
@@ -230,11 +191,6 @@ jobs:
|
||||
type: string
|
||||
ui-e2e-grep:
|
||||
description: "Mocha grep string used to run ui-e2e tests specific to given type of bridge"
|
||||
default: ''
|
||||
type: string
|
||||
oracle-e2e-script:
|
||||
description: "Yarn script string used to run oracle-e2e tests specific to given type of bridge"
|
||||
default: ''
|
||||
type: string
|
||||
steps:
|
||||
- checkout
|
||||
@@ -245,24 +201,16 @@ jobs:
|
||||
- tokenbridge-orb/yarn-install-cached-on-machine
|
||||
- run:
|
||||
name: Prepare the infrastructure
|
||||
command: e2e-commons/up.sh deploy << parameters.scenario-name >> blocks
|
||||
no_output_timeout: 50m
|
||||
command: e2e-commons/up.sh deploy << parameters.scenario-name >>
|
||||
no_output_timeout: 30m
|
||||
- tokenbridge-orb/wait-for-oracle:
|
||||
redis-key: << parameters.redis-key >>
|
||||
- when:
|
||||
condition: << parameters.ui-e2e-grep >>
|
||||
steps:
|
||||
- run:
|
||||
name: Run the ui-e2e tests
|
||||
command: |
|
||||
nvm use default;
|
||||
cd ui-e2e; yarn mocha -g "<< parameters.ui-e2e-grep >>" -b ./test.js
|
||||
- when:
|
||||
condition: << parameters.oracle-e2e-script >>
|
||||
steps:
|
||||
- run:
|
||||
name: Run the oracle-e2e tests
|
||||
command: cd e2e-commons && docker-compose run e2e yarn workspace oracle-e2e run << parameters.oracle-e2e-script >>
|
||||
- run:
|
||||
name: Run the ui-e2e tests
|
||||
command: |
|
||||
nvm use default;
|
||||
node ./e2e-commons/scripts/blocks.js &
|
||||
cd ui-e2e; yarn mocha -g "<< parameters.ui-e2e-grep >>" -b ./test.js
|
||||
workflows:
|
||||
tokenbridge:
|
||||
jobs:
|
||||
@@ -292,25 +240,18 @@ workflows:
|
||||
- deployment-oracle
|
||||
- deployment-ui
|
||||
- deployment-monitor
|
||||
- deployment-repo
|
||||
- deployment-multiple
|
||||
- ultimate:
|
||||
name: "ultimate: native to erc"
|
||||
name: "ultimate: native to erc"
|
||||
scenario-name: native-to-erc
|
||||
redis-key: native-erc-collected-signatures:lastProcessedBlock
|
||||
ui-e2e-grep: "NATIVE TO ERC"
|
||||
- ultimate:
|
||||
name: "ultimate: erc to native"
|
||||
name: "ultimate: erc to native"
|
||||
scenario-name: erc-to-native
|
||||
redis-key: erc-native-collected-signatures:lastProcessedBlock
|
||||
ui-e2e-grep: "ERC TO NATIVE"
|
||||
- ultimate:
|
||||
name: "ultimate: erc to erc"
|
||||
name: "ultimate: erc to erc"
|
||||
scenario-name: erc-to-erc
|
||||
redis-key: erc-erc-collected-signatures:lastProcessedBlock
|
||||
ui-e2e-grep: "ERC TO ERC"
|
||||
- ultimate:
|
||||
name: "ultimate: amb"
|
||||
scenario-name: amb
|
||||
redis-key: amb-collected-signatures:lastProcessedBlock
|
||||
oracle-e2e-script: "amb"
|
||||
|
||||
@@ -2,4 +2,3 @@ node_modules
|
||||
submodules
|
||||
coverage
|
||||
lib
|
||||
dist
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -6,7 +6,6 @@ coverage
|
||||
|
||||
# production
|
||||
build
|
||||
dist
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
@@ -49,4 +48,4 @@ __pycache__
|
||||
|
||||
#monitor
|
||||
monitor/responses/*
|
||||
!monitor/.gitkeep
|
||||
!monitor/.gitkeep
|
||||
2
.gitmodules
vendored
2
.gitmodules
vendored
@@ -1,3 +1,3 @@
|
||||
[submodule "contracts"]
|
||||
path = contracts
|
||||
url = https://github.com/poanetwork/tokenbridge-contracts.git
|
||||
url = https://github.com/poanetwork/poa-bridge-contracts.git
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
# Configuration
|
||||
|
||||
## Common configuration
|
||||
|
||||
name | description | value
|
||||
--- | --- | ---
|
||||
COMMON_HOME_RPC_URL | The HTTPS URL(s) used to communicate to the RPC nodes in the Home 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_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. | 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_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_FOREIGN_GAS_PRICE_SUPPLIER_URL | The URL used to get a JSON response from the gas price prediction oracle for the Foreign network. The provided gas price is used to send the validator's transactions to the RPC node. If the Foreign network is Ethereum Foundation mainnet, the oracle URL can be: https://gasprice.poa.network. Otherwise this parameter can be omitted. | URL
|
||||
COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE | Assuming the gas price oracle responds with the following JSON structure: `{"fast": 20.0, "block_time": 12.834, "health": true, "standard": 6.0, "block_number": 6470469, "instant": 71.0, "slow": 1.889}`, this parameter specifies the desirable transaction speed. The speed type can be omitted when `COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL`is not used. | `instant` / `fast` / `standard` / `slow`
|
||||
COMMON_FOREIGN_GAS_PRICE_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
|
||||
|
||||
|
||||
## Oracle configuration
|
||||
|
||||
name | description | value
|
||||
--- | --- | ---
|
||||
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
|
||||
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_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_HOME_GAS_PRICE_UPDATE_INTERVAL | An interval in milliseconds used to get the updated gas price value either from the oracle or from the Home Bridge contract. | integer
|
||||
ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL | The interval in milliseconds used to get the updated gas price value either from the oracle or from the Foreign Bridge contract. | integer
|
||||
ORACLE_QUEUE_URL | RabbitMQ URL used by watchers and senders to communicate to the message queue. Typically set to: `amqp://127.0.0.1`. | local URL
|
||||
ORACLE_REDIS_URL | Redis DB URL used by watchers and senders to communicate to the database. Typically set to: `redis://127.0.0.1:6379`. | local URL
|
||||
ORACLE_HOME_START_BLOCK | The block number in the Home network used to start watching for events when the bridge instance is run for the first time. Usually this is the same block where the Home Bridge contract is deployed. If a new validator instance is being deployed for an existing set of validators, the block number could be the latest block in the chain. | integer
|
||||
ORACLE_FOREIGN_START_BLOCK | The block number in the Foreign network used to start watching for events when the bridge instance runs for the first time. Usually this is the same block where the Foreign Bridge contract was deployed to. If a new validator instance is being deployed for an existing set of validators, the block number could be the latest block in the chain. | integer
|
||||
ORACLE_LOG_LEVEL | Set the level of details in the logs. | `trace` / `debug` / `info` / `warn` / `error` / `fatal`
|
||||
ORACLE_MAX_PROCESSING_TIME | The workers processes will be killed if this amount of time (in milliseconds) is elapsed before they finish processing. It is recommended to set this value to 4 times the value of the longest polling time (set with the `HOME_POLLING_INTERVAL` and `FOREIGN_POLLING_INTERVAL` variables). To disable this, set the time to 0. | integer
|
||||
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY | The private key of the bridge validator used to sign confirmations before sending transactions to the bridge contracts. The validator account is calculated automatically from the private key. Every bridge instance (set of watchers and senders) must have its own unique private key. The specified private key is used to sign transactions on both sides of the bridge. | hexidecimal without "0x"
|
||||
ORACLE_VALIDATOR_ADDRESS | The public address of the bridge validator | hexidecimal with "0x"
|
||||
|
||||
|
||||
## UI configuration
|
||||
|
||||
name | description | value
|
||||
--- | --- | ---
|
||||
UI_TITLE | The title for the bridge UI page. `%c` will be replaced by the name of the network. | string
|
||||
UI_DESCRIPTION | The meta description for the deployed bridge page. | string
|
||||
UI_NATIVE_TOKEN_DISPLAY_NAME | name of the home native coin | string
|
||||
UI_HOME_NETWORK_DISPLAY_NAME | name to be displayed for home network | string
|
||||
UI_FOREIGN_NETWORK_DISPLAY_NAME | name to be displayed for foreign network | string
|
||||
UI_HOME_WITHOUT_EVENTS | `true` if home network doesn't support events | true/false
|
||||
UI_FOREIGN_WITHOUT_EVENTS | `true` if foreign network doesn't support events | true/false
|
||||
UI_HOME_EXPLORER_TX_TEMPLATE | template link to transaction on home explorer. `%s` will be replaced by transaction hash | URL template
|
||||
UI_FOREIGN_EXPLORER_TX_TEMPLATE | template link to transaction on foreign explorer. `%s` will be replaced by transaction hash | URL template
|
||||
UI_HOME_EXPLORER_ADDRESS_TEMPLATE | template link to address on home explorer. `%s` will be replaced by address | URL template
|
||||
UI_FOREIGN_EXPLORER_ADDRESS_TEMPLATE | template link to address on foreign explorer. `%s` will be replaced by address | URL template
|
||||
UI_HOME_GAS_PRICE_UPDATE_INTERVAL | An interval in milliseconds used to get the updated gas price value either from the oracle or from the Home Bridge contract. | integer
|
||||
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL | An interval in milliseconds used to get the updated gas price value either from the oracle or from the Foreign Bridge contract. | integer
|
||||
UI_PORT | The port for the UI app. | integer
|
||||
UI_STYLES | The set of styles to render the bridge UI page. Currently only `classic` is implemented | classic
|
||||
|
||||
|
||||
## Monitor configuration
|
||||
|
||||
name | description | value
|
||||
--- | --- | ---
|
||||
MONITOR_HOME_START_BLOCK | The app will monitor transactions starting from this block. | integer
|
||||
MONITOR_FOREIGN_START_BLOCK | The app will monitor transactions starting from this block. | integer
|
||||
MONITOR_VALIDATOR_HOME_TX_LIMIT | Average gas usage of a transaction sent by a validator, it is used to estimate the number of transaction that can be paid by the validator. | integer
|
||||
MONITOR_VALIDATOR_FOREIGN_TX_LIMIT | Average gas usage of a transaction sent by a validator, it is used to estimate the number of transaction that can be paid by the validator. | integer
|
||||
MONITOR_TX_NUMBER_THRESHOLD | If estimated number of transaction is equal to or below this value, the monitor will report that the validator has less funds than it is required. | integer
|
||||
MONITOR_PORT | The port for the Monitor. | integer
|
||||
MONITOR_BRIDGE_NAME | The name to be used in the url path for the bridge | string
|
||||
MONITOR_CACHE_EVENTS | If set to true, monitor will cache obtained events for other workers runs
|
||||
@@ -3,7 +3,6 @@ FROM node:10
|
||||
WORKDIR /mono
|
||||
COPY package.json .
|
||||
COPY oracle-e2e/package.json ./oracle-e2e/
|
||||
COPY monitor-e2e/package.json ./monitor-e2e/
|
||||
COPY contracts/package.json ./contracts/
|
||||
|
||||
COPY yarn.lock .
|
||||
|
||||
16
README.md
16
README.md
@@ -26,11 +26,10 @@ Sub-repositories maintained within this monorepo are listed below.
|
||||
| [Oracle-E2E](oracle-e2e/README.md) | End to end tests for the Oracle |
|
||||
| [Monitor-E2E](monitor-e2e/README.md) | End to end tests for the Monitor |
|
||||
| [UI-E2E](ui-e2e/README.md) | End to end tests for the UI |
|
||||
| [Deployment-E2E](deployment-e2e/README.md) | End to end tests for the Deployment |
|
||||
| [Commons](commons/README.md) | Interfaces, constants and utilities shared between the sub-repositories |
|
||||
| [E2E-Commons](e2e-commons/README.md) | Common utilities and configuration used in end to end tests |
|
||||
|
||||
Additionally there are [Smart Contracts](https://github.com/poanetwork/tokenbridge-contracts) used to manage bridge validators, collect signatures, and confirm asset relay and disposal.
|
||||
Additionally there are [Smart Contracts](https://github.com/poanetwork/poa-bridge-contracts) used to manage bridge validators, collect signatures, and confirm asset relay and disposal.
|
||||
|
||||
## Available deployments
|
||||
|
||||
@@ -52,12 +51,11 @@ Additionally there are [Smart Contracts](https://github.com/poanetwork/tokenbrid
|
||||
|
||||
## Operational Modes
|
||||
|
||||
The POA TokenBridge provides four operational modes:
|
||||
The POA TokenBridge provides three 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] `Arbitrary-Message`: Transfer arbitrary data between two networks as so the data could be interpreted as an arbitrary contract method invocation.
|
||||
|
||||
## Initializing the monorepository
|
||||
|
||||
@@ -66,13 +64,11 @@ Clone the repository:
|
||||
git clone https://github.com/poanetwork/tokenbridge
|
||||
```
|
||||
|
||||
If there is no need to build docker images for the TokenBridge components (oracle, monitor, UI), initialize submodules, install dependencies, compile the Smart Contracts:
|
||||
Initialize submodules, install dependencies, compile the Smart Contracts:
|
||||
```
|
||||
yarn initialize
|
||||
```
|
||||
|
||||
Then refer to the corresponding README files to get information about particular TokenBridge component.
|
||||
|
||||
## Linting
|
||||
|
||||
Running linter for all JS projects:
|
||||
@@ -89,14 +85,13 @@ Running tests for all projects:
|
||||
yarn test
|
||||
```
|
||||
|
||||
Additionally there are end-to-end tests for [Oracle](oracle-e2e/README.md) and [UI](ui-e2e/README.md).
|
||||
Additionaly there are end-to-end tests for [Oracle](oracle-e2e/README.md) and [UI](ui-e2e/README.md).
|
||||
|
||||
For details on building, running and developing please refer to respective READMEs in sub-repositories.
|
||||
|
||||
## Building, running and deploying
|
||||
|
||||
Please refer to the instructions in sub-directories.
|
||||
Configuration details are available [here](./CONFIGURATION.md).
|
||||
|
||||
## Contributing
|
||||
|
||||
@@ -108,4 +103,5 @@ This project is licensed under the GNU Lesser General Public License v3.0. See t
|
||||
|
||||
## References
|
||||
|
||||
* [TokenBridge Documentation](http://www.tokenbridge.net/)
|
||||
* [Additional Documentation](https://forum.poa.network/c/tokenbridge)
|
||||
* [POA20 Bridge FAQ](https://forum.poa.network/c/tokenbridge/poa20-bridge)
|
||||
|
||||
Binary file not shown.
@@ -1,31 +0,0 @@
|
||||
module.exports = {
|
||||
parser: "@typescript-eslint/parser", // Specifies the ESLint parser
|
||||
extends: [
|
||||
"plugin:react/recommended",
|
||||
"plugin:@typescript-eslint/recommended", // Uses the recommended rules from @typescript-eslint/eslint-plugin
|
||||
"../.eslintrc"
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features
|
||||
sourceType: "module", // Allows for the use of imports
|
||||
ecmaFeatures: {
|
||||
jsx: true // Allows for the parsing of JSX
|
||||
}
|
||||
},
|
||||
rules: {
|
||||
"@typescript-eslint/explicit-function-return-type": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off", // Reduce the use of 'any'
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
"@typescript-eslint/no-var-requires": "off",
|
||||
"react/prop-types": "off",
|
||||
"@typescript-eslint/ban-ts-ignore": "off",
|
||||
"@typescript-eslint/member-delimiter-style": "off",
|
||||
"@typescript-eslint/indent": "off",
|
||||
"@typescript-eslint/explicit-member-accessibility": "off"
|
||||
},
|
||||
settings: {
|
||||
react: {
|
||||
version: "detect",
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,30 +0,0 @@
|
||||
FROM node:12 as plugin-base
|
||||
|
||||
WORKDIR /mono
|
||||
COPY package.json .
|
||||
RUN mkdir -p contracts/node_modules
|
||||
|
||||
COPY burner-wallet-plugin/package.json ./burner-wallet-plugin/
|
||||
COPY burner-wallet-plugin/lerna.json ./burner-wallet-plugin/
|
||||
COPY burner-wallet-plugin/yarn.lock ./burner-wallet-plugin/
|
||||
COPY burner-wallet-plugin/tsconfig.json ./burner-wallet-plugin/
|
||||
COPY burner-wallet-plugin/tokenbridge-bw-exchange/package.json ./burner-wallet-plugin/tokenbridge-bw-exchange/
|
||||
COPY burner-wallet-plugin/staging/package.json ./burner-wallet-plugin/staging/
|
||||
COPY burner-wallet-plugin/testing/package.json ./burner-wallet-plugin/testing/
|
||||
COPY yarn.lock .
|
||||
RUN yarn install --production --frozen-lockfile
|
||||
|
||||
COPY ./burner-wallet-plugin/tokenbridge-bw-exchange ./burner-wallet-plugin/tokenbridge-bw-exchange
|
||||
RUN yarn build:plugin
|
||||
|
||||
|
||||
FROM plugin-base as testing
|
||||
COPY ./burner-wallet-plugin/testing ./burner-wallet-plugin/testing
|
||||
WORKDIR /mono/burner-wallet-plugin
|
||||
CMD ["yarn", "start-testing"]
|
||||
|
||||
|
||||
FROM plugin-base as staging
|
||||
COPY ./burner-wallet-plugin/staging ./burner-wallet-plugin/staging
|
||||
WORKDIR /mono/burner-wallet-plugin
|
||||
CMD ["yarn", "start-staging"]
|
||||
@@ -1,41 +0,0 @@
|
||||
# TokenBridge Burner Wallet 2 Plugin
|
||||
|
||||
Please refer to the [Plugin README](./tokenrbdige-bw-exchange/README.md) for resources provided, instructions to install and use the plugin.
|
||||
|
||||
### Setup
|
||||
1. [Initialize](../README.md#initializing-the-monorepository) the monorepository.
|
||||
2. Run `yarn build` or from the monorepository root `yarn build:plugin`
|
||||
|
||||
### Run Burner Wallet with the plugin in Mainnet & Classic
|
||||
1. Create `.env` file in `staging` folder and set `REACT_APP_INFURA_KEY=<your key from infura.com>`
|
||||
2. Run `yarn start-staging` to start the wallet connected to Mainnet & Classic and interact with the ETH - WETC Bridge.
|
||||
|
||||
### Run Burner Wallet with the plugin in Sokol & Kovan
|
||||
1. Create `.env` file in `testing` folder and set `REACT_APP_INFURA_KEY=<your key from infura.com>`.
|
||||
Also, a private key can be set to start the wallet with the specified account `REACT_APP_PK=0x...`
|
||||
2. Run `yarn start-testing` to start the wallet connected to Sokol & Kovan and interact with a test bridge
|
||||
that works on top of the AMB bridge.
|
||||
|
||||
### Docker Setup
|
||||
Docker can be used to build the services and run the testing and staging wallets.
|
||||
|
||||
First you may want to create the `.env` files for testing and staging as mentioned before. This is optional before building the containers, variables can be passes later using `--env-file` or `--env` parameters in `docker run`.
|
||||
|
||||
Build the services with docker-compose:
|
||||
```bash
|
||||
docker-compose build
|
||||
```
|
||||
|
||||
### Run Burner Wallet with the plugin in Mainnet & Classic using Docker
|
||||
```bash
|
||||
docker run -ti -p 8080:8080 -e PORT=8080 --rm burner-wallet-plugin_staging
|
||||
```
|
||||
|
||||
### Run Burner Wallet with the plugin in Sokol & Kovan using Docker
|
||||
```bash
|
||||
docker run -ti -p 8080:8080 -e PORT=8080 --rm burner-wallet-plugin_testing
|
||||
```
|
||||
### Publish to npm
|
||||
In order to make this plugin accessible, it should be available as a npm package. Follow the [instructions](publish.md) to publish
|
||||
the package to npm registry.
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
---
|
||||
version: '2.4'
|
||||
services:
|
||||
staging:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: burner-wallet-plugin/Dockerfile
|
||||
target: staging
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
testing:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: burner-wallet-plugin/Dockerfile
|
||||
target: testing
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"packages": [
|
||||
"basic-wallet",
|
||||
"local-wallet",
|
||||
"tokenbridge-bw-exchange"
|
||||
],
|
||||
"npmClient": "yarn",
|
||||
"useWorkspaces": true,
|
||||
"version": "independent"
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
{
|
||||
"name": "burner-wallet-plugin",
|
||||
"description": "Burner Wallet 2 plugin",
|
||||
"version": "1.0.0",
|
||||
"license": "GPL-3.0-only",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"install": "lerna bootstrap",
|
||||
"build": "lerna run --ignore testing --ignore staging build --stream",
|
||||
"lint": "eslint '*/**/*.{js,ts,tsx}' --ignore-path ../.eslintignore",
|
||||
"start-staging": "lerna run --scope staging start --stream",
|
||||
"start-testing": "lerna run --scope testing start --stream",
|
||||
"test": "lerna run --ignore testing --ignore staging test --stream"
|
||||
},
|
||||
"workspaces": [
|
||||
"staging",
|
||||
"testing",
|
||||
"tokenbridge-bw-exchange"
|
||||
],
|
||||
"dependencies": {
|
||||
"@types/color": "3.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "1.13.0",
|
||||
"@typescript-eslint/parser": "1.13.0",
|
||||
"eslint-plugin-react": "7.19.0",
|
||||
"lerna": "3.16.4",
|
||||
"typescript": "3.5.3"
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
## Plugin Package Information
|
||||
|
||||
The package to be published gets its configuration from `tokenbridge/burner-wallet-plugin/tokenbridge-bw-exchange/package.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "tokenbridge-bw-exchange",
|
||||
"version": "1.0.0",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
"/dist"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
- `name` is the name of how package will be available in npm.
|
||||
- `main` is entry point for the package
|
||||
- `types` is the entry point for typescript types
|
||||
- `files` is the list of files included when publishing the package. So we have to run `yarn build` first to
|
||||
generate the `dist` folder.
|
||||
|
||||
## Steps to publish to npm
|
||||
|
||||
1. Create account in https://www.npmjs.com/
|
||||
|
||||
2. Go to `tokenbridge/burner-wallet-plugin/tokenbridge-bw-exchange/`
|
||||
|
||||
3. Run `yarn build`. Make sure it generates the `dist` folder
|
||||
|
||||
4. Update `version` in `tokenbridge/burner-wallet-plugin/tokenbridge-bw-exchange/package.json`
|
||||
5. Run `yarn login` and fill login information if required.
|
||||
6. Run `yarn publish --access public`.
|
||||
The prompt will ask for the new version, complete it with the version from `package.json`
|
||||
|
||||
More information in https://classic.yarnpkg.com/en/docs/publishing-a-package/
|
||||
@@ -1 +0,0 @@
|
||||
REACT_APP_INFURA_KEY=
|
||||
@@ -1,40 +0,0 @@
|
||||
{
|
||||
"name": "staging",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@burner-wallet/assets": "^1.1.10",
|
||||
"@burner-wallet/core": "^1.1.0",
|
||||
"@burner-wallet/exchange": "^1.1.4",
|
||||
"@burner-wallet/metamask-plugin": "^1.0.0",
|
||||
"@burner-wallet/modern-ui": "^1.0.7",
|
||||
"@poanet/tokenbridge-bw-exchange": "^1.0.0",
|
||||
"@types/node": "12.0.4",
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "16.8.4",
|
||||
"@types/react-router-dom": "^4.3.3",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6",
|
||||
"react-scripts": "3.0.1",
|
||||
"typescript": "3.5.1"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
},
|
||||
"devDependencies": {}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.8 KiB |
@@ -1,38 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React App</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"short_name": "React App",
|
||||
"name": "Create React App Sample",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
"sizes": "64x64 32x32 24x24 16x16",
|
||||
"type": "image/x-icon"
|
||||
}
|
||||
],
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#ffffff"
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import BurnerCore from '@burner-wallet/core'
|
||||
import { InjectedSigner, LocalSigner } from '@burner-wallet/core/signers'
|
||||
import { InfuraGateway, InjectedGateway } from '@burner-wallet/core/gateways'
|
||||
import Exchange from '@burner-wallet/exchange'
|
||||
import ModernUI from '@burner-wallet/modern-ui'
|
||||
import { Etc, Wetc, TokenBridgeGateway, WETCBridge } from '@poanet/tokenbridge-bw-exchange'
|
||||
import MetamaskPlugin from '@burner-wallet/metamask-plugin'
|
||||
|
||||
const core = new BurnerCore({
|
||||
signers: [new InjectedSigner(), new LocalSigner()],
|
||||
gateways: [new InjectedGateway(), new InfuraGateway(process.env.REACT_APP_INFURA_KEY), new TokenBridgeGateway()],
|
||||
assets: [Wetc, Etc]
|
||||
})
|
||||
|
||||
const exchange = new Exchange([new WETCBridge()])
|
||||
|
||||
const BurnerWallet = () => <ModernUI title="Staging Wallet" core={core} plugins={[exchange, new MetamaskPlugin()]} />
|
||||
|
||||
ReactDOM.render(<BurnerWallet />, document.getElementById('root'))
|
||||
@@ -1 +0,0 @@
|
||||
/// <reference types="react-scripts" />
|
||||
@@ -1,25 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "preserve"
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
]
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
REACT_APP_INFURA_KEY=
|
||||
#REACT_APP_PK=0x
|
||||
|
||||
REACT_APP_MODE=AMB_NATIVE_TO_ERC677
|
||||
|
||||
REACT_APP_HOME_TOKEN_NAME=sPOA
|
||||
REACT_APP_HOME_NETWORK=77
|
||||
REACT_APP_HOME_MEDIATOR_ADDRESS=0x867949C3F2f66D827Ed40847FaA7B3a369370e13
|
||||
REACT_APP_HOME_TOKEN_ADDRESS=
|
||||
|
||||
REACT_APP_FOREIGN_TOKEN_NAME=ksPOA
|
||||
REACT_APP_FOREIGN_NETWORK=42
|
||||
REACT_APP_FOREIGN_MEDIATOR_ADDRESS=0x99FB1a25caeB9c3a5Bf132686E2fe5e27BC0e2dd
|
||||
REACT_APP_FOREIGN_TOKEN_ADDRESS=0xff94183659f549D6273349696d73686Ee1d2AC83
|
||||
@@ -1,43 +0,0 @@
|
||||
{
|
||||
"name": "testing",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@burner-wallet/assets": "^1.1.10",
|
||||
"@burner-wallet/core": "^1.1.0",
|
||||
"@burner-wallet/exchange": "^1.1.4",
|
||||
"@burner-wallet/metamask-plugin": "^1.0.0",
|
||||
"@burner-wallet/modern-ui": "^1.0.7",
|
||||
"@poanet/tokenbridge-bw-exchange": "^1.0.0",
|
||||
"@types/node": "12.0.4",
|
||||
"@types/react": "16.8.19",
|
||||
"@types/react-dom": "16.8.4",
|
||||
"@types/react-router-dom": "^4.3.3",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6",
|
||||
"react-scripts": "3.0.1",
|
||||
"typescript": "3.5.1",
|
||||
"web3": "1.0.0-beta.55"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"axios": "^0.19.0"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.8 KiB |
@@ -1,38 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React App</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"short_name": "Burner Wallet",
|
||||
"name": "Burner Wallet",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
"sizes": "64x64 32x32 24x24 16x16",
|
||||
"type": "image/x-icon"
|
||||
}
|
||||
],
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#ffffff"
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import { Asset } from '@burner-wallet/assets'
|
||||
import BurnerCore from '@burner-wallet/core'
|
||||
import { InjectedSigner, LocalSigner } from '@burner-wallet/core/signers'
|
||||
import { InfuraGateway, InjectedGateway } from '@burner-wallet/core/gateways'
|
||||
import ModernUI from '@burner-wallet/modern-ui'
|
||||
import Exchange from '@burner-wallet/exchange'
|
||||
import { Mediator, sPOA, ERC677Asset, TokenBridgeGateway } from '@poanet/tokenbridge-bw-exchange'
|
||||
import MetamaskPlugin from '@burner-wallet/metamask-plugin'
|
||||
|
||||
let assetIdAtHome = 'assetAtHome'
|
||||
const assetIdAtForeign = 'assetAtForeign'
|
||||
let assetAtHome: Asset
|
||||
let assetAtForeign: Asset
|
||||
|
||||
if (process.env.REACT_APP_MODE === 'AMB_NATIVE_TO_ERC677') {
|
||||
sPOA.setMediatorAddress(process.env.REACT_APP_HOME_MEDIATOR_ADDRESS)
|
||||
assetAtHome = sPOA
|
||||
assetIdAtHome = sPOA.id
|
||||
|
||||
assetAtForeign = new ERC677Asset({
|
||||
id: 'assetAtForeign',
|
||||
// @ts-ignore
|
||||
name: process.env.REACT_APP_FOREIGN_TOKEN_NAME,
|
||||
// @ts-ignore
|
||||
network: process.env.REACT_APP_FOREIGN_NETWORK,
|
||||
// @ts-ignore
|
||||
address: process.env.REACT_APP_FOREIGN_TOKEN_ADDRESS
|
||||
})
|
||||
} else {
|
||||
// process.env.REACT_APP_MODE === 'AMB_ERC677_TO_ERC677'
|
||||
assetAtHome = new ERC677Asset({
|
||||
id: 'assetAtHome',
|
||||
// @ts-ignore
|
||||
name: process.env.REACT_APP_HOME_TOKEN_NAME,
|
||||
// @ts-ignore
|
||||
network: process.env.REACT_APP_HOME_NETWORK,
|
||||
// @ts-ignore
|
||||
address: process.env.REACT_APP_HOME_TOKEN_ADDRESS
|
||||
})
|
||||
|
||||
assetAtForeign = new ERC677Asset({
|
||||
id: 'assetAtForeign',
|
||||
// @ts-ignore
|
||||
name: process.env.REACT_APP_FOREIGN_TOKEN_NAME,
|
||||
// @ts-ignore
|
||||
network: process.env.REACT_APP_FOREIGN_NETWORK,
|
||||
// @ts-ignore
|
||||
address: process.env.REACT_APP_FOREIGN_TOKEN_ADDRESS
|
||||
})
|
||||
}
|
||||
|
||||
const testBridge = new Mediator({
|
||||
assetA: assetIdAtHome,
|
||||
// @ts-ignore
|
||||
assetABridge: process.env.REACT_APP_HOME_MEDIATOR_ADDRESS,
|
||||
assetB: assetIdAtForeign,
|
||||
// @ts-ignore
|
||||
assetBBridge: process.env.REACT_APP_FOREIGN_MEDIATOR_ADDRESS
|
||||
})
|
||||
|
||||
const core = new BurnerCore({
|
||||
signers: [new InjectedSigner(), new LocalSigner({ privateKey: process.env.REACT_APP_PK, saveKey: false })],
|
||||
gateways: [new InjectedGateway(), new TokenBridgeGateway(), new InfuraGateway(process.env.REACT_APP_INFURA_KEY)],
|
||||
assets: [assetAtHome, assetAtForeign]
|
||||
})
|
||||
|
||||
const exchange = new Exchange([testBridge])
|
||||
|
||||
const BurnerWallet = () => <ModernUI title="Testing Wallet" core={core} plugins={[exchange, new MetamaskPlugin()]} />
|
||||
|
||||
ReactDOM.render(<BurnerWallet />, document.getElementById('root'))
|
||||
@@ -1 +0,0 @@
|
||||
/// <reference types="react-scripts" />
|
||||
@@ -1,25 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "preserve"
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
]
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
# TokenBridge Burner Wallet 2 Plugin
|
||||
|
||||
This plugin defines a Bridge trading pair to be used in the Exchange Plugin.
|
||||
|
||||
Bridge trading pairs and assets supported:
|
||||
* ETC - WETC Bridge
|
||||
|
||||
It also provides some generic resources that can be used and extended:
|
||||
* **ERC677Asset** - A representation of an Erc677 token
|
||||
* **NativeMediatorAsset** - Represents a native token that interacts with a Mediator extension.
|
||||
* **Mediator Pair** - Represents an Exchange Pair that interacts with mediators extensions.
|
||||
* **TokenBridgeGateway** - A gateway to operate with ETC, POA Sokol and POA Core networks.
|
||||
|
||||
### Install package
|
||||
```
|
||||
yarn add @poanet/tokenbridge-bw-exchange
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
```javascript
|
||||
import { Etc, Wetc, EtcGateway, WETCBridge } from '@poanet/tokenbridge-bw-exchange'
|
||||
|
||||
const core = new BurnerCore({
|
||||
...
|
||||
gateways: [new EtcGateway(), new InfuraGateway(process.env.REACT_APP_INFURA_KEY)],
|
||||
assets: [Etc, Wetc]
|
||||
})
|
||||
|
||||
const exchange = new Exchange({
|
||||
pairs: [new WETCBridge()]
|
||||
})
|
||||
```
|
||||
|
||||
This is how the exchange plugin will look like:
|
||||
|
||||

|
||||
@@ -1,40 +0,0 @@
|
||||
{
|
||||
"name": "@poanet/tokenbridge-bw-exchange",
|
||||
"version": "1.0.0",
|
||||
"license": "GPL-3.0",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
"/dist",
|
||||
"README.md"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"start-basic": "tsc -w",
|
||||
"start-local": "tsc -w",
|
||||
"test": "TS_NODE_PROJECT=\"tsconfig.testing.json\" mocha -r ts-node/register test/**/*.spec.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@burner-wallet/assets": "^1.1.10",
|
||||
"@burner-wallet/core": "^1.1.9",
|
||||
"@burner-wallet/exchange": "^1.1.4",
|
||||
"@burner-wallet/types": "^1.0.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/mocha": "^7.0.2",
|
||||
"chai": "^4.2.0",
|
||||
"mocha": "^5.2.0",
|
||||
"ts-node": "^8.8.2",
|
||||
"typescript": "^3.5.2"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/poanetwork/tokenbridge.git",
|
||||
"directory": "burner-wallet-plugin/tokenbridge-bw-exchange"
|
||||
},
|
||||
"homepage": "https://tokenbridge.net/",
|
||||
"keywords": [
|
||||
"tokenbridge",
|
||||
"burner-wallet"
|
||||
]
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
import { ERC20Asset } from '@burner-wallet/assets'
|
||||
import { ERC677_ABI } from '../../utils'
|
||||
|
||||
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'
|
||||
const BLOCK_LOOKBACK = 250
|
||||
|
||||
interface ERC677Constructor {
|
||||
abi?: object
|
||||
address: string
|
||||
id: string
|
||||
name: string
|
||||
network: string
|
||||
}
|
||||
|
||||
export default class ERC677Asset extends ERC20Asset {
|
||||
constructor({ abi = ERC677_ABI, ...params }: ERC677Constructor) {
|
||||
super({ abi, type: 'erc677', ...params })
|
||||
}
|
||||
|
||||
async _send({ from, to, value }) {
|
||||
const receipt = await this.getContract()
|
||||
.methods.transferAndCall(to, value, '0x')
|
||||
.send({ from })
|
||||
return {
|
||||
...receipt,
|
||||
txHash: receipt.transactionHash,
|
||||
id: `${receipt.transactionHash}-${receipt.events.Transfer.logIndex}`
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides ERC20Asset `startWatchingAddress` to get the `Transfer` events by topic instead of
|
||||
* the event name because ERC677 abi has two events definitions named `Transfer` and
|
||||
* `getPastEvents` method does not provide a way to choose the correct one to use.
|
||||
* @param address
|
||||
*/
|
||||
startWatchingAddress(address) {
|
||||
let block = 0
|
||||
return this.poll(async () => {
|
||||
const currentBlock = await this.getWeb3().eth.getBlockNumber()
|
||||
if (block === 0) {
|
||||
block = Math.max(currentBlock - BLOCK_LOOKBACK, 0)
|
||||
}
|
||||
|
||||
const allTransferEvents = await this.getContract().getPastEvents('allEvents', {
|
||||
fromBlock: block,
|
||||
toBlock: currentBlock,
|
||||
topics: [TRANSFER_TOPIC]
|
||||
})
|
||||
// Manually filter `to` parameter because `filter` option does not work with allEvents
|
||||
const events = allTransferEvents.filter(e => e.returnValues.to.toLowerCase() === address.toLowerCase())
|
||||
|
||||
await events.map(async event =>
|
||||
this.core.addHistoryEvent({
|
||||
id: `${event.transactionHash}-${event.logIndex}`,
|
||||
asset: this.id,
|
||||
type: 'send',
|
||||
value: event.returnValues.value.toString(),
|
||||
from: event.returnValues.from,
|
||||
to: event.returnValues.to,
|
||||
tx: event.transactionHash,
|
||||
timestamp: await this._getBlockTimestamp(event.blockNumber)
|
||||
})
|
||||
)
|
||||
|
||||
block = currentBlock
|
||||
}, this._pollInterval)
|
||||
}
|
||||
|
||||
async getTx(txHash) {
|
||||
const historyEvents = this.core.getHistoryEvents({ asset: this.id })
|
||||
const eventMatch = historyEvents.filter(e => e.tx === txHash)
|
||||
if (eventMatch.length > 0) {
|
||||
return eventMatch[0]
|
||||
} else {
|
||||
return super.getTx(txHash)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
import NativeMediatorAsset from './NativeMediatorAsset'
|
||||
import { isBridgeContract, HOME_NATIVE_TO_ERC_ABI } from '../../utils'
|
||||
|
||||
class EtcNativeAsset extends NativeMediatorAsset {
|
||||
constructor(props) {
|
||||
super({ mediatorAddress: '0x073081832B4Ecdce79d4D6753565c85Ba4b3BeA9', ...props })
|
||||
}
|
||||
|
||||
async scanMediatorEvents(address, fromBlock, toBlock) {
|
||||
const web3 = this.getWeb3()
|
||||
const contract = new web3.eth.Contract(HOME_NATIVE_TO_ERC_ABI, this.mediatorAddress)
|
||||
const listenToBridgeEvent = await isBridgeContract(contract)
|
||||
if (listenToBridgeEvent && this.mediatorAddress != '') {
|
||||
const events = await contract.getPastEvents('AffirmationCompleted', {
|
||||
fromBlock,
|
||||
toBlock
|
||||
})
|
||||
const filteredEvents = events.filter(
|
||||
event => event.returnValues.recipient.toLowerCase() === address.toLowerCase()
|
||||
)
|
||||
|
||||
for (const event of filteredEvents) {
|
||||
this.core.addHistoryEvent({
|
||||
id: `${event.transactionHash}-${event.logIndex}`,
|
||||
asset: this.id,
|
||||
type: 'send',
|
||||
value: event.returnValues.value.toString(),
|
||||
from: this.mediatorAddress,
|
||||
to: event.returnValues.recipient,
|
||||
tx: event.transactionHash,
|
||||
timestamp: await this._getBlockTimestamp(event.blockNumber)
|
||||
})
|
||||
}
|
||||
} else {
|
||||
await super.scanMediatorEvents(address, fromBlock, toBlock)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default new EtcNativeAsset({
|
||||
id: 'etc',
|
||||
name: 'ETC',
|
||||
network: '61',
|
||||
icon: 'https://user-images.githubusercontent.com/4614574/77648741-666cf800-6f47-11ea-8cb4-01b9db00c264.png'
|
||||
})
|
||||
@@ -1,65 +0,0 @@
|
||||
import { NativeAsset } from '@burner-wallet/assets'
|
||||
import { Contract, EventData } from 'web3-eth-contract'
|
||||
import { MEDIATOR_ABI } from '../../utils'
|
||||
|
||||
interface NativeMediatorConstructor {
|
||||
mediatorAddress?: string
|
||||
id: string
|
||||
name: string
|
||||
network: string
|
||||
}
|
||||
|
||||
export default class NativeMediatorAsset extends NativeAsset {
|
||||
protected mediatorAddress: string
|
||||
|
||||
constructor({ mediatorAddress = '', ...params }: NativeMediatorConstructor) {
|
||||
super({ ...params })
|
||||
this.mediatorAddress = mediatorAddress
|
||||
}
|
||||
|
||||
async scanBlocks(address, fromBlock, toBlock) {
|
||||
await super.scanBlocks(address, fromBlock, toBlock)
|
||||
await this.scanMediatorEvents(address, fromBlock, toBlock)
|
||||
}
|
||||
|
||||
async getTx(txHash) {
|
||||
const historyEvents = this.core.getHistoryEvents({ asset: this.id, account: this.mediatorAddress })
|
||||
const eventMatch = historyEvents.filter(e => e.tx === txHash)
|
||||
if (eventMatch.length > 0) {
|
||||
return eventMatch[0]
|
||||
} else {
|
||||
return super.getTx(txHash)
|
||||
}
|
||||
}
|
||||
|
||||
async scanMediatorEvents(address, fromBlock, toBlock) {
|
||||
if (this.mediatorAddress != '') {
|
||||
const web3 = this.getWeb3()
|
||||
const contract: Contract = new web3.eth.Contract(MEDIATOR_ABI, this.mediatorAddress)
|
||||
const events: EventData[] = await contract.getPastEvents('TokensBridged', {
|
||||
fromBlock,
|
||||
toBlock,
|
||||
filter: {
|
||||
recipient: address
|
||||
}
|
||||
})
|
||||
|
||||
for (const event of events) {
|
||||
this.core.addHistoryEvent({
|
||||
id: `${event.transactionHash}-${event.logIndex}`,
|
||||
asset: this.id,
|
||||
type: 'send',
|
||||
value: event.returnValues.value.toString(),
|
||||
from: this.mediatorAddress,
|
||||
to: event.returnValues.recipient,
|
||||
tx: event.transactionHash,
|
||||
timestamp: await this._getBlockTimestamp(event.blockNumber)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setMediatorAddress(mediatorAddress) {
|
||||
this.mediatorAddress = mediatorAddress
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
import { default as ERC677Asset } from './ERC677Asset'
|
||||
|
||||
export default new ERC677Asset({
|
||||
id: 'wetc',
|
||||
name: 'WETC',
|
||||
network: '1',
|
||||
address: '0x86aabcc646f290b9fc9bd05ce17c3858d1511da1'
|
||||
})
|
||||
@@ -1,7 +0,0 @@
|
||||
import NativeMediatorAsset from './NativeMediatorAsset'
|
||||
|
||||
export default new NativeMediatorAsset({
|
||||
id: 'spoa',
|
||||
name: 'sPOA',
|
||||
network: '77'
|
||||
})
|
||||
@@ -1,54 +0,0 @@
|
||||
import { Gateway } from '@burner-wallet/core/gateways'
|
||||
import Web3 from 'web3'
|
||||
|
||||
export default class TokenBridgeGateway extends Gateway {
|
||||
private readonly providers: object
|
||||
private readonly providerStrings: { [id: string]: string }
|
||||
constructor() {
|
||||
super()
|
||||
this.providerStrings = {
|
||||
'61': `https://www.ethercluster.com/etc`,
|
||||
'77': 'https://sokol.poa.network',
|
||||
'99': 'https://core.poa.network'
|
||||
}
|
||||
this.providers = {}
|
||||
}
|
||||
|
||||
isAvailable() {
|
||||
return true
|
||||
}
|
||||
|
||||
getNetworks() {
|
||||
return ['61', '77', '99']
|
||||
}
|
||||
|
||||
_provider(network) {
|
||||
if (!this.providers[network]) {
|
||||
this._makeProvider(network)
|
||||
}
|
||||
return this.providers[network]
|
||||
}
|
||||
|
||||
_makeProvider(network) {
|
||||
if (!this.providerStrings[network]) {
|
||||
throw new Error(`Network ${network} not supported by TokenBridgeGateway`)
|
||||
}
|
||||
|
||||
this.providers[network] = new Web3.providers.HttpProvider(this.providerStrings[network])
|
||||
}
|
||||
|
||||
send(network, payload) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (this.getNetworks().indexOf(network) === -1) {
|
||||
return reject(new Error('TokenBridgeGateway does not support this network'))
|
||||
}
|
||||
|
||||
this._provider(network).send(payload, (err, response) => {
|
||||
if (err) {
|
||||
return reject(err)
|
||||
}
|
||||
return resolve(response.result)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
export { default as sPOA } from './assets/sPOA'
|
||||
export { default as Etc } from './assets/Etc'
|
||||
export { default as Wetc } from './assets/Wetc'
|
||||
export { default as ERC677Asset } from './assets/ERC677Asset'
|
||||
export { default as NativeMediatorAsset } from './assets/NativeMediatorAsset'
|
||||
export { default as TokenBridgeGateway } from './gateways/TokenBridgeGateway'
|
||||
export { default as Mediator } from './pairs/Mediator'
|
||||
@@ -1,107 +0,0 @@
|
||||
import BN from 'bn.js'
|
||||
import { Bridge, EstimateReturn, ValueTypes } from '@burner-wallet/exchange'
|
||||
import { waitForEvent, constants } from '../../utils'
|
||||
import { MEDIATOR_ABI, MEDIATOR_FEE_MANAGER_ABI } from '../../utils'
|
||||
import { fromWei, toBN } from 'web3-utils'
|
||||
|
||||
interface MediatorConstructor {
|
||||
assetA: string
|
||||
assetABridge: string
|
||||
assetB: string
|
||||
assetBBridge: string
|
||||
}
|
||||
|
||||
export default class Mediator extends Bridge {
|
||||
constructor({ assetA, assetABridge, assetB, assetBBridge }: MediatorConstructor) {
|
||||
super({ assetA, assetABridge, assetB, assetBBridge })
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
async detectExchangeBToAFinished(account, value, sendResult) {
|
||||
const asset = this.getExchange().getAsset(this.assetA)
|
||||
const web3 = asset.getWeb3()
|
||||
const contract = new web3.eth.Contract(MEDIATOR_ABI, this.assetABridge)
|
||||
await waitForEvent(web3, contract, 'TokensBridged', this.processMediatorEvents(account))
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
async detectExchangeAToBFinished(account, value, sendResult) {
|
||||
const web3 = this.getExchange()
|
||||
.getAsset(this.assetB)
|
||||
.getWeb3()
|
||||
const contract = new web3.eth.Contract(MEDIATOR_ABI, this.assetBBridge)
|
||||
await waitForEvent(web3, contract, 'TokensBridged', this.processMediatorEvents(account))
|
||||
}
|
||||
|
||||
processMediatorEvents(account) {
|
||||
return events => {
|
||||
const confirmationEvent = events.filter(
|
||||
event => event.returnValues.recipient.toLowerCase() === account.toLowerCase()
|
||||
)
|
||||
return confirmationEvent.length > 0
|
||||
}
|
||||
}
|
||||
|
||||
async estimateAtoB(value: ValueTypes): Promise<EstimateReturn> {
|
||||
const web3 = this.getExchange()
|
||||
.getAsset(this.assetB)
|
||||
.getWeb3()
|
||||
|
||||
const userAmount = this._getValue(value)
|
||||
|
||||
const contract = new web3.eth.Contract(MEDIATOR_ABI, this.assetBBridge)
|
||||
const { feeAmount, feePercentage } = await this.getFee(web3, contract, userAmount)
|
||||
const finalAmount = toBN(userAmount).sub(feeAmount)
|
||||
const estimateInfo = feeAmount.isZero() ? null : `${constants.ESTIMATE_FEE_MESSAGE} Fee: ${feePercentage}%`
|
||||
|
||||
return {
|
||||
estimate: finalAmount.toString(),
|
||||
estimateInfo
|
||||
}
|
||||
}
|
||||
|
||||
async estimateBtoA(value: ValueTypes): Promise<EstimateReturn> {
|
||||
const web3 = this.getExchange()
|
||||
.getAsset(this.assetA)
|
||||
.getWeb3()
|
||||
|
||||
const userAmount = this._getValue(value)
|
||||
|
||||
const contract = new web3.eth.Contract(MEDIATOR_ABI, this.assetABridge)
|
||||
const { feeAmount, feePercentage } = await this.getFee(web3, contract, userAmount)
|
||||
const finalAmount = toBN(userAmount).sub(feeAmount)
|
||||
const estimateInfo = feeAmount.isZero() ? null : `${constants.ESTIMATE_FEE_MESSAGE} Fee: ${feePercentage}%`
|
||||
|
||||
return {
|
||||
estimate: finalAmount.toString(),
|
||||
estimateInfo
|
||||
}
|
||||
}
|
||||
|
||||
async getFee(web3, contract, value): Promise<{ feeAmount: BN; feePercentage: number }> {
|
||||
const feeManagerAddress = await this.getFeeManagerContract(contract)
|
||||
if (feeManagerAddress != constants.ZERO_ADDRESS) {
|
||||
const feeManagerContract = new web3.eth.Contract(MEDIATOR_FEE_MANAGER_ABI, feeManagerAddress)
|
||||
const fee = toBN(await feeManagerContract.methods.fee().call())
|
||||
const feePercentage = Number(fromWei(fee, 'ether')) * 100
|
||||
const feeAmount = toBN(await feeManagerContract.methods.calculateFee(value).call())
|
||||
return {
|
||||
feeAmount,
|
||||
feePercentage
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
feeAmount: toBN(0),
|
||||
feePercentage: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async getFeeManagerContract(contract) {
|
||||
try {
|
||||
return await contract.methods.feeManagerContract().call()
|
||||
} catch (e) {
|
||||
return constants.ZERO_ADDRESS
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
export { ERC677Asset, NativeMediatorAsset, sPOA, Etc, Wetc, TokenBridgeGateway, Mediator } from './burner-wallet'
|
||||
export { WETCBridge } from './wetc-bridge'
|
||||
@@ -1,5 +0,0 @@
|
||||
export { default as ERC677_ABI } from './abis/ERC677'
|
||||
export { default as FOREIGN_NATIVE_TO_ERC_ABI } from './abis/ForeignBridgeNativeToErc'
|
||||
export { default as HOME_NATIVE_TO_ERC_ABI } from './abis/HomeBridgeNativeToErc'
|
||||
export { default as MEDIATOR_ABI } from './abis/Mediator'
|
||||
export { default as MEDIATOR_FEE_MANAGER_ABI } from './abis/MediatorFeeManager'
|
||||
@@ -1,275 +0,0 @@
|
||||
export default [
|
||||
{
|
||||
constant: false,
|
||||
inputs: [
|
||||
{
|
||||
name: '_spender',
|
||||
type: 'address'
|
||||
},
|
||||
{
|
||||
name: '_value',
|
||||
type: 'uint256'
|
||||
}
|
||||
],
|
||||
name: 'approve',
|
||||
outputs: [
|
||||
{
|
||||
name: '',
|
||||
type: 'bool'
|
||||
}
|
||||
],
|
||||
payable: false,
|
||||
stateMutability: 'nonpayable',
|
||||
type: 'function'
|
||||
},
|
||||
{
|
||||
constant: true,
|
||||
inputs: [],
|
||||
name: 'totalSupply',
|
||||
outputs: [
|
||||
{
|
||||
name: '',
|
||||
type: 'uint256'
|
||||
}
|
||||
],
|
||||
payable: false,
|
||||
stateMutability: 'view',
|
||||
type: 'function'
|
||||
},
|
||||
{
|
||||
constant: false,
|
||||
inputs: [
|
||||
{
|
||||
name: '_from',
|
||||
type: 'address'
|
||||
},
|
||||
{
|
||||
name: '_to',
|
||||
type: 'address'
|
||||
},
|
||||
{
|
||||
name: '_value',
|
||||
type: 'uint256'
|
||||
}
|
||||
],
|
||||
name: 'transferFrom',
|
||||
outputs: [
|
||||
{
|
||||
name: '',
|
||||
type: 'bool'
|
||||
}
|
||||
],
|
||||
payable: false,
|
||||
stateMutability: 'nonpayable',
|
||||
type: 'function'
|
||||
},
|
||||
{
|
||||
constant: true,
|
||||
inputs: [
|
||||
{
|
||||
name: '_who',
|
||||
type: 'address'
|
||||
}
|
||||
],
|
||||
name: 'balanceOf',
|
||||
outputs: [
|
||||
{
|
||||
name: '',
|
||||
type: 'uint256'
|
||||
}
|
||||
],
|
||||
payable: false,
|
||||
stateMutability: 'view',
|
||||
type: 'function'
|
||||
},
|
||||
{
|
||||
constant: false,
|
||||
inputs: [
|
||||
{
|
||||
name: '_to',
|
||||
type: 'address'
|
||||
},
|
||||
{
|
||||
name: '_value',
|
||||
type: 'uint256'
|
||||
}
|
||||
],
|
||||
name: 'transfer',
|
||||
outputs: [
|
||||
{
|
||||
name: '',
|
||||
type: 'bool'
|
||||
}
|
||||
],
|
||||
payable: false,
|
||||
stateMutability: 'nonpayable',
|
||||
type: 'function'
|
||||
},
|
||||
{
|
||||
constant: true,
|
||||
inputs: [
|
||||
{
|
||||
name: '_owner',
|
||||
type: 'address'
|
||||
},
|
||||
{
|
||||
name: '_spender',
|
||||
type: 'address'
|
||||
}
|
||||
],
|
||||
name: 'allowance',
|
||||
outputs: [
|
||||
{
|
||||
name: '',
|
||||
type: 'uint256'
|
||||
}
|
||||
],
|
||||
payable: false,
|
||||
stateMutability: 'view',
|
||||
type: 'function'
|
||||
},
|
||||
{
|
||||
anonymous: false,
|
||||
inputs: [
|
||||
{
|
||||
indexed: true,
|
||||
name: 'from',
|
||||
type: 'address'
|
||||
},
|
||||
{
|
||||
indexed: true,
|
||||
name: 'to',
|
||||
type: 'address'
|
||||
},
|
||||
{
|
||||
indexed: false,
|
||||
name: 'value',
|
||||
type: 'uint256'
|
||||
},
|
||||
{
|
||||
indexed: false,
|
||||
name: 'data',
|
||||
type: 'bytes'
|
||||
}
|
||||
],
|
||||
name: 'Transfer',
|
||||
type: 'event'
|
||||
},
|
||||
{
|
||||
anonymous: false,
|
||||
inputs: [
|
||||
{
|
||||
indexed: true,
|
||||
name: 'owner',
|
||||
type: 'address'
|
||||
},
|
||||
{
|
||||
indexed: true,
|
||||
name: 'spender',
|
||||
type: 'address'
|
||||
},
|
||||
{
|
||||
indexed: false,
|
||||
name: 'value',
|
||||
type: 'uint256'
|
||||
}
|
||||
],
|
||||
name: 'Approval',
|
||||
type: 'event'
|
||||
},
|
||||
{
|
||||
anonymous: false,
|
||||
inputs: [
|
||||
{
|
||||
indexed: true,
|
||||
name: 'from',
|
||||
type: 'address'
|
||||
},
|
||||
{
|
||||
indexed: true,
|
||||
name: 'to',
|
||||
type: 'address'
|
||||
},
|
||||
{
|
||||
indexed: false,
|
||||
name: 'value',
|
||||
type: 'uint256'
|
||||
}
|
||||
],
|
||||
name: 'Transfer',
|
||||
type: 'event'
|
||||
},
|
||||
{
|
||||
constant: false,
|
||||
inputs: [
|
||||
{
|
||||
name: '',
|
||||
type: 'address'
|
||||
},
|
||||
{
|
||||
name: '',
|
||||
type: 'uint256'
|
||||
},
|
||||
{
|
||||
name: '',
|
||||
type: 'bytes'
|
||||
}
|
||||
],
|
||||
name: 'transferAndCall',
|
||||
outputs: [
|
||||
{
|
||||
name: '',
|
||||
type: 'bool'
|
||||
}
|
||||
],
|
||||
payable: false,
|
||||
stateMutability: 'nonpayable',
|
||||
type: 'function'
|
||||
},
|
||||
{
|
||||
constant: false,
|
||||
inputs: [
|
||||
{
|
||||
name: 'spender',
|
||||
type: 'address'
|
||||
},
|
||||
{
|
||||
name: 'addedValue',
|
||||
type: 'uint256'
|
||||
}
|
||||
],
|
||||
name: 'increaseAllowance',
|
||||
outputs: [
|
||||
{
|
||||
name: '',
|
||||
type: 'bool'
|
||||
}
|
||||
],
|
||||
payable: false,
|
||||
stateMutability: 'nonpayable',
|
||||
type: 'function'
|
||||
},
|
||||
{
|
||||
constant: false,
|
||||
inputs: [
|
||||
{
|
||||
name: 'spender',
|
||||
type: 'address'
|
||||
},
|
||||
{
|
||||
name: 'subtractedValue',
|
||||
type: 'uint256'
|
||||
}
|
||||
],
|
||||
name: 'decreaseAllowance',
|
||||
outputs: [
|
||||
{
|
||||
name: '',
|
||||
type: 'bool'
|
||||
}
|
||||
],
|
||||
payable: false,
|
||||
stateMutability: 'nonpayable',
|
||||
type: 'function'
|
||||
}
|
||||
]
|
||||
@@ -1,49 +0,0 @@
|
||||
export default [
|
||||
{
|
||||
constant: true,
|
||||
inputs: [
|
||||
{
|
||||
name: '_txHash',
|
||||
type: 'bytes32'
|
||||
}
|
||||
],
|
||||
name: 'relayedMessages',
|
||||
outputs: [
|
||||
{
|
||||
name: '',
|
||||
type: 'bool'
|
||||
}
|
||||
],
|
||||
payable: false,
|
||||
stateMutability: 'view',
|
||||
type: 'function'
|
||||
},
|
||||
{
|
||||
constant: true,
|
||||
inputs: [],
|
||||
name: 'deployedAtBlock',
|
||||
outputs: [
|
||||
{
|
||||
name: '',
|
||||
type: 'uint256'
|
||||
}
|
||||
],
|
||||
payable: false,
|
||||
stateMutability: 'view',
|
||||
type: 'function'
|
||||
},
|
||||
{
|
||||
constant: true,
|
||||
inputs: [],
|
||||
name: 'getHomeFee',
|
||||
outputs: [
|
||||
{
|
||||
name: '',
|
||||
type: 'uint256'
|
||||
}
|
||||
],
|
||||
payable: false,
|
||||
stateMutability: 'view',
|
||||
type: 'function'
|
||||
}
|
||||
]
|
||||
@@ -1,52 +0,0 @@
|
||||
export default [
|
||||
{
|
||||
anonymous: false,
|
||||
inputs: [
|
||||
{
|
||||
indexed: false,
|
||||
name: 'recipient',
|
||||
type: 'address'
|
||||
},
|
||||
{
|
||||
indexed: false,
|
||||
name: 'value',
|
||||
type: 'uint256'
|
||||
},
|
||||
{
|
||||
indexed: false,
|
||||
name: 'transactionHash',
|
||||
type: 'bytes32'
|
||||
}
|
||||
],
|
||||
name: 'AffirmationCompleted',
|
||||
type: 'event'
|
||||
},
|
||||
{
|
||||
constant: true,
|
||||
inputs: [],
|
||||
name: 'deployedAtBlock',
|
||||
outputs: [
|
||||
{
|
||||
name: '',
|
||||
type: 'uint256'
|
||||
}
|
||||
],
|
||||
payable: false,
|
||||
stateMutability: 'view',
|
||||
type: 'function'
|
||||
},
|
||||
{
|
||||
constant: true,
|
||||
inputs: [],
|
||||
name: 'getForeignFee',
|
||||
outputs: [
|
||||
{
|
||||
name: '',
|
||||
type: 'uint256'
|
||||
}
|
||||
],
|
||||
payable: false,
|
||||
stateMutability: 'view',
|
||||
type: 'function'
|
||||
}
|
||||
]
|
||||
@@ -1,38 +0,0 @@
|
||||
export default [
|
||||
{
|
||||
anonymous: false,
|
||||
inputs: [
|
||||
{
|
||||
indexed: true,
|
||||
name: 'recipient',
|
||||
type: 'address'
|
||||
},
|
||||
{
|
||||
indexed: false,
|
||||
name: 'value',
|
||||
type: 'uint256'
|
||||
},
|
||||
{
|
||||
indexed: true,
|
||||
name: 'messageId',
|
||||
type: 'bytes32'
|
||||
}
|
||||
],
|
||||
name: 'TokensBridged',
|
||||
type: 'event'
|
||||
},
|
||||
{
|
||||
constant: true,
|
||||
inputs: [],
|
||||
name: 'feeManagerContract',
|
||||
outputs: [
|
||||
{
|
||||
name: '',
|
||||
type: 'address'
|
||||
}
|
||||
],
|
||||
payable: false,
|
||||
stateMutability: 'view',
|
||||
type: 'function'
|
||||
}
|
||||
]
|
||||
@@ -1,35 +0,0 @@
|
||||
export default [
|
||||
{
|
||||
constant: true,
|
||||
inputs: [
|
||||
{
|
||||
name: '',
|
||||
type: 'uint256'
|
||||
}
|
||||
],
|
||||
name: 'calculateFee',
|
||||
outputs: [
|
||||
{
|
||||
name: '',
|
||||
type: 'uint256'
|
||||
}
|
||||
],
|
||||
payable: false,
|
||||
stateMutability: 'view',
|
||||
type: 'function'
|
||||
},
|
||||
{
|
||||
constant: true,
|
||||
inputs: [],
|
||||
name: 'fee',
|
||||
outputs: [
|
||||
{
|
||||
name: '',
|
||||
type: 'uint256'
|
||||
}
|
||||
],
|
||||
payable: false,
|
||||
stateMutability: 'view',
|
||||
type: 'function'
|
||||
}
|
||||
]
|
||||
@@ -1,8 +0,0 @@
|
||||
export { constants, wait, waitForEvent, isBridgeContract } from './utils'
|
||||
export {
|
||||
ERC677_ABI,
|
||||
FOREIGN_NATIVE_TO_ERC_ABI,
|
||||
HOME_NATIVE_TO_ERC_ABI,
|
||||
MEDIATOR_ABI,
|
||||
MEDIATOR_FEE_MANAGER_ABI
|
||||
} from './abis'
|
||||
@@ -1,40 +0,0 @@
|
||||
import { EventData, Contract } from 'web3-eth-contract'
|
||||
import { toWei } from 'web3-utils'
|
||||
|
||||
export const wait = (time: number) => new Promise(resolve => setTimeout(resolve, time))
|
||||
|
||||
export const constants = {
|
||||
EXCHANGE_TIMEOUT: 300000,
|
||||
MAX_FEE: toWei('1', 'ether'),
|
||||
ESTIMATE_FEE_MESSAGE: 'Estimation takes fee charges into consideration.',
|
||||
ZERO_ADDRESS: '0x0000000000000000000000000000000000000000'
|
||||
}
|
||||
|
||||
export const waitForEvent = async (web3, contract: Contract, event: string, callback: Function) => {
|
||||
let fromBlock = await web3.eth.getBlockNumber()
|
||||
|
||||
const stopTime = Date.now() + constants.EXCHANGE_TIMEOUT
|
||||
while (Date.now() <= stopTime) {
|
||||
const currentBlock = await web3.eth.getBlockNumber()
|
||||
const events: EventData[] = await contract.getPastEvents(event, {
|
||||
fromBlock,
|
||||
toBlock: currentBlock
|
||||
})
|
||||
const eventFound = await callback(events)
|
||||
|
||||
if (eventFound) {
|
||||
return
|
||||
}
|
||||
fromBlock = currentBlock
|
||||
await wait(10000)
|
||||
}
|
||||
}
|
||||
|
||||
export const isBridgeContract = async (contract: Contract): Promise<boolean> => {
|
||||
try {
|
||||
await contract.methods.deployedAtBlock().call()
|
||||
return true
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
import { Mediator } from '../burner-wallet'
|
||||
import { HOME_NATIVE_TO_ERC_ABI, FOREIGN_NATIVE_TO_ERC_ABI } from '../utils'
|
||||
import { waitForEvent, isBridgeContract, constants } from '../utils'
|
||||
import { ValueTypes } from '@burner-wallet/exchange'
|
||||
import { toBN, fromWei } from 'web3-utils'
|
||||
|
||||
export default class WETCBridge extends Mediator {
|
||||
constructor() {
|
||||
super({
|
||||
assetA: 'etc',
|
||||
assetABridge: '0x073081832B4Ecdce79d4D6753565c85Ba4b3BeA9',
|
||||
assetB: 'wetc',
|
||||
assetBBridge: '0x0cB781EE62F815bdD9CD4c2210aE8600d43e7040'
|
||||
})
|
||||
}
|
||||
|
||||
async detectExchangeBToAFinished(account, value, sendResult) {
|
||||
const web3 = this.getExchange()
|
||||
.getAsset(this.assetA)
|
||||
.getWeb3()
|
||||
const contract = new web3.eth.Contract(HOME_NATIVE_TO_ERC_ABI, this.assetABridge)
|
||||
const listenToBridgeEvent = await isBridgeContract(contract)
|
||||
if (listenToBridgeEvent) {
|
||||
await waitForEvent(web3, contract, 'AffirmationCompleted', this.processBridgeEvents(sendResult.txHash))
|
||||
} else {
|
||||
await super.detectExchangeBToAFinished(account, value, sendResult)
|
||||
}
|
||||
}
|
||||
|
||||
async detectExchangeAToBFinished(account, value, sendResult) {
|
||||
const web3 = this.getExchange()
|
||||
.getAsset(this.assetB)
|
||||
.getWeb3()
|
||||
const contract = new web3.eth.Contract(FOREIGN_NATIVE_TO_ERC_ABI, this.assetBBridge)
|
||||
const listenToBridgeEvent = await isBridgeContract(contract)
|
||||
if (listenToBridgeEvent) {
|
||||
await waitForEvent(web3, contract, 'RelayedMessage', this.processBridgeEvents(sendResult.txHash))
|
||||
} else {
|
||||
await super.detectExchangeAToBFinished(account, value, sendResult)
|
||||
}
|
||||
}
|
||||
|
||||
processBridgeEvents(txHash) {
|
||||
return events => {
|
||||
const confirmationEvent = events.filter(event => event.returnValues.transactionHash === txHash)
|
||||
return confirmationEvent.length > 0
|
||||
}
|
||||
}
|
||||
|
||||
async estimateAtoB(value: ValueTypes) {
|
||||
const web3 = this.getExchange()
|
||||
.getAsset(this.assetB)
|
||||
.getWeb3()
|
||||
const contract = new web3.eth.Contract(FOREIGN_NATIVE_TO_ERC_ABI, this.assetBBridge)
|
||||
|
||||
const useBridgeContract = await isBridgeContract(contract)
|
||||
|
||||
if (useBridgeContract) {
|
||||
const fee = toBN(await contract.methods.getHomeFee().call())
|
||||
const feeAmount = toBN(this._getValue(value))
|
||||
.mul(fee)
|
||||
.div(toBN(constants.MAX_FEE))
|
||||
const finalAmount = toBN(this._getValue(value)).sub(feeAmount)
|
||||
const feePercentage = Number(fromWei(fee, 'ether')) * 100
|
||||
const estimateInfo = feeAmount.isZero() ? null : `${constants.ESTIMATE_FEE_MESSAGE} Fee: ${feePercentage}%`
|
||||
|
||||
return {
|
||||
estimate: finalAmount.toString(),
|
||||
estimateInfo
|
||||
}
|
||||
} else {
|
||||
return await super.estimateAtoB(value)
|
||||
}
|
||||
}
|
||||
|
||||
async estimateBtoA(value: ValueTypes) {
|
||||
const web3 = this.getExchange()
|
||||
.getAsset(this.assetA)
|
||||
.getWeb3()
|
||||
const contract = new web3.eth.Contract(HOME_NATIVE_TO_ERC_ABI, this.assetABridge)
|
||||
|
||||
const useBridgeContract = await isBridgeContract(contract)
|
||||
|
||||
if (useBridgeContract) {
|
||||
const fee = toBN(await contract.methods.getForeignFee().call())
|
||||
const feeAmount = toBN(this._getValue(value))
|
||||
.mul(fee)
|
||||
.div(toBN(constants.MAX_FEE))
|
||||
const finalAmount = toBN(this._getValue(value)).sub(feeAmount)
|
||||
const feePercentage = Number(fromWei(fee, 'ether')) * 100
|
||||
const estimateInfo = feeAmount.isZero() ? null : `${constants.ESTIMATE_FEE_MESSAGE} Fee: ${feePercentage}%`
|
||||
return {
|
||||
estimate: finalAmount.toString(),
|
||||
estimateInfo
|
||||
}
|
||||
} else {
|
||||
return await super.estimateBtoA(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export { default as WETCBridge } from './WETCBridge'
|
||||
@@ -1,112 +0,0 @@
|
||||
import { expect } from 'chai'
|
||||
import 'mocha'
|
||||
import ERC677Asset from '../src/burner-wallet/assets/ERC677Asset'
|
||||
|
||||
const ACCOUNT1 = '0x1010101010101010101010101010101010101010'
|
||||
const ACCOUNT2 = '0x0000000000000000000000000000000000000001'
|
||||
const TX_HASH = '0x376565f5614bd4483fd716c441aff43446b50f7772bef75496edef7faa070a85'
|
||||
const ONE_ETH = '1000000000000000000'
|
||||
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'
|
||||
|
||||
describe('ERC677Asset', () => {
|
||||
it('should add an event when sent', done => {
|
||||
const asset = new ERC677Asset({
|
||||
id: 'test',
|
||||
name: 'Test',
|
||||
network: '5777',
|
||||
address: '0xcbfaa26289d24a6b4c5fe562bdd9a1b623260359'
|
||||
})
|
||||
|
||||
const testConditions = event => {
|
||||
expect(event.asset).to.equal('test')
|
||||
expect(event.type).to.equal('send')
|
||||
expect(event.value).to.equal(ONE_ETH)
|
||||
expect(event.from).to.equal(ACCOUNT2)
|
||||
expect(event.to).to.equal(ACCOUNT1)
|
||||
expect(event.id).to.equal(`${TX_HASH}-0`)
|
||||
expect(event.tx).to.equal(TX_HASH)
|
||||
done()
|
||||
}
|
||||
|
||||
const burnerCore = {
|
||||
addHistoryEvent: testConditions,
|
||||
getWeb3: () => ({
|
||||
eth: {
|
||||
methods: {},
|
||||
Contract: function Contract() {
|
||||
this.methods = {
|
||||
transferAndCall() {
|
||||
return {
|
||||
send() {
|
||||
return {
|
||||
transactionHash: TX_HASH,
|
||||
events: {
|
||||
Transfer: {
|
||||
logIndex: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
asset.setCore(burnerCore)
|
||||
asset.send({ to: ACCOUNT1, from: ACCOUNT2, value: ONE_ETH })
|
||||
})
|
||||
it('should watch an address and add events for new transactions', done => {
|
||||
const asset = new ERC677Asset({
|
||||
id: 'test',
|
||||
name: 'Test',
|
||||
network: '5777',
|
||||
address: '0xcbfaa26289d24a6b4c5fe562bdd9a1b623260359'
|
||||
})
|
||||
|
||||
const testConditions = event => {
|
||||
expect(event.asset).to.equal('test')
|
||||
expect(event.type).to.equal('send')
|
||||
expect(event.value).to.equal(ONE_ETH)
|
||||
expect(event.from).to.equal(ACCOUNT2)
|
||||
expect(event.to).to.equal(ACCOUNT1)
|
||||
expect(event.tx).to.equal(TX_HASH)
|
||||
expect(event.timestamp).to.equal(1571234034)
|
||||
done()
|
||||
}
|
||||
|
||||
const burnerCore = {
|
||||
addHistoryEvent: testConditions,
|
||||
getWeb3: () => ({
|
||||
eth: {
|
||||
getBlockNumber: () => 100,
|
||||
getBlock: () => ({ timestamp: 1571234034 }),
|
||||
Contract: function Contract() {
|
||||
// @ts-ignore
|
||||
this.getPastEvents = (eventName, { topics }) => {
|
||||
expect(eventName).to.equal('allEvents')
|
||||
expect(topics[0]).to.equal(TRANSFER_TOPIC)
|
||||
return [
|
||||
{
|
||||
event: 'Transfer',
|
||||
returnValues: {
|
||||
to: ACCOUNT1,
|
||||
from: ACCOUNT2,
|
||||
value: ONE_ETH
|
||||
},
|
||||
transactionHash: TX_HASH
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
asset.setCore(burnerCore)
|
||||
const unsubscribe = asset.startWatchingAddress(ACCOUNT1)
|
||||
unsubscribe()
|
||||
})
|
||||
})
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "src",
|
||||
"outDir": "./dist"
|
||||
},
|
||||
"include": [
|
||||
"./src"
|
||||
]
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"module": "commonjs"
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "esnext",
|
||||
"declaration": true,
|
||||
"removeComments": true,
|
||||
"noLib": false,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"esModuleInterop": true,
|
||||
"jsx": "react",
|
||||
"target": "esnext",
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"noImplicitAny": false,
|
||||
"lib": [
|
||||
"es6",
|
||||
"dom"
|
||||
]
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -13,7 +13,6 @@ const REWARDABLE_VALIDATORS_ABI = require('../contracts/build/contracts/Rewardab
|
||||
const HOME_AMB_ABI = require('../contracts/build/contracts/HomeAMB').abi
|
||||
const FOREIGN_AMB_ABI = require('../contracts/build/contracts/ForeignAMB').abi
|
||||
const BOX_ABI = require('../contracts/build/contracts/Box').abi
|
||||
const SAI_TOP = require('../contracts/build/contracts/SaiTopMock').abi
|
||||
|
||||
const { HOME_V1_ABI, FOREIGN_V1_ABI } = require('./v1Abis')
|
||||
const { BRIDGE_MODES } = require('./constants')
|
||||
@@ -93,6 +92,5 @@ module.exports = {
|
||||
ERC20_BYTES32_ABI,
|
||||
HOME_AMB_ABI,
|
||||
FOREIGN_AMB_ABI,
|
||||
BOX_ABI,
|
||||
SAI_TOP
|
||||
BOX_ABI
|
||||
}
|
||||
|
||||
@@ -17,11 +17,23 @@ const FEE_MANAGER_MODE = {
|
||||
UNDEFINED: 'UNDEFINED'
|
||||
}
|
||||
|
||||
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
|
||||
const GAS_PRICE_OPTIONS = {
|
||||
UNDEFINED: '00',
|
||||
GAS_PRICE: '01',
|
||||
SPEED: '02'
|
||||
}
|
||||
|
||||
const ORACLE_GAS_PRICE_SPEEDS = {
|
||||
SLOW: 'slow',
|
||||
STANDARD: 'standard',
|
||||
FAST: 'fast',
|
||||
INSTANT: 'instant'
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
BRIDGE_MODES,
|
||||
ERC_TYPES,
|
||||
FEE_MANAGER_MODE,
|
||||
ZERO_ADDRESS
|
||||
GAS_PRICE_OPTIONS,
|
||||
ORACLE_GAS_PRICE_SPEEDS
|
||||
}
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
const web3Utils = require('web3-utils')
|
||||
const { GAS_PRICE_OPTIONS, ORACLE_GAS_PRICE_SPEEDS } = require('./constants')
|
||||
|
||||
const gasPriceSpeedMapper = {
|
||||
'01': ORACLE_GAS_PRICE_SPEEDS.INSTANT,
|
||||
'02': ORACLE_GAS_PRICE_SPEEDS.FAST,
|
||||
'03': ORACLE_GAS_PRICE_SPEEDS.STANDARD,
|
||||
'04': ORACLE_GAS_PRICE_SPEEDS.SLOW
|
||||
}
|
||||
|
||||
function strip0x(input) {
|
||||
return input.replace(/^0x/, '')
|
||||
}
|
||||
@@ -12,11 +22,37 @@ function parseAMBMessage(message) {
|
||||
const txHash = `0x${message.slice(0, 64)}`
|
||||
const sender = `0x${message.slice(64, 104)}`
|
||||
const executor = `0x${message.slice(104, 144)}`
|
||||
const gasLimit = web3Utils.toBN(message.slice(144, 208))
|
||||
const dataType = message.slice(208, 210)
|
||||
let gasPrice = null
|
||||
let gasPriceSpeed = null
|
||||
let dataStart = 210
|
||||
|
||||
switch (dataType) {
|
||||
case GAS_PRICE_OPTIONS.GAS_PRICE:
|
||||
gasPrice = web3Utils.toBN(message.slice(210, 274))
|
||||
dataStart += 64
|
||||
break
|
||||
case GAS_PRICE_OPTIONS.SPEED:
|
||||
gasPriceSpeed = gasPriceSpeedMapper[message.slice(210, 212)]
|
||||
dataStart += 2
|
||||
break
|
||||
case GAS_PRICE_OPTIONS.UNDEFINED:
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
const data = `0x${message.slice(dataStart, message.length)}`
|
||||
|
||||
return {
|
||||
sender,
|
||||
executor,
|
||||
txHash
|
||||
txHash,
|
||||
gasLimit,
|
||||
dataType,
|
||||
gasPrice,
|
||||
gasPriceSpeed,
|
||||
data
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const { BN } = require('web3-utils')
|
||||
const { BN, toBN } = require('web3-utils')
|
||||
const { expect } = require('chai').use(require('bn-chai')(BN))
|
||||
const { parseAMBMessage, strip0x, addTxHashToData } = require('../message')
|
||||
const { ORACLE_GAS_PRICE_SPEEDS } = require('../constants')
|
||||
|
||||
describe('strip0x', () => {
|
||||
it('should remove 0x from input', () => {
|
||||
@@ -59,11 +60,66 @@ describe('parseAMBMessage', () => {
|
||||
)}${msgGasLimit}${msgDataType}${strip0x(msgData)}`
|
||||
|
||||
// when
|
||||
const { sender, executor, txHash } = parseAMBMessage(message)
|
||||
const { sender, executor, txHash, gasLimit, dataType, gasPrice, gasPriceSpeed, data } = parseAMBMessage(message)
|
||||
|
||||
// then
|
||||
expect(sender).to.be.equal(msgSender)
|
||||
expect(executor).to.be.equal(msgExecutor)
|
||||
expect(txHash).to.be.equal(msgTxHash)
|
||||
expect(gasLimit).to.eq.BN(toBN(msgGasLimit))
|
||||
expect(dataType).to.be.equal(msgDataType)
|
||||
expect(gasPrice).to.be.equal(null)
|
||||
expect(gasPriceSpeed).to.be.equal(null)
|
||||
expect(data).to.be.equal(msgData)
|
||||
})
|
||||
it('should parse data type 01', () => {
|
||||
const msgSender = '0x003667154bb32e42bb9e1e6532f19d187fa0082e'
|
||||
const msgExecutor = '0xf4bef13f9f4f2b203faf0c3cbbaabe1afe056955'
|
||||
const msgTxHash = '0xbdceda9d8c94838aca10c687da1411a07b1390e88239c0638cb9cc264219cc10'
|
||||
const msgGasLimit = '000000000000000000000000000000000000000000000000000000005b877705'
|
||||
const msgDataType = '01'
|
||||
const msgGasPrice = '0000000000000000000000000000000000000000000000000000000165a0bc00'
|
||||
const msgData = '0xb1591967aed668a4b27645ff40c444892d91bf5951b382995d4d4f6ee3a2ce03'
|
||||
const message = `0x${strip0x(msgTxHash)}${strip0x(msgSender)}${strip0x(
|
||||
msgExecutor
|
||||
)}${msgGasLimit}${msgDataType}${msgGasPrice}${strip0x(msgData)}`
|
||||
|
||||
// when
|
||||
const { sender, executor, txHash, gasLimit, dataType, gasPrice, gasPriceSpeed, data } = parseAMBMessage(message)
|
||||
|
||||
// then
|
||||
expect(sender).to.be.equal(msgSender)
|
||||
expect(executor).to.be.equal(msgExecutor)
|
||||
expect(txHash).to.be.equal(msgTxHash)
|
||||
expect(gasLimit).to.eq.BN(toBN(msgGasLimit))
|
||||
expect(dataType).to.be.equal(msgDataType)
|
||||
expect(gasPrice).to.eq.BN(toBN(msgGasPrice))
|
||||
expect(gasPriceSpeed).to.be.equal(null)
|
||||
expect(data).to.be.equal(msgData)
|
||||
})
|
||||
it('should parse data type 02', () => {
|
||||
const msgSender = '0x003667154bb32e42bb9e1e6532f19d187fa0082e'
|
||||
const msgExecutor = '0xf4bef13f9f4f2b203faf0c3cbbaabe1afe056955'
|
||||
const msgTxHash = '0xbdceda9d8c94838aca10c687da1411a07b1390e88239c0638cb9cc264219cc10'
|
||||
const msgGasLimit = '000000000000000000000000000000000000000000000000000000005b877705'
|
||||
const msgDataType = '02'
|
||||
const msgGasPriceSpeed = '0x03'
|
||||
const msgData = '0xb1591967aed668a4b27645ff40c444892d91bf5951b382995d4d4f6ee3a2ce03'
|
||||
const message = `0x${strip0x(msgTxHash)}${strip0x(msgSender)}${strip0x(
|
||||
msgExecutor
|
||||
)}${msgGasLimit}${msgDataType}${strip0x(msgGasPriceSpeed)}${strip0x(msgData)}`
|
||||
|
||||
// when
|
||||
const { sender, executor, txHash, gasLimit, dataType, gasPrice, gasPriceSpeed, data } = parseAMBMessage(message)
|
||||
|
||||
// then
|
||||
expect(sender).to.be.equal(msgSender)
|
||||
expect(executor).to.be.equal(msgExecutor)
|
||||
expect(txHash).to.be.equal(msgTxHash)
|
||||
expect(gasLimit).to.eq.BN(toBN(msgGasLimit))
|
||||
expect(dataType).to.be.equal(msgDataType)
|
||||
expect(gasPrice).to.be.equal(null)
|
||||
expect(gasPriceSpeed).to.be.equal(ORACLE_GAS_PRICE_SPEEDS.STANDARD)
|
||||
expect(data).to.be.equal(msgData)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -205,7 +205,7 @@ const normalizeGasPrice = (oracleGasPrice, factor, limits = null) => {
|
||||
// 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 = {}) => {
|
||||
const gasPriceFromOracle = async (fetchFn, options = {}) => {
|
||||
try {
|
||||
const response = await fetchFn()
|
||||
const json = await response.json()
|
||||
@@ -224,7 +224,7 @@ const gasPriceFromSupplier = async (fetchFn, options = {}) => {
|
||||
options.logger.debug &&
|
||||
options.logger.debug({ oracleGasPrice, normalizedGasPrice }, 'Gas price updated using the API')
|
||||
|
||||
return normalizedGasPrice
|
||||
return options.returnAllSpeeds ? { gasPrice: normalizedGasPrice, oracleGasPriceSpeeds: json } : normalizedGasPrice
|
||||
} catch (e) {
|
||||
options.logger && options.logger.error && options.logger.error(`Gas Price API is not available. ${e.message}`)
|
||||
}
|
||||
@@ -258,7 +258,7 @@ module.exports = {
|
||||
getPastEvents,
|
||||
getDeployedAtBlock,
|
||||
normalizeGasPrice,
|
||||
gasPriceFromSupplier,
|
||||
gasPriceFromOracle,
|
||||
gasPriceFromContract,
|
||||
gasPriceWithinLimits
|
||||
}
|
||||
|
||||
Submodule contracts updated: a7ce4441ab...bab9d9199d
@@ -1,9 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
cd $(dirname $0)
|
||||
set -e # exit when any command fails
|
||||
|
||||
while [ "$1" != "" ]; do
|
||||
docker-compose build && docker-compose run molecule_runner /bin/bash -c "molecule test --scenario-name $1"
|
||||
|
||||
shift # Shift all the parameters down by one
|
||||
done
|
||||
@@ -1,3 +0,0 @@
|
||||
---
|
||||
- import_playbook: ../../../deployment/site.yml
|
||||
- import_playbook: ./run-checks.yml
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
- name: Generate initial data for monitor
|
||||
hosts: monitor
|
||||
become: true
|
||||
tasks:
|
||||
- name: Run monitor checks
|
||||
shell: /bin/bash -c 'cd /home/poadocker/bridge/monitor/scripts; ./getBridgeStats.sh >cronWorker.out 2>cronWorker.err'
|
||||
@@ -1,59 +0,0 @@
|
||||
---
|
||||
dependency:
|
||||
name: galaxy
|
||||
driver:
|
||||
name: docker
|
||||
lint:
|
||||
name: yamllint
|
||||
enabled: True
|
||||
options:
|
||||
config-data:
|
||||
ignore: ../../hosts.yml
|
||||
platforms:
|
||||
- name: multiple-host
|
||||
groups:
|
||||
- example
|
||||
children:
|
||||
- oracle
|
||||
- monitor
|
||||
- ui
|
||||
image: ubuntu:16.04
|
||||
privileged: true
|
||||
network_mode: host
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
provisioner:
|
||||
name: ansible
|
||||
lint:
|
||||
name: ansible-lint
|
||||
enabled: True
|
||||
options:
|
||||
r: ["bug"]
|
||||
playbooks:
|
||||
prepare: ../prepare.yml
|
||||
converge: ../monitor/converge.yml
|
||||
inventory:
|
||||
host_vars:
|
||||
multiple-host:
|
||||
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
|
||||
MONITOR_PORT: 3003
|
||||
syslog_server_port: "udp://127.0.0.1:514"
|
||||
verifier:
|
||||
name: testinfra
|
||||
lint:
|
||||
name: flake8
|
||||
additional_files_or_dirs:
|
||||
- ../../tests/*
|
||||
scenario:
|
||||
name: multiple
|
||||
test_sequence:
|
||||
- lint
|
||||
- cleanup
|
||||
- destroy
|
||||
- dependency
|
||||
- syntax
|
||||
- create
|
||||
- prepare
|
||||
- converge
|
||||
- verify
|
||||
- destroy
|
||||
@@ -1,32 +0,0 @@
|
||||
import os
|
||||
import pytest
|
||||
import testinfra.utils.ansible_runner
|
||||
|
||||
testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
|
||||
os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all')
|
||||
|
||||
|
||||
@pytest.mark.parametrize("service", [
|
||||
("poabridge"),
|
||||
("tokenbridge-ui"),
|
||||
("tokenbridge-monitor")
|
||||
])
|
||||
def test_services(host, service):
|
||||
assert host.service(service).is_enabled
|
||||
assert host.service(service).is_running
|
||||
|
||||
|
||||
@pytest.mark.parametrize("name", [
|
||||
("oracle_rabbit_1"),
|
||||
("oracle_redis_1"),
|
||||
("oracle_bridge_request_1"),
|
||||
("oracle_bridge_collected_1"),
|
||||
("oracle_bridge_affirmation_1"),
|
||||
("oracle_bridge_senderhome_1"),
|
||||
("oracle_bridge_senderforeign_1"),
|
||||
("ui_ui_1"),
|
||||
("monitor_monitor_1")
|
||||
])
|
||||
def test_docker_containers(host, name):
|
||||
container = host.docker(name)
|
||||
assert container.is_running
|
||||
@@ -1,12 +0,0 @@
|
||||
---
|
||||
- name: Install Repository
|
||||
hosts: all
|
||||
become: true
|
||||
tasks:
|
||||
- import_role:
|
||||
name: ../../../deployment/roles/common
|
||||
tasks_from: repo
|
||||
# Test that running the task again works
|
||||
- import_role:
|
||||
name: ../../../deployment/roles/common
|
||||
tasks_from: repo
|
||||
@@ -1,30 +0,0 @@
|
||||
---
|
||||
driver:
|
||||
name: docker
|
||||
platforms:
|
||||
- name: repo-host
|
||||
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: ./converge.yml
|
||||
inventory:
|
||||
host_vars:
|
||||
repo-host:
|
||||
bridge_repo_branch: master
|
||||
verifier:
|
||||
name: testinfra
|
||||
scenario:
|
||||
name: repo
|
||||
test_sequence:
|
||||
- destroy
|
||||
- create
|
||||
- prepare
|
||||
- converge
|
||||
- verify
|
||||
- destroy
|
||||
@@ -1,49 +0,0 @@
|
||||
import os
|
||||
import pytest
|
||||
import testinfra.utils.ansible_runner
|
||||
|
||||
testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
|
||||
os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all')
|
||||
|
||||
|
||||
@pytest.mark.parametrize("path", [
|
||||
("/home/poadocker"),
|
||||
("/home/poadocker/bridge"),
|
||||
("/home/poadocker/bridge/commons"),
|
||||
("/home/poadocker/bridge/e2e-commons"),
|
||||
("/home/poadocker/bridge/deployment"),
|
||||
("/home/poadocker/bridge/contracts"),
|
||||
("/home/poadocker/bridge/oracle"),
|
||||
("/home/poadocker/bridge/monitor"),
|
||||
("/home/poadocker/bridge/ui"),
|
||||
("/home/poadocker/bridge/parity")
|
||||
])
|
||||
def test_existing_folders(host, path):
|
||||
assert host.file(path).exists
|
||||
assert host.file(path).is_directory
|
||||
|
||||
|
||||
@pytest.mark.parametrize("path", [
|
||||
("/home/poadocker/bridge/package.json"),
|
||||
("/home/poadocker/bridge/commons/package.json"),
|
||||
("/home/poadocker/bridge/contracts/package.json"),
|
||||
("/home/poadocker/bridge/oracle/package.json"),
|
||||
("/home/poadocker/bridge/monitor/package.json"),
|
||||
("/home/poadocker/bridge/ui/package.json")
|
||||
])
|
||||
def test_existing_package_json(host, path):
|
||||
assert host.file(path).exists
|
||||
assert host.file(path).is_file
|
||||
|
||||
|
||||
@pytest.mark.parametrize("path", [
|
||||
("/home/poadocker/bridge/Dockerfile.e2e"),
|
||||
("/home/poadocker/bridge/contracts/Dockerfile"),
|
||||
("/home/poadocker/bridge/parity/Dockerfile"),
|
||||
("/home/poadocker/bridge/oracle/Dockerfile"),
|
||||
("/home/poadocker/bridge/monitor/Dockerfile"),
|
||||
("/home/poadocker/bridge/ui/Dockerfile")
|
||||
])
|
||||
def test_existing_docker_files(host, path):
|
||||
assert host.file(path).exists
|
||||
assert host.file(path).is_file
|
||||
@@ -1,23 +0,0 @@
|
||||
import os
|
||||
import pytest
|
||||
import testinfra.utils.ansible_runner
|
||||
|
||||
testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
|
||||
os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all')
|
||||
|
||||
|
||||
@pytest.mark.parametrize("path", [
|
||||
("/home/poadocker/bridge/node_modules"),
|
||||
("/home/poadocker/bridge/ui/node_modules"),
|
||||
("/home/poadocker/bridge/oracle/node_modules"),
|
||||
("/home/poadocker/bridge/monitor/node_modules"),
|
||||
("/home/poadocker/bridge/contracts/node_modules"),
|
||||
])
|
||||
def test_non_existing_node_modules(host, path):
|
||||
assert not host.file(path).exists
|
||||
|
||||
@pytest.mark.parametrize("path", [
|
||||
("/home/poadocker/bridge/.git")
|
||||
])
|
||||
def test_non_existing_git(host, path):
|
||||
assert not host.file(path).exists
|
||||
@@ -1,40 +0,0 @@
|
||||
---
|
||||
driver:
|
||||
name: docker
|
||||
platforms:
|
||||
- name: oracle-amb-host
|
||||
groups:
|
||||
- ultimate
|
||||
- amb
|
||||
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-amb-host:
|
||||
COMMON_HOME_RPC_URL: "http://parity1:8545"
|
||||
COMMON_FOREIGN_RPC_URL: "http://parity2:8545"
|
||||
ORACLE_VALIDATOR_ADDRESS: "0xaaB52d66283F7A1D5978bcFcB55721ACB467384b"
|
||||
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
|
||||
verifier:
|
||||
name: testinfra
|
||||
lint:
|
||||
name: flake8
|
||||
scenario:
|
||||
name: ultimate-amb
|
||||
test_sequence:
|
||||
- cleanup
|
||||
- destroy
|
||||
- syntax
|
||||
- create
|
||||
- prepare
|
||||
- converge
|
||||
@@ -1,26 +0,0 @@
|
||||
---
|
||||
- name: Slurp docker compose file
|
||||
slurp:
|
||||
src: "/home/poadocker/bridge/oracle/{{ file }}.yml"
|
||||
register: docker_compose_slurp
|
||||
- name: Parse docker compose file
|
||||
set_fact:
|
||||
docker_compose_parsed: "{{ docker_compose_slurp['content'] | b64decode | from_yaml }}"
|
||||
|
||||
- name: Add the external network used to connect to Parity nodes
|
||||
set_fact:
|
||||
docker_compose_parsed: "{{ docker_compose_parsed |combine({'networks': {'ultimate': {'external': 'true'}}}, recursive=True) }}"
|
||||
|
||||
- name: Add all Oracle containers to the network
|
||||
set_fact:
|
||||
docker_compose_parsed: "{{ docker_compose_parsed | combine({'services': {item: {'networks': docker_compose_parsed.services[item].networks | union(['ultimate'])}}}, recursive=True) }}"
|
||||
with_items: "{{ docker_compose_parsed.services }}"
|
||||
|
||||
- name: Expose Redis port to allow connecting from redis-cli
|
||||
set_fact:
|
||||
docker_compose_parsed: "{{ docker_compose_parsed | combine({'services': {'redis': {'ports': ['6379:6379']}}}, recursive=True) }}"
|
||||
|
||||
- name: Write updated docker file
|
||||
copy:
|
||||
content: "{{ docker_compose_parsed | to_yaml }}"
|
||||
dest: "/home/poadocker/bridge/oracle/{{ file }}.yml"
|
||||
@@ -1,35 +0,0 @@
|
||||
---
|
||||
- name: Overwrite Oracle the docker-compose
|
||||
hosts: oracle
|
||||
become: true
|
||||
tasks:
|
||||
- name: stop the service
|
||||
shell: service poabridge stop
|
||||
|
||||
- name: Build current oracle image
|
||||
shell: docker build -t oracle:ultimate-testing --file oracle/Dockerfile .
|
||||
delegate_to: 127.0.0.1
|
||||
become: false
|
||||
args:
|
||||
chdir: "{{ lookup('env', 'PWD') }}/.."
|
||||
|
||||
- name: Replace oracle image
|
||||
replace:
|
||||
path: "/home/poadocker/bridge/oracle/{{ item }}.yml"
|
||||
regexp: 'poanetwork/tokenbridge-oracle:latest'
|
||||
replace: "oracle:ultimate-testing"
|
||||
with_items:
|
||||
- docker-compose
|
||||
- docker-compose-transfer
|
||||
- docker-compose-erc-native
|
||||
|
||||
- include_tasks: oracle-add-docker-external-network.yml
|
||||
with_items:
|
||||
- docker-compose
|
||||
- docker-compose-transfer
|
||||
- docker-compose-erc-native
|
||||
loop_control:
|
||||
loop_var: file
|
||||
|
||||
- name: start the service
|
||||
shell: service poabridge start
|
||||
@@ -1,14 +0,0 @@
|
||||
# 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
|
||||
@@ -1,14 +0,0 @@
|
||||
# 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
|
||||
@@ -1,14 +0,0 @@
|
||||
# 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
|
||||
@@ -1,6 +1,6 @@
|
||||
# POA TokenBridge / Deployment Configuration
|
||||
|
||||
Please see the [Configuration](../CONFIGURATION.md) for additional configuration and execution details.
|
||||
Please see the [Oracle](../oracle/README.md) for additional configuration and execution details.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
@@ -30,7 +30,7 @@ cp hosts.yml.example hosts.yml
|
||||
hosts:
|
||||
<host_ip_A>:
|
||||
ansible_user: <user>
|
||||
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "<private_key>"
|
||||
VALIDATOR_ADDRESS_PRIVATE_KEY: "<private_key>"
|
||||
#syslog_server_port: "<protocol>://<ip>:<port>" # When this parameter is set all bridge logs will be redirected to <ip>:<port> address.
|
||||
<host_ip_B>:
|
||||
# (...)
|
||||
@@ -69,7 +69,7 @@ Example config for installing only UI:
|
||||
| `<bridge_name>` | The bridge name which tells Ansible which file to use. This is located in `group_vars/<bridge_name>.yml`. |
|
||||
| `<host_ip>` | Remote server IP address. |
|
||||
| ansible_user: `<user>` | User that will ssh into the node. This is typically `ubuntu` or `root`. |
|
||||
| ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: `"<private_key>"` | The private key for the specified validator address. |
|
||||
| VALIDATOR_ADDRESS_PRIVATE_KEY: `"<private_key>"` | The private key for the specified validator address. |
|
||||
| syslog_server_port: `"<protocol>://<ip>:<port>"` | Optional port specification for bridge logs. This value will be provided by an administrator if required. |
|
||||
|
||||
`hosts.yml` can contain multiple bridge configurations at once.
|
||||
@@ -78,10 +78,6 @@ Example config for installing only UI:
|
||||
1. Go to the group_vars folder.
|
||||
`cd group_vars`
|
||||
2. Note the <bridge_name> and add it to the hosts.yml configuration. For example, if a bridge file is named sokol-kovan.yml, you would change the <bridge_name> value in hosts.yml to sokol-kovan.
|
||||
|
||||
## Examples
|
||||
|
||||
[Deploy a monitor for multiple bridges](./MONITOR.md)
|
||||
|
||||
## Administrator Configurations
|
||||
|
||||
@@ -93,6 +89,10 @@ Example config for installing only UI:
|
||||
|
||||
2.1 `compose_service_user` - specifies the user created by the playbooks. This user runs the TokenBridge Oracle.
|
||||
|
||||
2.2 `bridge_repo` contains the address of the TokenBridge Oracle repository. The default value is https://github.com/poanetwork/tokenbridge.
|
||||
|
||||
2.3 `bridge_repo_branch` points to the specific branch or commit to use with the `bridge_repo`. If `bridge_repo_branch` is not specified, the default (`master`) branch is used.
|
||||
|
||||
2.4 `bridge_path` sets the path where the TokenBridge Oracle is installed. By default, it points. to the home folder of `compose_service_user`
|
||||
|
||||
2.5 `docker_compose_version` - specifies a version of docker-compose to be installed.
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
## Deploy multiple bridge monitor on the same host
|
||||
|
||||
If you want to deploy a monitor for different bridges, the [monitor variables](../monitor/.env.example) should be configured in `group_vars/<bridge_name>.yml` for each bridge.
|
||||
|
||||
For example, let's say we are going to deploy a monitor for xDai bridge and for WETC bridge.
|
||||
|
||||
#### Setup ansible configuration for xDai Bridge
|
||||
|
||||
First we create `hosts.yml` file to deploy the monitor for xdai bridge
|
||||
```yaml
|
||||
---
|
||||
xdai:
|
||||
children:
|
||||
monitor:
|
||||
hosts:
|
||||
<host_ip_A>:
|
||||
ansible_user: ubuntu
|
||||
```
|
||||
In `group_vars/xdai.yml`
|
||||
```
|
||||
---
|
||||
MONITOR_BRIDGE_NAME: "xdai"
|
||||
MONITOR_PORT: 3003
|
||||
MONITOR_CACHE_EVENTS: "true"
|
||||
|
||||
COMMON_HOME_RPC_URL: "https://dai.poa.network"
|
||||
COMMON_HOME_BRIDGE_ADDRESS: "0x7301CFA0e1756B71869E93d4e4Dca5c7d0eb0AA6"
|
||||
COMMON_FOREIGN_RPC_URL: "https://mainnet.infura.io/v3/INFURA_KEY"
|
||||
COMMON_FOREIGN_BRIDGE_ADDRESS: "0x4aa42145Aa6Ebf72e164C9bBC74fbD3788045016"
|
||||
|
||||
COMMON_HOME_GAS_PRICE_FALLBACK: 0
|
||||
COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL: "https://gasprice.poa.network/"
|
||||
COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE: "standard"
|
||||
COMMON_FOREIGN_GAS_PRICE_FALLBACK: 10000000000
|
||||
COMMON_FOREIGN_GAS_PRICE_FACTOR: 1
|
||||
|
||||
MONITOR_HOME_START_BLOCK: 759
|
||||
MONITOR_FOREIGN_START_BLOCK: 6478417
|
||||
MONITOR_VALIDATOR_HOME_TX_LIMIT: 0
|
||||
MONITOR_VALIDATOR_FOREIGN_TX_LIMIT: 300000
|
||||
MONITOR_TX_NUMBER_THRESHOLD: 100
|
||||
```
|
||||
|
||||
Run the playbook to deploy the monitor for xdai bridge
|
||||
```
|
||||
ansible-playbook -i hosts.yml site.yml
|
||||
```
|
||||
|
||||
This command will deploy the monitor component and enable statistics for xdai bridge.
|
||||
|
||||
#### Setup ansible configuration for WETC Bridge
|
||||
|
||||
Update `hosts.yml` file to deploy the monitor for WETC Bridge
|
||||
```yaml
|
||||
---
|
||||
wetc:
|
||||
children:
|
||||
monitor:
|
||||
hosts:
|
||||
<host_ip_A>:
|
||||
ansible_user: ubuntu
|
||||
```
|
||||
|
||||
In `group_vars/wetc.yml`
|
||||
```
|
||||
---
|
||||
MONITOR_BRIDGE_NAME: "wetc"
|
||||
MONITOR_CACHE_EVENTS: "true"
|
||||
|
||||
COMMON_HOME_RPC_URL: "https://ethereumclassic.network"
|
||||
COMMON_HOME_BRIDGE_ADDRESS: "0x073081832B4Ecdce79d4D6753565c85Ba4b3BeA9"
|
||||
COMMON_FOREIGN_RPC_URL: "https://mainnet.infura.io/v3/32e8e252699a4ac1b5dd5c1ef53cc301"
|
||||
COMMON_FOREIGN_BRIDGE_ADDRESS: "0x0cB781EE62F815bdD9CD4c2210aE8600d43e7040"
|
||||
|
||||
COMMON_HOME_GAS_PRICE_SUPPLIER_URL: "https://gasprice-etc.poa.network/"
|
||||
COMMON_HOME_GAS_PRICE_SPEED_TYPE: "standard"
|
||||
COMMON_HOME_GAS_PRICE_FALLBACK: 15000000000
|
||||
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: 10000000000
|
||||
ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
COMMON_FOREIGN_GAS_PRICE_FACTOR: 1
|
||||
|
||||
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
|
||||
```
|
||||
Given that there is a monitor component deployed in the system, the `MONITOR_PORT` variable is not needed.
|
||||
|
||||
Run the playbook to deploy the monitor for WETC Bridge
|
||||
```
|
||||
ansible-playbook -i hosts.yml site.yml
|
||||
```
|
||||
|
||||
They playbook will detect that the monitor component is already deployed in the system, so it will only generate the configuration needed to enable the WETC Bridge statistics.
|
||||
|
||||
##### Get Monitor results
|
||||
The monitor output will be available at `http://host_ip_A:MONITOR_PORT/MONITOR_BRIDGE_NAME`.
|
||||
|
||||
Given that in `xdai.env` the variable `MONITOR_BRIDGE_NAME` is set to `xdai`, the results are in the url `http://host_ip_A:3003/xdai/`.
|
||||
|
||||
Similar to the xdai case, in `wetc.env` the variable `MONITOR_BRIDGE_NAME` is set to `wetc`, so the results are in the url `http://host_ip_A:3003/wetc/`.
|
||||
@@ -16,7 +16,7 @@ Please refer to [Execution](./EXECUTION.md).
|
||||
|
||||
## Testing
|
||||
|
||||
Please refer to [Deployment-E2E](../deployment-e2e/README.md).
|
||||
Please refer to [Testing](./molecule/TESTING.md).
|
||||
|
||||
## Contributing
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
ORACLE_BRIDGE_MODE: "ARBITRARY_MESSAGE"
|
||||
COMMON_HOME_BRIDGE_ADDRESS: "0x0AEe1FCD12dDFab6265F7f8956e6E012A9Fe4Aa0"
|
||||
COMMON_FOREIGN_BRIDGE_ADDRESS: "0x0AEe1FCD12dDFab6265F7f8956e6E012A9Fe4Aa0"
|
||||
MONITOR_PORT: 3013
|
||||
@@ -1,34 +1,35 @@
|
||||
---
|
||||
## General settings
|
||||
ORACLE_BRIDGE_MODE: "ERC_TO_NATIVE"
|
||||
UI_NATIVE_TOKEN_DISPLAY_NAME: "xDai"
|
||||
BRIDGE_MODE: "ERC_TO_NATIVE"
|
||||
HOME_NATIVE_NAME: "xDai"
|
||||
|
||||
## Home contract
|
||||
COMMON_HOME_RPC_URL: "https://dai.poa.network"
|
||||
UI_HOME_NETWORK_DISPLAY_NAME: "xDai chain"
|
||||
UI_HOME_WITHOUT_EVENTS: false
|
||||
COMMON_HOME_BRIDGE_ADDRESS: "0x7301CFA0e1756B71869E93d4e4Dca5c7d0eb0AA6"
|
||||
ORACLE_HOME_RPC_POLLING_INTERVAL: 5000
|
||||
HOME_RPC_URL: "https://dai.poa.network"
|
||||
HOME_NAME: "xDai chain"
|
||||
HOME_WITHOUT_EVENTS: false
|
||||
HOME_BRIDGE_ADDRESS: "0x7301CFA0e1756B71869E93d4e4Dca5c7d0eb0AA6"
|
||||
HOME_POLLING_INTERVAL: 5000
|
||||
|
||||
## Foreign contract
|
||||
COMMON_FOREIGN_RPC_URL: "https://mainnet.infura.io"
|
||||
UI_FOREIGN_NETWORK_DISPLAY_NAME: "Ethereum Mainnet"
|
||||
UI_FOREIGN_WITHOUT_EVENTS: false
|
||||
COMMON_FOREIGN_BRIDGE_ADDRESS: "0x4aa42145Aa6Ebf72e164C9bBC74fbD3788045016"
|
||||
ORACLE_FOREIGN_RPC_POLLING_INTERVAL: 5000
|
||||
FOREIGN_RPC_URL: "https://mainnet.infura.io"
|
||||
FOREIGN_NAME: "Ethereum Mainnet"
|
||||
FOREIGN_WITHOUT_EVENTS: false
|
||||
FOREIGN_BRIDGE_ADDRESS: "0x4aa42145Aa6Ebf72e164C9bBC74fbD3788045016"
|
||||
ERC20_TOKEN_ADDRESS: "0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359"
|
||||
FOREIGN_POLLING_INTERVAL: 5000
|
||||
|
||||
## Home Gasprice
|
||||
# COMMON_HOME_GAS_PRICE_SUPPLIER_URL: "https://localhost:8888/"
|
||||
COMMON_HOME_GAS_PRICE_SPEED_TYPE: "standard"
|
||||
COMMON_HOME_GAS_PRICE_FALLBACK: 0
|
||||
COMMON_HOME_GAS_PRICE_FACTOR: 600000
|
||||
# HOME_GAS_PRICE_ORACLE_URL: "https://localhost:8888/"
|
||||
HOME_GAS_PRICE_SPEED_TYPE: "standard"
|
||||
HOME_GAS_PRICE_FALLBACK: 0
|
||||
HOME_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
|
||||
## 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
|
||||
ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
COMMON_FOREIGN_GAS_PRICE_FACTOR: 1
|
||||
FOREIGN_GAS_PRICE_ORACLE_URL: "https://gasprice.poa.network/"
|
||||
FOREIGN_GAS_PRICE_SPEED_TYPE: "standard"
|
||||
FOREIGN_GAS_PRICE_FALLBACK: 10000000000
|
||||
FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
FOREIGN_GAS_PRICE_FACTOR: 1
|
||||
|
||||
## UI
|
||||
UI_TITLE: "TokenBridge UI app - %c"
|
||||
@@ -38,15 +39,15 @@ UI_HOME_EXPLORER_TX_TEMPLATE: https://blockscout.com/poa/dai/tx/%s
|
||||
UI_FOREIGN_EXPLORER_TX_TEMPLATE: https://blockscout.com/eth/mainnet/tx/%s
|
||||
UI_HOME_EXPLORER_ADDRESS_TEMPLATE: https://blockscout.com/poa/dai/address/%s
|
||||
UI_FOREIGN_EXPLORER_ADDRESS_TEMPLATE: https://blockscout.com/eth/mainnet/address/%s
|
||||
UI_HOME_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
UI_HOME_GAS_PRICE_FALLBACK: 1000000000
|
||||
UI_FOREIGN_GAS_PRICE_FALLBACK: 10000000000
|
||||
|
||||
## Monitor
|
||||
MONITOR_BRIDGE_NAME: "xdai"
|
||||
MONITOR_PORT: 3003
|
||||
MONITOR_CACHE_EVENTS: "true"
|
||||
MONITOR_HOME_START_BLOCK: 759
|
||||
MONITOR_FOREIGN_START_BLOCK: 6478417
|
||||
MONITOR_VALIDATOR_HOME_TX_LIMIT: 300000
|
||||
MONITOR_VALIDATOR_FOREIGN_TX_LIMIT: 300000
|
||||
MONITOR_TX_NUMBER_THRESHOLD: 100
|
||||
MONITOR_HOME_DEPLOYMENT_BLOCK: 759
|
||||
MONITOR_FOREIGN_DEPLOYMENT_BLOCK: 6478417
|
||||
MONITOR_HOME_GAS_LIMIT: 300000
|
||||
MONITOR_FOREIGN_GAS_LIMIT: 300000
|
||||
MONITOR_HOME_GAS_PRICE_FALLBACK: 0
|
||||
MONITOR_FOREIGN_GAS_PRICE_FALLBACK: 10000000000
|
||||
MONITOR_LEFT_TX_THRESHOLD: 100
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
ORACLE_BRIDGE_MODE: "ERC_TO_ERC"
|
||||
COMMON_HOME_BRIDGE_ADDRESS: "0x1feB40aD9420b186F019A717c37f5546165d411E"
|
||||
COMMON_FOREIGN_BRIDGE_ADDRESS: "0x4a58D6d8D416a5fBCAcf3dC52eb8bE8948E25127"
|
||||
BRIDGE_MODE: "ERC_TO_ERC"
|
||||
HOME_BRIDGE_ADDRESS: "0x1feB40aD9420b186F019A717c37f5546165d411E"
|
||||
FOREIGN_BRIDGE_ADDRESS: "0x4a58D6d8D416a5fBCAcf3dC52eb8bE8948E25127"
|
||||
ERC20_TOKEN_ADDRESS: "0x3C665A31199694Bf723fD08844AD290207B5797f"
|
||||
UI_PORT: 3001
|
||||
MONITOR_PORT: 3011
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
ORACLE_BRIDGE_MODE: "ERC_TO_NATIVE"
|
||||
COMMON_HOME_BRIDGE_ADDRESS: "0x488Af810997eD1730cB3a3918cD83b3216E6eAda"
|
||||
COMMON_FOREIGN_BRIDGE_ADDRESS: "0x488Af810997eD1730cB3a3918cD83b3216E6eAda"
|
||||
BRIDGE_MODE: "ERC_TO_NATIVE"
|
||||
HOME_BRIDGE_ADDRESS: "0x488Af810997eD1730cB3a3918cD83b3216E6eAda"
|
||||
FOREIGN_BRIDGE_ADDRESS: "0x488Af810997eD1730cB3a3918cD83b3216E6eAda"
|
||||
ERC20_TOKEN_ADDRESS: "0x3C665A31199694Bf723fD08844AD290207B5797f"
|
||||
UI_PORT: 3002
|
||||
MONITOR_PORT: 3012
|
||||
|
||||
@@ -1,36 +1,36 @@
|
||||
---
|
||||
## General settings
|
||||
ORACLE_BRIDGE_MODE: "NATIVE_TO_ERC"
|
||||
ORACLE_LOG_LEVEL: debug
|
||||
UI_NATIVE_TOKEN_DISPLAY_NAME: "POA"
|
||||
BRIDGE_MODE: "NATIVE_TO_ERC"
|
||||
HOME_NATIVE_NAME: "POA"
|
||||
|
||||
## Home contract
|
||||
COMMON_HOME_RPC_URL: "https://sokol.poa.network"
|
||||
UI_HOME_NETWORK_DISPLAY_NAME: "POA Sokol"
|
||||
UI_HOME_WITHOUT_EVENTS: false
|
||||
COMMON_HOME_BRIDGE_ADDRESS: "0x98aFdE294f1C46aA0a27Cc4049ED337F879d8976"
|
||||
ORACLE_HOME_RPC_POLLING_INTERVAL: 5000
|
||||
HOME_RPC_URL: "https://sokol.poa.network"
|
||||
HOME_NAME: "POA Sokol"
|
||||
HOME_WITHOUT_EVENTS: false
|
||||
HOME_BRIDGE_ADDRESS: "0x98aFdE294f1C46aA0a27Cc4049ED337F879d8976"
|
||||
HOME_POLLING_INTERVAL: 5000
|
||||
|
||||
## Foreign contract
|
||||
COMMON_FOREIGN_RPC_URL: "https://sokol.poa.network"
|
||||
UI_FOREIGN_NETWORK_DISPLAY_NAME: "Kovan"
|
||||
UI_FOREIGN_WITHOUT_EVENTS: false
|
||||
COMMON_FOREIGN_BRIDGE_ADDRESS: "0x5a584f4C30B36f282848dAc9a2b20E7BEF481981"
|
||||
ORACLE_FOREIGN_RPC_POLLING_INTERVAL: 1000
|
||||
FOREIGN_RPC_URL: "https://sokol.poa.network"
|
||||
FOREIGN_NAME: "Kovan"
|
||||
FOREIGN_WITHOUT_EVENTS: false
|
||||
FOREIGN_BRIDGE_ADDRESS: "0x5a584f4C30B36f282848dAc9a2b20E7BEF481981"
|
||||
ERC20_TOKEN_ADDRESS: "0x6ef22442D600E1865AD8A8c254d6befCe7f4e6e4"
|
||||
FOREIGN_POLLING_INTERVAL: 1000
|
||||
|
||||
## Home Gasprice
|
||||
COMMON_HOME_GAS_PRICE_SUPPLIER_URL: "https://gasprice.poa.network/"
|
||||
COMMON_HOME_GAS_PRICE_SPEED_TYPE: "standard"
|
||||
COMMON_HOME_GAS_PRICE_FALLBACK: 1000000000 # in wei
|
||||
COMMON_HOME_GAS_PRICE_FACTOR: 1
|
||||
ORACLE_HOME_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
HOME_GAS_PRICE_ORACLE_URL: "https://gasprice.poa.network/"
|
||||
HOME_GAS_PRICE_SPEED_TYPE: "standard"
|
||||
HOME_GAS_PRICE_FALLBACK: 1000000000 # in wei
|
||||
HOME_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
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: 1000000000 # in wei
|
||||
COMMON_FOREIGN_GAS_PRICE_FACTOR: 1
|
||||
ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
FOREIGN_GAS_PRICE_ORACLE_URL: "https://gasprice.poa.network/"
|
||||
FOREIGN_GAS_PRICE_SPEED_TYPE: "standard"
|
||||
FOREIGN_GAS_PRICE_FALLBACK: 1000000000 # in wei
|
||||
FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
FOREIGN_GAS_PRICE_FACTOR: 1
|
||||
|
||||
## UI
|
||||
UI_TITLE: "TokenBridge UI app - %c"
|
||||
@@ -40,15 +40,15 @@ UI_HOME_EXPLORER_TX_TEMPLATE: https://blockscout.com/poa/sokol/tx/%s
|
||||
UI_FOREIGN_EXPLORER_TX_TEMPLATE: https://blockscout.com/eth/kovan/tx/%s
|
||||
UI_HOME_EXPLORER_ADDRESS_TEMPLATE: https://blockscout.com/poa/sokol/address/%s
|
||||
UI_FOREIGN_EXPLORER_ADDRESS_TEMPLATE: https://blockscout.com/eth/kovan/address/%s
|
||||
UI_HOME_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
UI_HOME_GAS_PRICE_FALLBACK: 1000000000
|
||||
UI_FOREIGN_GAS_PRICE_FALLBACK: 1000000000
|
||||
|
||||
## Monitor
|
||||
MONITOR_BRIDGE_NAME: "bridge"
|
||||
MONITOR_PORT: 3003
|
||||
MONITOR_CACHE_EVENTS: "false"
|
||||
MONITOR_HOME_START_BLOCK: 0
|
||||
MONITOR_FOREIGN_START_BLOCK: 0
|
||||
MONITOR_VALIDATOR_HOME_TX_LIMIT: 300000
|
||||
MONITOR_VALIDATOR_FOREIGN_TX_LIMIT: 300000
|
||||
MONITOR_TX_NUMBER_THRESHOLD: 100
|
||||
MONITOR_HOME_DEPLOYMENT_BLOCK: 0
|
||||
MONITOR_FOREIGN_DEPLOYMENT_BLOCK: 0
|
||||
MONITOR_HOME_GAS_LIMIT: 300000
|
||||
MONITOR_FOREIGN_GAS_LIMIT: 300000
|
||||
MONITOR_HOME_GAS_PRICE_FALLBACK: 1000000000
|
||||
MONITOR_FOREIGN_GAS_PRICE_FALLBACK: 1000000000
|
||||
MONITOR_LEFT_TX_THRESHOLD: 100
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
ORACLE_BRIDGE_MODE: "NATIVE_TO_ERC"
|
||||
COMMON_HOME_BRIDGE_ADDRESS: "0x32198D570fffC7033641F8A9094FFDCaAEF42624"
|
||||
COMMON_FOREIGN_BRIDGE_ADDRESS: "0x2B6871b9B02F73fa24F4864322CdC78604207769"
|
||||
BRIDGE_MODE: "NATIVE_TO_ERC"
|
||||
HOME_BRIDGE_ADDRESS: "0x32198D570fffC7033641F8A9094FFDCaAEF42624"
|
||||
FOREIGN_BRIDGE_ADDRESS: "0x2B6871b9B02F73fa24F4864322CdC78604207769"
|
||||
ERC20_TOKEN_ADDRESS: "0xdbeE25CbE97e4A5CC6c499875774dc7067E9426B"
|
||||
UI_PORT: 3000
|
||||
MONITOR_PORT: 3010
|
||||
|
||||
@@ -1,51 +1,56 @@
|
||||
---
|
||||
## General settings
|
||||
UI_NATIVE_TOKEN_DISPLAY_NAME: "POA"
|
||||
ORACLE_ALLOW_HTTP_FOR_RPC: yes
|
||||
ORACLE_LOG_LEVEL: debug
|
||||
# BRIDGE_MODE: ""
|
||||
HOME_NATIVE_NAME: "POA"
|
||||
ALLOW_HTTP: yes
|
||||
LOG_LEVEL: debug
|
||||
|
||||
## Home contract
|
||||
COMMON_HOME_RPC_URL: "https://sokol.poa.network"
|
||||
UI_HOME_NETWORK_DISPLAY_NAME: "POA Sokol"
|
||||
UI_HOME_WITHOUT_EVENTS: false
|
||||
ORACLE_HOME_RPC_POLLING_INTERVAL: 5000
|
||||
HOME_RPC_URL: "https://sokol.poa.network"
|
||||
HOME_NAME: "POA Sokol"
|
||||
HOME_WITHOUT_EVENTS: false
|
||||
# HOME_BRIDGE_ADDRESS: "0x32198D570fffC7033641F8A9094FFDCaAEF42624"
|
||||
HOME_POLLING_INTERVAL: 5000
|
||||
|
||||
## Foreign contract
|
||||
COMMON_FOREIGN_RPC_URL: "https://sokol.poa.network"
|
||||
UI_FOREIGN_NETWORK_DISPLAY_NAME: "Kovan"
|
||||
UI_FOREIGN_WITHOUT_EVENTS: false
|
||||
ORACLE_FOREIGN_RPC_POLLING_INTERVAL: 1000
|
||||
FOREIGN_RPC_URL: "https://sokol.poa.network"
|
||||
FOREIGN_NAME: "Kovan"
|
||||
FOREIGN_WITHOUT_EVENTS: false
|
||||
# FOREIGN_BRIDGE_ADDRESS: "0x2B6871b9B02F73fa24F4864322CdC78604207769"
|
||||
# ERC20_TOKEN_ADDRESS: "0xdbeE25CbE97e4A5CC6c499875774dc7067E9426B"
|
||||
FOREIGN_POLLING_INTERVAL: 1000
|
||||
|
||||
## Home Gasprice
|
||||
COMMON_HOME_GAS_PRICE_SUPPLIER_URL: "https://gasprice.poa.network/"
|
||||
COMMON_HOME_GAS_PRICE_SPEED_TYPE: "standard"
|
||||
COMMON_HOME_GAS_PRICE_FALLBACK: 1000000000 # in wei
|
||||
COMMON_HOME_GAS_PRICE_FACTOR: 1
|
||||
ORACLE_HOME_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
HOME_GAS_PRICE_ORACLE_URL: "https://gasprice.poa.network/"
|
||||
HOME_GAS_PRICE_SPEED_TYPE: "standard"
|
||||
HOME_GAS_PRICE_FALLBACK: 1000000000 # in wei
|
||||
HOME_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
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: 1000000000 # in wei
|
||||
COMMON_FOREIGN_GAS_PRICE_FACTOR: 1
|
||||
ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
FOREIGN_GAS_PRICE_ORACLE_URL: "https://gasprice.poa.network/"
|
||||
FOREIGN_GAS_PRICE_SPEED_TYPE: "standard"
|
||||
FOREIGN_GAS_PRICE_FALLBACK: 1000000000 # in wei
|
||||
FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
FOREIGN_GAS_PRICE_FACTOR: 1
|
||||
|
||||
|
||||
#ui
|
||||
## UI
|
||||
UI_TITLE: "TokenBridge UI app - %c"
|
||||
UI_DESCRIPTION: "The POA cross-chain bridge serves as a method of transferring POA native tokens from the POA Network to the Ethereum network in a quick and cost-efficient manner."
|
||||
# UI_PORT: 3000
|
||||
UI_HOME_EXPLORER_TX_TEMPLATE: https://blockscout.com/poa/sokol/tx/%s
|
||||
UI_FOREIGN_EXPLORER_TX_TEMPLATE: https://blockscout.com/eth/kovan/tx/%s
|
||||
UI_HOME_EXPLORER_ADDRESS_TEMPLATE: https://blockscout.com/poa/sokol/address/%s
|
||||
UI_FOREIGN_EXPLORER_ADDRESS_TEMPLATE: https://blockscout.com/eth/kovan/address/%s
|
||||
UI_HOME_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
UI_HOME_GAS_PRICE_FALLBACK: 1000000000
|
||||
UI_FOREIGN_GAS_PRICE_FALLBACK: 1000000000
|
||||
|
||||
#monitor
|
||||
MONITOR_BRIDGE_NAME: "bridge"
|
||||
MONITOR_CACHE_EVENTS: "true"
|
||||
MONITOR_HOME_START_BLOCK: 0
|
||||
MONITOR_FOREIGN_START_BLOCK: 0
|
||||
MONITOR_VALIDATOR_HOME_TX_LIMIT: 300000
|
||||
MONITOR_VALIDATOR_FOREIGN_TX_LIMIT: 300000
|
||||
MONITOR_TX_NUMBER_THRESHOLD: 100
|
||||
## Monitor
|
||||
# MONITOR_PORT: 3003
|
||||
MONITOR_HOME_DEPLOYMENT_BLOCK: 0
|
||||
MONITOR_FOREIGN_DEPLOYMENT_BLOCK: 0
|
||||
MONITOR_HOME_GAS_LIMIT: 300000
|
||||
MONITOR_FOREIGN_GAS_LIMIT: 300000
|
||||
MONITOR_HOME_GAS_PRICE_FALLBACK: 1000000000
|
||||
MONITOR_FOREIGN_GAS_PRICE_FALLBACK: 1000000000
|
||||
MONITOR_LEFT_TX_THRESHOLD: 100
|
||||
|
||||
@@ -1,35 +1,36 @@
|
||||
---
|
||||
## General settings
|
||||
ORACLE_BRIDGE_MODE: "NATIVE_TO_ERC"
|
||||
UI_NATIVE_TOKEN_DISPLAY_NAME: "ETC"
|
||||
BRIDGE_MODE: "NATIVE_TO_ERC"
|
||||
HOME_NATIVE_NAME: "ETC"
|
||||
|
||||
## Home contract
|
||||
COMMON_HOME_RPC_URL: "https://ethereumclassic.network"
|
||||
UI_HOME_NETWORK_DISPLAY_NAME: "Ethereum Classic"
|
||||
UI_HOME_WITHOUT_EVENTS: false
|
||||
COMMON_HOME_BRIDGE_ADDRESS: "0x073081832B4Ecdce79d4D6753565c85Ba4b3BeA9"
|
||||
ORACLE_HOME_RPC_POLLING_INTERVAL: 7000
|
||||
HOME_RPC_URL: "https://ethereumclassic.network"
|
||||
HOME_NAME: "Ethereum Classic"
|
||||
HOME_WITHOUT_EVENTS: false
|
||||
HOME_BRIDGE_ADDRESS: "0x073081832B4Ecdce79d4D6753565c85Ba4b3BeA9"
|
||||
HOME_POLLING_INTERVAL: 7000
|
||||
|
||||
## Foreign contract
|
||||
COMMON_FOREIGN_RPC_URL: "https://mainnet.infura.io/"
|
||||
UI_FOREIGN_NETWORK_DISPLAY_NAME: "Ethereum Mainnet"
|
||||
UI_FOREIGN_WITHOUT_EVENTS: false
|
||||
COMMON_FOREIGN_BRIDGE_ADDRESS: "0x0cB781EE62F815bdD9CD4c2210aE8600d43e7040"
|
||||
ORACLE_FOREIGN_RPC_POLLING_INTERVAL: 7000
|
||||
FOREIGN_RPC_URL: "https://mainnet.infura.io/"
|
||||
FOREIGN_NAME: "Ethereum Mainnet"
|
||||
FOREIGN_WITHOUT_EVENTS: false
|
||||
FOREIGN_BRIDGE_ADDRESS: "0x0cB781EE62F815bdD9CD4c2210aE8600d43e7040"
|
||||
ERC20_TOKEN_ADDRESS: "0x86aaBCc646f290b9Fc9Bd05CE17C3858d1511Da1"
|
||||
FOREIGN_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
|
||||
HOME_GAS_PRICE_ORACLE_URL: "https://gasprice-etc.poa.network/"
|
||||
HOME_GAS_PRICE_SPEED_TYPE: "standard"
|
||||
HOME_GAS_PRICE_FALLBACK: 15000000000 # in wei
|
||||
HOME_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
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
|
||||
FOREIGN_GAS_PRICE_ORACLE_URL: "https://gasprice.poa.network/"
|
||||
FOREIGN_GAS_PRICE_SPEED_TYPE: "standard"
|
||||
FOREIGN_GAS_PRICE_FALLBACK: 10000000000 # in wei
|
||||
FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
FOREIGN_GAS_PRICE_FACTOR: 1
|
||||
|
||||
## UI
|
||||
UI_TITLE: "TokenBridge UI app - %c"
|
||||
@@ -39,15 +40,15 @@ UI_HOME_EXPLORER_TX_TEMPLATE: https://blockscout.com/etc/mainnet/tx/%s
|
||||
UI_FOREIGN_EXPLORER_TX_TEMPLATE: https://blockscout.com/eth/mainnet/tx/%s
|
||||
UI_HOME_EXPLORER_ADDRESS_TEMPLATE: https://blockscout.com/etc/mainnet/address/%s
|
||||
UI_FOREIGN_EXPLORER_ADDRESS_TEMPLATE: https://blockscout.com/eth/mainnet/address/%s
|
||||
UI_HOME_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
UI_HOME_GAS_PRICE_FALLBACK: 15000000000
|
||||
UI_FOREIGN_GAS_PRICE_FALLBACK: 10000000000
|
||||
|
||||
## 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
|
||||
MONITOR_HOME_DEPLOYMENT_BLOCK: 7703292
|
||||
MONITOR_FOREIGN_DEPLOYMENT_BLOCK: 7412459
|
||||
MONITOR_HOME_GAS_LIMIT: 300000
|
||||
MONITOR_FOREIGN_GAS_LIMIT: 300000
|
||||
MONITOR_HOME_GAS_PRICE_FALLBACK: 15000000000
|
||||
MONITOR_FOREIGN_GAS_PRICE_FALLBACK: 10000000000
|
||||
MONITOR_LEFT_TX_THRESHOLD: 100
|
||||
|
||||
@@ -5,7 +5,7 @@ sokol-kovan:
|
||||
hosts:
|
||||
127.0.0.1:
|
||||
ansible_user: ubuntu
|
||||
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
VALIDATOR_ADDRESS_PRIVATE_KEY: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
#syslog_server_port: "udp://127.0.0.1:514"
|
||||
ui:
|
||||
hosts:
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
FROM python:3.7-stretch
|
||||
RUN curl -fsSL https://get.docker.com | sh
|
||||
RUN pip3 install docker molecule==2.22rc1 molecule[docker] flake8
|
||||
WORKDIR mono/deployment-e2e
|
||||
WORKDIR runner
|
||||
COPY . .
|
||||
@@ -33,4 +33,4 @@ ui | Deploys and checks standalone UI on Ubuntu host
|
||||
|
||||
## Ultimate E2E tests
|
||||
|
||||
For information on the Ultimate tests, please refer to [Ultimate](../e2e-commons/ULTIMATE.md).
|
||||
For information on the Ultimate tests, please refer to [Ultimate](../../e2e-commons/ULTIMATE.md).
|
||||
@@ -4,9 +4,8 @@ services:
|
||||
molecule_runner:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: deployment-e2e/Dockerfile
|
||||
dockerfile: molecule/Dockerfile
|
||||
restart: 'no'
|
||||
privileged: true
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- ..:/mono
|
||||
11
deployment/molecule/molecule.sh
Executable file
11
deployment/molecule/molecule.sh
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env bash
|
||||
cd $(dirname $0)
|
||||
set -e # exit when any command fails
|
||||
|
||||
CODEBASE_BRANCH=${CIRCLE_BRANCH-$(git symbolic-ref --short HEAD)}
|
||||
|
||||
while [ "$1" != "" ]; do
|
||||
docker-compose build && docker-compose run -e CODEBASE_BRANCH=$CODEBASE_BRANCH molecule_runner /bin/bash -c "molecule test --scenario-name $1"
|
||||
|
||||
shift # Shift all the parameters down by one
|
||||
done
|
||||
@@ -29,11 +29,11 @@ provisioner:
|
||||
r: ["bug"]
|
||||
playbooks:
|
||||
prepare: ../prepare.yml
|
||||
converge: ./converge.yml
|
||||
converge: ../../site.yml
|
||||
inventory:
|
||||
host_vars:
|
||||
monitor-host:
|
||||
MONITOR_PORT: 3003
|
||||
bridge_repo_branch: $CODEBASE_BRANCH
|
||||
syslog_server_port: "udp://127.0.0.1:514"
|
||||
verifier:
|
||||
name: testinfra
|
||||
@@ -34,14 +34,14 @@ def test_logging(host, filename):
|
||||
|
||||
def test_home_exists(host):
|
||||
assert host.run_test(
|
||||
'curl -s http://localhost:3003/bridge | '
|
||||
'curl -s http://localhost:3003 | '
|
||||
'grep -q -i "home"'
|
||||
)
|
||||
|
||||
|
||||
def test_foreign_exists(host):
|
||||
assert host.run_test(
|
||||
'curl -s http://localhost:3003/bridge | '
|
||||
'curl -s http://localhost:3003 | '
|
||||
'grep -q -i "foreign"'
|
||||
)
|
||||
|
||||
@@ -49,6 +49,6 @@ def test_foreign_exists(host):
|
||||
def test_no_error(host):
|
||||
assert host.run_expect(
|
||||
[1],
|
||||
'curl -s http://localhost:3003/bridge | '
|
||||
'curl -s http://localhost:3003 | '
|
||||
'grep -i -q "error"'
|
||||
)
|
||||
@@ -29,12 +29,13 @@ provisioner:
|
||||
r: ["bug"]
|
||||
playbooks:
|
||||
prepare: ../prepare.yml
|
||||
converge: ../../../deployment/site.yml
|
||||
converge: ../../site.yml
|
||||
inventory:
|
||||
host_vars:
|
||||
oracle-host:
|
||||
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
|
||||
VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
|
||||
syslog_server_port: "udp://127.0.0.1:514"
|
||||
bridge_repo_branch: $CODEBASE_BRANCH
|
||||
verifier:
|
||||
name: testinfra
|
||||
lint:
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user