Function: _liquidateExternally(uint256 tokenId, uint128[] amounts, uint256 lpTokens, address to, byte[] data)
Allows any caller to liquidate the existing loan using a flash loan of collateral tokens from the pool and/or CFMM LP tokens. Before the liquidation, the externalSwap function will be called. After that, a check will be made that enough tokens have been deposited. Allows only full liquidation of the loan.
Inputs
tokenIdValidation: There is no verification that the corresponding
_loanfor thistokenIdexists.Impact: A
tokenIdreferring to an existing_loan. Not necessarymsg.senderis owner of_loan, so the caller can choose any existing loan.
amountsValidation: There is a check that
amount<=s.TOKEN_BALANCEinsideexternalSwap->sendAndCalcCollateralLPTokens->sendTokenfunction.Impact: Amount of tokens from the pool to flash loan.
lpTokensValidation: There is a check that
lpTokens<=s.LP_TOKEN_BALANCEinsideexternalSwap->sendCFMMLPTokens->sendTokenfunctionImpact: Amount of CFMM LP tokens being flash loaned.
toValidation: Cannot be zero address.
Impact: Address that will receive the collateral tokens and/or
lpTokensin flash loan.
dataValidation: No checks.
Impact: Custom user data. It is passed to the
externalCall.
Branches and code coverage (including function calls)
The part of _liquidateExternally tests are skipped.
Intended branches
Negative behavior
Function call analysis
externalSwap(_loan, s.cfmm, amounts, lpTokens, to, data) -> sendAndCalcCollateralLPTokens(to, amounts, lastCFMMTotalSupply) -> sendToken(IERC20(tokens[i]), to, amounts[i], s.TOKEN_BALANCE[i], type(uint128).max) -> GammaSwapLibrary.safeTransfer(token, to, amount)External/Internal? External.
Argument control?
toandamount.Impact: The caller can transfer any number of tokens that is less than
s.TOKEN_BALANCE[i], but they must return the same or a larger amount after theexternalCallfunction call; it will be checked inside theupdateCollateralfunction.
externalSwap(_loan, s.cfmm, amounts, lpTokens, to, data) -> sendCFMMLPTokens(_cfmm, to, lpTokens) -> sendToken(IERC20(_cfmm), to, lpTokens, s.LP_TOKEN_BALANCE, type(uint256).max) -> GammaSwapLibrary.safeTransfer(token, to, amount)External/Internal? External.
Argument control?
toandamount.Impact: The caller can transfer any number of tokens that is less than
s.LP_TOKEN_BALANCE, but they must return the same or a larger amount after theexternalCallfunction call; it will be checked inside thepayLoanAndRefundLiquidatorfunction.
externalSwap(_loan, s.cfmm, amounts, lpTokens, to, data) -> IExternalCallee(to).externalCall(msg.sender, amounts, lpTokens, data);External/Internal? External.
Argument control?
msg.sender,amounts,lpTokens, anddata.Impact: The reentrancy is not possible because the other important external functions have
lock. If caller does not return enough amount of tokens, the transaction will be reverted.
externalSwap(_loan, s.cfmm, amounts, lpTokens, to, data) -> updateCollateral(_loan) -> GammaSwapLibrary.balanceOf(IERC20(tokens[i]), address(this)); -> address(_token).staticcall(abi.encodeWithSelector(_token.balanceOf.selector, _address))Impact: Return the current token balance of this contract. This balance will be compared with the last
tokenBalance[i]value; if the balance was increased, the_loan.tokensHeldands.TOKEN_BALANCEwill be increased too. But if the balance was decreased, the withdrawn value will be checked that it is no more thantokensHeld[i](available collateral) and the_loan.tokensHeldands.TOKEN_BALANCEwill be increased.
payLoanAndRefundLiquidator(tokenId, tokensHeld, loanLiquidity, 0, true) -> GammaSwapLibrary.safeTransfer(IERC20(s.cfmm), msg.sender, lpRefund);External/Internal? External.
Argument control? No.
Impact: The user should not control the
lpRefundvalue. Transfer the remaining part of CFMMLPTokens.