@black-market/sdk 0.1.0 → 0.4.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 (88) hide show
  1. package/README.md +92 -20
  2. package/dist/abyss.d.ts +4 -2748
  3. package/dist/abyss.d.ts.map +1 -1
  4. package/dist/abyss.js +3 -1029
  5. package/dist/abyss.js.map +1 -1
  6. package/dist/addresses.d.ts +3 -7
  7. package/dist/addresses.d.ts.map +1 -1
  8. package/dist/addresses.js +6 -21
  9. package/dist/addresses.js.map +1 -1
  10. package/dist/auction.d.ts +2 -2
  11. package/dist/auction.d.ts.map +1 -1
  12. package/dist/auction.js +2 -2
  13. package/dist/auction.js.map +1 -1
  14. package/dist/index.d.ts +2 -0
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +2 -0
  17. package/dist/index.js.map +1 -1
  18. package/dist/launch-api.d.ts +151 -0
  19. package/dist/launch-api.d.ts.map +1 -0
  20. package/dist/launch-api.js +117 -0
  21. package/dist/launch-api.js.map +1 -0
  22. package/dist/launch.d.ts +23 -185
  23. package/dist/launch.d.ts.map +1 -1
  24. package/dist/launch.js +35 -272
  25. package/dist/launch.js.map +1 -1
  26. package/dist/lifecycle/abi.d.ts +6391 -0
  27. package/dist/lifecycle/abi.d.ts.map +1 -0
  28. package/dist/lifecycle/abi.js +335 -0
  29. package/dist/lifecycle/abi.js.map +1 -0
  30. package/dist/lifecycle/authors.d.ts +133 -0
  31. package/dist/lifecycle/authors.d.ts.map +1 -0
  32. package/dist/lifecycle/authors.js +217 -0
  33. package/dist/lifecycle/authors.js.map +1 -0
  34. package/dist/lifecycle/fork.d.ts +15 -0
  35. package/dist/lifecycle/fork.d.ts.map +1 -0
  36. package/dist/lifecycle/fork.js +36 -0
  37. package/dist/lifecycle/fork.js.map +1 -0
  38. package/dist/lifecycle/index.d.ts +10 -0
  39. package/dist/lifecycle/index.d.ts.map +1 -0
  40. package/dist/lifecycle/index.js +10 -0
  41. package/dist/lifecycle/index.js.map +1 -0
  42. package/dist/lifecycle/markets.d.ts +349 -0
  43. package/dist/lifecycle/markets.d.ts.map +1 -0
  44. package/dist/lifecycle/markets.js +186 -0
  45. package/dist/lifecycle/markets.js.map +1 -0
  46. package/dist/lifecycle/planner.d.ts +20 -0
  47. package/dist/lifecycle/planner.d.ts.map +1 -0
  48. package/dist/lifecycle/planner.js +481 -0
  49. package/dist/lifecycle/planner.js.map +1 -0
  50. package/dist/lifecycle/progress.d.ts +43 -0
  51. package/dist/lifecycle/progress.d.ts.map +1 -0
  52. package/dist/lifecycle/progress.js +449 -0
  53. package/dist/lifecycle/progress.js.map +1 -0
  54. package/dist/lifecycle/rpc.d.ts +17 -0
  55. package/dist/lifecycle/rpc.d.ts.map +1 -0
  56. package/dist/lifecycle/rpc.js +100 -0
  57. package/dist/lifecycle/rpc.js.map +1 -0
  58. package/dist/lifecycle/schema.d.ts +1068 -0
  59. package/dist/lifecycle/schema.d.ts.map +1 -0
  60. package/dist/lifecycle/schema.js +335 -0
  61. package/dist/lifecycle/schema.js.map +1 -0
  62. package/dist/lifecycle/simulation.d.ts +3 -0
  63. package/dist/lifecycle/simulation.d.ts.map +1 -0
  64. package/dist/lifecycle/simulation.js +393 -0
  65. package/dist/lifecycle/simulation.js.map +1 -0
  66. package/dist/lifecycle/types.d.ts +273 -0
  67. package/dist/lifecycle/types.d.ts.map +1 -0
  68. package/dist/lifecycle/types.js +11 -0
  69. package/dist/lifecycle/types.js.map +1 -0
  70. package/docs/launch-lifecycle.md +243 -0
  71. package/package.json +12 -3
  72. package/src/abyss.ts +3 -1059
  73. package/src/addresses.ts +9 -26
  74. package/src/auction.ts +2 -2
  75. package/src/index.ts +2 -0
  76. package/src/launch-api.ts +110 -0
  77. package/src/launch.ts +43 -411
  78. package/src/lifecycle/abi.ts +343 -0
  79. package/src/lifecycle/authors.ts +203 -0
  80. package/src/lifecycle/fork.ts +36 -0
  81. package/src/lifecycle/index.ts +9 -0
  82. package/src/lifecycle/markets.ts +205 -0
  83. package/src/lifecycle/planner.ts +396 -0
  84. package/src/lifecycle/progress.ts +378 -0
  85. package/src/lifecycle/rpc.ts +88 -0
  86. package/src/lifecycle/schema.ts +387 -0
  87. package/src/lifecycle/simulation.ts +329 -0
  88. package/src/lifecycle/types.ts +132 -0
