From ebd0c733ed746b44aca9729f3de9ea1bb7fb8dd4 Mon Sep 17 00:00:00 2001 From: William Westgarth Date: Tue, 28 Oct 2025 09:11:13 +0000 Subject: [PATCH 1/3] chore: update examples and remove references to non-permissionless platforms --- README.md | 2 +- enclave/_perps.py | 2 + enclave/client.py | 2 +- enclave/models.py | 3 - examples/intro.py | 165 +++++--------------------------------------- examples/wsintro.py | 2 +- 6 files changed, 23 insertions(+), 153 deletions(-) diff --git a/README.md b/README.md index 7302313..3501184 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ pip install enclave from enclave.client import Client import enclave.models -client = Client("", "", enclave.models.PROD) +client = Client("", "", enclave.models.PROD_PERMISSIONLESS) print(client.wait_until_ready()) # should print True ``` diff --git a/enclave/_perps.py b/enclave/_perps.py index 389b19c..e7ff52d 100644 --- a/enclave/_perps.py +++ b/enclave/_perps.py @@ -3,6 +3,7 @@ """ import json from decimal import Decimal +from dataclasses import dataclass from typing import Optional, Union, List from . import _baseclient, models @@ -423,6 +424,7 @@ def cancel_order(self, *, client_order_id: Optional[str] = None, order_id: Optio return self.bc.delete(f"/v1/perps/orders/{path}") + @dataclass class OrderParams: market: str side: str diff --git a/enclave/client.py b/enclave/client.py index 327ea12..89101f9 100644 --- a/enclave/client.py +++ b/enclave/client.py @@ -32,7 +32,7 @@ class Client: or from a file using `from_api_file` with the key id on the first line and the secret on the second line. """ - def __init__(self, api_key: str, api_secret: str, base_url: str = models.PROD): + def __init__(self, api_key: str, api_secret: str, base_url: str = models.PROD_PERMISSIONLESS): self.bc = _baseclient.BaseClient(api_key, api_secret, base_url) self.cross = _cross.Cross(self.bc) diff --git a/enclave/models.py b/enclave/models.py index 22f9e6b..a5497db 100644 --- a/enclave/models.py +++ b/enclave/models.py @@ -10,12 +10,9 @@ PUT: Final[str] = "PUT" VERBS: Final[Set[str]] = {GET, POST, DELETE, PUT} -DEV: Final[str] = "https://api-dev.enclavemarket.dev" DEV_PERMISSIONLESS: Final[str] = "https://api-dev-permissionless.enclavemarket.dev" STAGING: Final[str] = "https://api-staging.enclavemarket.dev" -SANDBOX: Final[str] = "https://api-sandbox.enclave.market" SANDBOX_PERMISSIONLESS: Final[str] = "https://api-sandbox.enclave.trade" -PROD: Final[str] = "https://api.enclave.market" PROD_PERMISSIONLESS: Final[str] = "https://api.enclave.trade" BUY: Final[str] = "buy" diff --git a/examples/intro.py b/examples/intro.py index 991d363..f07437f 100644 --- a/examples/intro.py +++ b/examples/intro.py @@ -9,89 +9,14 @@ from enclave.client import Client -def spot(client: Client) -> None: - """Demonstrate some spot trading functionality.""" - - # get the balance of AVAX - balance = Decimal(client.get_balance("AVAX").json()["result"]["freeBalance"]) - print(f"Free AVAX balance: {balance=}") - - # get the AVAX-USDC trading pair to find the min order sizes - spot_trading_pairs = client.get_markets().json()["result"]["spot"]["tradingPairs"] - avax_trading_pair = [pairs for pairs in spot_trading_pairs if pairs["market"] == "AVAX-USDC"][0] - print(f"{avax_trading_pair=}") - avax_base_min, avax_quote_min = Decimal(avax_trading_pair["baseIncrement"]), Decimal( - avax_trading_pair["quoteIncrement"] - ) - print(f"{avax_base_min=} {avax_quote_min=}") - - # get top of book for avax usdc - avax_top_of_book = client.spot.get_depth("AVAX-USDC", depth=1).json()["result"] - print(f"{avax_top_of_book=}") - avax_ask_price, avax_ask_size = (Decimal(x) for x in avax_top_of_book["asks"][0]) - print(f"{avax_ask_price=}, {avax_ask_size=}") - - # place a sell limit order of the smallest size one tick above the top of book (so we don't get filled) - assert balance >= avax_base_min - custom_id = f"demo{int(time.time_ns())}" - sell_order = client.spot.add_order( - "AVAX-USDC", - enclave.models.SELL, - avax_ask_price + avax_quote_min, - avax_base_min, - order_type=enclave.models.LIMIT, - client_order_id=custom_id, - ).json()["result"] - print(f"{sell_order=}") - - # cancel all orders in the market - cancel_res = client.spot.cancel_orders("AVAX-USDC").json() - print(f"{cancel_res=}") - - # get the order status - order_status = client.spot.get_order(client_order_id=custom_id).json()["result"] - print(f"{order_status=}") - filled_size = Decimal(order_status["filledSize"]) - print(f"{filled_size=}") - - # cause a trade and query fills - custom_id = f"demo{int(time.time_ns())}" - sell_order = client.spot.add_order( - "AVAX-USDC", - enclave.models.SELL, - None, - avax_base_min, - order_type=enclave.models.MARKET, - client_order_id=custom_id, - ).json()["result"] - - print(f"{sell_order=}") - - fills_by_custom_id = client.spot.get_fills_by_id(client_order_id=custom_id).json()["result"] - print(f"found {len(fills_by_custom_id)} fills by custom id") - - fills_by_order_id = client.spot.get_fills_by_id(order_id=sell_order["orderId"]).json()["result"] - print(f"found {len(fills_by_order_id)} fills by order id") - - all_fills = client.spot.get_fills().json()["result"] - print(f"found {len(all_fills)} fills for all orders") - - def perps(client: Client) -> None: """Demonstrate some perps trading functionality.""" - # get USDC balance - usdc_balance = Decimal(client.get_balance("USDC").json()["result"]["freeBalance"]) - print(f"Free USDC balance: {usdc_balance=}") - - # transfer USDC from the main account to perps - assert usdc_balance >= Decimal(1) - margin_deposit = client.perps.transfer("USDC", Decimal(1)).json() - print(f"{margin_deposit=}") margin_balance = client.perps.get_balance().json() print(f"{margin_balance=}") available_margin = Decimal(margin_balance["result"]["availableMargin"]) print(f"{available_margin=}") + assert available_margin >= Decimal(1) # other than margin, leverage etc, perps is the same API as spot perps_trading_pairs = client.get_markets().json()["result"]["perps"]["tradingPairs"] @@ -121,12 +46,14 @@ def perps(client: Client) -> None: custom_id = f"demo{int(time.time_ns())}" buy_order = client.perps.add_order( - "BTC-USD.P", - enclave.models.BUY, - buy_price, - buy_size, - order_type=enclave.models.LIMIT, - client_order_id=custom_id, + client.perps.OrderParams( + market="BTC-USD.P", + side=enclave.models.BUY, + price=buy_price, + size=buy_size, + order_type=enclave.models.LIMIT, + client_order_id=custom_id + ) ).json() print(f"{buy_order=}") @@ -143,12 +70,14 @@ def perps(client: Client) -> None: # cause a trade and query fills custom_id = f"demo{int(time.time_ns())}" buy_order = client.perps.add_order( - "BTC-USD.P", - enclave.models.BUY, - None, - buy_size, - order_type=enclave.models.MARKET, - client_order_id=custom_id, + client.perps.OrderParams( + market="BTC-USD.P", + side=enclave.models.BUY, + price=None, + size=buy_size, + order_type=enclave.models.MARKET, + client_order_id=custom_id + ) ).json()["result"] print(f"{buy_order=}") @@ -170,56 +99,6 @@ def perps(client: Client) -> None: print(f"{margin_balance=}") -def cross(client: Client) -> None: - """Demonstrate some cross trading functionality.""" - - # get the balance of AVAX - balance = Decimal(client.get_balance("USDC").json()["result"]["freeBalance"]) - print(f"Free USDC balance: {balance=}") - - # get the AVAX-USDC trading pair to find the min order sizes for cross - cross_configs = client.get_markets().json()["result"]["tokenConfig"] - usdc_trading_pair = [token for token in cross_configs if token["id"] == "USDC"][0] - print(f"{usdc_trading_pair=}") - # doing a buy order so we need the sizes for the quote currency, USDC - min_usdc, max_usdc = Decimal(usdc_trading_pair["minOrderSize"]), Decimal(usdc_trading_pair["maxOrderSize"]) - print(f"{min_usdc=} {max_usdc=}") - - # get the oracle price for AVAX-USDC - avax_usdc_price = Decimal(client.cross.get_price("AVAX-USDC").json()["result"]["price"]) - print(f"{avax_usdc_price=}") - - # buy AVAX for USDC at no more than the current price + $1 - assert min_usdc <= balance <= max_usdc - custom_id = f"demo{int(time.time_ns())}" - buy_order = client.cross.add_order( - "AVAX-USDC", - enclave.models.BUY, - min_usdc, - cancel_above=avax_usdc_price + Decimal(1), - customer_order_id=custom_id, - ).json() - print(f"{buy_order=}") - - # cancel order - cancel_res = client.cross.cancel_order(customer_order_id=custom_id).json() - print(f"{cancel_res=}") - - # get the order details - order_status = client.cross.get_order(customer_order_id=custom_id).json()["result"] - print(f"{order_status=}") - print(f"amount filled: {order_status['filledSize']=}, status: {order_status['status']=}") - - fills_by_custom_id = client.cross.get_fills_by_id(customer_order_id=custom_id).json()["result"] - print(f"found {len(fills_by_custom_id)} fills by custom id") - - fills_by_order_id = client.cross.get_fills_by_id(internal_order_id=buy_order["result"]["internalOrderId"]).json()["result"] - print(f"found {len(fills_by_order_id)} fills by order id") - - all_fills = client.cross.get_fills().json()["result"] - print(f"found {len(all_fills)} fills for all orders") - - if __name__ == "__main__": # For more auth options, see auth.py @@ -228,24 +107,16 @@ def cross(client: Client) -> None: API_SECRET = str(os.getenv("enclave_secret")) # create a client - enclave_client = Client(API_KEY, API_SECRET, enclave.models.SANDBOX) + enclave_client = Client(API_KEY, API_SECRET, enclave.models.SANDBOX_PERMISSIONLESS) if not enclave_client.wait_until_ready(): raise RuntimeError("Enclave not connecting.") authed_hello = enclave_client.authed_hello().json() print(f"{authed_hello=}") - # run the spot example - print(f"\nRunning spot example...\n{'*' * 80}") - spot(enclave_client) - # run the perps example print(f"\nRunning perps example...\n{'*' * 80}") perps(enclave_client) - # run the cross example - print(f"\nRunning cross example...\n{'*' * 80}") - cross(enclave_client) - print("\nHave a nice day! (Thank you!)") # %% diff --git a/examples/wsintro.py b/examples/wsintro.py index 6c6e7f2..ffbf26f 100644 --- a/examples/wsintro.py +++ b/examples/wsintro.py @@ -44,7 +44,7 @@ async def main() -> None: ws = WebSocketClient( API_KEY, API_SECRET, - "wss://api-sandbox.enclave.market/ws", + "wss://api-sandbox.enclave.trade/ws", on_connect=lambda: print("On Connect"), on_auth=lambda: print("On Auth"), on_error=lambda x: print(f"On Error: {x}"), From fdb7ebff7e0d786febf5b8afbab3f54d45e03ad6 Mon Sep 17 00:00:00 2001 From: William Westgarth Date: Tue, 28 Oct 2025 11:51:27 +0000 Subject: [PATCH 2/3] chore: update readme --- README.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 3501184..b92b0d2 100644 --- a/README.md +++ b/README.md @@ -40,11 +40,13 @@ print(client.wait_until_ready()) # should print True ```python buy_order = client.perps.add_order( - "BTC-USD.P", - enclave.models.BUY, - Decimal(42_000), - Decimal(0.1), - order_type=enclave.models.LIMIT, + client.perps.OrderParams( + market="BTC-USD.P", + side=enclave.models.BUY, + price=Decimal(42_000), + size=Decimal(0.1), + order_type=enclave.models.LIMIT + ) ) ``` From 2e3fb5ce1988f51ef3864ae9e328db0924c40e82 Mon Sep 17 00:00:00 2001 From: William Westgarth Date: Tue, 28 Oct 2025 13:02:10 +0000 Subject: [PATCH 3/3] chore: PROD and PROD_PERMISSIONLESS point to the same URL --- README.md | 2 +- enclave/models.py | 3 +++ examples/intro.py | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b92b0d2..976a3d0 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ pip install enclave from enclave.client import Client import enclave.models -client = Client("", "", enclave.models.PROD_PERMISSIONLESS) +client = Client("", "", enclave.models.PROD) print(client.wait_until_ready()) # should print True ``` diff --git a/enclave/models.py b/enclave/models.py index a5497db..3205b67 100644 --- a/enclave/models.py +++ b/enclave/models.py @@ -10,9 +10,12 @@ PUT: Final[str] = "PUT" VERBS: Final[Set[str]] = {GET, POST, DELETE, PUT} +DEV: Final[str] = "https://api-dev-permissionless.enclavemarket.dev" DEV_PERMISSIONLESS: Final[str] = "https://api-dev-permissionless.enclavemarket.dev" STAGING: Final[str] = "https://api-staging.enclavemarket.dev" +SANDBOX: Final[str] = "https://api-sandbox.enclave.trade" SANDBOX_PERMISSIONLESS: Final[str] = "https://api-sandbox.enclave.trade" +PROD: Final[str] = "https://api.enclave.trade" PROD_PERMISSIONLESS: Final[str] = "https://api.enclave.trade" BUY: Final[str] = "buy" diff --git a/examples/intro.py b/examples/intro.py index f07437f..ee78295 100644 --- a/examples/intro.py +++ b/examples/intro.py @@ -107,7 +107,7 @@ def perps(client: Client) -> None: API_SECRET = str(os.getenv("enclave_secret")) # create a client - enclave_client = Client(API_KEY, API_SECRET, enclave.models.SANDBOX_PERMISSIONLESS) + enclave_client = Client(API_KEY, API_SECRET, enclave.models.SANDBOX) if not enclave_client.wait_until_ready(): raise RuntimeError("Enclave not connecting.") authed_hello = enclave_client.authed_hello().json()