aboutsummaryrefslogtreecommitdiffstats
path: root/python-packages
diff options
context:
space:
mode:
authorBrandon Millman <brandon.millman@gmail.com>2018-10-29 09:36:13 +0800
committerBrandon Millman <brandon.millman@gmail.com>2018-10-29 10:07:53 +0800
commit8d1689073b702d973075d30b2bb36369487fad1c (patch)
treecb0380d4782b0715f0d24e7a9c5f88b49a60fa50 /python-packages
parent4f5ab1a72d33dc6a7516d7b1d51f1aa15752a6b8 (diff)
parentae6202ed3d777605a3fd02cd29141a3ba40f4b34 (diff)
downloaddexon-sol-tools-8d1689073b702d973075d30b2bb36369487fad1c.tar
dexon-sol-tools-8d1689073b702d973075d30b2bb36369487fad1c.tar.gz
dexon-sol-tools-8d1689073b702d973075d30b2bb36369487fad1c.tar.bz2
dexon-sol-tools-8d1689073b702d973075d30b2bb36369487fad1c.tar.lz
dexon-sol-tools-8d1689073b702d973075d30b2bb36369487fad1c.tar.xz
dexon-sol-tools-8d1689073b702d973075d30b2bb36369487fad1c.tar.zst
dexon-sol-tools-8d1689073b702d973075d30b2bb36369487fad1c.zip
Merge branch 'development' into feature/instant/fixed-orders-in-render-method
* development: fix(instant): refactor some props to use isDisabled instead of disabled linting imports feat(instant): Disable input when processing Add back debounce Make doesBuyQuoteMatchState in reducer less strict fix(instant): prevent outdated quote requests from overriding the correct quote selected asset buy order state button -> selected asset buy order state buttons buy order state button -> buy order state buttons feat(order_utils.py): ERC721 asset data codec (#1186) Add note about tslint false positive tsx -> ts Get BuyOrderState one big connected component, and let user view failure Show View Transaction button on failure, and allow setting of width for Try Again button and View Txn button Added string to constants chore: Update contract-wrappers CHANGELOG.json fix(contract-wrappers): Fix tslint errors that were lingering due to misconfiguration chore: Add --format stylish to tslint
Diffstat (limited to 'python-packages')
-rwxr-xr-xpython-packages/order_utils/setup.py2
-rw-r--r--python-packages/order_utils/src/index.rst4
-rw-r--r--python-packages/order_utils/src/zero_ex/dev_utils/type_assertions.py15
-rw-r--r--python-packages/order_utils/src/zero_ex/order_utils/asset_data_utils.py77
-rw-r--r--python-packages/order_utils/test/test_asset_data_utils.py39
5 files changed, 131 insertions, 6 deletions
diff --git a/python-packages/order_utils/setup.py b/python-packages/order_utils/setup.py
index 159499ec4..22a5f4c41 100755
--- a/python-packages/order_utils/setup.py
+++ b/python-packages/order_utils/setup.py
@@ -20,7 +20,7 @@ class TestCommandExtension(TestCommand):
"""Invoke pytest."""
import pytest
- pytest.main()
+ exit(pytest.main())
# pylint: disable=too-many-ancestors
diff --git a/python-packages/order_utils/src/index.rst b/python-packages/order_utils/src/index.rst
index 9c26b7924..22d5b0ef9 100644
--- a/python-packages/order_utils/src/index.rst
+++ b/python-packages/order_utils/src/index.rst
@@ -15,7 +15,9 @@ Python zero_ex.order_utils
.. autoclass:: zero_ex.order_utils.asset_data_utils.ERC20AssetData
-See source for properties. Sphinx does not easily generate class property docs; pull requests welcome.
+.. autoclass:: zero_ex.order_utils.asset_data_utils.ERC721AssetData
+
+See source for class properties. Sphinx does not easily generate class property docs; pull requests welcome.
Indices and tables
==================
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
index 745d014e6..a100da567 100644
--- 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
@@ -31,3 +31,18 @@ def assert_is_list(value: Any, name: str) -> None:
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__}'"
+ )
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
index 451de39af..e6f9a07c1 100644
--- 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
@@ -5,10 +5,11 @@ 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
+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
@@ -19,6 +20,14 @@ class ERC20AssetData(TypedDict):
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.
@@ -39,7 +48,7 @@ def encode_erc20_asset_data(token_address: str) -> str:
def decode_erc20_asset_data(asset_data: str) -> ERC20AssetData:
# docstring considered all one line by pylint: disable=line-too-long
- """Decode an ERC20 assetData hex string.
+ """Decode an ERC20 asset data hex string.
:param asset_data: String produced by prior call to encode_erc20_asset_data()
@@ -55,7 +64,7 @@ def decode_erc20_asset_data(asset_data: str) -> ERC20AssetData:
+ f" Got {str(len(asset_data))}."
)
- asset_proxy_id: str = asset_data[0:10]
+ 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"
@@ -70,3 +79,65 @@ def decode_erc20_asset_data(asset_data: str) -> ERC20AssetData:
)[0]
return {"asset_proxy_id": asset_proxy_id, "token_address": token_address}
+
+
+def encode_erc721_asset_data(token_address: str, token_id: int) -> str:
+ # docstring considered all one line by pylint: disable=line-too-long
+ """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.
+ :rtype: 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:
+ # docstring considered all one line by pylint: disable=line-too-long
+ """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]
+ # prefer `black` formatting. pylint: disable=C0330
+ 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/test/test_asset_data_utils.py b/python-packages/order_utils/test/test_asset_data_utils.py
index eeada5873..079368714 100644
--- a/python-packages/order_utils/test/test_asset_data_utils.py
+++ b/python-packages/order_utils/test/test_asset_data_utils.py
@@ -3,9 +3,12 @@
import pytest
from zero_ex.order_utils.asset_data_utils import (
- encode_erc20_asset_data,
decode_erc20_asset_data,
+ decode_erc721_asset_data,
+ encode_erc20_asset_data,
+ encode_erc721_asset_data,
ERC20_ASSET_DATA_BYTE_LENGTH,
+ ERC721_ASSET_DATA_MINIMUM_BYTE_LENGTH,
)
@@ -33,3 +36,37 @@ def test_decode_erc20_asset_data_invalid_proxy_id():
decode_erc20_asset_data(
"0xffffffff" + (" " * ERC20_ASSET_DATA_BYTE_LENGTH)
)
+
+
+def test_encode_erc721_asset_data_type_error_on_token_address():
+ """Test that passing a non-string for token_address raises a TypeError."""
+ with pytest.raises(TypeError):
+ encode_erc721_asset_data(123, 123)
+
+
+def test_encode_erc721_asset_data_type_error_on_token_id():
+ """Test that passing a non-int for token_id raises a TypeError."""
+ with pytest.raises(TypeError):
+ encode_erc721_asset_data("asdf", "asdf")
+
+
+def test_decode_erc721_asset_data_type_error():
+ """Test that passing a non-string for asset_data raises a TypeError."""
+ with pytest.raises(TypeError):
+ decode_erc721_asset_data(123)
+
+
+def test_decode_erc721_asset_data_with_asset_data_too_short():
+ """Test that passing in too short of a string raises a ValueError."""
+ with pytest.raises(ValueError):
+ decode_erc721_asset_data(
+ " " * (ERC721_ASSET_DATA_MINIMUM_BYTE_LENGTH - 1)
+ )
+
+
+def test_decode_erc721_asset_data_invalid_proxy_id():
+ """Test that passing in too short of a string raises a ValueError."""
+ with pytest.raises(ValueError):
+ decode_erc721_asset_data(
+ "0xffffffff" + " " * (ERC721_ASSET_DATA_MINIMUM_BYTE_LENGTH - 1)
+ )