@ecash/lib
Version:
Library for eCash transaction building
253 lines • 8.63 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Address = exports.DEFAULT_PREFIX = exports.toLegacyAddress = exports.ECASH_PREFIXES_TESTNET = void 0;
// Copyright (c) 2024 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
const hex_1 = require("../io/hex");
const ecashaddrjs_1 = require("ecashaddrjs");
const legacyaddr_1 = require("./legacyaddr");
const script_1 = require("../script");
exports.ECASH_PREFIXES_TESTNET = ['ectest', 'ecregtest'];
/**
* Converts an ecash address in cashaddr format to legacy format
* Throws if user attempts to convert a legacy address to a legacy address
* Separated as its own function here for
*
* 1 - simpler unit testing
* 2 - exported for users looking to convert string cashaddr to string legacy addr
* without using the Address class
*/
const toLegacyAddress = (cashaddress) => {
try {
// No-op if user is trying to convert legacy to legacy
(0, legacyaddr_1.decodeLegacyAddress)(cashaddress);
return cashaddress;
}
catch {
// Do nothing with this error since we expect it every time for the function's intended use case
// Proceed to convert to legacy
}
const { prefix, type, hash } = (0, ecashaddrjs_1.decodeCashAddress)(cashaddress);
const isTestnet = exports.ECASH_PREFIXES_TESTNET.includes(prefix);
// Get correct version byte for legacy format
let versionByte;
switch (type) {
case 'p2pkh':
versionByte = isTestnet
? legacyaddr_1.LEGACY_VERSION_BYTES.legacy.testnet.p2pkh
: legacyaddr_1.LEGACY_VERSION_BYTES.legacy.mainnet.p2pkh;
break;
case 'p2sh':
versionByte = isTestnet
? legacyaddr_1.LEGACY_VERSION_BYTES.legacy.testnet.p2sh
: legacyaddr_1.LEGACY_VERSION_BYTES.legacy.mainnet.p2sh;
break;
default:
throw new Error('Unsupported address type: ' + type);
}
// Convert hash to Uint8Array
const hashArray = (0, hex_1.fromHex)(hash);
// Create a new Uint8Array to hold the data
const uint8Array = new Uint8Array(1 + hashArray.length);
// Set the version byte
uint8Array[0] = versionByte;
// Set the hash
uint8Array.set(hashArray, 1);
// Encode to base58check
return (0, legacyaddr_1.encodeBase58Check)(uint8Array);
};
exports.toLegacyAddress = toLegacyAddress;
exports.DEFAULT_PREFIX = 'ecash';
/**
* Address
* Stores properties of supported crypto addresses
* in standard typed structure. Provides methods for
* easy access of address data in dev-friendly formats.
* Provides methods for instantiating by type, encoding,
* script, prefix, and address string of arbitrary encoding.
*
* Simplifies conversion between cashaddr prefixes and
* address encoding types.
*
* Address is an ecash-first class. Legacy BTC format
* is supported to simplify conversion to and from
* ecash addresses.
*
* Address may be extended to support other crypto
* address formats.
*/
class Address {
constructor(params) {
this.toString = () => {
return this.address;
};
this.legacy = () => new Address({
type: this.type,
hash: this.hash,
address: (0, exports.toLegacyAddress)(this.address),
encoding: 'legacy',
});
/**
* Create an Address with cashaddr encoding
* from an existing Address
*/
this.cash = () => new Address({
type: this.type,
hash: this.hash,
address: (0, ecashaddrjs_1.encodeCashAddress)(typeof this.prefix !== 'undefined'
? this.prefix
: exports.DEFAULT_PREFIX, this.type, this.hash),
encoding: 'cashaddr',
prefix: typeof this.prefix !== 'undefined'
? this.prefix
: exports.DEFAULT_PREFIX,
});
/**
* Create address with specified prefix
* from an existing cashaddr-encoding Address
*/
this.withPrefix = (prefix) => {
if (this.encoding === 'legacy') {
// Take no action for legacy address types
throw new Error('withPrefix does not support legacy address types');
}
if (this.prefix === prefix) {
// Take no action if prefix is not changing
return this;
}
return new Address({
type: this.type,
hash: this.hash,
prefix,
address: (0, ecashaddrjs_1.encodeCashAddress)(prefix, this.type, this.hash),
encoding: 'cashaddr',
});
};
this.toScript = () => {
return new script_1.Script((0, hex_1.fromHex)((0, ecashaddrjs_1.getOutputScriptFromTypeAndHash)(this.type, this.hash)));
};
this.toScriptHex = () => {
return (0, ecashaddrjs_1.getOutputScriptFromTypeAndHash)(this.type, this.hash);
};
const { hash, type, address, encoding } = params;
this.hash = hash;
this.type = type;
this.address = address;
this.encoding = encoding;
if (typeof params.prefix !== 'undefined') {
this.prefix = params.prefix;
}
}
}
exports.Address = Address;
/**
* Create a new p2pkh Address from hash
* cashaddr encoding, ecash: prefix
*/
Address.p2pkh = (hash) => new Address({
type: 'p2pkh',
hash: hash instanceof Uint8Array ? (0, hex_1.toHex)(hash) : hash,
prefix: exports.DEFAULT_PREFIX,
address: (0, ecashaddrjs_1.encodeCashAddress)(exports.DEFAULT_PREFIX, 'p2pkh', hash),
encoding: 'cashaddr',
});
/**
* Create a new p2sh Address from hash
* cashaddr encoding
* ecash: prefix
*/
Address.p2sh = (hash) => new Address({
type: 'p2sh',
hash: hash instanceof Uint8Array ? (0, hex_1.toHex)(hash) : hash,
prefix: exports.DEFAULT_PREFIX,
address: (0, ecashaddrjs_1.encodeCashAddress)(exports.DEFAULT_PREFIX, 'p2sh', hash),
encoding: 'cashaddr',
});
/**
* Create a new Address from a given address string
* address must be valid legacy or cashaddr address
*/
Address.parse = (address) => {
if ((0, ecashaddrjs_1.isValidCashAddress)(address)) {
const { type, hash, prefix } = (0, ecashaddrjs_1.decodeCashAddress)(address);
return new Address({
type,
hash,
prefix,
encoding: 'cashaddr',
address,
});
}
try {
const { type, hash } = (0, legacyaddr_1.decodeLegacyAddress)(address);
return new Address({
type,
hash,
encoding: 'legacy',
address,
});
}
catch {
throw new Error('Invalid cashaddr or legacy address');
}
};
/**
* Create a new Address from a cashaddr
* prefix, type, and hash from creating cashaddr
*/
Address.fromCashAddress = (address) => {
const { type, hash, prefix } = (0, ecashaddrjs_1.decodeCashAddress)(address);
return new Address({
type,
hash,
address,
encoding: 'cashaddr',
prefix,
});
};
/**
* Create a new Address from legacy address
* No prefix for Address created from legacy address
* type and hash from legacy address
*/
Address.fromLegacyAddress = (legacy) => {
// Determine addr params from legacy address
const { type, hash } = (0, legacyaddr_1.decodeLegacyAddress)(legacy);
return new Address({
type,
hash,
address: legacy,
encoding: 'legacy',
});
};
/**
* Create a new Address from an outputScript as Script
* type and hash from outputScript
* cashaddr encoding
* ecash: prefix
*/
Address.fromScript = (script) => {
const scriptHex = (0, hex_1.toHex)(script.bytecode);
return Address.fromScriptHex(scriptHex);
};
/**
* Create a new Address from an outputScript as hex string
* type and hash from outputScript
* cashaddr encoding
* ecash: prefix
*/
Address.fromScriptHex = (scriptHex) => {
const { type, hash } = (0, ecashaddrjs_1.getTypeAndHashFromOutputScript)(scriptHex);
// Default cashaddr encoding with default prefix
const address = (0, ecashaddrjs_1.encodeCashAddress)(exports.DEFAULT_PREFIX, type, hash);
const prefix = exports.DEFAULT_PREFIX;
return new Address({
type,
hash,
prefix,
address,
encoding: 'cashaddr',
});
};
//# sourceMappingURL=address.js.map