Compare commits
37 Commits
2.0.0-rc1
...
oracle-ser
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
322729ae82 | ||
|
|
636f053c48 | ||
|
|
80841a76a6 | ||
|
|
994562a8b9 | ||
|
|
b86090a5a0 | ||
|
|
a07cecccc2 | ||
|
|
8556e7aec5 | ||
|
|
441224c1f0 | ||
|
|
db11aa6444 | ||
|
|
4db62d721d | ||
|
|
8d6acd0339 | ||
|
|
c013cc7378 | ||
|
|
d5e7e06788 | ||
|
|
d6e39f34af | ||
|
|
3b368ce644 | ||
|
|
c1d58c2908 | ||
|
|
d17e9e0eea | ||
|
|
a2c678d0a2 | ||
|
|
4bd3576691 | ||
|
|
d3576f5a79 | ||
|
|
62f9a080c9 | ||
|
|
10f67168a7 | ||
|
|
f90f888ae4 | ||
|
|
84508e2b84 | ||
|
|
2369e876aa | ||
|
|
4117f29a74 | ||
|
|
1921087ad1 | ||
|
|
b4abbc4910 | ||
|
|
bcbe34a839 | ||
|
|
738442e4cf | ||
|
|
64c5a5670f | ||
|
|
c8c589536b | ||
|
|
7b0edff624 | ||
|
|
b02b879b02 | ||
|
|
5b4b01a79b | ||
|
|
881fafe9a8 | ||
|
|
c1ed6f21e6 |
@@ -51,28 +51,25 @@ orbs:
|
||||
paths:
|
||||
- ~/.cache/yarn
|
||||
wait-for-oracle:
|
||||
parameters:
|
||||
redis-key:
|
||||
type: string
|
||||
steps:
|
||||
- run:
|
||||
name: Install redis tools
|
||||
command: sudo apt-get install -y redis-tools
|
||||
- run:
|
||||
name: Wait for the Oracle to start
|
||||
command: |
|
||||
set +e
|
||||
i=0
|
||||
while [[ $(redis-cli GET << parameters.redis-key >> ) ]]; do
|
||||
((i++))
|
||||
if [ "$i" -gt 30 ]
|
||||
then
|
||||
exit -1
|
||||
while :
|
||||
do
|
||||
(echo > /dev/tcp/127.0.0.1/6379) >/dev/null 2>&1
|
||||
if [[ $? -eq 0 ]]; then
|
||||
break
|
||||
fi
|
||||
((i++))
|
||||
if [ "$i" -gt 30 ]; then
|
||||
echo "Redis has not open the port"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Sleeping..."
|
||||
sleep 3
|
||||
done
|
||||
done
|
||||
executors:
|
||||
docker-node:
|
||||
docker:
|
||||
@@ -225,9 +222,6 @@ jobs:
|
||||
scenario-name:
|
||||
description: "Molecule scenario name used to create the infrastructure"
|
||||
type: string
|
||||
redis-key:
|
||||
description: "Redis key checked for non-emptiness to assert if Oracle is running"
|
||||
type: string
|
||||
ui-e2e-grep:
|
||||
description: "Mocha grep string used to run ui-e2e tests specific to given type of bridge"
|
||||
default: ''
|
||||
@@ -247,8 +241,7 @@ jobs:
|
||||
name: Prepare the infrastructure
|
||||
command: e2e-commons/up.sh deploy << parameters.scenario-name >> blocks
|
||||
no_output_timeout: 50m
|
||||
- tokenbridge-orb/wait-for-oracle:
|
||||
redis-key: << parameters.redis-key >>
|
||||
- tokenbridge-orb/wait-for-oracle
|
||||
- when:
|
||||
condition: << parameters.ui-e2e-grep >>
|
||||
steps:
|
||||
@@ -297,20 +290,20 @@ workflows:
|
||||
- ultimate:
|
||||
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"
|
||||
scenario-name: erc-to-native
|
||||
redis-key: erc-native-collected-signatures:lastProcessedBlock
|
||||
ui-e2e-grep: "ERC TO NATIVE"
|
||||
- ultimate:
|
||||
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
|
||||
ui-e2e-grep: "AMB-STAKE-ERC-TO-ERC"
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
**/*.md
|
||||
|
||||
contracts/test
|
||||
contracts/build
|
||||
oracle/test
|
||||
oracle/**/*.png
|
||||
oracle/**/*.jpg
|
||||
audit
|
||||
|
||||
@@ -2,3 +2,4 @@ node_modules
|
||||
submodules
|
||||
coverage
|
||||
lib
|
||||
dist
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -6,6 +6,7 @@ coverage
|
||||
|
||||
# production
|
||||
build
|
||||
dist
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
@@ -48,4 +49,5 @@ __pycache__
|
||||
|
||||
#monitor
|
||||
monitor/responses/*
|
||||
!monitor/.gitkeep
|
||||
monitor/configs/*.env
|
||||
!monitor/.gitkeep
|
||||
|
||||
@@ -43,6 +43,7 @@ ORACLE_VALIDATOR_ADDRESS | The public address of the bridge validator | hexideci
|
||||
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
|
||||
@@ -56,7 +57,8 @@ UI_FOREIGN_EXPLORER_ADDRESS_TEMPLATE | template link to address on foreign explo
|
||||
UI_HOME_GAS_PRICE_UPDATE_INTERVAL | An interval in milliseconds used to get the updated gas price value either from the oracle or from the Home Bridge contract. | integer
|
||||
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL | An interval in milliseconds used to get the updated gas price value either from the oracle or from the Foreign Bridge contract. | integer
|
||||
UI_PORT | The port for the UI app. | integer
|
||||
UI_STYLES | The set of styles to render the bridge UI page. Currently only `classic` is implemented | classic
|
||||
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
|
||||
@@ -70,3 +72,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
|
||||
|
||||
31
burner-wallet-plugin/.eslintrc.js
Normal file
31
burner-wallet-plugin/.eslintrc.js
Normal 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",
|
||||
}
|
||||
}
|
||||
};
|
||||
30
burner-wallet-plugin/Dockerfile
Normal file
30
burner-wallet-plugin/Dockerfile
Normal 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"]
|
||||
41
burner-wallet-plugin/README.md
Normal file
41
burner-wallet-plugin/README.md
Normal 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.
|
||||
|
||||
17
burner-wallet-plugin/docker-compose.yml
Normal file
17
burner-wallet-plugin/docker-compose.yml
Normal 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
|
||||
10
burner-wallet-plugin/lerna.json
Normal file
10
burner-wallet-plugin/lerna.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"packages": [
|
||||
"basic-wallet",
|
||||
"local-wallet",
|
||||
"tokenbridge-bw-exchange"
|
||||
],
|
||||
"npmClient": "yarn",
|
||||
"useWorkspaces": true,
|
||||
"version": "independent"
|
||||
}
|
||||
28
burner-wallet-plugin/package.json
Normal file
28
burner-wallet-plugin/package.json
Normal 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"
|
||||
}
|
||||
}
|
||||
36
burner-wallet-plugin/publish.md
Normal file
36
burner-wallet-plugin/publish.md
Normal 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/
|
||||
1
burner-wallet-plugin/staging/.env.example
Normal file
1
burner-wallet-plugin/staging/.env.example
Normal file
@@ -0,0 +1 @@
|
||||
REACT_APP_INFURA_KEY=
|
||||
40
burner-wallet-plugin/staging/package.json
Normal file
40
burner-wallet-plugin/staging/package.json
Normal 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": {}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
38
burner-wallet-plugin/staging/public/index.html
Normal file
38
burner-wallet-plugin/staging/public/index.html
Normal 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>
|
||||
15
burner-wallet-plugin/staging/public/manifest.json
Normal file
15
burner-wallet-plugin/staging/public/manifest.json
Normal 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"
|
||||
}
|
||||
21
burner-wallet-plugin/staging/src/index.tsx
Normal file
21
burner-wallet-plugin/staging/src/index.tsx
Normal 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'))
|
||||
1
burner-wallet-plugin/staging/src/react-app-env.d.ts
vendored
Normal file
1
burner-wallet-plugin/staging/src/react-app-env.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/// <reference types="react-scripts" />
|
||||
25
burner-wallet-plugin/staging/tsconfig.json
Normal file
25
burner-wallet-plugin/staging/tsconfig.json
Normal 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"
|
||||
]
|
||||
}
|
||||
14
burner-wallet-plugin/testing/.env.example
Normal file
14
burner-wallet-plugin/testing/.env.example
Normal 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
|
||||
43
burner-wallet-plugin/testing/package.json
Normal file
43
burner-wallet-plugin/testing/package.json
Normal 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"
|
||||
}
|
||||
}
|
||||
BIN
burner-wallet-plugin/testing/public/favicon.ico
Normal file
BIN
burner-wallet-plugin/testing/public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.8 KiB |
38
burner-wallet-plugin/testing/public/index.html
Normal file
38
burner-wallet-plugin/testing/public/index.html
Normal 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>
|
||||
15
burner-wallet-plugin/testing/public/manifest.json
Normal file
15
burner-wallet-plugin/testing/public/manifest.json
Normal 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"
|
||||
}
|
||||
73
burner-wallet-plugin/testing/src/index.tsx
Normal file
73
burner-wallet-plugin/testing/src/index.tsx
Normal 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'))
|
||||
1
burner-wallet-plugin/testing/src/react-app-env.d.ts
vendored
Normal file
1
burner-wallet-plugin/testing/src/react-app-env.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/// <reference types="react-scripts" />
|
||||
25
burner-wallet-plugin/testing/tsconfig.json
Normal file
25
burner-wallet-plugin/testing/tsconfig.json
Normal 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"
|
||||
]
|
||||
}
|
||||
37
burner-wallet-plugin/tokenbridge-bw-exchange/README.md
Normal file
37
burner-wallet-plugin/tokenbridge-bw-exchange/README.md
Normal 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:
|
||||
|
||||

|
||||
40
burner-wallet-plugin/tokenbridge-bw-exchange/package.json
Normal file
40
burner-wallet-plugin/tokenbridge-bw-exchange/package.json
Normal 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"
|
||||
]
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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'
|
||||
})
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import { default as ERC677Asset } from './ERC677Asset'
|
||||
|
||||
export default new ERC677Asset({
|
||||
id: 'wetc',
|
||||
name: 'WETC',
|
||||
network: '1',
|
||||
address: '0x86aabcc646f290b9fc9bd05ce17c3858d1511da1'
|
||||
})
|
||||
@@ -0,0 +1,7 @@
|
||||
import NativeMediatorAsset from './NativeMediatorAsset'
|
||||
|
||||
export default new NativeMediatorAsset({
|
||||
id: 'spoa',
|
||||
name: 'sPOA',
|
||||
network: '77'
|
||||
})
|
||||
@@ -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)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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'
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export { ERC677Asset, NativeMediatorAsset, sPOA, Etc, Wetc, TokenBridgeGateway, Mediator } from './burner-wallet'
|
||||
export { WETCBridge } from './wetc-bridge'
|
||||
@@ -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'
|
||||
@@ -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'
|
||||
}
|
||||
]
|
||||
@@ -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'
|
||||
}
|
||||
]
|
||||
@@ -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'
|
||||
}
|
||||
]
|
||||
@@ -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'
|
||||
}
|
||||
]
|
||||
@@ -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'
|
||||
}
|
||||
]
|
||||
@@ -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'
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export { default as WETCBridge } from './WETCBridge'
|
||||
@@ -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()
|
||||
})
|
||||
})
|
||||
10
burner-wallet-plugin/tokenbridge-bw-exchange/tsconfig.json
Normal file
10
burner-wallet-plugin/tokenbridge-bw-exchange/tsconfig.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "src",
|
||||
"outDir": "./dist"
|
||||
},
|
||||
"include": [
|
||||
"./src"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"module": "commonjs"
|
||||
}
|
||||
}
|
||||
27
burner-wallet-plugin/tsconfig.json
Normal file
27
burner-wallet-plugin/tsconfig.json
Normal 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
15931
burner-wallet-plugin/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
@@ -7,13 +7,17 @@ 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/IBlockReward').abi
|
||||
const BLOCK_REWARD_ABI = require('../contracts/build/contracts/BlockReward').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')
|
||||
@@ -67,6 +71,12 @@ 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}`)
|
||||
}
|
||||
@@ -94,5 +104,7 @@ module.exports = {
|
||||
HOME_AMB_ABI,
|
||||
FOREIGN_AMB_ABI,
|
||||
BOX_ABI,
|
||||
SAI_TOP
|
||||
SAI_TOP,
|
||||
HOME_STAKE_ERC_TO_ERC_ABI,
|
||||
FOREIGN_STAKE_ERC_TO_ERC_ABI
|
||||
}
|
||||
|
||||
@@ -3,7 +3,9 @@ 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'
|
||||
ARBITRARY_MESSAGE: 'ARBITRARY_MESSAGE',
|
||||
AMB_ERC_TO_ERC: 'AMB_ERC_TO_ERC',
|
||||
STAKE_AMB_ERC_TO_ERC: 'STAKE_AMB_ERC_TO_ERC'
|
||||
}
|
||||
|
||||
const ERC_TYPES = {
|
||||
@@ -14,6 +16,7 @@ const ERC_TYPES = {
|
||||
const FEE_MANAGER_MODE = {
|
||||
ONE_DIRECTION: 'ONE_DIRECTION',
|
||||
BOTH_DIRECTIONS: 'BOTH_DIRECTIONS',
|
||||
ONE_DIRECTION_STAKE: 'ONE_DIRECTION_STAKE',
|
||||
UNDEFINED: 'UNDEFINED'
|
||||
}
|
||||
|
||||
|
||||
@@ -9,14 +9,14 @@ function addTxHashToData({ encodedData, transactionHash }) {
|
||||
function parseAMBMessage(message) {
|
||||
message = strip0x(message)
|
||||
|
||||
const txHash = `0x${message.slice(0, 64)}`
|
||||
const messageId = `0x${message.slice(0, 64)}`
|
||||
const sender = `0x${message.slice(64, 104)}`
|
||||
const executor = `0x${message.slice(104, 144)}`
|
||||
|
||||
return {
|
||||
sender,
|
||||
executor,
|
||||
txHash
|
||||
messageId
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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(5)
|
||||
expect(Object.keys(BRIDGE_MODES).length).to.be.equal(7)
|
||||
})
|
||||
|
||||
it('should contain correct number of erc types', () => {
|
||||
|
||||
@@ -61,4 +61,99 @@ 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)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -50,20 +50,20 @@ describe('parseAMBMessage', () => {
|
||||
it('should parse data type 00', () => {
|
||||
const msgSender = '0x003667154bb32e42bb9e1e6532f19d187fa0082e'
|
||||
const msgExecutor = '0xf4bef13f9f4f2b203faf0c3cbbaabe1afe056955'
|
||||
const msgTxHash = '0xbdceda9d8c94838aca10c687da1411a07b1390e88239c0638cb9cc264219cc10'
|
||||
const msgId = '0xbdceda9d8c94838aca10c687da1411a07b1390e88239c0638cb9cc264219cc10'
|
||||
const msgGasLimit = '000000000000000000000000000000000000000000000000000000005b877705'
|
||||
const msgDataType = '00'
|
||||
const msgData = '0xb1591967aed668a4b27645ff40c444892d91bf5951b382995d4d4f6ee3a2ce03'
|
||||
const message = `0x${strip0x(msgTxHash)}${strip0x(msgSender)}${strip0x(
|
||||
const message = `0x${strip0x(msgId)}${strip0x(msgSender)}${strip0x(
|
||||
msgExecutor
|
||||
)}${msgGasLimit}${msgDataType}${strip0x(msgData)}`
|
||||
|
||||
// when
|
||||
const { sender, executor, txHash } = parseAMBMessage(message)
|
||||
const { sender, executor, messageId } = parseAMBMessage(message)
|
||||
|
||||
// then
|
||||
expect(sender).to.be.equal(msgSender)
|
||||
expect(executor).to.be.equal(msgExecutor)
|
||||
expect(txHash).to.be.equal(msgTxHash)
|
||||
expect(messageId).to.be.equal(msgId)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -12,6 +12,10 @@ 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}'`)
|
||||
}
|
||||
@@ -46,10 +50,31 @@ const getTokenType = async (bridgeTokenContract, bridgeAddress) => {
|
||||
return ERC_TYPES.ERC20
|
||||
}
|
||||
} catch (e) {
|
||||
return ERC_TYPES.ERC20
|
||||
try {
|
||||
const isBridge = await bridgeTokenContract.methods.isBridge(bridgeAddress).call()
|
||||
if (isBridge) {
|
||||
return ERC_TYPES.ERC677
|
||||
} else {
|
||||
return ERC_TYPES.ERC20
|
||||
}
|
||||
} catch (e) {
|
||||
return ERC_TYPES.ERC20
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const isErcToErcMode = bridgeMode => {
|
||||
return (
|
||||
bridgeMode === BRIDGE_MODES.ERC_TO_ERC ||
|
||||
bridgeMode === BRIDGE_MODES.AMB_ERC_TO_ERC ||
|
||||
bridgeMode === BRIDGE_MODES.STAKE_AMB_ERC_TO_ERC
|
||||
)
|
||||
}
|
||||
|
||||
const isMediatorMode = bridgeMode => {
|
||||
return bridgeMode === BRIDGE_MODES.AMB_ERC_TO_ERC || bridgeMode === BRIDGE_MODES.STAKE_AMB_ERC_TO_ERC
|
||||
}
|
||||
|
||||
const getUnit = bridgeMode => {
|
||||
let unitHome = null
|
||||
let unitForeign = null
|
||||
@@ -62,6 +87,9 @@ 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}`)
|
||||
}
|
||||
@@ -260,5 +288,7 @@ module.exports = {
|
||||
normalizeGasPrice,
|
||||
gasPriceFromSupplier,
|
||||
gasPriceFromContract,
|
||||
gasPriceWithinLimits
|
||||
gasPriceWithinLimits,
|
||||
isErcToErcMode,
|
||||
isMediatorMode
|
||||
}
|
||||
|
||||
Submodule contracts updated: 026dbfdac8...129f4b4a4e
@@ -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
|
||||
@@ -0,0 +1,54 @@
|
||||
---
|
||||
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
|
||||
@@ -24,3 +24,10 @@
|
||||
copy:
|
||||
content: "{{ docker_compose_parsed | to_yaml }}"
|
||||
dest: "/home/poadocker/bridge/oracle/{{ file }}.yml"
|
||||
|
||||
- name: Get updated docker file
|
||||
shell: cat "/home/poadocker/bridge/oracle/{{ file }}.yml"
|
||||
register: catout
|
||||
|
||||
- debug: var=catout.stdout_lines
|
||||
|
||||
|
||||
@@ -3,9 +3,30 @@
|
||||
hosts: oracle
|
||||
become: true
|
||||
tasks:
|
||||
- name: get statuses for docker containers
|
||||
shell: docker ps -a
|
||||
register: docker1out
|
||||
|
||||
- debug: var=docker1out.stdout_lines
|
||||
|
||||
- name: get status for poabridge
|
||||
shell: /etc/init.d/poabridge status
|
||||
register: serviceout
|
||||
|
||||
- debug: var=serviceout.stdout_lines
|
||||
|
||||
- name: stop the service
|
||||
shell: service poabridge stop
|
||||
|
||||
- name: force to stop redis and rabit
|
||||
shell: docker rm -f oracle_rabbit_1 oracle_redis_1 || true
|
||||
|
||||
- name: get statuses for docker containers
|
||||
shell: docker ps -a
|
||||
register: docker2out
|
||||
|
||||
- debug: var=docker2out.stdout_lines
|
||||
|
||||
- name: Build current oracle image
|
||||
shell: docker build -t oracle:ultimate-testing --file oracle/Dockerfile .
|
||||
delegate_to: 127.0.0.1
|
||||
@@ -32,4 +53,14 @@
|
||||
loop_var: file
|
||||
|
||||
- name: start the service
|
||||
shell: service poabridge start
|
||||
#shell: service poabridge start
|
||||
shell: /etc/init.d/poabridge start
|
||||
register: startout
|
||||
|
||||
- debug: var=startout.stdout_lines
|
||||
|
||||
- name: get statuses for docker containers
|
||||
shell: docker ps -a
|
||||
register: docker3out
|
||||
|
||||
- debug: var=docker3out.stdout_lines
|
||||
|
||||
@@ -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"
|
||||
|
||||
4
deployment/group_vars/amb-stake-erc-to-erc.yml
Normal file
4
deployment/group_vars/amb-stake-erc-to-erc.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
COMMON_HOME_BRIDGE_ADDRESS: "0xc26Aa60Ff574f157616D3aEE70e08aAC129E1dFC"
|
||||
COMMON_FOREIGN_BRIDGE_ADDRESS: "0xc26Aa60Ff574f157616D3aEE70e08aAC129E1dFC"
|
||||
UI_PORT: 3003
|
||||
@@ -32,6 +32,7 @@ COMMON_FOREIGN_GAS_PRICE_FACTOR: 1
|
||||
|
||||
## UI
|
||||
UI_TITLE: "TokenBridge UI app - %c"
|
||||
UI_OG_TITLE: "POA Bridge UI"
|
||||
UI_DESCRIPTION: "The TokenBridge serves as a method of transferring MakerDAO stable tokens between the Ethereum network to xDai chain in a quick and cost-efficient manner."
|
||||
UI_PORT: 3001
|
||||
UI_HOME_EXPLORER_TX_TEMPLATE: https://blockscout.com/poa/dai/tx/%s
|
||||
@@ -40,10 +41,13 @@ UI_HOME_EXPLORER_ADDRESS_TEMPLATE: https://blockscout.com/poa/dai/address/%s
|
||||
UI_FOREIGN_EXPLORER_ADDRESS_TEMPLATE: https://blockscout.com/eth/mainnet/address/%s
|
||||
UI_HOME_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
UI_STYLES: "core"
|
||||
UI_PUBLIC_URL: "https://dai-bridge.poa.network"
|
||||
|
||||
## 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
|
||||
|
||||
@@ -34,6 +34,7 @@ ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
|
||||
## UI
|
||||
UI_TITLE: "TokenBridge UI app - %c"
|
||||
UI_OG_TITLE: "POA Bridge UI"
|
||||
UI_DESCRIPTION: "The POA cross-chain bridge serves as a method of transferring POA native tokens from the POA Network to the Ethereum network in a quick and cost-efficient manner."
|
||||
UI_PORT: 3001
|
||||
UI_HOME_EXPLORER_TX_TEMPLATE: https://blockscout.com/poa/sokol/tx/%s
|
||||
@@ -42,10 +43,13 @@ UI_HOME_EXPLORER_ADDRESS_TEMPLATE: https://blockscout.com/poa/sokol/address/%s
|
||||
UI_FOREIGN_EXPLORER_ADDRESS_TEMPLATE: https://blockscout.com/eth/kovan/address/%s
|
||||
UI_HOME_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
UI_STYLES: "core"
|
||||
UI_PUBLIC_URL: "http://localhost:3001"
|
||||
|
||||
## 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
|
||||
|
||||
@@ -33,6 +33,7 @@ ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
|
||||
#ui
|
||||
UI_TITLE: "TokenBridge UI app - %c"
|
||||
UI_OG_TITLE: "POA Bridge UI"
|
||||
UI_DESCRIPTION: "The POA cross-chain bridge serves as a method of transferring POA native tokens from the POA Network to the Ethereum network in a quick and cost-efficient manner."
|
||||
UI_HOME_EXPLORER_TX_TEMPLATE: https://blockscout.com/poa/sokol/tx/%s
|
||||
UI_FOREIGN_EXPLORER_TX_TEMPLATE: https://blockscout.com/eth/kovan/tx/%s
|
||||
@@ -40,9 +41,12 @@ UI_HOME_EXPLORER_ADDRESS_TEMPLATE: https://blockscout.com/poa/sokol/address/%s
|
||||
UI_FOREIGN_EXPLORER_ADDRESS_TEMPLATE: https://blockscout.com/eth/kovan/address/%s
|
||||
UI_HOME_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
UI_STYLES: "core"
|
||||
UI_PUBLIC_URL: "http://localhost"
|
||||
|
||||
#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
|
||||
|
||||
@@ -33,6 +33,7 @@ COMMON_FOREIGN_GAS_PRICE_FACTOR: 1
|
||||
|
||||
## UI
|
||||
UI_TITLE: "TokenBridge UI app - %c"
|
||||
UI_OG_TITLE: "POA Bridge UI"
|
||||
UI_DESCRIPTION: "The TokenBridge serves as a method of transferring native tokens from the Ethereum Classic Network to the Ethereum network in a quick and cost-efficient manner."
|
||||
UI_PORT: 3001
|
||||
UI_HOME_EXPLORER_TX_TEMPLATE: https://blockscout.com/etc/mainnet/tx/%s
|
||||
@@ -41,10 +42,13 @@ UI_HOME_EXPLORER_ADDRESS_TEMPLATE: https://blockscout.com/etc/mainnet/address/%s
|
||||
UI_FOREIGN_EXPLORER_ADDRESS_TEMPLATE: https://blockscout.com/eth/mainnet/address/%s
|
||||
UI_HOME_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
UI_STYLES: "classic"
|
||||
UI_PUBLIC_URL: "https://wetc.app"
|
||||
|
||||
## 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
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
@@ -34,9 +34,9 @@ COMMON_FOREIGN_GAS_PRICE_FACTOR={{ COMMON_FOREIGN_GAS_PRICE_FACTOR }}
|
||||
|
||||
# Default
|
||||
UI_TITLE={{ UI_TITLE }}
|
||||
UI_OG_TITLE={{ UI_OG_TITLE }}
|
||||
UI_DESCRIPTION={{ UI_DESCRIPTION }}
|
||||
UI_PORT={{ UI_PORT }}
|
||||
UI_PUBLIC_URL={{ UI_PUBLIC_URL }}
|
||||
|
||||
{% if UI_STYLES | default('') != '' %}
|
||||
UI_STYLES={{ UI_STYLES }}
|
||||
{% endif %}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -21,3 +21,5 @@ COMMON_FOREIGN_GAS_PRICE_FACTOR=1
|
||||
ORACLE_HOME_RPC_POLLING_INTERVAL=500
|
||||
ORACLE_FOREIGN_RPC_POLLING_INTERVAL=500
|
||||
ORACLE_ALLOW_HTTP_FOR_RPC=yes
|
||||
ORACLE_HOME_START_BLOCK=1
|
||||
ORACLE_FOREIGN_START_BLOCK=1
|
||||
|
||||
@@ -21,3 +21,5 @@ COMMON_FOREIGN_GAS_PRICE_FACTOR=0.1
|
||||
ORACLE_HOME_RPC_POLLING_INTERVAL=500
|
||||
ORACLE_FOREIGN_RPC_POLLING_INTERVAL=500
|
||||
ORACLE_ALLOW_HTTP_FOR_RPC=yes
|
||||
ORACLE_HOME_START_BLOCK=1
|
||||
ORACLE_FOREIGN_START_BLOCK=1
|
||||
|
||||
@@ -21,3 +21,5 @@ COMMON_FOREIGN_GAS_PRICE_FACTOR=0.1
|
||||
ORACLE_HOME_RPC_POLLING_INTERVAL=500
|
||||
ORACLE_FOREIGN_RPC_POLLING_INTERVAL=500
|
||||
ORACLE_ALLOW_HTTP_FOR_RPC=yes
|
||||
ORACLE_HOME_START_BLOCK=1
|
||||
ORACLE_FOREIGN_START_BLOCK=1
|
||||
|
||||
23
e2e-commons/components-envs/ui-amb-stake-erc20-erc20.env
Normal file
23
e2e-commons/components-envs/ui-amb-stake-erc20-erc20.env
Normal file
@@ -0,0 +1,23 @@
|
||||
COMMON_HOME_BRIDGE_ADDRESS=0xc26Aa60Ff574f157616D3aEE70e08aAC129E1dFC
|
||||
COMMON_FOREIGN_BRIDGE_ADDRESS=0xc26Aa60Ff574f157616D3aEE70e08aAC129E1dFC
|
||||
COMMON_FOREIGN_RPC_URL=http://localhost:8542
|
||||
COMMON_HOME_RPC_URL=http://localhost:8541
|
||||
UI_NATIVE_TOKEN_DISPLAY_NAME=POA
|
||||
UI_HOME_NETWORK_DISPLAY_NAME=Sokol
|
||||
UI_FOREIGN_NETWORK_DISPLAY_NAME=Kovan
|
||||
UI_HOME_EXPLORER_TX_TEMPLATE=https://blockscout.com/poa/sokol/tx//%s
|
||||
UI_FOREIGN_EXPLORER_TX_TEMPLATE=https://blockscout.com/eth/kovan/tx/%s
|
||||
UI_HOME_EXPLORER_ADDRESS_TEMPLATE=https://blockscout.com/poa/sokol/address/%s
|
||||
UI_FOREIGN_EXPLORER_ADDRESS_TEMPLATE=https://blockscout.com/eth/kovan/address/%s
|
||||
COMMON_HOME_GAS_PRICE_SUPPLIER_URL=https://gasprice.poa.network/
|
||||
COMMON_HOME_GAS_PRICE_SPEED_TYPE=standard
|
||||
COMMON_HOME_GAS_PRICE_FALLBACK=5000000000
|
||||
UI_HOME_GAS_PRICE_UPDATE_INTERVAL=15000
|
||||
COMMON_HOME_GAS_PRICE_FACTOR=1
|
||||
COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL=https://gasprice.poa.network/
|
||||
COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE=standard
|
||||
COMMON_FOREIGN_GAS_PRICE_FALLBACK=5000000000
|
||||
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL=15000
|
||||
COMMON_FOREIGN_GAS_PRICE_FACTOR=1
|
||||
UI_PORT=3000
|
||||
UI_STYLES=stake
|
||||
@@ -20,3 +20,4 @@ COMMON_FOREIGN_GAS_PRICE_FALLBACK=5000000000
|
||||
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL=15000
|
||||
COMMON_FOREIGN_GAS_PRICE_FACTOR=1
|
||||
UI_PORT=3000
|
||||
UI_STYLES=core
|
||||
|
||||
@@ -20,3 +20,4 @@ COMMON_FOREIGN_GAS_PRICE_FALLBACK=5000000000
|
||||
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL=15000
|
||||
COMMON_FOREIGN_GAS_PRICE_FACTOR=1
|
||||
UI_PORT=3000
|
||||
UI_STYLES=core
|
||||
|
||||
@@ -20,3 +20,4 @@ COMMON_FOREIGN_GAS_PRICE_FALLBACK=5000000000
|
||||
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL=15000
|
||||
COMMON_FOREIGN_GAS_PRICE_FACTOR=1
|
||||
UI_PORT=3000
|
||||
UI_STYLES=core
|
||||
|
||||
@@ -63,6 +63,14 @@
|
||||
"foreignBox": "0x6C4EaAb8756d53Bf599FFe2347FAFF1123D6C8A1",
|
||||
"monitor": "http://monitor-amb:3013/bridge"
|
||||
},
|
||||
"ambStakeErcToErc": {
|
||||
"home": "0xc26Aa60Ff574f157616D3aEE70e08aAC129E1dFC",
|
||||
"foreign": "0xc26Aa60Ff574f157616D3aEE70e08aAC129E1dFC",
|
||||
"homeToken": "0x6f359aC418a5f7538F7755A33C9c7dDf38785524",
|
||||
"foreignToken": "0x6f359aC418a5f7538F7755A33C9c7dDf38785524",
|
||||
"blockReward": "0xF9698Eb93702dfdd0e2d802088d4c21822a8A977",
|
||||
"ui": "http://localhost:3003"
|
||||
},
|
||||
"homeRPC": {
|
||||
"URL": "http://parity1:8545",
|
||||
"ID": "77"
|
||||
|
||||
30
e2e-commons/contracts-envs/amb-stake-erc-to-erc.env
Normal file
30
e2e-commons/contracts-envs/amb-stake-erc-to-erc.env
Normal file
@@ -0,0 +1,30 @@
|
||||
BRIDGE_MODE=STAKE_AMB_ERC_TO_ERC
|
||||
DEPLOYMENT_ACCOUNT_PRIVATE_KEY=8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9
|
||||
DEPLOYMENT_GAS_LIMIT_EXTRA=0.2
|
||||
HOME_DEPLOYMENT_GAS_PRICE=10000000000
|
||||
FOREIGN_DEPLOYMENT_GAS_PRICE=10000000000
|
||||
GET_RECEIPT_INTERVAL_IN_MILLISECONDS=50
|
||||
HOME_STAKE_TOKEN_ADDRESS=0x6f359aC418a5f7538F7755A33C9c7dDf38785524
|
||||
FOREIGN_STAKE_TOKEN_ADDRESS=0x6f359aC418a5f7538F7755A33C9c7dDf38785524
|
||||
BLOCK_REWARD_ADDRESS=0xF9698Eb93702dfdd0e2d802088d4c21822a8A977
|
||||
HOME_RPC_URL=http://parity1:8545
|
||||
HOME_BRIDGE_OWNER=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
|
||||
HOME_UPGRADEABLE_ADMIN=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
|
||||
HOME_DAILY_LIMIT=30000000000000000000000000
|
||||
HOME_MAX_AMOUNT_PER_TX=1500000000000000000000000
|
||||
HOME_MIN_AMOUNT_PER_TX=10000000000000000
|
||||
HOME_TRANSACTIONS_FEE=0
|
||||
FOREIGN_RPC_URL=http://parity2:8545
|
||||
FOREIGN_BRIDGE_OWNER=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
|
||||
FOREIGN_UPGRADEABLE_ADMIN=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
|
||||
FOREIGN_DAILY_LIMIT=15000000000000000000000000
|
||||
FOREIGN_MAX_AMOUNT_PER_TX=750000000000000000000000
|
||||
FOREIGN_MIN_AMOUNT_PER_TX=10000000000000000
|
||||
HOME_AMB_BRIDGE=0x0AEe1FCD12dDFab6265F7f8956e6E012A9Fe4Aa0
|
||||
FOREIGN_AMB_BRIDGE=0x0AEe1FCD12dDFab6265F7f8956e6E012A9Fe4Aa0
|
||||
HOME_MEDIATOR_REQUEST_GAS_LIMIT=2000000
|
||||
FOREIGN_MEDIATOR_REQUEST_GAS_LIMIT=2000000
|
||||
|
||||
BRIDGEABLE_TOKEN_NAME='not used'
|
||||
BRIDGEABLE_TOKEN_SYMBOL='not used'
|
||||
BRIDGEABLE_TOKEN_DECIMALS='18'
|
||||
@@ -32,7 +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 0xdCC784657C78054aa61FbcFFd2605F32374816A4 0xDcef88209a20D52165230104B245803C3269454d"
|
||||
|
||||
@@ -93,6 +93,15 @@ services:
|
||||
command: "true"
|
||||
networks:
|
||||
- ultimate
|
||||
ui-amb-stake-erc20-erc20:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: ui/Dockerfile
|
||||
args:
|
||||
DOT_ENV_PATH: e2e-commons/components-envs/ui-amb-stake-erc20-erc20.env
|
||||
command: "true"
|
||||
networks:
|
||||
- ultimate
|
||||
monitor:
|
||||
build:
|
||||
context: ..
|
||||
|
||||
@@ -43,3 +43,13 @@ echo -e "\n\n############ Deploying test contract for amb ############\n"
|
||||
cd "$DEPLOY_PATH"
|
||||
node src/utils/deployTestBox.js
|
||||
cd - > /dev/null
|
||||
|
||||
echo -e "\n\n############ Deploying amb stake erc to erc ############\n"
|
||||
cp "$ENVS_PATH/amb-stake-erc-to-erc.env" "$DEPLOY_PATH/.env"
|
||||
node deployMultiBridgeToken.js
|
||||
node deployBridgeTokenRewardable.js
|
||||
cd "$DEPLOY_PATH"
|
||||
node deploy.js
|
||||
cd - > /dev/null
|
||||
node setupStakeTokens.js
|
||||
cd - > /dev/null
|
||||
|
||||
43
e2e-commons/scripts/deployBridgeTokenRewardable.js
Normal file
43
e2e-commons/scripts/deployBridgeTokenRewardable.js
Normal file
@@ -0,0 +1,43 @@
|
||||
const path = require('path')
|
||||
const { user } = require('../constants.json')
|
||||
const contractsPath = '../../contracts'
|
||||
require('dotenv').config({
|
||||
path: path.join(__dirname, contractsPath, '/deploy/.env')
|
||||
})
|
||||
|
||||
const { deployContract, sendRawTxHome, privateKeyToAddress } = require(`${contractsPath}/deploy/src/deploymentUtils`)
|
||||
const { web3Home, deploymentPrivateKey } = require(`${contractsPath}/deploy/src/web3`)
|
||||
const ERC677BridgeTokenRewardable = require(`${contractsPath}/build/contracts/ERC677BridgeTokenRewardable.json`)
|
||||
|
||||
const { DEPLOYMENT_ACCOUNT_PRIVATE_KEY } = process.env
|
||||
const DEPLOYMENT_ACCOUNT_ADDRESS = privateKeyToAddress(DEPLOYMENT_ACCOUNT_PRIVATE_KEY)
|
||||
|
||||
async function deployBridgeTokenRewardable() {
|
||||
try {
|
||||
let homeNonce = await web3Home.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS)
|
||||
console.log('\n[Home] Deploying ERC677BridgeTokenRewardable Test token')
|
||||
const stakeToken = await deployContract(ERC677BridgeTokenRewardable, ['STAKE', 'STAKE', '18', '77'], {
|
||||
from: DEPLOYMENT_ACCOUNT_ADDRESS,
|
||||
network: 'home',
|
||||
nonce: homeNonce
|
||||
})
|
||||
homeNonce++
|
||||
console.log('[Home] Stake Token: ', stakeToken.options.address)
|
||||
|
||||
const mintData = await stakeToken.methods
|
||||
.mint(user.address, '500000000000000000000')
|
||||
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
|
||||
await sendRawTxHome({
|
||||
data: mintData,
|
||||
nonce: homeNonce,
|
||||
to: stakeToken.options.address,
|
||||
privateKey: deploymentPrivateKey,
|
||||
url: process.env.HOME_RPC_URL
|
||||
})
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
deployBridgeTokenRewardable()
|
||||
43
e2e-commons/scripts/deployMultiBridgeToken.js
Normal file
43
e2e-commons/scripts/deployMultiBridgeToken.js
Normal file
@@ -0,0 +1,43 @@
|
||||
const path = require('path')
|
||||
const { user } = require('../constants.json')
|
||||
const contractsPath = '../../contracts'
|
||||
require('dotenv').config({
|
||||
path: path.join(__dirname, contractsPath, '/deploy/.env')
|
||||
})
|
||||
|
||||
const { deployContract, sendRawTxForeign, privateKeyToAddress } = require(`${contractsPath}/deploy/src/deploymentUtils`)
|
||||
const { web3Foreign, deploymentPrivateKey } = require(`${contractsPath}/deploy/src/web3`)
|
||||
const ERC677MultiBridgeToken = require(`${contractsPath}/build/contracts/ERC677MultiBridgeToken.json`)
|
||||
|
||||
const { DEPLOYMENT_ACCOUNT_PRIVATE_KEY } = process.env
|
||||
const DEPLOYMENT_ACCOUNT_ADDRESS = privateKeyToAddress(DEPLOYMENT_ACCOUNT_PRIVATE_KEY)
|
||||
|
||||
async function deployMultiBridgeToken() {
|
||||
try {
|
||||
let foreignNonce = await web3Foreign.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS)
|
||||
console.log('\n[Foreign] Deploying ERC677MultiBridgeToken Test token')
|
||||
const stakeToken = await deployContract(ERC677MultiBridgeToken, ['STAKE', 'STAKE', '18', '42'], {
|
||||
from: DEPLOYMENT_ACCOUNT_ADDRESS,
|
||||
network: 'foreign',
|
||||
nonce: foreignNonce
|
||||
})
|
||||
foreignNonce++
|
||||
console.log('[Foreign] Stake Token: ', stakeToken.options.address)
|
||||
|
||||
const mintData = await stakeToken.methods
|
||||
.mint(user.address, '500000000000000000000')
|
||||
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
|
||||
await sendRawTxForeign({
|
||||
data: mintData,
|
||||
nonce: foreignNonce,
|
||||
to: stakeToken.options.address,
|
||||
privateKey: deploymentPrivateKey,
|
||||
url: process.env.FOREIGN_RPC_URL
|
||||
})
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
deployMultiBridgeToken()
|
||||
111
e2e-commons/scripts/setupStakeTokens.js
Normal file
111
e2e-commons/scripts/setupStakeTokens.js
Normal file
@@ -0,0 +1,111 @@
|
||||
const path = require('path')
|
||||
const { ambStakeErcToErc, validator, secondValidator, thirdValidator } = require('../constants.json')
|
||||
const contractsPath = '../../contracts'
|
||||
require('dotenv').config({
|
||||
path: path.join(__dirname, contractsPath, '/deploy/.env')
|
||||
})
|
||||
const { sendRawTxHome, sendRawTxForeign, privateKeyToAddress } = require(`${contractsPath}/deploy/src/deploymentUtils`)
|
||||
const { web3Home, web3Foreign, deploymentPrivateKey } = require(`${contractsPath}/deploy/src/web3`)
|
||||
const BlockReward = require(`${contractsPath}/build/contracts/BlockReward.json`)
|
||||
const ERC677BridgeTokenRewardable = require(`${contractsPath}/build/contracts/ERC677BridgeTokenRewardable.json`)
|
||||
const ERC677MultiBridgeToken = require(`${contractsPath}/build/contracts/ERC677MultiBridgeToken.json`)
|
||||
|
||||
const { DEPLOYMENT_ACCOUNT_PRIVATE_KEY } = process.env
|
||||
const DEPLOYMENT_ACCOUNT_ADDRESS = privateKeyToAddress(DEPLOYMENT_ACCOUNT_PRIVATE_KEY)
|
||||
|
||||
async function setupStakeTokens() {
|
||||
try {
|
||||
let homeNonce = await web3Home.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS)
|
||||
|
||||
const blockReward = new web3Home.eth.Contract(BlockReward.abi, ambStakeErcToErc.blockReward)
|
||||
|
||||
console.log('\n[Home] Set token in block reward')
|
||||
const setTokenData = await blockReward.methods.setToken(ambStakeErcToErc.homeToken).encodeABI()
|
||||
await sendRawTxHome({
|
||||
data: setTokenData,
|
||||
nonce: homeNonce,
|
||||
to: blockReward.options.address,
|
||||
privateKey: deploymentPrivateKey,
|
||||
url: process.env.HOME_RPC_URL
|
||||
})
|
||||
homeNonce++
|
||||
|
||||
console.log('\n[Home] Set validators rewards in block reward')
|
||||
const setValidatorsRewardsData = await blockReward.methods
|
||||
.setValidatorsRewards([validator.address, secondValidator.address, thirdValidator.address])
|
||||
.encodeABI()
|
||||
await sendRawTxHome({
|
||||
data: setValidatorsRewardsData,
|
||||
nonce: homeNonce,
|
||||
to: blockReward.options.address,
|
||||
privateKey: deploymentPrivateKey,
|
||||
url: process.env.HOME_RPC_URL
|
||||
})
|
||||
homeNonce++
|
||||
|
||||
const homeToken = new web3Home.eth.Contract(ERC677BridgeTokenRewardable.abi, ambStakeErcToErc.homeToken)
|
||||
|
||||
console.log('\n[Home] Set block reward in token')
|
||||
const setBlockRewardData = await homeToken.methods.setBlockRewardContract(ambStakeErcToErc.blockReward).encodeABI()
|
||||
await sendRawTxHome({
|
||||
data: setBlockRewardData,
|
||||
nonce: homeNonce,
|
||||
to: homeToken.options.address,
|
||||
privateKey: deploymentPrivateKey,
|
||||
url: process.env.HOME_RPC_URL
|
||||
})
|
||||
homeNonce++
|
||||
|
||||
console.log('\n[Home] Add bridge in token')
|
||||
const addBridgeData = await homeToken.methods.addBridge(ambStakeErcToErc.home).encodeABI()
|
||||
await sendRawTxHome({
|
||||
data: addBridgeData,
|
||||
nonce: homeNonce,
|
||||
to: homeToken.options.address,
|
||||
privateKey: deploymentPrivateKey,
|
||||
url: process.env.HOME_RPC_URL
|
||||
})
|
||||
homeNonce++
|
||||
|
||||
console.log('\n[Home] transfer token ownership to mediator')
|
||||
const transferOwnershipData = await homeToken.methods.transferOwnership(ambStakeErcToErc.home).encodeABI()
|
||||
await sendRawTxHome({
|
||||
data: transferOwnershipData,
|
||||
nonce: homeNonce,
|
||||
to: homeToken.options.address,
|
||||
privateKey: deploymentPrivateKey,
|
||||
url: process.env.HOME_RPC_URL
|
||||
})
|
||||
homeNonce++
|
||||
|
||||
let foreignNonce = await web3Foreign.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS)
|
||||
const foreignToken = new web3Foreign.eth.Contract(ERC677MultiBridgeToken.abi, ambStakeErcToErc.foreignToken)
|
||||
|
||||
console.log('\n[Foreign] Add bridge in token')
|
||||
const addBridgeForeignData = await homeToken.methods.addBridge(ambStakeErcToErc.foreign).encodeABI()
|
||||
await sendRawTxForeign({
|
||||
data: addBridgeForeignData,
|
||||
nonce: foreignNonce,
|
||||
to: foreignToken.options.address,
|
||||
privateKey: deploymentPrivateKey,
|
||||
url: process.env.FOREIGN_RPC_URL
|
||||
})
|
||||
foreignNonce++
|
||||
|
||||
console.log('\n[Foreign] transfer token ownership to mediator')
|
||||
const transferOwnershipForeignData = await homeToken.methods.transferOwnership(ambStakeErcToErc.foreign).encodeABI()
|
||||
await sendRawTxForeign({
|
||||
data: transferOwnershipForeignData,
|
||||
nonce: foreignNonce,
|
||||
to: foreignToken.options.address,
|
||||
privateKey: deploymentPrivateKey,
|
||||
url: process.env.FOREIGN_RPC_URL
|
||||
})
|
||||
foreignNonce++
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
setupStakeTokens()
|
||||
@@ -8,6 +8,9 @@ docker network create --driver bridge ultimate || true
|
||||
docker-compose up -d parity1 parity2 e2e
|
||||
|
||||
startValidator () {
|
||||
# make sure that old image tags are not cached
|
||||
docker-compose $1 build
|
||||
|
||||
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
|
||||
@@ -71,11 +74,12 @@ while [ "$1" != "" ]; do
|
||||
fi
|
||||
|
||||
if [ "$1" == "ui" ]; then
|
||||
docker-compose up -d ui ui-erc20 ui-erc20-native
|
||||
docker-compose up -d ui ui-erc20 ui-erc20-native ui-amb-stake-erc20-erc20
|
||||
|
||||
docker-compose run -d -p 3000:3000 ui yarn start
|
||||
docker-compose run -d -p 3001:3000 ui-erc20 yarn start
|
||||
docker-compose run -d -p 3002:3000 ui-erc20-native yarn start
|
||||
docker-compose run -d -p 3003:3000 ui-amb-stake-erc20-erc20 yarn start
|
||||
fi
|
||||
|
||||
if [ "$1" == "deploy" ]; then
|
||||
@@ -106,5 +110,9 @@ while [ "$1" != "" ]; do
|
||||
../deployment-e2e/molecule.sh ultimate-amb
|
||||
fi
|
||||
|
||||
if [ "$1" == "ultimate-amb-stake-erc-to-erc" ]; then
|
||||
../deployment-e2e/molecule.sh ultimate-amb-stake-erc-to-erc
|
||||
fi
|
||||
|
||||
shift # Shift all the parameters down by one
|
||||
done
|
||||
|
||||
@@ -7,8 +7,7 @@ const {
|
||||
addValidator,
|
||||
initializeChaiToken,
|
||||
convertDaiToChai,
|
||||
setMinDaiTokenBalance,
|
||||
migrateToMCD
|
||||
setMinDaiTokenBalance
|
||||
} = require('../utils')
|
||||
|
||||
const baseUrl = ercToNativeBridge.monitor
|
||||
@@ -34,43 +33,12 @@ describe('ERC TO NATIVE with changing state of contracts', () => {
|
||||
|
||||
it('should change balanceDiff', async function() {
|
||||
this.timeout(60000)
|
||||
await sendTokens(foreignRPC.URL, user, ercToNativeBridge.halfDuplexToken, ercToNativeBridge.foreign)
|
||||
await sendTokens(foreignRPC.URL, user, ercToNativeBridge.foreignToken, ercToNativeBridge.foreign)
|
||||
|
||||
await waitUntil(async () => {
|
||||
;({ data } = await axios.get(`${baseUrl}`))
|
||||
const { erc20Balance, halfDuplexErc20Balance, investedErc20Balance } = data.foreign
|
||||
return (
|
||||
data.balanceDiff === 0.01 &&
|
||||
erc20Balance === '0.01' &&
|
||||
halfDuplexErc20Balance === undefined &&
|
||||
investedErc20Balance === undefined
|
||||
)
|
||||
})
|
||||
|
||||
await migrateToMCD(foreignRPC.URL, ercToNativeBridge.foreign)
|
||||
|
||||
await waitUntil(async () => {
|
||||
;({ data } = await axios.get(`${baseUrl}`))
|
||||
const { erc20Balance, halfDuplexErc20Balance, investedErc20Balance } = data.foreign
|
||||
return (
|
||||
data.balanceDiff === 0.01 &&
|
||||
erc20Balance === '0.01' &&
|
||||
halfDuplexErc20Balance === '0' &&
|
||||
investedErc20Balance === undefined
|
||||
)
|
||||
})
|
||||
|
||||
await sendTokens(foreignRPC.URL, user, ercToNativeBridge.halfDuplexToken, ercToNativeBridge.foreign)
|
||||
|
||||
await waitUntil(async () => {
|
||||
;({ data } = await axios.get(`${baseUrl}`))
|
||||
const { erc20Balance, halfDuplexErc20Balance, investedErc20Balance } = data.foreign
|
||||
return (
|
||||
data.balanceDiff === 0.02 &&
|
||||
erc20Balance === '0.01' &&
|
||||
halfDuplexErc20Balance === '0.01' &&
|
||||
investedErc20Balance === undefined
|
||||
)
|
||||
const { erc20Balance, investedErc20Balance } = data.foreign
|
||||
return data.balanceDiff === 0.01 && erc20Balance === '0.01' && investedErc20Balance === undefined
|
||||
})
|
||||
})
|
||||
|
||||
@@ -89,11 +57,10 @@ describe('ERC TO NATIVE with changing state of contracts', () => {
|
||||
|
||||
await waitUntil(async () => {
|
||||
;({ data } = await axios.get(`${baseUrl}`))
|
||||
const { erc20Balance, halfDuplexErc20Balance, investedErc20Balance, accumulatedInterest } = data.foreign
|
||||
const { erc20Balance, investedErc20Balance, accumulatedInterest } = data.foreign
|
||||
return (
|
||||
data.balanceDiff === 0.03 &&
|
||||
data.balanceDiff === 0.02 &&
|
||||
erc20Balance === '0.02' &&
|
||||
halfDuplexErc20Balance === '0.01' &&
|
||||
investedErc20Balance === '0' &&
|
||||
accumulatedInterest === '0.001' // value of dsrBalance() is initially defined in genesis block as 0.001
|
||||
)
|
||||
@@ -104,11 +71,10 @@ describe('ERC TO NATIVE with changing state of contracts', () => {
|
||||
|
||||
await waitUntil(async () => {
|
||||
;({ data } = await axios.get(`${baseUrl}`))
|
||||
const { erc20Balance, halfDuplexErc20Balance, investedErc20Balance, accumulatedInterest } = data.foreign
|
||||
const { erc20Balance, investedErc20Balance, accumulatedInterest } = data.foreign
|
||||
return (
|
||||
data.balanceDiff === 0.03 &&
|
||||
data.balanceDiff === 0.02 &&
|
||||
erc20Balance === '0.01' &&
|
||||
halfDuplexErc20Balance === '0.01' &&
|
||||
investedErc20Balance === '0.01' &&
|
||||
accumulatedInterest === '0.001'
|
||||
)
|
||||
@@ -119,11 +85,10 @@ describe('ERC TO NATIVE with changing state of contracts', () => {
|
||||
|
||||
await waitUntil(async () => {
|
||||
;({ data } = await axios.get(`${baseUrl}`))
|
||||
const { erc20Balance, halfDuplexErc20Balance, investedErc20Balance, accumulatedInterest } = data.foreign
|
||||
const { erc20Balance, investedErc20Balance, accumulatedInterest } = data.foreign
|
||||
return (
|
||||
data.balanceDiff === 0.03 &&
|
||||
data.balanceDiff === 0.02 &&
|
||||
erc20Balance === '0.005' &&
|
||||
halfDuplexErc20Balance === '0.01' &&
|
||||
investedErc20Balance === '0.015' &&
|
||||
accumulatedInterest === '0.001'
|
||||
)
|
||||
|
||||
@@ -67,16 +67,6 @@ const addValidator = async (rpcUrl, account, bridgeAddress) => {
|
||||
})
|
||||
}
|
||||
|
||||
const migrateToMCD = async (rpcUrl, bridgeAddress) => {
|
||||
const web3 = new Web3(new Web3.providers.HttpProvider(rpcUrl))
|
||||
web3.eth.accounts.wallet.add(validator.privateKey)
|
||||
const bridgeContract = new web3.eth.Contract(FOREIGN_ERC_TO_NATIVE_ABI, bridgeAddress)
|
||||
await bridgeContract.methods.migrateToMCD().send({
|
||||
from: validator.address,
|
||||
gas: '4000000'
|
||||
})
|
||||
}
|
||||
|
||||
const initializeChaiToken = async (rpcUrl, bridgeAddress) => {
|
||||
const web3 = new Web3(new Web3.providers.HttpProvider(rpcUrl))
|
||||
web3.eth.accounts.wallet.add(validator.privateKey)
|
||||
@@ -116,7 +106,6 @@ module.exports = {
|
||||
sendTokens,
|
||||
addValidator,
|
||||
sendAMBMessage,
|
||||
migrateToMCD,
|
||||
initializeChaiToken,
|
||||
setMinDaiTokenBalance,
|
||||
convertDaiToChai
|
||||
|
||||
@@ -21,3 +21,4 @@ COMMON_FOREIGN_GAS_PRICE_FACTOR=1
|
||||
|
||||
MONITOR_TX_NUMBER_THRESHOLD=100
|
||||
MONITOR_PORT=3003
|
||||
MONITOR_CACHE_EVENTS=true
|
||||
|
||||
@@ -31,6 +31,7 @@ async function checkWorker() {
|
||||
const foreign = Object.assign({}, balances.foreign, events.foreign)
|
||||
const status = Object.assign({}, balances, events, { home }, { foreign })
|
||||
if (!status) throw new Error('status is empty: ' + JSON.stringify(status))
|
||||
status.health = true
|
||||
writeFile(`/responses/${MONITOR_BRIDGE_NAME}/getBalances.json`, status)
|
||||
|
||||
logger.debug('calling validators()')
|
||||
@@ -59,6 +60,7 @@ async function checkWorker() {
|
||||
}
|
||||
|
||||
vBalances.ok = vBalances.homeOk && vBalances.foreignOk
|
||||
vBalances.health = true
|
||||
writeFile(`/responses/${MONITOR_BRIDGE_NAME}/validators.json`, vBalances)
|
||||
logger.debug('Done')
|
||||
} catch (e) {
|
||||
|
||||
@@ -16,12 +16,14 @@ async function checkWorker2() {
|
||||
(evStats.onlyInForeignDeposits || evStats.home.processedMsgNotDeliveredInForeign).length === 0 &&
|
||||
(evStats.onlyInHomeWithdrawals || evStats.foreign.deliveredMsgNotProcessedInHome).length === 0 &&
|
||||
(evStats.onlyInForeignWithdrawals || evStats.foreign.processedMsgNotDeliveredInHome).length === 0
|
||||
evStats.health = true
|
||||
writeFile(`/responses/${MONITOR_BRIDGE_NAME}/eventsStats.json`, evStats)
|
||||
|
||||
logger.debug('calling alerts()')
|
||||
const _alerts = await alerts()
|
||||
if (!_alerts) throw new Error('alerts is empty: ' + JSON.stringify(_alerts))
|
||||
_alerts.ok = !_alerts.executeAffirmations.mostRecentTxHash && !_alerts.executeSignatures.mostRecentTxHash
|
||||
_alerts.health = true
|
||||
writeFile(`/responses/${MONITOR_BRIDGE_NAME}/alerts.json`, _alerts)
|
||||
logger.debug('Done x2')
|
||||
} catch (e) {
|
||||
|
||||
@@ -19,6 +19,7 @@ async function checkWorker3() {
|
||||
const transfers = await stuckTransfers()
|
||||
if (!transfers) throw new Error('transfers is empty: ' + JSON.stringify(transfers))
|
||||
transfers.ok = transfers.total.length === 0
|
||||
transfers.health = true
|
||||
writeFile(`/responses/${MONITOR_BRIDGE_NAME}/stuckTransfers.json`, transfers)
|
||||
logger.debug('Done')
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user