Anybody have the calculation scripts for ICP and SNS projects?
I think you are looking for fn distribute_rewards.
I’m looking for a way to calculate the estimated APY when creating a neuron, specifically the Voting rewards calculation on the dashboard:
Hello @dostro
For the ICP Dashboard here is how we fetch the data for the Estimate Rewards
const fetchData = async () => {
try {
// https://ic-api.internetcomputer.org/api/v3/governance-metrics
const response = await queryApi('v3/governance-metrics', ApiType.IC);
const lastRewardRoundTotalAvailableE8s: any = response.data.metrics.find((element: any) => {
return element.name === 'governance_latest_reward_round_total_available_e8s'
});
const lastRewardsRoundTotalAvailableIcp: number =
Number(lastRewardRoundTotalAvailableE8s.subsets[0].value[1]) / 100000000;
setLastRewardsRoundTotalAvailableIcp(lastRewardsRoundTotalAvailableIcp);
const totalVotingPowerE8s: any = response.data.metrics.find((element: any) => {
return element.name === 'governance_voting_power_total'
});
const totalVotingPower: number =
Number(totalVotingPowerE8s.subsets[0].value[1]) / 100000000;
setTotalVotingPower(totalVotingPower);
} catch {
setLastRewardsRoundTotalAvailableIcp(undefined);
setTotalVotingPower(undefined);
}
};
And here is how we do the data calculations
if (lastRewardsRoundTotalAvailableIcp !== undefined
&& totalVotingPower !== undefined
&& totalVotingPower > 0) {
let estimatedRewardsPercentage: number | undefined;
let estimatedNeuronDailyRewards: number | undefined;
if (sliderState.dissolveDelayYears >= 0.5) {
const dissolveDelayBonusSlider: number = 1 + sliderState.dissolveDelayYears / 8;
const dailyRewardsIcpPerVotingPowerUnit: number =
lastRewardsRoundTotalAvailableIcp / totalVotingPower;
let ageBonus: number;
if (neuronInfo !== undefined) {
ageBonus =
1 +
Math.min(neuronInfo.ageSeconds, Constants.governanceMaxNeuronAgeForAgeBonusSeconds) /
Constants.governanceMaxNeuronAgeForAgeBonusSeconds / 4;
const dissolveDelayBonusActual: number =
1 + (NeuronInfo.getDissolveDelayBonusPercentage(neuronInfo) ?? 0) / 100;
estimatedNeuronDailyRewards =
neuronInfo.votingPowerE8s / 100000000 *
dailyRewardsIcpPerVotingPowerUnit *
dissolveDelayBonusSlider / dissolveDelayBonusActual;
} else
ageBonus = 1;
const estimatedRewardsIcpPerVotingPowerUnit: number =
dailyRewardsIcpPerVotingPowerUnit * dissolveDelayBonusSlider * ageBonus;
estimatedRewardsPercentage = estimatedRewardsIcpPerVotingPowerUnit * 365.25 * 100;
} else {
estimatedRewardsPercentage = 0;
estimatedNeuronDailyRewards = neuronInfo !== undefined ? 0 : undefined;
}
setEstimatedRewardsPercentage(estimatedRewardsPercentage);
setEstimatedNeuronDailyRewards(estimatedNeuronDailyRewards);
}
}
Thank you! Will take a look in the coming weeks and let you know how it goes.
hi @ngurian,
could you please take a look?
I have a private method that returns dailyRewards (lastRewardsRoundTotalAvailableIcp / totalVotingPower)
private async getIcpDashboardData(): Promise<
| {
dailyRewardsPerVotingPowerUnit: number
}
| undefined
> {
if (this.icpDashboardData) return this.icpDashboardData
try {
const response = await fetch(
"https://ic-api.internetcomputer.org/api/v3/governance-metrics",
)
const data = await response.json()
const latestRewards =
Number(
data.metrics.find(
(element: any) =>
element.name ===
"governance_latest_reward_round_total_available_e8s",
).subsets[0].value[1],
) /
10 ** this.token.getTokenDecimals()
const votingPower: any =
Number(
data.metrics.find(
(element: any) => element.name === "governance_voting_power_total",
).subsets[0].value[1],
) /
10 ** this.token.getTokenDecimals()
this.icpDashboardData = {
dailyRewardsPerVotingPowerUnit: latestRewards / votingPower,
}
return this.icpDashboardData
} catch (e) {
console.error("ICP Dahsboard Error: ", e)
}
}
Also I have two separate methods for calculating apr and rewards:
- APR:
Here I can’t understand what is 4 (ageBonus last devide action)? Is it a constant value or where it can be taken?
async calculateEstAPR(
lockValueInMonths: number,
lockValue: number,
): Promise<string | undefined> {
const data = await this.getIcpDashboardData()
if (data === undefined) return
const dissolveDelayBonusSlider =
1 + lockValueInMonths / (this.getMaximumLockTimeInMonths() / 12)
const ageBonus =
1 +
Math.min(lockValue, Number(this.params.max_neuron_age_for_age_bonus[0])) /
Number(this.params.max_neuron_age_for_age_bonus[0]) /
4
const estimatedRewardsIcpPerVotingPowerUnit: number =
data.dailyRewardsPerVotingPowerUnit * dissolveDelayBonusSlider * ageBonus
return `${(estimatedRewardsIcpPerVotingPowerUnit * 365.25 * 100).toFixed(
2,
)}%`
}
- Projected Rewards:
I am confused where should I take the votingPowerE8s variable??
async calculateProjectRewards(
amount: string,
lockValueInMonths: number,
): Promise<TokenValue | undefined> {
const data = await this.getIcpDashboardData()
if (data === undefined) return
const { dailyRewardsPerVotingPowerUnit } = data
const dissolveDelayBonusSlider =
1 + lockValueInMonths / 12 / this.getMaximumLockTimeInMonths() / 12
const dissolveDelayBonusActual =
1 +
(Number(this.params.max_dissolve_delay_bonus_percentage[0]) ?? 0) / 100
const votingPowerE8s = 1 // ???
const estimatedNeuronDailyRewards =
((votingPowerE8s / 10 ** this.token.getTokenDecimals()) *
dailyRewardsPerVotingPowerUnit *
dissolveDelayBonusSlider) /
dissolveDelayBonusActual
const value = (estimatedNeuronDailyRewards * lockValueInMonths * 30)
.toFixed(this.token.getTokenDecimals())
.replace(TRIM_ZEROS, "")
return {
getTokenValue: () => `${value} ${this.token.getTokenSymbol()}`,
getUSDValue: () =>
this.token.getTokenRateFormatted(value) || "Not listed",
}
}
@ngurian could you please help Vitalii with his questions? we’re still blocked here
Dividing by 4 scales the age bonus linearly from 0% to 25%, based on the neuron’s age.
The code is currently doing this:
ageBonus = 1 + (ageRatio / 4);
The code below does the same thing, and using 0.25
in the calculation like this probably would be a bit more clear than using 4
:
ageBonus = 1 + (ageRatio * 0.25);
An SNS sets its own voting rewards parameters, so if writing code for an SNS neuron you would use those parameters rather than scaling from 0% to 25%.
For an NNS neuron, you can call get_neuron_info on the NNS Governance canister.
For SNS neurons, the SNS Governance canister unfortunately does not return the voting power, so you need to calculate it yourself. The source of truth for how to do this is the SNS Governance code.