Created
December 31, 2022 19:38
-
-
Save Hero-Development/2922d812d874cd85a2a73c1ee76c4d45 to your computer and use it in GitHub Desktop.
Truffle Deploy script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
npx hardhat compile | |
npx hardhat test | |
truffle deploy --network rinkeby --contract=UntamedMatriarcks | tee notes/UntamedMatriarcks-rinkeby.txt | |
truffle run verify WGMIOwl --network rinkeby | |
truffle deploy --network mainnet --contract=BitBotSociety | |
truffle run verify BitBotSociety --network mainnet | |
*/ | |
const fs = require( "fs" ); | |
const path = require( "path" ); | |
const readline = require("readline"); | |
const log4js = require( "log4js" ); | |
const Web3 = require( "web3" ); | |
let logging = console; | |
class TruffleDeploy{ | |
deployer; | |
constructor( deployer ){ | |
this.deployer = deployer; | |
} | |
compileArgs( argv, contractArgs ){ | |
//TODO: convert to equals | |
//const contractArgs = []; | |
let contractName = null; | |
argv.forEach( arg => { | |
//TODO: TruffleDeploy.isArg( arg ) | |
if( arg.length > 6 && arg.substring( 0, 6 ) === '--arg=' ){ | |
let value = arg.substring( 6 ); | |
//TODO: TruffleDeploy.isQuoted( value ) | |
if( value[0] === '"' && value.substring( value.length - 1 ) === '"' ){ | |
value = arg.substring( 1, arg.length - 2 ); | |
logging.info({ value }); | |
} | |
else if( value[0] === "'" && value.substring( value.length - 1 ) === "'" ){ | |
value = arg.substring( 1, arg.length - 2 ); | |
logging.info({ value }); | |
} | |
//TODO: isHex | |
if( /^0x[0-9A-Fa-f]+$/.test( value ) ){ | |
logging.info( 'bytes arg scalar' ); | |
contractArgs.push( value ); | |
} | |
else if( !isNaN( value ) ){ | |
contractArgs.push( Number( value ) ); | |
} | |
else if( value[0] !== '[' && value[0] !== '{' ){ | |
contractArgs.push( value ); | |
} | |
//TODO: isJSON( value ) | |
else{ | |
try{ | |
const parsed = JSON.parse( value ); | |
logging.info({ 'XXXXXXXXX': (typeof parsed) }); | |
if( typeof parsed === 'object' ){ | |
logging.info( 'arg object' ); | |
contractArgs.push( parsed ); | |
} | |
else{ | |
throw new Error( `Unexpected JSON type: ${typeof parsed}` ); | |
//logging.info( 'arg scalar' ); | |
//contractArgs.push( value ); | |
} | |
} | |
catch( err ){ | |
logging.warn({ err }); | |
throw err; | |
//contractArgs.push( value ); | |
} | |
} | |
} | |
else if( arg.length > 11 && arg.substring( 0, 11 ) === '--contract=' ){ | |
contractName = arg.substring( 11 ); | |
} | |
//TODO: gas | |
//TODO: gasPrice | |
}); | |
return contractName; | |
} | |
compileSources( contract ){ | |
const modPath = path.join( path.dirname( __dirname ), 'node_modules' ); | |
const projPath = path.dirname( __dirname ); | |
//metadata.compiler.version | |
const metadata = JSON.parse( contract._json.metadata ); | |
const jsonInput = {}; | |
jsonInput.language = metadata.language; | |
jsonInput.settings = { | |
//enabled: metadata.settings.optimizer.enabled | |
//runs: metadata.settings.optimizer.runs | |
optimizer: metadata.settings.optimizer | |
}; | |
jsonInput.sources = {}; | |
const append = {}; | |
Object.keys( metadata.sources ).forEach( source => { | |
let modulePath; | |
if( source.startsWith( "project:" ) ){ | |
source = source.substring( 9 ); | |
modulePath = path.join( projPath, source); | |
//logging.info({ projPath, source }); | |
const content = fs.readFileSync( modulePath ).toString( 'utf8' ); | |
jsonInput.sources[ source ] = { content }; | |
} | |
else{ | |
modulePath = path.join( modPath, source ); | |
//logging.info({ source, modulePath }); | |
const content = fs.readFileSync( modulePath ).toString( 'utf8' ); | |
append[ source ] = { content }; | |
} | |
}); | |
for(const [source, content] of Object.entries(append)){ | |
jsonInput.sources[ source ] = content; | |
} | |
return jsonInput; | |
} | |
configure( contractName ){ | |
const dt = new Date(); | |
const rootPath = path.dirname( __dirname ); | |
const deploymentsPath = path.join( rootPath, "deployments" ); | |
if( !fs.existsSync( deploymentsPath ) ){ | |
fs.mkdirSync( deploymentsPath ); | |
} | |
const date = dt.toISOString().substring( 0, 10 ); | |
const datePath = path.join( deploymentsPath, date ); | |
if( !fs.existsSync( datePath ) ){ | |
fs.mkdirSync( datePath ); | |
} | |
const ts = dt.getHours().toString().padStart(2,'0') | |
+dt.getMinutes().toString().padStart(2,'0') | |
+dt.getSeconds().toString().padStart(2,'0'); | |
const tag = `${ts}_${contractName}`; | |
this.deployPath = path.join( datePath, tag ); | |
fs.mkdirSync( this.deployPath ); | |
const logPath = path.join(this.deployPath, "deploy.log"); | |
logging.info({ logPath }); | |
log4js.configure({ | |
disableClustering: true, | |
appenders: { | |
console: { | |
type: "console", | |
layout: { type: "colored" } | |
}, | |
dateFile: { | |
type: "dateFile", | |
filename: logPath, | |
keepFileExt: true, | |
}, | |
}, | |
categories: { | |
default: { | |
appenders: ["console","dateFile"], | |
level: "info", | |
}, | |
}, | |
}); | |
logging = log4js.getLogger("index.ts"); | |
return `${date}/${ts}_${contractName}`; | |
} | |
async confirm( network ){ | |
if( [ 'mainnet', 'polygon' ].includes( network ) ){ | |
const rl = readline.createInterface({ | |
input: process.stdin, | |
output: process.stdout | |
}); | |
const result = await new Promise((resolve, reject) => { | |
rl.question( `Network: ${network}, are you sure? `, res => { | |
rl.close(); | |
if( [ '1', 'y', 'yes' ].includes( res ) ) | |
resolve(true); | |
else | |
reject(new Error("User cancelled deployment")); | |
}) | |
}); | |
logging.info({ result }); | |
return result; | |
} | |
else{ | |
return true; | |
} | |
} | |
getNetworkInfo( deployer ){ | |
const network = deployer.networks[ deployer.network ]; | |
//HDWalletProvider | |
//console.warn({ "network.provider": network.provider() }); | |
const { network_id, from } = network; | |
const { gas, gasPrice, maxFeePerGas, maxPriorityFeePerGas } = deployer.options; | |
return { | |
from, | |
network_id, | |
gas, | |
gasPrice, | |
maxFeePerGas, | |
maxPriorityFeePerGas | |
}; | |
} | |
static async process( deployer ){ | |
const contractArgs = []; | |
const deploy = new TruffleDeploy( deployer ); | |
const contractName = deploy.compileArgs( process.argv, contractArgs ); | |
if( !contractName ) | |
throw new Error( 'No --contract specified' ); | |
const tag = deploy.configure( contractName ); | |
const networkInfo = deploy.getNetworkInfo( deployer ); | |
logging.info({ networkInfo }); | |
if( await deploy.confirm( deployer.network )){ | |
let contract; | |
try{ | |
logging.info( `Require contract '${contractName}'...` ); | |
contract = artifacts.require( contractName ); | |
} | |
catch( err ){ | |
logging.warn( String( err ) ); | |
logging.warn( `*********** is contract '${contractName}' missing? ***********` ); | |
return; | |
} | |
logging.info( `1) Saving ${tag}/verify.json...` ); | |
const jsonInput = deploy.compileSources( contract ); | |
fs.writeFileSync( path.join( deploy.deployPath, "verify.json" ), JSON.stringify( jsonInput, null, 2 )); | |
logging.info( `2) Saving ${tag}/${contractName}-abi.json...` ); | |
fs.writeFileSync( path.join( deploy.deployPath, `${contractName}-abi.json` ), JSON.stringify(contract._json.abi) ); | |
const argStr = contractArgs.length ? | |
' '+ contractArgs.join( ', ' ) +' ': ''; | |
logging.info( `3) Deploying ${contractName}(${argStr}) to network '${deployer.network}'...` ); | |
const truffleContract = await deployer.deploy( contract, ...contractArgs ); | |
//console.info({ "truffleContract.contract": truffleContract.contract }); | |
//truffleContract.address = '0xF432867ECe7C3297a0DEb01eFEB3026497A958b1'; | |
//truffleContract.transactionHash = '0xdd57b44db0511e3704d816c09a6487eaef778cc5d592aaf24d11479b6b05a14d'; | |
logging.info( `4) Waiting for confirmation...` ); | |
await contract.deployed(); | |
//const truffleContract2 = await contract.deployed(); | |
//truffleContract2.address = '0xF432867ECe7C3297a0DEb01eFEB3026497A958b1'; | |
//truffleContract2.transactionHash = '0xdd57b44db0511e3704d816c09a6487eaef778cc5d592aaf24d11479b6b05a14d'; | |
const network = contract._json.networks[ networkInfo.network_id ]; | |
//network.address | |
//network.transactionHash | |
logging.info( `...contract '${contractName}' deployed to address '${network.address}'!` ); | |
//HDWalletProvider | |
const web3 = new Web3( truffleContract.contract.currentProvider ); | |
//has input Data | |
//const txn = await web3.eth.getTransaction( truffleContract.transactionHash ); | |
const reciept = await web3.eth.getTransactionReceipt( truffleContract.transactionHash ); | |
console.warn({ reciept }); | |
//receipt.gasUsed: 3446842, | |
//TODO: prompt for verification? | |
//const network = contract._json.networks[ network_id ]; | |
//logging.info( contract._json.networks ); | |
//return; | |
} | |
} | |
} | |
module.exports = TruffleDeploy.process; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment