'use strict'; var _ = require('lodash'); var errors = require('./errors'); var $ = require('./util/preconditions'); var UNITS = { 'BTC' : [1e8, 8], 'mBTC' : [1e5, 5], 'uBTC' : [1e2, 2], 'bits' : [1e2, 2], 'satoshis' : [1, 0] }; /** * 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. 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|Number} code - The unit of the amount or the exchange rate * @returns {Unit} A new instance of an Unit * @constructor */ function Unit(amount, code) { if (!(this instanceof Unit)) { return new Unit(amount, 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); var self = this; var defineAccesor = function(key) { Object.defineProperty(self, key, { get: function() { return self.to(key); }, enumerable: true, }); }; Object.keys(UNITS).forEach(defineAccesor); } Object.keys(UNITS).forEach(function(key) { Unit[key] = key; }); /** * Returns a Unit instance created from JSON string or object * * @param {String|Object} json - JSON with keys: amount and code * @returns {Unit} A Unit instance */ Unit.fromObject = function fromObject(data){ $.checkArgument(_.isObject(data), 'Argument is expected to be an object'); return new Unit(data.amount, data.code); }; /** * Returns a Unit instance created from an amount in BTC * * @param {Number} amount - The amount in BTC * @returns {Unit} A Unit instance */ Unit.fromBTC = function(amount) { return new Unit(amount, Unit.BTC); }; /** * Returns a Unit instance created from an amount in mBTC * * @param {Number} amount - The amount in mBTC * @returns {Unit} A Unit instance */ Unit.fromMillis = Unit.fromMilis = function(amount) { return new Unit(amount, Unit.mBTC); }; /** * Returns a Unit instance created from an amount in bits * * @param {Number} amount - The amount in bits * @returns {Unit} A Unit instance */ Unit.fromMicros = Unit.fromBits = function(amount) { return new Unit(amount, Unit.bits); }; /** * Returns a Unit instance created from an amount in satoshis * * @param {Number} amount - The amount in satoshis * @returns {Unit} A Unit instance */ 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); } return parseInt((amount * UNITS[code][0]).toFixed()); }; /** * Returns the value represented in the specified unit * * @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); } var value = this._value / UNITS[code][0]; return parseFloat(value.toFixed(UNITS[code][1])); }; /** * Returns the value represented in BTC * * @returns {Number} The value converted to BTC */ Unit.prototype.toBTC = function() { return this.to(Unit.BTC); }; /** * Returns the value represented in mBTC * * @returns {Number} The value converted to mBTC */ Unit.prototype.toMillis = Unit.prototype.toMilis = function() { return this.to(Unit.mBTC); }; /** * Returns the value represented in bits * * @returns {Number} The value converted to bits */ Unit.prototype.toMicros = Unit.prototype.toBits = function() { return this.to(Unit.bits); }; /** * Returns the value represented in satoshis * * @returns {Number} The value converted to satoshis */ 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.atRate = function(rate) { return this.to(rate); }; /** * Returns a the string representation of the value in satoshis * * @returns {string} the value in satoshis */ Unit.prototype.toString = function() { return this.satoshis + ' satoshis'; }; /** * Returns a plain object representation of the Unit * * @returns {Object} An object with the keys: amount and code */ Unit.prototype.toObject = Unit.prototype.toJSON = function toObject() { return { amount: this.BTC, code: Unit.BTC }; }; /** * Returns a string formatted for the console * * @returns {string} the value in satoshis */ Unit.prototype.inspect = function() { return ''; }; module.exports = Unit;