Skip to content

Commit

Permalink
implement constructor guard in HD wallets
Browse files Browse the repository at this point in the history
  • Loading branch information
alejoacosta74 authored and rileystephens28 committed Jun 25, 2024
1 parent d77f3fe commit e2e3c76
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 23 deletions.
29 changes: 18 additions & 11 deletions src/wallet/hdwallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Mnemonic } from './mnemonic.js';
import { LangEn } from '../wordlists/lang-en.js';
import type { Wordlist } from '../wordlists/index.js';
import { randomBytes } from '../crypto/index.js';
import { getZoneForAddress } from '../utils/index.js';
import { getZoneForAddress, assertPrivate } from '../utils/index.js';
import { isQiAddress } from '../address/index.js';
import { Zone } from '../constants/index.js';
import { TransactionRequest, Provider, TransactionResponse } from '../providers/index.js';
Expand Down Expand Up @@ -36,6 +36,8 @@ export interface SerializedHDWallet {
*/
const MAX_ADDRESS_DERIVATION_ATTEMPTS = 10000000;

export const _guard = {};

/**
* Abstract class representing a Hierarchical Deterministic (HD) wallet.
*/
Expand All @@ -58,7 +60,8 @@ export abstract class AbstractHDWallet {
* @param {HDNodeWallet} root - The root node of the HD wallet.
* @param {Provider} [provider] - The provider for the HD wallet.
*/
protected constructor(root: HDNodeWallet, provider?: Provider) {
constructor(guard: any, root: HDNodeWallet, provider?: Provider) {
assertPrivate(guard, _guard, 'AbstractHDWallet');
this._root = root;
this.provider = provider;
}
Expand Down Expand Up @@ -90,8 +93,7 @@ export abstract class AbstractHDWallet {
* @param {number} account - The account number from which to derive the address node.
* @param {number} startingIndex - The index from which to start deriving addresses.
* @param {Zone} zone - The zone (shard) for which the address should be valid.
* @param {boolean} [isChange=false] - Whether to derive a change address (default is false). Default is `false`
* Default is `false` Default is `false`
* @param {boolean} [isChange=false] - Whether to derive a change address (default is false) Default is `false`
*
* @returns {HDNodeWallet} - The derived HD node wallet containing a valid address for the specified zone.
* @throws {Error} If a valid address for the specified zone cannot be derived within the allowed attempts.
Expand Down Expand Up @@ -135,7 +137,8 @@ export abstract class AbstractHDWallet {
*
* @param {number} account - The account number.
* @param {number} addressIndex - The address index.
* @param {boolean} [isChange=false] - Whether the address is a change address. Default is `false`
* @param {boolean} [isChange=false] - Whether the address is a change address. Default is `false` Default is
* `false`
*
* @returns {NeuteredAddressInfo} The added address info.
*/
Expand All @@ -149,7 +152,8 @@ export abstract class AbstractHDWallet {
* @param {Map<string, NeuteredAddressInfo>} addressMap - The address map.
* @param {number} account - The account number.
* @param {number} addressIndex - The address index.
* @param {boolean} [isChange=false] - Whether the address is a change address. Default is `false`
* @param {boolean} [isChange=false] - Whether the address is a change address. Default is `false` Default is
* `false`
*
* @returns {NeuteredAddressInfo} The added address info.
* @throws {Error} If the address for the index already exists.
Expand Down Expand Up @@ -262,12 +266,12 @@ export abstract class AbstractHDWallet {
* @returns {T} The created instance.
*/
protected static createInstance<T extends AbstractHDWallet>(
this: new (root: HDNodeWallet) => T,
this: new (guard: any, root: HDNodeWallet) => T,
mnemonic: Mnemonic,
): T {
const coinType = (this as any)._coinType;
const root = HDNodeWallet.fromMnemonic(mnemonic, (this as any).parentPath(coinType));
return new this(root);
return new (this as any)(_guard, root);
}

/**
Expand All @@ -278,7 +282,10 @@ export abstract class AbstractHDWallet {
*
* @returns {T} The created instance.
*/
static fromMnemonic<T extends AbstractHDWallet>(this: new (root: HDNodeWallet) => T, mnemonic: Mnemonic): T {
static fromMnemonic<T extends AbstractHDWallet>(
this: new (guard: any, root: HDNodeWallet) => T,
mnemonic: Mnemonic,
): T {
return (this as any).createInstance(mnemonic);
}

Expand All @@ -292,7 +299,7 @@ export abstract class AbstractHDWallet {
* @returns {T} The created instance.
*/
static createRandom<T extends AbstractHDWallet>(
this: new (root: HDNodeWallet) => T,
this: new (guard: any, root: HDNodeWallet) => T,
password?: string,
wordlist?: Wordlist,
): T {
Expand All @@ -317,7 +324,7 @@ export abstract class AbstractHDWallet {
* @returns {T} The created instance.
*/
static fromPhrase<T extends AbstractHDWallet>(
this: new (root: HDNodeWallet) => T,
this: new (guard: any, root: HDNodeWallet) => T,
phrase: string,
password?: string,
wordlist?: Wordlist,
Expand Down
14 changes: 6 additions & 8 deletions src/wallet/qi-hdwallet.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AbstractHDWallet, NeuteredAddressInfo, SerializedHDWallet } from './hdwallet.js';
import { AbstractHDWallet, NeuteredAddressInfo, SerializedHDWallet, _guard } from './hdwallet.js';
import { HDNodeWallet } from './hdnodewallet.js';
import { QiTransactionRequest, Provider, TransactionResponse } from '../providers/index.js';
import { computeAddress } from '../address/index.js';
Expand Down Expand Up @@ -125,8 +125,8 @@ export class QiHDWallet extends AbstractHDWallet {
* @param {HDNodeWallet} root - The root HDNodeWallet.
* @param {Provider} [provider] - The provider (optional).
*/
private constructor(root: HDNodeWallet, provider?: Provider) {
super(root, provider);
constructor(guard: any, root: HDNodeWallet, provider?: Provider) {
super(guard, root, provider);
}

/**
Expand Down Expand Up @@ -321,8 +321,7 @@ export class QiHDWallet extends AbstractHDWallet {
* until the gap limit is reached for both gap and change addresses.
*
* @param {Zone} zone - The zone in which to scan for addresses.
* @param {number} [account=0] - The index of the account to scan. Defaults to 0. Default is `0` Default is `0`
* Default is `0`
* @param {number} [account=0] - The index of the account to scan. Defaults to 0. Default is `0`
*
* @returns {Promise<void>} A promise that resolves when the scan is complete.
* @throws {Error} If the zone is invalid.
Expand Down Expand Up @@ -376,8 +375,7 @@ export class QiHDWallet extends AbstractHDWallet {
* scanning logic, generating new addresses until the gap limit is reached for both gap and change addresses.
*
* @param {Zone} zone - The zone in which to scan for addresses.
* @param {number} [account=0] - The index of the account to scan. Defaults to 0. Default is `0` Default is `0`
* Default is `0`
* @param {number} [account=0] - The index of the account to scan. Defaults to 0. Default is `0`
*
* @returns {Promise<void>} A promise that resolves when the scan is complete.
* @throws {Error} If the provider is not set.
Expand Down Expand Up @@ -543,7 +541,7 @@ export class QiHDWallet extends AbstractHDWallet {
const mnemonic = Mnemonic.fromPhrase(serialized.phrase);
const path = (this as any).parentPath(serialized.coinType);
const root = HDNodeWallet.fromMnemonic(mnemonic, path);
const wallet = new this(root);
const wallet = new this(_guard, root);

// import the addresses
wallet.importSerializedAddresses(wallet._addresses, serialized.addresses);
Expand Down
8 changes: 4 additions & 4 deletions src/wallet/quai-hdwallet.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AbstractHDWallet } from './hdwallet.js';
import { AbstractHDWallet, _guard } from './hdwallet.js';
import { HDNodeWallet } from './hdnodewallet.js';
import { QuaiTransactionRequest, Provider, TransactionResponse } from '../providers/index.js';
import { resolveAddress } from '../address/index.js';
Expand Down Expand Up @@ -59,8 +59,8 @@ export class QuaiHDWallet extends AbstractHDWallet {
* @param {HDNodeWallet} root - The root HD node wallet.
* @param {Provider} [provider] - The provider.
*/
private constructor(root: HDNodeWallet, provider?: Provider) {
super(root, provider);
constructor(guard: any, root: HDNodeWallet, provider?: Provider) {
super(guard, root, provider);
}

/**
Expand Down Expand Up @@ -125,7 +125,7 @@ export class QuaiHDWallet extends AbstractHDWallet {
const mnemonic = Mnemonic.fromPhrase(serialized.phrase);
const path = (this as any).parentPath(serialized.coinType);
const root = HDNodeWallet.fromMnemonic(mnemonic, path);
const wallet = new this(root);
const wallet = new this(_guard, root);

// import the addresses
wallet.importSerializedAddresses(wallet._addresses, serialized.addresses);
Expand Down

0 comments on commit e2e3c76

Please sign in to comment.