dsa-connectors-old/contracts/connectors/1inch.sol

323 lines
10 KiB
Solidity
Raw Normal View History

2020-05-08 09:11:46 +00:00
pragma solidity ^0.6.0;
2020-05-08 21:11:13 +00:00
// import files from common directory
import { TokenInterface , MemoryInterface, EventInterface} from "../common/interfaces.sol";
import { Stores } from "../common/stores.sol";
import { DSMath } from "../common/math.sol";
2020-07-29 13:51:14 +00:00
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
2020-05-08 09:11:46 +00:00
interface OneInchInterace {
function swap(
TokenInterface fromToken,
TokenInterface toToken,
uint256 fromTokenAmount,
uint256 minReturnAmount,
uint256 guaranteedAmount,
address payable referrer,
address[] calldata callAddresses,
bytes calldata callDataConcat,
uint256[] calldata starts,
uint256[] calldata gasLimitsAndValues
)
external
payable
returns (uint256 returnAmount);
}
2020-05-08 21:11:13 +00:00
contract OneHelpers is Stores, DSMath {
2020-07-29 13:51:14 +00:00
using SafeERC20 for IERC20;
2020-05-08 09:11:46 +00:00
/**
2020-05-08 21:11:13 +00:00
* @dev Return 1Inch Address
2020-05-08 09:11:46 +00:00
*/
function getOneInchAddress() internal pure returns (address) {
return 0x11111254369792b2Ca5d084aB5eEA397cA8fa48B;
}
2020-05-10 21:53:56 +00:00
/**
2020-07-24 12:52:04 +00:00
* @dev Return 1inch Token Taker Address
2020-05-10 21:53:56 +00:00
*/
2020-07-24 12:58:26 +00:00
function getOneInchTokenTaker() internal pure returns (address payable) {
2020-05-10 21:53:56 +00:00
return 0xE4C9194962532fEB467DCe8b3d42419641c6eD2E;
}
2020-05-09 20:28:08 +00:00
/**
2020-07-24 12:52:04 +00:00
* @dev Return 1inch swap function sig
2020-05-09 20:28:08 +00:00
*/
2020-07-24 12:58:26 +00:00
function getOneInchSig() internal pure returns (bytes4) {
2020-05-09 20:28:08 +00:00
return 0xf88309d7;
}
2020-07-24 11:12:04 +00:00
function getReferralAddr() internal pure returns (address) {
2020-07-30 13:20:25 +00:00
return 0xa7615CD307F323172331865181DC8b80a2834324; // TODO - change address
2020-07-24 11:12:04 +00:00
}
2020-05-08 09:11:46 +00:00
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 getTokenBal(TokenInterface token) internal view returns(uint _amt) {
2020-05-08 21:11:13 +00:00
_amt = address(token) == getEthAddr() ? address(this).balance : token.balanceOf(address(this));
2020-05-08 09:11:46 +00:00
}
function getTokensDec(TokenInterface buyAddr, TokenInterface sellAddr) internal view returns(uint buyDec, uint sellDec) {
2020-05-08 21:11:13 +00:00
buyDec = address(buyAddr) == getEthAddr() ? 18 : buyAddr.decimals();
sellDec = address(sellAddr) == getEthAddr() ? 18 : sellAddr.decimals();
2020-05-08 09:11:46 +00:00
}
2020-07-24 11:59:21 +00:00
2020-07-29 13:51:14 +00:00
function _transfer(address payable to, IERC20 token, uint _amt) internal {
address(token) == getEthAddr() ?
to.transfer(_amt) :
token.safeTransfer(to, _amt);
}
function takeFee(
address token,
uint amount,
address feeCollector,
uint feePercent
) internal returns (uint leftAmt, uint feeAmount){
if (feeCollector != address(0)) {
feeAmount = wmul(amount, feePercent);
leftAmt = sub(amount, feeAmount);
uint feeCollectorAmt = wmul(feeAmount, 3 * 10 ** 17);
uint restAmt = sub(feeAmount, feeCollectorAmt);
_transfer(payable(feeCollector), IERC20(token), feeCollectorAmt);
2020-07-30 13:20:25 +00:00
_transfer(payable(getReferralAddr()), IERC20(token), restAmt);
2020-07-29 13:51:14 +00:00
} else {
leftAmt = amount;
}
}
2020-05-08 09:11:46 +00:00
}
contract Resolver is OneHelpers {
2020-05-09 20:28:08 +00:00
function checkOneInchSig(bytes memory callData) internal pure returns(bool isOk) {
bytes memory _data = callData;
bytes4 sig;
// solium-disable-next-line security/no-inline-assembly
assembly {
sig := mload(add(_data, 32))
}
2020-07-24 12:58:26 +00:00
isOk = sig == getOneInchSig();
2020-05-09 20:28:08 +00:00
}
2020-07-31 07:31:21 +00:00
struct OneInchData {
2020-07-30 13:20:25 +00:00
TokenInterface sellToken;
TokenInterface buyToken;
uint _sellAmt;
uint _buyAmt;
uint unitAmt;
2020-07-31 07:31:21 +00:00
bytes callData;
2020-07-30 13:20:25 +00:00
address feeCollector;
uint256 feeAmount;
2020-07-24 11:12:04 +00:00
}
2020-05-09 00:40:44 +00:00
function oneInchSwap(
2020-07-31 07:31:21 +00:00
OneInchData memory oneInchData,
2020-05-09 00:40:44 +00:00
uint ethAmt
) internal returns (uint buyAmt) {
2020-07-31 07:31:21 +00:00
TokenInterface buyToken = oneInchData.buyToken;
(uint _buyDec, uint _sellDec) = getTokensDec(buyToken, oneInchData.sellToken);
uint _sellAmt18 = convertTo18(_sellDec, oneInchData._sellAmt);
uint _slippageAmt = convert18ToDec(_buyDec, wmul(oneInchData.unitAmt, _sellAmt18));
uint initalBal = getTokenBal(buyToken);
2020-05-09 00:40:44 +00:00
// solium-disable-next-line security/no-call-value
2020-07-31 07:31:21 +00:00
(bool success, ) = address(getOneInchAddress()).call.value(ethAmt)(oneInchData.callData);
2020-05-09 00:40:44 +00:00
if (!success) revert("1Inch-swap-failed");
2020-07-31 07:31:21 +00:00
uint finalBal = getTokenBal(buyToken);
2020-05-09 00:40:44 +00:00
buyAmt = sub(finalBal, initalBal);
require(_slippageAmt <= buyAmt, "Too much slippage");
}
2020-07-30 13:20:25 +00:00
2020-05-08 09:11:46 +00:00
}
2020-07-31 07:31:21 +00:00
contract OneInchEventResolver is Resolver {
2020-05-08 10:36:46 +00:00
event LogSell(
2020-05-08 09:11:46 +00:00
address indexed buyToken,
address indexed sellToken,
uint256 buyAmt,
uint256 sellAmt,
uint256 getId,
uint256 setId
);
2020-07-30 13:20:25 +00:00
event LogSellFee(
address indexed buyToken,
address indexed sellToken,
2020-07-30 11:56:39 +00:00
uint256 buyAmt,
uint256 sellAmt,
2020-07-30 13:20:25 +00:00
address indexed collector,
uint256 fee,
uint256 getId,
uint256 setId
);
function emitLogSell(
2020-07-31 07:31:21 +00:00
OneInchData memory oneInchData,
2020-07-30 11:56:39 +00:00
uint256 setId
) internal {
bytes32 _eventCode;
bytes memory _eventParam;
2020-07-31 07:31:21 +00:00
if (oneInchData.feeCollector == address(0)) {
2020-07-30 13:20:25 +00:00
emit LogSell(
2020-07-31 07:31:21 +00:00
address(oneInchData.buyToken),
address(oneInchData.sellToken),
oneInchData._buyAmt,
oneInchData._sellAmt,
0,
2020-07-30 13:20:25 +00:00
setId
);
2020-07-30 11:56:39 +00:00
_eventCode = keccak256("LogSell(address,address,uint256,uint256,uint256,uint256)");
2020-07-30 13:20:25 +00:00
_eventParam = abi.encode(
2020-07-31 07:31:21 +00:00
address(oneInchData.buyToken),
address(oneInchData.sellToken),
oneInchData._buyAmt,
oneInchData._sellAmt,
0,
2020-07-30 13:20:25 +00:00
setId
);
} else {
emit LogSellFee(
2020-07-31 07:31:21 +00:00
address(oneInchData.buyToken),
address(oneInchData.sellToken),
oneInchData._buyAmt,
oneInchData._sellAmt,
oneInchData.feeCollector,
oneInchData.feeAmount,
0,
2020-07-30 13:20:25 +00:00
setId
);
_eventCode = keccak256("LogSellFee(address,address,uint256,uint256,uint256,uint256)");
_eventParam = abi.encode(
2020-07-31 07:31:21 +00:00
address(oneInchData.buyToken),
address(oneInchData.sellToken),
oneInchData._buyAmt,
oneInchData._sellAmt,
oneInchData.feeCollector,
oneInchData.feeAmount,
0,
2020-07-30 13:20:25 +00:00
setId
);
2020-07-30 11:56:39 +00:00
}
emitEvent(_eventCode, _eventParam);
}
2020-07-31 07:31:21 +00:00
}
2020-07-30 11:56:39 +00:00
2020-07-31 07:31:21 +00:00
contract OneInchResolverHelpers is OneInchEventResolver {
function _sell (
OneInchData memory oneInchData,
uint feePercent,
uint setId
2020-07-30 11:56:39 +00:00
) internal {
2020-07-31 07:31:21 +00:00
TokenInterface _buyAddr = oneInchData.buyToken;
TokenInterface _sellAddr = oneInchData.sellToken;
2020-07-30 13:20:25 +00:00
2020-07-31 07:31:21 +00:00
uint ethAmt;
if (address(_sellAddr) == getEthAddr()) {
ethAmt = oneInchData._sellAmt;
2020-07-30 13:20:25 +00:00
} else {
2020-07-31 07:31:21 +00:00
TokenInterface(_sellAddr).approve(getOneInchTokenTaker(), oneInchData._sellAmt);
2020-07-30 11:56:39 +00:00
}
2020-05-09 07:26:03 +00:00
2020-07-31 07:31:21 +00:00
require(checkOneInchSig(oneInchData.callData), "Not-swap-function");
2020-07-30 13:20:25 +00:00
2020-07-31 07:31:21 +00:00
uint buyAmt = oneInchSwap(oneInchData, ethAmt);
2020-07-30 13:20:25 +00:00
(uint feeAmount, uint leftBuyAmt) = takeFee(
2020-07-31 07:31:21 +00:00
address(_buyAddr),
buyAmt,
oneInchData.feeCollector,
2020-07-30 13:20:25 +00:00
feePercent
);
setUint(setId, leftBuyAmt);
2020-07-31 07:31:21 +00:00
oneInchData.feeAmount = feeAmount;
2020-07-30 13:20:25 +00:00
2020-07-31 07:31:21 +00:00
emitLogSell(oneInchData, setId);
2020-07-30 13:20:25 +00:00
}
}
2020-07-31 07:31:21 +00:00
contract OneInchResolver is OneInchResolverHelpers {
2020-05-11 00:18:40 +00:00
/**
2020-07-31 07:31:21 +00:00
* @dev Sell ETH/ERC20_Token using 1inch.
2020-05-11 00:18:40 +00:00
* @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.
2020-07-31 07:31:21 +00:00
* @param callData Data from 1inch API.
2020-05-11 00:18:40 +00:00
* @param setId Set token amount at this ID in `InstaMemory` Contract.
*/
2020-05-08 09:11:46 +00:00
function sell(
address buyAddr,
address sellAddr,
uint sellAmt,
uint unitAmt,
2020-07-31 07:31:21 +00:00
bytes calldata callData,
2020-05-08 09:11:46 +00:00
uint setId
2020-05-09 20:28:08 +00:00
) external payable {
2020-07-31 07:31:21 +00:00
OneInchData memory oneInchData = OneInchData({
2020-07-30 13:20:25 +00:00
buyToken: TokenInterface(buyAddr),
sellToken: TokenInterface(sellAddr),
unitAmt: unitAmt,
2020-07-31 07:31:21 +00:00
callData: callData,
2020-07-30 13:20:25 +00:00
feeCollector: address(0),
_sellAmt: sellAmt,
_buyAmt: 0,
feeAmount: 0
});
2020-07-31 07:31:21 +00:00
_sell(oneInchData, 0, setId);
2020-07-30 13:20:25 +00:00
}
2020-05-09 20:28:08 +00:00
2020-07-30 13:20:25 +00:00
/**
2020-07-31 07:31:21 +00:00
* @dev Sell ETH/ERC20_Token using 1inch.
2020-07-30 13:20:25 +00:00
* @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.
2020-07-31 07:31:21 +00:00
* @param callData Data from 1inch API.
2020-07-30 13:20:25 +00:00
* @param feeCollector Fee amount to transfer.
* @param feePercent Fee percentage on buyAmt.
* @param setId Set token amount at this ID in `InstaMemory` Contract.
*/
function sellFee(
address buyAddr,
address sellAddr,
uint sellAmt,
uint unitAmt,
2020-07-31 07:31:21 +00:00
bytes calldata callData,
2020-07-30 13:20:25 +00:00
address feeCollector,
uint feePercent,
uint setId
) external payable {
require(feePercent > 0 && feePercent <= 2*10*16, "Fee more than 2%");
require(feeCollector != address(0), "feeCollector is not vaild address");
2020-07-31 07:31:21 +00:00
OneInchData memory oneInchData = OneInchData({
2020-07-30 13:20:25 +00:00
buyToken: TokenInterface(buyAddr),
sellToken: TokenInterface(sellAddr),
_sellAmt: sellAmt,
unitAmt: unitAmt,
2020-07-31 07:31:21 +00:00
callData: callData,
2020-07-30 13:20:25 +00:00
feeCollector: feeCollector,
_buyAmt: 0,
feeAmount: 0
});
2020-07-31 07:31:21 +00:00
_sell(oneInchData, feePercent, setId);
2020-07-24 11:12:04 +00:00
}
}
2020-07-30 13:20:25 +00:00
2020-07-24 11:12:04 +00:00
contract ConnectOne is OneInchResolver {
2020-07-31 07:31:21 +00:00
string public name = "1Inch-v1";
2020-05-08 09:11:46 +00:00
}