Create an ERC-20 Token

written by
Chris Cao
Date Last Updated
June 1, 2022
Download Project Files

ERC-20 are fungible tokens that can be bought, traded, or sold to represent a range of digital assets. This standard provides basic functionality to transfer tokens, as well as allow tokens to be approved so they can be spent by another on-chain third party.

Getting started with Ape-Template

In this tutorial, an ApeWorX core developer walks through how to compile cookie cutter and Vyper files in preparation for testing and deploying. This how-to series also outlines all 6 standard interfaces of ERC-20 and functions.

We are going start with ape to create a smart contract project. This project comes with a smart contract, configuration file and testing scripts.

We make use of ape-template to custom create your own project to your liking. The goal of the tutorial is to help you create your first ERC-20 Token and explain each part of the smart contract.

Ape-template is made with cookiecutter so you can personalize the project to you and your preferences.

To get started we going to clone the template.

$ git clone

Change Directory into the cloned repo in a your favorite IDE (integrated development environment) to take a look at what we are working with.

Next we are going to activate a python virtual environment so we can play with the template.

NOTE: If you don't have ape installed in a virtual environment you can click here to get started.

Once you have your vm activated, ape installed, and ape-template plugin installed, you can simply personalize the project:

$ ape template .

The CLI will prompt you to change the variable names to make your own:


If you like default names for each one, just press enter and it will keep the default names.

The project should be created under a directory with your project_name.

At this point the project is built and ready to compile and deploy! You are all set!

NOTE:  You must have ape-vyper plugin installed if you are compiling this project. If want to check and install ape-vyper

- Thank you Steiner

$ ape plugins list
$ ape plugins install vyper -y

Understanding the Smart Contract

The rest of the video is to explain each part of the smart contract so you can understand each part we built.

Let me preface by talking about why we chose Vyper and how we chose to write our contract (EIP-20).

Here are some of the reasons why we chose to write the contract in Vyper:

  • Bounds and overflow checking: On array accesses and arithmetic
  • Support for signed integers and decimal fixed point numbers
  • Decidability: It is possible to compute a precise upper bound for the gas consumption of any Vyper function call
  • Strong typing
  • Small and understandable compiler code
  • Limited support for pure functions: Anything marked constant is not allowed to change the state

We chose to write our contract based of the standardization of EIP-20 written by Fabian Vogelsteller, Vitalik Buterin. The goal is to make your token meet the standards of all the other ERC-20 tokens so you can work in the same environment.

Within the smart contract for ERC-20. We have 6 standard functions. These standardizations are written in the EIP-20.

Total Supply

Total Supply

Total supply is a function that tracks the summation of token across all the address that hold the tokens. The amount of tokens is changeable in the initiation.

# ERC20 State Variables
totalSupply: public(uint256)


balanceOf: public(HashMap[address, uint256])

BalanceOf is a hashmap of all address that own the token. It is a hashmap instead of an array simply because it is more efficient with search and update O(1) time complexity. 

The Vyper compiler automatically creates getter functions for all public storage variables. For the example balanceOf, the compiler will generate a function called balanceOf that does not take any arguments and returns a hashmap, the mapping of an address with its integer value (number of tokens). Public decorators are how Vyper lets you get a public getter for free. It will create a function to return the output of the variable, therefore you can reference it.

Allowance is a 2 input argument mapping. Which we will get into later

allowance: public(HashMap[address ,HashMap[address, uint256]])

Understanding "Events"

The next part of the contract are the events. Events are a way for you to capture and log all the actions in the smart contract and put it into an ETH node. 

Some of the parameters in the event are indexed for search and filter purposes. For example you want to view all the events that happen with a certain address. 

Understanding Mutable Functions

Next we have 3 mutable functions that change the state of a contract. Total Supply, BalanceOf and allowance do not change the state of the contract. They provide information about the state of the contract. In essence they are immutable functions. 


Transfer allows an individual to send some of their balance to a receiver. The caller of the msg.sender is authorized to an amount of a token from their account to transfer to the account of the receiver.

One of the nice features about Vyper is that safe math is integrated. Meaning that we do not need to perform require statement or asserts on the account balance. 

For example when you decrement the amount and you try and subtract more than what you have. The contract will revert and stop the transaction. Which means the caller of the method can not send more than what they own. 

It ultimately makes for cleaner code and fails properly.

After action is performed. We want to capture and log the event. Event logs reflect the stateful changes of the contract. 

It is very important that the event log format matches the order in which the action is performed. So when you go back and look at the logs. You can determine with confidence which event log belong to a function. 

Lastly we want to return True. Return a value allows each method to be gas efficient. It is more efficient to check a method with a return value instead of a method without a return value.


TransferFrom is very similar to Transfer. TransferFrom allows an account to transfer assets to another account on your behalf. For example you may want to swap tokens or deposit into a DeFi protocol. You don't want anyone to have authorization to transfer on your behalf. So transferFrom has some safeguards. On line 58 and 59, they are similar to above except the account input parameter is being decremented instead of the caller of the function as known as the operator.

And even before we initiate the transfer. We must check to make sure that the operator is authorized and is authorized for the correct amount. 


The sender is the account asset owner and the msg.sender is the operator. To allow the operator (msg.sender) to be authorized for the correct amount. We have the approve the operator with the ex amount it is allowed to transfer.

Approve updates the allowance of the given operator. Allowance first parameter is the caller the owner of the asset. The spender (operator) is taking authorization. After the approval we log event and return True.

NOTE: All transferFrom actions will only work after approval is called.

And that's it! That is the description of all 6 standard functions in an ERC-20 smart contract. I hope you give it a try and please let me know in the comments below, if you have any questions. We have an active discord. I would be happy to talk or walk through the project during office hours on Fridays. Just say hello we can help you out anytime.

Final Steps

  • Share it with the world
  • Test is via
  • Submit it to our developers for feedback
  • Join our discord channel and share your work that way
  • Create an awesome company
  • Have Fun
  • Create an awesome company


Python 3.7.2 or later

Ape Academy ERC-20: