diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..46a8184 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +v12.18.1 diff --git a/contracts/common/math.sol b/contracts/common/math.sol index b80bf47..63b5880 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) { + 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) { + 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) { + z = SafeMath.mul(x, y); + } + function div(uint x, uint y) internal pure returns (uint z) { + 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/common/stores.sol b/contracts/common/stores.sol index 7926bb7..ac53fe6 100644 --- a/contracts/common/stores.sol +++ b/contracts/common/stores.sol @@ -51,8 +51,8 @@ contract Stores { /** * @dev Connector Details - needs to be changed before deployment */ - function connectorID() public pure returns(uint model, uint id) { + function connectorID() public view returns(uint model, uint id) { (model, id) = (0, 0); } -} \ No newline at end of file +} diff --git a/contracts/connectors/curve.sol b/contracts/connectors/curve.sol index 0e0efb9..3dbd2a4 100644 --- a/contracts/connectors/curve.sol +++ b/contracts/connectors/curve.sol @@ -6,224 +6,223 @@ import { Stores } from "../common/stores.sol"; import { DSMath } from "../common/math.sol"; interface ICurve { - function underlying_coins(int128 tokenId) external view returns (address token); - function calc_token_amount(uint256[4] calldata amounts, bool deposit) external returns (uint256 amount); - function add_liquidity(uint256[4] 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[4] calldata amounts, uint256 max_burn_amount) external; + function underlying_coins(int128 tokenId) external view returns (address token); + function calc_token_amount(uint256[4] calldata amounts, bool deposit) external returns (uint256 amount); + function add_liquidity(uint256[4] 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[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 calc_withdraw_one_coin(uint256 _token_amount, int128 i) external returns (uint256 amount); } contract CurveHelpers is Stores, DSMath { - /** - * @dev Return Curve Swap Address - */ - function getCurveSwapAddr() internal pure returns (address) { - return 0xA5407eAE9Ba41422680e2e00537571bcC53efBfD; - } + /** + * @dev Return Curve Swap Address + */ + function getCurveSwapAddr() internal pure returns (address) { + return 0xA5407eAE9Ba41422680e2e00537571bcC53efBfD; + } - /** - * @dev Return Curve Token Address - */ - function getCurveTokenAddr() internal pure returns (address) { - return 0xC25a3A3b969415c80451098fa907EC722572917F; - } + /** + * @dev Return Curve Token Address + */ + function getCurveTokenAddr() internal pure returns (address) { + return 0xC25a3A3b969415c80451098fa907EC722572917F; + } - /** - * @dev Return Curve Zap Address - */ - function getCurveZapAddr() internal pure returns (address) { - return 0xFCBa3E75865d2d561BE8D220616520c171F12851; - } + /** + * @dev Return Curve Zap Address + */ + function getCurveZapAddr() internal pure returns (address) { + return 0xFCBa3E75865d2d561BE8D220616520c171F12851; + } - function convert18ToDec(uint _dec, uint256 _amt) internal pure returns (uint256 amt) { - amt = (_amt / 10 ** (18 - _dec)); - } + function convert18ToDec(uint _dec, uint256 _amt) internal pure returns (uint256 amt) { + amt = (_amt / 10 ** (18 - _dec)); + } - function convertTo18(uint _dec, uint256 _amt) internal pure returns (uint256 amt) { - amt = mul(_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(0x6B175474E89094C44Da98b954EedeAC495271d0F)) { - // DAI Token - i = 0; - } else if (token == address(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48)) { - // USDC Token - i = 1; - } else if (token == address(0xdAC17F958D2ee523a2206206994597C13D831ec7)) { - // USDT Token - i = 2; - } else if (token == address(0x57Ab1ec28D129707052df4dF418D58a2D46d5f51)) { - // sUSD Token - i = 3; - } else { - revert("token-not-found."); - } + function getTokenI(address token) internal pure returns (int128 i) { + if (token == address(0x6B175474E89094C44Da98b954EedeAC495271d0F)) { + // DAI Token + i = 0; + } else if (token == address(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48)) { + // USDC Token + i = 1; + } else if (token == address(0xdAC17F958D2ee523a2206206994597C13D831ec7)) { + // USDT Token + i = 2; + } else if (token == address(0x57Ab1ec28D129707052df4dF418D58a2D46d5f51)) { + // sUSD Token + i = 3; + } else { + revert("token-not-found."); } + } - 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 getTokenAddr(ICurve curve, uint256 i) internal view returns (address token) { + token = curve.underlying_coins(int128(i)); + require(token != address(0), "token-not-found."); + } } - contract CurveProtocol is CurveHelpers { - 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); + 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. + /** + * @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()); - TokenInterface _buyToken = TokenInterface(buyAddr); - TokenInterface _sellToken = TokenInterface(sellAddr); - _sellAmt = _sellAmt == uint(-1) ? _sellToken.balanceOf(address(this)) : _sellAmt; - _sellToken.approve(address(curve), _sellAmt); + 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()); + TokenInterface _buyToken = TokenInterface(buyAddr); + TokenInterface _sellToken = TokenInterface(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 _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 intialBal = _buyToken.balanceOf(address(this)); + curve.exchange(getTokenI(sellAddr), getTokenI(buyAddr), _sellAmt, _slippageAmt); + uint finalBal = _buyToken.balanceOf(address(this)); - uint _buyAmt = sub(finalBal, intialBal); + uint _buyAmt = sub(finalBal, intialBal); - setUint(setId, _buyAmt); + 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); + 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); + } + + /** + * @dev Deposit Token. + * @param token token address. + * @param amt token amount. + * @param unitAmt unit amount of curve_amt/token_amt 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 deposit( + address token, + uint amt, + uint unitAmt, + uint getId, + uint setId + ) external payable { + uint256 _amt = getUint(getId, amt); + TokenInterface tokenContract = TokenInterface(token); + + _amt = _amt == uint(-1) ? tokenContract.balanceOf(address(this)) : _amt; + uint[4] memory _amts; + _amts[uint(getTokenI(token))] = _amt; + + tokenContract.approve(getCurveSwapAddr(), _amt); + + uint _amt18 = convertTo18(tokenContract.decimals(), _amt); + uint _slippageAmt = wmul(unitAmt, _amt18); + + TokenInterface curveTokenContract = TokenInterface(getCurveTokenAddr()); + uint initialCurveBal = curveTokenContract.balanceOf(address(this)); + + ICurve(getCurveSwapAddr()).add_liquidity(_amts, _slippageAmt); + + uint finalCurveBal = curveTokenContract.balanceOf(address(this)); + + uint mintAmt = sub(finalCurveBal, initialCurveBal); + + setUint(setId, mintAmt); + + emit LogDeposit(token, _amt, mintAmt, getId, setId); + bytes32 _eventCode = keccak256("LogDeposit(address,uint256,uint256,uint256,uint256)"); + bytes memory _eventParam = abi.encode(token, _amt, mintAmt, getId, setId); + emitEvent(_eventCode, _eventParam); + } + + /** + * @dev Withdraw Token. + * @param token token address. + * @param amt token amount. + * @param unitAmt unit amount of curve_amt/token_amt 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 withdraw( + address token, + uint256 amt, + uint256 unitAmt, + uint getId, + uint setId + ) external payable { + uint _amt = getUint(getId, amt); + int128 tokenId = getTokenI(token); + + TokenInterface curveTokenContract = TokenInterface(getCurveTokenAddr()); + ICurveZap curveZap = ICurveZap(getCurveZapAddr()); + ICurve curveSwap = ICurve(getCurveSwapAddr()); + + uint _curveAmt; + uint[4] memory _amts; + if (_amt == uint(-1)) { + _curveAmt = curveTokenContract.balanceOf(address(this)); + _amt = curveZap.calc_withdraw_one_coin(_curveAmt, tokenId); + _amts[uint(tokenId)] = _amt; + } else { + _amts[uint(tokenId)] = _amt; + _curveAmt = curveSwap.calc_token_amount(_amts, false); } - /** - * @dev Deposit Token. - * @param token token address. - * @param amt token amount. - * @param unitAmt unit amount of curve_amt/token_amt 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 deposit( - address token, - uint amt, - uint unitAmt, - uint getId, - uint setId - ) external payable { - uint256 _amt = getUint(getId, amt); - TokenInterface tokenContract = TokenInterface(token); - _amt = _amt == uint(-1) ? tokenContract.balanceOf(address(this)) : _amt; - uint[4] memory _amts; - _amts[uint(getTokenI(token))] = _amt; + uint _amt18 = convertTo18(TokenInterface(token).decimals(), _amt); + uint _slippageAmt = wmul(unitAmt, _amt18); - tokenContract.approve(getCurveSwapAddr(), _amt); + curveTokenContract.approve(address(curveSwap), 0); + curveTokenContract.approve(address(curveSwap), _slippageAmt); - uint _amt18 = convertTo18(tokenContract.decimals(), _amt); - uint _slippageAmt = wmul(unitAmt, _amt18); + curveSwap.remove_liquidity_imbalance(_amts, _slippageAmt); - TokenInterface curveTokenContract = TokenInterface(getCurveTokenAddr()); - uint initialCurveBal = curveTokenContract.balanceOf(address(this)); + setUint(setId, _amt); - ICurve(getCurveSwapAddr()).add_liquidity(_amts, _slippageAmt); - - uint finalCurveBal = curveTokenContract.balanceOf(address(this)); - - uint mintAmt = sub(finalCurveBal, initialCurveBal); - - setUint(setId, mintAmt); - - emit LogDeposit(token, _amt, mintAmt, getId, setId); - bytes32 _eventCode = keccak256("LogDeposit(address,uint256,uint256,uint256,uint256)"); - bytes memory _eventParam = abi.encode(token, _amt, mintAmt, getId, setId); - emitEvent(_eventCode, _eventParam); - } - - /** - * @dev Withdraw Token. - * @param token token address. - * @param amt token amount. - * @param unitAmt unit amount of curve_amt/token_amt 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 withdraw( - address token, - uint256 amt, - uint256 unitAmt, - uint getId, - uint setId - ) external payable { - uint _amt = getUint(getId, amt); - int128 tokenId = getTokenI(token); - - TokenInterface curveTokenContract = TokenInterface(getCurveTokenAddr()); - ICurveZap curveZap = ICurveZap(getCurveZapAddr()); - ICurve curveSwap = ICurve(getCurveSwapAddr()); - - uint _curveAmt; - uint[4] memory _amts; - if (_amt == uint(-1)) { - _curveAmt = curveTokenContract.balanceOf(address(this)); - _amt = curveZap.calc_withdraw_one_coin(_curveAmt, tokenId); - _amts[uint(tokenId)] = _amt; - } else { - _amts[uint(tokenId)] = _amt; - _curveAmt = curveSwap.calc_token_amount(_amts, false); - } - - - uint _amt18 = convertTo18(TokenInterface(token).decimals(), _amt); - uint _slippageAmt = wmul(unitAmt, _amt18); - - curveTokenContract.approve(address(curveSwap), 0); - curveTokenContract.approve(address(curveSwap), _slippageAmt); - - curveSwap.remove_liquidity_imbalance(_amts, _slippageAmt); - - setUint(setId, _amt); - - emit LogWithdraw(token, _amt, _curveAmt, getId, setId); - bytes32 _eventCode = keccak256("LogWithdraw(address,uint256,uint256,uint256,uint256)"); - bytes memory _eventParam = abi.encode(token, _amt, _curveAmt, getId, setId); - emitEvent(_eventCode, _eventParam); - } + emit LogWithdraw(token, _amt, _curveAmt, getId, setId); + bytes32 _eventCode = keccak256("LogWithdraw(address,uint256,uint256,uint256,uint256)"); + bytes memory _eventParam = abi.encode(token, _amt, _curveAmt, getId, setId); + emitEvent(_eventCode, _eventParam); + } } contract ConnectCurve is CurveProtocol { - string public name = "Curve-susd-v1.2"; + string public name = "Curve-susd-v1.2"; } diff --git a/contracts/connectors/curvesbtc.sol b/contracts/connectors/curvesbtc.sol new file mode 100644 index 0000000..6996845 --- /dev/null +++ b/contracts/connectors/curvesbtc.sol @@ -0,0 +1,207 @@ +pragma solidity ^0.6.0; + +// import files from common directory +import { Stores } from "../common/stores.sol"; +import { DSMath } from "../common/math.sol"; +import { TokenInterface } from "../common/interfaces.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 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()); + TokenInterface _buyToken = TokenInterface(buyAddr); + TokenInterface _sellToken = TokenInterface(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); + } + + /** + * @dev Deposit Token. + * @param token token address. + * @param amt token amount. + * @param unitAmt unit amount of curve_amt/token_amt 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 deposit( + address token, + uint amt, + uint unitAmt, + uint getId, + uint setId + ) external payable { + uint256 _amt = getUint(getId, amt); + TokenInterface tokenContract = TokenInterface(token); + + _amt = _amt == uint(-1) ? tokenContract.balanceOf(address(this)) : _amt; + uint[3] memory _amts; + _amts[uint(getTokenI(token))] = _amt; + + tokenContract.approve(getCurveSwapAddr(), _amt); + + uint _amt18 = convertTo18(tokenContract.decimals(), _amt); + uint _slippageAmt = wmul(unitAmt, _amt18); + + TokenInterface curveTokenContract = TokenInterface(getCurveTokenAddr()); + uint initialCurveBal = curveTokenContract.balanceOf(address(this)); + + ICurve(getCurveSwapAddr()).add_liquidity(_amts, _slippageAmt); + + uint finalCurveBal = curveTokenContract.balanceOf(address(this)); + + uint mintAmt = sub(finalCurveBal, initialCurveBal); + + setUint(setId, mintAmt); + + emit LogDeposit(token, _amt, mintAmt, getId, setId); + bytes32 _eventCode = keccak256("LogDeposit(address,uint256,uint256,uint256,uint256)"); + bytes memory _eventParam = abi.encode(token, _amt, mintAmt, getId, setId); + emitEvent(_eventCode, _eventParam); + } + + /** + * @dev Withdraw Token. + * @param token token address. + * @param amt token amount. + * @param unitAmt unit amount of curve_amt/token_amt 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 withdraw( + address token, + uint256 amt, + uint256 unitAmt, + uint getId, + uint setId + ) external payable { + uint _amt = getUint(getId, amt); + int128 tokenId = getTokenI(token); + + TokenInterface curveTokenContract = TokenInterface(getCurveTokenAddr()); + ICurve curveSwap = ICurve(getCurveSwapAddr()); + + uint _curveAmt; + uint[3] memory _amts; + if (_amt == uint(-1)) { + _curveAmt = curveTokenContract.balanceOf(address(this)); + _amt = curveSwap.calc_withdraw_one_coin(_curveAmt, tokenId); + _amts[uint(tokenId)] = _amt; + } else { + _amts[uint(tokenId)] = _amt; + _curveAmt = curveSwap.calc_token_amount(_amts, false); + } + + uint _amt18 = convertTo18(TokenInterface(token).decimals(), _amt); + uint _slippageAmt = wmul(unitAmt, _amt18); + + curveTokenContract.approve(address(curveSwap), 0); + curveTokenContract.approve(address(curveSwap), _slippageAmt); + + curveSwap.remove_liquidity_imbalance(_amts, _slippageAmt); + + setUint(setId, _amt); + + emit LogWithdraw(token, _amt, _curveAmt, getId, setId); + bytes32 _eventCode = keccak256("LogWithdraw(address,uint256,uint256,uint256,uint256)"); + bytes memory _eventParam = abi.encode(token, _amt, _curveAmt, getId, setId); + emitEvent(_eventCode, _eventParam); + } +} + +contract ConnectSBTCCurve is CurveSBTCProtocol { + string public name = "Curve-sbtc-v1"; +} + diff --git a/migrations/2_deploy_connector.js b/migrations/2_deploy_connector.js index f3bea19..18f5843 100644 --- a/migrations/2_deploy_connector.js +++ b/migrations/2_deploy_connector.js @@ -1,5 +1,12 @@ -const Connector = artifacts.require("CurveProtocol"); // Change the Connector name while deploying. +const CurveProtocol = artifacts.require("CurveProtocol"); +const ConnectSBTCCurve = artifacts.require("ConnectSBTCCurve"); -module.exports = function(deployer) { - deployer.deploy(Connector); +const connectorsABI = require("../test/abi/connectors.json"); +let connectorsAddr = "0xD6A602C01a023B98Ecfb29Df02FBA380d3B21E0c"; +let connectorInstance = new web3.eth.Contract(connectorsABI, connectorsAddr); + +module.exports = async function(deployer) { + deployer.deploy(CurveProtocol); + let connectorLength = await connectorInstance.methods.connectorLength().call(); + deployer.deploy(ConnectSBTCCurve, 1, +connectorLength + 1); }; diff --git a/package-lock.json b/package-lock.json index c170b9f..9991825 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,10 +4,90 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@openzeppelin/contract-loader": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@openzeppelin/contract-loader/-/contract-loader-0.4.0.tgz", + "integrity": "sha512-K+Pl4tn0FbxMSP0H9sgi61ayCbecpqhQmuBshelC7A3q2MlpcqWRJan0xijpwdtv6TORNd5oZNe/+f3l+GD6tw==", + "dev": true, + "requires": { + "find-up": "^4.1.0", + "fs-extra": "^8.1.0", + "try-require": "^1.2.1" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + } + } + }, "@openzeppelin/contracts": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-3.0.2.tgz", - "integrity": "sha512-eK9F3jEbjQeRYLiqrHUrXCZBxE+7L4Ve5scYInsLezuasoFkrrEFlnDWD8gbN+6e5NgdgJP9fTWxjxWmaHh7dA==" + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-3.1.0.tgz", + "integrity": "sha512-dVXDnUKxrAKLzPdCRkz+N8qsVkK1XxJ6kk3zuI6zaQmcKxN7CkizoDP7lXxcs/Mi2I0mxceTRjJBqlzFffLJrQ==" + }, + "@openzeppelin/test-helpers": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/@openzeppelin/test-helpers/-/test-helpers-0.5.6.tgz", + "integrity": "sha512-8U4sR4ed4cFmc6UKj7akUxZzQJKU9P3p/3RbF+urQuRLLhBaB8zSya1m9VB7/anYEZnBmTDk8LuVgAmYaCPs9A==", + "dev": true, + "requires": { + "@openzeppelin/contract-loader": "^0.4.0", + "@truffle/contract": "^4.0.35 <4.2.2", + "ansi-colors": "^3.2.3", + "chai": "^4.2.0", + "chai-bn": "^0.2.1", + "ethjs-abi": "^0.2.1", + "lodash.flatten": "^4.4.0", + "semver": "^5.6.0", + "web3": "^1.2.1", + "web3-utils": "^1.2.1" + } }, "@openzeppelin/upgrades": { "version": "2.8.0", @@ -346,6 +426,7 @@ "eth-lib": "0.2.7", "ethereumjs-common": "^1.3.2", "ethereumjs-tx": "^2.1.1", + "scrypt-shim": "github:web3-js/scrypt-shim", "underscore": "1.9.1", "uuid": "3.3.2", "web3-core": "1.2.2", @@ -580,6 +661,23 @@ "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.6.2.tgz", "integrity": "sha512-kUVUvrqttndeprLoXjI5arWHeiP3uh4XODAKbG+ZaWHCVQeelxCbnXBeWxZ2BPHdXgH0xR9dU1b916JhDhbgAA==" }, + "@studydefi/money-legos": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@studydefi/money-legos/-/money-legos-2.3.5.tgz", + "integrity": "sha512-Whfsw+Ka5PCX8u7za0DOnb3j7DqPQ0QW2SjtjrC4drP+MRpq6ANdxTLgAqYU2e5BZ3/DrDZ6MGTajMCPKXoxZw==", + "dev": true, + "requires": { + "@openzeppelin/contracts": "^2.5.0" + }, + "dependencies": { + "@openzeppelin/contracts": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-2.5.1.tgz", + "integrity": "sha512-qIy6tLx8rtybEsIOAlrM4J/85s2q2nPkDqj/Rx46VakBZ0LwtFhXIVub96LXHczQX0vaqmAueDqNPXtbSXSaYQ==", + "dev": true + } + } + }, "@szmarczak/http-timer": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", @@ -600,6 +698,44 @@ "source-map-support": "^0.5.16" } }, + "@truffle/blockchain-utils": { + "version": "0.0.18", + "resolved": "https://registry.npmjs.org/@truffle/blockchain-utils/-/blockchain-utils-0.0.18.tgz", + "integrity": "sha512-XnRu5p1QO9krJizOeBY5WfzPDvEOmCnOT5u6qF8uN3Kkq9vcH3ZqW4XTuzz9ERZNpZfWb3UJx4PUosgeHLs5vw==", + "dev": true, + "requires": { + "source-map-support": "^0.5.16" + } + }, + "@truffle/contract": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@truffle/contract/-/contract-4.2.1.tgz", + "integrity": "sha512-af1rUyU/W75GYHt/i7r+NwHozwaCma7V/q/+SRZ3Cw2MFaGOQ0dA/ZGhH8P1F0fmDiUe1DBEIbKxXWai0PWFYg==", + "dev": true, + "requires": { + "@truffle/blockchain-utils": "^0.0.18", + "@truffle/contract-schema": "^3.1.0", + "@truffle/error": "^0.0.8", + "@truffle/interface-adapter": "^0.4.6", + "bignumber.js": "^7.2.1", + "ethereum-ens": "^0.8.0", + "ethers": "^4.0.0-beta.1", + "exorcist": "^1.0.1", + "source-map-support": "^0.5.16", + "web3": "1.2.1", + "web3-core-promievent": "1.2.1", + "web3-eth-abi": "1.2.1", + "web3-utils": "1.2.1" + }, + "dependencies": { + "bignumber.js": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-7.2.1.tgz", + "integrity": "sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ==", + "dev": true + } + } + }, "@truffle/contract-schema": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@truffle/contract-schema/-/contract-schema-3.1.0.tgz", @@ -610,6 +746,77 @@ "debug": "^4.1.0" } }, + "@truffle/error": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@truffle/error/-/error-0.0.8.tgz", + "integrity": "sha512-x55rtRuNfRO1azmZ30iR0pf0OJ6flQqbax1hJz+Avk1K5fdmOv5cr22s9qFnwTWnS6Bw0jvJEoR0ITsM7cPKtQ==", + "dev": true + }, + "@truffle/interface-adapter": { + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/@truffle/interface-adapter/-/interface-adapter-0.4.9.tgz", + "integrity": "sha512-2dYccf7lAwx90NVYmn89QABpd3dx7BxvDAaHgzVa2YVOUkTUpkZiaIsD2YlsVQ1rew17wMNi5WXH2RFnmzQ82A==", + "dev": true, + "requires": { + "bn.js": "^4.11.8", + "ethers": "^4.0.32", + "source-map-support": "^0.5.19", + "web3": "1.2.1" + }, + "dependencies": { + "ethers": { + "version": "4.0.47", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.47.tgz", + "integrity": "sha512-hssRYhngV4hiDNeZmVU/k5/E8xmLG8UpcNUzg6mb7lqhgpFPH/t7nuv20RjRrEf0gblzvi2XwR5Te+V3ZFc9pQ==", + "dev": true, + "requires": { + "aes-js": "3.0.0", + "bn.js": "^4.4.0", + "elliptic": "6.5.2", + "hash.js": "1.1.3", + "js-sha3": "0.5.7", + "scrypt-js": "2.0.4", + "setimmediate": "1.0.4", + "uuid": "2.0.1", + "xmlhttprequest": "1.8.0" + } + }, + "hash.js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", + "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.0" + } + }, + "js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc=", + "dev": true + }, + "scrypt-js": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.4.tgz", + "integrity": "sha512-4KsaGcPnuhtCZQCxFxN3GVYIhKFPTdLd8PLC552XwbMndtD0cjRFAhDuuydXQ0h08ZfPgzqe6EKHozpuH74iDw==", + "dev": true + }, + "setimmediate": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.4.tgz", + "integrity": "sha1-IOgd5iLUoCWIzgyNqJc8vPHTE48=", + "dev": true + }, + "uuid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", + "integrity": "sha1-wqMN7bPlNdcsz4LjQ5QaULqFM6w=", + "dev": true + } + } + }, "@types/bn.js": { "version": "4.11.6", "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", @@ -674,6 +881,12 @@ "dev": true, "optional": true }, + "ansi-colors": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", + "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", + "dev": true + }, "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", @@ -1267,6 +1480,26 @@ } } }, + "chai": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", + "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "pathval": "^1.1.0", + "type-detect": "^4.0.5" + } + }, + "chai-bn": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/chai-bn/-/chai-bn-0.2.1.tgz", + "integrity": "sha512-01jt2gSXAw7UYFPT5K8d7HYjdXj2vyeIuE+0T/34FWzlNcVbs1JkPxRu7rYMfQnJhrHT8Nr6qjSf5ZwwLU2EYg==", + "dev": true + }, "chalk": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.0.0.tgz", @@ -1276,6 +1509,12 @@ "supports-color": "^7.1.0" } }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true + }, "chokidar": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", @@ -1493,6 +1732,23 @@ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" }, + "convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } + } + }, "cookie": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", @@ -1727,6 +1983,15 @@ } } }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, "deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", @@ -2057,6 +2322,28 @@ "js-sha3": "^0.8.0" } }, + "ethereum-ens": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/ethereum-ens/-/ethereum-ens-0.8.0.tgz", + "integrity": "sha512-a8cBTF4AWw1Q1Y37V1LSCS9pRY4Mh3f8vCg5cbXCCEJ3eno1hbI/+Ccv9SZLISYpqQhaglP3Bxb/34lS4Qf7Bg==", + "dev": true, + "requires": { + "bluebird": "^3.4.7", + "eth-ens-namehash": "^2.0.0", + "js-sha3": "^0.5.7", + "pako": "^1.0.4", + "underscore": "^1.8.3", + "web3": "^1.0.0-beta.34" + }, + "dependencies": { + "js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc=", + "dev": true + } + } + }, "ethereumjs-abi": { "version": "0.6.8", "resolved": "https://registry.npmjs.org/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz", @@ -2162,6 +2449,31 @@ } } }, + "ethjs-abi": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/ethjs-abi/-/ethjs-abi-0.2.1.tgz", + "integrity": "sha1-4KepOn6BFjqUR3utVu3lJKtt5TM=", + "dev": true, + "requires": { + "bn.js": "4.11.6", + "js-sha3": "0.5.5", + "number-to-bn": "1.7.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=", + "dev": true + }, + "js-sha3": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.5.tgz", + "integrity": "sha1-uvDA6MVK1ZA0R9+Wreekobynmko=", + "dev": true + } + } + }, "ethjs-unit": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz", @@ -2233,6 +2545,43 @@ } } }, + "exorcist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/exorcist/-/exorcist-1.0.1.tgz", + "integrity": "sha1-eTFuPEiFhFSQ97tAXA5bXbEWfFI=", + "dev": true, + "requires": { + "is-stream": "~1.1.0", + "minimist": "0.0.5", + "mkdirp": "~0.5.1", + "mold-source-map": "~0.4.0" + }, + "dependencies": { + "minimist": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.5.tgz", + "integrity": "sha1-16oye87PUY+RBqxrjwA/o7zqhWY=", + "dev": true + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + }, + "dependencies": { + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + } + } + } + } + }, "expand-brackets": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", @@ -3106,12 +3455,692 @@ } } }, + "ganache-cli": { + "version": "6.10.0-beta.2", + "resolved": "https://registry.npmjs.org/ganache-cli/-/ganache-cli-6.10.0-beta.2.tgz", + "integrity": "sha512-mJZuwl5W7WLRGrILrmM8hOGCwy98L5dymOpHc5rg4Dqosa6TE+M+qPJPXbWH78jtbUyrbKERZc3E5YpNIfl8Ow==", + "dev": true, + "requires": { + "ethereumjs-util": "6.1.0", + "scrypt": "6.0.3", + "source-map-support": "0.5.12", + "yargs": "13.2.4" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "bundled": true, + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "bundled": true, + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "bindings": { + "version": "1.5.0", + "bundled": true, + "dev": true, + "requires": { + "file-uri-to-path": "1.0.0" + } + }, + "bip66": { + "version": "1.1.5", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "bn.js": { + "version": "4.11.8", + "bundled": true, + "dev": true + }, + "brorand": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "browserify-aes": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "buffer-from": { + "version": "1.1.1", + "bundled": true, + "dev": true + }, + "buffer-xor": { + "version": "1.0.3", + "bundled": true, + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "bundled": true, + "dev": true + }, + "cipher-base": { + "version": "1.0.4", + "bundled": true, + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "cliui": { + "version": "5.0.0", + "bundled": true, + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "color-convert": { + "version": "1.9.3", + "bundled": true, + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "bundled": true, + "dev": true + }, + "create-hash": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "bundled": true, + "dev": true, + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "cross-spawn": { + "version": "6.0.5", + "bundled": true, + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "decamelize": { + "version": "1.2.0", + "bundled": true, + "dev": true + }, + "drbg.js": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "browserify-aes": "^1.0.6", + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4" + } + }, + "elliptic": { + "version": "6.5.0", + "bundled": true, + "dev": true, + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" + } + }, + "emoji-regex": { + "version": "7.0.3", + "bundled": true, + "dev": true + }, + "end-of-stream": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "ethereumjs-util": { + "version": "6.1.0", + "bundled": true, + "dev": true, + "requires": { + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "ethjs-util": "0.1.6", + "keccak": "^1.0.2", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1", + "secp256k1": "^3.0.1" + } + }, + "ethjs-util": { + "version": "0.1.6", + "bundled": true, + "dev": true, + "requires": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" + } + }, + "evp_bytestokey": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "execa": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "file-uri-to-path": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "find-up": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "get-caller-file": { + "version": "2.0.5", + "bundled": true, + "dev": true + }, + "get-stream": { + "version": "4.1.0", + "bundled": true, + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "hash-base": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "hash.js": { + "version": "1.1.7", + "bundled": true, + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "inherits": { + "version": "2.0.4", + "bundled": true, + "dev": true + }, + "invert-kv": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "is-hex-prefixed": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "isexe": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "keccak": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "requires": { + "bindings": "^1.2.1", + "inherits": "^2.0.3", + "nan": "^2.2.1", + "safe-buffer": "^5.1.0" + } + }, + "lcid": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "invert-kv": "^2.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "map-age-cleaner": { + "version": "0.1.3", + "bundled": true, + "dev": true, + "requires": { + "p-defer": "^1.0.0" + } + }, + "md5.js": { + "version": "1.3.5", + "bundled": true, + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "mem": { + "version": "4.3.0", + "bundled": true, + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "bundled": true, + "dev": true + }, + "minimalistic-assert": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "nan": { + "version": "2.14.0", + "bundled": true, + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "bundled": true, + "dev": true + }, + "npm-run-path": { + "version": "2.0.2", + "bundled": true, + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "os-locale": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "requires": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + } + }, + "p-defer": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "p-finally": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "p-is-promise": { + "version": "2.1.0", + "bundled": true, + "dev": true + }, + "p-limit": { + "version": "2.2.0", + "bundled": true, + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "bundled": true, + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "path-key": { + "version": "2.0.1", + "bundled": true, + "dev": true + }, + "pump": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "require-directory": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "ripemd160": { + "version": "2.0.2", + "bundled": true, + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "rlp": { + "version": "2.2.3", + "bundled": true, + "dev": true, + "requires": { + "bn.js": "^4.11.1", + "safe-buffer": "^5.1.1" + } + }, + "safe-buffer": { + "version": "5.2.0", + "bundled": true, + "dev": true + }, + "secp256k1": { + "version": "3.7.1", + "bundled": true, + "dev": true, + "requires": { + "bindings": "^1.5.0", + "bip66": "^1.1.5", + "bn.js": "^4.11.8", + "create-hash": "^1.2.0", + "drbg.js": "^1.0.1", + "elliptic": "^6.4.1", + "nan": "^2.14.0", + "safe-buffer": "^5.1.2" + } + }, + "semver": { + "version": "5.7.0", + "bundled": true, + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "sha.js": { + "version": "2.4.11", + "bundled": true, + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shebang-command": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true + }, + "source-map": { + "version": "0.6.1", + "bundled": true, + "dev": true + }, + "source-map-support": { + "version": "0.5.12", + "bundled": true, + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "string-width": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "strip-eof": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "strip-hex-prefix": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "is-hex-prefixed": "1.0.0" + } + }, + "which": { + "version": "1.3.1", + "bundled": true, + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "wrap-ansi": { + "version": "5.1.0", + "bundled": true, + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "y18n": { + "version": "4.0.0", + "bundled": true, + "dev": true + }, + "yargs": { + "version": "13.2.4", + "bundled": true, + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "os-locale": "^3.1.0", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.0" + } + }, + "yargs-parser": { + "version": "13.1.1", + "bundled": true, + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, "get-caller-file": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", "dev": true }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true + }, "get-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", @@ -3938,6 +4967,12 @@ "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=" }, + "lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=", + "dev": true + }, "lodash.isequal": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", @@ -4300,6 +5335,24 @@ "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-4.12.0.tgz", "integrity": "sha512-/P/HtrlvBxY4o/PzXY9cCNBrdylDNxg7gnrv2sMNxj+UJ2m8jSpl0/A6fuJeNAWr99ZvGWH8XCbE0vmnM5KupQ==" }, + "mold-source-map": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/mold-source-map/-/mold-source-map-0.4.0.tgz", + "integrity": "sha1-z2fgsxxHq5uttcnCVlGGISe7gxc=", + "dev": true, + "requires": { + "convert-source-map": "^1.1.0", + "through": "~2.2.7" + }, + "dependencies": { + "through": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/through/-/through-2.2.7.tgz", + "integrity": "sha1-bo4hIAGR1OtqmfbwEN9Gqhxusr0=", + "dev": true + } + } + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -4634,6 +5687,12 @@ "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, "parse-asn1": { "version": "5.1.5", "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz", @@ -4726,6 +5785,12 @@ "pinkie-promise": "^2.0.0" } }, + "pathval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", + "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", + "dev": true + }, "pbkdf2": { "version": "3.0.17", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", @@ -5498,11 +6563,36 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "scrypt": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/scrypt/-/scrypt-6.0.3.tgz", + "integrity": "sha1-BOAUpWgrU/pQwtXM4WfXGcBthw0=", + "dev": true, + "optional": true, + "requires": { + "nan": "^2.0.8" + } + }, "scrypt-js": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.3.tgz", "integrity": "sha1-uwBAvgMEPamgEqLOqfyfhSz8h9Q=" }, + "scrypt-shim": { + "version": "github:web3-js/scrypt-shim#aafdadda13e660e25e1c525d1f5b2443f5eb1ebb", + "from": "github:web3-js/scrypt-shim", + "requires": { + "scryptsy": "^2.1.0", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, "scryptsy": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/scryptsy/-/scryptsy-2.1.0.tgz", @@ -6742,6 +7832,12 @@ "querystring": "^0.2.0" } }, + "try-require": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/try-require/-/try-require-1.2.1.tgz", + "integrity": "sha1-NEiaLKwMCcHMEO2RugEVlNQzO+I=", + "dev": true + }, "tsort": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/tsort/-/tsort-0.0.1.tgz", @@ -6774,6 +7870,12 @@ "prelude-ls": "~1.1.2" } }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, "type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", diff --git a/package.json b/package.json index 0acdd5f..a354223 100644 --- a/package.json +++ b/package.json @@ -5,10 +5,11 @@ "main": "truffle-config.js", "directories": {}, "scripts": { - "test": "npm run ganache sleep 5 && truffle test && npm run stop", + "test": "truffle test", "coverage": "./node_modules/.bin/solidity-coverage", "solium": "solium -d contracts/", - "build-contracts": "sol-merger \"./contracts/connectors/mock.sol\" ./contracts/build" + "build-contracts": "sol-merger \"./contracts/connectors/mock.sol\" ./contracts/build", + "ganache": "ganache-cli --deterministic --unlock 0xfcd22438ad6ed564a1c26151df73f6b33b817b56 -f https://mainnet.infura.io/v3/" }, "repository": { "type": "git", @@ -35,6 +36,9 @@ "truffle-verify": "^1.0.8" }, "devDependencies": { + "@openzeppelin/test-helpers": "^0.5.6", + "@studydefi/money-legos": "^2.3.5", + "ganache-cli": "^6.10.0-beta.2", "sol-merger": "^2.0.1", "solidity-coverage": "0.5.11", "solium": "1.2.3" diff --git a/test/CurveProtocol.js b/test/CurveProtocol.js index 512af0e..fdda7d3 100644 --- a/test/CurveProtocol.js +++ b/test/CurveProtocol.js @@ -2,7 +2,8 @@ const CurveProtocol = artifacts.require('CurveProtocol') const daiABI = require('./abi/dai'); const erc20 = require('./abi/erc20') const swap_abi = require('./abi/swap') -const { ether, balance } = require('openzeppelin-test-helpers'); +const { ether, balance } = require('@openzeppelin/test-helpers'); +const uniswap = require("@studydefi/money-legos/uniswap"); const BN = require('bn.js') @@ -11,7 +12,7 @@ const expect = chai.expect chai.use(require('chai-bn')(BN)); // userAddress must be unlocked using --unlock ADDRESS -const userAddress = '0x9eb7f2591ed42dee9315b6e2aaf21ba85ea69f8c'; +const userAddress = '0xfcd22438ad6ed564a1c26151df73f6b33b817b56'; const daiAddress = '0x6b175474e89094c44da98b954eedeac495271d0f'; const daiContract = new web3.eth.Contract(daiABI, daiAddress); @@ -24,99 +25,136 @@ const swapContract = new web3.eth.Contract(swap_abi, swap) const swapToken = '0xC25a3A3b969415c80451098fa907EC722572917F' const tokenContract = new web3.eth.Contract(erc20, swapToken) - - contract('Curve Protocol', async accounts => { + let account, contract; + beforeEach(async function() { + account = accounts[0] + contract = await CurveProtocol.deployed() - it('should send ether to the DAI address', async () => { - let account = accounts[0] - let contract = await CurveProtocol.deployed() - // Send 0.1 eth to userAddress to have gas to send an ERC20 tx. - await web3.eth.sendTransaction({ - from: accounts[0], - to: userAddress, - value: ether('0.1') - }); - const ethBalance = await balance.current(userAddress); - expect(+ethBalance).to.be.at.least(+ether('0.1')) - }); + let uniswapFactory = new web3.eth.Contract( + uniswap.factory.abi, + uniswap.factory.address + ); - it('should transfer DAI to CurveProtocol', async () => { - let account = accounts[0] - let contract = await CurveProtocol.deployed() - // Get 100 DAI for first 5 accounts - // daiAddress is passed to ganache-cli with flag `--unlock` - // so we can use the `transfer` method - await daiContract.methods - .transfer(contract.address, ether('100').toString()) - .send({ from: userAddress, gasLimit: 800000 }); - const daiBalance = await daiContract.methods.balanceOf(contract.address).call(); - expect(+daiBalance).to.be.at.least(+ether('100')) - }); + const daiExchangeAddress = await uniswapFactory.methods.getExchange( + daiAddress, + ).call(); - it('should approve DAI to CurveProtocol', async() => { - let account = accounts[0] - let contract = await CurveProtocol.deployed() + const daiExchange = new web3.eth.Contract( + uniswap.exchange.abi, + daiExchangeAddress + ); - await daiContract.methods - .approve(contract.address, ether('100').toString()) - .send({ from: account, gasLimit: 800000 }); - const daiAllowance = await daiContract.methods.allowance(account, contract.address).call() - expect(+daiAllowance).to.be.at.least(+ether('100')) - }); + const daiBefore = await daiContract.methods.balanceOf(userAddress).call(); - it('should exchange', async () => { - let account = accounts[0] - let contract = await CurveProtocol.deployed() + await daiExchange.methods.ethToTokenSwapInput( + 1, // min amount of token retrieved + 2525644800, // random timestamp in the future (year 2050) + ).send( + { + gas: 4000000, + value: ether("5"), + from: userAddress + } + ); - // Get 100 DAI for first 5 accounts - let get_dy = await contract.get_dy.call(0, 1, ether('1').toString()) - let min_dy = +get_dy * 0.99 - let receipt = await contract.exchange(0, 1, ether('1').toString(), 1, { from: account }) - let buyAmount = receipt.logs[0].args.buyAmount.toString() - expect(+buyAmount).to.be.at.least(min_dy); + let daiAfter = await daiContract.methods.balanceOf(userAddress).call(); - }); + expect(daiAfter - daiBefore).to.be.at.least(+ether("1000")); + }); - it('should add liquidity', async () => { - let account = accounts[0] - let contract = await CurveProtocol.deployed() + it('should send ether to the user address', async () => { + const ethBalanceBefore = await balance.current(userAddress); + // Send 0.1 eth to userAddress to have gas to send an ERC20 tx. + await web3.eth.sendTransaction({ + from: accounts[0], + to: userAddress, + value: ether('0.1') + }); + const ethBalanceAfter = await balance.current(userAddress); + expect(+ethBalanceAfter - +ethBalanceBefore).to.equal(+ether('0.1')) + }); - let amounts = [ether('1').toString(), 0, 0, 0] - let token_amount = await contract.calc_token_amount.call(amounts, true) + it('should transfer DAI to CurveProtocol', async () => { + // Get 100 DAI for first 5 accounts + // daiAddress is passed to ganache-cli with flag `--unlock` + // so we can use the `transfer` method + // + // Note: This only works as userAddress has 2546221640728945323079640 Dai, + // should remove this dependence in the future + const daiBalanceUser = await daiContract.methods.balanceOf(userAddress).call(); + await daiContract.methods + .transfer(contract.address, ether('100').toString()) + .send({ from: userAddress, gasLimit: 800000 }); + const daiBalance = await daiContract.methods.balanceOf(contract.address).call(); + expect(+daiBalance).to.be.at.least(+ether('100')) + }); - let receipt = await contract.add_liquidity(amounts, 1, { from: account }) - let mintAmount = receipt.logs[0].args.mintAmount.toString() - expect(+mintAmount).to.be.at.least(+mintAmount) - }) + it('should approve DAI to CurveProtocol', async() => { + await daiContract.methods + .approve(contract.address, ether('100').toString()) + .send({ from: account, gasLimit: 800000 }); + const daiAllowance = await daiContract.methods.allowance(account, contract.address).call() + expect(+daiAllowance).to.be.at.least(+ether('100')) + }); - it('should remove liquidity imbalance', async () => { - let account = accounts[0] - let contract = await CurveProtocol.deployed() + /* Deprecated as CurveProtocol is not ICurve and exchange has been implemented into sell method + it('should exchange', async () => { + let account = accounts[0] + let contract = await CurveProtocol.deployed() - let tokenBalance = await tokenContract.methods.balanceOf(contract.address).call() - let receipt = await contract.remove_liquidity_imbalance(["100000000000", 0, 0, 0], { from: account }) - let burnAmount = receipt.logs[0].args.burnAmount.toString() - let tokenBalanceAfter = await tokenContract.methods.balanceOf(contract.address).call() + // Get 100 DAI for first 5 accounts + console.log('before'); + let get_dy = await contract.get_dy.call(0, 1, ether('1').toString()) + console.log('after'); + let min_dy = +get_dy * 0.99 + let receipt = await contract.exchange(0, 1, ether('1').toString(), 1, { from: account }) + let buyAmount = receipt.logs[0].args.buyAmount.toString() + expect(+buyAmount).to.be.at.least(min_dy); + }); + */ - //weird Ganache errors sometimes "cannot decode event" - console.log(+tokenBalance, +tokenBalanceAfter, +burnAmount) - //expect(BN(tokenBalance)).to.be.a.bignumber.equal(BN(tokenBalanceAfter).add(burnAmount)) + /* Deprecated as CurveProtocol is not ICurve and calc_token_amount has been implemented into withdraw method + it('should add liquidity', async () => { + let account = accounts[0] + let contract = await CurveProtocol.deployed() - }) + let amounts = [ether('1').toString(), 0, 0, 0] + let token_amount = await contract.calc_token_amount.call(amounts, true) - it('should remove liquidity in one coin', async() => { - let account = accounts[0] - let contract = await CurveProtocol.deployed() + let receipt = await contract.add_liquidity(amounts, 1, { from: account }) + let mintAmount = receipt.logs[0].args.mintAmount.toString() + expect(+mintAmount).to.be.at.least(+mintAmount) + }) - let daiBalance = await daiContract.methods.balanceOf(contract.address).call() - let receipt = await contract.remove_liquidity_one_coin("100000000000", 0, 1, { from: account }) - let withdrawnAmount = receipt.logs[0].args.withdrawnAmount.toString() - let daiBalanceAfter = await daiContract.methods.balanceOf(contract.address).call() + it('should remove liquidity imbalance', async () => { + let account = accounts[0] + let contract = await CurveProtocol.deployed() - //weird Ganache errors sometimes "cannot decode event" - console.log(+daiBalance, +daiBalanceAfter, +withdrawnAmount) - //expect(BN(daiBalance)).to.be.a.bignumber.equal(BN(daiBalanceAfter).sub(withdrawnAmount)); - }) -}); \ No newline at end of file + let tokenBalance = await tokenContract.methods.balanceOf(contract.address).call() + let receipt = await contract.remove_liquidity_imbalance(["100000000000", 0, 0, 0], { from: account }) + let burnAmount = receipt.logs[0].args.burnAmount.toString() + let tokenBalanceAfter = await tokenContract.methods.balanceOf(contract.address).call() + +//weird Ganache errors sometimes "cannot decode event" + console.log(+tokenBalance, +tokenBalanceAfter, +burnAmount) +//expect(BN(tokenBalance)).to.be.a.bignumber.equal(BN(tokenBalanceAfter).add(burnAmount)) + + }) + + it('should remove liquidity in one coin', async() => { + let account = accounts[0] + let contract = await CurveProtocol.deployed() + + let daiBalance = await daiContract.methods.balanceOf(contract.address).call() + let receipt = await contract.remove_liquidity_one_coin("100000000000", 0, 1, { from: account }) + let withdrawnAmount = receipt.logs[0].args.withdrawnAmount.toString() + let daiBalanceAfter = await daiContract.methods.balanceOf(contract.address).call() + +//weird Ganache errors sometimes "cannot decode event" + console.log(+daiBalance, +daiBalanceAfter, +withdrawnAmount) +//expect(BN(daiBalance)).to.be.a.bignumber.equal(BN(daiBalanceAfter).sub(withdrawnAmount)); + }) + */ +}); diff --git a/test/CurveSBTCProtocol.js b/test/CurveSBTCProtocol.js new file mode 100644 index 0000000..c4bcbe7 --- /dev/null +++ b/test/CurveSBTCProtocol.js @@ -0,0 +1,196 @@ +const { + BN, // Big Number support + expectEvent, // Assertions for emitted events + expectRevert, // Assertions for transactions that should fail + balance, + ether +} = require('@openzeppelin/test-helpers'); + +const ConnectSBTCCurve = artifacts.require('ConnectSBTCCurve'); +const erc20 = require("@studydefi/money-legos/erc20"); +const uniswap = require("@studydefi/money-legos/uniswap"); +const sbtcABI = require("./abi/sbtc.json"); +const erc20ABI = require("./abi/erc20.js"); +const connectorsABI = require("./abi/connectors.json"); +const accountABI = require("./abi/account.json"); +const curveSwap = require("./abi/curveSwap.json"); + +contract('ConnectSBTCCurve', async accounts => { + const [sender, receiver] = accounts; + let masterAddress = "0xfcd22438ad6ed564a1c26151df73f6b33b817b56"; + let accountID = 7; + let dsrAddr = "0xEEB007bea2Bbb0cA6502217E8867f8f7b021B8D5"; + + let connectorsAddr = "0xD6A602C01a023B98Ecfb29Df02FBA380d3B21E0c"; + let connectorInstance = new web3.eth.Contract(connectorsABI, connectorsAddr); + + // let accountAddr = "0x939Daad09fC4A9B8f8A9352A485DAb2df4F4B3F8"; + let accountInstance = new web3.eth.Contract(accountABI, dsrAddr); + let connectSBTCCurve; + let wbtcContract = new web3.eth.Contract(erc20.wbtc.abi, erc20.wbtc.address); + + before(async function () { + connectSBTCCurve = await ConnectSBTCCurve.deployed(); + + let uniswapFactory = new web3.eth.Contract( + uniswap.factory.abi, + uniswap.factory.address + ); + + const wbtcExchangeAddress = await uniswapFactory.methods.getExchange( + erc20.wbtc.address, + ).call(); + + const wbtcExchange = new web3.eth.Contract( + uniswap.exchange.abi, + wbtcExchangeAddress + ); + + const wbtcBefore = await wbtcContract.methods.balanceOf(sender).call(); + console.log("Sender WBTC Before: ", wbtcBefore.toString()); + + const balanceBefore = await web3.eth.getBalance(sender); + console.log("Sender Balance Before: ", balanceBefore.toString()); + + await wbtcExchange.methods.ethToTokenSwapInput( + 1, // min amount of token retrieved + 2525644800, // random timestamp in the future (year 2050) + ).send( + { + gas: 4000000, + value: ether("10"), + from: sender + } + ); + + let wbtcAfter = await wbtcContract.methods.balanceOf(sender).call(); + console.log("Sender WBTC After: ", wbtcAfter.toString()); + const balanceAfter = await web3.eth.getBalance(sender); + console.log("Sender Balance After: ", balanceAfter.toString()); + + expect(wbtcAfter - wbtcBefore).to.be.at.least(10000000); + + // send WBTC to master + await wbtcContract.methods.transfer(dsrAddr, 10000000).send({from: sender}); + // send WBTC to connector + // await wbtcContract.methods.transfer(connectSBTCCurve.address, 10000000).send({from: sender}); + + // Send ETH to master + await web3.eth.sendTransaction({from: sender, to: masterAddress, value: ether("5")}); + + let connectorID = await connectSBTCCurve.connectorID(); + + // Enable the the given connector address + await connectorInstance.methods.enable(connectSBTCCurve.address).send({from: masterAddress}); + // check if the give connector address is enabled. + let isEnabled = await connectorInstance.methods.connectors(connectSBTCCurve.address).call(); + assert.ok(isEnabled); + }); + + it('can sell WBTC for SBTC', async function () { + const sbtcContract = new web3.eth.Contract(sbtcABI, "0xfe18be6b3bd88a2d2a7f928d00292e7a9963cfc6"); + + const sbtcBefore = await sbtcContract.methods.balanceOf(dsrAddr).call(); + console.log("Master SBTC Before: ", sbtcBefore.toString()); + let wbtcBefore = await wbtcContract.methods.balanceOf(dsrAddr).call(); + console.log("Master WBTC Before: ", wbtcBefore.toString()); + + const encoded = await connectSBTCCurve.contract.methods.sell( + "0xfe18be6b3bd88a2d2a7f928d00292e7a9963cfc6", + erc20.wbtc.address, + 10000000, + ( 0.09 / 0.1 * 1e18 ).toString(), + 0, + 0, + ).encodeABI(); + + await wbtcContract.methods.approve("0x7fC77b5c7614E1533320Ea6DDc2Eb61fa00A9714", 10000000).send({from: masterAddress}); + const curveSwapContract = new web3.eth.Contract(curveSwap, "0x7fC77b5c7614E1533320Ea6DDc2Eb61fa00A9714"); + const tx = await curveSwapContract.methods.exchange(1, 2, 1000000, 1).send({ from: masterAddress }); + console.log(tx); + + // const tx = await connectSBTCCurve.contract.methods.sell( + // "0xfe18be6b3bd88a2d2a7f928d00292e7a9963cfc6", + // erc20.wbtc.address, + // 1000000, + // 1, + // 0, + // 0, + // ).send({from: masterAddress}); + // console.log(tx); + + //Inputs for `cast()` function of DSA Account. + const castInputs = [ + [connectSBTCCurve.address], + [encoded], + masterAddress + ] + + // Execute `cast()` function + // const tx = await accountInstance.methods.cast(...castInputs).send({from: masterAddress}); + // console.log(tx); + + let wbtcAfter = await wbtcContract.methods.balanceOf(dsrAddr).call(); + console.log("Master WBTC After: ", wbtcAfter.toString()); + const sbtcAfter = await sbtcContract.methods.balanceOf(dsrAddr).call(); + console.log("Master SBTC After: ", sbtcAfter.toString()); + expect(sbtcAfter - sbtcBefore).to.be.at.least(+ether("0.09")); + }); + + it('can add and remove liquidity for wbtc', async function() { + const curveTokenContract = new web3.eth.Contract( + erc20ABI, + "0x075b1bb99792c9e1041ba13afef80c91a1e70fb3" + ) + + let wbtcBefore = await wbtcContract.methods.balanceOf(dsrAddr).call(); + console.log("Master WBTC Before: ", wbtcBefore.toString()); + + const encodedDeposit = await connectSBTCCurve.contract.methods.deposit( + erc20.wbtc.address, + 10000000, + ( 0.09 / 0.1 * 1e18 ).toString(), + 0, + 0 + ).encodeABI(); + + //Inputs for `cast()` function of DSA Account. + const castInputsDeposit = [ + [connectSBTCCurve.address], + [encodedDeposit], + masterAddress + ] + + // Execute `cast()` function + const txDeposit = await accountInstance.methods.cast(...castInputsDeposit).send({from: masterAddress}); + console.log(txDeposit); + + const balanceDeposit = await curveTokenContract.methods.balanceOf(dsrAddr); + + expect(balanceDeposit).to.be.at.least(ether("0.09")); + + const encodedWithdraw = await connectSBTCCurve.contract.methods.withdraw( + erc20.wbtc.address, + 10000000, + ( 0.09 / 0.1 * 1e18 ).toString(), + 0, + 0 + ).encodeABI(); + + //Inputs for `cast()` function of DSA Account. + const castInputsWithdraw = [ + [connectSBTCCurve.address], + [encodedWithdraw], + masterAddress + ] + + // Execute `cast()` function + const txWithdraw = await accountInstance.methods.cast(...castInputsWithdraw).send({from: masterAddress}); + console.log(txWithdraw); + + const balanceWithdraw = await curveTokenContract.methods.balanceOf(dsrAddr); + + expect(balanceWithdraw).to.equal(0); + }); + +}); diff --git a/test/abi/account.json b/test/abi/account.json new file mode 100644 index 0000000..cdac97a --- /dev/null +++ b/test/abi/account.json @@ -0,0 +1 @@ +[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"origin","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"LogCast","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"LogDisable","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"LogEnable","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"_shield","type":"bool"}],"name":"LogSwitchShield","type":"event"},{"inputs":[{"internalType":"address[]","name":"_targets","type":"address[]"},{"internalType":"bytes[]","name":"_datas","type":"bytes[]"},{"internalType":"address","name":"_origin","type":"address"}],"name":"cast","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"disable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"enable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"instaIndex","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"isAuth","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"shield","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_shield","type":"bool"}],"name":"switchShield","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}] diff --git a/test/abi/connectors.json b/test/abi/connectors.json new file mode 100644 index 0000000..1462cdc --- /dev/null +++ b/test/abi/connectors.json @@ -0,0 +1 @@ +[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"addr","type":"address"}],"name":"LogAddController","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"connector","type":"address"}],"name":"LogDisable","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"connector","type":"address"}],"name":"LogEnable","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"connector","type":"address"}],"name":"LogEnableStatic","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"addr","type":"address"}],"name":"LogRemoveController","type":"event"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"chief","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"connectorArray","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"connectorCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"connectorLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"connectors","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_connector","type":"address"}],"name":"disable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_userAddress","type":"address"}],"name":"disableChief","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_connector","type":"address"}],"name":"enable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_userAddress","type":"address"}],"name":"enableChief","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_connector","type":"address"}],"name":"enableStatic","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"instaIndex","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_connectors","type":"address[]"}],"name":"isConnector","outputs":[{"internalType":"bool","name":"isOk","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_connectors","type":"address[]"}],"name":"isStaticConnector","outputs":[{"internalType":"bool","name":"isOk","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"staticConnectorArray","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"staticConnectorLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"staticConnectors","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}] diff --git a/test/abi/curveSwap.json b/test/abi/curveSwap.json new file mode 100644 index 0000000..1e9cfe3 --- /dev/null +++ b/test/abi/curveSwap.json @@ -0,0 +1 @@ +[{"name":"TokenExchange","inputs":[{"type":"address","name":"buyer","indexed":true},{"type":"int128","name":"sold_id","indexed":false},{"type":"uint256","name":"tokens_sold","indexed":false},{"type":"int128","name":"bought_id","indexed":false},{"type":"uint256","name":"tokens_bought","indexed":false}],"anonymous":false,"type":"event"},{"name":"AddLiquidity","inputs":[{"type":"address","name":"provider","indexed":true},{"type":"uint256[3]","name":"token_amounts","indexed":false},{"type":"uint256[3]","name":"fees","indexed":false},{"type":"uint256","name":"invariant","indexed":false},{"type":"uint256","name":"token_supply","indexed":false}],"anonymous":false,"type":"event"},{"name":"RemoveLiquidity","inputs":[{"type":"address","name":"provider","indexed":true},{"type":"uint256[3]","name":"token_amounts","indexed":false},{"type":"uint256[3]","name":"fees","indexed":false},{"type":"uint256","name":"token_supply","indexed":false}],"anonymous":false,"type":"event"},{"name":"RemoveLiquidityOne","inputs":[{"type":"address","name":"provider","indexed":true},{"type":"uint256","name":"token_amount","indexed":false},{"type":"uint256","name":"coin_amount","indexed":false}],"anonymous":false,"type":"event"},{"name":"RemoveLiquidityImbalance","inputs":[{"type":"address","name":"provider","indexed":true},{"type":"uint256[3]","name":"token_amounts","indexed":false},{"type":"uint256[3]","name":"fees","indexed":false},{"type":"uint256","name":"invariant","indexed":false},{"type":"uint256","name":"token_supply","indexed":false}],"anonymous":false,"type":"event"},{"name":"CommitNewAdmin","inputs":[{"type":"uint256","name":"deadline","indexed":true,"unit":"sec"},{"type":"address","name":"admin","indexed":true}],"anonymous":false,"type":"event"},{"name":"NewAdmin","inputs":[{"type":"address","name":"admin","indexed":true}],"anonymous":false,"type":"event"},{"name":"CommitNewFee","inputs":[{"type":"uint256","name":"deadline","indexed":true,"unit":"sec"},{"type":"uint256","name":"fee","indexed":false},{"type":"uint256","name":"admin_fee","indexed":false}],"anonymous":false,"type":"event"},{"name":"NewFee","inputs":[{"type":"uint256","name":"fee","indexed":false},{"type":"uint256","name":"admin_fee","indexed":false}],"anonymous":false,"type":"event"},{"name":"RampA","inputs":[{"type":"uint256","name":"old_A","indexed":false},{"type":"uint256","name":"new_A","indexed":false},{"type":"uint256","name":"initial_time","indexed":false,"unit":"sec"},{"type":"uint256","name":"future_time","indexed":false,"unit":"sec"}],"anonymous":false,"type":"event"},{"name":"StopRampA","inputs":[{"type":"uint256","name":"A","indexed":false},{"type":"uint256","name":"t","indexed":false,"unit":"sec"}],"anonymous":false,"type":"event"},{"outputs":[],"inputs":[{"type":"address[3]","name":"_coins"},{"type":"address","name":"_pool_token"},{"type":"uint256","name":"_A"},{"type":"uint256","name":"_fee"}],"constant":false,"payable":false,"type":"constructor"},{"name":"A","outputs":[{"type":"uint256","name":""}],"inputs":[],"constant":true,"payable":false,"type":"function","gas":5227},{"name":"get_virtual_price","outputs":[{"type":"uint256","name":""}],"inputs":[],"constant":true,"payable":false,"type":"function","gas":1150488},{"name":"calc_token_amount","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"uint256[3]","name":"amounts"},{"type":"bool","name":"deposit"}],"constant":true,"payable":false,"type":"function","gas":4526955},{"name":"add_liquidity","outputs":[],"inputs":[{"type":"uint256[3]","name":"amounts"},{"type":"uint256","name":"min_mint_amount"}],"constant":false,"payable":false,"type":"function","gas":6972762},{"name":"get_dy","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"int128","name":"i"},{"type":"int128","name":"j"},{"type":"uint256","name":"dx"}],"constant":true,"payable":false,"type":"function","gas":2687932},{"name":"get_dy_underlying","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"int128","name":"i"},{"type":"int128","name":"j"},{"type":"uint256","name":"dx"}],"constant":true,"payable":false,"type":"function","gas":2687745},{"name":"exchange","outputs":[],"inputs":[{"type":"int128","name":"i"},{"type":"int128","name":"j"},{"type":"uint256","name":"dx"},{"type":"uint256","name":"min_dy"}],"constant":false,"payable":false,"type":"function","gas":5499133},{"name":"remove_liquidity","outputs":[],"inputs":[{"type":"uint256","name":"_amount"},{"type":"uint256[3]","name":"min_amounts"}],"constant":false,"payable":false,"type":"function","gas":196975},{"name":"remove_liquidity_imbalance","outputs":[],"inputs":[{"type":"uint256[3]","name":"amounts"},{"type":"uint256","name":"max_burn_amount"}],"constant":false,"payable":false,"type":"function","gas":6972281},{"name":"calc_withdraw_one_coin","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"uint256","name":"_token_amount"},{"type":"int128","name":"i"}],"constant":true,"payable":false,"type":"function","gas":15405},{"name":"remove_liquidity_one_coin","outputs":[],"inputs":[{"type":"uint256","name":"_token_amount"},{"type":"int128","name":"i"},{"type":"uint256","name":"min_amount"}],"constant":false,"payable":false,"type":"function","gas":4044074},{"name":"ramp_A","outputs":[],"inputs":[{"type":"uint256","name":"_future_A"},{"type":"uint256","unit":"sec","name":"_future_time"}],"constant":false,"payable":false,"type":"function","gas":151937},{"name":"stop_ramp_A","outputs":[],"inputs":[],"constant":false,"payable":false,"type":"function","gas":148697},{"name":"commit_new_fee","outputs":[],"inputs":[{"type":"uint256","name":"new_fee"},{"type":"uint256","name":"new_admin_fee"}],"constant":false,"payable":false,"type":"function","gas":110521},{"name":"apply_new_fee","outputs":[],"inputs":[],"constant":false,"payable":false,"type":"function","gas":97220},{"name":"revert_new_parameters","outputs":[],"inputs":[],"constant":false,"payable":false,"type":"function","gas":21955},{"name":"commit_transfer_ownership","outputs":[],"inputs":[{"type":"address","name":"_owner"}],"constant":false,"payable":false,"type":"function","gas":74632},{"name":"apply_transfer_ownership","outputs":[],"inputs":[],"constant":false,"payable":false,"type":"function","gas":60688},{"name":"revert_transfer_ownership","outputs":[],"inputs":[],"constant":false,"payable":false,"type":"function","gas":22045},{"name":"withdraw_admin_fees","outputs":[],"inputs":[],"constant":false,"payable":false,"type":"function","gas":17565},{"name":"kill_me","outputs":[],"inputs":[],"constant":false,"payable":false,"type":"function","gas":37998},{"name":"unkill_me","outputs":[],"inputs":[],"constant":false,"payable":false,"type":"function","gas":22135},{"name":"coins","outputs":[{"type":"address","name":""}],"inputs":[{"type":"int128","name":"arg0"}],"constant":true,"payable":false,"type":"function","gas":2310},{"name":"balances","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"int128","name":"arg0"}],"constant":true,"payable":false,"type":"function","gas":2340},{"name":"fee","outputs":[{"type":"uint256","name":""}],"inputs":[],"constant":true,"payable":false,"type":"function","gas":2171},{"name":"admin_fee","outputs":[{"type":"uint256","name":""}],"inputs":[],"constant":true,"payable":false,"type":"function","gas":2201},{"name":"owner","outputs":[{"type":"address","name":""}],"inputs":[],"constant":true,"payable":false,"type":"function","gas":2231},{"name":"initial_A","outputs":[{"type":"uint256","name":""}],"inputs":[],"constant":true,"payable":false,"type":"function","gas":2261},{"name":"future_A","outputs":[{"type":"uint256","name":""}],"inputs":[],"constant":true,"payable":false,"type":"function","gas":2291},{"name":"initial_A_time","outputs":[{"type":"uint256","unit":"sec","name":""}],"inputs":[],"constant":true,"payable":false,"type":"function","gas":2321},{"name":"future_A_time","outputs":[{"type":"uint256","unit":"sec","name":""}],"inputs":[],"constant":true,"payable":false,"type":"function","gas":2351},{"name":"admin_actions_deadline","outputs":[{"type":"uint256","unit":"sec","name":""}],"inputs":[],"constant":true,"payable":false,"type":"function","gas":2381},{"name":"transfer_ownership_deadline","outputs":[{"type":"uint256","unit":"sec","name":""}],"inputs":[],"constant":true,"payable":false,"type":"function","gas":2411},{"name":"future_fee","outputs":[{"type":"uint256","name":""}],"inputs":[],"constant":true,"payable":false,"type":"function","gas":2441},{"name":"future_admin_fee","outputs":[{"type":"uint256","name":""}],"inputs":[],"constant":true,"payable":false,"type":"function","gas":2471},{"name":"future_owner","outputs":[{"type":"address","name":""}],"inputs":[],"constant":true,"payable":false,"type":"function","gas":2501}] diff --git a/test/abi/sbtc.json b/test/abi/sbtc.json new file mode 100644 index 0000000..c227105 --- /dev/null +++ b/test/abi/sbtc.json @@ -0,0 +1 @@ +[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"spender","type":"address"},{"name":"value","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"}],"name":"nominateNewOwner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"from","type":"address"},{"name":"to","type":"address"},{"name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"nominatedOwner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_target","type":"address"}],"name":"setTarget","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"acceptOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"callData","type":"bytes"},{"name":"numTopics","type":"uint256"},{"name":"topic1","type":"bytes32"},{"name":"topic2","type":"bytes32"},{"name":"topic3","type":"bytes32"},{"name":"topic4","type":"bytes32"}],"name":"_emit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"useDELEGATECALL","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"value","type":"bool"}],"name":"setUseDELEGATECALL","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"target","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"owner","type":"address"},{"name":"spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_owner","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"newTarget","type":"address"}],"name":"TargetUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"newOwner","type":"address"}],"name":"OwnerNominated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"oldOwner","type":"address"},{"indexed":false,"name":"newOwner","type":"address"}],"name":"OwnerChanged","type":"event"}] diff --git a/truffle-config.js b/truffle-config.js index 71a9947..c1652ad 100644 --- a/truffle-config.js +++ b/truffle-config.js @@ -54,6 +54,12 @@ module.exports = { port: 8545, // Standard Ethereum port (default: none) network_id: "*", // Any network (default: none) }, + // Tenderly Proxy + proxy: { + host: "127.0.0.1", // Localhost (default: none) + port: 9545, // Standard Ethereum port (default: none) + network_id: "*", // Any network (default: none) + }, // Another network with more advanced options... // advanced: { @@ -108,7 +114,7 @@ module.exports = { // Configure your compilers compilers: { solc: { - version: "v0.6.0", // Fetch exact version from solc-bin (default: truffle's version) + version: "v0.6.2", // Fetch exact version from solc-bin (default: truffle's version) // docker: true, // Use "0.5.1" you've installed locally with docker (default: false) // settings: { // See the solidity docs for advice about optimization and evmVersion // optimizer: {