571 lines
15 KiB
JavaScript
Executable File
571 lines
15 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
|
|
'use strict';
|
|
|
|
var config = require('../lib/node/config');
|
|
var utils = require('../lib/utils/utils');
|
|
var Client = require('../lib/http/client');
|
|
var Wallet = require('../lib/http/wallet');
|
|
var assert = utils.assert;
|
|
|
|
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.createWallet = function createWallet(callback) {
|
|
var self = this;
|
|
var options = { id: this.argv[0] };
|
|
|
|
if (this.config.type)
|
|
options.type = this.config.type;
|
|
|
|
if (this.config.master)
|
|
options.master = this.config.master;
|
|
|
|
if (this.config.key)
|
|
options.key = this.config.key;
|
|
|
|
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;
|
|
|
|
this.client.createWallet(options, function(err, wallet) {
|
|
if (err)
|
|
return callback(err);
|
|
self.log(wallet);
|
|
callback();
|
|
});
|
|
};
|
|
|
|
CLI.prototype.addKey = function addKey(callback) {
|
|
var self = this;
|
|
var key = this.argv[0];
|
|
this.wallet.addKey(this.config.account, key, function(err, wallet) {
|
|
if (err)
|
|
return callback(err);
|
|
self.log('added');
|
|
callback();
|
|
});
|
|
};
|
|
|
|
CLI.prototype.removeKey = function removeKey(callback) {
|
|
var self = this;
|
|
var key = this.argv[0];
|
|
this.wallet.removeKey(this.config.account, key, function(err) {
|
|
if (err)
|
|
return callback(err);
|
|
self.log('removed');
|
|
callback();
|
|
});
|
|
};
|
|
|
|
CLI.prototype.getAccount = function getAccount(callback) {
|
|
var self = this;
|
|
var account = this.argv[0] || this.config.account;
|
|
this.wallet.getAccount(account, function(err, account) {
|
|
if (err)
|
|
return callback(err);
|
|
self.log(account);
|
|
callback();
|
|
});
|
|
};
|
|
|
|
CLI.prototype.createAccount = function createAccount(callback) {
|
|
var self = this;
|
|
var account = this.argv[0];
|
|
this.wallet.createAccount(account, function(err, account) {
|
|
if (err)
|
|
return callback(err);
|
|
self.log(account);
|
|
callback();
|
|
});
|
|
};
|
|
|
|
CLI.prototype.getAccounts = function getAccounts(callback) {
|
|
var self = this;
|
|
this.wallet.getAccounts(function(err, accounts) {
|
|
if (err)
|
|
return callback(err);
|
|
self.log(accounts);
|
|
callback();
|
|
});
|
|
};
|
|
|
|
CLI.prototype.getWallet = function getWallet(callback) {
|
|
var self = this;
|
|
this.wallet.getInfo(function(err, wallet) {
|
|
if (err)
|
|
return callback(err);
|
|
self.log(wallet);
|
|
callback();
|
|
});
|
|
};
|
|
|
|
CLI.prototype.getTX = function getTX(callback) {
|
|
var self = this;
|
|
var hash = this.argv[0];
|
|
if (utils.isBase58(hash)) {
|
|
return this.client.getTXByAddress(hash, function(err, txs) {
|
|
if (err)
|
|
return callback(err);
|
|
self.log(txs);
|
|
callback();
|
|
});
|
|
}
|
|
this.client.getTX(hash, function(err, tx) {
|
|
if (err)
|
|
return callback(err);
|
|
|
|
if (!tx) {
|
|
self.log('TX not found.');
|
|
return callback();
|
|
}
|
|
|
|
self.log(tx);
|
|
callback();
|
|
});
|
|
};
|
|
|
|
CLI.prototype.getBlock = function getBlock(callback) {
|
|
var self = this;
|
|
var hash = this.argv[0];
|
|
if (hash.length !== 64)
|
|
hash = +hash;
|
|
this.client.getBlock(hash, function(err, block) {
|
|
if (err)
|
|
return callback(err);
|
|
|
|
if (!block) {
|
|
self.log('Block not found.');
|
|
return callback();
|
|
}
|
|
|
|
self.log(block);
|
|
callback();
|
|
});
|
|
};
|
|
|
|
CLI.prototype.getCoin = function getCoin(callback) {
|
|
var self = this;
|
|
var hash = this.argv[0];
|
|
var index = this.argv[1];
|
|
if (utils.isBase58(hash)) {
|
|
return this.client.getCoinsByAddress(hash, function(err, coins) {
|
|
if (err)
|
|
return callback(err);
|
|
self.log(coins);
|
|
callback();
|
|
});
|
|
}
|
|
this.client.getCoin(hash, index, function(err, coin) {
|
|
if (err)
|
|
return callback(err);
|
|
|
|
if (!coin) {
|
|
self.log('Coin not found.');
|
|
return callback();
|
|
}
|
|
|
|
self.log(coin);
|
|
callback();
|
|
});
|
|
};
|
|
|
|
CLI.prototype.getWalletHistory = function getWalletHistory(callback) {
|
|
var self = this;
|
|
this.wallet.getHistory(this.config.account, function(err, txs) {
|
|
if (err)
|
|
return callback(err);
|
|
self.log(txs);
|
|
callback();
|
|
});
|
|
};
|
|
|
|
CLI.prototype.listenWallet = function listenWallet(callback) {
|
|
var self = this;
|
|
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);
|
|
});
|
|
};
|
|
|
|
CLI.prototype.getBalance = function getBalance(callback) {
|
|
var self = this;
|
|
this.wallet.getBalance(this.config.account, function(err, balance) {
|
|
if (err)
|
|
return callback(err);
|
|
self.log(balance);
|
|
callback();
|
|
});
|
|
};
|
|
|
|
CLI.prototype.getMempool = function getMempool(callback) {
|
|
var self = this;
|
|
this.client.getMempool(function(err, txs) {
|
|
if (err)
|
|
return callback(err);
|
|
self.log(txs);
|
|
callback();
|
|
});
|
|
};
|
|
|
|
CLI.prototype.sendTX = function sendTX(callback) {
|
|
var self = this;
|
|
var output = {};
|
|
var options;
|
|
|
|
if (this.config.script) {
|
|
output.script = this.config.script;
|
|
output.value = utils.satoshi(this.config.value || this.argv[0]);
|
|
} else {
|
|
output.address = this.config.address || this.argv[0];
|
|
output.value = utils.satoshi(this.config.value || this.argv[1]);
|
|
}
|
|
|
|
options = {
|
|
account: this.config.account,
|
|
passphrase: this.config.passphrase,
|
|
outputs: [output]
|
|
};
|
|
|
|
this.wallet.send(options, function(err, tx) {
|
|
if (err)
|
|
return callback(err);
|
|
self.log(tx);
|
|
callback();
|
|
});
|
|
};
|
|
|
|
CLI.prototype.createTX = function createTX(callback) {
|
|
var self = this;
|
|
var output = {};
|
|
var options;
|
|
|
|
if (this.config.script) {
|
|
output.script = this.config.script;
|
|
output.value = utils.satoshi(this.config.value || this.argv[0]);
|
|
} else {
|
|
output.address = this.config.address || this.argv[0];
|
|
output.value = utils.satoshi(this.config.value || this.argv[1]);
|
|
}
|
|
|
|
options = {
|
|
account: this.config.account,
|
|
passphrase: this.config.passphrase,
|
|
outputs: [output]
|
|
};
|
|
|
|
this.wallet.createTX(options, function(err, tx) {
|
|
if (err)
|
|
return callback(err);
|
|
self.log(tx);
|
|
callback();
|
|
});
|
|
};
|
|
|
|
CLI.prototype.signTX = function signTX(callback) {
|
|
var self = this;
|
|
var options = { passphrase: this.config.passphrase };
|
|
var tx = options.tx || this.argv[0];
|
|
this.wallet.sign(tx, options, function(err, tx) {
|
|
if (err)
|
|
return callback(err);
|
|
self.log(tx);
|
|
callback();
|
|
});
|
|
};
|
|
|
|
CLI.prototype.zap = function zap(callback) {
|
|
var self = this;
|
|
var age = (this.config.age >>> 0) || 72 * 60 * 60;
|
|
this.wallet.zap(this.config.account, age, function(err) {
|
|
if (err)
|
|
return callback(err);
|
|
self.log('Zapped!');
|
|
callback();
|
|
});
|
|
};
|
|
|
|
CLI.prototype.broadcast = function broadcast(callback) {
|
|
var self = this;
|
|
var tx = this.argv[0] || this.config.tx;
|
|
this.client.broadcast(tx, function(err, tx) {
|
|
if (err)
|
|
return callback(err);
|
|
self.log('Broadcasted:');
|
|
self.log(tx);
|
|
callback();
|
|
});
|
|
};
|
|
|
|
CLI.prototype.viewTX = function viewTX(callback) {
|
|
var self = this;
|
|
var tx = this.argv[0] || this.config.tx;
|
|
this.wallet.fill(tx, function(err, tx) {
|
|
if (err)
|
|
return callback(err);
|
|
self.log(tx);
|
|
callback();
|
|
});
|
|
};
|
|
|
|
CLI.prototype.getDetails = function getDetails(callback) {
|
|
var self = this;
|
|
var hash = this.argv[0];
|
|
this.wallet.getTX(hash, function(err, tx) {
|
|
if (err)
|
|
return callback(err);
|
|
self.log(tx);
|
|
callback();
|
|
});
|
|
};
|
|
|
|
CLI.prototype.rpc = function rpc(callback) {
|
|
var self = this;
|
|
var method = this.argv.shift();
|
|
var params = [];
|
|
var i, arg, param;
|
|
|
|
for (i = 0; i < this.argv.length; i++) {
|
|
arg = this.argv[i];
|
|
try {
|
|
param = JSON.parse(arg);
|
|
} catch (e) {
|
|
param = arg;
|
|
}
|
|
params.push(param);
|
|
}
|
|
|
|
this.client.rpc.call(method, params, function(err, result) {
|
|
if (err)
|
|
return callback(err);
|
|
self.log(result);
|
|
callback();
|
|
});
|
|
};
|
|
|
|
CLI.prototype.handleWallet = function handleWallet(callback) {
|
|
var self = this;
|
|
|
|
var options = {
|
|
id: this.config.id || 'primary',
|
|
token: this.config.token
|
|
};
|
|
|
|
this.wallet = new Wallet({
|
|
uri: this.config.url || this.config.uri,
|
|
apiKey: this.config.apikey,
|
|
network: this.config.network
|
|
});
|
|
|
|
this.wallet.open(options, function(err) {
|
|
if (err)
|
|
return callback(err);
|
|
|
|
switch (self.argv.shift()) {
|
|
case 'listen':
|
|
return self.listenWallet(callback);
|
|
case 'get':
|
|
return self.getWallet(callback);
|
|
case 'addkey':
|
|
return self.addKey(callback);
|
|
case 'rmkey':
|
|
return self.removeKey(callback);
|
|
case 'balance':
|
|
return self.getBalance(callback);
|
|
case 'history':
|
|
return self.getWalletHistory(callback);
|
|
case 'account':
|
|
if (self.argv[0] === 'create') {
|
|
self.argv.shift();
|
|
return self.createAccount(callback);
|
|
}
|
|
return self.getAccount(callback);
|
|
case 'accounts':
|
|
return self.getAccounts(callback);
|
|
case 'sign':
|
|
return self.signTX(callback);
|
|
case 'mktx':
|
|
return self.createTX(callback);
|
|
case 'send':
|
|
return self.sendTX(callback);
|
|
case 'zap':
|
|
return self.zap(callback);
|
|
case 'tx':
|
|
return self.getDetails(callback);
|
|
case 'view':
|
|
return self.viewTX(callback);
|
|
default:
|
|
self.log('Unrecognized command.');
|
|
self.log('Commands:');
|
|
self.log(' $ wallet [id] --keys [hdkeys]'
|
|
+ ' --type [pubkeyhash/multisig] -m [m-value]'
|
|
+ ' -n [n-value] --witness: View or create wallet by ID.');
|
|
self.log(' $ listen [id]: Listen for wallet events.');
|
|
self.log(' $ getwallet [id]: View wallet by ID.');
|
|
self.log(' $ addkey [id] --keys [hdkeys]: Add keys to wallet.');
|
|
self.log(' $ rmkey [id] --keys [hdkeys]: Remove keys from wallet.');
|
|
self.log(' $ balance [id]: Get wallet balance.');
|
|
self.log(' $ history [id]: View wallet TX history.');
|
|
self.log(' $ accounts [id]: List account names.');
|
|
self.log(' $ account [id] [acct]: Get account details.');
|
|
self.log(' $ send [id] [address] [value] --script [code]: Send transaction.');
|
|
self.log(' $ create [id] [address] [value] --script [code]: Create transaction.');
|
|
self.log(' $ sign [id] [tx-hex]: Sign transaction.');
|
|
self.log(' $ zap [id] --age [age]: Zap pending wallet TXs.');
|
|
self.log(' $ broadcast [tx-hex]: Broadcast transaction.');
|
|
self.log(' $ view [tx-hex]: View transaction.');
|
|
self.log(' $ mempool: Get mempool snapshot.');
|
|
self.log(' $ tx [hash/address]: View transactions.');
|
|
self.log(' $ coin [hash+index/address]: View coins.');
|
|
self.log(' $ block [hash/height]: View block.');
|
|
self.log('Other Options:');
|
|
self.log(' --passphrase [passphrase]: For signing and account creation.');
|
|
self.log(' --account [acctname]: Account name.');
|
|
return callback();
|
|
}
|
|
});
|
|
};
|
|
|
|
CLI.prototype.handleNode = function handleNode(callback) {
|
|
var self = this;
|
|
|
|
this.client = new Client({
|
|
uri: this.config.url || this.config.uri,
|
|
apiKey: this.config.apikey,
|
|
network: this.config.network
|
|
});
|
|
|
|
this.client.getInfo(function(err, info) {
|
|
if (err)
|
|
return callback(err);
|
|
|
|
switch (self.argv.shift()) {
|
|
case 'mkwallet':
|
|
return self.createWallet(callback);
|
|
case 'broadcast':
|
|
return self.broadcast(callback);
|
|
case 'mempool':
|
|
return self.getMempool(callback);
|
|
case 'tx':
|
|
return self.getTX(callback);
|
|
case 'coin':
|
|
return self.getCoin(callback);
|
|
case 'block':
|
|
return self.getBlock(callback);
|
|
case 'rpc':
|
|
return self.rpc(callback);
|
|
default:
|
|
self.log('Unrecognized command.');
|
|
self.log('Commands:');
|
|
self.log(' $ wallet [id] --keys [hdkeys]'
|
|
+ ' --type [pubkeyhash/multisig] -m [m-value]'
|
|
+ ' -n [n-value] --witness: View or create wallet by ID.');
|
|
self.log(' $ listen [id]: Listen for wallet events.');
|
|
self.log(' $ getwallet [id]: View wallet by ID.');
|
|
self.log(' $ addkey [id] --keys [hdkeys]: Add keys to wallet.');
|
|
self.log(' $ rmkey [id] --keys [hdkeys]: Remove keys from wallet.');
|
|
self.log(' $ balance [id]: Get wallet balance.');
|
|
self.log(' $ history [id]: View wallet TX history.');
|
|
self.log(' $ accounts [id]: List account names.');
|
|
self.log(' $ account [id] [acct]: Get account details.');
|
|
self.log(' $ send [id] [address] [value] --script [code]: Send transaction.');
|
|
self.log(' $ create [id] [address] [value] --script [code]: Create transaction.');
|
|
self.log(' $ sign [id] [tx-hex]: Sign transaction.');
|
|
self.log(' $ zap [id] --age [age]: Zap pending wallet TXs.');
|
|
self.log(' $ broadcast [tx-hex]: Broadcast transaction.');
|
|
self.log(' $ view [tx-hex]: View transaction.');
|
|
self.log(' $ mempool: Get mempool snapshot.');
|
|
self.log(' $ tx [hash/address]: View transactions.');
|
|
self.log(' $ coin [hash+index/address]: View coins.');
|
|
self.log(' $ block [hash/height]: View block.');
|
|
self.log('Other Options:');
|
|
self.log(' --passphrase [passphrase]: For signing and account creation.');
|
|
self.log(' --account [acctname]: Account name.');
|
|
return callback();
|
|
}
|
|
});
|
|
};
|
|
|
|
CLI.prototype.open = function open(callback) {
|
|
switch (this.argv[0]) {
|
|
case 'w':
|
|
case 'wallet':
|
|
this.argv.shift();
|
|
if (this.argv[0] === 'create') {
|
|
this.argv[0] = 'mkwallet';
|
|
return this.handleNode(callback);
|
|
}
|
|
return this.handleWallet(callback);
|
|
default:
|
|
return this.handleNode(callback);
|
|
}
|
|
};
|
|
|
|
CLI.prototype.destroy = function destroy(callback) {
|
|
if (this.wallet && !this.wallet.client.loading)
|
|
this.wallet.client.destroy();
|
|
if (this.client && !this.client.loading)
|
|
this.client.destroy();
|
|
callback();
|
|
};
|
|
|
|
function main(callback) {
|
|
var cli = new CLI();
|
|
cli.open(function(err) {
|
|
if (err)
|
|
return callback(err);
|
|
cli.destroy(callback);
|
|
});
|
|
}
|
|
|
|
main(function(err) {
|
|
if (err) {
|
|
console.error(err.stack + '');
|
|
return process.exit(1);
|
|
}
|
|
return process.exit(0);
|
|
});
|