From defb4e62f7f9b040280bf03099dac5e67b6bb17d Mon Sep 17 00:00:00 2001 From: Luke Hackett Date: Tue, 29 Sep 2026 09:50:54 +0100 Subject: [PATCH 1/3] Add synchronous Midas withdrawal settlement script --- src/request/scripts/SyncMidasWithdrawal.sol | 61 +++++++++++++ test/request/MorphoFlashLoanRequest.t.sol | 97 ++++++++++++++++++++- 2 files changed, 156 insertions(+), 2 deletions(-) create mode 100644 src/request/scripts/SyncMidasWithdrawal.sol diff --git a/src/request/scripts/SyncMidasWithdrawal.sol b/src/request/scripts/SyncMidasWithdrawal.sol new file mode 100644 index 00000000..ba51cadd --- /dev/null +++ b/src/request/scripts/SyncMidasWithdrawal.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.24; + +import {IFacilityFunds} from "../../interfaces/facility/base/IFacilityFunds.sol"; +import {IFacilityIntents} from "../../interfaces/facility/base/IFacilityIntents.sol"; +import {IFacilityPositionManager} from "../../interfaces/facility/base/IFacilityPositionManager.sol"; +import {IPositionManager} from "../../interfaces/manager/IPositionManager.sol"; +import {WithdrawalStrategy} from "../../interfaces/manager/base/IPositionManagerAdmin.sol"; +import {Asset, IntentProperties} from "../../libs/facility/LibIntent.sol"; +import {FixedPointMathLib} from "lib/solady/src/utils/FixedPointMathLib.sol"; + +/// @title SyncMidasWithdrawal +/// @notice Stateless script designed to be delegatecalled from MorphoFlashLoanRequest after a +/// bonded Midas redeem has been unlocked for instant settlement. +/// @dev Must NOT have any storage variables. The redeem order must already exist and its first +/// commit must already have paid the bond. Repays enough live debt to restore the target LTV, +/// withdraws the remaining redemption collateral, then executes second commit -> unlock; +/// MorphoFlashLoanRequest supplies and repays the debt asset around this call. +/// @author 3F Protocol +contract SyncMidasWithdrawal { + using FixedPointMathLib for uint256; + + uint256 private constant _WAD = 1e18; + + error InvalidPositionManager(); + error InvalidTargetLtv(); + error InvalidWithdrawAmount(); + error TargetLtvExceeded(); + + /// @notice Restores the target LTV, settles the remaining Midas redeem, and unlocks its proceeds. + /// @param facility The facility contract address. + /// @param intentId The intent ID on the facility. + /// @param withdrawAmount The remaining collateral required by the Midas redemption. + /// @param targetLtv The maximum LTV after the withdrawal, in WAD precision. + /// @param useTarget Whether the intent's target asset is the position manager. + function run(address facility, uint256 intentId, uint256 withdrawAmount, uint256 targetLtv, bool useTarget) external { + if (targetLtv >= _WAD) revert InvalidTargetLtv(); + + (IntentProperties memory properties,,,) = IFacilityIntents(facility).getIntent(intentId); + Asset memory managerAsset = useTarget ? properties.targetAsset : properties.depositAsset; + if (!managerAsset.isPositionManager) revert InvalidPositionManager(); + + IPositionManager manager = IPositionManager(managerAsset.asset); + uint256 collateral = manager.collateralAmount(); + if (withdrawAmount == 0 || withdrawAmount > collateral) revert InvalidWithdrawAmount(); + + uint256 quotedCollateral = manager.collateralAmountQuoted(); + uint256 quotedWithdrawal = quotedCollateral.mulDivUp(withdrawAmount, collateral); + uint256 targetDebt = (quotedCollateral - quotedWithdrawal).mulDiv(targetLtv, _WAD); + uint256 liveDebt = manager.debtAmount(); + uint256 repayAmount = liveDebt > targetDebt ? liveDebt - targetDebt : 0; + + IFacilityPositionManager(facility) + .withdrawManager(intentId, withdrawAmount, repayAmount, useTarget, WithdrawalStrategy.PROPORTIONAL); + // A partial withdrawal queue can remove more quoted value than the aggregate estimate. + if (manager.debtAmount() > manager.collateralAmountQuoted().mulDiv(targetLtv, _WAD)) revert TargetLtvExceeded(); + + IFacilityFunds(facility).commit(intentId); + IFacilityFunds(facility).unlock(intentId); + } +} diff --git a/test/request/MorphoFlashLoanRequest.t.sol b/test/request/MorphoFlashLoanRequest.t.sol index 862b0443..ebb5e773 100644 --- a/test/request/MorphoFlashLoanRequest.t.sol +++ b/test/request/MorphoFlashLoanRequest.t.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.24; import {FacilityBaseTest} from "test/facility/FacilityBase.t.sol"; import {MorphoFlashLoanRequest} from "src/request/MorphoFlashLoanRequest.sol"; import {MorphoFlashLoanRequestFactory} from "src/request/MorphoFlashLoanRequestFactory.sol"; +import {SyncMidasWithdrawal} from "src/request/scripts/SyncMidasWithdrawal.sol"; import {SyncDeposit} from "src/request/scripts/SyncDeposit.sol"; import {SyncWithdrawal} from "src/request/scripts/SyncWithdrawal.sol"; import {SyncAllocatorDeposit} from "src/request/scripts/SyncAllocatorDeposit.sol"; @@ -12,6 +13,7 @@ import {MockMorphoAllocator} from "test/mock/request/MockMorphoAllocator.sol"; import {Offer} from "src/interfaces/request/IOfferReceiver.sol"; import {LibCommonErrors} from "src/libs/common/LibCommonErrors.sol"; import {MockERC20} from "test/mock/MockERC20.sol"; +import {MockBorrowPosition} from "test/mock/borrow/MockBorrowPosition.sol"; import {Mode, State} from "src/libs/funds/Order.sol"; import {IntentProperties, Asset} from "src/libs/facility/LibIntent.sol"; import {WithdrawalStrategy} from "src/interfaces/manager/base/IPositionManagerAdmin.sol"; @@ -105,6 +107,7 @@ contract MorphoFlashLoanRequestTest is FacilityBaseTest { MorphoFlashLoanRequest public flashLoanRequest; MockScript public mockScript; SyncDeposit public syncDeposit; + SyncMidasWithdrawal public syncMidasWithdrawal; SyncWithdrawal public syncWithdrawal; SyncAllocatorDeposit public syncAllocatorDeposit; MockMorphoAllocator public mockAllocator; @@ -141,6 +144,12 @@ contract MorphoFlashLoanRequestTest is FacilityBaseTest { vm.prank(owner); flashLoanRequest.setScript(address(syncDeposit), true); + // Deploy and whitelist SyncMidasWithdrawal + syncMidasWithdrawal = new SyncMidasWithdrawal(); + vm.label(address(syncMidasWithdrawal), "SyncMidasWithdrawal"); + vm.prank(owner); + flashLoanRequest.setScript(address(syncMidasWithdrawal), true); + // Deploy and whitelist SyncWithdrawal syncWithdrawal = new SyncWithdrawal(); vm.label(address(syncWithdrawal), "SyncWithdrawal"); @@ -908,8 +917,8 @@ contract MorphoFlashLoanRequestTest is FacilityBaseTest { .execute( actualDebtBorrowed, MorphoFlashLoanRequest.SetRequestParams({ - intentId: syncIntentId, deadline: block.timestamp + 2 hours, signers: signers, signatures: sigs - }), + intentId: syncIntentId, deadline: block.timestamp + 2 hours, signers: signers, signatures: sigs + }), address(syncWithdrawal), withdrawPayload ); @@ -937,6 +946,90 @@ contract MorphoFlashLoanRequestTest is FacilityBaseTest { assertEq(collateralToken.balanceOf(address(facility)), 0); } + function test_execute_syncMidasWithdrawalCommitUnlock() public { + uint256 morphoBalBefore = debtToken.balanceOf(address(morpho)); + vm.prank(facilitator); + facility.depositManager(intentId, 0, 5_000e18, false); + + // A price drop makes the live LTV exceed the requested 50% target. + oracle.setPrice(0.9e36); + uint256 withdrawAmount = 1_000e18; + uint256 repayAmount = 950e18; // 5,000 - (10,000 - 1,000) * 0.9 * 0.5 + vm.prank(facilitator); + _setFund(intentId, address(mockFund)); + // MockFund represents the remaining redemption at the script's facility boundary. + mockFund.setNextCommitState(State.UNLOCKING); + mockFund.setUnlockAmount(withdrawAmount); + debtToken.setBalance(address(mockFund), withdrawAmount); + vm.prank(facilitator); + facility.create(intentId, withdrawAmount, withdrawAmount, Mode.REDEEM); + + vm.prank(executor); + flashLoanRequest.execute( + repayAmount, + _buildSetRequestParams(intentId, block.timestamp + 1 hours), + address(syncMidasWithdrawal), + abi.encodeCall(SyncMidasWithdrawal.run, (address(facility), intentId, withdrawAmount, 0.5e18, false)) + ); + + assertEq(positionManager.collateralAmount(), 9_000e18); + assertEq(positionManager.debtAmount(), 4_050e18); + assertEq(positionManager.debtAmount() * 1e18 / positionManager.collateralAmountQuoted(), 0.5e18); + assertEq(collateralToken.balanceOf(address(mockFund)), withdrawAmount); + assertEq(collateralToken.balanceOf(address(facility)), 0); + assertEq(debtToken.balanceOf(address(facility)), 5_050e18); + assertEq(debtToken.balanceOf(address(morpho)), morphoBalBefore - 4_050e18); + assertEq(debtToken.balanceOf(address(flashLoanRequest)), 0); + (, address fund, address request,) = facility.getIntent(intentId); + assertEq(fund, address(0)); + assertEq(request, address(0)); + } + + function test_syncMidasWithdrawal_rejectsInvalidParameters() public { + vm.expectRevert(SyncMidasWithdrawal.InvalidTargetLtv.selector); + syncMidasWithdrawal.run(address(facility), intentId, 1, 1e18, false); + vm.expectRevert(SyncMidasWithdrawal.InvalidPositionManager.selector); + syncMidasWithdrawal.run(address(facility), intentId, 1, 0.5e18, true); + vm.expectRevert(SyncMidasWithdrawal.InvalidWithdrawAmount.selector); + syncMidasWithdrawal.run(address(facility), intentId, 0, 0.5e18, false); + uint256 tooMuch = positionManager.collateralAmount() + 1; + vm.expectRevert(SyncMidasWithdrawal.InvalidWithdrawAmount.selector); + syncMidasWithdrawal.run(address(facility), intentId, tooMuch, 0.5e18, false); + } + + function test_syncMidasWithdrawal_revertsWhenPartialQueueRemovesMoreQuotedCollateral() public { + vm.prank(facilitator); + facility.depositManager(intentId, 0, 4_500e18, false); + + // This lower-priced module contributes to the aggregate quote but is excluded from withdrawals. + MockBorrowPosition excluded = new MockBorrowPosition(address(collateralToken), address(debtToken)); + excluded.setTotalCollateral(10_000e18); + excluded.setTotalCollateralQuoted(5_000e18); + excluded.setSafeLtv(uint128(PM_LTV)); + vm.mockCall(address(excluded), abi.encodeWithSignature("owner()"), abi.encode(address(positionManager))); + vm.prank(owner); + positionManager.addBorrowModule(address(excluded)); + + uint256 withdrawAmount = 1_000e18; + uint256 repayAmount = 225e18; // Aggregate quote estimates 750 removed; the queued position removes 1,000. + vm.prank(facilitator); + _setFund(intentId, address(mockFund)); + mockFund.setNextCommitState(State.UNLOCKING); + mockFund.setUnlockAmount(withdrawAmount); + debtToken.setBalance(address(mockFund), withdrawAmount); + vm.prank(facilitator); + facility.create(intentId, withdrawAmount, withdrawAmount, Mode.REDEEM); + + vm.prank(executor); + vm.expectRevert(SyncMidasWithdrawal.TargetLtvExceeded.selector); + flashLoanRequest.execute( + repayAmount, + _buildSetRequestParams(intentId, block.timestamp + 1 hours), + address(syncMidasWithdrawal), + abi.encodeCall(SyncMidasWithdrawal.run, (address(facility), intentId, withdrawAmount, 0.3e18, false)) + ); + } + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* I. pullFunds() TESTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ From 880879ba8bf9f90a63ac03069ec37b6876d83da5 Mon Sep 17 00:00:00 2001 From: Luke Hackett Date: Tue, 29 Sep 2026 09:52:04 +0100 Subject: [PATCH 2/3] Preserve existing formatting for CI --- test/request/MorphoFlashLoanRequest.t.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/request/MorphoFlashLoanRequest.t.sol b/test/request/MorphoFlashLoanRequest.t.sol index ebb5e773..8dd6704f 100644 --- a/test/request/MorphoFlashLoanRequest.t.sol +++ b/test/request/MorphoFlashLoanRequest.t.sol @@ -917,8 +917,8 @@ contract MorphoFlashLoanRequestTest is FacilityBaseTest { .execute( actualDebtBorrowed, MorphoFlashLoanRequest.SetRequestParams({ - intentId: syncIntentId, deadline: block.timestamp + 2 hours, signers: signers, signatures: sigs - }), + intentId: syncIntentId, deadline: block.timestamp + 2 hours, signers: signers, signatures: sigs + }), address(syncWithdrawal), withdrawPayload ); From dc1296780fe056557223ec6591a607ce99f8e53e Mon Sep 17 00:00:00 2001 From: Luke Hackett Date: Tue, 29 Sep 2026 09:58:17 +0100 Subject: [PATCH 3/3] Simplify Midas withdrawal helper to explicit amounts --- src/request/scripts/SyncMidasWithdrawal.sol | 66 +++++++-------------- test/request/MorphoFlashLoanRequest.t.sol | 64 +++----------------- 2 files changed, 31 insertions(+), 99 deletions(-) diff --git a/src/request/scripts/SyncMidasWithdrawal.sol b/src/request/scripts/SyncMidasWithdrawal.sol index ba51cadd..59ce185e 100644 --- a/src/request/scripts/SyncMidasWithdrawal.sol +++ b/src/request/scripts/SyncMidasWithdrawal.sol @@ -2,60 +2,38 @@ pragma solidity ^0.8.24; import {IFacilityFunds} from "../../interfaces/facility/base/IFacilityFunds.sol"; -import {IFacilityIntents} from "../../interfaces/facility/base/IFacilityIntents.sol"; import {IFacilityPositionManager} from "../../interfaces/facility/base/IFacilityPositionManager.sol"; -import {IPositionManager} from "../../interfaces/manager/IPositionManager.sol"; import {WithdrawalStrategy} from "../../interfaces/manager/base/IPositionManagerAdmin.sol"; -import {Asset, IntentProperties} from "../../libs/facility/LibIntent.sol"; -import {FixedPointMathLib} from "lib/solady/src/utils/FixedPointMathLib.sol"; /// @title SyncMidasWithdrawal -/// @notice Stateless script designed to be delegatecalled from MorphoFlashLoanRequest after a -/// bonded Midas redeem has been unlocked for instant settlement. -/// @dev Must NOT have any storage variables. The redeem order must already exist and its first -/// commit must already have paid the bond. Repays enough live debt to restore the target LTV, -/// withdraws the remaining redemption collateral, then executes second commit -> unlock; -/// MorphoFlashLoanRequest supplies and repays the debt asset around this call. +/// @notice Stateless script designed to be delegatecalled from MorphoFlashLoanRequest. +/// Executes the remaining Midas redemption flow: withdrawManager → commit → unlock. +/// @dev Must NOT have any storage variables. The redeem order must already exist, its bond +/// leg must be complete, and instant redemption must be unlocked before execute(). /// @author 3F Protocol contract SyncMidasWithdrawal { - using FixedPointMathLib for uint256; - - uint256 private constant _WAD = 1e18; - - error InvalidPositionManager(); - error InvalidTargetLtv(); - error InvalidWithdrawAmount(); - error TargetLtvExceeded(); - - /// @notice Restores the target LTV, settles the remaining Midas redeem, and unlocks its proceeds. + /// @notice Settles the remaining Midas redemption for a facility intent. /// @param facility The facility contract address. /// @param intentId The intent ID on the facility. /// @param withdrawAmount The remaining collateral required by the Midas redemption. - /// @param targetLtv The maximum LTV after the withdrawal, in WAD precision. - /// @param useTarget Whether the intent's target asset is the position manager. - function run(address facility, uint256 intentId, uint256 withdrawAmount, uint256 targetLtv, bool useTarget) external { - if (targetLtv >= _WAD) revert InvalidTargetLtv(); - - (IntentProperties memory properties,,,) = IFacilityIntents(facility).getIntent(intentId); - Asset memory managerAsset = useTarget ? properties.targetAsset : properties.depositAsset; - if (!managerAsset.isPositionManager) revert InvalidPositionManager(); - - IPositionManager manager = IPositionManager(managerAsset.asset); - uint256 collateral = manager.collateralAmount(); - if (withdrawAmount == 0 || withdrawAmount > collateral) revert InvalidWithdrawAmount(); - - uint256 quotedCollateral = manager.collateralAmountQuoted(); - uint256 quotedWithdrawal = quotedCollateral.mulDivUp(withdrawAmount, collateral); - uint256 targetDebt = (quotedCollateral - quotedWithdrawal).mulDiv(targetLtv, _WAD); - uint256 liveDebt = manager.debtAmount(); - uint256 repayAmount = liveDebt > targetDebt ? liveDebt - targetDebt : 0; - - IFacilityPositionManager(facility) - .withdrawManager(intentId, withdrawAmount, repayAmount, useTarget, WithdrawalStrategy.PROPORTIONAL); - // A partial withdrawal queue can remove more quoted value than the aggregate estimate. - if (manager.debtAmount() > manager.collateralAmountQuoted().mulDiv(targetLtv, _WAD)) revert TargetLtvExceeded(); - + /// @param repayAmount The amount of debt to repay to the position manager. + /// @param useTarget Whether to use the target asset for the position manager withdrawal. + /// @param strategy The withdrawal strategy (SEQUENTIAL or PROPORTIONAL). + function run( + address facility, + uint256 intentId, + uint256 withdrawAmount, + uint256 repayAmount, + bool useTarget, + WithdrawalStrategy strategy + ) external { + // 1. Withdraw collateral from position manager (repay debt, get collateral back) + IFacilityPositionManager(facility).withdrawManager(intentId, withdrawAmount, repayAmount, useTarget, strategy); + + // 2. Commit the remaining redemption collateral IFacilityFunds(facility).commit(intentId); + + // 3. Unlock the redemption proceeds IFacilityFunds(facility).unlock(intentId); } } diff --git a/test/request/MorphoFlashLoanRequest.t.sol b/test/request/MorphoFlashLoanRequest.t.sol index 8dd6704f..c6b67e5b 100644 --- a/test/request/MorphoFlashLoanRequest.t.sol +++ b/test/request/MorphoFlashLoanRequest.t.sol @@ -13,7 +13,6 @@ import {MockMorphoAllocator} from "test/mock/request/MockMorphoAllocator.sol"; import {Offer} from "src/interfaces/request/IOfferReceiver.sol"; import {LibCommonErrors} from "src/libs/common/LibCommonErrors.sol"; import {MockERC20} from "test/mock/MockERC20.sol"; -import {MockBorrowPosition} from "test/mock/borrow/MockBorrowPosition.sol"; import {Mode, State} from "src/libs/funds/Order.sol"; import {IntentProperties, Asset} from "src/libs/facility/LibIntent.sol"; import {WithdrawalStrategy} from "src/interfaces/manager/base/IPositionManagerAdmin.sol"; @@ -946,15 +945,14 @@ contract MorphoFlashLoanRequestTest is FacilityBaseTest { assertEq(collateralToken.balanceOf(address(facility)), 0); } - function test_execute_syncMidasWithdrawalCommitUnlock() public { + function testFuzz_execute_syncMidasWithdrawalCommitUnlock(bool proportional) public { uint256 morphoBalBefore = debtToken.balanceOf(address(morpho)); vm.prank(facilitator); facility.depositManager(intentId, 0, 5_000e18, false); - // A price drop makes the live LTV exceed the requested 50% target. - oracle.setPrice(0.9e36); uint256 withdrawAmount = 1_000e18; - uint256 repayAmount = 950e18; // 5,000 - (10,000 - 1,000) * 0.9 * 0.5 + uint256 repayAmount = 500e18; + WithdrawalStrategy strategy = proportional ? WithdrawalStrategy.PROPORTIONAL : WithdrawalStrategy.SEQUENTIAL; vm.prank(facilitator); _setFund(intentId, address(mockFund)); // MockFund represents the remaining redemption at the script's facility boundary. @@ -969,67 +967,23 @@ contract MorphoFlashLoanRequestTest is FacilityBaseTest { repayAmount, _buildSetRequestParams(intentId, block.timestamp + 1 hours), address(syncMidasWithdrawal), - abi.encodeCall(SyncMidasWithdrawal.run, (address(facility), intentId, withdrawAmount, 0.5e18, false)) + abi.encodeCall( + SyncMidasWithdrawal.run, (address(facility), intentId, withdrawAmount, repayAmount, false, strategy) + ) ); assertEq(positionManager.collateralAmount(), 9_000e18); - assertEq(positionManager.debtAmount(), 4_050e18); - assertEq(positionManager.debtAmount() * 1e18 / positionManager.collateralAmountQuoted(), 0.5e18); + assertEq(positionManager.debtAmount(), 4_500e18); assertEq(collateralToken.balanceOf(address(mockFund)), withdrawAmount); assertEq(collateralToken.balanceOf(address(facility)), 0); - assertEq(debtToken.balanceOf(address(facility)), 5_050e18); - assertEq(debtToken.balanceOf(address(morpho)), morphoBalBefore - 4_050e18); + assertEq(debtToken.balanceOf(address(facility)), 5_500e18); + assertEq(debtToken.balanceOf(address(morpho)), morphoBalBefore - 4_500e18); assertEq(debtToken.balanceOf(address(flashLoanRequest)), 0); (, address fund, address request,) = facility.getIntent(intentId); assertEq(fund, address(0)); assertEq(request, address(0)); } - function test_syncMidasWithdrawal_rejectsInvalidParameters() public { - vm.expectRevert(SyncMidasWithdrawal.InvalidTargetLtv.selector); - syncMidasWithdrawal.run(address(facility), intentId, 1, 1e18, false); - vm.expectRevert(SyncMidasWithdrawal.InvalidPositionManager.selector); - syncMidasWithdrawal.run(address(facility), intentId, 1, 0.5e18, true); - vm.expectRevert(SyncMidasWithdrawal.InvalidWithdrawAmount.selector); - syncMidasWithdrawal.run(address(facility), intentId, 0, 0.5e18, false); - uint256 tooMuch = positionManager.collateralAmount() + 1; - vm.expectRevert(SyncMidasWithdrawal.InvalidWithdrawAmount.selector); - syncMidasWithdrawal.run(address(facility), intentId, tooMuch, 0.5e18, false); - } - - function test_syncMidasWithdrawal_revertsWhenPartialQueueRemovesMoreQuotedCollateral() public { - vm.prank(facilitator); - facility.depositManager(intentId, 0, 4_500e18, false); - - // This lower-priced module contributes to the aggregate quote but is excluded from withdrawals. - MockBorrowPosition excluded = new MockBorrowPosition(address(collateralToken), address(debtToken)); - excluded.setTotalCollateral(10_000e18); - excluded.setTotalCollateralQuoted(5_000e18); - excluded.setSafeLtv(uint128(PM_LTV)); - vm.mockCall(address(excluded), abi.encodeWithSignature("owner()"), abi.encode(address(positionManager))); - vm.prank(owner); - positionManager.addBorrowModule(address(excluded)); - - uint256 withdrawAmount = 1_000e18; - uint256 repayAmount = 225e18; // Aggregate quote estimates 750 removed; the queued position removes 1,000. - vm.prank(facilitator); - _setFund(intentId, address(mockFund)); - mockFund.setNextCommitState(State.UNLOCKING); - mockFund.setUnlockAmount(withdrawAmount); - debtToken.setBalance(address(mockFund), withdrawAmount); - vm.prank(facilitator); - facility.create(intentId, withdrawAmount, withdrawAmount, Mode.REDEEM); - - vm.prank(executor); - vm.expectRevert(SyncMidasWithdrawal.TargetLtvExceeded.selector); - flashLoanRequest.execute( - repayAmount, - _buildSetRequestParams(intentId, block.timestamp + 1 hours), - address(syncMidasWithdrawal), - abi.encodeCall(SyncMidasWithdrawal.run, (address(facility), intentId, withdrawAmount, 0.3e18, false)) - ); - } - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* I. pullFunds() TESTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/