Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add return bytes to flashloan callback #570

Merged
4 changes: 2 additions & 2 deletions src/Morpho.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
3 changes: 2 additions & 1 deletion src/interfaces/IMorpho.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
3 changes: 2 additions & 1 deletion src/interfaces/IMorphoCallbacks.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
7 changes: 4 additions & 3 deletions src/mocks/FlashBorrowerMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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 returnData) {
ultrasecreth marked this conversation as resolved.
Show resolved Hide resolved
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 returnData) {
require(msg.sender == address(MORPHO));
address token = abi.decode(data, (address));
IERC20(token).approve(address(MORPHO), assets);
resultData = "";
ultrasecreth marked this conversation as resolved.
Show resolved Hide resolved
}
}
7 changes: 5 additions & 2 deletions test/forge/integration/CallbacksIntegrationTest.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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!";
}
}

Expand All @@ -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 {
Expand Down