Developing Smart Contracts V On Base: ERC 20.

prerequisites:-

  • What is an ERC 20 Token?

  • Use-cases of ERC-20.

  • Building an ERC-20 Token.

  • Deployment on Base.

WHAT IS AN ERC-20 TOKEN?

An ERC-20 token is a standardized type of fungible token on the Ethereum blockchain. ERC-20 standard defines a common set of rules for how these tokens should behave, allowing them to be compatible with various decentralized applications (dApps), wallets, and exchanges within the Ethereum ecosystem.

Key Features of ERC-20 Tokens:

  1. Fungibility: Every token is identical and interchangeable, meaning that one token is always equal in value to another of the same type.

  2. Standardized Interface: The ERC-20 standard ensures that tokens follow a specific interface, making it easier for developers to integrate these tokens into dApps and for wallets to support them.

Functions of the ERC-20 Standard:

The ERC-20 standard includes several important functions that all ERC-20 tokens must implement:

  • totalSupply: Returns the total number of tokens in existence.

  • balanceOf(address): Returns the balance of a particular address.

  • transfer(address, uint256): Transfers a specified amount of tokens to another address.

  • approve(address, uint256): Allows a spender to withdraw tokens from your account multiple times, up to a certain amount.

  • transferFrom(address, address, uint256): Allows a spender to transfer tokens from one account to another, given that it was previously approved.

  • allowance(address, address): Shows how much a spender is allowed to withdraw from a given account.

USE-CASES OF ERC-20.

  • Cryptocurrencies: Many projects use ERC-20 tokens to create their own cryptocurrencies on top of the Ethereum blockchain.

  • Crowdfunding (Initial Coin Offerings, ICOs): Projects can raise funds by issuing ERC-20 tokens during an ICO, giving early investors tokenized assets in exchange for their investment.

  • Decentralized Finance (DeFi): ERC-20 tokens are widely used in DeFi applications like lending, borrowing, and trading protocols.

  • Stablecoins: Tokens like USDT (Tether) or USDC are ERC-20 tokens pegged to the value of traditional currencies such as the US dollar, offering stable value for decentralized applications.

  • Governance: Some projects issue governance tokens using the ERC-20 standard, allowing holders to vote on decisions regarding the project’s development and operations.

BUILDING AN ERC-20 TOKEN.

Below is an interface for building an ERC20 contract:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

interface IERC20 {
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function transfer(address recipient, uint256 amount)
        external
        returns (bool);
    function allowance(address owner, address spender)
        external
        view
        returns (uint256);
    function approve(address spender, uint256 amount) external returns (bool);
    function transferFrom(address sender, address recipient, uint256 amount)
        external
        returns (bool);
}

ERC20 token contract.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

import "./IERC20.sol";

contract ERC20 is IERC20 {
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(
        address indexed owner, address indexed spender, uint256 value
    );

    uint256 public totalSupply;
    mapping(address => uint256) public balanceOf;
    mapping(address => mapping(address => uint256)) public allowance;
    string public name;
    string public symbol;
    uint8 public decimals;

    constructor(string memory _name, string memory _symbol, uint8 _decimals) {
        name = _name;
        symbol = _symbol;
        decimals = _decimals;
    }

    function transfer(address recipient, uint256 amount)
        external
        returns (bool)
    {
        balanceOf[msg.sender] -= amount;
        balanceOf[recipient] += amount;
        emit Transfer(msg.sender, recipient, amount);
        return true;
    }

    function approve(address spender, uint256 amount) external returns (bool) {
        allowance[msg.sender][spender] = amount;
        emit Approval(msg.sender, spender, amount);
        return true;
    }

    function transferFrom(address sender, address recipient, uint256 amount)
        external
        returns (bool)
    {
        allowance[sender][msg.sender] -= amount;
        balanceOf[sender] -= amount;
        balanceOf[recipient] += amount;
        emit Transfer(sender, recipient, amount);
        return true;
    }

    function _mint(address to, uint256 amount) internal {
        balanceOf[to] += amount;
        totalSupply += amount;
        emit Transfer(address(0), to, amount);
    }

    function _burn(address from, uint256 amount) internal {
        balanceOf[from] -= amount;
        totalSupply -= amount;
        emit Transfer(from, address(0), amount);
    }

    function mint(address to, uint256 amount) external {
        _mint(to, amount);
    }

    function burn(address from, uint256 amount) external {
        _burn(from, amount);
    }
}
  • This specifies the license type and version of Solidity used. The MIT license is open-source and widely used. Solidity version 0.8.26 is specified for the compiler.
import "./IERC20.sol";
  • Line 3: The contract imports an external file, likely an interface called IERC20. This file defines the functions required by the ERC-20 standard (e.g., transfer, approve, transferFrom).
