@andylu1988/matic-cli
Version:
A CLI to setup and manage Matic validator nodes
207 lines (180 loc) • 6.02 kB
JavaScript
import Listr from 'listr'
import execa from 'execa'
import chalk from 'chalk'
import inquirer from 'inquirer'
import path from 'path'
import fs from 'fs'
import { projectInstall } from 'pkg-install'
import { isValidAddress } from 'ethereumjs-util'
import { loadConfig } from '../config'
import { cloneRepository } from '../../lib/utils'
import { printDependencyInstructions } from '../helper'
// balance
const DEFAULT_BALANCE = 1000
export class Genesis {
constructor(config, options = {}) {
this.config = config
this.repositoryName = this.name
this.repositoryBranch = options.repositoryBranch || 'master'
//this.repositoryUrl = options.repositoryUrl || 'http://luxueqing:123456Aa@39.106.174.213/BitTorrentChain/genesis-contracts.git'
this.repositoryUrl = options.repositoryUrl || 'https://github.com/maticnetwork/genesis-contracts.git'
this.maticContractsRepository = 'matic-contracts'
this.maticContractsRepositoryUrl = 'https://github.com/maticnetwork/BitTorrentChain/contracts.git'
}
get name() {
return 'genesis-contracts'
}
get taskTitle() {
return 'Setup genesis contracts'
}
get repositoryDir() {
return path.join(this.config.codeDir, this.repositoryName)
}
get maticContractDir() {
return path.join(this.config.codeDir, this.repositoryName, this.maticContractsRepository)
}
get borGenesisFilePath() {
return path.join(this.repositoryDir, 'genesis.json')
}
async print() {
console.log(chalk.gray('Bor genesis path') + ': ' + chalk.bold.green(this.borGenesisFilePath))
}
// get genesis contact tasks
async getTasks() {
return new Listr(
[
{
title: 'Clone genesis-contracts repository',
task: () => cloneRepository(this.repositoryName, this.repositoryBranch, this.repositoryUrl, this.config.codeDir)
},
{
title: 'Install dependencies for genesis-contracts',
task: () => projectInstall({
cwd: this.repositoryDir
})
},
{
title: 'Setting up sub-modules',
task: () => execa('git', ['submodule', 'init'], {
cwd: this.repositoryDir
})
},
{
title: 'Update sub-modules',
task: () => execa('git', ['submodule', 'update'], {
cwd: this.repositoryDir
})
},
{
title: 'Install dependencies for matic-contracts',
task: () => projectInstall({
cwd: this.maticContractDir
})
},
{
title: 'Process templates',
task: () => execa('npm', ['run', 'template:process', '--', '--bor-chain-id', this.config.borChainId], {
cwd: this.maticContractDir
})
},
{
title: 'Compile matic-contracts',
task: () => execa('npm', ['run', 'truffle:compile'], {
cwd: this.maticContractDir
})
},
{
title: 'Prepare validators for genesis file',
task: () => {
const validators = this.config.genesisAddresses.map(a => {
return {
address: a,
stake: this.config.defaultStake, // without 10^18
balance: DEFAULT_BALANCE // without 10^18
}
})
return Promise.resolve().then(() => {
// check if validators js exists
const validatorJsPath = path.join(this.repositoryDir, 'validators.js')
if (!fs.existsSync(validatorJsPath)) {
return
}
// take validator js backup
return execa('mv', ['validators.js', 'validators.js.backup'], {
cwd: this.repositoryDir
})
}).then(() => {
fs.writeFileSync(path.join(this.repositoryDir, 'validators.json'), JSON.stringify(validators, null, 2), 'utf8')
})
}
},
{
title: 'Generate Bor validator set',
task: () => execa('node', [
'generate-borvalidatorset.js', '--bor-chain-id', this.config.borChainId, '--heimdall-chain-id', this.config.heimdallChainId
], {
cwd: this.repositoryDir
})
},
{
title: 'Generate genesis.json',
task: () => execa('node', [
'generate-genesis.js', '--bor-chain-id', this.config.borChainId, '--heimdall-chain-id', this.config.heimdallChainId
], {
cwd: this.repositoryDir
})
}
],
{
exitOnError: true
}
)
}
}
export async function getGenesisAddresses() {
const answers = await inquirer.prompt([
{
type: 'input',
name: 'genesisAddresses',
message: 'Please enter comma separated validator addresses',
default: '0x6c468CF8c9879006E22EC4029696E005C2319C9D',
validate: (input) => {
const addrs = input.split(',').map(a => {
return a.trim().toLowerCase()
}).filter(a => {
return isValidAddress(a)
})
// check if addrs has any valid address
if (addrs.length === 0) {
return 'Enter valid addresses (comma separated)'
}
return true
}
}
])
// set genesis addresses
return answers.genesisAddresses.split(',').map(a => {
return a.trim().toLowerCase()
})
}
async function setupGenesis(config) {
const genesis = new Genesis(config)
// load genesis addresses
config.genesisAddresses = await getGenesisAddresses()
// get all genesis related tasks
const tasks = await genesis.getTasks()
// run all tasks
await tasks.run()
console.log('%s Genesis file is ready', chalk.green.bold('DONE'))
// print genesis path
await genesis.print()
return true
}
export default async function () {
await printDependencyInstructions()
// configuration
const config = await loadConfig()
await config.loadChainIds()
// start setup
await setupGenesis(config)
}