address: make bech32 addrs more sane.
This commit is contained in:
parent
1eb08d39f4
commit
0ea341772c
@ -49,23 +49,14 @@ function Address(options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Address types. Note that the values
|
* Address types.
|
||||||
* have a direct mapping to script types.
|
|
||||||
* These also represent the "prefix type"
|
|
||||||
* as a network-agnostic version of the
|
|
||||||
* prefix byte. They DO NOT represent the
|
|
||||||
* script type. For example, script type
|
|
||||||
* `WITNESSMASTHASH` would be prefix type
|
|
||||||
* `WITNESSSCRIPTHASH` with a `version`
|
|
||||||
* of 1.
|
|
||||||
* @enum {Number}
|
* @enum {Number}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Address.types = {
|
Address.types = {
|
||||||
PUBKEYHASH: common.types.PUBKEYHASH,
|
PUBKEYHASH: 2,
|
||||||
SCRIPTHASH: common.types.SCRIPTHASH,
|
SCRIPTHASH: 3,
|
||||||
WITNESSSCRIPTHASH: common.types.WITNESSSCRIPTHASH,
|
WITNESS: 4
|
||||||
WITNESSPUBKEYHASH: common.types.WITNESSPUBKEYHASH
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -128,7 +119,7 @@ Address.prototype.getPrefix = function getPrefix(network) {
|
|||||||
if (!network)
|
if (!network)
|
||||||
network = this.network;
|
network = this.network;
|
||||||
network = Network.get(network);
|
network = Network.get(network);
|
||||||
return Address.getPrefix(this.type, network);
|
return Address.getPrefix(this.type, this.hash, network);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -231,7 +222,6 @@ Address.prototype.toBech32 = function toBech32(network) {
|
|||||||
network = this.network;
|
network = this.network;
|
||||||
|
|
||||||
network = Network.get(network);
|
network = Network.get(network);
|
||||||
|
|
||||||
hrp = network.addressPrefix.bech32;
|
hrp = network.addressPrefix.bech32;
|
||||||
|
|
||||||
data = bech32.bitsify(hash, 65, 8, 5, version, 0);
|
data = bech32.bitsify(hash, 65, 8, 5, version, 0);
|
||||||
@ -248,14 +238,24 @@ Address.prototype.toBech32 = function toBech32(network) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Address.prototype.fromString = function fromString(addr, network) {
|
Address.prototype.fromString = function fromString(addr, network) {
|
||||||
|
var i, type, hrp;
|
||||||
|
|
||||||
assert(typeof addr === 'string');
|
assert(typeof addr === 'string');
|
||||||
assert(addr.length > 2);
|
assert(addr.length > 2);
|
||||||
|
|
||||||
if (addr[0] === 'b' && addr[1] === 'c')
|
if (network) {
|
||||||
return this.fromBech32(addr, network);
|
network = Network.get(network);
|
||||||
|
hrp = network.addressPrefix.bech32;
|
||||||
if (addr[0] === 't' && addr[1] === 'b')
|
if (util.startsWith(addr, hrp))
|
||||||
return this.fromBech32(addr, network);
|
return this.fromBech32(addr, network);
|
||||||
|
} else {
|
||||||
|
for (i = 0; i < networks.types.length; i++) {
|
||||||
|
type = networks.types[i];
|
||||||
|
hrp = networks[type].addressPrefix.bech32;
|
||||||
|
if (util.startsWith(addr, hrp))
|
||||||
|
return this.fromBech32(addr, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return this.fromBase58(addr, network);
|
return this.fromBase58(addr, network);
|
||||||
};
|
};
|
||||||
@ -383,7 +383,8 @@ Address.fromBase58 = function fromBase58(address, network) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Address.prototype.fromBech32 = function fromBech32(data, network) {
|
Address.prototype.fromBech32 = function fromBech32(data, network) {
|
||||||
var i, addr, hash, type, version;
|
var type = Address.types.WITNESS;
|
||||||
|
var i, addr, hash, version;
|
||||||
|
|
||||||
assert(typeof data === 'string');
|
assert(typeof data === 'string');
|
||||||
|
|
||||||
@ -410,19 +411,6 @@ Address.prototype.fromBech32 = function fromBech32(data, network) {
|
|||||||
|
|
||||||
hash = bech32.bitsify(addr.data, 84, 5, 8, -1, 1);
|
hash = bech32.bitsify(addr.data, 84, 5, 8, -1, 1);
|
||||||
|
|
||||||
// TODO: Remove this by dropping old segwit addrs.
|
|
||||||
switch (hash.length) {
|
|
||||||
case 20:
|
|
||||||
type = Address.types.WITNESSPUBKEYHASH;
|
|
||||||
break;
|
|
||||||
case 32:
|
|
||||||
type = Address.types.WITNESSSCRIPTHASH;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(false, 'Unknown witness program data length.');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.fromHash(hash, type, version, network.type);
|
return this.fromHash(hash, type, version, network.type);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -468,21 +456,21 @@ Address.prototype.fromScript = function fromScript(script) {
|
|||||||
|
|
||||||
if (script.isWitnessPubkeyhash()) {
|
if (script.isWitnessPubkeyhash()) {
|
||||||
this.hash = script.get(1);
|
this.hash = script.get(1);
|
||||||
this.type = Address.types.WITNESSPUBKEYHASH;
|
this.type = Address.types.WITNESS;
|
||||||
this.version = 0;
|
this.version = 0;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (script.isWitnessScripthash()) {
|
if (script.isWitnessScripthash()) {
|
||||||
this.hash = script.get(1);
|
this.hash = script.get(1);
|
||||||
this.type = Address.types.WITNESSSCRIPTHASH;
|
this.type = Address.types.WITNESS;
|
||||||
this.version = 0;
|
this.version = 0;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (script.isWitnessMasthash()) {
|
if (script.isWitnessMasthash()) {
|
||||||
this.hash = script.get(1);
|
this.hash = script.get(1);
|
||||||
this.type = Address.types.WITNESSSCRIPTHASH;
|
this.type = Address.types.WITNESS;
|
||||||
this.version = 1;
|
this.version = 1;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -507,14 +495,14 @@ Address.prototype.fromWitness = function fromWitness(witness) {
|
|||||||
// since we can't get the version.
|
// since we can't get the version.
|
||||||
if (witness.isPubkeyhashInput()) {
|
if (witness.isPubkeyhashInput()) {
|
||||||
this.hash = crypto.hash160(witness.get(1));
|
this.hash = crypto.hash160(witness.get(1));
|
||||||
this.type = Address.types.WITNESSPUBKEYHASH;
|
this.type = Address.types.WITNESS;
|
||||||
this.version = 0;
|
this.version = 0;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (witness.isScripthashInput()) {
|
if (witness.isScripthashInput()) {
|
||||||
this.hash = crypto.sha256(witness.get(witness.length - 1));
|
this.hash = crypto.sha256(witness.get(witness.length - 1));
|
||||||
this.type = Address.types.WITNESSSCRIPTHASH;
|
this.type = Address.types.WITNESS;
|
||||||
this.version = 0;
|
this.version = 0;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -610,20 +598,19 @@ Address.prototype.fromHash = function fromHash(hash, type, version, network) {
|
|||||||
assert(util.isNumber(type));
|
assert(util.isNumber(type));
|
||||||
assert(util.isNumber(version));
|
assert(util.isNumber(version));
|
||||||
|
|
||||||
assert(Address.getPrefix(type, network) !== -1, 'Not a valid address type.');
|
assert(type >= Address.types.PUBKEYHASH && type <= Address.types.WITNESS,
|
||||||
|
'Not a valid address type.');
|
||||||
|
|
||||||
if (version === -1) {
|
if (version === -1) {
|
||||||
assert(!Address.isWitness(type), 'Wrong version (witness)');
|
assert(type !== Address.types.WITNESS, 'Wrong version (witness)');
|
||||||
assert(hash.length === 20, 'Hash is the wrong size.');
|
assert(hash.length === 20, 'Hash is the wrong size.');
|
||||||
} else {
|
} else {
|
||||||
assert(Address.isWitness(type), 'Wrong version (non-witness).');
|
assert(type === Address.types.WITNESS, 'Wrong version (non-witness).');
|
||||||
assert(version >= 0 && version <= 16, 'Bad program version.');
|
assert(version >= 0 && version <= 16, 'Bad program version.');
|
||||||
if (version === 0 && type === Address.types.WITNESSPUBKEYHASH)
|
if (version === 0 && type === Address.types.WITNESS) {
|
||||||
assert(hash.length === 20, 'Hash is the wrong size.');
|
assert(hash.length === 20 || hash.length === 32,
|
||||||
else if (version === 0 && type === Address.types.WITNESSSCRIPTHASH)
|
'Witness program hash is the wrong size.');
|
||||||
assert(hash.length === 32, 'Hash is the wrong size.');
|
}
|
||||||
else if (version === 1 && type === Address.types.WITNESSSCRIPTHASH)
|
|
||||||
assert(hash.length === 32, 'Hash is the wrong size.');
|
|
||||||
assert(hash.length >= 2 && hash.length <= 40, 'Hash is the wrong size.');
|
assert(hash.length >= 2 && hash.length <= 40, 'Hash is the wrong size.');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -706,7 +693,8 @@ Address.fromScripthash = function fromScripthash(hash, network) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Address.prototype.fromWitnessPubkeyhash = function fromWitnessPubkeyhash(hash, network) {
|
Address.prototype.fromWitnessPubkeyhash = function fromWitnessPubkeyhash(hash, network) {
|
||||||
var type = Address.types.WITNESSPUBKEYHASH;
|
var type = Address.types.WITNESS;
|
||||||
|
assert(hash.length === 20, 'P2WPKH must be 20 bytes.');
|
||||||
return this.fromHash(hash, type, 0, network);
|
return this.fromHash(hash, type, 0, network);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -730,7 +718,8 @@ Address.fromWitnessPubkeyhash = function fromWitnessPubkeyhash(hash, network) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Address.prototype.fromWitnessScripthash = function fromWitnessScripthash(hash, network) {
|
Address.prototype.fromWitnessScripthash = function fromWitnessScripthash(hash, network) {
|
||||||
var type = Address.types.WITNESSSCRIPTHASH;
|
var type = Address.types.WITNESS;
|
||||||
|
assert(hash.length === 32, 'P2WPKH must be 32 bytes.');
|
||||||
return this.fromHash(hash, type, 0, network);
|
return this.fromHash(hash, type, 0, network);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -755,25 +744,13 @@ Address.fromWitnessScripthash = function fromWitnessScripthash(hash, network) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Address.prototype.fromProgram = function fromProgram(version, hash, network) {
|
Address.prototype.fromProgram = function fromProgram(version, hash, network) {
|
||||||
var type;
|
var type = Address.types.WITNESS;
|
||||||
|
|
||||||
assert(version >= 0, 'Bad version for witness program.');
|
assert(version >= 0, 'Bad version for witness program.');
|
||||||
|
|
||||||
if (typeof hash === 'string')
|
if (typeof hash === 'string')
|
||||||
hash = new Buffer(hash, 'hex');
|
hash = new Buffer(hash, 'hex');
|
||||||
|
|
||||||
switch (hash.length) {
|
|
||||||
case 20:
|
|
||||||
type = Address.types.WITNESSPUBKEYHASH;
|
|
||||||
break;
|
|
||||||
case 32:
|
|
||||||
type = Address.types.WITNESSSCRIPTHASH;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(false, 'Unknown witness program data length.');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.fromHash(hash, type, version, network);
|
return this.fromHash(hash, type, version, network);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -813,7 +790,7 @@ Address.prototype.isScripthash = function isScripthash() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Address.prototype.isWitnessPubkeyhash = function isWitnessPubkeyhash() {
|
Address.prototype.isWitnessPubkeyhash = function isWitnessPubkeyhash() {
|
||||||
return this.version === 0 && this.type === Address.types.WITNESSPUBKEYHASH;
|
return this.version === 0 && this.hash.length === 20;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -822,7 +799,7 @@ Address.prototype.isWitnessPubkeyhash = function isWitnessPubkeyhash() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Address.prototype.isWitnessScripthash = function isWitnessScripthash() {
|
Address.prototype.isWitnessScripthash = function isWitnessScripthash() {
|
||||||
return this.version === 0 && this.type === Address.types.WITNESSSCRIPTHASH;
|
return this.version === 0 && this.hash.length === 32;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -831,7 +808,7 @@ Address.prototype.isWitnessScripthash = function isWitnessScripthash() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Address.prototype.isWitnessMasthash = function isWitnessMasthash() {
|
Address.prototype.isWitnessMasthash = function isWitnessMasthash() {
|
||||||
return this.version === 1 && this.type === Address.types.WITNESSSCRIPTHASH;
|
return this.version === 1 && this.hash.length === 32;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -843,6 +820,21 @@ Address.prototype.isProgram = function isProgram() {
|
|||||||
return this.version !== -1;
|
return this.version !== -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether the address is an unknown witness program.
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
|
||||||
|
Address.prototype.isUnknown = function isUnknown() {
|
||||||
|
if (this.version === -1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (this.version > 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return this.hash.length !== 20 && this.hash.length !== 32;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the hash of a base58 address or address-related object.
|
* Get the hash of a base58 address or address-related object.
|
||||||
* @param {Base58Address|Address|Hash} data
|
* @param {Base58Address|Address|Hash} data
|
||||||
@ -878,21 +870,24 @@ Address.getHash = function getHash(data, enc) {
|
|||||||
/**
|
/**
|
||||||
* Get a network address prefix for a specified address type.
|
* Get a network address prefix for a specified address type.
|
||||||
* @param {AddressPrefix} type
|
* @param {AddressPrefix} type
|
||||||
|
* @param {Buffer} hash
|
||||||
* @param {Network} network
|
* @param {Network} network
|
||||||
* @returns {Number}
|
* @returns {Number}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Address.getPrefix = function getPrefix(type, network) {
|
Address.getPrefix = function getPrefix(type, hash, network) {
|
||||||
var prefixes = network.addressPrefix;
|
var prefixes = network.addressPrefix;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Address.types.PUBKEYHASH:
|
case Address.types.PUBKEYHASH:
|
||||||
return prefixes.pubkeyhash;
|
return prefixes.pubkeyhash;
|
||||||
case Address.types.SCRIPTHASH:
|
case Address.types.SCRIPTHASH:
|
||||||
return prefixes.scripthash;
|
return prefixes.scripthash;
|
||||||
case Address.types.WITNESSPUBKEYHASH:
|
case Address.types.WITNESS:
|
||||||
return prefixes.witnesspubkeyhash;
|
if (hash.length === 20)
|
||||||
case Address.types.WITNESSSCRIPTHASH:
|
return prefixes.witnesspubkeyhash;
|
||||||
return prefixes.witnessscripthash;
|
if (hash.length === 32)
|
||||||
|
return prefixes.witnessscripthash;
|
||||||
|
assert(false, 'No witness prefix defined.');
|
||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -913,31 +908,14 @@ Address.getType = function getType(prefix, network) {
|
|||||||
case prefixes.scripthash:
|
case prefixes.scripthash:
|
||||||
return Address.types.SCRIPTHASH;
|
return Address.types.SCRIPTHASH;
|
||||||
case prefixes.witnesspubkeyhash:
|
case prefixes.witnesspubkeyhash:
|
||||||
return Address.types.WITNESSPUBKEYHASH;
|
return Address.types.WITNESS;
|
||||||
case prefixes.witnessscripthash:
|
case prefixes.witnessscripthash:
|
||||||
return Address.types.WITNESSSCRIPTHASH;
|
return Address.types.WITNESS;
|
||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Test whether an address type is a witness program.
|
|
||||||
* @param {AddressPrefix} type
|
|
||||||
* @returns {Boolean}
|
|
||||||
*/
|
|
||||||
|
|
||||||
Address.isWitness = function isWitness(type) {
|
|
||||||
switch (type) {
|
|
||||||
case Address.types.WITNESSPUBKEYHASH:
|
|
||||||
return true;
|
|
||||||
case Address.types.WITNESSSCRIPTHASH:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Expose
|
* Expose
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -763,11 +763,8 @@ KeyRing.prototype.getType = function getType() {
|
|||||||
if (this.nested)
|
if (this.nested)
|
||||||
return Address.types.SCRIPTHASH;
|
return Address.types.SCRIPTHASH;
|
||||||
|
|
||||||
if (this.witness) {
|
if (this.witness)
|
||||||
if (this.script)
|
return Address.types.WITNESS;
|
||||||
return Address.types.WITNESSSCRIPTHASH;
|
|
||||||
return Address.types.WITNESSPUBKEYHASH;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.script)
|
if (this.script)
|
||||||
return Address.types.SCRIPTHASH;
|
return Address.types.SCRIPTHASH;
|
||||||
|
|||||||
@ -157,6 +157,9 @@ Path.prototype.fromRaw = function fromRaw(data) {
|
|||||||
this.version = br.read8();
|
this.version = br.read8();
|
||||||
this.type = br.readU8();
|
this.type = br.readU8();
|
||||||
|
|
||||||
|
if (this.type === 129 || this.type === 130)
|
||||||
|
this.type = 4;
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -257,8 +257,7 @@ describe('Bech32', function() {
|
|||||||
ok2 = null;
|
ok2 = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
ok = ok1 === null && ok2 === null;
|
assert(!ok2);
|
||||||
assert(ok);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -578,7 +578,7 @@ describe('Chain', function() {
|
|||||||
it('should add wit addrs to miner', co(function* () {
|
it('should add wit addrs to miner', co(function* () {
|
||||||
miner.addresses.length = 0;
|
miner.addresses.length = 0;
|
||||||
miner.addAddress(wwallet.getReceive());
|
miner.addAddress(wwallet.getReceive());
|
||||||
assert.equal(wwallet.getReceive().getType(), 'witnesspubkeyhash');
|
assert.equal(wwallet.getReceive().getType(), 'witness');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should mine 2000 witness blocks', co(function* () {
|
it('should mine 2000 witness blocks', co(function* () {
|
||||||
|
|||||||
@ -16,7 +16,6 @@ var Input = require('../lib/primitives/input');
|
|||||||
var Outpoint = require('../lib/primitives/outpoint');
|
var Outpoint = require('../lib/primitives/outpoint');
|
||||||
var Script = require('../lib/script/script');
|
var Script = require('../lib/script/script');
|
||||||
var HD = require('../lib/hd');
|
var HD = require('../lib/hd');
|
||||||
var scriptTypes = Script.types;
|
|
||||||
|
|
||||||
var KEY1 = 'xprv9s21ZrQH143K3Aj6xQBymM31Zb4BVc7wxqfUhMZrzewdDVCt'
|
var KEY1 = 'xprv9s21ZrQH143K3Aj6xQBymM31Zb4BVc7wxqfUhMZrzewdDVCt'
|
||||||
+ 'qUP9iWfcHgJofs25xbaUpCps9GDXj83NiWvQCAkWQhVj5J4CorfnpKX94AZ';
|
+ 'qUP9iWfcHgJofs25xbaUpCps9GDXj83NiWvQCAkWQhVj5J4CorfnpKX94AZ';
|
||||||
@ -114,9 +113,9 @@ describe('Wallet', function() {
|
|||||||
addr = Address.fromString(w.getAddress('string'));
|
addr = Address.fromString(w.getAddress('string'));
|
||||||
|
|
||||||
if (witness)
|
if (witness)
|
||||||
assert.equal(addr.type, scriptTypes.WITNESSPUBKEYHASH);
|
assert.equal(addr.type, Address.types.WITNESS);
|
||||||
else
|
else
|
||||||
assert.equal(addr.type, scriptTypes.PUBKEYHASH);
|
assert.equal(addr.type, Address.types.PUBKEYHASH);
|
||||||
|
|
||||||
src = new MTX();
|
src = new MTX();
|
||||||
src.addInput(dummy());
|
src.addInput(dummy());
|
||||||
@ -652,11 +651,11 @@ describe('Wallet', function() {
|
|||||||
|
|
||||||
if (witness) {
|
if (witness) {
|
||||||
if (bullshitNesting)
|
if (bullshitNesting)
|
||||||
assert.equal(addr.type, scriptTypes.SCRIPTHASH);
|
assert.equal(addr.type, Address.types.SCRIPTHASH);
|
||||||
else
|
else
|
||||||
assert.equal(addr.type, scriptTypes.WITNESSSCRIPTHASH);
|
assert.equal(addr.type, Address.types.WITNESS);
|
||||||
} else {
|
} else {
|
||||||
assert.equal(addr.type, scriptTypes.SCRIPTHASH);
|
assert.equal(addr.type, Address.types.SCRIPTHASH);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.equal(w1.account[rec].getAddress('string'), b58);
|
assert.equal(w1.account[rec].getAddress('string'), b58);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user