From 7060973727631905746c4022ef9f385c11389883 Mon Sep 17 00:00:00 2001
From: pradyuman-verma <pradyumnverma27@gmail.com>
Date: Sun, 16 Jan 2022 22:38:21 +0530
Subject: [PATCH] added 1inch v3 and v4

---
 .../connectors/1inch/1inch-v3/events.sol      |  12 ++
 .../connectors/1inch/1inch-v3/helpers.sol     |  22 +++
 .../connectors/1inch/1inch-v3/interface.sol   |  30 ++++
 .../connectors/1inch/1inch-v3/main.sol        | 128 ++++++++++++++++++
 .../connectors/1inch/1inch-v4/events.sol      |  12 ++
 .../connectors/1inch/1inch-v4/helpers.sol     |  13 ++
 .../connectors/1inch/1inch-v4/interface.sol   |  30 ++++
 .../connectors/1inch/1inch-v4/main.sol        | 111 +++++++++++++++
 8 files changed, 358 insertions(+)
 create mode 100644 contracts/optimism/connectors/1inch/1inch-v3/events.sol
 create mode 100644 contracts/optimism/connectors/1inch/1inch-v3/helpers.sol
 create mode 100644 contracts/optimism/connectors/1inch/1inch-v3/interface.sol
 create mode 100644 contracts/optimism/connectors/1inch/1inch-v3/main.sol
 create mode 100644 contracts/optimism/connectors/1inch/1inch-v4/events.sol
 create mode 100644 contracts/optimism/connectors/1inch/1inch-v4/helpers.sol
 create mode 100644 contracts/optimism/connectors/1inch/1inch-v4/interface.sol
 create mode 100644 contracts/optimism/connectors/1inch/1inch-v4/main.sol

