@@ -9,6 +9,9 @@ import {Hooks} from "v4-core/libraries/Hooks.sol";
99import {MetaProxyDeployer} from "euler-swap/utils/MetaProxyDeployer.sol " ;
1010import {TestERC20} from "evk-test/unit/evault/EVaultTestBase.t.sol " ;
1111import {IEVault} from "evk/EVault/IEVault.sol " ;
12+ import {IEVC} from "evc/interfaces/IEthereumVaultConnector.sol " ;
13+ import {IEulerSwapFactory} from "euler-swap/interfaces/IEulerSwapFactory.sol " ;
14+ import {CurveLib} from "euler-swap/libraries/CurveLib.sol " ;
1215
1316import {console2 as console} from "forge-std/console2.sol " ;
1417
@@ -20,11 +23,15 @@ contract EulerSwapDebtScenario is DeployScenario {
2023 vm.startBroadcast (user3PK);
2124 eUSDC.setLTV (address (eWETH), 0.65e4 , 0.67e4 , 0 );
2225 eUSDC.setLTV (address (eUSDT), 0.85e4 , 0.87e4 , 0 );
26+ eWETH.setLTV (address (eUSDC), 0.65e4 , 0.67e4 , 0 );
27+ eWETH.setLTV (address (eUSDT), 0.85e4 , 0.87e4 , 0 );
28+ eUSDT.setLTV (address (eWETH), 0.85e4 , 0.87e4 , 0 );
29+ eUSDT.setLTV (address (eUSDC), 0.85e4 , 0.87e4 , 0 );
2330 deployJITpilot ();
2431 vm.stopBroadcast ();
2532
2633 vm.startBroadcast (user2PK);
27- createEulerSwap ( );
34+ deployEulerSwap ( getInitialEulerSwapParams (), false );
2835 authorizeJITpilot (user2);
2936 jitPilot.configureLp (user2, 1.4e18 , 1.5e18 );
3037 vm.stopBroadcast ();
@@ -40,26 +47,14 @@ contract EulerSwapDebtScenario is DeployScenario {
4047 borrowFromVault (user0, user0PK, address (eWETH), 500_000e18 );
4148 borrowFromVault (user1, user1PK, address (eUSDC), 1_600_000_000e6 );
4249
43- console.log ("user2 vault deposits: " , eWETH.balanceOf (user2));
44- console.log ("user2 vault deposits: " , eUSDC.balanceOf (user2));
45-
4650 // buy USDC so that user2's EulerSwap position has to borrow USDC
4751 uint256 amountOut = 286_500_000e6 ;
4852 uint256 amountIn = _swapExactOut (address (assetWETH), address (assetUSDC), amountOut, user0, user0PK);
49- console.log ("SOLD %s WETH FOR %s USDC " , amountIn, amountOut);
53+ console.log ("marketUser SOLD %s WETH FOR %s USDC " , amountIn, amountOut);
5054
5155 // user2 is in debt now. Let's fetch that data
52- JITpilot.BlockData memory blockData = jitPilot.getData (user2);
53-
54- console.log ("========================================================== " );
55- console.log ("EulerSwap instance is in debt now: " );
56- console.log ("allowedLTV: " , blockData.allowedLTV);
57- console.log ("currentLTV: " , blockData.currentLTV);
58- console.log ("swapFees: " , blockData.swapFees);
59- console.log ("netInterest: " , blockData.netInterest);
60- console.log ("depositValue: " , blockData.depositValue);
61- console.log ("controllerVault: " , blockData.controllerVault);
62- console.log ("========================================================== " );
56+ console.log ("EulerSwap state now after servicing trades: " );
57+ printEulerSwapData (user2);
6358
6459 // Get a quote for the current price of ETH in the EulerSwap instance
6560 uint256 ethPrice = eulerSwapPeriphery.quoteExactOutput (eulerSwap, address (assetUSDC), address (assetWETH), 1e18 );
@@ -72,6 +67,33 @@ contract EulerSwapDebtScenario is DeployScenario {
7267 // Let's see what the rebalancing params would be
7368 IEulerSwap.Params memory newParams = jitPilot.getRebalancingParams (user2);
7469 printEulerSwapParams (newParams);
70+
71+ // let's do the actual rebalancing then
72+ vm.startBroadcast (user2PK);
73+ jitPilot.updateMetrics (user2);
74+ IEVC (evc).setAccountOperator (user2, eulerSwap, false );
75+ IEulerSwapFactory (eulerSwapFactory).uninstallPool ();
76+ deployEulerSwap (newParams, true );
77+ vm.stopBroadcast ();
78+
79+ // Now let's see if the rebalancing was successful
80+ address poolAddr = eulerSwapFactory.poolByEulerAccount (user2);
81+ newParams = IEulerSwap (poolAddr).getParams ();
82+ printEulerSwapParams (newParams);
83+
84+ // Let's buy some WETH on the EulerSwap pool and see the effect on the debt
85+ // sell USDC so that user2's EulerSwap position has to borrow USDC
86+ uint256 newEthPrice = eulerSwapPeriphery.quoteExactOutput (eulerSwap, address (assetUSDC), address (assetWETH), 1e18 );
87+ console.log ("price of ETH (market): " , ethPrice);
88+ console.log ("price of ETH (EulerSwap): " , newEthPrice);
89+ amountIn = 105_000_000e6 ;
90+ amountOut = _swapExactIn (address (assetUSDC), address (assetWETH), amountIn, user0, user0PK);
91+ console.log ("marketUser BOUGHT %s WETH FOR %s USDC (price: %s) " , amountOut, amountIn, amountIn * 1e18 / amountOut);
92+
93+ // Let's see the new state of the EulerSwap pool after arbitrage
94+ console.log ("EulerSwap state now (after arbitrage): " );
95+ printEulerSwapData (user2);
96+ console.log ("price of ETH (EulerSwap, after arbitrage): " , eulerSwapPeriphery.quoteExactOutput (eulerSwap, address (assetUSDC), address (assetWETH), 1e18 ));
7597 }
7698
7799 function giveTonsOfCash (address user ) internal virtual {
@@ -98,26 +120,39 @@ contract EulerSwapDebtScenario is DeployScenario {
98120 evc.setAccountOperator (user, address (jitPilot), true );
99121 }
100122
101- function createEulerSwap () internal {
102- // Create pool parameters
103- IEulerSwap.Params memory poolParams = IEulerSwap.Params ({
104- vault0: address (eUSDC),
105- vault1: address (eWETH),
106- eulerAccount: user2,
107- equilibriumReserve0: 800_000_000e6 ,
108- equilibriumReserve1: 280_000e18 ,
109- priceX: 1e18 ,
110- priceY: 2865e6 ,
111- concentrationX: 0.9e18 ,
112- concentrationY: 0.9e18 ,
113- fee: 0 ,
114- protocolFee: 0 ,
115- protocolFeeRecipient: address (0 )
116- });
123+ function deployEulerSwap (IEulerSwap.Params memory poolParams , bool rebalancing ) internal {
117124
118- console.log ("INITIAL EULERSWAP PARAMS " );
125+ console.log ("DEPLOYING EULERSWAP WITH PARAMS " );
119126 printEulerSwapParams (poolParams);
120127
128+ bool asset0IsDebt = getCurrentControllerVault (poolParams.eulerAccount) == poolParams.vault0;
129+ uint112 currentReserve0 = poolParams.equilibriumReserve0;
130+ uint112 currentReserve1 = poolParams.equilibriumReserve1;
131+
132+ IEulerSwap.InitialState memory initialState;
133+ if (! rebalancing) {
134+ initialState = IEulerSwap.InitialState ({currReserve0: poolParams.equilibriumReserve0, currReserve1: poolParams.equilibriumReserve1});
135+ } else {
136+ if (asset0IsDebt) {
137+ {
138+ uint256 deltaReservesAsset0 = poolParams.equilibriumReserve0 * 1 / 3 ;
139+ // uint256 deltaReservesAsset1 = deltaReservesAsset0 * poolParams.priceX / poolParams.priceY;
140+ currentReserve0 = uint112 (poolParams.equilibriumReserve0 - deltaReservesAsset0);
141+ // currentReserve1 = uint112(poolParams.equilibriumReserve1 + deltaReservesAsset1);
142+ currentReserve1 = uint112 (CurveLib.f (uint256 (currentReserve0), uint256 (poolParams.priceX), uint256 (poolParams.priceY), uint256 (poolParams.equilibriumReserve0), uint256 (poolParams.equilibriumReserve1), uint256 (poolParams.concentrationX)));
143+ }
144+ } else {
145+ {
146+ uint256 deltaReservesAsset1 = poolParams.equilibriumReserve1 * 1 / 3 ;
147+ // uint256 deltaReservesAsset0 = deltaReservesAsset1 * poolParams.priceY / poolParams.priceX;
148+ currentReserve1 = uint112 (poolParams.equilibriumReserve1 - deltaReservesAsset1);
149+ // currentReserve0 = uint112(poolParams.equilibriumReserve0 + deltaReservesAsset0);
150+ currentReserve0 = uint112 (CurveLib.fInverse (uint256 (currentReserve1), uint256 (poolParams.priceY), uint256 (poolParams.priceX), uint256 (poolParams.equilibriumReserve1), uint256 (poolParams.equilibriumReserve0), uint256 (poolParams.concentrationY)));
151+ }
152+ }
153+ initialState = IEulerSwap.InitialState ({currReserve0: currentReserve0, currReserve1: currentReserve1});
154+ }
155+
121156 // Define required hook flags
122157 uint160 flags = uint160 (
123158 Hooks.BEFORE_INITIALIZE_FLAG | Hooks.BEFORE_SWAP_FLAG | Hooks.BEFORE_SWAP_RETURNS_DELTA_FLAG
@@ -129,11 +164,21 @@ contract EulerSwapDebtScenario is DeployScenario {
129164 (address hookAddress , bytes32 salt ) = HookMiner.find (address (eulerSwapFactory), flags, creationCode);
130165
131166 eulerSwap = hookAddress;
132- evc.setAccountOperator (user2, eulerSwap, true );
133-
134- eulerSwapFactory.deployPool (
135- poolParams, IEulerSwap.InitialState ({currReserve0: 800_000_000e6 , currReserve1: 280_000e18 }), salt
136- );
167+ // Deploy pool via EVC batch
168+ IEVC.BatchItem[] memory items = new IEVC.BatchItem [](2 );
169+ items[0 ] = IEVC.BatchItem ({
170+ onBehalfOfAccount: address (0 ),
171+ targetContract: address (evc),
172+ value: 0 ,
173+ data: abi.encodeCall (evc.setAccountOperator, (user2, eulerSwap, true ))
174+ });
175+ items[1 ] = IEVC.BatchItem ({
176+ onBehalfOfAccount: user2,
177+ targetContract: address (eulerSwapFactory),
178+ value: 0 ,
179+ data: abi.encodeCall (IEulerSwapFactory.deployPool, (poolParams, initialState, salt))
180+ });
181+ evc.batch (items);
137182
138183 string memory result = vm.serializeAddress ("eulerSwap " , "eulerSwap " , address (eulerSwap));
139184 vm.writeJson (result, "./dev-ctx/addresses/31337/EulerSwapAddresses.json " );
@@ -172,7 +217,7 @@ contract EulerSwapDebtScenario is DeployScenario {
172217 {
173218 vm.startBroadcast (userPK);
174219 amountIn = eulerSwapPeriphery.quoteExactOutput (eulerSwap, tokenIn, tokenOut, amountOut);
175- console.log ("amountIn " , amountIn);
220+ // console.log("amountIn", amountIn);
176221
177222 TestERC20 (tokenIn).approve (address (eulerSwapPeriphery), type (uint256 ).max);
178223 eulerSwapPeriphery.swapExactOut (
@@ -189,7 +234,47 @@ contract EulerSwapDebtScenario is DeployScenario {
189234 return amountIn;
190235 }
191236
192- function printEulerSwapParams (IEulerSwap.Params memory params ) internal {
237+ function _swapExactIn (address tokenIn , address tokenOut , uint256 amountIn , address receiver , uint256 userPK )
238+ internal
239+ returns (uint256 amountOut )
240+ {
241+ vm.startBroadcast (userPK);
242+ amountOut = eulerSwapPeriphery.quoteExactInput (eulerSwap, tokenIn, tokenOut, amountIn);
243+ // console.log("amountOut", amountOut);
244+
245+ TestERC20 (tokenIn).approve (address (eulerSwapPeriphery), type (uint256 ).max);
246+ eulerSwapPeriphery.swapExactIn (
247+ eulerSwap,
248+ tokenIn,
249+ tokenOut,
250+ amountIn,
251+ receiver,
252+ amountOut * 99 / 100 , // allow up to 1% slippage
253+ 0
254+ );
255+ vm.stopBroadcast ();
256+
257+ return amountOut;
258+ }
259+
260+ function getInitialEulerSwapParams () internal view returns (IEulerSwap.Params memory ) {
261+ return IEulerSwap.Params ({
262+ vault0: address (eUSDC),
263+ vault1: address (eWETH),
264+ eulerAccount: user2,
265+ equilibriumReserve0: 800_000_000e6 ,
266+ equilibriumReserve1: 280_000e18 ,
267+ priceX: 1e18 ,
268+ priceY: 2865e6 ,
269+ concentrationX: 0.9e18 ,
270+ concentrationY: 0.9e18 ,
271+ fee: 0 ,
272+ protocolFee: 0 ,
273+ protocolFeeRecipient: address (0 )
274+ });
275+ }
276+
277+ function printEulerSwapParams (IEulerSwap.Params memory params ) internal pure {
193278 console.log ("========================================================== " );
194279 console.log ("vault0: " , params.vault0);
195280 console.log ("vault1: " , params.vault1);
@@ -205,4 +290,35 @@ contract EulerSwapDebtScenario is DeployScenario {
205290 console.log ("protocolFeeRecipient: " , params.protocolFeeRecipient);
206291 console.log ("========================================================== " );
207292 }
293+
294+ function printEulerSwapData (address user ) internal view {
295+
296+ JITpilot.BlockData memory blockData = jitPilot.getData (user);
297+
298+ console.log ("========================================================== " );
299+ console.log ("healthFactor: " , blockData.allowedLTV * 1e4 / blockData.currentLTV / 100 , "% " );
300+ console.log ("allowedLTV: " , blockData.allowedLTV);
301+ console.log ("currentLTV: " , blockData.currentLTV);
302+ console.log ("swapFees: " , blockData.swapFees);
303+ console.log ("netInterest: " , blockData.netInterest);
304+ console.log ("depositValue: " , blockData.depositValue);
305+ console.log ("controllerVault: " , blockData.controllerVault);
306+ console.log ("========================================================== " );
307+ }
308+
309+ function getCurrentControllerVault (address lp ) internal view returns (address ) {
310+ address [] memory controllerVaults = evc.getControllers (lp);
311+ address currentControllerVault;
312+
313+ if (controllerVaults.length == 0 ) return address (0 );
314+
315+ // find which of the LP's controller vaults is the enabled debt vault
316+ for (uint256 i; i < controllerVaults.length ; ++ i) {
317+ if (evc.isControllerEnabled (lp, controllerVaults[i])) {
318+ currentControllerVault = controllerVaults[i];
319+ break ;
320+ }
321+ }
322+ return currentControllerVault;
323+ }
208324}
0 commit comments