180 lines
5.8 KiB
JavaScript
Executable File
180 lines
5.8 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
|
|
var _ = require('lodash');
|
|
var program = require('commander');
|
|
var utils = require('./cli-utils');
|
|
var moment = require('moment');
|
|
var async = require('async');
|
|
program = utils.configureCommander(program);
|
|
var N = 100;
|
|
|
|
program
|
|
.option('-t, --testnet', 'Query testnet wallet')
|
|
.option('-h, --history', 'Include full tx history')
|
|
.option('-f, --full', 'Dont trim output to ' + N + ' items')
|
|
.usage('<identifier>')
|
|
.parse(process.argv);
|
|
|
|
var args = program.args;
|
|
if (!args[0])
|
|
program.help();
|
|
|
|
var identifier = args[0];
|
|
var network = program.testnet ? 'testnet' : 'livenet';
|
|
var trim = program.full ? false : true;
|
|
var format = (amount, coin) => {
|
|
return utils.renderAmount(amount, coin);
|
|
};
|
|
|
|
utils.getClient(program, {
|
|
mustExist: true
|
|
}, (client) => {
|
|
client.getStatusByIdentifier({
|
|
identifier: identifier
|
|
}, (err, status) => {
|
|
utils.die(err);
|
|
if (!status) {
|
|
console.log('Could not find wallet associated to ' + identifier);
|
|
process.exit(0);
|
|
}
|
|
|
|
console.log('Found wallet associated to ' + identifier + '. Querying wallet info...');
|
|
|
|
utils.getClient(program, {
|
|
mustExist: true,
|
|
walletId: status.wallet.id,
|
|
}, (client) => {
|
|
|
|
async.parallel([
|
|
function(done) {
|
|
client.getSendMaxInfo({
|
|
returnInputs: true
|
|
}, done);
|
|
},
|
|
function(done) {
|
|
client.getMainAddresses({
|
|
doNotVerify: true
|
|
}, done);
|
|
},
|
|
function(done) {
|
|
client.getTxHistory({}, done);
|
|
},
|
|
], (err, res) => {
|
|
utils.die(err);
|
|
|
|
displayStatus(status);
|
|
if (trim) {
|
|
if ((res[1] && res[1].length>N) || (res[2] && res[2].length> N))
|
|
console.log('\n Trimming results to %s items', N );
|
|
|
|
if (res[1] && res[1].length > N)
|
|
res[1] = res[1].reverse().splice(0,N);
|
|
|
|
if (res[2] && res[2].length > N)
|
|
res[2] = res[2].splice(0,N);
|
|
};
|
|
|
|
displaySendMaxInfo(res[0], status.wallet);
|
|
displayAddresses(res[1], status.wallet);
|
|
displayHistory(res[2], status.wallet);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
|
|
|
|
function displayStatus(status) {
|
|
var w = status.wallet;
|
|
console.log('\n* Wallet info');
|
|
console.log(' ID: %s Coin:', w.id, w.coin);
|
|
console.log(' %s %d-of-%d%s [%s %s] wallet (status: %s)', w.network.toUpperCase(), w.m, w.n, w.singleAddress ? ' single-address' : '', w.derivationStrategy, w.addressType, w.status);
|
|
console.log(' Created on: %s', moment(w.createdOn * 1000));
|
|
|
|
if (w.status != 'complete') {
|
|
console.log(' Missing ' + (w.n - w.copayers.length) + ' copayers');
|
|
}
|
|
|
|
var x = status.balance;
|
|
console.log('\n* Balance')
|
|
|
|
console.log(' Total: %s (%s locked)', format(x.totalAmount, w.coin), format(x.lockedAmount, w.coin));
|
|
|
|
console.log(' Confirmed: %s (%s locked)', format(x.totalConfirmedAmount, w.coin), format(x.lockedConfirmedAmount, w.coin));
|
|
console.log(' Available: %s (%s confirmed / %s unconfirmed)', format(x.availableAmount, w.coin), format(x.availableConfirmedAmount, w.coin), format(x.availableAmount - x.availableConfirmedAmount, w.coin));
|
|
if (!_.isEmpty(x.byAddress)) {
|
|
console.log(' By address:');
|
|
}
|
|
_.each(x.byAddress, function(item) {
|
|
console.log(' %s (%s): %s', item.address, item.path, format(item.amount, w.coin));
|
|
});
|
|
|
|
if (!_.isEmpty(status.pendingTxps)) {
|
|
console.log("\n* Pending tx proposals");
|
|
_.each(status.pendingTxps, function(x) {
|
|
var missingSignatures = x.requiredSignatures - _.filter(_.values(x.actions), function(a) {
|
|
return a.type == 'accept';
|
|
}).length;
|
|
console.log(" [%s] %s (fee/kb %s) => %s (status: %s)", new moment(x.createdOn * 1000), format(x.amount, w.coin), format(x.feePerKb, w.coin), x.outputs[0].toAddress, missingSignatures > 0 ? 'missing ' + missingSignatures + ' signatures' : 'ready to broadcast');
|
|
});
|
|
} else {
|
|
console.log('\n* No pending tx proposals.');
|
|
}
|
|
};
|
|
|
|
function displaySendMaxInfo(info, wallet) {
|
|
if (info.amount == 0) return;
|
|
console.log('\n* Send max');
|
|
console.log(' Maximum spendable amount at "normal" fee level (%s per kb): %s', format(info.feePerKb, wallet.coin), format(info.amount, wallet.coin));
|
|
if (info.utxosBelowFee > 0) {
|
|
console.log(' %s UTXOs for a total amount of %s are currently below fee required to spend them', info.utxosBelowFee, info.amountBelowFee);
|
|
}
|
|
if (info.utxosAboveMaxSize > 0) {
|
|
console.log(' %s UTXOs for a total amount of %s exceed the max allowed tx size', info.utxosAboveMaxSize, info.amountAboveMaxSize);
|
|
}
|
|
|
|
if (!_.isEmpty(info.inputs)) {
|
|
console.log(' Available UTXOs:');
|
|
}
|
|
_.each(info.inputs, function(utxo) {
|
|
console.log(' %s%s %s', format(utxo.satoshis, wallet.coin), utxo.locked ? ' (locked)' : '', utxo.confirmations > 0 ? utxo.confirmations + ' confirmations' : 'unconfirmed');
|
|
});
|
|
};
|
|
|
|
function displayAddresses(addresses) {
|
|
if (_.isEmpty(addresses)) {
|
|
console.log('\n* No addresses.');
|
|
return;
|
|
}
|
|
console.log('\n* Main addresses (not including change addresses)');
|
|
_.each(addresses, function(a) {
|
|
console.log(' [%s] %s (%s)', moment(a.createdOn * 1000), a.address, a.path);
|
|
});
|
|
};
|
|
|
|
function displayHistory(history, wallet) {
|
|
if (_.isEmpty(history)) {
|
|
console.log('\n* No tx history.');
|
|
return;
|
|
}
|
|
|
|
console.log("\n* Tx history")
|
|
_.each(history, function(tx) {
|
|
var time = moment(tx.time * 1000);
|
|
var amount = format(tx.amount, wallet.coin);
|
|
var confirmations = tx.confirmations || 0;
|
|
switch (tx.action) {
|
|
case 'received':
|
|
direction = '<=';
|
|
break;
|
|
case 'moved':
|
|
direction = '==';
|
|
break;
|
|
case 'sent':
|
|
direction = '=>';
|
|
break;
|
|
}
|
|
console.log(" [%s] %s %s %s %s (fee/kb %s) (%s confirmations)", time, tx.txid, direction, tx.action, amount, format(tx.feePerKb, wallet.coin), confirmations);
|
|
});
|
|
};
|