From e5f418157faeee1c1f662ef382b2cc8c26609944 Mon Sep 17 00:00:00 2001 From: Lecky Lao Date: Tue, 30 Jun 2020 02:15:35 +1000 Subject: [PATCH] Updated math.sol to use SafeMath from OZ; update migration to deploy CurveSBTCProtocol; Added Curvesbtc.sol sell method and got it compiled; --- contracts/common/math.sol | 53 +++++++------ contracts/connectors/curvesbtc.sol | 115 +++++++++++++++++++++++++++++ migrations/2_deploy_connector.js | 6 +- 3 files changed, 148 insertions(+), 26 deletions(-) create mode 100644 contracts/connectors/curvesbtc.sol diff --git a/contracts/common/math.sol b/contracts/common/math.sol index b80bf47..cc3e20e 100644 --- a/contracts/common/math.sol +++ b/contracts/common/math.sol @@ -1,36 +1,41 @@ pragma solidity ^0.6.0; +import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol"; + contract DSMath { - uint constant WAD = 10 ** 18; - uint constant RAY = 10 ** 27; + uint constant WAD = 10 ** 18; + uint constant RAY = 10 ** 27; - function add(uint x, uint y) internal pure returns (uint z) { - require((z = x + y) >= x, "math-not-safe"); - } + function add(uint x, uint y) internal pure returns (uint z) { + SafeMath.add(x, y); + } - function sub(uint x, uint y) internal pure returns (uint z) { - require((z = x - y) <= x, "ds-math-sub-underflow"); - } + function sub(uint x, uint y) internal pure returns (uint z) { + SafeMath.sub(x, y); + } - function mul(uint x, uint y) internal pure returns (uint z) { - require(y == 0 || (z = x * y) / y == x, "math-not-safe"); - } + function mul(uint x, uint y) internal pure returns (uint z) { + SafeMath.mul(x, y); + } + function div(uint x, uint y) internal pure returns (uint z) { + SafeMath.div(x, y); + } - function wmul(uint x, uint y) internal pure returns (uint z) { - z = add(mul(x, y), WAD / 2) / WAD; - } + function wmul(uint x, uint y) internal pure returns (uint z) { + z = SafeMath.add(SafeMath.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; - } + function wdiv(uint x, uint y) internal pure returns (uint z) { + z = SafeMath.add(SafeMath.mul(x, WAD), y / 2) / y; + } - function rdiv(uint x, uint y) internal pure returns (uint z) { - z = add(mul(x, RAY), y / 2) / y; - } + function rdiv(uint x, uint y) internal pure returns (uint z) { + z = SafeMath.add(SafeMath.mul(x, RAY), y / 2) / y; + } - function rmul(uint x, uint y) internal pure returns (uint z) { - z = add(mul(x, y), RAY / 2) / RAY; - } + function rmul(uint x, uint y) internal pure returns (uint z) { + z = SafeMath.add(SafeMath.mul(x, y), RAY / 2) / RAY; + } -} \ No newline at end of file +} diff --git a/contracts/connectors/curvesbtc.sol b/contracts/connectors/curvesbtc.sol new file mode 100644 index 0000000..5a802a4 --- /dev/null +++ b/contracts/connectors/curvesbtc.sol @@ -0,0 +1,115 @@ +pragma solidity ^0.6.0; + +// import files from common directory +import { MemoryInterface, EventInterface} from "../common/interfaces.sol"; +import { Stores } from "../common/stores.sol"; +import { DSMath } from "../common/math.sol"; + +// import files from OZ +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {SafeCast} from "@openzeppelin/contracts/utils/SafeCast.sol"; + +interface ICurve { + function coins(int128 tokenId) external view returns (address token); + function calc_token_amount(uint256[3] calldata amounts, bool deposit) external returns (uint256 amount); + function add_liquidity(uint256[3] calldata amounts, uint256 min_mint_amount) external; + function get_dy(int128 sellTokenId, int128 buyTokenId, uint256 sellTokenAmt) external returns (uint256 buyTokenAmt); + function exchange(int128 sellTokenId, int128 buyTokenId, uint256 sellTokenAmt, uint256 minBuyToken) external; + function remove_liquidity_imbalance(uint256[3] calldata amounts, uint256 max_burn_amount) external; + function calc_withdraw_one_coin(uint256 _token_amount, int128 i) external returns (uint256 amount); +} + +contract CurveSBTCHelpers is Stores, DSMath{ + /** + * @dev Return Curve Swap Address + */ + function getCurveSwapAddr() internal pure returns (address) { + return 0x7fC77b5c7614E1533320Ea6DDc2Eb61fa00A9714; + } + + /** + * @dev Return Curve Token Address + */ + function getCurveTokenAddr() internal pure returns (address) { + return 0x075b1bb99792c9E1041bA13afEf80C91a1e70fB3; + } + + function convert18ToDec(uint _dec, uint256 _amt) internal pure returns (uint256 amt) { + amt = div(_amt, 10 ** (18 - _dec)); + } + + function convertTo18(uint _dec, uint256 _amt) internal pure returns (uint256 amt) { + amt = mul(_amt, 10 ** (18 - _dec)); + } + + 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."); + } + } +} + +contract CurveSBTCProtocol is CurveSBTCHelpers { + + // Events + event LogSell( + address indexed buyToken, + address indexed sellToken, + uint256 buyAmt, + uint256 sellAmt, + uint256 getId, + uint256 setId + ); + event LogDeposit(address token, uint256 amt, uint256 mintAmt, uint256 getId, uint256 setId); + event LogWithdraw(address token, uint256 amt, uint256 burnAmt, uint256 getId, uint256 setId); + + /** + * @dev Sell Stable ERC20_Token. + * @param buyAddr buying token address. + * @param sellAddr selling token amount. + * @param sellAmt selling token amount. + * @param unitAmt unit amount of buyAmt/sellAmt with slippage. + * @param getId Get token amount at this ID from `InstaMemory` Contract. + * @param setId Set token amount at this ID in `InstaMemory` Contract. + */ + function sell( + address buyAddr, + address sellAddr, + uint sellAmt, + uint unitAmt, + uint getId, + uint setId + ) external payable { + uint _sellAmt = getUint(getId, sellAmt); + ICurve curve = ICurve(getCurveSwapAddr()); + ERC20 _buyToken = ERC20(buyAddr); + ERC20 _sellToken = ERC20(sellAddr); + _sellAmt = _sellAmt == uint(-1) ? _sellToken.balanceOf(address(this)) : _sellAmt; + _sellToken.approve(address(curve), _sellAmt); + + uint _slippageAmt = convert18ToDec(_buyToken.decimals(), wmul(unitAmt, convertTo18(_sellToken.decimals(), _sellAmt))); + + uint intialBal = _buyToken.balanceOf(address(this)); + curve.exchange(getTokenI(sellAddr), getTokenI(buyAddr), _sellAmt, _slippageAmt); + uint finalBal = _buyToken.balanceOf(address(this)); + + uint _buyAmt = sub(finalBal, intialBal); + + setUint(setId, _buyAmt); + + emit LogSell(buyAddr, sellAddr, _buyAmt, _sellAmt, getId, setId); + bytes32 _eventCode = keccak256("LogSell(address,address,uint256,uint256,uint256,uint256)"); + bytes memory _eventParam = abi.encode(buyAddr, sellAddr, _buyAmt, _sellAmt, getId, setId); + emitEvent(_eventCode, _eventParam); + } + +} diff --git a/migrations/2_deploy_connector.js b/migrations/2_deploy_connector.js index f3bea19..d3f69ce 100644 --- a/migrations/2_deploy_connector.js +++ b/migrations/2_deploy_connector.js @@ -1,5 +1,7 @@ -const Connector = artifacts.require("CurveProtocol"); // Change the Connector name while deploying. +const CurveProtocol = artifacts.require("CurveProtocol"); +const CurveSBTCProtocol = artifacts.require("CurveSBTCProtocol"); module.exports = function(deployer) { - deployer.deploy(Connector); + deployer.deploy(CurveProtocol); + deployer.deploy(CurveSBTCProtocol); };