contract ERC20 is IERC20 {
  • The contract ERC20 is created and it implements the IERC20 interface, which means the contract must implement the functions defined in the ERC-20 interface.
event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(
        address indexed owner, address indexed spender, uint256 value
    );
  • Two events are declared:

    • Transfer: Emits an event when tokens are transferred between addresses.

    • Approval: Emits when an owner approves a spender to spend tokens on their behalf.

uint256 public totalSupply;
    mapping(address => uint256) public balanceOf;
    mapping(address => mapping(address => uint256)) public allowance;
    • totalSupply: Stores the total number of tokens in circulation.

      • balanceOf: A mapping that holds the token balance of each address.

      • allowance: A nested mapping that tracks the amount a spender is allowed to spend from an owner's balance.

string public name;
    string public symbol;
    uint8 public decimals;
    • name: The name of the token (e.g., "My Token").

      • symbol: The ticker symbol for the token (e.g., "MTK").

      • decimals: Specifies the number of decimal places the token can be divided into, commonly 18.

constructor(string memory _name, string memory _symbol, uint8 _decimals) {
        name = _name;
        symbol = _symbol;
        decimals = _decimals;
    }
  • This is the constructor function, which is called when the contract is deployed. It sets the token’s name, symbol, and decimal precision.
function transfer(address recipient, uint256 amount)
        external
        returns (bool)
    {
        balanceOf[msg.sender] -= amount;
        balanceOf[recipient] += amount;
        emit Transfer(msg.sender, recipient, amount);
        return true;
    }
    • transfer: Allows the caller (msg.sender) to transfer a specified amount of tokens to another address (recipient).

      • It deducts the amount from the caller’s balance and adds it to the recipient's balance.

      • It then emits the Transfer event to signal that tokens have moved and returns true to indicate success.

function approve(address spender, uint256 amount) external returns (bool) {
        allowance[msg.sender][spender] = amount;
        emit Approval(msg.sender, spender, amount);
        return true;
    }
    • approve: Allows the owner to approve a spender to transfer up to a certain amount of their tokens.

      • It sets the allowance for the spender and emits an Approval event.

      • transferFrom: Allows an approved spender to transfer tokens from one address (sender) to another (recipient).

      • It reduces the allowance by the transferred amount, adjusts the balances of the sender and recipient, and emits a Transfer event.

     function _mint(address to, uint256 amount) internal {
            balanceOf[to] += amount;
            totalSupply += amount;
            emit Transfer(address(0), to, amount);
        }
  • _mint: An internal function that creates new tokens and assigns them to a specific address (to).

  • It increases the total token supply and the balance of the specified address.

  • A Transfer event is emitted with address(0) as the sender to indicate the creation of tokens.

 function _burn(address from, uint256 amount) internal {
        balanceOf[from] -= amount;
        totalSupply -= amount;
        emit Transfer(from, address(0), amount);
    }
    • _burn: An internal function that destroys a specified amount of tokens from an address (from).

      • It decreases the total supply and the balance of the specified address.

      • The Transfer event is emitted, with address(0) as the recipient to indicate token destruction.

 function mint(address to, uint256 amount) external {
        _mint(to, amount);
    }
    • mint: An external function that calls the internal _mint function, allowing tokens to be created and assigned to an address.
function burn(address from, uint256 amount) external {
        _burn(from, amount);
    }
    • burn: An external function that calls the internal _burn function to destroy tokens from a specified address.

Contract to swap tokens

Here is an example contract, TokenSwap, to trade one ERC20 token for another.

This contract will swap tokens by calling

transferFrom(address sender, address recipient, uint256 amount)

which will transfer amount of token from sender to recipient.

For transferFrom to succeed, sender must

  • have more than amount tokens in their balance

  • allowed TokenSwap to withdraw amount tokens by calling approve

prior to TokenSwap calling transferFrom

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

import "./IERC20.sol";

/*
How to swap tokens

1. Alice has 100 tokens from AliceCoin, which is a ERC20 token.
2. Bob has 100 tokens from BobCoin, which is also a ERC20 token.
3. Alice and Bob wants to trade 10 AliceCoin for 20 BobCoin.
4. Alice or Bob deploys TokenSwap
5. Alice approves TokenSwap to withdraw 10 tokens from AliceCoin
6. Bob approves TokenSwap to withdraw 20 tokens from BobCoin
7. Alice or Bob calls TokenSwap.swap()
8. Alice and Bob traded tokens successfully.
*/

contract TokenSwap {
    IERC20 public token1;
    address public owner1;
    uint256 public amount1;
    IERC20 public token2;
    address public owner2;
    uint256 public amount2;

    constructor(
        address _token1,
        address _owner1,
        uint256 _amount1,
        address _token2,
        address _owner2,
        uint256 _amount2
    ) {
        token1 = IERC20(_token1);
        owner1 = _owner1;
        amount1 = _amount1;
        token2 = IERC20(_token2);
        owner2 = _owner2;
        amount2 = _amount2;
    }

    function swap() public {
        require(msg.sender == owner1 || msg.sender == owner2, "Not authorized");
        require(
            token1.allowance(owner1, address(this)) >= amount1,
            "Token 1 allowance too low"
        );
        require(
            token2.allowance(owner2, address(this)) >= amount2,
            "Token 2 allowance too low"
        );

        _safeTransferFrom(token1, owner1, owner2, amount1);
        _safeTransferFrom(token2, owner2, owner1, amount2);
    }

    function _safeTransferFrom(
        IERC20 token,
        address sender,
        address recipient,
        uint256 amount
    ) private {
        bool sent = token.transferFrom(sender, recipient, amount);
        require(sent, "Token transfer failed");
    }
}

DEPLOYMENT ON BASE.

Navigate to your metamask and add Base Sepolia Testnet to the list of networks. Click this to get some gas fees for deployment on base testnet.

After this, you should have been rewarded with 0.1Base Sepolia ETH!

Navigate back to your wallet.

Next is to connect your wallet to remix for smooth deployment.

Check for the address.

And verify on Base Sepolia Etherscan. Paste Address.

Conclusion

Congratulations on successfully creating your very own ERC-20 contract on the Base network! .