Solidity极简入门|第二十三讲Delegatecall

delegatecall

delegatecall 与 call 类似,是 solidity 中地址类型的低级成员函数。delegate 中是委托/代表的意思,那么 delegatecall 委托了什么?

当用户 A 通过合约 B 来 call 合约 C 的时候,执行的是合约 C 的函数,语境 (Context,可以理解为包含变量和状态的环境) 也是合约 C 的:msg.sender 是 B 的地址,并且如果函数改变一些状态变量,产生的效果会作用于合约 C 的变量上。

915855a38cdb7f4d4a11c1c49cce995f.jpeg

  call 的语境

而当用户 A 通过合约 B 来 delegatecall 合约 C 的时候,执行的是合约 C 的函数,但是语境仍是合约 B 的:msg.sender 是 A 的地址,并且如果函数改变一些状态变量,产生的效果会作用于合约 B 的变量上。 

2e33aa91856112136418b4b2ec2cc26a.jpeg

delegatecall 的语境 

大家可以这样理解:一个富商把它的资产(状态变量)都交给一个 VC 代理(目标合约的函数)来打理。执行的是 VC 的函数,但是改变的是富商的状态。

delegatecall 语法和 call 类似,也是:    

c37aad3226b7ffa4beb7ed2ebcda0d92.jpeg

  其中二进制编码利用结构化编码函数 abi.encodeWithSignature 获得:

fb2ded489940d7d080a51978ce35e618.jpeg

函数签名为"函数名(逗号分隔的参数类型)"。例如 abi.encodeWithSignature("f(uint256,address)", _x, _addr)。

和 call 不一样,delegatecall 在调用合约时可以指定交易发送的 gas,但不能指定发送的 ETH 数额

注意:delegatecall 有安全隐患,使用时要保证当前合约和目标合约的状态变量存储结构相同,并且目标合约安全,不然会造成资产损失。

什么情况下会用到 delegatecall?

目前 delegatecall 主要有两个应用场景:

代理合约(Proxy Contract):将智能合约的存储合约和逻辑合约分开:代理合约(Proxy Contract)存储所有相关的变量,并且保存逻辑合约的地址;所有函数存在逻辑合约(Logic Contract)里,通过 delegatecall 执行。当升级时,只需要将代理合约指向新的逻辑合约即可。

EIP-2535 Diamonds(钻石):钻石是一个支持构建可在生产中扩展的模块化智能合约系统的标准。钻石是具有多个实施合同的代理合同。更多信息请查看:钻石标准简介。

delegatecall 例子

调用结构:你(A)通过合约 B 调用目标合约 C。

被调用的合约 C

我们先写一个简单的目标合约 C:有两个 public 变量:num 和 sender,分别是 uint256 和 address 类型;有一个函数,可以将 num 设定为传入的_num,并且将 sender 设为 msg.sender。

766934bca52a7366b3bf5b297bb384ad.jpeg

发起调用的合约 B

首先,合约 B 必须和目标合约 C 的变量存储布局必须相同,两个变量,并且顺序为 num 和 sender

692d311bdb0beb3b0d117a139c733da3.jpeg

接下来,我们分别用 call 和 delegatecall 来调用合约 C 的 setVars 函数,更好的理解它们的区别。

callSetVars 函数通过 call 来调用 setVars。它有两个参数_addr 和_num,分别对应合约 C 的地址和 setVars 的参数。

a4c6518091b1e213f85cfe2520158ca3.jpeg

而 delegatecallSetVars 函数通过 delegatecall 来调用 setVars。与上面的 callSetVars 函数相同,有两个参数_addr 和_num,分别对应合约 C 的地址和 setVars 的参数。  

2e01059a81640768083ce200183e9051.jpeg

运行结果

我们把合约 B 和 C 都部署好,然后调用合约 C 中的 callSetVars,传入参数为合约 B 地址和 10。运行后,合约 C 中的状态变量将被修改:num 被改为 10,sender 变为合约 B 的地址。

接下来,我们调用合约 C 中的 delegatecallSetVars,传入参数为合约 B 地址和 100。由于是 delegatecall,语境为合约 B。在运行后,合约 B 中的状态变量将被修改:num 被改为 100,sender 变为合约你的钱包地址。

总结

这一讲我们介绍了 solidity 中的另一个低级函数 delegatecall。与 call 类似,它可以用来调用其他合约;不同点在于运行的语境,B call C,语境为 C;而 B delegatecall C,语境为 B。目前 delegatecall 最大的应用是代理合约和 EIP-2535 Diamonds(钻石)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值