176 lines
4.7 KiB
TypeScript
176 lines
4.7 KiB
TypeScript
import { PublicKey } from '@xocash/stack';
|
|
|
|
import {
|
|
encodeHdPublicKey,
|
|
decodeHdPublicKey,
|
|
deriveHdPath,
|
|
deriveHdPathRelative,
|
|
} from '@bitauth/libauth';
|
|
|
|
import type {
|
|
DecodedHdKey,
|
|
HdKeyNetwork,
|
|
HdPublicNodeValid,
|
|
} from '@bitauth/libauth';
|
|
|
|
/**
|
|
* Hierarchically Deterministic Public Node Entity.
|
|
*/
|
|
export class HDPublicNode {
|
|
// The HD Public Node.
|
|
protected readonly node: HdPublicNodeValid;
|
|
|
|
/**
|
|
* Construct a new HD Public Node.
|
|
*
|
|
* @param node {HdPublicNode} The HD Public Node.
|
|
*/
|
|
protected constructor(node: HdPublicNodeValid) {
|
|
this.node = node;
|
|
}
|
|
|
|
/**
|
|
* Creates a HD Public Node from the given XPriv Key.
|
|
*
|
|
* @param xpub {string} The XPriv Key.
|
|
*
|
|
* @throws {Error} If HD Public Node cannot be created.
|
|
*
|
|
* @returns {HDPrivateNode} The created HD Public Node.
|
|
*/
|
|
public static fromXPub(xpub: string): HDPublicNode {
|
|
// Attempt to decode the XPub Key.
|
|
const decodeResult = decodeHdPublicKey(xpub);
|
|
|
|
// If a string is returned, this indicates an error...
|
|
if (typeof decodeResult === 'string') {
|
|
throw new Error(decodeResult);
|
|
}
|
|
|
|
// Return a new HD Public Node from the given XPub.
|
|
return new HDPublicNode(decodeResult.node);
|
|
}
|
|
|
|
/**
|
|
* Creates a HDPublicNode instance from a raw object representation (LibAuth's HdPublicNodeValid).
|
|
*
|
|
* @remarks This method is UNSAFE and MUST only be used where input is already verified or trusted.
|
|
*
|
|
* @param obj - LibAuth Object of type HdPublicNodeValid
|
|
* @returns A new HDPublicNode instance
|
|
*/
|
|
public static fromRaw(node: HdPublicNodeValid) {
|
|
return new this(node);
|
|
}
|
|
|
|
public static isXPub(xpub: string): boolean {
|
|
try {
|
|
this.fromXPub(xpub);
|
|
return true;
|
|
} catch (_error) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets the Public Key Entity for this node.
|
|
*
|
|
* @returns The Public Key Entity for this node.
|
|
*/
|
|
public toPublicKey(): PublicKey {
|
|
// Return a Public Key Entity from the public key of our node.
|
|
return PublicKey.fromRaw(this.node.publicKey);
|
|
}
|
|
|
|
/**
|
|
* Converts this node to an XPub Key for export.
|
|
*
|
|
* @param network The network to encode for.
|
|
*
|
|
* @returns The XPub Key.
|
|
*/
|
|
public toXPub(network: HdKeyNetwork = 'mainnet'): string {
|
|
// Create our node info structure.
|
|
const nodeInfo = {
|
|
network: network,
|
|
node: this.node,
|
|
} as DecodedHdKey<HdPublicNodeValid>;
|
|
|
|
// Encode the XPub from our node info.
|
|
return encodeHdPublicKey(nodeInfo).hdPublicKey;
|
|
}
|
|
|
|
/**
|
|
* Returns the XPub string for this node.
|
|
*
|
|
* @returns {string} The XPub string for this node.
|
|
*/
|
|
public toString(): string {
|
|
// Return the Mainnet XPub.
|
|
return this.toXPub();
|
|
}
|
|
|
|
/**
|
|
* Converts the HDPublicKey to its raw Libauth representation (HDPublicNodeValid).
|
|
*
|
|
* @returns A LibAuth HDPublicNodeValid object
|
|
*/
|
|
public toRaw(): HdPublicNodeValid {
|
|
return { ...this.node };
|
|
}
|
|
|
|
/**
|
|
* Derives a HD Public Node from the given BIP32 path.
|
|
*
|
|
* @remarks
|
|
*
|
|
* This method automatically detects whether the path is absolute (starts with 'm/')
|
|
* or relative (e.g. '0/1') and uses the appropriate derivation method.
|
|
*
|
|
* @param path The BIP32 Path (e.g. m/44'/145'/0'/0/1 or 0/1).
|
|
*
|
|
* @throws {Error} If HD Public Node cannot be derived.
|
|
*
|
|
* @returns The derived HD Public Node
|
|
*/
|
|
public derivePath(path: string): HDPublicNode {
|
|
// Determine if this is an absolute path (starts with 'm' or 'M').
|
|
const isAbsolutePath = path.startsWith('m') || path.startsWith('M');
|
|
|
|
// Use the appropriate derivation function.
|
|
const derivePathResult = isAbsolutePath
|
|
? deriveHdPath(this.node, path)
|
|
: deriveHdPathRelative(this.node, path);
|
|
|
|
// If a string is returned, this indicates an error...
|
|
if (typeof derivePathResult === 'string') {
|
|
throw new Error(derivePathResult);
|
|
}
|
|
|
|
// Return a new HD Public Node Entity derived from the given path.
|
|
return new HDPublicNode(derivePathResult);
|
|
}
|
|
|
|
/**
|
|
* Derives a HD Public Node from the given relative BIP32 path.
|
|
*
|
|
* @param path The relative BIP32 Path (e.g. 0/0 or 0/1).
|
|
*
|
|
* @throws {Error} If HD Public Node cannot be derived.
|
|
*
|
|
* @returns The derived HD Public Node
|
|
*/
|
|
public deriveRelativePath(path: string): HDPublicNode {
|
|
// Attempt to derive the given relative path.
|
|
const derivePathResult = deriveHdPathRelative(this.node, path);
|
|
|
|
// If a string is returned, this indicates an error...
|
|
if (typeof derivePathResult === 'string') {
|
|
throw new Error(derivePathResult);
|
|
}
|
|
|
|
// Return a new HD Public Node Entity derived from the given path.
|
|
return new HDPublicNode(derivePathResult);
|
|
}
|
|
}
|