Search code examples
blockchainethereumsolidityether

Solidity: Is it possible to combine event emit and require?


If a user doesn't send enough enough Eth, I'd like the UI to know and respond with a message.

This function validates msg.value, but I'd like to trigger and event (which the UI can respond to) in this case.

function doSomething() external payable {
  require(
      msg.value == price,
      'Please send the correct amount of ETH'
  );
  //Do something
}

Is this the correct way to do that?

Is there any way to combine require() with sending events?

function doSomething() external payable {
 if (msg.value < amount){
   emit NotEnoughEth('Please make sure to send correct amount');
   revert();
 }

  //Do something
}

Solution

  • emit NotEnoughEth('Please make sure to send correct amount');
    

    you can't do this. to be able to emit a types.Log you need your evm.Call() to execute without doing a revert. There are 2 instructions in the EVM you are referring to: makeLog (https://github.com/ethereum/go-ethereum/blob/2aaff0ad76991be8851ae30454d2e2e967704102/core/vm/instructions.go#L828) this is the one that creates and Event log. And opRevert (https://github.com/ethereum/go-ethereum/blob/2aaff0ad76991be8851ae30454d2e2e967704102/core/vm/instructions.go#L806) , so if you do the revert, your Call() will return an error, and all the result of the transaction on ethereum State database will be reverted and nothing will be saved. Since the storage is cancelled, there is no way for your Log to be saved on the blockchain.

    This is the code that will check for error, and reverts to previously saved state (aka Snapshot) :

        if err != nil {
            evm.StateDB.RevertToSnapshot(snapshot)
            if err != ErrExecutionReverted {
                gas = 0
            }
            // TODO: consider clearing up unused snapshots:
            //} else {
            //  evm.StateDB.DiscardSnapshot(snapshot)
        }
        return ret, gas, err
    }
    

    https://github.com/ethereum/go-ethereum/blob/2aaff0ad76991be8851ae30454d2e2e967704102/core/vm/evm.go#L280

    Even though the opRevert() instruction doesn't explicitly returns an error, the Jump table is configured to always return an error for opRevert :

    instructionSet[REVERT] = &operation{
        execute:    opRevert,
        dynamicGas: gasRevert,
        minStack:   minStack(2, 0),
        maxStack:   maxStack(2, 0),
        memorySize: memoryRevert,
        reverts:    true,
        returns:    true,
    }
    

    https://github.com/ethereum/go-ethereum/blob/2aaff0ad76991be8851ae30454d2e2e967704102/core/vm/jump_table.go#L155

    and the Interpreter will issue errExecutionReverted on its own:

        case operation.reverts:
            return res, ErrExecutionReverted
    

    https://github.com/ethereum/go-ethereum/blob/2aaff0ad76991be8851ae30454d2e2e967704102/core/vm/interpreter.go#L297