Skip to content

Commit e38d836

Browse files
[Balance] fetch historical balance (#147)
* [chore] Update package-lock.json (#132) * [Balance] fetch historical balance * formatting * fix lint * add max size for fetching all history * rebase error * tweak naming * address comments * move list historical balance test under address * address comment * fix lint * fix IDE change * update changelog * add struct for ListHistoricalBalancesOptions * fix format * fix lint * change log version * address comments --------- Co-authored-by: John Peterson <[email protected]>
1 parent 23d4d80 commit e38d836

File tree

10 files changed

+3295
-2903
lines changed

10 files changed

+3295
-2903
lines changed

CHANGELOG.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
# Coinbase Node.js SDK Changelog
22

3-
## [0.0.15]
3+
## [0.0.16]
44

5-
### Added
5+
### Added
6+
7+
- Add Function `listHistoricalBalances` for `Address` for fetching historical balances for an asset
8+
9+
## [0.0.15]
10+
11+
### Added
612

713
- USD value conversion details to the StakingReward object
814
- Gasless USDC Sends

package-lock.json

Lines changed: 25 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/coinbase/address.ts

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,13 @@ import { Asset } from "./asset";
44
import { Balance } from "./balance";
55
import { BalanceMap } from "./balance_map";
66
import { FaucetTransaction } from "./faucet_transaction";
7-
import { Amount, StakeOptionsMode } from "./types";
7+
import { HistoricalBalance } from "./historical_balance";
8+
import {
9+
Amount,
10+
StakeOptionsMode,
11+
ListHistoricalBalancesResult,
12+
ListHistoricalBalancesOptions,
13+
} from "./types";
814
import { formatDate, getWeekBackDate } from "./utils";
915
import { StakingRewardFormat } from "../client";
1016
import { StakingReward } from "./staking_reward";
@@ -13,6 +19,8 @@ import { StakingReward } from "./staking_reward";
1319
* A representation of a blockchain address, which is a user-controlled account on a network.
1420
*/
1521
export class Address {
22+
private static MAX_HISTORICAL_BALANCE = 1000;
23+
1624
protected networkId: string;
1725
protected id: string;
1826

@@ -79,6 +87,71 @@ export class Address {
7987
return Balance.fromModelAndAssetId(response.data, assetId).amount;
8088
}
8189

90+
/**
91+
* Returns the historical balances of the provided asset.
92+
*
93+
* @param options - The options to list historical balances.
94+
* @param options.assetId - The asset ID.
95+
* @param options.limit - A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 10.
96+
* @param options.page - A cursor for pagination across multiple pages of results. Don\&#39;t include this parameter on the first call. Use the next_page value returned in a previous response to request subsequent results.
97+
* @returns The list of historical balance of the asset and next page token.
98+
*/
99+
public async listHistoricalBalances({
100+
assetId,
101+
limit,
102+
page,
103+
}: ListHistoricalBalancesOptions): Promise<ListHistoricalBalancesResult> {
104+
const historyList: HistoricalBalance[] = [];
105+
106+
if (limit !== undefined) {
107+
const response = await Coinbase.apiClients.externalAddress!.listAddressHistoricalBalance(
108+
this.getNetworkId(),
109+
this.getId(),
110+
Asset.primaryDenomination(assetId),
111+
limit,
112+
page ? page : undefined,
113+
);
114+
115+
response.data.data.forEach(historicalBalanceModel => {
116+
const historicalBalance = HistoricalBalance.fromModel(historicalBalanceModel);
117+
historyList.push(historicalBalance);
118+
});
119+
120+
return {
121+
historicalBalances: historyList,
122+
nextPageToken: response.data.next_page,
123+
};
124+
}
125+
126+
const queue: string[] = [""];
127+
while (queue.length > 0 && historyList.length < Address.MAX_HISTORICAL_BALANCE) {
128+
const page = queue.shift();
129+
const response = await Coinbase.apiClients.externalAddress!.listAddressHistoricalBalance(
130+
this.getNetworkId(),
131+
this.getId(),
132+
Asset.primaryDenomination(assetId),
133+
100,
134+
page ? page : undefined,
135+
);
136+
137+
response.data.data.forEach(historicalBalanceModel => {
138+
const historicalBalance = HistoricalBalance.fromModel(historicalBalanceModel);
139+
historyList.push(historicalBalance);
140+
});
141+
142+
if (response.data.has_more) {
143+
if (response.data.next_page) {
144+
queue.push(response.data.next_page);
145+
}
146+
}
147+
}
148+
149+
return {
150+
historicalBalances: historyList,
151+
nextPageToken: "",
152+
};
153+
}
154+
82155
/**
83156
* Lists the staking rewards for the address.
84157
*

src/coinbase/historical_balance.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import Decimal from "decimal.js";
2+
import { HistoricalBalance as HistoricalBalanceModel } from "../client";
3+
import { Asset } from "./asset";
4+
5+
/** A representation of historical balance. */
6+
export class HistoricalBalance {
7+
public readonly amount: Decimal;
8+
public readonly blockHash: string;
9+
public readonly blockHeight: Decimal;
10+
public readonly asset: Asset;
11+
12+
/**
13+
* Private constructor to prevent direct instantiation outside of the factory methods.
14+
*
15+
* @ignore
16+
* @param {Decimal} amount - The amount of the balance.
17+
* @param {Decimal} blockHeight - The block height at which the balance was recorded.
18+
* @param {string} blockHash - The block hash at which the balance was recorded
19+
* @param {string} asset - The asset we want to fetch.
20+
* @hideconstructor
21+
*/
22+
private constructor(amount: Decimal, blockHeight: Decimal, blockHash: string, asset: Asset) {
23+
this.amount = amount;
24+
this.blockHeight = blockHeight;
25+
this.blockHash = blockHash;
26+
this.asset = asset;
27+
}
28+
29+
/**
30+
* Converts a HistoricalBalanceModel into a HistoricalBalance object.
31+
*
32+
* @param {HistoricalBalanceModel} model - The historical balance model object.
33+
* @returns {HistoricalBalance} The HistoricalBalance object.
34+
*/
35+
public static fromModel(model: HistoricalBalanceModel): HistoricalBalance {
36+
const asset = Asset.fromModel(model.asset);
37+
return new HistoricalBalance(
38+
asset.fromAtomicAmount(new Decimal(model.amount)),
39+
new Decimal(model.block_height),
40+
model.block_hash,
41+
asset,
42+
);
43+
}
44+
}

src/coinbase/types.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
Address as AddressModel,
55
AddressList,
66
AddressBalanceList,
7+
AddressHistoricalBalanceList,
78
Balance,
89
CreateAddressRequest,
910
CreateWalletRequest,
@@ -34,6 +35,7 @@ import {
3435
} from "./../client/api";
3536
import { Address } from "./address";
3637
import { Wallet } from "./wallet";
38+
import { HistoricalBalance } from "./historical_balance";
3739

3840
export type AssetAPIClient = {
3941
/**
@@ -334,6 +336,27 @@ export type ExternalAddressAPIClient = {
334336
options?: RawAxiosRequestConfig,
335337
): AxiosPromise<Balance>;
336338

339+
/**
340+
* List the historical balance of an asset in a specific address.
341+
*
342+
* @summary Get address balance history for asset
343+
* @param networkId - The ID of the blockchain network
344+
* @param addressId - The ID of the address to fetch the historical balance for.
345+
* @param assetId - The symbol of the asset to fetch the historical balance for.
346+
* @param limit - A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 10.
347+
* @param page - A cursor for pagination across multiple pages of results. Don\&#39;t include this parameter on the first call. Use the next_page value returned in a previous response to request subsequent results.
348+
* @param options - Override http request option.
349+
* @throws {RequiredError}
350+
*/
351+
listAddressHistoricalBalance(
352+
networkId: string,
353+
addressId: string,
354+
assetId: string,
355+
limit?: number,
356+
page?: string,
357+
options?: RawAxiosRequestConfig,
358+
): AxiosPromise<AddressHistoricalBalanceList>;
359+
337360
/**
338361
* Request faucet funds to be sent to external address.
339362
*
@@ -770,3 +793,20 @@ export type CreateTradeOptions = {
770793
timeoutSeconds?: number;
771794
intervalSeconds?: number;
772795
};
796+
797+
/**
798+
* Options for listing historical balances of an address.
799+
*/
800+
export type ListHistoricalBalancesOptions = {
801+
assetId: string;
802+
limit?: number;
803+
page?: string;
804+
};
805+
806+
/**
807+
* Result of ListHistoricalBalances.
808+
*/
809+
export type ListHistoricalBalancesResult = {
810+
historicalBalances: HistoricalBalance[];
811+
nextPageToken: string;
812+
};

0 commit comments

Comments
 (0)