@@ -0,0 +1,387 @@
1
+ import { decodeAbiParameters, encodeAbiParameters, keccak256, stringToHex, type Address, type Hex } from "viem";
2
+
3
+ /** Current lifecycle wire schema; deployment and admission are always explicit. */
4
+ export enum LifecycleTokenKind { ERC20, ERC404 }
5
+ export enum LifecycleRewardMode { None, Staking, Dividends }
6
+ export enum LifecycleFundingKind { ERC20, NativeWrap, Swap }
7
+ export enum LifecycleMode { Atomic, Staged }
8
+ export enum LifecyclePhase { None, Preparing, Ready, Activating, Active, Cancelled }
9
+ export enum LifecycleVenue { UniswapV4, Abyss }
10
+ export type LaunchExecutionMode = "atomic" | "staged";
11
+
12
+ export type TokenConfigV1 = {
13
+ kind: LifecycleTokenKind; rewardMode: LifecycleRewardMode; name: string; symbol: string;
14
+ supply: bigint; nftUnit: bigint; metadataURI: string; salt: Hex;
15
+ inventoryRecipient: Address; burnOnCancel: boolean;
16
+ };
17
+ export type AssetFundingV1 = {
18
+ asset: Address; amount: bigint; kind: LifecycleFundingKind; inputAsset: Address;
19
+ inputAmount: bigint; target: Address; data: Hex;
20
+ };
21
+ export type LifecycleFeeAssetPolicyV2 = { asset: Address; ownerBps: number; rewardsBps: number; burnBps: number };
22
+ export type MarketConfigV1 = {
23
+ adapterId: Hex; profileId: Hex; quoteAsset: Address; tokenBudget: bigint; configVersion: number; config: Hex;
24
+ };
25
+ export type InitialBuyV1 = {
26
+ marketIndex: number; quoteAmountIn: bigint; minTokenOut: bigint; recipient: Address; sqrtPriceLimitX96: bigint;
27
+ };
28
+ export type LaunchPlanV1 = {
29
+ chainId: bigint; orchestrator: Address; creator: Address; nonce: bigint; token: TokenConfigV1;
30
+ funding: readonly AssetFundingV1[]; feeAssets: readonly LifecycleFeeAssetPolicyV2[];
31
+ markets: readonly MarketConfigV1[]; buys: readonly InitialBuyV1[]; deadline: bigint; executorFeeBps: number;
32
+ };
33
+ export type MarketIdentityV1 = {
34
+ venue: LifecycleVenue; canonicalId: Hex; manager: Address; factory: Address; pool: Address; poolId: Hex;
35
+ profileId: Hex; currency0: Address; currency1: Address; fee: number; tickSpacing: number;
36
+ hook: Address; openingSqrtPriceX96: bigint;
37
+ };
38
+ export type PreparedMarketV1 = {
39
+ identity: MarketIdentityV1; feeSource: Address; custody: Address; mintExecutor: Address; buyExecutor: Address;
40
+ exclusions: readonly Address[]; positionCount: number;
41
+ };
42
+ export type PositionIdentityV1 = {
43
+ canonicalId: Hex; marketId: Hex; manager: Address; custody: Address; tokenId: bigint;
44
+ tickLower: number; tickUpper: number; salt: Hex; liquidity: bigint;
45
+ };
46
+ export type LaunchExecutionContextV1 = {
47
+ launchId: Hex; marketIndex: number; operation: number; adapter: Address; executor: Address; token: Address;
48
+ quoteAsset: Address; manager: Address; custody: Address; recipient: Address; amount: bigint;
49
+ };
50
+ export type LaunchProgressV1 = {
51
+ launchId: Hex; planHash: Hex; creator: Address; nonce: bigint; mode: LifecycleMode; phase: LifecyclePhase;
52
+ token: Address; feeHub: Address; rewards: Address; preparedMarkets: number; marketCount: number;
53
+ buyCount: number; positionCount: number; deadline: bigint;
54
+ };
55
+ export type LaunchReceiptV1 = {
56
+ launchId: Hex; planHash: Hex; token: Address; feeHub: Address; rewards: Address;
57
+ marketCount: number; positionCount: number; quoteSpent: readonly bigint[]; tokenOut: readonly bigint[];
58
+ };
59
+ export type AdapterRegistrationV1 = {
60
+ implementation: Address; codeHash: Hex; capabilities: bigint; configVersion: number; enabled: boolean;
61
+ };
62
+ export type ProfileRegistrationV1 = {
63
+ adapterId: Hex; configSchema: Hex; dependencyDigest: Hex; venue: Address; factory: Address; hook: Address;
64
+ capabilities: bigint; enabled: boolean;
65
+ };
66
+ export type ProfileTopologyV1 = {
67
+ hookTopology: 0 | 1 | 2; configVersion: number; hookDeployer: Address; hookCreationCodeHash: Hex;
68
+ };
69
+ export type MarketLiveStateV1 = {
70
+ sqrtPriceX96: bigint; tick: number; liquidity: bigint; publicTrading: boolean; oracleReadyAt: bigint;
71
+ };
72
+
73
+ export type LaunchBoundsV2 = {
74
+ minimumTickSpacing: number; maximumTickSpacing: number;
75
+ maximumPositions: number; maximumOracleCardinality: number; feeModeFlags: number;
76
+ };
77
+ export type LaunchGraphV2 = {
78
+ manager: Address; hookRoot: Address; oracleFactory: Address; locker: Address; collectorFactory: Address;
79
+ collectorDeployer: Address; hookDeployer: Address; coreCodeHash: Hex; managerCodeHash: Hex;
80
+ hookRuntimeCodeHash: Hex; oracleFactoryCodeHash: Hex; lockerCodeHash: Hex; collectorFactoryCodeHash: Hex;
81
+ collectorDeployerCodeHash: Hex; hookDeployerCodeHash: Hex; hookCreationCodeHash: Hex;
82
+ codeChunk0: Address; codeChunk0Hash: Hex; codeChunk1: Address; codeChunk1Hash: Hex; sharedHookSalt: Hex;
83
+ };
84
+ export type LaunchEnvelopeV2 = {
85
+ artifactDigest: Hex; reviewManifestDigest: Hex; configBoundsDigest: Hex; termsDigest: Hex;
86
+ topology: 1 | 2; configVersion: number; economicVersion: number; capabilities: bigint; flags: bigint;
87
+ callbackFlags: number; callbackMask: number; protocolTreasury: Address; protocolFeeDenominator: number;
88
+ beneficiary: Address; maximumDeveloperFeeBps: number; bounds: LaunchBoundsV2; graph: LaunchGraphV2;
89
+ };
90
+ export type LifecycleDeveloperTerms = {
91
+ adapter: Address; beneficiary: Address; maximumDeveloperFeeBps: number; termsDigest: Hex; enabled: boolean;
92
+ };
93
+ export type SourceTermsV3 = {
94
+ adapter: Address; profileId: Hex; termsDigest: Hex; beneficiary: Address;
95
+ maximumDeveloperFeeBps: number; developerFeeBps: number;
96
+ };
97
+ export const launchBoundsV2Components = [
98
+ { name: "minimumTickSpacing", type: "int24" }, { name: "maximumTickSpacing", type: "int24" },
99
+ { name: "maximumPositions", type: "uint16" }, { name: "maximumOracleCardinality", type: "uint16" },
100
+ { name: "feeModeFlags", type: "uint8" },
101
+ ] as const;
102
+ export const launchGraphV2Components = [
103
+ { name: "manager", type: "address" }, { name: "hookRoot", type: "address" },
104
+ { name: "oracleFactory", type: "address" }, { name: "locker", type: "address" },
105
+ { name: "collectorFactory", type: "address" }, { name: "collectorDeployer", type: "address" },
106
+ { name: "hookDeployer", type: "address" }, { name: "coreCodeHash", type: "bytes32" },
107
+ { name: "managerCodeHash", type: "bytes32" }, { name: "hookRuntimeCodeHash", type: "bytes32" },
108
+ { name: "oracleFactoryCodeHash", type: "bytes32" }, { name: "lockerCodeHash", type: "bytes32" },
109
+ { name: "collectorFactoryCodeHash", type: "bytes32" }, { name: "collectorDeployerCodeHash", type: "bytes32" },
110
+ { name: "hookDeployerCodeHash", type: "bytes32" }, { name: "hookCreationCodeHash", type: "bytes32" },
111
+ { name: "codeChunk0", type: "address" }, { name: "codeChunk0Hash", type: "bytes32" },
112
+ { name: "codeChunk1", type: "address" }, { name: "codeChunk1Hash", type: "bytes32" },
113
+ { name: "sharedHookSalt", type: "bytes32" },
114
+ ] as const;
115
+ export const launchEnvelopeV2Components = [
116
+ { name: "artifactDigest", type: "bytes32" }, { name: "reviewManifestDigest", type: "bytes32" },
117
+ { name: "configBoundsDigest", type: "bytes32" }, { name: "termsDigest", type: "bytes32" },
118
+ { name: "topology", type: "uint8" }, { name: "configVersion", type: "uint32" },
119
+ { name: "economicVersion", type: "uint32" }, { name: "capabilities", type: "uint64" },
120
+ { name: "flags", type: "uint64" }, { name: "callbackFlags", type: "uint16" },
121
+ { name: "callbackMask", type: "uint16" }, { name: "protocolTreasury", type: "address" },
122
+ { name: "protocolFeeDenominator", type: "uint8" }, { name: "beneficiary", type: "address" },
123
+ { name: "maximumDeveloperFeeBps", type: "uint16" },
124
+ { name: "bounds", type: "tuple", components: launchBoundsV2Components },
125
+ { name: "graph", type: "tuple", components: launchGraphV2Components },
126
+ ] as const;
127
+ export const sourceTermsV3Components = [
128
+ { name: "adapter", type: "address" }, { name: "profileId", type: "bytes32" },
129
+ { name: "termsDigest", type: "bytes32" }, { name: "beneficiary", type: "address" },
130
+ { name: "maximumDeveloperFeeBps", type: "uint16" }, { name: "developerFeeBps", type: "uint16" },
131
+ ] as const;
132
+ export function encodeLaunchBounds(bounds: LaunchBoundsV2): Hex {
133
+ return encodeAbiParameters([{ type: "tuple", components: launchBoundsV2Components }], [bounds]);
134
+ }
135
+ export function decodeLaunchBounds(encoded: Hex): LaunchBoundsV2 {
136
+ return decodeAbiParameters([{ type: "tuple", components: launchBoundsV2Components }], encoded)[0];
137
+ }
138
+ export function hashLaunchBounds(bounds: LaunchBoundsV2): Hex {
139
+ return keccak256(encodeLaunchBounds(bounds));
140
+ }
141
+ export function encodeLaunchEnvelope(envelope: LaunchEnvelopeV2): Hex {
142
+ return encodeAbiParameters([{ type: "tuple", components: launchEnvelopeV2Components }], [envelope]);
143
+ }
144
+ export function decodeLaunchEnvelope(encoded: Hex): LaunchEnvelopeV2 {
145
+ const envelope = decodeAbiParameters([{ type: "tuple", components: launchEnvelopeV2Components }], encoded)[0];
146
+ if (envelope.topology !== 1 && envelope.topology !== 2) throw new Error("Unsupported reviewed hook topology");
147
+ return { ...envelope, topology: envelope.topology };
148
+ }
149
+ /** The registry identity deliberately excludes instance addresses and runtime immutables. */
150
+ export function hashLifecycleProfile(envelope: LaunchEnvelopeV2): Hex {
151
+ return keccak256(encodeAbiParameters([
152
+ { type: "bytes32" }, { type: "bytes32" }, { type: "bytes32" }, { type: "bytes32" }, { type: "bytes32" },
153
+ { type: "uint8" }, { type: "uint32" }, { type: "uint32" }, { type: "address" }, { type: "uint16" }, { type: "uint64" },
154
+ ], [keccak256(stringToHex("black-market.launch-profile.v2")), envelope.artifactDigest,
155
+ envelope.reviewManifestDigest, envelope.configBoundsDigest, envelope.termsDigest, envelope.topology,
156
+ envelope.configVersion, envelope.economicVersion, envelope.beneficiary, envelope.maximumDeveloperFeeBps, envelope.capabilities]));
157
+ }
158
+ /** Exact LaunchGraphLibV2 domain; shared salt is provenance, not an economic dependency. */
159
+ export function hashLaunchDependencies(options: {
160
+ chainId: bigint; core: Address; registry: Address; registrar: Address; graph: LaunchGraphV2;
161
+ }): Hex {
162
+ const { chainId, core, registry, registrar, graph: g } = options;
163
+ return keccak256(encodeAbiParameters([
164
+ { type: "bytes32" }, { type: "uint256" }, { type: "address" }, { type: "bytes32" },
165
+ { type: "address" }, { type: "address" }, { type: "address" }, { type: "bytes32" },
166
+ { type: "address" }, { type: "bytes32" }, { type: "address" }, { type: "bytes32" },
167
+ { type: "address" }, { type: "bytes32" }, { type: "address" }, { type: "bytes32" },
168
+ { type: "address" }, { type: "bytes32" }, { type: "address" }, { type: "bytes32" }, { type: "bytes32" },
169
+ { type: "address" }, { type: "bytes32" }, { type: "address" }, { type: "bytes32" },
170
+ ], [keccak256(stringToHex("black-market.v4-dependencies.v2")), chainId, core, g.coreCodeHash,
171
+ registry, registrar, g.manager, g.managerCodeHash, g.hookRoot, g.hookRuntimeCodeHash,
172
+ g.oracleFactory, g.oracleFactoryCodeHash, g.locker, g.lockerCodeHash, g.collectorFactory, g.collectorFactoryCodeHash,
173
+ g.collectorDeployer, g.collectorDeployerCodeHash, g.hookDeployer, g.hookDeployerCodeHash,
174
+ g.hookCreationCodeHash, g.codeChunk0, g.codeChunk0Hash, g.codeChunk1, g.codeChunk1Hash]));
175
+ }
176
+ export const LIFECYCLE_TOKEN_ONLY_CAPABILITY = 1n;
177
+ export const LIFECYCLE_EMPTY_PREPARE_CAPABILITY = 2n;
178
+ export const LIFECYCLE_PERMANENT_CUSTODY_CAPABILITY = 8n;
179
+ export const LIFECYCLE_CANONICAL_FEES_CAPABILITY = 16n;
180
+ export const LIFECYCLE_ERC404_CAPABILITY = 32n;
181
+ export const LIFECYCLE_MULTI_POSITION_CAPABILITY = 64n;
182
+ /** TOKEN_ONLY|EMPTY_PREPARE|PERMANENT_CUSTODY|CANONICAL_FEES. The retired POOL_GATE bit
183
+ * is never requested: preactivation safety is token transfer restrictions plus the
184
+ * activation-time canonical opening-state verification on both canonical venues. Atomic
185
+ * and staged share this mask; mode changes execution grouping, never venue eligibility. */
186
+ export const LIFECYCLE_REQUIRED_CAPABILITIES = LIFECYCLE_TOKEN_ONLY_CAPABILITY | LIFECYCLE_EMPTY_PREPARE_CAPABILITY | LIFECYCLE_PERMANENT_CUSTODY_CAPABILITY | LIFECYCLE_CANONICAL_FEES_CAPABILITY;
187
+ export const LIFECYCLE_MAX_ERC20_SUPPLY = (1n << 256n) - 1n;
188
+ export const LIFECYCLE_MAX_REWARD_ERC20_SUPPLY = 10n ** 77n;
189
+ export const LIFECYCLE_MAX_ERC404_SUPPLY = (1n << 96n) - 1n;
190
+
191
+ export const lifecycleTokenComponents = [
192
+ { name: "kind", type: "uint8" }, { name: "rewardMode", type: "uint8" },
193
+ { name: "name", type: "string" }, { name: "symbol", type: "string" },
194
+ { name: "supply", type: "uint256" }, { name: "nftUnit", type: "uint256" },
195
+ { name: "metadataURI", type: "string" }, { name: "salt", type: "bytes32" },
196
+ { name: "inventoryRecipient", type: "address" }, { name: "burnOnCancel", type: "bool" },
197
+ ] as const;
198
+ export const lifecycleFundingComponents = [
199
+ { name: "asset", type: "address" }, { name: "amount", type: "uint256" }, { name: "kind", type: "uint8" },
200
+ { name: "inputAsset", type: "address" }, { name: "inputAmount", type: "uint256" },
201
+ { name: "target", type: "address" }, { name: "data", type: "bytes" },
202
+ ] as const;
203
+ export const lifecycleFeePolicyComponents = [
204
+ { name: "asset", type: "address" }, { name: "ownerBps", type: "uint16" },
205
+ { name: "rewardsBps", type: "uint16" }, { name: "burnBps", type: "uint16" },
206
+ ] as const;
207
+ export const lifecycleMarketComponents = [
208
+ { name: "adapterId", type: "bytes32" }, { name: "profileId", type: "bytes32" },
209
+ { name: "quoteAsset", type: "address" }, { name: "tokenBudget", type: "uint256" },
210
+ { name: "configVersion", type: "uint32" }, { name: "config", type: "bytes" },
211
+ ] as const;
212
+ export const lifecycleBuyComponents = [
213
+ { name: "marketIndex", type: "uint32" }, { name: "quoteAmountIn", type: "uint256" },
214
+ { name: "minTokenOut", type: "uint256" }, { name: "recipient", type: "address" },
215
+ { name: "sqrtPriceLimitX96", type: "uint160" },
216
+ ] as const;
217
+ export const launchPlanV1Components = [
218
+ { name: "chainId", type: "uint256" }, { name: "orchestrator", type: "address" },
219
+ { name: "creator", type: "address" }, { name: "nonce", type: "uint256" },
220
+ { name: "token", type: "tuple", components: lifecycleTokenComponents },
221
+ { name: "funding", type: "tuple[]", components: lifecycleFundingComponents },
222
+ { name: "feeAssets", type: "tuple[]", components: lifecycleFeePolicyComponents },
223
+ { name: "markets", type: "tuple[]", components: lifecycleMarketComponents },
224
+ { name: "buys", type: "tuple[]", components: lifecycleBuyComponents },
225
+ { name: "deadline", type: "uint256" }, { name: "executorFeeBps", type: "uint16" },
226
+ ] as const;
227
+ export const marketIdentityV1Components = [
228
+ { name: "venue", type: "uint8" }, { name: "canonicalId", type: "bytes32" },
229
+ { name: "manager", type: "address" }, { name: "factory", type: "address" }, { name: "pool", type: "address" },
230
+ { name: "poolId", type: "bytes32" }, { name: "profileId", type: "bytes32" },
231
+ { name: "currency0", type: "address" }, { name: "currency1", type: "address" },
232
+ { name: "fee", type: "uint24" }, { name: "tickSpacing", type: "int24" },
233
+ { name: "hook", type: "address" }, { name: "openingSqrtPriceX96", type: "uint160" },
234
+ ] as const;
235
+ export const preparedMarketV1Components = [
236
+ { name: "identity", type: "tuple", components: marketIdentityV1Components },
237
+ { name: "feeSource", type: "address" }, { name: "custody", type: "address" },
238
+ { name: "mintExecutor", type: "address" }, { name: "buyExecutor", type: "address" },
239
+ { name: "exclusions", type: "address[]" }, { name: "positionCount", type: "uint32" },
240
+ ] as const;
241
+ export const positionIdentityV1Components = [
242
+ { name: "canonicalId", type: "bytes32" }, { name: "marketId", type: "bytes32" },
243
+ { name: "manager", type: "address" }, { name: "custody", type: "address" }, { name: "tokenId", type: "uint256" },
244
+ { name: "tickLower", type: "int24" }, { name: "tickUpper", type: "int24" },
245
+ { name: "salt", type: "bytes32" }, { name: "liquidity", type: "uint128" },
246
+ ] as const;
247
+ export const launchProgressV1Components = [
248
+ { name: "launchId", type: "bytes32" }, { name: "planHash", type: "bytes32" },
249
+ { name: "creator", type: "address" }, { name: "nonce", type: "uint256" },
250
+ { name: "mode", type: "uint8" }, { name: "phase", type: "uint8" },
251
+ { name: "token", type: "address" }, { name: "feeHub", type: "address" }, { name: "rewards", type: "address" },
252
+ { name: "preparedMarkets", type: "uint32" }, { name: "marketCount", type: "uint32" },
253
+ { name: "buyCount", type: "uint32" }, { name: "positionCount", type: "uint32" }, { name: "deadline", type: "uint256" },
254
+ ] as const;
255
+ export const launchReceiptV1Components = [
256
+ { name: "launchId", type: "bytes32" }, { name: "planHash", type: "bytes32" },
257
+ { name: "token", type: "address" }, { name: "feeHub", type: "address" }, { name: "rewards", type: "address" },
258
+ { name: "marketCount", type: "uint32" }, { name: "positionCount", type: "uint32" },
259
+ { name: "quoteSpent", type: "uint256[]" }, { name: "tokenOut", type: "uint256[]" },
260
+ ] as const;
261
+ export const adapterRegistrationV1Components = [
262
+ { name: "implementation", type: "address" }, { name: "codeHash", type: "bytes32" },
263
+ { name: "capabilities", type: "uint64" }, { name: "configVersion", type: "uint32" }, { name: "enabled", type: "bool" },
264
+ ] as const;
265
+ export const profileRegistrationV1Components = [
266
+ { name: "adapterId", type: "bytes32" }, { name: "configSchema", type: "bytes32" },
267
+ { name: "dependencyDigest", type: "bytes32" }, { name: "venue", type: "address" },
268
+ { name: "factory", type: "address" }, { name: "hook", type: "address" },
269
+ { name: "capabilities", type: "uint64" }, { name: "enabled", type: "bool" },
270
+ ] as const;
271
+ export const profileTopologyV1Components = [
272
+ { name: "hookTopology", type: "uint8" }, { name: "configVersion", type: "uint32" },
273
+ { name: "hookDeployer", type: "address" }, { name: "hookCreationCodeHash", type: "bytes32" },
274
+ ] as const;
275
+ export const marketLiveStateV1Components = [
276
+ { name: "sqrtPriceX96", type: "uint160" }, { name: "tick", type: "int24" }, { name: "liquidity", type: "uint128" },
277
+ { name: "publicTrading", type: "bool" }, { name: "oracleReadyAt", type: "uint256" },
278
+ ] as const;
279
+ export const launchExecutionContextV1Components = [
280
+ { name: "launchId", type: "bytes32" }, { name: "marketIndex", type: "uint32" }, { name: "operation", type: "uint8" },
281
+ { name: "adapter", type: "address" }, { name: "executor", type: "address" }, { name: "token", type: "address" },
282
+ { name: "quoteAsset", type: "address" }, { name: "manager", type: "address" }, { name: "custody", type: "address" },
283
+ { name: "recipient", type: "address" }, { name: "amount", type: "uint256" },
284
+ ] as const;
285
+
286
+ export function encodeLaunchPlan(plan: LaunchPlanV1): Hex {
287
+ return encodeAbiParameters([{ name: "plan", type: "tuple", components: launchPlanV1Components }], [plan]);
288
+ }
289
+
290
+ export const LIFECYCLE_PLAN_DOMAIN = keccak256(stringToHex("BLACK_MARKET_LAUNCH_PLAN_V1"));
291
+
292
+ /** Commitment to all economic fields, including chain, orchestrator, creator and nonce. */
293
+ export function hashLaunchPlan(plan: LaunchPlanV1): Hex {
294
+ return keccak256(encodeAbiParameters([
295
+ { type: "bytes32" }, { type: "tuple", components: launchPlanV1Components },
296
+ ], [LIFECYCLE_PLAN_DOMAIN, plan]));
297
+ }
298
+
299
+ /** Stable across blocks and modes; token config is committed separately by CREATE2. */
300
+ export function hashLaunchIdentity(plan: Pick<LaunchPlanV1, "chainId" | "orchestrator" | "creator" | "nonce">): Hex {
301
+ return keccak256(encodeAbiParameters([
302
+ { type: "uint256" }, { type: "address" }, { type: "address" }, { type: "uint256" },
303
+ ], [plan.chainId, plan.orchestrator, plan.creator, plan.nonce]));
304
+ }
305
+
306
+ /** Portable JSON uses decimal strings for uint160/uint256 fields, preserving exact integers. */
307
+ export function serializeLaunchPlan(plan: LaunchPlanV1): string {
308
+ return JSON.stringify(plan, (_key, value: unknown) => typeof value === "bigint" ? value.toString() : value);
309
+ }
310
+ function planRecord(value: unknown, label: string): Record<string, unknown> {
311
+ if (value === null || typeof value !== "object" || Array.isArray(value)) throw new Error(`${label} must be an object`);
312
+ // The object guard establishes the JSON schema boundary; individual fields remain unknown.
313
+ const record = value as Record<string, unknown>;
314
+ return record;
315
+ }
316
+ function planUint(value: unknown, bits: number, label: string): bigint {
317
+ let result: bigint;
318
+ if (typeof value === "string" && /^[0-9]+$/.test(value)) result = BigInt(value);
319
+ else if (typeof value === "number" && Number.isSafeInteger(value) && value >= 0) result = BigInt(value);
320
+ else throw new Error(`${label} must be an exact unsigned decimal integer`);
321
+ if (result >= 1n << BigInt(bits)) throw new Error(`${label} exceeds uint${bits}`);
322
+ return result;
323
+ }
324
+ function planString(value: unknown, label: string): string {
325
+ if (typeof value !== "string") throw new Error(`${label} must be a string`);
326
+ return value;
327
+ }
328
+ function planAddress(value: unknown, label: string): Address {
329
+ const string = planString(value, label);
330
+ if (!/^0x[0-9a-fA-F]{40}$/.test(string)) throw new Error(`${label} must be an address`);
331
+ // Exact 20-byte validation above establishes Address without changing committed casing.
332
+ return string as Address;
333
+ }
334
+ function planHex(value: unknown, label: string, bytes?: number): Hex {
335
+ const string = planString(value, label);
336
+ if (!/^0x(?:[0-9a-fA-F]{2})*$/.test(string) || (bytes !== undefined && string.length !== 2 + bytes * 2)) throw new Error(`${label} must be ${bytes === undefined ? "byte" : `${bytes}-byte`} hex`);
337
+ // Even-length byte validation establishes the ABI bytes boundary.
338
+ return string as Hex;
339
+ }
340
+ function planArray(value: unknown, label: string): unknown[] {
341
+ if (!Array.isArray(value)) throw new Error(`${label} must be an array`);
342
+ return value;
343
+ }
344
+ export function parseLaunchPlan(json: string): LaunchPlanV1 {
345
+ const value = planRecord(JSON.parse(json), "plan");
346
+ const token = planRecord(value.token, "token");
347
+ if (typeof token.burnOnCancel !== "boolean") throw new Error("burnOnCancel must be boolean");
348
+ const kind = Number(planUint(token.kind, 8, "token.kind"));
349
+ const rewardMode = Number(planUint(token.rewardMode, 8, "token.rewardMode"));
350
+ if (kind > LifecycleTokenKind.ERC404 || rewardMode > LifecycleRewardMode.Dividends) throw new Error("Unsupported token or reward kind");
351
+ return {
352
+ chainId: planUint(value.chainId, 256, "chainId"), orchestrator: planAddress(value.orchestrator, "orchestrator"),
353
+ creator: planAddress(value.creator, "creator"), nonce: planUint(value.nonce, 256, "nonce"),
354
+ token: {
355
+ kind, rewardMode, name: planString(token.name, "token.name"), symbol: planString(token.symbol, "token.symbol"),
356
+ supply: planUint(token.supply, 256, "token.supply"), nftUnit: planUint(token.nftUnit, 256, "token.nftUnit"),
357
+ metadataURI: planString(token.metadataURI, "metadataURI"), salt: planHex(token.salt, "token.salt", 32),
358
+ inventoryRecipient: planAddress(token.inventoryRecipient, "inventoryRecipient"), burnOnCancel: token.burnOnCancel,
359
+ },
360
+ funding: planArray(value.funding, "funding").map((raw) => {
361
+ const item = planRecord(raw, "funding asset");
362
+ const fundingKind = Number(planUint(item.kind, 8, "funding.kind"));
363
+ if (fundingKind > LifecycleFundingKind.Swap) throw new Error("Unsupported funding kind");
364
+ return { asset: planAddress(item.asset, "funding.asset"), amount: planUint(item.amount, 256, "funding.amount"),
365
+ kind: fundingKind, inputAsset: planAddress(item.inputAsset, "funding.inputAsset"), inputAmount: planUint(item.inputAmount, 256, "funding.inputAmount"),
366
+ target: planAddress(item.target, "funding.target"), data: planHex(item.data, "funding.data") };
367
+ }),
368
+ feeAssets: planArray(value.feeAssets, "feeAssets").map((raw) => {
369
+ const item = planRecord(raw, "fee policy");
370
+ return { asset: planAddress(item.asset, "fee asset"), ownerBps: Number(planUint(item.ownerBps, 16, "ownerBps")),
371
+ rewardsBps: Number(planUint(item.rewardsBps, 16, "rewardsBps")), burnBps: Number(planUint(item.burnBps, 16, "burnBps")) };
372
+ }),
373
+ markets: planArray(value.markets, "markets").map((raw) => {
374
+ const item = planRecord(raw, "market");
375
+ return { adapterId: planHex(item.adapterId, "adapterId", 32), profileId: planHex(item.profileId, "profileId", 32),
376
+ quoteAsset: planAddress(item.quoteAsset, "quoteAsset"), tokenBudget: planUint(item.tokenBudget, 256, "tokenBudget"),
377
+ configVersion: Number(planUint(item.configVersion, 32, "configVersion")), config: planHex(item.config, "config") };
378
+ }),
379
+ buys: planArray(value.buys, "buys").map((raw) => {
380
+ const item = planRecord(raw, "initial buy");
381
+ return { marketIndex: Number(planUint(item.marketIndex, 32, "marketIndex")), quoteAmountIn: planUint(item.quoteAmountIn, 256, "quoteAmountIn"),
382
+ minTokenOut: planUint(item.minTokenOut, 256, "minTokenOut"), recipient: planAddress(item.recipient, "recipient"),
383
+ sqrtPriceLimitX96: planUint(item.sqrtPriceLimitX96, 160, "sqrtPriceLimitX96") };
384
+ }),
385
+ deadline: planUint(value.deadline, 256, "deadline"), executorFeeBps: Number(planUint(value.executorFeeBps, 16, "executorFeeBps")),
386
+ };
387
+ }