Steem Delegations Tutorial Part One
utopian-io·@cutemachine·
0.000 HBDSteem Delegations Tutorial Part One
Delegating your Steem Power to another user can be a great way to invest in Steem and Steemit. You can get an excellent annual percentage rate (APR) on your investment if you delegate your Steem Power to another user. This is part one of a tutorial series about Steem delegations. There will be three parts in total.  ## Curriculum ### Part One You will learn how to … - get the current delegations for a user from the Steem blockchain - convert VESTS to Steem Power (SP) - show the information in a simple web application ### Part Two You will learn how to … - get the transaction history for an account - how to filter relevant data from the historical transaction data - calculate the annual percentage rate for your investments - show the information in a simple web application ### Part Three You will learn how to … - make a simple form for new delegations - delegate your Steem Power to another Steem user - to remove your delegation - to increase or decrease your delegation ## Requirements Knowledge of JavaScript is sufficient to go through this tutorial. ### Difficulty Intermediate ## Steem Delegation Tutorial One In this tutorial, you will learn how you can retrieve a user’s delegations. You can use my handle to see some data if you do not have made any delegations to another user yet. My user handle is @cutemachine. The web application we will build in this tutorial is quite simple. There is just one input field where one can enter a Steemit user. The application will then get the information from the blockchain and present it to the user in a table. [You can see the running application we will build in this tutorial by following this link](http://flamboyant-raman-46bb3b.netlify.com/). ## Technologies Used - [SteemJS—Steem.js the official JavaScript library for the Steem blockchain](https://github.com/steemit/steem-js) - [Next generation JavaScript](https://babeljs.io') - [Hyperapp—1 KB JavaScript library for building frontend applications](https://hyperapp.js.org') - [Hyperapp Router—Declarative routing for Hyperapp using the History API](https://github.com/hyperapp/router') - [Bulma—free and open source CSS framework based on Flexbox](https://bulma.io') - [Fontawesome—the web’s most popular icon set](https://fontawesome.com') - [Parcel—Blazing fast, zero configuration web application bundler](https://parceljs.org') ## Getting Started You can find [the code for this tutorial on GitHub](https://github.com/cutemachine/steem-delegations). You should clone the project to make it easier for yourself to follow along. I will not explain every line of code, but will instead give you a rundown of the most critical parts. When you have cloned the project, you should install the dependencies with `yarn`. When the installation has finished, you can run the new app with `yarn start`. These are the steps in more detail: git clone https://github.com/cutemachine/steem-delegations.git cd steem-delegations yarn yarn start When the dev server is running, then you can point your browser to the URL given in the Terminal. Normally this is [localhost:1234](http://localhost:1234). ### Application Control Flow The important files in the repository are: - src/views/HomeView.js - src/state/index.js - src/actions/index.js - src/common/utils.js The files `index.html`, `index.js`, `src/view/MainView.js` are needed to bootstrap the application. All you need to know is that at the end of this bootstrap process stands the rendering of the home view. You can see the home view when you start the application in your browser. It has the input field where you can enter the Steem username and request the Steem delegation data by clicking the *Request Delegations* button. In HomeView.js is the code to render the HTML input field: ```` <input onkeyup={ event => { (event.keyCode === 13) ? actions.submitUsername() : actions.changeUsername(event.target.value) } } class="input" type="text" placeholder="username …" autofocus /> ```` <br /> You can see that when a user enters a key into the input field, the action `changeUsername` will be called. You can find this action in `src/actions/index.js`. Here are the two actions used by the input field: ```` changeUsername: (value) => (state, actions) => { return { username: value } }, submitUsername: () => (state, actions) => { actions.requestDelegations(state.username) }, ```` <br /> In HyperApp all changes in application state will be done through actions. These actions take the user’s input and will lead to state changes or new actions being called. You can see that `changeUsername` takes a value, the value from the input field, and returns an object `{ username: value }`. This action will update the state in `src/state/index.js`. Here is the complete state tree of our application: ```` { location: location.state, isNavbarMenuActive: false, username: '', delegations: [], dynamicGlobalProperties: {}, } ```` <br /> You can ignore the location state. It is only used by the HyperApp router. Also ignore `isNavbarMenuActive`. It handles the menu in the Navbar. The username will be stored in `username` as a string. And the `delegations` will hold the array of delegations we get back from the steem-js lib by calling the `requestDelegations` action. The last state is called `dynamicGlobalProperties` and is an object. This state-piece will be filled by a call to the steem-js lib as well. The `submitUsername` action will not change the state tree directly but will trigger the action `requestDelegations`. When the user has entered her username and has submitted the field by pressing return or by clicking the button, the `requestDelegations` action will be invoked. ```` … setDynamicGlobalProperties: obj => state => ({ dynamicGlobalProperties: obj }), setDelegations: arr => state => ({ delegations: arr }), requestDelegations: (username) => async (state, actions) => { try { const [delegations, dynamicGlobalProperties] = await Promise.all([ steem.api.getVestingDelegationsAsync(username, -1, 100), steem.api.getDynamicGlobalPropertiesAsync() ]) if (!delegations) { throw new Error('Sorry, could not get delegations for user.')} if (!dynamicGlobalProperties) { throw new Error('Sorry, could not get dynamic global properties.')} actions.setDelegations(delegations) console.log('Vesting Delegations', delegations) actions.setDynamicGlobalProperties(dynamicGlobalProperties) console.log('Dynamic Global Properties', dynamicGlobalProperties) } catch (error) { actions.error.set(error.message) } }, … ```` <br /> Now, this is where the rubber hits the road. I think especially this part needs a little explanation: ```` const [delegations, dynamicGlobalProperties] = await Promise.all([ steem.api.getVestingDelegationsAsync(username, -1, 100), steem.api.getDynamicGlobalPropertiesAsync() ]) ```` <br /> Here we make two calls to the steem-js library. We do not want to block the user interface. Therefore we call the API asynchronously. We use the new async / await syntax. Because we can make the two calls in parallel, we use `Promise.all` and provide an array of the two API calls. When the Promise will resolve we will get back an array which we destructure with `const [delegations, dynamicGlobalProperties] = `. When all goes well, we will have an array with the delegation information in the `delegations` variable and an object with the dynamic global properties in the dynamicGlobalProperties variable. Let’s have a look at some example data you might get back from the Steem blockchain. Data Structure returned by the async call to the Steem API `steem.api.getVestingDelegationsAsync(username, -1, 100)`: ```` [{ delegatee: "jerrybanfield”, delegator: "cutemachine”, id: 620276, min_delegation_time: "2018-02-05T16:44:21”, vesting_shares: "2248194.554501 VESTS" }] ```` <br /> As you can see, the delegation amount is given in VESTS. You might have expected to see STEEM or Steem Power here as the unit. But we have to convert VESTS to SP ourselves. To convert VESTS to SP, we will use the two functions in `src/common/utils.js`. ```` export const unitString2Number = (stringWithUnit) => Number(stringWithUnit.split(' ')[0]) export const vests2Steem = (vestingShares, dynamicGlobalProperties) => { const { total_vesting_fund_steem, total_vesting_shares } = dynamicGlobalProperties const totalVestingFundSteemNumber = unitString2Number(total_vesting_fund_steem) const totalVestingSharesNumber = unitString2Number(total_vesting_shares) const vestingSharesNumber = unitString2Number(vestingShares) return (totalVestingFundSteemNumber * (vestingSharesNumber / totalVestingSharesNumber)).toFixed(6) } ```` <br /> `unitString2Number()` can be used to convert the vesting_shares to a JavaScript Number. It will be used in `vests2Steem`. `vests2Steem` will be used to convert VESTS to SP. Here we need to make use of the dynamic global properties. To calculate the conversion properly, we need to know the total_vesting_fund_steem and total_vesting_shares. Data structure returned by the async call to the Steem API `steem.api.getDynamicGlobalPropertiesAsync()`: ```` { average_block_size: 17395, confidential_sbd_supply: "0.000 SBD", confidential_supply: "0.000 STEEM", current_aslot: 20215178, current_reserve_ratio: 15036532, current_sbd_supply: "9571439.677 SBD", current_supply: "264562933.899 STEEM", current_witness: "blocktrades", head_block_id: "01337ebdd28d40cb21bb1b6772794047a9737647", head_block_number: 20151997, id: 0, last_irreversible_block_num: 20151982, max_virtual_bandwidth: "19866352688824320000", maximum_block_size: 65536, num_pow_witnesses: 172, participation_count: 128, pending_rewarded_vesting_shares: "312264752.226184 VESTS", pending_rewarded_vesting_steem: "151881.086 STEEM", recent_slots_filled: "340282366920938463463374607431768211455", sbd_interest_rate: 0, sbd_print_rate: 10000, time: "2018-02-24T13:58:54", total_pow: 514415, total_reward_fund_steem: "0.000 STEEM", total_reward_shares2: "0", total_vesting_fund_steem: "186284011.937 STEEM", total_vesting_shares: "380674659866.674495 VESTS", virtual_supply: "267334853.874 STEEM", vote_power_reserve_rate: 10 } ```` <br /> Good. Now we have all the pieces we need to render the result table. The rendering is done in the `HomeView.js` file. ```` let delegationItems = state.delegations.map((item, index) => { return ( <tr> <td>{item.delegator}</td> <td>{item.delegatee}</td> <td>{unitString2Number(item.vesting_shares)} VESTS</td> <td>{vests2Steem(item.vesting_shares, state.dynamicGlobalProperties)} SP</td> <td>{item.min_delegation_time}</td> </tr> ) }) ```` <br /> As you can see, we take the delegations from our state tree and iterate over it with `map`. The call to `map` will return a new array with all the delegations the user in question has made. You can also see how we call our `vests2Steem` utility function to convert the VESTS to SP. Easy wasn’t it. ## Conclusion It is not too complicated to retrieve a user’s delegation from the blockchain. But you need to know where to get all the pieces to the puzzle you want to solve. In the next part, we will see how we can retrieve all the rewards a user received for her delegations, which will be even trickier. Stay awesome, Jo <br /><hr/><em>Posted on <a href="https://utopian.io/utopian-io/@cutemachine/steem-delegations-tutorial-part-one">Utopian.io - Rewarding Open Source Contributors</a></em><hr/>