@black-market/sdk 0.11.0 → 0.13.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 (78) hide show
  1. package/README.md +96 -79
  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 +101 -46
  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 +3 -1
  30. package/dist/lifecycle/progress.d.ts.map +1 -1
  31. package/dist/lifecycle/progress.js +145 -59
  32. package/dist/lifecycle/progress.js.map +1 -1
  33. package/dist/lifecycle/rpc.d.ts +8 -2
  34. package/dist/lifecycle/rpc.d.ts.map +1 -1
  35. package/dist/lifecycle/rpc.js +165 -9
  36. package/dist/lifecycle/rpc.js.map +1 -1
  37. package/dist/lifecycle/simulation.d.ts +1 -1
  38. package/dist/lifecycle/simulation.d.ts.map +1 -1
  39. package/dist/lifecycle/simulation.js +15 -11
  40. package/dist/lifecycle/simulation.js.map +1 -1
  41. package/dist/lifecycle/types.d.ts +23 -1
  42. package/dist/lifecycle/types.d.ts.map +1 -1
  43. package/dist/lifecycle/types.js.map +1 -1
  44. package/dist/lifecycle/ufg-abi.d.ts +2386 -0
  45. package/dist/lifecycle/ufg-abi.d.ts.map +1 -0
  46. package/dist/lifecycle/ufg-abi.js +171 -0
  47. package/dist/lifecycle/ufg-abi.js.map +1 -0
  48. package/dist/lifecycle/ufg-config.d.ts +38 -0
  49. package/dist/lifecycle/ufg-config.d.ts.map +1 -0
  50. package/dist/lifecycle/ufg-config.js +75 -0
  51. package/dist/lifecycle/ufg-config.js.map +1 -0
  52. package/dist/lifecycle/ufg.d.ts +21 -0
  53. package/dist/lifecycle/ufg.d.ts.map +1 -0
  54. package/dist/lifecycle/ufg.js +98 -0
  55. package/dist/lifecycle/ufg.js.map +1 -0
  56. package/docs/launch-lifecycle.md +611 -1363
  57. package/docs/reference.md +332 -0
  58. package/examples/.env.example +3 -2
  59. package/examples/README.md +172 -539
  60. package/examples/launch-example-support.ts +11 -3
  61. package/examples/launch-example.ts +1 -1
  62. package/examples/launch-lifecycle-smoke.ts +1 -1
  63. package/examples/ufg-launch-config.ts +31 -0
  64. package/package.json +1 -1
  65. package/src/lifecycle/abi.ts +1 -0
  66. package/src/lifecycle/deployments/ufg-dynamic-pool-20261021.ts +74 -0
  67. package/src/lifecycle/deployments/ufg-fixed-pool-20261021.ts +74 -0
  68. package/src/lifecycle/index.ts +1 -0
  69. package/src/lifecycle/markets.ts +16 -3
  70. package/src/lifecycle/planner.ts +95 -45
  71. package/src/lifecycle/presets.ts +11 -4
  72. package/src/lifecycle/progress.ts +131 -51
  73. package/src/lifecycle/rpc.ts +158 -10
  74. package/src/lifecycle/simulation.ts +14 -10
  75. package/src/lifecycle/types.ts +15 -2
  76. package/src/lifecycle/ufg-abi.ts +173 -0
  77. package/src/lifecycle/ufg-config.ts +77 -0
  78. package/src/lifecycle/ufg.ts +86 -0
@@ -607,9 +607,7 @@ export function createLocalLaunchWallet({ privateKey, creator, chainId, orchestr
607
607
  if (request[field] < 0n) throw exampleError("INVALID_ENVELOPE", `${field} must be unsigned`);
608
608
  }
609
609
  }
610
- request.nonce = envelope.nonce === undefined
611
- ? exactNumber(await client.request({ method: "eth_getTransactionCount", params: [creator, "pending"] }), "nonce")
612
- : exactNumber(envelope.nonce, "nonce");
610
+ if (envelope.nonce !== undefined) request.nonce = exactNumber(envelope.nonce, "nonce");
613
611
  if (request.type !== undefined) {
614
612
  request.type = transactionTypes[request.type];
615
613
  if (!request.type) throw exampleError("INVALID_ENVELOPE", "Only legacy/EIP-2930/EIP-1559 envelopes are supported");
@@ -622,6 +620,16 @@ export function createLocalLaunchWallet({ privateKey, creator, chainId, orchestr
622
620
  request.maxFeePerGas ??= fees.maxFeePerGas;
623
621
  request.maxPriorityFeePerGas ??= fees.maxPriorityFeePerGas;
624
622
  }
623
+ const [nonceValue, balanceValue] = await Promise.all([
624
+ client.request({ method: "eth_getTransactionCount", params: [creator, "pending"] }),
625
+ client.request({ method: "eth_getBalance", params: [creator, "pending"] }),
626
+ ]);
627
+ const pendingNonce = exactNumber(nonceValue, "pending nonce");
628
+ if (request.nonce !== undefined && request.nonce !== pendingNonce) throw exampleError("PENDING_NONCE_CHANGED", "Pending account nonce differs from the exact reviewed envelope");
629
+ request.nonce = pendingNonce;
630
+ const maximumFee = request.gas * (request.gasPrice ?? request.maxFeePerGas);
631
+ if (BigInt(balanceValue) < request.value + maximumFee) throw exampleError("INSUFFICIENT_PENDING_BALANCE", "Pending balance cannot fund the exact transaction value and maximum gas envelope");
632
+ await assertChain();
625
633
  const rawTransaction = await account.signTransaction(request);
626
634
  redactor.addSecret(rawTransaction);
627
635
  const wire = { ...envelope, chainId: toHex(id), nonce: toHex(request.nonce) };
@@ -494,7 +494,7 @@ async function executePlan({ client, fixture, planned, sdk, artifacts, signal, l
494
494
  const next = await sdk.buildNextTransaction({ client, planned, receipts: references, limits, submissionClient: client, reviewedTransaction, signal });
495
495
  if (!next) return { references, activation };
496
496
  assert.ok(reviewedTransaction, "No transaction outside the saved review may be submitted");
497
- for (const field of ["id", "kind", "chainId", "from", "to", "data", "value", "gas", "gasPrice"]) assert.equal(next[field], reviewedTransaction[field], `Fresh ${field} must match the saved review`);
497
+ for (const field of ["id", "kind", "chainId", "from", "to", "data", "value", "nonce", "gas", "gasPrice"]) assert.equal(next[field], reviewedTransaction[field], `Fresh ${field} must match the saved review`);
498
498
  if (retainedReferences.length) {
499
499
  const progress = await sdk.readLaunchProgress({ client, planned, receipts: references, confirmations: planned.confirmations, signal });
500
500
  assertRetainedExampleReceipts({ progress, references, artifacts });
@@ -46,7 +46,7 @@ async function send(transaction) {
46
46
  const gasPrice = transaction.gasPrice ?? BigInt(await client.request({ method: "eth_gasPrice" }));
47
47
  const head = await client.request({ method: "eth_getBlockByNumber", params: ["latest", false] });
48
48
  const ceiling = [BigInt(head.gasLimit), BigInt(policy.chainTransactionGasLimit), BigInt(policy.rpcTransactionGasLimit), BigInt(policy.accountTransactionGasLimit)].reduce((a, b) => a < b ? a : b);
49
- const wire = { from: transaction.from, to: transaction.to, data: transaction.data, value: toHex(transaction.value), gasPrice: toHex(gasPrice) };
49
+ const wire = { from: transaction.from, to: transaction.to, data: transaction.data, value: toHex(transaction.value), gasPrice: toHex(gasPrice), ...(transaction.nonce === undefined ? {} : { nonce: toHex(transaction.nonce) }) };
50
50
  const estimated = transaction.gas ?? ((BigInt(await client.request({ method: "eth_estimateGas", params: [{ ...wire, gas: toHex(ceiling) }] })) * BigInt(10000 + Number(policy.headroomBps)) + 9999n) / 10000n);
51
51
  assert.ok(estimated <= ceiling, "Unsigned helper must still fit explicit local execution admission");
52
52
  const transactionHash = await client.request({ method: "eth_sendTransaction", params: [{ ...wire, gas: toHex(estimated) }] });
@@ -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.13.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" },