diff --git a/bit-wallet/bit-send b/bit-wallet/bit-send index c83f528..8dc858b 100755 --- a/bit-wallet/bit-send +++ b/bit-wallet/bit-send @@ -17,7 +17,12 @@ if (!args[0] || !args[1] || !args[2]) program.help(); var address = args[0]; -var amount = args[1]; +var amount; +try { + amount = utils.parseAmount(args[1]); +} catch (ex) { + utils.die(ex); +} var message = args[2]; var client = utils.getClient(program); diff --git a/bit-wallet/cli-utils.js b/bit-wallet/cli-utils.js index 46b0a33..237416d 100644 --- a/bit-wallet/cli-utils.js +++ b/bit-wallet/cli-utils.js @@ -1,4 +1,3 @@ - var _ = require('lodash'); var Client = require('../lib/client'); @@ -12,14 +11,14 @@ var die = Utils.die = function(err) { }; Utils.parseMN = function(MN) { - if (!MN) + if (!MN) die('No m-n parameter'); var mn = MN.split('-'); - var m = parseInt(mn[0]); + var m = parseInt(mn[0]); var n = parseInt(mn[1]); - if (!m || ! n) { + if (!m || !n) { die('Bad m-n parameter:' + MN); } @@ -62,6 +61,33 @@ Utils.findOneTxProposal = function(txps, id) { return matches[0]; }; +Utils.UNITS = { + 'btc': 100000000, + 'bit': 100, + 'sat': 1, +}; + +Utils.parseAmount = function(text) { + if (!_.isString(text)) + text = text.toString(); + + var regex = '^(\\d*(\\.\\d{0,8})?)\\s*(' + _.keys(Utils.UNITS).join('|') + ')?$'; + var match = new RegExp(regex, 'i').exec(text.trim()); + + if (!match || match.length === 0) throw new Error('Invalid amount'); + + var amount = parseFloat(match[1]); + if (!_.isNumber(amount) || _.isNaN(amount)) throw new Error('Invalid amount'); + + var unit = (match[3] || 'sat').toLowerCase(); + var rate = Utils.UNITS[unit]; + if (!rate) throw new Error('Invalid unit') + + var amountSat = parseFloat((amount * rate).toPrecision(12)); + if (amountSat != Math.round(amountSat)) throw new Error('Invalid amount'); + + return amountSat; +}; module.exports = Utils; diff --git a/bit-wallet/tests.js b/bit-wallet/tests.js new file mode 100644 index 0000000..b2a90d4 --- /dev/null +++ b/bit-wallet/tests.js @@ -0,0 +1,67 @@ +'use strict'; + +var _ = require('lodash'); +var chai = require('chai'); +var sinon = require('sinon'); +var should = chai.should(); +var CliUtils = require('./cli-utils'); + +describe('CliUtils', function() { + describe('#parseAmount', function() { + it('should successfully parse amounts', function() { + var texts = { + '1': 1, + '0': 0, + '1.': 1, + '000000.0000': 0, + '123': 123, + '123sat': 123, + '123 sat': 123, + '00123 sat': 123, + '1.23bit': 123, + '1.23 bit': 123, + '0 bit': 0, + '.45bit': 45, + '1btc': 100000000, + ' 1btc': 100000000, + '9999btc': 999900000000, + '0.00000001btc': 1, + '00000.00000001BTC': 1, + '0.00000001 BTC': 1, + '0.123btc': 12300000, + '0.123 bTc': 12300000, + }; + _.each(texts, function(satoshi, text) { + var amount = CliUtils.parseAmount(text); + amount.should.equal(satoshi); + }); + }); + it('should fail to parse incorrect amounts', function() { + var texts = [ + '', + ' ', + 'btc', + '1satoshi', + 'no-number', + '-3', + '1 b t c', + 'btc1', + 'btc 1', + '1,234', + '0.000000001btc', + '0.1sat', + '0.123bit', + '2.000000009btc', + ]; + _.each(texts, function(text) { + var valid = true; + try { + var amount = CliUtils.parseAmount(text); + } catch (e) { + valid = false; + } + valid.should.be.false; + }); + }); + }); +}); diff --git a/lib/client/api.js b/lib/client/api.js index f2674f6..31a195e 100644 --- a/lib/client/api.js +++ b/lib/client/api.js @@ -44,7 +44,10 @@ function _parseError(body) { var code = body.code || 'ERROR'; var message = body.error || 'There was an unknown error processing the request'; log.error(code, message); - return {message: message, code: code}; + return { + message: message, + code: code + }; }; function _signRequest(method, url, args, privKey) { @@ -61,7 +64,7 @@ function API(opts) { this.verbose = !!opts.verbose; this.request = request || opts.request; this.baseUrl = opts.baseUrl || BASE_URL; - this.basePath = this.baseUrl.replace(/http.?:\/\/[a-zA-Z0-9:-]*\//,'/'); + this.basePath = this.baseUrl.replace(/http.?:\/\/[a-zA-Z0-9:-]*\//, '/'); if (this.verbose) { log.level = 'debug'; } else { @@ -321,21 +324,17 @@ API.prototype.getStatus = function(cb) { * @param opts.message */ API.prototype.sendTxProposal = function(opts, cb) { + $.checkArgument(opts); + $.shouldBeNumber(opts.amount); + var self = this; this._loadAndCheck(function(err, data) { if (err) return cb(err); - var amount; - try { - amount = WalletUtils.parseAmount(opts.amount); - } catch (ex) { - return cb(ex); - } - var args = { toAddress: opts.toAddress, - amount: amount, + amount: opts.amount, message: _encryptProposalMessage(opts.message, data.sharedEncryptingKey), }; var hash = WalletUtils.getProposalHash(args.toAddress, args.amount, args.message); @@ -450,9 +449,10 @@ API.prototype.getTxProposals = function(opts, cb) { }; API.prototype.signTxProposal = function(txp, cb) { - var self = this; $.checkArgument(txp.creatorId); + var self = this; + this._loadAndCheck(function(err, data) { if (err) return cb(err); @@ -499,9 +499,10 @@ API.prototype.signTxProposal = function(txp, cb) { }; API.prototype.rejectTxProposal = function(txp, reason, cb) { - var self = this; $.checkArgument(cb); + var self = this; + this._loadAndCheck( function(err, data) { if (err) return cb(err); diff --git a/lib/walletutils.js b/lib/walletutils.js index 4ab8391..1a34077 100644 --- a/lib/walletutils.js +++ b/lib/walletutils.js @@ -105,33 +105,4 @@ WalletUtils.decryptMessage = function(cyphertextJson, encryptingKey) { return sjcl.decrypt(key, cyphertextJson); }; - -WalletUtils.UNITS = { - 'btc': 100000000, - 'bit': 100, - 'sat': 1, -}; - -WalletUtils.parseAmount = function(text) { - if (!_.isString(text)) - text = text.toString(); - - var regex = '^(\\d*(\\.\\d{0,8})?)\\s*(' + _.keys(WalletUtils.UNITS).join('|') + ')?$'; - var match = new RegExp(regex, 'i').exec(text.trim()); - - if (!match || match.length === 0) throw new Error('Invalid amount'); - - var amount = parseFloat(match[1]); - if (!_.isNumber(amount) || _.isNaN(amount)) throw new Error('Invalid amount'); - - var unit = (match[3] || 'sat').toLowerCase(); - var rate = WalletUtils.UNITS[unit]; - if (!rate) throw new Error('Invalid unit') - - var amountSat = Utils.strip(amount * rate); - if (amountSat != Math.round(amountSat)) throw new Error('Invalid amount'); - - return amountSat; -}; - module.exports = WalletUtils; diff --git a/test/integration/clientApi.js b/test/integration/clientApi.js index 1d4b53e..e086bd0 100644 --- a/test/integration/clientApi.js +++ b/test/integration/clientApi.js @@ -370,7 +370,7 @@ describe('client API ', function() { should.exist(x0.address); blockExplorerMock.setUtxo(x0, 1, 1); var opts = { - amount: '0.1btc', + amount: 10000000, toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5', message: 'hola 1-1', }; @@ -526,7 +526,7 @@ describe('client API ', function() { }); }); - describe('Transaction Troposals and Locked funds', function() { + describe('Transaction proposals and locked funds', function() { it('Should lock and release funds', function(done) { helpers.createAndJoinWallet(clients, 2, 2, function(err, w) { clients[0].createAddress(function(err, x0) { @@ -535,7 +535,7 @@ describe('client API ', function() { blockExplorerMock.setUtxo(x0, 1, 2); blockExplorerMock.setUtxo(x0, 1, 2); var opts = { - amount: '1.2btc', + amount: 120000000, toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5', message: 'hola 1-1', }; diff --git a/test/walletutils.js b/test/walletutils.js index 50e2082..192df87 100644 --- a/test/walletutils.js +++ b/test/walletutils.js @@ -74,63 +74,4 @@ describe('WalletUtils', function() { msg.should.equal('hello world'); }); }); - - describe('#parseAmount', function() { - it('should successfully parse amounts', function() { - var texts = { - '1': 1, - '0': 0, - '1.': 1, - '000000.0000': 0, - '123': 123, - '123sat': 123, - '123 sat': 123, - '00123 sat': 123, - '1.23bit': 123, - '1.23 bit': 123, - '0 bit': 0, - '.45bit': 45, - '1btc': 100000000, - ' 1btc': 100000000, - '9999btc': 999900000000, - '0.00000001btc': 1, - '00000.00000001BTC': 1, - '0.00000001 BTC': 1, - '0.123btc': 12300000, - '0.123 bTc': 12300000, - }; - _.each(texts, function(satoshi, text) { - var amount = WalletUtils.parseAmount(text); - amount.should.equal(satoshi); - }); - }); - it('should fail to parse incorrect amounts', function() { - var texts = [ - '', - ' ', - 'btc', - '1satoshi', - 'no-number', - '-3', - '1 b t c', - 'btc1', - 'btc 1', - '1,234', - '0.000000001btc', - '0.1sat', - '0.123bit', - '2.000000009btc', - ]; - _.each(texts, function(text) { - var valid = true; - try { - var amount = WalletUtils.parseAmount(text); - } catch (e) { - valid = false; - } - valid.should.be.false; - }); - }); - }); - });