@black-market/sdk 0.6.0 → 0.6.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.
- package/dist/lifecycle/planner.d.ts.map +1 -1
- package/dist/lifecycle/planner.js +192 -131
- package/dist/lifecycle/planner.js.map +1 -1
- package/dist/lifecycle/progress.d.ts.map +1 -1
- package/dist/lifecycle/progress.js +204 -143
- package/dist/lifecycle/progress.js.map +1 -1
- package/dist/lifecycle/rpc.d.ts +5 -0
- package/dist/lifecycle/rpc.d.ts.map +1 -1
- package/dist/lifecycle/rpc.js +89 -8
- package/dist/lifecycle/rpc.js.map +1 -1
- package/dist/lifecycle/simulation.d.ts.map +1 -1
- package/dist/lifecycle/simulation.js +8 -7
- package/dist/lifecycle/simulation.js.map +1 -1
- package/dist/lifecycle/types.d.ts +2 -0
- package/dist/lifecycle/types.d.ts.map +1 -1
- package/dist/lifecycle/types.js.map +1 -1
- package/docs/launch-lifecycle.md +72 -0
- package/package.json +1 -1
- package/src/lifecycle/planner.ts +158 -107
- package/src/lifecycle/progress.ts +187 -126
- package/src/lifecycle/rpc.ts +90 -8
- package/src/lifecycle/simulation.ts +8 -6
- package/src/lifecycle/types.ts +2 -0
|
@@ -2,7 +2,7 @@ import { concatHex, decodeFunctionData, encodeAbiParameters, encodeFunctionData,
|
|
|
2
2
|
import { abyssLifecycleAdapterAbi, launchLifecycleAbi, lifecycleAdapterAbi, lifecycleDirectoryAbi, lifecycleErc20Abi, lifecycleOracleFactoryAbi, lifecycleRegistryAbi, poolFeeCollectorFactoryV1Abi, lifecycleV4HookAbi, lifecycleV4LockerAbi, poolHookDeployerV1Abi, sharedHookDeployerV1Abi, fixedFeePoolHookV1Abi, poolMarketAdapterV1Abi, sharedMarketAdapterV1Abi } from "./abi.js";
|
|
3
3
|
import { decodePoolBoundV4LifecycleMarketConfig, encodePoolBoundHookParameters, hasLifecycleV4HookPermissions, hashPoolBoundV4MarketCommitment, poolBoundHookInitCodeHash, predictPoolBoundHookAddress, validateV4LifecycleMarket, V4_LIFECYCLE_CONFIG_SCHEMA, V4_POOL_BOUND_LIFECYCLE_CONFIG_SCHEMA } from "./markets.js";
|
|
4
4
|
import { hashLaunchIdentity, hashLaunchPlan, hashLaunchBounds, hashLaunchDependencies, hashLifecycleProfile, launchProgressV1Components, LifecycleMode, LifecyclePhase, LifecycleVenue, LIFECYCLE_REQUIRED_CAPABILITIES, LIFECYCLE_ERC404_CAPABILITY, LIFECYCLE_MULTI_POSITION_CAPABILITY } from "./schema.js";
|
|
5
|
-
import { assertLifecycleBlock, lifecycleRpc, readLifecycleBlock, readLifecycleContract, readLifecycleProfileTopology, rpcHex, rpcObject, rpcQuantity } from "./rpc.js";
|
|
5
|
+
import { assertLifecycleBlock, lifecyclePinnedRpc, lifecycleRpc, readLifecycleBlock, readLifecycleContract, readLifecycleProfileTopology, rpcHex, rpcObject, rpcQuantity, withLifecycleReadClient } from "./rpc.js";
|
|
6
6
|
import { LifecyclePlanningError } from "./types.js";
|
|
7
7
|
export const ABYSS_LIFECYCLE_CONFIG_SCHEMA = keccak256(stringToHex("(uint8,uint24,bytes32,uint160,(int24,int24,uint128,uint256)[])"));
|
|
8
8
|
export async function predictLifecycleToken(options) {
|
|
@@ -12,7 +12,7 @@ export async function predictLifecycleToken(options) {
|
|
|
12
12
|
return token;
|
|
13
13
|
}
|
|
14
14
|
async function readDependencyCode(client, address, block) {
|
|
15
|
-
const code = rpcHex(await
|
|
15
|
+
const code = rpcHex(await lifecyclePinnedRpc(client, "eth_getCode", [address, toHex(block.number)], block), "lifecycle dependency code");
|
|
16
16
|
if (address === zeroAddress || code === "0x")
|
|
17
17
|
throw new LifecyclePlanningError("PROFILE_DEPENDENCY", `Lifecycle dependency ${address} has no deployed code`);
|
|
18
18
|
return code;
|
|
@@ -26,19 +26,23 @@ async function certifyLifecycleProfile(client, orchestrator, registry, id, regis
|
|
|
26
26
|
const version = shared ? 4 : bound ? 5 : 1;
|
|
27
27
|
if (adapter.configVersion !== version || topology.configVersion !== version || topology.hookTopology !== (shared ? 1 : bound ? 2 : 0))
|
|
28
28
|
throw new LifecyclePlanningError("UNCERTIFIED_TOPOLOGY", "Registry topology/version differs from the supported config schema");
|
|
29
|
-
const implementationCode = await
|
|
29
|
+
const [implementationCode, authority, digest] = await Promise.all([
|
|
30
|
+
readDependencyCode(client, adapter.implementation, block),
|
|
31
|
+
readLifecycleContract(client, adapter.implementation, lifecycleAdapterAbi, "core", [], block),
|
|
32
|
+
readLifecycleContract(client, adapter.implementation, lifecycleAdapterAbi, "dependencyDigest", [], block),
|
|
33
|
+
]);
|
|
30
34
|
if (keccak256(implementationCode).toLowerCase() !== adapter.codeHash.toLowerCase())
|
|
31
35
|
throw new LifecyclePlanningError("PROFILE_CODE_HASH", "Adapter code hash differs from immutable registry approval");
|
|
32
|
-
const authority = await readLifecycleContract(client, adapter.implementation, lifecycleAdapterAbi, "core", [], block);
|
|
33
|
-
const digest = await readLifecycleContract(client, adapter.implementation, lifecycleAdapterAbi, "dependencyDigest", [], block);
|
|
34
36
|
if (authority.toLowerCase() !== orchestrator.toLowerCase() || digest.toLowerCase() !== registration.dependencyDigest.toLowerCase())
|
|
35
37
|
throw new LifecyclePlanningError("PROFILE_DEPENDENCY", "Adapter authority or dependency digest differs from immutable registry approval");
|
|
36
38
|
if (abyss) {
|
|
37
39
|
if (topology.hookDeployer !== zeroAddress || topology.hookCreationCodeHash !== zeroHash)
|
|
38
40
|
throw new LifecyclePlanningError("UNCERTIFIED_TOPOLOGY", "Abyss does not admit a V4 hook deployment graph");
|
|
39
|
-
const factory = await
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
const [factory, schema, actualVersion] = await Promise.all([
|
|
42
|
+
readLifecycleContract(client, adapter.implementation, abyssLifecycleAdapterAbi, "factory", [], block),
|
|
43
|
+
readLifecycleContract(client, adapter.implementation, abyssLifecycleAdapterAbi, "CONFIG_SCHEMA", [], block),
|
|
44
|
+
readLifecycleContract(client, adapter.implementation, abyssLifecycleAdapterAbi, "CONFIG_VERSION", [], block),
|
|
45
|
+
]);
|
|
42
46
|
const domain = keccak256(stringToHex("BLACK_MARKET_ABYSS_CANONICAL_PROFILE_V1"));
|
|
43
47
|
const known = [0, 1, 2, 3].some((variant) => keccak256(encodeAbiParameters([{ type: "bytes32" }, { type: "uint256" }, { type: "address" }, { type: "uint8" }], [domain, chainId, factory, variant])).toLowerCase() === id.toLowerCase());
|
|
44
48
|
if (!known || schema.toLowerCase() !== ABYSS_LIFECYCLE_CONFIG_SCHEMA.toLowerCase() || actualVersion !== 1 || registration.factory.toLowerCase() !== factory.toLowerCase() || registration.venue.toLowerCase() !== factory.toLowerCase() || registration.hook !== zeroAddress)
|
|
@@ -62,40 +66,49 @@ async function certifyLifecycleProfile(client, orchestrator, registry, id, regis
|
|
|
62
66
|
envelope.protocolTreasury === zeroAddress || (envelope.protocolFeeDenominator !== 0 && (envelope.protocolFeeDenominator < 4 || envelope.protocolFeeDenominator > 10)))
|
|
63
67
|
throw new LifecyclePlanningError("PROFILE_BOUNDS", "Registry envelope has unsupported executable bounds");
|
|
64
68
|
const abi = bound ? poolMarketAdapterV1Abi : sharedMarketAdapterV1Abi;
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
69
|
+
const [metadata, actualVersion] = await Promise.all([
|
|
70
|
+
Promise.all(["PROFILE_ID", "CONFIG_SCHEMA", "implementationRegistry"].map((getter) => readLifecycleContract(client, adapter.implementation, abi, getter, [], block))),
|
|
71
|
+
readLifecycleContract(client, adapter.implementation, abi, "CONFIG_VERSION", [], block),
|
|
72
|
+
]);
|
|
73
|
+
for (const [index, expected] of [id, registration.configSchema, registry].entries()) {
|
|
74
|
+
if (metadata[index]?.toLowerCase() !== expected.toLowerCase())
|
|
68
75
|
throw new LifecyclePlanningError("PROFILE_DEPENDENCY", "Reviewed adapter metadata differs from registry certification");
|
|
69
76
|
}
|
|
70
|
-
if (
|
|
77
|
+
if (actualVersion !== version)
|
|
71
78
|
throw new LifecyclePlanningError("PROFILE_DEPENDENCY", "Reviewed adapter config version differs from certification");
|
|
72
79
|
const g = envelope.graph;
|
|
73
80
|
if (registration.factory !== zeroAddress || registration.venue.toLowerCase() !== g.manager.toLowerCase() || registration.hook.toLowerCase() !== g.hookRoot.toLowerCase() ||
|
|
74
81
|
topology.hookDeployer.toLowerCase() !== g.hookDeployer.toLowerCase() || topology.hookCreationCodeHash.toLowerCase() !== g.hookCreationCodeHash.toLowerCase())
|
|
75
82
|
throw new LifecyclePlanningError("PROFILE_DEPENDENCY", "Reviewed venue/topology differs from the frozen envelope graph");
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
83
|
+
const deployerAbi = shared ? sharedHookDeployerV1Abi : poolHookDeployerV1Abi;
|
|
84
|
+
const codeBindings = [[orchestrator, g.coreCodeHash], [g.manager, g.managerCodeHash], [g.oracleFactory, g.oracleFactoryCodeHash],
|
|
85
|
+
[g.locker, g.lockerCodeHash], [g.collectorFactory, g.collectorFactoryCodeHash], [g.collectorDeployer, g.collectorDeployerCodeHash],
|
|
86
|
+
[g.hookDeployer, g.hookDeployerCodeHash]];
|
|
87
|
+
const [dependencies, dependencyCodes, collectorDeployer, launcher, lockerManager, creationCodeHash, chunk0, chunk1] = await Promise.all([
|
|
88
|
+
Promise.all(["poolManager", "hookRoot", "oracleFactory", "locker", "collectorFactory", "hookDeployer"].map((getter) => readLifecycleContract(client, adapter.implementation, abi, getter, [], block))),
|
|
89
|
+
Promise.all(codeBindings.map(([address]) => readDependencyCode(client, address, block))),
|
|
90
|
+
readLifecycleContract(client, g.collectorFactory, poolFeeCollectorFactoryV1Abi, "collectorDeployer", [], block),
|
|
91
|
+
readLifecycleContract(client, g.locker, lifecycleV4LockerAbi, "launcher", [], block),
|
|
92
|
+
readLifecycleContract(client, g.locker, lifecycleV4LockerAbi, "poolManager", [], block),
|
|
93
|
+
readLifecycleContract(client, g.hookDeployer, deployerAbi, "creationCodeHash", [], block),
|
|
94
|
+
readLifecycleContract(client, g.hookDeployer, deployerAbi, "codeChunk0", [], block),
|
|
95
|
+
readLifecycleContract(client, g.hookDeployer, deployerAbi, "codeChunk1", [], block),
|
|
96
|
+
]);
|
|
97
|
+
for (const [index, expected] of [g.manager, g.hookRoot, g.oracleFactory, g.locker, g.collectorFactory, g.hookDeployer].entries()) {
|
|
98
|
+
if (dependencies[index]?.toLowerCase() !== expected.toLowerCase())
|
|
79
99
|
throw new LifecyclePlanningError("PROFILE_DEPENDENCY", "Live adapter dependency differs from the frozen reviewed graph");
|
|
80
100
|
}
|
|
81
|
-
for (const [
|
|
82
|
-
[
|
|
83
|
-
[g.hookDeployer, g.hookDeployerCodeHash]]) {
|
|
84
|
-
if (keccak256(await readDependencyCode(client, address, block)).toLowerCase() !== expectedHash.toLowerCase())
|
|
101
|
+
for (const [index, [, expectedHash]] of codeBindings.entries()) {
|
|
102
|
+
if (keccak256(dependencyCodes[index]).toLowerCase() !== expectedHash.toLowerCase())
|
|
85
103
|
throw new LifecyclePlanningError("PROFILE_CODE_HASH", "Live runtime differs from the frozen reviewed graph hash");
|
|
86
104
|
}
|
|
87
|
-
const collectorDeployer = await readLifecycleContract(client, g.collectorFactory, poolFeeCollectorFactoryV1Abi, "collectorDeployer", [], block);
|
|
88
|
-
const launcher = await readLifecycleContract(client, g.locker, lifecycleV4LockerAbi, "launcher", [], block);
|
|
89
|
-
const lockerManager = await readLifecycleContract(client, g.locker, lifecycleV4LockerAbi, "poolManager", [], block);
|
|
90
105
|
if (collectorDeployer.toLowerCase() !== g.collectorDeployer.toLowerCase() || launcher.toLowerCase() !== adapter.implementation.toLowerCase() ||
|
|
91
106
|
lockerManager.toLowerCase() !== g.manager.toLowerCase() || g.locker.toLowerCase() === g.manager.toLowerCase() || g.locker.toLowerCase() === g.hookRoot.toLowerCase())
|
|
92
107
|
throw new LifecyclePlanningError("PROFILE_DEPENDENCY", "Reviewed collector or locker authority differs from the frozen graph");
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
const chunk0Code = await readDependencyCode(client, chunk0, block);
|
|
98
|
-
const chunk1Code = chunk1 === zeroAddress ? "0x" : await readDependencyCode(client, chunk1, block);
|
|
108
|
+
const [chunk0Code, chunk1Code] = await Promise.all([
|
|
109
|
+
readDependencyCode(client, chunk0, block),
|
|
110
|
+
chunk1 === zeroAddress ? Promise.resolve("0x") : readDependencyCode(client, chunk1, block),
|
|
111
|
+
]);
|
|
99
112
|
if (chunk0.toLowerCase() !== g.codeChunk0.toLowerCase() || chunk1.toLowerCase() !== g.codeChunk1.toLowerCase() || chunk0.toLowerCase() === chunk1.toLowerCase() ||
|
|
100
113
|
!chunk0Code.startsWith("0x00") || chunk0Code.length <= 4 || (chunk0Code.length - 2) / 2 > 24576 ||
|
|
101
114
|
(chunk1 !== zeroAddress && (!chunk1Code.startsWith("0x00") || chunk1Code.length <= 4 || (chunk1Code.length - 2) / 2 > 24576 || (chunk0Code.length - 2) / 2 !== 24576)) ||
|
|
@@ -107,20 +120,24 @@ async function certifyLifecycleProfile(client, orchestrator, registry, id, regis
|
|
|
107
120
|
hashLaunchDependencies({ chainId, core: orchestrator, registry, registrar: adapter.implementation, graph: g }).toLowerCase() !== digest.toLowerCase())
|
|
108
121
|
throw new LifecyclePlanningError("PROFILE_DEPENDENCY", "Reviewed creation artifact, constructor bound or graph digest differs from admission");
|
|
109
122
|
if (shared) {
|
|
110
|
-
const rootCode
|
|
111
|
-
|
|
123
|
+
const [rootCode, recordedHash, remotePrediction, dependencies, requiredFlags, allFlags] = await Promise.all([
|
|
124
|
+
readDependencyCode(client, g.hookRoot, block),
|
|
125
|
+
readLifecycleContract(client, g.hookDeployer, deployerAbi, "deployedCodeHash", [g.hookRoot], block),
|
|
126
|
+
readLifecycleContract(client, g.hookDeployer, sharedHookDeployerV1Abi, "predict", [g.manager, adapter.implementation, g.oracleFactory, g.sharedHookSalt], block),
|
|
127
|
+
Promise.all(["registrar", "poolManager", "oracleFactory"].map((getter) => readLifecycleContract(client, g.hookRoot, lifecycleV4HookAbi, getter, [], block))),
|
|
128
|
+
readLifecycleContract(client, g.hookRoot, lifecycleV4HookAbi, "REQUIRED_HOOK_FLAGS", [], block),
|
|
129
|
+
readLifecycleContract(client, g.hookRoot, lifecycleV4HookAbi, "ALL_HOOK_MASK", [], block),
|
|
130
|
+
]);
|
|
112
131
|
const initCodeHash = keccak256(concatHex([creationCode, encodeAbiParameters([{ type: "address" }, { type: "address" }, { type: "address" }], [g.manager, adapter.implementation, g.oracleFactory])]));
|
|
113
132
|
const prediction = predictPoolBoundHookAddress({ deployer: g.hookDeployer, initCodeHash, salt: g.sharedHookSalt });
|
|
114
|
-
const remotePrediction = await readLifecycleContract(client, g.hookDeployer, sharedHookDeployerV1Abi, "predict", [g.manager, adapter.implementation, g.oracleFactory, g.sharedHookSalt], block);
|
|
115
133
|
if (recordedHash === zeroHash || recordedHash.toLowerCase() !== g.hookRuntimeCodeHash.toLowerCase() || keccak256(rootCode).toLowerCase() !== recordedHash.toLowerCase() ||
|
|
116
134
|
!hasLifecycleV4HookPermissions(g.hookRoot) || prediction.toLowerCase() !== g.hookRoot.toLowerCase() || remotePrediction.toLowerCase() !== prediction.toLowerCase())
|
|
117
135
|
throw new LifecyclePlanningError("PROFILE_DEPENDENCY", "Shared root lacks exact typed-deployer runtime and constructor/salt provenance");
|
|
118
|
-
for (const [
|
|
119
|
-
if (
|
|
136
|
+
for (const [index, expected] of [adapter.implementation, g.manager, g.oracleFactory].entries()) {
|
|
137
|
+
if (dependencies[index]?.toLowerCase() !== expected.toLowerCase())
|
|
120
138
|
throw new LifecyclePlanningError("PROFILE_DEPENDENCY", "Shared hook immutable graph differs from admission");
|
|
121
139
|
}
|
|
122
|
-
if (
|
|
123
|
-
await readLifecycleContract(client, g.hookRoot, lifecycleV4HookAbi, "ALL_HOOK_MASK", [], block) !== 0x3fffn)
|
|
140
|
+
if (requiredFlags !== 0x1afcn || allFlags !== 0x3fffn)
|
|
124
141
|
throw new LifecyclePlanningError("PROFILE_DEPENDENCY", "Shared hook callbacks differ from admission");
|
|
125
142
|
}
|
|
126
143
|
else if (g.hookRoot !== zeroAddress || g.hookRuntimeCodeHash !== zeroHash || g.sharedHookSalt !== zeroHash)
|
|
@@ -140,55 +157,77 @@ export async function validateV4LifecycleOracle(options) {
|
|
|
140
157
|
}
|
|
141
158
|
}
|
|
142
159
|
export async function readLifecycleProfiles(options, pinnedBlock) {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
let
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
topology =
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
throw new LifecyclePlanningError("
|
|
160
|
+
return withLifecycleReadClient(options.client, async (client) => {
|
|
161
|
+
const [block, chainIdValue] = await Promise.all([
|
|
162
|
+
pinnedBlock ?? readLifecycleBlock(client),
|
|
163
|
+
lifecycleRpc(client, "eth_chainId"),
|
|
164
|
+
]);
|
|
165
|
+
const chainId = rpcQuantity(chainIdValue, "chain ID");
|
|
166
|
+
const registry = await readLifecycleContract(client, options.orchestrator, launchLifecycleAbi, "registry", [], block);
|
|
167
|
+
const offset = options.offset ?? 0n;
|
|
168
|
+
const limit = options.limit ?? 100n;
|
|
169
|
+
if (offset < 0n || limit < 0n || limit > 100n)
|
|
170
|
+
throw new LifecyclePlanningError("INVALID_PROFILE_PAGE", "Registry profile pages require unsigned offset and limit at most 100");
|
|
171
|
+
const [authority, ids] = await Promise.all([
|
|
172
|
+
readLifecycleContract(client, registry, lifecycleRegistryAbi, "core", [], block),
|
|
173
|
+
options.profileIds ?? readLifecycleContract(client, registry, lifecycleRegistryAbi, "profileIds", [offset, limit], block),
|
|
174
|
+
]);
|
|
175
|
+
if (authority.toLowerCase() !== options.orchestrator.toLowerCase())
|
|
176
|
+
throw new LifecyclePlanningError("REGISTRY_BINDING", "Registry is not bound to the selected lifecycle orchestrator");
|
|
177
|
+
let protocolMaximumDeveloperFeeBpsPromise;
|
|
178
|
+
const readProtocolMaximumDeveloperFeeBps = () => protocolMaximumDeveloperFeeBpsPromise ??=
|
|
179
|
+
readLifecycleContract(client, registry, lifecycleRegistryAbi, "protocolMaximumDeveloperFeeBps", [], block);
|
|
180
|
+
const profiles = await Promise.all(ids.map(async (id) => {
|
|
181
|
+
const registration = await readLifecycleContract(client, registry, lifecycleRegistryAbi, "profile", [id], block);
|
|
182
|
+
const adapter = await readLifecycleContract(client, registry, lifecycleRegistryAbi, "adapter", [registration.adapterId], block);
|
|
183
|
+
const schema = registration.configSchema.toLowerCase();
|
|
184
|
+
const venueKind = schema === V4_LIFECYCLE_CONFIG_SCHEMA.toLowerCase() || schema === V4_POOL_BOUND_LIFECYCLE_CONFIG_SCHEMA.toLowerCase() ? "uniswap-v4" : schema === ABYSS_LIFECYCLE_CONFIG_SCHEMA.toLowerCase() ? "abyss" : "unknown";
|
|
185
|
+
let topology = { hookTopology: 0, configVersion: adapter.configVersion, hookDeployer: zeroAddress, hookCreationCodeHash: zeroHash };
|
|
186
|
+
let envelope;
|
|
187
|
+
let developerTerms;
|
|
188
|
+
let protocolMaximumDeveloperFeeBps;
|
|
189
|
+
let admitted = false;
|
|
190
|
+
let reason;
|
|
191
|
+
try {
|
|
192
|
+
if (venueKind === "unknown")
|
|
193
|
+
throw new LifecyclePlanningError("UNSUPPORTED_SCHEMA", `Unsupported lifecycle config schema ${registration.configSchema}`);
|
|
194
|
+
const [recordedTopology, reviewed] = await Promise.all([
|
|
195
|
+
readLifecycleProfileTopology(client, registry, id, block),
|
|
196
|
+
venueKind === "uniswap-v4" ? Promise.all([
|
|
197
|
+
readLifecycleContract(client, registry, lifecycleRegistryAbi, "profileEnvelope", [id], block),
|
|
198
|
+
readLifecycleContract(client, registry, lifecycleRegistryAbi, "developerTerms", [id], block),
|
|
199
|
+
readProtocolMaximumDeveloperFeeBps(),
|
|
200
|
+
]) : undefined,
|
|
201
|
+
]);
|
|
202
|
+
topology = recordedTopology;
|
|
203
|
+
if (reviewed !== undefined) {
|
|
204
|
+
envelope = reviewed[0];
|
|
205
|
+
protocolMaximumDeveloperFeeBps = reviewed[2];
|
|
206
|
+
const [implementation, beneficiary, maximumDeveloperFeeBps, termsDigest, enabled] = reviewed[1];
|
|
207
|
+
developerTerms = { adapter: implementation, beneficiary, maximumDeveloperFeeBps, termsDigest, enabled };
|
|
208
|
+
if (implementation.toLowerCase() !== adapter.implementation.toLowerCase() || beneficiary.toLowerCase() !== envelope.beneficiary.toLowerCase() ||
|
|
209
|
+
termsDigest.toLowerCase() !== envelope.termsDigest.toLowerCase() || maximumDeveloperFeeBps !== envelope.maximumDeveloperFeeBps ||
|
|
210
|
+
maximumDeveloperFeeBps > reviewed[2])
|
|
211
|
+
throw new LifecyclePlanningError("PROFILE_TERMS", "Registry developer terms differ from the frozen reviewed envelope");
|
|
212
|
+
}
|
|
213
|
+
await certifyLifecycleProfile(client, options.orchestrator, registry, id, registration, adapter, topology, envelope, block, chainId);
|
|
214
|
+
const eligible = await readLifecycleContract(client, registry, lifecycleRegistryAbi, "requireEligible", [registration.adapterId, id, topology.configVersion, LIFECYCLE_REQUIRED_CAPABILITIES], block);
|
|
215
|
+
if (eligible.toLowerCase() !== adapter.implementation.toLowerCase() || (developerTerms !== undefined && !developerTerms.enabled))
|
|
216
|
+
throw new LifecyclePlanningError("INELIGIBLE_PROFILE", "Registry refuses this profile for pending source admission");
|
|
217
|
+
admitted = true;
|
|
177
218
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
await assertLifecycleBlock(options.client, block);
|
|
191
|
-
return profiles;
|
|
219
|
+
catch (failure) {
|
|
220
|
+
reason = failure instanceof Error ? failure.message : String(failure);
|
|
221
|
+
}
|
|
222
|
+
return { id, registration, adapter, topology, envelope, developerTerms, protocolMaximumDeveloperFeeBps: venueKind === "uniswap-v4" ? protocolMaximumDeveloperFeeBps : undefined, admitted, reason, venueKind };
|
|
223
|
+
}));
|
|
224
|
+
// A required V4 cap read still rejects the invocation on failure; Abyss has no developer-fee terms.
|
|
225
|
+
if (protocolMaximumDeveloperFeeBpsPromise !== undefined)
|
|
226
|
+
await protocolMaximumDeveloperFeeBpsPromise;
|
|
227
|
+
if (pinnedBlock === undefined)
|
|
228
|
+
await assertLifecycleBlock(client, block, chainId);
|
|
229
|
+
return profiles;
|
|
230
|
+
});
|
|
192
231
|
}
|
|
193
232
|
async function readPoolBoundHookDeploymentDetails(options, block) {
|
|
194
233
|
const { client, plan, marketIndex } = options;
|
|
@@ -199,20 +238,25 @@ async function readPoolBoundHookDeploymentDetails(options, block) {
|
|
|
199
238
|
if (chainId !== plan.chainId)
|
|
200
239
|
throw new LifecyclePlanningError("CHAIN_MISMATCH", "RPC chain differs from the committed plan");
|
|
201
240
|
const registry = await readLifecycleContract(client, plan.orchestrator, launchLifecycleAbi, "registry", [], block);
|
|
202
|
-
|
|
241
|
+
const [authority, registration] = await Promise.all([
|
|
242
|
+
readLifecycleContract(client, registry, lifecycleRegistryAbi, "core", [], block),
|
|
243
|
+
readLifecycleContract(client, registry, lifecycleRegistryAbi, "profile", [market.profileId], block),
|
|
244
|
+
]);
|
|
245
|
+
if (authority.toLowerCase() !== plan.orchestrator.toLowerCase())
|
|
203
246
|
throw new LifecyclePlanningError("REGISTRY_BINDING", "Registry is not bound to this lifecycle core");
|
|
204
|
-
const registration = await readLifecycleContract(client, registry, lifecycleRegistryAbi, "profile", [market.profileId], block);
|
|
205
247
|
const adapter = await readLifecycleContract(client, registry, lifecycleRegistryAbi, "adapter", [registration.adapterId], block);
|
|
206
248
|
if (registration.adapterId.toLowerCase() !== market.adapterId.toLowerCase())
|
|
207
249
|
throw new LifecyclePlanningError("INVALID_BOUND_MARKET", "Market adapter differs from the profile's immutable registration");
|
|
208
|
-
const recorded
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
250
|
+
const [recorded, envelope, [implementation, beneficiary, maximumDeveloperFeeBps, termsDigest, enabled], protocolMaximumDeveloperFeeBps, token] = await Promise.all([
|
|
251
|
+
readLifecycleProfileTopology(client, registry, market.profileId, block),
|
|
252
|
+
readLifecycleContract(client, registry, lifecycleRegistryAbi, "profileEnvelope", [market.profileId], block),
|
|
253
|
+
readLifecycleContract(client, registry, lifecycleRegistryAbi, "developerTerms", [market.profileId], block),
|
|
254
|
+
readLifecycleContract(client, registry, lifecycleRegistryAbi, "protocolMaximumDeveloperFeeBps", [], block),
|
|
255
|
+
readLifecycleContract(client, plan.orchestrator, launchLifecycleAbi, "predictToken", [plan], block),
|
|
256
|
+
]);
|
|
212
257
|
const { boundGraph } = await certifyLifecycleProfile(client, plan.orchestrator, registry, market.profileId, registration, adapter, recorded, envelope, block, chainId);
|
|
213
258
|
if (boundGraph === undefined)
|
|
214
259
|
throw new LifecyclePlanningError("UNCERTIFIED_TOPOLOGY", "Market does not have a certified pool-bound deployer graph");
|
|
215
|
-
const token = await readLifecycleContract(client, plan.orchestrator, launchLifecycleAbi, "predictToken", [plan], block);
|
|
216
260
|
const config = decodePoolBoundV4LifecycleMarketConfig(market.config);
|
|
217
261
|
validateV4LifecycleMarket({ market, config, token, profile: {
|
|
218
262
|
id: market.profileId, registration, adapter, topology: recorded, envelope,
|
|
@@ -228,37 +272,39 @@ async function readPoolBoundHookDeploymentDetails(options, block) {
|
|
|
228
272
|
marketCommitment: hashPoolBoundV4MarketCommitment({ chainId, core: plan.orchestrator, registrar: adapter.implementation, token, market }),
|
|
229
273
|
expectedPositionCount: config.positions.length,
|
|
230
274
|
};
|
|
231
|
-
const [parameters, parameterSalt]
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
275
|
+
const [[parameters, parameterSalt], [deployer, initCodeHash, salt, predictedHook], remoteInitCodeHash, remotePrediction] = await Promise.all([
|
|
276
|
+
readLifecycleContract(client, boundGraph.collectorFactory, poolFeeCollectorFactoryV1Abi, "poolBoundHookParameters", [adapter.implementation, token, market], block),
|
|
277
|
+
readLifecycleContract(client, adapter.implementation, poolMarketAdapterV1Abi, "hookDeploymentMetadata", [token, market], block),
|
|
278
|
+
readLifecycleContract(client, boundGraph.deployer, poolHookDeployerV1Abi, "initCodeHash", [expected], block),
|
|
279
|
+
readLifecycleContract(client, boundGraph.deployer, poolHookDeployerV1Abi, "predict", [expected, config.hookSalt], block),
|
|
280
|
+
]);
|
|
235
281
|
const localInitCodeHash = poolBoundHookInitCodeHash(boundGraph.creationCode, expected);
|
|
236
282
|
const localPrediction = predictPoolBoundHookAddress({ deployer: boundGraph.deployer, initCodeHash: localInitCodeHash, salt: config.hookSalt });
|
|
237
283
|
if (encodePoolBoundHookParameters(parameters).toLowerCase() !== encodePoolBoundHookParameters(expected).toLowerCase() || parameterSalt.toLowerCase() !== config.hookSalt.toLowerCase() || salt.toLowerCase() !== config.hookSalt.toLowerCase() || deployer.toLowerCase() !== boundGraph.deployer.toLowerCase() || initCodeHash.toLowerCase() !== localInitCodeHash.toLowerCase() || remoteInitCodeHash.toLowerCase() !== localInitCodeHash.toLowerCase() || predictedHook.toLowerCase() !== localPrediction.toLowerCase() || remotePrediction.toLowerCase() !== localPrediction.toLowerCase())
|
|
238
284
|
throw new LifecyclePlanningError("HOOK_DEPLOYMENT_CHANGED", "Bound hook metadata differs from the exact certified constructor economics, factory, initcode, salt or CREATE2 prediction");
|
|
239
|
-
const hookCode = rpcHex(await
|
|
285
|
+
const hookCode = rpcHex(await lifecyclePinnedRpc(client, "eth_getCode", [predictedHook, toHex(block.number)], block), "bound hook code");
|
|
240
286
|
if (hookCode !== "0x") {
|
|
241
|
-
const deployedCodeHash
|
|
287
|
+
const [deployedCodeHash, dependencies, requiredFlags, allFlags, actualPoolId, deploymentConfigHash, marketCommitment, opening, positions] = await Promise.all([
|
|
288
|
+
readLifecycleContract(client, deployer, poolHookDeployerV1Abi, "deployedCodeHash", [predictedHook], block),
|
|
289
|
+
Promise.all(["poolManager", "registrar", "oracleFactory", "core", "liquidityLocker", "token"].map((getter) => readLifecycleContract(client, predictedHook, fixedFeePoolHookV1Abi, getter, [], block))),
|
|
290
|
+
readLifecycleContract(client, predictedHook, fixedFeePoolHookV1Abi, "REQUIRED_HOOK_FLAGS", [], block),
|
|
291
|
+
readLifecycleContract(client, predictedHook, fixedFeePoolHookV1Abi, "ALL_HOOK_MASK", [], block),
|
|
292
|
+
readLifecycleContract(client, predictedHook, fixedFeePoolHookV1Abi, "boundPoolId", [], block),
|
|
293
|
+
readLifecycleContract(client, predictedHook, fixedFeePoolHookV1Abi, "deploymentConfigHash", [], block),
|
|
294
|
+
readLifecycleContract(client, predictedHook, fixedFeePoolHookV1Abi, "marketCommitment", [], block),
|
|
295
|
+
readLifecycleContract(client, predictedHook, fixedFeePoolHookV1Abi, "openingSqrtPriceX96", [], block),
|
|
296
|
+
readLifecycleContract(client, predictedHook, fixedFeePoolHookV1Abi, "expectedPositionCount", [], block),
|
|
297
|
+
]);
|
|
242
298
|
if ((hookCode.length - 2) / 2 > 24576 || deployedCodeHash === zeroHash || deployedCodeHash.toLowerCase() !== keccak256(hookCode).toLowerCase())
|
|
243
299
|
throw new LifecyclePlanningError("HOOK_DEPLOYMENT_CHANGED", "Existing hook lacks this exact typed deployer's bounded runtime-code provenance");
|
|
244
|
-
for (const [
|
|
245
|
-
|
|
246
|
-
["core", expected.core], ["liquidityLocker", expected.liquidityLocker], ["token", expected.token],
|
|
247
|
-
]) {
|
|
248
|
-
const actual = await readLifecycleContract(client, predictedHook, fixedFeePoolHookV1Abi, getter, [], block);
|
|
249
|
-
if (actual.toLowerCase() !== expectedAddress.toLowerCase())
|
|
300
|
+
for (const [index, expectedAddress] of [expected.poolManager, expected.registrar, expected.oracleFactory, expected.core, expected.liquidityLocker, expected.token].entries()) {
|
|
301
|
+
if (dependencies[index]?.toLowerCase() !== expectedAddress.toLowerCase())
|
|
250
302
|
throw new LifecyclePlanningError("HOOK_DEPLOYMENT_CHANGED", "Existing hook immutable dependency graph differs from the committed constructor");
|
|
251
303
|
}
|
|
252
|
-
if (
|
|
253
|
-
await readLifecycleContract(client, predictedHook, fixedFeePoolHookV1Abi, "ALL_HOOK_MASK", [], block) !== 0x3fffn)
|
|
304
|
+
if (requiredFlags !== 0x1afcn || allFlags !== 0x3fffn)
|
|
254
305
|
throw new LifecyclePlanningError("HOOK_DEPLOYMENT_CHANGED", "Existing bound hook callback declarations differ from the reviewed envelope");
|
|
255
306
|
const [currency0, currency1] = BigInt(token) < BigInt(market.quoteAsset) ? [token, market.quoteAsset] : [market.quoteAsset, token];
|
|
256
307
|
const expectedPoolId = keccak256(encodeAbiParameters([{ type: "address" }, { type: "address" }, { type: "uint24" }, { type: "int24" }, { type: "address" }], [currency0, currency1, config.lpFeePips, config.tickSpacing, predictedHook]));
|
|
257
|
-
const actualPoolId = await readLifecycleContract(client, predictedHook, fixedFeePoolHookV1Abi, "boundPoolId", [], block);
|
|
258
|
-
const deploymentConfigHash = await readLifecycleContract(client, predictedHook, fixedFeePoolHookV1Abi, "deploymentConfigHash", [], block);
|
|
259
|
-
const marketCommitment = await readLifecycleContract(client, predictedHook, fixedFeePoolHookV1Abi, "marketCommitment", [], block);
|
|
260
|
-
const opening = await readLifecycleContract(client, predictedHook, fixedFeePoolHookV1Abi, "openingSqrtPriceX96", [], block);
|
|
261
|
-
const positions = await readLifecycleContract(client, predictedHook, fixedFeePoolHookV1Abi, "expectedPositionCount", [], block);
|
|
262
308
|
if (actualPoolId.toLowerCase() !== expectedPoolId.toLowerCase() || deploymentConfigHash.toLowerCase() !== keccak256(encodePoolBoundHookParameters(expected)).toLowerCase() || marketCommitment.toLowerCase() !== expected.marketCommitment.toLowerCase() || opening !== expected.sqrtPriceX96 || positions !== expected.expectedPositionCount)
|
|
263
309
|
throw new LifecyclePlanningError("HOOK_DEPLOYMENT_CHANGED", "Existing hook key, economic commitment or immutable opening geometry changed");
|
|
264
310
|
}
|
|
@@ -268,24 +314,28 @@ async function readPoolBoundHookDeploymentDetails(options, block) {
|
|
|
268
314
|
export async function readPoolBoundHookDeployment(options, pinnedBlock) {
|
|
269
315
|
const commitment = hashLaunchPlan(options.plan);
|
|
270
316
|
const block = pinnedBlock ?? await readLifecycleBlock(options.client);
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
317
|
+
return withLifecycleReadClient(options.client, async (client) => {
|
|
318
|
+
const { deployment } = await readPoolBoundHookDeploymentDetails({ ...options, client }, block);
|
|
319
|
+
if (hashLaunchPlan(options.plan) !== commitment)
|
|
320
|
+
throw new LifecyclePlanningError("PLAN_MUTATED", "Economic plan changed while reading hook deployment metadata");
|
|
321
|
+
if (pinnedBlock === undefined)
|
|
322
|
+
await assertLifecycleBlock(client, block, options.plan.chainId);
|
|
323
|
+
return deployment;
|
|
324
|
+
});
|
|
277
325
|
}
|
|
278
326
|
/** Optional permissionless predeployment calldata; no token deployment, pool registration or wallet broadcast. */
|
|
279
327
|
export async function buildPoolBoundHookDeploymentTransaction(options) {
|
|
280
328
|
const commitment = hashLaunchPlan(options.plan);
|
|
281
329
|
const block = await readLifecycleBlock(options.client);
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
330
|
+
return withLifecycleReadClient(options.client, async (client) => {
|
|
331
|
+
const { deployment, parameters } = await readPoolBoundHookDeploymentDetails({ ...options, client }, block);
|
|
332
|
+
if (!hasLifecycleV4HookPermissions(deployment.predictedHook))
|
|
333
|
+
throw new LifecyclePlanningError("INVALID_HOOK_BITS", "Finalize a salt with the exact lifecycle hook permissions before predeployment");
|
|
334
|
+
if (hashLaunchPlan(options.plan) !== commitment)
|
|
335
|
+
throw new LifecyclePlanningError("PLAN_MUTATED", "Economic plan changed while constructing hook deployment calldata");
|
|
336
|
+
await assertLifecycleBlock(client, block, options.plan.chainId);
|
|
337
|
+
return { to: deployment.deployer, data: encodeFunctionData({ abi: poolHookDeployerV1Abi, functionName: "deploy", args: [parameters, deployment.salt] }), value: 0n, deployment };
|
|
338
|
+
});
|
|
289
339
|
}
|
|
290
340
|
export function validateLifecycleMarketIdentity(identity, plan, token, marketIndex) {
|
|
291
341
|
const market = plan.markets[marketIndex];
|
|
@@ -352,8 +402,10 @@ async function readReceipt(reference, options, block) {
|
|
|
352
402
|
if (observed === null || rpcHex(rpcObject(observed, "observed receipt block").hash, "observed receipt block hash").toLowerCase() !== reference.observedBlockHash.toLowerCase())
|
|
353
403
|
return { ...base, status: "reorged", blockNumber: observedNumber, blockHash: reference.observedBlockHash };
|
|
354
404
|
}
|
|
355
|
-
const receiptValue = await
|
|
356
|
-
|
|
405
|
+
const [receiptValue, transactionValue] = await Promise.all([
|
|
406
|
+
lifecycleRpc(options.client, "eth_getTransactionReceipt", [effectiveHash]),
|
|
407
|
+
lifecycleRpc(options.client, "eth_getTransactionByHash", [effectiveHash]),
|
|
408
|
+
]);
|
|
357
409
|
if (receiptValue === null) {
|
|
358
410
|
// An absent receipt with an unchanged canonical observed block is not a
|
|
359
411
|
// reorg: the transaction is simply not (yet) mined. A missing/changed
|
|
@@ -389,8 +441,11 @@ async function readReceipt(reference, options, block) {
|
|
|
389
441
|
}
|
|
390
442
|
/** Reads confirmation-bound canonical state and receipt provenance; local step counters are never used. */
|
|
391
443
|
export async function readLaunchProgress(options, pinnedBlock) {
|
|
392
|
-
const
|
|
393
|
-
|
|
444
|
+
const block = pinnedBlock ?? await readLifecycleBlock(options.client);
|
|
445
|
+
return withLifecycleReadClient(options.client, (client) => readLaunchProgressAtBlock(options, client, block, pinnedBlock === undefined));
|
|
446
|
+
}
|
|
447
|
+
async function readLaunchProgressAtBlock(options, client, block, checkBlock) {
|
|
448
|
+
const { planned } = options;
|
|
394
449
|
const confirmationDepth = options.confirmations ?? planned.confirmations;
|
|
395
450
|
if (!Number.isSafeInteger(confirmationDepth) || confirmationDepth < 1)
|
|
396
451
|
throw new LifecyclePlanningError("INVALID_CONFIRMATIONS", "Confirmation depth must be a positive integer");
|
|
@@ -403,9 +458,15 @@ export async function readLaunchProgress(options, pinnedBlock) {
|
|
|
403
458
|
throw new LifecyclePlanningError("ACCOUNT_MISMATCH", "Execution account must be the committed creator/payer/refund account");
|
|
404
459
|
if (hashLaunchPlan(planned.plan).toLowerCase() !== planned.planHash.toLowerCase() || hashLaunchIdentity(planned.plan).toLowerCase() !== planned.launchId.toLowerCase())
|
|
405
460
|
throw new LifecyclePlanningError("PLAN_MUTATED", "Stored economic plan no longer matches its commitment");
|
|
406
|
-
const head
|
|
407
|
-
|
|
408
|
-
|
|
461
|
+
const [head, confirmedProgress, token, confirmedNonce, headNonce, pendingNonce] = await Promise.all([
|
|
462
|
+
readLifecycleContract(client, planned.plan.orchestrator, launchLifecycleAbi, "readLaunchProgress", [planned.launchId], block, planned.account),
|
|
463
|
+
confirmedNumber === block.number ? undefined : readLifecycleContract(client, planned.plan.orchestrator, launchLifecycleAbi, "readLaunchProgress", [planned.launchId], confirmedBlock, planned.account),
|
|
464
|
+
readLifecycleContract(client, planned.plan.orchestrator, launchLifecycleAbi, "predictToken", [planned.plan], block),
|
|
465
|
+
lifecycleRpc(client, "eth_getTransactionCount", [planned.account, toHex(confirmedBlock.number)]),
|
|
466
|
+
confirmedNumber === block.number ? undefined : lifecycleRpc(client, "eth_getTransactionCount", [planned.account, toHex(block.number)]),
|
|
467
|
+
lifecycleRpc(client, "eth_getTransactionCount", [planned.account, "pending"]),
|
|
468
|
+
]);
|
|
469
|
+
const canonical = confirmedProgress ?? head;
|
|
409
470
|
if (token.toLowerCase() !== planned.predictedToken.toLowerCase())
|
|
410
471
|
throw new LifecyclePlanningError("TOKEN_IDENTITY", "Predicted token changed for the committed token configuration");
|
|
411
472
|
for (const progress of [canonical, head])
|
|
@@ -417,33 +478,33 @@ export async function readLaunchProgress(options, pinnedBlock) {
|
|
|
417
478
|
if (progress.preparedMarkets > progress.marketCount || progress.phase === LifecyclePhase.Activating || (progress.phase === LifecyclePhase.Ready && progress.preparedMarkets !== progress.marketCount))
|
|
418
479
|
throw new LifecyclePlanningError("INVALID_PROGRESS", "Canonical progress violates the committed ordered state machine");
|
|
419
480
|
}
|
|
420
|
-
const confirmedAccountNonce = rpcQuantity(
|
|
421
|
-
const headAccountNonce =
|
|
422
|
-
const pendingAccountNonce = rpcQuantity(
|
|
481
|
+
const confirmedAccountNonce = rpcQuantity(confirmedNonce, "confirmed account nonce");
|
|
482
|
+
const headAccountNonce = headNonce === undefined ? confirmedAccountNonce : rpcQuantity(headNonce, "head account nonce");
|
|
483
|
+
const pendingAccountNonce = rpcQuantity(pendingNonce, "pending account nonce");
|
|
423
484
|
const progressParameters = [{ type: "tuple", components: launchProgressV1Components }];
|
|
424
485
|
const confirmationSafe = confirmedAccountNonce === headAccountNonce && pendingAccountNonce === headAccountNonce && keccak256(encodeAbiParameters(progressParameters, [canonical])) === keccak256(encodeAbiParameters(progressParameters, [head]));
|
|
425
|
-
const receipts = [];
|
|
426
|
-
|
|
427
|
-
receipts.push(await readReceipt({ ...reference, confirmations: Math.max(reference.confirmations ?? 1, confirmationDepth) }, options, block));
|
|
428
|
-
const markets = [];
|
|
486
|
+
const receipts = await Promise.all((options.receipts ?? []).map((reference) => readReceipt({ ...reference, confirmations: Math.max(reference.confirmations ?? 1, confirmationDepth) }, { ...options, client }, block)));
|
|
487
|
+
let markets = [];
|
|
429
488
|
if (canonical.preparedMarkets > 0) {
|
|
430
489
|
const directory = await readLifecycleContract(client, planned.plan.orchestrator, launchLifecycleAbi, "directory", [], confirmedBlock);
|
|
431
|
-
|
|
490
|
+
markets = await Promise.all(Array.from({ length: canonical.preparedMarkets }, async (_, index) => {
|
|
432
491
|
const [adapter, prepared] = await readLifecycleContract(client, directory, lifecycleDirectoryAbi, "market", [planned.launchId, index], confirmedBlock);
|
|
433
492
|
validateLifecycleMarketIdentity(prepared.identity, planned.plan, token, index);
|
|
434
493
|
try {
|
|
435
494
|
const live = await readLifecycleContract(client, adapter, lifecycleAdapterAbi, "readMarket", [planned.launchId, index], confirmedBlock);
|
|
436
|
-
|
|
495
|
+
return { index, prepared, live };
|
|
437
496
|
}
|
|
438
497
|
catch (failure) {
|
|
439
|
-
|
|
498
|
+
return { index, prepared, error: failure instanceof Error ? failure.message : String(failure) };
|
|
440
499
|
}
|
|
441
|
-
}
|
|
500
|
+
}));
|
|
442
501
|
}
|
|
443
|
-
if (
|
|
444
|
-
await assertLifecycleBlock(client, block);
|
|
502
|
+
if (checkBlock)
|
|
503
|
+
await assertLifecycleBlock(client, block, chainId);
|
|
445
504
|
if (confirmedNumber !== block.number)
|
|
446
|
-
await assertLifecycleBlock(client, confirmedBlock);
|
|
505
|
+
await assertLifecycleBlock(client, confirmedBlock, chainId);
|
|
506
|
+
if (hashLaunchPlan(planned.plan).toLowerCase() !== planned.planHash.toLowerCase() || hashLaunchIdentity(planned.plan).toLowerCase() !== planned.launchId.toLowerCase())
|
|
507
|
+
throw new LifecyclePlanningError("PLAN_MUTATED", "Stored economic plan changed during asynchronous progress reads");
|
|
447
508
|
return { canonical, head, confirmationDepth, confirmedBlockNumber: confirmedBlock.number, confirmedBlockHash: confirmedBlock.hash, confirmedAccountNonce, headAccountNonce, pendingAccountNonce, confirmationSafe, token, planHash: planned.planHash, launchId: planned.launchId, chainId, blockNumber: block.number, blockHash: block.hash, markets, receipts };
|
|
448
509
|
}
|
|
449
510
|
//# sourceMappingURL=progress.js.map
|