Write a Steemit Web App: Part 13 - How to Calculate a Vote's RShares

in #steemdev7 years ago (edited)

(Previous Post: Part 12)

In the previous post, we calculated how much a vote was worth after it had been cast and committed to the blockchain. But, how can you determine the amount that a vote will be worth before the vote is cast (perhaps to allow the user to make an informed decision about how much voting power to use)?

Reward Shares

As we saw in the last post, each vote cast results in a "reward shares" (rshares) being contributed by the voter. This is used to determine the percentage of the reward fund that is paid out to the author at the end of the 7 days of voting.

rshares is calculated by the vote_evaluator (source code) as the blockchain is processed and database updated. It uses values from multiple sources in the calculation:

First, the user's current Voting Power must be calculated. Voting Power makes each vote cast worth less than the previous vote cast, and regenerates linearly over five days (20% of a user's total Voting Power regenerates per day).

When the user casts the vote, the Vote Weight (percentage) is set. In the Condenser user interface, this is done by means of a slider that appears after clicking Upvote, unless the user has less than 500 Steem Power (and then they will not see the vote percentage slider and can only place 100% votes). Vote Weight is multiplied by Voting Power in order to determine a Weighted Voting Power.

From the Dynamic Global Properties, vote_power_reserve_rate (10) is multiplied by the number of days represented in the STEEM_VOTE_REGENERATION_SECONDS constant (5 days) to calculate max_vote_denom. This appears to be a smoothing factor of sorts, to make votes worth more so long as the user is not voting more often than 10 times a day. Note: I really could use clarification of the purpose of max_vote_denom from someone familiar with it.

Use Weighted Voting Power and max_vote_denom as follows to calculate Used Voting Power:

used_power = (weighted_voting_power + max_vote_denom - 1) / max_vote_denom


Determine the user's effective_vesting_shares by subtracting delegated_vesting_shares from the account's vesting_shares and adding in any received_vesting_shares.

Finally, to calculate rshares, multiply the user's effective_vesting_shares by the Used Voting Power.

Code!

Here is a JavaScript implementation of what the Steem vote_evaluator code performs:

const STEEMIT_VOTE_REGENERATION_SECONDS = 5 * 60 * 60 * 24; // it takes 5 days to regenerate 100% voting power
const STEEMIT_100_PERCENT = 10000

// Adjust these values to use something other than 100% for voting power and vote weight. 
// Note: Value = percentage * 100, so 100% = 10000, 25.33% = 2533, etc.
const current_voting_power = STEEMIT_100_PERCENT;
const vote_pct_weight = STEEMIT_100_PERCENT;

steem.api.getAccountsAsync(["jfollas"]).then(function(results) {
  const account = results[0];

  const acct_vesting_shares = parseFloat(
    account.vesting_shares.replace(" VESTS", "")
  );
  const acct_delegated_vesting_shares = parseFloat(
    account.delegated_vesting_shares.replace(" VESTS", "")
  );
  const acct_received_vesting_shares = parseFloat(
    account.received_vesting_shares.replace(" VESTS", "")
  );

  const effective_vesting_shares =
    acct_vesting_shares -
    acct_delegated_vesting_shares +
    acct_received_vesting_shares;

  console.log("acct_vesting_shares", acct_vesting_shares);
  console.log("acct_delegated_vesting_shares", acct_delegated_vesting_shares);
  console.log("acct_received_vesting_shares", acct_received_vesting_shares);
  console.log("effective_vesting_shares", effective_vesting_shares); 

  steem.api.getRewardFundAsync("post").then(function(fund) {
    const pot = parseFloat(fund.reward_balance.replace(" STEEM", ""));
    const total_r2 = parseInt(fund.recent_claims, 10);

    console.log("pot", pot)
    console.log("total_r2", total_r2) 
    
    steem.api.getDynamicGlobalPropertiesAsync().then(function(gprops) {
      const max_vote_denom = gprops.vote_power_reserve_rate * STEEMIT_VOTE_REGENERATION_SECONDS / (60*60*24);
      
      let used_power = (current_voting_power * vote_pct_weight) / STEEMIT_100_PERCENT;
      used_power = (used_power + max_vote_denom - 1) / max_vote_denom;

      let rshares = effective_vesting_shares * used_power / STEEMIT_100_PERCENT;
      rshares = Math.floor(rshares * 1000000)

      console.log("max_vote_denom", max_vote_denom);
      console.log("used_power", used_power);
      console.log("rshares", rshares);
      console.log("STEEM value", rshares * pot / total_r2); 
    });
  });
});



(Next Post: Part 14)

Sort:  

This tutorial is awesome! long time ago I wanted to understand these small parts of the code! but the code is still complicated for me (a lot of lines to search in).
The only part that I did not understand is this:
used_power = (weighted_voting_power + max_vote_denom - 1) / max_vote_denom

max_vote_denom is always equal to 50... means something like "50 votes are regenerated in 5 days"... because the vote_power_reserve_rate is the number of votes regenerated per day (Source).

Any ideas?
Good work. Thank you.

That part is still not very clear to me, either. That was directly taken from the C source code. When I get time, I was going to go through the history of that file to see if I could gain some insight from the series of commits that touched that line.

Hi @jfollas, I have not seen any of your posts for a while, which are so interesting.
Look, I just posted in detail how the steemit reward system works, I hope it helps.

Hi @jfollas, I read the code (I'm very tired, a lot of research), now it is more clear for me.
I posted an infographic about all this reward system, if you want to check out.

Awesome posting! Hope I saw this earlier, only one doubt, why need toMath.floor(rshares * 1000000) ? Since I don't find this operation in vote_evaluator source code.