Resolve "WalletHD Genesis: Refactor to use Mnemonic Primitive"

This commit is contained in:
2025-07-26 22:46:10 +00:00
committed by Jim Hamill
parent 4f15ce0a7c
commit f40c23417d
5 changed files with 39 additions and 32 deletions
+1 -5
View File
@@ -1,11 +1,7 @@
import { BaseStore } from './base-store.js';
import { StoreComposite } from './store-composite.js';
import { EventEmitter, UUIDV7 } from '../utils/index.js';
// Make the given property in a type optional.
// TODO: This is an extremely useful utility. If we use it elsewhere, move to own "type-utils.ts" file.
type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
import { type Optional, EventEmitter, UUIDV7 } from '../utils/index.js';
// Base Activity interface
export interface Activity {
+1
View File
@@ -6,4 +6,5 @@ export * from './memoizer.js';
export * from './misc.js';
export * from './sse-session.js';
export * from './sse-session-msgpackr.js';
export * from './type-utils.js';
export * from './uuid.js';
+11
View File
@@ -0,0 +1,11 @@
/**
* Utility for removing keys that works with distributive unions.
*/
export type DistributiveOmit<T, K extends keyof any> = T extends any
? Omit<T, K>
: never;
/**
* Make the given property in a type optional.
*/
export type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
+20 -20
View File
@@ -5,6 +5,7 @@ import { type WalletBlockchain, type WalletDependencies } from './types.js';
import { WalletP2PKH } from './wallet-p2pkh.js';
import { type BaseStore, Activities, StoreInMemory } from '../storage/index.js';
import { type DistributiveOmit } from '../utils/index.js';
import {
type TokenBalances,
@@ -23,15 +24,20 @@ export const ADDRESS_GAP = 20;
export const CHAIN_EXTERNAL = 0;
export const CHAIN_INTERNAL = 1;
export type WalletHDGenesisData = {
type: 'WalletHD';
export type WalletHDEntropy =
| { seed: string }
| { xpriv: string }
| { mnemonic: Mnemonic };
export type WalletHDDerivationData = {
derivationPath: string;
addressGap?: number;
} & (
| { seed: string }
| { mnemonic: string; passphrase?: string }
| { xpriv: string }
);
};
export type WalletHDGenesisData = {
type: 'WalletHD';
} & WalletHDEntropy &
WalletHDDerivationData;
/**
* A Hierarhical Determinstic (BIP44) Wallet.
@@ -61,7 +67,7 @@ export class WalletHD extends BaseWallet {
static async from<T extends typeof WalletHD>(
this: T,
deps: WalletDependencies,
genesisData: WalletHDGenesisData,
genesisData: DistributiveOmit<WalletHDGenesisData, 'type'>,
) {
// Assign defaults if not otherwise provideed.
const activities = deps.activities
@@ -99,7 +105,7 @@ export class WalletHD extends BaseWallet {
constructor(
dependencies: Required<WalletDependencies>,
genesisData: WalletHDGenesisData,
genesisData: DistributiveOmit<WalletHDGenesisData, 'type'>,
) {
super();
@@ -109,22 +115,17 @@ export class WalletHD extends BaseWallet {
this.cache = dependencies.cache;
// Assign our state.
this.genesisData = genesisData;
this.genesisData = {
type: 'WalletHD',
...genesisData,
};
// Instantiate the HDPrivateNode from the type specified in our genesis data.
if ('seed' in genesisData) {
this.hdPrivateNode = HDPrivateNode.fromSeed(genesisData.seed);
} else if ('mnemonic' in genesisData) {
// TODO: We really want to support multiple word-lists somehow.
// But this is not trivial because other word-lists are technically not standard.
// For now, we are allowing any phrase (BIP39 derives seed from literal phrase, not word indexes).
const mnemonic = Mnemonic.fromRaw({
words: genesisData.mnemonic.split(' '),
passphrase: genesisData.passphrase,
});
// Create the HD Node from our Mnemonic instance.
this.hdPrivateNode = HDPrivateNode.fromMnemonic(mnemonic);
this.hdPrivateNode = HDPrivateNode.fromMnemonic(genesisData.mnemonic);
} else {
this.hdPrivateNode = HDPrivateNode.fromXPriv(genesisData.xpriv);
}
@@ -364,7 +365,6 @@ export class WalletHD extends BaseWallet {
cache: this.cache,
},
{
type: 'WalletP2PKH',
privateKey: privateKeyHex,
},
);
+6 -7
View File
@@ -45,7 +45,7 @@ export class WalletP2PKH extends BaseWallet {
static async from<T extends typeof WalletP2PKH>(
this: T,
deps: WalletDependencies,
genesisData: WalletP2PKHGenesisData,
genesisData: Omit<WalletP2PKHGenesisData, 'type'>,
) {
// Assign defaults if not otherwise provideed.
const activities = deps.activities
@@ -77,7 +77,6 @@ export class WalletP2PKH extends BaseWallet {
// Return a new instance of Wallet P2PKH.
return this.from<T>(services, {
type: 'WalletP2PKH',
privateKey: privateKey.toHex(),
});
}
@@ -92,7 +91,6 @@ export class WalletP2PKH extends BaseWallet {
// Return a new instance of Wallet P2PKH.
return this.from<T>(services, {
type: 'WalletP2PKH',
privateKey: privateKey.toHex(),
});
}
@@ -107,7 +105,6 @@ export class WalletP2PKH extends BaseWallet {
// Return a new instance of Wallet P2PKH.
return this.from<T>(services, {
type: 'WalletP2PKH',
privateKey: privateKey.toHex(),
});
}
@@ -121,7 +118,6 @@ export class WalletP2PKH extends BaseWallet {
// Return a new instance of Wallet P2PKH.
return this.from<T>(services, {
type: 'WalletP2PKH',
privateKey: privateKey.toHex(),
});
}
@@ -143,7 +139,7 @@ export class WalletP2PKH extends BaseWallet {
constructor(
dependencies: Required<WalletDependencies>,
genesisData: WalletP2PKHGenesisData,
genesisData: Omit<WalletP2PKHGenesisData, 'type'>,
) {
super();
@@ -153,7 +149,10 @@ export class WalletP2PKH extends BaseWallet {
this.cache = dependencies.cache;
// Assign our Genesis Data.
this.genesisData = genesisData;
this.genesisData = {
type: 'WalletP2PKH',
...genesisData,
};
// Optimizations/Simplifications.
this.privateKey = PrivateKey.fromHex(genesisData.privateKey);