From 5e6a194195348d95b0d21819c09a0c417990e7c3 Mon Sep 17 00:00:00 2001 From: Thrilok Kumar Date: Fri, 1 May 2020 21:32:33 +0530 Subject: [PATCH] Added oasis connector --- contracts/protocols/oasis.sol | 286 ++++++++++++++++++++++++++++++++++ 1 file changed, 286 insertions(+) create mode 100644 contracts/protocols/oasis.sol diff --git a/contracts/protocols/oasis.sol b/contracts/protocols/oasis.sol new file mode 100644 index 0000000..f073569 --- /dev/null +++ b/contracts/protocols/oasis.sol @@ -0,0 +1,286 @@ +pragma solidity ^0.6.0; + +interface OasisInterface { + function getMinSell(TokenInterface pay_gem) external view returns (uint); + function getBuyAmount(address dest, address src, uint srcAmt) external view returns(uint); + function getPayAmount(address src, address dest, uint destAmt) external view returns (uint); + function sellAllAmount( + address src, + uint srcAmt, + address dest, + uint minDest + ) external returns (uint destAmt); + function buyAllAmount( + address dest, + uint destAmt, + address src, + uint maxSrc + ) external returns (uint srcAmt); + + function getBestOffer(TokenInterface sell_gem, TokenInterface buy_gem) external view returns(uint); +} + +interface TokenInterface { + function allowance(address, address) external view returns (uint); + function balanceOf(address) external view returns (uint); + function decimals() external view returns (uint); + function approve(address, uint) external; + function transfer(address, uint) external returns (bool); + function transferFrom(address, address, uint) external returns (bool); + function deposit() external payable; + function withdraw(uint) external; +} + +interface AccountInterface { + function isAuth(address _user) external view returns (bool); +} + +interface MemoryInterface { + function getUint(uint _id) external returns (uint _num); + function setUint(uint _id, uint _val) external; +} + +interface EventInterface { + function emitEvent(uint _connectorType, uint _connectorID, bytes32 _eventCode, bytes calldata _eventData) external; +} + + +contract DSMath { + + function add(uint x, uint y) internal pure returns (uint z) { + require((z = x + y) >= x, "math-not-safe"); + } + + function mul(uint x, uint y) internal pure returns (uint z) { + require(y == 0 || (z = x * y) / y == x, "math-not-safe"); + } + + function sub(uint x, uint y) internal pure returns (uint z) { + require((z = x - y) <= x, "sub-overflow"); + } + + uint constant WAD = 10 ** 18; + + function wmul(uint x, uint y) internal pure returns (uint z) { + z = add(mul(x, y), WAD / 2) / WAD; + } + + function wdiv(uint x, uint y) internal pure returns (uint z) { + z = add(mul(x, WAD), y / 2) / y; + } + +} + + +contract Helpers is DSMath { + /** + * @dev Return ethereum address + */ + function getAddressETH() internal pure returns (address) { + return 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; // ETH Address + } + + /** + * @dev Return Memory Variable Address + */ + function getMemoryAddr() internal pure returns (address) { + return 0x8a5419CfC711B2343c17a6ABf4B2bAFaBb06957F; // InstaMemory Address + } + + /** + * @dev Return InstaEvent Address. + */ + function getEventAddr() internal pure returns (address) { + return 0x2af7ea6Cb911035f3eb1ED895Cb6692C39ecbA97; // InstaEvent Address + } + + /** + * @dev Get Uint value from InstaMemory Contract. + */ + function getUint(uint getId, uint val) internal returns (uint returnVal) { + returnVal = getId == 0 ? val : MemoryInterface(getMemoryAddr()).getUint(getId); + } + + /** + * @dev Set Uint value in InstaMemory Contract. + */ + function setUint(uint setId, uint val) internal { + if (setId != 0) MemoryInterface(getMemoryAddr()).setUint(setId, val); + } + + /** + * @dev Connector Details + */ + function connectorID() public pure returns(uint _type, uint _id) { + (_type, _id) = (1, 11); + } +} + + +contract OasisHelpers is Helpers { + /** + * @dev Return WETH address + */ + function getAddressWETH() internal pure returns (address) { + return 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; + } + + /** + * @dev Return Oasis Address + */ + function getOasisAddr() internal pure returns (address) { + return 0x794e6e91555438aFc3ccF1c5076A74F42133d08D; + } + + function convert18ToDec(uint _dec, uint256 _amt) internal pure returns (uint256 amt) { + amt = (_amt / 10 ** (18 - _dec)); + } + + function changeEthAddress(address buy, address sell) internal pure returns(TokenInterface _buy, TokenInterface _sell){ + _buy = buy == getAddressETH() ? TokenInterface(getAddressWETH()) : TokenInterface(buy); + _sell = sell == getAddressETH() ? TokenInterface(getAddressWETH()) : TokenInterface(sell); + } + + function convertEthToWeth(TokenInterface token, uint amount) internal { + if(address(token) == getAddressWETH()) token.deposit.value(amount)(); + } + + function convertWethToEth(TokenInterface token, uint amount) internal { + if(address(token) == getAddressWETH()) { + token.approve(getAddressWETH(), amount); + token.withdraw(amount); + } + } +} + + +contract OasisResolver is OasisHelpers { + event LogBuy( + address indexed buyToken, + address indexed sellToken, + uint256 buyAmt, + uint256 sellAmt, + uint256 getId, + uint256 setId + ); + + event LogSell( + address indexed buyToken, + address indexed sellToken, + uint256 buyAmt, + uint256 sellAmt, + uint256 getId, + uint256 setId + ); + + /** + * @dev Buy ETH/ERC20_Token. + * @param buyAddr buying token address.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param sellAddr selling token amount.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param buyAmt buying token amount. + * @param unitAmt unit amount of sellAmt/buyAmt 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 buy( + address buyAddr, + address sellAddr, + uint buyAmt, + uint unitAmt, + uint getId, + uint setId + ) external payable { + uint _buyAmt = getUint(getId, buyAmt); + (TokenInterface _buyAddr, TokenInterface _sellAddr) = changeEthAddress(buyAddr, sellAddr); + + uint _slippageAmt = convert18ToDec(_sellAddr.decimals(), wmul(unitAmt, _buyAmt)); + + OasisInterface oasisContract = OasisInterface(getOasisAddr()); + + require(oasisContract.getBestOffer(_sellAddr, _buyAddr) != 0, "no-offer"); + require(oasisContract.getMinSell(_sellAddr) <= _slippageAmt, "less-than-min-pay-amt"); + + uint _expectedAmt = oasisContract.getPayAmount(address(_sellAddr), address(_buyAddr), _buyAmt); + require(_slippageAmt >= _expectedAmt, "Too much slippage"); + + convertEthToWeth(_sellAddr, _expectedAmt); + _sellAddr.approve(getOasisAddr(), _expectedAmt); + + uint _sellAmt = oasisContract.buyAllAmount( + address(_buyAddr), + _buyAmt, + address(_sellAddr), + _slippageAmt + ); + + convertWethToEth(_buyAddr, _buyAmt); + + setUint(setId, _sellAmt); + + emit LogBuy(buyAddr, sellAddr, _buyAmt, _sellAmt, getId, setId); + bytes32 _eventCode = keccak256("LogBuy(address,address,uint256,uint256,uint256,uint256)"); + bytes memory _eventParam = abi.encode(buyAddr, sellAddr, _buyAmt, _sellAmt, getId, setId); + (uint _type, uint _id) = connectorID(); + EventInterface(getEventAddr()).emitEvent(_type, _id, _eventCode, _eventParam); + } + + /** + * @dev Sell ETH/ERC20_Token. + * @param buyAddr buying token address.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param sellAddr selling token amount.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @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); + (TokenInterface _buyAddr, TokenInterface _sellAddr) = changeEthAddress(buyAddr, sellAddr); + + if (_sellAmt == uint(-1)) { + _sellAmt = sellAddr == getAddressETH() ? address(this).balance : _buyAddr.balanceOf(address(this)); + } + + uint _slippageAmt = convert18ToDec(_buyAddr.decimals(), wmul(unitAmt, _sellAmt)); + + OasisInterface oasisContract = OasisInterface(getOasisAddr()); + + require(oasisContract.getBestOffer(_sellAddr, _buyAddr) != 0, "no-offer"); + require(oasisContract.getMinSell(_sellAddr) <= _sellAmt, "less-than-min-pay-amt"); + + uint _expectedAmt = oasisContract.getBuyAmount(address(_buyAddr), address(_sellAddr), _sellAmt); + require(_slippageAmt <= _expectedAmt, "Too much slippage"); + + convertEthToWeth(_sellAddr, _sellAmt); + _sellAddr.approve(getOasisAddr(), _sellAmt); + + uint _buyAmt = oasisContract.sellAllAmount( + address(_sellAddr), + _sellAmt, + address(_buyAddr), + _slippageAmt + ); + + convertWethToEth(_buyAddr, _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); + (uint _type, uint _id) = connectorID(); + EventInterface(getEventAddr()).emitEvent(_type, _id, _eventCode, _eventParam); + } +} + + +contract ConnectOasis is OasisResolver { + string public name = "Oasis-v1.1"; +} \ No newline at end of file