@black-market/sdk 0.13.0 → 0.14.1

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 (53) hide show
  1. package/README.md +4 -4
  2. package/dist/lifecycle/index.d.ts +3 -1
  3. package/dist/lifecycle/index.d.ts.map +1 -1
  4. package/dist/lifecycle/index.js +3 -1
  5. package/dist/lifecycle/index.js.map +1 -1
  6. package/dist/lifecycle/lens.d.ts +409 -0
  7. package/dist/lifecycle/lens.d.ts.map +1 -0
  8. package/dist/lifecycle/lens.js +30 -0
  9. package/dist/lifecycle/lens.js.map +1 -0
  10. package/dist/lifecycle/mining.d.ts +47 -0
  11. package/dist/lifecycle/mining.d.ts.map +1 -0
  12. package/dist/lifecycle/mining.js +89 -0
  13. package/dist/lifecycle/mining.js.map +1 -0
  14. package/dist/lifecycle/planner.d.ts.map +1 -1
  15. package/dist/lifecycle/planner.js +70 -62
  16. package/dist/lifecycle/planner.js.map +1 -1
  17. package/dist/lifecycle/presets.d.ts +5 -0
  18. package/dist/lifecycle/presets.d.ts.map +1 -1
  19. package/dist/lifecycle/presets.js +5 -0
  20. package/dist/lifecycle/presets.js.map +1 -1
  21. package/dist/lifecycle/progress.d.ts +48 -0
  22. package/dist/lifecycle/progress.d.ts.map +1 -1
  23. package/dist/lifecycle/progress.js +31 -20
  24. package/dist/lifecycle/progress.js.map +1 -1
  25. package/dist/lifecycle/rpc.d.ts +6 -2
  26. package/dist/lifecycle/rpc.d.ts.map +1 -1
  27. package/dist/lifecycle/rpc.js +47 -44
  28. package/dist/lifecycle/rpc.js.map +1 -1
  29. package/dist/lifecycle/simulation.d.ts +5 -3
  30. package/dist/lifecycle/simulation.d.ts.map +1 -1
  31. package/dist/lifecycle/simulation.js +130 -109
  32. package/dist/lifecycle/simulation.js.map +1 -1
  33. package/dist/lifecycle/snapshot.d.ts +8 -0
  34. package/dist/lifecycle/snapshot.d.ts.map +1 -0
  35. package/dist/lifecycle/snapshot.js +79 -0
  36. package/dist/lifecycle/snapshot.js.map +1 -0
  37. package/dist/lifecycle/types.d.ts +15 -5
  38. package/dist/lifecycle/types.d.ts.map +1 -1
  39. package/dist/lifecycle/types.js.map +1 -1
  40. package/docs/launch-lifecycle.md +42 -20
  41. package/docs/reference.md +43 -6
  42. package/examples/README.md +2 -2
  43. package/package.json +1 -1
  44. package/src/lifecycle/index.ts +5 -1
  45. package/src/lifecycle/lens.ts +42 -0
  46. package/src/lifecycle/mining.ts +80 -0
  47. package/src/lifecycle/planner.ts +72 -58
  48. package/src/lifecycle/presets.ts +10 -0
  49. package/src/lifecycle/progress.ts +26 -16
  50. package/src/lifecycle/rpc.ts +45 -43
  51. package/src/lifecycle/simulation.ts +126 -100
  52. package/src/lifecycle/snapshot.ts +72 -0
  53. package/src/lifecycle/types.ts +15 -5
@@ -0,0 +1,89 @@
1
+ import { parseAbi } from "viem";
2
+ import { hasLifecycleV4HookPermissions, minePoolBoundHookSalt, predictPoolBoundHookAddress } from "./markets.js";
3
+ import { readLifecycleContract } from "./rpc.js";
4
+ import { LifecyclePlanningError } from "./types.js";
5
+ import { lifecycleLensSnapshot } from "./lens.js";
6
+ export const hookSaltMinerAbi = parseAbi(["function findMany((address deployer, bytes32 initCodeHash, uint256 startSalt, uint160 flags)[] searches, uint256 maxAttempts) pure returns (bytes32[] salts, address[] hooks, bool[] found)"]);
7
+ /** Read-only bounded EVM mining; every returned winner is checked with local CREATE2. */
8
+ export async function mineLifecycleHooks(options) {
9
+ const { deployments, signal, onProgress, miner, client, block } = options;
10
+ const checkActive = () => { if (signal?.aborted)
11
+ throw Object.assign(new Error("Lifecycle hook mining cancelled"), { name: "AbortError" }); };
12
+ checkActive();
13
+ if (miner === undefined)
14
+ return Promise.all(deployments.map(async (deployment) => ({ ...deployment,
15
+ ...await minePoolBoundHookSalt({ ...deployment, startSalt: BigInt(deployment.salt), signal,
16
+ onProgress: onProgress === undefined ? undefined : (progress) => onProgress({ marketIndex: deployment.marketIndex, ...progress }) }),
17
+ })));
18
+ const results = deployments.map((deployment) => ({ ...deployment }));
19
+ const lens = lifecycleLensSnapshot(client, block);
20
+ let pending = [];
21
+ for (const [index, deployment] of deployments.entries()) {
22
+ const observed = lens?.hookDeployments.find((hook) => hook.marketIndex === deployment.marketIndex);
23
+ if (observed === undefined) {
24
+ pending.push(index);
25
+ continue;
26
+ }
27
+ const predictedHook = predictPoolBoundHookAddress({ ...deployment, salt: observed.salt });
28
+ if (observed.deployer.toLowerCase() !== deployment.deployer.toLowerCase() || observed.initCodeHash.toLowerCase() !== deployment.initCodeHash.toLowerCase() ||
29
+ BigInt(observed.salt) < BigInt(deployment.salt) || observed.found && (observed.hook.toLowerCase() !== predictedHook.toLowerCase() || !hasLifecycleV4HookPermissions(predictedHook))) {
30
+ throw new LifecyclePlanningError("INVALID_MINER_RESULT", "LaunchLens hook result differs from the locally derived constructor or CREATE2 address");
31
+ }
32
+ results[index] = { ...deployment, salt: observed.salt, predictedHook };
33
+ if (!observed.found)
34
+ pending.push(index);
35
+ else
36
+ onProgress?.({ marketIndex: deployment.marketIndex, salt: observed.salt, predictedHook, attempts: BigInt(observed.salt) - BigInt(deployment.salt) + 1n });
37
+ }
38
+ while (pending.length > 0) {
39
+ checkActive();
40
+ let maxAttempts = BigInt(Math.floor(150_000 / pending.length));
41
+ for (const index of pending) {
42
+ const available = (1n << 256n) - 1n - BigInt(results[index].salt);
43
+ if (available < maxAttempts)
44
+ maxAttempts = available;
45
+ }
46
+ if (maxAttempts === 0n) {
47
+ pending = pending.filter((index) => {
48
+ const deployment = results[index];
49
+ if (BigInt(deployment.salt) !== (1n << 256n) - 1n)
50
+ return true;
51
+ const predictedHook = predictPoolBoundHookAddress(deployment);
52
+ if (!hasLifecycleV4HookPermissions(predictedHook))
53
+ throw new LifecyclePlanningError("HOOK_SALT_EXHAUSTED", "No valid hook address remains in the uint256 salt range");
54
+ results[index] = { ...deployment, predictedHook };
55
+ onProgress?.({ marketIndex: deployment.marketIndex, salt: deployment.salt, predictedHook, attempts: BigInt(deployment.salt) - BigInt(deployments[index].salt) + 1n });
56
+ return false;
57
+ });
58
+ continue;
59
+ }
60
+ const searches = pending.map((index) => ({ deployer: results[index].deployer, initCodeHash: results[index].initCodeHash, startSalt: BigInt(results[index].salt), flags: 0x1afcn }));
61
+ const [salts, hooks, found] = await readLifecycleContract(client, miner, hookSaltMinerAbi, "findMany", [searches, maxAttempts], block);
62
+ checkActive();
63
+ if (salts.length !== pending.length || hooks.length !== pending.length || found.length !== pending.length)
64
+ throw new LifecyclePlanningError("INVALID_MINER_RESULT", "Hook miner omitted a search result");
65
+ const unfinished = [];
66
+ for (const [ordinal, index] of pending.entries()) {
67
+ const deployment = results[index];
68
+ const salt = salts[ordinal];
69
+ const end = searches[ordinal].startSalt + maxAttempts;
70
+ const predictedHook = predictPoolBoundHookAddress({ ...deployment, salt });
71
+ if (found[ordinal]) {
72
+ if (BigInt(salt) < searches[ordinal].startSalt || BigInt(salt) >= end || hooks[ordinal].toLowerCase() !== predictedHook.toLowerCase() || !hasLifecycleV4HookPermissions(predictedHook))
73
+ throw new LifecyclePlanningError("INVALID_MINER_RESULT", "Hook miner returned an invalid CREATE2 salt or permission mask");
74
+ }
75
+ else {
76
+ if (BigInt(salt) !== end)
77
+ throw new LifecyclePlanningError("INVALID_MINER_RESULT", "Hook miner did not advance to the next unsearched salt");
78
+ unfinished.push(index);
79
+ }
80
+ results[index] = { ...deployment, salt, predictedHook };
81
+ onProgress?.({ marketIndex: deployment.marketIndex, salt, predictedHook, attempts: BigInt(salt) - BigInt(deployments[index].salt) + (found[ordinal] ? 1n : 0n) });
82
+ checkActive();
83
+ }
84
+ pending = unfinished;
85
+ }
86
+ checkActive();
87
+ return results;
88
+ }
89
+ //# sourceMappingURL=mining.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mining.js","sourceRoot":"","sources":["../../src/lifecycle/mining.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"planner.d.ts","sourceRoot":"","sources":["../../src/lifecycle/planner.ts"],"names":[],"mappings":"AASA,OAAO,EAA0B,KAAK,2BAA2B,EAAkN,KAAK,mBAAmB,EAAE,KAAK,oBAAoB,EAAE,KAAK,aAAa,EAAE,KAAK,iBAAiB,EAAE,KAAK,oCAAoC,EAAE,KAAK,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAuQld;wFACwF;AACxF,wBAAsB,6BAA6B,CAAC,OAAO,EAAE,oCAAoC,GAAG,OAAO,CAAC,aAAa,CAAC,CAgFzH;AAED,qGAAqG;AACrG,wBAAsB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,aAAa,CAAC,CAQnF;AA4JD;uFACuF;AACvF,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,2BAA2B,GAAG,OAAO,CAAC,oBAAoB,GAAG,SAAS,CAAC,CAqD1H;AAED;qFACqF;AACrF,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAWzG"}
1
+ {"version":3,"file":"planner.d.ts","sourceRoot":"","sources":["../../src/lifecycle/planner.ts"],"names":[],"mappings":"AASA,OAAO,EAA0B,KAAK,2BAA2B,EAAkN,KAAK,mBAAmB,EAAE,KAAK,oBAAoB,EAAE,KAAK,aAAa,EAAE,KAAK,iBAAiB,EAAE,KAAK,oCAAoC,EAAE,KAAK,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAyQld;wFACwF;AACxF,wBAAsB,6BAA6B,CAAC,OAAO,EAAE,oCAAoC,GAAG,OAAO,CAAC,aAAa,CAAC,CA+EzH;AAED,qGAAqG;AACrG,wBAAsB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,aAAa,CAAC,CAQnF;AA2ID;uFACuF;AACvF,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,2BAA2B,GAAG,OAAO,CAAC,oBAAoB,GAAG,SAAS,CAAC,CAmF1H;AAED;qFACqF;AACrF,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAWzG"}
@@ -3,9 +3,9 @@ import { ABYSS_FEE_TIERS } from "../abyss.js";
3
3
  import { assertLaunchTopologyCoverage, getTickAtSqrtRatio } from "../launch.js";
4
4
  import { launchLifecycleAbi, lifecycleAdapterAbi, lifecycleErc20Abi } from "./abi.js";
5
5
  import { hashLaunchIdentity, hashLaunchPlan, LifecycleFundingKind, LifecyclePhase, LifecycleRewardMode, LifecycleTokenKind, LIFECYCLE_MAX_REWARD_ERC20_SUPPLY, LIFECYCLE_MAX_ERC404_SUPPLY, parseLaunchPlan, serializeLaunchPlan } from "./schema.js";
6
- import { readLaunchProgress, readLifecycleHeadProgress, readLifecycleProfiles, readLifecycleTokenAtBlock, readPoolBoundHookDeployment } from "./progress.js";
7
- import { decodeAbyssLifecycleMarketConfig, decodePoolBoundV4LifecycleMarketConfig, decodeV4LifecycleMarketConfig, encodePoolBoundV4LifecycleMarketConfig, isPoolBoundV4ConfigVersion, minePoolBoundHookSalt } from "./markets.js";
8
- import { assertLifecycleBlock, assertLifecycleReadClientOpen, lifecycleFailureReason, lifecyclePinnedRpc, lifecycleStaticRpc, lifecycleRpc, lifecycleStage, readLifecycleBlock, readLifecycleChainId, readLifecycleContract, readLifecycleGasPrice, resolveLifecycleLimits, rpcHex, rpcQuantity, withLifecycleReadClient } from "./rpc.js";
6
+ import { readLaunchProgress, readLifecycleExecutionProgress, readLifecycleHeadProgress, readLifecycleProfiles, readLifecycleTokenAtBlock, readPoolBoundHookDeployment } from "./progress.js";
7
+ import { decodeAbyssLifecycleMarketConfig, decodePoolBoundV4LifecycleMarketConfig, decodeV4LifecycleMarketConfig, encodePoolBoundV4LifecycleMarketConfig, isPoolBoundV4ConfigVersion } from "./markets.js";
8
+ import { assertLifecycleReadClientOpen, lifecycleFailureReason, lifecyclePinnedRpc, lifecycleStaticRpc, lifecycleRpc, lifecycleStage, readLifecycleChainId, readLifecycleContract, readLifecycleGasPrice, resolveLifecycleLimits, rpcHex, rpcQuantity, withLifecycleReadClient } from "./rpc.js";
9
9
  import { prepareLaunchSimulation, simulateLaunchTransactions } from "./simulation.js";
10
10
  import { LifecyclePlanningError } from "./types.js";
11
11
  import { deriveKnownPoolBoundHookDeployment, protectOrderedBuyMinimums, validateBuySlippageBps } from "./calibration.js";
@@ -14,6 +14,8 @@ import { buildLaunchTransactions, packPreparationBatches } from "./transactions.
14
14
  import { assertLifecycleMarketAllocation, assertLifecycleSupplyAllocation } from "./allocations.js";
15
15
  import { assertUfgLaunchAccount, hashUfgLaunchConfig, UFG_LAUNCH_PROXY_ADDRESS } from "./ufg-config.js";
16
16
  import { buildUfgLaunchTransactions, buildUfgCancelTransaction, validateUfgLaunchPlan } from "./ufg.js";
17
+ import { readLifecyclePlanningBlock } from "./snapshot.js";
18
+ import { mineLifecycleHooks } from "./mining.js";
17
19
  function validatePlanShape(plan) {
18
20
  // Encoding checks all exact integer widths, addresses, byte strings and tuple fields.
19
21
  const commitment = hashLaunchPlan(plan);
@@ -321,32 +323,28 @@ export async function prepareAndPlanLifecycleLaunch(options) {
321
323
  throw new LifecyclePlanningError("INVALID_GAS_ENVELOPE", "Fixed final envelope changed during preparation");
322
324
  };
323
325
  const result = await withLifecycleReadClient(options.client, async (client) => {
324
- const [block, chainId] = await Promise.all([readLifecycleBlock(client), readLifecycleChainId(client)]);
326
+ const block = await readLifecyclePlanningBlock(client, draft, options.account, options.ufg !== undefined, true);
327
+ const chainId = await readLifecycleChainId(client);
325
328
  if (chainId !== draft.chainId)
326
329
  throw new LifecyclePlanningError("CHAIN_MISMATCH", "RPC chain differs from the economic plan being finalized");
327
330
  const metadata = needsMining ? await Promise.all(draft.markets.map((market, marketIndex) => isPoolBoundV4ConfigVersion(market.configVersion)
328
331
  ? readPoolBoundHookDeployment({ client, plan: draft, marketIndex }, block) : undefined)) : [];
329
332
  assertDraft();
330
333
  const markets = [...draft.markets];
331
- const minedDeployments = [];
332
- for (const [marketIndex, deployment] of metadata.entries()) {
333
- if (deployment === undefined)
334
- continue;
334
+ const minedDeployments = await mineLifecycleHooks({ client, block,
335
+ miner: getKnownLifecycleDeployment({ chainId, orchestrator: draft.orchestrator })?.hookSaltMiner,
336
+ deployments: metadata.flatMap((deployment, marketIndex) => deployment === undefined ? [] : [{ marketIndex, ...deployment }]),
337
+ signal: options.signal, onProgress: options.onProgress });
338
+ for (const mined of minedDeployments) {
335
339
  assertDraft();
336
- const mined = await minePoolBoundHookSalt({
337
- deployer: deployment.deployer, initCodeHash: deployment.initCodeHash, startSalt: BigInt(deployment.salt), signal: options.signal,
338
- onProgress: options.onProgress === undefined ? undefined : (progress) => options.onProgress?.({ marketIndex, ...progress }),
339
- });
340
+ const marketIndex = mined.marketIndex;
340
341
  const market = markets[marketIndex];
341
342
  if (!isPoolBoundV4ConfigVersion(market.configVersion))
342
343
  throw new LifecyclePlanningError("INVALID_BOUND_MARKET", "Mined market lost its explicit pool-bound version");
343
344
  markets[marketIndex] = { ...market, config: encodePoolBoundV4LifecycleMarketConfig({ ...decodePoolBoundV4LifecycleMarketConfig(market.config, market.configVersion), hookSalt: mined.salt }) };
344
- minedDeployments.push({ marketIndex, deployer: deployment.deployer, initCodeHash: deployment.initCodeHash, ...mined });
345
345
  }
346
346
  assertDraft();
347
- // Mining is local construction, not a state admission. Economic observations
348
- // start at a fresh post-mining snapshot and share it through final protection.
349
- const executionBlock = needsMining ? await readLifecycleBlock(client) : block;
347
+ const executionBlock = block;
350
348
  assertDraft();
351
349
  const price = heldEnvelope === undefined ? undefined : heldEnvelope.gasPrice ?? rpcQuantity(await readLifecycleGasPrice(client), "gas price");
352
350
  const baseFeeEnvelope = (executionBlock.baseFeePerGas ?? 0n) * 2n;
@@ -356,11 +354,12 @@ export async function prepareAndPlanLifecycleLaunch(options) {
356
354
  });
357
355
  let plan = { ...draft, markets };
358
356
  let ownedProgress;
357
+ let sizing;
359
358
  if (needsProtection) {
360
359
  // A diagnostic minimum is never returned as an admitted or executable plan.
361
360
  // Price guards, funding minima, recipients and all ordered budgets stay exact.
362
361
  const diagnosticPlan = { ...plan, buys: plan.buys.map((buy) => ({ ...buy, minTokenOut: 1n })) };
363
- const diagnostic = await lifecycleStage(client, "plan", () => planLaunchWithReads({ ...options, plan: diagnosticPlan }, client, executionBlock, undefined, true, undefined, finalEnvelope));
362
+ const diagnostic = await lifecycleStage(client, "plan", () => planLaunchWithReads({ ...options, plan: diagnosticPlan }, client, executionBlock, undefined, true, finalEnvelope));
364
363
  assertDraft();
365
364
  if (diagnostic.progress.canonical.phase !== LifecyclePhase.None || diagnostic.progress.head.phase !== LifecyclePhase.None)
366
365
  throw new LifecyclePlanningError("LAUNCH_ALREADY_STARTED", "Buy protection cannot replace an already committed launch plan");
@@ -368,8 +367,9 @@ export async function prepareAndPlanLifecycleLaunch(options) {
368
367
  // This is the real SDK-owned None observation, not an assumed new-launch
369
368
  // state. No onchain commitment existed at this exact snapshot to replace.
370
369
  ownedProgress = { ...diagnostic.progress, planHash: hashLaunchPlan(plan) };
370
+ sizing = new Map(diagnostic.simulation.steps.map((step) => [step.transactionId, step.gasRequired ?? step.gasUsed]));
371
371
  }
372
- const planned = await lifecycleStage(client, "plan", () => planLaunchWithReads({ ...options, plan }, client, executionBlock, ownedProgress, false, undefined, finalEnvelope));
372
+ const planned = await lifecycleStage(client, "plan", () => planLaunchWithReads({ ...options, plan }, client, executionBlock, ownedProgress, false, finalEnvelope, sizing));
373
373
  assertDraft();
374
374
  assertFinalPlan(planned, options.signal);
375
375
  if (planned.progress.canonical.phase !== LifecyclePhase.Active && planned.progress.canonical.phase !== LifecyclePhase.Cancelled) {
@@ -397,12 +397,12 @@ export async function planLaunch(options) {
397
397
  assertFinalPlan(result, options.signal);
398
398
  return result;
399
399
  }
400
- async function planLaunchWithReads(options, client, pinnedBlock, ownedProgress, diagnostic = false, reviewed, fixedFinalEnvelope) {
400
+ async function planLaunchWithReads(options, client, pinnedBlock, ownedProgress, diagnostic = false, fixedFinalEnvelope, sizing) {
401
401
  const { plan, account, mode, ufg } = options;
402
402
  const { commitment: planHash, marketConfigs, ufgConfigHash } = validatePlanningIntent(options);
403
403
  const launchId = hashLaunchIdentity(plan);
404
404
  const [block, chainId] = await lifecycleStage(client, "plan.context", () => Promise.all([
405
- pinnedBlock ?? readLifecycleBlock(client), readLifecycleChainId(client),
405
+ pinnedBlock ?? readLifecyclePlanningBlock(client, plan, account, ufg !== undefined), readLifecycleChainId(client),
406
406
  ]));
407
407
  if (chainId !== plan.chainId)
408
408
  throw new LifecyclePlanningError("CHAIN_MISMATCH", "RPC chain differs from the committed plan");
@@ -451,11 +451,9 @@ async function planLaunchWithReads(options, client, pinnedBlock, ownedProgress,
451
451
  hookDeployments.push({ marketIndex, ...(known?.deployment ?? await readPoolBoundHookDeployment({ client, plan, marketIndex }, block)) });
452
452
  }
453
453
  const waiting = { ...placeholder, confidence: "stateful", reason: !progress.confirmationSafe ? "Canonical confirmed progress/account nonce has not caught up with head or pending transactions; wait for the selected confirmation depth" : "Wait for canonical receipt confirmations or resolve replacement before requesting another transaction" };
454
- await assertLifecycleBlock(client, block, plan.chainId);
455
454
  return { ...planned, hookDeployments, simulation: waiting };
456
455
  }
457
456
  if (progress.canonical.phase === LifecyclePhase.Active || progress.canonical.phase === LifecyclePhase.Cancelled) {
458
- await assertLifecycleBlock(client, block, plan.chainId);
459
457
  return { ...planned, simulation: { ...placeholder, confidence: "stateful", executionProof: "proved", protocolFit: "proved", admitted: true, reason: "Canonical launch is terminal; no transaction remains" } };
460
458
  }
461
459
  // Topology is a creation policy, not a retroactive obstacle to recovery of
@@ -472,45 +470,29 @@ async function planLaunchWithReads(options, client, pinnedBlock, ownedProgress,
472
470
  const computeCap = limits.transactionGasCeiling !== undefined && limits.transactionGasCeiling < limits.executionGasCeiling ? limits.transactionGasCeiling : limits.executionGasCeiling;
473
471
  let batches = [];
474
472
  if (mode === "staged")
475
- batches = reviewed === undefined ? packPreparationBatches(plan, prepared, computeCap)
476
- : [...(prepared > 0 ? [prepared] : []), ...(prepared < plan.markets.length ? [plan.markets.length - prepared] : [])];
477
- if (reviewed !== undefined && reviewed.kind === "prepare") {
478
- // Canonical progress fixes the start; the exact held calldata fixes its span.
479
- // Never rediscover a batch or enlarge a reviewed transaction.
480
- const match = /^prepare:(\d+):(\d+)$/.exec(reviewed.id);
481
- const start = Number(match?.[1]), count = Number(match?.[2]);
482
- if (start !== prepared || !Number.isSafeInteger(count) || count <= 0 || start + count > plan.markets.length)
483
- throw new LifecyclePlanningError("REVIEWED_TRANSACTION_MISMATCH", "Reviewed preparation differs from canonical unfinished progress");
484
- batches = [...(prepared > 0 ? [prepared] : []), count, ...(start + count < plan.markets.length ? [plan.markets.length - start - count] : [])];
485
- }
473
+ batches = packPreparationBatches(plan, prepared, computeCap);
486
474
  let transactions = orderedTransactions(plan, mode, progress, funding.approvals, batches, ufg);
487
475
  if (fixedFinalEnvelope !== undefined && (transactions.length !== 1 || transactions[0].kind !== "atomic")) {
488
476
  throw new LifecyclePlanningError("INVALID_GAS_ENVELOPE", "Fixed final envelope requires one immediate atomic launch with no preceding approvals");
489
477
  }
490
- if (reviewed !== undefined) {
491
- if (!matchesReviewedNextTransaction(transactions[0], reviewed))
492
- throw new LifecyclePlanningError("REVIEWED_TRANSACTION_MISMATCH", "Reviewed transaction differs from the current canonical unfinished next step");
493
- transactions = transactions.slice(0, 1);
494
- }
495
478
  if (metadata.reasons.length > 0) {
496
- await assertLifecycleBlock(client, block, plan.chainId);
497
479
  return { ...planned, simulation: { ...placeholder, confidence: "stateful", reason: metadata.reasons.join("; "), failureCategory: "semantic" }, transactions, totalCalldataBytes: transactions.reduce((total, transaction) => total + (transaction.data.length - 2) / 2, 0) };
498
480
  }
499
- const envelope = diagnostic ? undefined : reviewed ?? fixedFinalEnvelope;
500
- const preparedSimulation = prepareLaunchSimulation({ client, planned, limits: options.limits, fork: options.fork, signal: options.signal }, block, true, envelope, fixedFinalEnvelope?.gasPrice);
481
+ const envelope = diagnostic ? undefined : fixedFinalEnvelope;
482
+ const preparedSimulation = prepareLaunchSimulation({ client, planned, limits: options.limits, fork: options.fork, signal: options.signal }, block, true, envelope, fixedFinalEnvelope?.gasPrice, sizing);
501
483
  try {
502
484
  const execute = diagnostic ? preparedSimulation.measure : (candidate) => preparedSimulation(candidate, envelope);
503
485
  let simulation = await execute(transactions);
504
486
  assertFinalPlan(planned, options.signal);
505
487
  if (mode === "staged") {
506
- // Only a measurement that consumed almost its entire legal envelope
507
- // invalidates packing estimates, including gas hidden by CREATE wrappers.
508
- while (reviewed === undefined && !simulation.admitted && simulation.failedTransactionId?.startsWith("prepare:")) {
488
+ // Only pressure at the native ceiling can invalidate packing. A smaller
489
+ // affordability/RPC/account envelope is not evidence for another wallet write.
490
+ while (!simulation.admitted && simulation.failedTransactionId?.startsWith("prepare:")) {
509
491
  const failedIndex = transactions.findIndex((transaction) => transaction.id === simulation.failedTransactionId);
510
492
  const failedTransaction = transactions[failedIndex];
511
493
  const step = simulation.steps.find((candidate) => candidate.transactionId === simulation.failedTransactionId);
512
494
  const count = failedTransaction?.marketCount ?? 0;
513
- if (count <= 1 || step?.estimate !== undefined || step?.gasUsed === undefined || step.gasLimit === undefined || step.gasUsed * 100n < step.gasLimit * 95n)
495
+ if (count <= 1 || step?.gasUsed === undefined || step.gasLimit === undefined || step.gasLimit < limits.executionGasCeiling || step.gasUsed * 100n < limits.executionGasCeiling * 95n)
514
496
  break;
515
497
  let first = 0;
516
498
  const batchIndex = batches.findIndex((batch) => { const matches = first === failedTransaction?.marketStart; first += batch; return matches; });
@@ -526,9 +508,6 @@ async function planLaunchWithReads(options, client, pinnedBlock, ownedProgress,
526
508
  else if (!diagnostic && !simulation.admitted && !(simulation.capacityConstraint === "compute" && simulation.confidence === "provisional")) {
527
509
  simulation = { ...simulation, reason: `${simulation.reason ?? "Exact atomic plan is not admitted"}; choose staged explicitly only if empty preparation can be partitioned and complete activation fits` };
528
510
  }
529
- if (reviewed !== undefined && !matchesReviewedNextTransaction(transactions[0], reviewed)) {
530
- throw new LifecyclePlanningError("REVIEWED_TRANSACTION_MISMATCH", "Reviewed transaction differs from the current canonical unfinished next step");
531
- }
532
511
  return { ...planned, simulation, transactions: attachEstimates(transactions, simulation), totalCalldataBytes: transactions.reduce((total, transaction) => total + (transaction.data.length - 2) / 2, 0) };
533
512
  }
534
513
  finally {
@@ -556,8 +535,6 @@ async function preflightNextTransaction(options, next, simulation, reviewed) {
556
535
  }, "latest"]), "submission gas estimate");
557
536
  if (estimated <= 0n || estimated > next.gas)
558
537
  throw new Error("Submission RPC gas estimate exceeds the exact reviewed envelope or is zero");
559
- if (rpcQuantity(await lifecycleRpc(submissionClient, "eth_chainId"), "submission chain ID") !== simulation.chainId)
560
- throw new Error("Active submission RPC chain changed during preflight");
561
538
  assertPlanningActive(options.signal);
562
539
  }
563
540
  catch (failure) {
@@ -581,7 +558,7 @@ export async function buildNextTransaction(options) {
581
558
  const reviewed = supplied === undefined ? undefined : Object.freeze({ id: supplied.id, kind: supplied.kind, chainId: supplied.chainId,
582
559
  from: supplied.from, to: supplied.to, data: supplied.data, value: supplied.value, gas: supplied.gas, gasPrice: supplied.gasPrice, nonce: supplied.nonce });
583
560
  const result = await withLifecycleReadClient(options.client, async (client) => {
584
- const block = await readLifecycleBlock(client);
561
+ const block = await readLifecyclePlanningBlock(client, options.planned.plan, options.planned.account, options.planned.ufg !== undefined);
585
562
  const limitSource = options.limits === undefined ? options.planned.limits : options.limits;
586
563
  if (getKnownLifecycleDeployment({ chainId: options.planned.chainId, orchestrator: options.planned.plan.orchestrator }) !== undefined && typeof limitSource !== "function") {
587
564
  await Promise.all([
@@ -590,12 +567,11 @@ export async function buildNextTransaction(options) {
590
567
  resolveLifecycleLimits({ client, account: options.planned.account, orchestrator: options.planned.plan.orchestrator, block, chainId: options.planned.chainId }, limitSource),
591
568
  ]);
592
569
  }
593
- const progress = await readLaunchProgress({ ...options, client }, block);
570
+ const progress = await readLifecycleExecutionProgress({ ...options, client }, block);
594
571
  if (progress.canonical.phase === LifecyclePhase.Active || progress.canonical.phase === LifecyclePhase.Cancelled) {
595
572
  // Only the confirmed canonical terminal phase is terminal; a head-only
596
573
  // Active observation is not, and the confirmation/nonce/receipt gates below
597
574
  // remain in force for every nonterminal case.
598
- await assertLifecycleBlock(client, block, options.planned.chainId);
599
575
  return undefined;
600
576
  }
601
577
  if (!progress.confirmationSafe)
@@ -621,16 +597,48 @@ export async function buildNextTransaction(options) {
621
597
  throw new LifecyclePlanningError("MISSING_GAS_PROOF", "Cancellation omitted its exact simulation admission", simulation);
622
598
  return preflightNextTransaction(options, next, simulation, reviewed);
623
599
  }
624
- const refreshed = await lifecycleStage(client, "plan", () => planLaunchWithReads({ client, plan: options.planned.plan, account: options.planned.account, mode: options.planned.mode, limits: options.limits === undefined ? options.planned.limits : options.limits, fork: options.fork, receipts: options.receipts, confirmations: options.confirmations ?? options.planned.confirmations, signal: options.signal,
625
- ufg: options.planned.ufg, allowTopologyGaps: options.planned.allowTopologyGaps, allowMissingPermanentTail: options.planned.allowMissingPermanentTail }, client, block, progress, false, reviewed));
626
- assertFinalPlan(refreshed, options.signal);
627
- if (!refreshed.simulation.admitted)
628
- throw new LifecyclePlanningError("PLAN_NOT_ADMITTED", refreshed.simulation.reason ?? "Remaining exact launch sequence is not admitted", refreshed.simulation);
629
- assertPlannedDeploymentBindings(options.planned, refreshed);
630
- const next = refreshed.transactions[0];
631
- if (next === undefined)
600
+ const { planned } = options;
601
+ assertFinalPlan(planned, options.signal);
602
+ const funding = progress.canonical.phase === LifecyclePhase.None
603
+ ? await readFunding(client, planned.plan, block, planned.account, planned.ufg !== undefined)
604
+ : { prerequisites: [], approvals: [] };
605
+ const prepared = progress.canonical.preparedMarkets;
606
+ let batches = [];
607
+ if (planned.mode === "staged") {
608
+ let suffixStart = prepared;
609
+ const prefix = prepared > 0 ? [prepared] : [];
610
+ if (reviewed?.kind === "prepare") {
611
+ const span = /^prepare:(\d+):(\d+)$/.exec(reviewed.id);
612
+ const first = Number(span?.[1]), count = Number(span?.[2]);
613
+ if (first !== prepared || !Number.isSafeInteger(count) || count <= 0 || first + count > planned.plan.markets.length)
614
+ throw new LifecyclePlanningError("REVIEWED_TRANSACTION_MISMATCH", "Reviewed preparation does not start at the canonical unfinished market");
615
+ prefix.push(count);
616
+ suffixStart += count;
617
+ }
618
+ const suffix = planned.transactions
619
+ .filter((transaction) => transaction.kind === "prepare" && transaction.marketStart + transaction.marketCount > suffixStart)
620
+ .map((transaction) => transaction.marketStart + transaction.marketCount - Math.max(transaction.marketStart, suffixStart));
621
+ if (suffix.length === 0 && suffixStart < planned.plan.markets.length) {
622
+ const { limits } = await resolveLifecycleLimits({ client, account: planned.account, orchestrator: planned.plan.orchestrator, block, chainId: planned.chainId }, limitSource);
623
+ const cap = limits.transactionGasCeiling !== undefined && limits.transactionGasCeiling < limits.executionGasCeiling ? limits.transactionGasCeiling : limits.executionGasCeiling;
624
+ suffix.push(...packPreparationBatches(planned.plan, suffixStart, cap).slice(suffixStart > 0 ? 1 : 0));
625
+ }
626
+ batches = [...prefix, ...suffix];
627
+ }
628
+ const candidate = orderedTransactions(planned.plan, planned.mode, progress, funding.approvals, batches, planned.ufg)[0];
629
+ if (candidate === undefined)
632
630
  return undefined;
633
- return preflightNextTransaction(options, next, refreshed.simulation, reviewed);
631
+ if (reviewed !== undefined && !matchesReviewedNextTransaction(candidate, reviewed))
632
+ throw new LifecyclePlanningError("REVIEWED_TRANSACTION_MISMATCH", "Reviewed transaction differs from the current canonical unfinished next step");
633
+ const observed = planned.simulation.executionProof === "proved" ? planned.simulation.steps.find((step) => step.transactionId === candidate.id && step.success) : undefined;
634
+ const compute = observed?.computeGasRequired;
635
+ const sizing = reviewed !== undefined || compute === undefined ? undefined : new Map([[candidate.id, compute]]);
636
+ const simulation = await simulateLaunchTransactions({ client, planned, limits: limitSource, fork: options.fork, signal: options.signal }, [candidate], block, reviewed, sizing);
637
+ assertFinalPlan(planned, options.signal);
638
+ if (!simulation.admitted)
639
+ throw new LifecyclePlanningError("PLAN_NOT_ADMITTED", simulation.reason ?? "Next exact launch transaction is not admitted", simulation);
640
+ const next = attachEstimates([candidate], simulation)[0];
641
+ return preflightNextTransaction(options, next, simulation, reviewed);
634
642
  });
635
643
  assertFinalPlan(options.planned, options.signal);
636
644
  if (result !== undefined)