Starting to work on more comprehensive handling of cashAddr format. Basic handling of cashAddr on testnet.

This commit is contained in:
Brendon Duncan 2018-08-27 20:46:11 +12:00
commit 1be9ce39c1
2 changed files with 104 additions and 14 deletions

View file

@ -6,8 +6,11 @@
.module('bitcoincom.services')
.factory('bitcoinUriService', bitcoinUriService);
function bitcoinUriService(bitcoinCashJsService, bwcService) {
function bitcoinUriService(bitcoinCashJsService, bwcService, $log) {
var bch = bitcoinCashJsService.getBitcoinCashJs();
var bitcore = bwcService.getBitcore();
var cashAddrRe = /^((?:q|p)[a-z0-9]{41})|((?:Q|P)[A-Z0-9]{41})$/;
var service = {
parse: parse
};
@ -16,6 +19,39 @@
function isValidCashAddr(address, network) {
var privateKey = new bch.PrivateKey('testnet');
var address1 = privateKey.toAddress();
console.log('legacy pub:', address1.toString());
//var addrss = bitcoinCashJsService.readAddress(address1);
//console.log('generated:', addrss.cashaddr);
//bch.Address.fromString(address1, 'testnet');
console.log('generated:', address1.toString('cashaddr'));
var isValid = false;
var prefix = network === 'testnet' ? 'bchtest:' : 'bitcoincash:';
try {
if (cashAddrRe.test(address)) {
// bitcoinCashJs.Address.isValid() assumes legacy address for string data, so does not work with cashaddr.
var bchAddresses = bitcoinCashJsService.readAddress(address.toLowerCase());
if (bchAddresses) {
var legacyAddress = bchAddresses.legacy;
if (bch.Address.isValid(legacyAddress, network)) {
isValid = true;
}
}
}
} catch (e) {
// Nop - Must not be a valid cashAddr.
$log.error('Error validating address.', e);
}
console.log(address,'isValidCashAddr:', isValid);
return isValid;
}
/*
For parsing:
BIP21
@ -67,6 +103,13 @@
} else if (/^(?:bitcoincash)|(?:bitcoin-cash)$/.test(preColonLower)) {
parsed.coin = 'bch';
parsed.test = false;
addressAndParams = colonSplit[2];
console.log('Is bch');
} else if (/^(?:bchtest)$/.test(preColonLower)) {
parsed.coin = 'bch';
parsed.testnet = true;
addressAndParams = colonSplit[2];
console.log('Is bch');
@ -125,7 +168,7 @@
case 'r':
// Could use a more comprehesive regex to test URL validity, but then how would we know
// which part of the validatiion it failed?
// which part of the validation it failed?
if (value.startsWith('https://')) {
parsed.url = value;
} else {
@ -148,25 +191,37 @@
parsed.others = others;
parsed.req = req;
// Need to do bitpay format as well? Probably
if (address) {
var addressLowerCase = address.toLowerCase();
var bch = bitcoinCashJsService.getBitcoinCashJs();
// Just a rough validation to exclude half-pasted addresses, or things obviously not bitcoin addresses
var cashAddrRe = /^((?:q|p)[a-z0-9]{41})|((?:Q|P)[A-Z0-9]{41})$/;
var legacyRe = /^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$/;
var legacyTestnetRe = /^[mn][a-km-zA-HJ-NP-Z1-9]{25,34}$/;
if (legacyRe.test(address) && bitcore.Address.isValid(address, 'livenet')) {
//var legacyRe = /^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$/;
//var legacyTestnetRe = /^[mn][a-km-zA-HJ-NP-Z1-9]{25,34}$/;
if (bitcore.Address.isValid(address, 'livenet')) {
parsed.address = address;
parsed.legacyAddress = address;
parsed.testnet = false;
} else if (legacyTestnetRe.test(address) && bitcore.Address.isValid(address, 'testnet')) {
} else if (bitcore.Address.isValid(address, 'testnet')) {
parsed.address = address;
parsed.legacyAddress = address;
parsed.testnet = true;
// bitcoinCaashJs.Address.isValid() assumes legacy address for string data, so does not work with cashaddr.
// } else if (isValidCashAddr(addressLowerCase, 'livenet')) {
} else if (cashAddrRe.test(address) && parsed.testnet) {
var cashAddr = 'bchtest:' + addressLowerCase;
parsed.address = cashAddr;
parsed.coin = 'bch';
// TODO: Get legacy address
} else if (cashAddrRe.test(address)) {
var cashAddr = 'bitcoincash:' + address.toLowerCase();
var cashAddr = 'bitcoincash:' + addressLowerCase;
parsed.address = cashAddr;
parsed.coin = 'bch';
@ -175,13 +230,14 @@
parsed.testnet = false;
} // TODO: Check for private key
}
}
// TODO: identify different types of addresses
// TODO: Check for a private key here too
}
// If has no address, must have Url.
parsed.isValid = !!(parsed.address || parsed.url);

View file

@ -12,9 +12,6 @@ fdescribe('bitcoinUriService', function() {
});
it('Bitcoin testnet address', function() {
var parsed = bitcoinUriService.parse('mtWcoToWhbtPoCby5fvs8xdBujT5GGenD4');
@ -37,6 +34,17 @@ fdescribe('bitcoinUriService', function() {
expect(parsed.testnet).toBe(false);
});
it('cashAddr testnet with prefix', function() {
var parsed = bitcoinUriService.parse('bchtest:qpcz6pmurq9ctg5848trzz9zmuuygj4q5qam7ph3gt');
expect(parsed.isValid).toBe(true);
expect(parsed.address).toBe('bchtest:qpcz6pmurq9ctg5848trzz9zmuuygj4q5qam7ph3gt');
expect(parsed.coin).toBe('bch');
expect(parsed.legacyAddress).toBe('mqk5vE278ytt6LUZqd97wi8c3FHsSYREX4');
expect(parsed.testnet).toBe(true);
});
it('cashAddr with prefix', function() {
var parsed = bitcoinUriService.parse('bitcoincash:qrq9p82a247lecv08ldk5p5h6ahtnjzpqcnh8yhq92');
@ -58,4 +66,30 @@ fdescribe('bitcoinUriService', function() {
expect(parsed.legacyAddress).toBe('15fm3EwqgBYcxkndALBfforueps5yWKReJ');
expect(parsed.testnet).toBe(false);
});
// Invalid addresses from https://github.com/bitcoincashorg/bitcoincash.org/blob/master/spec/cashaddr.md
it('invalid cashAddr style 1', function() {
var parsed = bitcoinUriService.parse('prefix:x64nx6hz');
expect(parsed.isValid).toBe(false);
});
it('invalid cashAddr style 2', function() {
var parsed = bitcoinUriService.parse('p:gpf8m4h7');
expect(parsed.isValid).toBe(false);
});
it('invalid cashAddr style 3', function() {
var parsed = bitcoinUriService.parse('bitcoincash:qpzry9x8gf2tvdw0s3jn54khce6mua7lcw20ayyn');
expect(parsed.isValid).toBe(false);
});
it('invalid cashAddr style 4', function() {
var parsed = bitcoinUriService.parse('bchtest:testnetaddress4d6njnut');
expect(parsed.isValid).toBe(false);
});
it('invalid cashAddr style 5', function() {
var parsed = bitcoinUriService.parse('bchreg:555555555555555555555555555555555555555555555udxmlmrz');
expect(parsed.isValid).toBe(false);
});
});