There are a couple of problems that I foresee with this (but it might just be that I have missed something).
So, consider an hypothetical token, which has a burn
, which sends you back the ether:
function burn(amount int){
assert(balances[msg.sender] > amount);
if !msg.sender.send(amount).gas(0){
revert()
}
balances[msg.sender] -= amount
}
The code above looks like it would not be safe against reentrancy, but it de-facto is, since send
only has 0
gas, which becomes 2300
on the receiving end. This may be bad practice, but it’s still an invariant that has been around forever: “A 0->2300 CALL cannot modify state”.
With options 1,2,3, you put origin
in charge of gas forwarding, meaning that the (potentially malicious) transaction signer can change the behaviour of the (target) contract, and turn what today is not a vulnerable contract into a vulnerable contract.
Regarding Option 4, I don’t really understand it.
So, to handle the now vulnerable contracts, we obviously need to do something about the 2300
gas limit.
- Option 1 (EDITED): Yes, this would probably work, in most cases. I know that Serpent once upon a time added a little bonus on top of the 2300. If there are such contracts around, they would not benefit from the “0-2300 means no state changes” rule.
- Option 2: I think the contract-types broken by 1884 would be broken again :
EIp-1884. Example 1: (SLOAD + LOG)
function () public onlyIfRunning payable {
require(isApproved(msg.sender));
LogEthReceived(msg.sender, msg.value);
}
Example 2 (2 SLOAD):
modifier onlyICO() {
require(now >= icoStartDate && now < icoEndDate, "CrowdSale is not running");
_;
}