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

[MEX-672] user estimated weekly rewards #1558

Merged
merged 5 commits into from
Feb 11, 2025
Merged
Show file tree
Hide file tree
Changes from 3 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
2 changes: 2 additions & 0 deletions src/modules/farm/models/farm.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ export class BoostedRewardsModel {
@Field({ nullable: true })
accumulatedRewards: string;
@Field({ nullable: true })
estimatedWeeklyRewards: string;
@Field({ nullable: true })
curentBoostedAPR: number;
@Field({ nullable: true })
maximumBoostedAPR: number;
Expand Down
24 changes: 24 additions & 0 deletions src/modules/farm/v2/farm.v2.resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,30 @@ import { FarmComputeLoaderV2 } from './services/farm.v2.compute.loader';
export class FarmBoostedRewardsResolver {
constructor(private readonly farmCompute: FarmComputeServiceV2) {}

@ResolveField()
async estimatedWeeklyRewards(
@Parent() parent: BoostedRewardsModel,
@Args('additionalUserFarmAmount', {
type: () => String,
nullable: true,
defaultValue: '0',
})
additionalUserFarmAmount: string,
@Args('additionalUserEnergy', {
type: () => String,
nullable: true,
defaultValue: '0',
})
additionalUserEnergy: string,
): Promise<string> {
return this.farmCompute.computeUserEstimatedWeeklyRewards(
parent.farmAddress,
parent.userAddress,
additionalUserFarmAmount,
additionalUserEnergy,
);
}

@ResolveField()
async curentBoostedAPR(
@Parent() parent: BoostedRewardsModel,
Expand Down
53 changes: 37 additions & 16 deletions src/modules/farm/v2/services/farm.v2.compute.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -317,26 +317,15 @@ export class FarmComputeServiceV2
return userRewardForWeek.toFixed();
}

async computeUserCurentBoostedAPR(
async computeUserEstimatedWeeklyRewards(
scAddress: string,
userAddress: string,
additionalUserFarmAmount = '0',
additionalUserEnergy = '0',
): Promise<number> {
const [
currentWeek,
boostedRewardsPerWeek,
farmToken,
farmedToken,
farmingTokenPriceUSD,
farmedTokenPriceUSD,
] = await Promise.all([
): Promise<string> {
const [currentWeek, boostedRewardsPerWeek] = await Promise.all([
this.weekTimeKeepingAbi.currentWeek(scAddress),
this.computeBoostedRewardsPerWeek(scAddress),
this.farmService.getFarmToken(scAddress),
this.farmService.getFarmedToken(scAddress),
this.farmingTokenPriceUSD(scAddress),
this.farmedTokenPriceUSD(scAddress),
]);

let userTotalFarmPosition = await this.farmAbi.userTotalFarmPosition(
Expand All @@ -348,17 +337,49 @@ export class FarmComputeServiceV2
.toFixed();

if (userTotalFarmPosition === '0') {
return 0;
return '0';
}

const userRewardsPerWeek = await this.computeUserRewardsForWeek(
return await this.computeUserRewardsForWeek(
scAddress,
userAddress,
currentWeek,
additionalUserFarmAmount,
additionalUserEnergy,
boostedRewardsPerWeek,
);
}

async computeUserCurentBoostedAPR(
scAddress: string,
userAddress: string,
additionalUserFarmAmount = '0',
additionalUserEnergy = '0',
): Promise<number> {
const [
userRewardsPerWeek,
userTotalFarmPosition,
farmToken,
farmedToken,
farmingTokenPriceUSD,
farmedTokenPriceUSD,
] = await Promise.all([
this.computeUserEstimatedWeeklyRewards(
scAddress,
userAddress,
additionalUserFarmAmount,
additionalUserEnergy,
),
this.farmAbi.userTotalFarmPosition(scAddress, userAddress),
this.farmService.getFarmToken(scAddress),
this.farmService.getFarmedToken(scAddress),
this.farmingTokenPriceUSD(scAddress),
this.farmedTokenPriceUSD(scAddress),
]);

if (userRewardsPerWeek === '0') {
return 0;
}

const userTotalFarmPositionUSD = computeValueUSD(
userTotalFarmPosition,
Expand Down
13 changes: 13 additions & 0 deletions src/modules/fees-collector/fees-collector.resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,19 @@ export class UserEntryFeesCollectorResolver {
);
}

@ResolveField()
async lastWeekRewardsUSD(
@Parent() parent: UserEntryFeesCollectorModel,
@Args('additionalUserEnergy', { nullable: true })
additionalUserEnergy: string,
): Promise<string> {
return this.feesCollectorCompute.computeUserLastWeekRewardsUSD(
scAddress.feesCollector,
parent.userAddress,
additionalUserEnergy,
);
}

@UseGuards(JwtOrNativeAuthGuard)
@Query(() => UserEntryFeesCollectorModel)
async userFeesCollector(
Expand Down
3 changes: 3 additions & 0 deletions src/modules/fees-collector/models/fees-collector.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ export class UserEntryFeesCollectorModel {
@Field()
lastActiveWeekForUser: number;

@Field()
lastWeekRewardsUSD: string;

constructor(init?: Partial<UserEntryFeesCollectorModel>) {
Object.assign(this, init);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,46 @@ export class FeesCollectorComputeService {
.toFixed();
}

async computeUserLastWeekRewardsUSD(
scAddress: string,
userAddress: string,
additionalUserEnergy = '0',
): Promise<string> {
const currentWeek = await this.weekTimekeepingAbi.currentWeek(
scAddress,
);
const lastWeek = currentWeek - 1;
const [totalRewardsForWeekUSD, userEnergyForWeek] = await Promise.all([
this.weeklyRewardsSplittingCompute.totalRewardsForWeekUSD(
scAddress,
lastWeek,
),
this.weeklyRewardsSplittingAbi.userEnergyForWeek(
scAddress,
userAddress,
lastWeek,
),
]);
let totalEnergyForWeek =
await this.weeklyRewardsSplittingAbi.totalEnergyForWeek(
scAddress,
lastWeek,
);

userEnergyForWeek.amount = new BigNumber(userEnergyForWeek.amount)
.plus(additionalUserEnergy)
.toFixed();
totalEnergyForWeek = new BigNumber(totalEnergyForWeek)
.plus(additionalUserEnergy)
.toFixed();

const userRewardsForWeekUSD = new BigNumber(totalRewardsForWeekUSD)
.multipliedBy(userEnergyForWeek.amount)
.dividedBy(totalEnergyForWeek);

return userRewardsForWeekUSD.toFixed();
}

async computeUserRewardsAPR(
scAddress: string,
userAddress: string,
Expand All @@ -139,49 +179,31 @@ export class FeesCollectorComputeService {
return new BigNumber(0);
}

const [currentWeek, baseAssetTokenID] = await Promise.all([
this.weekTimekeepingAbi.currentWeek(scAddress),
this.energyAbi.baseAssetTokenID(),
]);
const lastWeek = currentWeek - 1;
const baseAssetTokenID = await this.energyAbi.baseAssetTokenID();

const [baseToken, userEnergy, totalRewardsForWeekUSD] =
await Promise.all([
this.tokenService.tokenMetadata(baseAssetTokenID),
this.energyService.getUserEnergy(userAddress),
this.weeklyRewardsSplittingCompute.totalRewardsForWeekUSD(
scAddress,
lastWeek,
),
]);

let totalEnergyForWeek =
await this.weeklyRewardsSplittingAbi.totalEnergyForWeek(
const [
baseToken,
userEnergy,
baseAssetTokenPriceUSD,
userRewardsForWeekUSD,
] = await Promise.all([
this.tokenService.tokenMetadata(baseAssetTokenID),
this.energyService.getUserEnergy(userAddress),
this.tokenCompute.tokenPriceDerivedUSD(baseAssetTokenID),
this.computeUserLastWeekRewardsUSD(
scAddress,
lastWeek,
);

if (customEnergyAmount) {
totalEnergyForWeek = new BigNumber(totalEnergyForWeek)
.minus(userEnergy.amount)
.plus(customEnergyAmount)
.toFixed();
}
userAddress,
customEnergyAmount,
),
]);

const baseAssetTokenPriceUSD =
await this.tokenCompute.computeTokenPriceDerivedUSD(
baseToken.identifier,
);
const userLockedTokensValueUSD = computeValueUSD(
customLockedTokens ?? userEnergy.totalLockedTokens,
baseToken.decimals,
baseAssetTokenPriceUSD,
);

const userRewardsForWeekUSD = new BigNumber(totalRewardsForWeekUSD)
.multipliedBy(customEnergyAmount ?? userEnergy.amount)
.dividedBy(totalEnergyForWeek);
const userAPRForWeek = userRewardsForWeekUSD
const userAPRForWeek = new BigNumber(userRewardsForWeekUSD)
.multipliedBy(52)
.dividedBy(userLockedTokensValueUSD)
.multipliedBy(100);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,11 @@ describe('FeesCollectorComputeService', () => {
'totalEnergyForWeek',
).mockReturnValue(Promise.resolve(totalEnergyForWeek));

jest.spyOn(
weeklyRewardsSplittingAbi,
'userEnergyForWeek',
).mockReturnValue(Promise.resolve(user1Energy));

jest.spyOn(energyService, 'getUserEnergy').mockReturnValueOnce(
Promise.resolve(user1Energy),
);
Expand Down Expand Up @@ -319,14 +324,18 @@ describe('FeesCollectorComputeService', () => {
'totalEnergyForWeek',
).mockReturnValue(Promise.resolve(totalEnergyForWeek));

jest.spyOn(
weeklyRewardsSplittingAbi,
'userEnergyForWeek',
).mockReturnValue(Promise.resolve(user1Energy));
jest.spyOn(energyService, 'getUserEnergy').mockReturnValueOnce(
Promise.resolve(user1Energy),
);

const apr = await service.computeUserRewardsAPR(
Address.Zero().bech32(),
user1,
new BigNumber(totalEnergyForWeek).dividedBy(2).toFixed(),
new BigNumber(totalEnergyForWeek).dividedBy(4).toFixed(),
);

expect(apr.toFixed()).toEqual('14.872');
Expand Down Expand Up @@ -380,14 +389,19 @@ describe('FeesCollectorComputeService', () => {
'totalEnergyForWeek',
).mockReturnValue(Promise.resolve(totalEnergyForWeek));

jest.spyOn(
weeklyRewardsSplittingAbi,
'userEnergyForWeek',
).mockReturnValue(Promise.resolve(user1Energy));

jest.spyOn(energyService, 'getUserEnergy').mockReturnValueOnce(
Promise.resolve(user1Energy),
);

const apr = await service.computeUserRewardsAPR(
Address.Zero().bech32(),
user1,
new BigNumber(totalEnergyForWeek).dividedBy(2).toFixed(),
new BigNumber(totalEnergyForWeek).dividedBy(4).toFixed(),
new BigNumber(totalLockedTokensForWeek).dividedBy(2).toFixed(),
);

Expand Down
47 changes: 31 additions & 16 deletions src/modules/staking/services/staking.compute.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -704,12 +704,12 @@ export class StakingComputeService {
return userRewardForWeek.toFixed();
}

async computeUserCurentBoostedAPR(
async computeUserEstimatedWeeklyRewards(
scAddress: string,
userAddress: string,
additionalUserStakeAmount = '0',
additionalUserEnergy = '0',
): Promise<number> {
): Promise<string> {
const [produceRewardsEnabled, accumulatedRewards, rewardsCapacity] =
await Promise.all([
this.stakingAbi.produceRewardsEnabled(scAddress),
Expand All @@ -721,7 +721,7 @@ export class StakingComputeService {
!produceRewardsEnabled ||
new BigNumber(accumulatedRewards).isEqualTo(rewardsCapacity)
) {
return 0;
return '0';
}

const [currentWeek, boostedRewardsPerWeek] = await Promise.all([
Expand All @@ -731,27 +731,42 @@ export class StakingComputeService {
additionalUserStakeAmount,
),
]);
let userTotalStakePosition =
await this.stakingAbi.userTotalStakePosition(
scAddress,
userAddress,
);
userTotalStakePosition = new BigNumber(userTotalStakePosition)
.plus(additionalUserStakeAmount)
.toFixed();

if (userTotalStakePosition === '0') {
return 0;
}

const userRewardsPerWeek = await this.computeUserRewardsForWeek(
return await this.computeUserRewardsForWeek(
scAddress,
userAddress,
currentWeek,
additionalUserStakeAmount,
additionalUserEnergy,
boostedRewardsPerWeek,
);
}

async computeUserCurentBoostedAPR(
scAddress: string,
userAddress: string,
additionalUserStakeAmount = '0',
additionalUserEnergy = '0',
): Promise<number> {
const userRewardsPerWeek = await this.computeUserEstimatedWeeklyRewards(
scAddress,
userAddress,
additionalUserStakeAmount,
additionalUserEnergy,
);

if (userRewardsPerWeek === '0') {
return 0;
}

let userTotalStakePosition =
await this.stakingAbi.userTotalStakePosition(
scAddress,
userAddress,
);
userTotalStakePosition = new BigNumber(userTotalStakePosition)
.plus(additionalUserStakeAmount)
.toFixed();

return new BigNumber(userRewardsPerWeek)
.multipliedBy(52)
Expand Down
Loading
Loading