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

Total token issuance history endpoint #165

Merged
merged 2 commits into from
Nov 27, 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
21 changes: 21 additions & 0 deletions public/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,27 @@
}
}
},
"/api/v1/{network}/token/supply-history/": {
"get": {
"tags": [
"Token"
],
"description": "Retreives total supply history at the beginning of a new dApp staking era for a given network and period.",
"parameters": [
{
"name": "network",
"in": "path",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/v1/{network}/dapps-staking/apr": {
"get": {
"tags": [
Expand Down
17 changes: 17 additions & 0 deletions src/controllers/TokenStatsController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,5 +243,22 @@ export class TokenStatsController extends ControllerBase implements IControllerB
*/
res.json(await this._indexerService.getHolders(req.params.network as NetworkType));
});

/**
* @description Total issuance history.
*/
app.route('/api/v1/:network/token/supply-history/').get(async (req: Request, res: Response) => {
/*
#swagger.description = 'Retreives total supply history at the beginning of a new dApp staking era for a given network and period.'
#swagger.tags = ['Token']
#swagger.parameters['network'] = {
in: 'path',
description: 'The network name. Supported networks: astar, shiden, shibuya'
required: true,
enum: ['astar', 'shiden', 'shibuya']
}
*/
res.json(await this._statsService.getTotalIssuanceHistory(req.params.network as NetworkType));
});
}
}
2 changes: 1 addition & 1 deletion src/services/DappStakingV3IndexerBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ export class DappStakingV3IndexerBase extends ServiceBase {

protected getApiUrl(network: NetworkType): string {
// For local development: `http://localhost:4350/graphql`;
return `https://astar-network.squids.live/dapps-staking-indexer-${network}/v/v14/graphql`;
return `https://astar-network.squids.live/dapps-staking-indexer-${network}/v/v15/graphql`;
}
}
52 changes: 42 additions & 10 deletions src/services/StatsService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,29 @@ import { NetworkType } from '../networks';
import { addressesToExclude } from './AddressesToExclude';
import { AccountData } from '../models/AccountData';
import { Guard } from '../guard';
import { DappStakingV3IndexerBase } from './DappStakingV3IndexerBase';
import axios from 'axios';

export type TotalSupply = {
block: number;
timestamp: number;
balance: bigint;
};

export interface IStatsService {
getTokenStats(network: NetworkType): Promise<TokenStats>;
getTotalSupply(network: NetworkType): Promise<number>;
getTotalIssuanceHistory(network: NetworkType): Promise<TotalSupply[]>;
}

@injectable()
/**
* Token statistics calculation service.
*/
export class StatsService implements IStatsService {
constructor(@inject(ContainerTypes.ApiFactory) private _apiFactory: IApiFactory) {}
export class StatsService extends DappStakingV3IndexerBase implements IStatsService {
constructor(@inject(ContainerTypes.ApiFactory) private _apiFactory: IApiFactory) {
super();
}

/**
* Calculates token circulation supply by substracting sum of all token holder accounts
Expand All @@ -29,7 +40,7 @@ export class StatsService implements IStatsService {
*/
public async getTokenStats(network: NetworkType): Promise<TokenStats> {
Guard.ThrowIfUndefined(network, 'network');
this.throwIfNetworkIsNotSupported(network);
this.GuardNetwork(network);

try {
const api = this._apiFactory.getApiInstance(network);
Expand All @@ -53,7 +64,7 @@ export class StatsService implements IStatsService {

public async getTotalSupply(network: NetworkType): Promise<number> {
Guard.ThrowIfUndefined(network, 'network');
this.throwIfNetworkIsNotSupported(network);
this.GuardNetwork(network);

try {
const api = this._apiFactory.getApiInstance(network);
Expand All @@ -67,6 +78,33 @@ export class StatsService implements IStatsService {
}
}

public async getTotalIssuanceHistory(network: NetworkType): Promise<TotalSupply[]> {
this.GuardNetwork(network);

try {
const result = await axios.post(this.getApiUrl(network), {
query: `query {
totalIssuances(orderBy: id_ASC) {
id
timestamp
balance
}
}`,
});

return result.data.data.totalIssuances.map((item: { id: string; timestamp: string; balance: string }) => {
return {
block: Number(item.id),
timestamp: Number(item.timestamp),
balance: BigInt(item.balance),
};
});
} catch (e) {
console.error(e);
return [];
}
}

private getTotalBalanceToExclude(balances: AccountData[]): BN {
const sum = balances
.map((balance) => {
Expand All @@ -82,10 +120,4 @@ export class StatsService implements IStatsService {

return parseInt(result.replaceAll(',', ''));
}

private throwIfNetworkIsNotSupported(network: NetworkType): void {
if (network !== 'astar' && network !== 'shiden' && network !== 'shibuya' && network !== 'rocstar') {
throw new Error(`Network ${network} is not supported.`);
}
}
}