contract AtomicUtils{    
    // ETH and its wrappers
    address constant WETHAddress = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
    IWETH constant WETH = IWETH(WETHAddress);
    Token constant ETH = Token(address(0));
    address constant EEEAddress = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
    Token constant EEE = Token(EEEAddress);
    
    // Universal function to query this contracts balance, supporting  and Token
    function balanceOf(Token token) internal view returns(uint balance){
        if(isETH(token)){
            return address(this).balance;
        }else{
            return token.balanceOf(address(this));
        }
    }
    
    // Universal send function, supporting ETH and Token
    function send(Token token, address payable recipient, uint amount) internal {
        if(isETH(token)){
            require(
                recipient.send(amount),
                "Sending of ETH failed."
            );
        }else{
            Token(token).transfer(recipient, amount);
            require(
                validateOptionalERC20Return(),
                "ERC20 token transfer failed."
            );
        }
    }
    
    // Universal function to claim tokens from msg.sender
    function claimTokenFromSenderTo(Token _token, uint _amount, address _receiver) internal {
        if (isETH(_token)) {
            require(msg.value == _amount);
            // dont forward ETH
        }else{
            require(msg.value  == 0);
            _token.transferFrom(msg.sender, _receiver, _amount);
        }
    }
    
    // Token approval function supporting non-compliant tokens
    function approve(Token _token, address _spender, uint _amount) internal {
        if (!isETH(_token)) {
            _token.approve(_spender, _amount);
            require(
                validateOptionalERC20Return(),
                "ERC20 approval failed."
            );
        }
    }
    
    // Validate return data of non-compliant erc20s
    function validateOptionalERC20Return() pure internal returns (bool){
        uint256 success = 0;

        assembly {
            switch returndatasize()             // Check the number of bytes the token contract returned
            case 0 {                            // Nothing returned, but contract did not throw > assume our transfer succeeded
                success := 1
            }
            case 32 {                           // 32 bytes returned, result is the returned bool
                returndatacopy(0, 0, 32)
                success := mload(0)
            }
        }

        return success != 0;
    }

    function isETH(Token token) pure internal  returns (bool){
        if(
            address(token) == address(0)
            || address(token) == EEEAddress
        ){
            return true;
        }else{
            return false;
        }
    }

    function isWETH(Token token) pure internal  returns (bool){
        if(address(token) == WETHAddress){
            return true;
        }else{
            return false;
        }
    }
    
    // Source: https://github.com/GNSPS/solidity-bytes-utils/blob/master/contracts/BytesLib.sol
    function sliceBytes(
        bytes memory _bytes,
        uint256 _start,
        uint256 _length
    )
    internal
    pure
    returns (bytes memory)
    {
        require(_bytes.length >= (_start + _length), "Read out of bounds");

        bytes memory tempBytes;

        assembly {
            switch iszero(_length)
            case 0 {
            // Get a location of some free memory and store it in tempBytes as
            // Solidity does for memory variables.
                tempBytes := mload(0x40)

            // The first word of the slice result is potentially a partial
            // word read from the original array. To read it, we calculate
            // the length of that partial word and start copying that many
            // bytes into the array. The first word we copy will start with
            // data we don't care about, but the last `lengthmod` bytes will
            // land at the beginning of the contents of the new array. When
            // we're done copying, we overwrite the full first word with
            // the actual length of the slice.
                let lengthmod := and(_length, 31)

            // The multiplication in the next line is necessary
            // because when slicing multiples of 32 bytes (lengthmod == 0)
            // the following copy loop was copying the origin's length
            // and then ending prematurely not copying everything it should.
                let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
                let end := add(mc, _length)

                for {
                // The multiplication in the next line has the same exact purpose
                // as the one above.
                    let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
                } lt(mc, end) {
                    mc := add(mc, 0x20)
                    cc := add(cc, 0x20)
                } {
                    mstore(mc, mload(cc))
                }

                mstore(tempBytes, _length)

            //update free-memory pointer
            //allocating the array padded to 32 bytes like the compiler does now
                mstore(0x40, and(add(mc, 31), not(31)))
            }
            //if we want a zero-length slice let's just return a zero-length array
            default {
                tempBytes := mload(0x40)

                mstore(0x40, add(tempBytes, 0x20))
            }
        }

        return tempBytes;
    }
}
function balanceOf(Token token) internal view returns(uint balance){
        if(isETH(token)){
            return address(this).balance;
        }else{
            return token.balanceOf(address(this));
        }
    }
// Universal function to query this contracts balance, supporting  and Token