Solidity 中的 EndSale() 函数失败
EndSale() function in Solidity fails
我有以下代码:
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))));
告诉你的合约将其全部余额转移到管理地址,要求转移调用的结果评估为真,否则函数失败并且状态恢复,阻止进一步执行。
然后,调用:
msg.sender.transfer(address(this).balance);
再次尝试转移此合约的总余额。
需要注意的一点是,require语句可以确保满足合约状态的条件before函数体是偶数在合约中声明并用作 修饰符 语句时执行。
另一件事是,调用 .transfer 不会 return 任何东西,它们只会传播发生的错误。有一种替代方法可以使用函数 .send() ,它 做 return 一个 bool 但它在语法上不是很吸引人并且不推荐使用它,除非有必要或者你知道自己在做什么,因为程序员需要明确要求在调用 returns 时调用 revert() false,如果忽视可能会导致严重的错误。
所以实际上,调用
require(tokenContract.transfer(admin, tokenContract.balanceOf(address(this))));
应该总是以异常终止,因为它的计算结果既不为真也不为假,而且 solidity 没有大多数其他编程语言中普遍存在的 NULL 值的概念。
您可以通过将字符串作为第二个参数添加到 require 调用来确定是否属于这种情况,当条件计算为 [=38 时,它将输出一条日志消息=]假.
然后,如果由于某种原因不是终止执行的原因,您还试图转移合同的余额,然后再调用您的方法转移其余额。
这是一个主要的逻辑 error/bug 并且会尝试再次转移相同金额(在合同已经这样做之后),这被称为 双重支付,但它应该不再有余额,因为它已通过之前在 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()
}
我有以下代码:
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))));
告诉你的合约将其全部余额转移到管理地址,要求转移调用的结果评估为真,否则函数失败并且状态恢复,阻止进一步执行。
然后,调用:
msg.sender.transfer(address(this).balance);
再次尝试转移此合约的总余额。
需要注意的一点是,require语句可以确保满足合约状态的条件before函数体是偶数在合约中声明并用作 修饰符 语句时执行。
另一件事是,调用 .transfer 不会 return 任何东西,它们只会传播发生的错误。有一种替代方法可以使用函数 .send() ,它 做 return 一个 bool 但它在语法上不是很吸引人并且不推荐使用它,除非有必要或者你知道自己在做什么,因为程序员需要明确要求在调用 returns 时调用 revert() false,如果忽视可能会导致严重的错误。
所以实际上,调用
require(tokenContract.transfer(admin, tokenContract.balanceOf(address(this))));
应该总是以异常终止,因为它的计算结果既不为真也不为假,而且 solidity 没有大多数其他编程语言中普遍存在的 NULL 值的概念。
您可以通过将字符串作为第二个参数添加到 require 调用来确定是否属于这种情况,当条件计算为 [=38 时,它将输出一条日志消息=]假.
然后,如果由于某种原因不是终止执行的原因,您还试图转移合同的余额,然后再调用您的方法转移其余额。
这是一个主要的逻辑 error/bug 并且会尝试再次转移相同金额(在合同已经这样做之后),这被称为 双重支付,但它应该不再有余额,因为它已通过之前在 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()
}