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

fix: Enforce CEI pattern in Zapper flash loans #666

Merged
merged 1 commit into from
Dec 22, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 14 additions & 11 deletions contracts/src/Zappers/Modules/FlashLoans/BalancerFlashLoan.sol
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,6 @@ contract BalancerFlashLoan is IFlashLoanRecipient, IFlashLoanProvider {
receiver = IFlashLoanReceiver(msg.sender);

vault.flashLoan(this, tokens, amounts, userData);

// Reset receiver
receiver = IFlashLoanReceiver(address(0));
}

function receiveFlashLoan(
Expand All @@ -61,6 +58,12 @@ contract BalancerFlashLoan is IFlashLoanRecipient, IFlashLoanProvider {
require(msg.sender == address(vault), "Caller is not Vault");
require(address(receiver) != address(0), "Flash loan not properly initiated");

// Cache and reset receiver, to comply with CEI pattern, as some callbacks in zappers do raw calls
// It’s not necessary, as Balancer flash loans are protected against re-entrancy
// But it’s safer, specially if someone tries to reuse this code, and more gas efficient
IFlashLoanReceiver receiverCached = receiver;
receiver = IFlashLoanReceiver(address(0));

// decode and operation
Operation operation = abi.decode(userData[0:32], (Operation));

Expand All @@ -72,9 +75,9 @@ contract BalancerFlashLoan is IFlashLoanRecipient, IFlashLoanProvider {
// Flash loan minus fees
uint256 effectiveFlashLoanAmount = amounts[0] - feeAmounts[0];
// We send only effective flash loan, keeping fees here
tokens[0].safeTransfer(address(receiver), effectiveFlashLoanAmount);
tokens[0].safeTransfer(address(receiverCached), effectiveFlashLoanAmount);
// Zapper callback
receiver.receiveFlashLoanOnOpenLeveragedTrove(openTroveParams, effectiveFlashLoanAmount);
receiverCached.receiveFlashLoanOnOpenLeveragedTrove(openTroveParams, effectiveFlashLoanAmount);
} else if (operation == Operation.LeverUpTrove) {
// Lever up
// decode params
Expand All @@ -83,9 +86,9 @@ contract BalancerFlashLoan is IFlashLoanRecipient, IFlashLoanProvider {
// Flash loan minus fees
uint256 effectiveFlashLoanAmount = amounts[0] - feeAmounts[0];
// We send only effective flash loan, keeping fees here
tokens[0].safeTransfer(address(receiver), effectiveFlashLoanAmount);
tokens[0].safeTransfer(address(receiverCached), effectiveFlashLoanAmount);
// Zapper callback
receiver.receiveFlashLoanOnLeverUpTrove(leverUpTroveParams, effectiveFlashLoanAmount);
receiverCached.receiveFlashLoanOnLeverUpTrove(leverUpTroveParams, effectiveFlashLoanAmount);
} else if (operation == Operation.LeverDownTrove) {
// Lever down
// decode params
Expand All @@ -94,19 +97,19 @@ contract BalancerFlashLoan is IFlashLoanRecipient, IFlashLoanProvider {
// Flash loan minus fees
uint256 effectiveFlashLoanAmount = amounts[0] - feeAmounts[0];
// We send only effective flash loan, keeping fees here
tokens[0].safeTransfer(address(receiver), effectiveFlashLoanAmount);
tokens[0].safeTransfer(address(receiverCached), effectiveFlashLoanAmount);
// Zapper callback
receiver.receiveFlashLoanOnLeverDownTrove(leverDownTroveParams, effectiveFlashLoanAmount);
receiverCached.receiveFlashLoanOnLeverDownTrove(leverDownTroveParams, effectiveFlashLoanAmount);
} else if (operation == Operation.CloseTrove) {
// Close trove
// decode params
IZapper.CloseTroveParams memory closeTroveParams = abi.decode(userData[32:], (IZapper.CloseTroveParams));
// Flash loan minus fees
uint256 effectiveFlashLoanAmount = amounts[0] - feeAmounts[0];
// We send only effective flash loan, keeping fees here
tokens[0].safeTransfer(address(receiver), effectiveFlashLoanAmount);
tokens[0].safeTransfer(address(receiverCached), effectiveFlashLoanAmount);
// Zapper callback
receiver.receiveFlashLoanOnCloseTroveFromCollateral(closeTroveParams, effectiveFlashLoanAmount);
receiverCached.receiveFlashLoanOnCloseTroveFromCollateral(closeTroveParams, effectiveFlashLoanAmount);
} else {
revert("LZ: Wrong Operation");
}
Expand Down
Loading