@guru-fund/sdk 0.2.7 → 0.2.9
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/dist/router/constants.d.ts +1 -0
- package/dist/router/constants.js +1 -0
- package/dist/router/index.d.ts +1 -0
- package/dist/router/index.js +35 -2
- package/dist/router/poolHelper.d.ts +2 -0
- package/dist/router/poolHelper.js +19 -9
- package/dist/router/v4PoolDiscovery.d.ts +1 -0
- package/dist/router/v4PoolDiscovery.js +6 -3
- package/package.json +1 -1
|
@@ -16,3 +16,4 @@ export declare const V4_ZERO_ADDRESS = "0x00000000000000000000000000000000000000
|
|
|
16
16
|
export declare const DEXSCREENER_ENDPOINT = "https://api.dexscreener.com/token-pairs/v1";
|
|
17
17
|
export declare const V4_DISCOVERY_MIN_LIQUIDITY_USD = 10000;
|
|
18
18
|
export declare const V4_DISCOVERY_MAX_POOLS = 3;
|
|
19
|
+
export declare const V4_DISCOVERY_MAX_LP_FEE = 100000;
|
package/dist/router/constants.js
CHANGED
|
@@ -25,3 +25,4 @@ export const V4_ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
|
|
|
25
25
|
export const DEXSCREENER_ENDPOINT = 'https://api.dexscreener.com/token-pairs/v1';
|
|
26
26
|
export const V4_DISCOVERY_MIN_LIQUIDITY_USD = 10_000;
|
|
27
27
|
export const V4_DISCOVERY_MAX_POOLS = 3;
|
|
28
|
+
export const V4_DISCOVERY_MAX_LP_FEE = 100_000;
|
package/dist/router/index.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export interface RouterContext {
|
|
|
10
10
|
getPath: PathFetcher;
|
|
11
11
|
}
|
|
12
12
|
export declare function veloraThenV4Discovery(velora: () => Promise<Route>, v4Discovery: () => Promise<Route>): Promise<Route>;
|
|
13
|
+
export declare function bestOfV4AndFallback(v4Discovery: () => Promise<Route>, fallback: () => Promise<Route>): Promise<Route>;
|
|
13
14
|
export declare function tryWithVeloraFallback<T>(velora: () => Promise<T>, fallback: () => Promise<T>): Promise<T>;
|
|
14
15
|
export declare function getRouteIn(params: RouteSearchParams, ctx: RouterContext): Promise<Route>;
|
|
15
16
|
export declare function getRouteOut(params: RouteSearchParams, ctx: RouterContext): Promise<Route>;
|
package/dist/router/index.js
CHANGED
|
@@ -43,6 +43,29 @@ export async function veloraThenV4Discovery(velora, v4Discovery) {
|
|
|
43
43
|
return await v4Discovery();
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
|
+
export async function bestOfV4AndFallback(v4Discovery, fallback) {
|
|
47
|
+
const [v4Result, fallbackResult] = await Promise.allSettled([
|
|
48
|
+
v4Discovery(),
|
|
49
|
+
fallback(),
|
|
50
|
+
]);
|
|
51
|
+
if (v4Result.status === 'rejected' &&
|
|
52
|
+
v4Result.reason instanceof Error &&
|
|
53
|
+
(v4Result.reason.message.includes('TOKEN_LOCKED_BY_V4_HOOK') ||
|
|
54
|
+
v4Result.reason.message.includes('UNISWAP_V4_HOOK_ROUTE_REVERTED'))) {
|
|
55
|
+
throw v4Result.reason;
|
|
56
|
+
}
|
|
57
|
+
if (v4Result.status === 'fulfilled' && fallbackResult.status === 'fulfilled') {
|
|
58
|
+
return BigInt(v4Result.value.data.amountToReceive) >=
|
|
59
|
+
BigInt(fallbackResult.value.data.amountToReceive)
|
|
60
|
+
? v4Result.value
|
|
61
|
+
: fallbackResult.value;
|
|
62
|
+
}
|
|
63
|
+
if (v4Result.status === 'fulfilled')
|
|
64
|
+
return v4Result.value;
|
|
65
|
+
if (fallbackResult.status === 'fulfilled')
|
|
66
|
+
return fallbackResult.value;
|
|
67
|
+
throw fallbackResult.reason;
|
|
68
|
+
}
|
|
46
69
|
export async function tryWithVeloraFallback(velora, fallback) {
|
|
47
70
|
try {
|
|
48
71
|
return await velora();
|
|
@@ -72,7 +95,12 @@ export async function getRouteIn(params, ctx) {
|
|
|
72
95
|
simulator: ctx.simulator,
|
|
73
96
|
getSwapFeePercentage: ctx.getSwapFeePercentage,
|
|
74
97
|
};
|
|
75
|
-
|
|
98
|
+
try {
|
|
99
|
+
return await getVeloraRoute(params, veloraCtx);
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
return bestOfV4AndFallback(() => getUniswapV4Route(params, v4Ctx), () => getFallbackRouteIn(params, fallbackCtx));
|
|
103
|
+
}
|
|
76
104
|
}
|
|
77
105
|
export async function getRouteOut(params, ctx) {
|
|
78
106
|
const veloraCtx = {
|
|
@@ -89,7 +117,12 @@ export async function getRouteOut(params, ctx) {
|
|
|
89
117
|
simulator: ctx.simulator,
|
|
90
118
|
getSwapFeePercentage: ctx.getSwapFeePercentage,
|
|
91
119
|
};
|
|
92
|
-
|
|
120
|
+
try {
|
|
121
|
+
return await getVeloraRoute(params, veloraCtx);
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
return bestOfV4AndFallback(() => getUniswapV4Route(params, v4Ctx), () => getFallbackRouteOut(params, fallbackCtx));
|
|
125
|
+
}
|
|
93
126
|
}
|
|
94
127
|
export async function getPriceUsd1e18(token, ctx) {
|
|
95
128
|
const addresses = getGuruProtocolAddresses(ctx.chainId);
|
|
@@ -24,7 +24,10 @@ const V3_FACTORY_ABI = [
|
|
|
24
24
|
const AERO_V3_FACTORY_ABI = [
|
|
25
25
|
'function getPool(address tokenA, address tokenB, int24 tickSpacing) view returns (address pool)',
|
|
26
26
|
];
|
|
27
|
-
const V3_POOL_ABI = [
|
|
27
|
+
const V3_POOL_ABI = [
|
|
28
|
+
'function fee() view returns (uint24)',
|
|
29
|
+
'function liquidity() view returns (uint128)',
|
|
30
|
+
];
|
|
28
31
|
const AERO_FACTORY_ABI = [
|
|
29
32
|
'function getPool(address tokenA, address tokenB, bool stable) view returns (address)',
|
|
30
33
|
];
|
|
@@ -114,6 +117,17 @@ function buildDexTable(addresses) {
|
|
|
114
117
|
}
|
|
115
118
|
return table;
|
|
116
119
|
}
|
|
120
|
+
export function rankUsablePools(pools) {
|
|
121
|
+
return pools
|
|
122
|
+
.filter((pool) => pool.feeTier === 0 || (pool.activeLiquidity ?? 0n) > 0n)
|
|
123
|
+
.sort((a, b) => {
|
|
124
|
+
if (a.wethBalance > b.wethBalance)
|
|
125
|
+
return -1;
|
|
126
|
+
if (a.wethBalance < b.wethBalance)
|
|
127
|
+
return 1;
|
|
128
|
+
return 0;
|
|
129
|
+
});
|
|
130
|
+
}
|
|
117
131
|
const PERCENT_DENOMINATOR = 100000n;
|
|
118
132
|
const CACHE_DURATION = 60 * 60 * 1000;
|
|
119
133
|
function withSlippageTolerance(amount, slippage) {
|
|
@@ -274,11 +288,14 @@ export default class PoolHelper {
|
|
|
274
288
|
const wethBalance = await wethToken.balanceOf(poolAddress);
|
|
275
289
|
if (wethBalance === 0n)
|
|
276
290
|
return;
|
|
291
|
+
const pool = connect(poolAddress, V3_POOL_ABI, this.provider);
|
|
292
|
+
const activeLiquidity = await pool.liquidity();
|
|
277
293
|
pools.push({
|
|
278
294
|
address: poolAddress,
|
|
279
295
|
feeTier: feeTier,
|
|
280
296
|
exchangeFactory: factoryAddress,
|
|
281
297
|
wethBalance,
|
|
298
|
+
activeLiquidity,
|
|
282
299
|
});
|
|
283
300
|
}
|
|
284
301
|
catch {
|
|
@@ -286,14 +303,7 @@ export default class PoolHelper {
|
|
|
286
303
|
}));
|
|
287
304
|
}
|
|
288
305
|
}));
|
|
289
|
-
pools
|
|
290
|
-
if (a.wethBalance > b.wethBalance)
|
|
291
|
-
return -1;
|
|
292
|
-
if (a.wethBalance < b.wethBalance)
|
|
293
|
-
return 1;
|
|
294
|
-
return 0;
|
|
295
|
-
});
|
|
296
|
-
return pools;
|
|
306
|
+
return rankUsablePools(pools);
|
|
297
307
|
}
|
|
298
308
|
async getUniswapCompatibleTokenPools(token, options) {
|
|
299
309
|
const swappableOnly = options?.swappableOnly ?? true;
|
|
@@ -8,6 +8,7 @@ export interface V4PoolKey {
|
|
|
8
8
|
tickSpacing: number;
|
|
9
9
|
hooks: string;
|
|
10
10
|
}
|
|
11
|
+
export declare function isSafeDiscoveredV4PoolKey(key: V4PoolKey): boolean;
|
|
11
12
|
export declare function computeV4PoolId(key: V4PoolKey): string;
|
|
12
13
|
interface DexscreenerPair {
|
|
13
14
|
dexId?: string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AbiCoder, keccak256, zeroPadValue, } from 'ethers';
|
|
2
2
|
import { getGuruProtocolAddresses, } from '../addresses.js';
|
|
3
3
|
import compareAddresses from '../helpers/compareAddresses.js';
|
|
4
|
-
import { DEXSCREENER_ENDPOINT, V4_ZERO_ADDRESS, V4_DISCOVERY_MAX_POOLS, V4_DISCOVERY_MIN_LIQUIDITY_USD, VELORA_NEGATIVE_CACHE_TTL, VELORA_PATH_CACHE_TTL, } from './constants.js';
|
|
4
|
+
import { DEXSCREENER_ENDPOINT, V4_ZERO_ADDRESS, V4_DISCOVERY_MAX_POOLS, V4_DISCOVERY_MAX_LP_FEE, V4_DISCOVERY_MIN_LIQUIDITY_USD, VELORA_NEGATIVE_CACHE_TTL, VELORA_PATH_CACHE_TTL, } from './constants.js';
|
|
5
5
|
const V4_CHAIN_CONFIG = {
|
|
6
6
|
1: {
|
|
7
7
|
dexscreenerSlug: 'ethereum',
|
|
@@ -20,6 +20,9 @@ const V4_CHAIN_CONFIG = {
|
|
|
20
20
|
},
|
|
21
21
|
};
|
|
22
22
|
const POOL_INITIALIZE_TOPIC = '0xdd466e674ea557f56295e2d0218a125ea4b4f0f6f3307b95f85e6110838d6438';
|
|
23
|
+
export function isSafeDiscoveredV4PoolKey(key) {
|
|
24
|
+
return key.fee >= 0 && key.fee <= V4_DISCOVERY_MAX_LP_FEE;
|
|
25
|
+
}
|
|
23
26
|
export function computeV4PoolId(key) {
|
|
24
27
|
return keccak256(AbiCoder.defaultAbiCoder().encode(['address', 'address', 'uint24', 'int24', 'address'], [key.currency0, key.currency1, key.fee, key.tickSpacing, key.hooks]));
|
|
25
28
|
}
|
|
@@ -150,7 +153,7 @@ async function discoverDirectV4Paths(chainId, tokenIn, tokenOut, provider, endpo
|
|
|
150
153
|
break;
|
|
151
154
|
}
|
|
152
155
|
const keys = await Promise.all(poolIds.map((poolId) => resolvePoolKey(chainId, poolId, provider)));
|
|
153
|
-
const resolvedKeys = keys.filter((key) => key !== null);
|
|
156
|
+
const resolvedKeys = keys.filter((key) => key !== null && isSafeDiscoveredV4PoolKey(key));
|
|
154
157
|
const onchainKeys = resolvedKeys.length > 0
|
|
155
158
|
? []
|
|
156
159
|
: await discoverOnchainDirectV4PoolKeys(chainId, tokenIn, tokenOut, provider);
|
|
@@ -187,7 +190,7 @@ async function discoverOnchainDirectV4PoolKeys(chainId, tokenIn, tokenOut, provi
|
|
|
187
190
|
});
|
|
188
191
|
return logs
|
|
189
192
|
.map(poolKeyFromInitializeLog)
|
|
190
|
-
.filter((key) => key !== null)
|
|
193
|
+
.filter((key) => key !== null && isSafeDiscoveredV4PoolKey(key))
|
|
191
194
|
.sort((a, b) => a.fee - b.fee);
|
|
192
195
|
}
|
|
193
196
|
export function _clearV4DiscoveryCache() {
|