From bfe1709da31bca2a5579002d02b7e5e7f8fdbbbb Mon Sep 17 00:00:00 2001 From: MazyGio Date: Thu, 3 Jul 2025 15:58:02 -0500 Subject: [PATCH 1/2] fix: normalize scale of fetchadata outputs so they're all based in 1e18 --- src/JITpilot.sol | 218 +++++++++++++++++++++++++++-------------------- 1 file changed, 127 insertions(+), 91 deletions(-) diff --git a/src/JITpilot.sol b/src/JITpilot.sol index bb53470..3052633 100644 --- a/src/JITpilot.sol +++ b/src/JITpilot.sol @@ -7,6 +7,7 @@ import {IEVault, IERC20} from "evk/EVault/IEVault.sol"; import {IEulerSwapFactory} from "euler-swap/interfaces/IEulerSwapFactory.sol"; import {IMaglevLens} from "src/interfaces/IMaglevLens.sol"; import {IPriceOracle} from "evk/interfaces/IPriceOracle.sol"; +import {console2 as console} from "forge-std/console2.sol"; /** * @title JITpilot @@ -14,13 +15,14 @@ import {IPriceOracle} from "evk/interfaces/IPriceOracle.sol"; * Tracks Health Factor and Yield as sliding time-weighted averages over 100 blocks */ contract JITpilot { + address public admin; address public owner; - + // Constants uint256 private constant WINDOW_SIZE = 100; uint256 private constant PRECISION = 1e18; - + // Configurable parameters uint256 public rebalanceThreshold = 5e17; // 0.5 in 18 decimals uint256 public weightHF = 6e17; // 0.6 weight for Health Factor @@ -31,7 +33,7 @@ contract JITpilot { address public EVK; address public MaglevLens; address public EulerSwapFactory; - + // Data structure to store block-level data from fetchData struct BlockData { uint256 allowedLTV; @@ -40,29 +42,32 @@ contract JITpilot { int256 netInterest; uint256 depositValue; } - + // LP data structure struct LPData { // Health Factor data uint256[] hfHistory; // Stores HF values for last 100 blocks uint256 twaHF; // Time-weighted average Health Factor - // Yield data + + // Yield data uint256[] yieldHistory; // Stores yield values for last 100 blocks uint256 twaYield; // Time-weighted average Yield + // Configuration uint256 hfMin; // Liquidation threshold uint256 hfDesired; // Target health factor set by LP uint256 yieldTarget; // Target yield set by LP + // Tracking uint256 lastUpdateBlock; // Last block when metrics were updated uint256 startBlock; // Block when LP started bool initialized; // Whether LP data is initialized } - + // Mappings mapping(address => LPData) public lpData; mapping(address => bool) public authorizedCallers; - + // Events event MetricsUpdated( address indexed lp, @@ -73,24 +78,32 @@ contract JITpilot { uint256 twaYield, uint256 compositeScore ); - + event RebalanceTriggered( - address indexed lp, uint256 indexed blockNumber, uint256 compositeScore, uint256 threshold + address indexed lp, + uint256 indexed blockNumber, + uint256 compositeScore, + uint256 threshold ); - - event LPConfigured(address indexed lp, uint256 hfMin, uint256 hfDesired, uint256 yieldTarget); - + + event LPConfigured( + address indexed lp, + uint256 hfMin, + uint256 hfDesired, + uint256 yieldTarget + ); + // Modifiers modifier onlyAuthorized() { require(authorizedCallers[msg.sender], "Not authorized"); _; } - + modifier onlyOwner() { require(msg.sender == owner, "Not owner"); _; } - + constructor() { authorizedCallers[msg.sender] = true; admin = msg.sender; @@ -101,19 +114,19 @@ contract JITpilot { function setEVC(address _EVC) external onlyOwner { EVC = _EVC; } - + function setEVK(address _EVK) external onlyOwner { EVK = _EVK; } - + function setMaglevLens(address _MaglevLens) external onlyOwner { MaglevLens = _MaglevLens; } - + function setEulerSwapFactory(address _EulerSwapFactory) external onlyOwner { EulerSwapFactory = _EulerSwapFactory; } - + /** * @dev Configure LP parameters * @param lp LP address @@ -121,38 +134,43 @@ contract JITpilot { * @param _hfDesired Target health factor * @param _yieldTarget Target yield */ - function configureLp(address lp, uint256 _hfMin, uint256 _hfDesired, uint256 _yieldTarget) external { + function configureLp( + address lp, + uint256 _hfMin, + uint256 _hfDesired, + uint256 _yieldTarget + ) external { require(lp != address(0), "Invalid LP address"); require(_hfDesired > _hfMin, "HF desired must be > HF min"); - + LPData storage data = lpData[lp]; data.hfMin = _hfMin; data.hfDesired = _hfDesired; data.yieldTarget = _yieldTarget; data.initialized = true; data.startBlock = block.number; - + emit LPConfigured(lp, _hfMin, _hfDesired, _yieldTarget); } - + /** * @dev Update metrics for a specific LP * @param lp LP address to update metrics for */ function updateMetrics(address lp) external { require(lpData[lp].initialized, "LP not configured"); - + LPData storage data = lpData[lp]; - + // Fetch current block data BlockData memory currentData = fetchData(lp); - + // Calculate current Health Factor uint256 currentHF = 0; if (currentData.currentLTV > 0) { currentHF = (currentData.allowedLTV * PRECISION) / currentData.currentLTV; } - + // Calculate current Yield uint256 currentYield = 0; uint256 swapApy = currentData.swapFees / currentData.depositValue; @@ -167,39 +185,47 @@ contract JITpilot { currentYield = 0; } } - + // Update sliding window for Health Factor _updateSlidingWindow(data.hfHistory, currentHF); - + // Update sliding window for Yield _updateSlidingWindow(data.yieldHistory, currentYield); - + // Calculate TWA for Health Factor data.twaHF = _calculateTWA(data.hfHistory, data.startBlock); - + // Calculate TWA for Yield data.twaYield = _calculateTWA(data.yieldHistory, data.startBlock); - + // Calculate normalized values uint256 normalizedHF = _normalizeHealthFactor(data.twaHF, data.hfMin, data.hfDesired); uint256 normalizedYield = _normalizeYield(data.twaYield, data.yieldTarget); - + // Calculate composite score uint256 compositeScore = (weightHF * normalizedHF + weightYield * normalizedYield) / PRECISION; - + // Update last update block data.lastUpdateBlock = block.number; - + // Emit metrics updated event - emit MetricsUpdated(lp, block.number, currentHF, currentYield, data.twaHF, data.twaYield, compositeScore); - + emit MetricsUpdated( + lp, + block.number, + currentHF, + currentYield, + data.twaHF, + data.twaYield, + compositeScore + ); + // Check if rebalancing is needed if (compositeScore < rebalanceThreshold) { emit RebalanceTriggered(lp, block.number, compositeScore, rebalanceThreshold); rebalance(lp); } } - + /** * @dev Update sliding window array with new value * @param history Array storing historical values @@ -217,7 +243,7 @@ contract JITpilot { history[WINDOW_SIZE - 1] = newValue; } } - + /** * @dev Calculate time-weighted average * @param history Array of historical values @@ -227,21 +253,21 @@ contract JITpilot { function _calculateTWA(uint256[] storage history, uint256 startBlock) internal view returns (uint256) { uint256 length = history.length; if (length == 0) return 0; - + // Calculate blocks elapsed since start uint256 blocksElapsed = block.number - startBlock + 1; - + // Determine effective window size uint256 effectiveWindow = blocksElapsed <= WINDOW_SIZE ? blocksElapsed : WINDOW_SIZE; - + uint256 sum = 0; for (uint256 i = 0; i < length; i++) { sum += history[i]; } - + return sum / effectiveWindow; } - + /** * @dev Normalize Health Factor to [0,1] range * @param twaHF Time-weighted average Health Factor @@ -249,13 +275,17 @@ contract JITpilot { * @param hfDesired Desired health factor * @return Normalized HF value */ - function _normalizeHealthFactor(uint256 twaHF, uint256 hfMin, uint256 hfDesired) internal pure returns (uint256) { + function _normalizeHealthFactor( + uint256 twaHF, + uint256 hfMin, + uint256 hfDesired + ) internal pure returns (uint256) { if (twaHF <= hfMin) return 0; if (twaHF >= hfDesired) return PRECISION; - + return ((twaHF - hfMin) * PRECISION) / (hfDesired - hfMin); } - + /** * @dev Normalize Yield to [0,1] range * @param twaYield Time-weighted average yield @@ -265,10 +295,10 @@ contract JITpilot { function _normalizeYield(uint256 twaYield, uint256 yieldTarget) internal pure returns (uint256) { if (yieldTarget == 0) return PRECISION; // Avoid division by zero if (twaYield >= yieldTarget) return PRECISION; - + return (twaYield * PRECISION) / yieldTarget; } - + /** * @dev Fetch current block data (placeholder - to be implemented later) * @param lp LP address @@ -277,10 +307,10 @@ contract JITpilot { function fetchData(address lp) internal view returns (BlockData memory) { // Placeholder implementation - this will fetch real data from Euler contracts // For now, return dummy data to avoid compilation errors - + // get LP's eulerSwap pool address address poolAddr = IEulerSwapFactory(EulerSwapFactory).poolByEulerAccount(lp); - + // get eulerSwap pool data EulerSwapData memory eulerSwapData = getEulerSwapData(poolAddr); @@ -301,8 +331,7 @@ contract JITpilot { // more accurate for our purposes. // uint256 collateralValue0 = getCollateralValue(lp, vault0); // uint256 collateralValue1 = getCollateralValue(lp, vault1); - uint256 collateralValueTotal = - getCollateralValue(lp, eulerSwapData.params.vault0) + getCollateralValue(lp, eulerSwapData.params.vault1); + uint256 collateralValueTotal = getCollateralValue(lp, eulerSwapData.params.vault0) + getCollateralValue(lp, eulerSwapData.params.vault1); // get supply APY data using the MaglevLens contract IMaglevLens maglevLens = IMaglevLens(MaglevLens); @@ -310,9 +339,12 @@ contract JITpilot { collateralVaults[0] = eulerSwapData.params.vault0; collateralVaults[1] = eulerSwapData.params.vault1; IMaglevLens.VaultGlobal[] memory collateralVaultsGlobal = maglevLens.vaultsGlobal(collateralVaults); + // packed2: shares (160), supply APY (48), borrow APY (48) for (uint256 i; i < collateralVaultsGlobal.length; ++i) { uint256 supplyApy = uint256((collateralVaultsGlobal[i].packed2 << (256 - 96)) >> (256 - 48)); supplyApyTotal += supplyApy * getCollateralValue(lp, collateralVaults[i]) / collateralValueTotal; + console.log("Supply APY for vault", collateralVaults[i], "is", supplyApy); + console.log("Supply APY total is", supplyApyTotal); } // get the currently enabled controller vault (i.e. the debt vault) @@ -320,19 +352,21 @@ contract JITpilot { // If there is no controller, there is no debt, and no liquidation metrics to calculate if (controllerVault == address(0)) { + console.log("doesn't have controller vault: ", controllerVault); blockData.allowedLTV = 0; blockData.currentLTV = 0; // If there is no debt, there is no looping or leverage blockData.depositValue = collateralValueTotal; blockData.netInterest = int256(supplyApyTotal); } else { + console.log("has controller vault: ", controllerVault); // Figure out which vault is the collateralVault - address collateralVault = (controllerVault == eulerSwapData.params.vault0) - ? eulerSwapData.params.vault1 - : eulerSwapData.params.vault0; + address collateralVault = (controllerVault == eulerSwapData.params.vault0) ? eulerSwapData.params.vault1 : eulerSwapData.params.vault0; uint256 debtValue = getDebtValue(lp, controllerVault); - blockData.allowedLTV = IEVault(controllerVault).LTVLiquidation(collateralVault); - blockData.currentLTV = debtValue / collateralValueTotal; + console.log("debtValue: ", debtValue); + blockData.allowedLTV = uint256(IEVault(controllerVault).LTVLiquidation(collateralVault)) * 1e18 / 1e4; + blockData.currentLTV = debtValue * 1e18 / collateralValueTotal; + console.log("currentLTV: ", blockData.currentLTV); address[] memory controllerVaultArray = new address[](1); controllerVaultArray[0] = controllerVault; @@ -345,14 +379,13 @@ contract JITpilot { blockData.depositValue = collateralValueTotal - debtValue; if (supplyApyTotal * collateralValueTotal < borrowApyTotal * debtValue) { // avoid overflow - blockData.netInterest = -int256((borrowApyTotal * debtValue - supplyApyTotal * collateralValueTotal) / blockData.depositValue); + blockData.netInterest = -int256((borrowApyTotal * debtValue - supplyApyTotal * collateralValueTotal) / blockData.depositValue) *1e9; } else { - blockData.netInterest = int256( - (supplyApyTotal * collateralValueTotal - borrowApyTotal * debtValue) / blockData.depositValue - ); + blockData.netInterest = int256((supplyApyTotal * collateralValueTotal - borrowApyTotal * debtValue) / blockData.depositValue) *1e9; } } + // get LP's liquidity status in the controller vault, with regards to liquidation // ( // address[] memory collateralVaults, @@ -368,12 +401,12 @@ contract JITpilot { // uint16 ltv = IEVault(controllerVault).LTVLiquidation(collateralVaults[i]); // collateralValues[i] = collateralValues[i] * 10000 / ltv; // Convert back to non-adjusted value // collateralValueTotal += collateralValues[i]; - + // // Calculate weighted average LTV // allowedLTV += ltv * collateralValues[i]; // totalWeight += collateralValues[i]; // } - + // Finalize weighted average LTV // if (totalWeight > 0) { // allowedLTV = allowedLTV / totalWeight; @@ -389,13 +422,13 @@ contract JITpilot { // #4 calculate net interest // uint256 netInterest = supplyApyTotal - borrowApy; - + // #5 get the depositValue // uint256 depositValue = collateralValueTotal - liabilityValue; return blockData; } - + struct EulerSwapData { address addr; IEulerSwap.Params params; @@ -428,12 +461,11 @@ contract JITpilot { * @dev Rebalance LP position (placeholder - to be implemented later) * @param lp LP address to rebalance */ - function rebalance(address lp) internal { // Placeholder implementation - this will perform actual rebalancing // Will be implemented in later iterations } - + /** * @dev Add authorized caller * @param caller Address to authorize @@ -441,7 +473,7 @@ contract JITpilot { function addAuthorizedCaller(address caller) external onlyAuthorized { authorizedCallers[caller] = true; } - + /** * @dev Remove authorized caller * @param caller Address to remove authorization @@ -449,7 +481,7 @@ contract JITpilot { function removeAuthorizedCaller(address caller) external onlyAuthorized { authorizedCallers[caller] = false; } - + /** * @dev Update rebalance threshold * @param newThreshold New threshold value @@ -458,7 +490,7 @@ contract JITpilot { require(newThreshold <= PRECISION, "Threshold too high"); rebalanceThreshold = newThreshold; } - + /** * @dev Update weights for composite score * @param newWeightHF New weight for Health Factor @@ -469,7 +501,7 @@ contract JITpilot { weightHF = newWeightHF; weightYield = newWeightYield; } - + /** * @dev Get LP data for viewing * @param lp LP address @@ -481,19 +513,15 @@ contract JITpilot { * @return lastUpdateBlock Last block when metrics were updated * @return initialized Whether LP data is initialized */ - function getLPData(address lp) - external - view - returns ( - uint256 twaHF, - uint256 twaYield, - uint256 hfMin, - uint256 hfDesired, - uint256 yieldTarget, - uint256 lastUpdateBlock, - bool initialized - ) - { + function getLPData(address lp) external view returns ( + uint256 twaHF, + uint256 twaYield, + uint256 hfMin, + uint256 hfDesired, + uint256 yieldTarget, + uint256 lastUpdateBlock, + bool initialized + ) { LPData storage data = lpData[lp]; return ( data.twaHF, @@ -505,7 +533,7 @@ contract JITpilot { data.initialized ); } - + /** * @dev Get current composite score for an LP * @param lp LP address @@ -514,10 +542,10 @@ contract JITpilot { function getCompositeScore(address lp) external view returns (uint256) { LPData storage data = lpData[lp]; if (!data.initialized) return 0; - + uint256 normalizedHF = _normalizeHealthFactor(data.twaHF, data.hfMin, data.hfDesired); uint256 normalizedYield = _normalizeYield(data.twaYield, data.yieldTarget); - + return (weightHF * normalizedHF + weightYield * normalizedYield) / PRECISION; } @@ -528,7 +556,7 @@ contract JITpilot { address currentControllerVault; if (controllerVaults.length == 0) return address(0); - + // find which of the LP's controller vaults is the enabled debt vault for (uint256 i; i < controllerVaults.length; ++i) { if (IEVC(EVC).isControllerEnabled(lp, controllerVaults[i])) { @@ -539,7 +567,12 @@ contract JITpilot { return currentControllerVault; } - function getCollateralValue(address account, address collateral) internal view virtual returns (uint256 value) { + function getCollateralValue(address account, address collateral) + internal + view + virtual + returns (uint256 value) + { IEVault collateralVault = IEVault(collateral); uint256 balance = IERC20(collateral).balanceOf(account); if (balance == 0) return 0; @@ -547,8 +580,7 @@ contract JITpilot { uint256 currentCollateralValue; // mid-point price - currentCollateralValue = - IPriceOracle(collateralVault.oracle()).getQuote(balance, collateral, collateralVault.unitOfAccount()); + currentCollateralValue = IPriceOracle(collateralVault.oracle()).getQuote(balance, collateral, collateralVault.unitOfAccount()); return currentCollateralValue; } @@ -565,4 +597,8 @@ contract JITpilot { return currentDebtValue; } + + function getData(address lp) external view returns (BlockData memory) { + return fetchData(lp); + } } From 58cb8795da2f1d86fe493e3d6bb4dae0d233e9d5 Mon Sep 17 00:00:00 2001 From: MazyGio Date: Thu, 3 Jul 2025 19:58:09 -0500 Subject: [PATCH 2/2] fix: run forge fmt --- src/JITpilot.sol | 203 +++++++++++++++++++++-------------------------- 1 file changed, 90 insertions(+), 113 deletions(-) diff --git a/src/JITpilot.sol b/src/JITpilot.sol index 3052633..7755df8 100644 --- a/src/JITpilot.sol +++ b/src/JITpilot.sol @@ -15,14 +15,13 @@ import {console2 as console} from "forge-std/console2.sol"; * Tracks Health Factor and Yield as sliding time-weighted averages over 100 blocks */ contract JITpilot { - address public admin; address public owner; - + // Constants uint256 private constant WINDOW_SIZE = 100; uint256 private constant PRECISION = 1e18; - + // Configurable parameters uint256 public rebalanceThreshold = 5e17; // 0.5 in 18 decimals uint256 public weightHF = 6e17; // 0.6 weight for Health Factor @@ -33,7 +32,7 @@ contract JITpilot { address public EVK; address public MaglevLens; address public EulerSwapFactory; - + // Data structure to store block-level data from fetchData struct BlockData { uint256 allowedLTV; @@ -42,32 +41,29 @@ contract JITpilot { int256 netInterest; uint256 depositValue; } - + // LP data structure struct LPData { // Health Factor data uint256[] hfHistory; // Stores HF values for last 100 blocks uint256 twaHF; // Time-weighted average Health Factor - - // Yield data + // Yield data uint256[] yieldHistory; // Stores yield values for last 100 blocks uint256 twaYield; // Time-weighted average Yield - // Configuration uint256 hfMin; // Liquidation threshold uint256 hfDesired; // Target health factor set by LP uint256 yieldTarget; // Target yield set by LP - // Tracking uint256 lastUpdateBlock; // Last block when metrics were updated uint256 startBlock; // Block when LP started bool initialized; // Whether LP data is initialized } - + // Mappings mapping(address => LPData) public lpData; mapping(address => bool) public authorizedCallers; - + // Events event MetricsUpdated( address indexed lp, @@ -78,32 +74,24 @@ contract JITpilot { uint256 twaYield, uint256 compositeScore ); - + event RebalanceTriggered( - address indexed lp, - uint256 indexed blockNumber, - uint256 compositeScore, - uint256 threshold + address indexed lp, uint256 indexed blockNumber, uint256 compositeScore, uint256 threshold ); - - event LPConfigured( - address indexed lp, - uint256 hfMin, - uint256 hfDesired, - uint256 yieldTarget - ); - + + event LPConfigured(address indexed lp, uint256 hfMin, uint256 hfDesired, uint256 yieldTarget); + // Modifiers modifier onlyAuthorized() { require(authorizedCallers[msg.sender], "Not authorized"); _; } - + modifier onlyOwner() { require(msg.sender == owner, "Not owner"); _; } - + constructor() { authorizedCallers[msg.sender] = true; admin = msg.sender; @@ -114,19 +102,19 @@ contract JITpilot { function setEVC(address _EVC) external onlyOwner { EVC = _EVC; } - + function setEVK(address _EVK) external onlyOwner { EVK = _EVK; } - + function setMaglevLens(address _MaglevLens) external onlyOwner { MaglevLens = _MaglevLens; } - + function setEulerSwapFactory(address _EulerSwapFactory) external onlyOwner { EulerSwapFactory = _EulerSwapFactory; } - + /** * @dev Configure LP parameters * @param lp LP address @@ -134,43 +122,38 @@ contract JITpilot { * @param _hfDesired Target health factor * @param _yieldTarget Target yield */ - function configureLp( - address lp, - uint256 _hfMin, - uint256 _hfDesired, - uint256 _yieldTarget - ) external { + function configureLp(address lp, uint256 _hfMin, uint256 _hfDesired, uint256 _yieldTarget) external { require(lp != address(0), "Invalid LP address"); require(_hfDesired > _hfMin, "HF desired must be > HF min"); - + LPData storage data = lpData[lp]; data.hfMin = _hfMin; data.hfDesired = _hfDesired; data.yieldTarget = _yieldTarget; data.initialized = true; data.startBlock = block.number; - + emit LPConfigured(lp, _hfMin, _hfDesired, _yieldTarget); } - + /** * @dev Update metrics for a specific LP * @param lp LP address to update metrics for */ function updateMetrics(address lp) external { require(lpData[lp].initialized, "LP not configured"); - + LPData storage data = lpData[lp]; - + // Fetch current block data BlockData memory currentData = fetchData(lp); - + // Calculate current Health Factor uint256 currentHF = 0; if (currentData.currentLTV > 0) { currentHF = (currentData.allowedLTV * PRECISION) / currentData.currentLTV; } - + // Calculate current Yield uint256 currentYield = 0; uint256 swapApy = currentData.swapFees / currentData.depositValue; @@ -185,47 +168,39 @@ contract JITpilot { currentYield = 0; } } - + // Update sliding window for Health Factor _updateSlidingWindow(data.hfHistory, currentHF); - + // Update sliding window for Yield _updateSlidingWindow(data.yieldHistory, currentYield); - + // Calculate TWA for Health Factor data.twaHF = _calculateTWA(data.hfHistory, data.startBlock); - + // Calculate TWA for Yield data.twaYield = _calculateTWA(data.yieldHistory, data.startBlock); - + // Calculate normalized values uint256 normalizedHF = _normalizeHealthFactor(data.twaHF, data.hfMin, data.hfDesired); uint256 normalizedYield = _normalizeYield(data.twaYield, data.yieldTarget); - + // Calculate composite score uint256 compositeScore = (weightHF * normalizedHF + weightYield * normalizedYield) / PRECISION; - + // Update last update block data.lastUpdateBlock = block.number; - + // Emit metrics updated event - emit MetricsUpdated( - lp, - block.number, - currentHF, - currentYield, - data.twaHF, - data.twaYield, - compositeScore - ); - + emit MetricsUpdated(lp, block.number, currentHF, currentYield, data.twaHF, data.twaYield, compositeScore); + // Check if rebalancing is needed if (compositeScore < rebalanceThreshold) { emit RebalanceTriggered(lp, block.number, compositeScore, rebalanceThreshold); rebalance(lp); } } - + /** * @dev Update sliding window array with new value * @param history Array storing historical values @@ -243,7 +218,7 @@ contract JITpilot { history[WINDOW_SIZE - 1] = newValue; } } - + /** * @dev Calculate time-weighted average * @param history Array of historical values @@ -253,21 +228,21 @@ contract JITpilot { function _calculateTWA(uint256[] storage history, uint256 startBlock) internal view returns (uint256) { uint256 length = history.length; if (length == 0) return 0; - + // Calculate blocks elapsed since start uint256 blocksElapsed = block.number - startBlock + 1; - + // Determine effective window size uint256 effectiveWindow = blocksElapsed <= WINDOW_SIZE ? blocksElapsed : WINDOW_SIZE; - + uint256 sum = 0; for (uint256 i = 0; i < length; i++) { sum += history[i]; } - + return sum / effectiveWindow; } - + /** * @dev Normalize Health Factor to [0,1] range * @param twaHF Time-weighted average Health Factor @@ -275,17 +250,13 @@ contract JITpilot { * @param hfDesired Desired health factor * @return Normalized HF value */ - function _normalizeHealthFactor( - uint256 twaHF, - uint256 hfMin, - uint256 hfDesired - ) internal pure returns (uint256) { + function _normalizeHealthFactor(uint256 twaHF, uint256 hfMin, uint256 hfDesired) internal pure returns (uint256) { if (twaHF <= hfMin) return 0; if (twaHF >= hfDesired) return PRECISION; - + return ((twaHF - hfMin) * PRECISION) / (hfDesired - hfMin); } - + /** * @dev Normalize Yield to [0,1] range * @param twaYield Time-weighted average yield @@ -295,10 +266,10 @@ contract JITpilot { function _normalizeYield(uint256 twaYield, uint256 yieldTarget) internal pure returns (uint256) { if (yieldTarget == 0) return PRECISION; // Avoid division by zero if (twaYield >= yieldTarget) return PRECISION; - + return (twaYield * PRECISION) / yieldTarget; } - + /** * @dev Fetch current block data (placeholder - to be implemented later) * @param lp LP address @@ -307,10 +278,10 @@ contract JITpilot { function fetchData(address lp) internal view returns (BlockData memory) { // Placeholder implementation - this will fetch real data from Euler contracts // For now, return dummy data to avoid compilation errors - + // get LP's eulerSwap pool address address poolAddr = IEulerSwapFactory(EulerSwapFactory).poolByEulerAccount(lp); - + // get eulerSwap pool data EulerSwapData memory eulerSwapData = getEulerSwapData(poolAddr); @@ -331,7 +302,8 @@ contract JITpilot { // more accurate for our purposes. // uint256 collateralValue0 = getCollateralValue(lp, vault0); // uint256 collateralValue1 = getCollateralValue(lp, vault1); - uint256 collateralValueTotal = getCollateralValue(lp, eulerSwapData.params.vault0) + getCollateralValue(lp, eulerSwapData.params.vault1); + uint256 collateralValueTotal = + getCollateralValue(lp, eulerSwapData.params.vault0) + getCollateralValue(lp, eulerSwapData.params.vault1); // get supply APY data using the MaglevLens contract IMaglevLens maglevLens = IMaglevLens(MaglevLens); @@ -361,7 +333,9 @@ contract JITpilot { } else { console.log("has controller vault: ", controllerVault); // Figure out which vault is the collateralVault - address collateralVault = (controllerVault == eulerSwapData.params.vault0) ? eulerSwapData.params.vault1 : eulerSwapData.params.vault0; + address collateralVault = (controllerVault == eulerSwapData.params.vault0) + ? eulerSwapData.params.vault1 + : eulerSwapData.params.vault0; uint256 debtValue = getDebtValue(lp, controllerVault); console.log("debtValue: ", debtValue); blockData.allowedLTV = uint256(IEVault(controllerVault).LTVLiquidation(collateralVault)) * 1e18 / 1e4; @@ -379,13 +353,15 @@ contract JITpilot { blockData.depositValue = collateralValueTotal - debtValue; if (supplyApyTotal * collateralValueTotal < borrowApyTotal * debtValue) { // avoid overflow - blockData.netInterest = -int256((borrowApyTotal * debtValue - supplyApyTotal * collateralValueTotal) / blockData.depositValue) *1e9; + blockData.netInterest = -int256((borrowApyTotal * debtValue - supplyApyTotal * collateralValueTotal) / blockData.depositValue) + * 1e9; } else { - blockData.netInterest = int256((supplyApyTotal * collateralValueTotal - borrowApyTotal * debtValue) / blockData.depositValue) *1e9; + blockData.netInterest = int256( + (supplyApyTotal * collateralValueTotal - borrowApyTotal * debtValue) / blockData.depositValue + ) * 1e9; } } - // get LP's liquidity status in the controller vault, with regards to liquidation // ( // address[] memory collateralVaults, @@ -401,12 +377,12 @@ contract JITpilot { // uint16 ltv = IEVault(controllerVault).LTVLiquidation(collateralVaults[i]); // collateralValues[i] = collateralValues[i] * 10000 / ltv; // Convert back to non-adjusted value // collateralValueTotal += collateralValues[i]; - + // // Calculate weighted average LTV // allowedLTV += ltv * collateralValues[i]; // totalWeight += collateralValues[i]; // } - + // Finalize weighted average LTV // if (totalWeight > 0) { // allowedLTV = allowedLTV / totalWeight; @@ -422,13 +398,13 @@ contract JITpilot { // #4 calculate net interest // uint256 netInterest = supplyApyTotal - borrowApy; - + // #5 get the depositValue // uint256 depositValue = collateralValueTotal - liabilityValue; return blockData; } - + struct EulerSwapData { address addr; IEulerSwap.Params params; @@ -461,11 +437,12 @@ contract JITpilot { * @dev Rebalance LP position (placeholder - to be implemented later) * @param lp LP address to rebalance */ + function rebalance(address lp) internal { // Placeholder implementation - this will perform actual rebalancing // Will be implemented in later iterations } - + /** * @dev Add authorized caller * @param caller Address to authorize @@ -473,7 +450,7 @@ contract JITpilot { function addAuthorizedCaller(address caller) external onlyAuthorized { authorizedCallers[caller] = true; } - + /** * @dev Remove authorized caller * @param caller Address to remove authorization @@ -481,7 +458,7 @@ contract JITpilot { function removeAuthorizedCaller(address caller) external onlyAuthorized { authorizedCallers[caller] = false; } - + /** * @dev Update rebalance threshold * @param newThreshold New threshold value @@ -490,7 +467,7 @@ contract JITpilot { require(newThreshold <= PRECISION, "Threshold too high"); rebalanceThreshold = newThreshold; } - + /** * @dev Update weights for composite score * @param newWeightHF New weight for Health Factor @@ -501,7 +478,7 @@ contract JITpilot { weightHF = newWeightHF; weightYield = newWeightYield; } - + /** * @dev Get LP data for viewing * @param lp LP address @@ -513,15 +490,19 @@ contract JITpilot { * @return lastUpdateBlock Last block when metrics were updated * @return initialized Whether LP data is initialized */ - function getLPData(address lp) external view returns ( - uint256 twaHF, - uint256 twaYield, - uint256 hfMin, - uint256 hfDesired, - uint256 yieldTarget, - uint256 lastUpdateBlock, - bool initialized - ) { + function getLPData(address lp) + external + view + returns ( + uint256 twaHF, + uint256 twaYield, + uint256 hfMin, + uint256 hfDesired, + uint256 yieldTarget, + uint256 lastUpdateBlock, + bool initialized + ) + { LPData storage data = lpData[lp]; return ( data.twaHF, @@ -533,7 +514,7 @@ contract JITpilot { data.initialized ); } - + /** * @dev Get current composite score for an LP * @param lp LP address @@ -542,10 +523,10 @@ contract JITpilot { function getCompositeScore(address lp) external view returns (uint256) { LPData storage data = lpData[lp]; if (!data.initialized) return 0; - + uint256 normalizedHF = _normalizeHealthFactor(data.twaHF, data.hfMin, data.hfDesired); uint256 normalizedYield = _normalizeYield(data.twaYield, data.yieldTarget); - + return (weightHF * normalizedHF + weightYield * normalizedYield) / PRECISION; } @@ -556,7 +537,7 @@ contract JITpilot { address currentControllerVault; if (controllerVaults.length == 0) return address(0); - + // find which of the LP's controller vaults is the enabled debt vault for (uint256 i; i < controllerVaults.length; ++i) { if (IEVC(EVC).isControllerEnabled(lp, controllerVaults[i])) { @@ -567,12 +548,7 @@ contract JITpilot { return currentControllerVault; } - function getCollateralValue(address account, address collateral) - internal - view - virtual - returns (uint256 value) - { + function getCollateralValue(address account, address collateral) internal view virtual returns (uint256 value) { IEVault collateralVault = IEVault(collateral); uint256 balance = IERC20(collateral).balanceOf(account); if (balance == 0) return 0; @@ -580,7 +556,8 @@ contract JITpilot { uint256 currentCollateralValue; // mid-point price - currentCollateralValue = IPriceOracle(collateralVault.oracle()).getQuote(balance, collateral, collateralVault.unitOfAccount()); + currentCollateralValue = + IPriceOracle(collateralVault.oracle()).getQuote(balance, collateral, collateralVault.unitOfAccount()); return currentCollateralValue; }