1

I am playing around with Solidity 0.6.1 and trying to build a simple funds forwarder. So ETH is sent to the contract and it sends the funds to another address.

I deployed it to Ropsten. But every time I send ETH to the contract address the transaction fails due to

Warning! Error encountered during contract execution [Out of gas] 

Here is my contract

pragma solidity ^0.6.1;

contract testFallback  {
    address payable public addr = 0x...;
    receive() external payable {
        if (msg.value > 0) {
            if (!addr.send(address(this).balance)) revert();
        }
    }
}

and an example of a failed transaction.

I have tried using the

fallback() external payable

function as well. I have been reading up on it here but I am unsure. why my contract cannot accept and then forward the ETH i=I send it. Thanks for your help.

4
  • It's possible the address you are trying to send to is rejecting it. Is it an EOA or another contract? Also, and your testing side, are you sending from an EOA or another contract? Commented Jan 23, 2020 at 23:32
  • @RobHitchens-B9lab I am sending from an EOA my account on metamask. And the address I am sending to is the contract created above. Thee address that the contract is forwarding to is another metamask account Commented Jan 23, 2020 at 23:39
  • Send extra gas (not gas price) in case the estimateGas function isn't working as expected. Commented Jan 23, 2020 at 23:44
  • 1
    @RobHitchens-B9lab the default value for the gas units was 85028 and by sending 185028 instead the transaction was confirmed. How could I code the smart contract to require more gas units in the estimateGas function so that a user would not have to change the gas fee? Thank you Commented Jan 24, 2020 at 0:01

3 Answers 3

1

Based on the comments, it's likely just gas estimation problem and you can resolve it by supplying more gas.

You can force a certain amount of gas to be sent forward using a syntax that might look a little scary. This sort of a long-hand way to do a send:

bool success = address(0).call.value(msg.value).gas(2300)(abi.encodeWithSelector(""));

Some caveats:

  • I'm not convinced the issue is owing to the receiver of that send running out. You should test around it to determine which step is failing.
  • Sending extra gas with a send defeats the gas stipend and may make your contract more vulnerable to reentrance attack. Not a problem if you follow best practice so you're not reliant on the protection provided by the gas stipend.
  • It is a failure point to hard-code a gas budget into your contract. Both the gas stipend and the pricing of OPCODEs are subject to change over time. Don't assume that today's arithmetic/findings will be tomorrow's. The Aragon project got into to trouble this way with a recent EVM fork. If you find a reason to do that, you probably need a way to change the constants from time to time to avoid obsolescence/failure.

More likely, MetaMask isn't supplying enough gas because the estimate is wrong. In that case it has to be resolved client-side.

You already know how to do it manually. A good web-based UI will form the transaction with something like:

var txn = await instance.revert({value: amount, from: me, gasPrice: bid, gas: HERE});

and you can add a little padding because you know MetaMask needs your estimate instead of its own.

Hope it helps.

5
  • Thank you this is a great detailed response Commented Jan 24, 2020 at 3:05
  • Hi Rob! Could you please explain in details your long statement? What happens in case of SC on the other side? Should it impact the receive() function or it is relying on the fallback() presence? Thank you in advance!
    – Rick Park
    Commented Jan 24, 2020 at 3:38
  • 1
    Which statement? Sorry. Commented Jan 24, 2020 at 4:04
  • This one: bool success = address(0).call.value(msg.value).gas(2300)(abi.encodeWithSelector(""));
    – Rick Park
    Commented Jan 24, 2020 at 8:37
  • It's supposed to rely on the fallback (encodeWithSelector("")). I just wanted to show the syntax for taking full control of gas allotment for the call and catching the result. Commented Jan 24, 2020 at 18:23
0

Apparently if you want to forward all the balance in a contract, you cannot have any amount available to pay the gas needed for the transaction.

That is: you need to have the sum of the contract balance (the amount you want to forward) + the gas needed to run the transaction and, unluckily, you have “the balance” only.

Let’s say that you send 100 ether to the forwarder. And that it needs 2300 wei of gas to make the transaction. The maximum it can forward is 100 eth - 2300 wei, not 100 Eth.

Try to forward something less than what is received in order to have gas available for the transaction.

0

Base on @Rob Hitchens , Recently on ^6.0 version . I update the version like the following:

receive() external payable {
    address(0).call{value:msg.value, gas:2300};
  //........................
}

and it is working

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.