From 652e4e480764ddf7363efbde708f750fc5d91e84 Mon Sep 17 00:00:00 2001 From: claudiovb Date: Fri, 10 Jul 2026 17:19:12 -0300 Subject: [PATCH 1/3] updates to new optional fields and functions to signer interface --- src/signer.js | 21 +++++++++++++++++++++ src/wallet-account.js | 15 +++++++++------ src/wallet-manager.js | 3 +++ types/src/signer.d.ts | 14 ++++++++++++++ types/src/wallet-account.d.ts | 21 ++++++++++++--------- types/src/wallet-manager.d.ts | 2 ++ 6 files changed, 61 insertions(+), 15 deletions(-) diff --git a/src/signer.js b/src/signer.js index 3d49487..65fcd54 100644 --- a/src/signer.js +++ b/src/signer.js @@ -15,12 +15,33 @@ import { NotImplementedError } from './errors.js' +/** @typedef {import('./wallet-account.js').KeyPair} KeyPair */ + /** * A minimal, cross-chain signer interface. * * @interface */ export class ISigner { + /** + * Whether the signer supports account derivation via {@link derive}. + * + * @type {boolean} + */ + get isDerivable () { + throw new NotImplementedError('isDerivable') + } + + /** + * The signer's key pair, or null if the signer does not allow retrieving + * key material (e.g. hardware signers). + * + * @type {KeyPair | null} + */ + get keyPair () { + throw new NotImplementedError('keyPair') + } + /** * Derive a child signer using a relative path (e.g., "0'/0/0"). * diff --git a/src/wallet-account.js b/src/wallet-account.js index 29e3def..38e66dc 100644 --- a/src/wallet-account.js +++ b/src/wallet-account.js @@ -35,27 +35,30 @@ import { NotImplementedError } from './errors.js' */ export class IWalletAccount extends IWalletAccountReadOnly { /** - * The derivation path's index of this account. + * The derivation path's index of this account, or undefined if the account's + * signer is not bound to a BIP-44 position (e.g. private-key signers). * - * @type {number} + * @type {number | undefined} */ get index () { throw new NotImplementedError('index') } /** - * The derivation path of this account (see [BIP-44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki)). + * The derivation path of this account (see [BIP-44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki)), + * or undefined if the account's signer is not bound to a BIP-44 position (e.g. private-key signers). * - * @type {string} + * @type {string | undefined} */ get path () { throw new NotImplementedError('path') } /** - * The account's key pair. + * The account's key pair, or null if the account's signer does not allow + * retrieving key material (e.g. hardware signers). * - * @type {KeyPair} + * @type {KeyPair | null} */ get keyPair () { throw new NotImplementedError('keyPair') diff --git a/src/wallet-manager.js b/src/wallet-manager.js index 9e72285..7a6355b 100644 --- a/src/wallet-manager.js +++ b/src/wallet-manager.js @@ -19,6 +19,7 @@ import { NotImplementedError } from './errors.js' /** @typedef {import('./wallet-account.js').IWalletAccount} IWalletAccount */ /** @typedef {import('./signer.js').ISigner} ISigner */ +/** @typedef {import('./errors.js').SignerError} SignerError */ /** * @typedef {Object} WalletConfig @@ -40,6 +41,7 @@ export default class WalletManager { * @overload * @param {string | Uint8Array} seed - The BIP-39 seed phrase or raw seed bytes. * @param {WalletConfig} [config] - The wallet configuration. + * @throws {Error} If the seed phrase is invalid. */ /** @@ -48,6 +50,7 @@ export default class WalletManager { * @overload * @param {ISigner} signer - The default signer. * @param {WalletConfig} [config] - The wallet configuration. + * @throws {SignerError} If the default signer does not support account derivation. */ constructor (seedOrSigner, config = {}) { if (typeof seedOrSigner === 'string') { diff --git a/types/src/signer.d.ts b/types/src/signer.d.ts index 038e21a..bc9e02f 100644 --- a/types/src/signer.d.ts +++ b/types/src/signer.d.ts @@ -4,6 +4,19 @@ * @interface */ export class ISigner { + /** + * Whether the signer supports account derivation via {@link derive}. + * + * @type {boolean} + */ + get isDerivable(): boolean; + /** + * The signer's key pair, or null if the signer does not allow retrieving + * key material (e.g. hardware signers). + * + * @type {KeyPair | null} + */ + get keyPair(): KeyPair | null; /** * Derive a child signer using a relative path (e.g., "0'/0/0"). * @@ -23,4 +36,5 @@ export class ISigner { */ dispose(): void; } +export type KeyPair = import("./wallet-account.js").KeyPair; export type SignerError = import("./errors.js").SignerError; diff --git a/types/src/wallet-account.d.ts b/types/src/wallet-account.d.ts index 90b20b4..cdb318f 100644 --- a/types/src/wallet-account.d.ts +++ b/types/src/wallet-account.d.ts @@ -1,23 +1,26 @@ /** @interface */ export interface IWalletAccount extends IWalletAccountReadOnly { /** - * The derivation path's index of this account. + * The derivation path's index of this account, or undefined if the account's + * signer is not bound to a BIP-44 position (e.g. private-key signers). * - * @type {number} + * @type {number | undefined} */ - get index(): number; + get index(): number | undefined; /** - * The derivation path of this account (see [BIP-44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki)). + * The derivation path of this account (see [BIP-44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki)), + * or undefined if the account's signer is not bound to a BIP-44 position (e.g. private-key signers). * - * @type {string} + * @type {string | undefined} */ - get path(): string; + get path(): string | undefined; /** - * The account's key pair. + * The account's key pair, or null if the account's signer does not allow + * retrieving key material (e.g. hardware signers). * - * @type {KeyPair} + * @type {KeyPair | null} */ - get keyPair(): KeyPair; + get keyPair(): KeyPair | null; /** * Signs a message. * diff --git a/types/src/wallet-manager.d.ts b/types/src/wallet-manager.d.ts index 9029fc7..d885de2 100644 --- a/types/src/wallet-manager.d.ts +++ b/types/src/wallet-manager.d.ts @@ -19,6 +19,7 @@ export default abstract class WalletManager { * * @param {string | Uint8Array} seed - The BIP-39 seed phrase or raw seed bytes. * @param {WalletConfig} [config] - The wallet configuration. + * @throws {Error} If the seed phrase is invalid. */ constructor(seed: string | Uint8Array, config?: WalletConfig); /** @@ -26,6 +27,7 @@ export default abstract class WalletManager { * * @param {ISigner} signer - The default signer. * @param {WalletConfig} [config] - The wallet configuration. + * @throws {SignerError} If the default signer does not support account derivation. */ constructor(signer: ISigner, config?: WalletConfig); /** @private */ From bd221c2d3e0d48a7d5123a4c91cd712674be3ca5 Mon Sep 17 00:00:00 2001 From: claudiovb Date: Fri, 17 Jul 2026 22:11:39 -0300 Subject: [PATCH 2/3] remove undefined in favor of null for optional interface --- src/wallet-account.js | 8 ++++---- types/src/wallet-account.d.ts | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/wallet-account.js b/src/wallet-account.js index 38e66dc..b135610 100644 --- a/src/wallet-account.js +++ b/src/wallet-account.js @@ -35,10 +35,10 @@ import { NotImplementedError } from './errors.js' */ export class IWalletAccount extends IWalletAccountReadOnly { /** - * The derivation path's index of this account, or undefined if the account's + * The derivation path's index of this account, or null if the account's * signer is not bound to a BIP-44 position (e.g. private-key signers). * - * @type {number | undefined} + * @type {number | null} */ get index () { throw new NotImplementedError('index') @@ -46,9 +46,9 @@ export class IWalletAccount extends IWalletAccountReadOnly { /** * The derivation path of this account (see [BIP-44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki)), - * or undefined if the account's signer is not bound to a BIP-44 position (e.g. private-key signers). + * or null if the account's signer is not bound to a BIP-44 position (e.g. private-key signers). * - * @type {string | undefined} + * @type {string | null} */ get path () { throw new NotImplementedError('path') diff --git a/types/src/wallet-account.d.ts b/types/src/wallet-account.d.ts index cdb318f..13e8be1 100644 --- a/types/src/wallet-account.d.ts +++ b/types/src/wallet-account.d.ts @@ -1,19 +1,19 @@ /** @interface */ export interface IWalletAccount extends IWalletAccountReadOnly { /** - * The derivation path's index of this account, or undefined if the account's + * The derivation path's index of this account, or null if the account's * signer is not bound to a BIP-44 position (e.g. private-key signers). * - * @type {number | undefined} + * @type {number | null} */ - get index(): number | undefined; + get index(): number | null; /** * The derivation path of this account (see [BIP-44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki)), - * or undefined if the account's signer is not bound to a BIP-44 position (e.g. private-key signers). + * or null if the account's signer is not bound to a BIP-44 position (e.g. private-key signers). * - * @type {string | undefined} + * @type {string | null} */ - get path(): string | undefined; + get path(): string | null; /** * The account's key pair, or null if the account's signer does not allow * retrieving key material (e.g. hardware signers). From 310b5677052363c1e11c878f733335d6e4d45a04 Mon Sep 17 00:00:00 2001 From: claudiovb Date: Fri, 17 Jul 2026 22:51:35 -0300 Subject: [PATCH 3/3] remove index from IWalletAccount and add IDisposable interface --- index.js | 2 ++ src/disposable.js | 26 ++++++++++++++++++++++++++ src/signer.js | 22 ++++++++++++++++++---- src/wallet-account.js | 13 +++---------- src/wallet-manager.js | 6 +++++- types/index.d.ts | 1 + types/src/disposable.d.ts | 7 +++++++ types/src/signer.d.ts | 16 +++++++++++++--- types/src/wallet-account.d.ts | 19 ++++++------------- types/src/wallet-manager.d.ts | 8 ++++++-- 10 files changed, 87 insertions(+), 33 deletions(-) create mode 100644 src/disposable.js create mode 100644 types/src/disposable.d.ts diff --git a/index.js b/index.js index 80f0b0d..94a8970 100644 --- a/index.js +++ b/index.js @@ -35,3 +35,5 @@ export { IWalletAccount } from './src/wallet-account.js' export { NotImplementedError, SignerError } from './src/errors.js' export { ISigner } from './src/signer.js' + +export { IDisposable } from './src/disposable.js' diff --git a/src/disposable.js b/src/disposable.js new file mode 100644 index 0000000..d861268 --- /dev/null +++ b/src/disposable.js @@ -0,0 +1,26 @@ +// Copyright 2024 Tether Operations Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +'use strict' + +import { NotImplementedError } from './errors.js' + +/** @interface */ +export class IDisposable { + /** + * Disposes the object along with all its data (cleaning up any sensitive field from memory). + */ + dispose () { + throw new NotImplementedError('dispose()') + } +} diff --git a/src/signer.js b/src/signer.js index 65fcd54..426c360 100644 --- a/src/signer.js +++ b/src/signer.js @@ -15,6 +15,8 @@ import { NotImplementedError } from './errors.js' +import { IDisposable } from './disposable.js' + /** @typedef {import('./wallet-account.js').KeyPair} KeyPair */ /** @@ -22,7 +24,7 @@ import { NotImplementedError } from './errors.js' * * @interface */ -export class ISigner { +export class ISigner extends IDisposable { /** * Whether the signer supports account derivation via {@link derive}. * @@ -42,6 +44,15 @@ export class ISigner { throw new NotImplementedError('keyPair') } + /** + * The BIP 0044 derivation path. + * + * @type {string | null} + */ + get path () { + throw new NotImplementedError('path') + } + /** * Derive a child signer using a relative path (e.g., "0'/0/0"). * @@ -63,9 +74,12 @@ export class ISigner { } /** - * Disposes the signer and clears any secret material from memory. + * Signs a message. + * + * @param {string} message - The message to sign. + * @returns {Promise} The message's signature. */ - dispose () { - throw new NotImplementedError('dispose()') + async sign (message) { + throw new NotImplementedError('sign(message)') } } diff --git a/src/wallet-account.js b/src/wallet-account.js index b135610..b3c2ab6 100644 --- a/src/wallet-account.js +++ b/src/wallet-account.js @@ -29,21 +29,14 @@ import { NotImplementedError } from './errors.js' * @property {Uint8Array | null} privateKey - The private key (null if the account has been disposed). */ +/** @typedef {import('./disposable.js').IDisposable} IDisposable */ + /** * @interface + * @implements {IDisposable} * @template [TSignedTransaction=unknown] */ export class IWalletAccount extends IWalletAccountReadOnly { - /** - * The derivation path's index of this account, or null if the account's - * signer is not bound to a BIP-44 position (e.g. private-key signers). - * - * @type {number | null} - */ - get index () { - throw new NotImplementedError('index') - } - /** * The derivation path of this account (see [BIP-44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki)), * or null if the account's signer is not bound to a BIP-44 position (e.g. private-key signers). diff --git a/src/wallet-manager.js b/src/wallet-manager.js index 7a6355b..0ab6a40 100644 --- a/src/wallet-manager.js +++ b/src/wallet-manager.js @@ -20,6 +20,7 @@ import { NotImplementedError } from './errors.js' /** @typedef {import('./wallet-account.js').IWalletAccount} IWalletAccount */ /** @typedef {import('./signer.js').ISigner} ISigner */ /** @typedef {import('./errors.js').SignerError} SignerError */ +/** @typedef {import('./disposable.js').IDisposable} IDisposable */ /** * @typedef {Object} WalletConfig @@ -33,7 +34,10 @@ import { NotImplementedError } from './errors.js' * @property {bigint} fast - The fee rate for transaction sent with fast priority. */ -/** @abstract */ +/** + * @abstract + * @implements {IDisposable} + */ export default class WalletManager { /** * Creates a new wallet manager from a BIP-39 seed. diff --git a/types/index.d.ts b/types/index.d.ts index 8f5f271..6b7afbc 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -10,3 +10,4 @@ export { default as WalletAccountReadOnly, IWalletAccountReadOnly } from "./src/ export { IWalletAccount } from "./src/wallet-account.js"; export { NotImplementedError, SignerError } from "./src/errors.js"; export { ISigner } from "./src/signer.js"; +export { IDisposable } from "./src/disposable.js"; diff --git a/types/src/disposable.d.ts b/types/src/disposable.d.ts new file mode 100644 index 0000000..f183c2c --- /dev/null +++ b/types/src/disposable.d.ts @@ -0,0 +1,7 @@ +/** @interface */ +export class IDisposable { + /** + * Disposes the object along with all its data (cleaning up any sensitive field from memory). + */ + dispose(): void; +} diff --git a/types/src/signer.d.ts b/types/src/signer.d.ts index bc9e02f..26ffe7c 100644 --- a/types/src/signer.d.ts +++ b/types/src/signer.d.ts @@ -3,7 +3,7 @@ * * @interface */ -export class ISigner { +export class ISigner extends IDisposable { /** * Whether the signer supports account derivation via {@link derive}. * @@ -17,6 +17,12 @@ export class ISigner { * @type {KeyPair | null} */ get keyPair(): KeyPair | null; + /** + * The BIP 0044 derivation path. + * + * @type {string | null} + */ + get path(): string | null; /** * Derive a child signer using a relative path (e.g., "0'/0/0"). * @@ -32,9 +38,13 @@ export class ISigner { */ getAddress(): Promise; /** - * Disposes the signer and clears any secret material from memory. + * Signs a message. + * + * @param {string} message - The message to sign. + * @returns {Promise} The message's signature. */ - dispose(): void; + sign(message: string): Promise; } export type KeyPair = import("./wallet-account.js").KeyPair; export type SignerError = import("./errors.js").SignerError; +import { IDisposable } from "./disposable.js"; diff --git a/types/src/wallet-account.d.ts b/types/src/wallet-account.d.ts index 13e8be1..0c0fe23 100644 --- a/types/src/wallet-account.d.ts +++ b/types/src/wallet-account.d.ts @@ -1,12 +1,8 @@ -/** @interface */ -export interface IWalletAccount extends IWalletAccountReadOnly { - /** - * The derivation path's index of this account, or null if the account's - * signer is not bound to a BIP-44 position (e.g. private-key signers). - * - * @type {number | null} - */ - get index(): number | null; +/** + * @interface + * @implements {IDisposable} + */ +export interface IWalletAccount extends IWalletAccountReadOnly, IDisposable { /** * The derivation path of this account (see [BIP-44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki)), * or null if the account's signer is not bound to a BIP-44 position (e.g. private-key signers). @@ -72,10 +68,6 @@ export interface IWalletAccount extends IWalletAcc * @returns {Promise} The read-only account. */ toReadOnlyAccount(): Promise; - /** - * Disposes the wallet account, erasing the private key from the memory. - */ - dispose(): void; } export type Transaction = import("./wallet-account-read-only.js").Transaction; export type TransactionResult = import("./wallet-account-read-only.js").TransactionResult; @@ -92,3 +84,4 @@ export type KeyPair = { privateKey: Uint8Array | null; }; import { IWalletAccountReadOnly } from './wallet-account-read-only.js'; +export type IDisposable = import("./disposable.js").IDisposable; diff --git a/types/src/wallet-manager.d.ts b/types/src/wallet-manager.d.ts index d885de2..9861e59 100644 --- a/types/src/wallet-manager.d.ts +++ b/types/src/wallet-manager.d.ts @@ -1,5 +1,8 @@ -/** @abstract */ -export default abstract class WalletManager { +/** + * @abstract + * @implements {IDisposable} + */ +export default abstract class WalletManager implements IDisposable { /** * Returns a random [BIP-39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) seed phrase. * @@ -176,3 +179,4 @@ export type FeeRates = { */ fast: bigint; }; +import { IDisposable } from "./disposable.js";