liquid-sdk 1.7.2 → 1.7.4

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.
@@ -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
 
@@ -455,21 +455,23 @@ const result = await sdk.bidInAuction({
455
455
 
456
456
  ---
457
457
 
458
- ### MEV Protection
458
+ ### MEV Descending Fees
459
459
 
460
- #### `sdk.getMevBlockDelay()` — Get configured block delay
460
+ #### `sdk.getMevDescendingFeesBlockDelay()` — Configured block delay
461
461
 
462
462
  ```typescript
463
- const delay = await sdk.getMevBlockDelay();
464
- // delay: bigint — number of blocks
463
+ const delay = await sdk.getMevDescendingFeesBlockDelay();
464
+ // delay: bigint — number of blocks the MEV module fee window covers
465
465
  ```
466
466
 
467
- #### `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
468
470
 
469
471
  ```typescript
470
472
  const unlockTime = await sdk.getPoolUnlockTime(poolId);
471
- // unlockTime: bigint unix timestamp
472
- // 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.
473
475
  ```
474
476
 
475
477
  ---
@@ -516,9 +518,9 @@ When calling `deployToken`, all fields except `name` and `symbol` are optional.
516
518
  | `rewardAdmins` | `[walletAddress]` | Deployer is admin |
517
519
  | `rewardRecipients` | `[walletAddress]` | Deployer gets rewards |
518
520
  | `rewardBps` | `[10000]` | 100% to deployer |
519
- | `tickLower` | `[-230400, -198600, -168600]` | 3-tranche Liquid default |
520
- | `tickUpper` | `[-198600, -168600, -122600]` | 3-tranche Liquid default |
521
- | `positionBps` | `[4000, 5000, 1000]` | 40% / 50% / 10% |
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% |
522
524
  | `mevModule` | `ADDRESSES.SNIPER_AUCTION_V2` | 80%→40% over 20s |
523
525
  | `extensions` | `[]` | No extensions |
524
526
 
@@ -587,7 +589,8 @@ import {
587
589
  LiquidSniperUtilV2Abi,
588
590
  LiquidAirdropV2Abi,
589
591
  LiquidPoolExtensionAllowlistAbi,
590
- LiquidMevBlockDelayAbi,
592
+ LiquidMevDescendingFeesAbi,
593
+ LiquidMevBlockDelayAbi, // deprecated alias — prefer LiquidMevDescendingFeesAbi
591
594
  LiquidLpLockerAbi,
592
595
  ERC20Abi,
593
596
  } from "liquid-sdk";
package/CHANGELOG.md CHANGED
@@ -2,6 +2,28 @@
2
2
 
3
3
  All notable changes to `liquid-sdk` will be documented in this file.
4
4
 
5
+ ## [1.7.4] - 2026-04-23
6
+
7
+ ### Added
8
+ - `EXTERNAL.DIEM` — the DIEM token address on Base, for DIEM-paired token launches.
9
+ - `shiftPositions(positions, shiftBy)` — re-anchor a fixed-shape position layout to a different starting tick, preserving `positionBps`.
10
+ - `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.
11
+
12
+ ### Fixed
13
+ - `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`.
14
+
15
+ ## [1.7.3] - 2026-04-22
16
+
17
+ ### Added
18
+ - `buildAirdropExtension({ admin, merkleRoot, allocationBps, lockupDuration, vestingDuration })` — creates a `LiquidAirdropV2` extension config for use in `deployToken({ extensions: [...] })`. Double-hashed leaf format compatible with OpenZeppelin `MerkleProof`. Contract minimums enforced (1-day lockup, ≤90% allocation).
19
+
20
+ ### Fixed
21
+ - `deployToken` no longer uses a hard-coded `gas: 5_000_000n` — real mainnet deploys currently require ~5.04M gas. Now uses `estimateContractGas * 1.2` with a 6M fallback so the SDK auto-adjusts as the factory evolves. Previous versions could OOG on mainnet.
22
+
23
+ ### Verified
24
+ - End-to-end airdrop flow fork-tested against Base mainnet (real `LiquidAirdropV2` at `0x1423974d48f525462f1c087cBFdCC20BDBc33CdD`): deploy → state register → claim with single-leaf proof all confirmed.
25
+ - Mainnet dry-run deploy confirmed on-chain state encoding: [basescan tx](https://basescan.org/tx/0x1807c1e3eb92ccb0c32779855cd35d5581e6143d4232f4ab66d39517ee86e3d0).
26
+
5
27
  ## [1.2.0] - 2025-03-10
6
28
 
7
29
  ### Added
package/dist/index.d.mts CHANGED
@@ -63,6 +63,21 @@ interface VaultExtensionParams {
63
63
  /** Vesting duration in seconds after lockup ends (0 = no vesting, tokens unlock all at once) */
64
64
  vestingDuration?: number;
65
65
  }
66
+ interface AirdropExtensionParams {
67
+ /** Address allowed to `updateAdmin`, `updateMerkleRoot` (under conditions),
68
+ * and `adminClaim` the remainder after claim expiration. */
69
+ admin: Address;
70
+ /** Merkle root over leaves `keccak256(bytes.concat(keccak256(abi.encode(
71
+ * recipient, allocatedAmount))))`. Double-hashed per OZ convention. */
72
+ merkleRoot: Hex;
73
+ /** Percentage of supply to reserve for the airdrop, in BPS (1–9000). */
74
+ allocationBps: number;
75
+ /** Lockup in seconds before any recipient can claim. Min 86400 (1 day). */
76
+ lockupDuration: number;
77
+ /** Linear vesting after lockup. 0 = instant claim of full entitlement at
78
+ * lockup end. */
79
+ vestingDuration?: number;
80
+ }
66
81
  interface DeployTokenParams {
67
82
  name: string;
68
83
  symbol: string;
@@ -270,6 +285,29 @@ declare class LiquidSDK {
270
285
  * ```
271
286
  */
272
287
  buildVaultExtension(vault: VaultExtensionParams): ExtensionConfig;
288
+ /**
289
+ * Build an ExtensionConfig that reserves a percentage of supply into
290
+ * the LiquidAirdropV2 contract for merkle-tree-based distribution.
291
+ *
292
+ * The airdrop contract expects `AirdropV2ExtensionData`:
293
+ * { address admin, bytes32 merkleRoot, uint256 lockupDuration, uint256 vestingDuration }
294
+ *
295
+ * Leaf encoding used by LiquidAirdropV2.claim (note: **double hashed**
296
+ * — OZ's standard 2nd-preimage-resistant pattern):
297
+ * leaf = keccak256(bytes.concat(keccak256(abi.encode(recipient, allocatedAmount))))
298
+ *
299
+ * @example
300
+ * ```typescript
301
+ * const airdropExt = sdk.buildAirdropExtension({
302
+ * admin: account.address,
303
+ * merkleRoot: "0x…",
304
+ * allocationBps: 2000, // 20%
305
+ * lockupDuration: 86400, // 1 day (minimum)
306
+ * vestingDuration: 0, // instant claim after lockup
307
+ * });
308
+ * ```
309
+ */
310
+ buildAirdropExtension(airdrop: AirdropExtensionParams): ExtensionConfig;
273
311
  /**
274
312
  * Validate a DeploymentConfig before sending to the contract.
275
313
  * Catches common mistakes client-side with clear error messages.
@@ -433,6 +471,9 @@ declare const ADDRESSES: {
433
471
  declare const EXTERNAL: {
434
472
  readonly POOL_MANAGER: Address;
435
473
  readonly WETH: Address;
474
+ /** DIEM — Liquid's intelligence-economy token. Also a pair token for
475
+ * agent-token launches (see `createLiquidPositionsUSD`). */
476
+ readonly DIEM: Address;
436
477
  readonly UNIVERSAL_ROUTER: Address;
437
478
  readonly PERMIT2: Address;
438
479
  };
@@ -489,7 +530,7 @@ declare const POOL_POSITIONS: {
489
530
  */
490
531
  declare const DEFAULTS: {
491
532
  readonly HOOK: `0x${string}`;
492
- /** LP Locker with fee conversion (converts fees to ETH before distributing) */
533
+ /** LP Locker with fee conversion (converts fees to WETH before distributing) */
493
534
  readonly LOCKER: `0x${string}`;
494
535
  readonly TICK_SPACING: 200;
495
536
  readonly TICK_IF_TOKEN0_IS_LIQUID: -230400;
@@ -583,31 +624,7 @@ declare const DEFAULT_CHAIN: {
583
624
  formatters: {
584
625
  readonly block: {
585
626
  exclude: [] | undefined;
586
- format: (args: viem_chains.OpStackRpcBlock, action
587
- /**
588
- * Pre-built position configurations.
589
- *
590
- * - **Standard**: Single position covering full range (~$20K → $1.5B).
591
- * Default starting tick -230400 (≈10 ETH market cap).
592
- *
593
- * - **Liquid**: 3-tranche default for Liquid Protocol.
594
- * Hardcoded for ≈10 ETH start at ~$2070/ETH.
595
- * For dynamic market cap targets, use `createPositionsUSD()` instead.
596
- *
597
- * Note: positionBps must sum to 10,000 (100%).
598
- */
599
- ? /**
600
- * Pre-built position configurations.
601
- *
602
- * - **Standard**: Single position covering full range (~$20K → $1.5B).
603
- * Default starting tick -230400 (≈10 ETH market cap).
604
- *
605
- * - **Liquid**: 3-tranche default for Liquid Protocol.
606
- * Hardcoded for ≈10 ETH start at ~$2070/ETH.
607
- * For dynamic market cap targets, use `createPositionsUSD()` instead.
608
- *
609
- * Note: positionBps must sum to 10,000 (100%).
610
- */: string | undefined) => {
627
+ format: (args: viem_chains.OpStackRpcBlock, action?: string | undefined) => {
611
628
  baseFeePerGas: bigint | null;
612
629
  blobGasUsed: bigint;
613
630
  difficulty: bigint;
@@ -2285,6 +2302,7 @@ declare function getTickFromMarketCapStable(marketCap: number, stableDecimals: n
2285
2302
  * market cap milestones. Percentages represent share of the *pool supply*
2286
2303
  * (i.e. after dev buy, airdrop, and vault allocations are deducted).
2287
2304
  */
2305
+
2288
2306
  interface MarketCapTranche {
2289
2307
  /** Upper bound market cap in ETH for this tranche */
2290
2308
  upperMarketCapETH: number;
@@ -2380,6 +2398,55 @@ declare function createPositionsUSD(startingMarketCapUSD: number, ethPriceUSD: n
2380
2398
  declare function createDefaultPositions(startingMarketCapUSD: number, ethPriceUSD: number, tickSpacing?: number): PositionArrays & {
2381
2399
  tickIfToken0IsLiquid: number;
2382
2400
  };
2401
+ /**
2402
+ * Shift every tick in a position layout by a fixed amount, preserving the
2403
+ * positionBps splits. The primitive behind `createLiquidPositionsUSD` — it
2404
+ * re-anchors a fixed-shape layout (e.g. `POOL_POSITIONS.Liquid`) to a
2405
+ * different starting tick.
2406
+ *
2407
+ * `shiftBy` should be a multiple of the pool's tick spacing so the shifted
2408
+ * ticks stay aligned. A difference of two aligned ticks is always aligned,
2409
+ * so deriving it as `targetTick - sourceBottomTick` is safe.
2410
+ *
2411
+ * @param positions - Source positions (e.g. `POOL_POSITIONS.Liquid`)
2412
+ * @param shiftBy - Ticks to add to every tickLower/tickUpper (may be negative)
2413
+ * @returns A fresh array — the source is not mutated
2414
+ */
2415
+ declare function shiftPositions(positions: readonly PoolPosition[], shiftBy: number): PoolPosition[];
2416
+ /**
2417
+ * Build the canonical 5-position "Liquid" layout (10/50/15/20/5) re-anchored
2418
+ * to a starting market cap, denominated in the *paired token's* USD price.
2419
+ *
2420
+ * Works for any pair token — pass the price of whatever the pool is paired
2421
+ * against:
2422
+ * - WETH-paired: `createLiquidPositionsUSD(20_000, ethPriceUSD)`
2423
+ * - DIEM-paired: `createLiquidPositionsUSD(20_000, diemPriceUSD)`
2424
+ *
2425
+ * Unlike `createDefaultPositions` (a 3-tranche layout), this preserves the
2426
+ * exact shape of `POOL_POSITIONS.Liquid` — the same curve `deployToken()`
2427
+ * uses by default — just shifted so its bottom sits at the requested start.
2428
+ *
2429
+ * @param startingMarketCapUSD - Initial market cap in USD
2430
+ * @param pairedTokenPriceUSD - USD price of the token the pool is paired against
2431
+ * @param tickSpacing - Tick spacing (default 200)
2432
+ * @returns Position arrays + `tickIfToken0IsLiquid`, ready to spread into `deployToken()`
2433
+ *
2434
+ * @example
2435
+ * ```ts
2436
+ * import { LiquidSDK, EXTERNAL, createLiquidPositionsUSD } from "liquid-sdk";
2437
+ *
2438
+ * const positions = createLiquidPositionsUSD(20_000, diemPriceUSD);
2439
+ * await sdk.deployToken({
2440
+ * name: "Agent Token",
2441
+ * symbol: "AGENT",
2442
+ * pairedToken: EXTERNAL.DIEM,
2443
+ * ...positions,
2444
+ * });
2445
+ * ```
2446
+ */
2447
+ declare function createLiquidPositionsUSD(startingMarketCapUSD: number, pairedTokenPriceUSD: number, tickSpacing?: number): PositionArrays & {
2448
+ tickIfToken0IsLiquid: number;
2449
+ };
2383
2450
  /**
2384
2451
  * Describe positions as human-readable market cap ranges.
2385
2452
  * Useful for displaying position info in UIs.
@@ -2496,7 +2563,7 @@ declare enum FeePreference {
2496
2563
  *
2497
2564
  * @example
2498
2565
  * ```ts
2499
- * // Single recipient, fees converted to ETH
2566
+ * // Single recipient, fees converted to WETH
2500
2567
  * const lockerData = encodeFeeConversionLockerData([FeePreference.Paired]);
2501
2568
  *
2502
2569
  * // Two recipients: first gets ETH, second gets the token
@@ -2557,4 +2624,4 @@ declare function parseContext(contextString: string): LiquidContext | null;
2557
2624
  */
2558
2625
  declare function parseMetadata(metadataString: string): LiquidMetadata | null;
2559
2626
 
2560
- export { ADDRESSES, type AirdropInfo, type BidInAuctionParams, type BidInAuctionResult, DEFAULTS, DEFAULT_CHAIN, DEFAULT_CHAIN_ID, DEFAULT_RPC_URL, DEFAULT_TRANCHES_USD, type DeployTokenParams, type DeployTokenResult, type DeploymentConfig, type DeploymentInfo, type DevBuyParams, type DynamicFeeConfig, ERC20Abi, EXTERNAL, type ExtensionConfig, FEE, FeePreference, type GetTokensOptions, LiquidAirdropV2Abi, type LiquidContext, LiquidFactoryAbi, LiquidFeeLockerAbi, LiquidHookDynamicFeeV2Abi, LiquidLpLockerAbi, type LiquidMetadata, LiquidMevBlockDelayAbi, LiquidMevDescendingFeesAbi, LiquidPoolExtensionAllowlistAbi, LiquidSDK, type LiquidSDKConfig, LiquidSniperAuctionV2Abi, LiquidSniperUtilV2Abi, LiquidTokenAbi, LiquidUniv4EthDevBuyAbi, LiquidVaultAbi, type LockerConfig, type MarketCapTranche, type MarketCapTrancheUSD, type MevModuleConfig, POOL_POSITIONS, type PoolConfig, type PoolDynamicConfigVars, type PoolDynamicFeeVars, type PoolKey, type PoolPosition, type PositionArrays, type PositionConfig, type SniperAuctionConfig, type SniperAuctionFeeConfig, type SniperAuctionState, type SocialMediaUrl, TOKEN, type TokenConfig, type TokenCreatedEvent, type TokenRewardInfo, type VaultAllocation, type VaultExtensionParams, buildContext, buildMetadata, createDefaultPositions, createPositions, createPositionsUSD, describePositions, encodeDynamicFeePoolData, encodeFeeConversionLockerData, encodeSniperAuctionData, encodeStaticFeePoolData, getTickFromMarketCapETH, getTickFromMarketCapStable, getTickFromMarketCapUSD, marketCapFromTickETH, marketCapFromTickUSD, parseContext, parseMetadata };
2627
+ export { ADDRESSES, type AirdropExtensionParams, type AirdropInfo, type BidInAuctionParams, type BidInAuctionResult, DEFAULTS, DEFAULT_CHAIN, DEFAULT_CHAIN_ID, DEFAULT_RPC_URL, DEFAULT_TRANCHES_USD, type DeployTokenParams, type DeployTokenResult, type DeploymentConfig, type DeploymentInfo, type DevBuyParams, type DynamicFeeConfig, ERC20Abi, EXTERNAL, type ExtensionConfig, FEE, FeePreference, type GetTokensOptions, LiquidAirdropV2Abi, type LiquidContext, LiquidFactoryAbi, LiquidFeeLockerAbi, LiquidHookDynamicFeeV2Abi, LiquidLpLockerAbi, type LiquidMetadata, LiquidMevBlockDelayAbi, LiquidMevDescendingFeesAbi, LiquidPoolExtensionAllowlistAbi, LiquidSDK, type LiquidSDKConfig, LiquidSniperAuctionV2Abi, LiquidSniperUtilV2Abi, LiquidTokenAbi, LiquidUniv4EthDevBuyAbi, LiquidVaultAbi, type LockerConfig, type MarketCapTranche, type MarketCapTrancheUSD, type MevModuleConfig, POOL_POSITIONS, type PoolConfig, type PoolDynamicConfigVars, type PoolDynamicFeeVars, type PoolKey, type PoolPosition, type PositionArrays, type PositionConfig, type SniperAuctionConfig, type SniperAuctionFeeConfig, type SniperAuctionState, type SocialMediaUrl, TOKEN, type TokenConfig, type TokenCreatedEvent, type TokenRewardInfo, type VaultAllocation, type VaultExtensionParams, buildContext, buildMetadata, createDefaultPositions, createLiquidPositionsUSD, createPositions, createPositionsUSD, describePositions, encodeDynamicFeePoolData, encodeFeeConversionLockerData, encodeSniperAuctionData, encodeStaticFeePoolData, getTickFromMarketCapETH, getTickFromMarketCapStable, getTickFromMarketCapUSD, marketCapFromTickETH, marketCapFromTickUSD, parseContext, parseMetadata, shiftPositions };
package/dist/index.d.ts CHANGED
@@ -63,6 +63,21 @@ interface VaultExtensionParams {
63
63
  /** Vesting duration in seconds after lockup ends (0 = no vesting, tokens unlock all at once) */
64
64
  vestingDuration?: number;
65
65
  }
66
+ interface AirdropExtensionParams {
67
+ /** Address allowed to `updateAdmin`, `updateMerkleRoot` (under conditions),
68
+ * and `adminClaim` the remainder after claim expiration. */
69
+ admin: Address;
70
+ /** Merkle root over leaves `keccak256(bytes.concat(keccak256(abi.encode(
71
+ * recipient, allocatedAmount))))`. Double-hashed per OZ convention. */
72
+ merkleRoot: Hex;
73
+ /** Percentage of supply to reserve for the airdrop, in BPS (1–9000). */
74
+ allocationBps: number;
75
+ /** Lockup in seconds before any recipient can claim. Min 86400 (1 day). */
76
+ lockupDuration: number;
77
+ /** Linear vesting after lockup. 0 = instant claim of full entitlement at
78
+ * lockup end. */
79
+ vestingDuration?: number;
80
+ }
66
81
  interface DeployTokenParams {
67
82
  name: string;
68
83
  symbol: string;
@@ -270,6 +285,29 @@ declare class LiquidSDK {
270
285
  * ```
271
286
  */
272
287
  buildVaultExtension(vault: VaultExtensionParams): ExtensionConfig;
288
+ /**
289
+ * Build an ExtensionConfig that reserves a percentage of supply into
290
+ * the LiquidAirdropV2 contract for merkle-tree-based distribution.
291
+ *
292
+ * The airdrop contract expects `AirdropV2ExtensionData`:
293
+ * { address admin, bytes32 merkleRoot, uint256 lockupDuration, uint256 vestingDuration }
294
+ *
295
+ * Leaf encoding used by LiquidAirdropV2.claim (note: **double hashed**
296
+ * — OZ's standard 2nd-preimage-resistant pattern):
297
+ * leaf = keccak256(bytes.concat(keccak256(abi.encode(recipient, allocatedAmount))))
298
+ *
299
+ * @example
300
+ * ```typescript
301
+ * const airdropExt = sdk.buildAirdropExtension({
302
+ * admin: account.address,
303
+ * merkleRoot: "0x…",
304
+ * allocationBps: 2000, // 20%
305
+ * lockupDuration: 86400, // 1 day (minimum)
306
+ * vestingDuration: 0, // instant claim after lockup
307
+ * });
308
+ * ```
309
+ */
310
+ buildAirdropExtension(airdrop: AirdropExtensionParams): ExtensionConfig;
273
311
  /**
274
312
  * Validate a DeploymentConfig before sending to the contract.
275
313
  * Catches common mistakes client-side with clear error messages.
@@ -433,6 +471,9 @@ declare const ADDRESSES: {
433
471
  declare const EXTERNAL: {
434
472
  readonly POOL_MANAGER: Address;
435
473
  readonly WETH: Address;
474
+ /** DIEM — Liquid's intelligence-economy token. Also a pair token for
475
+ * agent-token launches (see `createLiquidPositionsUSD`). */
476
+ readonly DIEM: Address;
436
477
  readonly UNIVERSAL_ROUTER: Address;
437
478
  readonly PERMIT2: Address;
438
479
  };
@@ -489,7 +530,7 @@ declare const POOL_POSITIONS: {
489
530
  */
490
531
  declare const DEFAULTS: {
491
532
  readonly HOOK: `0x${string}`;
492
- /** LP Locker with fee conversion (converts fees to ETH before distributing) */
533
+ /** LP Locker with fee conversion (converts fees to WETH before distributing) */
493
534
  readonly LOCKER: `0x${string}`;
494
535
  readonly TICK_SPACING: 200;
495
536
  readonly TICK_IF_TOKEN0_IS_LIQUID: -230400;
@@ -583,31 +624,7 @@ declare const DEFAULT_CHAIN: {
583
624
  formatters: {
584
625
  readonly block: {
585
626
  exclude: [] | undefined;
586
- format: (args: viem_chains.OpStackRpcBlock, action
587
- /**
588
- * Pre-built position configurations.
589
- *
590
- * - **Standard**: Single position covering full range (~$20K → $1.5B).
591
- * Default starting tick -230400 (≈10 ETH market cap).
592
- *
593
- * - **Liquid**: 3-tranche default for Liquid Protocol.
594
- * Hardcoded for ≈10 ETH start at ~$2070/ETH.
595
- * For dynamic market cap targets, use `createPositionsUSD()` instead.
596
- *
597
- * Note: positionBps must sum to 10,000 (100%).
598
- */
599
- ? /**
600
- * Pre-built position configurations.
601
- *
602
- * - **Standard**: Single position covering full range (~$20K → $1.5B).
603
- * Default starting tick -230400 (≈10 ETH market cap).
604
- *
605
- * - **Liquid**: 3-tranche default for Liquid Protocol.
606
- * Hardcoded for ≈10 ETH start at ~$2070/ETH.
607
- * For dynamic market cap targets, use `createPositionsUSD()` instead.
608
- *
609
- * Note: positionBps must sum to 10,000 (100%).
610
- */: string | undefined) => {
627
+ format: (args: viem_chains.OpStackRpcBlock, action?: string | undefined) => {
611
628
  baseFeePerGas: bigint | null;
612
629
  blobGasUsed: bigint;
613
630
  difficulty: bigint;
@@ -2285,6 +2302,7 @@ declare function getTickFromMarketCapStable(marketCap: number, stableDecimals: n
2285
2302
  * market cap milestones. Percentages represent share of the *pool supply*
2286
2303
  * (i.e. after dev buy, airdrop, and vault allocations are deducted).
2287
2304
  */
2305
+
2288
2306
  interface MarketCapTranche {
2289
2307
  /** Upper bound market cap in ETH for this tranche */
2290
2308
  upperMarketCapETH: number;
@@ -2380,6 +2398,55 @@ declare function createPositionsUSD(startingMarketCapUSD: number, ethPriceUSD: n
2380
2398
  declare function createDefaultPositions(startingMarketCapUSD: number, ethPriceUSD: number, tickSpacing?: number): PositionArrays & {
2381
2399
  tickIfToken0IsLiquid: number;
2382
2400
  };
2401
+ /**
2402
+ * Shift every tick in a position layout by a fixed amount, preserving the
2403
+ * positionBps splits. The primitive behind `createLiquidPositionsUSD` — it
2404
+ * re-anchors a fixed-shape layout (e.g. `POOL_POSITIONS.Liquid`) to a
2405
+ * different starting tick.
2406
+ *
2407
+ * `shiftBy` should be a multiple of the pool's tick spacing so the shifted
2408
+ * ticks stay aligned. A difference of two aligned ticks is always aligned,
2409
+ * so deriving it as `targetTick - sourceBottomTick` is safe.
2410
+ *
2411
+ * @param positions - Source positions (e.g. `POOL_POSITIONS.Liquid`)
2412
+ * @param shiftBy - Ticks to add to every tickLower/tickUpper (may be negative)
2413
+ * @returns A fresh array — the source is not mutated
2414
+ */
2415
+ declare function shiftPositions(positions: readonly PoolPosition[], shiftBy: number): PoolPosition[];
2416
+ /**
2417
+ * Build the canonical 5-position "Liquid" layout (10/50/15/20/5) re-anchored
2418
+ * to a starting market cap, denominated in the *paired token's* USD price.
2419
+ *
2420
+ * Works for any pair token — pass the price of whatever the pool is paired
2421
+ * against:
2422
+ * - WETH-paired: `createLiquidPositionsUSD(20_000, ethPriceUSD)`
2423
+ * - DIEM-paired: `createLiquidPositionsUSD(20_000, diemPriceUSD)`
2424
+ *
2425
+ * Unlike `createDefaultPositions` (a 3-tranche layout), this preserves the
2426
+ * exact shape of `POOL_POSITIONS.Liquid` — the same curve `deployToken()`
2427
+ * uses by default — just shifted so its bottom sits at the requested start.
2428
+ *
2429
+ * @param startingMarketCapUSD - Initial market cap in USD
2430
+ * @param pairedTokenPriceUSD - USD price of the token the pool is paired against
2431
+ * @param tickSpacing - Tick spacing (default 200)
2432
+ * @returns Position arrays + `tickIfToken0IsLiquid`, ready to spread into `deployToken()`
2433
+ *
2434
+ * @example
2435
+ * ```ts
2436
+ * import { LiquidSDK, EXTERNAL, createLiquidPositionsUSD } from "liquid-sdk";
2437
+ *
2438
+ * const positions = createLiquidPositionsUSD(20_000, diemPriceUSD);
2439
+ * await sdk.deployToken({
2440
+ * name: "Agent Token",
2441
+ * symbol: "AGENT",
2442
+ * pairedToken: EXTERNAL.DIEM,
2443
+ * ...positions,
2444
+ * });
2445
+ * ```
2446
+ */
2447
+ declare function createLiquidPositionsUSD(startingMarketCapUSD: number, pairedTokenPriceUSD: number, tickSpacing?: number): PositionArrays & {
2448
+ tickIfToken0IsLiquid: number;
2449
+ };
2383
2450
  /**
2384
2451
  * Describe positions as human-readable market cap ranges.
2385
2452
  * Useful for displaying position info in UIs.
@@ -2496,7 +2563,7 @@ declare enum FeePreference {
2496
2563
  *
2497
2564
  * @example
2498
2565
  * ```ts
2499
- * // Single recipient, fees converted to ETH
2566
+ * // Single recipient, fees converted to WETH
2500
2567
  * const lockerData = encodeFeeConversionLockerData([FeePreference.Paired]);
2501
2568
  *
2502
2569
  * // Two recipients: first gets ETH, second gets the token
@@ -2557,4 +2624,4 @@ declare function parseContext(contextString: string): LiquidContext | null;
2557
2624
  */
2558
2625
  declare function parseMetadata(metadataString: string): LiquidMetadata | null;
2559
2626
 
2560
- export { ADDRESSES, type AirdropInfo, type BidInAuctionParams, type BidInAuctionResult, DEFAULTS, DEFAULT_CHAIN, DEFAULT_CHAIN_ID, DEFAULT_RPC_URL, DEFAULT_TRANCHES_USD, type DeployTokenParams, type DeployTokenResult, type DeploymentConfig, type DeploymentInfo, type DevBuyParams, type DynamicFeeConfig, ERC20Abi, EXTERNAL, type ExtensionConfig, FEE, FeePreference, type GetTokensOptions, LiquidAirdropV2Abi, type LiquidContext, LiquidFactoryAbi, LiquidFeeLockerAbi, LiquidHookDynamicFeeV2Abi, LiquidLpLockerAbi, type LiquidMetadata, LiquidMevBlockDelayAbi, LiquidMevDescendingFeesAbi, LiquidPoolExtensionAllowlistAbi, LiquidSDK, type LiquidSDKConfig, LiquidSniperAuctionV2Abi, LiquidSniperUtilV2Abi, LiquidTokenAbi, LiquidUniv4EthDevBuyAbi, LiquidVaultAbi, type LockerConfig, type MarketCapTranche, type MarketCapTrancheUSD, type MevModuleConfig, POOL_POSITIONS, type PoolConfig, type PoolDynamicConfigVars, type PoolDynamicFeeVars, type PoolKey, type PoolPosition, type PositionArrays, type PositionConfig, type SniperAuctionConfig, type SniperAuctionFeeConfig, type SniperAuctionState, type SocialMediaUrl, TOKEN, type TokenConfig, type TokenCreatedEvent, type TokenRewardInfo, type VaultAllocation, type VaultExtensionParams, buildContext, buildMetadata, createDefaultPositions, createPositions, createPositionsUSD, describePositions, encodeDynamicFeePoolData, encodeFeeConversionLockerData, encodeSniperAuctionData, encodeStaticFeePoolData, getTickFromMarketCapETH, getTickFromMarketCapStable, getTickFromMarketCapUSD, marketCapFromTickETH, marketCapFromTickUSD, parseContext, parseMetadata };
2627
+ export { ADDRESSES, type AirdropExtensionParams, type AirdropInfo, type BidInAuctionParams, type BidInAuctionResult, DEFAULTS, DEFAULT_CHAIN, DEFAULT_CHAIN_ID, DEFAULT_RPC_URL, DEFAULT_TRANCHES_USD, type DeployTokenParams, type DeployTokenResult, type DeploymentConfig, type DeploymentInfo, type DevBuyParams, type DynamicFeeConfig, ERC20Abi, EXTERNAL, type ExtensionConfig, FEE, FeePreference, type GetTokensOptions, LiquidAirdropV2Abi, type LiquidContext, LiquidFactoryAbi, LiquidFeeLockerAbi, LiquidHookDynamicFeeV2Abi, LiquidLpLockerAbi, type LiquidMetadata, LiquidMevBlockDelayAbi, LiquidMevDescendingFeesAbi, LiquidPoolExtensionAllowlistAbi, LiquidSDK, type LiquidSDKConfig, LiquidSniperAuctionV2Abi, LiquidSniperUtilV2Abi, LiquidTokenAbi, LiquidUniv4EthDevBuyAbi, LiquidVaultAbi, type LockerConfig, type MarketCapTranche, type MarketCapTrancheUSD, type MevModuleConfig, POOL_POSITIONS, type PoolConfig, type PoolDynamicConfigVars, type PoolDynamicFeeVars, type PoolKey, type PoolPosition, type PositionArrays, type PositionConfig, type SniperAuctionConfig, type SniperAuctionFeeConfig, type SniperAuctionState, type SocialMediaUrl, TOKEN, type TokenConfig, type TokenCreatedEvent, type TokenRewardInfo, type VaultAllocation, type VaultExtensionParams, buildContext, buildMetadata, createDefaultPositions, createLiquidPositionsUSD, createPositions, createPositionsUSD, describePositions, encodeDynamicFeePoolData, encodeFeeConversionLockerData, encodeSniperAuctionData, encodeStaticFeePoolData, getTickFromMarketCapETH, getTickFromMarketCapStable, getTickFromMarketCapUSD, marketCapFromTickETH, marketCapFromTickUSD, parseContext, parseMetadata, shiftPositions };
package/dist/index.js CHANGED
@@ -49,6 +49,7 @@ __export(index_exports, {
49
49
  buildContext: () => buildContext,
50
50
  buildMetadata: () => buildMetadata,
51
51
  createDefaultPositions: () => createDefaultPositions,
52
+ createLiquidPositionsUSD: () => createLiquidPositionsUSD,
52
53
  createPositions: () => createPositions,
53
54
  createPositionsUSD: () => createPositionsUSD,
54
55
  describePositions: () => describePositions,
@@ -62,7 +63,8 @@ __export(index_exports, {
62
63
  marketCapFromTickETH: () => marketCapFromTickETH,
63
64
  marketCapFromTickUSD: () => marketCapFromTickUSD,
64
65
  parseContext: () => parseContext,
65
- parseMetadata: () => parseMetadata
66
+ parseMetadata: () => parseMetadata,
67
+ shiftPositions: () => shiftPositions
66
68
  });
67
69
  module.exports = __toCommonJS(index_exports);
68
70
 
@@ -92,6 +94,9 @@ var ADDRESSES = {
92
94
  var EXTERNAL = {
93
95
  POOL_MANAGER: "0x498581fF718922c3f8e6A244956aF099B2652b2b",
94
96
  WETH: "0x4200000000000000000000000000000000000006",
97
+ /** DIEM — Liquid's intelligence-economy token. Also a pair token for
98
+ * agent-token launches (see `createLiquidPositionsUSD`). */
99
+ DIEM: "0xF4d97F2da56e8c3098f3a8D538DB630A2606a024",
95
100
  UNIVERSAL_ROUTER: "0x6fF5693b99212Da76ad316178A184AB56D299b43",
96
101
  PERMIT2: "0x000000000022D473030F116dDEE9F6B43aC78BA3"
97
102
  };
@@ -161,7 +166,7 @@ var POOL_POSITIONS = {
161
166
  };
162
167
  var DEFAULTS = {
163
168
  HOOK: ADDRESSES.HOOK_STATIC_FEE_V2,
164
- /** LP Locker with fee conversion (converts fees to ETH before distributing) */
169
+ /** LP Locker with fee conversion (converts fees to WETH before distributing) */
165
170
  LOCKER: ADDRESSES.LP_LOCKER_FEE_CONVERSION,
166
171
  TICK_SPACING: 200,
167
172
  TICK_IF_TOKEN0_IS_LIQUID: -230400,
@@ -1201,6 +1206,73 @@ var LiquidSDK = class {
1201
1206
  extensionData
1202
1207
  };
1203
1208
  }
1209
+ // ── Airdrop Extension ──────────────────────────────────────────
1210
+ /**
1211
+ * Build an ExtensionConfig that reserves a percentage of supply into
1212
+ * the LiquidAirdropV2 contract for merkle-tree-based distribution.
1213
+ *
1214
+ * The airdrop contract expects `AirdropV2ExtensionData`:
1215
+ * { address admin, bytes32 merkleRoot, uint256 lockupDuration, uint256 vestingDuration }
1216
+ *
1217
+ * Leaf encoding used by LiquidAirdropV2.claim (note: **double hashed**
1218
+ * — OZ's standard 2nd-preimage-resistant pattern):
1219
+ * leaf = keccak256(bytes.concat(keccak256(abi.encode(recipient, allocatedAmount))))
1220
+ *
1221
+ * @example
1222
+ * ```typescript
1223
+ * const airdropExt = sdk.buildAirdropExtension({
1224
+ * admin: account.address,
1225
+ * merkleRoot: "0x…",
1226
+ * allocationBps: 2000, // 20%
1227
+ * lockupDuration: 86400, // 1 day (minimum)
1228
+ * vestingDuration: 0, // instant claim after lockup
1229
+ * });
1230
+ * ```
1231
+ */
1232
+ buildAirdropExtension(airdrop) {
1233
+ const MIN_LOCKUP = 86400;
1234
+ const MAX_BPS = 9e3;
1235
+ if (airdrop.allocationBps < 1 || airdrop.allocationBps > MAX_BPS) {
1236
+ throw new Error(
1237
+ `Airdrop allocationBps must be 1\u2013${MAX_BPS} (0.01%\u201390%). Got ${airdrop.allocationBps}.`
1238
+ );
1239
+ }
1240
+ if (airdrop.lockupDuration < MIN_LOCKUP) {
1241
+ throw new Error(
1242
+ `Airdrop lockupDuration must be \u2265 ${MIN_LOCKUP} seconds (1 day). Got ${airdrop.lockupDuration}.`
1243
+ );
1244
+ }
1245
+ if (airdrop.vestingDuration !== void 0 && airdrop.vestingDuration < 0) {
1246
+ throw new Error("Airdrop vestingDuration cannot be negative.");
1247
+ }
1248
+ const extensionData = (0, import_viem2.encodeAbiParameters)(
1249
+ [
1250
+ {
1251
+ type: "tuple",
1252
+ components: [
1253
+ { type: "address", name: "admin" },
1254
+ { type: "bytes32", name: "merkleRoot" },
1255
+ { type: "uint256", name: "lockupDuration" },
1256
+ { type: "uint256", name: "vestingDuration" }
1257
+ ]
1258
+ }
1259
+ ],
1260
+ [
1261
+ {
1262
+ admin: airdrop.admin,
1263
+ merkleRoot: airdrop.merkleRoot,
1264
+ lockupDuration: BigInt(airdrop.lockupDuration),
1265
+ vestingDuration: BigInt(airdrop.vestingDuration ?? 0)
1266
+ }
1267
+ ]
1268
+ );
1269
+ return {
1270
+ extension: ADDRESSES.AIRDROP_V2,
1271
+ msgValue: 0n,
1272
+ extensionBps: airdrop.allocationBps,
1273
+ extensionData
1274
+ };
1275
+ }
1204
1276
  // ── Validation ─────────────────────────────────────────────────
1205
1277
  /**
1206
1278
  * Validate a DeploymentConfig before sending to the contract.
@@ -1365,13 +1437,36 @@ var LiquidSDK = class {
1365
1437
  (sum, ext) => sum + ext.msgValue,
1366
1438
  0n
1367
1439
  );
1440
+ let gas;
1441
+ try {
1442
+ const estimated = await this.publicClient.estimateContractGas({
1443
+ address: ADDRESSES.FACTORY,
1444
+ abi: LiquidFactoryAbi,
1445
+ functionName: "deployToken",
1446
+ args: [deploymentConfig],
1447
+ value: msgValue,
1448
+ account: this.walletClient.account
1449
+ });
1450
+ gas = estimated * 120n / 100n;
1451
+ } catch (err) {
1452
+ const e = err;
1453
+ const looksLikeRevert = e?.name === "ContractFunctionExecutionError" || e?.name === "CallExecutionError" || typeof e?.shortMessage === "string" && /reverted|revert reason|execution reverted/i.test(e.shortMessage);
1454
+ if (looksLikeRevert) throw err;
1455
+ if (typeof console !== "undefined" && console.warn) {
1456
+ console.warn(
1457
+ "[liquid-sdk] deployToken gas estimation failed; falling back to 6M gas limit:",
1458
+ e?.shortMessage ?? err
1459
+ );
1460
+ }
1461
+ gas = 6000000n;
1462
+ }
1368
1463
  const txHash = await this.walletClient.writeContract({
1369
1464
  address: ADDRESSES.FACTORY,
1370
1465
  abi: LiquidFactoryAbi,
1371
1466
  functionName: "deployToken",
1372
1467
  args: [deploymentConfig],
1373
1468
  value: msgValue,
1374
- gas: 5000000n,
1469
+ gas,
1375
1470
  chain: import_chains2.base,
1376
1471
  account: this.walletClient.account
1377
1472
  });
@@ -2356,6 +2451,33 @@ function createDefaultPositions(startingMarketCapUSD, ethPriceUSD, tickSpacing =
2356
2451
  tickIfToken0IsLiquid: positions.tickLower[0]
2357
2452
  };
2358
2453
  }
2454
+ function shiftPositions(positions, shiftBy) {
2455
+ return positions.map((p) => ({
2456
+ tickLower: p.tickLower + shiftBy,
2457
+ tickUpper: p.tickUpper + shiftBy,
2458
+ positionBps: p.positionBps
2459
+ }));
2460
+ }
2461
+ function createLiquidPositionsUSD(startingMarketCapUSD, pairedTokenPriceUSD, tickSpacing = 200) {
2462
+ if (pairedTokenPriceUSD <= 0) {
2463
+ throw new Error("pairedTokenPriceUSD must be positive");
2464
+ }
2465
+ const startingTick = getTickFromMarketCapUSD(
2466
+ startingMarketCapUSD,
2467
+ pairedTokenPriceUSD,
2468
+ tickSpacing
2469
+ );
2470
+ const shifted = shiftPositions(
2471
+ POOL_POSITIONS.Liquid,
2472
+ startingTick - DEFAULTS.TICK_IF_TOKEN0_IS_LIQUID
2473
+ );
2474
+ return {
2475
+ tickLower: shifted.map((p) => p.tickLower),
2476
+ tickUpper: shifted.map((p) => p.tickUpper),
2477
+ positionBps: shifted.map((p) => p.positionBps),
2478
+ tickIfToken0IsLiquid: startingTick
2479
+ };
2480
+ }
2359
2481
  function describePositions(positions, ethPriceUSD) {
2360
2482
  return positions.tickLower.map((_, i) => {
2361
2483
  const lowerETH = Math.pow(1.0001, positions.tickLower[i]) * 1e11;
@@ -2405,6 +2527,7 @@ function describePositions(positions, ethPriceUSD) {
2405
2527
  buildContext,
2406
2528
  buildMetadata,
2407
2529
  createDefaultPositions,
2530
+ createLiquidPositionsUSD,
2408
2531
  createPositions,
2409
2532
  createPositionsUSD,
2410
2533
  describePositions,
@@ -2418,6 +2541,7 @@ function describePositions(positions, ethPriceUSD) {
2418
2541
  marketCapFromTickETH,
2419
2542
  marketCapFromTickUSD,
2420
2543
  parseContext,
2421
- parseMetadata
2544
+ parseMetadata,
2545
+ shiftPositions
2422
2546
  });
2423
2547
  //# sourceMappingURL=index.js.map