Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Balance] fetch historical balance #147

Merged
merged 20 commits into from
Aug 12, 2024
Merged
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
10 changes: 8 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
# Coinbase Node.js SDK Changelog

## [0.0.15]
## [0.0.16]

### Added
### Added

- Add Function `listHistoricalBalances` for `Address` for fetching historical balances for an asset

## [0.0.15]

### Added

- USD value conversion details to the StakingReward object
- Gasless USDC Sends
Expand Down
27 changes: 25 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

75 changes: 74 additions & 1 deletion src/coinbase/address.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@ import { Asset } from "./asset";
import { Balance } from "./balance";
import { BalanceMap } from "./balance_map";
import { FaucetTransaction } from "./faucet_transaction";
import { Amount, StakeOptionsMode } from "./types";
import { HistoricalBalance } from "./historical_balance";
import {
Amount,
StakeOptionsMode,
ListHistoricalBalancesResult,
ListHistoricalBalancesOptions,
} from "./types";
import { formatDate, getWeekBackDate } from "./utils";
import { StakingRewardFormat } from "../client";
import { StakingReward } from "./staking_reward";
Expand All @@ -13,6 +19,8 @@ import { StakingReward } from "./staking_reward";
* A representation of a blockchain address, which is a user-controlled account on a network.
*/
export class Address {
private static MAX_HISTORICAL_BALANCE = 1000;

protected networkId: string;
protected id: string;

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

/**
* Returns the historical balances of the provided asset.
*
* @param options - The options to list historical balances.
* @param options.assetId - The asset ID.
* @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.
* @param options.page - A cursor for pagination across multiple pages of results. Don\'t include this parameter on the first call. Use the next_page value returned in a previous response to request subsequent results.
* @returns The list of historical balance of the asset and next page token.
*/
public async listHistoricalBalances({
assetId,
limit,
page,
}: ListHistoricalBalancesOptions): Promise<ListHistoricalBalancesResult> {
const historyList: HistoricalBalance[] = [];

if (limit !== undefined) {
const response = await Coinbase.apiClients.externalAddress!.listAddressHistoricalBalance(
this.getNetworkId(),
this.getId(),
Asset.primaryDenomination(assetId),
limit,
page ? page : undefined,
);

response.data.data.forEach(historicalBalanceModel => {
const historicalBalance = HistoricalBalance.fromModel(historicalBalanceModel);
historyList.push(historicalBalance);
});

return {
historicalBalances: historyList,
nextPageToken: response.data.next_page,
};
}

const queue: string[] = [""];
while (queue.length > 0 && historyList.length < Address.MAX_HISTORICAL_BALANCE) {
const page = queue.shift();
const response = await Coinbase.apiClients.externalAddress!.listAddressHistoricalBalance(
this.getNetworkId(),
this.getId(),
Asset.primaryDenomination(assetId),
100,
page ? page : undefined,
);

response.data.data.forEach(historicalBalanceModel => {
const historicalBalance = HistoricalBalance.fromModel(historicalBalanceModel);
historyList.push(historicalBalance);
});

if (response.data.has_more) {
if (response.data.next_page) {
queue.push(response.data.next_page);
}
}
}

return {
historicalBalances: historyList,
nextPageToken: "",
};
}

/**
* Lists the staking rewards for the address.
*
Expand Down
44 changes: 44 additions & 0 deletions src/coinbase/historical_balance.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import Decimal from "decimal.js";
import { HistoricalBalance as HistoricalBalanceModel } from "../client";
import { Asset } from "./asset";

/** A representation of historical balance. */
export class HistoricalBalance {
public readonly amount: Decimal;
public readonly blockHash: string;
public readonly blockHeight: Decimal;
public readonly asset: Asset;

/**
* Private constructor to prevent direct instantiation outside of the factory methods.
*
* @ignore
* @param {Decimal} amount - The amount of the balance.
* @param {Decimal} blockHeight - The block height at which the balance was recorded.
* @param {string} blockHash - The block hash at which the balance was recorded
* @param {string} asset - The asset we want to fetch.
* @hideconstructor
*/
private constructor(amount: Decimal, blockHeight: Decimal, blockHash: string, asset: Asset) {
this.amount = amount;
this.blockHeight = blockHeight;
this.blockHash = blockHash;
this.asset = asset;
}

/**
* Converts a HistoricalBalanceModel into a HistoricalBalance object.
*
* @param {HistoricalBalanceModel} model - The historical balance model object.
* @returns {HistoricalBalance} The HistoricalBalance object.
*/
public static fromModel(model: HistoricalBalanceModel): HistoricalBalance {
const asset = Asset.fromModel(model.asset);
return new HistoricalBalance(
asset.fromAtomicAmount(new Decimal(model.amount)),
new Decimal(model.block_height),
model.block_hash,
asset,
);
}
}
40 changes: 40 additions & 0 deletions src/coinbase/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
Address as AddressModel,
AddressList,
AddressBalanceList,
AddressHistoricalBalanceList,
Balance,
CreateAddressRequest,
CreateWalletRequest,
Expand Down Expand Up @@ -34,6 +35,7 @@ import {
} from "./../client/api";
import { Address } from "./address";
import { Wallet } from "./wallet";
import { HistoricalBalance } from "./historical_balance";

export type AssetAPIClient = {
/**
Expand Down Expand Up @@ -334,6 +336,27 @@ export type ExternalAddressAPIClient = {
options?: RawAxiosRequestConfig,
): AxiosPromise<Balance>;

/**
* List the historical balance of an asset in a specific address.
*
* @summary Get address balance history for asset
* @param networkId - The ID of the blockchain network
* @param addressId - The ID of the address to fetch the historical balance for.
* @param assetId - The symbol of the asset to fetch the historical balance for.
* @param limit - A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 10.
* @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.
* @param options - Override http request option.
* @throws {RequiredError}
*/
listAddressHistoricalBalance(
networkId: string,
addressId: string,
assetId: string,
limit?: number,
page?: string,
options?: RawAxiosRequestConfig,
): AxiosPromise<AddressHistoricalBalanceList>;

/**
* Request faucet funds to be sent to external address.
*
Expand Down Expand Up @@ -770,3 +793,20 @@ export type CreateTradeOptions = {
timeoutSeconds?: number;
intervalSeconds?: number;
};

/**
* Options for listing historical balances of an address.
*/
export type ListHistoricalBalancesOptions = {
assetId: string;
limit?: number;
page?: string;
};

/**
* Result of ListHistoricalBalances.
*/
export type ListHistoricalBalancesResult = {
historicalBalances: HistoricalBalance[];
nextPageToken: string;
};
Loading
Loading