-
Notifications
You must be signed in to change notification settings - Fork 27
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
add basic cli & devchain cmd #24
Changes from 10 commits
16999d4
189bcad
6febbb1
d971941
2fcfd3b
104927d
9b0df85
46f4d30
2d35910
b745248
3d8ac66
04f67ec
19cc313
8609430
d65f503
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,8 @@ | ||
module.exports = { | ||
// ENS is deterministically deployed to this address | ||
ens: '0x5f6f7e8cc7346a11ca2def8f827b7a0b612c56a1' | ||
} | ||
// ENS is deterministically deployed to this address | ||
ens: '0x5f6f7e8cc7346a11ca2def8f827b7a0b612c56a1', | ||
ConsoleReporter: require('./src/reporters/ConsoleReporter'), | ||
commands: { | ||
devchain: require('./src/commands/devchain'), | ||
}, | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,10 @@ | ||
#!/bin/bash | ||
|
||
BASEPATH="$( dirname "$(dirname "$0")" )" | ||
mnemonic=$(node -p "require(require('path').join(\"${SCRIPTPATH}\", '../src/ganache-vars')).MNEMONIC") | ||
|
||
cd "$BASEPATH" | ||
rm -rf aragon-ganache | ||
mkdir aragon-ganache | ||
set -e; | ||
npx ganache-cli -m "explain tackle mirror kit van hammer degree position ginger unfair soup bonus" -i 15 -l 100000000 --db aragon-ganache | ||
npx ganache-cli -m "${mnemonic}" -i 15 -l 100000000 --db aragon-ganache |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
#!/usr/bin/env node | ||
require('@babel/polyfill') | ||
const ConsoleReporter = require('./reporters/ConsoleReporter') | ||
|
||
// Set up commands | ||
const cmd = require('yargs').commandDir('./commands') | ||
|
||
cmd.alias('h', 'help') | ||
cmd.alias('v', 'version') | ||
|
||
// Configure CLI behavior | ||
cmd.demandCommand(1, 'You need to specify a command') | ||
|
||
// Set global options | ||
cmd.option('silent', { | ||
description: 'Silence output to terminal', | ||
default: false, | ||
}) | ||
|
||
cmd.option('debug', { | ||
description: 'Show more output to terminal', | ||
default: false, | ||
coerce: debug => { | ||
if (debug || process.env.DEBUG) { | ||
global.DEBUG_MODE = true | ||
return true | ||
} | ||
}, | ||
}) | ||
|
||
// APM | ||
cmd.option('apm.ens-registry', { | ||
description: | ||
"Address of the ENS registry. This will be overwritten if the selected '--environment' from your arapp.json includes a `registry` property", | ||
default: require('../index').ens, | ||
}) | ||
cmd.group(['apm.ens-registry'], 'APM:') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We shouldn't include these APM options, since aragen is meant to deploy to a consistent ENS address each time. |
||
|
||
// Run | ||
const reporter = new ConsoleReporter() | ||
// reporter.debug(JSON.stringify(process.argv)) | ||
cmd | ||
.fail((msg, err, yargs) => { | ||
if (!err) yargs.showHelp() | ||
reporter.error(msg || err.message || 'An error occurred') | ||
reporter.debug(err && err.stack) | ||
}) | ||
.parse(process.argv.slice(2), { | ||
reporter, | ||
}) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
const TaskList = require('listr') | ||
const ncp = require('ncp') | ||
const ganache = require('ganache-core') | ||
const Web3 = require('web3') | ||
const { promisify } = require('util') | ||
const os = require('os') | ||
const path = require('path') | ||
const rimraf = require('rimraf') | ||
const mkdirp = require('mkdirp') | ||
const chalk = require('chalk') | ||
const fs = require('fs') | ||
const listrOpts = require('../helpers/listr-options') | ||
const pjson = require('../../package.json') | ||
|
||
const { BLOCK_GAS_LIMIT, MNEMONIC } = require('../helpers/ganache-vars') | ||
|
||
exports.command = 'devchain' | ||
exports.describe = | ||
'Open a test chain for development and pass arguments to ganache' | ||
exports.builder = { | ||
port: { | ||
description: 'The port to run the local chain on', | ||
default: 8545, | ||
}, | ||
reset: { | ||
type: 'boolean', | ||
default: false, | ||
description: 'Reset devchain to snapshot', | ||
}, | ||
accounts: { | ||
default: 2, | ||
description: 'Number of accounts to print', | ||
}, | ||
verbose: { | ||
default: false, | ||
type: 'boolean', | ||
description: 'Enable verbose devchain output', | ||
}, | ||
} | ||
|
||
exports.task = async function({ | ||
port = 8545, | ||
verbose = false, | ||
reset = false, | ||
showAccounts = 2, | ||
reporter, | ||
silent, | ||
debug, | ||
}) { | ||
const removeDir = promisify(rimraf) | ||
const mkDir = promisify(mkdirp) | ||
const recursiveCopy = promisify(ncp) | ||
|
||
const snapshotPath = path.join( | ||
os.homedir(), | ||
`.aragon/ganache-db-${pjson.version}` | ||
) | ||
|
||
const tasks = new TaskList( | ||
[ | ||
{ | ||
title: 'Setting up a new chain from latest Aragon snapshot', | ||
task: async (ctx, task) => { | ||
await removeDir(snapshotPath) | ||
await mkDir(path.resolve(snapshotPath, '..')) | ||
const snapshot = path.join(__dirname, '../../aragon-ganache') | ||
await recursiveCopy(snapshot, snapshotPath) | ||
}, | ||
enabled: () => !fs.existsSync(snapshotPath) || reset, | ||
}, | ||
{ | ||
title: 'Starting a local chain from snapshot', | ||
task: async (ctx, task) => { | ||
const server = ganache.server({ | ||
// Start on a different networkID every time to avoid Metamask nonce caching issue: | ||
// https://github.com/aragon/aragon-cli/issues/156 | ||
network_id: parseInt(1e8 * Math.random()), | ||
gasLimit: BLOCK_GAS_LIMIT, | ||
mnemonic: MNEMONIC, | ||
db_path: snapshotPath, | ||
logger: verbose ? { log: reporter.info.bind(reporter) } : undefined, | ||
}) | ||
const listen = () => | ||
new Promise((resolve, reject) => { | ||
server.listen(port, err => { | ||
if (err) return reject(err) | ||
|
||
task.title = `Local chain started at port ${port}` | ||
resolve() | ||
}) | ||
}) | ||
await listen() | ||
|
||
ctx.web3 = new Web3( | ||
new Web3.providers.WebsocketProvider(`ws://localhost:${port}`) | ||
) | ||
const accounts = await ctx.web3.eth.getAccounts() | ||
|
||
ctx.accounts = accounts.slice(0, parseInt(showAccounts)) | ||
ctx.mnemonic = MNEMONIC | ||
|
||
const ganacheAccounts = server.provider.manager.state.accounts | ||
ctx.privateKeys = ctx.accounts.map(address => ({ | ||
key: ganacheAccounts[address.toLowerCase()].secretKey.toString( | ||
'hex' | ||
), | ||
address, | ||
})) | ||
}, | ||
}, | ||
], | ||
listrOpts(silent, debug) | ||
) | ||
|
||
return tasks | ||
} | ||
|
||
exports.printAccounts = (reporter, privateKeys) => { | ||
const firstAccountComment = | ||
'(this account is used to deploy DAOs, it has more permissions)' | ||
|
||
const formattedAccounts = privateKeys.map( | ||
({ address, key }, i) => | ||
chalk.bold( | ||
`Address #${i + 1}: ${address} ${ | ||
i === 0 ? firstAccountComment : '' | ||
}\nPrivate key: ` | ||
) + key | ||
) | ||
|
||
reporter.info(`Here are some Ethereum accounts you can use. | ||
The first one will be used for all the actions the CLI performs. | ||
You can use your favorite Ethereum provider or wallet to import their private keys. | ||
\n${formattedAccounts.join('\n')}`) | ||
} | ||
|
||
exports.printMnemonic = (reporter, mnemonic) => { | ||
reporter.info( | ||
`The accounts were generated from the following mnemonic phrase:\n${mnemonic}\n` | ||
) | ||
} | ||
|
||
exports.printResetNotice = (reporter, reset) => { | ||
if (reset) { | ||
reporter.warning(`The devchain was reset, some steps need to be done to prevent issues: | ||
- Reset the application cache in Aragon Core by going to Settings > Troubleshooting. | ||
- If using Metamask: switch to a different network, and then switch back to the 'Private Network' (this will clear the nonce cache and prevent errors when sending transactions) | ||
`) | ||
} | ||
} | ||
|
||
exports.handler = async ({ | ||
reporter, | ||
port, | ||
reset, | ||
verbose, | ||
accounts, | ||
apm: apmOptions, | ||
silent, | ||
debug, | ||
}) => { | ||
const task = await exports.task({ | ||
port, | ||
reset, | ||
verbose, | ||
reporter, | ||
showAccounts: accounts, | ||
silent, | ||
debug, | ||
}) | ||
const { privateKeys, mnemonic } = await task.run() | ||
exports.printAccounts(reporter, privateKeys) | ||
exports.printMnemonic(reporter, mnemonic) | ||
exports.printResetNotice(reporter, reset) | ||
|
||
reporter.info(`ENS instance deployed at ${apmOptions['ens-registry']}\n`) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This address should always be |
||
|
||
reporter.info(`Devchain running: ${chalk.bold('http://localhost:' + port)}.`) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
module.exports = { | ||
BLOCK_GAS_LIMIT: 50e6, | ||
MNEMONIC: 'explain tackle mirror kit van hammer degree position ginger unfair soup bonus' | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
const ListrRenderer = require('../reporters/ListrRenderer') | ||
|
||
/** | ||
* https://github.com/SamVerschueren/listr#options | ||
* https://github.com/SamVerschueren/listr-update-renderer#options | ||
* https://github.com/SamVerschueren/listr-verbose-renderer#options | ||
* | ||
* @param {boolean} silent Option silent | ||
* @param {boolean} debug Option debug | ||
* @returns {Object} listr options object | ||
*/ | ||
function listrOpts(silent, debug) { | ||
return { | ||
renderer: ListrRenderer(silent, debug), | ||
dateFormat: false, | ||
} | ||
} | ||
|
||
module.exports = listrOpts |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
const chalk = require('chalk') | ||
const figures = require('figures') | ||
|
||
module.exports = class ConsoleReporter { | ||
constructor(opts = { silent: false }) { | ||
this.silent = opts.silent | ||
} | ||
|
||
message(category = 'info', message) { | ||
if (this.silent) return | ||
|
||
const color = { | ||
debug: 'magenta', | ||
info: 'blue', | ||
warning: 'yellow', | ||
error: 'red', | ||
success: 'green', | ||
}[category] | ||
const symbol = { | ||
debug: figures.pointer, | ||
info: figures.info, | ||
warning: figures.warning, | ||
error: figures.cross, | ||
success: figures.tick, | ||
}[category] | ||
const icon = chalk[color](symbol) | ||
console.log(` ${icon} ${message}`) | ||
} | ||
|
||
debug(message) { | ||
if (global.DEBUG_MODE) this.message('debug', message) | ||
} | ||
|
||
info(message) { | ||
this.message('info', message) | ||
} | ||
|
||
warning(message) { | ||
this.message('warning', message) | ||
} | ||
|
||
error(message) { | ||
this.message('error', message) | ||
} | ||
|
||
success(message) { | ||
this.message('success', message) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
const VerboseRenderer = require('listr-verbose-renderer') | ||
const SilentRenderer = require('listr-silent-renderer') | ||
const UpdateRenderer = require('listr-update-renderer') | ||
|
||
module.exports = function(silent, debug) { | ||
if (debug) return VerboseRenderer | ||
if (silent) return SilentRenderer | ||
return UpdateRenderer | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This still needs to be changed to
BASEPATH
and to remove the../
in../src/..
.