Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 43 - Need to account for already repaid amount in liquidations #85

Open
wants to merge 20 commits into
base: merge-train-r5
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;


// Contracts
import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
Expand Down Expand Up @@ -434,8 +435,14 @@ contract LenderCommitmentGroup_Smart is
{

int256 poolTotalEstimatedValueSigned = int256(totalPrincipalTokensCommitted)
//+ int256( totalPrincipalTokensRepaid ) //cant really incorporate because needs totalPrincipalTokensLended to help balance it

+ int256(totalInterestCollected) + int256(tokenDifferenceFromLiquidations)
- int256(totalPrincipalTokensWithdrawn);
- int256( totalPrincipalTokensWithdrawn )
//- int256( totalPrincipalTokensLended ) //amount borrowed -- should not be incorporated as it does not really affect net value
;



//if the poolTotalEstimatedValue_ is less than 0, we treat it as 0.
poolTotalEstimatedValue_ = poolTotalEstimatedValueSigned > int256(0)
Expand Down Expand Up @@ -661,7 +668,11 @@ contract LenderCommitmentGroup_Smart is

//use original principal amount as amountDue

uint256 amountDue = _getAmountOwedForBid(_bidId);
uint256 loanTotalPrincipalAmount = _getLoanTotalPrincipalAmount(_bidId); //only used for the auction delta amount

(uint256 principalDue,uint256 interestDue) = _getAmountOwedForBid(_bidId); //this is the base amount that must be repaid by the liquidator

// uint256 principalAmountAlreadyRepaid = loanTotalPrincipalAmount - principalDue;


uint256 loanDefaultedTimeStamp = ITellerV2(TELLER_V2)
Expand All @@ -673,10 +684,11 @@ contract LenderCommitmentGroup_Smart is
);

int256 minAmountDifference = getMinimumAmountDifferenceToCloseDefaultedLoan(
amountDue,
loanTotalPrincipalAmount,
loanDefaultedOrUnpausedAtTimeStamp
);


require(
_tokenAmountDifference >= minAmountDifference,
"Insufficient tokenAmountDifference"
Expand All @@ -687,7 +699,8 @@ contract LenderCommitmentGroup_Smart is
//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(minAmountDifference);




uint256 liquidationProtocolFee = Math.mulDiv(
tokensToTakeFromSender ,
Expand All @@ -699,18 +712,22 @@ contract LenderCommitmentGroup_Smart is
IERC20(principalToken).safeTransferFrom(
msg.sender,
address(this),
amountDue + tokensToTakeFromSender - liquidationProtocolFee
principalDue + tokensToTakeFromSender - liquidationProtocolFee
);

address protocolFeeRecipient = ITellerV2(address(TELLER_V2)).getProtocolFeeRecipient();

IERC20(principalToken).safeTransferFrom(
msg.sender,
address(protocolFeeRecipient),
liquidationProtocolFee
);
if (liquidationProtocolFee > 0) {
IERC20(principalToken).safeTransferFrom(
msg.sender,
address(protocolFeeRecipient),
liquidationProtocolFee
);
}

totalPrincipalTokensRepaid += principalDue;

totalPrincipalTokensRepaid += amountDue;
// tokenDifferenceFromLiquidations += int256(principalAmountAlreadyRepaid); //this helps us more correctly calculate the shortfall
tokenDifferenceFromLiquidations += int256(tokensToTakeFromSender - liquidationProtocolFee );


Expand All @@ -719,33 +736,56 @@ contract LenderCommitmentGroup_Smart is

uint256 tokensToGiveToSender = abs(minAmountDifference);


IERC20(principalToken).safeTransferFrom(
msg.sender,
address(this),
amountDue - tokensToGiveToSender
);


//dont stipend/refund more than principalDue base
if (tokensToGiveToSender > principalDue) {
tokensToGiveToSender = principalDue;
}

uint256 netAmountDue = principalDue - tokensToGiveToSender ;


totalPrincipalTokensRepaid += amountDue;
if (netAmountDue > 0) {
IERC20(principalToken).safeTransferFrom(
msg.sender,
address(this),
netAmountDue //principalDue - tokensToGiveToSender
);
}

totalPrincipalTokensRepaid += principalDue;

//this will make tokenDifference go more negative
tokenDifferenceFromLiquidations -= int256(tokensToGiveToSender);

//this is the shortfall
// tokenDifferenceFromLiquidations += int256(principalAmountAlreadyRepaid);//this helps us more correctly calculate the shortfall
// tokenDifferenceFromLiquidations -= int256(tokensToGiveToSender);

// uint256 shortfallNet = principalDue < tokensToGiveToSender ? tokensToGiveToSender - principalDue : 0;

tokenDifferenceFromLiquidations -= int256(tokensToGiveToSender);



}

//this will effectively 'forfeit' tokens from this contract equal to ... the amount (principal) that has not been repaid ! principalDue


//this will give collateral to the caller
ITellerV2(TELLER_V2).lenderCloseLoanWithRecipient(_bidId, msg.sender);


emit DefaultedLoanLiquidated(
_bidId,
msg.sender,
amountDue,
principalDue,
_tokenAmountDifference
);
}



function getLastUnpausedAt()
public view
Expand All @@ -766,18 +806,29 @@ contract LenderCommitmentGroup_Smart is
lastUnpausedAt = block.timestamp;
}

