@sentio/sdk 1.36.3 → 1.36.4

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 (42) hide show
  1. package/LICENSE +55 -0
  2. package/lib/aptos/aptos-plugin.d.ts +14 -0
  3. package/lib/aptos/aptos-plugin.js +190 -0
  4. package/lib/aptos/aptos-plugin.js.map +1 -0
  5. package/lib/aptos/index.d.ts +1 -0
  6. package/lib/aptos/index.js +3 -1
  7. package/lib/aptos/index.js.map +1 -1
  8. package/lib/core/eth-plugin.d.ts +14 -0
  9. package/lib/core/eth-plugin.js +221 -0
  10. package/lib/core/eth-plugin.js.map +1 -0
  11. package/lib/core/index.d.ts +3 -0
  12. package/lib/core/index.js +7 -1
  13. package/lib/core/index.js.map +1 -1
  14. package/lib/core/solana-plugin.d.ts +9 -0
  15. package/lib/core/solana-plugin.js +79 -0
  16. package/lib/core/solana-plugin.js.map +1 -0
  17. package/lib/core/sui-plugin.d.ts +8 -0
  18. package/lib/core/sui-plugin.js +46 -0
  19. package/lib/core/sui-plugin.js.map +1 -0
  20. package/lib/gen/index.d.ts +2 -1
  21. package/lib/gen/index.js +2 -1
  22. package/lib/gen/index.js.map +1 -1
  23. package/lib/plugin.d.ts +15 -0
  24. package/lib/plugin.js +32 -0
  25. package/lib/plugin.js.map +1 -0
  26. package/lib/processor-runner.js +0 -0
  27. package/lib/service.d.ts +7 -19
  28. package/lib/service.js +36 -486
  29. package/lib/service.js.map +1 -1
  30. package/package.json +6 -12
  31. package/src/aptos/aptos-plugin.ts +217 -0
  32. package/src/aptos/index.ts +2 -0
  33. package/src/core/eth-plugin.ts +255 -0
  34. package/src/core/index.ts +4 -0
  35. package/src/core/solana-plugin.ts +97 -0
  36. package/src/core/sui-plugin.ts +54 -0
  37. package/src/gen/index.ts +3 -1
  38. package/src/plugin.ts +41 -0
  39. package/src/service.ts +32 -563
  40. package/src/target-ethers-sentio/tsconfig.json +1 -1
  41. package/src/types/global.d.ts +15 -0
  42. package/lib/release.config.js +0 -39
@@ -0,0 +1,255 @@
1
+ import { Plugin, PluginManager } from '../plugin'
2
+ import {
3
+ AccountConfig,
4
+ ContractConfig,
5
+ DataBinding,
6
+ HandlerType,
7
+ LogFilter,
8
+ LogHandlerConfig,
9
+ ProcessConfigResponse,
10
+ ProcessResult,
11
+ } from '../gen/processor/protos/processor'
12
+ import { DEFAULT_MAX_BLOCK, errorString, mergeProcessResults, USER_PROCESSOR, Utf8ArrayToStr } from '../service'
13
+
14
+ import { ServerError, Status } from 'nice-grpc'
15
+ import { Block, Log } from '@ethersproject/abstract-provider'
16
+ import { Trace } from '@sentio/sdk'
17
+ import { ProcessorState } from '../binds'
18
+ import { AccountProcessorState } from './account-processor'
19
+ import Long from 'long'
20
+
21
+ export class EthPlugin implements Plugin {
22
+ name: string = 'EthPlugin'
23
+
24
+ private eventHandlers: ((event: Log) => Promise<ProcessResult>)[] = []
25
+ private traceHandlers: ((trace: Trace) => Promise<ProcessResult>)[] = []
26
+ private blockHandlers: ((block: Block) => Promise<ProcessResult>)[] = []
27
+
28
+ configure(config: ProcessConfigResponse): void {
29
+ for (const processor of ProcessorState.INSTANCE.getValues()) {
30
+ // If server favor incremental update this need to change
31
+ // Start basic config for contract
32
+ const chainId = processor.getChainId()
33
+ // this.processorsByChainId.set(chainId, processor)
34
+
35
+ const contractConfig: ContractConfig = {
36
+ processorType: USER_PROCESSOR,
37
+ contract: {
38
+ name: processor.config.name,
39
+ chainId: chainId.toString(),
40
+ address: processor.config.address,
41
+ abi: '',
42
+ },
43
+ intervalConfigs: [],
44
+ logConfigs: [],
45
+ traceConfigs: [],
46
+ startBlock: processor.config.startBlock,
47
+ endBlock: DEFAULT_MAX_BLOCK,
48
+ instructionConfig: undefined,
49
+ aptosEventConfigs: [],
50
+ aptosCallConfigs: [],
51
+ }
52
+ if (processor.config.endBlock) {
53
+ contractConfig.endBlock = processor.config.endBlock
54
+ }
55
+
56
+ // Step 1. Prepare all the block handlers
57
+ for (const blockHandler of processor.blockHandlers) {
58
+ const handlerId = this.blockHandlers.push(blockHandler.handler) - 1
59
+ // TODO wrap the block handler into one
60
+
61
+ contractConfig.intervalConfigs.push({
62
+ slot: 0,
63
+ slotInterval: blockHandler.blockInterval,
64
+ minutes: 0,
65
+ minutesInterval: blockHandler.timeIntervalInMinutes,
66
+ handlerId: handlerId,
67
+ })
68
+ }
69
+
70
+ // Step 2. Prepare all trace handlers
71
+ for (const traceHandler of processor.traceHandlers) {
72
+ const handlerId = this.traceHandlers.push(traceHandler.handler) - 1
73
+ contractConfig.traceConfigs.push({
74
+ signature: traceHandler.signature,
75
+ handlerId: handlerId,
76
+ })
77
+ }
78
+
79
+ // Step 3. Prepare all the event handlers
80
+ for (const eventsHandler of processor.eventHandlers) {
81
+ // associate id with filter
82
+ const handlerId = this.eventHandlers.push(eventsHandler.handler) - 1
83
+ const logConfig: LogHandlerConfig = {
84
+ handlerId: handlerId,
85
+ filters: [],
86
+ }
87
+
88
+ for (const filter of eventsHandler.filters) {
89
+ if (!filter.topics) {
90
+ throw new ServerError(Status.INVALID_ARGUMENT, 'Topic should not be null')
91
+ }
92
+ const logFilter: LogFilter = {
93
+ addressType: undefined,
94
+ address: contractConfig.contract?.address,
95
+ topics: [],
96
+ }
97
+
98
+ for (const ts of filter.topics) {
99
+ let hashes: string[] = []
100
+ if (Array.isArray(ts)) {
101
+ hashes = hashes.concat(ts)
102
+ } else if (ts) {
103
+ hashes.push(ts)
104
+ }
105
+ logFilter.topics.push({ hashes: hashes })
106
+ }
107
+ logConfig.filters.push(logFilter)
108
+ }
109
+ contractConfig.logConfigs.push(logConfig)
110
+ }
111
+
112
+ // Finish up a contract
113
+ config.contractConfigs.push(contractConfig)
114
+ }
115
+
116
+ // part 1.b prepare EVM account processors
117
+ for (const processor of AccountProcessorState.INSTANCE.getValues()) {
118
+ const accountConfig: AccountConfig = {
119
+ address: processor.config.address,
120
+ chainId: processor.getChainId().toString(),
121
+ startBlock: processor.config.startBlock ? Long.fromValue(processor.config.startBlock) : Long.ZERO,
122
+ aptosIntervalConfigs: [],
123
+ intervalConfigs: [],
124
+ logConfigs: [],
125
+ }
126
+ // TODO add interval
127
+ for (const eventsHandler of processor.eventHandlers) {
128
+ // associate id with filter
129
+ const handlerId = this.eventHandlers.push(eventsHandler.handler) - 1
130
+ const logConfig: LogHandlerConfig = {
131
+ handlerId: handlerId,
132
+ filters: [],
133
+ }
134
+
135
+ for (const filter of eventsHandler.filters) {
136
+ if (!filter.topics) {
137
+ throw new ServerError(Status.INVALID_ARGUMENT, 'Topic should not be null')
138
+ }
139
+ const logFilter: LogFilter = {
140
+ addressType: filter.addressType,
141
+ address: filter.address,
142
+ topics: [],
143
+ }
144
+
145
+ for (const ts of filter.topics) {
146
+ let hashes: string[] = []
147
+ if (Array.isArray(ts)) {
148
+ hashes = hashes.concat(ts)
149
+ } else if (ts) {
150
+ hashes.push(ts)
151
+ }
152
+ logFilter.topics.push({ hashes: hashes })
153
+ }
154
+ logConfig.filters.push(logFilter)
155
+ }
156
+ accountConfig.logConfigs.push(logConfig)
157
+ }
158
+
159
+ config.accountConfigs.push(accountConfig)
160
+ }
161
+ }
162
+
163
+ supportedHandlers = [HandlerType.ETH_LOG, HandlerType.ETH_BLOCK, HandlerType.ETH_TRACE]
164
+
165
+ processBinding(request: DataBinding): Promise<ProcessResult> {
166
+ // return Promise.resolve(undefined);
167
+ switch (request.handlerType) {
168
+ case HandlerType.ETH_LOG:
169
+ return this.processLog(request)
170
+ case HandlerType.ETH_TRACE:
171
+ return this.processTrace(request)
172
+ case HandlerType.ETH_BLOCK:
173
+ return this.processBlock(request)
174
+ default:
175
+ throw new ServerError(Status.INVALID_ARGUMENT, 'No handle type registered ' + request.handlerType)
176
+ }
177
+ }
178
+
179
+ async processLog(request: DataBinding): Promise<ProcessResult> {
180
+ if (!request.data) {
181
+ throw new ServerError(Status.INVALID_ARGUMENT, "Log can't be null")
182
+ }
183
+
184
+ const promises: Promise<ProcessResult>[] = []
185
+ let log: Log
186
+ if (request.data.ethLog) {
187
+ log = request.data.ethLog.log as Log
188
+ } else {
189
+ const jsonString = Utf8ArrayToStr(request.data.raw)
190
+ log = JSON.parse(jsonString)
191
+ }
192
+
193
+ for (const handlerId of request.handlerIds) {
194
+ const handler = this.eventHandlers[handlerId]
195
+ promises.push(
196
+ handler(log).catch((e) => {
197
+ throw new ServerError(Status.INTERNAL, 'error processing log: ' + JSON.stringify(log) + '\n' + errorString(e))
198
+ })
199
+ )
200
+ }
201
+ return mergeProcessResults(await Promise.all(promises))
202
+ }
203
+
204
+ async processTrace(binding: DataBinding): Promise<ProcessResult> {
205
+ if (!binding.data) {
206
+ throw new ServerError(Status.INVALID_ARGUMENT, "Trace can't be empty")
207
+ }
208
+ let trace: Trace
209
+ if (binding.data.ethTrace?.trace) {
210
+ trace = binding.data.ethTrace.trace as Trace
211
+ } else {
212
+ const jsonString = Utf8ArrayToStr(binding.data.raw)
213
+ trace = JSON.parse(jsonString)
214
+ }
215
+
216
+ const promises: Promise<ProcessResult>[] = []
217
+
218
+ for (const handlerId of binding.handlerIds) {
219
+ promises.push(
220
+ this.traceHandlers[handlerId](trace).catch((e) => {
221
+ throw new ServerError(
222
+ Status.INTERNAL,
223
+ 'error processing trace: ' + JSON.stringify(trace) + '\n' + errorString(e)
224
+ )
225
+ })
226
+ )
227
+ }
228
+ return mergeProcessResults(await Promise.all(promises))
229
+ }
230
+
231
+ async processBlock(binding: DataBinding): Promise<ProcessResult> {
232
+ if (!binding.data) {
233
+ throw new ServerError(Status.INVALID_ARGUMENT, "Block can't be empty")
234
+ }
235
+ let block: Block
236
+ if (binding.data.ethBlock?.block) {
237
+ block = binding.data.ethBlock.block as Block
238
+ } else {
239
+ const jsonString = Utf8ArrayToStr(binding.data.raw)
240
+ block = JSON.parse(jsonString)
241
+ }
242
+
243
+ const promises: Promise<ProcessResult>[] = []
244
+ for (const handlerId of binding.handlerIds) {
245
+ promises.push(
246
+ this.blockHandlers[handlerId](block).catch((e) => {
247
+ throw new ServerError(Status.INTERNAL, 'error processing block: ' + block.number + '\n' + errorString(e))
248
+ })
249
+ )
250
+ }
251
+ return mergeProcessResults(await Promise.all(promises))
252
+ }
253
+ }
254
+
255
+ PluginManager.INSTANCE.register(new EthPlugin())
package/src/core/index.ts CHANGED
@@ -16,3 +16,7 @@ export { SolanaBindOptions } from './solana-options'
16
16
  export { SolanaBaseProcessor } from './solana-processor'
17
17
 
18
18
  export type { TypedCallTrace, Trace } from './trace'
19
+
20
+ export { EthPlugin } from './eth-plugin'
21
+ export { SolanaPlugin } from './solana-plugin'
22
+ export { SuiPlugin } from './sui-plugin'
@@ -0,0 +1,97 @@
1
+ import { Plugin, PluginManager } from '../plugin'
2
+ import {
3
+ ContractConfig,
4
+ Data_SolInstruction,
5
+ DataBinding,
6
+ HandlerType,
7
+ ProcessConfigResponse,
8
+ ProcessResult,
9
+ } from '../gen/processor/protos/processor'
10
+ import { DEFAULT_MAX_BLOCK, errorString, mergeProcessResults, USER_PROCESSOR, Utf8ArrayToStr } from '../service'
11
+
12
+ import { ServerError, Status } from 'nice-grpc'
13
+
14
+ import { SolanaProcessorState } from './solana-processor'
15
+ import { Instruction as SolInstruction } from '@project-serum/anchor/dist/cjs/coder/borsh/instruction'
16
+
17
+ export class SolanaPlugin implements Plugin {
18
+ name: string = 'SolanaPlugin'
19
+
20
+ configure(config: ProcessConfigResponse): void {
21
+ // Part 2, prepare solana constractors
22
+ for (const solanaProcessor of SolanaProcessorState.INSTANCE.getValues()) {
23
+ const contractConfig: ContractConfig = {
24
+ processorType: USER_PROCESSOR,
25
+ contract: {
26
+ name: solanaProcessor.contractName,
27
+ chainId: solanaProcessor.network,
28
+ address: solanaProcessor.address,
29
+ abi: '',
30
+ },
31
+ logConfigs: [],
32
+ traceConfigs: [],
33
+ intervalConfigs: [],
34
+ startBlock: solanaProcessor.config.startSlot,
35
+ endBlock: DEFAULT_MAX_BLOCK,
36
+ instructionConfig: {
37
+ innerInstruction: solanaProcessor.processInnerInstruction,
38
+ parsedInstruction: solanaProcessor.fromParsedInstruction !== null,
39
+ rawDataInstruction: solanaProcessor.decodeInstruction !== null,
40
+ },
41
+ aptosEventConfigs: [],
42
+ aptosCallConfigs: [],
43
+ }
44
+ config.contractConfigs.push(contractConfig)
45
+ }
46
+ }
47
+
48
+ supportedHandlers = [HandlerType.SOL_INSTRUCTION]
49
+
50
+ processBinding(request: DataBinding): Promise<ProcessResult> {
51
+ switch (request.handlerType) {
52
+ case HandlerType.SOL_INSTRUCTION:
53
+ return this.processSolInstruction(request)
54
+ default:
55
+ throw new ServerError(Status.INVALID_ARGUMENT, 'No handle type registered ' + request.handlerType)
56
+ }
57
+ }
58
+
59
+ async processSolInstruction(request: DataBinding): Promise<ProcessResult> {
60
+ if (!request.data) {
61
+ throw new ServerError(Status.INVALID_ARGUMENT, 'instruction data cannot be empty')
62
+ }
63
+
64
+ const instruction = request.data.solInstruction || Data_SolInstruction.decode(request.data.raw) // JSON.parse(jsonString)
65
+ const promises: Promise<ProcessResult>[] = []
66
+
67
+ // Only have instruction handlers for solana processors
68
+ for (const processor of SolanaProcessorState.INSTANCE.getValues()) {
69
+ if (processor.address === instruction.programAccountId) {
70
+ let parsedInstruction: SolInstruction | null = null
71
+ if (instruction.parsed) {
72
+ parsedInstruction = processor.getParsedInstruction(instruction.parsed as { type: string; info: any })
73
+ } else if (instruction.instructionData) {
74
+ parsedInstruction = processor.getParsedInstruction(instruction.instructionData)
75
+ }
76
+ if (parsedInstruction == null) {
77
+ continue
78
+ }
79
+ const insHandler = processor.getInstructionHandler(parsedInstruction)
80
+ if (insHandler == null) {
81
+ continue
82
+ }
83
+ const res = await processor.handleInstruction(
84
+ parsedInstruction,
85
+ instruction.accounts,
86
+ insHandler,
87
+ instruction.slot
88
+ )
89
+
90
+ promises.push(Promise.resolve(res))
91
+ }
92
+ }
93
+ return mergeProcessResults(await Promise.all(promises))
94
+ }
95
+ }
96
+
97
+ PluginManager.INSTANCE.register(new SolanaPlugin())
@@ -0,0 +1,54 @@
1
+ import { Plugin, PluginManager } from '../plugin'
2
+ import {
3
+ ContractConfig,
4
+ DataBinding,
5
+ HandlerType,
6
+ ProcessConfigResponse,
7
+ ProcessResult,
8
+ } from '../gen/processor/protos/processor'
9
+ import { DEFAULT_MAX_BLOCK, USER_PROCESSOR } from '../service'
10
+
11
+ import { ServerError, Status } from 'nice-grpc'
12
+
13
+ import { CHAIN_IDS } from '../utils/chain'
14
+ import { SuiProcessorState } from './sui-processor'
15
+
16
+ export class SuiPlugin implements Plugin {
17
+ name: string = 'SolanaPlugin'
18
+
19
+ configure(config: ProcessConfigResponse): void {
20
+ for (const suiProcessor of SuiProcessorState.INSTANCE.getValues()) {
21
+ const contractConfig: ContractConfig = {
22
+ processorType: USER_PROCESSOR,
23
+ contract: {
24
+ name: 'sui contract',
25
+ chainId: CHAIN_IDS.SUI_DEVNET,
26
+ address: suiProcessor.address,
27
+ abi: '',
28
+ },
29
+ logConfigs: [],
30
+ intervalConfigs: [],
31
+ traceConfigs: [],
32
+ startBlock: suiProcessor.config.startSeqNumber,
33
+ endBlock: DEFAULT_MAX_BLOCK,
34
+ instructionConfig: undefined,
35
+ aptosEventConfigs: [],
36
+ aptosCallConfigs: [],
37
+ }
38
+ config.contractConfigs.push(contractConfig)
39
+ }
40
+ }
41
+
42
+ supportedHandlers = [HandlerType.SUI_TRANSACTION]
43
+
44
+ processBinding(request: DataBinding): Promise<ProcessResult> {
45
+ switch (request.handlerType) {
46
+ case HandlerType.SUI_TRANSACTION:
47
+ // return this.processSolInstruction(request)
48
+ default:
49
+ throw new ServerError(Status.INVALID_ARGUMENT, 'No handle type registered ' + request.handlerType)
50
+ }
51
+ }
52
+ }
53
+
54
+ PluginManager.INSTANCE.register(new SuiPlugin())
package/src/gen/index.ts CHANGED
@@ -1 +1,3 @@
1
- export * from '../gen/processor/protos/processor'
1
+ export * from './builtin'
2
+
3
+ export * from './processor/protos/processor'
package/src/plugin.ts ADDED
@@ -0,0 +1,41 @@
1
+ import { DataBinding, HandlerType, ProcessConfigResponse, ProcessResult } from './gen'
2
+
3
+ export interface Plugin {
4
+ name: string
5
+ supportedHandlers: HandlerType[]
6
+
7
+ configure(config: ProcessConfigResponse): void
8
+ processBinding(request: DataBinding): Promise<ProcessResult>
9
+ }
10
+
11
+ export class PluginManager {
12
+ static INSTANCE = new PluginManager()
13
+
14
+ plugins: Plugin[] = []
15
+ typesToPlugin = new Map<HandlerType, Plugin>()
16
+
17
+ register(plugin: Plugin) {
18
+ this.plugins.push(plugin)
19
+ // for (const plugin of this.plugins) {
20
+ for (const handlerType of plugin.supportedHandlers) {
21
+ const exsited = this.typesToPlugin.get(handlerType)
22
+ if (exsited) {
23
+ throw new Error(`Duplicate plugin for ${handlerType}: ${exsited.name} and ${plugin.name}`)
24
+ }
25
+ this.typesToPlugin.set(handlerType, plugin)
26
+ }
27
+ // }
28
+ }
29
+
30
+ configure(config: ProcessConfigResponse) {
31
+ this.plugins.forEach((plugin) => plugin.configure(config))
32
+ }
33
+
34
+ processBinding(request: DataBinding): Promise<ProcessResult> {
35
+ const plugin = this.typesToPlugin.get(request.handlerType)
36
+ if (!plugin) {
37
+ throw new Error(`No plugin for ${request.handlerType}`)
38
+ }
39
+ return plugin.processBinding(request)
40
+ }
41
+ }