View Source: contracts/modules/LoanClosingsShared.sol
↗ Extends: LoanClosingsEvents, VaultController, InterestUser, SwapsUser, RewardHelper, ModuleCommonFunctionalities ↘ Derived Contracts: LoanClosingsLiquidation, LoanClosingsRollover, LoanClosingsWith
This contract should only contains the internal function that is being used / utilized by LoanClosingsLiquidation, LoanClosingsRollover & LoanClosingsWith contract *
Enums
enum CloseTypes {
Deposit,
Swap,
Liquidation
}
Constants & Variables
//internal members
uint256 internal constant MONTH;
//public members
uint256 public constant paySwapExcessToBorrowerThreshold;
uint256 public constant TINY_AMOUNT;
modifier iTokenSupplyUnchanged(bytes32 loanId) internal
Arguments
Name | Type | Description |
---|---|---|
loanId | bytes32 |
- _settleInterestToPrincipal(struct LoanStruct.Loan loanLocal, struct LoanParamsStruct.LoanParams loanParamsLocal, uint256 loanCloseAmount, address receiver)
- _returnPrincipalWithDeposit(address loanToken, address receiver, uint256 principalNeeded)
- worthTheTransfer(address asset, uint256 amount)
- _doCollateralSwap(struct LoanStruct.Loan loanLocal, struct LoanParamsStruct.LoanParams loanParamsLocal, uint256 swapAmount, uint256 principalNeeded, bool returnTokenIsCollateral, bytes loanDataBytes)
- _withdrawAsset(address assetToken, address receiver, uint256 assetAmount)
- _closeLoan(struct LoanStruct.Loan loanLocal, uint256 loanCloseAmount)
- _settleInterest(struct LoanParamsStruct.LoanParams loanParamsLocal, struct LoanStruct.Loan loanLocal, uint256 closePrincipal)
- _checkAuthorized(bytes32 loanId)
- _closeWithSwap(bytes32 loanId, address receiver, uint256 swapAmount, bool returnTokenIsCollateral, bytes loanDataBytes)
- _finalizeClose(struct LoanStruct.Loan loanLocal, struct LoanParamsStruct.LoanParams loanParamsLocal, uint256 loanCloseAmount, uint256 collateralCloseAmount, uint256 collateralToLoanSwapRate, enum LoanClosingsShared.CloseTypes closeType)
- _coverPrincipalWithSwap(struct LoanStruct.Loan loanLocal, struct LoanParamsStruct.LoanParams loanParamsLocal, uint256 swapAmount, uint256 principalNeeded, bool returnTokenIsCollateral, bytes loanDataBytes)
- _emitClosingEvents(struct LoanParamsStruct.LoanParams loanParamsLocal, struct LoanStruct.Loan loanLocal, uint256 loanCloseAmount, uint256 collateralCloseAmount, uint256 collateralToLoanRate, uint256 collateralToLoanSwapRate, uint256 currentMargin, enum LoanClosingsShared.CloseTypes closeType)
- _getAmountInRbtc(address asset, uint256 amount)
- _checkLoan(bytes32 loanId)
computes the interest which needs to be refunded to the borrower based on the amount he's closing and either subtracts it from the amount which still needs to be paid back (in case outstanding amount > interest) or withdraws the excess to the borrower (in case interest > outstanding).
function _settleInterestToPrincipal(struct LoanStruct.Loan loanLocal, struct LoanParamsStruct.LoanParams loanParamsLocal, uint256 loanCloseAmount, address receiver) internal nonpayable
returns(uint256)
Arguments
Name | Type | Description |
---|---|---|
loanLocal | struct LoanStruct.Loan | the loan |
loanParamsLocal | struct LoanParamsStruct.LoanParams | the loan params |
loanCloseAmount | uint256 | the amount to be closed (base for the computation) |
receiver | address | the address of the receiver (usually the borrower) |
Source Code
function _settleInterestToPrincipal(
Loan memory loanLocal,
LoanParams memory loanParamsLocal,
uint256 loanCloseAmount,
address receiver
) internal returns (uint256) {
uint256 loanCloseAmountLessInterest = loanCloseAmount;
//compute the interest which neeeds to be refunded to the borrower (because full interest is paid on loan )
uint256 interestRefundToBorrower =
_settleInterest(loanParamsLocal, loanLocal, loanCloseAmountLessInterest);
uint256 interestAppliedToPrincipal;
//if the outstanding loan is bigger than the interest to be refunded, reduce the amount to be paid back / closed by the interest
if (loanCloseAmountLessInterest >= interestRefundToBorrower) {
// apply all of borrower interest refund torwards principal
interestAppliedToPrincipal = interestRefundToBorrower;
// principal needed is reduced by this amount
loanCloseAmountLessInterest -= interestRefundToBorrower;
// no interest refund remaining
interestRefundToBorrower = 0;
} else {
//if the interest refund is bigger than the outstanding loan, the user needs to get back the interest
// principal fully covered by excess interest
interestAppliedToPrincipal = loanCloseAmountLessInterest;
// amount refunded is reduced by this amount
interestRefundToBorrower -= loanCloseAmountLessInterest;
// principal fully covered by excess interest
loanCloseAmountLessInterest = 0;
if (interestRefundToBorrower != 0) {
// refund overage
_withdrawAsset(loanParamsLocal.loanToken, receiver, interestRefundToBorrower);
}
}
//pay the interest to the lender
//note: this is a waste of gas, because the loanCloseAmountLessInterest is withdrawn to the lender, too. It could be done at once.
if (interestAppliedToPrincipal != 0) {
// The lender always gets back an ERC20 (even wrbtc), so we call withdraw directly rather than
// use the _withdrawAsset helper function
vaultWithdraw(loanParamsLocal.loanToken, loanLocal.lender, interestAppliedToPrincipal);
}
return loanCloseAmountLessInterest;
}
function _returnPrincipalWithDeposit(address loanToken, address receiver, uint256 principalNeeded) internal nonpayable
Arguments
Name | Type | Description |
---|---|---|
loanToken | address | |
receiver | address | |
principalNeeded | uint256 |
Source Code
function _returnPrincipalWithDeposit(
address loanToken,
address receiver,
uint256 principalNeeded
) internal {
if (principalNeeded != 0) {
if (msg.value == 0) {
vaultTransfer(loanToken, msg.sender, receiver, principalNeeded);
} else {
require(loanToken == address(wrbtcToken), "wrong asset sent");
require(msg.value >= principalNeeded, "not enough ether");
wrbtcToken.deposit.value(principalNeeded)();
if (receiver != address(this)) {
vaultTransfer(loanToken, address(this), receiver, principalNeeded);
}
if (msg.value > principalNeeded) {
// refund overage
Address.sendValue(msg.sender, msg.value - principalNeeded);
}
}
} else {
require(msg.value == 0, "wrong asset sent");
}
}
checks if the amount of the asset to be transfered is worth the transfer fee
function worthTheTransfer(address asset, uint256 amount) internal nonpayable
returns(bool)
Arguments
Name | Type | Description |
---|---|---|
asset | address | the asset to be transfered |
amount | uint256 | the amount to be transfered |
Returns
True if the amount is bigger than the threshold
Source Code
function worthTheTransfer(address asset, uint256 amount) internal returns (bool) {
uint256 amountInRbtc = _getAmountInRbtc(asset, amount);
emit swapExcess(
amountInRbtc > paySwapExcessToBorrowerThreshold,
amount,
amountInRbtc,
paySwapExcessToBorrowerThreshold
);
return amountInRbtc > paySwapExcessToBorrowerThreshold;
}
function _doCollateralSwap(struct LoanStruct.Loan loanLocal, struct LoanParamsStruct.LoanParams loanParamsLocal, uint256 swapAmount, uint256 principalNeeded, bool returnTokenIsCollateral, bytes loanDataBytes) internal nonpayable
returns(destTokenAmountReceived uint256, sourceTokenAmountUsed uint256, collateralToLoanSwapRate uint256)
Arguments
Name | Type | Description |
---|---|---|
loanLocal | struct LoanStruct.Loan | the loan object |
loanParamsLocal | struct LoanParamsStruct.LoanParams | the loan parameters |
swapAmount | uint256 | the amount to be swapped |
principalNeeded | uint256 | the required destination token amount |
returnTokenIsCollateral | bool | if true -> required destination token amount will be passed on, else not note: quite dirty. should be refactored. |
loanDataBytes | bytes | additional loan data (not in use for token swaps) |
Source Code
function _doCollateralSwap(
Loan memory loanLocal,
LoanParams memory loanParamsLocal,
uint256 swapAmount,
uint256 principalNeeded,
bool returnTokenIsCollateral,
bytes memory loanDataBytes
)
internal
returns (
uint256 destTokenAmountReceived,
uint256 sourceTokenAmountUsed,
uint256 collateralToLoanSwapRate
)
{
(destTokenAmountReceived, sourceTokenAmountUsed, collateralToLoanSwapRate) = _loanSwap(
loanLocal.id,
loanParamsLocal.collateralToken,
loanParamsLocal.loanToken,
loanLocal.borrower,
swapAmount, // minSourceTokenAmount
loanLocal.collateral, // maxSourceTokenAmount
returnTokenIsCollateral
? principalNeeded // requiredDestTokenAmount
: 0,
false, // bypassFee
loanDataBytes
);
require(destTokenAmountReceived >= principalNeeded, "insufficient dest amount");
require(sourceTokenAmountUsed <= loanLocal.collateral, "excessive source amount");
}
Withdraw asset to receiver. *
function _withdrawAsset(address assetToken, address receiver, uint256 assetAmount) internal nonpayable
Arguments
Name | Type | Description |
---|---|---|
assetToken | address | The loan token. |
receiver | address | The address of the receiver. |
assetAmount | uint256 | The loan token amount. |
Source Code
function _withdrawAsset(
address assetToken,
address receiver,
uint256 assetAmount
) internal {
if (assetAmount != 0) {
if (assetToken == address(wrbtcToken)) {
vaultEtherWithdraw(receiver, assetAmount);
} else {
vaultWithdraw(assetToken, receiver, assetAmount);
}
}
}
Internal function to close a loan. *
function _closeLoan(struct LoanStruct.Loan loanLocal, uint256 loanCloseAmount) internal nonpayable
Arguments
Name | Type | Description |
---|---|---|
loanLocal | struct LoanStruct.Loan | The loan object. |
loanCloseAmount | uint256 | The amount to close: principal or lower. * |
Source Code
function _closeLoan(Loan storage loanLocal, uint256 loanCloseAmount) internal {
require(loanCloseAmount != 0, "nothing to close");
if (loanCloseAmount == loanLocal.principal) {
loanLocal.principal = 0;
loanLocal.active = false;
loanLocal.endTimestamp = block.timestamp;
loanLocal.pendingTradesId = 0;
activeLoansSet.removeBytes32(loanLocal.id);
lenderLoanSets[loanLocal.lender].removeBytes32(loanLocal.id);
borrowerLoanSets[loanLocal.borrower].removeBytes32(loanLocal.id);
} else {
loanLocal.principal = loanLocal.principal.sub(loanCloseAmount);
}
}
function _settleInterest(struct LoanParamsStruct.LoanParams loanParamsLocal, struct LoanStruct.Loan loanLocal, uint256 closePrincipal) internal nonpayable
returns(uint256)
Arguments
Name | Type | Description |
---|---|---|
loanParamsLocal | struct LoanParamsStruct.LoanParams | |
loanLocal | struct LoanStruct.Loan | |
closePrincipal | uint256 |
Source Code
function _settleInterest(
LoanParams memory loanParamsLocal,
Loan memory loanLocal,
uint256 closePrincipal
) internal returns (uint256) {
// pay outstanding interest to lender
_payInterest(loanLocal.lender, loanParamsLocal.loanToken);
LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];
LenderInterest storage lenderInterestLocal =
lenderInterest[loanLocal.lender][loanParamsLocal.loanToken];
uint256 interestTime = block.timestamp;
if (interestTime > loanLocal.endTimestamp) {
interestTime = loanLocal.endTimestamp;
}
_settleFeeRewardForInterestExpense(
loanInterestLocal,
loanLocal.id,
loanParamsLocal.loanToken, /// fee token
loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward
loanLocal.borrower,
interestTime
);
uint256 owedPerDayRefund;
if (closePrincipal < loanLocal.principal) {
owedPerDayRefund = loanInterestLocal.owedPerDay.mul(closePrincipal).div(
loanLocal.principal
);
} else {
owedPerDayRefund = loanInterestLocal.owedPerDay;
}
// update stored owedPerDay
loanInterestLocal.owedPerDay = loanInterestLocal.owedPerDay.sub(owedPerDayRefund);
lenderInterestLocal.owedPerDay = lenderInterestLocal.owedPerDay.sub(owedPerDayRefund);
// update borrower interest
uint256 interestRefundToBorrower = loanLocal.endTimestamp.sub(interestTime);
interestRefundToBorrower = interestRefundToBorrower.mul(owedPerDayRefund);
interestRefundToBorrower = interestRefundToBorrower.div(1 days);
if (closePrincipal < loanLocal.principal) {
loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.sub(
interestRefundToBorrower
);
} else {
loanInterestLocal.depositTotal = 0;
}
// update remaining lender interest values
lenderInterestLocal.principalTotal = lenderInterestLocal.principalTotal.sub(
closePrincipal
);
uint256 owedTotal = lenderInterestLocal.owedTotal;
lenderInterestLocal.owedTotal = owedTotal > interestRefundToBorrower
? owedTotal - interestRefundToBorrower
: 0;
return interestRefundToBorrower;
}
Check sender is borrower or delegatee and loan id exists. *
function _checkAuthorized(bytes32 loanId) internal view
Arguments
Name | Type | Description |
---|---|---|
loanId | bytes32 | byte32 of the loan id. |
Source Code
function _checkAuthorized(bytes32 loanId) internal view {
Loan storage loanLocal = loans[loanId];
require(
msg.sender == loanLocal.borrower || delegatedManagers[loanLocal.id][msg.sender],
"unauthorized"
);
}
Internal function for closing a position by swapping the collateral back to loan tokens, paying the lender and withdrawing the remainder. *
function _closeWithSwap(bytes32 loanId, address receiver, uint256 swapAmount, bool returnTokenIsCollateral, bytes loanDataBytes) internal nonpayable
returns(loanCloseAmount uint256, withdrawAmount uint256, withdrawToken address)
Arguments
Name | Type | Description |
---|---|---|
loanId | bytes32 | The id of the loan. |
receiver | address | The receiver of the remainder (unused collatral + profit). |
swapAmount | uint256 | Defines how much of the position should be closed and is denominated in collateral tokens. If swapAmount >= collateral, the complete position will be closed. Else if returnTokenIsCollateral, (swapAmount/collateral) * principal will be swapped (partial closure). Else coveredPrincipal |
returnTokenIsCollateral | bool | Defines if the remainder should be paid out in collateral tokens or underlying loan tokens. * |
loanDataBytes | bytes |
Returns
loanCloseAmount The amount of the collateral token of the loan.
Source Code
function _closeWithSwap(
bytes32 loanId,
address receiver,
uint256 swapAmount,
bool returnTokenIsCollateral,
bytes memory loanDataBytes
)
internal
returns (
uint256 loanCloseAmount,
uint256 withdrawAmount,
address withdrawToken
)
{
require(swapAmount != 0, "swapAmount == 0");
(Loan storage loanLocal, LoanParams storage loanParamsLocal) = _checkLoan(loanId);
/// Can't swap more than collateral.
swapAmount = swapAmount > loanLocal.collateral ? loanLocal.collateral : swapAmount;
//close whole loan if tiny position will remain
if (loanLocal.collateral - swapAmount > 0) {
if (
_getAmountInRbtc(
loanParamsLocal.collateralToken,
loanLocal.collateral - swapAmount
) <= TINY_AMOUNT
) {
swapAmount = loanLocal.collateral;
}
}
uint256 loanCloseAmountLessInterest;
if (swapAmount == loanLocal.collateral || returnTokenIsCollateral) {
/// loanCloseAmountLessInterest will be passed as required amount amount of destination tokens.
/// this means, the actual swapAmount passed to the swap contract does not matter at all.
/// the source token amount will be computed depending on the required amount amount of destination tokens.
loanCloseAmount = swapAmount == loanLocal.collateral
? loanLocal.principal
: loanLocal.principal.mul(swapAmount).div(loanLocal.collateral);
require(loanCloseAmount != 0, "loanCloseAmount == 0");
/// Computes the interest refund for the borrower and sends it to the lender to cover part of the principal.
loanCloseAmountLessInterest = _settleInterestToPrincipal(
loanLocal,
loanParamsLocal,
loanCloseAmount,
receiver
);
} else {
/// loanCloseAmount is calculated after swap; for this case we want to swap the entire source amount
/// and determine the loanCloseAmount and withdraw amount based on that.
loanCloseAmountLessInterest = 0;
}
uint256 coveredPrincipal;
uint256 usedCollateral;
/// swapAmount repurposed for collateralToLoanSwapRate to avoid stack too deep error.
(coveredPrincipal, usedCollateral, withdrawAmount, swapAmount) = _coverPrincipalWithSwap(
loanLocal,
loanParamsLocal,
swapAmount, /// The amount of source tokens to swap (only matters if !returnTokenIsCollateral or loanCloseAmountLessInterest = 0)
loanCloseAmountLessInterest, /// This is the amount of destination tokens we want to receive (only matters if returnTokenIsCollateral)
returnTokenIsCollateral,
loanDataBytes
);
if (loanCloseAmountLessInterest == 0) {
/// Condition prior to swap: swapAmount != loanLocal.collateral && !returnTokenIsCollateral
/// Amounts that is closed.
loanCloseAmount = coveredPrincipal;
if (coveredPrincipal != loanLocal.principal) {
loanCloseAmount = loanCloseAmount.mul(usedCollateral).div(loanLocal.collateral);
}
require(loanCloseAmount != 0, "loanCloseAmount == 0");
/// Amount that is returned to the lender.
loanCloseAmountLessInterest = _settleInterestToPrincipal(
loanLocal,
loanParamsLocal,
loanCloseAmount,
receiver
);
/// Remaining amount withdrawn to the receiver.
withdrawAmount = withdrawAmount.add(coveredPrincipal).sub(loanCloseAmountLessInterest);
} else {
/// Pay back the amount which was covered by the swap.
loanCloseAmountLessInterest = coveredPrincipal;
}
require(loanCloseAmountLessInterest != 0, "closeAmount is 0 after swap");
/// Reduce the collateral by the amount which was swapped for the closure.
if (usedCollateral != 0) {
loanLocal.collateral = loanLocal.collateral.sub(usedCollateral);
}
/// Repays principal to lender.
/// The lender always gets back an ERC20 (even wrbtc), so we call
/// withdraw directly rather than use the _withdrawAsset helper function.
vaultWithdraw(loanParamsLocal.loanToken, loanLocal.lender, loanCloseAmountLessInterest);
withdrawToken = returnTokenIsCollateral
? loanParamsLocal.collateralToken
: loanParamsLocal.loanToken;
if (withdrawAmount != 0) {
_withdrawAsset(withdrawToken, receiver, withdrawAmount);
}
_finalizeClose(
loanLocal,
loanParamsLocal,
loanCloseAmount,
usedCollateral,
swapAmount, /// collateralToLoanSwapRate
CloseTypes.Swap
);
}
Close a loan. *
function _finalizeClose(struct LoanStruct.Loan loanLocal, struct LoanParamsStruct.LoanParams loanParamsLocal, uint256 loanCloseAmount, uint256 collateralCloseAmount, uint256 collateralToLoanSwapRate, enum LoanClosingsShared.CloseTypes closeType) internal nonpayable
Arguments
Name | Type | Description |
---|---|---|
loanLocal | struct LoanStruct.Loan | The loan object. |
loanParamsLocal | struct LoanParamsStruct.LoanParams | The loan params. |
loanCloseAmount | uint256 | The amount to close: principal or lower. |
collateralCloseAmount | uint256 | The amount of collateral to close. |
collateralToLoanSwapRate | uint256 | The price rate collateral/loan token. |
closeType | enum LoanClosingsShared.CloseTypes | The type of loan close. |
Source Code
function _finalizeClose(
Loan storage loanLocal,
LoanParams storage loanParamsLocal,
uint256 loanCloseAmount,
uint256 collateralCloseAmount,
uint256 collateralToLoanSwapRate,
CloseTypes closeType
) internal {
_closeLoan(loanLocal, loanCloseAmount);
address _priceFeeds = priceFeeds;
uint256 currentMargin;
uint256 collateralToLoanRate;
/// This is still called even with full loan close to return collateralToLoanRate
(bool success, bytes memory data) =
_priceFeeds.staticcall(
abi.encodeWithSelector(
IPriceFeeds(_priceFeeds).getCurrentMargin.selector,
loanParamsLocal.loanToken,
loanParamsLocal.collateralToken,
loanLocal.principal,
loanLocal.collateral
)
);
assembly {
if eq(success, 1) {
currentMargin := mload(add(data, 32))
collateralToLoanRate := mload(add(data, 64))
}
}
/// Note: We can safely skip the margin check if closing
/// via closeWithDeposit or if closing the loan in full by any method.
require(
closeType == CloseTypes.Deposit ||
loanLocal.principal == 0 || /// loan fully closed
currentMargin > loanParamsLocal.maintenanceMargin,
"unhealthy position"
);
_emitClosingEvents(
loanParamsLocal,
loanLocal,
loanCloseAmount,
collateralCloseAmount,
collateralToLoanRate,
collateralToLoanSwapRate,
currentMargin,
closeType
);
}
Swaps a share of a loan's collateral or the complete collateral in order to cover the principle. *
function _coverPrincipalWithSwap(struct LoanStruct.Loan loanLocal, struct LoanParamsStruct.LoanParams loanParamsLocal, uint256 swapAmount, uint256 principalNeeded, bool returnTokenIsCollateral, bytes loanDataBytes) internal nonpayable
returns(coveredPrincipal uint256, usedCollateral uint256, withdrawAmount uint256, collateralToLoanSwapRate uint256)
Arguments
Name | Type | Description |
---|---|---|
loanLocal | struct LoanStruct.Loan | the loan |
loanParamsLocal | struct LoanParamsStruct.LoanParams | the loan parameters |
swapAmount | uint256 | in case principalNeeded == 0 or !returnTokenIsCollateral, this is the amount which is going to be swapped. Else, swapAmount doesn't matter, because the amount of source tokens needed for the swap is estimated by the connector. |
principalNeeded | uint256 | the required amount of destination tokens in order to cover the principle (only used if returnTokenIsCollateral) |
returnTokenIsCollateral | bool | tells if the user wants to withdraw his remaining collateral + profit in collateral tokens |
loanDataBytes | bytes |
Returns
coveredPrincipal The amount of principal that is covered.
Source Code
function _coverPrincipalWithSwap(
Loan memory loanLocal,
LoanParams memory loanParamsLocal,
uint256 swapAmount,
uint256 principalNeeded,
bool returnTokenIsCollateral,
bytes memory loanDataBytes
)
internal
returns (
uint256 coveredPrincipal,
uint256 usedCollateral,
uint256 withdrawAmount,
uint256 collateralToLoanSwapRate
)
{
uint256 destTokenAmountReceived;
uint256 sourceTokenAmountUsed;
(
destTokenAmountReceived,
sourceTokenAmountUsed,
collateralToLoanSwapRate
) = _doCollateralSwap(
loanLocal,
loanParamsLocal,
swapAmount,
principalNeeded,
returnTokenIsCollateral,
loanDataBytes
);
if (returnTokenIsCollateral) {
coveredPrincipal = principalNeeded;
/// Better fill than expected.
if (destTokenAmountReceived > coveredPrincipal) {
/// Send excess to borrower if the amount is big enough to be
/// worth the gas fees.
if (
worthTheTransfer(
loanParamsLocal.loanToken,
destTokenAmountReceived - coveredPrincipal
)
) {
_withdrawAsset(
loanParamsLocal.loanToken,
loanLocal.borrower,
destTokenAmountReceived - coveredPrincipal
);
}
/// Else, give the excess to the lender (if it goes to the
/// borrower, they're very confused. causes more trouble than it's worth)
else {
coveredPrincipal = destTokenAmountReceived;
}
}
withdrawAmount = swapAmount > sourceTokenAmountUsed
? swapAmount - sourceTokenAmountUsed
: 0;
} else {
require(sourceTokenAmountUsed == swapAmount, "swap error");
if (swapAmount == loanLocal.collateral) {
/// sourceTokenAmountUsed == swapAmount == loanLocal.collateral
coveredPrincipal = principalNeeded;
withdrawAmount = destTokenAmountReceived - principalNeeded;
} else {
/// sourceTokenAmountUsed == swapAmount < loanLocal.collateral
if (destTokenAmountReceived >= loanLocal.principal) {
/// Edge case where swap covers full principal.
coveredPrincipal = loanLocal.principal;
withdrawAmount = destTokenAmountReceived - loanLocal.principal;
/// Excess collateral refunds to the borrower.
_withdrawAsset(
loanParamsLocal.collateralToken,
loanLocal.borrower,
loanLocal.collateral - sourceTokenAmountUsed
);
sourceTokenAmountUsed = loanLocal.collateral;
} else {
coveredPrincipal = destTokenAmountReceived;
withdrawAmount = 0;
}
}
}
usedCollateral = sourceTokenAmountUsed > swapAmount ? sourceTokenAmountUsed : swapAmount;
}
function _emitClosingEvents(struct LoanParamsStruct.LoanParams loanParamsLocal, struct LoanStruct.Loan loanLocal, uint256 loanCloseAmount, uint256 collateralCloseAmount, uint256 collateralToLoanRate, uint256 collateralToLoanSwapRate, uint256 currentMargin, enum LoanClosingsShared.CloseTypes closeType) internal nonpayable
Arguments
Name | Type | Description |
---|---|---|
loanParamsLocal | struct LoanParamsStruct.LoanParams | |
loanLocal | struct LoanStruct.Loan | |
loanCloseAmount | uint256 | |
collateralCloseAmount | uint256 | |
collateralToLoanRate | uint256 | |
collateralToLoanSwapRate | uint256 | |
currentMargin | uint256 | |
closeType | enum LoanClosingsShared.CloseTypes |
Source Code
function _emitClosingEvents(
LoanParams memory loanParamsLocal,
Loan memory loanLocal,
uint256 loanCloseAmount,
uint256 collateralCloseAmount,
uint256 collateralToLoanRate,
uint256 collateralToLoanSwapRate,
uint256 currentMargin,
CloseTypes closeType
) internal {
if (closeType == CloseTypes.Deposit) {
emit CloseWithDeposit(
loanLocal.borrower, /// user (borrower)
loanLocal.lender, /// lender
loanLocal.id, /// loanId
msg.sender, /// closer
loanParamsLocal.loanToken, /// loanToken
loanParamsLocal.collateralToken, /// collateralToken
loanCloseAmount, /// loanCloseAmount
collateralCloseAmount, /// collateralCloseAmount
collateralToLoanRate, /// collateralToLoanRate
currentMargin /// currentMargin
);
} else if (closeType == CloseTypes.Swap) {
/// exitPrice = 1 / collateralToLoanSwapRate
if (collateralToLoanSwapRate != 0) {
collateralToLoanSwapRate = SafeMath.div(10**36, collateralToLoanSwapRate);
}
/// currentLeverage = 100 / currentMargin
if (currentMargin != 0) {
currentMargin = SafeMath.div(10**38, currentMargin);
}
emit CloseWithSwap(
loanLocal.borrower, /// user (trader)
loanLocal.lender, /// lender
loanLocal.id, /// loanId
loanParamsLocal.collateralToken, /// collateralToken
loanParamsLocal.loanToken, /// loanToken
msg.sender, /// closer
collateralCloseAmount, /// positionCloseSize
loanCloseAmount, /// loanCloseAmount
collateralToLoanSwapRate, /// exitPrice (1 / collateralToLoanSwapRate)
currentMargin /// currentLeverage
);
} else if (closeType == CloseTypes.Liquidation) {
emit Liquidate(
loanLocal.borrower, // user (borrower)
msg.sender, // liquidator
loanLocal.id, // loanId
loanLocal.lender, // lender
loanParamsLocal.loanToken, // loanToken
loanParamsLocal.collateralToken, // collateralToken
loanCloseAmount, // loanCloseAmount
collateralCloseAmount, // collateralCloseAmount
collateralToLoanRate, // collateralToLoanRate
currentMargin // currentMargin
);
}
}
returns amount of the asset converted to RBTC
function _getAmountInRbtc(address asset, uint256 amount) internal view
returns(uint256)
Arguments
Name | Type | Description |
---|---|---|
asset | address | the asset to be transferred |
amount | uint256 | the amount to be transferred |
Returns
amount in RBTC
Source Code
function _getAmountInRbtc(address asset, uint256 amount) internal view returns (uint256) {
(uint256 rbtcRate, uint256 rbtcPrecision) =
IPriceFeeds(priceFeeds).queryRate(asset, address(wrbtcToken));
return amount.mul(rbtcRate).div(rbtcPrecision);
}
private function which check the loanLocal & loanParamsLocal does exist *
function _checkLoan(bytes32 loanId) internal view
returns(struct LoanStruct.Loan, struct LoanParamsStruct.LoanParams)
Arguments
Name | Type | Description |
---|---|---|
loanId | bytes32 | bytes32 of loanId * |
Returns
Loan storage
Source Code
function _checkLoan(bytes32 loanId) internal view returns (Loan storage, LoanParams storage) {
Loan storage loanLocal = loans[loanId];
LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];
require(loanLocal.active, "loan is closed");
require(loanParamsLocal.id != 0, "loanParams not exists");
return (loanLocal, loanParamsLocal);
}
- Address
- Administered
- AdminRole
- AdvancedToken
- AdvancedTokenStorage
- Affiliates
- AffiliatesEvents
- ApprovalReceiver
- BProPriceFeed
- CheckpointsShared
- Constants
- Context
- DevelopmentFund
- DummyContract
- EnumerableAddressSet
- EnumerableBytes32Set
- EnumerableBytes4Set
- ERC20
- ERC20Detailed
- ErrorDecoder
- Escrow
- EscrowReward
- FeedsLike
- FeesEvents
- FeeSharingCollector
- FeeSharingCollectorProxy
- FeeSharingCollectorStorage
- FeesHelper
- FourYearVesting
- FourYearVestingFactory
- FourYearVestingLogic
- FourYearVestingStorage
- GenericTokenSender
- GovernorAlpha
- GovernorVault
- IApproveAndCall
- IChai
- IContractRegistry
- IConverterAMM
- IERC1820Registry
- IERC20_
- IERC20
- IERC777
- IERC777Recipient
- IERC777Sender
- IFeeSharingCollector
- IFourYearVesting
- IFourYearVestingFactory
- IFunctionsList
- ILiquidityMining
- ILiquidityPoolV1Converter
- ILoanPool
- ILoanToken
- ILoanTokenLogicBeacon
- ILoanTokenLogicModules
- ILoanTokenLogicProxy
- ILoanTokenModules
- ILoanTokenWRBTC
- ILockedSOV
- IMoCState
- IModulesProxyRegistry
- Initializable
- InterestUser
- IPot
- IPriceFeeds
- IPriceFeedsExt
- IProtocol
- IRSKOracle
- ISovryn
- ISovrynSwapNetwork
- IStaking
- ISwapsImpl
- ITeamVesting
- ITimelock
- IV1PoolOracle
- IVesting
- IVestingFactory
- IVestingRegistry
- IWrbtc
- IWrbtcERC20
- LenderInterestStruct
- LiquidationHelper
- LiquidityMining
- LiquidityMiningConfigToken
- LiquidityMiningProxy
- LiquidityMiningStorage
- LoanClosingsEvents
- LoanClosingsLiquidation
- LoanClosingsRollover
- LoanClosingsShared
- LoanClosingsWith
- LoanClosingsWithoutInvariantCheck
- LoanInterestStruct
- LoanMaintenance
- LoanMaintenanceEvents
- LoanOpenings
- LoanOpeningsEvents
- LoanParamsStruct
- LoanSettings
- LoanSettingsEvents
- LoanStruct
- LoanToken
- LoanTokenBase
- LoanTokenLogicBeacon
- LoanTokenLogicLM
- LoanTokenLogicProxy
- LoanTokenLogicStandard
- LoanTokenLogicStorage
- LoanTokenLogicWrbtc
- LoanTokenSettingsLowerAdmin
- LockedSOV
- MarginTradeStructHelpers
- Medianizer
- ModuleCommonFunctionalities
- ModulesCommonEvents
- ModulesProxy
- ModulesProxyRegistry
- MultiSigKeyHolders
- MultiSigWallet
- Mutex
- Objects
- OrderStruct
- OrigingVestingCreator
- OriginInvestorsClaim
- Ownable
- Pausable
- PausableOz
- PreviousLoanToken
- PreviousLoanTokenSettingsLowerAdmin
- PriceFeedRSKOracle
- PriceFeeds
- PriceFeedsLocal
- PriceFeedsMoC
- PriceFeedV1PoolOracle
- ProtocolAffiliatesInterface
- ProtocolLike
- ProtocolSettings
- ProtocolSettingsEvents
- ProtocolSettingsLike
- ProtocolSwapExternalInterface
- ProtocolTokenUser
- Proxy
- ProxyOwnable
- ReentrancyGuard
- RewardHelper
- RSKAddrValidator
- SafeERC20
- SafeMath
- SafeMath96
- setGet
- SharedReentrancyGuard
- SignedSafeMath
- SOV
- sovrynProtocol
- StakingAdminModule
- StakingGovernanceModule
- StakingInterface
- StakingProxy
- StakingRewards
- StakingRewardsProxy
- StakingRewardsStorage
- StakingShared
- StakingStakeModule
- StakingStorageModule
- StakingStorageShared
- StakingVestingModule
- StakingWithdrawModule
- State
- SwapsEvents
- SwapsExternal
- SwapsImplLocal
- SwapsImplSovrynSwap
- SwapsUser
- TeamVesting
- Timelock
- TimelockHarness
- TimelockInterface
- TokenSender
- UpgradableProxy
- USDTPriceFeed
- Utils
- VaultController
- Vesting
- VestingCreator
- VestingFactory
- VestingLogic
- VestingRegistry
- VestingRegistry2
- VestingRegistry3
- VestingRegistryLogic
- VestingRegistryProxy
- VestingRegistryStorage
- VestingStorage
- WeightedStakingModule
- WRBTC