solidity call和delegatecall的那些事儿

内容索引

  • 基本概念
    • call的用处
    • call的调用示例
      • 示例合约
      • 合约间调用
      • Remix调用
      • call调用注意事项
  • call vs delegatecall
    • 示例说明
      • call调用的执行上下文
      • delegatecall调用的执行上下文
  • delegatecall漏洞
    • solidity的特性
    • 漏洞示例
    • 扩展
  • 结语
    • 合约安全注意事项
    • call与delegatecall总结

基本概念

call的用处

call是solidity中合约之间交互的一个底层调用,但官方建议该方法仅在发送以太坊时使用,合约接受转账必须定义receive或payable fallback(当调用合约中不存在的方法时,该方法被默认调用),而不建议用call来调用合约中存在的方法。关于receive和fallback的区别见下面示例合约Caller的remoteCall方法,更详细的说明可参考这里。

call的调用示例

下面来演示以太坊的发送及合约方法的调用。注:为了方便调用本方的示例中使用的hardhat的console.sol合约来打印日志信息。

示例合约

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
contract Callee {
    fallback() external payable {
        console.log("In fallback Ether", msg.sender, msg.value);
    }

    receive() external payable {
        console.log("In Receive Ether", msg.sender, msg.value);
    }

    function foo(string memory _message, uint256 _x)
        public
        view
        returns (uint256)
    {
        console.log("foo invoking", msg.sender, _message);
        return _x + 1;
    }
}

contract Caller {
    constructor() payable{

    }
    function remoteCall(address instance) public payable {
        //触发fallback调用
        (bool sucess, ) = instance.call{value: 200}(abi.encodeWithSignature('nonExistingFunction()'));
        require(sucess, "call error");

        // //触发receive调用
        (bool sucess2, ) = instance.call{value: 200}('');
        require(sucess2, "call error");

        //调用foo
        (bool sucess3, ) = instance.call(abi.encodeWithSignature('foo(string,uint256)', 'hello foo', 100));
        require(sucess3, "call error");
    }
}

合约间调用

  • 用js脚本调用触发合约调用
const hre = require('hardhat');
async function main () {

  let Callee = await hre.ethers.getContractFactory("Callee");
  let Caller = await hre.ethers.getContractFactory("Caller");
  let callee = await Callee.deploy();
  //由于remoteCall方法向其它合约转以太坊,因此该合约部署时需要转入
  let caller = await Caller.deploy({value:10000});
  await caller.remoteCall(callee.address);
}

main()
  .then(() => process.exit(0))
  .catch(error => {
    console.error(error);
    process.exit(1);
  });
  • 执行结果solidity call和delegatecall的那些事儿_第1张图片
    注: 当使用npx hardhat run

你可能感兴趣的:(区块链,区块链,node.js,后端,web3)