function _getLoanTotalPrincipalAmount(uint256 _bidId )
internal
view
virtual
returns (uint256 principalAmount)
{
(,,,, principalAmount, , , )
= ITellerV2(TELLER_V2).getLoanSummary(_bidId);


}



function _getAmountOwedForBid(uint256 _bidId )
internal
view
virtual
returns (uint256 amountDue)
returns (uint256 principal,uint256 interest)
{
(,,,, amountDue, , , )
= ITellerV2(TELLER_V2).getLoanSummary(_bidId);
Payment memory owed = ITellerV2(TELLER_V2).calculateAmountOwed(_bidId, block.timestamp );


return (owed.principal, owed.interest) ;
}


Expand Down Expand Up @@ -966,7 +1017,11 @@ contract LenderCommitmentGroup_Smart is
public
view
returns (uint256)
{
{
if (totalPrincipalTokensRepaid > totalPrincipalTokensLended) {
return 0;
}

return totalPrincipalTokensLended - totalPrincipalTokensRepaid;
}

Expand Down
2 changes: 2 additions & 0 deletions packages/contracts/contracts/mock/TellerV2SolMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,8 @@ ILoanRepaymentCallbacks
);
}



/*
* @notice Calculates the minimum payment amount due for a loan.
* @param _bidId The id of the loan bid to get the payment amount for.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,8 @@ contract LenderCommitmentGroup_Smart_Test is Testable {
uint256 bidId = 0;


lenderCommitmentGroupSmart.set_mockAmountOwedForBid(amountOwed);
lenderCommitmentGroupSmart.set_mockLoanTotalPrincipalAmount(amountOwed);
lenderCommitmentGroupSmart.set_mockAmountOwedForBid(amountOwed, 0);



Expand Down Expand Up @@ -291,7 +292,8 @@ contract LenderCommitmentGroup_Smart_Test is Testable {

_tellerV2.setMockProtocolFeeRecipient( address(lenderCommitmentGroupSmart) );

lenderCommitmentGroupSmart.set_mockAmountOwedForBid(amountOwed);
lenderCommitmentGroupSmart.set_mockLoanTotalPrincipalAmount(amountOwed);
lenderCommitmentGroupSmart.set_mockAmountOwedForBid(amountOwed, 0);


//time has advanced enough to now have a 50 percent discount s
Expand Down Expand Up @@ -347,7 +349,9 @@ function test_liquidateDefaultedLoanWithIncentive_increments_amount_repaid_A() p
lenderCommitmentGroupSmart.set_totalPrincipalTokensCommitted(originalTotalPrincipalTokensCommitted);


lenderCommitmentGroupSmart.set_mockAmountOwedForBid(amountOwed);
lenderCommitmentGroupSmart.set_mockLoanTotalPrincipalAmount(amountOwed);
lenderCommitmentGroupSmart.set_mockAmountOwedForBid(amountOwed, 0);

_tellerV2.setMockProtocolFeeRecipient( address(lenderCommitmentGroupSmart) );


Expand Down Expand Up @@ -420,8 +424,8 @@ function test_liquidateDefaultedLoanWithIncentive_increments_amount_repaid_A() p
_tellerV2.setMockOwner( address(lenderCommitmentGroupSmart) );
_tellerV2.setMockProtocolFeeRecipient( address(lenderCommitmentGroupSmart) );

lenderCommitmentGroupSmart.set_mockAmountOwedForBid(amountOwed);

lenderCommitmentGroupSmart.set_mockLoanTotalPrincipalAmount(amountOwed);
lenderCommitmentGroupSmart.set_mockAmountOwedForBid(amountOwed, 0);

//time has advanced enough to now have a 50 percent discount s
vm.warp(1000); //loanDefaultedTimeStamp ?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ contract LenderCommitmentGroup_Smart_Override is LenderCommitmentGroup_Smart {
uint256 mockSharesExchangeRate;
int256 mockMinimumAmountDifferenceToCloseDefaultedLoan;

uint256 mockAmountOwed;
uint256 mockLoanTotalPrincipalAmount;

uint256 mockAmountOwedPrincipal;
uint256 mockAmountOwedInterest;

address mockToken0;
address mockToken1;
Expand Down Expand Up @@ -71,16 +74,28 @@ contract LenderCommitmentGroup_Smart_Override is LenderCommitmentGroup_Smart {
}

function _getAmountOwedForBid(uint256 _bidId )
internal override view returns (uint256){
return mockAmountOwed;
internal override view returns (uint256, uint256){
return (mockAmountOwedPrincipal,mockAmountOwedInterest );

}

function set_mockAmountOwedForBid(uint256 _amt) public {
mockAmountOwed = _amt;
function set_mockAmountOwedForBid(uint256 _principal,uint256 _interest) public {
mockAmountOwedPrincipal = _principal;
mockAmountOwedInterest = _interest;
}



function _getLoanTotalPrincipalAmount(uint256 _bidId )
internal override view returns (uint256){
return mockLoanTotalPrincipalAmount;

}
function set_mockLoanTotalPrincipalAmount(uint256 _principal) public {
mockLoanTotalPrincipalAmount = _principal;

}

function set_totalPrincipalTokensRepaid(uint256 _mockAmt) public {
totalPrincipalTokensRepaid = _mockAmt;
}
Expand Down
Loading
Loading