liquid-sdk 1.1.0 → 1.3.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.mjs CHANGED
@@ -5,6 +5,7 @@ import {
5
5
  encodePacked,
6
6
  keccak256,
7
7
  getAddress,
8
+ parseAbiItem,
8
9
  zeroAddress as zeroAddress2
9
10
  } from "viem";
10
11
  import { base as base2 } from "viem/chains";
@@ -93,6 +94,8 @@ var POOL_POSITIONS = {
93
94
  };
94
95
  var DEFAULTS = {
95
96
  HOOK: ADDRESSES.HOOK_STATIC_FEE_V2,
97
+ /** LP Locker with fee conversion (converts fees to ETH before distributing) */
98
+ LOCKER: ADDRESSES.LP_LOCKER_FEE_CONVERSION,
96
99
  TICK_SPACING: 200,
97
100
  TICK_IF_TOKEN0_IS_LIQUID: -230400,
98
101
  /** Static fee on buys (ETH → token): 1% (100 bps). Fees collected in ETH. */
@@ -201,6 +204,68 @@ function encodeSniperAuctionData(config) {
201
204
  ]);
202
205
  }
203
206
 
207
+ // src/utils/context.ts
208
+ function buildContext(input) {
209
+ const ctx = {
210
+ interface: input?.interface ?? "SDK"
211
+ };
212
+ if (input?.platform !== void 0) ctx.platform = input.platform;
213
+ if (input?.messageId !== void 0) ctx.messageId = input.messageId;
214
+ if (input?.id !== void 0) ctx.id = input.id;
215
+ return JSON.stringify(ctx);
216
+ }
217
+ function buildMetadata(input) {
218
+ if (!input) return "{}";
219
+ const meta = {};
220
+ if (input.description !== void 0) meta.description = input.description;
221
+ if (input.socialMediaUrls !== void 0 && input.socialMediaUrls.length > 0) {
222
+ meta.socialMediaUrls = input.socialMediaUrls;
223
+ }
224
+ if (input.auditUrls !== void 0 && input.auditUrls.length > 0) {
225
+ meta.auditUrls = input.auditUrls;
226
+ }
227
+ return JSON.stringify(meta);
228
+ }
229
+ function parseContext(contextString) {
230
+ if (!contextString || contextString === "") return null;
231
+ try {
232
+ const parsed = JSON.parse(contextString);
233
+ if (typeof parsed !== "object" || parsed === null) return null;
234
+ return {
235
+ interface: typeof parsed.interface === "string" ? parsed.interface : "unknown",
236
+ ...typeof parsed.platform === "string" && { platform: parsed.platform },
237
+ ...typeof parsed.messageId === "string" && { messageId: parsed.messageId },
238
+ ...typeof parsed.id === "string" && { id: parsed.id }
239
+ };
240
+ } catch {
241
+ return null;
242
+ }
243
+ }
244
+ function parseMetadata(metadataString) {
245
+ if (!metadataString || metadataString === "") return null;
246
+ try {
247
+ const parsed = JSON.parse(metadataString);
248
+ if (typeof parsed !== "object" || parsed === null) return null;
249
+ const result = {};
250
+ if (typeof parsed.description === "string") {
251
+ result.description = parsed.description;
252
+ }
253
+ if (Array.isArray(parsed.socialMediaUrls)) {
254
+ result.socialMediaUrls = parsed.socialMediaUrls.filter(
255
+ (item) => typeof item === "object" && item !== null && typeof item.platform === "string" && typeof item.url === "string"
256
+ );
257
+ }
258
+ if (Array.isArray(parsed.auditUrls)) {
259
+ result.auditUrls = parsed.auditUrls.filter(
260
+ (item) => typeof item === "string"
261
+ );
262
+ }
263
+ return result;
264
+ } catch {
265
+ return null;
266
+ }
267
+ }
268
+
204
269
  // src/abis/LiquidFactory.ts
