关于solidity的delegatecall的坑

今天遇到一个问题,记录这个坑

pragma solidity ^0.4.26;

contract Proxy {

    address internal masterCopy;
    constructor(address _masterCopy)
        public
    {
        require(_masterCopy != address(0), "Invalid master copy address provided");
        masterCopy = _masterCopy;
    }

    /// @dev Fallback function forwards all transactions and returns all received return data.
    function ()
        external
        payable
    {
        // solium-disable-next-line security/no-inline-assembly
        assembly {
            let masterCopy := and(sload(0), 0xffffffffffffffffffffffffffffffffffffffff)
            // 0xa619486e == keccak("masterCopy()"). The value is right padded to 32-bytes with 0s
            if eq(calldataload(0), 0xa619486e00000000000000000000000000000000000000000000000000000000) {
                mstore(0, masterCopy)
                return(0, 0x20)
            }
            calldatacopy(0, 0, calldatasize())
            let success := delegatecall(gas, masterCopy, 0, calldatasize(), 0, 0)
            returndatacopy(0, 0, returndatasize())
            if eq(success, 0) { revert(0, returndatasize()) }
            return(0, returndatasize())
        }
    }
}


contract Erc20 {
    address public sender;
    event DoSomething(address); 
    function dosomthing() public returns(bool){
        sender = msg.sender;
        emit DoSomething(msg.sender);
        return true;
    }
}


contract Hacker {
    event Ok(address,bytes,uint256);
    event Failed(bool);

    function setErc20Addr(address addr) public returns(bool) {
        erc20 = Erc20(addr);
    }

    Erc20  public erc20 ;
    function exec(address addr, bytes data, uint256 amount)  public payable returns(bool){
        bool success = erc20.dosomthing();
        if(success) {
            emit Ok(addr, data, amount);
            return true;
        } else {
            emit Failed(false);
            return false;
        }
    }   
}

调用setErc20Addr之后,直接调用Hacker则成功,但是通过调用proxyfallback 函数总是失败。

remix中报错如下
在这里插入图片描述

到底是什么原因呢?

原因是delegatecall的机制: https://solidity-cn.readthedocs.io/zh/develop/introduction-to-smart-contracts.html?highlight=delegatecall#index-13

在这里插入图片描述

也就是说, bool success = erc20.dosomthing(); 这一句,erc20Hacker的成员,当在Proxyfallback调用起Hackerexec时,仅仅把exec函数代码拿来用来,并没有把Hackererc20一起复制过去,所以,erc20是空的!

修改之后:


contract Hacker {
    event Ok(address,bytes,uint256);
    event Failed(bool);

    function exec(address addr, bytes data, uint256 amount)  public payable returns(bool){
        Erc20 erc20 = Erc20(addr);
        bool success = erc20.dosomthing();
        if(success) {
            emit Ok(addr, data, amount);
            return true;
        } else {
            emit Failed(false);
            return false;
        }
    }   
}

也就是说,erc20合约地址由Proxyfallback调用时传进来,再初始化erc20。现在就可以正常调用了。
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值