Skip to content

Commit b01893c

Browse files
committed
refactor: implement reviewer requests
1 parent 49554a2 commit b01893c

File tree

2 files changed

+113
-62
lines changed

2 files changed

+113
-62
lines changed

src/types/lib/contract/abi.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,14 @@ export type AbiEnum = {
4747
};
4848

4949
// AbiEvents type is an arborescence :
50-
// - Nodes are hashes of Cairo 1 components names, or of Cairo 0 or 1 event names,
51-
// - With Cairo 1 abi, the nodes are linked in accordance with the components arborescence ; the tree can have several levels.
52-
// - With Cairo 0 abi : the tree has only one level (no component concept)
53-
// - leaves are the description of each event (not the same for Cairo 0 and Cairo 1)
54-
// - if the #[flat] flag is used in the Cairo 1 code to describe an event, or if the event is in the main code, the branch for this event has only one level.
50+
// - Nodes are hashes of either Cairo 1 components names, or of Cairo 0 or 1 event names,
51+
// - With Cairo 1 abi, the nodes are linked in accordance with the components arborescence ; the tree can have several levels of nodes.
52+
// - With Cairo 0 abi : the tree has only one level of nodes (no component concept)
53+
// - leaves are at the end of each branch ; they describes each event (not the same for Cairo 0 and Cairo 1)
54+
// - if the #[flat] flag is used in the Cairo 1 code to describe an event, or if the event is in the main code, the branch for this event has only one level of nodes (see example class 0x46ded64ae2dead6448e247234bab192a9c483644395b66f2155f2614e5804b0 in Sepolia)
5555
export type AbiEvents = { [hash: string]: AbiEvent };
5656

57-
// if Cairo 1 then definition of an event, or new level
57+
// if Cairo 1 then either definition of an event, or new level of nodes
5858
// if Cairo 0 then definition of an event
5959
export type AbiEvent = CairoEvent | LegacyEvent;
6060

src/utils/events/index.ts

