Skip to content

Commit

Permalink
Merge branch 'development' into ci
Browse files Browse the repository at this point in the history
  • Loading branch information
Franklin Richards committed Jan 11, 2021
2 parents aa878fd + 259abf5 commit 5d0fa8c
Show file tree
Hide file tree
Showing 14 changed files with 758 additions and 149 deletions.
52 changes: 40 additions & 12 deletions contracts/connectors/loantoken/LoanTokenLogicStandard.sol
Original file line number Diff line number Diff line change
Expand Up @@ -341,8 +341,6 @@ contract LoanTokenLogicStandard is LoanTokenSettingsLowerAdmin {
return true;
}

event Debug(bytes32 slot, uint256 one, uint256 two);

/**
* @dev updates the user's checkpoint price and profit so far.
* @param _user the user address
Expand Down Expand Up @@ -385,7 +383,6 @@ contract LoanTokenLogicStandard is LoanTokenSettingsLowerAdmin {

checkpointPrices_[_user] = _currentPrice;

emit Debug(slot, _currentProfit, _currentPrice);
}

/* Public View functions */
Expand Down Expand Up @@ -732,23 +729,54 @@ contract LoanTokenLogicStandard is LoanTokenSettingsLowerAdmin {
}
}

/**
* @dev computes what the deposit is worth in loan tokens using the swap rate
* used for loan size computation
* @param collateralTokenAddress the address of the collateral token
* @param collateralTokenSent the number of collateral tokens provided the user
* @param loanTokenSent the number of loan tokens provided by the user
* @return the value of the deposit in loan tokens
* */
function _totalDeposit(
address collateralTokenAddress,
uint256 collateralTokenSent,
uint256 loanTokenSent
) internal view returns (uint256 totalDeposit) {
totalDeposit = loanTokenSent;

if (collateralTokenSent != 0) {
(uint256 sourceToDestRate, uint256 sourceToDestPrecision) =
FeedsLike(ProtocolLike(sovrynContractAddress).priceFeeds())
.queryRate(collateralTokenAddress, loanTokenAddress);
if (sourceToDestPrecision != 0) {
totalDeposit = collateralTokenSent
.mul(sourceToDestRate)
.div(sourceToDestPrecision)
.add(totalDeposit);
//get the oracle rate from collateral -> loan
(uint256 collateralToLoanRate, uint256 collateralToLoanPrecision) = FeedsLike(ProtocolLike(sovrynContractAddress).priceFeeds()).queryRate(
collateralTokenAddress,
loanTokenAddress
);
require((collateralToLoanRate != 0) && (collateralToLoanPrecision != 0), "invalid exchange rate for the collateral token");

//compute the loan token amount with the oracle rate
uint256 loanTokenAmount = collateralTokenSent
.mul(collateralToLoanRate)
.div(collateralToLoanPrecision
);

//see how many collateralTokens we would get if exchanging this amount of loan tokens to collateral tokens
uint256 collateralTokenAmount = ProtocolLike(sovrynContractAddress).getSwapExpectedReturn(
loanTokenAddress,
collateralTokenAddress,
loanTokenAmount
);

//probably not the same due to the price difference
if (collateralTokenAmount != collateralTokenSent) {
//scale the loan token amount accordingly, so we'll get the expected position size in the end
loanTokenAmount = loanTokenAmount
.mul(collateralTokenAmount)
.div(collateralTokenSent
);
}
}

totalDeposit = loanTokenAmount.add(totalDeposit);

}
}

function _getInterestRateAndBorrowAmount(
Expand Down
13 changes: 12 additions & 1 deletion contracts/connectors/loantoken/interfaces/ProtocolLike.sol
Original file line number Diff line number Diff line change
Expand Up @@ -73,5 +73,16 @@ interface ProtocolLike {

function isLoanPool(address loanPool) external view returns (bool);

function lendingFeePercent() external view returns (uint256);
function lendingFeePercent()
external
view
returns (uint256);

function getSwapExpectedReturn(
address sourceToken,
address destToken,
uint256 sourceTokenAmount)
external
view
returns(uint256);
}
64 changes: 39 additions & 25 deletions contracts/modules/LoanOpenings.sol
Original file line number Diff line number Diff line change
Expand Up @@ -116,14 +116,21 @@ contract LoanOpenings is

uint256 owedPerDay = newPrincipal.mul(interestRate).div(365 * 10**20);

uint256 interestAmountRequired = maxLoanTerm.mul(owedPerDay).div(86400);

uint256 receivedAmount =
_swapsExpectedReturn(
loanToken,
collateralToken,
loanTokenSent.sub(interestAmountRequired)
);
uint256 interestAmountRequired = maxLoanTerm
.mul(owedPerDay)
.div(86400);

uint256 swapAmount = loanTokenSent.sub(interestAmountRequired);
uint256 tradingFee = _getTradingFee(swapAmount);
if (tradingFee != 0) {
swapAmount = swapAmount.sub(tradingFee);
}

uint256 receivedAmount = _swapsExpectedReturn(
loanToken,
collateralToken,
swapAmount
);
if (receivedAmount == 0) {
return 0;
} else {
Expand Down Expand Up @@ -192,6 +199,7 @@ contract LoanOpenings is
.div(marginAmount)
.mul(sourceToDestRate)
.div(sourceToDestPrecision);

}
}
}
Expand Down Expand Up @@ -302,7 +310,8 @@ contract LoanOpenings is
"collateral insufficient"
);

loanLocal.collateral = loanLocal.collateral.add(sentValues[4]);
loanLocal.collateral = loanLocal.collateral
.add(sentValues[4]);

if (isTorqueLoan) {
// reclaiming varaible -> interestDuration
Expand All @@ -321,29 +330,32 @@ contract LoanOpenings is
);

return (sentValues[1], sentValues[4]); // newPrincipal, newCollateral
}
}


function _finalizeOpen(
LoanParams memory loanParamsLocal,
Loan storage loanLocal,
address[4] memory sentAddresses,
uint256[5] memory sentValues,
bool isTorqueLoan
) internal {
(uint256 initialMargin, uint256 collateralToLoanRate) =
IPriceFeeds(priceFeeds).getCurrentMargin(
loanParamsLocal.loanToken,
loanParamsLocal.collateralToken,
loanLocal.principal,
loanLocal.collateral
);
bool isTorqueLoan)
internal
{
//todo here the actual used rate and margin should go
(uint256 initialMargin, uint256 collateralToLoanRate) = IPriceFeeds(priceFeeds).getCurrentMargin(
loanParamsLocal.loanToken,
loanParamsLocal.collateralToken,
loanLocal.principal,
loanLocal.collateral
);
require(
initialMargin > loanParamsLocal.maintenanceMargin,
"unhealthy position"
);

if (loanLocal.startTimestamp == block.timestamp) {
loanLocal.startRate = collateralToLoanRate;
uint256 totalSwapRate = 10**36;
loanLocal.startRate = isTorqueLoan ? collateralToLoanRate : totalSwapRate.div(sentValues[3]);
}

_emitOpeningEvents(
Expand Down Expand Up @@ -611,16 +623,18 @@ contract LoanOpenings is
if (loanToken == collateralToken) {
collateralTokenAmount = newPrincipal.mul(marginAmount).div(10**20);
} else {
(uint256 sourceToDestRate, uint256 sourceToDestPrecision) =
IPriceFeeds(priceFeeds).queryRate(collateralToken, loanToken);
//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
collateralTokenAmount = newPrincipal
.mul(sourceToDestPrecision)
.div(sourceToDestRate)
.mul(marginAmount)
.div(10**20);
} else {
collateralTokenAmount = 0;
}
}

Expand Down
7 changes: 5 additions & 2 deletions contracts/swaps/ISwapsImpl.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ interface ISwapsImpl {
function internalExpectedRate(
address sourceTokenAddress,
address destTokenAddress,
uint256 sourceTokenAmount
) external view returns (uint256);
uint256 sourceTokenAmount,
address optionalContractAddress)
external
view
returns (uint256);
}
28 changes: 11 additions & 17 deletions contracts/swaps/SwapsUser.sol
Original file line number Diff line number Diff line change
Expand Up @@ -198,24 +198,18 @@ contract SwapsUser is State, SwapsEvents, FeesHelper {
function _swapsExpectedReturn(
address sourceToken,
address destToken,
uint256 sourceTokenAmount
) internal view returns (uint256) {
uint256 tradingFee = _getTradingFee(sourceTokenAmount);
if (tradingFee != 0) {
sourceTokenAmount = sourceTokenAmount.sub(tradingFee);
}

uint256 sourceToDestRate =
ISwapsImpl(swapsImpl).internalExpectedRate(
sourceToken,
destToken,
sourceTokenAmount
);
uint256 sourceToDestPrecision =
IPriceFeeds(priceFeeds).queryPrecision(sourceToken, destToken);
uint256 sourceTokenAmount)
internal
view
returns (uint256 destTokenAmount)
{

return
sourceTokenAmount.mul(sourceToDestRate).div(sourceToDestPrecision);
destTokenAmount = ISwapsImpl(swapsImpl).internalExpectedRate(
sourceToken,
destToken,
sourceTokenAmount,
sovrynSwapContractRegistryAddress
);
}

function _checkSwapSize(address tokenAddress, uint256 amount)
Expand Down
85 changes: 39 additions & 46 deletions contracts/swaps/connectors/SwapsImplSovrynSwap.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,16 @@ contract SwapsImplSovrynSwap is State, ISwapsImpl {
result := mload(add(source, 32))
}
}

function getSovrynSwapNetworkContract()
public
view
returns (ISovrynSwapNetwork)
{
// sovrynSwapContractRegistryAddress is part of State.sol and set in ProtocolSettings.sol
IContractRegistry contractRegistry =
IContractRegistry(sovrynSwapContractRegistryAddress);
return
ISovrynSwapNetwork(
contractRegistry.addressOf(
getContractHexName("SovrynSwapNetwork")
)
);

/**
* looks up the sovryn swap network contract registered at the given address
* @param sovrynSwapRegistryAddress the address of the registry
* */
function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress) public view returns(ISovrynSwapNetwork){
// state variable sovrynSwapContractRegistryAddress is part of State.sol and set in ProtocolSettings.sol
//and this function needs to work without delegate call as well -> therefore pass it
IContractRegistry contractRegistry = IContractRegistry(sovrynSwapRegistryAddress);
return ISovrynSwapNetwork(contractRegistry.addressOf(getContractHexName("SovrynSwapNetwork")));
}

/**
Expand Down Expand Up @@ -74,14 +69,13 @@ contract SwapsImplSovrynSwap is State, ISwapsImpl {
"invalid tokens"
);

ISovrynSwapNetwork sovrynSwapNetwork = getSovrynSwapNetworkContract();
IERC20[] memory path =
sovrynSwapNetwork.conversionPath(
IERC20(sourceTokenAddress),
IERC20(destTokenAddress)
);

uint256 minReturn = 0;
ISovrynSwapNetwork sovrynSwapNetwork = getSovrynSwapNetworkContract(sovrynSwapContractRegistryAddress);
IERC20[] memory path = sovrynSwapNetwork.conversionPath(
IERC20(sourceTokenAddress),
IERC20(destTokenAddress)
);

uint minReturn = 0;
sourceTokenAmountUsed = minSourceTokenAmount;

//if the required amount of destination tokens is passed, we need to calculate the estimated amount of source tokens
Expand Down Expand Up @@ -169,23 +163,19 @@ contract SwapsImplSovrynSwap is State, ISwapsImpl {
function estimateSourceTokenAmount(
address sourceTokenAddress,
address destTokenAddress,
uint256 requiredDestTokenAmount,
uint256 maxSourceTokenAmount
) internal returns (uint256 estimatedSourceAmount) {
uint256 sourceToDestPrecision =
IPriceFeeds(priceFeeds).queryPrecision(
sourceTokenAddress,
destTokenAddress
);
if (sourceToDestPrecision == 0) return maxSourceTokenAmount;
uint requiredDestTokenAmount,
uint maxSourceTokenAmount)
internal
view
returns(uint256 estimatedSourceAmount)
{

uint256 sourceToDestPrecision = IPriceFeeds(priceFeeds).queryPrecision(sourceTokenAddress, destTokenAddress);
if (sourceToDestPrecision == 0)
return maxSourceTokenAmount;

//compute the expected rate for the maxSourceTokenAmount -> if spending less, we can't get a worse rate.
uint256 expectedRate =
internalExpectedRate(
sourceTokenAddress,
destTokenAddress,
maxSourceTokenAmount
);
uint256 expectedRate = internalExpectedRate(sourceTokenAddress, destTokenAddress, maxSourceTokenAmount,sovrynSwapContractRegistryAddress);

//compute the source tokens needed to get the required amount with the worst case rate
estimatedSourceAmount = requiredDestTokenAmount
Expand Down Expand Up @@ -214,14 +204,17 @@ contract SwapsImplSovrynSwap is State, ISwapsImpl {
function internalExpectedRate(
address sourceTokenAddress,
address destTokenAddress,
uint256 sourceTokenAmount
) public view returns (uint256) {
ISovrynSwapNetwork sovrynSwapNetwork = getSovrynSwapNetworkContract();
IERC20[] memory path =
sovrynSwapNetwork.conversionPath(
IERC20(sourceTokenAddress),
IERC20(destTokenAddress)
);
uint256 sourceTokenAmount,
address sovrynSwapContractRegistryAddress)
public
view
returns (uint256)
{
ISovrynSwapNetwork sovrynSwapNetwork = getSovrynSwapNetworkContract(sovrynSwapContractRegistryAddress);
IERC20[] memory path = sovrynSwapNetwork.conversionPath(
IERC20(sourceTokenAddress),
IERC20(destTokenAddress)
);
//is returning the total amount of destination tokens
uint256 expectedReturn =
sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);
Expand Down
Loading

0 comments on commit 5d0fa8c

Please sign in to comment.