Merge branch 'development' of https://github.com/0xProject/0x-monorepo into feature/instant/prevent-css-leakage
This commit is contained in:
		@@ -162,6 +162,9 @@ jobs:
 | 
				
			|||||||
        working_directory: ~/repo
 | 
					        working_directory: ~/repo
 | 
				
			||||||
        docker:
 | 
					        docker:
 | 
				
			||||||
            - image: circleci/python
 | 
					            - image: circleci/python
 | 
				
			||||||
 | 
					            - image: 0xorg/ganache-cli
 | 
				
			||||||
 | 
					              command: |
 | 
				
			||||||
 | 
					                  ganache-cli --gasLimit 10000000 --noVMErrorsOnRPCResponse --db /snapshot --noVMErrorsOnRPCResponse -p 8545 --networkId 50 -m "concert load couple harbor equip island argue ramp clarify fence smart topic"
 | 
				
			||||||
        steps:
 | 
					        steps:
 | 
				
			||||||
            - checkout
 | 
					            - checkout
 | 
				
			||||||
            - run: sudo chown -R circleci:circleci /usr/local/bin
 | 
					            - run: sudo chown -R circleci:circleci /usr/local/bin
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -99,6 +99,7 @@ packages/*/scripts/
 | 
				
			|||||||
.mypy_cache
 | 
					.mypy_cache
 | 
				
			||||||
.tox
 | 
					.tox
 | 
				
			||||||
python-packages/*/build
 | 
					python-packages/*/build
 | 
				
			||||||
 | 
					python-packages/*/dist
 | 
				
			||||||
__pycache__
 | 
					__pycache__
 | 
				
			||||||
