Optimistic Rollup 就這樣用(1)
ERC20 的入金、轉帳與出金
TL;DR
- 本文會跳過 Optimistic Rollup 的介紹而直接實際演示,關於 Optimistic Rollup 的概念與設計原理筆者將在日後另撰文說明,有興趣的讀者可以先參考下列三篇文章(由淺入深):1. OVM Deep Dive 2. (Almost) Everything you need to know about Optimistic Rollup 3. How does Optimism’s Rollup really work?
- 本文將演示一個 Optimism Rollup 範例,程式碼在這裡。
- 本演示大量參考了以下這兩個官方範例:optimism-tutorial、l1-l2-deposit-withdrawal。
環境設置
- Git
- Node.js
- Yarn
- Docker
- Docker-compose
筆者沒有碰到環境相容問題,但是建議都升到最新版本, Node.js 使用
v16.1.0
或以上版本
Optimism 服務啟動
有關 Optimisim 的所有服務,都包裝在 Optimism 這個超大專案當中了,直接使用原始碼進行組建:
$ git clone git@github.com:ethereum-optimism/optimism.git
$ cd optimism
$ yarn
$ yarn build
組建完成後,就可以在本機啟動服務了:
$ cd ops
$ docker-compose build
$ docker-compose up
這個指令會啟動數個服務,包括:
- L1 Ethereum Node (EVM)
- L2 Ethereum Node (OVM)
- Batch Submitter
- Data Transport Layer
- Deployer
- Relayer
- Verifier
Deployer 服務中的一個參數要特別注意:
FRAUD_PROOF_WINDOW_SECONDS
,這個就是 Optimistic Rollup 的挑戰期,代表使用者出金(Withdraw)需等候的時長。在本篇演示中預設為0
秒。如果有需要重啟,記得把整個 Docker Volume 也清乾淨,例如:
docker-compose down -v
Optimism 整合測試
在繼續接下來的演示之前,我們需要先確認 Optimism 是否有順利啟動,特別是 Relayer 是否運作正常,因此我們需要先進行整合測試:
$ cd optimism/integration-tests
$ yarn build:integration
$ yarn test:integration
確保 L1 <--> L2 Communication
相關測試通過後再繼續執行接下來的演示內容。
啟動服務及部署合約需要花費一些時間,運行一段時間(約 120 秒)之後再執行測試,如果測試結果全部皆為 Fail,可能是 Optimism 尚未啟動完成,再等待一段時間即可。
ERC20 合約部署
Optimism 啟動成功並且完成整合測試後,接下來進行 ERC20 合約的部署。筆者已將合約及部署腳本放在 optimistic-rollup-example-erc20 這個專案中:
$ git clone git@github.com:ethereum-optimism/optimistic-rollup-example-erc20.git
$ cd optimistic-rollup-example-erc20
$ yarn install
$ yarn compile
接下來我們需要部署以下合約:
ERC20
,部署於 L1L2DepositedEERC20
,部署於 L2OVM_L1ERC20Gateway
,部署於 L1
OVM_L1ERC20Gateway
只部署在 L1 上,顧名思義它就是 L1 <=> L2 的「門戶」,提供Deposit
/Withdraw
兩個基本功能,使用者必須透過這個合約來進出 L2。雖然
OVM_L1ERC20Gateway
是 Optimistic Rollup 官方提供的合約。但是開發者也可以依需求自行設計自己的「門戶」。
接下來,我們直接用腳本進行部署:
$ node ./deploy.jsDeploying L1 ERC20...
L1 ERC20 Contract Address: 0xFD471836031dc5108809D173A067e8486B9047A3
Deploying L2 ERC20...
L2 ERC20 Contract Address: 0x09635F643e140090A9A8Dcd712eD6285858ceBef
Deploying L1 ERC20 Gateway...
L1 ERC20 Gateway Contract Address: 0xcbEAF3BDe82155F56486Fb5a1072cb8baAf547cc
Initializing L2 ERC20...
ERC20 入金、轉帳與出金
ERC20 入金(L1 => L2)
目前餘額:
在合約部署完成後,Deployer 是目前唯一有資金的帳戶,接下來我們就進行入金(Deposit),將 Deployer 的資金從 L1 搬到 L2。
首先,進入 ETH(L1) 的 Console:
$ npx hardhat console --network eth
Welcome to Node.js v16.1.0.
Type ".help" for more information.
>
取得 Deployer / User 帳戶:
// In Hardhat ETH Console> let accounts = await ethers.getSigners()> let deployer = accounts[0]> let user = accounts[1]
取得 ERC20
及 OVM_L1ERC20Gateway
合約物件,合約地址可以從部署訊息中取得:
// In Hardhat ETH Console
> let ERC20_abi = await artifacts.readArtifact("ERC20").then(c => c.abi)> let ERC20 = new ethers.Contract("0xFD471836031dc5108809D173A067e8486B9047A3", ERC20_abi)> let Gateway_abi = await artifacts.readArtifact("OVM_L1ERC20Gateway").then(c => c.abi)> let Gateway = new ethers.Contract("0xcbEAF3BDe82155F56486Fb5a1072cb8baAf547cc", Gateway_abi)
確認 Deployer 餘額:
> await ERC20.connect(deployer).balanceOf(deployer.address)BigNumber { _hex: '0x2710', _isBigNumber: true } // 10000
接下來,授權 OVM_L1ERC20Gateway
花費 ERC20:
// In Hardhat ETH Console
> await ERC20.connect(deployer).approve("0xcbEAF3BDe82155F56486Fb5a1072cb8baAf547cc", 10000){
hash: "...",
...
}> await ERC20.connect(user).approve("0xcbEAF3BDe82155F56486Fb5a1072cb8baAf547cc", 10000){
hash: "...",
...
}
注意:Deployer 及 User 都需要對
OVM_L1ERC20Gateway
進行授權,否則在接下來的出金步驟時 Relayer 會出錯
接著,在 OVM_L1ERC20Gateway
合約呼叫 Deposit
:
// In Hardhat ETH Console> await Gateway.connect(deployer).deposit(1000){
hash: "...",
...
}
我們可以到 Optimism (L2) 的 Console 確認入金是否成功:
$ npx hardhat console --network optimism
Welcome to Node.js v16.1.0.
Type ".help" for more information.
>
取得 Deployer / User 帳戶:
// In Hardhat Optimism Console> let accounts = await ethers.getSigners()> let deployer = accounts[0]> let user = accounts[1]
取得 L2DepositedERC20
合約物件,合約地址可以從部署訊息中取得:
// In Hardhat Optimism Console> let L2ERC20_abi = await artifacts.readArtifact("L2DepositedERC20").then(c => c.abi)> let L2DepositedERC20 = new ethers.Contract("0x09635F643e140090A9A8Dcd712eD6285858ceBef", L2ERC20_abi)
確認入金是否成功:
// In Hardhat Optimism Console> await L2DepositedERC20.connect(deployer).balanceOf(deployer.address)BigNumber { _hex: '0x03e8', _isBigNumber: true } // 1000
ERC20 轉帳(L2 <=> L2)
完成以上步驟後,目前的餘額如下:
接下來,我們在 L2 從 Deployer 轉移一部分資金給 User:
// In Hardhat Optimism Console> await L2DepositedERC20.connect(user).balanceOf(user.address)BigNumber { _hex: '0x00', _isBigNumber: true } // 0> await L2DepositedERC20.connect(deployer).transfer(user.address, 1000){
hash: "..."
...
}> await L2DepositedERC20.connect(wallet_1).balanceOf(user.address)BigNumber { _hex: '0x03e8', _isBigNumber: true } // 1000
ERC20 出金(L2 => L1)
完成以上步驟後,目前的餘額如下:
接下來,我們用 User 帳戶提領資金,在 L2DepositedERC20
合約呼叫 Withdraw
:
// In Hardhat Optimism Console> await L2DepositedERC20.connect(user).withdraw(1000){
hash: "..."
...
}> await L2DepositedERC20.connect(user).balanceOf(user.address)BigNumber { _hex: '0x00', _isBigNumber: true }
最後,檢查在 L1 是否提領成功:
// In Hardhat ETH Console> await ERC20.connect(user).balanceOf(user.address)BigNumber { _hex: '0x03e8', _isBigNumber: true } // 1000> await ERC20.connect(deployer).balanceOf(deployer.address)BigNumber { _hex: '0x2328', _isBigNumber: true } // 9000
由於挑戰期為 0 秒,因此提領幾乎無需等待時間,頂多只需數秒鐘
做完上述所有操作,餘額應該如下:
總結
本文演示了:
- Optimistic Rollup 相關服務的本機部署
- ERC20 L1 => L2 的入金(Deposit)
- ERC20 L2 帳戶之間轉帳(Transfer)
- ERC20 L2 => L1 的出金(Withdraw)
筆者未來將繼續擴充此系列的教學內容,例如 ERC721 / ERC1155 的使用方式,敬請期待。