Add BIP21 implementation
This commit is contained in:
parent
3b60170e9f
commit
ac525f226c
|
@ -46,6 +46,7 @@ requireWhenAccessed('BinaryParser', './util/BinaryParser');
|
||||||
requireWhenAccessed('Address', './lib/Address');
|
requireWhenAccessed('Address', './lib/Address');
|
||||||
requireWhenAccessed('AuthMessage', './lib/AuthMessage');
|
requireWhenAccessed('AuthMessage', './lib/AuthMessage');
|
||||||
requireWhenAccessed('HierarchicalKey', './lib/HierarchicalKey');
|
requireWhenAccessed('HierarchicalKey', './lib/HierarchicalKey');
|
||||||
|
requireWhenAccessed('BIP21', './lib/BIP21');
|
||||||
Object.defineProperty(module.exports, 'BIP32', {
|
Object.defineProperty(module.exports, 'BIP32', {
|
||||||
get: function() {
|
get: function() {
|
||||||
console.log('BIP32 is deprecated. Use bitcore.HierarchicalKey instead.');
|
console.log('BIP32 is deprecated. Use bitcore.HierarchicalKey instead.');
|
||||||
|
|
|
@ -16,6 +16,7 @@ var modules = [
|
||||||
'lib/AuthMessage',
|
'lib/AuthMessage',
|
||||||
'lib/Base58',
|
'lib/Base58',
|
||||||
'lib/HierarchicalKey',
|
'lib/HierarchicalKey',
|
||||||
|
'lib/BIP21',
|
||||||
'lib/BIP39',
|
'lib/BIP39',
|
||||||
'lib/BIP39WordlistEn',
|
'lib/BIP39WordlistEn',
|
||||||
'lib/Block',
|
'lib/Block',
|
||||||
|
@ -73,6 +74,7 @@ var createBitcore = function(opts) {
|
||||||
//modules included in "all" but not included in "main" bundle
|
//modules included in "all" but not included in "main" bundle
|
||||||
if (opts.includemain) {
|
if (opts.includemain) {
|
||||||
submodules = JSON.parse(JSON.stringify(modules));
|
submodules = JSON.parse(JSON.stringify(modules));
|
||||||
|
submodules.splice(submodules.indexOf('lib/BIP21'), 1);
|
||||||
submodules.splice(submodules.indexOf('lib/BIP39'), 1);
|
submodules.splice(submodules.indexOf('lib/BIP39'), 1);
|
||||||
submodules.splice(submodules.indexOf('lib/BIP39WordlistEn'), 1);
|
submodules.splice(submodules.indexOf('lib/BIP39WordlistEn'), 1);
|
||||||
submodules.splice(submodules.indexOf('lib/PayPro'), 1);
|
submodules.splice(submodules.indexOf('lib/PayPro'), 1);
|
||||||
|
|
42015
browser/bundle.js
42015
browser/bundle.js
File diff suppressed because one or more lines are too long
|
@ -1121,6 +1121,7 @@ var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
||||||
? Uint8Array
|
? Uint8Array
|
||||||
: Array
|
: Array
|
||||||
|
|
||||||
|
var ZERO = '0'.charCodeAt(0)
|
||||||
var PLUS = '+'.charCodeAt(0)
|
var PLUS = '+'.charCodeAt(0)
|
||||||
var SLASH = '/'.charCodeAt(0)
|
var SLASH = '/'.charCodeAt(0)
|
||||||
var NUMBER = '0'.charCodeAt(0)
|
var NUMBER = '0'.charCodeAt(0)
|
||||||
|
@ -1229,9 +1230,9 @@ var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.toByteArray = b64ToByteArray
|
module.exports.toByteArray = b64ToByteArray
|
||||||
exports.fromByteArray = uint8ToBase64
|
module.exports.fromByteArray = uint8ToBase64
|
||||||
}(typeof exports === 'undefined' ? (this.base64js = {}) : exports))
|
}())
|
||||||
|
|
||||||
},{}],4:[function(require,module,exports){
|
},{}],4:[function(require,module,exports){
|
||||||
exports.read = function(buffer, offset, isLE, mLen, nBytes) {
|
exports.read = function(buffer, offset, isLE, mLen, nBytes) {
|
||||||
|
@ -2002,8 +2003,8 @@ function hasOwnProperty(obj, prop) {
|
||||||
return Object.prototype.hasOwnProperty.call(obj, prop);
|
return Object.prototype.hasOwnProperty.call(obj, prop);
|
||||||
}
|
}
|
||||||
|
|
||||||
}).call(this,require("/home/maraoz/git/bitcore/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js"),typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
}).call(this,require("/Users/yemeljardi/code/bitcore/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js"),typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
||||||
},{"./support/isBuffer":7,"/home/maraoz/git/bitcore/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":6,"inherits":5}],"3kNi7S":[function(require,module,exports){
|
},{"./support/isBuffer":7,"/Users/yemeljardi/code/bitcore/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":6,"inherits":5}],"3kNi7S":[function(require,module,exports){
|
||||||
/*jslint eqeqeq: false, onevar: false, forin: true, nomen: false, regexp: false, plusplus: false*/
|
/*jslint eqeqeq: false, onevar: false, forin: true, nomen: false, regexp: false, plusplus: false*/
|
||||||
/*global module, require, __dirname, document*/
|
/*global module, require, __dirname, document*/
|
||||||
/**
|
/**
|
||||||
|
@ -2930,8 +2931,8 @@ module.exports=require('3kNi7S');
|
||||||
}
|
}
|
||||||
}(typeof sinon == "object" && sinon || null));
|
}(typeof sinon == "object" && sinon || null));
|
||||||
|
|
||||||
}).call(this,require("/home/maraoz/git/bitcore/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js"))
|
}).call(this,require("/Users/yemeljardi/code/bitcore/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js"))
|
||||||
},{"../sinon":"3kNi7S","/home/maraoz/git/bitcore/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":6}],13:[function(require,module,exports){
|
},{"../sinon":"3kNi7S","/Users/yemeljardi/code/bitcore/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":6}],13:[function(require,module,exports){
|
||||||
/**
|
/**
|
||||||
* @depend ../sinon.js
|
* @depend ../sinon.js
|
||||||
* @depend match.js
|
* @depend match.js
|
||||||
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// BIP21
|
||||||
|
// =======
|
||||||
|
// Helper for parsing and building bitcoin: URIs
|
||||||
|
//
|
||||||
|
// Examples:
|
||||||
|
// =======
|
||||||
|
// var uriString = 'bitcoin:1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj?message=Hey%20there&amount=1.212';
|
||||||
|
//
|
||||||
|
// var uri = new BIP21(uriString);
|
||||||
|
// uri.isValid() // true
|
||||||
|
// uri.address // bitcore.Address object
|
||||||
|
// uri.data.message // 'Hey there'
|
||||||
|
// uri.data.amount // 1.212
|
||||||
|
//
|
||||||
|
// uriString = new BIP21({
|
||||||
|
// address: '1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj',
|
||||||
|
// message: 'Hey there',
|
||||||
|
// amount: 1.212
|
||||||
|
// }).getURI();
|
||||||
|
|
||||||
|
|
||||||
|
var URL = require('url');
|
||||||
|
var Address = require('./Address');
|
||||||
|
|
||||||
|
var BIP21 = function(arg) {
|
||||||
|
this.data = {};
|
||||||
|
this.address = undefined;
|
||||||
|
|
||||||
|
if (typeof(arg) == 'string') {
|
||||||
|
this.parse(arg);
|
||||||
|
} else if (typeof(arg) == 'object') {
|
||||||
|
this.fromObj(arg);
|
||||||
|
} else if (typeof(arg) != 'undefined') {
|
||||||
|
throw new Error('Invalid argument');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BIP21.prototype.fromObj = function(obj) {
|
||||||
|
for (var key in obj) {
|
||||||
|
this.data[key] = obj[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj.address) {
|
||||||
|
delete this.data.address;
|
||||||
|
this.setAddress(obj.address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BIP21.prototype.parse = function(uri) {
|
||||||
|
var info = URL.parse(uri, true);
|
||||||
|
|
||||||
|
if (info.protocol != 'bitcoin:') {
|
||||||
|
throw new Error('Invalid protocol');
|
||||||
|
}
|
||||||
|
|
||||||
|
// workaround to host insensitiveness
|
||||||
|
var group = uri.match('[^:]*:/?/?([^?]*)');
|
||||||
|
this.setAddress(group && group[1]);
|
||||||
|
|
||||||
|
for (var arg in info.query) {
|
||||||
|
var val = info.query[arg];
|
||||||
|
if (arg == 'amount') val = Number(val);
|
||||||
|
this.data[arg] = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BIP21.prototype.isValid = function() {
|
||||||
|
var valid = true;
|
||||||
|
|
||||||
|
if (typeof(this.data.amount) != 'undefined') {
|
||||||
|
valid &= !isNaN(this.data.amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.address) {
|
||||||
|
valid &= typeof(this.address) == 'object' && this.address.isValid();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Require address or PayPro info
|
||||||
|
valid &= !!(this.address || this.data.r);
|
||||||
|
|
||||||
|
return !!valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
BIP21.prototype.setAddress = function(addr) {
|
||||||
|
if (addr) {
|
||||||
|
this.address = Address.validate(addr) ? new Address(addr) : addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
BIP21.prototype.getURI = function() {
|
||||||
|
if (!this.isValid()) throw new Error('Invalid state');
|
||||||
|
|
||||||
|
return URL.format({
|
||||||
|
protocol: 'bitcoin:',
|
||||||
|
host: this.address,
|
||||||
|
query: this.data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = BIP21;
|
|
@ -21,6 +21,7 @@
|
||||||
<script src="test.Base58.js"></script>
|
<script src="test.Base58.js"></script>
|
||||||
<script src="test.basic.js"></script>
|
<script src="test.basic.js"></script>
|
||||||
<script src="test.Bignum.js"></script>
|
<script src="test.Bignum.js"></script>
|
||||||
|
<script src="test.BIP21.js"></script>
|
||||||
<script src="test.BIP39.js"></script>
|
<script src="test.BIP39.js"></script>
|
||||||
<script src="test.Block.js"></script>
|
<script src="test.Block.js"></script>
|
||||||
<script src="test.Bloom.js"></script>
|
<script src="test.Bloom.js"></script>
|
||||||
|
|
|
@ -0,0 +1,157 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var chai = chai || require('chai');
|
||||||
|
var should = chai.should();
|
||||||
|
var bitcore = bitcore || require('../bitcore');
|
||||||
|
var BIP21 = bitcore.BIP21;
|
||||||
|
|
||||||
|
describe('BIP21', function() {
|
||||||
|
|
||||||
|
it('should support livent address', function() {
|
||||||
|
var uri;
|
||||||
|
|
||||||
|
uri = new BIP21('bitcoin:1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj');
|
||||||
|
uri.isValid().should.be.true;
|
||||||
|
uri.address.network().name = 'livenet';
|
||||||
|
uri.address.toString().should.equal('1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj');
|
||||||
|
|
||||||
|
uri = new BIP21('bitcoin:3FDFgmroEu5EFxxhHUkZL8vNJ3xrjUF3mB');
|
||||||
|
uri.isValid().should.be.true;
|
||||||
|
uri.address.network().name = 'livenet';
|
||||||
|
uri.address.toString().should.equal('3FDFgmroEu5EFxxhHUkZL8vNJ3xrjUF3mB');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should support testnet address', function() {
|
||||||
|
var uri;
|
||||||
|
|
||||||
|
uri = new BIP21('bitcoin:myNUd9RyL6VcLNdiTkYPDz9pQK6fo2JqYy');
|
||||||
|
uri.isValid().should.be.true;
|
||||||
|
uri.address.network().name = 'testnet';
|
||||||
|
uri.address.toString().should.equal('myNUd9RyL6VcLNdiTkYPDz9pQK6fo2JqYy');
|
||||||
|
|
||||||
|
uri = new BIP21('bitcoin:2N3EPfMSXoaEcNfuvLETKVfF4iddDsnwoYN');
|
||||||
|
uri.isValid().should.be.true;
|
||||||
|
uri.address.network().name = 'testnet';
|
||||||
|
uri.address.toString().should.equal('2N3EPfMSXoaEcNfuvLETKVfF4iddDsnwoYN');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should support double slash scheme', function() {
|
||||||
|
var uri = new BIP21('bitcoin://1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj');
|
||||||
|
uri.isValid().should.be.true;
|
||||||
|
uri.address.toString().should.equal('1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should support numeric amounts', function() {
|
||||||
|
var uri = new BIP21('bitcoin:1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj?amount=12.10001');
|
||||||
|
uri.isValid().should.be.true;
|
||||||
|
should.exist(uri.data.amount);
|
||||||
|
uri.data.amount.should.equal(12.10001);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should support extra arguments', function() {
|
||||||
|
var uri = new BIP21('bitcoin:1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj?message=Donation%20for%20project%20xyz&label=myLabel&other=xD');
|
||||||
|
uri.isValid().should.be.true;
|
||||||
|
|
||||||
|
should.exist(uri.data.message);
|
||||||
|
uri.data.message.should.equal('Donation for project xyz');
|
||||||
|
|
||||||
|
should.exist(uri.data.label);
|
||||||
|
uri.data.label.should.equal('myLabel');
|
||||||
|
|
||||||
|
should.exist(uri.data.other);
|
||||||
|
uri.data.other.should.equal('xD');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should validate address', function() {
|
||||||
|
var uri = new BIP21('bitcoin:invalidAddress');
|
||||||
|
uri.isValid().should.be.false;
|
||||||
|
uri.address.should.equal('invalidAddress');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should validate amount', function() {
|
||||||
|
var uri = new BIP21('bitcoin:1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj?amount=bad');
|
||||||
|
uri.isValid().should.be.false;
|
||||||
|
isNaN(uri.data.amount).should.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should support payment protocol', function() {
|
||||||
|
var uri = new BIP21('bitcoin:?message=Hi');
|
||||||
|
uri.isValid().should.be.false;
|
||||||
|
|
||||||
|
uri = new BIP21('bitcoin:?message=Hi&r=some-data');
|
||||||
|
uri.isValid().should.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should build from an object', function() {
|
||||||
|
var uri = new BIP21({
|
||||||
|
address: '1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj',
|
||||||
|
amount: 1.10001,
|
||||||
|
message: 'Hello World'
|
||||||
|
});
|
||||||
|
|
||||||
|
uri.isValid().should.be.true;
|
||||||
|
uri.address.toString().should.equal('1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj');
|
||||||
|
uri.data.amount.should.equal(1.10001);
|
||||||
|
uri.data.message.should.equal('Hello World');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should build from an object', function() {
|
||||||
|
var uri = new BIP21({
|
||||||
|
address: new bitcore.Address('1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj'),
|
||||||
|
amount: 1.10001,
|
||||||
|
message: 'Hello World'
|
||||||
|
});
|
||||||
|
|
||||||
|
uri.isValid().should.be.true;
|
||||||
|
uri.address.toString().should.equal('1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj');
|
||||||
|
uri.data.amount.should.equal(1.10001);
|
||||||
|
uri.data.message.should.equal('Hello World');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should generate a valid URI', function() {
|
||||||
|
new BIP21({
|
||||||
|
address: '1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj',
|
||||||
|
}).getURI().should.equal(
|
||||||
|
'bitcoin:1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj'
|
||||||
|
);
|
||||||
|
|
||||||
|
new BIP21({
|
||||||
|
address: '1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj',
|
||||||
|
amount: 1.10001,
|
||||||
|
message: 'Hello World'
|
||||||
|
}).getURI().should.equal(
|
||||||
|
'bitcoin:1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj?amount=1.10001&message=Hello%20World'
|
||||||
|
);
|
||||||
|
|
||||||
|
new BIP21({
|
||||||
|
r: 'payment-info'
|
||||||
|
}).getURI().should.equal(
|
||||||
|
'bitcoin:?r=payment-info'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fail with wrong arguments', function() {
|
||||||
|
(function() {
|
||||||
|
new BIP21(12);
|
||||||
|
}).should.throw(Error);
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
new BIP21();
|
||||||
|
}).should.not.throw(Error);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be case insensitive to protocol', function() {
|
||||||
|
var uri1 = new BIP21('bItcOin:1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj');
|
||||||
|
var uri2 = new BIP21('bitcoin:1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj');
|
||||||
|
|
||||||
|
uri1.address.toString().should.equal(uri2.address.toString());
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should setAddress correctly', function() {
|
||||||
|
var uri = new BIP21();
|
||||||
|
uri.isValid().should.be.false;
|
||||||
|
|
||||||
|
uri.setAddress('1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj');
|
||||||
|
uri.address.network().name.should.equal('livenet');
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue