@sentio/sdk 1.11.0 → 1.12.0

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 (45) hide show
  1. package/lib/bind-options.d.ts +2 -0
  2. package/lib/bind-options.js +4 -1
  3. package/lib/bind-options.js.map +1 -1
  4. package/lib/cli/cli.js +1 -1
  5. package/lib/cli/cli.js.map +1 -1
  6. package/lib/cli/commands/run-create.js +4 -2
  7. package/lib/cli/commands/run-create.js.map +1 -1
  8. package/lib/cli/commands/run-login.js +2 -2
  9. package/lib/cli/commands/run-login.js.map +1 -1
  10. package/lib/context.d.ts +2 -0
  11. package/lib/context.js +4 -1
  12. package/lib/context.js.map +1 -1
  13. package/lib/gen/processor/protos/processor.d.ts +1 -1
  14. package/lib/gen/processor/protos/processor.js +15 -15
  15. package/lib/gen/processor/protos/processor.js.map +1 -1
  16. package/lib/index.d.ts +2 -1
  17. package/lib/index.js +4 -1
  18. package/lib/index.js.map +1 -1
  19. package/lib/processor-state.d.ts +2 -0
  20. package/lib/processor-state.js +1 -0
  21. package/lib/processor-state.js.map +1 -1
  22. package/lib/service.js +48 -1
  23. package/lib/service.js.map +1 -1
  24. package/lib/sui-processor.d.ts +21 -0
  25. package/lib/sui-processor.js +65 -0
  26. package/lib/sui-processor.js.map +1 -0
  27. package/lib/test/sui.test.d.ts +1 -0
  28. package/lib/test/sui.test.js +162 -0
  29. package/lib/test/sui.test.js.map +1 -0
  30. package/lib/test/tic-tac-toe.d.ts +1 -0
  31. package/lib/test/tic-tac-toe.js +31 -0
  32. package/lib/test/tic-tac-toe.js.map +1 -0
  33. package/package.json +1 -1
  34. package/src/bind-options.ts +2 -0
  35. package/src/cli/cli.ts +1 -1
  36. package/src/cli/commands/run-create.ts +4 -2
  37. package/src/cli/commands/run-login.ts +2 -2
  38. package/src/context.ts +2 -0
  39. package/src/gen/processor/protos/processor.ts +19 -19
  40. package/src/index.ts +2 -1
  41. package/src/processor-state.ts +3 -0
  42. package/src/service.ts +53 -1
  43. package/src/sui-processor.ts +75 -0
  44. package/src/test/sui.test.ts +167 -0
  45. package/src/test/tic-tac-toe.ts +31 -0
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sentio/sdk",
3
3
  "license": "Apache-2.0",
