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

SERVICES-1379: compute undistributedBoostedRewards #982

Closed
wants to merge 11 commits into from
Closed
54 changes: 54 additions & 0 deletions src/modules/farm/mocks/farm.v2.abi.service.mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { FarmAbiServiceV2 } from '../v2/services/farm.v2.abi.service';
import { FarmAbiServiceMock } from './farm.abi.service.mock';
import { IFarmAbiServiceV2 } from '../v2/services/interfaces';
import { BoostedYieldsFactors } from '../models/farm.v2.model';

export class FarmAbiServiceMockV2
extends FarmAbiServiceMock
implements IFarmAbiServiceV2
{
async lastUndistributedBoostedRewardsCollectWeek(
farmAddress: string,
): Promise<number> {
return Promise.resolve(1);
claudiulataretu marked this conversation as resolved.
Show resolved Hide resolved
}
async undistributedBoostedRewards(farmAddress: string): Promise<string> {
return Promise.resolve('5000');
}
async remainingBoostedRewardsToDistribute(
farmAddress: string,
week: number,
): Promise<string> {
return Promise.resolve('1000');
}

accumulatedRewardsForWeek(scAddress: string, week: number): Promise<string> {
throw new Error('Method not implemented.');
}

boostedYieldsFactors(farmAddress: string): Promise<BoostedYieldsFactors> {
throw new Error('Method not implemented.');
}

boostedYieldsRewardsPercenatage(farmAddress: string): Promise<number> {
throw new Error('Method not implemented.');
}

energyFactoryAddress(farmAddress: string): Promise<string> {
throw new Error('Method not implemented.');
}

lockEpochs(farmAddress: string): Promise<number> {
throw new Error('Method not implemented.');
}

lockingScAddress(farmAddress: string): Promise<string> {
throw new Error('Method not implemented.');
}
}


