token - Solidity 中的 EndSale() 函数失败
问题描述
我有以下可靠代码:
function endSale() public {
require(msg.sender == admin);
require(tokenContract.transfer(admin, tokenContract.balanceOf(address(this))));
// UPDATE: Let's not destroy the contract here
// Just transfer the balance to the admin
msg.sender.transfer(address(this).balance);
}
由于某种原因,当我调用该函数时它失败了。我正在使用 pragma solidity 0.6.0;能否请你帮忙?谢谢!
解决方案
首先,这行代码
require(tokenContract.transfer(admin, tokenContract.balanceOf(address(this))));
告诉你的合约将其全部余额转移到管理员地址,要求调用 transfer 的结果为 true,否则函数失败并且状态恢复,阻止进一步执行。
然后,调用:
msg.sender.transfer(address(this).balance);
再次尝试转移该合约的总余额。
需要注意的一点是,当声明并用作合约中声明的修饰符语句时, require语句可以确保在函数体执行之前满足合约状态的条件。
另一件事是,对.transfer的调用不会返回任何内容,它们只会传播发生的错误。使用函数.send()有一个替代工作,它确实返回一个布尔值,但它在语法上不是很吸引人,并且不建议使用它,除非有必要或者你知道你在做什么,因为程序员需要明确要求在调用返回 false 的情况下调用revert()并且如果忽略可能会导致严重的错误。
所以实际上,调用
require(tokenContract.transfer(admin, tokenContract.balanceOf(address(this))));
应该总是以异常终止,因为它既不评估为真也不评估为假,并且在大多数其他编程语言中,solidity 没有普遍存在的 NULL 值的概念。
您可以通过将字符串作为第二个参数添加到require调用来确定是否是这种情况, 当条件评估为false时,它将输出一条日志消息。
然后,如果由于某种原因不是终止执行的原因,您还试图转移合同的余额,然后再调用您的方法转移其余额。
这是一个重大的逻辑错误/错误,并会尝试再次(在合同已经这样做之后)导致相同金额的转移,这被称为双重支付,但它不应再有余额,因为它有已通过require()中的先前调用转移给管理员;.
一个合理的解决方案可能看起来类似于:
modifier onlyAdmin(){
require(msg.sender == admin, "only an admin may access this method");
_;
}
modifier nonZeroBalance(){
require(tokenContract.balanceOf(address(this)) > 0 wei, "contract requires a non-zero balance to execute");
_;
}
function endSale() public onlyAdmin nonZeroBalance {
//
// require this contract to have a non-zero balance (or any other appropriate value as required) before accepting transfers since,
// it's a waste of gas to transfer nothing
//
// now transfer should work alright and will throw and exception,
// should .transfer fail in any way
uint256 previousBalance = address(this).balance;
//
msg.sender.transfer(previousBalance);
//
//transaction complete, this contract's balance is now 0
//
//perform additional sanity checks to ensure this contract and the admin's
//state are what should be expected, otherwise call revert() or throw()
}
推荐阅读
- c - 我的链接列表正在打印我的文本文件中所有元素的最后一个单词
- android - fragment.xml 中的 DrawerLayout 未在主页图标单击时显示
- java - IllegalStateException:相同的线程,不同的源(GUI)
- angular - angular 5 根据另一个字段的值有条件地验证字段
- sonos - Oauth2 进程中的错误:请求的资源上不存在“Access-Control-Allow-Origin”标头
- node.js - json数组中的节点分页
- azure-active-directory - LoginAsync 使用访问令牌和 MobileServiceAuthenticationProvider.WindowsAzureActiveDirectory
- angular - 离子 4 标签放置
- html - 只需将样式应用于 IE/Edge
- openssl - OpenSSL 警报编号 40