liquid-sdk 1.0.0 → 1.1.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/dist/index.js CHANGED
@@ -21,8 +21,11 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  ADDRESSES: () => ADDRESSES,
24
+ DEFAULTS: () => DEFAULTS,
24
25
  DEFAULT_CHAIN: () => DEFAULT_CHAIN,
25
26
  DEFAULT_CHAIN_ID: () => DEFAULT_CHAIN_ID,
27
+ DEFAULT_RPC_URL: () => DEFAULT_RPC_URL,
28
+ DEFAULT_TRANCHES_USD: () => DEFAULT_TRANCHES_USD,
26
29
  ERC20Abi: () => ERC20Abi,
27
30
  EXTERNAL: () => EXTERNAL,
28
31
  FEE: () => FEE,
@@ -37,12 +40,25 @@ __export(index_exports, {
37
40
  LiquidSniperAuctionV2Abi: () => LiquidSniperAuctionV2Abi,
38
41
  LiquidSniperUtilV2Abi: () => LiquidSniperUtilV2Abi,
39
42
  LiquidVaultAbi: () => LiquidVaultAbi,
40
- TOKEN: () => TOKEN
43
+ POOL_POSITIONS: () => POOL_POSITIONS,
44
+ TOKEN: () => TOKEN,
45
+ createDefaultPositions: () => createDefaultPositions,
46
+ createPositions: () => createPositions,
47
+ createPositionsUSD: () => createPositionsUSD,
48
+ describePositions: () => describePositions,
49
+ encodeDynamicFeePoolData: () => encodeDynamicFeePoolData,
50
+ encodeSniperAuctionData: () => encodeSniperAuctionData,
51
+ encodeStaticFeePoolData: () => encodeStaticFeePoolData,
52
+ getTickFromMarketCapETH: () => getTickFromMarketCapETH,
53
+ getTickFromMarketCapStable: () => getTickFromMarketCapStable,
54
+ getTickFromMarketCapUSD: () => getTickFromMarketCapUSD,
55
+ marketCapFromTickETH: () => marketCapFromTickETH,
56
+ marketCapFromTickUSD: () => marketCapFromTickUSD
41
57
  });
42
58
  module.exports = __toCommonJS(index_exports);
43
59
 
44
60
  // src/client.ts
45
- var import_viem = require("viem");
61
+ var import_viem2 = require("viem");
46
62
  var import_chains2 = require("viem/chains");
47
63
 
48
64
  // src/constants.ts
@@ -88,8 +104,154 @@ var TOKEN = {
88
104
  MAX_EXTENSIONS: 10,
89
105
  MAX_EXTENSION_BPS: 9e3
90
106
  };
107
+ var POOL_POSITIONS = {
108
+ /** Single position, 100% of liquidity in one range */
109
+ Standard: [
110
+ {
111
+ tickLower: -230400,
112
+ // ~10 ETH / ~$20K
113
+ tickUpper: -12e4,
114
+ // ~$1.5B
115
+ positionBps: 1e4
116
+ }
117
+ ],
118
+ /** 3-tranche Liquid default (hardcoded for ~10 ETH start, ~$2070/ETH) */
119
+ Liquid: [
120
+ {
121
+ tickLower: -230400,
122
+ // ~$20K starting
123
+ tickUpper: -198600,
124
+ // ~$500K
125
+ positionBps: 4e3
126
+ // 40%
127
+ },
128
+ {
129
+ tickLower: -198600,
130
+ // ~$500K
131
+ tickUpper: -168600,
132
+ // ~$10M
133
+ positionBps: 5e3
134
+ // 50%
135
+ },
136
+ {
137
+ tickLower: -168600,
138
+ // ~$10M
139
+ tickUpper: -122600,
140
+ // ~$1B
141
+ positionBps: 1e3
142
+ // 10%
143
+ }
144
+ ]
145
+ };
146
+ var DEFAULTS = {
147
+ HOOK: ADDRESSES.HOOK_STATIC_FEE_V2,
148
+ TICK_SPACING: 200,
149
+ TICK_IF_TOKEN0_IS_LIQUID: -230400,
150
+ /** Static fee on buys (ETH → token): 1% (100 bps). Fees collected in ETH. */
151
+ PAIRED_FEE_BPS: 100,
152
+ /** Static fee on sells (token → ETH): 0%. No fees in liquid token. */
153
+ LIQUID_FEE_BPS: 0,
154
+ /** MEV module: Sniper Auction V2 */
155
+ MEV_MODULE: ADDRESSES.SNIPER_AUCTION_V2,
156
+ /** Sniper auction starting fee: 80% (800,000 uniBps) */
157
+ SNIPER_STARTING_FEE: 8e5,
158
+ /** Sniper auction ending fee: 40% (400,000 uniBps) */
159
+ SNIPER_ENDING_FEE: 4e5,
160
+ /** Sniper auction decay period: 32 seconds */
161
+ SNIPER_SECONDS_TO_DECAY: 32
162
+ };
91
163
  var DEFAULT_CHAIN = import_chains.base;
