My ERC20 Contract

A special valentine smart contract writing adventure

Exploring the world of smart contracts at Web3Bridge has been nothing less than fascinating. While the world celebrates Valentine, I am glued to my PC, writing smart contracts and conducting tests. phew! We were assigned to write a special ERC20 smart contract with the following features:

  1. It should be transferable.

  2. A service fee of 10% should be implemented on the sender's balance. Simple, right? I guess that would be the case for the OGs and not for the newbies, of which I am one. However, I also realized it would be cool to add a third function that would return the balance of every address when requested.

So, I did some background research into ERC20 contracts as this is unfamiliar terrain, and realized some findings. ERC20 is a token standard to which token creators on the Ethereum network must adhere. T

Stack Used

To write this contract, I used the Remix IDE and ERC20 library from OpenZeppelin.

Writing the Contract

  1. I indicated my license and Solidity compiler version.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
  1. I imported the ERC20 library from OpenZeppelin.
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
  1. I began the contract by naming it SpecialContract.

  2. The next step was to run a mapping. This mapping allows me to link every address that interacts with the smart contract to its account balance. The reason for using addresses is that they are unique identifiers for every user on the blockchain.

      mapping(address=>uint256) balance;
    
  3. The next step was to initiate my constructor. In my constructor, I would be able to pass the token arguments. This is so that on deployment, the token can be easily identified by its properties.

     constructor(string memory _tokenName, string memory _symbol, uint256 _initialSupply) ERC20(_tokenName, _symbol) {
             _mint(msg.sender, _initialSupply);
         }
    

    I also added a minting function ``_mint(msg.sender, _initialSupply)``` in the constructor so we can generate some tokens for operations. This is paramount because if this is not done, the user cannot transfer as it would be inherently a failed transaction, as the contract does not have enough resources to complete the transaction it is called to perform. One mistake I learned was not to declare the minting function outside the constructor as it meant that more tokens could be created at random. Declaring it within the constructor ensures that it is performed once and cannot be repeated.

  4. After that, here comes the interesting part which is to write the actual function that allows for the transfer of tokens. I added some gated statements to require that some conditions such as account balance checks are performed before the transaction is processed and carried out, and I included a sanity check to ensure that no value is sent to address zero. I added the logic to implement the 10% service fee which is named serviceFee.

     function transferToken(uint256 _value, address _to) public returns(uint256){
             // uint256 coinSupply = totalSupply;
             require(balance[msg.sender] > _value, "You dont have enough SCT tokens in your account");
             require(_value > 0, "token amount must be greater than zero");
             require(msg.sender != address(0), "Check this address again. You cannnot send to this address!"); // performing a sanity check
             uint256 serviceFee = _value /10;
             balance[msg.sender] = balance[msg.sender] - serviceFee; // added service fee here
             balance[_to] = balance[_to] + _value; 
    
             emit TranferedTo(_value, _to);
             return balance[msg.sender];
         }
    
  5. The last function implemented is to return the balance of an address when the function is called.

     function tokenBalance(address _address) public view returns(uint256){
             return balance[_address];
         }
    

    To add some level of transparency to this contract in the spirit of decentralization, I added events ```event``` to the transfer function to keep a log of all transactions fired.

     event TranferedTo (uint256 indexed _value, address indexed _to);
    

Conclusion

Writing this contract has been nothing short of fun. Though I have yet to fully explore the ERC20 standard, I look forward to having a good grasp of it and being able to implement other contract types like interfaces to build a more robust smart contract.

Find the link to the code on GitHub

  1. gist via this link

  2. GitHub repo link