Compare commits
25 Commits
2.1.0
...
oracle-ser
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
322729ae82 | ||
|
|
636f053c48 | ||
|
|
80841a76a6 | ||
|
|
994562a8b9 | ||
|
|
b86090a5a0 | ||
|
|
a07cecccc2 | ||
|
|
8556e7aec5 | ||
|
|
441224c1f0 | ||
|
|
db11aa6444 | ||
|
|
4db62d721d | ||
|
|
8d6acd0339 | ||
|
|
c013cc7378 | ||
|
|
d5e7e06788 | ||
|
|
d6e39f34af | ||
|
|
3b368ce644 | ||
|
|
c1d58c2908 | ||
|
|
d17e9e0eea | ||
|
|
a2c678d0a2 | ||
|
|
4bd3576691 | ||
|
|
d3576f5a79 | ||
|
|
62f9a080c9 | ||
|
|
10f67168a7 | ||
|
|
f90f888ae4 | ||
|
|
84508e2b84 | ||
|
|
2369e876aa |
@@ -51,28 +51,25 @@ orbs:
|
||||
paths:
|
||||
- ~/.cache/yarn
|
||||
wait-for-oracle:
|
||||
parameters:
|
||||
redis-key:
|
||||
type: string
|
||||
steps:
|
||||
- run:
|
||||
name: Install redis tools
|
||||
command: sudo apt-get install -y redis-tools
|
||||
- run:
|
||||
name: Wait for the Oracle to start
|
||||
command: |
|
||||
set +e
|
||||
i=0
|
||||
while [[ $(redis-cli GET << parameters.redis-key >> ) ]]; do
|
||||
((i++))
|
||||
if [ "$i" -gt 30 ]
|
||||
then
|
||||
exit -1
|
||||
while :
|
||||
do
|
||||
(echo > /dev/tcp/127.0.0.1/6379) >/dev/null 2>&1
|
||||
if [[ $? -eq 0 ]]; then
|
||||
break
|
||||
fi
|
||||
((i++))
|
||||
if [ "$i" -gt 30 ]; then
|
||||
echo "Redis has not open the port"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Sleeping..."
|
||||
sleep 3
|
||||
done
|
||||
done
|
||||
executors:
|
||||
docker-node:
|
||||
docker:
|
||||
@@ -225,9 +222,6 @@ jobs:
|
||||
scenario-name:
|
||||
description: "Molecule scenario name used to create the infrastructure"
|
||||
type: string
|
||||
redis-key:
|
||||
description: "Redis key checked for non-emptiness to assert if Oracle is running"
|
||||
type: string
|
||||
ui-e2e-grep:
|
||||
description: "Mocha grep string used to run ui-e2e tests specific to given type of bridge"
|
||||
default: ''
|
||||
@@ -247,8 +241,7 @@ jobs:
|
||||
name: Prepare the infrastructure
|
||||
command: e2e-commons/up.sh deploy << parameters.scenario-name >> blocks
|
||||
no_output_timeout: 50m
|
||||
- tokenbridge-orb/wait-for-oracle:
|
||||
redis-key: << parameters.redis-key >>
|
||||
- tokenbridge-orb/wait-for-oracle
|
||||
- when:
|
||||
condition: << parameters.ui-e2e-grep >>
|
||||
steps:
|
||||
@@ -297,20 +290,20 @@ workflows:
|
||||
- ultimate:
|
||||
name: "ultimate: native to erc"
|
||||
scenario-name: native-to-erc
|
||||
redis-key: native-erc-collected-signatures:lastProcessedBlock
|
||||
ui-e2e-grep: "NATIVE TO ERC"
|
||||
- ultimate:
|
||||
name: "ultimate: erc to native"
|
||||
scenario-name: erc-to-native
|
||||
redis-key: erc-native-collected-signatures:lastProcessedBlock
|
||||
ui-e2e-grep: "ERC TO NATIVE"
|
||||
- ultimate:
|
||||
name: "ultimate: erc to erc"
|
||||
scenario-name: erc-to-erc
|
||||
redis-key: erc-erc-collected-signatures:lastProcessedBlock
|
||||
ui-e2e-grep: "ERC TO ERC"
|
||||
- ultimate:
|
||||
name: "ultimate: amb"
|
||||
scenario-name: amb
|
||||
redis-key: amb-collected-signatures:lastProcessedBlock
|
||||
oracle-e2e-script: "amb"
|
||||
- ultimate:
|
||||
name: "ultimate: amb stake erc to erc"
|
||||
scenario-name: ultimate-amb-stake-erc-to-erc
|
||||
ui-e2e-grep: "AMB-STAKE-ERC-TO-ERC"
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
**/*.md
|
||||
|
||||
contracts/test
|
||||
contracts/build
|
||||
oracle/test
|
||||
oracle/**/*.png
|
||||
oracle/**/*.jpg
|
||||
audit
|
||||
|
||||
1
.gitignore
vendored
@@ -49,4 +49,5 @@ __pycache__
|
||||
|
||||
#monitor
|
||||
monitor/responses/*
|
||||
monitor/configs/*.env
|
||||
!monitor/.gitkeep
|
||||
|
||||
@@ -43,6 +43,7 @@ ORACLE_VALIDATOR_ADDRESS | The public address of the bridge validator | hexideci
|
||||
name | description | value
|
||||
--- | --- | ---
|
||||
UI_TITLE | The title for the bridge UI page. `%c` will be replaced by the name of the network. | string
|
||||
UI_OG_TITLE | The meta title for the deployed bridge page. | string
|
||||
UI_DESCRIPTION | The meta description for the deployed bridge page. | string
|
||||
UI_NATIVE_TOKEN_DISPLAY_NAME | name of the home native coin | string
|
||||
UI_HOME_NETWORK_DISPLAY_NAME | name to be displayed for home network | string
|
||||
@@ -56,7 +57,8 @@ UI_FOREIGN_EXPLORER_ADDRESS_TEMPLATE | template link to address on foreign explo
|
||||
UI_HOME_GAS_PRICE_UPDATE_INTERVAL | An interval in milliseconds used to get the updated gas price value either from the oracle or from the Home Bridge contract. | integer
|
||||
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL | An interval in milliseconds used to get the updated gas price value either from the oracle or from the Foreign Bridge contract. | integer
|
||||
UI_PORT | The port for the UI app. | integer
|
||||
UI_STYLES | The set of styles to render the bridge UI page. Currently only `classic` is implemented | classic
|
||||
UI_STYLES | The set of styles to render the bridge UI page. | core/classic/stake
|
||||
UI_PUBLIC_URL | The public url for the deployed bridge page | string
|
||||
|
||||
|
||||
## Monitor configuration
|
||||
|
||||
@@ -7,13 +7,17 @@ const FOREIGN_ERC_TO_NATIVE_ABI = require('../contracts/build/contracts/ForeignB
|
||||
const ERC20_ABI = require('../contracts/build/contracts/ERC20').abi
|
||||
const ERC677_ABI = require('../contracts/build/contracts/ERC677').abi
|
||||
const ERC677_BRIDGE_TOKEN_ABI = require('../contracts/build/contracts/ERC677BridgeToken').abi
|
||||
const BLOCK_REWARD_ABI = require('../contracts/build/contracts/IBlockReward').abi
|
||||
const BLOCK_REWARD_ABI = require('../contracts/build/contracts/BlockReward').abi
|
||||
const BRIDGE_VALIDATORS_ABI = require('../contracts/build/contracts/BridgeValidators').abi
|
||||
const REWARDABLE_VALIDATORS_ABI = require('../contracts/build/contracts/RewardableValidators').abi
|
||||
const HOME_AMB_ABI = require('../contracts/build/contracts/HomeAMB').abi
|
||||
const FOREIGN_AMB_ABI = require('../contracts/build/contracts/ForeignAMB').abi
|
||||
const BOX_ABI = require('../contracts/build/contracts/Box').abi
|
||||
const SAI_TOP = require('../contracts/build/contracts/SaiTopMock').abi
|
||||
const HOME_AMB_ERC_TO_ERC_ABI = require('../contracts/build/contracts/HomeAMBErc677ToErc677').abi
|
||||
const FOREIGN_AMB_ERC_TO_ERC_ABI = require('../contracts/build/contracts/ForeignAMBErc677ToErc677').abi
|
||||
const HOME_STAKE_ERC_TO_ERC_ABI = require('../contracts/build/contracts/HomeStakeTokenMediator').abi
|
||||
const FOREIGN_STAKE_ERC_TO_ERC_ABI = require('../contracts/build/contracts/ForeignStakeTokenMediator').abi
|
||||
|
||||
const { HOME_V1_ABI, FOREIGN_V1_ABI } = require('./v1Abis')
|
||||
const { BRIDGE_MODES } = require('./constants')
|
||||
@@ -67,6 +71,12 @@ function getBridgeABIs(bridgeMode) {
|
||||
} else if (bridgeMode === BRIDGE_MODES.ARBITRARY_MESSAGE) {
|
||||
HOME_ABI = HOME_AMB_ABI
|
||||
FOREIGN_ABI = FOREIGN_AMB_ABI
|
||||
} else if (bridgeMode === BRIDGE_MODES.AMB_ERC_TO_ERC) {
|
||||
HOME_ABI = HOME_AMB_ERC_TO_ERC_ABI
|
||||
FOREIGN_ABI = FOREIGN_AMB_ERC_TO_ERC_ABI
|
||||
} else if (bridgeMode === BRIDGE_MODES.STAKE_AMB_ERC_TO_ERC) {
|
||||
HOME_ABI = HOME_STAKE_ERC_TO_ERC_ABI
|
||||
FOREIGN_ABI = FOREIGN_STAKE_ERC_TO_ERC_ABI
|
||||
} else {
|
||||
throw new Error(`Unrecognized bridge mode: ${bridgeMode}`)
|
||||
}
|
||||
@@ -94,5 +104,7 @@ module.exports = {
|
||||
HOME_AMB_ABI,
|
||||
FOREIGN_AMB_ABI,
|
||||
BOX_ABI,
|
||||
SAI_TOP
|
||||
SAI_TOP,
|
||||
HOME_STAKE_ERC_TO_ERC_ABI,
|
||||
FOREIGN_STAKE_ERC_TO_ERC_ABI
|
||||
}
|
||||
|
||||
@@ -3,7 +3,9 @@ const BRIDGE_MODES = {
|
||||
ERC_TO_ERC: 'ERC_TO_ERC',
|
||||
ERC_TO_NATIVE: 'ERC_TO_NATIVE',
|
||||
NATIVE_TO_ERC_V1: 'NATIVE_TO_ERC_V1',
|
||||
ARBITRARY_MESSAGE: 'ARBITRARY_MESSAGE'
|
||||
ARBITRARY_MESSAGE: 'ARBITRARY_MESSAGE',
|
||||
AMB_ERC_TO_ERC: 'AMB_ERC_TO_ERC',
|
||||
STAKE_AMB_ERC_TO_ERC: 'STAKE_AMB_ERC_TO_ERC'
|
||||
}
|
||||
|
||||
const ERC_TYPES = {
|
||||
@@ -14,6 +16,7 @@ const ERC_TYPES = {
|
||||
const FEE_MANAGER_MODE = {
|
||||
ONE_DIRECTION: 'ONE_DIRECTION',
|
||||
BOTH_DIRECTIONS: 'BOTH_DIRECTIONS',
|
||||
ONE_DIRECTION_STAKE: 'ONE_DIRECTION_STAKE',
|
||||
UNDEFINED: 'UNDEFINED'
|
||||
}
|
||||
|
||||
|
||||
@@ -9,14 +9,14 @@ function addTxHashToData({ encodedData, transactionHash }) {
|
||||
function parseAMBMessage(message) {
|
||||
message = strip0x(message)
|
||||
|
||||
const txHash = `0x${message.slice(0, 64)}`
|
||||
const messageId = `0x${message.slice(0, 64)}`
|
||||
const sender = `0x${message.slice(64, 104)}`
|
||||
const executor = `0x${message.slice(104, 144)}`
|
||||
|
||||
return {
|
||||
sender,
|
||||
executor,
|
||||
txHash
|
||||
messageId
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ const { BRIDGE_MODES, ERC_TYPES } = require('../constants')
|
||||
|
||||
describe('constants', () => {
|
||||
it('should contain correct number of bridge types', () => {
|
||||
expect(Object.keys(BRIDGE_MODES).length).to.be.equal(5)
|
||||
expect(Object.keys(BRIDGE_MODES).length).to.be.equal(7)
|
||||
})
|
||||
|
||||
it('should contain correct number of erc types', () => {
|
||||
|
||||
@@ -61,4 +61,99 @@ describe('getTokenType', () => {
|
||||
// Then
|
||||
expect(type).to.equal(ERC_TYPES.ERC20)
|
||||
})
|
||||
|
||||
it('should return ERC20 if bridgeContract and isBridge are not present', async () => {
|
||||
// Given
|
||||
const bridgeAddress = '0xCecBE80Ed3548dE11D7d2D922a36576eA40C4c26'
|
||||
const contract = {
|
||||
methods: {
|
||||
bridgeContract: () => {
|
||||
return {
|
||||
call: () => Promise.reject()
|
||||
}
|
||||
},
|
||||
isBridge: () => {
|
||||
return {
|
||||
call: () => Promise.reject()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// When
|
||||
const type = await getTokenType(contract, bridgeAddress)
|
||||
|
||||
// Then
|
||||
expect(type).to.equal(ERC_TYPES.ERC20)
|
||||
})
|
||||
|
||||
it('should return ERC677 if isBridge returns true', async () => {
|
||||
// Given
|
||||
const bridgeAddress = '0xCecBE80Ed3548dE11D7d2D922a36576eA40C4c26'
|
||||
const contract = {
|
||||
methods: {
|
||||
bridgeContract: () => {
|
||||
return {
|
||||
call: () => Promise.reject()
|
||||
}
|
||||
},
|
||||
isBridge: () => {
|
||||
return {
|
||||
call: () => Promise.resolve(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// When
|
||||
const type = await getTokenType(contract, bridgeAddress)
|
||||
|
||||
// Then
|
||||
expect(type).to.equal(ERC_TYPES.ERC677)
|
||||
})
|
||||
|
||||
it('should return ERC677 if isBridge returns true and bridgeContract not present', async () => {
|
||||
// Given
|
||||
const bridgeAddress = '0xCecBE80Ed3548dE11D7d2D922a36576eA40C4c26'
|
||||
const contract = {
|
||||
methods: {
|
||||
isBridge: () => {
|
||||
return {
|
||||
call: () => Promise.resolve(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// When
|
||||
const type = await getTokenType(contract, bridgeAddress)
|
||||
|
||||
// Then
|
||||
expect(type).to.equal(ERC_TYPES.ERC677)
|
||||
})
|
||||
|
||||
it('should return ERC20 if isBridge returns false', async () => {
|
||||
// Given
|
||||
const bridgeAddress = '0xCecBE80Ed3548dE11D7d2D922a36576eA40C4c26'
|
||||
const contract = {
|
||||
methods: {
|
||||
bridgeContract: () => {
|
||||
return {
|
||||
call: () => Promise.reject()
|
||||
}
|
||||
},
|
||||
isBridge: () => {
|
||||
return {
|
||||
call: () => Promise.resolve(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// When
|
||||
const type = await getTokenType(contract, bridgeAddress)
|
||||
|
||||
// Then
|
||||
expect(type).to.equal(ERC_TYPES.ERC20)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -50,20 +50,20 @@ describe('parseAMBMessage', () => {
|
||||
it('should parse data type 00', () => {
|
||||
const msgSender = '0x003667154bb32e42bb9e1e6532f19d187fa0082e'
|
||||
const msgExecutor = '0xf4bef13f9f4f2b203faf0c3cbbaabe1afe056955'
|
||||
const msgTxHash = '0xbdceda9d8c94838aca10c687da1411a07b1390e88239c0638cb9cc264219cc10'
|
||||
const msgId = '0xbdceda9d8c94838aca10c687da1411a07b1390e88239c0638cb9cc264219cc10'
|
||||
const msgGasLimit = '000000000000000000000000000000000000000000000000000000005b877705'
|
||||
const msgDataType = '00'
|
||||
const msgData = '0xb1591967aed668a4b27645ff40c444892d91bf5951b382995d4d4f6ee3a2ce03'
|
||||
const message = `0x${strip0x(msgTxHash)}${strip0x(msgSender)}${strip0x(
|
||||
const message = `0x${strip0x(msgId)}${strip0x(msgSender)}${strip0x(
|
||||
msgExecutor
|
||||
)}${msgGasLimit}${msgDataType}${strip0x(msgData)}`
|
||||
|
||||
// when
|
||||
const { sender, executor, txHash } = parseAMBMessage(message)
|
||||
const { sender, executor, messageId } = parseAMBMessage(message)
|
||||
|
||||
// then
|
||||
expect(sender).to.be.equal(msgSender)
|
||||
expect(executor).to.be.equal(msgExecutor)
|
||||
expect(txHash).to.be.equal(msgTxHash)
|
||||
expect(messageId).to.be.equal(msgId)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -12,6 +12,10 @@ function decodeBridgeMode(bridgeModeHash) {
|
||||
return BRIDGE_MODES.ERC_TO_NATIVE
|
||||
case '0x2544fbb9':
|
||||
return BRIDGE_MODES.ARBITRARY_MESSAGE
|
||||
case '0x16ea01e9':
|
||||
return BRIDGE_MODES.STAKE_AMB_ERC_TO_ERC
|
||||
case '0x76595b56':
|
||||
return BRIDGE_MODES.AMB_ERC_TO_ERC
|
||||
default:
|
||||
throw new Error(`Unrecognized bridge mode hash: '${bridgeModeHash}'`)
|
||||
}
|
||||
@@ -46,10 +50,31 @@ const getTokenType = async (bridgeTokenContract, bridgeAddress) => {
|
||||
return ERC_TYPES.ERC20
|
||||
}
|
||||
} catch (e) {
|
||||
return ERC_TYPES.ERC20
|
||||
try {
|
||||
const isBridge = await bridgeTokenContract.methods.isBridge(bridgeAddress).call()
|
||||
if (isBridge) {
|
||||
return ERC_TYPES.ERC677
|
||||
} else {
|
||||
return ERC_TYPES.ERC20
|
||||
}
|
||||
} catch (e) {
|
||||
return ERC_TYPES.ERC20
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const isErcToErcMode = bridgeMode => {
|
||||
return (
|
||||
bridgeMode === BRIDGE_MODES.ERC_TO_ERC ||
|
||||
bridgeMode === BRIDGE_MODES.AMB_ERC_TO_ERC ||
|
||||
bridgeMode === BRIDGE_MODES.STAKE_AMB_ERC_TO_ERC
|
||||
)
|
||||
}
|
||||
|
||||
const isMediatorMode = bridgeMode => {
|
||||
return bridgeMode === BRIDGE_MODES.AMB_ERC_TO_ERC || bridgeMode === BRIDGE_MODES.STAKE_AMB_ERC_TO_ERC
|
||||
}
|
||||
|
||||
const getUnit = bridgeMode => {
|
||||
let unitHome = null
|
||||
let unitForeign = null
|
||||
@@ -62,6 +87,9 @@ const getUnit = bridgeMode => {
|
||||
} else if (bridgeMode === BRIDGE_MODES.ERC_TO_NATIVE) {
|
||||
unitHome = 'Native coins'
|
||||
unitForeign = 'Tokens'
|
||||
} else if (bridgeMode === BRIDGE_MODES.STAKE_AMB_ERC_TO_ERC) {
|
||||
unitHome = 'Tokens'
|
||||
unitForeign = 'Tokens'
|
||||
} else {
|
||||
throw new Error(`Unrecognized bridge mode: ${bridgeMode}`)
|
||||
}
|
||||
@@ -260,5 +288,7 @@ module.exports = {
|
||||
normalizeGasPrice,
|
||||
gasPriceFromSupplier,
|
||||
gasPriceFromContract,
|
||||
gasPriceWithinLimits
|
||||
gasPriceWithinLimits,
|
||||
isErcToErcMode,
|
||||
isMediatorMode
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# Molecule managed
|
||||
|
||||
{% if item.registry is defined %}
|
||||
FROM {{ item.registry.url }}/{{ item.image }}
|
||||
{% else %}
|
||||
FROM {{ item.image }}
|
||||
{% endif %}
|
||||
|
||||
RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \
|
||||
elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash && dnf clean all; \
|
||||
elif [ $(command -v yum) ]; then yum makecache fast && yum install -y python sudo yum-plugin-ovl bash && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \
|
||||
elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml && zypper clean -a; \
|
||||
elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates; \
|
||||
elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates && xbps-remove -O; fi
|
||||
@@ -0,0 +1,54 @@
|
||||
---
|
||||
driver:
|
||||
name: docker
|
||||
platforms:
|
||||
- name: oracle-amb-host
|
||||
groups:
|
||||
- ultimate
|
||||
- amb
|
||||
children:
|
||||
- oracle
|
||||
image: ubuntu:16.04
|
||||
privileged: true
|
||||
network_mode: host
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- name: ui-amb-stake-erc-to-erc-host
|
||||
groups:
|
||||
- ultimate
|
||||
- amb-stake-erc-to-erc
|
||||
children:
|
||||
- ui
|
||||
image: ubuntu:16.04
|
||||
privileged: true
|
||||
network_mode: host
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
provisioner:
|
||||
name: ansible
|
||||
playbooks:
|
||||
prepare: ../prepare.yml
|
||||
converge: ../ultimate-commons/converge.yml
|
||||
inventory:
|
||||
host_vars:
|
||||
oracle-amb-host:
|
||||
COMMON_HOME_RPC_URL: "http://parity1:8545"
|
||||
COMMON_FOREIGN_RPC_URL: "http://parity2:8545"
|
||||
ORACLE_VALIDATOR_ADDRESS: "0xaaB52d66283F7A1D5978bcFcB55721ACB467384b"
|
||||
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
|
||||
ui-amb-stake-erc-to-erc-host:
|
||||
COMMON_HOME_RPC_URL: "http://localhost:8541"
|
||||
COMMON_FOREIGN_RPC_URL: "http://localhost:8542"
|
||||
verifier:
|
||||
name: testinfra
|
||||
lint:
|
||||
name: flake8
|
||||
scenario:
|
||||
name: ultimate-amb-stake-erc-to-erc
|
||||
test_sequence:
|
||||
- cleanup
|
||||
- destroy
|
||||
- syntax
|
||||
- create
|
||||
- prepare
|
||||
- converge
|
||||
@@ -24,3 +24,10 @@
|
||||
copy:
|
||||
content: "{{ docker_compose_parsed | to_yaml }}"
|
||||
dest: "/home/poadocker/bridge/oracle/{{ file }}.yml"
|
||||
|
||||
- name: Get updated docker file
|
||||
shell: cat "/home/poadocker/bridge/oracle/{{ file }}.yml"
|
||||
register: catout
|
||||
|
||||
- debug: var=catout.stdout_lines
|
||||
|
||||
|
||||
@@ -3,9 +3,30 @@
|
||||
hosts: oracle
|
||||
become: true
|
||||
tasks:
|
||||
- name: get statuses for docker containers
|
||||
shell: docker ps -a
|
||||
register: docker1out
|
||||
|
||||
- debug: var=docker1out.stdout_lines
|
||||
|
||||
- name: get status for poabridge
|
||||
shell: /etc/init.d/poabridge status
|
||||
register: serviceout
|
||||
|
||||
- debug: var=serviceout.stdout_lines
|
||||
|
||||
- name: stop the service
|
||||
shell: service poabridge stop
|
||||
|
||||
- name: force to stop redis and rabit
|
||||
shell: docker rm -f oracle_rabbit_1 oracle_redis_1 || true
|
||||
|
||||
- name: get statuses for docker containers
|
||||
shell: docker ps -a
|
||||
register: docker2out
|
||||
|
||||
- debug: var=docker2out.stdout_lines
|
||||
|
||||
- name: Build current oracle image
|
||||
shell: docker build -t oracle:ultimate-testing --file oracle/Dockerfile .
|
||||
delegate_to: 127.0.0.1
|
||||
@@ -32,4 +53,14 @@
|
||||
loop_var: file
|
||||
|
||||
- name: start the service
|
||||
shell: service poabridge start
|
||||
#shell: service poabridge start
|
||||
shell: /etc/init.d/poabridge start
|
||||
register: startout
|
||||
|
||||
- debug: var=startout.stdout_lines
|
||||
|
||||
- name: get statuses for docker containers
|
||||
shell: docker ps -a
|
||||
register: docker3out
|
||||
|
||||
- debug: var=docker3out.stdout_lines
|
||||
|
||||
4
deployment/group_vars/amb-stake-erc-to-erc.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
COMMON_HOME_BRIDGE_ADDRESS: "0xc26Aa60Ff574f157616D3aEE70e08aAC129E1dFC"
|
||||
COMMON_FOREIGN_BRIDGE_ADDRESS: "0xc26Aa60Ff574f157616D3aEE70e08aAC129E1dFC"
|
||||
UI_PORT: 3003
|
||||
@@ -32,6 +32,7 @@ COMMON_FOREIGN_GAS_PRICE_FACTOR: 1
|
||||
|
||||
## UI
|
||||
UI_TITLE: "TokenBridge UI app - %c"
|
||||
UI_OG_TITLE: "POA Bridge UI"
|
||||
UI_DESCRIPTION: "The TokenBridge serves as a method of transferring MakerDAO stable tokens between the Ethereum network to xDai chain in a quick and cost-efficient manner."
|
||||
UI_PORT: 3001
|
||||
UI_HOME_EXPLORER_TX_TEMPLATE: https://blockscout.com/poa/dai/tx/%s
|
||||
@@ -40,6 +41,8 @@ UI_HOME_EXPLORER_ADDRESS_TEMPLATE: https://blockscout.com/poa/dai/address/%s
|
||||
UI_FOREIGN_EXPLORER_ADDRESS_TEMPLATE: https://blockscout.com/eth/mainnet/address/%s
|
||||
UI_HOME_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
UI_STYLES: "core"
|
||||
UI_PUBLIC_URL: "https://dai-bridge.poa.network"
|
||||
|
||||
## Monitor
|
||||
MONITOR_BRIDGE_NAME: "xdai"
|
||||
|
||||
@@ -34,6 +34,7 @@ ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
|
||||
## UI
|
||||
UI_TITLE: "TokenBridge UI app - %c"
|
||||
UI_OG_TITLE: "POA Bridge UI"
|
||||
UI_DESCRIPTION: "The POA cross-chain bridge serves as a method of transferring POA native tokens from the POA Network to the Ethereum network in a quick and cost-efficient manner."
|
||||
UI_PORT: 3001
|
||||
UI_HOME_EXPLORER_TX_TEMPLATE: https://blockscout.com/poa/sokol/tx/%s
|
||||
@@ -42,6 +43,8 @@ UI_HOME_EXPLORER_ADDRESS_TEMPLATE: https://blockscout.com/poa/sokol/address/%s
|
||||
UI_FOREIGN_EXPLORER_ADDRESS_TEMPLATE: https://blockscout.com/eth/kovan/address/%s
|
||||
UI_HOME_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
UI_STYLES: "core"
|
||||
UI_PUBLIC_URL: "http://localhost:3001"
|
||||
|
||||
## Monitor
|
||||
MONITOR_BRIDGE_NAME: "bridge"
|
||||
|
||||
@@ -33,6 +33,7 @@ ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
|
||||
#ui
|
||||
UI_TITLE: "TokenBridge UI app - %c"
|
||||
UI_OG_TITLE: "POA Bridge UI"
|
||||
UI_DESCRIPTION: "The POA cross-chain bridge serves as a method of transferring POA native tokens from the POA Network to the Ethereum network in a quick and cost-efficient manner."
|
||||
UI_HOME_EXPLORER_TX_TEMPLATE: https://blockscout.com/poa/sokol/tx/%s
|
||||
UI_FOREIGN_EXPLORER_TX_TEMPLATE: https://blockscout.com/eth/kovan/tx/%s
|
||||
@@ -40,6 +41,8 @@ UI_HOME_EXPLORER_ADDRESS_TEMPLATE: https://blockscout.com/poa/sokol/address/%s
|
||||
UI_FOREIGN_EXPLORER_ADDRESS_TEMPLATE: https://blockscout.com/eth/kovan/address/%s
|
||||
UI_HOME_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
UI_STYLES: "core"
|
||||
UI_PUBLIC_URL: "http://localhost"
|
||||
|
||||
#monitor
|
||||
MONITOR_BRIDGE_NAME: "bridge"
|
||||
|
||||
@@ -33,6 +33,7 @@ COMMON_FOREIGN_GAS_PRICE_FACTOR: 1
|
||||
|
||||
## UI
|
||||
UI_TITLE: "TokenBridge UI app - %c"
|
||||
UI_OG_TITLE: "POA Bridge UI"
|
||||
UI_DESCRIPTION: "The TokenBridge serves as a method of transferring native tokens from the Ethereum Classic Network to the Ethereum network in a quick and cost-efficient manner."
|
||||
UI_PORT: 3001
|
||||
UI_HOME_EXPLORER_TX_TEMPLATE: https://blockscout.com/etc/mainnet/tx/%s
|
||||
@@ -41,6 +42,8 @@ UI_HOME_EXPLORER_ADDRESS_TEMPLATE: https://blockscout.com/etc/mainnet/address/%s
|
||||
UI_FOREIGN_EXPLORER_ADDRESS_TEMPLATE: https://blockscout.com/eth/mainnet/address/%s
|
||||
UI_HOME_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
UI_STYLES: "classic"
|
||||
UI_PUBLIC_URL: "https://wetc.app"
|
||||
|
||||
## Monitor
|
||||
MONITOR_BRIDGE_NAME: "wetc"
|
||||
|
||||
@@ -34,9 +34,9 @@ COMMON_FOREIGN_GAS_PRICE_FACTOR={{ COMMON_FOREIGN_GAS_PRICE_FACTOR }}
|
||||
|
||||
# Default
|
||||
UI_TITLE={{ UI_TITLE }}
|
||||
UI_OG_TITLE={{ UI_OG_TITLE }}
|
||||
UI_DESCRIPTION={{ UI_DESCRIPTION }}
|
||||
UI_PORT={{ UI_PORT }}
|
||||
UI_PUBLIC_URL={{ UI_PUBLIC_URL }}
|
||||
|
||||
{% if UI_STYLES | default('') != '' %}
|
||||
UI_STYLES={{ UI_STYLES }}
|
||||
{% endif %}
|
||||
|
||||
@@ -21,3 +21,5 @@ COMMON_FOREIGN_GAS_PRICE_FACTOR=1
|
||||
ORACLE_HOME_RPC_POLLING_INTERVAL=500
|
||||
ORACLE_FOREIGN_RPC_POLLING_INTERVAL=500
|
||||
ORACLE_ALLOW_HTTP_FOR_RPC=yes
|
||||
ORACLE_HOME_START_BLOCK=1
|
||||
ORACLE_FOREIGN_START_BLOCK=1
|
||||
|
||||
@@ -21,3 +21,5 @@ COMMON_FOREIGN_GAS_PRICE_FACTOR=0.1
|
||||
ORACLE_HOME_RPC_POLLING_INTERVAL=500
|
||||
ORACLE_FOREIGN_RPC_POLLING_INTERVAL=500
|
||||
ORACLE_ALLOW_HTTP_FOR_RPC=yes
|
||||
ORACLE_HOME_START_BLOCK=1
|
||||
ORACLE_FOREIGN_START_BLOCK=1
|
||||
|
||||
@@ -21,3 +21,5 @@ COMMON_FOREIGN_GAS_PRICE_FACTOR=0.1
|
||||
ORACLE_HOME_RPC_POLLING_INTERVAL=500
|
||||
ORACLE_FOREIGN_RPC_POLLING_INTERVAL=500
|
||||
ORACLE_ALLOW_HTTP_FOR_RPC=yes
|
||||
ORACLE_HOME_START_BLOCK=1
|
||||
ORACLE_FOREIGN_START_BLOCK=1
|
||||
|
||||
23
e2e-commons/components-envs/ui-amb-stake-erc20-erc20.env
Normal file
@@ -0,0 +1,23 @@
|
||||
COMMON_HOME_BRIDGE_ADDRESS=0xc26Aa60Ff574f157616D3aEE70e08aAC129E1dFC
|
||||
COMMON_FOREIGN_BRIDGE_ADDRESS=0xc26Aa60Ff574f157616D3aEE70e08aAC129E1dFC
|
||||
COMMON_FOREIGN_RPC_URL=http://localhost:8542
|
||||
COMMON_HOME_RPC_URL=http://localhost:8541
|
||||
UI_NATIVE_TOKEN_DISPLAY_NAME=POA
|
||||
UI_HOME_NETWORK_DISPLAY_NAME=Sokol
|
||||
UI_FOREIGN_NETWORK_DISPLAY_NAME=Kovan
|
||||
UI_HOME_EXPLORER_TX_TEMPLATE=https://blockscout.com/poa/sokol/tx//%s
|
||||
UI_FOREIGN_EXPLORER_TX_TEMPLATE=https://blockscout.com/eth/kovan/tx/%s
|
||||
UI_HOME_EXPLORER_ADDRESS_TEMPLATE=https://blockscout.com/poa/sokol/address/%s
|
||||
UI_FOREIGN_EXPLORER_ADDRESS_TEMPLATE=https://blockscout.com/eth/kovan/address/%s
|
||||
COMMON_HOME_GAS_PRICE_SUPPLIER_URL=https://gasprice.poa.network/
|
||||
COMMON_HOME_GAS_PRICE_SPEED_TYPE=standard
|
||||
COMMON_HOME_GAS_PRICE_FALLBACK=5000000000
|
||||
UI_HOME_GAS_PRICE_UPDATE_INTERVAL=15000
|
||||
COMMON_HOME_GAS_PRICE_FACTOR=1
|
||||
COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL=https://gasprice.poa.network/
|
||||
COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE=standard
|
||||
COMMON_FOREIGN_GAS_PRICE_FALLBACK=5000000000
|
||||
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL=15000
|
||||
COMMON_FOREIGN_GAS_PRICE_FACTOR=1
|
||||
UI_PORT=3000
|
||||
UI_STYLES=stake
|
||||
@@ -20,3 +20,4 @@ COMMON_FOREIGN_GAS_PRICE_FALLBACK=5000000000
|
||||
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL=15000
|
||||
COMMON_FOREIGN_GAS_PRICE_FACTOR=1
|
||||
UI_PORT=3000
|
||||
UI_STYLES=core
|
||||
|
||||
@@ -20,3 +20,4 @@ COMMON_FOREIGN_GAS_PRICE_FALLBACK=5000000000
|
||||
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL=15000
|
||||
COMMON_FOREIGN_GAS_PRICE_FACTOR=1
|
||||
UI_PORT=3000
|
||||
UI_STYLES=core
|
||||
|
||||
@@ -20,3 +20,4 @@ COMMON_FOREIGN_GAS_PRICE_FALLBACK=5000000000
|
||||
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL=15000
|
||||
COMMON_FOREIGN_GAS_PRICE_FACTOR=1
|
||||
UI_PORT=3000
|
||||
UI_STYLES=core
|
||||
|
||||
@@ -63,6 +63,14 @@
|
||||
"foreignBox": "0x6C4EaAb8756d53Bf599FFe2347FAFF1123D6C8A1",
|
||||
"monitor": "http://monitor-amb:3013/bridge"
|
||||
},
|
||||
"ambStakeErcToErc": {
|
||||
"home": "0xc26Aa60Ff574f157616D3aEE70e08aAC129E1dFC",
|
||||
"foreign": "0xc26Aa60Ff574f157616D3aEE70e08aAC129E1dFC",
|
||||
"homeToken": "0x6f359aC418a5f7538F7755A33C9c7dDf38785524",
|
||||
"foreignToken": "0x6f359aC418a5f7538F7755A33C9c7dDf38785524",
|
||||
"blockReward": "0xF9698Eb93702dfdd0e2d802088d4c21822a8A977",
|
||||
"ui": "http://localhost:3003"
|
||||
},
|
||||
"homeRPC": {
|
||||
"URL": "http://parity1:8545",
|
||||
"ID": "77"
|
||||
|
||||
30
e2e-commons/contracts-envs/amb-stake-erc-to-erc.env
Normal file
@@ -0,0 +1,30 @@
|
||||
BRIDGE_MODE=STAKE_AMB_ERC_TO_ERC
|
||||
DEPLOYMENT_ACCOUNT_PRIVATE_KEY=8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9
|
||||
DEPLOYMENT_GAS_LIMIT_EXTRA=0.2
|
||||
HOME_DEPLOYMENT_GAS_PRICE=10000000000
|
||||
FOREIGN_DEPLOYMENT_GAS_PRICE=10000000000
|
||||
GET_RECEIPT_INTERVAL_IN_MILLISECONDS=50
|
||||
HOME_STAKE_TOKEN_ADDRESS=0x6f359aC418a5f7538F7755A33C9c7dDf38785524
|
||||
FOREIGN_STAKE_TOKEN_ADDRESS=0x6f359aC418a5f7538F7755A33C9c7dDf38785524
|
||||
BLOCK_REWARD_ADDRESS=0xF9698Eb93702dfdd0e2d802088d4c21822a8A977
|
||||
HOME_RPC_URL=http://parity1:8545
|
||||
HOME_BRIDGE_OWNER=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
|
||||
HOME_UPGRADEABLE_ADMIN=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
|
||||
HOME_DAILY_LIMIT=30000000000000000000000000
|
||||
HOME_MAX_AMOUNT_PER_TX=1500000000000000000000000
|
||||
HOME_MIN_AMOUNT_PER_TX=10000000000000000
|
||||
HOME_TRANSACTIONS_FEE=0
|
||||
FOREIGN_RPC_URL=http://parity2:8545
|
||||
FOREIGN_BRIDGE_OWNER=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
|
||||
FOREIGN_UPGRADEABLE_ADMIN=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
|
||||
FOREIGN_DAILY_LIMIT=15000000000000000000000000
|
||||
FOREIGN_MAX_AMOUNT_PER_TX=750000000000000000000000
|
||||
FOREIGN_MIN_AMOUNT_PER_TX=10000000000000000
|
||||
HOME_AMB_BRIDGE=0x0AEe1FCD12dDFab6265F7f8956e6E012A9Fe4Aa0
|
||||
FOREIGN_AMB_BRIDGE=0x0AEe1FCD12dDFab6265F7f8956e6E012A9Fe4Aa0
|
||||
HOME_MEDIATOR_REQUEST_GAS_LIMIT=2000000
|
||||
FOREIGN_MEDIATOR_REQUEST_GAS_LIMIT=2000000
|
||||
|
||||
BRIDGEABLE_TOKEN_NAME='not used'
|
||||
BRIDGEABLE_TOKEN_SYMBOL='not used'
|
||||
BRIDGEABLE_TOKEN_DECIMALS='18'
|
||||
@@ -93,6 +93,15 @@ services:
|
||||
command: "true"
|
||||
networks:
|
||||
- ultimate
|
||||
ui-amb-stake-erc20-erc20:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: ui/Dockerfile
|
||||
args:
|
||||
DOT_ENV_PATH: e2e-commons/components-envs/ui-amb-stake-erc20-erc20.env
|
||||
command: "true"
|
||||
networks:
|
||||
- ultimate
|
||||
monitor:
|
||||
build:
|
||||
context: ..
|
||||
|
||||
@@ -43,3 +43,13 @@ echo -e "\n\n############ Deploying test contract for amb ############\n"
|
||||
cd "$DEPLOY_PATH"
|
||||
node src/utils/deployTestBox.js
|
||||
cd - > /dev/null
|
||||
|
||||
echo -e "\n\n############ Deploying amb stake erc to erc ############\n"
|
||||
cp "$ENVS_PATH/amb-stake-erc-to-erc.env" "$DEPLOY_PATH/.env"
|
||||
node deployMultiBridgeToken.js
|
||||
node deployBridgeTokenRewardable.js
|
||||
cd "$DEPLOY_PATH"
|
||||
node deploy.js
|
||||
cd - > /dev/null
|
||||
node setupStakeTokens.js
|
||||
cd - > /dev/null
|
||||
|
||||
43
e2e-commons/scripts/deployBridgeTokenRewardable.js
Normal file
@@ -0,0 +1,43 @@
|
||||
const path = require('path')
|
||||
const { user } = require('../constants.json')
|
||||
const contractsPath = '../../contracts'
|
||||
require('dotenv').config({
|
||||
path: path.join(__dirname, contractsPath, '/deploy/.env')
|
||||
})
|
||||
|
||||
const { deployContract, sendRawTxHome, privateKeyToAddress } = require(`${contractsPath}/deploy/src/deploymentUtils`)
|
||||
const { web3Home, deploymentPrivateKey } = require(`${contractsPath}/deploy/src/web3`)
|
||||
const ERC677BridgeTokenRewardable = require(`${contractsPath}/build/contracts/ERC677BridgeTokenRewardable.json`)
|
||||
|
||||
const { DEPLOYMENT_ACCOUNT_PRIVATE_KEY } = process.env
|
||||
const DEPLOYMENT_ACCOUNT_ADDRESS = privateKeyToAddress(DEPLOYMENT_ACCOUNT_PRIVATE_KEY)
|
||||
|
||||
async function deployBridgeTokenRewardable() {
|
||||
try {
|
||||
let homeNonce = await web3Home.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS)
|
||||
console.log('\n[Home] Deploying ERC677BridgeTokenRewardable Test token')
|
||||
const stakeToken = await deployContract(ERC677BridgeTokenRewardable, ['STAKE', 'STAKE', '18', '77'], {
|
||||
from: DEPLOYMENT_ACCOUNT_ADDRESS,
|
||||
network: 'home',
|
||||
nonce: homeNonce
|
||||
})
|
||||
homeNonce++
|
||||
console.log('[Home] Stake Token: ', stakeToken.options.address)
|
||||
|
||||
const mintData = await stakeToken.methods
|
||||
.mint(user.address, '500000000000000000000')
|
||||
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
|
||||
await sendRawTxHome({
|
||||
data: mintData,
|
||||
nonce: homeNonce,
|
||||
to: stakeToken.options.address,
|
||||
privateKey: deploymentPrivateKey,
|
||||
url: process.env.HOME_RPC_URL
|
||||
})
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
deployBridgeTokenRewardable()
|
||||
43
e2e-commons/scripts/deployMultiBridgeToken.js
Normal file
@@ -0,0 +1,43 @@
|
||||
const path = require('path')
|
||||
const { user } = require('../constants.json')
|
||||
const contractsPath = '../../contracts'
|
||||
require('dotenv').config({
|
||||
path: path.join(__dirname, contractsPath, '/deploy/.env')
|
||||
})
|
||||
|
||||
const { deployContract, sendRawTxForeign, privateKeyToAddress } = require(`${contractsPath}/deploy/src/deploymentUtils`)
|
||||
const { web3Foreign, deploymentPrivateKey } = require(`${contractsPath}/deploy/src/web3`)
|
||||
const ERC677MultiBridgeToken = require(`${contractsPath}/build/contracts/ERC677MultiBridgeToken.json`)
|
||||
|
||||
const { DEPLOYMENT_ACCOUNT_PRIVATE_KEY } = process.env
|
||||
const DEPLOYMENT_ACCOUNT_ADDRESS = privateKeyToAddress(DEPLOYMENT_ACCOUNT_PRIVATE_KEY)
|
||||
|
||||
async function deployMultiBridgeToken() {
|
||||
try {
|
||||
let foreignNonce = await web3Foreign.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS)
|
||||
console.log('\n[Foreign] Deploying ERC677MultiBridgeToken Test token')
|
||||
const stakeToken = await deployContract(ERC677MultiBridgeToken, ['STAKE', 'STAKE', '18', '42'], {
|
||||
from: DEPLOYMENT_ACCOUNT_ADDRESS,
|
||||
network: 'foreign',
|
||||
nonce: foreignNonce
|
||||
})
|
||||
foreignNonce++
|
||||
console.log('[Foreign] Stake Token: ', stakeToken.options.address)
|
||||
|
||||
const mintData = await stakeToken.methods
|
||||
.mint(user.address, '500000000000000000000')
|
||||
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
|
||||
await sendRawTxForeign({
|
||||
data: mintData,
|
||||
nonce: foreignNonce,
|
||||
to: stakeToken.options.address,
|
||||
privateKey: deploymentPrivateKey,
|
||||
url: process.env.FOREIGN_RPC_URL
|
||||
})
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
deployMultiBridgeToken()
|
||||
111
e2e-commons/scripts/setupStakeTokens.js
Normal file
@@ -0,0 +1,111 @@
|
||||
const path = require('path')
|
||||
const { ambStakeErcToErc, validator, secondValidator, thirdValidator } = require('../constants.json')
|
||||
const contractsPath = '../../contracts'
|
||||
require('dotenv').config({
|
||||
path: path.join(__dirname, contractsPath, '/deploy/.env')
|
||||
})
|
||||
const { sendRawTxHome, sendRawTxForeign, privateKeyToAddress } = require(`${contractsPath}/deploy/src/deploymentUtils`)
|
||||
const { web3Home, web3Foreign, deploymentPrivateKey } = require(`${contractsPath}/deploy/src/web3`)
|
||||
const BlockReward = require(`${contractsPath}/build/contracts/BlockReward.json`)
|
||||
const ERC677BridgeTokenRewardable = require(`${contractsPath}/build/contracts/ERC677BridgeTokenRewardable.json`)
|
||||
const ERC677MultiBridgeToken = require(`${contractsPath}/build/contracts/ERC677MultiBridgeToken.json`)
|
||||
|
||||
const { DEPLOYMENT_ACCOUNT_PRIVATE_KEY } = process.env
|
||||
const DEPLOYMENT_ACCOUNT_ADDRESS = privateKeyToAddress(DEPLOYMENT_ACCOUNT_PRIVATE_KEY)
|
||||
|
||||
async function setupStakeTokens() {
|
||||
try {
|
||||
let homeNonce = await web3Home.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS)
|
||||
|
||||
const blockReward = new web3Home.eth.Contract(BlockReward.abi, ambStakeErcToErc.blockReward)
|
||||
|
||||
console.log('\n[Home] Set token in block reward')
|
||||
const setTokenData = await blockReward.methods.setToken(ambStakeErcToErc.homeToken).encodeABI()
|
||||
await sendRawTxHome({
|
||||
data: setTokenData,
|
||||
nonce: homeNonce,
|
||||
to: blockReward.options.address,
|
||||
privateKey: deploymentPrivateKey,
|
||||
url: process.env.HOME_RPC_URL
|
||||
})
|
||||
homeNonce++
|
||||
|
||||
console.log('\n[Home] Set validators rewards in block reward')
|
||||
const setValidatorsRewardsData = await blockReward.methods
|
||||
.setValidatorsRewards([validator.address, secondValidator.address, thirdValidator.address])
|
||||
.encodeABI()
|
||||
await sendRawTxHome({
|
||||
data: setValidatorsRewardsData,
|
||||
nonce: homeNonce,
|
||||
to: blockReward.options.address,
|
||||
privateKey: deploymentPrivateKey,
|
||||
url: process.env.HOME_RPC_URL
|
||||
})
|
||||
homeNonce++
|
||||
|
||||
const homeToken = new web3Home.eth.Contract(ERC677BridgeTokenRewardable.abi, ambStakeErcToErc.homeToken)
|
||||
|
||||
console.log('\n[Home] Set block reward in token')
|
||||
const setBlockRewardData = await homeToken.methods.setBlockRewardContract(ambStakeErcToErc.blockReward).encodeABI()
|
||||
await sendRawTxHome({
|
||||
data: setBlockRewardData,
|
||||
nonce: homeNonce,
|
||||
to: homeToken.options.address,
|
||||
privateKey: deploymentPrivateKey,
|
||||
url: process.env.HOME_RPC_URL
|
||||
})
|
||||
homeNonce++
|
||||
|
||||
console.log('\n[Home] Add bridge in token')
|
||||
const addBridgeData = await homeToken.methods.addBridge(ambStakeErcToErc.home).encodeABI()
|
||||
await sendRawTxHome({
|
||||
data: addBridgeData,
|
||||
nonce: homeNonce,
|
||||
to: homeToken.options.address,
|
||||
privateKey: deploymentPrivateKey,
|
||||
url: process.env.HOME_RPC_URL
|
||||
})
|
||||
homeNonce++
|
||||
|
||||
console.log('\n[Home] transfer token ownership to mediator')
|
||||
const transferOwnershipData = await homeToken.methods.transferOwnership(ambStakeErcToErc.home).encodeABI()
|
||||
await sendRawTxHome({
|
||||
data: transferOwnershipData,
|
||||
nonce: homeNonce,
|
||||
to: homeToken.options.address,
|
||||
privateKey: deploymentPrivateKey,
|
||||
url: process.env.HOME_RPC_URL
|
||||
})
|
||||
homeNonce++
|
||||
|
||||
let foreignNonce = await web3Foreign.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS)
|
||||
const foreignToken = new web3Foreign.eth.Contract(ERC677MultiBridgeToken.abi, ambStakeErcToErc.foreignToken)
|
||||
|
||||
console.log('\n[Foreign] Add bridge in token')
|
||||
const addBridgeForeignData = await homeToken.methods.addBridge(ambStakeErcToErc.foreign).encodeABI()
|
||||
await sendRawTxForeign({
|
||||
data: addBridgeForeignData,
|
||||
nonce: foreignNonce,
|
||||
to: foreignToken.options.address,
|
||||
privateKey: deploymentPrivateKey,
|
||||
url: process.env.FOREIGN_RPC_URL
|
||||
})
|
||||
foreignNonce++
|
||||
|
||||
console.log('\n[Foreign] transfer token ownership to mediator')
|
||||
const transferOwnershipForeignData = await homeToken.methods.transferOwnership(ambStakeErcToErc.foreign).encodeABI()
|
||||
await sendRawTxForeign({
|
||||
data: transferOwnershipForeignData,
|
||||
nonce: foreignNonce,
|
||||
to: foreignToken.options.address,
|
||||
privateKey: deploymentPrivateKey,
|
||||
url: process.env.FOREIGN_RPC_URL
|
||||
})
|
||||
foreignNonce++
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
setupStakeTokens()
|
||||
@@ -8,6 +8,9 @@ docker network create --driver bridge ultimate || true
|
||||
docker-compose up -d parity1 parity2 e2e
|
||||
|
||||
startValidator () {
|
||||
# make sure that old image tags are not cached
|
||||
docker-compose $1 build
|
||||
|
||||
docker-compose $1 run -d --name $4 redis
|
||||
docker-compose $1 run -d --name $5 rabbit
|
||||
docker-compose $1 run $2 $3 -d oracle yarn watcher:signature-request
|
||||
@@ -71,11 +74,12 @@ while [ "$1" != "" ]; do
|
||||
fi
|
||||
|
||||
if [ "$1" == "ui" ]; then
|
||||
docker-compose up -d ui ui-erc20 ui-erc20-native
|
||||
docker-compose up -d ui ui-erc20 ui-erc20-native ui-amb-stake-erc20-erc20
|
||||
|
||||
docker-compose run -d -p 3000:3000 ui yarn start
|
||||
docker-compose run -d -p 3001:3000 ui-erc20 yarn start
|
||||
docker-compose run -d -p 3002:3000 ui-erc20-native yarn start
|
||||
docker-compose run -d -p 3003:3000 ui-amb-stake-erc20-erc20 yarn start
|
||||
fi
|
||||
|
||||
if [ "$1" == "deploy" ]; then
|
||||
@@ -106,5 +110,9 @@ while [ "$1" != "" ]; do
|
||||
../deployment-e2e/molecule.sh ultimate-amb
|
||||
fi
|
||||
|
||||
if [ "$1" == "ultimate-amb-stake-erc-to-erc" ]; then
|
||||
../deployment-e2e/molecule.sh ultimate-amb-stake-erc-to-erc
|
||||
fi
|
||||
|
||||
shift # Shift all the parameters down by one
|
||||
done
|
||||
|
||||
@@ -31,6 +31,7 @@ async function checkWorker() {
|
||||
const foreign = Object.assign({}, balances.foreign, events.foreign)
|
||||
const status = Object.assign({}, balances, events, { home }, { foreign })
|
||||
if (!status) throw new Error('status is empty: ' + JSON.stringify(status))
|
||||
status.health = true
|
||||
writeFile(`/responses/${MONITOR_BRIDGE_NAME}/getBalances.json`, status)
|
||||
|
||||
logger.debug('calling validators()')
|
||||
@@ -59,6 +60,7 @@ async function checkWorker() {
|
||||
}
|
||||
|
||||
vBalances.ok = vBalances.homeOk && vBalances.foreignOk
|
||||
vBalances.health = true
|
||||
writeFile(`/responses/${MONITOR_BRIDGE_NAME}/validators.json`, vBalances)
|
||||
logger.debug('Done')
|
||||
} catch (e) {
|
||||
|
||||
@@ -16,12 +16,14 @@ async function checkWorker2() {
|
||||
(evStats.onlyInForeignDeposits || evStats.home.processedMsgNotDeliveredInForeign).length === 0 &&
|
||||
(evStats.onlyInHomeWithdrawals || evStats.foreign.deliveredMsgNotProcessedInHome).length === 0 &&
|
||||
(evStats.onlyInForeignWithdrawals || evStats.foreign.processedMsgNotDeliveredInHome).length === 0
|
||||
evStats.health = true
|
||||
writeFile(`/responses/${MONITOR_BRIDGE_NAME}/eventsStats.json`, evStats)
|
||||
|
||||
logger.debug('calling alerts()')
|
||||
const _alerts = await alerts()
|
||||
if (!_alerts) throw new Error('alerts is empty: ' + JSON.stringify(_alerts))
|
||||
_alerts.ok = !_alerts.executeAffirmations.mostRecentTxHash && !_alerts.executeSignatures.mostRecentTxHash
|
||||
_alerts.health = true
|
||||
writeFile(`/responses/${MONITOR_BRIDGE_NAME}/alerts.json`, _alerts)
|
||||
logger.debug('Done x2')
|
||||
} catch (e) {
|
||||
|
||||
@@ -19,6 +19,7 @@ async function checkWorker3() {
|
||||
const transfers = await stuckTransfers()
|
||||
if (!transfers) throw new Error('transfers is empty: ' + JSON.stringify(transfers))
|
||||
transfers.ok = transfers.total.length === 0
|
||||
transfers.health = true
|
||||
writeFile(`/responses/${MONITOR_BRIDGE_NAME}/stuckTransfers.json`, transfers)
|
||||
logger.debug('Done')
|
||||
}
|
||||
|
||||
@@ -3,4 +3,6 @@ version: '2.4'
|
||||
services:
|
||||
monitor:
|
||||
image: poanetwork/tokenbridge-monitor
|
||||
build: .
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: monitor/Dockerfile
|
||||
|
||||
@@ -3,7 +3,6 @@ const BN = require('bignumber.js')
|
||||
const Web3 = require('web3')
|
||||
const logger = require('./logger')('getBalances')
|
||||
const { BRIDGE_MODES } = require('../commons')
|
||||
const { blockNumberHalfDuplexDisabled } = require('./utils/tokenUtils')
|
||||
|
||||
const Web3Utils = Web3.utils
|
||||
|
||||
@@ -86,28 +85,7 @@ async function main(bridgeMode) {
|
||||
const erc20Contract = new web3Foreign.eth.Contract(ERC20_ABI, erc20Address)
|
||||
let investedAmountInDai = 0
|
||||
let bridgeDsrBalance = 0
|
||||
let foreignHalfDuplexErc20Balance = 0
|
||||
let displayChaiToken = false
|
||||
let displayHalfDuplexToken = false
|
||||
let tokenSwapAllowed = false
|
||||
try {
|
||||
const halfDuplexTokenAddress = await foreignBridge.methods.halfDuplexErc20token().call()
|
||||
if (halfDuplexTokenAddress !== erc20Address) {
|
||||
const halfDuplexToken = new web3Foreign.eth.Contract(ERC20_ABI, halfDuplexTokenAddress)
|
||||
logger.debug('calling halfDuplexToken.methods.balanceOf')
|
||||
foreignHalfDuplexErc20Balance = await halfDuplexToken.methods
|
||||
.balanceOf(COMMON_FOREIGN_BRIDGE_ADDRESS)
|
||||
.call(null, blockNumberHalfDuplexDisabled)
|
||||
logger.debug('getting last block numbers')
|
||||
const block = await web3Foreign.eth.getBlock('latest')
|
||||
|
||||
logger.debug(`Checking if SCD Emergency Shutdown has happened`)
|
||||
tokenSwapAllowed = await foreignBridge.methods.isTokenSwapAllowed(block.timestamp).call()
|
||||
displayHalfDuplexToken = true
|
||||
}
|
||||
} catch (e) {
|
||||
logger.debug('Methods for half duplex token are not present')
|
||||
}
|
||||
|
||||
try {
|
||||
logger.debug('calling foreignBridge.methods.isChaiTokenEnabled')
|
||||
@@ -142,30 +120,16 @@ async function main(bridgeMode) {
|
||||
const foreignErc20BalanceBN = new BN(foreignErc20Balance)
|
||||
const investedAmountInDaiBN = new BN(investedAmountInDai)
|
||||
const bridgeDsrBalanceBN = new BN(bridgeDsrBalance)
|
||||
const halfDuplexErc20BalanceBN = displayHalfDuplexToken ? new BN(foreignHalfDuplexErc20Balance) : new BN(0)
|
||||
|
||||
const diff = foreignErc20BalanceBN
|
||||
.plus(halfDuplexErc20BalanceBN)
|
||||
.plus(investedAmountInDaiBN)
|
||||
.minus(totalSupplyBN)
|
||||
.toFixed()
|
||||
|
||||
let foreign = {
|
||||
const foreign = {
|
||||
erc20Balance: Web3Utils.fromWei(foreignErc20Balance)
|
||||
}
|
||||
|
||||
if (displayHalfDuplexToken && tokenSwapAllowed) {
|
||||
foreign = {
|
||||
...foreign,
|
||||
halfDuplexErc20Balance: Web3Utils.fromWei(foreignHalfDuplexErc20Balance)
|
||||
}
|
||||
} else if (displayHalfDuplexToken && !tokenSwapAllowed) {
|
||||
foreign = {
|
||||
...foreign,
|
||||
halfDuplexErc20BalanceAfterES: Web3Utils.fromWei(foreignHalfDuplexErc20Balance)
|
||||
}
|
||||
}
|
||||
|
||||
if (displayChaiToken) {
|
||||
foreign.investedErc20Balance = Web3Utils.fromWei(investedAmountInDai)
|
||||
foreign.accumulatedInterest = Web3Utils.fromWei(bridgeDsrBalanceBN.minus(investedAmountInDaiBN).toString(10))
|
||||
|
||||
@@ -1,11 +1,60 @@
|
||||
#!/bin/bash
|
||||
|
||||
CONFIGDIR="configs"
|
||||
RESPONSESDIR="responses"
|
||||
IMAGETAG="latest"
|
||||
|
||||
cd $(dirname $0)/..
|
||||
|
||||
if /usr/local/bin/docker-compose ps | grep -q -i 'monitor'; then
|
||||
for file in configs/*.env
|
||||
tstart=`date +"%s"`
|
||||
|
||||
for file in ${CONFIGDIR}/*.env
|
||||
do
|
||||
docker run --rm --env-file $file -v $(pwd)/responses:/mono/monitor/responses poanetwork/tokenbridge-monitor:latest /bin/bash -c 'yarn check-all'
|
||||
echo "${file} handling..."
|
||||
|
||||
bridgename=`source ${file} && echo ${MONITOR_BRIDGE_NAME}`
|
||||
reportdir=${RESPONSESDIR}"/"${bridgename}
|
||||
if [ ! -d ${reportdir} ]; then
|
||||
mkdir -p ${reportdir}
|
||||
fi
|
||||
checksumfile=${bridgename}".shasum"
|
||||
rm -f ${checksumfile}
|
||||
for json in alerts.json eventsStats.json getBalances.json validators.json stuckTransfers.json; do
|
||||
if [ -f ${reportdir}/${json} ]; then
|
||||
shasum -a 256 ${reportdir}/${json} >> ${checksumfile}
|
||||
fi
|
||||
done
|
||||
|
||||
containername=${bridgename}"-checker"
|
||||
docker container stats --no-stream ${containername} 2>/dev/null 1>&2
|
||||
if [ ! "$?" == "0" ]; then
|
||||
docker run --rm --env-file $file -v $(pwd)/${RESPONSESDIR}:/mono/monitor/responses \
|
||||
--name ${containername} poanetwork/tokenbridge-monitor:${IMAGETAG} \
|
||||
/bin/bash -c 'yarn check-all'
|
||||
shasum -a 256 -s -c ${checksumfile}
|
||||
if [ "$?" == "0" ]; then
|
||||
echo "JSON files have not been updated - the monitor is not healthy"
|
||||
for json in alerts.json eventsStats.json getBalances.json validators.json stuckTransfers.json; do
|
||||
if [ -f ${reportdir}/${json} ]; then
|
||||
echo '{"health": false, "lastChecked": '`date +"%s"`'}' > ${reportdir}/${json}
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo "JSON files have been updated - new metrics collected"
|
||||
fi
|
||||
else
|
||||
echo "${containername} have not finished yet" >&2
|
||||
fi
|
||||
|
||||
rm ${checksumfile}
|
||||
echo "========================================"
|
||||
done
|
||||
|
||||
tend=`date +"%s"`
|
||||
tdiff=`expr ${tend} - ${tstart}`
|
||||
echo "Total time to run: ${tdiff}"
|
||||
|
||||
else
|
||||
echo "Monitor is not running, skipping checks."
|
||||
fi
|
||||
fi
|
||||
@@ -114,6 +114,8 @@ async function main(mode) {
|
||||
let directTransfers = transferEvents
|
||||
const tokensSwappedAbiExists = FOREIGN_ABI.filter(e => e.type === 'event' && e.name === 'TokensSwapped')[0]
|
||||
if (tokensSwappedAbiExists) {
|
||||
logger.debug('collecting half duplex tokens participated in the bridge balance')
|
||||
logger.debug("calling foreignBridge.getPastEvents('TokensSwapped')")
|
||||
const tokensSwappedEvents = await getPastEvents(foreignBridge, {
|
||||
event: 'TokensSwapped',
|
||||
fromBlock: MONITOR_FOREIGN_START_BLOCK,
|
||||
@@ -128,7 +130,7 @@ async function main(mode) {
|
||||
|
||||
// Exclude chai token from previous erc20
|
||||
try {
|
||||
logger.debug('calling foreignBridge.chaiToken()')
|
||||
logger.debug('calling foreignBridge.chaiToken() to remove it from half duplex tokens list')
|
||||
const chaiToken = await foreignBridge.methods.chaiToken().call()
|
||||
uniqueTokenAddressesSet.delete(chaiToken)
|
||||
} catch (e) {
|
||||
@@ -136,7 +138,7 @@ async function main(mode) {
|
||||
}
|
||||
// Exclude dai token from previous erc20
|
||||
try {
|
||||
logger.debug('calling foreignBridge.erc20token()')
|
||||
logger.debug('calling foreignBridge.erc20token() to remove it from half duplex tokens list')
|
||||
const daiToken = await foreignBridge.methods.erc20token().call()
|
||||
uniqueTokenAddressesSet.delete(daiToken)
|
||||
} catch (e) {
|
||||
@@ -148,6 +150,8 @@ async function main(mode) {
|
||||
uniqueTokenAddresses.map(async tokenAddress => {
|
||||
const halfDuplexTokenContract = new web3Foreign.eth.Contract(ERC20_ABI, tokenAddress)
|
||||
|
||||
logger.debug('Half duplex token:', tokenAddress)
|
||||
logger.debug("calling halfDuplexTokenContract.getPastEvents('Transfer')")
|
||||
const halfDuplexTransferEvents = (await getPastEvents(halfDuplexTokenContract, {
|
||||
event: 'Transfer',
|
||||
fromBlock: MONITOR_FOREIGN_START_BLOCK,
|
||||
@@ -158,6 +162,7 @@ async function main(mode) {
|
||||
})).map(normalizeEvent)
|
||||
|
||||
// Remove events after the ES
|
||||
logger.debug('filtering half duplex transfers happened before ES')
|
||||
const validHalfDuplexTransfers = await filterTransferBeforeES(halfDuplexTransferEvents)
|
||||
|
||||
transferEvents = [...validHalfDuplexTransfers, ...transferEvents]
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
const web3Utils = require('web3').utils
|
||||
const { addTxHashToData, parseAMBMessage } = require('../../commons')
|
||||
const { parseAMBMessage } = require('../../commons')
|
||||
|
||||
function deliveredMsgNotProcessed(processedList) {
|
||||
return deliveredMsg => {
|
||||
const msg = parseAMBMessage(
|
||||
addTxHashToData({
|
||||
encodedData: deliveredMsg.returnValues.encodedData,
|
||||
transactionHash: deliveredMsg.transactionHash
|
||||
})
|
||||
)
|
||||
const msg = parseAMBMessage(deliveredMsg.returnValues.encodedData)
|
||||
return (
|
||||
processedList.filter(processedMsg => {
|
||||
return messageEqualsEvent(msg, processedMsg.returnValues)
|
||||
@@ -21,12 +16,7 @@ function processedMsgNotDelivered(deliveredList) {
|
||||
return processedMsg => {
|
||||
return (
|
||||
deliveredList.filter(deliveredMsg => {
|
||||
const msg = parseAMBMessage(
|
||||
addTxHashToData({
|
||||
encodedData: deliveredMsg.returnValues.encodedData,
|
||||
transactionHash: deliveredMsg.transactionHash
|
||||
})
|
||||
)
|
||||
const msg = parseAMBMessage(deliveredMsg.returnValues.encodedData)
|
||||
return messageEqualsEvent(msg, processedMsg.returnValues)
|
||||
}).length === 0
|
||||
)
|
||||
@@ -37,7 +27,7 @@ function messageEqualsEvent(parsedMsg, event) {
|
||||
return (
|
||||
web3Utils.toChecksumAddress(parsedMsg.sender) === event.sender &&
|
||||
web3Utils.toChecksumAddress(parsedMsg.executor) === event.executor &&
|
||||
parsedMsg.txHash === event.transactionHash
|
||||
parsedMsg.messageId === event.messageId
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
"worker:convert-to-chai": "./scripts/start-worker.sh worker convert-to-chai-worker",
|
||||
"sender:home": "./scripts/start-worker.sh sender home-sender",
|
||||
"sender:foreign": "./scripts/start-worker.sh sender foreign-sender",
|
||||
"confirm:transfer": "./scripts/start-worker.sh confirmRelay transfer-watcher",
|
||||
"dev": "concurrently -n 'watcher:signature-request,watcher:collected-signatures,watcher:affirmation-request,watcher:transfer,watcher:half-duplex-transfer, worker:swap-tokens, sender:home,sender:foreign' -c 'red,green,yellow,blue,white,gray,magenta,cyan' 'yarn watcher:signature-request' 'yarn watcher:collected-signatures' 'yarn watcher:affirmation-request' 'yarn watcher:transfer' 'yarn watcher:half-duplex-transfer' 'yarn worker:swap-tokens' 'yarn sender:home' 'yarn sender:foreign'",
|
||||
"test": "NODE_ENV=test mocha",
|
||||
"test:watch": "NODE_ENV=test mocha --watch --reporter=min",
|
||||
|
||||
@@ -8,11 +8,12 @@ LOGS_DIR="logs/"
|
||||
WORKER="${WORKERS_DIR}${1}.js"
|
||||
CONFIG="${2}.config.js"
|
||||
LOG="${LOGS_DIR}${2}.txt"
|
||||
TX_HASH="${3}"
|
||||
|
||||
CHECKS=$(node scripts/initialChecks.js)
|
||||
|
||||
if [ "${NODE_ENV}" = "production" ]; then
|
||||
exec node "${WORKER}" "${CONFIG}" "$CHECKS"
|
||||
exec node "${WORKER}" "${CONFIG}" "$CHECKS" "$TX_HASH"
|
||||
else
|
||||
node "${WORKER}" "${CONFIG}" "$CHECKS" | tee -a "${LOG}" | pino-pretty
|
||||
node "${WORKER}" "${CONFIG}" "$CHECKS" "$TX_HASH" | tee -a "${LOG}" | pino-pretty
|
||||
fi
|
||||
|
||||
186
oracle/src/confirmRelay.js
Normal file
@@ -0,0 +1,186 @@
|
||||
require('../env')
|
||||
const path = require('path')
|
||||
const { isAttached, connectWatcherToQueue, connection } = require('./services/amqpClient')
|
||||
const logger = require('./services/logger')
|
||||
const GasPrice = require('./services/gasPrice')
|
||||
const rpcUrlsManager = require('./services/getRpcUrlsManager')
|
||||
const { getNonce, getChainId, getEventsFromTx } = require('./tx/web3')
|
||||
const { sendTx } = require('./tx/sendTx')
|
||||
const { checkHTTPS, watchdog, syncForEach, addExtraGas } = require('./utils/utils')
|
||||
const { EXIT_CODES, EXTRA_GAS_PERCENTAGE } = require('./utils/constants')
|
||||
|
||||
const { ORACLE_VALIDATOR_ADDRESS, ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY, ORACLE_ALLOW_HTTP_FOR_RPC } = process.env
|
||||
|
||||
if (process.argv.length < 5) {
|
||||
logger.error('Please check the number of arguments, transaction hash is not present')
|
||||
process.exit(EXIT_CODES.GENERAL_ERROR)
|
||||
}
|
||||
|
||||
const config = require(path.join('../config/', process.argv[2]))
|
||||
const txHash = process.argv[4]
|
||||
|
||||
const processSignatureRequests = require('./events/processSignatureRequests')(config)
|
||||
const processCollectedSignatures = require('./events/processCollectedSignatures')(config)
|
||||
const processAffirmationRequests = require('./events/processAffirmationRequests')(config)
|
||||
const processTransfers = require('./events/processTransfers')(config)
|
||||
const processAMBSignatureRequests = require('./events/processAMBSignatureRequests')(config)
|
||||
const processAMBCollectedSignatures = require('./events/processAMBCollectedSignatures')(config)
|
||||
const processAMBAffirmationRequests = require('./events/processAMBAffirmationRequests')(config)
|
||||
|
||||
const web3Instance = config.web3
|
||||
const { eventContractAddress } = config
|
||||
const eventContract = new web3Instance.eth.Contract(config.eventAbi, eventContractAddress)
|
||||
|
||||
let attached
|
||||
|
||||
async function initialize() {
|
||||
try {
|
||||
const checkHttps = checkHTTPS(ORACLE_ALLOW_HTTP_FOR_RPC, logger)
|
||||
|
||||
rpcUrlsManager.homeUrls.forEach(checkHttps('home'))
|
||||
rpcUrlsManager.foreignUrls.forEach(checkHttps('foreign'))
|
||||
|
||||
attached = await isAttached()
|
||||
if (attached) {
|
||||
logger.info('RabbitMQ container is available, using oracle sender')
|
||||
} else {
|
||||
logger.info('RabbitMQ container is not available, using internal sender')
|
||||
}
|
||||
|
||||
connectWatcherToQueue({
|
||||
queueName: config.queue,
|
||||
workerQueue: config.workerQueue,
|
||||
cb: runMain
|
||||
})
|
||||
} catch (e) {
|
||||
logger.error(e)
|
||||
process.exit(EXIT_CODES.GENERAL_ERROR)
|
||||
}
|
||||
}
|
||||
|
||||
async function runMain({ sendToQueue }) {
|
||||
try {
|
||||
const sendJob = attached ? sendToQueue : sendJobTx
|
||||
if (!attached || connection.isConnected()) {
|
||||
if (config.maxProcessingTime) {
|
||||
await watchdog(() => main({ sendJob, txHash }), config.maxProcessingTime, () => {
|
||||
logger.fatal('Max processing time reached')
|
||||
process.exit(EXIT_CODES.MAX_TIME_REACHED)
|
||||
})
|
||||
} else {
|
||||
await main({ sendJob, txHash })
|
||||
}
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
runMain({ sendToQueue })
|
||||
}, config.pollingInterval)
|
||||
}
|
||||
} catch (e) {
|
||||
logger.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
function processEvents(events) {
|
||||
switch (config.id) {
|
||||
case 'native-erc-signature-request':
|
||||
case 'erc-erc-signature-request':
|
||||
case 'erc-native-signature-request':
|
||||
return processSignatureRequests(events)
|
||||
case 'native-erc-collected-signatures':
|
||||
case 'erc-erc-collected-signatures':
|
||||
case 'erc-native-collected-signatures':
|
||||
return processCollectedSignatures(events)
|
||||
case 'native-erc-affirmation-request':
|
||||
case 'erc677-erc677-affirmation-request':
|
||||
case 'erc-native-affirmation-request':
|
||||
case 'erc-erc-affirmation-request':
|
||||
return processAffirmationRequests(events)
|
||||
case 'erc-erc-transfer':
|
||||
case 'erc-native-transfer':
|
||||
return processTransfers(events)
|
||||
case 'amb-signature-request':
|
||||
return processAMBSignatureRequests(events)
|
||||
case 'amb-collected-signatures':
|
||||
return processAMBCollectedSignatures(events)
|
||||
case 'amb-affirmation-request':
|
||||
return processAMBAffirmationRequests(events)
|
||||
default:
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
async function main({ sendJob, txHash }) {
|
||||
try {
|
||||
const events = await getEventsFromTx({
|
||||
web3: web3Instance,
|
||||
contract: eventContract,
|
||||
event: config.event,
|
||||
txHash,
|
||||
filter: config.eventFilter
|
||||
})
|
||||
logger.info(`Found ${events.length} ${config.event} events`)
|
||||
|
||||
if (events.length) {
|
||||
const job = await processEvents(events)
|
||||
logger.info('Transactions to send:', job.length)
|
||||
|
||||
if (job.length) {
|
||||
await sendJob(job)
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
logger.error(e)
|
||||
}
|
||||
|
||||
await connection.close()
|
||||
|
||||
logger.debug('Finished')
|
||||
}
|
||||
|
||||
async function sendJobTx(jobs) {
|
||||
const gasPrice = await GasPrice.start(config.queue, true)
|
||||
const chainId = await getChainId(config.queue)
|
||||
let nonce = await getNonce(web3Instance, ORACLE_VALIDATOR_ADDRESS)
|
||||
|
||||
await syncForEach(jobs, async job => {
|
||||
const gasLimit = addExtraGas(job.gasEstimate, EXTRA_GAS_PERCENTAGE)
|
||||
|
||||
try {
|
||||
logger.info(`Sending transaction with nonce ${nonce}`)
|
||||
const txHash = await sendTx({
|
||||
chain: config.queue,
|
||||
data: job.data,
|
||||
nonce,
|
||||
gasPrice: gasPrice.toString(10),
|
||||
amount: '0',
|
||||
gasLimit,
|
||||
privateKey: ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY,
|
||||
to: job.to,
|
||||
chainId,
|
||||
web3: web3Instance
|
||||
})
|
||||
|
||||
nonce++
|
||||
logger.info(
|
||||
{ eventTransactionHash: job.transactionReference, generatedTransactionHash: txHash },
|
||||
`Tx generated ${txHash} for event Tx ${job.transactionReference}`
|
||||
)
|
||||
} catch (e) {
|
||||
logger.error(
|
||||
{ eventTransactionHash: job.transactionReference, error: e.message },
|
||||
`Tx Failed for event Tx ${job.transactionReference}.`,
|
||||
e.message
|
||||
)
|
||||
|
||||
if (e.message.includes('Insufficient funds')) {
|
||||
const currentBalance = await web3Instance.eth.getBalance(ORACLE_VALIDATOR_ADDRESS)
|
||||
const minimumBalance = gasLimit.multipliedBy(gasPrice)
|
||||
logger.error(
|
||||
`Insufficient funds: ${currentBalance}. Stop processing messages until the balance is at least ${minimumBalance}.`
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
initialize()
|
||||
@@ -6,7 +6,7 @@ const { web3Home } = require('../../services/web3')
|
||||
const bridgeValidatorsABI = require('../../../../contracts/build/contracts/BridgeValidators').abi
|
||||
const { EXIT_CODES, MAX_CONCURRENT_EVENTS } = require('../../utils/constants')
|
||||
const estimateGas = require('./estimateGas')
|
||||
const { addTxHashToData, parseAMBMessage } = require('../../../../commons')
|
||||
const { parseAMBMessage } = require('../../../../commons')
|
||||
const { AlreadyProcessedError, AlreadySignedError, InvalidValidatorError } = require('../../utils/errors')
|
||||
|
||||
const limit = promiseLimit(MAX_CONCURRENT_EVENTS)
|
||||
@@ -30,20 +30,16 @@ function processAffirmationRequestsBuilder(config) {
|
||||
rootLogger.debug(`Processing ${affirmationRequests.length} AffirmationRequest events`)
|
||||
const callbacks = affirmationRequests
|
||||
.map(affirmationRequest => async () => {
|
||||
const { encodedData } = affirmationRequest.returnValues
|
||||
const { messageId, encodedData: message } = affirmationRequest.returnValues
|
||||
|
||||
const logger = rootLogger.child({
|
||||
eventTransactionHash: affirmationRequest.transactionHash
|
||||
})
|
||||
|
||||
const message = addTxHashToData({
|
||||
encodedData,
|
||||
transactionHash: affirmationRequest.transactionHash
|
||||
eventTransactionHash: affirmationRequest.transactionHash,
|
||||
eventMessageId: messageId
|
||||
})
|
||||
|
||||
const { sender, executor } = parseAMBMessage(message)
|
||||
|
||||
logger.info({ sender, executor }, `Processing affirmationRequest ${affirmationRequest.transactionHash}`)
|
||||
logger.info({ sender, executor }, `Processing affirmationRequest ${messageId}`)
|
||||
|
||||
let gasEstimate
|
||||
try {
|
||||
@@ -63,12 +59,10 @@ function processAffirmationRequestsBuilder(config) {
|
||||
logger.fatal({ address: config.validatorAddress }, 'Invalid validator')
|
||||
process.exit(EXIT_CODES.INCOMPATIBILITY)
|
||||
} else if (e instanceof AlreadySignedError) {
|
||||
logger.info(`Already signed affirmationRequest ${affirmationRequest.transactionHash}`)
|
||||
logger.info(`Already signed affirmationRequest ${messageId}`)
|
||||
return
|
||||
} else if (e instanceof AlreadyProcessedError) {
|
||||
logger.info(
|
||||
`affirmationRequest ${affirmationRequest.transactionHash} was already processed by other validators`
|
||||
)
|
||||
logger.info(`affirmationRequest ${messageId} was already processed by other validators`)
|
||||
return
|
||||
} else {
|
||||
logger.error(e, 'Unknown error while processing transaction')
|
||||
|
||||
@@ -17,7 +17,7 @@ async function estimateGas({
|
||||
r,
|
||||
s,
|
||||
signatures,
|
||||
txHash,
|
||||
messageId,
|
||||
address
|
||||
}) {
|
||||
try {
|
||||
@@ -32,7 +32,7 @@ async function estimateGas({
|
||||
|
||||
// check if the message was already processed
|
||||
logger.debug('Check if the message was already processed')
|
||||
const alreadyProcessed = await foreignBridge.methods.relayedMessages(txHash).call()
|
||||
const alreadyProcessed = await foreignBridge.methods.relayedMessages(messageId).call()
|
||||
if (alreadyProcessed) {
|
||||
throw new AlreadyProcessedError()
|
||||
}
|
||||
|
||||
@@ -69,7 +69,8 @@ function processCollectedSignaturesBuilder(config) {
|
||||
await Promise.all(signaturePromises)
|
||||
const signatures = packSignatures(signaturesArray)
|
||||
|
||||
const { txHash } = parseAMBMessage(message)
|
||||
const { messageId } = parseAMBMessage(message)
|
||||
logger.info(`Processing messageId: ${messageId}`)
|
||||
|
||||
let gasEstimate
|
||||
try {
|
||||
@@ -83,7 +84,7 @@ function processCollectedSignaturesBuilder(config) {
|
||||
signatures,
|
||||
message,
|
||||
numberOfCollectedSignatures: NumberOfCollectedSignatures,
|
||||
txHash,
|
||||
messageId,
|
||||
address: config.validatorAddress
|
||||
})
|
||||
logger.debug({ gasEstimate }, 'Gas estimated')
|
||||
|
||||
@@ -4,7 +4,7 @@ const { HttpListProviderError } = require('http-list-provider')
|
||||
const bridgeValidatorsABI = require('../../../../contracts/build/contracts/BridgeValidators').abi
|
||||
const rootLogger = require('../../services/logger')
|
||||
const { web3Home } = require('../../services/web3')
|
||||
const { addTxHashToData, parseAMBMessage } = require('../../../../commons')
|
||||
const { parseAMBMessage } = require('../../../../commons')
|
||||
const estimateGas = require('../processSignatureRequests/estimateGas')
|
||||
const { AlreadyProcessedError, AlreadySignedError, InvalidValidatorError } = require('../../utils/errors')
|
||||
const { EXIT_CODES, MAX_CONCURRENT_EVENTS } = require('../../utils/constants')
|
||||
@@ -32,19 +32,15 @@ function processSignatureRequestsBuilder(config) {
|
||||
rootLogger.debug(`Processing ${signatureRequests.length} SignatureRequest events`)
|
||||
const callbacks = signatureRequests
|
||||
.map(signatureRequest => async () => {
|
||||
const { encodedData } = signatureRequest.returnValues
|
||||
const { messageId, encodedData: message } = signatureRequest.returnValues
|
||||
|
||||
const logger = rootLogger.child({
|
||||
eventTransactionHash: signatureRequest.transactionHash
|
||||
})
|
||||
|
||||
const message = addTxHashToData({
|
||||
encodedData,
|
||||
transactionHash: signatureRequest.transactionHash
|
||||
eventTransactionHash: signatureRequest.transactionHash,
|
||||
eventMessageId: messageId
|
||||
})
|
||||
|
||||
const { sender, executor } = parseAMBMessage(message)
|
||||
logger.info({ sender, executor }, `Processing signatureRequest ${signatureRequest.transactionHash}`)
|
||||
logger.info({ sender, executor }, `Processing signatureRequest ${messageId}`)
|
||||
|
||||
const signature = web3Home.eth.accounts.sign(message, `0x${ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY}`)
|
||||
|
||||
@@ -67,12 +63,10 @@ function processSignatureRequestsBuilder(config) {
|
||||
logger.fatal({ address: config.validatorAddress }, 'Invalid validator')
|
||||
process.exit(EXIT_CODES.INCOMPATIBILITY)
|
||||
} else if (e instanceof AlreadySignedError) {
|
||||
logger.info(`Already signed signatureRequest ${signatureRequest.transactionHash}`)
|
||||
logger.info(`Already signed signatureRequest ${messageId}`)
|
||||
return
|
||||
} else if (e instanceof AlreadyProcessedError) {
|
||||
logger.info(
|
||||
`signatureRequest ${signatureRequest.transactionHash} was already processed by other validators`
|
||||
)
|
||||
logger.info(`signatureRequest ${messageId} was already processed by other validators`)
|
||||
return
|
||||
} else {
|
||||
logger.error(e, 'Unknown error while processing transaction')
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
require('../../env')
|
||||
const url = require('url')
|
||||
const dns = require('dns')
|
||||
const connection = require('amqp-connection-manager').connect(process.env.ORACLE_QUEUE_URL)
|
||||
const logger = require('./logger')
|
||||
const { getRetrySequence } = require('../utils/utils')
|
||||
@@ -11,6 +13,14 @@ connection.on('disconnect', () => {
|
||||
logger.error('Disconnected from amqp Broker')
|
||||
})
|
||||
|
||||
async function isAttached() {
|
||||
if (!process.env.ORACLE_QUEUE_URL) {
|
||||
return false
|
||||
}
|
||||
const amqpHost = new url.URL(process.env.ORACLE_QUEUE_URL).hostname
|
||||
return new Promise(res => dns.lookup(amqpHost, err => res(err === null)))
|
||||
}
|
||||
|
||||
function connectWatcherToQueue({ queueName, workerQueue, cb }) {
|
||||
const queueList = workerQueue ? [queueName, workerQueue] : [queueName]
|
||||
|
||||
@@ -119,6 +129,7 @@ async function generateRetry({ data, msgRetries, channelWrapper, channel, queueN
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
isAttached,
|
||||
connectWatcherToQueue,
|
||||
connectSenderToQueue,
|
||||
connectWorkerToQueue,
|
||||
|
||||
@@ -45,7 +45,7 @@ const fetchGasPrice = async (speedType, factor, bridgeContract, gasPriceSupplier
|
||||
return cachedGasPrice
|
||||
}
|
||||
|
||||
async function start(chainId) {
|
||||
async function start(chainId, fetchOnce) {
|
||||
clearInterval(fetchGasPriceInterval)
|
||||
|
||||
let bridgeContract = null
|
||||
@@ -73,10 +73,16 @@ async function start(chainId) {
|
||||
throw new Error(`Unrecognized chainId '${chainId}'`)
|
||||
}
|
||||
|
||||
if (fetchOnce) {
|
||||
await fetchGasPrice(speedType, factor, bridgeContract, () => fetch(gasPriceSupplierUrl))
|
||||
return getPrice()
|
||||
}
|
||||
|
||||
fetchGasPriceInterval = setIntervalAndRun(
|
||||
() => fetchGasPrice(speedType, factor, bridgeContract, () => fetch(gasPriceSupplierUrl)),
|
||||
updateInterval
|
||||
)
|
||||
return null
|
||||
}
|
||||
|
||||
function getPrice() {
|
||||
|
||||
@@ -69,10 +69,34 @@ async function getEvents({ contract, event, fromBlock, toBlock, filter }) {
|
||||
}
|
||||
}
|
||||
|
||||
async function getEventsFromTx({ web3, contract, event, txHash, filter }) {
|
||||
try {
|
||||
const contractAddress = contract.options.address
|
||||
logger.info({ contractAddress, event, txHash }, 'Getting past events for specific transaction')
|
||||
const { logs } = await web3.eth.getTransactionReceipt(txHash)
|
||||
const eventAbi = contract.options.jsonInterface.find(abi => abi.name === event)
|
||||
const decodeAbi = contract._decodeEventABI.bind(eventAbi)
|
||||
const pastEvents = logs
|
||||
.filter(event => event.topics[0] === eventAbi.signature)
|
||||
.map(decodeAbi)
|
||||
.filter(event =>
|
||||
eventAbi.inputs.every(arg => {
|
||||
const encodeParam = param => web3.eth.abi.encodeParameter(arg.type, param)
|
||||
return !filter[arg.name] || encodeParam(filter[arg.name]) === encodeParam(event.returnValues[arg.name])
|
||||
})
|
||||
)
|
||||
logger.debug({ contractAddress, event, count: pastEvents.length }, 'Past events obtained')
|
||||
return pastEvents
|
||||
} catch (e) {
|
||||
throw new Error(`${event} events cannot be obtained`)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getNonce,
|
||||
getBlockNumber,
|
||||
getChainId,
|
||||
getRequiredBlockConfirmations,
|
||||
getEvents
|
||||
getEvents,
|
||||
getEventsFromTx
|
||||
}
|
||||
|
||||
@@ -7,18 +7,18 @@
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"wsrun": "3.6.5",
|
||||
"eslint-config-prettier": "3.1.0",
|
||||
"eslint": "5.16.0",
|
||||
"eslint-config-airbnb": "17.1.0",
|
||||
"eslint-config-prettier": "3.1.0",
|
||||
"eslint-plugin-flowtype": "^3.8.1",
|
||||
"eslint-plugin-jsx-a11y": "^6.2.1",
|
||||
"eslint-plugin-node": "7.0.1",
|
||||
"eslint-plugin-prettier": "2.6.2",
|
||||
"eslint-plugin-react": "^7.13.0",
|
||||
"eslint-plugin-react-hooks": "^1.6.0",
|
||||
"eslint-plugin-flowtype": "^3.8.1",
|
||||
"mocha": "^5.2.0",
|
||||
"prettier": "1.14.3",
|
||||
"mocha": "^5.2.0"
|
||||
"wsrun": "3.6.5"
|
||||
},
|
||||
"workspaces": [
|
||||
"commons",
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
"maxCodeSize": 24576,
|
||||
"maxCodeSizeTransition": "0x0",
|
||||
"eip140Transition": "0x0",
|
||||
"eip145Transition": "0x0",
|
||||
"eip211Transition": "0x0",
|
||||
"eip214Transition": "0x0",
|
||||
"eip658Transition": "0x0",
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
"maxCodeSize": 24576,
|
||||
"maxCodeSizeTransition": "0x0",
|
||||
"eip140Transition": "0x0",
|
||||
"eip145Transition": "0x0",
|
||||
"eip211Transition": "0x0",
|
||||
"eip214Transition": "0x0",
|
||||
"eip658Transition": "0x0",
|
||||
|
||||
@@ -5,6 +5,7 @@ const {
|
||||
nativeToErcBridge,
|
||||
ercToErcBridge,
|
||||
ercToNativeBridge,
|
||||
ambStakeErcToErc,
|
||||
homeRPC,
|
||||
foreignRPC
|
||||
} = require('../e2e-commons/constants.json')
|
||||
@@ -38,6 +39,10 @@ class Utils {
|
||||
return ercToNativeBridge.ui
|
||||
}
|
||||
|
||||
static async getAMBStakeStartURL() {
|
||||
return ambStakeErcToErc.ui
|
||||
}
|
||||
|
||||
static async startBrowserWithMetamask() {
|
||||
const source = './MetaMask.crx'
|
||||
const options = new chrome.Options()
|
||||
|
||||
@@ -2,7 +2,7 @@ const { By } = require('selenium-webdriver/lib/by')
|
||||
const { Page } = require('./Page.js')
|
||||
|
||||
const fieldAmount = By.id('amount')
|
||||
const buttonTransfer = By.className('bridge-form-button ')
|
||||
const buttonTransfer = By.className('bridge-form-button')
|
||||
const buttonOk = By.className('swal-button swal-button--confirm')
|
||||
const fieldsBalance = By.className('network-balance')
|
||||
const classWeb3Loaded = By.className('web3-loaded')
|
||||
|
||||
@@ -308,4 +308,94 @@ test.describe('e2e-test for bridge.poa, version 1.5.0', async function() {
|
||||
return await assert.strictEqual(result, true, 'Test FAILED. Foreign POA balance is not correct after transaction')
|
||||
})
|
||||
})
|
||||
|
||||
test.describe('AMB-STAKE-ERC-TO-ERC', async () => {
|
||||
test.it('User is able to open main page of bridge-ui ', async () => {
|
||||
startURL = await Utils.getAMBStakeStartURL()
|
||||
const result = await mainPage.open(startURL)
|
||||
console.log('Test URL: ' + startURL)
|
||||
return await assert.strictEqual(result, true, 'Test FAILED. Build failed.')
|
||||
})
|
||||
|
||||
test.it('Home page: disclaimer is displayed ', async () => {
|
||||
const result = await mainPage.confirmDisclaimer()
|
||||
return await assert.strictEqual(result, true, 'Test FAILED. Disclaimer is not displayed')
|
||||
})
|
||||
|
||||
test.it('Main page: foreign erc20 balance is displayed', async () => {
|
||||
await foreignAccount.setMetaMaskNetwork()
|
||||
foreignBalanceBefore = await mainPage.getForeignPOABalance()
|
||||
console.log('foreignBalanceBefore = ' + foreignBalanceBefore)
|
||||
const result = foreignBalanceBefore !== 0
|
||||
return await assert.strictEqual(result, true, 'Test FAILED. Foreign erc20 balance is zero')
|
||||
})
|
||||
|
||||
test.it('Main page: home erc20 balance is displayed', async () => {
|
||||
homeBalanceBefore = await mainPage.getHomePOABalance()
|
||||
console.log('homeBalanceBefore = ' + homeBalanceBefore)
|
||||
const result = homeBalanceBefore !== 0
|
||||
return await assert.strictEqual(result, true, 'Test FAILED. Home erc20 balance is zero or not displayed ')
|
||||
})
|
||||
|
||||
test.it('User is able to send tokens from Foreign account to Home account', async () => {
|
||||
homeBalanceBefore = await mainPage.getForeignPOABalance()
|
||||
foreignBalanceBefore = await mainPage.getHomePOABalance()
|
||||
const result = await foreignAccount.transferTokens(maxAmountPerTransactionLimit)
|
||||
return await assert.strictEqual(
|
||||
result,
|
||||
true,
|
||||
'Test FAILED. User is able send tokens from Foreign account to Home account'
|
||||
)
|
||||
})
|
||||
|
||||
test.it('Foreign POA balance has correctly changed after transaction', async () => {
|
||||
const newForeignBalance = await mainPage.getHomePOABalance()
|
||||
const shouldBe = foreignBalanceBefore - maxAmountPerTransactionLimit
|
||||
console.log('newForeignBalance = ' + newForeignBalance)
|
||||
console.log('shouldBe = ' + shouldBe)
|
||||
const result = Math.abs(shouldBe - newForeignBalance) < maxAmountPerTransactionLimit / 100
|
||||
return await assert.strictEqual(result, true, 'Test FAILED.Foreign POA balance is not correct after transaction')
|
||||
})
|
||||
|
||||
test.it('Home account has received correct amount of tokens after transaction', async () => {
|
||||
const newHomeBalance = await mainPage.getForeignPOABalance()
|
||||
const shouldBe = homeBalanceBefore + maxAmountPerTransactionLimit
|
||||
console.log('newHomeBalance = ' + newHomeBalance)
|
||||
console.log('shouldBe = ' + shouldBe)
|
||||
const result = Math.abs(shouldBe - newHomeBalance) < maxAmountPerTransactionLimit / 100
|
||||
return await assert.strictEqual(result, true, 'Test FAILED.Home POA balance is not correct after transaction')
|
||||
})
|
||||
test.it('User is able to send tokens from Home account to Foreign account', async () => {
|
||||
await homeAccount.setMetaMaskNetwork()
|
||||
homeBalanceBefore = await mainPage.getHomePOABalance()
|
||||
foreignBalanceBefore = await mainPage.getForeignPOABalance()
|
||||
const result = await homeAccount.transferTokens(maxAmountPerTransactionLimit)
|
||||
return await assert.strictEqual(
|
||||
result,
|
||||
true,
|
||||
'Test FAILED. User is able send tokens from Home account to Foreign account'
|
||||
)
|
||||
})
|
||||
|
||||
test.it('Home POA balance has correctly changed after transaction', async () => {
|
||||
const newHomeBalance = await mainPage.getHomePOABalance()
|
||||
const shouldBe = homeBalanceBefore - maxAmountPerTransactionLimit
|
||||
console.log('newHomeBalance = ' + newHomeBalance)
|
||||
console.log('shouldBe = ' + shouldBe)
|
||||
const result = Math.abs(shouldBe - newHomeBalance) < maxAmountPerTransactionLimit / 100
|
||||
homeBalanceBefore = newHomeBalance
|
||||
return await assert.strictEqual(result, true, 'Test FAILED.Home POA balance is not correct after transaction')
|
||||
})
|
||||
|
||||
test.it('Foreign account has received correct amount of tokens after transaction', async () => {
|
||||
const newForeignBalance = await mainPage.getForeignPOABalance()
|
||||
|
||||
const shouldBe = foreignBalanceBefore + maxAmountPerTransactionLimit
|
||||
console.log('newForeignBalance = ' + newForeignBalance)
|
||||
console.log('shouldBe = ' + shouldBe)
|
||||
|
||||
const result = Math.abs(shouldBe - newForeignBalance) < maxAmountPerTransactionLimit / 100
|
||||
return await assert.strictEqual(result, true, 'Test FAILED. Foreign POA balance is not correct after transaction')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -32,11 +32,15 @@ COMMON_FOREIGN_GAS_PRICE_FACTOR=1
|
||||
|
||||
# Default
|
||||
UI_TITLE=TokenBridge UI app - %c
|
||||
UI_OG_TITLE=POA Bridge UI
|
||||
UI_DESCRIPTION=The POA cross-chain bridge serves as a method of transferring POA native tokens from the POA Network to the Ethereum network in a quick and cost-efficient manner.
|
||||
UI_PORT=3000
|
||||
UI_PUBLIC_URL=https://bridge.poa.net
|
||||
|
||||
# RSK
|
||||
#UI_DESCRIPTION=The TokenBridge serves as a method of transferring Bancor Network tokens between the Ethereum network and the Rootstock network in a quick and cost-efficient manner.
|
||||
|
||||
# To use Ethereum-classic styles
|
||||
#UI_STYLES=classic
|
||||
# To use Ethereum-classic styles: classic
|
||||
# To use STAKE styles: stake
|
||||
# To use poa core styles: core
|
||||
UI_STYLES=core
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"bignumber.js": "^6.0.0",
|
||||
"coveralls": "^3.0.0",
|
||||
"customize-cra": "^0.2.12",
|
||||
"date-fns": "^2.13.0",
|
||||
"dotenv": "^7.0.0",
|
||||
"fs-extra": "^5.0.0",
|
||||
"mobx": "^4.0.2",
|
||||
|
||||
|
Before Width: | Height: | Size: 3.8 KiB |
BIN
ui/public/favicons/classic.ico
Normal file
|
After Width: | Height: | Size: 7.7 KiB |
BIN
ui/public/favicons/core.ico
Normal file
|
After Width: | Height: | Size: 7.7 KiB |
@@ -15,4 +15,4 @@
|
||||
"theme_color": "#ffffff",
|
||||
"background_color": "#ffffff",
|
||||
"display": "standalone"
|
||||
}
|
||||
}
|
||||
|
||||
BIN
ui/public/favicons/stake.ico
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 144 KiB |
BIN
ui/public/images/ogimage-classic.png
Normal file
|
After Width: | Height: | Size: 852 KiB |
BIN
ui/public/images/ogimage-core.png
Normal file
|
After Width: | Height: | Size: 852 KiB |
BIN
ui/public/images/ogimage-stake.png
Normal file
|
After Width: | Height: | Size: 37 KiB |
@@ -5,14 +5,13 @@
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="theme-color" content="#000000">
|
||||
<meta property="og:title" content="POA Bridge UI" />
|
||||
<meta property="og:title" content="%REACT_APP_UI_OG_TITLE%" />
|
||||
<meta property="og:description" content="%REACT_APP_UI_DESCRIPTION%" />
|
||||
<meta property="og:url" content="https://poanetwork.github.io/bridge-ui" />
|
||||
<meta property="og:url" content="%REACT_APP_UI_PUBLIC_URL%" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:image" content="/images/bridgeogimage.jpg">
|
||||
<link href="https://fonts.googleapis.com/css?family=Nunito:300,400,700" rel="stylesheet">
|
||||
<link rel="manifest" href="%PUBLIC_URL%/favicons/manifest.json">
|
||||
<link rel="shortcut icon" href="%PUBLIC_URL%/favicons/favicon.ico">
|
||||
<meta property="og:image" content="%REACT_APP_UI_PUBLIC_URL%/images/ogimage-%REACT_APP_UI_STYLES%.png">
|
||||
<link rel="manifest" href="/favicons/manifest.json">
|
||||
<link rel="shortcut icon" href="/favicons/%REACT_APP_UI_STYLES%.ico">
|
||||
<title>TokenBridge UI app</title>
|
||||
</head>
|
||||
|
||||
|
||||
@@ -6,12 +6,7 @@ const fs = require('fs')
|
||||
|
||||
const stylePath = path.resolve(__dirname, '..', 'src', 'assets', 'stylesheets')
|
||||
const destinationFilename = 'application.css'
|
||||
let filename
|
||||
|
||||
if (process.env.UI_STYLES === 'classic') {
|
||||
filename = 'application.classic.css'
|
||||
} else {
|
||||
filename = 'application.core.css'
|
||||
}
|
||||
const theme = process.env.UI_STYLES || 'core'
|
||||
const filename = `application.${theme}.css`
|
||||
|
||||
fs.copyFileSync(path.resolve(stylePath, filename), path.resolve(stylePath, destinationFilename))
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<svg width="220" height="105" viewBox="0 0 220 105" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<mask id="path-1-inside-1" fill="white">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M112.828 1.85788C111.266 0.295785 108.734 0.295786 107.172 1.85788L100.029 9.00001H4C1.79086 9.00001 0 10.7909 0 13V101C0 103.209 1.79086 105 4 105H216C218.209 105 220 103.209 220 101V13C220 10.7909 218.209 9.00001 216 9.00001H119.971L112.828 1.85788Z"/>
|
||||
</mask>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M112.828 1.85788C111.266 0.295785 108.734 0.295786 107.172 1.85788L100.029 9.00001H4C1.79086 9.00001 0 10.7909 0 13V101C0 103.209 1.79086 105 4 105H216C218.209 105 220 103.209 220 101V13C220 10.7909 218.209 9.00001 216 9.00001H119.971L112.828 1.85788Z" fill="white"/>
|
||||
<path d="M107.172 1.85788L106.464 1.15077V1.15078L107.172 1.85788ZM112.828 1.85788L113.536 1.15078V1.15077L112.828 1.85788ZM100.029 9.00001V10H100.444L100.737 9.70711L100.029 9.00001ZM119.971 9.00001L119.263 9.70711L119.556 10H119.971V9.00001ZM107.879 2.56499C109.05 1.39342 110.95 1.39342 112.121 2.56499L113.536 1.15077C111.583 -0.801845 108.417 -0.801845 106.464 1.15077L107.879 2.56499ZM100.737 9.70711L107.879 2.56499L106.464 1.15078L99.3223 8.2929L100.737 9.70711ZM4 10H100.029V8.00001H4V10ZM1 13C1 11.3432 2.34315 10 4 10V8.00001C1.23858 8.00001 -1 10.2386 -1 13H1ZM1 101V13H-1V101H1ZM4 104C2.34314 104 1 102.657 1 101H-1C-1 103.761 1.23857 106 4 106V104ZM216 104H4V106H216V104ZM219 101C219 102.657 217.657 104 216 104V106C218.761 106 221 103.761 221 101H219ZM219 13V101H221V13H219ZM216 10C217.657 10 219 11.3432 219 13H221C221 10.2386 218.761 8.00001 216 8.00001V10ZM119.971 10H216V8.00001H119.971V10ZM112.121 2.56499L119.263 9.70711L120.678 8.2929L113.536 1.15078L112.121 2.56499Z" fill="#E6ECF1" mask="url(#path-1-inside-1)"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1,7 @@
|
||||
<svg width="127" height="89" viewBox="0 0 127 89" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<mask id="path-1-inside-1" fill="white">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M65.8284 1.17157C64.2663 -0.390524 61.7337 -0.390524 60.1716 1.17157L53.3431 8.00001H4C1.79086 8.00001 0 9.79086 0 12V85C0 87.2091 1.79086 89 4 89H123C125.209 89 127 87.2092 127 85V12C127 9.79087 125.209 8.00001 123 8.00001H72.6569L65.8284 1.17157Z"/>
|
||||
</mask>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M65.8284 1.17157C64.2663 -0.390524 61.7337 -0.390524 60.1716 1.17157L53.3431 8.00001H4C1.79086 8.00001 0 9.79086 0 12V85C0 87.2091 1.79086 89 4 89H123C125.209 89 127 87.2092 127 85V12C127 9.79087 125.209 8.00001 123 8.00001H72.6569L65.8284 1.17157Z" fill="white"/>
|
||||
<path d="M60.1716 1.17157L60.8787 1.87868V1.87868L60.1716 1.17157ZM65.8284 1.17157L66.5355 0.464466V0.464465L65.8284 1.17157ZM53.3431 8.00001V9.00001H53.7574L54.0502 8.70711L53.3431 8.00001ZM72.6569 8.00001L71.9498 8.70711L72.2426 9.00001H72.6569V8.00001ZM60.8787 1.87868C62.0503 0.707108 63.9497 0.707105 65.1213 1.87868L66.5355 0.464465C64.5829 -1.48815 61.4171 -1.48816 59.4645 0.464467L60.8787 1.87868ZM54.0502 8.70711L60.8787 1.87868L59.4645 0.464466L52.636 7.2929L54.0502 8.70711ZM4 9.00001H53.3431V7.00001H4V9.00001ZM1 12C1 10.3431 2.34314 9.00001 4 9.00001V7.00001C1.23858 7.00001 -1 9.23858 -1 12H1ZM1 85V12H-1V85H1ZM4 88C2.34314 88 1 86.6569 1 85H-1C-1 87.7614 1.23857 90 4 90V88ZM123 88H4V90H123V88ZM126 85C126 86.6569 124.657 88 123 88V90C125.761 90 128 87.7614 128 85H126ZM126 12V85H128V12H126ZM123 9.00001C124.657 9.00001 126 10.3432 126 12H128C128 9.23858 125.761 7.00001 123 7.00001V9.00001ZM72.6569 9.00001H123V7.00001H72.6569V9.00001ZM65.1213 1.87868L71.9498 8.70711L73.364 7.2929L66.5355 0.464466L65.1213 1.87868Z" fill="#E6ECF1" mask="url(#path-1-inside-1)"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
BIN
ui/src/assets/images/themes/core/transparent.png
Normal file
|
After Width: | Height: | Size: 110 B |
@@ -0,0 +1,7 @@
|
||||
<svg width="220" height="105" viewBox="0 0 220 105" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<mask id="path-1-inside-1" fill="white">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M112.828 1.85788C111.266 0.295785 108.734 0.295786 107.172 1.85788L100.029 9.00001H4C1.79086 9.00001 0 10.7909 0 13V101C0 103.209 1.79086 105 4 105H216C218.209 105 220 103.209 220 101V13C220 10.7909 218.209 9.00001 216 9.00001H119.971L112.828 1.85788Z"/>
|
||||
</mask>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M112.828 1.85788C111.266 0.295785 108.734 0.295786 107.172 1.85788L100.029 9.00001H4C1.79086 9.00001 0 10.7909 0 13V101C0 103.209 1.79086 105 4 105H216C218.209 105 220 103.209 220 101V13C220 10.7909 218.209 9.00001 216 9.00001H119.971L112.828 1.85788Z" fill="white"/>
|
||||
<path d="M107.172 1.85788L106.464 1.15077V1.15078L107.172 1.85788ZM112.828 1.85788L113.536 1.15078V1.15077L112.828 1.85788ZM100.029 9.00001V10H100.444L100.737 9.70711L100.029 9.00001ZM119.971 9.00001L119.263 9.70711L119.556 10H119.971V9.00001ZM107.879 2.56499C109.05 1.39342 110.95 1.39342 112.121 2.56499L113.536 1.15077C111.583 -0.801845 108.417 -0.801845 106.464 1.15077L107.879 2.56499ZM100.737 9.70711L107.879 2.56499L106.464 1.15078L99.3223 8.2929L100.737 9.70711ZM4 10H100.029V8.00001H4V10ZM1 13C1 11.3432 2.34315 10 4 10V8.00001C1.23858 8.00001 -1 10.2386 -1 13H1ZM1 101V13H-1V101H1ZM4 104C2.34314 104 1 102.657 1 101H-1C-1 103.761 1.23857 106 4 106V104ZM216 104H4V106H216V104ZM219 101C219 102.657 217.657 104 216 104V106C218.761 106 221 103.761 221 101H219ZM219 13V101H221V13H219ZM216 10C217.657 10 219 11.3432 219 13H221C221 10.2386 218.761 8.00001 216 8.00001V10ZM119.971 10H216V8.00001H119.971V10ZM112.121 2.56499L119.263 9.70711L120.678 8.2929L113.536 1.15078L112.121 2.56499Z" fill="#E6ECF1" mask="url(#path-1-inside-1)"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1,7 @@
|
||||
<svg width="127" height="89" viewBox="0 0 127 89" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<mask id="path-1-inside-1" fill="white">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M65.8284 1.17157C64.2663 -0.390524 61.7337 -0.390524 60.1716 1.17157L53.3431 8.00001H4C1.79086 8.00001 0 9.79086 0 12V85C0 87.2091 1.79086 89 4 89H123C125.209 89 127 87.2092 127 85V12C127 9.79087 125.209 8.00001 123 8.00001H72.6569L65.8284 1.17157Z"/>
|
||||
</mask>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M65.8284 1.17157C64.2663 -0.390524 61.7337 -0.390524 60.1716 1.17157L53.3431 8.00001H4C1.79086 8.00001 0 9.79086 0 12V85C0 87.2091 1.79086 89 4 89H123C125.209 89 127 87.2092 127 85V12C127 9.79087 125.209 8.00001 123 8.00001H72.6569L65.8284 1.17157Z" fill="white"/>
|
||||
<path d="M60.1716 1.17157L60.8787 1.87868V1.87868L60.1716 1.17157ZM65.8284 1.17157L66.5355 0.464466V0.464465L65.8284 1.17157ZM53.3431 8.00001V9.00001H53.7574L54.0502 8.70711L53.3431 8.00001ZM72.6569 8.00001L71.9498 8.70711L72.2426 9.00001H72.6569V8.00001ZM60.8787 1.87868C62.0503 0.707108 63.9497 0.707105 65.1213 1.87868L66.5355 0.464465C64.5829 -1.48815 61.4171 -1.48816 59.4645 0.464467L60.8787 1.87868ZM54.0502 8.70711L60.8787 1.87868L59.4645 0.464466L52.636 7.2929L54.0502 8.70711ZM4 9.00001H53.3431V7.00001H4V9.00001ZM1 12C1 10.3431 2.34314 9.00001 4 9.00001V7.00001C1.23858 7.00001 -1 9.23858 -1 12H1ZM1 85V12H-1V85H1ZM4 88C2.34314 88 1 86.6569 1 85H-1C-1 87.7614 1.23857 90 4 90V88ZM123 88H4V90H123V88ZM126 85C126 86.6569 124.657 88 123 88V90C125.761 90 128 87.7614 128 85H126ZM126 12V85H128V12H126ZM123 9.00001C124.657 9.00001 126 10.3432 126 12H128C128 9.23858 125.761 7.00001 123 7.00001V9.00001ZM72.6569 9.00001H123V7.00001H72.6569V9.00001ZM65.1213 1.87868L71.9498 8.70711L73.364 7.2929L66.5355 0.464466L65.1213 1.87868Z" fill="#E6ECF1" mask="url(#path-1-inside-1)"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
22
ui/src/assets/images/themes/stake/background/bg-pattern.svg
Normal file
@@ -0,0 +1,22 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="360">
|
||||
<path fill="#90E1D9" fill-rule="evenodd" d="M120 300h60v60h-60v-60z"/>
|
||||
<path fill="#5B33A2" fill-rule="evenodd" d="M120 360c-33.137 0-60-26.863-60-60h60v60z"/>
|
||||
<path fill="#90E1D9" fill-rule="evenodd" d="M60 240h60v60H60v-60z"/>
|
||||
<path fill="#5B33A2" fill-rule="evenodd" d="M120 240H60v-60c33.137 0 60 26.863 60 60z"/>
|
||||
<path fill="#9987FC" fill-rule="evenodd" d="M60 240c-33.137 0-60-26.863-60-60h60v60z"/>
|
||||
<path fill="#90E1D9" fill-rule="evenodd" d="M0 180c0-33.137 26.863-60 60-60v60H0z"/>
|
||||
<path fill="#5B33A2" fill-rule="evenodd" d="M60 180v-60h60c0 33.137-26.863 60-60 60z"/>
|
||||
<path fill="#61DC97" fill-rule="evenodd" d="M60 60h60v60H60V60z"/>
|
||||
<path fill="#9987FC" fill-rule="evenodd" d="M60 60c0-33.137 26.863-60 60-60v60H60z"/>
|
||||
<path fill="#5B33A2" fill-rule="evenodd" d="M120 0h60v60h-60V0z"/>
|
||||
<path fill="#9987FC" fill-rule="evenodd" d="M300 300h60v60h-60v-60z"/>
|
||||
<path fill="#5B33A2" fill-rule="evenodd" d="M300 360c-33.137 0-60-26.863-60-60h60v60z"/>
|
||||
<path fill="#61DC97" fill-rule="evenodd" d="M240 240h60v60h-60v-60z"/>
|
||||
<path fill="#5B33A2" fill-rule="evenodd" d="M300 240h-60v-60c33.137 0 60 26.863 60 60z"/>
|
||||
<path fill="#9987FC" fill-rule="evenodd" d="M240 240c-33.137 0-60-26.863-60-60h60v60z"/>
|
||||
<path fill="#5B33A2" fill-rule="evenodd" d="M180 180c0-33.137 26.863-60 60-60v60h-60z"/>
|
||||
<path fill="#90E1D9" fill-rule="evenodd" d="M240 180v-60h60c0 33.137-26.863 60-60 60z"/>
|
||||
<path fill="#61DC97" fill-rule="evenodd" d="M240 60h60v60h-60V60z"/>
|
||||
<path fill="#5B33A2" fill-rule="evenodd" d="M240 60c0-33.137 26.863-60 60-60v60h-60z"/>
|
||||
<path fill="#90E1D9" fill-rule="evenodd" d="M300 0h60v60h-60V0z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
3
ui/src/assets/images/themes/stake/bridge/arrow.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M19.0917 10.7071C19.4823 10.3166 19.4822 9.68341 19.0917 9.29289L10.6064 0.807612C10.2159 0.417093 9.58277 0.417072 9.19223 0.807612C8.80169 1.19815 8.80171 1.83131 9.19223 2.22183L16.9704 10L9.19223 17.7782C8.80169 18.1687 8.80171 18.8019 9.19223 19.1924C9.58275 19.5829 10.2159 19.5829 10.6064 19.1924L19.0917 10.7071Z" fill="#9EAAB6"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 451 B |
|
After Width: | Height: | Size: 6.5 KiB |
@@ -0,0 +1,3 @@
|
||||
<svg width="1" height="200" viewBox="0 0 1 200" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="1" height="200" fill="#E6ECF1"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 149 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="1" height="199" viewBox="0 0 1 199" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="1" height="199" fill="#E6ECF1"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 149 B |
3
ui/src/assets/images/themes/stake/bridge/close.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M17.2923 17.2923C16.9011 17.6835 16.2669 17.6835 15.8757 17.2923L8.79285 10.2094L1.70996 17.2923C1.31878 17.6835 0.684559 17.6835 0.293382 17.2923C-0.0977942 16.9011 -0.0977941 16.2669 0.293383 15.8757L7.37627 8.79285L0.293383 1.70996C-0.0977941 1.31878 -0.0977942 0.684559 0.293382 0.293382C0.684559 -0.0977943 1.31878 -0.097794 1.70996 0.293383L8.79285 7.37627L15.8757 0.293407C16.2669 -0.09777 16.9011 -0.0977703 17.2923 0.293406C17.6835 0.684583 17.6835 1.31881 17.2923 1.70998L10.2094 8.79285L17.2923 15.8757C17.6835 16.2669 17.6835 16.9011 17.2923 17.2923Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 731 B |
@@ -0,0 +1,7 @@
|
||||
<svg width="220" height="105" viewBox="0 0 220 105" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<mask id="path-1-inside-1" fill="white">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M112.828 1.85788C111.266 0.295785 108.734 0.295786 107.172 1.85788L100.029 9.00001H4C1.79086 9.00001 0 10.7909 0 13V101C0 103.209 1.79086 105 4 105H216C218.209 105 220 103.209 220 101V13C220 10.7909 218.209 9.00001 216 9.00001H119.971L112.828 1.85788Z"/>
|
||||
</mask>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M112.828 1.85788C111.266 0.295785 108.734 0.295786 107.172 1.85788L100.029 9.00001H4C1.79086 9.00001 0 10.7909 0 13V101C0 103.209 1.79086 105 4 105H216C218.209 105 220 103.209 220 101V13C220 10.7909 218.209 9.00001 216 9.00001H119.971L112.828 1.85788Z" fill="white"/>
|
||||
<path d="M107.172 1.85788L106.464 1.15077V1.15078L107.172 1.85788ZM112.828 1.85788L113.536 1.15078V1.15077L112.828 1.85788ZM100.029 9.00001V10H100.444L100.737 9.70711L100.029 9.00001ZM119.971 9.00001L119.263 9.70711L119.556 10H119.971V9.00001ZM107.879 2.56499C109.05 1.39342 110.95 1.39342 112.121 2.56499L113.536 1.15077C111.583 -0.801845 108.417 -0.801845 106.464 1.15077L107.879 2.56499ZM100.737 9.70711L107.879 2.56499L106.464 1.15078L99.3223 8.2929L100.737 9.70711ZM4 10H100.029V8.00001H4V10ZM1 13C1 11.3432 2.34315 10 4 10V8.00001C1.23858 8.00001 -1 10.2386 -1 13H1ZM1 101V13H-1V101H1ZM4 104C2.34314 104 1 102.657 1 101H-1C-1 103.761 1.23857 106 4 106V104ZM216 104H4V106H216V104ZM219 101C219 102.657 217.657 104 216 104V106C218.761 106 221 103.761 221 101H219ZM219 13V101H221V13H219ZM216 10C217.657 10 219 11.3432 219 13H221C221 10.2386 218.761 8.00001 216 8.00001V10ZM119.971 10H216V8.00001H119.971V10ZM112.121 2.56499L119.263 9.70711L120.678 8.2929L113.536 1.15078L112.121 2.56499Z" fill="#E6ECF1" mask="url(#path-1-inside-1)"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1,7 @@
|
||||
<svg width="127" height="89" viewBox="0 0 127 89" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<mask id="path-1-inside-1" fill="white">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M65.8284 1.17157C64.2663 -0.390524 61.7337 -0.390524 60.1716 1.17157L53.3431 8.00001H4C1.79086 8.00001 0 9.79086 0 12V85C0 87.2091 1.79086 89 4 89H123C125.209 89 127 87.2092 127 85V12C127 9.79087 125.209 8.00001 123 8.00001H72.6569L65.8284 1.17157Z"/>
|
||||
</mask>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M65.8284 1.17157C64.2663 -0.390524 61.7337 -0.390524 60.1716 1.17157L53.3431 8.00001H4C1.79086 8.00001 0 9.79086 0 12V85C0 87.2091 1.79086 89 4 89H123C125.209 89 127 87.2092 127 85V12C127 9.79087 125.209 8.00001 123 8.00001H72.6569L65.8284 1.17157Z" fill="white"/>
|
||||
<path d="M60.1716 1.17157L60.8787 1.87868V1.87868L60.1716 1.17157ZM65.8284 1.17157L66.5355 0.464466V0.464465L65.8284 1.17157ZM53.3431 8.00001V9.00001H53.7574L54.0502 8.70711L53.3431 8.00001ZM72.6569 8.00001L71.9498 8.70711L72.2426 9.00001H72.6569V8.00001ZM60.8787 1.87868C62.0503 0.707108 63.9497 0.707105 65.1213 1.87868L66.5355 0.464465C64.5829 -1.48815 61.4171 -1.48816 59.4645 0.464467L60.8787 1.87868ZM54.0502 8.70711L60.8787 1.87868L59.4645 0.464466L52.636 7.2929L54.0502 8.70711ZM4 9.00001H53.3431V7.00001H4V9.00001ZM1 12C1 10.3431 2.34314 9.00001 4 9.00001V7.00001C1.23858 7.00001 -1 9.23858 -1 12H1ZM1 85V12H-1V85H1ZM4 88C2.34314 88 1 86.6569 1 85H-1C-1 87.7614 1.23857 90 4 90V88ZM123 88H4V90H123V88ZM126 85C126 86.6569 124.657 88 123 88V90C125.761 90 128 87.7614 128 85H126ZM126 12V85H128V12H126ZM123 9.00001C124.657 9.00001 126 10.3432 126 12H128C128 9.23858 125.761 7.00001 123 7.00001V9.00001ZM72.6569 9.00001H123V7.00001H72.6569V9.00001ZM65.1213 1.87868L71.9498 8.70711L73.364 7.2929L66.5355 0.464466L65.1213 1.87868Z" fill="#E6ECF1" mask="url(#path-1-inside-1)"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
BIN
ui/src/assets/images/themes/stake/bridge/pattern-1.png
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
ui/src/assets/images/themes/stake/bridge/pattern-2.png
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
@@ -0,0 +1,3 @@
|
||||
<svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="30" cy="30" r="29.5" fill="#F5F7F9" stroke="#E6ECF1"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 170 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="120" height="1" viewBox="0 0 120 1" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="120" height="1" fill="#E6ECF1"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 149 B |
1
ui/src/assets/images/themes/stake/logos/footer-logo.svg
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="34" height="8">
|
||||
<path fill="#5c34a2" fill-rule="evenodd" d="M3.781 6.375h-.344v1.031a.333.333 0 0 1-.312.337v.007H.469v-.007c-.006.001-.01.007-.016.007a.336.336 0 0 1-.328-.344V1.219c0-.19.147-.344.328-.344.006 0 .01.006.016.007V.875h3.312c1.467 0 2.656 1.231 2.656 2.75s-1.189 2.75-2.656 2.75zM10.422.875c1.838 0 3.328 1.539 3.328 3.437 0 1.899-1.49 3.438-3.328 3.438-1.838 0-3.328-1.539-3.328-3.438 0-1.898 1.49-3.437 3.328-3.437zM21.369 7.532a.209.209 0 0 1-.205.212h-7.542c-.005.001-.008.006-.013.006-.112 0-.203-.098-.203-.219 0-.042.023-.076.042-.109l-.008-.017 3.739-6.363h.017c.021-.094.091-.17.188-.17.098 0 .167.076.189.17h.017l3.779 6.405-.021.032c.005.019.021.032.021.053zM33.562 7.75h-4.374a.313.313 0 0 1-.313-.313V1.188c0-.173.14-.313.313-.313h4.374c.173 0 .313.14.313.313v6.249c0 .173-.14.313-.313.313zM29.5 1.5v5.625h3.75V1.5H29.5zm-2.188 5.625a.313.313 0 1 1 0 .625h-4.374a.313.313 0 0 1-.313-.313V4.312c0-.172.14-.312.313-.312H27V1.5h-4.062a.313.313 0 1 1 0-.625h4.374c.173 0 .313.14.313.313v3.124c0 .173-.14.313-.313.313H23.25v2.5h4.062z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
3
ui/src/assets/images/themes/stake/logos/logo-foreign.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="34" height="8">
|
||||
<path fill="#FFF" fill-rule="evenodd" d="M3.781 6.375h-.344v1.031a.333.333 0 0 1-.312.337v.007H.469v-.007c-.006.001-.01.007-.016.007a.336.336 0 0 1-.328-.344V1.219c0-.19.147-.344.328-.344.006 0 .01.006.016.007V.875h3.312c1.467 0 2.656 1.231 2.656 2.75s-1.189 2.75-2.656 2.75zM10.422.875c1.838 0 3.328 1.539 3.328 3.437 0 1.899-1.49 3.438-3.328 3.438-1.838 0-3.328-1.539-3.328-3.438 0-1.898 1.49-3.437 3.328-3.437zM21.369 7.532a.209.209 0 0 1-.205.212h-7.542c-.005.001-.008.006-.013.006-.112 0-.203-.098-.203-.219 0-.042.023-.076.042-.109l-.008-.017 3.739-6.363h.017c.021-.094.091-.17.188-.17.098 0 .167.076.189.17h.017l3.779 6.405-.021.032c.005.019.021.032.021.053zM33.562 7.75h-4.374a.313.313 0 0 1-.313-.313V1.188c0-.173.14-.313.313-.313h4.374c.173 0 .313.14.313.313v6.249c0 .173-.14.313-.313.313zM29.5 1.5v5.625h3.75V1.5H29.5zm-2.188 5.625a.313.313 0 1 1 0 .625h-4.374a.313.313 0 0 1-.313-.313V4.312c0-.172.14-.312.313-.312H27V1.5h-4.062a.313.313 0 1 1 0-.625h4.374c.173 0 .313.14.313.313v3.124c0 .173-.14.313-.313.313H23.25v2.5h4.062z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
BIN
ui/src/assets/images/themes/stake/logos/logo-home-modal.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
ui/src/assets/images/themes/stake/logos/logo-home.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
7
ui/src/assets/images/themes/stake/logos/logo-loading.svg
Normal file
|
After Width: | Height: | Size: 5.8 KiB |
1
ui/src/assets/images/themes/stake/logos/logo.svg
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
@@ -0,0 +1,23 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="59" height="59">
|
||||
<path fill="#5C34A2" fill-rule="evenodd" d="M6 0h47a6 6 0 0 1 6 6v47a6 6 0 0 1-6 6H6a6 6 0 0 1-6-6V6a6 6 0 0 1 6-6z"/>
|
||||
<path fill="#FFF" fill-rule="evenodd" d="M19 12h6v6h-6v-6z"/>
|
||||
<path fill="#9987FC" fill-rule="evenodd" d="M13 18a6 6 0 0 1 6-6v6h-6z"/>
|
||||
<path fill="#61DC97" fill-rule="evenodd" d="M13 18h6v6h-6v-6z"/>
|
||||
<path fill="#FFF" fill-rule="evenodd" d="M13 30v-6h6a6 6 0 0 1-6 6z"/>
|
||||
<path fill="#90E1D9" fill-rule="evenodd" d="M7 30a6 6 0 0 1 6-6v6H7z"/>
|
||||
<path fill="#9987FC" fill-rule="evenodd" d="M13 36a6 6 0 0 1-6-6h6v6z"/>
|
||||
<path fill="#90E1D9" fill-rule="evenodd" d="M19 36h-6v-6a6 6 0 0 1 6 6z"/>
|
||||
<path fill="#FFF" fill-rule="evenodd" d="M13 36h6v6h-6v-6z"/>
|
||||
<path fill="#61DC97" fill-rule="evenodd" d="M19 48a6 6 0 0 1-6-6h6v6z"/>
|
||||
<path fill="#9987FC" fill-rule="evenodd" d="M19 42h6v6h-6v-6z"/>
|
||||
<path fill="#FFF" fill-rule="evenodd" d="M35 42h6v6h-6v-6z"/>
|
||||
<path fill="#9987FC" fill-rule="evenodd" d="M41 48v-6h6a6 6 0 0 1-6 6z"/>
|
||||
<path fill="#61DC97" fill-rule="evenodd" d="M41 36h6v6h-6v-6z"/>
|
||||
<path fill="#FFF" fill-rule="evenodd" d="M41 36a6 6 0 0 1 6-6v6h-6z"/>
|
||||
<path fill="#90E1D9" fill-rule="evenodd" d="M47 36v-6h6a6 6 0 0 1-6 6z"/>
|
||||
<path fill="#9987FC" fill-rule="evenodd" d="M53 30h-6v-6a6 6 0 0 1 6 6z"/>
|
||||
<path fill="#90E1D9" fill-rule="evenodd" d="M47 30a6 6 0 0 1-6-6h6v6z"/>
|
||||
<path fill="#FFF" fill-rule="evenodd" d="M41 18h6v6h-6v-6z"/>
|
||||
<path fill="#61DC97" fill-rule="evenodd" d="M47 18h-6v-6a6 6 0 0 1 6 6z"/>
|
||||
<path fill="#9987FC" fill-rule="evenodd" d="M35 12h6v6h-6v-6z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,23 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="59" height="59">
|
||||
<path fill="#61DC97" fill-rule="evenodd" d="M6 0h47a6 6 0 0 1 6 6v47a6 6 0 0 1-6 6H6a6 6 0 0 1-6-6V6a6 6 0 0 1 6-6z"/>
|
||||
<path fill="#FFF" fill-rule="evenodd" d="M19 12h6v6h-6v-6z"/>
|
||||
<path fill="#9987FC" fill-rule="evenodd" d="M13 18a6 6 0 0 1 6-6v6h-6z"/>
|
||||
<path fill="#5C34A2" fill-rule="evenodd" d="M13 18h6v6h-6v-6z"/>
|
||||
<path fill="#FFF" fill-rule="evenodd" d="M13 30v-6h6a6 6 0 0 1-6 6z"/>
|
||||
<path fill="#90E1D9" fill-rule="evenodd" d="M7 30a6 6 0 0 1 6-6v6H7z"/>
|
||||
<path fill="#9987FC" fill-rule="evenodd" d="M13 36a6 6 0 0 1-6-6h6v6z"/>
|
||||
<path fill="#90E1D9" fill-rule="evenodd" d="M19 36h-6v-6a6 6 0 0 1 6 6z"/>
|
||||
<path fill="#FFF" fill-rule="evenodd" d="M13 36h6v6h-6v-6z"/>
|
||||
<path fill="#5C34A2" fill-rule="evenodd" d="M19 48a6 6 0 0 1-6-6h6v6z"/>
|
||||
<path fill="#9987FC" fill-rule="evenodd" d="M19 42h6v6h-6v-6z"/>
|
||||
<path fill="#FFF" fill-rule="evenodd" d="M35 42h6v6h-6v-6z"/>
|
||||
<path fill="#9987FC" fill-rule="evenodd" d="M41 48v-6h6a6 6 0 0 1-6 6z"/>
|
||||
<path fill="#5C34A2" fill-rule="evenodd" d="M41 36h6v6h-6v-6z"/>
|
||||
<path fill="#FFF" fill-rule="evenodd" d="M41 36a6 6 0 0 1 6-6v6h-6z"/>
|
||||
<path fill="#90E1D9" fill-rule="evenodd" d="M47 36v-6h6a6 6 0 0 1-6 6z"/>
|
||||
<path fill="#9987FC" fill-rule="evenodd" d="M53 30h-6v-6a6 6 0 0 1 6 6z"/>
|
||||
<path fill="#90E1D9" fill-rule="evenodd" d="M47 30a6 6 0 0 1-6-6h6v6z"/>
|
||||
<path fill="#FFF" fill-rule="evenodd" d="M41 18h6v6h-6v-6z"/>
|
||||
<path fill="#5C34A2" fill-rule="evenodd" d="M47 18h-6v-6a6 6 0 0 1 6 6z"/>
|
||||
<path fill="#9987FC" fill-rule="evenodd" d="M35 12h6v6h-6v-6z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |