Bauer
medium
Some NFTs, such as CryptoKitty and CryptoFighter, can be paused, which prevents users from repaying and liquidating
Some NFTs like CryptoKitty and CryptoFighter can be paused, which block repaying and liquidating . When NFTs are paused, borrowers still need to pay the accumulated interest and might not be able to liquidate on time.
When a borrower uses an NFT as collateral to borrow money, the NFT is accruing interest every second.As the code below, the function calculateAmountOwed()
calculates the interest of the collateral through the formula interest_ = (interestOwedInAYear * owedTime) / daysInYear;
, and adds up the total interests on top of the principal amount.
function calculateAmountOwed(
Bid storage _bid,
uint256 _lastRepaidTimestamp,
uint256 _timestamp,
PaymentCycleType _paymentCycleType
)
internal
view
returns (
uint256 owedPrincipal_,
uint256 duePrincipal_,
uint256 interest_
)
{
owedPrincipal_ =
_bid.loanDetails.principal -
_bid.loanDetails.totalRepaid.principal;
uint256 daysInYear = _paymentCycleType == PaymentCycleType.Monthly
? 360 days
: 365 days;
uint256 interestOwedInAYear = owedPrincipal_.percent(_bid.terms.APR);
uint256 owedTime = _timestamp - uint256(_lastRepaidTimestamp);
interest_ = (interestOwedInAYear * owedTime) / daysInYear;
// Cast to int265 to avoid underflow errors (negative means loan duration has passed)
int256 durationLeftOnLoan = int256(
uint256(_bid.loanDetails.loanDuration)
) -
(int256(_timestamp) -
int256(uint256(_bid.loanDetails.acceptedTimestamp)));
bool isLastPaymentCycle = durationLeftOnLoan <
int256(uint256(_bid.terms.paymentCycle)) || // Check if current payment cycle is within or beyond the last one
owedPrincipal_ + interest_ <= _bid.terms.paymentCycleAmount; // Check if what is left to pay is less than the payment cycle amount
if (_bid.paymentType == PaymentType.Bullet) {
if (isLastPaymentCycle) {
duePrincipal_ = owedPrincipal_;
}
} else {
// Default to PaymentType.EMI
// Max payable amount in a cycle
// NOTE: the last cycle could have less than the calculated payment amount
uint256 maxCycleOwed = isLastPaymentCycle
? owedPrincipal_ + interest_
: _bid.terms.paymentCycleAmount;
// Calculate accrued amount due since last repayment
uint256 owedAmount = (maxCycleOwed * owedTime) /
_bid.terms.paymentCycle;
duePrincipal_ = Math.min(owedAmount - interest_, owedPrincipal_);
}
}
The loan can also be liquidated if the requirements for liquidation are met.
function _canLiquidateLoan(uint256 _bidId, uint32 _liquidationDelay)
internal
view
returns (bool)
{
Bid storage bid = bids[_bidId];
// Make sure loan cannot be liquidated if it is not active
if (bid.state != BidState.ACCEPTED) return false;
if (bidDefaultDuration[_bidId] == 0) return false;
return (uint32(block.timestamp) -
_liquidationDelay -
lastRepaidTimestamp(_bidId) >
bidDefaultDuration[_bidId]);
}
However ,in both CryptoKitty and CryptoFighter NFT, the transfer method can be paused. Crypto-figher NFT: https://etherscan.io/address/0x87d598064c736dd0C712D329aFCFAA0Ccc1921A1#code#L873
function transferFrom(
address _from,
address _to,
uint256 _tokenId
)
public
whenNotPaused
{
Crypto-kitty NFT: https://etherscan.io/address/0x06012c8cf97BEaD5deAe237070F9587f8E7A266d#code#L615
function transferFrom(
address _from,
address _to,
uint256 _tokenId
)
external
whenNotPaused
{
According to the document, the protocol support any ERC721 token. Hence,if the transfer and transferFrom is paused , the repaying action will be blocked. The borrower cannot fully clear his debt and has to wait until the transfer is unpaused to pay the unnecessary extra interest. Also, if the NFT is paused for far too long, the NFT will be subjected to liquidation. Both scenarios will be unfair for the borrower.
See above
Manual Review
Blacklist some NFTs