aboutsummaryrefslogtreecommitdiffstats
path: root/python-packages/order_utils/src/zero_ex
diff options
context:
space:
mode:
authorHsuan Lee <hsuan@cobinhood.com>2019-01-19 18:42:04 +0800
committerHsuan Lee <hsuan@cobinhood.com>2019-01-19 18:42:04 +0800
commit7ae38906926dc09bc10670c361af0d2bf0050426 (patch)
tree5fb10ae366b987db09e4ddb4bc3ba0f75404ad08 /python-packages/order_utils/src/zero_ex
parentb5fd3c72a08aaa6957917d74c333387a16edf66b (diff)
downloaddexon-sol-tools-7ae38906926dc09bc10670c361af0d2bf0050426.tar
dexon-sol-tools-7ae38906926dc09bc10670c361af0d2bf0050426.tar.gz
dexon-sol-tools-7ae38906926dc09bc10670c361af0d2bf0050426.tar.bz2
dexon-sol-tools-7ae38906926dc09bc10670c361af0d2bf0050426.tar.lz
dexon-sol-tools-7ae38906926dc09bc10670c361af0d2bf0050426.tar.xz
dexon-sol-tools-7ae38906926dc09bc10670c361af0d2bf0050426.tar.zst
dexon-sol-tools-7ae38906926dc09bc10670c361af0d2bf0050426.zip
Update dependency packages
Diffstat (limited to 'python-packages/order_utils/src/zero_ex')
-rw-r--r--python-packages/order_utils/src/zero_ex/__init__.py2
-rw-r--r--python-packages/order_utils/src/zero_ex/dev_utils/__init__.py1
-rw-r--r--python-packages/order_utils/src/zero_ex/dev_utils/abi_utils.py101
-rw-r--r--python-packages/order_utils/src/zero_ex/dev_utils/type_assertions.py87
-rw-r--r--python-packages/order_utils/src/zero_ex/order_utils/__init__.py535
-rw-r--r--python-packages/order_utils/src/zero_ex/order_utils/asset_data_utils.py141
-rw-r--r--python-packages/order_utils/src/zero_ex/order_utils/py.typed0
7 files changed, 0 insertions, 867 deletions
diff --git a/python-packages/order_utils/src/zero_ex/__init__.py b/python-packages/order_utils/src/zero_ex/__init__.py
deleted file mode 100644
index e90d833db..000000000
--- a/python-packages/order_utils/src/zero_ex/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-"""0x Python API."""
-__import__("pkg_resources").declare_namespace(__name__)
diff --git a/python-packages/order_utils/src/zero_ex/dev_utils/__init__.py b/python-packages/order_utils/src/zero_ex/dev_utils/__init__.py
deleted file mode 100644
index b6a224d2c..000000000
--- a/python-packages/order_utils/src/zero_ex/dev_utils/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-"""Dev utils to be shared across 0x projects and packages."""
diff --git a/python-packages/order_utils/src/zero_ex/dev_utils/abi_utils.py b/python-packages/order_utils/src/zero_ex/dev_utils/abi_utils.py
deleted file mode 100644
index 3fec775b0..000000000
--- a/python-packages/order_utils/src/zero_ex/dev_utils/abi_utils.py
+++ /dev/null
@@ -1,101 +0,0 @@
-"""Ethereum ABI utilities.
-
-Builds on the eth-abi package, adding some convenience methods like those found
-in npmjs.com/package/ethereumjs-abi. Ideally, all of this code should be
-pushed upstream into eth-abi.
-"""
-
-import re
-from typing import Any, List
-
-from mypy_extensions import TypedDict
-
-from web3 import Web3
-from eth_abi import encode_abi
-
-from .type_assertions import assert_is_string, assert_is_list
-
-
-class MethodSignature(TypedDict, total=False):
- """Object interface to an ABI method signature."""
-
- method: str
- args: List[str]
-
-
-def parse_signature(signature: str) -> MethodSignature:
- """Parse a method signature into its constituent parts.
-
- >>> parse_signature("ERC20Token(address)")
- {'method': 'ERC20Token', 'args': ['address']}
- """
- assert_is_string(signature, "signature")
-
- matches = re.match(r"^(\w+)\((.+)\)$", signature)
- if matches is None:
- raise ValueError(f"Invalid method signature {signature}")
- return {"method": matches[1], "args": matches[2].split(",")}
-
-
-def elementary_name(name: str) -> str:
- """Convert from short to canonical names; barely implemented.
-
- Modeled after ethereumjs-abi's ABI.elementaryName(), but only implemented
- to support our particular use case and a few other simple ones.
-
- >>> elementary_name("address")
- 'address'
- >>> elementary_name("uint")
- 'uint256'
- """
- assert_is_string(name, "name")
-
- return {
- "int": "int256",
- "uint": "uint256",
- "fixed": "fixed128x128",
- "ufixed": "ufixed128x128",
- }.get(name, name)
-
-
-def event_id(name: str, types: List[str]) -> str:
- """Return the Keccak-256 hash of the given method.
-
- >>> event_id("ERC20Token", ["address"])
- '0xf47261b06eedbfce68afd46d0f3c27c60b03faad319eaf33103611cf8f6456ad'
- """
- assert_is_string(name, "name")
- assert_is_list(types, "types")
-
- signature = f"{name}({','.join(list(map(elementary_name, types)))})"
- return Web3.sha3(text=signature).hex()
-
-
-def method_id(name: str, types: List[str]) -> str:
- """Return the 4-byte method identifier.
-
- >>> method_id("ERC20Token", ["address"])
- '0xf47261b0'
- """
- assert_is_string(name, "name")
- assert_is_list(types, "types")
-
- return event_id(name, types)[0:10]
-
-
-def simple_encode(method: str, *args: Any) -> bytes:
- r"""Encode a method ABI.
-
- >>> simple_encode("ERC20Token(address)", "0x1dc4c1cefef38a777b15aa20260a54e584b16c48")
- b'\xf4ra\xb0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d\xc4\xc1\xce\xfe\xf3\x8aw{\x15\xaa &\nT\xe5\x84\xb1lH'
- """ # noqa: E501 (line too long)
- assert_is_string(method, "method")
-
- signature: MethodSignature = parse_signature(method)
-
- return bytes.fromhex(
- (
- method_id(signature["method"], signature["args"])
- + encode_abi(signature["args"], args).hex()
- )[2:]
- )
diff --git a/python-packages/order_utils/src/zero_ex/dev_utils/type_assertions.py b/python-packages/order_utils/src/zero_ex/dev_utils/type_assertions.py
deleted file mode 100644
index 4681315a8..000000000
--- a/python-packages/order_utils/src/zero_ex/dev_utils/type_assertions.py
+++ /dev/null
@@ -1,87 +0,0 @@
-"""Assertions for runtime type checking of function arguments."""
-
-from typing import Any
-
-from eth_utils import is_address
-from web3.providers.base import BaseProvider
-
-
-def assert_is_string(value: Any, name: str) -> None:
- """If :param value: isn't of type str, raise a TypeError.
-
- >>> try: assert_is_string(123, 'var')
- ... except TypeError as type_error: print(str(type_error))
- ...
- expected variable 'var', with value 123, to have type 'str', not 'int'
- """
- if not isinstance(value, str):
- raise TypeError(
- f"expected variable '{name}', with value {str(value)}, to have"
- + f" type 'str', not '{type(value).__name__}'"
- )
-
-
-def assert_is_list(value: Any, name: str) -> None:
- """If :param value: isn't of type list, raise a TypeError.
-
- >>> try: assert_is_list(123, 'var')
- ... except TypeError as type_error: print(str(type_error))
- ...
- expected variable 'var', with value 123, to have type 'list', not 'int'
- """
- if not isinstance(value, list):
- raise TypeError(
- f"expected variable '{name}', with value {str(value)}, to have"
- + f" type 'list', not '{type(value).__name__}'"
- )
-
-
-def assert_is_int(value: Any, name: str) -> None:
- """If :param value: isn't of type int, raise a TypeError.
-
- >>> try: assert_is_int('asdf', 'var')
- ... except TypeError as type_error: print(str(type_error))
- ...
- expected variable 'var', with value asdf, to have type 'int', not 'str'
- """
- if not isinstance(value, int):
- raise TypeError(
- f"expected variable '{name}', with value {str(value)}, to have"
- + 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
-
-
-def assert_is_address(value: Any, name: str) -> None:
- """Assert that `value` is a valid Ethereum address.
-
- If `value` isn't a hex string, raise a TypeError. If it isn't a valid
- Ethereum address, raise a ValueError.
- """
- assert_is_hex_string(value, name)
- if not is_address(value):
- raise ValueError(
- f"Expected variable '{name}' to be a valid Ethereum"
- + " address, but it's not."
- )
-
-
-def assert_is_provider(value: Any, name: str) -> None:
- """Assert that `value` is a Web3 provider.
-
- If `value` isn't a Web3 provider, raise a TypeError.
- """
- if not isinstance(value, BaseProvider):
- raise TypeError(
- f"Expected variable '{name}' to be an instance of a Web3 provider,"
- + " but it's not."
- )
diff --git a/python-packages/order_utils/src/zero_ex/order_utils/__init__.py b/python-packages/order_utils/src/zero_ex/order_utils/__init__.py
deleted file mode 100644
index 39d411507..000000000
--- a/python-packages/order_utils/src/zero_ex/order_utils/__init__.py
+++ /dev/null
@@ -1,535 +0,0 @@
-"""Order utilities for 0x applications.
-
-Some methods require the caller to pass in a `Web3.BaseProvider`:code: 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:2.2.2`:code:.
-"""
-
-from copy import copy
-from enum import auto, Enum
-import json
-from typing import cast, Dict, NamedTuple, Tuple
-from pkg_resources import resource_string
-
-from mypy_extensions import TypedDict
-
-from eth_utils import keccak, remove_0x_prefix, to_bytes, to_checksum_address
-from web3 import Web3
-import web3.exceptions
-from web3.providers.base import BaseProvider
-from web3.utils import datatypes
-
-from zero_ex.contract_addresses import NETWORK_TO_ADDRESSES, NetworkId
-import zero_ex.contract_artifacts
-from zero_ex.dev_utils.type_assertions import (
- assert_is_address,
- assert_is_hex_string,
- assert_is_provider,
-)
-from zero_ex.json_schemas import assert_valid
-
-
-class _Constants:
- """Static data used by order utilities."""
-
- null_address = "0x0000000000000000000000000000000000000000"
-
- eip191_header = b"\x19\x01"
-
- eip712_domain_separator_schema_hash = keccak(
- b"EIP712Domain(string name,string version,address verifyingContract)"
- )
-
- eip712_domain_struct_header = (
- eip712_domain_separator_schema_hash
- + keccak(b"0x Protocol")
- + keccak(b"2")
- )
-
- eip712_order_schema_hash = keccak(
- b"Order("
- + b"address makerAddress,"
- + b"address takerAddress,"
- + b"address feeRecipientAddress,"
- + b"address senderAddress,"
- + b"uint256 makerAssetAmount,"
- + b"uint256 takerAssetAmount,"
- + b"uint256 makerFee,"
- + b"uint256 takerFee,"
- + b"uint256 expirationTimeSeconds,"
- + b"uint256 salt,"
- + b"bytes makerAssetData,"
- + b"bytes takerAssetData"
- + b")"
- )
-
- class SignatureType(Enum):
- """Enumeration of known signature types."""
-
- ILLEGAL = 0
- INVALID = auto()
- EIP712 = auto()
- ETH_SIGN = auto()
- WALLET = auto()
- VALIDATOR = auto()
- PRE_SIGNED = auto()
- N_SIGNATURE_TYPES = auto()
-
-
-class Order(TypedDict): # pylint: disable=too-many-instance-attributes
- """A Web3-compatible representation of the Exchange.Order struct."""
-
- makerAddress: str
- """Address that created the order."""
-
- takerAddress: str
- """Address that is allowed to fill the order.
-
- If set to 0, any address is allowed to fill the order.
- """
-
- feeRecipientAddress: str
- """Address that will recieve fees when order is filled."""
-
- senderAddress: str
- """Address that is allowed to call Exchange contract methods that affect
- this order. If set to 0, any address is allowed to call these methods.
- """
-
- makerAssetAmount: int
- """Amount of makerAsset being offered by maker. Must be greater than 0."""
-
- takerAssetAmount: int
- """Amount of takerAsset being bid on by maker. Must be greater than 0."""
-
- makerFee: int
- """Amount of ZRX paid to feeRecipient by maker when order is filled. If
- set to 0, no transfer of ZRX from maker to feeRecipient will be attempted.
- """
-
- takerFee: int
- """Amount of ZRX paid to feeRecipient by taker when order is filled. If
- set to 0, no transfer of ZRX from taker to feeRecipient will be attempted.
- """
-
- expirationTimeSeconds: int
- """Timestamp in seconds at which order expires."""
-
- salt: int
- """Arbitrary number to facilitate uniqueness of the order's hash."""
-
- makerAssetData: bytes
- """Encoded data that can be decoded by a specified proxy contract when
- transferring makerAsset. The last byte references the id of this proxy.
- """
-
- takerAssetData: bytes
- """Encoded data that can be decoded by a specified proxy contract when
- transferring takerAsset. The last byte references the id of this proxy.
- """
-
-
-def make_empty_order() -> Order:
- """Construct an empty order.
-
- Initializes all strings to "0x0000000000000000000000000000000000000000",
- all numbers to 0, and all bytes to nulls.
- """
- return {
- "makerAddress": _Constants.null_address,
- "takerAddress": _Constants.null_address,
- "senderAddress": _Constants.null_address,
- "feeRecipientAddress": _Constants.null_address,
- "makerAssetData": (b"\x00") * 20,
- "takerAssetData": (b"\x00") * 20,
- "salt": 0,
- "makerFee": 0,
- "takerFee": 0,
- "makerAssetAmount": 0,
- "takerAssetAmount": 0,
- "expirationTimeSeconds": 0,
- }
-
-
-def order_to_jsdict(
- order: Order, exchange_address="0x0000000000000000000000000000000000000000"
-) -> dict:
- """Convert a Web3-compatible order struct to a JSON-schema-compatible dict.
-
- More specifically, do explicit decoding for the `bytes`:code: fields.
-
- >>> import pprint
- >>> pprint.pprint(order_to_jsdict(
- ... {
- ... 'makerAddress': "0x0000000000000000000000000000000000000000",
- ... 'takerAddress': "0x0000000000000000000000000000000000000000",
- ... 'feeRecipientAddress':
- ... "0x0000000000000000000000000000000000000000",
- ... 'senderAddress': "0x0000000000000000000000000000000000000000",
- ... 'makerAssetAmount': 1,
- ... 'takerAssetAmount': 1,
- ... 'makerFee': 0,
- ... 'takerFee': 0,
- ... 'expirationTimeSeconds': 1,
- ... 'salt': 1,
- ... 'makerAssetData': (0).to_bytes(1, byteorder='big') * 20,
- ... 'takerAssetData': (0).to_bytes(1, byteorder='big') * 20,
- ... },
- ... ))
- {'exchangeAddress': '0x0000000000000000000000000000000000000000',
- 'expirationTimeSeconds': 1,
- 'feeRecipientAddress': '0x0000000000000000000000000000000000000000',
- 'makerAddress': '0x0000000000000000000000000000000000000000',
- 'makerAssetAmount': 1,
- 'makerAssetData': '0x0000000000000000000000000000000000000000',
- 'makerFee': 0,
- 'salt': 1,
- 'senderAddress': '0x0000000000000000000000000000000000000000',
- 'takerAddress': '0x0000000000000000000000000000000000000000',
- 'takerAssetAmount': 1,
- 'takerAssetData': '0x0000000000000000000000000000000000000000',
- 'takerFee': 0}
- """
- jsdict = cast(Dict, copy(order))
-
- # encode bytes fields
- jsdict["makerAssetData"] = "0x" + order["makerAssetData"].hex()
- jsdict["takerAssetData"] = "0x" + order["takerAssetData"].hex()
-
- jsdict["exchangeAddress"] = exchange_address
-
- assert_valid(jsdict, "/orderSchema")
-
- return jsdict
-
-
-def jsdict_order_to_struct(jsdict: dict) -> Order:
- r"""Convert a JSON-schema-compatible dict order to a Web3-compatible struct.
-
- More specifically, do explicit encoding of the `bytes`:code: fields.
-
- >>> import pprint
- >>> pprint.pprint(jsdict_order_to_struct(
- ... {
- ... 'makerAddress': "0x0000000000000000000000000000000000000000",
- ... 'takerAddress': "0x0000000000000000000000000000000000000000",
- ... 'feeRecipientAddress': "0x0000000000000000000000000000000000000000",
- ... 'senderAddress': "0x0000000000000000000000000000000000000000",
- ... 'makerAssetAmount': 1000000000000000000,
- ... 'takerAssetAmount': 1000000000000000000,
- ... 'makerFee': 0,
- ... 'takerFee': 0,
- ... 'expirationTimeSeconds': 12345,
- ... 'salt': 12345,
- ... 'makerAssetData': "0x0000000000000000000000000000000000000000",
- ... 'takerAssetData': "0x0000000000000000000000000000000000000000",
- ... 'exchangeAddress': "0x0000000000000000000000000000000000000000",
- ... },
- ... ))
- {'expirationTimeSeconds': 12345,
- 'feeRecipientAddress': '0x0000000000000000000000000000000000000000',
- 'makerAddress': '0x0000000000000000000000000000000000000000',
- 'makerAssetAmount': 1000000000000000000,
- 'makerAssetData': b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
- b'\x00\x00\x00\x00\x00\x00\x00\x00',
- 'makerFee': 0,
- 'salt': 12345,
- 'senderAddress': '0x0000000000000000000000000000000000000000',
- 'takerAddress': '0x0000000000000000000000000000000000000000',
- 'takerAssetAmount': 1000000000000000000,
- 'takerAssetData': b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
- b'\x00\x00\x00\x00\x00\x00\x00\x00',
- 'takerFee': 0}
- """ # noqa: E501 (line too long)
- assert_valid(jsdict, "/orderSchema")
-
- order = cast(Order, copy(jsdict))
-
- order["makerAssetData"] = bytes.fromhex(
- remove_0x_prefix(jsdict["makerAssetData"])
- )
- order["takerAssetData"] = bytes.fromhex(
- remove_0x_prefix(jsdict["takerAssetData"])
- )
-
- del order["exchangeAddress"] # type: ignore
- # silence mypy pending release of
- # https://github.com/python/mypy/issues/3550
-
- return order
-
-
-def generate_order_hash_hex(order: Order, exchange_address: str) -> str:
- """Calculate the hash of the given order as a hexadecimal string.
-
- :param order: The order to be hashed. Must conform to `the 0x order JSON schema <https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/order_schema.json>`_.
- :param exchange_address: The address to which the 0x Exchange smart
- contract has been deployed.
- :returns: A string, of ASCII hex digits, representing the order hash.
-
- >>> generate_order_hash_hex(
- ... {
- ... 'makerAddress': "0x0000000000000000000000000000000000000000",
- ... 'takerAddress': "0x0000000000000000000000000000000000000000",
- ... 'feeRecipientAddress': "0x0000000000000000000000000000000000000000",
- ... 'senderAddress': "0x0000000000000000000000000000000000000000",
- ... 'makerAssetAmount': "1000000000000000000",
- ... 'takerAssetAmount': "1000000000000000000",
- ... 'makerFee': "0",
- ... 'takerFee': "0",
- ... 'expirationTimeSeconds': "12345",
- ... 'salt': "12345",
- ... 'makerAssetData': (0).to_bytes(1, byteorder='big') * 20,
- ... 'takerAssetData': (0).to_bytes(1, byteorder='big') * 20,
- ... },
- ... exchange_address="0x0000000000000000000000000000000000000000",
- ... )
- '55eaa6ec02f3224d30873577e9ddd069a288c16d6fb407210eecbc501fa76692'
- """ # noqa: E501 (line too long)
- assert_is_address(exchange_address, "exchange_address")
- assert_valid(order_to_jsdict(order, exchange_address), "/orderSchema")
-
- def pad_20_bytes_to_32(twenty_bytes: bytes):
- return bytes(12) + twenty_bytes
-
- def int_to_32_big_endian_bytes(i: int):
- return i.to_bytes(32, byteorder="big")
-
- eip712_domain_struct_hash = keccak(
- _Constants.eip712_domain_struct_header
- + pad_20_bytes_to_32(to_bytes(hexstr=exchange_address))
- )
-
- eip712_order_struct_hash = keccak(
- _Constants.eip712_order_schema_hash
- + pad_20_bytes_to_32(to_bytes(hexstr=order["makerAddress"]))
- + pad_20_bytes_to_32(to_bytes(hexstr=order["takerAddress"]))
- + pad_20_bytes_to_32(to_bytes(hexstr=order["feeRecipientAddress"]))
- + pad_20_bytes_to_32(to_bytes(hexstr=order["senderAddress"]))
- + int_to_32_big_endian_bytes(int(order["makerAssetAmount"]))
- + int_to_32_big_endian_bytes(int(order["takerAssetAmount"]))
- + int_to_32_big_endian_bytes(int(order["makerFee"]))
- + int_to_32_big_endian_bytes(int(order["takerFee"]))
- + int_to_32_big_endian_bytes(int(order["expirationTimeSeconds"]))
- + int_to_32_big_endian_bytes(int(order["salt"]))
- + keccak(to_bytes(hexstr=order["makerAssetData"].hex()))
- + keccak(to_bytes(hexstr=order["takerAssetData"].hex()))
- )
-
- return keccak(
- _Constants.eip191_header
- + eip712_domain_struct_hash
- + eip712_order_struct_hash
- ).hex()
-
-
-class OrderInfo(NamedTuple):
- """A Web3-compatible representation of the Exchange.OrderInfo struct."""
-
- order_status: str
- """A `str`:code: describing the order's validity and fillability."""
-
- order_hash: bytes
- """A `bytes`:code: object representing the EIP712 hash of the order."""
-
- order_taker_asset_filled_amount: int
- """An `int`:code: indicating the amount that has already been filled."""
-
-
-def is_valid_signature(
- provider: BaseProvider, data: str, signature: str, signer_address: str
-) -> Tuple[bool, str]:
- """Check the validity of the supplied signature.
-
- Check if the supplied `signature`:code: corresponds to signing `data`:code:
- with the private key corresponding to `signer_address`:code:.
-
- :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.
- :returns: Tuple consisting of a boolean and a string. Boolean is true if
- valid, false otherwise. If false, the string describes the reason.
-
- >>> is_valid_signature(
- ... Web3.HTTPProvider("http://127.0.0.1:8545"),
- ... '0x6927e990021d23b1eb7b8789f6a6feaf98fe104bb0cf8259421b79f9a34222b0',
- ... '0x1B61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc3340349190569279751135161d22529dc25add4f6069af05be04cacbda2ace225403',
- ... '0x5409ed021d9299bf6814279a6a1411a7e866a631',
- ... )
- (True, '')
- """ # noqa: E501 (line too long)
- assert_is_provider(provider, "provider")
- assert_is_hex_string(data, "data")
- assert_is_hex_string(signature, "signature")
- assert_is_address(signer_address, "signer_address")
-
- web3_instance = Web3(provider)
- # false positive from pylint: disable=no-member
- contract_address = NETWORK_TO_ADDRESSES[
- NetworkId(int(web3_instance.net.version))
- ].exchange
- # false positive from pylint: disable=no-member
- contract: datatypes.Contract = web3_instance.eth.contract(
- address=to_checksum_address(contract_address),
- abi=zero_ex.contract_artifacts.abi_by_name("Exchange"),
- )
- 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_ILLEGAL",
- "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}")
-
-
-class ECSignature(TypedDict):
- """Object representation of an elliptic curve signature's parameters."""
-
- v: int
- r: str
- s: str
-
-
-def _parse_signature_hex_as_vrs(signature_hex: str) -> ECSignature:
- """Parse signature hex as a concatentation of EC parameters ordered V, R, S.
-
- >>> _parse_signature_hex_as_vrs('0x1b117902c86dfb95fe0d1badd983ee166ad259b27acb220174cbb4460d872871137feabdfe76e05924b484789f79af4ee7fa29ec006cedce1bbf369320d034e10b03')
- {'v': 27, 'r': '117902c86dfb95fe0d1badd983ee166ad259b27acb220174cbb4460d87287113', 's': '7feabdfe76e05924b484789f79af4ee7fa29ec006cedce1bbf369320d034e10b'}
- """ # noqa: E501 (line too long)
- signature: ECSignature = {
- "v": int(signature_hex[2:4], 16),
- "r": signature_hex[4:68],
- "s": signature_hex[68:132],
- }
- if signature["v"] == 0 or signature["v"] == 1:
- signature["v"] = signature["v"] + 27
- return signature
-
-
-def _parse_signature_hex_as_rsv(signature_hex: str) -> ECSignature:
- """Parse signature hex as a concatentation of EC parameters ordered R, S, V.
-
- >>> _parse_signature_hex_as_rsv('0x117902c86dfb95fe0d1badd983ee166ad259b27acb220174cbb4460d872871137feabdfe76e05924b484789f79af4ee7fa29ec006cedce1bbf369320d034e10b00')
- {'r': '117902c86dfb95fe0d1badd983ee166ad259b27acb220174cbb4460d87287113', 's': '7feabdfe76e05924b484789f79af4ee7fa29ec006cedce1bbf369320d034e10b', 'v': 27}
- """ # noqa: E501 (line too long)
- signature: ECSignature = {
- "r": signature_hex[2:66],
- "s": signature_hex[66:130],
- "v": int(signature_hex[130:132], 16),
- }
- if signature["v"] == 0 or signature["v"] == 1:
- signature["v"] = signature["v"] + 27
- return signature
-
-
-def _convert_ec_signature_to_vrs_hex(signature: ECSignature) -> str:
- """Convert elliptic curve signature object to hex hash string.
-
- >>> _convert_ec_signature_to_vrs_hex(
- ... {
- ... 'r': '117902c86dfb95fe0d1badd983ee166ad259b27acb220174cbb4460d87287113',
- ... 's': '7feabdfe76e05924b484789f79af4ee7fa29ec006cedce1bbf369320d034e10b',
- ... 'v': 27
- ... }
- ... )
- '0x1b117902c86dfb95fe0d1badd983ee166ad259b27acb220174cbb4460d872871137feabdfe76e05924b484789f79af4ee7fa29ec006cedce1bbf369320d034e10b'
- """ # noqa: E501 (line too long)
- return (
- "0x"
- + signature["v"].to_bytes(1, byteorder="big").hex()
- + signature["r"]
- + signature["s"]
- )
-
-
-def sign_hash(
- provider: BaseProvider, signer_address: str, hash_hex: str
-) -> str:
- """Sign a message with the given hash, and return the signature.
-
- :param provider: A Web3 provider.
- :param signer_address: The address of the signing account.
- :param hash_hex: A hex string representing the hash, like that returned
- from `generate_order_hash_hex()`:code:.
- :returns: A string, of ASCII hex digits, representing the signature.
-
- >>> provider = Web3.HTTPProvider("http://127.0.0.1:8545")
- >>> sign_hash(
- ... provider,
- ... Web3(provider).personal.listAccounts[0],
- ... '0x34decbedc118904df65f379a175bb39ca18209d6ce41d5ed549d54e6e0a95004',
- ... )
- '0x1b117902c86dfb95fe0d1badd983ee166ad259b27acb220174cbb4460d872871137feabdfe76e05924b484789f79af4ee7fa29ec006cedce1bbf369320d034e10b03'
- """ # noqa: E501 (line too long)
- assert_is_provider(provider, "provider")
- assert_is_address(signer_address, "signer_address")
- assert_is_hex_string(hash_hex, "hash_hex")
-
- web3_instance = Web3(provider)
- # false positive from pylint: disable=no-member
- signature = web3_instance.eth.sign( # type: ignore
- signer_address, hexstr=hash_hex.replace("0x", "")
- ).hex()
-
- valid_v_param_values = [27, 28]
-
- # HACK: There is no consensus on whether the signatureHex string should be
- # formatted as v + r + s OR r + s + v, and different clients (even
- # different versions of the same client) return the signature params in
- # different orders. In order to support all client implementations, we
- # parse the signature in both ways, and evaluate if either one is a valid
- # signature. r + s + v is the most prevalent format from eth_sign, so we
- # attempt this first.
-
- ec_signature = _parse_signature_hex_as_rsv(signature)
- if ec_signature["v"] in valid_v_param_values:
- signature_as_vrst_hex = (
- _convert_ec_signature_to_vrs_hex(ec_signature)
- + _Constants.SignatureType.ETH_SIGN.value.to_bytes(
- 1, byteorder="big"
- ).hex()
- )
-
- (valid, _) = is_valid_signature(
- provider, hash_hex, signature_as_vrst_hex, signer_address
- )
-
- if valid is True:
- return signature_as_vrst_hex
-
- ec_signature = _parse_signature_hex_as_vrs(signature)
- if ec_signature["v"] in valid_v_param_values:
- signature_as_vrst_hex = (
- _convert_ec_signature_to_vrs_hex(ec_signature)
- + _Constants.SignatureType.ETH_SIGN.value.to_bytes(
- 1, byteorder="big"
- ).hex()
- )
- (valid, _) = is_valid_signature(
- provider, hash_hex, signature_as_vrst_hex, signer_address
- )
-
- if valid is True:
- return signature_as_vrst_hex
-
- raise RuntimeError(
- "Signature returned from web3 provider is in an unknown format."
- + " Attempted to parse as RSV and as VRS."
- )
diff --git a/python-packages/order_utils/src/zero_ex/order_utils/asset_data_utils.py b/python-packages/order_utils/src/zero_ex/order_utils/asset_data_utils.py
deleted file mode 100644
index f8e9bc42b..000000000
--- a/python-packages/order_utils/src/zero_ex/order_utils/asset_data_utils.py
+++ /dev/null
@@ -1,141 +0,0 @@
-"""Asset data encoding and decoding utilities."""
-
-from mypy_extensions import TypedDict
-
-import eth_abi
-
-from zero_ex.dev_utils import abi_utils
-from zero_ex.dev_utils.type_assertions import assert_is_string, assert_is_int
-
-
-ERC20_ASSET_DATA_BYTE_LENGTH = 36
-ERC721_ASSET_DATA_MINIMUM_BYTE_LENGTH = 53
-SELECTOR_LENGTH = 10
-
-
-class ERC20AssetData(TypedDict):
- """Object interface to ERC20 asset data."""
-
- asset_proxy_id: str
- """asset proxy id"""
-
- token_address: str
-
-
-class ERC721AssetData(TypedDict):
- """Object interface to ERC721 asset data."""
-
- asset_proxy_id: str
- token_address: str
- token_id: int
-
-
-def encode_erc20_asset_data(token_address: str) -> str:
- """Encode an ERC20 token address into an asset data string.
-
- :param token_address: the ERC20 token's contract address.
- :returns: hex encoded asset data string, usable in the makerAssetData or
- takerAssetData fields in a 0x order.
-
- >>> encode_erc20_asset_data('0x1dc4c1cefef38a777b15aa20260a54e584b16c48')
- '0xf47261b00000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48'
- """
- assert_is_string(token_address, "token_address")
-
- return (
- "0x"
- + abi_utils.simple_encode("ERC20Token(address)", token_address).hex()
- )
-
-
-def decode_erc20_asset_data(asset_data: str) -> ERC20AssetData:
- """Decode an ERC20 asset data hex string.
-
- :param asset_data: String produced by prior call to encode_erc20_asset_data()
-
- >>> decode_erc20_asset_data("0xf47261b00000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48")
- {'asset_proxy_id': '0xf47261b0', 'token_address': '0x1dc4c1cefef38a777b15aa20260a54e584b16c48'}
- """ # noqa: E501 (line too long)
- assert_is_string(asset_data, "asset_data")
-
- if len(asset_data) < ERC20_ASSET_DATA_BYTE_LENGTH:
- raise ValueError(
- "Could not decode ERC20 Proxy Data. Expected length of encoded"
- + f" data to be at least {str(ERC20_ASSET_DATA_BYTE_LENGTH)}."
- + f" Got {str(len(asset_data))}."
- )
-
- asset_proxy_id: str = asset_data[0:SELECTOR_LENGTH]
- if asset_proxy_id != abi_utils.method_id("ERC20Token", ["address"]):
- raise ValueError(
- "Could not decode ERC20 Proxy Data. Expected Asset Proxy Id to be"
- + f" ERC20 ({abi_utils.method_id('ERC20Token', ['address'])})"
- + f" but got {asset_proxy_id}."
- )
-
- # workaround for https://github.com/PyCQA/pylint/issues/1498
- # pylint: disable=unsubscriptable-object
- token_address = eth_abi.decode_abi(
- ["address"], bytes.fromhex(asset_data[SELECTOR_LENGTH:])
- )[0]
-
- return {"asset_proxy_id": asset_proxy_id, "token_address": token_address}
-
-
-def encode_erc721_asset_data(token_address: str, token_id: int) -> str:
- """Encode an ERC721 asset data hex string.
-
- :param token_address: the ERC721 token's contract address.
- :param token_id: the identifier of the asset's instance of the token.
- :returns: hex encoded asset data string, usable in the makerAssetData or
- takerAssetData fields in a 0x order.
-
- >>> encode_erc721_asset_data('0x1dc4c1cefef38a777b15aa20260a54e584b16c48', 1)
- '0x025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000001'
- """ # noqa: E501 (line too long)
- assert_is_string(token_address, "token_address")
- assert_is_int(token_id, "token_id")
-
- return (
- "0x"
- + abi_utils.simple_encode(
- "ERC721Token(address,uint256)", token_address, token_id
- ).hex()
- )
-
-
-def decode_erc721_asset_data(asset_data: str) -> ERC721AssetData:
- """Decode an ERC721 asset data hex string.
-
- >>> decode_erc721_asset_data('0x025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000001')
- {'asset_proxy_id': '0x02571792', 'token_address': '0x1dc4c1cefef38a777b15aa20260a54e584b16c48', 'token_id': 1}
- """ # noqa: E501 (line too long)
- assert_is_string(asset_data, "asset_data")
-
- if len(asset_data) < ERC721_ASSET_DATA_MINIMUM_BYTE_LENGTH:
- raise ValueError(
- "Could not decode ERC721 Asset Data. Expected length of encoded"
- + f"data to be at least {ERC721_ASSET_DATA_MINIMUM_BYTE_LENGTH}. "
- + f"Got {len(asset_data)}."
- )
-
- asset_proxy_id: str = asset_data[0:SELECTOR_LENGTH]
- if asset_proxy_id != abi_utils.method_id(
- "ERC721Token", ["address", "uint256"]
- ):
- raise ValueError(
- "Could not decode ERC721 Asset Data. Expected Asset Proxy Id to be"
- + f" ERC721 ("
- + f"{abi_utils.method_id('ERC721Token', ['address', 'uint256'])}"
- + f"), but got {asset_proxy_id}"
- )
-
- (token_address, token_id) = eth_abi.decode_abi(
- ["address", "uint256"], bytes.fromhex(asset_data[SELECTOR_LENGTH:])
- )
-
- return {
- "asset_proxy_id": asset_proxy_id,
- "token_address": token_address,
- "token_id": token_id,
- }
diff --git a/python-packages/order_utils/src/zero_ex/order_utils/py.typed b/python-packages/order_utils/src/zero_ex/order_utils/py.typed
deleted file mode 100644
index e69de29bb..000000000
--- a/python-packages/order_utils/src/zero_ex/order_utils/py.typed
+++ /dev/null