@apibara/starknet 2.1.0-beta.3 → 2.1.0-beta.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/common.ts CHANGED
@@ -1,40 +1,25 @@
1
- import { Schema } from "@effect/schema";
1
+ import type { Codec, CodecType } from "@apibara/protocol/codec";
2
+ import type * as proto from "./proto";
2
3
 
3
- const _FieldElement = Schema.TemplateLiteral(
4
- Schema.Literal("0x"),
5
- Schema.String,
6
- );
4
+ const MAX_U64 = 0xffffffffffffffffn;
7
5
 
8
- /** Wire representation of `FieldElement`. */
9
- export const FieldElementProto = Schema.Struct({
10
- x0: Schema.BigIntFromSelf,
11
- x1: Schema.BigIntFromSelf,
12
- x2: Schema.BigIntFromSelf,
13
- x3: Schema.BigIntFromSelf,
14
- });
15
-
16
- /** Field element. */
17
- export const FieldElement = Schema.transform(FieldElementProto, _FieldElement, {
18
- decode(value) {
19
- const x0 = value.x0.toString(16).padStart(16, "0");
20
- const x1 = value.x1.toString(16).padStart(16, "0");
21
- const x2 = value.x2.toString(16).padStart(16, "0");
22
- const x3 = value.x3.toString(16).padStart(16, "0");
23
- return `0x${x0}${x1}${x2}${x3}` as `0x${string}`;
24
- },
25
- encode(value) {
26
- const bn = BigInt(value);
27
- const hex = bn.toString(16).padStart(64, "0");
28
- const s = hex.length;
29
- const x3 = BigInt(`0x${hex.slice(s - 16, s)}`);
30
- const x2 = BigInt(`0x${hex.slice(s - 32, s - 16)}`);
31
- const x1 = BigInt(`0x${hex.slice(s - 48, s - 32)}`);
32
- const x0 = BigInt(`0x${hex.slice(s - 64, s - 48)}`);
6
+ export const FieldElement: Codec<`0x${string}`, proto.common.FieldElement> = {
7
+ encode(x) {
8
+ const bn = BigInt(x);
9
+ const x3 = bn & MAX_U64;
10
+ const x2 = (bn >> 64n) & MAX_U64;
11
+ const x1 = (bn >> 128n) & MAX_U64;
12
+ const x0 = (bn >> 192n) & MAX_U64;
33
13
  return { x0, x1, x2, x3 };
34
14
  },
35
- });
36
-
37
- export type FieldElement = Schema.Schema.Type<typeof FieldElement>;
15
+ decode(p) {
16
+ const x0 = p.x0 ?? 0n;
17
+ const x1 = p.x1 ?? 0n;
18
+ const x2 = p.x2 ?? 0n;
19
+ const x3 = p.x3 ?? 0n;
20
+ const bn = x3 + (x2 << 64n) + (x1 << 128n) + (x0 << 192n);
21
+ return `0x${bn.toString(16).padStart(64, "0")}` as `0x${string}`;
22
+ },
23
+ };
38
24
 
39
- export const feltToProto = Schema.encodeSync(FieldElement);
40
- export const feltFromProto = Schema.decodeSync(FieldElement);
25
+ export type FieldElement = CodecType<typeof FieldElement>;
package/src/event.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import type { Abi } from "abi-wan-kanabi";
2
2
  import type {
3
3
  AbiEventMember,
4
- EventToPrimitiveType,
5
4
  ExtractAbiEventNames,
6
5
  } from "abi-wan-kanabi/kanabi";
7
6
  import {
@@ -16,6 +15,16 @@ import {
16
15
  isPrimitiveType,
17
16
  isSpanType,
18
17
  } from "./abi";
18
+ import {
19
+ type AbiEvent,
20
+ type AbiEventEnum,
21
+ type AbiEventStruct,
22
+ type AbiMember,
23
+ type EventToPrimitiveType,
24
+ isEnumEventAbi,
25
+ isEventAbi,
26
+ isStructEventAbi,
27
+ } from "./abi-wan-helpers";
19
28
  import type { Event } from "./block";
20
29
  import {
21
30
  ParseError,
@@ -78,61 +87,184 @@ export function decodeEvent<
78
87
  (item) => item.name === eventName && item.type === "event",
79
88
  );
80
89
 
81
- if (!eventAbi || eventAbi.type !== "event") {
90
+ if (!eventAbi || !isEventAbi(eventAbi)) {
82
91
  if (strict) {
83
92
  throw new DecodeEventError(`Event ${eventName} not found in ABI`);
84
93
  }
85
-
86
94
  return null as DecodeEventReturn<TAbi, TEventName, TStrict>;
87
95
  }
88
96
 
89
- if (eventAbi.kind === "enum") {
90
- throw new DecodeEventError("enum: not implemented");
97
+ try {
98
+ if (isStructEventAbi(eventAbi)) {
99
+ return decodeStructEvent(abi, eventAbi, event, eventName);
100
+ }
101
+
102
+ if (isEnumEventAbi(eventAbi)) {
103
+ return decodeEnumEvent(abi, eventAbi, event, eventName);
104
+ }
105
+
106
+ throw new DecodeEventError(
107
+ `Unsupported event kind: ${(eventAbi as AbiEvent)?.kind}`,
108
+ );
109
+ } catch (error) {
110
+ if (
111
+ (error instanceof DecodeEventError || error instanceof ParseError) &&
112
+ !strict
113
+ ) {
114
+ return null as DecodeEventReturn<TAbi, TEventName, TStrict>;
115
+ }
116
+
117
+ throw error;
91
118
  }
119
+ }
92
120
 
121
+ function decodeStructEvent<
122
+ TAbi extends Abi = Abi,
123
+ TEventName extends ExtractAbiEventNames<TAbi> = ExtractAbiEventNames<TAbi>,
124
+ >(
125
+ abi: TAbi,
126
+ eventAbi: AbiEventStruct,
127
+ event: Event,
128
+ eventName: TEventName,
129
+ ): DecodedEvent<TAbi, TEventName> {
93
130
  const selector = BigInt(getEventSelector(eventName));
94
131
  if ((event.keys && selector !== BigInt(event.keys[0])) || !event.keys) {
95
- if (strict) {
96
- throw new DecodeEventError(
97
- `Selector mismatch. Expected ${selector}, got ${event.keys?.[0]}`,
98
- );
99
- }
100
-
101
- return null as DecodeEventReturn<TAbi, TEventName, TStrict>;
132
+ throw new DecodeEventError(
133
+ `Selector mismatch. Expected ${selector}, got ${event.keys?.[0]}`,
134
+ );
102
135
  }
103
136
 
104
137
  const keysAbi = eventAbi.members.filter((m) => m.kind === "key");
105
138
  const dataAbi = eventAbi.members.filter((m) => m.kind === "data");
106
139
 
107
- try {
108
- const keysParser = compileEventMembers(abi, keysAbi);
109
- const dataParser = compileEventMembers(abi, dataAbi);
110
-
111
- const keysWithoutSelector = event.keys?.slice(1) ?? [];
112
- const { out: decodedKeys } = keysParser(keysWithoutSelector, 0);
113
- const { out: decodedData } = dataParser(event.data ?? [], 0);
114
-
115
- const decoded = {
116
- ...decodedKeys,
117
- ...decodedData,
118
- } as EventToPrimitiveType<TAbi, TEventName>;
119
-
120
- return {
121
- ...event,
122
- eventName,
123
- args: decoded,
124
- } as DecodedEvent<TAbi, TEventName>;
125
- } catch (error) {
126
- if (error instanceof DecodeEventError && !strict) {
127
- return null as DecodeEventReturn<TAbi, TEventName, TStrict>;
128
- }
140
+ const keysParser = compileEventMembers(abi, keysAbi);
141
+ const dataParser = compileEventMembers(abi, dataAbi);
129
142
 
130
- if (error instanceof ParseError && !strict) {
131
- return null as DecodeEventReturn<TAbi, TEventName, TStrict>;
143
+ const keysWithoutSelector = event.keys?.slice(1) ?? [];
144
+
145
+ const { out: decodedKeys } = keysParser(keysWithoutSelector, 0);
146
+ const { out: decodedData } = dataParser(event.data ?? [], 0);
147
+
148
+ const decoded = {
149
+ ...decodedKeys,
150
+ ...decodedData,
151
+ } as EventToPrimitiveType<TAbi, TEventName>;
152
+
153
+ return {
154
+ ...event,
155
+ eventName,
156
+ args: decoded,
157
+ } as DecodedEvent<TAbi, TEventName>;
158
+ }
159
+
160
+ function decodeEnumEvent<
161
+ TAbi extends Abi = Abi,
162
+ TEventName extends ExtractAbiEventNames<TAbi> = ExtractAbiEventNames<TAbi>,
163
+ >(
164
+ abi: TAbi,
165
+ eventAbi: AbiEventEnum,
166
+ event: Event,
167
+ eventName: TEventName,
168
+ ): DecodedEvent<TAbi, TEventName> {
169
+ if (!event.keys || event.keys.length === 0) {
170
+ throw new DecodeEventError(
171
+ "Event has no keys; cannot determine variant selector",
172
+ );
173
+ }
174
+
175
+ const variants = eventAbi.variants;
176
+
177
+ const variantSelector = event.keys[0];
178
+
179
+ // Create a map of all possible selectors to their variant paths
180
+ const selectorToVariant = buildVariantSelectorMap(abi, variants);
181
+
182
+ // Find the matching variant and path
183
+ const matchingVariant = selectorToVariant[variantSelector];
184
+
185
+ if (!matchingVariant) {
186
+ throw new DecodeEventError(
187
+ `No matching variant found for selector: ${variantSelector}`,
188
+ );
189
+ }
190
+
191
+ const structEventAbi = abi.find(
192
+ (item) =>
193
+ item.name === matchingVariant.variant.type && item.type === "event",
194
+ );
195
+
196
+ if (!structEventAbi || !isStructEventAbi(structEventAbi)) {
197
+ throw new DecodeEventError(
198
+ `Nested event type not found or not a struct: ${matchingVariant.variant.type}`,
199
+ );
200
+ }
201
+
202
+ const decodedStruct = decodeStructEvent(
203
+ abi,
204
+ structEventAbi,
205
+ event,
206
+ matchingVariant.variant.name,
207
+ );
208
+
209
+ return {
210
+ ...event,
211
+ eventName,
212
+ args: {
213
+ _tag: matchingVariant.variant.name,
214
+ [matchingVariant.variant.name]: decodedStruct.args,
215
+ },
216
+ } as DecodedEvent<TAbi, TEventName>;
217
+ }
218
+
219
+ type EnumFlatVariantMap = Record<
220
+ string,
221
+ { variant: AbiEventMember; path: string[] }
222
+ >;
223
+
224
+ // Helper to build a map of all possible selectors to their variant paths
225
+ function buildVariantSelectorMap(
226
+ abi: Abi,
227
+ variants: AbiEventMember[],
228
+ ): EnumFlatVariantMap {
229
+ const selectorMap: EnumFlatVariantMap = {};
230
+
231
+ for (const variant of variants) {
232
+ // For nested events, just map the variant's own selector
233
+ if (variant.kind === "nested") {
234
+ const selector = getEventSelector(variant.name);
235
+ selectorMap[selector] = { variant, path: [variant.name] };
132
236
  }
237
+ // For flat events, recursively map all possible selectors from the event hierarchy
238
+ else if (variant.kind === "flat") {
239
+ const flatEventName = variant.type;
240
+ const flatEventAbi = abi.find(
241
+ (item) => item.name === flatEventName && item.type === "event",
242
+ );
133
243
 
134
- throw error;
244
+ // Skip if the flat event type is not found
245
+ if (!flatEventAbi) {
246
+ continue;
247
+ }
248
+
249
+ if (isEnumEventAbi(flatEventAbi)) {
250
+ // For enum events, recursively map all their variants
251
+ const nestedMap = buildVariantSelectorMap(abi, flatEventAbi.variants);
252
+
253
+ // Add this variant to the path for all nested selectors
254
+ for (const [
255
+ nestedSelector,
256
+ { variant: nestedVariant, path: nestedPath },
257
+ ] of Object.entries(nestedMap)) {
258
+ selectorMap[nestedSelector] = {
259
+ variant: nestedVariant,
260
+ path: [variant.name, ...nestedPath],
261
+ };
262
+ }
263
+ }
264
+ }
135
265
  }
266
+
267
+ return selectorMap;
136
268
  }
137
269
 
138
270
  function compileEventMembers<T extends Record<string, unknown>>(
@@ -176,18 +308,16 @@ function compileTypeParser(abi: Abi, type: string): Parser<unknown> {
176
308
  case "struct": {
177
309
  return compileStructParser(abi, typeAbi.members);
178
310
  }
179
- case "enum":
180
- throw new DecodeEventError("enum: not implemented");
311
+ case "enum": {
312
+ // This should never happen anyways as compileTypeParser is only called
313
+ // primitive types or to compile structs parsers.
314
+ throw new DecodeEventError(`Enum types are not supported: ${type}`);
315
+ }
181
316
  default:
182
317
  throw new DecodeEventError(`Invalid type ${typeAbi.type}`);
183
318
  }
184
319
  }
185
320
 
186
- type AbiMember = {
187
- name: string;
188
- type: string;
189
- };
190
-
191
321
  function compileStructParser(
192
322
  abi: Abi,
193
323
  members: readonly AbiMember[],