使用OpenZeppelin升級插件部署的合約具備可升級的特性:可以升級以修改其代碼,同時保留其地址,狀態(tài)和余額。 可以迭代地向項目中添加新功能,或修復(fù)在線上版本中可能發(fā)現(xiàn)的任何錯誤。
配置開發(fā)環(huán)境
創(chuàng)建一個新的npm項目
mkdir mycontract && cd mycontract
npm init -y
安裝并初始化Truffle
npm i --save-dev truffle
npx truffle init
安裝Truffle升級插件
npm i --save-dev @openzeppelin/truffle-upgrades
創(chuàng)建可升級合約
注意,可升級合約使用initialize函數(shù)而不是構(gòu)造函數(shù)來初始化狀態(tài)。
Box.sol
// contracts/Box.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
contract Box {
uint256 private value;
// Emitted when the stored value changes
event ValueChanged(uint256 newValue);
// Stores a new value in the contract
function store(uint256 newValue) public {
value = newValue;
emit ValueChanged(newValue);
}
// Reads the last stored value
function retrieve() public view returns (uint256) {
return value;
}
}
將合約部署到公共網(wǎng)絡(luò)
我們將使用Truffle遷移來部署B(yǎng)ox合約。Truffle升級插件提供了一個 deployProxy功能來部署可升級合約。它將部署我們實現(xiàn)的合約,ProxyAdmin會作為項目代理和代理管理員,并調(diào)用初始化函數(shù)。
在migrations目錄中創(chuàng)建以下2_deploy_contracts.js腳本。
在本文中,我們還沒有initialize函數(shù),因此將使用store 函數(shù)來初始化狀態(tài)。
2_deploy_contracts.js
// migrations/2_deploy_box.js
const Box = artifacts.require('Box');
const { deployProxy } = require('@openzeppelin/truffle-upgrades');
module.exports = async function (deployer) {
await deployProxy(Box, [42], { deployer, initializer: 'store' });
};
使用Rinkeby網(wǎng)絡(luò)運行truffle migration進行部署。 我們可以看到3 個合約:Box.sol、ProxyAdmin 和 代理合約TransparentUpgradeableProxy。
truffle migrate --network rinkeby
...
2_deploy_contracts.js
===============? ?Deploying 'Box'
? ?---------------
? ?> transaction hash: ? ?0x1e5a61c2d4560d6ffe5cc60d7badbfef6d5e420708eebff6dc580bb3f9f9f3e1
? ?> Blocks: 1 ? ? ? ? ? ?Seconds: 14
? ?> contract address: ? ?0x7f7dc11961fCD81f53e9F45D9DfBb745832c0657
...? ?Deploying 'ProxyAdmin'
? ?----------------------
? ?> transaction hash: ? ?0x298b429391c5a98701bf79df00f4f5526c61570f3091b3d6693e3a4f12a88409
? ?> Blocks: 1 ? ? ? ? ? ?Seconds: 14
? ?> contract address: ? ?0x7Bd40e62aEe2c5e232152351f57068038761E20F
...? ?Deploying 'TransparentUpgradeableProxy'
? ?---------------------------------------
? ?> transaction hash: ? ?0x7a0043dbe9a35ab9eab8cf0eac1856418cd0c359e330448df016150d293e6716
? ?> Blocks: 2 ? ? ? ? ? ?Seconds: 26
? ?> contract address: ? ?0xc2ea7DE43F194bB397761a30a05CEDcF28835F24
...
發(fā)布驗證合約
truffle run verify Box --network rinkeby
我們可以使用Truffle控制臺(truffle console)與我們的合約進行交互。
注意: Box.deployed() 是我們的代理合約的地址。
truffle console --network rinkeby
truffle(rinkeby)> box = await Box.deployed()
truffle(rinkeby)> box.address
'0xc2ea7DE43F194bB397761a30a05CEDcF28835F24'
truffle(rinkeby)> (await box.retrieve()).toString()
'42'
當前代理的管理員(可以執(zhí)行升級)是ProxyAdmin合約。 只有ProxyAdmin的所有者可以升級代理。 警告:ProxyAdmin 所有權(quán)轉(zhuǎn)移時請確保轉(zhuǎn)到我們控制的地址上。
在migrations目錄中創(chuàng)建以下3_transfer_ownership.js腳本。
3_transfer_ownership.js
// migrations/3_transfer_ownership.js
const { admin } = require('@openzeppelin/truffle-upgrades');
module.exports = async function (deployer, network) {
// 使用你的 錢包 地址
const admin = '0x1c14600daeca8852BA559CC8EdB1C383B8825906';
// Don't change ProxyAdmin ownership for our test network
if (network !== 'test') {
// The owner of the ProxyAdmin can upgrade our contracts
await admin.transferProxyAdminOwnership(admin);
}
};
在Rinkeby網(wǎng)絡(luò)上運行遷移
truffle migrate --network rinkeby
...
3_transfer_ownership.js
=======================? ?> Saving migration to chain.
? ?-------------------------------------
...
實現(xiàn)一個新的升級版本
一段時間后,我們決定要向合約添加功能。 在本文中,我們將添加一個increment函數(shù)。
注意:我們無法更改之前合約實現(xiàn)的存儲布局,有關(guān)技術(shù)限制的更多詳細信息,請參閱升級。
使用以下Solidity代碼在你的contracts目錄中創(chuàng)建新的實現(xiàn)BoxV2.sol 。
BoxV2.sol
// contracts/BoxV2.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
contract BoxV2 {
uint256 private value;
// Emitted when the stored value changes
event ValueChanged(uint256 newValue);
// Stores a new value in the contract
function store(uint256 newValue) public {
value = newValue;
emit ValueChanged(newValue);
}
// Reads the last stored value
function retrieve() public view returns (uint256) {
return value;
}
// Increments the stored value by 1
function increment() public {
value = value + 1;
emit ValueChanged(value);
}
}
部署新的升級版本
一旦測試了新的實現(xiàn),就可以準備升級。 這將驗證并部署新合約。 注意:我們僅是準備升級。
在migrations目錄中創(chuàng)建以下4_prepare_upgrade_boxv2.js腳本。
4_prepare_upgrade_boxv2.js
// migrations/4_prepare_upgrade_boxv2.js
const Box = artifacts.require('Box');
const BoxV2 = artifacts.require('BoxV2');
const { prepareUpgrade } = require('@openzeppelin/truffle-upgrades');
module.exports = async function (deployer) {
const box = await Box.deployed();
await prepareUpgrade(box.address, BoxV2, { deployer });
};
在Rinkeby網(wǎng)絡(luò)上運行遷移,以部署新的合約實現(xiàn)
truffle migrate --network rinkeby
...
4_prepare_upgrade_boxv2.js
==========================? ?Deploying 'BoxV2'
? ?-----------------
? ?> transaction hash: ? ?0x078c4c4454bb15e3791bc80396975e6e8fc8efb76c6f54c321cdaa01f5b960a7
? ?> Blocks: 1 ? ? ? ? ? ?Seconds: 17
? ?> contract address: ? ?0xEc784bE1CC7F5deA6976f61f578b328E856FB72c
...
部署后地址?
?進入truffle控制臺
truffle console --network rinkeby
truffle(rinkeby)> box = await Box.deployed()
truffle(rinkeby)> boxV2 = await BoxV2.deployed()
truffle(rinkeby)> box.address
'0xF325bB49f91445F97241Ec5C286f90215a7E3BC6'
truffle(rinkeby)> boxV2.address
'0xEc784bE1CC7F5deA6976f61f578b328E856FB72c'
升級合約
執(zhí)行ProxyAdmin合約的upgrade方法
proxy:TransparentUpgradeableProxy合約的地址
implementation:BoxV2合約的地址
然后需要在MetaMask(或你正使用的錢包)中簽署交易。
現(xiàn)在,我們可以與升級后的合約進行交互。 我們需要使用代理地址與BoxV2進行交互。 然后,我們可以調(diào)用新的“增量”功能,觀察到整個升級過程中都保持了狀態(tài)。
進入truffle控制臺文章來源:http://www.zghlxwxcb.cn/news/detail-403113.html
truffle console --network rinkeby
truffle(rinkeby)> box = await Box.deployed()
truffle(rinkeby)> boxV2 = await BoxV2.at(box.address)
truffle(rinkeby)> (await boxV2.retrieve()).toString()
'42'
truffle(rinkeby)> await boxV2.increment()
{ tx:
...
truffle(rinkeby)> (await boxV2.retrieve()).toString()
'43'文章來源地址http://www.zghlxwxcb.cn/news/detail-403113.html
到了這里,關(guān)于部署OpenZeppelin可升級合約的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!