From baf267870316143b9757cb2df0d9d981a34ccdce Mon Sep 17 00:00:00 2001 From: Rodrigo <95635797+poly-rodr@users.noreply.github.com> Date: Wed, 21 Sep 2022 15:00:10 -0300 Subject: [PATCH 1/5] code styling and general stuff --- .editorconfig | 22 +++++ .github/workflows/tests.yaml | 30 ------- .github/workflows/workflow.yaml | 24 +++++ Makefile | 5 +- README.md | 20 ++--- py_order_utils/builders/base_builder.py | 14 +-- py_order_utils/builders/exception.py | 1 - .../builders/limit_order_builder.py | 72 +++++++-------- .../builders/market_order_builder.py | 85 +++++++++++------- py_order_utils/config.py | 24 +++-- py_order_utils/constants.py | 6 +- py_order_utils/facades/base_facade.py | 14 +-- py_order_utils/facades/erc1155_facade.py | 18 ++-- py_order_utils/facades/erc20_facade.py | 21 +++-- py_order_utils/facades/limit_order_facade.py | 31 +++---- py_order_utils/model/__init__.py | 7 +- py_order_utils/model/model.py | 42 +++++---- py_order_utils/model/signatures.py | 2 +- py_order_utils/signer.py | 8 +- py_order_utils/utils.py | 15 ++-- requirements.txt | 1 + setup.py | 25 +++--- tests/test_config.py | 6 +- tests/test_facades.py | 61 ++++++++----- tests/test_limit_order_builder.py | 89 ++++++++++--------- tests/test_market_order_builder.py | 59 +++++++----- tests/test_utils.py | 8 +- 27 files changed, 402 insertions(+), 308 deletions(-) create mode 100644 .editorconfig delete mode 100644 .github/workflows/tests.yaml create mode 100644 .github/workflows/workflow.yaml diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..5999bf2 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,22 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_style = space +trim_trailing_whitespace = true +insert_final_newline = true + +[*.{py}] +indent_style = space +indent_size = 4 + + +[*.json] +indent_style = space +indent_size = 2 + +[*.yaml] +indent_style = space +indent_size = 2 +quote_type = single diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml deleted file mode 100644 index 683e22d..0000000 --- a/.github/workflows/tests.yaml +++ /dev/null @@ -1,30 +0,0 @@ -name: Tests - -on: - push: - branches: main - pull_request: - branches: "*" - -jobs: - test: - runs-on: ubuntu-latest - steps: - - name: Checkout Code - uses: actions/checkout@v2 - with: - persist-credentials: false - - - name: Install Python - uses: actions/setup-python@v2 - with: - python-version: 3.9.10 - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install -r requirements.txt - pip install -e . - - - name: Run Tests - run: make test diff --git a/.github/workflows/workflow.yaml b/.github/workflows/workflow.yaml new file mode 100644 index 0000000..c440199 --- /dev/null +++ b/.github/workflows/workflow.yaml @@ -0,0 +1,24 @@ +name: Test + +on: + push: + branches: [ main ] + pull_request: + +jobs: + build-lint-test: + name: Test + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: 3.9.10 + + - run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + pip install -e . + + - name: Run Tests + run: make test diff --git a/Makefile b/Makefile index 897951d..466c36c 100644 --- a/Makefile +++ b/Makefile @@ -2,4 +2,7 @@ init: pip install -r requirements.txt test: - pytest -s \ No newline at end of file + pytest -s + +fmt: + black ./. \ No newline at end of file diff --git a/README.md b/README.md index 621f257..b70ee95 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,7 @@ PyPI -Python utilities used to generate and sign limit and market orders on Polymarket's CLOB - +Python utilities used to generate and sign orders from Polymarket's Exchange ### Install @@ -16,7 +15,7 @@ pip install py-order-utils ### Usage ```py -from py_order_utils.builders import LimitOrderBuilder +from py_order_utils.builders import OrderBuilder from py_order_utils.signer import Signer from pprint import pprint @@ -24,19 +23,16 @@ def main(): exchange_address = "0x...." chain_id = 80001 signer = Signer("0x....") - builder = LimitOrderBuilder(exchange_address, chain_id, signer) - - # Create and sign the limit order - limit_order = builder.create_limit_order( - LimitOrderData( - maker_asset_address="0x...", - taker_asset_address="0x...", - taker_asset_id=1, + builder = OrderBuilder(exchange_address, chain_id, signer) + + # Create and sign the order + order = builder.create_order( + OrderData( ... ) ) # Generate the Order and Signature json to be sent to the CLOB API - pprint(json.dumps(limit_order.dict())) + pprint(json.dumps(order.dict())) ``` diff --git a/py_order_utils/builders/base_builder.py b/py_order_utils/builders/base_builder.py index 0430202..5cb4565 100644 --- a/py_order_utils/builders/base_builder.py +++ b/py_order_utils/builders/base_builder.py @@ -5,14 +5,17 @@ class BaseBuilder: - def __init__(self, exchange_address: str, chain_id: int, signer: Signer): self.contract_address = normalize_address(exchange_address) self.signer = signer self.chain_id = chain_id - self.domain_separator = self._get_domain_separator(self.chain_id, self.contract_address) + self.domain_separator = self._get_domain_separator( + self.chain_id, self.contract_address + ) - def _get_domain_separator(self, chain_id: int, verifying_contract: str)->EIP712Struct: + def _get_domain_separator( + self, chain_id: int, verifying_contract: str + ) -> EIP712Struct: return make_domain( name="Polymarket Limit Order Protocol", version="1", @@ -20,7 +23,7 @@ def _get_domain_separator(self, chain_id: int, verifying_contract: str)->EIP712S verifyingContract=verifying_contract, ) - def _create_struct_hash(self, order:EIP712Struct): + def _create_struct_hash(self, order: EIP712Struct): """ Creates an EIP712 compliant struct hash for the Order """ @@ -31,6 +34,3 @@ def sign(self, struct_hash): Signs the struct hash """ return self.signer.sign(struct_hash) - - - diff --git a/py_order_utils/builders/exception.py b/py_order_utils/builders/exception.py index 81e9ba7..2e3be02 100644 --- a/py_order_utils/builders/exception.py +++ b/py_order_utils/builders/exception.py @@ -1,3 +1,2 @@ class ValidationException(Exception): pass - diff --git a/py_order_utils/builders/limit_order_builder.py b/py_order_utils/builders/limit_order_builder.py index df209a4..5ecc8bd 100644 --- a/py_order_utils/builders/limit_order_builder.py +++ b/py_order_utils/builders/limit_order_builder.py @@ -10,20 +10,20 @@ class LimitOrderBuilder(BaseBuilder): """ Limit order builder """ - + def __init__(self, exchange_address: str, chain_id: int, signer: Signer): super().__init__(exchange_address, chain_id, signer) self.erc20_facade = Erc20Facade() self.erc1155_facade = Erc1155Facade() self.lop_facade = LimitOrderProtocolFacade() - - def build_limit_order(self, data: LimitOrderData)-> LimitOrder: + + def build_limit_order(self, data: LimitOrderData) -> LimitOrder: """ Builds a limit order """ if not self._validate_inputs(data): raise ValidationException("Invalid limit order inputs") - + if data.maker_asset_id is not None: maker_asset = data.exchange_address maker_asset_data = self.erc1155_facade.transfer_from( @@ -31,16 +31,14 @@ def build_limit_order(self, data: LimitOrderData)-> LimitOrder: data.taker_address, data.maker_asset_address, data.maker_asset_id, - data.maker_amount + data.maker_amount, ) else: maker_asset = data.maker_asset_address maker_asset_data = self.erc20_facade.transfer_from( - data.maker_address, - data.taker_address, - data.maker_amount + data.maker_address, data.taker_address, data.maker_amount ) - + if data.taker_asset_id is not None: taker_asset = data.exchange_address taker_asset_data = self.erc1155_facade.transfer_from( @@ -48,27 +46,33 @@ def build_limit_order(self, data: LimitOrderData)-> LimitOrder: data.maker_address, data.taker_asset_address, data.taker_asset_id, - data.taker_amount + data.taker_amount, ) else: taker_asset = data.taker_asset_address taker_asset_data = self.erc20_facade.transfer_from( - data.taker_address, - data.maker_address, - data.taker_amount + data.taker_address, data.maker_address, data.taker_amount ) - - predicate = data.predicate if(data.expiry is None and data.nonce is None) else self.lop_facade.lop_and( + + predicate = ( + data.predicate + if (data.expiry is None and data.nonce is None) + else self.lop_facade.lop_and( self.contract_address, [ self.lop_facade.timestamp_below(data.expiry), - self.lop_facade.nonce_equals(data.maker_address, data.nonce) - ] + self.lop_facade.nonce_equals(data.maker_address, data.nonce), + ], ) + ) signer = data.signer if data.signer is not None else data.maker_address - get_maker_amount = self.lop_facade.get_maker_amount_data(data.maker_amount, data.taker_amount) - get_taker_amount = self.lop_facade.get_taker_amount_data(data.maker_amount, data.taker_amount) + get_maker_amount = self.lop_facade.get_maker_amount_data( + data.maker_amount, data.taker_amount + ) + get_taker_amount = self.lop_facade.get_taker_amount_data( + data.maker_amount, data.taker_amount + ) return LimitOrder( salt=data.salt if data.salt else generate_seed(), @@ -80,10 +84,9 @@ def build_limit_order(self, data: LimitOrderData)-> LimitOrder: getTakerAmount=get_taker_amount, predicate=predicate, signer=signer, - sigType=data.sig_type + sigType=data.sig_type, ) - def build_limit_order_signature(self, limit_order: LimitOrder): """ Signs the Limit order @@ -91,7 +94,9 @@ def build_limit_order_signature(self, limit_order: LimitOrder): return self.sign(self._create_struct_hash(limit_order)) def build_limit_order_and_signature(self, limit_order: LimitOrder, signature: str): - return LimitOrderAndSignature(order=limit_order, signature=signature, orderType="limit") + return LimitOrderAndSignature( + order=limit_order, signature=signature, orderType="limit" + ) def create_limit_order(self, data: LimitOrderData): """ @@ -101,22 +106,19 @@ def create_limit_order(self, data: LimitOrderData): sig = self.build_limit_order_signature(order) return LimitOrderAndSignature(order=order, signature=sig, orderType="limit") - def _validate_inputs(self, data:LimitOrderData)-> bool: + def _validate_inputs(self, data: LimitOrderData) -> bool: return not ( # ensure required values exist - data.exchange_address is None or - data.maker_asset_address is None or - data.taker_asset_address is None or - data.maker_address is None or - data.maker_amount is None or - data.taker_amount is None or + data.exchange_address is None + or data.maker_asset_address is None + or data.taker_asset_address is None + or data.maker_address is None + or data.maker_amount is None + or data.taker_amount is None + or # both maker and taker asset ids cannot be None - (data.maker_asset_id is None and data.taker_asset_id is None) or + (data.maker_asset_id is None and data.taker_asset_id is None) + or # ensure that the exchange address is the same as the provided contract address normalize_address(data.exchange_address) != self.contract_address ) - - - - - diff --git a/py_order_utils/builders/market_order_builder.py b/py_order_utils/builders/market_order_builder.py index 7086fea..a97c6c8 100644 --- a/py_order_utils/builders/market_order_builder.py +++ b/py_order_utils/builders/market_order_builder.py @@ -6,12 +6,10 @@ class MarketOrderBuilder(BaseBuilder): - def __init__(self, exchange_address: str, chain_id: int, signer: Signer): super().__init__(exchange_address, chain_id, signer) - - def build_market_order(self, data: MarketOrderData)-> MarketOrder: + def build_market_order(self, data: MarketOrderData) -> MarketOrder: """ Builds a market order """ @@ -25,17 +23,16 @@ def build_market_order(self, data: MarketOrderData)-> MarketOrder: return MarketOrder( salt=data.salt if data.salt else generate_seed(), - maker = data.maker_address, - makerAsset = data.maker_asset_address, - makerAmount = data.maker_amount, - makerAssetID = maker_asset_id, - takerAsset = data.taker_asset_address, - takerAssetID = taker_asset_id, - signer= signer, - sigType = data.sig_type + maker=data.maker_address, + makerAsset=data.maker_asset_address, + makerAmount=data.maker_amount, + makerAssetID=maker_asset_id, + takerAsset=data.taker_asset_address, + takerAssetID=taker_asset_id, + signer=signer, + sigType=data.sig_type, ) - def build_market_order_signature(self, mkt_order: MarketOrder): """ Signs a market order @@ -43,12 +40,23 @@ def build_market_order_signature(self, mkt_order: MarketOrder): normalized_mkt_order = self._normalize(mkt_order) return self.sign(self._create_struct_hash(normalized_mkt_order)) - - def build_market_order_and_signature(self, mkt_order: MarketOrder, signature: str, minAmountReceived: str = "0", timeInForce: str = "FOK"): + def build_market_order_and_signature( + self, + mkt_order: MarketOrder, + signature: str, + minAmountReceived: str = "0", + timeInForce: str = "FOK", + ): """ Returns the canonical market order and signature object used across processes """ - return MarketOrderAndSignature(mkt_order, signature, "market", minAmountReceived=minAmountReceived, timeInForce=timeInForce) + return MarketOrderAndSignature( + mkt_order, + signature, + "market", + minAmountReceived=minAmountReceived, + timeInForce=timeInForce, + ) def create_market_order(self, data: MarketOrderData): """ @@ -56,30 +64,39 @@ def create_market_order(self, data: MarketOrderData): """ order = self.build_market_order(data) sig = self.build_market_order_signature(order) - return MarketOrderAndSignature(order=order, signature=sig, orderType="market", minAmountReceived=data.min_amount_received, timeInForce=data.time_in_force) + return MarketOrderAndSignature( + order=order, + signature=sig, + orderType="market", + minAmountReceived=data.min_amount_received, + timeInForce=data.time_in_force, + ) def _normalize(self, mkt_order: MarketOrder): return MarketOrder( - salt= mkt_order["salt"], - maker = mkt_order["maker"], - makerAsset = mkt_order["makerAsset"], - makerAmount = mkt_order["makerAmount"], - makerAssetID = mkt_order["makerAssetID"] if mkt_order["makerAssetID"] >= 0 else 0, - takerAsset = mkt_order["takerAsset"], - takerAssetID = mkt_order["takerAssetID"] if mkt_order["takerAssetID"] >= 0 else 0, - signer= mkt_order["signer"], - sigType = mkt_order["sigType"] + salt=mkt_order["salt"], + maker=mkt_order["maker"], + makerAsset=mkt_order["makerAsset"], + makerAmount=mkt_order["makerAmount"], + makerAssetID=mkt_order["makerAssetID"] + if mkt_order["makerAssetID"] >= 0 + else 0, + takerAsset=mkt_order["takerAsset"], + takerAssetID=mkt_order["takerAssetID"] + if mkt_order["takerAssetID"] >= 0 + else 0, + signer=mkt_order["signer"], + sigType=mkt_order["sigType"], ) - def _validate_inputs(self, data: MarketOrderData)->bool: + def _validate_inputs(self, data: MarketOrderData) -> bool: return not ( # ensure required values exist - data.exchange_address is None or - data.maker_asset_address is None or - data.taker_asset_address is None or - data.maker_address is None or - data.maker_amount is None or - (data.maker_asset_id is None and data.taker_asset_id is None) or - normalize_address(data.exchange_address) != self.contract_address + data.exchange_address is None + or data.maker_asset_address is None + or data.taker_asset_address is None + or data.maker_address is None + or data.maker_amount is None + or (data.maker_asset_id is None and data.taker_asset_id is None) + or normalize_address(data.exchange_address) != self.contract_address ) - \ No newline at end of file diff --git a/py_order_utils/config.py b/py_order_utils/config.py index 51bd494..29a7eda 100644 --- a/py_order_utils/config.py +++ b/py_order_utils/config.py @@ -7,41 +7,39 @@ def __init__(self, exchange, executor, collateral, conditional): def get_exchange(self): return self.exchange - + def get_executor(self): return self.executor - + def get_collateral(self): return self.collateral def get_conditional(self): return self.conditional - + CONFIG = { 137: ContractConfig( exchange="0xA5caFCC00E8D8E9121CC18B2DF279Eab5dE43bC5", executor="0xb2a29463Df393a4CAef36541544715e6B48b80B7", collateral="0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174", - conditional = "0x4D97DCd97eC945f40cF65F87097ACe5EA0476045" + conditional="0x4D97DCd97eC945f40cF65F87097ACe5EA0476045", ), - 80001: ContractConfig( - exchange="0xA5caFCC00E8D8E9121CC18B2DF279Eab5dE43bC5", - executor="0xb2a29463Df393a4CAef36541544715e6B48b80B7", + exchange="0xA5caFCC00E8D8E9121CC18B2DF279Eab5dE43bC5", + executor="0xb2a29463Df393a4CAef36541544715e6B48b80B7", collateral="0x2E8DCfE708D44ae2e406a1c02DFE2Fa13012f961", - conditional = "0x7D8610E9567d2a6C9FBf66a5A13E9Ba8bb120d43" - ) + conditional="0x7D8610E9567d2a6C9FBf66a5A13E9Ba8bb120d43", + ), } -def get_contract_config(chainID: int)->ContractConfig: + +def get_contract_config(chainID: int) -> ContractConfig: """ Get the contract configuration for the chain """ config = CONFIG.get(chainID) if config is None: raise Exception("Invalid chainID: ${}".format(chainID)) - - return config - + return config diff --git a/py_order_utils/constants.py b/py_order_utils/constants.py index 3096513..821cf1f 100644 --- a/py_order_utils/constants.py +++ b/py_order_utils/constants.py @@ -1,4 +1,2 @@ - -ZX = '0x' -ZERO_ADDRESS = '0x0000000000000000000000000000000000000000' - +ZX = "0x" +ZERO_ADDRESS = "0x0000000000000000000000000000000000000000" diff --git a/py_order_utils/facades/base_facade.py b/py_order_utils/facades/base_facade.py index 5d901b1..71a1818 100644 --- a/py_order_utils/facades/base_facade.py +++ b/py_order_utils/facades/base_facade.py @@ -2,8 +2,8 @@ import os from web3 import Web3 -class BaseFacade: +class BaseFacade: def __init__(self, contract_to_abi): self.contract_to_abi = contract_to_abi if contract_to_abi else {} self.web3 = Web3() @@ -11,20 +11,22 @@ def __init__(self, contract_to_abi): def _get_contract(self, contract_name): if not self.contract: - self.contract = self.web3.eth.contract(None, abi=self._get_abi(contract_name)) + self.contract = self.web3.eth.contract( + None, abi=self._get_abi(contract_name) + ) return self.contract - + def _get_abi(self, contract_name): abi_file_path = self.contract_to_abi.get(contract_name.lower()) if not abi_file_path: raise Exception("Contract ABI for {} not found".format(contract_name)) - + file_path = os.path.join( os.path.dirname(os.path.abspath(__file__)), - '..', + "..", abi_file_path, ) with open(file_path, "r") as fh: abi = json.load(fh) - return abi \ No newline at end of file + return abi diff --git a/py_order_utils/facades/erc1155_facade.py b/py_order_utils/facades/erc1155_facade.py index 167d4d9..91a5bee 100644 --- a/py_order_utils/facades/erc1155_facade.py +++ b/py_order_utils/facades/erc1155_facade.py @@ -2,10 +2,12 @@ from .base_facade import BaseFacade from ..utils import normalize_address + class Erc1155Facade(BaseFacade): """ Facade for ERC1155 transfers and balance """ + ABIS = {"erc1155": "abi/ERC1155ABI.json", "lop": "abi/PolyLimitOrderProtocol.json"} transferFrom = "func_733NCGU" balanceOf = "balanceOf" @@ -13,25 +15,29 @@ class Erc1155Facade(BaseFacade): def __init__(self): super().__init__(self.ABIS) - def transfer_from(self, from_address, to_address, token_address: str, token_id: str, value : str): + def transfer_from( + self, from_address, to_address, token_address: str, token_id: str, value: str + ): """ Creates transaction data for an ERC1155 transferFrom """ - + return self._get_contract("lop").encodeABI( - fn_name=self.transferFrom, + fn_name=self.transferFrom, args=[ normalize_address(from_address), normalize_address(to_address), value, normalize_address(token_address), token_id, - web3.Web3.toBytes(hexstr="0x0") - ] + web3.Web3.toBytes(hexstr="0x0"), + ], ) def balance_of(self, address: str, token_id: str): """ Creates transaction data for an ERC1155 balanceOf """ - return self._get_contract("erc1155").encodeABI(fn_name=self.balanceOf, args=[normalize_address(address), token_id]) + return self._get_contract("erc1155").encodeABI( + fn_name=self.balanceOf, args=[normalize_address(address), token_id] + ) diff --git a/py_order_utils/facades/erc20_facade.py b/py_order_utils/facades/erc20_facade.py index 8e6bf77..0fc956e 100644 --- a/py_order_utils/facades/erc20_facade.py +++ b/py_order_utils/facades/erc20_facade.py @@ -6,26 +6,29 @@ class Erc20Facade(BaseFacade): """ Facade for ERC20 transfers and balance """ - + ABIS = {"erc20": "abi/ERC20ABI.json"} def __init__(self): super().__init__(self.ABIS) - def transfer_from(self, from_address, to_address, value : str): + def transfer_from(self, from_address, to_address, value: str): """ Creates transaction data for an ERC20 transferFrom """ - return self._get_contract("erc20").encodeABI(fn_name="transferFrom", - args=[ - normalize_address(from_address), - normalize_address(to_address), - value - ] + return self._get_contract("erc20").encodeABI( + fn_name="transferFrom", + args=[ + normalize_address(from_address), + normalize_address(to_address), + value, + ], ) def balance_of(self, address): """ Creates transaction data for an ERC20 balanceOf """ - return self._get_contract("erc20").encodeABI(fn_name="balanceOf", args=[normalize_address(address)]) \ No newline at end of file + return self._get_contract("erc20").encodeABI( + fn_name="balanceOf", args=[normalize_address(address)] + ) diff --git a/py_order_utils/facades/limit_order_facade.py b/py_order_utils/facades/limit_order_facade.py index fe1018d..82e8cf1 100644 --- a/py_order_utils/facades/limit_order_facade.py +++ b/py_order_utils/facades/limit_order_facade.py @@ -7,7 +7,7 @@ class LimitOrderProtocolFacade(BaseFacade): """ Limit Order protocol facade """ - + ABIS = {"lop": "abi/PolyLimitOrderProtocol.json"} def __init__(self): @@ -18,24 +18,24 @@ def lop_and(self, contract_address: str, predicates: List[str]): function and(address[] calldata targets, bytes[] calldata data) """ return self._get_contract("lop").encodeABI( - fn_name="and", + fn_name="and", args=[ [normalize_address(contract_address) for _ in predicates], predicates, - ] + ], ) - + def nonce_equals(self, maker_address: str, maker_nonce: int): """ function nonceEquals(address makerAddress, uint256 makerNonce) external view returns(bool) """ return self._get_contract("lop").encodeABI( - fn_name="nonceEquals", + fn_name="nonceEquals", args=[ maker_address, maker_nonce, - ] + ], ) def timestamp_below(self, timestamp: int): @@ -43,31 +43,28 @@ def timestamp_below(self, timestamp: int): function timestampBelow(uint256 time) external view returns(bool) """ return self._get_contract("lop").encodeABI( - fn_name="timestampBelow", + fn_name="timestampBelow", args=[ timestamp, - ] + ], ) - def get_maker_amount_data(self, maker_amount, taker_amount:int): + def get_maker_amount_data(self, maker_amount, taker_amount: int): """ function getMakerAmount(uint256 orderMakerAmount, uint256 orderTakerAmount, uint256 swapTakerAmount) external pure returns(uint256) """ return self._get_amount_data("getMakerAmount", maker_amount, taker_amount) - def get_taker_amount_data(self, maker_amount, taker_amount:int): + def get_taker_amount_data(self, maker_amount, taker_amount: int): """ function getTakerAmount(uint256 orderMakerAmount, uint256 orderTakerAmount, uint256 swapMakerAmount) external pure returns(uint256) """ return self._get_amount_data("getTakerAmount", maker_amount, taker_amount) - def _get_amount_data(self, method, maker_amount, taker_amount: int, swap_taker_amount=0): + def _get_amount_data( + self, method, maker_amount, taker_amount: int, swap_taker_amount=0 + ): raw_amount_data = self._get_contract("lop").encodeABI( - fn_name=method, - args=[ - maker_amount, - taker_amount, - swap_taker_amount - ] + fn_name=method, args=[maker_amount, taker_amount, swap_taker_amount] ) return raw_amount_data[:138] diff --git a/py_order_utils/model/__init__.py b/py_order_utils/model/__init__.py index 70b3129..afa29e1 100644 --- a/py_order_utils/model/__init__.py +++ b/py_order_utils/model/__init__.py @@ -1,2 +1,7 @@ -from py_order_utils.model.model import LimitOrder, LimitOrderData, MarketOrderData, MarketOrder +from py_order_utils.model.model import ( + LimitOrder, + LimitOrderData, + MarketOrderData, + MarketOrder, +) from py_order_utils.model.signatures import EOA, CONTRACT, POLY_PROXY, POLY_GNOSIS_SAFE diff --git a/py_order_utils/model/model.py b/py_order_utils/model/model.py index e776c01..68c53eb 100644 --- a/py_order_utils/model/model.py +++ b/py_order_utils/model/model.py @@ -5,11 +5,13 @@ from .signatures import EOA from eip712_structs import Address, Bytes, EIP712Struct, Uint + @dataclass class LimitOrderData: """ Inputs to generate Limit orders """ + salt: int = None exchange_address: str = None maker_asset_address: str = None @@ -31,29 +33,30 @@ class LimitOrder(EIP712Struct): """ Limit Order """ + salt = Uint(256) - makerAsset = Address() + makerAsset = Address() takerAsset = Address() makerAssetData = Bytes() takerAssetData = Bytes() getMakerAmount = Bytes() getTakerAmount = Bytes() predicate = Bytes() - signer= Address() + signer = Address() sigType = Uint(256) def dict(self): return { - "salt": self["salt"], - "makerAsset": self["makerAsset"], - "takerAsset": self["takerAsset"], - "makerAssetData": self["makerAssetData"], - "takerAssetData": self["takerAssetData"], - "getMakerAmount": self["getMakerAmount"], - "getTakerAmount": self["getTakerAmount"], - "predicate": self["predicate"], - "signer": self["signer"], - "sigType": self["sigType"], + "salt": self["salt"], + "makerAsset": self["makerAsset"], + "takerAsset": self["takerAsset"], + "makerAssetData": self["makerAssetData"], + "takerAssetData": self["takerAssetData"], + "getMakerAmount": self["getMakerAmount"], + "getTakerAmount": self["getTakerAmount"], + "predicate": self["predicate"], + "signer": self["signer"], + "sigType": self["sigType"], } @@ -62,6 +65,7 @@ class MarketOrderData: """ Inputs to generate Market orders """ + salt: int = None exchange_address: str = None maker_asset_address: str = None @@ -75,10 +79,12 @@ class MarketOrderData: min_amount_received: int = "0" time_in_force: str = "FOK" + class MarketOrder(EIP712Struct): """ Market Order """ + # NOTE: Important to keep in mind, fields are ordered salt = Uint(256) signer = Address() @@ -102,13 +108,14 @@ def dict(self): "takerAssetID": str(self["takerAssetID"]), "sigType": self["sigType"], } - + @dataclass class LimitOrderAndSignature: """ Canonical Limit order and signature """ + order: LimitOrder signature: str orderType: str @@ -126,11 +133,14 @@ class MarketOrderAndSignature: """ Canonical Market order and signature """ + order: MarketOrder signature: str orderType: str - minAmountReceived: str = "0"; # Optional slippage protection field - timeInForce: str = "FOK"; # Optional market order type: FOK (fill or kill) / IOC (immediate or cancel) + minAmountReceived: str = "0" + # Optional slippage protection field + timeInForce: str = "FOK" + # Optional market order type: FOK (fill or kill) / IOC (immediate or cancel) def dict(self): return { @@ -138,5 +148,5 @@ def dict(self): "signature": self.signature, "orderType": self.orderType, "minAmountReceived": str(self.minAmountReceived), - "timeInForce": self.timeInForce + "timeInForce": self.timeInForce, } diff --git a/py_order_utils/model/signatures.py b/py_order_utils/model/signatures.py index 3a09289..a56a89d 100644 --- a/py_order_utils/model/signatures.py +++ b/py_order_utils/model/signatures.py @@ -1,4 +1,4 @@ EOA = 0 CONTRACT = 1 POLY_PROXY = 2 -POLY_GNOSIS_SAFE= 3 \ No newline at end of file +POLY_GNOSIS_SAFE = 3 diff --git a/py_order_utils/signer.py b/py_order_utils/signer.py index fea81bc..af49a40 100644 --- a/py_order_utils/signer.py +++ b/py_order_utils/signer.py @@ -1,17 +1,17 @@ from eth_account import Account + class Signer: """ - Signs orders using a private key + Signs orders using a private key """ def __init__(self, key: str): self._key = key self.account = Account.from_key(key) - - def sign(self, struct_hash)->str: + + def sign(self, struct_hash) -> str: """ Signs an EIP712 struct hash """ return Account._sign_hash(struct_hash, self._key).signature.hex() - diff --git a/py_order_utils/utils.py b/py_order_utils/utils.py index a5d069b..843012a 100644 --- a/py_order_utils/utils.py +++ b/py_order_utils/utils.py @@ -6,31 +6,36 @@ max_int = math.pow(2, 32) -def normalize(s: str)-> str: + +def normalize(s: str) -> str: lowered = s.lower() for p in punctuation: lowered = lowered.replace(p, "") return lowered + def normalize_address(address: str) -> str: return web3.Web3.toChecksumAddress(address) -def generate_seed()-> int: + +def generate_seed() -> int: """ Pseudo random seed """ now = datetime.now().replace(tzinfo=timezone.utc).timestamp() - return round(now * random()) + return round(now * random()) + def hash_string(s: str): return solidity_keccak("string", s) + def hash_bytes(b): - return solidity_keccak("bytes", b) + return solidity_keccak("bytes", b) + def solidity_keccak(typ, val): return web3.Web3.solidityKeccak( abi_types=[typ], values=[val], ) - diff --git a/requirements.txt b/requirements.txt index 38a86b7..cbdd31b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -46,3 +46,4 @@ varint==1.0.2 web3==5.26.0 websockets==9.1 yarl==1.7.2 +black==22.1.0 diff --git a/setup.py b/setup.py index 50dc69d..95f3758 100644 --- a/setup.py +++ b/setup.py @@ -5,26 +5,26 @@ setuptools.setup( name="py_order_utils", - version="0.0.23", + version="0.1.0", author="Jonathan Amenechi", author_email="jonathanamenechi@gmail.com", - description="Python utilities used to generate and sign limit and market orders on Polymarket's CLOB", + description="Python utilities used to generate and sign orders from Polymarket's Exchange", long_description=long_description, long_description_content_type="text/markdown", url="https://github.com/polymarket/python-order-utils", install_requires=[ - 'web3>=5.0.0,<6.0.0', - 'eth-account>=0.4.0,<0.6.0', - 'eip712-structs', - 'pytest', - 'eth-abi', - 'eth_typing', - 'eth_utils', - 'eth_utils', + "web3>=5.0.0,<6.0.0", + "eth-account>=0.4.0,<0.6.0", + "eip712-structs", + "pytest", + "eth-abi", + "eth_typing", + "eth_utils", + "eth_utils", ], package_data={ - 'py_order_utils': [ - 'abi/*.json', + "py_order_utils": [ + "abi/*.json", ], }, project_urls={ @@ -38,4 +38,3 @@ packages=setuptools.find_packages(), python_requires=">=3.9.10", ) - diff --git a/tests/test_config.py b/tests/test_config.py index 2c56f0a..d9ccaa0 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -1,17 +1,15 @@ from unittest import TestCase from py_order_utils.config import get_contract_config -class TestConfig(TestCase): +class TestConfig(TestCase): def test_get_config(self): valid_config = get_contract_config(80001) self.assertIsNotNone(valid_config) self.assertIsNotNone(valid_config.get_exchange()) self.assertIsNotNone(valid_config.get_executor()) self.assertIsNotNone(valid_config.get_collateral()) - - + # invalid config with self.assertRaises(Exception): get_contract_config(2190239023902) - diff --git a/tests/test_facades.py b/tests/test_facades.py index e13b804..477cf50 100644 --- a/tests/test_facades.py +++ b/tests/test_facades.py @@ -1,30 +1,33 @@ import web3 from unittest import TestCase -from py_order_utils.facades import Erc20Facade, Erc1155Facade , LimitOrderProtocolFacade +from py_order_utils.facades import Erc20Facade, Erc1155Facade, LimitOrderProtocolFacade class TestFacade(TestCase): - def setUp(self): self.erc20_facade = Erc20Facade() self.erc1155_facade = Erc1155Facade() self.lop_facade = LimitOrderProtocolFacade() - + def test_erc20_balance_of(self): address = "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B" # Expected input data generated using ethers - expected = "0x70a08231000000000000000000000000ab5801a7d398351b8be11c439e05c5b3259aec9b" + expected = ( + "0x70a08231000000000000000000000000ab5801a7d398351b8be11c439e05c5b3259aec9b" + ) self.assertEqual(expected, self.erc20_facade.balance_of(address)) def test_erc20_transfer_from(self): from_address = "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B" to_address = "0x1Db3439a222C519ab44bb1144fC28167b4Fa6EE6" - value = web3.Web3.toWei(100, 'ether') + value = web3.Web3.toWei(100, "ether") # Expected input data generated using ethers expected = "0x23b872dd000000000000000000000000ab5801a7d398351b8be11c439e05c5b3259aec9b0000000000000000000000001db3439a222c519ab44bb1144fc28167b4fa6ee60000000000000000000000000000000000000000000000056bc75e2d63100000" - - self.assertEqual(expected, self.erc20_facade.transfer_from(from_address, to_address, value)) + + self.assertEqual( + expected, self.erc20_facade.transfer_from(from_address, to_address, value) + ) def test_erc1155_balance_of(self): address = "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B" @@ -37,47 +40,63 @@ def test_erc1155_balance_of(self): def test_erc1155_transfer_from(self): from_address = "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B" to_address = "0x1Db3439a222C519ab44bb1144fC28167b4Fa6EE6" - value = web3.Web3.toWei(100, 'ether') + value = web3.Web3.toWei(100, "ether") token_address = "0xadbeD21409324e0fcB80AE8b5e662B0C857D85ed" token_id = 0 - + # Expected input data generated using ethers expected = "0x23b872e1000000000000000000000000ab5801a7d398351b8be11c439e05c5b3259aec9b0000000000000000000000001db3439a222c519ab44bb1144fc28167b4fa6ee60000000000000000000000000000000000000000000000056bc75e2d63100000000000000000000000000000adbed21409324e0fcb80ae8b5e662b0c857d85ed000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000" - self.assertEqual(expected, self.erc1155_facade.transfer_from(from_address, to_address, token_address, token_id, value)) + self.assertEqual( + expected, + self.erc1155_facade.transfer_from( + from_address, to_address, token_address, token_id, value + ), + ) def test_lop_and(self): - predicates=[ - "0x63592c2b0000000000000000000000000000000000000000000000000000000061f3f65e", - "0xcf6fc6e300000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c80000000000000000000000000000000000000000000000000000000000000000" + predicates = [ + "0x63592c2b0000000000000000000000000000000000000000000000000000000061f3f65e", + "0xcf6fc6e300000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c80000000000000000000000000000000000000000000000000000000000000000", ] expected = "0x961d5b1e000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cf7ed3acca5a467e9e704c703e8d87f634fb0fc9000000000000000000000000cf7ed3acca5a467e9e704c703e8d87f634fb0fc90000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000002463592c2b0000000000000000000000000000000000000000000000000000000061f3f65e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044cf6fc6e300000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - self.assertEqual(expected, self.lop_facade.lop_and("0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9", predicates)) + self.assertEqual( + expected, + self.lop_facade.lop_and( + "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9", predicates + ), + ) def test_lop_nonce_equals(self): maker_address = "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" maker_nonce = 0 expected = "0xcf6fc6e300000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c80000000000000000000000000000000000000000000000000000000000000000" - self.assertEqual(expected, self.lop_facade.nonce_equals(maker_address, maker_nonce)) + self.assertEqual( + expected, self.lop_facade.nonce_equals(maker_address, maker_nonce) + ) def test_lop_ts_below(self): timestamp = 1643379170 - expected = "0x63592c2b0000000000000000000000000000000000000000000000000000000061f3f9e2" + expected = ( + "0x63592c2b0000000000000000000000000000000000000000000000000000000061f3f9e2" + ) self.assertEqual(expected, self.lop_facade.timestamp_below(timestamp)) - + def test_lop_get_maker_amount(self): maker_amount = 1000000 taker_amount = 500000 expected = "0xf4a215c300000000000000000000000000000000000000000000000000000000000f4240000000000000000000000000000000000000000000000000000000000007a120" - self.assertEqual(expected, self.lop_facade.get_maker_amount_data(maker_amount, taker_amount)) - + self.assertEqual( + expected, self.lop_facade.get_maker_amount_data(maker_amount, taker_amount) + ) def test_lop_get_taker_amount(self): maker_amount = 1000000 taker_amount = 500000 expected = "0x296637bf00000000000000000000000000000000000000000000000000000000000f4240000000000000000000000000000000000000000000000000000000000007a120" - self.assertEqual(expected, self.lop_facade.get_taker_amount_data(maker_amount, taker_amount)) - \ No newline at end of file + self.assertEqual( + expected, self.lop_facade.get_taker_amount_data(maker_amount, taker_amount) + ) diff --git a/tests/test_limit_order_builder.py b/tests/test_limit_order_builder.py index 9adc9fa..346bca2 100644 --- a/tests/test_limit_order_builder.py +++ b/tests/test_limit_order_builder.py @@ -6,12 +6,13 @@ class TestLimitOrderBuilder(TestCase): - def test_validate_order(self): - lop_builder = LimitOrderBuilder("0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9", 1, mock.MagicMock()) + lop_builder = LimitOrderBuilder( + "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9", 1, mock.MagicMock() + ) data = self.generate_data() - + # Valid order self.assertTrue(lop_builder._validate_inputs(data)) @@ -32,88 +33,96 @@ def test_validate_order(self): self.assertFalse(lop_builder._validate_inputs(data)) def test_build_limit_order(self): - lop_builder = LimitOrderBuilder("0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9", 1, mock.MagicMock()) + lop_builder = LimitOrderBuilder( + "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9", 1, mock.MagicMock() + ) invalid_data_input = self.generate_data() - invalid_data_input.exchange_address = "0x0000000000000000000000000000000000000000" - + invalid_data_input.exchange_address = ( + "0x0000000000000000000000000000000000000000" + ) + # throw if invalid limit order input with self.assertRaises(ValidationException): lop_builder.build_limit_order(invalid_data_input) limit_order = lop_builder.build_limit_order(self.generate_data()) - + # Ensure correct values on limit order self.assertTrue(isinstance(limit_order["salt"], int)) - - self.assertEqual("0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", limit_order["makerAsset"]) - self.assertEqual("0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9", limit_order["takerAsset"]) self.assertEqual( - "0x23b872dd00000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f4240", - limit_order["makerAssetData"] + "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", limit_order["makerAsset"] + ) + self.assertEqual( + "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9", limit_order["takerAsset"] + ) + + self.assertEqual( + "0x23b872dd00000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f4240", + limit_order["makerAssetData"], ) self.assertEqual( - "0x23b872e1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8000000000000000000000000000000000000000000000000000000000007a1200000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa3000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000", - limit_order["takerAssetData"] + "0x23b872e1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8000000000000000000000000000000000000000000000000000000000007a1200000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa3000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000", + limit_order["takerAssetData"], ) self.assertEqual( "0xf4a215c300000000000000000000000000000000000000000000000000000000000f4240000000000000000000000000000000000000000000000000000000000007a120", - limit_order["getMakerAmount"] + limit_order["getMakerAmount"], ) self.assertEqual( "0x296637bf00000000000000000000000000000000000000000000000000000000000f4240000000000000000000000000000000000000000000000000000000000007a120", - limit_order["getTakerAmount"] + limit_order["getTakerAmount"], ) self.assertEqual( "0x961d5b1e000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cf7ed3acca5a467e9e704c703e8d87f634fb0fc9000000000000000000000000cf7ed3acca5a467e9e704c703e8d87f634fb0fc90000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000002463592c2b0000000000000000000000000000000000000000000000000000000061f5119f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044cf6fc6e300000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - limit_order["predicate"] + limit_order["predicate"], ) self.assertEqual( - "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", - limit_order["signer"] + "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", limit_order["signer"] ) - self.assertEqual( - EOA, - limit_order["sigType"] - ) + self.assertEqual(EOA, limit_order["sigType"]) def test_build_signature(self): signer = mock.MagicMock() expected_signature = "0xba171a61c9c0bc4453d29d9ab9e3699fd0be7eef8ab6fba1b2c6555ced42f79d7bb5a07f975b1bfaf7bccf7b8e89e1877ba717090a4e9934136f6e6743a7146b1b" - + # Instead of using a private key, unit tests mock the expected signature response signer.sign.return_value = expected_signature - builder = LimitOrderBuilder("0x0165878A594ca255338adfa4d48449f69242Eb8F", 31337, signer) - + builder = LimitOrderBuilder( + "0x0165878A594ca255338adfa4d48449f69242Eb8F", 31337, signer + ) + order = LimitOrder( salt=1568294891220, - makerAsset='0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512', - takerAsset='0x0165878A594ca255338adfa4d48449f69242Eb8F', - makerAssetData='0x23b872dd00000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f4240', - takerAssetData='0x23b872e1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8000000000000000000000000000000000000000000000000000000000007a1200000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa3000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000', - getMakerAmount='0xf4a215c300000000000000000000000000000000000000000000000000000000000f4240000000000000000000000000000000000000000000000000000000000007a120', - getTakerAmount='0x296637bf00000000000000000000000000000000000000000000000000000000000f4240000000000000000000000000000000000000000000000000000000000007a120', - predicate='0x961d5b1e000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000165878a594ca255338adfa4d48449f69242eb8f0000000000000000000000000165878a594ca255338adfa4d48449f69242eb8f0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000002463592c2b00000000000000000000000000000000000000000000000000000000628e1424000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044cf6fc6e300000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', - signer='0x70997970C51812dc3A010C7d01b50e0d17dc79C8', - sigType=0 + makerAsset="0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", + takerAsset="0x0165878A594ca255338adfa4d48449f69242Eb8F", + makerAssetData="0x23b872dd00000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f4240", + takerAssetData="0x23b872e1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8000000000000000000000000000000000000000000000000000000000007a1200000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa3000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000", + getMakerAmount="0xf4a215c300000000000000000000000000000000000000000000000000000000000f4240000000000000000000000000000000000000000000000000000000000007a120", + getTakerAmount="0x296637bf00000000000000000000000000000000000000000000000000000000000f4240000000000000000000000000000000000000000000000000000000000007a120", + predicate="0x961d5b1e000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000165878a594ca255338adfa4d48449f69242eb8f0000000000000000000000000165878a594ca255338adfa4d48449f69242eb8f0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000002463592c2b00000000000000000000000000000000000000000000000000000000628e1424000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044cf6fc6e300000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + signer="0x70997970C51812dc3A010C7d01b50e0d17dc79C8", + sigType=0, ) # Ensure struct hash is expected(generated via ethers) - expected_struct_hash = "0xfd94c8eb9dbfabc41329eda323fb9ad4d69eda4f27c1be41cc53c902fb749a4b" + expected_struct_hash = ( + "0xfd94c8eb9dbfabc41329eda323fb9ad4d69eda4f27c1be41cc53c902fb749a4b" + ) struct_hash = builder._create_struct_hash(order) self.assertEqual(expected_struct_hash, struct_hash.hex()) - + sig = builder.build_limit_order_signature(order) self.assertEqual(expected_signature, sig) - def generate_data(self)->LimitOrderData: + def generate_data(self) -> LimitOrderData: return LimitOrderData( salt=990606491137, exchange_address="0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9", @@ -125,7 +134,5 @@ def generate_data(self)->LimitOrderData: maker_amount=1000000, taker_amount=500000, expiry=1643450783, - nonce=0 + nonce=0, ) - - diff --git a/tests/test_market_order_builder.py b/tests/test_market_order_builder.py index 2ca3b60..2c0f5a9 100644 --- a/tests/test_market_order_builder.py +++ b/tests/test_market_order_builder.py @@ -6,12 +6,13 @@ class TestMarketOrderBuilder(TestCase): - def test_validate_inputs(self): - builder = MarketOrderBuilder("0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9", 31337, mock.MagicMock()) + builder = MarketOrderBuilder( + "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9", 31337, mock.MagicMock() + ) data = self.generate_data() - + # Valid order self.assertTrue(builder._validate_inputs(data)) @@ -30,50 +31,65 @@ def test_validate_inputs(self): data.maker_asset_id = None data.taker_asset_id = None self.assertFalse(builder._validate_inputs(data)) - def test_build_market_order(self): - builder = MarketOrderBuilder("0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9", 31337, mock.MagicMock()) + builder = MarketOrderBuilder( + "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9", 31337, mock.MagicMock() + ) mkt_order = builder.build_market_order(self.generate_data()) - + # Ensure correct values self.assertTrue(isinstance(mkt_order["salt"], int)) - self.assertEqual("0xe3d9BFA896aF6988f80027bfd13440A42C5ed02b", mkt_order["maker"]) - self.assertEqual("0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", mkt_order["makerAsset"]) + self.assertEqual( + "0xe3d9BFA896aF6988f80027bfd13440A42C5ed02b", mkt_order["maker"] + ) + self.assertEqual( + "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", mkt_order["makerAsset"] + ) self.assertEqual(1000000, mkt_order["makerAmount"]) self.assertEqual(0, mkt_order["makerAssetID"]) - self.assertEqual("0x5FbDB2315678afecb367f032d93F642f64180aa3", mkt_order["takerAsset"]) + self.assertEqual( + "0x5FbDB2315678afecb367f032d93F642f64180aa3", mkt_order["takerAsset"] + ) self.assertEqual(1, mkt_order["takerAssetID"]) - self.assertEqual("0xe3d9BFA896aF6988f80027bfd13440A42C5ed02b", mkt_order["signer"]) + self.assertEqual( + "0xe3d9BFA896aF6988f80027bfd13440A42C5ed02b", mkt_order["signer"] + ) self.assertEqual(EOA, mkt_order["sigType"]) def test_build_market_order_signature(self): mkt_order_data = MarketOrderData( - exchange_address='0x0165878A594ca255338adfa4d48449f69242Eb8F', + exchange_address="0x0165878A594ca255338adfa4d48449f69242Eb8F", salt=1028957131466, - signer='0x70997970C51812dc3A010C7d01b50e0d17dc79C8', - maker_address='0x70997970C51812dc3A010C7d01b50e0d17dc79C8', - maker_asset_address='0x5FbDB2315678afecb367f032d93F642f64180aa3', + signer="0x70997970C51812dc3A010C7d01b50e0d17dc79C8", + maker_address="0x70997970C51812dc3A010C7d01b50e0d17dc79C8", + maker_asset_address="0x5FbDB2315678afecb367f032d93F642f64180aa3", maker_amount=150000000, maker_asset_id=0, - taker_asset_address='0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512', + taker_asset_address="0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", taker_asset_id=0, - sig_type=0 + sig_type=0, ) expected_sig = "0x62a1b1b3634d5ba8eca890fd7954247c7dbe1a50211bdff31753b3687bb6d0311f3df23e52401f73be7f2cd407902696479af8d324fdc9836769993786b710d41c" signer = mock.MagicMock() signer.sign.return_value = expected_sig - - builder = MarketOrderBuilder("0x0165878A594ca255338adfa4d48449f69242Eb8F", 31337, signer) - expected_struct_hash = "0x6b5da848321b92bc4c7d045289484063e6e31aa3197bd2ccecad302f6b043b47" + + builder = MarketOrderBuilder( + "0x0165878A594ca255338adfa4d48449f69242Eb8F", 31337, signer + ) + expected_struct_hash = ( + "0x6b5da848321b92bc4c7d045289484063e6e31aa3197bd2ccecad302f6b043b47" + ) mkt_order = builder.build_market_order(mkt_order_data) - self.assertEqual(expected_struct_hash, builder._create_struct_hash(mkt_order).hex()) - + self.assertEqual( + expected_struct_hash, builder._create_struct_hash(mkt_order).hex() + ) + signature = builder.build_market_order_signature(mkt_order) self.assertEqual(expected_sig, signature) @@ -88,4 +104,3 @@ def generate_data(self): taker_asset_address="0x5FbDB2315678afecb367f032d93F642f64180aa3", taker_asset_id=1, ) - diff --git a/tests/test_utils.py b/tests/test_utils.py index ea68731..499297d 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -3,13 +3,11 @@ class TestUtils(TestCase): - def test_normalize_address(self): self.assertEqual( - normalize_address("0x8b4de256180cfec54c436a470af50f9ee2813dbb"), - "0x8B4de256180CFEC54c436A470AF50F9EE2813dbB" + normalize_address("0x8b4de256180cfec54c436a470af50f9ee2813dbb"), + "0x8B4de256180CFEC54c436A470AF50F9EE2813dbB", ) - + def test_generate_seed(self): self.assertIsNotNone(generate_seed()) - From 84f4c9a41ee98a3709fb690ff1d4facff8edea9a Mon Sep 17 00:00:00 2001 From: Rodrigo <95635797+poly-rodr@users.noreply.github.com> Date: Wed, 21 Sep 2022 19:58:09 -0300 Subject: [PATCH 2/5] new contract implementation + tests --- .gitignore | 1 + README.md | 2 +- py_order_utils/abi/ERC1155ABI.json | 319 ---- py_order_utils/abi/ERC20ABI.json | 222 --- py_order_utils/abi/Exchange.json | 1129 +++++++++++++ .../abi/PolyLimitOrderProtocol.json | 1437 ----------------- py_order_utils/builders/__init__.py | 3 +- py_order_utils/builders/base_builder.py | 7 +- .../builders/limit_order_builder.py | 124 -- .../builders/market_order_builder.py | 102 -- py_order_utils/builders/order_builder.py | 90 ++ py_order_utils/config.py | 4 +- py_order_utils/facades/__init__.py | 3 - py_order_utils/facades/base_facade.py | 32 - py_order_utils/facades/erc1155_facade.py | 43 - py_order_utils/facades/erc20_facade.py | 34 - py_order_utils/facades/limit_order_facade.py | 70 - py_order_utils/model/__init__.py | 10 +- py_order_utils/model/model.py | 152 -- py_order_utils/model/order.py | 171 ++ py_order_utils/model/sides.py | 3 + py_order_utils/model/signatures.py | 10 +- py_order_utils/signer.py | 3 + tests/test_facades.py | 102 -- tests/test_limit_order_builder.py | 138 -- tests/test_market_order_builder.py | 106 -- tests/test_order_builder.py | 149 ++ 27 files changed, 1565 insertions(+), 2901 deletions(-) delete mode 100644 py_order_utils/abi/ERC1155ABI.json delete mode 100644 py_order_utils/abi/ERC20ABI.json create mode 100644 py_order_utils/abi/Exchange.json delete mode 100644 py_order_utils/abi/PolyLimitOrderProtocol.json delete mode 100644 py_order_utils/builders/limit_order_builder.py delete mode 100644 py_order_utils/builders/market_order_builder.py create mode 100644 py_order_utils/builders/order_builder.py delete mode 100644 py_order_utils/facades/__init__.py delete mode 100644 py_order_utils/facades/base_facade.py delete mode 100644 py_order_utils/facades/erc1155_facade.py delete mode 100644 py_order_utils/facades/erc20_facade.py delete mode 100644 py_order_utils/facades/limit_order_facade.py delete mode 100644 py_order_utils/model/model.py create mode 100644 py_order_utils/model/order.py create mode 100644 py_order_utils/model/sides.py delete mode 100644 tests/test_facades.py delete mode 100644 tests/test_limit_order_builder.py delete mode 100644 tests/test_market_order_builder.py create mode 100644 tests/test_order_builder.py diff --git a/.gitignore b/.gitignore index 855a1dc..5f4ee09 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ lib64/ parts/ sdist/ var/ +venv/ # files .env diff --git a/README.md b/README.md index b70ee95..b0c7839 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ def main(): builder = OrderBuilder(exchange_address, chain_id, signer) # Create and sign the order - order = builder.create_order( + order = builder.build_signed_order( OrderData( ... ) diff --git a/py_order_utils/abi/ERC1155ABI.json b/py_order_utils/abi/ERC1155ABI.json deleted file mode 100644 index 84fc0a8..0000000 --- a/py_order_utils/abi/ERC1155ABI.json +++ /dev/null @@ -1,319 +0,0 @@ -[ - { - "inputs": [], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "operator", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "ApprovalForAll", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "operator", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256[]", - "name": "ids", - "type": "uint256[]" - }, - { - "indexed": false, - "internalType": "uint256[]", - "name": "values", - "type": "uint256[]" - } - ], - "name": "TransferBatch", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "operator", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "id", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "TransferSingle", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "string", - "name": "value", - "type": "string" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "id", - "type": "uint256" - } - ], - "name": "URI", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "uint256", - "name": "id", - "type": "uint256" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address[]", - "name": "accounts", - "type": "address[]" - }, - { - "internalType": "uint256[]", - "name": "ids", - "type": "uint256[]" - } - ], - "name": "balanceOfBatch", - "outputs": [ - { - "internalType": "uint256[]", - "name": "", - "type": "uint256[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "address", - "name": "operator", - "type": "address" - } - ], - "name": "isApprovedForAll", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256[]", - "name": "ids", - "type": "uint256[]" - }, - { - "internalType": "uint256[]", - "name": "amounts", - "type": "uint256[]" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "safeBatchTransferFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "id", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "safeTransferFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "operator", - "type": "address" - }, - { - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "setApprovalForAll", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes4", - "name": "interfaceId", - "type": "bytes4" - } - ], - "name": "supportsInterface", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "name": "uri", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/py_order_utils/abi/ERC20ABI.json b/py_order_utils/abi/ERC20ABI.json deleted file mode 100644 index 06b572d..0000000 --- a/py_order_utils/abi/ERC20ABI.json +++ /dev/null @@ -1,222 +0,0 @@ -[ - { - "constant": true, - "inputs": [], - "name": "name", - "outputs": [ - { - "name": "", - "type": "string" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "_spender", - "type": "address" - }, - { - "name": "_value", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "_from", - "type": "address" - }, - { - "name": "_to", - "type": "address" - }, - { - "name": "_value", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "decimals", - "outputs": [ - { - "name": "", - "type": "uint8" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "_owner", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "name": "balance", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "symbol", - "outputs": [ - { - "name": "", - "type": "string" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "_to", - "type": "address" - }, - { - "name": "_value", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "_owner", - "type": "address" - }, - { - "name": "_spender", - "type": "address" - } - ], - "name": "allowance", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "payable": true, - "stateMutability": "payable", - "type": "fallback" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "name": "spender", - "type": "address" - }, - { - "indexed": false, - "name": "value", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "from", - "type": "address" - }, - { - "indexed": true, - "name": "to", - "type": "address" - }, - { - "indexed": false, - "name": "value", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - } -] diff --git a/py_order_utils/abi/Exchange.json b/py_order_utils/abi/Exchange.json new file mode 100644 index 0000000..8083ebf --- /dev/null +++ b/py_order_utils/abi/Exchange.json @@ -0,0 +1,1129 @@ +[ + { + "inputs": [ + { "internalType": "address", "name": "_collateral", "type": "address" }, + { "internalType": "address", "name": "_ctf", "type": "address" }, + { "internalType": "address", "name": "_proxyFactory", "type": "address" }, + { "internalType": "address", "name": "_safeFactory", "type": "address" } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { "inputs": [], "name": "AlreadyRegistered", "type": "error" }, + { "inputs": [], "name": "FeeTooHigh", "type": "error" }, + { "inputs": [], "name": "InvalidComplement", "type": "error" }, + { "inputs": [], "name": "InvalidNonce", "type": "error" }, + { "inputs": [], "name": "InvalidSignature", "type": "error" }, + { "inputs": [], "name": "InvalidTokenId", "type": "error" }, + { "inputs": [], "name": "MakingGtRemaining", "type": "error" }, + { "inputs": [], "name": "MismatchedTokenIds", "type": "error" }, + { "inputs": [], "name": "NotAdmin", "type": "error" }, + { "inputs": [], "name": "NotCrossing", "type": "error" }, + { "inputs": [], "name": "NotOperator", "type": "error" }, + { "inputs": [], "name": "NotOwner", "type": "error" }, + { "inputs": [], "name": "NotTaker", "type": "error" }, + { "inputs": [], "name": "OrderExpired", "type": "error" }, + { "inputs": [], "name": "OrderFilledOrCancelled", "type": "error" }, + { "inputs": [], "name": "Paused", "type": "error" }, + { "inputs": [], "name": "TooLittleTokensReceived", "type": "error" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "FeeCharged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "newAdminAddress", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "admin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "newOperatorAddress", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "admin", + "type": "address" + } + ], + "name": "NewOperator", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "orderHash", + "type": "bytes32" + } + ], + "name": "OrderCancelled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "orderHash", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "filler", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "makerAssetId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "takerAssetId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "filled", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "remaining", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "fee", + "type": "uint256" + } + ], + "name": "OrderFilled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "takerOrderHash", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "makerAssetId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "takerAssetId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "makerAmountFilled", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "takerAmountFilled", + "type": "uint256" + } + ], + "name": "OrdersMatched", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldProxyFactory", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newProxyFactory", + "type": "address" + } + ], + "name": "ProxyFactoryUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "removedAdmin", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "admin", + "type": "address" + } + ], + "name": "RemovedAdmin", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "removedOperator", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "admin", + "type": "address" + } + ], + "name": "RemovedOperator", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldSafeFactory", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newSafeFactory", + "type": "address" + } + ], + "name": "SafeFactoryUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "token0", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "token1", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "conditionId", + "type": "bytes32" + } + ], + "name": "TokenRegistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pauser", + "type": "address" + } + ], + "name": "TradingPaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pauser", + "type": "address" + } + ], + "name": "TradingUnpaused", + "type": "event" + }, + { + "inputs": [ + { "internalType": "address", "name": "admin_", "type": "address" } + ], + "name": "addAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "operator_", "type": "address" } + ], + "name": "addOperator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "admins", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "uint256", "name": "salt", "type": "uint256" }, + { "internalType": "address", "name": "maker", "type": "address" }, + { "internalType": "address", "name": "signer", "type": "address" }, + { "internalType": "address", "name": "taker", "type": "address" }, + { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, + { + "internalType": "uint256", + "name": "makerAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "takerAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expiration", + "type": "uint256" + }, + { "internalType": "uint256", "name": "nonce", "type": "uint256" }, + { + "internalType": "uint256", + "name": "feeRateBps", + "type": "uint256" + }, + { "internalType": "enum Side", "name": "side", "type": "uint8" }, + { + "internalType": "enum SignatureType", + "name": "signatureType", + "type": "uint8" + }, + { "internalType": "bytes", "name": "signature", "type": "bytes" } + ], + "internalType": "struct Order", + "name": "order", + "type": "tuple" + } + ], + "name": "cancelOrder", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "uint256", "name": "salt", "type": "uint256" }, + { "internalType": "address", "name": "maker", "type": "address" }, + { "internalType": "address", "name": "signer", "type": "address" }, + { "internalType": "address", "name": "taker", "type": "address" }, + { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, + { + "internalType": "uint256", + "name": "makerAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "takerAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expiration", + "type": "uint256" + }, + { "internalType": "uint256", "name": "nonce", "type": "uint256" }, + { + "internalType": "uint256", + "name": "feeRateBps", + "type": "uint256" + }, + { "internalType": "enum Side", "name": "side", "type": "uint8" }, + { + "internalType": "enum SignatureType", + "name": "signatureType", + "type": "uint8" + }, + { "internalType": "bytes", "name": "signature", "type": "bytes" } + ], + "internalType": "struct Order[]", + "name": "orders", + "type": "tuple[]" + } + ], + "name": "cancelOrders", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "domainSeparator", + "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "uint256", "name": "salt", "type": "uint256" }, + { "internalType": "address", "name": "maker", "type": "address" }, + { "internalType": "address", "name": "signer", "type": "address" }, + { "internalType": "address", "name": "taker", "type": "address" }, + { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, + { + "internalType": "uint256", + "name": "makerAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "takerAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expiration", + "type": "uint256" + }, + { "internalType": "uint256", "name": "nonce", "type": "uint256" }, + { + "internalType": "uint256", + "name": "feeRateBps", + "type": "uint256" + }, + { "internalType": "enum Side", "name": "side", "type": "uint8" }, + { + "internalType": "enum SignatureType", + "name": "signatureType", + "type": "uint8" + }, + { "internalType": "bytes", "name": "signature", "type": "bytes" } + ], + "internalType": "struct Order", + "name": "order", + "type": "tuple" + }, + { "internalType": "uint256", "name": "fillAmount", "type": "uint256" } + ], + "name": "fillOrder", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "uint256", "name": "salt", "type": "uint256" }, + { "internalType": "address", "name": "maker", "type": "address" }, + { "internalType": "address", "name": "signer", "type": "address" }, + { "internalType": "address", "name": "taker", "type": "address" }, + { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, + { + "internalType": "uint256", + "name": "makerAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "takerAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expiration", + "type": "uint256" + }, + { "internalType": "uint256", "name": "nonce", "type": "uint256" }, + { + "internalType": "uint256", + "name": "feeRateBps", + "type": "uint256" + }, + { "internalType": "enum Side", "name": "side", "type": "uint8" }, + { + "internalType": "enum SignatureType", + "name": "signatureType", + "type": "uint8" + }, + { "internalType": "bytes", "name": "signature", "type": "bytes" } + ], + "internalType": "struct Order[]", + "name": "orders", + "type": "tuple[]" + }, + { + "internalType": "uint256[]", + "name": "fillAmounts", + "type": "uint256[]" + } + ], + "name": "fillOrders", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getCollateral", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "token", "type": "uint256" } + ], + "name": "getComplement", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "token", "type": "uint256" } + ], + "name": "getConditionId", + "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCtf", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getMaxFeeRate", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes32", "name": "orderHash", "type": "bytes32" } + ], + "name": "getOrderStatus", + "outputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "isFilledOrCancelled", + "type": "bool" + }, + { "internalType": "uint256", "name": "remaining", "type": "uint256" } + ], + "internalType": "struct OrderStatus", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPolyProxyFactoryImplementation", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_addr", "type": "address" } + ], + "name": "getPolyProxyWalletAddress", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getProxyFactory", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_addr", "type": "address" } + ], + "name": "getSafeAddress", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getSafeFactory", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getSafeFactoryImplementation", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "uint256", "name": "salt", "type": "uint256" }, + { "internalType": "address", "name": "maker", "type": "address" }, + { "internalType": "address", "name": "signer", "type": "address" }, + { "internalType": "address", "name": "taker", "type": "address" }, + { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, + { + "internalType": "uint256", + "name": "makerAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "takerAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expiration", + "type": "uint256" + }, + { "internalType": "uint256", "name": "nonce", "type": "uint256" }, + { + "internalType": "uint256", + "name": "feeRateBps", + "type": "uint256" + }, + { "internalType": "enum Side", "name": "side", "type": "uint8" }, + { + "internalType": "enum SignatureType", + "name": "signatureType", + "type": "uint8" + }, + { "internalType": "bytes", "name": "signature", "type": "bytes" } + ], + "internalType": "struct Order", + "name": "order", + "type": "tuple" + } + ], + "name": "hashOrder", + "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "incrementNonce", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "usr", "type": "address" }], + "name": "isAdmin", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "usr", "type": "address" }], + "name": "isOperator", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "usr", "type": "address" }, + { "internalType": "uint256", "name": "nonce", "type": "uint256" } + ], + "name": "isValidNonce", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "uint256", "name": "salt", "type": "uint256" }, + { "internalType": "address", "name": "maker", "type": "address" }, + { "internalType": "address", "name": "signer", "type": "address" }, + { "internalType": "address", "name": "taker", "type": "address" }, + { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, + { + "internalType": "uint256", + "name": "makerAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "takerAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expiration", + "type": "uint256" + }, + { "internalType": "uint256", "name": "nonce", "type": "uint256" }, + { + "internalType": "uint256", + "name": "feeRateBps", + "type": "uint256" + }, + { "internalType": "enum Side", "name": "side", "type": "uint8" }, + { + "internalType": "enum SignatureType", + "name": "signatureType", + "type": "uint8" + }, + { "internalType": "bytes", "name": "signature", "type": "bytes" } + ], + "internalType": "struct Order", + "name": "takerOrder", + "type": "tuple" + }, + { + "components": [ + { "internalType": "uint256", "name": "salt", "type": "uint256" }, + { "internalType": "address", "name": "maker", "type": "address" }, + { "internalType": "address", "name": "signer", "type": "address" }, + { "internalType": "address", "name": "taker", "type": "address" }, + { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, + { + "internalType": "uint256", + "name": "makerAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "takerAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expiration", + "type": "uint256" + }, + { "internalType": "uint256", "name": "nonce", "type": "uint256" }, + { + "internalType": "uint256", + "name": "feeRateBps", + "type": "uint256" + }, + { "internalType": "enum Side", "name": "side", "type": "uint8" }, + { + "internalType": "enum SignatureType", + "name": "signatureType", + "type": "uint8" + }, + { "internalType": "bytes", "name": "signature", "type": "bytes" } + ], + "internalType": "struct Order[]", + "name": "makerOrders", + "type": "tuple[]" + }, + { + "internalType": "uint256", + "name": "takerFillAmount", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "makerFillAmounts", + "type": "uint256[]" + } + ], + "name": "matchOrders", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "nonces", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "", "type": "address" }, + { "internalType": "address", "name": "", "type": "address" }, + { "internalType": "uint256[]", "name": "", "type": "uint256[]" }, + { "internalType": "uint256[]", "name": "", "type": "uint256[]" }, + { "internalType": "bytes", "name": "", "type": "bytes" } + ], + "name": "onERC1155BatchReceived", + "outputs": [{ "internalType": "bytes4", "name": "", "type": "bytes4" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "", "type": "address" }, + { "internalType": "address", "name": "", "type": "address" }, + { "internalType": "uint256", "name": "", "type": "uint256" }, + { "internalType": "uint256", "name": "", "type": "uint256" }, + { "internalType": "bytes", "name": "", "type": "bytes" } + ], + "name": "onERC1155Received", + "outputs": [{ "internalType": "bytes4", "name": "", "type": "bytes4" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "operators", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "name": "orderStatus", + "outputs": [ + { "internalType": "bool", "name": "isFilledOrCancelled", "type": "bool" }, + { "internalType": "uint256", "name": "remaining", "type": "uint256" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "parentCollectionId", + "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pauseTrading", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proxyFactory", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "token", "type": "uint256" }, + { "internalType": "uint256", "name": "complement", "type": "uint256" }, + { "internalType": "bytes32", "name": "conditionId", "type": "bytes32" } + ], + "name": "registerToken", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "name": "registry", + "outputs": [ + { "internalType": "uint256", "name": "complement", "type": "uint256" }, + { "internalType": "bytes32", "name": "conditionId", "type": "bytes32" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "admin", "type": "address" } + ], + "name": "removeAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "operator", "type": "address" } + ], + "name": "removeOperator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceAdminRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOperatorRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "safeFactory", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newProxyFactory", + "type": "address" + } + ], + "name": "setProxyFactory", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newSafeFactory", + "type": "address" + } + ], + "name": "setSafeFactory", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes4", "name": "interfaceId", "type": "bytes4" } + ], + "name": "supportsInterface", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "unpauseTrading", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "token", "type": "uint256" }, + { "internalType": "uint256", "name": "complement", "type": "uint256" } + ], + "name": "validateComplement", + "outputs": [], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "uint256", "name": "salt", "type": "uint256" }, + { "internalType": "address", "name": "maker", "type": "address" }, + { "internalType": "address", "name": "signer", "type": "address" }, + { "internalType": "address", "name": "taker", "type": "address" }, + { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, + { + "internalType": "uint256", + "name": "makerAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "takerAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expiration", + "type": "uint256" + }, + { "internalType": "uint256", "name": "nonce", "type": "uint256" }, + { + "internalType": "uint256", + "name": "feeRateBps", + "type": "uint256" + }, + { "internalType": "enum Side", "name": "side", "type": "uint8" }, + { + "internalType": "enum SignatureType", + "name": "signatureType", + "type": "uint8" + }, + { "internalType": "bytes", "name": "signature", "type": "bytes" } + ], + "internalType": "struct Order", + "name": "order", + "type": "tuple" + } + ], + "name": "validateOrder", + "outputs": [], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes32", "name": "orderHash", "type": "bytes32" }, + { + "components": [ + { "internalType": "uint256", "name": "salt", "type": "uint256" }, + { "internalType": "address", "name": "maker", "type": "address" }, + { "internalType": "address", "name": "signer", "type": "address" }, + { "internalType": "address", "name": "taker", "type": "address" }, + { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, + { + "internalType": "uint256", + "name": "makerAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "takerAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expiration", + "type": "uint256" + }, + { "internalType": "uint256", "name": "nonce", "type": "uint256" }, + { + "internalType": "uint256", + "name": "feeRateBps", + "type": "uint256" + }, + { "internalType": "enum Side", "name": "side", "type": "uint8" }, + { + "internalType": "enum SignatureType", + "name": "signatureType", + "type": "uint8" + }, + { "internalType": "bytes", "name": "signature", "type": "bytes" } + ], + "internalType": "struct Order", + "name": "order", + "type": "tuple" + } + ], + "name": "validateOrderSignature", + "outputs": [], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "tokenId", "type": "uint256" } + ], + "name": "validateTokenId", + "outputs": [], + "stateMutability": "view", + "type": "function" + } +] diff --git a/py_order_utils/abi/PolyLimitOrderProtocol.json b/py_order_utils/abi/PolyLimitOrderProtocol.json deleted file mode 100644 index 57a267c..0000000 --- a/py_order_utils/abi/PolyLimitOrderProtocol.json +++ /dev/null @@ -1,1437 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "maker", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newNonce", - "type": "uint256" - } - ], - "name": "NonceIncreased", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "orderHash", - "type": "bytes32" - }, - { - "indexed": true, - "internalType": "address", - "name": "canceller", - "type": "address" - } - ], - "name": "OrderCancelled", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "orderHash", - "type": "bytes32" - }, - { - "indexed": true, - "internalType": "address", - "name": "maker", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "taker", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "makerAsset", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "makerAssetID", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "takerAsset", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "takerAssetID", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "makerAmountFilled", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "takerAmountFilled", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "remainingAmount", - "type": "uint256" - } - ], - "name": "OrderFilled", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "previousOwner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "OwnershipTransferred", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "oldFactory", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newFactory", - "type": "address" - } - ], - "name": "ProxyFactoryChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "oldFactory", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newFactory", - "type": "address" - } - ], - "name": "SafeFactoryChanged", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "uint8", - "name": "amount", - "type": "uint8" - } - ], - "name": "advanceNonce", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address[]", - "name": "targets", - "type": "address[]" - }, - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "and", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "components": [ - { - "internalType": "uint256", - "name": "salt", - "type": "uint256" - }, - { - "internalType": "address", - "name": "makerAsset", - "type": "address" - }, - { - "internalType": "address", - "name": "takerAsset", - "type": "address" - }, - { - "internalType": "bytes", - "name": "makerAssetData", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "takerAssetData", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "getMakerAmount", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "getTakerAmount", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "predicate", - "type": "bytes" - }, - { - "internalType": "address", - "name": "signer", - "type": "address" - }, - { - "internalType": "uint256", - "name": "sigType", - "type": "uint256" - } - ], - "internalType": "struct Orders.LimitOrder[]", - "name": "orders", - "type": "tuple[]" - }, - { - "internalType": "bytes[]", - "name": "signatures", - "type": "bytes[]" - }, - { - "internalType": "uint256[]", - "name": "makingAmounts", - "type": "uint256[]" - }, - { - "internalType": "uint256[]", - "name": "takingAmounts", - "type": "uint256[]" - }, - { - "internalType": "uint256[]", - "name": "thresholdAmounts", - "type": "uint256[]" - } - ], - "internalType": "struct Orders.LimitOrderFillData", - "name": "fillData", - "type": "tuple" - } - ], - "name": "batchFillOrders", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint256", - "name": "salt", - "type": "uint256" - }, - { - "internalType": "address", - "name": "makerAsset", - "type": "address" - }, - { - "internalType": "address", - "name": "takerAsset", - "type": "address" - }, - { - "internalType": "bytes", - "name": "makerAssetData", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "takerAssetData", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "getMakerAmount", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "getTakerAmount", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "predicate", - "type": "bytes" - }, - { - "internalType": "address", - "name": "signer", - "type": "address" - }, - { - "internalType": "uint256", - "name": "sigType", - "type": "uint256" - } - ], - "internalType": "struct Orders.LimitOrder", - "name": "order", - "type": "tuple" - } - ], - "name": "cancelOrder", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint256", - "name": "salt", - "type": "uint256" - }, - { - "internalType": "address", - "name": "makerAsset", - "type": "address" - }, - { - "internalType": "address", - "name": "takerAsset", - "type": "address" - }, - { - "internalType": "bytes", - "name": "makerAssetData", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "takerAssetData", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "getMakerAmount", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "getTakerAmount", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "predicate", - "type": "bytes" - }, - { - "internalType": "address", - "name": "signer", - "type": "address" - }, - { - "internalType": "uint256", - "name": "sigType", - "type": "uint256" - } - ], - "internalType": "struct Orders.LimitOrder", - "name": "order", - "type": "tuple" - } - ], - "name": "checkPredicate", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "domainSeparator", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "eq", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint256", - "name": "salt", - "type": "uint256" - }, - { - "internalType": "address", - "name": "makerAsset", - "type": "address" - }, - { - "internalType": "address", - "name": "takerAsset", - "type": "address" - }, - { - "internalType": "bytes", - "name": "makerAssetData", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "takerAssetData", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "getMakerAmount", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "getTakerAmount", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "predicate", - "type": "bytes" - }, - { - "internalType": "address", - "name": "signer", - "type": "address" - }, - { - "internalType": "uint256", - "name": "sigType", - "type": "uint256" - } - ], - "internalType": "struct Orders.LimitOrder", - "name": "order", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - }, - { - "internalType": "uint256", - "name": "makingAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "takingAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "thresholdAmount", - "type": "uint256" - } - ], - "name": "fillOrder", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint256", - "name": "salt", - "type": "uint256" - }, - { - "internalType": "address", - "name": "makerAsset", - "type": "address" - }, - { - "internalType": "address", - "name": "takerAsset", - "type": "address" - }, - { - "internalType": "bytes", - "name": "makerAssetData", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "takerAssetData", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "getMakerAmount", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "getTakerAmount", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "predicate", - "type": "bytes" - }, - { - "internalType": "address", - "name": "signer", - "type": "address" - }, - { - "internalType": "uint256", - "name": "sigType", - "type": "uint256" - } - ], - "internalType": "struct Orders.LimitOrder", - "name": "order", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - }, - { - "internalType": "uint256", - "name": "makingAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "takingAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "thresholdAmount", - "type": "uint256" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - } - ], - "name": "fillOrderTo", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - }, - { - "internalType": "contract IERC721", - "name": "token", - "type": "address" - } - ], - "name": "func_20xtkDI", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - }, - { - "internalType": "contract IERC721", - "name": "token", - "type": "address" - } - ], - "name": "func_40aVqeY", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "contract IERC20", - "name": "token", - "type": "address" - } - ], - "name": "func_50BkM4K", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "contract IERC1155", - "name": "token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "func_733NCGU", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "orderMakerAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "orderTakerAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "swapTakerAmount", - "type": "uint256" - } - ], - "name": "getMakerAmount", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "orderMakerAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "orderTakerAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "swapMakerAmount", - "type": "uint256" - } - ], - "name": "getTakerAmount", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "gt", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint256", - "name": "salt", - "type": "uint256" - }, - { - "internalType": "address", - "name": "signer", - "type": "address" - }, - { - "internalType": "address", - "name": "maker", - "type": "address" - }, - { - "internalType": "address", - "name": "makerAsset", - "type": "address" - }, - { - "internalType": "uint256", - "name": "makerAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "makerAssetID", - "type": "uint256" - }, - { - "internalType": "address", - "name": "takerAsset", - "type": "address" - }, - { - "internalType": "uint256", - "name": "takerAssetID", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "sigType", - "type": "uint256" - } - ], - "internalType": "struct Orders.MarketOrder", - "name": "order", - "type": "tuple" - } - ], - "name": "hash", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint256", - "name": "salt", - "type": "uint256" - }, - { - "internalType": "address", - "name": "makerAsset", - "type": "address" - }, - { - "internalType": "address", - "name": "takerAsset", - "type": "address" - }, - { - "internalType": "bytes", - "name": "makerAssetData", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "takerAssetData", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "getMakerAmount", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "getTakerAmount", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "predicate", - "type": "bytes" - }, - { - "internalType": "address", - "name": "signer", - "type": "address" - }, - { - "internalType": "uint256", - "name": "sigType", - "type": "uint256" - } - ], - "internalType": "struct Orders.LimitOrder", - "name": "order", - "type": "tuple" - } - ], - "name": "hash", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "immutableOwner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "increaseNonce", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "lt", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "nonce", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "makerAddress", - "type": "address" - }, - { - "internalType": "uint256", - "name": "makerNonce", - "type": "uint256" - } - ], - "name": "nonceEquals", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address[]", - "name": "targets", - "type": "address[]" - }, - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "or", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proxyFactory", - "outputs": [ - { - "internalType": "contract IProxyWalletFactory", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "orderHash", - "type": "bytes32" - } - ], - "name": "remaining", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "orderHash", - "type": "bytes32" - } - ], - "name": "remainingRaw", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32[]", - "name": "orderHashes", - "type": "bytes32[]" - } - ], - "name": "remainingsRaw", - "outputs": [ - { - "internalType": "uint256[]", - "name": "results", - "type": "uint256[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "safeFactory", - "outputs": [ - { - "internalType": "contract ISafeFactory", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "factoryAddress", - "type": "address" - } - ], - "name": "setProxyWalletFactory", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "factoryAddress", - "type": "address" - } - ], - "name": "setSafeFactory", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "time", - "type": "uint256" - } - ], - "name": "timestampBelow", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint256", - "name": "salt", - "type": "uint256" - }, - { - "internalType": "address", - "name": "makerAsset", - "type": "address" - }, - { - "internalType": "address", - "name": "takerAsset", - "type": "address" - }, - { - "internalType": "bytes", - "name": "makerAssetData", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "takerAssetData", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "getMakerAmount", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "getTakerAmount", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "predicate", - "type": "bytes" - }, - { - "internalType": "address", - "name": "signer", - "type": "address" - }, - { - "internalType": "uint256", - "name": "sigType", - "type": "uint256" - } - ], - "internalType": "struct Orders.LimitOrder", - "name": "order", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "name": "validateLimitOrder", - "outputs": [], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint256", - "name": "salt", - "type": "uint256" - }, - { - "internalType": "address", - "name": "signer", - "type": "address" - }, - { - "internalType": "address", - "name": "maker", - "type": "address" - }, - { - "internalType": "address", - "name": "makerAsset", - "type": "address" - }, - { - "internalType": "uint256", - "name": "makerAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "makerAssetID", - "type": "uint256" - }, - { - "internalType": "address", - "name": "takerAsset", - "type": "address" - }, - { - "internalType": "uint256", - "name": "takerAssetID", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "sigType", - "type": "uint256" - } - ], - "internalType": "struct Orders.MarketOrder", - "name": "order", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "name": "validateMarketOrder", - "outputs": [], - "stateMutability": "view", - "type": "function" - } -] \ No newline at end of file diff --git a/py_order_utils/builders/__init__.py b/py_order_utils/builders/__init__.py index 7cf76f8..dede488 100644 --- a/py_order_utils/builders/__init__.py +++ b/py_order_utils/builders/__init__.py @@ -1,2 +1 @@ -from py_order_utils.builders.limit_order_builder import LimitOrderBuilder -from py_order_utils.builders.market_order_builder import MarketOrderBuilder +from py_order_utils.builders.order_builder import OrderBuilder diff --git a/py_order_utils/builders/base_builder.py b/py_order_utils/builders/base_builder.py index 5cb4565..e9ad6cc 100644 --- a/py_order_utils/builders/base_builder.py +++ b/py_order_utils/builders/base_builder.py @@ -5,19 +5,22 @@ class BaseBuilder: - def __init__(self, exchange_address: str, chain_id: int, signer: Signer): + def __init__( + self, exchange_address: str, chain_id: int, signer: Signer, salt_generator + ): self.contract_address = normalize_address(exchange_address) self.signer = signer self.chain_id = chain_id self.domain_separator = self._get_domain_separator( self.chain_id, self.contract_address ) + self.salt_generator = salt_generator def _get_domain_separator( self, chain_id: int, verifying_contract: str ) -> EIP712Struct: return make_domain( - name="Polymarket Limit Order Protocol", + name="Polymarket CTF Exchange", version="1", chainId=str(chain_id), verifyingContract=verifying_contract, diff --git a/py_order_utils/builders/limit_order_builder.py b/py_order_utils/builders/limit_order_builder.py deleted file mode 100644 index 5ecc8bd..0000000 --- a/py_order_utils/builders/limit_order_builder.py +++ /dev/null @@ -1,124 +0,0 @@ -from ..signer import Signer -from .base_builder import BaseBuilder -from .exception import ValidationException -from ..utils import generate_seed, normalize_address -from ..facades import Erc20Facade, Erc1155Facade, LimitOrderProtocolFacade -from ..model.model import LimitOrder, LimitOrderAndSignature, LimitOrderData - - -class LimitOrderBuilder(BaseBuilder): - """ - Limit order builder - """ - - def __init__(self, exchange_address: str, chain_id: int, signer: Signer): - super().__init__(exchange_address, chain_id, signer) - self.erc20_facade = Erc20Facade() - self.erc1155_facade = Erc1155Facade() - self.lop_facade = LimitOrderProtocolFacade() - - def build_limit_order(self, data: LimitOrderData) -> LimitOrder: - """ - Builds a limit order - """ - if not self._validate_inputs(data): - raise ValidationException("Invalid limit order inputs") - - if data.maker_asset_id is not None: - maker_asset = data.exchange_address - maker_asset_data = self.erc1155_facade.transfer_from( - data.maker_address, - data.taker_address, - data.maker_asset_address, - data.maker_asset_id, - data.maker_amount, - ) - else: - maker_asset = data.maker_asset_address - maker_asset_data = self.erc20_facade.transfer_from( - data.maker_address, data.taker_address, data.maker_amount - ) - - if data.taker_asset_id is not None: - taker_asset = data.exchange_address - taker_asset_data = self.erc1155_facade.transfer_from( - data.taker_address, - data.maker_address, - data.taker_asset_address, - data.taker_asset_id, - data.taker_amount, - ) - else: - taker_asset = data.taker_asset_address - taker_asset_data = self.erc20_facade.transfer_from( - data.taker_address, data.maker_address, data.taker_amount - ) - - predicate = ( - data.predicate - if (data.expiry is None and data.nonce is None) - else self.lop_facade.lop_and( - self.contract_address, - [ - self.lop_facade.timestamp_below(data.expiry), - self.lop_facade.nonce_equals(data.maker_address, data.nonce), - ], - ) - ) - signer = data.signer if data.signer is not None else data.maker_address - - get_maker_amount = self.lop_facade.get_maker_amount_data( - data.maker_amount, data.taker_amount - ) - get_taker_amount = self.lop_facade.get_taker_amount_data( - data.maker_amount, data.taker_amount - ) - - return LimitOrder( - salt=data.salt if data.salt else generate_seed(), - makerAsset=maker_asset, - takerAsset=taker_asset, - makerAssetData=maker_asset_data, - takerAssetData=taker_asset_data, - getMakerAmount=get_maker_amount, - getTakerAmount=get_taker_amount, - predicate=predicate, - signer=signer, - sigType=data.sig_type, - ) - - def build_limit_order_signature(self, limit_order: LimitOrder): - """ - Signs the Limit order - """ - return self.sign(self._create_struct_hash(limit_order)) - - def build_limit_order_and_signature(self, limit_order: LimitOrder, signature: str): - return LimitOrderAndSignature( - order=limit_order, signature=signature, orderType="limit" - ) - - def create_limit_order(self, data: LimitOrderData): - """ - Helper function to build and sign a limit order - """ - order = self.build_limit_order(data) - sig = self.build_limit_order_signature(order) - return LimitOrderAndSignature(order=order, signature=sig, orderType="limit") - - def _validate_inputs(self, data: LimitOrderData) -> bool: - return not ( - # ensure required values exist - data.exchange_address is None - or data.maker_asset_address is None - or data.taker_asset_address is None - or data.maker_address is None - or data.maker_amount is None - or data.taker_amount is None - or - # both maker and taker asset ids cannot be None - (data.maker_asset_id is None and data.taker_asset_id is None) - or - # ensure that the exchange address is the same as the provided contract address - normalize_address(data.exchange_address) != self.contract_address - ) diff --git a/py_order_utils/builders/market_order_builder.py b/py_order_utils/builders/market_order_builder.py deleted file mode 100644 index a97c6c8..0000000 --- a/py_order_utils/builders/market_order_builder.py +++ /dev/null @@ -1,102 +0,0 @@ -from ..signer import Signer -from ..utils import generate_seed, normalize_address -from .base_builder import BaseBuilder -from .exception import ValidationException -from ..model.model import MarketOrder, MarketOrderAndSignature, MarketOrderData - - -class MarketOrderBuilder(BaseBuilder): - def __init__(self, exchange_address: str, chain_id: int, signer: Signer): - super().__init__(exchange_address, chain_id, signer) - - def build_market_order(self, data: MarketOrderData) -> MarketOrder: - """ - Builds a market order - """ - if not self._validate_inputs(data): - raise ValidationException("Invalid market order inputs") - - maker_asset_id = data.maker_asset_id if data.maker_asset_id is not None else -1 - taker_asset_id = data.taker_asset_id if data.taker_asset_id is not None else -1 - - signer = data.signer if data.signer is not None else data.maker_address - - return MarketOrder( - salt=data.salt if data.salt else generate_seed(), - maker=data.maker_address, - makerAsset=data.maker_asset_address, - makerAmount=data.maker_amount, - makerAssetID=maker_asset_id, - takerAsset=data.taker_asset_address, - takerAssetID=taker_asset_id, - signer=signer, - sigType=data.sig_type, - ) - - def build_market_order_signature(self, mkt_order: MarketOrder): - """ - Signs a market order - """ - normalized_mkt_order = self._normalize(mkt_order) - return self.sign(self._create_struct_hash(normalized_mkt_order)) - - def build_market_order_and_signature( - self, - mkt_order: MarketOrder, - signature: str, - minAmountReceived: str = "0", - timeInForce: str = "FOK", - ): - """ - Returns the canonical market order and signature object used across processes - """ - return MarketOrderAndSignature( - mkt_order, - signature, - "market", - minAmountReceived=minAmountReceived, - timeInForce=timeInForce, - ) - - def create_market_order(self, data: MarketOrderData): - """ - Helper function to build and sign a market order - """ - order = self.build_market_order(data) - sig = self.build_market_order_signature(order) - return MarketOrderAndSignature( - order=order, - signature=sig, - orderType="market", - minAmountReceived=data.min_amount_received, - timeInForce=data.time_in_force, - ) - - def _normalize(self, mkt_order: MarketOrder): - return MarketOrder( - salt=mkt_order["salt"], - maker=mkt_order["maker"], - makerAsset=mkt_order["makerAsset"], - makerAmount=mkt_order["makerAmount"], - makerAssetID=mkt_order["makerAssetID"] - if mkt_order["makerAssetID"] >= 0 - else 0, - takerAsset=mkt_order["takerAsset"], - takerAssetID=mkt_order["takerAssetID"] - if mkt_order["takerAssetID"] >= 0 - else 0, - signer=mkt_order["signer"], - sigType=mkt_order["sigType"], - ) - - def _validate_inputs(self, data: MarketOrderData) -> bool: - return not ( - # ensure required values exist - data.exchange_address is None - or data.maker_asset_address is None - or data.taker_asset_address is None - or data.maker_address is None - or data.maker_amount is None - or (data.maker_asset_id is None and data.taker_asset_id is None) - or normalize_address(data.exchange_address) != self.contract_address - ) diff --git a/py_order_utils/builders/order_builder.py b/py_order_utils/builders/order_builder.py new file mode 100644 index 0000000..f090a15 --- /dev/null +++ b/py_order_utils/builders/order_builder.py @@ -0,0 +1,90 @@ +from ..signer import Signer +from .base_builder import BaseBuilder +from .exception import ValidationException +from ..utils import generate_seed, normalize_address +from ..model.order import Order, SignedOrder, OrderData +from ..model.sides import BUY, SELL +from ..model.signatures import EOA, POLY_GNOSIS_SAFE, POLY_PROXY + + +class OrderBuilder(BaseBuilder): + """ + Order builder + """ + + def __init__( + self, + exchange_address: str, + chain_id: int, + signer: Signer, + salt_generator=generate_seed, + ): + super().__init__(exchange_address, chain_id, signer, salt_generator) + + def build_order(self, data: OrderData) -> Order: + """ + Builds an order + """ + if not self._validate_inputs(data): + raise ValidationException("Invalid order inputs") + + if data.signer is None: + data.signer = data.maker + + if data.signer != self.signer.address(): + raise ValidationException("Signer does not match") + + if data.expiration is None: + data.expiration = "0" + + if data.signatureType is None: + data.signatureType = EOA + + return Order( + salt=int(self.salt_generator()), + maker=normalize_address(data.maker), + signer=normalize_address(data.signer), + taker=normalize_address(data.taker), + tokenId=int(data.tokenId), + makerAmount=int(data.makerAmount), + takerAmount=int(data.takerAmount), + expiration=int(data.expiration), + nonce=int(data.nonce), + feeRateBps=int(data.feeRateBps), + side=int(data.side), + signatureType=int(data.signatureType), + ) + + def build_order_signature(self, _order: Order) -> str: + """ + Signs the order + """ + return self.sign(self._create_struct_hash(_order)) + + def build_signed_order(self, data: OrderData) -> SignedOrder: + """ + Helper function to build and sign a order + """ + order = self.build_order(data) + sig = self.build_order_signature(order) + + return SignedOrder(order, sig) + + def _validate_inputs(self, data: OrderData) -> bool: + return not ( + # ensure required values exist + data.maker is None + or data.tokenId is None + or data.makerAmount is None + or data.takerAmount is None + or data.side is None + or data.side not in [BUY, SELL] + or not data.feeRateBps.isnumeric() + or int(data.feeRateBps) < 0 + or not data.nonce.isnumeric() + or int(data.nonce) < 0 + or not data.expiration.isnumeric() + or int(data.expiration) < 0 + or data.signatureType is None + or data.signatureType not in [EOA, POLY_GNOSIS_SAFE, POLY_PROXY] + ) diff --git a/py_order_utils/config.py b/py_order_utils/config.py index 29a7eda..deaa202 100644 --- a/py_order_utils/config.py +++ b/py_order_utils/config.py @@ -20,13 +20,13 @@ def get_conditional(self): CONFIG = { 137: ContractConfig( - exchange="0xA5caFCC00E8D8E9121CC18B2DF279Eab5dE43bC5", + exchange="0x0000000000000000000000000000000000000000", # TODO: Complete me executor="0xb2a29463Df393a4CAef36541544715e6B48b80B7", collateral="0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174", conditional="0x4D97DCd97eC945f40cF65F87097ACe5EA0476045", ), 80001: ContractConfig( - exchange="0xA5caFCC00E8D8E9121CC18B2DF279Eab5dE43bC5", + exchange="0x0000000000000000000000000000000000000000", # TODO: Complete me executor="0xb2a29463Df393a4CAef36541544715e6B48b80B7", collateral="0x2E8DCfE708D44ae2e406a1c02DFE2Fa13012f961", conditional="0x7D8610E9567d2a6C9FBf66a5A13E9Ba8bb120d43", diff --git a/py_order_utils/facades/__init__.py b/py_order_utils/facades/__init__.py deleted file mode 100644 index 6ec2ee9..0000000 --- a/py_order_utils/facades/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from py_order_utils.facades.erc20_facade import Erc20Facade -from py_order_utils.facades.erc1155_facade import Erc1155Facade -from py_order_utils.facades.limit_order_facade import LimitOrderProtocolFacade diff --git a/py_order_utils/facades/base_facade.py b/py_order_utils/facades/base_facade.py deleted file mode 100644 index 71a1818..0000000 --- a/py_order_utils/facades/base_facade.py +++ /dev/null @@ -1,32 +0,0 @@ -import json -import os -from web3 import Web3 - - -class BaseFacade: - def __init__(self, contract_to_abi): - self.contract_to_abi = contract_to_abi if contract_to_abi else {} - self.web3 = Web3() - self.contract = None - - def _get_contract(self, contract_name): - if not self.contract: - self.contract = self.web3.eth.contract( - None, abi=self._get_abi(contract_name) - ) - return self.contract - - def _get_abi(self, contract_name): - abi_file_path = self.contract_to_abi.get(contract_name.lower()) - if not abi_file_path: - raise Exception("Contract ABI for {} not found".format(contract_name)) - - file_path = os.path.join( - os.path.dirname(os.path.abspath(__file__)), - "..", - abi_file_path, - ) - - with open(file_path, "r") as fh: - abi = json.load(fh) - return abi diff --git a/py_order_utils/facades/erc1155_facade.py b/py_order_utils/facades/erc1155_facade.py deleted file mode 100644 index 91a5bee..0000000 --- a/py_order_utils/facades/erc1155_facade.py +++ /dev/null @@ -1,43 +0,0 @@ -import web3 -from .base_facade import BaseFacade -from ..utils import normalize_address - - -class Erc1155Facade(BaseFacade): - """ - Facade for ERC1155 transfers and balance - """ - - ABIS = {"erc1155": "abi/ERC1155ABI.json", "lop": "abi/PolyLimitOrderProtocol.json"} - transferFrom = "func_733NCGU" - balanceOf = "balanceOf" - - def __init__(self): - super().__init__(self.ABIS) - - def transfer_from( - self, from_address, to_address, token_address: str, token_id: str, value: str - ): - """ - Creates transaction data for an ERC1155 transferFrom - """ - - return self._get_contract("lop").encodeABI( - fn_name=self.transferFrom, - args=[ - normalize_address(from_address), - normalize_address(to_address), - value, - normalize_address(token_address), - token_id, - web3.Web3.toBytes(hexstr="0x0"), - ], - ) - - def balance_of(self, address: str, token_id: str): - """ - Creates transaction data for an ERC1155 balanceOf - """ - return self._get_contract("erc1155").encodeABI( - fn_name=self.balanceOf, args=[normalize_address(address), token_id] - ) diff --git a/py_order_utils/facades/erc20_facade.py b/py_order_utils/facades/erc20_facade.py deleted file mode 100644 index 0fc956e..0000000 --- a/py_order_utils/facades/erc20_facade.py +++ /dev/null @@ -1,34 +0,0 @@ -from ..utils import normalize_address -from .base_facade import BaseFacade - - -class Erc20Facade(BaseFacade): - """ - Facade for ERC20 transfers and balance - """ - - ABIS = {"erc20": "abi/ERC20ABI.json"} - - def __init__(self): - super().__init__(self.ABIS) - - def transfer_from(self, from_address, to_address, value: str): - """ - Creates transaction data for an ERC20 transferFrom - """ - return self._get_contract("erc20").encodeABI( - fn_name="transferFrom", - args=[ - normalize_address(from_address), - normalize_address(to_address), - value, - ], - ) - - def balance_of(self, address): - """ - Creates transaction data for an ERC20 balanceOf - """ - return self._get_contract("erc20").encodeABI( - fn_name="balanceOf", args=[normalize_address(address)] - ) diff --git a/py_order_utils/facades/limit_order_facade.py b/py_order_utils/facades/limit_order_facade.py deleted file mode 100644 index 82e8cf1..0000000 --- a/py_order_utils/facades/limit_order_facade.py +++ /dev/null @@ -1,70 +0,0 @@ -from typing import List -from ..utils import normalize_address -from .base_facade import BaseFacade - - -class LimitOrderProtocolFacade(BaseFacade): - """ - Limit Order protocol facade - """ - - ABIS = {"lop": "abi/PolyLimitOrderProtocol.json"} - - def __init__(self): - super().__init__(self.ABIS) - - def lop_and(self, contract_address: str, predicates: List[str]): - """ - function and(address[] calldata targets, bytes[] calldata data) - """ - return self._get_contract("lop").encodeABI( - fn_name="and", - args=[ - [normalize_address(contract_address) for _ in predicates], - predicates, - ], - ) - - def nonce_equals(self, maker_address: str, maker_nonce: int): - """ - function nonceEquals(address makerAddress, uint256 makerNonce) external view returns(bool) - """ - - return self._get_contract("lop").encodeABI( - fn_name="nonceEquals", - args=[ - maker_address, - maker_nonce, - ], - ) - - def timestamp_below(self, timestamp: int): - """ - function timestampBelow(uint256 time) external view returns(bool) - """ - return self._get_contract("lop").encodeABI( - fn_name="timestampBelow", - args=[ - timestamp, - ], - ) - - def get_maker_amount_data(self, maker_amount, taker_amount: int): - """ - function getMakerAmount(uint256 orderMakerAmount, uint256 orderTakerAmount, uint256 swapTakerAmount) external pure returns(uint256) - """ - return self._get_amount_data("getMakerAmount", maker_amount, taker_amount) - - def get_taker_amount_data(self, maker_amount, taker_amount: int): - """ - function getTakerAmount(uint256 orderMakerAmount, uint256 orderTakerAmount, uint256 swapMakerAmount) external pure returns(uint256) - """ - return self._get_amount_data("getTakerAmount", maker_amount, taker_amount) - - def _get_amount_data( - self, method, maker_amount, taker_amount: int, swap_taker_amount=0 - ): - raw_amount_data = self._get_contract("lop").encodeABI( - fn_name=method, args=[maker_amount, taker_amount, swap_taker_amount] - ) - return raw_amount_data[:138] diff --git a/py_order_utils/model/__init__.py b/py_order_utils/model/__init__.py index afa29e1..3e1b0ea 100644 --- a/py_order_utils/model/__init__.py +++ b/py_order_utils/model/__init__.py @@ -1,7 +1,3 @@ -from py_order_utils.model.model import ( - LimitOrder, - LimitOrderData, - MarketOrderData, - MarketOrder, -) -from py_order_utils.model.signatures import EOA, CONTRACT, POLY_PROXY, POLY_GNOSIS_SAFE +from py_order_utils.model.order import OrderData, Order, SignedOrder +from py_order_utils.model.signatures import EOA, POLY_PROXY, POLY_GNOSIS_SAFE +from py_order_utils.model.sides import BUY, SELL diff --git a/py_order_utils/model/model.py b/py_order_utils/model/model.py deleted file mode 100644 index 68c53eb..0000000 --- a/py_order_utils/model/model.py +++ /dev/null @@ -1,152 +0,0 @@ -from dataclasses import dataclass -import json - -from ..constants import ZERO_ADDRESS, ZX -from .signatures import EOA -from eip712_structs import Address, Bytes, EIP712Struct, Uint - - -@dataclass -class LimitOrderData: - """ - Inputs to generate Limit orders - """ - - salt: int = None - exchange_address: str = None - maker_asset_address: str = None - maker_asset_id: str = None - taker_asset_address: str = None - taker_asset_id: str = None - maker_address: str = None - taker_address: str = ZERO_ADDRESS - maker_amount: int = None - taker_amount: int = None - expiry: int = None - nonce: int = None - signer: str = None - sig_type: int = EOA - predicate: str = ZX - - -class LimitOrder(EIP712Struct): - """ - Limit Order - """ - - salt = Uint(256) - makerAsset = Address() - takerAsset = Address() - makerAssetData = Bytes() - takerAssetData = Bytes() - getMakerAmount = Bytes() - getTakerAmount = Bytes() - predicate = Bytes() - signer = Address() - sigType = Uint(256) - - def dict(self): - return { - "salt": self["salt"], - "makerAsset": self["makerAsset"], - "takerAsset": self["takerAsset"], - "makerAssetData": self["makerAssetData"], - "takerAssetData": self["takerAssetData"], - "getMakerAmount": self["getMakerAmount"], - "getTakerAmount": self["getTakerAmount"], - "predicate": self["predicate"], - "signer": self["signer"], - "sigType": self["sigType"], - } - - -@dataclass -class MarketOrderData: - """ - Inputs to generate Market orders - """ - - salt: int = None - exchange_address: str = None - maker_asset_address: str = None - maker_asset_id: int = None - taker_asset_address: str = None - taker_asset_id: int = None - maker_address: str = None - maker_amount: int = None - signer: str = None - sig_type: int = EOA - min_amount_received: int = "0" - time_in_force: str = "FOK" - - -class MarketOrder(EIP712Struct): - """ - Market Order - """ - - # NOTE: Important to keep in mind, fields are ordered - salt = Uint(256) - signer = Address() - maker = Address() - makerAsset = Address() - makerAmount = Uint(256) - makerAssetID = Uint(256) - takerAsset = Address() - takerAssetID = Uint(256) - sigType = Uint(256) - - def dict(self): - return { - "salt": self["salt"], - "signer": self["signer"], - "maker": self["maker"], - "makerAsset": self["makerAsset"], - "makerAmount": str(self["makerAmount"]), - "makerAssetID": str(self["makerAssetID"]), - "takerAsset": self["takerAsset"], - "takerAssetID": str(self["takerAssetID"]), - "sigType": self["sigType"], - } - - -@dataclass -class LimitOrderAndSignature: - """ - Canonical Limit order and signature - """ - - order: LimitOrder - signature: str - orderType: str - - def dict(self): - return { - "order": self.order.dict(), - "signature": self.signature, - "orderType": self.orderType, - } - - -@dataclass -class MarketOrderAndSignature: - """ - Canonical Market order and signature - """ - - order: MarketOrder - signature: str - orderType: str - minAmountReceived: str = "0" - # Optional slippage protection field - timeInForce: str = "FOK" - # Optional market order type: FOK (fill or kill) / IOC (immediate or cancel) - - def dict(self): - return { - "order": self.order.dict(), - "signature": self.signature, - "orderType": self.orderType, - "minAmountReceived": str(self.minAmountReceived), - "timeInForce": self.timeInForce, - } diff --git a/py_order_utils/model/order.py b/py_order_utils/model/order.py new file mode 100644 index 0000000..3b7227f --- /dev/null +++ b/py_order_utils/model/order.py @@ -0,0 +1,171 @@ +from dataclasses import dataclass + +from ..constants import ZERO_ADDRESS +from .signatures import EOA +from eip712_structs import Address, EIP712Struct, Uint + + +@dataclass +class OrderData: + """ + Inputs to generate orders + """ + + maker: str = None + """ + Maker of the order, i.e the source of funds for the order + """ + + taker: str = ZERO_ADDRESS + """ + Address of the order taker. The zero address is used to indicate a public order + """ + + tokenId: str = None + """ + Token Id of the CTF ERC1155 asset to be bought or sold. + If BUY, this is the tokenId of the asset to be bought, i.e the makerAssetId + If SELL, this is the tokenId of the asset to be sold, i.e the takerAssetId + """ + + makerAmount: str = None + """ + Maker amount, i.e the max amount of tokens to be sold + """ + + takerAmount: str = None + """ + Taker amount, i.e the minimum amount of tokens to be received + """ + + side: int = None + """ + The side of the order, BUY or SELL + """ + + feeRateBps: str = None + """ + Fee rate, in basis points, charged to the order maker, charged on proceeds + """ + + nonce: str = "0" + """ + Nonce used for onchain cancellations + """ + + signer: str = None + """ + Signer of the order. Optional, if it is not present the signer is the maker of the order. + """ + + expiration: str = "0" + """ + Timestamp after which the order is expired. + Optional, if it is not present the value is '0' (no expiration) + """ + + signatureType: int = EOA + """ + Signature type used by the Order. Default value 'EOA' + """ + + +class Order(EIP712Struct): + """ + Order + """ + + # NOTE: Important to keep in mind, fields are ordered + + salt = Uint(256) + """ + Unique salt to ensure entropy + """ + + maker = Address() + """ + Maker of the order, i.e the source of funds for the order + """ + + signer = Address() + """ + Signer of the order + """ + + taker = Address() + """ + Address of the order taker. The zero address is used to indicate a public order + """ + + tokenId = Uint(256) + """ + Token Id of the CTF ERC1155 asset to be bought or sold. + If BUY, this is the tokenId of the asset to be bought, i.e the makerAssetId + If SELL, this is the tokenId of the asset to be sold, i.e the takerAssetId + """ + + makerAmount = Uint(256) + """ + Maker amount, i.e the max amount of tokens to be sold + """ + + takerAmount = Uint(256) + """ + Taker amount, i.e the minimum amount of tokens to be received + """ + + expiration = Uint(256) + """ + Timestamp after which the order is expired + """ + + nonce = Uint(256) + """ + Nonce used for onchain cancellations + """ + + feeRateBps = Uint(256) + """ + Fee rate, in basis points, charged to the order maker, charged on proceeds + """ + + side = Uint(8) + """ + The side of the order, BUY or SELL + """ + + signatureType = Uint(8) + """ + Signature type used by the Order + """ + + def dict(self): + return { + "salt": self["salt"], + "maker": self["maker"], + "signer": self["signer"], + "taker": self["taker"], + "tokenId": self["tokenId"], + "makerAmount": self["makerAmount"], + "takerAmount": self["takerAmount"], + "expiration": self["expiration"], + "nonce": self["nonce"], + "feeRateBps": self["feeRateBps"], + "side": self["side"], + "signatureType": self["signatureType"], + } + + +@dataclass +class SignedOrder: + """ + Order + Signature + """ + + order: Order + signature: str + + def dict(self): + d = self.order.dict() + d["signature"] = self.signature + return d diff --git a/py_order_utils/model/sides.py b/py_order_utils/model/sides.py new file mode 100644 index 0000000..f415959 --- /dev/null +++ b/py_order_utils/model/sides.py @@ -0,0 +1,3 @@ +BUY = 0 + +SELL = 1 diff --git a/py_order_utils/model/signatures.py b/py_order_utils/model/signatures.py index a56a89d..7ef224f 100644 --- a/py_order_utils/model/signatures.py +++ b/py_order_utils/model/signatures.py @@ -1,4 +1,8 @@ +# ECDSA EIP712 signatures signed by EOAs EOA = 0 -CONTRACT = 1 -POLY_PROXY = 2 -POLY_GNOSIS_SAFE = 3 + +# EIP712 signatures signed by EOAs that own Polymarket Proxy wallets +POLY_PROXY = 1 + +# EIP712 signatures signed by EOAs that own Polymarket Gnosis safes +POLY_GNOSIS_SAFE = 2 diff --git a/py_order_utils/signer.py b/py_order_utils/signer.py index af49a40..b3e2b52 100644 --- a/py_order_utils/signer.py +++ b/py_order_utils/signer.py @@ -15,3 +15,6 @@ def sign(self, struct_hash) -> str: Signs an EIP712 struct hash """ return Account._sign_hash(struct_hash, self._key).signature.hex() + + def address(self) -> str: + return self.account.address diff --git a/tests/test_facades.py b/tests/test_facades.py deleted file mode 100644 index 477cf50..0000000 --- a/tests/test_facades.py +++ /dev/null @@ -1,102 +0,0 @@ -import web3 -from unittest import TestCase -from py_order_utils.facades import Erc20Facade, Erc1155Facade, LimitOrderProtocolFacade - - -class TestFacade(TestCase): - def setUp(self): - self.erc20_facade = Erc20Facade() - self.erc1155_facade = Erc1155Facade() - self.lop_facade = LimitOrderProtocolFacade() - - def test_erc20_balance_of(self): - address = "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B" - # Expected input data generated using ethers - expected = ( - "0x70a08231000000000000000000000000ab5801a7d398351b8be11c439e05c5b3259aec9b" - ) - - self.assertEqual(expected, self.erc20_facade.balance_of(address)) - - def test_erc20_transfer_from(self): - from_address = "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B" - to_address = "0x1Db3439a222C519ab44bb1144fC28167b4Fa6EE6" - value = web3.Web3.toWei(100, "ether") - # Expected input data generated using ethers - expected = "0x23b872dd000000000000000000000000ab5801a7d398351b8be11c439e05c5b3259aec9b0000000000000000000000001db3439a222c519ab44bb1144fc28167b4fa6ee60000000000000000000000000000000000000000000000056bc75e2d63100000" - - self.assertEqual( - expected, self.erc20_facade.transfer_from(from_address, to_address, value) - ) - - def test_erc1155_balance_of(self): - address = "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B" - token_id = 0 - # Expected input data generated using ethers - expected = "0x00fdd58e000000000000000000000000ab5801a7d398351b8be11c439e05c5b3259aec9b0000000000000000000000000000000000000000000000000000000000000000" - - self.assertEqual(expected, self.erc1155_facade.balance_of(address, token_id)) - - def test_erc1155_transfer_from(self): - from_address = "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B" - to_address = "0x1Db3439a222C519ab44bb1144fC28167b4Fa6EE6" - value = web3.Web3.toWei(100, "ether") - token_address = "0xadbeD21409324e0fcB80AE8b5e662B0C857D85ed" - token_id = 0 - - # Expected input data generated using ethers - expected = "0x23b872e1000000000000000000000000ab5801a7d398351b8be11c439e05c5b3259aec9b0000000000000000000000001db3439a222c519ab44bb1144fc28167b4fa6ee60000000000000000000000000000000000000000000000056bc75e2d63100000000000000000000000000000adbed21409324e0fcb80ae8b5e662b0c857d85ed000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000" - self.assertEqual( - expected, - self.erc1155_facade.transfer_from( - from_address, to_address, token_address, token_id, value - ), - ) - - def test_lop_and(self): - predicates = [ - "0x63592c2b0000000000000000000000000000000000000000000000000000000061f3f65e", - "0xcf6fc6e300000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c80000000000000000000000000000000000000000000000000000000000000000", - ] - - expected = "0x961d5b1e000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cf7ed3acca5a467e9e704c703e8d87f634fb0fc9000000000000000000000000cf7ed3acca5a467e9e704c703e8d87f634fb0fc90000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000002463592c2b0000000000000000000000000000000000000000000000000000000061f3f65e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044cf6fc6e300000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - self.assertEqual( - expected, - self.lop_facade.lop_and( - "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9", predicates - ), - ) - - def test_lop_nonce_equals(self): - maker_address = "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" - maker_nonce = 0 - expected = "0xcf6fc6e300000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c80000000000000000000000000000000000000000000000000000000000000000" - self.assertEqual( - expected, self.lop_facade.nonce_equals(maker_address, maker_nonce) - ) - - def test_lop_ts_below(self): - timestamp = 1643379170 - expected = ( - "0x63592c2b0000000000000000000000000000000000000000000000000000000061f3f9e2" - ) - self.assertEqual(expected, self.lop_facade.timestamp_below(timestamp)) - - def test_lop_get_maker_amount(self): - maker_amount = 1000000 - taker_amount = 500000 - - expected = "0xf4a215c300000000000000000000000000000000000000000000000000000000000f4240000000000000000000000000000000000000000000000000000000000007a120" - - self.assertEqual( - expected, self.lop_facade.get_maker_amount_data(maker_amount, taker_amount) - ) - - def test_lop_get_taker_amount(self): - maker_amount = 1000000 - taker_amount = 500000 - expected = "0x296637bf00000000000000000000000000000000000000000000000000000000000f4240000000000000000000000000000000000000000000000000000000000007a120" - - self.assertEqual( - expected, self.lop_facade.get_taker_amount_data(maker_amount, taker_amount) - ) diff --git a/tests/test_limit_order_builder.py b/tests/test_limit_order_builder.py deleted file mode 100644 index 346bca2..0000000 --- a/tests/test_limit_order_builder.py +++ /dev/null @@ -1,138 +0,0 @@ -from unittest import TestCase, mock -from py_order_utils.builders.exception import ValidationException -from py_order_utils.model.model import LimitOrder, LimitOrderData -from py_order_utils.builders import LimitOrderBuilder -from py_order_utils.model.signatures import EOA - - -class TestLimitOrderBuilder(TestCase): - def test_validate_order(self): - lop_builder = LimitOrderBuilder( - "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9", 1, mock.MagicMock() - ) - - data = self.generate_data() - - # Valid order - self.assertTrue(lop_builder._validate_inputs(data)) - - # Invalid if any of the required fields are missing - data = self.generate_data() - data.exchange_address = None - self.assertFalse(lop_builder._validate_inputs(data)) - - # Invalid if the exchange address on the data object is different from the provided contract address - data = self.generate_data() - data.exchange_address = "0x0000000000000000000000000000000000000000" - self.assertFalse(lop_builder._validate_inputs(data)) - - # Invalid if both maker_asset_id and taker_asset_id are None - data = self.generate_data() - data.maker_asset_id = None - data.taker_asset_id = None - self.assertFalse(lop_builder._validate_inputs(data)) - - def test_build_limit_order(self): - lop_builder = LimitOrderBuilder( - "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9", 1, mock.MagicMock() - ) - - invalid_data_input = self.generate_data() - invalid_data_input.exchange_address = ( - "0x0000000000000000000000000000000000000000" - ) - - # throw if invalid limit order input - with self.assertRaises(ValidationException): - lop_builder.build_limit_order(invalid_data_input) - - limit_order = lop_builder.build_limit_order(self.generate_data()) - - # Ensure correct values on limit order - self.assertTrue(isinstance(limit_order["salt"], int)) - - self.assertEqual( - "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", limit_order["makerAsset"] - ) - self.assertEqual( - "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9", limit_order["takerAsset"] - ) - - self.assertEqual( - "0x23b872dd00000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f4240", - limit_order["makerAssetData"], - ) - - self.assertEqual( - "0x23b872e1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8000000000000000000000000000000000000000000000000000000000007a1200000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa3000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000", - limit_order["takerAssetData"], - ) - - self.assertEqual( - "0xf4a215c300000000000000000000000000000000000000000000000000000000000f4240000000000000000000000000000000000000000000000000000000000007a120", - limit_order["getMakerAmount"], - ) - - self.assertEqual( - "0x296637bf00000000000000000000000000000000000000000000000000000000000f4240000000000000000000000000000000000000000000000000000000000007a120", - limit_order["getTakerAmount"], - ) - - self.assertEqual( - "0x961d5b1e000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cf7ed3acca5a467e9e704c703e8d87f634fb0fc9000000000000000000000000cf7ed3acca5a467e9e704c703e8d87f634fb0fc90000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000002463592c2b0000000000000000000000000000000000000000000000000000000061f5119f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044cf6fc6e300000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - limit_order["predicate"], - ) - - self.assertEqual( - "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", limit_order["signer"] - ) - - self.assertEqual(EOA, limit_order["sigType"]) - - def test_build_signature(self): - signer = mock.MagicMock() - expected_signature = "0xba171a61c9c0bc4453d29d9ab9e3699fd0be7eef8ab6fba1b2c6555ced42f79d7bb5a07f975b1bfaf7bccf7b8e89e1877ba717090a4e9934136f6e6743a7146b1b" - - # Instead of using a private key, unit tests mock the expected signature response - signer.sign.return_value = expected_signature - builder = LimitOrderBuilder( - "0x0165878A594ca255338adfa4d48449f69242Eb8F", 31337, signer - ) - - order = LimitOrder( - salt=1568294891220, - makerAsset="0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", - takerAsset="0x0165878A594ca255338adfa4d48449f69242Eb8F", - makerAssetData="0x23b872dd00000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f4240", - takerAssetData="0x23b872e1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8000000000000000000000000000000000000000000000000000000000007a1200000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa3000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000", - getMakerAmount="0xf4a215c300000000000000000000000000000000000000000000000000000000000f4240000000000000000000000000000000000000000000000000000000000007a120", - getTakerAmount="0x296637bf00000000000000000000000000000000000000000000000000000000000f4240000000000000000000000000000000000000000000000000000000000007a120", - predicate="0x961d5b1e000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000165878a594ca255338adfa4d48449f69242eb8f0000000000000000000000000165878a594ca255338adfa4d48449f69242eb8f0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000002463592c2b00000000000000000000000000000000000000000000000000000000628e1424000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044cf6fc6e300000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - signer="0x70997970C51812dc3A010C7d01b50e0d17dc79C8", - sigType=0, - ) - - # Ensure struct hash is expected(generated via ethers) - expected_struct_hash = ( - "0xfd94c8eb9dbfabc41329eda323fb9ad4d69eda4f27c1be41cc53c902fb749a4b" - ) - struct_hash = builder._create_struct_hash(order) - self.assertEqual(expected_struct_hash, struct_hash.hex()) - - sig = builder.build_limit_order_signature(order) - self.assertEqual(expected_signature, sig) - - def generate_data(self) -> LimitOrderData: - return LimitOrderData( - salt=990606491137, - exchange_address="0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9", - maker_asset_address="0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", - taker_asset_address="0x5FbDB2315678afecb367f032d93F642f64180aa3", - taker_asset_id=1, - maker_address="0x70997970C51812dc3A010C7d01b50e0d17dc79C8", - taker_address="0x0000000000000000000000000000000000000000", - maker_amount=1000000, - taker_amount=500000, - expiry=1643450783, - nonce=0, - ) diff --git a/tests/test_market_order_builder.py b/tests/test_market_order_builder.py deleted file mode 100644 index 2c0f5a9..0000000 --- a/tests/test_market_order_builder.py +++ /dev/null @@ -1,106 +0,0 @@ -from unittest import TestCase, mock -from py_order_utils.model.model import MarketOrder, MarketOrderData -from py_order_utils.builders import MarketOrderBuilder -from py_order_utils.model.signatures import EOA -from py_order_utils.signer import Signer - - -class TestMarketOrderBuilder(TestCase): - def test_validate_inputs(self): - builder = MarketOrderBuilder( - "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9", 31337, mock.MagicMock() - ) - - data = self.generate_data() - - # Valid order - self.assertTrue(builder._validate_inputs(data)) - - # Invalid if any of the required fields are missing - data = self.generate_data() - data.exchange_address = None - self.assertFalse(builder._validate_inputs(data)) - - # Invalid if the exchange address on the data object is different from the provided contract address - data = self.generate_data() - data.exchange_address = "0x0000000000000000000000000000000000000000" - self.assertFalse(builder._validate_inputs(data)) - - # Invalid if both maker_asset_id and taker_asset_id are None - data = self.generate_data() - data.maker_asset_id = None - data.taker_asset_id = None - self.assertFalse(builder._validate_inputs(data)) - - def test_build_market_order(self): - builder = MarketOrderBuilder( - "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9", 31337, mock.MagicMock() - ) - mkt_order = builder.build_market_order(self.generate_data()) - - # Ensure correct values - self.assertTrue(isinstance(mkt_order["salt"], int)) - - self.assertEqual( - "0xe3d9BFA896aF6988f80027bfd13440A42C5ed02b", mkt_order["maker"] - ) - self.assertEqual( - "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", mkt_order["makerAsset"] - ) - self.assertEqual(1000000, mkt_order["makerAmount"]) - self.assertEqual(0, mkt_order["makerAssetID"]) - - self.assertEqual( - "0x5FbDB2315678afecb367f032d93F642f64180aa3", mkt_order["takerAsset"] - ) - self.assertEqual(1, mkt_order["takerAssetID"]) - - self.assertEqual( - "0xe3d9BFA896aF6988f80027bfd13440A42C5ed02b", mkt_order["signer"] - ) - self.assertEqual(EOA, mkt_order["sigType"]) - - def test_build_market_order_signature(self): - mkt_order_data = MarketOrderData( - exchange_address="0x0165878A594ca255338adfa4d48449f69242Eb8F", - salt=1028957131466, - signer="0x70997970C51812dc3A010C7d01b50e0d17dc79C8", - maker_address="0x70997970C51812dc3A010C7d01b50e0d17dc79C8", - maker_asset_address="0x5FbDB2315678afecb367f032d93F642f64180aa3", - maker_amount=150000000, - maker_asset_id=0, - taker_asset_address="0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", - taker_asset_id=0, - sig_type=0, - ) - - expected_sig = "0x62a1b1b3634d5ba8eca890fd7954247c7dbe1a50211bdff31753b3687bb6d0311f3df23e52401f73be7f2cd407902696479af8d324fdc9836769993786b710d41c" - signer = mock.MagicMock() - signer.sign.return_value = expected_sig - - builder = MarketOrderBuilder( - "0x0165878A594ca255338adfa4d48449f69242Eb8F", 31337, signer - ) - expected_struct_hash = ( - "0x6b5da848321b92bc4c7d045289484063e6e31aa3197bd2ccecad302f6b043b47" - ) - - mkt_order = builder.build_market_order(mkt_order_data) - self.assertEqual( - expected_struct_hash, builder._create_struct_hash(mkt_order).hex() - ) - - signature = builder.build_market_order_signature(mkt_order) - self.assertEqual(expected_sig, signature) - - def generate_data(self): - return MarketOrderData( - salt=284374147907, - exchange_address="0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9", - maker_asset_address="0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", - maker_address="0xe3d9BFA896aF6988f80027bfd13440A42C5ed02b", - maker_asset_id=0, - maker_amount=1000000, - taker_asset_address="0x5FbDB2315678afecb367f032d93F642f64180aa3", - taker_asset_id=1, - ) diff --git a/tests/test_order_builder.py b/tests/test_order_builder.py new file mode 100644 index 0000000..e46bd57 --- /dev/null +++ b/tests/test_order_builder.py @@ -0,0 +1,149 @@ +from unittest import TestCase +from py_order_utils.builders.exception import ValidationException +from py_order_utils.model.order import OrderData +from py_order_utils.model.sides import BUY +from py_order_utils.builders import OrderBuilder +from py_order_utils.model.signatures import EOA +from py_order_utils.signer import Signer +from py_order_utils.constants import ZERO_ADDRESS + +# publicly known private key +private_key = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" +signer = Signer(key=private_key) +maker_address = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" +salt = 479249096354 +chain_id = 80001 + + +def mock_salt_generator(): + return salt + + +class TestOrderBuilder(TestCase): + def test_validate_order(self): + builder = OrderBuilder(ZERO_ADDRESS, chain_id, signer) + + # Valid order + data = self.generate_data() + self.assertTrue(builder._validate_inputs(data)) + + # Invalid if any of the required fields are missing + data = self.generate_data() + data.maker = None + self.assertFalse(builder._validate_inputs(data)) + + # Invalid if any of the required fields are invalid + data = self.generate_data() + data.nonce = "-1" + self.assertFalse(builder._validate_inputs(data)) + + data = self.generate_data() + data.expiration = "not a number" + self.assertFalse(builder._validate_inputs(data)) + + # Invalid signature type + data = self.generate_data() + data.signatureType = 100 + self.assertFalse(builder._validate_inputs(data)) + + def test_build_order(self): + builder = OrderBuilder(ZERO_ADDRESS, chain_id, signer) + + invalid_data_input = self.generate_data() + invalid_data_input.tokenId = None + + # throw if invalid order input + with self.assertRaises(ValidationException): + builder.build_order(invalid_data_input) + + invalid_data_input = self.generate_data() + invalid_data_input.signer = ZERO_ADDRESS + + # throw if invalid signer + with self.assertRaises(ValidationException): + builder.build_order(invalid_data_input) + + _order = builder.build_order(self.generate_data()) + + # Ensure correct values on order + self.assertTrue(isinstance(_order["salt"], int)) + self.assertEqual(maker_address, _order["maker"]) + self.assertEqual(maker_address, _order["signer"]) + self.assertEqual(ZERO_ADDRESS, _order["taker"]) + self.assertEqual(1234, _order["tokenId"]) + self.assertEqual(100000000, _order["makerAmount"]) + self.assertEqual(50000000, _order["takerAmount"]) + self.assertEqual(0, _order["expiration"]) + self.assertEqual(0, _order["nonce"]) + self.assertEqual(100, _order["feeRateBps"]) + self.assertEqual(BUY, _order["side"]) + self.assertEqual(EOA, _order["signatureType"]) + + # specific salt + builder = OrderBuilder(ZERO_ADDRESS, chain_id, signer, mock_salt_generator) + + _order = builder.build_order(self.generate_data()) + + # Ensure correct values on order + self.assertTrue(isinstance(_order["salt"], int)) + self.assertEqual(salt, _order["salt"]) + self.assertEqual(maker_address, _order["maker"]) + self.assertEqual(maker_address, _order["signer"]) + self.assertEqual(ZERO_ADDRESS, _order["taker"]) + self.assertEqual(1234, _order["tokenId"]) + self.assertEqual(100000000, _order["makerAmount"]) + self.assertEqual(50000000, _order["takerAmount"]) + self.assertEqual(0, _order["expiration"]) + self.assertEqual(0, _order["nonce"]) + self.assertEqual(100, _order["feeRateBps"]) + self.assertEqual(BUY, _order["side"]) + self.assertEqual(EOA, _order["signatureType"]) + + def test_build_signature(self): + builder = OrderBuilder(ZERO_ADDRESS, chain_id, signer, mock_salt_generator) + + _order = builder.build_order(self.generate_data()) + + # Ensure struct hash is expected(generated via ethers) + expected_struct_hash = ( + "0xcb61637e35c2870e125d337ec8d555d5b45d6691eee473e974aab9c5f875927b" + ) + struct_hash = builder._create_struct_hash(_order) + self.assertEqual(expected_struct_hash, struct_hash.hex()) + + expected_signature = "0xb233b07b1730105d9569f4358aeddc61039b2b91da8bf96fb4c6d1efdf701fb679262b801d28b3262b24630931edc434b3bdae918d98b7dab2be5a3c904f63b41c" + sig = builder.build_order_signature(_order) + self.assertEqual(expected_signature, sig) + + def test_build_signed_order(self): + builder = OrderBuilder(ZERO_ADDRESS, chain_id, signer, mock_salt_generator) + + signed_order = builder.build_signed_order(self.generate_data()) + + expected_signature = "0xb233b07b1730105d9569f4358aeddc61039b2b91da8bf96fb4c6d1efdf701fb679262b801d28b3262b24630931edc434b3bdae918d98b7dab2be5a3c904f63b41c" + self.assertEqual(expected_signature, signed_order.signature) + self.assertTrue(isinstance(signed_order.order["salt"], int)) + self.assertEqual(salt, signed_order.order["salt"]) + self.assertEqual(maker_address, signed_order.order["maker"]) + self.assertEqual(maker_address, signed_order.order["signer"]) + self.assertEqual(ZERO_ADDRESS, signed_order.order["taker"]) + self.assertEqual(1234, signed_order.order["tokenId"]) + self.assertEqual(100000000, signed_order.order["makerAmount"]) + self.assertEqual(50000000, signed_order.order["takerAmount"]) + self.assertEqual(0, signed_order.order["expiration"]) + self.assertEqual(0, signed_order.order["nonce"]) + self.assertEqual(100, signed_order.order["feeRateBps"]) + self.assertEqual(BUY, signed_order.order["side"]) + self.assertEqual(EOA, signed_order.order["signatureType"]) + + def generate_data(self) -> OrderData: + return OrderData( + maker=maker_address, + taker=ZERO_ADDRESS, + tokenId="1234", + makerAmount="100000000", + takerAmount="50000000", + side=BUY, + feeRateBps="100", + nonce="0", + ) From 0cde80fd886c8fe48432ee4cf040a8f1447cd382 Mon Sep 17 00:00:00 2001 From: Rodrigo <95635797+poly-rodr@users.noreply.github.com> Date: Wed, 21 Sep 2022 20:20:52 -0300 Subject: [PATCH 3/5] updating mumbai contract address --- py_order_utils/config.py | 31 +++++++++++++++---------------- tests/test_order_builder.py | 26 +++++++++++++++++--------- 2 files changed, 32 insertions(+), 25 deletions(-) diff --git a/py_order_utils/config.py b/py_order_utils/config.py index deaa202..97926b6 100644 --- a/py_order_utils/config.py +++ b/py_order_utils/config.py @@ -18,26 +18,25 @@ def get_conditional(self): return self.conditional -CONFIG = { - 137: ContractConfig( - exchange="0x0000000000000000000000000000000000000000", # TODO: Complete me - executor="0xb2a29463Df393a4CAef36541544715e6B48b80B7", - collateral="0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174", - conditional="0x4D97DCd97eC945f40cF65F87097ACe5EA0476045", - ), - 80001: ContractConfig( - exchange="0x0000000000000000000000000000000000000000", # TODO: Complete me - executor="0xb2a29463Df393a4CAef36541544715e6B48b80B7", - collateral="0x2E8DCfE708D44ae2e406a1c02DFE2Fa13012f961", - conditional="0x7D8610E9567d2a6C9FBf66a5A13E9Ba8bb120d43", - ), -} - - def get_contract_config(chainID: int) -> ContractConfig: """ Get the contract configuration for the chain """ + CONFIG = { + 137: ContractConfig( + exchange="0x0000000000000000000000000000000000000000", # TODO: Complete me + executor="0xb2a29463Df393a4CAef36541544715e6B48b80B7", + collateral="0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174", + conditional="0x4D97DCd97eC945f40cF65F87097ACe5EA0476045", + ), + 80001: ContractConfig( + exchange="0xdFE02Eb6733538f8Ea35D585af8DE5958AD99E40", + executor="0xb2a29463Df393a4CAef36541544715e6B48b80B7", + collateral="0x2E8DCfE708D44ae2e406a1c02DFE2Fa13012f961", + conditional="0x7D8610E9567d2a6C9FBf66a5A13E9Ba8bb120d43", + ), + } + config = CONFIG.get(chainID) if config is None: raise Exception("Invalid chainID: ${}".format(chainID)) diff --git a/tests/test_order_builder.py b/tests/test_order_builder.py index e46bd57..b262149 100644 --- a/tests/test_order_builder.py +++ b/tests/test_order_builder.py @@ -5,6 +5,7 @@ from py_order_utils.builders import OrderBuilder from py_order_utils.model.signatures import EOA from py_order_utils.signer import Signer +from py_order_utils.config import get_contract_config from py_order_utils.constants import ZERO_ADDRESS # publicly known private key @@ -13,6 +14,7 @@ maker_address = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" salt = 479249096354 chain_id = 80001 +mumbai_contracts = get_contract_config(chain_id) def mock_salt_generator(): @@ -21,7 +23,7 @@ def mock_salt_generator(): class TestOrderBuilder(TestCase): def test_validate_order(self): - builder = OrderBuilder(ZERO_ADDRESS, chain_id, signer) + builder = OrderBuilder(mumbai_contracts.exchange, chain_id, signer) # Valid order data = self.generate_data() @@ -47,7 +49,7 @@ def test_validate_order(self): self.assertFalse(builder._validate_inputs(data)) def test_build_order(self): - builder = OrderBuilder(ZERO_ADDRESS, chain_id, signer) + builder = OrderBuilder(mumbai_contracts.exchange, chain_id, signer) invalid_data_input = self.generate_data() invalid_data_input.tokenId = None @@ -80,7 +82,9 @@ def test_build_order(self): self.assertEqual(EOA, _order["signatureType"]) # specific salt - builder = OrderBuilder(ZERO_ADDRESS, chain_id, signer, mock_salt_generator) + builder = OrderBuilder( + mumbai_contracts.exchange, chain_id, signer, mock_salt_generator + ) _order = builder.build_order(self.generate_data()) @@ -99,28 +103,32 @@ def test_build_order(self): self.assertEqual(BUY, _order["side"]) self.assertEqual(EOA, _order["signatureType"]) - def test_build_signature(self): - builder = OrderBuilder(ZERO_ADDRESS, chain_id, signer, mock_salt_generator) + def test_build_prder_signature(self): + builder = OrderBuilder( + mumbai_contracts.exchange, chain_id, signer, mock_salt_generator + ) _order = builder.build_order(self.generate_data()) # Ensure struct hash is expected(generated via ethers) expected_struct_hash = ( - "0xcb61637e35c2870e125d337ec8d555d5b45d6691eee473e974aab9c5f875927b" + "0xffe5ee610bb27006448785a9af0b8b24c729632cc9ed78a5d571cf053cd2eba3" ) struct_hash = builder._create_struct_hash(_order) self.assertEqual(expected_struct_hash, struct_hash.hex()) - expected_signature = "0xb233b07b1730105d9569f4358aeddc61039b2b91da8bf96fb4c6d1efdf701fb679262b801d28b3262b24630931edc434b3bdae918d98b7dab2be5a3c904f63b41c" + expected_signature = "0x8388a5ebe31745a3225612cece129a494122f924e60691c9893901d10e996a01372f1dbde25952cb07719af209bf6b96592c513239aac82ec775846e4b09ee191c" sig = builder.build_order_signature(_order) self.assertEqual(expected_signature, sig) def test_build_signed_order(self): - builder = OrderBuilder(ZERO_ADDRESS, chain_id, signer, mock_salt_generator) + builder = OrderBuilder( + mumbai_contracts.exchange, chain_id, signer, mock_salt_generator + ) signed_order = builder.build_signed_order(self.generate_data()) - expected_signature = "0xb233b07b1730105d9569f4358aeddc61039b2b91da8bf96fb4c6d1efdf701fb679262b801d28b3262b24630931edc434b3bdae918d98b7dab2be5a3c904f63b41c" + expected_signature = "0x8388a5ebe31745a3225612cece129a494122f924e60691c9893901d10e996a01372f1dbde25952cb07719af209bf6b96592c513239aac82ec775846e4b09ee191c" self.assertEqual(expected_signature, signed_order.signature) self.assertTrue(isinstance(signed_order.order["salt"], int)) self.assertEqual(salt, signed_order.order["salt"]) From f5c751d9bc5f85a4ce8b575ec03655919469c493 Mon Sep 17 00:00:00 2001 From: Rodrigo <95635797+poly-rodr@users.noreply.github.com> Date: Fri, 23 Sep 2022 11:20:39 -0300 Subject: [PATCH 4/5] update setup --- setup.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 95f3758..ab3840e 100644 --- a/setup.py +++ b/setup.py @@ -6,8 +6,10 @@ setuptools.setup( name="py_order_utils", version="0.1.0", - author="Jonathan Amenechi", - author_email="jonathanamenechi@gmail.com", + author="Polymarket Engineering", + author_email="engineering@polymarket.com", + maintainer="Polymarket Engineering" + maintainer_email="engineering@polymarket.com" description="Python utilities used to generate and sign orders from Polymarket's Exchange", long_description=long_description, long_description_content_type="text/markdown", From f766c72b70d6f32fa4d71083680ee0c03e31d0be Mon Sep 17 00:00:00 2001 From: Rodrigo <95635797+poly-rodr@users.noreply.github.com> Date: Fri, 23 Sep 2022 11:25:43 -0300 Subject: [PATCH 5/5] setup fix --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index ab3840e..6def7fe 100644 --- a/setup.py +++ b/setup.py @@ -8,8 +8,8 @@ version="0.1.0", author="Polymarket Engineering", author_email="engineering@polymarket.com", - maintainer="Polymarket Engineering" - maintainer_email="engineering@polymarket.com" + maintainer="Polymarket Engineering", + maintainer_email="engineering@polymarket.com", description="Python utilities used to generate and sign orders from Polymarket's Exchange", long_description=long_description, long_description_content_type="text/markdown",