Update watcher to be able to skip events
This commit is contained in:
parent
0eeae74ffa
commit
3cd53f7bda
@ -32,7 +32,7 @@ FOREIGN_GAS_PRICE=10000000000
|
|||||||
FOREIGN_REWARDABLE=false
|
FOREIGN_REWARDABLE=false
|
||||||
|
|
||||||
BLOCK_REWARD_ADDRESS=0xF9698Eb93702dfdd0e2d802088d4c21822a8A977
|
BLOCK_REWARD_ADDRESS=0xF9698Eb93702dfdd0e2d802088d4c21822a8A977
|
||||||
ERC20_TOKEN_ADDRESS=0x7cc4b1851c35959d34e635a470f6b5c43ba3c9c9
|
ERC20_TOKEN_ADDRESS=0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359
|
||||||
|
|
||||||
REQUIRED_NUMBER_OF_VALIDATORS=1
|
REQUIRED_NUMBER_OF_VALIDATORS=1
|
||||||
VALIDATORS="0xaaB52d66283F7A1D5978bcFcB55721ACB467384b"
|
VALIDATORS="0xaaB52d66283F7A1D5978bcFcB55721ACB467384b"
|
||||||
|
@ -33,12 +33,122 @@ describe('erc to native', () => {
|
|||||||
before(async () => {
|
before(async () => {
|
||||||
halfDuplexTokenAddress = await foreignBridge.methods.halfDuplexErc20token().call()
|
halfDuplexTokenAddress = await foreignBridge.methods.halfDuplexErc20token().call()
|
||||||
halfDuplexToken = new foreignWeb3.eth.Contract(ERC677_BRIDGE_TOKEN_ABI, halfDuplexTokenAddress)
|
halfDuplexToken = new foreignWeb3.eth.Contract(ERC677_BRIDGE_TOKEN_ABI, halfDuplexTokenAddress)
|
||||||
|
})
|
||||||
|
it('should continue working after migration', async () => {
|
||||||
|
const originalBalanceOnHome = await homeWeb3.eth.getBalance(user.address)
|
||||||
|
|
||||||
// set min threshold for swap
|
const transferValue = homeWeb3.utils.toWei('0.01')
|
||||||
|
|
||||||
|
// erc20 token address and half duplex address are the same before migration
|
||||||
|
const tokenAddress = await foreignBridge.methods.erc20token().call()
|
||||||
|
|
||||||
|
const erc20AndhalfDuplexToken = new foreignWeb3.eth.Contract(ERC677_BRIDGE_TOKEN_ABI, tokenAddress)
|
||||||
|
|
||||||
|
// send tokens to foreign bridge
|
||||||
|
await erc20AndhalfDuplexToken.methods
|
||||||
|
.transfer(COMMON_FOREIGN_BRIDGE_ADDRESS, transferValue)
|
||||||
|
.send({
|
||||||
|
from: user.address,
|
||||||
|
gas: '1000000'
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
console.error(e)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Send a trivial transaction to generate a new block since the watcher
|
||||||
|
// is configured to wait 1 confirmation block
|
||||||
|
await generateNewBlock(foreignWeb3, user.address)
|
||||||
|
|
||||||
|
// check that balance increases
|
||||||
|
await promiseRetry(async (retry, number) => {
|
||||||
|
const balance = await homeWeb3.eth.getBalance(user.address)
|
||||||
|
await generateNewBlock(foreignWeb3, 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'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// call migration
|
||||||
|
await foreignBridge.methods.migrateToMCD().send({
|
||||||
|
from: validator.address,
|
||||||
|
gas: '4000000'
|
||||||
|
})
|
||||||
|
|
||||||
|
// update min threshold for swap
|
||||||
await foreignBridge.methods.setMinHDTokenBalance(foreignWeb3.utils.toWei('1', 'ether')).send({
|
await foreignBridge.methods.setMinHDTokenBalance(foreignWeb3.utils.toWei('1', 'ether')).send({
|
||||||
from: validator.address,
|
from: validator.address,
|
||||||
gas: '1000000'
|
gas: '1000000'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const AfterMigrateBalance = 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)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Send a trivial transaction to generate a new block since the watcher
|
||||||
|
// is configured to wait 1 confirmation block
|
||||||
|
await generateNewBlock(foreignWeb3, user.address)
|
||||||
|
|
||||||
|
// check that balance increases
|
||||||
|
await promiseRetry(async (retry, number) => {
|
||||||
|
const balance = await homeWeb3.eth.getBalance(user.address)
|
||||||
|
await generateNewBlock(foreignWeb3, user.address)
|
||||||
|
// retry at least 4 times to check transfer is not double processed by the two watchers
|
||||||
|
if (toBN(balance).lte(toBN(AfterMigrateBalance)) || number < 4) {
|
||||||
|
retry()
|
||||||
|
} else {
|
||||||
|
assert(
|
||||||
|
toBN(balance).eq(toBN(AfterMigrateBalance).add(toBN(transferValue))),
|
||||||
|
'User balance should be increased only by second transfer'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const afterMigrateAndTransferBalance = await homeWeb3.eth.getBalance(user.address)
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Send a trivial transaction to generate a new block since the watcher
|
||||||
|
// is configured to wait 1 confirmation block
|
||||||
|
await generateNewBlock(foreignWeb3, user.address)
|
||||||
|
|
||||||
|
// check that balance increases
|
||||||
|
await promiseRetry(async (retry, number) => {
|
||||||
|
const balance = await homeWeb3.eth.getBalance(user.address)
|
||||||
|
await generateNewBlock(foreignWeb3, user.address)
|
||||||
|
// retry at least 4 times to check transfer is not double processed by the two watchers
|
||||||
|
if (toBN(balance).lte(toBN(afterMigrateAndTransferBalance)) || number < 4) {
|
||||||
|
retry()
|
||||||
|
} else {
|
||||||
|
assert(
|
||||||
|
toBN(balance).eq(toBN(afterMigrateAndTransferBalance).add(toBN(transferValue))),
|
||||||
|
'User balance should be increased only by second transfer'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
it('should convert tokens in foreign to coins in home', async () => {
|
it('should convert tokens in foreign to coins in home', async () => {
|
||||||
const balance = await erc20Token.methods.balanceOf(user.address).call()
|
const balance = await erc20Token.methods.balanceOf(user.address).call()
|
||||||
@ -116,7 +226,6 @@ describe('erc to native', () => {
|
|||||||
const originalBalanceOnHome = await homeWeb3.eth.getBalance(user.address)
|
const originalBalanceOnHome = await homeWeb3.eth.getBalance(user.address)
|
||||||
const bridgeErc20TokenBalance = await erc20Token.methods.balanceOf(COMMON_FOREIGN_BRIDGE_ADDRESS).call()
|
const bridgeErc20TokenBalance = await erc20Token.methods.balanceOf(COMMON_FOREIGN_BRIDGE_ADDRESS).call()
|
||||||
const bridgeHalfDuplexBalance = await halfDuplexToken.methods.balanceOf(COMMON_FOREIGN_BRIDGE_ADDRESS).call()
|
const bridgeHalfDuplexBalance = await halfDuplexToken.methods.balanceOf(COMMON_FOREIGN_BRIDGE_ADDRESS).call()
|
||||||
assert(toBN(bridgeHalfDuplexBalance).isZero(), 'Bridge balance should be zero')
|
|
||||||
|
|
||||||
const valueToTransfer = foreignWeb3.utils.toWei('1', 'ether')
|
const valueToTransfer = foreignWeb3.utils.toWei('1', 'ether')
|
||||||
|
|
||||||
@ -176,7 +285,9 @@ describe('erc to native', () => {
|
|||||||
assert(toBN(updatedBalance).isZero(), 'Half duplex bridge balance should be zero')
|
assert(toBN(updatedBalance).isZero(), 'Half duplex bridge balance should be zero')
|
||||||
assert(
|
assert(
|
||||||
toBN(updatedBridgeErc20TokenBalance).eq(
|
toBN(updatedBridgeErc20TokenBalance).eq(
|
||||||
toBN(bridgeErc20TokenBalance).add(toBN(foreignWeb3.utils.toWei('2', 'ether')))
|
toBN(bridgeErc20TokenBalance)
|
||||||
|
.add(toBN(bridgeHalfDuplexBalance))
|
||||||
|
.add(toBN(foreignWeb3.utils.toWei('2', 'ether')))
|
||||||
),
|
),
|
||||||
'Erc20 token balance should be correctly increased by the token swap'
|
'Erc20 token balance should be correctly increased by the token swap'
|
||||||
)
|
)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
require('../env')
|
require('../env')
|
||||||
const Web3 = require('web3')
|
const Web3 = require('web3')
|
||||||
|
const { getTokensState } = require('../src/events/processTransfers/tokenState')
|
||||||
const {
|
const {
|
||||||
ERC677_BRIDGE_TOKEN_ABI,
|
ERC677_BRIDGE_TOKEN_ABI,
|
||||||
FOREIGN_ERC_TO_ERC_ABI,
|
FOREIGN_ERC_TO_ERC_ABI,
|
||||||
@ -9,7 +10,7 @@ const {
|
|||||||
|
|
||||||
async function initialChecks() {
|
async function initialChecks() {
|
||||||
const { ORACLE_BRIDGE_MODE, COMMON_FOREIGN_RPC_URL, COMMON_FOREIGN_BRIDGE_ADDRESS } = process.env
|
const { ORACLE_BRIDGE_MODE, COMMON_FOREIGN_RPC_URL, COMMON_FOREIGN_BRIDGE_ADDRESS } = process.env
|
||||||
const result = {}
|
let result = {}
|
||||||
const foreignWeb3 = new Web3(new Web3.providers.HttpProvider(COMMON_FOREIGN_RPC_URL))
|
const foreignWeb3 = new Web3(new Web3.providers.HttpProvider(COMMON_FOREIGN_RPC_URL))
|
||||||
|
|
||||||
if (ORACLE_BRIDGE_MODE === 'ERC_TO_ERC') {
|
if (ORACLE_BRIDGE_MODE === 'ERC_TO_ERC') {
|
||||||
@ -17,17 +18,7 @@ async function initialChecks() {
|
|||||||
result.bridgeableTokenAddress = await bridge.methods.erc20token().call()
|
result.bridgeableTokenAddress = await bridge.methods.erc20token().call()
|
||||||
} else if (ORACLE_BRIDGE_MODE === 'ERC_TO_NATIVE') {
|
} else if (ORACLE_BRIDGE_MODE === 'ERC_TO_NATIVE') {
|
||||||
const bridge = new foreignWeb3.eth.Contract(FOREIGN_ERC_TO_NATIVE_ABI, COMMON_FOREIGN_BRIDGE_ADDRESS)
|
const bridge = new foreignWeb3.eth.Contract(FOREIGN_ERC_TO_NATIVE_ABI, COMMON_FOREIGN_BRIDGE_ADDRESS)
|
||||||
result.bridgeableTokenAddress = await bridge.methods.erc20token().call()
|
result = await getTokensState(bridge)
|
||||||
try {
|
|
||||||
const halfDuplexErc20tokenAddress = await bridge.methods.halfDuplexErc20token().call()
|
|
||||||
if (halfDuplexErc20tokenAddress !== result.bridgeableTokenAddress) {
|
|
||||||
result.halfDuplexTokenAddress = halfDuplexErc20tokenAddress
|
|
||||||
} else {
|
|
||||||
result.idle = true
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
result.idle = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ORACLE_BRIDGE_MODE === 'ERC_TO_ERC') {
|
if (ORACLE_BRIDGE_MODE === 'ERC_TO_ERC') {
|
||||||
|
20
oracle/src/events/processTransfers/tokenState.js
Normal file
20
oracle/src/events/processTransfers/tokenState.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
async function getTokensState(bridgeContract) {
|
||||||
|
const context = {}
|
||||||
|
context.bridgeableTokenAddress = await bridgeContract.methods.erc20token().call()
|
||||||
|
try {
|
||||||
|
const halfDuplexErc20tokenAddress = await bridgeContract.methods.halfDuplexErc20token().call()
|
||||||
|
if (halfDuplexErc20tokenAddress !== context.bridgeableTokenAddress) {
|
||||||
|
context.halfDuplexTokenAddress = halfDuplexErc20tokenAddress
|
||||||
|
} else {
|
||||||
|
context.idle = true
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
context.idle = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getTokensState
|
||||||
|
}
|
@ -26,12 +26,16 @@ const processAMBSignatureRequests = require('./events/processAMBSignatureRequest
|
|||||||
const processAMBCollectedSignatures = require('./events/processAMBCollectedSignatures')(config)
|
const processAMBCollectedSignatures = require('./events/processAMBCollectedSignatures')(config)
|
||||||
const processAMBAffirmationRequests = require('./events/processAMBAffirmationRequests')(config)
|
const processAMBAffirmationRequests = require('./events/processAMBAffirmationRequests')(config)
|
||||||
|
|
||||||
|
const { getTokensState } = require('./events/processTransfers/tokenState')
|
||||||
|
|
||||||
const ZERO = toBN(0)
|
const ZERO = toBN(0)
|
||||||
const ONE = toBN(1)
|
const ONE = toBN(1)
|
||||||
|
|
||||||
const web3Instance = config.web3
|
const web3Instance = config.web3
|
||||||
const bridgeContract = new web3Instance.eth.Contract(config.bridgeAbi, config.bridgeContractAddress)
|
const bridgeContract = new web3Instance.eth.Contract(config.bridgeAbi, config.bridgeContractAddress)
|
||||||
const eventContract = new web3Instance.eth.Contract(config.eventAbi, config.eventContractAddress)
|
let { eventContractAddress } = config
|
||||||
|
let eventContract = new web3Instance.eth.Contract(config.eventAbi, eventContractAddress)
|
||||||
|
let skipEvents = config.idle
|
||||||
const lastBlockRedisKey = `${config.id}:lastProcessedBlock`
|
const lastBlockRedisKey = `${config.id}:lastProcessedBlock`
|
||||||
let lastProcessedBlock = BN.max(config.startBlock.sub(ONE), ZERO)
|
let lastProcessedBlock = BN.max(config.startBlock.sub(ONE), ZERO)
|
||||||
|
|
||||||
@ -117,6 +121,29 @@ function processEvents(events, blockNumber) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function checkConditions() {
|
||||||
|
let state
|
||||||
|
switch (config.id) {
|
||||||
|
case 'erc-native-transfer':
|
||||||
|
state = await getTokensState(bridgeContract)
|
||||||
|
updateEventContract(state.bridgeableTokenAddress)
|
||||||
|
break
|
||||||
|
case 'erc-native-half-duplex-transfer':
|
||||||
|
state = await getTokensState(bridgeContract)
|
||||||
|
skipEvents = state.idle
|
||||||
|
updateEventContract(state.halfDuplexTokenAddress)
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateEventContract(address) {
|
||||||
|
if (eventContractAddress !== address) {
|
||||||
|
eventContractAddress = address
|
||||||
|
eventContract = new web3Instance.eth.Contract(config.eventAbi, eventContractAddress)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function getLastBlockToProcess() {
|
async function getLastBlockToProcess() {
|
||||||
const lastBlockNumberPromise = getBlockNumber(web3Instance).then(toBN)
|
const lastBlockNumberPromise = getBlockNumber(web3Instance).then(toBN)
|
||||||
const requiredBlockConfirmationsPromise = getRequiredBlockConfirmations(bridgeContract).then(toBN)
|
const requiredBlockConfirmationsPromise = getRequiredBlockConfirmations(bridgeContract).then(toBN)
|
||||||
@ -130,7 +157,9 @@ async function getLastBlockToProcess() {
|
|||||||
|
|
||||||
async function main({ sendToQueue, sendToWorker }) {
|
async function main({ sendToQueue, sendToWorker }) {
|
||||||
try {
|
try {
|
||||||
if (config.idle) {
|
await checkConditions()
|
||||||
|
|
||||||
|
if (skipEvents) {
|
||||||
logger.debug('Watcher in idle mode, skipping getting events')
|
logger.debug('Watcher in idle mode, skipping getting events')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user