diff --git a/src/Morpho.sol b/src/Morpho.sol index 0f24d1a9f..f1e938b24 100644 --- a/src/Morpho.sol +++ b/src/Morpho.sol @@ -399,12 +399,12 @@ contract Morpho is IMorpho { /* FLASH LOANS */ /// @inheritdoc IMorpho - function flashLoan(address token, uint256 assets, bytes calldata data) external { + function flashLoan(address token, uint256 assets, bytes calldata data) external returns (bytes memory returnData) { IERC20(token).safeTransfer(msg.sender, assets); emit EventsLib.FlashLoan(msg.sender, token, assets); - IMorphoFlashLoanCallback(msg.sender).onMorphoFlashLoan(assets, data); + returnData = IMorphoFlashLoanCallback(msg.sender).onMorphoFlashLoan(assets, data); IERC20(token).safeTransferFrom(msg.sender, address(this), assets); } diff --git a/src/interfaces/IMorpho.sol b/src/interfaces/IMorpho.sol index 02aa4e204..b7e2433fd 100644 --- a/src/interfaces/IMorpho.sol +++ b/src/interfaces/IMorpho.sol @@ -280,7 +280,8 @@ interface IMorpho { /// @param token The token to flash loan. /// @param assets The amount of assets to flash loan. /// @param data Arbitrary data to pass to the `onMorphoFlashLoan` callback. - function flashLoan(address token, uint256 assets, bytes calldata data) external; + /// @return returnData Arbitrary data returned by the callback. + function flashLoan(address token, uint256 assets, bytes calldata data) external returns (bytes memory returnData); /// @notice Sets the authorization for `authorized` to manage `msg.sender`'s positions. /// @param authorized The authorized address. diff --git a/src/interfaces/IMorphoCallbacks.sol b/src/interfaces/IMorphoCallbacks.sol index b4c7898f7..910d13279 100644 --- a/src/interfaces/IMorphoCallbacks.sol +++ b/src/interfaces/IMorphoCallbacks.sol @@ -48,5 +48,6 @@ interface IMorphoFlashLoanCallback { /// @dev The callback is called only if data is not empty. /// @param assets The amount of assets that was flash loaned. /// @param data Arbitrary data passed to the `flashLoan` function. - function onMorphoFlashLoan(uint256 assets, bytes calldata data) external; + /// @return returnData Arbitrary data returned by the callback. + function onMorphoFlashLoan(uint256 assets, bytes calldata data) external returns (bytes memory returnData); } diff --git a/src/mocks/FlashBorrowerMock.sol b/src/mocks/FlashBorrowerMock.sol index be0783c9e..5a94ac58f 100644 --- a/src/mocks/FlashBorrowerMock.sol +++ b/src/mocks/FlashBorrowerMock.sol @@ -12,13 +12,14 @@ contract FlashBorrowerMock is IMorphoFlashLoanCallback { MORPHO = newMorpho; } - function flashLoan(address token, uint256 assets, bytes calldata data) external { - MORPHO.flashLoan(token, assets, data); + function flashLoan(address token, uint256 assets, bytes calldata data) external returns (bytes memory) { + return MORPHO.flashLoan(token, assets, data); } - function onMorphoFlashLoan(uint256 assets, bytes calldata data) external { + function onMorphoFlashLoan(uint256 assets, bytes calldata data) external returns (bytes memory) { require(msg.sender == address(MORPHO)); address token = abi.decode(data, (address)); IERC20(token).approve(address(MORPHO), assets); + return ""; } } diff --git a/test/forge/integration/CallbacksIntegrationTest.sol b/test/forge/integration/CallbacksIntegrationTest.sol index 62578aa19..3daa78d0f 100644 --- a/test/forge/integration/CallbacksIntegrationTest.sol +++ b/test/forge/integration/CallbacksIntegrationTest.sol @@ -60,13 +60,14 @@ contract CallbacksIntegrationTest is } } - function onMorphoFlashLoan(uint256 amount, bytes memory data) external { + function onMorphoFlashLoan(uint256 amount, bytes memory data) external returns (bytes memory returnData) { require(msg.sender == address(morpho)); bytes4 selector; (selector, data) = abi.decode(data, (bytes4, bytes)); if (selector == this.testFlashLoan.selector) { assertEq(loanToken.balanceOf(address(this)), amount); loanToken.approve(address(morpho), amount); + returnData = "Arbitrary data!"; } } @@ -78,9 +79,11 @@ contract CallbacksIntegrationTest is loanToken.setBalance(address(this), amount); morpho.supply(marketParams, amount, 0, address(this), hex""); - morpho.flashLoan(address(loanToken), amount, abi.encode(this.testFlashLoan.selector, hex"")); + bytes memory returnData = + morpho.flashLoan(address(loanToken), amount, abi.encode(this.testFlashLoan.selector, hex"")); assertEq(loanToken.balanceOf(address(morpho)), amount, "balanceOf"); + assertEq(returnData, "Arbitrary data!", "returnData"); } function testFlashLoanShouldRevertIfNotReimbursed(uint256 amount) public {