
Recap: In the previous tutorials we build a burnable token, we also learned and build a capped token, and make that token time sensitive. To learn more, check out our previous tutorials. In this tutorial, we will build a dividend token.
Prerequisite:
A dividend is the distribution of reward from a portion of company’s earnings and is paid to a class of its shareholders. So a token which pays out profits to its investor as dividends is a dividend token. There are multiple ways to pay the dividend in the token economy. Today we will discuss how to build this feature into a smart contract.
Dividends are standard practice to distribute earnings to investors. Dividends also create a passive income source for your investors. This will attract long-term investors and create incentives for holding tokens.
We will tackle below main problems which we usually face while building a dividend token.
Our code:
Now let's breakdown our dividend Token code.
string public name = "Dividend Token";
string public symbol = "DIV";
uint8 public decimals = 0;
uint256 public totalSupply\_ = 1000000;
uint256 totalDividendPoints = 0;
uint256 unclaimedDividends = 0;
uint256 pointMultiplier = 1000000000000000000;
address owner;
struct account{
uint256 balance;
uint256 lastDividendPoints;
}
mapping(address => account) public balanceOf;
Now let's dive into our main dividend logic.
modifier updateDividend(address investor) {
uint256 owing = dividendsOwing(investor);
if(owing > 0) {
unclaimedDividends = unclaimedDividends.sub(owing);
balanceOf[investor].balance = balanceOf[investor].balance.add(owing);
balanceOf[investor].lastDividendPoints = totalDividendPoints;
}
_;
}
function dividendsOwing(address investor) internal returns(uint256){
uint256 newDividendPoints = totalDividendPoints.sub(balanceOf[investor].lastDividendPoints);
return (balanceOf[investor].balance.mul(newDividendPoints)).div(pointMultiplier);
}
function disburse(uint256 amount) onlyOwner public {
totalDividendPoints = totalDividendPoints.add((amount.mul(pointMultiplier)).div(totalSupply_));
totalSupply_ = totalSupply_.add(amount);
unclaimedDividends = unclaimedDividends.add(amount);
}
updateDividend — This will calculate dividends owed by an account. It will call dividendsOwing
method, which we will see in a minute. After finding out what dividends owe to an account, we will update our unclaimedDividends
variable and then we will update investor’s account balance and lastDividendPoints
.
**_We will use this modifier with every transfer method for both sender and receiver._**
dividendsOwing — This function has our main logic to calculate dividends. it will calculate dividends using the following logic.
new dividend = totalDividendPoints - investor's lastDividnedPoint
investor's dividend = ( investor's balance * new dividend ) / points multiplier
You can see we are calculating dividends based on investor’s balance. This function will only be called by the contract owner.
disburse — This function will be called to pay dividends to the contract which will increase totalDividendPoints
, totalSupply_
and unclaimedDividends
. We are using pointmultiplier (10¹⁸)
to steer clear of a rounding error.
totalDividendPoints += (amount * pointMultiplier ) / totalSupply_
The Basic Formula for the dividend for an investor according to his/her balance is-
investor's dividend = Total Dividend / investor’s balance
Other parts of the contract are implementing with standard ERC20 methods. Which we will not discuss in this tutorial.
Now let’s write a test case where we will see if above is working properly.
it('dividend Test' , async() => {
await this.tokenInstance.transfer(web3.eth.accounts[1],100000, {from : web3.eth.accounts[0]});
await this.tokenInstance.disburse(100000);
await this.tokenInstance.transfer(web3.eth.accounts[2],100000, {from : web3.eth.accounts[1]});
const investor_1_balance = await this.tokenInstance.balanceOf(web3.eth.accounts[1]);
const investor_2_balance = await this.tokenInstance.balanceOf(web3.eth.accounts[2]);
const totalSupply = await this.tokenInstance.totalSupply_();
assert.equal( totalSupply, 1100000);
assert.equal(investor_1_balance, 10000);
assert.equal(investor_2_balance, 100000);
})
Below are the steps which are getting performed by the test case.
So, today we created a dividend token. We learned how to tackle a rounding error problem and a multiple dividend problem. There are multiple ways to create dividends for your investors in the token economy. Proof of stake protocol also has similar properties, which we will discuss in future.
Do not use this code in production, this code is for educational purpose. If you don’t understand something or want to learn something else let us know in comments. You can view full code in my GitHub repository.
Originally published:
November 15, 2018