chaingate
Version:
Multi-chain cryptocurrency SDK for TypeScript — unified API for Bitcoin, Ethereum, Litecoin, Dogecoin, Bitcoin Cash, Polygon, Arbitrum, and any EVM-compatible chain. Create wallets, query balances, send transactions, and manage tokens and NFTs across UTXO
141 lines (140 loc) • 5.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.HDWallet = void 0;
const bip32_1 = require("@scure/bip32");
const SigningWallet_1 = require("../SigningWallet");
const DerivedKey_1 = require("../../DerivedKey");
const DerivedPublicKey_1 = require("../../DerivedPublicKey");
const utils_1 = require("../../../utils");
const constants_1 = require("../../../constants");
const errors_1 = require("../../errors");
function requirePublicKey(key) {
if (!key.publicKey)
throw new errors_1.HDKeyNullError('publicKey');
return key.publicKey;
}
function requirePrivateKey(key) {
if (!key.privateKey)
throw new errors_1.HDKeyNullError('privateKey');
return key.privateKey;
}
/**
* Base class for HD wallets. Derive unlimited child keys from a single secret.
*
* Common derivation paths are pre-computed and cached automatically.
*
* @typeParam T - The secret type (e.g. {@link Phrase}, {@link Seed}, {@link Xpriv}).
*
* @example
* ```ts
* const key = await wallet.derive("m/44'/60'/0'/0/0");
* const pubKey = await wallet.derivePublicKey("m/44'/0'/0'/0/0");
* ```
*/
class HDWallet extends SigningWallet_1.SigningWallet {
/** @internal */
constructor(secret, restoreData) {
super(secret);
this._derivationIndex = new Map((restoreData?.derivationIndex ?? []).map((e) => [e.derivationPath, e]));
if (!secret.encrypted) {
const master = this.createMasterKey();
this._publicKey = (0, utils_1.bytesToHex)(requirePublicKey(master));
for (const path of constants_1.commonDerivationPaths) {
if (!this._derivationIndex.has(path)) {
const derived = master.derive(path);
this._derivationIndex.set(path, {
derivationPath: path,
xpub: derived.publicExtendedKey,
publicKey: (0, utils_1.bytesToHex)(requirePublicKey(derived)),
});
}
}
}
else {
this._publicKey = restoreData?.masterPublicKey ?? '';
}
}
createMasterKey() {
const source = this.getKeySource();
return 'seed' in source
? bip32_1.HDKey.fromMasterSeed(source.seed)
: bip32_1.HDKey.fromExtendedKey(source.xpriv);
}
/** The master public key as a hex string. */
get publicKey() {
return this._publicKey;
}
/** All derivation paths that have been used, with their cached public keys. */
get derivationIndex() {
return [...this._derivationIndex.values()];
}
/**
* Derives only the public key at a given path. Returns cached results when available.
*
* @param derivationPath - e.g. `"m/44'/60'/0'/0/0"`.
*/
async derivePublicKey(derivationPath) {
const cached = this._derivationIndex.get(derivationPath);
if (cached) {
return new DerivedPublicKey_1.DerivedPublicKey({
publicKey: (0, utils_1.hexToBytes)(cached.publicKey),
xpub: cached.xpub,
});
}
return this.secret.withDecrypted(() => {
const master = this.createMasterKey();
const derived = derivationPath ? master.derive(derivationPath) : master;
if (derivationPath) {
this._derivationIndex.set(derivationPath, {
derivationPath,
xpub: derived.publicExtendedKey,
publicKey: (0, utils_1.bytesToHex)(requirePublicKey(derived)),
});
}
if (!this._publicKey) {
this._publicKey = (0, utils_1.bytesToHex)(requirePublicKey(master));
}
return new DerivedPublicKey_1.DerivedPublicKey({
publicKey: requirePublicKey(derived),
xpub: derived.publicExtendedKey,
});
});
}
/**
* Derives a full key pair (public + private) at a given path.
*
* @param derivationPath - e.g. `"m/44'/60'/0'/0/0"`.
*/
async derive(derivationPath) {
return this.secret.withDecrypted(() => {
const master = this.createMasterKey();
const derived = derivationPath ? master.derive(derivationPath) : master;
if (derivationPath && !this._derivationIndex.has(derivationPath)) {
this._derivationIndex.set(derivationPath, {
derivationPath,
xpub: derived.publicExtendedKey,
publicKey: (0, utils_1.bytesToHex)(requirePublicKey(derived)),
});
}
if (!this._publicKey) {
this._publicKey = (0, utils_1.bytesToHex)(requirePublicKey(master));
}
return new DerivedKey_1.DerivedKey({
privateKey: requirePrivateKey(derived),
publicKey: requirePublicKey(derived),
xpriv: derived.privateExtendedKey,
xpub: derived.publicExtendedKey,
});
});
}
/** @inheritdoc */
async serialize(options) {
const base = await super.serialize(options);
return {
...base,
derivationIndex: this.derivationIndex,
masterPublicKey: this._publicKey || undefined,
};
}
}
exports.HDWallet = HDWallet;