polkascan / py-substrate-interface

Python Substrate Interface
https://polkascan.github.io/py-substrate-interface/
Apache License 2.0
240 stars 114 forks source link

Map events to extrinsics #184

Closed johnuopini closed 2 years ago

johnuopini commented 2 years ago

I am trying to create a tool that monitors events and notifies the user when something occurs based on filters. I am able to filter and check events and payload just fine by subscribing to new blocks and then checking events using the System.Events storage method, what i am not able to do is to get the extrinsic of the event itself as this is not part of the payload i get, this is required because i need to then point to external tools to browse the extrinsic and i also need to understand how to decode the extrinsic signer to get the source address which is not always part of the extrinsic data.

johnuopini commented 2 years ago

As an example i would like to get the events in the same way Subscan does here: https://moonbeam.subscan.io/extrinsic/333456-4?event=333456-13

This is an Ethereum Transaction Extrinsic that will then create a set of events. I would like to understand if there is a way to get those events out of the extrinsic payload.

arjanz commented 2 years ago

What you can try is to retrieve the ExtrinsicReceipt by the identifier and then you can loop through the triggered events as follows:

substrate = SubstrateInterface(url="wss://wss.api.moonbeam.network")
receipt = ExtrinsicReceipt.create_from_extrinsic_identifier(substrate, "333456-4")

for event in receipt.triggered_events:
    print(event.value)

This functionality might be a bit hidden, so I'm thinking of wrapping it in a function like substrate.retrieve_extrinsic_by_identifier("333456-4")

johnuopini commented 2 years ago

Many thanks for your answer. So what i am doing now is using web3 library to decode Ethereum.Transact extrinsics, it's probably cleaner although I am not always able to get the signing author of those extrinsic. Also with my approach i need the ABI of the call and right now i found no other way than hard coding JSON inside my code. So i think doing your way is probably easier. Will test it.

johnuopini commented 2 years ago

@arjanz any chance to add some helper method to also decode Ethereum exstrinsics? In particular i am trying to get the extrinsic signer out of an Ethereum.Transaction, for example this one: https://moonbeam.subscan.io/extrinsic/338985-8 Subscan correctly maps it to 0xbf6d989ad2ac8ff6ac21875611e205401bb57bc7

However i wasn't able to do that, i can get the signature this way (which i am not sure is correct):

      from eth_account._utils.signing import extract_chain_id, to_standard_v
      s = w3.eth.account._keys.Signature(vrs=(
          to_standard_v(extract_chain_id(signature['v'])[1]),
          w3.toInt(hexstr=signature['r']),
          w3.toInt(hexstr=signature['s'])
      ))

But then i need the msg hash to recover the public key and then the address and looks like there is no way to do that (i though call_hash in the extrinsic could be used but its doesnt work).

Any help would be appreciated!

arjanz commented 2 years ago

Maybe I don't understand your exact question, but isn't the Ethereum signer just inside the Ethereum.Executed event triggered by the extrinsic you mentioned?

substrate = SubstrateInterface(url="wss://wss.api.moonbeam.network")
receipt = substrate.retrieve_extrinsic_by_identifier("338985-8")

print(receipt.triggered_events[6].value['attributes'][0])
# '0xbf6d989ad2ac8ff6ac21875611e205401bb57bc7'

Needless to say my support is limited to this library :)

johnuopini commented 2 years ago

Yeah, i know its in the events but thats not what subscan does (i guess), the event could be any kind of payload, its not verified, Subscan get the address from the signature itself. Also i understand EVM is moonbeam specific but Moonbeam is not the only EVM compatible parachain and having a way to decode an EVM transaction encapsuled in an extrinsic i think could be useful for the library.

Anyway, many thanks!

johnuopini commented 2 years ago

I have been able to find the correct address by using EVM calls. Closing.