From 0dcccf82d856297c2f35555b4e913ec6eaebae5b Mon Sep 17 00:00:00 2001 From: Michael McShinsky Date: Fri, 10 Jul 2026 15:13:05 -0700 Subject: [PATCH] feat(sdk-core): type BitGoBase.wallets() as BitGoApiV1Wallets Define the full deprecated v1 wallets facade and use it on BitGoBase and BitGoAPI.wallets(). BitGoApiV1BitGo is a leaf type (imports api only) to avoid a bitgoBase/v1Wallets circular dependency. Docs make clear this is v1-only; v2 is coin().wallets() / IWallets. get/getWallet/add still return Promise for the CommonJS v1 Wallet instance so abstract-utxo recovery (recover/sweep, WalletV1) keeps typechecking until v1/wallet.ts is typed. WEB-000 --- modules/sdk-api/src/bitgoAPI.ts | 18 ++- modules/sdk-api/test/unit/bitgoAPI.ts | 24 ++++ modules/sdk-core/src/bitgo/bitgoBase.ts | 26 +++- modules/sdk-core/src/bitgo/v1Wallets.ts | 166 ++++++++++++++++++++++++ 4 files changed, 228 insertions(+), 6 deletions(-) create mode 100644 modules/sdk-core/src/bitgo/v1Wallets.ts diff --git a/modules/sdk-api/src/bitgoAPI.ts b/modules/sdk-api/src/bitgoAPI.ts index 7cddbf0c49..126d5e5c31 100644 --- a/modules/sdk-api/src/bitgoAPI.ts +++ b/modules/sdk-api/src/bitgoAPI.ts @@ -4,6 +4,7 @@ import { bitcoin, BitGoBase, BitGoRequest, + type BitGoApiV1Wallets, CoinConstructor, common, DecryptKeysOptions, @@ -101,6 +102,9 @@ const PendingApprovals = require('./v1/pendingapprovals'); const TravelRule = require('./v1/travelRule'); const TransactionBuilder = require('./v1/transactionBuilder'); +/** Re-export of the deprecated **v1** wallets facade type (`bitgo.wallets()`). Not v2 `IWallets`. */ +export type { BitGoApiV1Wallets } from '@bitgo/sdk-core'; + function validateDecryptKeysParams(params: DecryptKeysOptions): DecryptKeysOptions { params = params || {}; if (!params.walletIdEncryptedKeyPairs) { @@ -231,7 +235,7 @@ function deriveTokenIssuanceEcdhSecret(ecdhXprv: string, derivationPath: string, export class BitGoAPI implements BitGoBase { // v1 types protected _keychains: any; - protected _wallets: any; + protected _wallets: BitGoApiV1Wallets | null; protected _markets?: any; protected _blockchain?: any; protected _travelRule?: any; @@ -1746,12 +1750,16 @@ export class BitGoAPI implements BitGoBase { } /** - * Get the user's wallets object. - * @deprecated + * Get the user's **v1** wallets object (`modules/sdk-api/src/v1/wallets.ts`). + * + * Returns {@link BitGoApiV1Wallets}. This is **not** the v2 wallets API — + * for coin wallets use `this.coin(coinName).wallets()` ({@link IWallets}). + * + * @deprecated Prefer `coin(coinName).wallets()`. */ - wallets(): any { + wallets(): BitGoApiV1Wallets { if (!this._wallets) { - this._wallets = new Wallets(this); + this._wallets = new Wallets(this) as BitGoApiV1Wallets; } return this._wallets; } diff --git a/modules/sdk-api/test/unit/bitgoAPI.ts b/modules/sdk-api/test/unit/bitgoAPI.ts index f77700864e..68c6a2f750 100644 --- a/modules/sdk-api/test/unit/bitgoAPI.ts +++ b/modules/sdk-api/test/unit/bitgoAPI.ts @@ -1168,3 +1168,27 @@ describe('Constructor', function () { }); }); }); + +describe('wallets() v1 facade', function () { + it('returns BitGoApiV1Wallets with bitgo reference and all prototype methods', function () { + const bitgo = new BitGoAPI({ env: 'test' }); + const wallets = bitgo.wallets(); + wallets.bitgo.should.equal(bitgo); + wallets.list.should.be.a.Function(); + wallets.get.should.be.a.Function(); + wallets.getWallet.should.be.a.Function(); + wallets.add.should.be.a.Function(); + wallets.remove.should.be.a.Function(); + wallets.acceptShare.should.be.a.Function(); + wallets.createWalletWithKeychains.should.be.a.Function(); + wallets.createForwardWallet.should.be.a.Function(); + wallets.createKey.should.be.a.Function(); + wallets.listInvites.should.be.a.Function(); + wallets.cancelInvite.should.be.a.Function(); + wallets.listShares.should.be.a.Function(); + wallets.getShare.should.be.a.Function(); + wallets.updateShare.should.be.a.Function(); + wallets.cancelShare.should.be.a.Function(); + wallets.resendShareInvite.should.be.a.Function(); + }); +}); diff --git a/modules/sdk-core/src/bitgo/bitgoBase.ts b/modules/sdk-core/src/bitgo/bitgoBase.ts index 4be871cbdf..a3764ee6c0 100644 --- a/modules/sdk-core/src/bitgo/bitgoBase.ts +++ b/modules/sdk-core/src/bitgo/bitgoBase.ts @@ -11,9 +11,33 @@ import { IBaseCoin } from './baseCoin'; import { CoinConstructor } from './coinFactory'; import { EnvironmentName } from './environments'; import { EcdhDerivedKeypair, GetSigningKeyApi } from './keychain'; +import type { BitGoApiV1Wallets } from './v1Wallets'; + +export type { + BitGoApiV1AddWalletParams, + BitGoApiV1BitGo, + BitGoApiV1Callback, + BitGoApiV1CreateForwardWalletParams, + BitGoApiV1CreateWalletWithKeychainsParams, + BitGoApiV1GetWalletParams, + BitGoApiV1Keychains, + BitGoApiV1ListWalletsParams, + BitGoApiV1RemoveWalletParams, + BitGoApiV1Wallet, + BitGoApiV1WalletInviteParams, + BitGoApiV1WalletShareParams, + BitGoApiV1Wallets, +} from './v1Wallets'; export interface BitGoBase { - wallets(): any; // TODO - define v1 wallets type + /** + * Deprecated **v1** wallets accessor (`bitgo.wallets()` → {@link BitGoApiV1Wallets}). + * + * Do **not** confuse with v2 coin wallets: `bitgo.coin(name).wallets()` → {@link IWallets}. + * + * @deprecated Prefer `coin(coinName).wallets()`. + */ + wallets(): BitGoApiV1Wallets; coin(coinName: string): IBaseCoin; // need to change it to BaseCoin once it's moved to @bitgo/sdk-core decrypt(params: DecryptOptions): Promise; decryptKeys(params: DecryptKeysOptions): Promise; diff --git a/modules/sdk-core/src/bitgo/v1Wallets.ts b/modules/sdk-core/src/bitgo/v1Wallets.ts new file mode 100644 index 0000000000..84187fe76c --- /dev/null +++ b/modules/sdk-core/src/bitgo/v1Wallets.ts @@ -0,0 +1,166 @@ +import type { BitGoRequest, DecryptOptions, EncryptionVersion, EncryptOptions } from '../api'; + +/** + * Minimal BitGo client surface used by the **v1** Wallets facade + * (`modules/sdk-api/src/v1/wallets.ts`). + * + * Intentionally **not** {@link BitGoBase}: importing `BitGoBase` here would + * create a circular module dependency with `bitgoBase.ts`. + * Import graph: `bitgoBase → v1Wallets → api` (acyclic). + * + * @see BitGoApiV1Wallets for the collection returned by `bitgo.wallets()` + * @see IWallets for the **v2** coin wallets API (`bitgo.coin(name).wallets()`) + */ +export type BitGoApiV1BitGo = { + get(url: string): BitGoRequest; + post(url: string): BitGoRequest; + del(url: string): BitGoRequest; + url(path: string, version?: number): string; + encrypt(params: EncryptOptions): Promise; + decrypt(params: DecryptOptions): Promise; + getECDHKeychain(): Promise<{ encryptedXprv?: string; xprv?: string }>; + keychains(): BitGoApiV1Keychains; +}; + +/** + * v1 keychains surface used by `createWalletWithKeychains` on + * {@link BitGoApiV1Wallets}. Distinct from the v2 `IKeychains` API. + */ +export type BitGoApiV1Keychains = { + create(): { xpub: string; xprv?: string; encryptedXprv?: string }; + add(keychainData: Record): Promise; + createBackup(params: { provider: string; disableKRSEmail?: boolean }): Promise<{ xpub: string }>; + createBitGo(): Promise<{ xpub: string }>; +}; + +/** Legacy Node-style callback used by v1 wallet APIs. */ +export type BitGoApiV1Callback = (err?: Error | null, result?: T) => void; + +/** + * Structural hints for a CommonJS v1 Wallet instance + * (`modules/sdk-api/src/v1/wallet.ts`) when used as a **parameter**. + * + * Not the v2 {@link IWallet} / {@link Wallet} class. + * + * Methods that **return** a v1 wallet (`get` / `getWallet` / `add`) still use + * `Promise`: a stub return type with an index signature broke consumers + * (e.g. `abstract-utxo` recovery expects `.recover` / `.sweep` and a local + * `WalletV1` shape). Full typing of `v1/wallet.ts` is a follow-up. + */ +export type BitGoApiV1Wallet = { + id?: string; + createAddress?: (params?: Record) => Promise; +}; + +/** Params for {@link BitGoApiV1Wallets.list}. */ +export type BitGoApiV1ListWalletsParams = { + skip?: number; + prevId?: string; + limit?: number; + getbalances?: boolean; +}; + +/** Params for {@link BitGoApiV1Wallets.get} / {@link BitGoApiV1Wallets.getWallet}. */ +export type BitGoApiV1GetWalletParams = { + id: string; + gpk?: boolean | number; +}; + +/** Params for {@link BitGoApiV1Wallets.cancelInvite}. */ +export type BitGoApiV1WalletInviteParams = { + walletInviteId: string; +}; + +/** Params for v1 wallet-share methods on {@link BitGoApiV1Wallets}. */ +export type BitGoApiV1WalletShareParams = { + walletShareId: string; + state?: string; + encryptedXprv?: string; + userPassword?: string; + newWalletPassphrase?: string; + overrideEncryptedXprv?: string; + encryptionVersion?: EncryptionVersion; +}; + +/** Params for {@link BitGoApiV1Wallets.createWalletWithKeychains}. */ +export type BitGoApiV1CreateWalletWithKeychainsParams = { + passphrase: string; + label?: string; + backupXpub?: string; + backupXpubProvider?: string; + enterprise?: string; + passcodeEncryptionCode?: string; + disableTransactionNotifications?: boolean; + disableKRSEmail?: boolean; + encryptionVersion?: EncryptionVersion; +}; + +/** Params for {@link BitGoApiV1Wallets.createForwardWallet}. */ +export type BitGoApiV1CreateForwardWalletParams = { + privKey: string; + sourceAddress: string; + destinationWallet: BitGoApiV1Wallet; + label?: string; + enterprise?: string; +}; + +/** Params for {@link BitGoApiV1Wallets.add}. */ +export type BitGoApiV1AddWalletParams = { + label?: string; + m: number; + n: number; + keychains: { xpub: string }[]; + enterprise?: string; + disableTransactionNotifications?: boolean; +}; + +/** Params for {@link BitGoApiV1Wallets.remove}. */ +export type BitGoApiV1RemoveWalletParams = { + id: string; +}; + +/** + * **Deprecated v1** wallet collection facade returned by + * {@link BitGoBase.wallets} / `BitGoAPI.wallets()`. + * + * Source of truth: `modules/sdk-api/src/v1/wallets.ts` (CommonJS prototype). + * + * | Accessor | Type | API | + * | --- | --- | --- | + * | `bitgo.wallets()` | {@link BitGoApiV1Wallets} | **v1** (this type) | + * | `bitgo.coin(name).wallets()` | {@link IWallets} | **v2** (not this type) | + * + * Replaces the previous `wallets(): any` on {@link BitGoBase}. + * + * @deprecated Prefer `bitgo.coin(coinName).wallets()` ({@link IWallets}). + */ +export type BitGoApiV1Wallets = { + /** Owning BitGo client (v1 surface only; see {@link BitGoApiV1BitGo}). */ + bitgo: BitGoApiV1BitGo; + list(params?: BitGoApiV1ListWalletsParams, callback?: BitGoApiV1Callback): Promise; + /** + * Returns a CommonJS v1 Wallet instance. + * Typed as `any` until `sdk-api/src/v1/wallet.ts` is fully typed (call sites + * use `.recover` / `.sweep` / local `WalletV1` shapes). + */ + getWallet(params: BitGoApiV1GetWalletParams, callback?: BitGoApiV1Callback): Promise; + /** Shorthand for {@link BitGoApiV1Wallets.getWallet}. */ + get(params: BitGoApiV1GetWalletParams, callback?: BitGoApiV1Callback): Promise; + listInvites(params?: Record, callback?: BitGoApiV1Callback): Promise; + cancelInvite(params: BitGoApiV1WalletInviteParams, callback?: BitGoApiV1Callback): Promise; + listShares(params?: Record, callback?: BitGoApiV1Callback): Promise; + resendShareInvite(params: BitGoApiV1WalletShareParams, callback?: BitGoApiV1Callback): Promise; + getShare(params: BitGoApiV1WalletShareParams, callback?: BitGoApiV1Callback): Promise; + updateShare(params: BitGoApiV1WalletShareParams, callback?: BitGoApiV1Callback): Promise; + cancelShare(params: BitGoApiV1WalletShareParams, callback?: BitGoApiV1Callback): Promise; + acceptShare(params: BitGoApiV1WalletShareParams, callback?: BitGoApiV1Callback): Promise; + createKey(params?: Record): { address: string; key: string }; + createWalletWithKeychains( + params: BitGoApiV1CreateWalletWithKeychainsParams, + callback?: BitGoApiV1Callback + ): Promise; + createForwardWallet(params: BitGoApiV1CreateForwardWalletParams, callback?: BitGoApiV1Callback): Promise; + /** Returns a CommonJS v1 Wallet instance (`any` — see {@link BitGoApiV1Wallets.getWallet}). */ + add(params: BitGoApiV1AddWalletParams, callback?: BitGoApiV1Callback): Promise; + remove(params: BitGoApiV1RemoveWalletParams, callback?: BitGoApiV1Callback): Promise; +};