solidity call()与delegatecall()的理解和区别

call()

当使用方法是:require(msg.sender.call.value(_weiToWithdraw)());
则作用是将_weiToWithdraw个以太币发送给msg.sender地址,并且调用msg.sender地址的fallback函数

当使用方法是:

addr.call(abi.encode(keccak256("increaseAge(string,uint)")),"jack",1);
那就是调用了合约地址addr的函数increaseAge,并且传入参数是"jack",1

函数的结果

call()的返回结果是一个bool,表示是否成功的调用,或者是失败引起了EVM异常。该方法无法直接访问函数返回结果(因为需要事前知道编码和返回结果大小)。

call()的返回结果即使成功,并不能说操作成功了,只是没有出现异常,比如我们第一个例子中,实际是调用到了fallback()函数。

delegatecall()

calldelegatecall的功能类似,区别仅在于后者仅使用给定地址(Calltest)的代码,其它信息则使用当前合约(Compare)(如存储,余额等等)。

函数的设计目的是为了借用存储在另一个合约的库代码,作为当前合约代码的一部分执行。

二者执行代码的上下文环境的不同,当使用call调用其它合约的函数时,代码是在被调用的合约的环境里执行,对应的,使用delegatecall进行函数调用时代码则是在调用函数的合约的环境里执行,

通过代码测试说明(注意看注释和执行结果):

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
contract Calltest {
    address public sameAddress;
    // 获取当前合约地址,并赋值
    function test() public {
        sameAddress=address(this);
    }
}


contract Compare {
    // 注意此处的变量与合约Calltest的变量是一模一样的,为delegate,委托调用创造条件
    address public sameAddress;
    
    address public testaddress;
    // 构造时 将合约Calltest的部署地址传入
    constructor(address _addressOfCalltest) {
        testaddress = _addressOfCalltest;
    }
    // call方式调用,代表调用testaddress地址对应合约的test()方法,并且变更testaddress地址对应的状态数据 sameAddress
    function useCall() public {
        testaddress.call(abi.encode(keccak256("test()")));
    }
    // delegatecall 方法调用,官方叫做委托调用
    // 个人理解:其实就是借用testaddress合约地址的test()代码片段,拿到当前合约(Compare)来执行;
    // 也就是说执行时,把test()的代码作为了Compare的一部分代码,但是变量赋值时需要特别小心,每个当前合约的变量都要查看,未经充分测试绝对不要上线
    function useDelegatecall() public {
        testaddress.delegatecall(abi.encode(keccak256("test()")));
    }
}

开发环境:remix+Remix VM(London)

1.部署Calltest合约 获得地址A (0x1E90187F96cb22A93eCfC97dC1F9cBb1A1F3dE99)

2.部署Compare合约,将地址A传入部署,得到地址B (0x1E90187F96cb22A93eCfC97dC1F9cBb1A1F3dE99)

call()测试

        1.Compare合约中调用方法useCall

        2.Calltest合约调用查询方法sameAddress,发现有返回值(A地址)符合预期

        3.Compare合约调用查询方法sameAddress,发现返回值依然是0地址 符合预期

elegatecall()测试

        1.Compare合约中调用方法useDelegatecall

        2.Compare合约调用查询方法sameAddress,发现返回值不是0地址 而是=B地址 出乎意料吧

        精髓:

        elegatecall其实就是借用合约地址testaddress所指向的代码片段,作为当前合约代码的一部分来执行,这样就好理解了,借用+内嵌为当前合约代码执行

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值