From 191b0d09310c12280689ce092e9ee77234054ed5 Mon Sep 17 00:00:00 2001 From: Mubaris NK Date: Fri, 9 Oct 2020 12:06:31 +0530 Subject: [PATCH 1/4] Add uniswap v2 path finder algo --- contracts/protocols/uniswapV2.sol | 178 ++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) diff --git a/contracts/protocols/uniswapV2.sol b/contracts/protocols/uniswapV2.sol index 1e36002..daca76c 100644 --- a/contracts/protocols/uniswapV2.sol +++ b/contracts/protocols/uniswapV2.sol @@ -85,6 +85,22 @@ contract UniswapHelpers is Helpers { _sell = sell == getEthAddr() ? TokenInterface(getAddressWETH()) : TokenInterface(sell); } + function checkPaths( + IUniswapV2Router02 router, + address[] memory paths + ) internal view returns(bool isValid) { + isValid = true; + for (uint i; i < paths.length - 1; i++) { + if (paths[i] == paths[i + 1]) { + return false; + } + address pair = IUniswapV2Factory(router.factory()).getPair(paths[i], paths[i + 1]); + if (pair == address(0)) { + return false; + } + } + } + function getExpectedBuyAmt( address buyAddr, address sellAddr, @@ -173,6 +189,40 @@ contract UniswapHelpers is Helpers { amtA = wmul(_tokenA.balanceOf(exchangeAddr), share); amtB = wmul(_tokenB.balanceOf(exchangeAddr), share); } + + function _getExpectedBuyAmtByPath( + address[] memory paths, + uint sellAmt + ) internal view returns(uint buyAmt) { + IUniswapV2Router02 router = IUniswapV2Router02(getUniswapAddr()); + + if (checkPaths(router, paths)) { + uint[] memory amts = router.getAmountsOut( + sellAmt, + paths + ); + buyAmt = amts[amts.length - 1]; + } else { + buyAmt = 0; + } + } + + function _getExpectedSellAmtByPath( + address[] memory paths, + uint buyAmt + ) internal view returns(uint sellAmt) { + IUniswapV2Router02 router = IUniswapV2Router02(getUniswapAddr()); + + if (checkPaths(router, paths)) { + uint[] memory amts = router.getAmountsIn( + buyAmt, + paths + ); + sellAmt = amts[0]; + } else { + sellAmt = uint(-1); + } + } } @@ -293,6 +343,134 @@ contract Resolver is UniswapHelpers { } return poolData; } + + function getOptimalSellPath( + address buyAddr, + address sellAddr, + address[] memory tokens, + uint sellAmt, + uint slippage + ) public view returns (address[] memory paths, uint buyAmt, uint unitAmt) + { + (TokenInterface _buyAddr, TokenInterface _sellAddr) = changeEthAddress(buyAddr, sellAddr); + + address[] memory _path = new address[](2); + _path[0] = address(_sellAddr); + _path[1] = address(_buyAddr); + + paths = _path; + buyAmt = _getExpectedBuyAmtByPath(_path, sellAmt); + + _path = new address[](3); + _path[0] = address(_sellAddr); + _path[2] = address(_buyAddr); + + uint i; + uint j; + uint _buyAmt; + + for(i = 0; i < tokens.length; i++) { + _path[1] = tokens[i]; + + _buyAmt = _getExpectedBuyAmtByPath(_path, sellAmt); + + if (_buyAmt > buyAmt) { + buyAmt = _buyAmt; + paths = new address[](3); + paths[0] = _path[0]; + paths[1] = _path[1]; + paths[2] = _path[2]; + } + } + + _path = new address[](4); + _path[0] = address(_sellAddr); + _path[3] = address(_buyAddr); + + for(i = 0; i < tokens.length; i++) { + for(j = 0; j < tokens.length; j++) { + _path[1] = tokens[i]; + _path[2] = tokens[j]; + + _buyAmt = _getExpectedBuyAmtByPath(_path, sellAmt); + + if (_buyAmt > buyAmt) { + buyAmt = _buyAmt; + paths = new address[](4); + paths[0] = _path[0]; + paths[1] = _path[1]; + paths[2] = _path[2]; + paths[3] = _path[3]; + } + } + } + + unitAmt = getBuyUnitAmt(_buyAddr, buyAmt, _sellAddr, sellAmt, slippage); + } + + function getOptimalBuyPath( + address buyAddr, + address sellAddr, + address[] memory tokens, + uint buyAmt, + uint slippage + ) public view returns (address[] memory paths, uint sellAmt, uint unitAmt) + { + (TokenInterface _buyAddr, TokenInterface _sellAddr) = changeEthAddress(buyAddr, sellAddr); + + address[] memory _path = new address[](2); + _path[0] = address(_sellAddr); + _path[1] = address(_buyAddr); + + paths = _path; + sellAmt = _getExpectedSellAmtByPath(_path, buyAmt); + + _path = new address[](3); + _path[0] = address(_sellAddr); + _path[2] = address(_buyAddr); + + uint i; + uint j; + uint _sellAmt; + + for(i = 0; i < tokens.length; i++) { + _path[1] = tokens[i]; + + _sellAmt = _getExpectedSellAmtByPath(_path, buyAmt); + + if (_sellAmt < sellAmt) { + sellAmt = _sellAmt; + paths = new address[](3); + paths[0] = _path[0]; + paths[1] = _path[1]; + paths[2] = _path[2]; + } + } + + _path = new address[](4); + _path[0] = address(_sellAddr); + _path[3] = address(_buyAddr); + + for(i = 0; i < tokens.length; i++) { + for(j = 0; j < tokens.length; j++) { + _path[1] = tokens[i]; + _path[2] = tokens[j]; + + _sellAmt = _getExpectedSellAmtByPath(_path, buyAmt); + + if (_sellAmt < sellAmt) { + sellAmt = _sellAmt; + paths = new address[](4); + paths[0] = _path[0]; + paths[1] = _path[1]; + paths[2] = _path[2]; + paths[3] = _path[3]; + } + } + } + + unitAmt = getSellUnitAmt(_sellAddr, sellAmt, _buyAddr, buyAmt, slippage); + } } From 3f72634daa42cec9c65755fd403a7b0257d90a80 Mon Sep 17 00:00:00 2001 From: Mubaris NK Date: Mon, 16 Nov 2020 16:07:06 +0530 Subject: [PATCH 2/4] Aave v2 resolver --- contracts/protocols/aave_v2.sol | 246 ++++++++++++++++++++++++++++++++ 1 file changed, 246 insertions(+) create mode 100644 contracts/protocols/aave_v2.sol diff --git a/contracts/protocols/aave_v2.sol b/contracts/protocols/aave_v2.sol new file mode 100644 index 0000000..db106bb --- /dev/null +++ b/contracts/protocols/aave_v2.sol @@ -0,0 +1,246 @@ +pragma solidity ^0.6.0; +pragma experimental ABIEncoderV2; + +interface AaveProtocolDataProvider { + function getUserReserveData(address asset, address user) external view returns ( + uint256 currentATokenBalance, + uint256 currentStableDebt, + uint256 currentVariableDebt, + uint256 principalStableDebt, + uint256 scaledVariableDebt, + uint256 stableBorrowRate, + uint256 liquidityRate, + uint40 stableRateLastUpdated, + bool usageAsCollateralEnabled + ); + + function getReserveConfigurationData(address asset) external view returns ( + uint256 decimals, + uint256 ltv, + uint256 liquidationThreshold, + uint256 liquidationBonus, + uint256 reserveFactor, + bool usageAsCollateralEnabled, + bool borrowingEnabled, + bool stableBorrowRateEnabled, + bool isActive, + bool isFrozen + ); + + function getReserveData(address asset) external view returns ( + uint256 availableLiquidity, + uint256 totalStableDebt, + uint256 totalVariableDebt, + uint256 liquidityRate, + uint256 variableBorrowRate, + uint256 stableBorrowRate, + uint256 averageStableBorrowRate, + uint256 liquidityIndex, + uint256 variableBorrowIndex, + uint40 lastUpdateTimestamp + ); +} + +interface AaveLendingPool { + function getUserAccountData(address user) external view returns ( + uint256 totalCollateralETH, + uint256 totalDebtETH, + uint256 availableBorrowsETH, + uint256 currentLiquidationThreshold, + uint256 ltv, + uint256 healthFactor + ); +} + +interface AaveAddressProvider { + function getLendingPool() external view returns (address); + function getPriceOracle() external view returns (address); +} + +interface AavePriceOracle { + function getAssetPrice(address _asset) external view returns(uint256); + function getAssetsPrices(address[] calldata _assets) external view returns(uint256[] memory); + function getSourceOfAsset(address _asset) external view returns(uint256); + function getFallbackOracle() external view returns(uint256); +} + +contract DSMath { + + function add(uint x, uint y) internal pure returns (uint z) { + require((z = x + y) >= x, "math-not-safe"); + } + + function sub(uint x, uint y) internal pure returns (uint z) { + z = x - y <= x ? x - y : 0; + } + + function mul(uint x, uint y) internal pure returns (uint z) { + require(y == 0 || (z = x * y) / y == x, "math-not-safe"); + } + + uint constant WAD = 10 ** 18; + uint constant RAY = 10 ** 27; + + function rmul(uint x, uint y) internal pure returns (uint z) { + z = add(mul(x, y), RAY / 2) / RAY; + } + + function wmul(uint x, uint y) internal pure returns (uint z) { + z = add(mul(x, y), WAD / 2) / WAD; + } + + function rdiv(uint x, uint y) internal pure returns (uint z) { + z = add(mul(x, RAY), y / 2) / y; + } + + function wdiv(uint x, uint y) internal pure returns (uint z) { + z = add(mul(x, WAD), y / 2) / y; + } + +} + +contract AaveHelpers is DSMath { + /** + * @dev get Aave Provider Address + */ + function getAaveAddressProvider() internal pure returns (address) { + return 0x652B2937Efd0B5beA1c8d54293FC1289672AFC6b; // Kovan + } + + /** + * @dev get Aave Protocol Data Provider + */ + function getAaveProtocolDataProvider() internal pure returns (address) { + return 0x744C1aaA95232EeF8A9994C4E0b3a89659D9AB79; // Kovan + } + + struct AaveUserTokenData { + uint tokenPrice; + uint supplyBalance; + uint stableBorrowBalance; + uint variableBorrowBalance; + uint supplyRate; + uint stableBorrowRate; + uint variableBorrowRate; + AaveTokenData aaveTokenData; + } + + struct AaveUserData { + uint totalCollateralETH; + uint totalBorrowsETH; + uint availableBorrowsETH; + uint currentLiquidationThreshold; + uint ltv; + uint healthFactor; + } + + struct AaveTokenData { + uint ltv; + uint threshold; + uint reserveFactor; + bool usageAsCollEnabled; + bool borrowEnabled; + bool stableBorrowEnabled; + bool isActive; + bool isFrozen; + } + + function collateralData( + AaveProtocolDataProvider aaveData, + address token + ) internal view returns (AaveTokenData memory aaveTokenData) { + ( + , + aaveTokenData.ltv, + aaveTokenData.threshold, + , + aaveTokenData.reserveFactor, + aaveTokenData.usageAsCollEnabled, + aaveTokenData.borrowEnabled, + aaveTokenData.stableBorrowEnabled, + aaveTokenData.isActive, + aaveTokenData.isFrozen + ) = aaveData.getReserveConfigurationData(token); + } + + function getTokenData( + AaveProtocolDataProvider aaveData, + address user, + address token, + uint price + ) internal view returns(AaveUserTokenData memory tokenData) { + ( + tokenData.supplyBalance, + tokenData.stableBorrowBalance, + tokenData.variableBorrowBalance, + ,,,,, + ) = aaveData.getUserReserveData(token, user); + + ( + ,,, + tokenData.supplyRate, + tokenData.variableBorrowRate, + tokenData.stableBorrowRate, + ,,, + ) = aaveData.getReserveData(token); + + AaveTokenData memory aaveTokenData = collateralData(aaveData, token); + + tokenData.tokenPrice = price; + tokenData.aaveTokenData = aaveTokenData; + + // tokenData = AaveUserTokenData( + // price, + // supplyBal, + // stableDebtBal, + // variableDebtBal, + // liquidityRate, + // stableBorrowRate, + // variableBorrowRate, + // aaveTokenData + // ); + } + + function getUserData(AaveLendingPool aave, address user) + internal view returns (AaveUserData memory userData) { + ( + uint256 totalCollateralETH, + uint256 totalDebtETH, + uint256 availableBorrowsETH, + uint256 currentLiquidationThreshold, + uint256 ltv, + uint256 healthFactor + ) = aave.getUserAccountData(user); + + userData = AaveUserData( + totalCollateralETH, + totalDebtETH, + availableBorrowsETH, + currentLiquidationThreshold, + ltv, + healthFactor + ); + } +} + +contract Resolver is AaveHelpers { + function getPosition(address user, address[] memory tokens) public view returns(AaveUserTokenData[] memory, AaveUserData memory) { + AaveAddressProvider addrProvider = AaveAddressProvider(getAaveAddressProvider()); + // AavePriceOracle priceOracle = AavePriceOracle(addrProvider.getPriceOracle()); + // AaveProtocolDataProvider aaveData = AaveProtocolDataProvider(getAaveProtocolDataProvider()); + // AaveLendingPool aave = AaveLendingPool(addrProvider.getLendingPool()); + + AaveUserTokenData[] memory tokensData = new AaveUserTokenData[](tokens.length); + uint[] memory tokenPrices = AavePriceOracle(addrProvider.getPriceOracle()).getAssetsPrices(tokens); + + for (uint i = 0; i < tokens.length; i++) { + tokensData[i] = getTokenData(AaveProtocolDataProvider(getAaveProtocolDataProvider()), user, tokens[i], tokenPrices[i]); + } + + return (tokensData, getUserData(AaveLendingPool(addrProvider.getLendingPool()), user)); + } +} + +contract InstaAaveResolver is Resolver { + string public constant name = "Aave-v2-Resolver"; +} \ No newline at end of file From b97a1ade1d207170206ac14c31ba43ccfc6e07e8 Mon Sep 17 00:00:00 2001 From: Mubaris NK Date: Mon, 16 Nov 2020 17:18:00 +0530 Subject: [PATCH 3/4] Revert "Add uniswap v2 path finder algo" This reverts commit 191b0d09310c12280689ce092e9ee77234054ed5. --- contracts/protocols/uniswapV2.sol | 178 ------------------------------ 1 file changed, 178 deletions(-) diff --git a/contracts/protocols/uniswapV2.sol b/contracts/protocols/uniswapV2.sol index daca76c..1e36002 100644 --- a/contracts/protocols/uniswapV2.sol +++ b/contracts/protocols/uniswapV2.sol @@ -85,22 +85,6 @@ contract UniswapHelpers is Helpers { _sell = sell == getEthAddr() ? TokenInterface(getAddressWETH()) : TokenInterface(sell); } - function checkPaths( - IUniswapV2Router02 router, - address[] memory paths - ) internal view returns(bool isValid) { - isValid = true; - for (uint i; i < paths.length - 1; i++) { - if (paths[i] == paths[i + 1]) { - return false; - } - address pair = IUniswapV2Factory(router.factory()).getPair(paths[i], paths[i + 1]); - if (pair == address(0)) { - return false; - } - } - } - function getExpectedBuyAmt( address buyAddr, address sellAddr, @@ -189,40 +173,6 @@ contract UniswapHelpers is Helpers { amtA = wmul(_tokenA.balanceOf(exchangeAddr), share); amtB = wmul(_tokenB.balanceOf(exchangeAddr), share); } - - function _getExpectedBuyAmtByPath( - address[] memory paths, - uint sellAmt - ) internal view returns(uint buyAmt) { - IUniswapV2Router02 router = IUniswapV2Router02(getUniswapAddr()); - - if (checkPaths(router, paths)) { - uint[] memory amts = router.getAmountsOut( - sellAmt, - paths - ); - buyAmt = amts[amts.length - 1]; - } else { - buyAmt = 0; - } - } - - function _getExpectedSellAmtByPath( - address[] memory paths, - uint buyAmt - ) internal view returns(uint sellAmt) { - IUniswapV2Router02 router = IUniswapV2Router02(getUniswapAddr()); - - if (checkPaths(router, paths)) { - uint[] memory amts = router.getAmountsIn( - buyAmt, - paths - ); - sellAmt = amts[0]; - } else { - sellAmt = uint(-1); - } - } } @@ -343,134 +293,6 @@ contract Resolver is UniswapHelpers { } return poolData; } - - function getOptimalSellPath( - address buyAddr, - address sellAddr, - address[] memory tokens, - uint sellAmt, - uint slippage - ) public view returns (address[] memory paths, uint buyAmt, uint unitAmt) - { - (TokenInterface _buyAddr, TokenInterface _sellAddr) = changeEthAddress(buyAddr, sellAddr); - - address[] memory _path = new address[](2); - _path[0] = address(_sellAddr); - _path[1] = address(_buyAddr); - - paths = _path; - buyAmt = _getExpectedBuyAmtByPath(_path, sellAmt); - - _path = new address[](3); - _path[0] = address(_sellAddr); - _path[2] = address(_buyAddr); - - uint i; - uint j; - uint _buyAmt; - - for(i = 0; i < tokens.length; i++) { - _path[1] = tokens[i]; - - _buyAmt = _getExpectedBuyAmtByPath(_path, sellAmt); - - if (_buyAmt > buyAmt) { - buyAmt = _buyAmt; - paths = new address[](3); - paths[0] = _path[0]; - paths[1] = _path[1]; - paths[2] = _path[2]; - } - } - - _path = new address[](4); - _path[0] = address(_sellAddr); - _path[3] = address(_buyAddr); - - for(i = 0; i < tokens.length; i++) { - for(j = 0; j < tokens.length; j++) { - _path[1] = tokens[i]; - _path[2] = tokens[j]; - - _buyAmt = _getExpectedBuyAmtByPath(_path, sellAmt); - - if (_buyAmt > buyAmt) { - buyAmt = _buyAmt; - paths = new address[](4); - paths[0] = _path[0]; - paths[1] = _path[1]; - paths[2] = _path[2]; - paths[3] = _path[3]; - } - } - } - - unitAmt = getBuyUnitAmt(_buyAddr, buyAmt, _sellAddr, sellAmt, slippage); - } - - function getOptimalBuyPath( - address buyAddr, - address sellAddr, - address[] memory tokens, - uint buyAmt, - uint slippage - ) public view returns (address[] memory paths, uint sellAmt, uint unitAmt) - { - (TokenInterface _buyAddr, TokenInterface _sellAddr) = changeEthAddress(buyAddr, sellAddr); - - address[] memory _path = new address[](2); - _path[0] = address(_sellAddr); - _path[1] = address(_buyAddr); - - paths = _path; - sellAmt = _getExpectedSellAmtByPath(_path, buyAmt); - - _path = new address[](3); - _path[0] = address(_sellAddr); - _path[2] = address(_buyAddr); - - uint i; - uint j; - uint _sellAmt; - - for(i = 0; i < tokens.length; i++) { - _path[1] = tokens[i]; - - _sellAmt = _getExpectedSellAmtByPath(_path, buyAmt); - - if (_sellAmt < sellAmt) { - sellAmt = _sellAmt; - paths = new address[](3); - paths[0] = _path[0]; - paths[1] = _path[1]; - paths[2] = _path[2]; - } - } - - _path = new address[](4); - _path[0] = address(_sellAddr); - _path[3] = address(_buyAddr); - - for(i = 0; i < tokens.length; i++) { - for(j = 0; j < tokens.length; j++) { - _path[1] = tokens[i]; - _path[2] = tokens[j]; - - _sellAmt = _getExpectedSellAmtByPath(_path, buyAmt); - - if (_sellAmt < sellAmt) { - sellAmt = _sellAmt; - paths = new address[](4); - paths[0] = _path[0]; - paths[1] = _path[1]; - paths[2] = _path[2]; - paths[3] = _path[3]; - } - } - } - - unitAmt = getSellUnitAmt(_sellAddr, sellAmt, _buyAddr, buyAmt, slippage); - } } From 0c6dd6fb0f746f2fdd2b1663adf636702684f5a1 Mon Sep 17 00:00:00 2001 From: Mubaris NK Date: Mon, 16 Nov 2020 17:18:09 +0530 Subject: [PATCH 4/4] Remove comments --- contracts/protocols/aave_v2.sol | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/contracts/protocols/aave_v2.sol b/contracts/protocols/aave_v2.sol index db106bb..83691c9 100644 --- a/contracts/protocols/aave_v2.sol +++ b/contracts/protocols/aave_v2.sol @@ -188,17 +188,6 @@ contract AaveHelpers is DSMath { tokenData.tokenPrice = price; tokenData.aaveTokenData = aaveTokenData; - - // tokenData = AaveUserTokenData( - // price, - // supplyBal, - // stableDebtBal, - // variableDebtBal, - // liquidityRate, - // stableBorrowRate, - // variableBorrowRate, - // aaveTokenData - // ); } function getUserData(AaveLendingPool aave, address user) @@ -226,9 +215,6 @@ contract AaveHelpers is DSMath { contract Resolver is AaveHelpers { function getPosition(address user, address[] memory tokens) public view returns(AaveUserTokenData[] memory, AaveUserData memory) { AaveAddressProvider addrProvider = AaveAddressProvider(getAaveAddressProvider()); - // AavePriceOracle priceOracle = AavePriceOracle(addrProvider.getPriceOracle()); - // AaveProtocolDataProvider aaveData = AaveProtocolDataProvider(getAaveProtocolDataProvider()); - // AaveLendingPool aave = AaveLendingPool(addrProvider.getLendingPool()); AaveUserTokenData[] memory tokensData = new AaveUserTokenData[](tokens.length); uint[] memory tokenPrices = AavePriceOracle(addrProvider.getPriceOracle()).getAssetsPrices(tokens);