205
270
  var LiquidFactoryAbi = [
206
271
  {
@@ -819,6 +884,52 @@ var LiquidLpLockerAbi = [
819
884
  }
820
885
  ];
821
886
 
887
+ // src/abis/LiquidToken.ts
888
+ var LiquidTokenAbi = [
889
+ {
890
+ type: "function",
891
+ name: "updateImage",
892
+ inputs: [{ name: "image_", type: "string" }],
893
+ outputs: [],
894
+ stateMutability: "nonpayable"
895
+ },
896
+ {
897
+ type: "function",
898
+ name: "updateMetadata",
899
+ inputs: [{ name: "metadata_", type: "string" }],
900
+ outputs: [],
901
+ stateMutability: "nonpayable"
902
+ },
903
+ {
904
+ type: "function",
905
+ name: "updateAdmin",
906
+ inputs: [{ name: "admin_", type: "address" }],
907
+ outputs: [],
908
+ stateMutability: "nonpayable"
909
+ },
910
+ {
911
+ type: "event",
912
+ name: "UpdateImage",
913
+ inputs: [{ name: "image", type: "string", indexed: false }],
914
+ anonymous: false
915
+ },
916
+ {
917
+ type: "event",
918
+ name: "UpdateMetadata",
919
+ inputs: [{ name: "metadata", type: "string", indexed: false }],
920
+ anonymous: false
921
+ },
922
+ {
923
+ type: "event",
924
+ name: "UpdateAdmin",
925
+ inputs: [
926
+ { name: "oldAdmin", type: "address", indexed: false },
927
+ { name: "newAdmin", type: "address", indexed: false }
928
+ ],
929
+ anonymous: false
930
+ }
931
+ ];
932
+
822
933
  // src/abis/ERC20.ts
823
934
  var ERC20Abi = [
824
935
  {
@@ -1054,7 +1165,7 @@ var LiquidSDK = class {
1054
1165
  ),
1055
1166
  image: params.image ?? "",
1056
1167
  metadata: params.metadata ?? "",
1057
- context: params.context ?? "",
1168
+ context: params.context ?? buildContext(),
1058
1169
  originatingChainId: BigInt(DEFAULT_CHAIN_ID)
1059
1170
  },
1060
1171
  poolConfig: {
@@ -1068,7 +1179,7 @@ var LiquidSDK = class {
1068
1179
  )
1069
1180
  },
1070
1181
  lockerConfig: {
1071
- locker: params.locker ?? ADDRESSES.LP_LOCKER,
1182
+ locker: params.locker ?? DEFAULTS.LOCKER,
1072
1183
  rewardAdmins: params.rewardAdmins ?? [account],
1073
1184
  rewardRecipients: params.rewardRecipients ?? [account],
1074
1185
  rewardBps: params.rewardBps ?? [1e4],
@@ -1458,7 +1569,7 @@ var LiquidSDK = class {
1458
1569
  }
1459
1570
  // ── LP Locker ───────────────────────────────────────────────────────
1460
1571
  async getTokenRewards(tokenAddress, lockerAddress) {
1461
- const locker = lockerAddress ?? ADDRESSES.LP_LOCKER;
1572
+ const locker = lockerAddress ?? DEFAULTS.LOCKER;
1462
1573
  const result = await this.publicClient.readContract({
1463
1574
  address: locker,
1464
1575
  abi: LiquidLpLockerAbi,
@@ -1480,7 +1591,7 @@ var LiquidSDK = class {
1480
1591
  if (!this.walletClient?.account) {
1481
1592
  throw new Error("walletClient with account required for collectRewards");
1482
1593
  }
1483
- const locker = lockerAddress ?? ADDRESSES.LP_LOCKER;
1594
+ const locker = lockerAddress ?? DEFAULTS.LOCKER;
1484
1595
  return await this.walletClient.writeContract({
1485
1596
  address: locker,
1486
1597
  abi: LiquidLpLockerAbi,
@@ -1496,7 +1607,7 @@ var LiquidSDK = class {
1496
1607
  "walletClient with account required for collectRewardsWithoutUnlock"
1497
1608
  );
1498
1609
  }
1499
- const locker = lockerAddress ?? ADDRESSES.LP_LOCKER;
1610
+ const locker = lockerAddress ?? DEFAULTS.LOCKER;
1500
1611
  return await this.walletClient.writeContract({
1501
1612
  address: locker,
1502
1613
  abi: LiquidLpLockerAbi,
@@ -1512,7 +1623,7 @@ var LiquidSDK = class {
1512
1623
  "walletClient with account required for updateRewardRecipient"
1513
1624
  );
1514
1625
  }
1515
- const locker = lockerAddress ?? ADDRESSES.LP_LOCKER;
1626
+ const locker = lockerAddress ?? DEFAULTS.LOCKER;
1516
1627
  return await this.walletClient.writeContract({
1517
1628
  address: locker,
1518
1629
  abi: LiquidLpLockerAbi,
@@ -1547,8 +1658,298 @@ var LiquidSDK = class {
1547
1658
  args: [poolId]
1548
1659
  });
1549
1660
  }
1661
+ // ── Token Metadata Updates ──────────────────────────────────────────
1662
+ /**
1663
+ * Update a token's image. Must be called by the token admin.
1664
+ */
1665
+ async updateImage(tokenAddress, newImage) {
1666
+ if (!this.walletClient?.account) {
1667
+ throw new Error("walletClient with account required for updateImage");
1668
+ }
1669
+ return await this.walletClient.writeContract({
1670
+ address: tokenAddress,
1671
+ abi: LiquidTokenAbi,
1672
+ functionName: "updateImage",
1673
+ args: [newImage],
1674
+ chain: base2,
1675
+ account: this.walletClient.account
1676
+ });
1677
+ }
1678
+ /**
1679
+ * Update a token's metadata. Must be called by the token admin.
1680
+ */
1681
+ async updateMetadata(tokenAddress, newMetadata) {
1682
+ if (!this.walletClient?.account) {
1683
+ throw new Error("walletClient with account required for updateMetadata");
1684
+ }
1685
+ return await this.walletClient.writeContract({
1686
+ address: tokenAddress,
1687
+ abi: LiquidTokenAbi,
1688
+ functionName: "updateMetadata",
1689
+ args: [newMetadata],
1690
+ chain: base2,
1691
+ account: this.walletClient.account
1692
+ });
1693
+ }
1694
+ // ── Token Discovery ─────────────────────────────────────────────────
1695
+ /**
1696
+ * Get all tokens deployed by a specific address by querying TokenCreated events.
1697
+ * @param deployer - The address that deployed the tokens (msgSender)
1698
+ * @param fromBlock - Starting block to search from (defaults to 0n)
1699
+ * @param toBlock - Ending block to search to (defaults to 'latest')
1700
+ */
1701
+ async getDeployedTokens(deployer, fromBlock, toBlock) {
1702
+ return this.getTokens({ deployer, fromBlock, toBlock });
1703
+ }
1704
+ /**
1705
+ * Query TokenCreated events with optional filtering.
1706
+ *
1707
+ * Use this for token discovery, indexing, or building token lists.
1708
+ * Returns events in chronological order with block numbers for pagination.
1709
+ *
1710
+ * @example
1711
+ * // Get all tokens
1712
+ * const allTokens = await sdk.getTokens();
1713
+ *
1714
+ * // Get tokens by deployer
1715
+ * const myTokens = await sdk.getTokens({ deployer: myAddress });
1716
+ *
1717
+ * // Paginate with block ranges
1718
+ * const page1 = await sdk.getTokens({ fromBlock: 20000000n, toBlock: 20100000n });
1719
+ * const page2 = await sdk.getTokens({ fromBlock: 20100001n, toBlock: 20200000n });
1720
+ */
1721
+ async getTokens(options) {
1722
+ const logs = await this.publicClient.getLogs({
1723
+ address: ADDRESSES.FACTORY,
1724
+ event: parseAbiItem(
1725
+ "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)"
1726
+ ),
1727
+ fromBlock: options?.fromBlock ?? 0n,
1728
+ toBlock: options?.toBlock ?? "latest"
1729
+ });
1730
+ const deployer = options?.deployer;
1731
+ return logs.filter((log) => {
1732
+ if (!deployer) return true;
1733
+ const sender = log.args.msgSender;
1734
+ return sender && getAddress(sender) === getAddress(deployer);
1735
+ }).map((log) => {
1736
+ const args = log.args;
1737
+ return {
1738
+ msgSender: args.msgSender,
1739
+ tokenAddress: args.tokenAddress,
1740
+ tokenAdmin: args.tokenAdmin,
1741
+ tokenImage: args.tokenImage,
1742
+ tokenName: args.tokenName,
1743
+ tokenSymbol: args.tokenSymbol,
1744
+ tokenMetadata: args.tokenMetadata,
1745
+ tokenContext: args.tokenContext,
1746
+ startingTick: args.startingTick,
1747
+ poolHook: args.poolHook,
1748
+ poolId: args.poolId,
1749
+ pairedToken: args.pairedToken,
1750
+ locker: args.locker,
1751
+ mevModule: args.mevModule,
1752
+ extensionsSupply: args.extensionsSupply,
1753
+ extensions: args.extensions,
1754
+ blockNumber: log.blockNumber
1755
+ };
1756
+ });
1757
+ }
1758
+ /**
1759
+ * Look up a single token's on-chain event data by contract address.
1760
+ *
1761
+ * Returns the full TokenCreated event including metadata, context, poolId,
1762
+ * hook, locker, extensions — everything a wallet or aggregator needs to
1763
+ * display the token. Returns `null` if not found.
1764
+ *
1765
+ * This is indexed on-chain (tokenAddress is indexed in the event), so it's
1766
+ * a single RPC call regardless of how many tokens exist.
1767
+ */
1768
+ async getTokenEvent(tokenAddress) {
1769
+ const logs = await this.publicClient.getLogs({
1770
+ address: ADDRESSES.FACTORY,
1771
+ event: parseAbiItem(
1772
+ "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)"
1773
+ ),
1774
+ args: { tokenAddress },
1775
+ fromBlock: 0n,
1776
+ toBlock: "latest"
1777
+ });
1778
+ if (logs.length === 0) return null;
1779
+ const log = logs[0];
1780
+ const args = log.args;
1781
+ return {
1782
+ msgSender: args.msgSender,
1783
+ tokenAddress: args.tokenAddress,
1784
+ tokenAdmin: args.tokenAdmin,
1785
+ tokenImage: args.tokenImage,
1786
+ tokenName: args.tokenName,
1787
+ tokenSymbol: args.tokenSymbol,
1788
+ tokenMetadata: args.tokenMetadata,
1789
+ tokenContext: args.tokenContext,
1790
+ startingTick: args.startingTick,
1791
+ poolHook: args.poolHook,
1792
+ poolId: args.poolId,
1793
+ pairedToken: args.pairedToken,
1794
+ locker: args.locker,
1795
+ mevModule: args.mevModule,
1796
+ extensionsSupply: args.extensionsSupply,
1797
+ extensions: args.extensions,
1798
+ blockNumber: log.blockNumber
1799
+ };
1800
+ }
1550
1801
  };
1551
1802
 
1803
+ // src/abis/LiquidUniv4EthDevBuy.ts
1804
+ var LiquidUniv4EthDevBuyAbi = [
1805
+ {
1806
+ type: "constructor",
1807
+ inputs: [
1808
+ { name: "factory_", type: "address" },
1809
+ { name: "weth_", type: "address" },
1810
+ { name: "universalRouter_", type: "address" },
1811
+ { name: "permit2_", type: "address" }
1812
+ ],
1813
+ stateMutability: "nonpayable"
1814
+ },
1815
+ {
1816
+ type: "function",
1817
+ name: "factory",
1818
+ inputs: [],
1819
+ outputs: [{ name: "", type: "address" }],
1820
+ stateMutability: "view"
1821
+ },
1822
+ {
1823
+ type: "function",
1824
+ name: "weth",
1825
+ inputs: [],
1826
+ outputs: [{ name: "", type: "address" }],
1827
+ stateMutability: "view"
1828
+ },
1829
+ {
1830
+ type: "function",
1831
+ name: "universalRouter",
1832
+ inputs: [],
1833
+ outputs: [{ name: "", type: "address" }],
1834
+ stateMutability: "view"
1835
+ },
1836
+ {
1837
+ type: "function",
1838
+ name: "permit2",
1839
+ inputs: [],
1840
+ outputs: [{ name: "", type: "address" }],
1841
+ stateMutability: "view"
1842
+ },
1843
+ {
1844
+ type: "function",
1845
+ name: "receiveTokens",
1846
+ inputs: [
1847
+ {
1848
+ name: "deploymentConfig",
1849
+ type: "tuple",
1850
+ components: [
1851
+ {
1852
+ name: "tokenConfig",
1853
+ type: "tuple",
1854
+ components: [
1855
+ { name: "tokenAdmin", type: "address" },
1856
+ { name: "name", type: "string" },
1857
+ { name: "symbol", type: "string" },
1858
+ { name: "salt", type: "bytes32" },
1859
+ { name: "image", type: "string" },
1860
+ { name: "metadata", type: "string" },
1861
+ { name: "context", type: "string" },
1862
+ { name: "originatingChainId", type: "uint256" }
1863
+ ]
1864
+ },
1865
+ {
1866
+ name: "poolConfig",
1867
+ type: "tuple",
1868
+ components: [
1869
+ { name: "hook", type: "address" },
1870
+ { name: "pairedToken", type: "address" },
1871
+ { name: "tickIfToken0IsLiquid", type: "int24" },
1872
+ { name: "tickSpacing", type: "int24" },
1873
+ { name: "poolData", type: "bytes" }
1874
+ ]
1875
+ },
1876
+ {
1877
+ name: "lockerConfig",
1878
+ type: "tuple",
1879
+ components: [
1880
+ { name: "locker", type: "address" },
1881
+ { name: "rewardAdmins", type: "address[]" },
1882
+ { name: "rewardRecipients", type: "address[]" },
1883
+ { name: "rewardBps", type: "uint16[]" },
1884
+ { name: "tickLower", type: "int24[]" },
1885
+ { name: "tickUpper", type: "int24[]" },
1886
+ { name: "positionBps", type: "uint16[]" },
1887
+ { name: "lockerData", type: "bytes" }
1888
+ ]
1889
+ },
1890
+ {
1891
+ name: "mevModuleConfig",
1892
+ type: "tuple",
1893
+ components: [
1894
+ { name: "mevModule", type: "address" },
1895
+ { name: "mevModuleData", type: "bytes" }
1896
+ ]
1897
+ },
1898
+ {
1899
+ name: "extensionConfigs",
1900
+ type: "tuple[]",
1901
+ components: [
1902
+ { name: "extension", type: "address" },
1903
+ { name: "msgValue", type: "uint256" },
1904
+ { name: "extensionBps", type: "uint16" },
1905
+ { name: "extensionData", type: "bytes" }
1906
+ ]
1907
+ }
1908
+ ]
1909
+ },
1910
+ {
1911
+ name: "tokenPoolKey",
1912
+ type: "tuple",
1913
+ components: [
1914
+ { name: "currency0", type: "address" },
1915
+ { name: "currency1", type: "address" },
1916
+ { name: "fee", type: "uint24" },
1917
+ { name: "tickSpacing", type: "int24" },
1918
+ { name: "hooks", type: "address" }
1919
+ ]
1920
+ },
1921
+ { name: "token", type: "address" },
1922
+ { name: "extensionSupply", type: "uint256" },
1923
+ { name: "extensionIndex", type: "uint256" }
1924
+ ],
1925
+ outputs: [],
1926
+ stateMutability: "payable"
1927
+ },
1928
+ {
1929
+ type: "function",
1930
+ name: "supportsInterface",
1931
+ inputs: [{ name: "interfaceId", type: "bytes4" }],
1932
+ outputs: [{ name: "", type: "bool" }],
1933
+ stateMutability: "pure"
1934
+ },
1935
+ {
1936
+ type: "event",
1937
+ name: "EthDevBuy",
1938
+ inputs: [
1939
+ { name: "token", type: "address", indexed: true },
1940
+ { name: "user", type: "address", indexed: true },
1941
+ { name: "ethAmount", type: "uint256", indexed: false },
1942
+ { name: "tokenAmount", type: "uint256", indexed: false }
1943
+ ],
1944
+ anonymous: false
1945
+ },
1946
+ { type: "error", name: "InvalidEthDevBuyPercentage", inputs: [] },
1947
+ { type: "error", name: "InvalidMsgValue", inputs: [] },
1948
+ { type: "error", name: "InvalidPairedTokenPoolKey", inputs: [] },
1949
+ { type: "error", name: "ReentrancyGuardReentrantCall", inputs: [] },
1950
+ { type: "error", name: "Unauthorized", inputs: [] }
1951
+ ];
1952
+
1552
1953
  // src/utils/tick-math.ts
1553
1954
  var LOG_BASE = Math.log(1.0001);
1554
1955
  var DEFAULT_TICK_SPACING = 200;
@@ -1676,9 +2077,13 @@ export {
1676
2077
  LiquidSDK,
1677
2078
  LiquidSniperAuctionV2Abi,
1678
2079
  LiquidSniperUtilV2Abi,
2080
+ LiquidTokenAbi,
2081
+ LiquidUniv4EthDevBuyAbi,
1679
2082
  LiquidVaultAbi,
1680
2083
  POOL_POSITIONS,
1681
2084
  TOKEN,
2085
+ buildContext,
2086
+ buildMetadata,
1682
2087
  createDefaultPositions,
1683
2088
  createPositions,
1684
2089
  createPositionsUSD,
@@ -1690,6 +2095,8 @@ export {
1690
2095
  getTickFromMarketCapStable,
1691
2096
  getTickFromMarketCapUSD,
1692
2097
  marketCapFromTickETH,
1693
- marketCapFromTickUSD
2098
+ marketCapFromTickUSD,
2099
+ parseContext,
2100
+ parseMetadata
1694
2101
  };
1695
2102
  //# sourceMappingURL=index.mjs.map