18 min read
Overviewβ
The ability to adapt and evolve smart contracts post-deployment has become paramount. As projects grow, unforeseen requirements, potential optimizations or different products often emerge. For many, the traditional method of deploying a completely new contract and migrating users isn't just impractical; it's a recipe for potential user frustration and lost trust. Enter the power of upgradeable contracts, allowing you to evolve your token's logic while retaining its address and user data. In this guide, we'll show you how to harness OpenZeppelin's pre-audited contract suite and Foundry's deployment capabilities to create and roll out an upgradeable ERC-20 token.
What You Will Doβ
- Solidify your understanding of ERC-20 tokens
- Learn how upgradeability can add more functionality to your ERC-20 token
- Connect to the blockchain using QuickNode
- Create and deploy an upgradeable ERC-20 token with OpenZeppelin and Foundry
What You Will Needβ
- Basic understanding of Ethereum and Smart Contracts
- Knowledge of the ERC-20 token standard
- Node.js installed
- A Web3 Wallet
What is an ERC-20 token?β
The ERC-20 token standard is a blueprint for creating fungible tokens on Ethereum and EVM-based blockchains. "ERC" stands for Ethereum Request for Comment, and "20" is its proposal identifier. Before its inception, token creators faced a chaotic landscape, with each token's architecture being uniqueβleading to complexity in integration, especially for wallets and exchanges. However, ERC-20 introduced a standardized set of rules encapsulated in mandatory functions like transfer
, balanceOf
, and totalSupply
, ensuring consistent behavior across tokens. Similar to an interface in Object-Oriented Programming, developers can appreciate its role in enforcing the adoption of these key functions. This uniformity has revolutionized token interactions, making them seamless and efficient, with tokens now easily traded, used in dApps, or stored in wallets, all while operating on Ethereum's blockchain.
What is an Upgradeable ERC-20 Token?β
At its core, an upgradeable token embraces the flexibility to enhance or modify its functionality post-deployment. This is achieved through a layered architecture: the Proxy serves as the immutable smart contract interacting with users, while the Logic smart contract (also sometimes referred to as the implementation contract) contains the business logic. Upgrades are orchestrated by changing the proxy's reference to newer logic contracts, ensuring token balances and other state variables remain intact. In this design, an Admin role typically governs the upgrade process, making decisions about when and how the logic contract changes, thereby introducing an element of governance into the token's life cycle.
There are different types of upgradeable smart contracts, so let's cover the most common and compare them.
Transparent Proxyβ
The Transparent Proxy pattern is designed to distinguish between an administrator and a regular user. It works by using two different addresses: one for the admin (who can upgrade the contract) and one for regular users (who can interact with the contract's functions). The proxy contract includes logic to separate calls made by the admin from those made by regular users, preventing accidental execution of administrative functions during regular use.
UUPS Proxyβ
UUPS (Universal Upgradeable Proxy Standard) Proxy is a more streamlined and gas-efficient approach. In this pattern, the upgrade functionality is embedded within the logic contract itself. This design reduces the need for an additional 'admin' contract, simplifying the structure. However, it also requires that the logic contract is designed with upgradability in mind, embedding the necessary upgrade functions within it.
Beacon Proxyβ
The Beacon Proxy pattern introduces a central "Beacon" contract that all proxy instances reference to obtain the address of the current logic contract. This design allows for a more efficient upgrade process, as updating the logic contract address in the beacon automatically updates all associated proxies. It's particularly useful in scenarios where multiple proxy contracts need to be kept in sync with the same logic contract.
To learn more about Proxies, check out this QuickNode guide and OpenZeppelin Proxy.
For the technical demonstration in this guide, we'll be covering the UUPS Proxy method.
Why OpenZeppelin?β
OpenZeppelin provides a library of reusable smart contracts that are secure and well-audited, ensuring that the basic building blocks of your smart contract are safe. For upgradeability, OpenZeppelin offers proxy contracts that delegate calls to an implementation contract. This approach allows developers to replace the implementation contract while keeping the proxy's storage, address, and balance.
To learn more about OpenZeppelin and its upgradeability plug-in, check out this resource.
Project Prerequisite: Create a QuickNode Endpointβ
To deploy a smart contract to the blockchain, you'll need an API endpoint to communicate with the network. You're welcome to use public nodes or deploy and manage your own infrastructure; however, if you'd like 8x faster response times, you can leave the heavy lifting to us. Sign up for an account here.
Once logged in, click the Create an endpoint button, then select the blockchain and network you want to deploy on. For the purpose of this guide, we'll choose the Ethereum Sepolia chain.
After creating your endpoint, copy the HTTP Provider link and keep it handy, as you'll need it in the following sections.
Project Prerequisite: Fund Your Walletβ
If you're in need of ETH on Sepolia testnet, the Multi-Chain QuickNode Faucet makes it easy to obtain test ETH!
Navigate to the Multi-Chain QuickNode Faucet and connect your wallet (e.g., MetaMask, Coinbase Wallet) or paste in your wallet address to retrieve test ETH. Note that there is a mainnet balance requirement of 0.001 ETH on Ethereum Mainnet to use the EVM faucets. You can also tweet out your request to get a bonus!
In the next section, we will transition over to creating our project directory and configuring the project's files and dependencies.
Create the Upgradeable ERC-20 Token Projectβ
Now that we have a good fundamental understanding of ERC-20 tokens and how upgradeability works on Ethereum, let's start coding up a practical example. First, let's install and initialize a Foundry project.
Install Foundryβ
If you don't have Foundry installed already, open your terminal and run the following command:
curl -L https://foundry.paradigm.xyz | bash
The command above will install Foundryup
. Then, proceed according to the on-screen directions, which will enable you to use the foundryup
command in your CLI. Once installed, you can run the foundryup -v
command in your terminal to check the version and install the latest (nightly) precompiled binaries.
If you're using Windows, you will need to install and use Git BASH or WSL as your terminal since Foundryup currently does not support Powershell or Cmd. Follow the instructions here for Windows and alternate sources.
Alternatively, if you're on M1 Mac, and get the error:
dyld[32719]: Library not loaded: /usr/local/opt/libusb/lib/libusb-1.0.0.dylib
; Try installing the library via brew:brew install libusb
.
Once your installation is configured, initialize a Foundry project with the following command and navigate inside the directory:
forge init erc20_upgradeable && cd erc20_upgradeable
Then, navigate inside erc20_upgradeable, and your project structure should look like this:
.