Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parsing of events #697

Closed
edisontim opened this issue Jul 25, 2023 · 18 comments · Fixed by #704
Closed

Parsing of events #697

edisontim opened this issue Jul 25, 2023 · 18 comments · Fixed by #704
Assignees
Labels
OnlyDust Open for OnlyDust contributors released on @next Type: feature New feature or request

Comments

@edisontim
Copy link
Contributor

edisontim commented Jul 25, 2023

Is your feature request related to a problem? Please describe.
Not related to a problem per se but it would facilitate the usage of events in Starknet js

Describe the solution you'd like
It's a hassle to read events coming from a contract for which we have the ABI available. I think it would be very nice to have a ParseEvent function available in the Contract class

For now I believe the only way of reading events is by parsing it manually: https://www.starknetjs.com/docs/guides/events

@edisontim edisontim added the Type: feature New feature or request label Jul 25, 2023
@edisontim
Copy link
Contributor Author

I'm willing to implement this btw

@ivpavici
Copy link
Collaborator

Hello!
We already have an (old) issue open for this:
#112

The issue was that nodes didn't have web sockets implemented... But there are developments in this area being done as we speak...

Does this "help" or you have a different use case in mind?

@edisontim
Copy link
Contributor Author

edisontim commented Jul 25, 2023

I meant something different, after using provider.waitForTransaction(tx_hash) there can be a bunch of events emitted during that transaction, what I want to do is being able to call a parseEvent function of the contract object to parse the event's data into a useful format. Contract which I created with the ABI that has the definition of the event. Hopefully that makes if clearer, otherwise I can post an example

@tabaktoni
Copy link
Collaborator

tabaktoni commented Jul 25, 2023

Usage would be like?

const tx = myContract.increase_balance(1000);
waitForTransaction(tx.tx_hash)
const events = myContract.getEvents(tx.tx_hash);

Or with the event name?
const event = myContract.getEvent('myEvent', tx.tx_hash);
Or
const event = myContract.myEvent(tx.tx_hash);

Where event/s would be nicely formatted and parsed to js data based on ABI.
This is a good idea.
Before you start, it would be good to describe the use case so we can discuss the final interface before implementation.

@edisontim
Copy link
Contributor Author

I was thinking more of this:

const tx = myContract.increase_balance(1000);
const transactionResult = await provider.waitForTransaction(tx.transaction_hash);
const events = myContract.getEvents(transactionResult);

Then you don't need to query the blockchain again as every event is already stored in transactionResult, it would just find the events in transactionResult that match myContract.address. Only thing I'm not sure of is how you would get from the event's name in the ABI formatted as such:

{
	"kind": "struct",
	"name": "game::Game::StartGame",
	"type": "event",
	"members": [
	{
		"kind": "data",
		"name": "adventurer_state",
		"type": "game::Game::AdventurerState"
	},
	{
		"kind": "data",
		"name": "adventurer_meta",
		"type": "survivor::adventurer_meta::AdventurerMetadata"
	}
	]
},

to the event.key hash. Not sure how it's hashed

@PhilippeR26
Copy link
Collaborator

PhilippeR26 commented Jul 26, 2023

The hash of an event is :

starkCurve.keccak(eventName)

It will be necessary to take care that the event can write in both keys and data arrays :

{
      "type": "event",
      "name": "PhilTest2::PhilTest2::MyTestContract::CounterIncreased",
      "kind": "struct",
      "members": [
        {
          "name": "from",
          "type": "core::starknet::contract_address::ContractAddress",
          "kind": "key"
        },
        {
          "name": "amount",
          "type": "core::integer::u128",
          "kind": "data"
        }
      ]
    },

My feeling is that we should have :

const events: ParsedEvent[] = myContract.parseEvents(transactionResult);

For example with this :

{
    data: [ '0xa' ],
    from_address: '0x45b73ec5c290f6a5ed780bcde055ba5d914e1931ac3f04be9c51d091bbe2094',
    keys: [
      '0xd3651022da7ddf0a226dd81c8a16106318358829bd09702eb656630219c030',
      '0x6c8fe36d7454901424063b5c1b949d7e347ce3872d2487b30b76f3a4fd7c219'
    ]
  }

The result could be (type ParsedEvent) :

{
eventName : "CounterIncreased",
keys: {from: "0x6c8fe36d7454901424063b5c1b949d7e347ce3872d2487b30b76f3a4fd7c219"},
data: {amount: "0xa"}
}

