@xyo-network/chain-services 1.5.28 → 1.5.30

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 (50) hide show
  1. package/dist/neutral/index.mjs +252 -384
  2. package/dist/neutral/index.mjs.map +1 -1
  3. package/dist/types/AccountBalance/XyoChainAccountBalanceService.d.ts +8 -1
  4. package/dist/types/AccountBalance/XyoChainAccountBalanceService.d.ts.map +1 -1
  5. package/dist/types/AccountBalance/accountBalanceServiceFromArchivist.d.ts.map +1 -1
  6. package/dist/types/BaseService.d.ts +2 -1
  7. package/dist/types/BaseService.d.ts.map +1 -1
  8. package/dist/types/BlockProducer/XyoBlockProducer.d.ts +4 -4
  9. package/dist/types/BlockProducer/XyoBlockProducer.d.ts.map +1 -1
  10. package/dist/types/{XyoChainBlockNumberIterator.d.ts → ChainBlockNumberIteration/ChainBlockNumberIterationService.d.ts} +4 -10
  11. package/dist/types/ChainBlockNumberIteration/ChainBlockNumberIterationService.d.ts.map +1 -0
  12. package/dist/types/ChainBlockNumberIteration/index.d.ts +3 -0
  13. package/dist/types/ChainBlockNumberIteration/index.d.ts.map +1 -0
  14. package/dist/types/ChainBlockNumberIteration/model/BlockNumberIteration.d.ts +7 -0
  15. package/dist/types/ChainBlockNumberIteration/model/BlockNumberIteration.d.ts.map +1 -0
  16. package/dist/types/ChainBlockNumberIteration/model/index.d.ts +2 -0
  17. package/dist/types/ChainBlockNumberIteration/model/index.d.ts.map +1 -0
  18. package/dist/types/ChainIndexService.d.ts +2 -2
  19. package/dist/types/ChainIndexService.d.ts.map +1 -1
  20. package/dist/types/PendingTransactions/PendingTransactions.d.ts +14 -4
  21. package/dist/types/PendingTransactions/PendingTransactions.d.ts.map +1 -1
  22. package/dist/types/PendingTransactions/bundledPayloadToHydratedTransaction.d.ts +4 -0
  23. package/dist/types/PendingTransactions/bundledPayloadToHydratedTransaction.d.ts.map +1 -0
  24. package/dist/types/PendingTransactions/hydratedTransactionToPayloadBundle.d.ts +5 -0
  25. package/dist/types/PendingTransactions/hydratedTransactionToPayloadBundle.d.ts.map +1 -0
  26. package/dist/types/StakeIntent/XyoStakeIntentService.d.ts.map +1 -1
  27. package/dist/types/Staker/Evm/Evm.d.ts +5 -8
  28. package/dist/types/Staker/Evm/Evm.d.ts.map +1 -1
  29. package/dist/types/index.d.ts +1 -2
  30. package/dist/types/index.d.ts.map +1 -1
  31. package/package.json +38 -38
  32. package/src/AccountBalance/XyoChainAccountBalanceService.ts +36 -7
  33. package/src/AccountBalance/accountBalanceServiceFromArchivist.ts +1 -0
  34. package/src/BaseService.ts +2 -1
  35. package/src/BlockProducer/XyoBlockProducer.ts +6 -6
  36. package/src/{XyoChainBlockNumberIterator.ts → ChainBlockNumberIteration/ChainBlockNumberIterationService.ts} +14 -28
  37. package/src/ChainBlockNumberIteration/index.ts +2 -0
  38. package/src/ChainBlockNumberIteration/model/BlockNumberIteration.ts +7 -0
  39. package/src/ChainBlockNumberIteration/model/index.ts +1 -0
  40. package/src/ChainIndexService.ts +2 -2
  41. package/src/PendingTransactions/PendingTransactions.ts +70 -54
  42. package/src/PendingTransactions/bundledPayloadToHydratedTransaction.ts +14 -0
  43. package/src/PendingTransactions/hydratedTransactionToPayloadBundle.ts +23 -0
  44. package/src/StakeIntent/XyoStakeIntentService.ts +3 -2
  45. package/src/Staker/Evm/Evm.ts +34 -39
  46. package/src/index.ts +1 -2
  47. package/dist/types/BaseEthProvider.d.ts +0 -56
  48. package/dist/types/BaseEthProvider.d.ts.map +0 -1
  49. package/dist/types/XyoChainBlockNumberIterator.d.ts.map +0 -1
  50. package/src/BaseEthProvider.ts +0 -219
@@ -1,6 +1,5 @@
1
1
  import { assertEx } from '@xylabs/assert'
2
2
  import type { BaseParams } from '@xylabs/base'
3
- import { BaseEmitter } from '@xylabs/events'
4
3
  import { isDefined, isNull } from '@xylabs/typeof'
5
4
  import type { ArchivistInstance } from '@xyo-network/archivist-model'
6
5
  import { PayloadBuilder } from '@xyo-network/payload-builder'
@@ -16,38 +15,25 @@ import {
16
15
  } from '@xyo-network/xl1-protocol'
17
16
  import { LRUCache } from 'lru-cache'
18
17
 
19
- export class XyoChainBlockNumberIterator extends BaseEmitter<BaseParams, ChainIteratorEventData> implements EventingChainBlockNumberIterator {
20
- protected _blocksByBlockNumber = new LRUCache<number, BlockBoundWitness>({ max: 10_000 })
21
- protected _chainArchivist: ArchivistInstance
22
- protected _chainInformation: ChainIdentification
23
- protected _head: BlockBoundWitness
24
-
25
- protected constructor(params: XyoChainIteratorParams) {
26
- super({})
27
- const { chainArchivist: archivist, head } = params
28
- this._chainArchivist = archivist
29
- this._head = head
30
- this._chainInformation = { id: head.chain }
31
- }
18
+ import { BaseService } from '../BaseService.ts'
32
19
 
33
- get archivist(): ArchivistInstance { return this._chainArchivist }
20
+ export class ChainBlockNumberIterationService extends BaseService<XyoChainIteratorParams, ChainIteratorEventData> implements EventingChainBlockNumberIterator {
21
+ protected _blocksByBlockNumber = new LRUCache<number, BlockBoundWitness>({ max: 10_000 })
34
22
 
35
- get chainIdentification(): ChainIdentification { return this._chainInformation }
23
+ get chainArchivist(): ArchivistInstance { return assertEx(this.params.chainArchivist) }
36
24
 
37
- static async create(params: XyoChainIteratorParams): Promise<XyoChainBlockNumberIterator> {
38
- await Promise.resolve()
39
- return new XyoChainBlockNumberIterator(params)
40
- }
25
+ get chainIdentification(): ChainIdentification { return { id: assertEx(this.params.head?.chain) } }
41
26
 
42
27
  async get(block: number): Promise<BlockBoundWitness> {
28
+ const head = await this.head()
43
29
  // Bail early if the block requested is newer than the current head
44
- assertEx(this._head.block >= block, () => `Block requested is newer than the current head [${block}]`)
30
+ assertEx(head.block >= block, () => `Block requested is newer than the current head [${block}]`)
45
31
  const cached = this._blocksByBlockNumber.get(block)
46
32
  if (cached) return cached
47
33
  // Start at the current head and traverse backwards until the requested block is found
48
- const startingBlock = this._head
34
+ const startingBlock = head
49
35
  const currentBlockHash = await PayloadBuilder.hash(startingBlock)
50
- let currentBlock = (await this._chainArchivist.get([currentBlockHash])).at(0)
36
+ let currentBlock = (await this.chainArchivist.get([currentBlockHash])).at(0)
51
37
  while (isDefined(currentBlock)) {
52
38
  assertEx(asBlockBoundWitness(currentBlock), () => `Expected hash to be a block bound witness [${currentBlock?._hash}]`)
53
39
  if (isBlockBoundWitness(currentBlock)) {
@@ -57,14 +43,14 @@ export class XyoChainBlockNumberIterator extends BaseEmitter<BaseParams, ChainIt
57
43
  }
58
44
  const { previous } = currentBlock
59
45
  if (isNull(previous)) break
60
- currentBlock = (await this._chainArchivist.get([previous])).at(0)
46
+ currentBlock = (await this.chainArchivist.get([previous])).at(0)
61
47
  }
62
48
  }
63
49
  throw new Error(`Block not found: ${block}`)
64
50
  }
65
51
 
66
52
  async head(): Promise<BlockBoundWitness> {
67
- return await Promise.resolve(this._head)
53
+ return await Promise.resolve(assertEx(this.params.head))
68
54
  }
69
55
 
70
56
  async next(block: number): Promise<BlockBoundWitness | undefined> {
@@ -77,13 +63,13 @@ export class XyoChainBlockNumberIterator extends BaseEmitter<BaseParams, ChainIt
77
63
  // and then communicate via method name and documentation
78
64
  async previous(block: number | undefined = undefined, count: number = 1): Promise<BlockBoundWitness[]> {
79
65
  const results: BlockBoundWitness[] = []
80
- let currentBlock: BlockBoundWitness | undefined = isDefined(block) ? (await this.get(block)) : this._head
66
+ let currentBlock: BlockBoundWitness | undefined = isDefined(block) ? (await this.get(block)) : await this.head()
81
67
  while (currentBlock && results.length < count) {
82
68
  if (isBlockBoundWitness(currentBlock)) {
83
69
  results.push(currentBlock)
84
70
  const { previous } = currentBlock
85
71
  if (isNull(previous)) break
86
- const nextBlock = await this._chainArchivist.get([previous])
72
+ const nextBlock = await this.chainArchivist.get([previous])
87
73
  currentBlock = asOptionalBlockBoundWitness(nextBlock[0])
88
74
  } else {
89
75
  const hash = PayloadBuilder.hash(currentBlock)
@@ -96,7 +82,7 @@ export class XyoChainBlockNumberIterator extends BaseEmitter<BaseParams, ChainIt
96
82
  async updateHead(head: BlockBoundWitness): Promise<void> {
97
83
  // Async to allow for re-indexing, etc.
98
84
  await Promise.resolve()
99
- this._head = head
85
+ this.params.head = head
100
86
  void this.emit('headUpdated', { blocks: [head] })
101
87
  }
102
88
  }
@@ -0,0 +1,2 @@
1
+ export * from './ChainBlockNumberIterationService.ts'
2
+ export * from './model/index.ts'
@@ -0,0 +1,7 @@
1
+ import type { Promisable } from '@xylabs/promise'
2
+ import type { BlockBoundWitness, HydratedTransaction } from '@xyo-network/xl1-protocol'
3
+
4
+ export interface BlockNumberIteration {
5
+ validatePendingBlock(block: BlockBoundWitness): Promisable<Error[]>
6
+ validatePendingTransaction(tx: HydratedTransaction): Promise<boolean>
7
+ }
@@ -0,0 +1 @@
1
+ export * from './BlockNumberIteration.ts'
@@ -9,7 +9,7 @@ import {
9
9
 
10
10
  import { BaseService, creatableService } from './BaseService.ts'
11
11
 
12
- export interface XyoChainIndexServiceParams extends BaseServiceParams {
12
+ export interface ChainIndexServiceParams extends BaseServiceParams {
13
13
  archivist?: ArchivistInstance
14
14
  }
15
15
 
@@ -19,7 +19,7 @@ export interface ChainIndexService extends Service {
19
19
  }
20
20
 
21
21
  @creatableService()
22
- export class XyoChainIndexService extends BaseService<XyoChainIndexServiceParams> implements ChainIndexService {
22
+ export class XyoChainIndexService extends BaseService<ChainIndexServiceParams> implements ChainIndexService {
23
23
  private _head: Hash | null = null
24
24
  private _internalArchivist: ArchivistInstance | undefined
25
25
 
@@ -10,35 +10,23 @@ import { globalAttributes } from '@xyo-network/chain-telemetry'
10
10
  import { validateTransaction } from '@xyo-network/chain-validation'
11
11
  import { PayloadBuilder } from '@xyo-network/payload-builder'
12
12
  import {
13
- Payload,
14
- PayloadBundle, Sequence, WithStorageMeta,
13
+ Payload, PayloadBundle, Sequence, WithStorageMeta,
15
14
  } from '@xyo-network/payload-model'
16
15
  import {
17
- asOptionalTransactionBoundWitnessWithStorageMeta, BaseServiceParams,
18
- ChainIdentification, HydratedTransactionWithStorageMeta,
19
- isTransactionBoundWitnessWithStorageMeta,
20
- PendingTransactionsService,
16
+ asOptionalTransactionBoundWitnessWithStorageMeta, BaseServiceParams, ChainIdentification, HydratedTransactionWithStorageMeta,
17
+ isTransactionBoundWitnessWithStorageMeta, PendingTransactionsService,
21
18
  } from '@xyo-network/xl1-protocol'
22
- import { flattenHydratedTransaction } from '@xyo-network/xl1-protocol-sdk'
23
19
  import { Mutex } from 'async-mutex'
24
20
 
25
21
  import { BaseService, creatableService } from '../BaseService.ts'
22
+ import { bundledPayloadToHydratedTransaction } from './bundledPayloadToHydratedTransaction.ts'
23
+ import { hydratedTransactionWithHashStorageMetaToPayloadBundle } from './hydratedTransactionToPayloadBundle.ts'
26
24
 
27
25
  export interface XyoPendingTransactionsServiceParams extends BaseServiceParams {
28
26
  chainArchivist?: ArchivistInstance
29
27
  chainIdentification?: ChainIdentification
30
28
  pendingBundledTransactionsArchivist?: ArchivistInstance
31
- rejectedBundledTransactionsArchivist?: ArchivistInstance
32
- }
33
-
34
- async function bundledPayloadsToHydratedTransaction(
35
- payload: WithStorageMeta<PayloadBundle>,
36
- ): Promise<HydratedTransactionWithStorageMeta | undefined> {
37
- const withStorageMeta = await PayloadBuilder.addStorageMeta(payload.payloads)
38
- const tx = asOptionalTransactionBoundWitnessWithStorageMeta(withStorageMeta.find(p => p._hash === payload.root))
39
- if (tx) {
40
- return [tx, withStorageMeta.map(p => p._hash === payload.root ? undefined : p).filter(exists)]
41
- }
29
+ rejectedTransactionsArchivist?: ArchivistInstance
42
30
  }
43
31
 
44
32
  globalAttributes.setAttribute('XyoPendingTransactionsService:status', 'unknown')
@@ -81,6 +69,11 @@ export class XyoPendingTransactionsService extends BaseService<XyoPendingTransac
81
69
  */
82
70
  private _pendingTransactionsCount: number = 0
83
71
 
72
+ /**
73
+ * A set of transaction hashes that are pending removal from the
74
+ * curated pending transactions archivist. This is used to track
75
+ * which transactions need to be removed from the archivist.
76
+ */
84
77
  private _removablePendingTransactionHashes: Set<Hash> = new Set()
85
78
 
86
79
  /**
@@ -110,8 +103,8 @@ export class XyoPendingTransactionsService extends BaseService<XyoPendingTransac
110
103
  return this._pendingTransactionsCount
111
104
  }
112
105
 
113
- private get rejectedBundledTransactionsArchivist() {
114
- return assertEx(this.params.rejectedBundledTransactionsArchivist, () => 'No rejected bundled transactions archivist')
106
+ private get rejectedTransactionsArchivist() {
107
+ return assertEx(this.params.rejectedTransactionsArchivist, () => 'No rejected transactions archivist')
115
108
  }
116
109
 
117
110
  override async createHandler() {
@@ -125,12 +118,12 @@ export class XyoPendingTransactionsService extends BaseService<XyoPendingTransac
125
118
 
126
119
  // On new finalized blocks, remove the transactions from the curated archivist
127
120
  this.chainArchivist.on('inserted', ({ payloads }) => {
128
- this.removeFinalizedTransactions(payloads)
121
+ this.markAnyIncludedTransactionsForRemoval(payloads)
129
122
  })
130
123
 
131
- // On new rejected blocks, remove the transactions from the curated archivist
132
- this.rejectedBundledTransactionsArchivist.on('inserted', ({ payloads }) => {
133
- this.removeRejectedBundledTransactions(payloads)
124
+ // On new rejected transactions, remove the transactions from the curated archivist
125
+ this.rejectedTransactionsArchivist.on('inserted', ({ payloads }) => {
126
+ this.markAnyIncludedTransactionsForRemoval(payloads)
134
127
  })
135
128
 
136
129
  const pendingTransactionsCounter = this.meter?.createObservableUpDownCounter(
@@ -147,31 +140,58 @@ export class XyoPendingTransactionsService extends BaseService<XyoPendingTransac
147
140
 
148
141
  async getPendingTransactions(head: Hash, limit: number): Promise<HydratedTransactionWithStorageMeta[]> {
149
142
  return await this.spanAsync('getPendingTransactions', async () => {
143
+ // Acquires an exclusive mutex to ensure no race conditions while accessing pending transactions.
150
144
  return await this._updateCuratedPendingTransactionsArchivistMutex.runExclusive(async () => {
151
145
  const foundPendingTransactions: HydratedTransactionWithStorageMeta[] = []
152
146
  const foundPendingTransactionsToDeleteHashes: Hash[] = []
147
+
153
148
  let cursor: Sequence | undefined
149
+
150
+ // Continue fetching until the desired number of transactions is reached.
154
151
  while (foundPendingTransactions.length < limit) {
152
+ // Fetch the next batch of payloads
155
153
  const payloads = await this.pendingBundledTransactionsLocalArchivist.next({
156
- limit: 100, order: 'asc', cursor,
154
+ limit: 100,
155
+ order: 'asc',
156
+ cursor,
157
157
  }) as WithStorageMeta<PayloadBundle>[]
158
+
159
+ // Exit if no more payloads are available.
158
160
  if (payloads.length === 0) break
161
+
162
+ // Update the cursor for the next iteration to fetch subsequent payloads.
159
163
  cursor = payloads.at(-1)?._sequence
160
- const deletedTransactionBundles = payloads.filter(tx => this._removablePendingTransactionHashes.has(tx.root))
161
- foundPendingTransactionsToDeleteHashes.push(...deletedTransactionBundles.map(tx => tx._hash).filter(exists))
162
- const undeletedTransactionBundles = payloads.filter(tx => !this._removablePendingTransactionHashes.has(tx.root))
163
- // add the items that are not to be deleted
164
+
165
+ // Filter out bundles that are marked as removable.
166
+ const deletedTransactionBundles = payloads.filter(tx =>
167
+ this._removablePendingTransactionHashes.has(tx.root))
168
+
169
+ // Queue the hashes of deletable transactions for deletion and cleanup.
170
+ foundPendingTransactionsToDeleteHashes.push(
171
+ ...deletedTransactionBundles.map(tx => tx._hash).filter(exists),
172
+ )
173
+
174
+ // Keep only those payloads that are not marked for deletion.
175
+ const undeletedTransactionBundles = payloads.filter(tx =>
176
+ !this._removablePendingTransactionHashes.has(tx.root))
177
+
178
+ // Convert each undeleted payload bundle into a hydrated transaction.
164
179
  const transactions = (await Promise.all(
165
- undeletedTransactionBundles.map(p => bundledPayloadsToHydratedTransaction(p)),
180
+ undeletedTransactionBundles.map(p => bundledPayloadToHydratedTransaction(p)),
166
181
  )).filter(exists)
182
+
183
+ // Add the valid hydrated transactions to the result set.
167
184
  foundPendingTransactions.push(...transactions)
168
185
  }
169
- // remove the hashes from delete queue
186
+
187
+ // Actually delete the marked payload bundles from the archivist
188
+ await this.pendingBundledTransactionsLocalArchivist.delete(foundPendingTransactionsToDeleteHashes)
189
+
190
+ // Remove deleted hashes from the "pending delete" set now that they are deleted
170
191
  for (const hash of foundPendingTransactionsToDeleteHashes) {
171
192
  this._removablePendingTransactionHashes.delete(hash)
172
193
  }
173
- // actually delete the bundles
174
- await this.pendingBundledTransactionsLocalArchivist.delete(foundPendingTransactionsToDeleteHashes)
194
+
175
195
  return foundPendingTransactions
176
196
  }, XyoPendingTransactionsService.MutexPriority.ReadTransactions)
177
197
  })
@@ -196,6 +216,7 @@ export class XyoPendingTransactionsService extends BaseService<XyoPendingTransac
196
216
  }
197
217
 
198
218
  private async insertNewTransactions(payloads: WithStorageMeta<PayloadBundle>[]) {
219
+ if (payloads.length === 0) return
199
220
  this.logger?.log('insertNewTransactions', payloads)
200
221
  return await this.spanAsync('InsertNewTransactions', async () => {
201
222
  return await this._updateCuratedPendingTransactionsArchivistMutex.runExclusive(async () => {
@@ -203,7 +224,7 @@ export class XyoPendingTransactionsService extends BaseService<XyoPendingTransac
203
224
  const unprocessedTransactions = await this.filterAlreadyFinalizedTransactions(payloads)
204
225
  // Hydrate all unprocessed transactions
205
226
  const hydratedUnprocessedTransactions = (await Promise.all(unprocessedTransactions.map(async (tx) => {
206
- return await bundledPayloadsToHydratedTransaction(tx)
227
+ return await bundledPayloadToHydratedTransaction(tx)
207
228
  }))).filter(exists)
208
229
  // Filter to only valid transactions
209
230
  const validTransactions = await filterAsync(hydratedUnprocessedTransactions, async (tx) => {
@@ -214,17 +235,26 @@ export class XyoPendingTransactionsService extends BaseService<XyoPendingTransac
214
235
  return errors.length > 0 ? false : true
215
236
  })
216
237
  if (validTransactions.length > 0) {
217
- await this.pendingBundledTransactionsLocalArchivist.insert(validTransactions.map((tx) => {
218
- return {
219
- root: tx[0]._hash,
220
- payloads: flattenHydratedTransaction(tx),
221
- } as PayloadBundle
222
- }))
238
+ const bundledTransactions = validTransactions.map(tx => hydratedTransactionWithHashStorageMetaToPayloadBundle(tx))
239
+ await this.pendingBundledTransactionsLocalArchivist.insert(bundledTransactions)
223
240
  }
224
241
  }, XyoPendingTransactionsService.MutexPriority.InsertNewTransactions)
225
242
  })
226
243
  }
227
244
 
245
+ /**
246
+ * Marks any included transactions in the provided payloads for removal preventing them
247
+ * from being included in the curated pending transactions archivist and from being offered
248
+ * during the next retrieval of pending transactions.
249
+ * @param payloads An array of payloads that may contain transactions.
250
+ */
251
+ private markAnyIncludedTransactionsForRemoval(payloads: WithStorageMeta<Payload>[]) {
252
+ const hashes = payloads.filter(isTransactionBoundWitnessWithStorageMeta).map(p => p._hash)
253
+ for (const hash of hashes) {
254
+ this._removablePendingTransactionHashes.add(hash)
255
+ }
256
+ }
257
+
228
258
  private async removeBundledTransactions(
229
259
  bundledPayloads: WithStorageMeta<PayloadBundle>[],
230
260
  priority: keyof typeof XyoPendingTransactionsService.MutexPriority,
@@ -240,18 +270,4 @@ export class XyoPendingTransactionsService extends BaseService<XyoPendingTransac
240
270
  }, XyoPendingTransactionsService.MutexPriority[priority])
241
271
  })
242
272
  }
243
-
244
- private removeFinalizedTransactions(payloads: WithStorageMeta<Payload>[]) {
245
- const finalizedTransactionHashes = payloads.filter(isTransactionBoundWitnessWithStorageMeta).map(p => p._hash)
246
- for (const hash of finalizedTransactionHashes) {
247
- this._removablePendingTransactionHashes.add(hash)
248
- }
249
- }
250
-
251
- private removeRejectedBundledTransactions(payloads: WithStorageMeta<Payload>[]) {
252
- const rejectedTransactionHashes = payloads.filter(isTransactionBoundWitnessWithStorageMeta).map(p => p._hash)
253
- for (const hash of rejectedTransactionHashes) {
254
- this._removablePendingTransactionHashes.add(hash)
255
- }
256
- }
257
273
  }
@@ -0,0 +1,14 @@
1
+ import { PayloadBuilder } from '@xyo-network/payload-builder'
2
+ import type { PayloadBundle, WithStorageMeta } from '@xyo-network/payload-model'
3
+ import type { HydratedTransactionWithStorageMeta } from '@xyo-network/xl1-protocol'
4
+ import { asOptionalTransactionBoundWitnessWithStorageMeta } from '@xyo-network/xl1-protocol'
5
+
6
+ export const bundledPayloadToHydratedTransaction = async (
7
+ payload: WithStorageMeta<PayloadBundle>,
8
+ ): Promise<HydratedTransactionWithStorageMeta | undefined> => {
9
+ const withStorageMeta = await PayloadBuilder.addStorageMeta(payload.payloads)
10
+ const tx = asOptionalTransactionBoundWitnessWithStorageMeta(withStorageMeta.find(p => p._hash === payload.root))
11
+ if (tx) {
12
+ return [tx, withStorageMeta.filter(p => p._hash !== payload.root)]
13
+ }
14
+ }
@@ -0,0 +1,23 @@
1
+ import type { Hash } from '@xylabs/hex'
2
+ import { PayloadBuilder } from '@xyo-network/payload-builder'
3
+ import type { PayloadBundle } from '@xyo-network/payload-model'
4
+ import { PayloadBundleSchema } from '@xyo-network/payload-model'
5
+ import type { HydratedTransaction, HydratedTransactionWithStorageMeta } from '@xyo-network/xl1-protocol'
6
+ import { flattenHydratedTransaction } from '@xyo-network/xl1-protocol-sdk'
7
+
8
+ export const hydratedTransactionToPayloadBundle = async (transaction: HydratedTransaction): Promise<PayloadBundle> => {
9
+ const root = await PayloadBuilder.hash(transaction[0])
10
+ return bundle(root, transaction)
11
+ }
12
+
13
+ export const hydratedTransactionWithHashStorageMetaToPayloadBundle = (transaction: HydratedTransactionWithStorageMeta): PayloadBundle => {
14
+ const root = transaction[0]._hash
15
+ return bundle(root, transaction)
16
+ }
17
+
18
+ const bundle = (root: Hash, transaction: HydratedTransaction | HydratedTransactionWithStorageMeta) => {
19
+ const payloads = flattenHydratedTransaction(transaction).flatMap(p => PayloadBuilder.omitStorageMeta(p))
20
+ return new PayloadBuilder<PayloadBundle>({ schema: PayloadBundleSchema })
21
+ .fields({ payloads, root })
22
+ .build()
23
+ }
@@ -19,8 +19,9 @@ import type {
19
19
  BaseServiceParams, EventingChainBlockNumberIterator, Intent,
20
20
  } from '@xyo-network/xl1-protocol'
21
21
  import {
22
+ asChainIndexingServiceStateWithStorageMeta,
22
23
  asOptionalBlockBoundWitness, asOptionalBlockBoundWitnessWithStorageMeta,
23
- asOptionalChainIndexingServiceStateWithStorageMeta, asOptionalChainStakeIntent, ChainIndexingServiceState, ChainIndexingServiceStateSchema, ChainStakeViewer,
24
+ asOptionalChainStakeIntent, ChainIndexingServiceState, ChainIndexingServiceStateSchema, ChainStakeViewer,
24
25
  isChainIndexingServiceState,
25
26
  StakeIntentService,
26
27
  } from '@xyo-network/xl1-protocol'
@@ -162,7 +163,7 @@ export class XyoStakeIntentService extends BaseService<XyoStakeIntentServicePara
162
163
  const opts: ArchivistNextOptions = { ...DEFAULT_FIND_FIRST_MATCHING_NEXT_OPTIONS }
163
164
  while (true) {
164
165
  const predicate = (p: WithStorageMeta<Payload>) => {
165
- const state = asOptionalChainIndexingServiceStateWithStorageMeta(p)
166
+ const state = asChainIndexingServiceStateWithStorageMeta(p)
166
167
  return state ? true : false
167
168
  }
168
169
  const state = await findFirstMatching(this.stakeIntentStateArchivist, predicate, opts)
@@ -1,119 +1,114 @@
1
- import { Base } from '@xylabs/base'
1
+ import { assertEx } from '@xylabs/assert'
2
2
  import type { Address } from '@xylabs/hex'
3
3
  import { toAddress } from '@xylabs/hex'
4
- import type { Promisable } from '@xylabs/promise'
4
+ import { toEthAddress } from '@xyo-network/chain-ethereum'
5
5
  import type { StakedXyoChain } from '@xyo-network/typechain'
6
6
  import { StakedXyoChain__factory as StakedXyoChainFactory } from '@xyo-network/typechain'
7
7
  import type { BaseServiceParams, ChainService } from '@xyo-network/xl1-protocol'
8
8
  import { getAddress } from 'ethers/address'
9
9
  import type { ContractRunner } from 'ethers/providers'
10
10
 
11
- export interface EvmChainServiceParams extends BaseServiceParams {
11
+ import { BaseService } from '../../BaseService.ts'
12
+
13
+ export type EvmChainServiceParams = BaseServiceParams<{
12
14
  contract: StakedXyoChain
13
15
  id: Address
14
16
  runner: ContractRunner
15
- }
17
+ }>
16
18
 
17
19
  /**
18
20
  * A class that represents a chain stake as backed by an EVM smart contract
19
21
  */
20
- export class EvmChainService extends Base<EvmChainServiceParams> implements ChainService {
21
- private _contract: StakedXyoChain
22
-
23
- protected constructor(params: EvmChainServiceParams) {
24
- super(params)
25
- this._contract = params.contract
22
+ export class EvmChainService extends BaseService<EvmChainServiceParams> implements ChainService {
23
+ get contract() {
24
+ if (this.params.contract === undefined) {
25
+ this.params.contract = StakedXyoChainFactory.connect(
26
+ toEthAddress(this.id),
27
+ this.params.runner,
28
+ ) as StakedXyoChain
29
+ }
30
+ return assertEx(this.params.contract)
26
31
  }
27
32
 
28
33
  get id(): Address {
29
- return this.params.id
34
+ return assertEx(this.params.id)
30
35
  }
31
36
 
32
37
  get runner(): ContractRunner {
33
- return this.params.runner
34
- }
35
-
36
- static create({
37
- id, runner, logger, traceProvider, meterProvider,
38
- }: Omit<EvmChainServiceParams, 'contract'>): Promisable<EvmChainService> {
39
- const contractAddress = getAddress(id)
40
- const contract: StakedXyoChain = StakedXyoChainFactory.connect(contractAddress, runner)
41
- return new this({
42
- id, contract, runner, logger, traceProvider, meterProvider,
43
- })
38
+ return assertEx(this.params.runner)
44
39
  }
45
40
 
46
41
  async active(): Promise<bigint> {
47
- return await this._contract.active()
42
+ return await this.contract.active()
48
43
  }
49
44
 
50
45
  async activeByAddressStaked(address: string): Promise<bigint> {
51
- return await this._contract.activeByAddressStaked(getAddress(address))
46
+ return await this.contract.activeByAddressStaked(getAddress(address))
52
47
  }
53
48
 
54
49
  async activeByStaker(address: string): Promise<bigint> {
55
- return await this._contract.activeByStaker(getAddress(address))
50
+ return await this.contract.activeByStaker(getAddress(address))
56
51
  }
57
52
 
58
53
  async addStake(staked: string, amount: bigint): Promise<boolean> {
59
- const result = await this._contract.addStake(getAddress(staked), amount)
54
+ const result = await this.contract.addStake(getAddress(staked), amount)
60
55
  await result.wait()
61
56
  return true
62
57
  }
63
58
 
64
59
  async chainId(): Promise<Address> {
65
- return toAddress(await this._contract.chainId())
60
+ return toAddress(await this.contract.chainId())
66
61
  }
67
62
 
68
63
  async forkedAtBlockNumber(): Promise<bigint> {
69
- return await this._contract.forkedAtBlockNumber()
64
+ return await this.contract.forkedAtBlockNumber()
70
65
  }
71
66
 
72
67
  async forkedAtHash(): Promise<bigint> {
73
- return await this._contract.forkedAtHash()
68
+ return await this.contract.forkedAtHash()
74
69
  }
75
70
 
76
71
  async forkedChainId(): Promise<Address> {
77
- return toAddress(await this._contract.forkedChainId())
72
+ return toAddress(await this.contract.forkedChainId())
78
73
  }
79
74
 
80
75
  async minWithdrawalBlocks(): Promise<bigint> {
81
- return await this._contract.minWithdrawalBlocks()
76
+ return await this.contract.minWithdrawalBlocks()
82
77
  }
83
78
 
84
79
  async pending(): Promise<bigint> {
85
- return await this._contract.pending()
80
+ return await this.contract.pending()
86
81
  }
87
82
 
88
83
  async pendingByStaker(staker: string): Promise<bigint> {
89
- return await this._contract.pendingByStaker(getAddress(staker))
84
+ return await this.contract.pendingByStaker(getAddress(staker))
90
85
  }
91
86
 
92
87
  async removeStake(slot: bigint): Promise<boolean> {
93
- const result = await this._contract.removeStake(slot)
88
+ const result = await this.contract.removeStake(slot)
94
89
  await result.wait()
95
90
  return true
96
91
  }
97
92
 
98
93
  async rewardsContract(): Promise<string> {
99
- return await this._contract.rewardsContract()
94
+ return await this.contract.rewardsContract()
100
95
  }
101
96
 
102
97
  async stakingTokenAddress(): Promise<string> {
103
- return await this._contract.stakingTokenAddress()
98
+ return await this.contract.stakingTokenAddress()
104
99
  }
105
100
 
106
101
  async withdrawStake(slot: bigint): Promise<boolean> {
107
- const result = await this._contract.withdrawStake(slot)
102
+ const result = await this.contract.withdrawStake(slot)
108
103
  await result.wait()
109
104
  return true
110
105
  }
111
106
 
112
107
  async withdrawn(): Promise<bigint> {
113
- return await this._contract.withdrawn()
108
+ return await this.contract.withdrawn()
114
109
  }
115
110
 
116
111
  async withdrawnByStaker(staker: string): Promise<bigint> {
117
- return await this._contract.withdrawnByStaker(getAddress(staker))
112
+ return await this.contract.withdrawnByStaker(getAddress(staker))
118
113
  }
119
114
  }
package/src/index.ts CHANGED
@@ -1,11 +1,10 @@
1
1
  export * from './AccountBalance/index.ts'
2
- export * from './BaseEthProvider.ts'
3
2
  export * from './BaseService.ts'
4
3
  export * from './BlockProducer/index.ts'
5
4
  export * from './BlockReward/index.ts'
5
+ export * from './ChainBlockNumberIteration/index.ts'
6
6
  export * from './ChainValidator/index.ts'
7
7
  export * from './Election/index.ts'
8
8
  export * from './PendingTransactions/index.ts'
9
9
  export * from './StakeIntent/index.ts'
10
10
  export * from './Staker/index.ts'
11
- export * from './XyoChainBlockNumberIterator.ts'
@@ -1,56 +0,0 @@
1
- import type { Address, BlockAPI, BlockNumberOrTag, CompileResultAPI, EthExecutionAPI, FeeHistoryResultAPI, Filter, FilterResultsAPI, HexString, HexString8Bytes, HexString32Bytes, HexString256Bytes, HexStringBytes, SignedTransactionInfoAPI, SyncingStatusAPI, TransactionCallAPI, TransactionInfoAPI, TransactionReceiptAPI, TransactionWithSenderAPI, Uint, Uint256 } from 'web3-types';
2
- export declare class BaseEthProvider implements EthExecutionAPI {
3
- eth_accounts(): Address[];
4
- eth_blockNumber(): Uint;
5
- eth_call(_transaction: TransactionCallAPI, _blockNumber: BlockNumberOrTag): HexStringBytes;
6
- eth_clearSubscriptions(_keepSyncing?: boolean): void;
7
- eth_coinbase(): Address;
8
- eth_compileLLL(_code: string): HexStringBytes;
9
- eth_compileSerpent(_code: string): HexStringBytes;
10
- eth_compileSolidity(_code: string): CompileResultAPI;
11
- eth_estimateGas(_transaction: Partial<TransactionWithSenderAPI>, _blockNumber: BlockNumberOrTag): Uint;
12
- eth_feeHistory(_blockCount: Uint, _newestBlock: BlockNumberOrTag, _rewardPercentiles: number[]): FeeHistoryResultAPI;
13
- eth_gasPrice(): Uint;
14
- eth_getBalance(_address: Address, _blockNumber: BlockNumberOrTag): Uint;
15
- eth_getBlockByHash(_blockHash: HexString32Bytes, _hydrated: boolean): BlockAPI;
16
- eth_getBlockByNumber(_blockNumber: BlockNumberOrTag, _hydrated: boolean): BlockAPI;
17
- eth_getBlockTransactionCountByHash(_blockHash: HexString32Bytes): Uint;
18
- eth_getBlockTransactionCountByNumber(_blockNumber: BlockNumberOrTag): Uint;
19
- eth_getCode(_address: Address, _blockNumber: BlockNumberOrTag): HexStringBytes;
20
- eth_getCompilers(): string[];
21
- eth_getFilterChanges(_filterIdentifier: Uint): FilterResultsAPI;
22
- eth_getFilterLogs(_filterIdentifier: Uint): FilterResultsAPI;
23
- eth_getLogs(_filter: Filter): FilterResultsAPI;
24
- eth_getStorageAt(_address: Address, _storageSlot: Uint256, _blockNumber: BlockNumberOrTag): HexStringBytes;
25
- eth_getTransactionByBlockHashAndIndex(_blockHash: HexString32Bytes, _transactionIndex: Uint): TransactionInfoAPI | undefined;
26
- eth_getTransactionByBlockNumberAndIndex(_blockNumber: BlockNumberOrTag, _transactionIndex: Uint): TransactionInfoAPI | undefined;
27
- eth_getTransactionByHash(_transactionHash: HexString32Bytes): TransactionInfoAPI | undefined;
28
- eth_getTransactionCount(_address: Address, _blockNumber: BlockNumberOrTag): Uint;
29
- eth_getTransactionReceipt(_transactionHash: HexString32Bytes): TransactionReceiptAPI | undefined;
30
- eth_getUncleByBlockHashAndIndex(_blockHash: HexString32Bytes, _uncleIndex: Uint): BlockAPI;
31
- eth_getUncleByBlockNumberAndIndex(_blockNumber: BlockNumberOrTag, _uncleIndex: Uint): BlockAPI;
32
- eth_getUncleCountByBlockHash(_blockHash: HexString32Bytes): Uint;
33
- eth_getUncleCountByBlockNumber(_blockNumber: BlockNumberOrTag): Uint;
34
- eth_getWork(): [HexString32Bytes, HexString32Bytes, HexString32Bytes];
35
- eth_hashrate(): Uint;
36
- eth_maxPriorityFeePerGas(): Uint;
37
- eth_mining(): boolean;
38
- eth_newBlockFilter(): Uint;
39
- eth_newFilter(_filter: Filter): Uint;
40
- eth_newPendingTransactionFilter(): Uint;
41
- eth_protocolVersion(): string;
42
- eth_sendRawTransaction(_transaction: HexStringBytes): HexString32Bytes;
43
- eth_sendTransaction(_transaction: TransactionWithSenderAPI | Partial<TransactionWithSenderAPI>): HexString32Bytes;
44
- eth_sign(_address: Address, _message: HexStringBytes): HexString256Bytes;
45
- eth_signTransaction(_transaction: TransactionWithSenderAPI | Partial<TransactionWithSenderAPI>): HexStringBytes | SignedTransactionInfoAPI;
46
- eth_submitHashrate(_hashRate: HexString32Bytes, _id: HexString32Bytes): boolean;
47
- eth_submitWork(_nonce: HexString8Bytes, _hash: HexString32Bytes, _digest: HexString32Bytes): boolean;
48
- eth_subscribe(..._params: ['newHeads'] | ['newPendingTransactions'] | ['syncing'] | ['logs', {
49
- address?: HexString;
50
- topics?: HexString[];
51
- }]): HexString;
52
- eth_syncing(): SyncingStatusAPI;
53
- eth_uninstallFilter(_filterIdentifier: Uint): boolean;
54
- eth_unsubscribe(_subscriptionId: HexString): HexString;
55
- }
56
- //# sourceMappingURL=BaseEthProvider.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BaseEthProvider.d.ts","sourceRoot":"","sources":["../../src/BaseEthProvider.ts"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"XyoChainBlockNumberIterator.d.ts","sourceRoot":"","sources":["../../src/XyoChainBlockNumberIterator.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAE5C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAA;AAErE,OAAO,KAAK,EACV,iBAAiB,EAAE,mBAAmB,EACtC,sBAAsB,EACtB,gCAAgC,EAChC,sBAAsB,EACvB,MAAM,2BAA2B,CAAA;AAKlC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAEpC,qBAAa,2BAA4B,SAAQ,WAAW,CAAC,UAAU,EAAE,sBAAsB,CAAE,YAAW,gCAAgC;IAC1I,SAAS,CAAC,oBAAoB,+CAA2D;IACzF,SAAS,CAAC,eAAe,EAAE,iBAAiB,CAAA;IAC5C,SAAS,CAAC,iBAAiB,EAAE,mBAAmB,CAAA;IAChD,SAAS,CAAC,KAAK,EAAE,iBAAiB,CAAA;IAElC,SAAS,aAAa,MAAM,EAAE,sBAAsB;IAQpD,IAAI,SAAS,IAAI,iBAAiB,CAAgC;IAElE,IAAI,mBAAmB,IAAI,mBAAmB,CAAkC;WAEnE,MAAM,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,2BAA2B,CAAC;IAKnF,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAwB9C,IAAI,IAAI,OAAO,CAAC,iBAAiB,CAAC;IAIlC,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC;IAQ3D,QAAQ,CAAC,KAAK,GAAE,MAAM,GAAG,SAAqB,EAAE,KAAK,GAAE,MAAU,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAkBhG,UAAU,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;CAMzD"}