@black-market/sdk 0.11.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +17 -0
  2. package/dist/lifecycle/abi.d.ts +1 -0
  3. package/dist/lifecycle/abi.d.ts.map +1 -1
  4. package/dist/lifecycle/abi.js +1 -0
  5. package/dist/lifecycle/abi.js.map +1 -1
  6. package/dist/lifecycle/deployments/ufg-dynamic-pool-20261021.d.ts +71 -0
  7. package/dist/lifecycle/deployments/ufg-dynamic-pool-20261021.d.ts.map +1 -0
  8. package/dist/lifecycle/deployments/ufg-dynamic-pool-20261021.js +73 -0
  9. package/dist/lifecycle/deployments/ufg-dynamic-pool-20261021.js.map +1 -0
  10. package/dist/lifecycle/deployments/ufg-fixed-pool-20261021.d.ts +71 -0
  11. package/dist/lifecycle/deployments/ufg-fixed-pool-20261021.d.ts.map +1 -0
  12. package/dist/lifecycle/deployments/ufg-fixed-pool-20261021.js +73 -0
  13. package/dist/lifecycle/deployments/ufg-fixed-pool-20261021.js.map +1 -0
  14. package/dist/lifecycle/index.d.ts +1 -0
  15. package/dist/lifecycle/index.d.ts.map +1 -1
  16. package/dist/lifecycle/index.js +1 -0
  17. package/dist/lifecycle/index.js.map +1 -1
  18. package/dist/lifecycle/markets.d.ts +3 -1
  19. package/dist/lifecycle/markets.d.ts.map +1 -1
  20. package/dist/lifecycle/markets.js +20 -3
  21. package/dist/lifecycle/markets.js.map +1 -1
  22. package/dist/lifecycle/planner.d.ts.map +1 -1
  23. package/dist/lifecycle/planner.js +42 -22
  24. package/dist/lifecycle/planner.js.map +1 -1
  25. package/dist/lifecycle/presets.d.ts +4 -2
  26. package/dist/lifecycle/presets.d.ts.map +1 -1
  27. package/dist/lifecycle/presets.js +11 -4
  28. package/dist/lifecycle/presets.js.map +1 -1
  29. package/dist/lifecycle/progress.d.ts.map +1 -1
  30. package/dist/lifecycle/progress.js +26 -5
  31. package/dist/lifecycle/progress.js.map +1 -1
  32. package/dist/lifecycle/simulation.d.ts.map +1 -1
  33. package/dist/lifecycle/simulation.js +4 -1
  34. package/dist/lifecycle/simulation.js.map +1 -1
  35. package/dist/lifecycle/types.d.ts +11 -1
  36. package/dist/lifecycle/types.d.ts.map +1 -1
  37. package/dist/lifecycle/types.js.map +1 -1
  38. package/dist/lifecycle/ufg-abi.d.ts +2386 -0
  39. package/dist/lifecycle/ufg-abi.d.ts.map +1 -0
  40. package/dist/lifecycle/ufg-abi.js +171 -0
  41. package/dist/lifecycle/ufg-abi.js.map +1 -0
  42. package/dist/lifecycle/ufg-config.d.ts +38 -0
  43. package/dist/lifecycle/ufg-config.d.ts.map +1 -0
  44. package/dist/lifecycle/ufg-config.js +75 -0
  45. package/dist/lifecycle/ufg-config.js.map +1 -0
  46. package/dist/lifecycle/ufg.d.ts +21 -0
  47. package/dist/lifecycle/ufg.d.ts.map +1 -0
  48. package/dist/lifecycle/ufg.js +98 -0
  49. package/dist/lifecycle/ufg.js.map +1 -0
  50. package/docs/launch-lifecycle.md +138 -0
  51. package/examples/README.md +16 -2
  52. package/examples/ufg-launch-config.ts +31 -0
  53. package/package.json +1 -1
  54. package/src/lifecycle/abi.ts +1 -0
  55. package/src/lifecycle/deployments/ufg-dynamic-pool-20261021.ts +74 -0
  56. package/src/lifecycle/deployments/ufg-fixed-pool-20261021.ts +74 -0
  57. package/src/lifecycle/index.ts +1 -0
  58. package/src/lifecycle/markets.ts +16 -3
  59. package/src/lifecycle/planner.ts +37 -22
  60. package/src/lifecycle/presets.ts +11 -4
  61. package/src/lifecycle/progress.ts +22 -5
  62. package/src/lifecycle/simulation.ts +3 -1
  63. package/src/lifecycle/types.ts +6 -1
  64. package/src/lifecycle/ufg-abi.ts +173 -0
  65. package/src/lifecycle/ufg-config.ts +77 -0
  66. package/src/lifecycle/ufg.ts +86 -0
@@ -0,0 +1,98 @@
1
+ import { decodeFunctionResult, encodeFunctionData, keccak256, stringToHex, zeroAddress } from "viem";
2
+ import { lifecycleErc20Abi } from "./abi.js";
3
+ import { ufgLaunchProxyV1Abi, ufgTreasuryFactoryV1Abi } from "./ufg-abi.js";
4
+ import { buildLaunchTransactions } from "./transactions.js";
5
+ import { decodeAbyssLifecycleMarketConfig, encodeAbyssLifecycleMarketConfig, decodePoolBoundV4LifecycleMarketConfig } from "./markets.js";
6
+ import { getKnownLifecycleProfile, KnownLifecycleProfile } from "./presets.js";
7
+ import { LifecycleFundingKind, LifecycleTokenKind, LifecycleRewardMode, LifecycleMode } from "./schema.js";
8
+ import { LifecyclePlanningError } from "./types.js";
9
+ import { buildUfgFeeAssetPolicies, encodeUfgLaunchConfig, hashUfgLaunchConfig, isUfgProfile, UFG_DYNAMIC_ADAPTER_ID, UFG_FIXED_ADAPTER_ID, UFG_FIXED_PROFILE_ID, UFG_LAUNCH_PROXY_ADDRESS, UFG_TREASURY_FACTORY_ADDRESS, ufgPlanPrincipal } from "./ufg-config.js";
10
+ export { UFG_LAUNCH_PROXY_ADDRESS, UFG_TREASURY_FACTORY_ADDRESS, UFG_UPSTREAM_FACTORY_ADDRESS, UFG_ORCHESTRATOR_ADDRESS, UFG_FIXED_PROFILE_ID, UFG_DYNAMIC_PROFILE_ID, UFG_FIXED_ADAPTER_ID, UFG_DYNAMIC_ADAPTER_ID, isUfgProfile, ufgLaunchConfigComponents, encodeUfgLaunchConfig, decodeUfgLaunchConfig, hashUfgLaunchConfig, validateUfgLaunchConfig, ufgLaunchNonce, buildUfgFeeAssetPolicies } from "./ufg-config.js";
11
+ /** Offline proxy-specific admission. Live token/reserve code, registry and transfer checks still require simulation. */
12
+ export function validateUfgLaunchPlan(plan, config, predictedToken) {
13
+ try {
14
+ ufgPlanPrincipal(plan);
15
+ encodeUfgLaunchConfig(config);
16
+ if (plan.token.kind !== LifecycleTokenKind.ERC20 || plan.token.rewardMode !== LifecycleRewardMode.None || plan.executorFeeBps !== 0 || plan.markets.length === 0 || plan.token.inventoryRecipient.toLowerCase() === UFG_LAUNCH_PROXY_ADDRESS.toLowerCase() || plan.buys.some((buy) => buy.recipient.toLowerCase() === UFG_LAUNCH_PROXY_ADDRESS.toLowerCase()))
17
+ throw new Error("UFG requires ERC20/no rewards, zero executor fee, markets and external inventory/buy recipients");
18
+ const expected = buildUfgFeeAssetPolicies(predictedToken, config.reserveAssets);
19
+ if (plan.feeAssets.length !== expected.length || plan.feeAssets.some((policy, index) => {
20
+ const required = expected[index];
21
+ return policy.asset.toLowerCase() !== required.asset.toLowerCase() || policy.ownerBps !== required.ownerBps || policy.rewardsBps !== 0 || policy.burnBps !== required.burnBps;
22
+ }))
23
+ throw new Error("UFG fee policies must burn all token fees and send all reserve fees to the owner, in ascending asset order");
24
+ const reserves = new Set(config.reserveAssets.map((asset) => asset.toLowerCase()));
25
+ const quotes = new Set(plan.markets.map((market) => market.quoteAsset.toLowerCase()));
26
+ if (reserves.size !== quotes.size || [...quotes].some((quote) => !reserves.has(quote)))
27
+ throw new Error("Every reserve must be a market quote and every market quote a reserve");
28
+ const configHash = hashUfgLaunchConfig(config);
29
+ for (const market of plan.markets) {
30
+ if (market.configVersion === 1) {
31
+ const inner = decodeAbyssLifecycleMarketConfig(market.config);
32
+ const profile = getKnownLifecycleProfile({ chainId: plan.chainId, orchestrator: plan.orchestrator, key: inner.profile === 2 ? KnownLifecycleProfile.Abyss2 : KnownLifecycleProfile.Abyss3 });
33
+ if (market.adapterId.toLowerCase() !== keccak256(stringToHex("black-market.adapter.abyss-lifecycle.v1")) || (inner.profile !== 2 && inner.profile !== 3) || market.profileId.toLowerCase() !== profile?.profile.id || encodeAbyssLifecycleMarketConfig(inner).toLowerCase() !== market.config.toLowerCase())
34
+ throw new Error("UFG Abyss markets require canonical QUOTE or QUOTE_ORACLE config1 without a tail");
35
+ }
36
+ else if (market.configVersion === 6) {
37
+ if (!isUfgProfile(market.profileId))
38
+ throw new Error("UFG config6 markets require an admitted UFG fixed or dynamic profile");
39
+ const inner = decodePoolBoundV4LifecycleMarketConfig(market.config, 6);
40
+ const adapterId = market.profileId.toLowerCase() === UFG_FIXED_PROFILE_ID ? UFG_FIXED_ADAPTER_ID : UFG_DYNAMIC_ADAPTER_ID;
41
+ if (market.adapterId.toLowerCase() !== adapterId || inner.profileId.toLowerCase() !== market.profileId.toLowerCase() || inner.version !== 6 || inner.feeMode !== 1 || inner.lpFeePips !== 0 || inner.ufgLaunchConfig === undefined || hashUfgLaunchConfig(inner.ufgLaunchConfig) !== configHash)
42
+ throw new Error("Every UFG config6 market requires QuoteOnly, zero LP fee and the identical canonical proxy config tail");
43
+ }
44
+ else
45
+ throw new Error("UFG supports only canonical Abyss config1 and UFG pool-bound config6");
46
+ }
47
+ }
48
+ catch (error) {
49
+ if (error instanceof LifecyclePlanningError && error.code === "INVALID_UFG_PLAN")
50
+ throw error;
51
+ throw new LifecyclePlanningError("INVALID_UFG_PLAN", error instanceof Error ? error.message : "Invalid UFG launch plan");
52
+ }
53
+ }
54
+ /** Pure unsigned proxy commands; account is the principal encoded in plan.nonce. */
55
+ export function buildUfgLaunchTransactions(options) {
56
+ const { plan, config } = options;
57
+ const principal = ufgPlanPrincipal(plan);
58
+ encodeUfgLaunchConfig(config);
59
+ return buildLaunchTransactions(options).map((transaction) => {
60
+ const data = transaction.kind === "atomic" ? encodeFunctionData({ abi: ufgLaunchProxyV1Abi, functionName: "launchAtomic", args: [plan, config] })
61
+ : transaction.kind === "begin" ? encodeFunctionData({ abi: ufgLaunchProxyV1Abi, functionName: "beginLaunch", args: [plan, LifecycleMode.Staged, config] }) : transaction.data;
62
+ return { ...transaction, from: principal, to: UFG_LAUNCH_PROXY_ADDRESS, data, calldataBytes: (data.length - 2) / 2 };
63
+ });
64
+ }
65
+ export function buildUfgCancelTransaction({ plan, preparedMarkets = 0 }) {
66
+ const data = encodeFunctionData({ abi: ufgLaunchProxyV1Abi, functionName: "cancelLaunch", args: [plan] });
67
+ return { id: "cancel", kind: "cancel", chainId: Number(plan.chainId), from: ufgPlanPrincipal(plan), to: UFG_LAUNCH_PROXY_ADDRESS, data, calldataBytes: (data.length - 2) / 2, value: 0n, dependencies: [], postconditions: [{ kind: "launch", phase: "Cancelled", preparedMarkets }] };
68
+ }
69
+ /** Exact summed proxy pulls, not escrow allowances. Current allowance/reset discovery belongs to planning. */
70
+ export function buildUfgApprovals(plan) {
71
+ const principal = ufgPlanPrincipal(plan);
72
+ const totals = new Map();
73
+ for (const funding of plan.funding) {
74
+ if (funding.kind === LifecycleFundingKind.NativeWrap || BigInt(funding.inputAsset) === 0n)
75
+ continue;
76
+ const asset = funding.kind === LifecycleFundingKind.ERC20 ? funding.asset : funding.inputAsset;
77
+ const amount = funding.kind === LifecycleFundingKind.ERC20 ? funding.amount : funding.inputAmount;
78
+ const key = asset.toLowerCase();
79
+ const entry = totals.get(key);
80
+ if (entry === undefined)
81
+ totals.set(key, { asset, amount });
82
+ else
83
+ entry.amount += amount;
84
+ }
85
+ const transactions = [...totals.values()].map(({ asset, amount }) => {
86
+ const data = encodeFunctionData({ abi: lifecycleErc20Abi, functionName: "approve", args: [UFG_LAUNCH_PROXY_ADDRESS, amount] });
87
+ return { id: `approve:${asset}`, kind: "approve", chainId: Number(plan.chainId), from: principal, to: asset, data, calldataBytes: (data.length - 2) / 2, value: 0n, dependencies: [], postconditions: [{ kind: "allowance", asset, spender: UFG_LAUNCH_PROXY_ADDRESS, minimum: amount }] };
88
+ });
89
+ return transactions.map((transaction, index) => ({ ...transaction, dependencies: index === 0 ? [] : [transactions[index - 1].id] }));
90
+ }
91
+ /** Read-only upstream treasury lookup. No treasury is represented by undefined, not the zero address. */
92
+ export async function readUfgTreasury(client, token) {
93
+ const data = encodeFunctionData({ abi: ufgTreasuryFactoryV1Abi, functionName: "treasuryOf", args: [token] });
94
+ const result = await client.request({ method: "eth_call", params: [{ to: UFG_TREASURY_FACTORY_ADDRESS, data }, "latest"] });
95
+ const treasury = decodeFunctionResult({ abi: ufgTreasuryFactoryV1Abi, functionName: "treasuryOf", data: result });
96
+ return treasury === zeroAddress ? undefined : treasury;
97
+ }
98
+ //# sourceMappingURL=ufg.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ufg.js","sourceRoot":"","sources":["../../src/lifecycle/ufg.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,144 @@ The canonical authorities are the registry/certification/adapter/config contract
7
7
  in the protocol repository. Plan identity is `LaunchPlanV1`. Pool-bound V4 uses **config 6**,
