@xyo-network/chain-api 1.15.2 → 1.15.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 (38) hide show
  1. package/dist/node/driver/mongo/MongoMap.d.ts +9 -3
  2. package/dist/node/driver/mongo/MongoMap.d.ts.map +1 -1
  3. package/dist/node/helpers/index.d.ts +5 -0
  4. package/dist/node/helpers/index.d.ts.map +1 -0
  5. package/dist/node/helpers/initChainId.d.ts +4 -0
  6. package/dist/node/helpers/initChainId.d.ts.map +1 -0
  7. package/dist/node/helpers/initEvmProvider.d.ts +11 -0
  8. package/dist/node/helpers/initEvmProvider.d.ts.map +1 -0
  9. package/dist/node/helpers/initInfuraProvider.d.ts +6 -0
  10. package/dist/node/helpers/initInfuraProvider.d.ts.map +1 -0
  11. package/dist/node/helpers/initJsonRpcProvider.d.ts +6 -0
  12. package/dist/node/helpers/initJsonRpcProvider.d.ts.map +1 -0
  13. package/dist/node/index.mjs +198 -39
  14. package/dist/node/index.mjs.map +1 -1
  15. package/dist/node/manifest/getLocator.d.ts.map +1 -1
  16. package/dist/node/server/app.d.ts +2 -1
  17. package/dist/node/server/app.d.ts.map +1 -1
  18. package/dist/node/server/routes/addRoutes.d.ts +2 -1
  19. package/dist/node/server/routes/addRoutes.d.ts.map +1 -1
  20. package/dist/node/server/routes/healthz/get.d.ts +2 -1
  21. package/dist/node/server/routes/healthz/get.d.ts.map +1 -1
  22. package/dist/node/server/routes/rpc/routes/addRpcRoutes.d.ts +2 -1
  23. package/dist/node/server/routes/rpc/routes/addRpcRoutes.d.ts.map +1 -1
  24. package/dist/node/server/server.d.ts.map +1 -1
  25. package/package.json +58 -51
  26. package/src/driver/mongo/MongoMap.ts +42 -4
  27. package/src/helpers/index.ts +4 -0
  28. package/src/helpers/initChainId.ts +20 -0
  29. package/src/helpers/initEvmProvider.ts +24 -0
  30. package/src/helpers/initInfuraProvider.ts +27 -0
  31. package/src/helpers/initJsonRpcProvider.ts +21 -0
  32. package/src/manifest/getLocator.ts +24 -9
  33. package/src/manifest/public/Chain.json +52 -15
  34. package/src/server/app.ts +3 -2
  35. package/src/server/routes/addRoutes.ts +3 -2
  36. package/src/server/routes/healthz/get.ts +1 -1
  37. package/src/server/routes/rpc/routes/addRpcRoutes.ts +3 -2
  38. package/src/server/server.ts +23 -2
@@ -4,12 +4,17 @@ import {
4
4
  } from '@xylabs/creatable'
5
5
  import { BaseMongoSdk } from '@xylabs/mongo'
6
6
  import { isNull } from '@xylabs/typeof'
7
- import { AsynchronousMap } from '@xyo-network/chain-protocol'
7
+ import { AsynchronousMap } from '@xyo-network/xl1-protocol-sdk'
8
+ import { LRUCache } from 'lru-cache'
8
9
  import {
9
10
  Document, Filter, OptionalUnlessRequiredId, WithId,
10
11
  } from 'mongodb'
11
12
 
12
13
  export interface MongoMapParams<TData extends Document = Document> extends CreatableParams {
14
+ getCache?: {
15
+ enabled: boolean
16
+ maxEntries?: number
17
+ }
13
18
  sdk: BaseMongoSdk<TData>
14
19
  }
15
20
 
@@ -19,44 +24,77 @@ function stripMongoId<V extends Document>(doc: WithId<V>): V {
19
24
  }
20
25
 
21
26
  @creatable()
22
- export class MongoMap<K = string, V extends Document = Document>
27
+ export class MongoMap<K extends {} = string, V extends Document = Document>
23
28
  extends AbstractCreatable<MongoMapParams<V>>
24
29
  implements AsynchronousMap<K, V> {
30
+ private _getCache: LRUCache<K, V> | undefined
31
+
25
32
  get sdk(): BaseMongoSdk<V> {
26
33
  return assertEx(this.params.sdk, () => 'No sdk specified')
27
34
  }
28
35
 
29
36
  async clear(): Promise<void> {
37
+ this._getCache?.clear()
30
38
  await this.sdk.deleteMany({})
31
39
  }
32
40
 
33
41
  async delete(id: K): Promise<boolean> {
42
+ this._getCache?.delete(id)
43
+
34
44
  const filter = { _id: id } as Filter<V>
35
45
  const result = await this.sdk.deleteOne(filter)
36
46
  return result.deletedCount > 0
37
47
  }
38
48
 
39
49
  async get(id: K): Promise<V | undefined> {
50
+ if (this._getCache) {
51
+ const getCacheResult = this._getCache.get(id)
52
+ if (getCacheResult) {
53
+ return getCacheResult
54
+ }
55
+ }
40
56
  const filter = { _id: id } as Filter<V>
41
57
  const doc = await this.sdk.findOne(filter)
42
58
  return isNull(doc) ? undefined : stripMongoId(doc)
43
59
  }
44
60
 
61
+ async getMany(ids: K[]): Promise<V[]> {
62
+ const result: V[] = []
63
+ for (const id of ids) {
64
+ const value = await this.get(id)
65
+ if (value) {
66
+ result.push(value)
67
+ }
68
+ }
69
+ return result
70
+ }
71
+
45
72
  async has(id: K): Promise<boolean> {
73
+ if (this._getCache) {
74
+ const getCacheResult = this._getCache.has(id)
75
+ if (getCacheResult) {
76
+ return getCacheResult
77
+ }
78
+ }
46
79
  const filter = { _id: id } as Filter<V>
47
80
  const exists = await this.sdk.findOne(filter)
48
81
  return isNull(exists) ? false : true
49
82
  }
50
83
 
51
- async set(id: K, data: V): Promise<this> {
84
+ async set(id: K, data: V): Promise<void> {
52
85
  const filter = { _id: id } as Filter<V>
53
86
  const value = { ...data, _id: id } as OptionalUnlessRequiredId<V>
54
87
  await this.sdk.replaceOne(filter, value, { upsert: true })
55
- return this
88
+ this._getCache?.set(id, data)
56
89
  }
57
90
 
58
91
  override async startHandler(): Promise<void> {
59
92
  await super.startHandler()
60
93
  // TODO: Ensure index
94
+
95
+ if (this.params.getCache?.enabled === true) {
96
+ const maxEntries = this.params.getCache?.maxEntries ?? 5000
97
+ this._getCache = new LRUCache<K, V>({ max: maxEntries })
98
+ }
61
99
  }
62
100
  }
@@ -0,0 +1,4 @@
1
+ export * from './initChainId.ts'
2
+ export * from './initEvmProvider.ts'
3
+ export * from './initInfuraProvider.ts'
4
+ export * from './initJsonRpcProvider.ts'
@@ -0,0 +1,20 @@
1
+ import { assertEx } from '@xylabs/assert'
2
+ import { hexFrom, isHex } from '@xylabs/hex'
3
+ import { isDefined } from '@xylabs/typeof'
4
+ import type { Config } from '@xyo-network/xl1-protocol-sdk'
5
+
6
+ export const canUseChainId = (config: Config): boolean => {
7
+ return isDefined(config.evm.chainId)
8
+ }
9
+
10
+ export const getChainId = (config: Config) => {
11
+ const chainId = assertEx(config.evm.chainId, () => 'Missing config.evm.chainId')
12
+ if (isHex(chainId, { prefix: true })) {
13
+ const hex = hexFrom(chainId)
14
+ const parsed = Number.parseInt(hex, 16)
15
+ return parsed
16
+ } else {
17
+ const parsed = Number.parseInt(chainId, 10)
18
+ return parsed
19
+ }
20
+ }
@@ -0,0 +1,24 @@
1
+ import { assertEx } from '@xylabs/assert'
2
+ import type { Logger } from '@xylabs/logger'
3
+ import type { Config } from '@xyo-network/xl1-protocol-sdk'
4
+ import type { Provider } from 'ethers'
5
+ import type { JsonRpcProvider } from 'ethers/providers'
6
+
7
+ import { canUseInfuraProvider, initInfuraProvider } from './initInfuraProvider.ts'
8
+ import { canUseJsonRpcProvider, initJsonRpcProvider } from './initJsonRpcProvider.ts'
9
+
10
+ let provider: Promise<JsonRpcProvider> | undefined
11
+
12
+ export const initEvmProvider = async ({ config }: { config: Config; logger?: Logger }): Promise<Provider> => {
13
+ if (provider) return provider
14
+ if (canUseInfuraProvider(config)) {
15
+ provider = initInfuraProvider(config)
16
+ } else if (canUseJsonRpcProvider(config)) {
17
+ provider = initJsonRpcProvider(config)
18
+ }
19
+ return assertEx(await provider, () => 'Error: No provider available')
20
+ }
21
+
22
+ export const canUseEvmProvider = ({ config }: { config: Config }) => {
23
+ return canUseInfuraProvider(config) || canUseJsonRpcProvider(config)
24
+ }
@@ -0,0 +1,27 @@
1
+ import { assertEx } from '@xylabs/assert'
2
+ import { isDefined } from '@xylabs/typeof'
3
+ import type { Config } from '@xyo-network/xl1-protocol-sdk'
4
+ import { InfuraProvider } from 'ethers/providers'
5
+
6
+ import { canUseChainId, getChainId } from './initChainId.ts'
7
+
8
+ let instance: Promise<InfuraProvider> | undefined
9
+
10
+ export const initInfuraProvider = (config: Config) => {
11
+ if (instance) return instance
12
+ const providerConfig = getInfuraProviderConfig(config)
13
+ instance = Promise.resolve(new InfuraProvider(...providerConfig))
14
+ return instance
15
+ }
16
+
17
+ export const canUseInfuraProvider = (config: Config): boolean => {
18
+ return canUseChainId(config)
19
+ && isDefined(config.evm?.infura?.projectId)
20
+ && isDefined(config.evm?.infura?.projectSecret)
21
+ }
22
+
23
+ export const getInfuraProviderConfig = (config: Config) => {
24
+ const projectId = assertEx(config.evm?.infura?.projectId, () => 'Missing config.evm.infura.projectId')
25
+ const projectSecret = assertEx(config.evm?.infura?.projectSecret, () => 'Missing config.evm.infura.projectSecret')
26
+ return [getChainId(config), projectId, projectSecret] as const
27
+ }
@@ -0,0 +1,21 @@
1
+ import { assertEx } from '@xylabs/assert'
2
+ import { isDefined } from '@xylabs/typeof'
3
+ import type { Config } from '@xyo-network/xl1-protocol-sdk'
4
+ import { JsonRpcProvider } from 'ethers/providers'
5
+
6
+ import { canUseChainId, getChainId } from './initChainId.ts'
7
+
8
+ export const initJsonRpcProvider = (config: Config) => {
9
+ const providerConfig = getJsonRpcProviderConfig(config)
10
+ return Promise.resolve(new JsonRpcProvider(...providerConfig))
11
+ }
12
+
13
+ export const canUseJsonRpcProvider = (config: Config) => {
14
+ return canUseChainId(config)
15
+ && isDefined(config.evm.jsonRpc?.url)
16
+ }
17
+
18
+ export const getJsonRpcProviderConfig = (config: Config) => {
19
+ const jsonRpcUrl = assertEx(config.evm.jsonRpc?.url, () => 'Missing config.evm.jsonRpc.url')
20
+ return [jsonRpcUrl, getChainId(config)] as const
21
+ }
@@ -8,17 +8,20 @@ import { MemoryArchivist } from '@xyo-network/archivist-memory'
8
8
  import { MongoDBArchivistV2 } from '@xyo-network/archivist-mongodb'
9
9
  import { ViewArchivist } from '@xyo-network/archivist-view'
10
10
  import {
11
- AddressBalanceDivinerV2, ArchivistSyncDiviner, balanceSummaryRepositoryFromMap, HeadValidationDiviner,
11
+ AddressBalanceDivinerV2, AddressTransferDiviner, ArchivistSyncDiviner, HeadValidationDiviner,
12
12
  } from '@xyo-network/chain-modules'
13
- import type { MapType } from '@xyo-network/chain-protocol'
14
13
  import { initTelemetry } from '@xyo-network/chain-telemetry'
15
14
  import { AbstractModule, LoggerModuleStatusReporter } from '@xyo-network/module-abstract'
16
15
  import { ModuleFactoryLocator } from '@xyo-network/module-factory-locator'
17
16
  import type { MongoDBModuleParamsV2 } from '@xyo-network/module-model-mongodb'
18
17
  import type { WithStorageMeta } from '@xyo-network/payload-model'
19
18
  import { MemorySentinel } from '@xyo-network/sentinel-memory'
20
- import type { BalancesStepSummary, Config } from '@xyo-network/xl1-protocol-sdk'
19
+ import { StepSizes } from '@xyo-network/xl1-protocol'
20
+ import type {
21
+ BalancesStepSummary, Config, MapType, TransfersStepSummary,
22
+ } from '@xyo-network/xl1-protocol-sdk'
21
23
  import { hasMongoConfig } from '@xyo-network/xl1-protocol-sdk'
24
+ import { Semaphore } from 'async-mutex'
22
25
 
23
26
  import { MongoMap } from '../driver/index.ts'
24
27
 
@@ -51,8 +54,8 @@ export const getLocator = async (context: GetLocatorContext) => {
51
54
  const statusReporter = logger ? new LoggerModuleStatusReporter(logger) : undefined
52
55
 
53
56
  const locator = new ModuleFactoryLocator()
54
- // Initialize with an in-memory map for backing the summary repository
55
- let summaryMap: MapType<Hash, WithStorageMeta<BalancesStepSummary>> = new Map<Hash, WithStorageMeta<BalancesStepSummary>>()
57
+ let balanceSummaryMap: MapType<string, WithStorageMeta<BalancesStepSummary>> | undefined
58
+ let transferSummaryMap: MapType<string, WithStorageMeta<TransfersStepSummary>> | undefined
56
59
  // If there's a MongoDB configuration
57
60
  const mongoConfig = config.storage?.mongo
58
61
  if (hasMongoConfig(mongoConfig)) {
@@ -70,13 +73,25 @@ export const getLocator = async (context: GetLocatorContext) => {
70
73
  locator.register(MongoDBArchivistV2.factory(params), undefined, true)
71
74
 
72
75
  // Use a persistent MongoMap for the summary repository if MongoDB is configured
73
- const sdk = new BaseMongoSdk<WithStorageMeta<BalancesStepSummary>>({ ...payloadSdkConfig, collection: 'balance_summary_map' })
74
- summaryMap = await MongoMap.create<MongoMap<Hash, WithStorageMeta<BalancesStepSummary>>>({ sdk })
76
+ const sdkBalanceSummaryMap = new BaseMongoSdk<WithStorageMeta<BalancesStepSummary>>({ ...payloadSdkConfig, collection: 'balance_summary_map' })
77
+ balanceSummaryMap = await MongoMap.create<MongoMap<Hash, WithStorageMeta<BalancesStepSummary>>>({
78
+ sdk: sdkBalanceSummaryMap,
79
+ getCache: { enabled: true, maxEntries: 5000 },
80
+ })
81
+
82
+ const sdkTransferSummaryMap = new BaseMongoSdk<WithStorageMeta<TransfersStepSummary>>({ ...payloadSdkConfig, collection: 'transfer_summary_map' })
83
+ transferSummaryMap = await MongoMap.create<MongoMap<Hash, WithStorageMeta<TransfersStepSummary>>>({
84
+ sdk: sdkTransferSummaryMap,
85
+ getCache: { enabled: true, maxEntries: 5000 },
86
+ })
75
87
  }
76
88
 
77
- const summaryRepository = balanceSummaryRepositoryFromMap(summaryMap)
78
89
  locator.register(AddressBalanceDivinerV2.factory<AddressBalanceDivinerV2>({
79
- traceProvider, meterProvider, statusReporter, summaryRepository,
90
+ traceProvider, meterProvider, statusReporter, summaryMap: balanceSummaryMap, stepSemaphores: StepSizes.map(() => new Semaphore(20)),
91
+ }))
92
+
93
+ locator.register(AddressTransferDiviner.factory<AddressTransferDiviner>({
94
+ traceProvider, meterProvider, statusReporter, summaryMap: transferSummaryMap, stepSemaphores: StepSizes.map(() => new Semaphore(20)),
80
95
  }))
81
96
 
82
97
  const chainId = isDefined(config.chain.id)
@@ -30,12 +30,12 @@
30
30
  "eventSubscriptions": [
31
31
  {
32
32
  "sourceEvent": "inserted",
33
- "sourceModule": "Chain:Submissions",
33
+ "sourceModule": "Submissions",
34
34
  "targetModuleFunction": "divine"
35
35
  }
36
36
  ],
37
- "inArchivist": "Chain:Submissions",
38
- "outArchivist": "Chain:Validated",
37
+ "inArchivist": "Submissions",
38
+ "outArchivist": "Validated",
39
39
  "name": "HeadValidationDiviner"
40
40
  }
41
41
  },
@@ -66,7 +66,7 @@
66
66
  "accountPath": "1/1'/4'",
67
67
  "automations": [
68
68
  {
69
- "frequency": 60000,
69
+ "frequency": 10000,
70
70
  "frequencyUnits": "millis",
71
71
  "schema": "network.xyo.automation.interval",
72
72
  "type": "interval"
@@ -82,6 +82,28 @@
82
82
  }
83
83
  ]
84
84
  }
85
+ },
86
+ {
87
+ "config": {
88
+ "accountPath": "1/1'/5'",
89
+ "automations": [
90
+ {
91
+ "frequency": 10000,
92
+ "frequencyUnits": "millis",
93
+ "schema": "network.xyo.automation.interval",
94
+ "type": "interval"
95
+ }
96
+ ],
97
+ "name": "AddressTransferPollingSentinel",
98
+ "schema": "network.xyo.sentinel.config",
99
+ "synchronous": true,
100
+ "tasks": [
101
+ {
102
+ "mod": "AddressTransferDiviner",
103
+ "endPoint": "divine"
104
+ }
105
+ ]
106
+ }
85
107
  }
86
108
  ],
87
109
  "public": [
@@ -111,23 +133,38 @@
111
133
  "enabled": true,
112
134
  "maxEntries": 5000
113
135
  },
114
- "originArchivist": "Chain:Validated",
136
+ "originArchivist": "Validated",
115
137
  "schema": "network.xyo.archivist.view.config"
116
138
  }
117
139
  },
118
140
  {
119
141
  "config": {
120
- "accountPath": "1/1/3",
121
- "schema": "network.xyo.diviner.chain.address.balance.config",
122
- "archivist": "Chain:Validated",
142
+ "accountPath": "1/1/3'",
123
143
  "name": "AddressBalanceDiviner",
124
- "eventSubscriptions": [
125
- {
126
- "sourceEvent": "inserted",
127
- "sourceModule": "Chain:Validated",
128
- "targetModuleFunction": "divine"
144
+ "schema": "network.xyo.diviner.chain.address.balance.config",
145
+ "map": {
146
+ "lmdb": {
147
+ "dbName": "summaries",
148
+ "storeName": "address_balance",
149
+ "location": ".store"
129
150
  }
130
- ]
151
+ },
152
+ "archivist": "Validated"
153
+ }
154
+ },
155
+ {
156
+ "config": {
157
+ "accountPath": "1/1/4'",
158
+ "name": "AddressTransferDiviner",
159
+ "schema": "network.xyo.diviner.chain.address.transfer.config",
160
+ "map": {
161
+ "lmdb": {
162
+ "dbName": "summaries",
163
+ "storeName": "address_transfer",
164
+ "location": ".store"
165
+ }
166
+ },
167
+ "archivist": "Validated"
131
168
  }
132
169
  }
133
170
  ]
@@ -135,4 +172,4 @@
135
172
  }
136
173
  ],
137
174
  "schema": "network.xyo.manifest"
138
- }
175
+ }
package/src/server/app.ts CHANGED
@@ -9,6 +9,7 @@ import {
9
9
  standardResponses,
10
10
  } from '@xylabs/express'
11
11
  import type { NodeInstance } from '@xyo-network/node-model'
12
+ import type { StakedChainContextRead, StakeEventsRead } from '@xyo-network/xl1-protocol-sdk'
12
13
  import compression from 'compression'
13
14
  import cors from 'cors'
14
15
  import type { Express } from 'express'
@@ -17,7 +18,7 @@ import express from 'express'
17
18
  import { addInstrumentation } from './instrumentation.ts'
18
19
  import { addRoutes } from './routes/index.ts'
19
20
 
20
- export const getApp = (node: NodeInstance): Express => {
21
+ export const getApp = (node: NodeInstance, eventsReader: StakeEventsRead, stakedChainContext: StakedChainContextRead): Express => {
21
22
  addInstrumentation()
22
23
  const app = express()
23
24
  app.set('etag', false)
@@ -31,7 +32,7 @@ export const getApp = (node: NodeInstance): Express => {
31
32
  app.use(customPoweredByHeader)
32
33
  disableCaseSensitiveRouting(app)
33
34
  app.node = node
34
- addRoutes(app)
35
+ addRoutes(app, eventsReader, stakedChainContext)
35
36
  app.use(standardErrors)
36
37
  return app
37
38
  }
@@ -1,11 +1,12 @@
1
+ import type { StakedChainContextRead, StakeEventsRead } from '@xyo-network/xl1-protocol-sdk'
1
2
  import type { Express } from 'express'
2
3
 
3
4
  import { addNodeRoutes } from './address/index.ts'
4
5
  import { addDataLakeRoutes } from './dataLake/index.ts'
5
6
  import { addRpcRoutes } from './rpc/index.ts'
6
7
 
7
- export const addRoutes = (app: Express) => {
8
- addRpcRoutes(app)
8
+ export const addRoutes = (app: Express, eventsReader: StakeEventsRead, stakedChainContext: StakedChainContextRead) => {
9
+ addRpcRoutes(app, eventsReader, stakedChainContext)
9
10
  addDataLakeRoutes(app)
10
11
  addNodeRoutes(app)
11
12
  }
@@ -17,4 +17,4 @@ const handler: RequestHandler<NoReqParams> = (_req, res) => {
17
17
  res.status(200).send(data)
18
18
  }
19
19
 
20
- export const getHealthz = handler
20
+ export const getHealthz: RequestHandler<NoReqParams> = handler
@@ -1,15 +1,16 @@
1
1
  import { setRawResponseFormat } from '@xylabs/express'
2
2
  import { NodeXyoViewer } from '@xyo-network/chain-rpc'
3
+ import type { StakedChainContextRead, StakeEventsRead } from '@xyo-network/xl1-protocol-sdk'
3
4
  import {
4
5
  NodeXyoRunner, rpcEngineFromConnection,
5
6
  XyoBaseConnection,
6
7
  } from '@xyo-network/xl1-rpc'
7
8
  import type { Express } from 'express'
8
9
 
9
- export const addRpcRoutes = (app: Express) => {
10
+ export const addRpcRoutes = (app: Express, eventsReader: StakeEventsRead, stakedChainContext: StakedChainContextRead) => {
10
11
  const { node } = app
11
12
  const runner = new NodeXyoRunner(node)
12
- const viewer = new NodeXyoViewer(node)
13
+ const viewer = new NodeXyoViewer(node, eventsReader, stakedChainContext)
13
14
  const connection = new XyoBaseConnection({ runner, viewer })
14
15
  const engine = rpcEngineFromConnection(connection)
15
16
 
@@ -1,12 +1,19 @@
1
1
  import { assertEx } from '@xylabs/assert'
2
+ import { toEthAddress, ZERO_HASH } from '@xylabs/hex'
2
3
  import type { Logger } from '@xylabs/logger'
3
4
  import { isDefined, isString } from '@xylabs/typeof'
5
+ import { asArchivistInstance } from '@xyo-network/archivist-model'
4
6
  import { boot } from '@xyo-network/bios'
5
7
  import type { BiosExternalInterface } from '@xyo-network/bios-model'
8
+ import { EthereumChainStake, EthereumChainStakeEvents } from '@xyo-network/chain-ethereum'
6
9
  import type { NodeInstance } from '@xyo-network/node-model'
10
+ import type { Payload, WithStorageMeta } from '@xyo-network/payload-model'
11
+ import { StakedXyoChainV2__factory } from '@xyo-network/typechain'
7
12
  import { HDWallet } from '@xyo-network/wallet'
8
- import { type Config } from '@xyo-network/xl1-protocol-sdk'
13
+ import type { ChainId } from '@xyo-network/xl1-protocol'
14
+ import { type Config, readPayloadMapFromStore } from '@xyo-network/xl1-protocol-sdk'
9
15
 
16
+ import { initInfuraProvider } from '../helpers/index.ts'
10
17
  import { getNode } from '../manifest/index.ts'
11
18
  import { getApp } from './app.ts'
12
19
 
@@ -49,10 +56,24 @@ export const getServer = async (context: GetServerContext) => {
49
56
  const bios = await boot()
50
57
  const seedPhrase = isDefined(mnemonic) ? mnemonic : await getSeedPhrase(bios, config, logger)
51
58
  const wallet = await HDWallet.fromPhrase(seedPhrase)
59
+ const provider = await initInfuraProvider(config)
60
+ const contractAddress = assertEx(config.chain.id, () => 'Missing config.evm.chainId') as ChainId
61
+ const contract = StakedXyoChainV2__factory.connect(toEthAddress(contractAddress), provider)
52
62
  const nodeContext = {
53
63
  wallet, logger, config,
54
64
  }
55
- const app = getApp(node ?? await getNode(nodeContext))
65
+ const eventsReader = new EthereumChainStakeEvents(contract)
66
+ const stakeChainReader = await EthereumChainStake.create({ contract, eventsReader })
67
+ await stakeChainReader.start()
68
+ const rootNode = await getNode(nodeContext)
69
+ const archivist = assertEx(asArchivistInstance(
70
+ await rootNode.resolve('Chain:Validated'),
71
+ { required: true },
72
+ ), () => 'FinalizedArchivist not found in node')
73
+ const chainMap = readPayloadMapFromStore<WithStorageMeta<Payload>>(archivist)
74
+ const app = getApp(node ?? await getNode(nodeContext), eventsReader, {
75
+ chainId: contractAddress, stake: stakeChainReader, store: { chainMap }, head: () => ZERO_HASH,
76
+ })
56
77
  const server = app.listen(port, hostname, () => logger?.log(`[API] Server listening at http://${hostname}:${port}`))
57
78
  server.setTimeout(20_000)
58
79
  return server