delegatecall升级合约几种实现

  • 浪杭
  • 发布于 2025-04-08 17:53
  • 阅读 165

1、直接在代理合约上加代理的地址直接在代理合约上加代理的地址,这样只能加到原有合约的最下边,这样不会破坏存储空间顺序,这样会改动原有合约不建议使用。//https://nxf4usxfbgm.feishu.cn/docx/KmuadfFRVotvWIxw1jhc6KyHnof?openbrd=

1、直接在代理合约上加代理的地址

直接在代理合约上加代理的地址,这样只能加到原有合约的最下边,这样不会破坏存储空间顺序,这样会改动原有合约不建议使用。

// https://nxf4usxfbgm.feishu.cn/docx/KmuadfFRVotvWIxw1jhc6KyHnof?openbrd=1&doc_app_id=501&blockId=Ah28dFItmoVDYixCMs1cI3Tpnig&blockType=whiteboard&blockToken=GiRuw7FDph0pWVbE8FVccXIhnDg#Ah28dFItmoVDYixCMs1cI3Tpnig
pragma solidity ^0.8.0;

contract CounterV1{

    uint public count;

    function addCount(uint256 i) public {
        count+=1;
    }
    function getCount() public view returns (uint256){
        return count;
    }
    address public impl;
}

contract ProxyCounter{

    uint public count;

    function addCount(uint i) public {
        bytes memory callData =abi.encodeWithSignature("addCount(uint256)", i);
        (bool succ, ) = address(impl).delegatecall(callData);
        if (!succ) revert("delegatecall fail");
    }
    function getCount() external  returns (uint256){
        bytes memory callData =abi.encodeWithSignature("getCount()");
        (bool succ, bytes memory data) = address(impl).delegatecall(callData);
        if (!succ) revert("delegatecall fail");
        return abi.decode(data, (uint256));
    }
    function upgrade(address addr) public {
        impl = addr;
    }
    address public impl;
}

contract CounterV2{

    uint public count;

    function addCount(uint256 i) public {
        count+=i;
    }
    function getCount() public view returns (uint256){
        return count;
    }
    address public impl;
}

2、使用eip1967把需要升级的原有合约地址放到最后边

只需要更改代理合约,原有合约不需要改变,把需要升级的合约地址添加到upgradeTo方法即可

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;

contract CounterV1{

    uint public count;

    function addCount(uint256 i) public {
        count+=1;
    }
    function getCount() public view returns (uint256){
        return count;
    }
}

contract ProxyCounter{

    uint public count;
    event Upgraded(address indexed implementation);

    function addCount(uint i) external  {
        bytes memory callData =abi.encodeWithSignature("addCount(uint256)", i);
        (bool succ, ) = _getImplementation().delegatecall(callData);
        if (!succ) revert("delegatecall fail");
    }
    function getCount() external  returns (uint256){
        bytes memory callData =abi.encodeWithSignature("getCount()");
        (bool succ, bytes memory data) =_getImplementation().delegatecall(callData);
        if (!succ) revert("delegatecall fail");
        return abi.decode(data, (uint256));
    }
    constructor(){}

    function upgradeTo(address newImplementation) external  {
        require(newImplementation != address(0), "Invalid address");

        bytes32 slot = bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1);

        // 检查新实现合约是否符合要求
        // 例如:检查合约是否支持特定接口

        assembly {
            sstore(slot, newImplementation)
        }   
        emit Upgraded(newImplementation);
    }

    function _getImplementation() private view returns (address) {
        bytes32 slot = bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1);
        address impl;
        assembly {
            impl := sload(slot)
        }
        return impl;
    }

}

contract CounterV2{

    uint public count;

    function addCount(uint256 i) public {
        count+=i;
    }
    function getCount() public view returns (uint256){
        return count;
    }
}

3、委托通用函数来代理不需要写原有合约的逻辑

直接代理把原有合约放到upgradeTo方法里边进行代理,然后在remix部署原有合约at address里边填写代理合约地址就直接可以代理; 升级合约先部署好然后放到代理合约upgradeTo方法里边进行代理,然后在remix部署原有合约at address里边填写代理合约地址就直接可以代理,在升级合约执行业务逻辑,代理合约里边的值也会随着改变

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;

contract CounterV1{

    // address public impl;
    uint public count;

    function addCount(uint256 i) public {
        count+=1;
    }
    function getCount() public view returns (uint256){
        return count;
    }
}

contract ProxyCounter{

    uint public count;

    // EIP-1967 实现合约存储插槽
    bytes32 private constant _IMPLEMENTATION_SLOT = 
        bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1);

    // constructor(address implementation) {
    //     // require(implementation.isContract(), "Proxy: implementation is not a contract");
    //     _setImplementation(implementation);
    // }
    function upgradeTo(address _newImplementation) public {
        _setImplementation(_newImplementation);
    }
    function _setImplementation(address newImplementation) private   {

        bytes32 slot = _IMPLEMENTATION_SLOT;
        assembly {
            sstore(slot, newImplementation)
        }
    }
    receive() external payable { 
         _delegate(_implementation());
    }
    fallback() external payable {
        _delegate(_implementation());
    }

    function _implementation() internal view returns (address impl) {
        bytes32 slot = _IMPLEMENTATION_SLOT;
        assembly {
            impl := sload(slot)
        }
    }

    function _delegate(address implementation) internal {
        assembly {
            calldatacopy(0, 0, calldatasize())
            let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
            returndatacopy(0, 0, returndatasize())
            switch result
            case 0 { revert(0, returndatasize()) }
            default { return(0, returndatasize()) }
        }
    }

}

contract CounterV2{

    uint public count;

    function addCount(uint256 i) public {
        count+=i;
    }
    function getCount() public view returns (uint256){
        return count;
    }
}
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
浪杭
浪杭
0x8EE7...F029
江湖只有他的大名,没有他的介绍。