From e7839d9ba2ec215ae835abef87b69bdaf325ddc1 Mon Sep 17 00:00:00 2001 From: Yemel Jardi Date: Thu, 25 Dec 2014 19:04:03 -0300 Subject: [PATCH] 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); + }); + });