@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.
- package/lib/core/base-context.d.ts +2 -4
- package/lib/core/base-context.d.ts.map +1 -1
- package/lib/core/base-context.js +2 -6
- package/lib/core/base-context.js.map +1 -1
- package/lib/core/core-plugin.d.ts.map +1 -1
- package/lib/core/core-plugin.js +1 -6
- package/lib/core/core-plugin.js.map +1 -1
- package/lib/core/event-logger.d.ts +0 -5
- package/lib/core/event-logger.d.ts.map +1 -1
- package/lib/core/event-logger.js +16 -30
- package/lib/core/event-logger.js.map +1 -1
- package/lib/core/index.d.ts +1 -1
- package/lib/core/index.d.ts.map +1 -1
- package/lib/core/index.js +1 -1
- package/lib/core/index.js.map +1 -1
- package/lib/core/meter.d.ts +0 -43
- package/lib/core/meter.d.ts.map +1 -1
- package/lib/core/meter.js +18 -122
- package/lib/core/meter.js.map +1 -1
- package/lib/fuel/asset-processor.d.ts.map +1 -1
- package/lib/fuel/asset-processor.js +5 -1
- package/lib/fuel/asset-processor.js.map +1 -1
- package/lib/stark/codegen/codegen.d.ts +2 -0
- package/lib/stark/codegen/codegen.d.ts.map +1 -0
- package/lib/stark/codegen/codegen.js +110 -0
- package/lib/stark/codegen/codegen.js.map +1 -0
- package/lib/stark/codegen/index.d.ts +2 -0
- package/lib/stark/codegen/index.d.ts.map +1 -0
- package/lib/stark/codegen/index.js +2 -0
- package/lib/stark/codegen/index.js.map +1 -0
- package/lib/stark/codegen/run.d.ts +2 -0
- package/lib/stark/codegen/run.d.ts.map +1 -0
- package/lib/stark/codegen/run.js +11 -0
- package/lib/stark/codegen/run.js.map +1 -0
- package/lib/stark/codegen/utils.d.ts +2 -0
- package/lib/stark/codegen/utils.d.ts.map +1 -0
- package/lib/stark/codegen/utils.js +4 -0
- package/lib/stark/codegen/utils.js.map +1 -0
- package/lib/stark/context.d.ts +28 -0
- package/lib/stark/context.d.ts.map +1 -0
- package/lib/stark/context.js +59 -0
- package/lib/stark/context.js.map +1 -0
- package/lib/stark/contract.d.ts +12 -0
- package/lib/stark/contract.d.ts.map +1 -0
- package/lib/stark/contract.js +43 -0
- package/lib/stark/contract.js.map +1 -0
- package/lib/stark/event.d.ts +7 -0
- package/lib/stark/event.d.ts.map +1 -0
- package/lib/stark/event.js +11 -0
- package/lib/stark/event.js.map +1 -0
- package/lib/stark/index.d.ts +7 -0
- package/lib/stark/index.d.ts.map +1 -0
- package/lib/stark/index.js +7 -0
- package/lib/stark/index.js.map +1 -0
- package/lib/stark/starknet-plugin.d.ts +15 -0
- package/lib/stark/starknet-plugin.d.ts.map +1 -0
- package/lib/stark/starknet-plugin.js +87 -0
- package/lib/stark/starknet-plugin.js.map +1 -0
- package/lib/stark/starknet-processor.d.ts +35 -0
- package/lib/stark/starknet-processor.d.ts.map +1 -0
- package/lib/stark/starknet-processor.js +133 -0
- package/lib/stark/starknet-processor.js.map +1 -0
- package/lib/stark/types.d.ts +11 -0
- package/lib/stark/types.d.ts.map +1 -0
- package/lib/stark/types.js +2 -0
- package/lib/stark/types.js.map +1 -0
- package/lib/testing/starknet-facet.d.ts +9 -0
- package/lib/testing/starknet-facet.d.ts.map +1 -0
- package/lib/testing/starknet-facet.js +53 -0
- package/lib/testing/starknet-facet.js.map +1 -0
- package/lib/testing/test-processor-server.d.ts +2 -0
- package/lib/testing/test-processor-server.d.ts.map +1 -1
- package/lib/testing/test-processor-server.js +3 -0
- package/lib/testing/test-processor-server.js.map +1 -1
- package/lib/utils/price.js +1 -1
- package/package.json +9 -5
- package/src/core/base-context.ts +2 -6
- package/src/core/core-plugin.ts +1 -6
- package/src/core/event-logger.ts +18 -35
- package/src/core/index.ts +1 -12
- package/src/core/meter.ts +18 -148
- package/src/fuel/asset-processor.ts +5 -2
- package/src/stark/codegen/codegen.ts +125 -0
- package/src/stark/codegen/index.ts +1 -0
- package/src/stark/codegen/run.ts +10 -0
- package/src/stark/codegen/utils.ts +3 -0
- package/src/stark/context.ts +78 -0
- package/src/stark/contract.ts +55 -0
- package/src/stark/event.ts +7 -0
- package/src/stark/index.ts +9 -0
- package/src/stark/starknet-plugin.ts +116 -0
- package/src/stark/starknet-processor.ts +164 -0
- package/src/stark/types.ts +11 -0
- package/src/testing/starknet-facet.ts +62 -0
- package/src/testing/test-processor-server.ts +3 -0
- package/src/utils/price.ts +1 -1
- package/lib/core/base-context.test.d.ts +0 -2
- package/lib/core/base-context.test.d.ts.map +0 -1
- 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,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,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())
|