如何在Solidity中从我的合约中提取所有代币

9

有人可以帮我吗?

我创建了一个基本合约,但不知道如何撤销函数。请大家帮帮我。谢谢! 我尝试创建一个基本函数,但它没有工作。

function withdraw() public {
    msg.sender.transfer(address(this).balance);
}
4个回答

20
payable(msg.sender).transfer(address(this).balance);

这行代码会提取本地余额(如果您的合约在以太坊网络上,则是ETH)。


要提取代币余额,您需要在代币合约上执行transfer()函数。因此,要提取所有代币,您需要在所有代币合约上执行transfer()函数。

您可以创建一个函数,根据传入的代币合约地址提取任何ERC-20代币。

pragma solidity ^0.8;

interface IERC20 {
    function transfer(address _to, uint256 _amount) external returns (bool);
}

contract MyContract {
    function withdrawToken(address _tokenContract, uint256 _amount) external {
        IERC20 tokenContract = IERC20(_tokenContract);
        
        // transfer the token from address of this contract
        // to address of the user (executing the withdrawToken() function)
        tokenContract.transfer(msg.sender, _amount);
    }
}

请注意,此代码不安全 - 任何人都可以执行withdrawToken()函数。如果您想在生产环境中运行它,请添加某种形式的身份验证,例如Ownable模式。

不幸的是,由于代币标准(以及以太坊网络)的设计方式,没有一种简单的方法可以“一次性转移所有代币”,因为没有一种简单的方法可以获取地址的“非零代币余额”。您在区块链浏览器中看到的(例如,一个地址持有代币X、Y和Z)是无法在区块链上执行的聚合结果。


@learncode 你可能忘记在你的代码中定义接口了。只有当我省略了接口定义时才会得到相同的错误。 - Petr Hejda
我已经成功编译了,但是出现了1个新错误。 这是:Gas 估算失败。 你可以帮我吗? https://goerli.etherscan.io/tx/0x6a32cce4c67919ecc076e8d4cbad42721bb9753f873702846b84d8859f0a35d9 - learn code
请帮我@Petr Hejda。 - learn code
1
这是否意味着我可以使用 payable(msg.sender).transfer(address(this).balance); 在非本地代币合约内转移本地代币?因此,我可以使用此函数在非本地代币合约中传输锁定的本地代币(因某些原因),并使用 IERC20transfer 函数来传输非本地代币? - haxpor
1
@haxpor 没错。 - Petr Hejda
显示剩余4条评论

3
假设您的合约是ERC20,EIP20中定义的transfer函数如下:

将价值为_value的代币转移到地址_to,并必须触发Transfer事件。如果消息发送方的账户余额不足以支付,则该函数应抛出异常。

请注意,价值为0的转移必须被视为正常转移并触发Transfer事件。

function transfer(address _to, uint256 _value) public returns (bool success)

当您调用transfer实现时,基本上是更新调用者和接收者的余额。它们的余额通常存储在映射/查找表数据结构中。
请参见ConsenSys的transfer实现

如何从智能合约中提取基本代币,例如eth和bnb? 我已经尝试了很多次,但都没有成功。 你能帮我吗? - learn code
请给我一个函数。 - learn code
这是我的合约:https://goerli.etherscan.io/address/0x2196cbcc5200ea6d9984fcc425dacc83932e3cf9#code - learn code
如果您想将“HRS”转移到另一个帐户,请调用transfer函数 https://goerli.etherscan.io/address/0x2196cbcc5200ea6d9984fcc425dacc83932e3cf9#writeContract - ƛƛƛ
如果您想从您的合约转移ETH到另一个地址,首先您的合约必须有足够的ETH可以转出。然后您可以在接收方上调用“transfer”函数。 - ƛƛƛ
显示剩余2条评论

2

我来这里是为了找到解决方案,允许所有者提取任何不小心发送到我的智能合约地址的代币。我相信这对其他人也可能有用:

 /**
 * @dev transfer the token from the address of this contract  
 * to address of the owner 
 */
function withdrawToken(address _tokenContract, uint256 _amount) external onlyOwner {
    IERC20 tokenContract = IERC20(_tokenContract);

    // needs to execute `approve()` on the token contract to allow itself the transfer
    tokenContract.approve(address(this), _amount);

    tokenContract.transferFrom(address(this), owner(), _amount);
}

1
  • Since it is a basic contract, I assume it is not erc20 token and if you just want to withdraw money:

    function withdraw(uint amount) external onlyOwner{
       (bool success,)=owner.call{value:amount}("");
       require(success, "Transfer failed!");
     }
    

此函数只应由所有者调用。

  • If you want to withdraw entire balance during emergency situation:

    function emergencyWithdrawAll() external onlyWhenStopped onlyOwner {
       (bool success,)=owner.call{value:address(this).balance}("");
       require(success,"Transfer failed!");
     }
    

这个函数有两个修饰符:onlyWhenStopped onlyOwner

当你需要以下功能时,请使用紧急停止模式:

  • 暂停合约的能力。
  • 保护关键功能免受未发现漏洞的滥用。
  • 为潜在失败做好准备。

修饰符:

modifier onlyOwner() {
    // owner is storage variable is set during constructor
    if (msg.sender != owner) {
      revert OnlyOwner();
    }
    _;
  }
  • for onlyWhenStopped we set a state variable:

      bool public isStopped=false; 
    
然后是修改器。
modifier onlyWhenStopped{
    require(isStopped);
    _;
  }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接