protocol/python-packages/contract_wrappers/test/test_exchange_wrapper.py
F. Eugene Aumson df97b20913
abi-gen/Py: fix incorrect method return types and other small issues (#2345)
* .gitignore gen'd Python staking contract wrappers

* abi-gen/test-cli: check Python type hints in lint

* sra_client.py: Update doc for replicating examples

* abi-gen/Py: fix call() return type incl. tx hash

Previously, generated wrappers for contract methods were including type
hints that suggested that a call() (as opposed to a send_transaction())
might return either the underlying return type or a transaction hash.
This doesn't make sense because a call() will never return a TX hash.
Now, the type hint just has the return type of the underlying method.

* abi-gen: fix test_cli:lint checking wrong code

test_cli:lint is meant to be a rudimentary test of the code generated by
abi-gen.  However, previously, this script was incorporated into `yarn
lint`, and in CircleCI `static-tests` runs independently of `build`.
Consequently, the runs of test_cli:lint were checking the OLD code,
which was previously generated and checked in to git, NOT the code
generated with the version of abi-gen represented by the git repo.  Now,
test_cli:lint happens during `yarn test` rather than `yarn lint`,
because `yarn test` IS dependent on `yarn build`.

* contract_wrappers.py: fix misplaced doc

Previously, the routines `order_to_jsdict()` and `jsdict_to_order()`
were moved from contract_wrappers.exchange.types to
contract_wrappers.order_conversions.  However, the module-level
docstring describing those routines was accidentally left behind in
exchange.types.

* abi-gen/Py: stop documenting return types for TXs

Previously the send_transaction() interface included docstring
documentation for the return types of the contract method, but that
doesn't make any sense because send_transaction() returns a transaction
hash rather than any actual return values.

* abi-gen/Py: stop gen'ing send_tx for const methods

* abi-gen/Py: add build_tx to contract methods

* abi-gen/Py: fix incorrect method return types

Fixes #2298 .

* abi-gen/Py: rm validator arg to no-input methods

* abi-gen: mv Py Handlebars helpers to own module

Move all existing Python-related Handlebars helpers to the newly created
python_handlebars_helpers module.

* abi-gen: refactor internal interface

No functionality is changed.  Sole purpose of this commit is to
facilitate an upcoming commit.

* abi-gen: refactor internal interface

No functionality is changed.  Sole purpose of this commit is to
facilitate an upcoming commit.

* abi-gen/Py: name tuples w/internalType, not hash

Use the new `internalType` field on the `DataItem`s in the contract
artifact to give generated tuple classes a better name than just hashing
their component field names.

* Fix CI errors

* abi-gen/Py/wrapper: make internal member private

* Update CHANGELOGs
2019-11-15 18:27:45 -05:00

169 lines
5.9 KiB
Python

"""Test 0x Exchnage wrapper."""
import random
import pytest
from eth_utils import remove_0x_prefix
from zero_ex.contract_addresses import chain_to_addresses, ChainId
from zero_ex.contract_wrappers import TxParams
from zero_ex.contract_wrappers.exchange import Exchange
from zero_ex.contract_wrappers.exchange.types import Order
from zero_ex.json_schemas import assert_valid
from zero_ex.order_utils import (
asset_data_utils,
generate_order_hash_hex,
sign_hash,
)
@pytest.fixture(scope="module")
def exchange_wrapper(ganache_provider):
"""Get an Exchange wrapper instance."""
return Exchange(
web3_or_provider=ganache_provider,
contract_address=chain_to_addresses(ChainId.GANACHE).exchange,
)
def create_test_order(
maker_address,
maker_asset_amount,
maker_asset_data,
taker_asset_amount,
taker_asset_data,
):
"""Create a test order."""
order = Order(
makerAddress=maker_address,
takerAddress="0x0000000000000000000000000000000000000000",
feeRecipientAddress="0x0000000000000000000000000000000000000000",
senderAddress="0x0000000000000000000000000000000000000000",
makerAssetAmount=maker_asset_amount,
takerAssetAmount=taker_asset_amount,
makerFee=0,
takerFee=0,
expirationTimeSeconds=100000000000000,
salt=random.randint(1, 1000000000),
makerAssetData=maker_asset_data,
takerAssetData=taker_asset_data,
makerFeeAssetData=asset_data_utils.encode_erc20("0x" + "00" * 20),
takerFeeAssetData=asset_data_utils.encode_erc20("0x" + "00" * 20),
)
return order
def assert_fill_log(fill_log, maker, taker, order, order_hash):
"""assert that the fill log matches the order details"""
assert fill_log.makerAddress == maker
assert fill_log.takerAddress == taker
assert fill_log.feeRecipientAddress == order["feeRecipientAddress"]
assert fill_log.senderAddress == taker
assert fill_log.orderHash == bytes.fromhex(remove_0x_prefix(order_hash))
assert fill_log.makerAssetFilledAmount == order["makerAssetAmount"]
assert fill_log.takerAssetFilledAmount == order["takerAssetAmount"]
assert fill_log.makerFeePaid == order["makerFee"]
assert fill_log.takerFeePaid == order["takerFee"]
assert fill_log.makerAssetData == order["makerAssetData"]
assert fill_log.takerAssetData == order["takerAssetData"]
def test_exchange_wrapper__fill_order(
accounts,
exchange_wrapper, # pylint: disable=redefined-outer-name
ganache_provider,
weth_asset_data,
zrx_asset_data,
):
"""Test filling an order."""
taker = accounts[0]
maker = accounts[1]
exchange_address = exchange_wrapper.contract_address
order = create_test_order(maker, 1, weth_asset_data, 1, zrx_asset_data)
order_hash = generate_order_hash_hex(
order=order, exchange_address=exchange_address, chain_id=1337
)
order_signature = sign_hash(ganache_provider, maker, order_hash)
fill_results = exchange_wrapper.fill_order.call(
order=order,
taker_asset_fill_amount=order["takerAssetAmount"],
signature=order_signature,
tx_params=TxParams(from_=taker),
)
assert fill_results["makerAssetFilledAmount"] == 1
assert fill_results["takerAssetFilledAmount"] == 1
assert fill_results["makerFeePaid"] == 0
assert fill_results["takerFeePaid"] == 0
assert fill_results["protocolFeePaid"] == 0
tx_hash = exchange_wrapper.fill_order.send_transaction(
order=order,
taker_asset_fill_amount=order["takerAssetAmount"],
signature=order_signature,
tx_params=TxParams(from_=taker),
)
assert_valid(tx_hash.hex(), "/hexSchema")
fill_event = exchange_wrapper.get_fill_event(tx_hash)
assert_fill_log(fill_event[0].args, maker, taker, order, order_hash)
# pylint: disable=too-many-locals
def test_exchange_wrapper__batch_fill_orders(
accounts,
exchange_wrapper, # pylint: disable=redefined-outer-name
ganache_provider,
weth_asset_data,
):
"""Test filling a batch of orders."""
taker = accounts[0]
maker = accounts[1]
exchange_address = exchange_wrapper.contract_address
orders = []
order_1 = create_test_order(maker, 1, weth_asset_data, 1, weth_asset_data)
order_2 = create_test_order(maker, 1, weth_asset_data, 1, weth_asset_data)
orders.append(order_1)
orders.append(order_2)
order_hashes = [
generate_order_hash_hex(
order=order, exchange_address=exchange_address, chain_id=1337
)
for order in orders
]
order_signatures = [
sign_hash(ganache_provider, maker, order_hash)
for order_hash in order_hashes
]
taker_amounts = [order["takerAssetAmount"] for order in orders]
tx_hash = exchange_wrapper.batch_fill_orders.send_transaction(
orders=orders,
taker_asset_fill_amounts=taker_amounts,
signatures=order_signatures,
tx_params=TxParams(from_=taker),
)
assert_valid(tx_hash.hex(), "/hexSchema")
fill_events = exchange_wrapper.get_fill_event(tx_hash)
for index, order in enumerate(orders):
assert_fill_log(
fill_events[index].args, maker, taker, order, order_hashes[index]
)
def test_two_instantiations_with_web3_objects(web3_instance):
"""Test that instantiating two Exchange objects doesn't raise.
When instantiating an Exchange object with a web3 client (rather than a
provider) there was a bug encountered where web3.py was giving an error
when trying to install the rich-revert-handling middleware on the web3
client, an error saying "can't install this same middleware instance
again." Test that that bug isn't occurring.
"""
exchange = Exchange( # pylint: disable=unused-variable
web3_instance, chain_to_addresses(ChainId.GANACHE).exchange
)
exchange2 = Exchange( # pylint: disable=unused-variable
web3_instance, chain_to_addresses(ChainId.GANACHE).exchange
)