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.
@@ -0,0 +1,770 @@
1
+ # liquid-sdk — Agent & Developer Reference
2
+
3
+ > Zero API keys. One peer dependency (`viem`). Full on-chain token lifecycle on Base.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install liquid-sdk viem
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```typescript
14
+ import { createPublicClient, createWalletClient, http } from "viem";
15
+ import { base } from "viem/chains";
16
+ import { privateKeyToAccount } from "viem/accounts";
17
+ import { LiquidSDK } from "liquid-sdk";
18
+
19
+ // Read-only (no wallet needed)
20
+ const publicClient = createPublicClient({ chain: base, transport: http() });
21
+ const sdk = new LiquidSDK({ publicClient });
22
+
23
+ // Read + write (wallet required for transactions)
24
+ const account = privateKeyToAccount("0x...");
25
+ const walletClient = createWalletClient({ account, chain: base, transport: http() });
26
+ const sdk = new LiquidSDK({ publicClient, walletClient });
27
+ ```
28
+
29
+ No API keys, no backend, no database. The SDK talks directly to Base mainnet contracts via any RPC endpoint.
30
+
31
+ ---
32
+
33
+ ## What This SDK Does
34
+
35
+ Liquid Protocol deploys ERC-20 tokens on Base with:
36
+ - Uniswap V4 liquidity pools (automatic)
37
+ - LP fee collection and reward distribution
38
+ - MEV protection via block delay
39
+ - Optional extensions: dev buy, vault lockup/vesting, airdrops
40
+
41
+ Every token gets 100 billion supply (18 decimals), a Uniswap V4 pool, and locked liquidity with configurable reward splits.
42
+
43
+ ---
44
+
45
+ ## Complete Method Reference
46
+
47
+ ### Token Deployment
48
+
49
+ #### `sdk.deployToken(params)` — Deploy a new token
50
+
51
+ Requires wallet. Creates the token, pool, locks LP, and optionally buys tokens at launch.
52
+
53
+ ```typescript
54
+ const result = await sdk.deployToken({
55
+ name: "My Token",
56
+ symbol: "MTK",
57
+ image: "https://example.com/logo.png", // optional
58
+ metadata: '{"description":"A cool token"}', // optional, JSON string
59
+ context: '{"platform":"my-app"}', // optional, tracking/attribution
60
+
61
+ // All fields below are optional — sensible defaults are applied
62
+ // See "Default Values" section for what gets used if omitted
63
+ });
64
+
65
+ console.log(result.tokenAddress); // 0x... deployed token
66
+ console.log(result.txHash); // 0x... transaction hash
67
+ console.log(result.event.poolId); // 0x... Uniswap V4 pool ID
68
+ ```
69
+
70
+ **Returns:** `{ tokenAddress, txHash, event }` where `event` contains the full `TokenCreated` event data (poolId, hook, locker, extensions, etc.)
71
+
72
+ #### `sdk.deployToken(params)` — With dev buy (buy tokens at launch)
73
+
74
+ ```typescript
75
+ const result = await sdk.deployToken({
76
+ name: "My Token",
77
+ symbol: "MTK",
78
+ devBuy: {
79
+ ethAmount: parseEther("0.01"), // ETH to spend buying tokens
80
+ recipient: account.address, // who gets the tokens
81
+ },
82
+ });
83
+ ```
84
+
85
+ The dev buy extension is appended automatically. The ETH is swapped for tokens through the Uniswap V4 pool in the same transaction as deployment.
86
+
87
+ #### `sdk.buildDevBuyExtension(devBuy)` — Build dev buy extension manually
88
+
89
+ ```typescript
90
+ const ext = sdk.buildDevBuyExtension({
91
+ ethAmount: parseEther("0.1"),
92
+ recipient: "0x...",
93
+ });
94
+ // ext is an ExtensionConfig you can include in params.extensions
95
+ ```
96
+
97
+ ---
98
+
99
+ ### Checking & Collecting Fees
100
+
101
+ Tokens generate LP fees from Uniswap V4 trading. These accrue in the Fee Locker and can be claimed by the fee owner.
102
+
103
+ #### `sdk.getAvailableFees(feeOwner, tokenAddress)` — Check total unlocked fees
104
+
105
+ ```typescript
106
+ const fees = await sdk.getAvailableFees(ownerAddress, tokenAddress);
107
+ // fees: bigint — total fees available (in token's paired asset, usually WETH)
108
+ ```
109
+
110
+ #### `sdk.getFeesToClaim(feeOwner, tokenAddress)` — Check claimable fees
111
+
112
+ ```typescript
113
+ const claimable = await sdk.getFeesToClaim(ownerAddress, tokenAddress);
114
+ // claimable: bigint — fees ready to claim right now
115
+ ```
116
+
117
+ #### `sdk.claimFees(feeOwner, tokenAddress)` — Claim fees
118
+
119
+ Requires wallet.
120
+
121
+ ```typescript
122
+ if (claimable > 0n) {
123
+ const txHash = await sdk.claimFees(ownerAddress, tokenAddress);
124
+ await publicClient.waitForTransactionReceipt({ hash: txHash });
125
+ }
126
+ ```
127
+
128
+ ---
129
+
130
+ ### Checking & Collecting LP Rewards
131
+
132
+ LP rewards are distributed to reward recipients configured at deployment. The LP Locker holds the position and distributes fees according to BPS splits.
133
+
134
+ #### `sdk.getTokenRewards(tokenAddress)` — Get reward configuration
135
+
136
+ ```typescript
137
+ const rewards = await sdk.getTokenRewards(tokenAddress);
138
+ // rewards.rewardRecipients: Address[] — who receives rewards
139
+ // rewards.rewardBps: number[] — basis points per recipient (sum = 10000)
140
+ // rewards.rewardAdmins: Address[] — who can update recipients
141
+ // rewards.poolKey: PoolKey — the Uniswap V4 pool
142
+ // rewards.positionId: bigint — LP position NFT ID
143
+ // rewards.numPositions: bigint — number of LP positions
144
+ ```
145
+
146
+ #### `sdk.collectRewards(tokenAddress)` — Collect rewards and unlock LP
147
+
148
+ Requires wallet. Collects all accrued LP fees and distributes to recipients.
149
+
150
+ ```typescript
151
+ const txHash = await sdk.collectRewards(tokenAddress);
152
+ await publicClient.waitForTransactionReceipt({ hash: txHash });
153
+ ```
154
+
155
+ #### `sdk.collectRewardsWithoutUnlock(tokenAddress)` — Collect fees only (no unlock)
156
+
157
+ Requires wallet. Same as above but does not unlock the LP position. Use this to avoid MEV during collection.
158
+
159
+ ```typescript
160
+ const txHash = await sdk.collectRewardsWithoutUnlock(tokenAddress);
161
+ await publicClient.waitForTransactionReceipt({ hash: txHash });
162
+ ```
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.
165
+
166
+ #### `sdk.updateRewardRecipient(tokenAddress, rewardIndex, newRecipient)` — Change reward recipient
167
+
168
+ Requires wallet. Only callable by the reward admin for that index.
169
+
170
+ ```typescript
171
+ // Change the first reward recipient (index 0)
172
+ const txHash = await sdk.updateRewardRecipient(
173
+ tokenAddress,
174
+ 0n, // reward index (bigint)
175
+ newRecipientAddress, // new recipient
176
+ );
177
+ await publicClient.waitForTransactionReceipt({ hash: txHash });
178
+ ```
179
+
180
+ ---
181
+
182
+ ### Vault (Token Lockup & Vesting)
183
+
184
+ Tokens can be locked in a vault with a lockup period followed by linear vesting.
185
+
186
+ #### `sdk.getVaultAllocation(tokenAddress)` — Check vault state
187
+
188
+ ```typescript
189
+ const vault = await sdk.getVaultAllocation(tokenAddress);
190
+ // vault.amountTotal: bigint — total tokens locked
191
+ // vault.amountClaimed: bigint — already claimed
192
+ // vault.lockupEndTime: bigint — when lockup ends (unix timestamp)
193
+ // vault.vestingEndTime: bigint — when vesting fully unlocks (unix timestamp)
194
+ // vault.admin: Address — who can claim
195
+ // vault.token: Address — the token
196
+ ```
197
+
198
+ #### `sdk.getVaultClaimable(tokenAddress)` — Check claimable amount
199
+
200
+ ```typescript
201
+ const claimable = await sdk.getVaultClaimable(tokenAddress);
202
+ // claimable: bigint — tokens available to claim right now
203
+ ```
204
+
205
+ #### `sdk.claimVault(tokenAddress)` — Claim vested tokens
206
+
207
+ Requires wallet.
208
+
209
+ ```typescript
210
+ if (claimable > 0n) {
211
+ const txHash = await sdk.claimVault(tokenAddress);
212
+ await publicClient.waitForTransactionReceipt({ hash: txHash });
213
+ }
214
+ ```
215
+
216
+ ---
217
+
218
+ ### Airdrop
219
+
220
+ Tokens can include a merkle-tree airdrop extension for distributing tokens to a list of recipients.
221
+
222
+ #### `sdk.getAirdropInfo(tokenAddress)` — Check airdrop state
223
+
224
+ ```typescript
225
+ const info = await sdk.getAirdropInfo(tokenAddress);
226
+ // info.merkleRoot: Hex — merkle root
227
+ // info.totalSupply: bigint — total airdrop supply
228
+ // info.totalClaimed: bigint — already claimed
229
+ // info.lockupEndTime: bigint — when claims begin
230
+ // info.vestingEndTime: bigint — when vesting completes
231
+ // info.admin: Address — airdrop admin
232
+ // info.adminClaimed: boolean — whether admin reclaimed unclaimed tokens
233
+ ```
234
+
235
+ #### `sdk.getAirdropClaimable(tokenAddress, recipient, allocatedAmount)` — Check claimable
236
+
237
+ ```typescript
238
+ const claimable = await sdk.getAirdropClaimable(
239
+ tokenAddress,
240
+ recipientAddress,
241
+ allocatedAmount, // bigint — total allocation for this recipient (18 decimals)
242
+ );
243
+ ```
244
+
245
+ #### `sdk.claimAirdrop(tokenAddress, recipient, allocatedAmount, proof)` — Claim airdrop
246
+
247
+ Requires wallet. The merkle proof must be generated off-chain from the original airdrop tree.
248
+
249
+ ```typescript
250
+ const txHash = await sdk.claimAirdrop(
251
+ tokenAddress,
252
+ recipientAddress,
253
+ allocatedAmount, // bigint
254
+ merkleProof, // Hex[] — from the merkle tree
255
+ );
256
+ await publicClient.waitForTransactionReceipt({ hash: txHash });
257
+ ```
258
+
259
+ ---
260
+
261
+ ### Token Info
262
+
263
+ #### `sdk.getTokenInfo(tokenAddress)` — Get token metadata
264
+
265
+ ```typescript
266
+ const info = await sdk.getTokenInfo(tokenAddress);
267
+ // info.address: Address
268
+ // info.name: string
269
+ // info.symbol: string
270
+ // info.decimals: number (always 18)
271
+ // info.totalSupply: bigint
272
+ // info.deployment: { token, hook, locker, extensions }
273
+ ```
274
+
275
+ #### `sdk.getDeploymentInfo(tokenAddress)` — Get deployment addresses
276
+
277
+ ```typescript
278
+ const deploy = await sdk.getDeploymentInfo(tokenAddress);
279
+ // deploy.token: Address
280
+ // deploy.hook: Address — which hook contract
281
+ // deploy.locker: Address — which locker contract
282
+ // deploy.extensions: Address[] — active extensions
283
+ ```
284
+
285
+ ---
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
+
330
+ ### Token Metadata Updates
331
+
332
+ #### `sdk.updateImage(tokenAddress, newImageUrl)` — Update token image
333
+
334
+ Requires wallet. Only callable by token admin.
335
+
336
+ ```typescript
337
+ const txHash = await sdk.updateImage(tokenAddress, "https://new-image.png");
338
+ ```
339
+
340
+ #### `sdk.updateMetadata(tokenAddress, newMetadata)` — Update token metadata
341
+
342
+ Requires wallet. Only callable by token admin.
343
+
344
+ ```typescript
345
+ const txHash = await sdk.updateMetadata(tokenAddress, '{"description":"Updated"}');
346
+ ```
347
+
348
+ ---
349
+
350
+ ### Pool Reads
351
+
352
+ #### `sdk.getPoolConfig(poolId)` — Get dynamic fee configuration
353
+
354
+ ```typescript
355
+ const config = await sdk.getPoolConfig(poolId);
356
+ // config.baseFee: number — minimum fee (bps)
357
+ // config.maxLpFee: number — maximum LP fee
358
+ // config.referenceTickFilterPeriod: bigint — seconds
359
+ // config.resetPeriod: bigint — seconds
360
+ // config.resetTickFilter: number
361
+ // config.feeControlNumerator: bigint
362
+ // config.decayFilterBps: number
363
+ ```
364
+
365
+ #### `sdk.getPoolFeeState(poolId)` — Get current fee state
366
+
367
+ ```typescript
368
+ const state = await sdk.getPoolFeeState(poolId);
369
+ // state.referenceTick: number
370
+ // state.resetTick: number
371
+ // state.resetTickTimestamp: bigint
372
+ // state.lastSwapTimestamp: bigint
373
+ // state.appliedVR: number
374
+ // state.prevVA: number
375
+ ```
376
+
377
+ #### `sdk.getPoolCreationTimestamp(poolId)` — When was the pool created
378
+
379
+ ```typescript
380
+ const timestamp = await sdk.getPoolCreationTimestamp(poolId);
381
+ ```
382
+
383
+ #### `sdk.isLiquidToken0(poolId)` — Is the token token0 or token1
384
+
385
+ ```typescript
386
+ const isToken0 = await sdk.isLiquidToken0(poolId);
387
+ ```
388
+
389
+ ---
390
+
391
+ ### Sniper Auction
392
+
393
+ MEV auction system that prices early trading activity.
394
+
395
+ #### `sdk.getAuctionState(poolId)` — Current auction state
396
+
397
+ ```typescript
398
+ const auction = await sdk.getAuctionState(poolId);
399
+ // auction.nextAuctionBlock: bigint
400
+ // auction.round: bigint
401
+ // auction.gasPeg: bigint
402
+ // auction.currentFee: number
403
+ ```
404
+
405
+ #### `sdk.getAuctionFeeConfig(poolId)` — Auction fee parameters
406
+
407
+ ```typescript
408
+ const feeConfig = await sdk.getAuctionFeeConfig(poolId);
409
+ // feeConfig.startingFee: number
410
+ // feeConfig.endingFee: number
411
+ // feeConfig.secondsToDecay: bigint
412
+ ```
413
+
414
+ #### `sdk.getAuctionDecayStartTime(poolId)` — When fee decay started
415
+
416
+ ```typescript
417
+ const startTime = await sdk.getAuctionDecayStartTime(poolId);
418
+ ```
419
+
420
+ #### `sdk.getAuctionMaxRounds()` — Max auction rounds
421
+
422
+ ```typescript
423
+ const maxRounds = await sdk.getAuctionMaxRounds();
424
+ ```
425
+
426
+ #### `sdk.getAuctionGasPriceForBid(gasPeg, bidAmount)` — Calculate gas price for bid
427
+
428
+ ```typescript
429
+ const gasPrice = await sdk.getAuctionGasPriceForBid(
430
+ auction.gasPeg,
431
+ parseEther("1"), // desired bid
432
+ );
433
+ ```
434
+
435
+ ---
436
+
437
+ ### MEV Protection
438
+
439
+ #### `sdk.getMevBlockDelay()` — Get configured block delay
440
+
441
+ ```typescript
442
+ const delay = await sdk.getMevBlockDelay();
443
+ // delay: bigint — number of blocks
444
+ ```
445
+
446
+ #### `sdk.getPoolUnlockTime(poolId)` — When does MEV lock expire
447
+
448
+ ```typescript
449
+ const unlockTime = await sdk.getPoolUnlockTime(poolId);
450
+ // unlockTime: bigint — unix timestamp
451
+ // If Date.now()/1000 < unlockTime, pool is still locked
452
+ ```
453
+
454
+ ---
455
+
456
+ ### Factory & Allowlist Checks
457
+
458
+ #### `sdk.isFactoryDeprecated()` — Is the factory still active
459
+
460
+ ```typescript
461
+ const deprecated = await sdk.isFactoryDeprecated();
462
+ ```
463
+
464
+ #### `sdk.isLockerEnabled(lockerAddress, hookAddress)` — Is locker approved
465
+
466
+ ```typescript
467
+ const enabled = await sdk.isLockerEnabled(ADDRESSES.LP_LOCKER, ADDRESSES.HOOK_DYNAMIC_FEE_V2);
468
+ ```
469
+
470
+ #### `sdk.isExtensionEnabled(extensionAddress)` — Is extension on allowlist
471
+
472
+ ```typescript
473
+ const enabled = await sdk.isExtensionEnabled(ADDRESSES.UNIV4_ETH_DEV_BUY);
474
+ ```
475
+
476
+ ---
477
+
478
+ ## Default Values
479
+
480
+ When calling `deployToken`, all fields except `name` and `symbol` are optional. These defaults are applied:
481
+
482
+ | Field | Default | Notes |
483
+ |-------|---------|-------|
484
+ | `tokenAdmin` | Wallet address | Controls metadata updates |
485
+ | `salt` | `keccak256(name + symbol + timestamp)` | Unique per deploy |
486
+ | `image` | `""` | Empty string |
487
+ | `metadata` | `""` | Empty string |
488
+ | `context` | `'{"interface":"SDK"}'` | Auto-set via `buildContext()` |
489
+ | `hook` | `ADDRESSES.HOOK_STATIC_FEE_V2` | Static 1% buy fee |
490
+ | `pairedToken` | `EXTERNAL.WETH` | Base WETH |
491
+ | `tickIfToken0IsLiquid` | `-230400` | ≈10 ETH market cap |
492
+ | `tickSpacing` | `200` | Uniswap V4 tick spacing |
493
+ | `poolData` | `encodeStaticFeePoolData(0, 100)` | 0% sell, 1% buy |
494
+ | `locker` | `ADDRESSES.LP_LOCKER_FEE_CONVERSION` | LP locker with fee conversion to ETH |
495
+ | `rewardAdmins` | `[walletAddress]` | Deployer is admin |
496
+ | `rewardRecipients` | `[walletAddress]` | Deployer gets rewards |
497
+ | `rewardBps` | `[10000]` | 100% to deployer |
498
+ | `tickLower` | `[-230400, -198600, -168600]` | 3-tranche Liquid default |
499
+ | `tickUpper` | `[-198600, -168600, -122600]` | 3-tranche Liquid default |
500
+ | `positionBps` | `[4000, 5000, 1000]` | 40% / 50% / 10% |
501
+ | `mevModule` | `ADDRESSES.SNIPER_AUCTION_V2` | 80%→40% over 32s |
502
+ | `extensions` | `[]` | No extensions |
503
+
504
+ ---
505
+
506
+ ## Contract Addresses (Base Mainnet)
507
+
508
+ All addresses are exported as `ADDRESSES` and `EXTERNAL`:
509
+
510
+ ```typescript
511
+ import { ADDRESSES, EXTERNAL } from "liquid-sdk";
512
+
513
+ // Liquid Protocol contracts
514
+ ADDRESSES.FACTORY // 0x0000003482fe299E72d4908368044A8A173BE576
515
+ ADDRESSES.LP_LOCKER // 0x00000548732DfA56Be1257cE44D0CFc3B46dDb2A
516
+ ADDRESSES.FEE_LOCKER // 0x000008B9242b7e4432f6c4b1EeAD93562f9Cc94d
517
+ ADDRESSES.VAULT // 0x000001c5263F4d64CdC343cDA9C8bF961CF8376c
518
+ ADDRESSES.HOOK_DYNAMIC_FEE_V2 // 0x2A2F73CDDa098d639bd8Bbcd7dF2bf24E06728cC
519
+ ADDRESSES.HOOK_STATIC_FEE_V2 // 0xb2401c5369AaCF62F8d615623C7F68F84da428Cc
520
+ ADDRESSES.AIRDROP_V2 // 0x00000C222442512b08446D33dd9754a7F260BE79
521
+ ADDRESSES.SNIPER_AUCTION_V2 // 0x000007b64003ee07a69576F98859a0a36b854260
522
+ ADDRESSES.SNIPER_UTIL_V2 // 0x000003Ee0cb9B0C82C6C7FCB7b81a9883F285270
523
+ ADDRESSES.MEV_BLOCK_DELAY // 0x0000035D83588954F3c581c3A66251b3F06AD5e4
524
+ ADDRESSES.UNIV4_ETH_DEV_BUY // 0x00000d7DE1f0A3FA7957F5d8A2b97B0E24e5783D
525
+ ADDRESSES.POOL_EXTENSION_ALLOWLIST // 0x000003Afb1b070F037D2871eE0A6b8c8f53F7B77
526
+ ADDRESSES.LIQUID_DEPLOYER_LIB // 0x00000f88b2d37A2006F2F0C8552d22E0b8945202
527
+
528
+ // External (Uniswap V4 / Base)
529
+ EXTERNAL.POOL_MANAGER // 0x498581fF718922c3f8e6A244956aF099B2652b2b
530
+ EXTERNAL.WETH // 0x4200000000000000000000000000000000000006
531
+ EXTERNAL.UNIVERSAL_ROUTER // 0x6fF5693b99212Da76ad316178A184AB56D299b43
532
+ EXTERNAL.PERMIT2 // 0x000000000022D473030F116dDEE9F6B43aC78BA3
533
+ ```
534
+
535
+ ---
536
+
537
+ ## Constants
538
+
539
+ ```typescript
540
+ import { FEE, TOKEN } from "liquid-sdk";
541
+
542
+ FEE.DENOMINATOR // 1_000_000 (Uniswap V4 fee unit)
543
+ FEE.PROTOCOL_FEE_NUMERATOR // 200_000 (20% of LP fees → protocol)
544
+ FEE.MAX_LP_FEE // 100_000 (10% max LP fee)
545
+ FEE.MAX_MEV_FEE // 800_000 (80% max MEV fee)
546
+ FEE.BPS // 10_000 (basis points denominator)
547
+
548
+ TOKEN.SUPPLY // 100_000_000_000n * 10n ** 18n (100B tokens)
549
+ TOKEN.DECIMALS // 18
550
+ TOKEN.MAX_EXTENSIONS // 10
551
+ TOKEN.MAX_EXTENSION_BPS // 9000 (max 90% of supply to extensions)
552
+ ```
553
+
554
+ ---
555
+
556
+ ## Exported ABIs
557
+
558
+ All contract ABIs are exported for direct use with viem if needed:
559
+
560
+ ```typescript
561
+ import {
562
+ LiquidFactoryAbi,
563
+ LiquidFeeLockerAbi,
564
+ LiquidHookDynamicFeeV2Abi,
565
+ LiquidVaultAbi,
566
+ LiquidSniperAuctionV2Abi,
567
+ LiquidSniperUtilV2Abi,
568
+ LiquidAirdropV2Abi,
569
+ LiquidPoolExtensionAllowlistAbi,
570
+ LiquidMevBlockDelayAbi,
571
+ LiquidLpLockerAbi,
572
+ ERC20Abi,
573
+ } from "liquid-sdk";
574
+ ```
575
+
576
+ ---
577
+
578
+ ## Exported Types
579
+
580
+ ```typescript
581
+ import type {
582
+ AirdropInfo,
583
+ DeployTokenParams,
584
+ DeployTokenResult,
585
+ DeploymentConfig,
586
+ DeploymentInfo,
587
+ DevBuyParams,
588
+ ExtensionConfig,
589
+ LiquidSDKConfig,
590
+ LockerConfig,
591
+ MevModuleConfig,
592
+ PoolConfig,
593
+ PoolDynamicConfigVars,
594
+ PoolDynamicFeeVars,
595
+ PoolKey,
596
+ SniperAuctionFeeConfig,
597
+ SniperAuctionState,
598
+ TokenConfig,
599
+ TokenCreatedEvent,
600
+ TokenRewardInfo,
601
+ VaultAllocation,
602
+ } from "liquid-sdk";
603
+ ```
604
+
605
+ ---
606
+
607
+ ## Common Workflows
608
+
609
+ ### 1. Deploy a token and buy some at launch
610
+
611
+ ```typescript
612
+ import { createPublicClient, createWalletClient, http, parseEther } from "viem";
613
+ import { base } from "viem/chains";
614
+ import { privateKeyToAccount } from "viem/accounts";
615
+ import { LiquidSDK } from "liquid-sdk";
616
+
617
+ const account = privateKeyToAccount(PRIVATE_KEY);
618
+ const publicClient = createPublicClient({ chain: base, transport: http() });
619
+ const walletClient = createWalletClient({ account, chain: base, transport: http() });
620
+ const sdk = new LiquidSDK({ publicClient, walletClient });
621
+
622
+ const result = await sdk.deployToken({
623
+ name: "Agent Token",
624
+ symbol: "AGENT",
625
+ image: "https://example.com/logo.png",
626
+ metadata: JSON.stringify({ description: "Deployed by an AI agent" }),
627
+ devBuy: {
628
+ ethAmount: parseEther("0.01"),
629
+ recipient: account.address,
630
+ },
631
+ });
632
+
633
+ console.log("Token:", result.tokenAddress);
634
+ console.log("Pool ID:", result.event.poolId);
635
+ ```
636
+
637
+ ### 2. Check and collect all rewards for a token
638
+
639
+ ```typescript
640
+ // Step 1: Check reward config
641
+ const rewards = await sdk.getTokenRewards(tokenAddress);
642
+ console.log("Recipients:", rewards.rewardRecipients);
643
+ console.log("Splits:", rewards.rewardBps); // e.g. [10000] = 100%
644
+
645
+ // Step 2: Check if pool is unlocked (MEV protection)
646
+ const unlockTime = await sdk.getPoolUnlockTime(result.event.poolId);
647
+ const now = BigInt(Math.floor(Date.now() / 1000));
648
+
649
+ if (now < unlockTime) {
650
+ console.log("Pool still locked until:", new Date(Number(unlockTime) * 1000));
651
+ // Can still try collectRewardsWithoutUnlock
652
+ const txHash = await sdk.collectRewardsWithoutUnlock(tokenAddress);
653
+ await publicClient.waitForTransactionReceipt({ hash: txHash });
654
+ } else {
655
+ // Full collect + unlock
656
+ const txHash = await sdk.collectRewards(tokenAddress);
657
+ await publicClient.waitForTransactionReceipt({ hash: txHash });
658
+ }
659
+ ```
660
+
661
+ ### 3. Check and claim fees
662
+
663
+ ```typescript
664
+ const fees = await sdk.getFeesToClaim(ownerAddress, tokenAddress);
665
+ console.log("Claimable fees:", fees);
666
+
667
+ if (fees > 0n) {
668
+ const txHash = await sdk.claimFees(ownerAddress, tokenAddress);
669
+ const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
670
+ console.log("Fees claimed in tx:", receipt.transactionHash);
671
+ }
672
+ ```
673
+
674
+ ### 4. Check vault vesting and claim
675
+
676
+ ```typescript
677
+ const vault = await sdk.getVaultAllocation(tokenAddress);
678
+ const now = BigInt(Math.floor(Date.now() / 1000));
679
+
680
+ if (now < vault.lockupEndTime) {
681
+ console.log("Vault locked until:", new Date(Number(vault.lockupEndTime) * 1000));
682
+ } else {
683
+ const claimable = await sdk.getVaultClaimable(tokenAddress);
684
+ console.log("Claimable from vault:", claimable);
685
+
686
+ if (claimable > 0n) {
687
+ const txHash = await sdk.claimVault(tokenAddress);
688
+ await publicClient.waitForTransactionReceipt({ hash: txHash });
689
+ }
690
+ }
691
+ ```
692
+
693
+ ### 5. Full token status check (no wallet needed)
694
+
695
+ ```typescript
696
+ const sdk = new LiquidSDK({ publicClient }); // read-only
697
+
698
+ const info = await sdk.getTokenInfo(tokenAddress);
699
+ console.log(`${info.name} (${info.symbol})`);
700
+ console.log("Total supply:", info.totalSupply);
701
+ console.log("Hook:", info.deployment.hook);
702
+ console.log("Locker:", info.deployment.locker);
703
+ console.log("Extensions:", info.deployment.extensions);
704
+
705
+ const rewards = await sdk.getTokenRewards(tokenAddress);
706
+ console.log("Reward recipients:", rewards.rewardRecipients);
707
+
708
+ const poolConfig = await sdk.getPoolConfig(poolId);
709
+ console.log("Base fee:", poolConfig.baseFee, "bps");
710
+ console.log("Max LP fee:", poolConfig.maxLpFee, "bps");
711
+
712
+ const feeState = await sdk.getPoolFeeState(poolId);
713
+ console.log("Current reference tick:", feeState.referenceTick);
714
+
715
+ const auction = await sdk.getAuctionState(poolId);
716
+ console.log("Auction round:", auction.round);
717
+ console.log("Current sniper fee:", auction.currentFee);
718
+ ```
719
+
720
+ ### 6. Deploy with custom reward splits
721
+
722
+ ```typescript
723
+ const result = await sdk.deployToken({
724
+ name: "Split Token",
725
+ symbol: "SPLIT",
726
+ rewardAdmins: [deployer, partner],
727
+ rewardRecipients: [deployer, partner],
728
+ rewardBps: [7000, 3000], // 70% deployer, 30% partner
729
+ });
730
+ ```
731
+
732
+ ### 7. Update reward recipient (e.g., rotate to a new wallet)
733
+
734
+ ```typescript
735
+ const rewards = await sdk.getTokenRewards(tokenAddress);
736
+ // Only the admin at index N can update recipient at index N
737
+ const txHash = await sdk.updateRewardRecipient(
738
+ tokenAddress,
739
+ 0n, // index
740
+ newWalletAddress,
741
+ );
742
+ await publicClient.waitForTransactionReceipt({ hash: txHash });
743
+ ```
744
+
745
+ ---
746
+
747
+ ## Architecture Notes
748
+
749
+ - **Chain:** Base mainnet only (chain ID 8453)
750
+ - **Pool type:** Uniswap V4 with custom hooks (dynamic or static fee)
751
+ - **Token supply:** Always 100 billion (100,000,000,000) with 18 decimals
752
+ - **LP locking:** Liquidity is locked in the LP Locker — it cannot be rugged
753
+ - **Fee flow:** Trading fees → LP Locker → distributed to reward recipients by BPS
754
+ - **MEV protection:** After deployment, pool is locked for N blocks. `collectRewards` will revert with `ManagerLocked` during this period. Use `collectRewardsWithoutUnlock` or wait.
755
+ - **Extensions:** Up to 10 extensions per token, max 90% of supply allocated to extensions total
756
+ - **Dev buy:** Not a separate step — ETH is swapped in the same transaction as deployment
757
+
758
+ ---
759
+
760
+ ## Error Handling
761
+
762
+ All write methods throw viem errors on failure. Common revert reasons:
763
+
764
+ | Error | Meaning | Resolution |
765
+ |-------|---------|------------|
766
+ | `ManagerLocked` | Pool is still in MEV lock period | Wait for `getPoolUnlockTime()` to pass, or use `collectRewardsWithoutUnlock` |
767
+ | `NoFeesToClaim` | No fees accrued yet | Wait for trading activity |
768
+ | `Unauthorized` | Caller is not the admin/owner | Use the correct wallet |
769
+ | `AlreadyClaimed` | Airdrop already claimed | Check `getAirdropClaimable()` first |
770
+ | `LockupNotEnded` | Vault lockup period hasn't passed | Check `getVaultAllocation().lockupEndTime` |