@black-market/sdk 0.4.0 → 0.5.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/README.md +128 -149
- package/assets/splash.png +0 -0
- package/dist/addresses.d.ts +3 -1
- package/dist/addresses.d.ts.map +1 -1
- package/dist/addresses.js +23 -17
- package/dist/addresses.js.map +1 -1
- package/dist/client.js +2 -2
- package/dist/client.js.map +1 -1
- package/dist/launch-api.d.ts +2 -1
- package/dist/launch-api.d.ts.map +1 -1
- package/dist/launch-api.js +2 -1
- package/dist/launch-api.js.map +1 -1
- package/dist/lifecycle/abi.d.ts +1246 -292
- package/dist/lifecycle/abi.d.ts.map +1 -1
- package/dist/lifecycle/abi.js +106 -12
- package/dist/lifecycle/abi.js.map +1 -1
- package/dist/lifecycle/progress.js +9 -9
- package/dist/lifecycle/progress.js.map +1 -1
- package/dist/lifecycle/schema.d.ts +3 -4
- package/dist/lifecycle/schema.d.ts.map +1 -1
- package/dist/lifecycle/schema.js +3 -4
- package/dist/lifecycle/schema.js.map +1 -1
- package/docs/launch-lifecycle.md +199 -41
- package/examples/.env.example +20 -0
- package/examples/README.md +223 -0
- package/examples/generate-lifecycle-commitment-fixture.mjs +49 -0
- package/examples/launch-erc20-abyss.mjs +7 -0
- package/examples/launch-erc20-burn-mixed.mjs +7 -0
- package/examples/launch-erc20-dividends-abyss.mjs +7 -0
- package/examples/launch-erc20-staking-v4.mjs +7 -0
- package/examples/launch-erc20-v4.mjs +7 -0
- package/examples/launch-erc404-abyss.mjs +7 -0
- package/examples/launch-erc404-dividends-mixed.mjs +7 -0
- package/examples/launch-erc404-v4.mjs +7 -0
- package/examples/launch-example-support.mjs +397 -0
- package/examples/launch-example.mjs +589 -0
- package/examples/launch-lifecycle-smoke.mjs +180 -0
- package/examples/launch.mjs +38 -0
- package/examples/quickstart.mjs +37 -0
- package/package.json +8 -3
- package/src/addresses.ts +25 -18
- package/src/client.ts +2 -2
- package/src/launch-api.ts +3 -2
- package/src/lifecycle/abi.ts +107 -12
- package/src/lifecycle/progress.ts +9 -9
- package/src/lifecycle/schema.ts +3 -4
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
// Deliberately executing proof on an owned disposable loopback fixture only.
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { readFile } from "node:fs/promises";
|
|
4
|
+
import { decodeEventLog, decodeFunctionResult, encodeFunctionData, toHex, zeroHash } from "viem";
|
|
5
|
+
import {
|
|
6
|
+
buildClaimDeveloperFeesPageTransaction, buildNextTransaction, buildPoolBoundHookDeploymentTransaction,
|
|
7
|
+
createControlledLifecycleFork, decodeDeveloperClaimReceipt, decodePoolBoundV4LifecycleMarketConfig,
|
|
8
|
+
encodeLaunchPlan, encodePoolBoundV4LifecycleMarketConfig, hashLaunchIdentity, hashLaunchPlan,
|
|
9
|
+
launchLifecycleAbi, lifecycleAdapterAbi, lifecycleDirectoryAbi, lifecycleErc20Abi, lifecycleFeeHubAbi,
|
|
10
|
+
LifecyclePhase, parseLaunchPlan, planLaunch, predictLifecycleToken, preparePoolBoundLifecyclePlan,
|
|
11
|
+
readAuthorHubs, readDeveloperFees, readLaunchProgress, readLifecycleProfiles, readPoolBoundHookDeployment,
|
|
12
|
+
simulateLaunchPlan,
|
|
13
|
+
} from "../dist/lifecycle/index.js";
|
|
14
|
+
const [manifestFile, plansFile] = process.argv.slice(2);
|
|
15
|
+
if (!manifestFile || !plansFile) throw new Error("Usage: node examples/launch-lifecycle-smoke.mjs manifest.json sdk-plans.json");
|
|
16
|
+
const manifest = JSON.parse(await readFile(manifestFile, "utf8"));
|
|
17
|
+
const exported = JSON.parse(await readFile(plansFile, "utf8"));
|
|
18
|
+
const rpcUrl = process.env.LAUNCH_LIFECYCLE_RPC_URL;
|
|
19
|
+
const forkRpcUrl = process.env.LAUNCH_LIFECYCLE_FORK_RPC_URL;
|
|
20
|
+
if (!rpcUrl || !forkRpcUrl || !["127.0.0.1", "localhost", "[::1]"].includes(new URL(rpcUrl).hostname) || process.env.LAUNCH_LIFECYCLE_ALLOW_LOCAL_EXECUTION !== "1" || manifest.fixtureOnly !== true) throw new Error("Smoke requires explicitly authorized owned loopback fixture execution and a separate disposable fork");
|
|
21
|
+
if (!Array.isArray(exported.plans) || exported.plans.length === 0) throw new Error("Current Solidity-exported reviewed plans are required");
|
|
22
|
+
let requestId = 0;
|
|
23
|
+
const client = { async request({ method, params = [] }) {
|
|
24
|
+
const response = await fetch(rpcUrl, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ jsonrpc: "2.0", id: ++requestId, method, params }) });
|
|
25
|
+
if (!response.ok) throw new Error(`RPC HTTP ${response.status}`);
|
|
26
|
+
const body = await response.json();
|
|
27
|
+
if (body.error) throw Object.assign(new Error(`${method}: ${body.error.message}`), { data: body.error.data });
|
|
28
|
+
return body.result;
|
|
29
|
+
} };
|
|
30
|
+
const chainId = BigInt(await client.request({ method: "eth_chainId" }));
|
|
31
|
+
assert.equal(chainId, BigInt(manifest.chainId));
|
|
32
|
+
const policy = manifest.executionLimits;
|
|
33
|
+
assert.equal(policy?.provenance?.scope, "controlled-local-measurement", "Operator policy must not invent live RPC/account limits");
|
|
34
|
+
const limits = async ({ block, chainId, account, orchestrator }) => ({
|
|
35
|
+
chainId, account, orchestrator, observedBlockNumber: block.number, observedBlockHash: block.hash,
|
|
36
|
+
chainGasLimit: BigInt(policy.chainTransactionGasLimit), rpcGasLimit: BigInt(policy.rpcTransactionGasLimit),
|
|
37
|
+
accountGasLimit: BigInt(policy.accountTransactionGasLimit), maxCalldataBytes: Number(policy.maxCalldataBytes), headroomBps: Number(policy.headroomBps),
|
|
38
|
+
});
|
|
39
|
+
const fork = createControlledLifecycleFork({ sourceRpcUrl: rpcUrl, forkRpcUrl, allowTransactions: true, impersonation: "anvil" });
|
|
40
|
+
async function readContract(to, abi, functionName, args = []) {
|
|
41
|
+
return decodeFunctionResult({ abi, functionName, data: await client.request({ method: "eth_call", params: [{ to, data: encodeFunctionData({ abi, functionName, args }) }, "latest"] }) });
|
|
42
|
+
}
|
|
43
|
+
async function send(transaction) {
|
|
44
|
+
assert.equal(BigInt(transaction.chainId), chainId);
|
|
45
|
+
const gasPrice = transaction.gasPrice ?? BigInt(await client.request({ method: "eth_gasPrice" }));
|
|
46
|
+
const head = await client.request({ method: "eth_getBlockByNumber", params: ["latest", false] });
|
|
47
|
+
const ceiling = [BigInt(head.gasLimit), BigInt(policy.chainTransactionGasLimit), BigInt(policy.rpcTransactionGasLimit), BigInt(policy.accountTransactionGasLimit)].reduce((a, b) => a < b ? a : b);
|
|
48
|
+
const wire = { from: transaction.from, to: transaction.to, data: transaction.data, value: toHex(transaction.value), gasPrice: toHex(gasPrice) };
|
|
49
|
+
const estimated = transaction.gas ?? ((BigInt(await client.request({ method: "eth_estimateGas", params: [{ ...wire, gas: toHex(ceiling) }] })) * BigInt(10000 + Number(policy.headroomBps)) + 9999n) / 10000n);
|
|
50
|
+
assert.ok(estimated <= ceiling, "Unsigned helper must still fit explicit local execution admission");
|
|
51
|
+
const transactionHash = await client.request({ method: "eth_sendTransaction", params: [{ ...wire, gas: toHex(estimated) }] });
|
|
52
|
+
let receipt;
|
|
53
|
+
for (const deadline = Date.now() + 30000; Date.now() < deadline;) {
|
|
54
|
+
receipt = await client.request({ method: "eth_getTransactionReceipt", params: [transactionHash] });
|
|
55
|
+
if (receipt) break;
|
|
56
|
+
await new Promise((resolve) => setTimeout(resolve, 25));
|
|
57
|
+
}
|
|
58
|
+
assert.equal(receipt?.status, "0x1", `Actual local transaction must succeed: ${transactionHash}`);
|
|
59
|
+
return { receipt, reference: { transactionHash, observedBlockNumber: BigInt(receipt.blockNumber), observedBlockHash: receipt.blockHash, confirmations: 1 } };
|
|
60
|
+
}
|
|
61
|
+
function events(receipt, address, abi, name) {
|
|
62
|
+
return receipt.logs.filter((log) => log.address.toLowerCase() === address.toLowerCase()).flatMap((log) => {
|
|
63
|
+
try { const decoded = decodeEventLog({ abi, data: log.data, topics: log.topics, strict: true }); return decoded.eventName === name ? [decoded.args] : []; } catch { return []; }
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
const profiles = await readLifecycleProfiles({ client, orchestrator: manifest.addresses.orchestrator });
|
|
67
|
+
for (const row of exported.plans) for (const market of parseLaunchPlan(JSON.stringify(row.plan)).markets) {
|
|
68
|
+
const profile = profiles.find((profile) => profile.id.toLowerCase() === market.profileId.toLowerCase());
|
|
69
|
+
assert.equal(profile?.admitted, true, profile?.reason);
|
|
70
|
+
}
|
|
71
|
+
const results = [];
|
|
72
|
+
for (const row of exported.plans) for (const mode of ["atomic", "staged"]) {
|
|
73
|
+
const snapshot = await client.request({ method: "evm_snapshot" });
|
|
74
|
+
try {
|
|
75
|
+
let plan = parseLaunchPlan(JSON.stringify(row.plan));
|
|
76
|
+
assert.equal(encodeLaunchPlan(plan).toLowerCase(), row.encodedPlan.toLowerCase());
|
|
77
|
+
assert.equal(hashLaunchPlan(plan).toLowerCase(), row.planHash.toLowerCase());
|
|
78
|
+
assert.equal(hashLaunchIdentity(plan).toLowerCase(), row.launchId.toLowerCase());
|
|
79
|
+
assert.equal((await predictLifecycleToken({ client, plan })).toLowerCase(), row.predictedToken.toLowerCase());
|
|
80
|
+
const draft = { ...plan, markets: plan.markets.map((market) => market.configVersion === 5 ? {
|
|
81
|
+
...market, config: encodePoolBoundV4LifecycleMarketConfig({ ...decodePoolBoundV4LifecycleMarketConfig(market.config), hookSalt: zeroHash }),
|
|
82
|
+
} : market) };
|
|
83
|
+
const prepared = await preparePoolBoundLifecyclePlan({ client, plan: draft });
|
|
84
|
+
plan = prepared.plan;
|
|
85
|
+
assert.equal(hashLaunchPlan(plan).toLowerCase(), row.planHash.toLowerCase(), "Offchain mining reproduces the independent constructor/salt vector");
|
|
86
|
+
if (mode === "staged") for (const deployment of prepared.deployments) {
|
|
87
|
+
const unsigned = await buildPoolBoundHookDeploymentTransaction({ client, plan, marketIndex: deployment.marketIndex });
|
|
88
|
+
await send({ chainId: Number(chainId), from: plan.creator, ...unsigned });
|
|
89
|
+
const actual = await readPoolBoundHookDeployment({ client, plan, marketIndex: deployment.marketIndex });
|
|
90
|
+
assert.equal(actual.predictedHook.toLowerCase(), deployment.predictedHook.toLowerCase());
|
|
91
|
+
}
|
|
92
|
+
const planned = await planLaunch({ client, account: plan.creator, plan, mode, limits, fork });
|
|
93
|
+
assert.equal(planned.simulation.admitted, true, planned.simulation.reason);
|
|
94
|
+
const atomicReceipt = planned.atomicAttempt.steps.find((step) => step.transactionId === "atomic")?.returnData;
|
|
95
|
+
if (atomicReceipt) {
|
|
96
|
+
const decoded = decodeFunctionResult({ abi: launchLifecycleAbi, functionName: "launchAtomic", data: atomicReceipt });
|
|
97
|
+
assert.equal(decoded.planHash.toLowerCase(), planned.planHash.toLowerCase());
|
|
98
|
+
for (let i = 0; i < plan.buys.length; ++i) assert.ok(decoded.tokenOut[i] >= plan.buys[i].minTokenOut);
|
|
99
|
+
}
|
|
100
|
+
const replay = await simulateLaunchPlan({ client, planned, limits, fork });
|
|
101
|
+
assert.equal(replay.admitted, true, replay.reason);
|
|
102
|
+
const receipts = [];
|
|
103
|
+
let activationReceipt;
|
|
104
|
+
for (let guard = 0; guard < 64; ++guard) {
|
|
105
|
+
const next = await buildNextTransaction({ client, planned, receipts, limits, fork });
|
|
106
|
+
if (!next) break;
|
|
107
|
+
const submitted = await send(next);
|
|
108
|
+
receipts.push(submitted.reference);
|
|
109
|
+
if (["atomic", "activate"].includes(next.kind)) activationReceipt = submitted.receipt;
|
|
110
|
+
}
|
|
111
|
+
const progress = await readLaunchProgress({ client, planned, receipts });
|
|
112
|
+
assert.equal(progress.canonical.phase, LifecyclePhase.Active);
|
|
113
|
+
assert.equal(progress.token.toLowerCase(), row.predictedToken.toLowerCase());
|
|
114
|
+
assert.equal(progress.canonical.marketCount, plan.markets.length);
|
|
115
|
+
const buys = events(activationReceipt, plan.orchestrator, launchLifecycleAbi, "InitialBuyExecuted");
|
|
116
|
+
assert.equal(buys.length, plan.buys.length);
|
|
117
|
+
for (let i = 0; i < buys.length; ++i) {
|
|
118
|
+
assert.equal(buys[i].buyIndex, i); assert.equal(buys[i].marketIndex, plan.buys[i].marketIndex);
|
|
119
|
+
assert.ok(buys[i].tokenOut >= plan.buys[i].minTokenOut); assert.ok(buys[i].quoteSpent <= plan.buys[i].quoteAmountIn);
|
|
120
|
+
}
|
|
121
|
+
const directory = await readContract(plan.orchestrator, launchLifecycleAbi, "directory");
|
|
122
|
+
for (const market of progress.markets) {
|
|
123
|
+
assert.equal(market.live.publicTrading, true);
|
|
124
|
+
const positions = await readContract(directory, lifecycleDirectoryAbi, "positions", [planned.launchId, market.index, 0n, 32n]);
|
|
125
|
+
const profile = profiles.find((profile) => profile.id.toLowerCase() === market.prepared.identity.profileId.toLowerCase());
|
|
126
|
+
for (const position of positions) {
|
|
127
|
+
const [liquidity, custody] = await readContract(profile.adapter.implementation, lifecycleAdapterAbi, "readPosition", [position]);
|
|
128
|
+
assert.equal(liquidity, position.liquidity); assert.equal(custody.toLowerCase(), market.prepared.custody.toLowerCase());
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
assert.equal(await buildNextTransaction({ client, planned, receipts, limits, fork }), undefined);
|
|
132
|
+
const hub = progress.canonical.feeHub;
|
|
133
|
+
assert.equal(await readContract(hub, lifecycleFeeHubAbi, "economicVersion"), 3);
|
|
134
|
+
const authors = new Map();
|
|
135
|
+
for (const source of await readContract(hub, lifecycleFeeHubAbi, "sources")) {
|
|
136
|
+
const terms = await readContract(hub, lifecycleFeeHubAbi, "sourceTerms", [source]);
|
|
137
|
+
if (terms.developerFeeBps > 0) authors.set(terms.beneficiary.toLowerCase(), terms.beneficiary);
|
|
138
|
+
}
|
|
139
|
+
const ownerBefore = await Promise.all(plan.feeAssets.map((policy) => readContract(hub, lifecycleFeeHubAbi, "claimableOwnerFees", [plan.creator, policy.asset])));
|
|
140
|
+
const harvestData = encodeFunctionData({ abi: lifecycleFeeHubAbi, functionName: "claimAndSplit", args: [] });
|
|
141
|
+
const preview = decodeFunctionResult({ abi: lifecycleFeeHubAbi, functionName: "claimAndSplit", data: await client.request({ method: "eth_call", params: [{ from: plan.creator, to: hub, data: harvestData }, "latest"] }) });
|
|
142
|
+
const harvest = await send({ chainId: Number(chainId), from: plan.creator, to: hub, data: harvestData, value: 0n });
|
|
143
|
+
const distributions = events(harvest.receipt, hub, lifecycleFeeHubAbi, "Distributed");
|
|
144
|
+
assert.ok(distributions.some((event) => event.newlyCollected > 0n), "Real opening swaps produce actual source fees");
|
|
145
|
+
for (let i = 0; i < plan.feeAssets.length; ++i) {
|
|
146
|
+
const policy = plan.feeAssets[i];
|
|
147
|
+
const distribution = distributions.find((event) => event.asset.toLowerCase() === policy.asset.toLowerCase());
|
|
148
|
+
assert.equal(distribution.ownerAmount + distribution.developerAmount + distribution.executorAmount + distribution.rewardsAmount + distribution.burnAmount, distribution.newlyCollected);
|
|
149
|
+
assert.equal(preview.find((payment) => payment.asset.toLowerCase() === policy.asset.toLowerCase()).amount, distribution.executorAmount);
|
|
150
|
+
assert.equal(await readContract(hub, lifecycleFeeHubAbi, "claimableOwnerFees", [plan.creator, policy.asset]) - ownerBefore[i], distribution.ownerAmount);
|
|
151
|
+
assert.equal(await readContract(policy.asset, lifecycleErc20Abi, "balanceOf", [hub]),
|
|
152
|
+
await readContract(hub, lifecycleFeeHubAbi, "reservedOwnerFees", [policy.asset]) + await readContract(hub, lifecycleFeeHubAbi, "reservedDeveloperFees", [policy.asset]));
|
|
153
|
+
}
|
|
154
|
+
const claims = [];
|
|
155
|
+
for (const authorId of authors.values()) {
|
|
156
|
+
const discovered = await readAuthorHubs({ client, registry: manifest.addresses.implementationRegistry, authorId });
|
|
157
|
+
assert.ok(discovered.hubs.some((value) => value.toLowerCase() === hub.toLowerCase()));
|
|
158
|
+
const fees = await readDeveloperFees({ client, registry: discovered.registry, authorId, hub });
|
|
159
|
+
const balancesBefore = await Promise.all(fees.assets.map((asset) => readContract(asset, lifecycleErc20Abi, "balanceOf", [fees.payout])));
|
|
160
|
+
const unsigned = await buildClaimDeveloperFeesPageTransaction({ client, registry: discovered.registry, authorId, offset: 0n, limit: 10n, assets: [], account: plan.creator, chainId });
|
|
161
|
+
// Bound every page child call with the explicit owned-fixture operator ceiling;
|
|
162
|
+
// eth_estimateGas may otherwise succeed after reporting gas-starved failed rows.
|
|
163
|
+
const head = await client.request({ method: "eth_getBlockByNumber", params: ["latest", false] });
|
|
164
|
+
const pageGas = [BigInt(head.gasLimit), BigInt(policy.chainTransactionGasLimit), BigInt(policy.rpcTransactionGasLimit), BigInt(policy.accountTransactionGasLimit)].reduce((a, b) => a < b ? a : b);
|
|
165
|
+
const claim = await send({ ...unsigned, gas: pageGas });
|
|
166
|
+
const result = decodeDeveloperClaimReceipt({ receipt: claim.receipt, transaction: unsigned });
|
|
167
|
+
assert.equal(result.cursorComplete, true); assert.equal(result.paymentsSucceeded, true);
|
|
168
|
+
for (let i = 0; i < fees.assets.length; ++i) {
|
|
169
|
+
const amount = result.results.filter((row) => row.asset.toLowerCase() === fees.assets[i].toLowerCase()).reduce((total, row) => total + row.amount, 0n);
|
|
170
|
+
assert.equal(await readContract(fees.assets[i], lifecycleErc20Abi, "balanceOf", [fees.payout]) - balancesBefore[i], amount);
|
|
171
|
+
}
|
|
172
|
+
claims.push({ authorId, transactionHash: claim.reference.transactionHash, result });
|
|
173
|
+
}
|
|
174
|
+
results.push({ name: row.name, mode, phase: "Active", planHash: planned.planHash, token: progress.token, backend: replay.backend, receipts, buys, distributions, claims });
|
|
175
|
+
} finally {
|
|
176
|
+
assert.equal(await client.request({ method: "evm_revert", params: [snapshot] }), true);
|
|
177
|
+
await client.request({ method: "evm_mine" });
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
console.log(JSON.stringify({ schema: "black-market.node-sdk-smoke.v1", results }, (_key, value) => typeof value === "bigint" ? value.toString() : value, 2));
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// Reviewed launch planning only: no signatures, source-chain writes, uploads or publication.
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import { createPublicClient, http } from "viem";
|
|
4
|
+
import {
|
|
5
|
+
buildNextTransaction, createControlledLifecycleFork, parseLaunchPlan, planLaunch,
|
|
6
|
+
preparePoolBoundLifecyclePlan, readLaunchProgress, readLifecycleProfiles, serializeLaunchPlan,
|
|
7
|
+
} from "../dist/index.js";
|
|
8
|
+
const args = process.argv.slice(2);
|
|
9
|
+
const option = (name) => { const index = args.indexOf(name); return index === -1 ? undefined : args[index + 1]; };
|
|
10
|
+
const planFile = option("--plan"), rpcUrl = option("--rpc"), mode = option("--mode");
|
|
11
|
+
if (!planFile || !rpcUrl || !["atomic", "staged"].includes(mode)) {
|
|
12
|
+
throw new Error("Usage: node examples/launch.mjs --plan plan.json --rpc RPC_URL --mode atomic|staged [--limits current-limits.json] [--receipts receipts.json] [--confirmations N] [--fork-rpc LOOPBACK_RPC_URL] [--mine]");
|
|
13
|
+
}
|
|
14
|
+
const client = createPublicClient({ transport: http(rpcUrl) });
|
|
15
|
+
let plan = parseLaunchPlan(await readFile(planFile, "utf8"));
|
|
16
|
+
const profiles = await readLifecycleProfiles({ client, orchestrator: plan.orchestrator, profileIds: [...new Set(plan.markets.map((market) => market.profileId))] });
|
|
17
|
+
for (const profile of profiles) console.log(profile.id, profile.venueKind, profile.topology, profile.admitted ? "admitted" : profile.reason);
|
|
18
|
+
if (args.includes("--mine")) plan = (await preparePoolBoundLifecyclePlan({ client, plan,
|
|
19
|
+
onProgress: ({ marketIndex, attempts }) => console.error("salt mining", marketIndex, attempts.toString()),
|
|
20
|
+
})).plan;
|
|
21
|
+
const limitsFile = option("--limits");
|
|
22
|
+
const limits = limitsFile ? JSON.parse(await readFile(limitsFile, "utf8")) : undefined;
|
|
23
|
+
if (limits) for (const key of ["chainId", "observedBlockNumber", "chainGasLimit", "rpcGasLimit", "accountGasLimit", "maxSimulationGas"]) {
|
|
24
|
+
if (limits[key] !== undefined) limits[key] = BigInt(limits[key]);
|
|
25
|
+
}
|
|
26
|
+
const receiptsFile = option("--receipts");
|
|
27
|
+
const receipts = receiptsFile ? JSON.parse(await readFile(receiptsFile, "utf8"), (key, value) => key === "observedBlockNumber" ? BigInt(value) : value) : [];
|
|
28
|
+
const confirmations = Number(option("--confirmations") ?? "1");
|
|
29
|
+
const forkRpcUrl = option("--fork-rpc");
|
|
30
|
+
const fork = forkRpcUrl ? createControlledLifecycleFork({ sourceRpcUrl: rpcUrl, forkRpcUrl, allowTransactions: true, impersonation: "anvil" }) : undefined;
|
|
31
|
+
const planned = await planLaunch({ client, account: plan.creator, plan, mode, limits, fork, receipts, confirmations });
|
|
32
|
+
const progress = await readLaunchProgress({ client, planned, receipts });
|
|
33
|
+
const next = planned.simulation.admitted ? await buildNextTransaction({ client, planned, limits, fork, receipts }) : undefined;
|
|
34
|
+
console.log(JSON.stringify({ plan: JSON.parse(serializeLaunchPlan(plan)), mode,
|
|
35
|
+
simulation: planned.simulation, atomicAttempt: planned.atomicAttempt, progress, next },
|
|
36
|
+
(_key, value) => typeof value === "bigint" ? value.toString() : value, 2));
|
|
37
|
+
// Persist the returned plan/mode/confirmation policy and receipt references. An application
|
|
38
|
+
// must separately review, authenticate its wallet chain and sign exactly `next` if admitted.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Read-only deployed graph discovery. No signatures, transactions, uploads, or publication.
|
|
2
|
+
import { zeroAddress } from "viem";
|
|
3
|
+
import {
|
|
4
|
+
createProtocolPublicClient, getAddresses, isSupportedChainId,
|
|
5
|
+
launchLifecycleAbi, readLifecycleProfiles,
|
|
6
|
+
} from "../dist/index.js";
|
|
7
|
+
|
|
8
|
+
const chainId = Number(process.env.CHAIN_ID ?? "4663");
|
|
9
|
+
if (!isSupportedChainId(chainId)) throw new Error("CHAIN_ID must be 4663, 46631, or 31337");
|
|
10
|
+
const infrastructure = getAddresses(chainId);
|
|
11
|
+
if (infrastructure.launchOrchestrator === zeroAddress) {
|
|
12
|
+
throw new Error("Set LAUNCH_ORCHESTRATOR and the matching deployment addresses for this local chain; no mainnet launch address is assumed locally.");
|
|
13
|
+
}
|
|
14
|
+
const client = createProtocolPublicClient({ chainId });
|
|
15
|
+
if (await client.getChainId() !== chainId) throw new Error("RPC chain ID differs from CHAIN_ID");
|
|
16
|
+
const registry = await client.readContract({
|
|
17
|
+
address: infrastructure.launchOrchestrator,
|
|
18
|
+
abi: launchLifecycleAbi,
|
|
19
|
+
functionName: "registry",
|
|
20
|
+
});
|
|
21
|
+
if (registry.toLowerCase() !== infrastructure.launchImplementationRegistry.toLowerCase()) {
|
|
22
|
+
throw new Error("The selected orchestrator and LAUNCH_IMPLEMENTATION_REGISTRY are not the same deployment graph");
|
|
23
|
+
}
|
|
24
|
+
const profiles = await readLifecycleProfiles({ client, orchestrator: infrastructure.launchOrchestrator });
|
|
25
|
+
console.log("chain:", chainId);
|
|
26
|
+
console.log("orchestrator:", infrastructure.launchOrchestrator);
|
|
27
|
+
console.log("registry:", registry);
|
|
28
|
+
console.table(profiles.map((profile) => ({
|
|
29
|
+
profile: profile.id,
|
|
30
|
+
venue: profile.venueKind,
|
|
31
|
+
configVersion: profile.topology.configVersion,
|
|
32
|
+
admitted: profile.admitted,
|
|
33
|
+
reason: profile.reason ?? "",
|
|
34
|
+
})));
|
|
35
|
+
console.log("Abyss router:", infrastructure.abyssRouter);
|
|
36
|
+
console.log("lending pool:", infrastructure.lendingPool);
|
|
37
|
+
if (!profiles.some((profile) => profile.admitted)) throw new Error("No current profile was admitted by the selected deployment");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@black-market/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "Canonical TypeScript SDK for Black Market on Robinhood Chain (reviewed multi-market launches, Abyss DEX, lending).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -23,7 +23,9 @@
|
|
|
23
23
|
"files": [
|
|
24
24
|
"dist",
|
|
25
25
|
"src",
|
|
26
|
-
"docs"
|
|
26
|
+
"docs",
|
|
27
|
+
"assets",
|
|
28
|
+
"examples"
|
|
27
29
|
],
|
|
28
30
|
"sideEffects": false,
|
|
29
31
|
"engines": {
|
|
@@ -40,7 +42,10 @@
|
|
|
40
42
|
"examples": "pnpm build && node examples/quickstart.mjs",
|
|
41
43
|
"lint": "tsc -p tsconfig.json --noEmit",
|
|
42
44
|
"prepublishOnly": "pnpm build",
|
|
43
|
-
"test": "pnpm
|
|
45
|
+
"test": "pnpm test:unit",
|
|
46
|
+
"test:unit": "pnpm build && node --test test/*.test.mjs",
|
|
47
|
+
"test:api": "pnpm build && node --test test/integration/launch-api.read.test.mjs",
|
|
48
|
+
"test:api:write": "pnpm build && node --test test/integration/launch-api.sessions.test.mjs",
|
|
44
49
|
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
45
50
|
},
|
|
46
51
|
"dependencies": {
|
package/src/addresses.ts
CHANGED
|
@@ -20,7 +20,7 @@ export type AbyssInfrastructureAddresses = {
|
|
|
20
20
|
};
|
|
21
21
|
|
|
22
22
|
export type LaunchApplicationAddresses = {
|
|
23
|
-
/**
|
|
23
|
+
/** Mined mainnet deployment; local chains require explicit environment configuration. */
|
|
24
24
|
launchOrchestrator: Address;
|
|
25
25
|
launchImplementationRegistry: Address;
|
|
26
26
|
launchFeeOwnerRegistry: Address;
|
|
@@ -177,19 +177,26 @@ export const robinhoodAbyssInfrastructure: AbyssInfrastructureAddresses = {
|
|
|
177
177
|
abyssFeeRouter: "0x2c3B1b6fe0EDa8e10C0445567b47e66E825B34cd",
|
|
178
178
|
};
|
|
179
179
|
|
|
180
|
+
/** Mined pool-launch-v1 deployment, 20261005T053747Z-b5a7b88 (manifest.json). */
|
|
181
|
+
export const robinhoodLaunchApplication: LaunchApplicationAddresses = {
|
|
182
|
+
launchOrchestrator: "0xb75CBD17b9aecb7305B4DFcDa69595F783341c0E",
|
|
183
|
+
launchImplementationRegistry: "0xaa8a410709B79cBA6F118F1be1FF568877A3B8Ee",
|
|
184
|
+
launchFeeOwnerRegistry: "0x15778Aad08e12D458B2848F035860e2a8c2a0725",
|
|
185
|
+
};
|
|
186
|
+
|
|
180
187
|
|
|
181
|
-
/**
|
|
188
|
+
/** Robinhood-mainnet fork lending defaults; launch deployment remains explicit. */
|
|
182
189
|
const workbenchDefaults: ProtocolAddresses = {
|
|
183
190
|
...robinhoodAbyssInfrastructure,
|
|
184
191
|
...launchApplicationFromEnv(zeroLaunchApplication),
|
|
185
|
-
lendingPool: "
|
|
186
|
-
addressesProvider: "
|
|
187
|
-
dataProvider: "
|
|
192
|
+
lendingPool: "0x5D8878b145904425C598f12EB8eD550985369a82",
|
|
193
|
+
addressesProvider: "0x892faB533E8D04135D902F94974e45dB48C17697",
|
|
194
|
+
dataProvider: "0x1f3faA42C1D5cC330f6BD0242B9a56d611bdC78a",
|
|
188
195
|
uiPoolDataProvider: zero,
|
|
189
196
|
walletBalanceProvider: zero,
|
|
190
|
-
aaveOracle: "
|
|
197
|
+
aaveOracle: "0x6837B3cF5d959d01e07bf6DaB53f562877BF7d53",
|
|
191
198
|
liquidationExecutor: zero,
|
|
192
|
-
protocolVault: "
|
|
199
|
+
protocolVault: "0x83Ec5DbFEd6d972be89df88d3654EA2c70Fa2FB3",
|
|
193
200
|
ethUsdFeed: ROBINHOOD_ETH_USD,
|
|
194
201
|
weth: ROBINHOOD_WETH,
|
|
195
202
|
wethGateway: zero,
|
|
@@ -233,26 +240,26 @@ export const addresses: Record<SupportedChainId, ProtocolAddresses> = {
|
|
|
233
240
|
tokenVesting: envAddr(["TOKEN_VESTING", "VITE_TOKEN_VESTING", "NEXT_PUBLIC_TOKEN_VESTING"]),
|
|
234
241
|
faucet: envAddr(["FAUCET", "VITE_FAUCET", "NEXT_PUBLIC_FAUCET"]),
|
|
235
242
|
},
|
|
236
|
-
/**
|
|
243
|
+
/** Current mined launch, canonical Abyss, and replacement lending infrastructure. */
|
|
237
244
|
4663: {
|
|
238
245
|
...robinhoodAbyssInfrastructure,
|
|
239
|
-
...launchApplicationFromEnv(
|
|
240
|
-
lendingPool: "
|
|
241
|
-
addressesProvider: "
|
|
242
|
-
dataProvider: "
|
|
243
|
-
uiPoolDataProvider: "
|
|
244
|
-
walletBalanceProvider: "
|
|
245
|
-
aaveOracle: "
|
|
246
|
+
...launchApplicationFromEnv(robinhoodLaunchApplication),
|
|
247
|
+
lendingPool: "0x5D8878b145904425C598f12EB8eD550985369a82",
|
|
248
|
+
addressesProvider: "0x892faB533E8D04135D902F94974e45dB48C17697",
|
|
249
|
+
dataProvider: "0x1f3faA42C1D5cC330f6BD0242B9a56d611bdC78a",
|
|
250
|
+
uiPoolDataProvider: "0x02D2CA3bBbBaBD3C25bEDD4bE0eE6E5885C4D152",
|
|
251
|
+
walletBalanceProvider: "0xBbb5D81123C3d514456974e9Fe6C7C8d7a0E4E2A",
|
|
252
|
+
aaveOracle: "0x6837B3cF5d959d01e07bf6DaB53f562877BF7d53",
|
|
246
253
|
liquidationExecutor: envAddr([
|
|
247
254
|
"LIQUIDATION_EXECUTOR",
|
|
248
255
|
"VITE_LIQUIDATION_EXECUTOR",
|
|
249
256
|
"NEXT_PUBLIC_LIQUIDATION_EXECUTOR",
|
|
250
257
|
]),
|
|
251
|
-
protocolVault: "
|
|
258
|
+
protocolVault: "0x83Ec5DbFEd6d972be89df88d3654EA2c70Fa2FB3",
|
|
252
259
|
ethUsdFeed: ROBINHOOD_ETH_USD,
|
|
253
260
|
weth: ROBINHOOD_WETH,
|
|
254
|
-
wethGateway: "
|
|
255
|
-
lens: "
|
|
261
|
+
wethGateway: "0xa16aB7646267327cB26dD3533526309cDe676d9d",
|
|
262
|
+
lens: "0xB56079f966597CB9edaE27c589F8190f4dCD12df",
|
|
256
263
|
tokenVesting: zero,
|
|
257
264
|
faucet: zero,
|
|
258
265
|
},
|
package/src/client.ts
CHANGED
|
@@ -20,7 +20,7 @@ export function createProtocolPublicClient(opts?: {
|
|
|
20
20
|
}): PublicClient {
|
|
21
21
|
const chainId = opts?.chainId ?? 31337;
|
|
22
22
|
const chain = chains[chainId] ?? foundry;
|
|
23
|
-
const transport = http(opts?.rpcUrl ?? process.env.RPC_URL ??
|
|
23
|
+
const transport = http(opts?.rpcUrl ?? process.env.RPC_URL ?? chain.rpcUrls.default.http[0]);
|
|
24
24
|
return createPublicClient({ chain, transport });
|
|
25
25
|
}
|
|
26
26
|
|
|
@@ -31,7 +31,7 @@ export function createProtocolWalletClient(opts: {
|
|
|
31
31
|
}): WalletClient {
|
|
32
32
|
const chainId = opts.chainId ?? 31337;
|
|
33
33
|
const chain: Chain = chains[chainId] ?? foundry;
|
|
34
|
-
const transport: Transport = http(opts.rpcUrl ?? process.env.RPC_URL ??
|
|
34
|
+
const transport: Transport = http(opts.rpcUrl ?? process.env.RPC_URL ?? chain.rpcUrls.default.http[0]);
|
|
35
35
|
const account: Account = privateKeyToAccount(opts.privateKey);
|
|
36
36
|
return createWalletClient({ account, chain, transport });
|
|
37
37
|
}
|
package/src/launch-api.ts
CHANGED
|
@@ -14,7 +14,7 @@ export type LaunchAttributionAuthorization = { nonce: Hex; deadline: string; sig
|
|
|
14
14
|
export type LaunchSessionCreateRequest = { chainId: number; wallet: Address; metadata: LaunchSessionCreateMetadata; image?: LaunchSessionImageDescriptor; authorization: LaunchAttributionAuthorization };
|
|
15
15
|
export type LaunchSessionPublishRequest = { chainId: number; transactionHash: Hash };
|
|
16
16
|
export type LaunchSessionStatus = "awaiting_upload" | "verifying_image" | "ready_to_launch" | "transaction_submitted" | "awaiting_indexer" | "optimistic" | "final" | "reorged" | "expired" | "rejected";
|
|
17
|
-
export type LaunchSessionDirectUpload = { url: string; headers: Record<string, string>;
|
|
17
|
+
export type LaunchSessionDirectUpload = { url: string; method: "PUT"; headers: Record<string, string>; expiresInSeconds: number };
|
|
18
18
|
export type LaunchSessionResponse = { sessionId: string; chainId: number; wallet: Address; status: LaunchSessionStatus; metadata: { name: string; symbol: string; description: string | null; websiteUrl: string | null; twitterUrl: string | null; telegramUrl: string | null; discordUrl: string | null }; image: { sha256: Hex; contentType: LaunchImageContentType; contentLength: number; width: number | null; height: number | null } | null; transactionHash?: Hash | null; token?: Address | null; canonicalStatus: "pending" | "optimistic" | "final" | "reorged"; metadataStatus: "queued" | "ready" | "needs_owner_action" | "none"; imageStatus: "none" | "upload_pending" | "verifying" | "ready" | "rejected"; retryable: boolean; createdAt: string; updatedAt: string; sessionExpiresAt: string; publishedAt?: string; upload?: LaunchSessionDirectUpload; capability?: string; imageUrl?: string };
|
|
19
19
|
export type LaunchApiErrorCode = "INVALID_REQUEST" | "INVALID_ADDRESS" | "INVALID_IDEMPOTENCY_KEY" | "INVALID_CAPABILITY" | "UNSUPPORTED_CHAIN" | "NOT_FOUND" | "IMAGE_INVALID" | "SESSION_STATE_CONFLICT" | "SESSION_EXPIRED" | "IDEMPOTENCY_CONFLICT" | "UPLOAD_CONFLICT" | "RATE_LIMITED" | "OVERLOADED" | "RPC_UNAVAILABLE" | "RPC_TIMEOUT" | "INDEXER_UNAVAILABLE" | "APP_STORAGE_UNAVAILABLE" | "IMAGE_STORAGE_UNAVAILABLE" | "TX_REVERTED" | "TX_PROVENANCE_MISMATCH" | "TX_METADATA_MISMATCH" | (string & {});
|
|
20
20
|
|
|
@@ -102,7 +102,8 @@ export const launchAttributionTypes = { LaunchAttribution: [
|
|
|
102
102
|
{ name: "idempotencyKey", type: "string" }, { name: "nonce", type: "bytes32" }, { name: "deadline", type: "uint256" },
|
|
103
103
|
] } as const;
|
|
104
104
|
export function canonicalLaunchMetadataHash(metadata: LaunchSessionMetadata): Hex {
|
|
105
|
-
|
|
105
|
+
const url = (value: string | undefined) => value === undefined ? null : new URL(value.normalize("NFC").trim()).toString();
|
|
106
|
+
return keccak256(stringToHex(JSON.stringify({ name: metadata.name.normalize("NFC").trim(), symbol: metadata.symbol.normalize("NFC").trim(), description: (metadata.description ?? "").normalize("NFC").trim(), websiteUrl: url(metadata.websiteUrl), twitterUrl: url(metadata.twitterUrl), telegramUrl: url(metadata.telegramUrl), discordUrl: url(metadata.discordUrl), imageKey: metadata.imageKey ?? null })));
|
|
106
107
|
}
|
|
107
108
|
export async function sha256Hex(bytes: ArrayBuffer): Promise<Hex> {
|
|
108
109
|
const digest = await crypto.subtle.digest("SHA-256", bytes);
|
package/src/lifecycle/abi.ts
CHANGED
|
@@ -119,7 +119,6 @@ const v4AdapterMetadataAbi = [
|
|
|
119
119
|
{ type: "function", name: "CONFIG_VERSION", stateMutability: "view", inputs: [], outputs: [{ type: "uint32" }] },
|
|
120
120
|
{ type: "function", name: "implementationRegistry", stateMutability: "view", inputs: [], outputs: [{ type: "address" }] },
|
|
121
121
|
{ type: "function", name: "poolManager", stateMutability: "view", inputs: [], outputs: [{ type: "address" }] },
|
|
122
|
-
{ type: "function", name: "hookRoot", stateMutability: "view", inputs: [], outputs: [{ type: "address" }] },
|
|
123
122
|
{ type: "function", name: "oracleFactory", stateMutability: "view", inputs: [], outputs: [{ type: "address" }] },
|
|
124
123
|
{ type: "function", name: "locker", stateMutability: "view", inputs: [], outputs: [{ type: "address" }] },
|
|
125
124
|
{ type: "function", name: "collectorFactory", stateMutability: "view", inputs: [], outputs: [{ type: "address" }] },
|
|
@@ -127,6 +126,7 @@ const v4AdapterMetadataAbi = [
|
|
|
127
126
|
] as const;
|
|
128
127
|
export const sharedMarketAdapterV1Abi = [
|
|
129
128
|
...v4AdapterMetadataAbi,
|
|
129
|
+
{ type: "function", name: "hookRoot", stateMutability: "view", inputs: [], outputs: [{ type: "address" }] },
|
|
130
130
|
{ type: "constructor", stateMutability: "nonpayable", inputs: [
|
|
131
131
|
{ name: "core_", type: "address" }, { name: "manager_", type: "address" }, { name: "root_", type: "address" },
|
|
132
132
|
{ name: "locker_", type: "address" }, { name: "helper_", type: "address" }, { name: "registry_", type: "address" },
|
|
@@ -142,6 +142,7 @@ export const abyssLifecycleAdapterAbi = [
|
|
|
142
142
|
] as const;
|
|
143
143
|
export const poolMarketAdapterV1Abi = [
|
|
144
144
|
...v4AdapterMetadataAbi,
|
|
145
|
+
{ type: "function", name: "hookRoot", stateMutability: "pure", inputs: [], outputs: [{ type: "address" }] },
|
|
145
146
|
{ type: "constructor", stateMutability: "nonpayable", inputs: [
|
|
146
147
|
{ name: "core_", type: "address" }, { name: "manager_", type: "address" }, { name: "oracleFactory_", type: "address" },
|
|
147
148
|
{ name: "locker_", type: "address" }, { name: "deployer_", type: "address" }, { name: "helper_", type: "address" },
|
|
@@ -205,17 +206,78 @@ export const lifecycleV4HookAbi = [
|
|
|
205
206
|
{ type: "function", name: "pendingFees", stateMutability: "view", inputs: [{ type: "bytes32" }, { type: "address" }], outputs: [{ type: "uint256" }] },
|
|
206
207
|
{ type: "function", name: "settledFees", stateMutability: "view", inputs: [{ type: "bytes32" }, { type: "address" }], outputs: [{ type: "uint256" }] },
|
|
207
208
|
] as const;
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
{ type: "
|
|
212
|
-
{ type: "function", name: "
|
|
213
|
-
{ type: "function", name: "
|
|
214
|
-
{ type: "function", name: "
|
|
215
|
-
{ type: "function", name: "
|
|
216
|
-
{ type: "function", name: "
|
|
217
|
-
{ type: "function", name: "
|
|
218
|
-
{ type: "function", name: "
|
|
209
|
+
/** Complete mined FixedFeePoolHookV1 ABI (pool-launch-v1, 20261005T053747Z-b5a7b88).
|
|
210
|
+
* Compiler-only internalType annotations are omitted; the constructor is one 18-field tuple. */
|
|
211
|
+
export const fixedFeePoolHookV1Abi = [
|
|
212
|
+
{ type: "constructor", inputs: [boundParametersInput], stateMutability: "nonpayable" },
|
|
213
|
+
{ type: "function", name: "ALL_HOOK_MASK", inputs: [], outputs: [{ name: "", type: "uint160" }], stateMutability: "view" },
|
|
214
|
+
{ type: "function", name: "MAX_ORACLE_CARDINALITY", inputs: [], outputs: [{ name: "", type: "uint16" }], stateMutability: "view" },
|
|
215
|
+
{ type: "function", name: "PIPS_DENOMINATOR", inputs: [], outputs: [{ name: "", type: "uint24" }], stateMutability: "view" },
|
|
216
|
+
{ type: "function", name: "REQUIRED_HOOK_FLAGS", inputs: [], outputs: [{ name: "", type: "uint160" }], stateMutability: "view" },
|
|
217
|
+
{ type: "function", name: "afterDonate", inputs: [{ name: "", type: "address" }, { name: "key", type: "tuple", components: lifecycleV4PoolKeyComponents }, { name: "", type: "uint256" }, { name: "", type: "uint256" }, { name: "", type: "bytes" }], outputs: [{ name: "", type: "bytes4" }], stateMutability: "nonpayable" },
|
|
218
|
+
{ type: "function", name: "afterInitialize", inputs: [{ name: "sender", type: "address" }, { name: "key", type: "tuple", components: lifecycleV4PoolKeyComponents }, { name: "sqrtPriceX96", type: "uint160" }, { name: "tick", type: "int24" }], outputs: [{ name: "", type: "bytes4" }], stateMutability: "nonpayable" },
|
|
219
|
+
{ type: "function", name: "afterSwap", inputs: [{ name: "", type: "address" }, { name: "key", type: "tuple", components: lifecycleV4PoolKeyComponents }, { name: "params", type: "tuple", components: [{ name: "zeroForOne", type: "bool" }, { name: "amountSpecified", type: "int256" }, { name: "sqrtPriceLimitX96", type: "uint160" }] }, { name: "delta", type: "int256" }, { name: "", type: "bytes" }], outputs: [{ name: "", type: "bytes4" }, { name: "", type: "int128" }], stateMutability: "nonpayable" },
|
|
220
|
+
{ type: "function", name: "aggregateLiabilities", inputs: [{ name: "asset", type: "address" }], outputs: [{ name: "", type: "uint256" }], stateMutability: "view" },
|
|
221
|
+
{ type: "function", name: "aggregateManagerClaims", inputs: [{ name: "asset", type: "address" }], outputs: [{ name: "", type: "uint256" }], stateMutability: "view" },
|
|
222
|
+
{ type: "function", name: "beforeAddLiquidity", inputs: [{ name: "sender", type: "address" }, { name: "key", type: "tuple", components: lifecycleV4PoolKeyComponents }, { name: "params", type: "tuple", components: [{ name: "tickLower", type: "int24" }, { name: "tickUpper", type: "int24" }, { name: "liquidityDelta", type: "int256" }, { name: "salt", type: "bytes32" }] }, { name: "", type: "bytes" }], outputs: [{ name: "", type: "bytes4" }], stateMutability: "nonpayable" },
|
|
223
|
+
{ type: "function", name: "beforeDonate", inputs: [{ name: "", type: "address" }, { name: "key", type: "tuple", components: lifecycleV4PoolKeyComponents }, { name: "amount0", type: "uint256" }, { name: "amount1", type: "uint256" }, { name: "", type: "bytes" }], outputs: [{ name: "", type: "bytes4" }], stateMutability: "nonpayable" },
|
|
224
|
+
{ type: "function", name: "beforeRemoveLiquidity", inputs: [{ name: "sender", type: "address" }, { name: "key", type: "tuple", components: lifecycleV4PoolKeyComponents }, { name: "params", type: "tuple", components: [{ name: "tickLower", type: "int24" }, { name: "tickUpper", type: "int24" }, { name: "liquidityDelta", type: "int256" }, { name: "salt", type: "bytes32" }] }, { name: "", type: "bytes" }], outputs: [{ name: "", type: "bytes4" }], stateMutability: "nonpayable" },
|
|
225
|
+
{ type: "function", name: "beforeSwap", inputs: [{ name: "", type: "address" }, { name: "key", type: "tuple", components: lifecycleV4PoolKeyComponents }, { name: "params", type: "tuple", components: [{ name: "zeroForOne", type: "bool" }, { name: "amountSpecified", type: "int256" }, { name: "sqrtPriceLimitX96", type: "uint160" }] }, { name: "", type: "bytes" }], outputs: [{ name: "", type: "bytes4" }, { name: "", type: "int256" }, { name: "", type: "uint24" }], stateMutability: "nonpayable" },
|
|
226
|
+
{ type: "function", name: "boundPoolId", inputs: [], outputs: [{ name: "", type: "bytes32" }], stateMutability: "view" },
|
|
227
|
+
{ type: "function", name: "collectFees", inputs: [{ name: "key", type: "tuple", components: lifecycleV4PoolKeyComponents }], outputs: [{ name: "amount0", type: "uint256" }, { name: "amount1", type: "uint256" }], stateMutability: "nonpayable" },
|
|
228
|
+
{ type: "function", name: "completePoolOpening", inputs: [{ name: "key", type: "tuple", components: lifecycleV4PoolKeyComponents }], outputs: [], stateMutability: "nonpayable" },
|
|
229
|
+
{ type: "function", name: "core", inputs: [], outputs: [{ name: "", type: "address" }], stateMutability: "view" },
|
|
230
|
+
{ type: "function", name: "deploymentConfigHash", inputs: [], outputs: [{ name: "", type: "bytes32" }], stateMutability: "view" },
|
|
231
|
+
{ type: "function", name: "expectedPositionCount", inputs: [], outputs: [{ name: "", type: "uint32" }], stateMutability: "view" },
|
|
232
|
+
{ type: "function", name: "increaseObservationCardinalityNext", inputs: [{ name: "id", type: "bytes32" }, { name: "requested", type: "uint16" }], outputs: [], stateMutability: "nonpayable" },
|
|
233
|
+
{ type: "function", name: "initialized", inputs: [{ name: "id", type: "bytes32" }], outputs: [{ name: "", type: "bool" }], stateMutability: "view" },
|
|
234
|
+
{ type: "function", name: "liquidityLocker", inputs: [], outputs: [{ name: "", type: "address" }], stateMutability: "view" },
|
|
235
|
+
{ type: "function", name: "marketCommitment", inputs: [], outputs: [{ name: "", type: "bytes32" }], stateMutability: "view" },
|
|
236
|
+
{ type: "function", name: "observations", inputs: [{ name: "id", type: "bytes32" }, { name: "index", type: "uint256" }], outputs: [{ name: "blockTimestamp", type: "uint32" }, { name: "tickCumulative", type: "int56" }, { name: "secondsPerLiquidityCumulativeX128", type: "uint160" }, { name: "observationInitialized", type: "bool" }], stateMutability: "view" },
|
|
237
|
+
{ type: "function", name: "observeTruncated", inputs: [{ name: "id", type: "bytes32" }, { name: "secondsAgos", type: "uint32[]" }], outputs: [{ name: "tickCumulatives", type: "int56[]" }, { name: "secondsPerLiquidityCumulativeX128s", type: "uint160[]" }], stateMutability: "view" },
|
|
238
|
+
{ type: "function", name: "openingCompletedAt", inputs: [{ name: "id", type: "bytes32" }], outputs: [{ name: "", type: "uint256" }], stateMutability: "view" },
|
|
239
|
+
{ type: "function", name: "openingSqrtPriceX96", inputs: [], outputs: [{ name: "", type: "uint160" }], stateMutability: "view" },
|
|
240
|
+
{ type: "function", name: "oracleFactory", inputs: [], outputs: [{ name: "", type: "address" }], stateMutability: "view" },
|
|
241
|
+
{ type: "function", name: "oracleInitializedAt", inputs: [{ name: "id", type: "bytes32" }], outputs: [{ name: "", type: "uint256" }], stateMutability: "view" },
|
|
242
|
+
{ type: "function", name: "oracleState", inputs: [{ name: "id", type: "bytes32" }], outputs: [{ name: "index", type: "uint16" }, { name: "cardinality", type: "uint16" }, { name: "cardinalityNext", type: "uint16" }, { name: "tick", type: "int24" }, { name: "lastBlock", type: "uint64" }, { name: "initializedAt", type: "uint64" }, { name: "maxAbsTickMove", type: "int24" }, { name: "cardinalityCap", type: "uint16" }], stateMutability: "view" },
|
|
243
|
+
{ type: "function", name: "pendingFees", inputs: [{ name: "id", type: "bytes32" }, { name: "asset", type: "address" }], outputs: [{ name: "", type: "uint256" }], stateMutability: "view" },
|
|
244
|
+
{ type: "function", name: "pendingTreasurySweeps", inputs: [{ name: "id", type: "bytes32" }, { name: "asset", type: "address" }], outputs: [{ name: "", type: "uint256" }], stateMutability: "view" },
|
|
245
|
+
{ type: "function", name: "poolConfig", inputs: [{ name: "id", type: "bytes32" }], outputs: [{ name: "", type: "tuple", components: lifecycleV4HookPoolConfigComponents }], stateMutability: "view" },
|
|
246
|
+
{ type: "function", name: "poolKey", inputs: [{ name: "id", type: "bytes32" }], outputs: [{ name: "", type: "tuple", components: lifecycleV4PoolKeyComponents }], stateMutability: "view" },
|
|
247
|
+
{ type: "function", name: "poolManager", inputs: [], outputs: [{ name: "", type: "address" }], stateMutability: "view" },
|
|
248
|
+
{ type: "function", name: "pools", inputs: [], outputs: [{ name: "ids", type: "bytes32[]" }], stateMutability: "view" },
|
|
249
|
+
{ type: "function", name: "registerPool", inputs: [{ name: "key", type: "tuple", components: lifecycleV4PoolKeyComponents }, { name: "config", type: "tuple", components: lifecycleV4HookPoolConfigComponents }], outputs: [], stateMutability: "nonpayable" },
|
|
250
|
+
{ type: "function", name: "registered", inputs: [{ name: "id", type: "bytes32" }], outputs: [{ name: "", type: "bool" }], stateMutability: "view" },
|
|
251
|
+
{ type: "function", name: "registrar", inputs: [], outputs: [{ name: "", type: "address" }], stateMutability: "view" },
|
|
252
|
+
{ type: "function", name: "settledFees", inputs: [{ name: "id", type: "bytes32" }, { name: "asset", type: "address" }], outputs: [{ name: "", type: "uint256" }], stateMutability: "view" },
|
|
253
|
+
{ type: "function", name: "token", inputs: [], outputs: [{ name: "", type: "address" }], stateMutability: "view" },
|
|
254
|
+
{ type: "function", name: "unlockCallback", inputs: [{ name: "data", type: "bytes" }], outputs: [{ name: "", type: "bytes" }], stateMutability: "nonpayable" },
|
|
255
|
+
{ type: "function", name: "validateCollector", inputs: [{ name: "key", type: "tuple", components: lifecycleV4PoolKeyComponents }, { name: "collector", type: "address" }, { name: "locker", type: "address" }], outputs: [], stateMutability: "view" },
|
|
256
|
+
{ type: "function", name: "validateOracleConfig", inputs: [{ name: "oracleConfigId", type: "bytes32" }], outputs: [{ name: "maxAbsTickMove", type: "uint24" }, { name: "cardinality", type: "uint16" }], stateMutability: "view" },
|
|
257
|
+
{ type: "event", name: "FeeAccrued", inputs: [{ name: "poolId", type: "bytes32", indexed: true }, { name: "asset", type: "address", indexed: true }, { name: "gross", type: "uint256", indexed: false }, { name: "treasury", type: "uint256", indexed: false }], anonymous: false },
|
|
258
|
+
{ type: "event", name: "FeesCollected", inputs: [{ name: "poolId", type: "bytes32", indexed: true }, { name: "collector", type: "address", indexed: true }, { name: "amount0", type: "uint256", indexed: false }, { name: "amount1", type: "uint256", indexed: false }], anonymous: false },
|
|
259
|
+
{ type: "event", name: "IncreaseObservationCardinalityNext", inputs: [{ name: "poolId", type: "bytes32", indexed: true }, { name: "cardinalityNextOld", type: "uint16", indexed: false }, { name: "cardinalityNextNew", type: "uint16", indexed: false }], anonymous: false },
|
|
260
|
+
{ type: "event", name: "LpFeesCheckpointed", inputs: [{ name: "poolId", type: "bytes32", indexed: true }, { name: "locker", type: "address", indexed: true }, { name: "amount0", type: "uint256", indexed: false }, { name: "amount1", type: "uint256", indexed: false }], anonymous: false },
|
|
261
|
+
{ type: "event", name: "OpeningCompleted", inputs: [{ name: "poolId", type: "bytes32", indexed: true }, { name: "completedAt", type: "uint256", indexed: true }], anonymous: false },
|
|
262
|
+
{ type: "event", name: "PoolInitialized", inputs: [{ name: "poolId", type: "bytes32", indexed: true }], anonymous: false },
|
|
263
|
+
{ type: "event", name: "PoolRegistered", inputs: [{ name: "poolId", type: "bytes32", indexed: true }, { name: "collector", type: "address", indexed: true }, { name: "locker", type: "address", indexed: true }], anonymous: false },
|
|
264
|
+
{ type: "error", name: "AlreadyRegistered", inputs: [] },
|
|
265
|
+
{ type: "error", name: "ClaimMismatch", inputs: [] },
|
|
266
|
+
{ type: "error", name: "ExternalLiquidityDisabled", inputs: [] },
|
|
267
|
+
{ type: "error", name: "FeeSettlementRequired", inputs: [] },
|
|
268
|
+
{ type: "error", name: "FeeTooLarge", inputs: [] },
|
|
269
|
+
{ type: "error", name: "IncompleteFill", inputs: [] },
|
|
270
|
+
{ type: "error", name: "InexactTransfer", inputs: [] },
|
|
271
|
+
{ type: "error", name: "InvalidCallback", inputs: [] },
|
|
272
|
+
{ type: "error", name: "InvalidConfiguration", inputs: [] },
|
|
273
|
+
{ type: "error", name: "InvalidHookAddress", inputs: [] },
|
|
274
|
+
{ type: "error", name: "InvalidObservationState", inputs: [] },
|
|
275
|
+
{ type: "error", name: "InvalidPool", inputs: [] },
|
|
276
|
+
{ type: "error", name: "ObservationTooOld", inputs: [] },
|
|
277
|
+
{ type: "error", name: "OpeningAlreadyComplete", inputs: [] },
|
|
278
|
+
{ type: "error", name: "OpeningNotComplete", inputs: [] },
|
|
279
|
+
{ type: "error", name: "Reentrancy", inputs: [] },
|
|
280
|
+
{ type: "error", name: "Unauthorized", inputs: [] },
|
|
219
281
|
] as const;
|
|
220
282
|
export const lifecycleV4LockerAbi = [
|
|
221
283
|
{ type: "function", name: "poolManager", stateMutability: "view", inputs: [], outputs: [{ type: "address" }] },
|
|
@@ -249,6 +311,39 @@ export const lifecycleErc20Abi = [
|
|
|
249
311
|
{ type: "function", name: "allowance", stateMutability: "view", inputs: [{ type: "address" }, { type: "address" }], outputs: [{ type: "uint256" }] },
|
|
250
312
|
{ type: "function", name: "approve", stateMutability: "nonpayable", inputs: [{ type: "address" }, { type: "uint256" }], outputs: [{ type: "bool" }] },
|
|
251
313
|
] as const;
|
|
314
|
+
/** Shared immutable bindings and terminal state of LaunchERC20V1 / LaunchERC404V1. */
|
|
315
|
+
export const lifecycleTokenContextAbi = [
|
|
316
|
+
{ type: "function", name: "authority", stateMutability: "view", inputs: [], outputs: [{ type: "address" }] },
|
|
317
|
+
{ type: "function", name: "tokenFactory", stateMutability: "view", inputs: [], outputs: [{ type: "address" }] },
|
|
318
|
+
{ type: "function", name: "launchId", stateMutability: "view", inputs: [], outputs: [{ type: "bytes32" }] },
|
|
319
|
+
{ type: "function", name: "rewardMode", stateMutability: "view", inputs: [], outputs: [{ type: "uint8" }] },
|
|
320
|
+
{ type: "function", name: "initialSupply", stateMutability: "view", inputs: [], outputs: [{ type: "uint256" }] },
|
|
321
|
+
{ type: "function", name: "burnOnCancel", stateMutability: "view", inputs: [], outputs: [{ type: "bool" }] },
|
|
322
|
+
{ type: "function", name: "active", stateMutability: "view", inputs: [], outputs: [{ type: "bool" }] },
|
|
323
|
+
{ type: "function", name: "cancelled", stateMutability: "view", inputs: [], outputs: [{ type: "bool" }] },
|
|
324
|
+
{ type: "function", name: "exclusionsFinalized", stateMutability: "view", inputs: [], outputs: [{ type: "bool" }] },
|
|
325
|
+
{ type: "function", name: "feeHub", stateMutability: "view", inputs: [], outputs: [{ type: "address" }] },
|
|
326
|
+
{ type: "function", name: "rewardModule", stateMutability: "view", inputs: [], outputs: [{ type: "address" }] },
|
|
327
|
+
] as const;
|
|
328
|
+
export const lifecycleErc404Abi = [
|
|
329
|
+
...lifecycleTokenContextAbi,
|
|
330
|
+
{ type: "function", name: "unit", stateMutability: "view", inputs: [], outputs: [{ type: "uint256" }] },
|
|
331
|
+
{ type: "function", name: "baseURI", stateMutability: "view", inputs: [], outputs: [{ type: "string" }] },
|
|
332
|
+
{ type: "function", name: "mirrorERC721", stateMutability: "view", inputs: [], outputs: [{ type: "address" }] },
|
|
333
|
+
] as const;
|
|
334
|
+
export const lifecycleErc404MirrorAbi = [
|
|
335
|
+
{ type: "function", name: "baseERC20", stateMutability: "view", inputs: [], outputs: [{ type: "address" }] },
|
|
336
|
+
] as const;
|
|
337
|
+
export const lifecycleTokenFactoryAbi = [
|
|
338
|
+
{ type: "function", name: "core", stateMutability: "view", inputs: [], outputs: [{ type: "address" }] },
|
|
339
|
+
{ type: "function", name: "tokenOfLaunch", stateMutability: "view", inputs: [{ type: "bytes32" }], outputs: [{ type: "address" }] },
|
|
340
|
+
{ type: "function", name: "launchOfToken", stateMutability: "view", inputs: [{ type: "address" }], outputs: [{ type: "bytes32" }] },
|
|
341
|
+
{ type: "event", name: "TokenDeployed", anonymous: false, inputs: [
|
|
342
|
+
{ name: "launchId", type: "bytes32", indexed: true }, { name: "token", type: "address", indexed: true },
|
|
343
|
+
{ name: "kind", type: "uint8", indexed: false },
|
|
344
|
+
] },
|
|
345
|
+
] as const;
|
|
346
|
+
|
|
252
347
|
export const lifecycleOracleFactoryAbi = [
|
|
253
348
|
{ type: "function", name: "oracleConfigs", stateMutability: "view", inputs: [{ type: "bytes32" }], outputs: [{ type: "uint24" }, { type: "uint16" }] },
|
|
254
349
|
] as const;
|