Repository: Polymarket/py-clob-client Branch: main Commit: cc1740c11adf Files: 110 Total size: 365.5 KB Directory structure: gitextract_cz0xsyu3/ ├── .editorconfig ├── .github/ │ ├── CODEOWNERS │ ├── CODE_OF_CONDUCT.md │ ├── CONTRIBUTING.md │ ├── ISSUE_TEMPLATE.md │ ├── PULL_REQUEST_TEMPLATE.md │ └── workflows/ │ ├── release.yaml │ └── workflow.yaml ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── Makefile ├── README.md ├── SECURITY.md ├── examples/ │ ├── GTD_order.py │ ├── are_orders_scoring.py │ ├── cancel_all.py │ ├── cancel_market_orders.py │ ├── cancel_order.py │ ├── cancel_orders.py │ ├── create_api_key.py │ ├── create_readonly_api_key.py │ ├── delete_readonly_api_key.py │ ├── derive_api_key.py │ ├── drop_notifications.py │ ├── get_api_keys.py │ ├── get_balance_allowance.py │ ├── get_builder_trades.py │ ├── get_closed_only_mode.py │ ├── get_last_trade_price.py │ ├── get_last_trades_prices.py │ ├── get_market_trades_events.py │ ├── get_markets.py │ ├── get_mid_market_price.py │ ├── get_mid_markets_prices.py │ ├── get_notifications.py │ ├── get_ok.py │ ├── get_open_orders_with_readonly_key.py │ ├── get_order.py │ ├── get_orderbook.py │ ├── get_orderbooks.py │ ├── get_orders.py │ ├── get_price.py │ ├── get_prices.py │ ├── get_readonly_api_keys.py │ ├── get_server_time.py │ ├── get_spread.py │ ├── get_spreads.py │ ├── get_trades.py │ ├── is_order_scoring.py │ ├── market_buy_order.py │ ├── market_sell_order.py │ ├── order.py │ ├── orders.py │ ├── place_builder_order.py │ ├── post_heartbeat.py │ ├── post_only_order.py │ ├── rfq_accept_quote.py │ ├── rfq_approve_order.py │ ├── rfq_cancel_quote.py │ ├── rfq_cancel_request.py │ ├── rfq_config.py │ ├── rfq_create_quote.py │ ├── rfq_create_request.py │ ├── rfq_full_flow.py │ ├── rfq_get_best_quote.py │ ├── rfq_get_quotes.py │ ├── rfq_get_requests.py │ └── update_balance_allowance.py ├── py_clob_client/ │ ├── __init__.py │ ├── client.py │ ├── clob_types.py │ ├── config.py │ ├── constants.py │ ├── endpoints.py │ ├── exceptions.py │ ├── headers/ │ │ ├── __init__.py │ │ └── headers.py │ ├── http_helpers/ │ │ ├── __init__.py │ │ └── helpers.py │ ├── order_builder/ │ │ ├── __init__.py │ │ ├── builder.py │ │ ├── constants.py │ │ └── helpers.py │ ├── rfq/ │ │ ├── __init__.py │ │ ├── rfq_client.py │ │ ├── rfq_helpers.py │ │ └── rfq_types.py │ ├── signer.py │ ├── signing/ │ │ ├── __init__.py │ │ ├── eip712.py │ │ ├── hmac.py │ │ └── model.py │ └── utilities.py ├── requirements.txt ├── setup.py └── tests/ ├── __init__.py ├── headers/ │ ├── __init__.py │ └── test_headers.py ├── http_helpers/ │ ├── __init__.py │ └── test_helpers.py ├── order_builder/ │ ├── __init__.py │ ├── test_builder.py │ └── test_helpers.py ├── rfq/ │ ├── test_rfq_payload.py │ └── test_rfq_query_params.py ├── signing/ │ ├── __init__.py │ ├── test_eip712.py │ └── test_hmac.py └── test_utilities.py ================================================ FILE CONTENTS ================================================ ================================================ FILE: .editorconfig ================================================ 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 ================================================ FILE: .github/CODEOWNERS ================================================ # All PRs on any file must be reviewed by one of the following team members # Wildcard (*) for all files * @Polymarket/eng-platform ================================================ FILE: .github/CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socioeconomic status, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: - Using welcoming and inclusive language - Being respectful of differing viewpoints and experiences - Gracefully accepting constructive criticism - Focusing on what is best for the community - Showing empathy towards other community members Examples of unacceptable behavior by participants include: - The use of sexualized language or imagery and unwelcome sexual attention or advances - Trolling, insulting/derogatory comments, and personal or political attacks - Public or private harassment - Publishing others' private information, such as a physical or electronic address, without explicit permission - Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies within all project spaces, and it also applies when an individual is representing the project or its community in public spaces. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at [`liam@polymarket.com`](mailto:liam@polymarket.com). All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html [homepage]: https://www.contributor-covenant.org For answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq ================================================ FILE: .github/CONTRIBUTING.md ================================================ ## python-order-utils Monorepo Contribution Guide All contributions to the python-order-utils are welcome and greatly appreciated! This document serves to outline the process for contributions and help you get set up. ### Steps to get started 1. Fork 'Polymarket/python-order-utils' 2. Clone your fork 3. Follow the [installation instructions](./README.md) in the monorepo's top level README. 4. Open pull requests with the `[WIP]` flag against the `main` branch and include a description of the intended change in the PR description. Before removing the `[WIP]` tag and submitting a PR for review, make sure that: - it passes our linter checks - the test suite passes for all packages - it passes our continuous integration tests - your fork is up to date with `main` ### Branch structure & naming Our main branch, `main`, represents the current development state of the codebase. All pull requests should be opened against `main`. Name your branch with the format `{fix | feat | refactor | chore }/{ description }` - A `fix` addresses a bug or other issue - A `feat` adds new functionality/interface surface area - A `refactor` changes no business logic or interfaces, but improves implementation - A `chore` addresses minor improvements or configuration changes ================================================ FILE: .github/ISSUE_TEMPLATE.md ================================================ ## Overview ## Description ## Notes ## Action items - [ ] Tag issue (bug, enhancement, feature, etc.) - [ ] Initial discussion/assign team member - [ ] Move discussion to PR if necessary and when ready ================================================ FILE: .github/PULL_REQUEST_TEMPLATE.md ================================================ ## Overview ## Description ## Testing instructions ## Types of changes - [ ] Refactor/enhancement - [ ] Bug fix/behavior correction - [ ] New feature - [ ] Breaking change - [ ] Other, additional ## Notes ## Status - [ ] Prefix PR title with `[WIP]` if necessary (changes not yet made). - [ ] Add tests to cover changes as needed. - [ ] Update documentation/changelog as needed. - [ ] Verify all tests run correctly in CI and pass. - [ ] Ready for review/merge. ================================================ FILE: .github/workflows/release.yaml ================================================ name: Release on: release: types: [published] permissions: id-token: write jobs: release: name: release runs-on: ubuntu-latest steps: - name: Checkout Code uses: actions/checkout@v6 with: persist-credentials: false - uses: actions/setup-python@v5 with: python-version: 3.9 - run: | python -m pip install --upgrade pip pip install -r requirements.txt pip install -e . - name: Run Tests run: make test # If your build system reads version dynamically, set it here. # Common pattern: setuptools-scm or hatch-vcs will pick up the git tag automatically. - name: Install build tooling run: | pip install build - name: Build sdist and wheel env: # Many tools will respect this if you wire it up (optional) PACKAGE_VERSION: ${{ github.ref_name }} run: python -m build - name: Publish to PyPI uses: pypa/gh-action-pypi-publish@release/v1 ================================================ FILE: .github/workflows/workflow.yaml ================================================ name: Test on: push: branches: [main] pull_request: permissions: contents: read pull-requests: read jobs: build-lint-test: name: Test runs-on: ubuntu-latest steps: - name: Checkout Code uses: actions/checkout@v6 with: persist-credentials: false - uses: actions/setup-python@v5 with: python-version: 3.9 - run: | python -m pip install --upgrade pip pip install -r requirements.txt pip install -e . - name: Run Tests run: make test ================================================ FILE: .gitignore ================================================ .idea/ # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ pip-wheel-metadata/ share/python-wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .nox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover *.py,cover .hypothesis/ .pytest_cache/ # Translations *.mo *.pot # Django stuff: *.log local_settings.py db.sqlite3 db.sqlite3-journal # Flask stuff: instance/ .webassets-cache # Scrapy stuff: .scrapy # Sphinx documentation docs/_build/ # PyBuilder target/ # Jupyter Notebook .ipynb_checkpoints # IPython profile_default/ ipython_config.py # pyenv .python-version # pipenv # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. # However, in case of collaboration, if having platform-specific dependencies or dependencies # having no cross-platform support, pipenv may install dependencies that don't work, or not # install all needed dependencies. #Pipfile.lock # PEP 582; used by e.g. github.com/David-OConnor/pyflow __pypackages__/ # Celery stuff celerybeat-schedule celerybeat.pid # SageMath parsed files *.sage.py # Environments .env .venv env/ venv/ ENV/ env.bak/ venv.bak/ # Spyder project settings .spyderproject .spyproject # Rope project settings .ropeproject # mkdocs documentation /site # mypy .mypy_cache/ .dmypy.json dmypy.json # Pyre type checker .pyre/ ================================================ FILE: CONTRIBUTING.md ================================================ ### Contributing Thanks for helping improve `py-clob-client`. - Fork the repo and create a feature branch. - Create focused edits with tests where applicable. - Run the examples to sanity‑check trading flows against a sandbox. - Open a PR with a clear description of the change and motivation. For security issues, please see `SECURITY.md`. ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2022 Polymarket Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: Makefile ================================================ init: pip install -r requirements.txt test: pytest -s fmt: black ./. ================================================ FILE: README.md ================================================ # Polymarket Python CLOB Client PyPI Python client for the Polymarket Central Limit Order Book (CLOB). ## Documentation ## Installation ```bash # install from PyPI (Python 3.9>) pip install py-clob-client ``` ## Usage The examples below are short and copy‑pasteable. - What you need: - **Python 3.9+** - **Private key** that owns funds on Polymarket - Optional: a **proxy/funder address** if you use an email or smart‑contract wallet - Tip: store secrets in environment variables (e.g., with `.env`) ### Quickstart (read‑only) ```python from py_clob_client.client import ClobClient client = ClobClient("https://clob.polymarket.com") # Level 0 (no auth) ok = client.get_ok() time = client.get_server_time() print(ok, time) ``` ### Start trading (EOA) **Note**: If using MetaMask or hardware wallet, you must first set token allowances. See [Token Allowances section](#important-token-allowances-for-metamaskeoa-users) below. ```python from py_clob_client.client import ClobClient HOST = "https://clob.polymarket.com" CHAIN_ID = 137 PRIVATE_KEY = "" FUNDER = "" client = ClobClient( HOST, # The CLOB API endpoint key=PRIVATE_KEY, # Your wallet's private key chain_id=CHAIN_ID, # Polygon chain ID (137) signature_type=1, # 1 for email/Magic wallet signatures funder=FUNDER # Address that holds your funds ) client.set_api_creds(client.create_or_derive_api_creds()) ``` ### Start trading (proxy wallet) For email/Magic or browser wallet proxies, you need to specify two additional parameters: #### Funder Address The **funder address** is the actual address that holds your funds on Polymarket. When using proxy wallets (email wallets like Magic or browser extension wallets), the signing key differs from the address holding the funds. The funder address ensures orders are properly attributed to your funded account. #### Signature Types The **signature_type** parameter tells the system how to verify your signatures: - `signature_type=0` (default): Standard EOA (Externally Owned Account) signatures - includes MetaMask, hardware wallets, and any wallet where you control the private key directly - `signature_type=1`: Email/Magic wallet signatures (delegated signing) - `signature_type=2`: Browser wallet proxy signatures (when using a proxy contract, not direct wallet connections) ```python from py_clob_client.client import ClobClient HOST = "https://clob.polymarket.com" CHAIN_ID = 137 PRIVATE_KEY = "" PROXY_FUNDER = "" # Address that holds your funds client = ClobClient( HOST, # The CLOB API endpoint key=PRIVATE_KEY, # Your wallet's private key chain_id=CHAIN_ID, # Polygon chain ID (137) signature_type=1, # 1 for email/Magic wallet signatures funder=PROXY_FUNDER # Address that holds your funds ) client.set_api_creds(client.create_or_derive_api_creds()) ``` ### Find markets, prices, and orderbooks ```python from py_clob_client.client import ClobClient from py_clob_client.clob_types import BookParams client = ClobClient("https://clob.polymarket.com") # read-only token_id = "" # Get a token ID: https://docs.polymarket.com/developers/gamma-markets-api/get-markets mid = client.get_midpoint(token_id) price = client.get_price(token_id, side="BUY") book = client.get_order_book(token_id) books = client.get_order_books([BookParams(token_id=token_id)]) print(mid, price, book.market, len(books)) ``` ### Place a market order (buy by $ amount) **Note**: EOA/MetaMask users must set token allowances before trading. See [Token Allowances section](#important-token-allowances-for-metamaskeoa-users) below. ```python from py_clob_client.client import ClobClient from py_clob_client.clob_types import MarketOrderArgs, OrderType from py_clob_client.order_builder.constants import BUY HOST = "https://clob.polymarket.com" CHAIN_ID = 137 PRIVATE_KEY = "" FUNDER = "" client = ClobClient( HOST, # The CLOB API endpoint key=PRIVATE_KEY, # Your wallet's private key chain_id=CHAIN_ID, # Polygon chain ID (137) signature_type=1, # 1 for email/Magic wallet signatures funder=FUNDER # Address that holds your funds ) client.set_api_creds(client.create_or_derive_api_creds()) mo = MarketOrderArgs(token_id="", amount=25.0, side=BUY, order_type=OrderType.FOK) # Get a token ID: https://docs.polymarket.com/developers/gamma-markets-api/get-markets signed = client.create_market_order(mo) resp = client.post_order(signed, OrderType.FOK) print(resp) ``` ### Place a limit order (shares at a price) **Note**: EOA/MetaMask users must set token allowances before trading. See [Token Allowances section](#important-token-allowances-for-metamaskeoa-users) below. ```python from py_clob_client.client import ClobClient from py_clob_client.clob_types import OrderArgs, OrderType from py_clob_client.order_builder.constants import BUY HOST = "https://clob.polymarket.com" CHAIN_ID = 137 PRIVATE_KEY = "" FUNDER = "" client = ClobClient( HOST, # The CLOB API endpoint key=PRIVATE_KEY, # Your wallet's private key chain_id=CHAIN_ID, # Polygon chain ID (137) signature_type=1, # 1 for email/Magic wallet signatures funder=FUNDER # Address that holds your funds ) client.set_api_creds(client.create_or_derive_api_creds()) order = OrderArgs(token_id="", price=0.01, size=5.0, side=BUY) # Get a token ID: https://docs.polymarket.com/developers/gamma-markets-api/get-markets signed = client.create_order(order) resp = client.post_order(signed, OrderType.GTC) print(resp) ``` ### Manage orders **Note**: EOA/MetaMask users must set token allowances before trading. See [Token Allowances section](#important-token-allowances-for-metamaskeoa-users) below. ```python from py_clob_client.client import ClobClient from py_clob_client.clob_types import OpenOrderParams HOST = "https://clob.polymarket.com" CHAIN_ID = 137 PRIVATE_KEY = "" FUNDER = "" client = ClobClient( HOST, # The CLOB API endpoint key=PRIVATE_KEY, # Your wallet's private key chain_id=CHAIN_ID, # Polygon chain ID (137) signature_type=1, # 1 for email/Magic wallet signatures funder=FUNDER # Address that holds your funds ) client.set_api_creds(client.create_or_derive_api_creds()) open_orders = client.get_orders(OpenOrderParams()) order_id = open_orders[0]["id"] if open_orders else None if order_id: client.cancel(order_id) client.cancel_all() ``` ### Markets (read‑only) ```python from py_clob_client.client import ClobClient client = ClobClient("https://clob.polymarket.com") markets = client.get_simplified_markets() print(markets["data"][:1]) ``` ### User trades (requires auth) **Note**: EOA/MetaMask users must set token allowances before trading. See [Token Allowances section](#important-token-allowances-for-metamaskeoa-users) below. ```python from py_clob_client.client import ClobClient HOST = "https://clob.polymarket.com" CHAIN_ID = 137 PRIVATE_KEY = "" FUNDER = "" client = ClobClient( HOST, # The CLOB API endpoint key=PRIVATE_KEY, # Your wallet's private key chain_id=CHAIN_ID, # Polygon chain ID (137) signature_type=1, # 1 for email/Magic wallet signatures funder=FUNDER # Address that holds your funds ) client.set_api_creds(client.create_or_derive_api_creds()) last = client.get_last_trade_price("") trades = client.get_trades() print(last, len(trades)) ``` ## Important: Token Allowances for MetaMask/EOA Users ### Do I need to set allowances? - **Using email/Magic wallet?** No action needed - allowances are set automatically. - **Using MetaMask or hardware wallet?** You need to set allowances before trading. ### What are allowances? Think of allowances as permissions. Before Polymarket can move your funds to execute trades, you need to give the exchange contracts permission to access your USDC and conditional tokens. ### Quick Setup You need to approve two types of tokens: 1. **USDC** (for deposits and trading) 2. **Conditional Tokens** (the outcome tokens you trade) Each needs approval for the exchange contracts to work properly. ### Setting Allowances Here's a simple breakdown of what needs to be approved: **For USDC (your trading currency):** - Token: `0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174` - Approve for these contracts: - `0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E` (Main exchange) - `0xC5d563A36AE78145C45a50134d48A1215220f80a` (Neg risk markets) - `0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296` (Neg risk adapter) **For Conditional Tokens (your outcome tokens):** - Token: `0x4D97DCd97eC945f40cF65F87097ACe5EA0476045` - Approve for the same three contracts above ### Example Code See [this Python example](https://gist.github.com/poly-rodr/44313920481de58d5a3f6d1f8226bd5e) for setting allowances programmatically. **Pro tip**: You only need to set these once per wallet. After that, you can trade freely. ## Notes - To discover token IDs, use the Markets API Explorer: [Get Markets](https://docs.polymarket.com/developers/gamma-markets-api/get-markets). - Prices are in dollars from 0.00 to 1.00. Shares are whole or fractional units of the outcome token. See [/example](/examples) for more. ================================================ FILE: SECURITY.md ================================================ ### Security If you believe you’ve found a security vulnerability, please email security@polymarket.com. Do not open a public issue. Include: - A description of the issue and potential impact - Steps to reproduce or a minimal proof of concept - Any relevant logs or environment details We will acknowledge receipt, investigate, and provide guidance on next steps. ================================================ FILE: examples/GTD_order.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds, OrderArgs, OrderType from dotenv import load_dotenv from py_clob_client.constants import AMOY from py_clob_client.order_builder.constants import BUY load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) chain_id = AMOY client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) # Create and sign a limit order buying 100 YES tokens for 0.50c each order_args = OrderArgs( price=0.50, size=100.0, side=BUY, token_id="71321045679252212594626385532706912750332728571942532289631379312455583992563", expiration="1000000000000", ) signed_order = client.create_order(order_args) resp = client.post_order(signed_order, OrderType.GTD) print(resp) print("Done!") main() ================================================ FILE: examples/are_orders_scoring.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds, OrdersScoringParams from dotenv import load_dotenv from py_clob_client.constants import AMOY load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) chain_id = AMOY client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) scoring = client.are_orders_scoring( OrdersScoringParams( orderIds=[ "0xb816482a5187a3d3db49cbaf6fe3ddf24f53e6c712b5a4bf5e01d0ec7b11dabc" ] ) ) print(scoring) print("Done!") main() ================================================ FILE: examples/cancel_all.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds from dotenv import load_dotenv from py_clob_client.constants import AMOY load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) chain_id = AMOY client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) resp = client.cancel_all() print(resp) print("Done!") main() ================================================ FILE: examples/cancel_market_orders.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds from dotenv import load_dotenv from py_clob_client.constants import AMOY load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) chain_id = AMOY client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) resp = client.cancel_market_orders(market="0xaaa", asset_id="100") print(resp) print("Done!") main() ================================================ FILE: examples/cancel_order.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds from dotenv import load_dotenv from py_clob_client.constants import AMOY load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) chain_id = AMOY client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) resp = client.cancel(order_id="0xaaaa") print(resp) print("Done!") main() ================================================ FILE: examples/cancel_orders.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds from dotenv import load_dotenv from py_clob_client.constants import AMOY load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) chain_id = AMOY client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) resp = client.cancel_orders(["0xaaaa"]) print(resp) print("Done!") main() ================================================ FILE: examples/create_api_key.py ================================================ from dotenv import load_dotenv import os from py_clob_client.client import ClobClient from py_clob_client.constants import AMOY load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") key = os.getenv("PK") chain_id = AMOY client = ClobClient(host, key=key, chain_id=chain_id) print(client.create_api_key()) main() ================================================ FILE: examples/create_readonly_api_key.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds from dotenv import load_dotenv from py_clob_client.constants import AMOY load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) chain_id = AMOY client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) resp = client.create_readonly_api_key() print(resp) print("Done!") main() ================================================ FILE: examples/delete_readonly_api_key.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds from dotenv import load_dotenv from py_clob_client.constants import AMOY load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) chain_id = AMOY client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) # Replace with the readonly API key you want to delete readonly_api_key = "019aee85-4ea1-79cd-a287-8508f21209a2" resp = client.delete_readonly_api_key(readonly_api_key) print(resp) print("Done!") main() ================================================ FILE: examples/derive_api_key.py ================================================ from dotenv import load_dotenv import os from py_clob_client.client import ClobClient from py_clob_client.constants import AMOY load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") key = os.getenv("PK") chain_id = AMOY client = ClobClient(host, key=key, chain_id=chain_id) print(client.derive_api_key()) main() ================================================ FILE: examples/drop_notifications.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds, DropNotificationParams from dotenv import load_dotenv from py_clob_client.constants import AMOY load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) chain_id = AMOY client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) print(client.drop_notifications(params=DropNotificationParams(ids=["1", "2"]))) main() ================================================ FILE: examples/get_api_keys.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds from dotenv import load_dotenv from py_clob_client.constants import AMOY load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) chain_id = AMOY client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) print(client.get_api_keys()) main() ================================================ FILE: examples/get_balance_allowance.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds, BalanceAllowanceParams, AssetType from dotenv import load_dotenv from py_clob_client.constants import AMOY load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) chain_id = AMOY client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) collateral = client.get_balance_allowance( params=BalanceAllowanceParams(asset_type=AssetType.COLLATERAL) ) print(collateral) yes = client.get_balance_allowance( params=BalanceAllowanceParams( asset_type=AssetType.CONDITIONAL, token_id="52114319501245915516055106046884209969926127482827954674443846427813813222426", ) ) print(yes) no = client.get_balance_allowance( params=BalanceAllowanceParams( asset_type=AssetType.CONDITIONAL, token_id="71321045679252212594626385532706912750332728571942532289631379312455583992563", ) ) print(no) main() ================================================ FILE: examples/get_builder_trades.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds, TradeParams from py_builder_signing_sdk.config import BuilderConfig, BuilderApiKeyCreds from dotenv import load_dotenv from pprint import pprint from py_clob_client.constants import AMOY load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) chain_id = AMOY builder_config = BuilderConfig( local_builder_creds=BuilderApiKeyCreds( key=os.getenv("BUILDER_API_KEY"), secret=os.getenv("BUILDER_SECRET"), passphrase=os.getenv("BUILDER_PASS_PHRASE"), ) ) client = ClobClient( host, key=key, chain_id=chain_id, creds=creds, builder_config=builder_config ) resp = client.get_builder_trades() pprint(resp) print("Done!") main() ================================================ FILE: examples/get_closed_only_mode.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds from dotenv import load_dotenv from py_clob_client.constants import AMOY load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) chain_id = AMOY client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) print(client.get_closed_only_mode()) main() ================================================ FILE: examples/get_last_trade_price.py ================================================ import os from py_clob_client.client import ClobClient from dotenv import load_dotenv from pprint import pprint from py_clob_client.constants import AMOY load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") key = os.getenv("PK") chain_id = AMOY client = ClobClient(host, key=key, chain_id=chain_id) resp = client.get_last_trade_price( "71321045679252212594626385532706912750332728571942532289631379312455583992563" ) pprint(resp) print("Done!") main() ================================================ FILE: examples/get_last_trades_prices.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import BookParams from dotenv import load_dotenv from pprint import pprint from py_clob_client.constants import AMOY load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") key = os.getenv("PK") chain_id = AMOY client = ClobClient(host, key=key, chain_id=chain_id) resp = client.get_last_trades_prices( params=[ BookParams( token_id="71321045679252212594626385532706912750332728571942532289631379312455583992563" ), BookParams( token_id="52114319501245915516055106046884209969926127482827954674443846427813813222426" ), ] ) pprint(resp) print("Done!") main() ================================================ FILE: examples/get_market_trades_events.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds from dotenv import load_dotenv from py_clob_client.constants import AMOY load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) chain_id = AMOY client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) print(client.get_market_trades_events("condition_id")) print("Done!") main() ================================================ FILE: examples/get_markets.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds from dotenv import load_dotenv from py_clob_client.constants import AMOY load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) chain_id = AMOY client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) print(client.get_markets()) print(client.get_simplified_markets()) print(client.get_sampling_markets()) print(client.get_sampling_simplified_markets()) print(client.get_market("condition_id")) print("Done!") main() ================================================ FILE: examples/get_mid_market_price.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds from dotenv import load_dotenv from py_clob_client.constants import AMOY load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) chain_id = AMOY client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) resp = client.get_midpoint( "71321045679252212594626385532706912750332728571942532289631379312455583992563" ) # {'mid': '0.55'} print(resp) print("Done!") main() ================================================ FILE: examples/get_mid_markets_prices.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds, BookParams from dotenv import load_dotenv from py_clob_client.constants import AMOY load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) chain_id = AMOY client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) resp = client.get_midpoints( params=[ BookParams( token_id="71321045679252212594626385532706912750332728571942532289631379312455583992563" ), BookParams( token_id="52114319501245915516055106046884209969926127482827954674443846427813813222426" ), ] ) print(resp) print("Done!") main() ================================================ FILE: examples/get_notifications.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds from dotenv import load_dotenv from py_clob_client.constants import AMOY load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) chain_id = AMOY client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) print(client.get_notifications()) main() ================================================ FILE: examples/get_ok.py ================================================ from py_clob_client.client import ClobClient def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") client = ClobClient(host) print(client.get_ok()) pass main() ================================================ FILE: examples/get_open_orders_with_readonly_key.py ================================================ import os import httpx from dotenv import load_dotenv from py_clob_client.endpoints import ORDERS load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") # Replace with your address and readonly API key address = os.getenv("POLY_ADDRESS", "0xc68576124eC1fF645F81a560E14003C8deF2e8fb") readonly_api_key = os.getenv("CLOB_READONLY_API_KEY", "019aee85-4ea1-79cd-a287-8508f21209a2") # Get all open orders for the address response = httpx.get( f"{host}{ORDERS}", headers={ "POLY_READONLY_API_KEY": readonly_api_key, "POLY_ADDRESS": address, "Content-Type": "application/json", }, params={ "maker_address": address, }, follow_redirects=True, ) if response.status_code == 200: print(response.json()) else: print(f"Error {response.status_code}: {response.text}") print("Done!") main() ================================================ FILE: examples/get_order.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds from dotenv import load_dotenv from py_clob_client.constants import AMOY load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) chain_id = AMOY client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) resp = client.get_order( "0xf5667d8509bdc78ac43676fe2c980da1365c471ee92153820c89c488fc15d539" ) print(resp) print("Done!") main() ================================================ FILE: examples/get_orderbook.py ================================================ from py_clob_client.client import ClobClient import os from dotenv import load_dotenv load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") client = ClobClient(host) orderbook = client.get_order_book( "34097058504275310827233323421517291090691602969494795225921954353603704046623" ) print("orderbook", orderbook) hash = client.get_order_book_hash(orderbook) print("orderbook hash", hash) main() ================================================ FILE: examples/get_orderbooks.py ================================================ from py_clob_client.client import ClobClient from py_clob_client.clob_types import BookParams def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") client = ClobClient(host) resp = client.get_order_books( params=[ BookParams( token_id="71321045679252212594626385532706912750332728571942532289631379312455583992563" ), BookParams( token_id="52114319501245915516055106046884209969926127482827954674443846427813813222426" ), ] ) print(resp) print("Done!") main() ================================================ FILE: examples/get_orders.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds, OpenOrderParams from dotenv import load_dotenv from py_clob_client.constants import AMOY load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) chain_id = AMOY client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) resp = client.get_orders( OpenOrderParams( market="0x37a6a2dd9f3469495d9ec2467b0a764c5905371a294ce544bc3b2c944eb3e84a", ) ) print(resp) print("Done!") main() ================================================ FILE: examples/get_price.py ================================================ from py_clob_client.client import ClobClient from py_clob_client.clob_types import BookParams def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") client = ClobClient(host) resp = client.get_price( "71321045679252212594626385532706912750332728571942532289631379312455583992563", "BUY", ) print(resp) print("Done!") main() ================================================ FILE: examples/get_prices.py ================================================ from py_clob_client.client import ClobClient from py_clob_client.clob_types import BookParams def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") client = ClobClient(host) resp = client.get_prices( params=[ BookParams( token_id="71321045679252212594626385532706912750332728571942532289631379312455583992563", side="BUY", ), BookParams( token_id="71321045679252212594626385532706912750332728571942532289631379312455583992563", side="SELL", ), BookParams( token_id="52114319501245915516055106046884209969926127482827954674443846427813813222426", side="BUY", ), BookParams( token_id="52114319501245915516055106046884209969926127482827954674443846427813813222426", side="SELL", ), ] ) print(resp) print("Done!") main() ================================================ FILE: examples/get_readonly_api_keys.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds from dotenv import load_dotenv from py_clob_client.constants import AMOY load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) chain_id = AMOY client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) resp = client.get_readonly_api_keys() print(resp) print("Done!") main() ================================================ FILE: examples/get_server_time.py ================================================ from py_clob_client.client import ClobClient def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") client = ClobClient(host) print(client.get_server_time()) main() ================================================ FILE: examples/get_spread.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds from dotenv import load_dotenv from py_clob_client.constants import AMOY load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) chain_id = AMOY client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) resp = client.get_spread( "71321045679252212594626385532706912750332728571942532289631379312455583992563" ) print(resp) print("Done!") main() ================================================ FILE: examples/get_spreads.py ================================================ from py_clob_client.client import ClobClient from py_clob_client.clob_types import BookParams def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") client = ClobClient(host) resp = client.get_spreads( params=[ BookParams( token_id="71321045679252212594626385532706912750332728571942532289631379312455583992563" ), BookParams( token_id="52114319501245915516055106046884209969926127482827954674443846427813813222426" ), ] ) print(resp) print("Done!") main() ================================================ FILE: examples/get_trades.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds, TradeParams from dotenv import load_dotenv from pprint import pprint from py_clob_client.constants import AMOY load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) chain_id = AMOY client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) resp = client.get_trades( TradeParams( maker_address=client.get_address(), market="0x5f65177b394277fd294cd75650044e32ba009a95022d88a0c1d565897d72f8f1", ) ) pprint(resp) print("Done!") main() ================================================ FILE: examples/is_order_scoring.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds, OrderScoringParams from dotenv import load_dotenv from py_clob_client.constants import AMOY load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) chain_id = AMOY client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) scoring = client.is_order_scoring( OrderScoringParams( orderId="0xb816482a5187a3d3db49cbaf6fe3ddf24f53e6c712b5a4bf5e01d0ec7b11dabc" ) ) print(scoring) print("Done!") main() ================================================ FILE: examples/market_buy_order.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds, MarketOrderArgs, OrderType from dotenv import load_dotenv from py_clob_client.constants import AMOY from py_clob_client.order_builder.constants import BUY load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) chain_id = AMOY client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) # create a market buy order for the equivalent of 100 USDC at the market price order_args = MarketOrderArgs( token_id="71321045679252212594626385532706912750332728571942532289631379312455583992563", amount=100, # $$$ side=BUY, ) signed_order = client.create_market_order(order_args) resp = client.post_order(signed_order, orderType=OrderType.FOK) print(resp) print("Done!") main() ================================================ FILE: examples/market_sell_order.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds, MarketOrderArgs, OrderType from dotenv import load_dotenv from py_clob_client.constants import AMOY from py_clob_client.order_builder.constants import SELL load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) chain_id = AMOY client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) # create a market buy order for the equivalent of 100 USDC at the market price order_args = MarketOrderArgs( token_id="71321045679252212594626385532706912750332728571942532289631379312455583992563", amount=100, # SHARES side=SELL, ) signed_order = client.create_market_order(order_args) resp = client.post_order(signed_order, orderType=OrderType.FOK) print(resp) print("Done!") main() ================================================ FILE: examples/order.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds, OrderArgs from dotenv import load_dotenv from py_clob_client.constants import AMOY from py_clob_client.order_builder.constants import BUY load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) chain_id = int(os.getenv("CHAIN_ID", AMOY)) client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) # Create and sign a limit order buying 100 YES tokens for 0.0005 each order_args = OrderArgs( price=0.0005, size=20, side=BUY, token_id="71321045679252212594626385532706912750332728571942532289631379312455583992563", ) signed_order = client.create_order(order_args) resp = client.post_order(signed_order) print(resp) print("Done!") main() ================================================ FILE: examples/orders.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds, OrderArgs, PostOrdersArgs, OrderType from dotenv import load_dotenv from py_clob_client.constants import AMOY from py_clob_client.order_builder.constants import BUY, SELL load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) chain_id = AMOY client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) resp = client.post_orders( [ PostOrdersArgs( # Create and sign a limit order buying 100 YES tokens for 0.50 each order=client.create_order( OrderArgs( price=0.5, size=100, side=BUY, token_id="71321045679252212594626385532706912750332728571942532289631379312455583992563", ) ), orderType=OrderType.GTC, # Good 'Til Cancelled postOnly=False, ), PostOrdersArgs( # Create and sign a limit order selling 200 NO tokens for 0.25 each order=client.create_order( OrderArgs( price=0.25, size=200, side=SELL, token_id="52114319501245915516055106046884209969926127482827954674443846427813813222426", ) ), orderType=OrderType.GTC, # Good 'Til Cancelled postOnly=False, # Defaults to false, can be set to true to avoid matching on post ), ] ) print(resp) print("Done!") main() ================================================ FILE: examples/place_builder_order.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds, OrderArgs from dotenv import load_dotenv from py_clob_client.constants import POLYGON from py_clob_client.order_builder.constants import BUY from py_builder_signing_sdk.config import BuilderConfig, BuilderApiKeyCreds load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) chain_id = POLYGON builder_config = BuilderConfig( local_builder_creds=BuilderApiKeyCreds( key=os.getenv("BUILDER_API_KEY"), secret=os.getenv("BUILDER_SECRET"), passphrase=os.getenv("BUILDER_PASS_PHRASE"), ) ) client = ClobClient( host, key=key, chain_id=chain_id, creds=creds, builder_config=builder_config ) order_args = OrderArgs( price=0.06, size=20, side=BUY, token_id="104173557214744537570424345347209544585775842950109756851652855913015295701992", ) signed_order = client.create_order(order_args) resp = client.post_order(signed_order) print(resp) print("Done!") main() ================================================ FILE: examples/post_heartbeat.py ================================================ import os import time from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds from dotenv import load_dotenv from py_clob_client.constants import AMOY load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) chain_id = AMOY client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) heartbeat_id = None while True: resp = client.post_heartbeat(heartbeat_id) print(resp) heartbeat_id = resp["heartbeat_id"] # Wait 5 seconds before sending the next heartbeat time.sleep(5) # Example output on invalid heartbeat ID once heartbeats started: # PolyApiException[status_code=400, error_message={"error":"Invalid Heartbeat ID","heartbeat_id":"7f335bb3-36cb-433d-b8ff-4f9a2233d833"} main() ================================================ FILE: examples/post_only_order.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds, OrderArgs from dotenv import load_dotenv from py_clob_client.constants import AMOY from py_clob_client.clob_types import (OrderType) from py_clob_client.order_builder.constants import BUY, SELL load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) chain_id = AMOY client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) order_args = OrderArgs( price=0.4, size=5, side=BUY, token_id="102200530570339469387764365697342150521708074903735836831685780223982723092914", ) order = client.create_order(order_args) resp = client.post_order(order, orderType=OrderType.GTC, post_only=True) print(resp) print("Done!") main() ================================================ FILE: examples/rfq_accept_quote.py ================================================ import os import time from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds from py_clob_client.rfq import AcceptQuoteParams from py_clob_client.constants import AMOY from dotenv import load_dotenv load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob-staging.polymarket.com/") chain_id = int(os.getenv("CHAIN_ID", AMOY)) key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) # Accept a quote (requester side) # Refers to the order expiry, not request expiry. For request expiry, check the server RFQ config. expiration = int(time.time()) + 3600 accept_params = AcceptQuoteParams( request_id="019b04a4-2f4b-73b3-8fa2-2760b2754601", quote_id="019b04a7-5205-7eeb-9a48-227e8d53bd17", expiration=expiration, ) resp = client.rfq.accept_rfq_quote(accept_params) print(resp) print("Done!") main() ================================================ FILE: examples/rfq_approve_order.py ================================================ import os import time from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds from py_clob_client.rfq import ApproveOrderParams from py_clob_client.constants import AMOY from dotenv import load_dotenv load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob-staging.polymarket.com/") chain_id = int(os.getenv("CHAIN_ID", AMOY)) key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) # Approve an order (quoter side) # Refers to the order expiry, not quote expiry. For quote expiry, check the server RFQ config. expiration = int(time.time()) + 3600 approve_params = ApproveOrderParams( request_id="019b04a4-2f4b-73b3-8fa2-2760b2754601", quote_id="019b04a7-5205-7eeb-9a48-227e8d53bd17", expiration=expiration, ) resp = client.rfq.approve_rfq_order(approve_params) print(resp) print("Done!") main() ================================================ FILE: examples/rfq_cancel_quote.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds from py_clob_client.rfq import CancelRfqQuoteParams from py_clob_client.constants import AMOY from dotenv import load_dotenv load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob-staging.polymarket.com/") chain_id = int(os.getenv("CHAIN_ID", AMOY)) key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) resp = client.rfq.cancel_rfq_quote( CancelRfqQuoteParams(quote_id="0197656d-56ee-74a4-a06a-3b179121f3bf") ) print(resp) print("Done!") main() ================================================ FILE: examples/rfq_cancel_request.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds from py_clob_client.rfq import CancelRfqRequestParams from py_clob_client.constants import AMOY from dotenv import load_dotenv load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob-staging.polymarket.com/") chain_id = int(os.getenv("CHAIN_ID", AMOY)) key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) resp = client.rfq.cancel_rfq_request( CancelRfqRequestParams(request_id="0197656d-56ee-74a4-a06a-3b179121f3bf") ) print(resp) print("Done!") main() ================================================ FILE: examples/rfq_config.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds from py_clob_client.constants import AMOY from dotenv import load_dotenv load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob-staging.polymarket.com/") chain_id = int(os.getenv("CHAIN_ID", AMOY)) key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) resp = client.rfq.rfq_config() print(resp) print("Done!") main() ================================================ FILE: examples/rfq_create_quote.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds from py_clob_client.rfq import RfqUserQuote from py_clob_client.order_builder.constants import SELL from py_clob_client.constants import AMOY from dotenv import load_dotenv load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob-staging.polymarket.com/") chain_id = int(os.getenv("CHAIN_ID", AMOY)) key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) # Create a quote for an RFQ request to SELL 40 tokens at $0.50 each user_quote = RfqUserQuote( request_id="019b04a4-2f4b-73b3-8fa2-2760b2754601", token_id="34097058504275310827233323421517291090691602969494795225921954353603704046623", price=0.50, side=SELL, size=40.0, ) resp = client.rfq.create_rfq_quote(user_quote) print(resp) print("Done!") main() ================================================ FILE: examples/rfq_create_request.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds, PartialCreateOrderOptions from py_clob_client.rfq import RfqUserRequest from py_clob_client.order_builder.constants import BUY from py_clob_client.constants import AMOY from dotenv import load_dotenv load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob-staging.polymarket.com/") chain_id = int(os.getenv("CHAIN_ID", AMOY)) key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) # Create an RFQ request to BUY 100 tokens at $0.50 each user_request = RfqUserRequest( token_id="34097058504275310827233323421517291090691602969494795225921954353603704046623", price=0.50, side=BUY, size=40.0, ) resp = client.rfq.create_rfq_request(user_request, options=PartialCreateOrderOptions(tick_size=0.01)) print(resp) print("Done!") main() ================================================ FILE: examples/rfq_full_flow.py ================================================ """ RFQ Full Flow Example This script demonstrates the complete RFQ (Request for Quote) flow between two parties. For a single manual test, edit the REQUEST_PARAMS and QUOTE_PARAMS at the top. This example assumes two EOA wallets. For using different signature types, you need to set the funder address signature type when initializing the client. Usage: python rfq_full_flow.py TROUBLESHOOTING "invalid request" errors: 1. Ensure the tokenID exists in your environment (staging vs production) 2. Check that the market is active, RFQ-enabled and has liquidity 3. Verify your quoter has been whitelisted 4. Run `python examples/get_markets.py` to get valid token IDs 5. Make sure you're using the correct CLOB_API_URL for your environment ENV VARIABLES: REQUESTER_PK: Private key of the requester REQUESTER_API_KEY: API key of the requester REQUESTER_SECRET: Secret of the requester REQUESTER_PASS_PHRASE: Passphrase of the requester QUOTER_PK: Private key of the quoter QUOTER_API_KEY: API key of the quoter QUOTER_SECRET: Secret of the quoter QUOTER_PASS_PHRASE: Passphrase of the quoter CHAIN_ID: Chain ID of the network CLOB_API_URL: URL of the CLOB API """ import os import time from dotenv import load_dotenv from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds from py_clob_client.rfq import RfqUserRequest, RfqUserQuote, AcceptQuoteParams, ApproveOrderParams from py_clob_client.order_builder.constants import BUY, SELL from py_clob_client.constants import AMOY load_dotenv() # ============================================ # RFQ REQUEST PARAMETERS (REQUESTER) - EDIT THESE # ============================================ TOKEN_ID = "34097058504275310827233323421517291090691602969494795225921954353603704046623" USER_REQUEST = RfqUserRequest( token_id=TOKEN_ID, price=0.50, # Price per token (e.g., 0.50 = 50 cents) side=BUY, # BUY or SELL size=100.0, # Number of tokens ) # ============================================ # RFQ QUOTE PARAMETERS (QUOTER) - EDIT THESE # ============================================ QUOTE_TOKEN_ID = TOKEN_ID # Token ID for the quote (defaults to same as request) QUOTE_PRICE = 0.50 # Quoted price per token QUOTE_SIZE = 100.0 # Number of tokens to quote QUOTE_SIDE = SELL # BUY or SELL # ============================================ # EXPIRATION CONFIGURATION # ============================================ EXPIRATION_SECONDS = 3600 # 1 hour def main(): # ============================================ # Setup: Initialize both requester and quoter clients # ============================================ host = os.getenv("CLOB_API_URL", "https://clob-staging.polymarket.com/") chain_id = int(os.getenv("CHAIN_ID", AMOY)) # Requester (creates the request and accepts the quote) requester_key = os.getenv("REQUESTER_PK") requester_creds = ApiCreds( api_key=os.getenv("REQUESTER_API_KEY"), api_secret=os.getenv("REQUESTER_SECRET"), api_passphrase=os.getenv("REQUESTER_PASS_PHRASE"), ) requester_client = ClobClient(host, key=requester_key, chain_id=chain_id, creds=requester_creds) # Quoter (creates the quote and approves the order) quoter_key = os.getenv("QUOTER_PK") quoter_creds = ApiCreds( api_key=os.getenv("QUOTER_API_KEY"), api_secret=os.getenv("QUOTER_SECRET"), api_passphrase=os.getenv("QUOTER_PASS_PHRASE"), ) quoter_client = ClobClient(host, key=quoter_key, chain_id=chain_id, creds=quoter_creds) print("=" * 60) print("RFQ Full Flow") print("=" * 60) print(f"Host: {host}") print(f"Chain ID: {chain_id}") print("=" * 60) # ============================================ # Step 1: Requester creates RFQ request # ============================================ print("\n[Step 1] Requester creating RFQ request...") print(f" Token ID: {USER_REQUEST.token_id}") print(f" Side: {USER_REQUEST.side}") print(f" Size: {USER_REQUEST.size}") print(f" Price: {USER_REQUEST.price}") rfq_request_response = requester_client.rfq.create_rfq_request(USER_REQUEST) # Check for errors if rfq_request_response.get("error"): print(f"Failed to create request. Error: {rfq_request_response['error']}") raise Exception(f"Request creation failed: {rfq_request_response['error']}") request_id = rfq_request_response.get("requestId") if not request_id: print(f"Failed to create request. Response: {rfq_request_response}") raise Exception("Request creation failed - no requestId returned") print("Request created successfully!") print(f" Request ID: {request_id}") print(f" Full response: {rfq_request_response}") # ============================================ # Step 2: Quoter creates quote for the request # ============================================ print("\n[Step 2] Quoter creating quote for request...") print(f" Request ID: {request_id}") print(f" Token ID: {QUOTE_TOKEN_ID}") print(f" Price: {QUOTE_PRICE}") print(f" Side: {QUOTE_SIDE}") print(f" Size: {QUOTE_SIZE}") user_quote = RfqUserQuote( request_id=request_id, token_id=QUOTE_TOKEN_ID, price=QUOTE_PRICE, side=QUOTE_SIDE, size=QUOTE_SIZE, ) rfq_quote_response = quoter_client.rfq.create_rfq_quote(user_quote) # Check for errors if rfq_quote_response.get("error"): print(f"Failed to create quote. Error: {rfq_quote_response['error']}") raise Exception(f"Quote creation failed: {rfq_quote_response['error']}") quote_id = rfq_quote_response.get("quoteId") if not quote_id: print(f"Failed to create quote. Response: {rfq_quote_response}") raise Exception("Quote creation failed - no quoteId returned") print("Quote created successfully!") print(f" Quote ID: {quote_id}") print(f" Request ID: {request_id}") print(f" Full response: {rfq_quote_response}") # ============================================ # Step 3: Requester accepts the quote # ============================================ print("\n[Step 3] Requester accepting quote...") expiration = int(time.time()) + EXPIRATION_SECONDS accept_params = AcceptQuoteParams( request_id=request_id, quote_id=quote_id, expiration=expiration, ) accept_result = requester_client.rfq.accept_rfq_quote(accept_params) print(accept_result) print("Quote accepted successfully!") print(f" Request ID: {request_id}") print(f" Quote ID: {quote_id}") # ============================================ # Step 4: Quoter approves the order # ============================================ print("\n[Step 4] Quoter approving order...") approve_params = ApproveOrderParams( request_id=request_id, quote_id=quote_id, expiration=expiration, ) approve_result = quoter_client.rfq.approve_rfq_order(approve_params) print(approve_result) print("Order approved successfully!") print(f" Request ID: {request_id}") print(f" Quote ID: {quote_id}") # ============================================ # Summary # ============================================ print("\n" + "=" * 60) print("RFQ FLOW COMPLETED SUCCESSFULLY!") print("=" * 60) print(f"Request ID: {request_id}") print(f"Quote ID: {quote_id}") print("=" * 60) main() ================================================ FILE: examples/rfq_get_best_quote.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds from py_clob_client.rfq import GetRfqBestQuoteParams from py_clob_client.constants import AMOY from dotenv import load_dotenv load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob-staging.polymarket.com/") chain_id = int(os.getenv("CHAIN_ID", AMOY)) key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) params = GetRfqBestQuoteParams( request_id=os.getenv("RFQ_REQUEST_ID", "019b9f8d-2336-70db-a0dd-071363fb1ff3") ) resp = client.rfq.get_rfq_best_quote(params) print(resp) print("Done!") main() ================================================ FILE: examples/rfq_get_quotes.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds from py_clob_client.rfq import GetRfqQuotesParams from py_clob_client.constants import AMOY from dotenv import load_dotenv load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob-staging.polymarket.com/") chain_id = int(os.getenv("CHAIN_ID", AMOY)) key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) params = GetRfqQuotesParams( # quote_ids=["0197656d-56ee-74a4-a06a-3b179121f3bf"], state="active", # markets=["0x0000000000000000000000000000000000000000"], # size_min=5, # size_max=100, # price_min=0.1, # price_max=0.9, # sort_by="price", # sort_dir="asc", limit=10, # offset="MA==", ) # Get quotes on your requests (requester view) # Returns quotes that others have made on your RFQ requests print("Requester quotes (quotes on my requests):") requester_resp = client.rfq.get_rfq_requester_quotes(params) print(requester_resp) # Get quotes you've created (quoter view) # Returns quotes that you have made on others' RFQ requests print("\nQuoter quotes (quotes I've made):") quoter_resp = client.rfq.get_rfq_quoter_quotes(params) print(quoter_resp) print("Done!") main() ================================================ FILE: examples/rfq_get_requests.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds from py_clob_client.rfq import GetRfqRequestsParams from py_clob_client.constants import AMOY from dotenv import load_dotenv load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob-staging.polymarket.com/") chain_id = int(os.getenv("CHAIN_ID", AMOY)) key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) # Get all active RFQ requests params = GetRfqRequestsParams( # request_ids=["0197656d-56ee-74a4-a06a-3b179121f3bf"], state="active", # markets=["0x0000000000000000000000000000000000000000"], # size_min=5, # size_max=100, # price_min=0.1, # price_max=0.9, # sort_by="price", # sort_dir="asc", limit=10, offset="MA==", ) resp = client.rfq.get_rfq_requests(params) print(resp) print("Done!") main() ================================================ FILE: examples/update_balance_allowance.py ================================================ import os from py_clob_client.client import ClobClient from py_clob_client.clob_types import ApiCreds, BalanceAllowanceParams, AssetType from dotenv import load_dotenv from py_clob_client.constants import AMOY load_dotenv() def main(): host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com") key = os.getenv("PK") creds = ApiCreds( api_key=os.getenv("CLOB_API_KEY"), api_secret=os.getenv("CLOB_SECRET"), api_passphrase=os.getenv("CLOB_PASS_PHRASE"), ) chain_id = AMOY client = ClobClient(host, key=key, chain_id=chain_id, creds=creds) # USDC client.update_balance_allowance( params=BalanceAllowanceParams(asset_type=AssetType.COLLATERAL) ) # YES client.update_balance_allowance( params=BalanceAllowanceParams( asset_type=AssetType.CONDITIONAL, token_id="52114319501245915516055106046884209969926127482827954674443846427813813222426", ) ) # NO client.update_balance_allowance( params=BalanceAllowanceParams( asset_type=AssetType.CONDITIONAL, token_id="71321045679252212594626385532706912750332728571942532289631379312455583992563", ) ) main() ================================================ FILE: py_clob_client/__init__.py ================================================ from .client import ClobClient from .clob_types import ( ApiCreds, OrderArgs, MarketOrderArgs, OrderType, TickSize, BookParams, TradeParams, OpenOrderParams, BalanceAllowanceParams, AssetType, PartialCreateOrderOptions, CreateOrderOptions, ) # RFQ exports from .rfq import ( RfqClient, RfqUserRequest, RfqUserQuote, CreateRfqRequestParams, CreateRfqQuoteParams, CancelRfqRequestParams, CancelRfqQuoteParams, AcceptQuoteParams, ApproveOrderParams, GetRfqRequestsParams, GetRfqQuotesParams, GetRfqBestQuoteParams, RfqRequest, RfqQuote, RfqRequestResponse, RfqQuoteResponse, RfqPaginatedResponse, ) __all__ = [ # Main client "ClobClient", # Core types "ApiCreds", "OrderArgs", "MarketOrderArgs", "OrderType", "TickSize", "BookParams", "TradeParams", "OpenOrderParams", "BalanceAllowanceParams", "AssetType", "PartialCreateOrderOptions", "CreateOrderOptions", # RFQ client "RfqClient", # RFQ input types "RfqUserRequest", "RfqUserQuote", "CreateRfqRequestParams", "CreateRfqQuoteParams", "CancelRfqRequestParams", "CancelRfqQuoteParams", "AcceptQuoteParams", "ApproveOrderParams", "GetRfqRequestsParams", "GetRfqQuotesParams", "GetRfqBestQuoteParams", # RFQ response types "RfqRequest", "RfqQuote", "RfqRequestResponse", "RfqQuoteResponse", "RfqPaginatedResponse", ] ================================================ FILE: py_clob_client/client.py ================================================ import logging import json import time from typing import Optional from py_builder_signing_sdk.config import BuilderConfig from .order_builder.builder import OrderBuilder from .headers.headers import ( create_level_1_headers, create_level_2_headers, enrich_l2_headers_with_builder_headers, ) from .signer import Signer from .config import get_contract_config from .endpoints import ( CANCEL, CANCEL_ORDERS, CANCEL_MARKET_ORDERS, CANCEL_ALL, CREATE_API_KEY, DELETE_API_KEY, DERIVE_API_KEY, GET_API_KEYS, CLOSED_ONLY, CREATE_READONLY_API_KEY, GET_READONLY_API_KEYS, DELETE_READONLY_API_KEY, VALIDATE_READONLY_API_KEY, GET_LAST_TRADE_PRICE, GET_ORDER, GET_ORDER_BOOK, MID_POINT, ORDERS, POST_ORDER, POST_ORDERS, PRICE, TIME, TRADES, GET_NOTIFICATIONS, DROP_NOTIFICATIONS, GET_BALANCE_ALLOWANCE, UPDATE_BALANCE_ALLOWANCE, IS_ORDER_SCORING, GET_TICK_SIZE, GET_NEG_RISK, GET_FEE_RATE, ARE_ORDERS_SCORING, GET_SIMPLIFIED_MARKETS, GET_MARKETS, GET_MARKET, GET_SAMPLING_SIMPLIFIED_MARKETS, GET_SAMPLING_MARKETS, GET_MARKET_TRADES_EVENTS, GET_LAST_TRADES_PRICES, MID_POINTS, GET_ORDER_BOOKS, GET_PRICES, GET_SPREAD, GET_SPREADS, GET_BUILDER_TRADES, POST_HEARTBEAT, ) from .clob_types import ( ApiCreds, ReadonlyApiKeyResponse, TradeParams, OpenOrderParams, OrderArgs, RequestArgs, DropNotificationParams, OrderBookSummary, BalanceAllowanceParams, OrderScoringParams, TickSize, CreateOrderOptions, OrdersScoringParams, OrderType, PartialCreateOrderOptions, BookParams, MarketOrderArgs, PostOrdersArgs, ) from .exceptions import PolyException from .http_helpers.helpers import ( add_query_trade_params, add_query_open_orders_params, delete, get, post, drop_notifications_query_params, add_balance_allowance_params_to_url, add_order_scoring_params_to_url, ) from .constants import ( L0, L1, L1_AUTH_UNAVAILABLE, L2, L2_AUTH_UNAVAILABLE, END_CURSOR, BUILDER_AUTH_UNAVAILABLE, ) from .utilities import ( parse_raw_orderbook_summary, generate_orderbook_summary_hash, order_to_json, is_tick_size_smaller, price_valid, ) from .rfq import RfqClient class ClobClient: def __init__( self, host, chain_id: int = None, key: str = None, creds: ApiCreds = None, signature_type: int = None, funder: str = None, builder_config: BuilderConfig = None, tick_size_ttl: float = 300.0, ): """ Initializes the clob client The client can be started in 3 modes: 1) Level 0: Requires only the clob host url Allows access to open CLOB endpoints 2) Level 1: Requires the host, chain_id and a private key. Allows access to L1 authenticated endpoints + all unauthenticated endpoints 3) Level 2: Requires the host, chain_id, a private key, and Credentials. Allows access to all endpoints """ self.host = host[0:-1] if host.endswith("/") else host self.chain_id = chain_id self.signer = Signer(key, chain_id) if key else None self.creds = creds self.mode = self._get_client_mode() if self.signer: self.builder = OrderBuilder( self.signer, sig_type=signature_type, funder=funder ) self.builder_config = None if builder_config: self.builder_config = builder_config # local cache self.__tick_sizes = {} self.__tick_size_timestamps = {} self.__tick_size_ttl = tick_size_ttl self.__neg_risk = {} self.__fee_rates = {} # RFQ client self.rfq = RfqClient(self) self.logger = logging.getLogger(self.__class__.__name__) def get_address(self): """ Returns the public address of the signer """ return self.signer.address() if self.signer else None def get_collateral_address(self): """ Returns the collateral token address """ contract_config = get_contract_config(self.chain_id) if contract_config: return contract_config.collateral def get_conditional_address(self): """ Returns the conditional token address """ contract_config = get_contract_config(self.chain_id) if contract_config: return contract_config.conditional_tokens def get_exchange_address(self, neg_risk=False): """ Returns the exchange address """ contract_config = get_contract_config(self.chain_id, neg_risk) if contract_config: return contract_config.exchange def get_ok(self): """ Health check: Confirms that the server is up Does not need authentication """ return get("{}/".format(self.host)) def get_server_time(self): """ Returns the current timestamp on the server Does not need authentication """ return get("{}{}".format(self.host, TIME)) def create_api_key(self, nonce: int = None) -> ApiCreds: """ Creates a new CLOB API key for the given """ self.assert_level_1_auth() endpoint = "{}{}".format(self.host, CREATE_API_KEY) headers = create_level_1_headers(self.signer, nonce) creds_raw = post(endpoint, headers=headers) try: creds = ApiCreds( api_key=creds_raw["apiKey"], api_secret=creds_raw["secret"], api_passphrase=creds_raw["passphrase"], ) except: self.logger.error("Couldn't parse created CLOB creds") return None return creds def derive_api_key(self, nonce: int = None) -> ApiCreds: """ Derives an already existing CLOB API key for the given address and nonce """ self.assert_level_1_auth() endpoint = "{}{}".format(self.host, DERIVE_API_KEY) headers = create_level_1_headers(self.signer, nonce) creds_raw = get(endpoint, headers=headers) try: creds = ApiCreds( api_key=creds_raw["apiKey"], api_secret=creds_raw["secret"], api_passphrase=creds_raw["passphrase"], ) except: self.logger.error("Couldn't parse derived CLOB creds") return None return creds def create_or_derive_api_creds(self, nonce: int = None) -> ApiCreds: """ Creates API creds if not already created for nonce, otherwise derives them """ try: return self.create_api_key(nonce) except: return self.derive_api_key(nonce) def set_api_creds(self, creds: ApiCreds): """ Sets client api creds """ self.creds = creds self.mode = self._get_client_mode() def get_api_keys(self): """ Gets the available API keys for this address Level 2 Auth required """ self.assert_level_2_auth() request_args = RequestArgs(method="GET", request_path=GET_API_KEYS) headers = create_level_2_headers(self.signer, self.creds, request_args) return get("{}{}".format(self.host, GET_API_KEYS), headers=headers) def get_closed_only_mode(self): """ Gets the closed only mode flag for thsi address Level 2 Auth required """ self.assert_level_2_auth() request_args = RequestArgs(method="GET", request_path=CLOSED_ONLY) headers = create_level_2_headers(self.signer, self.creds, request_args) return get("{}{}".format(self.host, CLOSED_ONLY), headers=headers) def delete_api_key(self): """ Deletes an API key Level 2 Auth required """ self.assert_level_2_auth() request_args = RequestArgs(method="DELETE", request_path=DELETE_API_KEY) headers = create_level_2_headers(self.signer, self.creds, request_args) return delete("{}{}".format(self.host, DELETE_API_KEY), headers=headers) def create_readonly_api_key(self) -> ReadonlyApiKeyResponse: """ Creates a new readonly API key for a user Level 2 Auth required """ self.assert_level_2_auth() request_args = RequestArgs(method="POST", request_path=CREATE_READONLY_API_KEY) headers = create_level_2_headers(self.signer, self.creds, request_args) response = post("{}{}".format(self.host, CREATE_READONLY_API_KEY), headers=headers) try: return ReadonlyApiKeyResponse(api_key=response["apiKey"]) except: self.logger.error("Couldn't parse readonly API key response") return None def get_readonly_api_keys(self) -> list[str]: """ Gets the available readonly API keys for this address Level 2 Auth required """ self.assert_level_2_auth() request_args = RequestArgs(method="GET", request_path=GET_READONLY_API_KEYS) headers = create_level_2_headers(self.signer, self.creds, request_args) return get("{}{}".format(self.host, GET_READONLY_API_KEYS), headers=headers) def delete_readonly_api_key(self, key: str) -> bool: """ Deletes a readonly API key for a user Level 2 Auth required """ self.assert_level_2_auth() body = {"key": key} serialized = json.dumps(body, separators=(",", ":"), ensure_ascii=False) request_args = RequestArgs( method="DELETE", request_path=DELETE_READONLY_API_KEY, body=body, serialized_body=serialized, ) headers = create_level_2_headers(self.signer, self.creds, request_args) return delete( "{}{}".format(self.host, DELETE_READONLY_API_KEY), headers=headers, data=serialized, ) def validate_readonly_api_key(self, address: str, key: str) -> str: """ Validates a readonly API key for a given address This is a public endpoint, no authentication required """ return get( "{}{}?address={}&key={}".format( self.host, VALIDATE_READONLY_API_KEY, address, key ) ) def get_midpoint(self, token_id): """ Get the mid market price for the given market """ return get("{}{}?token_id={}".format(self.host, MID_POINT, token_id)) def get_midpoints(self, params: list[BookParams]): """ Get the mid market prices for a set of token ids """ body = [{"token_id": param.token_id} for param in params] return post("{}{}".format(self.host, MID_POINTS), data=body) def get_price(self, token_id, side): """ Get the market price for the given market """ return get("{}{}?token_id={}&side={}".format(self.host, PRICE, token_id, side)) def get_prices(self, params: list[BookParams]): """ Get the market prices for a set """ body = [{"token_id": param.token_id, "side": param.side} for param in params] return post("{}{}".format(self.host, GET_PRICES), data=body) def get_spread(self, token_id): """ Get the spread for the given market """ return get("{}{}?token_id={}".format(self.host, GET_SPREAD, token_id)) def get_spreads(self, params: list[BookParams]): """ Get the spreads for a set of token ids """ body = [{"token_id": param.token_id} for param in params] return post("{}{}".format(self.host, GET_SPREADS), data=body) def get_tick_size(self, token_id: str) -> TickSize: cached_at = self.__tick_size_timestamps.get(token_id) if ( token_id in self.__tick_sizes and cached_at is not None and (time.monotonic() - cached_at) < self.__tick_size_ttl ): return self.__tick_sizes[token_id] result = get("{}{}?token_id={}".format(self.host, GET_TICK_SIZE, token_id)) self.__tick_sizes[token_id] = str(result["minimum_tick_size"]) self.__tick_size_timestamps[token_id] = time.monotonic() return self.__tick_sizes[token_id] def clear_tick_size_cache(self, token_id: str = None): """ Clears the tick size cache, forcing fresh fetches on the next access. Args: token_id: If provided, only clears the cache for this token. Otherwise clears all cached tick sizes. """ if token_id is not None: self.__tick_sizes.pop(token_id, None) self.__tick_size_timestamps.pop(token_id, None) else: self.__tick_sizes.clear() self.__tick_size_timestamps.clear() def _update_tick_size_from_order_book(self, book: OrderBookSummary): """ Opportunistically updates the tick size cache from an order book response. """ if book and book.asset_id and book.tick_size: self.__tick_sizes[book.asset_id] = str(book.tick_size) self.__tick_size_timestamps[book.asset_id] = time.monotonic() def get_neg_risk(self, token_id: str) -> bool: if token_id in self.__neg_risk: return self.__neg_risk[token_id] result = get("{}{}?token_id={}".format(self.host, GET_NEG_RISK, token_id)) self.__neg_risk[token_id] = result["neg_risk"] return result["neg_risk"] def get_fee_rate_bps(self, token_id: str) -> int: if token_id in self.__fee_rates: return self.__fee_rates[token_id] result = get("{}{}?token_id={}".format(self.host, GET_FEE_RATE, token_id)) fee_rate = result.get("base_fee") or 0 self.__fee_rates[token_id] = fee_rate return fee_rate def __resolve_tick_size( self, token_id: str, tick_size: TickSize = None ) -> TickSize: min_tick_size = self.get_tick_size(token_id) if tick_size is not None: if is_tick_size_smaller(tick_size, min_tick_size): raise Exception( "invalid tick size (" + str(tick_size) + "), minimum for the market is " + str(min_tick_size), ) else: tick_size = min_tick_size return tick_size def __resolve_fee_rate(self, token_id: str, user_fee_rate: int = None) -> int: market_fee_rate_bps = self.get_fee_rate_bps(token_id) # If both fee rate on the market and the user supplied fee rate are non-zero, validate that they match # else return the market fee rate if ( market_fee_rate_bps is not None and market_fee_rate_bps > 0 and user_fee_rate is not None and user_fee_rate > 0 and user_fee_rate != market_fee_rate_bps ): raise Exception( f"invalid user provided fee rate: ({user_fee_rate}), fee rate for the market must be {market_fee_rate_bps}" ) return market_fee_rate_bps def create_order( self, order_args: OrderArgs, options: Optional[PartialCreateOrderOptions] = None ): """ Creates and signs an order Level 1 Auth required """ self.assert_level_1_auth() # add resolve_order_options, or similar tick_size = self.__resolve_tick_size( order_args.token_id, options.tick_size if options else None, ) if not price_valid(order_args.price, tick_size): raise Exception( "price (" + str(order_args.price) + "), min: " + str(tick_size) + " - max: " + str(1 - float(tick_size)) ) neg_risk = ( options.neg_risk if options and options.neg_risk else self.get_neg_risk(order_args.token_id) ) # fee rate fee_rate_bps = self.__resolve_fee_rate( order_args.token_id, order_args.fee_rate_bps ) order_args.fee_rate_bps = fee_rate_bps return self.builder.create_order( order_args, CreateOrderOptions( tick_size=tick_size, neg_risk=neg_risk, ), ) def create_market_order( self, order_args: MarketOrderArgs, options: Optional[PartialCreateOrderOptions] = None, ): """ Creates and signs an order Level 1 Auth required """ self.assert_level_1_auth() # add resolve_order_options, or similar tick_size = self.__resolve_tick_size( order_args.token_id, options.tick_size if options else None, ) if order_args.price is None or order_args.price <= 0: order_args.price = self.calculate_market_price( order_args.token_id, order_args.side, order_args.amount, order_args.order_type, ) if not price_valid(order_args.price, tick_size): raise Exception( "price (" + str(order_args.price) + "), min: " + str(tick_size) + " - max: " + str(1 - float(tick_size)) ) neg_risk = ( options.neg_risk if options and options.neg_risk else self.get_neg_risk(order_args.token_id) ) # fee rate fee_rate_bps = self.__resolve_fee_rate( order_args.token_id, order_args.fee_rate_bps ) order_args.fee_rate_bps = fee_rate_bps return self.builder.create_market_order( order_args, CreateOrderOptions( tick_size=tick_size, neg_risk=neg_risk, ), ) def post_orders(self, args: list[PostOrdersArgs]): """ Posts orders """ self.assert_level_2_auth() body = [ order_to_json(arg.order, self.creds.api_key, arg.orderType, arg.postOnly) for arg in args ] request_args = RequestArgs( method="POST", request_path=POST_ORDERS, body=body, serialized_body=json.dumps(body, separators=(",", ":"), ensure_ascii=False), ) headers = create_level_2_headers(self.signer, self.creds, request_args) # Builder flow if self.can_builder_auth(): builder_headers = self._generate_builder_headers(request_args, headers) if builder_headers is not None: return post( "{}{}".format(self.host, POST_ORDERS), headers=builder_headers, data=request_args.serialized_body, ) # send exact serialized bytes return post( "{}{}".format(self.host, POST_ORDERS), headers=headers, data=request_args.serialized_body, ) def post_order(self, order, orderType: OrderType = OrderType.GTC, post_only: bool = False): """ Posts the order """ if post_only and (orderType != OrderType.GTC and orderType != OrderType.GTD): raise Exception("post_only orders can only be of type GTC or GTD") self.assert_level_2_auth() body = order_to_json(order, self.creds.api_key, orderType, post_only) request_args = RequestArgs( method="POST", request_path=POST_ORDER, body=body, serialized_body=json.dumps(body, separators=(",", ":"), ensure_ascii=False), ) headers = create_level_2_headers(self.signer, self.creds, request_args) # Builder flow if self.can_builder_auth(): builder_headers = self._generate_builder_headers(request_args, headers) if builder_headers is not None: return post( "{}{}".format(self.host, POST_ORDER), headers=builder_headers, data=request_args.serialized_body, ) return post( "{}{}".format(self.host, POST_ORDER), headers=headers, data=request_args.serialized_body, ) def create_and_post_order( self, order_args: OrderArgs, options: PartialCreateOrderOptions = None ): """ Utility function to create and publish an order """ ord = self.create_order(order_args, options) return self.post_order(ord) def cancel(self, order_id): """ Cancels an order Level 2 Auth required """ self.assert_level_2_auth() body = {"orderID": order_id} request_args = RequestArgs( method="DELETE", request_path=CANCEL, body=body, serialized_body=json.dumps(body, separators=(",", ":"), ensure_ascii=False), ) headers = create_level_2_headers(self.signer, self.creds, request_args) return delete( "{}{}".format(self.host, CANCEL), headers=headers, data=request_args.serialized_body, ) def cancel_orders(self, order_ids): """ Cancels orders Level 2 Auth required """ self.assert_level_2_auth() body = order_ids serialized = json.dumps(body, separators=(",", ":"), ensure_ascii=False) request_args = RequestArgs( method="DELETE", request_path=CANCEL_ORDERS, body=body, serialized_body=serialized, ) headers = create_level_2_headers(self.signer, self.creds, request_args) return delete( "{}{}".format(self.host, CANCEL_ORDERS), headers=headers, data=serialized ) def cancel_all(self): """ Cancels all available orders for the user Level 2 Auth required """ self.assert_level_2_auth() request_args = RequestArgs(method="DELETE", request_path=CANCEL_ALL) headers = create_level_2_headers(self.signer, self.creds, request_args) return delete("{}{}".format(self.host, CANCEL_ALL), headers=headers) def post_heartbeat(self, heartbeat_id: Optional[str]): """ Sends a heartbeat to the server, if heartbeats are started and one isn't sent within 10s, all orders will be cancelled Requires Level 2 authentication """ self.assert_level_2_auth() body = {"heartbeat_id": heartbeat_id} serialized = json.dumps(body, separators=(",", ":"), ensure_ascii=False) request_args = RequestArgs(method="POST", request_path=POST_HEARTBEAT, body=body, serialized_body=serialized) headers = create_level_2_headers(self.signer, self.creds, request_args) return post( "{}{}".format(self.host, POST_HEARTBEAT), headers=headers, data=serialized ) def cancel_market_orders(self, market: str = "", asset_id: str = ""): """ Cancels orders Level 2 Auth required """ self.assert_level_2_auth() body = {"market": market, "asset_id": asset_id} serialized = json.dumps(body, separators=(",", ":"), ensure_ascii=False) request_args = RequestArgs( method="DELETE", request_path=CANCEL_MARKET_ORDERS, body=body, serialized_body=serialized, ) headers = create_level_2_headers(self.signer, self.creds, request_args) return delete( "{}{}".format(self.host, CANCEL_MARKET_ORDERS), headers=headers, data=serialized, ) def get_orders(self, params: OpenOrderParams = None, next_cursor="MA=="): """ Gets orders for the API key Requires Level 2 authentication """ self.assert_level_2_auth() request_args = RequestArgs(method="GET", request_path=ORDERS) headers = create_level_2_headers(self.signer, self.creds, request_args) results = [] next_cursor = next_cursor if next_cursor is not None else "MA==" while next_cursor != END_CURSOR: url = add_query_open_orders_params( "{}{}".format(self.host, ORDERS), params, next_cursor ) response = get(url, headers=headers) next_cursor = response["next_cursor"] results += response["data"] return results def get_order_book(self, token_id) -> OrderBookSummary: """ Fetches the orderbook for the token_id """ raw_obs = get("{}{}?token_id={}".format(self.host, GET_ORDER_BOOK, token_id)) result = parse_raw_orderbook_summary(raw_obs) self._update_tick_size_from_order_book(result) return result def get_order_books(self, params: list[BookParams]) -> list[OrderBookSummary]: """ Fetches the orderbook for a set of token ids """ body = [{"token_id": param.token_id} for param in params] raw_obs = post("{}{}".format(self.host, GET_ORDER_BOOKS), data=body) results = [parse_raw_orderbook_summary(r) for r in raw_obs] for book in results: self._update_tick_size_from_order_book(book) return results def get_order_book_hash(self, orderbook: OrderBookSummary) -> str: """ Calculates the hash for the given orderbook """ return generate_orderbook_summary_hash(orderbook) def get_order(self, order_id): """ Fetches the order corresponding to the order_id Requires Level 2 authentication """ self.assert_level_2_auth() endpoint = "{}{}".format(GET_ORDER, order_id) request_args = RequestArgs(method="GET", request_path=endpoint) headers = create_level_2_headers(self.signer, self.creds, request_args) return get("{}{}".format(self.host, endpoint), headers=headers) def get_trades(self, params: TradeParams = None, next_cursor="MA=="): """ Fetches the trade history for a user Requires Level 2 authentication """ self.assert_level_2_auth() request_args = RequestArgs(method="GET", request_path=TRADES) headers = create_level_2_headers(self.signer, self.creds, request_args) results = [] next_cursor = next_cursor if next_cursor is not None else "MA==" while next_cursor != END_CURSOR: url = add_query_trade_params( "{}{}".format(self.host, TRADES), params, next_cursor ) response = get(url, headers=headers) next_cursor = response["next_cursor"] results += response["data"] return results def get_last_trade_price(self, token_id): """ Fetches the last trade price token_id """ return get("{}{}?token_id={}".format(self.host, GET_LAST_TRADE_PRICE, token_id)) def get_last_trades_prices(self, params: list[BookParams]): """ Fetches the last trades prices for a set of token ids """ body = [{"token_id": param.token_id} for param in params] return post("{}{}".format(self.host, GET_LAST_TRADES_PRICES), data=body) def assert_level_1_auth(self): """ Level 1 Poly Auth """ if self.mode < L1: raise PolyException(L1_AUTH_UNAVAILABLE) def assert_level_2_auth(self): """ Level 2 Poly Auth """ if self.mode < L2: raise PolyException(L2_AUTH_UNAVAILABLE) def assert_builder_auth(self): """ Builder Auth """ if not self.can_builder_auth(): raise PolyException(BUILDER_AUTH_UNAVAILABLE) def can_builder_auth(self) -> bool: return self.builder_config is not None and self.builder_config.is_valid() def _get_client_mode(self): if self.signer is not None and self.creds is not None: return L2 if self.signer is not None: return L1 return L0 def _generate_builder_headers(self, request_args: RequestArgs, headers: dict): """ Generates builder headers and attaches them to the L2 Header """ if self.builder_config is not None: builder_headers = self._get_builder_headers( request_args.method, request_args.request_path, request_args.serialized_body, ) if builder_headers is None: return None return enrich_l2_headers_with_builder_headers(headers, builder_headers) return None def _get_builder_headers(self, method: str, path: str, body: Optional[str] = None): """ Generates builder headers for the given method, path, and body. Args: method (str): HTTP method. path (str): Request path. body (Optional[str]): Pre-serialized JSON string or None. Returns: dict or None: Builder headers as a dictionary, or None if not available. """ headers = self.builder_config.generate_builder_headers(method, path, body) if headers: return headers.to_dict() return None def get_notifications(self): """ Fetches the notifications for a user Requires Level 2 authentication """ self.assert_level_2_auth() request_args = RequestArgs(method="GET", request_path=GET_NOTIFICATIONS) headers = create_level_2_headers(self.signer, self.creds, request_args) url = "{}{}?signature_type={}".format( self.host, GET_NOTIFICATIONS, self.builder.sig_type ) return get(url, headers=headers) def drop_notifications(self, params: DropNotificationParams = None): """ Drops the notifications for a user Requires Level 2 authentication """ self.assert_level_2_auth() request_args = RequestArgs(method="DELETE", request_path=DROP_NOTIFICATIONS) headers = create_level_2_headers(self.signer, self.creds, request_args) url = drop_notifications_query_params( "{}{}".format(self.host, DROP_NOTIFICATIONS), params ) return delete(url, headers=headers) def get_balance_allowance(self, params: BalanceAllowanceParams = None): """ Fetches the balance & allowance for a user Requires Level 2 authentication """ self.assert_level_2_auth() request_args = RequestArgs(method="GET", request_path=GET_BALANCE_ALLOWANCE) headers = create_level_2_headers(self.signer, self.creds, request_args) if params.signature_type == -1: params.signature_type = self.builder.sig_type url = add_balance_allowance_params_to_url( "{}{}".format(self.host, GET_BALANCE_ALLOWANCE), params ) return get(url, headers=headers) def update_balance_allowance(self, params: BalanceAllowanceParams = None): """ Updates the balance & allowance for a user Requires Level 2 authentication """ self.assert_level_2_auth() request_args = RequestArgs(method="GET", request_path=UPDATE_BALANCE_ALLOWANCE) headers = create_level_2_headers(self.signer, self.creds, request_args) if params.signature_type == -1: params.signature_type = self.builder.sig_type url = add_balance_allowance_params_to_url( "{}{}".format(self.host, UPDATE_BALANCE_ALLOWANCE), params ) return get(url, headers=headers) def is_order_scoring(self, params: OrderScoringParams): """ Check if the order is currently scoring Requires Level 2 authentication """ self.assert_level_2_auth() request_args = RequestArgs(method="GET", request_path=IS_ORDER_SCORING) headers = create_level_2_headers(self.signer, self.creds, request_args) url = add_order_scoring_params_to_url( "{}{}".format(self.host, IS_ORDER_SCORING), params ) return get(url, headers=headers) def are_orders_scoring(self, params: OrdersScoringParams): """ Check if the orders are currently scoring Requires Level 2 authentication """ self.assert_level_2_auth() body = params.orderIds serialized = json.dumps(body, separators=(",", ":"), ensure_ascii=False) request_args = RequestArgs( method="POST", request_path=ARE_ORDERS_SCORING, body=body, serialized_body=serialized, ) headers = create_level_2_headers(self.signer, self.creds, request_args) return post( "{}{}".format(self.host, ARE_ORDERS_SCORING), headers=headers, data=serialized, ) def get_sampling_markets(self, next_cursor="MA=="): """ Get the current sampling markets """ return get( "{}{}?next_cursor={}".format(self.host, GET_SAMPLING_MARKETS, next_cursor) ) def get_sampling_simplified_markets(self, next_cursor="MA=="): """ Get the current sampling simplified markets """ return get( "{}{}?next_cursor={}".format( self.host, GET_SAMPLING_SIMPLIFIED_MARKETS, next_cursor ) ) def get_markets(self, next_cursor="MA=="): """ Get the current markets """ return get("{}{}?next_cursor={}".format(self.host, GET_MARKETS, next_cursor)) def get_simplified_markets(self, next_cursor="MA=="): """ Get the current simplified markets """ return get( "{}{}?next_cursor={}".format(self.host, GET_SIMPLIFIED_MARKETS, next_cursor) ) def get_market(self, condition_id): """ Get a market by condition_id """ return get("{}{}{}".format(self.host, GET_MARKET, condition_id)) def get_market_trades_events(self, condition_id): """ Get the market's trades events by condition id """ return get("{}{}{}".format(self.host, GET_MARKET_TRADES_EVENTS, condition_id)) def get_builder_trades(self, params: TradeParams = None, next_cursor="MA=="): """ Get trades originated by the builder """ self.assert_builder_auth() request_args = RequestArgs(method="GET", request_path=GET_BUILDER_TRADES) headers = self._get_builder_headers( request_args.method, request_args.request_path, request_args.body ) results = [] next_cursor = next_cursor if next_cursor is not None else "MA==" while next_cursor != END_CURSOR: url = add_query_trade_params( "{}{}".format(self.host, GET_BUILDER_TRADES), params, next_cursor ) response = get(url, headers=headers) next_cursor = response["next_cursor"] results += response["data"] return results def calculate_market_price( self, token_id: str, side: str, amount: float, order_type: OrderType ) -> float: """ Calculates the matching price considering an amount and the current orderbook """ book = self.get_order_book(token_id) if book is None: raise Exception("no orderbook") if side == "BUY": if book.asks is None: raise Exception("no match") return self.builder.calculate_buy_market_price( book.asks, amount, order_type ) else: if book.bids is None: raise Exception("no match") return self.builder.calculate_sell_market_price( book.bids, amount, order_type ) ================================================ FILE: py_clob_client/clob_types.py ================================================ from typing import Any from dataclasses import dataclass, asdict from json import dumps from typing import Literal, Optional from py_order_utils.model import ( SignedOrder, ) from .constants import ZERO_ADDRESS class OrderType(enumerate): GTC = "GTC" FOK = "FOK" GTD = "GTD" FAK = "FAK" @dataclass class ApiCreds: api_key: str api_secret: str api_passphrase: str @dataclass class ReadonlyApiKeyResponse: api_key: str @dataclass class RequestArgs: method: str request_path: str body: Any = None serialized_body: Optional[str] = None @dataclass class BookParams: token_id: str side: str = "" @dataclass class OrderArgs: token_id: str """ TokenID of the Conditional token asset being traded """ price: float """ Price used to create the order """ size: float """ Size in terms of the ConditionalToken """ side: str """ Side of the order """ fee_rate_bps: int = 0 """ Fee rate, in basis points, charged to the order maker, charged on proceeds """ nonce: int = 0 """ Nonce used for onchain cancellations """ expiration: int = 0 """ Timestamp after which the order is expired. """ taker: str = ZERO_ADDRESS """ Address of the order taker. The zero address is used to indicate a public order """ @dataclass class MarketOrderArgs: token_id: str """ TokenID of the Conditional token asset being traded """ amount: float """ BUY orders: $$$ Amount to buy SELL orders: Shares to sell """ side: str """ Side of the order """ price: float = 0 """ Price used to create the order """ fee_rate_bps: int = 0 """ Fee rate, in basis points, charged to the order maker, charged on proceeds """ nonce: int = 0 """ Nonce used for onchain cancellations """ taker: str = ZERO_ADDRESS """ Address of the order taker. The zero address is used to indicate a public order """ order_type: OrderType = OrderType.FOK @dataclass class TradeParams: id: str = None maker_address: str = None market: str = None asset_id: str = None before: int = None after: int = None @dataclass class OpenOrderParams: id: str = None market: str = None asset_id: str = None @dataclass class DropNotificationParams: ids: list[str] = None @dataclass class OrderSummary: price: str = None size: str = None @property def __dict__(self): return asdict(self) @property def json(self): return dumps(self.__dict__) @dataclass class OrderBookSummary: market: str = None asset_id: str = None timestamp: str = None bids: list[OrderSummary] = None asks: list[OrderSummary] = None min_order_size: str = None neg_risk: bool = None tick_size: str = None last_trade_price: str = None hash: str = None @property def __dict__(self): return asdict(self) @property def json(self): return dumps(self.__dict__, separators=(",", ":")) class AssetType(enumerate): COLLATERAL = "COLLATERAL" CONDITIONAL = "CONDITIONAL" @dataclass class BalanceAllowanceParams: asset_type: AssetType = None token_id: str = None signature_type: int = -1 @dataclass class OrderScoringParams: orderId: str @dataclass class OrdersScoringParams: orderIds: list[str] TickSize = Literal["0.1", "0.01", "0.001", "0.0001"] @dataclass class CreateOrderOptions: tick_size: TickSize neg_risk: bool @dataclass class PartialCreateOrderOptions: tick_size: Optional[TickSize] = None neg_risk: Optional[bool] = None @dataclass class RoundConfig: price: float size: float amount: float @dataclass class ContractConfig: """ Contract Configuration """ exchange: str """ The exchange contract responsible for matching orders """ collateral: str """ The ERC20 token used as collateral for the exchange's markets """ conditional_tokens: str """ The ERC1155 conditional tokens contract """ @dataclass class PostOrdersArgs: order: SignedOrder orderType: OrderType = OrderType.GTC postOnly: bool = False ================================================ FILE: py_clob_client/config.py ================================================ from .clob_types import ContractConfig def get_contract_config(chainID: int, neg_risk: bool = False) -> ContractConfig: """ Get the contract configuration for the chain """ CONFIG = { 137: ContractConfig( exchange="0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E", collateral="0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174", conditional_tokens="0x4D97DCd97eC945f40cF65F87097ACe5EA0476045", ), 80002: ContractConfig( exchange="0xdFE02Eb6733538f8Ea35D585af8DE5958AD99E40", collateral="0x9c4e1703476e875070ee25b56a58b008cfb8fa78", conditional_tokens="0x69308FB512518e39F9b16112fA8d994F4e2Bf8bB", ), } NEG_RISK_CONFIG = { 137: ContractConfig( exchange="0xC5d563A36AE78145C45a50134d48A1215220f80a", collateral="0x2791bca1f2de4661ed88a30c99a7a9449aa84174", conditional_tokens="0x4D97DCd97eC945f40cF65F87097ACe5EA0476045", ), 80002: ContractConfig( exchange="0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296", collateral="0x9c4e1703476e875070ee25b56a58b008cfb8fa78", conditional_tokens="0x69308FB512518e39F9b16112fA8d994F4e2Bf8bB", ), } if neg_risk: config = NEG_RISK_CONFIG.get(chainID) else: config = CONFIG.get(chainID) if config is None: raise Exception("Invalid chainID: ${}".format(chainID)) return config ================================================ FILE: py_clob_client/constants.py ================================================ # Access levels L0 = 0 L1 = 1 L2 = 2 CREDENTIAL_CREATION_WARNING = """🚨🚨🚨 Your credentials CANNOT be recovered after they've been created. Be sure to store them safely! 🚨🚨🚨""" L1_AUTH_UNAVAILABLE = "A private key is needed to interact with this endpoint!" L2_AUTH_UNAVAILABLE = "API Credentials are needed to interact with this endpoint!" BUILDER_AUTH_UNAVAILABLE = ( "Builder API Credentials needed to interact with this endpoint!" ) ZERO_ADDRESS = "0x0000000000000000000000000000000000000000" AMOY = 80002 POLYGON = 137 END_CURSOR = "LTE=" ================================================ FILE: py_clob_client/endpoints.py ================================================ TIME = "/time" CREATE_API_KEY = "/auth/api-key" GET_API_KEYS = "/auth/api-keys" DELETE_API_KEY = "/auth/api-key" DERIVE_API_KEY = "/auth/derive-api-key" CLOSED_ONLY = "/auth/ban-status/closed-only" # Readonly API Key endpoints CREATE_READONLY_API_KEY = "/auth/readonly-api-key" GET_READONLY_API_KEYS = "/auth/readonly-api-keys" DELETE_READONLY_API_KEY = "/auth/readonly-api-key" VALIDATE_READONLY_API_KEY = "/auth/validate-readonly-api-key" TRADES = "/data/trades" GET_ORDER_BOOK = "/book" GET_ORDER_BOOKS = "/books" GET_ORDER = "/data/order/" ORDERS = "/data/orders" POST_ORDER = "/order" POST_ORDERS = "/orders" CANCEL = "/order" CANCEL_ORDERS = "/orders" CANCEL_ALL = "/cancel-all" CANCEL_MARKET_ORDERS = "/cancel-market-orders" MID_POINT = "/midpoint" MID_POINTS = "/midpoints" PRICE = "/price" GET_PRICES = "/prices" GET_SPREAD = "/spread" GET_SPREADS = "/spreads" GET_LAST_TRADE_PRICE = "/last-trade-price" GET_LAST_TRADES_PRICES = "/last-trades-prices" GET_NOTIFICATIONS = "/notifications" DROP_NOTIFICATIONS = "/notifications" GET_BALANCE_ALLOWANCE = "/balance-allowance" UPDATE_BALANCE_ALLOWANCE = "/balance-allowance/update" IS_ORDER_SCORING = "/order-scoring" ARE_ORDERS_SCORING = "/orders-scoring" GET_TICK_SIZE = "/tick-size" GET_NEG_RISK = "/neg-risk" GET_FEE_RATE = "/fee-rate" GET_SAMPLING_SIMPLIFIED_MARKETS = "/sampling-simplified-markets" GET_SAMPLING_MARKETS = "/sampling-markets" GET_SIMPLIFIED_MARKETS = "/simplified-markets" GET_MARKETS = "/markets" GET_MARKET = "/markets/" GET_MARKET_TRADES_EVENTS = "/live-activity/events/" POST_HEARTBEAT = "/v1/heartbeats" GET_BUILDER_TRADES = "/builder/trades" # RFQ Endpoints CREATE_RFQ_REQUEST = "/rfq/request" CANCEL_RFQ_REQUEST = "/rfq/request" GET_RFQ_REQUESTS = "/rfq/data/requests" CREATE_RFQ_QUOTE = "/rfq/quote" CANCEL_RFQ_QUOTE = "/rfq/quote" GET_RFQ_REQUESTER_QUOTES = "/rfq/data/requester/quotes" GET_RFQ_QUOTER_QUOTES = "/rfq/data/quoter/quotes" GET_RFQ_BEST_QUOTE = "/rfq/data/best-quote" RFQ_REQUESTS_ACCEPT = "/rfq/request/accept" RFQ_QUOTE_APPROVE = "/rfq/quote/approve" RFQ_CONFIG = "/rfq/config" ================================================ FILE: py_clob_client/exceptions.py ================================================ from typing import Optional import httpx class PolyException(Exception): def __init__(self, msg): self.msg = msg class PolyApiException(PolyException): def __init__(self, resp: Optional[httpx.Response] = None, error_msg=None): assert resp is not None or error_msg is not None if resp is not None: self.status_code = resp.status_code self.error_msg = self._get_message(resp) else: self.status_code = None self.error_msg = error_msg def _get_message(self, resp: httpx.Response): try: return resp.json() except Exception: return resp.text def __repr__(self): return f"PolyApiException[status_code={self.status_code}, error_message={self.error_msg}]" def __str__(self): return self.__repr__() ================================================ FILE: py_clob_client/headers/__init__.py ================================================ ================================================ FILE: py_clob_client/headers/headers.py ================================================ from ..clob_types import ApiCreds, RequestArgs from ..signing.hmac import build_hmac_signature from ..signer import Signer from ..signing.eip712 import sign_clob_auth_message from datetime import datetime POLY_ADDRESS = "POLY_ADDRESS" POLY_SIGNATURE = "POLY_SIGNATURE" POLY_TIMESTAMP = "POLY_TIMESTAMP" POLY_NONCE = "POLY_NONCE" POLY_API_KEY = "POLY_API_KEY" POLY_PASSPHRASE = "POLY_PASSPHRASE" def create_level_1_headers(signer: Signer, nonce: int = None): """ Creates Level 1 Poly headers for a request """ timestamp = int(datetime.now().timestamp()) n = 0 if nonce is not None: n = nonce signature = sign_clob_auth_message(signer, timestamp, n) headers = { POLY_ADDRESS: signer.address(), POLY_SIGNATURE: signature, POLY_TIMESTAMP: str(timestamp), POLY_NONCE: str(n), } return headers def create_level_2_headers(signer: Signer, creds: ApiCreds, request_args: RequestArgs): """Creates Level 2 Poly headers for a request using pre-serialized body if provided""" timestamp = int(datetime.now().timestamp()) # Prefer the pre-serialized body string for deterministic signing if available body_for_sig = ( request_args.serialized_body if request_args.serialized_body is not None else request_args.body ) hmac_sig = build_hmac_signature( creds.api_secret, timestamp, request_args.method, request_args.request_path, body_for_sig, ) return { POLY_ADDRESS: signer.address(), POLY_SIGNATURE: hmac_sig, POLY_TIMESTAMP: str(timestamp), POLY_API_KEY: creds.api_key, POLY_PASSPHRASE: creds.api_passphrase, } def enrich_l2_headers_with_builder_headers( headers: dict, builder_headers: dict ) -> dict: return {**headers, **builder_headers} ================================================ FILE: py_clob_client/http_helpers/__init__.py ================================================ ================================================ FILE: py_clob_client/http_helpers/helpers.py ================================================ import httpx from py_clob_client.clob_types import ( DropNotificationParams, BalanceAllowanceParams, OrderScoringParams, OrdersScoringParams, TradeParams, OpenOrderParams, ) from ..exceptions import PolyApiException GET = "GET" POST = "POST" DELETE = "DELETE" PUT = "PUT" _http_client = httpx.Client(http2=True) def overloadHeaders(method: str, headers: dict) -> dict: if headers is None: headers = dict() headers["User-Agent"] = "py_clob_client" headers["Accept"] = "*/*" headers["Connection"] = "keep-alive" headers["Content-Type"] = "application/json" if method == GET: headers["Accept-Encoding"] = "gzip" return headers def request(endpoint: str, method: str, headers=None, data=None): try: headers = overloadHeaders(method, headers) if isinstance(data, str): # Pre-serialized body: send exact bytes resp = _http_client.request( method=method, url=endpoint, headers=headers, content=data.encode("utf-8"), ) else: resp = _http_client.request( method=method, url=endpoint, headers=headers, json=data, ) if resp.status_code != 200: raise PolyApiException(resp) try: return resp.json() except ValueError: return resp.text except httpx.RequestError: raise PolyApiException(error_msg="Request exception!") def post(endpoint, headers=None, data=None): return request(endpoint, POST, headers, data) def get(endpoint, headers=None, data=None): return request(endpoint, GET, headers, data) def delete(endpoint, headers=None, data=None): return request(endpoint, DELETE, headers, data) def put(endpoint, headers=None, data=None): return request(endpoint, PUT, headers, data) def build_query_params(url: str, param: str, val: str) -> str: url_with_params = url last = url_with_params[-1] # if last character in url string == "?", append the param directly: api.com?param=value if last == "?": url_with_params = "{}{}={}".format(url_with_params, param, val) else: # else add "&", then append the param url_with_params = "{}&{}={}".format(url_with_params, param, val) return url_with_params def add_query_trade_params( base_url: str, params: TradeParams = None, next_cursor="MA==" ) -> str: """ Adds query parameters to a url """ url = base_url # Include `next_cursor` even when `params` is None to advance pagination. has_query = bool(next_cursor) or ( bool(params) and any( [ params.market, params.asset_id, params.after, params.before, params.maker_address, params.id, ] ) ) if has_query: url = url + "?" if params: if params.market: url = build_query_params(url, "market", params.market) if params.asset_id: url = build_query_params(url, "asset_id", params.asset_id) if params.after: url = build_query_params(url, "after", params.after) if params.before: url = build_query_params(url, "before", params.before) if params.maker_address: url = build_query_params(url, "maker_address", params.maker_address) if params.id: url = build_query_params(url, "id", params.id) if next_cursor: url = build_query_params(url, "next_cursor", next_cursor) return url def add_query_open_orders_params( base_url: str, params: OpenOrderParams = None, next_cursor="MA==" ) -> str: """ Adds query parameters to a url """ url = base_url # Include `next_cursor` even when `params` is None to advance pagination. has_query = bool(next_cursor) or ( bool(params) and any([params.market, params.asset_id, params.id]) ) if has_query: url = url + "?" if params: if params.market: url = build_query_params(url, "market", params.market) if params.asset_id: url = build_query_params(url, "asset_id", params.asset_id) if params.id: url = build_query_params(url, "id", params.id) if next_cursor: url = build_query_params(url, "next_cursor", next_cursor) return url def drop_notifications_query_params( base_url: str, params: DropNotificationParams = None ) -> str: """ Adds query parameters to a url """ url = base_url if params: url = url + "?" if params.ids: url = build_query_params(url, "ids", ",".join(params.ids)) return url def add_balance_allowance_params_to_url( base_url: str, params: BalanceAllowanceParams = None ) -> str: """ Adds query parameters to a url """ url = base_url if params: url = url + "?" if params.asset_type: url = build_query_params(url, "asset_type", params.asset_type.__str__()) if params.token_id: url = build_query_params(url, "token_id", params.token_id) if params.signature_type is not None: url = build_query_params(url, "signature_type", params.signature_type) return url def add_order_scoring_params_to_url( base_url: str, params: OrderScoringParams = None ) -> str: """ Adds query parameters to a url """ url = base_url if params: url = url + "?" if params.orderId: url = build_query_params(url, "order_id", params.orderId) return url def add_orders_scoring_params_to_url( base_url: str, params: OrdersScoringParams = None ) -> str: """ Adds query parameters to a url """ url = base_url if params: url = url + "?" if params.orderIds: url = build_query_params(url, "order_ids", ",".join(params.orderIds)) return url ================================================ FILE: py_clob_client/order_builder/__init__.py ================================================ ================================================ FILE: py_clob_client/order_builder/builder.py ================================================ from py_order_utils.builders import OrderBuilder as UtilsOrderBuilder from py_order_utils.signer import Signer as UtilsSigner from py_order_utils.model import ( EOA, OrderData, SignedOrder, BUY as UtilsBuy, SELL as UtilsSell, ) from .helpers import ( to_token_decimals, round_down, round_normal, decimal_places, round_up, ) from .constants import BUY, SELL from ..config import get_contract_config from ..signer import Signer from ..clob_types import ( OrderArgs, CreateOrderOptions, TickSize, RoundConfig, MarketOrderArgs, OrderSummary, OrderType, ) ROUNDING_CONFIG: dict[TickSize, RoundConfig] = { "0.1": RoundConfig(price=1, size=2, amount=3), "0.01": RoundConfig(price=2, size=2, amount=4), "0.001": RoundConfig(price=3, size=2, amount=5), "0.0001": RoundConfig(price=4, size=2, amount=6), } class OrderBuilder: def __init__(self, signer: Signer, sig_type=None, funder=None): self.signer = signer # Signature type used sign orders, defaults to EOA type self.sig_type = sig_type if sig_type is not None else EOA # Address which holds funds to be used. # Used for Polymarket proxy wallets and other smart contract wallets # Defaults to the address of the signer self.funder = funder if funder is not None else self.signer.address() def get_order_amounts( self, side: str, size: float, price: float, round_config: RoundConfig ): raw_price = round_normal(price, round_config.price) if side == BUY: raw_taker_amt = round_down(size, round_config.size) raw_maker_amt = raw_taker_amt * raw_price if decimal_places(raw_maker_amt) > round_config.amount: raw_maker_amt = round_up(raw_maker_amt, round_config.amount + 4) if decimal_places(raw_maker_amt) > round_config.amount: raw_maker_amt = round_down(raw_maker_amt, round_config.amount) maker_amount = to_token_decimals(raw_maker_amt) taker_amount = to_token_decimals(raw_taker_amt) return UtilsBuy, maker_amount, taker_amount elif side == SELL: raw_maker_amt = round_down(size, round_config.size) raw_taker_amt = raw_maker_amt * raw_price if decimal_places(raw_taker_amt) > round_config.amount: raw_taker_amt = round_up(raw_taker_amt, round_config.amount + 4) if decimal_places(raw_taker_amt) > round_config.amount: raw_taker_amt = round_down(raw_taker_amt, round_config.amount) maker_amount = to_token_decimals(raw_maker_amt) taker_amount = to_token_decimals(raw_taker_amt) return UtilsSell, maker_amount, taker_amount else: raise ValueError(f"order_args.side must be '{BUY}' or '{SELL}'") def get_market_order_amounts( self, side: str, amount: float, price: float, round_config: RoundConfig ): raw_price = round_normal(price, round_config.price) if side == BUY: raw_maker_amt = round_down(amount, round_config.size) raw_taker_amt = raw_maker_amt / raw_price if decimal_places(raw_taker_amt) > round_config.amount: raw_taker_amt = round_up(raw_taker_amt, round_config.amount + 4) if decimal_places(raw_taker_amt) > round_config.amount: raw_taker_amt = round_down(raw_taker_amt, round_config.amount) maker_amount = to_token_decimals(raw_maker_amt) taker_amount = to_token_decimals(raw_taker_amt) return UtilsBuy, maker_amount, taker_amount elif side == SELL: raw_maker_amt = round_down(amount, round_config.size) raw_taker_amt = raw_maker_amt * raw_price if decimal_places(raw_taker_amt) > round_config.amount: raw_taker_amt = round_up(raw_taker_amt, round_config.amount + 4) if decimal_places(raw_taker_amt) > round_config.amount: raw_taker_amt = round_down(raw_taker_amt, round_config.amount) maker_amount = to_token_decimals(raw_maker_amt) taker_amount = to_token_decimals(raw_taker_amt) return UtilsSell, maker_amount, taker_amount else: raise ValueError(f"order_args.side must be '{BUY}' or '{SELL}'") def create_order( self, order_args: OrderArgs, options: CreateOrderOptions ) -> SignedOrder: """ Creates and signs an order """ side, maker_amount, taker_amount = self.get_order_amounts( order_args.side, order_args.size, order_args.price, ROUNDING_CONFIG[options.tick_size], ) data = OrderData( maker=self.funder, taker=order_args.taker, tokenId=order_args.token_id, makerAmount=str(maker_amount), takerAmount=str(taker_amount), side=side, feeRateBps=str(order_args.fee_rate_bps), nonce=str(order_args.nonce), signer=self.signer.address(), expiration=str(order_args.expiration), signatureType=self.sig_type, ) contract_config = get_contract_config( self.signer.get_chain_id(), options.neg_risk ) order_builder = UtilsOrderBuilder( contract_config.exchange, self.signer.get_chain_id(), UtilsSigner(key=self.signer.private_key), ) return order_builder.build_signed_order(data) def create_market_order( self, order_args: MarketOrderArgs, options: CreateOrderOptions ) -> SignedOrder: """ Creates and signs a market order """ side, maker_amount, taker_amount = self.get_market_order_amounts( order_args.side, order_args.amount, order_args.price, ROUNDING_CONFIG[options.tick_size], ) data = OrderData( maker=self.funder, taker=order_args.taker, tokenId=order_args.token_id, makerAmount=str(maker_amount), takerAmount=str(taker_amount), side=side, feeRateBps=str(order_args.fee_rate_bps), nonce=str(order_args.nonce), signer=self.signer.address(), expiration="0", signatureType=self.sig_type, ) contract_config = get_contract_config( self.signer.get_chain_id(), options.neg_risk ) order_builder = UtilsOrderBuilder( contract_config.exchange, self.signer.get_chain_id(), UtilsSigner(key=self.signer.private_key), ) return order_builder.build_signed_order(data) def calculate_buy_market_price( self, positions: list[OrderSummary], amount_to_match: float, order_type: OrderType, ) -> float: if not positions: raise Exception("no match") sum = 0 for p in reversed(positions): sum += float(p.size) * float(p.price) if sum >= amount_to_match: return float(p.price) if order_type == OrderType.FOK: raise Exception("no match") return float(positions[0].price) def calculate_sell_market_price( self, positions: list[OrderSummary], amount_to_match: float, order_type: OrderType, ) -> float: if not positions: raise Exception("no match") sum = 0 for p in reversed(positions): sum += float(p.size) if sum >= amount_to_match: return float(p.price) if order_type == OrderType.FOK: raise Exception("no match") return float(positions[0].price) ================================================ FILE: py_clob_client/order_builder/constants.py ================================================ BUY = "BUY" SELL = "SELL" ================================================ FILE: py_clob_client/order_builder/helpers.py ================================================ from math import floor, ceil from decimal import Decimal def round_down(x: float, sig_digits: int) -> float: return floor(x * (10**sig_digits)) / (10**sig_digits) def round_normal(x: float, sig_digits: int) -> float: return round(x * (10**sig_digits)) / (10**sig_digits) def round_up(x: float, sig_digits: int) -> float: return ceil(x * (10**sig_digits)) / (10**sig_digits) def to_token_decimals(x: float) -> int: f = (10**6) * x if decimal_places(f) > 0: f = round_normal(f, 0) return int(f) def decimal_places(x: float) -> int: return abs(Decimal(x.__str__()).as_tuple().exponent) ================================================ FILE: py_clob_client/rfq/__init__.py ================================================ from .rfq_types import ( # Input types RfqUserRequest, RfqUserQuote, CreateRfqRequestParams, CreateRfqQuoteParams, CancelRfqRequestParams, CancelRfqQuoteParams, AcceptQuoteParams, ApproveOrderParams, GetRfqRequestsParams, GetRfqQuotesParams, GetRfqBestQuoteParams, # Response types RfqRequest, RfqQuote, RfqRequestResponse, RfqQuoteResponse, RfqPaginatedResponse, ) from .rfq_helpers import ( parse_units, to_camel_case, parse_rfq_requests_params, parse_rfq_quotes_params, COLLATERAL_TOKEN_DECIMALS, CONDITIONAL_TOKEN_DECIMALS, ) from .rfq_client import RfqClient __all__ = [ # Client "RfqClient", # Input types "RfqUserRequest", "RfqUserQuote", "CreateRfqRequestParams", "CreateRfqQuoteParams", "CancelRfqRequestParams", "CancelRfqQuoteParams", "AcceptQuoteParams", "ApproveOrderParams", "GetRfqRequestsParams", "GetRfqQuotesParams", "GetRfqBestQuoteParams", # Response types "RfqRequest", "RfqQuote", "RfqRequestResponse", "RfqQuoteResponse", "RfqPaginatedResponse", # Helpers "parse_units", "to_camel_case", "parse_rfq_requests_params", "parse_rfq_quotes_params", "COLLATERAL_TOKEN_DECIMALS", "CONDITIONAL_TOKEN_DECIMALS", ] ================================================ FILE: py_clob_client/rfq/rfq_client.py ================================================ """ RFQ (Request for Quote) client for the Polymarket CLOB API. This module provides the RfqClient class which handles all RFQ operations including creating requests, quotes, and executing trades. """ import logging import json from urllib.parse import urlencode from typing import Optional, Any, TYPE_CHECKING from ..clob_types import RequestArgs, OrderArgs, PartialCreateOrderOptions from ..headers.headers import create_level_2_headers from ..http_helpers.helpers import get, post, delete from ..order_builder.builder import ROUNDING_CONFIG from ..order_builder.helpers import round_normal, round_down from ..order_builder.constants import BUY, SELL from ..endpoints import ( CREATE_RFQ_REQUEST, CANCEL_RFQ_REQUEST, GET_RFQ_REQUESTS, CREATE_RFQ_QUOTE, CANCEL_RFQ_QUOTE, GET_RFQ_REQUESTER_QUOTES, GET_RFQ_QUOTER_QUOTES, GET_RFQ_BEST_QUOTE, RFQ_REQUESTS_ACCEPT, RFQ_QUOTE_APPROVE, RFQ_CONFIG, ) from .rfq_types import ( RfqUserRequest, RfqUserQuote, CancelRfqRequestParams, CancelRfqQuoteParams, AcceptQuoteParams, ApproveOrderParams, GetRfqRequestsParams, GetRfqQuotesParams, GetRfqBestQuoteParams, MatchType, ) from .rfq_helpers import ( parse_units, parse_rfq_requests_params, parse_rfq_quotes_params, COLLATERAL_TOKEN_DECIMALS, ) if TYPE_CHECKING: from ..client import ClobClient class RfqClient: """ RFQ client for creating and managing RFQ requests and quotes. This client is typically accessed via the parent ClobClient's `rfq` attribute: client = ClobClient(host, chain_id, key, creds) response = client.rfq.create_rfq_request(user_request) """ def __init__(self, parent: "ClobClient"): """ Initialize the RFQ client. Args: parent: The parent ClobClient instance providing auth and config. """ self._parent = parent self.logger = logging.getLogger(self.__class__.__name__) def _ensure_l2_auth(self) -> None: """ Verify that L2 authentication is available. Raises: PolyException: If signer or creds are not configured. """ self._parent.assert_level_2_auth() def _get_l2_headers(self, method: str, endpoint: str, body: Any = None, serialized_body: Any = None) -> dict: """ Create L2 authentication headers for a request. Args: method: HTTP method (GET, POST, PUT, DELETE) endpoint: API endpoint path body: Optional request body Returns: Dictionary of authentication headers. """ request_args = RequestArgs(method=method, request_path=endpoint, body=body) if serialized_body is not None: request_args.serialized_body = serialized_body return create_level_2_headers( self._parent.signer, self._parent.creds, request_args, ) def _build_url(self, endpoint: str) -> str: """Build full URL from endpoint.""" return f"{self._parent.host}{endpoint}" # ========================================================================= # Request-side methods # ========================================================================= def create_rfq_request( self, user_request: RfqUserRequest, options: Optional[PartialCreateOrderOptions] = None, ) -> dict: """ Create and post an RFQ request from a user request. This method: 1. Resolves the tick size for the token 2. Rounds price and size according to tick size rules 3. Calculates amount_in and amount_out based on side 4. Posts the request to the server Args: user_order: Simplified order with token_id, price, side, size options: Optional tick size override Returns: Response dict with request_id on success. Example: >>> response = client.rfq.create_rfq_request( ... RfqUserRequest( ... token_id="123...", ... price=0.5, ... side="BUY", ... size=40, ... ) ... ) """ token_id = user_request.token_id price = user_request.price side = user_request.side size = user_request.size # Resolve tick size (from options or fetch from server) tick_size = self._parent._ClobClient__resolve_tick_size( token_id, options.tick_size if options else None, ) # Get rounding configuration (ensure tick_size is a string for lookup) tick_size_str = str(tick_size) if not isinstance(tick_size, str) else tick_size round_config = ROUNDING_CONFIG[tick_size_str] # Round price and size rounded_price = round_normal(price, round_config.price) rounded_size = round_down(size, round_config.size) # Format with correct decimal places price_decimals = int(round_config.price) size_decimals = int(round_config.size) amount_decimals = int(round_config.amount) rounded_price_str = f"{rounded_price:.{price_decimals}f}" rounded_size_str = f"{rounded_size:.{size_decimals}f}" # Parse back to numbers for calculation size_num = float(rounded_size_str) price_num = float(rounded_price_str) # Get signature type from parent's order builder user_type = self._parent.builder.sig_type # Calculate amounts based on side if side == BUY: # Buying tokens: pay USDC, receive tokens # asset_in = tokens (what requester receives) # asset_out = USDC (what requester pays) amount_in = parse_units(rounded_size_str, COLLATERAL_TOKEN_DECIMALS) usdc_amount = size_num * price_num usdc_amount_str = f"{usdc_amount:.{amount_decimals}f}" amount_out = parse_units(usdc_amount_str, COLLATERAL_TOKEN_DECIMALS) asset_in = token_id asset_out = "0" # USDC else: # Selling tokens: pay tokens, receive USDC # asset_in = USDC (what requester receives) # asset_out = tokens (what requester pays) usdc_amount = size_num * price_num usdc_amount_str = f"{usdc_amount:.{amount_decimals}f}" amount_in = parse_units(usdc_amount_str, COLLATERAL_TOKEN_DECIMALS) amount_out = parse_units(rounded_size_str, COLLATERAL_TOKEN_DECIMALS) asset_in = "0" # USDC asset_out = token_id # Post directly to the server self._ensure_l2_auth() body = { "assetIn": asset_in, "assetOut": asset_out, "amountIn": str(amount_in), "amountOut": str(amount_out), "userType": user_type, } serialized_body = json.dumps(body, separators=(",", ":"), ensure_ascii=False) headers = self._get_l2_headers("POST", CREATE_RFQ_REQUEST, body, serialized_body) return post(self._build_url(CREATE_RFQ_REQUEST), headers=headers, data=serialized_body) def cancel_rfq_request(self, params: CancelRfqRequestParams) -> str: """ Cancel an RFQ request. Args: params: Contains request_id to cancel. Returns: "OK" on success. """ self._ensure_l2_auth() body = {"requestId": params.request_id} serialized_body = json.dumps(body, separators=(",", ":"), ensure_ascii=False) headers = self._get_l2_headers("DELETE", CANCEL_RFQ_REQUEST, body, serialized_body) return delete(self._build_url(CANCEL_RFQ_REQUEST), headers=headers, data=serialized_body) def get_rfq_requests( self, params: Optional[GetRfqRequestsParams] = None ) -> dict: """ Get RFQ requests with optional filtering. Args: params: Optional filter parameters. Returns: Paginated response with RFQ requests. """ self._ensure_l2_auth() headers = self._get_l2_headers("GET", GET_RFQ_REQUESTS) query_params = parse_rfq_requests_params(params) # Build URL with query params url = self._build_url(GET_RFQ_REQUESTS) if query_params: # Use doseq=True so list values become repeated query params: # requestIds=id1&requestIds=id2 url = f"{url}?{urlencode(query_params, doseq=True)}" return get(url, headers=headers) # ========================================================================= # Quote-side methods # ========================================================================= def create_rfq_quote( self, user_quote: RfqUserQuote, options: Optional[PartialCreateOrderOptions] = None, ) -> dict: """ Create and post an RFQ quote in response to an RFQ request. This method: 1. Fetches the RFQ request to get token_id 2. Resolves the tick size for the token 3. Rounds price and size according to tick size rules 4. Calculates amount_in and amount_out based on side 5. Posts the quote to the server Args: user_quote: Simplified quote with request_id, token_id, price, side, size options: Optional tick size override Returns: Response dict with quote_id on success. Example: >>> response = client.rfq.create_rfq_quote( ... RfqUserQuote( ... request_id="019a83a9-f4c7-7c96-9139-2da2b2d934ef", ... token_id="123...", ... price=0.5, ... side="SELL", ... size=100.0, ... ) ... ) """ request_id = user_quote.request_id token_id = user_quote.token_id price = user_quote.price side = user_quote.side size = user_quote.size # Resolve tick size (from options or fetch from server) tick_size = self._parent._ClobClient__resolve_tick_size( token_id, options.tick_size if options else None, ) # Get rounding configuration (ensure tick_size is a string for lookup) tick_size_str = str(tick_size) if not isinstance(tick_size, str) else tick_size round_config = ROUNDING_CONFIG[tick_size_str] # Round price and size rounded_price = round_normal(price, round_config.price) rounded_size = round_down(size, round_config.size) # Format with correct decimal places price_decimals = int(round_config.price) size_decimals = int(round_config.size) amount_decimals = int(round_config.amount) rounded_price_str = f"{rounded_price:.{price_decimals}f}" rounded_size_str = f"{rounded_size:.{size_decimals}f}" # Parse back to numbers for calculation size_num = float(rounded_size_str) price_num = float(rounded_price_str) # Get signature type from parent's order builder user_type = self._parent.builder.sig_type # Calculate amounts based on side if side == BUY: # Buying tokens: pay USDC, receive tokens # asset_in = tokens (what quoter receives) # asset_out = USDC (what quoter pays) amount_in = parse_units(rounded_size_str, COLLATERAL_TOKEN_DECIMALS) usdc_amount = size_num * price_num usdc_amount_str = f"{usdc_amount:.{amount_decimals}f}" amount_out = parse_units(usdc_amount_str, COLLATERAL_TOKEN_DECIMALS) asset_in = token_id asset_out = "0" # USDC else: # Selling tokens: pay tokens, receive USDC # asset_in = USDC (what quoter receives) # asset_out = tokens (what quoter pays) usdc_amount = size_num * price_num usdc_amount_str = f"{usdc_amount:.{amount_decimals}f}" amount_in = parse_units(usdc_amount_str, COLLATERAL_TOKEN_DECIMALS) amount_out = parse_units(rounded_size_str, COLLATERAL_TOKEN_DECIMALS) asset_in = "0" # USDC asset_out = token_id # Post directly to the server self._ensure_l2_auth() body = { "requestId": request_id, "assetIn": asset_in, "assetOut": asset_out, "amountIn": str(amount_in), "amountOut": str(amount_out), "userType": user_type, } serialized_body = json.dumps(body, separators=(",", ":"), ensure_ascii=False) headers = self._get_l2_headers("POST", CREATE_RFQ_QUOTE, body, serialized_body) return post(self._build_url(CREATE_RFQ_QUOTE), headers=headers, data=serialized_body) def get_rfq_requester_quotes(self, params: Optional[GetRfqQuotesParams] = None) -> dict: """ Get quotes on requests created by the authenticated user (requester view). Returns quotes that others have made on your RFQ requests. Args: params: Optional filter parameters. Returns: Paginated response with RFQ quotes. """ self._ensure_l2_auth() headers = self._get_l2_headers("GET", GET_RFQ_REQUESTER_QUOTES) query_params = parse_rfq_quotes_params(params) # Build URL with query params url = self._build_url(GET_RFQ_REQUESTER_QUOTES) if query_params: url = f"{url}?{urlencode(query_params, doseq=True)}" return get(url, headers=headers) def get_rfq_quoter_quotes(self, params: Optional[GetRfqQuotesParams] = None) -> dict: """ Get quotes created by the authenticated user (quoter view). Returns quotes that you have made on others' RFQ requests. Args: params: Optional filter parameters. Returns: Paginated response with RFQ quotes. """ self._ensure_l2_auth() headers = self._get_l2_headers("GET", GET_RFQ_QUOTER_QUOTES) query_params = parse_rfq_quotes_params(params) # Build URL with query params url = self._build_url(GET_RFQ_QUOTER_QUOTES) if query_params: url = f"{url}?{urlencode(query_params, doseq=True)}" return get(url, headers=headers) def get_rfq_best_quote( self, params: Optional[GetRfqBestQuoteParams] = None ) -> dict: """ Get the best quote for an RFQ request. Args: params: Contains request_id. Returns: Single quote object representing the best quote. """ self._ensure_l2_auth() headers = self._get_l2_headers("GET", GET_RFQ_BEST_QUOTE) url = self._build_url(GET_RFQ_BEST_QUOTE) if params and params.request_id: url = f"{url}?{urlencode({'requestId': params.request_id})}" return get(url, headers=headers) def cancel_rfq_quote(self, params: CancelRfqQuoteParams) -> str: """ Cancel an RFQ quote. Args: params: Contains quote_id to cancel. Returns: "OK" on success. """ self._ensure_l2_auth() body = {"quoteId": params.quote_id} serialized_body = json.dumps(body, separators=(",", ":"), ensure_ascii=False) headers = self._get_l2_headers("DELETE", CANCEL_RFQ_QUOTE, body, serialized_body) return delete(self._build_url(CANCEL_RFQ_QUOTE), headers=headers, data=serialized_body) # ========================================================================= # Trade execution methods # ========================================================================= def accept_rfq_quote(self, params: AcceptQuoteParams) -> str: """ Accept an RFQ quote (requester side). This method: 1. Fetches the RFQ quote details 2. Creates a signed order matching the quote 3. Submits the acceptance with the order Args: params: Contains request_id, quote_id, and expiration. Returns: "OK" on success. """ self._ensure_l2_auth() resp = self.get_rfq_requester_quotes( GetRfqQuotesParams(quote_ids=[params.quote_id]) ) if not resp.get("data") or len(resp["data"]) == 0: raise Exception("RFQ quote not found") rfq_quote = resp["data"][0] order_creation_payload = self._get_request_order_creation_payload(rfq_quote) price = order_creation_payload.get("price") side = order_creation_payload["side"] size = float(order_creation_payload["size"]) token = order_creation_payload["token"] order_args = OrderArgs( token_id=token, price=price, size=size, side=side, expiration=params.expiration, ) order = self._parent.create_order(order_args) if not order: raise Exception("Error creating order") order_dict = order.dict() accept_payload = { "requestId": params.request_id, "quoteId": params.quote_id, "owner": self._parent.creds.api_key, # Order fields from dict "salt": int(order_dict["salt"]), "maker": order_dict["maker"], "signer": order_dict["signer"], "taker": order_dict["taker"], "tokenId": order_dict["tokenId"], "makerAmount": order_dict["makerAmount"], "takerAmount": order_dict["takerAmount"], "expiration": int(order_dict["expiration"]), "nonce": order_dict["nonce"], "feeRateBps": order_dict["feeRateBps"], "side": side, "signatureType": int(order_dict["signatureType"]), "signature": order_dict["signature"], } self.logger.debug( "Accept payload: requestId=%s, quoteId=%s, tokenId=%s, side=%s", accept_payload.get("requestId"), accept_payload.get("quoteId"), accept_payload.get("tokenId"), accept_payload.get("side"), ) serialized_body = json.dumps(accept_payload, separators=(",", ":"), ensure_ascii=False) headers = self._get_l2_headers("POST", RFQ_REQUESTS_ACCEPT, accept_payload, serialized_body) return post( self._build_url(RFQ_REQUESTS_ACCEPT), headers=headers, data=serialized_body, ) def approve_rfq_order(self, params: ApproveOrderParams) -> str: """ Approve an RFQ order (quoter side). This method: 1. Fetches the RFQ quote details 2. Creates a signed order based on quote parameters 3. Submits the approval with the order Args: params: Contains request_id, quote_id, and expiration. Returns: "OK" on success. """ self._ensure_l2_auth() # Step 1: Fetch the RFQ quote rfq_quotes = self.get_rfq_quoter_quotes( GetRfqQuotesParams(quote_ids=[params.quote_id]) ) if not rfq_quotes.get("data") or len(rfq_quotes["data"]) == 0: raise Exception("RFQ quote not found") rfq_quote = rfq_quotes["data"][0] # Step 2: Create an order based on quote details # Quoter uses their own quote's side side = rfq_quote.get("side", BUY) # Determine size based on quote side if side == BUY: size = rfq_quote.get("sizeIn") else: size = rfq_quote.get("sizeOut") token_id = rfq_quote.get("token") price = rfq_quote.get("price") order_args = OrderArgs( token_id=token_id, price=float(price), size=float(size), side=side, expiration=params.expiration, ) order = self._parent.create_order(order_args) if not order: raise Exception("Error creating order") # Step 3: Build approve payload order_dict = order.dict() approve_payload = { "requestId": params.request_id, "quoteId": params.quote_id, "owner": self._parent.creds.api_key, # Order fields from dict "salt": int(order_dict["salt"]), "maker": order_dict["maker"], "signer": order_dict["signer"], "taker": order_dict["taker"], "tokenId": order_dict["tokenId"], "makerAmount": order_dict["makerAmount"], "takerAmount": order_dict["takerAmount"], "expiration": int(order_dict["expiration"]), "nonce": order_dict["nonce"], "feeRateBps": order_dict["feeRateBps"], "side": side, "signatureType": int(order_dict["signatureType"]), "signature": order_dict["signature"], } serialized_body = json.dumps(approve_payload, separators=(",", ":"), ensure_ascii=False) headers = self._get_l2_headers("POST", RFQ_QUOTE_APPROVE, approve_payload, serialized_body) return post( self._build_url(RFQ_QUOTE_APPROVE), headers=headers, data=serialized_body, ) # ========================================================================= # Configuration # ========================================================================= def rfq_config(self) -> dict: """ Get RFQ configuration from the server. Returns: Configuration object with RFQ system parameters. """ self._ensure_l2_auth() headers = self._get_l2_headers("GET", RFQ_CONFIG) return get(self._build_url(RFQ_CONFIG), headers=headers) def _get_request_order_creation_payload(self, quote: dict) -> dict: """ Build the order creation payload for an RFQ request based on quote details. """ raw_match_type = quote.get("matchType", MatchType.COMPLEMENTARY) match_type = ( raw_match_type if isinstance(raw_match_type, MatchType) else MatchType(str(raw_match_type)) ) side = quote.get("side", BUY) if match_type == MatchType.COMPLEMENTARY: # For BUY <> SELL and SELL <> BUY # the order side is opposite the quote side token = quote.get("token") if not token: raise Exception("missing token for COMPLEMENTARY match") side = SELL if side == BUY else BUY size = quote.get("sizeOut") if side == BUY else quote.get("sizeIn") if size is None: raise Exception("missing sizeIn/sizeOut for COMPLEMENTARY match") price = quote.get("price") if price is None: raise Exception("missing price for COMPLEMENTARY match") price = float(price) return { "token": token, "side": side, "size": size, "price": price, } elif match_type in (MatchType.MINT, MatchType.MERGE): # BUY<> BUY, SELL <> SELL # the order side is the same as the quote side token = quote.get("complement") if not token: raise Exception("missing complement token for MINT/MERGE match") size = quote.get("sizeIn") if side == BUY else quote.get("sizeOut") if size is None: raise Exception("missing sizeIn/sizeOut for MINT/MERGE match") price = quote.get("price") if price is None: raise Exception("missing price for MINT/MERGE match") price = float(price) # For a MINT or a MERGE, the requester price is the inverse of the quote price # 95c Quote to BUY NO, implies that the Requester is buying YES at 5c # 45c Quote to SELL NO, implies the Requester is selling YES at 55c price = 1 - price return { "token": token, "side": side, "size": size, "price": price, } else: raise Exception(f"invalid match type: {raw_match_type}") ================================================ FILE: py_clob_client/rfq/rfq_helpers.py ================================================ """ RFQ helper functions for the Polymarket CLOB API. This module provides utility functions for RFQ operations including query parameter parsing and unit conversion. """ from typing import Optional, Dict, Any from .rfq_types import GetRfqRequestsParams, GetRfqQuotesParams # Token decimals constants COLLATERAL_TOKEN_DECIMALS = 6 # USDC has 6 decimals CONDITIONAL_TOKEN_DECIMALS = 6 def parse_units(value: str, decimals: int) -> int: """ Convert a decimal string to smallest units (like wei for ETH). Args: value: Decimal string (e.g., "1.5") decimals: Number of decimal places (e.g., 6 for USDC) Returns: Integer in smallest units (e.g., 1500000 for "1.5" with 6 decimals) Examples: >>> parse_units("1.5", 6) 1500000 >>> parse_units("100", 6) 100000000 >>> parse_units("0.000001", 6) 1 """ if "." in value: integer_part, decimal_part = value.split(".") # Pad or truncate decimal part to match decimals decimal_part = decimal_part[:decimals].ljust(decimals, "0") return int(integer_part + decimal_part) else: return int(value) * (10**decimals) def to_camel_case(snake_str: str) -> str: """ Convert snake_case string to camelCase. Args: snake_str: String in snake_case format Returns: String in camelCase format Examples: >>> to_camel_case("user_address") 'userAddress' >>> to_camel_case("request_id") 'requestId' >>> to_camel_case("size_usdc_min") 'sizeUsdcMin' """ components = snake_str.split("_") return components[0] + "".join(x.title() for x in components[1:]) def parse_rfq_requests_params(params: Optional[GetRfqRequestsParams] = None) -> Dict[str, Any]: """ Convert GetRfqRequestsParams to query string parameters. Arrays are kept as Python lists so the caller can serialize them with `urllib.parse.urlencode(..., doseq=True)` (repeated query params). Args: params: Optional filter parameters Returns: Dictionary of query parameters ready for HTTP request """ if params is None: return {} result = {} # Single value fields (convert snake_case to camelCase) single_fields = [ ("state", "state"), ("size_min", "sizeMin"), ("size_max", "sizeMax"), ("size_usdc_min", "sizeUsdcMin"), ("size_usdc_max", "sizeUsdcMax"), ("price_min", "priceMin"), ("price_max", "priceMax"), ("sort_by", "sortBy"), ("sort_dir", "sortDir"), ("limit", "limit"), ("offset", "offset"), ] for python_name, api_name in single_fields: value = getattr(params, python_name, None) if value is not None: result[api_name] = value # Array fields (keep as lists; let urlencode(doseq=True) expand them) if params.request_ids: result["requestIds"] = params.request_ids if params.markets: result["markets"] = params.markets return result def parse_rfq_quotes_params(params: Optional[GetRfqQuotesParams] = None) -> Dict[str, Any]: """ Convert GetRfqQuotesParams to query string parameters. Arrays are kept as Python lists so the caller can serialize them with `urllib.parse.urlencode(..., doseq=True)` (repeated query params). Args: params: Optional filter parameters Returns: Dictionary of query parameters ready for HTTP request """ if params is None: return {} result = {} # Single value fields (convert snake_case to camelCase) single_fields = [ ("state", "state"), ("size_min", "sizeMin"), ("size_max", "sizeMax"), ("size_usdc_min", "sizeUsdcMin"), ("size_usdc_max", "sizeUsdcMax"), ("price_min", "priceMin"), ("price_max", "priceMax"), ("sort_by", "sortBy"), ("sort_dir", "sortDir"), ("limit", "limit"), ("offset", "offset"), ] for python_name, api_name in single_fields: value = getattr(params, python_name, None) if value is not None: result[api_name] = value # Array fields (keep as lists; let urlencode(doseq=True) expand them) if params.quote_ids: result["quoteIds"] = params.quote_ids if params.request_ids: result["requestIds"] = params.request_ids if params.markets: result["markets"] = params.markets return result ================================================ FILE: py_clob_client/rfq/rfq_types.py ================================================ """ RFQ (Request for Quote) data types for the Polymarket CLOB API. This module defines all input and response types used by the RFQ client. """ from dataclasses import dataclass, field from typing import List, Optional, Any, Literal from enum import Enum # ============================================================================= # Input Types # ============================================================================= @dataclass class RfqUserRequest: """ Simplified user input for creating an RFQ request. This is the user-facing order format that gets converted to CreateRfqRequestParams for the API. """ token_id: str """Token ID of the conditional token being traded.""" price: float """Price per token (0 < price < 1).""" side: str """Order side: "BUY" or "SELL".""" size: float """Size in conditional tokens.""" @dataclass class RfqUserQuote: """ Simplified user input for creating an RFQ quote. This is the user-facing quote format that gets converted to CreateRfqQuoteParams for the API. """ request_id: str """ID of the RFQ request being quoted.""" token_id: str """Token ID of the conditional token being traded.""" price: float """Price per token (0 < price < 1).""" side: str """Quoter's side: "BUY" or "SELL".""" size: float """Size in conditional tokens.""" @dataclass class CreateRfqRequestParams: """ Server payload for creating an RFQ request. This is the format sent to the API after converting from RfqUserRequest. """ asset_in: str """Asset being received (token ID or "0" for USDC).""" asset_out: str """Asset being paid (token ID or "0" for USDC).""" amount_in: str """Amount being received (in smallest units, as string).""" amount_out: str """Amount being paid (in smallest units, as string).""" user_type: int """Signature type (0=EOA, 1=POLY_PROXY, 2=POLY_GNOSIS_SAFE).""" @dataclass class CreateRfqQuoteParams: """ Parameters for creating a quote in response to an RFQ request. """ request_id: str """ID of the RFQ request being quoted.""" asset_in: str """Asset the quoter is paying.""" asset_out: str """Asset the quoter is receiving.""" amount_in: str """Amount quoter is paying (in smallest units).""" amount_out: str """Amount quoter is receiving (in smallest units).""" # Note: user_type is auto-filled by the client @dataclass class CancelRfqRequestParams: """ Parameters for canceling an RFQ request. """ request_id: str """ID of the request to cancel.""" @dataclass class CancelRfqQuoteParams: """ Parameters for canceling an RFQ quote. """ quote_id: str """ID of the quote to cancel.""" @dataclass class AcceptQuoteParams: """ Parameters for accepting a quote (requester side). When a requester accepts a quote, they create a signed order and submit it with this payload. """ request_id: str """ID of the RFQ request.""" quote_id: str """ID of the quote being accepted.""" expiration: int """Unix timestamp for order expiration.""" @dataclass class ApproveOrderParams: """ Parameters for approving an order (quoter side). When a quoter's quote is accepted, they approve by creating a signed order and submitting it with this payload. """ request_id: str """ID of the RFQ request.""" quote_id: str """ID of the quote being approved.""" expiration: int """Unix timestamp for order expiration.""" @dataclass class GetRfqRequestsParams: """ Query parameters for fetching RFQ requests. All fields are optional filters. """ request_ids: Optional[List[str]] = None """Filter by specific request IDs (query param: requestIds; repeatable).""" state: Optional[Literal["active", "inactive"]] = None """Single state filter ("active" or "inactive").""" markets: Optional[List[str]] = None """Filter by market condition IDs (query param: markets; repeatable).""" size_min: Optional[float] = None """Minimum size filter.""" size_max: Optional[float] = None """Maximum size filter.""" size_usdc_min: Optional[float] = None """Minimum USDC size filter.""" size_usdc_max: Optional[float] = None """Maximum USDC size filter.""" price_min: Optional[float] = None """Minimum price filter.""" price_max: Optional[float] = None """Maximum price filter.""" sort_by: Optional[Literal["price", "expiry", "size", "created"]] = None """Field to sort by.""" sort_dir: Optional[Literal["asc", "desc"]] = None """Sort direction: "asc" or "desc".""" limit: Optional[int] = None """Pagination limit.""" offset: Optional[str] = None """Pagination cursor (base64 encoded).""" @dataclass class GetRfqQuotesParams: """ Query parameters for fetching RFQ quotes. All fields are optional filters. """ quote_ids: Optional[List[str]] = None """Filter by specific quote IDs (query param: quoteIds; repeatable).""" request_ids: Optional[List[str]] = None """Filter by request IDs (query param: requestIds; repeatable).""" state: Optional[Literal["active", "inactive"]] = None """Single state filter ("active" or "inactive").""" markets: Optional[List[str]] = None """Filter by market condition IDs (query param: markets; repeatable).""" size_min: Optional[float] = None """Minimum size filter.""" size_max: Optional[float] = None """Maximum size filter.""" size_usdc_min: Optional[float] = None """Minimum USDC size filter.""" size_usdc_max: Optional[float] = None """Maximum USDC size filter.""" price_min: Optional[float] = None """Minimum price filter.""" price_max: Optional[float] = None """Maximum price filter.""" sort_by: Optional[Literal["price", "expiry", "created"]] = None """Field to sort by.""" sort_dir: Optional[Literal["asc", "desc"]] = None """Sort direction: "asc" or "desc".""" limit: Optional[int] = None """Pagination limit.""" offset: Optional[str] = None """Pagination cursor (base64 encoded).""" @dataclass class GetRfqBestQuoteParams: """ Parameters for fetching the best quote for a request. """ request_id: Optional[str] = None """Request ID to get best quote for.""" # ============================================================================= # Response Types # ============================================================================= @dataclass class RfqRequest: """ Full RFQ request object returned by the API. """ request_id: str """Unique request identifier.""" user_address: str """Address of the requester.""" proxy_address: Optional[str] = None """Proxy address if applicable.""" token: Optional[str] = None """Token ID being traded.""" complement: Optional[str] = None """Complement token ID.""" condition: Optional[str] = None """Condition ID (market).""" side: Optional[str] = None """Order side: "BUY" or "SELL".""" size_in: Optional[str] = None """Size of asset_in.""" size_out: Optional[str] = None """Size of asset_out.""" price: Optional[float] = None """Price.""" accepted_quote_id: Optional[str] = None """ID of accepted quote (if any).""" state: Optional[str] = None """Request state.""" expiry: Optional[str] = None """Expiration timestamp.""" created_at: Optional[str] = None """Creation timestamp.""" updated_at: Optional[str] = None """Last update timestamp.""" @dataclass class RfqQuote: """ Full RFQ quote object returned by the API. """ quote_id: str """Unique quote identifier.""" request_id: str """Associated request ID.""" user_address: str """Address of the quoter.""" proxy_address: Optional[str] = None """Proxy address if applicable.""" complement: Optional[str] = None """Complement token ID.""" condition: Optional[str] = None """Condition ID (market).""" token: Optional[str] = None """Token ID.""" side: Optional[str] = None """Quote side: "BUY" or "SELL".""" size_in: Optional[str] = None """Size of asset_in.""" size_out: Optional[str] = None """Size of asset_out.""" price: Optional[float] = None """Quote price.""" state: Optional[str] = None """Quote state.""" expiry: Optional[str] = None """Expiration timestamp.""" created_at: Optional[str] = None """Creation timestamp.""" updated_at: Optional[str] = None """Last update timestamp.""" @dataclass class RfqRequestResponse: """ Response from creating an RFQ request. """ request_id: Optional[str] = None """Created request ID.""" error: Optional[str] = None """Error message if failed.""" @dataclass class RfqQuoteResponse: """ Response from creating an RFQ quote. """ quote_id: Optional[str] = None """Created quote ID.""" error: Optional[str] = None """Error message if failed.""" @dataclass class RfqPaginatedResponse: """ Paginated response for list queries. """ data: List[Any] = field(default_factory=list) """Array of results (RfqRequest or RfqQuote objects).""" next_cursor: Optional[str] = None """Cursor for next page.""" limit: Optional[int] = None """Page limit.""" count: Optional[int] = None """Number of results in this page.""" total_count: Optional[int] = None """Total count (optional).""" class MatchType(str, Enum): COMPLEMENTARY = "COMPLEMENTARY" MINT = "MINT" MERGE = "MERGE" ================================================ FILE: py_clob_client/signer.py ================================================ from eth_account import Account class Signer: def __init__(self, private_key: str, chain_id: int): assert private_key is not None and chain_id is not None self.private_key = private_key self.account = Account.from_key(private_key) self.chain_id = chain_id def address(self): return self.account.address def get_chain_id(self): return self.chain_id def sign(self, message_hash): """ Signs a message hash """ return Account._sign_hash(message_hash, self.private_key).signature.hex() ================================================ FILE: py_clob_client/signing/__init__.py ================================================ ================================================ FILE: py_clob_client/signing/eip712.py ================================================ from poly_eip712_structs import make_domain from eth_utils import keccak from py_order_utils.utils import prepend_zx from .model import ClobAuth from ..signer import Signer CLOB_DOMAIN_NAME = "ClobAuthDomain" CLOB_VERSION = "1" MSG_TO_SIGN = "This message attests that I control the given wallet" def get_clob_auth_domain(chain_id: int): return make_domain(name=CLOB_DOMAIN_NAME, version=CLOB_VERSION, chainId=chain_id) def sign_clob_auth_message(signer: Signer, timestamp: int, nonce: int) -> str: clob_auth_msg = ClobAuth( address=signer.address(), timestamp=str(timestamp), nonce=nonce, message=MSG_TO_SIGN, ) chain_id = signer.get_chain_id() auth_struct_hash = prepend_zx( keccak(clob_auth_msg.signable_bytes(get_clob_auth_domain(chain_id))).hex() ) return prepend_zx(signer.sign(auth_struct_hash)) ================================================ FILE: py_clob_client/signing/hmac.py ================================================ import hmac import hashlib import base64 def build_hmac_signature( secret: str, timestamp: str, method: str, requestPath: str, body=None ): """ Creates an HMAC signature by signing a payload with the secret """ base64_secret = base64.urlsafe_b64decode(secret) message = str(timestamp) + str(method) + str(requestPath) if body: # NOTE: Necessary to replace single quotes with double quotes # to generate the same hmac message as go and typescript message += str(body).replace("'", '"') h = hmac.new(base64_secret, bytes(message, "utf-8"), hashlib.sha256) # ensure base64 encoded return (base64.urlsafe_b64encode(h.digest())).decode("utf-8") ================================================ FILE: py_clob_client/signing/model.py ================================================ from poly_eip712_structs import EIP712Struct, Address, String, Uint class ClobAuth(EIP712Struct): address = Address() timestamp = String() nonce = Uint() message = String() ================================================ FILE: py_clob_client/utilities.py ================================================ import hashlib import json from .clob_types import OrderBookSummary, OrderSummary, TickSize def parse_raw_orderbook_summary(raw_obs: any) -> OrderBookSummary: bids = [] for bid in raw_obs["bids"]: bids.append(OrderSummary(size=bid["size"], price=bid["price"])) asks = [] for ask in raw_obs["asks"]: asks.append(OrderSummary(size=ask["size"], price=ask["price"])) orderbookSummary = OrderBookSummary( market=raw_obs["market"], asset_id=raw_obs["asset_id"], timestamp=raw_obs["timestamp"], last_trade_price=raw_obs["last_trade_price"], min_order_size=raw_obs["min_order_size"], neg_risk=raw_obs["neg_risk"], tick_size=raw_obs["tick_size"], bids=bids, asks=asks, hash=raw_obs["hash"], ) return orderbookSummary def generate_orderbook_summary_hash(orderbook: OrderBookSummary) -> str: """ Server-compatible orderbook hash. The server computes SHA1 over a compact JSON payload with a specific key order, and with the "hash" field set to an empty string while hashing. """ # Go server-side payload field order (struct order): # market, asset_id, timestamp, hash, bids, asks, min_order_size, tick_size, neg_risk, last_trade_price payload = { "market": orderbook.market, "asset_id": orderbook.asset_id, "timestamp": orderbook.timestamp, "hash": "", "bids": [{"price": o.price, "size": o.size} for o in (orderbook.bids or [])], "asks": [{"price": o.price, "size": o.size} for o in (orderbook.asks or [])], "min_order_size": orderbook.min_order_size, "tick_size": orderbook.tick_size, "neg_risk": orderbook.neg_risk, "last_trade_price": orderbook.last_trade_price, } serialized = json.dumps(payload, separators=(",", ":"), ensure_ascii=False) h = hashlib.sha1(serialized.encode("utf-8")).hexdigest() orderbook.hash = h return h def order_to_json(order, owner, orderType, post_only: bool = False) -> dict: return {"order": order.dict(), "owner": owner, "orderType": orderType, "postOnly": post_only} def is_tick_size_smaller(a: TickSize, b: TickSize) -> bool: return float(a) < float(b) def price_valid(price: float, tick_size: TickSize) -> bool: return price >= float(tick_size) and price <= 1 - float(tick_size) ================================================ FILE: requirements.txt ================================================ black==24.4.2 eth-account===0.13.0 eth-utils===4.1.1 poly_eip712_structs==0.0.1 py_order_utils==0.3.2 pytest==8.2.2 python-dotenv==0.19.2 websockets==12.0 py-builder-signing-sdk==0.0.2 httpx[http2]==0.27.0 ================================================ FILE: setup.py ================================================ import setuptools with open("README.md", "r", encoding="utf-8") as fh: long_description = fh.read() setuptools.setup( name="py_clob_client", version="0.34.6", author="Polymarket Engineering", author_email="engineering@polymarket.com", maintainer="Polymarket Engineering", maintainer_email="engineering@polymarket.com", description="Python client for the Polymarket CLOB", long_description=long_description, long_description_content_type="text/markdown", url="https://github.com/Polymarket/py-clob-client", install_requires=[ "eth-account>=0.13.0", "eth-utils>=4.1.1", "poly_eip712_structs>=0.0.1", "py-order-utils>=0.3.2", "python-dotenv", "py-builder-signing-sdk>=0.0.2", "httpx[http2]>=0.27.0", ], project_urls={ "Bug Tracker": "https://github.com/Polymarket/py-clob-client/issues", }, classifiers=[ "Programming Language :: Python :: 3", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", ], packages=setuptools.find_packages(), python_requires=">=3.9.10", ) ================================================ FILE: tests/__init__.py ================================================ ================================================ FILE: tests/headers/__init__.py ================================================ ================================================ FILE: tests/headers/test_headers.py ================================================ from datetime import datetime from unittest import TestCase from py_clob_client.clob_types import ApiCreds, RequestArgs from py_clob_client.constants import AMOY from py_clob_client.headers.headers import ( POLY_ADDRESS, POLY_API_KEY, POLY_NONCE, POLY_PASSPHRASE, POLY_SIGNATURE, POLY_TIMESTAMP, create_level_1_headers, create_level_2_headers, ) from py_clob_client.signer import Signer # publicly known private key private_key = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" chain_id = AMOY signer = Signer(private_key=private_key, chain_id=chain_id) creds = ApiCreds( api_key="000000000-0000-0000-0000-000000000000", api_passphrase="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", api_secret="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", ) class TestHeaders(TestCase): def test_create_level_1_headers(self): # no nonce l1_headers = create_level_1_headers(signer) self.assertIsNotNone(l1_headers) self.assertEqual(l1_headers[POLY_ADDRESS], signer.address()) self.assertIsNotNone(l1_headers[POLY_SIGNATURE]) self.assertIsNotNone(l1_headers[POLY_TIMESTAMP]) self.assertTrue( int(l1_headers[POLY_TIMESTAMP]) <= int(datetime.now().timestamp()) ) self.assertEqual(l1_headers[POLY_NONCE], "0") # nonce l1_headers = create_level_1_headers(signer, nonce=1012) self.assertIsNotNone(l1_headers) self.assertEqual(l1_headers[POLY_ADDRESS], signer.address()) self.assertIsNotNone(l1_headers[POLY_SIGNATURE]) self.assertIsNotNone(l1_headers[POLY_TIMESTAMP]) self.assertTrue( int(l1_headers[POLY_TIMESTAMP]) <= int(datetime.now().timestamp()) ) self.assertEqual(l1_headers[POLY_NONCE], "1012") def test_create_level_2_headers(self): # no body l2_headers = create_level_2_headers( signer, creds, request_args=RequestArgs(method="get", request_path="/order") ) self.assertIsNotNone(l2_headers) self.assertEqual(l2_headers[POLY_ADDRESS], signer.address()) self.assertIsNotNone(l2_headers[POLY_SIGNATURE]) self.assertIsNotNone(l2_headers[POLY_TIMESTAMP]) self.assertTrue( int(l2_headers[POLY_TIMESTAMP]) <= int(datetime.now().timestamp()) ) self.assertEqual(l2_headers[POLY_API_KEY], creds.api_key) self.assertEqual(l2_headers[POLY_PASSPHRASE], creds.api_passphrase) # body l2_headers = create_level_2_headers( signer, creds, request_args=RequestArgs( method="get", request_path="/order", body='{"hash": "0x123"}' ), ) self.assertIsNotNone(l2_headers) self.assertEqual(l2_headers[POLY_ADDRESS], signer.address()) self.assertIsNotNone(l2_headers[POLY_SIGNATURE]) self.assertIsNotNone(l2_headers[POLY_TIMESTAMP]) self.assertTrue( int(l2_headers[POLY_TIMESTAMP]) <= int(datetime.now().timestamp()) ) self.assertEqual(l2_headers[POLY_API_KEY], creds.api_key) self.assertEqual(l2_headers[POLY_PASSPHRASE], creds.api_passphrase) ================================================ FILE: tests/http_helpers/__init__.py ================================================ ================================================ FILE: tests/http_helpers/test_helpers.py ================================================ from unittest import TestCase from py_clob_client.clob_types import ( TradeParams, OpenOrderParams, DropNotificationParams, BalanceAllowanceParams, AssetType, OrderScoringParams, OrdersScoringParams, ) from py_clob_client.http_helpers.helpers import ( build_query_params, add_query_trade_params, add_query_open_orders_params, drop_notifications_query_params, add_balance_allowance_params_to_url, add_order_scoring_params_to_url, add_orders_scoring_params_to_url, ) class TestHelpers(TestCase): def test_build_query_params(self): # last is ? url = build_query_params("http://tracker?", "q1", "a") self.assertIsNotNone(url) self.assertEqual(url, "http://tracker?q1=a") # last is not ? url = build_query_params("http://tracker?q1=a", "q2", "b") self.assertIsNotNone(url) self.assertEqual(url, "http://tracker?q1=a&q2=b") def test_add_query_trade_params(self): url = add_query_trade_params( "http://tracker", TradeParams( market="10000", after=1450000, before=1460000, asset_id="100", maker_address="0x0", id="aa-bb", ), next_cursor="AA==", ) self.assertIsNotNone(url) self.assertEqual( url, "http://tracker?market=10000&asset_id=100&after=1450000&before=1460000&maker_address=0x0&id=aa-bb&next_cursor=AA==", ) def test_add_query_trade_params_no_params_includes_next_cursor(self): url = add_query_trade_params("http://tracker", None, next_cursor="AA==") self.assertIsNotNone(url) self.assertEqual(url, "http://tracker?next_cursor=AA==") def test_add_query_open_orders_params(self): url = add_query_open_orders_params( "http://tracker", OpenOrderParams(market="10000", asset_id="100", id="aa-bb"), ) self.assertIsNotNone(url) self.assertEqual( url, "http://tracker?market=10000&asset_id=100&id=aa-bb&next_cursor=MA==", ) def test_add_query_open_orders_params_no_params_includes_next_cursor(self): url = add_query_open_orders_params("http://tracker", None, next_cursor="AA==") self.assertIsNotNone(url) self.assertEqual(url, "http://tracker?next_cursor=AA==") def test_drop_notifications_query_params(self): url = drop_notifications_query_params( "http://tracker", DropNotificationParams(ids=["1", "2", "3"]), ) self.assertIsNotNone(url) self.assertEqual(url, "http://tracker?ids=1,2,3") def test_add_balance_allowance_params_to_url(self): url = add_balance_allowance_params_to_url( "http://tracker", BalanceAllowanceParams(asset_type=AssetType.COLLATERAL, signature_type=0), ) self.assertIsNotNone(url) self.assertEqual(url, "http://tracker?asset_type=COLLATERAL&signature_type=0") url = add_balance_allowance_params_to_url( "http://tracker", BalanceAllowanceParams( asset_type=AssetType.CONDITIONAL, token_id="222", signature_type=1 ), ) self.assertIsNotNone(url) self.assertEqual( url, "http://tracker?asset_type=CONDITIONAL&token_id=222&signature_type=1" ) def test_add_order_scoring_params_to_url(self): url = add_order_scoring_params_to_url( "http://tracker", OrderScoringParams(orderId="0x0123abc"), ) self.assertIsNotNone(url) self.assertEqual(url, "http://tracker?order_id=0x0123abc") def test_add_orders_scoring_params_to_urll(self): url = add_orders_scoring_params_to_url( "http://tracker", OrdersScoringParams(orderIds=["0x0", "0x1", "0x2"]), ) self.assertIsNotNone(url) self.assertEqual(url, "http://tracker?order_ids=0x0,0x1,0x2") ================================================ FILE: tests/order_builder/__init__.py ================================================ ================================================ FILE: tests/order_builder/test_builder.py ================================================ from unittest import TestCase from py_clob_client.clob_types import ( OrderArgs, MarketOrderArgs, CreateOrderOptions, OrderSummary, OrderType, ) from py_clob_client.constants import AMOY from py_clob_client.order_builder.constants import BUY, SELL from py_clob_client.signer import Signer from py_clob_client.order_builder.builder import OrderBuilder, ROUNDING_CONFIG from py_clob_client.order_builder.helpers import decimal_places, round_normal from py_order_utils.model import ( POLY_GNOSIS_SAFE, EOA, BUY as UtilsBuy, SELL as UtilsSell, ) # publicly known private key private_key = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" chain_id = AMOY signer = Signer(private_key=private_key, chain_id=chain_id) class TestOrderBuilder(TestCase): def test_calculate_buy_market_price_FOK(self): # empty with self.assertRaises(Exception): builder = OrderBuilder(signer) builder.calculate_buy_market_price([], 100, OrderType.FOK) # not enough with self.assertRaises(Exception): positions = [ OrderSummary(price="0.5", size="100"), OrderSummary(price="0.4", size="100"), ] builder = OrderBuilder(signer) builder.calculate_buy_market_price(positions, 100, OrderType.FOK) # OK positions = [ OrderSummary(price="0.5", size="100"), OrderSummary(price="0.4", size="100"), OrderSummary(price="0.3", size="100"), ] builder = OrderBuilder(signer) self.assertEqual( builder.calculate_buy_market_price(positions, 100, OrderType.FOK), 0.5 ) positions = [ OrderSummary(price="0.5", size="100"), OrderSummary(price="0.4", size="200"), OrderSummary(price="0.3", size="100"), ] builder = OrderBuilder(signer) self.assertEqual( builder.calculate_buy_market_price(positions, 100, OrderType.FOK), 0.4 ) positions = [ OrderSummary(price="0.5", size="120"), OrderSummary(price="0.4", size="100"), OrderSummary(price="0.3", size="100"), ] builder = OrderBuilder(signer) self.assertEqual( builder.calculate_buy_market_price(positions, 100, OrderType.FOK), 0.5 ) positions = [ OrderSummary(price="0.5", size="200"), OrderSummary(price="0.4", size="100"), OrderSummary(price="0.3", size="100"), ] builder = OrderBuilder(signer) self.assertEqual( builder.calculate_buy_market_price(positions, 100, OrderType.FOK), 0.5 ) def test_calculate_sell_market_price_FOK(self): # empty with self.assertRaises(Exception): builder = OrderBuilder(signer) builder.calculate_sell_market_price([], 100) # not enough with self.assertRaises(Exception): positions = [ OrderSummary(price="0.4", size="10"), OrderSummary(price="0.5", size="10"), ] builder = OrderBuilder(signer) builder.calculate_sell_market_price(positions, 100, OrderType.FOK) # OK positions = [ OrderSummary(price="0.3", size="100"), OrderSummary(price="0.4", size="100"), OrderSummary(price="0.5", size="100"), ] builder = OrderBuilder(signer) self.assertEqual( builder.calculate_sell_market_price(positions, 100, OrderType.FOK), 0.5 ) positions = [ OrderSummary(price="0.3", size="100"), OrderSummary(price="0.4", size="300"), OrderSummary(price="0.5", size="10"), ] builder = OrderBuilder(signer) self.assertEqual( builder.calculate_sell_market_price(positions, 100, OrderType.FOK), 0.4 ) positions = [ OrderSummary(price="0.3", size="100"), OrderSummary(price="0.4", size="200"), OrderSummary(price="0.5", size="10"), ] builder = OrderBuilder(signer) self.assertEqual( builder.calculate_sell_market_price(positions, 100, OrderType.FOK), 0.4 ) positions = [ OrderSummary(price="0.3", size="300"), OrderSummary(price="0.4", size="100"), OrderSummary(price="0.5", size="100"), ] builder = OrderBuilder(signer) self.assertEqual( builder.calculate_sell_market_price(positions, 200, OrderType.FOK), 0.4 ) positions = [ OrderSummary(price="0.3", size="334"), OrderSummary(price="0.4", size="100"), OrderSummary(price="0.5", size="100"), ] builder = OrderBuilder(signer) self.assertEqual( builder.calculate_sell_market_price(positions, 300, OrderType.FOK), 0.3 ) def test_calculate_buy_market_price_FAK(self): # empty with self.assertRaises(Exception): builder = OrderBuilder(signer) builder.calculate_buy_market_price([], 100, OrderType.FAK) # not enough positions = [ OrderSummary(price="0.5", size="100"), OrderSummary(price="0.4", size="100"), ] builder = OrderBuilder(signer) self.assertEqual( builder.calculate_buy_market_price(positions, 100, OrderType.FAK), 0.5 ) # OK positions = [ OrderSummary(price="0.5", size="100"), OrderSummary(price="0.4", size="100"), OrderSummary(price="0.3", size="100"), ] builder = OrderBuilder(signer) self.assertEqual( builder.calculate_buy_market_price(positions, 100, OrderType.FAK), 0.5 ) positions = [ OrderSummary(price="0.5", size="100"), OrderSummary(price="0.4", size="200"), OrderSummary(price="0.3", size="100"), ] builder = OrderBuilder(signer) self.assertEqual( builder.calculate_buy_market_price(positions, 100, OrderType.FAK), 0.4 ) positions = [ OrderSummary(price="0.5", size="120"), OrderSummary(price="0.4", size="100"), OrderSummary(price="0.3", size="100"), ] builder = OrderBuilder(signer) self.assertEqual( builder.calculate_buy_market_price(positions, 100, OrderType.FAK), 0.5 ) positions = [ OrderSummary(price="0.5", size="200"), OrderSummary(price="0.4", size="100"), OrderSummary(price="0.3", size="100"), ] builder = OrderBuilder(signer) self.assertEqual( builder.calculate_buy_market_price(positions, 100, OrderType.FAK), 0.5 ) def test_calculate_sell_market_price_FAK(self): # empty with self.assertRaises(Exception): builder = OrderBuilder(signer) builder.calculate_sell_market_price([], 100) # not enough positions = [ OrderSummary(price="0.4", size="10"), OrderSummary(price="0.5", size="10"), ] builder = OrderBuilder(signer) self.assertEqual( builder.calculate_sell_market_price(positions, 100, OrderType.FAK), 0.4 ) # OK positions = [ OrderSummary(price="0.3", size="100"), OrderSummary(price="0.4", size="100"), OrderSummary(price="0.5", size="100"), ] builder = OrderBuilder(signer) self.assertEqual( builder.calculate_sell_market_price(positions, 100, OrderType.FAK), 0.5 ) positions = [ OrderSummary(price="0.3", size="100"), OrderSummary(price="0.4", size="300"), OrderSummary(price="0.5", size="10"), ] builder = OrderBuilder(signer) self.assertEqual( builder.calculate_sell_market_price(positions, 100, OrderType.FAK), 0.4 ) positions = [ OrderSummary(price="0.3", size="100"), OrderSummary(price="0.4", size="200"), OrderSummary(price="0.5", size="10"), ] builder = OrderBuilder(signer) self.assertEqual( builder.calculate_sell_market_price(positions, 100, OrderType.FAK), 0.4 ) positions = [ OrderSummary(price="0.3", size="300"), OrderSummary(price="0.4", size="100"), OrderSummary(price="0.5", size="100"), ] builder = OrderBuilder(signer) self.assertEqual( builder.calculate_sell_market_price(positions, 200, OrderType.FAK), 0.4 ) positions = [ OrderSummary(price="0.3", size="334"), OrderSummary(price="0.4", size="100"), OrderSummary(price="0.5", size="100"), ] builder = OrderBuilder(signer) self.assertEqual( builder.calculate_sell_market_price(positions, 300, OrderType.FAK), 0.3 ) def test_get_market_order_amounts_buy_0_1(self): builder = OrderBuilder(signer) delta_price = 0.1 delta_size = 0.01 amount = 0.01 while amount <= 1000: price = 0.1 while price <= 1: side, maker, taker = builder.get_market_order_amounts( BUY, amount, price, ROUNDING_CONFIG["0.1"] ) self.assertEqual(side, UtilsBuy) self.assertEqual(decimal_places(maker), 0) self.assertEqual(decimal_places(taker), 0) self.assertGreaterEqual( round_normal(maker / taker, 2), round_normal(price, 2) ) price = price + delta_price amount = amount + delta_size def test_get_market_order_amounts_buy_0_01(self): builder = OrderBuilder(signer) delta_price = 0.01 delta_size = 0.01 amount = 0.01 while amount <= 100: price = 0.01 while price <= 1: side, maker, taker = builder.get_market_order_amounts( BUY, amount, price, ROUNDING_CONFIG["0.01"] ) self.assertEqual(side, UtilsBuy) self.assertEqual(decimal_places(maker), 0) self.assertEqual(decimal_places(taker), 0) self.assertGreaterEqual( round_normal(maker / taker, 4), round_normal(price, 4) ) price = price + delta_price amount = amount + delta_size def test_get_market_order_amounts_buy_0_001(self): builder = OrderBuilder(signer) delta_price = 0.001 delta_size = 0.01 amount = 0.01 while amount <= 10: price = 0.001 while price <= 1: side, maker, taker = builder.get_market_order_amounts( BUY, amount, price, ROUNDING_CONFIG["0.001"] ) self.assertEqual(side, UtilsBuy) self.assertEqual(decimal_places(maker), 0) self.assertEqual(decimal_places(taker), 0) self.assertGreaterEqual( round_normal(maker / taker, 6), round_normal(price, 6) ) price = price + delta_price amount = amount + delta_size def test_get_market_order_amounts_buy_0_0001(self): builder = OrderBuilder(signer) delta_price = 0.0001 delta_size = 0.01 amount = 0.01 while amount <= 1: price = 0.0001 while price <= 1: side, maker, taker = builder.get_market_order_amounts( BUY, amount, price, ROUNDING_CONFIG["0.0001"] ) self.assertEqual(side, UtilsBuy) self.assertEqual(decimal_places(maker), 0) self.assertEqual(decimal_places(taker), 0) self.assertGreaterEqual( round_normal(maker / taker, 8), round_normal(price, 8) ) price = price + delta_price amount = amount + delta_size def test_get_market_order_amounts_sell_0_1(self): builder = OrderBuilder(signer) delta_price = 0.1 delta_size = 0.01 amount = 0.01 while amount <= 1000: price = 0.1 while price <= 1: side, maker, taker = builder.get_market_order_amounts( SELL, amount, price, ROUNDING_CONFIG["0.1"] ) self.assertEqual(side, UtilsSell) self.assertEqual(decimal_places(maker), 0) self.assertEqual(decimal_places(taker), 0) self.assertGreaterEqual( round_normal(maker / taker, 2), round_normal(price, 2) ) price = price + delta_price amount = amount + delta_size def test_get_market_order_amounts_sell_0_01(self): builder = OrderBuilder(signer) delta_price = 0.01 delta_size = 0.01 amount = 0.01 while amount <= 100: price = 0.01 while price <= 1: side, maker, taker = builder.get_market_order_amounts( SELL, amount, price, ROUNDING_CONFIG["0.01"] ) self.assertEqual(side, UtilsSell) self.assertEqual(decimal_places(maker), 0) self.assertEqual(decimal_places(taker), 0) self.assertGreaterEqual( round_normal(maker / taker, 4), round_normal(price, 4) ) price = price + delta_price amount = amount + delta_size def test_get_market_order_amounts_sell_0_001(self): builder = OrderBuilder(signer) delta_price = 0.001 delta_size = 0.01 amount = 0.01 while amount <= 10: price = 0.001 while price <= 1: side, maker, taker = builder.get_market_order_amounts( SELL, amount, price, ROUNDING_CONFIG["0.001"] ) self.assertEqual(side, UtilsSell) self.assertEqual(decimal_places(maker), 0) self.assertEqual(decimal_places(taker), 0) self.assertGreaterEqual( round_normal(maker / taker, 6), round_normal(price, 6) ) price = price + delta_price amount = amount + delta_size def test_get_market_order_amounts_sell_0_0001(self): builder = OrderBuilder(signer) delta_price = 0.0001 delta_size = 0.01 amount = 0.01 while amount <= 1: price = 0.0001 while price <= 1: side, maker, taker = builder.get_market_order_amounts( SELL, amount, price, ROUNDING_CONFIG["0.0001"] ) self.assertEqual(side, UtilsSell) self.assertEqual(decimal_places(maker), 0) self.assertEqual(decimal_places(taker), 0) self.assertGreaterEqual( round_normal(taker / maker, 8), round_normal(price, 8) ) price = price + delta_price amount = amount + delta_size def test_get_order_amounts_buy_0_1(self): builder = OrderBuilder(signer) delta_price = 0.1 delta_size = 0.01 size = 0.01 while size <= 1000: price = 0.1 while price <= 1: side, maker, taker = builder.get_order_amounts( BUY, size, price, ROUNDING_CONFIG["0.1"] ) self.assertEqual(side, 0) self.assertEqual(decimal_places(maker), 0) self.assertEqual(decimal_places(taker), 0) self.assertGreaterEqual( round_normal(maker / taker, 2), round_normal(price, 2) ) price = price + delta_price size = size + delta_size def test_get_order_amounts_buy_0_01(self): builder = OrderBuilder(signer) delta_price = 0.01 delta_size = 0.01 size = 0.01 while size <= 100: price = 0.01 while price <= 1: side, maker, taker = builder.get_order_amounts( BUY, size, price, ROUNDING_CONFIG["0.01"] ) self.assertEqual(side, 0) self.assertEqual(decimal_places(maker), 0) self.assertEqual(decimal_places(taker), 0) self.assertGreaterEqual( round_normal(maker / taker, 4), round_normal(price, 4) ) price = price + delta_price size = size + delta_size def test_get_order_amounts_buy_0_001(self): builder = OrderBuilder(signer) delta_price = 0.001 delta_size = 0.01 size = 0.01 while size <= 10: price = 0.001 while price <= 1: side, maker, taker = builder.get_order_amounts( BUY, size, price, ROUNDING_CONFIG["0.001"] ) self.assertEqual(side, 0) self.assertEqual(decimal_places(maker), 0) self.assertEqual(decimal_places(taker), 0) self.assertGreaterEqual( round_normal(maker / taker, 6), round_normal(price, 6) ) price = price + delta_price size = size + delta_size def test_get_order_amounts_buy_0_0001(self): builder = OrderBuilder(signer) delta_price = 0.0001 delta_size = 0.01 size = 0.01 while size <= 1: price = 0.0001 while price <= 1: side, maker, taker = builder.get_order_amounts( BUY, size, price, ROUNDING_CONFIG["0.0001"] ) self.assertEqual(side, 0) self.assertEqual(decimal_places(maker), 0) self.assertEqual(decimal_places(taker), 0) self.assertGreaterEqual( round_normal(maker / taker, 8), round_normal(price, 8) ) price = price + delta_price size = size + delta_size def test_get_order_amounts_sell_0_1(self): builder = OrderBuilder(signer) delta_price = 0.1 delta_size = 0.01 size = 0.01 while size <= 1000: price = 0.1 while price <= 1: side, maker, taker = builder.get_order_amounts( SELL, size, price, ROUNDING_CONFIG["0.1"] ) self.assertEqual(side, 1) self.assertEqual(decimal_places(maker), 0) self.assertEqual(decimal_places(taker), 0) self.assertGreaterEqual( round_normal(taker / maker, 2), round_normal(price, 2) ) price = price + delta_price size = size + delta_size def test_get_order_amounts_sell_0_01(self): builder = OrderBuilder(signer) delta_price = 0.01 delta_size = 0.01 size = 0.01 while size <= 100: price = 0.01 while price <= 1: side, maker, taker = builder.get_order_amounts( SELL, size, price, ROUNDING_CONFIG["0.01"] ) self.assertEqual(side, 1) self.assertEqual(decimal_places(maker), 0) self.assertEqual(decimal_places(taker), 0) self.assertGreaterEqual( round_normal(taker / maker, 4), round_normal(price, 4) ) price = price + delta_price size = size + delta_size def test_get_order_amounts_sell_0_001(self): builder = OrderBuilder(signer) delta_price = 0.001 delta_size = 0.01 size = 0.01 while size <= 10: price = 0.001 while price <= 1: side, maker, taker = builder.get_order_amounts( SELL, size, price, ROUNDING_CONFIG["0.001"] ) self.assertEqual(side, 1) self.assertEqual(decimal_places(maker), 0) self.assertEqual(decimal_places(taker), 0) self.assertGreaterEqual( round_normal(taker / maker, 6), round_normal(price, 6) ) price = price + delta_price size = size + delta_size def test_get_order_amounts_sell_0_0001(self): builder = OrderBuilder(signer) delta_price = 0.0001 delta_size = 0.01 size = 0.01 while size <= 1: price = 0.0001 while price <= 1: side, maker, taker = builder.get_order_amounts( SELL, size, price, ROUNDING_CONFIG["0.0001"] ) self.assertEqual(side, 1) self.assertEqual(decimal_places(maker), 0) self.assertEqual(decimal_places(taker), 0) self.assertGreaterEqual( round_normal(taker / maker, 8), round_normal(price, 8) ) price = price + delta_price size = size + delta_size def test_create_order_decimal_accuracy(self): builder = OrderBuilder(signer) # BUY signed_order = builder.create_order( order_args=OrderArgs( token_id="123", price=0.24, size=15, side=BUY, ), options=CreateOrderOptions(tick_size="0.01", neg_risk=False), ) self.assertEqual( signed_order.order["makerAmount"], 3600000, ) self.assertEqual( signed_order.order["takerAmount"], 15000000, ) # SELL signed_order = builder.create_order( order_args=OrderArgs( token_id="123", price=0.24, size=15, side=SELL, ), options=CreateOrderOptions(tick_size="0.01", neg_risk=False), ) self.assertEqual( signed_order.order["makerAmount"], 15000000, ) self.assertEqual( signed_order.order["takerAmount"], 3600000, ) # BUY signed_order = builder.create_order( order_args=OrderArgs( token_id="123", price=0.82, size=101, side=BUY, ), options=CreateOrderOptions(tick_size="0.01", neg_risk=False), ) self.assertEqual( signed_order.order["makerAmount"], 82820000, ) self.assertEqual( signed_order.order["takerAmount"], 101000000, ) # SELL signed_order = builder.create_order( order_args=OrderArgs( token_id="123", price=0.82, size=101, side=SELL, ), options=CreateOrderOptions(tick_size="0.01", neg_risk=False), ) self.assertEqual( signed_order.order["makerAmount"], 101000000, ) self.assertEqual( signed_order.order["takerAmount"], 82820000, ) # BUY signed_order = builder.create_order( order_args=OrderArgs( token_id="123", price=0.78, size=12.8205, side=BUY, ), options=CreateOrderOptions(tick_size="0.01", neg_risk=False), ) self.assertEqual( signed_order.order["makerAmount"], 9999600, ) self.assertEqual( signed_order.order["takerAmount"], 12820000, ) # SELL signed_order = builder.create_order( order_args=OrderArgs( token_id="123", price=0.78, size=12.8205, side=SELL, ), options=CreateOrderOptions(tick_size="0.01", neg_risk=False), ) self.assertEqual( signed_order.order["makerAmount"], 12820000, ) self.assertEqual( signed_order.order["takerAmount"], 9999600, ) # SELL signed_order = builder.create_order( order_args=OrderArgs( token_id="123", price=0.39, size=2435.89, side=SELL, ), options=CreateOrderOptions(tick_size="0.01", neg_risk=False), ) self.assertEqual( signed_order.order["makerAmount"], 2435890000, ) self.assertEqual( signed_order.order["takerAmount"], 949997100, ) # SELL signed_order = builder.create_order( order_args=OrderArgs( token_id="123", price=0.43, size=19.1, side=SELL, ), options=CreateOrderOptions(tick_size="0.01", neg_risk=False), ) self.assertEqual( signed_order.order["makerAmount"], 19100000, ) self.assertEqual( signed_order.order["takerAmount"], 8213000, ) # BUY signed_order = builder.create_order( order_args=OrderArgs( token_id="123", price=0.58, size=18233.33, side=BUY, ), options=CreateOrderOptions(tick_size="0.01", neg_risk=False), ) self.assertEqual( signed_order.order["makerAmount"], 10575331400, ) self.assertEqual( signed_order.order["takerAmount"], 18233330000, ) self.assertEqual( signed_order.order["makerAmount"] / signed_order.order["takerAmount"], 0.58 ) def test_create_order_buy_0_1(self): builder = OrderBuilder(signer) signed_order = builder.create_order( order_args=OrderArgs( token_id="123", price=0.5, size=21.04, side=BUY, fee_rate_bps=111, nonce=123, expiration=50000, ), options=CreateOrderOptions(tick_size="0.1", neg_risk=False), ) self.assertTrue(isinstance(signed_order.order["salt"], int)) self.assertIsNotNone(signed_order) self.assertEqual( signed_order.order["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["taker"], "0x0000000000000000000000000000000000000000", ) self.assertEqual( signed_order.order["tokenId"], 123, ) self.assertEqual( signed_order.order["makerAmount"], 10520000, ) self.assertEqual( signed_order.order["takerAmount"], 21040000, ) self.assertEqual( signed_order.order["side"], 0, ) self.assertEqual( signed_order.order["expiration"], 50000, ) self.assertEqual( signed_order.order["nonce"], 123, ) self.assertEqual( signed_order.order["feeRateBps"], 111, ) self.assertEqual( signed_order.order["signatureType"], EOA, ) self.assertIsNotNone(signed_order.signature) self.assertEqual( float(signed_order.order["makerAmount"]) / float(signed_order.order["takerAmount"]), 0.5, ) def test_create_order_buy_0_01(self): builder = OrderBuilder(signer) signed_order = builder.create_order( order_args=OrderArgs( token_id="123", price=0.56, size=21.04, side=BUY, fee_rate_bps=111, nonce=123, expiration=50000, ), options=CreateOrderOptions(tick_size="0.01", neg_risk=False), ) self.assertTrue(isinstance(signed_order.order["salt"], int)) self.assertIsNotNone(signed_order) self.assertEqual( signed_order.order["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["taker"], "0x0000000000000000000000000000000000000000", ) self.assertEqual( signed_order.order["tokenId"], 123, ) self.assertEqual( signed_order.order["makerAmount"], 11782400, ) self.assertEqual( signed_order.order["takerAmount"], 21040000, ) self.assertEqual( signed_order.order["side"], 0, ) self.assertEqual( signed_order.order["expiration"], 50000, ) self.assertEqual( signed_order.order["nonce"], 123, ) self.assertEqual( signed_order.order["feeRateBps"], 111, ) self.assertEqual( signed_order.order["signatureType"], EOA, ) self.assertIsNotNone(signed_order.signature) self.assertEqual( float(signed_order.order["makerAmount"]) / float(signed_order.order["takerAmount"]), 0.56, ) def test_create_order_buy_0_001(self): builder = OrderBuilder(signer) signed_order = builder.create_order( order_args=OrderArgs( token_id="123", price=0.056, size=21.04, side=BUY, fee_rate_bps=111, nonce=123, expiration=50000, ), options=CreateOrderOptions(tick_size="0.001", neg_risk=False), ) self.assertTrue(isinstance(signed_order.order["salt"], int)) self.assertIsNotNone(signed_order) self.assertEqual( signed_order.order["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["taker"], "0x0000000000000000000000000000000000000000", ) self.assertEqual( signed_order.order["tokenId"], 123, ) self.assertEqual( signed_order.order["makerAmount"], 1178240, ) self.assertEqual( signed_order.order["takerAmount"], 21040000, ) self.assertEqual( signed_order.order["side"], 0, ) self.assertEqual( signed_order.order["expiration"], 50000, ) self.assertEqual( signed_order.order["nonce"], 123, ) self.assertEqual( signed_order.order["feeRateBps"], 111, ) self.assertEqual( signed_order.order["signatureType"], EOA, ) self.assertIsNotNone(signed_order.signature) self.assertEqual( float(signed_order.order["makerAmount"]) / float(signed_order.order["takerAmount"]), 0.056, ) def test_create_order_buy_0_0001(self): builder = OrderBuilder(signer) signed_order = builder.create_order( order_args=OrderArgs( token_id="123", price=0.0056, size=21.04, side=BUY, fee_rate_bps=111, nonce=123, expiration=50000, ), options=CreateOrderOptions(tick_size="0.0001", neg_risk=False), ) self.assertTrue(isinstance(signed_order.order["salt"], int)) self.assertIsNotNone(signed_order) self.assertEqual( signed_order.order["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["taker"], "0x0000000000000000000000000000000000000000", ) self.assertEqual( signed_order.order["tokenId"], 123, ) self.assertEqual( signed_order.order["makerAmount"], 117824, ) self.assertEqual( signed_order.order["takerAmount"], 21040000, ) self.assertEqual( signed_order.order["side"], 0, ) self.assertEqual( signed_order.order["expiration"], 50000, ) self.assertEqual( signed_order.order["nonce"], 123, ) self.assertEqual( signed_order.order["feeRateBps"], 111, ) self.assertEqual( signed_order.order["signatureType"], EOA, ) self.assertIsNotNone(signed_order.signature) self.assertEqual( float(signed_order.order["makerAmount"]) / float(signed_order.order["takerAmount"]), 0.0056, ) def test_create_order_sell_0_1(self): builder = OrderBuilder(signer, sig_type=POLY_GNOSIS_SAFE) signed_order = builder.create_order( order_args=OrderArgs( token_id="123", price=0.5, size=21.04, side=SELL, fee_rate_bps=111, nonce=123, expiration=50000, ), options=CreateOrderOptions(tick_size="0.1", neg_risk=False), ) self.assertTrue(isinstance(signed_order.order["salt"], int)) self.assertIsNotNone(signed_order) self.assertEqual( signed_order.order["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["taker"], "0x0000000000000000000000000000000000000000", ) self.assertEqual( signed_order.order["tokenId"], 123, ) self.assertEqual( signed_order.order["makerAmount"], 21040000, ) self.assertEqual( signed_order.order["takerAmount"], 10520000, ) self.assertEqual( signed_order.order["side"], 1, ) self.assertEqual( signed_order.order["expiration"], 50000, ) self.assertEqual( signed_order.order["nonce"], 123, ) self.assertEqual( signed_order.order["feeRateBps"], 111, ) self.assertEqual( signed_order.order["signatureType"], POLY_GNOSIS_SAFE, ) self.assertIsNotNone(signed_order.signature) self.assertEqual( float(signed_order.order["takerAmount"]) / float(signed_order.order["makerAmount"]), 0.5, ) def test_create_order_sell_0_01(self): builder = OrderBuilder(signer, sig_type=POLY_GNOSIS_SAFE) signed_order = builder.create_order( order_args=OrderArgs( token_id="123", price=0.56, size=21.04, side=SELL, fee_rate_bps=111, nonce=123, expiration=50000, ), options=CreateOrderOptions(tick_size="0.01", neg_risk=False), ) self.assertTrue(isinstance(signed_order.order["salt"], int)) self.assertIsNotNone(signed_order) self.assertEqual( signed_order.order["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["taker"], "0x0000000000000000000000000000000000000000", ) self.assertEqual( signed_order.order["tokenId"], 123, ) self.assertEqual( signed_order.order["makerAmount"], 21040000, ) self.assertEqual( signed_order.order["takerAmount"], 11782400, ) self.assertEqual( signed_order.order["side"], 1, ) self.assertEqual( signed_order.order["expiration"], 50000, ) self.assertEqual( signed_order.order["nonce"], 123, ) self.assertEqual( signed_order.order["feeRateBps"], 111, ) self.assertEqual( signed_order.order["signatureType"], POLY_GNOSIS_SAFE, ) self.assertIsNotNone(signed_order.signature) self.assertEqual( float(signed_order.order["takerAmount"]) / float(signed_order.order["makerAmount"]), 0.56, ) def test_create_order_sell_0_001(self): builder = OrderBuilder(signer, sig_type=POLY_GNOSIS_SAFE) signed_order = builder.create_order( order_args=OrderArgs( token_id="123", price=0.056, size=21.04, side=SELL, fee_rate_bps=111, nonce=123, expiration=50000, ), options=CreateOrderOptions(tick_size="0.001", neg_risk=False), ) self.assertTrue(isinstance(signed_order.order["salt"], int)) self.assertIsNotNone(signed_order) self.assertEqual( signed_order.order["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["taker"], "0x0000000000000000000000000000000000000000", ) self.assertEqual( signed_order.order["tokenId"], 123, ) self.assertEqual( signed_order.order["makerAmount"], 21040000, ) self.assertEqual( signed_order.order["takerAmount"], 1178240, ) self.assertEqual( signed_order.order["side"], 1, ) self.assertEqual( signed_order.order["expiration"], 50000, ) self.assertEqual( signed_order.order["nonce"], 123, ) self.assertEqual( signed_order.order["feeRateBps"], 111, ) self.assertEqual( signed_order.order["signatureType"], POLY_GNOSIS_SAFE, ) self.assertIsNotNone(signed_order.signature) self.assertEqual( float(signed_order.order["takerAmount"]) / float(signed_order.order["makerAmount"]), 0.056, ) def test_create_order_sell_0_0001(self): builder = OrderBuilder(signer, sig_type=POLY_GNOSIS_SAFE) signed_order = builder.create_order( order_args=OrderArgs( token_id="123", price=0.0056, size=21.04, side=SELL, fee_rate_bps=111, nonce=123, expiration=50000, ), options=CreateOrderOptions(tick_size="0.0001", neg_risk=False), ) self.assertTrue(isinstance(signed_order.order["salt"], int)) self.assertIsNotNone(signed_order) self.assertEqual( signed_order.order["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["taker"], "0x0000000000000000000000000000000000000000", ) self.assertEqual( signed_order.order["tokenId"], 123, ) self.assertEqual( signed_order.order["makerAmount"], 21040000, ) self.assertEqual( signed_order.order["takerAmount"], 117824, ) self.assertEqual( signed_order.order["side"], 1, ) self.assertEqual( signed_order.order["expiration"], 50000, ) self.assertEqual( signed_order.order["nonce"], 123, ) self.assertEqual( signed_order.order["feeRateBps"], 111, ) self.assertEqual( signed_order.order["signatureType"], POLY_GNOSIS_SAFE, ) self.assertIsNotNone(signed_order.signature) self.assertEqual( float(signed_order.order["takerAmount"]) / float(signed_order.order["makerAmount"]), 0.0056, ) def test_create_order_decimal_accuracy_neg_risk(self): builder = OrderBuilder(signer) # BUY signed_order = builder.create_order( order_args=OrderArgs( token_id="123", price=0.24, size=15, side=BUY, ), options=CreateOrderOptions(tick_size="0.01", neg_risk=True), ) self.assertEqual( signed_order.order["makerAmount"], 3600000, ) self.assertEqual( signed_order.order["takerAmount"], 15000000, ) # SELL signed_order = builder.create_order( order_args=OrderArgs( token_id="123", price=0.24, size=15, side=SELL, ), options=CreateOrderOptions(tick_size="0.01", neg_risk=True), ) self.assertEqual( signed_order.order["makerAmount"], 15000000, ) self.assertEqual( signed_order.order["takerAmount"], 3600000, ) # BUY signed_order = builder.create_order( order_args=OrderArgs( token_id="123", price=0.82, size=101, side=BUY, ), options=CreateOrderOptions(tick_size="0.01", neg_risk=True), ) self.assertEqual( signed_order.order["makerAmount"], 82820000, ) self.assertEqual( signed_order.order["takerAmount"], 101000000, ) # SELL signed_order = builder.create_order( order_args=OrderArgs( token_id="123", price=0.82, size=101, side=SELL, ), options=CreateOrderOptions(tick_size="0.01", neg_risk=True), ) self.assertEqual( signed_order.order["makerAmount"], 101000000, ) self.assertEqual( signed_order.order["takerAmount"], 82820000, ) # BUY signed_order = builder.create_order( order_args=OrderArgs( token_id="123", price=0.78, size=12.8205, side=BUY, ), options=CreateOrderOptions(tick_size="0.01", neg_risk=True), ) self.assertEqual( signed_order.order["makerAmount"], 9999600, ) self.assertEqual( signed_order.order["takerAmount"], 12820000, ) # SELL signed_order = builder.create_order( order_args=OrderArgs( token_id="123", price=0.78, size=12.8205, side=SELL, ), options=CreateOrderOptions(tick_size="0.01", neg_risk=True), ) self.assertEqual( signed_order.order["makerAmount"], 12820000, ) self.assertEqual( signed_order.order["takerAmount"], 9999600, ) # SELL signed_order = builder.create_order( order_args=OrderArgs( token_id="123", price=0.39, size=2435.89, side=SELL, ), options=CreateOrderOptions(tick_size="0.01", neg_risk=True), ) self.assertEqual( signed_order.order["makerAmount"], 2435890000, ) self.assertEqual( signed_order.order["takerAmount"], 949997100, ) # SELL signed_order = builder.create_order( order_args=OrderArgs( token_id="123", price=0.43, size=19.1, side=SELL, ), options=CreateOrderOptions(tick_size="0.01", neg_risk=True), ) self.assertEqual( signed_order.order["makerAmount"], 19100000, ) self.assertEqual( signed_order.order["takerAmount"], 8213000, ) # BUY signed_order = builder.create_order( order_args=OrderArgs( token_id="123", price=0.58, size=18233.33, side=BUY, ), options=CreateOrderOptions(tick_size="0.01", neg_risk=True), ) self.assertEqual( signed_order.order["makerAmount"], 10575331400, ) self.assertEqual( signed_order.order["takerAmount"], 18233330000, ) self.assertEqual( signed_order.order["makerAmount"] / signed_order.order["takerAmount"], 0.58 ) def test_create_order_buy_0_1_neg_risk(self): builder = OrderBuilder(signer) signed_order = builder.create_order( order_args=OrderArgs( token_id="123", price=0.5, size=21.04, side=BUY, fee_rate_bps=111, nonce=123, expiration=50000, ), options=CreateOrderOptions(tick_size="0.1", neg_risk=True), ) self.assertTrue(isinstance(signed_order.order["salt"], int)) self.assertIsNotNone(signed_order) self.assertEqual( signed_order.order["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["taker"], "0x0000000000000000000000000000000000000000", ) self.assertEqual( signed_order.order["tokenId"], 123, ) self.assertEqual( signed_order.order["makerAmount"], 10520000, ) self.assertEqual( signed_order.order["takerAmount"], 21040000, ) self.assertEqual( signed_order.order["side"], 0, ) self.assertEqual( signed_order.order["expiration"], 50000, ) self.assertEqual( signed_order.order["nonce"], 123, ) self.assertEqual( signed_order.order["feeRateBps"], 111, ) self.assertEqual( signed_order.order["signatureType"], EOA, ) self.assertIsNotNone(signed_order.signature) self.assertEqual( float(signed_order.order["makerAmount"]) / float(signed_order.order["takerAmount"]), 0.5, ) def test_create_order_buy_0_01_neg_risk(self): builder = OrderBuilder(signer) signed_order = builder.create_order( order_args=OrderArgs( token_id="123", price=0.56, size=21.04, side=BUY, fee_rate_bps=111, nonce=123, expiration=50000, ), options=CreateOrderOptions(tick_size="0.01", neg_risk=True), ) self.assertTrue(isinstance(signed_order.order["salt"], int)) self.assertIsNotNone(signed_order) self.assertEqual( signed_order.order["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["taker"], "0x0000000000000000000000000000000000000000", ) self.assertEqual( signed_order.order["tokenId"], 123, ) self.assertEqual( signed_order.order["makerAmount"], 11782400, ) self.assertEqual( signed_order.order["takerAmount"], 21040000, ) self.assertEqual( signed_order.order["side"], 0, ) self.assertEqual( signed_order.order["expiration"], 50000, ) self.assertEqual( signed_order.order["nonce"], 123, ) self.assertEqual( signed_order.order["feeRateBps"], 111, ) self.assertEqual( signed_order.order["signatureType"], EOA, ) self.assertIsNotNone(signed_order.signature) self.assertEqual( float(signed_order.order["makerAmount"]) / float(signed_order.order["takerAmount"]), 0.56, ) def test_create_order_buy_0_001_neg_risk(self): builder = OrderBuilder(signer) signed_order = builder.create_order( order_args=OrderArgs( token_id="123", price=0.056, size=21.04, side=BUY, fee_rate_bps=111, nonce=123, expiration=50000, ), options=CreateOrderOptions(tick_size="0.001", neg_risk=True), ) self.assertTrue(isinstance(signed_order.order["salt"], int)) self.assertIsNotNone(signed_order) self.assertEqual( signed_order.order["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["taker"], "0x0000000000000000000000000000000000000000", ) self.assertEqual( signed_order.order["tokenId"], 123, ) self.assertEqual( signed_order.order["makerAmount"], 1178240, ) self.assertEqual( signed_order.order["takerAmount"], 21040000, ) self.assertEqual( signed_order.order["side"], 0, ) self.assertEqual( signed_order.order["expiration"], 50000, ) self.assertEqual( signed_order.order["nonce"], 123, ) self.assertEqual( signed_order.order["feeRateBps"], 111, ) self.assertEqual( signed_order.order["signatureType"], EOA, ) self.assertIsNotNone(signed_order.signature) self.assertEqual( float(signed_order.order["makerAmount"]) / float(signed_order.order["takerAmount"]), 0.056, ) def test_create_order_buy_0_0001_neg_risk(self): builder = OrderBuilder(signer) signed_order = builder.create_order( order_args=OrderArgs( token_id="123", price=0.0056, size=21.04, side=BUY, fee_rate_bps=111, nonce=123, expiration=50000, ), options=CreateOrderOptions(tick_size="0.0001", neg_risk=True), ) self.assertTrue(isinstance(signed_order.order["salt"], int)) self.assertIsNotNone(signed_order) self.assertEqual( signed_order.order["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["taker"], "0x0000000000000000000000000000000000000000", ) self.assertEqual( signed_order.order["tokenId"], 123, ) self.assertEqual( signed_order.order["makerAmount"], 117824, ) self.assertEqual( signed_order.order["takerAmount"], 21040000, ) self.assertEqual( signed_order.order["side"], 0, ) self.assertEqual( signed_order.order["expiration"], 50000, ) self.assertEqual( signed_order.order["nonce"], 123, ) self.assertEqual( signed_order.order["feeRateBps"], 111, ) self.assertEqual( signed_order.order["signatureType"], EOA, ) self.assertIsNotNone(signed_order.signature) self.assertEqual( float(signed_order.order["makerAmount"]) / float(signed_order.order["takerAmount"]), 0.0056, ) def test_create_order_sell_0_1_neg_risk(self): builder = OrderBuilder(signer, sig_type=POLY_GNOSIS_SAFE) signed_order = builder.create_order( order_args=OrderArgs( token_id="123", price=0.5, size=21.04, side=SELL, fee_rate_bps=111, nonce=123, expiration=50000, ), options=CreateOrderOptions(tick_size="0.1", neg_risk=True), ) self.assertTrue(isinstance(signed_order.order["salt"], int)) self.assertIsNotNone(signed_order) self.assertEqual( signed_order.order["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["taker"], "0x0000000000000000000000000000000000000000", ) self.assertEqual( signed_order.order["tokenId"], 123, ) self.assertEqual( signed_order.order["makerAmount"], 21040000, ) self.assertEqual( signed_order.order["takerAmount"], 10520000, ) self.assertEqual( signed_order.order["side"], 1, ) self.assertEqual( signed_order.order["expiration"], 50000, ) self.assertEqual( signed_order.order["nonce"], 123, ) self.assertEqual( signed_order.order["feeRateBps"], 111, ) self.assertEqual( signed_order.order["signatureType"], POLY_GNOSIS_SAFE, ) self.assertIsNotNone(signed_order.signature) self.assertEqual( float(signed_order.order["takerAmount"]) / float(signed_order.order["makerAmount"]), 0.5, ) def test_create_order_sell_0_01_neg_risk(self): builder = OrderBuilder(signer, sig_type=POLY_GNOSIS_SAFE) signed_order = builder.create_order( order_args=OrderArgs( token_id="123", price=0.56, size=21.04, side=SELL, fee_rate_bps=111, nonce=123, expiration=50000, ), options=CreateOrderOptions(tick_size="0.01", neg_risk=True), ) self.assertTrue(isinstance(signed_order.order["salt"], int)) self.assertIsNotNone(signed_order) self.assertEqual( signed_order.order["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["taker"], "0x0000000000000000000000000000000000000000", ) self.assertEqual( signed_order.order["tokenId"], 123, ) self.assertEqual( signed_order.order["makerAmount"], 21040000, ) self.assertEqual( signed_order.order["takerAmount"], 11782400, ) self.assertEqual( signed_order.order["side"], 1, ) self.assertEqual( signed_order.order["expiration"], 50000, ) self.assertEqual( signed_order.order["nonce"], 123, ) self.assertEqual( signed_order.order["feeRateBps"], 111, ) self.assertEqual( signed_order.order["signatureType"], POLY_GNOSIS_SAFE, ) self.assertIsNotNone(signed_order.signature) self.assertEqual( float(signed_order.order["takerAmount"]) / float(signed_order.order["makerAmount"]), 0.56, ) def test_create_order_sell_0_001_neg_risk(self): builder = OrderBuilder(signer, sig_type=POLY_GNOSIS_SAFE) signed_order = builder.create_order( order_args=OrderArgs( token_id="123", price=0.056, size=21.04, side=SELL, fee_rate_bps=111, nonce=123, expiration=50000, ), options=CreateOrderOptions(tick_size="0.001", neg_risk=True), ) self.assertTrue(isinstance(signed_order.order["salt"], int)) self.assertIsNotNone(signed_order) self.assertEqual( signed_order.order["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["taker"], "0x0000000000000000000000000000000000000000", ) self.assertEqual( signed_order.order["tokenId"], 123, ) self.assertEqual( signed_order.order["makerAmount"], 21040000, ) self.assertEqual( signed_order.order["takerAmount"], 1178240, ) self.assertEqual( signed_order.order["side"], 1, ) self.assertEqual( signed_order.order["expiration"], 50000, ) self.assertEqual( signed_order.order["nonce"], 123, ) self.assertEqual( signed_order.order["feeRateBps"], 111, ) self.assertEqual( signed_order.order["signatureType"], POLY_GNOSIS_SAFE, ) self.assertIsNotNone(signed_order.signature) self.assertEqual( float(signed_order.order["takerAmount"]) / float(signed_order.order["makerAmount"]), 0.056, ) def test_create_order_sell_0_0001_neg_risk(self): builder = OrderBuilder(signer, sig_type=POLY_GNOSIS_SAFE) signed_order = builder.create_order( order_args=OrderArgs( token_id="123", price=0.0056, size=21.04, side=SELL, fee_rate_bps=111, nonce=123, expiration=50000, ), options=CreateOrderOptions(tick_size="0.0001", neg_risk=True), ) self.assertTrue(isinstance(signed_order.order["salt"], int)) self.assertIsNotNone(signed_order) self.assertEqual( signed_order.order["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["taker"], "0x0000000000000000000000000000000000000000", ) self.assertEqual( signed_order.order["tokenId"], 123, ) self.assertEqual( signed_order.order["makerAmount"], 21040000, ) self.assertEqual( signed_order.order["takerAmount"], 117824, ) self.assertEqual( signed_order.order["side"], 1, ) self.assertEqual( signed_order.order["expiration"], 50000, ) self.assertEqual( signed_order.order["nonce"], 123, ) self.assertEqual( signed_order.order["feeRateBps"], 111, ) self.assertEqual( signed_order.order["signatureType"], POLY_GNOSIS_SAFE, ) self.assertIsNotNone(signed_order.signature) self.assertEqual( float(signed_order.order["takerAmount"]) / float(signed_order.order["makerAmount"]), 0.0056, ) def test_dict_order_buy_neg_risk(self): builder = OrderBuilder(signer) signed_order = builder.create_order( order_args=OrderArgs( token_id="123", price=0.56, size=21.04, side=BUY, fee_rate_bps=111, nonce=123, expiration=50000, ), options=CreateOrderOptions(tick_size="0.01", neg_risk=True), ) self.assertIsNotNone(signed_order) signed_order_dict = signed_order.dict() self.assertIsNotNone(signed_order_dict) self.assertTrue(isinstance(signed_order_dict["salt"], int)) self.assertEqual( signed_order_dict["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order_dict["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order_dict["taker"], "0x0000000000000000000000000000000000000000", ) self.assertEqual( signed_order_dict["tokenId"], "123", ) self.assertEqual( signed_order_dict["makerAmount"], "11782400", ) self.assertEqual( signed_order_dict["takerAmount"], "21040000", ) self.assertEqual( signed_order_dict["side"], BUY, ) self.assertEqual( signed_order_dict["expiration"], "50000", ) self.assertEqual( signed_order_dict["nonce"], "123", ) self.assertEqual( signed_order_dict["feeRateBps"], "111", ) self.assertEqual( signed_order_dict["signatureType"], EOA, ) self.assertIsNotNone(signed_order_dict["signature"]) def test_dict_order_sell_neg_risk(self): builder = OrderBuilder(signer, sig_type=POLY_GNOSIS_SAFE) signed_order = builder.create_order( order_args=OrderArgs( token_id="123", price=0.56, size=21.04, side=SELL, fee_rate_bps=111, nonce=123, expiration=50000, ), options=CreateOrderOptions(tick_size="0.01", neg_risk=True), ) self.assertIsNotNone(signed_order) signed_order_dict = signed_order.dict() self.assertIsNotNone(signed_order_dict) self.assertTrue(isinstance(signed_order_dict["salt"], int)) self.assertEqual( signed_order_dict["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order_dict["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order_dict["taker"], "0x0000000000000000000000000000000000000000", ) self.assertEqual( signed_order_dict["tokenId"], "123", ) self.assertEqual( signed_order_dict["makerAmount"], "21040000", ) self.assertEqual( signed_order_dict["takerAmount"], "11782400", ) self.assertEqual( signed_order_dict["side"], SELL, ) self.assertEqual( signed_order_dict["expiration"], "50000", ) self.assertEqual( signed_order_dict["nonce"], "123", ) self.assertEqual( signed_order_dict["feeRateBps"], "111", ) self.assertEqual( signed_order_dict["signatureType"], POLY_GNOSIS_SAFE, ) self.assertIsNotNone(signed_order_dict["signature"]) def test_dict_order_buy(self): builder = OrderBuilder(signer) signed_order = builder.create_order( order_args=OrderArgs( token_id="123", price=0.56, size=21.04, side=BUY, fee_rate_bps=111, nonce=123, expiration=50000, ), options=CreateOrderOptions(tick_size="0.01", neg_risk=False), ) self.assertIsNotNone(signed_order) signed_order_dict = signed_order.dict() self.assertIsNotNone(signed_order_dict) self.assertTrue(isinstance(signed_order_dict["salt"], int)) self.assertEqual( signed_order_dict["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order_dict["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order_dict["taker"], "0x0000000000000000000000000000000000000000", ) self.assertEqual( signed_order_dict["tokenId"], "123", ) self.assertEqual( signed_order_dict["makerAmount"], "11782400", ) self.assertEqual( signed_order_dict["takerAmount"], "21040000", ) self.assertEqual( signed_order_dict["side"], BUY, ) self.assertEqual( signed_order_dict["expiration"], "50000", ) self.assertEqual( signed_order_dict["nonce"], "123", ) self.assertEqual( signed_order_dict["feeRateBps"], "111", ) self.assertEqual( signed_order_dict["signatureType"], EOA, ) self.assertIsNotNone(signed_order_dict["signature"]) def test_dict_order_sell(self): builder = OrderBuilder(signer, sig_type=POLY_GNOSIS_SAFE) signed_order = builder.create_order( order_args=OrderArgs( token_id="123", price=0.56, size=21.04, side=SELL, fee_rate_bps=111, nonce=123, expiration=50000, ), options=CreateOrderOptions(tick_size="0.01", neg_risk=False), ) self.assertIsNotNone(signed_order) signed_order_dict = signed_order.dict() self.assertIsNotNone(signed_order_dict) self.assertTrue(isinstance(signed_order_dict["salt"], int)) self.assertEqual( signed_order_dict["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order_dict["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order_dict["taker"], "0x0000000000000000000000000000000000000000", ) self.assertEqual( signed_order_dict["tokenId"], "123", ) self.assertEqual( signed_order_dict["makerAmount"], "21040000", ) self.assertEqual( signed_order_dict["takerAmount"], "11782400", ) self.assertEqual( signed_order_dict["side"], SELL, ) self.assertEqual( signed_order_dict["expiration"], "50000", ) self.assertEqual( signed_order_dict["nonce"], "123", ) self.assertEqual( signed_order_dict["feeRateBps"], "111", ) self.assertEqual( signed_order_dict["signatureType"], POLY_GNOSIS_SAFE, ) self.assertIsNotNone(signed_order_dict["signature"]) def test_create_market_order_buy_0_1(self): builder = OrderBuilder(signer) signed_order = builder.create_market_order( order_args=MarketOrderArgs( side=BUY, token_id="123", price=0.5, amount=100, fee_rate_bps=111, nonce=123, ), options=CreateOrderOptions(tick_size="0.1", neg_risk=False), ) self.assertTrue(isinstance(signed_order.order["salt"], int)) self.assertIsNotNone(signed_order) self.assertEqual( signed_order.order["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["taker"], "0x0000000000000000000000000000000000000000", ) self.assertEqual( signed_order.order["tokenId"], 123, ) self.assertEqual( signed_order.order["makerAmount"], 100000000, ) self.assertEqual( signed_order.order["takerAmount"], 200000000, ) self.assertEqual( signed_order.order["side"], 0, ) self.assertEqual( signed_order.order["expiration"], 0, ) self.assertEqual( signed_order.order["nonce"], 123, ) self.assertEqual( signed_order.order["feeRateBps"], 111, ) self.assertEqual( signed_order.order["signatureType"], EOA, ) self.assertIsNotNone(signed_order.signature) self.assertGreaterEqual( float(signed_order.order["makerAmount"]) / float(signed_order.order["takerAmount"]), 0.5, ) def test_create_market_order_buy_0_01(self): builder = OrderBuilder(signer) signed_order = builder.create_market_order( order_args=MarketOrderArgs( side=BUY, token_id="123", price=0.56, amount=100, fee_rate_bps=111, nonce=123, ), options=CreateOrderOptions(tick_size="0.01", neg_risk=False), ) self.assertTrue(isinstance(signed_order.order["salt"], int)) self.assertIsNotNone(signed_order) self.assertEqual( signed_order.order["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["taker"], "0x0000000000000000000000000000000000000000", ) self.assertEqual( signed_order.order["tokenId"], 123, ) self.assertEqual( signed_order.order["makerAmount"], 100000000, ) self.assertEqual( signed_order.order["takerAmount"], 178571400, ) self.assertEqual( signed_order.order["side"], 0, ) self.assertEqual( signed_order.order["expiration"], 0, ) self.assertEqual( signed_order.order["nonce"], 123, ) self.assertEqual( signed_order.order["feeRateBps"], 111, ) self.assertEqual( signed_order.order["signatureType"], EOA, ) self.assertIsNotNone(signed_order.signature) self.assertGreaterEqual( float(signed_order.order["makerAmount"]) / float(signed_order.order["takerAmount"]), 0.56, ) def test_create_market_order_buy_0_001(self): builder = OrderBuilder(signer) signed_order = builder.create_market_order( order_args=MarketOrderArgs( side=BUY, token_id="123", price=0.056, amount=100, fee_rate_bps=111, nonce=123, ), options=CreateOrderOptions(tick_size="0.001", neg_risk=False), ) self.assertTrue(isinstance(signed_order.order["salt"], int)) self.assertIsNotNone(signed_order) self.assertEqual( signed_order.order["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["taker"], "0x0000000000000000000000000000000000000000", ) self.assertEqual( signed_order.order["tokenId"], 123, ) self.assertEqual( signed_order.order["makerAmount"], 100000000, ) self.assertEqual( signed_order.order["takerAmount"], 1785714280, ) self.assertEqual( signed_order.order["side"], 0, ) self.assertEqual( signed_order.order["expiration"], 0, ) self.assertEqual( signed_order.order["nonce"], 123, ) self.assertEqual( signed_order.order["feeRateBps"], 111, ) self.assertEqual( signed_order.order["signatureType"], EOA, ) self.assertIsNotNone(signed_order.signature) self.assertGreaterEqual( float(signed_order.order["makerAmount"]) / float(signed_order.order["takerAmount"]), 0.056, ) def test_create_market_order_buy_0_0001(self): builder = OrderBuilder(signer) signed_order = builder.create_market_order( order_args=MarketOrderArgs( side=BUY, token_id="123", price=0.0056, amount=100, fee_rate_bps=111, nonce=123, ), options=CreateOrderOptions(tick_size="0.0001", neg_risk=False), ) self.assertTrue(isinstance(signed_order.order["salt"], int)) self.assertIsNotNone(signed_order) self.assertEqual( signed_order.order["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["taker"], "0x0000000000000000000000000000000000000000", ) self.assertEqual( signed_order.order["tokenId"], 123, ) self.assertEqual( signed_order.order["makerAmount"], 100000000, ) self.assertEqual( signed_order.order["takerAmount"], 17857142857, ) self.assertEqual( signed_order.order["side"], 0, ) self.assertEqual( signed_order.order["expiration"], 0, ) self.assertEqual( signed_order.order["nonce"], 123, ) self.assertEqual( signed_order.order["feeRateBps"], 111, ) self.assertEqual( signed_order.order["signatureType"], EOA, ) self.assertIsNotNone(signed_order.signature) self.assertGreaterEqual( float(signed_order.order["makerAmount"]) / float(signed_order.order["takerAmount"]), 0.0056, ) def test_create_market_order_buy_0_1_neg_risk(self): builder = OrderBuilder(signer) signed_order = builder.create_market_order( order_args=MarketOrderArgs( side=BUY, token_id="123", price=0.5, amount=100, fee_rate_bps=111, nonce=123, ), options=CreateOrderOptions(tick_size="0.1", neg_risk=True), ) self.assertTrue(isinstance(signed_order.order["salt"], int)) self.assertIsNotNone(signed_order) self.assertEqual( signed_order.order["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["taker"], "0x0000000000000000000000000000000000000000", ) self.assertEqual( signed_order.order["tokenId"], 123, ) self.assertEqual( signed_order.order["makerAmount"], 100000000, ) self.assertEqual( signed_order.order["takerAmount"], 200000000, ) self.assertEqual( signed_order.order["side"], 0, ) self.assertEqual( signed_order.order["expiration"], 0, ) self.assertEqual( signed_order.order["nonce"], 123, ) self.assertEqual( signed_order.order["feeRateBps"], 111, ) self.assertEqual( signed_order.order["signatureType"], EOA, ) self.assertIsNotNone(signed_order.signature) self.assertGreaterEqual( float(signed_order.order["makerAmount"]) / float(signed_order.order["takerAmount"]), 0.5, ) def test_create_market_order_buy_0_01_neg_risk(self): builder = OrderBuilder(signer) signed_order = builder.create_market_order( order_args=MarketOrderArgs( side=BUY, token_id="123", price=0.56, amount=100, fee_rate_bps=111, nonce=123, ), options=CreateOrderOptions(tick_size="0.01", neg_risk=True), ) self.assertTrue(isinstance(signed_order.order["salt"], int)) self.assertIsNotNone(signed_order) self.assertEqual( signed_order.order["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["taker"], "0x0000000000000000000000000000000000000000", ) self.assertEqual( signed_order.order["tokenId"], 123, ) self.assertEqual( signed_order.order["makerAmount"], 100000000, ) self.assertEqual( signed_order.order["takerAmount"], 178571400, ) self.assertEqual( signed_order.order["side"], 0, ) self.assertEqual( signed_order.order["expiration"], 0, ) self.assertEqual( signed_order.order["nonce"], 123, ) self.assertEqual( signed_order.order["feeRateBps"], 111, ) self.assertEqual( signed_order.order["signatureType"], EOA, ) self.assertIsNotNone(signed_order.signature) self.assertGreaterEqual( float(signed_order.order["makerAmount"]) / float(signed_order.order["takerAmount"]), 0.56, ) def test_create_market_order_buy_0_001_neg_risk(self): builder = OrderBuilder(signer) signed_order = builder.create_market_order( order_args=MarketOrderArgs( side=BUY, token_id="123", price=0.056, amount=100, fee_rate_bps=111, nonce=123, ), options=CreateOrderOptions(tick_size="0.001", neg_risk=True), ) self.assertTrue(isinstance(signed_order.order["salt"], int)) self.assertIsNotNone(signed_order) self.assertEqual( signed_order.order["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["taker"], "0x0000000000000000000000000000000000000000", ) self.assertEqual( signed_order.order["tokenId"], 123, ) self.assertEqual( signed_order.order["makerAmount"], 100000000, ) self.assertEqual( signed_order.order["takerAmount"], 1785714280, ) self.assertEqual( signed_order.order["side"], 0, ) self.assertEqual( signed_order.order["expiration"], 0, ) self.assertEqual( signed_order.order["nonce"], 123, ) self.assertEqual( signed_order.order["feeRateBps"], 111, ) self.assertEqual( signed_order.order["signatureType"], EOA, ) self.assertIsNotNone(signed_order.signature) self.assertGreaterEqual( float(signed_order.order["makerAmount"]) / float(signed_order.order["takerAmount"]), 0.056, ) def test_create_market_order_buy_0_0001_neg_risk(self): builder = OrderBuilder(signer) signed_order = builder.create_market_order( order_args=MarketOrderArgs( side=BUY, token_id="123", price=0.0056, amount=100, fee_rate_bps=111, nonce=123, ), options=CreateOrderOptions(tick_size="0.0001", neg_risk=True), ) self.assertTrue(isinstance(signed_order.order["salt"], int)) self.assertIsNotNone(signed_order) self.assertEqual( signed_order.order["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["taker"], "0x0000000000000000000000000000000000000000", ) self.assertEqual( signed_order.order["tokenId"], 123, ) self.assertEqual( signed_order.order["makerAmount"], 100000000, ) self.assertEqual( signed_order.order["takerAmount"], 17857142857, ) self.assertEqual( signed_order.order["side"], 0, ) self.assertEqual( signed_order.order["expiration"], 0, ) self.assertEqual( signed_order.order["nonce"], 123, ) self.assertEqual( signed_order.order["feeRateBps"], 111, ) self.assertEqual( signed_order.order["signatureType"], EOA, ) self.assertIsNotNone(signed_order.signature) self.assertGreaterEqual( float(signed_order.order["makerAmount"]) / float(signed_order.order["takerAmount"]), 0.0056, ) def test_create_market_order_sell_0_1(self): builder = OrderBuilder(signer) signed_order = builder.create_market_order( order_args=MarketOrderArgs( side=SELL, token_id="123", price=0.5, amount=100, fee_rate_bps=111, nonce=123, ), options=CreateOrderOptions(tick_size="0.1", neg_risk=False), ) self.assertTrue(isinstance(signed_order.order["salt"], int)) self.assertIsNotNone(signed_order) self.assertEqual( signed_order.order["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["taker"], "0x0000000000000000000000000000000000000000", ) self.assertEqual( signed_order.order["tokenId"], 123, ) self.assertEqual( signed_order.order["makerAmount"], 100000000, ) self.assertEqual( signed_order.order["takerAmount"], 50000000, ) self.assertEqual( signed_order.order["side"], 1, ) self.assertEqual( signed_order.order["expiration"], 0, ) self.assertEqual( signed_order.order["nonce"], 123, ) self.assertEqual( signed_order.order["feeRateBps"], 111, ) self.assertEqual( signed_order.order["signatureType"], EOA, ) self.assertIsNotNone(signed_order.signature) self.assertGreaterEqual( float(signed_order.order["takerAmount"]) / float(signed_order.order["makerAmount"]), 0.5, ) def test_create_market_order_sell_0_01(self): builder = OrderBuilder(signer) signed_order = builder.create_market_order( order_args=MarketOrderArgs( side=SELL, token_id="123", price=0.56, amount=100, fee_rate_bps=111, nonce=123, ), options=CreateOrderOptions(tick_size="0.01", neg_risk=False), ) self.assertTrue(isinstance(signed_order.order["salt"], int)) self.assertIsNotNone(signed_order) self.assertEqual( signed_order.order["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["taker"], "0x0000000000000000000000000000000000000000", ) self.assertEqual( signed_order.order["tokenId"], 123, ) self.assertEqual( signed_order.order["makerAmount"], 100000000, ) self.assertEqual( signed_order.order["takerAmount"], 56000000, ) self.assertEqual( signed_order.order["side"], 1, ) self.assertEqual( signed_order.order["expiration"], 0, ) self.assertEqual( signed_order.order["nonce"], 123, ) self.assertEqual( signed_order.order["feeRateBps"], 111, ) self.assertEqual( signed_order.order["signatureType"], EOA, ) self.assertIsNotNone(signed_order.signature) self.assertGreaterEqual( float(signed_order.order["takerAmount"]) / float(signed_order.order["makerAmount"]), 0.56, ) def test_create_market_order_sell_0_001(self): builder = OrderBuilder(signer) signed_order = builder.create_market_order( order_args=MarketOrderArgs( side=SELL, token_id="123", price=0.056, amount=100, fee_rate_bps=111, nonce=123, ), options=CreateOrderOptions(tick_size="0.001", neg_risk=False), ) self.assertTrue(isinstance(signed_order.order["salt"], int)) self.assertIsNotNone(signed_order) self.assertEqual( signed_order.order["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["taker"], "0x0000000000000000000000000000000000000000", ) self.assertEqual( signed_order.order["tokenId"], 123, ) self.assertEqual( signed_order.order["makerAmount"], 100000000, ) self.assertEqual( signed_order.order["takerAmount"], 5600000, ) self.assertEqual( signed_order.order["side"], 1, ) self.assertEqual( signed_order.order["expiration"], 0, ) self.assertEqual( signed_order.order["nonce"], 123, ) self.assertEqual( signed_order.order["feeRateBps"], 111, ) self.assertEqual( signed_order.order["signatureType"], EOA, ) self.assertIsNotNone(signed_order.signature) self.assertGreaterEqual( float(signed_order.order["takerAmount"]) / float(signed_order.order["makerAmount"]), 0.056, ) def test_create_market_order_sell_0_0001(self): builder = OrderBuilder(signer) signed_order = builder.create_market_order( order_args=MarketOrderArgs( side=SELL, token_id="123", price=0.0056, amount=100, fee_rate_bps=111, nonce=123, ), options=CreateOrderOptions(tick_size="0.0001", neg_risk=False), ) self.assertTrue(isinstance(signed_order.order["salt"], int)) self.assertIsNotNone(signed_order) self.assertEqual( signed_order.order["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["taker"], "0x0000000000000000000000000000000000000000", ) self.assertEqual( signed_order.order["tokenId"], 123, ) self.assertEqual( signed_order.order["makerAmount"], 100000000, ) self.assertEqual( signed_order.order["takerAmount"], 560000, ) self.assertEqual( signed_order.order["side"], 1, ) self.assertEqual( signed_order.order["expiration"], 0, ) self.assertEqual( signed_order.order["nonce"], 123, ) self.assertEqual( signed_order.order["feeRateBps"], 111, ) self.assertEqual( signed_order.order["signatureType"], EOA, ) self.assertIsNotNone(signed_order.signature) self.assertGreaterEqual( float(signed_order.order["takerAmount"]) / float(signed_order.order["makerAmount"]), 0.0056, ) def test_create_market_order_sell_0_1_neg_risk(self): builder = OrderBuilder(signer) signed_order = builder.create_market_order( order_args=MarketOrderArgs( side=SELL, token_id="123", price=0.5, amount=100, fee_rate_bps=111, nonce=123, ), options=CreateOrderOptions(tick_size="0.1", neg_risk=True), ) self.assertTrue(isinstance(signed_order.order["salt"], int)) self.assertIsNotNone(signed_order) self.assertEqual( signed_order.order["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["taker"], "0x0000000000000000000000000000000000000000", ) self.assertEqual( signed_order.order["tokenId"], 123, ) self.assertEqual( signed_order.order["makerAmount"], 100000000, ) self.assertEqual( signed_order.order["takerAmount"], 50000000, ) self.assertEqual( signed_order.order["side"], 1, ) self.assertEqual( signed_order.order["expiration"], 0, ) self.assertEqual( signed_order.order["nonce"], 123, ) self.assertEqual( signed_order.order["feeRateBps"], 111, ) self.assertEqual( signed_order.order["signatureType"], EOA, ) self.assertIsNotNone(signed_order.signature) self.assertGreaterEqual( float(signed_order.order["takerAmount"]) / float(signed_order.order["makerAmount"]), 0.5, ) def test_create_market_order_sell_0_01_neg_risk(self): builder = OrderBuilder(signer) signed_order = builder.create_market_order( order_args=MarketOrderArgs( side=SELL, token_id="123", price=0.56, amount=100, fee_rate_bps=111, nonce=123, ), options=CreateOrderOptions(tick_size="0.01", neg_risk=True), ) self.assertTrue(isinstance(signed_order.order["salt"], int)) self.assertIsNotNone(signed_order) self.assertEqual( signed_order.order["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["taker"], "0x0000000000000000000000000000000000000000", ) self.assertEqual( signed_order.order["tokenId"], 123, ) self.assertEqual( signed_order.order["makerAmount"], 100000000, ) self.assertEqual( signed_order.order["takerAmount"], 56000000, ) self.assertEqual( signed_order.order["side"], 1, ) self.assertEqual( signed_order.order["expiration"], 0, ) self.assertEqual( signed_order.order["nonce"], 123, ) self.assertEqual( signed_order.order["feeRateBps"], 111, ) self.assertEqual( signed_order.order["signatureType"], EOA, ) self.assertIsNotNone(signed_order.signature) self.assertGreaterEqual( float(signed_order.order["takerAmount"]) / float(signed_order.order["makerAmount"]), 0.56, ) def test_create_market_order_sell_0_001_neg_risk(self): builder = OrderBuilder(signer) signed_order = builder.create_market_order( order_args=MarketOrderArgs( side=SELL, token_id="123", price=0.056, amount=100, fee_rate_bps=111, nonce=123, ), options=CreateOrderOptions(tick_size="0.001", neg_risk=True), ) self.assertTrue(isinstance(signed_order.order["salt"], int)) self.assertIsNotNone(signed_order) self.assertEqual( signed_order.order["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["taker"], "0x0000000000000000000000000000000000000000", ) self.assertEqual( signed_order.order["tokenId"], 123, ) self.assertEqual( signed_order.order["makerAmount"], 100000000, ) self.assertEqual( signed_order.order["takerAmount"], 5600000, ) self.assertEqual( signed_order.order["side"], 1, ) self.assertEqual( signed_order.order["expiration"], 0, ) self.assertEqual( signed_order.order["nonce"], 123, ) self.assertEqual( signed_order.order["feeRateBps"], 111, ) self.assertEqual( signed_order.order["signatureType"], EOA, ) self.assertIsNotNone(signed_order.signature) self.assertGreaterEqual( float(signed_order.order["takerAmount"]) / float(signed_order.order["makerAmount"]), 0.056, ) def test_create_market_order_sell_0_0001_neg_risk(self): builder = OrderBuilder(signer) signed_order = builder.create_market_order( order_args=MarketOrderArgs( side=SELL, token_id="123", price=0.0056, amount=100, fee_rate_bps=111, nonce=123, ), options=CreateOrderOptions(tick_size="0.0001", neg_risk=True), ) self.assertTrue(isinstance(signed_order.order["salt"], int)) self.assertIsNotNone(signed_order) self.assertEqual( signed_order.order["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", ) self.assertEqual( signed_order.order["taker"], "0x0000000000000000000000000000000000000000", ) self.assertEqual( signed_order.order["tokenId"], 123, ) self.assertEqual( signed_order.order["makerAmount"], 100000000, ) self.assertEqual( signed_order.order["takerAmount"], 560000, ) self.assertEqual( signed_order.order["side"], 1, ) self.assertEqual( signed_order.order["expiration"], 0, ) self.assertEqual( signed_order.order["nonce"], 123, ) self.assertEqual( signed_order.order["feeRateBps"], 111, ) self.assertEqual( signed_order.order["signatureType"], EOA, ) self.assertIsNotNone(signed_order.signature) self.assertGreaterEqual( float(signed_order.order["takerAmount"]) / float(signed_order.order["makerAmount"]), 0.0056, ) ================================================ FILE: tests/order_builder/test_helpers.py ================================================ from unittest import TestCase from py_clob_client.order_builder.helpers import decimal_places class TestHelpers(TestCase): def test_decimal_places(self): self.assertEqual(decimal_places(949.9970999999999), 13) self.assertEqual(decimal_places(949), 0) ================================================ FILE: tests/rfq/test_rfq_payload.py ================================================ from unittest import TestCase from py_clob_client.rfq.rfq_client import RfqClient from py_clob_client.rfq.rfq_types import MatchType from py_clob_client.order_builder.constants import BUY, SELL class TestCreateAcceptQuotePayload(TestCase): def test_complementary(self): client = RfqClient(parent=None) quote = { "matchType": "COMPLEMENTARY", "side": BUY, "token": "tokenA", "sizeIn": "100", "sizeOut": "50", "price": "0.5", } payload = client._get_request_order_creation_payload(quote) self.assertEqual(payload["token"], "tokenA") self.assertEqual(payload["side"], SELL) self.assertEqual(payload["size"], "100") self.assertEqual(payload["price"], 0.5) quote = { "matchType": "COMPLEMENTARY", "side": SELL, "token": "tokenB", "sizeIn": "200", "sizeOut": "75", "price": "0.60" } payload = client._get_request_order_creation_payload(quote) self.assertEqual(payload["token"], "tokenB") self.assertEqual(payload["side"], BUY) self.assertEqual(payload["size"], "75") self.assertEqual(payload["price"], 0.60) def test_mint_merge(self): client = RfqClient(parent=None) quote = { "matchType": "MERGE", "side": BUY, "complement": "tokenC", "sizeIn": "30", "sizeOut": "15", "price": "0.35", } payload = client._get_request_order_creation_payload(quote) self.assertEqual(payload["token"], "tokenC") self.assertEqual(payload["side"], BUY) self.assertEqual(payload["size"], "30") self.assertEqual(payload["price"], 0.65) quote = { "matchType": "MINT", "side": BUY, "complement": "tokenC", "sizeIn": "30", # tokens bought "sizeOut": "15", "price": "0.40", } payload = client._get_request_order_creation_payload(quote) self.assertEqual(payload["token"], "tokenC") self.assertEqual(payload["side"], BUY) self.assertEqual(payload["size"], "30") self.assertEqual(payload["price"], 0.60) ================================================ FILE: tests/rfq/test_rfq_query_params.py ================================================ from unittest import TestCase from urllib.parse import urlencode from py_clob_client.rfq import GetRfqRequestsParams, GetRfqQuotesParams from py_clob_client.rfq.rfq_helpers import ( parse_rfq_requests_params, parse_rfq_quotes_params, ) class TestRfqQueryParams(TestCase): def test_get_rfq_requests_request_ids_are_repeated_query_params(self): id1 = "019b69d4-2eb6-7ef9-8595-d149c97de10b" id2 = "019b69c3-d49e-7abf-88d0-cb3fd79fb721" params = GetRfqRequestsParams(request_ids=[id1, id2]) parsed = parse_rfq_requests_params(params) qs = urlencode(parsed, doseq=True) self.assertEqual(qs, f"requestIds={id1}&requestIds={id2}") def test_get_rfq_quotes_quote_ids_are_repeated_query_params(self): q1 = "019b69d4-2eb6-7ef9-8595-d149c97de10b" q2 = "019b69c3-d49e-7abf-88d0-cb3fd79fb721" params = GetRfqQuotesParams(quote_ids=[q1, q2]) parsed = parse_rfq_quotes_params(params) qs = urlencode(parsed, doseq=True) self.assertEqual(qs, f"quoteIds={q1}"eIds={q2}") ================================================ FILE: tests/signing/__init__.py ================================================ ================================================ FILE: tests/signing/test_eip712.py ================================================ from unittest import TestCase from py_clob_client.constants import AMOY from py_clob_client.signer import Signer from py_clob_client.signing.eip712 import sign_clob_auth_message # publicly known private key private_key = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" chain_id = AMOY signer = Signer(private_key=private_key, chain_id=chain_id) class TestEIP712(TestCase): def test_sign_clob_auth_message(self): signature = sign_clob_auth_message(signer, 10000000, 23) self.assertIsNotNone(signature) self.assertEqual( signature, "0xf62319a987514da40e57e2f4d7529f7bac38f0355bd88bb5adbb3768d80de6c1682518e0af677d5260366425f4361e7b70c25ae232aff0ab2331e2b164a1aedc1b", ) ================================================ FILE: tests/signing/test_hmac.py ================================================ from unittest import TestCase import binascii from py_clob_client.signing.hmac import build_hmac_signature class TestHMAC(TestCase): def setUp(self): # Baseline inputs used across variation tests self.secret = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" self.timestamp = "1000000" self.method = "test-sign" self.path = "/orders" self.string_body = '{"hash": "0x123"}' self.baseline_signature = build_hmac_signature( self.secret, self.timestamp, self.method, self.path, self.string_body ) def test_build_hmac_signature_matches_expected(self): signature = build_hmac_signature( self.secret, self.timestamp, self.method, self.path, self.string_body ) self.assertIsNotNone(signature) # Expected signature for current implementation (no method mutation, verbatim string body) self.assertEqual("ZwAdJKvoYRlEKDkNMwd5BuwNNtg93kNaR_oU2HrfVvc=", signature) def test_dict_body_same_as_equivalent_string_body(self): # Current hmac implementation converts dict to python str() then swaps single to double quotes. # For a simple dict this matches the provided JSON string exactly, so signatures should be equal. dict_body_sig = build_hmac_signature( self.secret, self.timestamp, self.method, self.path, {"hash": "0x123"} ) self.assertEqual(self.baseline_signature, dict_body_sig) def test_different_method_changes_signature(self): get_sig = build_hmac_signature( self.secret, self.timestamp, "GET", self.path, {"hash": "0x123"} ) post_sig = build_hmac_signature( self.secret, self.timestamp, "POST", self.path, {"hash": "0x123"} ) self.assertNotEqual(get_sig, post_sig) self.assertNotEqual(get_sig, self.baseline_signature) def test_different_timestamp_changes_signature(self): sig_new_time = build_hmac_signature( self.secret, "1000001", self.method, self.path, {"hash": "0x123"} ) self.assertNotEqual(sig_new_time, self.baseline_signature) def test_different_path_changes_signature(self): sig_path = build_hmac_signature( self.secret, self.timestamp, self.method, "/api/v1/orders", {"hash": "0x123"}, ) self.assertNotEqual(sig_path, self.baseline_signature) def test_extra_key_and_ordering_affect_signature(self): sig_order1 = build_hmac_signature( self.secret, self.timestamp, self.method, self.path, {"hash": "0x123", "foo": "bar"}, ) sig_order2 = build_hmac_signature( self.secret, self.timestamp, self.method, self.path, {"foo": "bar", "hash": "0x123"}, ) self.assertNotEqual(sig_order1, sig_order2) self.assertNotEqual(sig_order1, self.baseline_signature) def test_array_body_signature(self): sig_array = build_hmac_signature( self.secret, self.timestamp, self.method, self.path, [1, 2, 3] ) self.assertIsNotNone(sig_array) self.assertNotEqual(sig_array, self.baseline_signature) def test_unicode_body_signature(self): sig_unicode = build_hmac_signature( self.secret, self.timestamp, self.method, self.path, {"emoji": "😃"} ) self.assertIsNotNone(sig_unicode) self.assertNotEqual(sig_unicode, self.baseline_signature) def test_none_body_omitted_from_message(self): sig_none = build_hmac_signature( self.secret, self.timestamp, self.method, self.path, None ) self.assertNotEqual(sig_none, self.baseline_signature) def test_empty_string_body_omitted(self): sig_empty = build_hmac_signature( self.secret, self.timestamp, self.method, self.path, "" ) self.assertNotEqual(sig_empty, self.baseline_signature) def test_none_and_empty_body_same_signature(self): sig_none = build_hmac_signature( self.secret, self.timestamp, self.method, self.path, None ) sig_empty = build_hmac_signature( self.secret, self.timestamp, self.method, self.path, "" ) self.assertEqual(sig_none, sig_empty) def test_idempotent_same_inputs(self): sig1 = build_hmac_signature( self.secret, self.timestamp, self.method, self.path, {"hash": "0x123"} ) sig2 = build_hmac_signature( self.secret, self.timestamp, self.method, self.path, {"hash": "0x123"} ) self.assertEqual(sig1, sig2) def test_different_secret_changes_signature(self): other_secret = "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=" sig_other = build_hmac_signature( other_secret, self.timestamp, self.method, self.path, {"hash": "0x123"} ) sig_original = build_hmac_signature( self.secret, self.timestamp, self.method, self.path, {"hash": "0x123"} ) self.assertNotEqual(sig_other, sig_original) def test_invalid_secret_raises(self): with self.assertRaises(binascii.Error): build_hmac_signature( "!!!notbase64!!!", self.timestamp, self.method, self.path, {"hash": "0x123"}, ) def test_boolean_body_signature(self): sig_true = build_hmac_signature( self.secret, self.timestamp, self.method, self.path, True ) sig_false = build_hmac_signature( self.secret, self.timestamp, self.method, self.path, False ) self.assertIsNotNone(sig_true) self.assertIsNotNone(sig_false) self.assertNotEqual(sig_true, sig_false) def test_numeric_body_signature(self): sig_int = build_hmac_signature( self.secret, self.timestamp, self.method, self.path, 42 ) sig_float = build_hmac_signature( self.secret, self.timestamp, self.method, self.path, 3.14159 ) self.assertIsNotNone(sig_int) self.assertIsNotNone(sig_float) self.assertNotEqual(sig_int, sig_float) def test_nested_object_no_sorting_means_signatures_can_differ(self): body_a = {"a": {"z": 1, "b": 2}, "c": [3, 2, 1]} body_b = {"c": [3, 2, 1], "a": {"b": 2, "z": 1}} sig_a = build_hmac_signature( self.secret, self.timestamp, self.method, self.path, body_a ) sig_b = build_hmac_signature( self.secret, self.timestamp, self.method, self.path, body_b ) self.assertNotEqual(sig_a, sig_b) def test_list_of_dicts_key_order_affects_signature(self): body1 = [{"b": 2, "a": 1}, {"d": 4, "c": 3}] body2 = [{"a": 1, "b": 2}, {"c": 3, "d": 4}] sig1 = build_hmac_signature( self.secret, self.timestamp, self.method, self.path, body1 ) sig2 = build_hmac_signature( self.secret, self.timestamp, self.method, self.path, body2 ) self.assertNotEqual(sig1, sig2) def test_string_body_preserved_verbatim(self): string_a = '{"x":1, "y":2}' string_b = '{"x":1,"y":2}' sig_a = build_hmac_signature( self.secret, self.timestamp, self.method, self.path, string_a ) sig_b = build_hmac_signature( self.secret, self.timestamp, self.method, self.path, string_b ) self.assertNotEqual(sig_a, sig_b) ================================================ FILE: tests/test_utilities.py ================================================ from unittest import TestCase from py_clob_client.clob_types import ( OrderArgs, OrderType, CreateOrderOptions, ) from py_clob_client.constants import AMOY from py_clob_client.order_builder.constants import BUY, SELL from py_clob_client.signer import Signer from py_clob_client.order_builder.builder import OrderBuilder from py_clob_client.utilities import ( parse_raw_orderbook_summary, generate_orderbook_summary_hash, order_to_json, is_tick_size_smaller, price_valid, ) class TestUtilities(TestCase): def test_parse_raw_orderbook_summary(self): raw_obs = { "market": "0xbd31dc8a20211944f6b70f31557f1001557b59905b7738480ca09bd4532f84af", "asset_id": "52114319501245915516055106046884209969926127482827954674443846427813813222426", "bids": [ {"price": "0.15", "size": "100"}, {"price": "0.31", "size": "148.56"}, {"price": "0.33", "size": "58"}, {"price": "0.5", "size": "100"}, ], "asks": [], "hash": "9d6d9e8831a150ac4cd878f99f7b2c6d419b875f", "min_order_size": "100", "neg_risk": False, "tick_size": "0.01", "timestamp": "123456789", "last_trade_price": "", } orderbook_summary = parse_raw_orderbook_summary(raw_obs) self.assertEqual( orderbook_summary.market, "0xbd31dc8a20211944f6b70f31557f1001557b59905b7738480ca09bd4532f84af", ) self.assertEqual( orderbook_summary.asset_id, "52114319501245915516055106046884209969926127482827954674443846427813813222426", ) self.assertEqual( orderbook_summary.hash, "9d6d9e8831a150ac4cd878f99f7b2c6d419b875f" ) self.assertEqual(orderbook_summary.timestamp, "123456789") self.assertEqual(orderbook_summary.min_order_size, "100") self.assertEqual(orderbook_summary.neg_risk, False) self.assertEqual(orderbook_summary.tick_size, "0.01") self.assertIsNotNone(orderbook_summary.asks) self.assertIsNotNone(orderbook_summary.bids) self.assertEqual(len(orderbook_summary.asks), 0) self.assertEqual(len(orderbook_summary.bids), 4) self.assertEqual(orderbook_summary.bids[0].price, "0.15") self.assertEqual(orderbook_summary.bids[0].size, "100") self.assertEqual(orderbook_summary.bids[1].price, "0.31") self.assertEqual(orderbook_summary.bids[1].size, "148.56") self.assertEqual(orderbook_summary.bids[2].price, "0.33") self.assertEqual(orderbook_summary.bids[2].size, "58") self.assertEqual(orderbook_summary.bids[3].price, "0.5") self.assertEqual(orderbook_summary.bids[3].size, "100") raw_obs = { "market": "0xaabbcc", "asset_id": "100", "bids": [], "asks": [], "hash": "7f81a35a09e1933a96b05edb51ac4be4a6163146", "timestamp": "123456789", "min_order_size": "100", "neg_risk": False, "tick_size": "0.01", "last_trade_price": "", } orderbook_summary = parse_raw_orderbook_summary(raw_obs) self.assertEqual( orderbook_summary.market, "0xaabbcc", ) self.assertEqual( orderbook_summary.asset_id, "100", ) self.assertEqual(orderbook_summary.min_order_size, "100") self.assertEqual(orderbook_summary.neg_risk, False) self.assertEqual(orderbook_summary.tick_size, "0.01") self.assertEqual( orderbook_summary.hash, "7f81a35a09e1933a96b05edb51ac4be4a6163146" ) self.assertEqual(orderbook_summary.timestamp, "123456789") self.assertIsNotNone(orderbook_summary.asks) self.assertIsNotNone(orderbook_summary.bids) self.assertEqual(len(orderbook_summary.asks), 0) self.assertEqual(len(orderbook_summary.bids), 0) def test_generate_orderbook_summary_hash(self): raw_obs = { "market": "0xaabbcc", "asset_id": "100", "bids": [ {"price": "0.3", "size": "100"}, {"price": "0.4", "size": "100"}, ], "asks": [ {"price": "0.6", "size": "100"}, {"price": "0.7", "size": "100"}, ], "hash": "", "timestamp": "123456789", "min_order_size": "100", "neg_risk": False, "tick_size": "0.01", "last_trade_price": "0.5", } orderbook_summary = parse_raw_orderbook_summary(raw_obs) self.assertEqual( generate_orderbook_summary_hash(orderbook_summary), "0458ea5755c9f73d64a14636fa5c36ed460ec394", ) self.assertEqual( orderbook_summary.hash, "0458ea5755c9f73d64a14636fa5c36ed460ec394", ) raw_obs = { "market": "0xaabbcc", "asset_id": "100", "timestamp": "123456789", "bids": [ {"price": "0.3", "size": "100"}, {"price": "0.4", "size": "100"}, ], "asks": [ {"price": "0.6", "size": "100"}, {"price": "0.7", "size": "100"}, ], "min_order_size": "100", "neg_risk": False, "tick_size": "0.01", "last_trade_price": "0.5", "hash": "", } orderbook_summary = parse_raw_orderbook_summary(raw_obs) self.assertEqual( generate_orderbook_summary_hash(orderbook_summary), "0458ea5755c9f73d64a14636fa5c36ed460ec394", ) self.assertEqual( orderbook_summary.hash, "0458ea5755c9f73d64a14636fa5c36ed460ec394", ) raw_obs = { "market": "0xaabbcc", "asset_id": "100", "timestamp": "", "bids": [], "asks": [], "hash": "", "min_order_size": "100", "neg_risk": False, "tick_size": "0.01", "last_trade_price": "0.5", } orderbook_summary = parse_raw_orderbook_summary(raw_obs) self.assertEqual( generate_orderbook_summary_hash(orderbook_summary), "74c6a7c81c1d572f1c877b7d3e25b80c336d8a6e", ) self.assertEqual( orderbook_summary.hash, "74c6a7c81c1d572f1c877b7d3e25b80c336d8a6e", ) def test_order_to_json_0_1(self): # publicly known private key private_key = ( "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" ) chain_id = AMOY signer = Signer(private_key=private_key, chain_id=chain_id) owner = "aaa-bbb-ccc" builder = OrderBuilder(signer) # GTC BUY json_order = order_to_json( order=builder.create_order( order_args=OrderArgs( token_id="100", price=0.5, size=100, side=BUY, ), options=CreateOrderOptions(tick_size="0.1", neg_risk=False), ), owner=owner, orderType=OrderType.GTC, ) self.assertIsNotNone(json_order) self.assertEqual(json_order["orderType"], "GTC") self.assertEqual(json_order["owner"], owner) self.assertIsNotNone(json_order["order"]) self.assertIsNotNone(json_order["order"]["salt"]) self.assertEqual( json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["taker"], "0x0000000000000000000000000000000000000000" ) self.assertEqual(json_order["order"]["tokenId"], "100") self.assertEqual(json_order["order"]["makerAmount"], "50000000") self.assertEqual(json_order["order"]["takerAmount"], "100000000") self.assertEqual(json_order["order"]["expiration"], "0") self.assertEqual(json_order["order"]["nonce"], "0") self.assertEqual(json_order["order"]["feeRateBps"], "0") self.assertEqual(json_order["order"]["side"], "BUY") self.assertEqual(json_order["order"]["signatureType"], 0) self.assertIsNotNone(json_order["order"]["signature"]) # GTC SELL json_order = order_to_json( order=builder.create_order( order_args=OrderArgs( token_id="100", price=0.5, size=100, side=SELL, ), options=CreateOrderOptions(tick_size="0.1", neg_risk=False), ), owner=owner, orderType=OrderType.GTC, ) self.assertIsNotNone(json_order) self.assertEqual(json_order["orderType"], "GTC") self.assertEqual(json_order["owner"], owner) self.assertIsNotNone(json_order["order"]) self.assertIsNotNone(json_order["order"]["salt"]) self.assertEqual( json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["taker"], "0x0000000000000000000000000000000000000000" ) self.assertEqual(json_order["order"]["tokenId"], "100") self.assertEqual(json_order["order"]["makerAmount"], "100000000") self.assertEqual(json_order["order"]["takerAmount"], "50000000") self.assertEqual(json_order["order"]["expiration"], "0") self.assertEqual(json_order["order"]["nonce"], "0") self.assertEqual(json_order["order"]["feeRateBps"], "0") self.assertEqual(json_order["order"]["side"], "SELL") self.assertEqual(json_order["order"]["signatureType"], 0) self.assertIsNotNone(json_order["order"]["signature"]) # GTD BUY json_order = order_to_json( order=builder.create_order( order_args=OrderArgs( token_id="100", price=0.5, size=100, side=BUY, ), options=CreateOrderOptions(tick_size="0.1", neg_risk=False), ), owner=owner, orderType=OrderType.GTD, post_only=True, ) self.assertIsNotNone(json_order) self.assertEqual(json_order["postOnly"], True) self.assertEqual(json_order["orderType"], "GTD") self.assertEqual(json_order["owner"], owner) self.assertIsNotNone(json_order["order"]) self.assertIsNotNone(json_order["order"]["salt"]) self.assertEqual( json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["taker"], "0x0000000000000000000000000000000000000000" ) self.assertEqual(json_order["order"]["tokenId"], "100") self.assertEqual(json_order["order"]["makerAmount"], "50000000") self.assertEqual(json_order["order"]["takerAmount"], "100000000") self.assertEqual(json_order["order"]["expiration"], "0") self.assertEqual(json_order["order"]["nonce"], "0") self.assertEqual(json_order["order"]["feeRateBps"], "0") self.assertEqual(json_order["order"]["side"], "BUY") self.assertEqual(json_order["order"]["signatureType"], 0) self.assertIsNotNone(json_order["order"]["signature"]) # GTD SELL json_order = order_to_json( order=builder.create_order( order_args=OrderArgs( token_id="100", price=0.5, size=100, side=SELL, ), options=CreateOrderOptions(tick_size="0.1", neg_risk=False), ), owner=owner, orderType=OrderType.GTD, ) self.assertIsNotNone(json_order) self.assertEqual(json_order["orderType"], "GTD") self.assertEqual(json_order["owner"], owner) self.assertIsNotNone(json_order["order"]) self.assertIsNotNone(json_order["order"]["salt"]) self.assertEqual( json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["taker"], "0x0000000000000000000000000000000000000000" ) self.assertEqual(json_order["order"]["tokenId"], "100") self.assertEqual(json_order["order"]["makerAmount"], "100000000") self.assertEqual(json_order["order"]["takerAmount"], "50000000") self.assertEqual(json_order["order"]["expiration"], "0") self.assertEqual(json_order["order"]["nonce"], "0") self.assertEqual(json_order["order"]["feeRateBps"], "0") self.assertEqual(json_order["order"]["side"], "SELL") self.assertEqual(json_order["order"]["signatureType"], 0) self.assertIsNotNone(json_order["order"]["signature"]) def test_order_to_json_0_01(self): # publicly known private key private_key = ( "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" ) chain_id = AMOY signer = Signer(private_key=private_key, chain_id=chain_id) owner = "aaa-bbb-ccc" builder = OrderBuilder(signer) # GTC BUY json_order = order_to_json( order=builder.create_order( order_args=OrderArgs( token_id="100", price=0.05, size=100, side=BUY, ), options=CreateOrderOptions(tick_size="0.01", neg_risk=False), ), owner=owner, orderType=OrderType.GTC, ) self.assertIsNotNone(json_order) self.assertEqual(json_order["orderType"], "GTC") self.assertEqual(json_order["owner"], owner) self.assertIsNotNone(json_order["order"]) self.assertIsNotNone(json_order["order"]["salt"]) self.assertEqual( json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["taker"], "0x0000000000000000000000000000000000000000" ) self.assertEqual(json_order["order"]["tokenId"], "100") self.assertEqual(json_order["order"]["makerAmount"], "5000000") self.assertEqual(json_order["order"]["takerAmount"], "100000000") self.assertEqual(json_order["order"]["expiration"], "0") self.assertEqual(json_order["order"]["nonce"], "0") self.assertEqual(json_order["order"]["feeRateBps"], "0") self.assertEqual(json_order["order"]["side"], "BUY") self.assertEqual(json_order["order"]["signatureType"], 0) self.assertIsNotNone(json_order["order"]["signature"]) # GTC SELL json_order = order_to_json( order=builder.create_order( order_args=OrderArgs( token_id="100", price=0.05, size=100, side=SELL, ), options=CreateOrderOptions(tick_size="0.01", neg_risk=False), ), owner=owner, orderType=OrderType.GTC, ) self.assertIsNotNone(json_order) self.assertEqual(json_order["orderType"], "GTC") self.assertEqual(json_order["owner"], owner) self.assertIsNotNone(json_order["order"]) self.assertIsNotNone(json_order["order"]["salt"]) self.assertEqual( json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["taker"], "0x0000000000000000000000000000000000000000" ) self.assertEqual(json_order["order"]["tokenId"], "100") self.assertEqual(json_order["order"]["makerAmount"], "100000000") self.assertEqual(json_order["order"]["takerAmount"], "5000000") self.assertEqual(json_order["order"]["expiration"], "0") self.assertEqual(json_order["order"]["nonce"], "0") self.assertEqual(json_order["order"]["feeRateBps"], "0") self.assertEqual(json_order["order"]["side"], "SELL") self.assertEqual(json_order["order"]["signatureType"], 0) self.assertIsNotNone(json_order["order"]["signature"]) # GTD BUY json_order = order_to_json( order=builder.create_order( order_args=OrderArgs( token_id="100", price=0.05, size=100, side=BUY, ), options=CreateOrderOptions(tick_size="0.01", neg_risk=False), ), owner=owner, orderType=OrderType.GTD, ) self.assertIsNotNone(json_order) self.assertEqual(json_order["orderType"], "GTD") self.assertEqual(json_order["owner"], owner) self.assertIsNotNone(json_order["order"]) self.assertIsNotNone(json_order["order"]["salt"]) self.assertEqual( json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["taker"], "0x0000000000000000000000000000000000000000" ) self.assertEqual(json_order["order"]["tokenId"], "100") self.assertEqual(json_order["order"]["makerAmount"], "5000000") self.assertEqual(json_order["order"]["takerAmount"], "100000000") self.assertEqual(json_order["order"]["expiration"], "0") self.assertEqual(json_order["order"]["nonce"], "0") self.assertEqual(json_order["order"]["feeRateBps"], "0") self.assertEqual(json_order["order"]["side"], "BUY") self.assertEqual(json_order["order"]["signatureType"], 0) self.assertIsNotNone(json_order["order"]["signature"]) # GTD SELL json_order = order_to_json( order=builder.create_order( order_args=OrderArgs( token_id="100", price=0.05, size=100, side=SELL, ), options=CreateOrderOptions(tick_size="0.01", neg_risk=False), ), owner=owner, orderType=OrderType.GTD, ) self.assertIsNotNone(json_order) self.assertEqual(json_order["orderType"], "GTD") self.assertEqual(json_order["owner"], owner) self.assertIsNotNone(json_order["order"]) self.assertIsNotNone(json_order["order"]["salt"]) self.assertEqual( json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["taker"], "0x0000000000000000000000000000000000000000" ) self.assertEqual(json_order["order"]["tokenId"], "100") self.assertEqual(json_order["order"]["makerAmount"], "100000000") self.assertEqual(json_order["order"]["takerAmount"], "5000000") self.assertEqual(json_order["order"]["expiration"], "0") self.assertEqual(json_order["order"]["nonce"], "0") self.assertEqual(json_order["order"]["feeRateBps"], "0") self.assertEqual(json_order["order"]["side"], "SELL") self.assertEqual(json_order["order"]["signatureType"], 0) self.assertIsNotNone(json_order["order"]["signature"]) def test_order_to_json_0_001(self): # publicly known private key private_key = ( "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" ) chain_id = AMOY signer = Signer(private_key=private_key, chain_id=chain_id) owner = "aaa-bbb-ccc" builder = OrderBuilder(signer) # GTC BUY json_order = order_to_json( order=builder.create_order( order_args=OrderArgs( token_id="100", price=0.005, size=100, side=BUY, ), options=CreateOrderOptions(tick_size="0.001", neg_risk=False), ), owner=owner, orderType=OrderType.GTC, ) self.assertIsNotNone(json_order) self.assertEqual(json_order["orderType"], "GTC") self.assertEqual(json_order["owner"], owner) self.assertIsNotNone(json_order["order"]) self.assertIsNotNone(json_order["order"]["salt"]) self.assertEqual( json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["taker"], "0x0000000000000000000000000000000000000000" ) self.assertEqual(json_order["order"]["tokenId"], "100") self.assertEqual(json_order["order"]["makerAmount"], "500000") self.assertEqual(json_order["order"]["takerAmount"], "100000000") self.assertEqual(json_order["order"]["expiration"], "0") self.assertEqual(json_order["order"]["nonce"], "0") self.assertEqual(json_order["order"]["feeRateBps"], "0") self.assertEqual(json_order["order"]["side"], "BUY") self.assertEqual(json_order["order"]["signatureType"], 0) self.assertIsNotNone(json_order["order"]["signature"]) # GTC SELL json_order = order_to_json( order=builder.create_order( order_args=OrderArgs( token_id="100", price=0.005, size=100, side=SELL, ), options=CreateOrderOptions(tick_size="0.001", neg_risk=False), ), owner=owner, orderType=OrderType.GTC, ) self.assertIsNotNone(json_order) self.assertEqual(json_order["orderType"], "GTC") self.assertEqual(json_order["owner"], owner) self.assertIsNotNone(json_order["order"]) self.assertIsNotNone(json_order["order"]["salt"]) self.assertEqual( json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["taker"], "0x0000000000000000000000000000000000000000" ) self.assertEqual(json_order["order"]["tokenId"], "100") self.assertEqual(json_order["order"]["makerAmount"], "100000000") self.assertEqual(json_order["order"]["takerAmount"], "500000") self.assertEqual(json_order["order"]["expiration"], "0") self.assertEqual(json_order["order"]["nonce"], "0") self.assertEqual(json_order["order"]["feeRateBps"], "0") self.assertEqual(json_order["order"]["side"], "SELL") self.assertEqual(json_order["order"]["signatureType"], 0) self.assertIsNotNone(json_order["order"]["signature"]) # GTD BUY json_order = order_to_json( order=builder.create_order( order_args=OrderArgs( token_id="100", price=0.005, size=100, side=BUY, ), options=CreateOrderOptions(tick_size="0.001", neg_risk=False), ), owner=owner, orderType=OrderType.GTD, ) self.assertIsNotNone(json_order) self.assertEqual(json_order["orderType"], "GTD") self.assertEqual(json_order["owner"], owner) self.assertIsNotNone(json_order["order"]) self.assertIsNotNone(json_order["order"]["salt"]) self.assertEqual( json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["taker"], "0x0000000000000000000000000000000000000000" ) self.assertEqual(json_order["order"]["tokenId"], "100") self.assertEqual(json_order["order"]["makerAmount"], "500000") self.assertEqual(json_order["order"]["takerAmount"], "100000000") self.assertEqual(json_order["order"]["expiration"], "0") self.assertEqual(json_order["order"]["nonce"], "0") self.assertEqual(json_order["order"]["feeRateBps"], "0") self.assertEqual(json_order["order"]["side"], "BUY") self.assertEqual(json_order["order"]["signatureType"], 0) self.assertIsNotNone(json_order["order"]["signature"]) # GTD SELL json_order = order_to_json( order=builder.create_order( order_args=OrderArgs( token_id="100", price=0.005, size=100, side=SELL, ), options=CreateOrderOptions(tick_size="0.001", neg_risk=False), ), owner=owner, orderType=OrderType.GTD, ) self.assertIsNotNone(json_order) self.assertEqual(json_order["orderType"], "GTD") self.assertEqual(json_order["owner"], owner) self.assertIsNotNone(json_order["order"]) self.assertIsNotNone(json_order["order"]["salt"]) self.assertEqual( json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["taker"], "0x0000000000000000000000000000000000000000" ) self.assertEqual(json_order["order"]["tokenId"], "100") self.assertEqual(json_order["order"]["makerAmount"], "100000000") self.assertEqual(json_order["order"]["takerAmount"], "500000") self.assertEqual(json_order["order"]["expiration"], "0") self.assertEqual(json_order["order"]["nonce"], "0") self.assertEqual(json_order["order"]["feeRateBps"], "0") self.assertEqual(json_order["order"]["side"], "SELL") self.assertEqual(json_order["order"]["signatureType"], 0) self.assertIsNotNone(json_order["order"]["signature"]) def test_order_to_json_0_0001(self): # publicly known private key private_key = ( "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" ) chain_id = AMOY signer = Signer(private_key=private_key, chain_id=chain_id) owner = "aaa-bbb-ccc" builder = OrderBuilder(signer) # GTC BUY json_order = order_to_json( order=builder.create_order( order_args=OrderArgs( token_id="100", price=0.0005, size=100, side=BUY, ), options=CreateOrderOptions(tick_size="0.0001", neg_risk=False), ), owner=owner, orderType=OrderType.GTC, ) self.assertIsNotNone(json_order) self.assertEqual(json_order["orderType"], "GTC") self.assertEqual(json_order["owner"], owner) self.assertIsNotNone(json_order["order"]) self.assertIsNotNone(json_order["order"]["salt"]) self.assertEqual( json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["taker"], "0x0000000000000000000000000000000000000000" ) self.assertEqual(json_order["order"]["tokenId"], "100") self.assertEqual(json_order["order"]["makerAmount"], "50000") self.assertEqual(json_order["order"]["takerAmount"], "100000000") self.assertEqual(json_order["order"]["expiration"], "0") self.assertEqual(json_order["order"]["nonce"], "0") self.assertEqual(json_order["order"]["feeRateBps"], "0") self.assertEqual(json_order["order"]["side"], "BUY") self.assertEqual(json_order["order"]["signatureType"], 0) self.assertIsNotNone(json_order["order"]["signature"]) # GTC SELL json_order = order_to_json( order=builder.create_order( order_args=OrderArgs( token_id="100", price=0.0005, size=100, side=SELL, ), options=CreateOrderOptions(tick_size="0.0001", neg_risk=False), ), owner=owner, orderType=OrderType.GTC, ) self.assertIsNotNone(json_order) self.assertEqual(json_order["orderType"], "GTC") self.assertEqual(json_order["owner"], owner) self.assertIsNotNone(json_order["order"]) self.assertIsNotNone(json_order["order"]["salt"]) self.assertEqual( json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["taker"], "0x0000000000000000000000000000000000000000" ) self.assertEqual(json_order["order"]["tokenId"], "100") self.assertEqual(json_order["order"]["makerAmount"], "100000000") self.assertEqual(json_order["order"]["takerAmount"], "50000") self.assertEqual(json_order["order"]["expiration"], "0") self.assertEqual(json_order["order"]["nonce"], "0") self.assertEqual(json_order["order"]["feeRateBps"], "0") self.assertEqual(json_order["order"]["side"], "SELL") self.assertEqual(json_order["order"]["signatureType"], 0) self.assertIsNotNone(json_order["order"]["signature"]) # GTD BUY json_order = order_to_json( order=builder.create_order( order_args=OrderArgs( token_id="100", price=0.0005, size=100, side=BUY, ), options=CreateOrderOptions(tick_size="0.0001", neg_risk=False), ), owner=owner, orderType=OrderType.GTD, ) self.assertIsNotNone(json_order) self.assertEqual(json_order["orderType"], "GTD") self.assertEqual(json_order["owner"], owner) self.assertIsNotNone(json_order["order"]) self.assertIsNotNone(json_order["order"]["salt"]) self.assertEqual( json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["taker"], "0x0000000000000000000000000000000000000000" ) self.assertEqual(json_order["order"]["tokenId"], "100") self.assertEqual(json_order["order"]["makerAmount"], "50000") self.assertEqual(json_order["order"]["takerAmount"], "100000000") self.assertEqual(json_order["order"]["expiration"], "0") self.assertEqual(json_order["order"]["nonce"], "0") self.assertEqual(json_order["order"]["feeRateBps"], "0") self.assertEqual(json_order["order"]["side"], "BUY") self.assertEqual(json_order["order"]["signatureType"], 0) self.assertIsNotNone(json_order["order"]["signature"]) # GTD SELL json_order = order_to_json( order=builder.create_order( order_args=OrderArgs( token_id="100", price=0.0005, size=100, side=SELL, ), options=CreateOrderOptions(tick_size="0.0001", neg_risk=False), ), owner=owner, orderType=OrderType.GTD, ) self.assertIsNotNone(json_order) self.assertEqual(json_order["orderType"], "GTD") self.assertEqual(json_order["owner"], owner) self.assertIsNotNone(json_order["order"]) self.assertIsNotNone(json_order["order"]["salt"]) self.assertEqual( json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["taker"], "0x0000000000000000000000000000000000000000" ) self.assertEqual(json_order["order"]["tokenId"], "100") self.assertEqual(json_order["order"]["makerAmount"], "100000000") self.assertEqual(json_order["order"]["takerAmount"], "50000") self.assertEqual(json_order["order"]["expiration"], "0") self.assertEqual(json_order["order"]["nonce"], "0") self.assertEqual(json_order["order"]["feeRateBps"], "0") self.assertEqual(json_order["order"]["side"], "SELL") self.assertEqual(json_order["order"]["signatureType"], 0) self.assertIsNotNone(json_order["order"]["signature"]) def test_order_to_json_0_1_neg_risk(self): # publicly known private key private_key = ( "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" ) chain_id = AMOY signer = Signer(private_key=private_key, chain_id=chain_id) owner = "aaa-bbb-ccc" builder = OrderBuilder(signer) # GTC BUY json_order = order_to_json( order=builder.create_order( order_args=OrderArgs( token_id="100", price=0.5, size=100, side=BUY, ), options=CreateOrderOptions(tick_size="0.1", neg_risk=True), ), owner=owner, orderType=OrderType.GTC, ) self.assertIsNotNone(json_order) self.assertEqual(json_order["orderType"], "GTC") self.assertEqual(json_order["owner"], owner) self.assertIsNotNone(json_order["order"]) self.assertIsNotNone(json_order["order"]["salt"]) self.assertEqual( json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["taker"], "0x0000000000000000000000000000000000000000" ) self.assertEqual(json_order["order"]["tokenId"], "100") self.assertEqual(json_order["order"]["makerAmount"], "50000000") self.assertEqual(json_order["order"]["takerAmount"], "100000000") self.assertEqual(json_order["order"]["expiration"], "0") self.assertEqual(json_order["order"]["nonce"], "0") self.assertEqual(json_order["order"]["feeRateBps"], "0") self.assertEqual(json_order["order"]["side"], "BUY") self.assertEqual(json_order["order"]["signatureType"], 0) self.assertIsNotNone(json_order["order"]["signature"]) # GTC SELL json_order = order_to_json( order=builder.create_order( order_args=OrderArgs( token_id="100", price=0.5, size=100, side=SELL, ), options=CreateOrderOptions(tick_size="0.1", neg_risk=True), ), owner=owner, orderType=OrderType.GTC, ) self.assertIsNotNone(json_order) self.assertEqual(json_order["orderType"], "GTC") self.assertEqual(json_order["owner"], owner) self.assertIsNotNone(json_order["order"]) self.assertIsNotNone(json_order["order"]["salt"]) self.assertEqual( json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["taker"], "0x0000000000000000000000000000000000000000" ) self.assertEqual(json_order["order"]["tokenId"], "100") self.assertEqual(json_order["order"]["makerAmount"], "100000000") self.assertEqual(json_order["order"]["takerAmount"], "50000000") self.assertEqual(json_order["order"]["expiration"], "0") self.assertEqual(json_order["order"]["nonce"], "0") self.assertEqual(json_order["order"]["feeRateBps"], "0") self.assertEqual(json_order["order"]["side"], "SELL") self.assertEqual(json_order["order"]["signatureType"], 0) self.assertIsNotNone(json_order["order"]["signature"]) # GTD BUY json_order = order_to_json( order=builder.create_order( order_args=OrderArgs( token_id="100", price=0.5, size=100, side=BUY, ), options=CreateOrderOptions(tick_size="0.1", neg_risk=True), ), owner=owner, orderType=OrderType.GTD, ) self.assertIsNotNone(json_order) self.assertEqual(json_order["orderType"], "GTD") self.assertEqual(json_order["owner"], owner) self.assertIsNotNone(json_order["order"]) self.assertIsNotNone(json_order["order"]["salt"]) self.assertEqual( json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["taker"], "0x0000000000000000000000000000000000000000" ) self.assertEqual(json_order["order"]["tokenId"], "100") self.assertEqual(json_order["order"]["makerAmount"], "50000000") self.assertEqual(json_order["order"]["takerAmount"], "100000000") self.assertEqual(json_order["order"]["expiration"], "0") self.assertEqual(json_order["order"]["nonce"], "0") self.assertEqual(json_order["order"]["feeRateBps"], "0") self.assertEqual(json_order["order"]["side"], "BUY") self.assertEqual(json_order["order"]["signatureType"], 0) self.assertIsNotNone(json_order["order"]["signature"]) # GTD SELL json_order = order_to_json( order=builder.create_order( order_args=OrderArgs( token_id="100", price=0.5, size=100, side=SELL, ), options=CreateOrderOptions(tick_size="0.1", neg_risk=True), ), owner=owner, orderType=OrderType.GTD, ) self.assertIsNotNone(json_order) self.assertEqual(json_order["orderType"], "GTD") self.assertEqual(json_order["owner"], owner) self.assertIsNotNone(json_order["order"]) self.assertIsNotNone(json_order["order"]["salt"]) self.assertEqual( json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["taker"], "0x0000000000000000000000000000000000000000" ) self.assertEqual(json_order["order"]["tokenId"], "100") self.assertEqual(json_order["order"]["makerAmount"], "100000000") self.assertEqual(json_order["order"]["takerAmount"], "50000000") self.assertEqual(json_order["order"]["expiration"], "0") self.assertEqual(json_order["order"]["nonce"], "0") self.assertEqual(json_order["order"]["feeRateBps"], "0") self.assertEqual(json_order["order"]["side"], "SELL") self.assertEqual(json_order["order"]["signatureType"], 0) self.assertIsNotNone(json_order["order"]["signature"]) def test_order_to_json_0_01_neg_risk(self): # publicly known private key private_key = ( "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" ) chain_id = AMOY signer = Signer(private_key=private_key, chain_id=chain_id) owner = "aaa-bbb-ccc" builder = OrderBuilder(signer) # GTC BUY json_order = order_to_json( order=builder.create_order( order_args=OrderArgs( token_id="100", price=0.05, size=100, side=BUY, ), options=CreateOrderOptions(tick_size="0.01", neg_risk=True), ), owner=owner, orderType=OrderType.GTC, ) self.assertIsNotNone(json_order) self.assertEqual(json_order["orderType"], "GTC") self.assertEqual(json_order["owner"], owner) self.assertIsNotNone(json_order["order"]) self.assertIsNotNone(json_order["order"]["salt"]) self.assertEqual( json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["taker"], "0x0000000000000000000000000000000000000000" ) self.assertEqual(json_order["order"]["tokenId"], "100") self.assertEqual(json_order["order"]["makerAmount"], "5000000") self.assertEqual(json_order["order"]["takerAmount"], "100000000") self.assertEqual(json_order["order"]["expiration"], "0") self.assertEqual(json_order["order"]["nonce"], "0") self.assertEqual(json_order["order"]["feeRateBps"], "0") self.assertEqual(json_order["order"]["side"], "BUY") self.assertEqual(json_order["order"]["signatureType"], 0) self.assertIsNotNone(json_order["order"]["signature"]) # GTC SELL json_order = order_to_json( order=builder.create_order( order_args=OrderArgs( token_id="100", price=0.05, size=100, side=SELL, ), options=CreateOrderOptions(tick_size="0.01", neg_risk=True), ), owner=owner, orderType=OrderType.GTC, ) self.assertIsNotNone(json_order) self.assertEqual(json_order["orderType"], "GTC") self.assertEqual(json_order["owner"], owner) self.assertIsNotNone(json_order["order"]) self.assertIsNotNone(json_order["order"]["salt"]) self.assertEqual( json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["taker"], "0x0000000000000000000000000000000000000000" ) self.assertEqual(json_order["order"]["tokenId"], "100") self.assertEqual(json_order["order"]["makerAmount"], "100000000") self.assertEqual(json_order["order"]["takerAmount"], "5000000") self.assertEqual(json_order["order"]["expiration"], "0") self.assertEqual(json_order["order"]["nonce"], "0") self.assertEqual(json_order["order"]["feeRateBps"], "0") self.assertEqual(json_order["order"]["side"], "SELL") self.assertEqual(json_order["order"]["signatureType"], 0) self.assertIsNotNone(json_order["order"]["signature"]) # GTD BUY json_order = order_to_json( order=builder.create_order( order_args=OrderArgs( token_id="100", price=0.05, size=100, side=BUY, ), options=CreateOrderOptions(tick_size="0.01", neg_risk=True), ), owner=owner, orderType=OrderType.GTD, ) self.assertIsNotNone(json_order) self.assertEqual(json_order["orderType"], "GTD") self.assertEqual(json_order["owner"], owner) self.assertIsNotNone(json_order["order"]) self.assertIsNotNone(json_order["order"]["salt"]) self.assertEqual( json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["taker"], "0x0000000000000000000000000000000000000000" ) self.assertEqual(json_order["order"]["tokenId"], "100") self.assertEqual(json_order["order"]["makerAmount"], "5000000") self.assertEqual(json_order["order"]["takerAmount"], "100000000") self.assertEqual(json_order["order"]["expiration"], "0") self.assertEqual(json_order["order"]["nonce"], "0") self.assertEqual(json_order["order"]["feeRateBps"], "0") self.assertEqual(json_order["order"]["side"], "BUY") self.assertEqual(json_order["order"]["signatureType"], 0) self.assertIsNotNone(json_order["order"]["signature"]) # GTD SELL json_order = order_to_json( order=builder.create_order( order_args=OrderArgs( token_id="100", price=0.05, size=100, side=SELL, ), options=CreateOrderOptions(tick_size="0.01", neg_risk=True), ), owner=owner, orderType=OrderType.GTD, ) self.assertIsNotNone(json_order) self.assertEqual(json_order["orderType"], "GTD") self.assertEqual(json_order["owner"], owner) self.assertIsNotNone(json_order["order"]) self.assertIsNotNone(json_order["order"]["salt"]) self.assertEqual( json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["taker"], "0x0000000000000000000000000000000000000000" ) self.assertEqual(json_order["order"]["tokenId"], "100") self.assertEqual(json_order["order"]["makerAmount"], "100000000") self.assertEqual(json_order["order"]["takerAmount"], "5000000") self.assertEqual(json_order["order"]["expiration"], "0") self.assertEqual(json_order["order"]["nonce"], "0") self.assertEqual(json_order["order"]["feeRateBps"], "0") self.assertEqual(json_order["order"]["side"], "SELL") self.assertEqual(json_order["order"]["signatureType"], 0) self.assertIsNotNone(json_order["order"]["signature"]) def test_order_to_json_0_001_neg_risk(self): # publicly known private key private_key = ( "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" ) chain_id = AMOY signer = Signer(private_key=private_key, chain_id=chain_id) owner = "aaa-bbb-ccc" builder = OrderBuilder(signer) # GTC BUY json_order = order_to_json( order=builder.create_order( order_args=OrderArgs( token_id="100", price=0.005, size=100, side=BUY, ), options=CreateOrderOptions(tick_size="0.001", neg_risk=True), ), owner=owner, orderType=OrderType.GTC, ) self.assertIsNotNone(json_order) self.assertEqual(json_order["orderType"], "GTC") self.assertEqual(json_order["owner"], owner) self.assertIsNotNone(json_order["order"]) self.assertIsNotNone(json_order["order"]["salt"]) self.assertEqual( json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["taker"], "0x0000000000000000000000000000000000000000" ) self.assertEqual(json_order["order"]["tokenId"], "100") self.assertEqual(json_order["order"]["makerAmount"], "500000") self.assertEqual(json_order["order"]["takerAmount"], "100000000") self.assertEqual(json_order["order"]["expiration"], "0") self.assertEqual(json_order["order"]["nonce"], "0") self.assertEqual(json_order["order"]["feeRateBps"], "0") self.assertEqual(json_order["order"]["side"], "BUY") self.assertEqual(json_order["order"]["signatureType"], 0) self.assertIsNotNone(json_order["order"]["signature"]) # GTC SELL json_order = order_to_json( order=builder.create_order( order_args=OrderArgs( token_id="100", price=0.005, size=100, side=SELL, ), options=CreateOrderOptions(tick_size="0.001", neg_risk=True), ), owner=owner, orderType=OrderType.GTC, ) self.assertIsNotNone(json_order) self.assertEqual(json_order["orderType"], "GTC") self.assertEqual(json_order["owner"], owner) self.assertIsNotNone(json_order["order"]) self.assertIsNotNone(json_order["order"]["salt"]) self.assertEqual( json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["taker"], "0x0000000000000000000000000000000000000000" ) self.assertEqual(json_order["order"]["tokenId"], "100") self.assertEqual(json_order["order"]["makerAmount"], "100000000") self.assertEqual(json_order["order"]["takerAmount"], "500000") self.assertEqual(json_order["order"]["expiration"], "0") self.assertEqual(json_order["order"]["nonce"], "0") self.assertEqual(json_order["order"]["feeRateBps"], "0") self.assertEqual(json_order["order"]["side"], "SELL") self.assertEqual(json_order["order"]["signatureType"], 0) self.assertIsNotNone(json_order["order"]["signature"]) # GTD BUY json_order = order_to_json( order=builder.create_order( order_args=OrderArgs( token_id="100", price=0.005, size=100, side=BUY, ), options=CreateOrderOptions(tick_size="0.001", neg_risk=True), ), owner=owner, orderType=OrderType.GTD, ) self.assertIsNotNone(json_order) self.assertEqual(json_order["orderType"], "GTD") self.assertEqual(json_order["owner"], owner) self.assertIsNotNone(json_order["order"]) self.assertIsNotNone(json_order["order"]["salt"]) self.assertEqual( json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["taker"], "0x0000000000000000000000000000000000000000" ) self.assertEqual(json_order["order"]["tokenId"], "100") self.assertEqual(json_order["order"]["makerAmount"], "500000") self.assertEqual(json_order["order"]["takerAmount"], "100000000") self.assertEqual(json_order["order"]["expiration"], "0") self.assertEqual(json_order["order"]["nonce"], "0") self.assertEqual(json_order["order"]["feeRateBps"], "0") self.assertEqual(json_order["order"]["side"], "BUY") self.assertEqual(json_order["order"]["signatureType"], 0) self.assertIsNotNone(json_order["order"]["signature"]) # GTD SELL json_order = order_to_json( order=builder.create_order( order_args=OrderArgs( token_id="100", price=0.005, size=100, side=SELL, ), options=CreateOrderOptions(tick_size="0.001", neg_risk=True), ), owner=owner, orderType=OrderType.GTD, ) self.assertIsNotNone(json_order) self.assertEqual(json_order["orderType"], "GTD") self.assertEqual(json_order["owner"], owner) self.assertIsNotNone(json_order["order"]) self.assertIsNotNone(json_order["order"]["salt"]) self.assertEqual( json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["taker"], "0x0000000000000000000000000000000000000000" ) self.assertEqual(json_order["order"]["tokenId"], "100") self.assertEqual(json_order["order"]["makerAmount"], "100000000") self.assertEqual(json_order["order"]["takerAmount"], "500000") self.assertEqual(json_order["order"]["expiration"], "0") self.assertEqual(json_order["order"]["nonce"], "0") self.assertEqual(json_order["order"]["feeRateBps"], "0") self.assertEqual(json_order["order"]["side"], "SELL") self.assertEqual(json_order["order"]["signatureType"], 0) self.assertIsNotNone(json_order["order"]["signature"]) def test_order_to_json_0_0001_neg_risk(self): # publicly known private key private_key = ( "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" ) chain_id = AMOY signer = Signer(private_key=private_key, chain_id=chain_id) owner = "aaa-bbb-ccc" builder = OrderBuilder(signer) # GTC BUY json_order = order_to_json( order=builder.create_order( order_args=OrderArgs( token_id="100", price=0.0005, size=100, side=BUY, ), options=CreateOrderOptions(tick_size="0.0001", neg_risk=True), ), owner=owner, orderType=OrderType.GTC, ) self.assertIsNotNone(json_order) self.assertEqual(json_order["orderType"], "GTC") self.assertEqual(json_order["owner"], owner) self.assertIsNotNone(json_order["order"]) self.assertIsNotNone(json_order["order"]["salt"]) self.assertEqual( json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["taker"], "0x0000000000000000000000000000000000000000" ) self.assertEqual(json_order["order"]["tokenId"], "100") self.assertEqual(json_order["order"]["makerAmount"], "50000") self.assertEqual(json_order["order"]["takerAmount"], "100000000") self.assertEqual(json_order["order"]["expiration"], "0") self.assertEqual(json_order["order"]["nonce"], "0") self.assertEqual(json_order["order"]["feeRateBps"], "0") self.assertEqual(json_order["order"]["side"], "BUY") self.assertEqual(json_order["order"]["signatureType"], 0) self.assertIsNotNone(json_order["order"]["signature"]) # GTC SELL json_order = order_to_json( order=builder.create_order( order_args=OrderArgs( token_id="100", price=0.0005, size=100, side=SELL, ), options=CreateOrderOptions(tick_size="0.0001", neg_risk=True), ), owner=owner, orderType=OrderType.GTC, ) self.assertIsNotNone(json_order) self.assertEqual(json_order["orderType"], "GTC") self.assertEqual(json_order["owner"], owner) self.assertIsNotNone(json_order["order"]) self.assertIsNotNone(json_order["order"]["salt"]) self.assertEqual( json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["taker"], "0x0000000000000000000000000000000000000000" ) self.assertEqual(json_order["order"]["tokenId"], "100") self.assertEqual(json_order["order"]["makerAmount"], "100000000") self.assertEqual(json_order["order"]["takerAmount"], "50000") self.assertEqual(json_order["order"]["expiration"], "0") self.assertEqual(json_order["order"]["nonce"], "0") self.assertEqual(json_order["order"]["feeRateBps"], "0") self.assertEqual(json_order["order"]["side"], "SELL") self.assertEqual(json_order["order"]["signatureType"], 0) self.assertIsNotNone(json_order["order"]["signature"]) # GTD BUY json_order = order_to_json( order=builder.create_order( order_args=OrderArgs( token_id="100", price=0.0005, size=100, side=BUY, ), options=CreateOrderOptions(tick_size="0.0001", neg_risk=True), ), owner=owner, orderType=OrderType.GTD, ) self.assertIsNotNone(json_order) self.assertEqual(json_order["orderType"], "GTD") self.assertEqual(json_order["owner"], owner) self.assertIsNotNone(json_order["order"]) self.assertIsNotNone(json_order["order"]["salt"]) self.assertEqual( json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["taker"], "0x0000000000000000000000000000000000000000" ) self.assertEqual(json_order["order"]["tokenId"], "100") self.assertEqual(json_order["order"]["makerAmount"], "50000") self.assertEqual(json_order["order"]["takerAmount"], "100000000") self.assertEqual(json_order["order"]["expiration"], "0") self.assertEqual(json_order["order"]["nonce"], "0") self.assertEqual(json_order["order"]["feeRateBps"], "0") self.assertEqual(json_order["order"]["side"], "BUY") self.assertEqual(json_order["order"]["signatureType"], 0) self.assertIsNotNone(json_order["order"]["signature"]) # GTD SELL json_order = order_to_json( order=builder.create_order( order_args=OrderArgs( token_id="100", price=0.0005, size=100, side=SELL, ), options=CreateOrderOptions(tick_size="0.0001", neg_risk=True), ), owner=owner, orderType=OrderType.GTD, ) self.assertIsNotNone(json_order) self.assertEqual(json_order["orderType"], "GTD") self.assertEqual(json_order["owner"], owner) self.assertIsNotNone(json_order["order"]) self.assertIsNotNone(json_order["order"]["salt"]) self.assertEqual( json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) self.assertEqual( json_order["order"]["taker"], "0x0000000000000000000000000000000000000000" ) self.assertEqual(json_order["order"]["tokenId"], "100") self.assertEqual(json_order["order"]["makerAmount"], "100000000") self.assertEqual(json_order["order"]["takerAmount"], "50000") self.assertEqual(json_order["order"]["expiration"], "0") self.assertEqual(json_order["order"]["nonce"], "0") self.assertEqual(json_order["order"]["feeRateBps"], "0") self.assertEqual(json_order["order"]["side"], "SELL") self.assertEqual(json_order["order"]["signatureType"], 0) self.assertIsNotNone(json_order["order"]["signature"]) def test_is_tick_size_smaller(self): # 0.1 self.assertFalse(is_tick_size_smaller("0.1", "0.1")) self.assertFalse(is_tick_size_smaller("0.1", "0.01")) self.assertFalse(is_tick_size_smaller("0.1", "0.001")) self.assertFalse(is_tick_size_smaller("0.1", "0.0001")) # 0.01 self.assertTrue(is_tick_size_smaller("0.01", "0.1")) self.assertFalse(is_tick_size_smaller("0.01", "0.01")) self.assertFalse(is_tick_size_smaller("0.01", "0.001")) self.assertFalse(is_tick_size_smaller("0.01", "0.0001")) # 0.001 self.assertTrue(is_tick_size_smaller("0.001", "0.1")) self.assertTrue(is_tick_size_smaller("0.001", "0.01")) self.assertFalse(is_tick_size_smaller("0.001", "0.001")) self.assertFalse(is_tick_size_smaller("0.001", "0.0001")) # 0.0001 self.assertTrue(is_tick_size_smaller("0.0001", "0.1")) self.assertTrue(is_tick_size_smaller("0.0001", "0.01")) self.assertTrue(is_tick_size_smaller("0.0001", "0.001")) self.assertFalse(is_tick_size_smaller("0.0001", "0.0001")) def test_price_valid(self): self.assertFalse(price_valid(0.00001, "0.0001")) self.assertTrue(price_valid(0.0001, "0.0001")) self.assertTrue(price_valid(0.001, "0.0001")) self.assertTrue(price_valid(0.01, "0.0001")) self.assertTrue(price_valid(0.1, "0.0001")) self.assertTrue(price_valid(0.9, "0.0001")) self.assertTrue(price_valid(0.99, "0.0001")) self.assertTrue(price_valid(0.999, "0.0001")) self.assertTrue(price_valid(0.9999, "0.0001")) self.assertFalse(price_valid(0.99999, "0.0001")) self.assertFalse(price_valid(0.00001, "0.001")) self.assertFalse(price_valid(0.0001, "0.001")) self.assertTrue(price_valid(0.001, "0.001")) self.assertTrue(price_valid(0.01, "0.001")) self.assertTrue(price_valid(0.1, "0.001")) self.assertTrue(price_valid(0.9, "0.001")) self.assertTrue(price_valid(0.99, "0.001")) self.assertTrue(price_valid(0.999, "0.001")) self.assertFalse(price_valid(0.9999, "0.001")) self.assertFalse(price_valid(0.99999, "0.001")) self.assertFalse(price_valid(0.00001, "0.01")) self.assertFalse(price_valid(0.0001, "0.01")) self.assertFalse(price_valid(0.001, "0.01")) self.assertTrue(price_valid(0.01, "0.01")) self.assertTrue(price_valid(0.1, "0.01")) self.assertTrue(price_valid(0.9, "0.01")) self.assertTrue(price_valid(0.99, "0.01")) self.assertFalse(price_valid(0.999, "0.01")) self.assertFalse(price_valid(0.9999, "0.01")) self.assertFalse(price_valid(0.99999, "0.01")) self.assertFalse(price_valid(0.00001, "0.1")) self.assertFalse(price_valid(0.0001, "0.1")) self.assertFalse(price_valid(0.001, "0.1")) self.assertFalse(price_valid(0.01, "0.1")) self.assertTrue(price_valid(0.1, "0.1")) self.assertTrue(price_valid(0.9, "0.1")) self.assertFalse(price_valid(0.99, "0.1")) self.assertFalse(price_valid(0.999, "0.1")) self.assertFalse(price_valid(0.9999, "0.1")) self.assertFalse(price_valid(0.99999, "0.1"))