Compare commits

..

37 Commits

Author SHA1 Message Date
Gerardo Nardelli
9d4dea9823 Fix amb subsidized mode e2e test 2019-08-22 17:35:53 -03:00
Gerardo Nardelli
2357d787a6 Fix amb subsidized mode tests in oracle-e2e 2019-08-22 17:22:49 -03:00
Gerardo Nardelli
065956e94e Fix amb subsidized mode hash in oracle-e2e 2019-08-22 17:08:49 -03:00
Gerardo Nardelli
7e651a86c4 Update oracle-e2e tests box contract addresses 2019-08-22 16:53:14 -03:00
Gerardo Nardelli
411c35d873 Fix amb packSignatures method in Oracle 2019-08-22 16:16:54 -03:00
Gerardo Nardelli
3ff096ef55 Lint fixes 2019-08-22 13:37:38 -03:00
Gerardo Nardelli
7f15733ad3 Merge fix 2019-08-22 13:30:07 -03:00
Gerardo Nardelli
d22a3e8bae Merge branch 'master' into amb-oracle
# Conflicts:
#	.prettierrc
#	commons/abis.js
#	commons/package.json
#	e2e-commons/docker-compose.yml
#	monitor/eventsStats.js
#	monitor/utils/events.js
#	oracle/src/services/gasPrice.js
#	oracle/test/gasPrice.test.js
#	yarn.lock
2019-08-22 12:10:49 -03:00
Gerardo Nardelli
43609d739d Pack signatures when processing amb collectedSignatures event in Oracle 2019-08-22 11:06:44 -03:00
Gerardo Nardelli
ab5166b895 Update submodule 2019-08-22 10:39:47 -03:00
Gerardo Nardelli
383e22cb58 Update amb message processing 2019-08-20 15:19:49 -03:00
Gerardo Nardelli
e1f20b8686 Update contract submodule 2019-08-20 15:19:09 -03:00
Gerardo Nardelli
4b59f18d29 Fix amb monitor 2019-07-30 10:05:44 -03:00
Gerardo Nardelli
2d42c236d7 Fix prettier 2019-07-25 15:28:36 -03:00
Gerardo Nardelli
ee4a6c8f5c Fix amb events in monitor 2019-07-25 14:44:05 -03:00
Gerardo Nardelli
55f8443c55 Update contract submodule 2019-07-25 14:43:14 -03:00
Gerardo Nardelli
e5ce665656 Move amb message utils to commons 2019-07-25 12:36:10 -03:00
Gerardo Nardelli
751b885f73 Support amb events info in monitor 2019-07-25 11:30:59 -03:00
Gerardo Nardelli
3d0f68fad9 Support amb balances info in monitor 2019-07-24 11:50:35 -03:00
Gerardo Nardelli
08d2c46a03 Update deployment oracle template 2019-07-23 11:35:54 -03:00
Gerardo Nardelli
48620a8d01 Update submodule to latest amb contract changes 2019-07-18 15:07:29 -03:00
Gerardo Nardelli
35c2e642ee Update amb contract submodule 2019-07-18 10:23:03 -03:00
Gerardo Nardelli
a056a75932 Update amb contract submodule 2019-07-18 09:30:40 -03:00
Gerardo Nardelli
e8a179bc19 Update contract module name 2019-07-18 09:04:10 -03:00
Gerardo Nardelli
aa32f2cc0c Update contract submodule 2019-07-18 08:39:51 -03:00
Gerardo Nardelli
473b6a3e46 Fix commons unit test 2019-07-17 12:09:55 -03:00
Gerardo Nardelli
8cf97aea3c Fix e2e-commons up script 2019-07-17 12:03:29 -03:00
Gerardo Nardelli
ac6775bd6e Lint fix 2019-07-17 11:53:43 -03:00
Gerardo Nardelli
478b30b2ed Add ARBITRARY_MESSAGE bridge mode 2019-07-17 11:49:29 -03:00
Gerardo Nardelli
70d03c1a93 Oracle amb merge fix 2019-07-17 11:47:25 -03:00
Gerardo Nardelli
0694fc24e9 Merge branch 'master' into amb-oracle
# Conflicts:
#	oracle-e2e/deploy.js
#	oracle-e2e/docker-compose.yml
#	oracle-e2e/run-tests.sh
#	oracle/config/base.config.js
#	oracle/src/services/gasPrice.js
#	oracle/src/utils/utils.js
#	oracle/test/gasPrice.test.js
2019-07-17 10:00:10 -03:00
Gerardo Nardelli
80940a0a82 Use compiled amb contracts on oracle 2019-06-04 11:25:53 -03:00
Gerardo Nardelli
a2603701b6 Merge branch 'master' into amb-oracle
# Conflicts:
#	oracle-e2e/run-tests.sh
2019-06-04 10:26:31 -03:00
Gerardo Nardelli
e006443f50 add amb oracle e2e tests 2019-06-03 16:56:53 -03:00
Gerardo Nardelli
0326745684 Update submodule to amb branch 2019-06-03 16:56:13 -03:00
Gerardo Nardelli
95f4a0acc6 use gas price from message on gas estimate for amb events 2019-05-27 16:28:29 -03:00
Gerardo Nardelli
7ca3b0079c add amb base implementation on oracle 2019-05-24 15:42:26 -03:00
429 changed files with 5647 additions and 31046 deletions

