Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 71 additions & 33 deletions poetry.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ packages = [{ include = "x10" }]
[tool.poetry.dependencies]
aiohttp = ">=3.10.11"
eth-account = ">=0.12.0"
fast-stark-crypto = "==0.3.8"
fast-stark-crypto = "==0.5.0"
pydantic = ">=2.9.0"
python = "^3.10"
pyyaml = ">=6.0.1"
Expand Down
11 changes: 11 additions & 0 deletions x10/perpetual/balances.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,14 @@ class BalanceModel(X10BaseModel):
initial_margin: Decimal
margin_ratio: Decimal
updated_time: int

class SpotBalanceModel(X10BaseModel):
account_id: int
asset: str
balance: Decimal
index_price: Decimal
notional_value: Decimal
contribution_factor: Decimal
equity_contribution: Decimal
available_to_withdraw: Decimal
updated_at: int
15 changes: 10 additions & 5 deletions x10/perpetual/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,11 @@ class EndpointConfig:
asset_operations_contract: str
collateral_asset_on_chain_id: str
collateral_decimals: int
collateral_asset_id: str
starknet_domain: StarknetDomain
vault_position: int = 0
vault_asset_on_chain_id: str = "0x0"
vault_asset_id: int = 0
vault_asset_name: str = "UNKNOWN"


TESTNET_CONFIG = EndpointConfig(
Expand All @@ -30,12 +33,15 @@ class EndpointConfig:
stream_url="wss://api.starknet.sepolia.extended.exchange/stream.extended.exchange/v1",
onboarding_url="https://api.starknet.sepolia.extended.exchange",
signing_domain="starknet.sepolia.extended.exchange",
collateral_asset_contract="0x31857064564ed0ff978e687456963cba09c2c6985d8f9300a1de4962fafa054",
collateral_asset_contract="0x05ba91db44b3e6a4485b5dbfcb17d791faa9cb6890a42731b66b3536b28b8ed5",
asset_operations_contract="",
collateral_asset_on_chain_id="0x1",
collateral_asset_on_chain_id="0x31857064564ed0ff978e687456963cba09c2c6985d8f9300a1de4962fafa054",
collateral_decimals=6,
collateral_asset_id="0x1",
starknet_domain=StarknetDomain(name="Perpetuals", version="v0", chain_id="SN_SEPOLIA", revision="1"),
vault_position=7,
vault_asset_on_chain_id="0x04471D52BA219221ba25A254f771bDA2BC89998895D3640A307D3C49aE262990",
vault_asset_id=33,
vault_asset_name="XVS",
)

MAINNET_CONFIG = EndpointConfig(
Expand All @@ -48,6 +54,5 @@ class EndpointConfig:
asset_operations_contract="",
collateral_asset_on_chain_id="0x1",
collateral_decimals=6,
collateral_asset_id="0x1",
starknet_domain=StarknetDomain(name="Perpetuals", version="v0", chain_id="SN_MAIN", revision="1"),
)
38 changes: 35 additions & 3 deletions x10/perpetual/order_object_settlement.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from decimal import Decimal
from typing import Callable, Optional, Tuple

from fast_stark_crypto import get_order_msg_hash
from fast_stark_crypto import get_limit_order_msg_hash, get_order_msg_hash

