Merge pull request #627 from yemel/feature/unit-util

Utility for unit conversion
This commit is contained in:
Manuel Aráoz 2014-12-01 16:17:17 -03:00
commit 1175c475a2
4 changed files with 371 additions and 0 deletions

59
docs/Unit.md Normal file
View File

@ -0,0 +1,59 @@
# Unit
Unit it's a utility for handling and converting bitcoins units. We strongly
recommend you to always use satoshis to represent amount inside your application
and only convert them to other units in the front-end.
The supported units are BTC, mBTC, bits and satoshis. The codes for each unit
can be found as members of the Unit class.
```javascript
var btcCode = Unit.BTC;
var mbtcCode = Unit.mBTC;
var bitsCode = Unit.bits;
var satsCode = Unit.satoshis;
```
There are two ways for creating a unit instance. You can instanciate the class
using a value and a unit code; alternatively if the unit it's fixed you could
you some of the static methods. Check some examples below:
```javascript
var unit;
var amount = 100;
// using a unit code
var unitPreference = Unit.BTC;
unit = new Unit(amount, unitPreference);
// using a known unit
unit = Unit.fromBTC(amount);
unit = Unit.fromMilis(amount);
unit = Unit.fromBits(amount);
unit = Unit.fromSatoshis(amount);
```
Once you have a unit instance, you can check it's representantion in all the
available units. For your convinience the classes expose three ways to acomplish
this. Using the `.to(unitCode)` method, using a fixed unit like `.toSatoshis()`
or by using the accessors.
```javascript
var unit;
// using a unit code
var unitPreference = Unit.BTC;
value = Unit.fromSatoshis(amount).to(unitPreference);
// using a known unit
value = Unit.fromBTC(amount).toBTC();
value = Unit.fromBTC(amount).toMilis();
value = Unit.fromBTC(amount).toBits();
value = Unit.fromBTC(amount).toSatoshis();
// using accessors
value = Unit.fromBTC(amount).BTC;
value = Unit.fromBTC(amount).mBTC;
value = Unit.fromBTC(amount).bits;
value = Unit.fromBTC(amount).satoshis;
```

View File

@ -41,6 +41,7 @@ bitcore.Script = require('./lib/script');
bitcore.Transaction = require('./lib/transaction');
bitcore.Txin = require('./lib/txin');
bitcore.Txout = require('./lib/txout');
bitcore.Unit = require('./lib/unit');
// dependencies, subject to change

179
lib/unit.js Normal file
View File

@ -0,0 +1,179 @@
'use strict';
/**
*
* Bitcore Unit
*
* Utility for handling and converting bitcoins units. The supported units are
* BTC, mBTC, bits and satoshis. A unit instance can be created with an
* amount and a unit code, or alternatively using static methods like {fromBTC}.
* 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.
*
* @example
*
* var sats = Unit.fromBTC(1.3).toSatoshis();
* var mili = Unit.fromBits(1.3).to(Unit.mBTC);
* 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
* @returns {Unit} A new instance of an Unit
*/
function Unit(amount, code) {
if (!(this instanceof Unit)) {
return new Unit(amount, code);
}
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);
};
var UNITS = {
'BTC' : [1e8, 8],
'mBTC' : [1e5, 5],
'bits' : [1e2, 2],
'satoshis' : [1, 0]
};
Object.keys(UNITS).forEach(function(key) {
Unit[key] = key;
});
/**
*
* Will return 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);
};
/**
*
* Will return a Unit instance created from an amount in mBTC
*
* @param {Number} amount - The amount in mBTC
* @returns {Unit} A Unit instance
*/
Unit.fromMilis = function(amount) {
return new Unit(amount, Unit.mBTC);
};
/**
*
* Will return a Unit instance created from an amount in bits
*
* @param {Number} amount - The amount in bits
* @returns {Unit} A Unit instance
*/
Unit.fromBits = function(amount) {
return new Unit(amount, Unit.bits);
};
/**
*
* Will return 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);
};
Unit.prototype._from = function(amount, code) {
if (!UNITS[code]) throw Error('Unknown unit code');
return parseInt((amount * UNITS[code][0]).toFixed());
};
/**
*
* Will return the value represented in the specified unit
*
* @param {string} code - The unit code
* @returns {Number} The converted value
*/
Unit.prototype.to = function(code) {
if (!UNITS[code]) throw Error('Unknown unit code');
var value = this._value / UNITS[code][0];
return parseFloat(value.toFixed(UNITS[code][1]));
};
/**
*
* Will return the value represented in BTC
*
* @returns {Number} The value converted to BTC
*/
Unit.prototype.toBTC = function() {
return this.to(Unit.BTC);
};
/**
*
* Will return the value represented in mBTC
*
* @returns {Number} The value converted to mBTC
*/
Unit.prototype.toMilis = function(code) {
return this.to(Unit.mBTC);
};
/**
*
* Will return the value represented in bits
*
* @returns {Number} The value converted to bits
*/
Unit.prototype.toBits = function(code) {
return this.to(Unit.bits);
};
/**
*
* Will return the value represented in satoshis
*
* @returns {Number} The value converted to satoshis
*/
Unit.prototype.toSatoshis = function() {
return this.to(Unit.satoshis);
};
/**
*
* Will return a the string representation of the value in satoshis
*
* @returns {String} the value in satoshis
*/
Unit.prototype.toString = function() {
return this.satoshis + ' satoshis';
};
/**
*
* Will return a string formatted for the console
*
* @returns {String} the value in satoshis
*/
Unit.prototype.inspect = function() {
return '<Unit: ' + this.toString() + '>';
};
module.exports = Unit;

