@sentio/sdk 3.0.0-rc-next.1 → 3.0.0-rc-next.3

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.
Files changed (99) hide show
  1. package/lib/core/base-context.d.ts +2 -4
  2. package/lib/core/base-context.d.ts.map +1 -1
  3. package/lib/core/base-context.js +2 -6
  4. package/lib/core/base-context.js.map +1 -1
  5. package/lib/core/core-plugin.d.ts.map +1 -1
  6. package/lib/core/core-plugin.js +1 -6
  7. package/lib/core/core-plugin.js.map +1 -1
  8. package/lib/core/event-logger.d.ts +0 -5
  9. package/lib/core/event-logger.d.ts.map +1 -1
  10. package/lib/core/event-logger.js +16 -30
  11. package/lib/core/event-logger.js.map +1 -1
  12. package/lib/core/index.d.ts +1 -1
  13. package/lib/core/index.d.ts.map +1 -1
  14. package/lib/core/index.js +1 -1
  15. package/lib/core/index.js.map +1 -1
  16. package/lib/core/meter.d.ts +0 -43
  17. package/lib/core/meter.d.ts.map +1 -1
  18. package/lib/core/meter.js +18 -122
  19. package/lib/core/meter.js.map +1 -1
  20. package/lib/fuel/asset-processor.d.ts.map +1 -1
  21. package/lib/fuel/asset-processor.js +5 -1
  22. package/lib/fuel/asset-processor.js.map +1 -1
  23. package/lib/stark/codegen/codegen.d.ts +2 -0
  24. package/lib/stark/codegen/codegen.d.ts.map +1 -0
  25. package/lib/stark/codegen/codegen.js +110 -0
  26. package/lib/stark/codegen/codegen.js.map +1 -0
  27. package/lib/stark/codegen/index.d.ts +2 -0
  28. package/lib/stark/codegen/index.d.ts.map +1 -0
  29. package/lib/stark/codegen/index.js +2 -0
  30. package/lib/stark/codegen/index.js.map +1 -0
  31. package/lib/stark/codegen/run.d.ts +2 -0
  32. package/lib/stark/codegen/run.d.ts.map +1 -0
  33. package/lib/stark/codegen/run.js +11 -0
  34. package/lib/stark/codegen/run.js.map +1 -0
  35. package/lib/stark/codegen/utils.d.ts +2 -0
  36. package/lib/stark/codegen/utils.d.ts.map +1 -0
  37. package/lib/stark/codegen/utils.js +4 -0
  38. package/lib/stark/codegen/utils.js.map +1 -0
  39. package/lib/stark/context.d.ts +28 -0
  40. package/lib/stark/context.d.ts.map +1 -0
  41. package/lib/stark/context.js +59 -0
  42. package/lib/stark/context.js.map +1 -0
  43. package/lib/stark/contract.d.ts +12 -0
  44. package/lib/stark/contract.d.ts.map +1 -0
  45. package/lib/stark/contract.js +43 -0
  46. package/lib/stark/contract.js.map +1 -0
  47. package/lib/stark/event.d.ts +7 -0
  48. package/lib/stark/event.d.ts.map +1 -0
  49. package/lib/stark/event.js +11 -0
  50. package/lib/stark/event.js.map +1 -0
  51. package/lib/stark/index.d.ts +7 -0
  52. package/lib/stark/index.d.ts.map +1 -0
  53. package/lib/stark/index.js +7 -0
  54. package/lib/stark/index.js.map +1 -0
  55. package/lib/stark/starknet-plugin.d.ts +15 -0
  56. package/lib/stark/starknet-plugin.d.ts.map +1 -0
  57. package/lib/stark/starknet-plugin.js +87 -0
  58. package/lib/stark/starknet-plugin.js.map +1 -0
  59. package/lib/stark/starknet-processor.d.ts +35 -0
  60. package/lib/stark/starknet-processor.d.ts.map +1 -0
  61. package/lib/stark/starknet-processor.js +133 -0
  62. package/lib/stark/starknet-processor.js.map +1 -0
  63. package/lib/stark/types.d.ts +11 -0
  64. package/lib/stark/types.d.ts.map +1 -0
  65. package/lib/stark/types.js +2 -0
  66. package/lib/stark/types.js.map +1 -0
  67. package/lib/testing/starknet-facet.d.ts +9 -0
  68. package/lib/testing/starknet-facet.d.ts.map +1 -0
  69. package/lib/testing/starknet-facet.js +53 -0
  70. package/lib/testing/starknet-facet.js.map +1 -0
  71. package/lib/testing/test-processor-server.d.ts +2 -0
  72. package/lib/testing/test-processor-server.d.ts.map +1 -1
  73. package/lib/testing/test-processor-server.js +3 -0
  74. package/lib/testing/test-processor-server.js.map +1 -1
  75. package/lib/utils/price.js +1 -1
  76. package/package.json +9 -5
  77. package/src/core/base-context.ts +2 -6
  78. package/src/core/core-plugin.ts +1 -6
  79. package/src/core/event-logger.ts +18 -35
  80. package/src/core/index.ts +1 -12
  81. package/src/core/meter.ts +18 -148
  82. package/src/fuel/asset-processor.ts +5 -2
  83. package/src/stark/codegen/codegen.ts +125 -0
  84. package/src/stark/codegen/index.ts +1 -0
  85. package/src/stark/codegen/run.ts +10 -0
  86. package/src/stark/codegen/utils.ts +3 -0
  87. package/src/stark/context.ts +78 -0
  88. package/src/stark/contract.ts +55 -0
  89. package/src/stark/event.ts +7 -0
  90. package/src/stark/index.ts +9 -0
  91. package/src/stark/starknet-plugin.ts +116 -0
  92. package/src/stark/starknet-processor.ts +164 -0
  93. package/src/stark/types.ts +11 -0
  94. package/src/testing/starknet-facet.ts +62 -0
  95. package/src/testing/test-processor-server.ts +3 -0
  96. package/src/utils/price.ts +1 -1
  97. package/lib/core/base-context.test.d.ts +0 -2
  98. package/lib/core/base-context.test.d.ts.map +0 -1
  99. package/lib/core/base-context.test.js.map +0 -1