View File

@@ -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,30 +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"
- ultimate:
name: "ultimate: amb stake erc to erc"
scenario-name: ultimate-amb-stake-erc-to-erc
redis-key: amb-collected-signatures:lastProcessedBlock
ui-e2e-grep: "AMB-STAKE-ERC-TO-ERC"

View File

@@ -9,8 +9,6 @@
**/*.md
contracts/test
contracts/build
oracle/test
oracle/**/*.png
oracle/**/*.jpg
audit

View File

@@ -2,4 +2,3 @@ node_modules
submodules
coverage
lib
dist

4
.gitignore vendored
View File

@@ -6,7 +6,6 @@ coverage
# production
build
dist
# misc
.DS_Store
@@ -49,5 +48,4 @@ __pycache__
#monitor
monitor/responses/*
monitor/configs/*.env
!monitor/.gitkeep
!monitor/.gitkeep

2
.gitmodules vendored
View File

@@ -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

2
.nvmrc
View File

@@ -1 +1 @@
10.16
10.15

View File

@@ -1,75 +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_OG_TITLE | The meta title for the deployed bridge page. | 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. | core/classic/stake
UI_PUBLIC_URL | The public url for the deployed bridge page | string
## 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

View File

@@ -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 .

View File

@@ -26,13 +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 |
| [ALM](alm/README.md) | DApp interface tool for AMB Live Monitoring |
| [Burner-wallet-plugin](burner-wallet-plugin/README.md) | TokenBridge Burner Wallet 2 Plugin |
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
@@ -54,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
@@ -68,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:
@@ -91,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
@@ -110,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)

View File

@@ -1,5 +0,0 @@
COMMON_HOME_BRIDGE_ADDRESS=0xFe446bEF1DbF7AFE24E81e05BC8B271C1BA9a560
COMMON_FOREIGN_BRIDGE_ADDRESS=0xFe446bEF1DbF7AFE24E81e05BC8B271C1BA9a560
COMMON_HOME_RPC_URL=https://sokol.poa.network
COMMON_FOREIGN_RPC_URL=https://kovan.infura.io/v3/

View File

@@ -1,6 +0,0 @@
module.exports = {
extends: [
"react-app",
"../.eslintrc"
]
}

23
alm/.gitignore vendored
View File

@@ -1,23 +0,0 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*

View File

@@ -1,23 +0,0 @@
FROM node:12
WORKDIR /mono
COPY package.json .
COPY contracts/package.json ./contracts/
COPY commons/package.json ./commons/
COPY alm/package.json ./alm/
COPY yarn.lock .
RUN yarn install --production --frozen-lockfile
COPY ./contracts ./contracts
RUN yarn run compile:contracts
RUN mv ./contracts/build ./ && rm -rf ./contracts/* ./contracts/.[!.]* && mv ./build ./contracts/
COPY ./commons ./commons
COPY ./alm ./alm
ARG DOT_ENV_PATH=./alm/.env
COPY ${DOT_ENV_PATH} ./alm/.env
WORKDIR /mono/alm
CMD echo "To start the application run:" \
"yarn start"

View File

@@ -1,46 +0,0 @@
# AMB Live Monitoring
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
## Available Scripts
In the project directory, you can run:
### `yarn start`
Runs the app in the development mode.<br />
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
The page will reload if you make edits.<br />
You will also see any lint errors in the console.
### `yarn test`
Launches the test runner in the interactive watch mode.<br />
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
### `yarn build`
Builds the app for production to the `build` folder.<br />
It correctly bundles React in production mode and optimizes the build for the best performance.
The build is minified and the filenames include the hashes.<br />
Your app is ready to be deployed!
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
### `yarn eject`
**Note: this is a one-way operation. Once you `eject`, you cant go back!**
If you arent satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point youre on your own.
You dont have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldnt feel obligated to use this feature. However we understand that this tool wouldnt be useful if you couldnt customize it when you are ready for it.
## Learn More
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
To learn React, check out the [React documentation](https://reactjs.org/).

View File

@@ -1,9 +0,0 @@
const { override, disableEsLint } = require('customize-cra')
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin')
const disableModuleScopePlugin = () => config => {
config.resolve.plugins = config.resolve.plugins.filter(plugin => !(plugin instanceof ModuleScopePlugin))
return config
}
module.exports = override(disableEsLint(), disableModuleScopePlugin())

View File

@@ -1,12 +0,0 @@
---
version: '2.4'
services:
alm:
build:
context: ..
dockerfile: alm/Dockerfile
env_file: ./.env
environment:
- NODE_ENV=production
restart: unless-stopped
entrypoint: yarn start

View File

@@ -1,16 +0,0 @@
#!/bin/bash
while read line; do
if [ "$line" = "" ]; then
: # Skip empty lines
elif [[ "$line" =~ \#.* ]]; then
: # Skip comment lines
elif [[ "$line" =~ "UI_PORT"* ]]; then
eval $line
export PORT="$UI_PORT"
else
export "REACT_APP_$line"
fi
done < '.env'
$*

View File

@@ -1,45 +0,0 @@
{
"name": "alm",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2",
"@types/jest": "^24.0.0",
"@types/node": "^12.0.0",
"@types/react": "^16.9.0",
"@types/react-dom": "^16.9.0",
"customize-cra": "^1.0.0",
"react": "^16.13.1",
"react-app-rewired": "^2.1.6",
"react-dom": "^16.13.1",
"react-scripts": "3.0.1",
"typescript": "^3.5.2"
},
"scripts": {
"start": "./load-env.sh react-app-rewired start",
"build": "./load-env.sh react-app-rewired build",
"test": "react-app-rewired test",
"eject": "react-app-rewired eject",
"lint": "eslint '*/**/*.{js,ts,tsx}' --ignore-path ../.eslintignore"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"eslint-plugin-prettier": "^3.1.3"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -1,43 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
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>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

View File

@@ -1,25 +0,0 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

View File

@@ -1,3 +0,0 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

View File

@@ -1,14 +0,0 @@
.App {
text-align: center;
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}

View File

@@ -1,9 +0,0 @@
import React from 'react'
import { render } from '@testing-library/react'
import App from './App'
test('renders learn react link', () => {
const { getByText } = render(<App />)
const linkElement = getByText(/AMB Live Monitoring/i)
expect(linkElement).toBeInTheDocument()
})

View File

@@ -1,14 +0,0 @@
import React from 'react'
import './App.css'
function App() {
return (
<div className="App">
<header className="App-header">
<p>AMB Live Monitoring</p>
</header>
</div>
)
}
export default App

View File

@@ -1,8 +0,0 @@
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}

View File

@@ -1,11 +0,0 @@
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
)

View File

@@ -1 +0,0 @@
/// <reference types="react-scripts" />

View File

@@ -1,5 +0,0 @@
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom/extend-expect'

View File

@@ -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"
]
}

View File

@@ -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",
}
}
};

View File

@@ -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"]

View File

@@ -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.

View File

@@ -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

View File

@@ -1,10 +0,0 @@
{
"packages": [
"basic-wallet",
"local-wallet",
"tokenbridge-bw-exchange"
],
"npmClient": "yarn",
"useWorkspaces": true,
"version": "independent"
}

View File

@@ -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"
}
}

View File

@@ -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/

View File

@@ -1 +0,0 @@
REACT_APP_INFURA_KEY=

View File

@@ -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": {}
}

View File

@@ -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>

View File

@@ -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"
}

View File

@@ -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'))

View File

@@ -1 +0,0 @@
/// <reference types="react-scripts" />

View File

@@ -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"
]
}

View File

@@ -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

View File

@@ -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

View File

@@ -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>

View File

@@ -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"
}

View File

@@ -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'))

View File

@@ -1 +0,0 @@
/// <reference types="react-scripts" />

View File

@@ -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"
]
}

View File

@@ -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:
![exchange-wetc](https://user-images.githubusercontent.com/4614574/80991095-e40d0900-8e0d-11ea-9915-1b4e4a052694.png)

View File

@@ -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"
]
}

View File

@@ -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)
}
}
}

View File

@@ -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'
})

View File

@@ -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
}
}

View File

@@ -1,8 +0,0 @@
import { default as ERC677Asset } from './ERC677Asset'
export default new ERC677Asset({
id: 'wetc',
name: 'WETC',
network: '1',
address: '0x86aabcc646f290b9fc9bd05ce17c3858d1511da1'
})

View File

@@ -1,7 +0,0 @@
import NativeMediatorAsset from './NativeMediatorAsset'
export default new NativeMediatorAsset({
id: 'spoa',
name: 'sPOA',
network: '77'
})

View File

@@ -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)
})
})
}
}

View File

@@ -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'

View File

@@ -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
}
}
}

View File

@@ -1,2 +0,0 @@
export { ERC677Asset, NativeMediatorAsset, sPOA, Etc, Wetc, TokenBridgeGateway, Mediator } from './burner-wallet'
export { WETCBridge } from './wetc-bridge'

View File

@@ -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'

View File

@@ -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'
}
]

View File

@@ -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'
}
]

View File

@@ -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'
}
]

View File

@@ -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'
}
]

View File

@@ -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'
}
]

View File

@@ -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'

View File

@@ -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
}
}

View File

@@ -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)
}
}
}

View File

@@ -1 +0,0 @@
export { default as WETCBridge } from './WETCBridge'

View File

@@ -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()
})
})

View File

@@ -1,10 +0,0 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "./dist"
},
"include": [
"./src"
]
}

View File

@@ -1,6 +0,0 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"module": "commonjs"
}
}

View File

@@ -1,30 +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"
],
"types" : [
"node"
]
},
"exclude": [
"node_modules",
"**/*.spec.ts"
]
}

