|
|
|
import async from 'async'
|
|
|
|
import { execution } from '@remix-project/remix-lib'
|
|
|
|
import Web3 from 'web3'
|
|
|
|
import { compilationInterface } from './types'
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @dev Deploy all contracts from compilation result
|
|
|
|
* @param compileResult compilation result
|
|
|
|
* @param web3 web3 object
|
|
|
|
* @param withDoubleGas If true, try deployment with gas double of estimation (used for Out-of-gas error only)
|
|
|
|
* @param callback Callback
|
|
|
|
*/
|
|
|
|
|
|
|
|
export function deployAll (compileResult: compilationInterface, web3: Web3, withDoubleGas: boolean, callback) {
|
|
|
|
const compiledObject = {}
|
|
|
|
const contracts = {}
|
|
|
|
let accounts: string[] = []
|
|
|
|
|
|
|
|
async.waterfall([
|
|
|
|
function getAccountList (next) {
|
|
|
|
web3.eth.getAccounts((_err, _accounts) => {
|
|
|
|
accounts = _accounts
|
|
|
|
next()
|
|
|
|
})
|
|
|
|
},
|
|
|
|
function getContractData (next) {
|
|
|
|
for (const contractFile in compileResult) {
|
|
|
|
for (const contractName in compileResult[contractFile]) {
|
|
|
|
const contract = compileResult[contractFile][contractName]
|
|
|
|
|
|
|
|
const className = contractName
|
|
|
|
const filename = contractFile
|
|
|
|
|
|
|
|
const abi = contract.abi
|
|
|
|
const code = contract.evm.bytecode.object
|
|
|
|
|
|
|
|
compiledObject[className] = {}
|
|
|
|
compiledObject[className].abi = abi
|
|
|
|
compiledObject[className].code = code
|
|
|
|
compiledObject[className].filename = filename
|
|
|
|
compiledObject[className].className = className
|
|
|
|
compiledObject[className].raw = contract
|
|
|
|
|
|
|
|
if (contractFile.endsWith('_test.sol')) {
|
|
|
|
compiledObject[className].isTest = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
next()
|
|
|
|
},
|
|
|
|
function determineContractsToDeploy (next) {
|
|
|
|
const contractsToDeploy: string[] = ['Assert']
|
|
|
|
const allContracts = Object.keys(compiledObject)
|
|
|
|
|
|
|
|
for (const contractName of allContracts) {
|
|
|
|
if (contractName === 'Assert') {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if (compiledObject[contractName].isTest) {
|
|
|
|
contractsToDeploy.push(contractName)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
next(null, contractsToDeploy)
|
|
|
|
},
|
|
|
|
function deployContracts (contractsToDeploy: string[], next) {
|
|
|
|
const deployRunner = (deployObject, contractObject, contractName, filename, callback) => {
|
|
|
|
deployObject.estimateGas().then((gasValue) => {
|
|
|
|
const gasBase = Math.ceil(gasValue * 1.2)
|
|
|
|
const gas = withDoubleGas ? gasBase * 2 : gasBase
|
|
|
|
deployObject.send({
|
|
|
|
from: accounts[0],
|
|
|
|
gas: gas
|
|
|
|
}).on('receipt', function (receipt) {
|
|
|
|
contractObject.options.address = receipt.contractAddress
|
|
|
|
contractObject.options.from = accounts[0]
|
|
|
|
contractObject.options.gas = 5000 * 1000
|
|
|
|
compiledObject[contractName].deployedAddress = receipt.contractAddress
|
|
|
|
|
|
|
|
contracts[contractName] = contractObject
|
|
|
|
contracts[contractName].filename = filename
|
|
|
|
|
|
|
|
callback(null, { receipt: { contractAddress: receipt.contractAddress } }) // TODO this will only work with JavaScriptV VM
|
|
|
|
}).on('error', function (err) {
|
|
|
|
console.error(err)
|
|
|
|
callback(err)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
async.eachOfLimit(contractsToDeploy, 1, function (contractName, index, nextEach) {
|
|
|
|
const contract = compiledObject[contractName]
|
|
|
|
const encodeDataFinalCallback = (error, contractDeployData) => {
|
|
|
|
if (error) return nextEach(error)
|
|
|
|
const contractObject = new web3.eth.Contract(contract.abi)
|
|
|
|
const deployObject = contractObject.deploy({ arguments: [], data: '0x' + contractDeployData.dataHex })
|
|
|
|
deployRunner(deployObject, contractObject, contractName, contract.filename, (error) => { nextEach(error) })
|
|
|
|
}
|
|
|
|
|
|
|
|
const encodeDataStepCallback = (msg) => { console.dir(msg) }
|
|
|
|
|
|
|
|
const encodeDataDeployLibraryCallback = (libData, callback) => {
|
|
|
|
const abi = compiledObject[libData.data.contractName].abi
|
|
|
|
const code = compiledObject[libData.data.contractName].code
|
|
|
|
const libraryObject = new web3.eth.Contract(abi)
|
|
|
|
const deployObject = libraryObject.deploy({ arguments: [], data: '0x' + code })
|
|
|
|
deployRunner(deployObject, libraryObject, libData.data.contractName, contract.filename, callback)
|
|
|
|
}
|
|
|
|
|
|
|
|
const funAbi = null // no need to set the abi for encoding the constructor
|
|
|
|
const params = '' // we suppose that the test contract does not have any param in the constructor
|
|
|
|
execution.txFormat.encodeConstructorCallAndDeployLibraries(contractName, contract.raw, compileResult, params, funAbi, encodeDataFinalCallback, encodeDataStepCallback, encodeDataDeployLibraryCallback)
|
|
|
|
}, function (err) {
|
|
|
|
if (err) next(err)
|
|
|
|
next(null, contracts)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
], callback)
|
|
|
|
}
|