package/src/core/meter.ts CHANGED
@@ -74,28 +74,6 @@ export class MetricState extends MapStateStorage<Metric> {
74
74
  }
75
75
  }
76
76
 
77
- export class MetricStateNew extends MapStateStorage<Metric> {
78
- static INSTANCE = new MetricStateNew()
79
-
80
- getOrRegisterMetric(type: MetricType, name: string, option?: CounterOptions | MetricOptions): Metric {
81
- const metricMap = this.getOrRegister()
82
- let metric = metricMap.get(name)
83
- if (metric && metric.config.type !== type) {
84
- throw Error(`redefine ${name} of metric type ${type} that is previously ${metric.config.type}`)
85
- }
86
-
87
- if (!metric) {
88
- if (type === MetricType.COUNTER) {
89
- metric = CounterNew._create(name, option)
90
- } else {
91
- metric = GaugeNew._create(name, option)
92
- }
93
- }
94
- metricMap.set(name, metric)
95
- return metric
96
- }
97
- }
98
-
99
77
  export class Counter extends Metric {
100
78
  static register(name: string, option?: CounterOptions): Counter {
101
79
  return MetricState.INSTANCE.getOrRegisterMetric(MetricType.COUNTER, name, option) as Counter
@@ -132,6 +110,7 @@ export class Counter extends Metric {
132
110
  private record(ctx: BaseContext, value: Numberish, labels: Labels, add: boolean) {
133
111
  processMetrics.process_metricrecord_count.add(1)
134
112
  ctx.update({
113
+ // legacy support, deprecating
135
114
  counters: [
136
115
  {
137
116
  metadata: ctx.getMetaData(this.name, labels),
@@ -139,6 +118,14 @@ export class Counter extends Metric {
139
118
  add: add,
140
119
  runtimeInfo: undefined
141
120
  }
121
+ ],
122
+ timeseriesResult: [
123
+ {
124
+ metadata: ctx.getMetaData(this.name, labels),
125
+ type: TimeseriesResult_TimeseriesType.COUNTER,
126
+ data: toTimeSeriesData(value, labels, !add),
127
+ runtimeInfo: undefined
128
+ }
142
129
  ]
143
130
  })
144
131
  }
@@ -181,12 +168,21 @@ export class Gauge extends Metric {
181
168
  record(ctx: BaseContext, value: Numberish, labels: Labels = {}) {
182
169
  processMetrics.process_metricrecord_count.add(1)
183
170
  ctx.update({
171
+ // legacy support, deprecating
184
172
  gauges: [
185
173
  {
186
174
  metadata: ctx.getMetaData(this.config.name, labels),
187
175
  metricValue: toMetricValue(value),
188
176
  runtimeInfo: undefined
189
177
  }
178
+ ],
179
+ timeseriesResult: [
180
+ {
181
+ metadata: ctx.getMetaData(this.name, labels),
182
+ type: TimeseriesResult_TimeseriesType.GAUGE,
183
+ data: toTimeSeriesData(value, labels, false),
184
+ runtimeInfo: undefined
185
+ }
190
186
  ]
191
187
  })
192
188
  }
@@ -221,129 +217,3 @@ export class Meter {
221
217
  return new GaugeBinding(name, this.ctx)
222
218
  }
223
219
  }
224
-
225
- export class MeterNew {
226
- private readonly ctx: BaseContext
227
-
228
- constructor(ctx: BaseContext) {
229
- this.ctx = ctx
230
- }
231
-
232
- Counter(name: string) {
233
- return new CounterNewBinding(name, this.ctx)
234
- }
235
-
236
- Gauge(name: string) {
237
- return new GaugeNewBinding(name, this.ctx)
238
- }
239
- }
240
-
241
- export class CounterNew extends Counter {
242
- static register(name: string, option?: CounterOptions): CounterNew {
243
- return MetricStateNew.INSTANCE.getOrRegisterMetric(MetricType.COUNTER, name, option) as CounterNew
244
- }
245
-
246
- /**
247
- * internal use only, to create a metric use {@link register} instead
248
- */
249
- static _create(name: string, option?: CounterOptions): CounterNew {
250
- return new CounterNew(name, option)
251
- }
252
-
253
- private constructor(name: string, option?: CounterOptions) {
254
- super(
255
- name,
256
- MetricConfig.fromPartial({
257
- ...option,
258
- aggregationConfig: {
259
- intervalInMinutes: option?.resolutionConfig ? [option?.resolutionConfig?.intervalInMinutes] : []
260
- }
261
- })
262
- )
263
- }
264
-
265
- add(ctx: BaseContext, value: Numberish, labels: Labels = {}) {
266
- this.recordNew(ctx, value, labels, true)
267
- }
268
-
269
- sub(ctx: BaseContext, value: Numberish, labels: Labels = {}) {
270
- this.recordNew(ctx, value, labels, false)
271
- }
272
-
273
- private recordNew(ctx: BaseContext, value: Numberish, labels: Labels, add: boolean) {
274
- processMetrics.process_metricrecord_count.add(1)
275
- ctx.update({
276
- timeseriesResult: [
277
- {
278
- metadata: ctx.getMetaData(this.name, labels),
279
- type: TimeseriesResult_TimeseriesType.COUNTER,
280
- data: toTimeSeriesData(value, labels, !add),
281
- runtimeInfo: undefined
282
- }
283
- ]
284
- })
285
- }
286
- }
287
-
288
- export class GaugeNewBinding {
289
- private readonly gauge: GaugeNew
290
- private readonly ctx: BaseContext
291
-
292
- constructor(name: string, ctx: BaseContext) {
293
- this.gauge = GaugeNew._create(name)
294
- this.ctx = ctx
295
- }
296
-
297
- record(value: Numberish, labels: Labels = {}) {
298
- this.gauge.record(this.ctx, value, labels)
299
- }
300
- }
301
-
302
- export class CounterNewBinding {
303
- private readonly counter: CounterNew
304
- private readonly ctx: BaseContext
305
-
306
- constructor(name: string, ctx: BaseContext) {
307
- this.counter = CounterNew._create(name)
308
- this.ctx = ctx
309
- }
310
-
311
- add(value: Numberish, labels: Labels = {}) {
312
- this.counter.add(this.ctx, value, labels)
313
- }
314
-
315
- sub(value: Numberish, labels: Labels = {}) {
316
- this.counter.sub(this.ctx, value, labels)
317
- }
318
- }
319
-
320
- export class GaugeNew extends Gauge {
321
- static register(name: string, option?: MetricOptions): Gauge {
322
- return MetricStateNew.INSTANCE.getOrRegisterMetric(MetricType.GAUGE, name, option) as Gauge
323
- }
324
-
325
- /**
326
- * internal use only, to create a metric use {@link register} instead
327
- */
328
- static _create(name: string, option?: MetricOptions): GaugeNew {
329
- return new GaugeNew(name, option)
330
- }
331
-
332
- private constructor(name: string, option?: MetricOptions) {
333
- super(name, MetricConfig.fromPartial({ ...option }))
334
- }
335
-
336
- record(ctx: BaseContext, value: Numberish, labels: Labels = {}) {
337
- processMetrics.process_metricrecord_count.add(1)
338
- ctx.update({
339
- timeseriesResult: [
340
- {
341
- metadata: ctx.getMetaData(this.name, labels),
342
- type: TimeseriesResult_TimeseriesType.GAUGE,
343
- data: toTimeSeriesData(value, labels, false),
344
- runtimeInfo: undefined
345
- }
346
- ]
347
- })
348
- }
349
- }
@@ -61,6 +61,7 @@ export class FuelAssetProcessor implements FuelBaseProcessor<FuelAssetProcessorC
61
61
  from: [],
62
62
  to: []
63
63
  }
64
+ let assetId = ''
64
65
  for (const input of tx.transaction.inputs || []) {
65
66
  if (input.type == InputType.Coin) {
66
67
  transfer.from.push({
@@ -68,6 +69,7 @@ export class FuelAssetProcessor implements FuelBaseProcessor<FuelAssetProcessorC
68
69
  assetId: input.assetId,
69
70
  amount: BigInt(input.amount.toString(10))
70
71
  })
72
+ assetId = input.assetId
71
73
  }
72
74
  }
73
75
 
@@ -82,11 +84,12 @@ export class FuelAssetProcessor implements FuelBaseProcessor<FuelAssetProcessorC
82
84
  amount: BigInt(value),
83
85
  assetId: output.assetId
84
86
  })
87
+ if (assetId == '') {
88
+ assetId = output.assetId
89
+ }
85
90
  }
