Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions modules/sdk-core/src/bitgo/wallet/iWallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,11 @@ export interface ForwarderBalanceOptions {
maximumBalance?: number;
}

export interface GetAccountResourcesOptions {
addresses: string[];
assetName?: string;
}

export type CreateAddressFormat = 'base58' | 'cashaddr';

export interface CreateAddressOptions {
Expand Down Expand Up @@ -988,6 +993,7 @@ export interface IWallet {
getAddress(params?: GetAddressOptions): Promise<any>;
createAddress(params?: CreateAddressOptions): Promise<any>;
updateAddress(params?: UpdateAddressOptions): Promise<any>;
getAccountResources(params: GetAccountResourcesOptions): Promise<any>;
listWebhooks(params?: PaginationOptions): Promise<any>;
simulateWebhook(params?: SimulateWebhookOptions): Promise<any>;
addWebhook(params?: ModifyWebhookOptions): Promise<any>;
Expand Down
25 changes: 25 additions & 0 deletions modules/sdk-core/src/bitgo/wallet/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ import {
WalletType,
BuildTokenApprovalResponse,
WalletInitResult,
GetAccountResourcesOptions,
} from './iWallet';

const debug = require('debug')('bitgo:v2:wallet');
Expand Down Expand Up @@ -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<any>} - response from WP API
*/
async getAccountResources(params: GetAccountResourcesOptions): Promise<any> {
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<unknown> {
common.validateParams(params, [], ['minFeeRate', 'changeAddressType', 'txFormat']);
return this.updateWallet({
Expand Down
114 changes: 114 additions & 0 deletions modules/sdk-core/test/unit/bitgo/wallet/getAccountResources.ts
Original file line number Diff line number Diff line change
@@ -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');
});
});
});
Loading