Skip to content

Commit

Permalink
Staker data aggregated by period (#158)
Browse files Browse the repository at this point in the history
* Staker data aggregated by period

* Documentation update
  • Loading branch information
bobo-k2 authored Jul 11, 2024
1 parent 722a537 commit d64d7b6
Show file tree
Hide file tree
Showing 4 changed files with 204 additions and 0 deletions.
68 changes: 68 additions & 0 deletions public/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -1214,6 +1214,74 @@
}
}
},
"/api/v3/{network}/dapps-staking/staker-aggregated/{address}": {
"get": {
"tags": [
"Dapps Staking"
],
"description": "Retrieves aggregated period data for the given staker containing all stakes and rewards per period.",
"parameters": [
{
"name": "network",
"in": "path",
"required": true,
"type": "string",
"description": "The network name. Supported networks: astar",
"enum": [
"astar",
"shiden",
"shibuya"
]
},
{
"name": "address",
"in": "path",
"required": true,
"type": "string",
"description": "Staker address."
}
],
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/v3/{network}/dapps-staking/staker-aggregated-total/{address}": {
"get": {
"tags": [
"Dapps Staking"
],
"description": "Retrieves aggregated period data for the given staker containing sum of all rewards claimed and the current period stake.",
"parameters": [
{
"name": "network",
"in": "path",
"required": true,
"type": "string",
"description": "The network name. Supported networks: astar",
"enum": [
"astar",
"shiden",
"shibuya"
]
},
{
"name": "address",
"in": "path",
"required": true,
"type": "string",
"description": "Staker address."
}
],
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/v1/{network}/node/tx-perblock/total": {
"get": {
"tags": [
Expand Down
60 changes: 60 additions & 0 deletions src/controllers/DappsStakingV3Controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -438,5 +438,65 @@ export class DappsStakingV3Controller extends ControllerBase implements IControl
}
},
);

app.route('/api/v3/:network/dapps-staking/staker-aggregated/:address').get(
async (req: Request, res: Response) => {
/*
#swagger.description = 'Retrieves aggregated period data for the given staker containing all stakes and rewards per period.'
#swagger.tags = ['Dapps Staking']
#swagger.parameters['network'] = {
in: 'path',
description: 'The network name. Supported networks: astar',
required: true,
enum: ['astar', 'shiden', 'shibuya']
}
#swagger.parameters['address'] = {
in: 'path',
description: 'Staker address.',
required: true,
}
*/
try {
res.json(
await this._dappsStakingEvents.getAggregatedStakerData(
req.params.network as NetworkType,
req.params.address,
),
);
} catch (err) {
this.handleError(res, err as Error);
}
},
);

app.route('/api/v3/:network/dapps-staking/staker-aggregated-total/:address').get(
async (req: Request, res: Response) => {
/*
#swagger.description = 'Retrieves aggregated period data for the given staker containing sum of all rewards claimed and the current period stake.'
#swagger.tags = ['Dapps Staking']
#swagger.parameters['network'] = {
in: 'path',
description: 'The network name. Supported networks: astar',
required: true,
enum: ['astar', 'shiden', 'shibuya']
}
#swagger.parameters['address'] = {
in: 'path',
description: 'Staker address.',
required: true,
}
*/
try {
res.json(
await this._dappsStakingEvents.getTotalAggregatedStakerData(
req.params.network as NetworkType,
req.params.address,
),
);
} catch (err) {
this.handleError(res, err as Error);
}
},
);
}
}
15 changes: 15 additions & 0 deletions src/services/DappStaking/ResponseData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,18 @@ export type PeriodDataResponse = {
rewardAmount: bigint;
stakeAmount: bigint;
};

export type StakerPeriodDataResponse = {
stakerAddress: string;
period: number;
stakerRewardAmount: bigint;
bonusRewardAmount: bigint;
stakeAmount: bigint;
};

export type StakerPeriodTotalResponse = {
stakerAddress: string;
totalBonusRewardsClaimed: bigint;
totalStakerRewardsClaimed: bigint;
currentStake: bigint;
};
61 changes: 61 additions & 0 deletions src/services/DappsStakingEvents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import {
DappStakingAggregatedData,
DappStakingAggregatedResponse,
PeriodDataResponse,
StakerPeriodDataResponse,
StakerPeriodTotalResponse,
} from './DappStaking/ResponseData';
import { IStatsIndexerService } from './StatsIndexerService';

Expand All @@ -37,6 +39,8 @@ export interface IDappsStakingEvents {
getDappStakingRewardsAggregated(network: NetworkType, address: string, period: PeriodType): Promise<Pair[]>;
getDappStakingStakersList(network: NetworkType, contractAddress: string): Promise<List[]>;
getAggregatedPeriodData(network: NetworkType, period: number): Promise<PeriodDataResponse[]>;
getAggregatedStakerData(network: NetworkType, stakerAddress: string): Promise<StakerPeriodDataResponse[]>;
getTotalAggregatedStakerData(network: NetworkType, stakerAddress: string): Promise<StakerPeriodTotalResponse>;
}

export type RewardEventType = 'Reward' | 'BonusReward' | 'DAppReward';
Expand Down Expand Up @@ -566,6 +570,63 @@ export class DappsStakingEvents extends ServiceBase implements IDappsStakingEven
}
}

public async getAggregatedStakerData(
network: NetworkType,
stakerAddress: string,
): Promise<StakerPeriodDataResponse[]> {
Guard.ThrowIfUndefined('network', network);
Guard.ThrowIfUndefined('stakerAddress', stakerAddress);
if (!['shibuya', 'shiden', 'astar'].includes(network)) {
throw new Error(`This method is not supported for the network ${network}`);
}

try {
const result = await axios.post(this.getApiUrl(network), {
query: `query {
stakesPerStakerAndPeriods(where: {stakerAddress_eq: "${stakerAddress}"}) {
stakerAddress
period
stakeAmount
stakerRewardAmount
bonusRewardAmount
}
}`,
});

return result.data.data.stakesPerStakerAndPeriods;
} catch (e) {
console.error(e);
return [];
}
}

public async getTotalAggregatedStakerData(
network: NetworkType,
stakerAddress: string,
): Promise<StakerPeriodTotalResponse> {
const data = await this.getAggregatedStakerData(network, stakerAddress);
let maxPeriod = -1;
const total = data.reduce(
(acc, item) => {
if (item.period > maxPeriod) {
acc.currentStake = BigInt(item.stakeAmount);
maxPeriod = item.period;
}
acc.totalStakerRewardsClaimed += BigInt(item.stakerRewardAmount);
acc.totalBonusRewardsClaimed += BigInt(item.bonusRewardAmount);
return acc;
},
{
currentStake: BigInt(0),
totalBonusRewardsClaimed: BigInt(0),
totalStakerRewardsClaimed: BigInt(0),
stakerAddress,
},
);

return total;
}

private getApiUrl(network: NetworkType): string {
// For local development: `http://localhost:4350/graphql`;
return ['astar', 'shiden', 'shibuya'].includes(network)
Expand Down

0 comments on commit d64d7b6

Please sign in to comment.