solidity icon indicating copy to clipboard operation
solidity copied to clipboard

Triggering complex events leads to transfer failure

Open PigCharid opened this issue 2 years ago • 6 comments

Call transfer and send to transfer the contract address. When the contract fallback function is triggered, setting an event in the fallback function that returns string, address, uint will cause transfer and send to fail

PigCharid avatar Jul 26 '22 07:07 PigCharid


// SPDX-License-Identifier:MIT
pragma solidity ^0.8;


contract ETHReceiver{
    event Log(uint amount,string func,address to);
    receive()external payable{
        emit Log(msg.value,"func",msg.sender);
    }
    function getBalance()external view returns(uint){
        return address(this).balance;
    }
}
contract SendEth{
    constructor() payable{

    }
    function sendViaTransfer(address payable _to)external  {
        _to.transfer(123);//发的是123个wei
    }
    function sendViaSend(address payable _to)external  {
        bool success = _to.send(123);
        require(success,"send fail");
    }
    function sendViaCall(address payable _to)external  {
       (bool success,)= _to.call{value:123}("");
       require(success,"call fail");
    }
     function getBalance()external view returns(uint){
        return address(this).balance;
    }
}

PigCharid avatar Jul 26 '22 07:07 PigCharid

status false Transaction mined but execution failed
transaction hash 0xdc8fbe8a9f8b7d0f4e584689e23977e4a77a0c224b6516328f9dbf51a665e921
from 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4
to SendEth.sendViaTransfer(address) 0xf5568aF61B089440008183EF92a3296C075A8c15
gas 3000000 gas
transaction cost 33593 gas
execution cost 33593 gas
input 0x636...a4713
decoded input { "address _to": "0xAAC129A3e6e9f44147951dDD5655d66c312A4713" }
decoded output {}
logs []
val 0 wei

transact to SendEth.sendViaTransfer errored: VM error: revert.

revert The transaction has been reverted to the initial state. Note: The called function should be payable if you send value and the value you send should be less than your current balance. Debug the transaction to get more information.

PigCharid avatar Jul 26 '22 07:07 PigCharid

I believe transfer only passes 2300 gas by default, which isn't enough to do the call + emit.

Use .call instead

joshlang avatar Jul 26 '22 16:07 joshlang

However, if the event does not return string, uint and address at the same time, then transfer and send can succeed

PigCharid avatar Jul 27 '22 06:07 PigCharid

Sure, but if I remember correctly, the CALL opcode takes 2100 gas? Something like that, anyway. CALL is how your function is called, and eats away at the 2300 gas that transfer passes.

Then emit takes like 700 or so, plus each parameter for a LOG# opcode

Accessing msg.value and msg.sender each cost a few gas

And there's gotta be some overload loading your string "func" onto the stack.

...Anyway, that's why .call("") exists. It does the same stuff but sends as much gas as it can, plus has other options. So... use it! Noone really uses .send or .transfer any more, for good reason.

joshlang avatar Jul 27 '22 13:07 joshlang

ok thanku

PigCharid avatar Jul 31 '22 15:07 PigCharid

Thanks for the help @joshlang, closing this then.

Marenz avatar Aug 29 '22 14:08 Marenz