diff --git a/contracts/optimism/connectors/1inch/1inch-v3/events.sol b/contracts/optimism/connectors/1inch/1inch-v3/events.sol
new file mode 100644
index 00000000..bec3b27a
--- /dev/null
+++ b/contracts/optimism/connectors/1inch/1inch-v3/events.sol
@@ -0,0 +1,12 @@
+pragma solidity ^0.7.0;
+
+contract Events {
+    event LogSell(
+        address indexed buyToken,
+        address indexed sellToken,
+        uint256 buyAmt,
+        uint256 sellAmt,
+        uint256 getId,
+        uint256 setId
+    );
+}
\ No newline at end of file
diff --git a/contracts/optimism/connectors/1inch/1inch-v3/helpers.sol b/contracts/optimism/connectors/1inch/1inch-v3/helpers.sol
new file mode 100644
index 00000000..fef36790
--- /dev/null
+++ b/contracts/optimism/connectors/1inch/1inch-v3/helpers.sol
@@ -0,0 +1,22 @@
+pragma solidity ^0.7.0;
+
+import { TokenInterface } from "../../../common/interfaces.sol";
+import { DSMath } from "../../../common/math.sol";
+import { Basic } from "../../../common/basic.sol";
+
+abstract contract Helpers is DSMath, Basic {
+    /**
+     * @dev 1Inch Address
+     */
+    address internal constant oneInchAddr = 0x11111112542D85B3EF69AE05771c2dCCff4fAa26;
+
+    /**
+     * @dev 1inch swap function sig
+     */
+    bytes4 internal constant oneInchSwapSig = 0x7c025200;
+
+     /**
+     * @dev 1inch swap function sig
+     */
+    bytes4 internal constant oneInchUnoswapSig = 0x2e95b6c8;
+}
\ No newline at end of file
diff --git a/contracts/optimism/connectors/1inch/1inch-v3/interface.sol b/contracts/optimism/connectors/1inch/1inch-v3/interface.sol
new file mode 100644
index 00000000..d2d790b7
--- /dev/null
+++ b/contracts/optimism/connectors/1inch/1inch-v3/interface.sol
@@ -0,0 +1,30 @@
+pragma solidity ^0.7.0;
+
+import { TokenInterface } from "../../../common/interfaces.sol";
+
+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);
+}
+
+struct OneInchData {
+    TokenInterface sellToken;
+    TokenInterface buyToken;
+    uint _sellAmt;
+    uint _buyAmt;
+    uint unitAmt;
+    bytes callData;
+}
\ No newline at end of file
diff --git a/contracts/optimism/connectors/1inch/1inch-v3/main.sol b/contracts/optimism/connectors/1inch/1inch-v3/main.sol
new file mode 100644
index 00000000..bee6070e
--- /dev/null
+++ b/contracts/optimism/connectors/1inch/1inch-v3/main.sol
@@ -0,0 +1,128 @@
+pragma solidity ^0.7.0;
+pragma experimental ABIEncoderV2;
+
+/**
+ * @title 1InchV3.
+ * @dev On-chain DEX Aggregator.
+ */
+
+// import files from common directory
+import { TokenInterface , MemoryInterface } from "../../../common/interfaces.sol";
+import { Stores } from "../../../common/stores.sol";
+import { OneInchInterace, OneInchData } from "./interface.sol";
+import { Helpers } from "./helpers.sol";
+import { Events } from "./events.sol";
+
+abstract contract OneInchResolver is Helpers, Events {
+    /**
+     * @dev 1inch swap uses `.call()`. This function restrict it to call only swap/trade functionality
+     * @param callData - calldata to extract the first 4 bytes for checking function signature
+     */
+    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))
+        }
+        isOk = sig == oneInchSwapSig || sig == oneInchUnoswapSig;
+    }
+
+    /**
+     * @dev 1inch API swap handler
+     * @param oneInchData - contains data returned from 1inch API. Struct defined in interfaces.sol
+     * @param ethAmt - Eth to swap for .value()
+     */
+    function oneInchSwap(
+        OneInchData memory oneInchData,
+        uint ethAmt
+    ) internal returns (uint buyAmt) {
+        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);
+
+        // solium-disable-next-line security/no-call-value
+        (bool success, ) = oneInchAddr.call{value: ethAmt}(oneInchData.callData);
+        if (!success) revert("1Inch-swap-failed");
+
+        uint finalBal = getTokenBal(buyToken);
+
+        buyAmt = sub(finalBal, initalBal);
+
+        require(_slippageAmt <= buyAmt, "Too much slippage");
+    }
+
+}
+
+abstract contract OneInchResolverHelpers is OneInchResolver {
+
+    /**
+     * @dev Gets the swapping data from 1inch's API.
+     * @param oneInchData Struct with multiple swap data defined in interfaces.sol 
+     * @param setId Set token amount at this ID in `InstaMemory` Contract.
+     */
+    function _sell(
+        OneInchData memory oneInchData,
+        uint setId
+    ) internal returns (OneInchData memory) {
+        TokenInterface _sellAddr = oneInchData.sellToken;
+
+        uint ethAmt;
+        if (address(_sellAddr) == ethAddr) {
+            ethAmt = oneInchData._sellAmt;
+        } else {
+            approve(TokenInterface(_sellAddr), oneInchAddr, oneInchData._sellAmt);
+        }
+
+        require(checkOneInchSig(oneInchData.callData), "Not-swap-function");
+
+        oneInchData._buyAmt = oneInchSwap(oneInchData, ethAmt);
+        setUint(setId, oneInchData._buyAmt);
+
+        return oneInchData;
+
+        // emitLogSellThree(oneInchData, setId);
+    }
+}
+
+abstract contract OneInch is OneInchResolverHelpers {
+    /**
+     * @dev Sell ETH/ERC20_Token using 1Inch.
+     * @notice Swap tokens from exchanges like kyber, 0x etc, with calculation done off-chain.
+     * @param buyAddr The address of the token to buy.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
+     * @param sellAddr The address of the token to sell.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
+     * @param sellAmt The amount of the token to sell.
+     * @param unitAmt The amount of buyAmt/sellAmt with slippage.
+     * @param callData Data from 1inch API. You can generate calldata for calling 1inch route for exchange: <a href="https://api.1inch.exchange/swagger/ethereum/#/Swap/SwapFactoryCommonController_getSwap" target="_blank">here </a>
+     * @param setId ID stores the amount of token brought.
+    */
+    function sell(
+        address buyAddr,
+        address sellAddr,
+        uint sellAmt,
+        uint unitAmt,
+        bytes calldata callData,
+        uint setId
+    ) external payable returns (string memory _eventName, bytes memory _eventParam) {
+        OneInchData memory oneInchData = OneInchData({
+            buyToken: TokenInterface(buyAddr),
+            sellToken: TokenInterface(sellAddr),
+            unitAmt: unitAmt,
+            callData: callData,
+            _sellAmt: sellAmt,
+            _buyAmt: 0
+        });
+
+        oneInchData = _sell(oneInchData, setId);
+
+        _eventName = "LogSell(address,address,uint256,uint256,uint256,uint256)";
+        _eventParam = abi.encode(buyAddr, sellAddr, oneInchData._buyAmt, oneInchData._sellAmt, 0, setId);
+    }
+}
+
+contract ConnectV2OneInchV3Optimism is OneInch {
+    string public name = "1Inch-v1.2";
+}
diff --git a/contracts/optimism/connectors/1inch/1inch-v4/events.sol b/contracts/optimism/connectors/1inch/1inch-v4/events.sol
new file mode 100644
index 00000000..bec3b27a
--- /dev/null
+++ b/contracts/optimism/connectors/1inch/1inch-v4/events.sol
@@ -0,0 +1,12 @@
+pragma solidity ^0.7.0;
+
+contract Events {
+    event LogSell(
+        address indexed buyToken,
+        address indexed sellToken,
+        uint256 buyAmt,
+        uint256 sellAmt,
+        uint256 getId,
+        uint256 setId
+    );
+}
\ No newline at end of file
diff --git a/contracts/optimism/connectors/1inch/1inch-v4/helpers.sol b/contracts/optimism/connectors/1inch/1inch-v4/helpers.sol
new file mode 100644
index 00000000..99e04f97
--- /dev/null
+++ b/contracts/optimism/connectors/1inch/1inch-v4/helpers.sol
@@ -0,0 +1,13 @@
+pragma solidity ^0.7.0;
+
+import { TokenInterface } from "../../../common/interfaces.sol";
+import { DSMath } from "../../../common/math.sol";
+import { Basic } from "../../../common/basic.sol";
+
+
+abstract contract Helpers is DSMath, Basic {
+    /**
+     * @dev 1Inch Address
+     */
+   address internal constant oneInchAddr = 0x1111111254760F7ab3F16433eea9304126DCd199;
+}
\ No newline at end of file
diff --git a/contracts/optimism/connectors/1inch/1inch-v4/interface.sol b/contracts/optimism/connectors/1inch/1inch-v4/interface.sol
new file mode 100644
index 00000000..d2d790b7
--- /dev/null
+++ b/contracts/optimism/connectors/1inch/1inch-v4/interface.sol
@@ -0,0 +1,30 @@
+pragma solidity ^0.7.0;
+
+import { TokenInterface } from "../../../common/interfaces.sol";
+
+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);
+}
+
+struct OneInchData {
+    TokenInterface sellToken;
+    TokenInterface buyToken;
+    uint _sellAmt;
+    uint _buyAmt;
+    uint unitAmt;
+    bytes callData;
+}
\ No newline at end of file
diff --git a/contracts/optimism/connectors/1inch/1inch-v4/main.sol b/contracts/optimism/connectors/1inch/1inch-v4/main.sol
new file mode 100644
index 00000000..59812799
--- /dev/null
+++ b/contracts/optimism/connectors/1inch/1inch-v4/main.sol
@@ -0,0 +1,111 @@
+pragma solidity ^0.7.0;
+pragma experimental ABIEncoderV2;
+
+/**
+ * @title 1InchV4.
+ * @dev On-chain DEX Aggregator.
+ */
+
+// import files from common directory
+import { TokenInterface , MemoryInterface } from "../../../common/interfaces.sol";
+import { Stores } from "../../../common/stores.sol";
+import { OneInchInterace, OneInchData } from "./interface.sol";
+import { Helpers } from "./helpers.sol";
+import { Events } from "./events.sol";
+
+abstract contract OneInchResolver is Helpers, Events {
+    /**
+     * @dev 1inch API swap handler
+     * @param oneInchData - contains data returned from 1inch API. Struct defined in interfaces.sol
+     * @param ethAmt - Eth to swap for .value()
+     */
+    function oneInchSwap(
+        OneInchData memory oneInchData,
+        uint ethAmt
+    ) internal returns (uint buyAmt) {
+        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);
+
+        // solium-disable-next-line security/no-call-value
+        (bool success, ) = oneInchAddr.call{value: ethAmt}(oneInchData.callData);
+        if (!success) revert("1Inch-swap-failed");
+
+        uint finalBal = getTokenBal(buyToken);
+
+        buyAmt = sub(finalBal, initalBal);
+
+        require(_slippageAmt <= buyAmt, "Too much slippage");
+    }
+
+}
+
+abstract contract OneInchResolverHelpers is OneInchResolver {
+
+    /**
+     * @dev Gets the swapping data from 1inch's API.
+     * @param oneInchData Struct with multiple swap data defined in interfaces.sol 
+     * @param setId Set token amount at this ID in `InstaMemory` Contract.
+     */
+    function _sell(
+        OneInchData memory oneInchData,
+        uint setId
+    ) internal returns (OneInchData memory) {
+        TokenInterface _sellAddr = oneInchData.sellToken;
+
+        uint ethAmt;
+        if (address(_sellAddr) == ethAddr) {
+            ethAmt = oneInchData._sellAmt;
+        } else {
+            approve(TokenInterface(_sellAddr), oneInchAddr, oneInchData._sellAmt);
+        }
+
+        oneInchData._buyAmt = oneInchSwap(oneInchData, ethAmt);
+        setUint(setId, oneInchData._buyAmt);
+
+        return oneInchData;
+
+    }
+}
+
+abstract contract OneInch is OneInchResolverHelpers {
+    /**
+     * @dev Sell ETH/ERC20_Token using 1Inch.
+     * @notice Swap tokens from exchanges like kyber, 0x etc, with calculation done off-chain.
+     * @param buyAddr The address of the token to buy.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
+     * @param sellAddr The address of the token to sell.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
+     * @param sellAmt The amount of the token to sell.
+     * @param unitAmt The amount of buyAmt/sellAmt with slippage.
+     * @param callData Data from 1inch API.
+     * @param setId ID stores the amount of token brought.
+    */
+    function sell(
+        address buyAddr,
+        address sellAddr,
+        uint sellAmt,
+        uint unitAmt,
+        bytes calldata callData,
+        uint setId
+    ) external payable returns (string memory _eventName, bytes memory _eventParam) {
+        OneInchData memory oneInchData = OneInchData({
+            buyToken: TokenInterface(buyAddr),
+            sellToken: TokenInterface(sellAddr),
+            unitAmt: unitAmt,
+            callData: callData,
+            _sellAmt: sellAmt,
+            _buyAmt: 0
+        });
+
+        oneInchData = _sell(oneInchData, setId);
+
+        _eventName = "LogSell(address,address,uint256,uint256,uint256,uint256)";
+        _eventParam = abi.encode(buyAddr, sellAddr, oneInchData._buyAmt, oneInchData._sellAmt, 0, setId);
+    }
+}
+
+contract ConnectV2OneInchV4Optimism is OneInch {
+    string public name = "1Inch-v4";
+}