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

Merge development into feat/sdk-core-v13 #1504

Merged
merged 5 commits into from
Oct 10, 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
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,26 @@ export class FeesCollectorSetterService extends GenericSetterService {
CacheTtlInfo.ContractInfo.localTtl,
);
}

async allTokens(tokens: string[]): Promise<string> {
return this.setData(
this.getCacheKey('allTokens'),
tokens,
CacheTtlInfo.ContractInfo.remoteTtl,
CacheTtlInfo.ContractInfo.localTtl,
);
}

async accumulatedFeesUntilNow(
scAddress: string,
week: number,
value: string,
): Promise<string> {
return this.setData(
this.getCacheKey('accumulatedFeesUntilNow', scAddress, week),
value,
CacheTtlInfo.ContractBalance.remoteTtl,
CacheTtlInfo.ContractBalance.localTtl,
);
}
}
23 changes: 19 additions & 4 deletions src/modules/staking/services/staking.compute.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,17 +141,24 @@ export class StakingComputeService {
async computeExtraRewardsBounded(
stakeAddress: string,
blockDifferenceBig: BigNumber,
): Promise<BigNumber> {
const extraRewardsAPRBoundedPerBlock =
await this.computeExtraRewardsAPRBoundedPerBlock(stakeAddress);

return extraRewardsAPRBoundedPerBlock.multipliedBy(blockDifferenceBig);
}

async computeExtraRewardsAPRBoundedPerBlock(
stakeAddress: string,
): Promise<BigNumber> {
const [farmTokenSupply, annualPercentageRewards] = await Promise.all([
this.stakingAbi.farmTokenSupply(stakeAddress),
this.stakingAbi.annualPercentageRewards(stakeAddress),
]);
const extraRewardsAPRBoundedPerBlock = new BigNumber(farmTokenSupply)
return new BigNumber(farmTokenSupply)
.multipliedBy(annualPercentageRewards)
.dividedBy(constantsConfig.MAX_PERCENT)
.dividedBy(constantsConfig.BLOCKS_IN_YEAR);

return extraRewardsAPRBoundedPerBlock.multipliedBy(blockDifferenceBig);
}

async farmingTokenPriceUSD(stakeAddress: string): Promise<string> {
Expand Down Expand Up @@ -325,10 +332,18 @@ export class StakingComputeService {
// 10 blocks per minute * 60 minutes per hour * 24 hours per day
const blocksInDay = 10 * 60 * 24;

const extraRewardsAPRBoundedPerBlock =
await this.computeExtraRewardsAPRBoundedPerBlock(stakeAddress);

const perBlockRewards = BigNumber.min(
extraRewardsAPRBoundedPerBlock,
perBlockRewardAmount,
);

return parseFloat(
new BigNumber(rewardsCapacity)
.minus(accumulatedRewards)
.dividedBy(perBlockRewardAmount)
.dividedBy(perBlockRewards)
.dividedBy(blocksInDay)
.toFixed(2),
);
Expand Down
13 changes: 13 additions & 0 deletions src/modules/staking/services/staking.setter.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { CacheTtlInfo } from 'src/services/caching/cache.ttl.info';
import { GenericSetterService } from 'src/services/generics/generic.setter.service';
import { Logger } from 'winston';
import { EsdtTokenPayment } from '@multiversx/sdk-exchange';
import { BoostedYieldsFactors } from 'src/modules/farm/models/farm.v2.model';

@Injectable()
export class StakingSetterService extends GenericSetterService {
Expand Down Expand Up @@ -178,6 +179,18 @@ export class StakingSetterService extends GenericSetterService {
);
}

async setBoostedYieldsFactors(
stakeAddress: string,
value: BoostedYieldsFactors,
): Promise<string> {
return await this.setData(
this.getCacheKey('boostedYieldsFactors', stakeAddress),
value,
CacheTtlInfo.ContractState.remoteTtl,
CacheTtlInfo.ContractState.localTtl,
);
}

async setUserTotalStakePosition(
stakeAddress: string,
userAddress: string,
Expand Down
8 changes: 8 additions & 0 deletions src/services/cache.warmer.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ import { TokensCacheWarmerService } from './crons/tokens.cache.warmer.service';
import { FarmModuleV2 } from 'src/modules/farm/v2/farm.v2.module';
import { EscrowCacheWarmerService } from './crons/escrow.cache.warmer.service';
import { EscrowModule } from 'src/modules/escrow/escrow.module';
import { FeesCollectorCacheWarmerService } from './crons/fees.collector.cache.warmer.service';
import { FeesCollectorModule } from 'src/modules/fees-collector/fees-collector.module';
import { WeekTimekeepingModule } from 'src/submodules/week-timekeeping/week-timekeeping.module';
import { WeeklyRewardsSplittingModule } from 'src/submodules/weekly-rewards-splitting/weekly-rewards-splitting.module';

@Module({
imports: [
Expand Down Expand Up @@ -66,6 +70,9 @@ import { EscrowModule } from 'src/modules/escrow/escrow.module';
GovernanceModule,
DynamicModuleUtils.getCacheModule(),
EscrowModule,
FeesCollectorModule,
WeekTimekeepingModule,
WeeklyRewardsSplittingModule,
],
controllers: [],
providers: [
Expand All @@ -85,6 +92,7 @@ import { EscrowModule } from 'src/modules/escrow/escrow.module';
ElasticService,
TokensCacheWarmerService,
EscrowCacheWarmerService,
FeesCollectorCacheWarmerService,
],
})
export class CacheWarmerModule {}
157 changes: 157 additions & 0 deletions src/services/crons/fees.collector.cache.warmer.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import { Inject, Injectable } from '@nestjs/common';
import { PUB_SUB } from '../redis.pubSub.module';
import { RedisPubSub } from 'graphql-redis-subscriptions';
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
import { Logger } from 'winston';
import { Cron, CronExpression } from '@nestjs/schedule';
import { PerformanceProfiler } from '@multiversx/sdk-nestjs-monitoring';
import { FeesCollectorAbiService } from 'src/modules/fees-collector/services/fees-collector.abi.service';
import { WeekTimekeepingAbiService } from 'src/submodules/week-timekeeping/services/week-timekeeping.abi.service';
import { constantsConfig, scAddress } from 'src/config';
import { FeesCollectorSetterService } from 'src/modules/fees-collector/services/fees-collector.setter.service';
import { WeeklyRewardsSplittingAbiService } from 'src/submodules/weekly-rewards-splitting/services/weekly-rewards-splitting.abi.service';
import { FeesCollectorComputeService } from 'src/modules/fees-collector/services/fees-collector.compute.service';
import { WeeklyRewardsSplittingSetterService } from 'src/submodules/weekly-rewards-splitting/services/weekly.rewarrds.splitting.setter.service';
import { Lock } from '@multiversx/sdk-nestjs-common';

@Injectable()
export class FeesCollectorCacheWarmerService {
constructor(
@Inject(PUB_SUB) private pubSub: RedisPubSub,
@Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger,
private readonly feesCollectorAbi: FeesCollectorAbiService,
private readonly feesCollectorCompute: FeesCollectorComputeService,
private readonly feesCollectorSetter: FeesCollectorSetterService,
private readonly weekTimekeepingAbi: WeekTimekeepingAbiService,
private readonly weeklyRewardsSplittingAbi: WeeklyRewardsSplittingAbiService,
private readonly weeklyRewardsSplittingSetter: WeeklyRewardsSplittingSetterService,
) {}

@Cron(CronExpression.EVERY_MINUTE)
@Lock({ name: 'cacheFeesCollector', verbose: true })
async cacheFeesCollector(): Promise<void> {
this.logger.info('Start refresh fees collector data', {
context: 'CacheFeesCollector',
});

const profiler = new PerformanceProfiler();

const [allTokens, currentWeek] = await Promise.all([
this.feesCollectorAbi.allTokens(),
this.weekTimekeepingAbi.currentWeek(scAddress.feesCollector),
]);

const accumulatedFeesUntilNow =
await this.feesCollectorCompute.computeAccumulatedFeesUntilNow(
scAddress.feesCollector,
currentWeek,
);

const cachedKeys = await Promise.all([
this.feesCollectorSetter.allTokens(allTokens),
this.feesCollectorSetter.accumulatedFeesUntilNow(
scAddress.feesCollector,
currentWeek,
accumulatedFeesUntilNow,
),
]);

const tokensAccumulatedFeesCacheKeys =
await this.cacheTokensAccumulatedFees(allTokens, currentWeek);

const claimWeeksCacheKeys = await this.cacheClaimWeeksData(
currentWeek,
scAddress.feesCollector,
);

cachedKeys.push(...tokensAccumulatedFeesCacheKeys);
cachedKeys.push(...claimWeeksCacheKeys);

await this.deleteCacheKeys(cachedKeys);

profiler.stop();
this.logger.info(
`Finish refresh fees collector data in ${profiler.duration}`,
{
context: 'CacheFeesCollector',
},
);
}

private async cacheTokensAccumulatedFees(
allTokens: string[],
week: number,
): Promise<string[]> {
const cachedKeys = [];
for (const token of allTokens) {
const accumulatedFees =
await this.feesCollectorAbi.getAccumulatedFeesRaw(week, token);

const cacheKey = await this.feesCollectorSetter.accumulatedFees(
week,
token,
accumulatedFees,
);

cachedKeys.push(cacheKey);
}

return cachedKeys;
}

private async cacheClaimWeeksData(
currentWeek: number,
feesCollectorScAddress: string,
): Promise<string[]> {
const cachedKeys = [];
const startWeek = currentWeek - constantsConfig.USER_MAX_CLAIM_WEEKS;

for (let week = startWeek; week <= currentWeek; week++) {
if (week < 1) {
continue;
}

const totalEnergyForWeek =
await this.weeklyRewardsSplittingAbi.totalEnergyForWeekRaw(
feesCollectorScAddress,
week,
);
const totalRewardsForWeek =
await this.weeklyRewardsSplittingAbi.totalRewardsForWeekRaw(
feesCollectorScAddress,
week,
);
const totalLockedTokensForWeek =
await this.weeklyRewardsSplittingAbi.totalLockedTokensForWeekRaw(
feesCollectorScAddress,
week,
);

const keys = await Promise.all([
this.weeklyRewardsSplittingSetter.totalEnergyForWeek(
feesCollectorScAddress,
week,
totalEnergyForWeek,
),
this.weeklyRewardsSplittingSetter.totalRewardsForWeek(
feesCollectorScAddress,
week,
totalRewardsForWeek,
),
this.weeklyRewardsSplittingSetter.totalLockedTokensForWeek(
feesCollectorScAddress,
week,
totalLockedTokensForWeek,
),
]);

cachedKeys.push(...keys);
}

return cachedKeys;
}

private async deleteCacheKeys(invalidatedKeys: string[]) {
await this.pubSub.publish('deleteCacheKeys', invalidatedKeys);
}
}
6 changes: 6 additions & 0 deletions src/services/crons/staking.cache.warmer.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,14 @@ export class StakingCacheWarmerService {
minUnboundEpochs,
divisionSafetyConstant,
state,
boostedYieldsFactors,
apr,
] = await Promise.all([
this.stakingAbi.getAnnualPercentageRewardsRaw(address),
this.stakingAbi.getMinUnbondEpochsRaw(address),
this.stakingAbi.getDivisionSafetyConstantRaw(address),
this.stakingAbi.getStateRaw(address),
this.stakingAbi.getBoostedYieldsFactorsRaw(address),
this.stakeCompute.computeStakeFarmAPR(address),
]);

Expand All @@ -78,6 +80,10 @@ export class StakingCacheWarmerService {
divisionSafetyConstant,
),
this.stakeSetterService.setState(address, state),
this.stakeSetterService.setBoostedYieldsFactors(
address,
boostedYieldsFactors,
),
this.stakeSetterService.setStakeFarmAPR(address, apr),
]);

Expand Down
Loading