[Tutorial] Calculating your Steem Power using SteemJS [bonus content: an Angular Pipe that does it for you]

in #steemdev7 years ago (edited)

A few posts ago we calculated a user's reputation. Next up is calculating your Steem Power.

For this we're going to fetch the user's info again, but also something called Steem's "dynamic global properties", which includes information about the total vesting shares and the total STEEM fund currently available in the blockchain.

Getting the user info

Just now I realized that I never properly explained how to fetch a user's info using SteemJS. It's pretty simple:

getUser(username) {
    return steem.api.getAccounts([username]);
}



The getAccounts() method expects an array so you could theoretically fetch multiple users at once. We only need one right now, so we just wrap the one username in an array ([name]). We return the promise, which will resolve when the API call is done.

The important part that we need is the user's vesting_shares property:


My vesting shares at the moment of writing this post

Vesting shares and Steem Power

For more information about what vesting shares mean see these three posts.

What's important for now is that your vesting shares are a fraction of the total amount of vesting shares on the Steem blockchain. This means that you are invested in Steem by owning a percentage of the total STEEM it has in its fund.

In other words, your value in STEEM is the fraction of the total VESTS you own multiplied by the total STEEM in the fund.

total_vesting_fund_steem * (user's vesting_shares / total_vesting_shares)

Getting the total vesting shares and fund

To know what the total vesting shares and total fund are, you need to call another API endpoint called getDynamicGlobalProperties().

The result that this method returns is an object containing (among others) the following properties:

{
    ...
    total_vesting_fund_steem: "183124826.141 STEEM"
    total_vesting_shares: "377884186141.130073 VESTS"
    ...
}

Calculating the user's Steem Power

Now that we know how to fetch both the user and the dynamic global properties, we have all the information we need. As soon as both calls are resolved (we wait for that using Promise.all() we can calculate the user's Steem Power.

As you might have noticed all the properties we need are strings, ending with the word "VESTS" or "STEEM". To calculate we do need to convert those to numbers first.

function getSteemPower(username) {
    return Promise.all([
        steem.api.getAccounts([username]),
        steem.api.getDynamicGlobalProperties()
    ]).then(([user, globals]) => {
        const totalSteem = Number(globals.total_vesting_fund_steem.split(' ')[0]);
        const totalVests = Number(globals.total_vesting_shares.split(' ')[0]);
        const userVests = Number(user[0].vesting_shares.split(' ')[0]);

        return totalSteem * (userVests / totalVests);
    });
}



And there you have it! Don't forget that this method returns a promise too, so to use the value you'll have to catch it in another .then().

A working example of this code can be found here: https://jsfiddle.net/u9xzzbqd/


Bonus content: an Angular pipe

Just like when we calculated the user's reputation, calculating the Steem Power is a great candidate for a pipe if you're using Angular. That way we can just put this in our template:

{{uer.vesting_shares | steemPower}}

To do that, we need some preparation first. Calling an asynchronous method inside a pipe is not a good idea, so we'll have to fetch the blockchain information beforehand. One important reason for this is that the dynamic global properties are, well, dynamic. Fetching them once and using that value everywhere means that all calculations use the same values. It would be really weird if one part of your page showed 1000 SP, and another part showed 1001 SP because when the second value was calculated it already used a newer (higher) value of the total STEEM fund.

To solve this I created a steemService that fetches the dynamicGlobalProperties once when the application is loaded, and stores that information in the property steemService.globals. That way I can access them from anywhere without having to do additional calls. With that information, I can now give you the Angular pipe I used:

steem-power.pipe.ts

import {Pipe, PipeTransform} from '@angular/core';
import {SteemService} from './steem.service';

@Pipe({
    name: 'steemPower'
})
export class SteemPowerPipe implements PipeTransform {
    private totalSteem;
    private totalShares;

    constructor(private steemService: SteemService) {
        steemService.globals$.subscribe(globals => {
            this.totalSteem = this.toNumber(globals.total_vesting_fund_steem);
            this.totalShares = this.toNumber(globals.total_vesting_shares);
        });
    }

    transform(value: string): string {
        const steemPower = this.totalSteem * (this.toNumber(value) / this.totalShares);

        return steemPower.toLocaleString() + ' SP';
    }

    private toNumber(string) {
        return Number(string.split(' ')[0]);
    }
}

As you can see I separated the toNumber method to keep clutter out of the main functions, but in essence this does exactly what the jsFiddle example above does. The difference is that now we can use it in our templates a lot easier.


I hope this was useful, let me know if you have any comments and/or questions!

Sort:  

The math is a little beyond me, but the working example was exactly what I needed for it to make some sense.

Thanks.

You're welcome, glad I could help you make some sense of it!

Very good your help and your tricks, thanks for sharing!

You're quite welcome!

This is one very useful info, thanks! If you are into good infos, I am blogging daily about offgrid lighting the non-solar, non-wind approach. Please visit my posts it may interest you. Upvoted anf followed you.

Congratulations @pilcrow! You have completed some achievement on Steemit and have been rewarded with new badge(s) :

Award for the total payout received

Click on any badge to view your own Board of Honor on SteemitBoard.
For more information about SteemitBoard, click here

If you no longer want to receive notifications, reply to this comment with the word STOP

By upvoting this notification, you can help all Steemit users. Learn how here!

wow impressive keep it up

Goeie info dit! Dank je wel voor het delen! Upvoted, followed, resteemd :) Thanx! :)

Is there an update for https://jsfiddle.net/u9xzzbqd/ ?? Seems to not be working..

Looks like the signatures of these functions changed some time. The parameters for Promise.all should promises themselves. So I tweaked the code a little. I am not sure if this is the best way as I had create a new promise for each API call.

You can check it out here https://jsfiddle.net/u0wwf829/2/

Thanks for the update. Checking it out now.