@black-market/sdk 0.15.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -8
- package/dist/lifecycle/auto-compound.d.ts +21 -0
- package/dist/lifecycle/auto-compound.d.ts.map +1 -0
- package/dist/lifecycle/auto-compound.js +34 -0
- package/dist/lifecycle/auto-compound.js.map +1 -0
- package/dist/lifecycle/calibration.d.ts +2 -4
- package/dist/lifecycle/calibration.d.ts.map +1 -1
- package/dist/lifecycle/calibration.js +1 -26
- package/dist/lifecycle/calibration.js.map +1 -1
- package/dist/lifecycle/deployments/auto-compound-dynamic-pool-v1-20261028.d.ts +73 -0
- package/dist/lifecycle/deployments/auto-compound-dynamic-pool-v1-20261028.d.ts.map +1 -0
- package/dist/lifecycle/deployments/auto-compound-dynamic-pool-v1-20261028.js +75 -0
- package/dist/lifecycle/deployments/auto-compound-dynamic-pool-v1-20261028.js.map +1 -0
- package/dist/lifecycle/deployments/auto-compound-static-pool-v1-20261028.d.ts +73 -0
- package/dist/lifecycle/deployments/auto-compound-static-pool-v1-20261028.d.ts.map +1 -0
- package/dist/lifecycle/deployments/auto-compound-static-pool-v1-20261028.js +75 -0
- package/dist/lifecycle/deployments/auto-compound-static-pool-v1-20261028.js.map +1 -0
- package/dist/lifecycle/deployments/raeto-dynamic-pool-v1-20261029.d.ts +71 -0
- package/dist/lifecycle/deployments/raeto-dynamic-pool-v1-20261029.d.ts.map +1 -0
- package/dist/lifecycle/deployments/raeto-dynamic-pool-v1-20261029.js +73 -0
- package/dist/lifecycle/deployments/raeto-dynamic-pool-v1-20261029.js.map +1 -0
- package/dist/lifecycle/deployments/raeto-fixed-pool-v1-20261029.d.ts +71 -0
- package/dist/lifecycle/deployments/raeto-fixed-pool-v1-20261029.d.ts.map +1 -0
- package/dist/lifecycle/deployments/raeto-fixed-pool-v1-20261029.js +73 -0
- package/dist/lifecycle/deployments/raeto-fixed-pool-v1-20261029.js.map +1 -0
- package/dist/lifecycle/gas-profile.d.ts +17 -13
- package/dist/lifecycle/gas-profile.d.ts.map +1 -1
- package/dist/lifecycle/gas-profile.js +133 -113
- package/dist/lifecycle/gas-profile.js.map +1 -1
- package/dist/lifecycle/index.d.ts +6 -4
- package/dist/lifecycle/index.d.ts.map +1 -1
- package/dist/lifecycle/index.js +6 -4
- package/dist/lifecycle/index.js.map +1 -1
- package/dist/lifecycle/markets.d.ts +4 -0
- package/dist/lifecycle/markets.d.ts.map +1 -1
- package/dist/lifecycle/markets.js +58 -3
- package/dist/lifecycle/markets.js.map +1 -1
- package/dist/lifecycle/opening-buys.js +3 -3
- package/dist/lifecycle/opening-buys.js.map +1 -1
- package/dist/lifecycle/planner.d.ts +6 -9
- package/dist/lifecycle/planner.d.ts.map +1 -1
- package/dist/lifecycle/planner.js +122 -208
- package/dist/lifecycle/planner.js.map +1 -1
- package/dist/lifecycle/presets.d.ts +9 -3
- package/dist/lifecycle/presets.d.ts.map +1 -1
- package/dist/lifecycle/presets.js +17 -1
- package/dist/lifecycle/presets.js.map +1 -1
- package/dist/lifecycle/raeto-abi.d.ts +175 -0
- package/dist/lifecycle/raeto-abi.d.ts.map +1 -0
- package/dist/lifecycle/raeto-abi.js +224 -0
- package/dist/lifecycle/raeto-abi.js.map +1 -0
- package/dist/lifecycle/raeto.d.ts +21 -0
- package/dist/lifecycle/raeto.d.ts.map +1 -0
- package/dist/lifecycle/raeto.js +59 -0
- package/dist/lifecycle/raeto.js.map +1 -0
- package/dist/lifecycle/rpc.d.ts +3 -13
- package/dist/lifecycle/rpc.d.ts.map +1 -1
- package/dist/lifecycle/rpc.js +11 -37
- package/dist/lifecycle/rpc.js.map +1 -1
- package/dist/lifecycle/snapshot.d.ts.map +1 -1
- package/dist/lifecycle/snapshot.js +1 -2
- package/dist/lifecycle/snapshot.js.map +1 -1
- package/dist/lifecycle/transactions.d.ts +10 -3
- package/dist/lifecycle/transactions.d.ts.map +1 -1
- package/dist/lifecycle/transactions.js +47 -10
- package/dist/lifecycle/transactions.js.map +1 -1
- package/dist/lifecycle/types.d.ts +32 -107
- package/dist/lifecycle/types.d.ts.map +1 -1
- package/dist/lifecycle/types.js +3 -3
- package/dist/lifecycle/types.js.map +1 -1
- package/dist/lifecycle/ufg.d.ts +1 -1
- package/dist/lifecycle/ufg.d.ts.map +1 -1
- package/dist/lifecycle/ufg.js +1 -1
- package/dist/lifecycle/ufg.js.map +1 -1
- package/docs/launch-lifecycle.md +113 -1
- package/docs/lifecycle-gas-profiles.md +141 -24
- package/docs/reference.md +112 -3
- package/examples/.env.example +0 -3
- package/examples/README.md +11 -11
- package/examples/launch-example-support.ts +4 -9
- package/examples/launch-example.ts +12 -28
- package/examples/launch-lifecycle-smoke.ts +10 -22
- package/examples/launch.ts +8 -11
- package/package.json +1 -1
- package/src/lifecycle/auto-compound.ts +38 -0
- package/src/lifecycle/calibration.ts +3 -23
- package/src/lifecycle/deployments/auto-compound-dynamic-pool-v1-20261028.ts +77 -0
- package/src/lifecycle/deployments/auto-compound-static-pool-v1-20261028.ts +77 -0
- package/src/lifecycle/deployments/raeto-dynamic-pool-v1-20261029.ts +74 -0
- package/src/lifecycle/deployments/raeto-fixed-pool-v1-20261029.ts +74 -0
- package/src/lifecycle/gas-profile.ts +125 -104
- package/src/lifecycle/index.ts +6 -4
- package/src/lifecycle/markets.ts +47 -3
- package/src/lifecycle/opening-buys.ts +3 -3
- package/src/lifecycle/planner.ts +116 -191
- package/src/lifecycle/presets.ts +17 -1
- package/src/lifecycle/raeto-abi.ts +223 -0
- package/src/lifecycle/raeto.ts +61 -0
- package/src/lifecycle/rpc.ts +10 -32
- package/src/lifecycle/snapshot.ts +1 -2
- package/src/lifecycle/transactions.ts +46 -9
- package/src/lifecycle/types.ts +38 -87
- package/src/lifecycle/ufg.ts +1 -1
- package/dist/lifecycle/fork.d.ts +0 -15
- package/dist/lifecycle/fork.d.ts.map +0 -1
- package/dist/lifecycle/fork.js +0 -36
- package/dist/lifecycle/fork.js.map +0 -1
- package/dist/lifecycle/simulation.d.ts +0 -17
- package/dist/lifecycle/simulation.d.ts.map +0 -1
- package/dist/lifecycle/simulation.js +0 -605
- package/dist/lifecycle/simulation.js.map +0 -1
- package/src/lifecycle/fork.ts +0 -36
- package/src/lifecycle/simulation.ts +0 -543
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
// Generated from the verified RaetoFeeCollectorV1 ABI by scripts/generate-raeto-presets.mjs.
|
|
2
|
+
// Provenance: test/fixtures/raeto-registry-readback.json, abiProvenance.
|
|
3
|
+
export const raetoFeeCollectorV1Abi = [
|
|
4
|
+
{
|
|
5
|
+
"anonymous": false,
|
|
6
|
+
"inputs": [
|
|
7
|
+
{
|
|
8
|
+
"indexed": true,
|
|
9
|
+
"internalType": "address",
|
|
10
|
+
"name": "launchToken",
|
|
11
|
+
"type": "address"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"indexed": true,
|
|
15
|
+
"internalType": "bytes32",
|
|
16
|
+
"name": "poolId",
|
|
17
|
+
"type": "bytes32"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"indexed": true,
|
|
21
|
+
"internalType": "address",
|
|
22
|
+
"name": "asset",
|
|
23
|
+
"type": "address"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"indexed": false,
|
|
27
|
+
"internalType": "uint256",
|
|
28
|
+
"name": "grossQuoteCollected",
|
|
29
|
+
"type": "uint256"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"indexed": false,
|
|
33
|
+
"internalType": "uint256",
|
|
34
|
+
"name": "raetoAmount",
|
|
35
|
+
"type": "uint256"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"indexed": false,
|
|
39
|
+
"internalType": "uint256",
|
|
40
|
+
"name": "forwardedQuote",
|
|
41
|
+
"type": "uint256"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"indexed": false,
|
|
45
|
+
"internalType": "uint16",
|
|
46
|
+
"name": "shareBps",
|
|
47
|
+
"type": "uint16"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"indexed": false,
|
|
51
|
+
"internalType": "uint256",
|
|
52
|
+
"name": "owedAfter",
|
|
53
|
+
"type": "uint256"
|
|
54
|
+
}
|
|
55
|
+
],
|
|
56
|
+
"name": "RaetoFeesBooked",
|
|
57
|
+
"type": "event"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"anonymous": false,
|
|
61
|
+
"inputs": [
|
|
62
|
+
{
|
|
63
|
+
"indexed": true,
|
|
64
|
+
"internalType": "address",
|
|
65
|
+
"name": "launchToken",
|
|
66
|
+
"type": "address"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"indexed": true,
|
|
70
|
+
"internalType": "bytes32",
|
|
71
|
+
"name": "poolId",
|
|
72
|
+
"type": "bytes32"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"indexed": true,
|
|
76
|
+
"internalType": "address",
|
|
77
|
+
"name": "payout",
|
|
78
|
+
"type": "address"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"indexed": false,
|
|
82
|
+
"internalType": "address",
|
|
83
|
+
"name": "asset",
|
|
84
|
+
"type": "address"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"indexed": false,
|
|
88
|
+
"internalType": "uint256",
|
|
89
|
+
"name": "amount",
|
|
90
|
+
"type": "uint256"
|
|
91
|
+
}
|
|
92
|
+
],
|
|
93
|
+
"name": "RaetoFeesClaimed",
|
|
94
|
+
"type": "event"
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"anonymous": false,
|
|
98
|
+
"inputs": [
|
|
99
|
+
{
|
|
100
|
+
"indexed": true,
|
|
101
|
+
"internalType": "address",
|
|
102
|
+
"name": "launchToken",
|
|
103
|
+
"type": "address"
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"indexed": true,
|
|
107
|
+
"internalType": "bytes32",
|
|
108
|
+
"name": "poolId",
|
|
109
|
+
"type": "bytes32"
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"indexed": true,
|
|
113
|
+
"internalType": "address",
|
|
114
|
+
"name": "operator",
|
|
115
|
+
"type": "address"
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"indexed": false,
|
|
119
|
+
"internalType": "uint16",
|
|
120
|
+
"name": "previousShareBps",
|
|
121
|
+
"type": "uint16"
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"indexed": false,
|
|
125
|
+
"internalType": "uint16",
|
|
126
|
+
"name": "newShareBps",
|
|
127
|
+
"type": "uint16"
|
|
128
|
+
}
|
|
129
|
+
],
|
|
130
|
+
"name": "RaetoShareUpdated",
|
|
131
|
+
"type": "event"
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"inputs": [
|
|
135
|
+
{
|
|
136
|
+
"internalType": "address",
|
|
137
|
+
"name": "asset",
|
|
138
|
+
"type": "address"
|
|
139
|
+
}
|
|
140
|
+
],
|
|
141
|
+
"name": "claimRaeto",
|
|
142
|
+
"outputs": [
|
|
143
|
+
{
|
|
144
|
+
"internalType": "uint256",
|
|
145
|
+
"name": "amount",
|
|
146
|
+
"type": "uint256"
|
|
147
|
+
}
|
|
148
|
+
],
|
|
149
|
+
"stateMutability": "nonpayable",
|
|
150
|
+
"type": "function"
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
"inputs": [],
|
|
154
|
+
"name": "launchToken",
|
|
155
|
+
"outputs": [
|
|
156
|
+
{
|
|
157
|
+
"internalType": "address",
|
|
158
|
+
"name": "",
|
|
159
|
+
"type": "address"
|
|
160
|
+
}
|
|
161
|
+
],
|
|
162
|
+
"stateMutability": "view",
|
|
163
|
+
"type": "function"
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
"inputs": [
|
|
167
|
+
{
|
|
168
|
+
"internalType": "address",
|
|
169
|
+
"name": "asset",
|
|
170
|
+
"type": "address"
|
|
171
|
+
}
|
|
172
|
+
],
|
|
173
|
+
"name": "owed",
|
|
174
|
+
"outputs": [
|
|
175
|
+
{
|
|
176
|
+
"internalType": "uint256",
|
|
177
|
+
"name": "amount",
|
|
178
|
+
"type": "uint256"
|
|
179
|
+
}
|
|
180
|
+
],
|
|
181
|
+
"stateMutability": "view",
|
|
182
|
+
"type": "function"
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
"inputs": [],
|
|
186
|
+
"name": "quoteAsset",
|
|
187
|
+
"outputs": [
|
|
188
|
+
{
|
|
189
|
+
"internalType": "address",
|
|
190
|
+
"name": "",
|
|
191
|
+
"type": "address"
|
|
192
|
+
}
|
|
193
|
+
],
|
|
194
|
+
"stateMutability": "view",
|
|
195
|
+
"type": "function"
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
"inputs": [
|
|
199
|
+
{
|
|
200
|
+
"internalType": "uint16",
|
|
201
|
+
"name": "newShareBps",
|
|
202
|
+
"type": "uint16"
|
|
203
|
+
}
|
|
204
|
+
],
|
|
205
|
+
"name": "setShareBps",
|
|
206
|
+
"outputs": [],
|
|
207
|
+
"stateMutability": "nonpayable",
|
|
208
|
+
"type": "function"
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
"inputs": [],
|
|
212
|
+
"name": "shareBps",
|
|
213
|
+
"outputs": [
|
|
214
|
+
{
|
|
215
|
+
"internalType": "uint16",
|
|
216
|
+
"name": "",
|
|
217
|
+
"type": "uint16"
|
|
218
|
+
}
|
|
219
|
+
],
|
|
220
|
+
"stateMutability": "view",
|
|
221
|
+
"type": "function"
|
|
222
|
+
}
|
|
223
|
+
] as const;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { encodeAbiParameters, type Hex } from "viem";
|
|
2
|
+
import { decodePoolBoundV4LifecycleMarketConfig } from "./markets.js";
|
|
3
|
+
import type { LaunchPlanV1 } from "./schema.js";
|
|
4
|
+
import { LifecyclePlanningError } from "./types.js";
|
|
5
|
+
|
|
6
|
+
export const RAETO_FIXED_PROFILE_ID: Hex = "0x9161833b162e7ca8160b11c64aedb307561e19a9136fd32f99cd797aab6da3ca";
|
|
7
|
+
export const RAETO_DYNAMIC_PROFILE_ID: Hex = "0x08387d00ee4f75f860810cc8fb434087328592c2f39ea3321109e589039f80e1";
|
|
8
|
+
export const RAETO_FIXED_ADAPTER_ID: Hex = "0x911d7ecefe56489d329235e3484829717dc00400d4181902f0f2de45f9338615";
|
|
9
|
+
export const RAETO_DYNAMIC_ADAPTER_ID: Hex = "0x8ab9c8c9b8fd4c8bbf12b780d9474463fa0fa52e3b450f0d5f68fd067dc1674d";
|
|
10
|
+
export const RAETO_PAYOUT_REGISTRY_ADDRESS = "0xBEC2C0e91612090F82df6743F31CDF18B4386b50";
|
|
11
|
+
/** The deployed collectors accept this menu, not the wider range in later source. */
|
|
12
|
+
export const RAETO_SHARE_BPS_OPTIONS = Object.freeze([500, 1000, 2500, 5000, 7500] as const);
|
|
13
|
+
export const RAETO_QUOTE_ASSETS = Object.freeze([
|
|
14
|
+
"0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73",
|
|
15
|
+
"0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168",
|
|
16
|
+
] as const);
|
|
17
|
+
export type RaetoLaunchConfigV1 = { shareBps: number };
|
|
18
|
+
|
|
19
|
+
export function isRaetoProfile(profileId: Hex): boolean {
|
|
20
|
+
const id = profileId.toLowerCase();
|
|
21
|
+
return id === RAETO_FIXED_PROFILE_ID || id === RAETO_DYNAMIC_PROFILE_ID;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function validateRaetoLaunchConfig(config: RaetoLaunchConfigV1): void {
|
|
25
|
+
if (!RAETO_SHARE_BPS_OPTIONS.some((share) => share === config.shareBps)) {
|
|
26
|
+
throw new LifecyclePlanningError("INVALID_RAETO_CONFIG", "Raeto shareBps must be one of 500, 1000, 2500, 5000 or 7500");
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Exactly abi.encode(RaetoLaunchConfigV1): one static uint16 word. */
|
|
31
|
+
export function encodeRaetoLaunchTail(config: RaetoLaunchConfigV1): Hex {
|
|
32
|
+
validateRaetoLaunchConfig(config);
|
|
33
|
+
return encodeAbiParameters([{ type: "uint16" }], [config.shareBps]);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function decodeRaetoLaunchTail(encoded: Hex): RaetoLaunchConfigV1 {
|
|
37
|
+
if (!/^0x[0-9a-fA-F]{64}$/.test(encoded)) throw new LifecyclePlanningError("INVALID_RAETO_CONFIG", "Raeto tail must be exactly one ABI word");
|
|
38
|
+
const share = BigInt(encoded);
|
|
39
|
+
if (share > 65535n) throw new LifecyclePlanningError("INVALID_RAETO_CONFIG", "Raeto tail must contain a canonical uint16");
|
|
40
|
+
const config = { shareBps: Number(share) };
|
|
41
|
+
validateRaetoLaunchConfig(config);
|
|
42
|
+
return config;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Raeto uses the normal lifecycle creator/funding route, not the UFG proxy. */
|
|
46
|
+
export function validateRaetoLaunchPlan(plan: LaunchPlanV1): void {
|
|
47
|
+
try {
|
|
48
|
+
if (plan.markets.length === 0) throw new Error("A Raeto plan requires at least one market");
|
|
49
|
+
for (const market of plan.markets) {
|
|
50
|
+
if (!isRaetoProfile(market.profileId) || market.configVersion !== 6 ||
|
|
51
|
+
!RAETO_QUOTE_ASSETS.some((quote) => quote.toLowerCase() === market.quoteAsset.toLowerCase()) ||
|
|
52
|
+
market.adapterId.toLowerCase() !== (market.profileId.toLowerCase() === RAETO_FIXED_PROFILE_ID ? RAETO_FIXED_ADAPTER_ID : RAETO_DYNAMIC_ADAPTER_ID)) {
|
|
53
|
+
throw new Error("Every Raeto market requires its Raeto config6 profile/adapter and a WETH or USDG quote");
|
|
54
|
+
}
|
|
55
|
+
const config = decodePoolBoundV4LifecycleMarketConfig(market.config, 6);
|
|
56
|
+
if (config.profileId.toLowerCase() !== market.profileId.toLowerCase()) throw new Error("Raeto config profile differs from its market");
|
|
57
|
+
}
|
|
58
|
+
} catch (error) {
|
|
59
|
+
throw new LifecyclePlanningError("INVALID_RAETO_PLAN", error instanceof Error ? error.message : "Invalid Raeto launch plan");
|
|
60
|
+
}
|
|
61
|
+
}
|
package/src/lifecycle/rpc.ts
CHANGED
|
@@ -22,8 +22,8 @@ type IndependentRead = { params: readonly unknown[]; resolve: (value: unknown) =
|
|
|
22
22
|
const lifecycleReadConcurrency = 8;
|
|
23
23
|
const diagnosticRpcMethods: Record<string, true> = {
|
|
24
24
|
eth_chainId: true, eth_getBlockByNumber: true, eth_getBlockByHash: true, eth_getCode: true,
|
|
25
|
-
eth_getBalance: true, eth_call: true,
|
|
26
|
-
|
|
25
|
+
eth_getBalance: true, eth_call: true, eth_gasPrice: true,
|
|
26
|
+
eth_getTransactionReceipt: true, eth_getTransactionByHash: true,
|
|
27
27
|
};
|
|
28
28
|
|
|
29
29
|
type SessionReadGroup = {
|
|
@@ -70,7 +70,7 @@ class SessionLifecycleCache implements LifecycleSessionCache {
|
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
/** Opt-in pinned read reuse; client-bound identity/
|
|
73
|
+
/** Opt-in pinned read reuse; client-bound identity/deployment facts are separate. */
|
|
74
74
|
export function createLifecycleSessionCache(): LifecycleSessionCache {
|
|
75
75
|
return new SessionLifecycleCache();
|
|
76
76
|
}
|
|
@@ -410,7 +410,7 @@ export function readLifecycleImmutable<T>(client: LifecycleRpcClient, key: strin
|
|
|
410
410
|
return (client instanceof InvocationLifecycleClient ? client.immutableRead(key, work) : work()) as Promise<T>;
|
|
411
411
|
}
|
|
412
412
|
|
|
413
|
-
/** Successful deployment
|
|
413
|
+
/** Successful deployment observations live for the caller's session, not one block. */
|
|
414
414
|
export function lifecycleSessionRead<T>(client: LifecycleRpcClient, key: string, work: () => Promise<T>): Promise<T> {
|
|
415
415
|
const source = lifecycleSourceClient(client);
|
|
416
416
|
const owner = source.sessionCache ?? source;
|
|
@@ -524,9 +524,7 @@ export async function readLifecycleProfileTopology(client: LifecycleRpcClient, r
|
|
|
524
524
|
if (topology.hookTopology !== 0 && topology.hookTopology !== 1 && topology.hookTopology !== 2) throw new LifecyclePlanningError("INVALID_RPC_RESPONSE", "Registry returned an unsupported hook topology");
|
|
525
525
|
return { ...topology, hookTopology: topology.hookTopology };
|
|
526
526
|
}
|
|
527
|
-
export const nitroArbSys = "0x0000000000000000000000000000000000000064";
|
|
528
527
|
export const nitroGasInfo = "0x000000000000000000000000000000000000006c";
|
|
529
|
-
export const nitroArbSysAbi = parseAbi(["function arbOSVersion() view returns (uint256)"]);
|
|
530
528
|
export const nitroGasInfoAbi = parseAbi([
|
|
531
529
|
// Transaction ceilings are release preset metadata, not guard-only getter reads.
|
|
532
530
|
"function getPricesInWei() view returns (uint256,uint256,uint256,uint256,uint256,uint256)",
|
|
@@ -534,7 +532,7 @@ export const nitroGasInfoAbi = parseAbi([
|
|
|
534
532
|
export type LifecycleNitroPrices = readonly [bigint, bigint, bigint, bigint, bigint, bigint];
|
|
535
533
|
const maxUint64 = (1n << 64n) - 1n;
|
|
536
534
|
|
|
537
|
-
/** Seeded by the planning aggregate
|
|
535
|
+
/** Seeded by the explicitly pinned planning aggregate. */
|
|
538
536
|
export function readNitroPrices(client: LifecycleRpcClient, block: LifecycleBlock): Promise<LifecycleNitroPrices> {
|
|
539
537
|
return readLifecycleContract(client, nitroGasInfo, nitroGasInfoAbi, "getPricesInWei", [], block, undefined, true, true);
|
|
540
538
|
}
|
|
@@ -551,12 +549,6 @@ export function nitroPosterGasBound(transaction: Pick<LifecycleTransaction, "dat
|
|
|
551
549
|
return { posterGas: 2n * ((feeBound + prices[5] - 1n) / prices[5]), feeBound };
|
|
552
550
|
}
|
|
553
551
|
|
|
554
|
-
async function readNitroScalar(context: LifecycleLimitContext, to: Address, abi: Abi, functionName: string): Promise<bigint> {
|
|
555
|
-
const data = encodeFunctionData({ abi, functionName });
|
|
556
|
-
const result = rpcHex(await lifecycleIndependentRpc(context.client, [{ to, data }, toHex(context.block.number)], context.block, true), functionName);
|
|
557
|
-
if (result.length !== 66) throw new LifecyclePlanningError("INVALID_RPC_RESPONSE", `${functionName} must return exactly one ABI word`);
|
|
558
|
-
return decodeFunctionResult({ abi, functionName, data: result }) as bigint;
|
|
559
|
-
}
|
|
560
552
|
|
|
561
553
|
export type LifecycleLimitObservation = {
|
|
562
554
|
limits: ResolvedLifecycleLimits;
|
|
@@ -591,7 +583,7 @@ async function resolveLifecycleLimitsFresh(context: LifecycleLimitContext, sourc
|
|
|
591
583
|
};
|
|
592
584
|
const headroomBps = configuration.headroomBps === undefined ? 1500 : configuration.headroomBps;
|
|
593
585
|
if (!Number.isSafeInteger(headroomBps) || headroomBps < 0 || headroomBps > 10000) throw new LifecyclePlanningError("INVALID_LIMITS", "Headroom must be between zero and 10000 basis points");
|
|
594
|
-
for (const limit of [context.block.gasLimit, configuration.chainGasLimit, configuration.rpcGasLimit, configuration.accountGasLimit
|
|
586
|
+
for (const limit of [context.block.gasLimit, configuration.chainGasLimit, configuration.rpcGasLimit, configuration.accountGasLimit]) {
|
|
595
587
|
if (limit !== undefined && (typeof limit !== "bigint" || limit <= 0n || limit > maxUint64)) throw new LifecyclePlanningError("INVALID_LIMITS", "Gas caps must be positive exact uint64 bigint values");
|
|
596
588
|
}
|
|
597
589
|
if (configuration.maxCalldataBytes !== undefined && (!Number.isSafeInteger(configuration.maxCalldataBytes) || configuration.maxCalldataBytes <= 0)) throw new LifecyclePlanningError("INVALID_LIMITS", "Calldata cap must be a positive byte count");
|
|
@@ -604,37 +596,23 @@ async function resolveLifecycleLimitsFresh(context: LifecycleLimitContext, sourc
|
|
|
604
596
|
throw new LifecyclePlanningError("LIMIT_CONTEXT_MISMATCH", "Supplied execution policy provenance differs from the canonical chain/account/core/block context");
|
|
605
597
|
}
|
|
606
598
|
const protocol = context.chainId === 4663n ? "nitro" : "evm";
|
|
607
|
-
|
|
608
|
-
let arbOSVersion: bigint | undefined;
|
|
609
|
-
if (protocol === "nitro") {
|
|
610
|
-
try {
|
|
611
|
-
const rawVersion = await readNitroScalar(context, nitroArbSys, nitroArbSysAbi, "arbOSVersion");
|
|
612
|
-
// ArbSys alone adds 55 to the logical Nitro ArbOS version.
|
|
613
|
-
if (typeof rawVersion !== "bigint" || rawVersion < 105n) throw new Error("ArbOS version 50 or newer is required (ArbSys raw version >= 105)");
|
|
614
|
-
arbOSVersion = rawVersion - 55n;
|
|
615
|
-
} catch (failure) {
|
|
616
|
-
if (failure instanceof Error && failure.name === "AbortError") throw failure;
|
|
617
|
-
throw new LifecyclePlanningError("NITRO_LIMITS_UNAVAILABLE", `Pinned Nitro version could not be established: ${lifecycleFailureReason(failure)}`);
|
|
618
|
-
}
|
|
619
|
-
if (configuration.estimateDataFee !== undefined) throw new LifecyclePlanningError("INVALID_LIMITS", "Nitro poster fees are already included in gas; an external data-fee estimator would double-charge them");
|
|
620
|
-
}
|
|
599
|
+
if (protocol === "nitro" && configuration.estimateDataFee !== undefined) throw new LifecyclePlanningError("INVALID_LIMITS", "Nitro poster fees are already included in gas; an external data-fee estimator would double-charge them");
|
|
621
600
|
const envelopeCaps = [configuration.chainGasLimit, configuration.rpcGasLimit, configuration.accountGasLimit].filter((limit): limit is bigint => limit !== undefined);
|
|
622
601
|
if (protocol === "evm") envelopeCaps.push(context.block.gasLimit);
|
|
623
602
|
const transactionGasCeiling = envelopeCaps.length === 0 ? undefined : envelopeCaps.reduce((minimum, limit) => limit < minimum ? limit : minimum);
|
|
624
603
|
const executionGasCeiling = protocol === "nitro" ? ROBINHOOD_NATIVE_TRANSACTION_GAS_LIMIT : transactionGasCeiling ?? context.block.gasLimit;
|
|
625
604
|
const unknownExecutionConstraints = [
|
|
626
|
-
...(protocol === "evm" && configuration.chainGasLimit === undefined ? ["Independent chain per-transaction
|
|
605
|
+
...(protocol === "evm" && configuration.chainGasLimit === undefined ? ["Independent chain per-transaction cap is unknown; the budget is bounded by the pinned header"] : []),
|
|
627
606
|
...(configuration.rpcGasLimit === undefined ? ["RPC transaction gas-envelope cap is unknown"] : []),
|
|
628
607
|
...(configuration.accountGasLimit === undefined ? ["Current account/wallet transaction gas-envelope cap is unknown"] : []),
|
|
629
608
|
...(configuration.maxCalldataBytes === undefined ? ["Applicable chain/account/RPC calldata byte cap is unknown"] : []),
|
|
630
|
-
...(maxSimulationGas === undefined ? ["RPC aggregate simulation gas cap is unknown"] : []),
|
|
631
609
|
];
|
|
632
610
|
assertCurrent();
|
|
633
611
|
return {
|
|
634
612
|
configuration, assertCurrent,
|
|
635
613
|
limits: Object.freeze({
|
|
636
|
-
protocol, executionGasCeiling, transactionGasCeiling,
|
|
637
|
-
maxCalldataBytes: configuration.maxCalldataBytes,
|
|
614
|
+
protocol, executionGasCeiling, transactionGasCeiling, headroomBps,
|
|
615
|
+
maxCalldataBytes: configuration.maxCalldataBytes,
|
|
638
616
|
blockGasLimit: context.block.gasLimit, chainGasLimit: configuration.chainGasLimit,
|
|
639
617
|
rpcGasLimit: configuration.rpcGasLimit, accountGasLimit: configuration.accountGasLimit,
|
|
640
618
|
unknownExecutionConstraints: Object.freeze(unknownExecutionConstraints),
|
|
@@ -5,7 +5,7 @@ import { getKnownLifecycleDeployment, type LifecycleDeploymentPreset } from "./p
|
|
|
5
5
|
import { lifecycleTokenPredictionAbi } from "./progress.js";
|
|
6
6
|
import { launchLensAbi, observeLifecycleLens, type LifecycleLensSnapshot } from "./lens.js";
|
|
7
7
|
import { hashLaunchIdentity, LifecycleFundingKind, type LaunchPlanV1 } from "./schema.js";
|
|
8
|
-
import { attestLifecycleMulticall, lifecycleRpc,
|
|
8
|
+
import { attestLifecycleMulticall, lifecycleRpc, nitroGasInfo, nitroGasInfoAbi, readLifecycleBlock, readLifecycleChainId, rpcHex, seedLifecycleRead } from "./rpc.js";
|
|
9
9
|
import { LifecyclePlanningError, type LifecycleBlock, type LifecycleRpcClient } from "./types.js";
|
|
10
10
|
import { UFG_LAUNCH_PROXY_ADDRESS } from "./ufg-config.js";
|
|
11
11
|
|
|
@@ -36,7 +36,6 @@ export async function readLifecyclePlanningBlock(client: LifecycleRpcClient, pla
|
|
|
36
36
|
if (escrow !== undefined) add(asset, lifecycleErc20Abi, "allowance", [account, escrow]);
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
|
-
add(nitroArbSys, nitroArbSysAbi, "arbOSVersion", []);
|
|
40
39
|
add(nitroGasInfo, nitroGasInfoAbi, "getPricesInWei", []);
|
|
41
40
|
await attestLifecycleMulticall(client, block);
|
|
42
41
|
const calls = reads.map((read) => ({ target: read.to, allowFailure: true, callData: encodeFunctionData({ abi: read.abi, functionName: read.functionName, args: read.args }) }));
|
|
@@ -3,27 +3,64 @@ import { launchLifecycleAbi } from "./abi.js";
|
|
|
3
3
|
import { LifecycleFundingKind, LifecycleMode, type LaunchPlanV1 } from "./schema.js";
|
|
4
4
|
import { LifecyclePlanningError, type BuildLaunchTransactionsOptions, type LifecycleTransaction } from "./types.js";
|
|
5
5
|
import { assertLifecycleTokenAllocation } from "./allocations.js";
|
|
6
|
-
import { HMM_V2_PREPARE_GAS } from "./presets.js";
|
|
7
|
-
import { isHmmProfile } from "./hmm.js";
|
|
8
6
|
import { ufgLaunchProxyV1Abi } from "./ufg-abi.js";
|
|
9
|
-
import { UFG_LAUNCH_PROXY_ADDRESS } from "./ufg-config.js";
|
|
7
|
+
import { UFG_LAUNCH_PROXY_ADDRESS, isUfgProfile } from "./ufg-config.js";
|
|
8
|
+
import { decodeAbyssLifecycleMarketConfig, decodePoolBoundV4LifecycleMarketConfig, decodeV4LifecycleMarketConfig, isPoolBoundV4ConfigVersion } from "./markets.js";
|
|
9
|
+
import { isHmmProfile } from "./hmm.js";
|
|
10
|
+
import { isRaetoProfile } from "./raeto.js";
|
|
11
|
+
import { isAutoCompoundProfile } from "./auto-compound.js";
|
|
10
12
|
import type { UfgLaunchConfig } from "./ufg-config.js";
|
|
11
13
|
|
|
12
|
-
|
|
14
|
+
// Native9,723,187 Abyss3 (0x679d…e77), fork32-position10,900,786;
|
|
15
|
+
// fork V4 fixed/dynamic8-position8,804,466; UFG9,896,176; native HMM8-position14,676,638 (0x459c…5b7).
|
|
16
|
+
const preparationCosts = {
|
|
17
|
+
abyss: { market: 9_800_000n, position: 70_000n },
|
|
18
|
+
v4: { market: 9_000_000n, position: 40_000n },
|
|
19
|
+
ufg: { market: 10_000_000n, position: 70_000n },
|
|
20
|
+
hmm: { market: 15_000_000n, position: 50_000n },
|
|
21
|
+
// template-gas-matrix.json: Raeto1 <=9.13M,32 <=11.23M.
|
|
22
|
+
raeto: { market: 9_300_000n, position: 70_000n },
|
|
23
|
+
// Same matrix: auto-compound1 <=8.71M,32 <=10.76M.
|
|
24
|
+
autoCompound: { market: 8_900_000n, position: 70_000n },
|
|
25
|
+
} as const;
|
|
26
|
+
export const LIFECYCLE_CAPACITY_PADDING_BPS = 2500;
|
|
27
|
+
/** Full single-market observations include call overhead. Add conservative full
|
|
28
|
+
* calldata/hash processing (16 intrinsic gas per nonzero byte plus8 for copying). */
|
|
29
|
+
export function preparationCalldataGas(data: `0x${string}`): bigint { return 24n * BigInt((data.length - 2) / 2); }
|
|
13
30
|
|
|
14
31
|
export function preparationGasEstimate(plan: LaunchPlanV1, first: number, count: number): bigint {
|
|
15
32
|
let gas = 0n;
|
|
16
|
-
for (let index = first; index < first + count; index += 1)
|
|
33
|
+
for (let index = first; index < first + count; index += 1) {
|
|
34
|
+
const market = plan.markets[index]!;
|
|
35
|
+
const positions = market.configVersion === 1 ? decodeAbyssLifecycleMarketConfig(market.config).positions.length
|
|
36
|
+
: isPoolBoundV4ConfigVersion(market.configVersion) ? decodePoolBoundV4LifecycleMarketConfig(market.config, market.configVersion).positions.length
|
|
37
|
+
: decodeV4LifecycleMarketConfig(market.config).positions.length;
|
|
38
|
+
const cost = market.configVersion === 1 ? preparationCosts.abyss : isHmmProfile(market.profileId) ? preparationCosts.hmm
|
|
39
|
+
: isUfgProfile(market.profileId) ? preparationCosts.ufg : isRaetoProfile(market.profileId) ? preparationCosts.raeto
|
|
40
|
+
: isAutoCompoundProfile(market.profileId) ? preparationCosts.autoCompound : preparationCosts.v4;
|
|
41
|
+
gas += cost.market + cost.position * BigInt(positions - 1);
|
|
42
|
+
}
|
|
17
43
|
return gas;
|
|
18
44
|
}
|
|
19
45
|
|
|
20
|
-
/** Contiguous
|
|
21
|
-
|
|
46
|
+
/** Contiguous deterministic packing with compute headroom. The caller reserves
|
|
47
|
+
* poster allocation separately from computeCap; neither resizes transaction gas. */
|
|
48
|
+
export function packPreparationBatches(plan: LaunchPlanV1, prepared: number, computeCap: bigint, headroomBps = 1500): number[] {
|
|
49
|
+
const data = buildLifecycleCommand(plan, { kind: "prepare", first: prepared, count: 1 }).data;
|
|
50
|
+
return packLifecyclePreparationBatches(plan, prepared, computeCap, headroomBps, preparationCalldataGas(data));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Internal path reuses the command already encoded for poster allocation. */
|
|
54
|
+
export function packLifecyclePreparationBatches(plan: LaunchPlanV1, prepared: number, computeCap: bigint, headroomBps: number, calldataGas: bigint): number[] {
|
|
55
|
+
if (!Number.isSafeInteger(headroomBps) || headroomBps < 0 || headroomBps > 10000) throw new LifecyclePlanningError("INVALID_LIMITS", "Headroom must be between zero and10000 basis points");
|
|
56
|
+
const padding = BigInt(10000 + Math.max(LIFECYCLE_CAPACITY_PADDING_BPS, headroomBps));
|
|
57
|
+
const fits = (gas: bigint) => ((gas + calldataGas) * padding + 9999n) / 10000n <= computeCap;
|
|
22
58
|
const batches = prepared > 0 ? [prepared] : [];
|
|
23
59
|
let count = 0, gas = 0n;
|
|
24
60
|
for (let index = prepared; index < plan.markets.length; index += 1) {
|
|
25
61
|
const estimate = preparationGasEstimate(plan, index, 1);
|
|
26
|
-
if (
|
|
62
|
+
if (!fits(estimate)) throw new LifecyclePlanningError("PREPARATION_GAS_LIMIT", "A market exceeds the preparation gas budget. Reduce its positions before launching.");
|
|
63
|
+
if (count > 0 && !fits(gas + estimate)) { batches.push(count); count = 0; gas = 0n; }
|
|
27
64
|
count += 1;
|
|
28
65
|
gas += estimate;
|
|
29
66
|
}
|
|
@@ -53,7 +90,7 @@ export function buildLifecycleCommand(plan: LaunchPlanV1, command: LifecycleComm
|
|
|
53
90
|
|
|
54
91
|
/** Pure unsigned launch commands. Every command carries the complete commitment;
|
|
55
92
|
* preparation splits only empty markets, never positions, buys or public opening.
|
|
56
|
-
* Allowance discovery, recovery and
|
|
93
|
+
* Allowance discovery, recovery and gas-budget checks belong to the planner. */
|
|
57
94
|
export function buildLifecycleCommands({ plan, mode, preparationBatches }: BuildLaunchTransactionsOptions, ufg?: LifecycleUfgRoute): LifecycleTransaction[] {
|
|
58
95
|
if (mode !== "atomic" && mode !== "staged") throw new LifecyclePlanningError("EXPLICIT_MODE_REQUIRED", "Choose atomic or staged explicitly; staged is never silently substituted");
|
|
59
96
|
if (plan.chainId <= 0n || plan.chainId > BigInt(Number.MAX_SAFE_INTEGER)) throw new LifecyclePlanningError("CHAIN_MISMATCH", "Chain ID must be a positive exact JavaScript integer");
|