- (LoanMaintenance.sol)
View Source: contracts/modules/LoanMaintenance.sol
↗ Extends: LoanOpeningsEvents, LoanMaintenanceEvents, VaultController, InterestUser, SwapsUser, LiquidationHelper, ModuleCommonFunctionalities
This contract code comes from bZx. bZx is a protocol for tokenized margin trading and lending https://bzx.network similar to the dYdX protocol.
- This contract contains functions to query loan data and to modify its status by withdrawing or depositing collateral.
struct LoanReturnData {
bytes32 loanId,
address loanToken,
address collateralToken,
uint256 principal,
uint256 collateral,
uint256 interestOwedPerDay,
uint256 interestDepositRemaining,
uint256 startRate,
uint256 startMargin,
uint256 maintenanceMargin,
uint256 currentMargin,
uint256 maxLoanTerm,
uint256 endTimestamp,
uint256 maxLiquidatable,
uint256 maxSeizable
}
struct LoanReturnDataV2 {
bytes32 loanId,
address loanToken,
address collateralToken,
address borrower,
uint256 principal,
uint256 collateral,
uint256 interestOwedPerDay,
uint256 interestDepositRemaining,
uint256 startRate,
uint256 startMargin,
uint256 maintenanceMargin,
uint256 currentMargin,
uint256 maxLoanTerm,
uint256 endTimestamp,
uint256 maxLiquidatable,
uint256 maxSeizable,
uint256 creationTimestamp
}
- constructor()
- constructor()
- initialize(address target)
- depositCollateral(bytes32 loanId, uint256 depositAmount)
- withdrawCollateral(bytes32 loanId, address receiver, uint256 withdrawAmount)
- withdrawAccruedInterest(address loanToken)
- extendLoanDuration(bytes32 loanId, uint256 depositAmount, bool useCollateral, bytes )
- reduceLoanDuration(bytes32 loanId, address receiver, uint256 withdrawAmount)
- getLenderInterestData(address lender, address loanToken)
- getLoanInterestData(bytes32 loanId)
- getUserLoans(address user, uint256 start, uint256 count, uint256 loanType, bool isLender, bool unsafeOnly)
- getUserLoansV2(address user, uint256 start, uint256 count, uint256 loanType, bool isLender, bool unsafeOnly)
- getLoan(bytes32 loanId)
- getLoanV2(bytes32 loanId)
- getActiveLoans(uint256 start, uint256 count, bool unsafeOnly)
- getActiveLoansV2(uint256 start, uint256 count, bool unsafeOnly)
- _getLoan(bytes32 loanId, uint256 loanType, bool unsafeOnly)
- _getLoanV2(bytes32 loanId, uint256 loanType, bool unsafeOnly)
- _doCollateralSwap(struct LoanStruct.Loan loanLocal, struct LoanParamsStruct.LoanParams loanParamsLocal, uint256 depositAmount)
Empty public constructor.
function () public nonpayable
Source Code
constructor() public {}
Fallback function is to react to receiving value (rBTC).
function () external nonpayable
Source Code
function() external {
revert("fallback not allowed");
}
Set initial values of proxy targets. *
function initialize(address target) external nonpayable onlyOwner
Arguments
Name | Type | Description |
---|---|---|
target | address | The address of the logic contract instance. |
Source Code
function initialize(address target) external onlyOwner {
address prevModuleContractAddress = logicTargets[this.depositCollateral.selector];
_setTarget(this.depositCollateral.selector, target);
_setTarget(this.withdrawCollateral.selector, target);
_setTarget(this.withdrawAccruedInterest.selector, target);
_setTarget(this.extendLoanDuration.selector, target);
_setTarget(this.reduceLoanDuration.selector, target);
_setTarget(this.getLenderInterestData.selector, target);
_setTarget(this.getLoanInterestData.selector, target);
_setTarget(this.getUserLoans.selector, target);
_setTarget(this.getUserLoansV2.selector, target);
_setTarget(this.getLoan.selector, target);
_setTarget(this.getLoanV2.selector, target);
_setTarget(this.getActiveLoans.selector, target);
_setTarget(this.getActiveLoansV2.selector, target);
emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, "LoanMaintenance");
}
Increase the margin of a position by depositing additional collateral. *
function depositCollateral(bytes32 loanId, uint256 depositAmount) external payable nonReentrant whenNotPaused
Arguments
Name | Type | Description |
---|---|---|
loanId | bytes32 | A unique ID representing the loan. |
depositAmount | uint256 | The amount to be deposited in collateral tokens. * |
Returns
actualWithdrawAmount The amount withdrawn taking into account drawdowns.
Source Code
function depositCollateral(
bytes32 loanId,
uint256 depositAmount /// must match msg.value if ether is sent
) external payable nonReentrant whenNotPaused {
require(depositAmount != 0, "depositAmount is 0");
Loan storage loanLocal = loans[loanId];
LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];
require(loanLocal.active, "loan is closed");
require(
msg.value == 0 || loanParamsLocal.collateralToken == address(wrbtcToken),
"wrong asset sent"
);
loanLocal.collateral = loanLocal.collateral.add(depositAmount);
if (msg.value == 0) {
vaultDeposit(loanParamsLocal.collateralToken, msg.sender, depositAmount);
} else {
require(msg.value == depositAmount, "ether deposit mismatch");
vaultEtherDeposit(msg.sender, msg.value);
}
(uint256 collateralToLoanRate, ) =
IPriceFeeds(priceFeeds).queryRate(
loanParamsLocal.collateralToken,
loanParamsLocal.loanToken
);
emit DepositCollateral(loanId, depositAmount, collateralToLoanRate);
}
Withdraw from the collateral. This reduces the margin of a position. *
function withdrawCollateral(bytes32 loanId, address receiver, uint256 withdrawAmount) external nonpayable nonReentrant whenNotPaused
returns(actualWithdrawAmount uint256)
Arguments
Name | Type | Description |
---|---|---|
loanId | bytes32 | A unique ID representing the loan. |
receiver | address | The account getting the withdrawal. |
withdrawAmount | uint256 | The amount to be withdrawn in collateral tokens. * |
Returns
actualWithdrawAmount The amount withdrawn taking into account drawdowns.
Source Code
function withdrawCollateral(
bytes32 loanId,
address receiver,
uint256 withdrawAmount
) external nonReentrant whenNotPaused returns (uint256 actualWithdrawAmount) {
require(withdrawAmount != 0, "withdrawAmount is 0");
Loan storage loanLocal = loans[loanId];
LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];
require(loanLocal.active, "loan is closed");
require(
msg.sender == loanLocal.borrower || delegatedManagers[loanLocal.id][msg.sender],
"unauthorized"
);
uint256 maxDrawdown =
IPriceFeeds(priceFeeds).getMaxDrawdown(
loanParamsLocal.loanToken,
loanParamsLocal.collateralToken,
loanLocal.principal,
loanLocal.collateral,
loanParamsLocal.maintenanceMargin
);
if (withdrawAmount > maxDrawdown) {
actualWithdrawAmount = maxDrawdown;
} else {
actualWithdrawAmount = withdrawAmount;
}
loanLocal.collateral = loanLocal.collateral.sub(actualWithdrawAmount);
if (loanParamsLocal.collateralToken == address(wrbtcToken)) {
vaultEtherWithdraw(receiver, actualWithdrawAmount);
} else {
vaultWithdraw(loanParamsLocal.collateralToken, receiver, actualWithdrawAmount);
}
}
Withdraw accrued loan interest. *
function withdrawAccruedInterest(address loanToken) external nonpayable whenNotPaused
Arguments
Name | Type | Description |
---|---|---|
loanToken | address | The loan token address. |
Source Code
function withdrawAccruedInterest(address loanToken) external whenNotPaused {
/// Pay outstanding interest to lender.
_payInterest(
msg.sender, /// Lender.
loanToken
);
}
Extend the loan duration by as much time as depositAmount can buy. *
function extendLoanDuration(bytes32 loanId, uint256 depositAmount, bool useCollateral, bytes ) external payable nonReentrant whenNotPaused
returns(secondsExtended uint256)
Arguments
Name | Type | Description |
---|---|---|
loanId | bytes32 | A unique ID representing the loan. |
depositAmount | uint256 | The amount to be deposited in loan tokens. Used to pay the interest for the new duration. |
useCollateral | bool | Whether pay interests w/ the collateral. If true, depositAmount of loan tokens will be purchased with the collateral. // param calldata The payload for the call. These loan DataBytes are additional loan data (not in use for token swaps). * |
bytes | loanId A unique ID representing the loan. |
Returns
secondsExtended The amount of time in seconds the loan is extended.
Source Code
function extendLoanDuration(
bytes32 loanId,
uint256 depositAmount,
bool useCollateral,
bytes calldata /// loanDataBytes, for future use.
) external payable nonReentrant whenNotPaused returns (uint256 secondsExtended) {
require(depositAmount != 0, "depositAmount is 0");
Loan storage loanLocal = loans[loanId];
LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];
require(loanLocal.active, "loan is closed");
require(
!useCollateral ||
msg.sender == loanLocal.borrower ||
delegatedManagers[loanLocal.id][msg.sender],
"unauthorized"
);
require(loanParamsLocal.maxLoanTerm == 0, "indefinite-term only");
require(
msg.value == 0 || (!useCollateral && loanParamsLocal.loanToken == address(wrbtcToken)),
"wrong asset sent"
);
/// Pay outstanding interest to lender.
_payInterest(loanLocal.lender, loanParamsLocal.loanToken);
LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];
_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,
block.timestamp
);
/// Handle back interest: calculates interest owned since the loan
/// endtime passed but the loan remained open.
uint256 backInterestOwed;
if (block.timestamp > loanLocal.endTimestamp) {
backInterestOwed = block.timestamp.sub(loanLocal.endTimestamp);
backInterestOwed = backInterestOwed.mul(loanInterestLocal.owedPerDay);
backInterestOwed = backInterestOwed.div(86400);
require(depositAmount > backInterestOwed, "deposit cannot cover back interest");
}
/// Deposit interest.
if (useCollateral) {
/// Used the whole converted loanToken to extend the loan duration
depositAmount = _doCollateralSwap(loanLocal, loanParamsLocal, depositAmount);
} else {
if (msg.value == 0) {
vaultDeposit(loanParamsLocal.loanToken, msg.sender, depositAmount);
} else {
require(msg.value == depositAmount, "ether deposit mismatch");
vaultEtherDeposit(msg.sender, msg.value);
}
}
if (backInterestOwed != 0) {
depositAmount = depositAmount.sub(backInterestOwed);
/// Pay out backInterestOwed
_payInterestTransfer(loanLocal.lender, loanParamsLocal.loanToken, backInterestOwed);
}
secondsExtended = depositAmount.mul(86400).div(loanInterestLocal.owedPerDay);
loanLocal.endTimestamp = loanLocal.endTimestamp.add(secondsExtended);
require(loanLocal.endTimestamp > block.timestamp, "loan too short");
uint256 maxDuration = loanLocal.endTimestamp.sub(block.timestamp);
/// Loan term has to at least be greater than one hour.
require(maxDuration > 3600, "loan too short");
loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.add(depositAmount);
lenderInterest[loanLocal.lender][loanParamsLocal.loanToken].owedTotal = lenderInterest[
loanLocal.lender
][loanParamsLocal.loanToken]
.owedTotal
.add(depositAmount);
}
Reduce the loan duration by withdrawing from the deposited interest. *
function reduceLoanDuration(bytes32 loanId, address receiver, uint256 withdrawAmount) external nonpayable nonReentrant whenNotPaused
returns(secondsReduced uint256)
Arguments
Name | Type | Description |
---|---|---|
loanId | bytes32 | A unique ID representing the loan. |
receiver | address | The account getting the withdrawal. |
withdrawAmount | uint256 | The amount to be withdrawn in loan tokens. * |
Returns
secondsReduced The amount of time in seconds the loan is reduced.
Source Code
function reduceLoanDuration(
bytes32 loanId,
address receiver,
uint256 withdrawAmount
) external nonReentrant whenNotPaused returns (uint256 secondsReduced) {
require(withdrawAmount != 0, "withdrawAmount is 0");
Loan storage loanLocal = loans[loanId];
LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];
require(loanLocal.active, "loan is closed");
require(
msg.sender == loanLocal.borrower || delegatedManagers[loanLocal.id][msg.sender],
"unauthorized"
);
require(loanParamsLocal.maxLoanTerm == 0, "indefinite-term only");
require(loanLocal.endTimestamp > block.timestamp, "loan term has ended");
/// Pay outstanding interest to lender.
_payInterest(loanLocal.lender, loanParamsLocal.loanToken);
LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];
_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,
block.timestamp
);
uint256 interestDepositRemaining =
loanLocal.endTimestamp.sub(block.timestamp).mul(loanInterestLocal.owedPerDay).div(
86400
);
require(withdrawAmount < interestDepositRemaining, "withdraw amount too high");
/// Withdraw interest.
if (loanParamsLocal.loanToken == address(wrbtcToken)) {
vaultEtherWithdraw(receiver, withdrawAmount);
} else {
vaultWithdraw(loanParamsLocal.loanToken, receiver, withdrawAmount);
}
secondsReduced = withdrawAmount.mul(86400).div(loanInterestLocal.owedPerDay);
require(loanLocal.endTimestamp > secondsReduced, "loan too short");
loanLocal.endTimestamp = loanLocal.endTimestamp.sub(secondsReduced);
require(loanLocal.endTimestamp > block.timestamp, "loan too short");
uint256 maxDuration = loanLocal.endTimestamp.sub(block.timestamp);
/// Loan term has to at least be greater than one hour.
require(maxDuration > 3600, "loan too short");
loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.sub(withdrawAmount);
lenderInterest[loanLocal.lender][loanParamsLocal.loanToken].owedTotal = lenderInterest[
loanLocal.lender
][loanParamsLocal.loanToken]
.owedTotal
.sub(withdrawAmount);
}
Get current lender interest data totals for all loans with a specific oracle and interest token. *
function getLenderInterestData(address lender, address loanToken) external view
returns(interestPaid uint256, interestPaidDate uint256, interestOwedPerDay uint256, interestUnPaid uint256, interestFeePercent uint256, principalTotal uint256)
Arguments
Name | Type | Description |
---|---|---|
lender | address | The lender address. |
loanToken | address | The loan token address. * |
Returns
interestPaid The total amount of interest that has been paid to a lender so far.
Source Code
function getLenderInterestData(address lender, address loanToken)
external
view
returns (
uint256 interestPaid,
uint256 interestPaidDate,
uint256 interestOwedPerDay,
uint256 interestUnPaid,
uint256 interestFeePercent,
uint256 principalTotal
)
{
LenderInterest memory lenderInterestLocal = lenderInterest[lender][loanToken];
interestUnPaid = block
.timestamp
.sub(lenderInterestLocal.updatedTimestamp)
.mul(lenderInterestLocal.owedPerDay)
.div(86400);
if (interestUnPaid > lenderInterestLocal.owedTotal)
interestUnPaid = lenderInterestLocal.owedTotal;
return (
lenderInterestLocal.paidTotal,
lenderInterestLocal.paidTotal != 0 ? lenderInterestLocal.updatedTimestamp : 0,
lenderInterestLocal.owedPerDay,
lenderInterestLocal.updatedTimestamp != 0 ? interestUnPaid : 0,
lendingFeePercent,
lenderInterestLocal.principalTotal
);
}
Get current interest data for a loan. *
function getLoanInterestData(bytes32 loanId) external view
returns(loanToken address, interestOwedPerDay uint256, interestDepositTotal uint256, interestDepositRemaining uint256)
Arguments
Name | Type | Description |
---|---|---|
loanId | bytes32 | A unique ID representing the loan. * |
Returns
loanToken The loan token that interest is paid in.
Source Code
function getLoanInterestData(bytes32 loanId)
external
view
returns (
address loanToken,
uint256 interestOwedPerDay,
uint256 interestDepositTotal,
uint256 interestDepositRemaining
)
{
loanToken = loanParams[loans[loanId].loanParamsId].loanToken;
interestOwedPerDay = loanInterest[loanId].owedPerDay;
interestDepositTotal = loanInterest[loanId].depositTotal;
uint256 endTimestamp = loans[loanId].endTimestamp;
uint256 interestTime = block.timestamp > endTimestamp ? endTimestamp : block.timestamp;
interestDepositRemaining = endTimestamp > interestTime
? endTimestamp.sub(interestTime).mul(interestOwedPerDay).div(86400)
: 0;
}
Get all user loans. * Only returns data for loans that are active. *
function getUserLoans(address user, uint256 start, uint256 count, uint256 loanType, bool isLender, bool unsafeOnly) external view
returns(loansData struct LoanMaintenance.LoanReturnData[])
Arguments
Name | Type | Description |
---|---|---|
user | address | The user address. |
start | uint256 | The lower loan ID to start with. |
count | uint256 | The maximum number of results. |
loanType | uint256 | The type of loan. loanType 0: all loans. loanType 1: margin trade loans. loanType 2: non-margin trade loans. |
isLender | bool | Whether the user is lender or borrower. |
unsafeOnly | bool | The safe filter (True/False). * |
Returns
loansData The array of loans as query result.
Source Code
function getUserLoans(
address user,
uint256 start,
uint256 count,
uint256 loanType,
bool isLender,
bool unsafeOnly
) external view returns (LoanReturnData[] memory loansData) {
EnumerableBytes32Set.Bytes32Set storage set =
isLender ? lenderLoanSets[user] : borrowerLoanSets[user];
uint256 end = start.add(count).min256(set.length());
if (start >= end) {
return loansData;
}
loansData = new LoanReturnData[](count);
uint256 itemCount;
for (uint256 i = end - start; i > 0; i--) {
if (itemCount == count) {
break;
}
LoanReturnData memory loanData =
_getLoan(
set.get(i + start - 1), /// loanId
loanType,
unsafeOnly
);
if (loanData.loanId == 0) continue;
loansData[itemCount] = loanData;
itemCount++;
}
if (itemCount < count) {
assembly {
mstore(loansData, itemCount)
}
}
}
Get all user loans. * Only returns data for loans that are active. *
function getUserLoansV2(address user, uint256 start, uint256 count, uint256 loanType, bool isLender, bool unsafeOnly) external view
returns(loansDataV2 struct LoanMaintenance.LoanReturnDataV2[])
Arguments
Name | Type | Description |
---|---|---|
user | address | The user address. |
start | uint256 | The lower loan ID to start with. |
count | uint256 | The maximum number of results. |
loanType | uint256 | The type of loan. loanType 0: all loans. loanType 1: margin trade loans. loanType 2: non-margin trade loans. |
isLender | bool | Whether the user is lender or borrower. |
unsafeOnly | bool | The safe filter (True/False). * |
Returns
loansData The array of loans as query result.
Source Code
function getUserLoansV2(
address user,
uint256 start,
uint256 count,
uint256 loanType,
bool isLender,
bool unsafeOnly
) external view returns (LoanReturnDataV2[] memory loansDataV2) {
EnumerableBytes32Set.Bytes32Set storage set =
isLender ? lenderLoanSets[user] : borrowerLoanSets[user];
uint256 end = start.add(count).min256(set.length());
if (start >= end) {
return loansDataV2;
}
loansDataV2 = new LoanReturnDataV2[](count);
uint256 itemCount;
for (uint256 i = end - start; i > 0; i--) {
if (itemCount == count) {
break;
}
LoanReturnDataV2 memory loanDataV2 =
_getLoanV2(
set.get(i + start - 1), /// loanId
loanType,
unsafeOnly
);
if (loanDataV2.loanId == 0) continue;
loansDataV2[itemCount] = loanDataV2;
itemCount++;
}
if (itemCount < count) {
assembly {
mstore(loansDataV2, itemCount)
}
}
}
Get one loan data structure by matching ID. * Wrapper to internal _getLoan call. *
function getLoan(bytes32 loanId) external view
returns(loanData struct LoanMaintenance.LoanReturnData)
Arguments
Name | Type | Description |
---|---|---|
loanId | bytes32 | A unique ID representing the loan. * |
Returns
loansData The data structure w/ loan information.
Source Code
function getLoan(bytes32 loanId) external view returns (LoanReturnData memory loanData) {
return
_getLoan(
loanId,
0, /// loanType
false /// unsafeOnly
);
}
Get one loan data structure by matching ID. * Wrapper to internal _getLoan call. *
function getLoanV2(bytes32 loanId) external view
returns(loanDataV2 struct LoanMaintenance.LoanReturnDataV2)
Arguments
Name | Type | Description |
---|---|---|
loanId | bytes32 | A unique ID representing the loan. * |
Returns
loansData The data structure w/ loan information.
Source Code
function getLoanV2(bytes32 loanId) external view returns (LoanReturnDataV2 memory loanDataV2) {
return
_getLoanV2(
loanId,
0, /// loanType
false /// unsafeOnly
);
}
Get all active loans. *
function getActiveLoans(uint256 start, uint256 count, bool unsafeOnly) external view
returns(loansData struct LoanMaintenance.LoanReturnData[])
Arguments
Name | Type | Description |
---|---|---|
start | uint256 | The lower loan ID to start with. |
count | uint256 | The maximum number of results. |
unsafeOnly | bool | The safe filter (True/False). * |
Returns
loansData The data structure w/ loan information.
Source Code
function getActiveLoans(
uint256 start,
uint256 count,
bool unsafeOnly
) external view returns (LoanReturnData[] memory loansData) {
uint256 end = start.add(count).min256(activeLoansSet.length());
if (start >= end) {
return loansData;
}
loansData = new LoanReturnData[](count);
uint256 itemCount;
for (uint256 i = end - start; i > 0; i--) {
if (itemCount == count) {
break;
}
LoanReturnData memory loanData =
_getLoan(
activeLoansSet.get(i + start - 1), /// loanId
0, /// loanType
unsafeOnly
);
if (loanData.loanId == 0) continue;
loansData[itemCount] = loanData;
itemCount++;
}
if (itemCount < count) {
assembly {
mstore(loansData, itemCount)
}
}
}
New view function which will return the loan data.
function getActiveLoansV2(uint256 start, uint256 count, bool unsafeOnly) external view
returns(loansDataV2 struct LoanMaintenance.LoanReturnDataV2[])
Arguments
Name | Type | Description |
---|---|---|
start | uint256 | The lower loan ID to start with. |
count | uint256 | The maximum number of results. |
unsafeOnly | bool | The safe filter (True/False). * |
Returns
loanData The data structure
Source Code
function getActiveLoansV2(
uint256 start,
uint256 count,
bool unsafeOnly
) external view returns (LoanReturnDataV2[] memory loansDataV2) {
uint256 end = start.add(count).min256(activeLoansSet.length());
if (start >= end) {
return loansDataV2;
}
loansDataV2 = new LoanReturnDataV2[](count);
uint256 itemCount;
for (uint256 i = end - start; i > 0; i--) {
if (itemCount == count) {
break;
}
LoanReturnDataV2 memory loanDataV2 =
_getLoanV2(
activeLoansSet.get(i + start - 1), /// loanId
0, /// loanType
unsafeOnly
);
if (loanDataV2.loanId == 0) continue;
loansDataV2[itemCount] = loanDataV2;
itemCount++;
}
if (itemCount < count) {
assembly {
mstore(loansDataV2, itemCount)
}
}
}
Internal function to get one loan data structure. *
function _getLoan(bytes32 loanId, uint256 loanType, bool unsafeOnly) internal view
returns(loanData struct LoanMaintenance.LoanReturnData)
Arguments
Name | Type | Description |
---|---|---|
loanId | bytes32 | A unique ID representing the loan. |
loanType | uint256 | The type of loan. loanType 0: all loans. loanType 1: margin trade loans. loanType 2: non-margin trade loans. |
unsafeOnly | bool | The safe filter (True/False). * |
Returns
loansData The data structure w/ the loan information.
Source Code
function _getLoan(
bytes32 loanId,
uint256 loanType,
bool unsafeOnly
) internal view returns (LoanReturnData memory loanData) {
Loan memory loanLocal = loans[loanId];
LoanParams memory loanParamsLocal = loanParams[loanLocal.loanParamsId];
if (loanType != 0) {
if (
!((loanType == 1 && loanParamsLocal.maxLoanTerm != 0) ||
(loanType == 2 && loanParamsLocal.maxLoanTerm == 0))
) {
return loanData;
}
}
LoanInterest memory loanInterestLocal = loanInterest[loanId];
(uint256 currentMargin, uint256 collateralToLoanRate) =
IPriceFeeds(priceFeeds).getCurrentMargin(
loanParamsLocal.loanToken,
loanParamsLocal.collateralToken,
loanLocal.principal,
loanLocal.collateral
);
uint256 maxLiquidatable;
uint256 maxSeizable;
if (currentMargin <= loanParamsLocal.maintenanceMargin) {
(maxLiquidatable, maxSeizable, ) = _getLiquidationAmounts(
loanLocal.principal,
loanLocal.collateral,
currentMargin,
loanParamsLocal.maintenanceMargin,
collateralToLoanRate
);
} else if (unsafeOnly) {
return loanData;
}
return
LoanReturnData({
loanId: loanId,
loanToken: loanParamsLocal.loanToken,
collateralToken: loanParamsLocal.collateralToken,
principal: loanLocal.principal,
collateral: loanLocal.collateral,
interestOwedPerDay: loanInterestLocal.owedPerDay,
interestDepositRemaining: loanLocal.endTimestamp >= block.timestamp
? loanLocal
.endTimestamp
.sub(block.timestamp)
.mul(loanInterestLocal.owedPerDay)
.div(86400)
: 0,
startRate: loanLocal.startRate,
startMargin: loanLocal.startMargin,
maintenanceMargin: loanParamsLocal.maintenanceMargin,
currentMargin: currentMargin,
maxLoanTerm: loanParamsLocal.maxLoanTerm,
endTimestamp: loanLocal.endTimestamp,
maxLiquidatable: maxLiquidatable,
maxSeizable: maxSeizable
});
}
Internal function to get one loan data structure v2. *
function _getLoanV2(bytes32 loanId, uint256 loanType, bool unsafeOnly) internal view
returns(loanDataV2 struct LoanMaintenance.LoanReturnDataV2)
Arguments
Name | Type | Description |
---|---|---|
loanId | bytes32 | A unique ID representing the loan. |
loanType | uint256 | The type of loan. loanType 0: all loans. loanType 1: margin trade loans. loanType 2: non-margin trade loans. |
unsafeOnly | bool | The safe filter (True/False). * |
Returns
loansData The data v2 structure w/ the loan information.
Source Code
function _getLoanV2(
bytes32 loanId,
uint256 loanType,
bool unsafeOnly
) internal view returns (LoanReturnDataV2 memory loanDataV2) {
Loan memory loanLocal = loans[loanId];
LoanParams memory loanParamsLocal = loanParams[loanLocal.loanParamsId];
if (loanType != 0) {
if (
!((loanType == 1 && loanParamsLocal.maxLoanTerm != 0) ||
(loanType == 2 && loanParamsLocal.maxLoanTerm == 0))
) {
return loanDataV2;
}
}
LoanInterest memory loanInterestLocal = loanInterest[loanId];
(uint256 currentMargin, uint256 collateralToLoanRate) =
IPriceFeeds(priceFeeds).getCurrentMargin(
loanParamsLocal.loanToken,
loanParamsLocal.collateralToken,
loanLocal.principal,
loanLocal.collateral
);
uint256 maxLiquidatable;
uint256 maxSeizable;
if (currentMargin <= loanParamsLocal.maintenanceMargin) {
(maxLiquidatable, maxSeizable, ) = _getLiquidationAmounts(
loanLocal.principal,
loanLocal.collateral,
currentMargin,
loanParamsLocal.maintenanceMargin,
collateralToLoanRate
);
} else if (unsafeOnly) {
return loanDataV2;
}
return
LoanReturnDataV2({
loanId: loanId,
loanToken: loanParamsLocal.loanToken,
collateralToken: loanParamsLocal.collateralToken,
borrower: loanLocal.borrower,
principal: loanLocal.principal,
collateral: loanLocal.collateral,
interestOwedPerDay: loanInterestLocal.owedPerDay,
interestDepositRemaining: loanLocal.endTimestamp >= block.timestamp
? loanLocal
.endTimestamp
.sub(block.timestamp)
.mul(loanInterestLocal.owedPerDay)
.div(86400)
: 0,
startRate: loanLocal.startRate,
startMargin: loanLocal.startMargin,
maintenanceMargin: loanParamsLocal.maintenanceMargin,
currentMargin: currentMargin,
maxLoanTerm: loanParamsLocal.maxLoanTerm,
endTimestamp: loanLocal.endTimestamp,
maxLiquidatable: maxLiquidatable,
maxSeizable: maxSeizable,
creationTimestamp: loanLocal.startTimestamp
});
}
Internal function to collect interest from the collateral. *
function _doCollateralSwap(struct LoanStruct.Loan loanLocal, struct LoanParamsStruct.LoanParams loanParamsLocal, uint256 depositAmount) internal nonpayable
returns(purchasedLoanToken uint256)
Arguments
Name | Type | Description |
---|---|---|
loanLocal | struct LoanStruct.Loan | The loan object. |
loanParamsLocal | struct LoanParamsStruct.LoanParams | The loan parameters. |
depositAmount | uint256 | The amount of underlying tokens provided on the loan. |
Source Code
function _doCollateralSwap(
Loan storage loanLocal,
LoanParams memory loanParamsLocal,
uint256 depositAmount
) internal returns (uint256 purchasedLoanToken) {
/// Reverts in _loanSwap if amountNeeded can't be bought.
(uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed, ) =
_loanSwap(
loanLocal.id,
loanParamsLocal.collateralToken,
loanParamsLocal.loanToken,
loanLocal.borrower,
loanLocal.collateral, /// minSourceTokenAmount
0, /// maxSourceTokenAmount (0 means minSourceTokenAmount)
depositAmount, /// requiredDestTokenAmount (partial spend of loanLocal.collateral to fill this amount)
true, /// bypassFee
"" /// loanDataBytes
);
loanLocal.collateral = loanLocal.collateral.sub(sourceTokenAmountUsed);
/// Ensure the loan is still healthy.
(uint256 currentMargin, ) =
IPriceFeeds(priceFeeds).getCurrentMargin(
loanParamsLocal.loanToken,
loanParamsLocal.collateralToken,
loanLocal.principal,
loanLocal.collateral
);
require(currentMargin > loanParamsLocal.maintenanceMargin, "unhealthy position");
return destTokenAmountReceived;
}
- 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