5

My contract emits several [ink(event)] events. My application subscribes to the events and receives Contracts_ContractEmitted data (from centrifuge go-substrate-rpc-client). How may I understand which of my events caused this?

From my experiments, I see that event.Topic[0] somehow identifies the event - the same event has the same values, different have differents. If so, how is it encoded?

1

1 Answer 1

2

What helped me to get a glimpse of this is to cargo expand a simple lib.rs file.

I added two events to the flipper contract:

    #[ink(event)]
    pub struct Created {
        value: bool,
    }

    #[ink(event)]
    pub struct Flipped {
        #[ink(topic)]
        value: bool,
    }

I executed cargo expand --lib > expanded_lib.rs and somewhere you can find the code where the topics are pushed (push_topic) to the TopicsBuilderBackend.

    const _: () = {
        impl ::ink::env::Topics for Created {
           type RemainingTopics = [::ink::env::topics::state::HasRemainingTopics; 1usize];
            fn topics<E, B>(
                &self,
                builder: ::ink::env::topics::TopicsBuilder<
                    ::ink::env::topics::state::Uninit,
                    E,
                    B,
                >,
            ) -> <B as ::ink::env::topics::TopicsBuilderBackend<E>>::Output
            where
                E: ::ink::env::Environment,
                B: ::ink::env::topics::TopicsBuilderBackend<E>,
            {
                builder
                    .build::<Self>()
                    .push_topic::<
                        ::ink::env::topics::PrefixedValue<[u8; 13usize]>,
                    >(
                        &::ink::env::topics::PrefixedValue {
                            value: b"Test::Created",
                            prefix: b"",
                        },
                    )
                    .finish()
            }
        }
    };
    const _: () = {
        impl ::ink::env::Topics for Flipped {
            type RemainingTopics = [::ink::env::topics::state::HasRemainingTopics; 2usize];
            fn topics<E, B>(
                &self,
                builder: ::ink::env::topics::TopicsBuilder<
                    ::ink::env::topics::state::Uninit,
                    E,
                    B,
                >,
            ) -> <B as ::ink::env::topics::TopicsBuilderBackend<E>>::Output
            where
                E: ::ink::env::Environment,
                B: ::ink::env::topics::TopicsBuilderBackend<E>,
            {
                builder
                    .build::<Self>()
                    .push_topic::<
                        ::ink::env::topics::PrefixedValue<[u8; 13usize]>,
                    >(
                        &::ink::env::topics::PrefixedValue {
                            value: b"Test::Flipped",
                            prefix: b"",
                        },
                    )
                    .push_topic::<
                        ::ink::env::topics::PrefixedValue<bool>,
                    >(
                        &::ink::env::topics::PrefixedValue {
                            value: &self.value,
                            prefix: b"Test::Flipped::value",
                        },
                    )
                    .finish()
            }
        }
    };

The first topic is the PrefixedValue of the event itself:

PrefixedValue { value: b"Test::Created", prefix: b"" }

The second topic is the actual #[ink(topic)] in the struct:

PrefixedValue { value: &self.value, prefix: b"Test::Flipped::value" }

When we add the anonymous attribute we get something like:

    const _: () = {
        impl ::ink::env::Topics for Created {
            type RemainingTopics = ::ink::env::topics::state::NoRemainingTopics;
            fn topics<E, B>(
                &self,
                builder: ::ink::env::topics::TopicsBuilder<
                    ::ink::env::topics::state::Uninit,
                    E,
                    B,
                >,
            ) -> <B as ::ink::env::topics::TopicsBuilderBackend<E>>::Output
            where
                E: ::ink::env::Environment,
                B: ::ink::env::topics::TopicsBuilderBackend<E>,
            {
                builder.build::<Self>().finish()
            }
        }
    };

Where you can see that no topics are pushed to TopicsBuilderBackend.

Additional info: erc20 tests for emitted events.

Hope this helps.

1
  • Genial! This helped a lot. Looking at encoded_into_hash source, I found that for event names shorter than 32 chars, their event ids are those names themselves, no hashing :) So "Test::Created" is simply 0x00546573743a3a43726561746564000000000000000000000000000000000000. Commented May 6, 2023 at 16:25

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.