86
91
  }
87
92
 
88
- const assetId = transfer.from[0].assetId || ''
89
-
90
93
  const ctx = new FuelContext(
91
94
  this.config.chainId,
92
95
  assetId,
@@ -0,0 +1,125 @@
1
+ import fs, { readFileSync, writeFileSync } from 'fs'
2
+ import chalk from 'chalk'
3
+ import path from 'path'
4
+ import { mkdirpSync } from 'mkdirp'
5
+ import { events } from 'starknet'
6
+ import { StarknetChainId } from '@sentio/chain'
7
+ import { Abi } from '@sentio/abi-wan-kanabi'
8
+ import { recursiveCodegen } from '../../core/codegen.js'
9
+
10
+ export async function codegen(abisDir: string, outDir: string) {
11
+ if (!fs.existsSync(abisDir)) {
12
+ return
13
+ }
14
+
15
+ const numFiles = await recursiveCodegen(abisDir, outDir, codegenInternal)
16
+ console.log(chalk.green(`Generated ${numFiles} files for Starknet`))
17
+ }
18
+
19
+ async function codegenInternal(abisDir: string, outDir: string): Promise<number> {
20
+ const allFiles = fs.readdirSync(abisDir, { recursive: true }) as string[]
21
+
22
+ const abis: Record<string, any> = {}
23
+ let fileCount = 0
24
+
25
+ function guessNameFromAbi(abi: any, address: string) {
26
+ if (Array.isArray(abi)) {
27
+ const arr = abi as any[]
28
+ for (const a of arr) {
29
+ if (a.type == 'impl') {
30
+ return a.name.replace('Impl', '')
31
+ }
32
+ }
33
+ }
34
+ return 'Contract' + address.replace('0x', '').slice(0, 6)
35
+ }
36
+
37
+ for (const f of allFiles) {
38
+ if (f.toLowerCase().endsWith('.json')) {
39
+ let name = f.replace('.json', '')
40
+ const content = readFileSync(path.join(abisDir, f))
41
+ const abi = JSON.parse(content.toString())
42
+ let chain = StarknetChainId.STARKNET_MAINNET
43
+ if (name.startsWith('sepolia/')) {
44
+ chain = StarknetChainId.STARKNET_SEPOLIA
45
+ name = name.slice('sepolia/'.length)
46
+ }
47
+ const parts = name.split('-')
48
+ const address = parts.pop() as string
49
+ if (parts.length > 0) {
50
+ name = parts.join('')
51
+ } else {
52
+ name = guessNameFromAbi(abi, address)
53
+ }
54
+ abis[name] = {
55
+ name,
56
+ address,
57
+ chain,
58
+ abi
59
+ }
60
+ }
61
+ }
62
+
63
+ const tABIContents: string[] = []
64
+
65
+ for (const [name, abi] of Object.entries(abis)) {
66
+ tABIContents.push(`export const ABI_${name} = ${JSON.stringify(abi.abi, null, 2)} as const;`)
67
+ }
68
+
69
+ mkdirpSync(outDir)
70
+ writeFileSync(path.join(outDir, 'tabi.ts'), tABIContents.join('\n'))
71
+ fileCount++
72
+ for (const { name, address, chain, abi: jsonAbi } of Object.values(abis)) {
73
+ const content: string[] = []
74
+ content.push(
75
+ `import { StarknetProcessorConfig, StarknetEvent, AbstractStarknetProcessor, StarknetContext } from '@sentio/sdk/starknet'`
76
+ )
77
+ content.push(`import { EventToPrimitiveType, TypedContractView, Abi } from "@sentio/abi-wan-kanabi"`)
78
+ content.push(`import { ABI_${name} } from "./tabi.js"\n`)
79
+ content.push(`export type ${name} = TypedContractView<typeof ABI_${name}>`)
80
+ const abi = jsonAbi as Abi
81
+ const abiEventsEnums = abi.filter((obj) => obj.type == 'event' && obj.kind === 'enum')
82
+ const eventMap: Record<string, string> = {}
83
+ for (const ev of Object.values(events.getAbiEvents(abi))) {
84
+ const fullName = ev.name as string
85
+ let eventName = fullName
86
+ for (const e of abiEventsEnums) {
87
+ for (const v of e.variants) {
88
+ if (v.type === fullName) {
89
+ eventName = v.name
90
+ break
91
+ }
92
+ }
93
+ }
94
+
95
+ eventMap[eventName] = fullName
96
+ content.push(`export type ${eventName} = EventToPrimitiveType<typeof ABI_${name}, "${fullName}">`)
97
+ }
98
+
99
+ content.push(`\nexport class ${name}Processor extends AbstractStarknetProcessor {
100
+ constructor(abi: Abi, config: Partial<StarknetProcessorConfig>) {
101
+ super(abi, {
102
+ name: "${name}",
103
+ address: "${address}",
104
+ chainId: "${chain}",
105
+ abi,
106
+ ...config
107
+ })
108
+ }`)
109
+ content.push(`\tstatic bind(config: Partial<StarknetProcessorConfig>) {
110
+ return new ${name}Processor(ABI_${name}, config)
111
+ }`)
112
+
113
+ for (const [eventName, structName] of Object.entries(eventMap)) {
114
+ content.push(`\ton${eventName}(handler: (event: StarknetEvent<${eventName}>, ctx: StarknetContext<${name}>) => Promise<void>) {
115
+ return this.onEvent<${eventName}, ${name}>("${eventName}", "${structName}", handler)
116
+ }`)
117
+ }
118
+
119
+ content.push(`}`)
120
+ writeFileSync(path.join(outDir, `${name}-processor.ts`), content.join('\n'))
121
+ fileCount++
122
+ }
123
+
124
+ return fileCount
125
+ }
@@ -0,0 +1 @@
1
+ export * from './codegen.js'
@@ -0,0 +1,10 @@
1
+ import { codegen } from './index.js'
2
+
3
+ if (process.argv.length > 3) {
4
+ const abisDir = process.argv[2]
5
+ const targetDir = process.argv[3]
6
+ await codegen(abisDir, targetDir)
7
+ } else {
8
+ console.error('Not enough argument')
9
+ process.exit(1)
10
+ }
@@ -0,0 +1,3 @@
1
+ export function upperFirst(str: string): string {
2
+ return str.charAt(0).toUpperCase() + str.slice(1)
3
+ }
@@ -0,0 +1,78 @@
1
+ import { ChainId } from '@sentio/chain'
2
+ import { RecordMetaData } from '@sentio/protos'
3
+ import { BaseContext, Labels, normalizeLabels } from '../core/index.js'
4
+ import { Provider, RpcProvider } from 'starknet'
5
+ import { StarknetProcessorConfig } from './types.js'
6
+ import { Abi } from '@sentio/abi-wan-kanabi'
7
+ import { StarknetContractView } from './contract.js'
8
+
9
+ class AbstractContext extends BaseContext {
10
+ constructor(
11
+ readonly provider: Provider,
12
+ readonly contractAddress: string,
13
+ readonly chainId: ChainId | string,
14
+ readonly blockNumber: number,
15
+ readonly blockHash: string,
16
+ readonly transactionHash: string,
17
+ readonly logIndex: number = -1,
18
+ readonly contractName: string = '',
19
+ readonly abi?: Abi
20
+ ) {
21
+ super({})
22
+ }
23
+
24
+ protected getMetaDataInternal(name: string, labels: Labels): RecordMetaData {
25
+ return {
26
+ address: this.contractAddress,
27
+ contractName: '',
28
+ blockNumber: BigInt(this.blockNumber),
29
+ transactionIndex: 0,
30
+ transactionHash: this.transactionHash,
31
+ chainId: this.getChainId(),
32
+ name: name,
33
+ logIndex: this.logIndex,
34
+ labels: normalizeLabels(labels)
35
+ }
36
+ }
37
+
38
+ getChainId(): ChainId {
39
+ return this.chainId as ChainId
40
+ }
41
+ }
42
+
43
+ export class StarknetContext<CT> extends AbstractContext {
44
+ private _contract: any
45
+
46
+ constructor(
47
+ config: StarknetProcessorConfig,
48
+ provider: RpcProvider,
49
+ blockNumber: number,
50
+ blockHash: string,
51
+ transaction_hash: string,
52
+ logIndex: number,
53
+ readonly classHash: string
54
+ ) {
55
+ super(
56
+ provider,
57
+ config.address,
58
+ config.chainId,
59
+ blockNumber,
60
+ blockHash,
61
+ transaction_hash,
62
+ logIndex,
63
+ config.name ?? classHash.slice(0, 8),
64
+ config.abi
65
+ )
66
+ }
67
+
68
+ getContract(): CT {
69
+ if (!this.abi) {
70
+ throw new Error('abi not found')
71
+ }
72
+
73
+ if (!this._contract) {
74
+ this._contract = new StarknetContractView(this.abi, this.contractAddress, this.provider, this.blockNumber)
75
+ }
76
+ return this._contract as CT
77
+ }
78
+ }
@@ -0,0 +1,55 @@
1
+ import {
2
+ ArgsOrCalldata,
3
+ ArgsOrCalldataWithOptions,
4
+ AsyncContractFunction,
5
+ CallOptions,
6
+ Contract,
7
+ Result,
8
+ RpcProvider,
9
+ CallData,
10
+ splitArgsAndOptions
11
+ } from 'starknet'
12
+ import { Abi } from '@sentio/abi-wan-kanabi'
13
+
14
+ export class StarknetContractView {
15
+ private _contract: Contract
16
+
17
+ constructor(
18
+ readonly abi: Abi,
19
+ readonly address: string,
20
+ readonly provider: RpcProvider,
21
+ readonly blockNumber: number
22
+ ) {
23
+ this._contract = new Contract(abi, address, provider)
24
+ const callData = new CallData(abi)
25
+
26
+ for (const fn of callData.abi) {
27
+ if (fn.type == 'function' && fn.state_mutability == 'view') {
28
+ const signature = fn.name
29
+ Object.defineProperty(this, signature, {
30
+ enumerable: true,
31
+ writable: false,
32
+ value: buildCall(this, signature)
33
+ })
34
+ }
35
+ }
36
+ }
37
+
38
+ call(method: string, args?: ArgsOrCalldata, callOptions?: CallOptions): Promise<Result> {
39
+ return this._contract.call(method, args, {
40
+ ...callOptions,
41
+ blockIdentifier: this.blockNumber
42
+ })
43
+ }
44
+ }
45
+
46
+ function buildCall(contract: StarknetContractView, name: string): AsyncContractFunction {
47
+ return async function (...args: ArgsOrCalldataWithOptions): Promise<any> {
48
+ const params = splitArgsAndOptions(args)
49
+ return contract.call(name, params.args, {
50
+ parseRequest: true,
51
+ parseResponse: true,
52
+ ...params.options
53
+ })
54
+ }
55
+ }
@@ -0,0 +1,7 @@
1
+ export class StarknetEvent<T> {
2
+ constructor(
3
+ readonly caller: string,
4
+ readonly transactionHash: string,
5
+ readonly data: T
6
+ ) {}
7
+ }
@@ -0,0 +1,9 @@
1
+ export { StarknetPlugin } from './starknet-plugin.js'
2
+
3
+ export * from './starknet-processor.js'
4
+
5
+ export { StarknetChainId } from '@sentio/chain'
6
+
7
+ export * from './context.js'
8
+ export * from './event.js'
9
+ export * from './types.js'
@@ -0,0 +1,116 @@
1
+ import { errorString, GLOBAL_CONFIG, mergeProcessResults, Plugin, PluginManager, USER_PROCESSOR } from '@sentio/runtime'
2
+ import {
3
+ ContractConfig,
4
+ DataBinding,
5
+ HandlerType,
6
+ InitResponse,
7
+ ProcessConfigResponse,
8
+ ProcessResult,
9
+ StartRequest
10
+ } from '@sentio/protos'
11
+
12
+ import { ServerError, Status } from 'nice-grpc'
13
+ import { TemplateInstanceState } from '../core/template.js'
14
+ import { HandlerRegister } from '../core/handler-register.js'
15
+ import { StarknetProcessorState } from './starknet-processor.js'
16
+ import { hash } from 'starknet'
17
+
18
+ export class StarknetPlugin extends Plugin {
19
+ name: string = 'StarknetPlugin'
20
+ handlerRegister = new HandlerRegister()
21
+
22
+ async init(config: InitResponse) {
23
+ for (const solanaProcessor of StarknetProcessorState.INSTANCE.getValues()) {
24
+ const chainId = solanaProcessor.config.chainId
25
+ config.chainIds.push(chainId)
26
+ }
27
+ }
28
+
29
+ async configure(config: ProcessConfigResponse, forChainId?: string) {
30
+ this.handlerRegister.clear(forChainId as any)
31
+
32
+ for (const processor of StarknetProcessorState.INSTANCE.getValues()) {
33
+ const chainId = processor.config.chainId
34
+ if (forChainId !== undefined && forChainId !== chainId.toString()) {
35
+ continue
36
+ }
37
+ await processor.configure()
38
+ const contractConfig = ContractConfig.fromPartial({
39
+ processorType: USER_PROCESSOR,
40
+ contract: {
41
+ name: processor.config.name,
42
+ chainId: processor.config.chainId.toString(),
43
+ address: processor.config.address || '*',
44
+ abi: ''
45
+ },
46
+ startBlock: processor.config.startBlock,
47
+ endBlock: processor.config.endBlock
48
+ })
49
+ for (const callHandler of processor.callHandlers) {
50
+ const handlerId = this.handlerRegister.register(callHandler.handler, chainId)
51
+
52
+ if (callHandler.eventFilter) {
53
+ contractConfig.starknetEventConfigs.push({
54
+ filters: callHandler.eventFilter.map((e) => ({
55
+ address: processor.config.address,
56
+ keys: [hash.getSelectorFromName(e)]
57
+ })),
58
+ handlerId,
59
+ handlerName: callHandler.handlerName
60
+ })
61
+ }
62
+ }
63
+
64
+ // Finish up a contract
65
+ config.contractConfigs.push(contractConfig)
66
+ }
67
+ }
68
+
69
+ supportedHandlers = [HandlerType.STARKNET_EVENT]
70
+
71
+ processBinding(request: DataBinding): Promise<ProcessResult> {
72
+ switch (request.handlerType) {
73
+ case HandlerType.STARKNET_EVENT:
74
+ return this.processEvent(request)
75
+ default:
76
+ throw new ServerError(Status.INVALID_ARGUMENT, 'No handle type registered ' + request.handlerType)
77
+ }
78
+ }
79
+
80
+ async start(request: StartRequest) {}
81
+
82
+ stateDiff(config: ProcessConfigResponse): boolean {
83
+ return TemplateInstanceState.INSTANCE.getValues().length !== config.templateInstances.length
84
+ }
85
+
86
+ async processEvent(binding: DataBinding): Promise<ProcessResult> {
87
+ if (!binding.data?.starknetEvents?.result) {
88
+ throw new ServerError(Status.INVALID_ARGUMENT, "starknetEvents can't be null")
89
+ }
90
+
91
+ const promises: Promise<ProcessResult>[] = []
92
+
93
+ const result = binding.data?.starknetEvents?.result
94
+
95
+ for (const handlerId of binding.handlerIds) {
96
+ const promise = this.handlerRegister
97
+ .getHandlerById(
98
+ binding.chainId,
99
+ handlerId
100
+ )(binding.data?.starknetEvents)
101
+ .catch((e: any) => {
102
+ throw new ServerError(
103
+ Status.INTERNAL,
104
+ 'error processing transaction: ' + JSON.stringify(result) + '\n' + errorString(e)
105
+ )
106
+ })
107
+ if (GLOBAL_CONFIG.execution.sequential) {
108
+ await promise
109
+ }
110
+ promises.push(promise)
111
+ }
112
+ return mergeProcessResults(await Promise.all(promises))
113
+ }
114
+ }
115
+
116
+ PluginManager.INSTANCE.register(new StarknetPlugin())