From 8c87bbdcf8fb6aaecab9d07ff44c94c49e6fb112 Mon Sep 17 00:00:00 2001 From: Alejo Acosta Date: Tue, 25 Jun 2024 13:19:59 -0300 Subject: [PATCH] implement constructor guard in HD wallets --- src/wallet/hdwallet.ts | 28 ++++++++++++++++++---------- src/wallet/qi-hdwallet.ts | 12 ++++++------ src/wallet/quai-hdwallet.ts | 8 ++++---- 3 files changed, 28 insertions(+), 20 deletions(-) diff --git a/src/wallet/hdwallet.ts b/src/wallet/hdwallet.ts index 9ef1f920..f0cb0a34 100644 --- a/src/wallet/hdwallet.ts +++ b/src/wallet/hdwallet.ts @@ -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'; @@ -36,6 +36,8 @@ export interface SerializedHDWallet { */ const MAX_ADDRESS_DERIVATION_ATTEMPTS = 10000000; +export const _guard = {}; + /** * Abstract class representing a Hierarchical Deterministic (HD) wallet. */ @@ -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; } @@ -91,7 +94,7 @@ export abstract class AbstractHDWallet { * @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` + * Default is `false` 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. @@ -135,7 +138,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. */ @@ -149,7 +153,8 @@ export abstract class AbstractHDWallet { * @param {Map} 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. @@ -262,12 +267,12 @@ export abstract class AbstractHDWallet { * @returns {T} The created instance. */ protected static createInstance( - 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); } /** @@ -278,7 +283,10 @@ export abstract class AbstractHDWallet { * * @returns {T} The created instance. */ - static fromMnemonic(this: new (root: HDNodeWallet) => T, mnemonic: Mnemonic): T { + static fromMnemonic( + this: new (guard: any, root: HDNodeWallet) => T, + mnemonic: Mnemonic, + ): T { return (this as any).createInstance(mnemonic); } @@ -292,7 +300,7 @@ export abstract class AbstractHDWallet { * @returns {T} The created instance. */ static createRandom( - this: new (root: HDNodeWallet) => T, + this: new (guard: any, root: HDNodeWallet) => T, password?: string, wordlist?: Wordlist, ): T { @@ -317,7 +325,7 @@ export abstract class AbstractHDWallet { * @returns {T} The created instance. */ static fromPhrase( - this: new (root: HDNodeWallet) => T, + this: new (guard: any, root: HDNodeWallet) => T, phrase: string, password?: string, wordlist?: Wordlist, diff --git a/src/wallet/qi-hdwallet.ts b/src/wallet/qi-hdwallet.ts index cd66d775..ced7a526 100644 --- a/src/wallet/qi-hdwallet.ts +++ b/src/wallet/qi-hdwallet.ts @@ -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'; @@ -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); } /** @@ -322,7 +322,7 @@ export class QiHDWallet extends AbstractHDWallet { * * @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` + * Default is `0` Default is `0` * * @returns {Promise} A promise that resolves when the scan is complete. * @throws {Error} If the zone is invalid. @@ -377,7 +377,7 @@ export class QiHDWallet extends AbstractHDWallet { * * @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` + * Default is `0` Default is `0` * * @returns {Promise} A promise that resolves when the scan is complete. * @throws {Error} If the provider is not set. @@ -543,7 +543,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); diff --git a/src/wallet/quai-hdwallet.ts b/src/wallet/quai-hdwallet.ts index c30c2447..1aa9d2fe 100644 --- a/src/wallet/quai-hdwallet.ts +++ b/src/wallet/quai-hdwallet.ts @@ -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'; @@ -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); } /** @@ -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);