contract MarketMakerProxy is 
    Ownable,
    LibDecoder,
    SafeToken
{
    string public version = "0.0.4";

    uint256 constant MAX_UINT = 2**256 - 1;
    address internal SIGNER;
    
    constructor () public {
        owner = msg.sender;
        operator = msg.sender;
    }

    // Manage
    function setSigner(address _signer) public onlyOperator {
        SIGNER = _signer;
    }

    function setAllowance(address[] memory token_addrs, address spender) public onlyOperator {
        for (uint i = 0; i < token_addrs.length; i++) {
            address token = token_addrs[i];
            doApprove(token, spender, MAX_UINT);
            doApprove(token, address(this), MAX_UINT);
        }
    }

    function closeAllowance(address[] memory token_addrs, address spender) public onlyOperator {
        for (uint i = 0; i < token_addrs.length; i++) {
            address token = token_addrs[i];
            doApprove(token, spender, 0);
            doApprove(token, address(this), 0);
        }
    }

    function withdraw(address token, address to, uint256 amount) public onlyOperator {
        doTransferFrom(token, address(this), to , amount);
    }

    function isValidSignature(bytes32 orderHash, bytes memory signature) public view returns (bytes32) {
        require(
            SIGNER == ecrecoverAddress(orderHash, signature),
            "INVALID_SIGNATURE"
        );
        return keccak256("isValidWalletSignature(bytes32,address,bytes)");
    }

    function ecrecoverAddress(bytes32 orderHash, bytes memory signature) internal pure returns (address) {
        (uint8 v, bytes32 r, bytes32 s, address user, uint16 feeFactor) = decodeMmSignature(signature);
        
        return ecrecover(
            keccak256(
                abi.encodePacked(
                    "\x19Ethereum Signed Message:\n54",
                    orderHash,
                    user,
                    feeFactor
                )),
            v, r, s
        );
    }
}
function setSigner(address _signer) public onlyOperator {
    SIGNER = _signer;
}

// Manage