Merge the develop branch to the master branch, preparation to v3.1.0
This merge contains the following set of changes: * [Oracle, Improvement] Try to detect unsynced node state (#592) * [Oracle, Improvement] Allow to override JSON RPC error codes (#603) * [Oracle, Fix] Fix handling of Compound related Transfer events (#595) * [Oracle, Fix] Add new nonce-related error messages (#599) * [Deployment, Fix] .env template includes latest changes related to the oracle configuration (#601) * [Deployment, Fix] Improvements for the local logs configuration (#602) * [Common, Other] Update the contract's submodule to the release 6.0.0 (#600)
This commit is contained in:
commit
78564afabd
4
.github/workflows/main.yml
vendored
4
.github/workflows/main.yml
vendored
@ -77,7 +77,7 @@ jobs:
|
|||||||
- name: Rebuild and push updated images
|
- name: Rebuild and push updated images
|
||||||
run: |
|
run: |
|
||||||
function check_if_image_exists() {
|
function check_if_image_exists() {
|
||||||
curl -fsSlL -H 'Authorization: bearer ${{ github.token }}' "https://${DOCKER_REGISTRY}/v2/${DOCKER_REPO}/tokenbridge-e2e-$1/manifests/$2" > /dev/null
|
curl -fsSlL "https://${{ github.actor }}:${{ github.token }}@${DOCKER_REGISTRY}/v2/${DOCKER_REPO}/tokenbridge-e2e-$1/manifests/$2" > /dev/null
|
||||||
}
|
}
|
||||||
updated=()
|
updated=()
|
||||||
if ! check_if_image_exists e2e ${E2E_TAG}; then updated+=("e2e"); fi
|
if ! check_if_image_exists e2e ${E2E_TAG}; then updated+=("e2e"); fi
|
||||||
@ -104,7 +104,7 @@ jobs:
|
|||||||
- name: Rebuild and push molecule runner e2e image
|
- name: Rebuild and push molecule runner e2e image
|
||||||
run: |
|
run: |
|
||||||
function check_if_image_exists() {
|
function check_if_image_exists() {
|
||||||
curl -fsSlL -H 'Authorization: bearer ${{ github.token }}' "https://${DOCKER_REGISTRY}/v2/${DOCKER_REPO}/tokenbridge-e2e-$1/manifests/$2" > /dev/null
|
curl -fsSlL "https://${{ github.actor }}:${{ github.token }}@${DOCKER_REGISTRY}/v2/${DOCKER_REPO}/tokenbridge-e2e-$1/manifests/$2" > /dev/null
|
||||||
}
|
}
|
||||||
if check_if_image_exists molecule_runner ${MOLECULE_RUNNER_TAG}; then
|
if check_if_image_exists molecule_runner ${MOLECULE_RUNNER_TAG}; then
|
||||||
echo "Image already exists"
|
echo "Image already exists"
|
||||||
|
@ -52,6 +52,7 @@ ORACLE_SHUTDOWN_CONTRACT_ADDRESS | Optional contract address in the side chain a
|
|||||||
ORACLE_SHUTDOWN_CONTRACT_METHOD | Method signature to be used in the side chain to identify the current shutdown status. Method should return boolean. Default value is `isShutdown()`. | `function signature`
|
ORACLE_SHUTDOWN_CONTRACT_METHOD | Method signature to be used in the side chain to identify the current shutdown status. Method should return boolean. Default value is `isShutdown()`. | `function signature`
|
||||||
ORACLE_FOREIGN_RPC_BLOCK_POLLING_LIMIT | Max length for the block range used in `eth_getLogs` requests for polling contract events for the Foreign chain. Infinite, if not provided. | `integer`
|
ORACLE_FOREIGN_RPC_BLOCK_POLLING_LIMIT | Max length for the block range used in `eth_getLogs` requests for polling contract events for the Foreign chain. Infinite, if not provided. | `integer`
|
||||||
ORACLE_HOME_RPC_BLOCK_POLLING_LIMIT | Max length for the block range used in `eth_getLogs` requests for polling contract events for the Home chain. Infinite, if not provided. | `integer`
|
ORACLE_HOME_RPC_BLOCK_POLLING_LIMIT | Max length for the block range used in `eth_getLogs` requests for polling contract events for the Home chain. Infinite, if not provided. | `integer`
|
||||||
|
ORACLE_JSONRPC_ERROR_CODES | Override default JSON rpc error codes that can trigger RPC fallback to the next URL from the list (or a retry in case of a single RPC URL). Default is `-32603,-32002,-32005`. Should be a comma-separated list of negative integers. | `string`
|
||||||
|
|
||||||
|
|
||||||
## Monitor configuration
|
## Monitor configuration
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
const HOME_ERC_TO_NATIVE_ABI = require('../contracts/build/contracts/HomeBridgeErcToNative').abi
|
const HOME_ERC_TO_NATIVE_ABI = require('../contracts/build/contracts/HomeBridgeErcToNative').abi
|
||||||
const FOREIGN_ERC_TO_NATIVE_ABI = require('../contracts/build/contracts/ForeignBridgeErcToNative').abi
|
const FOREIGN_ERC_TO_NATIVE_ABI = require('../contracts/build/contracts/XDaiForeignBridge.json').abi
|
||||||
const ERC20_ABI = require('../contracts/build/contracts/ERC20').abi
|
const ERC20_ABI = require('../contracts/build/contracts/ERC20').abi
|
||||||
const BLOCK_REWARD_ABI = require('../contracts/build/contracts/BlockRewardMock').abi
|
const BLOCK_REWARD_ABI = require('../contracts/build/contracts/BlockRewardMock').abi
|
||||||
const BRIDGE_VALIDATORS_ABI = require('../contracts/build/contracts/BridgeValidators').abi
|
const BRIDGE_VALIDATORS_ABI = require('../contracts/build/contracts/BridgeValidators').abi
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 004d466a3d593e6304e52c74e6c3e801b6a33b32
|
Subproject commit 908a48107919d4ab127f9af07d44d47eac91547e
|
@ -1,6 +1,6 @@
|
|||||||
/var/log/docker/*/docker.log {
|
/var/log/docker/*/docker.log {
|
||||||
rotate 5
|
rotate 5
|
||||||
size 1G
|
size 100M
|
||||||
compress
|
compress
|
||||||
missingok
|
missingok
|
||||||
delaycompress
|
delaycompress
|
||||||
@ -8,7 +8,7 @@
|
|||||||
}
|
}
|
||||||
/var/log/docker/*.log {
|
/var/log/docker/*.log {
|
||||||
rotate 5
|
rotate 5
|
||||||
size 1G
|
size 100M
|
||||||
compress
|
compress
|
||||||
missingok
|
missingok
|
||||||
delaycompress
|
delaycompress
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
loop_control:
|
loop_control:
|
||||||
loop_var: file
|
loop_var: file
|
||||||
|
|
||||||
- name: Set the local container logs configuration file
|
- name: Set the oracle's containers local logs configuration file
|
||||||
template:
|
template:
|
||||||
src: 31-oracle-docker.conf.j2
|
src: 31-oracle-docker.conf.j2
|
||||||
dest: /etc/rsyslog.d/31-oracle-docker.conf
|
dest: /etc/rsyslog.d/31-oracle-docker.conf
|
||||||
@ -15,6 +15,22 @@
|
|||||||
group: root
|
group: root
|
||||||
mode: 0644
|
mode: 0644
|
||||||
|
|
||||||
|
- name: Set the redis container local logs configuration file
|
||||||
|
template:
|
||||||
|
src: 32-redis-docker.conf.j2
|
||||||
|
dest: /etc/rsyslog.d/32-redis-docker.conf
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: 0644
|
||||||
|
|
||||||
|
- name: Set the rabbit MQ container local logs configuration file
|
||||||
|
template:
|
||||||
|
src: 33-rabbit-docker.conf.j2
|
||||||
|
dest: /etc/rsyslog.d/33-rabbit-docker.conf
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: 0644
|
||||||
|
|
||||||
- name: Set the log configuration file to send container logs to remote server
|
- name: Set the log configuration file to send container logs to remote server
|
||||||
template:
|
template:
|
||||||
src: 36-oracle-remote-logging.conf.j2
|
src: 36-oracle-remote-logging.conf.j2
|
||||||
|
@ -11,9 +11,16 @@ ORACLE_HOME_RPC_POLLING_INTERVAL={{ ORACLE_HOME_RPC_POLLING_INTERVAL }}
|
|||||||
|
|
||||||
## Foreign contract
|
## Foreign contract
|
||||||
COMMON_FOREIGN_RPC_URL={{ COMMON_FOREIGN_RPC_URL }}
|
COMMON_FOREIGN_RPC_URL={{ COMMON_FOREIGN_RPC_URL }}
|
||||||
|
{% if ORACLE_FOREIGN_ARCHIVE_RPC_URL | default('') != '' %}
|
||||||
|
ORACLE_FOREIGN_ARCHIVE_RPC_URL={{ ORACLE_FOREIGN_ARCHIVE_RPC_URL }}
|
||||||
|
{% endif %}
|
||||||
COMMON_FOREIGN_BRIDGE_ADDRESS={{ COMMON_FOREIGN_BRIDGE_ADDRESS }}
|
COMMON_FOREIGN_BRIDGE_ADDRESS={{ COMMON_FOREIGN_BRIDGE_ADDRESS }}
|
||||||
ORACLE_FOREIGN_RPC_POLLING_INTERVAL={{ ORACLE_FOREIGN_RPC_POLLING_INTERVAL }}
|
ORACLE_FOREIGN_RPC_POLLING_INTERVAL={{ ORACLE_FOREIGN_RPC_POLLING_INTERVAL }}
|
||||||
|
|
||||||
|
{% if ORACLE_TX_REDUNDANCY | default('') != '' %}
|
||||||
|
ORACLE_TX_REDUNDANCY={{ ORACLE_TX_REDUNDANCY }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
## Gasprice
|
## Gasprice
|
||||||
{% if COMMON_HOME_GAS_PRICE_SUPPLIER_URL | default('') != '' %}
|
{% if COMMON_HOME_GAS_PRICE_SUPPLIER_URL | default('') != '' %}
|
||||||
COMMON_HOME_GAS_PRICE_SUPPLIER_URL={{ COMMON_HOME_GAS_PRICE_SUPPLIER_URL }}
|
COMMON_HOME_GAS_PRICE_SUPPLIER_URL={{ COMMON_HOME_GAS_PRICE_SUPPLIER_URL }}
|
||||||
@ -47,8 +54,28 @@ COMMON_FOREIGN_GAS_PRICE_FACTOR={{ COMMON_FOREIGN_GAS_PRICE_FACTOR }}
|
|||||||
ORACLE_ALLOW_HTTP_FOR_RPC={{ "yes" if ORACLE_ALLOW_HTTP_FOR_RPC else "no" }}
|
ORACLE_ALLOW_HTTP_FOR_RPC={{ "yes" if ORACLE_ALLOW_HTTP_FOR_RPC else "no" }}
|
||||||
ORACLE_QUEUE_URL={{ ORACLE_QUEUE_URL }}
|
ORACLE_QUEUE_URL={{ ORACLE_QUEUE_URL }}
|
||||||
ORACLE_REDIS_URL={{ ORACLE_REDIS_URL }}
|
ORACLE_REDIS_URL={{ ORACLE_REDIS_URL }}
|
||||||
{% if ORACLE_TX_REDUNDANCY | default('') != '' %}
|
{% if ORACLE_FOREIGN_TX_RESEND_INTERVAL | default('') != '' %}
|
||||||
ORACLE_TX_REDUNDANCY={{ ORACLE_TX_REDUNDANCY }}
|
ORACLE_FOREIGN_TX_RESEND_INTERVAL={{ ORACLE_FOREIGN_TX_RESEND_INTERVAL }}
|
||||||
|
{% endif %}
|
||||||
|
{% if ORACLE_HOME_TX_RESEND_INTERVAL | default('') != '' %}
|
||||||
|
ORACLE_HOME_TX_RESEND_INTERVAL={{ ORACLE_HOME_TX_RESEND_INTERVAL }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
## Emergency shutdown configuration
|
||||||
|
{% if ORACLE_SHUTDOWN_SERVICE_URL | default('') != '' %}
|
||||||
|
ORACLE_SHUTDOWN_SERVICE_URL={{ ORACLE_SHUTDOWN_SERVICE_URL }}
|
||||||
|
{% endif %}
|
||||||
|
{% if ORACLE_SHUTDOWN_SERVICE_POLLING_INTERVAL | default('') != '' %}
|
||||||
|
ORACLE_SHUTDOWN_SERVICE_POLLING_INTERVAL={{ ORACLE_SHUTDOWN_SERVICE_POLLING_INTERVAL }}
|
||||||
|
{% endif %}
|
||||||
|
{% if ORACLE_SIDE_RPC_URL | default('') != '' %}
|
||||||
|
ORACLE_SIDE_RPC_URL={{ ORACLE_SIDE_RPC_URL }}
|
||||||
|
{% endif %}
|
||||||
|
{% if ORACLE_SHUTDOWN_CONTRACT_ADDRESS | default('') != '' %}
|
||||||
|
ORACLE_SHUTDOWN_CONTRACT_ADDRESS={{ ORACLE_SHUTDOWN_CONTRACT_ADDRESS }}
|
||||||
|
{% endif %}
|
||||||
|
{% if ORACLE_SHUTDOWN_CONTRACT_METHOD | default('') != '' %}
|
||||||
|
ORACLE_SHUTDOWN_CONTRACT_METHOD={{ ORACLE_SHUTDOWN_CONTRACT_METHOD }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if ORACLE_HOME_START_BLOCK | default('') != '' %}
|
{% if ORACLE_HOME_START_BLOCK | default('') != '' %}
|
||||||
|
11
deployment/roles/oracle/templates/32-redis-docker.conf.j2
Normal file
11
deployment/roles/oracle/templates/32-redis-docker.conf.j2
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
$FileCreateMode 0644
|
||||||
|
template(name="DockerLogFileName_Redis" type="list") {
|
||||||
|
constant(value="/var/log/docker/")
|
||||||
|
property(name="syslogtag" securepath="replace" regex.type="ERE" regex.submatch="1" regex.expression="oracle_(.*redis.*)\\/[a-zA-Z0-9]+\\[")
|
||||||
|
constant(value="/docker.log")
|
||||||
|
}
|
||||||
|
|
||||||
|
if $programname contains 'oracle' and $programname contains 'redis' then \
|
||||||
|
?DockerLogFileName_Redis
|
||||||
|
|
||||||
|
$FileCreateMode 0600
|
11
deployment/roles/oracle/templates/33-rabbit-docker.conf.j2
Normal file
11
deployment/roles/oracle/templates/33-rabbit-docker.conf.j2
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
$FileCreateMode 0644
|
||||||
|
template(name="DockerLogFileName_Rabbit" type="list") {
|
||||||
|
constant(value="/var/log/docker/")
|
||||||
|
property(name="syslogtag" securepath="replace" regex.type="ERE" regex.submatch="1" regex.expression="oracle_(.*rabbit.*)\\/[a-zA-Z0-9]+\\[")
|
||||||
|
constant(value="/docker.log")
|
||||||
|
}
|
||||||
|
|
||||||
|
if $programname contains 'oracle' and $programname contains 'rabbit' then \
|
||||||
|
?DockerLogFileName_Rabbit
|
||||||
|
|
||||||
|
$FileCreateMode 0600
|
@ -38,7 +38,7 @@
|
|||||||
"ercToNativeBridge": {
|
"ercToNativeBridge": {
|
||||||
"home": "0x5118AC62AE912Dd5B51EEfF7338c4fcb0248Ba8c",
|
"home": "0x5118AC62AE912Dd5B51EEfF7338c4fcb0248Ba8c",
|
||||||
"foreign": "0x32198D570fffC7033641F8A9094FFDCaAEF42624",
|
"foreign": "0x32198D570fffC7033641F8A9094FFDCaAEF42624",
|
||||||
"foreignToken": "0x7cc4b1851c35959d34e635a470f6b5c43ba3c9c9",
|
"foreignToken": "0x6B175474E89094C44Da98b954EedeAC495271d0F",
|
||||||
"monitor": "http://monitor-erc20-native:3012/bridge"
|
"monitor": "http://monitor-erc20-native:3012/bridge"
|
||||||
},
|
},
|
||||||
"amb": {
|
"amb": {
|
||||||
|
@ -32,7 +32,7 @@ FOREIGN_GAS_PRICE=10000000000
|
|||||||
FOREIGN_REWARDABLE=false
|
FOREIGN_REWARDABLE=false
|
||||||
|
|
||||||
BLOCK_REWARD_ADDRESS=0xdbeE25CbE97e4A5CC6c499875774dc7067E9426B
|
BLOCK_REWARD_ADDRESS=0xdbeE25CbE97e4A5CC6c499875774dc7067E9426B
|
||||||
ERC20_TOKEN_ADDRESS=0x7cc4b1851c35959d34e635a470f6b5c43ba3c9c9
|
ERC20_TOKEN_ADDRESS=0x6B175474E89094C44Da98b954EedeAC495271d0F
|
||||||
|
|
||||||
REQUIRED_NUMBER_OF_VALIDATORS=1
|
REQUIRED_NUMBER_OF_VALIDATORS=1
|
||||||
VALIDATORS="0xaaB52d66283F7A1D5978bcFcB55721ACB467384b 0xdCC784657C78054aa61FbcFFd2605F32374816A4 0xDcef88209a20D52165230104B245803C3269454d"
|
VALIDATORS="0xaaB52d66283F7A1D5978bcFcB55721ACB467384b 0xdCC784657C78054aa61FbcFFd2605F32374816A4 0xDcef88209a20D52165230104B245803C3269454d"
|
||||||
|
@ -46,24 +46,6 @@ async function main(bridgeMode, eventsInfo) {
|
|||||||
const foreignBridge = new web3Foreign.eth.Contract(FOREIGN_ERC_TO_NATIVE_ABI, COMMON_FOREIGN_BRIDGE_ADDRESS)
|
const foreignBridge = new web3Foreign.eth.Contract(FOREIGN_ERC_TO_NATIVE_ABI, COMMON_FOREIGN_BRIDGE_ADDRESS)
|
||||||
const erc20Address = await foreignBridge.methods.erc20token().call()
|
const erc20Address = await foreignBridge.methods.erc20token().call()
|
||||||
const erc20Contract = new web3Foreign.eth.Contract(ERC20_ABI, erc20Address)
|
const erc20Contract = new web3Foreign.eth.Contract(ERC20_ABI, erc20Address)
|
||||||
let investedAmountInDai = 0
|
|
||||||
let bridgeDsrBalance = 0
|
|
||||||
let displayChaiToken = false
|
|
||||||
|
|
||||||
try {
|
|
||||||
logger.debug('calling foreignBridge.methods.isChaiTokenEnabled')
|
|
||||||
if (await foreignBridge.methods.isChaiTokenEnabled().call()) {
|
|
||||||
displayChaiToken = true
|
|
||||||
logger.debug('calling foreignBridge.methods.investedAmountInDai')
|
|
||||||
investedAmountInDai = await foreignBridge.methods.investedAmountInDai().call()
|
|
||||||
logger.debug('calling foreignBridge.methods.dsrBalance')
|
|
||||||
bridgeDsrBalance = await foreignBridge.methods.dsrBalance().call()
|
|
||||||
} else {
|
|
||||||
logger.debug('Chai token is currently disabled')
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
logger.debug('Methods for chai token are not present')
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.debug('calling erc20Contract.methods.balanceOf')
|
logger.debug('calling erc20Contract.methods.balanceOf')
|
||||||
const foreignErc20Balance = await erc20Contract.methods
|
const foreignErc20Balance = await erc20Contract.methods
|
||||||
@ -85,29 +67,16 @@ async function main(bridgeMode, eventsInfo) {
|
|||||||
const burntCoinsBN = new BN(burntCoins)
|
const burntCoinsBN = new BN(burntCoins)
|
||||||
const totalSupplyBN = mintedCoinsBN.minus(burntCoinsBN)
|
const totalSupplyBN = mintedCoinsBN.minus(burntCoinsBN)
|
||||||
const foreignErc20BalanceBN = new BN(foreignErc20Balance).plus(lateForeignConfirmationsTotalValue)
|
const foreignErc20BalanceBN = new BN(foreignErc20Balance).plus(lateForeignConfirmationsTotalValue)
|
||||||
const investedAmountInDaiBN = new BN(investedAmountInDai)
|
|
||||||
const bridgeDsrBalanceBN = new BN(bridgeDsrBalance)
|
|
||||||
|
|
||||||
const diff = foreignErc20BalanceBN
|
|
||||||
.plus(investedAmountInDaiBN)
|
|
||||||
.minus(totalSupplyBN)
|
|
||||||
.toFixed()
|
|
||||||
|
|
||||||
const foreign = {
|
|
||||||
erc20Balance: Web3Utils.fromWei(foreignErc20Balance)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (displayChaiToken) {
|
|
||||||
foreign.investedErc20Balance = Web3Utils.fromWei(investedAmountInDai)
|
|
||||||
foreign.accumulatedInterest = Web3Utils.fromWei(bridgeDsrBalanceBN.minus(investedAmountInDaiBN).toString(10))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const diff = foreignErc20BalanceBN.minus(totalSupplyBN).toFixed()
|
||||||
logger.debug('Done')
|
logger.debug('Done')
|
||||||
return {
|
return {
|
||||||
home: {
|
home: {
|
||||||
totalSupply: Web3Utils.fromWei(totalSupplyBN.toFixed())
|
totalSupply: Web3Utils.fromWei(totalSupplyBN.toFixed())
|
||||||
},
|
},
|
||||||
foreign,
|
foreign: {
|
||||||
|
erc20Balance: Web3Utils.fromWei(foreignErc20Balance)
|
||||||
|
},
|
||||||
balanceDiff: Number(Web3Utils.fromWei(diff)),
|
balanceDiff: Number(Web3Utils.fromWei(diff)),
|
||||||
...blockRanges,
|
...blockRanges,
|
||||||
lastChecked: Math.floor(Date.now() / 1000)
|
lastChecked: Math.floor(Date.now() / 1000)
|
||||||
|
@ -11,7 +11,6 @@ const {
|
|||||||
OLD_AMB_USER_REQUEST_FOR_AFFIRMATION_ABI
|
OLD_AMB_USER_REQUEST_FOR_AFFIRMATION_ABI
|
||||||
} = require('../../commons')
|
} = require('../../commons')
|
||||||
const { normalizeEventInformation } = require('./message')
|
const { normalizeEventInformation } = require('./message')
|
||||||
const { filterTransferBeforeES } = require('./tokenUtils')
|
|
||||||
const { writeFile, readCacheFile } = require('./file')
|
const { writeFile, readCacheFile } = require('./file')
|
||||||
const { web3Home, web3Foreign, getHomeBlockNumber, getForeignBlockNumber } = require('./web3')
|
const { web3Home, web3Foreign, getHomeBlockNumber, getForeignBlockNumber } = require('./web3')
|
||||||
const { getPastEvents } = require('./web3Cache')
|
const { getPastEvents } = require('./web3Cache')
|
||||||
@ -160,80 +159,32 @@ async function main(mode) {
|
|||||||
filter: { to: COMMON_FOREIGN_BRIDGE_ADDRESS }
|
filter: { to: COMMON_FOREIGN_BRIDGE_ADDRESS }
|
||||||
},
|
},
|
||||||
chain: 'foreign'
|
chain: 'foreign'
|
||||||
})).map(normalizeEvent)
|
}))
|
||||||
|
.map(normalizeEvent)
|
||||||
|
.filter(e => e.recipient !== ZERO_ADDRESS) // filter mint operation during SCD-to-MCD swaps
|
||||||
|
.filter(e => e.recipient.toLowerCase() !== '0x5d3a536e4d6dbd6114cc1ead35777bab948e3643') // filter cDai withdraws during compounding
|
||||||
|
|
||||||
let directTransfers = transferEvents
|
// Get transfer events for each previously used Sai token
|
||||||
const tokensSwappedAbiExists = FOREIGN_ABI.filter(e => e.type === 'event' && e.name === 'TokensSwapped')[0]
|
const saiTokenAddress = '0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359'
|
||||||
if (tokensSwappedAbiExists) {
|
const halfDuplexTokenContract = new web3Foreign.eth.Contract(ERC20_ABI, saiTokenAddress)
|
||||||
logger.debug('collecting half duplex tokens participated in the bridge balance')
|
logger.debug('Half duplex token:', saiTokenAddress)
|
||||||
logger.debug("calling foreignBridge.getPastEvents('TokensSwapped')")
|
|
||||||
const tokensSwappedEvents = await getPastEvents(foreignBridge, {
|
|
||||||
event: 'TokensSwapped',
|
|
||||||
fromBlock: MONITOR_FOREIGN_START_BLOCK,
|
|
||||||
toBlock: foreignBlockNumber,
|
|
||||||
chain: 'foreign',
|
|
||||||
safeToBlock: foreignDelayedBlockNumber
|
|
||||||
})
|
|
||||||
|
|
||||||
// Get token swap events emitted by foreign bridge
|
|
||||||
const bridgeTokensSwappedEvents = tokensSwappedEvents.filter(e => e.address === COMMON_FOREIGN_BRIDGE_ADDRESS)
|
|
||||||
|
|
||||||
// Get transfer events for each previous erc20
|
|
||||||
const uniqueTokenAddressesSet = new Set(bridgeTokensSwappedEvents.map(e => e.returnValues.from))
|
|
||||||
|
|
||||||
// Exclude chai token from previous erc20
|
|
||||||
try {
|
|
||||||
logger.debug('calling foreignBridge.chaiToken() to remove it from half duplex tokens list')
|
|
||||||
const chaiToken = await foreignBridge.methods.chaiToken().call()
|
|
||||||
uniqueTokenAddressesSet.delete(chaiToken)
|
|
||||||
} catch (e) {
|
|
||||||
logger.debug('call to foreignBridge.chaiToken() failed')
|
|
||||||
}
|
|
||||||
// Exclude dai token from previous erc20
|
|
||||||
try {
|
|
||||||
logger.debug('calling foreignBridge.erc20token() to remove it from half duplex tokens list')
|
|
||||||
const daiToken = await foreignBridge.methods.erc20token().call()
|
|
||||||
uniqueTokenAddressesSet.delete(daiToken)
|
|
||||||
} catch (e) {
|
|
||||||
logger.debug('call to foreignBridge.erc20token() failed')
|
|
||||||
}
|
|
||||||
|
|
||||||
const uniqueTokenAddresses = [...uniqueTokenAddressesSet]
|
|
||||||
await Promise.all(
|
|
||||||
uniqueTokenAddresses.map(async tokenAddress => {
|
|
||||||
const halfDuplexTokenContract = new web3Foreign.eth.Contract(ERC20_ABI, tokenAddress)
|
|
||||||
|
|
||||||
logger.debug('Half duplex token:', tokenAddress)
|
|
||||||
logger.debug("calling halfDuplexTokenContract.getPastEvents('Transfer')")
|
logger.debug("calling halfDuplexTokenContract.getPastEvents('Transfer')")
|
||||||
|
// https://etherscan.io/tx/0xd0c3c92c94e05bc71256055ce8c4c993e047f04e04f3283a04e4cb077b71f6c6
|
||||||
|
const blockNumberHalfDuplexDisabled = 9884448
|
||||||
const halfDuplexTransferEvents = (await getPastEvents(halfDuplexTokenContract, {
|
const halfDuplexTransferEvents = (await getPastEvents(halfDuplexTokenContract, {
|
||||||
event: 'Transfer',
|
event: 'Transfer',
|
||||||
fromBlock: MONITOR_FOREIGN_START_BLOCK,
|
fromBlock: MONITOR_FOREIGN_START_BLOCK,
|
||||||
toBlock: foreignDelayedBlockNumber,
|
toBlock: Math.min(blockNumberHalfDuplexDisabled, foreignDelayedBlockNumber),
|
||||||
options: {
|
options: {
|
||||||
filter: { to: COMMON_FOREIGN_BRIDGE_ADDRESS }
|
filter: { to: COMMON_FOREIGN_BRIDGE_ADDRESS }
|
||||||
},
|
},
|
||||||
chain: 'foreign'
|
chain: 'foreign'
|
||||||
})).map(normalizeEvent)
|
})).map(normalizeEvent)
|
||||||
|
|
||||||
// Remove events after the ES
|
transferEvents = [...halfDuplexTransferEvents, ...transferEvents]
|
||||||
logger.debug('filtering half duplex transfers happened before ES')
|
|
||||||
const validHalfDuplexTransfers = await filterTransferBeforeES(halfDuplexTransferEvents)
|
|
||||||
|
|
||||||
transferEvents = [...validHalfDuplexTransfers, ...transferEvents]
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
// filter transfer that is part of a token swap
|
|
||||||
directTransfers = transferEvents.filter(
|
|
||||||
e =>
|
|
||||||
bridgeTokensSwappedEvents.findIndex(
|
|
||||||
t => t.transactionHash === e.referenceTx && e.recipient === ZERO_ADDRESS
|
|
||||||
) === -1
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get transfer events that didn't have a UserRequestForAffirmation event in the same transaction
|
// Get transfer events that didn't have a UserRequestForAffirmation event in the same transaction
|
||||||
directTransfers = directTransfers.filter(
|
const directTransfers = transferEvents.filter(
|
||||||
e => foreignToHomeRequests.findIndex(t => t.referenceTx === e.referenceTx) === -1
|
e => foreignToHomeRequests.findIndex(t => t.referenceTx === e.referenceTx) === -1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
// https://etherscan.io/tx/0xd0c3c92c94e05bc71256055ce8c4c993e047f04e04f3283a04e4cb077b71f6c6
|
|
||||||
const blockNumberHalfDuplexDisabled = 9884448
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the event was before the bridge stopped supporting half duplex transfers.
|
|
||||||
*/
|
|
||||||
async function transferBeforeES(event) {
|
|
||||||
return event.blockNumber < blockNumberHalfDuplexDisabled
|
|
||||||
}
|
|
||||||
|
|
||||||
async function filterTransferBeforeES(array) {
|
|
||||||
const newArray = []
|
|
||||||
// Iterate events from newer to older
|
|
||||||
for (let i = array.length - 1; i >= 0; i--) {
|
|
||||||
const beforeES = await transferBeforeES(array[i])
|
|
||||||
if (beforeES) {
|
|
||||||
// add element to first position so the new array will have the same order
|
|
||||||
newArray.unshift(array[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return newArray
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
filterTransferBeforeES,
|
|
||||||
blockNumberHalfDuplexDisabled
|
|
||||||
}
|
|
@ -33,6 +33,10 @@ const homeBridge = new homeWeb3.eth.Contract(HOME_ERC_TO_NATIVE_ABI, COMMON_HOME
|
|||||||
|
|
||||||
describe('erc to native', () => {
|
describe('erc to native', () => {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
|
console.log('Initializing interest')
|
||||||
|
await foreignBridge.methods
|
||||||
|
.initializeInterest(ercToNativeBridge.foreignToken, 1, 1, validator.address)
|
||||||
|
.send({ from: validator.address, gas: '4000000' })
|
||||||
if (process.env.ULTIMATE === 'true') {
|
if (process.env.ULTIMATE === 'true') {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -112,6 +116,7 @@ describe('erc to native', () => {
|
|||||||
.catch(e => {
|
.catch(e => {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
})
|
})
|
||||||
|
await foreignBridge.methods.investDai().send({ from: validator.address, gas: '4000000' })
|
||||||
|
|
||||||
// check that balance increases
|
// check that balance increases
|
||||||
await uniformRetry(async retry => {
|
await uniformRetry(async retry => {
|
||||||
|
@ -6,6 +6,7 @@ const logger = require('./services/logger')
|
|||||||
const GasPrice = require('./services/gasPrice')
|
const GasPrice = require('./services/gasPrice')
|
||||||
const { getNonce, getChainId, getEventsFromTx } = require('./tx/web3')
|
const { getNonce, getChainId, getEventsFromTx } = require('./tx/web3')
|
||||||
const { sendTx } = require('./tx/sendTx')
|
const { sendTx } = require('./tx/sendTx')
|
||||||
|
const { getTokensState } = require('./utils/tokenState')
|
||||||
const { checkHTTPS, watchdog, syncForEach, addExtraGas } = require('./utils/utils')
|
const { checkHTTPS, watchdog, syncForEach, addExtraGas } = require('./utils/utils')
|
||||||
const { EXIT_CODES, EXTRA_GAS_PERCENTAGE, MAX_GAS_LIMIT } = require('./utils/constants')
|
const { EXIT_CODES, EXTRA_GAS_PERCENTAGE, MAX_GAS_LIMIT } = require('./utils/constants')
|
||||||
|
|
||||||
@ -17,7 +18,7 @@ if (process.argv.length < 4) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const config = require(path.join('../config/', process.argv[2]))
|
const config = require(path.join('../config/', process.argv[2]))
|
||||||
const { web3, eventContract, chain } = config.main
|
const { web3, eventContract, chain, bridgeContract } = config.main
|
||||||
|
|
||||||
const isTxHash = txHash => txHash.length === 66 && web3.utils.isHexStrict(txHash)
|
const isTxHash = txHash => txHash.length === 66 && web3.utils.isHexStrict(txHash)
|
||||||
function readTxHashes(filePath) {
|
function readTxHashes(filePath) {
|
||||||
@ -49,7 +50,7 @@ async function initialize() {
|
|||||||
try {
|
try {
|
||||||
const checkHttps = checkHTTPS(ORACLE_ALLOW_HTTP_FOR_RPC, logger)
|
const checkHttps = checkHTTPS(ORACLE_ALLOW_HTTP_FOR_RPC, logger)
|
||||||
|
|
||||||
web3.currentProvider.subProvider.urls.forEach(checkHttps(chain))
|
web3.currentProvider.urls.forEach(checkHttps(chain))
|
||||||
|
|
||||||
attached = await isAttached()
|
attached = await isAttached()
|
||||||
if (attached) {
|
if (attached) {
|
||||||
@ -114,6 +115,12 @@ function processEvents(events) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function main({ sendJob, txHashes }) {
|
async function main({ sendJob, txHashes }) {
|
||||||
|
if (config.id === 'erc-native-transfer') {
|
||||||
|
logger.debug('Getting token address to listen Transfer events')
|
||||||
|
const state = await getTokensState(bridgeContract, logger)
|
||||||
|
eventContract.options.address = state.bridgeableTokenAddress
|
||||||
|
}
|
||||||
|
|
||||||
logger.info(`Processing ${txHashes.length} input transactions`)
|
logger.info(`Processing ${txHashes.length} input transactions`)
|
||||||
for (const txHash of txHashes) {
|
for (const txHash of txHashes) {
|
||||||
try {
|
try {
|
||||||
|
@ -13,12 +13,25 @@ const limit = promiseLimit(MAX_CONCURRENT_EVENTS)
|
|||||||
function processTransfersBuilder(config) {
|
function processTransfersBuilder(config) {
|
||||||
const { bridgeContract, web3 } = config.home
|
const { bridgeContract, web3 } = config.home
|
||||||
|
|
||||||
const userRequestForAffirmationAbi = config.foreign.bridgeABI.find(
|
const userRequestForAffirmationHash = web3.eth.abi.encodeEventSignature('UserRequestForAffirmation(address,uint256)')
|
||||||
e => e.type === 'event' && e.name === 'UserRequestForAffirmation'
|
const redeemHash = web3.eth.abi.encodeEventSignature('Redeem(address,uint256,uint256)')
|
||||||
)
|
const transferHash = web3.eth.abi.encodeEventSignature('Transfer(address,address,uint256)')
|
||||||
const tokensSwappedAbi = config.foreign.bridgeABI.find(e => e.type === 'event' && e.name === 'TokensSwapped')
|
|
||||||
const userRequestForAffirmationHash = web3.eth.abi.encodeEventSignature(userRequestForAffirmationAbi)
|
const foreignBridgeAddress = config.foreign.bridgeAddress
|
||||||
const tokensSwappedHash = tokensSwappedAbi ? web3.eth.abi.encodeEventSignature(tokensSwappedAbi) : '0x'
|
|
||||||
|
const decodeAddress = data => web3.eth.abi.decodeParameter('address', data)
|
||||||
|
|
||||||
|
const isUserRequestForAffirmation = e =>
|
||||||
|
e.address.toLowerCase() === foreignBridgeAddress.toLowerCase() && e.topics[0] === userRequestForAffirmationHash
|
||||||
|
const isRedeem = cTokenAddress => e =>
|
||||||
|
e.address.toLowerCase() === cTokenAddress.toLowerCase() &&
|
||||||
|
e.topics[0] === redeemHash &&
|
||||||
|
decodeAddress(e.data.slice(0, 66)).toLowerCase() === foreignBridgeAddress.toLowerCase()
|
||||||
|
const isCTokenTransfer = cTokenAddress => e =>
|
||||||
|
e.address.toLowerCase() === cTokenAddress.toLowerCase() &&
|
||||||
|
e.topics[0] === transferHash &&
|
||||||
|
decodeAddress(e.topics[1]).toLowerCase() === foreignBridgeAddress.toLowerCase() &&
|
||||||
|
decodeAddress(e.topics[2]).toLowerCase() === cTokenAddress.toLowerCase()
|
||||||
|
|
||||||
let validatorContract = null
|
let validatorContract = null
|
||||||
|
|
||||||
@ -32,37 +45,35 @@ function processTransfersBuilder(config) {
|
|||||||
rootLogger.debug(`Processing ${transfers.length} Transfer events`)
|
rootLogger.debug(`Processing ${transfers.length} Transfer events`)
|
||||||
const callbacks = transfers
|
const callbacks = transfers
|
||||||
.map(transfer => async () => {
|
.map(transfer => async () => {
|
||||||
const { from, value } = transfer.returnValues
|
const { from, to, value } = transfer.returnValues
|
||||||
|
|
||||||
const logger = rootLogger.child({
|
const logger = rootLogger.child({
|
||||||
eventTransactionHash: transfer.transactionHash
|
eventTransactionHash: transfer.transactionHash,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
value
|
||||||
})
|
})
|
||||||
|
|
||||||
logger.info({ from, value }, `Processing transfer ${transfer.transactionHash}`)
|
logger.info('Processing transfer')
|
||||||
|
|
||||||
const receipt = await config.foreign.web3.eth.getTransactionReceipt(transfer.transactionHash)
|
const receipt = await config.foreign.web3.eth.getTransactionReceipt(transfer.transactionHash)
|
||||||
|
|
||||||
const existsAffirmationEvent = receipt.logs.some(
|
if (receipt.logs.some(isUserRequestForAffirmation)) {
|
||||||
e => e.address === config.foreign.bridgeAddress && e.topics[0] === userRequestForAffirmationHash
|
logger.info('Transfer event discarded because affirmation is detected in the same transaction')
|
||||||
)
|
|
||||||
|
|
||||||
if (existsAffirmationEvent) {
|
|
||||||
logger.info(
|
|
||||||
`Transfer event discarded because a transaction with alternative receiver detected in transaction ${
|
|
||||||
transfer.transactionHash
|
|
||||||
}`
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const existsTokensSwappedEvent = tokensSwappedAbi
|
if (from === ZERO_ADDRESS) {
|
||||||
? receipt.logs.some(e => e.address === config.foreign.bridgeAddress && e.topics[0] === tokensSwappedHash)
|
logger.info('Mint-like transfers from zero address are not processed')
|
||||||
: false
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (from === ZERO_ADDRESS && existsTokensSwappedEvent) {
|
// when bridge performs a withdrawal from Compound, the following three events occur
|
||||||
logger.info(
|
// * token.Transfer(from=cToken, to=bridge, amount=X)
|
||||||
`Transfer event discarded because token swap is detected in transaction ${transfer.transactionHash}`
|
// * cToken.Redeem(redeemer=bridge, amount=X, tokens=Y)
|
||||||
)
|
// * cToken.Transfer(from=bridge, to=cToken, amount=Y)
|
||||||
|
if (receipt.logs.some(isRedeem(from)) && receipt.logs.some(isCTokenTransfer(from))) {
|
||||||
|
logger.info('Transfer event discarded because cToken redeem is detected in the same transaction')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ async function initialize() {
|
|||||||
try {
|
try {
|
||||||
const checkHttps = checkHTTPS(process.env.ORACLE_ALLOW_HTTP_FOR_RPC, logger)
|
const checkHttps = checkHTTPS(process.env.ORACLE_ALLOW_HTTP_FOR_RPC, logger)
|
||||||
|
|
||||||
web3.currentProvider.subProvider.urls.forEach(checkHttps(config.id))
|
web3.currentProvider.urls.forEach(checkHttps(config.id))
|
||||||
|
|
||||||
GasPrice.start(config.id)
|
GasPrice.start(config.id)
|
||||||
|
|
||||||
|
@ -4,8 +4,12 @@ const { FALLBACK_RPC_URL_SWITCH_TIMEOUT } = require('../utils/constants')
|
|||||||
|
|
||||||
const { onInjected } = require('./injectedLogger')
|
const { onInjected } = require('./injectedLogger')
|
||||||
|
|
||||||
|
const { ORACLE_JSONRPC_ERROR_CODES } = process.env
|
||||||
|
|
||||||
// From EIP-1474 and Infura documentation
|
// From EIP-1474 and Infura documentation
|
||||||
const JSONRPC_ERROR_CODES = [-32603, -32002, -32005]
|
const JSONRPC_ERROR_CODES = ORACLE_JSONRPC_ERROR_CODES
|
||||||
|
? ORACLE_JSONRPC_ERROR_CODES.split(',').map(s => parseInt(s, 10))
|
||||||
|
: [-32603, -32002, -32005]
|
||||||
|
|
||||||
const defaultOptions = {
|
const defaultOptions = {
|
||||||
name: 'main',
|
name: 'main',
|
||||||
@ -41,6 +45,20 @@ function HttpListProvider(urls, options = {}) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HttpListProvider.prototype.switchToFallbackRPC = function() {
|
||||||
|
if (this.urls.length < 2) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const prevIndex = this.currentIndex
|
||||||
|
const newIndex = (prevIndex + 1) % this.urls.length
|
||||||
|
this.logger.info(
|
||||||
|
{ index: newIndex, oldURL: this.urls[prevIndex], newURL: this.urls[newIndex] },
|
||||||
|
'Switching to fallback JSON-RPC URL'
|
||||||
|
)
|
||||||
|
this.currentIndex = newIndex
|
||||||
|
}
|
||||||
|
|
||||||
HttpListProvider.prototype.send = async function send(payload, callback) {
|
HttpListProvider.prototype.send = async function send(payload, callback) {
|
||||||
// if fallback URL is being used for too long, switch back to the primary URL
|
// if fallback URL is being used for too long, switch back to the primary URL
|
||||||
if (this.currentIndex > 0 && Date.now() - this.lastTimeUsedPrimary > FALLBACK_RPC_URL_SWITCH_TIMEOUT) {
|
if (this.currentIndex > 0 && Date.now() - this.lastTimeUsedPrimary > FALLBACK_RPC_URL_SWITCH_TIMEOUT) {
|
||||||
|
@ -1,20 +1,13 @@
|
|||||||
const { hexToNumber, isHexStrict } = require('web3').utils
|
const { hexToNumber, isHexStrict } = require('web3').utils
|
||||||
|
|
||||||
const { onInjected } = require('./injectedLogger')
|
|
||||||
|
|
||||||
function SafeEthLogsProvider(provider) {
|
function SafeEthLogsProvider(provider) {
|
||||||
this.subProvider = provider
|
const oldSend = provider.send.bind(provider)
|
||||||
onInjected(logger => {
|
const newSend = function(payload, callback) {
|
||||||
this.logger = logger.child({ module: 'SafeEthLogsProvider' })
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
SafeEthLogsProvider.prototype.send = function send(payload, callback) {
|
|
||||||
if (payload.method === 'eth_getLogs' && isHexStrict(payload.params[0].toBlock)) {
|
if (payload.method === 'eth_getLogs' && isHexStrict(payload.params[0].toBlock)) {
|
||||||
this.logger.debug('Modifying eth_getLogs request to include batch eth_blockNumber request')
|
this.logger.debug('Modifying eth_getLogs request to include batch eth_blockNumber request')
|
||||||
|
|
||||||
const newPayload = [payload, { jsonrpc: '2.0', id: payload.id + 1, method: 'eth_blockNumber', params: [] }]
|
const newPayload = [payload, { jsonrpc: '2.0', id: payload.id + 1, method: 'eth_blockNumber', params: [] }]
|
||||||
this.subProvider.send(newPayload, (err, res) => {
|
oldSend(newPayload, (err, res) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
callback(err, null)
|
callback(err, null)
|
||||||
} else {
|
} else {
|
||||||
@ -32,8 +25,11 @@ SafeEthLogsProvider.prototype.send = function send(payload, callback) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
this.subProvider.send(payload, callback)
|
oldSend(payload, callback)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
provider.send = newSend.bind(provider)
|
||||||
|
return provider
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
@ -38,10 +38,10 @@ const foreignOptions = {
|
|||||||
retry: RETRY_CONFIG
|
retry: RETRY_CONFIG
|
||||||
}
|
}
|
||||||
|
|
||||||
const homeProvider = new SafeEthLogsProvider(new HttpListProvider(homeUrls, homeOptions))
|
const homeProvider = SafeEthLogsProvider(new HttpListProvider(homeUrls, homeOptions))
|
||||||
const web3Home = new Web3(homeProvider)
|
const web3Home = new Web3(homeProvider)
|
||||||
|
|
||||||
const foreignProvider = new SafeEthLogsProvider(new HttpListProvider(foreignUrls, foreignOptions))
|
const foreignProvider = SafeEthLogsProvider(new HttpListProvider(foreignUrls, foreignOptions))
|
||||||
const web3Foreign = new Web3(foreignProvider)
|
const web3Foreign = new Web3(foreignProvider)
|
||||||
|
|
||||||
let web3ForeignArchive = null
|
let web3ForeignArchive = null
|
||||||
|
@ -25,6 +25,7 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
DEFAULT_TRANSACTION_RESEND_INTERVAL: 20 * 60 * 1000,
|
DEFAULT_TRANSACTION_RESEND_INTERVAL: 20 * 60 * 1000,
|
||||||
FALLBACK_RPC_URL_SWITCH_TIMEOUT: 60 * 60 * 1000,
|
FALLBACK_RPC_URL_SWITCH_TIMEOUT: 60 * 60 * 1000,
|
||||||
|
BLOCK_NUMBER_PROGRESS_ITERATIONS_LIMIT: 10,
|
||||||
SENDER_QUEUE_MAX_PRIORITY: 10,
|
SENDER_QUEUE_MAX_PRIORITY: 10,
|
||||||
SENDER_QUEUE_SEND_PRIORITY: 5,
|
SENDER_QUEUE_SEND_PRIORITY: 5,
|
||||||
SENDER_QUEUE_CHECK_STATUS_PRIORITY: 1,
|
SENDER_QUEUE_CHECK_STATUS_PRIORITY: 1,
|
||||||
|
@ -106,7 +106,11 @@ function isGasPriceError(e) {
|
|||||||
|
|
||||||
function isSameTransactionError(e) {
|
function isSameTransactionError(e) {
|
||||||
const message = e.message.toLowerCase()
|
const message = e.message.toLowerCase()
|
||||||
return message.includes('transaction with the same hash was already imported') || message.includes('already known')
|
return (
|
||||||
|
message.includes('transaction with the same hash was already imported') ||
|
||||||
|
message.includes('already known') ||
|
||||||
|
message.includes('alreadyknown')
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function isInsufficientBalanceError(e) {
|
function isInsufficientBalanceError(e) {
|
||||||
@ -119,7 +123,8 @@ function isNonceError(e) {
|
|||||||
return (
|
return (
|
||||||
message.includes('transaction nonce is too low') ||
|
message.includes('transaction nonce is too low') ||
|
||||||
message.includes('nonce too low') ||
|
message.includes('nonce too low') ||
|
||||||
message.includes('transaction with same nonce in the queue')
|
message.includes('transaction with same nonce in the queue') ||
|
||||||
|
message.includes('oldnonce')
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ const logger = require('./services/logger')
|
|||||||
const { getShutdownFlag } = require('./services/shutdownState')
|
const { getShutdownFlag } = require('./services/shutdownState')
|
||||||
const { getBlockNumber, getRequiredBlockConfirmations, getEvents } = require('./tx/web3')
|
const { getBlockNumber, getRequiredBlockConfirmations, getEvents } = require('./tx/web3')
|
||||||
const { checkHTTPS, watchdog } = require('./utils/utils')
|
const { checkHTTPS, watchdog } = require('./utils/utils')
|
||||||
const { EXIT_CODES } = require('./utils/constants')
|
const { EXIT_CODES, BLOCK_NUMBER_PROGRESS_ITERATIONS_LIMIT } = require('./utils/constants')
|
||||||
|
|
||||||
if (process.argv.length < 3) {
|
if (process.argv.length < 3) {
|
||||||
logger.error('Please check the number of arguments, config file was not provided')
|
logger.error('Please check the number of arguments, config file was not provided')
|
||||||
@ -29,12 +29,14 @@ const { getTokensState } = require('./utils/tokenState')
|
|||||||
const { web3, bridgeContract, eventContract, startBlock, pollingInterval, chain } = config.main
|
const { web3, bridgeContract, eventContract, startBlock, pollingInterval, chain } = config.main
|
||||||
const lastBlockRedisKey = `${config.id}:lastProcessedBlock`
|
const lastBlockRedisKey = `${config.id}:lastProcessedBlock`
|
||||||
let lastProcessedBlock = Math.max(startBlock - 1, 0)
|
let lastProcessedBlock = Math.max(startBlock - 1, 0)
|
||||||
|
let lastSeenBlockNumber = 0
|
||||||
|
let sameBlockNumberCounter = 0
|
||||||
|
|
||||||
async function initialize() {
|
async function initialize() {
|
||||||
try {
|
try {
|
||||||
const checkHttps = checkHTTPS(process.env.ORACLE_ALLOW_HTTP_FOR_RPC, logger)
|
const checkHttps = checkHTTPS(process.env.ORACLE_ALLOW_HTTP_FOR_RPC, logger)
|
||||||
|
|
||||||
web3.currentProvider.subProvider.urls.forEach(checkHttps(chain))
|
web3.currentProvider.urls.forEach(checkHttps(chain))
|
||||||
|
|
||||||
await getLastProcessedBlock()
|
await getLastProcessedBlock()
|
||||||
connectWatcherToQueue({
|
connectWatcherToQueue({
|
||||||
@ -117,6 +119,28 @@ async function getLastBlockToProcess(web3, bridgeContract) {
|
|||||||
getBlockNumber(web3),
|
getBlockNumber(web3),
|
||||||
getRequiredBlockConfirmations(bridgeContract)
|
getRequiredBlockConfirmations(bridgeContract)
|
||||||
])
|
])
|
||||||
|
|
||||||
|
if (lastBlockNumber < lastSeenBlockNumber) {
|
||||||
|
sameBlockNumberCounter = 0
|
||||||
|
logger.warn({ lastBlockNumber, lastSeenBlockNumber }, 'Received block number less than already seen block')
|
||||||
|
web3.currentProvider.switchToFallbackRPC()
|
||||||
|
} else if (lastBlockNumber === lastSeenBlockNumber) {
|
||||||
|
sameBlockNumberCounter++
|
||||||
|
if (sameBlockNumberCounter > 1) {
|
||||||
|
logger.info({ lastBlockNumber, sameBlockNumberCounter }, 'Received the same block number more than twice')
|
||||||
|
if (sameBlockNumberCounter >= BLOCK_NUMBER_PROGRESS_ITERATIONS_LIMIT) {
|
||||||
|
sameBlockNumberCounter = 0
|
||||||
|
logger.warn(
|
||||||
|
{ lastBlockNumber, n: BLOCK_NUMBER_PROGRESS_ITERATIONS_LIMIT },
|
||||||
|
'Received the same block number for too many times. Probably node is not synced anymore'
|
||||||
|
)
|
||||||
|
web3.currentProvider.switchToFallbackRPC()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sameBlockNumberCounter = 0
|
||||||
|
lastSeenBlockNumber = lastBlockNumber
|
||||||
|
}
|
||||||
return lastBlockNumber - requiredBlockConfirmations
|
return lastBlockNumber - requiredBlockConfirmations
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,8 +156,6 @@ async function main({ sendToQueue }) {
|
|||||||
logger.info(`Oracle watcher was unsuspended.`)
|
logger.info(`Oracle watcher was unsuspended.`)
|
||||||
}
|
}
|
||||||
|
|
||||||
await checkConditions()
|
|
||||||
|
|
||||||
const lastBlockToProcess = await getLastBlockToProcess(web3, bridgeContract)
|
const lastBlockToProcess = await getLastBlockToProcess(web3, bridgeContract)
|
||||||
|
|
||||||
if (lastBlockToProcess <= lastProcessedBlock) {
|
if (lastBlockToProcess <= lastProcessedBlock) {
|
||||||
@ -141,6 +163,8 @@ async function main({ sendToQueue }) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await checkConditions()
|
||||||
|
|
||||||
const fromBlock = lastProcessedBlock + 1
|
const fromBlock = lastProcessedBlock + 1
|
||||||
const rangeEndBlock = config.blockPollingLimit ? fromBlock + config.blockPollingLimit : lastBlockToProcess
|
const rangeEndBlock = config.blockPollingLimit ? fromBlock + config.blockPollingLimit : lastBlockToProcess
|
||||||
let toBlock = Math.min(lastBlockToProcess, rangeEndBlock)
|
let toBlock = Math.min(lastBlockToProcess, rangeEndBlock)
|
||||||
|
File diff suppressed because one or more lines are too long
33
parity/foreign_mocks/cDAIMock.sol
Normal file
33
parity/foreign_mocks/cDAIMock.sol
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
pragma solidity 0.4.24;
|
||||||
|
|
||||||
|
interface IERC20 {
|
||||||
|
function transferFrom(address from,address to,uint256 value) external;
|
||||||
|
function transfer(address to,uint256 value) external;
|
||||||
|
}
|
||||||
|
|
||||||
|
contract cDaiMock {
|
||||||
|
IERC20 daiToken;
|
||||||
|
|
||||||
|
event Transfer(address indexed from, address indexed to, uint amount);
|
||||||
|
event Mint(address minter, uint mintAmount, uint mintTokens);
|
||||||
|
event Redeem(address redeemer, uint redeemAmount, uint redeemTokens);
|
||||||
|
|
||||||
|
|
||||||
|
function mint(uint256 mintAmount) external returns (uint256) {
|
||||||
|
daiToken.transferFrom(msg.sender, address(this), mintAmount);
|
||||||
|
|
||||||
|
emit Mint(msg.sender, mintAmount, mintAmount);
|
||||||
|
emit Transfer(address(this), msg.sender, mintAmount);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function redeemUnderlying(uint256 redeemAmount) external returns (uint256) {
|
||||||
|
daiToken.transfer(msg.sender, redeemAmount);
|
||||||
|
|
||||||
|
emit Transfer(msg.sender, address(this), redeemAmount);
|
||||||
|
emit Redeem(msg.sender, redeemAmount, redeemAmount);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user