diff --git a/contracts/protocols/aave_v2.sol b/contracts/protocols/aave_v2.sol index c480c12..2cf4595 100644 --- a/contracts/protocols/aave_v2.sol +++ b/contracts/protocols/aave_v2.sol @@ -152,6 +152,7 @@ contract AaveHelpers is DSMath { uint variableBorrowBalance; uint supplyRate; uint stableBorrowRate; + uint userStableBorrowRate; uint variableBorrowRate; bool isCollateral; AaveTokenData aaveTokenData; @@ -230,7 +231,9 @@ contract AaveHelpers is DSMath { tokenData.supplyBalance, tokenData.stableBorrowBalance, tokenData.variableBorrowBalance, - ,,,,, + ,, + tokenData.userStableBorrowRate, + ,, tokenData.isCollateral ) = aaveData.getUserReserveData(token, user); @@ -300,5 +303,5 @@ contract Resolver is AaveHelpers { } contract InstaAaveV2Resolver is Resolver { - string public constant name = "AaveV2-Resolver-v1.3"; + string public constant name = "AaveV2-Resolver-v1.4"; } diff --git a/contracts/protocols/reflexer.sol b/contracts/protocols/reflexer.sol new file mode 100644 index 0000000..0f03393 --- /dev/null +++ b/contracts/protocols/reflexer.sol @@ -0,0 +1,272 @@ +/** + *Submitted for verification at Etherscan.io on 2020-07-29 +*/ + +pragma solidity ^0.6.0; +pragma experimental ABIEncoderV2; + +interface ManagerLike { + function collateralTypes(uint) external view returns (bytes32); + function ownsSAFE(uint) external view returns (address); + function safes(uint) external view returns (address); + function safeEngine() external view returns (address); +} + +interface GetSafesLike { + function getSafesAsc(address, address) external view returns (uint[] memory, address[] memory, bytes32[] memory); +} + +interface SAFEEngineLike { + function collateralTypes(bytes32) external view returns (uint, uint, uint, uint, uint); + function coinBalance(address) external view returns (uint); + function safes(bytes32, address) external view returns (uint, uint); + function tokenCollateral(bytes32, address) external view returns (uint); +} + +interface TaxCollectorLike { + function collateralTypes(bytes32) external view returns (uint, uint); + function globalStabilityFee() external view returns (uint); +} + +interface OracleRelayerLike { + function collateralTypes(bytes32) external view returns (OracleLike, uint, uint); + function redemptionRate() external view returns (uint); + +} + +interface OracleLike { + function getResultWithValidity() external view returns (bytes32, bool); +} + +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 Helpers is DSMath { + + struct SafeData { + uint id; + address owner; + string colType; + uint collateral; + uint debt; + uint adjustedDebt; + uint liquidatedCol; + uint borrowRate; + uint colPrice; + uint liquidationRatio; + address safeAddress; + } + + struct ColInfo { + uint borrowRate; + uint price; + uint liquidationRatio; + uint debtCeiling; + uint debtFloor; + uint totalDebt; + } + + struct ReflexerAddresses { + address manager; + address safeEngine; + address taxCollector; + address oracleRelayer; + address getSafes; + } + + /** + * @dev get Reflexer Address contract + */ + function getReflexerAddresses() public pure returns (ReflexerAddresses memory) { + return ReflexerAddresses( + 0xEfe0B4cA532769a3AE758fD82E1426a03A94F185, // manager + 0xCC88a9d330da1133Df3A7bD823B95e52511A6962, // safeEngine + 0xcDB05aEda142a1B0D6044C09C64e4226c1a281EB, // taxCollector + 0x4ed9C0dCa0479bC64d8f4EB3007126D5791f7851, // oracleRelayer + 0xdf4BC9aA98cC8eCd90Ba2BEe73aD4a1a9C8d202B // getSafes + ); + } + + /** + * @dev Convert String to bytes32. + */ + function stringToBytes32(string memory str) internal pure returns (bytes32 result) { + require(bytes(str).length != 0, "String-Empty"); + // solium-disable-next-line security/no-inline-assembly + assembly { + result := mload(add(str, 32)) + } + } + + /** + * @dev Convert bytes32 to String. + */ + function bytes32ToString(bytes32 _bytes32) internal pure returns (string memory) { + bytes32 _temp; + uint count; + for (uint256 i; i < 32; i++) { + _temp = _bytes32[i]; + if( _temp != bytes32(0)) { + count += 1; + } + } + bytes memory bytesArray = new bytes(count); + for (uint256 i; i < count; i++) { + bytesArray[i] = (_bytes32[i]); + } + return (string(bytesArray)); + } + + + function getFee(bytes32 collateralType) internal view returns (uint fee) { + address taxCollector = getReflexerAddresses().taxCollector; + (uint stabilityFee,) = TaxCollectorLike(taxCollector).collateralTypes(collateralType); + uint globalStabilityFee = TaxCollectorLike(taxCollector).globalStabilityFee(); + fee = add(stabilityFee, globalStabilityFee); + } + + function getColPrice(bytes32 collateralType) internal view returns (uint price) { + address oracleRelayer = getReflexerAddresses().oracleRelayer; + address safeEngine = getReflexerAddresses().safeEngine; + (, uint safetyCRatio,) = OracleRelayerLike(oracleRelayer).collateralTypes(collateralType); + (,,uint spotPrice,,) = SAFEEngineLike(safeEngine).collateralTypes(collateralType); + price = rmul(safetyCRatio, spotPrice); + } + + function getColRatio(bytes32 collateralType) internal view returns (uint ratio) { + address oracleRelayer = getReflexerAddresses().oracleRelayer; + (, ratio,) = OracleRelayerLike(oracleRelayer).collateralTypes(collateralType); + } + + function getDebtState(bytes32 collateralType) internal view returns (uint debtCeiling, uint debtFloor, uint totalDebt) { + address safeEngine = getReflexerAddresses().safeEngine; + (uint globalDebt,uint rate,,uint debtCeilingRad, uint debtFloorRad) = SAFEEngineLike(safeEngine).collateralTypes(collateralType); + debtCeiling = debtCeilingRad / 10 ** 45; + debtFloor = debtFloorRad / 10 ** 45; + totalDebt = rmul(globalDebt, rate); + } +} + + +contract SafeResolver is Helpers { + function getSafes(address owner) external view returns (SafeData[] memory) { + address manager = getReflexerAddresses().manager; + address safeManger = getReflexerAddresses().getSafes; + + (uint[] memory ids, address[] memory handlers, bytes32[] memory collateralTypes) = GetSafesLike(safeManger).getSafesAsc(manager, owner); + SafeData[] memory safes = new SafeData[](ids.length); + + for (uint i = 0; i < ids.length; i++) { + (uint collateral, uint debt) = SAFEEngineLike(ManagerLike(manager).safeEngine()).safes(collateralTypes[i], handlers[i]); + (,uint rate, uint priceMargin,,) = SAFEEngineLike(ManagerLike(manager).safeEngine()).collateralTypes(collateralTypes[i]); + uint safetyCRatio = getColRatio(collateralTypes[i]); + + safes[i] = SafeData( + ids[i], + owner, + bytes32ToString(collateralTypes[i]), + collateral, + debt, + rmul(debt,rate), + SAFEEngineLike(ManagerLike(manager).safeEngine()).tokenCollateral(collateralTypes[i], handlers[i]), + getFee(collateralTypes[i]), + rmul(priceMargin, safetyCRatio), + safetyCRatio, + handlers[i] + ); + } + return safes; + } + + function getSafeById(uint id) external view returns (SafeData memory) { + address manager = getReflexerAddresses().manager; + address handler = ManagerLike(manager).safes(id); + bytes32 collateralType = ManagerLike(manager).collateralTypes(id); + + (uint collateral, uint debt) = SAFEEngineLike(ManagerLike(manager).safeEngine()).safes(collateralType, handler); + (,uint rate, uint priceMargin,,) = SAFEEngineLike(ManagerLike(manager).safeEngine()).collateralTypes(collateralType); + + uint safetyCRatio = getColRatio(collateralType); + + uint feeRate = getFee(collateralType); + SafeData memory safe = SafeData( + id, + ManagerLike(manager).ownsSAFE(id), + bytes32ToString(collateralType), + collateral, + debt, + rmul(debt,rate), + SAFEEngineLike(ManagerLike(manager).safeEngine()).tokenCollateral(collateralType, handler), + feeRate, + rmul(priceMargin, safetyCRatio), + safetyCRatio, + handler + ); + return safe; + } + + function getColInfo(string[] memory name) public view returns (ColInfo[] memory) { + ColInfo[] memory colInfo = new ColInfo[](name.length); + + for (uint i = 0; i < name.length; i++) { + bytes32 collateralType = stringToBytes32(name[i]); + (uint debtCeiling, uint debtFloor, uint totalDebt) = getDebtState(collateralType); + colInfo[i] = ColInfo( + getFee(collateralType), + getColPrice(collateralType), + getColRatio(collateralType), + debtCeiling, + debtFloor, + totalDebt + ); + } + return colInfo; + } + +} + + +contract RedemptionRateResolver is SafeResolver { + function getRedemptionRate() external view returns (uint redemptionRate) { + address oracleRelayer = getReflexerAddresses().oracleRelayer; + redemptionRate = OracleRelayerLike(oracleRelayer).redemptionRate(); + } +} + + +contract InstaReflexerResolver is RedemptionRateResolver { + string public constant name = "Reflexer-Resolver-v1"; +} \ No newline at end of file