Add from/to Fiat methods to Unit class

This commit is contained in:
Yemel Jardi 2014-12-25 19:04:03 -03:00
parent 6e88efbe51
commit e7839d9ba2
3 changed files with 84 additions and 7 deletions

View File

@ -40,6 +40,9 @@ module.exports = [{
errors: [{ errors: [{
'name': 'UnknownCode', 'name': 'UnknownCode',
'message': format('Unrecognized unit code: {0}') 'message': format('Unrecognized unit code: {0}')
},{
'name': 'InvalidRate',
'message': format('Invalid exchange rate: {0}')
}] }]
}, { }, {
name: 'Transaction', name: 'Transaction',

View File

@ -1,5 +1,7 @@
'use strict'; 'use strict';
var _ = require('lodash');
var errors = require('./errors'); var errors = require('./errors');
var JSUtil = require('./util/js'); var JSUtil = require('./util/js');
@ -15,19 +17,23 @@ var UNITS = {
* Utility for handling and converting bitcoins units. The supported units are * Utility for handling and converting bitcoins units. The supported units are
* BTC, mBTC, bits (also named uBTC) and satoshis. A unit instance can be created with an * BTC, mBTC, bits (also named uBTC) and satoshis. A unit instance can be created with an
* amount and a unit code, or alternatively using static methods like {fromBTC}. * amount and a unit code, or alternatively using static methods like {fromBTC}.
* It also allows to be created from a fiat amount and the exchange rate, or
* alternatively using the {fromFiat} static method.
* You can consult for different representation of a unit instance using it's * You can consult for different representation of a unit instance using it's
* {to} method, the fixed unit methods like {toSatoshis} or alternatively using * {to} method, the fixed unit methods like {toSatoshis} or alternatively using
* the unit accessors. * the unit accessors. It also can be converted to a fiat amount by providing the
* corresponding BTC/fiat exchange rate.
* *
* @example * @example
* ```javascript * ```javascript
* var sats = Unit.fromBTC(1.3).toSatoshis(); * var sats = Unit.fromBTC(1.3).toSatoshis();
* var mili = Unit.fromBits(1.3).to(Unit.mBTC); * var mili = Unit.fromBits(1.3).to(Unit.mBTC);
* var bits = Unit.fromFiat(1.3, 350).bits;
* var btc = new Unit(1.3, Unit.bits).BTC; * var btc = new Unit(1.3, Unit.bits).BTC;
* ``` * ```
* *
* @param {Number} amount - The amount to be represented * @param {Number} amount - The amount to be represented
* @param {String} code - The unit of the amount * @param {String|Number} code - The unit of the amount or the exchange rate
* @returns {Unit} A new instance of an Unit * @returns {Unit} A new instance of an Unit
* @constructor * @constructor
*/ */
@ -36,8 +42,14 @@ function Unit(amount, code) {
return new Unit(amount, code); return new Unit(amount, code);
} }
this._amount = amount; // convert fiat to BTC
this._code = code; if (_.isNumber(code)) {
if (code <= 0) {
throw new errors.Unit.InvalidRate(code);
}
amount = amount / code;
code = Unit.BTC;
}
this._value = this._from(amount, code); this._value = this._from(amount, code);
@ -109,6 +121,17 @@ Unit.fromSatoshis = function(amount) {
return new Unit(amount, Unit.satoshis); return new Unit(amount, Unit.satoshis);
}; };
/**
* Returns a Unit instance created from a fiat amount and exchange rate.
*
* @param {Number} amount - The amount in fiat
* @param {Number} rate - The exchange rate BTC/fiat
* @returns {Unit} A Unit instance
*/
Unit.fromFiat = function(amount, rate) {
return new Unit(amount, rate);
};
Unit.prototype._from = function(amount, code) { Unit.prototype._from = function(amount, code) {
if (!UNITS[code]) { if (!UNITS[code]) {
throw new errors.Unit.UnknownCode(code); throw new errors.Unit.UnknownCode(code);
@ -119,10 +142,17 @@ Unit.prototype._from = function(amount, code) {
/** /**
* Returns the value represented in the specified unit * Returns the value represented in the specified unit
* *
* @param {string} code - The unit code * @param {String|Number} code - The unit code or exchange rate
* @returns {Number} The converted value * @returns {Number} The converted value
*/ */
Unit.prototype.to = function(code) { Unit.prototype.to = function(code) {
if (_.isNumber(code)) {
if (code <= 0) {
throw new errors.Unit.InvalidRate(code);
}
return parseFloat((this.BTC * code).toFixed(2));
}
if (!UNITS[code]) { if (!UNITS[code]) {
throw new errors.Unit.UnknownCode(code); throw new errors.Unit.UnknownCode(code);
} }
@ -167,6 +197,16 @@ Unit.prototype.toSatoshis = function() {
return this.to(Unit.satoshis); return this.to(Unit.satoshis);
}; };
/**
* Returns the value represented in fiat
*
* @param {string} rate - The exchange rate between BTC/currency
* @returns {Number} The value converted to satoshis
*/
Unit.prototype.toFiat = function(rate) {
return this.to(rate);
};
/** /**
* Returns a the string representation of the value in satoshis * Returns a the string representation of the value in satoshis
* *
@ -183,8 +223,8 @@ Unit.prototype.toString = function() {
*/ */
Unit.prototype.toObject = function toObject() { Unit.prototype.toObject = function toObject() {
return { return {
amount: this._amount, amount: this.BTC,
code: this._code code: Unit.BTC
}; };
}; };

View File

@ -15,10 +15,20 @@ describe('Unit', function() {
}).to.not.throw(); }).to.not.throw();
}); });
it('can be created from a number and exchange rate', function() {
expect(function() {
return new Unit(1.2, 350);
}).to.not.throw();
});
it('no "new" is required for creating an instance', function() { it('no "new" is required for creating an instance', function() {
expect(function() { expect(function() {
return Unit(1.2, 'BTC'); return Unit(1.2, 'BTC');
}).to.not.throw(); }).to.not.throw();
expect(function() {
return Unit(1.2, 350);
}).to.not.throw();
}); });
it('has property accesors "BTC", "mBTC", "uBTC", "bits", and "satoshis"', function() { it('has property accesors "BTC", "mBTC", "uBTC", "bits", and "satoshis"', function() {
@ -44,6 +54,9 @@ describe('Unit', function() {
unit = Unit.fromSatoshis('8999'); unit = Unit.fromSatoshis('8999');
unit.satoshis.should.equal(8999); unit.satoshis.should.equal(8999);
unit = Unit.fromFiat('43', 350);
unit.BTC.should.equal(0.12285714);
}); });
it('should have constructor helpers', function() { it('should have constructor helpers', function() {
@ -60,6 +73,9 @@ describe('Unit', function() {
unit = Unit.fromSatoshis(8999); unit = Unit.fromSatoshis(8999);
unit.satoshis.should.equal(8999); unit.satoshis.should.equal(8999);
unit = Unit.fromFiat(43, 350);
unit.BTC.should.equal(0.12285714);
}); });
it('converts to satoshis correctly', function() { it('converts to satoshis correctly', function() {
@ -124,6 +140,15 @@ describe('Unit', function() {
unit.toSatoshis().should.equal(unit.satoshis); unit.toSatoshis().should.equal(unit.satoshis);
}); });
it('can convert to fiat', function() {
var unit = new Unit(1.3, 350);
unit.toFiat(350).should.equal(1.3);
unit.to(350).should.equal(1.3);
unit = Unit.fromBTC(0.0123);
unit.toFiat(10).should.equal(0.12);
});
it('toString works as expected', function() { it('toString works as expected', function() {
var unit = new Unit(1.3, 'BTC'); var unit = new Unit(1.3, 'BTC');
should.exist(unit.toString); should.exist(unit.toString);
@ -156,4 +181,13 @@ describe('Unit', function() {
}).to.throw(errors.Unit.UnknownCode); }).to.throw(errors.Unit.UnknownCode);
}); });
it('fails when the exchange rate is invalid', function() {
expect(function() {
return new Unit(100, -123);
}).to.throw(errors.Unit.InvalidRate);
expect(function() {
return new Unit(100, 'BTC').toFiat(-123);
}).to.throw(errors.Unit.InvalidRate);
});
}); });