From e7839d9ba2ec215ae835abef87b69bdaf325ddc1 Mon Sep 17 00:00:00 2001 From: Yemel Jardi Date: Thu, 25 Dec 2014 19:04:03 -0300 Subject: [PATCH 1/3] Add from/to Fiat methods to Unit class --- lib/errors/spec.js | 3 +++ lib/unit.js | 54 ++++++++++++++++++++++++++++++++++++++++------ test/unit.js | 34 +++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 7 deletions(-) diff --git a/lib/errors/spec.js b/lib/errors/spec.js index 5b74937..6f45f95 100644 --- a/lib/errors/spec.js +++ b/lib/errors/spec.js @@ -40,6 +40,9 @@ module.exports = [{ errors: [{ 'name': 'UnknownCode', 'message': format('Unrecognized unit code: {0}') + },{ + 'name': 'InvalidRate', + 'message': format('Invalid exchange rate: {0}') }] }, { name: 'Transaction', diff --git a/lib/unit.js b/lib/unit.js index 6a2bb86..7accd82 100644 --- a/lib/unit.js +++ b/lib/unit.js @@ -1,5 +1,7 @@ 'use strict'; +var _ = require('lodash'); + var errors = require('./errors'); var JSUtil = require('./util/js'); @@ -15,19 +17,23 @@ var UNITS = { * 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 * 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 * {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 * ```javascript * var sats = Unit.fromBTC(1.3).toSatoshis(); * 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; * ``` * * @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 * @constructor */ @@ -36,8 +42,14 @@ function Unit(amount, code) { return new Unit(amount, code); } - this._amount = amount; - this._code = code; + // convert fiat to BTC + if (_.isNumber(code)) { + if (code <= 0) { + throw new errors.Unit.InvalidRate(code); + } + amount = amount / code; + code = Unit.BTC; + } this._value = this._from(amount, code); @@ -109,6 +121,17 @@ Unit.fromSatoshis = function(amount) { 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) { if (!UNITS[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 * - * @param {string} code - The unit code + * @param {String|Number} code - The unit code or exchange rate * @returns {Number} The converted value */ 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]) { throw new errors.Unit.UnknownCode(code); } @@ -167,6 +197,16 @@ Unit.prototype.toSatoshis = function() { 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 * @@ -183,8 +223,8 @@ Unit.prototype.toString = function() { */ Unit.prototype.toObject = function toObject() { return { - amount: this._amount, - code: this._code + amount: this.BTC, + code: Unit.BTC }; }; diff --git a/test/unit.js b/test/unit.js index ebd4204..f5b4e31 100644 --- a/test/unit.js +++ b/test/unit.js @@ -15,10 +15,20 @@ describe('Unit', function() { }).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() { expect(function() { return Unit(1.2, 'BTC'); }).to.not.throw(); + + expect(function() { + return Unit(1.2, 350); + }).to.not.throw(); }); it('has property accesors "BTC", "mBTC", "uBTC", "bits", and "satoshis"', function() { @@ -44,6 +54,9 @@ describe('Unit', function() { unit = Unit.fromSatoshis('8999'); unit.satoshis.should.equal(8999); + + unit = Unit.fromFiat('43', 350); + unit.BTC.should.equal(0.12285714); }); it('should have constructor helpers', function() { @@ -60,6 +73,9 @@ describe('Unit', function() { unit = Unit.fromSatoshis(8999); unit.satoshis.should.equal(8999); + + unit = Unit.fromFiat(43, 350); + unit.BTC.should.equal(0.12285714); }); it('converts to satoshis correctly', function() { @@ -124,6 +140,15 @@ describe('Unit', function() { 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() { var unit = new Unit(1.3, 'BTC'); should.exist(unit.toString); @@ -156,4 +181,13 @@ describe('Unit', function() { }).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); + }); + }); From 168d87185ce5a3d7a9e418ebe0f5cda5e29726ad Mon Sep 17 00:00:00 2001 From: Yemel Jardi Date: Thu, 25 Dec 2014 19:14:06 -0300 Subject: [PATCH 2/3] Update bitcore guide --- docs/guide/unit.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docs/guide/unit.md b/docs/guide/unit.md index b09640f..10de6a5 100644 --- a/docs/guide/unit.md +++ b/docs/guide/unit.md @@ -61,3 +61,19 @@ value = Unit.fromBTC(amount).mBTC; value = Unit.fromBTC(amount).bits; value = Unit.fromBTC(amount).satoshis; ``` + +## Using a fiat currency + +The unit class also provides a convenient alternative to create an instance from a fiat amount and the corresponding BTC/fiat exchange rate. Any unit instance can be converted to a fiat amount by providing the current exchange rate. Check the example below: + +```javascript +var unit, fiat; +var amount = 100; +var exchangeRate = 350; + +unit = new Unit(amount, exchangeRate); +unit = Unit.fromFiat(amount, exchangeRate); + +fiat = Unit.fromBits(amount).toFiat(exchangeRate); +fiat = Unit.fromBits(amount).to(exchangeRate); +``` From d922a625b90918e6b7a0548730072f6c17f0eea4 Mon Sep 17 00:00:00 2001 From: Yemel Jardi Date: Sun, 28 Dec 2014 17:40:11 -0300 Subject: [PATCH 3/3] Rename toFiat() to atRate() --- docs/guide/unit.md | 2 +- lib/unit.js | 2 +- test/unit.js | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/guide/unit.md b/docs/guide/unit.md index 10de6a5..d13c2ef 100644 --- a/docs/guide/unit.md +++ b/docs/guide/unit.md @@ -74,6 +74,6 @@ var exchangeRate = 350; unit = new Unit(amount, exchangeRate); unit = Unit.fromFiat(amount, exchangeRate); -fiat = Unit.fromBits(amount).toFiat(exchangeRate); +fiat = Unit.fromBits(amount).atRate(exchangeRate); fiat = Unit.fromBits(amount).to(exchangeRate); ``` diff --git a/lib/unit.js b/lib/unit.js index 7accd82..22bdc9d 100644 --- a/lib/unit.js +++ b/lib/unit.js @@ -203,7 +203,7 @@ Unit.prototype.toSatoshis = function() { * @param {string} rate - The exchange rate between BTC/currency * @returns {Number} The value converted to satoshis */ -Unit.prototype.toFiat = function(rate) { +Unit.prototype.atRate = function(rate) { return this.to(rate); }; diff --git a/test/unit.js b/test/unit.js index f5b4e31..97e441e 100644 --- a/test/unit.js +++ b/test/unit.js @@ -142,11 +142,11 @@ describe('Unit', function() { it('can convert to fiat', function() { var unit = new Unit(1.3, 350); - unit.toFiat(350).should.equal(1.3); + unit.atRate(350).should.equal(1.3); unit.to(350).should.equal(1.3); unit = Unit.fromBTC(0.0123); - unit.toFiat(10).should.equal(0.12); + unit.atRate(10).should.equal(0.12); }); it('toString works as expected', function() { @@ -186,7 +186,7 @@ describe('Unit', function() { return new Unit(100, -123); }).to.throw(errors.Unit.InvalidRate); expect(function() { - return new Unit(100, 'BTC').toFiat(-123); + return new Unit(100, 'BTC').atRate(-123); }).to.throw(errors.Unit.InvalidRate); });