@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.
- package/README.md +17 -0
- package/dist/lifecycle/abi.d.ts +1 -0
- package/dist/lifecycle/abi.d.ts.map +1 -1
- package/dist/lifecycle/abi.js +1 -0
- package/dist/lifecycle/abi.js.map +1 -1
- package/dist/lifecycle/deployments/ufg-dynamic-pool-20261021.d.ts +71 -0
- package/dist/lifecycle/deployments/ufg-dynamic-pool-20261021.d.ts.map +1 -0
- package/dist/lifecycle/deployments/ufg-dynamic-pool-20261021.js +73 -0
- package/dist/lifecycle/deployments/ufg-dynamic-pool-20261021.js.map +1 -0
- package/dist/lifecycle/deployments/ufg-fixed-pool-20261021.d.ts +71 -0
- package/dist/lifecycle/deployments/ufg-fixed-pool-20261021.d.ts.map +1 -0
- package/dist/lifecycle/deployments/ufg-fixed-pool-20261021.js +73 -0
- package/dist/lifecycle/deployments/ufg-fixed-pool-20261021.js.map +1 -0
- package/dist/lifecycle/index.d.ts +1 -0
- package/dist/lifecycle/index.d.ts.map +1 -1
- package/dist/lifecycle/index.js +1 -0
- package/dist/lifecycle/index.js.map +1 -1
- package/dist/lifecycle/markets.d.ts +3 -1
- package/dist/lifecycle/markets.d.ts.map +1 -1
- package/dist/lifecycle/markets.js +20 -3
- package/dist/lifecycle/markets.js.map +1 -1
- package/dist/lifecycle/planner.d.ts.map +1 -1
- package/dist/lifecycle/planner.js +42 -22
- package/dist/lifecycle/planner.js.map +1 -1
- package/dist/lifecycle/presets.d.ts +4 -2
- package/dist/lifecycle/presets.d.ts.map +1 -1
- package/dist/lifecycle/presets.js +11 -4
- package/dist/lifecycle/presets.js.map +1 -1
- package/dist/lifecycle/progress.d.ts.map +1 -1
- package/dist/lifecycle/progress.js +26 -5
- package/dist/lifecycle/progress.js.map +1 -1
- package/dist/lifecycle/simulation.d.ts.map +1 -1
- package/dist/lifecycle/simulation.js +4 -1
- package/dist/lifecycle/simulation.js.map +1 -1
- package/dist/lifecycle/types.d.ts +11 -1
- package/dist/lifecycle/types.d.ts.map +1 -1
- package/dist/lifecycle/types.js.map +1 -1
- package/dist/lifecycle/ufg-abi.d.ts +2386 -0
- package/dist/lifecycle/ufg-abi.d.ts.map +1 -0
- package/dist/lifecycle/ufg-abi.js +171 -0
- package/dist/lifecycle/ufg-abi.js.map +1 -0
- package/dist/lifecycle/ufg-config.d.ts +38 -0
- package/dist/lifecycle/ufg-config.d.ts.map +1 -0
- package/dist/lifecycle/ufg-config.js +75 -0
- package/dist/lifecycle/ufg-config.js.map +1 -0
- package/dist/lifecycle/ufg.d.ts +21 -0
- package/dist/lifecycle/ufg.d.ts.map +1 -0
- package/dist/lifecycle/ufg.js +98 -0
- package/dist/lifecycle/ufg.js.map +1 -0
- package/docs/launch-lifecycle.md +138 -0
- package/examples/README.md +16 -2
- package/examples/ufg-launch-config.ts +31 -0
- package/package.json +1 -1
- package/src/lifecycle/abi.ts +1 -0
- package/src/lifecycle/deployments/ufg-dynamic-pool-20261021.ts +74 -0
- package/src/lifecycle/deployments/ufg-fixed-pool-20261021.ts +74 -0
- package/src/lifecycle/index.ts +1 -0
- package/src/lifecycle/markets.ts +16 -3
- package/src/lifecycle/planner.ts +37 -22
- package/src/lifecycle/presets.ts +11 -4
- package/src/lifecycle/progress.ts +22 -5
- package/src/lifecycle/simulation.ts +3 -1
- package/src/lifecycle/types.ts +6 -1
- package/src/lifecycle/ufg-abi.ts +173 -0
- package/src/lifecycle/ufg-config.ts +77 -0
- 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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"}
|
package/docs/launch-lifecycle.md
CHANGED
|
@@ -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:
|
package/examples/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Examples
|
|
2
2
|
|
|
3
|
-
The launch examples use the public `@black-market/sdk` 0.
|
|
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.
|
|
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
package/src/lifecycle/abi.ts
CHANGED
|
@@ -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;
|
package/src/lifecycle/index.ts
CHANGED
package/src/lifecycle/markets.ts
CHANGED
|
@@ -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
|
-
/**
|
|
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
|
-
//
|
|
249
|
-
// The full plan commitment separately binds every byte of
|
|
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" },
|