liquid-sdk 1.0.0 → 1.2.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,
@@ -36,13 +39,28 @@ __export(index_exports, {
36
39
  LiquidSDK: () => LiquidSDK,
37
40
  LiquidSniperAuctionV2Abi: () => LiquidSniperAuctionV2Abi,
38
41
  LiquidSniperUtilV2Abi: () => LiquidSniperUtilV2Abi,
42
+ LiquidTokenAbi: () => LiquidTokenAbi,
43
+ LiquidUniv4EthDevBuyAbi: () => LiquidUniv4EthDevBuyAbi,
39
44
  LiquidVaultAbi: () => LiquidVaultAbi,
40
- TOKEN: () => TOKEN
45
+ POOL_POSITIONS: () => POOL_POSITIONS,
46
+ TOKEN: () => TOKEN,
47
+ createDefaultPositions: () => createDefaultPositions,
48
+ createPositions: () => createPositions,
49
+ createPositionsUSD: () => createPositionsUSD,
50
+ describePositions: () => describePositions,
51
+ encodeDynamicFeePoolData: () => encodeDynamicFeePoolData,
52
+ encodeSniperAuctionData: () => encodeSniperAuctionData,
53
+ encodeStaticFeePoolData: () => encodeStaticFeePoolData,
54
+ getTickFromMarketCapETH: () => getTickFromMarketCapETH,
55
+ getTickFromMarketCapStable: () => getTickFromMarketCapStable,
56
+ getTickFromMarketCapUSD: () => getTickFromMarketCapUSD,
57
+ marketCapFromTickETH: () => marketCapFromTickETH,
58
+ marketCapFromTickUSD: () => marketCapFromTickUSD
41
59
  });
42
60
  module.exports = __toCommonJS(index_exports);
43
61
 
44
62
  // src/client.ts
45
- var import_viem = require("viem");
63
+ var import_viem2 = require("viem");
46
64
  var import_chains2 = require("viem/chains");
47
65
 
48
66
  // src/constants.ts
@@ -88,8 +106,154 @@ var TOKEN = {
88
106
  MAX_EXTENSIONS: 10,
89
107
  MAX_EXTENSION_BPS: 9e3
90
108
  };
109
+ var POOL_POSITIONS = {
110
+ /** Single position, 100% of liquidity in one range */
111
+ Standard: [
112
+ {
113
+ tickLower: -230400,
114
+ // ~10 ETH / ~$20K
115
+ tickUpper: -12e4,
116
+ // ~$1.5B
117
+ positionBps: 1e4
118
+ }
119
+ ],
120
+ /** 3-tranche Liquid default (hardcoded for ~10 ETH start, ~$2070/ETH) */
121
+ Liquid: [
122
+ {
123
+ tickLower: -230400,
124
+ // ~$20K starting
125
+ tickUpper: -198600,
126
+ // ~$500K
127
+ positionBps: 4e3
128
+ // 40%
129
+ },
130
+ {
131
+ tickLower: -198600,
132
+ // ~$500K
133
+ tickUpper: -168600,
134
+ // ~$10M
135
+ positionBps: 5e3
136
+ // 50%
137
+ },
138
+ {
139
+ tickLower: -168600,
140
+ // ~$10M
141
+ tickUpper: -122600,
142
+ // ~$1B
143
+ positionBps: 1e3
144
+ // 10%
145
+ }
146
+ ]
147
+ };
148
+ var DEFAULTS = {
149
+ HOOK: ADDRESSES.HOOK_STATIC_FEE_V2,
150
+ TICK_SPACING: 200,
151
+ TICK_IF_TOKEN0_IS_LIQUID: -230400,
152
+ /** Static fee on buys (ETH → token): 1% (100 bps). Fees collected in ETH. */
153
+ PAIRED_FEE_BPS: 100,
154
+ /** Static fee on sells (token → ETH): 0%. No fees in liquid token. */
155
+ LIQUID_FEE_BPS: 0,
156
+ /** MEV module: Sniper Auction V2 */
157
+ MEV_MODULE: ADDRESSES.SNIPER_AUCTION_V2,
158
+ /** Sniper auction starting fee: 80% (800,000 uniBps) */
159
+ SNIPER_STARTING_FEE: 8e5,
160
+ /** Sniper auction ending fee: 40% (400,000 uniBps) */
161
+ SNIPER_ENDING_FEE: 4e5,
162
+ /** Sniper auction decay period: 32 seconds */
163
+ SNIPER_SECONDS_TO_DECAY: 32
164
+ };
91
165
  var DEFAULT_CHAIN = import_chains.base;
92
166
  var DEFAULT_CHAIN_ID = 8453;
167
+ var DEFAULT_RPC_URL = "https://base.drpc.org";
168
+
169
+ // src/utils/encoding.ts
170
+ var import_viem = require("viem");
171
+ var PoolInitializationDataAbi = [
172
+ {
173
+ type: "tuple",
174
+ components: [
175
+ { name: "extension", type: "address" },
176
+ { name: "extensionData", type: "bytes" },
177
+ { name: "feeData", type: "bytes" }
178
+ ]
179
+ }
180
+ ];
181
+ var StaticFeeInitAbi = [
182
+ { type: "uint24" },
183
+ { type: "uint24" }
184
+ ];
185
+ var SniperAuctionInitAbi = [
186
+ {
187
+ type: "tuple",
188
+ components: [
189
+ { name: "startingFee", type: "uint24" },
190
+ { name: "endingFee", type: "uint24" },
191
+ { name: "secondsToDecay", type: "uint256" }
192
+ ]
193
+ }
194
+ ];
195
+ function encodeStaticFeePoolData(liquidFeeBps, pairedFeeBps, extension = import_viem.zeroAddress, extensionData = "0x") {
196
+ const feeData = (0, import_viem.encodeAbiParameters)(StaticFeeInitAbi, [
197
+ liquidFeeBps * 100,
198
+ pairedFeeBps * 100
199
+ ]);
200
+ return (0, import_viem.encodeAbiParameters)(PoolInitializationDataAbi, [
201
+ {
202
+ extension,
203
+ extensionData,
204
+ feeData
205
+ }
206
+ ]);
207
+ }
208
+ var DynamicFeeInitAbi = [
209
+ { type: "uint24" },
210
+ // baseFee (uniBps)
211
+ { type: "uint24" },
212
+ // maxFee (uniBps)
213
+ { type: "uint256" },
214
+ // referenceTickFilterPeriod
215
+ { type: "uint256" },
216
+ // resetPeriod
217
+ { type: "int24" },
218
+ // resetTickFilter
219
+ { type: "uint256" },
220
+ // feeControlNumerator
221
+ { type: "uint24" }
222
+ // decayFilterBps
223
+ ];
224
+ function encodeDynamicFeePoolData(config, extension = import_viem.zeroAddress, extensionData = "0x") {
225
+ const feeData = (0, import_viem.encodeAbiParameters)(DynamicFeeInitAbi, [
226
+ config.baseFeeBps * 100,
227
+ config.maxFeeBps * 100,
228
+ BigInt(config.referenceTickFilterPeriod),
229
+ BigInt(config.resetPeriod),
230
+ config.resetTickFilter,
231
+ config.feeControlNumerator,
232
+ config.decayFilterBps
233
+ ]);
234
+ return (0, import_viem.encodeAbiParameters)(PoolInitializationDataAbi, [
235
+ {
236
+ extension,
237
+ extensionData,
238
+ feeData
239
+ }
240
+ ]);
241
+ }
242
+ function encodeSniperAuctionData(config) {
243
+ if (config.startingFee <= config.endingFee) {
244
+ throw new Error("startingFee must be greater than endingFee");
245
+ }
246
+ if (config.secondsToDecay <= 0) {
247
+ throw new Error("secondsToDecay must be positive");
248
+ }
249
+ return (0, import_viem.encodeAbiParameters)(SniperAuctionInitAbi, [
250
+ {
251
+ startingFee: config.startingFee,
252
+ endingFee: config.endingFee,
253
+ secondsToDecay: BigInt(config.secondsToDecay)
254
+ }
255
+ ]);
256
+ }
93
257
 
94
258
  // src/abis/LiquidFactory.ts
95
259
  var LiquidFactoryAbi = [
@@ -709,6 +873,52 @@ var LiquidLpLockerAbi = [
709
873
  }
710
874
  ];
711
875
 
876
+ // src/abis/LiquidToken.ts
877
+ var LiquidTokenAbi = [
878
+ {
879
+ type: "function",
880
+ name: "updateImage",
881
+ inputs: [{ name: "image_", type: "string" }],
882
+ outputs: [],
883
+ stateMutability: "nonpayable"
884
+ },
885
+ {
886
+ type: "function",
887
+ name: "updateMetadata",
888
+ inputs: [{ name: "metadata_", type: "string" }],
889
+ outputs: [],
890
+ stateMutability: "nonpayable"
891
+ },
892
+ {
893
+ type: "function",
894
+ name: "updateAdmin",
895
+ inputs: [{ name: "admin_", type: "address" }],
896
+ outputs: [],
897
+ stateMutability: "nonpayable"
898
+ },
899
+ {
900
+ type: "event",
901
+ name: "UpdateImage",
902
+ inputs: [{ name: "image", type: "string", indexed: false }],
903
+ anonymous: false
904
+ },
905
+ {
906
+ type: "event",
907
+ name: "UpdateMetadata",
908
+ inputs: [{ name: "metadata", type: "string", indexed: false }],
909
+ anonymous: false
910
+ },
911
+ {
912
+ type: "event",
913
+ name: "UpdateAdmin",
914
+ inputs: [
915
+ { name: "oldAdmin", type: "address", indexed: false },
916
+ { name: "newAdmin", type: "address", indexed: false }
917
+ ],
918
+ anonymous: false
919
+ }
920
+ ];
921
+
712
922
  // src/abis/ERC20.ts
713
923
  var ERC20Abi = [
714
924
  {
@@ -792,7 +1002,7 @@ var LiquidSDK = class {
792
1002
  * The paired token must be WETH for simple dev buys.
793
1003
  */
794
1004
  buildDevBuyExtension(devBuy) {
795
- const extensionData = (0, import_viem.encodeAbiParameters)(
1005
+ const extensionData = (0, import_viem2.encodeAbiParameters)(
796
1006
  [
797
1007
  {
798
1008
  type: "tuple",
@@ -816,11 +1026,11 @@ var LiquidSDK = class {
816
1026
  [
817
1027
  {
818
1028
  pairedTokenPoolKey: {
819
- currency0: import_viem.zeroAddress,
820
- currency1: import_viem.zeroAddress,
1029
+ currency0: import_viem2.zeroAddress,
1030
+ currency1: import_viem2.zeroAddress,
821
1031
  fee: 0,
822
1032
  tickSpacing: 0,
823
- hooks: import_viem.zeroAddress
1033
+ hooks: import_viem2.zeroAddress
824
1034
  },
825
1035
  pairedTokenAmountOutMinimum: 0n,
826
1036
  recipient: devBuy.recipient
@@ -834,6 +1044,97 @@ var LiquidSDK = class {
834
1044
  extensionData
835
1045
  };
836
1046
  }
1047
+ // ── Validation ─────────────────────────────────────────────────
1048
+ /**
1049
+ * Validate a DeploymentConfig before sending to the contract.
1050
+ * Catches common mistakes client-side with clear error messages.
1051
+ */
1052
+ validateDeploymentConfig(config) {
1053
+ const { lockerConfig, extensionConfigs } = config;
1054
+ const { tickSpacing } = config.poolConfig;
1055
+ const posLen = lockerConfig.tickLower.length;
1056
+ if (lockerConfig.tickUpper.length !== posLen || lockerConfig.positionBps.length !== posLen) {
1057
+ throw new Error(
1058
+ `tickLower (${posLen}), tickUpper (${lockerConfig.tickUpper.length}), and positionBps (${lockerConfig.positionBps.length}) arrays must be the same length`
1059
+ );
1060
+ }
1061
+ if (posLen === 0) {
1062
+ throw new Error("At least one position is required");
1063
+ }
1064
+ if (posLen > 7) {
1065
+ throw new Error(`Maximum 7 positions allowed, got ${posLen}`);
1066
+ }
1067
+ const posBpsSum = lockerConfig.positionBps.reduce((s, b) => s + b, 0);
1068
+ if (posBpsSum !== FEE.BPS) {
1069
+ throw new Error(
1070
+ `positionBps must sum to ${FEE.BPS} (100%), got ${posBpsSum}`
1071
+ );
1072
+ }
1073
+ for (let i = 0; i < posLen; i++) {
1074
+ if (lockerConfig.tickLower[i] >= lockerConfig.tickUpper[i]) {
1075
+ throw new Error(
1076
+ `Position ${i}: tickLower (${lockerConfig.tickLower[i]}) must be less than tickUpper (${lockerConfig.tickUpper[i]})`
1077
+ );
1078
+ }
1079
+ }
1080
+ for (let i = 0; i < posLen; i++) {
1081
+ if (lockerConfig.tickLower[i] % tickSpacing !== 0) {
1082
+ throw new Error(
1083
+ `Position ${i}: tickLower (${lockerConfig.tickLower[i]}) is not a multiple of tickSpacing (${tickSpacing})`
1084
+ );
1085
+ }
1086
+ if (lockerConfig.tickUpper[i] % tickSpacing !== 0) {
1087
+ throw new Error(
1088
+ `Position ${i}: tickUpper (${lockerConfig.tickUpper[i]}) is not a multiple of tickSpacing (${tickSpacing})`
1089
+ );
1090
+ }
1091
+ }
1092
+ const startingTick = config.poolConfig.tickIfToken0IsLiquid;
1093
+ for (let i = 0; i < posLen; i++) {
1094
+ if (lockerConfig.tickLower[i] < startingTick) {
1095
+ throw new Error(
1096
+ `Position ${i}: tickLower (${lockerConfig.tickLower[i]}) is below the starting tick (${startingTick})`
1097
+ );
1098
+ }
1099
+ }
1100
+ const touchesStart = lockerConfig.tickLower.some(
1101
+ (t) => t === startingTick
1102
+ );
1103
+ if (!touchesStart) {
1104
+ throw new Error(
1105
+ `At least one position's tickLower must equal tickIfToken0IsLiquid (${startingTick})`
1106
+ );
1107
+ }
1108
+ const rwdLen = lockerConfig.rewardAdmins.length;
1109
+ if (lockerConfig.rewardRecipients.length !== rwdLen || lockerConfig.rewardBps.length !== rwdLen) {
1110
+ throw new Error(
1111
+ `rewardAdmins (${rwdLen}), rewardRecipients (${lockerConfig.rewardRecipients.length}), and rewardBps (${lockerConfig.rewardBps.length}) arrays must be the same length`
1112
+ );
1113
+ }
1114
+ if (rwdLen === 0) {
1115
+ throw new Error("At least one reward recipient is required");
1116
+ }
1117
+ const rwdBpsSum = lockerConfig.rewardBps.reduce((s, b) => s + b, 0);
1118
+ if (rwdBpsSum !== FEE.BPS) {
1119
+ throw new Error(
1120
+ `rewardBps must sum to ${FEE.BPS} (100%), got ${rwdBpsSum}`
1121
+ );
1122
+ }
1123
+ if (extensionConfigs.length > TOKEN.MAX_EXTENSIONS) {
1124
+ throw new Error(
1125
+ `Maximum ${TOKEN.MAX_EXTENSIONS} extensions allowed, got ${extensionConfigs.length}`
1126
+ );
1127
+ }
1128
+ const extBpsSum = extensionConfigs.reduce(
1129
+ (s, e) => s + e.extensionBps,
1130
+ 0
1131
+ );
1132
+ if (extBpsSum > TOKEN.MAX_EXTENSION_BPS) {
1133
+ throw new Error(
1134
+ `Total extensionBps (${extBpsSum}) exceeds maximum (${TOKEN.MAX_EXTENSION_BPS})`
1135
+ );
1136
+ }
1137
+ }
837
1138
  // ── Token Deployment ─────────────────────────────────────────────
838
1139
  async deployToken(params) {
839
1140
  if (!this.walletClient?.account) {
@@ -845,8 +1146,8 @@ var LiquidSDK = class {
845
1146
  tokenAdmin: params.tokenAdmin ?? account,
846
1147
  name: params.name,
847
1148
  symbol: params.symbol,
848
- salt: params.salt ?? (0, import_viem.keccak256)(
849
- (0, import_viem.encodePacked)(
1149
+ salt: params.salt ?? (0, import_viem2.keccak256)(
1150
+ (0, import_viem2.encodePacked)(
850
1151
  ["string", "string", "uint256"],
851
1152
  [params.name, params.symbol, BigInt(Date.now())]
852
1153
  )
@@ -857,25 +1158,32 @@ var LiquidSDK = class {
857
1158
  originatingChainId: BigInt(DEFAULT_CHAIN_ID)
858
1159
  },
859
1160
  poolConfig: {
860
- hook: params.hook ?? ADDRESSES.HOOK_DYNAMIC_FEE_V2,
1161
+ hook: params.hook ?? DEFAULTS.HOOK,
861
1162
  pairedToken: params.pairedToken ?? EXTERNAL.WETH,
862
- tickIfToken0IsLiquid: params.tickIfToken0IsLiquid ?? -198720,
863
- tickSpacing: params.tickSpacing ?? 60,
864
- poolData: params.poolData ?? "0x"
1163
+ tickIfToken0IsLiquid: params.tickIfToken0IsLiquid ?? DEFAULTS.TICK_IF_TOKEN0_IS_LIQUID,
1164
+ tickSpacing: params.tickSpacing ?? DEFAULTS.TICK_SPACING,
1165
+ poolData: params.poolData ?? encodeStaticFeePoolData(
1166
+ DEFAULTS.LIQUID_FEE_BPS,
1167
+ DEFAULTS.PAIRED_FEE_BPS
1168
+ )
865
1169
  },
866
1170
  lockerConfig: {
867
1171
  locker: params.locker ?? ADDRESSES.LP_LOCKER,
868
1172
  rewardAdmins: params.rewardAdmins ?? [account],
869
1173
  rewardRecipients: params.rewardRecipients ?? [account],
870
1174
  rewardBps: params.rewardBps ?? [1e4],
871
- tickLower: params.tickLower ?? [-887220],
872
- tickUpper: params.tickUpper ?? [887220],
873
- positionBps: params.positionBps ?? [1e4],
1175
+ tickLower: params.tickLower ?? POOL_POSITIONS.Liquid.map((p) => p.tickLower),
1176
+ tickUpper: params.tickUpper ?? POOL_POSITIONS.Liquid.map((p) => p.tickUpper),
1177
+ positionBps: params.positionBps ?? POOL_POSITIONS.Liquid.map((p) => p.positionBps),
874
1178
  lockerData: params.lockerData ?? "0x"
875
1179
  },
876
1180
  mevModuleConfig: {
877
- mevModule: params.mevModule ?? ADDRESSES.MEV_BLOCK_DELAY,
878
- mevModuleData: params.mevModuleData ?? "0x"
1181
+ mevModule: params.mevModule ?? DEFAULTS.MEV_MODULE,
1182
+ mevModuleData: params.mevModuleData ?? encodeSniperAuctionData({
1183
+ startingFee: DEFAULTS.SNIPER_STARTING_FEE,
1184
+ endingFee: DEFAULTS.SNIPER_ENDING_FEE,
1185
+ secondsToDecay: DEFAULTS.SNIPER_SECONDS_TO_DECAY
1186
+ })
879
1187
  },
880
1188
  extensionConfigs: [...params.extensions ?? []]
881
1189
  };
@@ -884,6 +1192,7 @@ var LiquidSDK = class {
884
1192
  this.buildDevBuyExtension(params.devBuy)
885
1193
  );
886
1194
  }
1195
+ this.validateDeploymentConfig(deploymentConfig);
887
1196
  const msgValue = deploymentConfig.extensionConfigs.reduce(
888
1197
  (sum, ext) => sum + ext.msgValue,
889
1198
  0n
@@ -902,7 +1211,7 @@ var LiquidSDK = class {
902
1211
  });
903
1212
  const tokenCreatedLog = receipt.logs.find((log) => {
904
1213
  try {
905
- const decoded2 = (0, import_viem.decodeEventLog)({
1214
+ const decoded2 = (0, import_viem2.decodeEventLog)({
906
1215
  abi: LiquidFactoryAbi,
907
1216
  data: log.data,
908
1217
  topics: log.topics
@@ -915,14 +1224,14 @@ var LiquidSDK = class {
915
1224
  if (!tokenCreatedLog) {
916
1225
  throw new Error("TokenCreated event not found in transaction receipt");
917
1226
  }
918
- const decoded = (0, import_viem.decodeEventLog)({
1227
+ const decoded = (0, import_viem2.decodeEventLog)({
919
1228
  abi: LiquidFactoryAbi,
920
1229
  data: tokenCreatedLog.data,
921
1230
  topics: tokenCreatedLog.topics
922
1231
  });
923
1232
  const args = decoded.args;
924
1233
  return {
925
- tokenAddress: (0, import_viem.getAddress)(args.tokenAddress),
1234
+ tokenAddress: (0, import_viem2.getAddress)(args.tokenAddress),
926
1235
  txHash,
927
1236
  event: {
928
1237
  msgSender: args.msgSender,
@@ -1070,7 +1379,7 @@ var LiquidSDK = class {
1070
1379
  if (!this.walletClient?.account) {
1071
1380
  throw new Error("walletClient with account required for claimFees");
1072
1381
  }
1073
- return this.walletClient.writeContract({
1382
+ return await this.walletClient.writeContract({
1074
1383
  address: ADDRESSES.FEE_LOCKER,
1075
1384
  abi: LiquidFeeLockerAbi,
1076
1385
  functionName: "claim",
@@ -1109,7 +1418,7 @@ var LiquidSDK = class {
1109
1418
  if (!this.walletClient?.account) {
1110
1419
  throw new Error("walletClient with account required for claimVault");
1111
1420
  }
1112
- return this.walletClient.writeContract({
1421
+ return await this.walletClient.writeContract({
1113
1422
  address: ADDRESSES.VAULT,
1114
1423
  abi: LiquidVaultAbi,
1115
1424
  functionName: "claim",
@@ -1238,7 +1547,7 @@ var LiquidSDK = class {
1238
1547
  if (!this.walletClient?.account) {
1239
1548
  throw new Error("walletClient with account required for claimAirdrop");
1240
1549
  }
1241
- return this.walletClient.writeContract({
1550
+ return await this.walletClient.writeContract({
1242
1551
  address: ADDRESSES.AIRDROP_V2,
1243
1552
  abi: LiquidAirdropV2Abi,
1244
1553
  functionName: "claim",
@@ -1272,7 +1581,7 @@ var LiquidSDK = class {
1272
1581
  throw new Error("walletClient with account required for collectRewards");
1273
1582
  }
1274
1583
  const locker = lockerAddress ?? ADDRESSES.LP_LOCKER;
1275
- return this.walletClient.writeContract({
1584
+ return await this.walletClient.writeContract({
1276
1585
  address: locker,
1277
1586
  abi: LiquidLpLockerAbi,
1278
1587
  functionName: "collectRewards",
@@ -1288,7 +1597,7 @@ var LiquidSDK = class {
1288
1597
  );
1289
1598
  }
1290
1599
  const locker = lockerAddress ?? ADDRESSES.LP_LOCKER;
1291
- return this.walletClient.writeContract({
1600
+ return await this.walletClient.writeContract({
1292
1601
  address: locker,
1293
1602
  abi: LiquidLpLockerAbi,
1294
1603
  functionName: "collectRewardsWithoutUnlock",
@@ -1304,7 +1613,7 @@ var LiquidSDK = class {
1304
1613
  );
1305
1614
  }
1306
1615
  const locker = lockerAddress ?? ADDRESSES.LP_LOCKER;
1307
- return this.walletClient.writeContract({
1616
+ return await this.walletClient.writeContract({
1308
1617
  address: locker,
1309
1618
  abi: LiquidLpLockerAbi,
1310
1619
  functionName: "updateRewardRecipient",
@@ -1338,12 +1647,347 @@ var LiquidSDK = class {
1338
1647
  args: [poolId]
1339
1648
  });
1340
1649
  }
1650
+ // ── Token Metadata Updates ──────────────────────────────────────────
1651
+ /**
1652
+ * Update a token's image. Must be called by the token admin.
1653
+ */
1654
+ async updateImage(tokenAddress, newImage) {
1655
+ if (!this.walletClient?.account) {
1656
+ throw new Error("walletClient with account required for updateImage");
1657
+ }
1658
+ return await this.walletClient.writeContract({
1659
+ address: tokenAddress,
1660
+ abi: LiquidTokenAbi,
1661
+ functionName: "updateImage",
1662
+ args: [newImage],
1663
+ chain: import_chains2.base,
1664
+ account: this.walletClient.account
1665
+ });
1666
+ }
1667
+ /**
1668
+ * Update a token's metadata. Must be called by the token admin.
1669
+ */
1670
+ async updateMetadata(tokenAddress, newMetadata) {
1671
+ if (!this.walletClient?.account) {
1672
+ throw new Error("walletClient with account required for updateMetadata");
1673
+ }
1674
+ return await this.walletClient.writeContract({
1675
+ address: tokenAddress,
1676
+ abi: LiquidTokenAbi,
1677
+ functionName: "updateMetadata",
1678
+ args: [newMetadata],
1679
+ chain: import_chains2.base,
1680
+ account: this.walletClient.account
1681
+ });
1682
+ }
1683
+ // ── Token Discovery ─────────────────────────────────────────────────
1684
+ /**
1685
+ * Get all tokens deployed by a specific address by querying TokenCreated events.
1686
+ * @param deployer - The address that deployed the tokens (msgSender)
1687
+ * @param fromBlock - Starting block to search from (defaults to 0n)
1688
+ * @param toBlock - Ending block to search to (defaults to 'latest')
1689
+ */
1690
+ async getDeployedTokens(deployer, fromBlock, toBlock) {
1691
+ const logs = await this.publicClient.getLogs({
1692
+ address: ADDRESSES.FACTORY,
1693
+ event: (0, import_viem2.parseAbiItem)(
1694
+ "event TokenCreated(address msgSender, address indexed tokenAddress, address indexed tokenAdmin, string tokenImage, string tokenName, string tokenSymbol, string tokenMetadata, string tokenContext, int24 startingTick, address poolHook, bytes32 poolId, address pairedToken, address locker, address mevModule, uint256 extensionsSupply, address[] extensions)"
1695
+ ),
1696
+ fromBlock: fromBlock ?? 0n,
1697
+ toBlock: toBlock ?? "latest"
1698
+ });
1699
+ return logs.filter((log) => {
1700
+ const sender = log.args.msgSender;
1701
+ return sender && (0, import_viem2.getAddress)(sender) === (0, import_viem2.getAddress)(deployer);
1702
+ }).map((log) => {
1703
+ const args = log.args;
1704
+ return {
1705
+ msgSender: args.msgSender,
1706
+ tokenAddress: args.tokenAddress,
1707
+ tokenAdmin: args.tokenAdmin,
1708
+ tokenImage: args.tokenImage,
1709
+ tokenName: args.tokenName,
1710
+ tokenSymbol: args.tokenSymbol,
1711
+ tokenMetadata: args.tokenMetadata,
1712
+ tokenContext: args.tokenContext,
1713
+ startingTick: args.startingTick,
1714
+ poolHook: args.poolHook,
1715
+ poolId: args.poolId,
1716
+ pairedToken: args.pairedToken,
1717
+ locker: args.locker,
1718
+ mevModule: args.mevModule,
1719
+ extensionsSupply: args.extensionsSupply,
1720
+ extensions: args.extensions
1721
+ };
1722
+ });
1723
+ }
1341
1724
  };
1725
+
1726
+ // src/abis/LiquidUniv4EthDevBuy.ts
1727
+ var LiquidUniv4EthDevBuyAbi = [
1728
+ {
1729
+ type: "constructor",
1730
+ inputs: [
1731
+ { name: "factory_", type: "address" },
1732
+ { name: "weth_", type: "address" },
1733
+ { name: "universalRouter_", type: "address" },
1734
+ { name: "permit2_", type: "address" }
1735
+ ],
1736
+ stateMutability: "nonpayable"
1737
+ },
1738
+ {
1739
+ type: "function",
1740
+ name: "factory",
1741
+ inputs: [],
1742
+ outputs: [{ name: "", type: "address" }],
1743
+ stateMutability: "view"
1744
+ },
1745
+ {
1746
+ type: "function",
1747
+ name: "weth",
1748
+ inputs: [],
1749
+ outputs: [{ name: "", type: "address" }],
1750
+ stateMutability: "view"
1751
+ },
1752
+ {
1753
+ type: "function",
1754
+ name: "universalRouter",
1755
+ inputs: [],
1756
+ outputs: [{ name: "", type: "address" }],
1757
+ stateMutability: "view"
1758
+ },
1759
+ {
1760
+ type: "function",
1761
+ name: "permit2",
1762
+ inputs: [],
1763
+ outputs: [{ name: "", type: "address" }],
1764
+ stateMutability: "view"
1765
+ },
1766
+ {
1767
+ type: "function",
1768
+ name: "receiveTokens",
1769
+ inputs: [
1770
+ {
1771
+ name: "deploymentConfig",
1772
+ type: "tuple",
1773
+ components: [
1774
+ {
1775
+ name: "tokenConfig",
1776
+ type: "tuple",
1777
+ components: [
1778
+ { name: "tokenAdmin", type: "address" },
1779
+ { name: "name", type: "string" },
1780
+ { name: "symbol", type: "string" },
1781
+ { name: "salt", type: "bytes32" },
1782
+ { name: "image", type: "string" },
1783
+ { name: "metadata", type: "string" },
1784
+ { name: "context", type: "string" },
1785
+ { name: "originatingChainId", type: "uint256" }
1786
+ ]
1787
+ },
1788
+ {
1789
+ name: "poolConfig",
1790
+ type: "tuple",
1791
+ components: [
1792
+ { name: "hook", type: "address" },
1793
+ { name: "pairedToken", type: "address" },
1794
+ { name: "tickIfToken0IsLiquid", type: "int24" },
1795
+ { name: "tickSpacing", type: "int24" },
1796
+ { name: "poolData", type: "bytes" }
1797
+ ]
1798
+ },
1799
+ {
1800
+ name: "lockerConfig",
1801
+ type: "tuple",
1802
+ components: [
1803
+ { name: "locker", type: "address" },
1804
+ { name: "rewardAdmins", type: "address[]" },
1805
+ { name: "rewardRecipients", type: "address[]" },
1806
+ { name: "rewardBps", type: "uint16[]" },
1807
+ { name: "tickLower", type: "int24[]" },
1808
+ { name: "tickUpper", type: "int24[]" },
1809
+ { name: "positionBps", type: "uint16[]" },
1810
+ { name: "lockerData", type: "bytes" }
1811
+ ]
1812
+ },
1813
+ {
1814
+ name: "mevModuleConfig",
1815
+ type: "tuple",
1816
+ components: [
1817
+ { name: "mevModule", type: "address" },
1818
+ { name: "mevModuleData", type: "bytes" }
1819
+ ]
1820
+ },
1821
+ {
1822
+ name: "extensionConfigs",
1823
+ type: "tuple[]",
1824
+ components: [
1825
+ { name: "extension", type: "address" },
1826
+ { name: "msgValue", type: "uint256" },
1827
+ { name: "extensionBps", type: "uint16" },
1828
+ { name: "extensionData", type: "bytes" }
1829
+ ]
1830
+ }
1831
+ ]
1832
+ },
1833
+ {
1834
+ name: "tokenPoolKey",
1835
+ type: "tuple",
1836
+ components: [
1837
+ { name: "currency0", type: "address" },
1838
+ { name: "currency1", type: "address" },
1839
+ { name: "fee", type: "uint24" },
1840
+ { name: "tickSpacing", type: "int24" },
1841
+ { name: "hooks", type: "address" }
1842
+ ]
1843
+ },
1844
+ { name: "token", type: "address" },
1845
+ { name: "extensionSupply", type: "uint256" },
1846
+ { name: "extensionIndex", type: "uint256" }
1847
+ ],
1848
+ outputs: [],
1849
+ stateMutability: "payable"
1850
+ },
1851
+ {
1852
+ type: "function",
1853
+ name: "supportsInterface",
1854
+ inputs: [{ name: "interfaceId", type: "bytes4" }],
1855
+ outputs: [{ name: "", type: "bool" }],
1856
+ stateMutability: "pure"
1857
+ },
1858
+ {
1859
+ type: "event",
1860
+ name: "EthDevBuy",
1861
+ inputs: [
1862
+ { name: "token", type: "address", indexed: true },
1863
+ { name: "user", type: "address", indexed: true },
1864
+ { name: "ethAmount", type: "uint256", indexed: false },
1865
+ { name: "tokenAmount", type: "uint256", indexed: false }
1866
+ ],
1867
+ anonymous: false
1868
+ },
1869
+ { type: "error", name: "InvalidEthDevBuyPercentage", inputs: [] },
1870
+ { type: "error", name: "InvalidMsgValue", inputs: [] },
1871
+ { type: "error", name: "InvalidPairedTokenPoolKey", inputs: [] },
1872
+ { type: "error", name: "ReentrancyGuardReentrantCall", inputs: [] },
1873
+ { type: "error", name: "Unauthorized", inputs: [] }
1874
+ ];
1875
+
1876
+ // src/utils/tick-math.ts
1877
+ var LOG_BASE = Math.log(1.0001);
1878
+ var DEFAULT_TICK_SPACING = 200;
1879
+ var TOTAL_SUPPLY = 1e11;
1880
+ function getTickFromMarketCapETH(marketCapETH, tickSpacing = DEFAULT_TICK_SPACING) {
1881
+ if (marketCapETH <= 0) throw new Error("marketCapETH must be positive");
1882
+ const price = marketCapETH / TOTAL_SUPPLY;
1883
+ const rawTick = Math.log(price) / LOG_BASE;
1884
+ return Math.floor(rawTick / tickSpacing) * tickSpacing;
1885
+ }
1886
+ function getTickFromMarketCapUSD(marketCapUSD, ethPriceUSD, tickSpacing = DEFAULT_TICK_SPACING) {
1887
+ if (ethPriceUSD <= 0) throw new Error("ethPriceUSD must be positive");
1888
+ return getTickFromMarketCapETH(marketCapUSD / ethPriceUSD, tickSpacing);
1889
+ }
1890
+ function marketCapFromTickETH(tick) {
1891
+ const price = Math.pow(1.0001, tick);
1892
+ return price * TOTAL_SUPPLY;
1893
+ }
1894
+ function marketCapFromTickUSD(tick, ethPriceUSD) {
1895
+ return marketCapFromTickETH(tick) * ethPriceUSD;
1896
+ }
1897
+ function getTickFromMarketCapStable(marketCap, stableDecimals, tickSpacing = DEFAULT_TICK_SPACING) {
1898
+ if (marketCap <= 0) throw new Error("marketCap must be positive");
1899
+ const price = marketCap / Math.pow(10, 29 - stableDecimals);
1900
+ const rawTick = Math.log(price) / LOG_BASE;
1901
+ return Math.floor(rawTick / tickSpacing) * tickSpacing;
1902
+ }
1903
+
1904
+ // src/utils/positions.ts
1905
+ var DEFAULT_TRANCHES_USD = [
1906
+ { upperMarketCapUSD: 5e5, supplyPct: 40 },
1907
+ { upperMarketCapUSD: 1e7, supplyPct: 50 },
1908
+ { upperMarketCapUSD: 1e9, supplyPct: 10 }
1909
+ ];
1910
+ function createPositions(startingMarketCapETH, tranches, tickSpacing = 200) {
1911
+ if (tranches.length === 0) throw new Error("At least one tranche is required");
1912
+ if (tranches.length > 7) throw new Error("Maximum 7 positions allowed");
1913
+ const totalPct = tranches.reduce((sum, t) => sum + t.supplyPct, 0);
1914
+ if (Math.abs(totalPct - 100) > 0.01) {
1915
+ throw new Error(`Tranche percentages must sum to 100, got ${totalPct}`);
1916
+ }
1917
+ for (let i = 1; i < tranches.length; i++) {
1918
+ if (tranches[i].upperMarketCapETH <= tranches[i - 1].upperMarketCapETH) {
1919
+ throw new Error("Tranches must be ordered by ascending upperMarketCapETH");
1920
+ }
1921
+ }
1922
+ const startingTick = getTickFromMarketCapETH(startingMarketCapETH, tickSpacing);
1923
+ const tickLower = [];
1924
+ const tickUpper = [];
1925
+ const positionBps = [];
1926
+ let prevTick = startingTick;
1927
+ for (const tranche of tranches) {
1928
+ const upperTick = getTickFromMarketCapETH(tranche.upperMarketCapETH, tickSpacing);
1929
+ if (upperTick <= prevTick) {
1930
+ throw new Error(
1931
+ `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.`
1932
+ );
1933
+ }
1934
+ tickLower.push(prevTick);
1935
+ tickUpper.push(upperTick);
1936
+ positionBps.push(Math.round(tranche.supplyPct * 100));
1937
+ prevTick = upperTick;
1938
+ }
1939
+ return { tickLower, tickUpper, positionBps };
1940
+ }
1941
+ function createPositionsUSD(startingMarketCapUSD, ethPriceUSD, tranches, tickSpacing = 200) {
1942
+ if (ethPriceUSD <= 0) throw new Error("ethPriceUSD must be positive");
1943
+ const ethTranches = tranches.map((t) => ({
1944
+ upperMarketCapETH: t.upperMarketCapUSD / ethPriceUSD,
1945
+ supplyPct: t.supplyPct
1946
+ }));
1947
+ return createPositions(
1948
+ startingMarketCapUSD / ethPriceUSD,
1949
+ ethTranches,
1950
+ tickSpacing
1951
+ );
1952
+ }
1953
+ function createDefaultPositions(startingMarketCapUSD, ethPriceUSD, tickSpacing = 200) {
1954
+ const positions = createPositionsUSD(
1955
+ startingMarketCapUSD,
1956
+ ethPriceUSD,
1957
+ DEFAULT_TRANCHES_USD,
1958
+ tickSpacing
1959
+ );
1960
+ return {
1961
+ ...positions,
1962
+ tickIfToken0IsLiquid: positions.tickLower[0]
1963
+ };
1964
+ }
1965
+ function describePositions(positions, ethPriceUSD) {
1966
+ return positions.tickLower.map((_, i) => {
1967
+ const lowerETH = Math.pow(1.0001, positions.tickLower[i]) * 1e11;
1968
+ const upperETH = Math.pow(1.0001, positions.tickUpper[i]) * 1e11;
1969
+ return {
1970
+ index: i,
1971
+ tickLower: positions.tickLower[i],
1972
+ tickUpper: positions.tickUpper[i],
1973
+ supplyPct: positions.positionBps[i] / 100,
1974
+ marketCapLowerETH: lowerETH,
1975
+ marketCapUpperETH: upperETH,
1976
+ ...ethPriceUSD != null && {
1977
+ marketCapLowerUSD: lowerETH * ethPriceUSD,
1978
+ marketCapUpperUSD: upperETH * ethPriceUSD
1979
+ }
1980
+ };
1981
+ });
1982
+ }
1342
1983
  // Annotate the CommonJS export names for ESM import in node:
1343
1984
  0 && (module.exports = {
1344
1985
  ADDRESSES,
1986
+ DEFAULTS,
1345
1987
  DEFAULT_CHAIN,
1346
1988
  DEFAULT_CHAIN_ID,
1989
+ DEFAULT_RPC_URL,
1990
+ DEFAULT_TRANCHES_USD,
1347
1991
  ERC20Abi,
1348
1992
  EXTERNAL,
1349
1993
  FEE,
@@ -1357,7 +2001,22 @@ var LiquidSDK = class {
1357
2001
  LiquidSDK,
1358
2002
  LiquidSniperAuctionV2Abi,
1359
2003
  LiquidSniperUtilV2Abi,
2004
+ LiquidTokenAbi,
2005
+ LiquidUniv4EthDevBuyAbi,
1360
2006
  LiquidVaultAbi,
1361
- TOKEN
2007
+ POOL_POSITIONS,
2008
+ TOKEN,
2009
+ createDefaultPositions,
2010
+ createPositions,
2011
+ createPositionsUSD,
2012
+ describePositions,
2013
+ encodeDynamicFeePoolData,
2014
+ encodeSniperAuctionData,
2015
+ encodeStaticFeePoolData,
2016
+ getTickFromMarketCapETH,
2017
+ getTickFromMarketCapStable,
2018
+ getTickFromMarketCapUSD,
2019
+ marketCapFromTickETH,
2020
+ marketCapFromTickUSD
1362
2021
  });
1363
2022
  //# sourceMappingURL=index.js.map