initial implementation

This commit is contained in:
The3D 2020-10-22 18:15:56 +02:00
parent cdcb5c7d31
commit 8873b9cdac
3 changed files with 63 additions and 44 deletions

View File

@ -270,10 +270,10 @@ interface ILendingPool {
* @param referralCode the referral code of the caller * @param referralCode the referral code of the caller
**/ **/
function flashLoan( function flashLoan(
address receiver, address receiverAddress,
address reserve, address[] calldata assets,
uint256 amount, uint256[] calldata amounts,
uint256 debtType, uint256 mode,
bytes calldata params, bytes calldata params,
uint16 referralCode uint16 referralCode
) external; ) external;

View File

@ -483,11 +483,9 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
} }
struct FlashLoanLocalVars { struct FlashLoanLocalVars {
uint256 premium;
uint256 amountPlusPremium;
IFlashLoanReceiver receiver; IFlashLoanReceiver receiver;
address aTokenAddress;
address oracle; address oracle;
ReserveLogic.InterestRateMode debtMode;
} }
/** /**
@ -495,70 +493,85 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
* as long as the amount taken plus a fee is returned. NOTE There are security concerns for developers of flashloan receiver contracts * as long as the amount taken plus a fee is returned. NOTE There are security concerns for developers of flashloan receiver contracts
* that must be kept into consideration. For further details please visit https://developers.aave.com * that must be kept into consideration. For further details please visit https://developers.aave.com
* @param receiverAddress The address of the contract receiving the funds. The receiver should implement the IFlashLoanReceiver interface. * @param receiverAddress The address of the contract receiving the funds. The receiver should implement the IFlashLoanReceiver interface.
* @param asset The address of the principal reserve * @param assets The address of the principal reserve
* @param amount The amount requested for this flashloan * @param amounts The amount requested for this flashloan
* @param mode Type of the debt to open if the flash loan is not returned. 0 -> Don't open any debt, just revert, 1 -> stable, 2 -> variable * @param mode Type of the debt to open if the flash loan is not returned. 0 -> Don't open any debt, just revert, 1 -> stable, 2 -> variable
* @param params Variadic packed params to pass to the receiver as extra information * @param params Variadic packed params to pass to the receiver as extra information
* @param referralCode Referral code of the flash loan * @param referralCode Referral code of the flash loan
**/ **/
function flashLoan( function flashLoan(
address receiverAddress, address receiverAddress,
address asset, address[] calldata assets,
uint256 amount, uint256[] calldata amounts,
uint256 mode, uint256 mode,
bytes calldata params, bytes calldata params,
uint16 referralCode uint16 referralCode
) external override { ) external override {
_whenNotPaused(); _whenNotPaused();
ReserveLogic.ReserveData storage reserve = _reserves[asset];
FlashLoanLocalVars memory vars; FlashLoanLocalVars memory vars;
vars.aTokenAddress = reserve.aTokenAddress; ValidationLogic.validateFlashloan(assets, amounts, mode, vars.premium);
vars.premium = amount.mul(FLASHLOAN_PREMIUM_TOTAL).div(10000); address[] memory aTokenAddresses = new address[](assets.length);
uint256[] memory premiums = new uint256[](assets.length);
ValidationLogic.validateFlashloan(mode, vars.premium);
ReserveLogic.InterestRateMode debtMode = ReserveLogic.InterestRateMode(mode);
vars.receiver = IFlashLoanReceiver(receiverAddress); vars.receiver = IFlashLoanReceiver(receiverAddress);
vars.debtMode = ReserveLogic.InterestRateMode(mode);
for (uint256 i = 0; i < assets.length; i++) {
ReserveLogic.ReserveData storage reserve = _reserves[assets[i]];
aTokenAddresses[i] = reserve.aTokenAddress;
premiums[i] = amounts[i].mul(FLASHLOAN_PREMIUM_TOTAL).div(10000);
//transfer funds to the receiver //transfer funds to the receiver
IAToken(vars.aTokenAddress).transferUnderlyingTo(receiverAddress, amount); IAToken(vars.aTokenAddress).transferUnderlyingTo(receiverAddress, amounts[i]);
}
//execute action of the receiver //execute action of the receiver
require( require(
vars.receiver.executeOperation(asset, amount, vars.premium, params), vars.receiver.executeOperation(assets, amounts, premiums, params),
Errors.INVALID_FLASH_LOAN_EXECUTOR_RETURN Errors.INVALID_FLASH_LOAN_EXECUTOR_RETURN
); );
vars.amountPlusPremium = amount.add(vars.premium); for (uint256 i = 0; i < assets.length; i++) {
uint256 amountPlusPremium = amounts[i].add(premiums[i]);
if (debtMode == ReserveLogic.InterestRateMode.NONE) { if (vars.debtMode == ReserveLogic.InterestRateMode.NONE) {
IERC20(asset).safeTransferFrom(receiverAddress, vars.aTokenAddress, vars.amountPlusPremium); _reserves[assets[i]].updateState();
_reserves[assets[i]].cumulateToLiquidityIndex(
IERC20(aTokenAddresses[i]).totalSupply(),
vars.premium
);
_reserves[assets[i]].updateInterestRates(assets[i], aTokenAddresses[i], vars.premium, 0);
reserve.updateState(); IERC20(assets[i]).safeTransferFrom(
reserve.cumulateToLiquidityIndex(IERC20(vars.aTokenAddress).totalSupply(), vars.premium); receiverAddress,
reserve.updateInterestRates(asset, vars.aTokenAddress, vars.premium, 0); vars.aTokenAddresses[i],
vars.amountPlusPremium
);
emit FlashLoan(receiverAddress, asset, amount, vars.premium, referralCode); emit FlashLoan(receiverAddress, assets[i], amounts[i], vars.premium, referralCode);
} else { } else {
//if the user didn't choose to return the funds, the system checks if there //if the user didn't choose to return the funds, the system checks if there
//is enough collateral and eventually open a position //is enough collateral and eventually open a position
_executeBorrow( _executeBorrow(
ExecuteBorrowParams( ExecuteBorrowParams(
asset, assets[i],
msg.sender, msg.sender,
msg.sender, msg.sender,
vars.amountPlusPremium, amountPlusPremium,
mode, vars.mode,
vars.aTokenAddress, aTokenAddresses[i],
referralCode, referralCode,
false false
) )
); );
} }
} }
}
/** /**
* @dev returns the state and configuration of the reserve * @dev returns the state and configuration of the reserve

View File

@ -329,9 +329,15 @@ library ValidationLogic {
* @param mode the flashloan mode (0 = classic flashloan, 1 = open a stable rate loan, 2 = open a variable rate loan) * @param mode the flashloan mode (0 = classic flashloan, 1 = open a stable rate loan, 2 = open a variable rate loan)
* @param premium the premium paid on the flashloan * @param premium the premium paid on the flashloan
**/ **/
function validateFlashloan(uint256 mode, uint256 premium) internal pure { function validateFlashloan(
address[] memory assets,
address[] memory amounts,
uint256 mode,
uint256 premium
) internal pure {
require(premium > 0, Errors.REQUESTED_AMOUNT_TOO_SMALL); require(premium > 0, Errors.REQUESTED_AMOUNT_TOO_SMALL);
require(mode <= uint256(ReserveLogic.InterestRateMode.VARIABLE), Errors.INVALID_FLASHLOAN_MODE); require(mode <= uint256(ReserveLogic.InterestRateMode.VARIABLE), Errors.INVALID_FLASHLOAN_MODE);
require(assets.length == amounts.length, Errors.INCONSISTENT_FLASHLOAN_PARAMS);
} }
/** /**