132
test/unit.js Normal file
View File

@ -0,0 +1,132 @@
'use strict';
var should = require('chai').should();
var bitcore = require('..');
var Unit = bitcore.Unit;
describe('Unit', function() {
it('should create an instance', function() {
var unit;
unit = new Unit(1.2, 'BTC');
should.exist(unit);
unit = Unit(1.2, 'BTC');
should.exist(unit);
});
it('should have property accesors', function() {
var unit = new Unit(1.2, 'BTC');
should.exist(unit.BTC);
should.exist(unit.mBTC);
should.exist(unit.bits);
should.exist(unit.satoshis);
});
it('should allow amount as string', function() {
var unit;
unit = Unit.fromBTC('1.00001');
unit.BTC.should.equal(1.00001);
unit = Unit.fromMilis('1.00001');
unit.mBTC.should.equal(1.00001);
unit = Unit.fromBits('100');
unit.bits.should.equal(100);
unit = Unit.fromSatoshis('8999');
unit.satoshis.should.equal(8999);
});
it('should have constructor helpers', function() {
var unit;
unit = Unit.fromBTC(1.00001);
unit.BTC.should.equal(1.00001);
unit = Unit.fromMilis(1.00001);
unit.mBTC.should.equal(1.00001);
unit = Unit.fromBits(100);
unit.bits.should.equal(100);
unit = Unit.fromSatoshis(8999);
unit.satoshis.should.equal(8999);
});
it('should convert to satoshis correctly', function() {
var unit;
unit = Unit.fromBTC(1.3);
unit.mBTC.should.equal(1300);
unit.bits.should.equal(1300000);
unit.satoshis.should.equal(130000000);
unit = Unit.fromMilis(1.3);
unit.BTC.should.equal(0.0013);
unit.bits.should.equal(1300);
unit.satoshis.should.equal(130000);
unit = Unit.fromBits(1.3);
unit.BTC.should.equal(0.0000013);
unit.mBTC.should.equal(0.0013);
unit.satoshis.should.equal(130);
unit = Unit.fromSatoshis(3);
unit.BTC.should.equal(0.00000003);
unit.mBTC.should.equal(0.00003);
unit.bits.should.equal(0.03);
});
it('should take in count floating point problems', function() {
var unit = Unit.fromBTC(0.00000003);
unit.mBTC.should.equal(0.00003);
unit.bits.should.equal(0.03);
unit.satoshis.should.equal(3);
});
it('should expose unit codes', function() {
should.exist(Unit.BTC);
Unit.BTC.should.equal('BTC');
should.exist(Unit.mBTC);
Unit.mBTC.should.equal('mBTC');
should.exist(Unit.bits);
Unit.bits.should.equal('bits');
should.exist(Unit.satoshis);
Unit.satoshis.should.equal('satoshis');
});
it('should expose shorthand conversion methods', function() {
var unit = new Unit(1.3, 'BTC');
unit.toBTC().should.equal(unit.BTC);
unit.toMilis().should.equal(unit.mBTC);
unit.toBits().should.equal(unit.bits);
unit.toSatoshis().should.equal(unit.satoshis);
});
it('should expose a general conversion method', function() {
var unit = new Unit(1.3, 'BTC');
unit.to(Unit.BTC).should.equal(unit.BTC);
unit.to(Unit.mBTC).should.equal(unit.mBTC);
unit.to(Unit.bits).should.equal(unit.bits);
unit.to(Unit.satoshis).should.equal(unit.satoshis);
});
it('should have a toString method', function() {
var unit = new Unit(1.3, 'BTC');
should.exist(unit.toString);
unit.toString().should.be.a('string');
});
it('should have an inspect method', function() {
var unit = new Unit(1.3, 'BTC');
should.exist(unit.inspect);
unit.inspect().should.be.a('string');
});
});