
With a few lines of solidity code you can implement a staking mechanism, one of the most powerful incentive schemes in token economics.
Any mistakes that I make is an investment in my future. — Rose Namajunas
Someone is said to have a stake in a venture when they contribute some assets in exchange of exercising some level of control, influence, or participation in its activities.
In the cryptocurrency world this is understood as giving users some kind of right or reward for as long as they don’t transfer some tokens in their possession. A staking mechanism usually encourages token holding against token trading, which in turn is expected to drive up the token valuation.
At TechHQ we believe that knowledge exists to be shared, and in this article we are going to show how to implement a staking mechanism in solidity. The whole project including development environment and tests is available from our public github.
To build this staking mechanism we will need:
Let’s get on with it.
A staking token can be created as an ERC20 token. I’m going to need SafeMath and Ownable later on, so let’s import and use those as well.
<a href="https://medium.com/media/7cac94e3a2951a24e94eb21c60e37d14/href">https://medium.com/media/7cac94e3a2951a24e94eb21c60e37d14/href</a>
To make the code more readable I’m going to follow the function names from ERC20 and create equivalents to get the data from the stakes mapping.
<a href="https://medium.com/media/d7f48826b3b52ae20e9bf4e190ad3771/href">https://medium.com/media/d7f48826b3b52ae20e9bf4e190ad3771/href</a>
The methods implemented allow just to add a stakeholder, remove a stakeholder, and verify whether an address belongs to a stakeholder. Other more efficient implementations are surely possible but I like this one for readability.
<a href="https://medium.com/media/de236062f5b33e4f0ab2f4f70c2dd610/href">https://medium.com/media/de236062f5b33e4f0ab2f4f70c2dd610/href</a>
A stake at its simplest form will need to record the stake size and the stake holder. A really simple implementation of this could be just a mapping from the address of the stakeholder to the stake size.
<a href="https://medium.com/media/5a625d386c0201f667458c329199132b/href">https://medium.com/media/5a625d386c0201f667458c329199132b/href</a>
To make the code more readable I’m going to follow the function names from ERC20 and create equivalents to get the data from the stakes mapping.
<a href="https://medium.com/media/fa26e1f9b5776b90ce085cdbbc371369/href">https://medium.com/media/fa26e1f9b5776b90ce085cdbbc371369/href</a>
We are now going to give STK holders the capability to create and remove stakes. We will burn the tokens as they are staked to stop users from transferring them until the stake is removed.
Please note that on stake creation _burn will revert if the user tries to stake more tokens than he owns, and on stake removal the update of the stakes mapping will revert if there is an attempt to remove more tokens that were staked.
Finally, we use addStakeholder and removeStakeholder to have a record of who has stakes, to be used later in the rewards system.
<a href="https://medium.com/media/131b1b04f406959cd27aaa17113e98d3/href">https://medium.com/media/131b1b04f406959cd27aaa17113e98d3/href</a>
Rewards mechanisms can have many different implementations and be quite heavy to run. For this contract we will implement a very simple version where the stakeholders periodically receive a reward in STK tokens equivalent to a 1% of their individual stakes.
In more sophisticated contracts the distribution of rewards would be automatically triggered when certain conditions are met, but in this case we will let the owner trigger it manually. Following best practice we will also keep track of the rewards and implement a method to withdraw them.
As before, to make the code readable we have followed the naming conventions from the ERC20.sol contract, first the data structure and data management methods:
<a href="https://medium.com/media/820aef9972e7a18a6c8f350f4cacba52/href">https://medium.com/media/820aef9972e7a18a6c8f350f4cacba52/href</a>
Follow the methods to calculate, distribute and withdraw rewards:
<a href="https://medium.com/media/8eaf82138fa220e799957f86717d6b61/href">https://medium.com/media/8eaf82138fa220e799957f86717d6b61/href</a>
No contract can be complete without a comprehensive set of tests. I tend to produce a bug per function at least, and often things don’t work the way I think they do. You could say I get things wrong most of the time, and surely I’m not alone in this.
Apart from allowing you to produce code that works, tests also are quite useful in developing a process to set up and use contracts. I always write my Getting Started documentation from the code that sets up the environment for the tests.
Follows an extract of how the test environment is set up and used. We will mint 1000 STK tokens and give them to a user to play with the system. We use truffle for testing which gives us the accounts to use.
<a href="https://medium.com/media/7ec717cd41c86a819137827eabe15a49/href">https://medium.com/media/7ec717cd41c86a819137827eabe15a49/href</a>
When creating tests I always write the tests that make the code revert, but those are not very interesting to see. The test for createStake shows what needs to be done to create a stake, and what should change afterwards.
It is important to notice how in this staking contract we have two parallel data structures, one for STK balances and one for stakes and how their sum remains constant through stake creation and removal. In this example we give 3 STK wei to the user, and the sum of balance plus stakes for that user will always be 3.
<a href="https://medium.com/media/d69ab1b1ff96e2ae0b2be64a4c3a27f2/href">https://medium.com/media/d69ab1b1ff96e2ae0b2be64a4c3a27f2/href</a>
For rewards, the test below shows how the owner fires up the distribution of fees, with the user getting a reward of a 1% of his stake.
<a href="https://medium.com/media/a8a0af577391b17ccc782b4a6ec4f6f4/href">https://medium.com/media/a8a0af577391b17ccc782b4a6ec4f6f4/href</a>
The total supply for STK is increased when rewards are distributed, and this test shows how the three data structures (balances, stakes and rewards) relate to each other. The amount of existing and promised STK will always be the amount minted on creation plus the amount distributed in rewards, which might or might not be minted. The amount of STK minted on creation will be equal to the sum of balances and stakes until a distribution is done.
<a href="https://medium.com/media/e88fac51c43290b8d70c0d895a8ebf09/href">https://medium.com/media/e88fac51c43290b8d70c0d895a8ebf09/href</a>
A staking and rewards mechanism is a powerful incentive tool that only needs to be as complex as we want to make it. The methods provided in the ERC20 standard and SafeMath allows us to code it in about 200 lines of sparse code.
Please feel free to use the code in our public github for your own purposes, or to contact us if you would like our help to implement a production version of this pattern. And if you liked this article, please press that clap button for a little while.
Thanks to Vlad Fărcaş for inspiring some of this code, to Sergio Pereira and Tiago Martins for their reviews for publication and especially to Bernardo Vieira for teaching me how to do real world blockchain applications.