Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve checks of configuration parameters for contracts deployment #228

Merged
merged 5 commits into from
Jul 15, 2019
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions deploy/deploy.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ const { BRIDGE_MODE, ERC20_TOKEN_ADDRESS } = env
const deployResultsPath = path.join(__dirname, './bridgeDeploymentResults.json')

async function deployNativeToErc() {
const preDeploy = require('./src/native_to_erc/preDeploy')
const deployHome = require('./src/native_to_erc/home')
const deployForeign = require('./src/native_to_erc/foreign')

await preDeploy()
const { homeBridge } = await deployHome()
const { foreignBridge, erc677 } = await deployForeign()
console.log('\nDeployment has been completed.\n\n')
Expand Down Expand Up @@ -79,9 +80,10 @@ async function deployErcToErc() {
}

async function deployErcToNative() {
const preDeploy = require('./src/erc_to_native/preDeploy')
const deployHome = require('./src/erc_to_native/home')
const deployForeign = require('./src/erc_to_native/foreign')

await preDeploy()
const { homeBridge } = await deployHome()
const { foreignBridge } = await deployForeign()
console.log('\nDeployment has been completed.\n\n')
Expand Down
8 changes: 7 additions & 1 deletion deploy/src/deploymentUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,11 @@ function getSendTxMethod(url) {
return url === HOME_RPC_URL ? sendRawTxHome : sendRawTxForeign
}

async function isContract(web3, address) {
const code = await web3.eth.getCode(address)
return code !== '0x' && code !== '0x0'
}

module.exports = {
deployContract,
sendRawTxHome,
Expand All @@ -307,5 +312,6 @@ module.exports = {
transferProxyOwnership,
transferOwnership,
setBridgeContract,
assertStateWithRetry
assertStateWithRetry,
isContract
}
31 changes: 29 additions & 2 deletions deploy/src/erc_to_erc/preDeploy.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,39 @@
const { web3Foreign } = require('../web3')
const { ERC20_TOKEN_ADDRESS, ERC20_EXTENDED_BY_ERC677 } = require('../loadEnv')
const { web3Home, web3Foreign } = require('../web3')
const {
ERC20_TOKEN_ADDRESS,
ERC20_EXTENDED_BY_ERC677,
HOME_REWARDABLE,
BLOCK_REWARD_ADDRESS,
DEPLOY_REWARDABLE_TOKEN,
DPOS_STAKING_ADDRESS
} = require('../loadEnv')
const { isContract } = require('../deploymentUtils')
const {
foreignContracts: {
ERC677BridgeToken: { abi }
}
} = require('../loadContracts')

async function preDeploy() {
const isERC20AContract = await isContract(web3Foreign, ERC20_TOKEN_ADDRESS)
if (!isERC20AContract) {
throw new Error(`ERC20_TOKEN_ADDRESS should be a contract address`)
}

if (DEPLOY_REWARDABLE_TOKEN) {
const isDPOSStakingAContract = await isContract(web3Foreign, DPOS_STAKING_ADDRESS)
if (!isDPOSStakingAContract) {
throw new Error(`DPOS_STAKING_ADDRESS should be a contract address`)
}
}

if (HOME_REWARDABLE === 'BOTH_DIRECTIONS') {
const isBlockRewardAContract = await isContract(web3Home, BLOCK_REWARD_ADDRESS)
if (!isBlockRewardAContract) {
throw new Error(`BLOCK_REWARD_ADDRESS should be a contract address`)
}
}

if (ERC20_EXTENDED_BY_ERC677) {
const tokenContract = new web3Foreign.eth.Contract(abi, ERC20_TOKEN_ADDRESS)
try {
Expand Down
12 changes: 12 additions & 0 deletions deploy/src/erc_to_native/preDeploy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const { web3Foreign } = require('../web3')
const { ERC20_TOKEN_ADDRESS } = require('../loadEnv')
const { isContract } = require('../deploymentUtils')

async function preDeploy() {
const isERC20AContract = await isContract(web3Foreign, ERC20_TOKEN_ADDRESS)
if (!isERC20AContract) {
throw new Error(`ERC20_TOKEN_ADDRESS should be a contract address`)
}
}

module.exports = preDeploy
167 changes: 124 additions & 43 deletions deploy/src/loadEnv.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ const { isAddress, toBN } = require('web3').utils
const envalid = require('envalid')
const { ZERO_ADDRESS, EVM_TYPES } = require('./constants')

const homePrefix = 'HOME'
const foreignPrefix = 'FOREIGN'

// Validations and constants
const evmVersions = [EVM_TYPES.BYZANTIUM, EVM_TYPES.SPURIOUSDRAGON]
const validBridgeModes = ['NATIVE_TO_ERC', 'ERC_TO_ERC', 'ERC_TO_NATIVE']
Expand Down Expand Up @@ -34,6 +37,36 @@ const validateRewardableAddresses = (validators, rewards) => {
}
}

function checkValidators(validators, requiredValidators) {
if (validators.split(' ').length < requiredValidators) {
throw new Error(
`The number of validators VALIDATORS = ${
validators.split(' ').length
} should be bigger or equal the number of required signatures REQUIRED_NUMBER_OF_VALIDATORS = ${requiredValidators} .`
)
}
}

function checkGasPrices(gasPrice, prefix) {
if (gasPrice.isZero()) {
throw new Error(`${prefix}_GAS_PRICE should be bigger than zero.`)
akolotov marked this conversation as resolved.
Show resolved Hide resolved
}
}

function checkBlockConfirmations(confirmations, prefix) {
if (confirmations <= 0) {
throw new Error(`${prefix}_REQUIRED_BLOCK_CONFIRMATIONS should be bigger than zero.`)
}
}

function checkLimits(min, max, daily, prefix) {
if (min.isZero() || min.gte(max) || max.gte(daily)) {
throw new Error(
`Limit parameters should be defined as 0 < ${prefix}_MIN_AMOUNT_PER_TX < ${prefix}_MAX_AMOUNT_PER_TX < ${prefix}_DAILY_LIMIT`
)
}
}

const {
BRIDGE_MODE,
HOME_REWARDABLE,
Expand All @@ -47,6 +80,8 @@ const {
FOREIGN_EVM_VERSION
} = process.env

// Types validations

if (HOME_EVM_VERSION) {
if (!evmVersions.includes(HOME_EVM_VERSION)) {
throw new Error(
Expand Down Expand Up @@ -101,6 +136,7 @@ let validations = {
FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS: envalid.num(),
FOREIGN_GAS_PRICE: bigNumValidator(),
FOREIGN_MAX_AMOUNT_PER_TX: bigNumValidator(),
FOREIGN_DAILY_LIMIT: bigNumValidator(),
REQUIRED_NUMBER_OF_VALIDATORS: envalid.num(),
VALIDATORS: addressesValidator()
}
Expand All @@ -111,10 +147,8 @@ if (BRIDGE_MODE === 'NATIVE_TO_ERC') {
BRIDGEABLE_TOKEN_NAME: envalid.str(),
BRIDGEABLE_TOKEN_SYMBOL: envalid.str(),
BRIDGEABLE_TOKEN_DECIMALS: envalid.num(),
FOREIGN_DAILY_LIMIT: bigNumValidator(),
FOREIGN_MIN_AMOUNT_PER_TX: bigNumValidator(),
DEPLOY_REWARDABLE_TOKEN: envalid.bool(),
BLOCK_REWARD_ADDRESS: addressValidator()
DEPLOY_REWARDABLE_TOKEN: envalid.bool()
akolotov marked this conversation as resolved.
Show resolved Hide resolved
}

if (DEPLOY_REWARDABLE_TOKEN === 'true') {
Expand All @@ -123,19 +157,8 @@ if (BRIDGE_MODE === 'NATIVE_TO_ERC') {
DPOS_STAKING_ADDRESS: addressValidator()
}
}

if (FOREIGN_REWARDABLE === 'BOTH_DIRECTIONS') {
throw new Error(
`FOREIGN_REWARDABLE: ${FOREIGN_REWARDABLE} is not supported on ${BRIDGE_MODE} bridge mode`
)
}

if (HOME_REWARDABLE === 'BOTH_DIRECTIONS' && FOREIGN_REWARDABLE === 'ONE_DIRECTION') {
throw new Error(
`Combination of HOME_REWARDABLE: ${HOME_REWARDABLE} and FOREIGN_REWARDABLE: ${FOREIGN_REWARDABLE} should be avoided on ${BRIDGE_MODE} bridge mode.`
)
}
}

if (BRIDGE_MODE === 'ERC_TO_ERC') {
validations = {
...validations,
Expand All @@ -144,25 +167,25 @@ if (BRIDGE_MODE === 'ERC_TO_ERC') {
BRIDGEABLE_TOKEN_SYMBOL: envalid.str(),
BRIDGEABLE_TOKEN_DECIMALS: envalid.num(),
DEPLOY_REWARDABLE_TOKEN: envalid.bool(),
DPOS_STAKING_ADDRESS: addressValidator(),
BLOCK_REWARD_ADDRESS: addressValidator(),
akolotov marked this conversation as resolved.
Show resolved Hide resolved
ERC20_EXTENDED_BY_ERC677: envalid.bool()
}

if (ERC20_EXTENDED_BY_ERC677 === 'true') {
validations = {
...validations,
FOREIGN_DAILY_LIMIT: bigNumValidator(),
FOREIGN_MIN_AMOUNT_PER_TX: bigNumValidator()
}
}

if (FOREIGN_REWARDABLE !== 'false') {
throw new Error(
`Collecting fees on Foreign Network on ${BRIDGE_MODE} bridge mode is not supported.`
)
if (DEPLOY_REWARDABLE_TOKEN === 'true') {
validations = {
...validations,
DPOS_STAKING_ADDRESS: addressValidator()
}
}
}

if (BRIDGE_MODE === 'ERC_TO_NATIVE') {
validations = {
...validations,
Expand All @@ -171,6 +194,86 @@ if (BRIDGE_MODE === 'ERC_TO_NATIVE') {
default: ZERO_ADDRESS
})
}
}

if (HOME_REWARDABLE !== 'false' || FOREIGN_REWARDABLE !== 'false') {
validateRewardableAddresses(VALIDATORS, VALIDATORS_REWARD_ACCOUNTS)
validations = {
...validations,
VALIDATORS_REWARD_ACCOUNTS: addressesValidator(),
HOME_TRANSACTIONS_FEE: envalid.num(),
FOREIGN_TRANSACTIONS_FEE: envalid.num()
}
}

const env = envalid.cleanEnv(process.env, validations)

// Logic validations
checkValidators(env.VALIDATORS, env.REQUIRED_NUMBER_OF_VALIDATORS)
checkGasPrices(env.HOME_GAS_PRICE, homePrefix)
checkGasPrices(env.FOREIGN_GAS_PRICE, foreignPrefix)
checkBlockConfirmations(env.HOME_REQUIRED_BLOCK_CONFIRMATIONS, homePrefix)
checkBlockConfirmations(env.FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS, foreignPrefix)
checkLimits(
env.HOME_MIN_AMOUNT_PER_TX,
env.HOME_MAX_AMOUNT_PER_TX,
env.HOME_DAILY_LIMIT,
homePrefix
)

if (env.BRIDGE_MODE === 'NATIVE_TO_ERC') {
checkLimits(
env.FOREIGN_MIN_AMOUNT_PER_TX,
env.FOREIGN_MAX_AMOUNT_PER_TX,
env.FOREIGN_DAILY_LIMIT,
foreignPrefix
)
if (env.FOREIGN_REWARDABLE === 'BOTH_DIRECTIONS') {
throw new Error(
`FOREIGN_REWARDABLE: ${env.FOREIGN_REWARDABLE} is not supported on ${
env.BRIDGE_MODE
} bridge mode`
)
}

if (env.HOME_REWARDABLE === 'BOTH_DIRECTIONS' && env.FOREIGN_REWARDABLE === 'ONE_DIRECTION') {
throw new Error(
`Combination of HOME_REWARDABLE: ${env.HOME_REWARDABLE} and FOREIGN_REWARDABLE: ${
env.FOREIGN_REWARDABLE
} should be avoided on ${env.BRIDGE_MODE} bridge mode.`
)
}
}

if (env.BRIDGE_MODE === 'ERC_TO_ERC') {
if (env.ERC20_EXTENDED_BY_ERC677) {
checkLimits(
env.FOREIGN_MIN_AMOUNT_PER_TX,
env.FOREIGN_MAX_AMOUNT_PER_TX,
env.FOREIGN_DAILY_LIMIT,
foreignPrefix
)
} else if (env.FOREIGN_MAX_AMOUNT_PER_TX.gte(env.FOREIGN_DAILY_LIMIT)) {
throw new Error(`FOREIGN_DAILY_LIMIT should be greater than FOREIGN_MAX_AMOUNT_PER_TX`)
}

if (env.HOME_REWARDABLE === 'BOTH_DIRECTIONS' && env.BLOCK_REWARD_ADDRESS === ZERO_ADDRESS) {
throw new Error(
'Collecting fees on Home Network on ERC_TO_ERC mode without Block Reward contract is not supported.'
)
}

if (env.FOREIGN_REWARDABLE !== 'false') {
throw new Error(
`Collecting fees on Foreign Network on ${env.BRIDGE_MODE} bridge mode is not supported.`
)
}
}

if (env.BRIDGE_MODE === 'ERC_TO_NATIVE') {
if (env.FOREIGN_MAX_AMOUNT_PER_TX.gte(env.FOREIGN_DAILY_LIMIT)) {
throw new Error(`FOREIGN_DAILY_LIMIT should be greater than FOREIGN_MAX_AMOUNT_PER_TX`)
}

if (HOME_REWARDABLE === 'ONE_DIRECTION') {
throw new Error(
Expand All @@ -193,26 +296,4 @@ if (BRIDGE_MODE === 'ERC_TO_NATIVE') {
}
}

if (HOME_REWARDABLE !== 'false' || FOREIGN_REWARDABLE !== 'false') {
validateRewardableAddresses(VALIDATORS, VALIDATORS_REWARD_ACCOUNTS)
validations = {
...validations,
VALIDATORS_REWARD_ACCOUNTS: addressesValidator(),
HOME_TRANSACTIONS_FEE: envalid.num(),
FOREIGN_TRANSACTIONS_FEE: envalid.num()
}
}

const env = envalid.cleanEnv(process.env, validations)

if (
env.BRIDGE_MODE === 'ERC_TO_ERC' &&
env.HOME_REWARDABLE === 'true' &&
env.BLOCK_REWARD_ADDRESS === ZERO_ADDRESS
) {
throw new Error(
'Collecting fees on Home Network on ERC_TO_ERC mode without Block Reward contract is not supported.'
)
}

module.exports = env
14 changes: 14 additions & 0 deletions deploy/src/native_to_erc/preDeploy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const { web3Foreign } = require('../web3')
const { DEPLOY_REWARDABLE_TOKEN, DPOS_STAKING_ADDRESS } = require('../loadEnv')
const { isContract } = require('../deploymentUtils')

async function preDeploy() {
if (DEPLOY_REWARDABLE_TOKEN) {
const isDPOSStakingAContract = await isContract(web3Foreign, DPOS_STAKING_ADDRESS)
if (!isDPOSStakingAContract) {
throw new Error(`DPOS_STAKING_ADDRESS should be a contract address`)
}
}
}

module.exports = preDeploy