4
- "version": "1.11.0",
4
+ "version": "1.12.0",
5
5
  "scripts": {
6
6
  "compile_target": "yarn tsc -b src/target-ethers-sentio/tsconfig.json",
7
7
  "compile": "tsc -p . && cp src/cli/webpack.config.js lib/cli",
@@ -39,3 +39,5 @@ export class SolanaBindOptions extends BindOptions {
39
39
  declare network?: string
40
40
  processInnerInstruction?: boolean
41
41
  }
42
+
43
+ export class SuiBindOptions extends BindOptions {}
package/src/cli/cli.ts CHANGED
@@ -112,7 +112,7 @@ if (mainOptions.command === 'login') {
112
112
  const usage = commandLineUsage([
113
113
  {
114
114
  header: 'Sentio upload',
115
- content: 'Upload your project files to Sentio.',
115
+ content: 'sentio upload',
116
116
  },
117
117
  {
118
118
  header: 'Options',
@@ -16,6 +16,7 @@ export function runCreate(argv: string[]) {
16
16
  {
17
17
  name: 'name',
18
18
  alias: 'n',
19
+ defaultOption: true,
19
20
  type: String,
20
21
  description: '(Optional) Project name, If not provided they "Default" name will be used',
21
22
  },
@@ -25,8 +26,8 @@ export function runCreate(argv: string[]) {
25
26
  if (options.help) {
26
27
  const usage = commandLineUsage([
27
28
  {
28
- header: 'Sentio Create',
29
- content: 'Create a template project',
29
+ header: 'Create a template project',
30
+ content: 'sentio create [$name]',
30
31
  },
31
32
  {
32
33
  header: 'Options',
@@ -77,5 +78,6 @@ export function runCreate(argv: string[]) {
77
78
 
78
79
  fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson))
79
80
  }
81
+ console.log(chalk.green("successfully create project '" + projectName + "'"))
80
82
  }
81
83
  }
@@ -30,8 +30,8 @@ export function runLogin(argv: string[]) {
30
30
  if (options.help || !options['api-key']) {
31
31
  const usage = commandLineUsage([
32
32
  {
33
- header: 'Sentio Login',
34
- content: 'Try login to Sentio with your apikey.',
33
+ header: 'Login to Sentio',
34
+ content: 'sentio login --api-key=$key',
35
35
  },
36
36
  {
37
37
  header: 'Options',
package/src/context.ts CHANGED
@@ -101,3 +101,5 @@ export class SolanaContext extends BaseContext {
101
101
  this.address = address
102
102
  }
103
103
  }
104
+
105
+ export class SuiContext extends SolanaContext {}
@@ -194,7 +194,7 @@ export interface ProcessTracesResponse {
194
194
  }
195
195
 
196
196
  export interface ProcessTransactionsRequest {
197
- transaction: RawTransaction | undefined;
197
+ transactions: RawTransaction[];
198
198
  }
199
199
 
200
200
  export interface ProcessInstructionsRequest {
@@ -1620,7 +1620,7 @@ export const ProcessTracesResponse = {
1620
1620
  };
1621
1621
 
1622
1622
  function createBaseProcessTransactionsRequest(): ProcessTransactionsRequest {
1623
- return { transaction: undefined };
1623
+ return { transactions: [] };
1624
1624
  }
1625
1625
 
1626
1626
  export const ProcessTransactionsRequest = {
@@ -1628,11 +1628,8 @@ export const ProcessTransactionsRequest = {
1628
1628
  message: ProcessTransactionsRequest,
1629
1629
  writer: _m0.Writer = _m0.Writer.create()
1630
1630
  ): _m0.Writer {
1631
- if (message.transaction !== undefined) {
1632
- RawTransaction.encode(
1633
- message.transaction,
1634
- writer.uint32(10).fork()
1635
- ).ldelim();
1631
+ for (const v of message.transactions) {
1632
+ RawTransaction.encode(v!, writer.uint32(10).fork()).ldelim();
1636
1633
  }
1637
1634
  return writer;
1638
1635
  },
@@ -1648,7 +1645,9 @@ export const ProcessTransactionsRequest = {
1648
1645
  const tag = reader.uint32();
1649
1646
  switch (tag >>> 3) {
1650
1647
  case 1:
1651
- message.transaction = RawTransaction.decode(reader, reader.uint32());
1648
+ message.transactions.push(
1649
+ RawTransaction.decode(reader, reader.uint32())
1650
+ );
1652
1651
  break;
1653
1652
  default:
1654
1653
  reader.skipType(tag & 7);
@@ -1660,18 +1659,21 @@ export const ProcessTransactionsRequest = {
1660
1659
 
1661
1660
  fromJSON(object: any): ProcessTransactionsRequest {
1662
1661
  return {
1663
- transaction: isSet(object.transaction)
1664
- ? RawTransaction.fromJSON(object.transaction)
1665
- : undefined,
1662
+ transactions: Array.isArray(object?.transactions)
1663
+ ? object.transactions.map((e: any) => RawTransaction.fromJSON(e))
1664
+ : [],
1666
1665
  };
1667
1666
  },
1668
1667
 
1669
1668
  toJSON(message: ProcessTransactionsRequest): unknown {
1670
1669
  const obj: any = {};
1671
- message.transaction !== undefined &&
1672
- (obj.transaction = message.transaction
1673
- ? RawTransaction.toJSON(message.transaction)
1674
- : undefined);
1670
+ if (message.transactions) {
1671
+ obj.transactions = message.transactions.map((e) =>
1672
+ e ? RawTransaction.toJSON(e) : undefined
1673
+ );
1674
+ } else {
1675
+ obj.transactions = [];
1676
+ }
1675
1677
  return obj;
1676
1678
  },
1677
1679
 
@@ -1679,10 +1681,8 @@ export const ProcessTransactionsRequest = {
1679
1681
  object: DeepPartial<ProcessTransactionsRequest>
1680
1682
  ): ProcessTransactionsRequest {
1681
1683
  const message = createBaseProcessTransactionsRequest();
1682
- message.transaction =
1683
- object.transaction !== undefined && object.transaction !== null
1684
- ? RawTransaction.fromPartial(object.transaction)
1685
- : undefined;
1684
+ message.transactions =
1685
+ object.transactions?.map((e) => RawTransaction.fromPartial(e)) || [];
1686
1686
  return message;
1687
1687
  },
1688
1688
  };
package/src/index.ts CHANGED
@@ -6,8 +6,9 @@ export { ProcessorServiceImpl } from './service'
6
6
  export { Counter, Meter, Gauge } from './meter'
7
7
  export { getProvider, setProvider, DummyProvider } from './provider'
8
8
  export { SolanaBaseProcessor } from './solana-processor'
9
+ export { SuiBaseProcessor } from './sui-processor'
9
10
  export { ContractNamer } from './contract-namer'
10
- export { BindOptions, SolanaBindOptions } from './bind-options'
11
+ export { BindOptions, SolanaBindOptions, SuiBindOptions } from './bind-options'
11
12
  export { transformEtherError } from './error'
12
13
  export { ProcessorState } from './processor-state'
13
14
  export { BigNumber as BigDecimal } from 'bignumber.js'
@@ -5,6 +5,7 @@ import { BaseProcessorTemplate } from './base-processor-template'
5
5
  import { TemplateInstance } from './gen/processor/protos/processor'
6
6
  import { Provider } from '@ethersproject/providers'
7
7
  import { SolanaBaseProcessor } from './solana-processor'
8
+ import { SuiBaseProcessor } from './sui-processor'
8
9
 
9
10
  export class ProcessorState {
10
11
  // from abiName_address_chainId => contract wrapper
@@ -21,4 +22,6 @@ export class ProcessorState {
21
22
  templatesInstances: TemplateInstance[] = []
22
23
 
23
24
  solanaProcessors: SolanaBaseProcessor[] = []
25
+
26
+ suiProcessors: SuiBaseProcessor[] = []
24
27
  }
package/src/service.ts CHANGED
@@ -175,6 +175,26 @@ export class ProcessorServiceImpl implements ProcessorServiceImplementation {
175
175
  }
176
176
  this.contractConfigs.push(contractConfig)
177
177
  }
178
+
179
+ // Part 3, prepare sui constractors
180
+ for (const suiProcessor of global.PROCESSOR_STATE.suiProcessors) {
181
+ const contractConfig: ContractConfig = {
182
+ processorType: 'user_processor',
183
+ contract: {
184
+ name: 'sui processor',
185
+ chainId: 'SUI_devnet',
186
+ address: suiProcessor.address,
187
+ abi: '',
188
+ },
189
+ blockConfigs: [],
190
+ logConfigs: [],
191
+ traceConfigs: [],
192
+ startBlock: suiProcessor.config.startSeqNumber,
193
+ endBlock: DEFAULT_MAX_BLOCK,
194
+ instructionConfig: undefined,
195
+ }
196
+ this.contractConfigs.push(contractConfig)
197
+ }
178
198
  }
179
199
 
180
200
  async start(request: StartRequest, context: CallContext): Promise<Empty> {
@@ -276,7 +296,39 @@ export class ProcessorServiceImpl implements ProcessorServiceImplementation {
276
296
  throw new ServerError(Status.UNAVAILABLE, 'Service not started.')
277
297
  }
278
298
 
279
- throw new ServerError(Status.UNIMPLEMENTED, 'Processing transaction is not suppored.')
299
+ const result: ProcessResult = {
300
+ gauges: [],
301
+ counters: [],
302
+ logs: [],
303
+ }
304
+
305
+ if (global.PROCESSOR_STATE.suiProcessors) {
306
+ const processorPromises: Promise<void>[] = []
307
+ for (const txn of request.transactions) {
308
+ processorPromises.push(
309
+ new Promise((resolve, _) => {
310
+ for (const processor of global.PROCESSOR_STATE.suiProcessors) {
311
+ const res = processor.handleTransaction(JSON.parse(new TextDecoder().decode(txn.raw)))
312
+ if (res) {
313
+ res.gauges.forEach((g) => {
314
+ result.gauges.push(g)
315
+ })
316
+ res.counters.forEach((c) => {
317
+ result.counters.push(c)
318
+ })
319
+ }
320
+ }
321
+ resolve()
322
+ })
323
+ )
324
+ }
325
+ await Promise.all(processorPromises)
326
+ }
327
+
328
+ recordRuntimeInfo(result, HandlerType.TRANSACTION)
329
+ return {
330
+ result,
331
+ }
280
332
  }
281
333
 
282
334
  async processInstructions(
@@ -0,0 +1,75 @@
1
+ import { SuiBindOptions } from './bind-options'
2
+ import { SuiContext } from './context'
3
+ import { ProcessResult } from './index'
4
+ import Long from 'long'
5
+
6
+ type IndexConfigure = {
7
+ startSeqNumber: Long
8
+ endSeqNumber?: Long
9
+ }
10
+
11
+ export class SuiBaseProcessor {
12
+ public transactionHanlder: (transaction: any, ctx: SuiContext) => void
13
+ address: string
14
+ config: IndexConfigure = { startSeqNumber: new Long(0) }
15
+
16
+ constructor(options: SuiBindOptions) {
17
+ if (options) {
18
+ this.bind(options)
19
+ }
20
+ global.PROCESSOR_STATE.suiProcessors.push(this)
21
+ }
22
+
23
+ bind(options: SuiBindOptions) {
24
+ this.address = options.address
25
+ if (options.startBlock) {
26
+ this.startSlot(options.startBlock)
27
+ }
28
+ if (options.endBlock) {
29
+ this.endBlock(options.endBlock)
30
+ }
31
+ }
32
+
33
+ public onTransaction(handler: (transaction: any, ctx: SuiContext) => void) {
34
+ if (!this.isBind()) {
35
+ throw new Error("Processor doesn't bind to an address")
36
+ }
37
+
38
+ this.transactionHanlder = handler
39
+
40
+ return this
41
+ }
42
+
43
+ public handleTransaction(txn: any): ProcessResult | null {
44
+ const ctx = new SuiContext(this.address)
45
+
46
+ if (txn) {
47
+ this.transactionHanlder(txn, ctx)
48
+ }
49
+ return {
50
+ gauges: ctx.gauges,
51
+ counters: ctx.counters,
52
+ logs: [],
53
+ }
54
+ }
55
+
56
+ public isBind() {
57
+ return this.address !== null
58
+ }
59
+
60
+ public startSlot(startSlot: Long | number) {
61
+ if (typeof startSlot === 'number') {
62
+ startSlot = Long.fromNumber(startSlot)
63
+ }
64
+ this.config.startSeqNumber = startSlot
65
+ return this
66
+ }
67
+
68
+ public endBlock(endBlock: Long | number) {
69
+ if (typeof endBlock === 'number') {
70
+ endBlock = Long.fromNumber(endBlock)
71
+ }
72
+ this.config.endSeqNumber = endBlock
73
+ return this
74
+ }
75
+ }
@@ -0,0 +1,167 @@
1
+ import { expect } from 'chai'
2
+ import { TextEncoder } from 'util'
3
+ import { ProcessTransactionsRequest } from '..'
4
+
5
+ import { TestProcessorServer } from './test-processor-server'
6
+
7
+ describe('Test Sui Example', () => {
8
+ const service = new TestProcessorServer(() => {
9
+ require('./tic-tac-toe')
10
+ })
11
+
12
+ beforeAll(async () => {
13
+ await service.start({ templateInstances: [] })
14
+ })
15
+
16
+ test('check configuration ', async () => {
17
+ const config = await service.getConfig({})
18
+ expect(config.contractConfigs).length(1)
19
+ })
20
+
21
+ test('Check tictactoe transaction dispatch', async () => {
22
+ const request: ProcessTransactionsRequest = {
23
+ transactions: [
24
+ {
25
+ txHash: 'z3HjnnFFKAaszOi0pMSImtGMpRd2r7ljLjAjUoqs3Kw=',
26
+ raw: new TextEncoder().encode(JSON.stringify(testData)),
27
+ programAccountId: '0xb8252513f0b9efaa3e260842c4b84d8ff933522d',
28
+ },
29
+ ],
30
+ }
31
+ const res = await service.processTransactions(request)
32
+ expect(res.result?.counters).length(1)
33
+ expect(res.result?.gauges).length(0)
34
+ })
35
+ })
36
+
37
+ const testData = {
38
+ certificate: {
39
+ transactionDigest: 'z3HjnnFFKAaszOi0pMSImtGMpRd2r7ljLjAjUoqs3Kw=',
40
+ data: {
41
+ transactions: [
42
+ {
43
+ Call: {
44
+ package: {
45
+ objectId: '0xb8252513f0b9efaa3e260842c4b84d8ff933522d',
46
+ version: 1,
47
+ digest: 'UyeEXDb5jCLGuk/PVcqdLtbKSI3mSANB2/DxiyzXRC8=',
48
+ },
49
+ module: 'shared_tic_tac_toe',
50
+ function: 'place_mark',
51
+ arguments: ['0x8ed24078d64aa1a2a7593cba7ab64eb2016fa3d4', 2, ''],
52
+ },
53
+ },
54
+ ],
55
+ sender: '0x1c270459011d19dc342751aff75b4188334438fa',
56
+ gasPayment: {
57
+ objectId: '0x018b73e6652bab0f6419fa998263b568fa0688bb',
58
+ version: 8,
59
+ digest: 'suj5fniFCh3oqu+3BQWASz5zyUl4jUWVmJFf76AwVoE=',
60
+ },
61
+ gasBudget: 1000,
62
+ },
63
+ txSignature:
64
+ 'ACIBv8kDff83DOjZsrUe4RqC1BLBGZtLAwFf/3tHUWJe1F+fxtg16Kqdm85TY9IWeYhVTtQkmchROxX8g0pi/Ak48WB/fgCTwX6K9CIMWgmr+j4k7x4dPYBNizpjHvBgCQ==',
65
+ authSignInfo: {
66
+ epoch: 0,
67
+ signature: [
68
+ 'o4tOmjc4jJ27NoKGEHlNDZav0rBJLDqzzsL1kGJOviPKgpLlxyFCeBHrgjAwoc4Y5M75wYgccCuiv67l1w05DQ==',
69
+ 'B2tClnK9GYCDFg6HbO/IW7hlJkhfIXi6NoDn7s4Pyw94BjMB/v0S0ZufbLwDO/WhBwU83q+wRTanG4HRhvUuBw==',
70
+ '5s49bESgHvDH7/oqjuxjy9YW4xWCG4e8g6hGlZC0bTXskPdf+q6bSGglkkMpOr1B3uIlMeif1NAlRQCKsfNcCg==',
71
+ ],
72
+ signers_map: [58, 48, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0, 16, 0, 0, 0, 1, 0, 2, 0, 3, 0],
73
+ },
74
+ },
75
+ effects: {
76
+ status: {
77
+ status: 'success',
78
+ },
79
+ gasUsed: {
80
+ computationCost: 716,
81
+ storageCost: 48,
82
+ storageRebate: 35,
83
+ },
84
+ sharedObjects: [
85
+ {
86
+ objectId: '0x8ed24078d64aa1a2a7593cba7ab64eb2016fa3d4',
87
+ version: 6,
88
+ digest: 'kY/I9fcr6rL2EbDO88MxrEmEaxAEtRxgd+lcfQnE4ww=',
89
+ },
90
+ ],
91
+ transactionDigest: 'z3HjnnFFKAaszOi0pMSImtGMpRd2r7ljLjAjUoqs3Kw=',
92
+ created: [
93
+ {
94
+ owner: {
95
+ AddressOwner: '0x1c270459011d19dc342751aff75b4188334438fa',
96
+ },
97
+ reference: {
98
+ objectId: '0x2e37e03297a9d138687ffd921f8a830a6f498ec6',
99
+ version: 1,
100
+ digest: '1zZhoVoTLPRM1YpGX9EcrwPJulKcXyLrF+40rTIQ06g=',
101
+ },
102
+ },
103
+ ],
104
+ mutated: [
105
+ {
106
+ owner: {
107
+ AddressOwner: '0x1c270459011d19dc342751aff75b4188334438fa',
108
+ },
109
+ reference: {
110
+ objectId: '0x018b73e6652bab0f6419fa998263b568fa0688bb',
111
+ version: 9,
112
+ digest: 'naHwWYK8vl7UBnhp40o7h7JI+cxvFF8rTIOQ4RJ4vus=',
113
+ },
114
+ },
115
+ {
116
+ owner: 'Shared',
117
+ reference: {
118
+ objectId: '0x8ed24078d64aa1a2a7593cba7ab64eb2016fa3d4',
119
+ version: 7,
120
+ digest: 's3R+lWAMGde7eqZzllafAJkoR7Em55An8gHgz7oCImw=',
121
+ },
122
+ },
123
+ ],
124
+ gasObject: {
125
+ owner: {
126
+ AddressOwner: '0x1c270459011d19dc342751aff75b4188334438fa',
127
+ },
128
+ reference: {
129
+ objectId: '0x018b73e6652bab0f6419fa998263b568fa0688bb',
130
+ version: 9,
131
+ digest: 'naHwWYK8vl7UBnhp40o7h7JI+cxvFF8rTIOQ4RJ4vus=',
132
+ },
133
+ },
134
+ events: [
135
+ {
136
+ moveEvent: {
137
+ packageId: '0xb8252513f0b9efaa3e260842c4b84d8ff933522d',
138
+ transactionModule: 'shared_tic_tac_toe',
139
+ sender: '0x1c270459011d19dc342751aff75b4188334438fa',
140
+ type: '0xb8252513f0b9efaa3e260842c4b84d8ff933522d::shared_tic_tac_toe::GameEndEvent',
141
+ fields: {
142
+ game_id: '0x8ed24078d64aa1a2a7593cba7ab64eb2016fa3d4',
143
+ },
144
+ bcs: 'jtJAeNZKoaKnWTy6erZOsgFvo9Q=',
145
+ },
146
+ },
147
+ {
148
+ newObject: {
149
+ packageId: '0xb8252513f0b9efaa3e260842c4b84d8ff933522d',
150
+ transactionModule: 'shared_tic_tac_toe',
151
+ sender: '0x1c270459011d19dc342751aff75b4188334438fa',
152
+ recipient: {
153
+ AddressOwner: '0x1c270459011d19dc342751aff75b4188334438fa',
154
+ },
155
+ objectId: '0x2e37e03297a9d138687ffd921f8a830a6f498ec6',
156
+ },
157
+ },
158
+ ],
159
+ dependencies: [
160
+ 'UgLnWz4u9GTgAJYwR+rz+YO5TDJiZHuFjzyh9blJO2o=',
161
+ 'lw2dyQ9J3fPeH5Lx5aiHfjxDHJENTH4910r2/Y/PQX4=',
162
+ 'phojYeMd7C6mRxGXQFDPF10NFYMEUfBND+f8wJGKkbg=',
163
+ ],
164
+ },
165
+ timestamp_ms: 1662996912461,
166
+ parsed_data: null,
167
+ }
@@ -0,0 +1,31 @@
1
+ import { SuiBindOptions } from '../bind-options'
2
+ import { SuiBaseProcessor } from '../sui-processor'
3
+
4
+ class TicTacToeProcessor extends SuiBaseProcessor {
5
+ static bind(options: SuiBindOptions): TicTacToeProcessor {
6
+ if (options && !options.name) {
7
+ options.name = 'TicTacToe'
8
+ }
9
+ return new TicTacToeProcessor(options)
10
+ }
11
+ }
12
+
13
+ TicTacToeProcessor.bind({
14
+ startBlock: 0,
15
+ address: '',
16
+ }).onTransaction((txn, ctx) => {
17
+ if (txn.certificate.data.transactions && txn.certificate.data.transactions.length > 0) {
18
+ if (txn.certificate.data.transactions[0].Call.package.objectId === '0xb8252513f0b9efaa3e260842c4b84d8ff933522d') {
19
+ if (txn.effects.events) {
20
+ txn.effects.events.forEach((event: { newObject: { recipient: { AddressOwner: any } } }) => {
21
+ if (event.newObject) {
22
+ const owner = event.newObject.recipient.AddressOwner
23
+ if ((owner.toString() as string).includes('0x1c27')) {
24
+ ctx.meter.Counter('win_count').add(1)
25
+ }
26
+ }
27
+ })
28
+ }
29
+ }
30
+ }
31
+ })