关于【可变合约】的二三事(下)

本文详细介绍了Solidity中的delegatecall函数及其在代理合约中的应用。通过示例解析了如何使用delegatecall调用其他合约的函数,并探讨了代理合约与多重合约的区别。此外,还分析了OpenZeppelin的Proxy合约实现,讲解了内联汇编在实现代理调用中的关键作用。最后,文章提到了代理合约在实际项目中的应用,如TwitterScan的合约实现,并预告了后续将讨论的内容,包括插槽冲突、透明合约和钻石合约等。
摘要由CSDN通过智能技术生成

代理合约

delegatecall函数

要比较好地理解代理合约,必须对delegatecall函数有所了解。

delegatecall是solidity中比较底层的函数,其主要作用就是委托调用,在日常的业务开发中,其实用的比较少,与之类似的函数还有call函数,也是比较底层的函数,其作用是调用。

如果你当前不太理解,没有关系,我直接给一个具体的例子,让你比较好地理解delegatecall。

首先,在进行编码前,你需要知道delegatecall的语法:目标合约address.delegatecall(合约方法对应的二进制编码)。

怎么获得二进制编码?

这需要理解Solidity ABI(Application Binary Interface,应用二进制接口)的概念。ABI是我们与ETH合约交互的标准,Solidity中提供了4个与ABI编码相关的函数,分别是:abi.encode, abi.encodePacked, abi.encodeWithSignature, abi.encodeWithSelector。

其中abi.encodeWithSignature函数获得的结果便是deletegatecall函数需要的二进制编码。ABI相关的细节,单独开一篇文章讨论,这里只需要了解abi.encodeWithSignature函数的使用方式,简单写个合约:

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.4;


contract LearnAbiContract {
    uint256 x = 6;

    address account_addr = 0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2;
    uint[] arr = [1,2,3,4,5];

    function encodeWithSignature() public view returns(bytes memory result) {
        result = abi.encodeWithSignature("function_name(uint256, address, uint[])", x, account_addr, arr);
    }

}

获得的结果如下:

39ce10b9a1a7edb112858451755c888b.png

理解abi.encodeWithSignature函数的使用方式后,便来使用一下delegatecall函数,我们构建出这样的结构:用户通过合约A调用合约B。

嗯,似乎跟多重合约类似?

将合约B的address传递给合约A,然后在合约A中实例化合约B再调用合约B的方法就好了?

是的,但这里,我们通过delegatecall函数的方式来做,顺便我们对比一下,delegatecall函数的做法与多重合约做法之间的差异。

先实现合约B:

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.4;

contract ContractB {
    uint256 public x;
    address public addr;

    event TransferLog(address sender_addr, uint256 amount, uint256 gas);

    function set_value(uint256 _x) public payable {
        x = _x;
        addr = msg.sender;

        if (msg.value > 0) {
          emit TransferLog(msg.sender, msg.value, gasleft());
        }
    }

    function getBalance() public view returns(uint256){
        return address(this).balance;
    }
}

在ContractB合约中,有x变量与addr变量,定义了set_value函数,用payable关键字标注,即该函数可以支持转账功能,最后还有getBalance函数用于查看当前合约的ETH余额。

ContractB合约平平无奇,没啥特别的,接着写ContractA合约:

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.4;

contract ContractA {
    uint256 public x;
    address public addr;

    event Response(bool success, bytes data);

    function deleg
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

懒编程-二两

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值