File diff suppressed because it is too large Load Diff

View File

@@ -7,17 +7,12 @@ const FOREIGN_ERC_TO_NATIVE_ABI = require('../contracts/build/contracts/ForeignB
const ERC20_ABI = require('../contracts/build/contracts/ERC20').abi
const ERC677_ABI = require('../contracts/build/contracts/ERC677').abi
const ERC677_BRIDGE_TOKEN_ABI = require('../contracts/build/contracts/ERC677BridgeToken').abi
const BLOCK_REWARD_ABI = require('../contracts/build/contracts/BlockReward').abi
const BLOCK_REWARD_ABI = require('../contracts/build/contracts/IBlockReward').abi
const BRIDGE_VALIDATORS_ABI = require('../contracts/build/contracts/BridgeValidators').abi
const REWARDABLE_VALIDATORS_ABI = require('../contracts/build/contracts/RewardableValidators').abi
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_AMB_ERC_TO_ERC_ABI = require('../contracts/build/contracts/HomeAMBErc677ToErc677').abi
const FOREIGN_AMB_ERC_TO_ERC_ABI = require('../contracts/build/contracts/ForeignAMBErc677ToErc677').abi
const HOME_STAKE_ERC_TO_ERC_ABI = require('../contracts/build/contracts/HomeStakeTokenMediator').abi
const FOREIGN_STAKE_ERC_TO_ERC_ABI = require('../contracts/build/contracts/ForeignStakeTokenMediator').abi
const { HOME_V1_ABI, FOREIGN_V1_ABI } = require('./v1Abis')
const { BRIDGE_MODES } = require('./constants')
@@ -71,12 +66,6 @@ function getBridgeABIs(bridgeMode) {
} else if (bridgeMode === BRIDGE_MODES.ARBITRARY_MESSAGE) {
HOME_ABI = HOME_AMB_ABI
FOREIGN_ABI = FOREIGN_AMB_ABI
} else if (bridgeMode === BRIDGE_MODES.AMB_ERC_TO_ERC) {
HOME_ABI = HOME_AMB_ERC_TO_ERC_ABI
FOREIGN_ABI = FOREIGN_AMB_ERC_TO_ERC_ABI
} else if (bridgeMode === BRIDGE_MODES.STAKE_AMB_ERC_TO_ERC) {
HOME_ABI = HOME_STAKE_ERC_TO_ERC_ABI
FOREIGN_ABI = FOREIGN_STAKE_ERC_TO_ERC_ABI
} else {
throw new Error(`Unrecognized bridge mode: ${bridgeMode}`)
}
@@ -103,8 +92,5 @@ module.exports = {
ERC20_BYTES32_ABI,
HOME_AMB_ABI,
FOREIGN_AMB_ABI,
BOX_ABI,
SAI_TOP,
HOME_STAKE_ERC_TO_ERC_ABI,
FOREIGN_STAKE_ERC_TO_ERC_ABI
BOX_ABI
}

View File

@@ -3,9 +3,7 @@ const BRIDGE_MODES = {
ERC_TO_ERC: 'ERC_TO_ERC',
ERC_TO_NATIVE: 'ERC_TO_NATIVE',
NATIVE_TO_ERC_V1: 'NATIVE_TO_ERC_V1',
ARBITRARY_MESSAGE: 'ARBITRARY_MESSAGE',
AMB_ERC_TO_ERC: 'AMB_ERC_TO_ERC',
STAKE_AMB_ERC_TO_ERC: 'STAKE_AMB_ERC_TO_ERC'
ARBITRARY_MESSAGE: 'ARBITRARY_MESSAGE'
}
const ERC_TYPES = {
@@ -16,15 +14,26 @@ const ERC_TYPES = {
const FEE_MANAGER_MODE = {
ONE_DIRECTION: 'ONE_DIRECTION',
BOTH_DIRECTIONS: 'BOTH_DIRECTIONS',
ONE_DIRECTION_STAKE: 'ONE_DIRECTION_STAKE',
UNDEFINED: 'UNDEFINED'
}
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
const 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
}

View File

@@ -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/, '')
}
@@ -9,14 +19,40 @@ function addTxHashToData({ encodedData, transactionHash }) {
function parseAMBMessage(message) {
message = strip0x(message)
const messageId = `0x${message.slice(0, 64)}`
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,
messageId
txHash,
gasLimit,
dataType,
gasPrice,
gasPriceSpeed,
data
}
}

