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
tokenId
Validation: There is no verification that the corresponding
_loan
for thistokenId
exists.Impact: A
tokenId
referring to an existing_loan
. Not necessarymsg.sender
is owner of_loan
, so the caller can choose any existing loan.
amounts
Validation: There is a check that
amount
<=s.TOKEN_BALANCE
insideexternalSwap->sendAndCalcCollateralLPTokens->sendToken
function.Impact: Amount of tokens from the pool to flash loan.
lpTokens
Validation: There is a check that
lpTokens
<=s.LP_TOKEN_BALANCE
insideexternalSwap->sendCFMMLPTokens->sendToken
functionImpact: Amount of CFMM LP tokens being flash loaned.
to
Validation: Cannot be zero address.
Impact: Address that will receive the collateral tokens and/or
lpTokens
in flash loan.
data
Validation: 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?
to
andamount
.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 theexternalCall
function call; it will be checked inside theupdateCollateral
function.
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?
to
andamount
.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 theexternalCall
function call; it will be checked inside thepayLoanAndRefundLiquidator
function.
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.tokensHeld
ands.TOKEN_BALANCE
will 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.tokensHeld
ands.TOKEN_BALANCE
will 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
lpRefund
value. Transfer the remaining part of CFMMLPTokens.