python-packages/*/src/*.egg-info
 | 
					python-packages/*/src/*.egg-info
 | 
				
			||||||
python-packages/*/.coverage
 | 
					python-packages/*/.coverage
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,7 @@ lib
 | 
				
			|||||||
/packages/contracts/generated-artifacts
 | 
					/packages/contracts/generated-artifacts
 | 
				
			||||||
/packages/abi-gen-wrappers/src/generated-wrappers
 | 
					/packages/abi-gen-wrappers/src/generated-wrappers
 | 
				
			||||||
/packages/contract-artifacts/artifacts
 | 
					/packages/contract-artifacts/artifacts
 | 
				
			||||||
 | 
					/python-packages/order_utils/src/zero_ex/contract_artifacts/artifacts
 | 
				
			||||||
/packages/json-schemas/schemas
 | 
					/packages/json-schemas/schemas
 | 
				
			||||||
/packages/metacoin/src/contract_wrappers
 | 
					/packages/metacoin/src/contract_wrappers
 | 
				
			||||||
/packages/metacoin/artifacts
 | 
					/packages/metacoin/artifacts
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,6 +24,10 @@
 | 
				
			|||||||
                "note":
 | 
					                "note":
 | 
				
			||||||
                    "Fix bug where default values for `AssetBuyer` public facing methods could get overriden by `undefined` values",
 | 
					                    "Fix bug where default values for `AssetBuyer` public facing methods could get overriden by `undefined` values",
 | 
				
			||||||
                "pr": 1207
 | 
					                "pr": 1207
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                "note": "Lower default expiry buffer from 5 minutes to 2 minutes",
 | 
				
			||||||
 | 
					                "pr": 1217
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,7 +9,7 @@ const MAINNET_NETWORK_ID = 1;
 | 
				
			|||||||
const DEFAULT_ASSET_BUYER_OPTS: AssetBuyerOpts = {
 | 
					const DEFAULT_ASSET_BUYER_OPTS: AssetBuyerOpts = {
 | 
				
			||||||
    networkId: MAINNET_NETWORK_ID,
 | 
					    networkId: MAINNET_NETWORK_ID,
 | 
				
			||||||
    orderRefreshIntervalMs: 10000, // 10 seconds
 | 
					    orderRefreshIntervalMs: 10000, // 10 seconds
 | 
				
			||||||
    expiryBufferSeconds: 300, // 5 minutes
 | 
					    expiryBufferSeconds: 120, // 2 minutes
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const DEFAULT_BUY_QUOTE_REQUEST_OPTS: BuyQuoteRequestOpts = {
 | 
					const DEFAULT_BUY_QUOTE_REQUEST_OPTS: BuyQuoteRequestOpts = {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,7 +18,7 @@ Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
### Install Code and Dependencies
 | 
					### Install Code and Dependencies
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Ensure that you have Python >=3.6 installed, then:
 | 
					Ensure that you have installed Python >=3.6 and Docker. Then:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
pip install -e .[dev]
 | 
					pip install -e .[dev]
 | 
				
			||||||
@@ -26,7 +26,7 @@ pip install -e .[dev]
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
### Test
 | 
					### Test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
`./setup.py test`
 | 
					Tests depend on a running ganache instance with the 0x contracts deployed in it. For convenience, a docker container is provided that has ganache-cli and a snapshot containing the necessary contracts. A shortcut is provided to run that docker container: `./setup.py ganache`. With that running, the tests can be run with `./setup.py test`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Clean
 | 
					### Clean
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,11 +5,12 @@
 | 
				
			|||||||
import subprocess  # nosec
 | 
					import subprocess  # nosec
 | 
				
			||||||
from shutil import rmtree
 | 
					from shutil import rmtree
 | 
				
			||||||
from os import environ, path
 | 
					from os import environ, path
 | 
				
			||||||
 | 
					from pathlib import Path
 | 
				
			||||||
from sys import argv
 | 
					from sys import argv
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from distutils.command.clean import clean
 | 
					from distutils.command.clean import clean
 | 
				
			||||||
import distutils.command.build_py
 | 
					import distutils.command.build_py
 | 
				
			||||||
from setuptools import setup
 | 
					from setuptools import find_packages, setup
 | 
				
			||||||
from setuptools.command.test import test as TestCommand
 | 
					from setuptools.command.test import test as TestCommand
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -59,8 +60,15 @@ class LintCommand(distutils.command.build_py.build_py):
 | 
				
			|||||||
        import eth_abi
 | 
					        import eth_abi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        eth_abi_dir = path.dirname(path.realpath(eth_abi.__file__))
 | 
					        eth_abi_dir = path.dirname(path.realpath(eth_abi.__file__))
 | 
				
			||||||
        with open(path.join(eth_abi_dir, "py.typed"), "a"):
 | 
					        Path(path.join(eth_abi_dir, "py.typed")).touch()
 | 
				
			||||||
            pass
 | 
					
 | 
				
			||||||
 | 
					        # HACK(gene): until eth_utils fixes
 | 
				
			||||||
 | 
					        # https://github.com/ethereum/eth-utils/issues/140 , we need to simply
 | 
				
			||||||
 | 
					        # create an empty file `py.typed` in the eth_abi package directory.
 | 
				
			||||||
 | 
					        import eth_utils
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        eth_utils_dir = path.dirname(path.realpath(eth_utils.__file__))
 | 
				
			||||||
 | 
					        Path(path.join(eth_utils_dir, "py.typed")).touch()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for lint_command in lint_commands:
 | 
					        for lint_command in lint_commands:
 | 
				
			||||||
            print(
 | 
					            print(
 | 
				
			||||||
@@ -79,7 +87,7 @@ class CleanCommandExtension(clean):
 | 
				
			|||||||
        rmtree(".mypy_cache", ignore_errors=True)
 | 
					        rmtree(".mypy_cache", ignore_errors=True)
 | 
				
			||||||
        rmtree(".tox", ignore_errors=True)
 | 
					        rmtree(".tox", ignore_errors=True)
 | 
				
			||||||
        rmtree(".pytest_cache", ignore_errors=True)
 | 
					        rmtree(".pytest_cache", ignore_errors=True)
 | 
				
			||||||
        rmtree("src/order_utils.egg-info", ignore_errors=True)
 | 
					        rmtree("src/0x_order_utils.egg-info", ignore_errors=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# pylint: disable=too-many-ancestors
 | 
					# pylint: disable=too-many-ancestors
 | 
				
			||||||
@@ -111,6 +119,26 @@ class PublishCommand(distutils.command.build_py.build_py):
 | 
				
			|||||||
        subprocess.check_call("twine upload dist/*".split())  # nosec
 | 
					        subprocess.check_call("twine upload dist/*".split())  # nosec
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# pylint: disable=too-many-ancestors
 | 
				
			||||||
 | 
					class GanacheCommand(distutils.command.build_py.build_py):
 | 
				
			||||||
 | 
					    """Custom command to publish to pypi.org."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    description = "Run ganache daemon to support tests."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def run(self):
 | 
				
			||||||
 | 
					        """Run ganache."""
 | 
				
			||||||
 | 
					        cmd_line = (
 | 
				
			||||||
 | 
					            "docker run -d -p 8545:8545 0xorg/ganache-cli --gasLimit"
 | 
				
			||||||
 | 
					            + " 10000000 --db /snapshot --noVMErrorsOnRPCResponse -p 8545"
 | 
				
			||||||
 | 
					            + " --networkId 50 -m"
 | 
				
			||||||
 | 
					        ).split()
 | 
				
			||||||
 | 
					        cmd_line.append(
 | 
				
			||||||
 | 
					            "concert load couple harbor equip island argue ramp clarify fence"
 | 
				
			||||||
 | 
					            + " smart topic"
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        subprocess.call(cmd_line)  # nosec
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
with open("README.md", "r") as file_handle:
 | 
					with open("README.md", "r") as file_handle:
 | 
				
			||||||
    README_MD = file_handle.read()
 | 
					    README_MD = file_handle.read()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -130,9 +158,9 @@ setup(
 | 
				
			|||||||
        "test": TestCommandExtension,
 | 
					        "test": TestCommandExtension,
 | 
				
			||||||
        "test_publish": TestPublishCommand,
 | 
					        "test_publish": TestPublishCommand,
 | 
				
			||||||
        "publish": PublishCommand,
 | 
					        "publish": PublishCommand,
 | 
				
			||||||
 | 
					        "ganache": GanacheCommand,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    include_package_data=True,
 | 
					    install_requires=["eth-abi", "eth_utils", "mypy_extensions", "web3"],
 | 
				
			||||||
    install_requires=["eth-abi", "mypy_extensions", "web3"],
 | 
					 | 
				
			||||||
    extras_require={
 | 
					    extras_require={
 | 
				
			||||||
        "dev": [
 | 
					        "dev": [
 | 
				
			||||||
            "bandit",
 | 
					            "bandit",
 | 
				
			||||||
@@ -151,14 +179,17 @@ setup(
 | 
				
			|||||||
        ]
 | 
					        ]
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    python_requires=">=3.6, <4",
 | 
					    python_requires=">=3.6, <4",
 | 
				
			||||||
    package_data={"zero_ex.order_utils": ["py.typed"]},
 | 
					    package_data={
 | 
				
			||||||
 | 
					        "zero_ex.order_utils": ["py.typed"],
 | 
				
			||||||
 | 
					        "zero_ex.contract_artifacts": ["artifacts/*"],
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    package_dir={"": "src"},
 | 
					    package_dir={"": "src"},
 | 
				
			||||||
    license="Apache 2.0",
 | 
					    license="Apache 2.0",
 | 
				
			||||||
    keywords=(
 | 
					    keywords=(
 | 
				
			||||||
        "ethereum cryptocurrency 0x decentralized blockchain dex exchange"
 | 
					        "ethereum cryptocurrency 0x decentralized blockchain dex exchange"
 | 
				
			||||||
    ),
 | 
					    ),
 | 
				
			||||||
    namespace_packages=["zero_ex"],
 | 
					    namespace_packages=["zero_ex"],
 | 
				
			||||||
    packages=["zero_ex.order_utils", "zero_ex.dev_utils"],
 | 
					    packages=find_packages("src"),
 | 
				
			||||||
    classifiers=[
 | 
					    classifiers=[
 | 
				
			||||||
        "Development Status :: 2 - Pre-Alpha",
 | 
					        "Development Status :: 2 - Pre-Alpha",
 | 
				
			||||||
        "Intended Audience :: Developers",
 | 
					        "Intended Audience :: Developers",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,7 @@
 | 
				
			|||||||
# Reference: http://www.sphinx-doc.org/en/master/config
 | 
					# Reference: http://www.sphinx-doc.org/en/master/config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from typing import List
 | 
					from typing import List
 | 
				
			||||||
 | 
					import pkg_resources
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# pylint: disable=invalid-name
 | 
					# pylint: disable=invalid-name
 | 
				
			||||||
@@ -12,7 +13,7 @@ project = "0x-order-utils"
 | 
				
			|||||||
# pylint: disable=redefined-builtin
 | 
					# pylint: disable=redefined-builtin
 | 
				
			||||||
copyright = "2018, ZeroEx, Intl."
 | 
					copyright = "2018, ZeroEx, Intl."
 | 
				
			||||||
author = "F. Eugene Aumson"
 | 
					author = "F. Eugene Aumson"
 | 
				
			||||||
version = "0.1.0"  # The short X.Y version
 | 
					version = pkg_resources.get_distribution("0x-order-utils").version
 | 
				
			||||||
release = ""  # The full version, including alpha/beta/rc tags
 | 
					release = ""  # The full version, including alpha/beta/rc tags
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extensions = [
 | 
					extensions = [
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,6 +19,9 @@ Python zero_ex.order_utils
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
See source for class properties.  Sphinx does not easily generate class property docs; pull requests welcome.
 | 
					See source for class properties.  Sphinx does not easily generate class property docs; pull requests welcome.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. automodule:: zero_ex.order_utils.signature_utils
 | 
				
			||||||
 | 
					   :members:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Indices and tables
 | 
					Indices and tables
 | 
				
			||||||
==================
 | 
					==================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					"""Solc-generated artifacts for 0x smart contracts."""
 | 
				
			||||||
@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					../../../../../packages/contract-artifacts/artifacts
 | 
				
			||||||
@@ -46,3 +46,13 @@ def assert_is_int(value: Any, name: str) -> None:
 | 
				
			|||||||
            f"expected variable '{name}', with value {str(value)}, to have"
 | 
					            f"expected variable '{name}', with value {str(value)}, to have"
 | 
				
			||||||
            + f" type 'int', not '{type(value).__name__}'"
 | 
					            + f" type 'int', not '{type(value).__name__}'"
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def assert_is_hex_string(value: Any, name: str) -> None:
 | 
				
			||||||
 | 
					    """Assert that :param value: is a string of hex chars.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    If :param value: isn't a str, raise a TypeError.  If it is a string but
 | 
				
			||||||
 | 
					    contains non-hex characters ("0x" prefix permitted), raise a ValueError.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    assert_is_string(value, name)
 | 
				
			||||||
 | 
					    int(value, 16)  # raises a ValueError if value isn't a base-16 str
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1 +1,11 @@
 | 
				
			|||||||
"""Order utilities for 0x applications."""
 | 
					"""Order utilities for 0x applications.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Some methods require the caller to pass in a `Web3.HTTPProvider` object.  For
 | 
				
			||||||
 | 
					local testing one may construct such a provider pointing at an instance of
 | 
				
			||||||
 | 
					`ganache-cli <https://www.npmjs.com/package/ganache-cli>`_ which has the 0x
 | 
				
			||||||
 | 
					contracts deployed on it.  For convenience, a docker container is provided for
 | 
				
			||||||
 | 
					just this purpose.  To start it: ``docker run -d -p 8545:8545 0xorg/ganache-cli
 | 
				
			||||||
 | 
					--gasLimit 10000000 --db /snapshot --noVMErrorsOnRPCResponse -p 8545
 | 
				
			||||||
 | 
					--networkId 50 -m "concert load couple harbor equip island argue ramp clarify
 | 
				
			||||||
 | 
					fence smart topic"``.
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,88 @@
 | 
				
			|||||||
 | 
					"""Signature utilities."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from typing import Dict, Tuple
 | 
				
			||||||
 | 
					import json
 | 
				
			||||||
 | 
					from pkg_resources import resource_string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from eth_utils import is_address, to_checksum_address
 | 
				
			||||||
 | 
					from web3 import Web3
 | 
				
			||||||
 | 
					import web3.exceptions
 | 
				
			||||||
 | 
					from web3.utils import datatypes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from zero_ex.dev_utils.type_assertions import assert_is_hex_string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# prefer `black` formatting. pylint: disable=C0330
 | 
				
			||||||
 | 
					EXCHANGE_ABI = json.loads(
 | 
				
			||||||
 | 
					    resource_string("zero_ex.contract_artifacts", "artifacts/Exchange.json")
 | 
				
			||||||
 | 
					)["compilerOutput"]["abi"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					network_to_exchange_addr: Dict[str, str] = {
 | 
				
			||||||
 | 
					    "1": "0x4f833a24e1f95d70f028921e27040ca56e09ab0b",
 | 
				
			||||||
 | 
					    "3": "0x4530c0483a1633c7a1c97d2c53721caff2caaaaf",
 | 
				
			||||||
 | 
					    "42": "0x35dd2932454449b14cee11a94d3674a936d5d7b2",
 | 
				
			||||||
 | 
					    "50": "0x48bacb9266a570d521063ef5dd96e61686dbe788",
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# prefer `black` formatting. pylint: disable=C0330
 | 
				
			||||||
 | 
					def is_valid_signature(
 | 
				
			||||||
 | 
					    provider: Web3.HTTPProvider, data: str, signature: str, signer_address: str
 | 
				
			||||||
 | 
					) -> Tuple[bool, str]:
 | 
				
			||||||
 | 
					    # docstring considered all one line by pylint: disable=line-too-long
 | 
				
			||||||
 | 
					    """Check the validity of the supplied signature.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Check if the supplied ``signature`` corresponds to signing ``data`` with
 | 
				
			||||||
 | 
					    the private key corresponding to ``signer_address``.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    :param provider: A Web3 provider able to access the 0x Exchange contract.
 | 
				
			||||||
 | 
					    :param data: The hex encoded data signed by the supplied signature.
 | 
				
			||||||
 | 
					    :param signature: The hex encoded signature.
 | 
				
			||||||
 | 
					    :param signer_address: The hex encoded address that signed the data to
 | 
				
			||||||
 | 
					        produce the supplied signature.
 | 
				
			||||||
 | 
					    :rtype: Boolean indicating whether the given signature is valid.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    >>> is_valid_signature(
 | 
				
			||||||
 | 
					    ...     Web3.HTTPProvider("http://127.0.0.1:8545"),
 | 
				
			||||||
 | 
					    ...     '0x6927e990021d23b1eb7b8789f6a6feaf98fe104bb0cf8259421b79f9a34222b0',
 | 
				
			||||||
 | 
					    ...     '0x1B61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc3340349190569279751135161d22529dc25add4f6069af05be04cacbda2ace225403',
 | 
				
			||||||
 | 
					    ...     '0x5409ed021d9299bf6814279a6a1411a7e866a631',
 | 
				
			||||||
 | 
					    ... )
 | 
				
			||||||
 | 
					    (True, '')
 | 
				
			||||||
 | 
					    """  # noqa: E501 (line too long)
 | 
				
			||||||
 | 
					    # TODO: make this provider check more flexible. pylint: disable=fixme
 | 
				
			||||||
 | 
					    # https://app.asana.com/0/684263176955174/901300863045491/f
 | 
				
			||||||
 | 
					    if not isinstance(provider, Web3.HTTPProvider):
 | 
				
			||||||
 | 
					        raise TypeError("provider is not a Web3.HTTPProvider")
 | 
				
			||||||
 | 
					    assert_is_hex_string(data, "data")
 | 
				
			||||||
 | 
					    assert_is_hex_string(signature, "signature")
 | 
				
			||||||
 | 
					    assert_is_hex_string(signer_address, "signer_address")
 | 
				
			||||||
 | 
					    if not is_address(signer_address):
 | 
				
			||||||
 | 
					        raise ValueError("signer_address is not a valid address")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    web3_instance = Web3(provider)
 | 
				
			||||||
 | 
					    # false positive from pylint: disable=no-member
 | 
				
			||||||
 | 
					    network_id = web3_instance.net.version
 | 
				
			||||||
 | 
					    contract_address = network_to_exchange_addr[network_id]
 | 
				
			||||||
 | 
					    # false positive from pylint: disable=no-member
 | 
				
			||||||
 | 
					    contract: datatypes.Contract = web3_instance.eth.contract(
 | 
				
			||||||
 | 
					        address=to_checksum_address(contract_address), abi=EXCHANGE_ABI
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        return (
 | 
				
			||||||
 | 
					            contract.call().isValidSignature(
 | 
				
			||||||
 | 
					                data, to_checksum_address(signer_address), signature
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            "",
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    except web3.exceptions.BadFunctionCallOutput as exception:
 | 
				
			||||||
 | 
					        known_revert_reasons = [
 | 
				
			||||||
 | 
					            "LENGTH_GREATER_THAN_0_REQUIRED",
 | 
				
			||||||
 | 
					            "SIGNATURE_UNSUPPORTED",
 | 
				
			||||||
 | 
					            "LENGTH_0_REQUIRED",
 | 
				
			||||||
 | 
					            "LENGTH_65_REQUIRED",
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					        for known_revert_reason in known_revert_reasons:
 | 
				
			||||||
 | 
					            if known_revert_reason in str(exception):
 | 
				
			||||||
 | 
					                return (False, known_revert_reason)
 | 
				
			||||||
 | 
					        return (False, f"Unknown: {exception}")
 | 
				
			||||||
@@ -1,6 +1,8 @@
 | 
				
			|||||||
from distutils.dist import Distribution
 | 
					from distutils.dist import Distribution
 | 
				
			||||||
from typing import Any
 | 
					from typing import Any, List
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def setup(**attrs: Any) -> Distribution: ...
 | 
					def setup(**attrs: Any) -> Distribution: ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Command: ...
 | 
					class Command: ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def find_packages(where: str) -> List[str]: ...
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,26 @@
 | 
				
			|||||||
from typing import Optional, Union
 | 
					from typing import Dict, Optional, Union
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from web3.utils import datatypes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Web3:
 | 
					class Web3:
 | 
				
			||||||
 | 
					    class HTTPProvider: ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, provider: HTTPProvider) -> None: ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @staticmethod
 | 
					    @staticmethod
 | 
				
			||||||
    def sha3(
 | 
					    def sha3(
 | 
				
			||||||
        primitive: Optional[Union[bytes, int, None]] = None,
 | 
					        primitive: Optional[Union[bytes, int, None]] = None,
 | 
				
			||||||
        text: Optional[str] = None,
 | 
					        text: Optional[str] = None,
 | 
				
			||||||
        hexstr: Optional[str] = None
 | 
					        hexstr: Optional[str] = None
 | 
				
			||||||
    ) -> bytes: ...
 | 
					    ) -> bytes: ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class net:
 | 
				
			||||||
 | 
					        version: str
 | 
				
			||||||
 | 
					        ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class eth:
 | 
				
			||||||
 | 
					        @staticmethod
 | 
				
			||||||
 | 
					        def contract(address: str, abi: Dict) -> datatypes.Contract: ...
 | 
				
			||||||
 | 
					        ...
 | 
				
			||||||
    ...
 | 
					    ...
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								python-packages/order_utils/stubs/web3/exceptions.pyi
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								python-packages/order_utils/stubs/web3/exceptions.pyi
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					class BadFunctionCallOutput(Exception):
 | 
				
			||||||
 | 
					    ...
 | 
				
			||||||
@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					class Contract:
 | 
				
			||||||
 | 
					    def call(self): ...
 | 
				
			||||||
 | 
					    ...
 | 
				
			||||||
@@ -1,24 +1,18 @@
 | 
				
			|||||||
"""Exercise doctests for order_utils module."""
 | 
					"""Exercise doctests for all of our modules."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from doctest import testmod
 | 
					from doctest import testmod
 | 
				
			||||||
 | 
					import pkgutil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from zero_ex.dev_utils import abi_utils, type_assertions
 | 
					import zero_ex
 | 
				
			||||||
from zero_ex.order_utils import asset_data_utils
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_doctest_asset_data_utils():
 | 
					def test_all_doctests():
 | 
				
			||||||
    """Invoke doctest on the asset_data_utils module."""
 | 
					    """Gather zero_ex.* modules and doctest them."""
 | 
				
			||||||
    (failure_count, _) = testmod(asset_data_utils)
 | 
					    # prefer `black` formatting. pylint: disable=bad-continuation
 | 
				
			||||||
    assert failure_count == 0
 | 
					    for (importer, modname, _) in pkgutil.walk_packages(
 | 
				
			||||||
 | 
					        path=zero_ex.__path__, prefix="zero_ex."
 | 
				
			||||||
 | 
					    ):
 | 
				
			||||||
def test_doctest_abi_utils():
 | 
					        module = importer.find_module(modname).load_module(modname)
 | 
				
			||||||
    """Invoke doctest on the abi_utils module."""
 | 
					        print(module)
 | 
				
			||||||
    (failure_count, _) = testmod(abi_utils)
 | 
					        (failure_count, _) = testmod(module)
 | 
				
			||||||
    assert failure_count == 0
 | 
					        assert failure_count == 0
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def test_doctest_type_assertions():
 | 
					 | 
				
			||||||
    """Invoke doctest on the type_assertions module."""
 | 
					 | 
				
			||||||
    (failure_count, _) = testmod(type_assertions)
 | 
					 | 
				
			||||||
    assert failure_count == 0
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										128
									
								
								python-packages/order_utils/test/test_signature_utils.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								python-packages/order_utils/test/test_signature_utils.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,128 @@
 | 
				
			|||||||
 | 
					"""Tests of zero_ex.order_utils.signature_utils."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import pytest
 | 
				
			||||||
 | 
					from web3 import Web3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from zero_ex.order_utils.signature_utils import is_valid_signature
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_is_valid_signature__provider_wrong_type():
 | 
				
			||||||
 | 
					    """Test that giving a non-HTTPProvider raises a TypeError."""
 | 
				
			||||||
 | 
					    with pytest.raises(TypeError):
 | 
				
			||||||
 | 
					        is_valid_signature(
 | 
				
			||||||
 | 
					            123,
 | 
				
			||||||
 | 
					            "0x6927e990021d23b1eb7b8789f6a6feaf98fe104bb0cf8259421b79f9a34222b"
 | 
				
			||||||
 | 
					            + "0",
 | 
				
			||||||
 | 
					            "0x1B61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351b"
 | 
				
			||||||
 | 
					            + "c3340349190569279751135161d22529dc25add4f6069af05be04cacbda2ace"
 | 
				
			||||||
 | 
					            + "225403",
 | 
				
			||||||
 | 
					            "0x5409ed021d9299bf6814279a6a1411a7e866a631",
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_is_valid_signature__data_not_string():
 | 
				
			||||||
 | 
					    """Test that giving non-string `data` raises a TypeError."""
 | 
				
			||||||
 | 
					    with pytest.raises(TypeError):
 | 
				
			||||||
 | 
					        is_valid_signature(
 | 
				
			||||||
 | 
					            Web3.HTTPProvider("http://127.0.0.1:8545"),
 | 
				
			||||||
 | 
					            123,
 | 
				
			||||||
 | 
					            "0x1B61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351b"
 | 
				
			||||||
 | 
					            + "c3340349190569279751135161d22529dc25add4f6069af05be04cacbda2ace"
 | 
				
			||||||
 | 
					            + "225403",
 | 
				
			||||||
 | 
					            "0x5409ed021d9299bf6814279a6a1411a7e866a631",
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_is_valid_signature__data_not_hex_string():
 | 
				
			||||||
 | 
					    """Test that giving non-hex-string `data` raises a ValueError."""
 | 
				
			||||||
 | 
					    with pytest.raises(ValueError):
 | 
				
			||||||
 | 
					        is_valid_signature(
 | 
				
			||||||
 | 
					            Web3.HTTPProvider("http://127.0.0.1:8545"),
 | 
				
			||||||
 | 
					            "jjj",
 | 
				
			||||||
 | 
					            "0x1B61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351b"
 | 
				
			||||||
 | 
					            + "c3340349190569279751135161d22529dc25add4f6069af05be04cacbda2ace"
 | 
				
			||||||
 | 
					            + "225403",
 | 
				
			||||||
 | 
					            "0x5409ed021d9299bf6814279a6a1411a7e866a631",
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_is_valid_signature__signature_not_string():
 | 
				
			||||||
 | 
					    """Test that passng a non-string signature raises a TypeError."""
 | 
				
			||||||
 | 
					    with pytest.raises(TypeError):
 | 
				
			||||||
 | 
					        is_valid_signature(
 | 
				
			||||||
 | 
					            Web3.HTTPProvider("http://127.0.0.1:8545"),
 | 
				
			||||||
 | 
					            "0x6927e990021d23b1eb7b8789f6a6feaf98fe104bb0cf8259421b79f9a34222b"
 | 
				
			||||||
 | 
					            + "0",
 | 
				
			||||||
 | 
					            123,
 | 
				
			||||||
 | 
					            "0x5409ed021d9299bf6814279a6a1411a7e866a631",
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_is_valid_signature__signature_not_hex_string():
 | 
				
			||||||
 | 
					    """Test that passing a non-hex-string signature raises a ValueError."""
 | 
				
			||||||
 | 
					    with pytest.raises(ValueError):
 | 
				
			||||||
 | 
					        is_valid_signature(
 | 
				
			||||||
 | 
					            Web3.HTTPProvider("http://127.0.0.1:8545"),
 | 
				
			||||||
 | 
					            "0x6927e990021d23b1eb7b8789f6a6feaf98fe104bb0cf8259421b79f9a34222b"
 | 
				
			||||||
 | 
					            + "0",
 | 
				
			||||||
 | 
					            "jjj",
 | 
				
			||||||
 | 
					            "0x5409ed021d9299bf6814279a6a1411a7e866a631",
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_is_valid_signature__signer_address_not_string():
 | 
				
			||||||
 | 
					    """Test that giving a non-address `signer_address` raises a ValueError."""
 | 
				
			||||||
 | 
					    with pytest.raises(TypeError):
 | 
				
			||||||
 | 
					        is_valid_signature(
 | 
				
			||||||
 | 
					            Web3.HTTPProvider("http://127.0.0.1:8545"),
 | 
				
			||||||
 | 
					            "0x6927e990021d23b1eb7b8789f6a6feaf98fe104bb0cf8259421b79f9a34222b"
 | 
				
			||||||
 | 
					            + "0",
 | 
				
			||||||
 | 
					            "0x1B61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351b"
 | 
				
			||||||
 | 
					            + "c3340349190569279751135161d22529dc25add4f6069af05be04cacbda2ace"
 | 
				
			||||||
 | 
					            + "225403",
 | 
				
			||||||
 | 
					            123,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_is_valid_signature__signer_address_not_hex_string():
 | 
				
			||||||
 | 
					    """Test that giving a non-hex-str `signer_address` raises a ValueError."""
 | 
				
			||||||
 | 
					    with pytest.raises(ValueError):
 | 
				
			||||||
 | 
					        is_valid_signature(
 | 
				
			||||||
 | 
					            Web3.HTTPProvider("http://127.0.0.1:8545"),
 | 
				
			||||||
 | 
					            "0x6927e990021d23b1eb7b8789f6a6feaf98fe104bb0cf8259421b79f9a34222b"
 | 
				
			||||||
 | 
					            + "0",
 | 
				
			||||||
 | 
					            "0x1B61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351b"
 | 
				
			||||||
 | 
					            + "c3340349190569279751135161d22529dc25add4f6069af05be04cacbda2ace"
 | 
				
			||||||
 | 
					            + "225403",
 | 
				
			||||||
 | 
					            "jjj",
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_is_valid_signature__signer_address_not_valid_address():
 | 
				
			||||||
 | 
					    """Test that giving a non-address for `signer_address` raises an error."""
 | 
				
			||||||
 | 
					    with pytest.raises(ValueError):
 | 
				
			||||||
 | 
					        is_valid_signature(
 | 
				
			||||||
 | 
					            Web3.HTTPProvider("http://127.0.0.1:8545"),
 | 
				
			||||||
 | 
					            "0x6927e990021d23b1eb7b8789f6a6feaf98fe104bb0cf8259421b79f9a34222b"
 | 
				
			||||||
 | 
					            + "0",
 | 
				
			||||||
 | 
					            "0x1B61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351b"
 | 
				
			||||||
 | 
					            + "c3340349190569279751135161d22529dc25add4f6069af05be04cacbda2ace"
 | 
				
			||||||
 | 
					            + "225403",
 | 
				
			||||||
 | 
					            "0xff",
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_is_valid_signature__unsupported_sig_types():
 | 
				
			||||||
 | 
					    """Test that passing in a sig w/invalid type raises error.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    To induce this error, the last byte of the signature is tweaked from 03 to
 | 
				
			||||||
 | 
					    ff."""
 | 
				
			||||||
 | 
					    (is_valid, reason) = is_valid_signature(
 | 
				
			||||||
 | 
					        Web3.HTTPProvider("http://127.0.0.1:8545"),
 | 
				
			||||||
 | 
					        "0x6927e990021d23b1eb7b8789f6a6feaf98fe104bb0cf8259421b79f9a34222b0",
 | 
				
			||||||
 | 
					        "0x1B61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc334"
 | 
				
			||||||
 | 
					        + "0349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254ff",
 | 
				
			||||||
 | 
					        "0x5409ed021d9299bf6814279a6a1411a7e866a631",
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    assert is_valid is False
 | 
				
			||||||
 | 
					    assert reason == "SIGNATURE_UNSUPPORTED"
 | 
				
			||||||
		Reference in New Issue
	
	Block a user