From 95362ea2b435ae16b6cd6add73eadae30fdb2536 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20P=C3=A9rez=20Sacrist=C3=A1n?= Date: Fri, 30 Apr 2021 14:02:46 +0200 Subject: [PATCH] Completed LoanOpenings. Modules is work in progress --- contracts/modules/LoanOpenings.sol | 391 ++++++++++++++++++++++------- 1 file changed, 304 insertions(+), 87 deletions(-) diff --git a/contracts/modules/LoanOpenings.sol b/contracts/modules/LoanOpenings.sol index 46a76cae8..f91afbf72 100644 --- a/contracts/modules/LoanOpenings.sol +++ b/contracts/modules/LoanOpenings.sol @@ -12,13 +12,27 @@ import "../mixins/VaultController.sol"; import "../mixins/InterestUser.sol"; import "../swaps/SwapsUser.sol"; +/** + * @title Loan Openings contract. + * + * @notice 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 borrow and trade. + * */ contract LoanOpenings is LoanOpeningsEvents, VaultController, InterestUser, SwapsUser { constructor() public {} + /** + * @notice Fallback function is to react to receiving value (rBTC). + * */ function() external { revert("fallback not allowed"); } + /** + * @notice Set function selectors on target contract. + * */ function initialize(address target) external onlyOwner { _setTarget(this.borrowOrTradeFromPool.selector, target); _setTarget(this.setDelegatedManager.selector, target); @@ -27,34 +41,52 @@ contract LoanOpenings is LoanOpeningsEvents, VaultController, InterestUser, Swap _setTarget(this.getBorrowAmount.selector, target); } - // Note: Only callable by loan pools (iTokens) + /** + * @notice Borrow or trade from pool. + * + * @dev Note: Only callable by loan pools (iTokens). + * Wrapper to _borrowOrTrade internal function. + * + * @param loanParamsId The ID of the loan parameters. + * @param loanId The ID of the loan. If 0, start a new loan. + * @param isTorqueLoan Whether the loan is a Torque loan. + * @param initialMargin The initial amount of margin. + * @param sentAddresses The addresses to send tokens: lender, borrower, + * receiver and manager: + * lender: must match loan if loanId provided. + * borrower: must match loan if loanId provided. + * receiver: receiver of funds (address(0) assumes borrower address). + * manager: delegated manager of loan unless address(0). + * @param sentValues The values to send: + * newRate: New loan interest rate. + * newPrincipal: New loan size (borrowAmount + any borrowed interest). + * torqueInterest: New amount of interest to escrow for Torque loan (determines initial loan length). + * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans). + * collateralTokenReceived: Total collateralToken deposit. + * @param loanDataBytes The payload for the call. These loan DataBytes are + * additional loan data (not in use for token swaps). + * + * @return newPrincipal The new loan size. + * @return newCollateral The new collateral amount. + * */ function borrowOrTradeFromPool( bytes32 loanParamsId, - bytes32 loanId, // if 0, start a new loan + bytes32 loanId, bool isTorqueLoan, uint256 initialMargin, address[4] calldata sentAddresses, - // lender: must match loan if loanId provided - // borrower: must match loan if loanId provided - // receiver: receiver of funds (address(0) assumes borrower address) - // manager: delegated manager of loan unless address(0) uint256[5] calldata sentValues, - // newRate: new loan interest rate - // newPrincipal: new loan size (borrowAmount + any borrowed interest) - // torqueInterest: new amount of interest to escrow for Torque loan (determines initial loan length) - // loanTokenReceived: total loanToken deposit (amount not sent to borrower in the case of Torque loans) - // collateralTokenReceived: total collateralToken deposit bytes calldata loanDataBytes ) external payable nonReentrant returns (uint256 newPrincipal, uint256 newCollateral) { require(msg.value == 0 || loanDataBytes.length != 0, "loanDataBytes required with ether"); - // only callable by loan pools + /// Only callable by loan pools. require(loanPoolToUnderlying[msg.sender] != address(0), "not authorized"); LoanParams memory loanParamsLocal = loanParams[loanParamsId]; require(loanParamsLocal.id != 0, "loanParams not exists"); - // get required collateral + /// Get required collateral. uint256 collateralAmountRequired = _getRequiredCollateral(loanParamsLocal.loanToken, loanParamsLocal.collateralToken, sentValues[1], initialMargin, isTorqueLoan); require(collateralAmountRequired != 0, "collateral is 0"); @@ -72,6 +104,15 @@ contract LoanOpenings is LoanOpeningsEvents, VaultController, InterestUser, Swap ); } + /** + * @notice Set the delegated manager. + * + * @dev Wrapper for _setDelegatedManager internal function. + * + * @param loanId The ID of the loan. If 0, start a new loan. + * @param delegated The address of the delegated manager. + * @param toggle The flag true/false for the delegated manager. + * */ function setDelegatedManager( bytes32 loanId, address delegated, @@ -82,6 +123,24 @@ contract LoanOpenings is LoanOpeningsEvents, VaultController, InterestUser, Swap _setDelegatedManager(loanId, msg.sender, delegated, toggle); } + /** + * @notice Get the estimated margin exposure. + * + * Margin is the money borrowed from a broker to purchase an investment + * and is the difference between the total value of investment and the + * loan amount. Margin trading refers to the practice of using borrowed + * funds from a broker to trade a financial asset, which forms the + * collateral for the loan from the broker. + * + * @param loanToken The loan token instance address. + * @param collateralToken The collateral token instance address. + * @param loanTokenSent The amount of loan tokens sent. + * @param collateralTokenSent The amount of collateral tokens sent. + * @param interestRate The interest rate. Percentage w/ 18 decimals. + * @param newPrincipal The updated amount of principal (current debt). + * + * @return The margin exposure. + * */ function getEstimatedMarginExposure( address loanToken, address collateralToken, @@ -110,6 +169,19 @@ contract LoanOpenings is LoanOpeningsEvents, VaultController, InterestUser, Swap } } + /** + * @notice Get the required collateral. + * + * @dev Calls internal _getRequiredCollateral and add fees. + * + * @param loanToken The loan token instance address. + * @param collateralToken The collateral token instance address. + * @param newPrincipal The updated amount of principal (current debt). + * @param marginAmount The amount of margin of the trade. + * @param isTorqueLoan Whether the loan is a Torque loan. + * + * @return collateralAmountRequired The required collateral. + * */ function getRequiredCollateral( address loanToken, address collateralToken, @@ -127,6 +199,23 @@ contract LoanOpenings is LoanOpeningsEvents, VaultController, InterestUser, Swap } } + /** + * @notice Get the borrow amount of a trade loan. + * + * @dev Basically borrowAmount = collateral / marginAmount + * + * Collateral is something that helps secure a loan. When you borrow money, + * you agree that your lender can take something and sell it to get their + * money back if you fail to repay the loan. That's the collateral. + * + * @param loanToken The loan token instance address. + * @param collateralToken The collateral token instance address. + * @param collateralTokenAmount The amount of collateral. + * @param marginAmount The amount of margin of the trade. + * @param isTorqueLoan Whether the loan is a Torque loan. + * + * @return borrowAmount The borrow amount. + * */ function getBorrowAmount( address loanToken, address collateralToken, @@ -136,7 +225,7 @@ contract LoanOpenings is LoanOpeningsEvents, VaultController, InterestUser, Swap ) public view returns (uint256 borrowAmount) { if (marginAmount != 0) { if (isTorqueLoan) { - marginAmount = marginAmount.add(10**20); // adjust for over-collateralized loan + marginAmount = marginAmount.add(10**20); /// Adjust for over-collateralized loan. } uint256 collateral = collateralTokenAmount; @@ -156,48 +245,65 @@ contract LoanOpenings is LoanOpeningsEvents, VaultController, InterestUser, Swap } } + /** + * @notice Borrow or trade. + * + * @param loanParamsLocal The loan parameters. + * @param loanId The ID of the loan. If 0, start a new loan. + * @param isTorqueLoan Whether the loan is a Torque loan. + * @param collateralAmountRequired The required amount of collateral. + * @param initialMargin The initial amount of margin. + * @param sentAddresses The addresses to send tokens: lender, borrower, + * receiver and manager: + * lender: must match loan if loanId provided. + * borrower: must match loan if loanId provided. + * receiver: receiver of funds (address(0) assumes borrower address). + * manager: delegated manager of loan unless address(0). + * @param sentValues The values to send: + * newRate: New loan interest rate. + * newPrincipal: New loan size (borrowAmount + any borrowed interest). + * torqueInterest: New amount of interest to escrow for Torque loan (determines initial loan length). + * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans). + * collateralTokenReceived: Total collateralToken deposit. + * @param loanDataBytes The payload for the call. These loan DataBytes are + * additional loan data (not in use for token swaps). + * + * @return The new loan size. + * @return The new collateral amount. + * */ function _borrowOrTrade( LoanParams memory loanParamsLocal, - bytes32 loanId, // if 0, start a new loan + bytes32 loanId, bool isTorqueLoan, uint256 collateralAmountRequired, uint256 initialMargin, address[4] memory sentAddresses, - // lender: must match loan if loanId provided - // borrower: must match loan if loanId provided - // receiver: receiver of funds (address(0) assumes borrower address) - // manager: delegated manager of loan unless address(0) uint256[5] memory sentValues, - // newRate: new loan interest rate - // newPrincipal: new loan size (borrowAmount + any borrowed interest) - // torqueInterest: new amount of interest to escrow for Torque loan (determines initial loan length) - // loanTokenReceived: total loanToken deposit - // collateralTokenReceived: total collateralToken deposit bytes memory loanDataBytes ) internal returns (uint256, uint256) { require(loanParamsLocal.collateralToken != loanParamsLocal.loanToken, "collateral/loan match"); require(initialMargin >= loanParamsLocal.minInitialMargin, "initialMargin too low"); - // maxLoanTerm == 0 indicates a Torqueloan and requres that torqueInterest != 0 + /// maxLoanTerm == 0 indicates a Torque loan and requires that torqueInterest != 0 require( - loanParamsLocal.maxLoanTerm != 0 || sentValues[2] != 0, // torqueInterest + loanParamsLocal.maxLoanTerm != 0 || sentValues[2] != 0, /// torqueInterest "invalid interest" ); - // initialize loan + /// Initialize loan. Loan storage loanLocal = loans[_initializeLoan(loanParamsLocal, loanId, initialMargin, sentAddresses, sentValues)]; - // get required interest + // Get required interest. uint256 amount = _initializeInterest( loanParamsLocal, loanLocal, - sentValues[0], // newRate - sentValues[1], // newPrincipal, - sentValues[2] // torqueInterest + sentValues[0], /// newRate + sentValues[1], /// newPrincipal, + sentValues[2] /// torqueInterest ); - // substract out interest from usable loanToken sent + /// substract out interest from usable loanToken sent. sentValues[3] = sentValues[3].sub(amount); if (isTorqueLoan) { @@ -206,35 +312,35 @@ contract LoanOpenings is LoanOpeningsEvents, VaultController, InterestUser, Swap uint256 borrowingFee = _getBorrowingFee(sentValues[4]); if (borrowingFee != 0) { _payBorrowingFee( - sentAddresses[1], // borrower + sentAddresses[1], /// borrower loanLocal.id, loanParamsLocal.collateralToken, borrowingFee ); - sentValues[4] = sentValues[4] // collateralTokenReceived + sentValues[4] = sentValues[4] /// collateralTokenReceived .sub(borrowingFee); } } else { - // update collateral after trade - // sentValues[3] is repurposed to hold loanToCollateralSwapRate to avoid stack too deep error + /// Update collateral after trade. + /// sentValues[3] is repurposed to hold loanToCollateralSwapRate to avoid stack too deep error. uint256 receivedAmount; (receivedAmount, , sentValues[3]) = _loanSwap( loanId, loanParamsLocal.loanToken, loanParamsLocal.collateralToken, - sentAddresses[1], // borrower - sentValues[3], // loanTokenUsable (minSourceTokenAmount) - 0, // maxSourceTokenAmount (0 means minSourceTokenAmount) - 0, // requiredDestTokenAmount (enforces that all of loanTokenUsable is swapped) - false, // bypassFee + sentAddresses[1], /// borrower + sentValues[3], /// loanTokenUsable (minSourceTokenAmount) + 0, /// maxSourceTokenAmount (0 means minSourceTokenAmount) + 0, /// requiredDestTokenAmount (enforces that all of loanTokenUsable is swapped) + false, /// bypassFee loanDataBytes ); - sentValues[4] = sentValues[4] // collateralTokenReceived + sentValues[4] = sentValues[4] /// collateralTokenReceived .add(receivedAmount); } - // settle collateral + /// Settle collateral. require( _isCollateralSatisfied(loanParamsLocal, loanLocal, initialMargin, sentValues[4], collateralAmountRequired), "collateral insufficient" @@ -243,18 +349,39 @@ contract LoanOpenings is LoanOpeningsEvents, VaultController, InterestUser, Swap loanLocal.collateral = loanLocal.collateral.add(sentValues[4]); if (isTorqueLoan) { - // reclaiming varaible -> interestDuration + /// reclaiming varaible -> interestDuration sentValues[2] = loanLocal.endTimestamp.sub(block.timestamp); } else { - // reclaiming varaible -> entryLeverage = 100 / initialMargin + /// reclaiming varaible -> entryLeverage = 100 / initialMargin sentValues[2] = SafeMath.div(10**38, initialMargin); } _finalizeOpen(loanParamsLocal, loanLocal, sentAddresses, sentValues, isTorqueLoan); - return (sentValues[1], sentValues[4]); // newPrincipal, newCollateral + return (sentValues[1], sentValues[4]); /// newPrincipal, newCollateral } + /** + * @notice Finalize an open loan. + * + * @dev Finalize it by updating local parameters of the loan. + * + * @param loanParamsLocal The loan parameters. + * @param loanLocal The loan object. + * @param sentAddresses The addresses to send tokens: lender, borrower, + * receiver and manager: + * lender: must match loan if loanId provided. + * borrower: must match loan if loanId provided. + * receiver: receiver of funds (address(0) assumes borrower address). + * manager: delegated manager of loan unless address(0). + * @param sentValues The values to send: + * newRate: New loan interest rate. + * newPrincipal: New loan size (borrowAmount + any borrowed interest). + * torqueInterest: New amount of interest to escrow for Torque loan (determines initial loan length). + * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans). + * collateralTokenReceived: Total collateralToken deposit. + * @param isTorqueLoan Whether the loan is a Torque loan. + * */ function _finalizeOpen( LoanParams memory loanParamsLocal, Loan storage loanLocal, @@ -262,7 +389,7 @@ contract LoanOpenings is LoanOpeningsEvents, VaultController, InterestUser, Swap uint256[5] memory sentValues, bool isTorqueLoan ) internal { - //todo here the actual used rate and margin should go + /// @dev TODO: here the actual used rate and margin should go. (uint256 initialMargin, uint256 collateralToLoanRate) = IPriceFeeds(priceFeeds).getCurrentMargin( loanParamsLocal.loanToken, @@ -284,6 +411,28 @@ contract LoanOpenings is LoanOpeningsEvents, VaultController, InterestUser, Swap _emitOpeningEvents(loanParamsLocal, loanLocal, sentAddresses, sentValues, collateralToLoanRate, initialMargin, isTorqueLoan); } + /** + * @notice Emit the opening events. + * + * @param loanParamsLocal The loan parameters. + * @param loanLocal The loan object. + * @param sentAddresses The addresses to send tokens: lender, borrower, + * receiver and manager: + * lender: must match loan if loanId provided. + * borrower: must match loan if loanId provided. + * receiver: receiver of funds (address(0) assumes borrower address). + * manager: delegated manager of loan unless address(0). + * @param sentValues The values to send: + * newRate: New loan interest rate. + * newPrincipal: New loan size (borrowAmount + any borrowed interest). + * torqueInterest: New amount of interest to escrow for Torque loan (determines initial loan length). + * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans). + * collateralTokenReceived: Total collateralToken deposit. + * @param collateralToLoanRate The exchange rate from collateral to loan + * tokens. + * @param margin The amount of margin of the trade. + * @param isTorqueLoan Whether the loan is a Torque loan. + * */ function _emitOpeningEvents( LoanParams memory loanParamsLocal, Loan memory loanLocal, @@ -295,39 +444,47 @@ contract LoanOpenings is LoanOpeningsEvents, VaultController, InterestUser, Swap ) internal { if (isTorqueLoan) { emit Borrow( - sentAddresses[1], // user (borrower) - sentAddresses[0], // lender - loanLocal.id, // loanId - loanParamsLocal.loanToken, // loanToken - loanParamsLocal.collateralToken, // collateralToken - sentValues[1], // newPrincipal - sentValues[4], // newCollateral - sentValues[0], // interestRate - sentValues[2], // interestDuration - collateralToLoanRate, // collateralToLoanRate, - margin // currentMargin + sentAddresses[1], /// user (borrower) + sentAddresses[0], /// lender + loanLocal.id, /// loanId + loanParamsLocal.loanToken, /// loanToken + loanParamsLocal.collateralToken, /// collateralToken + sentValues[1], /// newPrincipal + sentValues[4], /// newCollateral + sentValues[0], /// interestRate + sentValues[2], /// interestDuration + collateralToLoanRate, /// collateralToLoanRate, + margin /// currentMargin ); } else { - // currentLeverage = 100 / currentMargin + /// currentLeverage = 100 / currentMargin margin = SafeMath.div(10**38, margin); emit Trade( - sentAddresses[1], // user (trader) - sentAddresses[0], // lender - loanLocal.id, // loanId - loanParamsLocal.collateralToken, // collateralToken - loanParamsLocal.loanToken, // loanToken - sentValues[4], // positionSize - sentValues[1], // borrowedAmount - sentValues[0], // interestRate, - loanLocal.endTimestamp, // settlementDate - sentValues[3], // entryPrice (loanToCollateralSwapRate) - sentValues[2], // entryLeverage - margin // currentLeverage + sentAddresses[1], /// user (trader) + sentAddresses[0], /// lender + loanLocal.id, /// loanId + loanParamsLocal.collateralToken, /// collateralToken + loanParamsLocal.loanToken, /// loanToken + sentValues[4], /// positionSize + sentValues[1], /// borrowedAmount + sentValues[0], /// interestRate, + loanLocal.endTimestamp, /// settlementDate + sentValues[3], /// entryPrice (loanToCollateralSwapRate) + sentValues[2], /// entryLeverage + margin /// currentLeverage ); } } + /** + * @notice Set the delegated manager. + * + * @param loanId The ID of the loan. If 0, start a new loan. + * @param delegator The address of previous manager. + * @param delegated The address of the delegated manager. + * @param toggle The flag true/false for the delegated manager. + * */ function _setDelegatedManager( bytes32 loanId, address delegator, @@ -339,6 +496,19 @@ contract LoanOpenings is LoanOpeningsEvents, VaultController, InterestUser, Swap emit DelegatedManagerSet(loanId, delegator, delegated, toggle); } + /** + * @notice Calculate whether the collateral is satisfied. + * + * @dev Basically check collateral + drawdown >= 98% of required. + * + * @param loanParamsLocal The loan parameters. + * @param loanLocal The loan object. + * @param initialMargin The initial amount of margin. + * @param newCollateral The amount of new collateral. + * @param collateralAmountRequired The amount of required collateral. + * + * @return Whether the collateral is satisfied. + * */ function _isCollateralSatisfied( LoanParams memory loanParamsLocal, Loan memory loanLocal, @@ -346,11 +516,11 @@ contract LoanOpenings is LoanOpeningsEvents, VaultController, InterestUser, Swap uint256 newCollateral, uint256 collateralAmountRequired ) internal view returns (bool) { - // allow at most 2% under-collateralized + /// Allow at most 2% under-collateralized. collateralAmountRequired = collateralAmountRequired.mul(98 ether).div(100 ether); if (newCollateral < collateralAmountRequired) { - // check that existing collateral is sufficient coverage + /// Check that existing collateral is sufficient coverage. if (loanLocal.collateral != 0) { uint256 maxDrawdown = IPriceFeeds(priceFeeds).getMaxDrawdown( @@ -368,6 +538,26 @@ contract LoanOpenings is LoanOpeningsEvents, VaultController, InterestUser, Swap return true; } + /** + * @notice Initialize a loan. + * + * @param loanParamsLocal The loan parameters. + * @param loanId The ID of the loan. + * @param initialMargin The amount of margin of the trade. + * @param sentAddresses The addresses to send tokens: lender, borrower, + * receiver and manager: + * lender: must match loan if loanId provided. + * borrower: must match loan if loanId provided. + * receiver: receiver of funds (address(0) assumes borrower address). + * manager: delegated manager of loan unless address(0). + * @param sentValues The values to send: + * newRate: New loan interest rate. + * newPrincipal: New loan size (borrowAmount + any borrowed interest). + * torqueInterest: New amount of interest to escrow for Torque loan (determines initial loan length). + * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans). + * collateralTokenReceived: Total collateralToken deposit. + * @return The loanId. + * */ function _initializeLoan( LoanParams memory loanParamsLocal, bytes32 loanId, @@ -395,11 +585,11 @@ contract LoanOpenings is LoanOpeningsEvents, VaultController, InterestUser, Swap pendingTradesId: 0, active: true, principal: newPrincipal, - collateral: 0, // calculated later + collateral: 0, /// calculated later startTimestamp: block.timestamp, - endTimestamp: 0, // calculated later + endTimestamp: 0, /// calculated later startMargin: initialMargin, - startRate: 0, // queried later + startRate: 0, /// queried later borrower: borrower, lender: lender }); @@ -426,14 +616,27 @@ contract LoanOpenings is LoanOpeningsEvents, VaultController, InterestUser, Swap return loanId; } + /** + * @notice Initialize a loan interest. + * + * @dev A Torque loan is an indefinite-term loan. + * + * @param loanParamsLocal The loan parameters. + * @param loanLocal The loan object. + * @param newRate The new interest rate of the loan. + * @param newPrincipal The new principal amount of the loan. + * @param torqueInterest The interest rate of the Torque loan. + * + * @return interestAmountRequired The interest amount required. + * */ function _initializeInterest( LoanParams memory loanParamsLocal, Loan storage loanLocal, uint256 newRate, uint256 newPrincipal, - uint256 torqueInterest // ignored for fixed-term loans + uint256 torqueInterest /// ignored for fixed-term loans ) internal returns (uint256 interestAmountRequired) { - // pay outstanding interest to lender + /// Pay outstanding interest to lender. _payInterest(loanLocal.lender, loanParamsLocal.loanToken); LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id]; @@ -447,33 +650,33 @@ contract LoanOpenings is LoanOpeningsEvents, VaultController, InterestUser, Swap if (maxLoanTerm == 0 && loanLocal.endTimestamp != 0) { previousDepositRemaining = loanLocal .endTimestamp - .sub(block.timestamp) // block.timestamp < endTimestamp was confirmed earlier + .sub(block.timestamp) /// block.timestamp < endTimestamp was confirmed earlier. .mul(loanInterestLocal.owedPerDay) .div(86400); } uint256 owedPerDay = newPrincipal.mul(newRate).div(365 * 10**20); - // update stored owedPerDay + /// Update stored owedPerDay loanInterestLocal.owedPerDay = loanInterestLocal.owedPerDay.add(owedPerDay); lenderInterestLocal.owedPerDay = lenderInterestLocal.owedPerDay.add(owedPerDay); if (maxLoanTerm == 0) { - // indefinite-term (Torque) loan + /// Indefinite-term (Torque) loan. - // torqueInterest != 0 was confirmed earlier + /// torqueInterest != 0 was confirmed earlier. loanLocal.endTimestamp = torqueInterest.add(previousDepositRemaining).mul(86400).div(loanInterestLocal.owedPerDay).add( block.timestamp ); maxLoanTerm = loanLocal.endTimestamp.sub(block.timestamp); - // loan term has to at least be greater than one hour + /// Loan term has to at least be greater than one hour. require(maxLoanTerm > 3600, "loan too short"); interestAmountRequired = torqueInterest; } else { - // fixed-term loan + /// Fixed-term loan. if (loanLocal.endTimestamp == 0) { loanLocal.endTimestamp = block.timestamp.add(maxLoanTerm); @@ -484,11 +687,24 @@ contract LoanOpenings is LoanOpeningsEvents, VaultController, InterestUser, Swap loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.add(interestAmountRequired); - // update remaining lender interest values + /// Update remaining lender interest values. lenderInterestLocal.principalTotal = lenderInterestLocal.principalTotal.add(newPrincipal); lenderInterestLocal.owedTotal = lenderInterestLocal.owedTotal.add(interestAmountRequired); } + /** + * @notice Get the required collateral. + * + * @dev Basically collateral = newPrincipal * marginAmount + * + * @param loanToken The loan token instance address. + * @param collateralToken The collateral token instance address. + * @param newPrincipal The updated amount of principal (current debt). + * @param marginAmount The amount of margin of the trade. + * @param isTorqueLoan Whether the loan is a Torque loan. + * + * @return collateralTokenAmount The required collateral. + * */ function _getRequiredCollateral( address loanToken, address collateralToken, @@ -499,8 +715,9 @@ contract LoanOpenings is LoanOpeningsEvents, VaultController, InterestUser, Swap if (loanToken == collateralToken) { collateralTokenAmount = newPrincipal.mul(marginAmount).div(10**20); } else { - //using the price feed instead of the swap expected return because we need the rate in the inverse direction - //so the swap is probably farther off than the price feed. + /// Using the price feed instead of the swap expected return + /// because we need the rate in the inverse direction + /// so the swap is probably farther off than the price feed. (uint256 sourceToDestRate, uint256 sourceToDestPrecision) = IPriceFeeds(priceFeeds).queryRate(collateralToken, loanToken); if (sourceToDestRate != 0) { collateralTokenAmount = newPrincipal.mul(sourceToDestPrecision).div(sourceToDestRate).mul(marginAmount).div(10**20);