From d2862993760a7c83a4948a47056173d77624ae9a 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 --- examples/ts/trx/get-account-resources.ts | 40 ++++++ modules/sdk-core/src/bitgo/wallet/iWallet.ts | 36 ++++++ modules/sdk-core/src/bitgo/wallet/wallet.ts | 26 ++++ .../unit/bitgo/wallet/getAccountResources.ts | 115 ++++++++++++++++++ 4 files changed, 217 insertions(+) create mode 100644 examples/ts/trx/get-account-resources.ts create mode 100644 modules/sdk-core/test/unit/bitgo/wallet/getAccountResources.ts diff --git a/examples/ts/trx/get-account-resources.ts b/examples/ts/trx/get-account-resources.ts new file mode 100644 index 0000000000..01fa1973bf --- /dev/null +++ b/examples/ts/trx/get-account-resources.ts @@ -0,0 +1,40 @@ +/** + * Get account resources for a Tron wallet at BitGo. + * + * This tool will help you see how to use the BitGo API to easily get + * account resources information for a wallet. + * + * Copyright 2026, BitGo, Inc. All Rights Reserved. + */ +import { BitGo } from 'bitgo'; + +// TODO: change to 'production' for mainnet +const env = 'test'; +const bitgo = new BitGo({ env }); + +// TODO: change to 'trx' for mainnet or 'ttrx:' for testnet token +const coin = 'ttrx'; + +// TODO: set your wallet id +const walletId = ''; + +// TODO: set your access token here +// You can get this from User Settings > Developer Options > Add Access Token +const accessToken = ''; + +// TODO: set the addresses to query +// Note: To get energy deficit for a token transfer, make sure the token exists in the address. +const addresses = ['']; + +async function main() { + bitgo.authenticateWithAccessToken({ accessToken }); + + const wallet = await bitgo.coin(coin).wallets().getWallet({ id: walletId }); + + console.log('Wallet ID:', wallet.id()); + + const resources = await wallet.getAccountResources({ addresses }); + console.log('Account Resources:', JSON.stringify(resources, null, 2)); +} + +main().catch((e) => console.error(e)); diff --git a/modules/sdk-core/src/bitgo/wallet/iWallet.ts b/modules/sdk-core/src/bitgo/wallet/iWallet.ts index 750bb80224..e63de68695 100644 --- a/modules/sdk-core/src/bitgo/wallet/iWallet.ts +++ b/modules/sdk-core/src/bitgo/wallet/iWallet.ts @@ -539,6 +539,41 @@ export interface ForwarderBalanceOptions { maximumBalance?: number; } +export interface GetAccountResourcesOptions { + addresses: string[]; + destinationAddress?: string; +} + +export interface AccountResourceInfo { + address: string; + free_bandwidth_available: number; + free_bandwidth_used: number; + staked_bandwidth_available: number; + staked_bandwidth_used: number; + energy_available: number; + energy_used: number; + resourceDeficitForAssetTransfer?: { + bandwidthDeficit: number; + bandwidthSunRequired: string; + energyDeficit?: number; + energySunRequired?: string; + }; + maxResourcesDelegatable?: { + bandwidthWeight: string; + energyWeight: string; + }; +} + +export interface FailedAddressInfo { + address: string; + error: string; +} + +export interface GetAccountResourcesResponse { + resources: AccountResourceInfo[]; + failedAddresses: FailedAddressInfo[]; +} + export type CreateAddressFormat = 'base58' | 'cashaddr'; export interface CreateAddressOptions { @@ -988,6 +1023,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..a747492deb 100644 --- a/modules/sdk-core/src/bitgo/wallet/wallet.ts +++ b/modules/sdk-core/src/bitgo/wallet/wallet.ts @@ -125,6 +125,8 @@ import { WalletType, BuildTokenApprovalResponse, WalletInitResult, + GetAccountResourcesOptions, + GetAccountResourcesResponse, } from './iWallet'; const debug = require('debug')('bitgo:v2:wallet'); @@ -1465,6 +1467,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 destinationAddress + * @returns {Promise} - response from WP API + */ + async getAccountResources(params: GetAccountResourcesOptions): Promise { + const { addresses, destinationAddress } = 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: GetAccountResourcesOptions = { addresses }; + if (destinationAddress) { + query.destinationAddress = destinationAddress; + } + + return this.bitgo.get(this.url('/getAccountResources')).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..56d3c646aa --- /dev/null +++ b/modules/sdk-core/test/unit/bitgo/wallet/getAccountResources.ts @@ -0,0 +1,115 @@ +import * as assert from 'assert'; +import * as sinon from 'sinon'; +import 'should'; +import { Wallet } from '../../../../src'; + +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'), + supportsTss: sinon.stub().returns(false), + }; + + 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); + sinon.assert.calledOnce(mockBitGo.get); + const queryStub = mockBitGo.get.returnValues[0].query; + sinon.assert.calledWith(queryStub, { addresses }); + }); + + it('should call WP API with addresses and destinationAddress parameters', async function () { + const mockResponse = { + resources: [{ address: 'address1', balance: 100 }], + }; + + mockBitGo.get.returns({ + query: sinon.stub().returns({ + result: sinon.stub().resolves(mockResponse), + }), + }); + + const addresses = ['address1']; + const destinationAddress = 'TDestAddress123'; + const result = await wallet.getAccountResources({ addresses, destinationAddress }); + + result.should.deepEqual(mockResponse); + sinon.assert.calledOnce(mockBitGo.get); + const queryStub = mockBitGo.get.returnValues[0].query; + sinon.assert.calledWith(queryStub, { addresses, destinationAddress }); + }); + + 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 destinationAddress 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('destinationAddress'); + }); + }); +});