Merge branch '100/flash-loan-bath-modes' into 'master'

Added batch of modes to flashLoan()

Closes #100

See merge request aave-tech/protocol-v2!111
This commit is contained in:
Ernesto Boado 2020-10-30 14:01:52 +00:00
commit 22e4cc353c
11 changed files with 89 additions and 66 deletions

View File

@ -100,20 +100,18 @@ interface ILendingPool {
/**
* @dev emitted when a flashloan is executed
* @param target the address of the flashLoanReceiver
* @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 onBehalfOf the address incurring the debt, if borrow mode is not 0
* @param assets the address of the assets being flashborrowed
* @param amounts the amount requested
* @param premiums the total fee on the amount
* @param initiator the address initiating the flash loan
* @param asset the address of the asset being flashborrowed
* @param amount the amount requested
* @param premium the total fee on the amount
* @param referralCode the referral code of the caller
**/
event FlashLoan(
address indexed target,
uint256 mode,
address indexed onBehalfOf,
address[] assets,
uint256[] amounts,
uint256[] premiums,
address indexed initiator,
address indexed asset,
uint256 amount,
uint256 premium,
uint16 referralCode
);
@ -295,7 +293,7 @@ interface ILendingPool {
* @param receiver The address of the contract receiving the funds. The receiver should implement the IFlashLoanReceiver interface.
* @param assets the address of the principal reserve
* @param amounts the amount requested for this flashloan
* @param mode the flashloan mode
* @param modes the flashloan borrow modes
* @param params a bytes array to be sent to the flashloan executor
* @param referralCode the referral code of the caller
**/
@ -303,7 +301,7 @@ interface ILendingPool {
address receiver,
address[] calldata assets,
uint256[] calldata amounts,
uint256 mode,
uint256[] calldata modes,
address onBehalfOf,
bytes calldata params,
uint16 referralCode

View File

@ -490,13 +490,13 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
struct FlashLoanLocalVars {
IFlashLoanReceiver receiver;
address oracle;
ReserveLogic.InterestRateMode debtMode;
uint256 i;
address currentAsset;
address currentATokenAddress;
uint256 currentAmount;
uint256 currentPremium;
uint256 currentAmountPlusPremium;
address debtToken;
}
/**
@ -506,7 +506,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
* @param receiverAddress The address of the contract receiving the funds. The receiver should implement the IFlashLoanReceiver interface.
* @param assets The addresss of the assets being flashborrowed
* @param amounts The amounts requested for this flashloan for each asset
* @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 modes Types 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 onBehalfOf If mode is not 0, then the address to take the debt onBehalfOf. The onBehalfOf address must already have approved `msg.sender` to incur the debt on their behalf.
* @param params Variadic packed params to pass to the receiver as extra information
* @param referralCode Referral code of the flash loan
@ -515,7 +515,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
address receiverAddress,
address[] calldata assets,
uint256[] calldata amounts,
uint256 mode,
uint256[] calldata modes,
address onBehalfOf,
bytes calldata params,
uint16 referralCode
@ -524,13 +524,12 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
FlashLoanLocalVars memory vars;
ValidationLogic.validateFlashloan(assets, amounts, mode);
ValidationLogic.validateFlashloan(assets, amounts);
address[] memory aTokenAddresses = new address[](assets.length);
uint256[] memory premiums = new uint256[](assets.length);
vars.receiver = IFlashLoanReceiver(receiverAddress);
vars.debtMode = ReserveLogic.InterestRateMode(mode);
for (vars.i = 0; vars.i < assets.length; vars.i++) {
aTokenAddresses[vars.i] = _reserves[assets[vars.i]].aTokenAddress;
@ -552,10 +551,9 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
vars.currentAmount = amounts[vars.i];
vars.currentPremium = premiums[vars.i];
vars.currentATokenAddress = aTokenAddresses[vars.i];
vars.currentAmountPlusPremium = vars.currentAmount.add(vars.currentPremium);
if (vars.debtMode == ReserveLogic.InterestRateMode.NONE) {
if (ReserveLogic.InterestRateMode(modes[vars.i]) == ReserveLogic.InterestRateMode.NONE) {
_reserves[vars.currentAsset].updateState();
_reserves[vars.currentAsset].cumulateToLiquidityIndex(
IERC20(vars.currentATokenAddress).totalSupply(),
@ -575,13 +573,11 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
);
} else {
if (msg.sender != onBehalfOf) {
address debtToken = _reserves[vars.currentAsset].getDebtTokenAddress(mode);
vars.debtToken = _reserves[vars.currentAsset].getDebtTokenAddress(modes[vars.i]);
_borrowAllowance[debtToken][onBehalfOf][msg
.sender] = _borrowAllowance[debtToken][onBehalfOf][msg.sender].sub(
vars.currentAmount,
Errors.BORROW_ALLOWANCE_ARE_NOT_ENOUGH
);
_borrowAllowance[vars.debtToken][onBehalfOf][msg.sender] = _borrowAllowance[vars
.debtToken][onBehalfOf][msg.sender]
.sub(vars.currentAmount, Errors.BORROW_ALLOWANCE_ARE_NOT_ENOUGH);
}
//if the user didn't choose to return the funds, the system checks if there
@ -592,14 +588,21 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
msg.sender,
onBehalfOf,
vars.currentAmount,
mode,
modes[vars.i],
vars.currentATokenAddress,
referralCode,
false
)
);
}
emit FlashLoan(receiverAddress, mode, onBehalfOf, assets, amounts, premiums, referralCode);
emit FlashLoan(
receiverAddress,
msg.sender,
vars.currentAsset,
vars.currentAmount,
vars.currentPremium,
referralCode
);
}
}

View File

@ -159,7 +159,11 @@ contract LendingPoolConfigurator is VersionedInitializable {
* @param proxy the aToken proxy address
* @param implementation the new aToken implementation
**/
event ATokenUpgraded(address indexed asset, address indexed proxy, address indexed implementation);
event ATokenUpgraded(
address indexed asset,
address indexed proxy,
address indexed implementation
);
/**
* @dev emitted when the implementation of a stable debt token is upgraded
@ -167,7 +171,11 @@ contract LendingPoolConfigurator is VersionedInitializable {
* @param proxy the stable debt token proxy address
* @param implementation the new aToken implementation
**/
event StableDebtTokenUpgraded(address indexed asset, address indexed proxy, address indexed implementation);
event StableDebtTokenUpgraded(
address indexed asset,
address indexed proxy,
address indexed implementation
);
/**
* @dev emitted when the implementation of a variable debt token is upgraded
@ -175,7 +183,11 @@ contract LendingPoolConfigurator is VersionedInitializable {
* @param proxy the variable debt token proxy address
* @param implementation the new aToken implementation
**/
event VariableDebtTokenUpgraded(address indexed asset, address indexed proxy, address indexed implementation);
event VariableDebtTokenUpgraded(
address indexed asset,
address indexed proxy,
address indexed implementation
);
ILendingPoolAddressesProvider internal addressesProvider;
ILendingPool internal pool;

View File

@ -98,7 +98,6 @@ library Errors {
string public constant INVALID_DECIMALS = '73';
string public constant INVALID_RESERVE_FACTOR = '74';
enum CollateralManagerErrors {
NO_ERROR,
NO_COLLATERAL_AVAILABLE,

View File

@ -283,8 +283,7 @@ library ValidationLogic {
require(
!userConfig.isUsingAsCollateral(reserve.id) ||
reserve.configuration.getLtv() == 0 ||
stableDebt.add(variableDebt) >
IERC20(reserve.aTokenAddress).balanceOf(msg.sender),
stableDebt.add(variableDebt) > IERC20(reserve.aTokenAddress).balanceOf(msg.sender),
Errors.CALLATERAL_SAME_AS_BORROWING_CURRENCY
);
} else {
@ -331,16 +330,10 @@ library ValidationLogic {
/**
* @dev validates a flashloan action
* @param mode the flashloan mode (0 = classic flashloan, 1 = open a stable rate loan, 2 = open a variable rate loan)
* @param assets the assets being flashborrowed
* @param amounts the amounts for each asset being borrowed
**/
function validateFlashloan(
address[] memory assets,
uint256[] memory amounts,
uint256 mode
) internal pure {
require(mode <= uint256(ReserveLogic.InterestRateMode.VARIABLE), Errors.INVALID_FLASHLOAN_MODE);
function validateFlashloan(address[] memory assets, uint256[] memory amounts) internal pure {
require(assets.length == amounts.length, Errors.INCONSISTENT_FLASHLOAN_PARAMS);
}

View File

@ -97,7 +97,7 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
address user,
uint256 amount,
uint256 rate
) external override onlyLendingPool returns(bool) {
) external override onlyLendingPool returns (bool) {
MintLocalVars memory vars;
//cumulates the user debt

View File

@ -62,7 +62,7 @@ interface IStableDebtToken {
address user,
uint256 amount,
uint256 rate
) external returns(bool);
) external returns (bool);
/**
* @dev burns debt of the target user.

View File

@ -266,4 +266,4 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
}
}
}

View File

@ -71,8 +71,11 @@ makeSuite('AToken: Transfer', (testEnv: TestEnv) => {
users[1].address
);
const userReserveData = await helpersContract.getUserReserveData(weth.address, users[1].address);
const userReserveData = await helpersContract.getUserReserveData(
weth.address,
users[1].address
);
expect(userReserveData.currentStableDebt.toString()).to.be.eq(ethers.utils.parseEther('0.1'));
});
@ -80,7 +83,7 @@ makeSuite('AToken: Transfer', (testEnv: TestEnv) => {
const {users, pool, aDai, dai, weth} = testEnv;
const aDAItoTransfer = await convertToCurrencyDecimals(dai.address, '1000');
await expect(
aDai.connect(users[1].signer).transfer(users[0].address, aDAItoTransfer),
TRANSFER_NOT_ALLOWED
@ -88,15 +91,14 @@ makeSuite('AToken: Transfer', (testEnv: TestEnv) => {
});
it('User 1 tries to transfer a small amount of DAI used as collateral back to user 0', async () => {
const {users, pool, aDai, dai, weth} = testEnv;
const aDAItoTransfer = await convertToCurrencyDecimals(dai.address, '100');
await aDai.connect(users[1].signer).transfer(users[0].address, aDAItoTransfer);
const user0Balance = await aDai.balanceOf(users[0].address);
expect(user0Balance.toString()).to.be.eq(aDAItoTransfer.toString());
});
});
});

View File

@ -48,7 +48,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
_mockFlashLoanReceiver.address,
[weth.address],
[ethers.utils.parseEther('0.8')],
0,
[0],
_mockFlashLoanReceiver.address,
'0x10',
'0'
@ -78,7 +78,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
_mockFlashLoanReceiver.address,
[weth.address],
['1000720000000000000'],
0,
[0],
_mockFlashLoanReceiver.address,
'0x10',
'0'
@ -110,7 +110,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
_mockFlashLoanReceiver.address,
[weth.address],
[ethers.utils.parseEther('0.8')],
0,
[0],
caller.address,
'0x10',
'0'
@ -131,7 +131,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
_mockFlashLoanReceiver.address,
[weth.address],
[ethers.utils.parseEther('0.8')],
0,
[0],
caller.address,
'0x10',
'0'
@ -152,12 +152,12 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
_mockFlashLoanReceiver.address,
[weth.address],
[ethers.utils.parseEther('0.8')],
4,
[4],
caller.address,
'0x10',
'0'
)
).to.be.revertedWith(INVALID_FLASHLOAN_MODE);
).to.be.reverted;
});
it('Caller deposits 1000 DAI as collateral, Takes WETH flashloan with mode = 2, does not return the funds. A variable loan for caller is created', async () => {
@ -181,7 +181,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
_mockFlashLoanReceiver.address,
[weth.address],
[ethers.utils.parseEther('0.8')],
2,
[2],
caller.address,
'0x10',
'0'
@ -209,7 +209,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
_mockFlashLoanReceiver.address,
[weth.address],
['1004415000000000000'], //slightly higher than the available liquidity
2,
[2],
caller.address,
'0x10',
'0'
@ -223,7 +223,15 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
const caller = users[1];
await expect(
pool.flashLoan(deployer.address, [weth.address], ['1000000000000000000'], 2, caller.address, '0x10', '0')
pool.flashLoan(
deployer.address,
[weth.address],
['1000000000000000000'],
[2],
caller.address,
'0x10',
'0'
)
).to.be.reverted;
});
@ -251,7 +259,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
_mockFlashLoanReceiver.address,
[usdc.address],
[flashloanAmount],
0,
[0],
_mockFlashLoanReceiver.address,
'0x10',
'0'
@ -294,7 +302,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
_mockFlashLoanReceiver.address,
[usdc.address],
[flashloanAmount],
2,
[2],
caller.address,
'0x10',
'0'
@ -321,7 +329,15 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
await pool
.connect(caller.signer)
.flashLoan(_mockFlashLoanReceiver.address, [usdc.address], [flashloanAmount], 2, caller.address, '0x10', '0');
.flashLoan(
_mockFlashLoanReceiver.address,
[usdc.address],
[flashloanAmount],
[2],
caller.address,
'0x10',
'0'
);
const {variableDebtTokenAddress} = await helpersContract.getReserveTokensAddresses(
usdc.address
);
@ -360,7 +376,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
_mockFlashLoanReceiver.address,
[weth.address],
[flashAmount],
0,
[0],
caller.address,
'0x10',
'0'
@ -383,7 +399,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
_mockFlashLoanReceiver.address,
[weth.address],
[flashAmount],
1,
[1],
caller.address,
'0x10',
'0'
@ -429,7 +445,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
_mockFlashLoanReceiver.address,
[weth.address],
[flashAmount],
1,
[1],
onBehalfOf.address,
'0x10',
'0'
@ -458,7 +474,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
_mockFlashLoanReceiver.address,
[weth.address],
[flashAmount],
1,
[1],
onBehalfOf.address,
'0x10',
'0'

View File

@ -191,7 +191,7 @@ makeSuite('Pausable Pool', (testEnv: TestEnv) => {
_mockFlashLoanReceiver.address,
[weth.address],
[flashAmount],
1,
[1],
caller.address,
'0x10',
'0'