Branch data Line data Source code
1 : : // SPDX-License-Identifier: BUSL-1.1
2 : : pragma solidity ^0.8.10;
3 : :
4 : : import {GPv2SafeERC20} from '../../../dependencies/gnosis/contracts/GPv2SafeERC20.sol';
5 : : import {SafeCast} from '../../../dependencies/openzeppelin/contracts/SafeCast.sol';
6 : : import {IERC20} from '../../../dependencies/openzeppelin/contracts/IERC20.sol';
7 : : import {IAToken} from '../../../interfaces/IAToken.sol';
8 : : import {IPool} from '../../../interfaces/IPool.sol';
9 : : import {IFlashLoanReceiver} from '../../../misc/flashloan/interfaces/IFlashLoanReceiver.sol';
10 : : import {IFlashLoanSimpleReceiver} from '../../../misc/flashloan/interfaces/IFlashLoanSimpleReceiver.sol';
11 : : import {IPoolAddressesProvider} from '../../../interfaces/IPoolAddressesProvider.sol';
12 : : import {ReserveConfiguration} from '../configuration/ReserveConfiguration.sol';
13 : : import {Errors} from '../helpers/Errors.sol';
14 : : import {WadRayMath} from '../math/WadRayMath.sol';
15 : : import {PercentageMath} from '../math/PercentageMath.sol';
16 : : import {DataTypes} from '../types/DataTypes.sol';
17 : : import {ValidationLogic} from './ValidationLogic.sol';
18 : : import {BorrowLogic} from './BorrowLogic.sol';
19 : : import {ReserveLogic} from './ReserveLogic.sol';
20 : :
21 : : /**
22 : : * @title FlashLoanLogic library
23 : : * @author Aave
24 : : * @notice Implements the logic for the flash loans
25 : : */
26 : : library FlashLoanLogic {
27 : : using ReserveLogic for DataTypes.ReserveCache;
28 : : using ReserveLogic for DataTypes.ReserveData;
29 : : using GPv2SafeERC20 for IERC20;
30 : : using ReserveConfiguration for DataTypes.ReserveConfigurationMap;
31 : : using WadRayMath for uint256;
32 : : using PercentageMath for uint256;
33 : : using SafeCast for uint256;
34 : :
35 : : // See `IPool` for descriptions
36 : : event FlashLoan(
37 : : address indexed target,
38 : : address initiator,
39 : : address indexed asset,
40 : : uint256 amount,
41 : : DataTypes.InterestRateMode interestRateMode,
42 : : uint256 premium,
43 : : uint16 indexed referralCode
44 : : );
45 : :
46 : : // Helper struct for internal variables used in the `executeFlashLoan` function
47 : : struct FlashLoanLocalVars {
48 : : IFlashLoanReceiver receiver;
49 : : address currentAsset;
50 : : uint256 currentAmount;
51 : : uint256[] totalPremiums;
52 : : uint256 flashloanPremiumTotal;
53 : : uint256 flashloanPremiumToProtocol;
54 : : }
55 : :
56 : : /**
57 : : * @notice Implements the flashloan feature that allow users to access liquidity of the pool for one transaction
58 : : * as long as the amount taken plus fee is returned or debt is opened.
59 : : * @dev For authorized flashborrowers the fee is waived
60 : : * @dev At the end of the transaction the pool will pull amount borrowed + fee from the receiver,
61 : : * if the receiver have not approved the pool the transaction will revert.
62 : : * @dev Emits the `FlashLoan()` event
63 : : * @param reservesData The state of all the reserves
64 : : * @param reservesList The addresses of all the active reserves
65 : : * @param eModeCategories The configuration of all the efficiency mode categories
66 : : * @param userConfig The user configuration mapping that tracks the supplied/borrowed assets
67 : : * @param params The additional parameters needed to execute the flashloan function
68 : : */
69 : : function executeFlashLoan(
70 : : mapping(address => DataTypes.ReserveData) storage reservesData,
71 : : mapping(uint256 => address) storage reservesList,
72 : : mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories,
73 : : DataTypes.UserConfigurationMap storage userConfig,
74 : : DataTypes.FlashloanParams memory params
75 : : ) external {
76 : : // The usual action flow (cache -> updateState -> validation -> changeState -> updateRates)
77 : : // is altered to (validation -> user payload -> cache -> updateState -> changeState -> updateRates) for flashloans.
78 : : // This is done to protect against reentrance and rate manipulation within the user specified payload.
79 : :
80 : 1011 : ValidationLogic.validateFlashloan(reservesData, params.assets, params.amounts);
81 : :
82 : 7 : FlashLoanLocalVars memory vars;
83 : :
84 : 7 : vars.totalPremiums = new uint256[](params.assets.length);
85 : :
86 : 7 : vars.receiver = IFlashLoanReceiver(params.receiverAddress);
87 : 7 : (vars.flashloanPremiumTotal, vars.flashloanPremiumToProtocol) = params.isAuthorizedFlashBorrower
88 : : ? (0, 0)
89 : : : (params.flashLoanPremiumTotal, params.flashLoanPremiumToProtocol);
90 : :
91 : 7 : for (uint256 i = 0; i < params.assets.length; i++) {
92 : 8 : vars.currentAmount = params.amounts[i];
93 : 8 : vars.totalPremiums[i] = DataTypes.InterestRateMode(params.interestRateModes[i]) ==
94 : : DataTypes.InterestRateMode.NONE
95 : : ? vars.currentAmount.percentMul(vars.flashloanPremiumTotal)
96 : : : 0;
97 : :
98 : 8 : if (reservesData[params.assets[i]].configuration.getIsVirtualAccActive()) {
99 : 8 : reservesData[params.assets[i]].virtualUnderlyingBalance -= vars.currentAmount.toUint128();
100 : : }
101 : :
102 : 8 : IAToken(reservesData[params.assets[i]].aTokenAddress).transferUnderlyingTo(
103 : : params.receiverAddress,
104 : : vars.currentAmount
105 : : );
106 : : }
107 : :
108 : 7 : require(
109 : : vars.receiver.executeOperation(
110 : : params.assets,
111 : : params.amounts,
112 : : vars.totalPremiums,
113 : : msg.sender,
114 : : params.params
115 : : ),
116 : : Errors.INVALID_FLASHLOAN_EXECUTOR_RETURN
117 : : );
118 : :
119 : 4 : for (uint256 i = 0; i < params.assets.length; i++) {
120 : 5 : vars.currentAsset = params.assets[i];
121 : 5 : vars.currentAmount = params.amounts[i];
122 : :
123 : : if (
124 : 5 : DataTypes.InterestRateMode(params.interestRateModes[i]) == DataTypes.InterestRateMode.NONE
125 : : ) {
126 : 3 : _handleFlashLoanRepayment(
127 : : reservesData[vars.currentAsset],
128 : : DataTypes.FlashLoanRepaymentParams({
129 : : asset: vars.currentAsset,
130 : : receiverAddress: params.receiverAddress,
131 : : amount: vars.currentAmount,
132 : : totalPremium: vars.totalPremiums[i],
133 : : flashLoanPremiumToProtocol: vars.flashloanPremiumToProtocol,
134 : : referralCode: params.referralCode
135 : : })
136 : : );
137 : : } else {
138 : : // If the user chose to not return the funds, the system checks if there is enough collateral and
139 : : // eventually opens a debt position
140 : 2 : BorrowLogic.executeBorrow(
141 : : reservesData,
142 : : reservesList,
143 : : eModeCategories,
144 : : userConfig,
145 : : DataTypes.ExecuteBorrowParams({
146 : : asset: vars.currentAsset,
147 : : user: msg.sender,
148 : : onBehalfOf: params.onBehalfOf,
149 : : amount: vars.currentAmount,
150 : : interestRateMode: DataTypes.InterestRateMode(params.interestRateModes[i]),
151 : : referralCode: params.referralCode,
152 : : releaseUnderlying: false,
153 : : reservesCount: IPool(params.pool).getReservesCount(),
154 : : oracle: IPoolAddressesProvider(params.addressesProvider).getPriceOracle(),
155 : : userEModeCategory: IPool(params.pool).getUserEMode(params.onBehalfOf).toUint8(),
156 : : priceOracleSentinel: IPoolAddressesProvider(params.addressesProvider)
157 : : .getPriceOracleSentinel()
158 : : })
159 : : );
160 : : // no premium is paid when taking on the flashloan as debt
161 : 1 : emit FlashLoan(
162 : : params.receiverAddress,
163 : : msg.sender,
164 : : vars.currentAsset,
165 : : vars.currentAmount,
166 : : DataTypes.InterestRateMode(params.interestRateModes[i]),
167 : : 0,
168 : : params.referralCode
169 : : );
170 : : }
171 : : }
172 : : }
173 : :
174 : : /**
175 : : * @notice Implements the simple flashloan feature that allow users to access liquidity of ONE reserve for one
176 : : * transaction as long as the amount taken plus fee is returned.
177 : : * @dev Does not waive fee for approved flashborrowers nor allow taking on debt instead of repaying to save gas
178 : : * @dev At the end of the transaction the pool will pull amount borrowed + fee from the receiver,
179 : : * if the receiver have not approved the pool the transaction will revert.
180 : : * @dev Emits the `FlashLoan()` event
181 : : * @param reserve The state of the flashloaned reserve
182 : : * @param params The additional parameters needed to execute the simple flashloan function
183 : : */
184 : : function executeFlashLoanSimple(
185 : : DataTypes.ReserveData storage reserve,
186 : : DataTypes.FlashloanSimpleParams memory params
187 : : ) external {
188 : : // The usual action flow (cache -> updateState -> validation -> changeState -> updateRates)
189 : : // is altered to (validation -> user payload -> cache -> updateState -> changeState -> updateRates) for flashloans.
190 : : // This is done to protect against reentrance and rate manipulation within the user specified payload.
191 : :
192 : 11 : ValidationLogic.validateFlashloanSimple(reserve, params.amount);
193 : :
194 : 10 : IFlashLoanSimpleReceiver receiver = IFlashLoanSimpleReceiver(params.receiverAddress);
195 : 10 : uint256 totalPremium = params.amount.percentMul(params.flashLoanPremiumTotal);
196 : :
197 : 10 : if (reserve.configuration.getIsVirtualAccActive()) {
198 : 10 : reserve.virtualUnderlyingBalance -= params.amount.toUint128();
199 : : }
200 : :
201 : 10 : IAToken(reserve.aTokenAddress).transferUnderlyingTo(params.receiverAddress, params.amount);
202 : :
203 : 10 : require(
204 : : receiver.executeOperation(
205 : : params.asset,
206 : : params.amount,
207 : : totalPremium,
208 : : msg.sender,
209 : : params.params
210 : : ),
211 : : Errors.INVALID_FLASHLOAN_EXECUTOR_RETURN
212 : : );
213 : :
214 : 6 : _handleFlashLoanRepayment(
215 : : reserve,
216 : : DataTypes.FlashLoanRepaymentParams({
217 : : asset: params.asset,
218 : : receiverAddress: params.receiverAddress,
219 : : amount: params.amount,
220 : : totalPremium: totalPremium,
221 : : flashLoanPremiumToProtocol: params.flashLoanPremiumToProtocol,
222 : : referralCode: params.referralCode
223 : : })
224 : : );
225 : : }
226 : :
227 : : /**
228 : : * @notice Handles repayment of flashloaned assets + premium
229 : : * @dev Will pull the amount + premium from the receiver, so must have approved pool
230 : : * @param reserve The state of the flashloaned reserve
231 : : * @param params The additional parameters needed to execute the repayment function
232 : : */
233 : : function _handleFlashLoanRepayment(
234 : : DataTypes.ReserveData storage reserve,
235 : : DataTypes.FlashLoanRepaymentParams memory params
236 : : ) internal {
237 : 9 : uint256 premiumToProtocol = params.totalPremium.percentMul(params.flashLoanPremiumToProtocol);
238 : 9 : uint256 premiumToLP = params.totalPremium - premiumToProtocol;
239 : 9 : uint256 amountPlusPremium = params.amount + params.totalPremium;
240 : :
241 : 9 : DataTypes.ReserveCache memory reserveCache = reserve.cache();
242 : 9 : reserve.updateState(reserveCache);
243 : 9 : reserveCache.nextLiquidityIndex = reserve.cumulateToLiquidityIndex(
244 : : IERC20(reserveCache.aTokenAddress).totalSupply() +
245 : : uint256(reserve.accruedToTreasury).rayMul(reserveCache.nextLiquidityIndex),
246 : : premiumToLP
247 : : );
248 : :
249 : 9 : reserve.accruedToTreasury += premiumToProtocol
250 : : .rayDiv(reserveCache.nextLiquidityIndex)
251 : : .toUint128();
252 : :
253 : 9 : reserve.updateInterestRatesAndVirtualBalance(reserveCache, params.asset, amountPlusPremium, 0);
254 : :
255 : 9 : IERC20(params.asset).safeTransferFrom(
256 : : params.receiverAddress,
257 : : reserveCache.aTokenAddress,
258 : : amountPlusPremium
259 : : );
260 : :
261 : 9 : IAToken(reserveCache.aTokenAddress).handleRepayment(
262 : : params.receiverAddress,
263 : : params.receiverAddress,
264 : : amountPlusPremium
265 : : );
266 : :
267 : 9 : emit FlashLoan(
268 : : params.receiverAddress,
269 : : msg.sender,
270 : : params.asset,
271 : : params.amount,
272 : : DataTypes.InterestRateMode.NONE,
273 : : params.totalPremium,
274 : : params.referralCode
275 : : );
276 : : }
277 : : }
|