Compare commits

..

32 Commits

Author SHA1 Message Date
Alexander Kolotov
4117f29a74 Merge the develop branch to the master branch, preparation to v2.1.0 2020-05-07 22:32:05 +03:00
dependabot[bot]
1921087ad1 Bump acorn from 5.7.3 to 5.7.4 (#305) 2020-05-07 20:48:59 +03:00
Kirill Fedoseev
b4abbc4910 Cache monitor RPC calls to increase performance (#322) 2020-05-07 20:42:27 +03:00
Alexander Kolotov
bcbe34a839 Update the contract's submodule to the release 5.0.0-rc0 (#321) 2020-05-05 20:03:12 +03:00
Gerardo Nardelli
738442e4cf Add Burner Wallet Plugin for WETC Bridge (#306) 2020-05-04 23:35:46 +03:00
Gerardo Nardelli
64c5a5670f Update contract's submodule and e2e tests (#313) 2020-04-24 21:01:07 +03:00
Gerardo Nardelli
c8c589536b Fix monitor balances displayed for erc to native (#312) 2020-04-18 21:30:38 +03:00
Gerardo Nardelli
7b0edff624 Update monitor half duplex transfer filter (#311) 2020-04-16 23:19:03 +03:00
Alexander Kolotov
b02b879b02 Update the contract's submodule to the release 4.1.0 (#307) 2020-04-09 17:34:37 +03:00
Alexander Kolotov
5b4b01a79b Merge the develop branch to the master branch, preparation to v2.0.0 2020-03-23 16:43:32 +03:00
Alexander Kolotov
881fafe9a8 Update the contract's submodule to the release 4.0.1 (#301) 2020-03-14 00:22:52 +03:00
Kirill Fedoseev
c1ed6f21e6 Correct handling of Chai to Dai swaps in oracle and monitor components (#302) 2020-03-13 01:12:48 +03:00
Alexander Kolotov
8ae0fa82d5 Merge the develop branch to the master branch, preparation to v2.0.0-rc1 2020-02-21 18:42:19 +03:00
Alexander Kolotov
dbf3d3d90d Composer files to build oracle and monitor docker images (#299) 2020-02-21 16:58:05 +03:00
Alexander Kolotov
8977ed6d3b Removal of putting .env file into the docker image for monitor (#289) 2020-02-21 16:56:55 +03:00
Alexander Kolotov
df0dc1c313 Update the contract's submodule to the release 4.0.0-rc1 (#298) 2020-02-21 10:17:18 +03:00
Gerardo Nardelli
7b2bebbcf0 Update metamask extension in ui e2e tests (#297) 2020-02-20 22:13:18 +03:00
Kirill Fedoseev
85104d67c0 Support of Chai token by monitor in erc-to-native (#287) 2020-02-18 19:17:01 +03:00
Kirill Fedoseev
2a3d7c8e08 Oracle support for erc-to-native with Chai integrated (#286) 2020-02-17 23:48:43 +03:00
Kirill Fedoseev
e6052f162a Fix some of the possibles failure reasons in e2e tests (#294) 2020-02-11 20:50:34 +03:00
Gerardo Nardelli
52ed4e85e2 Upgrade pip version in deployment common (#296) 2020-02-10 19:31:36 +03:00
Alexander Kolotov
bc6dd13193 Merge the develop branch to the master branch, preparation to v2.0.0-rc0 2020-02-04 14:33:16 +03:00
Gerardo Nardelli
bce1e6509e Use monitor docker hub image for monitor deployment (#284) 2020-02-04 08:16:27 +03:00
Gerardo Nardelli
52358d477b Use oracle docker hub image for oracle deployment (#280) 2020-02-04 00:48:28 +03:00
Gerardo Nardelli
232f807e9d Add ultimate e2e tests for AMB (#285) 2020-02-03 19:39:21 +03:00
Gerardo Nardelli
fe4a569e34 Update monitor check-all script to generate stuckTransfers statistics for v1 bridges (#279) 2020-02-03 15:50:18 +03:00
Gerardo Nardelli
c408d57716 Add custom response for favicon resource in monitor (#278) 2020-02-03 15:48:28 +03:00
Gerardo Nardelli
7fcb118c8c Add deployment test scenario 3 components on 1 host (#277) 2020-02-03 15:47:44 +03:00
Alexander Kolotov
1eaf774e33 Update the contract's submodule to the release 4.0.0-rc0 (#276) 2020-01-22 22:51:28 +03:00
Kirill Fedoseev
8650ba4d21 Updated oracle watchers to use blob version of execute signatures (#269) 2020-01-21 00:11:26 +03:00
Gerardo Nardelli
edc51c78e2 Use 3 validators in oracle e2e tests (#264) 2020-01-20 23:00:04 +03:00
Gerardo Nardelli
612f130544 Fix remote server loop var name in deployment (#275) 2020-01-20 22:53:20 +03:00
151 changed files with 26578 additions and 927 deletions

View File

@@ -11,7 +11,7 @@ orbs:
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
@@ -89,29 +89,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 +143,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 +161,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:
@@ -194,7 +194,7 @@ jobs:
steps:
- checkout
- run: git submodule update --init
- run:
- run:
name: Run the scenario
command: deployment-e2e/molecule.sh monitor
no_output_timeout: 40m
@@ -210,7 +210,15 @@ jobs:
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
ultimate:
executor: tokenbridge-orb/machine-with-docker-caching
parameters:
@@ -222,6 +230,11 @@ 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
@@ -232,16 +245,24 @@ jobs:
- tokenbridge-orb/yarn-install-cached-on-machine
- run:
name: Prepare the infrastructure
command: e2e-commons/up.sh deploy << parameters.scenario-name >>
command: e2e-commons/up.sh deploy << parameters.scenario-name >> blocks
no_output_timeout: 50m
- tokenbridge-orb/wait-for-oracle:
redis-key: << parameters.redis-key >>
- 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
- when:
condition: << parameters.ui-e2e-grep >>
steps:
- run:
name: Run the ui-e2e tests
command: |
nvm use default;
cd ui-e2e; yarn mocha -g "<< parameters.ui-e2e-grep >>" -b ./test.js
- when:
condition: << parameters.oracle-e2e-script >>
steps:
- run:
name: Run the oracle-e2e tests
command: cd e2e-commons && docker-compose run e2e yarn workspace oracle-e2e run << parameters.oracle-e2e-script >>
workflows:
tokenbridge:
jobs:
@@ -272,18 +293,24 @@ workflows:
- 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"

View File

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

3
.gitignore vendored
View File

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

View File

@@ -70,3 +70,4 @@ MONITOR_VALIDATOR_FOREIGN_TX_LIMIT | Average gas usage of a transaction sent by
MONITOR_TX_NUMBER_THRESHOLD | If estimated number of transaction is equal to or below this value, the monitor will report that the validator has less funds than it is required. | integer
MONITOR_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

@@ -66,11 +66,13 @@ Clone the repository:
git clone https://github.com/poanetwork/tokenbridge
```
Initialize submodules, install dependencies, compile the Smart Contracts:
If there is no need to build docker images for the TokenBridge components (oracle, monitor, UI), 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:

View File

@@ -0,0 +1,31 @@
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

@@ -0,0 +1,30 @@
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

@@ -0,0 +1,41 @@
# 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

@@ -0,0 +1,17 @@
---
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

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

View File

@@ -0,0 +1,28 @@
{
"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

@@ -0,0 +1,36 @@
## 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

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

View File

@@ -0,0 +1,40 @@
{
"name": "staging",
"version": "0.1.0",
"private": true,
"dependencies": {
"@burner-wallet/assets": "^1.1.10",
"@burner-wallet/core": "^1.1.0",
"@burner-wallet/exchange": "^1.1.4",
"@burner-wallet/metamask-plugin": "^1.0.0",
"@burner-wallet/modern-ui": "^1.0.7",
"@poanet/tokenbridge-bw-exchange": "^1.0.0",
"@types/node": "12.0.4",
"@types/react": "*",
"@types/react-dom": "16.8.4",
"@types/react-router-dom": "^4.3.3",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-scripts": "3.0.1",
"typescript": "3.5.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@@ -0,0 +1,38 @@
<!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

@@ -0,0 +1,15 @@
{
"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

@@ -0,0 +1,21 @@
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

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

View File

@@ -0,0 +1,25 @@
{
"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

@@ -0,0 +1,14 @@
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

@@ -0,0 +1,43 @@
{
"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.

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@@ -0,0 +1,38 @@
<!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

@@ -0,0 +1,15 @@
{
"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

@@ -0,0 +1,73 @@
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

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

View File

@@ -0,0 +1,25 @@
{
"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

@@ -0,0 +1,37 @@
# 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

@@ -0,0 +1,40 @@
{
"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

@@ -0,0 +1,79 @@
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

@@ -0,0 +1,45 @@
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

@@ -0,0 +1,65 @@
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

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

View File

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

View File

@@ -0,0 +1,54 @@
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

@@ -0,0 +1,7 @@
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

@@ -0,0 +1,107 @@
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

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

View File

@@ -0,0 +1,5 @@
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

@@ -0,0 +1,275 @@
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

@@ -0,0 +1,49 @@
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

@@ -0,0 +1,52 @@
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

@@ -0,0 +1,38 @@
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

@@ -0,0 +1,35 @@
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

@@ -0,0 +1,8 @@
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

@@ -0,0 +1,40 @@
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

@@ -0,0 +1,100 @@
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

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

View File

@@ -0,0 +1,112 @@
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

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

View File

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

View File

@@ -0,0 +1,27 @@
{
"compilerOptions": {
"module": "esnext",
"declaration": true,
"removeComments": true,
"noLib": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"esModuleInterop": true,
"jsx": "react",
"target": "esnext",
"sourceMap": true,
"strict": true,
"allowSyntheticDefaultImports": true,
"moduleResolution": "node",
"resolveJsonModule": true,
"noImplicitAny": false,
"lib": [
"es6",
"dom"
]
},
"exclude": [
"node_modules",
"**/*.spec.ts"
]
}

15931
burner-wallet-plugin/yarn.lock Normal file

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -0,0 +1,59 @@
---
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

@@ -0,0 +1,32 @@
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

@@ -9,7 +9,6 @@ testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
def test_repo(host):
assert host.file('/home/poadocker/bridge').exists
assert host.file('/home/poadocker/bridge').is_directory
assert host.file('/home/poadocker/bridge/package.json').exists
def test_docker_group(host):

View File

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

View File

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

View File

@@ -1,7 +1,7 @@
---
- name: Slurp docker compose file
slurp:
src: "/home/poadocker/bridge/oracle/{{ item }}.yml"
src: "/home/poadocker/bridge/oracle/{{ file }}.yml"
register: docker_compose_slurp
- name: Parse docker compose file
set_fact:
@@ -23,4 +23,4 @@
- name: Write updated docker file
copy:
content: "{{ docker_compose_parsed | to_yaml }}"
dest: "/home/poadocker/bridge/oracle/{{ item }}.yml"
dest: "/home/poadocker/bridge/oracle/{{ file }}.yml"

View File

@@ -6,11 +6,30 @@
- name: stop the service
shell: service poabridge stop
- include_tasks: oracle-add-docker-external-network.yml
- name: Build current oracle image
shell: docker build -t oracle:ultimate-testing --file oracle/Dockerfile .
delegate_to: 127.0.0.1
become: false
args:
chdir: "{{ lookup('env', 'PWD') }}/.."
- name: Replace oracle image
replace:
path: "/home/poadocker/bridge/oracle/{{ item }}.yml"
regexp: 'poanetwork/tokenbridge-oracle:latest'
replace: "oracle:ultimate-testing"
with_items:
- docker-compose
- docker-compose-transfer
- docker-compose-erc-native
- include_tasks: oracle-add-docker-external-network.yml
with_items:
- docker-compose
- docker-compose-transfer
- docker-compose-erc-native
loop_control:
loop_var: file
- name: start the service
shell: service poabridge start

View File

@@ -21,6 +21,7 @@ In `group_vars/xdai.yml`
---
MONITOR_BRIDGE_NAME: "xdai"
MONITOR_PORT: 3003
MONITOR_CACHE_EVENTS: "true"
COMMON_HOME_RPC_URL: "https://dai.poa.network"
COMMON_HOME_BRIDGE_ADDRESS: "0x7301CFA0e1756B71869E93d4e4Dca5c7d0eb0AA6"
@@ -64,6 +65,7 @@ In `group_vars/wetc.yml`
```
---
MONITOR_BRIDGE_NAME: "wetc"
MONITOR_CACHE_EVENTS: "true"
COMMON_HOME_RPC_URL: "https://ethereumclassic.network"
COMMON_HOME_BRIDGE_ADDRESS: "0x073081832B4Ecdce79d4D6753565c85Ba4b3BeA9"

View File

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

View File

@@ -44,6 +44,7 @@ UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
## Monitor
MONITOR_BRIDGE_NAME: "xdai"
MONITOR_PORT: 3003
MONITOR_CACHE_EVENTS: "true"
MONITOR_HOME_START_BLOCK: 759
MONITOR_FOREIGN_START_BLOCK: 6478417
MONITOR_VALIDATOR_HOME_TX_LIMIT: 300000

View File

@@ -46,6 +46,7 @@ UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
## Monitor
MONITOR_BRIDGE_NAME: "bridge"
MONITOR_PORT: 3003
MONITOR_CACHE_EVENTS: "false"
MONITOR_HOME_START_BLOCK: 0
MONITOR_FOREIGN_START_BLOCK: 0
MONITOR_VALIDATOR_HOME_TX_LIMIT: 300000

View File

@@ -43,6 +43,7 @@ UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
#monitor
MONITOR_BRIDGE_NAME: "bridge"
MONITOR_CACHE_EVENTS: "true"
MONITOR_HOME_START_BLOCK: 0
MONITOR_FOREIGN_START_BLOCK: 0
MONITOR_VALIDATOR_HOME_TX_LIMIT: 300000

View File

@@ -45,6 +45,7 @@ UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
## Monitor
MONITOR_BRIDGE_NAME: "wetc"
MONITOR_PORT: 3003
MONITOR_CACHE_EVENTS: "true"
MONITOR_HOME_START_BLOCK: 7703292
MONITOR_FOREIGN_START_BLOCK: 7412459
MONITOR_VALIDATOR_HOME_TX_LIMIT: 300000

View File

@@ -32,6 +32,9 @@
group: "root"
mode: "0755"
- name: Upgrade pip version
shell: pip3 install --upgrade pip
- name: Install python docker library
shell: pip3 install docker docker-compose setuptools

View File

@@ -1,6 +1,6 @@
---
- name: Check if component is already deployed
shell: "test -f {{ bridge_path }}/{{ component }}/docker-compose.yml && echo 'true'"
shell: "test -f {{ bridge_path }}/{{ component }}/.env && echo 'true'"
ignore_errors: True
register: already_deployed
when: check_deployed is defined
@@ -14,7 +14,7 @@
- name: Include repo tasks
include_tasks: repo.yml
when: skip_task != true
when: skip_task != true and skip_repo is undefined
- name: Include logging tasks
include_tasks: logging.yml

View File

@@ -1,3 +1,3 @@
---
dependencies:
- { role: common, check_deployed: true, component: 'monitor' }
- { role: common, skip_repo: true, check_deployed: true, component: 'monitor' }

View File

@@ -1,5 +1,5 @@
---
- name: Build the containers
shell: docker-compose build
- name: Pull the containers images
shell: docker-compose pull
args:
chdir: "{{ bridge_path }}/monitor"

View File

@@ -1,10 +1,46 @@
---
- name: Create configs directory
file:
path: "{{ bridge_path }}/monitor/configs"
state: directory
mode: '0755'
when: skip_task != true
- name: Create responses directory
file:
path: "{{ bridge_path }}/monitor/responses"
state: directory
mode: '0755'
when: skip_task != true
- name: Create scripts directory
file:
path: "{{ bridge_path }}/monitor/scripts"
state: directory
mode: '0755'
when: skip_task != true
- name: Install .env config
template:
src: .env.j2
dest: "{{ bridge_path }}/monitor/.env"
when: skip_task != true
- name: Copy docker-compose file
copy:
src: ../../../../monitor/docker-compose.yml
dest: "{{ bridge_path }}/monitor/docker-compose.yml"
mode: '0755'
when: skip_task != true
- name: Copy script file
copy:
src: ../../../../monitor/scripts/getBridgeStats.sh
dest: "{{ bridge_path }}/monitor/scripts/getBridgeStats.sh"
owner: "{{ compose_service_user }}"
mode: '0755'
when: skip_task != true
- name: Install bridge config env
template:
src: config.env.j2

View File

@@ -1,6 +1,5 @@
# This role creates a tokenbridge-monitor service which is designed to manage docker-compose monitor deployment.
# /etc/init.d/tokenbridge-monitor start, status, stop, restart - does what the services usually do in such cases.
# /etc/init.d/tokenbridge-monitor rebuild - builds a new monitor deployment from scratch.
---
- name: "Set the service"
template:

View File

@@ -32,3 +32,5 @@ MONITOR_FOREIGN_START_BLOCK={{ MONITOR_FOREIGN_START_BLOCK }}
MONITOR_VALIDATOR_HOME_TX_LIMIT={{ MONITOR_VALIDATOR_HOME_TX_LIMIT }}
MONITOR_VALIDATOR_FOREIGN_TX_LIMIT={{ MONITOR_VALIDATOR_FOREIGN_TX_LIMIT }}
MONITOR_TX_NUMBER_THRESHOLD={{ MONITOR_TX_NUMBER_THRESHOLD }}
MONITOR_CACHE_EVENTS={{ MONITOR_CACHE_EVENTS }}

View File

@@ -34,14 +34,6 @@ status(){
sudo -u "{{ compose_service_user }}" /usr/local/bin/docker-compose ps
}
rebuild(){
echo "Rebuild TokenBridge Monitor.."
cd $WORKDIR
sudo -u "{{ compose_service_user }}" /usr/local/bin/docker-compose down -v
sudo -u "{{ compose_service_user }}" /usr/local/bin/docker-compose rm -fv
sudo -u "{{ compose_service_user }}" /usr/local/bin/docker-compose up --detach --force-recreate --no-deps --build
}
case "$1" in
@@ -63,12 +55,8 @@ case "$1" in
start
;;
rebuild)
rebuild
;;
*)
echo $"Usage: $0 {start|stop|restart|rebuild|status}"
echo $"Usage: $0 {start|stop|restart|status}"
exit 1
;;

View File

@@ -1,3 +1,3 @@
---
dependencies:
- role: common
- { role: common, skip_repo: true }

View File

@@ -1,5 +1,5 @@
---
- name: Build the containers
shell: docker-compose build
- name: Pull the containers images
shell: docker-compose pull
args:
chdir: "{{ bridge_path }}/oracle"

View File

@@ -4,6 +4,8 @@
- docker-compose
- docker-compose-transfer
- docker-compose-erc-native
loop_control:
loop_var: file
- name: Set the local container logs configuration file
template:

View File

@@ -1,7 +1,7 @@
---
- name: Slurp docker compose file
slurp:
src: "{{ bridge_path }}/oracle/{{ item }}.yml"
src: "{{ bridge_path }}/oracle/{{ file }}.yml"
register: docker_compose_slurp
- name: Parse docker compose file
@@ -16,4 +16,4 @@
- name: Write updated docker file
copy:
content: "{{ docker_compose_parsed | to_yaml }}"
dest: "{{ bridge_path }}/oracle/{{ item }}.yml"
dest: "{{ bridge_path }}/oracle/{{ file }}.yml"

View File

@@ -1,7 +1,7 @@
---
- name: Get blocks
become_user: "{{ compose_service_user }}"
shell: docker-compose run --entrypoint "node scripts/getValidatorStartBlocks.js" bridge_affirmation
shell: docker-compose run --rm --entrypoint "node scripts/getValidatorStartBlocks.js" bridge_affirmation
args:
chdir: "{{ bridge_path }}/oracle"
register: BLOCKS
@@ -18,7 +18,7 @@
- name: Get validator address
become_user: "{{ compose_service_user }}"
shell: docker-compose run -e ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY="{{ ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY }}" --entrypoint "node scripts/privateKeyToAddress.js" bridge_affirmation
shell: docker-compose run --rm -e ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY="{{ ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY }}" --entrypoint "node scripts/privateKeyToAddress.js" bridge_affirmation
args:
chdir: "{{ bridge_path }}/oracle"
register: VADDRESS
@@ -29,7 +29,7 @@
- name: Get foreign erc type
become_user: "{{ compose_service_user }}"
shell: docker-compose run --entrypoint "node scripts/initialChecks.js" bridge_affirmation
shell: docker-compose run --rm --entrypoint "node scripts/initialChecks.js" bridge_affirmation
args:
chdir: "{{ bridge_path }}/oracle"
register: ERCTYPE

View File

@@ -1,5 +1,21 @@
---
- name: Create oracle directory
file:
path: "{{ bridge_path }}/oracle"
state: directory
mode: '0755'
- name: Install .env config
template:
src: .env.j2
dest: "{{ bridge_path }}/oracle/.env"
- name: Copy docker-compose files
copy:
src: ../../../../oracle/{{ item }}
dest: "{{ bridge_path }}/oracle/"
mode: '0755'
with_items:
- docker-compose.yml
- docker-compose-transfer.yml
- docker-compose-erc-native.yml

View File

@@ -1,6 +1,5 @@
# This role creates a poabridge service which is designed to manage docker-compose bridge deployment.
# /etc/init.d/poabridge start, status, stop, restart - does what the services usually do in such cases.
# /etc/init.d/poabridge rebuild - builds a new bridge deployment from scratch.
---
- name: "Set poabridge service"
template:

View File

@@ -52,14 +52,6 @@ status(){
sudo -u "{{ compose_service_user }}" /usr/local/bin/docker-compose $composefileoverride ps
}
rebuild(){
echo "Rebuild bridge.."
cd $WORKDIR
sudo -u "{{ compose_service_user }}" /usr/local/bin/docker-compose $composefileoverride down -v
sudo -u "{{ compose_service_user }}" /usr/local/bin/docker-compose $composefileoverride rm -fv
sudo -u "{{ compose_service_user }}" ORACLE_VALIDATOR_ADDRESS=$vaddr ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=$vkey /usr/local/bin/docker-compose $composefileoverride up --detach --force-recreate --no-deps --build
}
case "$1" in
@@ -81,12 +73,8 @@ case "$1" in
start
;;
rebuild)
rebuild
;;
*)
echo $"Usage: $0 {start|stop|restart|rebuild|status}"
echo $"Usage: $0 {start|stop|restart|status}"
exit 1
;;

View File

@@ -17,3 +17,4 @@ COMMON_FOREIGN_GAS_PRICE_FACTOR=1
MONITOR_TX_NUMBER_THRESHOLD=100
MONITOR_PORT=3013
MONITOR_BRIDGE_NAME=bridge
MONITOR_CACHE_EVENTS=false

View File

@@ -17,3 +17,4 @@ COMMON_FOREIGN_GAS_PRICE_FACTOR=1
MONITOR_TX_NUMBER_THRESHOLD=100
MONITOR_PORT=3012
MONITOR_BRIDGE_NAME=bridge
MONITOR_CACHE_EVENTS=false

View File

@@ -17,3 +17,4 @@ COMMON_FOREIGN_GAS_PRICE_FACTOR=1
MONITOR_TX_NUMBER_THRESHOLD=100
MONITOR_PORT=3011
MONITOR_BRIDGE_NAME=bridge
MONITOR_CACHE_EVENTS=false

View File

@@ -17,3 +17,4 @@ COMMON_FOREIGN_GAS_PRICE_FACTOR=1
MONITOR_TX_NUMBER_THRESHOLD=100
MONITOR_PORT=3010
MONITOR_BRIDGE_NAME=bridge
MONITOR_CACHE_EVENTS=false

View File

@@ -7,10 +7,26 @@
"address": "0xcca2fb44C8C36E51f743269d6F484Fd027B9F9Aa",
"privateKey": "0xcf954e07e6a439faf392eb474e95ddb444c2ca444847f2ad6ecc79e1a585e2b8"
},
"thirdUser": {
"address": "0x441cc8537aB6cE63d060b63F3A44eE021d62e6cF",
"privateKey": "0xd3915199f27691d7784cb01ab0c7220308053b229f95d592e97493326314a8d0"
},
"fourthUser": {
"address": "0x3CC5baAB679eC0732C175760079Bf48F564ad26B",
"privateKey": "0xedb53ee050631b7914d5f1a66c2f0d2df3ec85a9ed2a9616b16a7b1b7a10b8d1"
},
"validator": {
"address": "0xaaB52d66283F7A1D5978bcFcB55721ACB467384b",
"privateKey": "0x8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
},
"secondValidator": {
"address": "0xdCC784657C78054aa61FbcFFd2605F32374816A4",
"privateKey": "0x5a5c3645d0f04e9eb4f27f94ed4c244a225587405b8838e7456f7781ce3a9513"
},
"thirdValidator": {
"address": "0xDcef88209a20D52165230104B245803C3269454d",
"privateKey": "0xf877f62a1c19f852cff1d29f0fb1ecac18821c0080d4cc0520c60c098293dca1"
},
"blockGenerator": {
"address": "0xB4579fd5AfEaB60B03Db3F408AAdD315035943f7",
"privateKey": "0xd6143d390d8b28c33601bb0fe29392fb1c35c24ccfe8722c09c2bdd6ada2699f"
@@ -36,6 +52,7 @@
"foreignToken": "0x7cc4b1851c35959d34e635a470f6b5c43ba3c9c9",
"halfDuplexToken": "0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359",
"saiTop": "0x9b0ccf7C8994E19F39b2B4CF708e0A7DF65fA8a3",
"chaiToken": "0x06af07097c9eeb7fd685c692751d5c66db49c215",
"ui": "http://localhost:3002",
"monitor": "http://monitor-erc20-native:3012/bridge"
},

View File

@@ -22,4 +22,4 @@ FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS=1
FOREIGN_GAS_PRICE=10000000000
REQUIRED_NUMBER_OF_VALIDATORS=1
VALIDATORS=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
VALIDATORS="0xaaB52d66283F7A1D5978bcFcB55721ACB467384b 0xdCC784657C78054aa61FbcFFd2605F32374816A4 0xDcef88209a20D52165230104B245803C3269454d"

View File

@@ -34,8 +34,7 @@ FOREIGN_REWARDABLE=false
ERC20_TOKEN_ADDRESS=0x3C665A31199694Bf723fD08844AD290207B5797f
REQUIRED_NUMBER_OF_VALIDATORS=1
VALIDATORS="0xaaB52d66283F7A1D5978bcFcB55721ACB467384b"
VALIDATORS_REWARD_ACCOUNTS=0x0000000000000000000000000000000000000000
VALIDATORS="0xaaB52d66283F7A1D5978bcFcB55721ACB467384b 0xdCC784657C78054aa61FbcFFd2605F32374816A4 0xDcef88209a20D52165230104B245803C3269454d"
BLOCK_REWARD_ADDRESS=0x0000000000000000000000000000000000000000
DPOS_STAKING_ADDRESS=0x0000000000000000000000000000000000000000
ERC20_EXTENDED_BY_ERC677=false

View File

@@ -32,8 +32,7 @@ FOREIGN_GAS_PRICE=10000000000
FOREIGN_REWARDABLE=false
BLOCK_REWARD_ADDRESS=0xF9698Eb93702dfdd0e2d802088d4c21822a8A977
ERC20_TOKEN_ADDRESS=0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359
ERC20_TOKEN_ADDRESS=0x7cc4b1851c35959d34e635a470f6b5c43ba3c9c9
REQUIRED_NUMBER_OF_VALIDATORS=1
VALIDATORS="0xaaB52d66283F7A1D5978bcFcB55721ACB467384b"
VALIDATORS_REWARD_ACCOUNTS=0x0000000000000000000000000000000000000000
VALIDATORS="0xaaB52d66283F7A1D5978bcFcB55721ACB467384b 0xdCC784657C78054aa61FbcFFd2605F32374816A4 0xDcef88209a20D52165230104B245803C3269454d"

View File

@@ -34,6 +34,5 @@ FOREIGN_GAS_PRICE=10000000000
FOREIGN_REWARDABLE=false
REQUIRED_NUMBER_OF_VALIDATORS=1
VALIDATORS="0xaaB52d66283F7A1D5978bcFcB55721ACB467384b"
VALIDATORS_REWARD_ACCOUNTS=0x0000000000000000000000000000000000000000
VALIDATORS="0xaaB52d66283F7A1D5978bcFcB55721ACB467384b 0xdCC784657C78054aa61FbcFFd2605F32374816A4 0xDcef88209a20D52165230104B245803C3269454d"
BLOCK_REWARD_ADDRESS=0x0000000000000000000000000000000000000000

View File

@@ -24,16 +24,13 @@ services:
- ultimate
rabbit:
image: "rabbitmq:3-management"
ports:
- "15672:15672"
networks:
- ultimate
oracle:
build:
context: ..
dockerfile: oracle/Dockerfile
args:
DOT_ENV_PATH: e2e-commons/components-envs/oracle.env
env_file: ../e2e-commons/components-envs/oracle.env
environment:
- NODE_ENV=production
command: "true"
@@ -43,8 +40,7 @@ services:
build:
context: ..
dockerfile: oracle/Dockerfile
args:
DOT_ENV_PATH: e2e-commons/components-envs/oracle-erc20.env
env_file: ../e2e-commons/components-envs/oracle-erc20.env
environment:
- NODE_ENV=production
command: "true"
@@ -54,8 +50,7 @@ services:
build:
context: ..
dockerfile: oracle/Dockerfile
args:
DOT_ENV_PATH: e2e-commons/components-envs/oracle-erc20-native.env
env_file: ../e2e-commons/components-envs/oracle-erc20-native.env
environment:
- NODE_ENV=production
command: "true"
@@ -65,8 +60,7 @@ services:
build:
context: ..
dockerfile: oracle/Dockerfile
args:
DOT_ENV_PATH: e2e-commons/components-envs/oracle-amb.env
env_file: ../e2e-commons/components-envs/oracle-amb.env
environment:
- NODE_ENV=production
command: "true"
@@ -103,8 +97,7 @@ services:
build:
context: ..
dockerfile: monitor/Dockerfile
args:
DOT_ENV_PATH: e2e-commons/components-envs/monitor.env
env_file: ../e2e-commons/components-envs/monitor.env
entrypoint: yarn check-and-start
ports:
- "3010:3010"
@@ -114,8 +107,7 @@ services:
build:
context: ..
dockerfile: monitor/Dockerfile
args:
DOT_ENV_PATH: e2e-commons/components-envs/monitor-erc20.env
env_file: ../e2e-commons/components-envs/monitor-erc20.env
entrypoint: yarn check-and-start
ports:
- "3011:3011"
@@ -125,8 +117,7 @@ services:
build:
context: ..
dockerfile: monitor/Dockerfile
args:
DOT_ENV_PATH: e2e-commons/components-envs/monitor-erc20-native.env
env_file: ../e2e-commons/components-envs/monitor-erc20-native.env
entrypoint: yarn check-and-start
ports:
- "3012:3012"
@@ -136,8 +127,7 @@ services:
build:
context: ..
dockerfile: monitor/Dockerfile
args:
DOT_ENV_PATH: e2e-commons/components-envs/monitor-amb.env
env_file: ../e2e-commons/components-envs/monitor-amb.env
entrypoint: yarn check-and-start
ports:
- "3013:3013"
@@ -150,3 +140,10 @@ services:
command: "true"
networks:
- ultimate
blocks:
build:
context: ..
dockerfile: Dockerfile.e2e
entrypoint: node e2e-commons/scripts/blocks.js
networks:
- ultimate

View File

@@ -5,4 +5,6 @@ if [ $CI ]; then exit $rc; fi
ps | grep node | grep -v grep | awk '{print "kill " $1}' | /bin/bash
docker-compose down
docker-compose -p validator2 down
docker-compose -p validator3 down
docker network rm ultimate || true

View File

@@ -1,8 +1,7 @@
const Web3 = require('web3')
const { generateNewBlock } = require('../utils')
const homeWeb3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8541'))
const foreignWeb3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8542'))
const homeWeb3 = new Web3(new Web3.providers.HttpProvider('http://parity1:8545'))
const foreignWeb3 = new Web3(new Web3.providers.HttpProvider('http://parity2:8545'))
const {user, blockGenerator} = require('../constants.json');
homeWeb3.eth.accounts.wallet.add(user.privateKey)
@@ -10,10 +9,24 @@ foreignWeb3.eth.accounts.wallet.add(user.privateKey)
homeWeb3.eth.accounts.wallet.add(blockGenerator.privateKey)
foreignWeb3.eth.accounts.wallet.add(blockGenerator.privateKey)
function generateNewBlock(web3, address) {
return web3.eth.sendTransaction({
from: address,
to: '0x0000000000000000000000000000000000000000',
gasPrice: '1',
gas: '21000',
value: '1'
})
}
function main() {
setTimeout(async () => {
generateNewBlock(homeWeb3, blockGenerator.address)
generateNewBlock(foreignWeb3, blockGenerator.address)
try {
generateNewBlock(homeWeb3, blockGenerator.address)
} catch {} // in case of Transaction with the same hash was already imported.
try {
generateNewBlock(foreignWeb3, blockGenerator.address)
} catch {} // in case of Transaction with the same hash was already imported.
main()
}, 1000)
}

View File

@@ -6,6 +6,9 @@ CONTRACTS_PATH="../../contracts"
DEPLOY_PATH="$CONTRACTS_PATH/deploy"
ENVS_PATH="../contracts-envs"
# mock bridge validators contract with the one with deterministic isValidatorDuty
mv "$CONTRACTS_PATH/build/contracts/BridgeValidatorsDeterministic.json" "$CONTRACTS_PATH/build/contracts/BridgeValidators.json"
echo -e "\n\n############ Deploying native-to-erc ############\n"
cp "$ENVS_PATH/native-to-erc.env" "$DEPLOY_PATH/.env"
cd "$DEPLOY_PATH"

View File

@@ -7,6 +7,30 @@ docker-compose build
docker network create --driver bridge ultimate || true
docker-compose up -d parity1 parity2 e2e
startValidator () {
docker-compose $1 run -d --name $4 redis
docker-compose $1 run -d --name $5 rabbit
docker-compose $1 run $2 $3 -d oracle yarn watcher:signature-request
docker-compose $1 run $2 $3 -d oracle yarn watcher:collected-signatures
docker-compose $1 run $2 $3 -d oracle yarn watcher:affirmation-request
docker-compose $1 run $2 $3 -d oracle-erc20 yarn watcher:signature-request
docker-compose $1 run $2 $3 -d oracle-erc20 yarn watcher:collected-signatures
docker-compose $1 run $2 $3 -d oracle-erc20 yarn watcher:affirmation-request
docker-compose $1 run $2 $3 -d oracle-erc20 yarn watcher:transfer
docker-compose $1 run $2 $3 -d oracle-erc20-native yarn watcher:signature-request
docker-compose $1 run $2 $3 -d oracle-erc20-native yarn watcher:collected-signatures
docker-compose $1 run $2 $3 -d oracle-erc20-native yarn watcher:affirmation-request
docker-compose $1 run $2 $3 -d oracle-erc20-native yarn watcher:transfer
docker-compose $1 run $2 $3 -d oracle-erc20-native yarn watcher:half-duplex-transfer
docker-compose $1 run $2 $3 -d oracle-erc20-native yarn worker:swap-tokens
docker-compose $1 run $2 $3 -d oracle-erc20-native yarn worker:convert-to-chai
docker-compose $1 run $2 $3 -d oracle-amb yarn watcher:signature-request
docker-compose $1 run $2 $3 -d oracle-amb yarn watcher:collected-signatures
docker-compose $1 run $2 $3 -d oracle-amb yarn watcher:affirmation-request
docker-compose $1 run $2 $3 -d oracle-erc20-native yarn sender:home
docker-compose $1 run $2 $3 -d oracle-erc20-native yarn sender:foreign
}
while [ "$1" != "" ]; do
if [ "$1" == "oracle" ]; then
docker-compose up -d redis rabbit oracle oracle-erc20 oracle-erc20-native oracle-amb
@@ -24,6 +48,7 @@ while [ "$1" != "" ]; do
docker-compose run -d oracle-erc20-native yarn watcher:transfer
docker-compose run -d oracle-erc20-native yarn watcher:half-duplex-transfer
docker-compose run -d oracle-erc20-native yarn worker:swap-tokens
docker-compose run -d oracle-erc20-native yarn worker:convert-to-chai
docker-compose run -d oracle-amb yarn watcher:signature-request
docker-compose run -d oracle-amb yarn watcher:collected-signatures
docker-compose run -d oracle-amb yarn watcher:affirmation-request
@@ -31,6 +56,20 @@ while [ "$1" != "" ]; do
docker-compose run -d oracle yarn sender:foreign
fi
if [ "$1" == "oracle-validator-2" ]; then
oracle2name="-p validator2"
oracle2Values="-e ORACLE_VALIDATOR_ADDRESS=0xdCC784657C78054aa61FbcFFd2605F32374816A4 -e ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=5a5c3645d0f04e9eb4f27f94ed4c244a225587405b8838e7456f7781ce3a9513"
oracle2comp="-e ORACLE_QUEUE_URL=amqp://rabbit2 -e ORACLE_REDIS_URL=redis://redis2"
startValidator "$oracle2name" "$oracle2Values" "$oracle2comp" "redis2" "rabbit2"
fi
if [ "$1" == "oracle-validator-3" ]; then
oracle3name="-p validator3"
oracle3Values="-e ORACLE_VALIDATOR_ADDRESS=0xDcef88209a20D52165230104B245803C3269454d -e ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=f877f62a1c19f852cff1d29f0fb1ecac18821c0080d4cc0520c60c098293dca1"
oracle3comp="-e ORACLE_QUEUE_URL=amqp://rabbit3 -e ORACLE_REDIS_URL=redis://redis3"
startValidator "$oracle3name" "$oracle3Values" "$oracle3comp" "redis3" "rabbit3"
fi
if [ "$1" == "ui" ]; then
docker-compose up -d ui ui-erc20 ui-erc20-native
@@ -44,7 +83,7 @@ while [ "$1" != "" ]; do
fi
if [ "$1" == "blocks" ]; then
node ./scripts/blocks.js &
docker-compose up -d blocks
fi
if [ "$1" == "monitor" ]; then
@@ -63,5 +102,9 @@ while [ "$1" != "" ]; do
../deployment-e2e/molecule.sh ultimate-erc-to-erc
fi
if [ "$1" == "amb" ]; then
../deployment-e2e/molecule.sh ultimate-amb
fi
shift # Shift all the parameters down by one
done

View File

@@ -1,13 +1,18 @@
function generateNewBlock(web3, address) {
return web3.eth.sendTransaction({
from: address,
to: '0x0000000000000000000000000000000000000000',
gasPrice: '1',
gas: '21000',
value: '1'
const promiseRetry = require('promise-retry')
async function uniformRetry(f) {
return promiseRetry(f, {
forever: true,
factor: 1,
minTimeout: 500
})
}
module.exports = {
generateNewBlock
async function sleep(timeout) {
return new Promise(res => setTimeout(res, timeout))
}
module.exports = {
uniformRetry,
sleep
}

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