Draft Inverse Bloom Filter
This commit is contained in:
@@ -1,10 +1,9 @@
|
||||
import { Bytes } from './bytes.js';
|
||||
|
||||
import {
|
||||
Base58AddressFormatVersion,
|
||||
addressContentsToLockingBytecode,
|
||||
lockingBytecodeToAddressContents,
|
||||
isHex,
|
||||
binToHex,
|
||||
hexToBin,
|
||||
decodeBase58Address,
|
||||
decodeCashAddress,
|
||||
disassembleBytecodeBCH,
|
||||
@@ -27,6 +26,25 @@ export const DEFAULT_ADDRESS_PREFIXES = [
|
||||
|
||||
/**
|
||||
* Address Entity.
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* ```ts
|
||||
* // Import our primitives.
|
||||
* import { Address } from '@xocash/primitives';
|
||||
*
|
||||
* // Instantiate from a CashAddr (Legacy Addresses also supported).
|
||||
* const address = Address.from('bitcoincash:qpmlpygrtzznznhgsl4c245xgmglpfh0vgcqns0q0r');
|
||||
*
|
||||
* // Convert to Locking Bytecode.
|
||||
* console.log(address.toLockscriptBytes());
|
||||
*
|
||||
* // Convert to Legacy Address.
|
||||
* console.log(address.toLegacy());
|
||||
*
|
||||
* // Convert to Token Address.
|
||||
* console.log(address.toTokenAddress());
|
||||
* ```
|
||||
*/
|
||||
export class Address {
|
||||
protected readonly addressContents: KnownAddressTypeContents;
|
||||
@@ -81,7 +99,7 @@ export class Address {
|
||||
.find((result) => typeof result !== 'string');
|
||||
|
||||
if (!decodeResult) {
|
||||
throw new Error('Invalid address format');
|
||||
throw new Error(`Cannot decode address '${cashAddr}': ${decodeResult}`);
|
||||
}
|
||||
|
||||
// Define the encode type in advance.
|
||||
@@ -98,7 +116,9 @@ export class Address {
|
||||
encodeType = decodeResult.payload.length === 32 ? 'P2SH32' : 'P2SH20';
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unsupported address type: ${decodeResult.type}`);
|
||||
throw new Error(
|
||||
`Cannot decode address '${cashAddr}': Unsupported address type '${decodeResult.type}'`,
|
||||
);
|
||||
}
|
||||
|
||||
// Return new instance of address.
|
||||
@@ -120,7 +140,9 @@ export class Address {
|
||||
|
||||
// If a string is returned, this indicates an error...
|
||||
if (typeof decodeResult === 'string') {
|
||||
throw new Error(decodeResult);
|
||||
throw new Error(
|
||||
`Cannot decode address '${legacyAddress}': ${decodeResult}`,
|
||||
);
|
||||
}
|
||||
|
||||
// Define the encode type in advance.
|
||||
@@ -137,7 +159,9 @@ export class Address {
|
||||
encodeType = 'P2SH20';
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unsupported address type: ${decodeResult.version}`);
|
||||
throw new Error(
|
||||
`Cannot decode address '${legacyAddress}': Unsupported address type '${decodeResult.version}'`,
|
||||
);
|
||||
}
|
||||
|
||||
return new this({ payload: decodeResult.payload, type: encodeType });
|
||||
@@ -146,23 +170,37 @@ export class Address {
|
||||
/**
|
||||
* Instantiate an address from Contract Bytecode.
|
||||
*
|
||||
* @param contractBytes The contract bytecode
|
||||
* @param bytes The contract bytecode
|
||||
*
|
||||
* @throws {Error} If address cannot be instantiated from Contract Bytecode.
|
||||
*
|
||||
* @returns {Address} Instance of Address.
|
||||
*/
|
||||
public static fromRedeemScript(
|
||||
contractBytes: Uint8Array,
|
||||
bytes: Uint8Array,
|
||||
type: 'P2SH20' | 'P2SH32' = 'P2SH32',
|
||||
): Address {
|
||||
// Do an initial SHA256 on the Contract Bytes.
|
||||
let payload = sha256.hash(contractBytes);
|
||||
let payload = sha256.hash(bytes);
|
||||
|
||||
if (type === 'P2SH20') {
|
||||
// Make sure length is 20 bytes.
|
||||
if (bytes.length !== 20) {
|
||||
throw new Error(
|
||||
`Invalid payload length. Received '${bytes.length}', expected 20 for P2SH20`,
|
||||
);
|
||||
}
|
||||
|
||||
// RIPEMD160 the SHA256 hash.
|
||||
payload = ripemd160.hash(payload);
|
||||
} else if (type === 'P2SH32') {
|
||||
// Make sure length is 32 bytes.
|
||||
if (bytes.length !== 32) {
|
||||
throw new Error(
|
||||
`Invalid payload length. Received '${bytes.length}', expected 32 for P2SH20`,
|
||||
);
|
||||
}
|
||||
|
||||
// SHA256 Hash the SHA256 hash a seconr time.
|
||||
payload = sha256.hash(payload);
|
||||
}
|
||||
@@ -184,14 +222,8 @@ export class Address {
|
||||
hex: string,
|
||||
type: 'P2SH20' | 'P2SH32' = 'P2SH32',
|
||||
): Address {
|
||||
if (!isHex(hex)) {
|
||||
throw new Error('Invalid hex');
|
||||
}
|
||||
|
||||
const contractBytecode = hexToBin(hex);
|
||||
|
||||
// Return a new instance of address.
|
||||
return this.fromRedeemScript(contractBytecode, type);
|
||||
return this.fromRedeemScript(Bytes.fromHex(hex).toBytes(), type);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -224,13 +256,7 @@ export class Address {
|
||||
* @returns {Address} Instance of Address.
|
||||
*/
|
||||
public static fromLockscriptHex(hex: string): Address {
|
||||
if (!isHex(hex)) {
|
||||
throw new Error('Invalid hex');
|
||||
}
|
||||
|
||||
const lockScriptBytes = hexToBin(hex);
|
||||
|
||||
return this.fromLockscriptBytes(lockScriptBytes);
|
||||
return this.fromLockscriptBytes(Bytes.fromHex(hex).toBytes());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -243,7 +269,7 @@ export class Address {
|
||||
*
|
||||
* @returns {Address} Instance of Address.
|
||||
*/
|
||||
public static fromHash160(
|
||||
public static fromHash160Bytes(
|
||||
hash160: Uint8Array,
|
||||
type: AddressType = 'P2PKH',
|
||||
): Address {
|
||||
@@ -271,13 +297,7 @@ export class Address {
|
||||
hash160Hex: string,
|
||||
type: AddressType = 'P2PKH',
|
||||
): Address {
|
||||
if (!isHex(hash160Hex)) {
|
||||
throw new Error('Invalid hex');
|
||||
}
|
||||
|
||||
const hash160Bytes = hexToBin(hash160Hex);
|
||||
|
||||
return this.fromHash160(hash160Bytes, type);
|
||||
return this.fromHash160Bytes(Bytes.fromHex(hash160Hex).toBytes(), type);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -373,7 +393,7 @@ export class Address {
|
||||
* @returns {Uint8Array} The Hash160 of this address.
|
||||
*/
|
||||
public toHash160Hex(): string {
|
||||
return binToHex(this.addressContents.payload);
|
||||
return Bytes.fromBytes(this.addressContents.payload).toHex();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -496,7 +516,7 @@ export class Address {
|
||||
* @returns {Uint8Array} The lockscript as a hex string.
|
||||
*/
|
||||
public toLockscriptHex(): string {
|
||||
return binToHex(this.toLockscriptBytes());
|
||||
return Bytes.fromBytes(this.toLockscriptBytes()).toHex();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { binToHex, hexToBin, isHex, hash256 } from '@bitauth/libauth';
|
||||
import { Bytes } from './bytes.js';
|
||||
|
||||
import { hash256 } from '@bitauth/libauth';
|
||||
|
||||
export interface BlockHeaderRaw {
|
||||
version: number;
|
||||
@@ -13,6 +15,21 @@ export interface BlockHeaderRaw {
|
||||
* Represents a Bitcoin Cash block header.
|
||||
* This class handles parsing and serialization of BCH block headers between different formats
|
||||
* (raw object, bytes, hex) and provides access to individual header fields.
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* ```ts
|
||||
* // Import our primitives.
|
||||
* import { BlockHeader } from '@xocash/primitives';
|
||||
*
|
||||
* // Instantiate BlockHeader Primitive from Hex.
|
||||
* const blockHeader = BlockHeader.from('blockHeaderHex');
|
||||
*
|
||||
* // Output Block Header information.
|
||||
* console.log(blockHeader.getVersion());
|
||||
* console.log(blockHeader.getTimestamp());
|
||||
* console.log(blockHeader.getNonce());
|
||||
* ```
|
||||
*/
|
||||
export class BlockHeader {
|
||||
/**
|
||||
@@ -80,12 +97,7 @@ export class BlockHeader {
|
||||
* @throws Error if the hex string length is not 160
|
||||
*/
|
||||
static fromHex(hex: string): BlockHeader {
|
||||
// Ensure that the given string is hex.
|
||||
if (!isHex(hex)) {
|
||||
throw new Error('The given string is not valid hexadecimal.');
|
||||
}
|
||||
|
||||
return this.fromBytes(hexToBin(hex));
|
||||
return this.fromBytes(Bytes.fromHex(hex).toBytes());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -149,7 +161,7 @@ export class BlockHeader {
|
||||
* @returns 160-character hex string representing the block header
|
||||
*/
|
||||
toHex(): string {
|
||||
return binToHex(this.toBytes());
|
||||
return Bytes.fromBytes(this.toBytes()).toHex();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -193,7 +205,7 @@ export class BlockHeader {
|
||||
* @returns 64-character hex string
|
||||
*/
|
||||
getPreviousBlockHashHex(): string {
|
||||
return binToHex(this.previousBlockHash);
|
||||
return Bytes.fromBytes(this.previousBlockHash).toHex();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -201,7 +213,7 @@ export class BlockHeader {
|
||||
* @returns 64-character hex string
|
||||
*/
|
||||
getMerkleRootHex(): string {
|
||||
return binToHex(this.merkleRoot);
|
||||
return Bytes.fromBytes(this.merkleRoot).toHex();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -217,6 +229,6 @@ export class BlockHeader {
|
||||
* @returns 64-character hex string
|
||||
*/
|
||||
getHashHex(): string {
|
||||
return binToHex(this.getHash());
|
||||
return Bytes.fromBytes(this.getHash()).toHex();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ export class Bytes {
|
||||
public static fromBase64(base64: string): Bytes {
|
||||
// If the Base64 is invalid, throw an error.
|
||||
if (!isBase64(base64)) {
|
||||
throw new Error('Invalid base64 string');
|
||||
throw new Error(`Cannot decode invalid base64 '${base64}'`);
|
||||
}
|
||||
|
||||
return new this(base64ToBin(base64));
|
||||
@@ -96,7 +96,7 @@ export class Bytes {
|
||||
public static fromHex(hex: string): Bytes {
|
||||
// If the hex is invalid, throw an error.
|
||||
if (!isHex(hex)) {
|
||||
throw new Error('Invalid hexidecimal string');
|
||||
throw new Error(`Cannot decode invalid hex '${hex}'`);
|
||||
}
|
||||
|
||||
return new this(hexToBin(hex));
|
||||
|
||||
@@ -21,6 +21,25 @@ import type {
|
||||
|
||||
/**
|
||||
* Hierarchically Deterministic Private Node Entity.
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* ```ts
|
||||
* // Import our primitives.
|
||||
* import { Mnemonic, HDPrivateNode } from '@xocash/primitives';
|
||||
*
|
||||
* // Generate a mnemonic.
|
||||
* const mnemonic = Mnemonic.generateRandom();
|
||||
*
|
||||
* // Initialize a HD Private Node from Mnemonic.
|
||||
* const hdPrivateNode = HDPrivateNode.fromMnemonic(mnemonic);
|
||||
*
|
||||
* // Derive the first Private Key.
|
||||
* const privateKey = hdPrivateNode.derivePath("m/44'/145'/0'/0/0").toPrivateKey();
|
||||
*
|
||||
* // Output the BCH Address.
|
||||
* console.log(privateKey.derivePublicKey().deriveAddress().toCashAddr());
|
||||
* ```
|
||||
*/
|
||||
export class HDPrivateNode {
|
||||
// The HD Private Node.
|
||||
@@ -72,18 +91,15 @@ export class HDPrivateNode {
|
||||
/**
|
||||
* Creates a HD Private Node from the given mnemonic.
|
||||
*
|
||||
* @param phrase The mnemonic phrase as a string or array of words.
|
||||
* @param mnemonic The mnemonic to use.
|
||||
*
|
||||
* @throws {Error} If HD Private Node cannot be created.
|
||||
*
|
||||
* @returns The created HD Private Node.
|
||||
*/
|
||||
public static fromMnemonic(phrase: string | Array<string>): HDPrivateNode {
|
||||
// Derive the seed from the mnemonic.
|
||||
const seed = Mnemonic.from(phrase).toSeed();
|
||||
|
||||
public static fromMnemonic(mnemonic: Mnemonic): HDPrivateNode {
|
||||
// Return a new HDPrivateNode from the given seed.
|
||||
return this.fromSeed(seed);
|
||||
return this.fromSeed(mnemonic.toSeed());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -10,6 +10,5 @@ export * from './public-key.js';
|
||||
export * from './satoshis.js';
|
||||
export * from './script.js';
|
||||
export * from './transaction.js';
|
||||
export * from './transaction-hash.js';
|
||||
export * from './utils.js';
|
||||
export * from './utxo.js';
|
||||
|
||||
@@ -12,6 +12,22 @@ export type MnemonicRaw = {
|
||||
/**
|
||||
* Class representing a BIP39 Mnemonic phrase.
|
||||
* Supports 12, 15, 18, 21, and 24 word phrases with optional passphrase.
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* ```ts
|
||||
* // Import our primitives.
|
||||
* import { Mnemonic } from '@xocash/primitives';
|
||||
*
|
||||
* // Generate a random mnemonic.
|
||||
* const mnemonic = Mnemonic.generateRandom();
|
||||
*
|
||||
* // Output the mnemonic phrase.
|
||||
* console.log(mnemonic.toPhrase());
|
||||
*
|
||||
* // Derive the seed from the mnemonic.
|
||||
* console.log(mnemonic.toSeed());
|
||||
* ```
|
||||
*/
|
||||
export class Mnemonic {
|
||||
protected static VALID_WORD_COUNTS = new Set([12, 15, 18, 21, 24]);
|
||||
|
||||
@@ -2,7 +2,8 @@ import { Bytes } from './bytes.js';
|
||||
import { PublicKey } from './public-key.js';
|
||||
|
||||
import {
|
||||
binToHex,
|
||||
type RecoverableSignature,
|
||||
type WalletImportFormatType,
|
||||
decodePrivateKeyWif,
|
||||
encodePrivateKeyWif,
|
||||
generatePrivateKey,
|
||||
@@ -11,13 +12,24 @@ import {
|
||||
sha256,
|
||||
} from '@bitauth/libauth';
|
||||
|
||||
import type {
|
||||
RecoverableSignature,
|
||||
WalletImportFormatType,
|
||||
} from '@bitauth/libauth';
|
||||
|
||||
/**
|
||||
* Private Key entity.
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* ```ts
|
||||
* // Import our primitives
|
||||
* import { PrivateKey } from '@xocash/primitives';
|
||||
*
|
||||
* // Create a Private Key from a WIF.
|
||||
* const privateKey = PrivateKey.from('wif');
|
||||
*
|
||||
* // Derive the Public Key
|
||||
* const publicKey = PrivateKey.derivePublicKey();
|
||||
*
|
||||
* // Output the CashAddr.
|
||||
* console.log(publicKey.deriveAddress().toCashAddr());
|
||||
* ```
|
||||
*/
|
||||
export class PrivateKey {
|
||||
// The raw bytes representing the Private Key.
|
||||
@@ -101,7 +113,7 @@ export class PrivateKey {
|
||||
*/
|
||||
public static fromWIF(
|
||||
wif: string,
|
||||
removePrefixes = ['bitcoincash:', 'wif:'],
|
||||
removePrefixes = ['bitcoincash:', 'wif:', 'bch-wif:'],
|
||||
): PrivateKey {
|
||||
// Remove the prefixes from the WIF (if they exist).
|
||||
const wifWithoutPrefixes = removePrefixes.reduce((result, prefix) => {
|
||||
@@ -176,7 +188,7 @@ export class PrivateKey {
|
||||
*/
|
||||
public toHex(): string {
|
||||
// Return the hexadecimal encoded bytes of this Private Key.
|
||||
return binToHex(this.bytes);
|
||||
return Bytes.fromBytes(this.bytes).toHex();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,17 +1,26 @@
|
||||
import { Bytes } from './bytes.js';
|
||||
import { Address } from './address.js';
|
||||
|
||||
import {
|
||||
binToHex,
|
||||
hexToBin,
|
||||
isHex,
|
||||
secp256k1,
|
||||
sha256,
|
||||
ripemd160,
|
||||
utf8ToBin,
|
||||
} from '@bitauth/libauth';
|
||||
import { secp256k1, sha256, ripemd160, utf8ToBin } from '@bitauth/libauth';
|
||||
|
||||
/**
|
||||
* Public Key Entity.
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* ```ts
|
||||
* // Import our primitives
|
||||
* import { PublicKey } from '@xocash/primitives';
|
||||
*
|
||||
* // Create a Public Key from Hex.
|
||||
* const publicKey = PublicKey.from('publicKeyHex');
|
||||
*
|
||||
* // Derive the address.
|
||||
* const address = publicKey.deriveAddress();
|
||||
*
|
||||
* // Output as a CashAddr.
|
||||
* console.log(address.toCashAddr());
|
||||
* ```
|
||||
*/
|
||||
export class PublicKey {
|
||||
// The raw bytes representing the Public Key.
|
||||
@@ -69,18 +78,7 @@ export class PublicKey {
|
||||
* @returns The created Public Key entity.
|
||||
*/
|
||||
public static fromHex(publicKeyHex: string): PublicKey {
|
||||
// Ensure that the given string is hex.
|
||||
if (!isHex(publicKeyHex)) {
|
||||
throw new Error(
|
||||
`The given string (${publicKeyHex}) is not valid hexadecimal.`,
|
||||
);
|
||||
}
|
||||
|
||||
// Convert the hex to binary (Uint8Array).
|
||||
const publicKey = hexToBin(publicKeyHex);
|
||||
|
||||
// Create a Public Key Entity from the binary.
|
||||
return new this(publicKey);
|
||||
return new this(Bytes.fromHex(publicKeyHex).toBytes());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -102,7 +100,7 @@ export class PublicKey {
|
||||
* @returns The raw bytes Public Key encoded as Hexadecimal.
|
||||
*/
|
||||
public toHex(): string {
|
||||
return binToHex(this.bytes);
|
||||
return Bytes.fromBytes(this.bytes).toHex();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -158,7 +156,7 @@ export class PublicKey {
|
||||
public deriveHash160Hex(): string {
|
||||
const hash160Bytes = this.deriveHash160();
|
||||
|
||||
return binToHex(hash160Bytes);
|
||||
return Bytes.fromBytes(hash160Bytes).toHex();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -171,7 +169,7 @@ export class PublicKey {
|
||||
const ripemd160Hash = this.deriveHash160();
|
||||
|
||||
// Return an instance of address
|
||||
return Address.fromHash160(ripemd160Hash, 'P2PKH');
|
||||
return Address.fromHash160Bytes(ripemd160Hash, 'P2PKH');
|
||||
}
|
||||
|
||||
public verifyMessageSchnorr(
|
||||
@@ -234,11 +232,11 @@ export class PublicKey {
|
||||
signature: Uint8Array | string,
|
||||
): boolean {
|
||||
if (typeof messageHash === 'string') {
|
||||
messageHash = hexToBin(messageHash);
|
||||
messageHash = Bytes.fromHex(messageHash).toBytes();
|
||||
}
|
||||
|
||||
if (typeof signature === 'string') {
|
||||
signature = hexToBin(signature);
|
||||
signature = Bytes.fromHex(signature).toBytes();
|
||||
}
|
||||
|
||||
const validity = secp256k1.verifySignatureDER(
|
||||
@@ -263,11 +261,11 @@ export class PublicKey {
|
||||
signature: Uint8Array | string,
|
||||
): boolean {
|
||||
if (typeof messageHash === 'string') {
|
||||
messageHash = hexToBin(messageHash);
|
||||
messageHash = Bytes.fromHex(messageHash).toBytes();
|
||||
}
|
||||
|
||||
if (typeof signature === 'string') {
|
||||
signature = hexToBin(signature);
|
||||
signature = Bytes.fromHex(signature).toBytes();
|
||||
}
|
||||
|
||||
const validity = secp256k1.verifySignatureSchnorr(
|
||||
|
||||
@@ -2,6 +2,22 @@ export type BCHUnits = ['sats', 'bits', 'mBCH', 'BCH'];
|
||||
|
||||
/**
|
||||
* Satoshis Primitive
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* ```ts
|
||||
* // Import our primitives
|
||||
* import { Satoshis } from '@xocash/primitives';
|
||||
*
|
||||
* // Create an amount from BCH.
|
||||
* const sats = Satoshis.fromBCH(0.54321);
|
||||
*
|
||||
* // Output as a satoshi number.
|
||||
* console.log(satoshis.toSats());
|
||||
*
|
||||
* // Output as a satoshis bigint.
|
||||
* console.log(satoshis.toBigInt());
|
||||
* ```
|
||||
*/
|
||||
export class Satoshis {
|
||||
protected readonly satoshis: bigint;
|
||||
@@ -81,6 +97,19 @@ export class Satoshis {
|
||||
return new this(satoshis);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance from serialized data.
|
||||
*
|
||||
* @remarks This method is UNSAFE and MUST only be used where input is already verified or trusted.
|
||||
*
|
||||
* @param bytes - Serialized Primitive Data
|
||||
*
|
||||
* @returns A new instance of this primitive.
|
||||
*/
|
||||
public static fromRaw(sats: bigint) {
|
||||
return new this(sats);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rounds a number to the given number of digits.
|
||||
*
|
||||
@@ -89,7 +118,10 @@ export class Satoshis {
|
||||
*
|
||||
* @returns {Number} The rounded number.
|
||||
*/
|
||||
public static roundToDigits(numberToRound: number, digits: number): number {
|
||||
protected static roundToDigits(
|
||||
numberToRound: number,
|
||||
digits: number,
|
||||
): number {
|
||||
// Set the options of the Number Format object.
|
||||
const options: Intl.NumberFormatOptions = {
|
||||
style: 'decimal',
|
||||
@@ -165,4 +197,13 @@ export class Satoshis {
|
||||
public toBCH(): number {
|
||||
return Satoshis.roundToDigits(Number(this.satoshis) / 100_000_000, 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this primitive to a serializable raw object representation.
|
||||
*
|
||||
* @returns Serialzied primitive data.
|
||||
*/
|
||||
toRaw() {
|
||||
return this.satoshis;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,25 @@
|
||||
import {
|
||||
assembleBytecodeBCH,
|
||||
disassembleBytecodeBCH,
|
||||
binToHex,
|
||||
hexToBin,
|
||||
isHex,
|
||||
} from '@bitauth/libauth';
|
||||
import { Bytes } from './bytes.js';
|
||||
|
||||
import { assembleBytecodeBCH, disassembleBytecodeBCH } from '@bitauth/libauth';
|
||||
|
||||
/**
|
||||
* Script Entity.
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* ```ts
|
||||
* // Import our primitives
|
||||
* import { Script } from '@xocash/primitives';
|
||||
*
|
||||
* // Create a script from ASM.
|
||||
* const script = Script.fromASM('OP_RETURN <0xbeef>');
|
||||
*
|
||||
* // Output as in hexadecimal representation.
|
||||
* console.log(script.toHex());
|
||||
*
|
||||
* // Output as bytecode.
|
||||
* console.log(script.toBytes());
|
||||
* ```
|
||||
*/
|
||||
export class Script {
|
||||
protected readonly bytes: Uint8Array;
|
||||
@@ -46,7 +58,11 @@ export class Script {
|
||||
* @returns {Script} The created Script Entity.
|
||||
*/
|
||||
public static fromBytes(bytes: Uint8Array): Script {
|
||||
return new this(bytes);
|
||||
// Disassemble the bytecode.
|
||||
const disassembledBytecode = disassembleBytecodeBCH(bytes);
|
||||
|
||||
// And then try to instantiate it from ASM to catch any errors.
|
||||
return this.fromASM(disassembledBytecode);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -58,7 +74,22 @@ export class Script {
|
||||
*
|
||||
* @returns {Script} The created Script Entity.
|
||||
*/
|
||||
public static fromASM(asm: string): Script {
|
||||
public static fromASM(asm: string, disallowUnknown = true): Script {
|
||||
// If we should disallow unknown OP codes...
|
||||
if (disallowUnknown) {
|
||||
// Check if there are any unknown OP Codes.
|
||||
const containsUnknown = asm
|
||||
.split(/\s+/)
|
||||
.some((opCode) => opCode.startsWith('OP_UNKNOWN'));
|
||||
|
||||
// Throw an error if there are unknown OP codes.
|
||||
if (containsUnknown) {
|
||||
throw new Error(
|
||||
`Failed to decode script '${asm}': Unknown OP codes detected (set disallowUnknown to false if this is expected)`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt to convert the given ASM to bytecode.
|
||||
const assembleResult = assembleBytecodeBCH(asm);
|
||||
|
||||
@@ -69,7 +100,9 @@ export class Script {
|
||||
|
||||
// If the success flag is not marked, this indicates an error...
|
||||
if (!assembleResult.success) {
|
||||
throw new Error('Could not assemble bytecode from assembly.');
|
||||
throw new Error(
|
||||
`Failed to decode '${asm}': Could not assemble bytecode from assembly.`,
|
||||
);
|
||||
}
|
||||
|
||||
// Return new Script Entity from the assembled bytecode.
|
||||
@@ -86,16 +119,21 @@ export class Script {
|
||||
* @returns {Script} The created Script Entity.
|
||||
*/
|
||||
public static fromHex(hex: string): Script {
|
||||
// Ensure that the given string is hex.
|
||||
if (!isHex(hex)) {
|
||||
throw new Error(`The given string (${hex}) is not valid hexadecimal.`);
|
||||
}
|
||||
|
||||
// Conver the given hex to binary (Uint8Array).
|
||||
const scriptBin = hexToBin(hex);
|
||||
|
||||
// Return new Script entity constructed from the binary.
|
||||
return new this(scriptBin);
|
||||
return this.fromBytes(Bytes.fromHex(hex).toBytes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance from serialized data.
|
||||
*
|
||||
* @remarks This method is UNSAFE and MUST only be used where input is already verified or trusted.
|
||||
*
|
||||
* @param bytes - Serialized Primitive Data
|
||||
*
|
||||
* @returns A new instance of this primitive.
|
||||
*/
|
||||
public static fromRaw(bytes: Uint8Array) {
|
||||
return new this(bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,6 +166,15 @@ export class Script {
|
||||
* @returns {string} The compiled bytes as a hex string.
|
||||
*/
|
||||
public toHex(): string {
|
||||
return binToHex(this.bytes);
|
||||
return Bytes.fromBytes(this.bytes).toHex();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this primitive to a serializable raw object representation.
|
||||
*
|
||||
* @returns Serialzied primitive data.
|
||||
*/
|
||||
toRaw() {
|
||||
return this.bytes;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,160 +0,0 @@
|
||||
import { binToHex, hexToBin, hashTransaction, isHex } from '@bitauth/libauth';
|
||||
|
||||
/**
|
||||
* Transaction Hash Primitive.
|
||||
*/
|
||||
export class TransactionHash {
|
||||
protected readonly bytes: Uint8Array;
|
||||
|
||||
/**
|
||||
* Instantiates TransactionHash from a Transaction Hash's bytes.
|
||||
*
|
||||
* @param bytes {Uint8Array} The Transaction Hash's bytes.
|
||||
*/
|
||||
protected constructor(bytes: Uint8Array) {
|
||||
this.bytes = bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a TransactionHash from either the Hash Hex or Hash Bytes.
|
||||
*
|
||||
* @param hash The Transaction Hash as either hex or bytes.
|
||||
*
|
||||
* @throws {Error} If the hash is invalid.
|
||||
*
|
||||
* @returns The created Public Key Primitive.
|
||||
*/
|
||||
public static from(hash: Uint8Array | string) {
|
||||
return hash instanceof Uint8Array
|
||||
? this.fromBytes(hash)
|
||||
: this.fromHex(hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates TransactionHash from Hash Bytes.
|
||||
*
|
||||
* @param bytes The hash as bytes.
|
||||
*
|
||||
* @throws {Error} If hash is invalid.
|
||||
*
|
||||
* @returns {TransactionHash} Instance of TransactionHash.
|
||||
*/
|
||||
public static fromBytes(bytes: Uint8Array): TransactionHash {
|
||||
// If bytes is not exactly 32, then this is an invalid transaction hash...
|
||||
if (bytes.length !== 32) {
|
||||
throw new Error(
|
||||
`Invalid Transaction Hash: Expected 32 bytes but received ${bytes.length}`,
|
||||
);
|
||||
}
|
||||
|
||||
return new this(bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates TransactionHash from a hex string.
|
||||
*
|
||||
* @param hex {string} The hex string.
|
||||
*
|
||||
* @throws {Error} If hex is invalid.
|
||||
*
|
||||
* @returns {TransactionHash} Instance of TransactionHash.
|
||||
*/
|
||||
public static fromHex(hex: string): TransactionHash {
|
||||
if (!isHex(hex)) {
|
||||
throw new Error('Invalid hex provided');
|
||||
}
|
||||
|
||||
const bytes = hexToBin(hex);
|
||||
|
||||
return this.fromBytes(bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a TransactionHash from either the Transaction Hex or Transaction Hash.
|
||||
*
|
||||
* @param hash The Transaction as either hex or bytes.
|
||||
*
|
||||
* @throws {Error} If the public key cannot be decoded.
|
||||
*
|
||||
* @returns The created Public Key Primitive.
|
||||
*/
|
||||
public static fromTransaction(transaction: Uint8Array | string) {
|
||||
return transaction instanceof Uint8Array
|
||||
? this.fromTransactionBytes(transaction)
|
||||
: this.fromTransactionHex(transaction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates TransactionHash from a Transaction's bytes.
|
||||
*
|
||||
* @param transactionBytes {Uint8Array} The Transaction's bytes.
|
||||
*
|
||||
* @returns {TransactionHash} Instance of TransactionHash.
|
||||
*/
|
||||
public static fromTransactionBytes(
|
||||
transactionBytes: Uint8Array,
|
||||
): TransactionHash {
|
||||
const transactionHash = hashTransaction(transactionBytes);
|
||||
|
||||
return new this(hexToBin(transactionHash));
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates TransactionHash from a Transaction's bytes in hex.
|
||||
*
|
||||
* @param transactionHex {Uint8Array} The Transaction's bytes in hex.
|
||||
*
|
||||
* @throws {Error} If hex is invalid.
|
||||
*
|
||||
* @returns {TransactionHash} Instance of TransactionHash.
|
||||
*/
|
||||
public static fromTransactionHex(transactionHex: string): TransactionHash {
|
||||
if (!isHex(transactionHex)) {
|
||||
throw new Error('Invalid hex provided');
|
||||
}
|
||||
|
||||
const bytes = hexToBin(transactionHex);
|
||||
|
||||
return this.fromTransactionBytes(bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance from serialized data.
|
||||
*
|
||||
* @remarks This method is UNSAFE and MUST only be used where input is already verified or trusted.
|
||||
*
|
||||
* @param bytes - Serialized Primitive Data
|
||||
*
|
||||
* @returns A new instance of this primitive.
|
||||
*/
|
||||
public static fromRaw(bytes: Uint8Array) {
|
||||
return new this(bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns transaction hash as a hex string.
|
||||
*
|
||||
* @returns {string} Hex string of the Transaction Hash.
|
||||
*/
|
||||
public toHex(): string {
|
||||
return binToHex(this.bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns transaction hash as a Uint8Array.
|
||||
*
|
||||
* @returns {Uint8Array} Uint8Array of the Transaction Hash.
|
||||
*/
|
||||
public toBytes(): Uint8Array {
|
||||
return this.bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this primitive to a serializable representation.
|
||||
*
|
||||
* @returns Serialzied primitive data.
|
||||
*/
|
||||
toRaw() {
|
||||
return this.bytes;
|
||||
}
|
||||
}
|
||||
@@ -1,110 +1,20 @@
|
||||
import { TransactionHash } from './transaction-hash.js';
|
||||
import { Bytes } from './bytes.js';
|
||||
|
||||
import {
|
||||
binToHex,
|
||||
hexToBin,
|
||||
encodeTransaction,
|
||||
decodeTransaction,
|
||||
isHex,
|
||||
decodeTransactionBCH,
|
||||
hashTransaction,
|
||||
} from '@bitauth/libauth';
|
||||
import type { TransactionBCH } from '@bitauth/libauth';
|
||||
import type { ResolvedTransactionBCH, TransactionBCH } from '@bitauth/libauth';
|
||||
|
||||
/**
|
||||
* Transaction Primitive.
|
||||
*/
|
||||
export class Transaction {
|
||||
protected constructor(public transaction: TransactionBCH) {}
|
||||
class BaseTransaction {
|
||||
protected readonly transaction: TransactionBCH;
|
||||
|
||||
/**
|
||||
* Instantiates a transaction from either:
|
||||
*
|
||||
* 1. Transaction bytecode
|
||||
* 2. Transaction bytecode (in hexadecimal format)
|
||||
*
|
||||
* @param transaction The transaction in one of the above formats.
|
||||
*
|
||||
* @throws {Error} If transaction data cannot be decoded.
|
||||
*
|
||||
* @returns The created Transaction Primitive.
|
||||
*/
|
||||
public static from(transaction: Uint8Array | string) {
|
||||
return transaction instanceof Uint8Array
|
||||
? this.fromBytes(transaction)
|
||||
: this.fromHex(transaction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Transaction Primitive from the given byte data.
|
||||
*
|
||||
* @param bytes The raw byte data of the transaction.
|
||||
*
|
||||
* @throws {Error} If transaction data cannot be decoded.
|
||||
*
|
||||
* @returns {Transaction} The created Transaction Primitive.
|
||||
*/
|
||||
public static fromBytes(bytes: Uint8Array): Transaction {
|
||||
// Attempt to decode the raw transaction bytes.
|
||||
const decodeResult = decodeTransaction(bytes);
|
||||
|
||||
// If a string is returned, this indicates an error...
|
||||
if (typeof decodeResult === 'string') {
|
||||
throw new Error(decodeResult);
|
||||
}
|
||||
|
||||
// Return a new instance of the Transaction Primitive created from the decode result.
|
||||
return new this(decodeResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Transaction Primitive from the given byte data encoded as hexadecimal string.
|
||||
*
|
||||
* @param hex The raw byte data (encoded as hexadecimal string) of the transaction.
|
||||
*
|
||||
* @throws {Error} If transaction cannot be decoded.
|
||||
*
|
||||
* @returns {Transaction} The created Transaction Primitive.
|
||||
*/
|
||||
public static fromHex(hex: string): Transaction {
|
||||
// Ensure that the given string is hex.
|
||||
if (!isHex(hex)) {
|
||||
throw new Error('The given string is not valid hexadecimal.');
|
||||
}
|
||||
|
||||
// Convert our hex to binary.
|
||||
const bytes = hexToBin(hex);
|
||||
|
||||
// Return the transaction constructed from our bytes.
|
||||
return this.fromBytes(bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Transaction Primitive from LibAuth's TransactionBCH type.
|
||||
*
|
||||
* @remarks This method is UNSAFE and MUST only be used where input is already verified or trusted.
|
||||
*
|
||||
* @param transaction The transaction object (as per LibAuth).
|
||||
*
|
||||
* @returns The created Transaction Primitive.
|
||||
*/
|
||||
public static fromRaw(transaction: TransactionBCH) {
|
||||
return new this(transaction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the structure of a transaction.
|
||||
*
|
||||
* @param transaction The transaction (as hex or bytes).
|
||||
*
|
||||
* @returns boolean indicating whether the transaction structure is valid.
|
||||
*/
|
||||
public static isValid(transaction: Uint8Array | string): boolean {
|
||||
try {
|
||||
this.from(transaction);
|
||||
} catch (_error) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
protected constructor(transaction: TransactionBCH) {
|
||||
this.transaction = transaction;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -151,14 +61,6 @@ export class Transaction {
|
||||
return this.toHash().toBytes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts transaction to a raw object representation.
|
||||
* @returns A TransactionBCH LibAuth object.
|
||||
*/
|
||||
public toRaw(): TransactionBCH {
|
||||
return { ...this.transaction };
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the version for this transaction.
|
||||
*
|
||||
@@ -232,3 +134,382 @@ export class Transaction {
|
||||
return isOutpointZero && isOutpointIndexMax;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transaction Primitive.
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* ```ts
|
||||
* // Import our primitives.
|
||||
* import { Transaction } from '@xocash/primitive';
|
||||
*
|
||||
* // Instantiate primitive from Transaction Hex.
|
||||
* const transaction = Transaction.from('transactionHex');
|
||||
*
|
||||
* // Output Transaction Information.
|
||||
* console.log(transaction.getVersion());
|
||||
* console.log(transaction.getLocktime());
|
||||
* console.log(transaction.getInputs());
|
||||
* console.log(transaction.getOutputs());
|
||||
*
|
||||
* // Output the Transaction Hash.
|
||||
* console.log(transaction.toHash().toHex());
|
||||
* ```
|
||||
*/
|
||||
export class Transaction extends BaseTransaction {
|
||||
protected constructor(transaction: TransactionBCH) {
|
||||
super(transaction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a transaction from either:
|
||||
*
|
||||
* 1. Transaction bytecode
|
||||
* 2. Transaction bytecode (in hexadecimal format)
|
||||
*
|
||||
* @param transaction The transaction in one of the above formats.
|
||||
*
|
||||
* @throws {Error} If transaction data cannot be decoded.
|
||||
*
|
||||
* @returns The created Transaction Primitive.
|
||||
*/
|
||||
public static from(transaction: Uint8Array | string) {
|
||||
return transaction instanceof Uint8Array
|
||||
? this.fromBytes(transaction)
|
||||
: this.fromHex(transaction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Transaction Primitive from the given byte data.
|
||||
*
|
||||
* @param bytes The raw byte data of the transaction.
|
||||
*
|
||||
* @throws {Error} If transaction data cannot be decoded.
|
||||
*
|
||||
* @returns {Transaction} The created Transaction Primitive.
|
||||
*/
|
||||
public static fromBytes(bytes: Uint8Array): Transaction {
|
||||
// Attempt to decode the raw transaction bytes.
|
||||
const decodeResult = decodeTransaction(bytes);
|
||||
|
||||
// If a string is returned, this indicates an error...
|
||||
if (typeof decodeResult === 'string') {
|
||||
throw new Error(decodeResult);
|
||||
}
|
||||
|
||||
// Return a new instance of the Transaction Primitive created from the decode result.
|
||||
return new this(decodeResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Transaction Primitive from the given byte data encoded as hexadecimal string.
|
||||
*
|
||||
* @param hex The raw byte data (encoded as hexadecimal string) of the transaction.
|
||||
*
|
||||
* @throws {Error} If transaction cannot be decoded.
|
||||
*
|
||||
* @returns {Transaction} The created Transaction Primitive.
|
||||
*/
|
||||
public static fromHex(hex: string): Transaction {
|
||||
const bytes = Bytes.fromHex(hex).toBytes();
|
||||
return this.fromBytes(bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Transaction Primitive from LibAuth's TransactionBCH type.
|
||||
*
|
||||
* @remarks This method is UNSAFE and MUST only be used where input is already verified or trusted.
|
||||
*
|
||||
* @param transaction The transaction object (as per LibAuth).
|
||||
*
|
||||
* @returns The created Transaction Primitive.
|
||||
*/
|
||||
public static fromRaw(transaction: TransactionBCH) {
|
||||
return new this(transaction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the structure of a transaction.
|
||||
*
|
||||
* @param transaction The transaction (as hex or bytes).
|
||||
*
|
||||
* @returns boolean indicating whether the transaction structure is valid.
|
||||
*/
|
||||
public static isValid(transaction: Uint8Array | string): boolean {
|
||||
try {
|
||||
this.from(transaction);
|
||||
} catch (_error) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts transaction to a raw object representation.
|
||||
* @returns A TransactionBCH LibAuth object.
|
||||
*/
|
||||
public toRaw(): TransactionBCH {
|
||||
return { ...this.transaction };
|
||||
}
|
||||
}
|
||||
|
||||
export class TransactionResolved extends BaseTransaction {
|
||||
protected sourceOutputs: Array<any>;
|
||||
|
||||
protected constructor(
|
||||
transaction: TransactionBCH,
|
||||
sourceOutputs: Array<any>,
|
||||
) {
|
||||
super(transaction);
|
||||
this.sourceOutputs = sourceOutputs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a transaction from either:
|
||||
*
|
||||
* 1. Transaction bytecode
|
||||
* 2. Transaction bytecode (in hexadecimal format)
|
||||
*
|
||||
* @param transaction The transaction in one of the above formats.
|
||||
*
|
||||
* @throws {Error} If transaction data cannot be decoded.
|
||||
*
|
||||
* @returns The created Transaction Primitive.
|
||||
*/
|
||||
public static from(
|
||||
transaction: Uint8Array | string,
|
||||
sourceOutputs: Array<any>,
|
||||
) {
|
||||
return transaction instanceof Uint8Array
|
||||
? this.fromBytes(transaction, sourceOutputs)
|
||||
: this.fromHex(transaction, sourceOutputs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Transaction Primitive from the given byte data.
|
||||
*
|
||||
* @param bytes The raw byte data of the transaction.
|
||||
*
|
||||
* @throws {Error} If transaction data cannot be decoded.
|
||||
*
|
||||
* @returns {Transaction} The created Transaction Primitive.
|
||||
*/
|
||||
public static fromBytes(bytes: Uint8Array, sourceOutputs: Array<any>) {
|
||||
// Attempt to decode the raw transaction bytes.
|
||||
const decodeResult = decodeTransactionBCH(bytes);
|
||||
|
||||
// If a string is returned, this indicates an error...
|
||||
if (typeof decodeResult === 'string') {
|
||||
throw new Error(decodeResult);
|
||||
}
|
||||
|
||||
// Return a new instance of the Transaction Primitive created from the decode result.
|
||||
return new this(decodeResult, sourceOutputs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Transaction Primitive from the given byte data encoded as hexadecimal string.
|
||||
*
|
||||
* @param hex The raw byte data (encoded as hexadecimal string) of the transaction.
|
||||
*
|
||||
* @throws {Error} If transaction cannot be decoded.
|
||||
*
|
||||
* @returns {Transaction} The created Transaction Primitive.
|
||||
*/
|
||||
public static fromHex(hex: string, sourceOutputs: Array<any>) {
|
||||
const bytes = Bytes.fromHex(hex).toBytes();
|
||||
return this.fromBytes(bytes, sourceOutputs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Transaction Primitive from LibAuth's TransactionBCH type.
|
||||
*
|
||||
* @remarks This method is UNSAFE and MUST only be used where input is already verified or trusted.
|
||||
*
|
||||
* @param transaction The transaction object (as per LibAuth).
|
||||
*
|
||||
* @returns The created Transaction Primitive.
|
||||
*/
|
||||
public static fromRaw(resolvedTransaction: ResolvedTransactionBCH) {
|
||||
return new this(
|
||||
resolvedTransaction.transaction,
|
||||
resolvedTransaction.sourceOutputs,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the structure of a transaction.
|
||||
*
|
||||
* @param transaction The transaction (as hex or bytes).
|
||||
*
|
||||
* @returns boolean indicating whether the transaction structure is valid.
|
||||
*/
|
||||
public static isValid(
|
||||
transaction: Uint8Array | string,
|
||||
sourceOutputs: Array<any>,
|
||||
): boolean {
|
||||
try {
|
||||
this.from(transaction, sourceOutputs);
|
||||
} catch (_error) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public toRaw() {
|
||||
return {
|
||||
transaction: this.transaction,
|
||||
sourceOutputs: this.sourceOutputs,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transaction Hash Primitive.
|
||||
*/
|
||||
export class TransactionHash {
|
||||
/**
|
||||
* Instantiates TransactionHash from a Transaction Hash's bytes.
|
||||
*
|
||||
* @param bytes {Uint8Array} The Transaction Hash's bytes.
|
||||
*/
|
||||
protected constructor(protected readonly bytes: Uint8Array) {
|
||||
this.bytes = bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a TransactionHash from either the Hash Hex or Hash Bytes.
|
||||
*
|
||||
* @param hash The Transaction Hash as either hex or bytes.
|
||||
*
|
||||
* @throws {Error} If the hash is invalid.
|
||||
*
|
||||
* @returns The created Public Key Primitive.
|
||||
*/
|
||||
public static from(hash: Uint8Array | string) {
|
||||
return hash instanceof Uint8Array
|
||||
? this.fromBytes(hash)
|
||||
: this.fromHex(hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates TransactionHash from Hash Bytes.
|
||||
*
|
||||
* @param bytes The hash as bytes.
|
||||
*
|
||||
* @throws {Error} If hash is invalid.
|
||||
*
|
||||
* @returns {TransactionHash} Instance of TransactionHash.
|
||||
*/
|
||||
public static fromBytes(bytes: Uint8Array): TransactionHash {
|
||||
// If bytes is not exactly 32, then this is an invalid transaction hash...
|
||||
if (bytes.length !== 32) {
|
||||
throw new Error(
|
||||
`Invalid Transaction Hash: Expected 32 bytes but received ${bytes.length}`,
|
||||
);
|
||||
}
|
||||
|
||||
return new this(bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates TransactionHash from a hex string.
|
||||
*
|
||||
* @param hex {string} The hex string.
|
||||
*
|
||||
* @throws {Error} If hex is invalid.
|
||||
*
|
||||
* @returns {TransactionHash} Instance of TransactionHash.
|
||||
*/
|
||||
public static fromHex(hex: string): TransactionHash {
|
||||
const bytes = Bytes.fromHex(hex).toBytes();
|
||||
return this.fromBytes(bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a TransactionHash from either the Transaction Hex or Transaction Hash.
|
||||
*
|
||||
* @param hash The Transaction as either hex or bytes.
|
||||
*
|
||||
* @throws {Error} If the public key cannot be decoded.
|
||||
*
|
||||
* @returns The created Public Key Primitive.
|
||||
*/
|
||||
public static fromTransaction(transaction: Uint8Array | string) {
|
||||
return transaction instanceof Uint8Array
|
||||
? this.fromTransactionBytes(transaction)
|
||||
: this.fromTransactionHex(transaction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates TransactionHash from a Transaction's bytes.
|
||||
*
|
||||
* @param transactionBytes {Uint8Array} The Transaction's bytes.
|
||||
*
|
||||
* @returns {TransactionHash} Instance of TransactionHash.
|
||||
*/
|
||||
public static fromTransactionBytes(
|
||||
transactionBytes: Uint8Array,
|
||||
): TransactionHash {
|
||||
const transactionHash = hashTransaction(transactionBytes);
|
||||
|
||||
return new this(hexToBin(transactionHash));
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates TransactionHash from a Transaction's bytes in hex.
|
||||
*
|
||||
* @param transactionHex {Uint8Array} The Transaction's bytes in hex.
|
||||
*
|
||||
* @throws {Error} If hex is invalid.
|
||||
*
|
||||
* @returns {TransactionHash} Instance of TransactionHash.
|
||||
*/
|
||||
public static fromTransactionHex(transactionHex: string): TransactionHash {
|
||||
const bytes = Bytes.fromHex(transactionHex).toBytes();
|
||||
return this.fromTransactionBytes(bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance from serialized data.
|
||||
*
|
||||
* @remarks This method is UNSAFE and MUST only be used where input is already verified or trusted.
|
||||
*
|
||||
* @param bytes - Serialized Primitive Data
|
||||
*
|
||||
* @returns A new instance of this primitive.
|
||||
*/
|
||||
public static fromRaw(bytes: Uint8Array) {
|
||||
return new this(bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns transaction hash as a hex string.
|
||||
*
|
||||
* @returns {string} Hex string of the Transaction Hash.
|
||||
*/
|
||||
public toHex(): string {
|
||||
return binToHex(this.bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns transaction hash as a Uint8Array.
|
||||
*
|
||||
* @returns {Uint8Array} Uint8Array of the Transaction Hash.
|
||||
*/
|
||||
public toBytes(): Uint8Array {
|
||||
return this.bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this primitive to a serializable representation.
|
||||
*
|
||||
* @returns Serialzied primitive data.
|
||||
*/
|
||||
toRaw() {
|
||||
return this.bytes;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user