# ICP/SNS staking rewards calculation?

**URL:** <https://forum.dfinity.org/t/icp-sns-staking-rewards-calculation/42190>\
**Category:** Developers\
**Created:** [March 12, 2025, 3:00pm UTC](https://forum.dfinity.org/t/icp-sns-staking-rewards-calculation/42190 "2025-03-12T15:00:42Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![dostro](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/dostro/32/1161_2.png) [@dostro](https://forum.dfinity.org/u/dostro)\
**Post date:** [March 12, 2025, 3:00pm UTC](https://forum.dfinity.org/t/icp-sns-staking-rewards-calculation/42190/1 "2025-03-12T15:00:42Z")

</div>

Anybody have the calculation scripts for ICP and SNS projects?

---

<div class="post-metadata">

**Author:** ![daniel-wong](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/daniel-wong/32/6248_2.png) [@daniel-wong](https://forum.dfinity.org/u/daniel-wong)\
**Post date:** [March 14, 2025, 11:01am UTC](https://forum.dfinity.org/t/icp-sns-staking-rewards-calculation/42190/2 "2025-03-14T11:01:54Z")

</div>

I think you are looking for [fn distribute\_rewards](https://sourcegraph.com/search?q=repo:%5Egithub%5C.com/dfinity/ic%24+f:gov+fn%5C+distribute_rewards%5C%28&patternType=regexp&sm=0).

---

<div class="post-metadata">

**Author:** ![dostro](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/dostro/32/1161_2.png) [@dostro](https://forum.dfinity.org/u/dostro)\
**Post date:** [March 14, 2025, 1:12pm UTC](https://forum.dfinity.org/t/icp-sns-staking-rewards-calculation/42190/3 "2025-03-14T13:12:06Z")

</div>

I’m looking for a way to calculate the estimated APY when creating a neuron, specifically the [Voting rewards](https://dashboard.internetcomputer.org/governance) calculation on the dashboard:

 ![image](https://us1.discourse-cdn.com/flex023/uploads/dfn/original/3X/1/b/1b0104c7f252682021f0acaf624591b852d0e857.jpeg)

---

<div class="post-metadata">

**Author:** ![ngurian](https://avatars.discourse-cdn.com/v4/letter/n/ac8455/32.png) [@ngurian](https://forum.dfinity.org/u/ngurian)\
**Post date:** [March 14, 2025, 1:53pm UTC](https://forum.dfinity.org/t/icp-sns-staking-rewards-calculation/42190/4 "2025-03-14T13:53:13Z")

</div>

Hello @dostro  
For the ICP Dashboard here is how we fetch the data for the Estimate Rewards

```auto
  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

```auto
    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);
    } 
  }

```

---

<div class="post-metadata">

**Author:** ![dostro](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/dostro/32/1161_2.png) [@dostro](https://forum.dfinity.org/u/dostro)\
**Post date:** [March 14, 2025, 5:11pm UTC](https://forum.dfinity.org/t/icp-sns-staking-rewards-calculation/42190/5 "2025-03-14T17:11:26Z")

</div>

Thank you! Will take a look in the coming weeks and let you know how it goes.

---

<div class="post-metadata">

**Author:** ![Vitalii](https://avatars.discourse-cdn.com/v4/letter/v/d6d6ee/32.png) [@Vitalii](https://forum.dfinity.org/u/Vitalii)\
**Post date:** [April 7, 2025, 11:46am UTC](https://forum.dfinity.org/t/icp-sns-staking-rewards-calculation/42190/6 "2025-04-07T11:46:52Z")

</div>

hi @ngurian,  
could you please take a look?

I have a private method that returns dailyRewards (lastRewardsRoundTotalAvailableIcp / totalVotingPower)

```auto
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:

1. APR:  
Here I can’t understand what is 4 (ageBonus last devide action)? Is it a constant value or where it can be taken?

```auto
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,
    )}%`
  }

```

1. Projected Rewards:  
I am confused where should I take the votingPowerE8s variable??

```auto
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",
    }
  }

```

---

<div class="post-metadata">

**Author:** ![dostro](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/dostro/32/1161_2.png) [@dostro](https://forum.dfinity.org/u/dostro)\
**Post date:** [May 15, 2025, 1:03pm UTC](https://forum.dfinity.org/t/icp-sns-staking-rewards-calculation/42190/7 "2025-05-15T13:03:04Z")

</div>

@ngurian could you please help Vitalii with his questions? we’re still blocked here

---

<div class="post-metadata">

**Author:** ![Dylan](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/dylan/32/18010_2.png) [@Dylan](https://forum.dfinity.org/u/Dylan)\
**Post date:** [May 15, 2025, 4:25pm UTC](https://forum.dfinity.org/t/icp-sns-staking-rewards-calculation/42190/8 "2025-05-15T16:25:50Z")

</div>

> [@Vitalii](#):
>
> APR:  
> Here I can’t understand what is 4 (ageBonus last devide action)? Is it a constant value or where it can be taken?

Dividing by 4 scales the age bonus linearly from 0% to 25%, based on the neuron’s age.

The code is currently doing this:

```auto
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`:

```auto
ageBonus = 1 + (ageRatio * 0.25);

```

 ![image](https://us1.discourse-cdn.com/flex023/uploads/dfn/original/3X/c/d/cd07d99f0ecb444402b39b57e198c31124783610.png)

---

<div class="post-metadata">

**Author:** ![Dylan](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/dylan/32/18010_2.png) [@Dylan](https://forum.dfinity.org/u/Dylan)\
**Post date:** [May 15, 2025, 4:28pm UTC](https://forum.dfinity.org/t/icp-sns-staking-rewards-calculation/42190/9 "2025-05-15T16:28:27Z")

</div>

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%.

---

<div class="post-metadata">

**Author:** ![Dylan](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/dylan/32/18010_2.png) [@Dylan](https://forum.dfinity.org/u/Dylan)\
**Post date:** [May 15, 2025, 4:34pm UTC](https://forum.dfinity.org/t/icp-sns-staking-rewards-calculation/42190/10 "2025-05-15T16:34:40Z")

</div>

> [@Vitalii](#):
>
> Projected Rewards:  
> I am confused where should I take the votingPowerE8s variable??

For an NNS neuron, you can call [get\_neuron\_info](https://dashboard.internetcomputer.org/canister/rrkah-fqaaa-aaaaa-aaaaq-cai#get_neuron_info) on the NNS Governance canister.

 ![image](https://us1.discourse-cdn.com/flex023/uploads/dfn/original/3X/4/8/482c816a02dd0da1c7658aeb6573ed15891cad1e.png)

---

<div class="post-metadata">

**Author:** ![Dylan](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/dylan/32/18010_2.png) [@Dylan](https://forum.dfinity.org/u/Dylan)\
**Post date:** [May 15, 2025, 4:48pm UTC](https://forum.dfinity.org/t/icp-sns-staking-rewards-calculation/42190/11 "2025-05-15T16:48:09Z")

</div>

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.

> <https://github.com/dfinity/ic/blob/2c3d1cbacb353597167b0352f15b0a7a3a0791e8/rs/sns/governance/src/neuron.rs#L194>
