diff --git a/contracts/connectors/loantoken/LoanTokenLogicStandard.sol b/contracts/connectors/loantoken/LoanTokenLogicStandard.sol index 3347964e1..8d699b264 100644 --- a/contracts/connectors/loantoken/LoanTokenLogicStandard.sol +++ b/contracts/connectors/loantoken/LoanTokenLogicStandard.sol @@ -311,7 +311,7 @@ contract LoanTokenLogicStandard is LoanTokenLogicStorage { * @param collateralTokenSent The amount of collateral tokens provided by the user. * @param collateralTokenAddress The token address of collateral. * @param trader The account that performs this trade. - * @param minReturn Minimum amount (position size) in the collateral tokens + * @param minEntryPrice Value of loan token in collateral. * @param loanDataBytes Additional loan data (not in use for token swaps). * * @return New principal and new collateral added to trade. @@ -323,7 +323,7 @@ contract LoanTokenLogicStandard is LoanTokenLogicStorage { uint256 collateralTokenSent, address collateralTokenAddress, address trader, - uint256 minReturn, // minimum position size in the collateral tokens + uint256 minEntryPrice, // value of loan token in collateral bytes memory loanDataBytes /// Arbitrary order data. ) public @@ -336,14 +336,6 @@ contract LoanTokenLogicStandard is LoanTokenLogicStorage { { _checkPause(); - checkPriceDivergence( - leverageAmount, - loanTokenSent, - collateralTokenSent, - collateralTokenAddress, - minReturn - ); - if (collateralTokenAddress == address(0)) { collateralTokenAddress = wrbtcTokenAddress; } @@ -387,6 +379,11 @@ contract LoanTokenLogicStandard is LoanTokenLogicStorage { sentAmounts[1] /// depositAmount ); + checkPriceDivergence( + loanTokenSent.add(sentAmounts[1]), + collateralTokenAddress, + minEntryPrice + ); require( _getAmountInRbtc(loanTokenAddress, sentAmounts[1]) > TINY_AMOUNT, "principal too small" @@ -416,7 +413,7 @@ contract LoanTokenLogicStandard is LoanTokenLogicStorage { * @param collateralTokenSent The amount of collateral tokens provided by the user. * @param collateralTokenAddress The token address of collateral. * @param trader The account that performs this trade. - * @param minReturn Minimum position size in the collateral tokens + * @param minEntryPrice Value of loan token in collateral. * @param affiliateReferrer The address of the referrer from affiliates program. * @param loanDataBytes Additional loan data (not in use for token swaps). * @@ -429,7 +426,7 @@ contract LoanTokenLogicStandard is LoanTokenLogicStorage { uint256 collateralTokenSent, address collateralTokenAddress, address trader, - uint256 minReturn, /// Minimum position size in the collateral tokens. + uint256 minEntryPrice, /// Value of loan token in collateral address affiliateReferrer, /// The user was brought by the affiliate (referrer). bytes calldata loanDataBytes /// Arbitrary order data. ) @@ -453,7 +450,7 @@ contract LoanTokenLogicStandard is LoanTokenLogicStorage { collateralTokenSent, collateralTokenAddress, trader, - minReturn, + minEntryPrice, loanDataBytes ); } @@ -934,21 +931,28 @@ contract LoanTokenLogicStandard is LoanTokenLogicStorage { } } + /** + * @notice Check if entry price lies above a minimum + * + * @param loanTokenSent The amount of deposit. + * @param collateralTokenAddress The token address of collateral. + * @param minEntryPrice Value of loan token in collateral + * */ function checkPriceDivergence( - uint256 leverageAmount, uint256 loanTokenSent, - uint256 collateralTokenSent, address collateralTokenAddress, - uint256 minReturn + uint256 minEntryPrice ) public view { - (, uint256 estimatedCollateral, ) = - getEstimatedMarginDetails( - leverageAmount, - loanTokenSent, - collateralTokenSent, - collateralTokenAddress + /// @dev See how many collateralTokens we would get if exchanging this amount of loan tokens to collateral tokens. + uint256 collateralTokensReceived = + ProtocolLike(sovrynContractAddress).getSwapExpectedReturn( + loanTokenAddress, + collateralTokenAddress, + loanTokenSent ); - require(estimatedCollateral >= minReturn, "coll too low"); + uint256 collateralTokenPrice = + (collateralTokensReceived.mul(WEI_PRECISION)).div(loanTokenSent); + require(collateralTokenPrice >= minEntryPrice, "entry price above the minimum"); } /* Internal functions */ diff --git a/contracts/governance/Staking/Staking.sol b/contracts/governance/Staking/Staking.sol index 0ae7627f4..40b868829 100644 --- a/contracts/governance/Staking/Staking.sol +++ b/contracts/governance/Staking/Staking.sol @@ -230,7 +230,6 @@ contract Staking is * the total duration might end up a bit shorter than specified * depending on the date of staking. * */ - uint256 start = timestampToLockDate(block.timestamp + cliff); if (duration > MAX_DURATION) { duration = MAX_DURATION; diff --git a/contracts/interfaces/ILoanTokenModules.sol b/contracts/interfaces/ILoanTokenModules.sol index 6859f23a4..07a4ed5a1 100644 --- a/contracts/interfaces/ILoanTokenModules.sol +++ b/contracts/interfaces/ILoanTokenModules.sol @@ -95,7 +95,7 @@ interface ILoanTokenModules { uint256 collateralTokenSent, address collateralTokenAddress, address trader, - uint256 minReturn, // minimum position size in the collateral tokens + uint256 minEntryPrice, // Value of loan token in collateral. bytes calldata loanDataBytes /// Arbitrary order data. ) external @@ -112,9 +112,9 @@ interface ILoanTokenModules { uint256 collateralTokenSent, address collateralTokenAddress, address trader, - uint256 minReturn, /// Minimum position size in the collateral tokens. - address affiliateReferrer, /// The user was brought by the affiliate (referrer). - bytes calldata loanDataBytes /// Arbitrary order data. + uint256 minEntryPrice, // Value of loan token in collateral. + address affiliateReferrer, // The user was brought by the affiliate (referrer). + bytes calldata loanDataBytes // Arbitrary order data. ) external payable @@ -193,11 +193,9 @@ interface ILoanTokenModules { ) external view returns (uint256 borrowAmount); function checkPriceDivergence( - uint256 leverageAmount, uint256 loanTokenSent, - uint256 collateralTokenSent, address collateralTokenAddress, - uint256 minReturn + uint256 minEntryPrice ) external view; function getMaxEscrowAmount(uint256 leverageAmount) diff --git a/scripts/contractInteraction/testnet_contracts.json b/scripts/contractInteraction/testnet_contracts.json index b60b598b3..72bb49e95 100644 --- a/scripts/contractInteraction/testnet_contracts.json +++ b/scripts/contractInteraction/testnet_contracts.json @@ -9,9 +9,9 @@ "iBProProxy": "0xeE953baeF70937E2feB1D79416855886582e395E", "iXUSDProxy": "0x4172F7a3C7fA9703140Ab579dcdA27A637a1CB7c", "iRBTCProxy": "0x3138140Cf23b10e0ed02cFf190Da4Ae3F288f6D8", - "LoanTokenLogicLM": "0xFB0b4DBCDf49802bE24Da19f66AE9a62942aEC19", + "LoanTokenLogicLM": "0x5B7f1AF3160957832761704f5Bc60aa082Af2f15", "LoanTokenLogicBeaconLM": "0x961F75cb98BAaAA9Ce5efb707d2fe22E8CBdC074", - "LoanTokenLogicWrbtc": "0x3E686322ac52DF2380a96dC71264d296A8eBe289", + "LoanTokenLogicWrbtc": "0xB073ddD17e94ee5f7F8D4A90D9cd26787a3133F7", "LoanTokenLogicBeaconWrbtc": "0x4A3d7163F9Bc3D3Be0a467452A880D3c25a83e70", "sovrynProtocol": "0x25380305f223B32FDB844152abD2E82BC5Ad99c3", "DoC": "0xCB46c0ddc60D18eFEB0E586C17Af6ea36452Dae0", diff --git a/tests/loan-token/TradingTestToken.test.js b/tests/loan-token/TradingTestToken.test.js index c05b9029b..ec324b3ce 100644 --- a/tests/loan-token/TradingTestToken.test.js +++ b/tests/loan-token/TradingTestToken.test.js @@ -708,16 +708,14 @@ contract("LoanTokenTrading", (accounts) => { expect(args["positionSize"]).to.equal(sovryn_collateral_token_balance_diff); }); - it("checkPriceDivergence should success if min position size is less than or equal to collateral", async () => { + it("checkPriceDivergence should succeed if entry price is less than or equal to a minimum", async () => { await set_demand_curve(loanToken); await SUSD.transfer(loanToken.address, wei("500", "ether")); await loanToken.checkPriceDivergence( - new BN(2).mul(oneEth), - wei("0.01", "ether"), - wei("0.01", "ether"), + wei("1", "ether"), RBTC.address, - wei("0.02", "ether") + wei("0.0001", "ether") ); }); @@ -755,7 +753,7 @@ contract("LoanTokenTrading", (accounts) => { 10000, // collateral token sent RBTC.address, // collateralTokenAddress (RBTC) accounts[1], // trader, - 20000, // slippage + 20000, // minEntryPrice "0x", // loanDataBytes (only required with ether) { from: accounts[2] } ), @@ -780,24 +778,18 @@ contract("LoanTokenTrading", (accounts) => { oneEth.toString(), // collateral token sent RBTC.address, // collateralTokenAddress (RBTC) accounts[1], // trader, - oneEth.mul(new BN(2)).toString(), // slippage + 200000, // minEntryPrice "0x", // loanDataBytes (only required with ether) { from: accounts[2] } ); }); - it("checkPriceDivergence should revert if min position size is greater than collateral", async () => { + it("checkPriceDivergence should revert if entry price lies above a minimum", async () => { await set_demand_curve(loanToken); await expectRevert( - loanToken.checkPriceDivergence( - new BN(2).mul(oneEth), - wei("2", "ether"), - 0, - RBTC.address, - wei("1", "ether") - ), - "coll too low" + loanToken.checkPriceDivergence(wei("2", "ether"), RBTC.address, wei("1", "ether")), + "entry price above the minimum" ); }); });