Lines changed: 107 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// import { API } from '@starknet-io/types-js';
12
import { UDC } from '../../constants';
23
import {
34
Abi,
@@ -13,6 +14,7 @@ import {
1314
type CairoEventDefinition,
1415
type CairoEventVariant,
1516
type InvokeTransactionReceiptResponse,
17+
type AbiEntry,
1618
} from '../../types';
1719
import assert from '../assert';
1820
import { isCairo1Abi } from '../calldata/cairo';
@@ -22,11 +24,113 @@ import { addHexPrefix, utf8ToArray } from '../encode';
2224
import { cleanHex } from '../num';
2325

2426
/**
25-
* Retrieves the events from the given ABI.
27+
* Check if an ABI entry is related to events.
28+
* @param {AbiEntry} object an Abi entry
29+
* @returns {boolean} true if this Abi Entry is related to an event
30+
* @example
31+
* ```typescript
32+
* // use of a transaction receipt
33+
* ```
34+
*/
35+
export function isAbiEvent(object: AbiEntry): boolean {
36+
return object.type === 'event';
37+
}
38+
39+
/**
40+
* Retrieves the events from the given Cairo 0 ABI.
41+
* @param {Abi} abi - The Cairo 0 ABI to extract events from.
42+
* @return {AbiEvents} - An object containing the hashes and the definition of the events.
43+
* @example
44+
* ```typescript
45+
* const result = events.getCairo0AbiEvents(abi0);
46+
* // result = {
47+
'0x35ea10b06d74221d24a134672e9f776a3088ba6b9829e53b9a10abd8817a211': {
48+
data: [{ name: 'admin_requester', type: 'felt' }, { name: 'new_requester', type: 'felt' }],
49+
keys: [],
50+
name: 'AddAdmin',
51+
type: 'event'
52+
}
53+
* ```
54+
*/
55+
function getCairo0AbiEvents(abi: Abi) {
56+
return abi
57+
.filter((abiEntry) => abiEntry.type === 'event')
58+
.reduce((acc, abiEntry) => {
59+
const entryName = abiEntry.name;
60+
const abiEntryMod = { ...abiEntry };
61+
abiEntryMod.name = entryName;
62+
return {
63+
...acc,
64+
[addHexPrefix(starkCurve.keccak(utf8ToArray(entryName)).toString(16))]: abiEntryMod,
65+
};
66+
}, {});
67+
}
68+
69+
/**
70+
* Retrieves the events from the given Cairo 1 ABI.
71+
*
72+
* Is able to handle events nested in Cairo components.
73+
* @param {Abi} abi - The Cairo 1 ABI to extract events from.
74+
* @return {AbiEvents} - An object containing the hashes and the definition of the events.
75+
* @example
76+
* ```typescript
77+
* const result = events.getCairo1AbiEvents(abi1);
78+
* // result = {
79+
* // '0x22ea134d4126804c60797e633195f8c9aa5fd6d1567e299f4961d0e96f373ee':
80+
* // { '0x34e55c1cd55f1338241b50d352f0e91c7e4ffad0e4271d64eb347589ebdfd16': {
81+
* // kind: 'struct', type: 'event',
82+
* // name: 'ka::ExComponent::ex_logic_component::Mint',
83+
84+
* // members: [{
85+
* // name: 'spender',
86+
* // type: 'core::starknet::contract_address::ContractAddress',
87+
* // kind: 'key'},
88+
* // { name: 'value', type: 'core::integer::u256', kind: 'data' }]},
89+
* // ...
90+
* ```
91+
*/
92+
function getCairo1AbiEvents(abi: Abi) {
93+
const abiEventsStructs = abi.filter((obj) => isAbiEvent(obj) && obj.kind === 'struct');
94+
const abiEventsEnums = abi.filter((obj) => isAbiEvent(obj) && obj.kind === 'enum');
95+
const abiEventsData: AbiEvents = abiEventsStructs.reduce((acc: CairoEvent, event: CairoEvent) => {
96+
let nameList: string[] = [];
97+
let { name } = event;
98+
let flat: boolean = false;
99+
const findName = (variant: CairoEventVariant) => variant.type === name;
100+
// eslint-disable-next-line no-constant-condition
101+
while (true) {
102+
const eventEnum = abiEventsEnums.find((eventE) => eventE.variants.some(findName));
103+
if (typeof eventEnum === 'undefined') break;
104+
const variant: CairoEventVariant = eventEnum.variants.find(findName);
105+
nameList.unshift(variant.name);
106+
if (variant.kind === 'flat') flat = true;
107+
name = eventEnum.name;
108+
}
109+
if (nameList.length === 0) {
110+
throw new Error('inconsistency in ABI events definition.');
111+
}
112+
if (flat) nameList = [nameList[nameList.length - 1]];
113+
const final = nameList.pop();
114+
let result: AbiEvents = {
115+
[addHexPrefix(starkCurve.keccak(utf8ToArray(final!)).toString(16))]: event,
116+
};
117+
while (nameList.length > 0) {
118+
result = {
119+
[addHexPrefix(starkCurve.keccak(utf8ToArray(nameList.pop()!)).toString(16))]: result,
120+
};
121+
}
122+
result = { ...result };
123+
return mergeAbiEvents(acc, result);
124+
}, {});
125+
return abiEventsData;
126+
}
127+
128+
/**
129+
* Retrieves the events from the given ABI (from Cairo 0 or Cairo 1 contract).
26130
*
27131
* Is able to handle Cairo 1 events nested in Cairo components.
28132
* @param {Abi} abi - The ABI to extract events from.
29-
* @return {AbiEvents} - An object containing the extracted events.
133+
* @return {AbiEvents} - An object containing the hashes and the definition of the events.
30134
* @example
31135
* ```typescript
32136
* const result = events.getAbiEvents(abi);
@@ -45,60 +149,7 @@ import { cleanHex } from '../num';
45149
* ```
46150
*/
47151
export function getAbiEvents(abi: Abi): AbiEvents {
48-
let finalResult: AbiEvents;
49-
if (!isCairo1Abi(abi)) {
50-
// Cairo 0 abi
51-
finalResult = abi
52-
.filter((abiEntry) => abiEntry.type === 'event')
53-
.reduce((acc, abiEntry) => {
54-
const entryName = abiEntry.name;
55-
const abiEntryMod = { ...abiEntry };
56-
abiEntryMod.name = entryName;
57-
return {
58-
...acc,
59-
[addHexPrefix(starkCurve.keccak(utf8ToArray(entryName)).toString(16))]: abiEntryMod,
60-
};
61-
}, {});
62-
} else {
63-
// Cairo 1 abi
64-
const abiEventsStructs = abi.filter((obj) => obj.type === 'event' && obj.kind === 'struct');
65-
const abiEventsEnums = abi.filter((obj) => obj.type === 'event' && obj.kind === 'enum');
66-
const abiEventsData: AbiEvents = abiEventsStructs.reduce(
67-
(acc: CairoEvent, event: CairoEvent) => {
68-
let nameList: string[] = [];
69-
let { name } = event;
70-
let flat: boolean = false;
71-
const findName = (variant: CairoEventVariant) => variant.type === name;
72-
// eslint-disable-next-line no-constant-condition
73-
while (true) {
74-
const eventEnum = abiEventsEnums.find((eventE) => eventE.variants.some(findName));
75-
if (typeof eventEnum === 'undefined') break;
76-
const variant: CairoEventVariant = eventEnum.variants.find(findName);
77-
nameList.unshift(variant.name);
78-
if (variant.kind === 'flat') flat = true;
79-
name = eventEnum.name;
80-
}
81-
if (nameList.length === 0) {
82-
throw new Error('inconsistancy in ABI events definition.');
83-
}
84-
if (flat) nameList = [nameList[nameList.length - 1]];
85-
const final = nameList.pop();
86-
let result: AbiEvents = {
87-
[addHexPrefix(starkCurve.keccak(utf8ToArray(final!)).toString(16))]: event,
88-
};
89-
while (nameList.length > 0) {
90-
result = {
91-
[addHexPrefix(starkCurve.keccak(utf8ToArray(nameList.pop()!)).toString(16))]: result,
92-
};
93-
}
94-
result = { ...result };
95-
return mergeAbiEvents(acc, result);
96-
},
97-
{}
98-
);
99-
finalResult = abiEventsData;
100-
}
101-
return finalResult;
152+
return isCairo1Abi(abi) ? getCairo1AbiEvents(abi) : getCairo0AbiEvents(abi);
102153
}
103154

104155
/**

0 commit comments

Comments
 (0)