Skip to content

Commit 84ffdb7

Browse files
Merge pull request #1390 from qbzzt/250218-custom-superchain-erc20
Tutorial that teaches how to write custom SuperchainERC20 token contracts
2 parents 01555aa + 7ac523f commit 84ffdb7

File tree

3 files changed

+209
-0
lines changed

3 files changed

+209
-0
lines changed

pages/stack/interop/tutorials/_meta.json

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
"message-passing": "Interop message passing",
33
"deploy-superchain-erc20": "Issuing new assets with SuperchainERC20",
44
"transfer-superchainERC20": "Transferring a SuperchainERC20",
5+
"deploy-superchain-erc20": "Issuing new assets with SuperchainERC20",
6+
"custom-superchain-erc20": "Custom SuperchainERC20 tokens",
57
"bridge-crosschain-eth": "Bridging native cross-chain ETH transfers",
68
"relay-messages-cast": "Relaying interop messages using `cast`",
79
"relay-messages-viem": "Relaying interop messages using `viem`",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
---
2+
title: Creating custom SuperchainERC20 tokens
3+
lang: en-US
4+
description: Create SuperchainERC20 tokens with custom behaviors
5+
---
6+
7+
import { Callout } from 'nextra/components'
8+
import { Steps } from 'nextra/components'
9+
10+
<Callout>
11+
The SuperchainERC20 standard is ready for production deployments.
12+
Please note that the OP Stack interoperability upgrade, required for crosschain messaging, is currently still in active development.
13+
</Callout>
14+
15+
# Custom SuperchainERC20 tokens
16+
17+
## Overview
18+
19+
This guide explains how to modify the behavior of [`SuperchainERC20`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/SuperchainERC20.sol) contracts to create custom tokens that can then be bridged quickly and safely using the [`SuperchainTokenBridge`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/SuperchainTokenBridge.sol) contract (once interop is operational).
20+
For more information on how it works, [see the explainer](/stack/interop/superchain-erc20).
21+
22+
To ensure fungibility across chains, `SuperchainERC20` assets *must* have the same contract address on all chains.
23+
This requirement abstracts away the complexity of cross-chain validation.
24+
Achieving this requires deterministic deployment methods. There are [many ways to do this](https://github.com/Arachnid/deterministic-deployment-proxy).
25+
Here we will use the [SuperchainERC20 Starter Kit](/app-developers/starter-kit).
26+
27+
### What you'll do
28+
29+
* Use the [SuperchainERC20 Starter Kit](/app-developers/starter-kit) to deploy tokens with your custom code.
30+
31+
### What you'll learn
32+
33+
* How to deploy custom ERC-20 tokens on different chains at the same address so that they can be bridged with the [`SuperchainTokenBridge`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/SuperchainTokenBridge.sol) contract.
34+
35+
## Prerequisites
36+
37+
Before starting this tutorial, ensure your development environment meets the following requirements:
38+
39+
### Technical knowledge
40+
41+
* Understanding of smart contract development
42+
* Familiarity with blockchain concepts
43+
* Familiarity with [standard SuperchainERC20 deployments](./deploy-superchain-erc20).
44+
45+
### Development environment
46+
47+
* Unix-like operating system (Linux, macOS, or WSL for Windows)
48+
* Git for version control
49+
50+
### Required tools
51+
52+
The tutorial uses these primary tools:
53+
54+
* Foundry: For sending transactions to blockchains.
55+
56+
## Step by step explanation
57+
58+
<Steps>
59+
### Prepare for deployment
60+
61+
1. Follow the setup steps in the [SuperchainERC20 Starter Kit](/app-developers/starter-kit#setup).
62+
Don't start the development environment (step 5).
63+
64+
2. Follow [the deployment preparations steps](./deploy-superchain-erc20#prepare-for-deployment) in the issuing new assets page.
65+
Don't deploy the contracts yet.
66+
67+
**Note:** Make sure to specify a previously unused value for the salt, for example your address and a timestamp.
68+
This is necessary because if the same constructor code is used with the same salt when using the deployment script, it gets the same address, which is a problem if you want a fresh deployment.
69+
70+
### Create the custom contract
71+
72+
The easiest way to do this is to copy and modify the `L2NativeSuperchainERC20.sol` contract.
73+
Use this code, for example, as `packages/contracts/src/CustomSuperchainToken.sol`.
74+
75+
```solidity file=<rootDir>/public/tutorials/CustomSuperchainToken.sol hash=4ad95b9203ce523351eba0501f8b972d
76+
```
77+
78+
<details>
79+
<summary>Explanation</summary>
80+
81+
```solidity file=<rootDir>/public/tutorials/CustomSuperchainToken.sol#L36-L38 hash=4e402ea88c9cd796500425172a6de16d
82+
```
83+
84+
This function lets users get tokens for themselves.
85+
This token is for testing purposes, so it is useful for users to get their own tokens to run tests.
86+
</details>
87+
88+
### Deploy the new token
89+
90+
1. Edit `packages/contracts/scripts/SuperchainERC20Deployer.s.sol`:
91+
92+
* Change line 6 to import the new token.
93+
94+
```solidity
95+
import {CustomSuperchainToken} from "../src/CustomSuperchainToken.sol";
96+
```
97+
98+
* Update lines 52-54 to get the `CustomSuperchainToken` initialization code.
99+
100+
```solidity
101+
bytes memory initCode = abi.encodePacked(
102+
type(CustomSuperchainToken).creationCode, abi.encode(ownerAddr_, name, symbol, uint8(decimals))
103+
);
104+
```
105+
106+
* Modify line 62 to deploy a `CustomSuperchainToken` contract.
107+
108+
```solidity
109+
addr_ = address(new CustomSuperchainToken{salt: _implSalt()}(ownerAddr_, name, symbol, uint8(decimals)));
110+
```
111+
112+
2. Deploy the token contract.
113+
114+
```sh
115+
pnpm contracts:deploy:token
116+
```
117+
118+
<details>
119+
<summary>Sanity check</summary>
120+
121+
1. Set `TOKEN_ADDRESS` to the address where the token is deployed.
122+
You can also play with the token I created, which is at address [`0xF3Ce0794cB4Ef75A902e07e5D2b75E4D71495ee8`](https://sid.testnet.routescan.io/address/0xF3Ce0794cB4Ef75A902e07e5D2b75E4D71495ee8).
123+
124+
```sh
125+
TOKEN_ADDRESS=0xF3Ce0794cB4Ef75A902e07e5D2b75E4D71495ee8
126+
```
127+
128+
2. Source the `.env` file to get the private key and the address to which it corresponds.
129+
130+
```sh
131+
. packages/contracts/.env
132+
MY_ADDRESS=`cast wallet address $DEPLOYER_PRIVATE_KEY`
133+
```
134+
135+
3. Set variables for the RPC URLs.
136+
137+
```sh
138+
RPC_DEV0=https://interop-alpha-0.optimism.io
139+
RPC_DEV1=https://interop-alpha-1.optimism.io
140+
```
141+
142+
4. Get your current balance (it should be zero).
143+
144+
```sh
145+
cast call --rpc-url $RPC_DEV0 $TOKEN_ADDRESS "balanceOf(address)" $MY_ADDRESS | cast --from-wei
146+
```
147+
148+
5. Call the faucet to get a token and check the balance again.
149+
150+
```sh
151+
cast send --private-key $DEPLOYER_PRIVATE_KEY --rpc-url $RPC_DEV0 $TOKEN_ADDRESS "faucet()"
152+
cast call --rpc-url $RPC_DEV0 $TOKEN_ADDRESS "balanceOf(address)" $MY_ADDRESS | cast --from-wei
153+
```
154+
</details>
155+
</Steps>
156+
157+
## How does this work?
158+
159+
To allow for superchain interoperability, an ERC-20 token has to implement [ERC-7802](https://specs.optimism.io/interop/token-bridging.html#ierc7802).
160+
You can either use [the `SuperchainERC20` implementation](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/SuperchainERC20.sol#L26-L46), or write your own.
161+
162+
For more details [see the explainer](../superchain-erc20).
163+
164+
## Next steps
165+
166+
* Use the [SuperchainERC20 Starter Kit](/app-developers/starter-kit) to deploy your token across the Superchain.
167+
* Explore the [SuperchainERC20 specifications](https://specs.optimism.io/interop/token-bridging.html) for in-depth implementation details.
168+
* Review the [Superchain Interop Explainer](../explainer) for answers to common questions about interoperability.
+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.25;
3+
4+
import {SuperchainERC20} from "./SuperchainERC20.sol";
5+
import {Ownable} from "@solady/auth/Ownable.sol";
6+
7+
contract CustomSuperchainToken is SuperchainERC20, Ownable {
8+
string private _name;
9+
string private _symbol;
10+
uint8 private immutable _decimals;
11+
12+
constructor(address owner_, string memory name_, string memory symbol_, uint8 decimals_) {
13+
_name = name_;
14+
_symbol = symbol_;
15+
_decimals = decimals_;
16+
17+
_initializeOwner(owner_);
18+
}
19+
20+
function name() public view virtual override returns (string memory) {
21+
return _name;
22+
}
23+
24+
function symbol() public view virtual override returns (string memory) {
25+
return _symbol;
26+
}
27+
28+
function decimals() public view override returns (uint8) {
29+
return _decimals;
30+
}
31+
32+
function mintTo(address to_, uint256 amount_) external onlyOwner {
33+
_mint(to_, amount_);
34+
}
35+
36+
function faucet() external {
37+
_mint(msg.sender, 10**_decimals);
38+
}
39+
}

0 commit comments

Comments
 (0)