pkqs90 - `liquidateDefaultedLoanWithIncentive` cannot be called with 0 tokens even if 96400 seconds has passed for ERC20 tokens that doesn't support zero-transfer #270
liquidateDefaultedLoanWithIncentive cannot be called with 0 tokens even if 96400 seconds has passed for ERC20 tokens that doesn't support zero-transfer
Summary
During liquidation phase of LenderCommitmentGroup_Smart, users can call liquidateDefaultedLoanWithIncentive for liquidating loans that are default. If 96400 seconds has passed the default loan time, the liquidation should be able to finish without transfering any tokens. However, for ERC20 tokens that reverts on zero-transfer, this is not possible, and at least 1wei token must be supplied.
Vulnerability Detail
After 96400 has passed, user can pass _tokenAmountDifference equal to negative of amountDue to perform liquidation with 0 tokens. However, this is not possible for tokens that doesn't support zero-transfer, and at least 1 wei must be supplied by the user, which is unexpected.
An example of revert on zero-transfer token is LEND.
The contest README states that any tokens compatible with Uniswap V3 should be supported.
We are allowing any standard token that would be compatible with Uniswap V3 to work with our codebase, just as was the case for the original audit of TellerV2.sol. The tokens are assumed to be able to work with Uniswap V3.
function liquidateDefaultedLoanWithIncentive(
uint256 _bidId,
int256 _tokenAmountDifference
) public bidIsActiveForGroup(_bidId) {
uint256 amountDue = getAmountOwedForBid(_bidId, false);
uint256 loanDefaultedTimeStamp = ITellerV2(TELLER_V2)
.getLoanDefaultTimestamp(_bidId);
int256 minAmountDifference = getMinimumAmountDifferenceToCloseDefaultedLoan(
amountDue,
loanDefaultedTimeStamp
);
require(
_tokenAmountDifference >= minAmountDifference,
"Insufficient tokenAmountDifference"
);
if (_tokenAmountDifference > 0) {
//this is used when the collateral value is higher than the principal (rare)
//the loan will be completely made whole and our contract gets extra funds too
uint256 tokensToTakeFromSender = abs(_tokenAmountDifference);
IERC20(principalToken).transferFrom(
msg.sender,
address(this),
amountDue + tokensToTakeFromSender
);
tokenDifferenceFromLiquidations += int256(tokensToTakeFromSender);
totalPrincipalTokensRepaid += amountDue;
} else {
uint256 tokensToGiveToSender = abs(_tokenAmountDifference);
> IERC20(principalToken).transferFrom(
> msg.sender,
> address(this),
> amountDue - tokensToGiveToSender
> );
tokenDifferenceFromLiquidations -= int256(tokensToGiveToSender);
totalPrincipalTokensRepaid += amountDue;
}
//this will give collateral to the caller
ITellerV2(TELLER_V2).lenderCloseLoanWithRecipient(_bidId, msg.sender);
}
function getMinimumAmountDifferenceToCloseDefaultedLoan(
uint256 _amountOwed,
uint256 _loanDefaultedTimestamp
) public view virtual returns (int256 amountDifference_) {
require(
_loanDefaultedTimestamp > 0,
"Loan defaulted timestamp must be greater than zero"
);
require(
block.timestamp > _loanDefaultedTimestamp,
"Loan defaulted timestamp must be in the past"
);
uint256 secondsSinceDefaulted = block.timestamp -
_loanDefaultedTimestamp;
int256 incentiveMultiplier = int256(86400) -
int256(secondsSinceDefaulted);
if (incentiveMultiplier < -10000) {
incentiveMultiplier = -10000;
}
amountDifference_ =
(int256(_amountOwed) * incentiveMultiplier) /
int256(10000);
}
Impact
User must supply 1 wei of token to call liquidateDefaultedLoanWithIncentive() even though the required amount is 0 (after 96400 seconds).
pkqs90
medium
liquidateDefaultedLoanWithIncentive
cannot be called with 0 tokens even if 96400 seconds has passed for ERC20 tokens that doesn't support zero-transferSummary
During liquidation phase of
LenderCommitmentGroup_Smart
, users can callliquidateDefaultedLoanWithIncentive
for liquidating loans that are default. If 96400 seconds has passed the default loan time, the liquidation should be able to finish without transfering any tokens. However, for ERC20 tokens that reverts on zero-transfer, this is not possible, and at least 1wei token must be supplied.Vulnerability Detail
After 96400 has passed, user can pass
_tokenAmountDifference
equal to negative ofamountDue
to perform liquidation with 0 tokens. However, this is not possible for tokens that doesn't support zero-transfer, and at least 1 wei must be supplied by the user, which is unexpected.An example of revert on zero-transfer token is LEND.
The contest README states that any tokens compatible with Uniswap V3 should be supported.
Impact
User must supply 1 wei of token to call
liquidateDefaultedLoanWithIncentive()
even though the required amount is 0 (after 96400 seconds).Code Snippet
Tool used
Manual review
Recommendation
Add a check for token transfer value, and skip calling
transfer
if it is zero.