@black-market/sdk 0.16.1 → 0.17.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 (62) hide show
  1. package/README.md +5 -4
  2. package/dist/lifecycle/deployments/rwa-dynamic-pool-v1-20261113.d.ts +71 -0
  3. package/dist/lifecycle/deployments/rwa-dynamic-pool-v1-20261113.d.ts.map +1 -0
  4. package/dist/lifecycle/deployments/rwa-dynamic-pool-v1-20261113.js +73 -0
  5. package/dist/lifecycle/deployments/rwa-dynamic-pool-v1-20261113.js.map +1 -0
  6. package/dist/lifecycle/deployments/rwa-fixed-pool-v1-20261113.d.ts +71 -0
  7. package/dist/lifecycle/deployments/rwa-fixed-pool-v1-20261113.d.ts.map +1 -0
  8. package/dist/lifecycle/deployments/rwa-fixed-pool-v1-20261113.js +73 -0
  9. package/dist/lifecycle/deployments/rwa-fixed-pool-v1-20261113.js.map +1 -0
  10. package/dist/lifecycle/gas-profile.d.ts +1 -1
  11. package/dist/lifecycle/gas-profile.d.ts.map +1 -1
  12. package/dist/lifecycle/gas-profile.js +17 -6
  13. package/dist/lifecycle/gas-profile.js.map +1 -1
  14. package/dist/lifecycle/index.d.ts +2 -0
  15. package/dist/lifecycle/index.d.ts.map +1 -1
  16. package/dist/lifecycle/index.js +2 -0
  17. package/dist/lifecycle/index.js.map +1 -1
  18. package/dist/lifecycle/markets.d.ts +2 -0
  19. package/dist/lifecycle/markets.d.ts.map +1 -1
  20. package/dist/lifecycle/markets.js +32 -4
  21. package/dist/lifecycle/markets.js.map +1 -1
  22. package/dist/lifecycle/opening-buys.js +1 -1
  23. package/dist/lifecycle/opening-buys.js.map +1 -1
  24. package/dist/lifecycle/planner.d.ts.map +1 -1
  25. package/dist/lifecycle/planner.js +5 -1
  26. package/dist/lifecycle/planner.js.map +1 -1
  27. package/dist/lifecycle/presets.d.ts +4 -2
  28. package/dist/lifecycle/presets.d.ts.map +1 -1
  29. package/dist/lifecycle/presets.js +8 -1
  30. package/dist/lifecycle/presets.js.map +1 -1
  31. package/dist/lifecycle/raeto-abi.d.ts +29 -0
  32. package/dist/lifecycle/raeto-abi.d.ts.map +1 -1
  33. package/dist/lifecycle/raeto-abi.js +40 -1
  34. package/dist/lifecycle/raeto-abi.js.map +1 -1
  35. package/dist/lifecycle/rwa-abi.d.ts +752 -0
  36. package/dist/lifecycle/rwa-abi.d.ts.map +1 -0
  37. package/dist/lifecycle/rwa-abi.js +968 -0
  38. package/dist/lifecycle/rwa-abi.js.map +1 -0
  39. package/dist/lifecycle/rwa.d.ts +42 -0
  40. package/dist/lifecycle/rwa.d.ts.map +1 -0
  41. package/dist/lifecycle/rwa.js +113 -0
  42. package/dist/lifecycle/rwa.js.map +1 -0
  43. package/dist/lifecycle/transactions.d.ts.map +1 -1
  44. package/dist/lifecycle/transactions.js +11 -3
  45. package/dist/lifecycle/transactions.js.map +1 -1
  46. package/docs/launch-lifecycle.md +81 -1
  47. package/docs/lifecycle-gas-profiles.md +60 -3
  48. package/docs/reference.md +61 -0
  49. package/examples/README.md +2 -2
  50. package/package.json +1 -1
  51. package/src/lifecycle/deployments/rwa-dynamic-pool-v1-20261113.ts +74 -0
  52. package/src/lifecycle/deployments/rwa-fixed-pool-v1-20261113.ts +74 -0
  53. package/src/lifecycle/gas-profile.ts +17 -7
  54. package/src/lifecycle/index.ts +2 -0
  55. package/src/lifecycle/markets.ts +24 -2
  56. package/src/lifecycle/opening-buys.ts +1 -1
  57. package/src/lifecycle/planner.ts +6 -1
  58. package/src/lifecycle/presets.ts +8 -1
  59. package/src/lifecycle/raeto-abi.ts +41 -1
  60. package/src/lifecycle/rwa-abi.ts +968 -0
  61. package/src/lifecycle/rwa.ts +119 -0
  62. package/src/lifecycle/transactions.ts +9 -2
@@ -0,0 +1,74 @@
1
+ import type { LaunchEnvelopeV2, AdapterRegistrationV1, ProfileRegistrationV1, ProfileTopologyV1 } from "../schema.js";
2
+
3
+ // Generated by scripts/generate-rwa-presets.mjs from admission and registry readback.
4
+ // Robinhood block 113693643, 0xea409fea2955aa229e8b1bff0e63d4ffb88c8eba0f85bd8553d9e6479e545461; admission 0xce4c0d0ad3e25f2f82abfc3e28bf6aedbe7da8282360d07beb131d62b641a592.
5
+ export const rwaDynamicEnvelope = Object.freeze({
6
+ artifactDigest: "0xd448a4117b78714cc4f96824356c6a90ec666449fde5c57e2b7bbe072f5e4a7a",
7
+ reviewManifestDigest: "0x03eacc82d31be9528ea12eee454bfa995a021bbfaa67612fc78a5a49dc98ce58",
8
+ configBoundsDigest: "0x11ec57e16f972e0ac5f687d4078d785a51de11d421bcf97e2ba129dfd83fe7b4",
9
+ termsDigest: "0xa8646837c15c4f01f34543b3783685fcc2a844bd738dd667161ea25149168dee",
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: 2,
27
+ }),
28
+ graph: Object.freeze({
29
+ manager: "0x8366a39CC670B4001A1121B8F6A443A643e40951",
30
+ hookRoot: "0x0000000000000000000000000000000000000000",
31
+ oracleFactory: "0xe7feF2BC860B25bbdEB6F6AB96d88bAAa77ddad7",
32
+ locker: "0xFFF8409ce0D9030ea30aB9B0C027B5fA0114a949",
33
+ collectorFactory: "0x7F999EB2127dD6C4702cBb716518EFFFb318d7d0",
34
+ collectorDeployer: "0x4B60a9D76c9184CC519CA3C5e3A371705b93a329",
35
+ hookDeployer: "0xCb4bCaEF4816F75EFa547a9F0F94d6116819848B",
36
+ coreCodeHash: "0x9fb8f46c3b980b9db25dfdb487a69a308a86be145860269b4036a4e74480787b",
37
+ managerCodeHash: "0xbd3881180b547f5fe817545743cfb4343e96b1bc6640dcd70c106b0066e95626",
38
+ hookRuntimeCodeHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
39
+ oracleFactoryCodeHash: "0x974fb5c72d91ccb99f1eb4679a5d4432c82bbaa0906b1c2917ec4da3499b7b98",
40
+ lockerCodeHash: "0xe28dd3f6a99881b729ca294651a0c4c3dce1be485cec91add74ee4210fc7c7df",
41
+ collectorFactoryCodeHash: "0x73528940f83090464994ad6eb64f656c9b324204674b3408410d644b327299a2",
42
+ collectorDeployerCodeHash: "0x8a8a564ddea793e4be2fa135d85876dbe2461ca574841f3008e73de3c6ea9c97",
43
+ hookDeployerCodeHash: "0x1a4beb855873bf7d1da0d403741e1bf2fc6dfc7f26dd9893b58875c2a1dcba35",
44
+ hookCreationCodeHash: "0xd448a4117b78714cc4f96824356c6a90ec666449fde5c57e2b7bbe072f5e4a7a",
45
+ codeChunk0: "0x27BB9608aE394623bD23490367CaC137443c890c",
46
+ codeChunk0Hash: "0x818c56bf10ae21129fe54f1b8991d6f807ce4ccef35b34c56251c1fd2d7d623f",
47
+ codeChunk1: "0xD99b86Ab8CB65D49A6cE93ab8b1ebedeF513634E",
48
+ codeChunk1Hash: "0xbc73944bfa7e74df5968907a05fe2579a17ab155d3a0db407588d1baff51b4de",
49
+ sharedHookSalt: "0x0000000000000000000000000000000000000000000000000000000000000000",
50
+ }),
51
+ }) satisfies LaunchEnvelopeV2;
52
+ export const rwaDynamicAdapter = Object.freeze({
53
+ implementation: "0xF06a5EC32F0Bba89e4cA16E8AeCd56c9f125A157",
54
+ codeHash: "0xae6db24fa7ca9ed3bf65a2eb99e4c3c10f0564d801b73d9591bc5859752a3be1",
55
+ capabilities: 123n,
56
+ configVersion: 6,
57
+ enabled: true,
58
+ }) satisfies AdapterRegistrationV1;
59
+ export const rwaDynamicRegistration = Object.freeze({
60
+ adapterId: "0x46a5f7c611f6584cc99cffcdeb55183d6c3dcafe5fc6fcce85995be82639bbe1",
61
+ configSchema: "0x51c5ca14c40012f78425cd1afb1ea77980da3fed0490a00911a8a4ed34792045",
62
+ dependencyDigest: "0x6b0ef655a4eb9f8b81920ae63cd71bc26f320c5f819a4385534a3264ea152d2e",
63
+ venue: "0x8366a39CC670B4001A1121B8F6A443A643e40951",
64
+ factory: "0x0000000000000000000000000000000000000000",
65
+ hook: "0x0000000000000000000000000000000000000000",
66
+ capabilities: 123n,
67
+ enabled: true,
68
+ }) satisfies ProfileRegistrationV1;
69
+ export const rwaDynamicTopology = Object.freeze({
70
+ hookTopology: 2,
71
+ configVersion: 6,
72
+ hookDeployer: "0xCb4bCaEF4816F75EFa547a9F0F94d6116819848B",
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-rwa-presets.mjs from admission and registry readback.
4
+ // Robinhood block 113693643, 0xea409fea2955aa229e8b1bff0e63d4ffb88c8eba0f85bd8553d9e6479e545461; admission 0xeea3456cd41b8b86dd17bbace3dfd9d96c04212beb5e1c7f421602176930cb17.
5
+ export const rwaFixedEnvelope = Object.freeze({
6
+ artifactDigest: "0x11c4c7b1f265ed708b7d53ab828c89d237ca821333daa808f1913986c6f8f1ab",
7
+ reviewManifestDigest: "0x42e315ab29ad2507b1decb69246efa24a63c29c7afb900283037b78b4c5d28f5",
8
+ configBoundsDigest: "0x11ec57e16f972e0ac5f687d4078d785a51de11d421bcf97e2ba129dfd83fe7b4",
9
+ termsDigest: "0x8523375098878c66e6289b908069c0d0152897876a73a80a7c7696679341be64",
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: 2,
27
+ }),
28
+ graph: Object.freeze({
29
+ manager: "0x8366a39CC670B4001A1121B8F6A443A643e40951",
30
+ hookRoot: "0x0000000000000000000000000000000000000000",
31
+ oracleFactory: "0xe7feF2BC860B25bbdEB6F6AB96d88bAAa77ddad7",
32
+ locker: "0x5249CA601E8E695eFECf9375AaFA531141d7e2f0",
33
+ collectorFactory: "0x5A34F50e945220774b3210E05C0c3a3f6132955d",
34
+ collectorDeployer: "0x9488807200eba120d242f328374e1aA9A17bb185",
35
+ hookDeployer: "0x6ADeaa3d9fa1e3a5F04D2c0DeB21Bf438ce9Af9A",
36
+ coreCodeHash: "0x9fb8f46c3b980b9db25dfdb487a69a308a86be145860269b4036a4e74480787b",
37
+ managerCodeHash: "0xbd3881180b547f5fe817545743cfb4343e96b1bc6640dcd70c106b0066e95626",
38
+ hookRuntimeCodeHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
39
+ oracleFactoryCodeHash: "0x974fb5c72d91ccb99f1eb4679a5d4432c82bbaa0906b1c2917ec4da3499b7b98",
40
+ lockerCodeHash: "0x9953bb0c86f09018368fcc2f019d08466370ce4f078cd48d38a2ac7e42c0eafd",
41
+ collectorFactoryCodeHash: "0x7b8708516701f1344d62cab07ab15d6eedc8266bb9506efd67a57d93576bf6aa",
42
+ collectorDeployerCodeHash: "0x8a8a564ddea793e4be2fa135d85876dbe2461ca574841f3008e73de3c6ea9c97",
43
+ hookDeployerCodeHash: "0x6622a5805ebfd327d6bd26f5466da8fced080fdb8b34811f431db538e56155af",
44
+ hookCreationCodeHash: "0x11c4c7b1f265ed708b7d53ab828c89d237ca821333daa808f1913986c6f8f1ab",
45
+ codeChunk0: "0xaBeaf6bF6DFF808eea159B7020Ca598A8765d8f7",
46
+ codeChunk0Hash: "0xe5f56287276954b21f4211cabf2d9c251aae68836c5fa86ce68091ffccdee26b",
47
+ codeChunk1: "0xE351513eA18691dA1aa62aD4eEA5596806461F17",
48
+ codeChunk1Hash: "0x76efd61e1a109a85140ce3473c43694a83f490eaac54d18673c17872a5262a47",
49
+ sharedHookSalt: "0x0000000000000000000000000000000000000000000000000000000000000000",
50
+ }),
51
+ }) satisfies LaunchEnvelopeV2;
52
+ export const rwaFixedAdapter = Object.freeze({
53
+ implementation: "0x56BF798a2eA3935E2f16ABC48d2E20D7b156800e",
54
+ codeHash: "0xf2d2e4c8d3272de1159811eabd17ba126a1a25cbee5cf9b64b4c299e67b43095",
55
+ capabilities: 123n,
56
+ configVersion: 6,
57
+ enabled: true,
58
+ }) satisfies AdapterRegistrationV1;
59
+ export const rwaFixedRegistration = Object.freeze({
60
+ adapterId: "0x0f13f4a8553a4dece69888deb425b04ff169d41132f3e2097034aff00f584dd6",
61
+ configSchema: "0x51c5ca14c40012f78425cd1afb1ea77980da3fed0490a00911a8a4ed34792045",
62
+ dependencyDigest: "0x5fce23ef64a1f6c510a299f9abdeb8ab686bb9e994bc1e607b15cd68acda3554",
63
+ venue: "0x8366a39CC670B4001A1121B8F6A443A643e40951",
64
+ factory: "0x0000000000000000000000000000000000000000",
65
+ hook: "0x0000000000000000000000000000000000000000",
66
+ capabilities: 123n,
67
+ enabled: true,
68
+ }) satisfies ProfileRegistrationV1;
69
+ export const rwaFixedTopology = Object.freeze({
70
+ hookTopology: 2,
71
+ configVersion: 6,
72
+ hookDeployer: "0x6ADeaa3d9fa1e3a5F04D2c0DeB21Bf438ce9Af9A",
73
+ hookCreationCodeHash: "0x11c4c7b1f265ed708b7d53ab828c89d237ca821333daa808f1913986c6f8f1ab",
74
+ }) satisfies ProfileTopologyV1;
@@ -10,18 +10,19 @@ import { UFG_LAUNCH_PROXY_ADDRESS, isUfgProfile, ufgPlanPrincipal, type UfgLaunc
10
10
  import { LifecyclePlanningError, type LifecycleBlock, type LifecycleLaunchGasBounds, type LifecycleLimitSource, type LifecycleOpeningBuyQuote, type LifecyclePlanningAssessment, type LifecycleRpcClient, type LifecycleTransaction, type PlannedLaunch } from "./types.js";
11
11
  import { isHmmProfile } from "./hmm.js";
12
12
  import { isRaetoProfile } from "./raeto.js";
13
+ import { isRwaProfile } from "./rwa.js";
13
14
 
14
- export const LIFECYCLE_GAS_PROFILE_VERSION = "robinhood-4663-capacity-v5";
15
+ export const LIFECYCLE_GAS_PROFILE_VERSION = "robinhood-4663-capacity-v6";
15
16
  export type NextTransactionEnvelope = Readonly<{ gas: bigint; gasPrice: bigint }>;
16
17
  const ceil = (value: bigint, divisor: bigint) => (value + divisor - 1n) / divisor;
17
18
  const approval = (transaction: LifecycleTransaction) => transaction.kind === "approve" || transaction.kind === "approve-reset";
18
- type MarketGas = { abyss: boolean; hmm: boolean; ufgHook: boolean; raeto: boolean; autoCompound: boolean; positions: number };
19
+ type MarketGas = { abyss: boolean; hmm: boolean; ufgHook: boolean; raeto: boolean; rwa: boolean; autoCompound: boolean; positions: number };
19
20
 
20
21
  function marketGas(plan: LaunchPlanV1): MarketGas[] {
21
22
  return plan.markets.map((market) => {
22
23
  const abyss = market.configVersion === 1;
23
24
  const config = abyss ? decodeAbyssLifecycleMarketConfig(market.config) : decodePoolBoundV4LifecycleMarketConfig(market.config, 6);
24
- return { abyss, hmm: isHmmProfile(market.profileId), ufgHook: isUfgProfile(market.profileId), raeto: isRaetoProfile(market.profileId), autoCompound: isAutoCompoundProfile(market.profileId), positions: config.positions.length };
25
+ return { abyss, hmm: isHmmProfile(market.profileId), ufgHook: isUfgProfile(market.profileId), raeto: isRaetoProfile(market.profileId), rwa: isRwaProfile(market.profileId), autoCompound: isAutoCompoundProfile(market.profileId), positions: config.positions.length };
25
26
  });
26
27
  }
27
28
 
@@ -53,6 +54,9 @@ const activationCosts = {
53
54
  abyss: { market: 500_000n, position: 1_250_000n },
54
55
  v4: { market: 250_000n, position: 500_000n },
55
56
  raeto: { market: 500_000n, position: 500_000n },
57
+ // template-gas-rwa-matrix.json: six-stock RWA activation marginal is ~0.54M/position; the
58
+ // 32-position four-buy activation (24.43M) still fits 32M, so its bound must stay below it.
59
+ rwa: { market: 250_000n, position: 540_000n },
56
60
  autoCompound: { market: 750_000n, position: 500_000n },
57
61
  hmm: 1_000_000n,
58
62
  ufg: 250_000n,
@@ -68,25 +72,31 @@ function capacityBasis(plan: LaunchPlanV1, transaction: LifecycleTransaction, ma
68
72
  // template-gas-matrix.json: Raeto/auto-compound atomic1 <=19.60M,
69
73
  // atomic8 <=23.99M; atomic32 exceeds32M. The18M calibration base plus
70
74
  // position/buy work and25% padding bounds compute and forwarding envelopes.
71
- let gas = atomic ? (markets[0]!.raeto || markets[0]!.autoCompound ? 18_000_000n : 22_000_000n) + tokenCreationGas(plan.token) + (ufgRoute ? 6_500_000n : 0n)
75
+ // template-gas-rwa-matrix.json: RWA atomic1 <=22.79M, atomic8 four buys <=27.39M
76
+ // (still within 32M), so its tighter 17M base keeps that observed fit plannable.
77
+ const first = markets[0]!;
78
+ let gas = atomic ? (first.rwa ? 17_000_000n : first.raeto || first.autoCompound ? 18_000_000n : 22_000_000n) + tokenCreationGas(plan.token) + (ufgRoute ? 6_500_000n : 0n)
72
79
  : activationCosts.call + (ufgRoute ? activationCosts.ufg : 0n);
73
80
  // Escrow executes each Swap during begin, including within atomic. This
74
81
  // empirical2M reserve is padded below, not a proof for arbitrary router code.
75
82
  if (atomic) for (const funding of plan.funding) if (funding.kind === LifecycleFundingKind.Swap) gas += 2_000_000n;
76
83
  for (const market of markets) {
77
84
  if (atomic) gas += (market.hmm ? 7_000_000n : market.ufgHook ? 1_000_000n : market.abyss ? 500_000n : 0n) +
78
- (market.abyss ? 1_500_000n : 600_000n) * BigInt(market.positions - 1);
85
+ (market.abyss ? 1_500_000n : market.rwa ? 550_000n : 600_000n) * BigInt(market.positions - 1);
79
86
  else {
80
- const cost = market.abyss ? activationCosts.abyss : market.raeto ? activationCosts.raeto : market.autoCompound ? activationCosts.autoCompound : activationCosts.v4;
87
+ const cost = market.abyss ? activationCosts.abyss : market.raeto ? activationCosts.raeto : market.rwa ? activationCosts.rwa : market.autoCompound ? activationCosts.autoCompound : activationCosts.v4;
81
88
  gas += cost.market + cost.position * BigInt(market.positions) + (market.hmm ? activationCosts.hmm : market.ufgHook ? activationCosts.ufg : 0n);
82
89
  }
83
90
  }
84
91
  gas += activationCosts.buy * BigInt(quotes.length);
85
92
  // These collectors revalidate the prepared position set for each buy. At32
86
93
  // positions the measured marginal exceeds1M/buy; flat0.5M is insufficient.
94
+ // RWA buys use ~0.66M at one position and ~1.25M at 32 (forwarding estimate
95
+ // ~1.7M/buy), so a flat part covers small shapes and a smaller position term large ones.
87
96
  for (const quote of quotes) {
88
97
  const market = markets[quote.marketIndex]!;
89
- if (market.raeto || market.autoCompound) gas += 25_000n * BigInt(market.positions);
98
+ if (market.rwa) gas += 150_000n + 20_000n * BigInt(market.positions);
99
+ else if (market.raeto || market.autoCompound) gas += 25_000n * BigInt(market.positions);
90
100
  }
91
101
  if (plan.token.kind === LifecycleTokenKind.ERC404) for (const quote of quotes) gas += activationCosts.nft * ceil(quote.tokenOut, plan.token.nftUnit);
92
102
  return gas + 24n * BigInt((transaction.data.length - 2) / 2) + 100_000n * BigInt(plan.feeAssets.length);
@@ -8,6 +8,8 @@ export * from "./ufg.js";
8
8
  export * from "./auto-compound.js";
9
9
  export * from "./raeto.js";
10
10
  export * from "./raeto-abi.js";
11
+ export * from "./rwa.js";
12
+ export * from "./rwa-abi.js";
11
13
  export { ABYSS_LIFECYCLE_CONFIG_SCHEMA, readLifecycleTokenAtBlock, readLifecycleHeadProgress, predictLifecycleToken,
12
14
  validateV4LifecycleOracle, readLifecycleProfiles, readPoolBoundHookDeployment,
13
15
  buildPoolBoundHookDeploymentTransaction, validateLifecycleMarketIdentity, readLaunchProgress } from "./progress.js";
@@ -5,6 +5,7 @@ import { decodeHmmLaunchTail, encodeHmmLaunchTail, isHmmProfile, type HmmLaunchC
5
5
  import { decodeUfgLaunchConfig, encodeUfgLaunchConfig, isUfgProfile, type UfgLaunchConfig } from "./ufg-config.js";
6
6
  import { decodeAutoCompoundTail, encodeAutoCompoundTail, isAutoCompoundProfile, validateAutoCompoundConfig, type AutoCompoundConfigV1 } from "./auto-compound.js";
7
7
  import { decodeRaetoLaunchTail, encodeRaetoLaunchTail, isRaetoProfile, RAETO_QUOTE_ASSETS, validateRaetoLaunchConfig, type RaetoLaunchConfigV1 } from "./raeto.js";
8
+ import { decodeRwaLaunchTail, encodeRwaLaunchTail, isRwaProfile, RWA_QUOTE_ASSET, validateRwaLaunchConfig, type RwaLaunchConfigV1 } from "./rwa.js";
8
9
 
9
10
  export type V4LifecyclePositionConfig = {
10
11
  tickLower: number; tickUpper: number; liquidity: bigint; salt: Hex; maxTokenAmount: bigint;
@@ -50,6 +51,7 @@ export type V4PoolBoundLifecycleMarketConfigV6 = Omit<V4LifecycleMarketConfig, "
50
51
  ufgLaunchConfig?: UfgLaunchConfig;
51
52
  autoCompoundConfig?: AutoCompoundConfigV1;
52
53
  raetoLaunchConfig?: RaetoLaunchConfigV1;
54
+ rwaLaunchConfig?: RwaLaunchConfigV1;
53
55
  };
54
56
  export type V4PoolBoundLifecycleMarketConfig = V4PoolBoundLifecycleMarketConfigV5 | V4PoolBoundLifecycleMarketConfigV6;
55
57
  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)[])"));
@@ -98,7 +100,7 @@ function assertV1HookFeeShape(config: object): void {
98
100
 
99
101
  function validateAutoCompoundMarket(config: V4LifecycleMarketConfig | V4PoolBoundLifecycleMarketConfig): asserts config is V4PoolBoundLifecycleMarketConfigV6 & { autoCompoundConfig: AutoCompoundConfigV1 } {
100
102
  if (config.version !== 6 || config.autoCompoundConfig === undefined) throw new LifecyclePlanningError("INVALID_AUTO_COMPOUND_CONFIG", "Auto-compounding profiles require config6 and an explicit autoCompoundConfig");
101
- if (config.hmmLaunchConfig !== undefined || config.ufgLaunchConfig !== undefined || config.raetoLaunchConfig !== undefined) throw new LifecyclePlanningError("INVALID_AUTO_COMPOUND_CONFIG", "Auto-compounding profiles cannot carry HMM, UFG or Raeto tails");
103
+ if (config.hmmLaunchConfig !== undefined || config.ufgLaunchConfig !== undefined || config.raetoLaunchConfig !== undefined || config.rwaLaunchConfig !== undefined) throw new LifecyclePlanningError("INVALID_AUTO_COMPOUND_CONFIG", "Auto-compounding profiles cannot carry HMM, UFG, Raeto or RWA tails");
102
104
  if (config.lpFeePips !== 0) throw new LifecyclePlanningError("INVALID_HOOK_FEES", "Auto-compounding profiles require zero LP fee");
103
105
  if (config.developerFeeBps !== 0) throw new LifecyclePlanningError("DEVELOPER_FEE_CEILING", "Auto-compounding profiles require zero developer fee");
104
106
  validateAutoCompoundConfig(config.autoCompoundConfig);
@@ -106,11 +108,18 @@ function validateAutoCompoundMarket(config: V4LifecycleMarketConfig | V4PoolBoun
106
108
 
107
109
  function validateRaetoMarket(config: V4LifecycleMarketConfig | V4PoolBoundLifecycleMarketConfig): asserts config is V4PoolBoundLifecycleMarketConfigV6 & { raetoLaunchConfig: RaetoLaunchConfigV1 } {
108
110
  if (config.version !== 6 || config.raetoLaunchConfig === undefined) throw new LifecyclePlanningError("INVALID_RAETO_CONFIG", "Raeto profiles require config6 and an explicit raetoLaunchConfig");
109
- if (config.hmmLaunchConfig !== undefined || config.ufgLaunchConfig !== undefined || config.autoCompoundConfig !== undefined) throw new LifecyclePlanningError("INVALID_RAETO_CONFIG", "Raeto profiles cannot carry HMM, UFG or auto-compounding tails");
111
+ if (config.hmmLaunchConfig !== undefined || config.ufgLaunchConfig !== undefined || config.autoCompoundConfig !== undefined || config.rwaLaunchConfig !== undefined) throw new LifecyclePlanningError("INVALID_RAETO_CONFIG", "Raeto profiles cannot carry HMM, UFG, auto-compounding or RWA tails");
110
112
  if (config.feeMode !== 1 || config.lpFeePips !== 0 || config.developerFeeBps !== 0) throw new LifecyclePlanningError("INVALID_RAETO_CONFIG", "Raeto requires QuoteOnly feeMode 1, zero LP fee and zero developer fee");
111
113
  validateRaetoLaunchConfig(config.raetoLaunchConfig);
112
114
  }
113
115
 
116
+ function validateRwaMarket(config: V4LifecycleMarketConfig | V4PoolBoundLifecycleMarketConfig): asserts config is V4PoolBoundLifecycleMarketConfigV6 & { rwaLaunchConfig: RwaLaunchConfigV1 } {
117
+ if (config.version !== 6 || config.rwaLaunchConfig === undefined) throw new LifecyclePlanningError("INVALID_RWA_CONFIG", "RWA profiles require config6 and an explicit rwaLaunchConfig");
118
+ if (config.hmmLaunchConfig !== undefined || config.ufgLaunchConfig !== undefined || config.autoCompoundConfig !== undefined || config.raetoLaunchConfig !== undefined) throw new LifecyclePlanningError("INVALID_RWA_CONFIG", "RWA profiles cannot carry HMM, UFG, auto-compounding or Raeto tails");
119
+ if (config.feeMode !== 1 || config.lpFeePips !== 0 || config.developerFeeBps !== 0) throw new LifecyclePlanningError("INVALID_RWA_CONFIG", "RWA requires QuoteOnly feeMode 1, zero LP fee and zero developer fee");
120
+ validateRwaLaunchConfig(config.rwaLaunchConfig);
121
+ }
122
+
114
123
  /** Auxiliary launch profiles require their typed tail and append it automatically. */
115
124
  export function encodePoolBoundV4LifecycleMarketConfig(config: V4PoolBoundLifecycleMarketConfig): Hex {
116
125
  const prefix = encodePoolBoundV4Prefix(config);
@@ -119,6 +128,11 @@ export function encodePoolBoundV4LifecycleMarketConfig(config: V4PoolBoundLifecy
119
128
  return concatHex([prefix, encodeRaetoLaunchTail(config.raetoLaunchConfig)]);
120
129
  }
121
130
  if (config.version === 6 && config.raetoLaunchConfig !== undefined) throw new LifecyclePlanningError("INVALID_RAETO_CONFIG", "A Raeto tail requires a Raeto profile");
131
+ if (isRwaProfile(config.profileId)) {
132
+ validateRwaMarket(config);
133
+ return concatHex([prefix, encodeRwaLaunchTail(config.rwaLaunchConfig)]);
134
+ }
135
+ if (config.version === 6 && config.rwaLaunchConfig !== undefined) throw new LifecyclePlanningError("INVALID_RWA_CONFIG", "An RWA tail requires an RWA profile");
122
136
  if (isAutoCompoundProfile(config.profileId)) {
123
137
  validateAutoCompoundMarket(config);
124
138
  return concatHex([prefix, encodeAutoCompoundTail(config.autoCompoundConfig)]);
@@ -163,6 +177,10 @@ export function decodePoolBoundV4LifecycleMarketConfig(encoded: Hex, expectedVer
163
177
  if (config.version !== 6) throw new LifecyclePlanningError("INVALID_RAETO_CONFIG", "Raeto profiles require config6");
164
178
  config.raetoLaunchConfig = decodeRaetoLaunchTail(`0x${encoded.slice(encodePoolBoundV4Prefix(config).length)}`);
165
179
  }
180
+ if (isRwaProfile(config.profileId)) {
181
+ if (config.version !== 6) throw new LifecyclePlanningError("INVALID_RWA_CONFIG", "RWA profiles require config6");
182
+ config.rwaLaunchConfig = decodeRwaLaunchTail(`0x${encoded.slice(encodePoolBoundV4Prefix(config).length)}`);
183
+ }
166
184
  if (isAutoCompoundProfile(config.profileId)) {
167
185
  if (config.version !== 6) throw new LifecyclePlanningError("INVALID_AUTO_COMPOUND_CONFIG", "Auto-compounding profiles require config6");
168
186
  config.autoCompoundConfig = decodeAutoCompoundTail(`0x${encoded.slice(encodePoolBoundV4Prefix(config).length)}`);
@@ -202,6 +220,10 @@ export function validateV4LifecycleMarket(options: {
202
220
  validateRaetoMarket(config);
203
221
  if (!RAETO_QUOTE_ASSETS.some((quote) => quote.toLowerCase() === market.quoteAsset.toLowerCase())) throw new LifecyclePlanningError("INVALID_RAETO_CONFIG", "Raeto quote asset must be WETH or USDG");
204
222
  } else if (config.version === 6 && config.raetoLaunchConfig !== undefined) throw new LifecyclePlanningError("INVALID_RAETO_CONFIG", "A Raeto tail requires a Raeto profile");
223
+ if (isRwaProfile(config.profileId)) {
224
+ validateRwaMarket(config);
225
+ if (market.quoteAsset.toLowerCase() !== RWA_QUOTE_ASSET.toLowerCase()) throw new LifecyclePlanningError("INVALID_RWA_CONFIG", "RWA quote asset must be USDG");
226
+ } else if (config.version === 6 && config.rwaLaunchConfig !== undefined) throw new LifecyclePlanningError("INVALID_RWA_CONFIG", "An RWA tail requires an RWA profile");
205
227
  const { envelope, developerTerms: terms, protocolMaximumDeveloperFeeBps: protocolCeiling } = profile;
206
228
  if (envelope === undefined || terms === undefined || protocolCeiling === undefined || !terms.enabled ||
207
229
  profile.topology.hookTopology !== (config.version === 4 ? 1 : 2) || market.configVersion !== config.version ||
@@ -52,7 +52,7 @@ function openingState(plan: LaunchPlanV1, marketIndex: number): OpeningState {
52
52
  const config = decodePoolBoundV4LifecycleMarketConfig(market.config, 6);
53
53
  if (config.profileId.toLowerCase() !== market.profileId.toLowerCase()) throw new LifecyclePlanningError("INVALID_MARKET", "V4 opening config differs from the selected profile");
54
54
  price = config.sqrtPriceX96; spacing = config.tickSpacing; lpFee = BigInt(config.lpFeePips); positions = config.positions;
55
- const dynamic = preset.key === KnownLifecycleProfile.V4DynamicFeePool || preset.key === KnownLifecycleProfile.V4HmmDynamicPool || preset.key === KnownLifecycleProfile.V4UfgDynamicPool || preset.key === KnownLifecycleProfile.V4AutoCompoundDynamicPool || preset.key === KnownLifecycleProfile.V4RaetoDynamicPool;
55
+ const dynamic = preset.key === KnownLifecycleProfile.V4DynamicFeePool || preset.key === KnownLifecycleProfile.V4HmmDynamicPool || preset.key === KnownLifecycleProfile.V4UfgDynamicPool || preset.key === KnownLifecycleProfile.V4AutoCompoundDynamicPool || preset.key === KnownLifecycleProfile.V4RaetoDynamicPool || preset.key === KnownLifecycleProfile.V4RwaDynamicPool;
56
56
  hookFee = BigInt(dynamic ? config.minimumHookFeePips! : config.hookFeePips);
57
57
  }
58
58
  const tick = getTickAtSqrtRatio(price), liquidityNet = new Map<number, bigint>();
@@ -19,6 +19,7 @@ import { computeLifecycleOpeningBuys, hasProfiledOpeningMath } from "./opening-b
19
19
  import { assessLifecycleTransactions, deriveLifecycleLaunchCapacity, type NextTransactionEnvelope, type ProfiledLaunchCapacity } from "./gas-profile.js";
20
20
  import type { LifecycleOpeningBuyQuote } from "./types.js";
21
21
  import { isRaetoProfile, RAETO_QUOTE_ASSETS } from "./raeto.js";
22
+ import { validateRwaLaunchPlan } from "./rwa.js";
22
23
 
23
24
  type ValidatedPlanShape = {
24
25
  commitment: Hex;
@@ -81,6 +82,7 @@ function validatePlanShape(plan: LaunchPlanV1): ValidatedPlanShape {
81
82
  previous = BigInt(policy.asset);
82
83
  }
83
84
  if (plan.feeAssets.some((policy) => policy.rewardsBps !== 0) !== (plan.token.rewardMode !== LifecycleRewardMode.None)) throw new LifecyclePlanningError("INVALID_FEE_POLICY", "Reward-enabled tokens require a rewards share; reward-free tokens cannot commit rewards shares");
85
+ validateRwaLaunchPlan(plan);
84
86
  previous = 0n;
85
87
  for (const funding of plan.funding) {
86
88
  if (BigInt(funding.asset) <= previous || funding.amount <= 0n || funding.inputAmount <= 0n) throw new LifecyclePlanningError("INVALID_FUNDING", "Funding output assets must be positive, unique and ascending");
@@ -471,7 +473,10 @@ function finalizeNextTransaction(options: BuildNextTransactionOptions, next: Lif
471
473
  /** Recovery observes actual canonical receipts, then constructs and budgets only
472
474
  * the next command. No launch transaction is executed during planning. */
473
475
  export async function buildNextTransaction(options: BuildNextTransactionOptions): Promise<LifecycleTransaction | undefined> {
474
- if (options.action !== "cancel") for (const market of options.planned.plan.markets) validateRaetoMarketContext(market);
476
+ if (options.action !== "cancel") {
477
+ for (const market of options.planned.plan.markets) validateRaetoMarketContext(market);
478
+ validateRwaLaunchPlan(options.planned.plan);
479
+ }
475
480
  const original = options.planned, matches = observedFields(original);
476
481
  const assertInput = () => {
477
482
  if (options.planned !== original || !matches()) throw new LifecyclePlanningError("PLAN_MUTATED", "Stored launch context changed while constructing its next transaction");
@@ -17,6 +17,9 @@ import { AUTO_COMPOUND_STATIC_V1_PROFILE_ID, AUTO_COMPOUND_DYNAMIC_V1_PROFILE_ID
17
17
  import { raetoFixedEnvelope, raetoFixedAdapter, raetoFixedRegistration } from "./deployments/raeto-fixed-pool-v1-20261029.js";
18
18
  import { raetoDynamicEnvelope, raetoDynamicAdapter, raetoDynamicRegistration } from "./deployments/raeto-dynamic-pool-v1-20261029.js";
19
19
  import { RAETO_FIXED_PROFILE_ID, RAETO_DYNAMIC_PROFILE_ID } from "./raeto.js";
20
+ import { rwaFixedEnvelope, rwaFixedAdapter, rwaFixedRegistration } from "./deployments/rwa-fixed-pool-v1-20261113.js";
21
+ import { rwaDynamicEnvelope, rwaDynamicAdapter, rwaDynamicRegistration } from "./deployments/rwa-dynamic-pool-v1-20261113.js";
22
+ import { RWA_FIXED_PROFILE_ID, RWA_DYNAMIC_PROFILE_ID } from "./rwa.js";
20
23
 
21
24
  export enum KnownLifecycleProfile {
22
25
  Abyss0 = "abyss-0",
@@ -33,6 +36,8 @@ export enum KnownLifecycleProfile {
33
36
  V4AutoCompoundDynamicPool = "v4-auto-compound-dynamic-pool",
34
37
  V4RaetoFixedPool = "v4-raeto-fixed-pool",
35
38
  V4RaetoDynamicPool = "v4-raeto-dynamic-pool",
39
+ V4RwaFixedPool = "v4-rwa-fixed-pool",
40
+ V4RwaDynamicPool = "v4-rwa-dynamic-pool",
36
41
  }
37
42
 
38
43
  export enum KnownLifecycleHook {
@@ -367,6 +372,8 @@ const knownDeployment: LifecycleDeploymentPreset = Object.freeze({
367
372
  poolBoundPreset(KnownLifecycleProfile.V4AutoCompoundDynamicPool, AUTO_COMPOUND_DYNAMIC_V1_PROFILE_ID, autoCompoundDynamicEnvelope, autoCompoundDynamicAdapter, autoCompoundDynamicRegistration, autoCompoundDynamicCreationCode),
368
373
  poolBoundPreset(KnownLifecycleProfile.V4RaetoFixedPool, RAETO_FIXED_PROFILE_ID, raetoFixedEnvelope, raetoFixedAdapter, raetoFixedRegistration, fixedFeePoolHookV1CreationCode),
369
374
  poolBoundPreset(KnownLifecycleProfile.V4RaetoDynamicPool, RAETO_DYNAMIC_PROFILE_ID, raetoDynamicEnvelope, raetoDynamicAdapter, raetoDynamicRegistration, dynamicFeePoolHookV1CreationCode),
375
+ poolBoundPreset(KnownLifecycleProfile.V4RwaFixedPool, RWA_FIXED_PROFILE_ID, rwaFixedEnvelope, rwaFixedAdapter, rwaFixedRegistration, fixedFeePoolHookV1CreationCode),
376
+ poolBoundPreset(KnownLifecycleProfile.V4RwaDynamicPool, RWA_DYNAMIC_PROFILE_ID, rwaDynamicEnvelope, rwaDynamicAdapter, rwaDynamicRegistration, dynamicFeePoolHookV1CreationCode),
370
377
  ]),
371
378
  provenance: Object.freeze({ sourceCommit: "e174ce695c7010f50ca9211b07b9f178c990beac", deploymentBlock: 82880546n }),
372
379
  });
@@ -396,7 +403,7 @@ export function getKnownLifecycleProfile(options: KnownLifecycleDeploymentIdenti
396
403
  return undefined;
397
404
  }
398
405
 
399
- /** Stable, frozen order: Abyss, fixed/dynamic V4, HMM, UFG, auto-compounding, then Raeto. */
406
+ /** Stable, frozen order: Abyss, fixed/dynamic V4, HMM, UFG, auto-compounding, Raeto, then RWA. */
400
407
  export function listKnownLifecycleProfiles(options: KnownLifecycleDeploymentIdentity): readonly LifecycleProfilePreset[] {
401
408
  return getKnownLifecycleDeployment(options)?.profiles ?? noProfiles;
402
409
  }
@@ -1,4 +1,4 @@
1
- // Generated from the verified RaetoFeeCollectorV1 ABI by scripts/generate-raeto-presets.mjs.
1
+ // Generated from the verified Raeto collector/registry ABIs by scripts/generate-raeto-presets.mjs.
2
2
  // Provenance: test/fixtures/raeto-registry-readback.json, abiProvenance.
3
3
  export const raetoFeeCollectorV1Abi = [
4
4
  {
@@ -181,6 +181,32 @@ export const raetoFeeCollectorV1Abi = [
181
181
  "stateMutability": "view",
182
182
  "type": "function"
183
183
  },
184
+ {
185
+ "inputs": [],
186
+ "name": "payoutRegistry",
187
+ "outputs": [
188
+ {
189
+ "internalType": "address",
190
+ "name": "",
191
+ "type": "address"
192
+ }
193
+ ],
194
+ "stateMutability": "view",
195
+ "type": "function"
196
+ },
197
+ {
198
+ "inputs": [],
199
+ "name": "poolId",
200
+ "outputs": [
201
+ {
202
+ "internalType": "bytes32",
203
+ "name": "",
204
+ "type": "bytes32"
205
+ }
206
+ ],
207
+ "stateMutability": "view",
208
+ "type": "function"
209
+ },
184
210
  {
185
211
  "inputs": [],
186
212
  "name": "quoteAsset",
@@ -221,3 +247,17 @@ export const raetoFeeCollectorV1Abi = [
221
247
  "type": "function"
222
248
  }
223
249
  ] as const;
250
+
251
+ export const raetoPayoutRegistryV1Abi = [
252
+ {
253
+ "name": "payout",
254
+ "type": "function",
255
+ "stateMutability": "view",
256
+ "inputs": [],
257
+ "outputs": [
258
+ {
259
+ "type": "address"
260
+ }
261
+ ]
262
+ }
263
+ ] as const;