liquid-sdk 1.2.0 → 1.3.1
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 +770 -0
- package/CHANGELOG.md +60 -0
- package/dist/index.d.mts +127 -1
- package/dist/index.d.ts +127 -1
- package/dist/index.js +192 -20
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +185 -19
- package/dist/index.mjs.map +1 -1
- package/llms.txt +154 -0
- package/package.json +22 -4
package/AGENT_README.md
ADDED
|
@@ -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` |
|