export const FarmAbiServiceProviderV2 = {
provide: FarmAbiServiceV2,
useClass: FarmAbiServiceMockV2,
};
2 changes: 2 additions & 0 deletions src/modules/farm/models/farm.v2.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ export class FarmModelV2 extends BaseFarmModel {
@Field()
undistributedBoostedRewards: string;
@Field()
undistributedBoostedRewardsClaimed: string;
@Field()
energyFactoryAddress: string;
@Field()
rewardType: FarmRewardType;
Expand Down
81 changes: 81 additions & 0 deletions src/modules/farm/specs/farm.v2.compute.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { BigNumber } from 'bignumber.js';
import { Test, TestingModule } from '@nestjs/testing';
import { FarmComputeServiceV2 } from '../v2/services/farm.v2.compute.service';
import { CommonAppModule } from '../../../common.app.module';
import { CachingModule } from '../../../services/caching/cache.module';
import { FarmAbiServiceProviderV2 } from '../mocks/farm.v2.abi.service.mock';
import { FarmServiceV2 } from '../v2/services/farm.v2.service';
import { MXDataApiServiceProvider } from '../../../services/multiversx-communication/mx.data.api.service.mock';
import { WrapAbiServiceProvider } from '../../wrapping/mocks/wrap.abi.service.mock';
import { RouterAbiServiceProvider } from '../../router/mocks/router.abi.service.mock';
import { TokenComputeService } from '../../tokens/services/token.compute.service';
import { TokenGetterServiceProvider } from '../../tokens/mocks/token.getter.service.mock';
import { PairComputeServiceProvider } from '../../pair/mocks/pair.compute.service.mock';
import { PairAbiServiceProvider } from '../../pair/mocks/pair.abi.service.mock';
import { PairService } from '../../pair/services/pair.service';
import { ContextGetterServiceProvider } from '../../../services/context/mocks/context.getter.service.mock';
import { MXApiServiceProvider } from '../../../services/multiversx-communication/mx.api.service.mock';
import {
WeekTimekeepingAbiServiceProvider,
} from '../../../submodules/week-timekeeping/mocks/week.timekeeping.abi.service.mock';
import {
WeekTimekeepingComputeService,
} from '../../../submodules/week-timekeeping/services/week-timekeeping.compute.service';
import {
WeeklyRewardsSplittingAbiServiceProvider,
} from '../../../submodules/weekly-rewards-splitting/mocks/weekly.rewards.splitting.abi.mock';
import {
WeeklyRewardsSplittingComputeService,
} from '../../../submodules/weekly-rewards-splitting/services/weekly-rewards-splitting.compute.service';
import { EnergyAbiServiceProvider } from '../../energy/mocks/energy.abi.service.mock';

describe('FarmServiceV2', () => {
let module: TestingModule;

beforeEach(async () => {
module = await Test.createTestingModule({
imports: [CommonAppModule, CachingModule],
providers: [
MXApiServiceProvider,
ContextGetterServiceProvider,
PairService,
PairAbiServiceProvider,
PairComputeServiceProvider,
TokenGetterServiceProvider,
TokenComputeService,
RouterAbiServiceProvider,
WrapAbiServiceProvider,
MXDataApiServiceProvider,
WeekTimekeepingAbiServiceProvider,
WeekTimekeepingComputeService,
WeeklyRewardsSplittingAbiServiceProvider,
EnergyAbiServiceProvider,
WeeklyRewardsSplittingComputeService,
FarmComputeServiceV2,
FarmAbiServiceProviderV2,
FarmServiceV2,
],
}).compile();
});
it("should correctly calculate total rewards", async () => {
const service = module.get<FarmComputeServiceV2>(
FarmComputeServiceV2,
);
const result = await service.computeUndistributedBoostedRewards('erd18h5dulxp5zdp80qjndd2w25kufx0rm5yqd2h7ajrfucjhr82y8vqyq0hye', 10);
const expectedTotal = new BigNumber('5000').plus('4000').integerValue().toFixed(); // 4 weeks * 1000
expect(result).toEqual(expectedTotal);
// expect(mockFarmAbi.undistributedBoostedRewards).toHaveBeenCalled();
claudiulataretu marked this conversation as resolved.
Show resolved Hide resolved
// expect(mockFarmAbi.lastUndistributedBoostedRewardsCollectWeek).toHaveBeenCalled();
// expect(mockFarmAbi.remainingBoostedRewardsToDistribute).toHaveBeenCalledTimes(4);
});
// it("should return undistributedBoostedRewards if firstWeek > lastWeek", async () => {
// const service = module.get<FarmComputeServiceV2>(
// FarmComputeServiceV2,
// );
// const result = await service.computeUndistributedBoostedRewards('erd18h5dulxp5zdp80qjndd2w25kufx0rm5yqd2h7ajrfucjhr82y8vqyq0hye', 5);
// expect(result).toEqual('5000');
// // expect(mockFarmAbi.undistributedBoostedRewards).toHaveBeenCalled();
// // expect(mockFarmAbi.lastUndistributedBoostedRewardsCollectWeek).toHaveBeenCalled();
// }, 10000);
});

18 changes: 16 additions & 2 deletions src/modules/farm/v2/farm.v2.resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@ import { Parent, ResolveField, Resolver } from '@nestjs/graphql';
import { BoostedYieldsFactors, FarmModelV2 } from '../models/farm.v2.model';
import { FarmResolver } from '../base-module/farm.resolver';
import { FarmServiceV2 } from './services/farm.v2.service';
import { GlobalInfoByWeekModel } from '../../../submodules/weekly-rewards-splitting/models/weekly-rewards-splitting.model';
import {
GlobalInfoByWeekModel,
} from '../../../submodules/weekly-rewards-splitting/models/weekly-rewards-splitting.model';
import { WeekTimekeepingModel } from '../../../submodules/week-timekeeping/models/week-timekeeping.model';
import { FarmComputeServiceV2 } from './services/farm.v2.compute.service';
import { constantsConfig } from '../../../config';
import { WeekTimekeepingAbiService } from 'src/submodules/week-timekeeping/services/week-timekeeping.abi.service';
import { WeeklyRewardsSplittingAbiService } from 'src/submodules/weekly-rewards-splitting/services/weekly-rewards-splitting.abi.service';
import {
WeeklyRewardsSplittingAbiService,
} from 'src/submodules/weekly-rewards-splitting/services/weekly-rewards-splitting.abi.service';
import { FarmAbiServiceV2 } from './services/farm.v2.abi.service';

@Resolver(() => FarmModelV2)
Expand Down Expand Up @@ -110,6 +114,16 @@ export class FarmResolverV2 extends FarmResolver {
@ResolveField()
async undistributedBoostedRewards(
@Parent() parent: FarmModelV2,
): Promise<string> {
const currentWeek = await this.weekTimekeepingAbi.currentWeek(
parent.address,
);
return this.farmCompute.computeUndistributedBoostedRewards(parent.address, currentWeek);
}

@ResolveField()
async undistributedBoostedRewardsClaimed(
@Parent() parent: FarmModelV2,
): Promise<string> {
return this.farmAbi.undistributedBoostedRewards(parent.address);
}
Expand Down
17 changes: 17 additions & 0 deletions src/modules/farm/v2/services/farm.v2.abi.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,23 @@ export class FarmAbiServiceV2
return response.firstValue.valueOf().toFixed();
}

@ErrorLoggerAsync({
className: FarmAbiServiceV2.name,
logArgs: true,
})
@GetOrSetCache({
baseKey: 'farm',
remoteTtl: CacheTtlInfo.ContractState.remoteTtl,
localTtl: CacheTtlInfo.ContractState.localTtl,
})
async lastUndistributedBoostedRewardsCollectWeek(
farmAddress: string,
): Promise<number> {
return this.gatewayService.getSCStorageKey(farmAddress,
'lastUndistributedBoostedRewardsCollectWeek'
);
}

@ErrorLoggerAsync({
className: FarmAbiServiceV2.name,
logArgs: true,
Expand Down
62 changes: 58 additions & 4 deletions src/modules/farm/v2/services/farm.v2.compute.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Inject, Injectable, forwardRef } from '@nestjs/common';
import { forwardRef, Inject, Injectable } from '@nestjs/common';
import { FarmComputeService } from '../../base-module/services/farm.compute.service';
import BigNumber from 'bignumber.js';
import { EsdtTokenPayment } from '../../../../models/esdtTokenPayment.model';
Expand All @@ -8,16 +8,22 @@ import { constantsConfig } from '../../../../config';
import { CalculateRewardsArgs } from '../../models/farm.args';
import { PairService } from '../../../pair/services/pair.service';
import { ContextGetterService } from '../../../../services/context/context.getter.service';
import { WeekTimekeepingComputeService } from 'src/submodules/week-timekeeping/services/week-timekeeping.compute.service';
import { WeeklyRewardsSplittingAbiService } from 'src/submodules/weekly-rewards-splitting/services/weekly-rewards-splitting.abi.service';
import {
WeekTimekeepingComputeService,
} from 'src/submodules/week-timekeeping/services/week-timekeeping.compute.service';
import {
WeeklyRewardsSplittingAbiService,
} from 'src/submodules/weekly-rewards-splitting/services/weekly-rewards-splitting.abi.service';
import { FarmAbiServiceV2 } from './farm.v2.abi.service';
import { FarmServiceV2 } from './farm.v2.service';
import { ErrorLoggerAsync } from 'src/helpers/decorators/error.logger';
import { GetOrSetCache } from 'src/helpers/decorators/caching.decorator';
import { CacheTtlInfo } from 'src/services/caching/cache.ttl.info';
import { CachingService } from 'src/services/caching/cache.service';
import { TokenDistributionModel } from 'src/submodules/weekly-rewards-splitting/models/weekly-rewards-splitting.model';
import { WeeklyRewardsSplittingComputeService } from 'src/submodules/weekly-rewards-splitting/services/weekly-rewards-splitting.compute.service';
import {
WeeklyRewardsSplittingComputeService,
} from 'src/submodules/weekly-rewards-splitting/services/weekly-rewards-splitting.compute.service';
import { IFarmComputeServiceV2 } from './interfaces';

@Injectable()
Expand Down Expand Up @@ -457,6 +463,54 @@ export class FarmComputeServiceV2
.toFixed();
}

@ErrorLoggerAsync({
className: FarmComputeServiceV2.name,
logArgs: true,
})
@GetOrSetCache({
baseKey: 'farm',
remoteTtl: CacheTtlInfo.ContractState.remoteTtl,
localTtl: CacheTtlInfo.ContractState.localTtl,
})
async computeUndistributedBoostedRewards(
claudiulataretu marked this conversation as resolved.
Show resolved Hide resolved
scAddress: string,
currentWeek: number,
): Promise<string> {
const [
undistributedBoostedRewards,
lastUndistributedBoostedRewardsCollectWeek,
] = await Promise.all([
this.farmAbi.undistributedBoostedRewards(scAddress),
this.farmAbi.lastUndistributedBoostedRewardsCollectWeek(
scAddress,
),
]);

const firstWeek = lastUndistributedBoostedRewardsCollectWeek + 1;
const lastWeek = currentWeek - constantsConfig.USER_MAX_CLAIM_WEEKS - 1;
if (firstWeek > lastWeek) {
return undistributedBoostedRewards;
}
const promises = []
for (let week = firstWeek; week <= lastWeek; week++) {
promises.push(
this.farmAbi.remainingBoostedRewardsToDistribute(
scAddress,
week,
)
)
}
const remainingRewards = await Promise.all(promises);
const totalRemainingRewards = remainingRewards.reduce((acc, curr) => {
return new BigNumber(acc).plus(curr).integerValue().toFixed();
claudiulataretu marked this conversation as resolved.
Show resolved Hide resolved
});
return new BigNumber(undistributedBoostedRewards)
.plus(totalRemainingRewards)
.integerValue()
.toFixed();

}

async computeBlocksInWeek(
scAddress: string,
week: number,
Expand Down
dragos-rebegea marked this conversation as resolved.
Show resolved Hide resolved
Empty file.
8 changes: 4 additions & 4 deletions src/modules/farm/v2/services/interfaces.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import { TokenDistributionModel } from 'src/submodules/weekly-rewards-splitting/models/weekly-rewards-splitting.model';
import {
IFarmAbiService,
IFarmComputeService,
} from '../../base-module/services/interfaces';
import { IFarmAbiService, IFarmComputeService } from '../../base-module/services/interfaces';
import { BoostedYieldsFactors } from '../../models/farm.v2.model';
import { EsdtTokenPayment } from '../../../../models/esdtTokenPayment.model';

Expand All @@ -14,6 +11,9 @@ export interface IFarmAbiServiceV2 extends IFarmAbiService {
farmAddress: string,
week: number,
): Promise<string>;
lastUndistributedBoostedRewardsCollectWeek(
farmAddress: string,
): Promise<number>;
undistributedBoostedRewards(farmAddress: string): Promise<string>;
boostedYieldsFactors(farmAddress: string): Promise<BoostedYieldsFactors>;
accumulatedRewardsForWeek(scAddress: string, week: number): Promise<string>;
Expand Down
5 changes: 2 additions & 3 deletions src/modules/rabbitmq/handlers/router.handler.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {
} from '@multiversx/sdk-exchange';
import { Inject, Injectable } from '@nestjs/common';
import { RedisPubSub } from 'graphql-redis-subscriptions';
import { constantsConfig } from 'src/config';
import { PUB_SUB } from 'src/services/redis.pubSub.module';
import { generateCacheKeyFromParams } from 'src/utils/generate-cache-key';
import { RouterAbiService } from '../../router/services/router.abi.service';
Expand Down Expand Up @@ -45,8 +44,8 @@ export class RouterHandlerService {
uniqueTokens,
commonTokens,
] = await Promise.all([
this.routerAbiService.pairsMetadata(),
this.routerAbiService.pairsAddress(),
this.routerAbiService.getPairsMetadataRaw(),
this.routerAbiService.getAllPairsAddressRaw(),
this.tokenGetter.getEsdtTokenType(firstTokenID),
this.tokenGetter.getEsdtTokenType(secondTokenID),
this.tokenService.getUniqueTokenIDs(true),
Expand Down
2 changes: 1 addition & 1 deletion src/modules/rabbitmq/rabbitmq.consumer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ export class RabbitMqConsumer {

async getFilterAddresses(): Promise<void> {
this.filterAddresses = [];
this.filterAddresses = await this.routerAbi.pairsAddress();
this.filterAddresses = await this.routerAbi.getAllPairsAddressRaw();
this.filterAddresses.push(...farmsAddresses());
this.filterAddresses.push(scAddress.routerAddress);
this.filterAddresses.push(scAddress.metabondingStakingAddress);
Expand Down
13 changes: 12 additions & 1 deletion src/modules/tokens/services/token.compute.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export class TokenComputeService implements ITokenComputeService {
}

const pairsMetadata = await this.routerAbi.pairsMetadata();
const tokenPairs: PairMetadata[] = [];
let tokenPairs: PairMetadata[] = [];
for (const pair of pairsMetadata) {
if (
pair.firstTokenID === tokenID ||
Expand All @@ -46,6 +46,17 @@ export class TokenComputeService implements ITokenComputeService {
}
}

if (tokenPairs.length > 1) {
const states = await Promise.all(
tokenPairs.map((pair) => this.pairAbi.state(pair.address)),
);
if (states.find((state) => state === 'Active')) {
tokenPairs = tokenPairs.filter((pair, index) => {
return states[index] === 'Active';
});
}
}

let largestLiquidityEGLD = new BigNumber(0);
let priceSoFar = '0';

Expand Down