Support of multi send transaction generation

This commit is contained in:
Kirill Fedoseev 2019-10-14 23:40:55 +03:00
parent 9070333d46
commit 9bcbdfab67
13 changed files with 245 additions and 95 deletions

View File

@ -5,12 +5,28 @@ const system = Application('System Events')
const curApp = Application.currentApplication()
curApp.includeStandardAdditions = true
const ethReceiver = '0x9072708Cf98a0e7962cd3420e5bdb1c9A3898f0a'
const bncReceiver = 'tbnb1300mwrkuhxtzdqahlyqfqx246p7jt6kfcst5vd'
const validator1 = '0x99Eb3D86663c6Db090eFFdBC20510Ca9f836DCE3'
const validator2 = '0xAa006899B0EC407De930bA8A166DEfe59bBfd3DC'
const validator3 = '0x6352e3e6038e05b9da00C84AE851308f9774F883'
const userAccounts = [
{
privateKey: '7ed93ad7753e00b52265a73dfbbcd2296256772965323fcb9a6320b5cd084b89',
ethAddress: '0x4db6b4bd0a3fdc03b027a60f1c48f05c572312aa',
bncAddress: 'tbnb14r3z8xk7qsar3vwj05w8cd8gqwk7g6gfurlt5l'
},
{
privateKey: '2ad6e3a232ad3ea058b61352302118a99085600ff8b6eec4ccf0066a33756231',
ethAddress: '0xf7ca4aed1795e424433498cef43f6a3825c88731',
bncAddress: 'tbnb1efjg7xt98t67ql2cmwjc5860lgayet9l8m55ym'
},
{
privateKey: 'eb6dd328677b3fa2822fb8e834507e569bda52e8ffa49266df0f2de239c4ec98',
ethAddress: '0xad6c8127143032d843a260c5d379d8d9b3d51f15',
bncAddress: 'tbnb12epcy4p7ktas0nlyrfuektcyh0e83dwzuq73f4'
}
]
let bridgeBncAddress
const windows = terminal.windows()
@ -82,6 +98,11 @@ function wait (n) {
}
}
function execSync(n, script) {
exec(n, script)
wait(n)
}
function waitAll () {
wait(1)
wait(2)
@ -109,6 +130,27 @@ function waitApi (n, url, check) {
} while (true)
}
function prefundEthAddresses () {
for (let { ethAddress } of userAccounts) {
exec(4, `./src/test-services/ethereumSend/run.sh ${ethAddress} 100`)
wait(4)
}
}
function prefundBncAddresses () {
for (let { bncAddress } of userAccounts) {
exec(4, `./src/test-services/binanceSend/run.sh ${bncAddress} 100 0.1`)
wait(4)
}
}
function initBalances () {
userAccounts.forEach(account => {
account.ethBalance = getEthTokenBalance(account.ethAddress)
account.bncBalance = getBncTokenBalance(account.bncAddress)
})
}
function getBncTokenBalance (address) {
const res = curApp.doShellScript(`./src/test-services/binanceBalance/run.sh ${address}`)
return parseFloat(/KFT-94F: [0-9.]+/.exec(res)[0].split(' ')[1])
@ -118,7 +160,7 @@ function waitBncTokenBalance (address, balance) {
do {
const newBalance = getBncTokenBalance(address)
if (Math.abs(newBalance - balance) < 0.0001)
return true
return newBalance
delay(0.3)
} while (true)
}
@ -132,23 +174,21 @@ function waitEthTokenBalance (address, balance) {
do {
const newBalance = getEthTokenBalance(address)
if (Math.abs(newBalance - balance) < 0.0001)
return true
return newBalance
delay(0.3)
} while (true)
}
function apiRequest(n, url, suffix) {
exec(4, `curl -s -X GET http://localhost:500${n}${url} ${suffix ? suffix : ''}`)
wait(4)
function apiRequest (n, url, suffix) {
execSync(4, `curl -s -X GET http://localhost:500${n}${url} ${suffix ? suffix : ''}`)
}
function printState (msg) {
exec(4, `echo "${msg}"`)
wait(4)
execSync(4, `echo "${msg}"`)
apiRequest(1, '/info', '| jq .')
}
function initCwd() {
function initCwd () {
const cwd = $.getenv('PWD')
for (let i = 1; i <= 4; i++) {
@ -157,17 +197,14 @@ function initCwd() {
waitAll()
}
function killDockerContainers() {
exec(4, `docker kill $(docker ps | grep validator | awk '{print $1}') > /dev/null 2>&1 || true`)
wait(4)
exec(4, `docker kill ganache_side ganache_home > /dev/null 2>&1 || true`)
wait(4)
function killDockerContainers () {
execSync(4, `docker kill $(docker ps | grep validator | awk '{print $1}') > /dev/null 2>&1 || true`)
execSync(4, `docker kill ganache_side ganache_home > /dev/null 2>&1 || true`)
}
function clean() {
function clean () {
killDockerContainers()
exec(4, `./demo/clean.sh`)
wait(4)
execSync(4, `./demo/clean.sh`)
exec(1, `clear`)
exec(2, `clear`)
@ -175,10 +212,9 @@ function clean() {
waitAll()
}
function testEthToBnc() {
function testEthToBnc () {
console.log('Testing eth => bnc')
// try token transfer in eth => bnc direction
const prevBncBalance = getBncTokenBalance(bncReceiver)
let prevBridgeHomeBalance
let prevBridgeForeignBalance
waitApi(1, '/info', res => {
@ -187,20 +223,25 @@ function testEthToBnc() {
return true
})
exec(4, `./src/test-services/ethereumSend/run.sh bridge 5`)
wait(4)
userAccounts.forEach(({ privateKey }, i) => {
exec(4, `PRIVATE_KEY=${privateKey} ./src/test-services/ethereumSend/run.sh bridge ${5 + i}`)
wait(4)
})
waitApi(1, '/info', res => res.homeBalance === prevBridgeHomeBalance + 5 && res.foreignBalanceTokens === prevBridgeForeignBalance - 5)
waitBncTokenBalance(bncReceiver, prevBncBalance + 5)
const delta = (9 + userAccounts.length) * userAccounts.length / 2
waitApi(1, '/info', res => res.homeBalance === prevBridgeHomeBalance + delta && res.foreignBalanceTokens === prevBridgeForeignBalance - delta)
userAccounts.forEach((account, i) => {
account.bncBalance = waitBncTokenBalance(account.bncAddress, account.bncBalance + 5 + i)
})
printState(`Token transfer in eth => bnc direction succeed`)
console.log('Testing eth => bnc is OK')
}
function testBncToEth() {
function testBncToEth () {
console.log('Testing bnc => eth')
// try token transfer in bnc => eth direction
const prevEthBalance = getEthTokenBalance(ethReceiver)
let prevBridgeHomeBalance
let prevBridgeForeignBalance
waitApi(1, '/info', res => {
@ -209,17 +250,24 @@ function testBncToEth() {
return true
})
exec(4, `./src/test-services/binanceSend/run.sh ${bridgeBncAddress} 3`)
wait(4)
userAccounts.forEach(({ privateKey }, i) => {
exec(4, `PRIVATE_KEY=${privateKey} ./src/test-services/binanceSend/run.sh ${bridgeBncAddress} ${3 + i}`)
wait(4)
})
waitApi(1, '/info', res => res.homeBalance === prevBridgeHomeBalance - 3 && res.foreignBalanceTokens === prevBridgeForeignBalance + 3)
waitEthTokenBalance(ethReceiver, prevEthBalance + 3)
const delta = (5 + userAccounts.length) * userAccounts.length / 2
waitApi(1, '/info', res => res.homeBalance === prevBridgeHomeBalance - delta && res.foreignBalanceTokens === prevBridgeForeignBalance + delta)
userAccounts.forEach((account, i) => {
account.ethBalance = waitEthTokenBalance(account.ethAddress, account.ethBalance + 3 + i)
})
printState(`Token transfer in bnc => eth direction succeed`)
console.log('Testing bnc => eth is OK')
}
function testRemoveValidator() {
function testRemoveValidator () {
console.log('Testing removing validator')
apiRequest(1, '/vote/startVoting')
apiRequest(2, '/vote/startVoting')
@ -240,7 +288,7 @@ function testRemoveValidator() {
console.log('Testing removing validator is OK')
}
function testAddValidator() {
function testAddValidator () {
console.log('Testing adding validator')
apiRequest(1, '/vote/startVoting')
apiRequest(3, '/vote/startVoting')
@ -261,7 +309,7 @@ function testAddValidator() {
console.log('Testing adding validator is OK')
}
function testChangeThreshold() {
function testChangeThreshold () {
console.log('Testing changing threshold')
apiRequest(1, '/vote/startVoting')
apiRequest(3, '/vote/startVoting')
@ -291,8 +339,12 @@ function run () {
clean()
exec(4, `./demo/start-environment.sh`)
wait(4)
execSync(4, `./demo/start-environment.sh`)
prefundEthAddresses()
prefundBncAddresses()
initBalances()
exec(1, `N=1 ./demo/validator-demo.sh`)
exec(2, `N=2 ./demo/validator-demo.sh`)
@ -303,8 +355,7 @@ function run () {
bridgeBncAddress = /tbnb\w+/.exec(log)[0]
// prefund binance account
exec(4, `./src/test-services/binanceSend/run.sh ${bridgeBncAddress} 100 0.1`)
wait(4)
execSync(4, `./src/test-services/binanceSend/run.sh ${bridgeBncAddress} 100 0.1`)
// wait until binance prefund transaction will be processed
waitApi(1, '/info', res => res.foreignBalanceTokens === 100)

View File

@ -22,7 +22,7 @@ start_dev_blockchain_networks() {
docker network create blockchain_side > /dev/null 2>&1 || true
docker run -d --network blockchain_side --rm --name ganache_side -v "$SIDE_GANACHE_DB:/app/db" \
trufflesuite/ganache-cli:latest \
-m "shrug dwarf easily blade trigger lucky reopen cage lake scatter desk boat" -i 33 -q --db /app/db -b 1
-m "shrug dwarf easily blade trigger lucky reopen cage lake scatter desk boat" -i 33 -q --db /app/db -b 3 --noVMErrorsOnRPCResponse
echo "Starting home test blockchain"
@ -30,7 +30,7 @@ start_dev_blockchain_networks() {
docker network create blockchain_home > /dev/null 2>&1 || true
docker run -d --network blockchain_home --rm --name ganache_home -v "$HOME_GANACHE_DB:/app/db" \
trufflesuite/ganache-cli:latest \
-m "shrug dwarf easily blade trigger lucky reopen cage lake scatter desk boat" -i 44 -q --db /app/db -b 1
-m "shrug dwarf easily blade trigger lucky reopen cage lake scatter desk boat" -i 44 -q --db /app/db -b 3 --noVMErrorsOnRPCResponse
sleep 4
}

View File

@ -3,6 +3,8 @@ HOME_BRIDGE_ADDRESS=0x44c158FE850821ae69DaF37AADF5c539e9d0025B
HOME_TOKEN_ADDRESS=0xd5fE0D28e058D375b0b038fFbB446Da37E85fFdc
HOME_START_BLOCK=1
BLOCKS_RANGE_SIZE=50
SIDE_RPC_URL=http://ganache_side:8545
SIDE_SHARED_DB_ADDRESS=0xd5fE0D28e058D375b0b038fFbB446Da37E85fFdc
@ -16,3 +18,4 @@ VOTES_PROXY_PORT=5001
SIGN_RESTART_PORT=6001
LOG_LEVEL=debug

View File

@ -3,6 +3,8 @@ HOME_BRIDGE_ADDRESS=0x6ADCa5e691341fb9de8927d15c0a89B83A4E665e
HOME_TOKEN_ADDRESS=0x57d2533B640cfb58f8f1F69C14c089968Da9fdFc
HOME_START_BLOCK=13276224
BLOCKS_RANGE_SIZE=10
SIDE_RPC_URL=https://sokol.poa.network
SIDE_SHARED_DB_ADDRESS=0xda9a1cA2Fcb18cAB02934269369627D2b4ea8902
@ -16,3 +18,4 @@ VOTES_PROXY_PORT=5001
SIGN_RESTART_PORT=6001
LOG_LEVEL=info

View File

@ -3,6 +3,8 @@ HOME_BRIDGE_ADDRESS=0x44c158FE850821ae69DaF37AADF5c539e9d0025B
HOME_TOKEN_ADDRESS=0xd5fE0D28e058D375b0b038fFbB446Da37E85fFdc
HOME_START_BLOCK=1
BLOCKS_RANGE_SIZE=50
SIDE_RPC_URL=http://ganache_side:8545
SIDE_SHARED_DB_ADDRESS=0xd5fE0D28e058D375b0b038fFbB446Da37E85fFdc
@ -16,3 +18,4 @@ VOTES_PROXY_PORT=5002
SIGN_RESTART_PORT=6002
LOG_LEVEL=debug

View File

@ -3,6 +3,8 @@ HOME_BRIDGE_ADDRESS=0x6ADCa5e691341fb9de8927d15c0a89B83A4E665e
HOME_TOKEN_ADDRESS=0x57d2533B640cfb58f8f1F69C14c089968Da9fdFc
HOME_START_BLOCK=13276224
BLOCKS_RANGE_SIZE=10
SIDE_RPC_URL=https://sokol.poa.network
SIDE_SHARED_DB_ADDRESS=0xda9a1cA2Fcb18cAB02934269369627D2b4ea8902
@ -16,3 +18,4 @@ VOTES_PROXY_PORT=5002
SIGN_RESTART_PORT=6002
LOG_LEVEL=info

View File

@ -3,6 +3,8 @@ HOME_BRIDGE_ADDRESS=0x44c158FE850821ae69DaF37AADF5c539e9d0025B
HOME_TOKEN_ADDRESS=0xd5fE0D28e058D375b0b038fFbB446Da37E85fFdc
HOME_START_BLOCK=1
BLOCKS_RANGE_SIZE=50
SIDE_RPC_URL=http://ganache_side:8545
SIDE_SHARED_DB_ADDRESS=0xd5fE0D28e058D375b0b038fFbB446Da37E85fFdc
@ -16,3 +18,4 @@ VOTES_PROXY_PORT=5003
SIGN_RESTART_PORT=6003
LOG_LEVEL=debug

View File

@ -3,6 +3,8 @@ HOME_BRIDGE_ADDRESS=0x6ADCa5e691341fb9de8927d15c0a89B83A4E665e
HOME_TOKEN_ADDRESS=0x57d2533B640cfb58f8f1F69C14c089968Da9fdFc
HOME_START_BLOCK=13276224
BLOCKS_RANGE_SIZE=10
SIDE_RPC_URL=https://sokol.poa.network
SIDE_SHARED_DB_ADDRESS=0xda9a1cA2Fcb18cAB02934269369627D2b4ea8902
@ -16,3 +18,4 @@ VOTES_PROXY_PORT=5003
SIGN_RESTART_PORT=6003
LOG_LEVEL=info

View File

@ -16,7 +16,7 @@ services:
- VALIDATOR_PRIVATE_KEY
- FOREIGN_URL
- FOREIGN_ASSET
- 'LOG_LEVEL=info'
- LOG_LEVEL
volumes:
- '../deploy/deploy-test/build/contracts/IERC20.json:/proxy/contracts_data/IERC20.json'
- '../deploy/deploy-home/build/contracts/Bridge.json:/proxy/contracts_data/Bridge.json'
@ -35,7 +35,7 @@ services:
environment:
- 'RABBITMQ_URL=amqp://rabbitmq:5672'
- 'PROXY_URL=http://proxy:8001'
- 'LOG_LEVEL=info'
- LOG_LEVEL
volumes:
- '${PWD}/${TARGET_NETWORK}/keys:/keys'
networks:
@ -51,7 +51,7 @@ services:
- FOREIGN_CHAIN_ID
- FOREIGN_URL
- FOREIGN_ASSET
- 'LOG_LEVEL=info'
- LOG_LEVEL
volumes:
- '${PWD}/${TARGET_NETWORK}/keys:/keys'
ports:
@ -86,8 +86,9 @@ services:
- HOME_TOKEN_ADDRESS
- HOME_CHAIN_ID
- HOME_START_BLOCK
- BLOCKS_RANGE_SIZE
- 'RABBITMQ_URL=amqp://rabbitmq:5672'
- 'LOG_LEVEL=info'
- LOG_LEVEL
volumes:
- '../deploy/deploy-home/build/contracts/Bridge.json:/watcher/contracts_data/Bridge.json'
networks:
@ -103,7 +104,7 @@ services:
- FOREIGN_ASSET
- 'RABBITMQ_URL=amqp://rabbitmq:5672'
- 'PROXY_URL=http://proxy:8001'
- 'LOG_LEVEL=info'
- LOG_LEVEL
volumes:
- '${PWD}/${TARGET_NETWORK}/keys:/keys'
networks:

View File

@ -16,7 +16,7 @@ services:
- VALIDATOR_PRIVATE_KEY
- FOREIGN_URL
- FOREIGN_ASSET
- 'LOG_LEVEL=info'
- LOG_LEVEL
volumes:
- '../deploy/deploy-test/build/contracts/IERC20.json:/proxy/contracts_data/IERC20.json'
- '../deploy/deploy-home/build/contracts/Bridge.json:/proxy/contracts_data/Bridge.json'
@ -35,7 +35,7 @@ services:
environment:
- 'RABBITMQ_URL=amqp://rabbitmq:5672'
- 'PROXY_URL=http://proxy:8001'
- 'LOG_LEVEL=info'
- LOG_LEVEL
volumes:
- '${PWD}/${TARGET_NETWORK}/keys:/keys'
networks:
@ -53,7 +53,7 @@ services:
- FOREIGN_CHAIN_ID
- FOREIGN_URL
- FOREIGN_ASSET
- 'LOG_LEVEL=info'
- LOG_LEVEL
volumes:
- '${PWD}/${TARGET_NETWORK}/keys:/keys'
ports:
@ -97,7 +97,7 @@ services:
- HOME_CHAIN_ID
- HOME_START_BLOCK
- 'RABBITMQ_URL=amqp://rabbitmq:5672'
- 'LOG_LEVEL=info'
- LOG_LEVEL
volumes:
- '../deploy/deploy-home/build/contracts/Bridge.json:/watcher/contracts_data/Bridge.json'
networks:
@ -113,7 +113,7 @@ services:
- FOREIGN_ASSET
- 'RABBITMQ_URL=amqp://rabbitmq:5672'
- 'PROXY_URL=http://proxy:8001'
- 'LOG_LEVEL=info'
- LOG_LEVEL
volumes:
- '${PWD}/${TARGET_NETWORK}/keys:/keys'
networks:

View File

@ -11,18 +11,24 @@ const { publicKeyToAddress } = require('./crypto')
const abiBridge = require('./contracts_data/Bridge.json').abi
const { HOME_RPC_URL, HOME_BRIDGE_ADDRESS, RABBITMQ_URL, HOME_START_BLOCK } = process.env
const BLOCKS_RANGE_SIZE = parseInt(process.env.BLOCKS_RANGE_SIZE)
const web3Home = new Web3(HOME_RPC_URL)
const bridge = new web3Home.eth.Contract(abiBridge, HOME_BRIDGE_ADDRESS)
let channel
let exchangeQueue
let signQueue
let keygenQueue
let cancelKeygenQueue
let blockNumber
let foreignNonce = []
let epoch
let epochStart
let rangeStart
let rangeEnd
let redisTx
let lastTransactionBlockNumber
async function resetFutureMessages (queue) {
logger.debug(`Resetting future messages in queue ${queue.name}`)
@ -62,6 +68,7 @@ async function resetFutureMessages (queue) {
async function initialize () {
channel = await connectRabbit(RABBITMQ_URL)
exchangeQueue = await assertQueue(channel, 'exchangeQueue')
signQueue = await assertQueue(channel, 'signQueue')
keygenQueue = await assertQueue(channel, 'keygenQueue')
cancelKeygenQueue = await assertQueue(channel, 'cancelKeygenQueue')
@ -71,7 +78,7 @@ async function initialize () {
})
epoch = events.length ? events[events.length - 1].returnValues.epoch.toNumber() : 0
logger.info(`Current epoch ${epoch}`)
const epochStart = events.length ? events[events.length - 1].blockNumber : 1
epochStart = events.length ? events[events.length - 1].blockNumber : 1
const saved = (parseInt(await redis.get('homeBlock')) + 1) || parseInt(HOME_START_BLOCK)
logger.debug(epochStart, saved)
if (epochStart > saved) {
@ -88,8 +95,14 @@ async function initialize () {
foreignNonce[epoch] = parseInt(await redis.get(`foreignNonce${epoch}`)) || 0
}
rangeStart = blockNumber - (blockNumber - epochStart) % BLOCKS_RANGE_SIZE
rangeEnd = rangeStart + BLOCKS_RANGE_SIZE - 1
logger.info('Initialized sign range range, [%d-%d]', rangeStart, rangeEnd)
await resetFutureMessages(keygenQueue)
await resetFutureMessages(cancelKeygenQueue)
await resetFutureMessages(exchangeQueue)
await resetFutureMessages(signQueue)
logger.debug(`Sending start commands`)
await axios.get('http://keygen:8001/start')
@ -128,11 +141,25 @@ async function main () {
case 'EpochStart':
epoch = event.returnValues.epoch.toNumber()
logger.info(`Epoch ${epoch} started`)
rangeStart = blockNumber
rangeEnd = blockNumber + BLOCKS_RANGE_SIZE - 1
logger.info('Updated sign range range, [%d-%d]', rangeStart, rangeEnd)
foreignNonce[epoch] = 0
break
}
}
if (blockNumber === rangeEnd) {
logger.info('Reached end of the current block range')
if (lastTransactionBlockNumber >= rangeStart) {
logger.info('Sending message to start signature generation for the ended range')
await sendStartSign()
}
rangeStart = rangeEnd + 1
rangeEnd = rangeEnd + BLOCKS_RANGE_SIZE
logger.info('Updated sign range range, [%d-%d]', rangeStart, rangeEnd)
}
blockNumber++
// Exec redis tx
await redisTx.incr('homeBlock').exec()
@ -201,15 +228,26 @@ async function sendSign (event) {
x: publicKey.substr(4, 64),
y: publicKey.substr(68, 64)
}),
value: (new BN(event.returnValues.value)).dividedBy(10 ** 18).toFixed(8, 3),
nonce: foreignNonce[epoch],
threshold: (await bridge.methods.getThreshold(epoch).call()).toNumber(),
parties: (await bridge.methods.getParties(epoch).call()).toNumber()
value: (new BN(event.returnValues.value)).dividedBy(10 ** 18).toFixed(8, 3)
}
signQueue.send(msgToQueue)
exchangeQueue.send(msgToQueue)
logger.debug('Sent new sign event: %o', msgToQueue)
redisTx.incr(`foreignNonce${epoch}`)
foreignNonce[epoch]++
lastTransactionBlockNumber = blockNumber
redisTx.set('lastTransactionBlockNumber', blockNumber)
logger.debug('Set lastTransactionBlockNumber to %d', blockNumber)
}
async function sendStartSign() {
redisTx.incr(`foreignNonce${epoch}`)
signQueue.send({
epoch,
blockNumber,
nonce: foreignNonce[epoch]++,
startBlock: rangeStart,
endBlock: rangeEnd,
threshold: (await bridge.methods.getThreshold(epoch).call()).toNumber(),
parties: (await bridge.methods.getParties(epoch).call()).toNumber()
})
}

View File

@ -26,11 +26,14 @@ let attempt
let nextAttempt = null
let cancelled
let ready = false
let exchangeQueue
let channel
async function main () {
logger.info('Connecting to RabbitMQ server')
const channel = await connectRabbit(RABBITMQ_URL)
channel = await connectRabbit(RABBITMQ_URL)
logger.info('Connecting to signature events queue')
exchangeQueue = await assertQueue(channel, 'exchangeQueue')
const signQueue = await assertQueue(channel, 'signQueue')
while (!ready) {
@ -42,7 +45,7 @@ async function main () {
const data = JSON.parse(msg.content)
logger.info('Consumed sign event: %o', data)
const { recipient, value, nonce, epoch, newEpoch, parties, threshold } = data
const { nonce, epoch, newEpoch, startBlock, endBlock, parties, threshold } = data
const keysFile = `/keys/keys${epoch}.store`
const { address: from, publicKey } = getAccountFromFile(keysFile)
@ -58,15 +61,17 @@ async function main () {
attempt = 1
if (recipient && account.sequence <= nonce) {
if (!newEpoch && account.sequence <= nonce) {
while (true) {
logger.info(`Building corresponding transfer transaction, nonce ${nonce}, recipient ${recipient}`)
logger.info(`Building corresponding transfer transaction, nonce ${nonce}`)
const exchanges = await getExchangeMessages(startBlock, endBlock)
const exchangesData = exchanges.map(msg => JSON.parse(msg.content))
const tx = new Transaction({
from,
accountNumber: account.account_number,
sequence: nonce,
to: recipient,
tokens: value,
recipients: exchangesData.map(({ value, recipient }) => ({ to: recipient, tokens: value })),
asset: FOREIGN_ASSET,
memo: `Attempt ${attempt}`
})
@ -76,6 +81,7 @@ async function main () {
const done = await sign(keysFile, hash, tx, publicKey) && await waitForAccountNonce(from, nonce + 1)
if (done) {
exchanges.forEach(msg => channel.ack(msg))
break
}
attempt = nextAttempt ? nextAttempt : attempt + 1
@ -93,10 +99,12 @@ async function main () {
from,
accountNumber: account.account_number,
sequence: nonce,
to,
tokens: account.balances.find(x => x.symbol === FOREIGN_ASSET).free,
recipients: [{
to,
tokens: account.balances.find(x => x.symbol === FOREIGN_ASSET).free,
bnbs: new BN(account.balances.find(x => x.symbol === 'BNB').free).minus(new BN(60000).div(10 ** 8)),
}],
asset: FOREIGN_ASSET,
bnbs: new BN(account.balances.find(x => x.symbol === 'BNB').free).minus(new BN(60000).div(10 ** 8)),
memo: `Attempt ${attempt}`
})
@ -123,6 +131,27 @@ async function main () {
main()
async function getExchangeMessages(startBlock, endBlock) {
logger.debug('Getting exchange messages')
const messages = []
do {
const msg = await exchangeQueue.get()
if (msg === false) {
break;
}
const data = JSON.parse(msg.content)
logger.debug('Got message %o', data)
if (data.blockNumber > endBlock) {
channel.ack(msg)
break;
}
if (data.blockNumber >= startBlock)
messages.push(msg)
} while (true)
logger.debug('Found %d messages', messages.length)
return messages
}
function sign (keysFile, hash, tx, publicKey) {
return new Promise(resolve => {
const cmd = exec.execFile('./sign-entrypoint.sh', [ PROXY_URL, keysFile, hash ], async (error) => {

View File

@ -7,50 +7,63 @@ const { padZeros } = require('./crypto')
const { FOREIGN_CHAIN_ID } = process.env
const BNB_ASSET = 'BNB'
class Transaction {
constructor (options) {
const { from, accountNumber, sequence, to, tokens, asset, bnbs, memo = '' } = options
const accCode = crypto.decodeAddress(from)
const toAccCode = crypto.decodeAddress(to)
const { from, accountNumber, sequence, recipients, asset, memo = '' } = options
const coins = []
if (tokens && tokens !== '0' && asset) {
coins.push({
const totalTokens = recipients.reduce((sum, { tokens }) => sum.plus(new BN(tokens || 0)), new BN(0))
const totalBnbs = recipients.reduce((sum, { bnbs }) => sum.plus(new BN(bnbs || 0)), new BN(0))
const senderCoins = []
if (asset && totalTokens.isGreaterThan(0)) {
senderCoins.push({
denom: asset,
amount: new BN(tokens).multipliedBy(10 ** 8).toNumber(),
amount: totalTokens.multipliedBy(10 ** 8).toNumber(),
})
}
if (bnbs && bnbs !== '0') {
coins.push({
denom: 'BNB',
amount: new BN(bnbs).multipliedBy(10 ** 8).toNumber(),
if (totalBnbs.isGreaterThan(0)) {
senderCoins.push({
denom: BNB_ASSET,
amount: totalBnbs.multipliedBy(10 ** 8).toNumber(),
})
}
senderCoins.sort((a, b) => a.denom > b.denom)
coins.sort((a, b) => a.denom > b.denom)
const inputs = [ {
address: from,
coins: senderCoins
} ]
const outputs = recipients.map(({ to, tokens, bnbs }) => {
const receiverCoins = []
if (asset && tokens) {
receiverCoins.push({
denom: asset,
amount: new BN(tokens).multipliedBy(10 ** 8).toNumber(),
})
}
if (bnbs) {
receiverCoins.push({
denom: BNB_ASSET,
amount: new BN(bnbs).multipliedBy(10 ** 8).toNumber(),
})
}
receiverCoins.sort((a, b) => a.denom > b.denom)
return {
address: to,
coins: receiverCoins
}
})
const msg = {
inputs: [ {
address: accCode,
coins
} ],
outputs: [ {
address: toAccCode,
coins
} ],
inputs: inputs.map((x) => ({...x, address: crypto.decodeAddress(x.address)})),
outputs: outputs.map((x) => ({...x, address: crypto.decodeAddress(x.address)})),
msgType: 'MsgSend'
}
this.signMsg = {
inputs: [ {
address: from,
coins
} ],
outputs: [ {
address: to,
coins
} ]
inputs,
outputs
}
this.tx = new TransactionBnc({