92
164
  var DEFAULT_CHAIN_ID = 8453;
165
+ var DEFAULT_RPC_URL = "https://base.drpc.org";
166
+
167
+ // src/utils/encoding.ts
168
+ var import_viem = require("viem");
169
+ var PoolInitializationDataAbi = [
170
+ {
171
+ type: "tuple",
172
+ components: [
173
+ { name: "extension", type: "address" },
174
+ { name: "extensionData", type: "bytes" },
175
+ { name: "feeData", type: "bytes" }
176
+ ]
177
+ }
178
+ ];
179
+ var StaticFeeInitAbi = [
180
+ { type: "uint24" },
181
+ { type: "uint24" }
182
+ ];
183
+ var SniperAuctionInitAbi = [
184
+ {
185
+ type: "tuple",
186
+ components: [
187
+ { name: "startingFee", type: "uint24" },
188
+ { name: "endingFee", type: "uint24" },
189
+ { name: "secondsToDecay", type: "uint256" }
190
+ ]
191
+ }
192
+ ];
193
+ function encodeStaticFeePoolData(liquidFeeBps, pairedFeeBps, extension = import_viem.zeroAddress, extensionData = "0x") {
194
+ const feeData = (0, import_viem.encodeAbiParameters)(StaticFeeInitAbi, [
195
+ liquidFeeBps * 100,
196
+ pairedFeeBps * 100
197
+ ]);
198
+ return (0, import_viem.encodeAbiParameters)(PoolInitializationDataAbi, [
199
+ {
200
+ extension,
201
+ extensionData,
202
+ feeData
203
+ }
204
+ ]);
205
+ }
206
+ var DynamicFeeInitAbi = [
207
+ { type: "uint24" },
208
+ // baseFee (uniBps)
209
+ { type: "uint24" },
210
+ // maxFee (uniBps)
211
+ { type: "uint256" },
212
+ // referenceTickFilterPeriod
213
+ { type: "uint256" },
214
+ // resetPeriod
215
+ { type: "int24" },
216
+ // resetTickFilter
217
+ { type: "uint256" },
218
+ // feeControlNumerator
219
+ { type: "uint24" }
220
+ // decayFilterBps
221
+ ];
222
+ function encodeDynamicFeePoolData(config, extension = import_viem.zeroAddress, extensionData = "0x") {
223
+ const feeData = (0, import_viem.encodeAbiParameters)(DynamicFeeInitAbi, [
224
+ config.baseFeeBps * 100,
225
+ config.maxFeeBps * 100,
226
+ BigInt(config.referenceTickFilterPeriod),
227
+ BigInt(config.resetPeriod),
228
+ config.resetTickFilter,
229
+ config.feeControlNumerator,
230
+ config.decayFilterBps
231
+ ]);
232
+ return (0, import_viem.encodeAbiParameters)(PoolInitializationDataAbi, [
233
+ {
234
+ extension,
235
+ extensionData,
236
+ feeData
237
+ }
238
+ ]);
239
+ }
240
+ function encodeSniperAuctionData(config) {
241
+ if (config.startingFee <= config.endingFee) {
242
+ throw new Error("startingFee must be greater than endingFee");
243
+ }
244
+ if (config.secondsToDecay <= 0) {
245
+ throw new Error("secondsToDecay must be positive");
246
+ }
247
+ return (0, import_viem.encodeAbiParameters)(SniperAuctionInitAbi, [
248
+ {
249
+ startingFee: config.startingFee,
250
+ endingFee: config.endingFee,
251
+ secondsToDecay: BigInt(config.secondsToDecay)
252
+ }
253
+ ]);
254
+ }
93
255
 
94
256
  // src/abis/LiquidFactory.ts
95
257
  var LiquidFactoryAbi = [
@@ -792,7 +954,7 @@ var LiquidSDK = class {
792
954
  * The paired token must be WETH for simple dev buys.
793
955
  */
794
956
  buildDevBuyExtension(devBuy) {
795
- const extensionData = (0, import_viem.encodeAbiParameters)(
957
+ const extensionData = (0, import_viem2.encodeAbiParameters)(
796
958
  [
797
959
  {
798
960
  type: "tuple",
@@ -816,11 +978,11 @@ var LiquidSDK = class {
816
978
  [
817
979
  {
818
980
  pairedTokenPoolKey: {
819
- currency0: import_viem.zeroAddress,
820
- currency1: import_viem.zeroAddress,
981
+ currency0: import_viem2.zeroAddress,
982
+ currency1: import_viem2.zeroAddress,
821
983
  fee: 0,
822
984
  tickSpacing: 0,
823
- hooks: import_viem.zeroAddress
985
+ hooks: import_viem2.zeroAddress
824
986
  },
825
987
  pairedTokenAmountOutMinimum: 0n,
826
988
  recipient: devBuy.recipient
@@ -834,6 +996,97 @@ var LiquidSDK = class {
834
996
  extensionData
835
997
  };
836
998
  }
999
+ // ── Validation ─────────────────────────────────────────────────
1000
+ /**
1001
+ * Validate a DeploymentConfig before sending to the contract.
1002
+ * Catches common mistakes client-side with clear error messages.
1003
+ */
1004
+ validateDeploymentConfig(config) {
1005
+ const { lockerConfig, extensionConfigs } = config;
1006
+ const { tickSpacing } = config.poolConfig;
1007
+ const posLen = lockerConfig.tickLower.length;
1008
+ if (lockerConfig.tickUpper.length !== posLen || lockerConfig.positionBps.length !== posLen) {
1009
+ throw new Error(
1010
+ `tickLower (${posLen}), tickUpper (${lockerConfig.tickUpper.length}), and positionBps (${lockerConfig.positionBps.length}) arrays must be the same length`
1011
+ );
1012
+ }
1013
+ if (posLen === 0) {
1014
+ throw new Error("At least one position is required");
1015
+ }
1016
+ if (posLen > 7) {
1017
+ throw new Error(`Maximum 7 positions allowed, got ${posLen}`);
1018
+ }
1019
+ const posBpsSum = lockerConfig.positionBps.reduce((s, b) => s + b, 0);
1020
+ if (posBpsSum !== FEE.BPS) {
1021
+ throw new Error(
1022
+ `positionBps must sum to ${FEE.BPS} (100%), got ${posBpsSum}`
1023
+ );
1024
+ }
1025
+ for (let i = 0; i < posLen; i++) {
1026
+ if (lockerConfig.tickLower[i] >= lockerConfig.tickUpper[i]) {
1027
+ throw new Error(
1028
+ `Position ${i}: tickLower (${lockerConfig.tickLower[i]}) must be less than tickUpper (${lockerConfig.tickUpper[i]})`
1029
+ );
1030
+ }
1031
+ }
1032
+ for (let i = 0; i < posLen; i++) {
1033
+ if (lockerConfig.tickLower[i] % tickSpacing !== 0) {
1034
+ throw new Error(
1035
+ `Position ${i}: tickLower (${lockerConfig.tickLower[i]}) is not a multiple of tickSpacing (${tickSpacing})`
1036
+ );
1037
+ }
1038
+ if (lockerConfig.tickUpper[i] % tickSpacing !== 0) {
1039
+ throw new Error(
1040
+ `Position ${i}: tickUpper (${lockerConfig.tickUpper[i]}) is not a multiple of tickSpacing (${tickSpacing})`
1041
+ );
1042
+ }
1043
+ }
1044
+ const startingTick = config.poolConfig.tickIfToken0IsLiquid;
1045
+ for (let i = 0; i < posLen; i++) {
1046
+ if (lockerConfig.tickLower[i] < startingTick) {
1047
+ throw new Error(
1048
+ `Position ${i}: tickLower (${lockerConfig.tickLower[i]}) is below the starting tick (${startingTick})`
1049
+ );
1050
+ }
1051
+ }
1052
+ const touchesStart = lockerConfig.tickLower.some(
1053
+ (t) => t === startingTick
1054
+ );
1055
+ if (!touchesStart) {
1056
+ throw new Error(
1057
+ `At least one position's tickLower must equal tickIfToken0IsLiquid (${startingTick})`
1058
+ );
1059
+ }
1060
+ const rwdLen = lockerConfig.rewardAdmins.length;
1061
+ if (lockerConfig.rewardRecipients.length !== rwdLen || lockerConfig.rewardBps.length !== rwdLen) {
1062
+ throw new Error(
1063
+ `rewardAdmins (${rwdLen}), rewardRecipients (${lockerConfig.rewardRecipients.length}), and rewardBps (${lockerConfig.rewardBps.length}) arrays must be the same length`
1064
+ );
1065
+ }
1066
+ if (rwdLen === 0) {
1067
+ throw new Error("At least one reward recipient is required");
1068
+ }
1069
+ const rwdBpsSum = lockerConfig.rewardBps.reduce((s, b) => s + b, 0);
1070
+ if (rwdBpsSum !== FEE.BPS) {
1071
+ throw new Error(
1072
+ `rewardBps must sum to ${FEE.BPS} (100%), got ${rwdBpsSum}`
1073
+ );
1074
+ }
1075
+ if (extensionConfigs.length > TOKEN.MAX_EXTENSIONS) {
1076
+ throw new Error(
1077
+ `Maximum ${TOKEN.MAX_EXTENSIONS} extensions allowed, got ${extensionConfigs.length}`
1078
+ );
1079
+ }
1080
+ const extBpsSum = extensionConfigs.reduce(
1081
+ (s, e) => s + e.extensionBps,
1082
+ 0
1083
+ );
1084
+ if (extBpsSum > TOKEN.MAX_EXTENSION_BPS) {
1085
+ throw new Error(
1086
+ `Total extensionBps (${extBpsSum}) exceeds maximum (${TOKEN.MAX_EXTENSION_BPS})`
1087
+ );
1088
+ }
1089
+ }
837
1090
  // ── Token Deployment ─────────────────────────────────────────────
838
1091
  async deployToken(params) {
839
1092
  if (!this.walletClient?.account) {
@@ -845,8 +1098,8 @@ var LiquidSDK = class {
845
1098
  tokenAdmin: params.tokenAdmin ?? account,
846
1099
  name: params.name,
847
1100
  symbol: params.symbol,
848
- salt: params.salt ?? (0, import_viem.keccak256)(
849
- (0, import_viem.encodePacked)(
1101
+ salt: params.salt ?? (0, import_viem2.keccak256)(
1102
+ (0, import_viem2.encodePacked)(
850
1103
  ["string", "string", "uint256"],
851
1104
  [params.name, params.symbol, BigInt(Date.now())]
852
1105
  )
@@ -857,25 +1110,32 @@ var LiquidSDK = class {
857
1110
  originatingChainId: BigInt(DEFAULT_CHAIN_ID)
858
1111
  },
859
1112
  poolConfig: {
860
- hook: params.hook ?? ADDRESSES.HOOK_DYNAMIC_FEE_V2,
1113
+ hook: params.hook ?? DEFAULTS.HOOK,
861
1114
  pairedToken: params.pairedToken ?? EXTERNAL.WETH,
862
- tickIfToken0IsLiquid: params.tickIfToken0IsLiquid ?? -198720,
863
- tickSpacing: params.tickSpacing ?? 60,
864
- poolData: params.poolData ?? "0x"
1115
+ tickIfToken0IsLiquid: params.tickIfToken0IsLiquid ?? DEFAULTS.TICK_IF_TOKEN0_IS_LIQUID,
1116
+ tickSpacing: params.tickSpacing ?? DEFAULTS.TICK_SPACING,
1117
+ poolData: params.poolData ?? encodeStaticFeePoolData(
1118
+ DEFAULTS.LIQUID_FEE_BPS,
1119
+ DEFAULTS.PAIRED_FEE_BPS
1120
+ )
865
1121
  },
866
1122
  lockerConfig: {
867
1123
  locker: params.locker ?? ADDRESSES.LP_LOCKER,
868
1124
  rewardAdmins: params.rewardAdmins ?? [account],
869
1125
  rewardRecipients: params.rewardRecipients ?? [account],
870
1126
  rewardBps: params.rewardBps ?? [1e4],
871
- tickLower: params.tickLower ?? [-887220],
872
- tickUpper: params.tickUpper ?? [887220],
873
- positionBps: params.positionBps ?? [1e4],
1127
+ tickLower: params.tickLower ?? POOL_POSITIONS.Liquid.map((p) => p.tickLower),
1128
+ tickUpper: params.tickUpper ?? POOL_POSITIONS.Liquid.map((p) => p.tickUpper),
1129
+ positionBps: params.positionBps ?? POOL_POSITIONS.Liquid.map((p) => p.positionBps),
874
1130
  lockerData: params.lockerData ?? "0x"
875
1131
  },
876
1132
  mevModuleConfig: {
877
- mevModule: params.mevModule ?? ADDRESSES.MEV_BLOCK_DELAY,
878
- mevModuleData: params.mevModuleData ?? "0x"
1133
+ mevModule: params.mevModule ?? DEFAULTS.MEV_MODULE,
1134
+ mevModuleData: params.mevModuleData ?? encodeSniperAuctionData({
1135
+ startingFee: DEFAULTS.SNIPER_STARTING_FEE,
1136
+ endingFee: DEFAULTS.SNIPER_ENDING_FEE,
1137
+ secondsToDecay: DEFAULTS.SNIPER_SECONDS_TO_DECAY
1138
+ })
879
1139
  },
880
1140
  extensionConfigs: [...params.extensions ?? []]
881
1141
  };
@@ -884,6 +1144,7 @@ var LiquidSDK = class {
884
1144
  this.buildDevBuyExtension(params.devBuy)
885
1145
  );
886
1146
  }
1147
+ this.validateDeploymentConfig(deploymentConfig);
887
1148
  const msgValue = deploymentConfig.extensionConfigs.reduce(
888
1149
  (sum, ext) => sum + ext.msgValue,
889
1150
  0n
@@ -902,7 +1163,7 @@ var LiquidSDK = class {
902
1163
  });
903
1164
  const tokenCreatedLog = receipt.logs.find((log) => {
904
1165
  try {
905
- const decoded2 = (0, import_viem.decodeEventLog)({
1166
+ const decoded2 = (0, import_viem2.decodeEventLog)({
906
1167
  abi: LiquidFactoryAbi,
907
1168
  data: log.data,
908
1169
  topics: log.topics
@@ -915,14 +1176,14 @@ var LiquidSDK = class {
915
1176
  if (!tokenCreatedLog) {
916
1177
  throw new Error("TokenCreated event not found in transaction receipt");
917
1178
  }
918
- const decoded = (0, import_viem.decodeEventLog)({
1179
+ const decoded = (0, import_viem2.decodeEventLog)({
919
1180
  abi: LiquidFactoryAbi,
920
1181
  data: tokenCreatedLog.data,
921
1182
  topics: tokenCreatedLog.topics
922
1183
  });
923
1184
  const args = decoded.args;
924
1185
  return {
925
- tokenAddress: (0, import_viem.getAddress)(args.tokenAddress),
1186
+ tokenAddress: (0, import_viem2.getAddress)(args.tokenAddress),
926
1187
  txHash,
927
1188
  event: {
928
1189
  msgSender: args.msgSender,
@@ -1070,7 +1331,7 @@ var LiquidSDK = class {
1070
1331
  if (!this.walletClient?.account) {
1071
1332
  throw new Error("walletClient with account required for claimFees");
1072
1333
  }
1073
- return this.walletClient.writeContract({
1334
+ return await this.walletClient.writeContract({
1074
1335
  address: ADDRESSES.FEE_LOCKER,
1075
1336
  abi: LiquidFeeLockerAbi,
1076
1337
  functionName: "claim",
@@ -1109,7 +1370,7 @@ var LiquidSDK = class {
1109
1370
  if (!this.walletClient?.account) {
1110
1371
  throw new Error("walletClient with account required for claimVault");
1111
1372
  }
1112
- return this.walletClient.writeContract({
1373
+ return await this.walletClient.writeContract({
1113
1374
  address: ADDRESSES.VAULT,
1114
1375
  abi: LiquidVaultAbi,
1115
1376
  functionName: "claim",
@@ -1238,7 +1499,7 @@ var LiquidSDK = class {
1238
1499
  if (!this.walletClient?.account) {
1239
1500
  throw new Error("walletClient with account required for claimAirdrop");
1240
1501
  }
1241
- return this.walletClient.writeContract({
1502
+ return await this.walletClient.writeContract({
1242
1503
  address: ADDRESSES.AIRDROP_V2,
1243
1504
  abi: LiquidAirdropV2Abi,
1244
1505
  functionName: "claim",
@@ -1272,7 +1533,7 @@ var LiquidSDK = class {
1272
1533
  throw new Error("walletClient with account required for collectRewards");
1273
1534
  }
1274
1535
  const locker = lockerAddress ?? ADDRESSES.LP_LOCKER;
1275
- return this.walletClient.writeContract({
1536
+ return await this.walletClient.writeContract({
1276
1537
  address: locker,
1277
1538
  abi: LiquidLpLockerAbi,
1278
1539
  functionName: "collectRewards",
@@ -1288,7 +1549,7 @@ var LiquidSDK = class {
1288
1549
  );
1289
1550
  }
1290
1551
  const locker = lockerAddress ?? ADDRESSES.LP_LOCKER;
1291
- return this.walletClient.writeContract({
1552
+ return await this.walletClient.writeContract({
1292
1553
  address: locker,
1293
1554
  abi: LiquidLpLockerAbi,
1294
1555
  functionName: "collectRewardsWithoutUnlock",
@@ -1304,7 +1565,7 @@ var LiquidSDK = class {
1304
1565
  );
1305
1566
  }
1306
1567
  const locker = lockerAddress ?? ADDRESSES.LP_LOCKER;
1307
- return this.walletClient.writeContract({
1568
+ return await this.walletClient.writeContract({
1308
1569
  address: locker,
1309
1570
  abi: LiquidLpLockerAbi,
1310
1571
  functionName: "updateRewardRecipient",
@@ -1339,11 +1600,122 @@ var LiquidSDK = class {
1339
1600
  });
1340
1601
  }
1341
1602
  };
1603
+
1604
+ // src/utils/tick-math.ts
1605
+ var LOG_BASE = Math.log(1.0001);
1606
+ var DEFAULT_TICK_SPACING = 200;
1607
+ var TOTAL_SUPPLY = 1e11;
1608
+ function getTickFromMarketCapETH(marketCapETH, tickSpacing = DEFAULT_TICK_SPACING) {
1609
+ if (marketCapETH <= 0) throw new Error("marketCapETH must be positive");
1610
+ const price = marketCapETH / TOTAL_SUPPLY;
1611
+ const rawTick = Math.log(price) / LOG_BASE;
1612
+ return Math.floor(rawTick / tickSpacing) * tickSpacing;
1613
+ }
1614
+ function getTickFromMarketCapUSD(marketCapUSD, ethPriceUSD, tickSpacing = DEFAULT_TICK_SPACING) {
1615
+ if (ethPriceUSD <= 0) throw new Error("ethPriceUSD must be positive");
1616
+ return getTickFromMarketCapETH(marketCapUSD / ethPriceUSD, tickSpacing);
1617
+ }
1618
+ function marketCapFromTickETH(tick) {
1619
+ const price = Math.pow(1.0001, tick);
1620
+ return price * TOTAL_SUPPLY;
1621
+ }
1622
+ function marketCapFromTickUSD(tick, ethPriceUSD) {
1623
+ return marketCapFromTickETH(tick) * ethPriceUSD;
1624
+ }
1625
+ function getTickFromMarketCapStable(marketCap, stableDecimals, tickSpacing = DEFAULT_TICK_SPACING) {
1626
+ if (marketCap <= 0) throw new Error("marketCap must be positive");
1627
+ const price = marketCap / Math.pow(10, 29 - stableDecimals);
1628
+ const rawTick = Math.log(price) / LOG_BASE;
1629
+ return Math.floor(rawTick / tickSpacing) * tickSpacing;
1630
+ }
1631
+
1632
+ // src/utils/positions.ts
1633
+ var DEFAULT_TRANCHES_USD = [
1634
+ { upperMarketCapUSD: 5e5, supplyPct: 40 },
1635
+ { upperMarketCapUSD: 1e7, supplyPct: 50 },
1636
+ { upperMarketCapUSD: 1e9, supplyPct: 10 }
1637
+ ];
1638
+ function createPositions(startingMarketCapETH, tranches, tickSpacing = 200) {
1639
+ if (tranches.length === 0) throw new Error("At least one tranche is required");
1640
+ if (tranches.length > 7) throw new Error("Maximum 7 positions allowed");
1641
+ const totalPct = tranches.reduce((sum, t) => sum + t.supplyPct, 0);
1642
+ if (Math.abs(totalPct - 100) > 0.01) {
1643
+ throw new Error(`Tranche percentages must sum to 100, got ${totalPct}`);
1644
+ }
1645
+ for (let i = 1; i < tranches.length; i++) {
1646
+ if (tranches[i].upperMarketCapETH <= tranches[i - 1].upperMarketCapETH) {
1647
+ throw new Error("Tranches must be ordered by ascending upperMarketCapETH");
1648
+ }
1649
+ }
1650
+ const startingTick = getTickFromMarketCapETH(startingMarketCapETH, tickSpacing);
1651
+ const tickLower = [];
1652
+ const tickUpper = [];
1653
+ const positionBps = [];
1654
+ let prevTick = startingTick;
1655
+ for (const tranche of tranches) {
1656
+ const upperTick = getTickFromMarketCapETH(tranche.upperMarketCapETH, tickSpacing);
1657
+ if (upperTick <= prevTick) {
1658
+ throw new Error(
1659
+ `Tranche upper market cap ${tranche.upperMarketCapETH} ETH resolves to tick ${upperTick}, which is not above previous tick ${prevTick}. Increase the market cap or reduce tick spacing.`
1660
+ );
1661
+ }
1662
+ tickLower.push(prevTick);
1663
+ tickUpper.push(upperTick);
1664
+ positionBps.push(Math.round(tranche.supplyPct * 100));
1665
+ prevTick = upperTick;
1666
+ }
1667
+ return { tickLower, tickUpper, positionBps };
1668
+ }
1669
+ function createPositionsUSD(startingMarketCapUSD, ethPriceUSD, tranches, tickSpacing = 200) {
1670
+ if (ethPriceUSD <= 0) throw new Error("ethPriceUSD must be positive");
1671
+ const ethTranches = tranches.map((t) => ({
1672
+ upperMarketCapETH: t.upperMarketCapUSD / ethPriceUSD,
1673
+ supplyPct: t.supplyPct
1674
+ }));
1675
+ return createPositions(
1676
+ startingMarketCapUSD / ethPriceUSD,
1677
+ ethTranches,
1678
+ tickSpacing
1679
+ );
1680
+ }
1681
+ function createDefaultPositions(startingMarketCapUSD, ethPriceUSD, tickSpacing = 200) {
1682
+ const positions = createPositionsUSD(
1683
+ startingMarketCapUSD,
1684
+ ethPriceUSD,
1685
+ DEFAULT_TRANCHES_USD,
1686
+ tickSpacing
1687
+ );
1688
+ return {
1689
+ ...positions,
1690
+ tickIfToken0IsLiquid: positions.tickLower[0]
1691
+ };
1692
+ }
1693
+ function describePositions(positions, ethPriceUSD) {
1694
+ return positions.tickLower.map((_, i) => {
1695
+ const lowerETH = Math.pow(1.0001, positions.tickLower[i]) * 1e11;
1696
+ const upperETH = Math.pow(1.0001, positions.tickUpper[i]) * 1e11;
1697
+ return {
1698
+ index: i,
1699
+ tickLower: positions.tickLower[i],
1700
+ tickUpper: positions.tickUpper[i],
1701
+ supplyPct: positions.positionBps[i] / 100,
1702
+ marketCapLowerETH: lowerETH,
1703
+ marketCapUpperETH: upperETH,
1704
+ ...ethPriceUSD != null && {
1705
+ marketCapLowerUSD: lowerETH * ethPriceUSD,
1706
+ marketCapUpperUSD: upperETH * ethPriceUSD
1707
+ }
1708
+ };
1709
+ });
1710
+ }
1342
1711
  // Annotate the CommonJS export names for ESM import in node:
1343
1712
  0 && (module.exports = {
1344
1713
  ADDRESSES,
1714
+ DEFAULTS,
1345
1715
  DEFAULT_CHAIN,
1346
1716
  DEFAULT_CHAIN_ID,
1717
+ DEFAULT_RPC_URL,
1718
+ DEFAULT_TRANCHES_USD,
1347
1719
  ERC20Abi,
1348
1720
  EXTERNAL,
1349
1721
  FEE,
@@ -1358,6 +1730,19 @@ var LiquidSDK = class {
1358
1730
  LiquidSniperAuctionV2Abi,
1359
1731
  LiquidSniperUtilV2Abi,
1360
1732
  LiquidVaultAbi,
1361
- TOKEN
1733
+ POOL_POSITIONS,
1734
+ TOKEN,
1735
+ createDefaultPositions,
1736
+ createPositions,
1737
+ createPositionsUSD,
1738
+ describePositions,
1739
+ encodeDynamicFeePoolData,
1740
+ encodeSniperAuctionData,
1741
+ encodeStaticFeePoolData,
1742
+ getTickFromMarketCapETH,
1743
+ getTickFromMarketCapStable,
1744
+ getTickFromMarketCapUSD,
1745
+ marketCapFromTickETH,
1746
+ marketCapFromTickUSD
1362
1747
  });
1363
1748
  //# sourceMappingURL=index.js.map