@guru-fund/sdk 0.2.6 → 0.2.7
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 +3 -3
- package/dist/GuruProtocol.d.ts +4 -0
- package/dist/GuruProtocol.js +6 -0
- package/dist/addresses.d.ts +2 -1
- package/dist/addresses.js +36 -2
- package/dist/index.d.ts +2 -1
- package/dist/quotes/quoteClose.d.ts +22 -0
- package/dist/quotes/quoteClose.js +57 -0
- package/dist/quotes/quoteHarvest.js +2 -2
- package/dist/router/helpers.d.ts +1 -0
- package/dist/router/helpers.js +10 -5
- package/dist/router/index.js +4 -4
- package/dist/router/simulation.js +2 -8
- package/dist/router/v4PoolDiscovery.js +53 -4
- package/dist/schemas/index.d.ts +1 -0
- package/dist/schemas/index.js +1 -0
- package/dist/schemas/quoteClose.d.ts +14 -0
- package/dist/schemas/quoteClose.js +7 -0
- package/dist/txBuilders/buildCloseTx.d.ts +14 -0
- package/dist/txBuilders/buildCloseTx.js +15 -0
- package/dist/txBuilders/index.d.ts +2 -0
- package/dist/txBuilders/index.js +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ import { GuruProtocol } from '@guru-fund/sdk'
|
|
|
23
23
|
|
|
24
24
|
const protocol = new GuruProtocol({
|
|
25
25
|
rpcUrl: 'https://mainnet.infura.io/v3/<key>',
|
|
26
|
-
chainId: 1, // mainnet (1)
|
|
26
|
+
chainId: 1, // mainnet (1), base (8453), and Robinhood (4663) are supported
|
|
27
27
|
})
|
|
28
28
|
```
|
|
29
29
|
|
|
@@ -32,7 +32,7 @@ const protocol = new GuruProtocol({
|
|
|
32
32
|
- Builds an internal `JsonRpcProvider(rpcUrl)`. Do not pass a provider in.
|
|
33
33
|
- Resolves the Guru Protocol contract addresses from the SDK's vendored registry. Do
|
|
34
34
|
not pass contracts in.
|
|
35
|
-
- Throws `UnsupportedChainError` for any chain outside `{ 1, 8453 }`.
|
|
35
|
+
- Throws `UnsupportedChainError` for any chain outside `{ 1, 8453, 4663 }`.
|
|
36
36
|
|
|
37
37
|
Optional override slots (`GuruProtocolOptions`): `simulator`, `getSwapFeePercentage`,
|
|
38
38
|
`getPriceUsd1e18`, `veloraEndpoint`, `getPath`. Each has a sensible default —
|
|
@@ -213,7 +213,7 @@ const decoded = quote.decodeLogs(receipt!.logs) ?? {
|
|
|
213
213
|
## Errors
|
|
214
214
|
|
|
215
215
|
- `UnsupportedChainError` — thrown by the constructor on `chainId` outside
|
|
216
|
-
`{ 1, 8453 }`.
|
|
216
|
+
`{ 1, 8453, 4663 }`.
|
|
217
217
|
- `z.ZodError` — thrown by quote methods on malformed inputs (zod schema at
|
|
218
218
|
the SDK boundary parses every quote method's input).
|
|
219
219
|
- `SdkError` — internal errors (e.g., `EVENT_NOT_FOUND` from the receipt
|
package/dist/GuruProtocol.d.ts
CHANGED
|
@@ -3,11 +3,13 @@ import { type GuruProtocolAddresses, type GuruProtocolChainId } from './addresse
|
|
|
3
3
|
import type { GetPriceUsd1e18 } from './helpers/FundDataFetcher';
|
|
4
4
|
import { type QuoteDepositParams, type QuoteDepositResult } from './quotes/quoteDeposit';
|
|
5
5
|
import { type QuoteHarvestParams, type QuoteHarvestResult } from './quotes/quoteHarvest';
|
|
6
|
+
import { type QuoteCloseParams, type QuoteCloseResult } from './quotes/quoteClose';
|
|
6
7
|
import { type QuoteRebalanceParams, type QuoteRebalanceResult } from './quotes/quoteRebalance';
|
|
7
8
|
import { type QuoteTradeParams, type QuoteTradeResult } from './quotes/quoteTrade';
|
|
8
9
|
import { type QuoteWithdrawalParams, type QuoteWithdrawalResult } from './quotes/quoteWithdrawal';
|
|
9
10
|
import { type PathFetcher } from './router/pathCache';
|
|
10
11
|
import type { SwapSimulator } from './router/simulation';
|
|
12
|
+
import buildCloseTx from './txBuilders/buildCloseTx';
|
|
11
13
|
import buildDepositTx from './txBuilders/buildDepositTx';
|
|
12
14
|
import buildHarvestTx from './txBuilders/buildHarvestTx';
|
|
13
15
|
import buildTradeTx from './txBuilders/buildTradeTx';
|
|
@@ -35,8 +37,10 @@ export declare class GuruProtocol {
|
|
|
35
37
|
quoteWithdrawal(params: QuoteWithdrawalParams): Promise<QuoteWithdrawalResult>;
|
|
36
38
|
quoteTrade(params: QuoteTradeParams): Promise<QuoteTradeResult>;
|
|
37
39
|
quoteHarvest(params: QuoteHarvestParams): Promise<QuoteHarvestResult>;
|
|
40
|
+
quoteClose(params: QuoteCloseParams): Promise<QuoteCloseResult>;
|
|
38
41
|
quoteRebalance(params: QuoteRebalanceParams): Promise<QuoteRebalanceResult>;
|
|
39
42
|
static buildDepositTx: typeof buildDepositTx;
|
|
43
|
+
static buildCloseTx: typeof buildCloseTx;
|
|
40
44
|
static buildWithdrawTx: typeof buildWithdrawTx;
|
|
41
45
|
static buildHarvestTx: typeof buildHarvestTx;
|
|
42
46
|
static buildTradeTx: typeof buildTradeTx;
|
package/dist/GuruProtocol.js
CHANGED
|
@@ -2,11 +2,13 @@ import { JsonRpcProvider } from 'ethers';
|
|
|
2
2
|
import { getGuruProtocolAddresses, isSupportedChainId, UnsupportedChainError, } from './addresses.js';
|
|
3
3
|
import quoteDeposit from './quotes/quoteDeposit.js';
|
|
4
4
|
import quoteHarvest from './quotes/quoteHarvest.js';
|
|
5
|
+
import quoteClose from './quotes/quoteClose.js';
|
|
5
6
|
import quoteRebalance from './quotes/quoteRebalance.js';
|
|
6
7
|
import quoteTrade from './quotes/quoteTrade.js';
|
|
7
8
|
import quoteWithdrawal from './quotes/quoteWithdrawal.js';
|
|
8
9
|
import { getPriceUsd1e18 as defaultGetPriceUsd1e18 } from './router/index.js';
|
|
9
10
|
import { getPath as defaultGetPath } from './router/pathCache.js';
|
|
11
|
+
import buildCloseTx from './txBuilders/buildCloseTx.js';
|
|
10
12
|
import buildDepositTx from './txBuilders/buildDepositTx.js';
|
|
11
13
|
import buildHarvestTx from './txBuilders/buildHarvestTx.js';
|
|
12
14
|
import buildTradeTx from './txBuilders/buildTradeTx.js';
|
|
@@ -64,10 +66,14 @@ export class GuruProtocol {
|
|
|
64
66
|
quoteHarvest(params) {
|
|
65
67
|
return quoteHarvest(params, this.routerCtx());
|
|
66
68
|
}
|
|
69
|
+
quoteClose(params) {
|
|
70
|
+
return quoteClose(params, this.routerCtx());
|
|
71
|
+
}
|
|
67
72
|
quoteRebalance(params) {
|
|
68
73
|
return quoteRebalance(params, this.routerCtx());
|
|
69
74
|
}
|
|
70
75
|
static buildDepositTx = buildDepositTx;
|
|
76
|
+
static buildCloseTx = buildCloseTx;
|
|
71
77
|
static buildWithdrawTx = buildWithdrawTx;
|
|
72
78
|
static buildHarvestTx = buildHarvestTx;
|
|
73
79
|
static buildTradeTx = buildTradeTx;
|
package/dist/addresses.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type GuruProtocolChainId = 1 | 8453;
|
|
1
|
+
export type GuruProtocolChainId = 1 | 8453 | 4663;
|
|
2
2
|
type AdapterKey = 'uniswapV2' | 'uniswapV3' | 'uniswapV4' | 'uniswapV4Hook' | 'pancakeV2' | 'pancakeV3' | 'aerodromeV2' | 'aerodromeV3';
|
|
3
3
|
type FactoryKey = AdapterKey | 'aerodromeV3Bis';
|
|
4
4
|
type RouterKey = AdapterKey;
|
|
@@ -26,6 +26,7 @@ export type GuruProtocolAddresses = {
|
|
|
26
26
|
WETH: string;
|
|
27
27
|
USDC: string;
|
|
28
28
|
USDT: string;
|
|
29
|
+
USDG?: string;
|
|
29
30
|
}>;
|
|
30
31
|
readonly migrator?: string;
|
|
31
32
|
};
|
package/dist/addresses.js
CHANGED
|
@@ -95,14 +95,48 @@ const BASE = {
|
|
|
95
95
|
},
|
|
96
96
|
migrator: '0x209656784c8eb405765288c8f447d11c0aa1a3d3',
|
|
97
97
|
};
|
|
98
|
+
const ROBINHOOD = {
|
|
99
|
+
chainId: 4663,
|
|
100
|
+
protocol: '0xe0d99cd8bf9f091713c88ff763d669ad3703876c',
|
|
101
|
+
vaultImplementation: '0x70451b00c42a73ea2d9707ddc7413aff8620be85',
|
|
102
|
+
ledgerImplementation: '0xa8644a5eb1cf74f0d8c7771d3bca9cb5f4edd6a5',
|
|
103
|
+
controllers: {
|
|
104
|
+
fund: '0x36e2de2f1b66ecaa5fda2196abb88ce663616533',
|
|
105
|
+
},
|
|
106
|
+
adapters: {
|
|
107
|
+
uniswapV2: '0xdeb704836165043c172ae80467249ff87429605f',
|
|
108
|
+
uniswapV3: '0x34e1efca367b1686af9bc3eb9a593c02c2b295f6',
|
|
109
|
+
uniswapV4: '0x907e28e12a36a41a9cf01e1f455f4778408da198',
|
|
110
|
+
},
|
|
111
|
+
factories: {
|
|
112
|
+
uniswapV2: '0x8bceaa40b9acdfaedf85adf4ff01f5ad6517937f',
|
|
113
|
+
uniswapV3: '0x1f7d7550b1b028f7571e69a784071f0205fd2efa',
|
|
114
|
+
},
|
|
115
|
+
routers: {
|
|
116
|
+
uniswapV2: '0x89e5db8b5aa49aa85ac63f691524311aeb649eba',
|
|
117
|
+
uniswapV3: '0xcaf681a66d020601342297493863e78c959e5cb2',
|
|
118
|
+
uniswapV4: '0x8876789976decbfcbbbe364623c63652db8c0904',
|
|
119
|
+
},
|
|
120
|
+
quoters: {
|
|
121
|
+
uniswapV3: '0x33e885ed0ec9bf04ecfb19341582aadcb4c8a9e7',
|
|
122
|
+
uniswapV4: '0x8dc178efb8111bb0973dd9d722ebeff267c98f94',
|
|
123
|
+
},
|
|
124
|
+
tokens: {
|
|
125
|
+
WETH: '0x0bd7d308f8e1639fab988df18a8011f41eacad73',
|
|
126
|
+
USDC: '0x5fc5360d0400a0fd4f2af552add042d716f1d168',
|
|
127
|
+
USDT: '0x5fc5360d0400a0fd4f2af552add042d716f1d168',
|
|
128
|
+
USDG: '0x5fc5360d0400a0fd4f2af552add042d716f1d168',
|
|
129
|
+
},
|
|
130
|
+
};
|
|
98
131
|
export const GURU_PROTOCOL_ADDRESSES = {
|
|
99
132
|
1: MAINNET,
|
|
100
133
|
8453: BASE,
|
|
134
|
+
4663: ROBINHOOD,
|
|
101
135
|
};
|
|
102
136
|
export const SUPPORTED_CHAIN_IDS = [
|
|
103
|
-
1, 8453,
|
|
137
|
+
1, 8453, 4663,
|
|
104
138
|
];
|
|
105
|
-
export const isSupportedChainId = (chainId) => chainId === 1 || chainId === 8453;
|
|
139
|
+
export const isSupportedChainId = (chainId) => chainId === 1 || chainId === 8453 || chainId === 4663;
|
|
106
140
|
export function getGuruProtocolAddresses(chainId) {
|
|
107
141
|
if (!isSupportedChainId(chainId)) {
|
|
108
142
|
throw new UnsupportedChainError(chainId);
|
package/dist/index.d.ts
CHANGED
|
@@ -3,11 +3,12 @@ export { GURU_PROTOCOL_ADDRESSES, SUPPORTED_CHAIN_IDS, UnsupportedChainError, ge
|
|
|
3
3
|
export type { GuruProtocolAddresses, GuruProtocolChainId } from './addresses';
|
|
4
4
|
export { GuruProtocol } from './GuruProtocol';
|
|
5
5
|
export type { GuruProtocolOptions } from './GuruProtocol';
|
|
6
|
-
export type { BuildDepositTxParams, BuildHarvestTxParams, BuildTradeTxParams, BuildWithdrawTxParams, } from './txBuilders';
|
|
6
|
+
export type { BuildDepositTxParams, BuildCloseTxParams, BuildHarvestTxParams, BuildTradeTxParams, BuildWithdrawTxParams, } from './txBuilders';
|
|
7
7
|
export type { QuoteDepositParams, QuoteDepositResult, QuoteDepositLogs, } from './quotes/quoteDeposit';
|
|
8
8
|
export type { QuoteWithdrawalParams, QuoteWithdrawalResult, QuoteWithdrawalLogs, } from './quotes/quoteWithdrawal';
|
|
9
9
|
export type { QuoteTradeParams, QuoteTradeResult } from './quotes/quoteTrade';
|
|
10
10
|
export type { QuoteHarvestParams, QuoteHarvestResult, QuoteHarvestLogs, } from './quotes/quoteHarvest';
|
|
11
|
+
export type { QuoteCloseParams, QuoteCloseResult } from './quotes/quoteClose';
|
|
11
12
|
export type { QuoteRebalanceParams, QuoteRebalanceResult, QuoteRebalanceLogs, QuoteRebalanceTrade, QuoteRebalanceLogTrade, QuoteRebalanceEmptyReason, QuoteRebalanceTargetWeight, } from './quotes/quoteRebalance';
|
|
12
13
|
export type { Route, RouteSearchParams, V2Path, V3Path, V3PathHop, CachedPath, } from './router/types';
|
|
13
14
|
export type { PathFetcher, GetPathParams } from './router/pathCache';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type AddressLike, type BytesLike, type TransactionRequest } from 'ethers';
|
|
2
|
+
import { type GuruProtocolChainId } from '../addresses';
|
|
3
|
+
import { type GetPriceUsd1e18 } from '../helpers/FundDataFetcher';
|
|
4
|
+
import { type RouterContext } from '../router';
|
|
5
|
+
export type ExternalCallStruct = {
|
|
6
|
+
adapter: AddressLike;
|
|
7
|
+
callData: BytesLike;
|
|
8
|
+
};
|
|
9
|
+
export interface QuoteCloseParams {
|
|
10
|
+
ledger: string;
|
|
11
|
+
coin: string;
|
|
12
|
+
slippageSettings?: Record<string, bigint>;
|
|
13
|
+
}
|
|
14
|
+
export interface QuoteCloseContext extends RouterContext {
|
|
15
|
+
chainId: GuruProtocolChainId;
|
|
16
|
+
getPriceUsd1e18: GetPriceUsd1e18;
|
|
17
|
+
}
|
|
18
|
+
export interface QuoteCloseResult {
|
|
19
|
+
extCalls: ExternalCallStruct[];
|
|
20
|
+
txData: TransactionRequest;
|
|
21
|
+
}
|
|
22
|
+
export default function quoteClose(params: QuoteCloseParams, ctx: QuoteCloseContext): Promise<QuoteCloseResult>;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { ZeroAddress, } from 'ethers';
|
|
2
|
+
import { getGuruProtocolAddresses, } from '../addresses.js';
|
|
3
|
+
import compareAddresses from '../helpers/compareAddresses.js';
|
|
4
|
+
import FundDataFetcher from '../helpers/FundDataFetcher.js';
|
|
5
|
+
import { getRouteOut } from '../router/index.js';
|
|
6
|
+
import { stablecoinAddresses } from '../router/helpers.js';
|
|
7
|
+
import { quoteCloseSchema } from '../schemas/quoteClose.js';
|
|
8
|
+
import buildCloseTx from '../txBuilders/buildCloseTx.js';
|
|
9
|
+
import { FundLedger__factory } from '../typechain/index.js';
|
|
10
|
+
const slippageE2For = (settings, token) => {
|
|
11
|
+
const slippage = settings?.[token.toLowerCase()];
|
|
12
|
+
return slippage == null ? undefined : Number(slippage / 10n);
|
|
13
|
+
};
|
|
14
|
+
export default async function quoteClose(params, ctx) {
|
|
15
|
+
const parsed = quoteCloseSchema.parse(params);
|
|
16
|
+
const addresses = getGuruProtocolAddresses(ctx.chainId);
|
|
17
|
+
const isStablecoin = stablecoinAddresses(addresses).some((stable) => compareAddresses(parsed.coin, stable));
|
|
18
|
+
if (!isStablecoin) {
|
|
19
|
+
throw new Error(`[@guru-fund/sdk] quoteClose: coin ${parsed.coin} is not a supported stablecoin on chainId ${ctx.chainId}`);
|
|
20
|
+
}
|
|
21
|
+
const provider = ctx.provider;
|
|
22
|
+
const ledger = FundLedger__factory.connect(parsed.ledger, provider);
|
|
23
|
+
const fetcher = new FundDataFetcher({
|
|
24
|
+
chainId: ctx.chainId,
|
|
25
|
+
provider,
|
|
26
|
+
getPriceUsd1e18: ctx.getPriceUsd1e18,
|
|
27
|
+
});
|
|
28
|
+
const [fundData, vault, manager, controllerAddress] = await Promise.all([
|
|
29
|
+
fetcher.fetchFundData(ledger),
|
|
30
|
+
ledger.vault(),
|
|
31
|
+
ledger.manager(),
|
|
32
|
+
ledger.controller(),
|
|
33
|
+
]);
|
|
34
|
+
const extCalls = await Promise.all(fundData.assets.map(async (asset) => {
|
|
35
|
+
if (compareAddresses(asset.token.address, parsed.coin)) {
|
|
36
|
+
return { adapter: ZeroAddress, callData: '0x' };
|
|
37
|
+
}
|
|
38
|
+
const route = await getRouteOut({
|
|
39
|
+
chainId: ctx.chainId,
|
|
40
|
+
tokenIn: asset.token.address,
|
|
41
|
+
tokenOut: parsed.coin,
|
|
42
|
+
amountIn: asset.balance,
|
|
43
|
+
slippageE2: slippageE2For(parsed.slippageSettings, asset.token.address),
|
|
44
|
+
account: vault,
|
|
45
|
+
vault,
|
|
46
|
+
}, ctx);
|
|
47
|
+
return { adapter: route.adapter, callData: route.callData };
|
|
48
|
+
}));
|
|
49
|
+
const txData = buildCloseTx({
|
|
50
|
+
controller: controllerAddress,
|
|
51
|
+
ledger: parsed.ledger,
|
|
52
|
+
coin: parsed.coin,
|
|
53
|
+
extCalls,
|
|
54
|
+
from: manager,
|
|
55
|
+
});
|
|
56
|
+
return { extCalls, txData };
|
|
57
|
+
}
|
|
@@ -4,6 +4,7 @@ import { GURU_TOKEN_MAINNET, MANAGEMENT_FEE_COOLDOWN_DAYS, MANAGEMENT_FEE_ELIGIB
|
|
|
4
4
|
import compareAddresses from '../helpers/compareAddresses.js';
|
|
5
5
|
import FundDataFetcher, { WEIGHT_DENOMINATOR, } from '../helpers/FundDataFetcher.js';
|
|
6
6
|
import { getRouteOut } from '../router/index.js';
|
|
7
|
+
import { stablecoinAddresses } from '../router/helpers.js';
|
|
7
8
|
import { quoteHarvestSchema } from '../schemas/quoteHarvest.js';
|
|
8
9
|
import buildHarvestTx from '../txBuilders/buildHarvestTx.js';
|
|
9
10
|
import { FundLedger__factory, HarvestController__factory } from '../typechain/index.js';
|
|
@@ -17,8 +18,7 @@ const slippageE2For = (settings, token) => {
|
|
|
17
18
|
export default async function quoteHarvest(params, ctx) {
|
|
18
19
|
const parsed = quoteHarvestSchema.parse(params);
|
|
19
20
|
const addresses = getGuruProtocolAddresses(ctx.chainId);
|
|
20
|
-
const isStablecoin = compareAddresses(parsed.coin,
|
|
21
|
-
compareAddresses(parsed.coin, addresses.tokens.USDT);
|
|
21
|
+
const isStablecoin = stablecoinAddresses(addresses).some((stable) => compareAddresses(parsed.coin, stable));
|
|
22
22
|
if (!isStablecoin) {
|
|
23
23
|
throw new Error(`[@guru-fund/sdk] quoteHarvest: coin ${parsed.coin} is not a supported stablecoin on chainId ${ctx.chainId}`);
|
|
24
24
|
}
|
package/dist/router/helpers.d.ts
CHANGED
|
@@ -8,4 +8,5 @@ export interface BaseTollContext {
|
|
|
8
8
|
};
|
|
9
9
|
swapAmountIn: bigint;
|
|
10
10
|
}
|
|
11
|
+
export declare function stablecoinAddresses(addresses: GuruProtocolAddresses): string[];
|
|
11
12
|
export declare function resolveBaseToll(addresses: GuruProtocolAddresses, tokenIn: string, tokenOut: string, amountIn: bigint): BaseTollContext;
|
package/dist/router/helpers.js
CHANGED
|
@@ -5,12 +5,17 @@ export function withSlippageTolerance(amount, slippage) {
|
|
|
5
5
|
const tolerance = (amount * slippage) / PERCENTAGE_DENOMINATOR;
|
|
6
6
|
return amount - tolerance;
|
|
7
7
|
}
|
|
8
|
+
export function stablecoinAddresses(addresses) {
|
|
9
|
+
return [
|
|
10
|
+
addresses.tokens.USDC,
|
|
11
|
+
addresses.tokens.USDT,
|
|
12
|
+
addresses.tokens.USDG,
|
|
13
|
+
].filter((token) => Boolean(token));
|
|
14
|
+
}
|
|
8
15
|
export function resolveBaseToll(addresses, tokenIn, tokenOut, amountIn) {
|
|
9
|
-
const tollableTokens =
|
|
10
|
-
addresses.tokens.
|
|
11
|
-
|
|
12
|
-
addresses.tokens.WETH.toLowerCase(),
|
|
13
|
-
];
|
|
16
|
+
const tollableTokens = stablecoinAddresses(addresses)
|
|
17
|
+
.concat(addresses.tokens.WETH)
|
|
18
|
+
.map((token) => token.toLowerCase());
|
|
14
19
|
const tollIn = tollableTokens.some((token) => compareAddresses(token, tokenIn));
|
|
15
20
|
const tollOut = !tollIn &&
|
|
16
21
|
tollableTokens.some((token) => compareAddresses(token, tokenOut));
|
package/dist/router/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import { Token } from '../helpers/Token.js';
|
|
|
5
5
|
import { getFallbackRouteIn, getFallbackRouteOut, } from './getFallbackRoutes.js';
|
|
6
6
|
import getUniswapV4Route, { connectV4Quoter, toAdapterPathKeys, } from './getUniswapV4Route.js';
|
|
7
7
|
import getVeloraRoute from './getVeloraRoute.js';
|
|
8
|
+
import { stablecoinAddresses } from './helpers.js';
|
|
8
9
|
import PoolHelper from './poolHelper.js';
|
|
9
10
|
import { discoverV4Paths } from './v4PoolDiscovery.js';
|
|
10
11
|
const AERO_V3_FACTORY_ABI = [
|
|
@@ -92,8 +93,7 @@ export async function getRouteOut(params, ctx) {
|
|
|
92
93
|
}
|
|
93
94
|
export async function getPriceUsd1e18(token, ctx) {
|
|
94
95
|
const addresses = getGuruProtocolAddresses(ctx.chainId);
|
|
95
|
-
if (compareAddresses(token,
|
|
96
|
-
compareAddresses(token, addresses.tokens.USDT)) {
|
|
96
|
+
if (stablecoinAddresses(addresses).some((stable) => compareAddresses(token, stable))) {
|
|
97
97
|
return 10n ** 18n;
|
|
98
98
|
}
|
|
99
99
|
const poolHelper = new PoolHelper({
|
|
@@ -101,7 +101,7 @@ export async function getPriceUsd1e18(token, ctx) {
|
|
|
101
101
|
provider: ctx.provider,
|
|
102
102
|
getSwapFeePercentage: ctx.getSwapFeePercentage,
|
|
103
103
|
});
|
|
104
|
-
const stable = addresses.tokens.USDC;
|
|
104
|
+
const stable = addresses.tokens.USDG ?? addresses.tokens.USDC;
|
|
105
105
|
const { decimals: stableDecimals } = await new Token(stable, ctx.provider)
|
|
106
106
|
.metadata()
|
|
107
107
|
.catch(() => ({ decimals: 6 }));
|
|
@@ -309,7 +309,7 @@ async function _priceViaV4Pools(token, oneToken, getWethUsd, ctx) {
|
|
|
309
309
|
}
|
|
310
310
|
return best > 0n ? best : null;
|
|
311
311
|
};
|
|
312
|
-
const inUsdc = await quoteVia(addresses.tokens.USDC);
|
|
312
|
+
const inUsdc = await quoteVia(addresses.tokens.USDG ?? addresses.tokens.USDC);
|
|
313
313
|
if (inUsdc !== null) {
|
|
314
314
|
return inUsdc * 10n ** 12n;
|
|
315
315
|
}
|
|
@@ -45,13 +45,7 @@ export async function findMaxPassingAmountToReceive({ chainId, blockNumber, cont
|
|
|
45
45
|
.map((result, index) => (result.success ? index : -1))
|
|
46
46
|
.filter((index) => index !== -1);
|
|
47
47
|
if (successIndices.length === 0) {
|
|
48
|
-
|
|
49
|
-
const fallback = withSlippageTolerance(amountQuoted, maxSlippageE3);
|
|
50
|
-
console.warn(`[findMax] All ${BUNDLE_SIMULATION_CANDIDATES} simulation candidates failed. ` +
|
|
51
|
-
`Falling back to caller-provided max slippage (${Number(maxSlippageE3) / 1000}%).`, { amountQuoted, fallback, maxSlippageE3 });
|
|
52
|
-
return fallback;
|
|
53
|
-
}
|
|
54
|
-
console.warn('Found no successful simulations with correct slippage, returning initial slippage', {
|
|
48
|
+
console.warn('Found no successful simulations for executable route quote', {
|
|
55
49
|
chainId,
|
|
56
50
|
blockNumber,
|
|
57
51
|
controller,
|
|
@@ -62,7 +56,7 @@ export async function findMaxPassingAmountToReceive({ chainId, blockNumber, cont
|
|
|
62
56
|
callData: encodeVaultExecute(adapter, buildCallDataForAmount(high)),
|
|
63
57
|
path,
|
|
64
58
|
});
|
|
65
|
-
|
|
59
|
+
throw new Error('NO_EXECUTABLE_ROUTE_FOUND');
|
|
66
60
|
}
|
|
67
61
|
const [bestIndex, secondBestIndex] = successIndices;
|
|
68
62
|
const targetIndex = secondBestIndex ?? bestIndex;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AbiCoder, keccak256 } from 'ethers';
|
|
1
|
+
import { AbiCoder, keccak256, zeroPadValue, } from 'ethers';
|
|
2
2
|
import { getGuruProtocolAddresses, } from '../addresses.js';
|
|
3
3
|
import compareAddresses from '../helpers/compareAddresses.js';
|
|
4
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';
|
|
@@ -13,6 +13,11 @@ const V4_CHAIN_CONFIG = {
|
|
|
13
13
|
poolManager: '0x498581ff718922c3f8e6a244956af099b2652b2b',
|
|
14
14
|
deployBlock: 25_000_000,
|
|
15
15
|
},
|
|
16
|
+
4663: {
|
|
17
|
+
dexscreenerSlug: 'robinhood',
|
|
18
|
+
poolManager: '0x8366a39cc670b4001a1121b8f6a443a643e40951',
|
|
19
|
+
deployBlock: 0,
|
|
20
|
+
},
|
|
16
21
|
};
|
|
17
22
|
const POOL_INITIALIZE_TOPIC = '0xdd466e674ea557f56295e2d0218a125ea4b4f0f6f3307b95f85e6110838d6438';
|
|
18
23
|
export function computeV4PoolId(key) {
|
|
@@ -73,6 +78,19 @@ async function resolvePoolKey(chainId, poolId, provider) {
|
|
|
73
78
|
const log = logs[0];
|
|
74
79
|
if (!log)
|
|
75
80
|
return null;
|
|
81
|
+
const key = poolKeyFromInitializeLog(log);
|
|
82
|
+
if (!key)
|
|
83
|
+
return null;
|
|
84
|
+
if (computeV4PoolId(key).toLowerCase() !== poolId.toLowerCase()) {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
poolKeyCache.set(cacheKey, key);
|
|
88
|
+
return key;
|
|
89
|
+
}
|
|
90
|
+
function poolKeyFromInitializeLog(log) {
|
|
91
|
+
const poolId = log.topics[1];
|
|
92
|
+
if (!poolId || !log.topics[2] || !log.topics[3])
|
|
93
|
+
return null;
|
|
76
94
|
const [fee, tickSpacing, hooks] = AbiCoder.defaultAbiCoder().decode(['uint24', 'int24', 'address', 'uint160', 'int24'], log.data);
|
|
77
95
|
const key = {
|
|
78
96
|
currency0: '0x' + log.topics[2].slice(26),
|
|
@@ -84,7 +102,6 @@ async function resolvePoolKey(chainId, poolId, provider) {
|
|
|
84
102
|
if (computeV4PoolId(key).toLowerCase() !== poolId.toLowerCase()) {
|
|
85
103
|
return null;
|
|
86
104
|
}
|
|
87
|
-
poolKeyCache.set(cacheKey, key);
|
|
88
105
|
return key;
|
|
89
106
|
}
|
|
90
107
|
const discoveryCache = new Map();
|
|
@@ -112,7 +129,13 @@ export async function discoverV4Paths(chainId, tokenIn, tokenOut, provider, endp
|
|
|
112
129
|
async function discoverDirectV4Paths(chainId, tokenIn, tokenOut, provider, endpoint, cachedPaths) {
|
|
113
130
|
const config = V4_CHAIN_CONFIG[chainId];
|
|
114
131
|
const { tokens } = getGuruProtocolAddresses(chainId);
|
|
115
|
-
const majors = [
|
|
132
|
+
const majors = [
|
|
133
|
+
tokens.WETH,
|
|
134
|
+
tokens.USDC,
|
|
135
|
+
tokens.USDT,
|
|
136
|
+
tokens.USDG,
|
|
137
|
+
V4_ZERO_ADDRESS,
|
|
138
|
+
].filter((token) => Boolean(token));
|
|
116
139
|
const isMajor = (token) => majors.some((major) => compareAddresses(major, token));
|
|
117
140
|
const queryOrder = isMajor(tokenIn) ? [tokenOut, tokenIn] : [tokenIn, tokenOut];
|
|
118
141
|
let poolIds = [];
|
|
@@ -127,7 +150,12 @@ async function discoverDirectV4Paths(chainId, tokenIn, tokenOut, provider, endpo
|
|
|
127
150
|
break;
|
|
128
151
|
}
|
|
129
152
|
const keys = await Promise.all(poolIds.map((poolId) => resolvePoolKey(chainId, poolId, provider)));
|
|
130
|
-
const
|
|
153
|
+
const resolvedKeys = keys.filter((key) => key !== null);
|
|
154
|
+
const onchainKeys = resolvedKeys.length > 0
|
|
155
|
+
? []
|
|
156
|
+
: await discoverOnchainDirectV4PoolKeys(chainId, tokenIn, tokenOut, provider);
|
|
157
|
+
const paths = resolvedKeys
|
|
158
|
+
.concat(onchainKeys)
|
|
131
159
|
.filter((key) => key !== null)
|
|
132
160
|
.map((key) => [
|
|
133
161
|
{
|
|
@@ -141,6 +169,27 @@ async function discoverDirectV4Paths(chainId, tokenIn, tokenOut, provider, endpo
|
|
|
141
169
|
]);
|
|
142
170
|
return paths;
|
|
143
171
|
}
|
|
172
|
+
async function discoverOnchainDirectV4PoolKeys(chainId, tokenIn, tokenOut, provider) {
|
|
173
|
+
const config = V4_CHAIN_CONFIG[chainId];
|
|
174
|
+
const [currency0, currency1] = tokenIn.toLowerCase() < tokenOut.toLowerCase()
|
|
175
|
+
? [tokenIn, tokenOut]
|
|
176
|
+
: [tokenOut, tokenIn];
|
|
177
|
+
const logs = await provider.getLogs({
|
|
178
|
+
address: config.poolManager,
|
|
179
|
+
topics: [
|
|
180
|
+
POOL_INITIALIZE_TOPIC,
|
|
181
|
+
null,
|
|
182
|
+
zeroPadValue(currency0, 32),
|
|
183
|
+
zeroPadValue(currency1, 32),
|
|
184
|
+
],
|
|
185
|
+
fromBlock: config.deployBlock,
|
|
186
|
+
toBlock: 'latest',
|
|
187
|
+
});
|
|
188
|
+
return logs
|
|
189
|
+
.map(poolKeyFromInitializeLog)
|
|
190
|
+
.filter((key) => key !== null)
|
|
191
|
+
.sort((a, b) => a.fee - b.fee);
|
|
192
|
+
}
|
|
144
193
|
export function _clearV4DiscoveryCache() {
|
|
145
194
|
discoveryCache.clear();
|
|
146
195
|
poolKeyCache.clear();
|
package/dist/schemas/index.d.ts
CHANGED
|
@@ -3,4 +3,5 @@ export { quoteDepositSchema } from './quoteDeposit';
|
|
|
3
3
|
export { quoteWithdrawalSchema } from './quoteWithdrawal';
|
|
4
4
|
export { quoteTradeSchema } from './quoteTrade';
|
|
5
5
|
export { quoteHarvestSchema } from './quoteHarvest';
|
|
6
|
+
export { quoteCloseSchema } from './quoteClose';
|
|
6
7
|
export { quoteRebalanceSchema } from './quoteRebalance';
|
package/dist/schemas/index.js
CHANGED
|
@@ -3,4 +3,5 @@ export { quoteDepositSchema } from './quoteDeposit.js';
|
|
|
3
3
|
export { quoteWithdrawalSchema } from './quoteWithdrawal.js';
|
|
4
4
|
export { quoteTradeSchema } from './quoteTrade.js';
|
|
5
5
|
export { quoteHarvestSchema } from './quoteHarvest.js';
|
|
6
|
+
export { quoteCloseSchema } from './quoteClose.js';
|
|
6
7
|
export { quoteRebalanceSchema } from './quoteRebalance.js';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const quoteCloseSchema: z.ZodObject<{
|
|
3
|
+
ledger: z.ZodString;
|
|
4
|
+
coin: z.ZodString;
|
|
5
|
+
slippageSettings: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodUnion<[z.ZodBigInt, z.ZodEffects<z.ZodNumber, bigint, number>]>, z.ZodEffects<z.ZodString, bigint, string>]>>>;
|
|
6
|
+
}, "strip", z.ZodTypeAny, {
|
|
7
|
+
ledger: string;
|
|
8
|
+
coin: string;
|
|
9
|
+
slippageSettings?: Record<string, bigint> | undefined;
|
|
10
|
+
}, {
|
|
11
|
+
ledger: string;
|
|
12
|
+
coin: string;
|
|
13
|
+
slippageSettings?: Record<string, string | number | bigint> | undefined;
|
|
14
|
+
}>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AddressLike, BytesLike, TransactionRequest } from 'ethers';
|
|
2
|
+
type ExternalCallStruct = {
|
|
3
|
+
adapter: AddressLike;
|
|
4
|
+
callData: BytesLike;
|
|
5
|
+
};
|
|
6
|
+
export interface BuildCloseTxParams {
|
|
7
|
+
controller: string;
|
|
8
|
+
ledger: string;
|
|
9
|
+
coin: string;
|
|
10
|
+
extCalls: ExternalCallStruct[];
|
|
11
|
+
from: string;
|
|
12
|
+
}
|
|
13
|
+
export default function buildCloseTx(params: BuildCloseTxParams): TransactionRequest;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { FundController__factory } from '../typechain/index.js';
|
|
2
|
+
export default function buildCloseTx(params) {
|
|
3
|
+
const data = FundController__factory.createInterface().encodeFunctionData('closeFund', [
|
|
4
|
+
{
|
|
5
|
+
ledger: params.ledger,
|
|
6
|
+
coin: params.coin,
|
|
7
|
+
extCalls: params.extCalls,
|
|
8
|
+
},
|
|
9
|
+
]);
|
|
10
|
+
return {
|
|
11
|
+
to: params.controller,
|
|
12
|
+
from: params.from,
|
|
13
|
+
data,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { default as buildDepositTx } from './buildDepositTx';
|
|
2
2
|
export type { BuildDepositTxParams } from './buildDepositTx';
|
|
3
|
+
export { default as buildCloseTx } from './buildCloseTx';
|
|
4
|
+
export type { BuildCloseTxParams } from './buildCloseTx';
|
|
3
5
|
export { default as buildWithdrawTx } from './buildWithdrawTx';
|
|
4
6
|
export type { BuildWithdrawTxParams } from './buildWithdrawTx';
|
|
5
7
|
export { default as buildHarvestTx } from './buildHarvestTx';
|
package/dist/txBuilders/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { default as buildDepositTx } from './buildDepositTx.js';
|
|
2
|
+
export { default as buildCloseTx } from './buildCloseTx.js';
|
|
2
3
|
export { default as buildWithdrawTx } from './buildWithdrawTx.js';
|
|
3
4
|
export { default as buildHarvestTx } from './buildHarvestTx.js';
|
|
4
5
|
export { default as buildTradeTx } from './buildTradeTx.js';
|