@clawnch/clawncher-sdk 0.2.0 → 0.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.
- package/README.md +190 -0
- package/dist/errors.d.ts +1 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +3 -0
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/liquidity.d.ts +14 -8
- package/dist/liquidity.d.ts.map +1 -1
- package/dist/liquidity.js +149 -15
- package/dist/liquidity.js.map +1 -1
- package/dist/permit2.d.ts +258 -0
- package/dist/permit2.d.ts.map +1 -0
- package/dist/permit2.js +520 -0
- package/dist/permit2.js.map +1 -0
- package/dist/uniswap-abis.d.ts +525 -0
- package/dist/uniswap-abis.d.ts.map +1 -1
- package/dist/uniswap-abis.js +432 -1
- package/dist/uniswap-abis.js.map +1 -1
- package/dist/uniswap-chains.d.ts +77 -0
- package/dist/uniswap-chains.d.ts.map +1 -0
- package/dist/uniswap-chains.js +362 -0
- package/dist/uniswap-chains.js.map +1 -0
- package/dist/uniswap-quoter.d.ts +178 -0
- package/dist/uniswap-quoter.d.ts.map +1 -0
- package/dist/uniswap-quoter.js +432 -0
- package/dist/uniswap-quoter.js.map +1 -0
- package/dist/uniswap-trading.d.ts +203 -0
- package/dist/uniswap-trading.d.ts.map +1 -0
- package/dist/uniswap-trading.js +380 -0
- package/dist/uniswap-trading.js.map +1 -0
- package/package.json +3 -1
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UniswapQuoter — On-chain V4 quote simulation + price impact estimation.
|
|
3
|
+
*
|
|
4
|
+
* Uses the deployed V4 Quoter contract to simulate swaps without executing
|
|
5
|
+
* them. This works even without a Trading API key — it's purely on-chain.
|
|
6
|
+
*
|
|
7
|
+
* Supports:
|
|
8
|
+
* - Single-pool exact input/output quotes
|
|
9
|
+
* - Price impact calculation
|
|
10
|
+
* - Pool discovery for Clawncher tokens
|
|
11
|
+
* - Multi-chain via uniswap-chains registry
|
|
12
|
+
*
|
|
13
|
+
* @see https://docs.uniswap.org/contracts/v4/reference/periphery/interfaces/IQuoter
|
|
14
|
+
*/
|
|
15
|
+
import { V4QuoterABI, StateViewABI } from './uniswap-abis.js';
|
|
16
|
+
import { getUniswapChain } from './uniswap-chains.js';
|
|
17
|
+
import { getUniswapV4Addresses } from './uniswap-addresses.js';
|
|
18
|
+
import { ClawnchErrorCode, ClawnchDeployError } from './errors.js';
|
|
19
|
+
import { ClawnchReader } from './reader.js';
|
|
20
|
+
// ============================================================================
|
|
21
|
+
// Constants
|
|
22
|
+
// ============================================================================
|
|
23
|
+
const Q96 = 2n ** 96n;
|
|
24
|
+
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
|
|
25
|
+
// Min/max sqrt price for Uniswap V4 (from TickMath)
|
|
26
|
+
const MIN_SQRT_PRICE = 4295128739n + 1n; // TickMath.MIN_SQRT_PRICE + 1
|
|
27
|
+
const MAX_SQRT_PRICE = 1461446703485210103287273052203988822378723970342n - 1n; // TickMath.MAX_SQRT_PRICE - 1
|
|
28
|
+
// ============================================================================
|
|
29
|
+
// UniswapQuoter
|
|
30
|
+
// ============================================================================
|
|
31
|
+
export class UniswapQuoter {
|
|
32
|
+
publicClient;
|
|
33
|
+
chainId;
|
|
34
|
+
network;
|
|
35
|
+
chainConfig;
|
|
36
|
+
constructor(config) {
|
|
37
|
+
this.publicClient = config.publicClient;
|
|
38
|
+
this.chainId = config.chainId ?? 8453;
|
|
39
|
+
this.network = config.network ?? 'mainnet';
|
|
40
|
+
this.chainConfig = getUniswapChain(this.chainId);
|
|
41
|
+
}
|
|
42
|
+
/** Get the V4 Quoter address for the current chain */
|
|
43
|
+
getQuoterAddress() {
|
|
44
|
+
// For Base, use the known address from uniswap-addresses.ts
|
|
45
|
+
if (this.chainId === 8453 || this.chainId === 84532) {
|
|
46
|
+
const v4 = getUniswapV4Addresses(this.network);
|
|
47
|
+
return v4.quoter;
|
|
48
|
+
}
|
|
49
|
+
// For other chains, use the chain config
|
|
50
|
+
if (this.chainConfig?.v4Quoter && this.chainConfig.v4Quoter !== ZERO_ADDRESS) {
|
|
51
|
+
return this.chainConfig.v4Quoter;
|
|
52
|
+
}
|
|
53
|
+
throw new ClawnchDeployError(ClawnchErrorCode.FEATURE_NOT_AVAILABLE, `V4 Quoter not available on chain ${this.chainId}`);
|
|
54
|
+
}
|
|
55
|
+
/** Get the StateView address for the current chain */
|
|
56
|
+
getStateViewAddress() {
|
|
57
|
+
if (this.chainId === 8453 || this.chainId === 84532) {
|
|
58
|
+
const v4 = getUniswapV4Addresses(this.network);
|
|
59
|
+
return v4.stateView;
|
|
60
|
+
}
|
|
61
|
+
if (this.chainConfig?.v4StateView && this.chainConfig.v4StateView !== ZERO_ADDRESS) {
|
|
62
|
+
return this.chainConfig.v4StateView;
|
|
63
|
+
}
|
|
64
|
+
throw new ClawnchDeployError(ClawnchErrorCode.FEATURE_NOT_AVAILABLE, `V4 StateView not available on chain ${this.chainId}`);
|
|
65
|
+
}
|
|
66
|
+
// ==========================================================================
|
|
67
|
+
// Pool State Reading
|
|
68
|
+
// ==========================================================================
|
|
69
|
+
/**
|
|
70
|
+
* Read current pool state from StateView.
|
|
71
|
+
*/
|
|
72
|
+
async getPoolState(poolKey) {
|
|
73
|
+
const stateView = this.getStateViewAddress();
|
|
74
|
+
const poolId = await this.computePoolId(poolKey);
|
|
75
|
+
const [slot0, liquidity] = await Promise.all([
|
|
76
|
+
this.publicClient.readContract({
|
|
77
|
+
address: stateView,
|
|
78
|
+
abi: StateViewABI,
|
|
79
|
+
functionName: 'getSlot0',
|
|
80
|
+
args: [poolId],
|
|
81
|
+
}),
|
|
82
|
+
this.publicClient.readContract({
|
|
83
|
+
address: stateView,
|
|
84
|
+
abi: StateViewABI,
|
|
85
|
+
functionName: 'getLiquidity',
|
|
86
|
+
args: [poolId],
|
|
87
|
+
}),
|
|
88
|
+
]);
|
|
89
|
+
return {
|
|
90
|
+
sqrtPriceX96: slot0[0],
|
|
91
|
+
tick: Number(slot0[1]),
|
|
92
|
+
liquidity: liquidity,
|
|
93
|
+
protocolFee: Number(slot0[2]),
|
|
94
|
+
lpFee: Number(slot0[3]),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Compute pool ID from pool key (keccak256 of abi-encoded key).
|
|
99
|
+
*/
|
|
100
|
+
async computePoolId(poolKey) {
|
|
101
|
+
const { keccak256, encodeAbiParameters } = await import('viem');
|
|
102
|
+
return keccak256(encodeAbiParameters([
|
|
103
|
+
{ type: 'address' },
|
|
104
|
+
{ type: 'address' },
|
|
105
|
+
{ type: 'uint24' },
|
|
106
|
+
{ type: 'int24' },
|
|
107
|
+
{ type: 'address' },
|
|
108
|
+
], [
|
|
109
|
+
poolKey.currency0,
|
|
110
|
+
poolKey.currency1,
|
|
111
|
+
poolKey.fee,
|
|
112
|
+
poolKey.tickSpacing,
|
|
113
|
+
poolKey.hooks,
|
|
114
|
+
]));
|
|
115
|
+
}
|
|
116
|
+
// ==========================================================================
|
|
117
|
+
// Quoting
|
|
118
|
+
// ==========================================================================
|
|
119
|
+
/**
|
|
120
|
+
* Quote an exact input swap (sell a fixed amount, get variable output).
|
|
121
|
+
*
|
|
122
|
+
* Uses the V4 Quoter's `quoteExactInputSingle` via `eth_call` simulation.
|
|
123
|
+
* The Quoter intentionally reverts with the result — viem handles this
|
|
124
|
+
* via `simulateContract` or we catch the revert.
|
|
125
|
+
*/
|
|
126
|
+
async quoteExactInput(params) {
|
|
127
|
+
const quoter = this.getQuoterAddress();
|
|
128
|
+
const sqrtPriceLimit = params.sqrtPriceLimitX96 ??
|
|
129
|
+
(params.zeroForOne ? MIN_SQRT_PRICE : MAX_SQRT_PRICE);
|
|
130
|
+
try {
|
|
131
|
+
// The V4 Quoter works by simulating a swap and reverting with the result.
|
|
132
|
+
// We use eth_call (readContract) which catches the revert output.
|
|
133
|
+
const result = await this.publicClient.readContract({
|
|
134
|
+
address: quoter,
|
|
135
|
+
abi: V4QuoterABI,
|
|
136
|
+
functionName: 'quoteExactInputSingle',
|
|
137
|
+
args: [{
|
|
138
|
+
poolKey: {
|
|
139
|
+
currency0: params.poolKey.currency0,
|
|
140
|
+
currency1: params.poolKey.currency1,
|
|
141
|
+
fee: params.poolKey.fee,
|
|
142
|
+
tickSpacing: params.poolKey.tickSpacing,
|
|
143
|
+
hooks: params.poolKey.hooks,
|
|
144
|
+
},
|
|
145
|
+
zeroForOne: params.zeroForOne,
|
|
146
|
+
exactAmount: params.amount,
|
|
147
|
+
sqrtPriceLimitX96: sqrtPriceLimit,
|
|
148
|
+
hookData: params.hookData ?? '0x',
|
|
149
|
+
}],
|
|
150
|
+
});
|
|
151
|
+
const amountOut = result[0];
|
|
152
|
+
const gasEstimate = result[1];
|
|
153
|
+
// Calculate price impact
|
|
154
|
+
const impact = await this.calculatePriceImpact(params.poolKey, params.zeroForOne, params.amount, amountOut);
|
|
155
|
+
return {
|
|
156
|
+
quotedAmount: amountOut,
|
|
157
|
+
gasEstimate,
|
|
158
|
+
...impact,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
catch (err) {
|
|
162
|
+
// The quoter may revert with encoded output — try to parse it
|
|
163
|
+
if (err.cause?.data) {
|
|
164
|
+
return this.parseQuoterRevert(err.cause.data, params);
|
|
165
|
+
}
|
|
166
|
+
throw new ClawnchDeployError(ClawnchErrorCode.RPC_ERROR, `V4 Quoter quoteExactInputSingle failed: ${err.message}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Quote an exact output swap (buy a fixed amount, pay variable input).
|
|
171
|
+
*/
|
|
172
|
+
async quoteExactOutput(params) {
|
|
173
|
+
const quoter = this.getQuoterAddress();
|
|
174
|
+
const sqrtPriceLimit = params.sqrtPriceLimitX96 ??
|
|
175
|
+
(params.zeroForOne ? MIN_SQRT_PRICE : MAX_SQRT_PRICE);
|
|
176
|
+
try {
|
|
177
|
+
const result = await this.publicClient.readContract({
|
|
178
|
+
address: quoter,
|
|
179
|
+
abi: V4QuoterABI,
|
|
180
|
+
functionName: 'quoteExactOutputSingle',
|
|
181
|
+
args: [{
|
|
182
|
+
poolKey: {
|
|
183
|
+
currency0: params.poolKey.currency0,
|
|
184
|
+
currency1: params.poolKey.currency1,
|
|
185
|
+
fee: params.poolKey.fee,
|
|
186
|
+
tickSpacing: params.poolKey.tickSpacing,
|
|
187
|
+
hooks: params.poolKey.hooks,
|
|
188
|
+
},
|
|
189
|
+
zeroForOne: params.zeroForOne,
|
|
190
|
+
exactAmount: params.amount,
|
|
191
|
+
sqrtPriceLimitX96: sqrtPriceLimit,
|
|
192
|
+
hookData: params.hookData ?? '0x',
|
|
193
|
+
}],
|
|
194
|
+
});
|
|
195
|
+
const amountIn = result[0];
|
|
196
|
+
const gasEstimate = result[1];
|
|
197
|
+
const impact = await this.calculatePriceImpact(params.poolKey, params.zeroForOne, amountIn, params.amount);
|
|
198
|
+
return {
|
|
199
|
+
quotedAmount: amountIn,
|
|
200
|
+
gasEstimate,
|
|
201
|
+
...impact,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
catch (err) {
|
|
205
|
+
if (err.cause?.data) {
|
|
206
|
+
return this.parseQuoterRevert(err.cause.data, params);
|
|
207
|
+
}
|
|
208
|
+
throw new ClawnchDeployError(ClawnchErrorCode.RPC_ERROR, `V4 Quoter quoteExactOutputSingle failed: ${err.message}`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
// ==========================================================================
|
|
212
|
+
// Price Impact
|
|
213
|
+
// ==========================================================================
|
|
214
|
+
/**
|
|
215
|
+
* Calculate price impact for a swap.
|
|
216
|
+
*
|
|
217
|
+
* Price impact = (executionPrice - marketPrice) / marketPrice
|
|
218
|
+
*
|
|
219
|
+
* For exact input: executionPrice = amountOut / amountIn
|
|
220
|
+
* Market price comes from current pool sqrtPriceX96.
|
|
221
|
+
*/
|
|
222
|
+
async calculatePriceImpact(poolKey, zeroForOne, amountIn, amountOut) {
|
|
223
|
+
try {
|
|
224
|
+
const state = await this.getPoolState(poolKey);
|
|
225
|
+
if (state.sqrtPriceX96 === 0n || state.liquidity === 0n) {
|
|
226
|
+
return { priceImpact: null, currentPrice: null, priceAfterSwap: null };
|
|
227
|
+
}
|
|
228
|
+
// Current market price (token1/token0)
|
|
229
|
+
const currentPrice = this.sqrtPriceX96ToPrice(state.sqrtPriceX96);
|
|
230
|
+
// Execution price from the quote
|
|
231
|
+
// If zeroForOne: selling currency0, buying currency1
|
|
232
|
+
// executionPrice = amountOut / amountIn (currency1 per currency0)
|
|
233
|
+
// If oneForZero: selling currency1, buying currency0
|
|
234
|
+
// executionPrice = amountIn / amountOut (currency1 per currency0)
|
|
235
|
+
let executionPrice;
|
|
236
|
+
if (zeroForOne) {
|
|
237
|
+
executionPrice = Number(amountOut) / Number(amountIn);
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
executionPrice = Number(amountIn) / Number(amountOut);
|
|
241
|
+
}
|
|
242
|
+
// Price impact (negative = unfavorable)
|
|
243
|
+
const priceImpact = currentPrice > 0
|
|
244
|
+
? (executionPrice - currentPrice) / currentPrice
|
|
245
|
+
: null;
|
|
246
|
+
return {
|
|
247
|
+
priceImpact,
|
|
248
|
+
currentPrice,
|
|
249
|
+
priceAfterSwap: executionPrice,
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
catch {
|
|
253
|
+
return { priceImpact: null, currentPrice: null, priceAfterSwap: null };
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Get estimated price impact without executing a full quote.
|
|
258
|
+
*
|
|
259
|
+
* Uses the simplified formula:
|
|
260
|
+
* impact ≈ amountIn / (2 * liquidityInPool)
|
|
261
|
+
*
|
|
262
|
+
* This is a rough estimate — use quoteExactInput for precision.
|
|
263
|
+
*/
|
|
264
|
+
async estimatePriceImpact(poolKey, amountIn) {
|
|
265
|
+
const state = await this.getPoolState(poolKey);
|
|
266
|
+
if (state.liquidity === 0n)
|
|
267
|
+
return 1; // 100% impact if no liquidity
|
|
268
|
+
// Simplified: impact ≈ amount / (2 * liquidity)
|
|
269
|
+
return Number(amountIn) / (2 * Number(state.liquidity));
|
|
270
|
+
}
|
|
271
|
+
// ==========================================================================
|
|
272
|
+
// Utility
|
|
273
|
+
// ==========================================================================
|
|
274
|
+
/** Convert sqrtPriceX96 to a float price (token1/token0) */
|
|
275
|
+
sqrtPriceX96ToPrice(sqrtPriceX96) {
|
|
276
|
+
if (sqrtPriceX96 === 0n)
|
|
277
|
+
return 0;
|
|
278
|
+
const sqrtPrice = Number(sqrtPriceX96) / Number(Q96);
|
|
279
|
+
return sqrtPrice * sqrtPrice;
|
|
280
|
+
}
|
|
281
|
+
/** Convert a float price to sqrtPriceX96 */
|
|
282
|
+
priceToSqrtPriceX96(price) {
|
|
283
|
+
if (price <= 0)
|
|
284
|
+
return 0n;
|
|
285
|
+
const sqrtPrice = Math.sqrt(price);
|
|
286
|
+
return BigInt(Math.floor(sqrtPrice * Number(Q96)));
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Check if a pool exists and has liquidity.
|
|
290
|
+
*/
|
|
291
|
+
async isPoolActive(poolKey) {
|
|
292
|
+
try {
|
|
293
|
+
const state = await this.getPoolState(poolKey);
|
|
294
|
+
return state.sqrtPriceX96 > 0n && state.liquidity > 0n;
|
|
295
|
+
}
|
|
296
|
+
catch {
|
|
297
|
+
return false;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Get the WETH address for the current chain.
|
|
302
|
+
*/
|
|
303
|
+
getWethAddress() {
|
|
304
|
+
if (this.chainConfig)
|
|
305
|
+
return this.chainConfig.weth;
|
|
306
|
+
throw new ClawnchDeployError(ClawnchErrorCode.INVALID_CHAIN, `Cannot determine WETH address for chain ${this.chainId}`);
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Build a pool key for a token paired with WETH.
|
|
310
|
+
*
|
|
311
|
+
* Automatically sorts currency0/currency1 (lower address first).
|
|
312
|
+
*/
|
|
313
|
+
buildWethPoolKey(token, fee = 3000, tickSpacing = 60, hooks = ZERO_ADDRESS) {
|
|
314
|
+
const weth = this.getWethAddress();
|
|
315
|
+
const tokenLower = token.toLowerCase();
|
|
316
|
+
const wethLower = weth.toLowerCase();
|
|
317
|
+
const [currency0, currency1] = tokenLower < wethLower
|
|
318
|
+
? [token, weth]
|
|
319
|
+
: [weth, token];
|
|
320
|
+
return { currency0, currency1, fee, tickSpacing, hooks };
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Determine if selling token for WETH requires zeroForOne or oneForZero.
|
|
324
|
+
*/
|
|
325
|
+
isTokenCurrency0(token) {
|
|
326
|
+
const weth = this.getWethAddress();
|
|
327
|
+
return token.toLowerCase() < weth.toLowerCase();
|
|
328
|
+
}
|
|
329
|
+
// ==========================================================================
|
|
330
|
+
// Clawnch-native: Auto-discover pool keys from LP locker
|
|
331
|
+
// ==========================================================================
|
|
332
|
+
/**
|
|
333
|
+
* Build a pool key for a Clawnch token by reading its deployment data
|
|
334
|
+
* from the LP locker contract.
|
|
335
|
+
*
|
|
336
|
+
* This is the SDK's killer feature — Clawnch tokens have their pool key
|
|
337
|
+
* (including the correct hook address) stored on-chain in the LP locker.
|
|
338
|
+
* No manual configuration needed. This works for ANY token deployed
|
|
339
|
+
* through Clawnch, including tokens with MEV hooks, custom fee tiers,
|
|
340
|
+
* and non-standard tick spacings.
|
|
341
|
+
*
|
|
342
|
+
* Falls back to `buildWethPoolKey()` (zero hook, 3000 fee) if the token
|
|
343
|
+
* is not a Clawnch token.
|
|
344
|
+
*
|
|
345
|
+
* @param token - Token address (must be on Base)
|
|
346
|
+
* @returns Pool key with correct hook, fee, and tick spacing
|
|
347
|
+
*/
|
|
348
|
+
async buildPoolKeyFromToken(token) {
|
|
349
|
+
const rewards = await this.getTokenRewards(token);
|
|
350
|
+
if (rewards) {
|
|
351
|
+
return {
|
|
352
|
+
currency0: rewards.poolKey.currency0,
|
|
353
|
+
currency1: rewards.poolKey.currency1,
|
|
354
|
+
fee: rewards.poolKey.fee,
|
|
355
|
+
tickSpacing: rewards.poolKey.tickSpacing,
|
|
356
|
+
hooks: rewards.poolKey.hooks,
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
// Not a Clawnch token — fall back to generic WETH pool key
|
|
360
|
+
return this.buildWethPoolKey(token);
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Get the full token reward info from the Clawnch LP locker.
|
|
364
|
+
*
|
|
365
|
+
* Returns null if the token wasn't deployed through Clawnch.
|
|
366
|
+
*/
|
|
367
|
+
async getTokenRewards(token) {
|
|
368
|
+
// Only works on Base (Clawnch's chain)
|
|
369
|
+
if (this.chainId !== 8453 && this.chainId !== 84532)
|
|
370
|
+
return null;
|
|
371
|
+
try {
|
|
372
|
+
const reader = new ClawnchReader({
|
|
373
|
+
publicClient: this.publicClient,
|
|
374
|
+
network: this.network,
|
|
375
|
+
});
|
|
376
|
+
return await reader.getTokenRewards(token);
|
|
377
|
+
}
|
|
378
|
+
catch {
|
|
379
|
+
return null;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* One-call quote for any Clawnch token: auto-discovers pool key,
|
|
384
|
+
* determines swap direction, and returns the quote.
|
|
385
|
+
*
|
|
386
|
+
* This replaces the 3-step manual flow of:
|
|
387
|
+
* 1. Get pool key from LP locker
|
|
388
|
+
* 2. Determine zeroForOne from WETH position
|
|
389
|
+
* 3. Call quoteExactInput
|
|
390
|
+
*
|
|
391
|
+
* @param token - Clawnch token address
|
|
392
|
+
* @param ethAmount - ETH amount to swap (raw units)
|
|
393
|
+
* @param direction - 'buy' (ETH→Token) or 'sell' (Token→ETH)
|
|
394
|
+
*/
|
|
395
|
+
async quoteClawnchToken(token, ethAmount, direction = 'buy') {
|
|
396
|
+
const poolKey = await this.buildPoolKeyFromToken(token);
|
|
397
|
+
const tokenIsCurrency0 = this.isTokenCurrency0(token);
|
|
398
|
+
// buy = ETH→Token: selling WETH for token
|
|
399
|
+
// sell = Token→ETH: selling token for WETH
|
|
400
|
+
const zeroForOne = direction === 'buy' ? !tokenIsCurrency0 : tokenIsCurrency0;
|
|
401
|
+
const quote = await this.quoteExactInput({
|
|
402
|
+
poolKey,
|
|
403
|
+
zeroForOne,
|
|
404
|
+
amount: ethAmount,
|
|
405
|
+
});
|
|
406
|
+
return { ...quote, poolKey };
|
|
407
|
+
}
|
|
408
|
+
// ==========================================================================
|
|
409
|
+
// Internal
|
|
410
|
+
// ==========================================================================
|
|
411
|
+
/**
|
|
412
|
+
* Try to parse a quoter revert (the V4 quoter reverts with encoded results).
|
|
413
|
+
*/
|
|
414
|
+
async parseQuoterRevert(data, params) {
|
|
415
|
+
try {
|
|
416
|
+
// The quoter reverts with abi.encode(uint256 amount, uint256 gasEstimate)
|
|
417
|
+
const { decodeAbiParameters } = await import('viem');
|
|
418
|
+
const decoded = decodeAbiParameters([{ type: 'uint256' }, { type: 'uint256' }], data);
|
|
419
|
+
return {
|
|
420
|
+
quotedAmount: decoded[0],
|
|
421
|
+
gasEstimate: decoded[1],
|
|
422
|
+
priceImpact: null,
|
|
423
|
+
currentPrice: null,
|
|
424
|
+
priceAfterSwap: null,
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
catch {
|
|
428
|
+
throw new ClawnchDeployError(ClawnchErrorCode.RPC_ERROR, 'Failed to decode V4 Quoter revert data');
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
//# sourceMappingURL=uniswap-quoter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uniswap-quoter.js","sourceRoot":"","sources":["../src/uniswap-quoter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UniswapTradingApi — Swap execution via Uniswap's Trading API.
|
|
3
|
+
*
|
|
4
|
+
* Implements the 3-step flow:
|
|
5
|
+
* 1. POST /check_approval → tells you if token approval is needed
|
|
6
|
+
* 2. POST /quote → returns a firm swap quote
|
|
7
|
+
* 3. POST /swap → returns signed calldata for UniversalRouter
|
|
8
|
+
*
|
|
9
|
+
* Supports all 15 Uniswap chains via the multi-chain registry.
|
|
10
|
+
* Falls through to direct V4 UniversalRouter execution if no API key
|
|
11
|
+
* is available (see uniswap-quoter.ts for on-chain quoting).
|
|
12
|
+
*
|
|
13
|
+
* @see https://docs.uniswap.org/api/trading-api
|
|
14
|
+
*
|
|
15
|
+
* Critical Trading API rules (from Uniswap AI swap-integration skill):
|
|
16
|
+
* - Spread the quote response INTO the swap request (don't nest/wrap it)
|
|
17
|
+
* - Strip `permitData: null` before sending to /swap
|
|
18
|
+
* - Quotes expire in ~30 seconds — execute promptly
|
|
19
|
+
* - Use `x-universal-router-version: 2.0` header
|
|
20
|
+
*/
|
|
21
|
+
import { type Address, type Hash, type Hex } from 'viem';
|
|
22
|
+
import type { PublicClient, WalletClient } from 'viem';
|
|
23
|
+
import { type UniswapChainConfig } from './uniswap-chains.js';
|
|
24
|
+
import { Permit2Client } from './permit2.js';
|
|
25
|
+
export interface UniswapTradingConfig {
|
|
26
|
+
/** Wallet client (must have an account) */
|
|
27
|
+
wallet: WalletClient & {
|
|
28
|
+
account: {
|
|
29
|
+
address: Address;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
/** Public client for the target chain */
|
|
33
|
+
publicClient: PublicClient;
|
|
34
|
+
/** Chain ID to trade on (default: 8453 = Base) */
|
|
35
|
+
chainId?: number;
|
|
36
|
+
/** Uniswap Trading API key (required for Trading API path) */
|
|
37
|
+
apiKey?: string;
|
|
38
|
+
/** Slippage tolerance in basis points (default: 50 = 0.5%) */
|
|
39
|
+
slippageBps?: number;
|
|
40
|
+
}
|
|
41
|
+
export interface TradingSwapParams {
|
|
42
|
+
/** Token to sell (use native address or 'NATIVE' for ETH) */
|
|
43
|
+
tokenIn: Address;
|
|
44
|
+
/** Token to buy */
|
|
45
|
+
tokenOut: Address;
|
|
46
|
+
/** Amount to sell (in raw units, as string for the API) */
|
|
47
|
+
amount: bigint;
|
|
48
|
+
/** 'EXACT_INPUT' or 'EXACT_OUTPUT' */
|
|
49
|
+
type?: 'EXACT_INPUT' | 'EXACT_OUTPUT';
|
|
50
|
+
/** Slippage in bps (overrides config-level) */
|
|
51
|
+
slippageBps?: number;
|
|
52
|
+
/** Swap recipient (defaults to wallet address) */
|
|
53
|
+
recipient?: Address;
|
|
54
|
+
/** Deadline in seconds from now (default: 300 = 5 min) */
|
|
55
|
+
deadlineSeconds?: number;
|
|
56
|
+
}
|
|
57
|
+
/** Response from /check_approval */
|
|
58
|
+
export interface ApprovalCheckResult {
|
|
59
|
+
/** Whether approval is needed */
|
|
60
|
+
approvalNeeded: boolean;
|
|
61
|
+
/** The spender to approve (Permit2 address) */
|
|
62
|
+
approvalTarget: Address | null;
|
|
63
|
+
/** Token needing approval */
|
|
64
|
+
token: Address | null;
|
|
65
|
+
/** Approval transaction data (if needed) */
|
|
66
|
+
approvalTx: {
|
|
67
|
+
to: Address;
|
|
68
|
+
data: Hex;
|
|
69
|
+
value: string;
|
|
70
|
+
} | null;
|
|
71
|
+
}
|
|
72
|
+
/** Parsed quote from the Trading API */
|
|
73
|
+
export interface TradingQuote {
|
|
74
|
+
/** Raw quote response (to spread into /swap request) */
|
|
75
|
+
raw: Record<string, any>;
|
|
76
|
+
/** Quoted output amount */
|
|
77
|
+
quoteAmount: bigint;
|
|
78
|
+
/** Gas estimate in native token units */
|
|
79
|
+
gasEstimate: bigint;
|
|
80
|
+
/** Price impact as a decimal (e.g. 0.003 = 0.3%) */
|
|
81
|
+
priceImpact: number;
|
|
82
|
+
/** Route description */
|
|
83
|
+
routeDescription: string;
|
|
84
|
+
/** When the quote expires */
|
|
85
|
+
expiresAt: number;
|
|
86
|
+
}
|
|
87
|
+
/** Result after executing a Trading API swap */
|
|
88
|
+
export interface TradingSwapResult {
|
|
89
|
+
/** Transaction hash */
|
|
90
|
+
txHash: Hash;
|
|
91
|
+
/** Amount received (from quote — on-chain receipt may differ slightly) */
|
|
92
|
+
quoteAmount: bigint;
|
|
93
|
+
/** Transaction receipt */
|
|
94
|
+
receipt: any;
|
|
95
|
+
/** Gas used */
|
|
96
|
+
gasUsed: bigint;
|
|
97
|
+
}
|
|
98
|
+
export declare class UniswapTradingApi {
|
|
99
|
+
private readonly wallet;
|
|
100
|
+
private readonly publicClient;
|
|
101
|
+
private readonly chainId;
|
|
102
|
+
private readonly apiKey;
|
|
103
|
+
private readonly slippageBps;
|
|
104
|
+
private readonly chainConfig;
|
|
105
|
+
constructor(config: UniswapTradingConfig);
|
|
106
|
+
/** Lazy-initialized Permit2 client for signature-based approvals */
|
|
107
|
+
private _permit2;
|
|
108
|
+
/** Check if the Trading API is available (has API key) */
|
|
109
|
+
get isAvailable(): boolean;
|
|
110
|
+
/** Get the taker address */
|
|
111
|
+
get taker(): Address;
|
|
112
|
+
/** Get Permit2 client for advanced approval flows */
|
|
113
|
+
get permit2(): Permit2Client;
|
|
114
|
+
private apiPost;
|
|
115
|
+
/**
|
|
116
|
+
* Check if the sell token needs approval for Permit2 / UniversalRouter.
|
|
117
|
+
*
|
|
118
|
+
* Native ETH never needs approval.
|
|
119
|
+
*/
|
|
120
|
+
checkApproval(tokenIn: Address, amount: bigint): Promise<ApprovalCheckResult>;
|
|
121
|
+
/**
|
|
122
|
+
* Get a firm swap quote from the Trading API.
|
|
123
|
+
*
|
|
124
|
+
* The raw quote response must be spread into the /swap request — the API
|
|
125
|
+
* expects the same shape, not a nested `quote` key.
|
|
126
|
+
*/
|
|
127
|
+
getQuote(params: TradingSwapParams): Promise<TradingQuote>;
|
|
128
|
+
/**
|
|
129
|
+
* Execute a swap using the Trading API's /swap endpoint.
|
|
130
|
+
*
|
|
131
|
+
* The quote response is spread directly into the swap request body.
|
|
132
|
+
* `permitData: null` is stripped (the API rejects it if present).
|
|
133
|
+
*/
|
|
134
|
+
executeSwap(quote: TradingQuote): Promise<TradingSwapResult>;
|
|
135
|
+
/**
|
|
136
|
+
* Execute a full swap: check approval → approve if needed → quote → swap.
|
|
137
|
+
*
|
|
138
|
+
* This is the primary high-level method.
|
|
139
|
+
*
|
|
140
|
+
* Approval flow:
|
|
141
|
+
* 1. If Trading API returns an approval tx, execute it directly
|
|
142
|
+
* 2. Otherwise, use Permit2Client for the full two-step flow:
|
|
143
|
+
* a. ERC20.approve(Permit2, MAX) — one-time per token
|
|
144
|
+
* b. Permit2.approve(token, UniversalRouter, amount, expiry) — grant router access
|
|
145
|
+
*/
|
|
146
|
+
swap(params: TradingSwapParams): Promise<TradingSwapResult>;
|
|
147
|
+
/**
|
|
148
|
+
* Full Permit2 approval flow for swaps:
|
|
149
|
+
* 1. ERC20.approve(Permit2, MAX) — one-time per token
|
|
150
|
+
* 2. Permit2.approve(token, UniversalRouter, amount, expiry)
|
|
151
|
+
*
|
|
152
|
+
* Uses direct on-chain approve (not signature) since agent wallets
|
|
153
|
+
* control their own private key and don't benefit from gasless signing.
|
|
154
|
+
*/
|
|
155
|
+
ensureFullPermit2Approval(token: Address, amount: bigint): Promise<{
|
|
156
|
+
approvalTxHash: Hash | null;
|
|
157
|
+
permitTxHash: Hash | null;
|
|
158
|
+
}>;
|
|
159
|
+
/**
|
|
160
|
+
* Approve a token for Permit2 (ERC20→Permit2 only, step 1).
|
|
161
|
+
*
|
|
162
|
+
* For the full flow (ERC20→Permit2 + Permit2→Router), use
|
|
163
|
+
* `ensureFullPermit2Approval()` or the `permit2` client directly.
|
|
164
|
+
*/
|
|
165
|
+
approveTokenForPermit2(token: Address): Promise<Hash | null>;
|
|
166
|
+
/**
|
|
167
|
+
* Check ERC20 allowance to the Permit2 contract.
|
|
168
|
+
*/
|
|
169
|
+
getErc20Permit2Allowance(token: Address): Promise<bigint>;
|
|
170
|
+
/**
|
|
171
|
+
* Check Permit2 AllowanceTransfer state for a token → spender pair.
|
|
172
|
+
*
|
|
173
|
+
* Returns the Permit2 internal allowance (amount, expiration, nonce),
|
|
174
|
+
* NOT the ERC20 allowance to Permit2 itself.
|
|
175
|
+
*/
|
|
176
|
+
getPermit2Allowance(token: Address, spender?: Address): Promise<import("./permit2.js").Permit2Allowance>;
|
|
177
|
+
/**
|
|
178
|
+
* Generate a Uniswap app deep link for a swap.
|
|
179
|
+
*
|
|
180
|
+
* Useful for sharing swap links or as a fallback UI for users.
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* ```
|
|
184
|
+
* const link = trading.getSwapDeepLink({
|
|
185
|
+
* tokenIn: WETH,
|
|
186
|
+
* tokenOut: TOKEN,
|
|
187
|
+
* amount: parseEther('0.1'),
|
|
188
|
+
* });
|
|
189
|
+
* // => "https://app.uniswap.org/swap?chain=base&inputCurrency=0x...&outputCurrency=0x...&value=0.1&field=INPUT"
|
|
190
|
+
* ```
|
|
191
|
+
*/
|
|
192
|
+
getSwapDeepLink(params: {
|
|
193
|
+
tokenIn: Address;
|
|
194
|
+
tokenOut: Address;
|
|
195
|
+
amount?: bigint;
|
|
196
|
+
decimals?: number;
|
|
197
|
+
}): string;
|
|
198
|
+
private isNative;
|
|
199
|
+
private buildRouteDescription;
|
|
200
|
+
/** Get chain config */
|
|
201
|
+
get chain(): UniswapChainConfig;
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=uniswap-trading.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uniswap-trading.d.ts","sourceRoot":"","sources":["../src/uniswap-trading.ts"],"names":[],"mappings":"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"}
|