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 six standard interfaces of ERC-20 and their functions.

We are going to 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 project to your liking. The tutorial aims to help you create your first ERC-20 Token and explain each part of the smart contract.

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

To get started, we are going to clone the template.

$ git clone

Change Directory into the cloned repo in your favorite IDE (integrated development environment) to 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 personalize the project:

$ ape template .

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


If you like the default names for each one, 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 you 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 explains each part of the smart contract so you can understand each part we built.

Let me preface by discussing 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 on the standardization of EIP-20 written by Fabian Vogelsteller and 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 six standard functions, and these standardizations are written in the EIP-20.

Total Supply

Total Supply

Total supply is a function that tracks the summation of tokens across all the addresses 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 addresses that own the token. It is a hashmap instead of an array 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 is the events. Events are a way to capture and log all the actions in the smart contract and put them 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 specific 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, and 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 excellent features of Vyper is the safe math it integrates. Meaning that we do not need to perform require statement or asserts on the account balance.

For example, when you decrease the amount and try subtracting more than what you have, the contract willrevert and stop the transaction. This means the caller of the method can only send what they own.

It ultimately makes for cleaner code and fails appropriately.

After an action is performed, we want to capture and log the event. Event logs reflect the stateful changes in the contract.

The event log format must match 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. Checking a method with a return value is more efficient than 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, and you don't want anyone authorized to transfer on your behalf. So transferFrom has some safeguards. On lines 58 and 59, they are similar to above, except the account input parameter is being decremented instead of the caller of the function 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 must 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 the 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, and I would happily 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: