├── .coveralls.yml
├── .dockerignore
├── .editorconfig
├── .eslintignore
├── .eslintrc
├── .github
└── workflows
│ └── main.yml
├── .gitignore
├── .gitmodules
├── .nvmrc
├── .prettierrc
├── CODE_OF_CONDUCT.md
├── CONFIGURATION.md
├── CONTRIBUTING.md
├── Dockerfile.e2e
├── LICENSE
├── README.md
├── alm-e2e
├── .eslintrc
├── package.json
├── run-tests.sh
└── src
│ ├── test.js
│ └── utils
│ └── utils.js
├── alm
├── .env.example
├── .eslintrc.js
├── .gitignore
├── Dockerfile
├── README.md
├── config-overrides.js
├── docker-compose.yml
├── load-env.sh
├── package.json
├── public
│ ├── _redirects
│ ├── favicon.ico
│ ├── index.html
│ ├── manifest.json
│ └── robots.txt
├── scripts
│ └── createSnapshots.js
├── src
│ ├── App.tsx
│ ├── abis
│ │ ├── BridgeValidators.ts
│ │ ├── ForeignAMB.ts
│ │ ├── HomeAMB.ts
│ │ └── index.ts
│ ├── components
│ │ ├── ConfirmationsContainer.tsx
│ │ ├── ExecutionConfirmation.tsx
│ │ ├── Form.tsx
│ │ ├── MainPage.tsx
│ │ ├── ManualExecutionButton.tsx
│ │ ├── MessageSelector.tsx
│ │ ├── NetworkTransactionSelector.tsx
│ │ ├── StatusContainer.tsx
│ │ ├── TransactionSelector.tsx
│ │ ├── ValidatorsConfirmations.tsx
│ │ └── commons
│ │ │ ├── BackButton.tsx
│ │ │ ├── Button.tsx
│ │ │ ├── CloseIcon.tsx
│ │ │ ├── ErrorAlert.tsx
│ │ │ ├── ExplorerTxLink.tsx
│ │ │ ├── InfoAlert.tsx
│ │ │ ├── InfoIcon.tsx
│ │ │ ├── Labels.tsx
│ │ │ ├── LeftArrow.tsx
│ │ │ ├── Loading.tsx
│ │ │ ├── MultiLine.tsx
│ │ │ ├── RadioButton.tsx
│ │ │ ├── Table.tsx
│ │ │ └── WarningAlert.tsx
│ ├── config
│ │ ├── constants.ts
│ │ └── descriptions.ts
│ ├── global.d.ts
│ ├── hooks
│ │ ├── useBlockConfirmations.ts
│ │ ├── useBridgeContracts.ts
│ │ ├── useClosestBlock.ts
│ │ ├── useMessageConfirmations.ts
│ │ ├── useNetwork.ts
│ │ ├── useTransactionFinder.ts
│ │ ├── useTransactionStatus.ts
│ │ └── useValidatorContract.ts
│ ├── index.tsx
│ ├── react-app-env.d.ts
│ ├── services
│ │ ├── BlockNumberProvider.ts
│ │ ├── SnapshotProvider.ts
│ │ └── ValidatorsCache.ts
│ ├── setupTests.ts
│ ├── snapshots
│ │ └── .gitkeep
│ ├── state
│ │ └── StateProvider.tsx
│ ├── themes
│ │ ├── Dark.tsx
│ │ ├── GlobalStyle.tsx
│ │ └── Light.ts
│ └── utils
│ │ ├── __tests__
│ │ ├── contracts.test.ts
│ │ ├── explorer.test.ts
│ │ ├── getConfirmationsForTx.test.ts
│ │ └── getFinalizationEvent.test.ts
│ │ ├── contract.ts
│ │ ├── explorer.ts
│ │ ├── getConfirmationsForTx.ts
│ │ ├── getFinalizationEvent.ts
│ │ ├── networks.ts
│ │ ├── signatures.ts
│ │ ├── validatorConfirmationHelpers.ts
│ │ └── web3.ts
└── tsconfig.json
├── audit
├── chainsecurity
│ ├── FT-AMB-6.0.0-and-OmniBridge-1.1.0-contracts-security-assessment-report.pdf
│ └── FT-OmniBridge-contracts-1.0.0-rc2-security-assessment-report.pdf
├── peppersec
│ └── POA-Network-Token-bridge-security-assessment-report.pdf
├── quantstamp
│ ├── POA-Network-Token-bridge-security-assessment-report.pdf
│ └── POA-Network-TokenBridge-contracts-5.4.1-security-assessment-report.pdf
└── smartdec
│ └── POA-Network-TokenBridge-Contracts-v2-3-2-Security-Assessment.pdf
├── burner-wallet-plugin
├── .eslintrc.js
├── Dockerfile
├── README.md
├── docker-compose.yml
├── lerna.json
├── package.json
├── publish.md
├── staging
│ ├── .env.example
│ ├── package.json
│ ├── public
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ └── manifest.json
│ ├── src
│ │ ├── index.tsx
│ │ └── react-app-env.d.ts
│ └── tsconfig.json
├── testing
│ ├── .env.example
│ ├── package.json
│ ├── public
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ └── manifest.json
│ ├── src
│ │ ├── LocalhostGateway.ts
│ │ ├── index.tsx
│ │ └── react-app-env.d.ts
│ └── tsconfig.json
├── tokenbridge-bw-exchange
│ ├── README.md
│ ├── package.json
│ ├── src
│ │ ├── bridges
│ │ │ ├── MOONBridge.ts
│ │ │ ├── QDAIBridge.ts
│ │ │ ├── WETCBridge.ts
│ │ │ └── index.ts
│ │ ├── burner-wallet
│ │ │ ├── assets
│ │ │ │ ├── BridgeableERC20Asset.ts
│ │ │ │ ├── Dai.ts
│ │ │ │ ├── ERC677Asset.ts
│ │ │ │ ├── Etc.ts
│ │ │ │ ├── MOON.ts
│ │ │ │ ├── NativeMediatorAsset.ts
│ │ │ │ ├── Wetc.ts
│ │ │ │ ├── qDai.ts
│ │ │ │ ├── sPOA.ts
│ │ │ │ └── xMOON.ts
│ │ │ ├── gateways
│ │ │ │ └── TokenBridgeGateway.ts
│ │ │ ├── index.ts
│ │ │ └── pairs
│ │ │ │ ├── Mediator.ts
│ │ │ │ └── MediatorErcToNative.ts
│ │ ├── index.ts
│ │ └── utils
│ │ │ ├── abis.ts
│ │ │ ├── abis
│ │ │ ├── ERC677.ts
│ │ │ ├── ForeignBridgeNativeToErc.ts
│ │ │ ├── HomeBridgeNativeToErc.ts
│ │ │ ├── Mediator.ts
│ │ │ ├── MediatorErcToNative.ts
│ │ │ └── MediatorFeeManager.ts
│ │ │ ├── index.ts
│ │ │ └── utils.ts
│ ├── test
│ │ └── ERC677Asset.spec.ts
│ ├── tsconfig.json
│ └── tsconfig.testing.json
├── tsconfig.json
└── yarn.lock
├── commons
├── .eslintrc
├── README.md
├── abis.js
├── constants.js
├── index.js
├── message.js
├── package.json
├── test
│ ├── constants.test.js
│ ├── gas.js
│ ├── message.test.js
│ └── validators.js
└── utils.js
├── deployment-e2e
├── Dockerfile
├── README.md
├── molecule.sh
└── molecule
│ ├── monitor
│ ├── Dockerfile.j2
│ ├── converge.yml
│ ├── molecule.yml
│ ├── run-checks.yml
│ └── tests
│ │ └── test_monitor.py
│ ├── multiple
│ ├── Dockerfile.j2
│ ├── molecule.yml
│ └── tests
│ │ └── test_multiple.py
│ ├── oracle
│ ├── Dockerfile.j2
│ ├── molecule.yml
│ └── tests
│ │ └── test_oracle.py
│ ├── prepare.yml
│ ├── repo
│ ├── Dockerfile.j2
│ ├── converge.yml
│ ├── molecule.yml
│ └── tests
│ │ ├── test_existing.py
│ │ └── test_non_existing.py
│ ├── tests
│ └── test_all.py
│ ├── ultimate-amb
│ ├── Dockerfile.j2
│ └── molecule.yml
│ ├── ultimate-commons
│ ├── converge.yml
│ └── oracle-docker-compose.yml
│ └── ultimate-erc-to-native
│ ├── Dockerfile.j2
│ └── molecule.yml
├── deployment
├── .yamllint
├── CONFIGURATION.md
├── EXECUTION.md
├── MONITOR.md
├── README.md
├── ansible.cfg
├── group_vars
│ ├── amb.yml
│ ├── dai.yml
│ ├── erc-to-native.yml
│ ├── example.yml
│ └── ultimate.yml
├── hosts.yml.example
├── requirements.txt
├── roles
│ ├── common
│ │ ├── defaults
│ │ │ └── main.yml
│ │ ├── files
│ │ │ └── daemon.json
│ │ ├── handlers
│ │ │ └── main.yml
│ │ ├── tasks
│ │ │ ├── dependencies.yml
│ │ │ ├── logging.yml
│ │ │ ├── main.yml
│ │ │ └── repo.yml
│ │ └── templates
│ │ │ ├── 30-docker.conf.j2
│ │ │ ├── 35-docker-remote-logging.conf.j2
│ │ │ └── docker-logs.j2
│ ├── monitor
│ │ ├── defaults
│ │ │ └── main.yml
│ │ ├── meta
│ │ │ └── main.yml
│ │ ├── tasks
│ │ │ ├── cron.yml
│ │ │ ├── jumpbox.yml
│ │ │ ├── logging.yml
│ │ │ ├── main.yml
│ │ │ ├── pre_config.yml
│ │ │ └── servinstall.yml
│ │ └── templates
│ │ │ ├── .env.j2
│ │ │ ├── 33-monitor-docker.conf.j2
│ │ │ ├── 38-monitor-remote-logging.conf.j2
│ │ │ ├── config.env.j2
│ │ │ └── tokenbridge-monitor.j2
│ └── oracle
│ │ ├── defaults
│ │ └── main.yml
│ │ ├── files
│ │ └── modify_to_use_syslog.py
│ │ ├── meta
│ │ └── main.yml
│ │ ├── tasks
│ │ ├── jumpbox.yml
│ │ ├── logging.yml
│ │ ├── logging_by_syslog.yml
│ │ ├── main.yml
│ │ ├── post_config.yml
│ │ ├── pre_config.yml
│ │ └── servinstall.yml
│ │ └── templates
│ │ ├── .env.j2
│ │ ├── 31-oracle-docker.conf.j2
│ │ ├── 32-redis-docker.conf.j2
│ │ ├── 33-rabbit-docker.conf.j2
│ │ ├── 36-oracle-remote-logging.conf.j2
│ │ ├── key.j2
│ │ └── poabridge.j2
└── site.yml
├── e2e-commons
├── README.md
├── ULTIMATE.md
├── access-lists
│ ├── allowance_list.txt
│ └── block_list.txt
├── build.sh
├── components-envs
│ ├── alm.env
│ ├── monitor-amb.env
│ ├── monitor-erc20-native.env
│ ├── oracle-amb.env
│ └── oracle-erc20-native.env
├── constants.json
├── contracts-envs
│ ├── amb.env
│ └── erc-to-native.env
├── docker-compose.yml
├── down.sh
├── pull.sh
├── scripts
│ ├── blocks.js
│ └── deploy.sh
├── ultimate.png
├── up.sh
└── utils.js
├── monitor-e2e
├── .eslintrc
├── README.md
├── package.json
├── periodically-check-all.sh
├── run-tests.sh
├── test
│ ├── amb.js
│ ├── common.js
│ └── ercToNative.js
├── utils.js
└── wait-for-monitor.sh
├── monitor
├── .env.example
├── .eslintrc
├── Dockerfile
├── README.md
├── alerts.js
├── cache
│ └── .gitkeep
├── checkWorker.js
├── checkWorker2.js
├── checkWorker3.js
├── configs
│ └── .gitkeep
├── crontab.example
├── detectFailures.js
├── detectMediators.js
├── docker-compose-build.yml
├── docker-compose.yml
├── eventsStats.js
├── getBalances.js
├── getShortEventStats.js
├── index.js
├── logger.js
├── metricsWorker.js
├── package.json
├── prometheusMetrics.js
├── responses
│ └── .gitkeep
├── scripts
│ └── getBridgeStats.sh
├── test-srv.js
├── test
│ └── message.test.js
├── utils
│ ├── events.js
│ ├── file.js
│ ├── getValidatorsList.js
│ ├── message.js
│ ├── web3.js
│ └── web3Cache.js
└── validators.js
├── oracle-e2e
├── .eslintrc
├── README.md
├── package.json
├── run-tests.sh
├── scripts
│ └── generate-amb-tx.js
└── test
│ ├── amb.js
│ ├── ercToNative.js
│ ├── mocha.opts
│ └── utils.js
├── oracle
├── .env.example
├── .eslintrc
├── Dockerfile
├── ERC_TO_NATIVE.png
├── README.md
├── config
│ ├── affirmation-request-watcher.config.js
│ ├── base.config.js
│ ├── collected-signatures-watcher.config.js
│ ├── foreign-mev-sender.config.js
│ ├── foreign-sender.config.js
│ ├── home-sender.config.js
│ ├── information-request-watcher.config.js
│ ├── mev-collected-signatures-watcher.config.js
│ ├── shutdown-manager.config.js
│ ├── signature-request-watcher.config.js
│ └── transfer-watcher.config.js
├── docker-compose-amb.yml
├── docker-compose-build.yml
├── docker-compose-helpers.yml
├── docker-compose-transfer.yml
├── docker-compose.yml
├── docs
│ └── stress-testing.md
├── env.js
├── esController.sol
├── package.json
├── reset-lastBlock.sh
├── scripts
│ ├── .eslintrc
│ ├── compute-stats.js
│ ├── erc20_to_native
│ │ ├── sendForeign.js
│ │ └── sendHome.js
│ ├── getValidatorStartBlocks.js
│ ├── interestFetcher.js
│ ├── privateKeyToAddress.js
│ ├── resetLastBlock.js
│ ├── signPendingMessages.js
│ ├── start-worker.sh
│ └── utils
│ │ └── utils.js
├── src
│ ├── confirmRelay.js
│ ├── events
│ │ ├── processAMBAffirmationRequests
│ │ │ ├── estimateGas.js
│ │ │ └── index.js
│ │ ├── processAMBCollectedSignatures
│ │ │ ├── estimateGas.js
│ │ │ └── index.js
│ │ ├── processAMBCollectedSignaturesMEV
│ │ │ └── index.js
│ │ ├── processAMBInformationRequests
│ │ │ ├── calls
│ │ │ │ ├── ethBlockNumber.js
│ │ │ │ ├── ethCall.js
│ │ │ │ ├── ethGetBalance.js
│ │ │ │ ├── ethGetBlockByHash.js
│ │ │ │ ├── ethGetBlockByNumber.js
│ │ │ │ ├── ethGetStorageAt.js
│ │ │ │ ├── ethGetTransactionByHash.js
│ │ │ │ ├── ethGetTransactionCount.js
│ │ │ │ ├── ethGetTransactionReceipt.js
│ │ │ │ └── serializers.js
│ │ │ ├── estimateGas.js
│ │ │ └── index.js
│ │ ├── processAMBSignatureRequests
│ │ │ └── index.js
│ │ ├── processAffirmationRequests
│ │ │ ├── estimateGas.js
│ │ │ └── index.js
│ │ ├── processCollectedSignatures
│ │ │ ├── estimateGas.js
│ │ │ └── index.js
│ │ ├── processSignatureRequests
│ │ │ ├── estimateGas.js
│ │ │ └── index.js
│ │ └── processTransfers
│ │ │ └── index.js
│ ├── mevSender.js
│ ├── mevWatcher.js
│ ├── sender.js
│ ├── services
│ │ ├── HttpListProvider.js
│ │ ├── RedundantHttpListProvider.js
│ │ ├── SafeEthLogsProvider.js
│ │ ├── amqpClient.js
│ │ ├── blockFinder.js
│ │ ├── gasPrice.js
│ │ ├── injectedLogger.js
│ │ ├── logger.js
│ │ ├── redisClient.js
│ │ ├── shutdownState.js
│ │ └── web3.js
│ ├── shutdownManager.js
│ ├── tx
│ │ ├── sendTx.js
│ │ └── web3.js
│ ├── utils
│ │ ├── constants.js
│ │ ├── errors.js
│ │ ├── message.js
│ │ ├── mev.js
│ │ ├── tokenState.js
│ │ ├── tryEach.js
│ │ └── utils.js
│ └── watcher.js
└── test
│ ├── .eslintrc
│ ├── amqp.test.js
│ ├── blockFinder.test.js
│ ├── gasPrice.test.js
│ ├── message.test.js
│ ├── processAffirmationRequests.test.js
│ ├── processCollectedSignatures.test.js
│ ├── processSignatureRequests.test.js
│ ├── test.env
│ ├── tryEach.test.js
│ └── utils.test.js
├── package.json
├── parity
├── Dockerfile
├── Dockerfile-foreign
├── chain-foreign.json
├── chain.json
└── foreign_mocks
│ └── cDAIMock.sol
└── yarn.lock
/.coveralls.yml:
--------------------------------------------------------------------------------
1 | service_name: circleci
2 |
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | **/node_modules
2 | **/submodules
3 | **/Dockerfile
4 | **/.dockerignore
5 | **/docker-compose.yml
6 | .gitmodules
7 | **/.git
8 | **/docs
9 | **/*.md
10 |
11 | monitor/**/*.env*
12 | oracle/**/*.env*
13 | !**/.env.example
14 |
15 | contracts/test
16 | contracts/build
17 | oracle/test
18 | monitor/test
19 | monitor/responses
20 | monitor/cache/*
21 | commons/test
22 | oracle/**/*.png
23 | oracle/**/*.jpg
24 | audit
25 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | end_of_line = lf
6 | insert_final_newline = true
7 | indent_style = space
8 | indent_size = 2
9 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | submodules
3 | coverage
4 | lib
5 | dist
6 | build
7 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "plugin:prettier/recommended"
4 | ],
5 | "plugins": ["prettier"],
6 | "rules": {
7 | "prettier/prettier": "error",
8 | "arrow-body-style": "off",
9 | "func-names": "off",
10 | "no-await-in-loop": "off",
11 | "no-console": "off",
12 | "no-else-return": "off",
13 | "no-param-reassign": "off",
14 | "no-plusplus": "off",
15 | "no-restricted-syntax": "off",
16 | "no-shadow": "off",
17 | "no-use-before-define": ["error", { "functions": false }],
18 | "import/no-dynamic-require": "off",
19 | "prefer-template": "off",
20 | "no-underscore-dangle": "off"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # dependencies
2 | node_modules
3 |
4 | # testing
5 | coverage
6 |
7 | # production
8 | build
9 | dist
10 |
11 | # misc
12 | .DS_Store
13 | *.env*
14 | !.env.example
15 | .idea
16 | .nyc_output
17 | logs/
18 |
19 |
20 | *.err
21 | *.out
22 | data
23 |
24 | # contracts build
25 | ui/src/contracts
26 | oracle/abis
27 | monitor/abis
28 |
29 | # compiled css
30 | *.css
31 |
32 | npm-debug.log*
33 | yarn-debug.log*
34 | yarn-error.log*
35 |
36 | #deployment
37 | *.retry
38 | hosts.yml
39 | hosts
40 | *.log
41 | Vagrantfile
42 | vagrant-hosts.yml
43 | .vagrant
44 | deployment/venv
45 | __pycache__
46 |
47 | #monitor
48 | monitor/responses/*
49 | monitor/cache/*
50 | !monitor/cache/.gitkeep
51 | !monitor/.gitkeep
52 |
53 | # Local Netlify folder
54 | .netlify
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "contracts"]
2 | path = contracts
3 | url = https://github.com/poanetwork/tokenbridge-contracts.git
4 |
--------------------------------------------------------------------------------
/.nvmrc:
--------------------------------------------------------------------------------
1 | 12.22
2 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "semi": false,
3 | "singleQuote": true,
4 | "printWidth": 120,
5 | "bracketSpacing": true
6 | }
7 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ## Contributing
2 |
3 | Thank your for contributing to this project! We welcome collaborators and expect users to follow our [code of conduct](CODE_OF_CONDUCT.md) when submitting code or comments.
4 |
5 | 1. Fork the repo ( https://github.com/poanetwork/tokenbridge/fork ).
6 | 2. Create your feature branch (`git checkout -b my-new-feature`).
7 | 3. Write tests that cover your work.
8 | 4. Commit your changes (`git commit -am 'Add some feature'`).
9 | 5. Push to your branch (`git push origin my-new-feature`).
10 | 6. Create a new PR (Pull Request).
11 |
12 | ### General
13 |
14 | * Commits should be one logical change that still allows all tests to pass. We prefer smaller commits if there could be two levels of logic grouping. The goal is to provide future contributors (including your future self) the reasoning behind your changes and allow them to cherry-pick, patch or port those changes in isolation to other branches or forks.
15 | * If during your PR you reveal a pre-existing bug and know how to fix it:
16 | 1. If you can isolate the bug, fix it in a separate PR.
17 | 2. If the fix depends on your other commits, add it in a separate commit to the same PR.
18 |
19 | In either case, try to write a regression test that fails because of the bug but passes with your fix.
20 |
21 | ### Issues
22 | Creating and discussing [Issues](https://github.com/poanetwork/tokenbridge/issues) provides significant value to the project. If you find a bug you can report it in an Issue.
23 |
24 | ### Pull Requests
25 | All pull requests should include:
26 | * A clear, readable description of the purpose of the PR
27 | * A clear, readable description of changes
28 | * Any additional concerns or comments (optional)
29 |
--------------------------------------------------------------------------------
/Dockerfile.e2e:
--------------------------------------------------------------------------------
1 | FROM node:12 as contracts
2 |
3 | WORKDIR /mono
4 |
5 | COPY contracts/package.json contracts/package-lock.json ./contracts/
6 |
7 | WORKDIR /mono/contracts
8 | RUN npm install --only=prod
9 |
10 | COPY ./contracts/truffle-config.js ./
11 | COPY ./contracts/contracts ./contracts
12 | RUN npm run compile
13 |
14 | FROM node:12
15 |
16 | WORKDIR /mono
17 | COPY package.json .
18 | COPY --from=contracts /mono/contracts/build ./contracts/build
19 | COPY commons/package.json ./commons/
20 | COPY oracle-e2e/package.json ./oracle-e2e/
21 | COPY monitor-e2e/package.json ./monitor-e2e/
22 | COPY oracle/src/utils/constants.js ./oracle/src/utils/constants.js
23 |
24 | COPY yarn.lock .
25 | RUN NOYARNPOSTINSTALL=1 yarn install --frozen-lockfile --production
26 |
27 | COPY ./contracts/deploy ./contracts/deploy
28 | RUN yarn install:deploy
29 |
30 | COPY commons/ ./commons/
31 | COPY oracle-e2e/ ./oracle-e2e/
32 | COPY monitor-e2e/ ./monitor-e2e/
33 | COPY e2e-commons/ ./e2e-commons/
34 |
--------------------------------------------------------------------------------
/alm-e2e/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "plugin:node/recommended",
4 | "airbnb-base",
5 | "../.eslintrc"
6 | ],
7 | "plugins": ["node", "jest"],
8 | "env": {
9 | "jest/globals": true
10 | },
11 | "globals": {
12 | "page": true,
13 | "browser": true
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/alm-e2e/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "alm-e2e",
3 | "version": "0.0.1",
4 | "private": true,
5 | "scripts": {
6 | "test": "jest --detectOpenHandles",
7 | "lint": "eslint . --ignore-path ../.eslintignore",
8 | "lint:fix": "eslint . --fix"
9 | },
10 | "dependencies": {
11 | "jest": "24.7.1",
12 | "jest-puppeteer": "^4.4.0",
13 | "puppeteer": "^5.2.1"
14 | },
15 | "jest": {
16 | "preset": "jest-puppeteer"
17 | },
18 | "devDependencies": {
19 | "eslint-plugin-jest": "^23.18.0"
20 | },
21 | "engines": {
22 | "node": ">= 12.22"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/alm-e2e/run-tests.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | cd $(dirname $0)
3 |
4 | ../e2e-commons/up.sh deploy generate-amb-tx blocks alm alm-e2e
5 |
6 | # run oracle amb e2e tests to generate transactions for alm
7 | docker-compose -f ../e2e-commons/docker-compose.yml run e2e yarn workspace oracle-e2e run alm
8 |
9 | yarn test
10 | rc=$?
11 |
12 | ../e2e-commons/down.sh
13 | exit $rc
14 |
--------------------------------------------------------------------------------
/alm-e2e/src/test.js:
--------------------------------------------------------------------------------
1 | const puppeteer = require('puppeteer')
2 | const { waitUntil } = require('./utils/utils')
3 |
4 | jest.setTimeout(60000)
5 |
6 | const statusText = 'Success'
7 | const statusSelector = 'label[data-id="status"]'
8 |
9 | const homeToForeignTxURL = 'http://localhost:3004/77/0x295efbe6ae98937ef35d939376c9bd752b4dc6f6899a9d5ddd6a57cea3d76c89'
10 | const foreignToHomeTxURL = 'http://localhost:3004/42/0x7262f7dbe6c30599edded2137fbbe93c271b37f5c54dd27f713f0cf510e3b4dd'
11 |
12 | describe('ALM', () => {
13 | let browser
14 | let page
15 |
16 | beforeAll(async () => {
17 | browser = await puppeteer.launch()
18 | page = await browser.newPage()
19 | })
20 |
21 | afterAll(async () => {
22 | await browser.close()
23 | })
24 |
25 | it('should be titled "AMB Live Monitoring"', async () => {
26 | await page.goto(foreignToHomeTxURL)
27 |
28 | await expect(page.title()).resolves.toMatch('AMB Live Monitoring')
29 | })
30 | it('should display information of foreign to home transaction', async () => {
31 | await page.goto(foreignToHomeTxURL)
32 |
33 | await page.waitForSelector(statusSelector)
34 | await waitUntil(async () => {
35 | const element = await page.$(statusSelector)
36 | const text = await page.evaluate(element => element.textContent, element)
37 | return text === statusText
38 | })
39 | })
40 | it('should display information of home to foreign transaction', async () => {
41 | await page.goto(homeToForeignTxURL)
42 |
43 | await page.waitForSelector(statusSelector)
44 | await waitUntil(async () => {
45 | const element = await page.$(statusSelector)
46 | const text = await page.evaluate(element => element.textContent, element)
47 | return text === statusText
48 | })
49 | })
50 | })
51 |
--------------------------------------------------------------------------------
/alm-e2e/src/utils/utils.js:
--------------------------------------------------------------------------------
1 | const waitUntil = async (predicate, step = 100, timeout = 20000) => {
2 | const stopTime = Date.now() + timeout
3 | while (Date.now() <= stopTime) {
4 | const result = await predicate()
5 | if (result) {
6 | return result
7 | }
8 | await new Promise(resolve => setTimeout(resolve, step)) // sleep
9 | }
10 | throw new Error(`waitUntil timed out after ${timeout} ms`)
11 | }
12 |
13 | module.exports = {
14 | waitUntil
15 | }
16 |
--------------------------------------------------------------------------------
/alm/.env.example:
--------------------------------------------------------------------------------
1 | COMMON_HOME_BRIDGE_ADDRESS=0xFe446bEF1DbF7AFE24E81e05BC8B271C1BA9a560
2 | COMMON_FOREIGN_BRIDGE_ADDRESS=0xFe446bEF1DbF7AFE24E81e05BC8B271C1BA9a560
3 |
4 | COMMON_HOME_RPC_URL=https://sokol.poa.network
5 | COMMON_FOREIGN_RPC_URL=https://kovan.infura.io/v3/
6 |
7 | ALM_HOME_NETWORK_NAME=Sokol Testnet
8 | ALM_FOREIGN_NETWORK_NAME=Kovan Testnet
9 |
10 | ALM_HOME_EXPLORER_TX_TEMPLATE=https://blockscout.com/poa/sokol/tx/%s
11 | ALM_FOREIGN_EXPLORER_TX_TEMPLATE=https://blockscout.com/eth/kovan/tx/%s
12 |
13 | ALM_HOME_EXPLORER_API=https://blockscout.com/poa/sokol/api
14 | ALM_FOREIGN_EXPLORER_API=https://kovan.etherscan.io/api?apikey=YourApiKeyToken
15 | PORT=8080
16 |
--------------------------------------------------------------------------------
/alm/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: [
3 | "react-app",
4 | "../.eslintrc"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/alm/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | src/snapshots/*.json
4 |
5 | # dependencies
6 | /node_modules
7 | /.pnp
8 | .pnp.js
9 |
10 | # testing
11 | /coverage
12 |
13 | # production
14 | /build
15 |
16 | # misc
17 | .DS_Store
18 | .env.local
19 | .env.development.local
20 | .env.test.local
21 | .env.production.local
22 |
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 |
--------------------------------------------------------------------------------
/alm/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:12 as contracts
2 |
3 | WORKDIR /mono
4 |
5 | COPY contracts/package.json contracts/package-lock.json ./contracts/
6 |
7 | WORKDIR /mono/contracts
8 | RUN npm install --only=prod
9 |
10 | COPY ./contracts/truffle-config.js ./
11 | COPY ./contracts/contracts ./contracts
12 | RUN npm run compile
13 |
14 | FROM node:12 as alm-builder
15 |
16 | WORKDIR /mono
17 | COPY package.json .
18 | COPY --from=contracts /mono/contracts/build ./contracts/build
19 | COPY commons/package.json ./commons/
20 | COPY alm/package.json ./alm/
21 | COPY yarn.lock .
22 | RUN NOYARNPOSTINSTALL=1 yarn install --frozen-lockfile
23 |
24 | COPY ./commons ./commons
25 | COPY ./alm ./alm
26 |
27 | ARG DOT_ENV_PATH=./alm/.env
28 | COPY ${DOT_ENV_PATH} ./alm/.env
29 |
30 | WORKDIR /mono/alm
31 | RUN yarn run build
32 |
33 |
34 | FROM node:12 as alm-production
35 | RUN yarn global add serve
36 | WORKDIR /app
37 | COPY --from=alm-builder /mono/alm/build .
38 | CMD serve -p $PORT -s .
39 |
--------------------------------------------------------------------------------
/alm/config-overrides.js:
--------------------------------------------------------------------------------
1 | const { override, disableEsLint } = require('customize-cra')
2 | const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin')
3 |
4 | const disableModuleScopePlugin = () => config => {
5 | config.resolve.plugins = config.resolve.plugins.filter(plugin => !(plugin instanceof ModuleScopePlugin))
6 | return config
7 | }
8 |
9 | module.exports = override(disableEsLint(), disableModuleScopePlugin())
10 |
--------------------------------------------------------------------------------
/alm/docker-compose.yml:
--------------------------------------------------------------------------------
1 | ---
2 | version: '2.4'
3 | services:
4 | alm:
5 | build:
6 | context: ..
7 | dockerfile: alm/Dockerfile
8 | ports:
9 | - "${PORT}:${PORT}"
10 | env_file: ./.env
11 | environment:
12 | - NODE_ENV=production
13 | restart: unless-stopped
14 | entrypoint: serve -p ${PORT} -s .
15 |
--------------------------------------------------------------------------------
/alm/load-env.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | while read line; do
4 | if [ "$line" = "" ]; then
5 | : # Skip empty lines
6 | elif [[ "$line" =~ \#.* ]]; then
7 | : # Skip comment lines
8 | elif [[ "$line" =~ "UI_PORT"* ]]; then
9 | eval $line
10 | export PORT="$UI_PORT"
11 | else
12 | export "REACT_APP_$line"
13 | fi
14 | done < '.env'
15 |
16 | $*
17 |
--------------------------------------------------------------------------------
/alm/public/_redirects:
--------------------------------------------------------------------------------
1 | /* /index.html 200
--------------------------------------------------------------------------------
/alm/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omni/tokenbridge/961b12b9f3545830a04044e109762277efcea6ef/alm/public/favicon.ico
--------------------------------------------------------------------------------
/alm/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "ALM",
3 | "name": "AMB Live Monitoring",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/alm/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/alm/src/App.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { BrowserRouter } from 'react-router-dom'
3 | import { Web3ReactProvider } from '@web3-react/core'
4 | import Web3 from 'web3'
5 | import { MainPage } from './components/MainPage'
6 | import { StateProvider } from './state/StateProvider'
7 |
8 | function App() {
9 | return (
10 |
11 | new Web3(provider)}>
12 |
13 |
14 |
15 |
16 |
17 | )
18 | }
19 |
20 | export default App
21 |
--------------------------------------------------------------------------------
/alm/src/abis/index.ts:
--------------------------------------------------------------------------------
1 | export { default as HOME_AMB_ABI } from './HomeAMB'
2 | export { default as FOREIGN_AMB_ABI } from './ForeignAMB'
3 | export { default as BRIDGE_VALIDATORS_ABI } from './BridgeValidators'
4 |
--------------------------------------------------------------------------------
/alm/src/components/commons/BackButton.tsx:
--------------------------------------------------------------------------------
1 | import { Link } from 'react-router-dom'
2 | import { LeftArrow } from './LeftArrow'
3 | import React from 'react'
4 | import styled from 'styled-components'
5 |
6 | const StyledButton = styled.button`
7 | color: var(--button-color);
8 | border-color: var(--font-color);
9 | margin-top: 10px;
10 | &:focus {
11 | outline: var(--button-color);
12 | }
13 | `
14 |
15 | const BackLabel = styled.label`
16 | margin-left: 5px;
17 | cursor: pointer;
18 | `
19 |
20 | export interface BackButtonParam {
21 | onBackToMain: () => void
22 | }
23 |
24 | export const BackButton = ({ onBackToMain }: BackButtonParam) => (
25 |
26 |
27 |
28 |
29 |
30 | Search another transaction
31 |
32 |
33 |
34 |
35 | )
36 |
--------------------------------------------------------------------------------
/alm/src/components/commons/Button.tsx:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components'
2 |
3 | export const Button = styled.button`
4 | height: 36px;
5 | color: var(--button-color);
6 | border-color: var(--button-color);
7 | &:focus {
8 | outline: var(--button-color);
9 | }
10 | `
11 |
--------------------------------------------------------------------------------
/alm/src/components/commons/CloseIcon.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | export const CloseIcon = ({ color }: { color?: string }) => (
4 |
18 | )
19 |
--------------------------------------------------------------------------------
/alm/src/components/commons/ErrorAlert.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styled from 'styled-components'
3 | import { InfoIcon } from './InfoIcon'
4 | import { CloseIcon } from './CloseIcon'
5 | import { ExplorerTxLink } from './ExplorerTxLink'
6 |
7 | const StyledErrorAlert = styled.div`
8 | border: 1px solid var(--failed-color);
9 | border-radius: 4px;
10 | margin-bottom: 20px;
11 | padding-top: 10px;
12 | `
13 |
14 | const CloseIconContainer = styled.div`
15 | cursor: pointer;
16 | `
17 |
18 | const TextContainer = styled.div`
19 | white-space: pre-wrap;
20 | flex-direction: column;
21 | `
22 |
23 | export const ErrorAlert = ({ onClick, error }: { onClick: () => void; error: string }) => {
24 | const errorArray = error.split('%link')
25 | const text = errorArray[0]
26 | let link
27 | if (errorArray.length > 1) {
28 | link = (
29 |
30 | {errorArray[1]}
31 |
32 | )
33 | }
34 | return (
35 |
36 |
37 |
38 |
39 | {text}
40 | {link}
41 |
42 |
43 |
44 |
45 |
46 |
47 | )
48 | }
49 |
--------------------------------------------------------------------------------
/alm/src/components/commons/ExplorerTxLink.tsx:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components'
2 |
3 | export const ExplorerTxLink = styled.a`
4 | color: var(--link-color);
5 | text-decoration: underline;
6 | font-weight: bold;
7 | `
8 |
--------------------------------------------------------------------------------
/alm/src/components/commons/InfoAlert.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styled from 'styled-components'
3 | import { InfoIcon } from './InfoIcon'
4 | import { CloseIcon } from './CloseIcon'
5 |
6 | const StyledInfoAlert = styled.div`
7 | border: 1px solid var(--button-color);
8 | border-radius: 4px;
9 | margin-bottom: 20px;
10 | padding-top: 10px;
11 | `
12 |
13 | const CloseIconContainer = styled.div`
14 | cursor: pointer;
15 | `
16 |
17 | const TextContainer = styled.div`
18 | flex-direction: column;
19 | `
20 |
21 | export const InfoAlert = ({ onClick, children }: { onClick: () => void; children: React.ReactChild[] }) => (
22 |
23 |
24 |
25 | {children}
26 |
27 |
28 |
29 |
30 |
31 | )
32 |
--------------------------------------------------------------------------------
/alm/src/components/commons/InfoIcon.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | export const InfoIcon = ({ color }: { color?: string }) => (
4 |
16 | )
17 |
--------------------------------------------------------------------------------
/alm/src/components/commons/Labels.tsx:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components'
2 |
3 | export const SuccessLabel = styled.label`
4 | color: var(--success-color);
5 | background-color: var(--success-bg-color);
6 | padding: 0.4rem 0.7rem;
7 | border-radius: 4px;
8 | `
9 |
10 | export const GreyLabel = styled.label`
11 | color: var(--not-required-color);
12 | background-color: var(--not-required-bg-color);
13 | padding: 0.4rem 0.7rem;
14 | border-radius: 4px;
15 | `
16 |
17 | export const RedLabel = styled.label`
18 | color: var(--failed-color);
19 | background-color: var(--failed-bg-color);
20 | padding: 0.4rem 0.7rem;
21 | border-radius: 4px;
22 | `
23 |
--------------------------------------------------------------------------------
/alm/src/components/commons/LeftArrow.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useContext } from 'react'
3 | import { ThemeContext } from 'styled-components'
4 |
5 | export const LeftArrow = () => {
6 | const themeContext = useContext(ThemeContext)
7 | return (
8 |
19 | )
20 | }
21 |
--------------------------------------------------------------------------------
/alm/src/components/commons/MultiLine.tsx:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components'
2 |
3 | export const MultiLine = styled.div`
4 | white-space: pre-wrap;
5 | `
6 |
--------------------------------------------------------------------------------
/alm/src/components/commons/RadioButton.tsx:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components'
2 |
3 | export const RadioButtonLabel = styled.label`
4 | padding-left: 5px;
5 | `
6 |
7 | export const RadioButtonContainer = styled.div`
8 | padding: 10px;
9 | `
10 |
--------------------------------------------------------------------------------
/alm/src/components/commons/Table.tsx:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components'
2 |
3 | export const Thead = styled.thead`
4 | border-bottom: 2px solid #9e9e9e;
5 | `
6 |
7 | export const StatusTd = styled.td`
8 | width: 150px;
9 | `
10 |
11 | export const AgeTd = styled.td`
12 | width: 180px;
13 | `
14 |
--------------------------------------------------------------------------------
/alm/src/components/commons/WarningAlert.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styled from 'styled-components'
3 | import { InfoIcon } from './InfoIcon'
4 | import { CloseIcon } from './CloseIcon'
5 |
6 | const StyledErrorAlert = styled.div`
7 | border: 1px solid var(--warning-color);
8 | border-radius: 4px;
9 | margin-bottom: 20px;
10 | padding-top: 10px;
11 | `
12 |
13 | const CloseIconContainer = styled.div`
14 | cursor: pointer;
15 | `
16 |
17 | const TextContainer = styled.div`
18 | white-space: pre-wrap;
19 | flex-direction: column;
20 | `
21 |
22 | export const WarningAlert = ({ onClick, error }: { onClick: () => void; error: string }) => {
23 | return (
24 |
25 |
26 |
27 | {error}
28 |
29 |
30 |
31 |
32 |
33 | )
34 | }
35 |
--------------------------------------------------------------------------------
/alm/src/global.d.ts:
--------------------------------------------------------------------------------
1 | declare type Maybe = T | null
2 |
--------------------------------------------------------------------------------
/alm/src/hooks/useBridgeContracts.ts:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react'
2 | import { HOME_AMB_ABI, FOREIGN_AMB_ABI } from '../abis'
3 | import { FOREIGN_BRIDGE_ADDRESS, HOME_BRIDGE_ADDRESS } from '../config/constants'
4 | import { Contract } from 'web3-eth-contract'
5 | import Web3 from 'web3'
6 |
7 | export interface useBridgeContractsParams {
8 | homeWeb3: Web3
9 | foreignWeb3: Web3
10 | }
11 |
12 | export const useBridgeContracts = ({ homeWeb3, foreignWeb3 }: useBridgeContractsParams) => {
13 | const [homeBridge, setHomeBridge] = useState>(null)
14 | const [foreignBridge, setForeignBridge] = useState>(null)
15 |
16 | useEffect(
17 | () => {
18 | if (!homeWeb3) return
19 | const homeContract = new homeWeb3.eth.Contract(HOME_AMB_ABI, HOME_BRIDGE_ADDRESS)
20 | setHomeBridge(homeContract)
21 | },
22 | [homeWeb3]
23 | )
24 |
25 | useEffect(
26 | () => {
27 | if (!foreignWeb3) return
28 | const foreignContract = new foreignWeb3.eth.Contract(FOREIGN_AMB_ABI, FOREIGN_BRIDGE_ADDRESS)
29 | setForeignBridge(foreignContract)
30 | },
31 | [foreignWeb3]
32 | )
33 |
34 | return {
35 | homeBridge,
36 | foreignBridge
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/alm/src/hooks/useNetwork.ts:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react'
2 | import { getChainId, getWeb3 } from '../utils/web3'
3 | import { SnapshotProvider } from '../services/SnapshotProvider'
4 |
5 | export const useNetwork = (url: string, snapshotProvider: SnapshotProvider) => {
6 | const [loading, setLoading] = useState(true)
7 | const [chainId, setChainId] = useState(0)
8 | const web3 = getWeb3(url)
9 |
10 | useEffect(
11 | () => {
12 | setLoading(true)
13 | const getWeb3ChainId = async () => {
14 | const id = await getChainId(web3, snapshotProvider)
15 | setChainId(id)
16 | setLoading(false)
17 | }
18 | getWeb3ChainId()
19 | },
20 | [web3, snapshotProvider]
21 | )
22 |
23 | return {
24 | web3,
25 | chainId,
26 | loading
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/alm/src/hooks/useTransactionFinder.ts:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react'
2 | import { TransactionReceipt } from 'web3-eth'
3 | import { HOME_RPC_POLLING_INTERVAL, TRANSACTION_STATUS } from '../config/constants'
4 | import Web3 from 'web3'
5 |
6 | export const useTransactionFinder = ({ txHash, web3 }: { txHash: string; web3: Maybe }) => {
7 | const [status, setStatus] = useState(TRANSACTION_STATUS.UNDEFINED)
8 | const [receipt, setReceipt] = useState>(null)
9 |
10 | useEffect(
11 | () => {
12 | if (!txHash || !web3) return
13 |
14 | let timeoutId: number
15 |
16 | const getReceipt = async () => {
17 | const txReceipt = await web3.eth.getTransactionReceipt(txHash)
18 | setReceipt(txReceipt)
19 |
20 | if (!txReceipt) {
21 | setStatus(TRANSACTION_STATUS.NOT_FOUND)
22 | timeoutId = setTimeout(getReceipt, HOME_RPC_POLLING_INTERVAL)
23 | } else {
24 | setStatus(TRANSACTION_STATUS.FOUND)
25 | }
26 | }
27 |
28 | getReceipt()
29 |
30 | return () => clearTimeout(timeoutId)
31 | },
32 | [txHash, web3]
33 | )
34 |
35 | return {
36 | status,
37 | receipt
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/alm/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import { ThemeProvider } from 'styled-components'
4 | import { GlobalStyle } from './themes/GlobalStyle'
5 | import App from './App'
6 | import Light from './themes/Light'
7 |
8 | ReactDOM.render(
9 |
10 |
11 |
12 |
13 |
14 | ,
15 | document.getElementById('root')
16 | )
17 |
--------------------------------------------------------------------------------
/alm/src/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/alm/src/services/ValidatorsCache.ts:
--------------------------------------------------------------------------------
1 | import { ConfirmationParam } from '../hooks/useMessageConfirmations'
2 |
3 | class ValidatorsCache {
4 | private readonly store: { [key: string]: boolean }
5 | private readonly dataStore: { [key: string]: ConfirmationParam }
6 |
7 | constructor() {
8 | this.store = {}
9 | this.dataStore = {}
10 | }
11 |
12 | get(key: string) {
13 | return this.store[key]
14 | }
15 |
16 | set(key: string, value: boolean) {
17 | this.store[key] = value
18 | }
19 |
20 | getData(key: string) {
21 | return this.dataStore[key]
22 | }
23 |
24 | setData(key: string, value: ConfirmationParam) {
25 | this.dataStore[key] = value
26 | }
27 | }
28 |
29 | export default new ValidatorsCache()
30 |
--------------------------------------------------------------------------------
/alm/src/setupTests.ts:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom/extend-expect'
6 |
--------------------------------------------------------------------------------
/alm/src/snapshots/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omni/tokenbridge/961b12b9f3545830a04044e109762277efcea6ef/alm/src/snapshots/.gitkeep
--------------------------------------------------------------------------------
/alm/src/themes/Dark.tsx:
--------------------------------------------------------------------------------
1 | const theme = {
2 | backgroundColor: '#121212',
3 | fontColor: '#f5f5f5',
4 | buttonColor: '#f5f5f5',
5 | colorPrimary: '#272727',
6 | colorGrey: '#272727',
7 | colorLightGrey: '#272727',
8 | linkColor: '#ffffff',
9 | success: {
10 | textColor: '#00c9a7',
11 | backgroundColor: '#004d40'
12 | },
13 | notRequired: {
14 | textColor: '#bdbdbd',
15 | backgroundColor: '#424242'
16 | },
17 | failed: {
18 | textColor: '#EF5350',
19 | backgroundColor: '#4E342E'
20 | }
21 | }
22 | export default theme
23 |
--------------------------------------------------------------------------------
/alm/src/themes/GlobalStyle.tsx:
--------------------------------------------------------------------------------
1 | import { createGlobalStyle } from 'styled-components'
2 |
3 | import theme from './Light'
4 |
5 | type ThemeType = typeof theme
6 |
7 | export const GlobalStyle = createGlobalStyle<{ theme: ThemeType }>`
8 | body {
9 | margin: 0;
10 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
11 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
12 | sans-serif;
13 | -webkit-font-smoothing: antialiased;
14 | -moz-osx-font-smoothing: grayscale;
15 | }
16 |
17 | :root {
18 | --bg-color: ${props => props.theme.backgroundColor};
19 | --font-color: ${props => props.theme.fontColor};
20 | --button-color: ${props => props.theme.buttonColor};
21 | --color-primary: ${props => props.theme.colorPrimary};
22 | --color-grey: ${props => props.theme.colorGrey};
23 | --color-lightGrey: ${props => props.theme.colorLightGrey};
24 | --link-color: ${props => props.theme.linkColor};
25 | --success-color: ${props => props.theme.success.textColor};
26 | --success-bg-color: ${props => props.theme.success.backgroundColor};
27 | --not-required-color: ${props => props.theme.notRequired.textColor};
28 | --not-required-bg-color: ${props => props.theme.notRequired.backgroundColor};
29 | --failed-color: ${props => props.theme.failed.textColor};
30 | --failed-bg-color: ${props => props.theme.failed.backgroundColor};
31 | --warning-color: ${props => props.theme.warning.textColor};
32 | --warning-bg-color: ${props => props.theme.warning.backgroundColor};
33 | }
34 | `
35 |
--------------------------------------------------------------------------------
/alm/src/themes/Light.ts:
--------------------------------------------------------------------------------
1 | const theme = {
2 | backgroundColor: '#FFFFFF',
3 | fontColor: 'rgba(0, 0, 0, 0.65)',
4 | buttonColor: '#1890ff',
5 | colorPrimary: '#BDBDBD',
6 | colorGrey: '#1890ff',
7 | colorLightGrey: '#1890ff',
8 | linkColor: '#1890ff',
9 | success: {
10 | textColor: '#388E3C',
11 | backgroundColor: 'rgba(0,201,167,.1)'
12 | },
13 | notRequired: {
14 | textColor: '#77838f',
15 | backgroundColor: 'rgba(119,131,143,.1)'
16 | },
17 | failed: {
18 | textColor: '#de4437',
19 | backgroundColor: 'rgba(222,68,55,.1)'
20 | },
21 | warning: {
22 | textColor: '#ffa758',
23 | backgroundColor: 'rgba(222,68,55,.1)'
24 | }
25 | }
26 | export default theme
27 |
--------------------------------------------------------------------------------
/alm/src/utils/networks.ts:
--------------------------------------------------------------------------------
1 | import { formatDistance } from 'date-fns'
2 | import {
3 | CONFIRMATIONS_STATUS_DESCRIPTION,
4 | CONFIRMATIONS_STATUS_DESCRIPTION_HOME,
5 | TRANSACTION_STATUS_DESCRIPTION
6 | } from '../config/descriptions'
7 | import { FOREIGN_EXPLORER_TX_TEMPLATE, HOME_EXPLORER_TX_TEMPLATE } from '../config/constants'
8 |
9 | export const validTxHash = (txHash: string) => /^0x[a-fA-F0-9]{64}$/.test(txHash)
10 |
11 | export const formatTxHash = (txHash: string) => `${txHash.substring(0, 6)}...${txHash.substring(txHash.length - 4)}`
12 |
13 | export const getExplorerTxUrl = (txHash: string, isHome: boolean) => {
14 | const template = isHome ? HOME_EXPLORER_TX_TEMPLATE : FOREIGN_EXPLORER_TX_TEMPLATE
15 | return template.replace('%s', txHash)
16 | }
17 |
18 | export const formatTxHashExtended = (txHash: string) =>
19 | `${txHash.substring(0, 10)}...${txHash.substring(txHash.length - 8)}`
20 |
21 | export const formatTimestamp = (timestamp: number): string => {
22 | const txDate = new Date(0).setUTCSeconds(timestamp)
23 | return formatDistance(txDate, new Date(), {
24 | addSuffix: true
25 | })
26 | }
27 |
28 | export const getTransactionStatusDescription = (status: string, timestamp: Maybe = null) => {
29 | let description = TRANSACTION_STATUS_DESCRIPTION[status]
30 |
31 | if (timestamp) {
32 | description = description.replace('%t', formatTimestamp(timestamp))
33 | }
34 |
35 | return description
36 | }
37 |
38 | export const getConfirmationsStatusDescription = (status: string, home: string, foreign: string, fromHome: boolean) => {
39 | const statusDescription = fromHome ? CONFIRMATIONS_STATUS_DESCRIPTION_HOME : CONFIRMATIONS_STATUS_DESCRIPTION
40 |
41 | return statusDescription[status]
42 | }
43 |
--------------------------------------------------------------------------------
/alm/src/utils/signatures.ts:
--------------------------------------------------------------------------------
1 | import Web3 from 'web3'
2 |
3 | function strip0x(s: string) {
4 | return Web3.utils.isHexStrict(s) ? s.substr(2) : s
5 | }
6 |
7 | export interface Signature {
8 | v: string
9 | r: string
10 | s: string
11 | }
12 |
13 | export function signatureToVRS(rawSignature: string): Signature {
14 | const signature = strip0x(rawSignature)
15 | const v = signature.substr(64 * 2)
16 | const r = signature.substr(0, 32 * 2)
17 | const s = signature.substr(32 * 2, 32 * 2)
18 | return { v, r, s }
19 | }
20 |
21 | export function packSignatures(array: Array): string {
22 | const length = strip0x(Web3.utils.toHex(array.length))
23 | const msgLength = length.length === 1 ? `0${length}` : length
24 | const [v, r, s] = array.reduce(([vs, rs, ss], { v, r, s }) => [vs + v, rs + r, ss + s], ['', '', ''])
25 | return `0x${msgLength}${v}${r}${s}`
26 | }
27 |
--------------------------------------------------------------------------------
/alm/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": [
5 | "dom",
6 | "dom.iterable",
7 | "esnext"
8 | ],
9 | "allowJs": true,
10 | "skipLibCheck": true,
11 | "esModuleInterop": true,
12 | "allowSyntheticDefaultImports": true,
13 | "strict": true,
14 | "forceConsistentCasingInFileNames": true,
15 | "module": "esnext",
16 | "moduleResolution": "node",
17 | "resolveJsonModule": true,
18 | "isolatedModules": true,
19 | "noEmit": true,
20 | "jsx": "preserve"
21 | },
22 | "include": [
23 | "src"
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/audit/chainsecurity/FT-AMB-6.0.0-and-OmniBridge-1.1.0-contracts-security-assessment-report.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omni/tokenbridge/961b12b9f3545830a04044e109762277efcea6ef/audit/chainsecurity/FT-AMB-6.0.0-and-OmniBridge-1.1.0-contracts-security-assessment-report.pdf
--------------------------------------------------------------------------------
/audit/chainsecurity/FT-OmniBridge-contracts-1.0.0-rc2-security-assessment-report.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omni/tokenbridge/961b12b9f3545830a04044e109762277efcea6ef/audit/chainsecurity/FT-OmniBridge-contracts-1.0.0-rc2-security-assessment-report.pdf
--------------------------------------------------------------------------------
/audit/peppersec/POA-Network-Token-bridge-security-assessment-report.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omni/tokenbridge/961b12b9f3545830a04044e109762277efcea6ef/audit/peppersec/POA-Network-Token-bridge-security-assessment-report.pdf
--------------------------------------------------------------------------------
/audit/quantstamp/POA-Network-Token-bridge-security-assessment-report.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omni/tokenbridge/961b12b9f3545830a04044e109762277efcea6ef/audit/quantstamp/POA-Network-Token-bridge-security-assessment-report.pdf
--------------------------------------------------------------------------------
/audit/quantstamp/POA-Network-TokenBridge-contracts-5.4.1-security-assessment-report.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omni/tokenbridge/961b12b9f3545830a04044e109762277efcea6ef/audit/quantstamp/POA-Network-TokenBridge-contracts-5.4.1-security-assessment-report.pdf
--------------------------------------------------------------------------------
/audit/smartdec/POA-Network-TokenBridge-Contracts-v2-3-2-Security-Assessment.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omni/tokenbridge/961b12b9f3545830a04044e109762277efcea6ef/audit/smartdec/POA-Network-TokenBridge-Contracts-v2-3-2-Security-Assessment.pdf
--------------------------------------------------------------------------------
/burner-wallet-plugin/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | parser: "@typescript-eslint/parser", // Specifies the ESLint parser
3 | extends: [
4 | "plugin:react/recommended",
5 | "plugin:@typescript-eslint/recommended", // Uses the recommended rules from @typescript-eslint/eslint-plugin
6 | "../.eslintrc"
7 | ],
8 | parserOptions: {
9 | ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features
10 | sourceType: "module", // Allows for the use of imports
11 | ecmaFeatures: {
12 | jsx: true // Allows for the parsing of JSX
13 | }
14 | },
15 | rules: {
16 | "@typescript-eslint/explicit-function-return-type": "off",
17 | "@typescript-eslint/no-explicit-any": "off", // Reduce the use of 'any'
18 | "@typescript-eslint/no-non-null-assertion": "off",
19 | "@typescript-eslint/no-var-requires": "off",
20 | "react/prop-types": "off",
21 | "@typescript-eslint/ban-ts-ignore": "off",
22 | "@typescript-eslint/member-delimiter-style": "off",
23 | "@typescript-eslint/indent": "off",
24 | "@typescript-eslint/explicit-member-accessibility": "off"
25 | },
26 | settings: {
27 | react: {
28 | version: "detect",
29 | }
30 | }
31 | };
32 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:12 as plugin-base
2 |
3 | WORKDIR /mono
4 | COPY package.json .
5 | RUN mkdir -p contracts/node_modules
6 |
7 | COPY burner-wallet-plugin/package.json ./burner-wallet-plugin/
8 | COPY burner-wallet-plugin/lerna.json ./burner-wallet-plugin/
9 | COPY burner-wallet-plugin/yarn.lock ./burner-wallet-plugin/
10 | COPY burner-wallet-plugin/tsconfig.json ./burner-wallet-plugin/
11 | COPY burner-wallet-plugin/tokenbridge-bw-exchange/package.json ./burner-wallet-plugin/tokenbridge-bw-exchange/
12 | COPY burner-wallet-plugin/staging/package.json ./burner-wallet-plugin/staging/
13 | COPY burner-wallet-plugin/testing/package.json ./burner-wallet-plugin/testing/
14 | COPY yarn.lock .
15 | RUN yarn install --production --frozen-lockfile
16 |
17 | COPY ./burner-wallet-plugin/tokenbridge-bw-exchange ./burner-wallet-plugin/tokenbridge-bw-exchange
18 | RUN yarn build:plugin
19 |
20 |
21 | FROM plugin-base as testing
22 | COPY ./burner-wallet-plugin/testing ./burner-wallet-plugin/testing
23 | WORKDIR /mono/burner-wallet-plugin
24 | CMD ["yarn", "start-testing"]
25 |
26 |
27 | FROM plugin-base as staging
28 | COPY ./burner-wallet-plugin/staging ./burner-wallet-plugin/staging
29 | WORKDIR /mono/burner-wallet-plugin
30 | CMD ["yarn", "start-staging"]
31 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/docker-compose.yml:
--------------------------------------------------------------------------------
1 | ---
2 | version: '2.4'
3 | services:
4 | staging:
5 | build:
6 | context: ..
7 | dockerfile: burner-wallet-plugin/Dockerfile
8 | target: staging
9 | environment:
10 | - NODE_ENV=production
11 | testing:
12 | build:
13 | context: ..
14 | dockerfile: burner-wallet-plugin/Dockerfile
15 | target: testing
16 | environment:
17 | - NODE_ENV=production
18 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/lerna.json:
--------------------------------------------------------------------------------
1 | {
2 | "packages": [
3 | "basic-wallet",
4 | "local-wallet",
5 | "tokenbridge-bw-exchange"
6 | ],
7 | "npmClient": "yarn",
8 | "useWorkspaces": true,
9 | "version": "independent"
10 | }
11 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "burner-wallet-plugin",
3 | "description": "Burner Wallet 2 plugin",
4 | "version": "1.0.0",
5 | "license": "GPL-3.0-only",
6 | "private": true,
7 | "scripts": {
8 | "install": "lerna bootstrap",
9 | "build": "lerna run --ignore testing --ignore staging build --stream",
10 | "lint": "eslint '*/**/*.{js,ts,tsx}' --ignore-path ../.eslintignore",
11 | "start-staging": "lerna run --scope staging start --stream",
12 | "start-testing": "lerna run --scope testing start --stream",
13 | "test": "lerna run --ignore testing --ignore staging test --stream"
14 | },
15 | "workspaces": [
16 | "staging",
17 | "testing",
18 | "tokenbridge-bw-exchange"
19 | ],
20 | "dependencies": {
21 | "@types/color": "3.0.0",
22 | "@typescript-eslint/eslint-plugin": "1.13.0",
23 | "@typescript-eslint/parser": "1.13.0",
24 | "eslint-plugin-react": "7.19.0",
25 | "lerna": "3.16.4",
26 | "typescript": "3.5.3"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/publish.md:
--------------------------------------------------------------------------------
1 | ## Plugin Package Information
2 |
3 | The package to be published gets its configuration from `tokenbridge/burner-wallet-plugin/tokenbridge-bw-exchange/package.json`
4 |
5 | ```json
6 | {
7 | "name": "tokenbridge-bw-exchange",
8 | "version": "1.0.0",
9 | "main": "dist/index.js",
10 | "types": "dist/index.d.ts",
11 | "files": [
12 | "/dist"
13 | ]
14 | }
15 | ```
16 |
17 | - `name` is the name of how package will be available in npm.
18 | - `main` is entry point for the package
19 | - `types` is the entry point for typescript types
20 | - `files` is the list of files included when publishing the package. So we have to run `yarn build` first to
21 | generate the `dist` folder.
22 |
23 | ## Steps to publish to npm
24 |
25 | 1. Create account in https://www.npmjs.com/
26 |
27 | 2. Go to `tokenbridge/burner-wallet-plugin/tokenbridge-bw-exchange/`
28 |
29 | 3. Run `yarn build`. Make sure it generates the `dist` folder
30 |
31 | 4. Update `version` in `tokenbridge/burner-wallet-plugin/tokenbridge-bw-exchange/package.json`
32 | 5. Run `yarn login` and fill login information if required.
33 | 6. Run `yarn publish --access public`.
34 | The prompt will ask for the new version, complete it with the version from `package.json`
35 |
36 | More information in https://classic.yarnpkg.com/en/docs/publishing-a-package/
37 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/staging/.env.example:
--------------------------------------------------------------------------------
1 | REACT_APP_INFURA_KEY=
2 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/staging/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "staging",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@burner-wallet/assets": "^1.1.10",
7 | "@burner-wallet/core": "^1.1.0",
8 | "@burner-wallet/exchange": "^1.1.4",
9 | "@burner-wallet/metamask-plugin": "^1.0.0",
10 | "@burner-wallet/modern-ui": "^1.0.7",
11 | "@poanet/tokenbridge-bw-exchange": "^1.0.0",
12 | "@types/node": "12.0.4",
13 | "@types/react": "*",
14 | "@types/react-dom": "16.8.4",
15 | "@types/react-router-dom": "^4.3.3",
16 | "react": "^16.8.6",
17 | "react-dom": "^16.8.6",
18 | "react-scripts": "3.0.1",
19 | "typescript": "3.5.1"
20 | },
21 | "scripts": {
22 | "start": "react-scripts start",
23 | "build": "react-scripts build",
24 | "test": "react-scripts test",
25 | "eject": "react-scripts eject"
26 | },
27 | "browserslist": {
28 | "production": [
29 | ">0.2%",
30 | "not dead",
31 | "not op_mini all"
32 | ],
33 | "development": [
34 | "last 1 chrome version",
35 | "last 1 firefox version",
36 | "last 1 safari version"
37 | ]
38 | },
39 | "devDependencies": {}
40 | }
41 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/staging/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omni/tokenbridge/961b12b9f3545830a04044e109762277efcea6ef/burner-wallet-plugin/staging/public/favicon.ico
--------------------------------------------------------------------------------
/burner-wallet-plugin/staging/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
22 | React App
23 |
24 |
25 |
26 |
27 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/staging/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/staging/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import BurnerCore from '@burner-wallet/core'
4 | import { InjectedSigner, LocalSigner } from '@burner-wallet/core/signers'
5 | import { XDaiBridge } from '@burner-wallet/exchange'
6 | import { xdai } from '@burner-wallet/assets'
7 | import { InfuraGateway, InjectedGateway, XDaiGateway } from '@burner-wallet/core/gateways'
8 | import Exchange from '@burner-wallet/exchange'
9 | import ModernUI from '@burner-wallet/modern-ui'
10 | import {
11 | Etc,
12 | Wetc,
13 | Dai,
14 | qDai,
15 | MOON,
16 | xMOON,
17 | TokenBridgeGateway,
18 | WETCBridge,
19 | QDAIBridge,
20 | MOONBridge
21 | } from '@poanet/tokenbridge-bw-exchange'
22 | import MetamaskPlugin from '@burner-wallet/metamask-plugin'
23 |
24 | const core = new BurnerCore({
25 | signers: [new InjectedSigner(), new LocalSigner()],
26 | gateways: [
27 | new InjectedGateway(),
28 | new XDaiGateway(),
29 | new InfuraGateway(process.env.REACT_APP_INFURA_KEY),
30 | new TokenBridgeGateway()
31 | ],
32 | assets: [xdai, Wetc, Etc, Dai, qDai, MOON, xMOON]
33 | })
34 |
35 | const exchange = new Exchange([new XDaiBridge(), new WETCBridge(), new QDAIBridge(), new MOONBridge()])
36 |
37 | const BurnerWallet = () =>
38 |
39 | ReactDOM.render(, document.getElementById('root'))
40 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/staging/src/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/staging/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": [
5 | "dom",
6 | "dom.iterable",
7 | "esnext"
8 | ],
9 | "allowJs": true,
10 | "skipLibCheck": true,
11 | "esModuleInterop": true,
12 | "allowSyntheticDefaultImports": true,
13 | "strict": true,
14 | "forceConsistentCasingInFileNames": true,
15 | "module": "esnext",
16 | "moduleResolution": "node",
17 | "resolveJsonModule": true,
18 | "isolatedModules": true,
19 | "noEmit": true,
20 | "jsx": "preserve"
21 | },
22 | "include": [
23 | "src"
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/testing/.env.example:
--------------------------------------------------------------------------------
1 | REACT_APP_INFURA_KEY=
2 | #REACT_APP_PK=0x
3 |
4 | REACT_APP_MODE=AMB_NATIVE_TO_ERC677
5 |
6 | REACT_APP_HOME_TOKEN_NAME=sPOA
7 | REACT_APP_HOME_NETWORK=77
8 | REACT_APP_HOME_MEDIATOR_ADDRESS=0x867949C3F2f66D827Ed40847FaA7B3a369370e13
9 | REACT_APP_HOME_TOKEN_ADDRESS=
10 |
11 | REACT_APP_FOREIGN_TOKEN_NAME=ksPOA
12 | REACT_APP_FOREIGN_NETWORK=42
13 | REACT_APP_FOREIGN_MEDIATOR_ADDRESS=0x99FB1a25caeB9c3a5Bf132686E2fe5e27BC0e2dd
14 | REACT_APP_FOREIGN_TOKEN_ADDRESS=0xff94183659f549D6273349696d73686Ee1d2AC83
15 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/testing/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "testing",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@burner-wallet/assets": "^1.1.10",
7 | "@burner-wallet/core": "^1.1.0",
8 | "@burner-wallet/exchange": "^1.1.4",
9 | "@burner-wallet/metamask-plugin": "^1.0.0",
10 | "@burner-wallet/modern-ui": "^1.0.7",
11 | "@poanet/tokenbridge-bw-exchange": "^1.0.0",
12 | "@types/node": "12.0.4",
13 | "@types/react": "16.8.19",
14 | "@types/react-dom": "16.8.4",
15 | "@types/react-router-dom": "^4.3.3",
16 | "react": "^16.8.6",
17 | "react-dom": "^16.8.6",
18 | "react-scripts": "3.0.1",
19 | "typescript": "3.5.1"
20 | },
21 | "scripts": {
22 | "start": "react-scripts start",
23 | "build": "react-scripts build",
24 | "test": "react-scripts test",
25 | "eject": "react-scripts eject"
26 | },
27 | "browserslist": {
28 | "production": [
29 | ">0.2%",
30 | "not dead",
31 | "not op_mini all"
32 | ],
33 | "development": [
34 | "last 1 chrome version",
35 | "last 1 firefox version",
36 | "last 1 safari version"
37 | ]
38 | },
39 | "devDependencies": {
40 | "axios": "^0.19.0"
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/testing/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omni/tokenbridge/961b12b9f3545830a04044e109762277efcea6ef/burner-wallet-plugin/testing/public/favicon.ico
--------------------------------------------------------------------------------
/burner-wallet-plugin/testing/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
22 | React App
23 |
24 |
25 |
26 |
27 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/testing/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "Burner Wallet",
3 | "name": "Burner Wallet",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/testing/src/LocalhostGateway.ts:
--------------------------------------------------------------------------------
1 | import { Gateway } from '@burner-wallet/core/gateways'
2 | import Web3 from 'web3'
3 |
4 | export default class LocalhostGateway extends Gateway {
5 | private readonly providers: object
6 | private readonly providerStrings: { [id: string]: string }
7 | constructor() {
8 | super()
9 | this.providerStrings = {
10 | '111': 'http://localhost:8545',
11 | '1337': 'http://localhost:8546'
12 | }
13 | this.providers = {}
14 | }
15 |
16 | isAvailable() {
17 | return true
18 | }
19 |
20 | getNetworks() {
21 | return ['111', '1337']
22 | }
23 |
24 | _provider(network) {
25 | if (!this.providers[network]) {
26 | this._makeProvider(network)
27 | }
28 | return this.providers[network]
29 | }
30 |
31 | _makeProvider(network) {
32 | if (!this.providerStrings[network]) {
33 | throw new Error(`Network ${network} not supported by LocalhostGateway`)
34 | }
35 |
36 | this.providers[network] = new Web3.providers.HttpProvider(this.providerStrings[network])
37 | }
38 |
39 | send(network, payload) {
40 | return new Promise((resolve, reject) => {
41 | if (this.getNetworks().indexOf(network) === -1) {
42 | return reject(new Error('LocalhostGateway does not support this network'))
43 | }
44 |
45 | this._provider(network).send(payload, (err, response) => {
46 | if (err) {
47 | return reject(err)
48 | }
49 | return resolve(response.result)
50 | })
51 | })
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/testing/src/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/testing/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": [
5 | "dom",
6 | "dom.iterable",
7 | "esnext"
8 | ],
9 | "allowJs": true,
10 | "skipLibCheck": true,
11 | "esModuleInterop": true,
12 | "allowSyntheticDefaultImports": true,
13 | "strict": true,
14 | "forceConsistentCasingInFileNames": true,
15 | "module": "esnext",
16 | "moduleResolution": "node",
17 | "resolveJsonModule": true,
18 | "isolatedModules": true,
19 | "noEmit": true,
20 | "noImplicitAny": false,
21 | "jsx": "preserve"
22 | },
23 | "include": [
24 | "src"
25 | ]
26 | }
27 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/tokenbridge-bw-exchange/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@poanet/tokenbridge-bw-exchange",
3 | "version": "1.1.0",
4 | "license": "GPL-3.0",
5 | "main": "dist/index.js",
6 | "types": "dist/index.d.ts",
7 | "files": [
8 | "/dist",
9 | "README.md"
10 | ],
11 | "scripts": {
12 | "build": "tsc",
13 | "start-basic": "tsc -w",
14 | "start-local": "tsc -w",
15 | "test": "TS_NODE_PROJECT=\"tsconfig.testing.json\" mocha -r ts-node/register test/**/*.spec.ts"
16 | },
17 | "dependencies": {
18 | "@burner-wallet/assets": "^1.1.10",
19 | "@burner-wallet/core": "^1.1.9",
20 | "@burner-wallet/exchange": "^1.1.4",
21 | "@burner-wallet/types": "^1.0.6"
22 | },
23 | "devDependencies": {
24 | "@types/mocha": "^7.0.2",
25 | "chai": "^4.2.0",
26 | "mocha": "^5.2.0",
27 | "ts-node": "^8.8.2",
28 | "typescript": "^3.5.2"
29 | },
30 | "repository": {
31 | "type": "git",
32 | "url": "https://github.com/poanetwork/tokenbridge.git",
33 | "directory": "burner-wallet-plugin/tokenbridge-bw-exchange"
34 | },
35 | "homepage": "https://tokenbridge.net/",
36 | "keywords": [
37 | "tokenbridge",
38 | "burner-wallet"
39 | ]
40 | }
41 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/tokenbridge-bw-exchange/src/bridges/MOONBridge.ts:
--------------------------------------------------------------------------------
1 | import { Mediator } from '../burner-wallet'
2 |
3 | export default class MOONBridge extends Mediator {
4 | constructor() {
5 | super({
6 | assetA: 'xmoon',
7 | assetABridge: '0x1E0507046130c31DEb20EC2f870ad070Ff266079',
8 | assetB: 'moon',
9 | assetBBridge: '0xFEaB457D95D9990b7eb6c943c839258245541754'
10 | })
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/tokenbridge-bw-exchange/src/bridges/QDAIBridge.ts:
--------------------------------------------------------------------------------
1 | import { MediatorErcToNative } from '../burner-wallet'
2 |
3 | export default class QDAIBridge extends MediatorErcToNative {
4 | constructor() {
5 | super({
6 | assetA: 'qdai',
7 | assetABridge: '0xFEaB457D95D9990b7eb6c943c839258245541754',
8 | assetB: 'dai',
9 | assetBBridge: '0xf6edFA16926f30b0520099028A145F4E06FD54ed'
10 | })
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/tokenbridge-bw-exchange/src/bridges/index.ts:
--------------------------------------------------------------------------------
1 | export { default as WETCBridge } from './WETCBridge'
2 | export { default as QDAIBridge } from './QDAIBridge'
3 | export { default as MOONBridge } from './MOONBridge'
4 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/tokenbridge-bw-exchange/src/burner-wallet/assets/Dai.ts:
--------------------------------------------------------------------------------
1 | import BridgeableERC20Asset from './BridgeableERC20Asset'
2 |
3 | export default new BridgeableERC20Asset({
4 | id: 'dai',
5 | name: 'Dai',
6 | network: '1',
7 | address: '0x6b175474e89094c44da98b954eedeac495271d0f',
8 | usdPrice: 1,
9 | icon: 'https://static.burnerfactory.com/icons/mcd.svg',
10 | bridgeModes: ['erc-to-native-amb']
11 | })
12 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/tokenbridge-bw-exchange/src/burner-wallet/assets/MOON.ts:
--------------------------------------------------------------------------------
1 | import BridgeableERC20Asset from './BridgeableERC20Asset'
2 |
3 | export default new BridgeableERC20Asset({
4 | id: 'moon',
5 | name: 'MOON',
6 | network: '4',
7 | address: '0xDF82c9014F127243CE1305DFE54151647d74B27A',
8 | icon: 'https://blockscout.com/poa/xdai/images/icons/moon.png',
9 | bridgeModes: ['erc-to-erc-amb']
10 | })
11 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/tokenbridge-bw-exchange/src/burner-wallet/assets/Wetc.ts:
--------------------------------------------------------------------------------
1 | import { default as ERC677Asset } from './ERC677Asset'
2 |
3 | export default new ERC677Asset({
4 | id: 'wetc',
5 | name: 'WETC',
6 | network: '1',
7 | address: '0x86aabcc646f290b9fc9bd05ce17c3858d1511da1'
8 | })
9 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/tokenbridge-bw-exchange/src/burner-wallet/assets/qDai.ts:
--------------------------------------------------------------------------------
1 | import NativeMediatorAsset from './NativeMediatorAsset'
2 |
3 | export default new NativeMediatorAsset({
4 | id: 'qdai',
5 | name: 'qDai',
6 | network: '181',
7 | usdPrice: 1,
8 | mediatorAddress: '0xFEaB457D95D9990b7eb6c943c839258245541754'
9 | })
10 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/tokenbridge-bw-exchange/src/burner-wallet/assets/sPOA.ts:
--------------------------------------------------------------------------------
1 | import NativeMediatorAsset from './NativeMediatorAsset'
2 |
3 | export default new NativeMediatorAsset({
4 | id: 'spoa',
5 | name: 'sPOA',
6 | network: '77'
7 | })
8 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/tokenbridge-bw-exchange/src/burner-wallet/assets/xMOON.ts:
--------------------------------------------------------------------------------
1 | import { default as ERC677Asset } from './ERC677Asset'
2 |
3 | export default new ERC677Asset({
4 | id: 'xmoon',
5 | name: 'xMOON',
6 | network: '100',
7 | address: '0x1e16aa4Df73d29C029d94CeDa3e3114EC191E25A',
8 | icon: 'https://blockscout.com/poa/xdai/images/icons/moon.png'
9 | })
10 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/tokenbridge-bw-exchange/src/burner-wallet/gateways/TokenBridgeGateway.ts:
--------------------------------------------------------------------------------
1 | import { Gateway } from '@burner-wallet/core/gateways'
2 | import Web3 from 'web3'
3 |
4 | export default class TokenBridgeGateway extends Gateway {
5 | private readonly providers: object
6 | private readonly providerStrings: { [id: string]: string }
7 | constructor() {
8 | super()
9 | this.providerStrings = {
10 | '61': `https://www.ethercluster.com/etc`,
11 | '77': 'https://sokol.poa.network',
12 | '99': 'https://core.poa.network',
13 | '181': 'https://quorum-rpc.tokenbridge.net'
14 | }
15 | this.providers = {}
16 | }
17 |
18 | isAvailable() {
19 | return true
20 | }
21 |
22 | getNetworks() {
23 | return ['61', '77', '99', '181']
24 | }
25 |
26 | _provider(network) {
27 | if (!this.providers[network]) {
28 | this._makeProvider(network)
29 | }
30 | return this.providers[network]
31 | }
32 |
33 | _makeProvider(network) {
34 | if (!this.providerStrings[network]) {
35 | throw new Error(`Network ${network} not supported by TokenBridgeGateway`)
36 | }
37 |
38 | this.providers[network] = new Web3.providers.HttpProvider(this.providerStrings[network])
39 | }
40 |
41 | send(network, payload) {
42 | return new Promise((resolve, reject) => {
43 | if (this.getNetworks().indexOf(network) === -1) {
44 | return reject(new Error('TokenBridgeGateway does not support this network'))
45 | }
46 |
47 | this._provider(network).send(payload, (err, response) => {
48 | if (err) {
49 | return reject(err)
50 | }
51 | return resolve(response.result)
52 | })
53 | })
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/tokenbridge-bw-exchange/src/burner-wallet/index.ts:
--------------------------------------------------------------------------------
1 | export { default as sPOA } from './assets/sPOA'
2 | export { default as Etc } from './assets/Etc'
3 | export { default as Wetc } from './assets/Wetc'
4 | export { default as Dai } from './assets/Dai'
5 | export { default as qDai } from './assets/qDai'
6 | export { default as MOON } from './assets/MOON'
7 | export { default as xMOON } from './assets/xMOON'
8 | export { default as ERC677Asset } from './assets/ERC677Asset'
9 | export { default as BridgeableERC20Asset } from './assets/BridgeableERC20Asset'
10 | export { default as NativeMediatorAsset } from './assets/NativeMediatorAsset'
11 | export { default as TokenBridgeGateway } from './gateways/TokenBridgeGateway'
12 | export { default as Mediator } from './pairs/Mediator'
13 | export { default as MediatorErcToNative } from './pairs/MediatorErcToNative'
14 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/tokenbridge-bw-exchange/src/index.ts:
--------------------------------------------------------------------------------
1 | export {
2 | ERC677Asset,
3 | BridgeableERC20Asset,
4 | NativeMediatorAsset,
5 | sPOA,
6 | Etc,
7 | Wetc,
8 | qDai,
9 | Dai,
10 | MOON,
11 | xMOON,
12 | TokenBridgeGateway,
13 | Mediator,
14 | MediatorErcToNative
15 | } from './burner-wallet'
16 | export { WETCBridge, QDAIBridge, MOONBridge } from './bridges'
17 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/tokenbridge-bw-exchange/src/utils/abis.ts:
--------------------------------------------------------------------------------
1 | export { default as ERC677_ABI } from './abis/ERC677'
2 | export { default as FOREIGN_NATIVE_TO_ERC_ABI } from './abis/ForeignBridgeNativeToErc'
3 | export { default as HOME_NATIVE_TO_ERC_ABI } from './abis/HomeBridgeNativeToErc'
4 | export { default as MEDIATOR_ABI } from './abis/Mediator'
5 | export { default as MEDIATOR_FEE_MANAGER_ABI } from './abis/MediatorFeeManager'
6 | export { default as MEDIATOR_ERC_TO_NATIVE_ABI } from './abis/MediatorErcToNative'
7 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/tokenbridge-bw-exchange/src/utils/abis/ForeignBridgeNativeToErc.ts:
--------------------------------------------------------------------------------
1 | export default [
2 | {
3 | constant: true,
4 | inputs: [
5 | {
6 | name: '_txHash',
7 | type: 'bytes32'
8 | }
9 | ],
10 | name: 'relayedMessages',
11 | outputs: [
12 | {
13 | name: '',
14 | type: 'bool'
15 | }
16 | ],
17 | payable: false,
18 | stateMutability: 'view',
19 | type: 'function'
20 | },
21 | {
22 | constant: true,
23 | inputs: [],
24 | name: 'deployedAtBlock',
25 | outputs: [
26 | {
27 | name: '',
28 | type: 'uint256'
29 | }
30 | ],
31 | payable: false,
32 | stateMutability: 'view',
33 | type: 'function'
34 | },
35 | {
36 | constant: true,
37 | inputs: [],
38 | name: 'getHomeFee',
39 | outputs: [
40 | {
41 | name: '',
42 | type: 'uint256'
43 | }
44 | ],
45 | payable: false,
46 | stateMutability: 'view',
47 | type: 'function'
48 | }
49 | ]
50 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/tokenbridge-bw-exchange/src/utils/abis/HomeBridgeNativeToErc.ts:
--------------------------------------------------------------------------------
1 | export default [
2 | {
3 | anonymous: false,
4 | inputs: [
5 | {
6 | indexed: false,
7 | name: 'recipient',
8 | type: 'address'
9 | },
10 | {
11 | indexed: false,
12 | name: 'value',
13 | type: 'uint256'
14 | },
15 | {
16 | indexed: false,
17 | name: 'transactionHash',
18 | type: 'bytes32'
19 | }
20 | ],
21 | name: 'AffirmationCompleted',
22 | type: 'event'
23 | },
24 | {
25 | constant: true,
26 | inputs: [],
27 | name: 'deployedAtBlock',
28 | outputs: [
29 | {
30 | name: '',
31 | type: 'uint256'
32 | }
33 | ],
34 | payable: false,
35 | stateMutability: 'view',
36 | type: 'function'
37 | },
38 | {
39 | constant: true,
40 | inputs: [],
41 | name: 'getForeignFee',
42 | outputs: [
43 | {
44 | name: '',
45 | type: 'uint256'
46 | }
47 | ],
48 | payable: false,
49 | stateMutability: 'view',
50 | type: 'function'
51 | }
52 | ]
53 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/tokenbridge-bw-exchange/src/utils/abis/Mediator.ts:
--------------------------------------------------------------------------------
1 | export default [
2 | {
3 | anonymous: false,
4 | inputs: [
5 | {
6 | indexed: true,
7 | name: 'recipient',
8 | type: 'address'
9 | },
10 | {
11 | indexed: false,
12 | name: 'value',
13 | type: 'uint256'
14 | },
15 | {
16 | indexed: true,
17 | name: 'messageId',
18 | type: 'bytes32'
19 | }
20 | ],
21 | name: 'TokensBridged',
22 | type: 'event'
23 | },
24 | {
25 | constant: true,
26 | inputs: [],
27 | name: 'feeManagerContract',
28 | outputs: [
29 | {
30 | name: '',
31 | type: 'address'
32 | }
33 | ],
34 | payable: false,
35 | stateMutability: 'view',
36 | type: 'function'
37 | },
38 | {
39 | constant: false,
40 | inputs: [
41 | {
42 | name: '',
43 | type: 'address'
44 | },
45 | {
46 | name: '',
47 | type: 'uint256'
48 | }
49 | ],
50 | name: 'relayTokens',
51 | outputs: [],
52 | payable: false,
53 | stateMutability: 'nonpayable',
54 | type: 'function'
55 | },
56 | {
57 | constant: true,
58 | inputs: [],
59 | name: 'getBridgeMode',
60 | outputs: [
61 | {
62 | name: '',
63 | type: 'bytes4'
64 | }
65 | ],
66 | payable: false,
67 | stateMutability: 'pure',
68 | type: 'function'
69 | }
70 | ]
71 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/tokenbridge-bw-exchange/src/utils/abis/MediatorErcToNative.ts:
--------------------------------------------------------------------------------
1 | export default [
2 | {
3 | constant: true,
4 | inputs: [
5 | {
6 | name: '',
7 | type: 'bytes32'
8 | }
9 | ],
10 | name: 'getFee',
11 | outputs: [
12 | {
13 | name: '',
14 | type: 'uint256'
15 | }
16 | ],
17 | payable: false,
18 | stateMutability: 'view',
19 | type: 'function'
20 | },
21 | {
22 | constant: true,
23 | inputs: [
24 | {
25 | name: '',
26 | type: 'bytes32'
27 | },
28 | {
29 | name: '',
30 | type: 'uint256'
31 | }
32 | ],
33 | name: 'calculateFee',
34 | outputs: [
35 | {
36 | name: '',
37 | type: 'uint256'
38 | }
39 | ],
40 | payable: false,
41 | stateMutability: 'view',
42 | type: 'function'
43 | }
44 | ]
45 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/tokenbridge-bw-exchange/src/utils/abis/MediatorFeeManager.ts:
--------------------------------------------------------------------------------
1 | export default [
2 | {
3 | constant: true,
4 | inputs: [
5 | {
6 | name: '',
7 | type: 'uint256'
8 | }
9 | ],
10 | name: 'calculateFee',
11 | outputs: [
12 | {
13 | name: '',
14 | type: 'uint256'
15 | }
16 | ],
17 | payable: false,
18 | stateMutability: 'view',
19 | type: 'function'
20 | },
21 | {
22 | constant: true,
23 | inputs: [],
24 | name: 'fee',
25 | outputs: [
26 | {
27 | name: '',
28 | type: 'uint256'
29 | }
30 | ],
31 | payable: false,
32 | stateMutability: 'view',
33 | type: 'function'
34 | }
35 | ]
36 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/tokenbridge-bw-exchange/src/utils/index.ts:
--------------------------------------------------------------------------------
1 | export { constants, wait, waitForEvent, isVanillaBridgeContract, isBridgeContract } from './utils'
2 | export {
3 | ERC677_ABI,
4 | FOREIGN_NATIVE_TO_ERC_ABI,
5 | HOME_NATIVE_TO_ERC_ABI,
6 | MEDIATOR_ABI,
7 | MEDIATOR_FEE_MANAGER_ABI,
8 | MEDIATOR_ERC_TO_NATIVE_ABI
9 | } from './abis'
10 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/tokenbridge-bw-exchange/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "rootDir": "src",
5 | "outDir": "./dist"
6 | },
7 | "include": [
8 | "./src"
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/tokenbridge-bw-exchange/tsconfig.testing.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "module": "commonjs"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/burner-wallet-plugin/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "esnext",
4 | "declaration": true,
5 | "removeComments": true,
6 | "noLib": false,
7 | "emitDecoratorMetadata": true,
8 | "experimentalDecorators": true,
9 | "esModuleInterop": true,
10 | "jsx": "react",
11 | "target": "esnext",
12 | "sourceMap": true,
13 | "strict": true,
14 | "allowSyntheticDefaultImports": true,
15 | "moduleResolution": "node",
16 | "resolveJsonModule": true,
17 | "noImplicitAny": false,
18 | "lib": [
19 | "es6",
20 | "dom"
21 | ],
22 | "types" : [
23 | "node"
24 | ]
25 | },
26 | "exclude": [
27 | "node_modules",
28 | "**/*.spec.ts"
29 | ]
30 | }
31 |
--------------------------------------------------------------------------------
/commons/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "airbnb-base",
4 | "../.eslintrc"
5 | ],
6 | "rules": {
7 | "no-unused-expressions": "off",
8 | "import/no-extraneous-dependencies": "off",
9 | "no-bitwise": "off"
10 | },
11 | "env": {
12 | "mocha": true
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/commons/README.md:
--------------------------------------------------------------------------------
1 | # POA TokenBridge / Commons
2 | Interfaces, constants and utilities shared between the sub-repositories
3 |
--------------------------------------------------------------------------------
/commons/constants.js:
--------------------------------------------------------------------------------
1 | const BRIDGE_MODES = {
2 | ERC_TO_NATIVE: 'ERC_TO_NATIVE',
3 | ARBITRARY_MESSAGE: 'ARBITRARY_MESSAGE',
4 | AMB_ERC_TO_ERC: 'AMB_ERC_TO_ERC'
5 | }
6 |
7 | const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
8 |
9 | module.exports = {
10 | BRIDGE_MODES,
11 | ZERO_ADDRESS
12 | }
13 |
--------------------------------------------------------------------------------
/commons/index.js:
--------------------------------------------------------------------------------
1 | const constants = require('./constants')
2 | const abis = require('./abis')
3 | const utils = require('./utils')
4 | const message = require('./message')
5 |
6 | module.exports = {
7 | ...constants,
8 | ...abis,
9 | ...utils,
10 | ...message
11 | }
12 |
--------------------------------------------------------------------------------
/commons/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "commons",
3 | "version": "0.0.1",
4 | "private": true,
5 | "main": "index.js",
6 | "scripts": {
7 | "lint": "eslint . --ignore-path ../.eslintignore",
8 | "test": "NODE_ENV=test mocha"
9 | },
10 | "dependencies": {
11 | "@mycrypto/gas-estimation": "^1.1.0",
12 | "gas-price-oracle": "^0.1.5",
13 | "web3-utils": "^1.3.0",
14 | "node-fetch": "^2.1.2"
15 | },
16 | "devDependencies": {
17 | "bn-chai": "^1.0.1",
18 | "chai": "^4.2.0"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/commons/test/constants.test.js:
--------------------------------------------------------------------------------
1 | const { expect } = require('chai')
2 | const { BRIDGE_MODES } = require('../constants')
3 |
4 | describe('constants', () => {
5 | it('should contain correct number of bridge types', () => {
6 | expect(Object.keys(BRIDGE_MODES).length).to.be.equal(3)
7 | })
8 | })
9 |
--------------------------------------------------------------------------------
/commons/test/message.test.js:
--------------------------------------------------------------------------------
1 | const { BN } = require('web3-utils')
2 | const { expect } = require('chai').use(require('bn-chai')(BN))
3 | const { parseAMBMessage, strip0x } = require('../message')
4 |
5 | describe('strip0x', () => {
6 | it('should remove 0x from input', () => {
7 | // Given
8 | const input = '0x12345'
9 |
10 | // When
11 | const result = strip0x(input)
12 |
13 | // Then
14 | expect(result).to.be.equal('12345')
15 | })
16 | it('should not modify input if 0x is not present', () => {
17 | // Given
18 | const input = '12345'
19 |
20 | // When
21 | const result = strip0x(input)
22 |
23 | // Then
24 | expect(result).to.be.equal(input)
25 | })
26 | })
27 | describe('parseAMBMessage', () => {
28 | it('should parse data type 00', () => {
29 | const msgSender = '0x003667154bb32e42bb9e1e6532f19d187fa0082e'
30 | const msgExecutor = '0xf4bef13f9f4f2b203faf0c3cbbaabe1afe056955'
31 | const msgId = '0xbdceda9d8c94838aca10c687da1411a07b1390e88239c0638cb9cc264219cc10'
32 | const msgGasLimit = '000000000000000000000000000000000000000000000000000000005b877705'
33 | const msgDataType = '00'
34 | const msgData = '0xb1591967aed668a4b27645ff40c444892d91bf5951b382995d4d4f6ee3a2ce03'
35 | const message = `0x${strip0x(msgId)}${strip0x(msgSender)}${strip0x(
36 | msgExecutor
37 | )}${msgGasLimit}${msgDataType}${strip0x(msgData)}`
38 |
39 | // when
40 | const { sender, executor, messageId } = parseAMBMessage(message)
41 |
42 | // then
43 | expect(sender).to.be.equal(msgSender)
44 | expect(executor).to.be.equal(msgExecutor)
45 | expect(messageId).to.be.equal(msgId)
46 | })
47 | })
48 |
--------------------------------------------------------------------------------
/deployment-e2e/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.7-stretch
2 | RUN curl -fsSL https://get.docker.com | sh
3 | RUN pip3 install docker molecule==2.22rc1 molecule[docker] flake8
4 | WORKDIR mono/deployment-e2e
5 |
--------------------------------------------------------------------------------
/deployment-e2e/README.md:
--------------------------------------------------------------------------------
1 | # POA TokenBridge / Deployment Testing
2 |
3 | The deployment playbooks are tested using [Molecule](https://molecule.readthedocs.io).
4 |
5 | ## Push remote branch
6 |
7 | The deployment playbooks are cloning the monorepository on target hosts, using your current local git branch name. If the branch does not exists on remote, you need to push it.
8 |
9 | ```
10 | git push
11 | ```
12 |
13 | Alternatively, if there are no changes except the playbooks, you can use the `master` branch:
14 |
15 | ```
16 | ./molecule.sh
17 | ```
18 |
19 | In this case `master` branch will be used as a codebase for Monitor, Oracle and Contracts deployed by your local playbook.
20 |
21 | ## Run the tests
22 |
23 | ```
24 | ./molecule.sh
25 | ```
26 |
27 | Available scenarios:
28 |
29 | Scenario | Description
30 | --- | ---
31 | oracle | Deploys and checks standalone Oracle on Ubuntu host
32 |
33 | ## Ultimate E2E tests
34 |
35 | For information on the Ultimate tests, please refer to [Ultimate](../e2e-commons/ULTIMATE.md).
36 |
--------------------------------------------------------------------------------
/deployment-e2e/molecule.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | cd ./e2e-commons
3 | set -e # exit when any command fails
4 |
5 | if [ -z "$CI" ]; then
6 | docker-compose build molecule_runner
7 | else
8 | docker-compose pull molecule_runner
9 | fi
10 | docker network create --driver bridge ultimate || true
11 | while [ "$1" != "" ]; do
12 | docker-compose run molecule_runner /bin/bash -c "molecule test --scenario-name $1"
13 |
14 | shift # Shift all the parameters down by one
15 | done
16 |
--------------------------------------------------------------------------------
/deployment-e2e/molecule/monitor/Dockerfile.j2:
--------------------------------------------------------------------------------
1 | # Molecule managed
2 |
3 | {% if item.registry is defined %}
4 | FROM {{ item.registry.url }}/{{ item.image }}
5 | {% else %}
6 | FROM {{ item.image }}
7 | {% endif %}
8 |
9 | RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \
10 | elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash && dnf clean all; \
11 | 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; \
12 | elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml && zypper clean -a; \
13 | elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates; \
14 | elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates && xbps-remove -O; fi
15 |
--------------------------------------------------------------------------------
/deployment-e2e/molecule/monitor/converge.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - import_playbook: ../../../deployment/site.yml
3 | - import_playbook: ./run-checks.yml
4 |
--------------------------------------------------------------------------------
/deployment-e2e/molecule/monitor/molecule.yml:
--------------------------------------------------------------------------------
1 | ---
2 | dependency:
3 | name: galaxy
4 | driver:
5 | name: docker
6 | lint:
7 | name: yamllint
8 | enabled: True
9 | options:
10 | config-data:
11 | ignore: ../../hosts.yml
12 | platforms:
13 | - name: monitor-host
14 | groups:
15 | - example
16 | children:
17 | - monitor
18 | image: ubuntu:16.04
19 | privileged: true
20 | network_mode: host
21 | volumes:
22 | - /var/run/docker.sock:/var/run/docker.sock
23 | provisioner:
24 | name: ansible
25 | lint:
26 | name: ansible-lint
27 | enabled: True
28 | options:
29 | r: ["bug"]
30 | playbooks:
31 | prepare: ../prepare.yml
32 | converge: ./converge.yml
33 | inventory:
34 | host_vars:
35 | monitor-host:
36 | MONITOR_PORT: 3003
37 | syslog_server_port: "udp://127.0.0.1:514"
38 | verifier:
39 | name: testinfra
40 | lint:
41 | name: flake8
42 | additional_files_or_dirs:
43 | - ../../tests/*
44 | scenario:
45 | name: monitor
46 | test_sequence:
47 | - lint
48 | - cleanup
49 | - destroy
50 | - dependency
51 | - syntax
52 | - create
53 | - prepare
54 | - converge
55 | - verify
56 | - destroy
57 |
--------------------------------------------------------------------------------
/deployment-e2e/molecule/monitor/run-checks.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Generate initial data for monitor
3 | hosts: monitor
4 | become: true
5 | tasks:
6 | - name: Run monitor checks
7 | shell: /bin/bash -c 'cd /home/poadocker/bridge/monitor/scripts; ./getBridgeStats.sh >cronWorker.out 2>cronWorker.err'
8 |
--------------------------------------------------------------------------------
/deployment-e2e/molecule/monitor/tests/test_monitor.py:
--------------------------------------------------------------------------------
1 | import os
2 | import pytest
3 | import testinfra.utils.ansible_runner
4 |
5 | testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
6 | os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('monitor')
7 |
8 |
9 | @pytest.mark.parametrize("name", [
10 | ("monitor_monitor_1")
11 | ])
12 | def test_docker_containers(host, name):
13 | container = host.docker(name)
14 | assert container.is_running
15 |
16 |
17 | @pytest.mark.parametrize("service", [
18 | ("tokenbridge-monitor"),
19 | ("rsyslog")
20 | ])
21 | def test_services(host, service):
22 | assert host.service(service).is_enabled
23 | assert host.service(service).is_running
24 |
25 |
26 | @pytest.mark.parametrize("filename", [
27 | ("/etc/rsyslog.d/33-monitor-docker.conf"),
28 | ("/etc/rsyslog.d/38-monitor-remote-logging.conf")
29 | ])
30 | def test_logging(host, filename):
31 | assert host.file(filename).exists
32 | assert host.file(filename).mode == 0o0644
33 |
34 |
35 | def test_home_exists(host):
36 | assert host.run_test(
37 | 'curl -s http://localhost:3003/bridge | '
38 | 'grep -q -i "home"'
39 | )
40 |
41 |
42 | def test_foreign_exists(host):
43 | assert host.run_test(
44 | 'curl -s http://localhost:3003/bridge | '
45 | 'grep -q -i "foreign"'
46 | )
47 |
48 |
49 | def test_no_error(host):
50 | assert host.run_expect(
51 | [1],
52 | 'curl -s http://localhost:3003/bridge | '
53 | 'grep -i -q "error"'
54 | )
55 |
--------------------------------------------------------------------------------
/deployment-e2e/molecule/multiple/Dockerfile.j2:
--------------------------------------------------------------------------------
1 | # Molecule managed
2 |
3 | {% if item.registry is defined %}
4 | FROM {{ item.registry.url }}/{{ item.image }}
5 | {% else %}
6 | FROM {{ item.image }}
7 | {% endif %}
8 |
9 | RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \
10 | elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash && dnf clean all; \
11 | 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; \
12 | elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml && zypper clean -a; \
13 | elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates; \
14 | elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates && xbps-remove -O; fi
15 |
--------------------------------------------------------------------------------
/deployment-e2e/molecule/multiple/molecule.yml:
--------------------------------------------------------------------------------
1 | ---
2 | dependency:
3 | name: galaxy
4 | driver:
5 | name: docker
6 | lint:
7 | name: yamllint
8 | enabled: True
9 | options:
10 | config-data:
11 | ignore: ../../hosts.yml
12 | platforms:
13 | - name: multiple-host
14 | groups:
15 | - example
16 | children:
17 | - oracle
18 | - monitor
19 | image: ubuntu:16.04
20 | privileged: true
21 | network_mode: host
22 | volumes:
23 | - /var/run/docker.sock:/var/run/docker.sock
24 | provisioner:
25 | name: ansible
26 | lint:
27 | name: ansible-lint
28 | enabled: True
29 | options:
30 | r: ["bug"]
31 | playbooks:
32 | prepare: ../prepare.yml
33 | converge: ../monitor/converge.yml
34 | inventory:
35 | host_vars:
36 | multiple-host:
37 | ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "6c48435bd464a53ed66ed62127c4dba8af75cf1a99a8ebe2680599948fbfbc6d"
38 | MONITOR_PORT: 3003
39 | syslog_server_port: "udp://127.0.0.1:514"
40 | verifier:
41 | name: testinfra
42 | lint:
43 | name: flake8
44 | additional_files_or_dirs:
45 | - ../../tests/*
46 | scenario:
47 | name: multiple
48 | test_sequence:
49 | - lint
50 | - cleanup
51 | - destroy
52 | - dependency
53 | - syntax
54 | - create
55 | - prepare
56 | - converge
57 | - verify
58 | - destroy
59 |
--------------------------------------------------------------------------------
/deployment-e2e/molecule/multiple/tests/test_multiple.py:
--------------------------------------------------------------------------------
1 | import os
2 | import pytest
3 | import testinfra.utils.ansible_runner
4 |
5 | testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
6 | os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all')
7 |
8 |
9 | @pytest.mark.parametrize("service", [
10 | ("poabridge"),
11 | ("tokenbridge-monitor")
12 | ])
13 | def test_services(host, service):
14 | assert host.service(service).is_enabled
15 | assert host.service(service).is_running
16 |
17 |
18 | @pytest.mark.parametrize("name", [
19 | ("oracle_rabbit_1"),
20 | ("oracle_redis_1"),
21 | ("oracle_bridge_request_1"),
22 | ("oracle_bridge_collected_1"),
23 | ("oracle_bridge_affirmation_1"),
24 | ("oracle_bridge_senderhome_1"),
25 | ("oracle_bridge_senderforeign_1"),
26 | ("oracle_bridge_shutdown_1"),
27 | ("monitor_monitor_1")
28 | ])
29 | def test_docker_containers(host, name):
30 | container = host.docker(name)
31 | assert container.is_running
32 |
--------------------------------------------------------------------------------
/deployment-e2e/molecule/oracle/Dockerfile.j2:
--------------------------------------------------------------------------------
1 | # Molecule managed
2 |
3 | {% if item.registry is defined %}
4 | FROM {{ item.registry.url }}/{{ item.image }}
5 | {% else %}
6 | FROM {{ item.image }}
7 | {% endif %}
8 |
9 | RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \
10 | elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash && dnf clean all; \
11 | 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; \
12 | elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml && zypper clean -a; \
13 | elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates; \
14 | elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates && xbps-remove -O; fi
15 |
--------------------------------------------------------------------------------
/deployment-e2e/molecule/oracle/molecule.yml:
--------------------------------------------------------------------------------
1 | ---
2 | dependency:
3 | name: galaxy
4 | driver:
5 | name: docker
6 | lint:
7 | name: yamllint
8 | enabled: True
9 | options:
10 | config-data:
11 | ignore: ../../hosts.yml
12 | platforms:
13 | - name: oracle-host
14 | groups:
15 | - example
16 | children:
17 | - oracle
18 | image: ubuntu:16.04
19 | privileged: true
20 | network_mode: host
21 | volumes:
22 | - /var/run/docker.sock:/var/run/docker.sock
23 | provisioner:
24 | name: ansible
25 | lint:
26 | name: ansible-lint
27 | enabled: True
28 | options:
29 | r: ["bug"]
30 | playbooks:
31 | prepare: ../prepare.yml
32 | converge: ../../../deployment/site.yml
33 | inventory:
34 | host_vars:
35 | oracle-host:
36 | ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "6c48435bd464a53ed66ed62127c4dba8af75cf1a99a8ebe2680599948fbfbc6d"
37 | syslog_server_port: "udp://127.0.0.1:514"
38 | verifier:
39 | name: testinfra
40 | lint:
41 | name: flake8
42 | additional_files_or_dirs:
43 | - ../../tests/*
44 | scenario:
45 | name: oracle
46 | test_sequence:
47 | - lint
48 | - cleanup
49 | - destroy
50 | - dependency
51 | - syntax
52 | - create
53 | - prepare
54 | - converge
55 | - verify
56 | - destroy
57 |
--------------------------------------------------------------------------------
/deployment-e2e/molecule/oracle/tests/test_oracle.py:
--------------------------------------------------------------------------------
1 | import os
2 | import pytest
3 | import testinfra.utils.ansible_runner
4 |
5 | testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
6 | os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('oracle')
7 |
8 |
9 | @pytest.mark.parametrize("name", [
10 | ("oracle_rabbit_1"),
11 | ("oracle_redis_1"),
12 | ("oracle_bridge_request_1"),
13 | ("oracle_bridge_collected_1"),
14 | ("oracle_bridge_affirmation_1"),
15 | ("oracle_bridge_senderhome_1"),
16 | ("oracle_bridge_senderforeign_1"),
17 | ("oracle_bridge_shutdown_1"),
18 | ])
19 | def test_docker_containers(host, name):
20 | container = host.docker(name)
21 | assert container.is_running
22 |
23 |
24 | @pytest.mark.parametrize("service", [
25 | ("poabridge"),
26 | ("rsyslog")
27 | ])
28 | def test_services(host, service):
29 | assert host.service(service).is_enabled
30 | assert host.service(service).is_running
31 |
32 |
33 | @pytest.mark.parametrize("filename", [
34 | ("/etc/rsyslog.d/31-oracle-docker.conf"),
35 | ("/etc/rsyslog.d/36-oracle-remote-logging.conf")
36 | ])
37 | def test_logging(host, filename):
38 | assert host.file(filename).exists
39 | assert host.file(filename).mode == 0o0644
40 |
--------------------------------------------------------------------------------
/deployment-e2e/molecule/prepare.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: prepare
3 | hosts: all
4 | tasks:
5 | - name: install apt packages
6 | apt:
7 | name: "{{ packages }}"
8 | vars:
9 | packages:
10 | - apt-transport-https
11 | - rsyslog
12 | - shell: service rsyslog start
13 | - shell: groupadd docker && chgrp docker /var/run/docker.sock
14 |
--------------------------------------------------------------------------------
/deployment-e2e/molecule/repo/Dockerfile.j2:
--------------------------------------------------------------------------------
1 | # Molecule managed
2 |
3 | {% if item.registry is defined %}
4 | FROM {{ item.registry.url }}/{{ item.image }}
5 | {% else %}
6 | FROM {{ item.image }}
7 | {% endif %}
8 |
9 | RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \
10 | elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash && dnf clean all; \
11 | 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; \
12 | elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml && zypper clean -a; \
13 | elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates; \
14 | elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates && xbps-remove -O; fi
15 |
--------------------------------------------------------------------------------
/deployment-e2e/molecule/repo/converge.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Install Repository
3 | hosts: all
4 | become: true
5 | tasks:
6 | - import_role:
7 | name: ../../../deployment/roles/common
8 | tasks_from: repo
9 | # Test that running the task again works
10 | - import_role:
11 | name: ../../../deployment/roles/common
12 | tasks_from: repo
13 |
--------------------------------------------------------------------------------
/deployment-e2e/molecule/repo/molecule.yml:
--------------------------------------------------------------------------------
1 | ---
2 | driver:
3 | name: docker
4 | platforms:
5 | - name: repo-host
6 | image: ubuntu:16.04
7 | privileged: true
8 | network_mode: host
9 | volumes:
10 | - /var/run/docker.sock:/var/run/docker.sock
11 | provisioner:
12 | name: ansible
13 | playbooks:
14 | prepare: ../prepare.yml
15 | converge: ./converge.yml
16 | inventory:
17 | host_vars:
18 | repo-host:
19 | bridge_repo_branch: master
20 | verifier:
21 | name: testinfra
22 | scenario:
23 | name: repo
24 | test_sequence:
25 | - destroy
26 | - create
27 | - prepare
28 | - converge
29 | - verify
30 | - destroy
31 |
--------------------------------------------------------------------------------
/deployment-e2e/molecule/repo/tests/test_existing.py:
--------------------------------------------------------------------------------
1 | import os
2 | import pytest
3 | import testinfra.utils.ansible_runner
4 |
5 | testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
6 | os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all')
7 |
8 |
9 | @pytest.mark.parametrize("path", [
10 | ("/home/poadocker"),
11 | ("/home/poadocker/bridge"),
12 | ("/home/poadocker/bridge/commons"),
13 | ("/home/poadocker/bridge/e2e-commons"),
14 | ("/home/poadocker/bridge/deployment"),
15 | ("/home/poadocker/bridge/contracts"),
16 | ("/home/poadocker/bridge/oracle"),
17 | ("/home/poadocker/bridge/monitor"),
18 | ("/home/poadocker/bridge/parity")
19 | ])
20 | def test_existing_folders(host, path):
21 | assert host.file(path).exists
22 | assert host.file(path).is_directory
23 |
24 |
25 | @pytest.mark.parametrize("path", [
26 | ("/home/poadocker/bridge/package.json"),
27 | ("/home/poadocker/bridge/commons/package.json"),
28 | ("/home/poadocker/bridge/contracts/package.json"),
29 | ("/home/poadocker/bridge/oracle/package.json"),
30 | ("/home/poadocker/bridge/monitor/package.json")
31 | ])
32 | def test_existing_package_json(host, path):
33 | assert host.file(path).exists
34 | assert host.file(path).is_file
35 |
36 |
37 | @pytest.mark.parametrize("path", [
38 | ("/home/poadocker/bridge/Dockerfile.e2e"),
39 | ("/home/poadocker/bridge/contracts/Dockerfile"),
40 | ("/home/poadocker/bridge/parity/Dockerfile"),
41 | ("/home/poadocker/bridge/oracle/Dockerfile"),
42 | ("/home/poadocker/bridge/monitor/Dockerfile")
43 | ])
44 | def test_existing_docker_files(host, path):
45 | assert host.file(path).exists
46 | assert host.file(path).is_file
47 |
--------------------------------------------------------------------------------
/deployment-e2e/molecule/repo/tests/test_non_existing.py:
--------------------------------------------------------------------------------
1 | import os
2 | import pytest
3 | import testinfra.utils.ansible_runner
4 |
5 | testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
6 | os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all')
7 |
8 |
9 | @pytest.mark.parametrize("path", [
10 | ("/home/poadocker/bridge/node_modules"),
11 | ("/home/poadocker/bridge/ui/node_modules"),
12 | ("/home/poadocker/bridge/oracle/node_modules"),
13 | ("/home/poadocker/bridge/monitor/node_modules"),
14 | ("/home/poadocker/bridge/contracts/node_modules"),
15 | ])
16 | def test_non_existing_node_modules(host, path):
17 | assert not host.file(path).exists
18 |
19 | @pytest.mark.parametrize("path", [
20 | ("/home/poadocker/bridge/.git")
21 | ])
22 | def test_non_existing_git(host, path):
23 | assert not host.file(path).exists
24 |
--------------------------------------------------------------------------------
/deployment-e2e/molecule/tests/test_all.py:
--------------------------------------------------------------------------------
1 | import os
2 | import pytest
3 | import testinfra.utils.ansible_runner
4 |
5 | testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
6 | os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all')
7 |
8 |
9 | def test_repo(host):
10 | assert host.file('/home/poadocker/bridge').exists
11 | assert host.file('/home/poadocker/bridge').is_directory
12 |
13 |
14 | def test_docker_group(host):
15 | assert host.group('docker').exists
16 |
17 |
18 | def test_user(host):
19 | assert host.user('poadocker').exists
20 | assert 'docker' in host.user('poadocker').groups
21 |
22 |
23 | @pytest.mark.parametrize("filename", [
24 | ("/etc/rsyslog.d/30-docker.conf"),
25 | ("/etc/rsyslog.d/35-docker-remote-logging.conf")
26 | ])
27 | def test_logging(host, filename):
28 | assert host.file(filename).exists
29 | assert host.file(filename).mode == 0o0644
30 |
31 |
32 | def test_docker_config(host):
33 | assert host.file('/etc/docker/daemon.json').exists
34 |
--------------------------------------------------------------------------------
/deployment-e2e/molecule/ultimate-amb/Dockerfile.j2:
--------------------------------------------------------------------------------
1 | # Molecule managed
2 |
3 | {% if item.registry is defined %}
4 | FROM {{ item.registry.url }}/{{ item.image }}
5 | {% else %}
6 | FROM {{ item.image }}
7 | {% endif %}
8 |
9 | RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \
10 | elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash && dnf clean all; \
11 | 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; \
12 | elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml && zypper clean -a; \
13 | elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates; \
14 | elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates && xbps-remove -O; fi
15 |
--------------------------------------------------------------------------------
/deployment-e2e/molecule/ultimate-amb/molecule.yml:
--------------------------------------------------------------------------------
1 | ---
2 | driver:
3 | name: docker
4 | platforms:
5 | - name: oracle-amb-host
6 | groups:
7 | - ultimate
8 | - amb
9 | children:
10 | - oracle
11 | image: ubuntu:16.04
12 | privileged: true
13 | network_mode: host
14 | volumes:
15 | - /var/run/docker.sock:/var/run/docker.sock
16 | provisioner:
17 | name: ansible
18 | playbooks:
19 | prepare: ../prepare.yml
20 | converge: ../ultimate-commons/converge.yml
21 | inventory:
22 | host_vars:
23 | oracle-amb-host:
24 | ORACLE_VALIDATOR_ADDRESS: "0xaaB52d66283F7A1D5978bcFcB55721ACB467384b"
25 | ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
26 | verifier:
27 | name: testinfra
28 | lint:
29 | name: flake8
30 | scenario:
31 | name: ultimate-amb
32 | test_sequence:
33 | - cleanup
34 | - destroy
35 | - syntax
36 | - create
37 | - prepare
38 | - converge
39 |
--------------------------------------------------------------------------------
/deployment-e2e/molecule/ultimate-commons/converge.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - import_playbook: ./oracle-docker-compose.yml
3 | - import_playbook: ../../../deployment/site.yml
4 |
--------------------------------------------------------------------------------
/deployment-e2e/molecule/ultimate-commons/oracle-docker-compose.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Prepare Oracle for ultimate tests
3 | hosts: oracle
4 | become: true
5 | tasks:
6 | - name: Connect parity to oracle networks
7 | shell: "docker network create {{ item }} && docker network connect {{ item }} parity1 && docker network connect {{ item }} parity2"
8 | with_items:
9 | - oracle_net_db_bridge_request
10 | - oracle_net_db_bridge_collected
11 | - oracle_net_db_bridge_affirmation
12 | - oracle_net_db_bridge_information
13 | - oracle_net_db_bridge_transfer
14 | - oracle_net_db_bridge_senderhome
15 | - oracle_net_db_bridge_senderforeign
16 | - oracle_net_db_bridge_shutdown
17 | - oracle_net_rabbit_bridge_request
18 | - oracle_net_rabbit_bridge_collected
19 | - oracle_net_rabbit_bridge_affirmation
20 | - oracle_net_rabbit_bridge_information
21 | - oracle_net_rabbit_bridge_transfer
22 | - oracle_net_rabbit_bridge_senderhome
23 | - oracle_net_rabbit_bridge_senderforeign
24 | delegate_to: 127.0.0.1
25 | become: false
26 |
--------------------------------------------------------------------------------
/deployment-e2e/molecule/ultimate-erc-to-native/Dockerfile.j2:
--------------------------------------------------------------------------------
1 | # Molecule managed
2 |
3 | {% if item.registry is defined %}
4 | FROM {{ item.registry.url }}/{{ item.image }}
5 | {% else %}
6 | FROM {{ item.image }}
7 | {% endif %}
8 |
9 | RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \
10 | elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash && dnf clean all; \
11 | 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; \
12 | elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml && zypper clean -a; \
13 | elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates; \
14 | elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates && xbps-remove -O; fi
15 |
--------------------------------------------------------------------------------
/deployment-e2e/molecule/ultimate-erc-to-native/molecule.yml:
--------------------------------------------------------------------------------
1 | ---
2 | driver:
3 | name: docker
4 | platforms:
5 | - name: oracle-erc-to-native-host
6 | groups:
7 | - ultimate
8 | - erc-to-native
9 | children:
10 | - oracle
11 | image: ubuntu:16.04
12 | privileged: true
13 | network_mode: host
14 | volumes:
15 | - /var/run/docker.sock:/var/run/docker.sock
16 | provisioner:
17 | name: ansible
18 | playbooks:
19 | prepare: ../prepare.yml
20 | converge: ../ultimate-commons/converge.yml
21 | inventory:
22 | host_vars:
23 | oracle-erc-to-native-host:
24 | ORACLE_VALIDATOR_ADDRESS: "0xaaB52d66283F7A1D5978bcFcB55721ACB467384b"
25 | ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
26 | ORACLE_HOME_START_BLOCK: 1
27 | ORACLE_FOREIGN_START_BLOCK: 1
28 | verifier:
29 | name: testinfra
30 | lint:
31 | name: flake8
32 | scenario:
33 | name: ultimate-erc-to-native
34 | test_sequence:
35 | - cleanup
36 | - destroy
37 | - syntax
38 | - create
39 | - prepare
40 | - converge
41 |
--------------------------------------------------------------------------------
/deployment/.yamllint:
--------------------------------------------------------------------------------
1 | extends: default
2 |
3 | rules:
4 | braces:
5 | max-spaces-inside: 1
6 | level: error
7 | brackets:
8 | max-spaces-inside: 1
9 | level: error
10 | line-length: disable
11 | truthy: disable
12 |
--------------------------------------------------------------------------------
/deployment/README.md:
--------------------------------------------------------------------------------
1 | # POA TokenBridge / Deployment
2 | Ansible playbooks for deploying cross-chain bridges.
3 |
4 | ## Overview
5 | Please refer to the [POA TokenBridge](../README.md) overview first of all.
6 |
7 | These playbooks are designed to automate the deployment process for cross-chain bridges on bridge validator nodes. This process installs the bridge as a service and sets .env configurations on a remote server.
8 |
9 | ## Configuration
10 |
11 | Please refer to [Configuration](./CONFIGURATION.md).
12 |
13 | ## Execution
14 |
15 | Please refer to [Execution](./EXECUTION.md).
16 |
17 | ## Testing
18 |
19 | Please refer to [Deployment-E2E](../deployment-e2e/README.md).
20 |
21 | ## Contributing
22 |
23 | See the [CONTRIBUTING](../CONTRIBUTING.md) document for contribution, testing and pull request protocol.
24 |
25 | ## License
26 |
27 | [](https://www.gnu.org/licenses/lgpl-3.0)
28 |
29 | This project is licensed under the GNU Lesser General Public License v3.0. See the [LICENSE](../LICENSE) file for details.
30 |
31 |
32 |
--------------------------------------------------------------------------------
/deployment/ansible.cfg:
--------------------------------------------------------------------------------
1 | [defaults]
2 | host_key_checking = False
3 | stdout_callback = skippy
4 | ANSIBLE_DEBUG=1
5 |
6 | [ssh_connection]
7 | pipelining=True
8 |
--------------------------------------------------------------------------------
/deployment/group_vars/amb.yml:
--------------------------------------------------------------------------------
1 | ---
2 | ORACLE_BRIDGE_MODE: "ARBITRARY_MESSAGE"
3 | COMMON_HOME_BRIDGE_ADDRESS: "0x8397be90BCF57b0B71219f555Fe121b22e5a994C"
4 | COMMON_FOREIGN_BRIDGE_ADDRESS: "0x1feB40aD9420b186F019A717c37f5546165d411E"
5 | MONITOR_PORT: 3013
6 |
--------------------------------------------------------------------------------
/deployment/group_vars/dai.yml:
--------------------------------------------------------------------------------
1 | ---
2 | ## General settings
3 | ORACLE_BRIDGE_MODE: "ERC_TO_NATIVE"
4 |
5 | ## Home contract
6 | COMMON_HOME_RPC_URL: "https://dai.poa.network"
7 | COMMON_HOME_BRIDGE_ADDRESS: "0x7301CFA0e1756B71869E93d4e4Dca5c7d0eb0AA6"
8 | ORACLE_HOME_RPC_POLLING_INTERVAL: 5000
9 |
10 | ## Foreign contract
11 | COMMON_FOREIGN_RPC_URL: "https://mainnet.infura.io"
12 | COMMON_FOREIGN_BRIDGE_ADDRESS: "0x4aa42145Aa6Ebf72e164C9bBC74fbD3788045016"
13 | ORACLE_FOREIGN_RPC_POLLING_INTERVAL: 5000
14 |
15 | ## Home Gasprice
16 | # COMMON_HOME_GAS_PRICE_SUPPLIER_URL: "https://localhost:8888/"
17 | COMMON_HOME_GAS_PRICE_SPEED_TYPE: "standard"
18 | COMMON_HOME_GAS_PRICE_FALLBACK: 0
19 | COMMON_HOME_GAS_PRICE_FACTOR: 600000
20 |
21 | ## Foreign Gasprice
22 | COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL: "https://gasprice.poa.network/"
23 | COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE: "standard"
24 | COMMON_FOREIGN_GAS_PRICE_FALLBACK: 10000000000
25 | ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
26 | COMMON_FOREIGN_GAS_PRICE_FACTOR: 1
27 |
28 | ## Monitor
29 | MONITOR_BRIDGE_NAME: "xdai"
30 | MONITOR_PORT: 3003
31 | MONITOR_CACHE_EVENTS: "true"
32 | MONITOR_HOME_START_BLOCK: 759
33 | MONITOR_FOREIGN_START_BLOCK: 6478417
34 | MONITOR_VALIDATOR_HOME_TX_LIMIT: 300000
35 | MONITOR_VALIDATOR_FOREIGN_TX_LIMIT: 300000
36 | MONITOR_TX_NUMBER_THRESHOLD: 100
37 |
--------------------------------------------------------------------------------
/deployment/group_vars/erc-to-native.yml:
--------------------------------------------------------------------------------
1 | ---
2 | ORACLE_BRIDGE_MODE: "ERC_TO_NATIVE"
3 | COMMON_HOME_BRIDGE_ADDRESS: "0x5118AC62AE912Dd5B51EEfF7338c4fcb0248Ba8c"
4 | COMMON_FOREIGN_BRIDGE_ADDRESS: "0x32198D570fffC7033641F8A9094FFDCaAEF42624"
5 | MONITOR_PORT: 3012
6 |
--------------------------------------------------------------------------------
/deployment/group_vars/example.yml:
--------------------------------------------------------------------------------
1 | ---
2 | ## General settings
3 | ORACLE_BRIDGE_MODE: "ARBITRARY_MESSAGE"
4 | ORACLE_LOG_LEVEL: debug
5 |
6 | ## Home contract
7 | COMMON_HOME_RPC_URL: "https://sokol.poa.network"
8 | COMMON_HOME_BRIDGE_ADDRESS: "0x59ba90A588ce732AB33FD32Aab1b58c21400A0f6"
9 | ORACLE_HOME_RPC_POLLING_INTERVAL: 5000
10 |
11 | ## Foreign contract
12 | COMMON_FOREIGN_RPC_URL: "https://kovan.infura.io/v3/5d7bd94c50ed43fab1cb8e74f58678b0"
13 | COMMON_FOREIGN_BRIDGE_ADDRESS: "0xdA4a49a00F4fF4A5988b9AceE95f99e3b2c208b6"
14 | ORACLE_FOREIGN_RPC_POLLING_INTERVAL: 5000
15 |
16 | ## Home Gasprice
17 | COMMON_HOME_GAS_PRICE_SUPPLIER_URL: "https://gasprice.poa.network/"
18 | COMMON_HOME_GAS_PRICE_SPEED_TYPE: "standard"
19 | COMMON_HOME_GAS_PRICE_FALLBACK: 1000000000 # in wei
20 | COMMON_HOME_GAS_PRICE_FACTOR: 1
21 | ORACLE_HOME_GAS_PRICE_UPDATE_INTERVAL: 600000
22 |
23 | ## Foreign Gasprice
24 | COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL: "https://gasprice.poa.network/"
25 | COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE: "standard"
26 | COMMON_FOREIGN_GAS_PRICE_FALLBACK: 1000000000 # in wei
27 | COMMON_FOREIGN_GAS_PRICE_FACTOR: 1
28 | ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
29 |
30 | ## Monitor
31 | MONITOR_BRIDGE_NAME: "bridge"
32 | MONITOR_PORT: 3003
33 | MONITOR_CACHE_EVENTS: "false"
34 | MONITOR_HOME_START_BLOCK: 20821049
35 | MONITOR_FOREIGN_START_BLOCK: 24773297
36 | MONITOR_VALIDATOR_HOME_TX_LIMIT: 300000
37 | MONITOR_VALIDATOR_FOREIGN_TX_LIMIT: 300000
38 | MONITOR_TX_NUMBER_THRESHOLD: 100
39 |
--------------------------------------------------------------------------------
/deployment/group_vars/ultimate.yml:
--------------------------------------------------------------------------------
1 | ---
2 | ## General settings
3 | ORACLE_ALLOW_HTTP_FOR_RPC: yes
4 | ORACLE_LOG_LEVEL: debug
5 |
6 | ## Home contract
7 | COMMON_HOME_RPC_URL: "http://parity1:8545"
8 | ORACLE_HOME_RPC_POLLING_INTERVAL: 5000
9 |
10 | ## Foreign contract
11 | COMMON_FOREIGN_RPC_URL: "http://parity2:8545"
12 | ORACLE_FOREIGN_RPC_POLLING_INTERVAL: 1000
13 |
14 | ## Home Gasprice
15 | COMMON_HOME_GAS_PRICE_SUPPLIER_URL: "https://gasprice.poa.network/"
16 | COMMON_HOME_GAS_PRICE_SPEED_TYPE: "standard"
17 | COMMON_HOME_GAS_PRICE_FALLBACK: 1000000000 # in wei
18 | COMMON_HOME_GAS_PRICE_FACTOR: 1
19 | ORACLE_HOME_GAS_PRICE_UPDATE_INTERVAL: 600000
20 |
21 | ## Foreign Gasprice
22 | COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL: "https://gasprice.poa.network/"
23 | COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE: "standard"
24 | COMMON_FOREIGN_GAS_PRICE_FALLBACK: 1000000000 # in wei
25 | COMMON_FOREIGN_GAS_PRICE_FACTOR: 1
26 | ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
27 |
28 | #monitor
29 | MONITOR_BRIDGE_NAME: "bridge"
30 | MONITOR_CACHE_EVENTS: "true"
31 | MONITOR_HOME_START_BLOCK: 0
32 | MONITOR_FOREIGN_START_BLOCK: 0
33 | MONITOR_VALIDATOR_HOME_TX_LIMIT: 300000
34 | MONITOR_VALIDATOR_FOREIGN_TX_LIMIT: 300000
35 | MONITOR_TX_NUMBER_THRESHOLD: 100
36 |
37 | # disable building and pulling of docker images from the Docker Hub
38 | skip_pull: true
39 | skip_build: true
40 |
--------------------------------------------------------------------------------
/deployment/hosts.yml.example:
--------------------------------------------------------------------------------
1 | ---
2 | sokol-kovan:
3 | children:
4 | oracle:
5 | hosts:
6 | 127.0.0.1:
7 | ansible_user: ubuntu
8 | ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
9 | #syslog_server_port: "udp://127.0.0.1:514"
10 | monitor:
11 | hosts:
12 | 127.0.0.1:
13 | ansible_user: ubuntu
14 | #syslog_server_port: "://:"
15 | #monitor_cron_schedule: "*/4 * * * *"
16 |
--------------------------------------------------------------------------------
/deployment/requirements.txt:
--------------------------------------------------------------------------------
1 | # pre-release because it contains "CI Fixes for ansible 2.8"
2 | molecule==2.22rc1
3 | docker
4 | flake8
5 |
--------------------------------------------------------------------------------
/deployment/roles/common/defaults/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | docker_compose_version: 1.23.2
3 | compose_service_user: poadocker
4 | bridge_path: "/home/{{ compose_service_user }}/bridge"
5 |
--------------------------------------------------------------------------------
/deployment/roles/common/files/daemon.json:
--------------------------------------------------------------------------------
1 | {
2 | "live-restore": true,
3 | "no-new-privileges": true
4 | }
5 |
--------------------------------------------------------------------------------
/deployment/roles/common/handlers/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: restart rsyslog
3 | service:
4 | name: rsyslog
5 | state: restarted
6 |
7 | - name: restart auditd
8 | service:
9 | name: auditd
10 | state: restarted
11 |
12 | - name: restart docker
13 | service:
14 | name: docker
15 | state: restarted
16 |
--------------------------------------------------------------------------------
/deployment/roles/common/tasks/logging.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Set the local docker logs configuration file
3 | template:
4 | src: 30-docker.conf.j2
5 | dest: /etc/rsyslog.d/30-docker.conf
6 | owner: root
7 | group: root
8 | mode: 0644
9 |
10 | - name: Set the log configuration file to send docker logs to remote server
11 | template:
12 | src: 35-docker-remote-logging.conf.j2
13 | dest: /etc/rsyslog.d/35-docker-remote-logging.conf
14 | owner: root
15 | group: root
16 | mode: 0644
17 | when: syslog_server_port is defined
18 |
19 | - name: Set the logrotate config file
20 | template:
21 | src: docker-logs.j2
22 | dest: /etc/logrotate.d/docker-logs
23 | owner: root
24 | group: root
25 | mode: 0644
26 |
27 | - name: restart rsyslog
28 | service:
29 | name: rsyslog
30 | state: restarted
31 |
--------------------------------------------------------------------------------
/deployment/roles/common/tasks/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Check if component is already deployed
3 | shell: "test -f {{ bridge_path }}/{{ component }}/.env && echo 'true'"
4 | ignore_errors: True
5 | register: already_deployed
6 | when: check_deployed is defined
7 |
8 | - name: Set if tasks should be skipped
9 | set_fact: skip_task="{{ already_deployed.stdout | default('false') }}"
10 |
11 | - name: Include dependencies tasks
12 | include_tasks: dependencies.yml
13 | when: skip_task != true
14 |
15 | - name: Include repo tasks
16 | include_tasks: repo.yml
17 | when: skip_task != true and skip_repo is undefined
18 |
19 | - name: Include logging tasks
20 | include_tasks: logging.yml
21 | when: skip_task != true
22 |
--------------------------------------------------------------------------------
/deployment/roles/common/tasks/repo.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Create archives of the monorepository
3 | shell: |
4 | (git ls-tree -r HEAD --name-only | sed '/^contracts$/d') | xargs tar zcfv monorepo.tar.gz --files-from -
5 | cd contracts; (git ls-tree -r HEAD --name-only) | xargs tar zcfv ../contracts.tar.gz --files-from -
6 | delegate_to: 127.0.0.1
7 | become: false
8 | args:
9 | chdir: "{{ lookup('env', 'PWD') }}/.."
10 |
11 | - name: Copy the archives
12 | copy:
13 | src: ../../../../{{ item }}
14 | dest: "{{ bridge_path }}/"
15 | mode: '0640'
16 | with_items:
17 | - monorepo.tar.gz
18 | - contracts.tar.gz
19 |
20 | - name: Untar the archives
21 | shell: |
22 | tar zxfv monorepo.tar.gz && rm monorepo.tar.gz
23 | mkdir -p contracts && tar zxfv contracts.tar.gz -C ./contracts && rm contracts.tar.gz
24 | args:
25 | chdir: "{{ bridge_path }}"
26 |
27 | - name: Remove local archives
28 | shell: rm {{ item }}
29 | delegate_to: 127.0.0.1
30 | become: false
31 | args:
32 | chdir: "{{ lookup('env', 'PWD') }}/.."
33 | with_items:
34 | - monorepo.tar.gz
35 | - contracts.tar.gz
36 |
--------------------------------------------------------------------------------
/deployment/roles/common/templates/30-docker.conf.j2:
--------------------------------------------------------------------------------
1 | $FileCreateMode 0644
2 |
3 | if $programname startswith 'docker' then \
4 | /var/log/docker/no_tag/docker.log
5 |
6 | $FileCreateMode 0600
7 |
--------------------------------------------------------------------------------
/deployment/roles/common/templates/35-docker-remote-logging.conf.j2:
--------------------------------------------------------------------------------
1 | template(name="RemoteForwardFormat" type="list") {
2 | constant(value="<")
3 | property(name="pri")
4 | constant(value=">")
5 | property(name="timestamp" dateFormat="rfc3339")
6 | constant(value=" ")
7 | property(name="hostname")
8 | constant(value=" ")
9 | property(name="syslogtag")
10 | property(name="msg" spifno1stsp="on")
11 | property(name="msg")
12 | }
13 |
14 | if $programname startswith 'docker' then {
15 | action(
16 | type="omfwd"
17 | protocol="{{ syslog_server_port.split(":")[0] }}"
18 | target="{{ (syslog_server_port.split(":")[1])[2:] }}"
19 | port="{{ syslog_server_port.split(":")[2] }}"
20 | template="RemoteForwardFormat"
21 | queue.SpoolDirectory="/var/spool/rsyslog"
22 | queue.FileName="remote"
23 | queue.MaxDiskSpace="1g"
24 | queue.SaveOnShutdown="on"
25 | queue.Type="LinkedList"
26 | ResendLastMSGOnReconnect="on"
27 | )
28 | }
29 |
--------------------------------------------------------------------------------
/deployment/roles/common/templates/docker-logs.j2:
--------------------------------------------------------------------------------
1 | /var/log/docker/*/docker.log {
2 | rotate 5
3 | size 100M
4 | compress
5 | missingok
6 | delaycompress
7 | copytruncate
8 | }
9 | /var/log/docker/*.log {
10 | rotate 5
11 | size 100M
12 | compress
13 | missingok
14 | delaycompress
15 | copytruncate
16 | }
17 |
--------------------------------------------------------------------------------
/deployment/roles/monitor/defaults/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | monitor_cron_schedule: "*/4 * * * *"
3 |
--------------------------------------------------------------------------------
/deployment/roles/monitor/meta/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | dependencies:
3 | - { role: common, skip_repo: true, check_deployed: true, component: 'monitor' }
4 |
--------------------------------------------------------------------------------
/deployment/roles/monitor/tasks/cron.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Parse cron schedule
3 | set_fact:
4 | minute: "{{ monitor_cron_schedule.split(' ')[0] }}"
5 | hour: "{{ monitor_cron_schedule.split(' ')[1] }}"
6 | day: "{{ monitor_cron_schedule.split(' ')[2] }}"
7 | month: "{{ monitor_cron_schedule.split(' ')[3] }}"
8 | weekday: "{{ monitor_cron_schedule.split(' ')[4] }}"
9 | job: "/bin/bash -c 'cd {{ bridge_path }}/monitor/scripts; ./getBridgeStats.sh >cronWorker.out 2>cronWorker.err'"
10 | - name: Add cron entry
11 | cron:
12 | name: "RUN_MONITOR_CHECKS"
13 | minute: "{{ minute }}"
14 | hour: "{{ hour }}"
15 | day: "{{ day }}"
16 | month: "{{ month }}"
17 | weekday: "{{ weekday }}"
18 | job: "{{ job }}"
19 |
--------------------------------------------------------------------------------
/deployment/roles/monitor/tasks/jumpbox.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Pull the containers images
3 | shell: docker-compose pull
4 | args:
5 | chdir: "{{ bridge_path }}/monitor"
6 | when: skip_pull is undefined
7 |
--------------------------------------------------------------------------------
/deployment/roles/monitor/tasks/logging.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Slurp docker compose file
3 | slurp:
4 | src: "{{ bridge_path }}/monitor/docker-compose.yml"
5 | register: docker_compose_slurp
6 |
7 | - name: Parse docker compose file
8 | set_fact:
9 | docker_compose_parsed: "{{ docker_compose_slurp['content'] | b64decode | from_yaml }}"
10 |
11 | - name: Set logger to remote server
12 | set_fact:
13 | docker_compose_parsed: "{{ docker_compose_parsed |combine({'services': {item: {'logging': {'driver': 'syslog','options': {'tag': '{{.Name}}/{{.ID}}'}}}}}, recursive=True) }}"
14 | with_items: "{{ docker_compose_parsed.services }}"
15 |
16 | - name: Write new docker-compose file
17 | copy:
18 | content: "{{ docker_compose_parsed | to_yaml }}"
19 | dest: "{{ bridge_path }}/monitor/docker-compose.yml"
20 |
21 | - name: Set the local container logs configuration file
22 | template:
23 | src: 33-monitor-docker.conf.j2
24 | dest: /etc/rsyslog.d/33-monitor-docker.conf
25 | owner: root
26 | group: root
27 | mode: 0644
28 |
29 | - name: Set the log configuration file to send container logs to remote server
30 | template:
31 | src: 38-monitor-remote-logging.conf.j2
32 | dest: /etc/rsyslog.d/38-monitor-remote-logging.conf
33 | owner: root
34 | group: root
35 | mode: 0644
36 | when: syslog_server_port is defined
37 |
38 | - name: restart rsyslog
39 | service:
40 | name: rsyslog
41 | state: restarted
42 |
--------------------------------------------------------------------------------
/deployment/roles/monitor/tasks/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - include_tasks: pre_config.yml
3 |
4 | - name: Include logging tasks
5 | include_tasks: logging.yml
6 | when: skip_task != true
7 |
8 | - name: Include jumpbox tasks
9 | include_tasks: jumpbox.yml
10 | when: skip_task != true
11 |
12 | - name: Include servinstall tasks
13 | include_tasks: servinstall.yml
14 | when: skip_task != true
15 |
16 | - name: Include cron tasks
17 | include_tasks: cron.yml
18 | when: skip_task != true
19 |
--------------------------------------------------------------------------------
/deployment/roles/monitor/tasks/pre_config.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Create configs directory
3 | file:
4 | path: "{{ bridge_path }}/monitor/configs"
5 | state: directory
6 | mode: '0755'
7 | when: skip_task != true
8 |
9 | - name: Create responses directory
10 | file:
11 | path: "{{ bridge_path }}/monitor/responses"
12 | state: directory
13 | mode: '0755'
14 | when: skip_task != true
15 |
16 | - name: Create scripts directory
17 | file:
18 | path: "{{ bridge_path }}/monitor/scripts"
19 | state: directory
20 | mode: '0755'
21 | when: skip_task != true
22 |
23 | - name: Install .env config
24 | template:
25 | src: .env.j2
26 | dest: "{{ bridge_path }}/monitor/.env"
27 | owner: "{{ compose_service_user }}"
28 | mode: '0640'
29 | when: skip_task != true
30 |
31 | - name: Copy docker-compose file
32 | copy:
33 | src: ../../../../monitor/docker-compose.yml
34 | dest: "{{ bridge_path }}/monitor/docker-compose.yml"
35 | mode: '0755'
36 | when: skip_task != true
37 |
38 | - name: Copy script file
39 | copy:
40 | src: ../../../../monitor/scripts/getBridgeStats.sh
41 | dest: "{{ bridge_path }}/monitor/scripts/getBridgeStats.sh"
42 | owner: "{{ compose_service_user }}"
43 | mode: '0755'
44 | when: skip_task != true
45 |
46 | - name: Install bridge config env
47 | template:
48 | src: config.env.j2
49 | dest: "{{ bridge_path }}/monitor/configs/{{ MONITOR_BRIDGE_NAME }}.env"
50 | owner: "{{ compose_service_user }}"
51 | mode: '0640'
52 |
--------------------------------------------------------------------------------
/deployment/roles/monitor/tasks/servinstall.yml:
--------------------------------------------------------------------------------
1 | # This role creates a tokenbridge-monitor service which is designed to manage docker-compose monitor deployment.
2 | # /etc/init.d/tokenbridge-monitor start, status, stop, restart - does what the services usually do in such cases.
3 | ---
4 | - name: "Set the service"
5 | template:
6 | src: tokenbridge-monitor.j2
7 | dest: "/etc/init.d/tokenbridge-monitor"
8 | owner: root
9 | mode: 755
10 |
11 | - name: "Enable the service"
12 | service:
13 | name: "tokenbridge-monitor"
14 | state: started
15 | enabled: yes
16 | use: service
17 |
18 | - name: Start the service
19 | shell: service tokenbridge-monitor start
20 |
--------------------------------------------------------------------------------
/deployment/roles/monitor/templates/.env.j2:
--------------------------------------------------------------------------------
1 | MONITOR_PORT={{ MONITOR_PORT }}
2 |
--------------------------------------------------------------------------------
/deployment/roles/monitor/templates/33-monitor-docker.conf.j2:
--------------------------------------------------------------------------------
1 | $FileCreateMode 0644
2 | template(name="DockerLogFileName_Monitor" type="list") {
3 | constant(value="/var/log/docker/")
4 | property(name="syslogtag" securepath="replace" regex.type="ERE" regex.submatch="1" regex.expression="monitor_(.*)\\/[a-zA-Z0-9]+\\[")
5 | constant(value="/docker.log")
6 | }
7 |
8 | if $programname startswith 'monitor_' then \
9 | ?DockerLogFileName_Monitor
10 |
11 | $FileCreateMode 0600
12 |
--------------------------------------------------------------------------------
/deployment/roles/monitor/templates/38-monitor-remote-logging.conf.j2:
--------------------------------------------------------------------------------
1 | if $programname startswith 'monitor_' then {
2 | action(
3 | type="omfwd"
4 | protocol="{{ syslog_server_port.split(":")[0] }}"
5 | target="{{ (syslog_server_port.split(":")[1])[2:] }}"
6 | port="{{ syslog_server_port.split(":")[2] }}"
7 | template="RemoteForwardFormat"
8 | queue.SpoolDirectory="/var/spool/rsyslog"
9 | queue.FileName="remote"
10 | queue.MaxDiskSpace="1g"
11 | queue.SaveOnShutdown="on"
12 | queue.Type="LinkedList"
13 | ResendLastMSGOnReconnect="on"
14 | )
15 | }
16 |
--------------------------------------------------------------------------------
/deployment/roles/monitor/templates/tokenbridge-monitor.j2:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ### BEGIN INIT INFO
4 | # Provides: tokenbridge-monitor
5 | # Required-Start: $remote_fs $syslog
6 | # Required-Stop: $remote_fs $syslog
7 | # Default-Start: 2 3 4 5
8 | # Default-Stop: 0 1 6
9 | # Short-Description: Start daemon at boot time
10 | # Description: Enable service provided by daemon.
11 | ### END INIT INFO
12 |
13 | WORKDIR="{{ '/home/' + compose_service_user | default('poadocker') + '/' + bridge_path + '/monitor' if bridge_path[:1] != "/" else bridge_path + '/monitor' }}"
14 |
15 | start(){
16 | echo "Starting TokenBridge Monitor.."
17 | cd $WORKDIR
18 | sudo -u "{{ compose_service_user }}" /usr/local/bin/docker-compose down -v
19 | sudo -u "{{ compose_service_user }}" /usr/local/bin/docker-compose rm -fv
20 | sudo -u "{{ compose_service_user }}" /usr/local/bin/docker-compose up --detach
21 | sudo -u "{{ compose_service_user }}" /bin/bash -c 'cd scripts; ./getBridgeStats.sh >cronWorker.out 2>cronWorker.err'
22 | }
23 |
24 | stop(){
25 | echo "Stopping TokenBridge Monitor.."
26 | cd $WORKDIR
27 | sudo -u "{{ compose_service_user }}" /usr/local/bin/docker-compose down -v
28 | sleep 2
29 | }
30 |
31 | status(){
32 | echo "TokenBridge Monitor status:"
33 | cd $WORKDIR
34 | sudo -u "{{ compose_service_user }}" /usr/local/bin/docker-compose ps
35 | }
36 |
37 |
38 | case "$1" in
39 |
40 | start)
41 | start
42 | ;;
43 |
44 | stop)
45 | stop
46 | ;;
47 |
48 | status)
49 | status
50 | ;;
51 |
52 | restart)
53 | echo "Restarting TokenBridge Monitor.."
54 | stop
55 | start
56 | ;;
57 |
58 | *)
59 | echo $"Usage: $0 {start|stop|restart|status}"
60 | exit 1
61 | ;;
62 |
63 | esac
64 |
65 | exit 0
66 |
--------------------------------------------------------------------------------
/deployment/roles/oracle/defaults/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | bridge_path: "/home/{{ compose_service_user }}/bridge"
3 | ORACLE_ALLOW_HTTP_FOR_RPC: no
4 | ORACLE_QUEUE_URL: amqp://rabbit
5 | ORACLE_REDIS_URL: redis://redis
6 | keyfile_path: "/root/.key"
7 |
--------------------------------------------------------------------------------
/deployment/roles/oracle/files/modify_to_use_syslog.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 |
3 | from yaml import safe_load, safe_dump
4 | from argparse import ArgumentParser
5 | from os.path import basename
6 | import sys
7 |
8 | parser = ArgumentParser()
9 | parser.add_argument('composefile', type=str, nargs=1, metavar='compose-file', help='docker-compose.yml')
10 | parser.add_argument('-d', action='store_true', help='output result instead of writing the file', dest='debug')
11 |
12 | if basename(sys.argv[0]) == "ipykernel_launcher.py":
13 | args = parser.parse_args(['docker-compose.yml'])
14 | else:
15 | args = parser.parse_args()
16 |
17 | file_to_operate = args.composefile[0]
18 |
19 | with open(file_to_operate) as composefile:
20 | composecnt=composefile.read()
21 | yml = safe_load(composecnt)
22 | for i in yml['services']:
23 | yml['services'][i]['logging'] = {'driver': 'syslog','options': {'tag': '{{.Name}}/{{.ID}}'}}
24 | if args.debug or (basename(sys.argv[0]) == "ipykernel_launcher.py"):
25 | print(safe_dump(yml))
26 | else:
27 | with open(file_to_operate, 'w') as composefile:
28 | safe_dump(yml, composefile, explicit_start=True)
--------------------------------------------------------------------------------
/deployment/roles/oracle/meta/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | dependencies:
3 | - { role: common, skip_repo: true }
4 |
--------------------------------------------------------------------------------
/deployment/roles/oracle/tasks/jumpbox.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Pull the containers images
3 | shell: docker-compose pull
4 | args:
5 | chdir: "{{ bridge_path }}/oracle"
6 | when: skip_pull is undefined
7 |
--------------------------------------------------------------------------------
/deployment/roles/oracle/tasks/logging.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - include_tasks: logging_by_syslog.yml
3 | with_items:
4 | - docker-compose
5 | - docker-compose-transfer
6 | - docker-compose-amb
7 | loop_control:
8 | loop_var: file
9 |
10 | - name: Set the oracle's containers local logs configuration file
11 | template:
12 | src: 31-oracle-docker.conf.j2
13 | dest: /etc/rsyslog.d/31-oracle-docker.conf
14 | owner: root
15 | group: root
16 | mode: 0644
17 |
18 | - name: Set the redis container local logs configuration file
19 | template:
20 | src: 32-redis-docker.conf.j2
21 | dest: /etc/rsyslog.d/32-redis-docker.conf
22 | owner: root
23 | group: root
24 | mode: 0644
25 |
26 | - name: Set the rabbit MQ container local logs configuration file
27 | template:
28 | src: 33-rabbit-docker.conf.j2
29 | dest: /etc/rsyslog.d/33-rabbit-docker.conf
30 | owner: root
31 | group: root
32 | mode: 0644
33 |
34 | - name: Set the log configuration file to send container logs to remote server
35 | template:
36 | src: 36-oracle-remote-logging.conf.j2
37 | dest: /etc/rsyslog.d/36-oracle-remote-logging.conf
38 | owner: root
39 | group: root
40 | mode: 0644
41 | when: syslog_server_port is defined
42 |
43 | - name: Discarding unwanted messages in rsyslog
44 | blockinfile:
45 | path: /etc/rsyslog.conf
46 | insertbefore: "# Where to place spool and state files"
47 | marker: "#{mark} add string to discarding unwanted messages"
48 | content: ':msg, contains, "ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY" ~'
49 | notify: restart rsyslog
50 |
--------------------------------------------------------------------------------
/deployment/roles/oracle/tasks/logging_by_syslog.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Change logging facility to forward logs to syslog
3 | script: modify_to_use_syslog.py "{{ bridge_path }}/oracle/{{ file }}.yml"
4 | args:
5 | executable: python3
--------------------------------------------------------------------------------
/deployment/roles/oracle/tasks/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - include_tasks: pre_config.yml
3 | - include_tasks: logging.yml
4 | - include_tasks: jumpbox.yml
5 | - include_tasks: post_config.yml
6 | - include_tasks: servinstall.yml
7 |
--------------------------------------------------------------------------------
/deployment/roles/oracle/tasks/pre_config.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Create oracle directory
3 | file:
4 | path: "{{ bridge_path }}/oracle"
5 | state: directory
6 | mode: '0755'
7 |
8 | - name: Install .env config
9 | template:
10 | src: .env.j2
11 | dest: "{{ bridge_path }}/oracle/.env"
12 | owner: "{{ compose_service_user }}"
13 | mode: '0640'
14 |
15 | - name: Copy docker-compose files
16 | copy:
17 | src: ../../../../oracle/{{ item }}
18 | dest: "{{ bridge_path }}/oracle/"
19 | mode: '0755'
20 | with_items:
21 | - docker-compose.yml
22 | - docker-compose-transfer.yml
23 | - docker-compose-amb.yml
24 |
--------------------------------------------------------------------------------
/deployment/roles/oracle/tasks/servinstall.yml:
--------------------------------------------------------------------------------
1 | # This role creates a poabridge service which is designed to manage docker-compose bridge deployment.
2 | # /etc/init.d/poabridge start, status, stop, restart - does what the services usually do in such cases.
3 | ---
4 | - name: "Set poabridge service"
5 | template:
6 | src: poabridge.j2
7 | dest: "/etc/init.d/poabridge"
8 | owner: root
9 | mode: 755
10 |
11 | - name: "Enable the service"
12 | service:
13 | name: "poabridge"
14 | state: started
15 | enabled: yes
16 | use: service
17 |
18 | - name: Start the service
19 | shell: service poabridge start
20 |
--------------------------------------------------------------------------------
/deployment/roles/oracle/templates/31-oracle-docker.conf.j2:
--------------------------------------------------------------------------------
1 | $FileCreateMode 0644
2 | template(name="DockerLogFileName_Oracle" type="list") {
3 | constant(value="/var/log/docker/")
4 | property(name="syslogtag" securepath="replace" regex.type="ERE" regex.submatch="1" regex.expression="bridge_(.*)\\/[a-zA-Z0-9]+\\[")
5 | constant(value="/docker.log")
6 | }
7 |
8 | if $programname startswith 'oracle_bridge_' then \
9 | ?DockerLogFileName_Oracle
10 |
11 | $FileCreateMode 0600
12 |
--------------------------------------------------------------------------------
/deployment/roles/oracle/templates/32-redis-docker.conf.j2:
--------------------------------------------------------------------------------
1 | $FileCreateMode 0644
2 | template(name="DockerLogFileName_Redis" type="list") {
3 | constant(value="/var/log/docker/")
4 | property(name="syslogtag" securepath="replace" regex.type="ERE" regex.submatch="1" regex.expression="oracle_(.*redis.*)\\/[a-zA-Z0-9]+\\[")
5 | constant(value="/docker.log")
6 | }
7 |
8 | if $programname contains 'oracle' and $programname contains 'redis' then \
9 | ?DockerLogFileName_Redis
10 |
11 | $FileCreateMode 0600
12 |
--------------------------------------------------------------------------------
/deployment/roles/oracle/templates/33-rabbit-docker.conf.j2:
--------------------------------------------------------------------------------
1 | $FileCreateMode 0644
2 | template(name="DockerLogFileName_Rabbit" type="list") {
3 | constant(value="/var/log/docker/")
4 | property(name="syslogtag" securepath="replace" regex.type="ERE" regex.submatch="1" regex.expression="oracle_(.*rabbit.*)\\/[a-zA-Z0-9]+\\[")
5 | constant(value="/docker.log")
6 | }
7 |
8 | if $programname contains 'oracle' and $programname contains 'rabbit' then \
9 | ?DockerLogFileName_Rabbit
10 |
11 | $FileCreateMode 0600
12 |
--------------------------------------------------------------------------------
/deployment/roles/oracle/templates/36-oracle-remote-logging.conf.j2:
--------------------------------------------------------------------------------
1 | if $programname startswith 'oracle_bridge_' then {
2 | action(
3 | type="omfwd"
4 | protocol="{{ syslog_server_port.split(":")[0] }}"
5 | target="{{ (syslog_server_port.split(":")[1])[2:] }}"
6 | port="{{ syslog_server_port.split(":")[2] }}"
7 | template="RemoteForwardFormat"
8 | queue.SpoolDirectory="/var/spool/rsyslog"
9 | queue.FileName="remote"
10 | queue.MaxDiskSpace="1g"
11 | queue.SaveOnShutdown="on"
12 | queue.Type="LinkedList"
13 | ResendLastMSGOnReconnect="on"
14 | )
15 | }
16 |
--------------------------------------------------------------------------------
/deployment/roles/oracle/templates/key.j2:
--------------------------------------------------------------------------------
1 | ## Validator-specific options
2 | ORACLE_VALIDATOR_ADDRESS={{ ORACLE_VALIDATOR_ADDRESS }}
3 | ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY={{ ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY }}
4 |
--------------------------------------------------------------------------------
/deployment/site.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Install Oracle
3 | hosts: oracle
4 | become: true
5 | roles:
6 | - { role: oracle }
7 | - name: Install Monitor
8 | hosts: monitor
9 | become: true
10 | roles:
11 | - { role: monitor }
12 |
--------------------------------------------------------------------------------
/e2e-commons/README.md:
--------------------------------------------------------------------------------
1 | # POA TokenBridge / E2E-Commons
2 |
3 | Common scripts and configuration for the end-to-end tests.
4 |
5 | ## Usage
6 |
7 | Spin up parity networks, redis, rabbit, e2e container needed for end-to-end tests:
8 |
9 | ```
10 | ./up.sh [components]
11 | ```
12 |
13 | Shut down and cleans up containers, networks, services, running scripts:
14 |
15 | ```
16 | ./down.sh
17 | ```
18 |
19 | ### Components
20 |
21 | | Component | Description |
22 | | --- | --- |
23 | | deploy | Deploys the Smart Contracts |
24 | | oracle | Launches Oracle containers |
25 | | oracle-validator-2 | Launches Oracle containers for second validator |
26 | | oracle-validator-3 | Launches Oracle containers for third validator |
27 | | blocks | Auto mines blocks |
28 | | monitor | Launches Monitor containers |
29 | | erc-to-native | Creates infrastructure for ultimate e2e testing, for erc-to-native type of bridge |
30 | | amb | Creates infrastructure for ultimate e2e testing, for arbitrary message type of bridge |
31 |
32 | #### Ultimate e2e testing
33 |
34 | For more information on the Ultimate e2e testing, please refer to [Ultimate](./ULTIMATE.md).
35 |
--------------------------------------------------------------------------------
/e2e-commons/ULTIMATE.md:
--------------------------------------------------------------------------------
1 | # POA TokenBridge / Ultimate E2E
2 |
3 | Documentation regarding the Ultimate end-to-end tests.
4 |
5 | ## Overview
6 |
7 | The ultimate e2e test scenario covers erc-to-native and amb types of bridges.
8 | It runs the e2e tests on components deployed using the deployment playbooks.
9 |
10 |
11 | ## Usage
12 |
13 | ### 1. Prepare the infrastructure
14 |
15 | Run the Parity nodes, deploy the bridge contracts, deploy Oracle using the deployment playbook.
16 |
17 | ```bash
18 | ./e2e-commons/up.sh deploy blocks
19 | ./deployment-e2e/molecule.sh ultimate-erc-to-native
20 | ```
21 |
22 | ### 2. Run the E2E tests
23 |
24 | ```bash
25 | cd e2e-commons
26 | docker-compose run -e ULTIMATE=true e2e yarn workspace oracle-e2e run erc-to-native
27 | ```
28 |
29 | ## Diagram
30 |
31 | 
32 |
--------------------------------------------------------------------------------
/e2e-commons/access-lists/allowance_list.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omni/tokenbridge/961b12b9f3545830a04044e109762277efcea6ef/e2e-commons/access-lists/allowance_list.txt
--------------------------------------------------------------------------------
/e2e-commons/access-lists/block_list.txt:
--------------------------------------------------------------------------------
1 | 0xc9e38bfdB9c635F0796ad83CC8705dc379F41c04
2 | 0xF9698Eb93702dfdd0e2d802088d4c21822a8A977
3 |
--------------------------------------------------------------------------------
/e2e-commons/build.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | cd $(dirname $0)
3 | set -e # exit when any command fails
4 |
5 | docker-compose build e2e
6 | while [ "$1" != "" ]; do
7 | if [ "$1" == "oracle" ]; then
8 | docker-compose build oracle-amb
9 | elif [ "$1" == "alm-e2e" ]; then
10 | docker-compose build oracle-amb
11 | elif [ "$1" == "monitor" ]; then
12 | docker-compose build monitor-amb
13 | elif [ "$1" == "alm" ]; then
14 | docker-compose build alm
15 | fi
16 | shift
17 | done
18 |
--------------------------------------------------------------------------------
/e2e-commons/components-envs/alm.env:
--------------------------------------------------------------------------------
1 | COMMON_HOME_BRIDGE_ADDRESS=0x8397be90BCF57b0B71219f555Fe121b22e5a994C
2 | COMMON_FOREIGN_BRIDGE_ADDRESS=0x1feB40aD9420b186F019A717c37f5546165d411E
3 |
4 | COMMON_HOME_RPC_URL=http://localhost:8541
5 | COMMON_FOREIGN_RPC_URL=http://localhost:8542
6 |
7 | ALM_HOME_NETWORK_NAME=Parity1
8 | ALM_FOREIGN_NETWORK_NAME=Parity2
9 |
10 | PORT=3000
11 |
--------------------------------------------------------------------------------
/e2e-commons/components-envs/monitor-amb.env:
--------------------------------------------------------------------------------
1 | COMMON_HOME_RPC_URL=http://parity1:8545
2 | COMMON_FOREIGN_RPC_URL=http://parity2:8545
3 | COMMON_HOME_BRIDGE_ADDRESS=0x8397be90BCF57b0B71219f555Fe121b22e5a994C
4 | COMMON_FOREIGN_BRIDGE_ADDRESS=0x1feB40aD9420b186F019A717c37f5546165d411E
5 | MONITOR_HOME_START_BLOCK=0
6 | MONITOR_FOREIGN_START_BLOCK=0
7 | MONITOR_VALIDATOR_HOME_TX_LIMIT=300000
8 | COMMON_HOME_GAS_PRICE_SUPPLIER_URL=https://gasprice.poa.network/
9 | COMMON_HOME_GAS_PRICE_SPEED_TYPE=standard
10 | COMMON_HOME_GAS_PRICE_FALLBACK=1000000000
11 | COMMON_HOME_GAS_PRICE_FACTOR=1
12 | MONITOR_VALIDATOR_FOREIGN_TX_LIMIT=300000
13 | COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL=https://gasprice.poa.network/
14 | COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE=standard
15 | COMMON_FOREIGN_GAS_PRICE_FALLBACK=1000000000
16 | COMMON_FOREIGN_GAS_PRICE_FACTOR=1
17 | MONITOR_TX_NUMBER_THRESHOLD=100
18 | MONITOR_PORT=3013
19 | MONITOR_BRIDGE_NAME=bridge
20 | MONITOR_CACHE_EVENTS=false
21 |
--------------------------------------------------------------------------------
/e2e-commons/components-envs/monitor-erc20-native.env:
--------------------------------------------------------------------------------
1 | COMMON_HOME_RPC_URL=http://parity1:8545
2 | COMMON_FOREIGN_RPC_URL=http://parity2:8545
3 | COMMON_HOME_BRIDGE_ADDRESS=0x5118AC62AE912Dd5B51EEfF7338c4fcb0248Ba8c
4 | COMMON_FOREIGN_BRIDGE_ADDRESS=0x32198D570fffC7033641F8A9094FFDCaAEF42624
5 | MONITOR_HOME_START_BLOCK=0
6 | MONITOR_FOREIGN_START_BLOCK=0
7 | MONITOR_VALIDATOR_HOME_TX_LIMIT=300000
8 | COMMON_HOME_GAS_PRICE_SUPPLIER_URL=https://gasprice.poa.network/
9 | COMMON_HOME_GAS_PRICE_SPEED_TYPE=standard
10 | COMMON_HOME_GAS_PRICE_FALLBACK=1000000000
11 | COMMON_HOME_GAS_PRICE_FACTOR=1
12 | MONITOR_VALIDATOR_FOREIGN_TX_LIMIT=300000
13 | COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL=https://gasprice.poa.network/
14 | COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE=standard
15 | COMMON_FOREIGN_GAS_PRICE_FALLBACK=1000000000
16 | COMMON_FOREIGN_GAS_PRICE_FACTOR=1
17 | MONITOR_TX_NUMBER_THRESHOLD=100
18 | MONITOR_PORT=3012
19 | MONITOR_BRIDGE_NAME=bridge
20 | MONITOR_CACHE_EVENTS=false
21 |
--------------------------------------------------------------------------------
/e2e-commons/components-envs/oracle-amb.env:
--------------------------------------------------------------------------------
1 |
2 | ORACLE_BRIDGE_MODE=ARBITRARY_MESSAGE
3 | ORACLE_QUEUE_URL=amqp://rabbit
4 | ORACLE_REDIS_URL=redis://redis
5 | COMMON_HOME_RPC_URL=http://parity1:8545
6 | COMMON_FOREIGN_RPC_URL=http://parity2:8545
7 | COMMON_HOME_BRIDGE_ADDRESS=0x8397be90BCF57b0B71219f555Fe121b22e5a994C
8 | COMMON_FOREIGN_BRIDGE_ADDRESS=0x1feB40aD9420b186F019A717c37f5546165d411E
9 | COMMON_HOME_GAS_PRICE_SUPPLIER_URL=
10 | COMMON_HOME_GAS_PRICE_SPEED_TYPE=standard
11 | COMMON_HOME_GAS_PRICE_FALLBACK=1000000000
12 | ORACLE_HOME_GAS_PRICE_UPDATE_INTERVAL=600000
13 | COMMON_HOME_GAS_PRICE_FACTOR=1
14 | COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL=
15 | COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE=standard
16 | COMMON_FOREIGN_GAS_PRICE_FALLBACK=10000000000
17 | ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL=600000
18 | COMMON_FOREIGN_GAS_PRICE_FACTOR=1
19 | ORACLE_HOME_RPC_POLLING_INTERVAL=500
20 | ORACLE_FOREIGN_RPC_POLLING_INTERVAL=500
21 | ORACLE_ALLOW_HTTP_FOR_RPC=yes
22 | ORACLE_HOME_START_BLOCK=1
23 | ORACLE_FOREIGN_START_BLOCK=1
24 | ORACLE_HOME_TO_FOREIGN_BLOCK_LIST=/mono/oracle/access-lists/block_list.txt
25 | ORACLE_FOREIGN_ARCHIVE_RPC_URL=http://parity2:8545
26 | ORACLE_HOME_EVENTS_REPROCESSING=false
27 | ORACLE_HOME_EVENTS_REPROCESSING_BATCH_SIZE=10
28 | ORACLE_HOME_EVENTS_REPROCESSING_BLOCK_DELAY=10
29 | ORACLE_FOREIGN_EVENTS_REPROCESSING=true
30 | ORACLE_FOREIGN_EVENTS_REPROCESSING_BATCH_SIZE=10
31 | ORACLE_FOREIGN_EVENTS_REPROCESSING_BLOCK_DELAY=10
32 |
--------------------------------------------------------------------------------
/e2e-commons/components-envs/oracle-erc20-native.env:
--------------------------------------------------------------------------------
1 |
2 | ORACLE_BRIDGE_MODE=ERC_TO_NATIVE
3 | ORACLE_QUEUE_URL=amqp://rabbit
4 | ORACLE_REDIS_URL=redis://redis
5 | COMMON_HOME_RPC_URL=http://parity1:8545
6 | COMMON_FOREIGN_RPC_URL=http://parity2:8545
7 | COMMON_HOME_BRIDGE_ADDRESS=0x5118AC62AE912Dd5B51EEfF7338c4fcb0248Ba8c
8 | COMMON_FOREIGN_BRIDGE_ADDRESS=0x32198D570fffC7033641F8A9094FFDCaAEF42624
9 | COMMON_HOME_GAS_PRICE_SUPPLIER_URL=https://gasprice.poa.network/
10 | COMMON_HOME_GAS_PRICE_SPEED_TYPE=standard
11 | COMMON_HOME_GAS_PRICE_FALLBACK=1
12 | ORACLE_HOME_GAS_PRICE_UPDATE_INTERVAL=600000
13 | COMMON_HOME_GAS_PRICE_FACTOR=1
14 | COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL=https://gasprice.poa.network/
15 | COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE=standard
16 | COMMON_FOREIGN_GAS_PRICE_FALLBACK=1
17 | ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL=600000
18 | COMMON_FOREIGN_GAS_PRICE_FACTOR=0.1
19 | ORACLE_HOME_RPC_POLLING_INTERVAL=500
20 | ORACLE_FOREIGN_RPC_POLLING_INTERVAL=500
21 | ORACLE_ALLOW_HTTP_FOR_RPC=yes
22 | ORACLE_HOME_START_BLOCK=1
23 | ORACLE_FOREIGN_START_BLOCK=1
24 | ORACLE_HOME_TO_FOREIGN_BLOCK_LIST=/mono/oracle/access-lists/block_list.txt
25 | ORACLE_HOME_EVENTS_REPROCESSING=true
26 | ORACLE_HOME_EVENTS_REPROCESSING_BATCH_SIZE=10
27 | ORACLE_HOME_EVENTS_REPROCESSING_BLOCK_DELAY=10
28 | ORACLE_FOREIGN_EVENTS_REPROCESSING=true
29 | ORACLE_FOREIGN_EVENTS_REPROCESSING_BATCH_SIZE=10
30 | ORACLE_FOREIGN_EVENTS_REPROCESSING_BLOCK_DELAY=10
31 |
--------------------------------------------------------------------------------
/e2e-commons/contracts-envs/amb.env:
--------------------------------------------------------------------------------
1 | BRIDGE_MODE=ARBITRARY_MESSAGE
2 | DEPLOYMENT_ACCOUNT_PRIVATE_KEY=8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9
3 | HOME_DEPLOYMENT_GAS_PRICE=10000000000
4 | FOREIGN_DEPLOYMENT_GAS_PRICE=10000000000
5 | GET_RECEIPT_INTERVAL_IN_MILLISECONDS=50
6 | DEPLOYMENT_GAS_LIMIT_EXTRA=0.2
7 |
8 | HOME_RPC_URL=http://parity1:8545
9 | HOME_BRIDGE_OWNER=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
10 | HOME_VALIDATORS_OWNER=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
11 | HOME_UPGRADEABLE_ADMIN=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
12 | HOME_MAX_AMOUNT_PER_TX=2000000
13 | HOME_REQUIRED_BLOCK_CONFIRMATIONS=1
14 | HOME_GAS_PRICE=1000000000
15 |
16 | FOREIGN_RPC_URL=http://parity2:8545
17 | FOREIGN_BRIDGE_OWNER=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
18 | FOREIGN_VALIDATORS_OWNER=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
19 | FOREIGN_UPGRADEABLE_ADMIN=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
20 | FOREIGN_MAX_AMOUNT_PER_TX=2000000
21 | FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS=1
22 | FOREIGN_GAS_PRICE=10000000000
23 |
24 | REQUIRED_NUMBER_OF_VALIDATORS=1
25 | VALIDATORS="0xaaB52d66283F7A1D5978bcFcB55721ACB467384b 0xdCC784657C78054aa61FbcFFd2605F32374816A4 0xDcef88209a20D52165230104B245803C3269454d"
26 |
--------------------------------------------------------------------------------
/e2e-commons/contracts-envs/erc-to-native.env:
--------------------------------------------------------------------------------
1 | BRIDGE_MODE=ERC_TO_NATIVE
2 | DEPLOYMENT_ACCOUNT_PRIVATE_KEY=8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9
3 | HOME_DEPLOYMENT_GAS_PRICE=10000000000
4 | FOREIGN_DEPLOYMENT_GAS_PRICE=10000000000
5 | GET_RECEIPT_INTERVAL_IN_MILLISECONDS=50
6 | DEPLOYMENT_GAS_LIMIT_EXTRA=0.2
7 |
8 | BRIDGEABLE_TOKEN_NAME="Your New Bridged Token"
9 | BRIDGEABLE_TOKEN_SYMBOL="TEST"
10 | BRIDGEABLE_TOKEN_DECIMALS="18"
11 |
12 | HOME_RPC_URL=http://parity1:8545
13 | HOME_BRIDGE_OWNER=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
14 | HOME_VALIDATORS_OWNER=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
15 | HOME_UPGRADEABLE_ADMIN=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
16 | HOME_DAILY_LIMIT=30000000000000000000000000
17 | HOME_MAX_AMOUNT_PER_TX=1500000000000000000000000
18 | HOME_MIN_AMOUNT_PER_TX=10000000000000000
19 | HOME_REQUIRED_BLOCK_CONFIRMATIONS=1
20 | HOME_GAS_PRICE=1000000000
21 | HOME_REWARDABLE=false
22 |
23 | FOREIGN_RPC_URL=http://parity2:8545
24 | FOREIGN_BRIDGE_OWNER=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
25 | FOREIGN_VALIDATORS_OWNER=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
26 | FOREIGN_UPGRADEABLE_ADMIN=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
27 | FOREIGN_DAILY_LIMIT=15000000000000000000000000
28 | FOREIGN_MAX_AMOUNT_PER_TX=750000000000000000000000
29 | FOREIGN_MIN_AMOUNT_PER_TX=10000000000000000
30 | FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS=1
31 | FOREIGN_GAS_PRICE=10000000000
32 | FOREIGN_REWARDABLE=false
33 |
34 | BLOCK_REWARD_ADDRESS=0xdbeE25CbE97e4A5CC6c499875774dc7067E9426B
35 | ERC20_TOKEN_ADDRESS=0x6B175474E89094C44Da98b954EedeAC495271d0F
36 |
37 | REQUIRED_NUMBER_OF_VALIDATORS=1
38 | VALIDATORS="0xaaB52d66283F7A1D5978bcFcB55721ACB467384b 0xdCC784657C78054aa61FbcFFd2605F32374816A4 0xDcef88209a20D52165230104B245803C3269454d"
39 |
--------------------------------------------------------------------------------
/e2e-commons/down.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | cd $(dirname $0)
3 |
4 | if [ $CI ]; then
5 | rm -rf logs || true
6 |
7 | mkdir ./logs
8 |
9 | for project in "" validator{1,2,3}; do
10 | for container in $(docker-compose -p "$project" ps | tail -n +3 | awk '{print $1}') ; do
11 | if [[ -z "$project" ]]; then
12 | path="./logs/$container.log"
13 | else
14 | mkdir -p "./logs/$project"
15 | path="./logs/$project/$container.log"
16 | fi
17 | docker logs "$container" > "$path" 2>&1
18 | done
19 | done
20 |
21 | touch ../oracle/.env
22 | for file in ../oracle/docker-compose-{amb,transfer}.yml; do
23 | for container in $(docker-compose -f "$file" ps | tail -n +3 | awk '{print $1}') ; do
24 | mkdir -p "./logs/oracle"
25 | docker logs "$container" > "./logs/oracle/$container.log" 2>&1
26 | done
27 | done
28 |
29 | exit $rc;
30 | fi
31 |
32 | ps | grep node | grep -v grep | grep -v yarn | awk '{print "kill " $1}' | /bin/bash
33 | docker-compose down
34 | docker-compose -p validator1 down
35 | docker-compose -p validator2 down
36 | docker-compose -p validator3 down
37 | docker network rm ultimate || true
38 |
--------------------------------------------------------------------------------
/e2e-commons/pull.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | cd $(dirname $0)
3 | set -e # exit when any command fails
4 |
5 | docker-compose pull e2e
6 | while [ "$1" != "" ]; do
7 | if [ "$1" == "oracle" ]; then
8 | docker-compose pull oracle-amb
9 | elif [ "$1" == "alm-e2e" ]; then
10 | docker-compose pull oracle-amb
11 | elif [ "$1" == "monitor" ]; then
12 | docker-compose pull monitor-amb
13 | elif [ "$1" == "alm" ]; then
14 | docker-compose pull alm
15 | fi
16 | shift
17 | done
18 |
--------------------------------------------------------------------------------
/e2e-commons/scripts/blocks.js:
--------------------------------------------------------------------------------
1 | const Web3 = require('web3')
2 |
3 | const homeWeb3 = new Web3(new Web3.providers.HttpProvider('http://parity1:8545'))
4 | const foreignWeb3 = new Web3(new Web3.providers.HttpProvider('http://parity2:8545'))
5 | const {user, blockGenerator} = require('../constants.json');
6 |
7 | homeWeb3.eth.accounts.wallet.add(user.privateKey)
8 | foreignWeb3.eth.accounts.wallet.add(user.privateKey)
9 | homeWeb3.eth.accounts.wallet.add(blockGenerator.privateKey)
10 | foreignWeb3.eth.accounts.wallet.add(blockGenerator.privateKey)
11 |
12 | function generateNewBlock(web3, address) {
13 | return web3.eth.sendTransaction({
14 | from: address,
15 | to: '0x0000000000000000000000000000000000000000',
16 | gasPrice: '1',
17 | gas: '21000',
18 | value: '1'
19 | })
20 | }
21 |
22 | function main() {
23 | setTimeout(async () => {
24 | try {
25 | generateNewBlock(homeWeb3, blockGenerator.address)
26 | } catch (_) {} // in case of Transaction with the same hash was already imported.
27 | try {
28 | generateNewBlock(foreignWeb3, blockGenerator.address)
29 | } catch (_) {} // in case of Transaction with the same hash was already imported.
30 | main()
31 | }, 1000)
32 | }
33 |
34 | main()
35 |
36 | process.on('SIGTERM', function () {
37 | console.log('Finishing sending blocks...')
38 | process.exit(0);
39 | });
40 |
--------------------------------------------------------------------------------
/e2e-commons/scripts/deploy.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | cd $(dirname $0)
3 | set -e # exit when any command fails
4 |
5 | CONTRACTS_PATH="../../contracts"
6 | DEPLOY_PATH="$CONTRACTS_PATH/deploy"
7 | ENVS_PATH="../contracts-envs"
8 |
9 | # mock bridge validators contract with the one with deterministic isValidatorDuty
10 | mv "$CONTRACTS_PATH/build/contracts/BridgeValidatorsDeterministic.json" "$CONTRACTS_PATH/build/contracts/BridgeValidators.json"
11 |
12 | echo -e "\n\n############ Deploying block reward ############\n"
13 | cp "$ENVS_PATH/erc-to-native.env" "$DEPLOY_PATH/.env"
14 | cd "$DEPLOY_PATH"
15 | node src/utils/deployBlockReward.js
16 | cd - > /dev/null
17 |
18 | echo -e "\n\n############ Deploying erc-to-native ############\n"
19 | cd "$DEPLOY_PATH"
20 | node deploy.js
21 | cd - > /dev/null
22 |
23 | echo -e "\n\n############ Deploying amb ############\n"
24 | cp "$ENVS_PATH/amb.env" "$DEPLOY_PATH/.env"
25 | cd "$DEPLOY_PATH"
26 | node deploy.js
27 | cd - > /dev/null
28 |
29 | echo -e "\n\n############ Deploying test contract for amb ############\n"
30 | cd "$DEPLOY_PATH"
31 | node src/utils/deployTestBox.js
32 | cd - > /dev/null
33 |
34 | echo -e "\n\n############ Deploying one more test contract for amb ############\n"
35 | cd "$DEPLOY_PATH"
36 | node src/utils/deployTestBox.js
37 | cd - > /dev/null
38 |
39 | echo -e "\n\n############ Deploying one more amb without oracle for confirm relay tests ############\n"
40 | cp "$ENVS_PATH/amb.env" "$DEPLOY_PATH/.env"
41 | cd "$DEPLOY_PATH"
42 | node deploy.js
43 | cd - > /dev/null
44 |
--------------------------------------------------------------------------------
/e2e-commons/ultimate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omni/tokenbridge/961b12b9f3545830a04044e109762277efcea6ef/e2e-commons/ultimate.png
--------------------------------------------------------------------------------
/e2e-commons/utils.js:
--------------------------------------------------------------------------------
1 | const promiseRetry = require('promise-retry')
2 |
3 | async function uniformRetry(f) {
4 | return promiseRetry(f, {
5 | forever: true,
6 | factor: 1,
7 | minTimeout: 500
8 | })
9 | }
10 |
11 | async function sleep(timeout) {
12 | return new Promise(res => setTimeout(res, timeout))
13 | }
14 |
15 | module.exports = {
16 | uniformRetry,
17 | sleep
18 | }
19 |
--------------------------------------------------------------------------------
/monitor-e2e/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "plugin:node/recommended",
4 | "airbnb-base",
5 | "../.eslintrc"
6 | ],
7 | "plugins": ["node"],
8 | "rules": {
9 | "node/no-unpublished-require": "off",
10 | "node/no-extraneous-require": "off",
11 | "import/no-extraneous-dependencies": "off"
12 | },
13 | "env": {
14 | "mocha": true
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/monitor-e2e/README.md:
--------------------------------------------------------------------------------
1 | # POA TokenBridge / Monitor-E2E
2 |
3 | End to end tests for the POA TokenBridge [Monitor](../monitor/README.md).
4 |
5 | ## Running
6 |
7 | To run the bridge end-to-end tests, you just have to run:
8 |
9 | ```
10 | ./run-tests.sh
11 | ```
12 |
--------------------------------------------------------------------------------
/monitor-e2e/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "monitor-e2e",
3 | "version": "0.0.1",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "mocha --timeout 120000 --exit",
8 | "lint": "eslint . --ignore-path ../.eslintignore"
9 | },
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "mocha": "^5.2.0",
14 | "axios": "0.19.0"
15 | },
16 | "engines": {
17 | "node": ">= 12.22"
18 | },
19 | "devDependencies": {}
20 | }
21 |
--------------------------------------------------------------------------------
/monitor-e2e/periodically-check-all.sh:
--------------------------------------------------------------------------------
1 | while true; do
2 | docker-compose -f ../e2e-commons/docker-compose.yml exec -T monitor-erc20-native yarn check-all
3 | pid1=$!
4 | docker-compose -f ../e2e-commons/docker-compose.yml exec -T monitor-amb yarn check-all
5 | pid2=$!
6 |
7 | wait $pid1
8 | wait $pid2
9 | done
10 |
--------------------------------------------------------------------------------
/monitor-e2e/run-tests.sh:
--------------------------------------------------------------------------------
1 | cd $(dirname $0)
2 |
3 | mode="$1"
4 | case "$mode" in
5 | amb)
6 | script=./test/amb.js
7 | ;;
8 | erc-to-native)
9 | script=./test/ercToNative.js
10 | ;;
11 | esac
12 |
13 | MODE="$mode" ../e2e-commons/up.sh deploy blocks monitor
14 |
15 | MODE="$mode" ./wait-for-monitor.sh
16 | nohup ./periodically-check-all.sh < /dev/null > /dev/null 2>&1 &
17 | checkPID=$!
18 |
19 | docker-compose -f ../e2e-commons/docker-compose.yml run e2e yarn workspace monitor-e2e run start $script
20 | rc=$?
21 |
22 | ../e2e-commons/down.sh
23 | kill $checkPID
24 | exit $rc
25 |
--------------------------------------------------------------------------------
/monitor-e2e/test/ercToNative.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert')
2 | const axios = require('axios')
3 | const { ercToNativeBridge, user, foreignRPC, validator } = require('../../e2e-commons/constants.json')
4 | const { waitUntil, sendTokens, addValidator } = require('../utils')
5 |
6 | const baseUrl = ercToNativeBridge.monitor
7 |
8 | describe('ERC TO NATIVE', () => {
9 | let data
10 |
11 | before(async () => {
12 | ;({ data } = await axios.get(`${baseUrl}`))
13 | })
14 |
15 | it('balance', () => assert(parseInt(data.foreign.erc20Balance, 10) >= 0))
16 | it('should contain totalSupply', () => assert(data.home.totalSupply === '0'))
17 | })
18 |
19 | describe('ERC TO NATIVE with changing state of contracts', () => {
20 | let data
21 |
22 | before(async () => {
23 | assert((await axios.get(`${baseUrl}`)).data.balanceDiff === 0)
24 | assert((await axios.get(`${baseUrl}/validators`)).data.validatorsMatch === true)
25 | })
26 |
27 | it('should change balanceDiff', async function() {
28 | this.timeout(60000)
29 | await sendTokens(foreignRPC.URL, user, ercToNativeBridge.foreignToken, ercToNativeBridge.foreign)
30 |
31 | await waitUntil(async () => {
32 | ;({ data } = await axios.get(`${baseUrl}`))
33 | if (!data.foreign) {
34 | return false
35 | }
36 | const { erc20Balance, investedErc20Balance } = data.foreign
37 | return data.balanceDiff === 0.01 && erc20Balance === '0.01' && investedErc20Balance === undefined
38 | })
39 | })
40 |
41 | it('should change validatorsMatch', async () => {
42 | await addValidator(foreignRPC.URL, validator, ercToNativeBridge.foreign)
43 | await waitUntil(async () => {
44 | ;({ data } = await axios.get(`${baseUrl}/validators`))
45 | return data.validatorsMatch === false
46 | })
47 | })
48 | })
49 |
--------------------------------------------------------------------------------
/monitor-e2e/wait-for-monitor.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | FILES=(getBalances.json validators.json eventsStats.json alerts.json)
4 |
5 | check_files_exist() {
6 | rc=0
7 | for f in "${FILES[@]}"; do
8 | command="test -f responses/bridge/$f"
9 | if [[ -z "$MODE" || "$MODE" == erc-to-native ]]; then
10 | (docker-compose -f ../e2e-commons/docker-compose.yml exec -T monitor-erc20-native /bin/bash -c "$command") || rc=1
11 | fi
12 | if [[ -z "$MODE" || "$MODE" == amb ]]; then
13 | (docker-compose -f ../e2e-commons/docker-compose.yml exec -T monitor-amb /bin/bash -c "$command") || rc=1
14 | fi
15 | done
16 | return $rc
17 | }
18 |
19 | i=0
20 | until check_files_exist
21 | do
22 | ((i++))
23 | if [ "$i" -gt 30 ]
24 | then
25 | exit -1
26 | fi
27 |
28 | echo "Waiting for monitor to start..."
29 | sleep 3
30 | done
31 |
32 | echo "Monitor started"
33 |
--------------------------------------------------------------------------------
/monitor/.env.example:
--------------------------------------------------------------------------------
1 | MONITOR_BRIDGE_NAME=bridge
2 |
3 | COMMON_HOME_RPC_URL=https://sokol.poa.network
4 | COMMON_FOREIGN_RPC_URL=https://kovan.infura.io/mew
5 | COMMON_HOME_BRIDGE_ADDRESS=0xABb4C1399DcC28FBa3Beb76CAE2b50Be3e087353
6 | COMMON_FOREIGN_BRIDGE_ADDRESS=0xE405F6872cE38a7a4Ff63DcF946236D458c2ca3a
7 | MONITOR_HOME_START_BLOCK=0
8 | MONITOR_FOREIGN_START_BLOCK=0
9 |
10 | MONITOR_VALIDATOR_HOME_TX_LIMIT=300000
11 | COMMON_HOME_GAS_PRICE_SUPPLIER_URL=https://gasprice.poa.network/
12 | COMMON_HOME_GAS_PRICE_SPEED_TYPE=standard
13 | COMMON_HOME_GAS_PRICE_FALLBACK=1000000000
14 | COMMON_HOME_GAS_PRICE_FACTOR=1
15 |
16 | MONITOR_VALIDATOR_FOREIGN_TX_LIMIT=300000
17 | COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL=https://gasprice.poa.network/
18 | COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE=standard
19 | COMMON_FOREIGN_GAS_PRICE_FALLBACK=1000000000
20 | COMMON_FOREIGN_GAS_PRICE_FACTOR=1
21 |
22 | MONITOR_TX_NUMBER_THRESHOLD=100
23 | MONITOR_PORT=3003
24 | MONITOR_CACHE_EVENTS=true
25 |
26 | MONITOR_HOME_TO_FOREIGN_ALLOWANCE_LIST=
27 | MONITOR_HOME_TO_FOREIGN_BLOCK_LIST=
28 |
29 | # MONITOR_HOME_VALIDATORS_BALANCE_ENABLE=0x... 0x... 0x...
30 | # MONITOR_FOREIGN_VALIDATORS_BALANCE_ENABLE=0x... 0x... 0x...
31 |
--------------------------------------------------------------------------------
/monitor/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": ["node"],
3 | "extends": [
4 | "plugin:node/recommended",
5 | "airbnb-base",
6 | "../.eslintrc"
7 | ],
8 | "rules": {
9 | "no-use-before-define": "off",
10 | "node/no-unpublished-require": "off"
11 | },
12 | "env": {
13 | "mocha": true
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/monitor/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:12 as contracts
2 |
3 | WORKDIR /mono
4 |
5 | COPY contracts/package.json contracts/package-lock.json ./contracts/
6 |
7 | WORKDIR /mono/contracts
8 | RUN npm install --only=prod
9 |
10 | COPY ./contracts/truffle-config.js ./
11 | COPY ./contracts/contracts ./contracts
12 | RUN npm run compile
13 |
14 | FROM node:12
15 |
16 | WORKDIR /mono
17 | COPY package.json .
18 | COPY --from=contracts /mono/contracts/build ./contracts/build
19 | COPY commons/package.json ./commons/
20 | COPY monitor/package.json ./monitor/
21 | COPY yarn.lock .
22 | RUN NOYARNPOSTINSTALL=1 yarn install --frozen-lockfile --production
23 |
24 | COPY ./commons ./commons
25 | COPY ./monitor ./monitor
26 |
27 | WORKDIR /mono/monitor
28 | CMD echo "To start the monitor web service run:" \
29 | "yarn start" \
30 | "To run monitor scripts run:" \
31 | "yarn check-all"
32 |
--------------------------------------------------------------------------------
/monitor/cache/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omni/tokenbridge/961b12b9f3545830a04044e109762277efcea6ef/monitor/cache/.gitkeep
--------------------------------------------------------------------------------
/monitor/checkWorker3.js:
--------------------------------------------------------------------------------
1 | require('dotenv').config()
2 | const logger = require('./logger')('checkWorker3')
3 | const detectMediators = require('./detectMediators')
4 | const detectFailures = require('./detectFailures')
5 | const { writeFile, createDir } = require('./utils/file')
6 | const { web3Home } = require('./utils/web3')
7 | const { saveCache } = require('./utils/web3Cache')
8 |
9 | const { MONITOR_BRIDGE_NAME, COMMON_HOME_BRIDGE_ADDRESS } = process.env
10 | const { getBridgeMode, HOME_ERC_TO_NATIVE_ABI, BRIDGE_MODES } = require('../commons')
11 |
12 | async function checkWorker3() {
13 | try {
14 | const homeBridge = new web3Home.eth.Contract(HOME_ERC_TO_NATIVE_ABI, COMMON_HOME_BRIDGE_ADDRESS)
15 | const bridgeMode = await getBridgeMode(homeBridge)
16 | if (bridgeMode === BRIDGE_MODES.ARBITRARY_MESSAGE) {
17 | createDir(`/responses/${MONITOR_BRIDGE_NAME}`)
18 |
19 | logger.debug('calling detectMediators()')
20 | const mediators = await detectMediators(bridgeMode)
21 | mediators.ok = true
22 | mediators.health = true
23 | writeFile(`/responses/${MONITOR_BRIDGE_NAME}/mediators.json`, mediators)
24 |
25 | logger.debug('calling detectFailures()')
26 | const failures = await detectFailures(bridgeMode)
27 | failures.ok = true
28 | failures.health = true
29 | writeFile(`/responses/${MONITOR_BRIDGE_NAME}/failures.json`, failures)
30 |
31 | saveCache()
32 | logger.debug('Done')
33 | }
34 | } catch (e) {
35 | logger.error('checkWorker3.js', e)
36 | }
37 | }
38 | checkWorker3()
39 |
--------------------------------------------------------------------------------
/monitor/configs/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omni/tokenbridge/961b12b9f3545830a04044e109762277efcea6ef/monitor/configs/.gitkeep
--------------------------------------------------------------------------------
/monitor/crontab.example:
--------------------------------------------------------------------------------
1 | # Yarn:
2 | */4 * * * * cd $HOME/tokenbridge/monitor; yarn check-all >>cronWorker.out 2>>cronWorker.err
3 |
4 | # Docker:
5 | */4 * * * * cd $HOME/tokenbridge/monitor; docker run --rm --env-file .env -v $(pwd)/responses:/mono/monitor/responses poanetwork/tokenbridge-monitor:latest /bin/bash -c 'yarn check-all' >>cronWorker.out 2>>cronWorker.err
6 |
--------------------------------------------------------------------------------
/monitor/docker-compose-build.yml:
--------------------------------------------------------------------------------
1 | ---
2 | version: '2.4'
3 | services:
4 | monitor:
5 | image: poanetwork/tokenbridge-monitor
6 | build:
7 | context: ..
8 | dockerfile: ./monitor/Dockerfile
9 |
--------------------------------------------------------------------------------
/monitor/docker-compose.yml:
--------------------------------------------------------------------------------
1 | ---
2 | version: '2.4'
3 | services:
4 | monitor:
5 | image: poanetwork/tokenbridge-monitor:latest
6 | ports:
7 | - "${MONITOR_PORT}:${MONITOR_PORT}"
8 | env_file: ./.env
9 | environment:
10 | - NODE_ENV=production
11 | volumes:
12 | - ./responses:/mono/monitor/responses
13 | - ./cache:/mono/monitor/cache
14 | restart: unless-stopped
15 | entrypoint: "yarn start"
16 |
--------------------------------------------------------------------------------
/monitor/index.js:
--------------------------------------------------------------------------------
1 | require('dotenv').config()
2 | const express = require('express')
3 | const cors = require('cors')
4 | const { readFile } = require('./utils/file')
5 |
6 | const app = express()
7 | const bridgeRouter = express.Router({ mergeParams: true })
8 |
9 | app.use(cors())
10 |
11 | app.get('/favicon.ico', (req, res) => res.sendStatus(204))
12 | app.use('/:bridgeName', bridgeRouter)
13 |
14 | bridgeRouter.get('/:file(validators|eventsStats|alerts|mediators|stuckTransfers|failures)?', (req, res, next) => {
15 | try {
16 | const { bridgeName, file } = req.params
17 | const results = readFile(`./responses/${bridgeName}/${file || 'getBalances'}.json`)
18 | res.json(results)
19 | } catch (e) {
20 | // this will eventually be handled by your error handling middleware
21 | next(e)
22 | }
23 | })
24 |
25 | bridgeRouter.get('/metrics', (req, res, next) => {
26 | try {
27 | const { bridgeName } = req.params
28 | const metrics = readFile(`./responses/${bridgeName}/metrics.txt`, false)
29 | res.type('text').send(metrics)
30 | } catch (e) {
31 | next(e)
32 | }
33 | })
34 |
35 | const port = process.env.MONITOR_PORT || 3003
36 | app.set('port', port)
37 | app.listen(port, () => console.log(`Monitoring app listening on port ${port}!`))
38 |
--------------------------------------------------------------------------------
/monitor/logger.js:
--------------------------------------------------------------------------------
1 | module.exports = function logger(name) {
2 | let lastlog = 0
3 |
4 | function log(...args) {
5 | const now = new Date()
6 | console.log(now.toISOString(), `(+${lastlog ? now.getTime() - lastlog : 0}ms)`, `[${name}]`, ...args)
7 | lastlog = now.getTime()
8 | }
9 |
10 | function error(...args) {
11 | const now = new Date()
12 | console.error(now.toISOString(), `[${name}]`, ...args)
13 | }
14 |
15 | let dbg
16 | if (process.env.DEBUG) {
17 | dbg = (...args) => {
18 | log(...args)
19 | }
20 | } else {
21 | dbg = () => {}
22 | }
23 |
24 | return {
25 | log,
26 | error,
27 | debug: dbg
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/monitor/metricsWorker.js:
--------------------------------------------------------------------------------
1 | require('dotenv').config()
2 | const logger = require('./logger')('metricsWorker')
3 | const { writeFile, createDir } = require('./utils/file')
4 | const getPrometheusMetrics = require('./prometheusMetrics')
5 |
6 | const { MONITOR_BRIDGE_NAME } = process.env
7 |
8 | async function metricsWorker() {
9 | try {
10 | createDir(`/responses/${MONITOR_BRIDGE_NAME}`)
11 | logger.debug('calling getPrometheusMetrics()')
12 | const metrics = await getPrometheusMetrics(MONITOR_BRIDGE_NAME)
13 | if (!metrics) throw new Error('metrics is empty: ' + JSON.stringify(metrics))
14 | writeFile(`/responses/${MONITOR_BRIDGE_NAME}/metrics.txt`, metrics, { stringify: false })
15 | logger.debug('Done')
16 | } catch (e) {
17 | logger.error(e)
18 | }
19 | }
20 | metricsWorker()
21 |
--------------------------------------------------------------------------------
/monitor/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "monitor",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "check-all": "timeout -s 9 5m node checkWorker.js && timeout -s 9 5m node checkWorker2.js && timeout -s 9 5m node checkWorker3.js && timeout -s 9 10s node metricsWorker.js",
8 | "start": "node index.js",
9 | "check-and-start": "yarn check-all && yarn start",
10 | "lint": "eslint . --ignore-path ../.eslintignore",
11 | "lint:fix": "eslint . --fix",
12 | "test": "NODE_ENV=test mocha"
13 | },
14 | "author": "",
15 | "license": "ISC",
16 | "dependencies": {
17 | "bignumber.js": "^9.0.1",
18 | "cors": "^2.8.5",
19 | "dotenv": "^5.0.1",
20 | "express": "^4.16.3",
21 | "node-fetch": "^2.1.2",
22 | "web3": "^1.3.0"
23 | },
24 | "engines": {
25 | "node": ">= 12.22"
26 | },
27 | "devDependencies": {
28 | "chai": "^4.2.0"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/monitor/responses/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omni/tokenbridge/961b12b9f3545830a04044e109762277efcea6ef/monitor/responses/.gitkeep
--------------------------------------------------------------------------------
/monitor/test-srv.js:
--------------------------------------------------------------------------------
1 | const express = require('express')
2 |
3 | const app = express()
4 |
5 | app.all('/', (req, res) => {
6 | setTimeout(() => {
7 | res.status(504)
8 | res.end()
9 | }, 2000)
10 | })
11 |
12 | const MONITOR_PORT = process.env.MONITOR_PORT || 4000
13 | app.listen(MONITOR_PORT, () => console.log('Listening on port ' + MONITOR_PORT))
14 |
--------------------------------------------------------------------------------
/monitor/utils/web3.js:
--------------------------------------------------------------------------------
1 | require('dotenv').config()
2 | const Web3 = require('web3')
3 |
4 | const { COMMON_HOME_RPC_URL, COMMON_FOREIGN_RPC_URL } = process.env
5 |
6 | const homeProvider = new Web3.providers.HttpProvider(COMMON_HOME_RPC_URL)
7 | const web3Home = new Web3(homeProvider)
8 |
9 | const foreignProvider = new Web3.providers.HttpProvider(COMMON_FOREIGN_RPC_URL)
10 | const web3Foreign = new Web3(foreignProvider)
11 |
12 | function blockNumberWrapper(web3) {
13 | let blockNumber = null
14 | return async () => {
15 | if (!blockNumber) {
16 | blockNumber = await web3.eth.getBlockNumber()
17 | }
18 | return blockNumber
19 | }
20 | }
21 |
22 | module.exports = {
23 | web3Home,
24 | web3Foreign,
25 | getHomeBlockNumber: blockNumberWrapper(web3Home),
26 | getForeignBlockNumber: blockNumberWrapper(web3Foreign)
27 | }
28 |
--------------------------------------------------------------------------------
/oracle-e2e/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "plugin:node/recommended",
4 | "airbnb-base",
5 | "../.eslintrc"
6 | ],
7 | "plugins": ["node"],
8 | "rules": {
9 | "node/no-unpublished-require": "off"
10 | },
11 | "env": {
12 | "mocha": true
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/oracle-e2e/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "oracle-e2e",
3 | "version": "0.0.1",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "mocha",
8 | "generate-amb-tx": "node ./scripts/generate-amb-tx.js",
9 | "lint": "eslint . --ignore-path ../.eslintignore",
10 | "amb": "mocha test/amb.js",
11 | "erc-to-native": "mocha test/ercToNative.js",
12 | "alm": "mocha test/amb.js"
13 | },
14 | "author": "",
15 | "license": "ISC",
16 | "dependencies": {
17 | "mocha": "^5.2.0",
18 | "chalk": "^2.4.1",
19 | "dotenv": "^6.0.0",
20 | "promise-retry": "^1.1.1",
21 | "shelljs": "^0.8.2",
22 | "tree-kill": "^1.2.0",
23 | "web3": "^1.3.0",
24 | "websocket": "^1.0.28"
25 | },
26 | "engines": {
27 | "node": ">= 12.22"
28 | },
29 | "devDependencies": {}
30 | }
31 |
--------------------------------------------------------------------------------
/oracle-e2e/run-tests.sh:
--------------------------------------------------------------------------------
1 | cd $(dirname $0)
2 |
3 | mode="$1"
4 | case "$mode" in
5 | amb)
6 | script=./test/amb.js
7 | ;;
8 | erc-to-native)
9 | script=./test/ercToNative.js
10 | ;;
11 | esac
12 |
13 | MODE="$mode" ../e2e-commons/up.sh deploy generate-amb-tx manual-amb-relay blocks oracle oracle-validator-2 oracle-validator-3
14 |
15 | docker-compose -f ../e2e-commons/docker-compose.yml run e2e yarn workspace oracle-e2e run start $script
16 | rc=$?
17 |
18 | ../e2e-commons/down.sh
19 | exit $rc
20 |
--------------------------------------------------------------------------------
/oracle-e2e/scripts/generate-amb-tx.js:
--------------------------------------------------------------------------------
1 | const Web3 = require('web3')
2 | const { user, homeRPC, foreignRPC, amb2: amb } = require('../../e2e-commons/constants.json')
3 | const { BOX_ABI } = require('../../commons')
4 |
5 | const homeWeb3 = new Web3(new Web3.providers.HttpProvider(homeRPC.URL))
6 | const foreignWeb3 = new Web3(new Web3.providers.HttpProvider(foreignRPC.URL))
7 |
8 | homeWeb3.eth.accounts.wallet.add(user.privateKey)
9 | foreignWeb3.eth.accounts.wallet.add(user.privateKey)
10 |
11 | const opts = {
12 | from: user.address,
13 | gas: 400000,
14 | gasPrice: '1'
15 | }
16 | const homeBox = new homeWeb3.eth.Contract(BOX_ABI, amb.homeBox, opts)
17 | const foreignBox = new foreignWeb3.eth.Contract(BOX_ABI, amb.foreignBox, opts)
18 |
19 | async function main() {
20 | const res1 = await homeBox.methods.setValueOnOtherNetwork(123, amb.home, amb.foreignBox).send()
21 | const res2 = await foreignBox.methods.setValueOnOtherNetwork(456, amb.foreign, amb.homeBox).send()
22 | const res3 = await foreignBox.methods.setValueOnOtherNetwork(789, amb.foreign, amb.homeBox).send()
23 |
24 | console.log(res1.transactionHash)
25 | console.log(res2.transactionHash)
26 | console.log(res3.transactionHash)
27 | }
28 |
29 | main()
30 |
--------------------------------------------------------------------------------
/oracle-e2e/test/mocha.opts:
--------------------------------------------------------------------------------
1 | --timeout 120000 --exit
2 |
--------------------------------------------------------------------------------
/oracle-e2e/test/utils.js:
--------------------------------------------------------------------------------
1 | const { BRIDGE_VALIDATORS_ABI } = require('../../commons')
2 |
3 | async function delay(ms) {
4 | return new Promise(res => setTimeout(res, ms))
5 | }
6 |
7 | const setRequiredSignatures = async ({ bridgeContract, web3, requiredSignatures, options }) => {
8 | const validatorAddress = await bridgeContract.methods.validatorContract().call()
9 | const validatorContract = new web3.eth.Contract(BRIDGE_VALIDATORS_ABI, validatorAddress)
10 |
11 | return validatorContract.methods.setRequiredSignatures(requiredSignatures).send(options)
12 | }
13 |
14 | module.exports = {
15 | delay,
16 | setRequiredSignatures
17 | }
18 |
--------------------------------------------------------------------------------
/oracle/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "plugin:node/recommended",
4 | "airbnb-base",
5 | "../.eslintrc"
6 | ],
7 | "plugins": ["node"],
8 | "rules": {
9 | "node/no-unpublished-require": "off",
10 | "global-require": "off"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/oracle/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:12 as contracts
2 |
3 | WORKDIR /mono
4 |
5 | COPY contracts/package.json contracts/package-lock.json ./contracts/
6 |
7 | WORKDIR /mono/contracts
8 | RUN npm install --only=prod
9 |
10 | COPY ./contracts/truffle-config.js ./
11 | COPY ./contracts/contracts ./contracts
12 | RUN npm run compile
13 |
14 | FROM node:12
15 |
16 | RUN apt-get update && \
17 | apt-get install -y build-essential libc6-dev libc6-dev-i386 wget && \
18 | apt-get clean
19 |
20 | WORKDIR /mono
21 | COPY package.json .
22 | COPY --from=contracts /mono/contracts/build ./contracts/build
23 | COPY commons/package.json ./commons/
24 | COPY oracle/package.json ./oracle/
25 | COPY yarn.lock .
26 | RUN NOYARNPOSTINSTALL=1 yarn install --frozen-lockfile --production
27 |
28 | COPY ./commons ./commons
29 | COPY ./oracle ./oracle
30 |
31 | WORKDIR /mono/oracle
32 | CMD echo "To start a bridge process run:" \
33 | "ORACLE_VALIDATOR_ADDRESS= ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY= docker-compose up -d --build"
34 |
--------------------------------------------------------------------------------
/oracle/ERC_TO_NATIVE.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omni/tokenbridge/961b12b9f3545830a04044e109762277efcea6ef/oracle/ERC_TO_NATIVE.png
--------------------------------------------------------------------------------
/oracle/config/affirmation-request-watcher.config.js:
--------------------------------------------------------------------------------
1 | const baseConfig = require('./base.config')
2 |
3 | const id = `${baseConfig.id}-affirmation-request`
4 |
5 | module.exports = {
6 | ...baseConfig,
7 | main: baseConfig.foreign,
8 | event: 'UserRequestForAffirmation',
9 | sender: 'home',
10 | queue: 'home-prioritized',
11 | name: `watcher-${id}`,
12 | id
13 | }
14 |
--------------------------------------------------------------------------------
/oracle/config/collected-signatures-watcher.config.js:
--------------------------------------------------------------------------------
1 | const baseConfig = require('./base.config')
2 |
3 | const id = `${baseConfig.id}-collected-signatures`
4 |
5 | module.exports = {
6 | ...baseConfig,
7 | main: baseConfig.home,
8 | event: 'CollectedSignatures',
9 | sender: 'foreign',
10 | queue: 'foreign-prioritized',
11 | name: `watcher-${id}`,
12 | id
13 | }
14 |
--------------------------------------------------------------------------------
/oracle/config/foreign-mev-sender.config.js:
--------------------------------------------------------------------------------
1 | const baseConfig = require('./base.config')
2 |
3 | const { DEFAULT_TRANSACTION_RESEND_INTERVAL } = require('../src/utils/constants')
4 | const { MEV_HELPER_ABI } = require('../src/utils/mev')
5 | const { web3Foreign, getFlashbotsProvider } = require('../src/services/web3')
6 |
7 | const {
8 | ORACLE_FOREIGN_TX_RESEND_INTERVAL,
9 | ORACLE_MEV_FOREIGN_HELPER_CONTRACT_ADDRESS,
10 | ORACLE_MEV_FOREIGN_MIN_GAS_PRICE,
11 | ORACLE_MEV_FOREIGN_FLAT_MINER_FEE,
12 | ORACLE_MEV_FOREIGN_MAX_PRIORITY_FEE_PER_GAS,
13 | ORACLE_MEV_FOREIGN_MAX_FEE_PER_GAS,
14 | ORACLE_MEV_FOREIGN_BUNDLES_BLOCK_RANGE
15 | } = process.env
16 |
17 | const contract = new baseConfig.foreign.web3.eth.Contract(MEV_HELPER_ABI, ORACLE_MEV_FOREIGN_HELPER_CONTRACT_ADDRESS)
18 |
19 | module.exports = {
20 | ...baseConfig,
21 | pollingInterval: baseConfig.foreign.pollingInterval,
22 | mevForeign: {
23 | contractAddress: ORACLE_MEV_FOREIGN_HELPER_CONTRACT_ADDRESS,
24 | contract,
25 | minGasPrice: ORACLE_MEV_FOREIGN_MIN_GAS_PRICE,
26 | flatMinerFee: ORACLE_MEV_FOREIGN_FLAT_MINER_FEE,
27 | maxPriorityFeePerGas: ORACLE_MEV_FOREIGN_MAX_PRIORITY_FEE_PER_GAS,
28 | maxFeePerGas: ORACLE_MEV_FOREIGN_MAX_FEE_PER_GAS,
29 | bundlesPerIteration: Math.max(parseInt(ORACLE_MEV_FOREIGN_BUNDLES_BLOCK_RANGE, 10) || 5, 1),
30 | getFlashbotsProvider
31 | },
32 | mevJobsRedisKey: `${baseConfig.id}-collected-signatures-mev:mevJobs`,
33 | id: 'mev-sender-foreign',
34 | name: 'mev-sender-foreign',
35 | web3: web3Foreign,
36 | resendInterval: parseInt(ORACLE_FOREIGN_TX_RESEND_INTERVAL, 10) || DEFAULT_TRANSACTION_RESEND_INTERVAL
37 | }
38 |
--------------------------------------------------------------------------------
/oracle/config/foreign-sender.config.js:
--------------------------------------------------------------------------------
1 | const baseConfig = require('./base.config')
2 |
3 | const { DEFAULT_TRANSACTION_RESEND_INTERVAL } = require('../src/utils/constants')
4 |
5 | const { ORACLE_FOREIGN_TX_RESEND_INTERVAL } = process.env
6 |
7 | module.exports = {
8 | ...baseConfig,
9 | main: baseConfig.foreign,
10 | queue: 'foreign-prioritized',
11 | id: 'foreign',
12 | name: 'sender-foreign',
13 | resendInterval: parseInt(ORACLE_FOREIGN_TX_RESEND_INTERVAL, 10) || DEFAULT_TRANSACTION_RESEND_INTERVAL
14 | }
15 |
--------------------------------------------------------------------------------
/oracle/config/home-sender.config.js:
--------------------------------------------------------------------------------
1 | const baseConfig = require('./base.config')
2 |
3 | const { DEFAULT_TRANSACTION_RESEND_INTERVAL } = require('../src/utils/constants')
4 |
5 | const { ORACLE_HOME_TX_RESEND_INTERVAL } = process.env
6 |
7 | module.exports = {
8 | ...baseConfig,
9 | main: baseConfig.home,
10 | queue: 'home-prioritized',
11 | id: 'home',
12 | name: 'sender-home',
13 | resendInterval: parseInt(ORACLE_HOME_TX_RESEND_INTERVAL, 10) || DEFAULT_TRANSACTION_RESEND_INTERVAL
14 | }
15 |
--------------------------------------------------------------------------------
/oracle/config/information-request-watcher.config.js:
--------------------------------------------------------------------------------
1 | const baseConfig = require('./base.config')
2 |
3 | const id = `${baseConfig.id}-information-request`
4 |
5 | module.exports = {
6 | ...baseConfig,
7 | main: baseConfig.home,
8 | event: 'UserRequestForInformation',
9 | sender: 'home',
10 | queue: 'home-prioritized',
11 | name: `watcher-${id}`,
12 | id
13 | }
14 |
--------------------------------------------------------------------------------
/oracle/config/mev-collected-signatures-watcher.config.js:
--------------------------------------------------------------------------------
1 | const baseConfig = require('./base.config')
2 | const { MEV_HELPER_ABI } = require('../src/utils/mev')
3 |
4 | const {
5 | ORACLE_MEV_FOREIGN_HELPER_CONTRACT_ADDRESS,
6 | ORACLE_MEV_FOREIGN_MIN_GAS_PRICE,
7 | ORACLE_MEV_FOREIGN_FLAT_MINER_FEE,
8 | ORACLE_MEV_FOREIGN_MAX_PRIORITY_FEE_PER_GAS,
9 | ORACLE_MEV_FOREIGN_MAX_FEE_PER_GAS
10 | } = process.env
11 |
12 | const id = `${baseConfig.id}-collected-signatures-mev`
13 |
14 | const contract = new baseConfig.foreign.web3.eth.Contract(MEV_HELPER_ABI, ORACLE_MEV_FOREIGN_HELPER_CONTRACT_ADDRESS)
15 |
16 | module.exports = {
17 | ...baseConfig,
18 | mevForeign: {
19 | contractAddress: ORACLE_MEV_FOREIGN_HELPER_CONTRACT_ADDRESS,
20 | contract,
21 | minGasPrice: ORACLE_MEV_FOREIGN_MIN_GAS_PRICE,
22 | flatMinerFee: ORACLE_MEV_FOREIGN_FLAT_MINER_FEE,
23 | maxPriorityFeePerGas: ORACLE_MEV_FOREIGN_MAX_PRIORITY_FEE_PER_GAS,
24 | maxFeePerGas: ORACLE_MEV_FOREIGN_MAX_FEE_PER_GAS
25 | },
26 | main: baseConfig.home,
27 | event: 'CollectedSignatures',
28 | name: `watcher-${id}`,
29 | id
30 | }
31 |
--------------------------------------------------------------------------------
/oracle/config/shutdown-manager.config.js:
--------------------------------------------------------------------------------
1 | const baseConfig = require('./base.config')
2 |
3 | const {
4 | ORACLE_SHUTDOWN_SERVICE_POLLING_INTERVAL,
5 | ORACLE_SHUTDOWN_SERVICE_URL,
6 | ORACLE_SHUTDOWN_CONTRACT_ADDRESS,
7 | ORACLE_SHUTDOWN_CONTRACT_METHOD
8 | } = process.env
9 |
10 | module.exports = {
11 | ...baseConfig,
12 | id: 'shutdown-manager',
13 | name: 'shutdown-manager',
14 | pollingInterval: ORACLE_SHUTDOWN_SERVICE_POLLING_INTERVAL || 120000,
15 | checksBeforeResume: 3,
16 | checksBeforeStop: 1,
17 | shutdownServiceURL: ORACLE_SHUTDOWN_SERVICE_URL,
18 | shutdownContractAddress: ORACLE_SHUTDOWN_CONTRACT_ADDRESS,
19 | shutdownMethod: (ORACLE_SHUTDOWN_CONTRACT_METHOD || 'isShutdown()').trim(),
20 | requestTimeout: 2000
21 | }
22 |
--------------------------------------------------------------------------------
/oracle/config/signature-request-watcher.config.js:
--------------------------------------------------------------------------------
1 | const baseConfig = require('./base.config')
2 |
3 | const id = `${baseConfig.id}-signature-request`
4 |
5 | module.exports = {
6 | ...baseConfig,
7 | main: baseConfig.home,
8 | event: 'UserRequestForSignature',
9 | sender: 'home',
10 | queue: 'home-prioritized',
11 | name: `watcher-${id}`,
12 | id
13 | }
14 |
--------------------------------------------------------------------------------
/oracle/config/transfer-watcher.config.js:
--------------------------------------------------------------------------------
1 | const baseConfig = require('./base.config')
2 | const { ERC20_ABI, ZERO_ADDRESS } = require('../../commons')
3 | const { EXIT_CODES } = require('../src/utils/constants')
4 |
5 | const id = `${baseConfig.id}-transfer`
6 |
7 | if (baseConfig.id !== 'erc-native') {
8 | console.error(`Transfer watcher not required for bridge mode ${process.env.ORACLE_BRIDGE_MODE}`)
9 | process.exit(EXIT_CODES.WATCHER_NOT_REQUIRED)
10 | }
11 |
12 | // exact address of the token contract is set in the watcher.js checkConditions() function
13 | baseConfig.foreign.eventContract = new baseConfig.foreign.web3.eth.Contract(ERC20_ABI, ZERO_ADDRESS)
14 |
15 | module.exports = {
16 | ...baseConfig,
17 | main: baseConfig.foreign,
18 | event: 'Transfer',
19 | eventFilter: { to: baseConfig.foreign.bridgeAddress },
20 | sender: 'home',
21 | queue: 'home-prioritized',
22 | name: `watcher-${id}`,
23 | id
24 | }
25 |
--------------------------------------------------------------------------------
/oracle/docker-compose-build.yml:
--------------------------------------------------------------------------------
1 | ---
2 | version: '2.4'
3 | services:
4 | oracle:
5 | image: poanetwork/tokenbridge-oracle
6 | build:
7 | context: ..
8 | dockerfile: ./oracle/Dockerfile
9 |
--------------------------------------------------------------------------------
/oracle/env.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 | require('dotenv').config({
3 | path: path.join(__dirname, process.env.NODE_ENV === 'test' ? './test/test.env' : './.env')
4 | })
5 |
--------------------------------------------------------------------------------
/oracle/esController.sol:
--------------------------------------------------------------------------------
1 | //SPDX-License-Identifier: GPL-3.0-only
2 |
3 | /*
4 | This contract can be used together with the emergency shutdown
5 | functionality of the TokenBridge oracles.
6 | */
7 |
8 | pragma solidity 0.7.6;
9 |
10 | contract PauseController {
11 | address public manager;
12 | bool internal paused;
13 | bytes32 private immutable ID;
14 |
15 | constructor (string memory _id, address _manager) {
16 | require(bytes(_id).length <= 32);
17 | bytes32 id;
18 | assembly {
19 | id := mload(add(_id, 32))
20 | }
21 | ID = id;
22 |
23 | manager = _manager;
24 | }
25 |
26 | modifier onlyManager() {
27 | require(msg.sender == manager);
28 | _;
29 | }
30 |
31 | function changeManager(address _newmanager) external onlyManager {
32 | require(_newmanager != address(0));
33 | manager = _newmanager;
34 | }
35 |
36 | function pause() external onlyManager {
37 | paused = true;
38 | }
39 |
40 | function play() external onlyManager {
41 | paused = false;
42 | }
43 |
44 | function isPaused() external view returns(bool) {
45 | return paused;
46 | }
47 |
48 | function id() external view returns(string memory) {
49 | return string(abi.encodePacked(ID));
50 | }
51 |
52 | }
--------------------------------------------------------------------------------
/oracle/reset-lastBlock.sh:
--------------------------------------------------------------------------------
1 | node scripts/resetLastBlock.js $1 $2
2 |
--------------------------------------------------------------------------------
/oracle/scripts/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../.eslintrc",
3 | "rules": {
4 | "import/no-extraneous-dependencies": "off",
5 | "node/no-unpublished-require": "off"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/oracle/scripts/erc20_to_native/sendHome.js:
--------------------------------------------------------------------------------
1 | require('../../env')
2 | const { web3Home } = require('../../src/services/web3')
3 | const { sendTx } = require('../../src/tx/sendTx')
4 | const { isValidAmount } = require('../utils/utils')
5 | const { HOME_ERC_TO_NATIVE_ABI } = require('../../../commons')
6 |
7 | const {
8 | USER_ADDRESS,
9 | USER_ADDRESS_PRIVATE_KEY,
10 | COMMON_HOME_BRIDGE_ADDRESS,
11 | HOME_MIN_AMOUNT_PER_TX,
12 | HOME_TEST_TX_GAS_PRICE
13 | } = process.env
14 |
15 | const NUMBER_OF_DEPOSITS_TO_SEND = process.argv[2] || 1
16 |
17 | async function main() {
18 | const bridge = new web3Home.eth.Contract(HOME_ERC_TO_NATIVE_ABI, COMMON_HOME_BRIDGE_ADDRESS)
19 |
20 | try {
21 | await isValidAmount(HOME_MIN_AMOUNT_PER_TX, bridge)
22 |
23 | const homeChainId = await web3Home.eth.getChainId()
24 | let nonce = await web3Home.eth.getTransactionCount(USER_ADDRESS)
25 | let actualSent = 0
26 | for (let i = 0; i < Number(NUMBER_OF_DEPOSITS_TO_SEND); i++) {
27 | const txHash = await sendTx({
28 | privateKey: USER_ADDRESS_PRIVATE_KEY,
29 | data: '0x',
30 | nonce,
31 | gasPrice: HOME_TEST_TX_GAS_PRICE,
32 | value: web3Home.utils.toWei(HOME_MIN_AMOUNT_PER_TX),
33 | gasLimit: 100000,
34 | to: COMMON_HOME_BRIDGE_ADDRESS,
35 | web3: web3Home,
36 | chainId: homeChainId
37 | })
38 | if (txHash !== undefined) {
39 | nonce++
40 | actualSent++
41 | console.log(actualSent, ' # ', txHash)
42 | }
43 | }
44 | } catch (e) {
45 | console.log(e)
46 | }
47 | }
48 | main()
49 |
--------------------------------------------------------------------------------
/oracle/scripts/getValidatorStartBlocks.js:
--------------------------------------------------------------------------------
1 | require('../env')
2 |
3 | const { BRIDGE_VALIDATORS_ABI } = require('../../commons')
4 | const { home, foreign } = require('../config/base.config')
5 |
6 | async function getStartBlock(bridgeContract, web3) {
7 | try {
8 | const deployedAtBlock = await bridgeContract.methods.deployedAtBlock().call()
9 |
10 | const validatorContractAddress = await bridgeContract.methods.validatorContract().call()
11 | const validatorContract = new web3.eth.Contract(BRIDGE_VALIDATORS_ABI, validatorContractAddress)
12 |
13 | const validatorDeployedAtBlock = await validatorContract.methods.deployedAtBlock().call()
14 |
15 | const validatorAddedEvents = await validatorContract.getPastEvents('ValidatorAdded', {
16 | fromBlock: validatorDeployedAtBlock,
17 | filter: { validator: process.env.ORACLE_VALIDATOR_ADDRESS }
18 | })
19 |
20 | return validatorAddedEvents.length ? validatorAddedEvents[0].blockNumber : deployedAtBlock
21 | } catch (e) {
22 | return 0
23 | }
24 | }
25 |
26 | async function main() {
27 | const homeStartBlock = await getStartBlock(home.bridgeContract, home.web3)
28 | const foreignStartBlock = await getStartBlock(foreign.bridgeContract, foreign.web3)
29 | const result = {
30 | homeStartBlock,
31 | foreignStartBlock
32 | }
33 | console.log(JSON.stringify(result))
34 | return result
35 | }
36 |
37 | main()
38 |
39 | module.exports = main
40 |
--------------------------------------------------------------------------------
/oracle/scripts/privateKeyToAddress.js:
--------------------------------------------------------------------------------
1 | require('../env')
2 | const { privateKeyToAddress } = require('../src/utils/utils')
3 | const { EXIT_CODES } = require('../src/utils/constants')
4 |
5 | const privateKey = process.env.ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY
6 |
7 | if (!privateKey) {
8 | console.error('Environment variable ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY is not set')
9 | process.exit(EXIT_CODES.GENERAL_ERROR)
10 | }
11 |
12 | const address = privateKeyToAddress(privateKey)
13 |
14 | console.log(address)
15 |
--------------------------------------------------------------------------------
/oracle/scripts/resetLastBlock.js:
--------------------------------------------------------------------------------
1 | require('../env')
2 | const Redis = require('ioredis')
3 | const { id } = require('../config/base.config')
4 | const { EXIT_CODES } = require('../src/utils/constants')
5 |
6 | const redis = new Redis(process.env.ORACLE_REDIS_URL)
7 |
8 | redis.on('error', () => {
9 | logError('Error: Cannot connect to redis')
10 | })
11 |
12 | if (process.argv.length < 4) {
13 | logError(
14 | 'Please provide process key and new block value. Example:' +
15 | '\n signature-request 12345 ' +
16 | '\n collected-signatures 12345 ' +
17 | '\n affirmation-request 12345'
18 | )
19 | }
20 |
21 | function logError(message) {
22 | console.log(message)
23 | process.exit(EXIT_CODES.GENERAL_ERROR)
24 | }
25 |
26 | function getRedisKey(name) {
27 | return `${id}-${name}:lastProcessedBlock`
28 | }
29 |
30 | async function main() {
31 | try {
32 | const processName = process.argv[2]
33 | const rawBlockValue = process.argv[3]
34 |
35 | const newBlockValue = Number(rawBlockValue)
36 | if (!Number.isInteger(newBlockValue)) {
37 | logError('Expecting new block value to be an integer!')
38 | }
39 |
40 | const lastBlockRedisKey = getRedisKey(processName)
41 |
42 | const value = await redis.get(lastBlockRedisKey)
43 |
44 | if (!value) {
45 | logError(
46 | 'Error: Process key not found on redis. Please provide one of the following:' +
47 | '\n signature-request' +
48 | '\n collected-signatures' +
49 | '\n affirmation-request'
50 | )
51 | }
52 |
53 | await redis.set(lastBlockRedisKey, newBlockValue)
54 |
55 | console.log(`${processName} last block updated to ${newBlockValue}`)
56 |
57 | redis.disconnect()
58 | } catch (e) {
59 | console.log(e)
60 | }
61 | }
62 |
63 | main()
64 |
--------------------------------------------------------------------------------
/oracle/scripts/start-worker.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -o pipefail
4 |
5 | WORKERS_DIR="src/"
6 | LOGS_DIR="logs/"
7 |
8 | WORKER="${WORKERS_DIR}${1}.js"
9 | CONFIG="${2}.config.js"
10 | LOG="${LOGS_DIR}${2}.txt"
11 | TX_HASH=${@:3}
12 |
13 | if [ "${NODE_ENV}" = "production" ]; then
14 | exec node "${WORKER}" "${CONFIG}" $TX_HASH
15 | else
16 | node "${WORKER}" "${CONFIG}" $TX_HASH | tee -a "${LOG}" | pino-pretty
17 | fi
18 |
--------------------------------------------------------------------------------
/oracle/scripts/utils/utils.js:
--------------------------------------------------------------------------------
1 | const { fromWei } = require('web3').utils
2 |
3 | async function getMinPerTxLimit(bridge) {
4 | const minPerTx = await bridge.methods.minPerTx().call()
5 | return fromWei(minPerTx)
6 | }
7 |
8 | async function isValidAmount(amount, bridge) {
9 | const minLimit = await getMinPerTxLimit(bridge)
10 | if (amount < minLimit) {
11 | throw new Error(`The amount per Tx ${amount} should be at least ${minLimit}`)
12 | }
13 | }
14 |
15 | module.exports = {
16 | getMinPerTxLimit,
17 | isValidAmount
18 | }
19 |
--------------------------------------------------------------------------------
/oracle/src/events/processAMBInformationRequests/calls/ethBlockNumber.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | 'eth_blockNumber()': async (web3, _, block) => [true, web3.eth.abi.encodeParameter('uint256', block.number)]
3 | }
4 |
--------------------------------------------------------------------------------
/oracle/src/events/processAMBInformationRequests/calls/ethGetBalance.js:
--------------------------------------------------------------------------------
1 | const { toBN } = require('web3').utils
2 |
3 | const { ASYNC_CALL_ERRORS } = require('../../../utils/constants')
4 |
5 | async function call(web3, data, foreignBlock) {
6 | const address = web3.eth.abi.decodeParameter('address', data)
7 |
8 | const balance = await web3.eth.getBalance(address, foreignBlock.number)
9 |
10 | return [true, web3.eth.abi.encodeParameter('uint256', balance)]
11 | }
12 |
13 | async function callArchive(web3, data, foreignBlock) {
14 | const { 0: address, 1: blockNumber } = web3.eth.abi.decodeParameters(['address', 'uint256'], data)
15 |
16 | if (toBN(blockNumber).gt(toBN(foreignBlock.number))) {
17 | return [false, ASYNC_CALL_ERRORS.BLOCK_IS_IN_THE_FUTURE]
18 | }
19 |
20 | const balance = await web3.eth.getBalance(address, blockNumber)
21 |
22 | return [true, web3.eth.abi.encodeParameter('uint256', balance)]
23 | }
24 |
25 | module.exports = {
26 | 'eth_getBalance(address)': call,
27 | 'eth_getBalance(address,uint256)': callArchive
28 | }
29 |
--------------------------------------------------------------------------------
/oracle/src/events/processAMBInformationRequests/calls/ethGetBlockByHash.js:
--------------------------------------------------------------------------------
1 | const { ASYNC_CALL_ERRORS } = require('../../../utils/constants')
2 | const { serializeBlock } = require('./serializers')
3 |
4 | async function call(web3, data, foreignBlock) {
5 | const blockHash = web3.eth.abi.decodeParameter('bytes32', data)
6 |
7 | const block = await web3.eth.getBlock(blockHash)
8 |
9 | if (block === null || block.number > foreignBlock.number) {
10 | return [false, ASYNC_CALL_ERRORS.NOT_FOUND]
11 | }
12 |
13 | return [true, serializeBlock(web3, block)]
14 | }
15 |
16 | module.exports = {
17 | 'eth_getBlockByHash(bytes32)': call
18 | }
19 |
--------------------------------------------------------------------------------
/oracle/src/events/processAMBInformationRequests/calls/ethGetBlockByNumber.js:
--------------------------------------------------------------------------------
1 | const { toBN } = require('web3').utils
2 |
3 | const { ASYNC_CALL_ERRORS } = require('../../../utils/constants')
4 | const { serializeBlock } = require('./serializers')
5 |
6 | async function call(web3, data, foreignBlock) {
7 | const blockNumber = web3.eth.abi.decodeParameter('uint256', data)
8 |
9 | if (toBN(blockNumber).gt(toBN(foreignBlock.number))) {
10 | return [false, ASYNC_CALL_ERRORS.BLOCK_IS_IN_THE_FUTURE]
11 | }
12 |
13 | const block = await web3.eth.getBlock(blockNumber)
14 |
15 | return [true, serializeBlock(web3, block)]
16 | }
17 |
18 | module.exports = {
19 | 'eth_getBlockByNumber()': async (web3, _, block) => [true, serializeBlock(web3, block)],
20 | 'eth_getBlockByNumber(uint256)': call
21 | }
22 |
--------------------------------------------------------------------------------
/oracle/src/events/processAMBInformationRequests/calls/ethGetStorageAt.js:
--------------------------------------------------------------------------------
1 | const { toBN } = require('web3').utils
2 |
3 | const { ASYNC_CALL_ERRORS } = require('../../../utils/constants')
4 |
5 | async function call(web3, data, foreignBlock) {
6 | const { 0: address, 1: slot } = web3.eth.abi.decodeParameters(['address', 'bytes32'], data)
7 |
8 | const value = await web3.eth.getStorageAt(address, slot, foreignBlock.number)
9 |
10 | return [true, web3.eth.abi.encodeParameter('bytes32', value)]
11 | }
12 |
13 | async function callArchive(web3, data, foreignBlock) {
14 | const { 0: address, 1: slot, 2: blockNumber } = web3.eth.abi.decodeParameters(['address', 'bytes32', 'uint256'], data)
15 |
16 | if (toBN(blockNumber).gt(toBN(foreignBlock.number))) {
17 | return [false, ASYNC_CALL_ERRORS.BLOCK_IS_IN_THE_FUTURE]
18 | }
19 |
20 | const value = await web3.eth.getStorageAt(address, slot, blockNumber)
21 |
22 | return [true, web3.eth.abi.encodeParameter('bytes32', value)]
23 | }
24 |
25 | module.exports = {
26 | 'eth_getStorageAt(address,bytes32)': call,
27 | 'eth_getStorageAt(address,bytes32,uint256)': callArchive
28 | }
29 |
--------------------------------------------------------------------------------
/oracle/src/events/processAMBInformationRequests/calls/ethGetTransactionByHash.js:
--------------------------------------------------------------------------------
1 | const { ASYNC_CALL_ERRORS } = require('../../../utils/constants')
2 | const { serializeTx } = require('./serializers')
3 |
4 | async function call(web3, data, foreignBlock) {
5 | const hash = web3.eth.abi.decodeParameter('bytes32', data)
6 |
7 | const tx = await web3.eth.getTransaction(hash)
8 |
9 | if (tx === null || tx.blockNumber > foreignBlock.number) {
10 | return [false, ASYNC_CALL_ERRORS.NOT_FOUND]
11 | }
12 |
13 | return [true, serializeTx(web3, tx)]
14 | }
15 |
16 | module.exports = {
17 | 'eth_getTransactionByHash(bytes32)': call
18 | }
19 |
--------------------------------------------------------------------------------
/oracle/src/events/processAMBInformationRequests/calls/ethGetTransactionCount.js:
--------------------------------------------------------------------------------
1 | const { toBN } = require('web3').utils
2 |
3 | const { ASYNC_CALL_ERRORS } = require('../../../utils/constants')
4 |
5 | async function call(web3, data, foreignBlock) {
6 | const address = web3.eth.abi.decodeParameter('address', data)
7 |
8 | const nonce = await web3.eth.getTransactionCount(address, foreignBlock.number)
9 |
10 | return [true, web3.eth.abi.encodeParameter('uint256', nonce)]
11 | }
12 |
13 | async function callArchive(web3, data, foreignBlock) {
14 | const { 0: address, 1: blockNumber } = web3.eth.abi.decodeParameters(['address', 'uint256'], data)
15 |
16 | if (toBN(blockNumber).gt(toBN(foreignBlock.number))) {
17 | return [false, ASYNC_CALL_ERRORS.BLOCK_IS_IN_THE_FUTURE]
18 | }
19 |
20 | const nonce = await web3.eth.getTransactionCount(address, blockNumber)
21 |
22 | return [true, web3.eth.abi.encodeParameter('uint256', nonce)]
23 | }
24 |
25 | module.exports = {
26 | 'eth_getTransactionCount(address)': call,
27 | 'eth_getTransactionCount(address,uint256)': callArchive
28 | }
29 |
--------------------------------------------------------------------------------
/oracle/src/events/processAMBInformationRequests/calls/ethGetTransactionReceipt.js:
--------------------------------------------------------------------------------
1 | const { ASYNC_CALL_ERRORS } = require('../../../utils/constants')
2 | const { serializeReceipt } = require('./serializers')
3 |
4 | async function call(web3, data, foreignBlock) {
5 | const hash = web3.eth.abi.decodeParameter('bytes32', data)
6 |
7 | const receipt = await web3.eth.getTransactionReceipt(hash)
8 |
9 | if (receipt === null || receipt.blockNumber > foreignBlock.number) {
10 | return [false, ASYNC_CALL_ERRORS.NOT_FOUND]
11 | }
12 |
13 | return [true, serializeReceipt(web3, receipt)]
14 | }
15 |
16 | module.exports = {
17 | 'eth_getTransactionReceipt(bytes32)': call
18 | }
19 |
--------------------------------------------------------------------------------
/oracle/src/services/RedundantHttpListProvider.js:
--------------------------------------------------------------------------------
1 | const promiseRetry = require('promise-retry')
2 | const { promiseAny } = require('../utils/utils')
3 | const { defaultOptions, HttpListProviderError, send } = require('./HttpListProvider')
4 | const { onInjected } = require('./injectedLogger')
5 |
6 | function RedundantHttpListProvider(urls, options = {}) {
7 | if (!(this instanceof RedundantHttpListProvider)) {
8 | return new RedundantHttpListProvider(urls)
9 | }
10 |
11 | if (!urls || !urls.length) {
12 | throw new TypeError(`Invalid URLs: '${urls}'`)
13 | }
14 |
15 | this.urls = urls
16 | this.options = { ...defaultOptions, ...options }
17 | onInjected(logger => {
18 | this.logger = logger.child({ module: `RedundantHttpListProvider:${this.options.name}` })
19 | })
20 | }
21 |
22 | RedundantHttpListProvider.prototype.send = async function send(payload, callback) {
23 | try {
24 | const result = await promiseRetry(retry => {
25 | return trySend(payload, this.urls, this.options).catch(retry)
26 | }, this.options.retry)
27 | callback(null, result)
28 | } catch (e) {
29 | callback(e)
30 | }
31 | }
32 |
33 | async function trySend(payload, urls, options) {
34 | try {
35 | return await promiseAny(urls.map(url => send(url, payload, options)))
36 | } catch (errors) {
37 | throw new HttpListProviderError('Request failed for all urls', errors)
38 | }
39 | }
40 |
41 | module.exports = {
42 | RedundantHttpListProvider
43 | }
44 |
--------------------------------------------------------------------------------
/oracle/src/services/SafeEthLogsProvider.js:
--------------------------------------------------------------------------------
1 | const { hexToNumber, isHexStrict } = require('web3').utils
2 |
3 | function SafeEthLogsProvider(provider) {
4 | const oldSend = provider.send.bind(provider)
5 | const newSend = function(payload, callback) {
6 | if (payload.method === 'eth_getLogs' && isHexStrict(payload.params[0].toBlock)) {
7 | this.logger.debug('Modifying eth_getLogs request to include batch eth_blockNumber request')
8 |
9 | const newPayload = [payload, { jsonrpc: '2.0', id: payload.id + 1, method: 'eth_blockNumber', params: [] }]
10 | oldSend(newPayload, (err, res) => {
11 | if (err) {
12 | callback(err, null)
13 | } else {
14 | const rawLogs = res.find(({ id }) => id === payload.id)
15 | const rawBlockNumber = res.find(({ id }) => id === payload.id + 1)
16 | const blockNumber = hexToNumber(rawBlockNumber.result)
17 | const toBlock = hexToNumber(payload.params[0].toBlock)
18 |
19 | if (blockNumber < toBlock) {
20 | this.logger.warn({ toBlock, blockNumber }, 'Returned block number is less than the specified toBlock')
21 | callback(new Error('block number too low'), null)
22 | } else {
23 | callback(null, rawLogs)
24 | }
25 | }
26 | })
27 | } else {
28 | oldSend(payload, callback)
29 | }
30 | }
31 | provider.send = newSend.bind(provider)
32 | return provider
33 | }
34 |
35 | module.exports = {
36 | SafeEthLogsProvider
37 | }
38 |
--------------------------------------------------------------------------------
/oracle/src/services/injectedLogger.js:
--------------------------------------------------------------------------------
1 | // workaround to avoid circular dependencies in module imports
2 | // e.g. logger -> config -> web3 -> provider -> logger
3 | // transforms to the following import chain
4 | // logger -> config -> web3 -> provider -> injectedLogger
5 | // logger -> injectedLogger
6 |
7 | let logger
8 |
9 | const callbacks = []
10 |
11 | function onInjected(cb) {
12 | if (logger) {
13 | cb(logger)
14 | } else {
15 | callbacks.push(cb)
16 | }
17 | }
18 |
19 | function setLogger(newLogger) {
20 | logger = newLogger
21 | callbacks.forEach(cb => cb(logger))
22 | }
23 |
24 | module.exports = {
25 | onInjected,
26 | setLogger
27 | }
28 |
--------------------------------------------------------------------------------
/oracle/src/services/logger.js:
--------------------------------------------------------------------------------
1 | const pino = require('pino')
2 | const path = require('path')
3 |
4 | const { setLogger } = require('./injectedLogger')
5 |
6 | const config = process.env.NODE_ENV !== 'test' ? require(path.join('../../config/', process.argv[2])) : {}
7 |
8 | const logger = pino({
9 | enabled: process.env.NODE_ENV !== 'test',
10 | name: config.name,
11 | level: process.env.ORACLE_LOG_LEVEL || 'debug',
12 | base: {
13 | validator: config.validatorAddress
14 | }
15 | })
16 |
17 | setLogger(logger)
18 |
19 | module.exports = logger
20 |
--------------------------------------------------------------------------------
/oracle/src/services/redisClient.js:
--------------------------------------------------------------------------------
1 | const Redis = require('ioredis')
2 | const logger = require('./logger')
3 |
4 | const redis = new Redis(process.env.ORACLE_REDIS_URL)
5 |
6 | redis.on('connect', () => {
7 | logger.info('Connected to redis')
8 | })
9 |
10 | redis.on('error', () => {
11 | logger.error('Disconnected from redis')
12 | })
13 |
14 | module.exports = {
15 | redis
16 | }
17 |
--------------------------------------------------------------------------------
/oracle/src/services/shutdownState.js:
--------------------------------------------------------------------------------
1 | const { redis } = require('./redisClient')
2 |
3 | let isShutdown = false
4 | async function getShutdownFlag(logger, shutdownKey, force = false) {
5 | if (force) {
6 | logger.debug('Reading current shutdown state from the DB')
7 | isShutdown = (await redis.get(shutdownKey)) === 'true'
8 | logger.debug({ isShutdown }, 'Read shutdown state from the DB')
9 | }
10 | return isShutdown
11 | }
12 |
13 | async function setShutdownFlag(logger, shutdownKey, value) {
14 | logger.info({ isShutdown: value }, 'Updating current shutdown state in the DB')
15 | isShutdown = value
16 | await redis.set(shutdownKey, value)
17 | logger.debug('Updated state in the DB')
18 | }
19 |
20 | module.exports = {
21 | getShutdownFlag,
22 | setShutdownFlag
23 | }
24 |
--------------------------------------------------------------------------------
/oracle/src/tx/sendTx.js:
--------------------------------------------------------------------------------
1 | async function sendTx(opts) {
2 | const { privateKey, data, nonce, gasPrice, gasPriceOptions, value, gasLimit, to, chainId, web3, mevOptions } = opts
3 | const gasOpts = gasPriceOptions || { gasPrice }
4 | const serializedTx = await web3.eth.accounts.signTransaction(
5 | {
6 | nonce: Number(nonce),
7 | chainId,
8 | to,
9 | data,
10 | value,
11 | gas: gasLimit,
12 | ...gasOpts
13 | },
14 | privateKey
15 | )
16 |
17 | if (!mevOptions) {
18 | return new Promise((res, rej) =>
19 | web3.eth
20 | .sendSignedTransaction(serializedTx.rawTransaction)
21 | .once('transactionHash', res)
22 | .once('error', rej)
23 | )
24 | }
25 |
26 | mevOptions.logger.debug(
27 | { rawTx: serializedTx.rawTransaction, txHash: serializedTx.transactionHash },
28 | 'Signed MEV helper transaction'
29 | )
30 |
31 | for (let blockNumber = mevOptions.fromBlock; blockNumber <= mevOptions.toBlock; blockNumber++) {
32 | mevOptions.logger.debug({ txHash: serializedTx.transactionHash, blockNumber }, 'Sending MEV bundle transaction')
33 | await mevOptions.provider.sendRawBundle([serializedTx.rawTransaction], blockNumber)
34 | }
35 | return Promise.resolve(serializedTx.transactionHash)
36 | }
37 |
38 | module.exports = {
39 | sendTx
40 | }
41 |
--------------------------------------------------------------------------------
/oracle/src/utils/errors.js:
--------------------------------------------------------------------------------
1 | class AlreadyProcessedError extends Error {}
2 | class AlreadySignedError extends Error {}
3 | class IncompatibleContractError extends Error {}
4 | class InvalidValidatorError extends Error {}
5 |
6 | module.exports = {
7 | AlreadyProcessedError,
8 | AlreadySignedError,
9 | IncompatibleContractError,
10 | InvalidValidatorError
11 | }
12 |
--------------------------------------------------------------------------------
/oracle/src/utils/mev.js:
--------------------------------------------------------------------------------
1 | const MEV_HELPER_ABI = [
2 | {
3 | constant: false,
4 | inputs: [
5 | {
6 | name: '_data',
7 | type: 'bytes'
8 | }
9 | ],
10 | name: 'execute',
11 | outputs: [],
12 | payable: false,
13 | stateMutability: 'nonpayable',
14 | type: 'function'
15 | },
16 | {
17 | constant: false,
18 | inputs: [
19 | {
20 | name: '_gasPrice',
21 | type: 'uint256'
22 | },
23 | {
24 | name: '_data',
25 | type: 'bytes'
26 | }
27 | ],
28 | name: 'estimateProfit',
29 | outputs: [
30 | {
31 | name: '',
32 | type: 'uint256'
33 | }
34 | ],
35 | payable: true,
36 | stateMutability: 'nonpayable',
37 | type: 'function'
38 | }
39 | ]
40 |
41 | module.exports = {
42 | MEV_HELPER_ABI
43 | }
44 |
--------------------------------------------------------------------------------
/oracle/src/utils/tokenState.js:
--------------------------------------------------------------------------------
1 | async function getTokensState(bridgeContract, logger) {
2 | const context = {}
3 | try {
4 | logger.debug('Getting bridgeable token address')
5 | context.bridgeableTokenAddress = await bridgeContract.methods.erc20token().call()
6 | logger.debug({ address: context.bridgeableTokenAddress }, 'Token address obtained')
7 | } catch (e) {
8 | throw new Error(`Bridgeable token address cannot be obtained`)
9 | }
10 |
11 | return context
12 | }
13 |
14 | module.exports = {
15 | getTokensState
16 | }
17 |
--------------------------------------------------------------------------------
/oracle/src/utils/tryEach.js:
--------------------------------------------------------------------------------
1 | module.exports = async (array, f) => {
2 | const errors = []
3 |
4 | for (let i = 0; i < array.length; i++) {
5 | try {
6 | const res = await f(array[i])
7 | return [res, i]
8 | } catch (e) {
9 | errors.push(e)
10 | }
11 | }
12 |
13 | return Promise.reject(errors)
14 | }
15 |
--------------------------------------------------------------------------------
/oracle/test/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../.eslintrc",
3 | "globals": {
4 | "describe": false,
5 | "it": false,
6 | "beforeEach": false,
7 | "afterEach": false
8 | },
9 | "rules": {
10 | "node/no-unpublished-require": "off"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/oracle/test/test.env:
--------------------------------------------------------------------------------
1 | COMMON_HOME_RPC_URL=http://example.com
2 | COMMON_FOREIGN_RPC_URL=http://example.com
3 | ORACLE_QUEUE_URL=http://example.com
4 |
--------------------------------------------------------------------------------
/parity/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM parity/parity:v2.3.3
2 |
3 | WORKDIR /stuff
4 |
5 | COPY . .
6 |
7 | CMD ["--chain", "chain.json", "--network-id", "77", "--jsonrpc-apis", "all", "--jsonrpc-interface", "all", "--jsonrpc-cors", "all", "--jsonrpc-hosts", "all"]
8 |
--------------------------------------------------------------------------------
/parity/Dockerfile-foreign:
--------------------------------------------------------------------------------
1 | FROM parity/parity:v2.3.3
2 |
3 | WORKDIR /stuff
4 |
5 | COPY . .
6 |
7 | CMD ["--chain", "chain-foreign.json", "--network-id", "42", "--jsonrpc-apis", "all", "--jsonrpc-interface", "all", "--jsonrpc-cors", "all", "--jsonrpc-hosts", "all"]
8 |
--------------------------------------------------------------------------------
/parity/foreign_mocks/cDAIMock.sol:
--------------------------------------------------------------------------------
1 | pragma solidity 0.4.24;
2 |
3 | interface IERC20 {
4 | function transferFrom(address from,address to,uint256 value) external;
5 | function transfer(address to,uint256 value) external;
6 | }
7 |
8 | contract cDaiMock {
9 | IERC20 daiToken;
10 |
11 | event Transfer(address indexed from, address indexed to, uint amount);
12 | event Mint(address minter, uint mintAmount, uint mintTokens);
13 | event Redeem(address redeemer, uint redeemAmount, uint redeemTokens);
14 |
15 |
16 | function mint(uint256 mintAmount) external returns (uint256) {
17 | daiToken.transferFrom(msg.sender, address(this), mintAmount);
18 |
19 | emit Mint(msg.sender, mintAmount, mintAmount);
20 | emit Transfer(address(this), msg.sender, mintAmount);
21 |
22 | return 0;
23 | }
24 |
25 | function redeemUnderlying(uint256 redeemAmount) external returns (uint256) {
26 | daiToken.transfer(msg.sender, redeemAmount);
27 |
28 | emit Transfer(msg.sender, address(this), redeemAmount);
29 | emit Redeem(msg.sender, redeemAmount, redeemAmount);
30 |
31 | return 0;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------