0
# Approval & Liquidity
1
2
Token approval and liquidity management utilities for position management and swap-and-add operations. The ApproveAndCall class supports various approval strategies and NFT position handling for Uniswap V3 liquidity operations.
3
4
## Capabilities
5
6
### ApproveAndCall Class
7
8
Abstract class providing static methods for encoding token approvals and liquidity management operations.
9
10
```typescript { .api }
11
/**
12
* Abstract class for encoding approval and liquidity operations
13
*/
14
abstract class ApproveAndCall {
15
/** Contract interface for IApproveAndCall */
16
static INTERFACE: Interface;
17
18
/**
19
* Encode maximum token approval
20
* @param token - Token to approve
21
* @returns Encoded function data for max approval
22
*/
23
static encodeApproveMax(token: Token): string;
24
25
/**
26
* Encode maximum minus one token approval
27
* @param token - Token to approve
28
* @returns Encoded function data for max-1 approval
29
*/
30
static encodeApproveMaxMinusOne(token: Token): string;
31
32
/**
33
* Encode zero then maximum token approval (for tokens requiring zero reset)
34
* @param token - Token to approve
35
* @returns Encoded function data for zero then max approval
36
*/
37
static encodeApproveZeroThenMax(token: Token): string;
38
39
/**
40
* Encode zero then maximum minus one token approval
41
* @param token - Token to approve
42
* @returns Encoded function data for zero then max-1 approval
43
*/
44
static encodeApproveZeroThenMaxMinusOne(token: Token): string;
45
46
/**
47
* Encode call to position manager with batched calldatas
48
* @param calldatas - Array of encoded function calls
49
* @returns Encoded function data for position manager call
50
*/
51
static encodeCallPositionManager(calldatas: string[]): string;
52
53
/**
54
* Encode adding liquidity to a position in the NFT manager contract
55
* @param position - Forecasted position with expected amount out from swap
56
* @param minimalPosition - Forecasted position with custom minimal token amounts
57
* @param addLiquidityOptions - Options for adding liquidity (mint or increase)
58
* @param slippageTolerance - Maximum slippage tolerance
59
* @returns Encoded function data for add liquidity operation
60
*/
61
static encodeAddLiquidity(
62
position: Position,
63
minimalPosition: Position,
64
addLiquidityOptions: CondensedAddLiquidityOptions,
65
slippageTolerance: Percent
66
): string;
67
68
/**
69
* Encode approval with specified approval type
70
* @param token - Currency to approve (will use wrapped version)
71
* @param approvalType - Type of approval to perform
72
* @returns Encoded function data for the specified approval type
73
*/
74
static encodeApprove(token: Currency, approvalType: ApprovalTypes): string;
75
}
76
```
77
78
### Approval Types
79
80
Enumeration of different approval strategies for token spending.
81
82
```typescript { .api }
83
/**
84
* Different approval strategies for token spending
85
*/
86
enum ApprovalTypes {
87
/** No approval required */
88
NOT_REQUIRED = 0,
89
90
/** Approve maximum uint256 amount */
91
MAX = 1,
92
93
/** Approve maximum uint256 minus one */
94
MAX_MINUS_ONE = 2,
95
96
/** First approve zero, then approve maximum (for problematic tokens) */
97
ZERO_THEN_MAX = 3,
98
99
/** First approve zero, then approve maximum minus one */
100
ZERO_THEN_MAX_MINUS_ONE = 4
101
}
102
```
103
104
### Liquidity Options
105
106
Configuration options for adding liquidity to positions.
107
108
```typescript { .api }
109
/**
110
* Condensed version of v3-sdk AddLiquidityOptions containing only necessary swap + add attributes
111
*/
112
type CondensedAddLiquidityOptions = Omit<MintSpecificOptions, 'createPool'> | IncreaseSpecificOptions;
113
114
/**
115
* Type guard to check if options are for minting a new position
116
* @param options - Liquidity options to check
117
* @returns True if options are for minting, false for increasing existing position
118
*/
119
function isMint(options: CondensedAddLiquidityOptions): options is Omit<MintSpecificOptions, 'createPool'>;
120
```
121
122
**Usage Examples:**
123
124
```typescript
125
import { ApproveAndCall, ApprovalTypes, isMint } from "@uniswap/router-sdk";
126
import { Token, Percent } from "@uniswap/sdk-core";
127
import { Position } from "@uniswap/v3-sdk";
128
129
// Basic token approval
130
const token = new Token(1, "0x...", 18, "USDC", "USD Coin");
131
const approvalCalldata = ApproveAndCall.encodeApproveMax(token);
132
133
// Send approval transaction
134
const approvalTx = {
135
to: APPROVE_AND_CALL_ADDRESS,
136
data: approvalCalldata
137
};
138
```
139
140
```typescript
141
// Different approval strategies
142
const maxApproval = ApproveAndCall.encodeApprove(token, ApprovalTypes.MAX);
143
const zeroThenMaxApproval = ApproveAndCall.encodeApprove(token, ApprovalTypes.ZERO_THEN_MAX);
144
145
// For problematic tokens that require zero reset
146
if (requiresZeroReset) {
147
const calldata = ApproveAndCall.encodeApprove(token, ApprovalTypes.ZERO_THEN_MAX);
148
}
149
```
150
151
```typescript
152
// Add liquidity after swap
153
import { Pool } from "@uniswap/v3-sdk";
154
155
const pool = new Pool(token0, token1, fee, sqrtPriceX96, liquidity, tick);
156
const position = new Position({
157
pool,
158
liquidity: targetLiquidity,
159
tickLower: -887220,
160
tickUpper: 887220
161
});
162
163
// Create minimal position for slippage protection
164
const minimalPosition = Position.fromAmounts({
165
pool: position.pool,
166
tickLower: position.tickLower,
167
tickUpper: position.tickUpper,
168
amount0: minimumAmount0,
169
amount1: minimumAmount1,
170
useFullPrecision: false
171
});
172
173
// Configure liquidity options for new position
174
const mintOptions = {
175
recipient: "0x742d35Cc6435C6329Eb54F0d86C05B1E11a02E6B",
176
deadline: Math.floor(Date.now() / 1000) + 1800,
177
slippageTolerance: new Percent(50, 10000)
178
};
179
180
// Encode add liquidity operation
181
const addLiquidityCalldata = ApproveAndCall.encodeAddLiquidity(
182
position,
183
minimalPosition,
184
mintOptions,
185
new Percent(50, 10000) // 0.5% slippage
186
);
187
```
188
189
```typescript
190
// Increase existing position liquidity
191
const increaseOptions = {
192
tokenId: 123456, // Existing position NFT ID
193
deadline: Math.floor(Date.now() / 1000) + 1800,
194
slippageTolerance: new Percent(50, 10000)
195
};
196
197
// Check if this is a mint or increase operation
198
if (isMint(mintOptions)) {
199
console.log("Creating new position");
200
} else {
201
console.log("Increasing existing position");
202
}
203
204
const increaseCalldata = ApproveAndCall.encodeAddLiquidity(
205
position,
206
minimalPosition,
207
increaseOptions,
208
new Percent(50, 10000)
209
);
210
```
211
212
```typescript
213
// Batch multiple operations
214
const calldatas = [
215
ApproveAndCall.encodeApproveMax(token0),
216
ApproveAndCall.encodeApproveMax(token1),
217
addLiquidityCalldata
218
];
219
220
// Encode batched call to position manager
221
const batchedCalldata = ApproveAndCall.encodeCallPositionManager(calldatas);
222
223
// Execute batched transaction
224
const batchTx = {
225
to: APPROVE_AND_CALL_ADDRESS,
226
data: batchedCalldata
227
};
228
```
229
230
```typescript
231
// Complete swap and add workflow
232
import { SwapRouter } from "@uniswap/router-sdk";
233
234
const swapAndAddCalldata = SwapRouter.swapAndAddCallParameters(
235
trade,
236
swapAndAddOptions,
237
position,
238
mintOptions,
239
ApprovalTypes.MAX, // Input token approval
240
ApprovalTypes.NOT_REQUIRED // Output token approval (already have from swap)
241
);
242
243
// This internally uses ApproveAndCall for the liquidity portion
244
console.log("Swap and add calldata:", swapAndAddCalldata.calldata);
245
console.log("ETH value required:", swapAndAddCalldata.value);
246
```
247
248
### Error Handling
249
250
Common errors and their handling:
251
252
```typescript
253
// Handle approval failures
254
try {
255
const calldata = ApproveAndCall.encodeApprove(token, ApprovalTypes.MAX);
256
} catch (error) {
257
if (error.message === 'Error: invalid ApprovalType') {
258
// Handle invalid approval type
259
console.error("Invalid approval type provided");
260
}
261
}
262
263
// Validate liquidity options
264
function validateLiquidityOptions(options: CondensedAddLiquidityOptions) {
265
if (isMint(options)) {
266
if (!options.recipient) {
267
throw new Error("Recipient required for mint operations");
268
}
269
} else {
270
if (!options.tokenId) {
271
throw new Error("Token ID required for increase operations");
272
}
273
}
274
}
275
```