├── .coveralls.yml ├── .editorconfig ├── .gitignore ├── .travis.yml ├── LICENCE ├── README.md ├── bin ├── cli-utils.js ├── filestorage.js ├── wallet ├── wallet-address ├── wallet-addresses ├── wallet-airsign ├── wallet-balance ├── wallet-broadcast ├── wallet-confirm ├── wallet-create ├── wallet-derive ├── wallet-export ├── wallet-genkey ├── wallet-history ├── wallet-import ├── wallet-join ├── wallet-mnemonic ├── wallet-recreate ├── wallet-reject ├── wallet-rm ├── wallet-scan ├── wallet-send ├── wallet-sign ├── wallet-status └── wallet-txproposals ├── package-lock.json ├── package.json └── test └── cliUtils.js /.coveralls.yml: -------------------------------------------------------------------------------- 1 | repo_token: sPSI9ALVcN1NzwkXUxIMHVCfbWO1XNH9h 2 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | ; .editorconfig 2 | 3 | root = true 4 | 5 | [**.js] 6 | indent_style = space 7 | indent_size = 2 8 | 9 | [**.css] 10 | indent_style = space 11 | indent_size = 2 12 | 13 | [**.html] 14 | indent_style = space 15 | indent_size = 2 16 | max_char = 78 17 | brace_style = expand 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | *.sw* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 18 | .grunt 19 | 20 | # Compiled binary addons (http://nodejs.org/api/addons.html) 21 | build/Release 22 | 23 | # Dependency directory 24 | # Commenting this out is preferred by some people, see 25 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 26 | node_modules 27 | 28 | # Users Environment Variables 29 | .lock-wscript 30 | 31 | *.swp 32 | out/ 33 | db/* 34 | 35 | .bit 36 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '0.10' 4 | install: 5 | - npm install 6 | after_success: 7 | - npm run coveralls 8 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2015 BitPay 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This was moved to: 2 | 3 | https://github.com/bitpay/bitcore/tree/master/packages/bitcore-wallet 4 | 5 | 6 | see: https://github.com/bitpay/bitcore/pull/1992 7 | -------------------------------------------------------------------------------- /bin/cli-utils.js: -------------------------------------------------------------------------------- 1 | var _ = require('lodash'); 2 | var url = require('url'); 3 | var read = require('read') 4 | var log = require('npmlog'); 5 | var Client = require('bitcore-wallet-client'); 6 | var FileStorage = require('./filestorage'); 7 | var sjcl = require('sjcl'); 8 | 9 | var WALLET_ENCRYPTION_OPTS = { 10 | iter: 5000 11 | }; 12 | 13 | var Utils = function() {}; 14 | 15 | var die = Utils.die = function(err) { 16 | if (err) { 17 | if (err.code && err.code == 'ECONNREFUSED') { 18 | console.error('!! Could not connect to Bicore Wallet Service'); 19 | } else { 20 | console.log('!! ' + err.toString()); 21 | } 22 | process.exit(1); 23 | } 24 | }; 25 | 26 | Utils.parseMN = function(text) { 27 | if (!text) throw new Error('No m-n parameter'); 28 | 29 | var regex = /^(\d+)(-|of|-of-)?(\d+)$/i; 30 | var match = regex.exec(text.trim()); 31 | 32 | if (!match || match.length === 0) throw new Error('Invalid m-n parameter'); 33 | 34 | var m = parseInt(match[1]); 35 | var n = parseInt(match[3]); 36 | if (m > n) throw new Error('Invalid m-n parameter'); 37 | 38 | return [m, n]; 39 | }; 40 | 41 | 42 | Utils.shortID = function(id) { 43 | return id.substr(id.length - 4); 44 | }; 45 | 46 | Utils.confirmationId = function(copayer) { 47 | return parseInt(copayer.xPubKeySignature.substr(-4), 16).toString().substr(-4); 48 | } 49 | 50 | 51 | Utils.doLoad = function(client, doNotComplete, walletData, password, filename, cb) { 52 | if (password) { 53 | try { 54 | walletData = sjcl.decrypt(password, walletData); 55 | } catch (e) { 56 | die('Could not open wallet. Wrong password.'); 57 | } 58 | } 59 | 60 | try { 61 | client.import(walletData); 62 | } catch (e) { 63 | die('Corrupt wallet file.'); 64 | }; 65 | if (doNotComplete) return cb(client); 66 | 67 | 68 | client.on('walletCompleted', function(wallet) { 69 | Utils.doSave(client, filename, password, function() { 70 | log.info('Your wallet has just been completed. Please backup your wallet file or use the export command.'); 71 | }); 72 | }); 73 | client.openWallet(function(err, isComplete) { 74 | if (err) throw err; 75 | 76 | return cb(client); 77 | }); 78 | }; 79 | 80 | Utils.loadEncrypted = function(client, opts, walletData, filename, cb) { 81 | read({ 82 | prompt: 'Enter password to decrypt:', 83 | silent: true 84 | }, function(er, password) { 85 | if (er) die(err); 86 | if (!password) die("no password given"); 87 | 88 | return Utils.doLoad(client, opts.doNotComplete, walletData, password, filename, cb); 89 | }); 90 | }; 91 | 92 | Utils.getClient = function(args, opts, cb) { 93 | opts = opts || {}; 94 | 95 | var filename = args.file || process.env['WALLET_FILE'] || process.env['HOME'] + '/.wallet.dat'; 96 | var host = args.host || process.env['BWS_HOST'] || 'https://bws.bitpay.com/'; 97 | 98 | var storage = new FileStorage({ 99 | filename: filename, 100 | }); 101 | 102 | var client = new Client({ 103 | baseUrl: url.resolve(host, '/bws/api'), 104 | verbose: args.verbose, 105 | supportStaffWalletId: opts.walletId, 106 | timeout: 20 * 60 * 1000, 107 | //timeout: 1000, 108 | }); 109 | 110 | storage.load(function(err, walletData) { 111 | if (err) { 112 | if (err.code == 'ENOENT') { 113 | if (opts.mustExist) { 114 | die('File "' + filename + '" not found.'); 115 | } 116 | } else { 117 | die(err); 118 | } 119 | } 120 | 121 | if (walletData && opts.mustBeNew) { 122 | die('File "' + filename + '" already exists.'); 123 | } 124 | if (!walletData) return cb(client); 125 | 126 | var json; 127 | try { 128 | json = JSON.parse(walletData); 129 | } catch (e) { 130 | die('Invalid input file'); 131 | }; 132 | 133 | if (json.ct) { 134 | Utils.loadEncrypted(client, opts, walletData, filename, cb); 135 | } else { 136 | Utils.doLoad(client, opts.doNotComplete, walletData, null, filename, cb); 137 | } 138 | }); 139 | }; 140 | 141 | Utils.doSave = function(client, filename, password, cb) { 142 | var opts = {}; 143 | 144 | var str = client.export(); 145 | if (password) { 146 | str = sjcl.encrypt(password, str, WALLET_ENCRYPTION_OPTS); 147 | } 148 | 149 | var storage = new FileStorage({ 150 | filename: filename, 151 | }); 152 | 153 | storage.save(str, function(err) { 154 | die(err); 155 | return cb(); 156 | }); 157 | }; 158 | 159 | Utils.saveEncrypted = function(client, filename, cb) { 160 | read({ 161 | prompt: 'Enter password to encrypt:', 162 | silent: true 163 | }, function(er, password) { 164 | if (er) Utils.die(err); 165 | if (!password) Utils.die("no password given"); 166 | read({ 167 | prompt: 'Confirm password:', 168 | silent: true 169 | }, function(er, password2) { 170 | if (er) Utils.die(err); 171 | if (password != password2) 172 | Utils.die("passwords were not equal"); 173 | 174 | Utils.doSave(client, filename, password, cb); 175 | }); 176 | }); 177 | }; 178 | 179 | Utils.saveClient = function(args, client, opts, cb) { 180 | if (_.isFunction(opts)) { 181 | cb = opts; 182 | opts = {}; 183 | } 184 | 185 | var filename = args.file || process.env['WALLET_FILE'] || process.env['HOME'] + '/.wallet.dat'; 186 | 187 | var storage = new FileStorage({ 188 | filename: filename, 189 | }); 190 | 191 | console.log(' * Saving file', filename); 192 | 193 | storage.exists(function(exists) { 194 | if (exists && opts.doNotOverwrite) { 195 | console.log(' * File already exists! Please specify a new filename using the -f option.'); 196 | return cb(); 197 | } 198 | 199 | if (args.password) { 200 | Utils.saveEncrypted(client, filename, cb); 201 | } else { 202 | Utils.doSave(client, filename, null, cb); 203 | }; 204 | }); 205 | }; 206 | 207 | Utils.findOneTxProposal = function(txps, id) { 208 | var matches = _.filter(txps, function(tx) { 209 | return _.endsWith(Utils.shortID(tx.id), id); 210 | }); 211 | 212 | if (!matches.length) 213 | Utils.die('Could not find TX Proposal:' + id); 214 | 215 | if (matches.length > 1) { 216 | console.log('More than one TX Proposals match:' + id); 217 | Utils.renderTxProposals(txps); 218 | process.exit(1); 219 | } 220 | 221 | return matches[0]; 222 | }; 223 | 224 | Utils.UNITS2 = { 225 | 'btc': 100000000, 226 | 'bit': 100, 227 | 'sat': 1, 228 | }; 229 | 230 | Utils.parseAmount = function(text) { 231 | if (!_.isString(text)) 232 | text = text.toString(); 233 | 234 | var regex = '^(\\d*(\\.\\d{0,8})?)\\s*(' + _.keys(Utils.UNITS2).join('|') + ')?$'; 235 | var match = new RegExp(regex, 'i').exec(text.trim()); 236 | 237 | if (!match || match.length === 0) { 238 | Utils.die('Invalid amount: ' + text); 239 | } 240 | 241 | var amount = parseFloat(match[1]); 242 | if (!_.isNumber(amount) || _.isNaN(amount)) throw new Error('Invalid amount'); 243 | 244 | var unit = (match[3] || 'sat').toLowerCase(); 245 | var rate = Utils.UNITS2[unit]; 246 | if (!rate) { 247 | Utils.die('Invalid unit: ' + unit); 248 | } 249 | 250 | var amountSat = parseFloat((amount * rate).toPrecision(12)); 251 | if (amountSat != Math.round(amountSat)) { 252 | Utils.die('Invalid amount: ' + amount + ' ' + unit); 253 | } 254 | 255 | return amountSat; 256 | }; 257 | 258 | Utils.configureCommander = function(program) { 259 | program 260 | .version('0.0.1') 261 | .option('-f, --file ', 'Wallet file') 262 | .option('-h, --host ', 'Bitcore Wallet Service URL (eg: http://localhost:3001/copay/api') 263 | .option('-v, --verbose', 'be verbose') 264 | 265 | return program; 266 | }; 267 | 268 | Utils.COIN = { 269 | bch: { 270 | name: 'bch', 271 | toSatoshis: 100000000, 272 | maxDecimals: 8, 273 | minDecimals: 8, 274 | }, 275 | btc: { 276 | name: 'btc', 277 | toSatoshis: 100000000, 278 | maxDecimals: 8, 279 | minDecimals: 8, 280 | }, 281 | bit: { 282 | name: 'bit', 283 | toSatoshis: 100, 284 | maxDecimals: 2, 285 | minDecimals: 2, 286 | }, 287 | bch: { 288 | name: 'bch', 289 | toSatoshis: 100000000, 290 | maxDecimals: 8, 291 | minDecimals: 8, 292 | }, 293 | 294 | }; 295 | 296 | Utils.renderAmount = function(satoshis, coin, opts) { 297 | function clipDecimals(number, decimals) { 298 | var x = number.toString().split('.'); 299 | var d = (x[1] || '0').substring(0, decimals); 300 | return parseFloat(x[0] + '.' + d); 301 | }; 302 | 303 | function addSeparators(nStr, thousands, decimal, minDecimals) { 304 | nStr = nStr.replace('.', decimal); 305 | var x = nStr.split(decimal); 306 | var x0 = x[0]; 307 | var x1 = x[1]; 308 | 309 | x1 = _.dropRightWhile(x1, function(n, i) { 310 | return n == '0' && i >= minDecimals; 311 | }).join(''); 312 | var x2 = x.length > 1 ? decimal + x1 : ''; 313 | 314 | x0 = x0.replace(/\B(?=(\d{3})+(?!\d))/g, thousands); 315 | return x0 + x2; 316 | }; 317 | 318 | opts = opts || {}; 319 | 320 | var coin = coin || 'btc'; 321 | var u = Utils.COIN[coin] || Utils.COIN.btc; 322 | var amount = clipDecimals((satoshis / u.toSatoshis), u.maxDecimals).toFixed(u.maxDecimals); 323 | return addSeparators(amount, opts.thousandsSeparator || ',', opts.decimalSeparator || '.', u.minDecimals) + ' ' + u.name; 324 | }; 325 | 326 | Utils.renderTxProposals = function(txps) { 327 | if (_.isEmpty(txps)) 328 | return; 329 | 330 | console.log("* TX Proposals:") 331 | 332 | _.each(txps, function(x) { 333 | var missingSignatures = x.requiredSignatures - _.filter(_.values(x.actions), function(a) { 334 | return a.type == 'accept'; 335 | }).length; 336 | console.log("\t%s [\"%s\" by %s] %s => %s", Utils.shortID(x.id), x.message, x.creatorName, Utils.renderAmount(x.amount), x.outputs[0].toAddress); 337 | 338 | if (!_.isEmpty(x.actions)) { 339 | console.log('\t\tActions: ', _.map(x.actions, function(a) { 340 | return a.copayerName + ' ' + (a.type == 'accept' ? '✓' : '✗') + (a.comment ? ' (' + a.comment + ')' : ''); 341 | }).join('. ')); 342 | } 343 | if (missingSignatures > 0) { 344 | console.log('\t\tMissing signatures: ' + missingSignatures); 345 | } else { 346 | console.log('\t\tReady to broadcast'); 347 | } 348 | }); 349 | 350 | }; 351 | 352 | module.exports = Utils; 353 | -------------------------------------------------------------------------------- /bin/filestorage.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs') 2 | 3 | function FileStorage(opts) { 4 | if (!opts.filename) { 5 | throw new Error('Please set wallet filename'); 6 | } 7 | this.filename = opts.filename; 8 | this.fs = opts.fs || fs; 9 | }; 10 | 11 | FileStorage.prototype.getName = function() { 12 | return this.filename; 13 | }; 14 | 15 | FileStorage.prototype.save = function(data, cb) { 16 | this.fs.writeFile(this.filename, JSON.stringify(data), cb); 17 | }; 18 | 19 | FileStorage.prototype.load = function(cb) { 20 | this.fs.readFile(this.filename, 'utf8', function(err, data) { 21 | if (err) return cb(err); 22 | try { 23 | data = JSON.parse(data); 24 | } catch (e) {} 25 | return cb(null, data); 26 | }); 27 | }; 28 | 29 | FileStorage.prototype.exists = function(cb) { 30 | fs.exists(this.filename, cb); 31 | }; 32 | 33 | module.exports = FileStorage; 34 | -------------------------------------------------------------------------------- /bin/wallet: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var program = require('commander'); 4 | 5 | program 6 | .version('0.0.7') 7 | .command('create [username]', 'creates a wallet') 8 | .command('join [username]', 'join a wallet') 9 | .command('mnemonic', 'show mnemonics from my wallet') 10 | .command('status', 'get wallet status') 11 | .command('address', 'create a new address from server') 12 | .command('addresses', 'list addresses') 13 | .command('balance', 'wallet balance') 14 | .command('send
[note]', 'send bitcoins') 15 | .command('sign ', 'sign a transaction proposal') 16 | .command('reject [reason]', 'reject a transaction proposal') 17 | .command('broadcast ', 'broadcast a transaction proposal to the Bitcoin network') 18 | .command('rm ', 'remove a transaction proposal') 19 | .command('history', 'list of past incoming and outgoing transactions') 20 | .command('export', 'export wallet critical data') 21 | .command('import ', 'import wallet critical data') 22 | .command('confirm', 'show copayer\'s data for confirmation') 23 | .command('recreate', 'recreate a wallet on a remove server given local infomation') 24 | .command('txproposals', 'list transactions proposals') 25 | .command('genkey', 'generates extended private key for later wallet usage') 26 | .command('airsign ', 'sign a list of transaction proposals from an air-gapped device') 27 | .command('derive ', 'derive using the extended private key') 28 | .parse(process.argv); 29 | 30 | if (!program.args.length || !program.runningCommand) 31 | program.help(); 32 | -------------------------------------------------------------------------------- /bin/wallet-address: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var program = require('commander'); 4 | var bitcoreCash = require('bitcore-wallet-client').BitcoreCash; 5 | var utils = require('./cli-utils'); 6 | program = utils.configureCommander(program); 7 | 8 | program 9 | .parse(process.argv); 10 | 11 | var args = program.args; 12 | utils.getClient(program, { 13 | mustExist: true 14 | }, function(client) { 15 | client.createAddress({}, function(err, x) { 16 | utils.die(err); 17 | 18 | if (client.credentials.coin == 'bch') { 19 | x.address = (new bitcoreCash.Address(x.address)).toCashAddress(); 20 | } 21 | 22 | console.log('* New Address %s ', x.address); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /bin/wallet-addresses: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var _ = require('lodash'); 4 | var program = require('commander'); 5 | var bitcoreCash = require('bitcore-wallet-client').BitcoreCash; 6 | var utils = require('./cli-utils'); 7 | program = utils.configureCommander(program); 8 | 9 | program 10 | .parse(process.argv); 11 | 12 | var args = program.args; 13 | 14 | utils.getClient(program, { mustExist: true }, function (client) { 15 | client.getMainAddresses({ 16 | doNotVerify: true 17 | }, function(err, x) { 18 | utils.die(err); 19 | 20 | if (x.length > 0) { 21 | console.log('* Addresses:'); 22 | _.each(x, function(a) { 23 | if (client.credentials.coin == 'bch') { 24 | a.address = (new bitcoreCash.Address(a.address)).toCashAddress(); 25 | } 26 | 27 | 28 | console.log(' ', a.address); 29 | }); 30 | } else { 31 | console.log('* No addresses.'); 32 | } 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /bin/wallet-airsign: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var _ = require('lodash'); 4 | var fs = require('fs'); 5 | var program = require('commander'); 6 | var utils = require('./cli-utils'); 7 | program = utils.configureCommander(program); 8 | 9 | program 10 | .usage('[options] ') 11 | .option('-o, --output ', 'write signatures to file') 12 | .parse(process.argv); 13 | 14 | var args = program.args; 15 | if (!args[0]) 16 | program.help(); 17 | 18 | var file = args[0]; 19 | 20 | utils.getClient(program, { mustExist: true, doNotComplete: true }, function (client) { 21 | var task = JSON.parse(fs.readFileSync(file)); 22 | var errors = []; 23 | var signatures = _.map(task.txps, function (txp) { 24 | try { 25 | return { 26 | txpId: txp.id, 27 | signatures: client.signTxProposalFromAirGapped(txp, task.encryptedPkr, task.m, task.n), 28 | }; 29 | } catch (ex) { 30 | errors.push({ 31 | txp: txp, 32 | error: ex 33 | }); 34 | } 35 | }); 36 | if (errors.length == 0) { 37 | if (program.output) { 38 | fs.writeFileSync(program.output, JSON.stringify(signatures)); 39 | console.log('Signatures written to file.'); 40 | } else { 41 | console.log(JSON.stringify(signatures)); 42 | } 43 | } else { 44 | console.log('Error signing transactions:'); 45 | _.each(errors, function (e) { 46 | console.log('\tTransaction %s: %s', e.txp.id, e.error.message); 47 | }); 48 | } 49 | }); 50 | -------------------------------------------------------------------------------- /bin/wallet-balance: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var program = require('commander'); 4 | var utils = require('./cli-utils'); 5 | program = utils.configureCommander(program); 6 | program 7 | .option('-c, --coin ', 'coin (btc/bch)') 8 | .parse(process.argv); 9 | 10 | 11 | program.option = function(){};; 12 | 13 | var args = program.args; 14 | 15 | 16 | var opts = {}; 17 | if (program.coin) { 18 | opts.coin = program.coin 19 | } 20 | 21 | utils.getClient(program, { 22 | mustExist: true 23 | }, function(client) { 24 | client.getBalance(opts, function(err, x) { 25 | utils.die(err); 26 | console.log('* Wallet balance %s (Locked %s)', utils.renderAmount(x.totalAmount), utils.renderAmount(x.lockedAmount)); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /bin/wallet-broadcast: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var _ = require('lodash'); 4 | var program = require('commander'); 5 | var utils = require('./cli-utils'); 6 | program = utils.configureCommander(program); 7 | 8 | program 9 | .usage('[options] ') 10 | .parse(process.argv); 11 | 12 | var args = program.args; 13 | var txpid = args[0] || ''; 14 | 15 | utils.getClient(program, { mustExist: true }, function (client) { 16 | client.getTxProposals({}, function(err, txps) { 17 | utils.die(err); 18 | 19 | var txp = utils.findOneTxProposal(txps, txpid); 20 | client.broadcastTxProposal(txp, function(err, txp) { 21 | utils.die(err); 22 | console.log('Transaction Broadcasted: TXID: ' + txp.txid); 23 | }); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /bin/wallet-confirm: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var _ = require('lodash'); 4 | var program = require('commander'); 5 | var utils = require('./cli-utils'); 6 | program = utils.configureCommander(program); 7 | 8 | program 9 | .parse(process.argv); 10 | 11 | utils.getClient(program, { mustExist: true }, function (client) { 12 | client.getStatus({}, function(err, x) { 13 | utils.die(err); 14 | 15 | if (x.wallet.n == 1) { 16 | console.log('Confirmations only work on shared wallets'); 17 | process.exit(1); 18 | } 19 | console.log('\n To be sure that no copayer has joined this wallet more than once, you can asked them for their confirmation number. They can get theirs by running the bit-confirm command.'); 20 | console.log('\n * Copayer confirmation IDs:'); 21 | 22 | var myConfirmationId; 23 | _.each(x.wallet.copayers, function(x) { 24 | var confirmationId = utils.confirmationId(x); 25 | if (x.id != client.credentials.copayerId) 26 | console.log('\t\t* %s : %s', x.name, confirmationId); 27 | else 28 | myConfirmationId = confirmationId; 29 | }); 30 | 31 | console.log('\t\t---'); 32 | console.log('\t\tYour confirmation ID: %s', myConfirmationId); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /bin/wallet-create: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var _ = require('lodash'); 4 | var program = require('commander'); 5 | var utils = require('./cli-utils'); 6 | program = utils.configureCommander(program); 7 | 8 | program 9 | .option('-t, --testnet', 'Create a Testnet Wallet') 10 | .option('-p, --password', 'Encrypt wallet. Will ask password interactively') 11 | .option('-c, --coin ', 'coin (btc/bch)') 12 | .usage('[options] [copayerName] ') 13 | .parse(process.argv); 14 | 15 | var args = program.args; 16 | if (!args[0]) 17 | program.help(); 18 | 19 | var walletName = args[0]; 20 | var copayerName = args[2] || process.env.USER; 21 | var passphrase = args[3]; 22 | var network = program.testnet ? 'testnet' : 'livenet'; 23 | var coin = program.coin ? program.coin : 'btc'; 24 | 25 | var mn; 26 | try { 27 | mn = utils.parseMN(args[1]); 28 | } catch (ex) { 29 | utils.die(ex); 30 | } 31 | 32 | utils.getClient(program, { 33 | doNotComplete: true 34 | }, function(client) { 35 | client.seedFromRandomWithMnemonic({ 36 | network: network, 37 | passphrase: passphrase, 38 | language: 'en', 39 | coin: coin, 40 | }); 41 | 42 | client.createWallet(walletName, copayerName, mn[0], mn[1], { 43 | network: network, 44 | coin: coin, 45 | }, function(err, secret) { 46 | utils.die(err); 47 | console.log(' * ' + _.capitalize(network) + ' Wallet Created.'); 48 | utils.saveClient(program, client, { 49 | doNotOverwrite: true 50 | }, function() { 51 | if (secret) { 52 | console.log(' - Secret to share:\n\t' + secret); 53 | } 54 | }); 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /bin/wallet-derive: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var program = require('commander'); 4 | var utils = require('./cli-utils'); 5 | var Bitcore = require('bitcore-wallet-client').Bitcore; 6 | 7 | program = utils.configureCommander(program); 8 | 9 | program 10 | .usage('[options] ') 11 | .description('Derive from an arbitrary path from a private key.'); 12 | 13 | program.on('--help', function() { 14 | console.log(' Examples:'); 15 | console.log(''); 16 | console.log(' $ wallet-derive "m/44\'/0\'/0\'"'); 17 | console.log(' $ wallet-derive "m/1/1"'); 18 | console.log(''); 19 | }); 20 | program.parse(process.argv); 21 | 22 | var args = program.args; 23 | if (!args[0]) 24 | program.help(); 25 | 26 | var path = args[0]; 27 | 28 | function getExtendedPublicKey(client, path) { 29 | var xpriv = client.credentials.xPrivKey; 30 | var derivedXPriv = new Bitcore.HDPrivateKey(xpriv).derive(path); 31 | return derivedXPriv.hdPublicKey.toString(); 32 | }; 33 | 34 | utils.getClient(program, { 35 | mustExist: true 36 | }, function(client) { 37 | var xpub = getExtendedPublicKey(client, path); 38 | var pub = new Bitcore.HDPublicKey(xpub).publicKey; 39 | var address = pub.toAddress().toString(); 40 | console.log('Derived XPub:', xpub, '\nPublic key:', pub.toString(), '\nAddress:', address); 41 | }); 42 | -------------------------------------------------------------------------------- /bin/wallet-export: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var program = require('commander'); 4 | var qr = require('qr-image'); 5 | var fs = require('fs'); 6 | var _ = require('lodash'); 7 | 8 | var utils = require('./cli-utils'); 9 | program = utils.configureCommander(program); 10 | 11 | program 12 | .option('-n, --nosign', 'export wallet credentials without transaction signing keys (extended private key)') 13 | .option('-q, --qr', 'export a QR code') 14 | .option('-e, --exportpassword ', 'a password to encrypt the exported data') 15 | .option('-o, --output ', 'output file'); 16 | 17 | program 18 | .parse(process.argv); 19 | 20 | var args = program.args; 21 | 22 | utils.getClient(program, { doNotComplete: true, mustExist: true }, function (client) { 23 | var x; 24 | try { 25 | x = client.export({ 26 | compressed: !!program.qr, 27 | noSign: !!program.nosign, 28 | password: program.exportpassword, 29 | }); 30 | } catch (ex) { 31 | utils.die(ex); 32 | } 33 | 34 | var access = !!program.nosign ? 'without signing capability' : 'with signing capability'; 35 | if (program.qr) { 36 | var filename = program.file + '.svg'; 37 | var qr_svg = qr.image(x, { 38 | type: 'svg' 39 | }); 40 | qr_svg.pipe(fs.createWriteStream(filename)); 41 | console.log('Wallet data: exported to %s %s.', filename, access); 42 | } else { 43 | if (program.output) { 44 | fs.writeFileSync(program.output, x, { encoding: 'utf8' }); 45 | console.log('Wallet data saved at %s %s.', program.output, access); 46 | } else { 47 | console.log('Wallet data (%s).\n%s', access, x); 48 | } 49 | } 50 | }); 51 | -------------------------------------------------------------------------------- /bin/wallet-genkey: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var _ = require('lodash'); 4 | var program = require('commander'); 5 | var fs = require('fs'); 6 | var utils = require('./cli-utils'); 7 | program = utils.configureCommander(program); 8 | 9 | program 10 | .option('-t, --testnet', 'Create a Testnet Extended Private Key') 11 | .option('-c, --coin ', 'coin (btc/bch)') 12 | .option('-p, --password', 'Encrypt wallet. Will ask password interactively') 13 | .parse(process.argv); 14 | 15 | var args = program.args; 16 | var network = program.testnet ? 'testnet' : 'livenet'; 17 | var coin = program.coin ? 'btc' : 'bch'; 18 | utils.getClient(program, { doNotComplete: true, mustBeNew: true }, function (client) { 19 | client.seedFromRandom({network:network, coin:coin}); 20 | utils.saveClient(program, client, function () { 21 | console.log(' * ' + _.capitalize(network) + '/' + coin + ' Extended Private Key Created.'); 22 | console.log(' To operate with the corresponding public keys from a proxy device, please run `wallet-export --nosign` and then on the proxy device `wallet-import`.'); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /bin/wallet-history: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var _ = require('lodash'); 4 | var fs = require('fs'); 5 | var moment = require('moment'); 6 | var async = require('async'); 7 | var program = require('commander'); 8 | var utils = require('./cli-utils'); 9 | program = utils.configureCommander(program); 10 | 11 | program 12 | .option('-o, --output ', 'get JSON output in file') 13 | .option('-l, --limit ', 'limit history to n transactions') 14 | .option('-i, --info', 'get extra history info') 15 | .option('-t, --format ', 'format csv / json') 16 | .parse(process.argv); 17 | 18 | var args = program.args; 19 | 20 | var skip = 0, total = 0 , 21 | limit = program.limit, got, page = 1000; 22 | console.warn("* TX History:") 23 | 24 | let converter = JSON.stringify.bind(); 25 | 26 | 27 | function formatDate(date) { 28 | var dateObj = new Date(date); 29 | if (!dateObj) { 30 | this.logger.warn('Error formating a date'); 31 | return 'DateError'; 32 | } 33 | if (!dateObj.toJSON()) { 34 | return ''; 35 | } 36 | return dateObj.toJSON(); 37 | } 38 | 39 | 40 | 41 | if (program.format == 'csv') { 42 | converter = function(txs) { 43 | 44 | var ret = ''; 45 | var _amount, _note, _copayers, _creator, _comment; 46 | var csvContent = []; 47 | 48 | // from Copay 49 | txs.forEach(it => { 50 | var amount = it.amount; 51 | if (it.action == 'moved') amount = 0; 52 | 53 | _copayers = ''; 54 | _creator = ''; 55 | 56 | if (it.actions && it.actions.length > 1) { 57 | for (var i = 0; i < it.actions.length; i++) { 58 | _copayers += 59 | it.actions[i].copayerName + ':' + it.actions[i].type + ' - '; 60 | } 61 | _creator = 62 | it.creatorName && it.creatorName != 'undefined' 63 | ? it.creatorName 64 | : ''; 65 | } 66 | _amount = (it.action == 'sent' ? '-' : '') + (amount /1e8).toFixed(8); 67 | _note = it.message || ''; 68 | _comment = it.note ? it.note.body : ''; 69 | 70 | if (it.action == 'moved') 71 | _note += ' Moved:' + (it.amount /1e8).toFixed(8); 72 | 73 | csvContent.push({ 74 | Date: formatDate(it.time * 1000), 75 | Destination: it.addressTo || '', 76 | Description: _note, 77 | Amount: _amount, 78 | Currency: this.currency, 79 | Txid: it.txid, 80 | Creator: _creator, 81 | Copayers: _copayers, 82 | Comment: _comment 83 | }); 84 | 85 | if (it.fees && (it.action == 'moved' || it.action == 'sent')) { 86 | var _fee = (it.fees / 1e8).toFixed(8); 87 | csvContent.push({ 88 | Date: formatDate(it.time * 1000), 89 | Destination: 'Bitcoin Network Fees', 90 | Description: '', 91 | Amount: '-' + _fee, 92 | Currency: this.currency, 93 | Txid: '', 94 | Creator: '', 95 | Copayers: '' 96 | }); 97 | } 98 | 99 | }); 100 | 101 | csvContent.forEach(it => { 102 | ret = ret + `${it.Date},${it.Txid},${it.Destination},${it.Amount}` + "\n"; 103 | }); 104 | return ret; 105 | }; 106 | } else if (program.format == 'json') { 107 | } else if (program.format) { 108 | utils.die('Unknown format ' + program.format); 109 | } 110 | 111 | 112 | var allTxs=[]; 113 | 114 | utils.getClient(program, { mustExist: true }, function (client) { 115 | async.doWhilst( 116 | function(cb) { 117 | client.getTxHistory({ 118 | skip: skip, 119 | limit: page+ 1, 120 | includeExtendedInfo: program.info, 121 | }, function(err, txs) { 122 | if (err) return cb(err); 123 | 124 | if (_.isEmpty(txs)) 125 | return; 126 | 127 | got = txs.length; 128 | if (got > page) { 129 | txs.pop(); 130 | } 131 | 132 | if (program.output) { 133 | allTxs = allTxs.concat(txs); 134 | fs.writeFile(program.output,converter(allTxs), { 135 | encoding: 'utf8' 136 | }, function(err) { 137 | if (err) console.error(err); 138 | console.warn('Output file updated') 139 | }); 140 | } else { 141 | _.each(txs, function(tx) { 142 | var time = moment(tx.time * 1000).fromNow(); 143 | var amount = utils.renderAmount(tx.amount); 144 | var confirmations = tx.confirmations || 0; 145 | var proposal = tx.proposalId ? '["' + tx.message + '" by ' + tx.creatorName + '] ' : ''; 146 | var direction; 147 | switch (tx.action) { 148 | case 'received': 149 | direction = '<='; 150 | break; 151 | case 'moved': 152 | direction = '=='; 153 | break; 154 | case 'sent': 155 | direction = '=>'; 156 | break; 157 | default: 158 | direction = tx.action; 159 | break; 160 | } 161 | console.log("\t%s: %s %s %s %s(%s confirmations)", time, direction, tx.action, amount, proposal, confirmations); 162 | }); 163 | } 164 | return cb(); 165 | }); 166 | }, 167 | function() { 168 | total = total + got; 169 | var cont = got > page && (!limit || total < limit); 170 | if (cont) { 171 | skip+= page; 172 | console.warn('* Skip:', skip); 173 | } 174 | return cont; 175 | }, 176 | function (err) { 177 | if (err) console.log(err); 178 | } 179 | ); 180 | }); 181 | -------------------------------------------------------------------------------- /bin/wallet-import: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var program = require('commander'); 4 | var fs = require('fs'); 5 | var sjcl = require('sjcl'); 6 | var utils = require('./cli-utils'); 7 | program = utils.configureCommander(program); 8 | 9 | program 10 | .option('-c, --coin ', 'coin (btc/bch)') 11 | .option('-t, --testnet', 'testnet network') 12 | .option('-i, --input', 'import from file') 13 | .option('-q, --qr', 'import from a QR code') 14 | .option('-e, --exportpassword ', 'a password to decrypt the data being imported') 15 | .option('-k, --keypassword ', 'password to decrypt private key from imported file') 16 | .option('-p, --password', 'Encrypt wallet. Will ask password interactively') 17 | .usage('[options] [<"backup-words"> | ] ') 18 | .parse(process.argv); 19 | 20 | var args = program.args; 21 | 22 | if (!args[0]) 23 | program.help(); 24 | 25 | utils.getClient(program, { 26 | mustBeNew: true 27 | }, function(client) { 28 | 29 | if (program.input) { 30 | var file = args[0]; 31 | console.log("Importing from file:" + file); 32 | var str; 33 | 34 | try { 35 | str = fs.readFileSync(file, { 36 | encoding: 'utf8' 37 | }); 38 | } catch (e) { 39 | utils.die('Could not import: ' + e); 40 | }; 41 | if (str.substr(0,6) == '{"iv":') { 42 | console.log('Backup is encrypted'); 43 | if (!program.exportpassword) 44 | utils.die('Provide export\'s password with -e '); 45 | try { 46 | str = sjcl.decrypt( program.exportpassword, str); 47 | } catch (e) { 48 | utils.die('Could not decrypt import: ' + e); 49 | }; 50 | }; 51 | 52 | try { 53 | client.import(str, { 54 | compressed: !!program.qr, 55 | password: program.keypassword, 56 | }); 57 | } catch (ex) { 58 | utils.die('Could not import. Check input file and password:' + ex.message); 59 | } 60 | 61 | utils.saveClient(program, client, function() { 62 | var access = client.canSign() ? 'with signing capability' : 'without signing capability'; 63 | console.log('Wallet Imported ' + access + '.'); 64 | }); 65 | } else { 66 | console.log("Importing from mnemonic"); 67 | var mnemonics = args[0]; 68 | var passphrase = args[1]; 69 | var network = program.testnet ? 'testnet' : 'livenet'; 70 | var coin = program.coin ? program.coin : 'btc'; 71 | client.importFromMnemonic(mnemonics, { 72 | network: network, 73 | passphrase: passphrase, 74 | coin: coin, 75 | }, function(err) { 76 | if (err) 77 | utils.die('Could not import' + err); 78 | 79 | utils.saveClient(program, client, function() { 80 | var access = client.canSign() ? 'with signing capability' : 'without signing capability'; 81 | console.log('Wallet Imported ' + access + '.'); 82 | }); 83 | }); 84 | } 85 | }); 86 | -------------------------------------------------------------------------------- /bin/wallet-join: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var program = require('commander'); 4 | var utils = require('./cli-utils'); 5 | program = utils.configureCommander(program); 6 | 7 | program 8 | .usage('[options] [copayerName]') 9 | .option('-p, --password', 'Encrypt wallet. Will ask password interactively') 10 | .parse(process.argv); 11 | 12 | var args = program.args; 13 | if (!args[0]) 14 | program.help(); 15 | 16 | var secret = args[0]; 17 | var copayerName = args[1] || process.env.USER; 18 | 19 | utils.getClient(program, { doNotComplete: true }, function (client) { 20 | client.joinWallet(secret, copayerName, {}, function(err, wallet) { 21 | utils.die(err); 22 | console.log(' * Wallet Joined.', wallet.name); 23 | utils.saveClient(program, client, function () {}); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /bin/wallet-mnemonic: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var program = require('commander'); 4 | var utils = require('./cli-utils'); 5 | program = utils.configureCommander(program); 6 | 7 | program 8 | .parse(process.argv); 9 | 10 | var args = program.args; 11 | 12 | utils.getClient(program, { 13 | mustExist: true 14 | }, function(client) { 15 | var mnemonic = client.getMnemonic(); 16 | console.log('* Wallet seed: %s', mnemonic); 17 | }); 18 | -------------------------------------------------------------------------------- /bin/wallet-recreate: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var _ = require('lodash'); 4 | var program = require('commander'); 5 | var utils = require('./cli-utils'); 6 | program = utils.configureCommander(program); 7 | 8 | program 9 | .usage('[options]') 10 | .description('Creates a wallet on the remote server given the local information') 11 | .parse(process.argv); 12 | 13 | var args = program.args; 14 | utils.getClient(program, { mustExist: true }, function (client) { 15 | client.recreateWallet(function(err) { 16 | utils.die(err); 17 | console.log(' * Wallet created.'); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /bin/wallet-reject: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var _ = require('lodash'); 4 | var program = require('commander'); 5 | var utils = require('./cli-utils'); 6 | program = utils.configureCommander(program); 7 | 8 | program 9 | .usage('[options] [reason]') 10 | .parse(process.argv); 11 | 12 | var args = program.args; 13 | var txpid = args[0] || ''; 14 | var reason = args[1] || ''; 15 | 16 | utils.getClient(program, { mustExist: true }, function (client) { 17 | client.getTxProposals({}, function(err, txps) { 18 | utils.die(err); 19 | 20 | var txp = utils.findOneTxProposal(txps, txpid); 21 | client.rejectTxProposal(txp, reason, function(err, tx) { 22 | utils.die(err); 23 | if (tx.status == 'rejected') 24 | console.log('Transaction finally rejected.'); 25 | else 26 | console.log('Transaction rejected by you.'); 27 | }); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /bin/wallet-rm: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var _ = require('lodash'); 4 | var program = require('commander'); 5 | var utils = require('./cli-utils'); 6 | program = utils.configureCommander(program); 7 | 8 | program 9 | .usage('[options] ') 10 | .parse(process.argv); 11 | 12 | var args = program.args; 13 | var txpid = args[0] || ''; 14 | 15 | utils.getClient(program, { mustExist: true }, function (client) { 16 | client.getTxProposals({}, function(err, txps) { 17 | utils.die(err); 18 | 19 | if (program.verbose) 20 | console.log('* Raw Server Response:\n', txps); //TODO 21 | 22 | var txp = utils.findOneTxProposal(txps, txpid); 23 | client.removeTxProposal(txp, function(err) { 24 | utils.die(err); 25 | 26 | console.log('Transaction removed.'); 27 | }); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /bin/wallet-scan: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var _ = require('lodash'); 4 | var program = require('commander'); 5 | var utils = require('./cli-utils'); 6 | program = utils.configureCommander(program); 7 | 8 | program 9 | .usage('[options]') 10 | .description('Scan wallets addresses for funds') 11 | .parse(process.argv); 12 | 13 | var args = program.args; 14 | utils.getClient(program, { mustExist: true }, function (client) { 15 | client.startScan({}, function(err) { 16 | utils.die(err); 17 | console.log(' * Scan started. Check with `wallet-status`.'); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /bin/wallet-send: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var program = require('commander'); 4 | var utils = require('./cli-utils'); 5 | var _ = require('lodash'); 6 | var bwc = require('bitcore-wallet-client'); 7 | var Bitcore_ = { 8 | bch: bwc.BitcoreCash, 9 | btc: bwc.Bitcore, 10 | }; 11 | 12 | program = utils.configureCommander(program); 13 | 14 | program 15 | .option('--fee ', 'Fee per kB to use. Default 100bits.') 16 | .usage('[options]
[note]') 17 | .description('Create a proposal for sending bitcoins to a destination address.\n The amount can be specified in bit, btc or sat (the default).'); 18 | 19 | program.on('--help', function() { 20 | console.log(' Examples:'); 21 | console.log(''); 22 | console.log(' $ wallet-send n2HRFgtoihgAhx1qAEXcdBMjoMvAx7AcDc 500bit'); 23 | console.log(' $ wallet-send mgWeRvUC6d1LRPKtdDbvYEpaUEmApS4XrY 0.2btc "dinner with friends"'); 24 | console.log(' $ wallet-send https://paypro.url/1234 # will ask for confirmation '); 25 | console.log(''); 26 | }); 27 | program.parse(process.argv); 28 | 29 | var args = program.args; 30 | if (!args[0]) 31 | program.help(); 32 | 33 | 34 | function confirmDiag(amountStr, note, cb) { 35 | const readline = require('readline'); 36 | 37 | const rl = readline.createInterface({ 38 | input: process.stdin, 39 | output: process.stdout 40 | }); 41 | 42 | rl.question(`Confirm send ${amountStr} to ${note}? (y/N)`, (answer) => { 43 | rl.close(); 44 | return cb(answer =='y'); 45 | }); 46 | }; 47 | 48 | 49 | function send(client, address, amount, fee, note, uri) { 50 | var amount, feePerKb; 51 | try { 52 | feePerKb = !_.isUndefined(fee) ? utils.parseAmount(fee) : 100e2; 53 | } catch (ex) { 54 | utils.die(ex); 55 | } 56 | 57 | 58 | client.createTxProposal({ 59 | outputs: [{ 60 | toAddress: address, 61 | amount: amount, 62 | }], 63 | message: note, 64 | feePerKb: feePerKb, 65 | payProUrl: uri, 66 | }, function(err, txp) { 67 | utils.die(err); 68 | client.publishTxProposal({ 69 | txp: txp 70 | }, function(err) { 71 | utils.die(err); 72 | console.log(' * Tx created: ID %s [%s] RequiredSignatures:', 73 | utils.shortID(txp.id), txp.status, txp.requiredSignatures); 74 | }); 75 | }); 76 | }; 77 | 78 | 79 | var arg1 = args[0]; 80 | var uri; 81 | 82 | 83 | 84 | utils.getClient(program, { 85 | mustExist: true 86 | }, function(client) { 87 | var coin = client.credentials.coin; 88 | var bitcore = Bitcore_[coin]; 89 | 90 | var uri, addr, amount, note; 91 | 92 | // no backwards compat uri 93 | if ((/^bitcoin(cash)?:\?r=[\w+]/).exec(arg1)) { 94 | var coin2 = 'btc'; 95 | if (arg1.indexOf('bitcoincash') === 0) coin2 = 'bch'; 96 | if (coin != coin2) utils.die('Wallet / Payment Coin mismatch'); 97 | uri = arg1.replace(/bitcoin(cash)?:\?r=/, ''); 98 | 99 | } else { 100 | 101 | // BIP21 102 | try { 103 | 104 | var parsed = new bitcore.URI(arg1); 105 | if (!parsed.r) { 106 | 107 | addr = parsed.address ? parsed.address.toString() : ''; 108 | note = parsed.message; 109 | amount = parsed.amount ? parsed.amount : ''; 110 | 111 | } else { 112 | uri = parsed.r; 113 | } 114 | } catch (e) { 115 | uri = null; 116 | } 117 | } 118 | 119 | //Send to URI or addr 120 | 121 | if (uri) { 122 | console.log('Fetching Payment from: ' + uri); 123 | client.fetchPayPro({ 124 | payProUrl: uri, 125 | }, function(err, paypro) { 126 | if (err) { 127 | utils.die(' Failed to fetch payment: ' + err); 128 | } else if (!paypro.verified) { 129 | utils.die('Failed to verify payment protocol signatures'); 130 | } 131 | 132 | var amountStr = utils.renderAmount(paypro.amount, coin); 133 | confirmDiag(amountStr, paypro.memo, function(confirmed) { 134 | if (!confirmed) utils.die('User canceled'); 135 | send(client, paypro.toAddress, paypro.amount, program.fee, paypro.memo, uri); 136 | }); 137 | }); 138 | } else { 139 | 140 | // Grab data from CLI if not set before 141 | addr = addr || arg1; 142 | amount = amount || utils.parseAmount(args[1]); 143 | note = note || args[2]; 144 | 145 | send(client, addr, amount, program.fee, note); 146 | } 147 | }); 148 | -------------------------------------------------------------------------------- /bin/wallet-sign: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var _ = require('lodash'); 4 | var fs = require('fs'); 5 | var program = require('commander'); 6 | var utils = require('./cli-utils'); 7 | program = utils.configureCommander(program); 8 | 9 | program 10 | .usage('[options] ') 11 | .option('-i, --input [filename]', 'use signatures from file') 12 | .parse(process.argv); 13 | 14 | var args = program.args; 15 | var txpid = args[0] || ''; 16 | 17 | function processBatch(client, signatures) { 18 | client.getTxProposals({}, function(err, txps) { 19 | utils.die(err); 20 | 21 | var selected = []; 22 | if (txpid) { 23 | txp = utils.findOneTxProposal(txps, txpid); 24 | selected.push(txp); 25 | } else { 26 | if (txps.length == 0) { 27 | utils.die('There are no pending transaction proposals.'); 28 | } 29 | selected = txps; 30 | } 31 | 32 | _.each(selected, function (txp) { 33 | var sigs = _.find(signatures, { txpId: txp.id }); 34 | if (sigs) { 35 | txp.signatures = sigs.signatures; 36 | client.signTxProposal(txp, function(err, tx) { 37 | utils.die(err); 38 | console.log('Transaction %s signed by you.', txp.id); 39 | }); 40 | } 41 | }); 42 | }); 43 | }; 44 | 45 | utils.getClient(program, { mustExist: true }, function (client) { 46 | if (program.input) { 47 | var inFile = JSON.parse(fs.readFileSync(program.input)); 48 | processBatch(client, inFile); 49 | } else { 50 | client.getTxProposals({}, function(err, txps) { 51 | utils.die(err); 52 | var txp = utils.findOneTxProposal(txps, txpid); 53 | client.signTxProposal(txp, function(err, tx) { 54 | utils.die(err); 55 | console.log('Transaction signed by you.'); 56 | }); 57 | }); 58 | } 59 | }); 60 | -------------------------------------------------------------------------------- /bin/wallet-status: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var _ = require('lodash'); 4 | var program = require('commander'); 5 | var utils = require('./cli-utils'); 6 | program = utils.configureCommander(program); 7 | 8 | program 9 | .option('-v, --verbose', 'Show wallet raw data') 10 | .parse(process.argv); 11 | 12 | var args = program.args; 13 | utils.getClient(program, { mustExist: true }, function (client) { 14 | client.getStatus({}, function(err, res) { 15 | utils.die(err); 16 | 17 | var x = res.wallet; 18 | console.log('* Wallet %s [%s]: %d-of-%d %s Coin:%s ', x.name, x.network, x.m, x.n, x.status, x.coin); 19 | 20 | if (x.status != 'complete') { 21 | console.log(' Missing copayers:', x.n - x.copayers.length); 22 | console.log(' Wallet secret:', x.secret); 23 | } 24 | console.log('* Copayers:', _.map(x.copayers,'name').join(', ')); 25 | 26 | 27 | if (program.verbose) { 28 | console.log('* Wallet Raw Data:', x); 29 | } 30 | 31 | var x = res.balance; 32 | console.log('* Balance %s (Locked: %s)', utils.renderAmount(x.totalAmount), utils.renderAmount(x.lockedAmount)); 33 | 34 | utils.renderTxProposals(res.pendingTxps); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /bin/wallet-txproposals: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var _ = require('lodash'); 4 | var fs = require('fs'); 5 | var program = require('commander'); 6 | var utils = require('./cli-utils'); 7 | program = utils.configureCommander(program); 8 | 9 | program 10 | .option('-o, --output [filename]', 'write tx to output file for air-gapped signing') 11 | .parse(process.argv); 12 | 13 | var args = program.args; 14 | 15 | utils.getClient(program, { mustExist: true }, function (client) { 16 | client.getTxProposals({forAirGapped: !!program.output}, function (err, res) { 17 | utils.die(err); 18 | 19 | if (program.output) { 20 | fs.writeFileSync(program.output, JSON.stringify(res)); 21 | console.log(' * Tx proposals saved to: %s\n', program.output); 22 | } else { 23 | utils.renderTxProposals(res); 24 | } 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bitcore-wallet", 3 | "version": "1.2.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "ansi": { 8 | "version": "0.3.1", 9 | "resolved": "https://registry.npmjs.org/ansi/-/ansi-0.3.1.tgz", 10 | "integrity": "sha1-DELU+xcWDVqa8eSEus4cZpIsGyE=" 11 | }, 12 | "ansi-regex": { 13 | "version": "2.1.1", 14 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", 15 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" 16 | }, 17 | "are-we-there-yet": { 18 | "version": "1.0.6", 19 | "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.0.6.tgz", 20 | "integrity": "sha1-otKMkxAqpsyWJFomy5VN4G7FPww=", 21 | "requires": { 22 | "delegates": "^1.0.0", 23 | "readable-stream": "^2.0.0 || ^1.1.13" 24 | } 25 | }, 26 | "ascli": { 27 | "version": "1.0.1", 28 | "resolved": "https://registry.npmjs.org/ascli/-/ascli-1.0.1.tgz", 29 | "integrity": "sha1-vPpZdKYvGOgcq660lzKrSoj5Brw=", 30 | "requires": { 31 | "colour": "~0.7.1", 32 | "optjs": "~3.2.2" 33 | } 34 | }, 35 | "asn1.js": { 36 | "version": "5.0.1", 37 | "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.0.1.tgz", 38 | "integrity": "sha512-aO8EaEgbgqq77IEw+1jfx5c9zTbzvkfuRBuZsSsPnTHMkmd5AI4J6OtITLZFa381jReeaQL67J0GBTUu0+ZTVw==", 39 | "requires": { 40 | "bn.js": "^4.0.0", 41 | "inherits": "^2.0.1", 42 | "minimalistic-assert": "^1.0.0" 43 | } 44 | }, 45 | "asn1.js-rfc3280": { 46 | "version": "4.0.0", 47 | "resolved": "https://registry.npmjs.org/asn1.js-rfc3280/-/asn1.js-rfc3280-4.0.0.tgz", 48 | "integrity": "sha1-EBA54GJrzH5XFEeGDjSnZuPUmCU=" 49 | }, 50 | "asn1.js-rfc5280": { 51 | "version": "3.0.0", 52 | "resolved": "https://registry.npmjs.org/asn1.js-rfc5280/-/asn1.js-rfc5280-3.0.0.tgz", 53 | "integrity": "sha512-Y2LZPOWeZ6qehv698ZgOGGCZXBQShObWnGthTrIFlIQjuV1gg2B8QOhWFRExq/MR1VnPpIIe7P9vX2vElxv+Pg==", 54 | "requires": { 55 | "asn1.js": "^5.0.0" 56 | } 57 | }, 58 | "assertion-error": { 59 | "version": "1.1.0", 60 | "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", 61 | "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", 62 | "dev": true 63 | }, 64 | "async": { 65 | "version": "2.6.1", 66 | "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", 67 | "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", 68 | "requires": { 69 | "lodash": "^4.17.10" 70 | }, 71 | "dependencies": { 72 | "lodash": { 73 | "version": "4.17.11", 74 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", 75 | "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" 76 | } 77 | } 78 | }, 79 | "asynckit": { 80 | "version": "0.4.0", 81 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 82 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" 83 | }, 84 | "balanced-match": { 85 | "version": "1.0.0", 86 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 87 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" 88 | }, 89 | "base-x": { 90 | "version": "3.0.5", 91 | "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.5.tgz", 92 | "integrity": "sha512-C3picSgzPSLE+jW3tcBzJoGwitOtazb5B+5YmAxZm2ybmTi9LNgAtDO/jjVEBZwHoXmDBZ9m/IELj3elJVRBcA==", 93 | "requires": { 94 | "safe-buffer": "^5.0.1" 95 | } 96 | }, 97 | "bigi": { 98 | "version": "1.4.2", 99 | "resolved": "https://registry.npmjs.org/bigi/-/bigi-1.4.2.tgz", 100 | "integrity": "sha1-nGZalfiLiwj8Bc/XMfVhhZ1yWCU=" 101 | }, 102 | "bip38": { 103 | "version": "1.4.0", 104 | "resolved": "https://registry.npmjs.org/bip38/-/bip38-1.4.0.tgz", 105 | "integrity": "sha1-uNsw/xgwFt3eLO+0mzBVho6N8y0=", 106 | "requires": { 107 | "bigi": "^1.2.0", 108 | "browserify-aes": "^1.0.1", 109 | "buffer-xor": "^1.0.2", 110 | "coinstring": "^2.2.0", 111 | "create-hash": "^1.1.1", 112 | "ecurve": "^1.0.0", 113 | "scryptsy": "^1.2.0" 114 | } 115 | }, 116 | "bitcore-lib": { 117 | "version": "0.16.0", 118 | "resolved": "https://registry.npmjs.org/bitcore-lib/-/bitcore-lib-0.16.0.tgz", 119 | "integrity": "sha512-CEtcrPAH2gwgaMN+OPMJc18TBEak1+TtzMyafrqrIbK9PIa3kat195qBJhC0liJSHRiRr6IE2eLcXeIFFs+U8w==", 120 | "requires": { 121 | "bn.js": "=4.11.8", 122 | "bs58": "=4.0.1", 123 | "buffer-compare": "=1.1.1", 124 | "elliptic": "=6.4.0", 125 | "inherits": "=2.0.1", 126 | "lodash": "=4.17.11" 127 | }, 128 | "dependencies": { 129 | "bs58": { 130 | "version": "4.0.1", 131 | "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", 132 | "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", 133 | "requires": { 134 | "base-x": "^3.0.2" 135 | } 136 | }, 137 | "inherits": { 138 | "version": "2.0.1", 139 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", 140 | "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" 141 | }, 142 | "lodash": { 143 | "version": "4.17.11", 144 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", 145 | "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" 146 | } 147 | } 148 | }, 149 | "bitcore-lib-cash": { 150 | "version": "0.19.0", 151 | "resolved": "https://registry.npmjs.org/bitcore-lib-cash/-/bitcore-lib-cash-0.19.0.tgz", 152 | "integrity": "sha512-JBD30YS5M2OSUPbXggM257FjWXb5A1pHFn88lZQsqOokgddmdwp45K4APVEsj2iaKLR7uLOnGppSbAWj5Hihwg==", 153 | "requires": { 154 | "bn.js": "=4.11.8", 155 | "bs58": "=4.0.1", 156 | "buffer-compare": "=1.1.1", 157 | "elliptic": "=6.4.0", 158 | "inherits": "=2.0.1", 159 | "lodash": "=4.17.11" 160 | }, 161 | "dependencies": { 162 | "bs58": { 163 | "version": "4.0.1", 164 | "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", 165 | "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", 166 | "requires": { 167 | "base-x": "^3.0.2" 168 | } 169 | }, 170 | "inherits": { 171 | "version": "2.0.1", 172 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", 173 | "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" 174 | }, 175 | "lodash": { 176 | "version": "4.17.11", 177 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", 178 | "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" 179 | } 180 | } 181 | }, 182 | "bitcore-mnemonic": { 183 | "version": "1.7.0", 184 | "resolved": "https://registry.npmjs.org/bitcore-mnemonic/-/bitcore-mnemonic-1.7.0.tgz", 185 | "integrity": "sha512-1JV1okgz9Vv+Y4fG2m3ToR+BGdKA6tSoqjepIxA95BZjW6YaeopVW4iOe/dY9dnkZH4+LA2AJ4YbDE6H3ih3Yw==", 186 | "requires": { 187 | "bitcore-lib": "^0.16.0", 188 | "unorm": "^1.4.1" 189 | } 190 | }, 191 | "bitcore-payment-protocol": { 192 | "version": "1.8.0", 193 | "resolved": "https://registry.npmjs.org/bitcore-payment-protocol/-/bitcore-payment-protocol-1.8.0.tgz", 194 | "integrity": "sha512-1+C4KbcRbeXKo6YQh+n5THVNU6V9uWZB/A2v9ZWAr/Opf4dX/OIMzacI9E7Y5/sBaAPnJs/LzukpmsR9AKmpfQ==", 195 | "requires": { 196 | "asn1.js": "^5.0.1", 197 | "asn1.js-rfc3280": "^4.0.0", 198 | "asn1.js-rfc5280": "^3.0.0", 199 | "bs58": "^4.0.1", 200 | "jsrsasign": "^8.0.12", 201 | "protobufjs": "=5.0.3" 202 | }, 203 | "dependencies": { 204 | "bs58": { 205 | "version": "4.0.1", 206 | "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", 207 | "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", 208 | "requires": { 209 | "base-x": "^3.0.2" 210 | } 211 | } 212 | } 213 | }, 214 | "bitcore-wallet-client": { 215 | "version": "6.8.1", 216 | "resolved": "https://registry.npmjs.org/bitcore-wallet-client/-/bitcore-wallet-client-6.8.1.tgz", 217 | "integrity": "sha512-hX6ttm5iMwxbGHZ/Jci+fWz4K+fyWljJZkWQ8Yipa6jmsfN/ucG4VL20YJlAZ0wz4kn3sDww/dw1H+uokIxN/A==", 218 | "requires": { 219 | "async": "^0.9.0", 220 | "bip38": "^1.3.0", 221 | "bitcore-lib": "=0.16.0", 222 | "bitcore-lib-cash": "=0.19.0", 223 | "bitcore-mnemonic": "^1.3.0", 224 | "bitcore-payment-protocol": "^1.7.0", 225 | "json-stable-stringify": "^1.0.0", 226 | "lodash": "^4.17.11", 227 | "preconditions": "^2.2.1", 228 | "sjcl": "1.0.3", 229 | "superagent": "^3.4.1" 230 | }, 231 | "dependencies": { 232 | "async": { 233 | "version": "0.9.2", 234 | "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", 235 | "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=" 236 | }, 237 | "lodash": { 238 | "version": "4.17.11", 239 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", 240 | "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" 241 | }, 242 | "sjcl": { 243 | "version": "1.0.3", 244 | "resolved": "https://registry.npmjs.org/sjcl/-/sjcl-1.0.3.tgz", 245 | "integrity": "sha1-TtSGSY7Wt0K11KIZAiaBFvBUpwk=" 246 | } 247 | } 248 | }, 249 | "bn.js": { 250 | "version": "4.11.8", 251 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", 252 | "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" 253 | }, 254 | "brace-expansion": { 255 | "version": "1.1.11", 256 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 257 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 258 | "requires": { 259 | "balanced-match": "^1.0.0", 260 | "concat-map": "0.0.1" 261 | } 262 | }, 263 | "brorand": { 264 | "version": "1.1.0", 265 | "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", 266 | "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" 267 | }, 268 | "browserify-aes": { 269 | "version": "1.2.0", 270 | "resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", 271 | "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", 272 | "requires": { 273 | "buffer-xor": "^1.0.3", 274 | "cipher-base": "^1.0.0", 275 | "create-hash": "^1.1.0", 276 | "evp_bytestokey": "^1.0.3", 277 | "inherits": "^2.0.1", 278 | "safe-buffer": "^5.0.1" 279 | } 280 | }, 281 | "bs58": { 282 | "version": "2.0.1", 283 | "resolved": "https://registry.npmjs.org/bs58/-/bs58-2.0.1.tgz", 284 | "integrity": "sha1-VZCNWPGYKrogCPob7Y+RmYopv40=" 285 | }, 286 | "buffer-compare": { 287 | "version": "1.1.1", 288 | "resolved": "https://registry.npmjs.org/buffer-compare/-/buffer-compare-1.1.1.tgz", 289 | "integrity": "sha1-W+e+hTr4kZjR9N3AkNHWakiu9ZY=" 290 | }, 291 | "buffer-xor": { 292 | "version": "1.0.3", 293 | "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", 294 | "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" 295 | }, 296 | "bytebuffer": { 297 | "version": "5.0.1", 298 | "resolved": "https://registry.npmjs.org/bytebuffer/-/bytebuffer-5.0.1.tgz", 299 | "integrity": "sha1-WC7qSxqHO20CCkjVjfhfC7ps/d0=", 300 | "requires": { 301 | "long": "~3" 302 | } 303 | }, 304 | "camelcase": { 305 | "version": "2.1.1", 306 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", 307 | "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=" 308 | }, 309 | "chai": { 310 | "version": "3.5.0", 311 | "resolved": "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz", 312 | "integrity": "sha1-TQJjewZ/6Vi9v906QOxW/vc3Mkc=", 313 | "dev": true, 314 | "requires": { 315 | "assertion-error": "^1.0.1", 316 | "deep-eql": "^0.1.3", 317 | "type-detect": "^1.0.0" 318 | } 319 | }, 320 | "cipher-base": { 321 | "version": "1.0.4", 322 | "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", 323 | "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", 324 | "requires": { 325 | "inherits": "^2.0.1", 326 | "safe-buffer": "^5.0.1" 327 | } 328 | }, 329 | "cliui": { 330 | "version": "3.2.0", 331 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", 332 | "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", 333 | "requires": { 334 | "string-width": "^1.0.1", 335 | "strip-ansi": "^3.0.1", 336 | "wrap-ansi": "^2.0.0" 337 | } 338 | }, 339 | "code-point-at": { 340 | "version": "1.1.0", 341 | "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", 342 | "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" 343 | }, 344 | "coinstring": { 345 | "version": "2.3.0", 346 | "resolved": "https://registry.npmjs.org/coinstring/-/coinstring-2.3.0.tgz", 347 | "integrity": "sha1-zbYzY6lhUCQEolr7gsLibV/2J6Q=", 348 | "requires": { 349 | "bs58": "^2.0.1", 350 | "create-hash": "^1.1.1" 351 | } 352 | }, 353 | "colour": { 354 | "version": "0.7.1", 355 | "resolved": "https://registry.npmjs.org/colour/-/colour-0.7.1.tgz", 356 | "integrity": "sha1-nLFpkX7F0SwHNtPoaFdG3xyt93g=" 357 | }, 358 | "combined-stream": { 359 | "version": "1.0.7", 360 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", 361 | "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", 362 | "requires": { 363 | "delayed-stream": "~1.0.0" 364 | } 365 | }, 366 | "commander": { 367 | "version": "2.18.0", 368 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.18.0.tgz", 369 | "integrity": "sha512-6CYPa+JP2ftfRU2qkDK+UTVeQYosOg/2GbcjIcKPHfinyOLPVGXu/ovN86RP49Re5ndJK1N0kuiidFFuepc4ZQ==" 370 | }, 371 | "component-emitter": { 372 | "version": "1.2.1", 373 | "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", 374 | "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" 375 | }, 376 | "concat-map": { 377 | "version": "0.0.1", 378 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 379 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" 380 | }, 381 | "cookiejar": { 382 | "version": "2.1.2", 383 | "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", 384 | "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==" 385 | }, 386 | "core-util-is": { 387 | "version": "1.0.2", 388 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 389 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 390 | }, 391 | "create-hash": { 392 | "version": "1.2.0", 393 | "resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", 394 | "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", 395 | "requires": { 396 | "cipher-base": "^1.0.1", 397 | "inherits": "^2.0.1", 398 | "md5.js": "^1.3.4", 399 | "ripemd160": "^2.0.1", 400 | "sha.js": "^2.4.0" 401 | } 402 | }, 403 | "create-hmac": { 404 | "version": "1.1.7", 405 | "resolved": "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", 406 | "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", 407 | "requires": { 408 | "cipher-base": "^1.0.3", 409 | "create-hash": "^1.1.0", 410 | "inherits": "^2.0.1", 411 | "ripemd160": "^2.0.0", 412 | "safe-buffer": "^5.0.1", 413 | "sha.js": "^2.4.8" 414 | } 415 | }, 416 | "debug": { 417 | "version": "3.2.6", 418 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", 419 | "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", 420 | "requires": { 421 | "ms": "^2.1.1" 422 | } 423 | }, 424 | "decamelize": { 425 | "version": "1.2.0", 426 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", 427 | "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" 428 | }, 429 | "deep-eql": { 430 | "version": "0.1.3", 431 | "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", 432 | "integrity": "sha1-71WKyrjeJSBs1xOQbXTlaTDrafI=", 433 | "dev": true, 434 | "requires": { 435 | "type-detect": "0.1.1" 436 | }, 437 | "dependencies": { 438 | "type-detect": { 439 | "version": "0.1.1", 440 | "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz", 441 | "integrity": "sha1-C6XsKohWQORw6k6FBZcZANrFiCI=", 442 | "dev": true 443 | } 444 | } 445 | }, 446 | "delayed-stream": { 447 | "version": "1.0.0", 448 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 449 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" 450 | }, 451 | "delegates": { 452 | "version": "1.0.0", 453 | "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", 454 | "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" 455 | }, 456 | "ecurve": { 457 | "version": "1.0.6", 458 | "resolved": "https://registry.npmjs.org/ecurve/-/ecurve-1.0.6.tgz", 459 | "integrity": "sha512-/BzEjNfiSuB7jIWKcS/z8FK9jNjmEWvUV2YZ4RLSmcDtP7Lq0m6FvDuSnJpBlDpGRpfRQeTLGLBI8H+kEv0r+w==", 460 | "requires": { 461 | "bigi": "^1.1.0", 462 | "safe-buffer": "^5.0.1" 463 | } 464 | }, 465 | "elliptic": { 466 | "version": "6.4.0", 467 | "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz", 468 | "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=", 469 | "requires": { 470 | "bn.js": "^4.4.0", 471 | "brorand": "^1.0.1", 472 | "hash.js": "^1.0.0", 473 | "hmac-drbg": "^1.0.0", 474 | "inherits": "^2.0.1", 475 | "minimalistic-assert": "^1.0.0", 476 | "minimalistic-crypto-utils": "^1.0.0" 477 | } 478 | }, 479 | "errr": { 480 | "version": "2.2.1", 481 | "resolved": "https://registry.npmjs.org/errr/-/errr-2.2.1.tgz", 482 | "integrity": "sha1-H+eLb7KS0mXGJcBqfsmjsy4blt8=" 483 | }, 484 | "evp_bytestokey": { 485 | "version": "1.0.3", 486 | "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", 487 | "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", 488 | "requires": { 489 | "md5.js": "^1.3.4", 490 | "safe-buffer": "^5.1.1" 491 | } 492 | }, 493 | "extend": { 494 | "version": "3.0.2", 495 | "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", 496 | "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" 497 | }, 498 | "form-data": { 499 | "version": "2.3.3", 500 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", 501 | "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", 502 | "requires": { 503 | "asynckit": "^0.4.0", 504 | "combined-stream": "^1.0.6", 505 | "mime-types": "^2.1.12" 506 | } 507 | }, 508 | "formatio": { 509 | "version": "1.1.1", 510 | "resolved": "https://registry.npmjs.org/formatio/-/formatio-1.1.1.tgz", 511 | "integrity": "sha1-XtPM1jZVEJc4NGXZlhmRAOhhYek=", 512 | "dev": true, 513 | "requires": { 514 | "samsam": "~1.1" 515 | } 516 | }, 517 | "formidable": { 518 | "version": "1.2.1", 519 | "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.1.tgz", 520 | "integrity": "sha512-Fs9VRguL0gqGHkXS5GQiMCr1VhZBxz0JnJs4JmMp/2jL18Fmbzvv7vOFRU+U8TBkHEE/CX1qDXzJplVULgsLeg==" 521 | }, 522 | "fs.realpath": { 523 | "version": "1.0.0", 524 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 525 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" 526 | }, 527 | "gauge": { 528 | "version": "1.2.7", 529 | "resolved": "https://registry.npmjs.org/gauge/-/gauge-1.2.7.tgz", 530 | "integrity": "sha1-6c7FSD09TuDvRLYKfZnkk14TbZM=", 531 | "requires": { 532 | "ansi": "^0.3.0", 533 | "has-unicode": "^2.0.0", 534 | "lodash.pad": "^4.1.0", 535 | "lodash.padend": "^4.1.0", 536 | "lodash.padstart": "^4.1.0" 537 | } 538 | }, 539 | "glob": { 540 | "version": "7.1.3", 541 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", 542 | "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", 543 | "requires": { 544 | "fs.realpath": "^1.0.0", 545 | "inflight": "^1.0.4", 546 | "inherits": "2", 547 | "minimatch": "^3.0.4", 548 | "once": "^1.3.0", 549 | "path-is-absolute": "^1.0.0" 550 | } 551 | }, 552 | "has-unicode": { 553 | "version": "2.0.1", 554 | "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", 555 | "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" 556 | }, 557 | "hash-base": { 558 | "version": "3.0.4", 559 | "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", 560 | "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", 561 | "requires": { 562 | "inherits": "^2.0.1", 563 | "safe-buffer": "^5.0.1" 564 | } 565 | }, 566 | "hash.js": { 567 | "version": "1.1.7", 568 | "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", 569 | "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", 570 | "requires": { 571 | "inherits": "^2.0.3", 572 | "minimalistic-assert": "^1.0.1" 573 | } 574 | }, 575 | "hmac-drbg": { 576 | "version": "1.0.1", 577 | "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", 578 | "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", 579 | "requires": { 580 | "hash.js": "^1.0.3", 581 | "minimalistic-assert": "^1.0.0", 582 | "minimalistic-crypto-utils": "^1.0.1" 583 | } 584 | }, 585 | "inflight": { 586 | "version": "1.0.6", 587 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 588 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 589 | "requires": { 590 | "once": "^1.3.0", 591 | "wrappy": "1" 592 | } 593 | }, 594 | "inherits": { 595 | "version": "2.0.3", 596 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 597 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 598 | }, 599 | "invert-kv": { 600 | "version": "1.0.0", 601 | "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", 602 | "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" 603 | }, 604 | "is-fullwidth-code-point": { 605 | "version": "1.0.0", 606 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", 607 | "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", 608 | "requires": { 609 | "number-is-nan": "^1.0.0" 610 | } 611 | }, 612 | "isarray": { 613 | "version": "1.0.0", 614 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 615 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" 616 | }, 617 | "json-stable-stringify": { 618 | "version": "1.0.1", 619 | "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", 620 | "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", 621 | "requires": { 622 | "jsonify": "~0.0.0" 623 | } 624 | }, 625 | "jsonify": { 626 | "version": "0.0.0", 627 | "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", 628 | "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" 629 | }, 630 | "jsrsasign": { 631 | "version": "8.0.12", 632 | "resolved": "https://registry.npmjs.org/jsrsasign/-/jsrsasign-8.0.12.tgz", 633 | "integrity": "sha1-Iqu5ZW00owuVMENnIINeicLlwxY=" 634 | }, 635 | "lcid": { 636 | "version": "1.0.0", 637 | "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", 638 | "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", 639 | "requires": { 640 | "invert-kv": "^1.0.0" 641 | } 642 | }, 643 | "lodash": { 644 | "version": "4.17.11", 645 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", 646 | "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" 647 | }, 648 | "lodash.pad": { 649 | "version": "4.5.1", 650 | "resolved": "https://registry.npmjs.org/lodash.pad/-/lodash.pad-4.5.1.tgz", 651 | "integrity": "sha1-QzCUmoM6fI2iLMIPaibE1Z3runA=" 652 | }, 653 | "lodash.padend": { 654 | "version": "4.6.1", 655 | "resolved": "https://registry.npmjs.org/lodash.padend/-/lodash.padend-4.6.1.tgz", 656 | "integrity": "sha1-U8y6BH0G4VjTEfRdpiX05J5vFm4=" 657 | }, 658 | "lodash.padstart": { 659 | "version": "4.6.1", 660 | "resolved": "https://registry.npmjs.org/lodash.padstart/-/lodash.padstart-4.6.1.tgz", 661 | "integrity": "sha1-0uPuv/DZ05rVD1y9G1KnvOa7YRs=" 662 | }, 663 | "lolex": { 664 | "version": "1.3.2", 665 | "resolved": "http://registry.npmjs.org/lolex/-/lolex-1.3.2.tgz", 666 | "integrity": "sha1-fD2mL/yzDw9agKJWbKJORdigHzE=", 667 | "dev": true 668 | }, 669 | "long": { 670 | "version": "3.2.0", 671 | "resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz", 672 | "integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=" 673 | }, 674 | "md5.js": { 675 | "version": "1.3.5", 676 | "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", 677 | "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", 678 | "requires": { 679 | "hash-base": "^3.0.0", 680 | "inherits": "^2.0.1", 681 | "safe-buffer": "^5.1.2" 682 | } 683 | }, 684 | "methods": { 685 | "version": "1.1.2", 686 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 687 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 688 | }, 689 | "mime": { 690 | "version": "1.6.0", 691 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 692 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" 693 | }, 694 | "mime-db": { 695 | "version": "1.37.0", 696 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz", 697 | "integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==" 698 | }, 699 | "mime-types": { 700 | "version": "2.1.21", 701 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz", 702 | "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==", 703 | "requires": { 704 | "mime-db": "~1.37.0" 705 | } 706 | }, 707 | "minimalistic-assert": { 708 | "version": "1.0.1", 709 | "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", 710 | "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" 711 | }, 712 | "minimalistic-crypto-utils": { 713 | "version": "1.0.1", 714 | "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", 715 | "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" 716 | }, 717 | "minimatch": { 718 | "version": "3.0.4", 719 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 720 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 721 | "requires": { 722 | "brace-expansion": "^1.1.7" 723 | } 724 | }, 725 | "moment": { 726 | "version": "2.22.2", 727 | "resolved": "https://registry.npmjs.org/moment/-/moment-2.22.2.tgz", 728 | "integrity": "sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y=" 729 | }, 730 | "ms": { 731 | "version": "2.1.1", 732 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", 733 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" 734 | }, 735 | "mute-stream": { 736 | "version": "0.0.7", 737 | "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", 738 | "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" 739 | }, 740 | "npmlog": { 741 | "version": "1.2.1", 742 | "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-1.2.1.tgz", 743 | "integrity": "sha1-KOe+YZYJtT960d0wChDWTXFiaLY=", 744 | "requires": { 745 | "ansi": "~0.3.0", 746 | "are-we-there-yet": "~1.0.0", 747 | "gauge": "~1.2.0" 748 | } 749 | }, 750 | "number-is-nan": { 751 | "version": "1.0.1", 752 | "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", 753 | "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" 754 | }, 755 | "once": { 756 | "version": "1.4.0", 757 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 758 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 759 | "requires": { 760 | "wrappy": "1" 761 | } 762 | }, 763 | "optjs": { 764 | "version": "3.2.2", 765 | "resolved": "https://registry.npmjs.org/optjs/-/optjs-3.2.2.tgz", 766 | "integrity": "sha1-aabOicRCpEQDFBrS+bNwvVu29O4=" 767 | }, 768 | "os-locale": { 769 | "version": "1.4.0", 770 | "resolved": "http://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", 771 | "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", 772 | "requires": { 773 | "lcid": "^1.0.0" 774 | } 775 | }, 776 | "path-is-absolute": { 777 | "version": "1.0.1", 778 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 779 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" 780 | }, 781 | "pbkdf2": { 782 | "version": "3.0.17", 783 | "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", 784 | "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", 785 | "requires": { 786 | "create-hash": "^1.1.2", 787 | "create-hmac": "^1.1.4", 788 | "ripemd160": "^2.0.1", 789 | "safe-buffer": "^5.0.1", 790 | "sha.js": "^2.4.8" 791 | } 792 | }, 793 | "preconditions": { 794 | "version": "2.2.1", 795 | "resolved": "https://registry.npmjs.org/preconditions/-/preconditions-2.2.1.tgz", 796 | "integrity": "sha1-o9JeRQoOrzLcb2tAEob5VWN4Ts4=", 797 | "requires": { 798 | "errr": "2.2.1", 799 | "lodash": "4.17.5" 800 | }, 801 | "dependencies": { 802 | "lodash": { 803 | "version": "4.17.5", 804 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", 805 | "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==" 806 | } 807 | } 808 | }, 809 | "process-nextick-args": { 810 | "version": "2.0.0", 811 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", 812 | "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" 813 | }, 814 | "protobufjs": { 815 | "version": "5.0.3", 816 | "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-5.0.3.tgz", 817 | "integrity": "sha512-55Kcx1MhPZX0zTbVosMQEO5R6/rikNXd9b6RQK4KSPcrSIIwoXTtebIczUrXlwaSrbz4x8XUVThGPob1n8I4QA==", 818 | "requires": { 819 | "ascli": "~1", 820 | "bytebuffer": "~5", 821 | "glob": "^7.0.5", 822 | "yargs": "^3.10.0" 823 | } 824 | }, 825 | "qr-image": { 826 | "version": "3.2.0", 827 | "resolved": "https://registry.npmjs.org/qr-image/-/qr-image-3.2.0.tgz", 828 | "integrity": "sha1-n6gpW+rlDEoUnPn5CaHbRkqGcug=" 829 | }, 830 | "qs": { 831 | "version": "6.6.0", 832 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.6.0.tgz", 833 | "integrity": "sha512-KIJqT9jQJDQx5h5uAVPimw6yVg2SekOKu959OCtktD3FjzbpvaPr8i4zzg07DOMz+igA4W/aNM7OV8H37pFYfA==" 834 | }, 835 | "read": { 836 | "version": "1.0.7", 837 | "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", 838 | "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", 839 | "requires": { 840 | "mute-stream": "~0.0.4" 841 | } 842 | }, 843 | "readable-stream": { 844 | "version": "2.3.6", 845 | "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", 846 | "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", 847 | "requires": { 848 | "core-util-is": "~1.0.0", 849 | "inherits": "~2.0.3", 850 | "isarray": "~1.0.0", 851 | "process-nextick-args": "~2.0.0", 852 | "safe-buffer": "~5.1.1", 853 | "string_decoder": "~1.1.1", 854 | "util-deprecate": "~1.0.1" 855 | } 856 | }, 857 | "ripemd160": { 858 | "version": "2.0.2", 859 | "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", 860 | "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", 861 | "requires": { 862 | "hash-base": "^3.0.0", 863 | "inherits": "^2.0.1" 864 | } 865 | }, 866 | "safe-buffer": { 867 | "version": "5.1.2", 868 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 869 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 870 | }, 871 | "samsam": { 872 | "version": "1.1.2", 873 | "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.1.2.tgz", 874 | "integrity": "sha1-vsEf3IOp/aBjQBIQ5AF2wwJNFWc=", 875 | "dev": true 876 | }, 877 | "scryptsy": { 878 | "version": "1.2.1", 879 | "resolved": "https://registry.npmjs.org/scryptsy/-/scryptsy-1.2.1.tgz", 880 | "integrity": "sha1-oyJfpLJST4AnAHYeKFW987LZIWM=", 881 | "requires": { 882 | "pbkdf2": "^3.0.3" 883 | } 884 | }, 885 | "sha.js": { 886 | "version": "2.4.11", 887 | "resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", 888 | "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", 889 | "requires": { 890 | "inherits": "^2.0.1", 891 | "safe-buffer": "^5.0.1" 892 | } 893 | }, 894 | "sinon": { 895 | "version": "1.17.7", 896 | "resolved": "http://registry.npmjs.org/sinon/-/sinon-1.17.7.tgz", 897 | "integrity": "sha1-RUKk9JugxFwF6y6d2dID4rjv4L8=", 898 | "dev": true, 899 | "requires": { 900 | "formatio": "1.1.1", 901 | "lolex": "1.3.2", 902 | "samsam": "1.1.2", 903 | "util": ">=0.10.3 <1" 904 | } 905 | }, 906 | "sjcl": { 907 | "version": "1.0.7", 908 | "resolved": "https://registry.npmjs.org/sjcl/-/sjcl-1.0.7.tgz", 909 | "integrity": "sha1-MrNlpQ3Ju6JriLo8nfjqNCF9n0U=" 910 | }, 911 | "string-width": { 912 | "version": "1.0.2", 913 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", 914 | "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", 915 | "requires": { 916 | "code-point-at": "^1.0.0", 917 | "is-fullwidth-code-point": "^1.0.0", 918 | "strip-ansi": "^3.0.0" 919 | } 920 | }, 921 | "string_decoder": { 922 | "version": "1.1.1", 923 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 924 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 925 | "requires": { 926 | "safe-buffer": "~5.1.0" 927 | } 928 | }, 929 | "strip-ansi": { 930 | "version": "3.0.1", 931 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", 932 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", 933 | "requires": { 934 | "ansi-regex": "^2.0.0" 935 | } 936 | }, 937 | "superagent": { 938 | "version": "3.8.3", 939 | "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.8.3.tgz", 940 | "integrity": "sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA==", 941 | "requires": { 942 | "component-emitter": "^1.2.0", 943 | "cookiejar": "^2.1.0", 944 | "debug": "^3.1.0", 945 | "extend": "^3.0.0", 946 | "form-data": "^2.3.1", 947 | "formidable": "^1.2.0", 948 | "methods": "^1.1.1", 949 | "mime": "^1.4.1", 950 | "qs": "^6.5.1", 951 | "readable-stream": "^2.3.5" 952 | } 953 | }, 954 | "type-detect": { 955 | "version": "1.0.0", 956 | "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz", 957 | "integrity": "sha1-diIXzAbbJY7EiQihKY6LlRIejqI=", 958 | "dev": true 959 | }, 960 | "unorm": { 961 | "version": "1.4.1", 962 | "resolved": "https://registry.npmjs.org/unorm/-/unorm-1.4.1.tgz", 963 | "integrity": "sha1-NkIA1fE2RsqLzURJAnEzVhR5IwA=" 964 | }, 965 | "util": { 966 | "version": "0.11.0", 967 | "resolved": "https://registry.npmjs.org/util/-/util-0.11.0.tgz", 968 | "integrity": "sha512-5n12uMzKCjvB2HPFHnbQSjaqAa98L5iIXmHrZCLavuZVe0qe/SJGbDGWlpaHk5lnBkWRDO+dRu1/PgmUYKPPTw==", 969 | "dev": true, 970 | "requires": { 971 | "inherits": "2.0.3" 972 | } 973 | }, 974 | "util-deprecate": { 975 | "version": "1.0.2", 976 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 977 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" 978 | }, 979 | "window-size": { 980 | "version": "0.1.4", 981 | "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz", 982 | "integrity": "sha1-+OGqHuWlPsW/FR/6CXQqatdpeHY=" 983 | }, 984 | "wrap-ansi": { 985 | "version": "2.1.0", 986 | "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", 987 | "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", 988 | "requires": { 989 | "string-width": "^1.0.1", 990 | "strip-ansi": "^3.0.1" 991 | } 992 | }, 993 | "wrappy": { 994 | "version": "1.0.2", 995 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 996 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 997 | }, 998 | "y18n": { 999 | "version": "3.2.1", 1000 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", 1001 | "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" 1002 | }, 1003 | "yargs": { 1004 | "version": "3.32.0", 1005 | "resolved": "http://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz", 1006 | "integrity": "sha1-AwiOnr+edWtpdRYR0qXvWRSCyZU=", 1007 | "requires": { 1008 | "camelcase": "^2.0.1", 1009 | "cliui": "^3.0.3", 1010 | "decamelize": "^1.1.1", 1011 | "os-locale": "^1.4.0", 1012 | "string-width": "^1.0.1", 1013 | "window-size": "^0.1.4", 1014 | "y18n": "^3.2.0" 1015 | } 1016 | } 1017 | } 1018 | } 1019 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bitcore-wallet", 3 | "description": "A CLI Mutisig HD Bitcoin Wallet, demo for Bitcore Wallet Service", 4 | "author": "BitPay Inc", 5 | "version": "1.2.0", 6 | "keywords": [ 7 | "bitcoin", 8 | "copay", 9 | "multisig", 10 | "wallet" 11 | ], 12 | "repository": { 13 | "url": "git@github.com:bitpay/bitcore-wallet.git", 14 | "type": "git" 15 | }, 16 | "bugs": {}, 17 | "dependencies": { 18 | "async": "^2.6.1", 19 | "bitcore-wallet-client": "^6.8.1", 20 | "commander": "^2.6.0", 21 | "lodash": "^4.17.11", 22 | "moment": "^2.9.0", 23 | "npmlog": "^1.2.0", 24 | "qr-image": "^3.1.0", 25 | "read": "^1.0.5", 26 | "sjcl": "^1.0.2" 27 | }, 28 | "devDependencies": { 29 | "chai": "^3.3.0", 30 | "sinon": "^1.17.1" 31 | }, 32 | "scripts": { 33 | "start": "node app.js", 34 | "coverage": "./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha -- --reporter spec test", 35 | "test": "./node_modules/.bin/mocha", 36 | "coveralls": "./node_modules/.bin/istanbul cover ./node_modules/mocha/bin/_mocha --report lcovonly -- -R spec && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage" 37 | }, 38 | "contributors": [ 39 | { 40 | "name": "Ivan Socolsky", 41 | "email": "ivan@gmail.com" 42 | }, 43 | { 44 | "name": "Matias Alejo Garcia", 45 | "email": "ematiu@gmail.com" 46 | } 47 | ], 48 | "bin": { 49 | "wallet": "./bin/wallet", 50 | "wallet-address": "./bin/wallet-address", 51 | "wallet-addresses": "./bin/wallet-addresses", 52 | "wallet-airsign": "./bin/wallet-airsign", 53 | "wallet-balance": "./bin/wallet-balance", 54 | "wallet-broadcast": "./bin/wallet-broadcast", 55 | "wallet-confirm": "./bin/wallet-confirm", 56 | "wallet-create": "./bin/wallet-create", 57 | "wallet-export": "./bin/wallet-export", 58 | "wallet-genkey": "./bin/wallet-genkey", 59 | "wallet-history": "./bin/wallet-history", 60 | "wallet-import": "./bin/wallet-import", 61 | "wallet-join": "./bin/wallet-join", 62 | "wallet-recreate": "./bin/wallet-recreate", 63 | "wallet-reject": "./bin/wallet-reject", 64 | "wallet-rm": "./bin/wallet-rm", 65 | "wallet-send": "./bin/wallet-send", 66 | "wallet-sign": "./bin/wallet-sign", 67 | "wallet-status": "./bin/wallet-status", 68 | "wallet-txproposals": "./bin/wallet-txproposals", 69 | "wallet-mnemonic": "./bin/wallet-mnemonic", 70 | "wallet-derive": "./bin/wallet-derive" 71 | }, 72 | "licence": "MIT" 73 | } 74 | -------------------------------------------------------------------------------- /test/cliUtils.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _ = require('lodash'); 4 | var chai = require('chai'); 5 | var sinon = require('sinon'); 6 | var should = chai.should(); 7 | var CliUtils = require('../bin/cli-utils'); 8 | 9 | describe('CliUtils', function() { 10 | describe('#parseMN', function() { 11 | it('should successfully parse m & n', function() { 12 | var texts = { 13 | '1-1': [1, 1], 14 | '1-of-1': [1, 1], 15 | '1of1': [1, 1], 16 | '1-OF-2': [1, 2], 17 | '1OF2': [1, 2], 18 | ' 2-2': [2, 2], 19 | '2-3 ': [2, 3], 20 | '10-10': [10, 10], 21 | '10-of-10': [10, 10], 22 | }; 23 | _.each(texts, function(expected, text) { 24 | var result = CliUtils.parseMN(text); 25 | result.should.deep.equal(expected); 26 | }); 27 | }); 28 | it('should fail to parse incorrect m & n', function() { 29 | var texts = [ 30 | '', 31 | ' ', 32 | '1', 33 | 'x-1', 34 | '1-x', 35 | 'of-1-1', 36 | '2-2-of', 37 | '1-1-1', 38 | ' 1_1 ', 39 | '2-1', 40 | '2-of-1', 41 | '-1-2', 42 | '1--2', 43 | 'x-of-2', 44 | ]; 45 | _.each(texts, function(text) { 46 | var valid = true; 47 | try { 48 | CliUtils.parseMN(text); 49 | } catch (e) { 50 | valid = false; 51 | } 52 | valid.should.be.false; 53 | }); 54 | }); 55 | }); 56 | 57 | describe('#parseAmount', function() { 58 | it('should successfully parse amounts', function() { 59 | var texts = { 60 | '1': 1, 61 | '0': 0, 62 | '1.': 1, 63 | '000000.0000': 0, 64 | '123': 123, 65 | '123sat': 123, 66 | '123 sat': 123, 67 | '00123 sat': 123, 68 | '1.23bit': 123, 69 | '1.23 bit': 123, 70 | '0 bit': 0, 71 | '.45bit': 45, 72 | '1btc': 100000000, 73 | ' 1btc': 100000000, 74 | '9999btc': 999900000000, 75 | '0.00000001btc': 1, 76 | '00000.00000001BTC': 1, 77 | '0.00000001 BTC': 1, 78 | '0.123btc': 12300000, 79 | '0.123 bTc': 12300000, 80 | }; 81 | _.each(texts, function(satoshi, text) { 82 | var amount = CliUtils.parseAmount(text); 83 | amount.should.equal(satoshi); 84 | }); 85 | }); 86 | it('should fail to parse incorrect amounts', function() { 87 | var texts = [ 88 | '', 89 | ' ', 90 | 'btc', 91 | '1satoshi', 92 | 'no-number', 93 | '-3', 94 | '1 b t c', 95 | 'btc1', 96 | 'btc 1', 97 | '1,234', 98 | '0.000000001btc', 99 | '0.1sat', 100 | '0.123bit', 101 | '2.000000009btc', 102 | ]; 103 | _.each(texts, function(text) { 104 | var valid = true; 105 | try { 106 | CliUtils.parseAmount(text); 107 | } catch (e) { 108 | valid = false; 109 | } 110 | valid.should.be.false; 111 | }); 112 | }); 113 | }); 114 | }); 115 | --------------------------------------------------------------------------------