智能合约通俗点说就是写在区块链上面的代码,代码里面编写着严谨完善的规则,一旦某个用户满足了合约里面的规则条件,就会触发里面的代码,执行某个方法。
为什么要使智能合约达到可升级
智能合约的特点之一就是部署到链上之后不能修改,这一机制使得合约的交互方都可以信任合约。但也带来了一系列的问题,并且如果已部署的合约发现漏洞,也是无法修复的。假如发现了bug,必须修复,那如何处理?就是使用合约达到可升级优化才能满足需求
升级合约的机制原理
什么是合约升级
使已经部署上链的合约做到可优化可更改,例如链上的业务逻辑代码和状态变量达到可增删改的功能.
2.合约升级的实现机制原理
目前实现的方式根据存储区分有各种各样的模式,但是都离不开一个最底层的机制,就是使用delegatecall的特性去实现可升级的合约,达到合约可持续优化更改的效果.
delegatecall介绍
目前调用合约的方式主要有三种
call
delegateCall
staticCall
共同点:都是去调用执行目标合约地址的方法
区别:delegateCall的执行环境和call和staticCall相反,正因为这样所以可利用这种特性实现可升级,在用户层面上无感知。
实现可升级的ERC20合约
编写InitializedProxy代理合约,此合约主要作用是转发和存储数据.
继承openzeppelin的StorageSlotUpgradeable合约,用于插槽工具类。
//SPDX-License-Identifier:GPL-3.0
import" openzeppelin/contracts-upgradeable/utils/StorageSlotUpgradeable.sol";
pragma solidity>=0.7.0<0.9.0;
contract InitializedProxy{
//address of logic contract
//slot bytes32(uint256(keccak256('EIP1967.PROXY.CONFTI.IMPLEMENTATION'))-1)
bytes32 internal constant _IMPLEMENTATION_SLOT=0x5f62ce3c9aebd463c7a36ab1b244d2bb94f07a2c13889b3b687940ebc467b9b3;
//========Constructor=========
constructor(
address logic,
bytes memory initializationCalldata
){
require(logic!=address(0),"Proxy::Wrong proxy contract address");
StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value=logic;
//Delegatecall into the logic contract,supplying initialization calldata
(bool _ok,bytes memory returnData)=
logic.delegatecall(initializationCalldata);
//Revert if delegatecall to implementation reverts
require(_ok,string(returnData));
}
//========Fallback=========
fallback()external payable{
address _impl=StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value;
assembly{
let ptr:=mload(0x40)
calldatacopy(ptr,0,calldatasize())
let result:=delegatecall(gas(),_impl,ptr,calldatasize(),0,0)
let size:=returndatasize()
returndatacopy(ptr,0,size)
switch result
case 0{
revert(ptr,size)
}
default{
return(ptr,size)
}
}
}
//========Receive===
receive()external payable{}//solhint-disable-line no-empty-blocks
function upgradeVersion(address newAddress_)public{
StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value=newAddress_;
}
}