Skip to content

Instantly share code, notes, and snippets.

@0xtrou
Last active May 8, 2024 09:25
Show Gist options
  • Save 0xtrou/3b994c1b1c8b7baac499a53c57c0bfb8 to your computer and use it in GitHub Desktop.
Save 0xtrou/3b994c1b1c8b7baac499a53c57c0bfb8 to your computer and use it in GitHub Desktop.
Handle Events in Cosmos
const EVENT_LEVEL = {
TX_LEVEL: 'tx_level',
MSG_LEVEL: 'msg_level',
}
export class TxEventParserProvider {
constructor(
private _registry: any,
private tx: any
) {}
public aggregateEvents(): any[] {
const tx = this.tx;
if (!!tx.tx_response.code) { // this means tx has failed
return [];
}
const txEvents: any[] = [];
const messageActionEventIndexes: number[] = [];
const messageEvents = {}
const decodedEvents = tx.tx_response.events.map((event: any) => ({
type: event.type,
attributes: event.attributes.map((attribute: any, index: number) => ({
block_height: parseInt(tx.tx_response.height, 10),
index,
key: attribute?.key
? this._registry.decodeAttribute(attribute?.key)
: null,
value: attribute?.value
? this._registry.decodeAttribute(attribute?.value)
: null,
})),
// msg_index: event.msg_index || undefined, // map later
// level: EVENT_LEVEL.TX_LEVEL,
}));
// Now we aggregate
// If your goal is to just separate out tx-level events and events for individual msgs, I think you only need to look at the events field (and ignore log altogether):
// - events under events are sorted by order of occurrence
// - "type":"message" event is the leading indicator of the start of a msg
// so basically any event that comes before the first "type":"message" is a tx-level event
// then between the second "type":"message" and the third "type":"message" is event for the second msg, and so on
// just use type: message with "key": "action" in its attributes
// so tx-level events will appear before every message events
// given the events were sorted by order of occurrence, you can just iterate through the events array and separate them out
decodedEvents.forEach((event: any, index: number) => {
// mark the index of message events
if (event.type === 'message' && event.attributes.length === 1 && event.attributes[0].key === 'action') {
messageActionEventIndexes.push(index);
messageEvents[index] = {
...event,
msg_index: messageActionEventIndexes.length - 1, // get current index
level: EVENT_LEVEL.MSG_LEVEL,
};
txEvents.push(messageEvents[index]);
return;
}
// expect we already had message events
if (messageActionEventIndexes.length > 0) {
// if the event "message" without "action" attribute, then it is a message event, then we merge it with the previous message event
if (event.type === 'message' && event.attributes.find((attr: any) => attr.key === 'action') === undefined){
const messageIndex = messageActionEventIndexes.length - 1;
messageEvents[messageActionEventIndexes[messageIndex]].attributes.push(...event.attributes.map((attr: any, index: number) => {
return {
...attr,
// modify index of the attributes
index: messageEvents[messageActionEventIndexes[messageIndex]].attributes.length + index,
}
}));
return;
}
// if the event is not a message event, and its index between message events,
// then we set tx_msg_index to the previous message event index
// also set the source to MSG_EVENT
const messageIndex = messageActionEventIndexes.length - 1;
txEvents.push({
...event,
msg_index: messageIndex,
level: EVENT_LEVEL.MSG_LEVEL,
});
return;
}
// detect tx-level events, so tx-level events will appear before every message events
if (messageActionEventIndexes.length === 0 || index < messageActionEventIndexes[0]) {
txEvents.push({
...event,
msg_index: null,
level: EVENT_LEVEL.TX_LEVEL,
});
return;
}
});
return txEvents;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment