Merge pull request #726 from braydonf/feature/standardized-interface
Standardized toJSON, fromJSON, toString and fromString interfaces
This commit is contained in:
commit
f108cc7ea5
|
@ -3,6 +3,7 @@
|
|||
var base58check = require('./encoding/base58check');
|
||||
var Networks = require('./networks');
|
||||
var Hash = require('./crypto/hash');
|
||||
var JSUtil = require('./util/js');
|
||||
|
||||
/**
|
||||
* Instantiate an address from an address String or Buffer, a public key or script hash Buffer,
|
||||
|
@ -305,6 +306,20 @@ Address.fromString = function(str, network, type) {
|
|||
return new Address(info.hashBuffer, info.network, info.type);
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiate an address from JSON
|
||||
*
|
||||
* @param {String} json - An JSON string or Object with keys: hash, network and type
|
||||
* @returns {Address} A new valid instance of an Address
|
||||
*/
|
||||
Address.fromJSON = function fromJSON(json) {
|
||||
if (JSUtil.isValidJson(json)) {
|
||||
json = JSON.parse(json);
|
||||
}
|
||||
var hashBuffer = new Buffer(json.hash, 'hex');
|
||||
return new Address(hashBuffer, json.network, json.type);
|
||||
};
|
||||
|
||||
/**
|
||||
* Will return a validation error if exists
|
||||
*
|
||||
|
@ -372,6 +387,17 @@ Address.prototype.toBuffer = function() {
|
|||
return buf;
|
||||
};
|
||||
|
||||
/**
|
||||
* @returns {Object} An object of the address
|
||||
*/
|
||||
Address.prototype.toJSON = function toJSON() {
|
||||
return {
|
||||
hash: this.hashBuffer.toString('hex'),
|
||||
type: this.type,
|
||||
network: this.network.toString()
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Will return a the string representation of the address
|
||||
*
|
||||
|
|
16
lib/block.js
16
lib/block.js
|
@ -121,6 +121,15 @@ Block.fromBuffer = function fromBuffer(buf) {
|
|||
return Block.fromBufferReader(BufferReader(buf));
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {String} - str - A hex encoded string of the block
|
||||
* @returns {Block} - A hex encoded string of the block
|
||||
*/
|
||||
Block.fromString = function fromString(str) {
|
||||
var buf = new Buffer(str, 'hex');
|
||||
return Block.fromBuffer(buf);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Binary} - Raw block binary data or buffer
|
||||
* @returns {Block} - An instance of block
|
||||
|
@ -158,6 +167,13 @@ Block.prototype.toBuffer = function toBuffer() {
|
|||
return this.toBufferWriter().concat();
|
||||
};
|
||||
|
||||
/**
|
||||
* @returns {String} - A hex encoded string of the block
|
||||
*/
|
||||
Block.prototype.toString = function toString() {
|
||||
return this.toBuffer().toString('hex');
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {BufferWriter} - An existing instance of BufferWriter
|
||||
* @returns {BufferWriter} - An instance of BufferWriter representation of the Block
|
||||
|
|
|
@ -103,6 +103,15 @@ BlockHeader.fromBuffer = function fromBuffer(buf) {
|
|||
return new BlockHeader(info);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {String} - A hex encoded buffer of the block header
|
||||
* @returns {BlockHeader} - An instance of block header
|
||||
*/
|
||||
BlockHeader.fromString = function fromString(str) {
|
||||
var buf = new Buffer(str, 'hex');
|
||||
return BlockHeader.fromBuffer(buf);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {BufferReader} - A BufferReader of the block header
|
||||
* @returns {Object} - An object representing block header data
|
||||
|
@ -150,6 +159,13 @@ BlockHeader.prototype.toBuffer = function toBuffer() {
|
|||
return this.toBufferWriter().concat();
|
||||
};
|
||||
|
||||
/**
|
||||
* @returns {String} - A hex encoded string of the BlockHeader
|
||||
*/
|
||||
BlockHeader.prototype.toString = function toString() {
|
||||
return this.toBuffer().toString('hex');
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {BufferWriter} - An existing instance BufferWriter
|
||||
* @returns {BufferWriter} - An instance of BufferWriter representation of the BlockHeader
|
||||
|
|
37
lib/unit.js
37
lib/unit.js
|
@ -1,5 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
var JSUtil = require('./util/js');
|
||||
|
||||
/**
|
||||
*
|
||||
* Bitcore Unit
|
||||
|
@ -27,6 +29,9 @@ function Unit(amount, code) {
|
|||
return new Unit(amount, code);
|
||||
}
|
||||
|
||||
this._amount = amount;
|
||||
this._code = code;
|
||||
|
||||
this._value = this._from(amount, code);
|
||||
|
||||
var self = this;
|
||||
|
@ -51,9 +56,20 @@ Object.keys(UNITS).forEach(function(key) {
|
|||
Unit[key] = key;
|
||||
});
|
||||
|
||||
/**
|
||||
* Will return 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.fromJSON = function fromJSON(json){
|
||||
if (JSUtil.isValidJson(json)) {
|
||||
json = JSON.parse(json);
|
||||
}
|
||||
return new Unit(json.amount, json.code);
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* Will return a Unit instance created from an amount in BTC
|
||||
*
|
||||
* @param {Number} amount - The amount in BTC
|
||||
|
@ -64,7 +80,6 @@ Unit.fromBTC = function(amount) {
|
|||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* Will return a Unit instance created from an amount in mBTC
|
||||
*
|
||||
* @param {Number} amount - The amount in mBTC
|
||||
|
@ -75,7 +90,6 @@ Unit.fromMilis = function(amount) {
|
|||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* Will return a Unit instance created from an amount in bits
|
||||
*
|
||||
* @param {Number} amount - The amount in bits
|
||||
|
@ -86,7 +100,6 @@ Unit.fromBits = function(amount) {
|
|||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* Will return a Unit instance created from an amount in satoshis
|
||||
*
|
||||
* @param {Number} amount - The amount in satoshis
|
||||
|
@ -103,7 +116,6 @@ Unit.prototype._from = function(amount, code) {
|
|||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* Will return the value represented in the specified unit
|
||||
*
|
||||
* @param {string} code - The unit code
|
||||
|
@ -117,7 +129,6 @@ Unit.prototype.to = function(code) {
|
|||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* Will return the value represented in BTC
|
||||
*
|
||||
* @returns {Number} The value converted to BTC
|
||||
|
@ -137,7 +148,6 @@ Unit.prototype.toMilis = function(code) {
|
|||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* Will return the value represented in bits
|
||||
*
|
||||
* @returns {Number} The value converted to bits
|
||||
|
@ -147,7 +157,6 @@ Unit.prototype.toBits = function(code) {
|
|||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* Will return the value represented in satoshis
|
||||
*
|
||||
* @returns {Number} The value converted to satoshis
|
||||
|
@ -157,7 +166,6 @@ Unit.prototype.toSatoshis = function() {
|
|||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* Will return a the string representation of the value in satoshis
|
||||
*
|
||||
* @returns {String} the value in satoshis
|
||||
|
@ -167,7 +175,18 @@ Unit.prototype.toString = function() {
|
|||
};
|
||||
|
||||
/**
|
||||
* Will return a the JSON object representation of the unit
|
||||
*
|
||||
* @returns {Object} An object with the keys: amount and code
|
||||
*/
|
||||
Unit.prototype.toJSON = function toJSON(){
|
||||
return {
|
||||
amount: this._amount,
|
||||
code: this._code
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Will return a string formatted for the console
|
||||
*
|
||||
* @returns {String} the value in satoshis
|
||||
|
|
90
lib/uri.js
90
lib/uri.js
|
@ -5,9 +5,9 @@ var URL = require('url');
|
|||
|
||||
var Address = require('./address');
|
||||
var Unit = require('./unit');
|
||||
var JSUtil = require('./util/js');
|
||||
|
||||
/**
|
||||
*
|
||||
* Bitcore URI
|
||||
*
|
||||
* Instantiate an URI from a bitcoin URI String or an Object. An URI instance
|
||||
|
@ -35,11 +35,13 @@ var URI = function(data, knownParams) {
|
|||
this.knownParams = knownParams || [];
|
||||
this.address = this.network = this.amount = this.message = null;
|
||||
|
||||
if (typeof(data) == 'string') {
|
||||
if (typeof(data) === 'string') {
|
||||
var params = URI.parse(data);
|
||||
if (params.amount) params.amount = this._parseAmount(params.amount);
|
||||
if (params.amount) {
|
||||
params.amount = this._parseAmount(params.amount);
|
||||
}
|
||||
this._fromObject(params);
|
||||
} else if (typeof(data) == 'object') {
|
||||
} else if (typeof(data) === 'object') {
|
||||
this._fromObject(data);
|
||||
} else {
|
||||
throw new TypeError('Unrecognized data format.');
|
||||
|
@ -47,7 +49,32 @@ var URI = function(data, knownParams) {
|
|||
};
|
||||
|
||||
/**
|
||||
* Instantiate a URI from a String
|
||||
*
|
||||
* @param {String} str - JSON string or object of the URI
|
||||
* @returns {URI} A new instance of a URI
|
||||
*/
|
||||
URI.fromString = function fromString(str) {
|
||||
if (typeof(str) !== 'string') {
|
||||
throw TypeError('Expected a string');
|
||||
}
|
||||
return new URI(str);
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiate a URI from JSON
|
||||
*
|
||||
* @param {String|Object} json - JSON string or object of the URI
|
||||
* @returns {URI} A new instance of a URI
|
||||
*/
|
||||
URI.fromJSON = function fromJSON(json) {
|
||||
if (JSUtil.isValidJson(json)) {
|
||||
json = JSON.parse(json);
|
||||
}
|
||||
return new URI(json);
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if an bitcoin URI string is valid
|
||||
*
|
||||
* @example
|
||||
|
@ -69,7 +96,6 @@ URI.isValid = function(arg, knownParams) {
|
|||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* Convert a bitcoin URI string into a simple object.
|
||||
*
|
||||
* @param {string} uri - A bitcoin URI string
|
||||
|
@ -90,8 +116,9 @@ URI.parse = function(uri) {
|
|||
return info.query;
|
||||
};
|
||||
|
||||
URI.Members = ['address', 'amount', 'message', 'label', 'r'];
|
||||
|
||||
/**
|
||||
*
|
||||
* Internal function to load the URI instance with an object.
|
||||
*
|
||||
* @param {Object} obj - Object with the information
|
||||
|
@ -100,9 +127,10 @@ URI.parse = function(uri) {
|
|||
* @throws {Error} Unknown required argument
|
||||
*/
|
||||
URI.prototype._fromObject = function(obj) {
|
||||
var members = ['address', 'amount', 'message', 'label', 'r'];
|
||||
|
||||
if (!Address.isValid(obj.address)) throw new TypeError('Invalid bitcoin address');
|
||||
if (!Address.isValid(obj.address)) {
|
||||
throw new TypeError('Invalid bitcoin address');
|
||||
}
|
||||
|
||||
this.address = new Address(obj.address);
|
||||
this.network = this.address.network;
|
||||
|
@ -115,13 +143,12 @@ URI.prototype._fromObject = function(obj) {
|
|||
throw Error('Unknown required argument ' + key);
|
||||
}
|
||||
|
||||
var destination = members.indexOf(key) > -1 ? this : this.extras;
|
||||
var destination = URI.Members.indexOf(key) > -1 ? this : this.extras;
|
||||
destination[key] = obj[key];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* Internal function to transform a BTC string amount into satoshis
|
||||
*
|
||||
* @param {String} amount - Amount BTC string
|
||||
|
@ -129,21 +156,49 @@ URI.prototype._fromObject = function(obj) {
|
|||
* @returns {Object} Amount represented in satoshis
|
||||
*/
|
||||
URI.prototype._parseAmount = function(amount) {
|
||||
var amount = Number(amount);
|
||||
if (isNaN(amount)) throw new TypeError('Invalid amount');
|
||||
amount = Number(amount);
|
||||
if (isNaN(amount)) {
|
||||
throw new TypeError('Invalid amount');
|
||||
}
|
||||
return Unit.fromBTC(amount).toSatoshis();
|
||||
};
|
||||
|
||||
URI.prototype.toJSON = function() {
|
||||
var json = {};
|
||||
for (var i = 0; i < URI.Members.length; i++) {
|
||||
var m = URI.Members[i];
|
||||
if (this.hasOwnProperty(m) && typeof(this[m]) !== 'undefined') {
|
||||
if (typeof(this[m].toString) === 'function') {
|
||||
json[m] = this[m].toString();
|
||||
} else {
|
||||
json[m] = this[m];
|
||||
}
|
||||
}
|
||||
}
|
||||
_.extend(json, this.extras);
|
||||
return json;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* Will return a the string representation of the URI
|
||||
*
|
||||
* @returns {String} Bitcoin URI string
|
||||
*/
|
||||
URI.prototype.toString = function() {
|
||||
var query = _.clone(this.extras);
|
||||
if (this.amount) query.amount = Unit.fromSatoshis(this.amount).toBTC();
|
||||
if (this.message) query.message = this.message;
|
||||
var query = {};
|
||||
if (this.amount) {
|
||||
query.amount = Unit.fromSatoshis(this.amount).toBTC();
|
||||
}
|
||||
if (this.message) {
|
||||
query.message = this.message;
|
||||
}
|
||||
if (this.label) {
|
||||
query.label = this.label;
|
||||
}
|
||||
if (this.r) {
|
||||
query.r = this.r;
|
||||
}
|
||||
_.extend(query, this.extras);
|
||||
|
||||
return URL.format({
|
||||
protocol: 'bitcoin:',
|
||||
|
@ -153,13 +208,12 @@ URI.prototype.toString = function() {
|
|||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* Will return a string formatted for the console
|
||||
*
|
||||
* @returns {String} Bitcoin URI
|
||||
*/
|
||||
URI.prototype.inspect = function() {
|
||||
return '<URI: ' + this.toString() + '>';
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = URI;
|
||||
|
|
|
@ -355,6 +355,21 @@ describe('Address', function() {
|
|||
|
||||
});
|
||||
|
||||
describe('#json', function() {
|
||||
|
||||
it('should output/input a JSON object', function() {
|
||||
var address = Address.fromJSON(new Address(str).toJSON());
|
||||
address.toString().should.equal(str);
|
||||
});
|
||||
|
||||
it('should output/input a JSON string', function() {
|
||||
var json = JSON.stringify(new Address(str).toJSON());
|
||||
var address = Address.fromJSON(json);
|
||||
address.toString().should.equal(str);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#toString', function() {
|
||||
|
||||
it('should output a livenet pubkeyhash address', function() {
|
||||
|
|
|
@ -118,6 +118,15 @@ describe('Block', function() {
|
|||
|
||||
});
|
||||
|
||||
describe('#fromString/#toString', function() {
|
||||
|
||||
it('should output/input a block hex string', function() {
|
||||
var b = Block.fromString(blockhex);
|
||||
b.toString().should.equal(blockhex);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#fromBuffer', function() {
|
||||
|
||||
it('should make a block from this known buffer', function() {
|
||||
|
|
|
@ -122,6 +122,15 @@ describe('BlockHeader', function() {
|
|||
|
||||
});
|
||||
|
||||
describe('#fromString/#toString', function() {
|
||||
|
||||
it('should output/input a block hex string', function() {
|
||||
var b = BlockHeader.fromString(bhhex);
|
||||
b.toString().should.equal(bhhex);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#fromBuffer', function() {
|
||||
|
||||
it('should parse this known buffer', function() {
|
||||
|
|
|
@ -123,6 +123,12 @@ describe('Unit', function() {
|
|||
unit.toString().should.be.a('string');
|
||||
});
|
||||
|
||||
it('should input/output JSON', function() {
|
||||
var json = {amount:1.3, code:'BTC'};
|
||||
var unit = Unit.fromJSON(json);
|
||||
unit.toJSON().should.deep.equal(json);
|
||||
});
|
||||
|
||||
it('should have an inspect method', function() {
|
||||
var unit = new Unit(1.3, 'BTC');
|
||||
should.exist(unit.inspect);
|
||||
|
|
22
test/uri.js
22
test/uri.js
|
@ -65,6 +65,11 @@ describe('URI', function() {
|
|||
uri.address.should.be.instanceof(bitcore.Address);
|
||||
uri.network.should.equal(Networks.livenet);
|
||||
|
||||
uri = URI.fromString('bitcoin:1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj?amount=123.22');
|
||||
uri.address.toString().should.equal('1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj');
|
||||
uri.amount.should.equal(12322000000);
|
||||
expect(uri.otherParam).to.be.undefined;
|
||||
|
||||
uri = new URI('bitcoin:mkYY5NRvikVBY1EPtaq9fAFgquesdjqECw');
|
||||
uri.address.should.be.instanceof(bitcore.Address);
|
||||
uri.network.should.equal(Networks.testnet);
|
||||
|
@ -135,6 +140,21 @@ describe('URI', function() {
|
|||
uri.address.toString().should.equal('1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj');
|
||||
});
|
||||
|
||||
it('should input/output String', function() {
|
||||
var str = 'bitcoin:1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj?message=Donation%20for%20project%20xyz&label=myLabel&other=xD';
|
||||
URI.fromString(str).toString().should.equal(str);
|
||||
});
|
||||
|
||||
it('should input/output JSON', function() {
|
||||
var json = {
|
||||
address: '1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj',
|
||||
message: 'Donation for project xyz',
|
||||
label: 'myLabel',
|
||||
other: 'xD'
|
||||
};
|
||||
URI.fromJSON(json).toJSON().should.deep.equal(json);
|
||||
});
|
||||
|
||||
it('should support numeric amounts', function() {
|
||||
var uri = new URI('bitcoin:1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj?amount=12.10001');
|
||||
expect(uri.amount).to.be.equal(1210001000);
|
||||
|
@ -166,7 +186,7 @@ describe('URI', function() {
|
|||
message: 'Hello World',
|
||||
something: 'else'
|
||||
}).toString().should.equal(
|
||||
'bitcoin:1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj?something=else&amount=1.10001&message=Hello%20World'
|
||||
'bitcoin:1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj?amount=1.10001&message=Hello%20World&something=else'
|
||||
);
|
||||
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue