@guru-fund/sdk 0.2.1 → 0.2.3

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.
@@ -1,5 +1,5 @@
1
1
  export declare const VELORA_ENDPOINT = "https://api.velora.xyz/swap";
2
- export declare const SUPPORTED_DEXS: readonly ["UniswapV2", "UniswapV3", "UniswapV4", "PancakeSwapV2", "PancakeSwapV3"];
2
+ export declare const SUPPORTED_DEXS: readonly ["UniswapV2", "UniswapV3", "UniswapV4", "AerodromeV2", "PancakeSwapV2", "PancakeSwapV3"];
3
3
  export declare const VELORA_VERSION_BY_DEX: Partial<Record<SupportedDex, string>>;
4
4
  export type SupportedDex = (typeof SUPPORTED_DEXS)[number];
5
5
  export declare const INITIAL_SLIPPAGE_E3 = 500n;
@@ -3,6 +3,7 @@ export const SUPPORTED_DEXS = [
3
3
  'UniswapV2',
4
4
  'UniswapV3',
5
5
  'UniswapV4',
6
+ 'AerodromeV2',
6
7
  'PancakeSwapV2',
7
8
  'PancakeSwapV3',
8
9
  ];
@@ -2,6 +2,42 @@ import compareAddresses from '../helpers/compareAddresses.js';
2
2
  import { FundVault__factory } from '../typechain/index.js';
3
3
  import PoolHelper from './poolHelper.js';
4
4
  import { quoteWethTrade } from './quoteWethTrade.js';
5
+ async function tryDirectAerodromeV2RouteIn(poolHelper, { tokenIn, tokenOut, amountIn, slippage, finalization, }) {
6
+ const factory = poolHelper.addresses.factories.aerodromeV2;
7
+ if (!factory || !poolHelper.addresses.adapters.aerodromeV2)
8
+ return null;
9
+ try {
10
+ const route = await poolHelper.getStableForTokenQuote({
11
+ path: [tokenIn, tokenOut],
12
+ inputAmount: amountIn,
13
+ slippage,
14
+ exchangeFactory: factory,
15
+ finalization,
16
+ });
17
+ return { ...route, hops: 1 };
18
+ }
19
+ catch {
20
+ return null;
21
+ }
22
+ }
23
+ async function tryDirectAerodromeV2RouteOut(poolHelper, { tokenIn, tokenOut, amountIn, slippage, finalization, }) {
24
+ const factory = poolHelper.addresses.factories.aerodromeV2;
25
+ if (!factory || !poolHelper.addresses.adapters.aerodromeV2)
26
+ return null;
27
+ try {
28
+ const route = await poolHelper.getTokensForStableQuote({
29
+ path: [tokenIn, tokenOut],
30
+ inputAmount: amountIn,
31
+ slippage,
32
+ exchangeFactory: factory,
33
+ finalization,
34
+ });
35
+ return { ...route, hops: 1 };
36
+ }
37
+ catch {
38
+ return null;
39
+ }
40
+ }
5
41
  export async function getFallbackRouteIn(params, ctx) {
6
42
  const { chainId, tokenIn, tokenOut, amountIn, slippageE2 } = params;
7
43
  const slippage = BigInt(slippageE2 ?? 500) * 10n;
@@ -34,6 +70,15 @@ export async function getFallbackRouteIn(params, ctx) {
34
70
  finalization,
35
71
  });
36
72
  }
73
+ const directAerodrome = await tryDirectAerodromeV2RouteIn(poolHelper, {
74
+ tokenIn,
75
+ tokenOut,
76
+ amountIn,
77
+ slippage,
78
+ finalization,
79
+ });
80
+ if (directAerodrome)
81
+ return directAerodrome;
37
82
  const pool = await poolHelper.getUniswapCompatibleTokenPool(tokenOut);
38
83
  const path = [tokenIn, weth, tokenOut];
39
84
  const route = await poolHelper.getStableForTokenQuote({
@@ -78,6 +123,15 @@ export async function getFallbackRouteOut(params, ctx) {
78
123
  });
79
124
  return { ...route, hops: 1 };
80
125
  }
126
+ const directAerodrome = await tryDirectAerodromeV2RouteOut(poolHelper, {
127
+ tokenIn,
128
+ tokenOut,
129
+ amountIn,
130
+ slippage,
131
+ finalization,
132
+ });
133
+ if (directAerodrome)
134
+ return directAerodrome;
81
135
  const pool = await poolHelper.getUniswapCompatibleTokenPool(tokenIn);
82
136
  const path = [tokenIn, weth, tokenOut];
83
137
  const route = await poolHelper.getTokensForStableQuote({
@@ -65,26 +65,44 @@ export async function getRouteOut(params, ctx) {
65
65
  }
66
66
  export async function getPriceUsd1e18(token, ctx) {
67
67
  const addresses = getGuruProtocolAddresses(ctx.chainId);
68
+ if (compareAddresses(token, addresses.tokens.USDC) ||
69
+ compareAddresses(token, addresses.tokens.USDT)) {
70
+ return 10n ** 18n;
71
+ }
68
72
  const poolHelper = new PoolHelper({
69
73
  chainId: ctx.chainId,
70
74
  provider: ctx.provider,
71
75
  getSwapFeePercentage: ctx.getSwapFeePercentage,
72
76
  });
73
- const { amount: wethUsdt } = await poolHelper.getBestQuote({
74
- tokenAmount: parseEther('1'),
75
- path: [addresses.tokens.WETH, addresses.tokens.USDT],
76
- requireSwappable: false,
77
- });
78
- const wethUsd = wethUsdt * 10n ** 12n;
77
+ const stable = addresses.tokens.USDC;
78
+ const { decimals: stableDecimals } = await new Token(stable, ctx.provider)
79
+ .metadata()
80
+ .catch(() => ({ decimals: 6 }));
81
+ const stableUnit = Token.unitFor(stableDecimals);
82
+ const stableAmountToUsd1e18 = (amount) => (amount * 10n ** 18n) / stableUnit;
83
+ let wethUsdCache;
84
+ const getWethUsd = async () => {
85
+ if (wethUsdCache != null)
86
+ return wethUsdCache;
87
+ const { amount: wethStable } = await poolHelper.getBestQuote({
88
+ tokenAmount: parseEther('1'),
89
+ path: [addresses.tokens.WETH, stable],
90
+ requireSwappable: false,
91
+ });
92
+ wethUsdCache = stableAmountToUsd1e18(wethStable);
93
+ return wethUsdCache;
94
+ };
79
95
  if (compareAddresses(token, addresses.tokens.WETH)) {
80
- return wethUsd;
96
+ return getWethUsd();
81
97
  }
82
- const { decimals } = await new Token(token, ctx.provider)
83
- .metadata()
84
- .catch(() => ({ decimals: 0 }));
98
+ const { decimals } = await new Token(token, ctx.provider).metadata();
85
99
  const oneToken = 10n ** BigInt(decimals);
100
+ const stableUsd = await _priceViaDirectStablePool(token, oneToken, poolHelper, stable, stableDecimals);
101
+ if (stableUsd !== null)
102
+ return stableUsd;
86
103
  const WETH_UNIT = 10n ** 18n;
87
104
  try {
105
+ const wethUsd = await getWethUsd();
88
106
  const { amount: oneTokenInWeth } = await poolHelper.getBestQuote({
89
107
  tokenAmount: oneToken,
90
108
  path: [token, addresses.tokens.WETH],
@@ -93,13 +111,32 @@ export async function getPriceUsd1e18(token, ctx) {
93
111
  return (oneTokenInWeth * wethUsd) / WETH_UNIT;
94
112
  }
95
113
  catch (error) {
96
- const v4Usd = await _priceViaV4Pools(token, oneToken, wethUsd, ctx);
114
+ const v4Usd = await _priceViaV4Pools(token, oneToken, getWethUsd, ctx);
97
115
  if (v4Usd !== null)
98
116
  return v4Usd;
99
117
  throw error;
100
118
  }
101
119
  }
102
- async function _priceViaV4Pools(token, oneToken, wethUsd, ctx) {
120
+ async function _priceViaDirectStablePool(token, oneToken, poolHelper, stable, stableDecimals) {
121
+ const factory = poolHelper.addresses.factories.aerodromeV2;
122
+ if (!factory)
123
+ return null;
124
+ const route = await poolHelper
125
+ .getTokensForStableQuote({
126
+ path: [token, stable],
127
+ inputAmount: oneToken,
128
+ slippage: 0n,
129
+ exchangeFactory: factory,
130
+ })
131
+ .catch(() => null);
132
+ if (!route)
133
+ return null;
134
+ const amountToReceive = BigInt(route.data.amountToReceive);
135
+ if (amountToReceive === 0n)
136
+ return null;
137
+ return (amountToReceive * 10n ** 18n) / Token.unitFor(stableDecimals);
138
+ }
139
+ async function _priceViaV4Pools(token, oneToken, getWethUsd, ctx) {
103
140
  const addresses = getGuruProtocolAddresses(ctx.chainId);
104
141
  const quoterAddress = addresses.quoters.uniswapV4;
105
142
  if (!quoterAddress)
@@ -129,6 +166,7 @@ async function _priceViaV4Pools(token, oneToken, wethUsd, ctx) {
129
166
  }
130
167
  const inWeth = await quoteVia(addresses.tokens.WETH);
131
168
  if (inWeth !== null) {
169
+ const wethUsd = await getWethUsd();
132
170
  return (inWeth * wethUsd) / WETH_UNIT;
133
171
  }
134
172
  return null;
@@ -4,6 +4,21 @@ export function extractPathFromResponse(dex, response) {
4
4
  if (dex === 'UniswapV4') {
5
5
  return extractV4Path(response);
6
6
  }
7
+ if (dex === 'AerodromeV2') {
8
+ const v2Response = response;
9
+ const exchange = v2Response.priceRoute.bestRoute[0].swaps[0].swapExchanges[0];
10
+ const path = exchange.data.path;
11
+ if (!Array.isArray(path) || typeof path[0] !== 'string') {
12
+ throw new Error('Unexpected Aerodrome V2 path structure');
13
+ }
14
+ const routes = path.slice(0, -1).map((from, i) => ({
15
+ from,
16
+ to: path[i + 1],
17
+ stable: Boolean(exchange.data.pools?.[i]?.stable),
18
+ factory: exchange.data.factory,
19
+ }));
20
+ return { type: 'aerodromeV2', path, routes, hops: path.length - 1 };
21
+ }
7
22
  if (dex === 'UniswapV2' || dex === 'PancakeSwapV2') {
8
23
  const v2Response = response;
9
24
  const path = v2Response.priceRoute.bestRoute[0].swaps[0].swapExchanges[0]
@@ -61,7 +61,7 @@ type VersionSpecificQuoteRequest = Omit<QuoteRequest, 'path' | 'slippage'> & {
61
61
  poolAddress?: string;
62
62
  };
63
63
  export type StableQuoteRequest = {
64
- path: [string, string, string];
64
+ path: [string, string] | [string, string, string];
65
65
  inputAmount: bigint;
66
66
  slippage: bigint;
67
67
  exchangeFactory: string;
@@ -547,20 +547,24 @@ export default class PoolHelper {
547
547
  const quoter = dexData.kind === 'aerodrome'
548
548
  ? connect(dexData.quoter, AERO_V3_QUOTER_ABI, this.provider)
549
549
  : IPancakeQuoterV2__factory.connect(dexData.quoter, this.provider);
550
+ const [stable, intermediate, token] = path;
551
+ if (!token) {
552
+ throw new Error(`${PoolHelperError.EXCHANGE_INCOMPATIBLE}: direct V3 fallback not supported (factory=${exchangeFactory})`);
553
+ }
550
554
  const { feeTier: stableFeeTier } = await this.getUniswapCompatibleTokenPool(path[0], {
551
555
  exchangeFactory,
552
556
  });
553
- const { feeTier: tokenFeeTier } = await this.getUniswapCompatibleTokenPool(path[2], {
557
+ const { feeTier: tokenFeeTier } = await this.getUniswapCompatibleTokenPool(token, {
554
558
  exchangeFactory,
555
559
  });
556
- const pathBytes = solidityPacked(['address', 'uint24', 'address', 'uint24', 'address'], [path[0], stableFeeTier, path[1], tokenFeeTier, path[2]]);
560
+ const pathBytes = solidityPacked(['address', 'uint24', 'address', 'uint24', 'address'], [stable, stableFeeTier, intermediate, tokenFeeTier, token]);
557
561
  if (dexData.kind === 'aerodrome') {
558
562
  throw new Error(`${PoolHelperError.EXCHANGE_INCOMPATIBLE}: Aerodrome V3 multi-hop not supported (factory=${exchangeFactory})`);
559
563
  }
560
564
  const univ3Quoter = quoter;
561
565
  const amountOut = await this._quoteV3MultiHop(univ3Quoter, adjustedInputAmount, pathBytes, [
562
- { tokenIn: path[0], tokenOut: path[1], fee: stableFeeTier },
563
- { tokenIn: path[1], tokenOut: path[2], fee: tokenFeeTier },
566
+ { tokenIn: stable, tokenOut: intermediate, fee: stableFeeTier },
567
+ { tokenIn: intermediate, tokenOut: token, fee: tokenFeeTier },
564
568
  ]);
565
569
  const deadline = Math.floor((Date.now() + 1000 * 60 * 5) / 1000);
566
570
  const finalized = await this._finalizeExecutableQuote({
@@ -568,13 +572,13 @@ export default class PoolHelper {
568
572
  adapter,
569
573
  path: [
570
574
  {
571
- tokenIn: path[0],
572
- tokenOut: path[1],
575
+ tokenIn: stable,
576
+ tokenOut: intermediate,
573
577
  fee: String(stableFeeTier),
574
578
  },
575
579
  {
576
- tokenIn: path[1],
577
- tokenOut: path[2],
580
+ tokenIn: intermediate,
581
+ tokenOut: token,
578
582
  fee: String(tokenFeeTier),
579
583
  },
580
584
  ],
@@ -662,7 +666,10 @@ export default class PoolHelper {
662
666
  adapter,
663
667
  data: finalized.data,
664
668
  callData: finalized.callData,
665
- toll: { currency: path[2], amount: finalized.tollAmount },
669
+ toll: {
670
+ currency: path[path.length - 1],
671
+ amount: finalized.tollAmount,
672
+ },
666
673
  effectiveSlippageBps: finalized.effectiveSlippageBps,
667
674
  };
668
675
  }
@@ -697,7 +704,10 @@ export default class PoolHelper {
697
704
  adapter,
698
705
  data: finalized.data,
699
706
  callData: finalized.callData,
700
- toll: { currency: path[2], amount: finalized.tollAmount },
707
+ toll: {
708
+ currency: path[path.length - 1],
709
+ amount: finalized.tollAmount,
710
+ },
701
711
  effectiveSlippageBps: finalized.effectiveSlippageBps,
702
712
  };
703
713
  }
@@ -705,16 +715,20 @@ export default class PoolHelper {
705
715
  throw new Error(`${PoolHelperError.EXCHANGE_INCOMPATIBLE}: Aerodrome V3 multi-hop not supported (factory=${exchangeFactory})`);
706
716
  }
707
717
  const v3Quoter = IPancakeQuoterV2__factory.connect(dexData.quoter, this.provider);
718
+ const [token, intermediate, stable] = path;
719
+ if (!stable) {
720
+ throw new Error(`${PoolHelperError.EXCHANGE_INCOMPATIBLE}: direct V3 fallback not supported (factory=${exchangeFactory})`);
721
+ }
708
722
  const { feeTier: tokenFeeTier } = await this.getUniswapCompatibleTokenPool(path[0], {
709
723
  exchangeFactory,
710
724
  });
711
- const { feeTier: stableFeeTier } = await this.getUniswapCompatibleTokenPool(path[2], {
725
+ const { feeTier: stableFeeTier } = await this.getUniswapCompatibleTokenPool(stable, {
712
726
  exchangeFactory,
713
727
  });
714
- const pathBytes = solidityPacked(['address', 'uint24', 'address', 'uint24', 'address'], [path[0], tokenFeeTier, path[1], stableFeeTier, path[2]]);
728
+ const pathBytes = solidityPacked(['address', 'uint24', 'address', 'uint24', 'address'], [token, tokenFeeTier, intermediate, stableFeeTier, stable]);
715
729
  const amountOut = await this._quoteV3MultiHop(v3Quoter, inputAmount, pathBytes, [
716
- { tokenIn: path[0], tokenOut: path[1], fee: tokenFeeTier },
717
- { tokenIn: path[1], tokenOut: path[2], fee: stableFeeTier },
730
+ { tokenIn: token, tokenOut: intermediate, fee: tokenFeeTier },
731
+ { tokenIn: intermediate, tokenOut: stable, fee: stableFeeTier },
718
732
  ]);
719
733
  const deadline = Math.floor((Date.now() + 1000 * 60 * 5) / 1000);
720
734
  const netAmountOut = amountOut - (amountOut * swapFeePercentage) / PERCENT_DENOMINATOR;
@@ -723,13 +737,13 @@ export default class PoolHelper {
723
737
  adapter,
724
738
  path: [
725
739
  {
726
- tokenIn: path[0],
727
- tokenOut: path[1],
740
+ tokenIn: token,
741
+ tokenOut: intermediate,
728
742
  fee: String(tokenFeeTier),
729
743
  },
730
744
  {
731
- tokenIn: path[1],
732
- tokenOut: path[2],
745
+ tokenIn: intermediate,
746
+ tokenOut: stable,
733
747
  fee: String(stableFeeTier),
734
748
  },
735
749
  ],
@@ -755,7 +769,7 @@ export default class PoolHelper {
755
769
  adapter,
756
770
  data: finalized.data,
757
771
  callData: finalized.callData,
758
- toll: { currency: path[2], amount: finalized.tollAmount },
772
+ toll: { currency: stable, amount: finalized.tollAmount },
759
773
  effectiveSlippageBps: finalized.effectiveSlippageBps,
760
774
  };
761
775
  }
@@ -5,6 +5,12 @@ import type { SwapV4Struct } from '../typechain/out/UniswapV4Adapter';
5
5
  import type { GuruProtocolChainId } from '../addresses';
6
6
  import type { PrefixTx } from './simulation';
7
7
  export type V2Path = string[];
8
+ export type AeroV2Route = {
9
+ from: string;
10
+ to: string;
11
+ stable: boolean;
12
+ factory: string;
13
+ };
8
14
  export type V4PathHop = {
9
15
  tokenIn: string;
10
16
  tokenOut: string;
@@ -40,6 +46,11 @@ export type CachedPath = {
40
46
  type: 'v2';
41
47
  path: V2Path;
42
48
  hops: number;
49
+ } | {
50
+ type: 'aerodromeV2';
51
+ path: V2Path;
52
+ routes: AeroV2Route[];
53
+ hops: number;
43
54
  } | {
44
55
  type: 'v3';
45
56
  path: V3Path;
@@ -121,6 +132,14 @@ export interface VeloraDataV2 {
121
132
  feeFactor: number;
122
133
  gasUSD: string;
123
134
  }
135
+ export interface VeloraDataAerodromeV2 extends VeloraDataV2 {
136
+ pools?: {
137
+ stable?: boolean;
138
+ address?: string;
139
+ fee?: number;
140
+ direction?: boolean;
141
+ }[];
142
+ }
124
143
  export interface VeloraDataV3 {
125
144
  path: V3PathHop[];
126
145
  gasUSD: string;
@@ -145,5 +164,6 @@ export interface VeloraDataV4 {
145
164
  gasUSD?: string;
146
165
  }
147
166
  export type VeloraRouteResponseV2 = VeloraRouteResponse<VeloraDataV2>;
167
+ export type VeloraRouteResponseAerodromeV2 = VeloraRouteResponse<VeloraDataAerodromeV2>;
148
168
  export type VeloraRouteResponseV3 = VeloraRouteResponse<VeloraDataV3>;
149
169
  export type VeloraRouteResponseV4 = VeloraRouteResponse<VeloraDataV4>;
@@ -13,6 +13,7 @@ interface V3DexEntry {
13
13
  }
14
14
  interface VeloraDexConfig {
15
15
  UniswapV2?: V2DexEntry;
16
+ AerodromeV2?: V2DexEntry;
16
17
  PancakeSwapV2?: V2DexEntry;
17
18
  UniswapV3?: V3DexEntry;
18
19
  PancakeSwapV3?: V3DexEntry;
@@ -1,15 +1,21 @@
1
1
  import { Contract, solidityPacked } from 'ethers';
2
2
  import { TOLL_DIVISOR_20BPS } from '../constants.js';
3
- import { IPancakeQuoterV2__factory, UniswapV2Adapter__factory, UniswapV3Adapter__factory, UniswapV4Adapter__factory, } from '../typechain/index.js';
3
+ import { AerodromeV2Adapter__factory, IPancakeQuoterV2__factory, UniswapV2Adapter__factory, UniswapV3Adapter__factory, UniswapV4Adapter__factory, } from '../typechain/index.js';
4
4
  import { connectV4Quoter, toAdapterPathKeys } from './getUniswapV4Route.js';
5
5
  import { SWAP_DEADLINE_SECONDS } from './constants.js';
6
6
  import { finalizeRouteQuote } from './finalizeRoute.js';
7
7
  const V2_ROUTER_ABI = [
8
8
  'function getAmountsOut(uint256 amountIn, address[] memory path) external view returns (uint256[] memory amounts)',
9
9
  ];
10
+ const AERO_V2_ROUTER_ABI = [
11
+ 'function getAmountsOut(uint256 amountIn, (address from, address to, bool stable, address factory)[] routes) external view returns (uint256[] amounts)',
12
+ ];
10
13
  function connectV2Router(address, provider) {
11
14
  return new Contract(address, V2_ROUTER_ABI, provider);
12
15
  }
16
+ function connectAeroV2Router(address, provider) {
17
+ return new Contract(address, AERO_V2_ROUTER_ABI, provider);
18
+ }
13
19
  function connectV3Quoter(address, provider) {
14
20
  return IPancakeQuoterV2__factory.connect(address, provider);
15
21
  }
@@ -21,6 +27,12 @@ export function buildVeloraDexConfig(addresses) {
21
27
  routerAddress: addresses.routers.uniswapV2,
22
28
  };
23
29
  }
30
+ if (addresses.adapters.aerodromeV2 && addresses.routers.aerodromeV2) {
31
+ cfg.AerodromeV2 = {
32
+ adapter: addresses.adapters.aerodromeV2,
33
+ routerAddress: addresses.routers.aerodromeV2,
34
+ };
35
+ }
24
36
  if (addresses.adapters.pancakeV2 && addresses.routers.pancakeV2) {
25
37
  cfg.PancakeSwapV2 = {
26
38
  adapter: addresses.adapters.pancakeV2,
@@ -65,6 +77,73 @@ export async function getRouteFromPath({ chainId, addresses, provider, simulator
65
77
  }
66
78
  const dexConfig = buildVeloraDexConfig(addresses);
67
79
  switch (dex) {
80
+ case 'AerodromeV2': {
81
+ if (cachedPath.type !== 'aerodromeV2') {
82
+ throw new Error('Expected Aerodrome V2 path');
83
+ }
84
+ const entry = dexConfig[dex];
85
+ if (!entry) {
86
+ throw new Error(`DEX ${dex} not supported on chainId ${chainId}`);
87
+ }
88
+ const router = connectAeroV2Router(entry.routerAddress, provider);
89
+ const adapter = entry.adapter;
90
+ const [grossAmountToReceive, blockNumber] = await Promise.all([
91
+ router
92
+ .getAmountsOut(amountIn, cachedPath.routes)
93
+ .then((amounts) => amounts.at(-1)),
94
+ provider.getBlockNumber(),
95
+ ]);
96
+ let amountQuoted = grossAmountToReceive;
97
+ let amountToSend = amountIn;
98
+ if (toll.amount === 0n) {
99
+ toll.amount = grossAmountToReceive / TOLL_DIVISOR_20BPS;
100
+ amountQuoted -= toll.amount;
101
+ }
102
+ else {
103
+ amountToSend += toll.amount;
104
+ }
105
+ const deadline = Math.floor(Date.now() / 1000) + SWAP_DEADLINE_SECONDS;
106
+ const buildCallDataForAmount = (amountToReceive) => AerodromeV2Adapter__factory.createInterface().encodeFunctionData('executeSwap', [
107
+ {
108
+ amountToSend,
109
+ amountToReceive,
110
+ routes: cachedPath.routes,
111
+ deadline,
112
+ },
113
+ ]);
114
+ const context = {
115
+ chainId,
116
+ blockNumber,
117
+ controller,
118
+ vault,
119
+ adapter,
120
+ account,
121
+ path: cachedPath.path,
122
+ buildCallDataForAmount,
123
+ simulator,
124
+ prefixTxs,
125
+ };
126
+ const { finalAmountToReceive, callData, effectiveSlippageBps, finalTollAmount, } = await finalizeRouteQuote({
127
+ context,
128
+ amountToSend,
129
+ amountQuoted,
130
+ initialTollAmount: toll.amount,
131
+ maxSlippageE3,
132
+ });
133
+ return {
134
+ adapter,
135
+ data: {
136
+ amountToSend,
137
+ amountToReceive: finalAmountToReceive,
138
+ routes: cachedPath.routes,
139
+ deadline,
140
+ },
141
+ callData,
142
+ toll: { ...toll, amount: finalTollAmount },
143
+ hops: cachedPath.hops,
144
+ effectiveSlippageBps,
145
+ };
146
+ }
68
147
  case 'PancakeSwapV2':
69
148
  case 'UniswapV2': {
70
149
  if (cachedPath.type !== 'v2') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@guru-fund/sdk",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Guru Protocol SDK — quote + transaction builders for on-chain managed funds.",
5
5
  "license": "MIT",
6
6
  "type": "module",