|
1 | 1 | # uniswap-dev-kit |
2 | | - |
3 | 2 | [](https://github.com/BootNodeDev/uni-dev-kit/actions/workflows/ci.yml) |
4 | 3 | [](https://github.com/BootNodeDev/uni-dev-kit/actions/workflows/release.yml) |
5 | 4 | [](https://bootnodedev.github.io/uni-dev-kit) |
6 | 5 |
|
7 | 6 | > Modern TypeScript SDK for integrating Uniswap V4 into your dapp. |
8 | 7 | > **Early version:** API may change rapidly. |
9 | 8 |
|
| 9 | +A developer-friendly library for interacting with Uniswap V4 contracts. This library provides a simple and flexible interface for common operations like adding liquidity, swapping tokens, and managing positions. |
| 10 | + |
10 | 11 | ## Features |
11 | 12 |
|
12 | | -- 🚀 Full TypeScript support |
13 | | -- 🔄 Multi-chain support out of the box |
14 | | -- 📦 Zero dependencies (except peer deps) |
15 | | -- 🔍 Comprehensive error handling |
16 | | -- 🧪 Fully tested |
17 | | -- 📚 Well documented |
| 13 | +- 🚀 Simple and intuitive API |
| 14 | +- 🔄 Support for all major Uniswap V4 operations |
| 15 | +- 💰 Native token support |
| 16 | +- 🔒 Permit2 integration for gasless approvals |
| 17 | +- 📊 Flexible liquidity management |
| 18 | +- 🔍 Built-in quote simulation |
| 19 | +- 🛠 TypeScript support |
18 | 20 |
|
19 | | -## Install |
| 21 | +## Installation |
20 | 22 |
|
21 | 23 | ```bash |
22 | | -pnpm install uniswap-dev-kit |
23 | | -# or |
24 | 24 | npm install uniswap-dev-kit |
| 25 | +# or |
| 26 | +yarn add uniswap-dev-kit |
25 | 27 | ``` |
26 | 28 |
|
27 | 29 | ## Quick Start |
28 | 30 |
|
29 | | -### 1. Configure and create SDK instances |
30 | | - |
31 | 31 | ```ts |
32 | | -import { UniDevKitV4 } from "uniswap-dev-kit"; |
| 32 | +import { UniDevKitV4 } from 'uniswap-dev-kit'; |
33 | 33 |
|
34 | | -// Create instance for Ethereum mainnet |
35 | | -const ethInstance = new UniDevKitV4({ |
| 34 | +const uniDevKit = new UniDevKitV4({ |
36 | 35 | chainId: 1, |
37 | | - rpcUrl: "https://eth.llamarpc.com", |
38 | 36 | contracts: { |
39 | 37 | poolManager: "0x...", |
40 | | - positionDescriptor: "0x...", |
41 | 38 | positionManager: "0x...", |
| 39 | + positionDescriptor: "0x...", |
42 | 40 | quoter: "0x...", |
43 | 41 | stateView: "0x...", |
44 | | - universalRouter: "0x...", |
45 | | - permit2: "0x..." |
| 42 | + universalRouter: "0x..." |
46 | 43 | } |
47 | 44 | }); |
48 | 45 |
|
49 | | -// Create instance for another chain (e.g., Base) |
50 | | -const baseInstance = new UniDevKitV4({ |
51 | | - chainId: 8453, |
52 | | - rpcUrl: "https://mainnet.base.org", |
53 | | - contracts: { |
54 | | - // Base Uniswap V4 contract addresses... |
55 | | - } |
| 46 | +const pool = await uniDevKit.getPool({ |
| 47 | + tokens: ["0xTokenA", "0xTokenB"], |
| 48 | + fee: 3000 |
| 49 | +}); |
| 50 | + |
| 51 | +const quote = await uniDevKit.getQuote({ |
| 52 | + pool, |
| 53 | + amountIn: "1000000000000000000" |
56 | 54 | }); |
57 | 55 | ``` |
58 | 56 |
|
59 | | -### 2. Get a quote |
| 57 | +## Documentation |
| 58 | +Full API documentation with TypeDoc: [https://bootnodedev.github.io/uni-dev-kit](https://bootnodedev.github.io/uni-dev-kit) |
60 | 59 |
|
| 60 | +## API Reference |
| 61 | + |
| 62 | +### Index |
| 63 | +- [uniswap-dev-kit](#uniswap-dev-kit) |
| 64 | + - [Features](#features) |
| 65 | + - [Installation](#installation) |
| 66 | + - [Quick Start](#quick-start) |
| 67 | + - [Documentation](#documentation) |
| 68 | + - [API Reference](#api-reference) |
| 69 | + - [Index](#index) |
| 70 | + - [`getPool`](#getpool) |
| 71 | + - [`getQuote`](#getquote) |
| 72 | + - [`getTokens`](#gettokens) |
| 73 | + - [`getPosition`](#getposition) |
| 74 | + - [`getPoolKeyFromPoolId`](#getpoolkeyfrompoolid) |
| 75 | + - [`buildSwapCallData`](#buildswapcalldata) |
| 76 | + - [`buildAddLiquidityCallData`](#buildaddliquiditycalldata) |
| 77 | + - [`preparePermit2BatchCallData`](#preparepermit2batchcalldata) |
| 78 | + - [Useful Links](#useful-links) |
| 79 | + - [Development](#development) |
| 80 | + - [Scripts](#scripts) |
| 81 | + - [Contributing](#contributing) |
| 82 | + - [Release](#release) |
| 83 | + - [License](#license) |
| 84 | + |
| 85 | +### `getPool` |
| 86 | +Retrieve a pool object from two tokens and a fee tier. |
61 | 87 | ```ts |
62 | | -import { parseEther } from "viem"; |
63 | | - |
64 | | -const quote = await ethInstance.getQuote({ |
65 | | - tokens: [ |
66 | | - "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC |
67 | | - "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // WETH |
68 | | - ], |
69 | | - feeTier: 3000, |
70 | | - amountIn: parseEther("1"), |
71 | | - zeroForOne: true |
| 88 | +const pool = await uniDevKit.getPool({ |
| 89 | + tokens: [tokenA, tokenB], |
| 90 | + fee: 3000 |
72 | 91 | }); |
73 | | -console.log(quote.amountOut); |
74 | 92 | ``` |
75 | 93 |
|
76 | | -### 3. Get a pool |
77 | | - |
| 94 | +### `getQuote` |
| 95 | +Simulate a swap to get `amountOut` and `sqrtPriceLimitX96`. |
78 | 96 | ```ts |
79 | | -const pool = await ethInstance.getPool({ |
80 | | - tokens: [ |
81 | | - "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", |
82 | | - "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" |
83 | | - ], |
84 | | - feeTier: 3000 |
| 97 | +const quote = await uniDevKit.getQuote({ |
| 98 | + pool, |
| 99 | + amountIn: "1000000000000000000" |
85 | 100 | }); |
86 | | -console.log(pool.liquidity.toString()); |
87 | 101 | ``` |
88 | 102 |
|
89 | | -### 4. Get a position |
90 | | - |
| 103 | +### `getTokens` |
| 104 | +Retrieve token metadata. |
91 | 105 | ```ts |
92 | | -const position = await ethInstance.getPosition({ |
93 | | - tokenId: "123" |
94 | | -}); |
95 | | -console.log({ |
96 | | - token0: position.token0.symbol, |
97 | | - token1: position.token1.symbol, |
98 | | - liquidity: position.position.liquidity.toString() |
| 106 | +const tokens = await uniDevKit.getTokens({ |
| 107 | + addresses: ["0x...", "0x..."] |
99 | 108 | }); |
100 | 109 | ``` |
101 | 110 |
|
102 | | -## Advanced Usage |
103 | | - |
104 | | -### Error Handling |
| 111 | +### `getPosition` |
| 112 | +Get details about a Uniswap V4 LP position. |
| 113 | +```ts |
| 114 | +const position = await uniDevKit.getPosition({ |
| 115 | + tokenId: 123 |
| 116 | +}); |
| 117 | +``` |
105 | 118 |
|
106 | | -All SDK functions include comprehensive error handling: |
| 119 | +### `getPoolKeyFromPoolId` |
| 120 | +Retrieve the `PoolKey` object for a given pool ID. |
| 121 | +```ts |
| 122 | +const poolKey = await uniDevKit.getPoolKeyFromPoolId({ |
| 123 | + poolId: "0x..." |
| 124 | +}); |
| 125 | +``` |
107 | 126 |
|
| 127 | +### `buildSwapCallData` |
| 128 | +Construct calldata and value for a Universal Router swap. |
108 | 129 | ```ts |
109 | | -try { |
110 | | - const quote = await ethInstance.getQuote({ |
111 | | - tokens: [token0, token1], |
112 | | - feeTier: 3000, |
113 | | - amountIn: parseEther("1"), |
114 | | - zeroForOne: true |
115 | | - }); |
116 | | -} catch (error) { |
117 | | - // Handle specific error types |
118 | | - if (error.message.includes("insufficient liquidity")) { |
119 | | - // Handle liquidity error |
120 | | - } else if (error.message.includes("invalid pool")) { |
121 | | - // Handle pool error |
122 | | - } |
123 | | -} |
| 130 | +const { calldata, value } = await uniDevKit.buildSwapCallData({ |
| 131 | + tokenIn, |
| 132 | + tokenOut, |
| 133 | + amountIn: "1000000000000000000", |
| 134 | + recipient, |
| 135 | + slippageBips: 50 |
| 136 | +}); |
124 | 137 | ``` |
125 | 138 |
|
126 | | -### Using with React |
| 139 | +### `buildAddLiquidityCallData` |
| 140 | +Build calldata to add liquidity to a pool. |
| 141 | +```ts |
| 142 | +// Without permit |
| 143 | +const { calldata, value } = await uniDevKit.buildAddLiquidityCallData({ |
| 144 | + pool, |
| 145 | + amount0: "100000000", |
| 146 | + amount1: "50000000000000000", |
| 147 | + recipient: "0x...", |
| 148 | + slippageTolerance: 50 |
| 149 | +}); |
127 | 150 |
|
128 | | -You can use the SDK with React Query for data fetching: |
| 151 | +// With Permit2 batch approval |
| 152 | +const permitData = await uniDevKit.preparePermit2BatchData({ |
| 153 | + tokens: [pool.token0.address, pool.token1.address], |
| 154 | + spender: uniDevKit.getContractAddress('positionManager'), |
| 155 | + owner: userAddress |
| 156 | +}); |
129 | 157 |
|
130 | | -```tsx |
131 | | -import { useQuery } from '@tanstack/react-query'; |
132 | | -import { UniDevKitV4 } from 'uniswap-dev-kit'; |
| 158 | +const signature = await signer.signTypedData( |
| 159 | + permitData.toSign.domain, |
| 160 | + permitData.toSign.types, |
| 161 | + permitData.toSign.values |
| 162 | +); |
133 | 163 |
|
134 | | -// Create instance once |
135 | | -const sdk = new UniDevKitV4({ |
136 | | - chainId: 1, |
137 | | - rpcUrl: "https://eth.llamarpc.com", |
138 | | - contracts: { |
139 | | - // ... contract addresses |
140 | | - } |
| 164 | +const permitWithSignature = permitData.buildPermit2BatchDataWithSignature(signature); |
| 165 | + |
| 166 | +const { calldata, value } = await uniDevKit.buildAddLiquidityCallData({ |
| 167 | + pool, |
| 168 | + amount0: parseUnits("100", 6), |
| 169 | + recipient: "0x...", |
| 170 | + permit2BatchSignature: permitWithSignature |
141 | 171 | }); |
142 | 172 |
|
143 | | -// Simple hook for quotes |
144 | | -function useQuote() { |
145 | | - return useQuery({ |
146 | | - queryKey: ['quote'], |
147 | | - queryFn: () => sdk.getQuote({ |
148 | | - tokens: [ |
149 | | - "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", |
150 | | - "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" |
151 | | - ], |
152 | | - feeTier: 3000, |
153 | | - amountIn: parseEther("1"), |
154 | | - zeroForOne: true |
155 | | - }) |
156 | | - }); |
157 | | -} |
| 173 | +const tx = await sendTransaction({ |
| 174 | + to: uniDevKit.getContractAddress('positionManager'), |
| 175 | + data: calldata, |
| 176 | + value |
| 177 | +}); |
158 | 178 | ``` |
159 | 179 |
|
160 | | ---- |
161 | | - |
162 | | -## API Reference |
163 | | - |
164 | | -See [full TypeDoc documentation](https://bootnodedev.github.io/uni-dev-kit) for all methods, types, and advanced usage. |
| 180 | +### `preparePermit2BatchCallData` |
| 181 | +Construct a Permit2 batch approval for gasless interactions. |
| 182 | +```ts |
| 183 | +const permitData = await uniDevKit.preparePermit2BatchCallData({ |
| 184 | + tokens: [tokenA.address, tokenB.address], |
| 185 | + spender: uniDevKit.getContractAddress('positionManager'), |
| 186 | + owner: userAddress |
| 187 | +}); |
| 188 | +``` |
165 | 189 |
|
166 | | ---- |
| 190 | +## Useful Links |
| 191 | +- [Uniswap V4 Docs](https://docs.uniswap.org/contracts/v4/overview) |
167 | 192 |
|
168 | 193 | ## Development |
169 | 194 |
|
170 | 195 | ### Scripts |
171 | | - |
172 | 196 | - `pnpm build` — Build the library |
173 | 197 | - `pnpm test` — Run all tests |
174 | 198 | - `pnpm lint` — Lint code with Biome |
175 | 199 | - `pnpm format` — Format code with Biome |
176 | 200 | - `pnpm docs` — Generate API docs with TypeDoc |
177 | 201 |
|
178 | | -### Contributing |
| 202 | +## Contributing |
179 | 203 |
|
180 | 204 | See [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines. |
181 | 205 |
|
182 | | -### Release |
| 206 | +## Release |
183 | 207 |
|
184 | 208 | - Releases are automated with [semantic-release](https://semantic-release.gitbook.io/semantic-release/). |
185 | | -- Versioning: [semver](https://semver.org/) |
186 | | - |
187 | | ---- |
188 | | - |
189 | | -## FAQ |
190 | | - |
191 | | -- **Does it work in Node and browser?** |
192 | | - Yes, works in both environments. |
193 | | -- **Can I use my own ABIs?** |
194 | | - Yes, but Uniswap V4 ABIs are included. |
195 | | - |
196 | | ---- |
197 | 209 |
|
198 | 210 | ## License |
199 | | - |
200 | 211 | MIT |
201 | | - |
202 | | ---- |
203 | | - |
204 | | -> Feedback, issues, and PRs welcome. |
205 | | -> [API Docs](https://bootnodedev.github.io/uni-dev-kit) • [Open an Issue](https://github.com/BootNodeDev/uni-dev-kit/issues) |
|
0 commit comments