OpenZeppelin 可昇級合約插件 8/9 從 OpenZeppelin CLI 部署
差異性
CLI 和 插件 的主要不同之處,是CLI用於追蹤合約的可昇級部署。在某些情況下這很方便,因為不需要擔心太多關於代理合約、功能合約及地址。可以專注於按照名稱昇級合約或送到合約的交易。
讓CLI持續追蹤也會帶來額外的限制,限制使用不同的工具和工作流程。但是由於插件是設計為可以獨立於 CLI 工作的,因此我們消除了一些限制,可以靈活地追蹤代理合約。(補充,此段敘述並沒有說明什麼,CLI 和 Plugin 兩者還是有不同,只是為了插件環境,但插件還是有其限制。)
除了上述的不同(CLI是用來追蹤合約的可昇級部署)之外其餘都一樣,因為在背後都是使用相同的 Proxy 和 ProxyAdmin 合約,來產生兩個不同的接口來管理它們。這表示部署專案不會跟鏈上有任何接觸,每件事都是安全而且是在本地的。
安裝
安裝 Truffle ,並且初始化專案
注意:
當 Truffle 詢問時,選擇不覆寫合約,或是測試目錄的話,就不會進行初始部署,要確定的是建立了 Migrations.sol 和初始化部署。
$ npm install --save-dev truffle $ npx truffle init
然後安裝可昇級合約插件
$ npm install --save-dev @openzeppelin/truffle-upgrades
部署 CLI 專案
注意,這是一個單向的過程,確定你對 ./openzeppeling/ 已經備份或是版本管理。
現在我們開始部署專案
$ npx migrate-oz-cli-project
以下是輸出結果
✔ Successfully migrated .openzeppelin/rinkeby.json ✔ Migration data exported to openzeppelin-cli-export.json ✔ Deleting .openzeppelin/project.json These were your project's compiler options: { "compilerSettings": { "optimizer": { "enabled": false, "runs": "200" } }, "typechain": { "enabled": false }, "manager": "openzeppelin", "solcVersion": "0.6.12", "artifactsDir": "build/contracts", "contractsDir": "contracts" }
這個腳本跟插件一起安裝,作用是刪除 CLI專案文件,以及將存放於 .openzeppelin 目錄底下舊的網路設定檔轉換為跟插件一樣的檔案。再次提醒,這不會改變任何鏈上的東西,只有本地端的檔案。另外要注意到,一旦執行這個腳本,就不能再用 CLI 管這個專案,除非從備份或版本管理裡面還原。
部署腳本會輸出名為 openzeppelin-cli-export.json 的檔案到工作目錄裡面,其中包括CLI 用來做為管理的所有資料,你可以任意使用。這裡面包括編譯的設定,為了方便,這些設定也會在編譯完成之後,列印在螢幕上。接下來要把這些設定加到專案的組態裡面:
在 compilers 欄位裡面找到編譯器的設定,並且複製下來
// truffle-config.js module.exports = { // ... compilers: { solc: { version: "0.6.12", settings: { optimizer: { enabled: false, runs: 200 } } } } }
注意: solc 設檔案的格式跟 truffle-config.js 和 buidler.config.js 檔案不一樣
這樣就完成了 CLI 專案的部署。接下來試試用這些新的設定檔來昇級你部署好的合約的其中之一。
昇級到新版本
假設我們有一個 Box 合約是 CLI 專案之一,發佈在 Rinkeby 網路上。打開輸出的檔案,會類似如下
// openzeppelin-cli-export.json { "networks": { "rinkeby": { "proxies": { "openzeppelin-upgrades-migration-example/Box": [ { "address": "0x500D1d6A4c7D8Ae28240b47c8FCde034D827fD5e", "version": "1.0.0", "implementation": "0x038B86d9d8FAFdd0a02ebd1A476432877b0107C8", "admin": "0x1A1FEe7EeD918BD762173e4dc5EfDB8a78C924A8", "kind": "Upgradeable" } ] } } }, "compiler": { // we'll ignore compiler settings for this } }
這個檔案是 JSON 格式,包括了可昇級合約的以下訊息
- address: 代理合約地址(代理合約包括可昇級合約的狀態)
- implementation: 功能合約地址(可昇級合約裡,負責邏輯合約的地址)
- admin:代理合約管理員的地址,除非另外設定,否則就是 ProxyAdmin 合約的地址
以下就是我們決定把 Box 合約昇級到 BoxV2 合約,給插件的輸出檔案,看起來的樣子:
// migrations/2_upgrade_box_contract.js const { upgradeProxy } = require('@openzeppelin/truffle-upgrades'); const OZ_SDK_EXPORT = require("../openzeppelin-cli-export.json"); const BoxV2 = artifacts.require('BoxV2'); module.exports = async function (deployer) { const [ Box ] = OZ_SDK_EXPORT.networks.rinkeby.proxies["openzeppelin-upgrades-migration-example/Box"]; const instance = await upgradeProxy(Box.address, BoxV2, { deployer }); console.log("Upgraded", instance.address); };
然後再執行 Truffle 的部署。可以參考[2], 和 truffle-upgrades 插件[3]
$ npx truffle migrate --network rinkeby
這樣,就完成了 OpenZeppelin CLI 專案的部署,部署到 Truffle 或 Buidler 然後使用插件昇級。
參考
[1]https://docs.openzeppelin.com/upgrades-plugins/1.x/migrate-from-cli
[2]https://www.trufflesuite.com/docs/truffle/getting-started/running-migrations
[3]https://docs.openzeppelin.com/upgrades-plugins/1.x/truffle-upgrades