2

Starting with solidity v0.8.15 we can now get an event selector just as we used for functions.

event.selector

Is it possible at this point to emit an event dynamically based on its selector? Something like:

event E1(bytes32 arg1, bytes32 arg2);
event E2(bytes32 arg1, bytes32 arg2);

function foo() public {
    dynamicEmit(E1.selector, 0x00, 0x00);
    dynamicEmit(E2.selector, 0x00, 0x00);
}

function dynamicEmit(bytes32 eventSelector, bytes32 arg1, bytes32 arg2) internal {
    // emit here event based on selector
} 

1 Answer 1

2

Yes. You'd only have to do a simple if:

    event E1(bytes32 arg1, bytes32 arg2);
    event E2(bytes32 arg1, bytes32 arg2);

    function foo() public {
        dynamicEmit(E1.selector, 0x00, 0x00);
        dynamicEmit(E2.selector, 0x00, 0x00);
    }

    function dynamicEmit(bytes32 eventSelector, bytes32 arg1, bytes32 arg2) internal {
        // emit here event based on selector

        if(E1.selector == eventSelector) {
            emit E1(arg1, arg2);
        } else if(E2.selector == eventSelector) {
            emit E2(arg1, arg2);
        }

    } 

In Remix, it prints something like:

enter image description here

It's not possible to "call" or "emit" an event directly from outside of the contract. An event is not a function. Even though it has a selector, it's not compiled nor used to access it directly. We cannot even declare an event as public.

I compiled the code above and this is the running bytecode:

608060405234801561001057600080fd5b506004361061002b5760003560e01c8063c298557814610030575b600080fd5b61003861003a565b005b61006b7f9a6311b27884bd845f20acbd9a955a4d2b083bc8631271b7520f317d3b4019c76000801b6000801b61009e565b61009c7f1000096eb75ded08a4c6ed11be5789e871886380989efb20fff024b38dadc2166000801b6000801b61009e565b565b827f9a6311b27884bd845f20acbd9a955a4d2b083bc8631271b7520f317d3b4019c703610103577f9a6311b27884bd845f20acbd9a955a4d2b083bc8631271b7520f317d3b4019c782826040516100f6929190610183565b60405180910390a1610165565b827f1000096eb75ded08a4c6ed11be5789e871886380989efb20fff024b38dadc21603610164577f1000096eb75ded08a4c6ed11be5789e871886380989efb20fff024b38dadc216828260405161015b929190610183565b60405180910390a15b5b505050565b6000819050919050565b61017d8161016a565b82525050565b60006040820190506101986000830185610174565b6101a56020830184610174565b939250505056fea26469706673582212209ebf6eb9c67d2c52a1bbd1251e0e75732c3f6b1404bf97066191d0252597f84564736f6c63430008100033

I then decompiled here: https://ethervm.io/decompile

And the entry point function of the decompiled contract, main, looks like this:

function main() {
        memory[0x40:0x60] = 0x80;
        var var0 = msg.value;
    
        if (var0) { revert(memory[0x00:0x00]); }
    
        if (msg.data.length < 0x04) { revert(memory[0x00:0x00]); }
    
        var0 = msg.data[0x00:0x20] >> 0xe0;
    
        if (var0 != 0xc2985578) { revert(memory[0x00:0x00]); }
    
        var var1 = 0x0038;
        func_003A();
        stop();
    }
    

The code only has one public function, foo(). And if we calculate the keccak256 hash of it, then we can see that is:

c2985578b8f3b75f7dc66a767be2a4ef7d7c2224896a1c86e92ccf30bae678b7

You can calculated it yourself here: https://emn178.github.io/online-tools/keccak_256.html

If you take the first 4 bytes of that hash, you endup with c2985578. If you search those bytes in the main() function, you will find it at line:

//...
if (var0 != 0xc2985578) { revert(memory[0x00:0x00]); }
//...

As you can see, since there's only 1 public function, there's only 1 check here. And if you 'call' a 'function' that does not have that selector, then it reverts. Thus, we cannot 'call' an event directly.

Event E1(bytes32,bytes32) keccak256 hash is: 9a6311b27884bd845f20acbd9a955a4d2b083bc8631271b7520f317d3b4019c7

Event E2(bytes32,bytes32) keccak256 hash is: 1000096eb75ded08a4c6ed11be5789e871886380989efb20fff024b38dadc216

We can find those hashes in the decompiled code, but not in the main() function which is the entry point of the contract.

    function func_003A() {
        var var0 = 0x006b;
        var var1 = 0x9a6311b27884bd845f20acbd9a955a4d2b083bc8631271b7520f317d3b4019c7;
        var var2 = 0x00 << 0x00;
        var var3 = 0x00 << 0x00;
        func_009E(var1, var2, var3);
    
    label_006B:
        var0 = 0x009c;
        var1 = 0x1000096eb75ded08a4c6ed11be5789e871886380989efb20fff024b38dadc216;
        var2 = 0x00 << 0x00;
        var3 = 0x00 << 0x00;
        func_009E(var1, var2, var3);
    
    label_009C:
    }
    
    function func_009E(var arg0, var arg1, var arg2) {
        if (!(0x9a6311b27884bd845f20acbd9a955a4d2b083bc8631271b7520f317d3b4019c7 - arg0)) {
            var0 = 0x9a6311b27884bd845f20acbd9a955a4d2b083bc8631271b7520f317d3b4019c7;
            var1 = 0x00f6;
            var2 = arg1;
            var4 = memory[0x40:0x60];
            var3 = arg2;
            var1 = func_0183(var2, var3, var4);
            var temp1 = memory[0x40:0x60];
            log(memory[temp1:temp1 + var1 - temp1], [stack[-2]]);
            return;
        } else if (0x1000096eb75ded08a4c6ed11be5789e871886380989efb20fff024b38dadc216 - arg0) {
        label_0164:
            return;
        } else {
            var var0 = 0x1000096eb75ded08a4c6ed11be5789e871886380989efb20fff024b38dadc216;
            var var1 = 0x015b;
            var var2 = arg1;
            var var3 = arg2;
            var var4 = memory[0x40:0x60];
            var1 = func_0183(var2, var3, var4);
            var temp0 = memory[0x40:0x60];
            log(memory[temp0:temp0 + var1 - temp0], [stack[-2]]);
            goto label_0164;
        }
    }
4
  • 1
    Sure, although I was searching for a solution like when you use call with function selectors, when you encode it with parameters Sep 9, 2022 at 15:57
  • I updated the answer. Take a look. Sep 9, 2022 at 16:24
  • 1
    Clear, hope in the future versions we will be able to emit events "dynamically" Sep 12, 2022 at 11:17
  • 1
    To be more specific: emitting events "dynamically" internally, not from outside the contract (which of course defeats challenges the paradigm quite a bit). There are use cases where it could be useful Sep 13, 2022 at 11:35

Your Answer

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

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