diff --git a/contracts/mainnet/connectors/0x/helpers.sol b/contracts/mainnet/connectors/0x/helpers.sol index 7919436d..459d3abd 100644 --- a/contracts/mainnet/connectors/0x/helpers.sol +++ b/contracts/mainnet/connectors/0x/helpers.sol @@ -3,11 +3,66 @@ pragma solidity ^0.7.0; import {TokenInterface} from "../../common/interfaces.sol"; import {DSMath} from "../../common/math.sol"; import {Basic} from "../../common/basic.sol"; +import {ZeroExData, zeroExInterface} from "./interface.sol"; -abstract contract Helpers is DSMath, Basic { +contract Helpers is DSMath, Basic { /** * @dev 0x Address */ address internal constant zeroExAddr = 0xDef1C0ded9bec7F1a1670819833240f027b25EfF; + + function _swapHelper(ZeroExData memory zeroExData, uint256 ethAmt) + internal + returns (uint256 buyAmt) + { + TokenInterface buyToken = zeroExData.buyToken; + (uint256 _buyDec, uint256 _sellDec) = getTokensDec( + buyToken, + zeroExData.sellToken + ); + uint256 _sellAmt18 = convertTo18(_sellDec, zeroExData._sellAmt); + uint256 _slippageAmt = convert18ToDec( + _buyDec, + wmul(zeroExData.unitAmt, _sellAmt18) + ); + + uint256 initalBal = getTokenBal(buyToken); + + // solium-disable-next-line security/no-call-value + (bool success, ) = zeroExAddr.call{value: ethAmt}(zeroExData.callData); + if (!success) revert("0x-swap-failed"); + + uint256 finalBal = getTokenBal(buyToken); + + buyAmt = sub(finalBal, initalBal); + + require(_slippageAmt <= buyAmt, "Too much slippage"); + } + + function _swap(ZeroExData memory zeroExData, uint256 setId) + internal + returns (ZeroExData memory) + { + TokenInterface _sellAddr = zeroExData.sellToken; + + uint256 ethAmt; + if (address(_sellAddr) == ethAddr) { + ethAmt = zeroExData._sellAmt; + } else { + address transformWallet = address( + zeroExInterface(zeroExAddr).getTransformWallet() + ); + approve( + TokenInterface(_sellAddr), + transformWallet, + zeroExData._sellAmt + ); + } + + zeroExData._buyAmt = _swapHelper(zeroExData, ethAmt); + setUint(setId, zeroExData._buyAmt); + + return zeroExData; + } } diff --git a/contracts/mainnet/connectors/0x/interface.sol b/contracts/mainnet/connectors/0x/interface.sol index a261afce..d6c7c57e 100644 --- a/contracts/mainnet/connectors/0x/interface.sol +++ b/contracts/mainnet/connectors/0x/interface.sol @@ -3,14 +3,6 @@ pragma solidity ^0.7.0; import {TokenInterface} from "../../common/interfaces.sol"; interface zeroExInterface { - // function transformERC20( - // IERC20TokenV06 inputToken, - // IERC20TokenV06 outputToken, - // uint256 inputTokenAmount, - // uint256 minOutputTokenAmount, - // Transformation[] calldata transformations - // ) external payable returns (uint256 outputTokenAmount); - function getTransformWallet() external view returns (IFlashWallet wallet); } diff --git a/contracts/mainnet/connectors/0x/main.sol b/contracts/mainnet/connectors/0x/main.sol index f55c496b..bd0e27b9 100644 --- a/contracts/mainnet/connectors/0x/main.sol +++ b/contracts/mainnet/connectors/0x/main.sol @@ -12,63 +12,7 @@ import {ZeroExData, zeroExInterface} from "./interface.sol"; import {Helpers} from "./helpers.sol"; import {Events} from "./events.sol"; -contract zeroExHelper is Helpers { - function zeroExSwap(ZeroExData memory zeroExData, uint256 ethAmt) - internal - returns (uint256 buyAmt) - { - TokenInterface buyToken = zeroExData.buyToken; - (uint256 _buyDec, uint256 _sellDec) = getTokensDec( - buyToken, - zeroExData.sellToken - ); - uint256 _sellAmt18 = convertTo18(_sellDec, zeroExData._sellAmt); - uint256 _slippageAmt = convert18ToDec( - _buyDec, - wmul(zeroExData.unitAmt, _sellAmt18) - ); - - uint256 initalBal = getTokenBal(buyToken); - - // solium-disable-next-line security/no-call-value - (bool success, ) = zeroExAddr.call{value: ethAmt}(zeroExData.callData); - if (!success) revert("0x-swap-failed"); - - uint256 finalBal = getTokenBal(buyToken); - - buyAmt = sub(finalBal, initalBal); - - require(_slippageAmt <= buyAmt, "Too much slippage"); - } - - function _swap(ZeroExData memory zeroExData, uint256 setId) - internal - returns (ZeroExData memory) - { - TokenInterface _sellAddr = zeroExData.sellToken; - - uint256 ethAmt; - if (address(_sellAddr) == ethAddr) { - ethAmt = zeroExData._sellAmt; - } else { - address transformWallet = address( - zeroExInterface(zeroExAddr).getTransformWallet() - ); - approve( - TokenInterface(_sellAddr), - transformWallet, - zeroExData._sellAmt - ); - } - - zeroExData._buyAmt = zeroExSwap(zeroExData, ethAmt); - setUint(setId, zeroExData._buyAmt); - - return zeroExData; - } -} - -abstract contract ZeroEx is zeroExHelper { +abstract contract ZeroEx is Helpers { /** * @dev Sell ETH/ERC20_Token using 0x. * @param buyAddr The address of the token to buy.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) @@ -115,5 +59,5 @@ abstract contract ZeroEx is zeroExHelper { } contract ConnectV2ZeroEx is ZeroEx { - string public name = ""; + string public name = "0x-V4"; } diff --git a/contracts/polygon/connectors/0x/events.sol b/contracts/polygon/connectors/0x/events.sol new file mode 100644 index 00000000..66f9943a --- /dev/null +++ b/contracts/polygon/connectors/0x/events.sol @@ -0,0 +1,12 @@ +pragma solidity ^0.7.0; + +contract Events { + event LogSwap( + address indexed buyToken, + address indexed sellToken, + uint256 buyAmt, + uint256 sellAmt, + uint256 getId, + uint256 setId + ); +} diff --git a/contracts/polygon/connectors/0x/helpers.sol b/contracts/polygon/connectors/0x/helpers.sol new file mode 100644 index 00000000..835b8d7d --- /dev/null +++ b/contracts/polygon/connectors/0x/helpers.sol @@ -0,0 +1,70 @@ +pragma solidity ^0.7.0; + +import {TokenInterface} from "../../common/interfaces.sol"; +import {DSMath} from "../../common/math.sol"; +import {ZeroExData, zeroExInterface} from "./interface.sol"; +import {Basic} from "../../common/basic.sol"; + +contract Helpers is DSMath, Basic { + /** + * @dev 0x Address + */ + address internal constant zeroExAddr = + 0xDef1C0ded9bec7F1a1670819833240f027b25EfF; + + function _swapHelper(ZeroExData memory zeroExData, uint256 maticAmt) + internal + returns (uint256 buyAmt) + { + TokenInterface buyToken = zeroExData.buyToken; + (uint256 _buyDec, uint256 _sellDec) = getTokensDec( + buyToken, + zeroExData.sellToken + ); + uint256 _sellAmt18 = convertTo18(_sellDec, zeroExData._sellAmt); + uint256 _slippageAmt = convert18ToDec( + _buyDec, + wmul(zeroExData.unitAmt, _sellAmt18) + ); + + uint256 initalBal = getTokenBal(buyToken); + + // solium-disable-next-line security/no-call-value + (bool success, ) = zeroExAddr.call{value: maticAmt}( + zeroExData.callData + ); + if (!success) revert("0x-swap-failed"); + + uint256 finalBal = getTokenBal(buyToken); + + buyAmt = sub(finalBal, initalBal); + + require(_slippageAmt <= buyAmt, "Too much slippage"); + } + + function _swap(ZeroExData memory zeroExData, uint256 setId) + internal + returns (ZeroExData memory) + { + TokenInterface _sellAddr = zeroExData.sellToken; + + uint256 maticAmt; + if (address(_sellAddr) == maticAddr) { + maticAmt = zeroExData._sellAmt; + } else { + address transformWallet = address( + zeroExInterface(zeroExAddr).getTransformWallet() + ); + approve( + TokenInterface(_sellAddr), + transformWallet, + zeroExData._sellAmt + ); + } + + zeroExData._buyAmt = _swapHelper(zeroExData, maticAmt); + setUint(setId, zeroExData._buyAmt); + + return zeroExData; + } +} diff --git a/contracts/polygon/connectors/0x/interface.sol b/contracts/polygon/connectors/0x/interface.sol new file mode 100644 index 00000000..79952c90 --- /dev/null +++ b/contracts/polygon/connectors/0x/interface.sol @@ -0,0 +1,49 @@ +pragma solidity ^0.7.0; + +import {TokenInterface} from "../../common/interfaces.sol"; + +interface zeroExInterface { + function getTransformWallet() external view returns (IFlashWallet wallet); +} + +interface IFlashWallet { + /// @dev Execute an arbitrary call. Only an authority can call this. + /// @param target The call target. + /// @param callData The call data. + /// @param value Ether to attach to the call. + /// @return resultData The data returned by the call. + + function executeCall( + address payable target, + bytes calldata callData, + uint256 value + ) external payable returns (bytes memory resultData); + + /// @dev Execute an arbitrary delegatecall, in the context of this puppet. + /// Only an authority can call this. + /// @param target The call target. + /// @param callData The call data. + /// @return resultData The data returned by the call. + + function executeDelegateCall( + address payable target, + bytes calldata callData + ) external payable returns (bytes memory resultData); + + /// @dev Allows the puppet to receive ETH. + receive() external payable; + + /// @dev Fetch the immutable owner/deployer of this contract. + /// @return owner_ The immutable owner/deployer/ + + function owner() external view returns (address owner_); +} + +struct ZeroExData { + TokenInterface sellToken; + TokenInterface buyToken; + uint256 _sellAmt; + uint256 _buyAmt; + uint256 unitAmt; + bytes callData; +} diff --git a/contracts/polygon/connectors/0x/main.sol b/contracts/polygon/connectors/0x/main.sol new file mode 100644 index 00000000..bd0e27b9 --- /dev/null +++ b/contracts/polygon/connectors/0x/main.sol @@ -0,0 +1,63 @@ +pragma solidity ^0.7.0; +pragma experimental ABIEncoderV2; + +/** + * @title 0x. + * @dev On-chain DEX Aggregator. + */ + +import {TokenInterface, MemoryInterface} from "../../common/interfaces.sol"; +import {Stores} from "../../common/stores.sol"; +import {ZeroExData, zeroExInterface} from "./interface.sol"; +import {Helpers} from "./helpers.sol"; +import {Events} from "./events.sol"; + +abstract contract ZeroEx is Helpers { + /** + * @dev Sell ETH/ERC20_Token using 0x. + * @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 0x API. + * @param setId ID stores the amount of token brought. + */ + + function swap( + address buyAddr, + address sellAddr, + uint256 sellAmt, + uint256 unitAmt, + bytes calldata callData, + uint256 setId + ) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + ZeroExData memory zeroExData = ZeroExData({ + buyToken: TokenInterface(buyAddr), + sellToken: TokenInterface(sellAddr), + unitAmt: unitAmt, + callData: callData, + _sellAmt: sellAmt, + _buyAmt: 0 + }); + + zeroExData = _swap(zeroExData, setId); + + _eventName = "LogSwap(address,address,uint256,uint256,uint256,uint256)"; + _eventParam = abi.encode( + buyAddr, + sellAddr, + zeroExData._buyAmt, + zeroExData._sellAmt, + 0, + setId + ); + } +} + +contract ConnectV2ZeroEx is ZeroEx { + string public name = "0x-V4"; +}