@xyo-network/chain-sdk 4.0.5 → 4.1.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 (76) hide show
  1. package/dist/browser/modules/ethereum/block/blockRangeChunks.d.ts +8 -0
  2. package/dist/browser/modules/ethereum/block/blockRangeChunks.d.ts.map +1 -0
  3. package/dist/browser/modules/ethereum/block/estimateBlockNumberAt.d.ts +17 -0
  4. package/dist/browser/modules/ethereum/block/estimateBlockNumberAt.d.ts.map +1 -0
  5. package/dist/browser/modules/ethereum/block/index.d.ts +2 -0
  6. package/dist/browser/modules/ethereum/block/index.d.ts.map +1 -1
  7. package/dist/browser/modules/ethereum/drivers/EvmStakeEventsViewer.d.ts +28 -1
  8. package/dist/browser/modules/ethereum/drivers/EvmStakeEventsViewer.d.ts.map +1 -1
  9. package/dist/browser/modules/ethereum/drivers/EvmStakeViewer.d.ts +1 -1
  10. package/dist/browser/modules/ethereum/drivers/EvmStakeViewer.d.ts.map +1 -1
  11. package/dist/browser/modules/ethereum/providers/AbstractEvmProvider.d.ts +4 -1
  12. package/dist/browser/modules/ethereum/providers/AbstractEvmProvider.d.ts.map +1 -1
  13. package/dist/browser/modules/ethereum/providers/AbstractEvmViewer.d.ts +5 -1
  14. package/dist/browser/modules/ethereum/providers/AbstractEvmViewer.d.ts.map +1 -1
  15. package/dist/browser/modules/ethereum/providers/EvmChainContractViewer.d.ts +1 -2
  16. package/dist/browser/modules/ethereum/providers/EvmChainContractViewer.d.ts.map +1 -1
  17. package/dist/browser/modules/ethereum/providers/EvmStakeTotalsViewer.d.ts +1 -1
  18. package/dist/browser/modules/ethereum/providers/EvmStakeTotalsViewer.d.ts.map +1 -1
  19. package/dist/browser/modules/ethereum/rpc/isRpcRateLimitError.d.ts +6 -0
  20. package/dist/browser/modules/ethereum/rpc/isRpcRateLimitError.d.ts.map +1 -0
  21. package/dist/browser/modules/ethereum/rpc/withRpcRateLimitBackoff.d.ts +19 -0
  22. package/dist/browser/modules/ethereum/rpc/withRpcRateLimitBackoff.d.ts.map +1 -0
  23. package/dist/browser/modules/services/NetworkStakeStepReward/BaseNetworkStakeStepRewardService.d.ts +0 -2
  24. package/dist/browser/modules/services/NetworkStakeStepReward/BaseNetworkStakeStepRewardService.d.ts.map +1 -1
  25. package/dist/neutral/ethereum.mjs +290 -80
  26. package/dist/neutral/ethereum.mjs.map +4 -4
  27. package/dist/neutral/modules/ethereum/block/blockRangeChunks.d.ts +8 -0
  28. package/dist/neutral/modules/ethereum/block/blockRangeChunks.d.ts.map +1 -0
  29. package/dist/neutral/modules/ethereum/block/estimateBlockNumberAt.d.ts +17 -0
  30. package/dist/neutral/modules/ethereum/block/estimateBlockNumberAt.d.ts.map +1 -0
  31. package/dist/neutral/modules/ethereum/block/index.d.ts +2 -0
  32. package/dist/neutral/modules/ethereum/block/index.d.ts.map +1 -1
  33. package/dist/neutral/modules/ethereum/drivers/EvmStakeEventsViewer.d.ts +28 -1
  34. package/dist/neutral/modules/ethereum/drivers/EvmStakeEventsViewer.d.ts.map +1 -1
  35. package/dist/neutral/modules/ethereum/drivers/EvmStakeViewer.d.ts +1 -1
  36. package/dist/neutral/modules/ethereum/drivers/EvmStakeViewer.d.ts.map +1 -1
  37. package/dist/neutral/modules/ethereum/providers/AbstractEvmProvider.d.ts +4 -1
  38. package/dist/neutral/modules/ethereum/providers/AbstractEvmProvider.d.ts.map +1 -1
  39. package/dist/neutral/modules/ethereum/providers/AbstractEvmViewer.d.ts +5 -1
  40. package/dist/neutral/modules/ethereum/providers/AbstractEvmViewer.d.ts.map +1 -1
  41. package/dist/neutral/modules/ethereum/providers/EvmChainContractViewer.d.ts +1 -2
  42. package/dist/neutral/modules/ethereum/providers/EvmChainContractViewer.d.ts.map +1 -1
  43. package/dist/neutral/modules/ethereum/providers/EvmStakeTotalsViewer.d.ts +1 -1
  44. package/dist/neutral/modules/ethereum/providers/EvmStakeTotalsViewer.d.ts.map +1 -1
  45. package/dist/neutral/modules/ethereum/rpc/isRpcRateLimitError.d.ts +6 -0
  46. package/dist/neutral/modules/ethereum/rpc/isRpcRateLimitError.d.ts.map +1 -0
  47. package/dist/neutral/modules/ethereum/rpc/withRpcRateLimitBackoff.d.ts +19 -0
  48. package/dist/neutral/modules/ethereum/rpc/withRpcRateLimitBackoff.d.ts.map +1 -0
  49. package/dist/neutral/modules/services/NetworkStakeStepReward/BaseNetworkStakeStepRewardService.d.ts +0 -2
  50. package/dist/neutral/modules/services/NetworkStakeStepReward/BaseNetworkStakeStepRewardService.d.ts.map +1 -1
  51. package/dist/neutral/services.mjs.map +2 -2
  52. package/dist/node/modules/ethereum/block/blockRangeChunks.d.ts +8 -0
  53. package/dist/node/modules/ethereum/block/blockRangeChunks.d.ts.map +1 -0
  54. package/dist/node/modules/ethereum/block/estimateBlockNumberAt.d.ts +17 -0
  55. package/dist/node/modules/ethereum/block/estimateBlockNumberAt.d.ts.map +1 -0
  56. package/dist/node/modules/ethereum/block/index.d.ts +2 -0
  57. package/dist/node/modules/ethereum/block/index.d.ts.map +1 -1
  58. package/dist/node/modules/ethereum/drivers/EvmStakeEventsViewer.d.ts +28 -1
  59. package/dist/node/modules/ethereum/drivers/EvmStakeEventsViewer.d.ts.map +1 -1
  60. package/dist/node/modules/ethereum/drivers/EvmStakeViewer.d.ts +1 -1
  61. package/dist/node/modules/ethereum/drivers/EvmStakeViewer.d.ts.map +1 -1
  62. package/dist/node/modules/ethereum/providers/AbstractEvmProvider.d.ts +4 -1
  63. package/dist/node/modules/ethereum/providers/AbstractEvmProvider.d.ts.map +1 -1
  64. package/dist/node/modules/ethereum/providers/AbstractEvmViewer.d.ts +5 -1
  65. package/dist/node/modules/ethereum/providers/AbstractEvmViewer.d.ts.map +1 -1
  66. package/dist/node/modules/ethereum/providers/EvmChainContractViewer.d.ts +1 -2
  67. package/dist/node/modules/ethereum/providers/EvmChainContractViewer.d.ts.map +1 -1
  68. package/dist/node/modules/ethereum/providers/EvmStakeTotalsViewer.d.ts +1 -1
  69. package/dist/node/modules/ethereum/providers/EvmStakeTotalsViewer.d.ts.map +1 -1
  70. package/dist/node/modules/ethereum/rpc/isRpcRateLimitError.d.ts +6 -0
  71. package/dist/node/modules/ethereum/rpc/isRpcRateLimitError.d.ts.map +1 -0
  72. package/dist/node/modules/ethereum/rpc/withRpcRateLimitBackoff.d.ts +19 -0
  73. package/dist/node/modules/ethereum/rpc/withRpcRateLimitBackoff.d.ts.map +1 -0
  74. package/dist/node/modules/services/NetworkStakeStepReward/BaseNetworkStakeStepRewardService.d.ts +0 -2
  75. package/dist/node/modules/services/NetworkStakeStepReward/BaseNetworkStakeStepRewardService.d.ts.map +1 -1
  76. package/package.json +18 -40
@@ -162,6 +162,42 @@ var BaseEthProvider = class {
162
162
  }
163
163
  };
164
164
 
165
+ // src/modules/ethereum/block/blockRangeChunks.ts
166
+ function blockRangeChunks(fromBlock, toBlock, chunkSize) {
167
+ if (!Number.isInteger(chunkSize) || chunkSize < 1) {
168
+ throw new TypeError(`chunkSize must be an integer >= 1, got ${chunkSize}`);
169
+ }
170
+ if (!Number.isFinite(fromBlock) || !Number.isFinite(toBlock)) {
171
+ throw new TypeError(`fromBlock and toBlock must be finite numbers, got [${fromBlock}, ${toBlock}]`);
172
+ }
173
+ if (fromBlock > toBlock) {
174
+ return [];
175
+ }
176
+ const chunks = [];
177
+ for (let start = fromBlock; start <= toBlock; start += chunkSize) {
178
+ const end = Math.min(start + chunkSize - 1, toBlock);
179
+ chunks.push([start, end]);
180
+ }
181
+ return chunks;
182
+ }
183
+
184
+ // src/modules/ethereum/block/estimateBlockNumberAt.ts
185
+ import { assertEx } from "@ariestools/sdk";
186
+ var DEFAULT_EVM_BLOCK_TIME_SEC = 12;
187
+ var DEFAULT_ESTIMATE_BLOCK_DATE = new Date(Date.UTC(2025, 5, 1));
188
+ function estimateBlockNumberFromHead(headNumber, headTimestampSec, targetDate = DEFAULT_ESTIMATE_BLOCK_DATE, avgBlockTimeSec = DEFAULT_EVM_BLOCK_TIME_SEC) {
189
+ const targetTimestampSec = Math.floor(targetDate.getTime() / 1e3);
190
+ if (targetTimestampSec >= headTimestampSec) {
191
+ return headNumber;
192
+ }
193
+ const blocksBack = Math.ceil((headTimestampSec - targetTimestampSec) / avgBlockTimeSec);
194
+ return Math.max(0, headNumber - blocksBack);
195
+ }
196
+ async function estimateBlockNumberAt(provider, targetDate = DEFAULT_ESTIMATE_BLOCK_DATE, avgBlockTimeSec = DEFAULT_EVM_BLOCK_TIME_SEC) {
197
+ const head = assertEx(await provider.getBlock("latest"), () => new Error("Failed to get latest eth block"));
198
+ return estimateBlockNumberFromHead(head.number, head.timestamp, targetDate, avgBlockTimeSec);
199
+ }
200
+
165
201
  // src/modules/ethereum/block/rate/blockRate.ts
166
202
  import { isDefined, isFalsy } from "@ariestools/sdk";
167
203
  import {
@@ -210,7 +246,7 @@ var calculateEthBlockRate = async (provider, range, timeUnit) => {
210
246
 
211
247
  // src/modules/ethereum/block/rate/timeRate.ts
212
248
  import {
213
- assertEx,
249
+ assertEx as assertEx2,
214
250
  isDefined as isDefined2,
215
251
  isDefinedNotNull
216
252
  } from "@ariestools/sdk";
@@ -222,12 +258,12 @@ import {
222
258
  var DEFAULT_TOLERANCE_MS = 3e4;
223
259
  var DEFAULT_MAX_ATTEMPTS = 20;
224
260
  var calculateEthTimeRate = async (provider, timeConfig, startBlockNumber, timeUnit, toleranceMs = DEFAULT_TOLERANCE_MS, maxAttempts = DEFAULT_MAX_ATTEMPTS) => {
225
- assertEx(Object.keys(timeConfig ?? {}).length === 1, () => "Only one time unit should be specified in timeConfig");
261
+ assertEx2(Object.keys(timeConfig ?? {}).length === 1, () => "Only one time unit should be specified in timeConfig");
226
262
  const startBlock = isDefinedNotNull(startBlockNumber) ? await provider.getBlock(BigInt(startBlockNumber)) : null;
227
- assertEx(isDefinedNotNull(startBlockNumber) && isDefinedNotNull(startBlock), () => "Start block could not be resolved");
228
- const resolvedStartBlock = isDefinedNotNull(startBlock) ? startBlock : assertEx(await provider.getBlock("latest"));
263
+ assertEx2(isDefinedNotNull(startBlockNumber) && isDefinedNotNull(startBlock), () => "Start block could not be resolved");
264
+ const resolvedStartBlock = isDefinedNotNull(startBlock) ? startBlock : assertEx2(await provider.getBlock("latest"));
229
265
  const timeInMilliseconds = getTimeConfigInMilliseconds(timeConfig);
230
- assertEx(timeInMilliseconds > 0, () => "Time duration must be greater than zero");
266
+ assertEx2(timeInMilliseconds > 0, () => "Time duration must be greater than zero");
231
267
  const blocksPerMillisecondRate = 1 / (12 * 1e3);
232
268
  const initialBlocksInDuration = Math.floor(blocksPerMillisecondRate * timeInMilliseconds);
233
269
  const endBlockNumber = await findEndBlockRecursive(
@@ -246,14 +282,14 @@ var calculateEthTimeRate = async (provider, timeConfig, startBlockNumber, timeUn
246
282
  };
247
283
  var findEndBlockRecursive = async (provider, startBlock, targetTimeMs, estimatedBlocksBack, toleranceMs, attemptsRemaining) => {
248
284
  console.log(`Attempts remaining: ${attemptsRemaining}, Estimated blocks back: ${estimatedBlocksBack}`);
249
- assertEx(attemptsRemaining > 0, () => "Maximum attempts reached while searching for end block");
285
+ assertEx2(attemptsRemaining > 0, () => "Maximum attempts reached while searching for end block");
250
286
  const startBlockEpoch = startBlock.timestamp;
251
287
  const estimatedEndBlockNumber = startBlock.number - estimatedBlocksBack;
252
288
  if (estimatedEndBlockNumber < 0) {
253
289
  throw new Error("Estimated end block number is less than zero");
254
290
  }
255
291
  const endBlock = await provider.getBlock(estimatedEndBlockNumber);
256
- const resolvedEndBlock = assertEx(
292
+ const resolvedEndBlock = assertEx2(
257
293
  isDefined2(endBlock) ? endBlock : void 0,
258
294
  () => `Could not retrieve block ${estimatedEndBlockNumber} for time rate calculation`
259
295
  );
@@ -296,7 +332,7 @@ import { createGenesisBlock } from "#protocol";
296
332
  // src/modules/ethereum/createChainContract.ts
297
333
  import {
298
334
  asAddress,
299
- assertEx as assertEx2,
335
+ assertEx as assertEx3,
300
336
  ETH_ZERO_ADDRESS,
301
337
  hexToBigInt,
302
338
  toEthAddress
@@ -324,7 +360,7 @@ var createChainContract = async (signer, stakingTokenAddress, genesisBlockHash,
324
360
  );
325
361
  await deployResponse.waitForDeployment();
326
362
  const xyoChainContractAddress = await deployResponse.getAddress();
327
- return assertEx2(asAddress(xyoChainContractAddress), () => "Invalid staking contract address");
363
+ return assertEx3(asAddress(xyoChainContractAddress), () => "Invalid staking contract address");
328
364
  } catch (ex) {
329
365
  console.log(ex);
330
366
  throw ex;
@@ -334,7 +370,7 @@ var createChainContract = async (signer, stakingTokenAddress, genesisBlockHash,
334
370
  // src/modules/ethereum/createChainRewardsContract.ts
335
371
  import {
336
372
  asAddress as asAddress2,
337
- assertEx as assertEx3,
373
+ assertEx as assertEx4,
338
374
  toFixedPoint
339
375
  } from "@ariestools/sdk";
340
376
  import { XyoChainRewards__factory as XyoChainRewardsFactory } from "@xyo-network/typechain";
@@ -361,7 +397,7 @@ var createChainRewardsContract = async (signer, genesisReward = 0n, gas = gasCon
361
397
  );
362
398
  await deployResponse.waitForDeployment();
363
399
  const xyoChainRewardsAddress = await deployResponse.getAddress();
364
- return assertEx3(asAddress2(xyoChainRewardsAddress), () => "Invalid rewards contract address");
400
+ return assertEx4(asAddress2(xyoChainRewardsAddress), () => "Invalid rewards contract address");
365
401
  } catch (ex) {
366
402
  console.log(ex);
367
403
  throw ex;
@@ -371,7 +407,7 @@ var createChainRewardsContract = async (signer, genesisReward = 0n, gas = gasCon
371
407
  // src/modules/ethereum/nextContractAddress.ts
372
408
  import {
373
409
  asAddress as asAddress3,
374
- assertEx as assertEx4,
410
+ assertEx as assertEx5,
375
411
  toEthAddress as toEthAddress2
376
412
  } from "@ariestools/sdk";
377
413
  import { getCreateAddress } from "ethers/address";
@@ -379,11 +415,11 @@ var nextContractAddressForAddress = async (address, provider) => {
379
415
  const deployerAddress = toEthAddress2(address);
380
416
  const nonce = await provider.getTransactionCount(deployerAddress);
381
417
  const contractAddress = getCreateAddress({ from: deployerAddress, nonce });
382
- return assertEx4(asAddress3(contractAddress), () => "Unable to convert contract address to address");
418
+ return assertEx5(asAddress3(contractAddress), () => "Unable to convert contract address to address");
383
419
  };
384
420
  var nextContractAddress = async (signer) => {
385
- const provider = assertEx4(signer.provider, () => "Unable to obtain provider from signer");
386
- const address = assertEx4(asAddress3(await signer.getAddress()), () => "Unable to obtain address from signer");
421
+ const provider = assertEx5(signer.provider, () => "Unable to obtain provider from signer");
422
+ const address = assertEx5(asAddress3(await signer.getAddress()), () => "Unable to obtain address from signer");
387
423
  return await nextContractAddressForAddress(address, provider);
388
424
  };
389
425
 
@@ -414,7 +450,7 @@ async function createChain(signer, stakingTokenAddress, initialBlockProducer, re
414
450
 
415
451
  // src/modules/ethereum/drivers/EvmStakeEventsViewer.ts
416
452
  import {
417
- assertEx as assertEx7,
453
+ assertEx as assertEx10,
418
454
  exists,
419
455
  isDefined as isDefined3,
420
456
  toAddress as toAddress3,
@@ -425,36 +461,58 @@ import {
425
461
  } from "@xyo-network/typechain";
426
462
  import {
427
463
  creatableProvider as creatableProvider4,
464
+ EvmChainViewerMoniker as EvmChainViewerMoniker4,
428
465
  StakeEventsViewerMoniker
429
466
  } from "@xyo-network/xl1-sdk";
430
467
  import { asAttoXL1 } from "@xyo-network/xl1-sdk";
431
468
 
432
469
  // src/modules/ethereum/providers/AbstractEvmProvider.ts
433
- import { toEthAddress as toEthAddress4 } from "@ariestools/sdk";
470
+ import {
471
+ assertEx as assertEx6,
472
+ toEthAddress as toEthAddress4
473
+ } from "@ariestools/sdk";
434
474
  import { AbstractCreatableProvider } from "@xyo-network/xl1-sdk";
435
475
  var AbstractEvmProvider = class extends AbstractCreatableProvider {
436
476
  _contract;
477
+ _address;
478
+ get address() {
479
+ return assertEx6(this._address, () => "EVM contract address not initialized");
480
+ }
437
481
  get contract() {
438
482
  return this._contract;
439
483
  }
440
484
  async createHandler() {
441
485
  await super.createHandler();
442
- this._contract = this.connectContract(toEthAddress4(this.params.address));
486
+ this._address = this.params.address ?? toEthAddress4(assertEx6(this.config?.chain?.id, () => "EVM provider requires an address param or config.chain.id"));
487
+ this._contract = this.connectContract(this._address);
443
488
  }
444
489
  };
445
490
 
446
491
  // src/modules/ethereum/providers/AbstractEvmRunner.ts
447
- import { assertEx as assertEx5 } from "@ariestools/sdk";
492
+ import { assertEx as assertEx8 } from "@ariestools/sdk";
448
493
 
449
494
  // src/modules/ethereum/providers/AbstractEvmViewer.ts
495
+ import { assertEx as assertEx7 } from "@ariestools/sdk";
496
+ import { EvmChainViewerMoniker } from "@xyo-network/xl1-sdk";
450
497
  var AbstractEvmViewer = class extends AbstractEvmProvider {
498
+ _provider;
499
+ get provider() {
500
+ return assertEx7(this.params.provider ?? this._provider, () => "EVM provider not initialized");
501
+ }
502
+ async createHandler() {
503
+ if (this.params.provider === void 0) {
504
+ const evmChainViewer = await this.locateAndCreate(EvmChainViewerMoniker);
505
+ this._provider = await evmChainViewer.provider();
506
+ }
507
+ await super.createHandler();
508
+ }
451
509
  };
452
510
 
453
511
  // src/modules/ethereum/providers/AbstractEvmRunner.ts
454
512
  var AbstractEvmRunner = class extends AbstractEvmViewer {
455
513
  static async paramsHandler(params) {
456
- const runner = assertEx5(params?.runner, () => new Error("No runner defined"));
457
- const provider = assertEx5(runner.provider, () => new Error("Runner must have a provider defined"));
514
+ const runner = assertEx8(params?.runner, () => new Error("No runner defined"));
515
+ const provider = assertEx8(runner.provider, () => new Error("Runner must have a provider defined"));
458
516
  return { ...await super.paramsHandler({ ...params, provider }), runner };
459
517
  }
460
518
  };
@@ -462,7 +520,7 @@ var AbstractEvmRunner = class extends AbstractEvmViewer {
462
520
  // src/modules/ethereum/providers/EvmChainContractViewer.ts
463
521
  import {
464
522
  asHash,
465
- assertEx as assertEx6,
523
+ assertEx as assertEx9,
466
524
  toAddress as toAddress2,
467
525
  toEthAddress as toEthAddress5,
468
526
  toHex
@@ -471,6 +529,7 @@ import { IStakedXyoChain__factory } from "@xyo-network/typechain";
471
529
  import {
472
530
  ChainContractViewerMoniker,
473
531
  creatableProvider,
532
+ EvmChainViewerMoniker as EvmChainViewerMoniker2,
474
533
  toXL1BlockNumber,
475
534
  withContextCacheResponse
476
535
  } from "@xyo-network/xl1-sdk";
@@ -483,11 +542,8 @@ var EvmChainContractViewer = class extends AbstractEvmViewer {
483
542
  _minWithdrawalBlocks;
484
543
  _rewardsContract;
485
544
  _stakingTokenAddress;
486
- get address() {
487
- return this.params.address;
488
- }
489
545
  chainId() {
490
- return toHex(this.params.address, { prefix: false });
546
+ return toHex(this.address, { prefix: false });
491
547
  }
492
548
  async chainIdAtBlockNumber(blockNumber) {
493
549
  return await withContextCacheResponse(this.context, "chainIdAtBlockNumber", String(blockNumber), async () => {
@@ -495,7 +551,7 @@ var EvmChainContractViewer = class extends AbstractEvmViewer {
495
551
  let contractViewer = this;
496
552
  let forkedAtBlockNumber = await contractViewer.forkedAtBlockNumber();
497
553
  while (forkedAtBlockNumber !== null && blockNumber <= forkedAtBlockNumber) {
498
- contractViewer = assertEx6(await contractViewer.forkedChainContractViewer(), () => "Forked chain contract viewer is undefined");
554
+ contractViewer = assertEx9(await contractViewer.forkedChainContractViewer(), () => "Forked chain contract viewer is undefined");
499
555
  forkedAtBlockNumber = await contractViewer.forkedAtBlockNumber();
500
556
  chainId = await contractViewer.chainId();
501
557
  }
@@ -520,7 +576,11 @@ var EvmChainContractViewer = class extends AbstractEvmViewer {
520
576
  async forkedChainContractViewer() {
521
577
  this._forkedChainContractViewer = this._forkedChainContractViewer ?? (async () => {
522
578
  const address = await this.forkedChainId();
523
- return EvmChainContractViewer.create({ ...this.params, address: toEthAddress5(address) });
579
+ return EvmChainContractViewer.create({
580
+ ...this.params,
581
+ address: toEthAddress5(address),
582
+ provider: this.provider
583
+ });
524
584
  })();
525
585
  return await this._forkedChainContractViewer;
526
586
  }
@@ -547,12 +607,12 @@ var EvmChainContractViewer = class extends AbstractEvmViewer {
547
607
  return await this._stakingTokenAddress;
548
608
  }
549
609
  connectContract(address) {
550
- return IStakedXyoChain__factory.connect(address, this.params.provider);
610
+ return IStakedXyoChain__factory.connect(address, this.provider);
551
611
  }
552
612
  };
553
613
  __publicField(EvmChainContractViewer, "connectionTypes", ["evm-rpc"]);
554
614
  __publicField(EvmChainContractViewer, "defaultMoniker", ChainContractViewerMoniker);
555
- __publicField(EvmChainContractViewer, "dependencies", []);
615
+ __publicField(EvmChainContractViewer, "dependencies", [EvmChainViewerMoniker2]);
556
616
  __publicField(EvmChainContractViewer, "monikers", [ChainContractViewerMoniker]);
557
617
  __publicField(EvmChainContractViewer, "surface", "node");
558
618
  EvmChainContractViewer = __decorateClass([
@@ -602,6 +662,7 @@ import { toEthAddress as toEthAddress7 } from "@ariestools/sdk";
602
662
  import { IStakedXyoChain__factory as IStakedXyoChain__factory3 } from "@xyo-network/typechain";
603
663
  import {
604
664
  creatableProvider as creatableProvider3,
665
+ EvmChainViewerMoniker as EvmChainViewerMoniker3,
605
666
  StakeTotalsViewerMoniker
606
667
  } from "@xyo-network/xl1-sdk";
607
668
  import { getAddress as getAddress2 } from "ethers/address";
@@ -629,18 +690,105 @@ var EvmStakeTotalsViewer = class extends AbstractEvmViewer {
629
690
  return await this.contract.withdrawnByStaker(getAddress2(staker));
630
691
  }
631
692
  connectContract(address) {
632
- return IStakedXyoChain__factory3.connect(address, this.params.provider);
693
+ return IStakedXyoChain__factory3.connect(address, this.provider);
633
694
  }
634
695
  };
635
696
  __publicField(EvmStakeTotalsViewer, "connectionTypes", ["evm-rpc"]);
636
697
  __publicField(EvmStakeTotalsViewer, "defaultMoniker", StakeTotalsViewerMoniker);
637
- __publicField(EvmStakeTotalsViewer, "dependencies", []);
698
+ __publicField(EvmStakeTotalsViewer, "dependencies", [EvmChainViewerMoniker3]);
638
699
  __publicField(EvmStakeTotalsViewer, "monikers", [StakeTotalsViewerMoniker]);
639
700
  __publicField(EvmStakeTotalsViewer, "surface", "node");
640
701
  EvmStakeTotalsViewer = __decorateClass([
641
702
  creatableProvider3()
642
703
  ], EvmStakeTotalsViewer);
643
704
 
705
+ // src/modules/ethereum/rpc/withRpcRateLimitBackoff.ts
706
+ import { delay } from "@ariestools/sdk";
707
+
708
+ // src/modules/ethereum/rpc/isRpcRateLimitError.ts
709
+ function isRpcRateLimitError(error) {
710
+ const seen = /* @__PURE__ */ new Set();
711
+ const queue = [error];
712
+ while (queue.length > 0) {
713
+ const current = queue.pop();
714
+ if (current === void 0 || current === null || seen.has(current)) {
715
+ continue;
716
+ }
717
+ seen.add(current);
718
+ if (typeof current === "string") {
719
+ if (matchesRateLimitText(current)) {
720
+ return true;
721
+ }
722
+ continue;
723
+ }
724
+ if (typeof current === "number") {
725
+ if (isRateLimitCode(current)) {
726
+ return true;
727
+ }
728
+ continue;
729
+ }
730
+ if (typeof current !== "object") {
731
+ continue;
732
+ }
733
+ if (Array.isArray(current)) {
734
+ const items = current;
735
+ queue.push(...items);
736
+ continue;
737
+ }
738
+ const record = current;
739
+ for (const key of ["code", "message", "shortMessage", "reason", "status", "statusCode"]) {
740
+ if (key in record) {
741
+ queue.push(record[key]);
742
+ }
743
+ }
744
+ for (const key of ["error", "info", "data", "value", "body", "payload"]) {
745
+ if (key in record) {
746
+ queue.push(record[key]);
747
+ }
748
+ }
749
+ }
750
+ return false;
751
+ }
752
+ function isRateLimitCode(code) {
753
+ return code === 429 || code === -32005 || code === -32007 || code === -32016;
754
+ }
755
+ function matchesRateLimitText(text) {
756
+ const normalized = text.toLowerCase();
757
+ return normalized.includes("too many requests") || normalized.includes("rate limit") || normalized.includes("rate exceeded") || normalized.includes("call rate limit") || normalized.includes("request limit") || normalized.includes("exceeded the quota");
758
+ }
759
+
760
+ // src/modules/ethereum/rpc/withRpcRateLimitBackoff.ts
761
+ async function withRpcRateLimitBackoff(fn, options = {}) {
762
+ const {
763
+ backoff = 2,
764
+ initialDelayMs = 1e3,
765
+ maxAttempts = 8,
766
+ maxDelayMs = 3e4,
767
+ onRetry
768
+ } = options;
769
+ if (!Number.isInteger(maxAttempts) || maxAttempts < 1) {
770
+ throw new TypeError(`maxAttempts must be an integer >= 1, got ${maxAttempts}`);
771
+ }
772
+ let delayMs = initialDelayMs;
773
+ let lastError;
774
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
775
+ try {
776
+ return await fn();
777
+ } catch (error) {
778
+ lastError = error;
779
+ const isLastAttempt = attempt >= maxAttempts;
780
+ if (!isRpcRateLimitError(error) || isLastAttempt) {
781
+ throw error;
782
+ }
783
+ const waitMs = Math.min(delayMs, maxDelayMs);
784
+ onRetry?.(error, attempt, waitMs);
785
+ await delay(waitMs);
786
+ delayMs = Math.min(delayMs * backoff, maxDelayMs);
787
+ }
788
+ }
789
+ throw lastError;
790
+ }
791
+
644
792
  // src/modules/ethereum/drivers/EvmStakeEventZod.ts
645
793
  import {
646
794
  EthAddressZod,
@@ -696,11 +844,25 @@ var asEvmStakeWithdrawnEvent = zodAsFactory(EvmStakeWithdrawnEventZod, "asEvmSta
696
844
  var toEvmStakeWithdrawnEvent = zodToFactory(EvmStakeWithdrawnEventZod, "toEvmStakeWithdrawnEvent");
697
845
 
698
846
  // src/modules/ethereum/drivers/EvmStakeEventsViewer.ts
847
+ var DEFAULT_EVENT_QUERY_BLOCK_CHUNK_SIZE = 2e3;
848
+ var DEFAULT_EVENT_QUERY_MAX_ATTEMPTS = 8;
849
+ var DEFAULT_EVENT_QUERY_INITIAL_DELAY_MS = 1e3;
699
850
  var EvmStakeEventsViewer = class extends AbstractEvmViewer {
700
851
  moniker = EvmStakeEventsViewer.defaultMoniker;
852
+ /** Set at start when `params.deploymentBlock` is omitted (estimated 2025-06-01). */
853
+ defaultDeploymentBlock = 0;
701
854
  eventCache = /* @__PURE__ */ new Map();
702
855
  get deploymentBlock() {
703
- return this.params.deploymentBlock ?? 0;
856
+ return this.params.deploymentBlock ?? this.defaultDeploymentBlock;
857
+ }
858
+ get eventQueryBlockChunkSize() {
859
+ return this.params.eventQueryBlockChunkSize ?? DEFAULT_EVENT_QUERY_BLOCK_CHUNK_SIZE;
860
+ }
861
+ get eventQueryInitialDelayMs() {
862
+ return this.params.eventQueryInitialDelayMs ?? DEFAULT_EVENT_QUERY_INITIAL_DELAY_MS;
863
+ }
864
+ get eventQueryMaxAttempts() {
865
+ return this.params.eventQueryMaxAttempts ?? DEFAULT_EVENT_QUERY_MAX_ATTEMPTS;
704
866
  }
705
867
  async positionCount(range) {
706
868
  const events = await this.stakeEvents(range);
@@ -733,7 +895,7 @@ var EvmStakeEventsViewer = class extends AbstractEvmViewer {
733
895
  return result;
734
896
  }
735
897
  connectContract(address) {
736
- return IAddressStakingEvents__factory.connect(address, this.params.provider);
898
+ return IAddressStakingEvents__factory.connect(address, this.provider);
737
899
  }
738
900
  onEventHandler(staked, staker, id, amount, event, throwOnInvalid = false) {
739
901
  const validatedEventResult = EvmStakeEventZod.safeParse(event);
@@ -747,9 +909,7 @@ var EvmStakeEventsViewer = class extends AbstractEvmViewer {
747
909
  }
748
910
  const validatedEvent = validatedEventResult.data;
749
911
  const { eventName, blockNumber } = validatedEvent;
750
- this.logger?.log(`Processing ${eventName} event for stake ID ${id} at block ${blockNumber}`);
751
912
  const cacheKey = `${Number(id)}|${eventName}|${staker}`;
752
- const existingStakeEvent = this.eventCache.get(cacheKey);
753
913
  const stakeEvent = {
754
914
  name: eventName,
755
915
  args: {
@@ -760,67 +920,106 @@ var EvmStakeEventsViewer = class extends AbstractEvmViewer {
760
920
  },
761
921
  time: blockNumber
762
922
  };
763
- if (isDefined3(existingStakeEvent)) {
764
- this.logger?.warn(`Received ${eventName} event for stake ID ${id} that is already cached, updating cache...`);
765
- this.logger?.warn("1");
766
- this.logger?.warn("Previous event", existingStakeEvent);
767
- this.logger?.warn("2");
768
- this.logger?.warn("New event", stakeEvent);
769
- this.logger?.warn("3");
770
- }
771
923
  this.eventCache.set(cacheKey, stakeEvent);
772
924
  return stakeEvent;
773
925
  }
774
926
  async startHandler() {
775
927
  try {
776
- const currentEthBlock = assertEx7(await this.contract.runner?.provider?.getBlockNumber(), () => new Error("Failed to egt currentEthBlock"));
777
- await this.contract.on(this.contract.getEvent("StakeAdded"), (staked, staker, id, amount, event) => {
778
- this.onEventHandler(staked, staker, id, amount, event);
779
- });
780
- await this.contract.on(this.contract.getEvent("StakeRemoved"), (staked, staker, id, amount, event) => {
781
- this.onEventHandler(staked, staker, id, amount, event);
782
- });
783
- await this.contract.on(this.contract.getEvent("StakeWithdrawn"), (staked, staker, id, amount, event) => {
784
- this.onEventHandler(staked, staker, id, amount, event);
785
- });
786
- await this.loadHistoricalEvents(currentEthBlock);
928
+ const provider = assertEx10(this.contract.runner?.provider, () => new Error("Failed to get provider"));
929
+ const historyEndBlock = assertEx10(await provider.getBlockNumber(), () => new Error("Failed to get currentEthBlock"));
930
+ if (!isDefined3(this.params.deploymentBlock)) {
931
+ this.defaultDeploymentBlock = await estimateBlockNumberAt(provider);
932
+ }
933
+ await this.loadHistoricalEvents(this.deploymentBlock, historyEndBlock);
934
+ await this.attachLiveListeners();
935
+ const latestBlock = assertEx10(await provider.getBlockNumber(), () => new Error("Failed to get latestEthBlock"));
936
+ if (latestBlock > historyEndBlock) {
937
+ await this.loadHistoricalEvents(historyEndBlock + 1, latestBlock);
938
+ }
787
939
  } catch (error) {
788
940
  this.logger?.error("EthereumChainStakeEvents failed to start:", error);
789
941
  throw error;
790
942
  }
791
943
  }
792
- async loadHistoricalEvents(currentEthBlock) {
944
+ async attachLiveListeners() {
945
+ await this.contract.on(this.contract.getEvent("StakeAdded"), (staked, staker, id, amount, event) => {
946
+ this.onEventHandler(staked, staker, id, amount, event);
947
+ });
948
+ await this.contract.on(this.contract.getEvent("StakeRemoved"), (staked, staker, id, amount, event) => {
949
+ this.onEventHandler(staked, staker, id, amount, event);
950
+ });
951
+ await this.contract.on(this.contract.getEvent("StakeWithdrawn"), (staked, staker, id, amount, event) => {
952
+ this.onEventHandler(staked, staker, id, amount, event);
953
+ });
954
+ }
955
+ async loadHistoricalEvents(fromBlock, toBlock) {
956
+ if (fromBlock > toBlock) {
957
+ return;
958
+ }
793
959
  const stakeEventGroups = await Promise.all([
794
- this.stakeEventsNative([this.deploymentBlock, currentEthBlock], { name: "StakeAdded" }),
795
- this.stakeEventsNative([this.deploymentBlock, currentEthBlock], { name: "StakeRemoved" }),
796
- this.stakeEventsNative([this.deploymentBlock, currentEthBlock], { name: "StakeWithdrawn" })
960
+ this.stakeEventsNative([fromBlock, toBlock], { name: "StakeAdded" }),
961
+ this.stakeEventsNative([fromBlock, toBlock], { name: "StakeRemoved" }),
962
+ this.stakeEventsNative([fromBlock, toBlock], { name: "StakeWithdrawn" })
797
963
  ]);
798
964
  const allStakeEvents = stakeEventGroups.flat().toSorted((a, b) => a.time - b.time);
799
- console.warn(`Caching ${allStakeEvents.length} stake events from chain starting at block ${this.deploymentBlock}`);
965
+ const chunks = blockRangeChunks(fromBlock, toBlock, this.eventQueryBlockChunkSize);
966
+ this.logger?.log(
967
+ `Cached ${allStakeEvents.length} stake events from blocks ${fromBlock}-${toBlock} (${chunks.length} chunk(s) of up to ${this.eventQueryBlockChunkSize} blocks)`
968
+ );
800
969
  for (const event of allStakeEvents) {
801
970
  this.eventCache.set(`${Number(event.args.id)}|${event.name}|${event.args.staker}`, event);
802
971
  }
803
972
  }
804
973
  async stakeEventsNative(range = [0, "latest"], filter) {
805
974
  const name = filter?.name;
806
- if (isDefined3(name)) {
807
- const stakedFilter = filter?.args?.staked;
808
- const stakerFilter = filter?.args?.staker;
809
- const stakedFilterEth = isDefined3(stakedFilter) ? toEthAddress8(stakedFilter) : void 0;
810
- const stakerFilterEth = isDefined3(stakerFilter) ? toEthAddress8(stakerFilter) : void 0;
811
- const ethFilter = this.contract.filters[name](stakedFilterEth, stakerFilterEth);
812
- const ethEvents = await this.contract.queryFilter(ethFilter, range[0], range[1]);
813
- return ethEvents.map((e) => {
814
- assertEx7(e.eventName === name, () => `Event name mismatch expected '${name}' but got '${e.eventName}'`);
815
- return this.onEventHandler(e.args.staked, e.args.by, e.args.id, e.args.amount, e, true);
816
- }).filter(exists);
975
+ if (!isDefined3(name)) {
976
+ throw new Error("Only filtered stake events (by name) are supported");
977
+ }
978
+ const stakedFilter = filter?.args?.staked;
979
+ const stakerFilter = filter?.args?.staker;
980
+ const stakedFilterEth = isDefined3(stakedFilter) ? toEthAddress8(stakedFilter) : void 0;
981
+ const stakerFilterEth = isDefined3(stakerFilter) ? toEthAddress8(stakerFilter) : void 0;
982
+ const ethFilter = this.contract.filters[name](stakedFilterEth, stakerFilterEth);
983
+ const fromBlock = range[0];
984
+ const toBlock = range[1] === "latest" ? assertEx10(await this.contract.runner?.provider?.getBlockNumber(), () => new Error("Failed to resolve latest block")) : range[1];
985
+ if (fromBlock > toBlock) {
986
+ return [];
987
+ }
988
+ const chunkSize = this.eventQueryBlockChunkSize;
989
+ const chunks = blockRangeChunks(fromBlock, toBlock, chunkSize);
990
+ const ethEventGroups = [];
991
+ for (const [chunkFrom, chunkTo] of chunks) {
992
+ try {
993
+ ethEventGroups.push(await withRpcRateLimitBackoff(
994
+ () => this.contract.queryFilter(ethFilter, chunkFrom, chunkTo),
995
+ {
996
+ initialDelayMs: this.eventQueryInitialDelayMs,
997
+ maxAttempts: this.eventQueryMaxAttempts,
998
+ onRetry: (_error, attempt, delayMs) => {
999
+ this.logger?.warn(
1000
+ `Rate limited fetching ${name} logs for blocks ${chunkFrom}-${chunkTo} (attempt ${attempt}/${this.eventQueryMaxAttempts}); backing off ${delayMs}ms`
1001
+ );
1002
+ }
1003
+ }
1004
+ ));
1005
+ } catch (error) {
1006
+ this.logger?.error(
1007
+ `eth_getLogs failed for ${name} blocks ${chunkFrom}-${chunkTo} after rate-limit retries (from=${fromBlock} to=${toBlock}):`,
1008
+ error
1009
+ );
1010
+ throw error;
1011
+ }
817
1012
  }
818
- throw new Error("Only filtered stake events (by name) are supported");
1013
+ const ethEvents = ethEventGroups.flat();
1014
+ return ethEvents.map((e) => {
1015
+ assertEx10(e.eventName === name, () => `Event name mismatch expected '${name}' but got '${e.eventName}'`);
1016
+ return this.onEventHandler(e.args.staked, e.args.by, e.args.id, e.args.amount, e, true);
1017
+ }).filter(exists);
819
1018
  }
820
1019
  };
821
1020
  __publicField(EvmStakeEventsViewer, "connectionTypes", ["evm-rpc"]);
822
1021
  __publicField(EvmStakeEventsViewer, "defaultMoniker", StakeEventsViewerMoniker);
823
- __publicField(EvmStakeEventsViewer, "dependencies", []);
1022
+ __publicField(EvmStakeEventsViewer, "dependencies", [EvmChainViewerMoniker4]);
824
1023
  __publicField(EvmStakeEventsViewer, "monikers", [StakeEventsViewerMoniker]);
825
1024
  __publicField(EvmStakeEventsViewer, "surface", "node");
826
1025
  EvmStakeEventsViewer = __decorateClass([
@@ -829,13 +1028,15 @@ EvmStakeEventsViewer = __decorateClass([
829
1028
 
830
1029
  // src/modules/ethereum/drivers/EvmStakeViewer.ts
831
1030
  import {
832
- assertEx as assertEx8,
1031
+ assertEx as assertEx11,
1032
+ isDefined as isDefined4,
833
1033
  toAddress as toAddress4,
834
1034
  toEthAddress as toEthAddress9
835
1035
  } from "@ariestools/sdk";
836
1036
  import { IAddressStaking__factory } from "@xyo-network/typechain";
837
1037
  import {
838
1038
  creatableProvider as creatableProvider5,
1039
+ EvmChainViewerMoniker as EvmChainViewerMoniker5,
839
1040
  StakeEventsViewerMoniker as StakeEventsViewerMoniker2,
840
1041
  StakeViewerMoniker
841
1042
  } from "@xyo-network/xl1-sdk";
@@ -883,6 +1084,7 @@ var EvmStakeViewer = class extends AbstractEvmViewer {
883
1084
  async createHandler() {
884
1085
  await super.createHandler();
885
1086
  this._stakeEventsViewer = await this.locator.getInstance(StakeEventsViewerMoniker2);
1087
+ this._deploymentBlock = isDefined4(this.params.deploymentBlock) ? this.params.deploymentBlock : await estimateBlockNumberAt(this.provider);
886
1088
  }
887
1089
  minWithdrawalBlocks() {
888
1090
  return 0;
@@ -968,7 +1170,7 @@ var EvmStakeViewer = class extends AbstractEvmViewer {
968
1170
  return this._stakeCache.values().filter((stake) => stake.removeBlock !== 0 && stake.withdrawBlock !== 0).toArray();
969
1171
  }
970
1172
  connectContract(address) {
971
- return IAddressStaking__factory.connect(address, this.params.provider);
1173
+ return IAddressStaking__factory.connect(address, this.provider);
972
1174
  }
973
1175
  async startHandler() {
974
1176
  await this.contract.on(this.contract.getEvent("StakeAdded"), (staked, staker, id, amount, event) => {
@@ -983,14 +1185,14 @@ var EvmStakeViewer = class extends AbstractEvmViewer {
983
1185
  });
984
1186
  });
985
1187
  await this.contract.on(this.contract.getEvent("StakeRemoved"), (staked, staker, id, amount, event) => {
986
- const stake = assertEx8(this._stakeCache.get(Number(id)));
1188
+ const stake = assertEx11(this._stakeCache.get(Number(id)));
987
1189
  this._stakeCache.set(Number(id), {
988
1190
  ...stake,
989
1191
  removeBlock: event.blockNumber
990
1192
  });
991
1193
  });
992
1194
  await this.contract.on(this.contract.getEvent("StakeWithdrawn"), (staked, staker, id, amount, event) => {
993
- const stake = assertEx8(this._stakeCache.get(Number(id)));
1195
+ const stake = assertEx11(this._stakeCache.get(Number(id)));
994
1196
  this._stakeCache.set(Number(id), {
995
1197
  ...stake,
996
1198
  withdrawBlock: event.blockNumber
@@ -1023,7 +1225,7 @@ var EvmStakeViewer = class extends AbstractEvmViewer {
1023
1225
  return;
1024
1226
  }
1025
1227
  if (event.name === "StakeRemoved") {
1026
- const stake = assertEx8(this._stakeCache.get(event.args.id));
1228
+ const stake = assertEx11(this._stakeCache.get(event.args.id));
1027
1229
  this._stakeCache.set(event.args.id, {
1028
1230
  ...stake,
1029
1231
  removeBlock: event.time
@@ -1031,7 +1233,7 @@ var EvmStakeViewer = class extends AbstractEvmViewer {
1031
1233
  return;
1032
1234
  }
1033
1235
  if (event.name === "StakeWithdrawn") {
1034
- const stake = assertEx8(this._stakeCache.get(event.args.id));
1236
+ const stake = assertEx11(this._stakeCache.get(event.args.id));
1035
1237
  this._stakeCache.set(event.args.id, {
1036
1238
  ...stake,
1037
1239
  withdrawBlock: event.time
@@ -1041,7 +1243,7 @@ var EvmStakeViewer = class extends AbstractEvmViewer {
1041
1243
  };
1042
1244
  __publicField(EvmStakeViewer, "connectionTypes", ["evm-rpc"]);
1043
1245
  __publicField(EvmStakeViewer, "defaultMoniker", StakeViewerMoniker);
1044
- __publicField(EvmStakeViewer, "dependencies", []);
1246
+ __publicField(EvmStakeViewer, "dependencies", [EvmChainViewerMoniker5]);
1045
1247
  __publicField(EvmStakeViewer, "monikers", [StakeViewerMoniker]);
1046
1248
  __publicField(EvmStakeViewer, "surface", "node");
1047
1249
  EvmStakeViewer = __decorateClass([
@@ -1062,6 +1264,11 @@ export {
1062
1264
  AbstractEvmRunner,
1063
1265
  AbstractEvmViewer,
1064
1266
  BaseEthProvider,
1267
+ DEFAULT_ESTIMATE_BLOCK_DATE,
1268
+ DEFAULT_EVENT_QUERY_BLOCK_CHUNK_SIZE,
1269
+ DEFAULT_EVENT_QUERY_INITIAL_DELAY_MS,
1270
+ DEFAULT_EVENT_QUERY_MAX_ATTEMPTS,
1271
+ DEFAULT_EVM_BLOCK_TIME_SEC,
1065
1272
  EthHashRegEx,
1066
1273
  EthHashZod,
1067
1274
  EvmChainContractViewer,
@@ -1082,11 +1289,14 @@ export {
1082
1289
  asEvmStakeEvent,
1083
1290
  asEvmStakeRemovedEvent,
1084
1291
  asEvmStakeWithdrawnEvent,
1292
+ blockRangeChunks,
1085
1293
  calculateEthBlockRate,
1086
1294
  calculateEthTimeRate,
1087
1295
  createChain,
1088
1296
  createChainContract,
1089
1297
  createChainRewardsContract,
1298
+ estimateBlockNumberAt,
1299
+ estimateBlockNumberFromHead,
1090
1300
  ethBlockRate,
1091
1301
  getDefaultGasConfig,
1092
1302
  getEthBlockRateBlocks,