tokenbridge-contracts/test/helpers/helpers.js

220 lines
6.1 KiB
JavaScript

const { expect } = require('chai')
const { BN } = require('../setup')
// returns a Promise that resolves with a hex string that is the signature of
// `data` signed with the key of `address`
function sign(address, data) {
return new Promise((resolve, reject) => {
web3.eth.sign(data, address, (err, result) => {
if (err !== null) {
return reject(err)
}
return resolve(normalizeSignature(result))
// return resolve(result);
})
})
}
module.exports.sign = sign
// geth && testrpc has different output of eth_sign than parity
// https://github.com/ethereumjs/testrpc/issues/243#issuecomment-326750236
function normalizeSignature(rawSignature) {
const signature = strip0x(rawSignature)
// increase v by 27...
return `0x${signature.substr(0, 128)}${(parseInt(signature.substr(128), 16) + 27).toString(16)}`
}
module.exports.normalizeSignature = normalizeSignature
// strips leading "0x" if present
function strip0x(input) {
return input.replace(/^0x/, '')
}
module.exports.strip0x = strip0x
// extracts and returns the `v`, `r` and `s` values from a `signature`.
function signatureToVRS(rawSignature) {
assert.equal(rawSignature.length, 2 + 32 * 2 + 32 * 2 + 2)
const signature = strip0x(rawSignature)
const v = signature.substr(64 * 2)
const r = signature.substr(0, 32 * 2)
const s = signature.substr(32 * 2, 32 * 2)
return { v, r, s }
}
module.exports.signatureToVRS = signatureToVRS
function packSignatures(array) {
const length = strip0x(web3.utils.toHex(array.length))
const msgLength = length.length === 1 ? `0${length}` : length
let v = ''
let r = ''
let s = ''
array.forEach(e => {
v = v.concat(e.v)
r = r.concat(e.r)
s = s.concat(e.s)
})
return `0x${msgLength}${v}${r}${s}`
}
module.exports.packSignatures = packSignatures
// returns BigNumber `num` converted to a little endian hex string
// that is exactly 32 bytes long.
// `num` must represent an unsigned integer
function bigNumberToPaddedBytes32(num) {
let result = strip0x(num.toString(16))
while (result.length < 64) {
result = `0${result}`
}
return `0x${result}`
}
module.exports.bigNumberToPaddedBytes32 = bigNumberToPaddedBytes32
// returns an promise that resolves to an object
// that maps `addresses` to their current balances
function getBalances(addresses) {
return Promise.all(
addresses.map(address => {
return web3.eth.getBalance(address)
})
).then(balancesArray => {
const addressToBalance = {}
addresses.forEach((address, index) => {
addressToBalance[address] = balancesArray[index]
})
return addressToBalance
})
}
module.exports.getBalances = getBalances
// returns hex string of the bytes of the message
// composed from `recipient`, `value` and `transactionHash`
// that is relayed from `foreign` to `home` on withdraw
function createMessage(rawRecipient, rawValue, rawTransactionHash, rawContractAddress) {
const recipient = strip0x(rawRecipient)
assert.equal(recipient.length, 20 * 2)
const value = strip0x(bigNumberToPaddedBytes32(rawValue))
assert.equal(value.length, 64)
const transactionHash = strip0x(rawTransactionHash)
assert.equal(transactionHash.length, 32 * 2)
const contractAddress = strip0x(rawContractAddress)
assert.equal(contractAddress.length, 20 * 2)
const message = `0x${recipient}${value}${transactionHash}${contractAddress}`
const expectedMessageLength = (20 + 32 + 32 + 20) * 2 + 2
assert.equal(message.length, expectedMessageLength)
return message
}
module.exports.createMessage = createMessage
// returns array of integers progressing from `start` up to, but not including, `end`
function range(start, end) {
const result = []
for (let i = start; i < end; i++) {
result.push(i)
}
return result
}
module.exports.range = range
// just used to signal/document that we're explicitely ignoring/expecting an error
function ignoreExpectedError() {}
module.exports.ignoreExpectedError = ignoreExpectedError
const getEvents = (truffleInstance, filter, fromBlock = 0, toBlock = 'latest') =>
truffleInstance.contract.getPastEvents(filter.event, { fromBlock, toBlock })
module.exports.getEvents = getEvents
function ether(n) {
return new BN(web3.utils.toWei(n, 'ether'))
}
module.exports.ether = ether
function expectEventInLogs(logs, eventName, eventArgs = {}) {
const events = logs.filter(e => e.event === eventName)
expect(events.length > 0).to.equal(true, `There is no '${eventName}'`)
const exception = []
const event = events.find(e => {
for (const [k, v] of Object.entries(eventArgs)) {
try {
contains(e.args, k, v)
} catch (error) {
exception.push(error)
return false
}
}
return true
})
if (event === undefined) {
throw exception[0]
}
return event
}
function contains(args, key, value) {
expect(key in args).to.equal(true, `Unknown event argument '${key}'`)
if (value === null) {
expect(args[key]).to.equal(null)
} else if (isBN(args[key])) {
expect(args[key]).to.be.bignumber.equal(value)
} else {
expect(args[key]).to.be.equal(value)
}
}
function isBN(object) {
return BN.isBN(object) || object instanceof BN
}
module.exports.expectEventInLogs = expectEventInLogs
function createAccounts(web3, amount) {
const array = []
for (let i = 0; i < amount; i++) {
array[i] = web3.eth.accounts.create().address
}
return array
}
module.exports.createAccounts = createAccounts
function createFullAccounts(web3, amount) {
const array = []
for (let i = 0; i < amount; i++) {
array[i] = web3.eth.accounts.create()
}
return array
}
module.exports.createFullAccounts = createFullAccounts
async function delay(ms) {
return new Promise(res => setTimeout(res, ms))
}
module.exports.delay = delay
async function evalMetrics(target, ...metrics) {
const before = await Promise.all(metrics.map(metric => metric()))
await target()
const after = await Promise.all(metrics.map(metric => metric()))
return [...before, ...after]
}
module.exports.evalMetrics = evalMetrics
function paymasterError(reason) {
return `paymaster rejected in local view call to 'relayCall()' : ${reason}`
}
module.exports.paymasterError = paymasterError