8
8
  canonical Abyss uses **config 1**, and generic current shared-V4 support uses **config 4**.
9
9
 
10
+ ## 0.12.0 release: opt-in UFG treasuries
11
+
12
+ UFG is an additive **proxy launch route**, not a new token kind or a replacement
13
+ for the core path. Existing launch defaults, calldata, salts and HMM behavior are
14
+ unchanged when `ufg` is omitted. The pinned Robinhood deployment (chain **4663**) is:
15
+
16
+ | Export | Address |
17
+ | --- | --- |
18
+ | `UFG_LAUNCH_PROXY_ADDRESS` | `0xf6673d859DE03eB74A0b01696Edb97f941dFD0CA` |
19
+ | `UFG_TREASURY_FACTORY_ADDRESS` | `0x26Aa5D52134c8E6c4C01E9fb53A7568c0C64901F` |
20
+ | `UFG_UPSTREAM_FACTORY_ADDRESS` | `0xA170b5A58C111334A7237F2Ea2c428ec5022f68E` |
21
+ | `UFG_ORCHESTRATOR_ADDRESS` | `0x91560876033d568d25CDe98C78c33ff8FC43962c` |
22
+
23
+ `KnownLifecycleProfile.V4UfgFixedPool` (`v4-ufg-fixed-pool`) selects profile
24
+ `0x5c6045af480814e469f3dba7c120d264047c9320b869c63a064536041a2dbae6`;
25
+ `V4UfgDynamicPool` (`v4-ufg-dynamic-pool`) selects
26
+ `0x03de8d5e38f2957d80ecb9f2e59d555601ff091dfb17bce84178956a2e8d9b41`.
27
+ `isUfgProfile` recognizes only these IDs. Frozen envelopes, adapter/registration/
28
+ topology and bound-hook metadata come from committed registry readback at block
29
+ **94,551,140** (`test/fixtures/ufg-registry-readback.json`). Regenerate with
30
+ `node --experimental-transform-types scripts/generate-ufg-presets.mjs /path/to/black-market`;
31
+ add `--readback` only to recapture that exact block with read-only RPC.
32
+ The fixed and zero-royalty dynamic creation bytes exactly match the existing
33
+ `FixedFeePoolV1` / `DynamicFeePoolV1` artifacts, so no duplicate hook enum is needed.
34
+ UFG deployers, lockers, collectors and adapters are nevertheless different graphs.
35
+ Frozen presets are construction evidence, not live admission.
36
+
37
+ ### Configuration and supported markets
38
+
39
+ `UfgLaunchConfig` is `{ treasuryShareBps, exitFeeBps, reserveAssets }`. The proxy
40
+ requires treasury share **10000**, integer exit fee **0..2000 bps**, and **1..7**
41
+ nonzero, unique, strictly ascending reserve addresses, excluding the predicted
42
+ launch token. Reserves and market quotes must form exactly the same set.
43
+
44
+ - ERC20 only, no staking/dividends, zero executor fee and at least one market.
45
+ Neither inventory nor initial-buy recipients may be the proxy.
46
+ - Native Abyss uses the canonical adapter with config1 profile **2 (QUOTE)** or
47
+ **3 (QUOTE_ORACLE)** and the matching canonical profile ID. Its canonical
48
+ config has **no tail**.
49
+ - V4 uses config6 and one of the two UFG profiles, `feeMode: 1` (QuoteOnly) and
50
+ `lpFeePips: 0`. Preset zero-royalty terms still apply. Supply/position budgets,
51
+ price/ranges, oracle registration and ordinary lifecycle bounds are unchanged.
52
+ - Fee policies contain exactly the token plus reserves in ascending order:
53
+ token `{ ownerBps: 0, rewardsBps: 0, burnBps: 10000 }`, reserves
54
+ `{ ownerBps: 10000, rewardsBps: 0, burnBps: 0 }`.
55
+ `buildUfgFeeAssetPolicies(predictedToken, reserveAssets)` builds that exact set;
56
+ reserve ordering is validated, never silently repaired.
57
+
58
+ `encodeUfgLaunchConfig` encodes **one dynamic tuple**:
59
+ `abi.encode((uint16,uint16,address[]))`, including the leading `0x20` offset.
60
+ `decodeUfgLaunchConfig` checks canonical re-encoding; trailing bytes, alternate
61
+ offsets and dirty padding are rejected. `hashUfgLaunchConfig` is its keccak256.
62
+ Config6's typed `ufgLaunchConfig` automatically appends that encoding after the
63
+ canonical V6 prefix and decodes/splits it on read. Every UFG V4 tail must equal
64
+ the proxy config. The constructor economics hash remains **prefix-only with zero
65
+ hook salt**; the full plan hash binds the tail. No UFG tail is added to ordinary
66
+ V4, HMM or Abyss configs. Independent `cast abi-encode` fixtures are regenerated
67
+ with `node scripts/generate-ufg-fixtures.mjs`.
68
+
69
+ ### Principal funding, planning and recovery
70
+
71
+ The economic plan's **creator is the proxy**. Its nonce is
72
+ `ufgLaunchNonce(principal, nonce96) = (uint160(principal) << 96) | nonce96`.
73
+ The `account` and every sender are the **same principal**, never the proxy.
74
+ The core still derives launch ID/token from the committed core/proxy/nonce.
75
+
76
+ ```ts
77
+ const config = {
78
+ treasuryShareBps: 10000, exitFeeBps: 100,
79
+ reserveAssets: [getAddresses(4663).weth],
80
+ };
81
+ // economicPlan already contains your full token/funding/market/buy economics;
82
+ // every UFG V4 market was encoded with this same ufgLaunchConfig.
83
+ const plan = { ...economicPlan, creator: UFG_LAUNCH_PROXY_ADDRESS,
84
+ nonce: ufgLaunchNonce(principal, 1n) };
85
+ const token = await client.readContract({ address: plan.orchestrator,
86
+ abi: launchLifecycleAbi, functionName: "predictToken", args: [plan] });
87
+ plan.feeAssets = buildUfgFeeAssetPolicies(token, config.reserveAssets);
88
+ validateUfgLaunchPlan(plan, config, token); // pure/offline proxy rules
89
+ const planned = await prepareAndPlanLifecycleLaunch({
90
+ client, account: principal, plan, mode: "staged", ufg: { config },
91
+ });
92
+ // No signing here. Obtain fresh admitted proxy envelopes before wallet execution:
93
+ const next = await buildNextTransaction({ client, planned });
94
+ ```
95
+
96
+ The opt-in works on `planLaunch` too. `PlannedLaunch.ufg` retains config and its
97
+ hash; `simulateLaunchPlan`, `readLaunchProgress`, and `buildNextTransaction`
98
+ (including `action: "cancel"`) retain the route and reject config mutation,
99
+ wrong principal/nonce, wrong receipt target/config, or proxy binding mismatch.
100
+ Salt mining and optional buy-minimum calibration use the existing machinery.
101
+ Native Nitro metering/execution proofs remain mandatory on production chain4663.
102
+
103
+ The proxy pulls summed non-native inputs from the principal: ERC20 asset/amount
104
+ or swap inputAsset/inputAmount. **Approve the proxy, not the funding escrow**.
105
+ `buildUfgApprovals(plan)` builds exact summed approvals; planning observes current
106
+ allowances and includes zero-reset commands when needed. Native-wrap and native
107
+ swap inputs are `msg.value` on atomic/begin only. Refunds return to the principal.
108
+
109
+ Pure `buildUfgLaunchTransactions({ plan, config, mode, preparationBatches })`
110
+ produces proxy `launchAtomic(plan, config)`, or `beginLaunch(plan, Staged, config)`,
111
+ ordered `prepareMarkets` batches, then `activateLaunch`. The explicit batches
112
+ must cover all markets. `buildUfgCancelTransaction({ plan, preparedMarkets })`
113
+ targets the same proxy. These builders alone do not establish execution admission.
114
+ `validateUfgLaunchPlan` checks offline proxy rules; live registry continuity,
115
+ reserve/token code and supply bounds, transfers and treasury creation require RPC
116
+ simulation. The existing non-UFG core transaction builder is intentionally unchanged.
117
+
118
+ `readUfgTreasury(client, token)` reads the treasury factory's `treasuryOf(token)`
119
+ and returns the upstream address, or `undefined` for zero. Complete
120
+ `ufgLaunchProxyV1Abi`, `ufgTreasuryFactoryV1Abi`, `ufgBlackMarketFactoryAbi` and
121
+ `ufgBlackMarketTreasuryAbi` expose proxy config hashes and upstream treasury
122
+ collect/redeem/assets/backing/position/debt operations without inventing wrappers.
123
+ The pure example is `node examples/ufg-launch-config.ts` after building.
124
+
125
+ ### UFG owned-fork check
126
+
127
+ This explicitly authorized local-only integration uses the unlocked Anvil default
128
+ account, no keys, and only public SDK launch APIs. In separate terminals:
129
+
130
+ ```sh
131
+ anvil --fork-url https://rpc.mainnet.chain.robinhood.com/ \
132
+ --chain-id 4663 --port 8561 \
133
+ --gas-limit 100000000 --silent
134
+ pnpm build
135
+ UFG_FORK_RPC_URL=http://127.0.0.1:8561 node test/integration/ufg-launch.fork.mjs
136
+ ```
137
+
138
+ It validates the tuple against the deployed factory, mines bound-hook salts,
139
+ executes Abyss QUOTE atomic, mixed Abyss QUOTE + UFG fixed staged (ERC20 funding/
140
+ proxy approval), and UFG dynamic atomic launches. It calls each exact proxy
141
+ command from the principal first, then checks Active, a nonzero `readUfgTreasury`
142
+ and `proxy.launchConfigHash == hashUfgLaunchConfig`. Snapshot restoration makes
143
+ the check repeatable. Stop Anvil afterward. Generic Anvil proves EVM contract
144
+ behavior here, **not ArbOS compute/poster admission**: construction/read/mining/
145
+ unsigned APIs plus actual fork `eth_call`/receipts are used, not a fake native
146
+ Nitro planner certificate. Ordinary `pnpm test` never runs this funded check.
147
+
10
148
  ## 0.11.0 release: gas sizing, packing and prefix proof
11
149
 
12
150
  New atomic/activation envelopes containing HMM V2 markets add one forwarding target:
@@ -1,8 +1,8 @@
1
1
  # Examples
2
2
 
3
- The launch examples use the public `@black-market/sdk` 0.11.0 package and viem.
3
+ The launch examples use the public `@black-market/sdk` 0.12.0 package and viem.
4
4
  Build this checkout before running its examples; in a consumer project install
5
- `@black-market/sdk@0.11.0` for current gas packing and proof-coverage semantics.
5
+ `@black-market/sdk@0.12.0` for opt-in UFG treasuries and current proof semantics.
6
6
  The default chain-4663 launch cases retain
7
7
  the October8 mined fixed pool-bound V4 config6/V2 and canonical Abyss config1 deployment.
8
8
  The SDK additionally knows the October11 zero-author-royalty Dynamic Fee Hook;
@@ -25,11 +25,25 @@ examples; their relative support imports use explicit `.ts` extensions for Node
25
25
  | --- | --- |
26
26
  | `quickstart.ts` | Reads the current mainnet orchestrator, checks its registry binding, and discovers admitted profiles. No wallet or writes. |
27
27
  | `hmm-launch-config.ts` | Pure HMM V2 fixed/dynamic config construction with caller-chosen bid/reference guards and an automatically appended 512-byte launch tail; no RPC, signatures or writes. |
28
+ | `ufg-launch-config.ts` | Pure fixed/dynamic UFG quote-only config6 construction, canonical reserve tail and config hash; no RPC, wallet or writes. |
28
29
  | `launch.ts` | Reviews/reconstructs an explicit saved plan and selected atomic/staged mode; optional offchain config6/V2 salt mining. Prints simulation, progress, and an admitted unsigned next transaction when evidence permits. |
29
30
  | `generate-lifecycle-commitment-fixture.ts` | Frozen independent historical config4/Abyss ABI bytes/hash/identity vector. Its pre-cutover allocations are not an executable 0.7.1 plan. |
30
31
  | `launch-lifecycle-smoke.ts` | Actual SDK launch/recovery/custody/fee operations, only on an explicitly authorized owned disposable loopback graph. |
31
32
  | `launch-erc20-*.ts`, `launch-erc404-*.ts` | Eleven independent fixed cases: unsigned end-to-end planning by default; `--broadcast` adds guarded local signing, chain verification and mandatory API publication/indexing. |
32
33
 
34
+ ## UFG treasury configuration
35
+
36
+ Run `pnpm build && node examples/ufg-launch-config.ts` for a pure consumer example.
37
+ Real UFG plans use the proxy as creator and a principal-namespaced nonce, with
38
+ `ufg: { config }` on `prepareAndPlanLifecycleLaunch`; the principal remains the
39
+ planning/signing account. Use only reward-free ERC20, full treasury reserve share,
40
+ launch-token burn policies, Abyss QUOTE/QUOTE_ORACLE or the UFG fixed/dynamic
41
+ presets. Approvals go to the proxy. The existing eleven launch cases and their
42
+ selected non-UFG offerings are intentionally unchanged.
43
+
44
+ The opt-in owned-fork regression is `test/integration/ufg-launch.fork.mjs`; see the
45
+ [lifecycle guide](../docs/launch-lifecycle.md#ufg-owned-fork-check).
46
+
33
47
  ## Deployed read-only discovery
34
48
 
35
49
  ```sh
@@ -0,0 +1,31 @@
1
+ // Pure configuration example; no RPC, wallet, key, signing or broadcast.
2
+ // This is not a priced/admitted plan. Use core.predictToken(plan) for real fee policies,
3
+ // derive funded one-sided positions, then prepareAndPlanLifecycleLaunch({ ..., ufg: { config } }).
4
+ import { encodeAbiParameters, keccak256, zeroHash } from "viem";
5
+ import {
6
+ getAddresses, KnownLifecycleProfile, getKnownLifecycleProfile,
7
+ UFG_ORCHESTRATOR_ADDRESS, UFG_LAUNCH_PROXY_ADDRESS, encodeUfgLaunchConfig,
8
+ hashUfgLaunchConfig, encodePoolBoundV4LifecycleMarketConfig,
9
+ } from "@black-market/sdk";
10
+
11
+ const identity = { chainId: 4663n, orchestrator: UFG_ORCHESTRATOR_ADDRESS };
12
+ const config = { treasuryShareBps: 10000, exitFeeBps: 100, reserveAssets: [getAddresses(4663).weth] };
13
+ for (const key of [KnownLifecycleProfile.V4UfgFixedPool, KnownLifecycleProfile.V4UfgDynamicPool]) {
14
+ const preset = getKnownLifecycleProfile({ ...identity, key })!;
15
+ const envelope = preset.profile.envelope!;
16
+ const encoded = encodePoolBoundV4LifecycleMarketConfig({
17
+ version: 6, lpFeePips: 0, tickSpacing: 60, sqrtPriceX96: 1n << 96n,
18
+ hookFeePips: 10000, minimumHookFeePips: 1000, feeSensitivityPipsSecondsPerTick: 7654321,
19
+ feeMode: 1, protocolFeeDenominator: envelope.protocolFeeDenominator,
20
+ treasury: envelope.protocolTreasury, externalLiquidityDisabled: false,
21
+ oracleConfigId: keccak256(encodeAbiParameters([{ type: "uint24" }, { type: "uint16" }], [1, 4096])),
22
+ hookSalt: zeroHash, profileId: preset.profile.id, termsDigest: envelope.termsDigest,
23
+ developerBeneficiary: envelope.beneficiary, developerFeeBps: 0,
24
+ // Geometry/price are illustrative. Real launch uses predicted token ordering and budget-funded ranges.
25
+ positions: [{ tickLower: 0, tickUpper: 887220, liquidity: 1000n, salt: zeroHash, maxTokenAmount: 1000000n }],
26
+ ufgLaunchConfig: config,
27
+ });
28
+ console.log(key, { proxy: UFG_LAUNCH_PROXY_ADDRESS, profileId: preset.profile.id,
29
+ configBytes: (encoded.length - 2) / 2, tailBytes: (encodeUfgLaunchConfig(config).length - 2) / 2,
30
+ launchConfigHash: hashUfgLaunchConfig(config) });
31
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@black-market/sdk",
3
- "version": "0.11.0",
3
+ "version": "0.12.0",
4
4
  "description": "TypeScript SDK for Abyss token launches, swaps, and lending.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -6,6 +6,7 @@ import {
6
6
  } from "./schema.js";
7
7
  import { poolBoundHookParametersV1Components, poolBoundHookParametersV2Components, v4LifecycleMarketComponents } from "./markets.js";
8
8
  export { hmmLiquidityManagerV2Abi, hmmFeeCollectorV2Abi, hmmFeeCollectorFactoryV2Abi, hmmFixedHookV2Abi, hmmDynamicHookV2Abi } from "./hmm-abi.js";
9
+ export { ufgLaunchProxyV1Abi, ufgTreasuryFactoryV1Abi, ufgBlackMarketFactoryAbi, ufgBlackMarketTreasuryAbi } from "./ufg-abi.js";
9
10
 
10
11
  const planInput = { name: "plan", type: "tuple", components: launchPlanV1Components } as const;
11
12
  export const launchLifecycleAbi = [
@@ -0,0 +1,74 @@
1
+ import type { LaunchEnvelopeV2, AdapterRegistrationV1, ProfileRegistrationV1, ProfileTopologyV1 } from "../schema.js";
2
+
3
+ // Generated by scripts/generate-ufg-presets.mjs from ufg-registry-readback.json.
4
+ // Robinhood block 94551140, 0x0778956b5a7bad65f8182b969ac4efc6a7182a0a922fbcb94dc87bfea26e9cc4. Creation code is byte-identical to the existing dynamic zero-royalty hook.
5
+ export const ufgDynamicEnvelope = Object.freeze({
6
+ artifactDigest: "0xd448a4117b78714cc4f96824356c6a90ec666449fde5c57e2b7bbe072f5e4a7a",
7
+ reviewManifestDigest: "0x0a3a0dfcae4fa51b2cccb2213e44800b7e3b74e681a66bc090f2e403a15b64b3",
8
+ configBoundsDigest: "0x72e0b2d542556d472a47f9c38b2c91079c72793af847dee77933f0eca203129d",
9
+ termsDigest: "0xbe3b09dc6d49fd548e76fed654b852039e8899e591ebacafc5e67f0692d0c699",
10
+ topology: 2,
11
+ configVersion: 6,
12
+ economicVersion: 3,
13
+ capabilities: 123n,
14
+ flags: 0n,
15
+ callbackFlags: 6908,
16
+ callbackMask: 16383,
17
+ protocolTreasury: "0x961981916AB6575C3af3eeCecbf6A3b7Fad7C9e1",
18
+ protocolFeeDenominator: 6,
19
+ beneficiary: "0x7cb44b8693b3C350A2BcD4b681aF85365aa27783",
20
+ maximumDeveloperFeeBps: 0,
21
+ bounds: Object.freeze({
22
+ minimumTickSpacing: 1,
23
+ maximumTickSpacing: 32767,
24
+ maximumPositions: 32,
25
+ maximumOracleCardinality: 4096,
26
+ feeModeFlags: 3,
27
+ }),
28
+ graph: Object.freeze({
29
+ manager: "0x8366a39CC670B4001A1121B8F6A443A643e40951",
30
+ hookRoot: "0x0000000000000000000000000000000000000000",
31
+ oracleFactory: "0xe7feF2BC860B25bbdEB6F6AB96d88bAAa77ddad7",
32
+ locker: "0xDa3bdeD722Bc45126752Ad6f28FAf27917D1a2fa",
33
+ collectorFactory: "0x46a8493b8f84E3Da412856Dd256263107e3873F2",
34
+ collectorDeployer: "0x50d6C10435dD928e426B8094FB944582c4FCa6f7",
35
+ hookDeployer: "0x435E0cb9b4C244edD5Bed40F9e39acdfcCd8d0f3",
36
+ coreCodeHash: "0x9fb8f46c3b980b9db25dfdb487a69a308a86be145860269b4036a4e74480787b",
37
+ managerCodeHash: "0xbd3881180b547f5fe817545743cfb4343e96b1bc6640dcd70c106b0066e95626",
38
+ hookRuntimeCodeHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
39
+ oracleFactoryCodeHash: "0x974fb5c72d91ccb99f1eb4679a5d4432c82bbaa0906b1c2917ec4da3499b7b98",
40
+ lockerCodeHash: "0x686024936a31a60193d2c6ea15ddb97ee36fc59a805eb1856cde61116075b370",
41
+ collectorFactoryCodeHash: "0xb0bd33507bebe1bb969153961237ee9a5661dd9ed60b9384a8869fa03ec5ed51",
42
+ collectorDeployerCodeHash: "0x79118bf755c242e2a190f9602c021e59ccc49d51eeff3b0c1524b4a53c25618d",
43
+ hookDeployerCodeHash: "0xe2a9753e6a8858b32443cd32b89c0ac9de95673a85611383d2a7bebc3b9d1187",
44
+ hookCreationCodeHash: "0xd448a4117b78714cc4f96824356c6a90ec666449fde5c57e2b7bbe072f5e4a7a",
45
+ codeChunk0: "0x550187621373bcece198E44EA31bE6b3936c699b",
46
+ codeChunk0Hash: "0x818c56bf10ae21129fe54f1b8991d6f807ce4ccef35b34c56251c1fd2d7d623f",
47
+ codeChunk1: "0x6C6c05e1C61c69C85548887e5E06384934AE7d71",
48
+ codeChunk1Hash: "0xbc73944bfa7e74df5968907a05fe2579a17ab155d3a0db407588d1baff51b4de",
49
+ sharedHookSalt: "0x0000000000000000000000000000000000000000000000000000000000000000",
50
+ }),
51
+ }) satisfies LaunchEnvelopeV2;
52
+ export const ufgDynamicAdapter = Object.freeze({
53
+ implementation: "0x38FAA8061c91BA6B2D3ef735f110017d12705067",
54
+ codeHash: "0xa13c2d0e05e0cc6a366f85ecbfab37ef26136e0993999bed4dd46538eabce23c",
55
+ capabilities: 123n,
56
+ configVersion: 6,
57
+ enabled: true,
58
+ }) satisfies AdapterRegistrationV1;
59
+ export const ufgDynamicRegistration = Object.freeze({
60
+ adapterId: "0xc0906e17625b48240a87a3afc6ee921b653bdacd72906a16b359d0776d938518",
61
+ configSchema: "0x51c5ca14c40012f78425cd1afb1ea77980da3fed0490a00911a8a4ed34792045",
62
+ dependencyDigest: "0x43078cffe54d685efc2c8e05243c50956569c98fd608861b6ed81f6ab1ad49b3",
63
+ venue: "0x8366a39CC670B4001A1121B8F6A443A643e40951",
64
+ factory: "0x0000000000000000000000000000000000000000",
65
+ hook: "0x0000000000000000000000000000000000000000",
66
+ capabilities: 123n,
67
+ enabled: true,
68
+ }) satisfies ProfileRegistrationV1;
69
+ export const ufgDynamicTopology = Object.freeze({
70
+ hookTopology: 2,
71
+ configVersion: 6,
72
+ hookDeployer: "0x435E0cb9b4C244edD5Bed40F9e39acdfcCd8d0f3",
73
+ hookCreationCodeHash: "0xd448a4117b78714cc4f96824356c6a90ec666449fde5c57e2b7bbe072f5e4a7a",
74
+ }) satisfies ProfileTopologyV1;
@@ -0,0 +1,74 @@
1
+ import type { LaunchEnvelopeV2, AdapterRegistrationV1, ProfileRegistrationV1, ProfileTopologyV1 } from "../schema.js";
2
+
3
+ // Generated by scripts/generate-ufg-presets.mjs from ufg-registry-readback.json.
4
+ // Robinhood block 94551140, 0x0778956b5a7bad65f8182b969ac4efc6a7182a0a922fbcb94dc87bfea26e9cc4. Creation code is byte-identical to the existing fixed zero-royalty hook.
5
+ export const ufgFixedEnvelope = Object.freeze({
6
+ artifactDigest: "0x11c4c7b1f265ed708b7d53ab828c89d237ca821333daa808f1913986c6f8f1ab",
7
+ reviewManifestDigest: "0x0a3a0dfcae4fa51b2cccb2213e44800b7e3b74e681a66bc090f2e403a15b64b3",
8
+ configBoundsDigest: "0x72e0b2d542556d472a47f9c38b2c91079c72793af847dee77933f0eca203129d",
9
+ termsDigest: "0xf2503b91eeec87f95c4f5e47df517a143422c766528c403ea44bdbd9b40df10e",
10
+ topology: 2,
11
+ configVersion: 6,
12
+ economicVersion: 3,
13
+ capabilities: 123n,
14
+ flags: 0n,
15
+ callbackFlags: 6908,
16
+ callbackMask: 16383,
17
+ protocolTreasury: "0x961981916AB6575C3af3eeCecbf6A3b7Fad7C9e1",
18
+ protocolFeeDenominator: 6,
19
+ beneficiary: "0x7cb44b8693b3C350A2BcD4b681aF85365aa27783",
20
+ maximumDeveloperFeeBps: 0,
21
+ bounds: Object.freeze({
22
+ minimumTickSpacing: 1,
23
+ maximumTickSpacing: 32767,
24
+ maximumPositions: 32,
25
+ maximumOracleCardinality: 4096,
26
+ feeModeFlags: 3,
27
+ }),
28
+ graph: Object.freeze({
29
+ manager: "0x8366a39CC670B4001A1121B8F6A443A643e40951",
30
+ hookRoot: "0x0000000000000000000000000000000000000000",
31
+ oracleFactory: "0xe7feF2BC860B25bbdEB6F6AB96d88bAAa77ddad7",
32
+ locker: "0xfbc0AbCD1A3EA65aF2196fa8Af1327a49B4C92FC",
33
+ collectorFactory: "0x46a8493b8f84E3Da412856Dd256263107e3873F2",
34
+ collectorDeployer: "0x50d6C10435dD928e426B8094FB944582c4FCa6f7",
35
+ hookDeployer: "0x4b04Ed1B02885DE905d8a14207EAC93F6AB231b2",
36
+ coreCodeHash: "0x9fb8f46c3b980b9db25dfdb487a69a308a86be145860269b4036a4e74480787b",
37
+ managerCodeHash: "0xbd3881180b547f5fe817545743cfb4343e96b1bc6640dcd70c106b0066e95626",
38
+ hookRuntimeCodeHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
39
+ oracleFactoryCodeHash: "0x974fb5c72d91ccb99f1eb4679a5d4432c82bbaa0906b1c2917ec4da3499b7b98",
40
+ lockerCodeHash: "0xa6fd4decc88671feb632d1871688a96582b46fd500b53f587d0fe18dad23fc2d",
41
+ collectorFactoryCodeHash: "0xb0bd33507bebe1bb969153961237ee9a5661dd9ed60b9384a8869fa03ec5ed51",
42
+ collectorDeployerCodeHash: "0x79118bf755c242e2a190f9602c021e59ccc49d51eeff3b0c1524b4a53c25618d",
43
+ hookDeployerCodeHash: "0xc97b52314cfc0225fcc0a901382898870e57394b318124956367d8fd3818506c",
44
+ hookCreationCodeHash: "0x11c4c7b1f265ed708b7d53ab828c89d237ca821333daa808f1913986c6f8f1ab",
45
+ codeChunk0: "0x94Fd6fB6E3db16Ef97c9bEEA229617b2Ec00c196",
46
+ codeChunk0Hash: "0xe5f56287276954b21f4211cabf2d9c251aae68836c5fa86ce68091ffccdee26b",
47
+ codeChunk1: "0x191F43334Ed2D7d154BF635E961BCb0e9848CB7c",
48
+ codeChunk1Hash: "0x76efd61e1a109a85140ce3473c43694a83f490eaac54d18673c17872a5262a47",
49
+ sharedHookSalt: "0x0000000000000000000000000000000000000000000000000000000000000000",
50
+ }),
51
+ }) satisfies LaunchEnvelopeV2;
52
+ export const ufgFixedAdapter = Object.freeze({
53
+ implementation: "0x3c7bb8541DBe2C8576E1000C4B6B803fDD36CA5d",
54
+ codeHash: "0x27079feaeb1a0ce8034588c46d15fead2a6407451d6f9e37059cade7c2df7610",
55
+ capabilities: 123n,
56
+ configVersion: 6,
57
+ enabled: true,
58
+ }) satisfies AdapterRegistrationV1;
59
+ export const ufgFixedRegistration = Object.freeze({
60
+ adapterId: "0x073a4d46af70a3d4f69641e4f9dcdc9d8c279cd443daff960bbdf65a3b5fc758",
61
+ configSchema: "0x51c5ca14c40012f78425cd1afb1ea77980da3fed0490a00911a8a4ed34792045",
62
+ dependencyDigest: "0xead7c65bd240844e961647f7cd059948afd384dfea490807f576325cad78aee0",
63
+ venue: "0x8366a39CC670B4001A1121B8F6A443A643e40951",
64
+ factory: "0x0000000000000000000000000000000000000000",
65
+ hook: "0x0000000000000000000000000000000000000000",
66
+ capabilities: 123n,
67
+ enabled: true,
68
+ }) satisfies ProfileRegistrationV1;
69
+ export const ufgFixedTopology = Object.freeze({
70
+ hookTopology: 2,
71
+ configVersion: 6,
72
+ hookDeployer: "0x4b04Ed1B02885DE905d8a14207EAC93F6AB231b2",
73
+ hookCreationCodeHash: "0x11c4c7b1f265ed708b7d53ab828c89d237ca821333daa808f1913986c6f8f1ab",
74
+ }) satisfies ProfileTopologyV1;
@@ -4,6 +4,7 @@ export * from "./types.js";
4
4
  export * from "./abi.js";
5
5
  export * from "./markets.js";
6
6
  export * from "./hmm.js";
7
+ export * from "./ufg.js";
7
8
  export * from "./progress.js";
8
9
  export * from "./fork.js";
9
10
  export * from "./authors.js";
@@ -2,6 +2,7 @@ import { concatHex, decodeAbiParameters, encodeAbiParameters, getAddress, hexToB
2
2
  import type { MarketConfigV1 } from "./schema.js";
3
3
  import { LifecyclePlanningError, type LifecycleProfile, type PoolBoundHookSaltProgress } from "./types.js";
4
4
  import { decodeHmmLaunchTail, encodeHmmLaunchTail, isHmmProfile, type HmmLaunchConfig } from "./hmm.js";
5
+ import { decodeUfgLaunchConfig, encodeUfgLaunchConfig, isUfgProfile, type UfgLaunchConfig } from "./ufg-config.js";
5
6
 
6
7
  export type V4LifecyclePositionConfig = {
7
8
  tickLower: number; tickUpper: number; liquidity: bigint; salt: Hex; maxTokenAmount: bigint;
@@ -44,6 +45,7 @@ export type V4PoolBoundLifecycleMarketConfigV5 = Omit<V4LifecycleMarketConfig, "
44
45
  export type V4PoolBoundLifecycleMarketConfigV6 = Omit<V4LifecycleMarketConfig, "version"> & {
45
46
  version: 6; minimumHookFeePips: number; feeSensitivityPipsSecondsPerTick: number; hookSalt: Hex;
46
47
  hmmLaunchConfig?: HmmLaunchConfig;
48
+ ufgLaunchConfig?: UfgLaunchConfig;
47
49
  };
48
50
  export type V4PoolBoundLifecycleMarketConfig = V4PoolBoundLifecycleMarketConfigV5 | V4PoolBoundLifecycleMarketConfigV6;
49
51
  export const V4_LIFECYCLE_CONFIG_SCHEMA = keccak256(stringToHex("(uint16,uint24,int24,uint160,uint24,uint8,uint8,address,bool,bytes32,bytes32,bytes32,address,uint16,(int24,int24,uint128,bytes32,uint256)[])"));
@@ -90,9 +92,16 @@ function assertV1HookFeeShape(config: object): void {
90
92
  }
91
93
  }
92
94
 
93
- /** HMM profile selection requires a typed tail and appends it automatically. */
95
+ /** Auxiliary launch profiles require their typed tail and append it automatically. */
94
96
  export function encodePoolBoundV4LifecycleMarketConfig(config: V4PoolBoundLifecycleMarketConfig): Hex {
95
97
  const prefix = encodePoolBoundV4Prefix(config);
98
+ if (isUfgProfile(config.profileId)) {
99
+ if (config.version !== 6 || config.ufgLaunchConfig === undefined) throw new LifecyclePlanningError("INVALID_UFG_CONFIG", "UFG profiles require config6 and an explicit ufgLaunchConfig");
100
+ if (config.hmmLaunchConfig !== undefined) throw new LifecyclePlanningError("INVALID_UFG_CONFIG", "UFG profiles cannot carry an HMM tail");
101
+ if (config.lpFeePips !== 0 || config.feeMode !== 1) throw new LifecyclePlanningError("INVALID_UFG_CONFIG", "UFG requires QuoteOnly feeMode 1 and zero LP fee");
102
+ return concatHex([prefix, encodeUfgLaunchConfig(config.ufgLaunchConfig)]);
103
+ }
104
+ if (config.version === 6 && config.ufgLaunchConfig !== undefined) throw new LifecyclePlanningError("INVALID_UFG_CONFIG", "A UFG launch tail requires a UFG profile");
96
105
  if (isHmmProfile(config.profileId)) {
97
106
  if (config.version !== 6 || config.hmmLaunchConfig === undefined) throw new LifecyclePlanningError("INVALID_HMM_CONFIG", "HMM profiles require config6 and an explicit hmmLaunchConfig");
98
107
  if (config.lpFeePips !== 0) throw new LifecyclePlanningError("INVALID_HOOK_FEES", "HMM profiles require zero LP fee");
@@ -126,6 +135,10 @@ export function decodePoolBoundV4LifecycleMarketConfig(encoded: Hex, expectedVer
126
135
  const prefixLength = encodePoolBoundV4Prefix(config).length;
127
136
  config.hmmLaunchConfig = decodeHmmLaunchTail(`0x${encoded.slice(prefixLength)}`);
128
137
  }
138
+ if (isUfgProfile(config.profileId)) {
139
+ if (config.version !== 6) throw new LifecyclePlanningError("INVALID_UFG_CONFIG", "UFG profiles require config6");
140
+ config.ufgLaunchConfig = decodeUfgLaunchConfig(`0x${encoded.slice(encodePoolBoundV4Prefix(config).length)}`);
141
+ }
129
142
  if (encodePoolBoundV4LifecycleMarketConfig(config).toLowerCase() !== encoded.toLowerCase()) throw new LifecyclePlanningError("INVALID_BOUND_MARKET", "Pool-bound config is not canonical for its explicit schema");
130
143
  return config;
131
144
  }
@@ -245,8 +258,8 @@ export function hashPoolBoundV4MarketCommitment(options: { chainId: bigint; core
245
258
  if (!isPoolBoundV4ConfigVersion(market.configVersion)) throw new LifecyclePlanningError("INVALID_BOUND_MARKET", "Pool-bound V4 market requires explicit config version 5 or 6");
246
259
  const config = decodePoolBoundV4LifecycleMarketConfig(market.config, market.configVersion);
247
260
  if (config.profileId.toLowerCase() !== market.profileId.toLowerCase()) throw new LifecyclePlanningError("INVALID_BOUND_MARKET", "Config profile differs from the committed market profile");
248
- // The collector factory commits the V6 prefix, not the auxiliary HMM tail.
249
- // The full plan commitment separately binds every byte of that tail.
261
+ // Collector factories commit only the V6 prefix, not auxiliary launch tails.
262
+ // The full plan commitment separately binds every byte of those tails.
250
263
  const configHash = keccak256(encodePoolBoundV4Prefix({ ...config, hookSalt: zeroHash }));
251
264
  return keccak256(encodeAbiParameters([
252
265
  { type: "bytes32" }, { type: "uint256" }, { type: "address" }, { type: "address" }, { type: "address" },