diff --git a/build/deployments-1.json b/build/deployments-1.json index 589f552a..acf42861 100644 --- a/build/deployments-1.json +++ b/build/deployments-1.json @@ -1,42 +1,47 @@ { - "executions": { - "001_CoreMainnet": 1723685111, - "002_UpgradeMainnet": 1726812322, - "003_UpgradeLidoARMScript": 1729073099, - "004_UpdateCrossPriceScript": 1739872139, - "005_RegisterLidoWithdrawalsScript": 1743500783, - "006_ChangeFeeCollector": 1751894483, - "007_UpgradeLidoARMMorphoScript": 1754407511, - "008_DeployPendleAdaptor": 1755770279, - "009_UpgradeLidoARMSetBufferScript": 1755692363, - "010_UpgradeLidoARMAssetScript": 1764755147, - "011_DeployEtherFiARMScript": 1761812927, - "012_UpgradeEtherFiARMScript": 1763557643, - "014_DeployEthenaARMScript": 1764664655, - "015_UpgradeEthenaARMScript": 1766319523 - }, - "contracts": { - "ARM_ZAPPER": "0xE11EDbd5AE4Fa434Af7f8D7F03Da1742996e7Ab2", - "ETHENA_ARM": "0xCEDa2d856238aA0D12f6329de20B9115f07C366d", - "ETHENA_ARM_CAP_IMPL": "0x7073F39ae371962C2469D72f01f907375bB11E08", - "ETHENA_ARM_CAP_MAN": "0x687AFB5A52A15122fD5FC54A8B52cfd58346fb0C", - "ETHENA_ARM_IMPL": "0x11E6bEe1662a2E2B20A7163CC33334fa1cf19979", - "ETHERFI_ARM_IMPL": "0x69b98667134EeE3eBF75799dacBCd604E28709ab", - "ETHER_FI_ARM": "0xfB0A3CF9B019BFd8827443d131b235B3E0FC58d2", - "ETHER_FI_ARM_CAP_IMPL": "0xe27720Fc3f3707D47015e274D81a99e5B0800472", - "ETHER_FI_ARM_CAP_MAN": "0xf2A18F7330141Ec737EB73A0A5Ea8E4d7e9bE7ec", - "ETHER_FI_ARM_IMPL": "0x00B53CEE151c043CBe4bbFe4cfD2938Cb4fabCEB", - "LIDO_ARM": "0x85B78AcA6Deae198fBF201c82DAF6Ca21942acc6", - "LIDO_ARM_CAP_IMPL": "0x8506486813d025C5935dF481E450e27D2e483dc9", - "LIDO_ARM_CAP_MAN": "0xf54ebff575f699d281645c6F14Fe427dFFE629CF", - "LIDO_ARM_IMPL": "0xC0297a0E39031F09406F0987C9D9D41c5dfbc3df", - "LIDO_ARM_ZAPPER": "0x01F30B7358Ba51f637d1aa05D9b4A60f76DAD680", - "MORPHO_MARKET_ETHERFI": "0x8Cf42b82fFFa3E7714D62a2cA223acBeC1Eef095", - "MORPHO_MARKET_ETHERFI_IMPL": "0x2a1b59870f7806E60dF58415B0C220C096f57658", - "MORPHO_MARKET_MEVCAPITAL": "0x29c4Bb7B1eBcc53e8CBd16480B5bAe52C69806D3", - "MORPHO_MARKET_MEVCAPITAL_IMP": "0x90c7ABC962f96de171ee395A242D2Ff794D0a04c", - "OETH_ARM": "0x6bac785889A4127dB0e0CeFEE88E0a9F1Aaf3cC7", - "OETH_ARM_IMPL": "0x187FfF686a5f42ACaaF56469FcCF8e6Feca18248", - "PENDLE_ORIGIN_ARM_SY": "0xbcae2Eb1cc47F137D8B2D351B0E0ea8DdA4C6184" - } -} + "executions": { + "001_CoreMainnet": 1723685111, + "002_UpgradeMainnet": 1726812322, + "003_UpgradeLidoARMScript": 1729073099, + "004_UpdateCrossPriceScript": 1739872139, + "005_RegisterLidoWithdrawalsScript": 1743500783, + "006_ChangeFeeCollector": 1751894483, + "007_UpgradeLidoARMMorphoScript": 1754407511, + "008_DeployPendleAdaptor": 1755770279, + "009_UpgradeLidoARMSetBufferScript": 1755692363, + "010_UpgradeLidoARMAssetScript": 1764755147, + "011_DeployEtherFiARMScript": 1761812927, + "012_UpgradeEtherFiARMScript": 1763557643, + "013_UpgradeOETHARMScript": 1765353455, + "014_DeployEthenaARMScript": 1764664655, + "015_UpgradeEthenaARMScript": 1766319523, + "016_UpdateLidoARMCrossPriceScript": 1767616727, + "017_DeployNewMorphoMarketForEtherFiARM": 1770197063 + }, + "contracts": { + "ARM_ZAPPER": "0xE11EDbd5AE4Fa434Af7f8D7F03Da1742996e7Ab2", + "ETHENA_ARM": "0xCEDa2d856238aA0D12f6329de20B9115f07C366d", + "ETHENA_ARM_CAP_IMPL": "0x7073F39ae371962C2469D72f01f907375bB11E08", + "ETHENA_ARM_CAP_MAN": "0x687AFB5A52A15122fD5FC54A8B52cfd58346fb0C", + "ETHENA_ARM_IMPL": "0x11E6bEe1662a2E2B20A7163CC33334fa1cf19979", + "ETHERFI_ARM_IMPL": "0x69b98667134EeE3eBF75799dacBCd604E28709ab", + "ETHER_FI_ARM": "0xfB0A3CF9B019BFd8827443d131b235B3E0FC58d2", + "ETHER_FI_ARM_CAP_IMPL": "0xe27720Fc3f3707D47015e274D81a99e5B0800472", + "ETHER_FI_ARM_CAP_MAN": "0xf2A18F7330141Ec737EB73A0A5Ea8E4d7e9bE7ec", + "ETHER_FI_ARM_IMPL": "0x00B53CEE151c043CBe4bbFe4cfD2938Cb4fabCEB", + "LIDO_ARM": "0x85B78AcA6Deae198fBF201c82DAF6Ca21942acc6", + "LIDO_ARM_CAP_IMPL": "0x8506486813d025C5935dF481E450e27D2e483dc9", + "LIDO_ARM_CAP_MAN": "0xf54ebff575f699d281645c6F14Fe427dFFE629CF", + "LIDO_ARM_IMPL": "0xC0297a0E39031F09406F0987C9D9D41c5dfbc3df", + "LIDO_ARM_ZAPPER": "0x01F30B7358Ba51f637d1aa05D9b4A60f76DAD680", + "MORPHO_MARKET_ETHERFI": "0xe776485B4A12d50503aF40DBEa519671318472Ed", + "MORPHO_MARKET_ETHERFI_IMPL": "0x20DC48008D4CC8988C7027bbd38e5ad6766e1d5D", + "MORPHO_MARKET_MEVCAPITAL": "0x29c4Bb7B1eBcc53e8CBd16480B5bAe52C69806D3", + "MORPHO_MARKET_MEVCAPITAL_IMP": "0x90c7ABC962f96de171ee395A242D2Ff794D0a04c", + "MORPHO_MARKET_ORIGIN": "0x0ad39D67404aE36Fe476eFDDE1306a5414383544", + "MORPHO_MARKET_ORIGIN_IMPL": "0x2ea9D1827973813D77aA8f35BD23cb1F1311A648", + "OETH_ARM": "0x6bac785889A4127dB0e0CeFEE88E0a9F1Aaf3cC7", + "OETH_ARM_IMPL": "0x9A2be51E45Eec98F75b3e6e1b334246c94663641", + "PENDLE_ORIGIN_ARM_SY": "0xbcae2Eb1cc47F137D8B2D351B0E0ea8DdA4C6184" + } +} \ No newline at end of file diff --git a/script/deploy/DeployManager.sol b/script/deploy/DeployManager.sol index e4fbcdde..7f111a76 100644 --- a/script/deploy/DeployManager.sol +++ b/script/deploy/DeployManager.sol @@ -25,6 +25,7 @@ import {UpgradeOETHARMScript} from "./mainnet/013_UpgradeOETHARMScript.sol"; import {DeployEthenaARMScript} from "./mainnet/014_DeployEthenaARMScript.sol"; import {UpgradeEthenaARMScript} from "./mainnet/015_UpgradeEthenaARMScript.sol"; import {UpgradeLidoARMCrossPriceScript} from "./mainnet/016_UpdateLidoARMCrossPriceScript.sol"; +import {DeployNewMorphoMarketForEtherFiARM} from "./mainnet/017_DeployNewMorphoMarketForEtherFiARM.sol"; import {EmptyScript} from "./mainnet/999_empty.sol"; contract DeployManager is Script { @@ -89,6 +90,7 @@ contract DeployManager is Script { _runDeployFile(new DeployEthenaARMScript()); _runDeployFile(new UpgradeEthenaARMScript()); _runDeployFile(new UpgradeLidoARMCrossPriceScript()); + _runDeployFile(new DeployNewMorphoMarketForEtherFiARM()); _runDeployFile(new EmptyScript()); } else if (block.chainid == 17000) { // Holesky diff --git a/script/deploy/mainnet/017_DeployNewMorphoMarketForEtherFiARM.sol b/script/deploy/mainnet/017_DeployNewMorphoMarketForEtherFiARM.sol new file mode 100644 index 00000000..0d7de52e --- /dev/null +++ b/script/deploy/mainnet/017_DeployNewMorphoMarketForEtherFiARM.sol @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.23; + +// Foundry imports +import {console} from "forge-std/console.sol"; + +// Contract imports +import {Proxy} from "contracts/Proxy.sol"; +import {Mainnet} from "contracts/utils/Addresses.sol"; +import {MorphoMarket} from "contracts/markets/MorphoMarket.sol"; +import {Abstract4626MarketWrapper} from "contracts/markets/Abstract4626MarketWrapper.sol"; + +// Deployment imports +import {GovProposal, GovSixHelper} from "contracts/utils/GovSixHelper.sol"; +import {AbstractDeployScript} from "../AbstractDeployScript.sol"; + +contract DeployNewMorphoMarketForEtherFiARM is AbstractDeployScript { + using GovSixHelper for GovProposal; + + GovProposal public govProposal; + + string public constant override DEPLOY_NAME = "017_DeployNewMorphoMarketForEtherFiARM"; + bool public constant override proposalExecuted = false; + + Proxy morphoMarketProxy; + MorphoMarket morphoMarket; + + function _execute() internal override { + console.log("Deploy:", DEPLOY_NAME); + console.log("------------"); + + // 1. Deploy MorphoMarket proxy + morphoMarketProxy = new Proxy(); + _recordDeploy("MORPHO_MARKET_ETHERFI", address(morphoMarketProxy)); + + // 2. Deploy MorphoMarket + morphoMarket = new MorphoMarket(Mainnet.ETHERFI_ARM, Mainnet.MORPHO_MARKET_OETH_VAULT); + _recordDeploy("MORPHO_MARKET_ETHERFI_IMPL", address(morphoMarket)); + // 3. Initialize MorphoMarket proxy with the implementation, Timelock as owner + bytes memory data = abi.encodeWithSelector( + Abstract4626MarketWrapper.initialize.selector, Mainnet.STRATEGIST, Mainnet.MERKLE_DISTRIBUTOR + ); + morphoMarketProxy.initialize(address(morphoMarket), Mainnet.TIMELOCK, data); + + console.log("Finished deploying", DEPLOY_NAME); + } +} diff --git a/src/contracts/utils/Addresses.sol b/src/contracts/utils/Addresses.sol index 605e9b35..a43b5252 100644 --- a/src/contracts/utils/Addresses.sol +++ b/src/contracts/utils/Addresses.sol @@ -60,6 +60,7 @@ library Mainnet { address public constant MORPHO_MARKET_MEVCAPITAL = 0x9a8bC3B04b7f3D87cfC09ba407dCED575f2d61D8; address public constant MORPHO_MARKET_ETHERFI = 0x4881Ef0BF6d2365D3dd6499ccd7532bcdBCE0658; address public constant MORPHO_MARKET_YEARN_OG = 0xE89371eAaAC6D46d4C3ED23453241987916224FC; + address public constant MORPHO_MARKET_OETH_VAULT = 0x3Dfe70B05657949A5dB340754aD664810ac63b21; // Apostro Ethena USDe is currently the only curated Morpho market that takes USDe address public constant MORPHO_MARKET_ETHENA = 0x4EDfaB296F8Eb15aC0907CF9eCb7079b1679Da57; diff --git a/test/smoke/EthenaARMSmokeTest.t.sol b/test/smoke/EthenaARMSmokeTest.t.sol index 1900e7a6..a39816e9 100644 --- a/test/smoke/EthenaARMSmokeTest.t.sol +++ b/test/smoke/EthenaARMSmokeTest.t.sol @@ -212,6 +212,7 @@ contract Fork_EthenaARM_Smoke_Test is AbstractSmokeTest { _swapExactTokensForTokens(susde, usde, 0.998e36, 100 ether); // Operator requests an Ethena withdrawal + skip(ethenaARM.DELAY_REQUEST() + 1); vm.prank(Mainnet.ARM_RELAYER); ethenaARM.requestBaseWithdrawal(10 ether); } @@ -221,6 +222,7 @@ contract Fork_EthenaARM_Smoke_Test is AbstractSmokeTest { _swapExactTokensForTokens(susde, usde, 0.998e36, 100 ether); // Owner requests an Ethena withdrawal + skip(ethenaARM.DELAY_REQUEST() + 1); vm.prank(Mainnet.TIMELOCK); ethenaARM.requestBaseWithdrawal(10 ether); } @@ -231,6 +233,7 @@ contract Fork_EthenaARM_Smoke_Test is AbstractSmokeTest { // Owner requests an Ethena withdrawal uint256 nextUnstakerIndex = ethenaARM.nextUnstakerIndex(); + skip(ethenaARM.DELAY_REQUEST() + 1); vm.prank(Mainnet.TIMELOCK); ethenaARM.requestBaseWithdrawal(10 ether); diff --git a/test/smoke/EtherFiARMSmokeTest.t.sol b/test/smoke/EtherFiARMSmokeTest.t.sol index cd8c1932..05eeec0b 100644 --- a/test/smoke/EtherFiARMSmokeTest.t.sol +++ b/test/smoke/EtherFiARMSmokeTest.t.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.23; import {AbstractSmokeTest} from "./AbstractSmokeTest.sol"; -import {IERC20, IEETHWithdrawalNFT} from "contracts/Interfaces.sol"; +import {IERC20, IERC4626, IEETHWithdrawalNFT} from "contracts/Interfaces.sol"; import {EtherFiARM} from "contracts/EtherFiARM.sol"; import {CapManager} from "contracts/CapManager.sol"; import {Proxy} from "contracts/Proxy.sol"; @@ -19,6 +19,7 @@ contract Fork_EtherFiARM_Smoke_Test is AbstractSmokeTest { EtherFiARM etherFiARM; CapManager capManager; IEETHWithdrawalNFT etherfiWithdrawalNFT; + IERC4626 morphoMarket; address operator; function setUp() public { @@ -34,6 +35,7 @@ contract Fork_EtherFiARM_Smoke_Test is AbstractSmokeTest { etherFiARM = EtherFiARM(payable(deployManager.getDeployment("ETHER_FI_ARM"))); capManager = CapManager(deployManager.getDeployment("ETHER_FI_ARM_CAP_MAN")); etherfiWithdrawalNFT = IEETHWithdrawalNFT(Mainnet.ETHERFI_WITHDRAWAL_NFT); + morphoMarket = IERC4626(deployManager.getDeployment("MORPHO_MARKET_ETHERFI")); vm.prank(etherFiARM.owner()); etherFiARM.setOwner(Mainnet.TIMELOCK); @@ -253,4 +255,78 @@ contract Fork_EtherFiARM_Smoke_Test is AbstractSmokeTest { requestIdArray[0] = requestId; etherFiARM.claimEtherFiWithdrawals(requestIdArray); } + + /* Lending Market Allocation Tests */ + + function test_allocate_to_lending_market() external { + // Add and set the active market to the Morpho market + vm.startPrank(Mainnet.TIMELOCK); + if (!etherFiARM.supportedMarkets(address(morphoMarket))) { + address[] memory markets = new address[](1); + markets[0] = address(morphoMarket); + etherFiARM.addMarkets(markets); + } + etherFiARM.setActiveMarket(address(morphoMarket)); + vm.stopPrank(); + + // Deal WETH to the ARM + deal(address(weth), address(etherFiARM), 100 ether); + + uint256 armWethBefore = weth.balanceOf(address(etherFiARM)); + uint256 marketBalanceBefore = morphoMarket.maxWithdraw(address(etherFiARM)); + + // Set buffer to 0% so all liquidity goes to the lending market + vm.prank(Mainnet.ARM_RELAYER); + etherFiARM.setARMBuffer(0); + + // Allocate liquidity to the lending market + vm.prank(Mainnet.ARM_RELAYER); + (, int256 actualDelta) = etherFiARM.allocate(); + + uint256 armWethAfter = weth.balanceOf(address(etherFiARM)); + uint256 marketBalanceAfter = morphoMarket.maxWithdraw(address(etherFiARM)); + + // Verify liquidity moved to the lending market + assertGt(actualDelta, 0, "Actual delta should be positive (deposited to market)"); + assertLt(armWethAfter, armWethBefore, "ARM WETH balance should decrease"); + assertGt(marketBalanceAfter, marketBalanceBefore, "Market balance should increase"); + } + + function test_allocate_from_lending_market() external { + // Add and set the active market to the Morpho market + vm.startPrank(Mainnet.TIMELOCK); + if (!etherFiARM.supportedMarkets(address(morphoMarket))) { + address[] memory markets = new address[](1); + markets[0] = address(morphoMarket); + etherFiARM.addMarkets(markets); + } + etherFiARM.setActiveMarket(address(morphoMarket)); + vm.stopPrank(); + + // Deal WETH to the ARM and allocate to market with buffer at 0% + deal(address(weth), address(etherFiARM), 100 ether); + vm.prank(Mainnet.ARM_RELAYER); + etherFiARM.setARMBuffer(0); + vm.prank(Mainnet.ARM_RELAYER); + etherFiARM.allocate(); + + uint256 armWethBefore = weth.balanceOf(address(etherFiARM)); + uint256 marketBalanceBefore = morphoMarket.maxWithdraw(address(etherFiARM)); + + // Set buffer to 100% so liquidity comes back from the lending market + vm.prank(Mainnet.ARM_RELAYER); + etherFiARM.setARMBuffer(1e18); + + // Allocate liquidity from the lending market + vm.prank(Mainnet.ARM_RELAYER); + (, int256 actualDelta) = etherFiARM.allocate(); + + uint256 armWethAfter = weth.balanceOf(address(etherFiARM)); + uint256 marketBalanceAfter = morphoMarket.maxWithdraw(address(etherFiARM)); + + // Verify liquidity moved from the lending market (as much as available) + assertLt(actualDelta, 0, "Actual delta should be negative (withdrawn from market)"); + assertGt(armWethAfter, armWethBefore, "ARM WETH balance should increase"); + assertLe(marketBalanceAfter, marketBalanceBefore, "Market balance should decrease or stay same"); + } } diff --git a/test/smoke/LidoARMSmokeTest.t.sol b/test/smoke/LidoARMSmokeTest.t.sol index bab81a91..95bb40da 100644 --- a/test/smoke/LidoARMSmokeTest.t.sol +++ b/test/smoke/LidoARMSmokeTest.t.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.23; import {AbstractSmokeTest} from "./AbstractSmokeTest.sol"; -import {IERC20, IStETHWithdrawal} from "contracts/Interfaces.sol"; +import {IERC20, IERC4626, IStETHWithdrawal} from "contracts/Interfaces.sol"; import {LidoARM} from "contracts/LidoARM.sol"; import {CapManager} from "contracts/CapManager.sol"; import {Proxy} from "contracts/Proxy.sol"; @@ -18,6 +18,7 @@ contract Fork_LidoARM_Smoke_Test is AbstractSmokeTest { Proxy proxy; LidoARM lidoARM; CapManager capManager; + IERC4626 morphoMarket; address operator; function setUp() public { @@ -32,6 +33,7 @@ contract Fork_LidoARM_Smoke_Test is AbstractSmokeTest { proxy = Proxy(payable(deployManager.getDeployment("LIDO_ARM"))); lidoARM = LidoARM(payable(deployManager.getDeployment("LIDO_ARM"))); capManager = CapManager(deployManager.getDeployment("LIDO_ARM_CAP_MAN")); + morphoMarket = IERC4626(deployManager.getDeployment("MORPHO_MARKET_MEVCAPITAL")); // Only fuzz from this address. Big speedup on fork. targetSender(address(this)); @@ -229,4 +231,78 @@ contract Fork_LidoARM_Smoke_Test is AbstractSmokeTest { assertEq(totalAmountRequested, lidoARM.lidoWithdrawalQueueAmount()); } + + /* Lending Market Allocation Tests */ + + function test_allocate_to_lending_market() external { + // Add and set the active market to the Morpho market + vm.startPrank(Mainnet.TIMELOCK); + if (!lidoARM.supportedMarkets(address(morphoMarket))) { + address[] memory markets = new address[](1); + markets[0] = address(morphoMarket); + lidoARM.addMarkets(markets); + } + lidoARM.setActiveMarket(address(morphoMarket)); + vm.stopPrank(); + + // Deal WETH to the ARM + deal(address(weth), address(lidoARM), 100 ether); + + uint256 armWethBefore = weth.balanceOf(address(lidoARM)); + uint256 marketBalanceBefore = morphoMarket.maxWithdraw(address(lidoARM)); + + // Set buffer to 0% so all liquidity goes to the lending market + vm.prank(Mainnet.ARM_RELAYER); + lidoARM.setARMBuffer(0); + + // Allocate liquidity to the lending market + vm.prank(Mainnet.ARM_RELAYER); + (, int256 actualDelta) = lidoARM.allocate(); + + uint256 armWethAfter = weth.balanceOf(address(lidoARM)); + uint256 marketBalanceAfter = morphoMarket.maxWithdraw(address(lidoARM)); + + // Verify liquidity moved to the lending market + assertGt(actualDelta, 0, "Actual delta should be positive (deposited to market)"); + assertLt(armWethAfter, armWethBefore, "ARM WETH balance should decrease"); + assertGt(marketBalanceAfter, marketBalanceBefore, "Market balance should increase"); + } + + function test_allocate_from_lending_market() external { + // Add and set the active market to the Morpho market + vm.startPrank(Mainnet.TIMELOCK); + if (!lidoARM.supportedMarkets(address(morphoMarket))) { + address[] memory markets = new address[](1); + markets[0] = address(morphoMarket); + lidoARM.addMarkets(markets); + } + lidoARM.setActiveMarket(address(morphoMarket)); + vm.stopPrank(); + + // Deal WETH to the ARM and allocate to market with buffer at 0% + deal(address(weth), address(lidoARM), 100 ether); + vm.prank(Mainnet.ARM_RELAYER); + lidoARM.setARMBuffer(0); + vm.prank(Mainnet.ARM_RELAYER); + lidoARM.allocate(); + + uint256 armWethBefore = weth.balanceOf(address(lidoARM)); + uint256 marketBalanceBefore = morphoMarket.maxWithdraw(address(lidoARM)); + + // Set buffer to 100% so liquidity comes back from the lending market + vm.prank(Mainnet.ARM_RELAYER); + lidoARM.setARMBuffer(1e18); + + // Allocate liquidity from the lending market + vm.prank(Mainnet.ARM_RELAYER); + (, int256 actualDelta) = lidoARM.allocate(); + + uint256 armWethAfter = weth.balanceOf(address(lidoARM)); + uint256 marketBalanceAfter = morphoMarket.maxWithdraw(address(lidoARM)); + + // Verify liquidity moved from the lending market (as much as available) + assertLt(actualDelta, 0, "Actual delta should be negative (withdrawn from market)"); + assertGt(armWethAfter, armWethBefore, "ARM WETH balance should increase"); + assertLe(marketBalanceAfter, marketBalanceBefore, "Market balance should decrease or stay same"); + } } diff --git a/test/smoke/OethARMSmokeTest.t.sol b/test/smoke/OethARMSmokeTest.t.sol index e8e0de85..67621898 100644 --- a/test/smoke/OethARMSmokeTest.t.sol +++ b/test/smoke/OethARMSmokeTest.t.sol @@ -5,7 +5,7 @@ import {Test} from "forge-std/Test.sol"; import {AbstractSmokeTest} from "./AbstractSmokeTest.sol"; -import {IERC20} from "contracts/Interfaces.sol"; +import {IERC20, IERC4626} from "contracts/Interfaces.sol"; import {Proxy} from "contracts/Proxy.sol"; import {Mainnet} from "contracts/utils/Addresses.sol"; import {OriginARM} from "contracts/OriginARM.sol"; @@ -17,6 +17,7 @@ contract Fork_OriginARM_Smoke_Test is AbstractSmokeTest { IERC20 oeth; Proxy proxy; OriginARM originARM; + IERC4626 morphoMarket; address operator; function setUp() public { @@ -30,6 +31,7 @@ contract Fork_OriginARM_Smoke_Test is AbstractSmokeTest { proxy = Proxy(payable(deployManager.getDeployment("OETH_ARM"))); originARM = OriginARM(deployManager.getDeployment("OETH_ARM")); + morphoMarket = IERC4626(deployManager.getDeployment("MORPHO_MARKET_ORIGIN")); _dealWETH(address(originARM), 100 ether); _dealOETH(address(originARM), 100 ether); @@ -317,4 +319,78 @@ contract Fork_OriginARM_Smoke_Test is AbstractSmokeTest { uint256 amountClaimed = originARM.claimOriginWithdrawals(requestIds); assertEq(amountClaimed, 10 ether); } + + /* Lending Market Allocation Tests */ + + function test_allocate_to_lending_market() external { + // Add and set the active market to the Morpho market + vm.startPrank(Mainnet.TIMELOCK); + if (!originARM.supportedMarkets(address(morphoMarket))) { + address[] memory markets = new address[](1); + markets[0] = address(morphoMarket); + originARM.addMarkets(markets); + } + originARM.setActiveMarket(address(morphoMarket)); + vm.stopPrank(); + + // Deal WETH to the ARM + deal(address(weth), address(originARM), 100 ether); + + uint256 armWethBefore = weth.balanceOf(address(originARM)); + uint256 marketBalanceBefore = morphoMarket.maxWithdraw(address(originARM)); + + // Set buffer to 0% so all liquidity goes to the lending market + vm.prank(Mainnet.ARM_RELAYER); + originARM.setARMBuffer(0); + + // Allocate liquidity to the lending market + vm.prank(Mainnet.ARM_RELAYER); + (, int256 actualDelta) = originARM.allocate(); + + uint256 armWethAfter = weth.balanceOf(address(originARM)); + uint256 marketBalanceAfter = morphoMarket.maxWithdraw(address(originARM)); + + // Verify liquidity moved to the lending market + assertGt(actualDelta, 0, "Actual delta should be positive (deposited to market)"); + assertLt(armWethAfter, armWethBefore, "ARM WETH balance should decrease"); + assertGt(marketBalanceAfter, marketBalanceBefore, "Market balance should increase"); + } + + function test_allocate_from_lending_market() external { + // Add and set the active market to the Morpho market + vm.startPrank(Mainnet.TIMELOCK); + if (!originARM.supportedMarkets(address(morphoMarket))) { + address[] memory markets = new address[](1); + markets[0] = address(morphoMarket); + originARM.addMarkets(markets); + } + originARM.setActiveMarket(address(morphoMarket)); + vm.stopPrank(); + + // Deal WETH to the ARM and allocate to market with buffer at 0% + deal(address(weth), address(originARM), 100 ether); + vm.prank(Mainnet.ARM_RELAYER); + originARM.setARMBuffer(0); + vm.prank(Mainnet.ARM_RELAYER); + originARM.allocate(); + + uint256 armWethBefore = weth.balanceOf(address(originARM)); + uint256 marketBalanceBefore = morphoMarket.maxWithdraw(address(originARM)); + + // Set buffer to 100% so liquidity comes back from the lending market + vm.prank(Mainnet.ARM_RELAYER); + originARM.setARMBuffer(1e18); + + // Allocate liquidity from the lending market + vm.prank(Mainnet.ARM_RELAYER); + (, int256 actualDelta) = originARM.allocate(); + + uint256 armWethAfter = weth.balanceOf(address(originARM)); + uint256 marketBalanceAfter = morphoMarket.maxWithdraw(address(originARM)); + + // Verify liquidity moved from the lending market (as much as available) + assertLt(actualDelta, 0, "Actual delta should be negative (withdrawn from market)"); + assertGt(armWethAfter, armWethBefore, "ARM WETH balance should increase"); + assertLe(marketBalanceAfter, marketBalanceBefore, "Market balance should decrease or stay same"); + } }