Since 2009, we have been utilizing our extensive expertise in blockchain technologies to help businesses, both large and small, maximize their efficiency.
Explore More
Since 2009, we have been utilizing our extensive expertise in blockchain technologies to help businesses, both large and small, maximize their efficiency.
Explore More18th May 2023
15 min read
To create a dividend ERC20 token, you will need to implement a smart contract on the Ethereum blockchain that tracks the balance of each token holder and distributes dividends to them based on the number of tokens they hold.
A dividend ERC20 token is a type of ERC20 token that allows its holders to receive periodic dividend payments based on the number of tokens they hold. In other words, a dividend token is designed to distribute profits or earnings to its token holders.
Dividend tokens work by incorporating a dividend distribution mechanism into their smart contract code. This mechanism is typically triggered at regular intervals, such as monthly or quarterly, and distributes a portion of the token's revenue or profits to its holders. The distribution is usually based on the proportion of tokens each holder holds.
For example, suppose you hold 1% of a dividend token's total supply, and the token generates $10,000 in revenue in a given month. If the token's dividend distribution rate is set at 5%, you would be entitled to receive $50 in dividends for that month.
//SPDX-License-Identifier: Unlicense
pragma solidity 0.8.4;
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { ReentrancyGuard } from "@openzeppelin/contracts/security/ReentrancyGuard.sol";
contract DToken is Ownable, ReentrancyGuard, ERC20 {
uint256 constant public MAX_SUPPLY = 100 ether;
uint32 constant private MULTIPLIER = 1e9; // in gwei
/// @notice Eth share of each token in gwei
uint256 dividendPerToken;
mapping(address => uint256) xDividendPerToken;
/// @notice Amount that should have been withdrawn
mapping (address => uint256) credit;
/// @notice State variable representing amount withdrawn by account in ETH
mapping (address => uint256) debt;
/// @notice If locked is true, users are not allowed to withdraw funds
bool public locked;
event FundsReceived(uint256 amount, uint256 dividendPerToken);
modifier mintable(uint256 amount) {
require(amount + totalSupply() <= MAX_SUPPLY, "amount surpasses max supply");
_;
}
modifier isUnlocked() {
require(!locked, "contract is currently locked");
_;
}
receive() external payable {
require(totalSupply() != 0, "No tokens minted");
dividendPerToken += msg.value * MULTIPLIER / totalSupply();
// gwei Multiplier decreases impact of remainder though
emit FundsReceived(msg.value, dividendPerToken);
}
constructor(string memory name_, string memory symbol_) ERC20(name_, symbol_) {
locked = true;
}
function mint(address to_, uint256 amount_) public onlyOwner mintable(amount_) {
_withdrawToCredit(to_);
_mint(to_, amount_);
}
function toggleLock() external onlyOwner {
locked = !locked;
}
/// @notice Withdraw Eth from contract onto the caller w.r.t balance of token held by caller
/// @dev Reentrancy Guard modifier in order to protect the transaction from reentrancy attack
function withdraw() external nonReentrant isUnlocked {
uint256 holderBalance = balanceOf(_msgSender());
require(holderBalance != 0, "DToken: caller possess no shares");
uint256 amount = ( (dividendPerToken - xDividendPerToken[_msgSender()]) * holderBalance / MULTIPLIER);
amount += credit[_msgSender()];
credit[_msgSender()] = 0;
xDividendPerToken[_msgSender()] = dividendPerToken;
(bool success, ) = payable(_msgSender()).call{value: amount}("");
require(success, "DToken: Could not withdraw eth");
}
/// @notice In extreme cases (i.e. lost tokens) leading to unaccessed funds, owner can resort to this function
/// @dev Putting this function there requires trust from the community, hence, this needs to be discussed
function emergencyWithdraw() external onlyOwner {
(bool success, ) = payable(owner()).call{value: address(this).balance}("");
require(success, "DToken: Could not withdraw eth");
}
//=================================== INTERNAL ==============================================
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal override {
if(from == address (0) || to == address(0)) return;
// receiver first withdraw funds to credit
_withdrawToCredit(to);
_withdrawToCredit(from);
}
//=================================== PRIVATE ==============================================
function _withdrawToCredit(
address to_
) private
{
uint256 recipientBalance = balanceOf(to_);
if(recipientBalance != 0) {
uint256 amount = ( (dividendPerToken - xDividendPerToken[to_]) * recipientBalance / MULTIPLIER);
credit[to_] += amount;
}
xDividendPerToken[to_] = dividendPerToken;
}
}
If you want more information related to Ethereum-based dApp development or want to get started with a project, you may connect with our skilled blockchain developers.