Compare commits

...

10 Commits

Author SHA1 Message Date
Alexander Kolotov
2e1b022512 Merge the develop branch to the master branch, preparation to v2.4.0 2020-08-24 00:28:20 +03:00
Kirill Fedoseev
f252ed2618 Add a possibility to fetch gas price from multiple sources (#420) 2020-08-23 22:56:59 +03:00
Gerardo Nardelli
bea91c0e6e Remove half duplex erc20 token support from oracle (#413) 2020-08-11 23:37:47 +03:00
Alexander Kolotov
c2f6b5e8ba Merge the develop branch to the master branch, preparation to v2.3.1 2020-08-11 20:13:58 +03:00
Alexander Kolotov
f3f226afdf Correction of the message for a transaction without the bridge requests (#416) 2020-08-06 23:43:13 +03:00
Kirill Fedoseev
1eb8a8b1dc Use requestGasLimit parameter in AMB oracle in estimateGas (#415) 2020-08-06 16:15:51 +03:00
Alexander Kolotov
8a42cfbe2b Merge the develop branch to the master branch, preparation to v2.3.0 2020-07-29 16:13:24 +03:00
Gerardo Nardelli
ab406bc1db Add alm basic e2e tests (#407) 2020-07-29 13:30:36 +03:00
Gerardo Nardelli
8cf73d572c Correctly set a validator status as not required (#410) 2020-07-27 22:23:08 +03:00
Jongchan J
fa6b37db1c Change the remote RPC url for Ethereum Classic (#408) 2020-07-26 00:16:10 +03:00
51 changed files with 728 additions and 523 deletions

View File

@@ -143,8 +143,8 @@ jobs:
command: |
docker login -u ${DOCKER_LOGIN} -p ${DOCKER_PASSWORD}
cd e2e-commons
docker-compose build oracle monitor ui e2e molecule_runner
docker-compose push oracle monitor ui e2e molecule_runner
docker-compose build oracle monitor ui alm e2e molecule_runner
docker-compose push oracle monitor ui alm e2e molecule_runner
oracle-e2e:
executor: tokenbridge-orb/machine-without-dlc
steps:
@@ -164,6 +164,14 @@ jobs:
steps:
- tokenbridge-orb/init-repo
- run: ./monitor-e2e/run-tests.sh
alm-e2e:
executor: tokenbridge-orb/machine-without-dlc
steps:
- tokenbridge-orb/install-node
- tokenbridge-orb/install-yarn
- restore_cache:
key: initialize-{{ .Environment.CIRCLE_SHA1 }}
- run: yarn run alm-e2e
cover:
executor: tokenbridge-orb/docker-node
steps:
@@ -288,6 +296,10 @@ workflows:
- monitor-e2e:
requires:
- build-e2e-images
- alm-e2e:
requires:
- build-e2e-images
- initialize
- deployment-oracle:
requires:
- build-e2e-images

2
.nvmrc
View File

@@ -1 +1 @@
10.16
10.22

View File

@@ -12,7 +12,7 @@ COMMON_HOME_GAS_PRICE_SUPPLIER_URL | The URL used to get a JSON response from th
COMMON_HOME_GAS_PRICE_SPEED_TYPE | Assuming the gas price oracle responds with the following JSON structure: `{"fast": 20.0, "block_time": 12.834, "health": true, "standard": 6.0, "block_number": 6470469, "instant": 71.0, "slow": 1.889}`, this parameter specifies the desirable transaction speed. The speed type can be omitted when `COMMON_HOME_GAS_PRICE_SUPPLIER_URL` is not used. | `instant` / `fast` / `standard` / `slow`
COMMON_HOME_GAS_PRICE_FALLBACK | The gas price (in Wei) that is used if both the oracle and the fall back gas price specified in the Home Bridge contract are not available. | integer
COMMON_HOME_GAS_PRICE_FACTOR | A value that will multiply the gas price of the oracle to convert it to gwei. If the oracle API returns gas prices in gwei then this can be set to `1`. Also, it could be used to intentionally pay more gas than suggested by the oracle to guarantee the transaction verification. E.g. `1.25` or `1.5`. | integer
COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL | The URL used to get a JSON response from the gas price prediction oracle for the Foreign network. The provided gas price is used to send the validator's transactions to the RPC node. If the Foreign network is Ethereum Foundation mainnet, the oracle URL can be: https://gasprice.poa.network. Otherwise this parameter can be omitted. | URL
COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL | The URL used to get a JSON response from the gas price prediction oracle for the Foreign network. The provided gas price is used to send the validator's transactions to the RPC node. If the Foreign network is Ethereum Foundation mainnet, the oracle URL can be: https://gasprice.poa.network. Otherwise this parameter can be omitted. Set to `gas-price-oracle` if you want to use npm `gas-price-oracle` package for retrieving gas price from multiple sources. | URL
COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE | Assuming the gas price oracle responds with the following JSON structure: `{"fast": 20.0, "block_time": 12.834, "health": true, "standard": 6.0, "block_number": 6470469, "instant": 71.0, "slow": 1.889}`, this parameter specifies the desirable transaction speed. The speed type can be omitted when `COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL`is not used. | `instant` / `fast` / `standard` / `slow`
COMMON_FOREIGN_GAS_PRICE_FALLBACK | The gas price (in Wei) used if both the oracle and fall back gas price specified in the Foreign Bridge contract are not available. | integer
COMMON_FOREIGN_GAS_PRICE_FACTOR | A value that will multiply the gas price of the oracle to convert it to gwei. If the oracle API returns gas prices in gwei then this can be set to `1`. Also, it could be used to intentionally pay more gas than suggested by the oracle to guarantee the transaction verification. E.g. `1.25` or `1.5`. | integer

15
alm-e2e/.eslintrc Normal file
View File

@@ -0,0 +1,15 @@
{
"extends": [
"plugin:node/recommended",
"airbnb-base",
"../.eslintrc"
],
"plugins": ["node", "jest"],
"env": {
"jest/globals": true
},
"globals": {
"page": true,
"browser": true
}
}

24
alm-e2e/package.json Normal file
View File

@@ -0,0 +1,24 @@
{
"name": "alm-e2e",
"version": "0.0.1",
"private": true,
"scripts": {
"test": "jest --detectOpenHandles",
"lint": "eslint . --ignore-path ../.eslintignore",
"lint:fix": "eslint . --fix"
},
"dependencies": {
"jest": "24.7.1",
"jest-puppeteer": "^4.4.0",
"puppeteer": "^5.2.1"
},
"jest": {
"preset": "jest-puppeteer"
},
"devDependencies": {
"eslint-plugin-jest": "^23.18.0"
},
"engines": {
"node": ">= 8.9"
}
}

13
alm-e2e/run-tests.sh Normal file
View File

@@ -0,0 +1,13 @@
#!/usr/bin/env bash
cd $(dirname $0)
../e2e-commons/up.sh deploy blocks alm alm-e2e
# run oracle amb e2e tests to generate transactions for alm
docker-compose -f ../e2e-commons/docker-compose.yml run e2e yarn workspace oracle-e2e run alm
yarn test
rc=$?
../e2e-commons/down.sh
exit $rc

50
alm-e2e/src/test.js Normal file
View File

@@ -0,0 +1,50 @@
const puppeteer = require('puppeteer')
const { waitUntil } = require('./utils/utils')
jest.setTimeout(60000)
const statusText = 'Success'
const statusSelector = 'label[data-id="status"]'
const homeToForeignTxURL = 'http://localhost:3004/77/0x58e7d63368335b9591d4dbb43889084f698fcee93ab7656fd7a39d8c66bc4b60'
const foreignToHomeTxURL = 'http://localhost:3004/42/0x592bf28fc896419d2838f71cd0388775814b692688f1ecd5b1519081566b994a'
describe('ALM', () => {
let browser
let page
beforeAll(async () => {
browser = await puppeteer.launch()
page = await browser.newPage()
})
afterAll(async () => {
await browser.close()
})
it('should be titled "AMB Live Monitoring"', async () => {
await page.goto(foreignToHomeTxURL)
await expect(page.title()).resolves.toMatch('AMB Live Monitoring')
})
it('should display information of foreign to home transaction', async () => {
await page.goto(foreignToHomeTxURL)
await page.waitForSelector(statusSelector)
await waitUntil(async () => {
const element = await page.$(statusSelector)
const text = await page.evaluate(element => element.textContent, element)
return text === statusText
})
})
it('should display information of home to foreign transaction', async () => {
await page.goto(homeToForeignTxURL)
await page.waitForSelector(statusSelector)
await waitUntil(async () => {
const element = await page.$(statusSelector)
const text = await page.evaluate(element => element.textContent, element)
return text === statusText
})
})
})

View File

@@ -0,0 +1,15 @@
const waitUntil = async (predicate, step = 100, timeout = 20000) => {
const stopTime = Date.now() + timeout
while (Date.now() <= stopTime) {
const result = await predicate()
if (result) {
return result
}
await new Promise(resolve => setTimeout(resolve, step)) // sleep
}
throw new Error(`waitUntil timed out after ${timeout} ms`)
}
module.exports = {
waitUntil
}

View File

@@ -87,7 +87,7 @@ export const ConfirmationsContainer = ({ message, receipt, fromHome, timestamp }
<StyledConfirmationContainer className="col-9">
<div className="row is-center">
<StatusLabel>Status:</StatusLabel>
<StatusResultLabel>
<StatusResultLabel data-id="status">
{status !== CONFIRMATIONS_STATUS.UNDEFINED ? statusLabel[status] : <SimpleLoading />}
</StatusResultLabel>
</div>

View File

@@ -64,10 +64,6 @@ export const StatusContainer = ({ onBackToMain, setNetworkFromParams, receiptPar
const displayReference = multiMessageSelected ? messages[selectedMessageId].id : txHash
const formattedMessageId = formatTxHash(displayReference)
const displayedDescription = multiMessageSelected
? getTransactionStatusDescription(TRANSACTION_STATUS.SUCCESS_ONE_MESSAGE, timestamp)
: description
const isHome = chainId === home.chainId.toString()
const txExplorerLink = getExplorerTxUrl(txHash, isHome)
const displayExplorerLink = status !== TRANSACTION_STATUS.NOT_FOUND
@@ -75,17 +71,32 @@ export const StatusContainer = ({ onBackToMain, setNetworkFromParams, receiptPar
const displayConfirmations = status === TRANSACTION_STATUS.SUCCESS_ONE_MESSAGE || multiMessageSelected
const messageToConfirm =
messages.length > 1 ? messages[selectedMessageId] : messages.length > 0 ? messages[0] : { id: '', data: '' }
let displayedDescription: string = multiMessageSelected
? getTransactionStatusDescription(TRANSACTION_STATUS.SUCCESS_ONE_MESSAGE, timestamp)
: description
let link
const descArray = displayedDescription.split('%link')
if (descArray.length > 1) {
displayedDescription = descArray[0]
link = (
<ExplorerTxLink href={descArray[1]} target="_blank" rel="noopener noreferrer">
{descArray[1]}
</ExplorerTxLink>
)
}
return (
<div>
{status && (
<p>
The request{' '}
The transaction{' '}
{displayExplorerLink && (
<ExplorerTxLink href={txExplorerLink} target="_blank">
{formattedMessageId}
</ExplorerTxLink>
)}
{!displayExplorerLink && <label>{formattedMessageId}</label>} {displayedDescription}
{!displayExplorerLink && <label>{formattedMessageId}</label>} {displayedDescription} {link}
</p>
)}
{displayMessageSelector && <MessageSelector messages={messages} onMessageSelected={onMessageSelected} />}

View File

@@ -2,7 +2,8 @@
export const TRANSACTION_STATUS_DESCRIPTION: { [key: string]: string } = {
SUCCESS_MULTIPLE_MESSAGES: 'was initiated %t and contains several bridge messages. Specify one of them:',
SUCCESS_ONE_MESSAGE: 'was initiated %t',
SUCCESS_NO_MESSAGES: 'execution succeeded %t but it does not contain any bridge messages',
SUCCESS_NO_MESSAGES:
'successfully mined %t but it does not seem to contain any request to the bridge, \nso nothing needs to be confirmed by the validators. \nIf you are sure that the transaction should contain a request to the bridge,\ncontact to the validators by \nmessaging on %linkhttps://forum.poa.network/c/support',
FAILED: 'failed %t',
NOT_FOUND:
'Transaction not found. \n1. Check that the transaction hash is correct. \n2. Wait several blocks for the transaction to be\nmined, gas price affects mining speed.'

View File

@@ -118,7 +118,10 @@ export const getConfirmationsForTx = async (
status: VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED
}))
validatorConfirmations = [...validatorConfirmations, ...notRequiredConfirmations]
notRequiredConfirmations.forEach(validatorData => {
const index = validatorConfirmations.findIndex(e => e.validator === validatorData.validator)
validatorConfirmations[index] = validatorData
})
signatureCollectedResult = true
}

View File

@@ -13,7 +13,6 @@ const REWARDABLE_VALIDATORS_ABI = require('../contracts/build/contracts/Rewardab
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
@@ -136,7 +135,6 @@ module.exports = {
OLD_AMB_USER_REQUEST_FOR_AFFIRMATION_ABI,
OLD_AMB_USER_REQUEST_FOR_SIGNATURE_ABI,
BOX_ABI,
SAI_TOP,
HOME_STAKE_ERC_TO_ERC_ABI,
FOREIGN_STAKE_ERC_TO_ERC_ABI
}

View File

@@ -8,6 +8,7 @@
"test": "NODE_ENV=test mocha"
},
"dependencies": {
"gas-price-oracle": "^0.1.5",
"web3-utils": "1.0.0-beta.34"
},
"devDependencies": {

View File

@@ -1,7 +1,10 @@
const { toWei, toBN } = require('web3-utils')
const { GasPriceOracle } = require('gas-price-oracle')
const { BRIDGE_MODES, FEE_MANAGER_MODE, ERC_TYPES } = require('./constants')
const { REWARDABLE_VALIDATORS_ABI } = require('./abis')
const gasPriceOracle = new GasPriceOracle()
function decodeBridgeMode(bridgeModeHash) {
switch (bridgeModeHash) {
case '0x92a8d7fe':
@@ -235,8 +238,13 @@ const normalizeGasPrice = (oracleGasPrice, factor, limits = null) => {
// we use built-in 'fetch' on browser side, and `node-fetch` package in Node.
const gasPriceFromSupplier = async (fetchFn, options = {}) => {
try {
const response = await fetchFn()
const json = await response.json()
let json
if (fetchFn) {
const response = await fetchFn()
json = await response.json()
} else {
json = await gasPriceOracle.fetchGasPricesOffChain()
}
const oracleGasPrice = json[options.speedType]
if (!oracleGasPrice) {

View File

@@ -4,7 +4,7 @@ ORACLE_BRIDGE_MODE: "NATIVE_TO_ERC"
UI_NATIVE_TOKEN_DISPLAY_NAME: "ETC"
## Home contract
COMMON_HOME_RPC_URL: "https://ethereumclassic.network"
COMMON_HOME_RPC_URL: "https://www.ethercluster.com/etc"
UI_HOME_NETWORK_DISPLAY_NAME: "Ethereum Classic"
UI_HOME_WITHOUT_EVENTS: false
COMMON_HOME_BRIDGE_ADDRESS: "0x073081832B4Ecdce79d4D6753565c85Ba4b3BeA9"

View File

@@ -0,0 +1,10 @@
COMMON_HOME_BRIDGE_ADDRESS=0x0AEe1FCD12dDFab6265F7f8956e6E012A9Fe4Aa0
COMMON_FOREIGN_BRIDGE_ADDRESS=0x0AEe1FCD12dDFab6265F7f8956e6E012A9Fe4Aa0
COMMON_HOME_RPC_URL=http://localhost:8541
COMMON_FOREIGN_RPC_URL=http://localhost:8542
ALM_HOME_NETWORK_NAME=Parity1
ALM_FOREIGN_NETWORK_NAME=Parity2
PORT=3000

View File

@@ -50,8 +50,6 @@
"home": "0x488Af810997eD1730cB3a3918cD83b3216E6eAda",
"foreign": "0x488Af810997eD1730cB3a3918cD83b3216E6eAda",
"foreignToken": "0x7cc4b1851c35959d34e635a470f6b5c43ba3c9c9",
"halfDuplexToken": "0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359",
"saiTop": "0x9b0ccf7C8994E19F39b2B4CF708e0A7DF65fA8a3",
"chaiToken": "0x06af07097c9eeb7fd685c692751d5c66db49c215",
"ui": "http://localhost:3002",
"monitor": "http://monitor-erc20-native:3012/bridge"

View File

@@ -113,6 +113,16 @@ services:
command: "true"
networks:
- ultimate
alm:
image: ${DOCKER_LOGIN}/tokenbridge-e2e-alm:${CIRCLE_BRANCH}
build:
context: ..
dockerfile: alm/Dockerfile
args:
DOT_ENV_PATH: e2e-commons/components-envs/alm.env
command: "true"
networks:
- ultimate
monitor:
image: ${DOCKER_LOGIN}/tokenbridge-e2e-monitor:${CIRCLE_BRANCH}
build:

View File

@@ -10,6 +10,8 @@ while [ "$1" != "" ]; do
docker-compose pull monitor
elif [ "$1" == "ui" ]; then
docker-compose pull ui
elif [ "$1" == "alm" ]; then
docker-compose pull alm
fi
shift
done

View File

@@ -22,8 +22,6 @@ startValidator () {
docker-compose $1 run $2 $3 -d oracle-erc20-native yarn watcher:collected-signatures
docker-compose $1 run $2 $3 -d oracle-erc20-native yarn watcher:affirmation-request
docker-compose $1 run $2 $3 -d oracle-erc20-native yarn watcher:transfer
docker-compose $1 run $2 $3 -d oracle-erc20-native yarn watcher:half-duplex-transfer
docker-compose $1 run $2 $3 -d oracle-erc20-native yarn worker:swap-tokens
docker-compose $1 run $2 $3 -d oracle-erc20-native yarn worker:convert-to-chai
docker-compose $1 run $2 $3 -d oracle-amb yarn watcher:signature-request
docker-compose $1 run $2 $3 -d oracle-amb yarn watcher:collected-signatures
@@ -32,6 +30,16 @@ startValidator () {
docker-compose $1 run $2 $3 -d oracle-erc20-native yarn sender:foreign
}
startAMBValidator () {
docker-compose $1 run -d --name $4 redis
docker-compose $1 run -d --name $5 rabbit
docker-compose $1 run $2 $3 -d oracle-amb yarn watcher:signature-request
docker-compose $1 run $2 $3 -d oracle-amb yarn watcher:collected-signatures
docker-compose $1 run $2 $3 -d oracle-amb yarn watcher:affirmation-request
docker-compose $1 run $2 $3 -d oracle-amb yarn sender:home
docker-compose $1 run $2 $3 -d oracle-amb yarn sender:foreign
}
while [ "$1" != "" ]; do
if [ "$1" == "oracle" ]; then
docker-compose up -d redis rabbit
@@ -47,8 +55,6 @@ while [ "$1" != "" ]; do
docker-compose run -d oracle-erc20-native yarn watcher:collected-signatures
docker-compose run -d oracle-erc20-native yarn watcher:affirmation-request
docker-compose run -d oracle-erc20-native yarn watcher:transfer
docker-compose run -d oracle-erc20-native yarn watcher:half-duplex-transfer
docker-compose run -d oracle-erc20-native yarn worker:swap-tokens
docker-compose run -d oracle-erc20-native yarn worker:convert-to-chai
docker-compose run -d oracle-amb yarn watcher:signature-request
docker-compose run -d oracle-amb yarn watcher:collected-signatures
@@ -83,6 +89,12 @@ while [ "$1" != "" ]; do
docker-compose run -d -p 3003:3000 ui-amb-stake-erc20-erc20 yarn start
fi
if [ "$1" == "alm" ]; then
docker-compose up -d alm
docker-compose run -d -p 3004:3000 alm serve -p 3000 -s .
fi
if [ "$1" == "deploy" ]; then
docker-compose run e2e e2e-commons/scripts/deploy.sh
fi
@@ -115,5 +127,25 @@ while [ "$1" != "" ]; do
../deployment-e2e/molecule.sh ultimate-amb-stake-erc-to-erc
fi
if [ "$1" == "alm-e2e" ]; then
docker-compose up -d redis rabbit
docker-compose run -d oracle-amb yarn watcher:signature-request
docker-compose run -d oracle-amb yarn watcher:collected-signatures
docker-compose run -d oracle-amb yarn watcher:affirmation-request
docker-compose run -d oracle-amb yarn sender:home
docker-compose run -d oracle-amb yarn sender:foreign
oracle2name="-p validator2"
oracle2Values="-e ORACLE_VALIDATOR_ADDRESS=0xdCC784657C78054aa61FbcFFd2605F32374816A4 -e ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=5a5c3645d0f04e9eb4f27f94ed4c244a225587405b8838e7456f7781ce3a9513"
oracle2comp="-e ORACLE_QUEUE_URL=amqp://rabbit2 -e ORACLE_REDIS_URL=redis://redis2"
startAMBValidator "$oracle2name" "$oracle2Values" "$oracle2comp" "redis2" "rabbit2"
oracle3name="-p validator3"
oracle3Values="-e ORACLE_VALIDATOR_ADDRESS=0xDcef88209a20D52165230104B245803C3269454d -e ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=f877f62a1c19f852cff1d29f0fb1ecac18821c0080d4cc0520c60c098293dca1"
oracle3comp="-e ORACLE_QUEUE_URL=amqp://rabbit3 -e ORACLE_REDIS_URL=redis://redis3"
startAMBValidator "$oracle3name" "$oracle3Values" "$oracle3comp" "redis3" "rabbit3"
fi
shift # Shift all the parameters down by one
done

View File

@@ -3,4 +3,6 @@ version: '2.4'
services:
monitor:
image: poanetwork/tokenbridge-monitor
build: .
build:
context: ..
dockerfile: ./monitor/Dockerfile

View File

@@ -100,8 +100,13 @@ async function main(bridgeMode) {
if (MONITOR_VALIDATOR_FOREIGN_TX_LIMIT) {
logger.debug('calling foreign getGasPrices')
const fetchFn =
COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL === 'gas-price-oracle'
? null
: () => fetch(COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL)
foreignGasPrice =
(await gasPriceFromSupplier(() => fetch(COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL), foreignGasPriceSupplierOpts)) ||
(await gasPriceFromSupplier(fetchFn, foreignGasPriceSupplierOpts)) ||
Web3Utils.toBN(COMMON_FOREIGN_GAS_PRICE_FALLBACK)
foreignGasPriceGwei = Web3Utils.fromWei(foreignGasPrice.toString(), 'gwei')
foreignTxCost = foreignGasPrice.mul(Web3Utils.toBN(MONITOR_VALIDATOR_FOREIGN_TX_LIMIT))

View File

@@ -6,7 +6,8 @@
"scripts": {
"start": "mocha",
"lint": "eslint . --ignore-path ../.eslintignore",
"amb": "ULTIMATE=true mocha test/amb.js"
"amb": "ULTIMATE=true mocha test/amb.js",
"alm": "mocha test/amb.js"
},
"author": "",
"license": "ISC",

View File

@@ -31,12 +31,7 @@ const foreignBridge = new foreignWeb3.eth.Contract(FOREIGN_ERC_TO_NATIVE_ABI, CO
const homeBridge = new homeWeb3.eth.Contract(HOME_ERC_TO_NATIVE_ABI, COMMON_HOME_BRIDGE_ADDRESS)
describe('erc to native', () => {
let halfDuplexTokenAddress
let halfDuplexToken
before(async () => {
halfDuplexTokenAddress = await foreignBridge.methods.halfDuplexErc20token().call()
halfDuplexToken = new foreignWeb3.eth.Contract(ERC677_BRIDGE_TOKEN_ABI, halfDuplexTokenAddress)
// Set 2 required signatures for home bridge
await setRequiredSignatures({
bridgeContract: homeBridge,
@@ -59,85 +54,6 @@ describe('erc to native', () => {
}
})
})
it('should not convert half duplex tokens to native tokens in home', async () => {
const originalBalanceOnHome = await homeWeb3.eth.getBalance(user.address)
const transferValue = homeWeb3.utils.toWei('0.01')
// send tokens to foreign bridge
await halfDuplexToken.methods
.transfer(COMMON_FOREIGN_BRIDGE_ADDRESS, transferValue)
.send({
from: user.address,
gas: '1000000'
})
.catch(e => {
console.error(e)
})
// check that balance does not increases
await promiseRetry(async (retry, number) => {
const balance = await homeWeb3.eth.getBalance(user.address)
// retry at least 4 times to check transfer is not processed
if (toBN(balance).eq(toBN(originalBalanceOnHome)) && number < 4) {
retry()
} else {
assert(toBN(balance).eq(toBN(originalBalanceOnHome)), 'User balance should not be increased')
}
})
// send tokens to foreign bridge
await erc20Token.methods
.transfer(COMMON_FOREIGN_BRIDGE_ADDRESS, transferValue)
.send({
from: user.address,
gas: '1000000'
})
.catch(e => {
console.error(e)
})
// check that balance increases
await promiseRetry(async (retry, number) => {
const balance = await homeWeb3.eth.getBalance(user.address)
// retry at least 4 times to check transfer is not double processed by the two watchers
if (toBN(balance).lte(toBN(originalBalanceOnHome)) || number < 4) {
retry()
} else {
assert(
toBN(balance).eq(toBN(originalBalanceOnHome).add(toBN(transferValue))),
'User balance should be increased only by second transfer'
)
}
})
const afterTransferBalance = await homeWeb3.eth.getBalance(user.address)
// send tokens to foreign bridge
await erc20Token.methods
.transfer(COMMON_FOREIGN_BRIDGE_ADDRESS, transferValue)
.send({
from: user.address,
gas: '1000000'
})
.catch(e => {
console.error(e)
})
// check that balance increases
await promiseRetry(async (retry, number) => {
const balance = await homeWeb3.eth.getBalance(user.address)
// retry at least 4 times to check transfer is not double processed by the two watchers
if (toBN(balance).lte(toBN(afterTransferBalance)) || number < 4) {
retry()
} else {
assert(
toBN(balance).eq(toBN(afterTransferBalance).add(toBN(transferValue))),
'User balance should be increased'
)
}
})
})
it('should convert tokens in foreign to coins in home', async () => {
const balance = await erc20Token.methods.balanceOf(user.address).call()
const originalBalanceOnHome = await homeWeb3.eth.getBalance(user.address)

View File

@@ -1,39 +0,0 @@
const baseConfig = require('./base.config')
const { ERC20_ABI } = require('../../commons')
const { EXIT_CODES } = require('../src/utils/constants')
const initialChecksJson = process.argv[3]
if (!initialChecksJson) {
throw new Error('initial check parameter was not provided.')
}
let initialChecks
try {
initialChecks = JSON.parse(initialChecksJson)
} catch (e) {
throw new Error('Error on decoding values from initial checks.')
}
const id = `${baseConfig.id}-half-duplex-transfer`
const transferWatcherRequired = baseConfig.id === 'erc-native'
if (!transferWatcherRequired) {
console.error(`Transfer watcher not required for bridge mode ${process.env.ORACLE_BRIDGE_MODE}`)
process.exit(EXIT_CODES.WATCHER_NOT_REQUIRED)
}
module.exports = {
...baseConfig.bridgeConfig,
...baseConfig.foreignConfig,
event: 'Transfer',
eventContractAddress: initialChecks.halfDuplexTokenAddress,
eventAbi: ERC20_ABI,
eventFilter: { to: process.env.COMMON_FOREIGN_BRIDGE_ADDRESS },
queue: 'home',
workerQueue: 'swap-tokens',
name: `watcher-${id}`,
id,
idle: initialChecks.idle
}

View File

@@ -1,20 +0,0 @@
const baseConfig = require('./base.config')
const { EXIT_CODES } = require('../src/utils/constants')
const id = `${baseConfig.id}-swap-tokens`
const workerRequired = baseConfig.id === 'erc-native'
if (!workerRequired) {
console.error(`Swap tokens worker not required for bridge mode ${process.env.ORACLE_BRIDGE_MODE}`)
process.exit(EXIT_CODES.WATCHER_NOT_REQUIRED)
}
module.exports = {
...baseConfig.bridgeConfig,
...baseConfig.foreignConfig,
workerQueue: 'swap-tokens',
senderQueue: 'foreign',
name: `worker-${id}`,
id
}

View File

@@ -3,4 +3,6 @@ version: '2.4'
services:
oracle:
image: poanetwork/tokenbridge-oracle
build: .
build:
context: ..
dockerfile: ./oracle/Dockerfile

View File

@@ -7,8 +7,6 @@ services:
service: rabbit
networks:
- net_rabbit_bridge_transfer
- net_rabbit_bridge_half_duplex_transfer
- net_rabbit_bridge_swap_tokens_worker
- net_rabbit_bridge_convert_to_chai_worker
redis:
extends:
@@ -16,7 +14,6 @@ services:
service: redis
networks:
- net_db_bridge_transfer
- net_db_bridge_half_duplex_transfer
bridge_request:
extends:
file: docker-compose.yml
@@ -51,31 +48,6 @@ services:
networks:
- net_db_bridge_transfer
- net_rabbit_bridge_transfer
bridge_half_duplex_transfer:
cpus: 0.1
mem_limit: 500m
image: poanetwork/tokenbridge-oracle:latest
env_file: ./.env
environment:
- NODE_ENV=production
- ORACLE_VALIDATOR_ADDRESS=${ORACLE_VALIDATOR_ADDRESS}
restart: unless-stopped
entrypoint: yarn watcher:half-duplex-transfer
networks:
- net_db_bridge_half_duplex_transfer
- net_rabbit_bridge_half_duplex_transfer
bridge_swap_tokens_worker:
cpus: 0.1
mem_limit: 500m
image: poanetwork/tokenbridge-oracle:latest
env_file: ./.env
environment:
- NODE_ENV=production
- ORACLE_VALIDATOR_ADDRESS=${ORACLE_VALIDATOR_ADDRESS}
restart: unless-stopped
entrypoint: yarn worker:swap-tokens
networks:
- net_rabbit_bridge_swap_tokens_worker
bridge_convert_to_chai_worker:
cpus: 0.1
mem_limit: 500m
@@ -112,8 +84,6 @@ networks:
driver: bridge
net_db_bridge_transfer:
driver: bridge
net_db_bridge_half_duplex_transfer:
driver: bridge
net_db_bridge_senderhome:
driver: bridge
net_db_bridge_senderforeign:
@@ -126,10 +96,6 @@ networks:
driver: bridge
net_rabbit_bridge_transfer:
driver: bridge
net_rabbit_bridge_half_duplex_transfer:
driver: bridge
net_rabbit_bridge_swap_tokens_worker:
driver: bridge
net_rabbit_bridge_senderhome:
driver: bridge
net_rabbit_bridge_senderforeign:

View File

@@ -9,13 +9,11 @@
"watcher:collected-signatures": "./scripts/start-worker.sh watcher collected-signatures-watcher",
"watcher:affirmation-request": "./scripts/start-worker.sh watcher affirmation-request-watcher",
"watcher:transfer": "./scripts/start-worker.sh watcher transfer-watcher",
"watcher:half-duplex-transfer": "./scripts/start-worker.sh watcher half-duplex-transfer-watcher",
"worker:swap-tokens": "./scripts/start-worker.sh worker swap-tokens-worker",
"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'",
"dev": "concurrently -n 'watcher:signature-request,watcher:collected-signatures,watcher:affirmation-request,watcher:transfer, sender:home,sender:foreign' -c 'red,green,yellow,blue,magenta,cyan' 'yarn watcher:signature-request' 'yarn watcher:collected-signatures' 'yarn watcher:affirmation-request' 'yarn watcher:transfer' 'yarn sender:home' 'yarn sender:foreign'",
"test": "NODE_ENV=test mocha",
"test:watch": "NODE_ENV=test mocha --watch --reporter=min",
"coverage": "NODE_ENV=test nyc --reporter=text --reporter=html mocha",

View File

@@ -7,7 +7,7 @@ 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 { EXIT_CODES, EXTRA_GAS_PERCENTAGE, MAX_GAS_LIMIT } = require('./utils/constants')
const { ORACLE_VALIDATOR_ADDRESS, ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY, ORACLE_ALLOW_HTTP_FOR_RPC } = process.env
@@ -143,7 +143,12 @@ async function sendJobTx(jobs) {
let nonce = await getNonce(web3Instance, ORACLE_VALIDATOR_ADDRESS)
await syncForEach(jobs, async job => {
const gasLimit = addExtraGas(job.gasEstimate, EXTRA_GAS_PERCENTAGE)
let gasLimit
if (typeof job.extraGas === 'number') {
gasLimit = addExtraGas(job.gasEstimate + job.extraGas, 0, MAX_GAS_LIMIT)
} else {
gasLimit = addExtraGas(job.gasEstimate, EXTRA_GAS_PERCENTAGE, MAX_GAS_LIMIT)
}
try {
logger.info(`Sending transaction with nonce ${nonce}`)

View File

@@ -3,14 +3,23 @@ const { AlreadyProcessedError, AlreadySignedError, InvalidValidatorError } = req
const logger = require('../../services/logger').child({
module: 'processAffirmationRequests:estimateGas'
})
const { parseAMBHeader } = require('../../utils/message')
const { strip0x } = require('../../../../commons')
const {
AMB_AFFIRMATION_REQUEST_EXTRA_GAS_ESTIMATOR: estimateExtraGas,
MIN_AMB_HEADER_LENGTH
} = require('../../utils/constants')
async function estimateGas({ web3, homeBridge, validatorContract, message, address }) {
try {
const gasEstimate = await homeBridge.methods.executeAffirmation(message).estimateGas({
from: address
})
const msgGasLimit = parseAMBHeader(message).gasLimit
// message length in bytes
const len = strip0x(message).length / 2 - MIN_AMB_HEADER_LENGTH
return gasEstimate
return gasEstimate + msgGasLimit + estimateExtraGas(len)
} catch (e) {
if (e instanceof HttpListProviderError) {
throw e

View File

@@ -4,7 +4,7 @@ const promiseLimit = require('promise-limit')
const rootLogger = require('../../services/logger')
const { web3Home } = require('../../services/web3')
const bridgeValidatorsABI = require('../../../../contracts/build/contracts/BridgeValidators').abi
const { EXIT_CODES, MAX_CONCURRENT_EVENTS } = require('../../utils/constants')
const { EXIT_CODES, MAX_CONCURRENT_EVENTS, EXTRA_GAS_ABSOLUTE } = require('../../utils/constants')
const estimateGas = require('./estimateGas')
const { parseAMBMessage } = require('../../../../commons')
const { AlreadyProcessedError, AlreadySignedError, InvalidValidatorError } = require('../../utils/errors')
@@ -75,6 +75,7 @@ function processAffirmationRequestsBuilder(config) {
txToSend.push({
data,
gasEstimate,
extraGas: EXTRA_GAS_ABSOLUTE,
transactionReference: affirmationRequest.transactionHash,
to: config.homeBridgeAddress
})

View File

@@ -4,6 +4,7 @@ const { AlreadyProcessedError, IncompatibleContractError, InvalidValidatorError
const logger = require('../../services/logger').child({
module: 'processCollectedSignatures:estimateGas'
})
const { parseAMBHeader } = require('../../utils/message')
const web3 = new Web3()
const { toBN } = Web3.utils
@@ -24,7 +25,12 @@ async function estimateGas({
const gasEstimate = await foreignBridge.methods.executeSignatures(message, signatures).estimateGas({
from: address
})
return gasEstimate
const msgGasLimit = parseAMBHeader(message).gasLimit
// + estimateExtraGas(len)
// is not needed here, since estimateGas will already take into account gas
// needed for memory expansion, message processing, etc.
return gasEstimate + msgGasLimit
} catch (e) {
if (e instanceof HttpListProviderError) {
throw e

View File

@@ -8,7 +8,7 @@ const { signatureToVRS, packSignatures } = require('../../utils/message')
const { parseAMBMessage } = require('../../../../commons')
const estimateGas = require('./estimateGas')
const { AlreadyProcessedError, IncompatibleContractError, InvalidValidatorError } = require('../../utils/errors')
const { MAX_CONCURRENT_EVENTS } = require('../../utils/constants')
const { MAX_CONCURRENT_EVENTS, EXTRA_GAS_ABSOLUTE } = require('../../utils/constants')
const limit = promiseLimit(MAX_CONCURRENT_EVENTS)
@@ -107,6 +107,7 @@ function processCollectedSignaturesBuilder(config) {
txToSend.push({
data,
gasEstimate,
extraGas: EXTRA_GAS_ABSOLUTE,
transactionReference: colSignature.transactionHash,
to: config.foreignBridgeAddress
})

View File

@@ -1,134 +0,0 @@
require('../../../env')
const promiseLimit = require('promise-limit')
const { HttpListProviderError } = require('http-list-provider')
const { BRIDGE_VALIDATORS_ABI, ZERO_ADDRESS } = require('../../../../commons')
const rootLogger = require('../../services/logger')
const { web3Home, web3Foreign } = require('../../services/web3')
const { AlreadyProcessedError, AlreadySignedError, InvalidValidatorError } = require('../../utils/errors')
const { EXIT_CODES, MAX_CONCURRENT_EVENTS } = require('../../utils/constants')
const estimateGas = require('../processAffirmationRequests/estimateGas')
const limit = promiseLimit(MAX_CONCURRENT_EVENTS)
let validatorContract = null
function processTransfersBuilder(config) {
const homeBridge = new web3Home.eth.Contract(config.homeBridgeAbi, config.homeBridgeAddress)
const foreignBridge = new web3Foreign.eth.Contract(config.foreignBridgeAbi, config.foreignBridgeAddress)
const userRequestForAffirmationAbi = config.foreignBridgeAbi.filter(
e => e.type === 'event' && e.name === 'UserRequestForAffirmation'
)[0]
const tokensSwappedAbi = config.foreignBridgeAbi.filter(e => e.type === 'event' && e.name === 'TokensSwapped')[0]
const userRequestForAffirmationHash = web3Home.eth.abi.encodeEventSignature(userRequestForAffirmationAbi)
const tokensSwappedHash = tokensSwappedAbi ? web3Home.eth.abi.encodeEventSignature(tokensSwappedAbi) : '0x'
return async function processTransfers(transfers, blockNumber) {
const txToSend = []
if (validatorContract === null) {
rootLogger.debug('Getting validator contract address')
const validatorContractAddress = await homeBridge.methods.validatorContract().call()
rootLogger.debug({ validatorContractAddress }, 'Validator contract address obtained')
validatorContract = new web3Home.eth.Contract(BRIDGE_VALIDATORS_ABI, validatorContractAddress)
}
rootLogger.debug(`Processing ${transfers.length} Transfer events`)
const callbacks = transfers
.map(transfer => async () => {
const { from, value } = transfer.returnValues
const logger = rootLogger.child({
eventTransactionHash: transfer.transactionHash
})
logger.info({ from, value }, `Processing transfer ${transfer.transactionHash}`)
const block = await web3Foreign.eth.getBlock(blockNumber)
logger.debug({ blockNumber, timestamp: block.timestamp }, `Block obtained`)
const tokenSwapAllowed = await foreignBridge.methods.isTokenSwapAllowed(block.timestamp).call()
if (!tokenSwapAllowed) {
logger.info(
`Transfer event discarded because SCD Emergency Shutdown has happened ${transfer.transactionHash}`
)
return
}
const receipt = await web3Foreign.eth.getTransactionReceipt(transfer.transactionHash)
const existsAffirmationEvent = receipt.logs.some(
e => e.address === config.foreignBridgeAddress && e.topics[0] === userRequestForAffirmationHash
)
if (existsAffirmationEvent) {
logger.info(
`Transfer event discarded because a transaction with alternative receiver detected in transaction ${
transfer.transactionHash
}`
)
return
}
const existsTokensSwappedEvent = tokensSwappedAbi
? receipt.logs.some(e => e.address === config.foreignBridgeAddress && e.topics[0] === tokensSwappedHash)
: false
if (from === ZERO_ADDRESS && existsTokensSwappedEvent) {
logger.info(
`Transfer event discarded because token swap is detected in transaction ${transfer.transactionHash}`
)
return
}
let gasEstimate
try {
logger.debug('Estimate gas')
gasEstimate = await estimateGas({
web3: web3Home,
homeBridge,
validatorContract,
recipient: from,
value,
txHash: transfer.transactionHash,
address: config.validatorAddress
})
logger.debug({ gasEstimate }, 'Gas estimated')
} catch (e) {
if (e instanceof HttpListProviderError) {
throw new Error('RPC Connection Error: submitSignature Gas Estimate cannot be obtained.')
} else if (e instanceof InvalidValidatorError) {
logger.fatal({ address: config.validatorAddress }, 'Invalid validator')
process.exit(EXIT_CODES.INCOMPATIBILITY)
} else if (e instanceof AlreadySignedError) {
logger.info(`Already signed transfer ${transfer.transactionHash}`)
return
} else if (e instanceof AlreadyProcessedError) {
logger.info(`transfer ${transfer.transactionHash} was already processed by other validators`)
return
} else {
logger.error(e, 'Unknown error while processing transaction')
throw e
}
}
const data = await homeBridge.methods
.executeAffirmation(from, value, transfer.transactionHash)
.encodeABI({ from: config.validatorAddress })
txToSend.push({
data,
gasEstimate,
transactionReference: transfer.transactionHash,
to: config.homeBridgeAddress
})
})
.map(promise => limit(promise))
await Promise.all(callbacks)
return txToSend
}
}
module.exports = processTransfersBuilder

View File

@@ -16,7 +16,7 @@ const {
watchdog,
nonceError
} = require('./utils/utils')
const { EXIT_CODES, EXTRA_GAS_PERCENTAGE } = require('./utils/constants')
const { EXIT_CODES, EXTRA_GAS_PERCENTAGE, MAX_GAS_LIMIT } = require('./utils/constants')
const { ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY } = process.env
@@ -106,7 +106,12 @@ async function main({ msg, ackMsg, nackMsg, channel, scheduleForRetry }) {
logger.debug(`Sending ${txArray.length} transactions`)
await syncForEach(txArray, async job => {
const gasLimit = addExtraGas(job.gasEstimate, EXTRA_GAS_PERCENTAGE)
let gasLimit
if (typeof job.extraGas === 'number') {
gasLimit = addExtraGas(job.gasEstimate + job.extraGas, 0, MAX_GAS_LIMIT)
} else {
gasLimit = addExtraGas(job.gasEstimate, EXTRA_GAS_PERCENTAGE, MAX_GAS_LIMIT)
}
try {
logger.info(`Sending transaction with nonce ${nonce}`)

View File

@@ -73,13 +73,14 @@ async function start(chainId, fetchOnce) {
throw new Error(`Unrecognized chainId '${chainId}'`)
}
const fetchFn = gasPriceSupplierUrl === 'gas-price-oracle' ? null : () => fetch(gasPriceSupplierUrl)
if (fetchOnce) {
await fetchGasPrice(speedType, factor, bridgeContract, () => fetch(gasPriceSupplierUrl))
await fetchGasPrice(speedType, factor, bridgeContract, fetchFn)
return getPrice()
}
fetchGasPriceInterval = setIntervalAndRun(
() => fetchGasPrice(speedType, factor, bridgeContract, () => fetch(gasPriceSupplierUrl)),
() => fetchGasPrice(speedType, factor, bridgeContract, fetchFn),
updateInterval
)
return null

View File

@@ -1,5 +1,9 @@
module.exports = {
EXTRA_GAS_PERCENTAGE: 4,
EXTRA_GAS_ABSOLUTE: 200000,
AMB_AFFIRMATION_REQUEST_EXTRA_GAS_ESTIMATOR: len => Math.floor(0.0035 * len ** 2 + 40 * len),
MIN_AMB_HEADER_LENGTH: 32 + 20 + 20 + 4 + 2 + 1 + 2,
MAX_GAS_LIMIT: 10000000,
MAX_CONCURRENT_EVENTS: 50,
RETRY_CONFIG: {
retries: 20,

View File

@@ -73,9 +73,37 @@ function packSignatures(array) {
return `0x${msgLength}${v}${r}${s}`
}
function parseAMBHeader(message) {
message = strip0x(message)
const messageIdStart = 0
const messageIdLength = 32 * 2
const messageId = `0x${message.slice(messageIdStart, messageIdStart + messageIdLength)}`
const senderStart = messageIdStart + messageIdLength
const senderLength = 20 * 2
const sender = `0x${message.slice(senderStart, senderStart + senderLength)}`
const executorStart = senderStart + senderLength
const executorLength = 20 * 2
const executor = `0x${message.slice(executorStart, executorStart + executorLength)}`
const gasLimitStart = executorStart + executorLength
const gasLimitLength = 4 * 2
const gasLimit = parseInt(message.slice(gasLimitStart, gasLimitStart + gasLimitLength), 16)
return {
messageId,
sender,
executor,
gasLimit
}
}
module.exports = {
createMessage,
parseMessage,
signatureToVRS,
packSignatures
packSignatures,
parseAMBHeader
}

View File

@@ -8,21 +8,6 @@ async function getTokensState(bridgeContract, logger) {
throw new Error(`Bridgeable token address cannot be obtained`)
}
try {
logger.debug('Getting Half Duplex token address')
const halfDuplexErc20tokenAddress = await bridgeContract.methods.halfDuplexErc20token().call()
logger.debug({ address: halfDuplexErc20tokenAddress }, 'Half Duplex token address obtained')
if (halfDuplexErc20tokenAddress !== context.bridgeableTokenAddress) {
context.halfDuplexTokenAddress = halfDuplexErc20tokenAddress
} else {
logger.info('Migration to support two tokens was not applied')
context.idle = true
}
} catch (e) {
logger.info('Old version of contracts is used')
context.idle = true
}
return context
}

View File

@@ -48,13 +48,13 @@ async function waitForFunds(web3, address, minimumBalance, cb, logger) {
)
}
function addExtraGas(gas, extraPercentage) {
function addExtraGas(gas, extraPercentage, maxGasLimit = Infinity) {
gas = BigNumber(gas)
extraPercentage = BigNumber(1 + extraPercentage)
const gasWithExtra = gas.multipliedBy(extraPercentage).toFixed(0)
return BigNumber(gasWithExtra)
return BigNumber.min(maxGasLimit, gasWithExtra)
}
function setIntervalAndRun(f, interval) {

View File

@@ -22,7 +22,6 @@ const processSignatureRequests = require('./events/processSignatureRequests')(co
const processCollectedSignatures = require('./events/processCollectedSignatures')(config)
const processAffirmationRequests = require('./events/processAffirmationRequests')(config)
const processTransfers = require('./events/processTransfers')(config)
const processHalfDuplexTransfers = require('./events/processHalfDuplexTransfers')(config)
const processAMBSignatureRequests = require('./events/processAMBSignatureRequests')(config)
const processAMBCollectedSignatures = require('./events/processAMBCollectedSignatures')(config)
const processAMBAffirmationRequests = require('./events/processAMBAffirmationRequests')(config)
@@ -36,7 +35,6 @@ const web3Instance = config.web3
const bridgeContract = new web3Instance.eth.Contract(config.bridgeAbi, config.bridgeContractAddress)
let { eventContractAddress } = config
let eventContract = new web3Instance.eth.Contract(config.eventAbi, eventContractAddress)
let skipEvents = config.idle
const lastBlockRedisKey = `${config.id}:lastProcessedBlock`
let lastProcessedBlock = BN.max(config.startBlock.sub(ONE), ZERO)
@@ -91,7 +89,7 @@ function updateLastProcessedBlock(lastBlockNumber) {
return redis.set(lastBlockRedisKey, lastProcessedBlock.toString())
}
function processEvents(events, blockNumber) {
function processEvents(events) {
switch (config.id) {
case 'native-erc-signature-request':
case 'erc-erc-signature-request':
@@ -109,8 +107,6 @@ function processEvents(events, blockNumber) {
case 'erc-erc-transfer':
case 'erc-native-transfer':
return processTransfers(events)
case 'erc-native-half-duplex-transfer':
return processHalfDuplexTransfers(events, blockNumber)
case 'amb-signature-request':
return processAMBSignatureRequests(events)
case 'amb-collected-signatures':
@@ -130,12 +126,6 @@ async function checkConditions() {
state = await getTokensState(bridgeContract, logger)
updateEventContract(state.bridgeableTokenAddress)
break
case 'erc-native-half-duplex-transfer':
logger.debug('Getting Half Duplex token address to listen Transfer events')
state = await getTokensState(bridgeContract, logger)
skipEvents = state.idle
updateEventContract(state.halfDuplexTokenAddress)
break
default:
}
}
@@ -171,11 +161,6 @@ async function main({ sendToQueue, sendToWorker }) {
try {
await checkConditions()
if (skipEvents) {
logger.debug('Watcher in idle mode, skipping getting events')
return
}
const lastBlockToProcess = await getLastBlockToProcess()
if (lastBlockToProcess.lte(lastProcessedBlock)) {
@@ -200,7 +185,7 @@ async function main({ sendToQueue, sendToWorker }) {
await sendToWorker({ blockNumber: toBlock.toString() })
}
const job = await processEvents(events, toBlock.toString())
const job = await processEvents(events)
logger.info('Transactions to send:', job.length)
if (job.length) {

View File

@@ -7,7 +7,6 @@ const { connectWorkerToQueue } = require('./services/amqpClient')
const config = require(path.join('../config/', process.argv[2]))
const swapTokens = require('./workers/swapTokens')(config)
const convertToChai = require('./workers/convertToChai')(config)
async function initialize() {
@@ -38,9 +37,7 @@ async function initialize() {
}
async function run(blockNumber) {
if (config.id === 'erc-native-swap-tokens') {
return swapTokens(blockNumber)
} else if (config.id === 'erc-native-convert-to-chai') {
if (config.id === 'erc-native-convert-to-chai') {
return convertToChai(blockNumber)
} else {
return []

View File

@@ -1,111 +0,0 @@
require('../../env')
const { HttpListProviderError } = require('http-list-provider')
const rootLogger = require('../services/logger')
const { web3Foreign } = require('../services/web3')
const { BRIDGE_VALIDATORS_ABI, ERC20_ABI } = require('../../../commons')
let validatorContract = null
let halfDuplexTokenContract = null
function swapTokensBuilder(config) {
const foreignBridge = new web3Foreign.eth.Contract(config.foreignBridgeAbi, config.foreignBridgeAddress)
return async function swapTokens(blockNumber) {
const txToSend = []
const logger = rootLogger.child({
blockNumber: blockNumber.toString()
})
logger.debug(`Starting swap tokens operation`)
if (validatorContract === null) {
logger.debug('Getting validator contract address')
const validatorContractAddress = await foreignBridge.methods.validatorContract().call()
logger.debug({ validatorContractAddress }, 'Validator contract address obtained')
validatorContract = new web3Foreign.eth.Contract(BRIDGE_VALIDATORS_ABI, validatorContractAddress)
}
logger.debug(`Checking if is validator duty`)
const validatorDuty = await validatorContract.methods.isValidatorDuty(config.validatorAddress).call()
if (!validatorDuty) {
logger.info(`Token swap discarded because is not validator duty`)
return txToSend
}
logger.debug(`Checking if half duplex token balance is above the threshold`)
const hdTokenBalanceAboveMinBalance = await foreignBridge.methods.isHDTokenBalanceAboveMinBalance().call()
if (!hdTokenBalanceAboveMinBalance) {
logger.info(`Token swap discarded because half duplex balance is below the threshold`)
return txToSend
}
const block = await web3Foreign.eth.getBlock(blockNumber)
logger.debug({ timestamp: block.timestamp }, `Block obtained`)
logger.debug(`Checking if SCD Emergency Shutdown has happened`)
const tokenSwapAllowed = await foreignBridge.methods.isTokenSwapAllowed(block.timestamp).call()
if (!tokenSwapAllowed) {
logger.info(`Token swap discarded because SCD Emergency Shutdown has happened`)
return txToSend
}
let gasEstimate
try {
logger.debug(`Estimate gas`)
gasEstimate = await foreignBridge.methods.swapTokens().estimateGas({
from: config.validatorAddress
})
logger.debug({ gasEstimate }, 'Gas estimated')
} catch (e) {
if (e instanceof HttpListProviderError) {
const errorMsg = 'RPC Connection Error: swapTokens Gas Estimate cannot be obtained.'
logger.error(e, errorMsg)
throw new Error(errorMsg)
} else {
if (halfDuplexTokenContract === null) {
logger.debug('Getting half duplex token contract address')
const halfDuplexErc20Token = await foreignBridge.methods.halfDuplexErc20token().call()
logger.debug({ halfDuplexErc20Token }, 'Half duplex token contract address obtained')
halfDuplexTokenContract = new web3Foreign.eth.Contract(ERC20_ABI, halfDuplexErc20Token)
}
const balance = web3Foreign.utils.toBN(
await halfDuplexTokenContract.methods.balanceOf(config.foreignBridgeAddress).call()
)
logger.debug({ balance: balance.toString() }, 'Half duplex token bridge balance obtained')
if (balance.isZero()) {
logger.info(`Gas estimate failed because half duplex token balance is zero. Tokens swap is discarded.`)
return txToSend
}
logger.error(e, 'Unknown error while processing transaction')
throw e
}
}
// generate data
const data = await foreignBridge.methods.swapTokens().encodeABI()
// push to job
txToSend.push({
data,
gasEstimate,
transactionReference: `swap tokens operation for block number ${blockNumber.toString()}`,
to: config.foreignBridgeAddress
})
return txToSend
}
}
module.exports = swapTokensBuilder

View File

@@ -1,6 +1,6 @@
const { BN, toBN } = require('web3').utils
const { expect } = require('chai').use(require('bn-chai')(BN))
const { createMessage, parseMessage, signatureToVRS } = require('../src/utils/message')
const { createMessage, parseMessage, signatureToVRS, parseAMBHeader } = require('../src/utils/message')
describe('message utils', () => {
const expectedMessageLength = 104
@@ -288,4 +288,19 @@ describe('message utils', () => {
expect(signatureThunk).to.throw()
})
})
describe('parseAMBHeader', () => {
it('should return correct values for parsed headers', () => {
// given
const message =
'0x000500009a6ff99b356dd998260582be7d95a4d08b2132600000000000000061339d0e6f308a410f18888932bdf661636a0f538f34718200957aeadd6bece186e61b95618e73a6dc000f42400101002a4d2fb102cf00000000000000000000000081c770bbe8f5f41b4642ed575e630c911c94e4070000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000002e516d543162324178466b6643456a6f715861547148734370666f724a4c66765667434853516e513847575a347662000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002e516d5a7543586f693378487338486e4c325a423539316674466f4c454471516b473655746e47324d6d513147614e000000000000000000000000000000000000'
const { messageId, sender, executor, gasLimit } = parseAMBHeader(message)
// then
expect(messageId).to.equal('0x000500009a6ff99b356dd998260582be7d95a4d08b2132600000000000000061')
expect(sender).to.equal('0x339d0e6f308a410f18888932bdf661636a0f538f')
expect(executor).to.equal('0x34718200957aeadd6bece186e61b95618e73a6dc')
expect(gasLimit).to.equal(1000000)
})
})
})

View File

@@ -34,6 +34,14 @@ describe('utils', () => {
expect(result.toString()).to.equal('225')
})
it('should handle maxGasLimit', () => {
const result1 = addExtraGas(new BigNumber(100), 0.25, 110)
const result2 = addExtraGas(new BigNumber(100), 0.25, 150)
expect(result1.toString()).to.equal('110')
expect(result2.toString()).to.equal('125')
})
})
describe('checkHTTPS', () => {

View File

@@ -30,7 +30,8 @@
"monitor-e2e",
"contracts",
"burner-wallet-plugin",
"alm"
"alm",
"alm-e2e"
],
"scripts": {
"initialize": "yarn clean && git submodule update --init && yarn install --unsafe-perm --frozen-lockfile && yarn install:deploy && yarn compile:contracts",
@@ -39,10 +40,11 @@
"build:alm": "yarn workspace alm run build",
"build:plugin": "yarn workspace burner-wallet-plugin run build",
"lint": "yarn wsrun --exclude token-bridge-contracts lint",
"test": "yarn wsrun --exclude oracle-e2e --exclude ui-e2e --exclude monitor-e2e test",
"test": "yarn wsrun --exclude oracle-e2e --exclude ui-e2e --exclude monitor-e2e --exclude alm-e2e test",
"oracle-e2e": "./oracle-e2e/run-tests.sh",
"ui-e2e": "./ui-e2e/run-tests.sh",
"monitor-e2e": "./monitor-e2e/run-tests.sh",
"alm-e2e": "./alm-e2e/run-tests.sh",
"clean": "rm -rf ./node_modules ./**/node_modules ./**/**/node_modules ./**/build ./**/**/dist",
"compile:contracts": "yarn workspace token-bridge-contracts run compile",
"install:deploy": "cd contracts/deploy && npm install --unsafe-perm --silent",

View File

@@ -53,7 +53,8 @@ class GasPriceStore {
}
const oracleOptions = { speedType: this.speedType, factor: this.factor, logger: console }
this.gasPrice = (await gasPriceFromSupplier(() => fetch(this.gasPriceSupplierUrl), oracleOptions)) || this.gasPrice
const fetchFn = this.gasPriceSupplierUrl === 'gas-price-oracle' ? null : () => fetch(this.gasPriceSupplierUrl)
this.gasPrice = (await gasPriceFromSupplier(fetchFn, oracleOptions)) || this.gasPrice
setTimeout(() => this.updateGasPrice(), this.updateInterval)
}

395
yarn.lock
View File

@@ -1466,11 +1466,21 @@
resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.0.0.tgz#9f05469c88cb2fd3dcd624776b54ee95c312126a"
integrity sha512-mV6T0IYqb0xL1UALPFplXYQmR0twnXG0M6jUswpquqT2sD12BOiCiLy3EvMp/Fy7s3DZElC4/aPjEjo2jeZpvw==
"@hapi/bourne@1.x.x":
version "1.3.2"
resolved "https://registry.yarnpkg.com/@hapi/bourne/-/bourne-1.3.2.tgz#0a7095adea067243ce3283e1b56b8a8f453b242a"
integrity sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA==
"@hapi/hoek@6.x.x":
version "6.2.3"
resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-6.2.3.tgz#0abff7ac75d0c5388d2829c464b2aff74d473721"
integrity sha512-CtV9cp35+6Sfh6OfB+AYBozNIorZ6npNJjfO8InIyh/iFQI7uBW9bIApYoYf6TWq9w9BArecw2DDJf7oK+VlRw==
"@hapi/hoek@8.x.x":
version "8.5.1"
resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-8.5.1.tgz#fde96064ca446dec8c55a8c2f130957b070c6e06"
integrity sha512-yN7kbciD87WzLGc5539Tn0sApjyiGHAJgKvG9W8C7O+6c7qmoQMfVs0W4bX17eqz6C78QJqqFrtgdK5EWf6Qow==
"@hapi/joi@^15.0.0":
version "15.0.3"
resolved "https://registry.yarnpkg.com/@hapi/joi/-/joi-15.0.3.tgz#e94568fd859e5e945126d5675e7dd218484638a7"
@@ -1480,6 +1490,16 @@
"@hapi/hoek" "6.x.x"
"@hapi/topo" "3.x.x"
"@hapi/joi@^15.0.3":
version "15.1.1"
resolved "https://registry.yarnpkg.com/@hapi/joi/-/joi-15.1.1.tgz#c675b8a71296f02833f8d6d243b34c57b8ce19d7"
integrity sha512-entf8ZMOK8sc+8YfeOlM8pCfg3b5+WZIKBfUaaJT8UsjAAPjartzxIYm3TIbjvA4u+u++KbcXD38k682nVHDAQ==
dependencies:
"@hapi/address" "2.x.x"
"@hapi/bourne" "1.x.x"
"@hapi/hoek" "8.x.x"
"@hapi/topo" "3.x.x"
"@hapi/topo@3.x.x":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-3.1.0.tgz#5c47cd9637c2953db185aa957a27bcb2a8b7a6f8"
@@ -3155,6 +3175,13 @@
dependencies:
"@types/yargs-parser" "*"
"@types/yauzl@^2.9.1":
version "2.9.1"
resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.9.1.tgz#d10f69f9f522eef3cf98e30afb684a1e1ec923af"
integrity sha512-A1b8SU4D10uoPjwb0lnHmmu8wZhR9d+9o2PKBQT2jU5YPTKsxac6M2qGAdY7VcL+dHHhARVUDmeg0rOrcd9EjA==
dependencies:
"@types/node" "*"
"@typescript-eslint/eslint-plugin@1.13.0":
version "1.13.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-1.13.0.tgz#22fed9b16ddfeb402fd7bcde56307820f6ebc49f"
@@ -3185,6 +3212,16 @@
"@typescript-eslint/typescript-estree" "1.13.0"
eslint-scope "^4.0.0"
"@typescript-eslint/experimental-utils@^2.5.0":
version "2.34.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.34.0.tgz#d3524b644cdb40eebceca67f8cf3e4cc9c8f980f"
integrity sha512-eS6FTkq+wuMJ+sgtuNTtcqavWXqsflWcfBnlYhg/nS4aZ1leewkXGbvBhaapn1q6qf4M71bsR1tez5JTRMuqwA==
dependencies:
"@types/json-schema" "^7.0.3"
"@typescript-eslint/typescript-estree" "2.34.0"
eslint-scope "^5.0.0"
eslint-utils "^2.0.0"
"@typescript-eslint/parser@1.13.0":
version "1.13.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-1.13.0.tgz#61ac7811ea52791c47dc9fd4dd4a184fae9ac355"
@@ -3220,6 +3257,19 @@
lodash.unescape "4.0.1"
semver "5.5.0"
"@typescript-eslint/typescript-estree@2.34.0":
version "2.34.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.34.0.tgz#14aeb6353b39ef0732cc7f1b8285294937cf37d5"
integrity sha512-OMAr+nJWKdlVM9LOqCqh3pQQPwxHAN7Du8DR6dmwCrAmxtiXQnhHJ6tBNtf+cggqfo51SG/FCwnKhXCIM7hnVg==
dependencies:
debug "^4.1.1"
eslint-visitor-keys "^1.1.0"
glob "^7.1.6"
is-glob "^4.0.1"
lodash "^4.17.15"
semver "^7.3.2"
tsutils "^3.17.1"
"@use-it/interval@^0.1.3":
version "0.1.3"
resolved "https://registry.yarnpkg.com/@use-it/interval/-/interval-0.1.3.tgz#5d1096b2295d7a5dda8e8022f3abb5f9d9ef27f8"
@@ -3543,6 +3593,11 @@ agent-base@4, agent-base@^4.3.0:
dependencies:
es6-promisify "^5.0.0"
agent-base@5:
version "5.1.1"
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-5.1.1.tgz#e8fb3f242959db44d63be665db7a8e739537a32c"
integrity sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==
agent-base@~4.2.1:
version "4.2.1"
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9"
@@ -4154,6 +4209,13 @@ axios@0.19.0:
follow-redirects "1.5.10"
is-buffer "^2.0.2"
axios@^0.19.2:
version "0.19.2"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27"
integrity sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==
dependencies:
follow-redirects "1.5.10"
axobject-query@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.0.2.tgz#ea187abe5b9002b377f925d8bf7d1c561adf38f9"
@@ -6105,7 +6167,7 @@ commander@2.6.0:
resolved "https://registry.yarnpkg.com/commander/-/commander-2.6.0.tgz#9df7e52fb2a0cb0fb89058ee80c3104225f37e1d"
integrity sha1-nfflL7Kgyw+4kFjugMMQQiXzfh0=
commander@3.0.2:
commander@3.0.2, commander@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/commander/-/commander-3.0.2.tgz#6837c3fb677ad9933d1cfba42dd14d5117d6b39e"
integrity sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==
@@ -6457,7 +6519,7 @@ core-js@^2.4.0:
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.8.tgz#dc3a1e633a04267944e0cb850d3880f340248139"
integrity sha512-RWlREFU74TEkdXzyl1bka66O3kYp8jeTXrvJZDzVVMH8AiHUSOFpL1yfhQJ+wHocAm1m+4971W1PPzfLuCv1vg==
core-js@^2.5.0:
core-js@^2.5.0, core-js@^2.6.5:
version "2.6.11"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c"
integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==
@@ -6892,6 +6954,14 @@ customize-cra@^1.0.0:
dependencies:
lodash.flow "^3.5.0"
cwd@^0.10.0:
version "0.10.0"
resolved "https://registry.yarnpkg.com/cwd/-/cwd-0.10.0.tgz#172400694057c22a13b0cf16162c7e4b7a7fe567"
integrity sha1-FyQAaUBXwioTsM8WFix+S3p/5Wc=
dependencies:
find-pkg "^0.1.2"
fs-exists-sync "^0.1.0"
cyclist@~0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640"
@@ -6984,6 +7054,13 @@ debug@3.2.6, debug@^3.1.0, debug@^3.2.5, debug@^3.2.6:
dependencies:
ms "^2.1.1"
debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
dependencies:
ms "^2.1.1"
debug@4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.0.tgz#373687bffa678b38b1cd91f861b63850035ddc87"
@@ -6991,13 +7068,6 @@ debug@4.1.0:
dependencies:
ms "^2.1.1"
debug@^4.0.1, debug@^4.1.0, debug@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
dependencies:
ms "^2.1.1"
debuglog@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492"
@@ -7335,6 +7405,11 @@ detect-port-alt@1.1.6:
address "^1.0.1"
debug "^2.6.0"
devtools-protocol@0.0.781568:
version "0.0.781568"
resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.781568.tgz#4cdca90a952d2c77831096ff6cd32695d8715a04"
integrity sha512-9Uqnzy6m6zEStluH9iyJ3iHyaQziFnMnLeC8vK0eN6smiJmIx7+yB64d67C2lH/LZra+5cGscJAJsNXO+MdPMg==
dezalgo@^1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456"
@@ -8039,6 +8114,13 @@ eslint-plugin-import@^2.18.2:
read-pkg-up "^2.0.0"
resolve "^1.12.0"
eslint-plugin-jest@^23.18.0:
version "23.18.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-23.18.0.tgz#4813eacb181820ed13c5505f400956d176b25af8"
integrity sha512-wLPM/Rm1SGhxrFQ2TKM/BYsYPhn7ch6ZEK92S2o/vGkAAnDXM0I4nTIo745RIX+VlCRMFgBuJEax6XfTHMdeKg==
dependencies:
"@typescript-eslint/experimental-utils" "^2.5.0"
eslint-plugin-jsx-a11y@6.2.1, eslint-plugin-jsx-a11y@^6.2.1:
version "6.2.1"
resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.2.1.tgz#4ebba9f339b600ff415ae4166e3e2e008831cf0c"
@@ -8184,6 +8266,13 @@ eslint-utils@^1.3.0, eslint-utils@^1.3.1, eslint-utils@^1.4.2, eslint-utils@^1.4
dependencies:
eslint-visitor-keys "^1.1.0"
eslint-utils@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27"
integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==
dependencies:
eslint-visitor-keys "^1.1.0"
eslint-visitor-keys@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d"
@@ -8887,6 +8976,13 @@ expand-template@^2.0.3:
resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c"
integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==
expand-tilde@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-1.2.2.tgz#0b81eba897e5a3d31d1c3d102f8f01441e559449"
integrity sha1-C4HrqJflo9MdHD0QL48BRB5VlEk=
dependencies:
os-homedir "^1.0.1"
expand-tilde@^2.0.0, expand-tilde@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502"
@@ -8894,6 +8990,11 @@ expand-tilde@^2.0.0, expand-tilde@^2.0.2:
dependencies:
homedir-polyfill "^1.0.1"
expect-puppeteer@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/expect-puppeteer/-/expect-puppeteer-4.4.0.tgz#1c948af08acdd6c8cbdb7f90e617f44d86888886"
integrity sha512-6Ey4Xy2xvmuQu7z7YQtMsaMV0EHJRpVxIDOd5GRrm04/I3nkTKIutELfECsLp6le+b3SSa3cXhPiw6PgqzxYWA==
expect@^24.8.0:
version "24.8.0"
resolved "https://registry.yarnpkg.com/expect/-/expect-24.8.0.tgz#471f8ec256b7b6129ca2524b2a62f030df38718d"
@@ -9017,6 +9118,17 @@ extract-zip@^1.6.7:
mkdirp "0.5.1"
yauzl "2.4.1"
extract-zip@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a"
integrity sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==
dependencies:
debug "^4.1.1"
get-stream "^5.1.0"
yauzl "^2.10.0"
optionalDependencies:
"@types/yauzl" "^2.9.1"
extsprintf@1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
@@ -9279,6 +9391,30 @@ find-cache-dir@^2.0.0:
make-dir "^2.0.0"
pkg-dir "^3.0.0"
find-file-up@^0.1.2:
version "0.1.3"
resolved "https://registry.yarnpkg.com/find-file-up/-/find-file-up-0.1.3.tgz#cf68091bcf9f300a40da411b37da5cce5a2fbea0"
integrity sha1-z2gJG8+fMApA2kEbN9pczlovvqA=
dependencies:
fs-exists-sync "^0.1.0"
resolve-dir "^0.1.0"
find-pkg@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/find-pkg/-/find-pkg-0.1.2.tgz#1bdc22c06e36365532e2a248046854b9788da557"
integrity sha1-G9wiwG42NlUy4qJIBGhUuXiNpVc=
dependencies:
find-file-up "^0.1.2"
find-process@^1.4.3:
version "1.4.3"
resolved "https://registry.yarnpkg.com/find-process/-/find-process-1.4.3.tgz#25f9105dc32e42abad4636752c37c51cd57dce45"
integrity sha512-+IA+AUsQCf3uucawyTwMWcY+2M3FXq3BRvw3S+j5Jvydjk31f/+NPWpYZOJs+JUs2GvxH4Yfr6Wham0ZtRLlPA==
dependencies:
chalk "^2.0.1"
commander "^2.11.0"
debug "^2.6.8"
find-up@3.0.0, find-up@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73"
@@ -9301,6 +9437,14 @@ find-up@^2.0.0, find-up@^2.1.0:
dependencies:
locate-path "^2.0.0"
find-up@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
dependencies:
locate-path "^5.0.0"
path-exists "^4.0.0"
findup-sync@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc"
@@ -9499,6 +9643,11 @@ fs-constants@^1.0.0:
resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==
fs-exists-sync@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add"
integrity sha1-mC1ok6+RjnLQjeyehnP/K1qNat0=
fs-extra@7.0.1, fs-extra@^7.0.0:
version "7.0.1"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9"
@@ -9680,6 +9829,14 @@ ganache-core@^2.6.0:
ethereumjs-wallet "0.6.3"
web3 "1.2.4"
gas-price-oracle@^0.1.5:
version "0.1.5"
resolved "https://registry.yarnpkg.com/gas-price-oracle/-/gas-price-oracle-0.1.5.tgz#09dd0d9806465c2f5e63b682e6742f96f6eb525c"
integrity sha512-fkaTXnxJcSVco/tMPEcN5gieoUNs8O6JYMXflGLN2+3YeGZAucUI0fgCliazM3nRVAk//bBEm9819/Zb83xhrw==
dependencies:
axios "^0.19.2"
bignumber.js "^9.0.0"
gauge@~2.7.3:
version "2.7.4"
resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
@@ -9936,7 +10093,7 @@ glob@^5.0.15:
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@^7.0.0, glob@^7.0.3, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@~7.1.1, glob@~7.1.6:
glob@^7.0.0, glob@^7.0.3, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@~7.1.1, glob@~7.1.6:
version "7.1.6"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
@@ -9974,6 +10131,14 @@ global-modules@2.0.0:
dependencies:
global-prefix "^3.0.0"
global-modules@^0.2.3:
version "0.2.3"
resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d"
integrity sha1-6lo77ULG1s6ZWk+KEmm12uIjgo0=
dependencies:
global-prefix "^0.1.4"
is-windows "^0.2.0"
global-modules@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea"
@@ -9983,6 +10148,16 @@ global-modules@^1.0.0:
is-windows "^1.0.1"
resolve-dir "^1.0.0"
global-prefix@^0.1.4:
version "0.1.5"
resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-0.1.5.tgz#8d3bc6b8da3ca8112a160d8d496ff0462bfef78f"
integrity sha1-jTvGuNo8qBEqFg2NSW/wRiv+948=
dependencies:
homedir-polyfill "^1.0.0"
ini "^1.3.4"
is-windows "^0.2.0"
which "^1.2.12"
global-prefix@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe"
@@ -10500,7 +10675,7 @@ home-or-tmp@^2.0.0:
os-homedir "^1.0.0"
os-tmpdir "^1.0.1"
homedir-polyfill@^1.0.1:
homedir-polyfill@^1.0.0, homedir-polyfill@^1.0.1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8"
integrity sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==
@@ -10707,6 +10882,14 @@ https-proxy-agent@^2.2.3:
agent-base "^4.3.0"
debug "^3.1.0"
https-proxy-agent@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz#702b71fb5520a132a66de1f67541d9e62154d82b"
integrity sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==
dependencies:
agent-base "5"
debug "4"
humanize-ms@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed"
@@ -11566,6 +11749,11 @@ is-valid-glob@^1.0.0:
resolved "https://registry.yarnpkg.com/is-valid-glob/-/is-valid-glob-1.0.0.tgz#29bf3eff701be2d4d315dbacc39bc39fe8f601aa"
integrity sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao=
is-windows@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c"
integrity sha1-3hqm1j6indJIc3tp8f+LgALSEIw=
is-windows@^1.0.0, is-windows@^1.0.1, is-windows@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
@@ -11807,6 +11995,19 @@ jest-config@^24.8.0:
pretty-format "^24.8.0"
realpath-native "^1.1.0"
jest-dev-server@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/jest-dev-server/-/jest-dev-server-4.4.0.tgz#557113faae2877452162696aa94c1e44491ab011"
integrity sha512-STEHJ3iPSC8HbrQ3TME0ozGX2KT28lbT4XopPxUm2WimsX3fcB3YOptRh12YphQisMhfqNSNTZUmWyT3HEXS2A==
dependencies:
chalk "^3.0.0"
cwd "^0.10.0"
find-process "^1.4.3"
prompts "^2.3.0"
spawnd "^4.4.0"
tree-kill "^1.2.2"
wait-on "^3.3.0"
jest-diff@^24.0.0, jest-diff@^24.8.0:
version "24.8.0"
resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-24.8.0.tgz#146435e7d1e3ffdf293d53ff97e193f1d1546172"
@@ -11896,6 +12097,16 @@ jest-environment-node@^24.8.0:
jest-mock "^24.8.0"
jest-util "^24.8.0"
jest-environment-puppeteer@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/jest-environment-puppeteer/-/jest-environment-puppeteer-4.4.0.tgz#d82a37e0e0c51b63cc6b15dea101d53967508860"
integrity sha512-iV8S8+6qkdTM6OBR/M9gKywEk8GDSOe05hspCs5D8qKSwtmlUfdtHfB4cakdc68lC6YfK3AUsLirpfgodCHjzQ==
dependencies:
chalk "^3.0.0"
cwd "^0.10.0"
jest-dev-server "^4.4.0"
merge-deep "^3.0.2"
jest-get-type@^24.8.0:
version "24.8.0"
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-24.8.0.tgz#a7440de30b651f5a70ea3ed7ff073a32dfe646fc"
@@ -11990,6 +12201,14 @@ jest-pnp-resolver@^1.2.1:
resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz#ecdae604c077a7fbc70defb6d517c3c1c898923a"
integrity sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ==
jest-puppeteer@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/jest-puppeteer/-/jest-puppeteer-4.4.0.tgz#4b906e638a5e3782ed865e7b673c82047b85952e"
integrity sha512-ZaiCTlPZ07B9HW0erAWNX6cyzBqbXMM7d2ugai4epBDKpKvRDpItlRQC6XjERoJELKZsPziFGS0OhhUvTvQAXA==
dependencies:
expect-puppeteer "^4.4.0"
jest-environment-puppeteer "^4.4.0"
jest-regex-util@^24.3.0:
version "24.3.0"
resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-24.3.0.tgz#d5a65f60be1ae3e310d5214a0307581995227b36"
@@ -12548,7 +12767,7 @@ klaw@^1.0.0:
optionalDependencies:
graceful-fs "^4.1.9"
kleur@^3.0.2:
kleur@^3.0.2, kleur@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e"
integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==
@@ -12895,6 +13114,13 @@ locate-path@^3.0.0:
p-locate "^3.0.0"
path-exists "^3.0.0"
locate-path@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==
dependencies:
p-locate "^4.1.0"
lodash._reinterpolate@^3.0.0, lodash._reinterpolate@~3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
@@ -14814,6 +15040,13 @@ p-limit@^2.0.0:
dependencies:
p-try "^2.0.0"
p-limit@^2.2.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
dependencies:
p-try "^2.0.0"
p-locate@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43"
@@ -14828,6 +15061,13 @@ p-locate@^3.0.0:
dependencies:
p-limit "^2.0.0"
p-locate@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07"
integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==
dependencies:
p-limit "^2.2.0"
p-map-series@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/p-map-series/-/p-map-series-1.0.0.tgz#bf98fe575705658a9e1351befb85ae4c1f07bdca"
@@ -15063,6 +15303,11 @@ path-exists@^3.0.0:
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=
path-exists@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
path-is-absolute@^1.0.0, path-is-absolute@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
@@ -15250,6 +15495,13 @@ pkg-dir@^3.0.0:
dependencies:
find-up "^3.0.0"
pkg-dir@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3"
integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==
dependencies:
find-up "^4.0.0"
pkg-up@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-2.0.0.tgz#c819ac728059a461cab1c3889a2be3c49a004d7f"
@@ -16094,7 +16346,7 @@ process@~0.5.1:
resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf"
integrity sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8=
progress@^2.0.0:
progress@^2.0.0, progress@^2.0.1:
version "2.0.3"
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
@@ -16165,6 +16417,14 @@ prompts@^2.0.1:
kleur "^3.0.2"
sisteransi "^1.0.0"
prompts@^2.3.0:
version "2.3.2"
resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.3.2.tgz#480572d89ecf39566d2bd3fe2c9fccb7c4c0b068"
integrity sha512-Q06uKs2CkNYVID0VqwfAl9mipo99zkBv/n2JtWY89Yxa3ZabWSrs0e2KTudKVa3peLUvYXMefDqIleLPVUBZMA==
dependencies:
kleur "^3.0.3"
sisteransi "^1.0.4"
promzard@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/promzard/-/promzard-0.3.0.tgz#26a5d6ee8c7dee4cb12208305acfb93ba382a9ee"
@@ -16213,6 +16473,11 @@ proxy-addr@~2.0.5:
forwarded "~0.1.2"
ipaddr.js "1.9.0"
proxy-from-env@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
proxyquire@^2.0.1:
version "2.1.0"
resolved "https://registry.yarnpkg.com/proxyquire/-/proxyquire-2.1.0.tgz#c2263a38bf0725f2ae950facc130e27510edce8d"
@@ -16357,6 +16622,24 @@ punycode@^2.1.0, punycode@^2.1.1:
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
puppeteer@^5.2.1:
version "5.2.1"
resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-5.2.1.tgz#7f0564f0a5384f352a38c8cc42af875cd87f4ea6"
integrity sha512-PZoZG7u+T6N1GFWBQmGVG162Ak5MAy8nYSVpeeQrwJK2oYUlDWpHEJPcd/zopyuEMTv7DiztS1blgny1txR2qw==
dependencies:
debug "^4.1.0"
devtools-protocol "0.0.781568"
extract-zip "^2.0.0"
https-proxy-agent "^4.0.0"
mime "^2.0.3"
pkg-dir "^4.2.0"
progress "^2.0.1"
proxy-from-env "^1.0.0"
rimraf "^3.0.2"
tar-fs "^2.0.0"
unbzip2-stream "^1.3.3"
ws "^7.2.3"
q@^1.1.2, q@^1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
@@ -17320,6 +17603,14 @@ resolve-cwd@^2.0.0:
dependencies:
resolve-from "^3.0.0"
resolve-dir@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-0.1.1.tgz#b219259a5602fac5c5c496ad894a6e8cc430261e"
integrity sha1-shklmlYC+sXFxJatiUpujMQwJh4=
dependencies:
expand-tilde "^1.2.2"
global-modules "^0.2.3"
resolve-dir@^1.0.0, resolve-dir@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43"
@@ -17474,6 +17765,13 @@ rimraf@2.6.3, rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf
dependencies:
glob "^7.1.3"
rimraf@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
dependencies:
glob "^7.1.3"
ripemd160@^2.0.0, ripemd160@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c"
@@ -17525,6 +17823,11 @@ rx@2.3.24:
resolved "https://registry.yarnpkg.com/rx/-/rx-2.3.24.tgz#14f950a4217d7e35daa71bbcbe58eff68ea4b2b7"
integrity sha1-FPlQpCF9fjXapxu8vljv9o6ksrc=
rx@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782"
integrity sha1-pfE/957zt0D+MKqAP7CfmIBdR4I=
rxjs@^6.4.0:
version "6.5.2"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.2.tgz#2e35ce815cd46d84d02a209fb4e5921e051dbec7"
@@ -17805,6 +18108,11 @@ semver@^7.1.3:
resolved "https://registry.yarnpkg.com/semver/-/semver-7.1.3.tgz#e4345ce73071c53f336445cfc19efb1c311df2a6"
integrity sha512-ekM0zfiA9SCBlsKa2X1hxyxiI4L3B6EbVJkkdgQXnSEEaHlGdvyodMruTiulSRWMMB4NeIuYNMC9rTKTz97GxA==
semver@^7.3.2:
version "7.3.2"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938"
integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==
semver@~5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
@@ -18069,6 +18377,11 @@ sisteransi@^1.0.0:
resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.0.tgz#77d9622ff909080f1c19e5f4a1df0c1b0a27b88c"
integrity sha512-N+z4pHB4AmUv0SjveWRd6q1Nj5w62m5jodv+GD8lvmbY/83T/rpbJGZOnK5T149OldDj4Db07BSv9xY4K6NTPQ==
sisteransi@^1.0.4:
version "1.0.5"
resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed"
integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==
slash@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55"
@@ -18317,6 +18630,16 @@ spawn-wrap@^1.4.2:
signal-exit "^3.0.2"
which "^1.3.0"
spawnd@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/spawnd/-/spawnd-4.4.0.tgz#bb52c5b34a22e3225ae1d3acb873b2cd58af0886"
integrity sha512-jLPOfB6QOEgMOQY15Z6+lwZEhH3F5ncXxIaZ7WHPIapwNNLyjrs61okj3VJ3K6tmP5TZ6cO0VAu9rEY4MD4YQg==
dependencies:
exit "^0.1.2"
signal-exit "^3.0.2"
tree-kill "^1.2.2"
wait-port "^0.2.7"
spdx-correct@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4"
@@ -19414,7 +19737,7 @@ tr46@^1.0.1:
dependencies:
punycode "^2.1.0"
tree-kill@^1.1.0, tree-kill@^1.2.0:
tree-kill@^1.1.0, tree-kill@^1.2.0, tree-kill@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc"
integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==
@@ -19502,6 +19825,13 @@ tsort@0.0.1:
resolved "https://registry.yarnpkg.com/tsort/-/tsort-0.0.1.tgz#e2280f5e817f8bf4275657fd0f9aebd44f5a2786"
integrity sha1-4igPXoF/i/QnVlf9D5rr1E9aJ4Y=
tsutils@^3.17.1:
version "3.17.1"
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759"
integrity sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==
dependencies:
tslib "^1.8.1"
tsutils@^3.7.0:
version "3.10.0"
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.10.0.tgz#6f1c95c94606e098592b0dff06590cf9659227d6"
@@ -19664,6 +19994,14 @@ unbzip2-stream@^1.0.9:
buffer "^5.2.1"
through "^2.3.8"
unbzip2-stream@^1.3.3:
version "1.4.3"
resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz#b0da04c4371311df771cdc215e87f2130991ace7"
integrity sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==
dependencies:
buffer "^5.2.1"
through "^2.3.8"
unc-path-regex@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa"
@@ -20209,6 +20547,26 @@ wait-for-expect@^3.0.2:
resolved "https://registry.yarnpkg.com/wait-for-expect/-/wait-for-expect-3.0.2.tgz#d2f14b2f7b778c9b82144109c8fa89ceaadaa463"
integrity sha512-cfS1+DZxuav1aBYbaO/kE06EOS8yRw7qOFoD3XtjTkYvCvh3zUvNST8DXK/nPaeqIzIv3P3kL3lRJn8iwOiSag==
wait-on@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/wait-on/-/wait-on-3.3.0.tgz#9940981d047a72a9544a97b8b5fca45b2170a082"
integrity sha512-97dEuUapx4+Y12aknWZn7D25kkjMk16PbWoYzpSdA8bYpVfS6hpl2a2pOWZ3c+Tyt3/i4/pglyZctG3J4V1hWQ==
dependencies:
"@hapi/joi" "^15.0.3"
core-js "^2.6.5"
minimist "^1.2.0"
request "^2.88.0"
rx "^4.1.0"
wait-port@^0.2.7:
version "0.2.9"
resolved "https://registry.yarnpkg.com/wait-port/-/wait-port-0.2.9.tgz#3905cf271b5dbe37a85c03b85b418b81cb24ee55"
integrity sha512-hQ/cVKsNqGZ/UbZB/oakOGFqic00YAMM5/PEj3Bt4vKarv2jWIWzDbqlwT94qMs/exAQAsvMOq99sZblV92zxQ==
dependencies:
chalk "^2.4.2"
commander "^3.0.2"
debug "^4.1.1"
walker@^1.0.7, walker@~1.0.5:
version "1.0.7"
resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb"
@@ -21437,7 +21795,7 @@ which-pm-runs@^1.0.0:
resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb"
integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=
which@1, which@^1.1.1, which@^1.2.14, which@^1.2.9, which@^1.3.0, which@^1.3.1:
which@1, which@^1.1.1, which@^1.2.12, which@^1.2.14, which@^1.2.9, which@^1.3.0, which@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
@@ -21749,6 +22107,11 @@ ws@^6.1.2:
dependencies:
async-limiter "~1.0.0"
ws@^7.2.3:
version "7.3.1"
resolved "https://registry.yarnpkg.com/ws/-/ws-7.3.1.tgz#d0547bf67f7ce4f12a72dfe31262c68d7dc551c8"
integrity sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA==
wsrun@3.6.5:
version "3.6.5"
resolved "https://registry.yarnpkg.com/wsrun/-/wsrun-3.6.5.tgz#febcfb72e63d401da72829baac7f50760bb01af6"
@@ -22077,7 +22440,7 @@ yauzl@2.4.1:
dependencies:
fd-slicer "~1.0.1"
yauzl@^2.4.2:
yauzl@^2.10.0, yauzl@^2.4.2:
version "2.10.0"
resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9"
integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=