liquid-sdk 1.7.3 → 1.7.5

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/AGENT_README.md CHANGED
@@ -35,7 +35,7 @@ No API keys, no backend, no database. The SDK talks directly to Base mainnet con
35
35
  Liquid Protocol deploys ERC-20 tokens on Base with:
36
36
  - Uniswap V4 liquidity pools (automatic)
37
37
  - LP fee collection and reward distribution
38
- - MEV protection via block delay
38
+ - MEV protection via sniper auction
39
39
  - Optional extensions: dev buy, vault lockup/vesting, airdrops
40
40
 
41
41
  Every token gets 100 billion supply (18 decimals), a Uniswap V4 pool, and locked liquidity with configurable reward splits.
@@ -54,7 +54,7 @@ Requires wallet. Creates the token, pool, locks LP, and optionally buys tokens a
54
54
  const result = await sdk.deployToken({
55
55
  name: "My Token",
56
56
  symbol: "MTK",
57
- image: "https://example.com/logo.png", // optional
57
+ image: "ipfs://QmYourImageCID", // optional, IPFS recommended
58
58
  metadata: '{"description":"A cool token"}', // optional, JSON string
59
59
  context: '{"platform":"my-app"}', // optional, tracking/attribution
60
60
 
@@ -100,27 +100,27 @@ const ext = sdk.buildDevBuyExtension({
100
100
 
101
101
  Tokens generate LP fees from Uniswap V4 trading. These accrue in the Fee Locker and can be claimed by the fee owner.
102
102
 
103
- #### `sdk.getAvailableFees(feeOwner, feeToken?)` — Check total unlocked fees
103
+ #### `sdk.getAvailableFees(feeOwner, tokenAddress)` — Check total unlocked fees
104
104
 
105
105
  ```typescript
106
- const fees = await sdk.getAvailableFees(ownerAddress);
107
- // fees: bigint — total fees available, defaulting to WETH-denominated claims
106
+ const fees = await sdk.getAvailableFees(ownerAddress, tokenAddress);
107
+ // fees: bigint — total fees available (in token's paired asset, usually WETH)
108
108
  ```
109
109
 
110
- #### `sdk.getFeesToClaim(feeOwner, feeToken?)` — Check claimable fees
110
+ #### `sdk.getFeesToClaim(feeOwner, tokenAddress)` — Check claimable fees
111
111
 
112
112
  ```typescript
113
- const claimable = await sdk.getFeesToClaim(ownerAddress);
114
- // claimable: bigint — fees ready to claim right now (WETH by default)
113
+ const claimable = await sdk.getFeesToClaim(ownerAddress, tokenAddress);
114
+ // claimable: bigint — fees ready to claim right now
115
115
  ```
116
116
 
117
- #### `sdk.claimFees(feeOwner, feeToken?)` — Claim fees
117
+ #### `sdk.claimFees(feeOwner, tokenAddress)` — Claim fees
118
118
 
119
119
  Requires wallet.
120
120
 
121
121
  ```typescript
122
122
  if (claimable > 0n) {
123
- const txHash = await sdk.claimFees(ownerAddress);
123
+ const txHash = await sdk.claimFees(ownerAddress, tokenAddress);
124
124
  await publicClient.waitForTransactionReceipt({ hash: txHash });
125
125
  }
126
126
  ```
@@ -161,7 +161,7 @@ const txHash = await sdk.collectRewardsWithoutUnlock(tokenAddress);
161
161
  await publicClient.waitForTransactionReceipt({ hash: txHash });
162
162
  ```
163
163
 
164
- **Important:** After deployment, the pool is locked for a MEV block delay. `collectRewardsWithoutUnlock` may revert with `ManagerLocked` if called too soon. Use `getPoolUnlockTime` to check.
164
+ **Important:** After deployment, the sniper auction MEV module may block early reward collection. If `collectRewardsWithoutUnlock` reverts with `ManagerLocked`, wait for the auction period to end.
165
165
 
166
166
  #### `sdk.updateRewardRecipient(tokenAddress, rewardIndex, newRecipient)` — Change reward recipient
167
167
 
@@ -284,6 +284,49 @@ const deploy = await sdk.getDeploymentInfo(tokenAddress);
284
284
 
285
285
  ---
286
286
 
287
+ ### Token Discovery
288
+
289
+ #### `sdk.getTokens(options?)` — Query all deployed tokens
290
+
291
+ Query TokenCreated events with optional filtering. For wallet integrations, token listings, and indexing.
292
+
293
+ ```typescript
294
+ // Get all tokens
295
+ const allTokens = await sdk.getTokens();
296
+
297
+ // Get tokens by deployer
298
+ const myTokens = await sdk.getTokens({ deployer: myAddress });
299
+
300
+ // Paginate with block ranges
301
+ const page1 = await sdk.getTokens({ fromBlock: 20000000n, toBlock: 20100000n });
302
+ const page2 = await sdk.getTokens({ fromBlock: 20100001n });
303
+ ```
304
+
305
+ Each result includes full on-chain event data: name, symbol, image, metadata, context, poolId, hook, locker, extensions, and `blockNumber` for cursor-based pagination.
306
+
307
+ #### `sdk.getTokenEvent(tokenAddress)` — Look up a single token's event data
308
+
309
+ Fast lookup by contract address (tokenAddress is indexed on-chain = single RPC call).
310
+
311
+ ```typescript
312
+ const event = await sdk.getTokenEvent(tokenAddress);
313
+ // event.tokenName, event.tokenSymbol, event.tokenImage
314
+ // event.tokenMetadata — parse with parseMetadata()
315
+ // event.tokenContext — parse with parseContext()
316
+ // event.poolId, event.poolHook, event.locker, event.extensions
317
+ // event.blockNumber
318
+ ```
319
+
320
+ #### `sdk.getDeployedTokens(deployer, fromBlock?, toBlock?)` — Get tokens by deployer
321
+
322
+ Convenience wrapper around `getTokens({ deployer })`.
323
+
324
+ ```typescript
325
+ const tokens = await sdk.getDeployedTokens(deployerAddress);
326
+ ```
327
+
328
+ ---
329
+
287
330
  ### Token Metadata Updates
288
331
 
289
332
  #### `sdk.updateImage(tokenAddress, newImageUrl)` — Update token image
@@ -385,27 +428,50 @@ const maxRounds = await sdk.getAuctionMaxRounds();
385
428
  ```typescript
386
429
  const gasPrice = await sdk.getAuctionGasPriceForBid(
387
430
  auction.gasPeg,
388
- parseEther("1"), // desired bid
431
+ parseEther("0.001"), // desired bid
389
432
  );
390
433
  ```
391
434
 
435
+ #### `sdk.bidInAuction(params, gasPrice)` — Bid in auction and swap tokens
436
+
437
+ Requires wallet. Auto-wraps ETH → WETH and approves SniperUtilV2 if needed. Sets gas manually (800K) and both `maxFeePerGas`/`maxPriorityFeePerGas` to the auction gas price.
438
+
439
+ ```typescript
440
+ const rewards = await sdk.getTokenRewards(tokenAddress);
441
+ const zeroForOne = rewards.poolKey.currency0.toLowerCase() === EXTERNAL.WETH.toLowerCase();
442
+
443
+ const result = await sdk.bidInAuction({
444
+ poolKey: rewards.poolKey,
445
+ zeroForOne, // depends on token sort order vs WETH
446
+ amountIn: parseEther("0.001"), // WETH to swap (auto-wrapped from ETH)
447
+ amountOutMinimum: 0n, // set slippage in production
448
+ round: auction.round, // must match current on-chain round
449
+ bidAmount: parseEther("0.0005"), // ETH bid (sent as msg.value)
450
+ }, gasPrice);
451
+ // result.txHash — transaction hash
452
+ ```
453
+
454
+ **Important:** The bid is valid only at `nextAuctionBlock`. Submit when `currentBlock === nextAuctionBlock - 1`. The `amountIn` is pulled from your WETH balance (separate from the bid's `msg.value`). Auction runs 5 rounds, every 2 blocks, starting 2 blocks after deployment.
455
+
392
456
  ---
393
457
 
394
- ### MEV Protection
458
+ ### MEV Descending Fees
395
459
 
396
- #### `sdk.getMevBlockDelay()` — Get configured block delay
460
+ #### `sdk.getMevDescendingFeesBlockDelay()` — Configured block delay
397
461
 
398
462
  ```typescript
399
- const delay = await sdk.getMevBlockDelay();
400
- // delay: bigint — number of blocks
463
+ const delay = await sdk.getMevDescendingFeesBlockDelay();
464
+ // delay: bigint — number of blocks the MEV module fee window covers
401
465
  ```
402
466
 
403
- #### `sdk.getPoolUnlockTime(poolId)` When does MEV lock expire
467
+ `sdk.getMevBlockDelay()` is a deprecated alias for the same call.
468
+
469
+ #### `sdk.getPoolUnlockTime(poolId)` — When MEV lock expires
404
470
 
405
471
  ```typescript
406
472
  const unlockTime = await sdk.getPoolUnlockTime(poolId);
407
- // unlockTime: bigint unix timestamp
408
- // If Date.now()/1000 < unlockTime, pool is still locked
473
+ // If Date.now()/1000 < unlockTime, the pool is still inside the MEV window
474
+ // and writes that go through the MevDescendingFees hook may revert with ManagerLocked.
409
475
  ```
410
476
 
411
477
  ---
@@ -442,20 +508,20 @@ When calling `deployToken`, all fields except `name` and `symbol` are optional.
442
508
  | `salt` | `keccak256(name + symbol + timestamp)` | Unique per deploy |
443
509
  | `image` | `""` | Empty string |
444
510
  | `metadata` | `""` | Empty string |
445
- | `context` | `""` | Empty string |
446
- | `hook` | `ADDRESSES.HOOK_DYNAMIC_FEE_V2` | Dynamic fee model |
511
+ | `context` | `'{"interface":"SDK"}'` | Auto-set via `buildContext()` |
512
+ | `hook` | `ADDRESSES.HOOK_STATIC_FEE_V2` | Static 1% buy + 1% sell |
447
513
  | `pairedToken` | `EXTERNAL.WETH` | Base WETH |
448
- | `tickIfToken0IsLiquid` | `-198720` | Starting price tick |
449
- | `tickSpacing` | `60` | Uniswap V4 tick spacing |
450
- | `poolData` | `"0x"` | Hook uses its default fee config |
451
- | `locker` | `ADDRESSES.LP_LOCKER` | Standard LP locker |
514
+ | `tickIfToken0IsLiquid` | `-230400` | ≈10 ETH market cap |
515
+ | `tickSpacing` | `200` | Uniswap V4 tick spacing |
516
+ | `poolData` | `encodeStaticFeePoolData(100, 100)` | 1% sell, 1% buy |
517
+ | `locker` | `ADDRESSES.LP_LOCKER_FEE_CONVERSION` | LP locker with fee conversion to ETH |
452
518
  | `rewardAdmins` | `[walletAddress]` | Deployer is admin |
453
519
  | `rewardRecipients` | `[walletAddress]` | Deployer gets rewards |
454
520
  | `rewardBps` | `[10000]` | 100% to deployer |
455
- | `tickLower` | `[-887220]` | Full-range lower |
456
- | `tickUpper` | `[887220]` | Full-range upper |
457
- | `positionBps` | `[10000]` | Single position, 100% |
458
- | `mevModule` | `ADDRESSES.MEV_BLOCK_DELAY` | MEV protection on |
521
+ | `tickLower` | `[-230400, -216000, -202000, -155000, -141000]` | 5-position Liquid layout |
522
+ | `tickUpper` | `[-216000, -155000, -155000, -120000, -120000]` | 5-position Liquid layout |
523
+ | `positionBps` | `[1000, 5000, 1500, 2000, 500]` | 10% / 50% / 15% / 20% / 5% |
524
+ | `mevModule` | `ADDRESSES.SNIPER_AUCTION_V2` | 80%→40% over 20s |
459
525
  | `extensions` | `[]` | No extensions |
460
526
 
461
527
  ---
@@ -468,19 +534,18 @@ All addresses are exported as `ADDRESSES` and `EXTERNAL`:
468
534
  import { ADDRESSES, EXTERNAL } from "liquid-sdk";
469
535
 
470
536
  // Liquid Protocol contracts
471
- ADDRESSES.FACTORY // 0x0000003482fe299E72d4908368044A8A173BE576
472
- ADDRESSES.LP_LOCKER // 0x00000548732DfA56Be1257cE44D0CFc3B46dDb2A
473
- ADDRESSES.FEE_LOCKER // 0x000008B9242b7e4432f6c4b1EeAD93562f9Cc94d
474
- ADDRESSES.VAULT // 0x000001c5263F4d64CdC343cDA9C8bF961CF8376c
475
- ADDRESSES.HOOK_DYNAMIC_FEE_V2 // 0x2A2F73CDDa098d639bd8Bbcd7dF2bf24E06728cC
476
- ADDRESSES.HOOK_STATIC_FEE_V2 // 0xb2401c5369AaCF62F8d615623C7F68F84da428Cc
477
- ADDRESSES.AIRDROP_V2 // 0x00000C222442512b08446D33dd9754a7F260BE79
478
- ADDRESSES.SNIPER_AUCTION_V2 // 0x000007b64003ee07a69576F98859a0a36b854260
479
- ADDRESSES.SNIPER_UTIL_V2 // 0x000003Ee0cb9B0C82C6C7FCB7b81a9883F285270
480
- ADDRESSES.MEV_BLOCK_DELAY // 0x0000035D83588954F3c581c3A66251b3F06AD5e4
481
- ADDRESSES.UNIV4_ETH_DEV_BUY // 0x00000d7DE1f0A3FA7957F5d8A2b97B0E24e5783D
482
- ADDRESSES.POOL_EXTENSION_ALLOWLIST // 0x000003Afb1b070F037D2871eE0A6b8c8f53F7B77
483
- ADDRESSES.LIQUID_DEPLOYER_LIB // 0x00000f88b2d37A2006F2F0C8552d22E0b8945202
537
+ ADDRESSES.FACTORY // 0x04F1a284168743759BE6554f607a10CEBdB77760
538
+ ADDRESSES.LP_LOCKER_FEE_CONVERSION // 0x77247fCD1d5e34A3703AcA898A591Dc7422435f3
539
+ ADDRESSES.FEE_LOCKER // 0xF7d3BE3FC0de76fA5550C29A8F6fa53667B876FF
540
+ ADDRESSES.VAULT // 0xdFCCC93257c20519A9005A2281CFBdF84836d50E
541
+ ADDRESSES.HOOK_DYNAMIC_FEE_V2 // 0x80E2F7dC8C2C880BbC4BDF80A5Fb0eB8B1DB68CC
542
+ ADDRESSES.HOOK_STATIC_FEE_V2 // 0x9811f10Cd549c754Fa9E5785989c422A762c28cc
543
+ ADDRESSES.AIRDROP_V2 // 0x1423974d48f525462f1c087cBFdCC20BDBc33CdD
544
+ ADDRESSES.SNIPER_AUCTION_V2 // 0x187e8627c02c58F31831953C1268e157d3BfCefd
545
+ ADDRESSES.SNIPER_UTIL_V2 // 0x2B6cd5Be183c388Dd0074d53c52317df1414cd9f
546
+ ADDRESSES.MEV_DESCENDING_FEES // 0x8D6B080e48756A99F3893491D556B5d6907b6910
547
+ ADDRESSES.UNIV4_ETH_DEV_BUY // 0x5934097864dC487D21A7B4e4EEe201A39ceF728D
548
+ ADDRESSES.POOL_EXTENSION_ALLOWLIST // 0xb614167d79aDBaA9BA35d05fE1d5542d7316Ccaa
484
549
 
485
550
  // External (Uniswap V4 / Base)
486
551
  EXTERNAL.POOL_MANAGER // 0x498581fF718922c3f8e6A244956aF099B2652b2b
@@ -524,7 +589,8 @@ import {
524
589
  LiquidSniperUtilV2Abi,
525
590
  LiquidAirdropV2Abi,
526
591
  LiquidPoolExtensionAllowlistAbi,
527
- LiquidMevBlockDelayAbi,
592
+ LiquidMevDescendingFeesAbi,
593
+ LiquidMevBlockDelayAbi, // deprecated alias — prefer LiquidMevDescendingFeesAbi
528
594
  LiquidLpLockerAbi,
529
595
  ERC20Abi,
530
596
  } from "liquid-sdk";
@@ -579,7 +645,7 @@ const sdk = new LiquidSDK({ publicClient, walletClient });
579
645
  const result = await sdk.deployToken({
580
646
  name: "Agent Token",
581
647
  symbol: "AGENT",
582
- image: "https://example.com/logo.png",
648
+ image: "ipfs://QmYourImageCID",
583
649
  metadata: JSON.stringify({ description: "Deployed by an AI agent" }),
584
650
  devBuy: {
585
651
  ethAmount: parseEther("0.01"),
@@ -618,11 +684,11 @@ if (now < unlockTime) {
618
684
  ### 3. Check and claim fees
619
685
 
620
686
  ```typescript
621
- const fees = await sdk.getFeesToClaim(ownerAddress);
687
+ const fees = await sdk.getFeesToClaim(ownerAddress, tokenAddress);
622
688
  console.log("Claimable fees:", fees);
623
689
 
624
690
  if (fees > 0n) {
625
- const txHash = await sdk.claimFees(ownerAddress);
691
+ const txHash = await sdk.claimFees(ownerAddress, tokenAddress);
626
692
  const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
627
693
  console.log("Fees claimed in tx:", receipt.transactionHash);
628
694
  }
package/CHANGELOG.md CHANGED
@@ -2,6 +2,23 @@
2
2
 
3
3
  All notable changes to `liquid-sdk` will be documented in this file.
4
4
 
5
+ ## [1.7.5] - 2026-06-09
6
+
7
+ ### Security
8
+ - `bidInAuction` now approves WETH to `SniperUtilV2` for **exactly `amountIn`** (previously `amountIn * 10n`). Each bid's `transferFrom` consumes the full allowance, so **no standing WETH allowance survives** — removing the "drain via standing approval" surface that hit a sibling Clanker fork in 2026-05. Complements the protocol-level `paymentPerGasUnit == 0` mitigation already live on the auction contract. (#18)
9
+ - **Action for existing users:** if you bid through an older SDK that approved a multiplier, **revoke your residual WETH allowance to `SniperUtilV2` (`0x2B6cd5Be183c388Dd0074d53c52317df1414cd9f`)**.
10
+ - **Trade-off:** prior versions pre-approved 10× so 9 subsequent bids skipped the approve. Bots relying on that should either `WETH.approve(SNIPER_UTIL_V2, amountIn)` ahead of the auction window or start `bidInAuction` ~1 block earlier so the approve confirms in time.
11
+
12
+ ## [1.7.4] - 2026-04-23
13
+
14
+ ### Added
15
+ - `EXTERNAL.DIEM` — the DIEM token address on Base, for DIEM-paired token launches.
16
+ - `shiftPositions(positions, shiftBy)` — re-anchor a fixed-shape position layout to a different starting tick, preserving `positionBps`.
17
+ - `createLiquidPositionsUSD(startingMarketCapUSD, pairedTokenPriceUSD, tickSpacing?)` — the canonical 5-position "Liquid" layout re-anchored to a starting market cap, denominated in the *paired token's* USD price. Works for any pair token (WETH or DIEM); unlike `createDefaultPositions` (3-tranche), it preserves the exact `POOL_POSITIONS.Liquid` curve `deployToken()` uses by default.
18
+
19
+ ### Fixed
20
+ - `deployToken` gas estimation no longer silently swallows on-chain revert errors. Previously a failing `eth_estimateGas` (e.g., insufficient msg.value, paused factory, pre-flight check revert) would be caught and replaced with a 6M fallback, causing the tx to be broadcast and burn real gas for nothing. Now a revert-shaped error bubbles to the caller; only transport-level failures fall back. Non-revert fallbacks log a warning via `console.warn`.
21
+
5
22
  ## [1.7.3] - 2026-04-22
6
23
 
7
24
  ### Added