fcoin/bin/cli
2016-12-19 08:04:30 -08:00

698 lines
18 KiB
JavaScript
Executable File

#!/usr/bin/env node
'use strict';
var config = require('../lib/node/config');
var util = require('../lib/utils/util');
var co = require('../lib/utils/co');
var Client = require('../lib/http/client');
var Wallet = require('../lib/http/wallet');
var Amount = require('../lib/btc/amount');
var main;
function CLI() {
this.config = config({
config: true,
arg: true,
env: true,
network: 'main'
}).data;
this.argv = this.config.args;
this.client = null;
this.wallet = null;
}
CLI.prototype.log = function log(json) {
if (typeof json === 'string')
return console.log.apply(console, arguments);
console.log(JSON.stringify(json, null, 2));
};
CLI.prototype.getInfo = co(function* getInfo() {
var info = yield this.client.getInfo();
this.log(info);
});
CLI.prototype.getWallets = co(function* getWallets() {
var wallets = yield this.client.getWallets();
this.log(wallets);
});
CLI.prototype.createWallet = co(function* createWallet() {
var options = { id: this.argv[0] };
var wallet;
if (this.config.type)
options.type = this.config.type;
if (this.config.master)
options.master = this.config.master;
if (this.config.mnemonic)
options.master = this.config.mnemonic;
if (this.config.m)
options.m = this.config.m >>> 0;
if (this.config.n)
options.n = this.config.n >>> 0;
if (this.config.witness != null)
options.witness = !!this.config.witness;
if (this.config.passphrase)
options.passphrase = this.config.passphrase;
if (this.config.watch) {
options.watchOnly = true;
options.accountKey = this.config.watch;
}
wallet = yield this.client.createWallet(options);
this.log(wallet);
});
CLI.prototype.getMaster = co(function* getMaster() {
var master = yield this.wallet.getMaster();
this.log(master);
});
CLI.prototype.getKey = co(function* getKey() {
var address = this.argv[0];
var key = yield this.wallet.getKey(address);
this.log(key);
});
CLI.prototype.getWIF = co(function* getWIF() {
var address = this.argv[0];
var key = yield this.wallet.getWIF(address, this.config.passphrase);
this.log(key.privateKey);
});
CLI.prototype.addSharedKey = co(function* addSharedKey() {
var key = this.argv[0];
yield this.wallet.addSharedKey(this.config.account, key);
this.log('Added key.');
});
CLI.prototype.removeSharedKey = co(function* removeSharedKey() {
var key = this.argv[0];
yield this.wallet.removeSharedKey(this.config.account, key);
this.log('Removed key.');
});
CLI.prototype.getSharedKeys = co(function* getSharedKeys() {
var acct = this.argv[0] || this.config.account;
var account = yield this.wallet.getAccount(acct);
this.log(account.keys);
});
CLI.prototype.getAccount = co(function* getAccount() {
var acct = this.argv[0] || this.config.account;
var account = yield this.wallet.getAccount(acct);
this.log(account);
});
CLI.prototype.createAccount = co(function* createAccount() {
var options = { name: this.argv[0] };
var account;
if (this.config.type)
options.type = this.config.type;
if (this.config.m)
options.m = this.config.m >>> 0;
if (this.config.n)
options.n = this.config.n >>> 0;
if (this.config.witness != null)
options.witness = !!this.config.witness;
if (this.config.watch)
options.accountKey = this.config.watch;
account = yield this.wallet.createAccount(options);
this.log(account);
});
CLI.prototype.createAddress = co(function* createAddress() {
var account = this.argv[0];
var addr = yield this.wallet.createAddress(account);
this.log(addr);
});
CLI.prototype.createChange = co(function* createChange() {
var account = this.argv[0];
var addr = yield this.wallet.createChange(account);
this.log(addr);
});
CLI.prototype.createNested = co(function* createNested() {
var account = this.argv[0];
var addr = yield this.wallet.createNested(account);
this.log(addr);
});
CLI.prototype.getAccounts = co(function* getAccounts() {
var accounts = yield this.wallet.getAccounts();
this.log(accounts);
});
CLI.prototype.getWallet = co(function* getWallet() {
var info = yield this.wallet.getInfo();
this.log(info);
});
CLI.prototype.getTX = co(function* getTX() {
var hash = this.argv[0];
var txs, tx;
if (util.isBase58(hash)) {
txs = yield this.client.getTXByAddress(hash);
this.log(txs);
return;
}
tx = yield this.client.getTX(hash);
if (!tx) {
this.log('TX not found.');
return;
}
this.log(tx);
});
CLI.prototype.getBlock = co(function* getBlock() {
var hash = this.argv[0];
var block;
if (hash.length !== 64)
hash = +hash;
block = yield this.client.getBlock(hash);
if (!block) {
this.log('Block not found.');
return;
}
this.log(block);
});
CLI.prototype.getCoin = co(function* getCoin() {
var hash = this.argv[0];
var index = this.argv[1];
var coins, coin;
if (util.isBase58(hash)) {
coins = yield this.client.getCoinsByAddress(hash);
this.log(coins);
return;
}
coin = yield this.client.getCoin(hash, index);
if (!coin) {
this.log('Coin not found.');
return;
}
this.log(coin);
});
CLI.prototype.getWalletHistory = co(function* getWalletHistory() {
var txs = yield this.wallet.getHistory(this.config.account);
this.log(txs);
});
CLI.prototype.getWalletPending = co(function* getWalletPending() {
var txs = yield this.wallet.getPending(this.config.account);
this.log(txs);
});
CLI.prototype.getWalletCoins = co(function* getWalletCoins() {
var coins = yield this.wallet.getCoins(this.config.account);
this.log(coins);
});
CLI.prototype.listenWallet = co(function* listenWallet() {
var self = this;
yield this.wallet.open();
this.wallet.on('tx', function(details) {
self.log('TX:');
self.log(details);
});
this.wallet.on('confirmed', function(details) {
self.log('TX confirmed:');
self.log(details);
});
this.wallet.on('unconfirmed', function(details) {
self.log('TX unconfirmed:');
self.log(details);
});
this.wallet.on('conflict', function(details) {
self.log('TX conflict:');
self.log(details);
});
this.wallet.on('address', function(receive) {
self.log('New addresses allocated:');
self.log(receive);
});
this.wallet.on('balance', function(balance) {
self.log('Balance:');
self.log(balance);
});
return yield this.wallet.onDisconnect();
});
CLI.prototype.getBalance = co(function* getBalance() {
var balance = yield this.wallet.getBalance(this.config.account);
this.log(balance);
});
CLI.prototype.getMempool = co(function* getMempool() {
var txs = yield this.client.getMempool();
this.log(txs);
});
CLI.prototype.sendTX = co(function* sendTX() {
var output = {};
var options, tx;
if (this.config.script) {
output.script = this.config.script;
output.value = Amount.value(this.config.value || this.argv[0]);
} else {
output.address = this.config.address || this.argv[0];
output.value = Amount.value(this.config.value || this.argv[1]);
}
options = {
account: this.config.account,
passphrase: this.config.passphrase,
outputs: [output]
};
tx = yield this.wallet.send(options);
this.log(tx);
});
CLI.prototype.createTX = co(function* createTX() {
var output = {};
var options, tx;
if (this.config.script) {
output.script = this.config.script;
output.value = Amount.value(this.config.value || this.argv[0]);
} else {
output.address = this.config.address || this.argv[0];
output.value = Amount.value(this.config.value || this.argv[1]);
}
options = {
account: this.config.account,
passphrase: this.config.passphrase,
outputs: [output]
};
tx = yield this.wallet.createTX(options);
this.log(tx);
});
CLI.prototype.signTX = co(function* signTX() {
var options = { passphrase: this.config.passphrase };
var raw = options.tx || this.argv[0];
var tx = yield this.wallet.sign(raw, options);
this.log(tx);
});
CLI.prototype.zapWallet = co(function* zapWallet() {
var age = (this.config.age >>> 0) || 72 * 60 * 60;
yield this.wallet.zap(this.config.account, age);
this.log('Zapped!');
});
CLI.prototype.broadcast = co(function* broadcast() {
var raw = this.argv[0] || this.config.tx;
var tx = yield this.client.broadcast(raw);
this.log('Broadcasted:');
this.log(tx);
});
CLI.prototype.viewTX = co(function* viewTX() {
var raw = this.argv[0] || this.config.tx;
var tx = yield this.wallet.fill(raw);
this.log(tx);
});
CLI.prototype.getDetails = co(function* getDetails() {
var hash = this.argv[0];
var details = yield this.wallet.getTX(hash);
this.log(details);
});
CLI.prototype.getWalletBlocks = co(function* getWalletBlocks() {
var blocks = yield this.wallet.getBlocks();
this.log(blocks);
});
CLI.prototype.getWalletBlock = co(function* getWalletBlock() {
var height = this.argv[0] | 0;
var block = yield this.wallet.getBlock(height);
this.log(block);
});
CLI.prototype.retoken = co(function* retoken() {
var result = yield this.wallet.retoken();
this.log(result);
});
CLI.prototype.rescan = co(function* rescan() {
var height = this.argv[0];
if (!util.isUInt32(height))
height = null;
yield this.client.rescan(height);
this.log('Rescanning...');
});
CLI.prototype.reset = co(function* reset() {
var hash = this.argv[0];
if (hash.length !== 64)
hash = +hash;
yield this.client.reset(hash);
this.log('Chain has been reset.');
});
CLI.prototype.resend = co(function* resend() {
yield this.client.resend();
this.log('Resending...');
});
CLI.prototype.resendWallet = co(function* resendWallet() {
yield this.wallet.resend();
this.log('Resending...');
});
CLI.prototype.backup = co(function* backup() {
var path = this.argv[0];
yield this.client.backup(path);
this.log('Backup complete.');
});
CLI.prototype.importKey = co(function* importKey() {
var key = this.argv[0];
var account = this.config.account;
if (!key)
throw new Error('No key for import.');
if (util.isBase58(key)) {
yield this.wallet.importPrivate(account, key);
this.log('Imported private key.');
return;
}
if (util.isHex(key)) {
yield this.wallet.importPublic(account, key);
this.log('Imported public key.');
return;
}
throw new Error('Bad key for import.');
});
CLI.prototype.importAddress = co(function* importKey() {
var address = this.argv[0];
var account = this.config.account;
yield this.wallet.importAddress(account, address);
this.log('Imported address.');
});
CLI.prototype.lock = co(function* lock() {
yield this.wallet.lock();
this.log('Locked.');
});
CLI.prototype.unlock = co(function* unlock() {
var passphrase = this.argv[0];
var timeout = +this.argv[1] || null;
yield this.wallet.unlock(passphrase, timeout);
this.log('Unlocked.');
});
CLI.prototype.rpc = co(function* rpc() {
var method = this.argv.shift();
var params = [];
var i, arg, param, result;
for (i = 0; i < this.argv.length; i++) {
arg = this.argv[i];
try {
param = JSON.parse(arg);
} catch (e) {
param = arg;
}
params.push(param);
}
result = yield this.client.rpc.call(method, params);
this.log(result);
});
CLI.prototype.handleWallet = co(function* handleWallet() {
this.wallet = new Wallet({
uri: this.config.url || this.config.uri,
apiKey: this.config.apikey,
network: this.config.network,
id: this.config.id || 'primary',
token: this.config.token
});
switch (this.argv.shift()) {
case 'listen':
return yield this.listenWallet();
case 'get':
return yield this.getWallet();
case 'master':
return yield this.getMaster();
case 'shared':
if (this.argv[0] === 'add') {
this.argv.shift();
return yield this.addSharedKey();
}
if (this.argv[0] === 'remove') {
this.argv.shift();
return yield this.removeSharedKey();
}
if (this.argv[0] === 'list')
this.argv.shift();
return yield this.getSharedKeys();
case 'balance':
return yield this.getBalance();
case 'history':
return yield this.getWalletHistory();
case 'pending':
return yield this.getWalletPending();
case 'coins':
return yield this.getWalletCoins();
case 'account':
if (this.argv[0] === 'list') {
this.argv.shift();
return yield this.getAccounts();
}
if (this.argv[0] === 'create') {
this.argv.shift();
return yield this.createAccount();
}
if (this.argv[0] === 'get')
this.argv.shift();
return yield this.getAccount();
case 'address':
return yield this.createAddress();
case 'change':
return yield this.createChange();
case 'nested':
return yield this.createNested();
case 'retoken':
return yield this.retoken();
case 'sign':
return yield this.signTX();
case 'mktx':
return yield this.createTX();
case 'send':
return yield this.sendTX();
case 'zap':
return yield this.zapWallet();
case 'tx':
return yield this.getDetails();
case 'blocks':
return yield this.getWalletBlocks();
case 'block':
return yield this.getWalletBlock();
case 'view':
return yield this.viewTX();
case 'import':
return yield this.importKey();
case 'watch':
return yield this.importAddress();
case 'key':
return yield this.getKey();
case 'dump':
return yield this.getWIF();
case 'lock':
return yield this.lock();
case 'unlock':
return yield this.unlock();
case 'resend':
return yield this.resendWallet();
default:
this.log('Unrecognized command.');
this.log('Commands:');
this.log(' $ listen: Listen for events.');
this.log(' $ get: View wallet.');
this.log(' $ master: View wallet master key.');
this.log(' $ shared add [xpubkey]: Add key to wallet.');
this.log(' $ shared remove [xpubkey]: Remove key from wallet.');
this.log(' $ balance: Get wallet balance.');
this.log(' $ history: View TX history.');
this.log(' $ pending: View pending TXs.');
this.log(' $ coins: View wallet coins.');
this.log(' $ account list: List account names.');
this.log(' $ account create [account-name]: Create account.');
this.log(' $ account get [account-name]: Get account details.');
this.log(' $ address: Derive new address.');
this.log(' $ change: Derive new change address.');
this.log(' $ nested: Derive new nested address.');
this.log(' $ retoken: Create new api key.');
this.log(' $ send [address] [value]: Send transaction.');
this.log(' $ mktx [address] [value]: Create transaction.');
this.log(' $ sign [tx-hex]: Sign transaction.');
this.log(' $ zap [age?]: Zap pending wallet TXs.');
this.log(' $ tx [hash]: View transaction details.');
this.log(' $ blocks: List wallet blocks.');
this.log(' $ block [height]: View wallet block.');
this.log(' $ view [tx-hex]: Parse and view transaction.');
this.log(' $ import [wif|hex]: Import private or public key.');
this.log(' $ watch [address]: Import an address.');
this.log(' $ key [address]: Get wallet key by address.');
this.log(' $ dump [address]: Get wallet key WIF by address.');
this.log(' $ lock: Lock wallet.');
this.log(' $ unlock [passphrase] [timeout?]: Unlock wallet.');
this.log(' $ resend: Resend pending transactions.');
this.log('Other Options:');
this.log(' --passphrase [passphrase]: For signing and account creation.');
this.log(' --account [account-name]: Account name.');
return;
}
});
CLI.prototype.handleNode = co(function* handleNode() {
this.client = new Client({
uri: this.config.url || this.config.uri,
apiKey: this.config.apikey,
network: this.config.network
});
switch (this.argv.shift()) {
case 'info':
return yield this.getInfo();
case 'wallets':
return yield this.getWallets();
case 'mkwallet':
return yield this.createWallet();
case 'broadcast':
return yield this.broadcast();
case 'mempool':
return yield this.getMempool();
case 'tx':
return yield this.getTX();
case 'coin':
return yield this.getCoin();
case 'block':
return yield this.getBlock();
case 'rescan':
return yield this.rescan();
case 'reset':
return yield this.reset();
case 'resend':
return yield this.resend();
case 'backup':
return yield this.backup();
case 'rpc':
return yield this.rpc();
default:
this.log('Unrecognized command.');
this.log('Commands:');
this.log(' $ info: Get server info.');
this.log(' $ wallets: List all wallets.');
this.log(' $ wallet create [id]: Create wallet.');
this.log(' $ broadcast [tx-hex]: Broadcast transaction.');
this.log(' $ mempool: Get mempool snapshot.');
this.log(' $ tx [hash/address]: View transactions.');
this.log(' $ coin [hash+index/address]: View coins.');
this.log(' $ block [hash/height]: View block.');
this.log(' $ rescan [height]: Rescan for transactions.');
this.log(' $ reset [height/hash]: Reset chain to desired block.');
this.log(' $ resend: Resend pending transactions.');
this.log(' $ backup [path]: Backup the wallet db.');
this.log(' $ rpc [command] [args]: Execute RPC command.');
return;
}
});
CLI.prototype.open = co(function* open() {
switch (this.argv[0]) {
case 'w':
case 'wallet':
this.argv.shift();
if (this.argv[0] === 'create') {
this.argv[0] = 'mkwallet';
return yield this.handleNode();
}
return yield this.handleWallet();
default:
return yield this.handleNode();
}
});
CLI.prototype.destroy = function destroy() {
if (this.wallet)
this.wallet.client.destroy();
if (this.client)
this.client.destroy();
return Promise.resolve();
};
main = co(function* main() {
var cli = new CLI();
yield cli.open();
yield cli.destroy();
});
main().then(process.exit).catch(function(err) {
console.error(err.stack + '');
return process.exit(1);
});