From 84a32944e68d844375f0bb47bf04a7cecd73df88 Mon Sep 17 00:00:00 2001 From: Thrilok Kumar Date: Tue, 30 Jun 2020 04:41:35 +0530 Subject: [PATCH] Added sbtc curve resolver and refactored susd pool --- contracts/protocols/curve_sbtc.sol | 189 ++++++++++++++++++ .../protocols/{curve.sol => curve_susd.sol} | 90 +++------ 2 files changed, 218 insertions(+), 61 deletions(-) create mode 100644 contracts/protocols/curve_sbtc.sol rename contracts/protocols/{curve.sol => curve_susd.sol} (69%) diff --git a/contracts/protocols/curve_sbtc.sol b/contracts/protocols/curve_sbtc.sol new file mode 100644 index 0000000..af6177c --- /dev/null +++ b/contracts/protocols/curve_sbtc.sol @@ -0,0 +1,189 @@ +pragma solidity ^0.6.0; +pragma experimental ABIEncoderV2; + +interface ICurve { + function get_virtual_price() external view returns (uint256 out); + + function coins(int128 tokenId) external view returns (address token); + + function calc_token_amount(uint256[3] calldata amounts, bool deposit) external view returns (uint256 amount); + + function get_dy(int128 sellTokenId, int128 buyTokenId, uint256 sellTokenAmt) external view returns (uint256 buyTokenAmt); +} + +interface TokenInterface { + function decimals() external view returns (uint); + function totalSupply() external view returns (uint256); + function balanceOf(address) external view returns (uint); +} + + +contract DSMath { + + function add(uint x, uint y) internal pure returns (uint z) { + require((z = x + y) >= x, "math-not-safe"); + } + + function mul(uint x, uint y) internal pure returns (uint z) { + require(y == 0 || (z = x * y) / y == x, "math-not-safe"); + } + + function sub(uint x, uint y) internal pure returns (uint z) { + require((z = x - y) <= x, "sub-overflow"); + } + + uint constant WAD = 10 ** 18; + + function wmul(uint x, uint y) internal pure returns (uint z) { + z = add(mul(x, y), WAD / 2) / WAD; + } + + function wdiv(uint x, uint y) internal pure returns (uint z) { + z = add(mul(x, WAD), y / 2) / y; + } + +} + +contract CurveHelpers is DSMath { + /** + * @dev Return Curve sBTC Swap Address + */ + function getCurveSwapAddr() internal pure returns (address) { + return 0x7fC77b5c7614E1533320Ea6DDc2Eb61fa00A9714; + } + + /** + * @dev Return Curve sBTC Token Address + */ + function getCurveTokenAddr() internal pure returns (address) { + return 0x075b1bb99792c9E1041bA13afEf80C91a1e70fB3; + } + + function getTokenI(address token) internal pure returns (int128 i) { + if (token == address(0xEB4C2781e4ebA804CE9a9803C67d0893436bB27D)) { + // renBTC Token + i = 0; + } else if (token == address(0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599)) { + // WBTC Token + i = 1; + } else if (token == address(0xfE18be6b3Bd88A2D2A7f928d00292E7a9963CfC6)) { + // sBTC Token + i = 2; + } else { + revert("token-not-found."); + } + } + + function convertTo18(uint _dec, uint256 _amt) internal pure returns (uint256 amt) { + amt = mul(_amt, 10 ** (18 - _dec)); + } + + function convert18ToDec(uint _dec, uint256 _amt) internal pure returns (uint256 amt) { + amt = (_amt / 10 ** (18 - _dec)); + } + + function getBuyUnitAmt( + address buyAddr, + address sellAddr, + uint sellAmt, + uint buyAmt, + uint slippage + ) internal view returns (uint unitAmt) { + uint _sellAmt = convertTo18(TokenInterface(sellAddr).decimals(), sellAmt); + uint _buyAmt = convertTo18(TokenInterface(buyAddr).decimals(), buyAmt); + unitAmt = wdiv(_buyAmt, _sellAmt); + unitAmt = wmul(unitAmt, sub(WAD, slippage)); + } + + function getDepositUnitAmt( + address token, + uint depositAmt, + uint curveAmt, + uint slippage + ) internal view returns (uint unitAmt) { + uint _depositAmt = convertTo18(TokenInterface(token).decimals(), depositAmt); + uint _curveAmt = convertTo18(TokenInterface(getCurveTokenAddr()).decimals(), curveAmt); + unitAmt = wdiv(_curveAmt, _depositAmt); + unitAmt = wmul(unitAmt, sub(WAD, slippage)); + } + + function getWithdrawtUnitAmt( + address token, + uint withdrawAmt, + uint curveAmt, + uint slippage + ) internal view returns (uint unitAmt) { + uint _withdrawAmt = convertTo18(TokenInterface(token).decimals(), withdrawAmt); + uint _curveAmt = convertTo18(TokenInterface(getCurveTokenAddr()).decimals(), curveAmt); + unitAmt = wdiv(_curveAmt, _withdrawAmt); + unitAmt = wmul(unitAmt, add(WAD, slippage)); + } +} + + +contract Resolver is CurveHelpers { + + function getBuyAmount(address buyAddr, address sellAddr, uint sellAmt, uint slippage) + public + view + returns (uint buyAmt, uint unitAmt, uint virtualPrice) + { + ICurve curve = ICurve(getCurveSwapAddr()); + buyAmt = curve.get_dy(getTokenI(sellAddr), getTokenI(buyAddr), sellAmt); + virtualPrice = curve.get_virtual_price(); + unitAmt = getBuyUnitAmt(buyAddr, sellAddr, sellAmt, buyAmt, slippage); + } + + function getDepositAmount(address token, uint depositAmt, uint slippage) + public + view + returns (uint curveAmt, uint unitAmt, uint virtualPrice) + { + uint[3] memory amts; + amts[uint(getTokenI(token))] = depositAmt; + ICurve curve = ICurve(getCurveSwapAddr()); + curveAmt = curve.calc_token_amount(amts, true); + virtualPrice = curve.get_virtual_price(); + unitAmt = getDepositUnitAmt(token, depositAmt, curveAmt, slippage); + } + + function getWithdrawAmount(address token, uint withdrawAmt, uint slippage) + public + view + returns (uint curveAmt, uint unitAmt, uint virtualPrice) + { + uint[3] memory amts; + amts[uint(getTokenI(token))] = withdrawAmt; + ICurve curve = ICurve(getCurveSwapAddr()); + curveAmt = curve.calc_token_amount(amts, false); + virtualPrice = curve.get_virtual_price(); + unitAmt = getWithdrawtUnitAmt(token, withdrawAmt, curveAmt, slippage); + } + + function getPosition( + address user + ) public view returns ( + uint userBal, + uint totalSupply, + uint virtualPrice, + uint userShare, + uint poolRenBtcBal, + uint poolWbtcBal, + uint poolSbtcBal + ) { + TokenInterface curveToken = TokenInterface(getCurveTokenAddr()); + userBal = curveToken.balanceOf(user); + totalSupply = curveToken.totalSupply(); + userShare = wdiv(userBal, totalSupply); + ICurve curveContract = ICurve(getCurveSwapAddr()); + virtualPrice = curveContract.get_virtual_price(); + poolRenBtcBal = TokenInterface(curveContract.coins(0)).balanceOf(getCurveSwapAddr()); + poolWbtcBal = TokenInterface(curveContract.coins(1)).balanceOf(getCurveSwapAddr()); + poolSbtcBal = TokenInterface(curveContract.coins(2)).balanceOf(getCurveSwapAddr()); + } +} + + +contract InstaCurveResolver is Resolver { + string public constant name = "Curve-sBTC-Resolver-v1"; +} \ No newline at end of file diff --git a/contracts/protocols/curve.sol b/contracts/protocols/curve_susd.sol similarity index 69% rename from contracts/protocols/curve.sol rename to contracts/protocols/curve_susd.sol index df87d9c..9719bfb 100644 --- a/contracts/protocols/curve.sol +++ b/contracts/protocols/curve_susd.sol @@ -2,33 +2,10 @@ pragma solidity ^0.6.0; pragma experimental ABIEncoderV2; interface ICurve { - function get_virtual_price() external returns (uint256 out); - + function get_virtual_price() external view returns (uint256 out); function underlying_coins(int128 tokenId) external view returns (address token); - function calc_token_amount(uint256[4] calldata amounts, bool deposit) external view returns (uint256 amount); - function get_dy(int128 sellTokenId, int128 buyTokenId, uint256 sellTokenAmt) external view returns (uint256 buyTokenAmt); - - // Used when there's an underlying token. Example:- cdai, cusdc, etc. If not then - function get_dy_underlying(int128 sellTokenId, int128 buyTokenId, uint256 sellTokenAmt) external returns (uint256 buyTokenAmt); - - function exchange(int128 sellTokenId, int128 buyTokenId, uint256 sellTokenAmt, uint256 minBuyToken) external; - - // Used when there's an underlying token. Example:- cdai, cusdc, etc. - function exchange_underlying(int128 sellTokenId, int128 buyTokenId, uint256 sellTokenAmt, uint256 minBuyToken) external; - - function remove_liquidity(uint256 _amount, uint256[4] calldata min_amounts) external; - - function remove_liquidity_imbalance(uint256[4] calldata amounts, uint256 max_burn_amount) external; -} - -interface ICurveZap { - - function calc_withdraw_one_coin(uint256 _token_amount, int128 i) external returns (uint256 amount); - - function remove_liquidity_one_coin(uint256 _token_amount, int128 i, uint256 min_uamount) external; - } interface TokenInterface { @@ -64,18 +41,7 @@ contract DSMath { } - -contract Helpers is DSMath { - /** - * @dev get Ethereum address - */ - function getAddressETH() public pure returns (address) { - return 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; - } -} - - -contract CurveHelpers is Helpers { +contract CurveHelpers is DSMath { /** * @dev Return Curve Swap Address */ @@ -90,13 +56,6 @@ contract CurveHelpers is Helpers { return 0xC25a3A3b969415c80451098fa907EC722572917F; } - /** - * @dev Return Curve Zap Address - */ - function getCurveZapAddr() internal pure returns (address) { - return 0xFCBa3E75865d2d561BE8D220616520c171F12851; - } - function getTokenI(address token) internal pure returns (int128 i) { if (token == address(0x6B175474E89094C44Da98b954EedeAC495271d0F)) { // DAI Token @@ -115,16 +74,6 @@ contract CurveHelpers is Helpers { } } - function getTokenAddr(ICurve curve, uint256 i) internal view returns (address token) { - token = curve.underlying_coins(int128(i)); - require(token != address(0), "token-not-found."); - } - - function getTokenDecimals(address buy, address sell) internal view returns(uint _buyDec, uint _sellDec){ - _buyDec = buy == getAddressETH() ? 18 : TokenInterface(buy).decimals(); - _sellDec = sell == getAddressETH() ? 18 : TokenInterface(sell).decimals(); - } - function convertTo18(uint _dec, uint256 _amt) internal pure returns (uint256 amt) { amt = mul(_amt, 10 ** (18 - _dec)); } @@ -174,23 +123,40 @@ contract CurveHelpers is Helpers { contract Resolver is CurveHelpers { - function getBuyAmount(address buyAddr, address sellAddr, uint sellAmt, uint slippage) public view returns (uint buyAmt, uint unitAmt) { - buyAmt = ICurve(getCurveSwapAddr()).get_dy(getTokenI(sellAddr), getTokenI(buyAddr), sellAmt); + function getBuyAmount(address buyAddr, address sellAddr, uint sellAmt, uint slippage) + public + view + returns (uint buyAmt, uint unitAmt, uint virtualPrice) + { + ICurve curve = ICurve(getCurveSwapAddr()); + buyAmt = curve.get_dy(getTokenI(sellAddr), getTokenI(buyAddr), sellAmt); + virtualPrice = curve.get_virtual_price(); unitAmt = getBuyUnitAmt(buyAddr, sellAddr, sellAmt, buyAmt, slippage); } - function getDepositAmount(address token, uint depositAmt, uint slippage) public view returns (uint curveAmt, uint unitAmt) { + function getDepositAmount(address token, uint depositAmt, uint slippage) + public + view + returns (uint curveAmt, uint unitAmt, uint virtualPrice) + { uint[4] memory amts; amts[uint(getTokenI(token))] = depositAmt; - curveAmt = ICurve(getCurveSwapAddr()).calc_token_amount(amts, true); + ICurve curve = ICurve(getCurveSwapAddr()); + curveAmt = curve.calc_token_amount(amts, true); + virtualPrice = curve.get_virtual_price(); unitAmt = getDepositUnitAmt(token, depositAmt, curveAmt, slippage); } - - function getWithdrawAmount(address token, uint withdrawAmt, uint slippage) public view returns (uint curveAmt, uint unitAmt) { + function getWithdrawAmount(address token, uint withdrawAmt, uint slippage) + public + view + returns (uint curveAmt, uint unitAmt, uint virtualPrice) + { uint[4] memory amts; amts[uint(getTokenI(token))] = withdrawAmt; - curveAmt = ICurve(getCurveSwapAddr()).calc_token_amount(amts, false); + ICurve curve = ICurve(getCurveSwapAddr()); + curveAmt = curve.calc_token_amount(amts, false); + virtualPrice = curve.get_virtual_price(); unitAmt = getWithdrawtUnitAmt(token, withdrawAmt, curveAmt, slippage); } @@ -199,6 +165,7 @@ contract Resolver is CurveHelpers { ) public view returns ( uint userBal, uint totalSupply, + uint virtualPrice, uint userShare, uint poolDaiBal, uint poolUsdcBal, @@ -210,6 +177,7 @@ contract Resolver is CurveHelpers { totalSupply = curveToken.totalSupply(); userShare = wdiv(userBal, totalSupply); ICurve curveContract = ICurve(getCurveSwapAddr()); + virtualPrice = curveContract.get_virtual_price(); poolDaiBal = TokenInterface(curveContract.underlying_coins(0)).balanceOf(getCurveSwapAddr()); poolUsdcBal = TokenInterface(curveContract.underlying_coins(1)).balanceOf(getCurveSwapAddr()); poolUsdtBal = TokenInterface(curveContract.underlying_coins(2)).balanceOf(getCurveSwapAddr()); @@ -219,5 +187,5 @@ contract Resolver is CurveHelpers { contract InstaCurveResolver is Resolver { - string public constant name = "Curve-Resolver-v1"; + string public constant name = "Curve-SUSD-Resolver-v1.1"; } \ No newline at end of file