Skip to content

Commit

Permalink
feat: browser compatible BlockfrostRewardsProvider
Browse files Browse the repository at this point in the history
  • Loading branch information
rhyslbw committed Nov 19, 2024
1 parent 4f6dced commit dd12ee6
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 183 deletions.
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
import { Cardano, Reward, RewardAccountBalanceArgs, RewardsHistoryArgs, RewardsProvider } from '@cardano-sdk/core';

import { BlockfrostProvider } from '../../util/BlockfrostProvider/BlockfrostProvider';
import {
BlockfrostClient,
BlockfrostProvider,
blockfrostToProviderError,
isBlockfrostNotFoundError
} from '../blockfrost';
import { Logger } from 'ts-log';
import { Range } from '@cardano-sdk/util';
import { blockfrostToProviderError, isBlockfrostNotFoundError } from '@cardano-sdk/cardano-services-client';
import { Responses } from '@blockfrost/blockfrost-js';

const stringToBigInt = (str: string) => BigInt(str);

export class BlockfrostRewardsProvider extends BlockfrostProvider implements RewardsProvider {
constructor(client: BlockfrostClient, logger: Logger) {
super(client, logger);
}

public async rewardAccountBalance({ rewardAccount }: RewardAccountBalanceArgs) {
try {
const accountResponse = await this.blockfrost.accounts(rewardAccount.toString());
const accountResponse = await this.request<Responses['account_content']>(`accounts/${rewardAccount.toString()}`);
return BigInt(accountResponse.withdrawable_amount);
} catch (error) {
if (isBlockfrostNotFoundError(error)) {
Expand All @@ -31,7 +41,9 @@ export class BlockfrostRewardsProvider extends BlockfrostProvider implements Rew
let page = 1;
let haveMorePages = true;
while (haveMorePages) {
const rewardsPage = await this.blockfrost.accountsRewards(stakeAddress.toString(), { count: batchSize, page });
const rewardsPage = await this.request<Responses['account_reward_content']>(
`accounts/${stakeAddress.toString()}/rewards?count=${batchSize}?page=${page}`
);

result.push(
...rewardsPage
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './BlockfrostRewardsProvider';
export * from './rewardsHttpProvider';
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import { BlockfrostClient, BlockfrostRewardsProvider } from '../../src';
import { Cardano } from '@cardano-sdk/core';
import { Responses } from '@blockfrost/blockfrost-js';
import { logger } from '@cardano-sdk/util-dev';
import { mockResponses } from '../AssetInfoProvider/util';
jest.mock('@blockfrost/blockfrost-js');

describe('blockfrostRewardsProvider', () => {
let request: jest.Mock;
let provider: BlockfrostRewardsProvider;

beforeEach(async () => {
request = jest.fn();
const client = { request } as unknown as BlockfrostClient;
provider = new BlockfrostRewardsProvider(client, logger);
});

describe('rewardAccountBalance', () => {
test('used reward account', async () => {
const mockedAccountsResponse = {
active: true,
active_epoch: 81,
controlled_amount: '95565690389731',
pool_id: 'pool1y6chk7x7fup4ms9leesdr57r4qy9cwxuee0msan72x976a6u0nc',
reserves_sum: '0',
rewards_sum: '615803862289',
stake_address: 'stake_test1uqfu74w3wh4gfzu8m6e7j987h4lq9r3t7ef5gaw497uu85qsqfy27',
treasury_sum: '0',
withdrawable_amount: '615803862289',
withdrawals_sum: '0'
};
mockResponses(request, [
['accounts/stake_test1uqfu74w3wh4gfzu8m6e7j987h4lq9r3t7ef5gaw497uu85qsqfy27', mockedAccountsResponse]
]);

const response = await provider.rewardAccountBalance({
rewardAccount: Cardano.RewardAccount('stake_test1uqfu74w3wh4gfzu8m6e7j987h4lq9r3t7ef5gaw497uu85qsqfy27')
});

expect(response).toEqual(BigInt(mockedAccountsResponse.withdrawable_amount));
});
});

describe('rewardsHistory', () => {
const pool_id = 'pool1pu5jlj4q9w9jlxeu370a3c9myx47md5j5m2str0naunn2q3lkdy';
const rewardAccounts = [
'stake_test1uqfu74w3wh4gfzu8m6e7j987h4lq9r3t7ef5gaw497uu85qsqfy27',
'stake_test1up7pvfq8zn4quy45r2g572290p9vf99mr9tn7r9xrgy2l2qdsf58d'
].map(Cardano.RewardAccount);
const generateRewardsResponse = (numEpochs: number, firstEpoch = 0): Responses['account_reward_content'] =>
[...Array.from({ length: numEpochs }).keys()].map((epoch) => ({
amount: '1000',
epoch: firstEpoch + epoch,
pool_id,
type: 'member'
}));

test('epoch bounds & query per stake address', async () => {
mockResponses(request, [
[`accounts/${rewardAccounts[0]}/rewards?count=100?page=1`, generateRewardsResponse(2, 98)],
[`accounts/${rewardAccounts[1]}/rewards?count=100?page=1`, generateRewardsResponse(2, 98)]
]);

const response = await provider.rewardsHistory({
epochs: {
lowerBound: Cardano.EpochNo(98),
upperBound: Cardano.EpochNo(98)
},
rewardAccounts
});

expect(response).toEqual(
new Map([
[rewardAccounts[0], [{ epoch: 98, rewards: 1000n }]],
[rewardAccounts[1], [{ epoch: 98, rewards: 1000n }]]
])
);
});

test('pagination', async () => {
mockResponses(request, [
[`accounts/${rewardAccounts[0]}/rewards?count=100?page=1`, generateRewardsResponse(100)],
[`accounts/${rewardAccounts[0]}/rewards?count=100?page=2`, generateRewardsResponse(0)]
]);

const response = await provider.rewardsHistory({
epochs: {
lowerBound: Cardano.EpochNo(98)
},
rewardAccounts: [rewardAccounts[0]]
});

expect(response).toEqual(
new Map([
[
rewardAccounts[0],
[
{ epoch: 98, rewards: 1000n },
{ epoch: 99, rewards: 1000n }
]
]
])
);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
BlockfrostAssetProvider,
BlockfrostChainHistoryProvider,
BlockfrostNetworkInfoProvider,
BlockfrostRewardsProvider,
BlockfrostUtxoProvider,
CardanoWsClient,
TxSubmitApiProvider
Expand All @@ -40,7 +41,6 @@ import {
StubTokenMetadataService,
TypeormAssetProvider
} from '../../Asset';
import { BlockfrostRewardsProvider, DbSyncRewardsProvider, RewardsHttpService } from '../../Rewards';
import { BlockfrostTxSubmitProvider, NodeTxSubmitProvider, TxSubmitHttpService } from '../../TxSubmit';
import { ChainHistoryHttpService, DbSyncChainHistoryProvider } from '../../ChainHistory';
import {
Expand All @@ -54,6 +54,7 @@ import {
} from '../options';
import { DbPools, DbSyncEpochPollService, TypeormProvider, getBlockfrostApi, getBlockfrostClient } from '../../util';
import { DbSyncNetworkInfoProvider, NetworkInfoHttpService } from '../../NetworkInfo';
import { DbSyncRewardsProvider, RewardsHttpService } from '../../Rewards';
import {
DbSyncStakePoolProvider,
StakePoolHttpService,
Expand Down Expand Up @@ -344,7 +345,7 @@ const serviceMapFactory = (options: ServiceMapFactoryOptions) => {
const getBlockfrostChainHistoryProvider = (nInfoProvider: NetworkInfoProvider | DbSyncNetworkInfoProvider) =>
new BlockfrostChainHistoryProvider(getBlockfrostClient(), nInfoProvider, logger);

const getBlockfrostRewardsProvider = () => new BlockfrostRewardsProvider({ blockfrost: getBlockfrostApi(), logger });
const getBlockfrostRewardsProvider = () => new BlockfrostRewardsProvider(getBlockfrostClient(), logger);

const getDbSyncRewardsProvider = withDbSyncProvider(
(dbPools, cardanoNode) =>
Expand Down

This file was deleted.

1 change: 0 additions & 1 deletion packages/cardano-services/src/Rewards/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
export * from './BlockfrostRewardsProvider';
export * from './DbSyncRewardProvider';
export * from './RewardsHttpService';

This file was deleted.

0 comments on commit dd12ee6

Please sign in to comment.