solidity
solidity copied to clipboard
Triggering complex events leads to transfer failure
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
// 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;
}
}
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.
I believe transfer
only passes 2300 gas by default, which isn't enough to do the call
+ emit
.
Use .call
instead
However, if the event does not return string, uint and address at the same time, then transfer and send can succeed
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.
ok thanku
Thanks for the help @joshlang, closing this then.