diff --git a/CONFIGURATION.md b/CONFIGURATION.md index 20251b9b6..f13d24b85 100644 --- a/CONFIGURATION.md +++ b/CONFIGURATION.md @@ -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 diff --git a/commons/abis.js b/commons/abis.js index 62289d2d6..0f8040957 100644 --- a/commons/abis.js +++ b/commons/abis.js @@ -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 } diff --git a/commons/package.json b/commons/package.json index 200922ac1..5c30bf55c 100644 --- a/commons/package.json +++ b/commons/package.json @@ -8,6 +8,7 @@ "test": "NODE_ENV=test mocha" }, "dependencies": { + "gas-price-oracle": "^0.1.5", "web3-utils": "1.0.0-beta.34" }, "devDependencies": { diff --git a/commons/utils.js b/commons/utils.js index 965eb0085..520008c1c 100644 --- a/commons/utils.js +++ b/commons/utils.js @@ -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) { diff --git a/contracts b/contracts index f405ba9e5..dd4613524 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit f405ba9e56ca447b84ee5d53e93ac919b8f8565f +Subproject commit dd46135248dbb4684752735aab3cf64db170a405 diff --git a/e2e-commons/constants.json b/e2e-commons/constants.json index ecdfab103..904e1ba5c 100644 --- a/e2e-commons/constants.json +++ b/e2e-commons/constants.json @@ -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" diff --git a/e2e-commons/up.sh b/e2e-commons/up.sh index cf56d69a6..b54481aac 100755 --- a/e2e-commons/up.sh +++ b/e2e-commons/up.sh @@ -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 @@ -57,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 diff --git a/monitor/docker-compose-build.yml b/monitor/docker-compose-build.yml index 08faa1987..124f89c52 100644 --- a/monitor/docker-compose-build.yml +++ b/monitor/docker-compose-build.yml @@ -3,4 +3,6 @@ version: '2.4' services: monitor: image: poanetwork/tokenbridge-monitor - build: . + build: + context: .. + dockerfile: ./monitor/Dockerfile diff --git a/monitor/validators.js b/monitor/validators.js index e298b06b3..e8f71dfcf 100644 --- a/monitor/validators.js +++ b/monitor/validators.js @@ -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)) diff --git a/oracle-e2e/test/ercToNative.js b/oracle-e2e/test/ercToNative.js index a5dca5b7a..33b9092f6 100644 --- a/oracle-e2e/test/ercToNative.js +++ b/oracle-e2e/test/ercToNative.js @@ -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) diff --git a/oracle/config/half-duplex-transfer-watcher.config.js b/oracle/config/half-duplex-transfer-watcher.config.js deleted file mode 100644 index 1ec942282..000000000 --- a/oracle/config/half-duplex-transfer-watcher.config.js +++ /dev/null @@ -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 -} diff --git a/oracle/config/swap-tokens-worker.config.js b/oracle/config/swap-tokens-worker.config.js deleted file mode 100644 index 9ef53d85e..000000000 --- a/oracle/config/swap-tokens-worker.config.js +++ /dev/null @@ -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 -} diff --git a/oracle/docker-compose-build.yml b/oracle/docker-compose-build.yml index c129d6629..5905acd2b 100644 --- a/oracle/docker-compose-build.yml +++ b/oracle/docker-compose-build.yml @@ -3,4 +3,6 @@ version: '2.4' services: oracle: image: poanetwork/tokenbridge-oracle - build: . + build: + context: .. + dockerfile: ./oracle/Dockerfile diff --git a/oracle/docker-compose-erc-native.yml b/oracle/docker-compose-erc-native.yml index 655d78060..cc6427677 100644 --- a/oracle/docker-compose-erc-native.yml +++ b/oracle/docker-compose-erc-native.yml @@ -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: diff --git a/oracle/package.json b/oracle/package.json index 2872aa6cd..0eb384eed 100644 --- a/oracle/package.json +++ b/oracle/package.json @@ -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", diff --git a/oracle/src/events/processHalfDuplexTransfers/index.js b/oracle/src/events/processHalfDuplexTransfers/index.js deleted file mode 100644 index 0bd9b8810..000000000 --- a/oracle/src/events/processHalfDuplexTransfers/index.js +++ /dev/null @@ -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 diff --git a/oracle/src/services/gasPrice.js b/oracle/src/services/gasPrice.js index 96a4c8ac0..6cd25c1df 100644 --- a/oracle/src/services/gasPrice.js +++ b/oracle/src/services/gasPrice.js @@ -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 diff --git a/oracle/src/utils/tokenState.js b/oracle/src/utils/tokenState.js index 8d2d98633..f3e5e59ca 100644 --- a/oracle/src/utils/tokenState.js +++ b/oracle/src/utils/tokenState.js @@ -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 } diff --git a/oracle/src/watcher.js b/oracle/src/watcher.js index 1687ac69f..cc99f9b11 100644 --- a/oracle/src/watcher.js +++ b/oracle/src/watcher.js @@ -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) { diff --git a/oracle/src/worker.js b/oracle/src/worker.js index 773d89438..0836c8fad 100644 --- a/oracle/src/worker.js +++ b/oracle/src/worker.js @@ -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 [] diff --git a/oracle/src/workers/swapTokens.js b/oracle/src/workers/swapTokens.js deleted file mode 100644 index 9635df8c5..000000000 --- a/oracle/src/workers/swapTokens.js +++ /dev/null @@ -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 diff --git a/ui/src/stores/GasPriceStore.js b/ui/src/stores/GasPriceStore.js index 328c588e0..20a286550 100644 --- a/ui/src/stores/GasPriceStore.js +++ b/ui/src/stores/GasPriceStore.js @@ -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) } diff --git a/yarn.lock b/yarn.lock index e86569d03..2263a4412 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4209,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" @@ -9822,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"