from x10.perpetual.amounts import (
ROUNDING_BUY_CONTEXT,
Expand Down Expand Up @@ -45,13 +45,45 @@ class SettlementDataCtx:
starknet_domain: StarknetDomain


def __calc_settlement_expiration(expiration_timestamp: datetime):
def calculate_order_settlement_expiration(expiration_timestamp: datetime):
expire_time_with_buffer = expiration_timestamp + timedelta(days=14)
expire_time_as_seconds = math.ceil(expire_time_with_buffer.timestamp())

return expire_time_as_seconds


def hash_limit_order(
amount_base: StarkAmount,
amount_quote: StarkAmount,
max_fee: StarkAmount,
nonce: int,
position_id: int,
expiration_timestamp: datetime,
public_key: int,
starknet_domain: StarknetDomain,
) -> int:
synthetic_asset = amount_base.asset
collateral_asset = amount_quote.asset

return get_limit_order_msg_hash(
source_position_id=position_id,
receive_position_id=position_id,
base_asset_id=int(synthetic_asset.settlement_external_id, 16),
base_amount=amount_base.value,
quote_asset_id=int(collateral_asset.settlement_external_id, 16),
quote_amount=amount_quote.value,
fee_amount=max_fee.value,
fee_asset_id=int(collateral_asset.settlement_external_id, 16),
expiration=calculate_order_settlement_expiration(expiration_timestamp),
salt=nonce,
user_public_key=public_key,
domain_name=starknet_domain.name,
domain_version=starknet_domain.version,
domain_chain_id=starknet_domain.chain_id,
domain_revision=starknet_domain.revision,
)


def hash_order(
amount_synthetic: StarkAmount,
amount_collateral: StarkAmount,
Expand All @@ -73,7 +105,7 @@ def hash_order(
quote_amount=amount_collateral.value,
fee_amount=max_fee.value,
fee_asset_id=int(collateral_asset.settlement_external_id, 16),
expiration=__calc_settlement_expiration(expiration_timestamp),
expiration=calculate_order_settlement_expiration(expiration_timestamp),
salt=nonce,
user_public_key=public_key,
domain_name=starknet_domain.name,
Expand Down
14 changes: 14 additions & 0 deletions x10/perpetual/orders.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,20 @@ class StarkSettlementModel(X10BaseModel):
collateral_position: Decimal


class LimitOrderSettlementModel(X10BaseModel):
base_amount: int
quote_amount: int
fee_amount: int
base_asset_id: HexValue
quote_asset_id: HexValue
fee_asset_id: HexValue
expiration_timestamp: int
nonce: int
receiver_position_id: int
sender_position_id: int
signature: SettlementSignatureModel


class StarkDebuggingOrderAmountsModel(X10BaseModel):
collateral_amount: Decimal
fee_amount: Decimal
Expand Down
10 changes: 9 additions & 1 deletion x10/perpetual/trading_client/account_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
AssetOperationStatus,
AssetOperationType,
)
from x10.perpetual.balances import BalanceModel
from x10.perpetual.balances import BalanceModel, SpotBalanceModel
from x10.perpetual.bridges import BridgesConfig, Quote
from x10.perpetual.clients import ClientModel
from x10.perpetual.fees import TradingFeeModel
Expand Down Expand Up @@ -124,6 +124,14 @@ async def get_order_by_external_id(self, external_id: str) -> WrappedApiResponse
url = self._get_url("/user/orders/external/<external_id>", external_id=external_id)

return await send_get_request(await self.get_session(), url, list[OpenOrderModel], api_key=self._get_api_key())

async def get_spot_balances(self) -> WrappedApiResponse[List[SpotBalanceModel]]:
"""
https://api.docs.extended.exchange/#get-spot-balance
"""

url = self._get_url("/user/spot/balances")
return await send_get_request(await self.get_session(), url, List[SpotBalanceModel], api_key=self._get_api_key())

async def get_trades(
self,
Expand Down
18 changes: 18 additions & 0 deletions x10/perpetual/trading_client/trading_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
)
from x10.perpetual.trading_client.order_management_module import OrderManagementModule
from x10.perpetual.trading_client.testnet_module import TestnetModule
from x10.perpetual.trading_client.vault_module import VaultModule
from x10.utils.date import utc_now
from x10.utils.http import WrappedApiResponse
from x10.utils.log import get_logger
Expand All @@ -41,6 +42,7 @@ class PerpetualTradingClient:
__order_management_module: OrderManagementModule
__testnet_module: TestnetModule
__config: EndpointConfig
__vault_module: VaultModule

async def place_order(
self,
Expand Down Expand Up @@ -102,6 +104,12 @@ async def close(self):
await self.__account_module.close_session()
await self.__order_management_module.close_session()

async def __aenter__(self):
return self

async def __aexit__(self, exc_type, exc_value, traceback):
await self.close()

def __init__(self, endpoint_config: EndpointConfig, stark_account: StarkPerpetualAccount | None = None):
api_key = stark_account.api_key if stark_account else None

Expand All @@ -116,6 +124,12 @@ def __init__(self, endpoint_config: EndpointConfig, stark_account: StarkPerpetua
self.__order_management_module = OrderManagementModule(endpoint_config, api_key=api_key)
self.__testnet_module = TestnetModule(endpoint_config, api_key=api_key, account_module=self.__account_module)
self.__config = endpoint_config
self.__vault_module = VaultModule(
endpoint_config,
account_module=self.__account_module,
account=stark_account,
api_key=api_key,
)

@property
def info(self):
Expand All @@ -136,3 +150,7 @@ def orders(self):
@property
def testnet(self):
return self.__testnet_module

@property
def vault(self):
return self.__vault_module
Loading
Loading