以太坊智能合约之间的调用

最近有个新的需求
已经有一个代币合约如C,需要实现一个合约,在这个合约中调用代币合约C中的transfer函数,即转代币的函数。

要在一个合约中调用另一个合约,可用用以下三种方式调用。

  • CALL:最常用调用,内置变量msg的值会被修改为调用者,执行环境为被调用者的运行环境。
  • DELEGATECALL:调用后内置变量msg的值不会修改为调用者,但执行环境为调用者的运行环境。
  • CALLCODE和DELEGATECALL: 是在调用者的上下文中执行, 可以修改调用者的storage; CALLCODE 阻止msg.sender和msg.value传递;
    而DELEGATECALL不阻止;

在A的合约中,B.callcode(c的函数): c看到msg.sender是B;
在A的合约中,B.delegatecall(c的函数): c看到msg.sender是A;

可以看到,这三种方式都并不符合我们的需求。
方法只有,先让用户调用代币合约C中的approve方法,再调用下面实现的合约中的depositToken方法。
pragma solidity ^0.4.25;

contract Deposit {
    
    bool public stopped = false;
    uint256 public totalDeposit=0;
    uint256 minDepositValue;
    address owner;
    address cTokenAddr=0x01c2ce7bd1bc34eed8a99d0ea0abee305362c143;
    uint256 minBlockGap;
    mapping(address => mapping(string=>uint256))  depositRecords;
    mapping(address=>mapping(string=>uint256))  withdrawRecords;
    uint256 public account=0;
    
    uint256 public blocknum ;
   
    constructor(uint256 _minValue,uint256 _minBlockGap) public {
        owner=msg.sender;
        minDepositValue=_minValue;
        minBlockGap=_minBlockGap;
    }
    
    event Withdraw(address indexed _from, string indexed _pk, uint indexed _value);
    event DepositToken(address indexed _from,address indexed _to,uint256 indexed _value);


    function depositToken(address _to,uint256 _value,string pk) public isRunning  validAddress returns (bool sucess) {
        require(_value>minDepositValue);
        bytes4 transferFromMethodId = bytes4(keccak256("transferFrom(address,address,uint256)"));
        if(cTokenAddr.call(transferFromMethodId,msg.sender,_to, _value)){
             depositRecords[msg.sender][pk]+=_value;
             totalDeposit+=_value;
             emit DepositToken(msg.sender,_to,_value);
             return true;
        }
        return false;
    }
    
    function setMinBlockGap(uint256 _blockGap) public onlyOwner {
        minBlockGap=_blockGap;
    }

    function withdraw(uint256 _value,string _pk) public onlyOwner isRunning  validAddress returns (bool sucess) {
        require(depositRecords[msg.sender][_pk]>_value);
        uint256 blockNumGap=getBlockNumGap(_pk);
        if(blockNumGap<minBlockGap)
             return false;
             
        bytes4 transferMethodId = bytes4(keccak256("transfer(address,uint256)"));
        if(cTokenAddr.call(transferMethodId,msg.sender, _value)){
            depositRecords[msg.sender][_pk]-=_value;
            withdrawRecords[msg.sender][_pk]=0;
            totalDeposit-=_value;
            emit Withdraw(msg.sender,_pk,_value);
            return true;
        }
        return false;
    }

  
    
    function getDeposit(string pk) public view returns (uint256){
        return depositRecords[msg.sender][pk];
    }
    
    function getDepositByAddr(address addr,string pk) public onlyOwner view returns(uint256){
        return depositRecords[addr][pk];
    }
    
    
    function RequestWithdraw(string pk) public returns (bool){
       getBlockNumGap(pk);
    }
    
    function getwithdrawRecords(string pk) public view returns (uint256){
        return withdrawRecords[msg.sender][pk];
    }
    
    function getBlockNum() private view returns (uint256){
        return block.number;
    }
    
  
    function getBlockNumGap(string pk) private returns (uint256){
        uint256 number=getBlockNum();
        if (withdrawRecords[msg.sender][pk]==0){
            withdrawRecords[msg.sender][pk]=number;
            return 0;
        }else{
            return number-withdrawRecords[msg.sender][pk];
        }
    }
    
    function getTotalDeposit()  public onlyOwner view returns (uint256){
        return totalDeposit;
    }
    
    function stop(address _to,bool ifTransfer) public onlyOwner returns (bool sucess) {
        stopped=true;
        if(!ifTransfer){
            return true;
        }
        bytes4 methodId = bytes4(keccak256("transfer(address,uint256)"));
        if(cTokenAddr.call(methodId,_to,totalDeposit)){
            totalDeposit=0;
            return true;
        }
       return false;
    }
    
    function () payable public {
        revert();
    }
    
    function start() public onlyOwner {
        stopped = false;
    }
  
    modifier onlyOwner {
        require(msg.sender == owner);
        _;
    }
    modifier isRunning {
        require(!stopped);
        _;
    }
    modifier validAddress {
        require(address(0) != msg.sender);
        _;
    }
}


版权声明:本文为yujuan110原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。