From 2c533ce38bcef40cd229a624771a3f6a3339bfcc Mon Sep 17 00:00:00 2001 From: Bhavi Dhingra Date: Thu, 19 Feb 2026 19:43:44 +0530 Subject: [PATCH] feat(sdk-core): add getAccountResources() in wallet TICKET: CHALO-206 --- modules/sdk-core/src/bitgo/wallet/iWallet.ts | 6 + modules/sdk-core/src/bitgo/wallet/wallet.ts | 25 ++++ .../unit/bitgo/wallet/getAccountResources.ts | 114 ++++++++++++++++++ 3 files changed, 145 insertions(+) create mode 100644 modules/sdk-core/test/unit/bitgo/wallet/getAccountResources.ts diff --git a/modules/sdk-core/src/bitgo/wallet/iWallet.ts b/modules/sdk-core/src/bitgo/wallet/iWallet.ts index 750bb80224..f0cd202046 100644 --- a/modules/sdk-core/src/bitgo/wallet/iWallet.ts +++ b/modules/sdk-core/src/bitgo/wallet/iWallet.ts @@ -539,6 +539,11 @@ export interface ForwarderBalanceOptions { maximumBalance?: number; } +export interface GetAccountResourcesOptions { + addresses: string[]; + assetName?: string; +} + export type CreateAddressFormat = 'base58' | 'cashaddr'; export interface CreateAddressOptions { @@ -988,6 +993,7 @@ export interface IWallet { getAddress(params?: GetAddressOptions): Promise; createAddress(params?: CreateAddressOptions): Promise; updateAddress(params?: UpdateAddressOptions): Promise; + getAccountResources(params: GetAccountResourcesOptions): Promise; listWebhooks(params?: PaginationOptions): Promise; simulateWebhook(params?: SimulateWebhookOptions): Promise; addWebhook(params?: ModifyWebhookOptions): Promise; diff --git a/modules/sdk-core/src/bitgo/wallet/wallet.ts b/modules/sdk-core/src/bitgo/wallet/wallet.ts index de1a4386c2..c2bf7815fe 100644 --- a/modules/sdk-core/src/bitgo/wallet/wallet.ts +++ b/modules/sdk-core/src/bitgo/wallet/wallet.ts @@ -125,6 +125,7 @@ import { WalletType, BuildTokenApprovalResponse, WalletInitResult, + GetAccountResourcesOptions, } from './iWallet'; const debug = require('debug')('bitgo:v2:wallet'); @@ -1465,6 +1466,30 @@ export class Wallet implements IWallet { return this.bitgo.put(url).send(putParams).result(); } + /** + * Get account resources for the given addresses + * @param params - options object containing addresses and optional assetName + * @returns {Promise} - response from WP API + */ + async getAccountResources(params: GetAccountResourcesOptions): Promise { + const { addresses, assetName } = params; + + if (!Array.isArray(addresses)) { + throw new Error('addresses must be an array'); + } + + if (addresses.length === 0) { + throw new Error('addresses array cannot be empty'); + } + + const query: any = { addresses }; + if (assetName) { + query.assetName = assetName; + } + + return this.bitgo.get(this.url('/accountResources')).query(query).result(); + } + async updateWalletBuildDefaults(params: UpdateBuildDefaultOptions): Promise { common.validateParams(params, [], ['minFeeRate', 'changeAddressType', 'txFormat']); return this.updateWallet({ diff --git a/modules/sdk-core/test/unit/bitgo/wallet/getAccountResources.ts b/modules/sdk-core/test/unit/bitgo/wallet/getAccountResources.ts new file mode 100644 index 0000000000..560c67ebea --- /dev/null +++ b/modules/sdk-core/test/unit/bitgo/wallet/getAccountResources.ts @@ -0,0 +1,114 @@ +import * as assert from 'assert'; +import * as sinon from 'sinon'; +import 'should'; +import { Wallet } from '../../../../src/bitgo/wallet/wallet'; + +describe('Wallet - getAccountResources', function () { + let wallet: Wallet; + let mockBitGo: any; + let mockBaseCoin: any; + let mockWalletData: any; + + beforeEach(function () { + mockBitGo = { + get: sinon.stub(), + }; + + mockBaseCoin = { + url: sinon.stub().returns('/test/coin'), + }; + + mockWalletData = { + id: 'test-wallet-id', + keys: ['user-key', 'backup-key', 'bitgo-key'], + }; + + wallet = new Wallet(mockBitGo, mockBaseCoin, mockWalletData); + }); + + afterEach(function () { + sinon.restore(); + }); + + describe('getAccountResources', function () { + it('should call WP API with addresses parameter', async function () { + const mockResponse = { + resources: [ + { address: 'address1', balance: 100 }, + { address: 'address2', balance: 200 }, + ], + }; + + mockBitGo.get.returns({ + query: sinon.stub().returns({ + result: sinon.stub().resolves(mockResponse), + }), + }); + + const addresses = ['address1', 'address2']; + const result = await wallet.getAccountResources({ addresses }); + + result.should.deepEqual(mockResponse); + mockBitGo.get.should.have.been.calledOnce; + const queryStub = mockBitGo.get.returnValues[0].query; + queryStub.should.have.been.calledWith({ addresses }); + }); + + it('should call WP API with addresses and assetName parameters', async function () { + const mockResponse = { + resources: [{ address: 'address1', balance: 100, token: 'USDT' }], + }; + + mockBitGo.get.returns({ + query: sinon.stub().returns({ + result: sinon.stub().resolves(mockResponse), + }), + }); + + const addresses = ['address1']; + const assetName = 'USDT'; + const result = await wallet.getAccountResources({ addresses, assetName }); + + result.should.deepEqual(mockResponse); + mockBitGo.get.should.have.been.calledOnce; + const queryStub = mockBitGo.get.returnValues[0].query; + queryStub.should.have.been.calledWith({ addresses, assetName }); + }); + + it('should throw error if addresses is not an array', async function () { + try { + await wallet.getAccountResources({ addresses: 'not-an-array' as any }); + assert.fail('Should have thrown error'); + } catch (error) { + error.message.should.equal('addresses must be an array'); + } + }); + + it('should throw error if addresses array is empty', async function () { + try { + await wallet.getAccountResources({ addresses: [] }); + assert.fail('Should have thrown error'); + } catch (error) { + error.message.should.equal('addresses array cannot be empty'); + } + }); + + it('should not include assetName in query if not provided', async function () { + const mockResponse = { resources: [] }; + + mockBitGo.get.returns({ + query: sinon.stub().returns({ + result: sinon.stub().resolves(mockResponse), + }), + }); + + const addresses = ['address1']; + await wallet.getAccountResources({ addresses }); + + const queryStub = mockBitGo.get.returnValues[0].query; + const queryArg = queryStub.firstCall.args[0]; + queryArg.should.deepEqual({ addresses }); + queryArg.should.not.have.property('assetName'); + }); + }); +});