@edisontim
Copy link
Contributor Author

edisontim commented Jul 27, 2023

Yep, exactly what I had in mind, thank you for the example!

@tabaktoni
Copy link
Collaborator

tabaktoni commented Jul 27, 2023

Ok, so implementation can be made in utils/events/responseParser.ts ?
Wrapper function in Contract Class that uses implementation

public parseEvents(receipt: GetTransactionReceiptResponse): ParsedEvent

@tabaktoni tabaktoni added the OnlyDust Open for OnlyDust contributors label Jul 27, 2023
@tabaktoni
Copy link
Collaborator

@edisontim You can start working on this task

@tabaktoni
Copy link
Collaborator

{
      "type": "event",
      "name": "PhilTest2::PhilTest2::MyTestContract::CounterIncreased",
      "kind": "struct",
      "members": [
        {
          "name": "from",
          "type": "core::starknet::contract_address::ContractAddress",
          "kind": "key"
        },
        {
          "name": "amount",
          "type": "core::integer::u128",
          "kind": "data"
        }
      ]
    },

The result could be (type ParsedEvent) :

{
eventName : "CounterIncreased",
keys: {from: "0x6c8fe36d7454901424063b5c1b949d7e347ce3872d2487b30b76f3a4fd7c219"},
data: {amount: "0xa"}
}

On this point final result should be js representation of data so for Struct of this types:

{
  CounterIncreased: {
    from: BigInt,
    amount: BigInt,
  }
}

@edisontim
Copy link
Contributor Author

Implemented in #704

@edisontim
Copy link
Contributor Author

Could someone have a look at the PR? The CI doesn't pass but I've tried to reproduce the failure locally and can't manage to @ivpavici ?

@edisontim
Copy link
Contributor Author

On this point final result should be js representation of data so for Struct of this types:

Had to slightly change the final representation as multiple events of the same type can be in the same receipt:

{
  CounterIncreased: [
    {
      from: BigInt,
      amount: BigInt,
    },
    ...
  ]
}

@PhilippeR26
Copy link
Collaborator

PhilippeR26 commented Aug 8, 2023

I made a test with this format, and I am not fully convinced.
The result :

events = {
  EventRegular: [
    {
      simpleKeyVariable: 0n,
      simpleKeyStruct: [Object],
      simpleKeyArray: [Array],
      simpleDataVariable: 6n,
      simpleDataStruct: [Object],
      simpleDataArray: [Array]
    },
    {
      simpleKeyVariable: 100n,
      simpleKeyStruct: [Object],
      simpleKeyArray: [Array],
      simpleDataVariable: 6n,
      simpleDataStruct: [Object],
      simpleDataArray: [Array]
    }
  ],
  EventPanic: [ { errorType: 8n, errorDescription: 93566154138418073030976302n } ],
  EventNested: [ { nestedKeyStruct: [Object], nestedDataStruct: [Object] } ]
}

I find this format not adapted for post processing (ex : how to count the nb of events?).
I think that the output format of getEvents (API) is better : array of Events.
Something like that :

events = [
{EventRegular : {
      simpleKeyVariable: 0n,
      simpleKeyStruct: [Object],
      simpleKeyArray: [Array],
      simpleDataVariable: 6n,
      simpleDataStruct: [Object],
      simpleDataArray: [Array]
    }},
{EventRegular : {
      simpleKeyVariable: 100n,
      simpleKeyStruct: [Object],
      simpleKeyArray: [Array],
      simpleDataVariable: 6n,
      simpleDataStruct: [Object],
      simpleDataArray: [Array]
    }},
{EventPanic: {errorType: 8n, errorDescription: 93566154138418073030976302n 
}},
{EventNested: { nestedKeyStruct: [Object], nestedDataStruct: [Object] }}
]

@tabaktoni
Copy link
Collaborator

tabaktoni commented Aug 8, 2023

I agree this format is inconvenient. It can be flattened before return if the refractor is complicated easily by:

Object.entries(events).map(i=>i[1].flatMap(t=>({[i[0]]:t}))).flat()

Even doe this can be used to flatter results now it is not trivial.

@edisontim
Copy link
Contributor Author

Ok, I thought the format was easier but the change is done :)

@github-actions
Copy link

🎉 This issue has been resolved in version 5.19.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

@tabaktoni
Copy link
Collaborator

Resolved in #712
v5.19.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
OnlyDust Open for OnlyDust contributors released on @next Type: feature New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants