var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __decorateClass = (decorators, target, key, kind) => {
  var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
  for (var i = decorators.length - 1, decorator; i >= 0; i--)
    if (decorator = decorators[i])
      result = (kind ? decorator(target, key, result) : decorator(result)) || result;
  if (kind && result) __defProp(target, key, result);
  return result;
};
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);

// src/modules/protocol-sdk/test/buildRandomChain.ts
import { asAddress as asAddress2, assertEx as assertEx6 } from "@ariestools/sdk";
import {
  Account as Account3,
  asSchema as asSchema2,
  IdSchema as IdSchema2,
  MemoryArchivist,
  PayloadBuilder as PayloadBuilder8
} from "@xyo-network/sdk";
import {
  asXL1BlockNumber as asXL1BlockNumber6
} from "@xyo-network/xl1-protocol/protocol-lib";

// src/modules/protocol-sdk/block/hydrate/allHashesPresent.ts
function allHashesPresent(hashes, payloads) {
  const payloadHashes = new Set(payloads.map((p) => p._hash));
  return hashes.every((hash) => payloadHashes.has(hash));
}

// src/modules/protocol-sdk/block/hydrate/flattenHydratedBlock.ts
import { asHydratedBlock } from "@xyo-network/xl1-protocol/protocol-lib";
var flattenHydratedBlock = (hydratedBlock) => {
  const [blk, blkPayloads] = hydratedBlock;
  return [...blkPayloads, blk];
};

// src/modules/protocol-sdk/block/hydrate/flattenHydratedBlocks.ts
var flattenHydratedBlocks = (hydratedBlocks) => hydratedBlocks.flatMap((blk) => flattenHydratedBlock(blk));

// src/modules/protocol-sdk/block/hydrate/hydrateBlock.ts
import { assertEx } from "@ariestools/sdk";
import { asAnyPayload } from "@xyo-network/sdk";
import { asBlockBoundWitnessWithStorageMeta, isTransactionBoundWitnessWithStorageMeta } from "@xyo-network/xl1-protocol/protocol-lib";
var hydrateBlock = async (context, hash, maxDepth = 1, minDepth = maxDepth) => {
  assertEx(maxDepth >= 0, () => "maxDepth must be greater than or equal to 0");
  assertEx(minDepth >= 0, () => "minDepth must be greater than or equal to 0");
  assertEx(maxDepth >= minDepth, () => "maxDepth must be greater than or equal to minDepth");
  const { chainMap } = context;
  const [block] = await chainMap.get([hash]);
  const bw = assertEx(asBlockBoundWitnessWithStorageMeta(
    assertEx(block, () => `block ${hash} not found`)
  ), () => `hash ${hash} is not a BlockBoundWitness`);
  if (maxDepth === 0) return [bw, []];
  const blockPayloadResults = await chainMap.get(bw.payload_hashes);
  const blkPayloads = blockPayloadResults.map((p) => asAnyPayload(p, true));
  if (minDepth === 1) assertEx(allHashesPresent(bw.payload_hashes, blkPayloads), () => `Unable to find all payloads for block ${hash}`);
  if (maxDepth === 1) return [bw, blkPayloads];
  const transactions = blkPayloads.filter(isTransactionBoundWitnessWithStorageMeta);
  const transactionsPayloadHashes = transactions.flatMap((tx) => tx.payload_hashes);
  const transactionPayloadResults = await chainMap.get(transactionsPayloadHashes);
  const transactionsPayloads = transactionPayloadResults.map((p) => asAnyPayload(p, true));
  assertEx(allHashesPresent(transactionsPayloadHashes, transactionsPayloads), () => `Unable to find all payloads for transactions in block ${hash}`);
  const allPayloadsHashes = new Set([...blkPayloads, ...transactionsPayloads].flatMap((p) => p._hash));
  const allPayloadResults = await chainMap.get([...allPayloadsHashes]);
  const allPayloads = allPayloadResults.map((p) => asAnyPayload(p, true));
  const allPayloadsFiltered = allPayloads.filter((p) => allPayloadsHashes.has(p._hash));
  if (maxDepth === 2) assertEx(allHashesPresent(
    [...allPayloadsHashes],
    allPayloadsFiltered
  ), () => `Unable to find all payloads for transactions in block ${hash}`);
  return [bw, allPayloadsFiltered];
};

// src/modules/protocol-sdk/block/primitives/blockFromBlockNumber.ts
import {
  asHash,
  isDefined as isDefined2,
  spanAsync
} from "@ariestools/sdk";
import { toSafeJsonString } from "@ariestools/sdk";
import {
  asSignedBlockBoundWitnessWithStorageMeta,
  SignedBlockBoundWitnessWithHashMetaZod,
  StepSizes
} from "@xyo-network/xl1-protocol/protocol-lib";

// src/modules/protocol-sdk/ChainContextHelpers.ts
import {
  isDefined,
  isObject,
  isUndefined,
  timeBudget
} from "@ariestools/sdk";
import { LruCacheMap, MemoryMap } from "#driver-memory";
function contextCache(context, name, create) {
  if (!isObject(context.caches)) {
    throw new Error("Context does not have an appropriate caches property");
  }
  if (isUndefined(context.caches[name])) {
    context.caches[name] = create?.() ?? new MemoryMap();
  }
  return context.caches[name];
}
async function withContextCacheResponse(context, name, key, func, { max = 1e4 } = {}) {
  const cache = contextCache(
    context,
    name,
    () => new LruCacheMap({ max })
  );
  const { timeBudgetLimit = 0 } = context;
  const cacheResult = await cache.get(key);
  if (isDefined(cacheResult)) {
    return cacheResult;
  }
  const result = timeBudgetLimit > 0 ? timeBudget(name, context.logger, func, timeBudgetLimit) : func();
  await cache.set(key, result);
  return result;
}

// src/modules/protocol-sdk/block/primitives/blockFromBlockNumber.ts
async function blockFromBlockNumber(context, blockNumber) {
  return await spanAsync("blockFromBlockNumber", async () => {
    const cacheKey = String(blockNumber);
    const { chainMap, head } = context;
    return await withContextCacheResponse(context, "blockFromBlockNumber", cacheKey, async () => {
      const [result] = await chainMap.get([head._hash]);
      if (!isDefined2(result)) {
        throw new Error(`Head block not found for hash: ${head._hash}`);
      }
      let currentBlock = asSignedBlockBoundWitnessWithStorageMeta(
        result,
        () => `Found Payload is not a Signed<BlockBoundWitness>: ${JSON.stringify(result, null, 2)}`
      );
      if (currentBlock.block < blockNumber) {
        throw new Error(`Block number ${blockNumber} is greater than head ${currentBlock.block}.`);
      }
      while (currentBlock.block > blockNumber) {
        let jumpHash = currentBlock.previous;
        let jumpBlockNumber = currentBlock.block - 1;
        for (const [step, stepSize3] of StepSizes.entries()) {
          const possibleJumpBlockNumber = currentBlock.block - currentBlock.block % stepSize3 - 1;
          if (possibleJumpBlockNumber >= blockNumber && possibleJumpBlockNumber <= jumpBlockNumber) {
            jumpBlockNumber = possibleJumpBlockNumber;
            jumpHash = asHash(currentBlock.step_hashes?.at(step), () => `Step hash not found for step ${step} in block ${currentBlock.block}`);
          }
        }
        const [newBlock] = await chainMap.get([
          asHash(jumpHash, () => `Jump hash not found for block number [${blockNumber}]: ${jumpBlockNumber} ${toSafeJsonString(currentBlock, 10)}`)
        ]);
        if (!isDefined2(newBlock)) {
          throw new Error(`Block not found for jump hash: ${jumpHash}`);
        }
        currentBlock = asSignedBlockBoundWitnessWithStorageMeta(
          newBlock,
          () => {
            const result2 = SignedBlockBoundWitnessWithHashMetaZod.safeParse(newBlock);
            return `Found Payload [jump hash] is not a Signed<BlockBoundWitness>: ${result2.error}`;
          }
        );
        if (currentBlock.block === blockNumber) {
          break;
        }
        if (currentBlock.block < blockNumber) {
          throw new Error(`Block number ${blockNumber} is not a valid step block number for block ${head._hash}.`);
        }
      }
      return currentBlock;
    });
  }, { ...context, timeBudgetLimit: 500 });
}

// src/modules/protocol-sdk/block/primitives/frames/calculateFramesFromRange.ts
import { asXL1BlockNumber, stepSize } from "@xyo-network/xl1-protocol/protocol-lib";
function calculateFramesFromRange(range, step) {
  const size = stepSize(step);
  let start = Math.trunc(range[0] / size) * size;
  const fitted = [];
  const remaining = [];
  if (start !== range[0]) {
    start += size;
    remaining.push([range[0], asXL1BlockNumber(Math.min(start - 1, range[1]), true)]);
  }
  for (let i = start; i <= range[1]; i += size) {
    if (i + size - 1 <= range[1]) {
      fitted.push([
        asXL1BlockNumber(i, { name: "calculateFramesFromRange A" }),
        asXL1BlockNumber(Math.min(i + size - 1, range[1]), { name: "calculateFramesFromRange B" })
      ]);
    } else {
      remaining.push([asXL1BlockNumber(i, { name: "calculateFramesFromRange C" }), range[1]]);
    }
  }
  return [fitted, remaining];
}

// src/modules/protocol-sdk/block/primitives/frames/deepCalculateFramesFromRange.ts
import { StepSizes as StepSizes2 } from "@xyo-network/xl1-protocol/protocol-lib";
function deepCalculateFramesFromRange(range, startingStep = StepSizes2.length - 1) {
  const fitted = [];
  let remaining = [range];
  const actualStartingStep = Math.min(startingStep, StepSizes2.length - 1);
  for (let step = actualStartingStep; step >= 0; step--) {
    const newRemaining = [];
    for (const range2 of remaining) {
      const [newFittedFrames, newRemainingFrames] = calculateFramesFromRange(range2, step);
      fitted.push(...newFittedFrames);
      newRemaining.push(...newRemainingFrames);
    }
    remaining = newRemaining;
  }
  for (const range2 of remaining) {
    for (let i = range2[0]; i <= range2[1]; i++) {
      fitted.push([i, i]);
    }
  }
  return fitted.toSorted((a, b) => a[0] - b[0]);
}

// src/modules/protocol-sdk/block/primitives/validateTransactionOpcodes.ts
import {
  assertEx as assertEx2,
  isHash,
  toSafeJsonString as toSafeJsonString2
} from "@ariestools/sdk";
import {
  PayloadBuilder
} from "@xyo-network/sdk";
import { isExecutable } from "@xyo-network/xl1-protocol/protocol-lib";
async function processElevateOperation(opCode, args, txBw, txPayloads) {
  const [hash, ...rest] = args;
  const txPayloadsWithStorageMeta = await PayloadBuilder.addStorageMeta(txPayloads);
  assertEx2(rest.length === 0, () => `Invalid elevate operation ${opCode} ${args.join(", ")} - Too many Arguments`);
  if (isHash(hash)) {
    assertEx2(
      txBw.payload_hashes.includes(hash),
      () => `Invalid elevate operation ${opCode} ${args.join(", ")} - Hash not in payload hashes => ${toSafeJsonString2(txBw, 20)}`
    );
    return assertEx2(
      txPayloadsWithStorageMeta.find((p) => p._hash === hash),
      () => `Invalid elevate operation ${opCode} ${args.join(", ")} - Payload not found`
    );
  }
  throw new Error(`Invalid elevate operation ${opCode} ${args.join(", ")} - Invalid hash`);
}
async function processOperation(opCode, args, txBw, txPayloads) {
  switch (opCode) {
    case "elevate": {
      return await processElevateOperation(opCode, args, txBw, txPayloads);
    }
    default: {
      throw new Error(`Invalid opCode ${opCode}`);
    }
  }
}
async function validateTransactionsOpcodes(txs) {
  const txElevatedPayloads = [];
  for (const [txBw, txPayloads] of txs) {
    if (isExecutable(txBw)) {
      const operations = txBw.script.map((op) => op.split("|"));
      for (const [opCode, ...args] of operations) {
        const txPayload = await processOperation(opCode, args, txBw, txPayloads);
        if (txPayload !== void 0) {
          txElevatedPayloads.push(txPayload);
        }
      }
    }
  }
  return txElevatedPayloads;
}

// src/modules/protocol-sdk/test/buildNextBlock.ts
import {
  AttoXL1 as AttoXL12,
  XYO_STEP_REWARD_ADDRESS as XYO_STEP_REWARD_ADDRESS2
} from "@xyo-network/xl1-protocol/protocol-lib";

// src/modules/protocol-sdk/test/buildBlock.ts
import { assertEx as assertEx3, isDefined as isDefined3 } from "@ariestools/sdk";
import {
  asAnyPayload as asAnyPayload2,
  BoundWitnessBuilder,
  PayloadBuilder as PayloadBuilder3
} from "@xyo-network/sdk";
import {
  asXL1BlockNumber as asXL1BlockNumber2,
  AttoXL1,
  isBlockBoundWitness,
  rewardAddressFromStepIdentity,
  StepRewardFractions,
  StepSizes as StepSizes3,
  XL1_PROTOCOL_VERSION,
  XYO_STEP_REWARD_ADDRESS,
  XYO_ZERO_ADDRESS
} from "@xyo-network/xl1-protocol/protocol-lib";

// src/modules/protocol-sdk/createTransferPayload.ts
import { toHex } from "@ariestools/sdk";
import { PayloadBuilder as PayloadBuilder2 } from "@xyo-network/sdk";
import { TransferSchema } from "@xyo-network/xl1-protocol/protocol-lib";
function createTransferPayload(from, transfers, context) {
  const payloadBuilder = new PayloadBuilder2({ schema: TransferSchema });
  const builder = payloadBuilder.fields({
    epoch: Date.now(),
    from,
    transfers: Object.fromEntries(Object.entries(transfers).map(([k, v]) => [k, toHex(v)])),
    context
  });
  return builder.build();
}

// src/modules/protocol-sdk/test/BuildBlockOptions.ts
import {
  isAddress,
  isArray,
  isHash as isHash2,
  isNumber,
  isObject as isObject2
} from "@ariestools/sdk";
var isBaseBuildBlockOptions = (value) => {
  if (!isObject2(value)) {
    return false;
  }
  const typedValue = value;
  if (!isArray(typedValue.blockPayloads) || !isAddress(typedValue.chainId) || !isArray(typedValue.signers) || !isArray(typedValue.txs)) {
    return false;
  }
  return true;
};
var isBuildGenesisBlockOptions = (value) => {
  if (!isBaseBuildBlockOptions(value)) {
    return false;
  }
  const typedValue = value;
  if (typedValue.previousBlockHash !== null) {
    return false;
  }
  if (typedValue.previousBlockNumber !== void 0) {
    return false;
  }
  return true;
};
var isBuildNextBlockOptions = (value) => {
  if (!isBaseBuildBlockOptions(value)) {
    return false;
  }
  const typedValue = value;
  if (!isHash2(typedValue.previousBlockHash)) {
    return false;
  }
  if (!isNumber(typedValue.previousBlockNumber)) {
    return false;
  }
  if (!isArray(typedValue.previousStepHashes)) {
    return false;
  }
  return true;
};

// src/modules/protocol-sdk/test/buildBlock.ts
function calculateCompletedStepReward(step, balance) {
  return AttoXL1(StepRewardFractions[step][0] * balance / StepRewardFractions[step][1]);
}
function buildStepHashes(blockNumber, inStepHashes, previousBlockHash, chainStepRewardAddress, stepRewardPoolBalance) {
  const completedStepRewardTransfers = [];
  const step_hashes = [];
  for (const [i, step] of StepSizes3.entries()) {
    if (blockNumber < step) {
      break;
    }
    if (blockNumber % step === 0) {
      if (StepRewardFractions[i][0] > 0 && chainStepRewardAddress !== XYO_ZERO_ADDRESS) {
        const completedStepRewardHolderAddress = rewardAddressFromStepIdentity({ block: blockNumber, step });
        const completedStepReward = calculateCompletedStepReward(i, stepRewardPoolBalance);
        completedStepRewardTransfers.push(createTransferPayload(chainStepRewardAddress, { [completedStepRewardHolderAddress]: completedStepReward }));
      }
      step_hashes.push(assertEx3(previousBlockHash, () => `Previous block hash is required for step ${step} at block ${blockNumber}`));
    } else if (isDefined3(inStepHashes.at(i))) {
      step_hashes.push(inStepHashes[i]);
    }
  }
  return { completedStepRewardTransfers, step_hashes };
}
async function buildBlock(options) {
  const previousBlockNumber = isBuildGenesisBlockOptions(options) ? -1 : options.previousBlockNumber;
  const blockNumber = asXL1BlockNumber2(previousBlockNumber + 1, true);
  const inStepHashes = isBuildNextBlockOptions(options) ? options.previousStepHashes : [];
  const previousBlockHash = isBuildNextBlockOptions(options) ? options.previousBlockHash : void 0;
  const stepRewardPoolBalance = isBuildNextBlockOptions(options) ? options.stepRewardPoolBalance : AttoXL1(0n);
  const {
    chainId,
    txs,
    chainStepRewardAddress = XYO_STEP_REWARD_ADDRESS,
    blockPayloads,
    protocol = XL1_PROTOCOL_VERSION,
    signers
  } = options;
  for (const [tx] of txs) {
    if (tx.nbf > blockNumber) {
      throw new Error(`Transaction ${await PayloadBuilder3.hash(tx)} not valid for block ${blockNumber} - NBF is ${tx.nbf}`);
    }
    if (tx.exp < blockNumber) {
      throw new Error(`Transaction ${await PayloadBuilder3.hash(tx)} not valid for block ${blockNumber} - EXP is ${tx.exp}`);
    }
  }
  const { step_hashes, completedStepRewardTransfers } = buildStepHashes(
    blockNumber,
    inStepHashes,
    previousBlockHash,
    chainStepRewardAddress,
    stepRewardPoolBalance
  );
  const previous = previousBlockHash ?? null;
  const block = blockNumber;
  const txElevatedPayloads = await validateTransactionsOpcodes(txs);
  const payloads = [
    ...txs.map(([tx]) => tx),
    ...blockPayloads,
    ...txElevatedPayloads,
    ...completedStepRewardTransfers
  ];
  const boundWitnessBuilder = new BoundWitnessBuilder();
  const builder = boundWitnessBuilder.fields({
    block,
    chain: chainId,
    previous,
    step_hashes,
    protocol
  }).meta({ $epoch: Date.now(), $signatures: [] }).signers(signers).payloads(await PayloadBuilder3.addStorageMeta(payloads));
  const [bw, txPayloads] = await builder.build();
  assertEx3(isBlockBoundWitness(bw), () => "Build of BlockBoundWitness failed");
  return [await PayloadBuilder3.addStorageMeta(bw), txPayloads.map((p) => asAnyPayload2(p, true))];
}

// src/modules/protocol-sdk/test/buildNextBlock.ts
async function buildNextBlock(previousBlock, txs, blockPayloads, signers, chainStepRewardAddress = XYO_STEP_REWARD_ADDRESS2, stepRewardPoolBalance = AttoXL12(0n), protocol, chainId) {
  return await buildBlock({
    chainId: chainId ?? previousBlock.chain,
    previousBlockNumber: previousBlock.block,
    previousStepHashes: previousBlock.step_hashes ?? [],
    previousBlockHash: previousBlock._hash,
    txs,
    blockPayloads,
    signers,
    protocol,
    chainStepRewardAddress,
    stepRewardPoolBalance
  });
}

// src/modules/protocol-sdk/test/buildRandomGenesisBlock.ts
import { asAddress, assertEx as assertEx5 } from "@ariestools/sdk";
import {
  Account as Account2,
  asAnyPayload as asAnyPayload4,
  asSchema,
  IdSchema,
  PayloadBuilder as PayloadBuilder5
} from "@xyo-network/sdk";
import {
  asXL1BlockNumber as asXL1BlockNumber4
} from "@xyo-network/xl1-protocol/protocol-lib";

// src/modules/protocol-sdk/test/buildGenesisBlock.ts
import { XYO_ZERO_ADDRESS as XYO_ZERO_ADDRESS2 } from "@xyo-network/xl1-protocol/protocol-lib";
async function buildGenesisBlock(chainId, txs, blockPayloads, signers, chainStepRewardAddress = XYO_ZERO_ADDRESS2, protocol) {
  return await buildBlock({
    previousBlockHash: null,
    chainId,
    txs,
    blockPayloads,
    signers,
    chainStepRewardAddress,
    protocol
  });
}

// src/modules/protocol-sdk/test/buildRandomTransaction.ts
import { Account } from "@xyo-network/sdk";
import { asXL1BlockNumber as asXL1BlockNumber3, isAllowedBlockPayload } from "@xyo-network/xl1-protocol/protocol-lib";

// src/modules/protocol-sdk/transaction/buildTransaction.ts
import { assertEx as assertEx4, toHex as toHex2 } from "@ariestools/sdk";
import {
  asAnyPayload as asAnyPayload3,
  BoundWitnessBuilder as BoundWitnessBuilder2,
  PayloadBuilder as PayloadBuilder4
} from "@xyo-network/sdk";
import { defaultTransactionFees } from "@xyo-network/xl1-protocol/protocol-lib";
async function buildTransaction(chain, onChainPayloads, offChainPayloads, signer, nbf, exp, from, fees = defaultTransactionFees) {
  if (from === void 0 && Array.isArray(signer)) {
    throw new Error("from is required when signer is an array");
  }
  const txBoundWitnessFields = {
    chain,
    fees: {
      base: toHex2(fees.base),
      gasLimit: toHex2(fees.gasLimit),
      gasPrice: toHex2(fees.gasPrice),
      priority: toHex2(fees.priority)
    },
    nbf,
    exp
  };
  const elevatedHashes = await PayloadBuilder4.hashes(onChainPayloads);
  const script = Array.from(elevatedHashes, (elevatedHash) => `elevate|${elevatedHash}`);
  const fields = {
    ...txBoundWitnessFields,
    from: from ?? (Array.isArray(signer) ? assertEx4(signer.at(0)?.address) : signer.address)
  };
  if (script.length > 0) {
    fields.script = script;
  }
  const boundWitnessBuilder = new BoundWitnessBuilder2();
  const builder = boundWitnessBuilder.fields(fields).meta({ $signatures: [] }).payloads([...onChainPayloads, ...offChainPayloads]).signers(Array.isArray(signer) ? signer : [signer]);
  const [tx, txPayloads] = await builder.build();
  return [await PayloadBuilder4.addHashMeta(tx), await PayloadBuilder4.addHashMeta(txPayloads.map((p) => asAnyPayload3(p, true)))];
}

// src/modules/protocol-sdk/test/buildRandomTransaction.ts
var buildRandomTransaction = async (chain, payloads, account, nbf = asXL1BlockNumber3(0, true), exp = asXL1BlockNumber3(nbf + 1e3, true), privatePayloadSchemas = [], receiverAddress) => {
  const elevatedPayloads = (payloads ?? []).filter(isAllowedBlockPayload);
  const additionalPayloads = (payloads ?? []).filter((payload) => !isAllowedBlockPayload(payload));
  const sender = account ?? await Account.random();
  if (elevatedPayloads.length === 0) {
    const defaultReceiver = await Account.random();
    const receiver = receiverAddress ?? defaultReceiver.address;
    const transferPayload = createTransferPayload(sender.address, { [receiver]: 1n });
    elevatedPayloads.push(transferPayload);
  }
  const hydratedTransaction = await buildTransaction(chain, elevatedPayloads, additionalPayloads, sender, nbf, exp);
  return [hydratedTransaction[0], hydratedTransaction[1].filter((payload) => !privatePayloadSchemas.includes(payload.schema))];
};

// src/modules/protocol-sdk/test/buildRandomGenesisBlock.ts
var TestChainId = assertEx5(asAddress("c5fe2e6F6841Cbab12d8C0618Be2DF8C6156cC44"));

// src/modules/protocol-sdk/test/createGenesisBlock.ts
import { PayloadBuilder as PayloadBuilder7 } from "@xyo-network/sdk";
import {
  BlockBoundWitnessSchemaPayload,
  BlockBoundWitnessWithStorageMetaSchemaPayload,
  ChainStakeIntentPayloadJsonSchemaPayload,
  HashPayloadJsonSchemaPayload,
  TransactionBoundWitnessSchemaPayload,
  TransactionBoundWitnessWithStorageMetaSchemaPayload,
  TransferPayloadJsonSchemaPayload
} from "@xyo-network/xl1-protocol/schema";

// src/modules/protocol-sdk/test/createProducerChainStakeIntentTransaction.ts
import { PayloadBuilder as PayloadBuilder6 } from "@xyo-network/sdk";
import {
  asXL1BlockNumber as asXL1BlockNumber5,
  ChainStakeIntentSchema,
  defaultTransactionFees as defaultTransactionFees2
} from "@xyo-network/xl1-protocol/protocol-lib";
async function createProducerChainStakeIntent(from, exp, nbf = 0) {
  const payloadBuilder = new PayloadBuilder6({ schema: ChainStakeIntentSchema });
  const builder = payloadBuilder.fields({
    from,
    exp,
    nbf,
    intent: "producer"
  });
  return await PayloadBuilder6.addHashMeta(builder.build());
}

// src/modules/protocol-sdk/test/createGenesisBlock.ts
var createGenesisBlock = async (initialBlockProducer, nextContractAddress, genesisBlockRewardAmount, genesisBlockRewardAddress) => {
  const blockPayloads = await PayloadBuilder7.addHashMeta([
    TransferPayloadJsonSchemaPayload,
    BlockBoundWitnessSchemaPayload,
    BlockBoundWitnessWithStorageMetaSchemaPayload,
    TransactionBoundWitnessSchemaPayload,
    TransactionBoundWitnessWithStorageMetaSchemaPayload,
    ChainStakeIntentPayloadJsonSchemaPayload,
    HashPayloadJsonSchemaPayload
  ]);
  const intentPayload = await createProducerChainStakeIntent(initialBlockProducer.address, 1, 0);
  blockPayloads.push(intentPayload);
  if (genesisBlockRewardAmount > 0n) {
    blockPayloads.push(await PayloadBuilder7.addHashMeta(createTransferPayload(
      nextContractAddress,
      { [genesisBlockRewardAddress]: genesisBlockRewardAmount }
    )));
  }
  return await buildGenesisBlock(nextContractAddress, [], blockPayloads, [initialBlockProducer]);
};

// src/modules/protocol-sdk/test/buildRandomChain.ts
var TestGenesisBlockRewardAddress = assertEx6(asAddress2("fa7f0bb865a4bfff3d5e2c726d3e063297014da9"));
var buildRandomChain = async (blockProducer, count = 10, previousBlock, chainId, transactionAccount, receiverAddresses) => {
  const chainIdToUse = chainId ?? TestChainId;
  const blocks = [];
  let remaining = count;
  let lastBlock = previousBlock;
  const transactionAccountToUse = transactionAccount ?? await Account3.random();
  if (!lastBlock) {
    const block = await createGenesisBlock(
      blockProducer,
      chainIdToUse,
      1000000000n * 10n ** 18n,
      transactionAccountToUse.address
    );
    blocks.push(block);
    remaining = remaining - 1;
    lastBlock = block;
  }
  const defaultReceiver = await Account3.random();
  const resolvedReceiverAddresses = receiverAddresses ?? [defaultReceiver.address];
  let saltCounter = 0;
  while (remaining > 0) {
    saltCounter += 1;
    const idPayloadBuilder = new PayloadBuilder8({ schema: IdSchema2 });
    const idBuilder = idPayloadBuilder.fields({ salt: `${Date.now()}-${saltCounter}` });
    const payloads = [idBuilder.build()];
    saltCounter += 1;
    const additionalPrivatePayloads = remaining % 2 === 0 ? (() => {
      const privatePayloadBuilder = new PayloadBuilder8({ schema: asSchema2("network.xyo.private", true) });
      const privateBuilder = privatePayloadBuilder.fields({ salt: `${Date.now()}-${saltCounter}` });
      return [privateBuilder.build()];
    })() : [];
    const txs = [];
    for (const receiverAddress of resolvedReceiverAddresses) {
      txs.push(await buildRandomTransaction(
        chainIdToUse,
        [...payloads, ...additionalPrivatePayloads],
        transactionAccountToUse,
        asXL1BlockNumber6(Math.max(count - remaining - 1e3, 0), true),
        asXL1BlockNumber6(count - remaining + 1e3, true),
        [asSchema2("network.xyo.private", true)],
        receiverAddress
      ));
    }
    const previousBlock2 = assertEx6(lastBlock?.[0], () => new Error("No last block"));
    const block = await buildNextBlock(previousBlock2, txs, [], [blockProducer], transactionAccountToUse.address);
    blocks.push(block);
    remaining = remaining - 1;
    lastBlock = block;
  }
  return blocks;
};
async function buildRandomChainArchivist(count = 20) {
  const producerAccount = await Account3.random();
  const blocks = await buildRandomChain(producerAccount, count);
  const archivist = await MemoryArchivist.create();
  const payloads = flattenHydratedBlocks(blocks);
  await archivist.insert(payloads);
  return archivist;
}

// src/modules/protocol-sdk/test/getSimpleBlockViewerLocator.ts
import { XYO_ZERO_ADDRESS as XYO_ZERO_ADDRESS3 } from "@xyo-network/xl1-protocol/protocol-lib";

// src/modules/protocol-sdk/CreatableProvider/AbstractCreatableProvider.ts
import {
  AbstractCreatable,
  assertEx as assertEx8,
  IdLogger
} from "@ariestools/sdk";

// src/modules/protocol-sdk/CreatableProvider/ProviderFactory.ts
import { assertEx as assertEx7 } from "@ariestools/sdk";
function providerFactoryDescription(factory, labels) {
  return `${factory.providerName}:${factory.defaultMoniker}:${JSON.stringify(labels ?? factory.labels ?? {})}`;
}
var ProviderFactory = class _ProviderFactory {
  creatableProvider;
  defaultMoniker;
  defaultParams;
  dependencies;
  labels;
  monikers;
  providerName;
  scope;
  _uniqueId;
  constructor(creatableProvider2, dependencies, params, labels = {}, scope = "context") {
    this.creatableProvider = creatableProvider2;
    this.defaultParams = params;
    this.defaultMoniker = creatableProvider2.defaultMoniker;
    this.dependencies = dependencies;
    this.monikers = creatableProvider2.monikers;
    this.scope = scope;
    assertEx7(this.monikers.includes(this.defaultMoniker), () => "defaultMoniker must be in monikers");
    this.labels = Object.assign({}, creatableProvider2.labels ?? {}, labels ?? {});
    this.providerName = creatableProvider2.name;
    this._uniqueId = Symbol(providerFactoryDescription(this));
  }
  get resolvedMoniker() {
    const labels = this.labels ?? {};
    const labelString = Object.entries(labels).map(([key, value]) => `${key}=${value}`).join(",");
    return labelString.length === 0 ? this.defaultMoniker : `${this.defaultMoniker}|${labelString}`;
  }
  get uniqueId() {
    return this._uniqueId;
  }
  static withParams(creatableProvider2, dependencies, params, labels = {}) {
    return new _ProviderFactory(creatableProvider2, dependencies, params, labels);
  }
  factory(dependencies, params, labels = {}) {
    return new _ProviderFactory(this.creatableProvider, dependencies, params, labels);
  }
  async getInstance(params, { start = true }) {
    let scopeObject;
    switch (this.scope) {
      case "global": {
        scopeObject = getOrCreateGlobalSingletons();
        break;
      }
      case "context": {
        const context = assertEx7(
          params?.context,
          () => "Context is required for context-scoped providers"
        );
        context.singletons ??= {};
        scopeObject = context.singletons;
        break;
      }
      default: {
        scopeObject = {};
        break;
      }
    }
    const mergedParams = {
      ...this.defaultParams,
      ...params
    };
    const resultPromise = scopeObject[this.resolvedMoniker] ?? this.creatableProvider.create(mergedParams);
    scopeObject[this.resolvedMoniker] = resultPromise;
    const result = await resultPromise;
    if (start) {
      assertEx7(await result.start(), () => `Failed to start provider instance [${this.resolvedMoniker}]`);
    }
    return result;
  }
  async tryGetInstance(params, options) {
    try {
      return await this.getInstance(params, options);
    } catch {
      return;
    }
  }
};
function getOrCreateGlobalSingletons() {
  const existing = globalThis.xyoServiceSingletons;
  if (existing !== void 0) {
    return existing;
  }
  const singletons = {};
  Reflect.set(globalThis, "xyoServiceSingletons", singletons);
  return singletons;
}

// src/modules/protocol-sdk/CreatableProvider/AbstractCreatableProvider.ts
var AbstractCreatableProvider = class extends AbstractCreatable {
  dependencies = {};
  _contextCache;
  _logger;
  get logger() {
    if (this._logger === void 0) {
      const providedLogger = this.params.logger ?? this.context.logger;
      this._logger = providedLogger ? new IdLogger(providedLogger, () => `${this.moniker} [${this.constructor.name}]`) : null;
    }
    return this._logger ?? void 0;
  }
  get meter() {
    return this.context.meterProvider?.getMeter(this.name) ?? super.meter;
  }
  get tracer() {
    return this.context.traceProvider?.getTracer(this.name) ?? super.tracer;
  }
  get config() {
    return this.context.config;
  }
  get context() {
    return this.params.context;
  }
  get locator() {
    return this.context.locator;
  }
  static factory(dependencies, params) {
    const factory = ProviderFactory.withParams(this, dependencies, params);
    return factory;
  }
  static async paramsHandler(params = {}) {
    const context = assertEx8(params.context, () => new Error("Context is required"));
    const config = assertEx8(context.config, () => new Error("Context config is required"));
    const locator = assertEx8(context.locator, () => new Error("Context locator is required"));
    return await super.paramsHandler({
      ...params,
      statusReporter: params.statusReporter ?? context.statusReporter,
      context: {
        ...context,
        config,
        locator
      },
      name: params.name ?? this.defaultMoniker,
      logger: params.logger ?? context.logger
    });
  }
  async createHandler() {
    await super.createHandler();
    if (this.tracer === void 0) {
      this.logger?.warn("No tracer available in context");
    }
    if (this.meter === void 0) {
      this.logger?.warn("No meter available in context");
    }
  }
  async locateAndCreate(moniker) {
    return await this.locator.getInstance(moniker);
  }
  async tryLocateAndCreate(moniker) {
    return await this.locator.tryGetInstance(moniker);
  }
};

// src/modules/protocol-sdk/CreatableProvider/CreatableProvider.ts
function creatableProvider() {
  return (constructor) => {
    constructor;
  };
}

// src/modules/protocol-sdk/CreatableProvider/CreatableProviderRegistry.ts
import { isTruthy } from "@ariestools/sdk";
var buildProviderFactory = (provider, defaultParams, labels) => {
  const factory = {
    monikers: provider.monikers,
    uniqueId: Symbol(providerFactoryDescription(provider, labels)),
    // Merge module & supplied labels
    labels: { ...provider.labels, ...labels },
    creatableProvider: provider.creatableProvider,
    dependencies: provider.dependencies,
    resolvedMoniker: provider.resolvedMoniker,
    providerName: provider.providerName,
    scope: provider.scope,
    defaultParams,
    getInstance: provider.getInstance.bind(provider),
    tryGetInstance: provider.tryGetInstance?.bind(provider),
    defaultMoniker: provider.defaultMoniker,
    factory: provider.factory.bind(provider)
  };
  return factory;
};
var registerCreatableProviderFactory = (registry2, factory, labels, primary = false) => {
  const primaryMonikers = primary !== true && isTruthy(primary) ? Array.isArray(primary) ? primary : [primary] : [];
  for (const primaryMoniker of primaryMonikers) {
    if (!factory.monikers.includes(primaryMoniker)) {
      throw new Error(`Primary moniker ${String(primaryMoniker)} not found in factory monikers`);
    }
  }
  const isPrimaryForMoniker = (moniker) => {
    switch (typeof primary) {
      case "boolean": {
        return primary;
      }
      case "string": {
        return moniker === primary;
      }
      case "object": {
        if (Array.isArray(primary)) {
          return primary.includes(moniker);
        }
      }
    }
    throw new Error(`Invalid primary value: ${String(primary)}`);
  };
  const factoryClone = buildProviderFactory(factory, factory.defaultParams, labels);
  registry2[factoryClone.defaultMoniker] = [factoryClone, ...registry2[factoryClone.defaultMoniker] ?? []];
  for (const moniker of factoryClone.monikers) {
    if (moniker === factoryClone.defaultMoniker) continue;
    registry2[moniker] = isPrimaryForMoniker(moniker) ? [factoryClone, ...registry2[moniker] ?? []] : [...registry2[moniker] ?? [], factoryClone];
  }
};

// src/modules/protocol-sdk/CreatableProvider/LabeledCreatableProviderFactory.ts
var hasLabels = (factory) => {
  return factory.labels !== void 0;
};

// src/modules/protocol-sdk/CreatableProvider/ProviderFactoryLocator.ts
import { hasAllLabels } from "@ariestools/sdk";
import { assertEx as assertEx9 } from "@ariestools/sdk";
var ProviderFactoryLocator = class {
  _context;
  _registry;
  _frozen = false;
  _parent;
  _validateDepsOnRegister;
  constructor(context, registry2 = {}, validateDepsOnRegister = false) {
    this._registry = registry2;
    this._context = { ...context, locator: this };
    this._parent = context.locator;
    this._validateDepsOnRegister = validateDepsOnRegister;
  }
  get context() {
    return this._context;
  }
  get logger() {
    return this.context.logger;
  }
  /**
   * The current registry for the module factory
   */
  get registry() {
    return this._registry;
  }
  get validateDepsOnRegister() {
    return this._validateDepsOnRegister;
  }
  freeze() {
    this._frozen = true;
  }
  async getInstance(moniker, { start = true, labels } = {}) {
    return assertEx9(
      await this.tryGetInstance(moniker, { start, labels }),
      () => `No provider instance for the supplied config moniker [${moniker}]${labels ? ` & labels [${JSON.stringify(labels)}]` : ""} could be created`
    );
  }
  has(moniker) {
    return Object.hasOwn(this._registry, moniker);
  }
  /**
   * Locates a provider factory that matches the supplied moniker and labels
   * @param moniker The config moniker for the provider
   * @param labels The labels for the provider factory
   * @returns A provider factory that matches the supplied moniker and labels or throws if one is not found
   */
  locate(moniker, labels) {
    return assertEx9(
      this.tryLocate(moniker, labels),
      () => `No module factory for the supplied config moniker [${moniker}]${labels ? ` & labels [${JSON.stringify(labels)}]` : ""} registered`
    );
  }
  /**
   * Registers a single module factory (with optional tags) with the locator
   * @param factory The factory to register
   * @param labels The labels for the module factory
   */
  register(factory, labels, primary = false) {
    assertEx9(!this._frozen, () => "Cannot register a module factory after the locator has been frozen");
    if (this.validateDepsOnRegister) {
      const missingDeps = factory.dependencies.filter((dep) => !this.registered(dep));
      assertEx9(missingDeps.length === 0, () => `Cannot register module factory [${factory.uniqueId.description}] due to missing dependencies: ${missingDeps.join(", ")}`);
    }
    registerCreatableProviderFactory(this._registry, factory, labels, primary);
    return this;
  }
  /**
   * Registers multiple module factories with the locator
   * @param factories The factories to register
   */
  registerMany(factories) {
    for (const factory of factories) {
      this.register(factory);
    }
    return this;
  }
  registered(moniker) {
    return Object.hasOwn(this.registry, moniker) || (this._parent?.registered(moniker) ?? false);
  }
  async tryGetInstance(moniker, { start = true, labels } = {}) {
    const resolvedParams = { context: this.context };
    const factory = this.tryLocate(moniker, labels);
    if (factory !== void 0) {
      if (Object.hasOwn(this.context.singletons, factory.uniqueId)) {
        return this.context.singletons[factory.uniqueId];
      }
      this.logger?.debug(`Creating provider instance for moniker [${moniker}]${labels ? ` with labels [${JSON.stringify(labels)}]` : ""} using factory [${factory.uniqueId.description}]`);
      const result = await factory.getInstance(resolvedParams, { start });
      this.context.singletons[factory.uniqueId] = result;
      return result;
    }
  }
  /**
   * Tries to locate a module factory that matches the supplied moniker and labels
   * @param moniker The config moniker for the module
   * @param labels The labels for the module factory
   * @returns A module factory that matches the supplied moniker and labels or undefined
   */
  tryLocate(moniker, labels) {
    const result = (labels ? this._registry[moniker]?.filter(hasLabels).find((factory) => hasAllLabels(factory?.labels, labels)) ?? this._registry[moniker]?.[0] : this._registry[moniker]?.[0]) ?? this._parent?.tryLocate(moniker, labels);
    return result;
  }
  validateDependencies(recursive = false) {
    if (recursive) {
      this._parent?.validateDependencies();
    }
    for (const moniker in this.registry) {
      for (const factory of this.registry[moniker] ?? []) {
        const missingDeps = factory.dependencies.filter((dep) => !this.registered(dep));
        assertEx9(missingDeps.length === 0, () => `Module factory [${factory.uniqueId.description}] is missing dependencies: ${missingDeps.join(", ")}`);
      }
    }
  }
};

// src/modules/protocol-sdk/_internal/context/getTestProviderContext.ts
function getTestProviderContext(config) {
  const singletons = {};
  const caches = {};
  const locator = new ProviderFactoryLocator({
    config,
    singletons,
    caches,
    logger: console
  });
  return locator.context;
}

// src/modules/protocol-sdk/config/Actor.ts
import {
  zodAsFactory as zodAsFactory2,
  zodIsFactory as zodIsFactory2,
  zodToFactory as zodToFactory2
} from "@ariestools/sdk";
import { globalRegistry as globalRegistry8, z as z12 } from "zod/mini";

// src/modules/protocol-sdk/config/LocatorConfigFields.ts
import { z as z11 } from "zod/mini";

// src/modules/protocol-sdk/config/Chain.ts
import { HexZod } from "@ariestools/sdk";
import { XyoAddressZod } from "@xyo-network/sdk";
import { globalRegistry, z } from "zod/mini";
var ChainConfigZod = z.object({
  id: z.optional(HexZod).register(globalRegistry, {
    description: "The unique identifier for the chain. Should be the staking contract address for contract-backed chains.",
    title: "chain.id",
    type: "string"
  }),
  genesisRewardAddress: z.optional(XyoAddressZod).register(globalRegistry, {
    description: "Address to send the initial genesis rewards to, if a new chain is being created.",
    title: "chain.genesisRewardAddress",
    type: "Address"
  }),
  deploymentBlock: z.optional(z.coerce.number()).register(globalRegistry, {
    description: "Block number on the backing EVM chain where the staking contract was deployed. When omitted, viewers auto-detect it via a getCode binary search (archive RPC) with a date-estimate fallback.",
    title: "chain.deploymentBlock",
    type: "number"
  })
});

// src/modules/protocol-sdk/config/connections/Connection.ts
import { globalRegistry as globalRegistry3, z as z4 } from "zod";

// src/modules/protocol-sdk/config/connections/Mongo.ts
import { globalRegistry as globalRegistry2, z as z2 } from "zod";
var MongoConfigZod = z2.object({
  // TODO: Create from other arguments
  connectionString: z2.string().nonempty().optional().register(globalRegistry2, {
    description: "MongoDB connection string",
    title: "storage.mongo.connectionString",
    type: "string"
  }),
  database: z2.string().nonempty().optional().register(globalRegistry2, {
    description: "MongoDB database name",
    title: "storage.mongo.database",
    type: "string"
  }),
  domain: z2.string().nonempty().optional().register(globalRegistry2, {
    description: "MongoDB domain",
    title: "storage.mongo.domain",
    type: "string"
  }),
  password: z2.string().nonempty().optional().register(globalRegistry2, {
    description: "MongoDB password",
    title: "storage.mongo.password",
    type: "string"
  }),
  username: z2.string().nonempty().optional().register(globalRegistry2, {
    description: "MongoDB username",
    title: "storage.mongo.username",
    type: "string"
  })
});

// src/modules/protocol-sdk/config/connections/S3.ts
import { z as z3 } from "zod";
var S3BucketConfigZod = z3.object({
  accessKeyId: z3.string().nonempty().optional().describe("S3-compatible access key id for this bucket (overrides the shared default)"),
  accountId: z3.string().nonempty().optional().describe("Account id for this bucket; on Cloudflare R2 it forms the endpoint (overrides the shared default)"),
  bucket: z3.string().nonempty().optional().describe("S3-compatible bucket name"),
  endpoint: z3.string().nonempty().optional().describe("S3-compatible API endpoint for reads and writes; when omitted, derived from accountId as a Cloudflare R2 endpoint"),
  prefix: z3.string().nonempty().optional().describe("Optional key prefix within the bucket"),
  readUrl: z3.string().nonempty().optional().describe("Public HTTP/CDN base URL for anonymous reads of this bucket"),
  secretAccessKey: z3.string().nonempty().optional().describe("S3-compatible secret access key for this bucket (overrides the shared default)")
});

// src/modules/protocol-sdk/config/connections/Connection.ts
var LmdbConnectionConfigZod = z4.object({
  access: z4.enum(["read", "write"]).optional().register(globalRegistry3, {
    description: "Access mode for this LMDB connection (read or write)",
    title: "connections.lmdb.access",
    type: "string"
  }),
  root: z4.string().register(globalRegistry3, {
    description: "Root directory for local LMDB storage",
    title: "connections.lmdb.root",
    type: "string"
  }),
  store: z4.string().optional().register(globalRegistry3, {
    description: "Logical store name within the LMDB root (e.g. finalized-chain, mempool)",
    title: "connections.lmdb.store",
    type: "string"
  }),
  type: z4.literal("lmdb")
}).describe("LMDB local storage connection");
var MongoConnectionConfigZod = z4.object({
  type: z4.literal("mongo"),
  connectionString: MongoConfigZod.shape.connectionString,
  database: MongoConfigZod.shape.database,
  domain: MongoConfigZod.shape.domain,
  password: MongoConfigZod.shape.password,
  username: MongoConfigZod.shape.username,
  collection: z4.string().optional().register(globalRegistry3, {
    description: "MongoDB collection this connection routes to (e.g. the chain index)",
    title: "connections.mongo.collection",
    type: "string"
  })
}).describe("MongoDB storage connection");
var RpcConnectionConfigZod = z4.object({
  type: z4.literal("rpc"),
  protocol: z4.string().default("http").register(globalRegistry3, {
    description: "Protocol for the RPC connection (http or postMessage)",
    title: "connections.rpc.protocol",
    type: "string"
  }),
  url: z4.string().optional().register(globalRegistry3, {
    description: "URL for the Chain RPC API (http protocol)",
    title: "connections.rpc.url",
    type: "string"
  }),
  networkId: z4.string().optional().register(globalRegistry3, {
    description: "Network ID for the postMessage RPC connection",
    title: "connections.rpc.networkId",
    type: "string"
  }),
  sessionId: z4.string().optional().register(globalRegistry3, {
    description: "Session ID for the postMessage RPC connection",
    title: "connections.rpc.sessionId",
    type: "string"
  })
}).describe("XL1 JSON-RPC connection");
var RestConnectionConfigZod = z4.object({
  type: z4.literal("rest"),
  baseUrl: z4.string().register(globalRegistry3, {
    description: "HTTP base URL for REST reads",
    title: "connections.rest.baseUrl",
    type: "string"
  })
}).describe("HTTP REST read connection");
var S3ConnectionConfigZod = S3BucketConfigZod.extend({
  type: z4.literal("s3"),
  accessKeyId: z4.string().optional(),
  accountId: z4.string().optional(),
  secretAccessKey: z4.string().optional()
}).describe("S3-compatible object storage connection");
var EvmRpcConnectionConfigZod = z4.object({
  type: z4.literal("evm-rpc"),
  url: z4.string().register(globalRegistry3, {
    description: "EVM JSON-RPC URL",
    title: "connections.evm-rpc.url",
    type: "string"
  }),
  chainId: z4.string().optional().register(globalRegistry3, {
    description: "EVM chain ID for this RPC endpoint; auto-detected from the endpoint when omitted",
    title: "connections.evm-rpc.chainId",
    type: "string"
  }),
  eventQueryBlockChunkSize: z4.coerce.number().optional().register(globalRegistry3, {
    description: "Fixed max blocks per eth_getLogs call against this endpoint; when omitted, consumers adapt to the provider's advertised range limit",
    title: "connections.evm-rpc.eventQueryBlockChunkSize",
    type: "number"
  })
}).describe("EVM JSON-RPC connection");
var MemoryConnectionConfigZod = z4.object({ type: z4.literal("memory") }).describe("In-process memory connection");
var ConnectionConfigZod = z4.discriminatedUnion("type", [
  LmdbConnectionConfigZod,
  MongoConnectionConfigZod,
  RpcConnectionConfigZod,
  RestConnectionConfigZod,
  S3ConnectionConfigZod,
  EvmRpcConnectionConfigZod,
  MemoryConnectionConfigZod
]);
var ConnectionsConfigZod = z4.record(z4.string(), ConnectionConfigZod).default({});

// src/modules/protocol-sdk/config/Log.ts
import { LogLevel } from "@ariestools/sdk";
import { globalRegistry as globalRegistry4, z as z5 } from "zod";
var LogLevelNames = Object.keys(LogLevel);
var LogConfigZod = z5.object({
  logLevel: z5.enum(LogLevelNames).default("info").register(globalRegistry4, {
    choices: LogLevelNames,
    default: "info",
    description: "Desired process verbosity",
    title: "logLevel",
    type: "string"
  }),
  silent: z5.boolean().default(false).register(globalRegistry4, {
    default: false,
    description: "Whether to run in silent mode",
    title: "silent",
    type: "boolean"
  })
});

// src/modules/protocol-sdk/config/ProviderBinding.ts
import { globalRegistry as globalRegistry5, z as z6 } from "zod";
var ProviderBindingConfigZod = z6.object({
  connection: z6.string().optional().register(globalRegistry5, {
    description: "Named connection from the top-level connections map",
    title: "providerBindings.connection",
    type: "string"
  }),
  provider: z6.string().optional().register(globalRegistry5, {
    description: "Winning provider descriptor id when config is compile-resolved",
    title: "providerBindings.provider",
    type: "string"
  })
}).describe("Provider connection binding");
var ProviderBindingsConfigZod = z6.record(z6.string(), ProviderBindingConfigZod).default({});

// src/modules/protocol-sdk/config/Providers.ts
import z8 from "zod";

// src/modules/protocol-sdk/config/Provider.ts
import {
  zodAsFactory,
  zodIsFactory,
  zodToFactory
} from "@ariestools/sdk";
import { z as z7 } from "zod";
var ProviderConfigZod = z7.object({
  moniker: z7.string(),
  labels: z7.array(z7.string()).optional()
}).describe("Configuration for a Provider");
var isProviderConfig = zodIsFactory(ProviderConfigZod);
var asProviderConfig = zodAsFactory(ProviderConfigZod, "asProviderConfig");
var toProviderConfig = zodToFactory(ProviderConfigZod, "toProviderConfig");

// src/modules/protocol-sdk/config/Providers.ts
var ProvidersConfigZod = z8.array(
  ProviderConfigZod.loose()
).describe("Configuration for providers").default([]);

// src/modules/protocol-sdk/config/Telemetry.ts
import { globalRegistry as globalRegistry6, z as z9 } from "zod";
var MetricsScrapeConfigZod = z9.object({
  path: z9.string().default("/metrics").register(globalRegistry6, {
    default: "/metrics",
    description: "Path for the metrics scrape endpoint",
    title: "telemetry.metrics.scrape.path",
    type: "string"
  }),
  port: z9.coerce.number().int().nonnegative().optional().register(globalRegistry6, {
    description: "Port for the metrics scrape endpoint (0 disables the scrape endpoint)",
    title: "telemetry.metrics.scrape.port",
    type: "number"
  })
}).describe("Metrics scrape configuration");
var MetricsConfigZod = z9.object({ scrape: MetricsScrapeConfigZod }).describe("Metrics configuration options");
var OpenTelemetryConfigZod = z9.object({
  // OpenTelemetry options
  otlpEndpoint: z9.url().optional().register(globalRegistry6, {
    description: "OTLP endpoint for exporting telemetry data",
    title: "telemetry.otel.otlpEndpoint",
    type: "string"
  })
});
var TelemetryConfigZod = z9.object({
  // Metrics configuration
  metrics: MetricsConfigZod.optional().describe("Metrics configuration"),
  // OpenTelemetry configuration
  otel: OpenTelemetryConfigZod.optional().describe("OpenTelemetry configuration")
}).describe("Telemetry configuration options");

// src/modules/protocol-sdk/config/Validation.ts
import { SignerAuthorizationZod } from "@xyo-network/xl1-protocol/validation";
import { globalRegistry as globalRegistry7, z as z10 } from "zod";

// src/modules/protocol-sdk/primitives/block/rate/blockRate.ts
import { isDefined as isDefined5, isFalsy } from "@ariestools/sdk";
import { asXL1BlockRange } from "@xyo-network/xl1-protocol/protocol-lib";

// src/modules/protocol-sdk/primitives/block/rate/timeHelpers.ts
import { assertEx as assertEx10, isDefined as isDefined4 } from "@ariestools/sdk";
var rateMultipliers = {
  millis: 1,
  seconds: 1e3,
  minutes: 1e3 * 60,
  hours: 1e3 * 60 * 60,
  days: 1e3 * 60 * 60 * 24,
  weeks: 1e3 * 60 * 60 * 24 * 7
};
var timeDurations = (timeInMs) => ({
  millis: timeInMs,
  seconds: timeInMs / 1e3,
  minutes: timeInMs / (1e3 * 60),
  hours: timeInMs / (1e3 * 60 * 60),
  days: timeInMs / (1e3 * 60 * 60 * 24),
  weeks: timeInMs / (1e3 * 60 * 60 * 24 * 7)
});
var getTimeConfigInMilliseconds = (timeConfig) => {
  const assertedTimeConfig = assertEx10(isDefined4(timeConfig) ? timeConfig : void 0, () => "Time configuration must be provided");
  let totalMilliseconds = 0;
  if ("years" in assertedTimeConfig) {
    totalMilliseconds += assertedTimeConfig.years * 31536e6;
    return totalMilliseconds;
  }
  if ("months" in assertedTimeConfig) {
    totalMilliseconds += assertedTimeConfig.months * 2592e6;
    return totalMilliseconds;
  }
  if ("weeks" in assertedTimeConfig) {
    totalMilliseconds += assertedTimeConfig.weeks * 6048e5;
    return totalMilliseconds;
  }
  if ("days" in assertedTimeConfig) {
    totalMilliseconds += assertedTimeConfig.days * 864e5;
    return totalMilliseconds;
  }
  if ("hours" in assertedTimeConfig) {
    totalMilliseconds += assertedTimeConfig.hours * 36e5;
    return totalMilliseconds;
  }
  if ("minutes" in assertedTimeConfig) {
    totalMilliseconds += assertedTimeConfig.minutes * 6e4;
    return totalMilliseconds;
  }
  return totalMilliseconds;
};

// src/modules/protocol-sdk/primitives/block/rate/blockRate.ts
var blockRate = (startBlock, endBlock, timeUnit) => {
  const startingBlock = startBlock[0];
  const endingBlock = endBlock[0];
  const heightDifference = endingBlock.block - startingBlock.block;
  const timeDifference = endingBlock.$epoch - startingBlock.$epoch;
  if (timeDifference === 0) {
    throw new Error("Time difference must be greater than 0");
  }
  const rate = heightDifference / timeDifference;
  const timeUnitValue = isDefined5(timeUnit) ? timeUnit : "millis";
  const returnedTimeDifference = isDefined5(timeUnit) ? timeDurations(timeDifference)[timeUnit] : timeDifference;
  const timePerBlock = returnedTimeDifference / heightDifference;
  return {
    range: asXL1BlockRange([startingBlock.block, endingBlock.block], true),
    span: heightDifference,
    rate: isDefined5(timeUnit) ? rate * rateMultipliers[timeUnit] : rate,
    timeUnit: timeUnitValue,
    timeDifference: returnedTimeDifference,
    timePerBlock
  };
};
var getBlockRateBlocks = async (viewer, startBlockHeight, endBlockHeight) => {
  if (endBlockHeight <= startBlockHeight) {
    throw new Error(`End block height must be greater than start block height [start=${startBlockHeight}, end=${endBlockHeight}]`);
  }
  const startingBlock = await viewer.blockByNumber(startBlockHeight);
  const endingBlock = await viewer.blockByNumber(endBlockHeight);
  if (isFalsy(startingBlock) || isFalsy(endingBlock)) {
    throw new Error("Could not retrieve blocks for speed calculation");
  }
  return { startingBlock, endingBlock };
};
var calculateBlockRate = async (viewer, range, timeUnit) => {
  const [startBlockHeight, endBlockHeight] = range;
  const { startingBlock, endingBlock } = await getBlockRateBlocks(
    viewer,
    startBlockHeight,
    endBlockHeight
  );
  return blockRate(startingBlock, endingBlock, timeUnit);
};

// src/modules/protocol-sdk/primitives/block/rate/stepRate.ts
import { assertEx as assertEx11 } from "@ariestools/sdk";
import {
  asXL1BlockRange as asXL1BlockRange2,
  isValidStep,
  StepSizes as StepSizes4
} from "@xyo-network/xl1-protocol/protocol-lib";
var stepRate = async (viewer, start, step, count = 1, timeUnit) => {
  const end = start + step * count;
  const range = asXL1BlockRange2([start, end], true);
  return await calculateBlockRate(viewer, range, timeUnit);
};
var calculateStepSizeRate = async (viewer, start, stepIndex, count = 1, timeUnit) => {
  assertEx11(isValidStep(stepIndex), () => `Invalid step index: ${stepIndex}`);
  const step = StepSizes4[stepIndex];
  return await stepRate(viewer, start, step, count, timeUnit);
};

// src/modules/protocol-sdk/primitives/block/rate/timeRate.ts
import {
  assertEx as assertEx12,
  isDefined as isDefined6,
  isDefinedNotNull
} from "@ariestools/sdk";
import { asXL1BlockNumber as asXL1BlockNumber7, asXL1BlockRange as asXL1BlockRange3 } from "@xyo-network/xl1-protocol/protocol-lib";
var DEFAULT_TOLERANCE_MS = 3e4;
var DEFAULT_MAX_ATTEMPTS = 10;
var calculateTimeRate = async (viewer, timeConfig, startBlockNumber, timeUnit, toleranceMs = DEFAULT_TOLERANCE_MS, maxAttempts = DEFAULT_MAX_ATTEMPTS) => {
  assertEx12(Object.keys(timeConfig ?? {}).length === 1, () => "Only one time unit should be specified in timeConfig");
  const startBlock = isDefinedNotNull(startBlockNumber) ? await viewer.blockByNumber(startBlockNumber) : null;
  const currentBlockResult = await viewer.currentBlock();
  const blockResult = isDefinedNotNull(startBlock) ? startBlock : currentBlockResult;
  const resolvedStartBlock = blockResult[0];
  const timeInMilliseconds = getTimeConfigInMilliseconds(timeConfig);
  assertEx12(timeInMilliseconds > 0, () => "Time duration must be greater than zero");
  const blocksPerMillisecondRate = 1 / (12 * 1e3);
  const initialBlocksInDuration = Math.floor(blocksPerMillisecondRate * timeInMilliseconds);
  const endBlockNumber = await findEndBlockRecursive(
    viewer,
    resolvedStartBlock,
    timeInMilliseconds,
    initialBlocksInDuration,
    toleranceMs,
    maxAttempts
  );
  return await calculateBlockRate(
    viewer,
    asXL1BlockRange3([endBlockNumber, resolvedStartBlock.block], true),
    timeUnit
  );
};
var findEndBlockRecursive = async (viewer, startBlock, targetTimeMs, estimatedBlocksBack, toleranceMs, attemptsRemaining) => {
  assertEx12(attemptsRemaining >= 0, () => "Maximum attempts reached while searching for end block");
  const startBlockEpoch = startBlock.$epoch;
  const estimatedEndBlockNumber = asXL1BlockNumber7(startBlock.block - estimatedBlocksBack, true);
  if (estimatedEndBlockNumber < 0) {
    throw new Error("Estimated end block number is less than zero");
  }
  const endBlock = await viewer.blockByNumber(estimatedEndBlockNumber);
  const resolvedEndBlock = assertEx12(
    isDefined6(endBlock?.[0]) ? endBlock[0] : void 0,
    () => `Could not retrieve block ${estimatedEndBlockNumber} for time rate calculation`
  );
  const endBlockEpoch = resolvedEndBlock.$epoch;
  if (!Number.isFinite(startBlockEpoch) || !Number.isFinite(endBlockEpoch)) {
    throw new TypeError("Block has missing or invalid $epoch");
  }
  const actualTimeDifference = startBlockEpoch - endBlockEpoch;
  if (actualTimeDifference === 0) {
    throw new Error("Start and end blocks have identical timestamps");
  }
  const timeDelta = Math.abs(actualTimeDifference - targetTimeMs);
  if (timeDelta <= toleranceMs) {
    return resolvedEndBlock.block;
  }
  let adjustedBlocksBack;
  if (actualTimeDifference < targetTimeMs) {
    const adjustmentFactor = targetTimeMs / actualTimeDifference;
    adjustedBlocksBack = Math.floor(estimatedBlocksBack * adjustmentFactor);
  } else {
    const adjustmentFactor = actualTimeDifference / targetTimeMs;
    adjustedBlocksBack = Math.floor(estimatedBlocksBack / adjustmentFactor);
  }
  adjustedBlocksBack = Number.isFinite(adjustedBlocksBack) && adjustedBlocksBack >= 1 ? adjustedBlocksBack : 1;
  return await findEndBlockRecursive(
    viewer,
    startBlock,
    targetTimeMs,
    adjustedBlocksBack,
    toleranceMs,
    attemptsRemaining - 1
  );
};

// src/modules/protocol-sdk/primitives/state/findMostRecentBlock.ts
import { isSignedBlockBoundWitnessWithStorageMeta } from "@xyo-network/xl1-protocol/protocol-lib";
var DEFAULT_NEXT_OPTIONS = { limit: 50 };
var findMostRecentBlock = async (chainArchivist, nextOptions = DEFAULT_NEXT_OPTIONS, maxIterations = Infinity) => {
  let mostRecentBlock;
  let cursor;
  let batch;
  let iterations = 0;
  do {
    batch = await chainArchivist.next({
      ...nextOptions,
      order: "desc",
      cursor
    });
    const blocks = batch.filter(isSignedBlockBoundWitnessWithStorageMeta);
    const last = blocks?.at(0);
    if (last) {
      mostRecentBlock = last;
      break;
    }
    cursor = batch.at(-1)?._sequence;
    iterations = iterations + 1;
  } while (batch.length > 0 && iterations < maxIterations);
  return mostRecentBlock;
};

// src/modules/protocol-sdk/primitives/state/hydratedBlockByNumber.ts
import { assertEx as assertEx13, spanAsync as spanAsync2 } from "@ariestools/sdk";
async function hydratedBlockByNumber(context, blockNumber) {
  return await spanAsync2("hydratedBlockByNumber", async () => {
    if (blockNumber < 0) throw new Error(`Block number ${blockNumber} is less than 0`);
    if (blockNumber > Number.MAX_SAFE_INTEGER) throw new Error(`Block number ${blockNumber} is greater than the maximum safe integer`);
    if (blockNumber % 1 !== 0) throw new Error(`Block number ${blockNumber} is not an integer`);
    const cacheKey = String(blockNumber);
    return await withContextCacheResponse(context, "hydratedBlockByNumber", cacheKey, async () => {
      const block = assertEx13(
        await blockFromBlockNumber(context, blockNumber),
        () => `Could not find block for block number ${blockNumber}`
      );
      return await hydrateBlock(context, block._hash);
    }, { max: 2e4 });
  }, { ...context, timeBudgetLimit: 500 });
}

// src/modules/protocol-sdk/primitives/uncle/findBestUncle.ts
var DEFAULT_MIN_CANDIDATES = 1;
var DEFAULT_BACKOFF_MS = 12e4;

// src/modules/protocol-sdk/config/Validation.ts
var ValidationConfigZod = z10.object({
  signerAuthorizations: z10.array(SignerAuthorizationZod).default([]).register(globalRegistry7, {
    description: "Authorizations granting signers the right to sign for addresses derived by a given function (e.g. completed-step-reward, derived-receive). Empty = self-transfers only.",
    title: "validation.signerAuthorizations",
    type: "array"
  }),
  minCandidates: z10.coerce.number().default(DEFAULT_MIN_CANDIDATES).register(globalRegistry7, {
    default: DEFAULT_MIN_CANDIDATES,
    description: "Minimum number of uncle candidates before selecting the best uncle",
    title: "validation.minCandidates",
    type: "number"
  }),
  backoffMs: z10.coerce.number().default(DEFAULT_BACKOFF_MS).register(globalRegistry7, {
    default: DEFAULT_BACKOFF_MS,
    description: "Back-off timeout in ms. If head age exceeds this, minCandidates is ignored",
    title: "validation.backoffMs",
    type: "number"
  })
});

// src/modules/protocol-sdk/config/LocatorConfigFields.ts
var LocatorConfigFieldsZod = z11.strictObject({
  chain: z11._default(ChainConfigZod, ChainConfigZod.parse({})).check(z11.describe("Configuration for the chain")),
  log: z11._default(LogConfigZod, LogConfigZod.parse({})).check(z11.describe("Configuration for logging")),
  connections: z11._default(ConnectionsConfigZod, ConnectionsConfigZod.parse({})).check(z11.describe("Named connection profiles (rpc, rest, s3, lmdb, mongo, evm-rpc)")),
  providerBindings: z11._default(ProviderBindingsConfigZod, ProviderBindingsConfigZod.parse({})).check(z11.describe("Per-moniker provider connection bindings")),
  /**
   * @deprecated Not consumed by locator/provider resolution — registration is
   * driven by `providerBindings` + `connections` instead. Kept temporarily to
   * detect any remaining config usage before removal.
   */
  providers: z11._default(ProvidersConfigZod, ProvidersConfigZod.parse([])).check(z11.describe("Configuration for providers (deprecated, unused \u2014 use providerBindings + connections instead)")),
  telemetry: z11._default(TelemetryConfigZod, TelemetryConfigZod.parse({})).check(z11.describe("Configuration for telemetry")),
  validation: z11._default(ValidationConfigZod, ValidationConfigZod.parse({})).check(z11.describe("Configuration for validation"))
});
var LOCATOR_CONFIG_FIELD_KEYS = Object.keys(LocatorConfigFieldsZod.shape);

// src/modules/protocol-sdk/config/Actor.ts
var AccountPathZod = z12.string().check(z12.regex(
  /^(m(\/\d+'?)+|\d+'?(\/\d+'?)*)$/,
  `Invalid BIP-32 derivation path. Use either an absolute path like "m/44'/60'/0'/0/0" or a relative path like "0", "0/1", or "44'/60'/0'/0/0".`
));
var ActorConfigZod = z12.extend(LocatorConfigFieldsZod, {
  name: z12.string(),
  accountPath: z12.optional(AccountPathZod).register(globalRegistry8, {
    description: 'BIP-32 derivation path for the actor wallet. Absolute when it starts with "m/"; otherwise relative to the root wallet base path. Each actor must derive to a distinct path.',
    title: "accountPath",
    type: "string"
  })
});
var isActorConfig = zodIsFactory2(ActorConfigZod);
var asActorConfig = zodAsFactory2(ActorConfigZod, "asActorConfig");
var toActorConfig = zodToFactory2(ActorConfigZod, "toActorConfig");

// src/modules/protocol-sdk/config/Actors.ts
import { z as z13 } from "zod/mini";
var ActorsConfigZod = z13._default(
  z13.array(z13.looseObject(ActorConfigZod.shape)).check(z13.describe("Actor-specific configurations that override the base configuration when the actor is running")),
  []
);

// src/modules/protocol-sdk/config/Config.ts
import { globalRegistry as globalRegistry9, z as z14 } from "zod/mini";
var ConfigZod = z14.extend(LocatorConfigFieldsZod, {
  actors: ActorsConfigZod,
  healthCheckPort: z14.optional(z14.coerce.number()).register(globalRegistry9, {
    description: "Port for the system-wide health, readiness, and liveness endpoints (/healthz, /livez, /readyz). Set to 0 to disable.",
    title: "healthCheckPort",
    type: "number"
  }),
  strictDependencies: z14.optional(z14.boolean()).register(globalRegistry9, {
    default: false,
    description: "Require memory-backed dependencies to have explicit provider bindings instead of creating them implicitly.",
    title: "strictDependencies",
    type: "boolean"
  })
}).check(z14.describe("The complete configuration for the protocol, including global settings and actor-specific overrides"));

// src/modules/protocol-sdk/summary/primitives/blocks/blocksMaxStep.ts
var blocksMaxStep = 3;

// src/modules/protocol-sdk/summary/primitives/blocks/blocksStepSummaryFromRange.ts
import { assertEx as assertEx14, spanRootAsync } from "@ariestools/sdk";
import { isAnyPayload } from "@xyo-network/sdk";
import {
  asBlocksStepSummary,
  asXL1BlockNumber as asXL1BlockNumber8,
  BlocksStepSummarySchema,
  StepSizes as StepSizes5
} from "@xyo-network/xl1-protocol/protocol-lib";
function blocksStepSummaryKey(frameHeadHash, frameSize) {
  return `${frameHeadHash}|${frameSize}`;
}
async function blocksStepSummaryFromRange(context, semaphores, blockViewer, summaryMap, range) {
  const cacheKey = `${range[0]}|${range[1]}`;
  return await withContextCacheResponse(context, "blocksStepSummaryFromRange", cacheKey, async () => {
    return await spanRootAsync("blocksStepSummaryFromRange", async () => {
      const frameHead = assertEx14(
        await blockViewer.blockByNumber(range[1]),
        () => `Block not found for number: ${range[1]}`
      );
      const frameHeadHash = frameHead[0]._hash;
      const frameSize = range[1] - range[0] + 1;
      let result;
      if (frameSize === 1) {
        result = {
          schema: BlocksStepSummarySchema,
          hash: frameHeadHash,
          stepSize: -1,
          blocks: [frameHead]
        };
      } else {
        const step = StepSizes5.indexOf(asXL1BlockNumber8(frameSize, true));
        assertEx14(step !== -1, () => `Invalid step size: ${frameSize}. Must be one of ${StepSizes5.join(", ")}`);
        const key = blocksStepSummaryKey(frameHeadHash, frameSize);
        const summaryResult = await summaryMap.get(key);
        if (isAnyPayload(summaryResult)) {
          result = asBlocksStepSummary(summaryResult, { required: true });
        } else {
          await semaphores[step].acquire();
          try {
            const subRanges = deepCalculateFramesFromRange(range, step - 1);
            const subResults = await Promise.all(subRanges.map((subRange) => blocksStepSummaryFromRange(
              context,
              semaphores,
              blockViewer,
              summaryMap,
              subRange
            )));
            const blocks = subResults.flatMap((subResult) => subResult.blocks);
            result = {
              schema: BlocksStepSummarySchema,
              hash: frameHeadHash,
              stepSize: frameSize,
              blocks
            };
            await summaryMap.set(key, result);
          } finally {
            semaphores[step].release();
          }
        }
      }
      return result;
    }, { ...context, timeBudgetLimit: 500 });
  }, { max: 1e5 });
}

// src/modules/protocol-sdk/simple/block/SimpleBlockViewer.ts
import {
  assertEx as assertEx15,
  exists,
  isUndefined as isUndefined2
} from "@ariestools/sdk";
import {
  asSignedHydratedBlockWithHashMeta,
  asSignedHydratedBlockWithStorageMeta,
  asXL1BlockNumber as asXL1BlockNumber9,
  asXL1BlockRange as asXL1BlockRange4,
  BlockViewerMoniker,
  FinalizationViewerMoniker,
  stepSize as stepSize2,
  StepSizes as StepSizes6
} from "@xyo-network/xl1-protocol/protocol-lib";
import { Semaphore } from "async-mutex";
import { LruCacheMap as LruCacheMap2 } from "#driver-memory";

// src/modules/protocol-sdk/Archivists/ArchivistFactory.ts
import { Mutex } from "async-mutex";
var KEY_SEPARATOR = "::";
function archivistCacheKey(connectionName, archivistName) {
  return `${connectionName}${KEY_SEPARATOR}${archivistName}`;
}
var ArchivistInstanceCache = class {
  cache = /* @__PURE__ */ new Map();
  mutex = new Mutex();
  async clear() {
    await this.mutex.runExclusive(() => {
      this.cache.clear();
    });
  }
  async getOrCreate(connectionName, archivistName, create) {
    const key = archivistCacheKey(connectionName, archivistName);
    return await this.mutex.runExclusive(async () => {
      const existing = this.cache.get(key);
      if (existing !== void 0) return existing;
      const created = await create();
      this.cache.set(key, created);
      return created;
    });
  }
  has(connectionName, archivistName) {
    return this.cache.has(archivistCacheKey(connectionName, archivistName));
  }
};

// src/modules/protocol-sdk/Archivists/MemoryArchivistFactory.ts
import { MemoryArchivist as MemoryArchivist2 } from "@xyo-network/sdk";
var MemoryArchivistFactory = class _MemoryArchivistFactory {
  static cache = new ArchivistInstanceCache();
  static async connect(connectionName, _config, options) {
    const { name, max } = options;
    return await _MemoryArchivistFactory.cache.getOrCreate(
      connectionName,
      name,
      // Omit `max` when unset so the chain store inherits MemoryArchivist's default
      // (the node-backed memory fallback never capped it — a small cap would evict blocks).
      async () => await MemoryArchivist2.create({ account: "random", config: max === void 0 ? { name } : { max, name } })
    );
  }
  /** Test-only: drop all cached memory archivists so a fresh process state can be simulated. */
  static async reset() {
    await _MemoryArchivistFactory.cache.clear();
  }
};

// src/modules/protocol-sdk/Archivists/archivistFactoryRegistry.ts
var registry = /* @__PURE__ */ new Map();
function registerArchivistFactory(type, factory) {
  registry.set(type, factory);
}
function getArchivistFactory(type) {
  return registry.get(type);
}
registerArchivistFactory("memory", MemoryArchivistFactory);

// src/modules/protocol-sdk/Archivists/archivistRoles.ts
var CHAIN_ARCHIVIST_ROLE = "chain";

// src/modules/protocol-sdk/Archivists/connectArchivist.ts
async function connectArchivist(binding, options) {
  const factory = getArchivistFactory(binding.config.type);
  if (factory === void 0) {
    throw new Error(`connectArchivist: no archivist factory registered for connection type '${binding.config.type}'`);
  }
  return await factory.connect(binding.name, binding.config, options);
}

// src/modules/protocol-sdk/utils/HydratedCache.ts
import { LRUCache } from "lru-cache";
var HydratedCache = class {
  cache;
  context;
  hydrateFunction;
  constructor(context, hydrateFunction, maxCount = 2e3, ttl = Number.MAX_SAFE_INTEGER) {
    this.context = context;
    this.hydrateFunction = hydrateFunction;
    this.cache = new LRUCache({ max: maxCount, ttl });
  }
  async get(hash) {
    const existing = this.cache.get(hash);
    if (existing !== void 0) return existing;
    const block = await this.hydrateFunction(this.context, hash) ?? null;
    if (block !== null) this.cache.set(hash, block);
    return block;
  }
  has(hash) {
    return this.cache.has(hash);
  }
};

// src/modules/protocol-sdk/simple/block/SimpleBlockViewer.ts
var MIN_HEAD_POLL_INTERVAL_MS = 5e3;
var SimpleBlockViewer = class extends AbstractCreatableProvider {
  moniker = SimpleBlockViewer.defaultMoniker;
  _store;
  finalizationViewer;
  payloadCache = new LruCacheMap2({ max: 1e4 });
  signedHydratedBlockWithHashMetaCache = new LruCacheMap2({ max: 2e3, ttl: 1e3 * 60 * 60 });
  _blockStepSemaphores = StepSizes6.map(() => new Semaphore(20));
  _blocksSummaryMap;
  _headPollHash;
  _headPollInProgress = false;
  _headPollTimer = null;
  _signedHydratedBlockCache;
  get finalizedArchivist() {
    return assertEx15(this.params.finalizedArchivist, () => "finalizedArchivist is required \u2014 inject it or bind a connection");
  }
  get blocksSummaryMap() {
    this._blocksSummaryMap ??= this.params.blocksSummaryMap ?? new LruCacheMap2({ max: 32 });
    return this._blocksSummaryMap;
  }
  get headPollIntervalMs() {
    return this.params.headPollIntervalMs;
  }
  get hydratedBlockCache() {
    if (this._signedHydratedBlockCache) return this._signedHydratedBlockCache;
    const context = this.getBlockContextRead();
    this._signedHydratedBlockCache = new HydratedCache(context, async (context2, hash, maxDepth, minDepth) => {
      const result = await hydrateBlock(context2, hash, maxDepth, minDepth);
      return asSignedHydratedBlockWithStorageMeta(result, true);
    }, 2e4);
    return this._signedHydratedBlockCache;
  }
  get store() {
    return this._store;
  }
  static async paramsHandler(params) {
    const headPollIntervalMs = params.headPollIntervalMs;
    if (headPollIntervalMs !== void 0) {
      assertEx15(headPollIntervalMs >= MIN_HEAD_POLL_INTERVAL_MS, () => `headPollIntervalMs must be at least ${MIN_HEAD_POLL_INTERVAL_MS}ms`);
    }
    const connection = params.connection;
    const finalizedArchivist = params.finalizedArchivist ?? (connection ? await connectArchivist(connection, { name: CHAIN_ARCHIVIST_ROLE }) : void 0);
    return {
      ...await super.paramsHandler(params),
      blocksSummaryMap: params.blocksSummaryMap,
      finalizedArchivist: assertEx15(finalizedArchivist, () => "finalizedArchivist is required \u2014 inject it or bind a connection"),
      headPollIntervalMs
    };
  }
  async blockByHash(hash) {
    return await this.spanAsync("blockByHash", async () => {
      const cachedBlock = this.signedHydratedBlockWithHashMetaCache.get(hash);
      if (cachedBlock) {
        return cachedBlock;
      }
      const cache = this.hydratedBlockCache;
      const block = await cache.get(hash);
      if (block) {
        this.signedHydratedBlockWithHashMetaCache.set(hash, block);
      }
      return block ?? null;
    }, { ...this.context, timeBudgetLimit: 100 });
  }
  async blockByNumber(blockNumber) {
    return await this.spanAsync("blockByNumber", async () => {
      const chainContext = await this.getChainContextRead();
      if (isUndefined2(chainContext.head)) {
        return null;
      }
      return await this.blockByNumberWithContext(chainContext, blockNumber);
    }, { ...this.context, timeBudgetLimit: 100 });
  }
  async blocksByHash(hash, limit = 50) {
    return await this.spanAsync("blocksByHash", async () => {
      assertEx15(limit > 0, () => "limit must be greater than 0");
      assertEx15(limit <= 100, () => "limit must be less than 100");
      const blocks = [];
      let current = await this.blockByHash(hash);
      while (current && blocks.length < limit) {
        blocks.push(current);
        const previousHash = current[0].previous;
        if (previousHash === null) break;
        current = await this.blockByHash(previousHash);
      }
      return blocks.map((b) => asSignedHydratedBlockWithHashMeta(b, true));
    }, { ...this.context, timeBudgetLimit: 300 });
  }
  async blocksByNumber(blockNumber, limit = 50) {
    return await this.spanAsync("blocksByNumber", async () => {
      assertEx15(limit > 0, () => "limit must be greater than 0");
      assertEx15(limit <= 100, () => "limit must be less than 100");
      const chainContext = await this.getChainContextRead();
      if (isUndefined2(chainContext.head)) {
        return [];
      }
      const blocks = [];
      let current = await this.blockByNumberWithContext(chainContext, blockNumber);
      while (current && blocks.length < limit) {
        blocks.push(current);
        if (current[0].block === 0) break;
        const previousNumber = asXL1BlockNumber9(current[0].block - 1, true);
        current = await this.blockByNumberWithContext(chainContext, previousNumber);
      }
      return blocks.map((b) => asSignedHydratedBlockWithHashMeta(b, true));
    }, this.context);
  }
  async blocksByStep(stepLevel, stepIndex) {
    return await this.spanAsync("blocksByStep", async () => {
      assertEx15(Number.isSafeInteger(stepIndex) && stepIndex >= 0, () => "stepIndex must be a non-negative integer");
      const size = stepSize2(stepLevel);
      assertEx15(
        stepLevel <= blocksMaxStep,
        () => `blocksByStep does not support step levels above ${blocksMaxStep} (requested ${stepLevel})`
      );
      const chainContext = await this.getChainContextRead();
      if (isUndefined2(chainContext.head)) {
        return [];
      }
      const start = stepIndex * size;
      const end = Math.min(start + size - 1, chainContext.head.block);
      if (end < start) {
        return [];
      }
      const range = asXL1BlockRange4([start, end], { name: "blocksByStep" });
      const frames = deepCalculateFramesFromRange(range, blocksMaxStep);
      const summaries = await Promise.all(frames.map((frame) => blocksStepSummaryFromRange(this.context, this._blockStepSemaphores, this, this.blocksSummaryMap, frame)));
      const blocks = summaries.flatMap((summary) => summary.blocks);
      return blocks.map((b) => asSignedHydratedBlockWithHashMeta(b, true)).toReversed();
    }, this.context);
  }
  async chainId(blockNumber = "latest") {
    return await this.spanAsync("chainId", async () => {
      if (blockNumber === "latest") {
        const headBlock = await this.finalizationViewer.headBlock();
        return headBlock.chain;
      }
      const block = assertEx15(await this.blockByNumber(blockNumber), () => `Block not found [${blockNumber}]`);
      return block[0].chain;
    }, this.context);
  }
  async createHandler() {
    await super.createHandler();
    this.finalizationViewer = await this.locator.getInstance(FinalizationViewerMoniker);
    this._store = { chainMap: this.finalizedArchivist };
  }
  async currentBlock() {
    return await this.finalizationViewer.head();
  }
  async currentBlockHash() {
    return await this.finalizationViewer.headHash();
  }
  async currentBlockNumber() {
    return await this.finalizationViewer.headNumber();
  }
  async payloadByHash(hash) {
    const [payload] = await this.payloadsByHash([hash]);
    return payload ?? null;
  }
  async payloadsByHash(hashes) {
    let remainingHashes = [...hashes];
    const cachedPayloads = this.payloadCache.getMany(remainingHashes);
    const cachedHashes = new Set(cachedPayloads.map((p) => p._hash));
    remainingHashes = remainingHashes.filter((h) => !cachedHashes.has(h));
    const finalizedPayloads = remainingHashes.length > 0 ? await this.finalizedArchivist.get(remainingHashes) : [];
    const resultPayloads = [...cachedPayloads, ...finalizedPayloads.filter(exists)];
    for (const payload of resultPayloads) {
      this.payloadCache.set(payload._hash, payload);
    }
    return resultPayloads;
  }
  async rate(range, timeUnit) {
    return await calculateBlockRate(this, range, timeUnit);
  }
  async stepSizeRate(start, stepIndex, count = 1, timeUnit) {
    return await calculateStepSizeRate(this, start, stepIndex, count, timeUnit);
  }
  async timeDurationRate(timeConfig, startBlockNumber, timeUnit, toleranceMs, maxAttempts) {
    return await calculateTimeRate(this, timeConfig, startBlockNumber, timeUnit, toleranceMs, maxAttempts);
  }
  getBlockContextRead() {
    return {
      ...this.context,
      chainMap: this.store.chainMap
    };
  }
  async getChainContextRead() {
    const headBlock = await this.finalizationViewer.head();
    return {
      ...this.getBlockContextRead(),
      head: headBlock[0]
    };
  }
  async startHandler() {
    await super.startHandler();
    if (this.headPollIntervalMs === void 0) return;
    await this.pollHead(false);
    this.startHeadPolling();
  }
  async stopHandler() {
    this.stopHeadPolling();
    this._headPollHash = void 0;
    await super.stopHandler();
  }
  async blockByNumberWithContext(chainContext, blockNumber) {
    return asSignedHydratedBlockWithHashMeta(await hydratedBlockByNumber(chainContext, blockNumber)) ?? null;
  }
  async pollHead(emitOnChange) {
    if (this._headPollInProgress) return;
    this._headPollInProgress = true;
    try {
      const block = await this.currentBlock();
      const hash = block[0]._hash;
      if (this._headPollHash === void 0) {
        this._headPollHash = hash;
        return;
      }
      if (hash !== this._headPollHash) {
        this._headPollHash = hash;
        if (emitOnChange) {
          await this.emit("headUpdated", { block });
        }
      }
    } catch (ex) {
      this.logger?.error("Error polling block head", ex);
    } finally {
      this._headPollInProgress = false;
    }
  }
  startHeadPolling() {
    if (this.headPollIntervalMs === void 0) return;
    this.stopHeadPolling();
    this._headPollTimer = setInterval(() => {
      void this.pollHead(true);
    }, this.headPollIntervalMs);
  }
  stopHeadPolling() {
    if (!this._headPollTimer) {
      return;
    }
    clearInterval(this._headPollTimer);
    this._headPollTimer = null;
  }
};
__publicField(SimpleBlockViewer, "connectionTypes", ["lmdb", "mongo", "memory"]);
__publicField(SimpleBlockViewer, "defaultMoniker", BlockViewerMoniker);
__publicField(SimpleBlockViewer, "dependencies", [FinalizationViewerMoniker]);
__publicField(SimpleBlockViewer, "monikers", [BlockViewerMoniker]);
__publicField(SimpleBlockViewer, "surface", "node");
SimpleBlockViewer = __decorateClass([
  creatableProvider()
], SimpleBlockViewer);

// src/modules/protocol-sdk/simple/chainContractViewer/SimpleChainContractViewer.ts
import { assertEx as assertEx16 } from "@ariestools/sdk";
import { ChainContractViewerMoniker, FinalizationViewerMoniker as FinalizationViewerMoniker2 } from "@xyo-network/xl1-protocol/protocol-lib";
var SimpleChainContractViewer = class extends AbstractCreatableProvider {
  moniker = SimpleChainContractViewer.defaultMoniker;
  _finalizationViewer;
  get finalizationViewer() {
    return this._finalizationViewer;
  }
  chainId() {
    return this.finalizationViewer.chainId();
  }
  async chainIdAtBlockNumber(blockNumber) {
    return await withContextCacheResponse(this.context, "chainIdAtBlockNumber", String(blockNumber), async () => {
      let chainId = this.chainId();
      let contractViewer = this;
      let forkedAtBlockNumber = await contractViewer.forkedAtBlockNumber();
      while (forkedAtBlockNumber !== null && blockNumber <= forkedAtBlockNumber) {
        contractViewer = assertEx16(await contractViewer.forkedChainContractViewer());
        forkedAtBlockNumber = await contractViewer.forkedAtBlockNumber();
        chainId = await contractViewer.chainId();
      }
      return chainId;
    });
  }
  async createHandler() {
    this._finalizationViewer = await this.locator.getInstance(FinalizationViewerMoniker2);
    return await super.createHandler();
  }
  forkedAtBlockNumber() {
    return this.params.forkedAtBlockNumber ?? null;
  }
  forkedAtHash() {
    return this.params.forkedAtHash ?? null;
  }
  forkedChainContractViewer() {
    return this.params.forkedChainContractViewer ?? null;
  }
  forkedChainId() {
    return this.params.forkedChainId ?? null;
  }
  minWithdrawalBlocks() {
    return this.params.minWithdrawalBlocks;
  }
  rewardsContract() {
    return this.params.rewardsContract;
  }
  stakingTokenAddress() {
    return this.params.stakingTokenAddress;
  }
};
__publicField(SimpleChainContractViewer, "connectionTypes", ["lmdb", "mongo", "memory"]);
__publicField(SimpleChainContractViewer, "defaultMoniker", ChainContractViewerMoniker);
__publicField(SimpleChainContractViewer, "dependencies", [FinalizationViewerMoniker2]);
__publicField(SimpleChainContractViewer, "monikers", [ChainContractViewerMoniker]);
__publicField(SimpleChainContractViewer, "surface", "node");
SimpleChainContractViewer = __decorateClass([
  creatableProvider()
], SimpleChainContractViewer);

// src/modules/protocol-sdk/simple/finalization/SimpleFinalizationViewer.ts
import { assertEx as assertEx17 } from "@ariestools/sdk";
import { asSignedHydratedBlockWithStorageMeta as asSignedHydratedBlockWithStorageMeta2, FinalizationViewerMoniker as FinalizationViewerMoniker3 } from "@xyo-network/xl1-protocol/protocol-lib";
var SimpleFinalizationViewer = class extends AbstractCreatableProvider {
  moniker = SimpleFinalizationViewer.defaultMoniker;
  _chainId;
  _store;
  _signedHydratedBlockCache;
  get finalizedArchivist() {
    return assertEx17(this.params.finalizedArchivist, () => "finalizedArchivist is required \u2014 inject it or bind a connection");
  }
  get hydratedBlockCache() {
    if (this._signedHydratedBlockCache) return this._signedHydratedBlockCache;
    const context = this.getBlockContextRead();
    this._signedHydratedBlockCache = new HydratedCache(context, async (store, hash, maxDepth, minDepth) => {
      const result = await hydrateBlock(context, hash, maxDepth, minDepth);
      return asSignedHydratedBlockWithStorageMeta2(result, true);
    }, 200);
    return this._signedHydratedBlockCache;
  }
  get store() {
    return this._store;
  }
  static async paramsHandler(params) {
    const connection = params.connection;
    const finalizedArchivist = params.finalizedArchivist ?? (connection ? await connectArchivist(connection, { name: CHAIN_ARCHIVIST_ROLE }) : void 0);
    return {
      ...await super.paramsHandler(params),
      finalizedArchivist: assertEx17(finalizedArchivist, () => "finalizedArchivist is required \u2014 inject it or bind a connection")
    };
  }
  chainId() {
    return this._chainId;
  }
  async createHandler() {
    await super.createHandler();
    const finalizedArchivist = this.finalizedArchivist;
    const mostRecentBlock = await findMostRecentBlock(finalizedArchivist);
    this._chainId = assertEx17(this.config.chain.id ?? mostRecentBlock?.chain, () => "chain.id is required if empty archivist");
    this._store = { chainMap: finalizedArchivist };
  }
  async head() {
    return await this.spanAsync("head", async () => {
      const currentHead = assertEx17(await this.getCurrentHead(), () => "Could not find most recent block [currentBlock]");
      const cache = this.hydratedBlockCache;
      const block = await cache.get(currentHead._hash);
      if (!block) {
        this.logger?.error(`Could not find current block with hash ${currentHead._hash}`);
      }
      return assertEx17(block, () => "Could not find current block");
    }, this.context);
  }
  async headBlock() {
    const headBlock = await this.head();
    return headBlock[0];
  }
  async headHash() {
    const headBlock = await this.headBlock();
    return headBlock._hash;
  }
  async headNumber() {
    const headBlock = await this.headBlock();
    return headBlock.block;
  }
  getBlockContextRead() {
    return {
      ...this.context,
      chainMap: this.store.chainMap
    };
  }
  async getChainContextRead() {
    const headBlock = await this.head();
    return {
      ...this.getBlockContextRead(),
      head: headBlock[0]
    };
  }
  async getCurrentHead() {
    const chainArchivist = this.finalizedArchivist;
    const result = assertEx17(await findMostRecentBlock(chainArchivist), () => "Could not find most recent block [getCurrentHead]");
    assertEx17(result?.chain === this._chainId, () => "Chain ID does not match head block chain ID");
    return result;
  }
};
__publicField(SimpleFinalizationViewer, "connectionTypes", ["lmdb", "mongo", "memory"]);
__publicField(SimpleFinalizationViewer, "defaultMoniker", FinalizationViewerMoniker3);
__publicField(SimpleFinalizationViewer, "dependencies", []);
__publicField(SimpleFinalizationViewer, "monikers", [FinalizationViewerMoniker3]);
__publicField(SimpleFinalizationViewer, "surface", "node");
SimpleFinalizationViewer = __decorateClass([
  creatableProvider()
], SimpleFinalizationViewer);

// src/modules/protocol-sdk/test/getSimpleBlockViewerLocator.ts
async function getTestSimpleBlockViewerLocator({
  minWithdrawalBlocks = 10,
  config = ConfigZod.parse({}),
  finalizedArchivist: finalizedArchivistIn,
  rewardsContract = XYO_ZERO_ADDRESS3,
  stakingTokenAddress = XYO_ZERO_ADDRESS3
}) {
  const finalizedArchivist = finalizedArchivistIn ?? await buildRandomChainArchivist();
  const context = getTestProviderContext(config);
  context.locator.registerMany([
    SimpleChainContractViewer.factory(SimpleChainContractViewer.dependencies, {
      minWithdrawalBlocks,
      rewardsContract,
      stakingTokenAddress
    }),
    SimpleFinalizationViewer.factory(SimpleFinalizationViewer.dependencies, { finalizedArchivist }),
    SimpleBlockViewer.factory(SimpleBlockViewer.dependencies, { finalizedArchivist })
  ]);
  return context.locator;
}

// src/modules/protocol-sdk/test/getTestProviderContext.ts
function getTestProviderContext2(config) {
  return getTestProviderContext(config);
}
export {
  TestGenesisBlockRewardAddress,
  buildRandomChain,
  buildRandomChainArchivist,
  buildRandomTransaction,
  getTestProviderContext2 as getTestProviderContext,
  getTestSimpleBlockViewerLocator
};
//# sourceMappingURL=protocol-sdk.test.mjs.map