View File

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

View File

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

View File

@@ -1,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', () => {
@@ -50,20 +51,75 @@ describe('parseAMBMessage', () => {
it('should parse data type 00', () => {
const msgSender = '0x003667154bb32e42bb9e1e6532f19d187fa0082e'
const msgExecutor = '0xf4bef13f9f4f2b203faf0c3cbbaabe1afe056955'
const msgId = '0xbdceda9d8c94838aca10c687da1411a07b1390e88239c0638cb9cc264219cc10'
const msgTxHash = '0xbdceda9d8c94838aca10c687da1411a07b1390e88239c0638cb9cc264219cc10'
const msgGasLimit = '000000000000000000000000000000000000000000000000000000005b877705'
const msgDataType = '00'
const msgData = '0xb1591967aed668a4b27645ff40c444892d91bf5951b382995d4d4f6ee3a2ce03'
const message = `0x${strip0x(msgId)}${strip0x(msgSender)}${strip0x(
const message = `0x${strip0x(msgTxHash)}${strip0x(msgSender)}${strip0x(
msgExecutor
)}${msgGasLimit}${msgDataType}${strip0x(msgData)}`
// when
const { sender, executor, messageId } = 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(messageId).to.be.equal(msgId)
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)
})
})

View File

@@ -12,10 +12,6 @@ function decodeBridgeMode(bridgeModeHash) {
return BRIDGE_MODES.ERC_TO_NATIVE
case '0x2544fbb9':
return BRIDGE_MODES.ARBITRARY_MESSAGE
case '0x16ea01e9':
return BRIDGE_MODES.STAKE_AMB_ERC_TO_ERC
case '0x76595b56':
return BRIDGE_MODES.AMB_ERC_TO_ERC
default:
throw new Error(`Unrecognized bridge mode hash: '${bridgeModeHash}'`)
}
@@ -50,31 +46,10 @@ const getTokenType = async (bridgeTokenContract, bridgeAddress) => {
return ERC_TYPES.ERC20
}
} catch (e) {
try {
const isBridge = await bridgeTokenContract.methods.isBridge(bridgeAddress).call()
if (isBridge) {
return ERC_TYPES.ERC677
} else {
return ERC_TYPES.ERC20
}
} catch (e) {
return ERC_TYPES.ERC20
}
return ERC_TYPES.ERC20
}
}
const isErcToErcMode = bridgeMode => {
return (
bridgeMode === BRIDGE_MODES.ERC_TO_ERC ||
bridgeMode === BRIDGE_MODES.AMB_ERC_TO_ERC ||
bridgeMode === BRIDGE_MODES.STAKE_AMB_ERC_TO_ERC
)
}
const isMediatorMode = bridgeMode => {
return bridgeMode === BRIDGE_MODES.AMB_ERC_TO_ERC || bridgeMode === BRIDGE_MODES.STAKE_AMB_ERC_TO_ERC
}
const getUnit = bridgeMode => {
let unitHome = null
let unitForeign = null
@@ -87,9 +62,6 @@ const getUnit = bridgeMode => {
} else if (bridgeMode === BRIDGE_MODES.ERC_TO_NATIVE) {
unitHome = 'Native coins'
unitForeign = 'Tokens'
} else if (bridgeMode === BRIDGE_MODES.STAKE_AMB_ERC_TO_ERC) {
unitHome = 'Tokens'
unitForeign = 'Tokens'
} else {
throw new Error(`Unrecognized bridge mode: ${bridgeMode}`)
}
@@ -233,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()
@@ -252,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}`)
}
@@ -286,9 +258,7 @@ module.exports = {
getPastEvents,
getDeployedAtBlock,
normalizeGasPrice,
gasPriceFromSupplier,
gasPriceFromOracle,
gasPriceFromContract,
gasPriceWithinLimits,
isErcToErcMode,
isMediatorMode
gasPriceWithinLimits
}

View File

@@ -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

View File

@@ -1,3 +0,0 @@
---
- import_playbook: ../../../deployment/site.yml
- import_playbook: ./run-checks.yml

View File

@@ -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'

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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

View File

@@ -1,54 +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
- name: ui-amb-stake-erc-to-erc-host
groups:
- ultimate
- amb-stake-erc-to-erc
children:
- ui
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"
ui-amb-stake-erc-to-erc-host:
COMMON_HOME_RPC_URL: "http://localhost:8541"
COMMON_FOREIGN_RPC_URL: "http://localhost:8542"
verifier:
name: testinfra
lint:
name: flake8
scenario:
name: ultimate-amb-stake-erc-to-erc
test_sequence:
- cleanup
- destroy
- syntax
- create
- prepare
- converge

View File

@@ -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

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