@sherwoodagent/cli 0.88.2 → 0.89.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/dist/{abis-WJQ6IVYV.js → abis-2VBXBA7Y.js} +16 -2
- package/dist/{agent-FCGZL4GF.js → agent-KMLNSKBS.js} +11 -11
- package/dist/{chat-AKLYUJZV.js → chat-JW5Z3JRE.js} +13 -13
- package/dist/{chunk-6SAE2VDK.js → chunk-6IC2NRED.js} +2 -2
- package/dist/{chunk-HMFPP2PE.js → chunk-77MBGRE5.js} +52 -24
- package/dist/chunk-77MBGRE5.js.map +1 -0
- package/dist/{chunk-G5MXVAFC.js → chunk-D3GTHAJS.js} +5 -5
- package/dist/chunk-G5FOHSQW.js +338 -0
- package/dist/chunk-G5FOHSQW.js.map +1 -0
- package/dist/chunk-GAQMHH44.js +18 -0
- package/dist/chunk-GAQMHH44.js.map +1 -0
- package/dist/{chunk-FWQESFFM.js → chunk-GYGSKMZE.js} +91 -8
- package/dist/chunk-GYGSKMZE.js.map +1 -0
- package/dist/{chunk-J2IZWAEW.js → chunk-JCL2DEH3.js} +2048 -2
- package/dist/chunk-JCL2DEH3.js.map +1 -0
- package/dist/{chunk-BH3VTJ4F.js → chunk-JKSDCCVL.js} +6 -6
- package/dist/{chunk-EEI6FRTE.js → chunk-JLOROS5V.js} +3 -3
- package/dist/{chunk-6D3FNU75.js → chunk-JRGYI34A.js} +5 -5
- package/dist/chunk-KZGY7NT7.js +209 -0
- package/dist/chunk-KZGY7NT7.js.map +1 -0
- package/dist/{chunk-G3FUEM5N.js → chunk-LIW6K4OJ.js} +2 -2
- package/dist/{chunk-4ITTHKRX.js → chunk-P4LFNKSX.js} +5 -5
- package/dist/{chunk-3TZIOAPH.js → chunk-QUAVAJWE.js} +13 -2
- package/dist/chunk-QUAVAJWE.js.map +1 -0
- package/dist/chunk-QVXKYT2N.js +489 -0
- package/dist/chunk-QVXKYT2N.js.map +1 -0
- package/dist/chunk-UPRFO4YU.js +458 -0
- package/dist/chunk-UPRFO4YU.js.map +1 -0
- package/dist/{chunk-QFGZQYZA.js → chunk-WDPA2BYK.js} +1024 -87
- package/dist/chunk-WDPA2BYK.js.map +1 -0
- package/dist/{chunk-CWGP4VXZ.js → chunk-YIN6R66K.js} +7 -7
- package/dist/{chunk-D4BSBW3Q.js → chunk-Z53JZORT.js} +3 -3
- package/dist/{chunk-SCQAKMMI.js → chunk-ZPOPWFSP.js} +5 -5
- package/dist/{client-PYFE6YQR.js → client-DA434B67.js} +4 -4
- package/dist/{config-ZGFS4I7K.js → config-UZ2GIXAO.js} +6 -2
- package/dist/{eas-B4HR2HXX.js → eas-ZH7BDEOK.js} +7 -7
- package/dist/{governor-QFBN6RYS.js → governor-WHT2V2EU.js} +7 -7
- package/dist/identity-TRPUQEQK.js +19 -0
- package/dist/index.js +7758 -5862
- package/dist/index.js.map +1 -1
- package/dist/launchpad-3N4ZFL6J.js +26 -0
- package/dist/lighter-perp-template-VC4TB7AM.js +92 -0
- package/dist/lighter-preflight-GH3JKLR6.js +149 -0
- package/dist/lighter-preflight-GH3JKLR6.js.map +1 -0
- package/dist/{network-7445KSCF.js → network-EZ5X2BF7.js} +3 -3
- package/dist/network-EZ5X2BF7.js.map +1 -0
- package/dist/{price-EXZDYVDD.js → price-RX5J7GTO.js} +9 -7
- package/dist/{price-EXZDYVDD.js.map → price-RX5J7GTO.js.map} +1 -1
- package/dist/{providers-6UZKDFQD.js → providers-XEEFKITN.js} +5 -5
- package/dist/{research-T7A27OMB.js → research-PYMQ5VKH.js} +9 -9
- package/dist/{session-45NQAHFI.js → session-DE47TUEW.js} +15 -15
- package/dist/{trade-ZOVM433K.js → trade-3VMAQ75D.js} +20 -18
- package/dist/{trade-ZOVM433K.js.map → trade-3VMAQ75D.js.map} +1 -1
- package/dist/{vault-E7XD6DLD.js → vault-PXGG2E3K.js} +9 -9
- package/dist/vault-PXGG2E3K.js.map +1 -0
- package/dist/{xmtp-72IRK7JL.js → xmtp-5PTIIVAI.js} +7 -7
- package/package.json +1 -1
- package/dist/chunk-3TZIOAPH.js.map +0 -1
- package/dist/chunk-FWQESFFM.js.map +0 -1
- package/dist/chunk-HMFPP2PE.js.map +0 -1
- package/dist/chunk-J2IZWAEW.js.map +0 -1
- package/dist/chunk-QFGZQYZA.js.map +0 -1
- package/dist/identity-I2BG4IGT.js +0 -18
- /package/dist/{abis-WJQ6IVYV.js.map → abis-2VBXBA7Y.js.map} +0 -0
- /package/dist/{agent-FCGZL4GF.js.map → agent-KMLNSKBS.js.map} +0 -0
- /package/dist/{chat-AKLYUJZV.js.map → chat-JW5Z3JRE.js.map} +0 -0
- /package/dist/{chunk-6SAE2VDK.js.map → chunk-6IC2NRED.js.map} +0 -0
- /package/dist/{chunk-G5MXVAFC.js.map → chunk-D3GTHAJS.js.map} +0 -0
- /package/dist/{chunk-BH3VTJ4F.js.map → chunk-JKSDCCVL.js.map} +0 -0
- /package/dist/{chunk-EEI6FRTE.js.map → chunk-JLOROS5V.js.map} +0 -0
- /package/dist/{chunk-6D3FNU75.js.map → chunk-JRGYI34A.js.map} +0 -0
- /package/dist/{chunk-G3FUEM5N.js.map → chunk-LIW6K4OJ.js.map} +0 -0
- /package/dist/{chunk-4ITTHKRX.js.map → chunk-P4LFNKSX.js.map} +0 -0
- /package/dist/{chunk-CWGP4VXZ.js.map → chunk-YIN6R66K.js.map} +0 -0
- /package/dist/{chunk-D4BSBW3Q.js.map → chunk-Z53JZORT.js.map} +0 -0
- /package/dist/{chunk-SCQAKMMI.js.map → chunk-ZPOPWFSP.js.map} +0 -0
- /package/dist/{client-PYFE6YQR.js.map → client-DA434B67.js.map} +0 -0
- /package/dist/{config-ZGFS4I7K.js.map → config-UZ2GIXAO.js.map} +0 -0
- /package/dist/{eas-B4HR2HXX.js.map → eas-ZH7BDEOK.js.map} +0 -0
- /package/dist/{governor-QFBN6RYS.js.map → governor-WHT2V2EU.js.map} +0 -0
- /package/dist/{identity-I2BG4IGT.js.map → identity-TRPUQEQK.js.map} +0 -0
- /package/dist/{network-7445KSCF.js.map → launchpad-3N4ZFL6J.js.map} +0 -0
- /package/dist/{vault-E7XD6DLD.js.map → lighter-perp-template-VC4TB7AM.js.map} +0 -0
- /package/dist/{providers-6UZKDFQD.js.map → providers-XEEFKITN.js.map} +0 -0
- /package/dist/{research-T7A27OMB.js.map → research-PYMQ5VKH.js.map} +0 -0
- /package/dist/{session-45NQAHFI.js.map → session-DE47TUEW.js.map} +0 -0
- /package/dist/{xmtp-72IRK7JL.js.map → xmtp-5PTIIVAI.js.map} +0 -0
|
@@ -1,33 +1,49 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LIGHTER_USDG,
|
|
3
|
+
buildExecuteCalls,
|
|
4
|
+
buildInitData,
|
|
5
|
+
buildSettleCalls,
|
|
6
|
+
parseLighterTemplateFlags,
|
|
7
|
+
usdgToTicks
|
|
8
|
+
} from "./chunk-G5FOHSQW.js";
|
|
9
|
+
import {
|
|
10
|
+
buildExecuteCalls as buildExecuteCalls2,
|
|
11
|
+
buildInitData as buildInitData2,
|
|
12
|
+
buildLaunchpadInitParams,
|
|
13
|
+
buildSettleCalls as buildSettleCalls2
|
|
14
|
+
} from "./chunk-QVXKYT2N.js";
|
|
1
15
|
import {
|
|
2
16
|
AERODROME,
|
|
3
17
|
CHAINLINK,
|
|
4
18
|
MOONWELL,
|
|
5
19
|
ROBINHOOD_STOCK_ROUTES,
|
|
20
|
+
STRATEGY_VENUES,
|
|
6
21
|
SYNTHRA,
|
|
7
22
|
TOKENS,
|
|
8
23
|
UNISWAP,
|
|
9
24
|
VENICE
|
|
10
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-GYGSKMZE.js";
|
|
11
26
|
import {
|
|
12
27
|
getPublicClient
|
|
13
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-Z53JZORT.js";
|
|
14
29
|
import {
|
|
15
30
|
getNetwork
|
|
16
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-LIW6K4OJ.js";
|
|
17
32
|
import {
|
|
18
33
|
BASE_STRATEGY_ABI,
|
|
34
|
+
CONCENTRATED_LIQUIDITY_STRATEGY_ABI,
|
|
19
35
|
ERC20_ABI,
|
|
20
36
|
UNISWAP_QUOTER_V2_ABI
|
|
21
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-JCL2DEH3.js";
|
|
22
38
|
|
|
23
39
|
// src/lib/swap-router.ts
|
|
24
|
-
import { encodeFunctionData as
|
|
40
|
+
import { encodeFunctionData as encodeFunctionData11, decodeFunctionResult } from "viem";
|
|
25
41
|
|
|
26
42
|
// src/lib/template-encoder.ts
|
|
27
43
|
import {
|
|
28
|
-
parseUnits,
|
|
29
|
-
isAddress,
|
|
30
|
-
encodeAbiParameters as
|
|
44
|
+
parseUnits as parseUnits2,
|
|
45
|
+
isAddress as isAddress2,
|
|
46
|
+
encodeAbiParameters as encodeAbiParameters12,
|
|
31
47
|
concat as concat2,
|
|
32
48
|
numberToHex
|
|
33
49
|
} from "viem";
|
|
@@ -35,7 +51,7 @@ import chalk from "chalk";
|
|
|
35
51
|
|
|
36
52
|
// src/strategies/moonwell-supply-template.ts
|
|
37
53
|
import { encodeAbiParameters, encodeFunctionData } from "viem";
|
|
38
|
-
function
|
|
54
|
+
function buildInitData3(underlying, mToken, supplyAmount, minRedeemAmount, isNativeEthMarket) {
|
|
39
55
|
return encodeAbiParameters(
|
|
40
56
|
[
|
|
41
57
|
{ type: "address" },
|
|
@@ -47,7 +63,7 @@ function buildInitData(underlying, mToken, supplyAmount, minRedeemAmount, isNati
|
|
|
47
63
|
[underlying, mToken, supplyAmount, minRedeemAmount, isNativeEthMarket]
|
|
48
64
|
);
|
|
49
65
|
}
|
|
50
|
-
function
|
|
66
|
+
function buildExecuteCalls3(clone, underlying, supplyAmount) {
|
|
51
67
|
return [
|
|
52
68
|
{
|
|
53
69
|
target: underlying,
|
|
@@ -68,7 +84,7 @@ function buildExecuteCalls(clone, underlying, supplyAmount) {
|
|
|
68
84
|
}
|
|
69
85
|
];
|
|
70
86
|
}
|
|
71
|
-
function
|
|
87
|
+
function buildSettleCalls3(clone) {
|
|
72
88
|
return [
|
|
73
89
|
{
|
|
74
90
|
target: clone,
|
|
@@ -101,10 +117,10 @@ var INIT_PARAMS_TYPES = [
|
|
|
101
117
|
]
|
|
102
118
|
}
|
|
103
119
|
];
|
|
104
|
-
function
|
|
120
|
+
function buildInitData4(params) {
|
|
105
121
|
return encodeAbiParameters2(INIT_PARAMS_TYPES, [params]);
|
|
106
122
|
}
|
|
107
|
-
function
|
|
123
|
+
function buildExecuteCalls4(clone, asset, assetAmount) {
|
|
108
124
|
return [
|
|
109
125
|
{
|
|
110
126
|
target: asset,
|
|
@@ -125,7 +141,7 @@ function buildExecuteCalls2(clone, asset, assetAmount) {
|
|
|
125
141
|
}
|
|
126
142
|
];
|
|
127
143
|
}
|
|
128
|
-
function
|
|
144
|
+
function buildSettleCalls4(clone) {
|
|
129
145
|
return [
|
|
130
146
|
{
|
|
131
147
|
target: clone,
|
|
@@ -160,10 +176,10 @@ var INIT_PARAMS_TYPES2 = [
|
|
|
160
176
|
]
|
|
161
177
|
}
|
|
162
178
|
];
|
|
163
|
-
function
|
|
179
|
+
function buildInitData5(params) {
|
|
164
180
|
return encodeAbiParameters3(INIT_PARAMS_TYPES2, [params]);
|
|
165
181
|
}
|
|
166
|
-
function
|
|
182
|
+
function buildExecuteCalls5(clone, tokenA, amountA, tokenB, amountB) {
|
|
167
183
|
return [
|
|
168
184
|
{
|
|
169
185
|
target: tokenA,
|
|
@@ -193,7 +209,7 @@ function buildExecuteCalls3(clone, tokenA, amountA, tokenB, amountB) {
|
|
|
193
209
|
}
|
|
194
210
|
];
|
|
195
211
|
}
|
|
196
|
-
function
|
|
212
|
+
function buildSettleCalls5(clone) {
|
|
197
213
|
return [
|
|
198
214
|
{
|
|
199
215
|
target: clone,
|
|
@@ -225,10 +241,10 @@ var INIT_PARAMS_TYPES3 = [
|
|
|
225
241
|
]
|
|
226
242
|
}
|
|
227
243
|
];
|
|
228
|
-
function
|
|
244
|
+
function buildInitData6(params) {
|
|
229
245
|
return encodeAbiParameters4(INIT_PARAMS_TYPES3, [params]);
|
|
230
246
|
}
|
|
231
|
-
function
|
|
247
|
+
function buildExecuteCalls6(clone, weth, supplyAmount) {
|
|
232
248
|
const approveAmount = supplyAmount === 0n ? maxUint256 : supplyAmount;
|
|
233
249
|
return [
|
|
234
250
|
{
|
|
@@ -259,7 +275,7 @@ function buildExecuteCalls4(clone, weth, supplyAmount) {
|
|
|
259
275
|
}
|
|
260
276
|
];
|
|
261
277
|
}
|
|
262
|
-
function
|
|
278
|
+
function buildSettleCalls6(clone) {
|
|
263
279
|
return [
|
|
264
280
|
{
|
|
265
281
|
target: clone,
|
|
@@ -274,7 +290,7 @@ function buildSettleCalls4(clone) {
|
|
|
274
290
|
|
|
275
291
|
// src/strategies/mamo-yield-template.ts
|
|
276
292
|
import { encodeAbiParameters as encodeAbiParameters5, encodeFunctionData as encodeFunctionData5 } from "viem";
|
|
277
|
-
function
|
|
293
|
+
function buildInitData7(underlying, mamoFactory, minRedeemAmount) {
|
|
278
294
|
return encodeAbiParameters5(
|
|
279
295
|
[
|
|
280
296
|
{ type: "address" },
|
|
@@ -284,7 +300,7 @@ function buildInitData5(underlying, mamoFactory, minRedeemAmount) {
|
|
|
284
300
|
[underlying, mamoFactory, minRedeemAmount]
|
|
285
301
|
);
|
|
286
302
|
}
|
|
287
|
-
function
|
|
303
|
+
function buildExecuteCalls7(clone, underlying, amount) {
|
|
288
304
|
return [
|
|
289
305
|
{
|
|
290
306
|
target: underlying,
|
|
@@ -305,7 +321,7 @@ function buildExecuteCalls5(clone, underlying, amount) {
|
|
|
305
321
|
}
|
|
306
322
|
];
|
|
307
323
|
}
|
|
308
|
-
function
|
|
324
|
+
function buildSettleCalls7(clone) {
|
|
309
325
|
return [
|
|
310
326
|
{
|
|
311
327
|
target: clone,
|
|
@@ -355,7 +371,7 @@ function v4PathExtraData(hops) {
|
|
|
355
371
|
)
|
|
356
372
|
);
|
|
357
373
|
}
|
|
358
|
-
function
|
|
374
|
+
function buildInitData8(asset, swapAdapter, allocations, totalAmount, maxSlippageBps) {
|
|
359
375
|
const tokens = allocations.map((a) => a.token);
|
|
360
376
|
const weightsBps = allocations.map((a) => BigInt(a.weightBps));
|
|
361
377
|
const swapExtraData = allocations.map((a) => a.swapExtraData);
|
|
@@ -386,7 +402,7 @@ function buildInitData6(asset, swapAdapter, allocations, totalAmount, maxSlippag
|
|
|
386
402
|
]
|
|
387
403
|
);
|
|
388
404
|
}
|
|
389
|
-
function
|
|
405
|
+
function buildExecuteCalls8(clone, asset, totalAmount) {
|
|
390
406
|
return [
|
|
391
407
|
{
|
|
392
408
|
target: asset,
|
|
@@ -407,7 +423,7 @@ function buildExecuteCalls6(clone, asset, totalAmount) {
|
|
|
407
423
|
}
|
|
408
424
|
];
|
|
409
425
|
}
|
|
410
|
-
function
|
|
426
|
+
function buildSettleCalls8(clone) {
|
|
411
427
|
return [
|
|
412
428
|
{
|
|
413
429
|
target: clone,
|
|
@@ -801,7 +817,7 @@ var HYPERLIQUID_PERP_STRATEGY_ABI = [
|
|
|
801
817
|
];
|
|
802
818
|
|
|
803
819
|
// src/strategies/hyperliquid-perp-template.ts
|
|
804
|
-
function
|
|
820
|
+
function buildInitData9(asset, depositAmount, perpAssetIndex, leverage, maxPositionSize, maxTradesPerDay) {
|
|
805
821
|
return encodeAbiParameters7(
|
|
806
822
|
[
|
|
807
823
|
{ type: "address" },
|
|
@@ -814,7 +830,7 @@ function buildInitData7(asset, depositAmount, perpAssetIndex, leverage, maxPosit
|
|
|
814
830
|
[asset, depositAmount, perpAssetIndex, leverage, maxPositionSize, maxTradesPerDay]
|
|
815
831
|
);
|
|
816
832
|
}
|
|
817
|
-
function
|
|
833
|
+
function buildExecuteCalls9(clone, asset, amount) {
|
|
818
834
|
const approveAmount = amount === 0n ? maxUint2562 : amount;
|
|
819
835
|
return [
|
|
820
836
|
{
|
|
@@ -845,7 +861,7 @@ function buildExecuteCalls7(clone, asset, amount) {
|
|
|
845
861
|
}
|
|
846
862
|
];
|
|
847
863
|
}
|
|
848
|
-
function
|
|
864
|
+
function buildSettleCalls9(clone) {
|
|
849
865
|
return [
|
|
850
866
|
{
|
|
851
867
|
target: clone,
|
|
@@ -860,7 +876,7 @@ function buildSettleCalls7(clone) {
|
|
|
860
876
|
|
|
861
877
|
// src/strategies/hyperliquid-grid-template.ts
|
|
862
878
|
import { encodeAbiParameters as encodeAbiParameters8, encodeFunctionData as encodeFunctionData8, maxUint256 as maxUint2563 } from "viem";
|
|
863
|
-
function
|
|
879
|
+
function buildInitData10(asset, depositAmount, leverage, maxOrderSize, maxOrdersPerTick, assetIndices) {
|
|
864
880
|
return encodeAbiParameters8(
|
|
865
881
|
[
|
|
866
882
|
{ type: "address" },
|
|
@@ -873,7 +889,7 @@ function buildInitData8(asset, depositAmount, leverage, maxOrderSize, maxOrdersP
|
|
|
873
889
|
[asset, depositAmount, leverage, maxOrderSize, maxOrdersPerTick, assetIndices]
|
|
874
890
|
);
|
|
875
891
|
}
|
|
876
|
-
function
|
|
892
|
+
function buildExecuteCalls10(clone, asset, amount) {
|
|
877
893
|
const approveAmount = amount === 0n ? maxUint2563 : amount;
|
|
878
894
|
return [
|
|
879
895
|
{
|
|
@@ -904,7 +920,7 @@ function buildExecuteCalls8(clone, asset, amount) {
|
|
|
904
920
|
}
|
|
905
921
|
];
|
|
906
922
|
}
|
|
907
|
-
function
|
|
923
|
+
function buildSettleCalls10(clone) {
|
|
908
924
|
return [
|
|
909
925
|
{
|
|
910
926
|
target: clone,
|
|
@@ -917,6 +933,827 @@ function buildSettleCalls8(clone) {
|
|
|
917
933
|
];
|
|
918
934
|
}
|
|
919
935
|
|
|
936
|
+
// src/strategies/morpho-supply-template.ts
|
|
937
|
+
import { encodeAbiParameters as encodeAbiParameters10, encodeFunctionData as encodeFunctionData9, formatUnits, parseUnits } from "viem";
|
|
938
|
+
|
|
939
|
+
// src/strategies/morpho-cl-shared.ts
|
|
940
|
+
import { encodeAbiParameters as encodeAbiParameters9, isAddress, keccak256, toFunctionSelector } from "viem";
|
|
941
|
+
var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
942
|
+
function viewOutputComponents(abi, fn) {
|
|
943
|
+
const entry = abi.find(
|
|
944
|
+
(e) => e.type === "function" && e.name === fn
|
|
945
|
+
);
|
|
946
|
+
const components = entry?.outputs?.[0]?.components;
|
|
947
|
+
if (!components) throw new Error(`generated ABI has no tuple output for ${fn}()`);
|
|
948
|
+
return components;
|
|
949
|
+
}
|
|
950
|
+
var MARKET_PARAMS_COMPONENTS = viewOutputComponents(
|
|
951
|
+
CONCENTRATED_LIQUIDITY_STRATEGY_ABI,
|
|
952
|
+
"marketParams"
|
|
953
|
+
);
|
|
954
|
+
function marketIdOf(mp) {
|
|
955
|
+
return keccak256(
|
|
956
|
+
encodeAbiParameters9(
|
|
957
|
+
[{ type: "address" }, { type: "address" }, { type: "address" }, { type: "address" }, { type: "uint256" }],
|
|
958
|
+
[mp.loanToken, mp.collateralToken, mp.oracle, mp.irm, mp.lltv]
|
|
959
|
+
)
|
|
960
|
+
);
|
|
961
|
+
}
|
|
962
|
+
function MORPHO_CL_VENUES() {
|
|
963
|
+
const v = STRATEGY_VENUES();
|
|
964
|
+
return {
|
|
965
|
+
MORPHO_BLUE: v.MORPHO_BLUE,
|
|
966
|
+
UNISWAP_V3_FACTORY: v.UNISWAP_V3_FACTORY,
|
|
967
|
+
UNISWAP_V3_POSITION_MANAGER: v.UNISWAP_V3_POSITION_MANAGER
|
|
968
|
+
};
|
|
969
|
+
}
|
|
970
|
+
var MORPHO_READ_ABI = [
|
|
971
|
+
{
|
|
972
|
+
type: "function",
|
|
973
|
+
name: "idToMarketParams",
|
|
974
|
+
stateMutability: "view",
|
|
975
|
+
inputs: [{ name: "id", type: "bytes32" }],
|
|
976
|
+
outputs: [{ name: "", type: "tuple", components: MARKET_PARAMS_COMPONENTS }]
|
|
977
|
+
},
|
|
978
|
+
{
|
|
979
|
+
type: "function",
|
|
980
|
+
name: "market",
|
|
981
|
+
stateMutability: "view",
|
|
982
|
+
inputs: [{ name: "id", type: "bytes32" }],
|
|
983
|
+
outputs: [
|
|
984
|
+
{
|
|
985
|
+
name: "",
|
|
986
|
+
type: "tuple",
|
|
987
|
+
components: [
|
|
988
|
+
{ name: "totalSupplyAssets", type: "uint128" },
|
|
989
|
+
{ name: "totalSupplyShares", type: "uint128" },
|
|
990
|
+
{ name: "totalBorrowAssets", type: "uint128" },
|
|
991
|
+
{ name: "totalBorrowShares", type: "uint128" },
|
|
992
|
+
{ name: "lastUpdate", type: "uint128" },
|
|
993
|
+
{ name: "fee", type: "uint128" }
|
|
994
|
+
]
|
|
995
|
+
}
|
|
996
|
+
]
|
|
997
|
+
}
|
|
998
|
+
];
|
|
999
|
+
var TIER_BINDING_ABI = [
|
|
1000
|
+
{ type: "function", name: "governor", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "address" }] },
|
|
1001
|
+
{ type: "function", name: "tierRegistry", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "address" }] },
|
|
1002
|
+
{
|
|
1003
|
+
type: "function",
|
|
1004
|
+
name: "isCounterpartyAllowed",
|
|
1005
|
+
stateMutability: "view",
|
|
1006
|
+
inputs: [{ name: "counterparty", type: "address" }],
|
|
1007
|
+
outputs: [{ name: "", type: "bool" }]
|
|
1008
|
+
}
|
|
1009
|
+
];
|
|
1010
|
+
var VAULT_ASSET_ABI = [
|
|
1011
|
+
{ type: "function", name: "asset", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "address" }] }
|
|
1012
|
+
];
|
|
1013
|
+
var ERC4626_PREVIEW_ABI = [
|
|
1014
|
+
{ type: "function", name: "asset", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "address" }] },
|
|
1015
|
+
{
|
|
1016
|
+
type: "function",
|
|
1017
|
+
name: "previewDeposit",
|
|
1018
|
+
stateMutability: "view",
|
|
1019
|
+
inputs: [{ name: "assets", type: "uint256" }],
|
|
1020
|
+
outputs: [{ name: "", type: "uint256" }]
|
|
1021
|
+
},
|
|
1022
|
+
{
|
|
1023
|
+
type: "function",
|
|
1024
|
+
name: "previewRedeem",
|
|
1025
|
+
stateMutability: "view",
|
|
1026
|
+
inputs: [{ name: "shares", type: "uint256" }],
|
|
1027
|
+
outputs: [{ name: "", type: "uint256" }]
|
|
1028
|
+
}
|
|
1029
|
+
];
|
|
1030
|
+
async function readTierRegistry(client, vault) {
|
|
1031
|
+
try {
|
|
1032
|
+
const governor = await client.readContract({
|
|
1033
|
+
address: vault,
|
|
1034
|
+
abi: TIER_BINDING_ABI,
|
|
1035
|
+
functionName: "governor"
|
|
1036
|
+
});
|
|
1037
|
+
if (!governor || governor === ZERO_ADDRESS) return null;
|
|
1038
|
+
const registry = await client.readContract({
|
|
1039
|
+
address: governor,
|
|
1040
|
+
abi: TIER_BINDING_ABI,
|
|
1041
|
+
functionName: "tierRegistry"
|
|
1042
|
+
});
|
|
1043
|
+
return registry && registry !== ZERO_ADDRESS ? registry : null;
|
|
1044
|
+
} catch {
|
|
1045
|
+
return null;
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
async function readAllowed(client, registry, counterparties) {
|
|
1049
|
+
const out = {};
|
|
1050
|
+
const unique = [...new Set(counterparties.map((c) => c.toLowerCase()))];
|
|
1051
|
+
await Promise.all(
|
|
1052
|
+
unique.map(async (c) => {
|
|
1053
|
+
if (!registry) {
|
|
1054
|
+
out[c] = false;
|
|
1055
|
+
return;
|
|
1056
|
+
}
|
|
1057
|
+
try {
|
|
1058
|
+
out[c] = await client.readContract({
|
|
1059
|
+
address: registry,
|
|
1060
|
+
abi: TIER_BINDING_ABI,
|
|
1061
|
+
functionName: "isCounterpartyAllowed",
|
|
1062
|
+
args: [c]
|
|
1063
|
+
});
|
|
1064
|
+
} catch {
|
|
1065
|
+
out[c] = false;
|
|
1066
|
+
}
|
|
1067
|
+
})
|
|
1068
|
+
);
|
|
1069
|
+
return out;
|
|
1070
|
+
}
|
|
1071
|
+
function isAllowed(allowed, a) {
|
|
1072
|
+
return allowed[a.toLowerCase()] === true;
|
|
1073
|
+
}
|
|
1074
|
+
function sameAddress(a, b) {
|
|
1075
|
+
return a.toLowerCase() === b.toLowerCase();
|
|
1076
|
+
}
|
|
1077
|
+
function withSelector(signature) {
|
|
1078
|
+
return `${signature} [${toFunctionSelector(signature)}]`;
|
|
1079
|
+
}
|
|
1080
|
+
function parseAddressFlag(raw, flag) {
|
|
1081
|
+
const s = String(raw ?? "").trim();
|
|
1082
|
+
if (!isAddress(s)) throw new Error(`${flag} must be a 0x-address (got '${s}')`);
|
|
1083
|
+
return s;
|
|
1084
|
+
}
|
|
1085
|
+
function parseBytes32Flag(raw, flag) {
|
|
1086
|
+
const s = String(raw ?? "").trim();
|
|
1087
|
+
if (!/^0x[0-9a-fA-F]{64}$/.test(s)) throw new Error(`${flag} must be a 0x-prefixed 32-byte hex id (got '${s}')`);
|
|
1088
|
+
return s.toLowerCase();
|
|
1089
|
+
}
|
|
1090
|
+
function parseIntFlag(raw, flag, fallback, min = Number.MIN_SAFE_INTEGER, max = Number.MAX_SAFE_INTEGER) {
|
|
1091
|
+
if (raw === void 0 || raw === null || raw === "") return fallback;
|
|
1092
|
+
const s = String(raw).trim();
|
|
1093
|
+
if (!/^-?\d+$/.test(s)) throw new Error(`${flag} must be an integer (got '${s}')`);
|
|
1094
|
+
const n = Number(s);
|
|
1095
|
+
if (n < min || n > max) throw new Error(`${flag} must be within [${min}, ${max}] (got ${n})`);
|
|
1096
|
+
return n;
|
|
1097
|
+
}
|
|
1098
|
+
function parseUintFlag(raw, flag, fallback) {
|
|
1099
|
+
if (raw === void 0 || raw === null || raw === "") return fallback;
|
|
1100
|
+
const s = String(raw).trim();
|
|
1101
|
+
if (!/^\d+$/.test(s)) throw new Error(`${flag} must be a non-negative integer (got '${s}')`);
|
|
1102
|
+
return BigInt(s);
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
// src/strategies/morpho-supply-template.ts
|
|
1106
|
+
function buildInitData11(morpho, marketParams, supplyAmount) {
|
|
1107
|
+
return encodeAbiParameters10(
|
|
1108
|
+
[
|
|
1109
|
+
{ type: "address" },
|
|
1110
|
+
{ type: "tuple", components: MARKET_PARAMS_COMPONENTS },
|
|
1111
|
+
{ type: "uint256" }
|
|
1112
|
+
],
|
|
1113
|
+
[morpho, marketParams, supplyAmount]
|
|
1114
|
+
);
|
|
1115
|
+
}
|
|
1116
|
+
function buildExecuteCalls11(clone, asset, supplyAmount) {
|
|
1117
|
+
return [
|
|
1118
|
+
{
|
|
1119
|
+
target: asset,
|
|
1120
|
+
data: encodeFunctionData9({ abi: ERC20_ABI, functionName: "approve", args: [clone, supplyAmount] }),
|
|
1121
|
+
value: 0n
|
|
1122
|
+
},
|
|
1123
|
+
{
|
|
1124
|
+
target: clone,
|
|
1125
|
+
data: encodeFunctionData9({ abi: BASE_STRATEGY_ABI, functionName: "execute" }),
|
|
1126
|
+
value: 0n
|
|
1127
|
+
}
|
|
1128
|
+
];
|
|
1129
|
+
}
|
|
1130
|
+
function buildSettleCalls11(clone) {
|
|
1131
|
+
return [
|
|
1132
|
+
{
|
|
1133
|
+
target: clone,
|
|
1134
|
+
data: encodeFunctionData9({ abi: BASE_STRATEGY_ABI, functionName: "settle" }),
|
|
1135
|
+
value: 0n
|
|
1136
|
+
}
|
|
1137
|
+
];
|
|
1138
|
+
}
|
|
1139
|
+
function planMorphoSupply(inputs, state) {
|
|
1140
|
+
const errors = [];
|
|
1141
|
+
const warnings = [];
|
|
1142
|
+
const { morpho, marketId } = inputs;
|
|
1143
|
+
const mp = state.marketParams;
|
|
1144
|
+
if (sameAddress(morpho, ZERO_ADDRESS)) {
|
|
1145
|
+
errors.push(`${withSelector("ZeroAddress()")}: no Morpho Blue address \u2014 pass --morpho on this network`);
|
|
1146
|
+
}
|
|
1147
|
+
if (!state.tierRegistry) {
|
|
1148
|
+
errors.push(
|
|
1149
|
+
`${withSelector("TierRegistryUnresolved()")}: the vault's governor names no TierRegistry, so the strategy cannot bind Morpho`
|
|
1150
|
+
);
|
|
1151
|
+
} else if (!state.morphoAllowed) {
|
|
1152
|
+
errors.push(
|
|
1153
|
+
`${withSelector("MorphoNotAllowed(address,address)")}: Morpho ${morpho} is not counterparty-allowlisted on the vault's TierRegistry ${state.tierRegistry}`
|
|
1154
|
+
);
|
|
1155
|
+
}
|
|
1156
|
+
let supplyAmount = 0n;
|
|
1157
|
+
try {
|
|
1158
|
+
supplyAmount = parseUnits(inputs.amount, state.assetDecimals);
|
|
1159
|
+
} catch {
|
|
1160
|
+
errors.push(`--amount '${inputs.amount}' is not a decimal amount of ${state.assetSymbol}`);
|
|
1161
|
+
}
|
|
1162
|
+
if (supplyAmount === 0n) errors.push(`${withSelector("InvalidAmount()")}: --amount must be > 0`);
|
|
1163
|
+
const unknownMarket = sameAddress(mp.loanToken, ZERO_ADDRESS) && mp.lltv === 0n;
|
|
1164
|
+
if (unknownMarket) {
|
|
1165
|
+
errors.push(
|
|
1166
|
+
`${withSelector("MarketNotCreated()")}: market ${marketId} does not exist on Morpho ${morpho} (idToMarketParams is empty)`
|
|
1167
|
+
);
|
|
1168
|
+
} else {
|
|
1169
|
+
if (!sameAddress(mp.loanToken, state.vaultAsset)) {
|
|
1170
|
+
errors.push(
|
|
1171
|
+
`${withSelector("LoanAssetMismatch()")}: market ${marketId} lends ${mp.loanToken}, but the vault asset is ${state.vaultAsset} (${state.assetSymbol})`
|
|
1172
|
+
);
|
|
1173
|
+
}
|
|
1174
|
+
const derived = marketIdOf(mp);
|
|
1175
|
+
if (derived.toLowerCase() !== marketId.toLowerCase()) {
|
|
1176
|
+
errors.push(`market params returned for ${marketId} hash to ${derived} \u2014 not the market you named`);
|
|
1177
|
+
}
|
|
1178
|
+
if (state.market.lastUpdate === 0n) {
|
|
1179
|
+
errors.push(`${withSelector("MarketNotCreated()")}: market ${marketId} has never been created on ${morpho}`);
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
if (supplyAmount > 0n && state.vaultBalance < supplyAmount) {
|
|
1183
|
+
errors.push(
|
|
1184
|
+
`vault holds ${formatUnits(state.vaultBalance, state.assetDecimals)} ${state.assetSymbol} but execute pulls ${formatUnits(supplyAmount, state.assetDecimals)} (--amount is in human units)`
|
|
1185
|
+
);
|
|
1186
|
+
}
|
|
1187
|
+
if (errors.length > 0) return { plan: null, errors, warnings };
|
|
1188
|
+
return {
|
|
1189
|
+
plan: { morpho, marketId, marketParams: mp, asset: state.vaultAsset, supplyAmount },
|
|
1190
|
+
errors,
|
|
1191
|
+
warnings
|
|
1192
|
+
};
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
// src/strategies/concentrated-liquidity-template.ts
|
|
1196
|
+
import { encodeAbiParameters as encodeAbiParameters11, encodeFunctionData as encodeFunctionData10, formatUnits as formatUnits2 } from "viem";
|
|
1197
|
+
var BPS = 10000n;
|
|
1198
|
+
var FEE_DENOMINATOR = 1000000n;
|
|
1199
|
+
var MIN_TICK = -887272;
|
|
1200
|
+
var MAX_TICK = 887272;
|
|
1201
|
+
var MAX_POOL_SHARE_BPS = 1000n;
|
|
1202
|
+
var MIN_LLTV_BUFFER_BPS = 500n;
|
|
1203
|
+
var MAX_SLIPPAGE_BPS = 1e3;
|
|
1204
|
+
var MAX_TWAP_DEVIATION_BPS = 1e3;
|
|
1205
|
+
var MIN_TWAP_WINDOW = 300;
|
|
1206
|
+
var MAX_RERANGE_LIMIT = 20;
|
|
1207
|
+
var MAX_HALF_WIDTH_TICKS = MAX_TICK;
|
|
1208
|
+
var CL_DEFAULTS = {
|
|
1209
|
+
twapWindow: 1800,
|
|
1210
|
+
maxTwapDeviationBps: 100,
|
|
1211
|
+
mintSlippageBps: 500,
|
|
1212
|
+
settleSlippageBps: 500,
|
|
1213
|
+
settleDeadline: 0n,
|
|
1214
|
+
rerangeTriggerBps: 8e3,
|
|
1215
|
+
rerangeMinInterval: 3600n,
|
|
1216
|
+
maxReranges: 3,
|
|
1217
|
+
rerangeSlippageBps: 500
|
|
1218
|
+
};
|
|
1219
|
+
function rerangeComponents() {
|
|
1220
|
+
const entry = CONCENTRATED_LIQUIDITY_STRATEGY_ABI.find(
|
|
1221
|
+
(e) => e.type === "function" && e.name === "rerangePolicy"
|
|
1222
|
+
);
|
|
1223
|
+
const c = entry?.outputs?.[0]?.components;
|
|
1224
|
+
if (!c) throw new Error("generated ABI has no tuple output for rerangePolicy()");
|
|
1225
|
+
return c;
|
|
1226
|
+
}
|
|
1227
|
+
var INIT_PARAMS_COMPONENTS = [
|
|
1228
|
+
{ name: "pool", type: "address" },
|
|
1229
|
+
{ name: "positionManager", type: "address" },
|
|
1230
|
+
{ name: "uniswapFactory", type: "address" },
|
|
1231
|
+
{ name: "swapAdapter", type: "address" },
|
|
1232
|
+
{ name: "morpho", type: "address" },
|
|
1233
|
+
{ name: "marketParams", type: "tuple", components: MARKET_PARAMS_COMPONENTS },
|
|
1234
|
+
{ name: "collateralAmount", type: "uint256" },
|
|
1235
|
+
{ name: "borrowAmount", type: "uint256" },
|
|
1236
|
+
{ name: "tickLower", type: "int24" },
|
|
1237
|
+
{ name: "tickUpper", type: "int24" },
|
|
1238
|
+
{ name: "expectedLiquidity", type: "uint128" },
|
|
1239
|
+
{ name: "swapFractionBps", type: "uint256" },
|
|
1240
|
+
{ name: "twapWindow", type: "uint32" },
|
|
1241
|
+
{ name: "maxTwapDeviationBps", type: "uint256" },
|
|
1242
|
+
{ name: "mintSlippageBps", type: "uint256" },
|
|
1243
|
+
{ name: "rerange", type: "tuple", components: rerangeComponents() },
|
|
1244
|
+
{ name: "settleSlippageBps", type: "uint256" },
|
|
1245
|
+
{ name: "settleDeadline", type: "uint256" },
|
|
1246
|
+
{ name: "swapExtraData", type: "bytes" }
|
|
1247
|
+
];
|
|
1248
|
+
function buildInitData12(p) {
|
|
1249
|
+
return encodeAbiParameters11([{ type: "tuple", components: INIT_PARAMS_COMPONENTS }], [p]);
|
|
1250
|
+
}
|
|
1251
|
+
function buildExecuteCalls12(clone, asset, collateralAmount) {
|
|
1252
|
+
return [
|
|
1253
|
+
{
|
|
1254
|
+
target: asset,
|
|
1255
|
+
data: encodeFunctionData10({ abi: ERC20_ABI, functionName: "approve", args: [clone, collateralAmount] }),
|
|
1256
|
+
value: 0n
|
|
1257
|
+
},
|
|
1258
|
+
{
|
|
1259
|
+
target: clone,
|
|
1260
|
+
data: encodeFunctionData10({ abi: BASE_STRATEGY_ABI, functionName: "execute" }),
|
|
1261
|
+
value: 0n
|
|
1262
|
+
}
|
|
1263
|
+
];
|
|
1264
|
+
}
|
|
1265
|
+
function buildSettleCalls12(clone) {
|
|
1266
|
+
return [
|
|
1267
|
+
{
|
|
1268
|
+
target: clone,
|
|
1269
|
+
data: encodeFunctionData10({ abi: BASE_STRATEGY_ABI, functionName: "settle" }),
|
|
1270
|
+
value: 0n
|
|
1271
|
+
}
|
|
1272
|
+
];
|
|
1273
|
+
}
|
|
1274
|
+
var Q96 = 1n << 96n;
|
|
1275
|
+
var MAX_UINT256 = (1n << 256n) - 1n;
|
|
1276
|
+
function getSqrtRatioAtTick(tick) {
|
|
1277
|
+
if (!Number.isInteger(tick)) throw new Error(`tick must be an integer (got ${tick})`);
|
|
1278
|
+
const absTick = BigInt(Math.abs(tick));
|
|
1279
|
+
if (absTick > BigInt(MAX_TICK)) throw new Error(`tick ${tick} outside [${MIN_TICK}, ${MAX_TICK}]`);
|
|
1280
|
+
let ratio = (absTick & 0x1n) !== 0n ? 0xfffcb933bd6fad37aa2d162d1a594001n : 0x100000000000000000000000000000000n;
|
|
1281
|
+
const steps = [
|
|
1282
|
+
[0x2n, 0xfff97272373d413259a46990580e213an],
|
|
1283
|
+
[0x4n, 0xfff2e50f5f656932ef12357cf3c7fdccn],
|
|
1284
|
+
[0x8n, 0xffe5caca7e10e4e61c3624eaa0941cd0n],
|
|
1285
|
+
[0x10n, 0xffcb9843d60f6159c9db58835c926644n],
|
|
1286
|
+
[0x20n, 0xff973b41fa98c081472e6896dfb254c0n],
|
|
1287
|
+
[0x40n, 0xff2ea16466c96a3843ec78b326b52861n],
|
|
1288
|
+
[0x80n, 0xfe5dee046a99a2a811c461f1969c3053n],
|
|
1289
|
+
[0x100n, 0xfcbe86c7900a88aedcffc83b479aa3a4n],
|
|
1290
|
+
[0x200n, 0xf987a7253ac413176f2b074cf7815e54n],
|
|
1291
|
+
[0x400n, 0xf3392b0822b70005940c7a398e4b70f3n],
|
|
1292
|
+
[0x800n, 0xe7159475a2c29b7443b29c7fa6e889d9n],
|
|
1293
|
+
[0x1000n, 0xd097f3bdfd2022b8845ad8f792aa5825n],
|
|
1294
|
+
[0x2000n, 0xa9f746462d870fdf8a65dc1f90e061e5n],
|
|
1295
|
+
[0x4000n, 0x70d869a156d2a1b890bb3df62baf32f7n],
|
|
1296
|
+
[0x8000n, 0x31be135f97d08fd981231505542fcfa6n],
|
|
1297
|
+
[0x10000n, 0x9aa508b5b7a84e1c677de54f3e99bc9n],
|
|
1298
|
+
[0x20000n, 0x5d6af8dedb81196699c329225ee604n],
|
|
1299
|
+
[0x40000n, 0x2216e584f5fa1ea926041bedfe98n],
|
|
1300
|
+
[0x80000n, 0x48a170391f7dc42444e8fa2n]
|
|
1301
|
+
];
|
|
1302
|
+
for (const [bit, mul] of steps) {
|
|
1303
|
+
if ((absTick & bit) !== 0n) ratio = ratio * mul >> 128n;
|
|
1304
|
+
}
|
|
1305
|
+
if (tick > 0) ratio = MAX_UINT256 / ratio;
|
|
1306
|
+
return (ratio >> 32n) + (ratio % (1n << 32n) === 0n ? 0n : 1n);
|
|
1307
|
+
}
|
|
1308
|
+
function snapDown(tick, spacing) {
|
|
1309
|
+
return Math.floor(tick / spacing) * spacing;
|
|
1310
|
+
}
|
|
1311
|
+
function snapUp(tick, spacing) {
|
|
1312
|
+
return Math.ceil(tick / spacing) * spacing;
|
|
1313
|
+
}
|
|
1314
|
+
function rangeFromPct(centerTick, pct, spacing) {
|
|
1315
|
+
if (!(pct > 0 && pct < 100)) throw new Error(`--range-pct must be in (0, 100) (got ${pct})`);
|
|
1316
|
+
const p = pct / 100;
|
|
1317
|
+
const lnBase = Math.log(1.0001);
|
|
1318
|
+
const down = Math.floor(Math.log(1 - p) / lnBase);
|
|
1319
|
+
const up = Math.ceil(Math.log(1 + p) / lnBase);
|
|
1320
|
+
const minAligned = snapUp(MIN_TICK, spacing);
|
|
1321
|
+
const maxAligned = snapDown(MAX_TICK, spacing);
|
|
1322
|
+
const tickLower = Math.max(minAligned, snapDown(centerTick + down, spacing));
|
|
1323
|
+
const tickUpper = Math.min(maxAligned, snapUp(centerTick + up, spacing));
|
|
1324
|
+
return { tickLower, tickUpper };
|
|
1325
|
+
}
|
|
1326
|
+
function liquidityForAmount0(sqrtA, sqrtB, amount0) {
|
|
1327
|
+
if (sqrtA > sqrtB) [sqrtA, sqrtB] = [sqrtB, sqrtA];
|
|
1328
|
+
const intermediate = sqrtA * sqrtB / Q96;
|
|
1329
|
+
return amount0 * intermediate / (sqrtB - sqrtA);
|
|
1330
|
+
}
|
|
1331
|
+
function liquidityForAmount1(sqrtA, sqrtB, amount1) {
|
|
1332
|
+
if (sqrtA > sqrtB) [sqrtA, sqrtB] = [sqrtB, sqrtA];
|
|
1333
|
+
return amount1 * Q96 / (sqrtB - sqrtA);
|
|
1334
|
+
}
|
|
1335
|
+
function liquidityForAmounts(sqrtP, sqrtA, sqrtB, amount0, amount1) {
|
|
1336
|
+
if (sqrtA > sqrtB) [sqrtA, sqrtB] = [sqrtB, sqrtA];
|
|
1337
|
+
if (sqrtP <= sqrtA) return liquidityForAmount0(sqrtA, sqrtB, amount0);
|
|
1338
|
+
if (sqrtP < sqrtB) {
|
|
1339
|
+
const l0 = liquidityForAmount0(sqrtP, sqrtB, amount0);
|
|
1340
|
+
const l1 = liquidityForAmount1(sqrtA, sqrtP, amount1);
|
|
1341
|
+
return l0 < l1 ? l0 : l1;
|
|
1342
|
+
}
|
|
1343
|
+
return liquidityForAmount1(sqrtA, sqrtB, amount1);
|
|
1344
|
+
}
|
|
1345
|
+
function amountsForLiquidity(sqrtP, sqrtA, sqrtB, liquidity) {
|
|
1346
|
+
if (sqrtA > sqrtB) [sqrtA, sqrtB] = [sqrtB, sqrtA];
|
|
1347
|
+
const a0 = (lo, hi) => (liquidity << 96n) * (hi - lo) / hi / lo;
|
|
1348
|
+
const a1 = (lo, hi) => liquidity * (hi - lo) / Q96;
|
|
1349
|
+
if (sqrtP <= sqrtA) return { amount0: a0(sqrtA, sqrtB), amount1: 0n };
|
|
1350
|
+
if (sqrtP < sqrtB) return { amount0: a0(sqrtP, sqrtB), amount1: a1(sqrtA, sqrtP) };
|
|
1351
|
+
return { amount0: 0n, amount1: a1(sqrtA, sqrtB) };
|
|
1352
|
+
}
|
|
1353
|
+
function token0ToToken1(amount0, sqrtP) {
|
|
1354
|
+
return amount0 * sqrtP / Q96 * sqrtP / Q96;
|
|
1355
|
+
}
|
|
1356
|
+
function token1ToToken0(amount1, sqrtP) {
|
|
1357
|
+
return amount1 * Q96 / sqrtP * Q96 / sqrtP;
|
|
1358
|
+
}
|
|
1359
|
+
function idealSwapFractionBps(sqrtP, tickLower, tickUpper, assetIsToken0) {
|
|
1360
|
+
const sqrtA = getSqrtRatioAtTick(tickLower);
|
|
1361
|
+
const sqrtB = getSqrtRatioAtTick(tickUpper);
|
|
1362
|
+
const { amount0, amount1 } = amountsForLiquidity(sqrtP, sqrtA, sqrtB, 10n ** 24n);
|
|
1363
|
+
const value0 = token0ToToken1(amount0, sqrtP);
|
|
1364
|
+
const total = value0 + amount1;
|
|
1365
|
+
if (total === 0n) return 0;
|
|
1366
|
+
const other = assetIsToken0 ? amount1 : value0;
|
|
1367
|
+
return Number((other * BPS + total / 2n) / total);
|
|
1368
|
+
}
|
|
1369
|
+
function estimateExpectedLiquidity(args) {
|
|
1370
|
+
const { sqrtPriceX96: sqrtP, assetIsToken0, deployable } = args;
|
|
1371
|
+
const swapped = deployable * BigInt(args.swapFractionBps) / BPS;
|
|
1372
|
+
const kept = deployable - swapped;
|
|
1373
|
+
let otherOut = assetIsToken0 ? token0ToToken1(swapped, sqrtP) : token1ToToken0(swapped, sqrtP);
|
|
1374
|
+
otherOut = otherOut * (FEE_DENOMINATOR - BigInt(args.poolFee)) / FEE_DENOMINATOR;
|
|
1375
|
+
const amount0 = assetIsToken0 ? kept : otherOut;
|
|
1376
|
+
const amount1 = assetIsToken0 ? otherOut : kept;
|
|
1377
|
+
return liquidityForAmounts(
|
|
1378
|
+
sqrtP,
|
|
1379
|
+
getSqrtRatioAtTick(args.tickLower),
|
|
1380
|
+
getSqrtRatioAtTick(args.tickUpper),
|
|
1381
|
+
amount0,
|
|
1382
|
+
amount1
|
|
1383
|
+
);
|
|
1384
|
+
}
|
|
1385
|
+
function derivedRerangeRange(center, halfWidthTicks, spacing) {
|
|
1386
|
+
const minAligned = snapUp(MIN_TICK, spacing);
|
|
1387
|
+
const maxAligned = snapDown(MAX_TICK, spacing);
|
|
1388
|
+
const lo = center - halfWidthTicks;
|
|
1389
|
+
const hi = center + halfWidthTicks;
|
|
1390
|
+
return {
|
|
1391
|
+
tickLower: lo <= minAligned ? minAligned : snapDown(lo, spacing),
|
|
1392
|
+
tickUpper: hi >= maxAligned ? maxAligned : snapUp(hi, spacing)
|
|
1393
|
+
};
|
|
1394
|
+
}
|
|
1395
|
+
function estimateSwapImpactBps(args) {
|
|
1396
|
+
const { sqrtPriceX96: sqrtP, liquidity: L } = args;
|
|
1397
|
+
const amt = args.amountIn * (FEE_DENOMINATOR - BigInt(args.poolFee)) / FEE_DENOMINATOR;
|
|
1398
|
+
if (amt === 0n) return 0;
|
|
1399
|
+
if (L === 0n || sqrtP === 0n) return 1e4;
|
|
1400
|
+
let num;
|
|
1401
|
+
let den;
|
|
1402
|
+
if (args.tokenInIsToken0) {
|
|
1403
|
+
const next = L * sqrtP * Q96 / (L * Q96 + amt * sqrtP);
|
|
1404
|
+
num = sqrtP - next;
|
|
1405
|
+
den = sqrtP;
|
|
1406
|
+
} else {
|
|
1407
|
+
const next = sqrtP + amt * Q96 / L;
|
|
1408
|
+
num = next - sqrtP;
|
|
1409
|
+
den = next;
|
|
1410
|
+
}
|
|
1411
|
+
const bps = (num * BPS + den - 1n) / den;
|
|
1412
|
+
return Number(bps > BPS ? BPS : bps);
|
|
1413
|
+
}
|
|
1414
|
+
var IMPACT_WARN_SHARE_BPS = 7000n;
|
|
1415
|
+
var POOL_SHARE_WARN_BPS = 8000n;
|
|
1416
|
+
function twapTickFromCumulatives(tickCumulatives, window) {
|
|
1417
|
+
const delta = tickCumulatives[1] - tickCumulatives[0];
|
|
1418
|
+
const w = BigInt(window);
|
|
1419
|
+
let avg = delta / w;
|
|
1420
|
+
if (delta < 0n && delta % w !== 0n) avg -= 1n;
|
|
1421
|
+
return Number(avg);
|
|
1422
|
+
}
|
|
1423
|
+
var UINT128_MAX = (1n << 128n) - 1n;
|
|
1424
|
+
function planConcentratedLiquidity(inputs, state) {
|
|
1425
|
+
const errors = [];
|
|
1426
|
+
const warnings = [];
|
|
1427
|
+
const asset = state.vaultAsset;
|
|
1428
|
+
const mp = state.marketParams;
|
|
1429
|
+
const sym = state.assetSymbol;
|
|
1430
|
+
const fmt = (v) => `${formatUnits2(v, state.assetDecimals)} ${sym}`;
|
|
1431
|
+
const named = [
|
|
1432
|
+
["pool", inputs.pool],
|
|
1433
|
+
["positionManager", inputs.positionManager],
|
|
1434
|
+
["morpho", inputs.morpho],
|
|
1435
|
+
["swapAdapter", inputs.swapAdapter],
|
|
1436
|
+
["uniswapFactory", inputs.uniswapFactory]
|
|
1437
|
+
];
|
|
1438
|
+
for (const [name, a] of named) {
|
|
1439
|
+
if (sameAddress(a, ZERO_ADDRESS)) {
|
|
1440
|
+
errors.push(`${withSelector("ZeroAddress()")}: ${name} is unset \u2014 no default on this network, pass it by flag`);
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
if (inputs.collateralAmount === 0n || inputs.borrowAmount === 0n) {
|
|
1444
|
+
errors.push(`${withSelector("InvalidAmount()")}: --collateral-amount and --borrow-amount must both be > 0`);
|
|
1445
|
+
}
|
|
1446
|
+
if (!state.tierRegistry) {
|
|
1447
|
+
errors.push(
|
|
1448
|
+
`${withSelector("TierRegistryUnresolved()")}: the vault's governor names no TierRegistry, so no counterparty can be vouched for`
|
|
1449
|
+
);
|
|
1450
|
+
} else {
|
|
1451
|
+
const bound = [
|
|
1452
|
+
["swap adapter", inputs.swapAdapter],
|
|
1453
|
+
["position manager", inputs.positionManager],
|
|
1454
|
+
["Morpho", inputs.morpho],
|
|
1455
|
+
["Uniswap V3 factory", inputs.uniswapFactory]
|
|
1456
|
+
];
|
|
1457
|
+
if (!sameAddress(mp.collateralToken, asset) && !sameAddress(mp.collateralToken, ZERO_ADDRESS)) {
|
|
1458
|
+
bound.push(["market collateral token", mp.collateralToken]);
|
|
1459
|
+
}
|
|
1460
|
+
for (const [label, a] of bound) {
|
|
1461
|
+
if (!sameAddress(a, ZERO_ADDRESS) && !isAllowed(state.allowed, a)) {
|
|
1462
|
+
errors.push(
|
|
1463
|
+
`${withSelector("CounterpartyNotAllowed(address,address)")}: ${label} ${a} is not counterparty-allowlisted on TierRegistry ${state.tierRegistry}`
|
|
1464
|
+
);
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
}
|
|
1468
|
+
const pool = state.pool;
|
|
1469
|
+
let otherToken = ZERO_ADDRESS;
|
|
1470
|
+
let assetIsToken0 = false;
|
|
1471
|
+
let poolUsable = false;
|
|
1472
|
+
if (!pool.hasCode) {
|
|
1473
|
+
errors.push(`${withSelector("PoolNotFromFactory()")}: pool ${inputs.pool} holds no code`);
|
|
1474
|
+
} else {
|
|
1475
|
+
if (!sameAddress(pool.factoryPool, inputs.pool)) {
|
|
1476
|
+
errors.push(
|
|
1477
|
+
`${withSelector("PoolNotFromFactory()")}: factory ${inputs.uniswapFactory}.getPool(token0, token1, ${pool.fee}) = ${pool.factoryPool}, not ${inputs.pool}`
|
|
1478
|
+
);
|
|
1479
|
+
}
|
|
1480
|
+
if (sameAddress(pool.token0, asset)) {
|
|
1481
|
+
assetIsToken0 = true;
|
|
1482
|
+
otherToken = pool.token1;
|
|
1483
|
+
} else if (sameAddress(pool.token1, asset)) {
|
|
1484
|
+
otherToken = pool.token0;
|
|
1485
|
+
} else {
|
|
1486
|
+
errors.push(
|
|
1487
|
+
`${withSelector("PoolAssetMismatch()")}: pool ${inputs.pool} trades ${pool.token0}/${pool.token1}; neither is the vault asset ${asset} (${sym})`
|
|
1488
|
+
);
|
|
1489
|
+
}
|
|
1490
|
+
if (!sameAddress(otherToken, ZERO_ADDRESS)) {
|
|
1491
|
+
poolUsable = true;
|
|
1492
|
+
if (state.tierRegistry && !isAllowed(state.allowed, otherToken)) {
|
|
1493
|
+
errors.push(
|
|
1494
|
+
`${withSelector("CounterpartyNotAllowed(address,address)")}: the pool's other token ${otherToken} is not counterparty-allowlisted on TierRegistry ${state.tierRegistry}`
|
|
1495
|
+
);
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1499
|
+
const unknownMarket = sameAddress(mp.loanToken, ZERO_ADDRESS) && mp.lltv === 0n;
|
|
1500
|
+
if (unknownMarket) {
|
|
1501
|
+
errors.push(
|
|
1502
|
+
`${withSelector("MarketNotCreated()")}: market ${inputs.marketId} does not exist on Morpho ${inputs.morpho} (idToMarketParams is empty)`
|
|
1503
|
+
);
|
|
1504
|
+
} else {
|
|
1505
|
+
if (!sameAddress(mp.loanToken, asset)) {
|
|
1506
|
+
errors.push(
|
|
1507
|
+
`${withSelector("LoanAssetMismatch()")}: market ${inputs.marketId} lends ${mp.loanToken}, not the vault asset ${asset} (${sym})`
|
|
1508
|
+
);
|
|
1509
|
+
}
|
|
1510
|
+
const derived = marketIdOf(mp);
|
|
1511
|
+
if (derived.toLowerCase() !== inputs.marketId.toLowerCase()) {
|
|
1512
|
+
errors.push(`market params returned for ${inputs.marketId} hash to ${derived} \u2014 not the market you named`);
|
|
1513
|
+
}
|
|
1514
|
+
if (state.market.lastUpdate === 0n) {
|
|
1515
|
+
errors.push(`${withSelector("MarketNotCreated()")}: market ${inputs.marketId} has never been created`);
|
|
1516
|
+
}
|
|
1517
|
+
if (poolUsable && sameAddress(mp.collateralToken, otherToken)) {
|
|
1518
|
+
errors.push(
|
|
1519
|
+
`${withSelector("CollateralAssetMismatch()")}: the market's collateral ${mp.collateralToken} is the pool's volatile leg \u2014 CL borrows the vault asset against the vault asset or an ERC-4626 wrapper of it (e.g. a USDG-loan market with USDG/sUSDG collateral)`
|
|
1520
|
+
);
|
|
1521
|
+
} else if (!sameAddress(mp.collateralToken, asset)) {
|
|
1522
|
+
const wa = state.collateral.wrapperAsset;
|
|
1523
|
+
if (!wa || !sameAddress(wa, asset)) {
|
|
1524
|
+
errors.push(
|
|
1525
|
+
`${withSelector("CollateralAssetMismatch()")}: the market's collateral ${mp.collateralToken} is neither the vault asset nor an ERC-4626 wrapper of it` + (wa ? ` (its asset() is ${wa})` : " (no ERC-4626 asset())")
|
|
1526
|
+
);
|
|
1527
|
+
}
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
const lendable = state.market.totalSupplyAssets > state.market.totalBorrowAssets ? state.market.totalSupplyAssets - state.market.totalBorrowAssets : 0n;
|
|
1531
|
+
if (!unknownMarket && inputs.borrowAmount > lendable) {
|
|
1532
|
+
errors.push(
|
|
1533
|
+
`${withSelector("BorrowExceedsLiquidity()")}: borrow ${fmt(inputs.borrowAmount)} exceeds the market's lendable ${fmt(lendable)}`
|
|
1534
|
+
);
|
|
1535
|
+
}
|
|
1536
|
+
let ltvBps = 0n;
|
|
1537
|
+
const lltvBps = mp.lltv * BPS / 10n ** 18n;
|
|
1538
|
+
if (!unknownMarket && inputs.collateralAmount > 0n) {
|
|
1539
|
+
const value = sameAddress(mp.collateralToken, asset) ? inputs.collateralAmount : state.collateral.value;
|
|
1540
|
+
if (value === null || value === 0n) {
|
|
1541
|
+
if (!sameAddress(mp.collateralToken, asset)) {
|
|
1542
|
+
errors.push(
|
|
1543
|
+
`${withSelector("CollateralValueUnavailable()")}: ${mp.collateralToken}.previewRedeem(previewDeposit(${inputs.collateralAmount})) is unreadable or zero`
|
|
1544
|
+
);
|
|
1545
|
+
}
|
|
1546
|
+
} else {
|
|
1547
|
+
ltvBps = inputs.borrowAmount * BPS / value;
|
|
1548
|
+
if (lltvBps < MIN_LLTV_BUFFER_BPS || ltvBps > lltvBps - MIN_LLTV_BUFFER_BPS) {
|
|
1549
|
+
const maxLtv = lltvBps >= MIN_LLTV_BUFFER_BPS ? lltvBps - MIN_LLTV_BUFFER_BPS : 0n;
|
|
1550
|
+
const maxBorrow = value * maxLtv / BPS;
|
|
1551
|
+
errors.push(
|
|
1552
|
+
`${withSelector("LtvInsideLiquidationBuffer()")}: LTV ${ltvBps} bps vs market LLTV ${lltvBps} bps \u2014 must be \u2264 ${maxLtv} bps (LLTV \u2212 ${MIN_LLTV_BUFFER_BPS} bps buffer); max borrow against ${fmt(inputs.collateralAmount)} collateral \u2248 ${fmt(maxBorrow)}`
|
|
1553
|
+
);
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
const spacing = pool.tickSpacing;
|
|
1558
|
+
let tickLower = 0;
|
|
1559
|
+
let tickUpper = 0;
|
|
1560
|
+
let rangeOk = false;
|
|
1561
|
+
if (poolUsable) {
|
|
1562
|
+
if ("pct" in inputs.range) {
|
|
1563
|
+
try {
|
|
1564
|
+
({ tickLower, tickUpper } = rangeFromPct(pool.tick, inputs.range.pct, spacing));
|
|
1565
|
+
} catch (e) {
|
|
1566
|
+
errors.push(e.message);
|
|
1567
|
+
}
|
|
1568
|
+
} else {
|
|
1569
|
+
({ tickLower, tickUpper } = inputs.range);
|
|
1570
|
+
}
|
|
1571
|
+
if (tickLower >= tickUpper || spacing <= 0 || tickLower % spacing !== 0 || tickUpper % spacing !== 0) {
|
|
1572
|
+
errors.push(
|
|
1573
|
+
`${withSelector("InvalidTickRange()")}: [${tickLower}, ${tickUpper}] must be ordered, non-empty and multiples of tickSpacing ${spacing}`
|
|
1574
|
+
);
|
|
1575
|
+
} else if (tickLower < MIN_TICK || tickUpper > MAX_TICK) {
|
|
1576
|
+
errors.push(`tick range [${tickLower}, ${tickUpper}] leaves the V3 domain [${MIN_TICK}, ${MAX_TICK}] \u2014 the mint would revert`);
|
|
1577
|
+
} else {
|
|
1578
|
+
rangeOk = true;
|
|
1579
|
+
}
|
|
1580
|
+
}
|
|
1581
|
+
const swapFractionBps = inputs.swapFractionBps ?? (rangeOk ? idealSwapFractionBps(pool.sqrtPriceX96, tickLower, tickUpper, assetIsToken0) : 0);
|
|
1582
|
+
const poolShareCap = pool.liquidity * MAX_POOL_SHARE_BPS / BPS;
|
|
1583
|
+
let expectedLiquidity = inputs.expectedLiquidity ?? 0n;
|
|
1584
|
+
if (inputs.expectedLiquidity === void 0 && rangeOk && pool.sqrtPriceX96 > 0n) {
|
|
1585
|
+
expectedLiquidity = estimateExpectedLiquidity({
|
|
1586
|
+
sqrtPriceX96: pool.sqrtPriceX96,
|
|
1587
|
+
tickLower,
|
|
1588
|
+
tickUpper,
|
|
1589
|
+
assetIsToken0,
|
|
1590
|
+
deployable: inputs.borrowAmount,
|
|
1591
|
+
swapFractionBps,
|
|
1592
|
+
poolFee: pool.fee
|
|
1593
|
+
});
|
|
1594
|
+
}
|
|
1595
|
+
if (poolUsable && rangeOk) {
|
|
1596
|
+
if (expectedLiquidity === 0n) {
|
|
1597
|
+
errors.push(`${withSelector("InvalidAmount()")}: expectedLiquidity is 0 \u2014 the borrow is too small to mint in this range`);
|
|
1598
|
+
} else if (expectedLiquidity > UINT128_MAX) {
|
|
1599
|
+
errors.push(`expectedLiquidity ${expectedLiquidity} does not fit uint128`);
|
|
1600
|
+
} else if (expectedLiquidity > poolShareCap) {
|
|
1601
|
+
const maxBorrow = inputs.borrowAmount * poolShareCap / expectedLiquidity;
|
|
1602
|
+
errors.push(
|
|
1603
|
+
`${withSelector("PositionExceedsPoolShareCap()")}: expected liquidity ${expectedLiquidity} exceeds ${MAX_POOL_SHARE_BPS} bps of the pool's in-range liquidity (${pool.liquidity} \u2192 cap ${poolShareCap}); at this range the borrow must stay under \u2248 ${fmt(maxBorrow)}`
|
|
1604
|
+
);
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
const bounds = [
|
|
1608
|
+
[inputs.twapWindow < MIN_TWAP_WINDOW, `--twap-window ${inputs.twapWindow} < MIN_TWAP_WINDOW ${MIN_TWAP_WINDOW}`],
|
|
1609
|
+
[
|
|
1610
|
+
inputs.maxTwapDeviationBps === 0 || inputs.maxTwapDeviationBps > MAX_TWAP_DEVIATION_BPS,
|
|
1611
|
+
`--max-twap-deviation ${inputs.maxTwapDeviationBps} must be in [1, ${MAX_TWAP_DEVIATION_BPS}]`
|
|
1612
|
+
],
|
|
1613
|
+
[
|
|
1614
|
+
inputs.mintSlippageBps === 0 || inputs.mintSlippageBps > MAX_SLIPPAGE_BPS,
|
|
1615
|
+
`--mint-slippage-bps ${inputs.mintSlippageBps} must be in [1, ${MAX_SLIPPAGE_BPS}]`
|
|
1616
|
+
],
|
|
1617
|
+
[
|
|
1618
|
+
inputs.settleSlippageBps === 0 || inputs.settleSlippageBps > MAX_SLIPPAGE_BPS,
|
|
1619
|
+
`--settle-slippage-bps ${inputs.settleSlippageBps} must be in [1, ${MAX_SLIPPAGE_BPS}] (0 is not a legal init value)`
|
|
1620
|
+
],
|
|
1621
|
+
[swapFractionBps < 0 || swapFractionBps > 1e4, `--swap-fraction-bps ${swapFractionBps} must be in [0, 10000]`]
|
|
1622
|
+
];
|
|
1623
|
+
for (const [bad, msg] of bounds) if (bad) errors.push(`${withSelector("InvalidBound()")}: ${msg}`);
|
|
1624
|
+
const halfWidthTicks = inputs.rerange.halfWidthTicks ?? Math.max(spacing, Math.ceil((tickUpper - tickLower) / 2));
|
|
1625
|
+
let rerangeSwapFraction = swapFractionBps;
|
|
1626
|
+
if (inputs.rerange.swapFractionBps !== void 0) {
|
|
1627
|
+
rerangeSwapFraction = inputs.rerange.swapFractionBps;
|
|
1628
|
+
} else if (poolUsable && rangeOk && pool.sqrtPriceX96 > 0n && halfWidthTicks >= spacing && halfWidthTicks <= MAX_HALF_WIDTH_TICKS) {
|
|
1629
|
+
const centred = derivedRerangeRange(pool.tick, halfWidthTicks, spacing);
|
|
1630
|
+
rerangeSwapFraction = idealSwapFractionBps(pool.sqrtPriceX96, centred.tickLower, centred.tickUpper, assetIsToken0);
|
|
1631
|
+
}
|
|
1632
|
+
if (poolUsable && rangeOk) {
|
|
1633
|
+
const policy = [
|
|
1634
|
+
[halfWidthTicks < spacing, `--rerange-half-width ${halfWidthTicks} < tickSpacing ${spacing}`],
|
|
1635
|
+
[
|
|
1636
|
+
halfWidthTicks * 2 < tickUpper - tickLower,
|
|
1637
|
+
`--rerange-half-width ${halfWidthTicks} \xD7 2 is narrower than the initial range (${tickUpper - tickLower} ticks)`
|
|
1638
|
+
],
|
|
1639
|
+
[halfWidthTicks > MAX_HALF_WIDTH_TICKS, `--rerange-half-width ${halfWidthTicks} > ${MAX_HALF_WIDTH_TICKS}`]
|
|
1640
|
+
];
|
|
1641
|
+
for (const [bad, msg] of policy) if (bad) errors.push(`${withSelector("InvalidRerangePolicy()")}: ${msg}`);
|
|
1642
|
+
}
|
|
1643
|
+
const policyBounds = [
|
|
1644
|
+
[
|
|
1645
|
+
inputs.rerange.triggerBps === 0 || inputs.rerange.triggerBps > 1e4,
|
|
1646
|
+
`--rerange-trigger-bps ${inputs.rerange.triggerBps} must be in [1, 10000]`
|
|
1647
|
+
],
|
|
1648
|
+
[inputs.rerange.maxReranges > MAX_RERANGE_LIMIT, `--max-reranges ${inputs.rerange.maxReranges} > ${MAX_RERANGE_LIMIT}`],
|
|
1649
|
+
[
|
|
1650
|
+
inputs.rerange.slippageBps === 0 || inputs.rerange.slippageBps > MAX_SLIPPAGE_BPS,
|
|
1651
|
+
`--rerange-slippage-bps ${inputs.rerange.slippageBps} must be in [1, ${MAX_SLIPPAGE_BPS}]`
|
|
1652
|
+
],
|
|
1653
|
+
[
|
|
1654
|
+
rerangeSwapFraction < 0 || rerangeSwapFraction > 1e4,
|
|
1655
|
+
`--rerange-swap-fraction-bps ${rerangeSwapFraction} must be in [0, 10000]`
|
|
1656
|
+
]
|
|
1657
|
+
];
|
|
1658
|
+
for (const [bad, msg] of policyBounds) if (bad) errors.push(`${withSelector("InvalidRerangePolicy()")}: ${msg}`);
|
|
1659
|
+
if (inputs.collateralAmount > 0n && state.vaultBalance < inputs.collateralAmount) {
|
|
1660
|
+
errors.push(
|
|
1661
|
+
`vault holds ${fmt(state.vaultBalance)} but execute pulls ${fmt(inputs.collateralAmount)} as collateral (amounts are human units)`
|
|
1662
|
+
);
|
|
1663
|
+
}
|
|
1664
|
+
if (poolUsable) {
|
|
1665
|
+
if (pool.observationCardinality < 2 || pool.twapTick === null) {
|
|
1666
|
+
warnings.push(
|
|
1667
|
+
`pool ${inputs.pool} cannot serve a ${inputs.twapWindow}s TWAP right now (observation cardinality ${pool.observationCardinality}) \u2014 execute() reverts ${withSelector("TwapUnavailable()")} until it can; raise it with pool.increaseObservationCardinalityNext(n) and wait out the window`
|
|
1668
|
+
);
|
|
1669
|
+
} else {
|
|
1670
|
+
const dev = Math.abs(pool.tick - pool.twapTick);
|
|
1671
|
+
if (dev > inputs.maxTwapDeviationBps) {
|
|
1672
|
+
warnings.push(
|
|
1673
|
+
`spot tick ${pool.tick} is ${dev} ticks from the ${inputs.twapWindow}s TWAP ${pool.twapTick} (bound ${inputs.maxTwapDeviationBps}) \u2014 execute() would revert ${withSelector("SpotOutsideTwapBound()")} if it ran now`
|
|
1674
|
+
);
|
|
1675
|
+
}
|
|
1676
|
+
}
|
|
1677
|
+
}
|
|
1678
|
+
if (poolUsable && rangeOk && pool.sqrtPriceX96 > 0n && expectedLiquidity > 0n && expectedLiquidity <= UINT128_MAX) {
|
|
1679
|
+
const sqrtA = getSqrtRatioAtTick(tickLower);
|
|
1680
|
+
const sqrtB = getSqrtRatioAtTick(tickUpper);
|
|
1681
|
+
const otherIsToken0 = !assetIsToken0;
|
|
1682
|
+
const pick = (a) => otherIsToken0 ? a.amount0 : a.amount1;
|
|
1683
|
+
const legNow = pick(amountsForLiquidity(pool.sqrtPriceX96, sqrtA, sqrtB, expectedLiquidity));
|
|
1684
|
+
const edgeSqrt = otherIsToken0 ? sqrtA : sqrtB;
|
|
1685
|
+
const legEdge = pick(amountsForLiquidity(edgeSqrt, sqrtA, sqrtB, expectedLiquidity));
|
|
1686
|
+
const impact = (sqrt, amountIn, tokenInIsToken0) => estimateSwapImpactBps({ sqrtPriceX96: sqrt, liquidity: pool.liquidity, amountIn, tokenInIsToken0, poolFee: pool.fee });
|
|
1687
|
+
const settleNow = impact(pool.sqrtPriceX96, legNow, otherIsToken0);
|
|
1688
|
+
const settleEdge = impact(edgeSqrt, legEdge, otherIsToken0);
|
|
1689
|
+
const settle = BigInt(inputs.settleSlippageBps);
|
|
1690
|
+
const approx = `(constant in-range liquidity ${pool.liquidity}, no tick crossings, pool route only \u2014 an estimate)`;
|
|
1691
|
+
const suggest = (bps) => Math.min(MAX_SLIPPAGE_BPS, Math.ceil(bps * 1e4 / Number(IMPACT_WARN_SHARE_BPS)));
|
|
1692
|
+
if (BigInt(settleNow) * BPS > settle * IMPACT_WARN_SHARE_BPS) {
|
|
1693
|
+
warnings.push(
|
|
1694
|
+
`settle sells the volatile leg (~${legNow} base units of ${otherToken} at today's price) through this pool with an estimated ${settleNow} bps price impact ${approx} \u2014 more than 70% of --settle-slippage-bps ${inputs.settleSlippageBps}, so settle() can revert on its own slippage floor. Settle slippage can only be tightened after init: consider --settle-slippage-bps ${suggest(settleNow)} or a smaller borrow`
|
|
1695
|
+
);
|
|
1696
|
+
} else if (BigInt(settleEdge) * BPS > settle * BPS) {
|
|
1697
|
+
warnings.push(
|
|
1698
|
+
`if price reaches the range edge on the volatile side, settle sells the whole position (~${legEdge} base units of ${otherToken}) with an estimated ${settleEdge} bps impact ${approx} \u2014 above --settle-slippage-bps ${inputs.settleSlippageBps}, which can only be tightened after init; consider --settle-slippage-bps ${suggest(settleEdge)} or a smaller borrow`
|
|
1699
|
+
);
|
|
1700
|
+
}
|
|
1701
|
+
const swapped = inputs.borrowAmount * BigInt(swapFractionBps) / BPS;
|
|
1702
|
+
const mintImpact = impact(pool.sqrtPriceX96, swapped, assetIsToken0);
|
|
1703
|
+
if (BigInt(mintImpact) * BPS > BigInt(inputs.mintSlippageBps) * IMPACT_WARN_SHARE_BPS) {
|
|
1704
|
+
warnings.push(
|
|
1705
|
+
`execute swaps ${fmt(swapped)} into ${otherToken} through this pool with an estimated ${mintImpact} bps price impact ${approx} \u2014 more than 70% of --mint-slippage-bps ${inputs.mintSlippageBps}; execute() can revert on its slippage floor. Consider --mint-slippage-bps ${suggest(mintImpact)} or a smaller borrow`
|
|
1706
|
+
);
|
|
1707
|
+
}
|
|
1708
|
+
if (poolShareCap > 0n && expectedLiquidity <= poolShareCap && expectedLiquidity * BPS > poolShareCap * POOL_SHARE_WARN_BPS) {
|
|
1709
|
+
const pct = Number(expectedLiquidity * 1000n / poolShareCap) / 10;
|
|
1710
|
+
warnings.push(
|
|
1711
|
+
`expected liquidity ${expectedLiquidity} is ${pct}% of the pool-share cap ${poolShareCap} (${MAX_POOL_SHARE_BPS} bps of in-range liquidity ${pool.liquidity}). execute() re-checks the ACTUAL minted liquidity against the pool as it is then; a small drop in pool liquidity (or a mint above the estimate) reverts ${withSelector("PositionExceedsPoolShareCap()")} \u2014 leave more headroom`
|
|
1712
|
+
);
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
1715
|
+
if (errors.length > 0) return { plan: null, errors, warnings };
|
|
1716
|
+
const params = {
|
|
1717
|
+
pool: inputs.pool,
|
|
1718
|
+
positionManager: inputs.positionManager,
|
|
1719
|
+
uniswapFactory: inputs.uniswapFactory,
|
|
1720
|
+
swapAdapter: inputs.swapAdapter,
|
|
1721
|
+
morpho: inputs.morpho,
|
|
1722
|
+
marketParams: mp,
|
|
1723
|
+
collateralAmount: inputs.collateralAmount,
|
|
1724
|
+
borrowAmount: inputs.borrowAmount,
|
|
1725
|
+
tickLower,
|
|
1726
|
+
tickUpper,
|
|
1727
|
+
expectedLiquidity,
|
|
1728
|
+
swapFractionBps: BigInt(swapFractionBps),
|
|
1729
|
+
twapWindow: inputs.twapWindow,
|
|
1730
|
+
maxTwapDeviationBps: BigInt(inputs.maxTwapDeviationBps),
|
|
1731
|
+
mintSlippageBps: BigInt(inputs.mintSlippageBps),
|
|
1732
|
+
rerange: {
|
|
1733
|
+
halfWidthTicks,
|
|
1734
|
+
triggerBps: BigInt(inputs.rerange.triggerBps),
|
|
1735
|
+
minInterval: inputs.rerange.minInterval,
|
|
1736
|
+
maxReranges: BigInt(inputs.rerange.maxReranges),
|
|
1737
|
+
slippageBps: BigInt(inputs.rerange.slippageBps),
|
|
1738
|
+
swapFractionBps: BigInt(rerangeSwapFraction)
|
|
1739
|
+
},
|
|
1740
|
+
settleSlippageBps: BigInt(inputs.settleSlippageBps),
|
|
1741
|
+
settleDeadline: inputs.settleDeadline,
|
|
1742
|
+
swapExtraData: inputs.swapExtraData ?? v3SingleHopExtraData(pool.fee)
|
|
1743
|
+
};
|
|
1744
|
+
return {
|
|
1745
|
+
plan: {
|
|
1746
|
+
params,
|
|
1747
|
+
asset,
|
|
1748
|
+
otherToken,
|
|
1749
|
+
assetIsToken0,
|
|
1750
|
+
info: { ltvBps, lltvBps, poolShareCap, spotTick: pool.tick, twapTick: pool.twapTick }
|
|
1751
|
+
},
|
|
1752
|
+
errors,
|
|
1753
|
+
warnings
|
|
1754
|
+
};
|
|
1755
|
+
}
|
|
1756
|
+
|
|
920
1757
|
// src/lib/template-encoder.ts
|
|
921
1758
|
var ZERO = "0x0000000000000000000000000000000000000000";
|
|
922
1759
|
function encodeV3Path(tokens, fees) {
|
|
@@ -933,13 +1770,13 @@ function encodeV3Path(tokens, fees) {
|
|
|
933
1770
|
function buildSwapExtraData(network, tokenIn, tokenOut, feeTier, hop, perHopSlippageBps = 100) {
|
|
934
1771
|
if (hop) {
|
|
935
1772
|
const path = encodeV3Path([tokenIn, hop.via, tokenOut], [hop.feeIn, hop.feeOut]);
|
|
936
|
-
const encoded2 =
|
|
1773
|
+
const encoded2 = encodeAbiParameters12(
|
|
937
1774
|
[{ type: "bytes" }, { type: "uint16" }],
|
|
938
1775
|
[path, perHopSlippageBps]
|
|
939
1776
|
);
|
|
940
1777
|
return `0x01${encoded2.slice(2)}`;
|
|
941
1778
|
}
|
|
942
|
-
const encoded =
|
|
1779
|
+
const encoded = encodeAbiParameters12([{ type: "uint24" }], [feeTier]);
|
|
943
1780
|
return `0x00${encoded.slice(2)}`;
|
|
944
1781
|
}
|
|
945
1782
|
function parseSwapRouteSpec(spec, token) {
|
|
@@ -973,7 +1810,7 @@ function parseSwapRouteSpec(spec, token) {
|
|
|
973
1810
|
let currency;
|
|
974
1811
|
if (c === "eth" || c === "native") currency = ZERO;
|
|
975
1812
|
else if (c === "self") currency = token;
|
|
976
|
-
else if (
|
|
1813
|
+
else if (isAddress2(currencyRaw.trim())) currency = currencyRaw.trim();
|
|
977
1814
|
else throw new Error(`bad v4path currency '${currencyRaw}' in '${spec}' (use eth/native/self/0x-address)`);
|
|
978
1815
|
return { currency, fee, tickSpacing };
|
|
979
1816
|
});
|
|
@@ -996,14 +1833,14 @@ function computeProposalAssetChecks(templateKey, opts) {
|
|
|
996
1833
|
const token = opts.token || "USDC";
|
|
997
1834
|
const asset = resolveToken(token);
|
|
998
1835
|
const decimals = assetDecimalsForSymbol(token);
|
|
999
|
-
return [{ asset, amount:
|
|
1836
|
+
return [{ asset, amount: parseUnits2(opts.amount, decimals), label: token.toUpperCase() }];
|
|
1000
1837
|
}
|
|
1001
1838
|
if (templateKey === "venice-inference") {
|
|
1002
1839
|
if (!opts.amount) return [];
|
|
1003
1840
|
const assetSymbol = opts.asset || "USDC";
|
|
1004
1841
|
const asset = resolveToken(assetSymbol);
|
|
1005
1842
|
const decimals = assetDecimalsForSymbol(assetSymbol);
|
|
1006
|
-
return [{ asset, amount:
|
|
1843
|
+
return [{ asset, amount: parseUnits2(opts.amount, decimals), label: assetSymbol.toUpperCase() }];
|
|
1007
1844
|
}
|
|
1008
1845
|
if (templateKey === "aerodrome-lp") {
|
|
1009
1846
|
if (!opts.tokenA || !opts.tokenB || !opts.amountA || !opts.amountB) return [];
|
|
@@ -1013,7 +1850,7 @@ function computeProposalAssetChecks(templateKey, opts) {
|
|
|
1013
1850
|
if (!opts.amount) return [];
|
|
1014
1851
|
return [{
|
|
1015
1852
|
asset: TOKENS().WETH,
|
|
1016
|
-
amount:
|
|
1853
|
+
amount: parseUnits2(opts.amount, 18),
|
|
1017
1854
|
label: "WETH"
|
|
1018
1855
|
}];
|
|
1019
1856
|
}
|
|
@@ -1022,14 +1859,25 @@ function computeProposalAssetChecks(templateKey, opts) {
|
|
|
1022
1859
|
const assetSymbol = opts.asset || defaultPortfolioAsset();
|
|
1023
1860
|
const asset = resolveToken(assetSymbol);
|
|
1024
1861
|
const decimals = assetDecimalsForSymbol(assetSymbol);
|
|
1025
|
-
return [{ asset, amount:
|
|
1862
|
+
return [{ asset, amount: parseUnits2(opts.amount, decimals), label: assetSymbol.toUpperCase() }];
|
|
1026
1863
|
}
|
|
1027
1864
|
if (templateKey === "hyperliquid-perp" || templateKey === "hyperliquid-grid") {
|
|
1028
1865
|
if (!opts.amount) return [];
|
|
1029
1866
|
const token = opts.token || "USDC";
|
|
1030
1867
|
const asset = resolveToken(token);
|
|
1031
1868
|
const decimals = assetDecimalsForSymbol(token);
|
|
1032
|
-
return [{ asset, amount:
|
|
1869
|
+
return [{ asset, amount: parseUnits2(opts.amount, decimals), label: token.toUpperCase() }];
|
|
1870
|
+
}
|
|
1871
|
+
if (templateKey === "lighter-perp") {
|
|
1872
|
+
const human = opts.deposit ?? opts.amount;
|
|
1873
|
+
if (!human) return [];
|
|
1874
|
+
let amount;
|
|
1875
|
+
try {
|
|
1876
|
+
amount = usdgToTicks(human);
|
|
1877
|
+
} catch {
|
|
1878
|
+
return [];
|
|
1879
|
+
}
|
|
1880
|
+
return [{ asset: LIGHTER_USDG, amount, label: "USDG" }];
|
|
1033
1881
|
}
|
|
1034
1882
|
return [];
|
|
1035
1883
|
}
|
|
@@ -1048,11 +1896,11 @@ async function buildInitDataForTemplate(templateKey, opts, vault, resolved) {
|
|
|
1048
1896
|
const underlying = resolveToken(token);
|
|
1049
1897
|
const mToken = resolveMToken(token);
|
|
1050
1898
|
const decimals = assetDecimalsForSymbol(token);
|
|
1051
|
-
const supplyAmount =
|
|
1052
|
-
const minRedeem =
|
|
1899
|
+
const supplyAmount = parseUnits2(opts.amount, decimals);
|
|
1900
|
+
const minRedeem = parseUnits2(opts.minRedeem || opts.amount, decimals);
|
|
1053
1901
|
const isNativeEthMarket = token.toUpperCase() !== "USDC";
|
|
1054
1902
|
return {
|
|
1055
|
-
initData:
|
|
1903
|
+
initData: buildInitData3(underlying, mToken, supplyAmount, minRedeem, isNativeEthMarket),
|
|
1056
1904
|
asset: underlying,
|
|
1057
1905
|
assetAmount: supplyAmount
|
|
1058
1906
|
};
|
|
@@ -1067,7 +1915,7 @@ async function buildInitDataForTemplate(templateKey, opts, vault, resolved) {
|
|
|
1067
1915
|
const vvv = VENICE().VVV;
|
|
1068
1916
|
const isDirect = asset.toLowerCase() === vvv.toLowerCase();
|
|
1069
1917
|
const decimals = assetDecimalsForSymbol(assetSymbol);
|
|
1070
|
-
const assetAmount =
|
|
1918
|
+
const assetAmount = parseUnits2(opts.amount, decimals);
|
|
1071
1919
|
const agent = opts.agent || resolved?.veniceAgent;
|
|
1072
1920
|
if (!agent) {
|
|
1073
1921
|
throw new Error(
|
|
@@ -1078,7 +1926,7 @@ async function buildInitDataForTemplate(templateKey, opts, vault, resolved) {
|
|
|
1078
1926
|
let minVVV = 0n;
|
|
1079
1927
|
if (!isDirect) {
|
|
1080
1928
|
if (opts.minVvv) {
|
|
1081
|
-
minVVV =
|
|
1929
|
+
minVVV = parseUnits2(opts.minVvv, 18);
|
|
1082
1930
|
} else if (resolved?.veniceMinVVV !== void 0) {
|
|
1083
1931
|
minVVV = resolved.veniceMinVVV;
|
|
1084
1932
|
} else {
|
|
@@ -1101,7 +1949,7 @@ async function buildInitDataForTemplate(templateKey, opts, vault, resolved) {
|
|
|
1101
1949
|
singleHop: isSingleHop
|
|
1102
1950
|
};
|
|
1103
1951
|
return {
|
|
1104
|
-
initData:
|
|
1952
|
+
initData: buildInitData4(params),
|
|
1105
1953
|
asset,
|
|
1106
1954
|
assetAmount
|
|
1107
1955
|
};
|
|
@@ -1121,10 +1969,10 @@ async function buildInitDataForTemplate(templateKey, opts, vault, resolved) {
|
|
|
1121
1969
|
);
|
|
1122
1970
|
}
|
|
1123
1971
|
const { decimalsA, decimalsB } = resolved.aerodromeDecimals;
|
|
1124
|
-
const amountA =
|
|
1125
|
-
const amountB =
|
|
1126
|
-
const minAOut =
|
|
1127
|
-
const minBOut =
|
|
1972
|
+
const amountA = parseUnits2(opts.amountA, decimalsA);
|
|
1973
|
+
const amountB = parseUnits2(opts.amountB, decimalsB);
|
|
1974
|
+
const minAOut = parseUnits2(opts.minAOut || "0", decimalsA);
|
|
1975
|
+
const minBOut = parseUnits2(opts.minBOut || "0", decimalsB);
|
|
1128
1976
|
const params = {
|
|
1129
1977
|
tokenA,
|
|
1130
1978
|
tokenB,
|
|
@@ -1142,14 +1990,14 @@ async function buildInitDataForTemplate(templateKey, opts, vault, resolved) {
|
|
|
1142
1990
|
minAmountBOut: minBOut
|
|
1143
1991
|
};
|
|
1144
1992
|
return {
|
|
1145
|
-
initData:
|
|
1993
|
+
initData: buildInitData5(params),
|
|
1146
1994
|
asset: tokenA,
|
|
1147
1995
|
assetAmount: amountA,
|
|
1148
1996
|
extraApprovals: [{ token: tokenB, amount: amountB }]
|
|
1149
1997
|
};
|
|
1150
1998
|
}
|
|
1151
1999
|
if (templateKey === "wsteth-moonwell") {
|
|
1152
|
-
const supplyAmount = opts.amount ?
|
|
2000
|
+
const supplyAmount = opts.amount ? parseUnits2(opts.amount, 18) : 0n;
|
|
1153
2001
|
const slippageBps = BigInt(opts.slippage || "500");
|
|
1154
2002
|
const ONE = 10n ** 18n;
|
|
1155
2003
|
const minWstethOutPerWeth = ONE * (10000n - slippageBps) / 10000n;
|
|
@@ -1167,7 +2015,7 @@ async function buildInitDataForTemplate(templateKey, opts, vault, resolved) {
|
|
|
1167
2015
|
deadlineOffset: 300n
|
|
1168
2016
|
};
|
|
1169
2017
|
return {
|
|
1170
|
-
initData:
|
|
2018
|
+
initData: buildInitData6(params),
|
|
1171
2019
|
asset: TOKENS().WETH,
|
|
1172
2020
|
assetAmount: supplyAmount
|
|
1173
2021
|
};
|
|
@@ -1184,10 +2032,10 @@ async function buildInitDataForTemplate(templateKey, opts, vault, resolved) {
|
|
|
1184
2032
|
const token = opts.token || "USDC";
|
|
1185
2033
|
const underlying = resolveToken(token);
|
|
1186
2034
|
const decimals = assetDecimalsForSymbol(token);
|
|
1187
|
-
const amount =
|
|
1188
|
-
const minRedeemAmount =
|
|
2035
|
+
const amount = parseUnits2(opts.amount, decimals);
|
|
2036
|
+
const minRedeemAmount = parseUnits2(opts.minRedeem || opts.amount, decimals);
|
|
1189
2037
|
return {
|
|
1190
|
-
initData:
|
|
2038
|
+
initData: buildInitData7(underlying, opts.mamoFactory, minRedeemAmount),
|
|
1191
2039
|
asset: underlying,
|
|
1192
2040
|
assetAmount: amount
|
|
1193
2041
|
};
|
|
@@ -1226,12 +2074,12 @@ async function buildInitDataForTemplate(templateKey, opts, vault, resolved) {
|
|
|
1226
2074
|
const assetSymbol = opts.asset || defaultPortfolioAsset();
|
|
1227
2075
|
const asset = resolveToken(assetSymbol);
|
|
1228
2076
|
const decimals = assetDecimalsForSymbol(assetSymbol);
|
|
1229
|
-
const totalAmount =
|
|
2077
|
+
const totalAmount = parseUnits2(opts.amount, decimals);
|
|
1230
2078
|
const maxSlippageBps = Number(opts.maxSlippage || "500");
|
|
1231
2079
|
const feeTier = opts.feeTier || "3000";
|
|
1232
2080
|
const tokenSpecs = opts.tokens.split(",").map((t) => t.trim());
|
|
1233
2081
|
const tokenAddrs = tokenSpecs.map((trimmed) => {
|
|
1234
|
-
if (
|
|
2082
|
+
if (isAddress2(trimmed)) return trimmed;
|
|
1235
2083
|
const allTokens = tokens;
|
|
1236
2084
|
const resolvedAddr = allTokens[trimmed.toUpperCase()];
|
|
1237
2085
|
if (resolvedAddr && resolvedAddr !== ZERO) return resolvedAddr;
|
|
@@ -1314,14 +2162,14 @@ async function buildInitDataForTemplate(templateKey, opts, vault, resolved) {
|
|
|
1314
2162
|
console.log(chalk.dim(` ${token.slice(0, 10)}... \u2192 ${route.routeDesc}`));
|
|
1315
2163
|
const priceDecimals2 = priceDecimalOverrides[i] ? Number(priceDecimalOverrides[i]) : 8;
|
|
1316
2164
|
let feed = feedOverrides[i];
|
|
1317
|
-
if (feed && !
|
|
2165
|
+
if (feed && !isAddress2(feed)) {
|
|
1318
2166
|
console.error(chalk.red(`Bad --feeds entry for ${tokenSpecs[i]}: '${feed}' is not a 0x-prefixed AggregatorV3 address.`));
|
|
1319
2167
|
process.exit(1);
|
|
1320
2168
|
}
|
|
1321
2169
|
if (!feed) {
|
|
1322
2170
|
const sym = tokenSpecs[i].toUpperCase();
|
|
1323
2171
|
const feedKey = sym === "WETH" || sym === "ETH" ? "ETH_USD_FEED" : `${sym}_USD_FEED`;
|
|
1324
|
-
feed =
|
|
2172
|
+
feed = isAddress2(tokenSpecs[i]) ? void 0 : chainlink[feedKey];
|
|
1325
2173
|
}
|
|
1326
2174
|
if (!feed || feed === ZERO) {
|
|
1327
2175
|
console.error(chalk.red(`No Chainlink push feed for ${tokenSpecs[i]} on ${network}. Pass --feeds <feedAddr,...> to supply AggregatorV3 addresses (every slot must be non-zero).`));
|
|
@@ -1336,7 +2184,7 @@ async function buildInitDataForTemplate(templateKey, opts, vault, resolved) {
|
|
|
1336
2184
|
});
|
|
1337
2185
|
}
|
|
1338
2186
|
return {
|
|
1339
|
-
initData:
|
|
2187
|
+
initData: buildInitData8(asset, swapAdapter, allocations, totalAmount, maxSlippageBps),
|
|
1340
2188
|
asset,
|
|
1341
2189
|
assetAmount: totalAmount
|
|
1342
2190
|
};
|
|
@@ -1345,13 +2193,13 @@ async function buildInitDataForTemplate(templateKey, opts, vault, resolved) {
|
|
|
1345
2193
|
const token = opts.token || "USDC";
|
|
1346
2194
|
const asset = resolveToken(token);
|
|
1347
2195
|
const decimals = assetDecimalsForSymbol(token);
|
|
1348
|
-
const depositAmount = opts.amount ?
|
|
2196
|
+
const depositAmount = opts.amount ? parseUnits2(opts.amount, decimals) : 0n;
|
|
1349
2197
|
const leverage = Number(opts.leverage || "10");
|
|
1350
2198
|
const assetIndex = Number(opts.assetIndex || "0");
|
|
1351
|
-
const maxPosition =
|
|
2199
|
+
const maxPosition = parseUnits2(opts.maxPosition || "100000", decimals);
|
|
1352
2200
|
const maxTradesDay = Number(opts.maxTradesPerDay || "50");
|
|
1353
2201
|
return {
|
|
1354
|
-
initData:
|
|
2202
|
+
initData: buildInitData9(asset, depositAmount, assetIndex, leverage, maxPosition, maxTradesDay),
|
|
1355
2203
|
asset,
|
|
1356
2204
|
assetAmount: depositAmount
|
|
1357
2205
|
};
|
|
@@ -1360,68 +2208,139 @@ async function buildInitDataForTemplate(templateKey, opts, vault, resolved) {
|
|
|
1360
2208
|
const token = opts.token || "USDC";
|
|
1361
2209
|
const asset = resolveToken(token);
|
|
1362
2210
|
const decimals = assetDecimalsForSymbol(token);
|
|
1363
|
-
const depositAmount = opts.amount ?
|
|
2211
|
+
const depositAmount = opts.amount ? parseUnits2(opts.amount, decimals) : 0n;
|
|
1364
2212
|
const leverage = Number(opts.leverage || "5");
|
|
1365
|
-
const maxOrderSize =
|
|
2213
|
+
const maxOrderSize = parseUnits2(opts.maxOrderSize || "10000", decimals);
|
|
1366
2214
|
const maxOrdersPerTick = Number(opts.maxOrdersPerTick || "20");
|
|
1367
2215
|
const assetIndices = (opts.assetIndices || "0").split(",").map((s) => Number(s.trim())).filter((n) => !Number.isNaN(n));
|
|
1368
2216
|
return {
|
|
1369
|
-
initData:
|
|
2217
|
+
initData: buildInitData10(asset, depositAmount, leverage, maxOrderSize, maxOrdersPerTick, assetIndices),
|
|
1370
2218
|
asset,
|
|
1371
2219
|
assetAmount: depositAmount
|
|
1372
2220
|
};
|
|
1373
2221
|
}
|
|
2222
|
+
if (templateKey === "lighter-perp") {
|
|
2223
|
+
const params = parseLighterTemplateFlags(
|
|
2224
|
+
{
|
|
2225
|
+
pubkey: opts.pubkey,
|
|
2226
|
+
keyIndex: opts.keyIndex,
|
|
2227
|
+
markets: opts.markets,
|
|
2228
|
+
deposit: opts.deposit,
|
|
2229
|
+
amount: opts.amount
|
|
2230
|
+
},
|
|
2231
|
+
resolved?.lighterSavedKey
|
|
2232
|
+
);
|
|
2233
|
+
return {
|
|
2234
|
+
initData: buildInitData(params),
|
|
2235
|
+
asset: LIGHTER_USDG,
|
|
2236
|
+
assetAmount: params.depositAmount
|
|
2237
|
+
};
|
|
2238
|
+
}
|
|
2239
|
+
if (templateKey === "launchpad") {
|
|
2240
|
+
if (!resolved?.launchpad) {
|
|
2241
|
+
throw new Error("launchpad: missing resolved chain inputs \u2014 run resolveChainInputsForTemplate before encoding");
|
|
2242
|
+
}
|
|
2243
|
+
const { params } = buildLaunchpadInitParams(opts, resolved.launchpad);
|
|
2244
|
+
return {
|
|
2245
|
+
initData: buildInitData2(params),
|
|
2246
|
+
asset: resolved.launchpad.asset,
|
|
2247
|
+
assetAmount: params.assetIn,
|
|
2248
|
+
maxDrawdownBps: resolved.launchpad.maxDrawdownBps
|
|
2249
|
+
};
|
|
2250
|
+
}
|
|
2251
|
+
if (templateKey === "morpho-supply") {
|
|
2252
|
+
const plan = resolved?.morphoSupply;
|
|
2253
|
+
if (!plan) throw new Error("morpho-supply: missing resolved market plan \u2014 resolve chain inputs before encoding");
|
|
2254
|
+
return {
|
|
2255
|
+
initData: buildInitData11(plan.morpho, plan.marketParams, plan.supplyAmount),
|
|
2256
|
+
asset: plan.asset,
|
|
2257
|
+
assetAmount: plan.supplyAmount
|
|
2258
|
+
};
|
|
2259
|
+
}
|
|
2260
|
+
if (templateKey === "concentrated-liquidity") {
|
|
2261
|
+
const plan = resolved?.concentratedLiquidity;
|
|
2262
|
+
if (!plan) throw new Error("concentrated-liquidity: missing resolved pool/market plan \u2014 resolve chain inputs before encoding");
|
|
2263
|
+
return {
|
|
2264
|
+
initData: buildInitData12(plan.params),
|
|
2265
|
+
asset: plan.asset,
|
|
2266
|
+
assetAmount: plan.params.collateralAmount
|
|
2267
|
+
};
|
|
2268
|
+
}
|
|
1374
2269
|
throw new Error(`No init builder for template: ${templateKey}`);
|
|
1375
2270
|
}
|
|
1376
2271
|
function buildCallsForTemplate(templateKey, clone, asset, assetAmount, extraApprovals) {
|
|
1377
2272
|
if (templateKey === "moonwell-supply") {
|
|
1378
2273
|
return {
|
|
1379
|
-
executeCalls:
|
|
1380
|
-
settleCalls:
|
|
2274
|
+
executeCalls: buildExecuteCalls3(clone, asset, assetAmount),
|
|
2275
|
+
settleCalls: buildSettleCalls3(clone)
|
|
1381
2276
|
};
|
|
1382
2277
|
}
|
|
1383
2278
|
if (templateKey === "venice-inference") {
|
|
1384
2279
|
return {
|
|
1385
|
-
executeCalls:
|
|
1386
|
-
settleCalls:
|
|
2280
|
+
executeCalls: buildExecuteCalls4(clone, asset, assetAmount),
|
|
2281
|
+
settleCalls: buildSettleCalls4(clone)
|
|
1387
2282
|
};
|
|
1388
2283
|
}
|
|
1389
2284
|
if (templateKey === "aerodrome-lp") {
|
|
1390
2285
|
const tokenB = extraApprovals?.[0]?.token ?? ZERO;
|
|
1391
2286
|
const amountB = extraApprovals?.[0]?.amount ?? 0n;
|
|
1392
2287
|
return {
|
|
1393
|
-
executeCalls:
|
|
1394
|
-
settleCalls:
|
|
2288
|
+
executeCalls: buildExecuteCalls5(clone, asset, assetAmount, tokenB, amountB),
|
|
2289
|
+
settleCalls: buildSettleCalls5(clone)
|
|
1395
2290
|
};
|
|
1396
2291
|
}
|
|
1397
2292
|
if (templateKey === "wsteth-moonwell") {
|
|
1398
2293
|
return {
|
|
1399
|
-
executeCalls:
|
|
1400
|
-
settleCalls:
|
|
2294
|
+
executeCalls: buildExecuteCalls6(clone, asset, assetAmount),
|
|
2295
|
+
settleCalls: buildSettleCalls6(clone)
|
|
1401
2296
|
};
|
|
1402
2297
|
}
|
|
1403
2298
|
if (templateKey === "mamo-yield") {
|
|
1404
2299
|
return {
|
|
1405
|
-
executeCalls:
|
|
1406
|
-
settleCalls:
|
|
2300
|
+
executeCalls: buildExecuteCalls7(clone, asset, assetAmount),
|
|
2301
|
+
settleCalls: buildSettleCalls7(clone)
|
|
1407
2302
|
};
|
|
1408
2303
|
}
|
|
1409
2304
|
if (templateKey === "portfolio") {
|
|
1410
2305
|
return {
|
|
1411
|
-
executeCalls:
|
|
1412
|
-
settleCalls:
|
|
2306
|
+
executeCalls: buildExecuteCalls8(clone, asset, assetAmount),
|
|
2307
|
+
settleCalls: buildSettleCalls8(clone)
|
|
1413
2308
|
};
|
|
1414
2309
|
}
|
|
1415
2310
|
if (templateKey === "hyperliquid-perp") {
|
|
1416
2311
|
return {
|
|
1417
|
-
executeCalls:
|
|
1418
|
-
settleCalls:
|
|
2312
|
+
executeCalls: buildExecuteCalls9(clone, asset, assetAmount),
|
|
2313
|
+
settleCalls: buildSettleCalls9(clone)
|
|
1419
2314
|
};
|
|
1420
2315
|
}
|
|
1421
2316
|
if (templateKey === "hyperliquid-grid") {
|
|
1422
2317
|
return {
|
|
1423
|
-
executeCalls:
|
|
1424
|
-
settleCalls:
|
|
2318
|
+
executeCalls: buildExecuteCalls10(clone, asset, assetAmount),
|
|
2319
|
+
settleCalls: buildSettleCalls10(clone)
|
|
2320
|
+
};
|
|
2321
|
+
}
|
|
2322
|
+
if (templateKey === "lighter-perp") {
|
|
2323
|
+
return {
|
|
2324
|
+
executeCalls: buildExecuteCalls(clone, asset, assetAmount),
|
|
2325
|
+
settleCalls: buildSettleCalls(clone)
|
|
2326
|
+
};
|
|
2327
|
+
}
|
|
2328
|
+
if (templateKey === "launchpad") {
|
|
2329
|
+
return {
|
|
2330
|
+
executeCalls: buildExecuteCalls2(clone, asset, assetAmount),
|
|
2331
|
+
settleCalls: buildSettleCalls2(clone)
|
|
2332
|
+
};
|
|
2333
|
+
}
|
|
2334
|
+
if (templateKey === "morpho-supply") {
|
|
2335
|
+
return {
|
|
2336
|
+
executeCalls: buildExecuteCalls11(clone, asset, assetAmount),
|
|
2337
|
+
settleCalls: buildSettleCalls11(clone)
|
|
2338
|
+
};
|
|
2339
|
+
}
|
|
2340
|
+
if (templateKey === "concentrated-liquidity") {
|
|
2341
|
+
return {
|
|
2342
|
+
executeCalls: buildExecuteCalls12(clone, asset, assetAmount),
|
|
2343
|
+
settleCalls: buildSettleCalls12(clone)
|
|
1425
2344
|
};
|
|
1426
2345
|
}
|
|
1427
2346
|
throw new Error(`No call builder for template: ${templateKey}`);
|
|
@@ -1438,7 +2357,7 @@ function resolveSwapAdapter() {
|
|
|
1438
2357
|
process.exit(1);
|
|
1439
2358
|
}
|
|
1440
2359
|
function resolveToken(symbolOrAddress) {
|
|
1441
|
-
if (
|
|
2360
|
+
if (isAddress2(symbolOrAddress)) return symbolOrAddress;
|
|
1442
2361
|
const upper = symbolOrAddress.toUpperCase();
|
|
1443
2362
|
const tokenMap = {
|
|
1444
2363
|
...TOKENS(),
|
|
@@ -1545,7 +2464,7 @@ async function selectBestFeeTier(params, deps = {}) {
|
|
|
1545
2464
|
}
|
|
1546
2465
|
async function getQuote(params, deps = {}) {
|
|
1547
2466
|
const client = deps.client ?? getPublicClient();
|
|
1548
|
-
const calldata =
|
|
2467
|
+
const calldata = encodeFunctionData11({
|
|
1549
2468
|
abi: UNISWAP_QUOTER_V2_ABI,
|
|
1550
2469
|
functionName: "quoteExactInputSingle",
|
|
1551
2470
|
args: [
|
|
@@ -1571,7 +2490,7 @@ async function getQuote(params, deps = {}) {
|
|
|
1571
2490
|
}
|
|
1572
2491
|
async function getMultiHopQuote(params, deps = {}) {
|
|
1573
2492
|
const client = deps.client ?? getPublicClient();
|
|
1574
|
-
const calldata =
|
|
2493
|
+
const calldata = encodeFunctionData11({
|
|
1575
2494
|
abi: UNISWAP_QUOTER_V2_ABI,
|
|
1576
2495
|
functionName: "quoteExactInput",
|
|
1577
2496
|
args: [params.path, params.amountIn]
|
|
@@ -1599,6 +2518,24 @@ function encodeSwapPath(tokens, fees) {
|
|
|
1599
2518
|
|
|
1600
2519
|
export {
|
|
1601
2520
|
HYPERLIQUID_PERP_STRATEGY_ABI,
|
|
2521
|
+
v3SingleHopExtraData,
|
|
2522
|
+
ZERO_ADDRESS,
|
|
2523
|
+
MORPHO_CL_VENUES,
|
|
2524
|
+
MORPHO_READ_ABI,
|
|
2525
|
+
VAULT_ASSET_ABI,
|
|
2526
|
+
ERC4626_PREVIEW_ABI,
|
|
2527
|
+
readTierRegistry,
|
|
2528
|
+
readAllowed,
|
|
2529
|
+
sameAddress,
|
|
2530
|
+
parseAddressFlag,
|
|
2531
|
+
parseBytes32Flag,
|
|
2532
|
+
parseIntFlag,
|
|
2533
|
+
parseUintFlag,
|
|
2534
|
+
planMorphoSupply,
|
|
2535
|
+
CL_DEFAULTS,
|
|
2536
|
+
twapTickFromCumulatives,
|
|
2537
|
+
planConcentratedLiquidity,
|
|
2538
|
+
parseSwapRouteSpec,
|
|
1602
2539
|
computeProposalAssetChecks,
|
|
1603
2540
|
parseAlignedOverrides,
|
|
1604
2541
|
buildInitDataForTemplate,
|
|
@@ -1614,4 +2551,4 @@ export {
|
|
|
1614
2551
|
applySlippage,
|
|
1615
2552
|
encodeSwapPath
|
|
1616
2553
|
};
|
|
1617
|
-
//# sourceMappingURL=chunk-
|
|
2554
|
+
//# sourceMappingURL=chunk-WDPA2BYK.js.map
|