move parseAmount to CLI only
This commit is contained in:
parent
345938824f
commit
675369eed0
|
@ -17,7 +17,12 @@ if (!args[0] || !args[1] || !args[2])
|
||||||
program.help();
|
program.help();
|
||||||
|
|
||||||
var address = args[0];
|
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 message = args[2];
|
||||||
|
|
||||||
var client = utils.getClient(program);
|
var client = utils.getClient(program);
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
var _ = require('lodash');
|
var _ = require('lodash');
|
||||||
var Client = require('../lib/client');
|
var Client = require('../lib/client');
|
||||||
|
|
||||||
|
@ -12,14 +11,14 @@ var die = Utils.die = function(err) {
|
||||||
};
|
};
|
||||||
|
|
||||||
Utils.parseMN = function(MN) {
|
Utils.parseMN = function(MN) {
|
||||||
if (!MN)
|
if (!MN)
|
||||||
die('No m-n parameter');
|
die('No m-n parameter');
|
||||||
var mn = MN.split('-');
|
var mn = MN.split('-');
|
||||||
|
|
||||||
var m = parseInt(mn[0]);
|
var m = parseInt(mn[0]);
|
||||||
var n = parseInt(mn[1]);
|
var n = parseInt(mn[1]);
|
||||||
|
|
||||||
if (!m || ! n) {
|
if (!m || !n) {
|
||||||
die('Bad m-n parameter:' + MN);
|
die('Bad m-n parameter:' + MN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,6 +61,33 @@ Utils.findOneTxProposal = function(txps, id) {
|
||||||
return matches[0];
|
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;
|
module.exports = Utils;
|
||||||
|
|
|
@ -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;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -44,7 +44,10 @@ function _parseError(body) {
|
||||||
var code = body.code || 'ERROR';
|
var code = body.code || 'ERROR';
|
||||||
var message = body.error || 'There was an unknown error processing the request';
|
var message = body.error || 'There was an unknown error processing the request';
|
||||||
log.error(code, message);
|
log.error(code, message);
|
||||||
return {message: message, code: code};
|
return {
|
||||||
|
message: message,
|
||||||
|
code: code
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
function _signRequest(method, url, args, privKey) {
|
function _signRequest(method, url, args, privKey) {
|
||||||
|
@ -61,7 +64,7 @@ function API(opts) {
|
||||||
this.verbose = !!opts.verbose;
|
this.verbose = !!opts.verbose;
|
||||||
this.request = request || opts.request;
|
this.request = request || opts.request;
|
||||||
this.baseUrl = opts.baseUrl || BASE_URL;
|
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) {
|
if (this.verbose) {
|
||||||
log.level = 'debug';
|
log.level = 'debug';
|
||||||
} else {
|
} else {
|
||||||
|
@ -321,21 +324,17 @@ API.prototype.getStatus = function(cb) {
|
||||||
* @param opts.message
|
* @param opts.message
|
||||||
*/
|
*/
|
||||||
API.prototype.sendTxProposal = function(opts, cb) {
|
API.prototype.sendTxProposal = function(opts, cb) {
|
||||||
|
$.checkArgument(opts);
|
||||||
|
$.shouldBeNumber(opts.amount);
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
this._loadAndCheck(function(err, data) {
|
this._loadAndCheck(function(err, data) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
|
||||||
var amount;
|
|
||||||
try {
|
|
||||||
amount = WalletUtils.parseAmount(opts.amount);
|
|
||||||
} catch (ex) {
|
|
||||||
return cb(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
var args = {
|
var args = {
|
||||||
toAddress: opts.toAddress,
|
toAddress: opts.toAddress,
|
||||||
amount: amount,
|
amount: opts.amount,
|
||||||
message: _encryptProposalMessage(opts.message, data.sharedEncryptingKey),
|
message: _encryptProposalMessage(opts.message, data.sharedEncryptingKey),
|
||||||
};
|
};
|
||||||
var hash = WalletUtils.getProposalHash(args.toAddress, args.amount, args.message);
|
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) {
|
API.prototype.signTxProposal = function(txp, cb) {
|
||||||
var self = this;
|
|
||||||
$.checkArgument(txp.creatorId);
|
$.checkArgument(txp.creatorId);
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
|
||||||
this._loadAndCheck(function(err, data) {
|
this._loadAndCheck(function(err, data) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
|
||||||
|
@ -499,9 +499,10 @@ API.prototype.signTxProposal = function(txp, cb) {
|
||||||
};
|
};
|
||||||
|
|
||||||
API.prototype.rejectTxProposal = function(txp, reason, cb) {
|
API.prototype.rejectTxProposal = function(txp, reason, cb) {
|
||||||
var self = this;
|
|
||||||
$.checkArgument(cb);
|
$.checkArgument(cb);
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
|
||||||
this._loadAndCheck(
|
this._loadAndCheck(
|
||||||
function(err, data) {
|
function(err, data) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
|
|
@ -105,33 +105,4 @@ WalletUtils.decryptMessage = function(cyphertextJson, encryptingKey) {
|
||||||
return sjcl.decrypt(key, cyphertextJson);
|
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;
|
module.exports = WalletUtils;
|
||||||
|
|
|
@ -370,7 +370,7 @@ describe('client API ', function() {
|
||||||
should.exist(x0.address);
|
should.exist(x0.address);
|
||||||
blockExplorerMock.setUtxo(x0, 1, 1);
|
blockExplorerMock.setUtxo(x0, 1, 1);
|
||||||
var opts = {
|
var opts = {
|
||||||
amount: '0.1btc',
|
amount: 10000000,
|
||||||
toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5',
|
toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5',
|
||||||
message: 'hola 1-1',
|
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) {
|
it('Should lock and release funds', function(done) {
|
||||||
helpers.createAndJoinWallet(clients, 2, 2, function(err, w) {
|
helpers.createAndJoinWallet(clients, 2, 2, function(err, w) {
|
||||||
clients[0].createAddress(function(err, x0) {
|
clients[0].createAddress(function(err, x0) {
|
||||||
|
@ -535,7 +535,7 @@ describe('client API ', function() {
|
||||||
blockExplorerMock.setUtxo(x0, 1, 2);
|
blockExplorerMock.setUtxo(x0, 1, 2);
|
||||||
blockExplorerMock.setUtxo(x0, 1, 2);
|
blockExplorerMock.setUtxo(x0, 1, 2);
|
||||||
var opts = {
|
var opts = {
|
||||||
amount: '1.2btc',
|
amount: 120000000,
|
||||||
toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5',
|
toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5',
|
||||||
message: 'hola 1-1',
|
message: 'hola 1-1',
|
||||||
};
|
};
|
||||||
|
|
|
@ -74,63 +74,4 @@ describe('WalletUtils', function() {
|
||||||
msg.should.equal('hello world');
|
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;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue