@black-market/sdk 0.14.1 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/README.md +4 -3
  2. package/dist/lifecycle/authors.js +2 -2
  3. package/dist/lifecycle/authors.js.map +1 -1
  4. package/dist/lifecycle/gas-profile.d.ts +35 -0
  5. package/dist/lifecycle/gas-profile.d.ts.map +1 -0
  6. package/dist/lifecycle/gas-profile.js +183 -0
  7. package/dist/lifecycle/gas-profile.js.map +1 -0
  8. package/dist/lifecycle/index.d.ts +3 -1
  9. package/dist/lifecycle/index.d.ts.map +1 -1
  10. package/dist/lifecycle/index.js +3 -1
  11. package/dist/lifecycle/index.js.map +1 -1
  12. package/dist/lifecycle/opening-buys.d.ts +13 -0
  13. package/dist/lifecycle/opening-buys.d.ts.map +1 -0
  14. package/dist/lifecycle/opening-buys.js +171 -0
  15. package/dist/lifecycle/opening-buys.js.map +1 -0
  16. package/dist/lifecycle/planner.d.ts +2 -2
  17. package/dist/lifecycle/planner.d.ts.map +1 -1
  18. package/dist/lifecycle/planner.js +178 -163
  19. package/dist/lifecycle/planner.js.map +1 -1
  20. package/dist/lifecycle/presets.d.ts +3 -0
  21. package/dist/lifecycle/presets.d.ts.map +1 -1
  22. package/dist/lifecycle/presets.js +3 -0
  23. package/dist/lifecycle/presets.js.map +1 -1
  24. package/dist/lifecycle/progress.d.ts +1 -1
  25. package/dist/lifecycle/progress.d.ts.map +1 -1
  26. package/dist/lifecycle/progress.js +21 -20
  27. package/dist/lifecycle/progress.js.map +1 -1
  28. package/dist/lifecycle/rpc.d.ts +24 -19
  29. package/dist/lifecycle/rpc.d.ts.map +1 -1
  30. package/dist/lifecycle/rpc.js +58 -50
  31. package/dist/lifecycle/rpc.js.map +1 -1
  32. package/dist/lifecycle/simulation.d.ts +3 -4
  33. package/dist/lifecycle/simulation.d.ts.map +1 -1
  34. package/dist/lifecycle/simulation.js +98 -247
  35. package/dist/lifecycle/simulation.js.map +1 -1
  36. package/dist/lifecycle/snapshot.d.ts.map +1 -1
  37. package/dist/lifecycle/snapshot.js +1 -2
  38. package/dist/lifecycle/snapshot.js.map +1 -1
  39. package/dist/lifecycle/transactions.d.ts +19 -3
  40. package/dist/lifecycle/transactions.d.ts.map +1 -1
  41. package/dist/lifecycle/transactions.js +25 -20
  42. package/dist/lifecycle/transactions.js.map +1 -1
  43. package/dist/lifecycle/types.d.ts +53 -45
  44. package/dist/lifecycle/types.d.ts.map +1 -1
  45. package/dist/lifecycle/types.js.map +1 -1
  46. package/dist/lifecycle/ufg.d.ts.map +1 -1
  47. package/dist/lifecycle/ufg.js +3 -7
  48. package/dist/lifecycle/ufg.js.map +1 -1
  49. package/docs/launch-lifecycle.md +67 -78
  50. package/docs/lifecycle-gas-profiles.md +90 -0
  51. package/docs/reference.md +43 -45
  52. package/examples/README.md +11 -8
  53. package/examples/launch-example.ts +35 -25
  54. package/examples/launch-lifecycle-smoke.ts +5 -3
  55. package/package.json +1 -1
  56. package/src/lifecycle/authors.ts +2 -2
  57. package/src/lifecycle/gas-profile.ts +175 -0
  58. package/src/lifecycle/index.ts +3 -1
  59. package/src/lifecycle/opening-buys.ts +157 -0
  60. package/src/lifecycle/planner.ts +164 -151
  61. package/src/lifecycle/presets.ts +5 -0
  62. package/src/lifecycle/progress.ts +19 -20
  63. package/src/lifecycle/rpc.ts +56 -44
  64. package/src/lifecycle/simulation.ts +85 -231
  65. package/src/lifecycle/snapshot.ts +1 -2
  66. package/src/lifecycle/transactions.ts +33 -21
  67. package/src/lifecycle/types.ts +52 -42
  68. package/src/lifecycle/ufg.ts +3 -7
@@ -48,18 +48,18 @@ export type LifecycleLimits = {
48
48
  /** Optional tightening caps on the complete transaction gas envelope, including Nitro poster gas. */
49
49
  headroomBps?: number; chainGasLimit?: bigint; rpcGasLimit?: bigint; accountGasLimit?: bigint;
50
50
  maxCalldataBytes?: number;
51
- /** Aggregate gas-used budget for one simulation request; defaults to 50M on chain 4663. */
51
+ /** Optional aggregate gas-used policy ceiling for one simulation request; no SDK-invented default window. */
52
52
  maxSimulationGas?: bigint;
53
53
  chainId?: bigint; orchestrator?: Address; account?: Address; observedBlockNumber?: bigint; observedBlockHash?: Hash;
54
54
  /** External data fee not already charged in gas, called with exact calldata and the pinned block.
55
- * Nitro poster fees are included in gas and use the native NodeInterface instead. */
55
+ * Nitro poster fees are already included in gas, bounded locally from same-review ArbGasInfo prices. */
56
56
  estimateDataFee?: (transaction: LifecycleTransaction, context: LifecycleLimitContext) => Promise<bigint>;
57
57
  };
58
58
  export type LifecycleLimitSource = LifecycleLimits | ((context: LifecycleLimitContext) => Promise<LifecycleLimits>);
59
59
  export type ResolvedLifecycleLimits = {
60
- /** Generic EVM gas ceiling; on Nitro this is the pinned compute ceiling, not total gas. */
60
+ /** Fixed native transaction ceiling, including poster gas; caller caps may refuse but never resize it. */
61
61
  executionGasCeiling: bigint; transactionGasCeiling?: bigint; protocol: "evm" | "nitro";
62
- arbOSVersion?: bigint; maxTxComputeGas?: bigint; maxBlockComputeGas?: bigint;
62
+ arbOSVersion?: bigint;
63
63
  headroomBps: number; maxCalldataBytes?: number; maxSimulationGas?: bigint;
64
64
  blockGasLimit: bigint; chainGasLimit?: bigint; rpcGasLimit?: bigint; accountGasLimit?: bigint;
65
65
  unknownExecutionConstraints: readonly string[]; unknownConstraints: readonly string[];
@@ -78,40 +78,38 @@ export type LifecyclePostcondition =
78
78
  export type LifecycleTransaction = {
79
79
  id: string; kind: LifecycleTransactionKind; chainId: number; from: Address; to: Address; data: Hex; value: bigint;
80
80
  dependencies: readonly string[]; postconditions: readonly LifecyclePostcondition[];
81
- marketStart?: number; marketCount?: number; gas?: bigint; gasPrice?: bigint; nonce?: bigint;
81
+ marketStart?: number; marketCount?: number; gas?: bigint; gasPrice?: bigint;
82
82
  /** Exact encoded byte count; populated on SDK-built commands, including approvals. */
83
83
  calldataBytes?: number;
84
- /** Only the immediate command receives exact gas/price/estimate/admission.
85
- * Future commands must be re-sized and proved by buildNextTransaction. */
84
+ /** Only the immediate command receives its current fee and admission.
85
+ * Executable launch gas is the native ceiling; approvals leave gas to the wallet. */
86
86
  admission?: LifecycleAdmission;
87
87
  estimate?: LifecycleTransactionEstimate;
88
88
  };
89
89
  export type LifecycleTransactionEstimate = {
90
- gasUsed: bigint; gasLimit: bigint; gasPrice: bigint; executionFee: bigint; dataFee?: bigint; totalFee?: bigint;
90
+ /** Present only for measured execution; a ceiling budget never fabricates gas usage. */
91
+ gasUsed?: bigint; gasLimit: bigint; gasPrice: bigint; executionFee: bigint; dataFee?: bigint; totalFee?: bigint;
91
92
  /** Estimated poster allocation within gasLimit, never an exact compute measurement or an extra fee. */
92
93
  posterGas?: bigint; posterFee?: bigint; dataFeeIncludedInGas: boolean;
93
- feeConfidence: "execution-and-data" | "execution-only";
94
+ feeConfidence: "execution-and-data" | "execution-only" | "native-ceiling-and-data";
94
95
  };
95
96
  /** Proof scopes are independent: current execution is not guaranteed wallet submission. */
96
97
  export type LifecycleProofOutcomes = {
97
- executionProof: "proved" | "failed" | "unavailable";
98
- protocolFit: "proved" | "failed" | "unknown";
99
- transportPreflight: "not-requested" | "passed" | "failed";
98
+ executionProof: "proved" | "failed" | "unavailable" | "not-run";
99
+ protocolFit: "proved" | "failed" | "unknown" | "profiled";
100
100
  };
101
101
  export type LifecycleAdmission = LifecycleProofOutcomes & {
102
- admitted: boolean; confidence: "stateful" | "provisional";
102
+ admitted: boolean; confidence: "stateful" | "provisional" | "profiled";
103
103
  blockNumber: bigint; blockHash: Hash; account: Address; chainId: bigint;
104
104
  reason?: string; limits: ResolvedLifecycleLimits;
105
105
  };
106
106
  export type LifecycleFailureCategory = "semantic" | "capacity" | "opaque" | "source" | "postcondition" | "affordability";
107
- export type LifecycleCapacityConstraint = "compute" | "gas-envelope" | "calldata" | "simulation-gas";
107
+ export type LifecycleCapacityConstraint = "compute" | "gas-envelope" | "calldata" | "simulation-gas" | "activation";
108
108
  export type LifecycleSimulationStep = {
109
109
  transactionId: string; success: boolean; gasUsed?: bigint; gasLimit?: bigint; gasRequired?: bigint;
110
- /** Compute-only sizing observation, excluding Nitro poster gas; not admission. */
111
- computeGasRequired?: bigint;
112
110
  returnData?: Hex; error?: string; estimate?: LifecycleTransactionEstimate;
113
- /** Suffix feasibility budget only, not a transaction estimate or execution admission.
114
- * buildNextTransaction obtains a fresh poster quote and exact envelope at its turn. */
111
+ /** Suffix proof is historical and provisional; only a fresh build admits
112
+ * its immediate transaction, still at the native ceiling and current fee. */
115
113
  provisional?: boolean;
116
114
  failureCategory?: LifecycleFailureCategory; decodedError?: string;
117
115
  /** Safe failed-call facts only; native messages and error-data bytes are never copied here. */
@@ -121,17 +119,32 @@ export type LifecycleSimulationStep = {
121
119
  /** Explicit native simulator report, not inferred from gas consumption or the requested limit. */
122
120
  nativeGasCapped?: boolean;
123
121
  };
122
+ export type LifecycleOpeningBuyQuote = {
123
+ buyIndex: number; marketIndex: number; quoteAmountIn: bigint; quoteSpent: bigint;
124
+ tokenOut: bigint; sqrtPriceAfterX96: bigint;
125
+ };
126
+ /** Conservative compute bounds used for mode/capacity decisions, never gas-limit sizing.
127
+ * An upper bound above the ceiling is uncertain, not proof of impossibility. */
128
+ export type LifecycleLaunchGasBounds = {
129
+ atomicComputeGasUpperBound: bigint; activationComputeGasUpperBound: bigint;
130
+ };
131
+ export type LifecycleGasProfileEvidence = {
132
+ version: string; bounds: LifecycleLaunchGasBounds;
133
+ initialBuys: readonly LifecycleOpeningBuyQuote[];
134
+ };
124
135
  export type LifecycleSimulation = LifecycleProofOutcomes & {
125
- backend: "eth_simulateV1" | "controlled-fork" | "unavailable";
126
- /** Full successful prefix feasibility; only its immediate envelope is final. */
127
- confidence: "stateful" | "provisional"; admitted: boolean;
136
+ backend: "eth_simulateV1" | "controlled-fork" | "unavailable" | "profiled";
137
+ /** Stateful execution or versioned profile coverage; only the immediate envelope is final. */
138
+ confidence: "stateful" | "provisional" | "profiled"; admitted: boolean;
128
139
  blockNumber: bigint; blockHash: Hash; account: Address; chainId: bigint;
129
140
  steps: readonly LifecycleSimulationStep[]; limits: ResolvedLifecycleLimits;
130
- /** Unproved suffix. These transactions receive no gas, price, estimate or admission. */
141
+ /** Immediate fixed-ceiling fee budget; absent for wallet-prepared approvals. */
142
+ estimate?: LifecycleTransactionEstimate;
143
+ gasProfile?: LifecycleGasProfileEvidence;
144
+ /** Work outside the returned admission, including an RPC-cap failed suffix. */
131
145
  deferredTransactionIds: readonly string[];
132
146
  reason?: string; failedTransactionId?: string;
133
- /** Affordability can mean insufficient sizing margin, even if smaller exact
134
- * envelopes could fit. A refused RPC exposes no prefix results to refine them. */
147
+ /** A payer must reserve the native ceiling up front even if actual gas usage is lower. */
135
148
  failureCategory?: LifecycleFailureCategory; capacityConstraint?: LifecycleCapacityConstraint;
136
149
  };
137
150
  export type LifecycleFundingPrerequisite = {
@@ -152,15 +165,18 @@ export type LifecycleMarketProgress = {
152
165
  export type LifecycleReceiptReference = {
153
166
  transactionHash: Hash; replacementHash?: Hash; confirmations?: number;
154
167
  observedBlockNumber?: bigint; observedBlockHash?: Hash;
168
+ /** Actual submitted nonce from the wallet/transaction observation, never a planning guess. */
169
+ nonce?: bigint;
155
170
  };
156
171
  export type LifecycleReceiptStatus = {
157
172
  transactionHash: Hash; effectiveHash: Hash; status: "pending" | "confirmed" | "reverted" | "reorged" | "unconfirmed" | "replacement-cancelled";
158
- blockNumber?: bigint; blockHash?: Hash; confirmations?: bigint; replaced: boolean;
173
+ blockNumber?: bigint; blockHash?: Hash; confirmations?: bigint; replaced: boolean; nonce?: bigint;
159
174
  };
160
175
  export type CanonicalLaunchProgress = {
161
176
  canonical: LaunchProgressV1; blockNumber: bigint; blockHash: Hash; chainId: bigint;
162
177
  head: LaunchProgressV1; confirmationDepth: number; confirmedBlockNumber: bigint; confirmedBlockHash: Hash;
163
- confirmedAccountNonce: bigint; headAccountNonce: bigint; pendingAccountNonce: bigint; confirmationSafe: boolean;
178
+ /** Confirmed launch state only; unrelated account pending transactions do not block it. */
179
+ confirmationSafe: boolean;
164
180
  markets: readonly LifecycleMarketProgress[]; receipts: readonly LifecycleReceiptStatus[];
165
181
  token: Address; planHash: Hash; launchId: Hash;
166
182
  };
@@ -174,8 +190,8 @@ export type PlannedLaunch = {
174
190
  account: Address; chainId: bigint; mode: LaunchExecutionMode; confirmations: number;
175
191
  /** Opt-in proxy routing; the committed creator remains the proxy, account is its principal. */
176
192
  ufg?: { config: UfgLaunchConfig; configHash: Hash };
177
- /** With admitted exact proof, transactions[0] is the immediate reviewed envelope,
178
- * including nonce, gas and gasPrice. Deferred commands have no execution admission. */
193
+ /** Only transactions[0] has fresh immediate admission/fees. Launch gas is fixed
194
+ * at the native ceiling; wallet-assigned nonce and approval gas are omitted. */
179
195
  transactions: readonly LifecycleTransaction[]; prerequisites: readonly LifecycleFundingPrerequisite[];
180
196
  /** Sum of exact calldata bytes across the returned remaining commands, including approvals. */
181
197
  totalCalldataBytes: number;
@@ -188,8 +204,10 @@ export type PlannedLaunch = {
188
204
  allowTopologyGaps?: boolean; allowMissingPermanentTail?: boolean;
189
205
  };
190
206
  export type PlanLaunchOptions = {
191
- client: LifecycleRpcClient; account: Address; plan: LaunchPlanV1; mode: LaunchExecutionMode;
192
- limits?: LifecycleLimitSource; fork?: ControlledLifecycleFork; receipts?: readonly LifecycleReceiptReference[];
207
+ client: LifecycleRpcClient; account: Address; plan: LaunchPlanV1;
208
+ /** Atomic is a preference: conservative capacity may select staged before begin.
209
+ * Explicit staged and an already-started launch's recorded mode are retained. */
210
+ mode: LaunchExecutionMode; limits?: LifecycleLimitSource; fork?: ControlledLifecycleFork; receipts?: readonly LifecycleReceiptReference[];
193
211
  confirmations?: number; signal?: AbortSignal;
194
212
  /** Opt in to the pinned UFG proxy; sender must match the nonce's principal namespace. */
195
213
  ufg?: { config: UfgLaunchConfig };
@@ -198,17 +216,11 @@ export type PlanLaunchOptions = {
198
216
  /** Unstarted only: waive the funded boundary tail; all other topology checks remain required. */
199
217
  allowMissingPermanentTail?: boolean;
200
218
  };
201
- /** Explicit atomic final gas. Omitted price freezes this invocation's recommendation;
202
- * a supplied price is replayed exactly, never refreshed or silently increased. */
203
- export type LifecycleFinalEnvelope = Readonly<{ gas: bigint; gasPrice?: bigint }>;
204
219
  export type PrepareAndPlanLifecycleLaunchOptions = PlanLaunchOptions & {
205
220
  onProgress?: (progress: PoolBoundLifecyclePreparationProgress) => void;
206
- /** Protect every ordered buy from its actual diagnostic receipt output, rounded down.
207
- * Omitted preserves the caller's committed minima. Only an unstarted launch may be protected. */
221
+ /** Protect ordered buys from exact local curve outputs or native diagnostics,
222
+ * rounded down. Omitted preserves committed minima; unstarted launches only. */
208
223
  buySlippageBps?: number;
209
- /** Atomic only, with no preceding approvals. Final calldata receives one exact
210
- * validated replay, not a new gas recommendation or a larger rescue envelope. */
211
- fixedFinalEnvelope?: LifecycleFinalEnvelope;
212
224
  };
213
225
  export type BuildLaunchTransactionsOptions = {
214
226
  plan: LaunchPlanV1; mode: LaunchExecutionMode;
@@ -230,10 +242,8 @@ export type ReadLaunchProgressOptions = {
230
242
  };
231
243
  export type BuildNextTransactionOptions = ReadLaunchProgressOptions & {
232
244
  planned: PlannedLaunch; action?: "continue" | "cancel"; limits?: LifecycleLimitSource; fork?: ControlledLifecycleFork;
233
- /** Optional active submission RPC. Only the immediate next exact transaction is estimated, read-only. */
234
- submissionClient?: LifecycleRpcClient;
235
- /** Untrusted reviewed next envelope. Canonical identity and direct exact replay
236
- * prove only this immediate transaction at its held gas and gasPrice. */
245
+ /** Untrusted reviewed intent/fee. Gas differing from the native ceiling is stale;
246
+ * never resize it, bump a held fee or assign a wallet nonce. */
237
247
  reviewedTransaction?: LifecycleTransaction;
238
248
  };
239
249
  export class LifecyclePlanningError extends Error {
@@ -1,10 +1,10 @@
1
1
  import { decodeFunctionResult, encodeFunctionData, keccak256, stringToHex, zeroAddress, type Address } from "viem";
2
2
  import { lifecycleErc20Abi } from "./abi.js";
3
3
  import { ufgLaunchProxyV1Abi, ufgTreasuryFactoryV1Abi } from "./ufg-abi.js";
4
- import { buildLaunchTransactions } from "./transactions.js";
4
+ import { buildLifecycleCommands } from "./transactions.js";
5
5
  import { decodeAbyssLifecycleMarketConfig, encodeAbyssLifecycleMarketConfig, decodePoolBoundV4LifecycleMarketConfig } from "./markets.js";
6
6
  import { getKnownLifecycleProfile, KnownLifecycleProfile } from "./presets.js";
7
- import { LifecycleFundingKind, LifecycleTokenKind, LifecycleRewardMode, LifecycleMode, type LaunchPlanV1 } from "./schema.js";
7
+ import { LifecycleFundingKind, LifecycleTokenKind, LifecycleRewardMode, type LaunchPlanV1 } from "./schema.js";
8
8
  import { LifecyclePlanningError, type BuildLaunchTransactionsOptions, type LifecycleRpcClient, type LifecycleTransaction } from "./types.js";
9
9
  import { buildUfgFeeAssetPolicies, encodeUfgLaunchConfig, hashUfgLaunchConfig, isUfgProfile, UFG_DYNAMIC_ADAPTER_ID, UFG_FIXED_ADAPTER_ID, UFG_FIXED_PROFILE_ID, UFG_LAUNCH_PROXY_ADDRESS, UFG_TREASURY_FACTORY_ADDRESS, ufgPlanPrincipal, type UfgLaunchConfig } from "./ufg-config.js";
10
10
 
@@ -49,11 +49,7 @@ export function buildUfgLaunchTransactions(options: BuildUfgLaunchTransactionsOp
49
49
  const { plan, config } = options;
50
50
  const principal = ufgPlanPrincipal(plan);
51
51
  encodeUfgLaunchConfig(config);
52
- return buildLaunchTransactions(options).map((transaction) => {
53
- const data = transaction.kind === "atomic" ? encodeFunctionData({ abi: ufgLaunchProxyV1Abi, functionName: "launchAtomic", args: [plan, config] })
54
- : transaction.kind === "begin" ? encodeFunctionData({ abi: ufgLaunchProxyV1Abi, functionName: "beginLaunch", args: [plan, LifecycleMode.Staged, config] }) : transaction.data;
55
- return { ...transaction, from: principal, to: UFG_LAUNCH_PROXY_ADDRESS, data, calldataBytes: (data.length - 2) / 2 };
56
- });
52
+ return buildLifecycleCommands(options, { account: principal, config });
57
53
  }
58
54
  export function buildUfgCancelTransaction({ plan, preparedMarkets = 0 }: { plan: LaunchPlanV1; preparedMarkets?: number }): LifecycleTransaction {
59
55
  const data = encodeFunctionData({ abi: ufgLaunchProxyV1Abi, functionName: "cancelLaunch", args: [plan] });