Function: flashLoanMultiple(IFlashLoanRecipient recipient, address[] tokens, uint256[] amounts, byte[] userData)
Allows to take a flash loan from the vault, taking multiple assets at the same time.
Inputs
recipient
Control: Arbitrary.
Constraints: None.
Impact: Determines the recipient that receives the borrowed assets.
tokens
Control: Arbitrary.
Constraints: Elements must be sorted and unique.
Impact: Determines the assets to be borrowed.
amounts
Control: Arbitrary.
Constraints:
amounts.length == tokens.length
; every amount is less than the corresponding vault balance.Impact: Determines the amounts to be borrowed.
userData
Control: Arbitrary.
Constraints: None.
Impact: Arbitrary data passed to the recipient.
Branches and code coverage (including function calls)
Intended branches
Sends the borrowed funds to the recipient, invokes the recipient, and checks that the funds and interests are returned.
Negative behavior
Reverts if the vault balance is not enough to cover the requested loan.
Reverts if the borrower does not return ERC3156_CALLBACK_SUCCESS
.
Reverts if the flash loan is not repaid.
Reverts if amounts.length != tokens.length
.
Reverts if the vault does not have sufficient balance to cover the requested loan.
Function call analysis
rootFunction -> preLoanBalances[i] = IERC20(token).balanceOf(address(this))
What is controllable?
token
.If return value controllable, how is it used and how can it go wrong? Used as the preloan balance of the contract, not controllable for legitimate tokens.
What happens if it reverts, reenters, or does other unusual control flow? Reverts are bubbled up; reentrancy is prevented via the
nonReentrant
modifier.
rootFunction -> feeAmounts[i] = _calculateFlashLoanFeeAmount(amount)
What is controllable?
amount
.If return value controllable, how is it used and how can it go wrong? The function returns the interests of the flash loan, proportional to
amount
.What happens if it reverts, reenters, or does other unusual control flow? Reverts (e.g., due to overflow) are bubbled up; reentrancy is not a concern.
rootFunction -> TransferHelper.safeTransfer(token, address(receiver), amount)
What is controllable?
token
,receiver
,amount
.If return value controllable, how is it used and how can it go wrong? The return value of the internal call must be
bool(true)
.What happens if it reverts, reenters, or does other unusual control flow? Reverts are bubbled up; reentrancy is prevented via the
nonReentrant
modifier.
rootFunction -> recipient.receiveFlashLoan(tokens, amounts, feeAmounts, userData)
What is controllable?
tokens
,amounts
,userData
.If return value controllable, how is it used and how can it go wrong? N/A.
What happens if it reverts, reenters, or does other unusual control flow? Reverts are bubbled up; reentrancy is prevented via the
nonReentrant
modifier.
rootFunction -> postLoanBalance = IERC20(token).balanceOf(address(this))
What is controllable?
token
.If return value controllable, how is it used and how can it go wrong? Used as the postloan balance of the contract, not controllable for legitimate tokens.
What happens if it reverts, reenters, or does other unusual control flow? Reverts are bubbled up; reentrancy is prevented via the
nonReentrant
modifier.
rootFunction -> _payFeeAmount(token, receivedFeeAmount)
What is controllable?
token
,receivedFeeAmount
.If return value controllable, how is it used and how can it go wrong? N/A.
What happens if it reverts, reenters, or does other unusual control flow? Reverts are bubbled up; reentrancy is prevented via the
nonReentrant
modifier.