Write a Steemit Web App: Part 4 - Calculating Steem Power

in #steem-dev7 years ago (edited)

(Previous Post: Part 3)

Steem Power

Steem Power is the measure of a person's influence on Steemit. Steem Power is accumulated as a reward for posting, commenting, and curating, as well as powering up STEEM. It is an investment in the platform - like being a shareowner of a corporation. The more Steem Power you have, the more each of your upvotes is worth.

Steem Power can also be delegated from one person to another. For example, when someone first signs up for an account on Steemit, they are delegated something like 27 Steem Power so that they can start upvoting posts (only worth about $0.01 per upvote, but it's still something).

Vesting Shares

Within an Account object, there are two fields that tracks how many shares the account has: vesting_shares and received_vesting_shares. As the names may suggest, vesting_shares is what the account has accumulated as a reward over time, and received_vesting_shares is what others have delegated to the account.

These are stored as string values, however, with the unit of measure "VESTS" appended onto the end:

// steem.api.getAccounts()

{
...
  received_vesting_shares: "57000.000000 VESTS",
  vesting_shares: "225696.822060 VESTS",
...
}

In order to use the values in calculations, we must parseFloat() the string with the "VESTS" suffix removed:

let vestingShares = parseFloat(result[0].vesting_shares.replace(" VESTS", ""))
let receivedVestingShares = parseFloat(result[0].received_vesting_shares.replace(" VESTS", ""))

Steem Power

Vesting Shares itself is not the same as Steem Power.

When an account Powers Up, it transfers STEEM (the liquid currency) into a platform-wide investment fund and is given a number of vesting shares in return. The account's Steem Power is the percentage of all of that STEEM that is allocated to the account - the more vesting shares that an account owns, the more of that STEEM it represents. This is it's Steem Power.

In order to retrieve the total STEEM in the investment fund as well as the total number of platform-wide vesting shares have been allocated, we must make an API call using the getDynamicGlobalProperties() function:

steem.api.getDynamicGlobalPropertiesAsync()
  .then(function (gprops) {
     ...
  })

The Dynamic Global Properties contains a lot of accounting-type information:

  average_block_size: 6588,
  confidential_sbd_supply: "0.000 SBD",
  confidential_supply: "0.000 STEEM",
  current_aslot: 13570340,
  current_reserve_ratio: 20000,
  current_sbd_supply: "3285224.631 SBD",
  current_supply: "251239319.256 STEEM",
  current_witness: "riverhead",
  head_block_id: "00ce30a8dc185a38c4f009167fc62b80974f1b39",
  head_block_number: 13512872,
  id: 0,
  last_irreversible_block_num: 13512855,
  max_virtual_bandwidth: "5986734968066277376",
  maximum_block_size: 65536,
  num_pow_witnesses: 172,
  participation_count: 128,
  pending_rewarded_vesting_shares: "227066161.225193 VESTS",
  pending_rewarded_vesting_steem: "109711.857 STEEM",
  recent_slots_filled: "340282366920938463463374607431768211455",
  sbd_interest_rate: 0,
  sbd_print_rate: 10000,
  time :"2017-07-08T20:37:00",
  total_pow: 514415,
  total_reward_fund_steem: "0.000 STEEM",
  total_reward_shares2: "0",
  total_vesting_fund_steem: "179266708.519 STEEM",
  total_vesting_shares: "370719133044.262656 VESTS",
  virtual_supply: "253058380.513 STEEM",
  vote_power_reserve_rate: 10
}

From all of this, we are only interested in two values for calculating Steem Power: total_vesting_fund_steem and total_vesting_shares. And like the Account values above, we need to trim the units suffix from each string value and then use parseFloat() to convert to a number that can be used in a calculation:

  let totalVestingFundSteem = parseFloat(gprops.total_vesting_fund_steem.replace(" STEEM", ""))
  let totalVestingShares = parseFloat(gprops.total_vesting_shares.replace(" VESTS", ""))

Putting it all together

The basic formula to calculate an Account's Steem Power is:

Total_Vesting_Fund_Steem * (Account_Vesting_Shares / Total_Vesting_Shares)

steem.api.getAccountsAsync([accountName])
  .then(function (result) {
     ...
    steem.api.getDynamicGlobalPropertiesAsync()
      .then(function (gprops) {
        const totalVestingFundSteem = parseFloat(gprops.total_vesting_fund_steem.replace(" STEEM", ""))
        const totalVestingShares = parseFloat(gprops.total_vesting_shares.replace(" VESTS", ""))
        const vestingShares = parseFloat(result[0].vesting_shares.replace(" VESTS", ""))
        const receivedVestingShares = parseFloat(result[0].received_vesting_shares.replace(" VESTS", ""))

        let totalSteemPower = (totalVestingFundSteem * ((vestingShares + receivedVestingShares) / totalVestingShares))

        if (totalSteemPower == null) {
          totalSteemPower = 0
        }

        vm.$set(obj, 'sp', totalSteemPower.toFixed(3))
        vm.$set(obj, 'vesting_shares', vestingShares.toFixed(3))
      })
  })

Animals

I've seen the terms "Minnows", "Dolphins", "Orcas", and "Whales" thrown out there, which is some indication of how much Steem Power an account has. What I haven't been able to determine was exact breakpoints (i.e., when does a Minnow become a Dolphin).

However, I took a stab at writing a function using some arbitrary breakpoints:

if (totalSteemPower >= 500000) {
  vm.$set(obj, 'animal', 'Whale')
} else if (totalSteemPower >= 100000) {
  vm.$set(obj, 'animal', 'Orca')
} else if (totalSteemPower >= 500) {
  vm.$set(obj, 'animal', 'Dolphin')
} else {
  vm.$set(obj, 'animal', 'Minnow')
}

I expect that if this is innaccurate, that there will be a comment to this post with clarifications.

javascriptlogo.png

(Next Post: Part 5)

Sort:  

should be:
vm.$set(vm.userData, 'sp', totalSteemPower.toFixed(3))
vm.$set(vm.userData, 'vesting_shares', vestingShares.toFixed(3))

not
vm.$set(obj, 'sp', totalSteemPower.toFixed(3))
vm.$set(obj, 'vesting_shares', vestingShares.toFixed(3))

I think. It errors out with obj and works with vm.userData. Unless there is a reason not to use vm.userData

I pass the data returned from getAccountsAsync to getDynamicGlobalPropertiesAsync function by setting a variable in this and accessing this way:

        function refreshAccountData(accountName,refresh=false) {
          return steem.api.getAccountsAsync([accountName])
            .then(function (result) {

...
                this.accountData = result
...
                steem.api.getDynamicGlobalPropertiesAsync()
                  .then(function (resultGlobal) {
                    result = this.accountData
...

It works perfect! Thanks for sharing this.

This entire series is amazing, thanks for putting it together. I'm building an Steem API-based web app in Ruby on Rails and your information has been invaluable. Thanks for helping me figure out some of the "mystery math" behind Steem.

Coin Marketplace

STEEM 0.20
TRX 0.25
JST 0.038
BTC 96907.08
ETH 3380.66
USDT 1.00
SBD 3.23