Skip to content
Merged
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
14 changes: 7 additions & 7 deletions tests/perpetual/test_transfer_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,24 +32,24 @@ async def test_create_transfer(mocker: MockerFixture, create_trading_account, cr
transfer_obj.to_api_request_json(),
equal_to(
{
"fromVault": trading_account.vault,
"toVault": int(accounts[1].l2_vault),
"fromVault": 10002,
"toVault": 10002,
"amount": "1.1",
"transferredAsset": "0x1",
"settlement": {
"amount": 1100000,
"assetId": "0x1",
"expirationTimestamp": 1706231337,
"nonce": 1473459052,
"receiverPositionId": int(accounts[1].l2_vault),
"receiverPublicKey": accounts[1].l2_key,
"senderPositionId": trading_account.vault,
"senderPublicKey": f"{hex(trading_account.public_key)}",
"receiverPositionId": 10002,
"receiverPublicKey": "0x3895139a98a6168dc8b0db251bcd0e6dcf97fd1e96f7a87d9bd3f341753a844",
"senderPositionId": 10002,
"senderPublicKey": "0x61c5e7e8339b7d56f197f54ea91b776776690e3232313de0f2ecbd0ef76f466",
"signature": {
"r": "0x21f353080b04ab862474d0d2985f4d223087a89193a3a8bdea3de320f845cf8",
"s": "0x6f70daa9e65037d97ccf0667cc6f1368b7b01a93d0ededf929b53be3f177d96",
},
},
"transferredAsset": "0x1",
}
),
)
29 changes: 29 additions & 0 deletions x10/perpetual/assets.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,21 @@
from x10.utils.model import HexValue, X10BaseModel


class AssetModel(X10BaseModel):
id: int
name: str
symbol: str
precision: int
is_active: bool
is_collateral: bool
starkex_id: HexValue
starkex_resolution: int
l1_id: str
l1_resolution: int
version: int


# FIXME: Replace with AssetModel
@dataclass
class Asset:
id: int
Expand Down Expand Up @@ -37,6 +52,20 @@ def convert_internal_quantity_to_l1_quantity(self, internal: Decimal) -> int:
raise ValueError("Only collateral assets have an L1 representation")
return int(internal * Decimal(self.l1_resolution))

@staticmethod
def from_model(model: AssetModel):
return Asset(
id=model.id,
name=model.name,
precision=model.precision,
active=model.is_active,
is_collateral=model.is_collateral,
settlement_external_id=hex(model.starkex_id),
settlement_resolution=model.starkex_resolution,
l1_external_id=model.l1_id,
l1_resolution=model.l1_resolution,
)


class AssetOperationType(StrEnum):
CLAIM = "CLAIM"
Expand Down
12 changes: 12 additions & 0 deletions x10/perpetual/balances.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,15 @@ 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
11 changes: 8 additions & 3 deletions x10/perpetual/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class StarknetDomain:
class EndpointConfig:
"""
Attributes:
chain_rpc_url (str): Field is deprecated and will be removed.
asset_operations_contract (str): Field is deprecated and will be removed.
collateral_asset_contract (str): Field is deprecated and will be removed.
collateral_asset_on_chain_id (str): Field is deprecated and will be removed.
Expand All @@ -33,19 +34,22 @@ class EndpointConfig:
collateral_decimals: int
collateral_asset_id: str

vault_asset_name: str


TESTNET_CONFIG = EndpointConfig(
chain_rpc_url="https://rpc.sepolia.org",
api_base_url="https://api.starknet.sepolia.extended.exchange/api/v1",
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",
starknet_domain=StarknetDomain(name="Perpetuals", version="v0", chain_id="SN_SEPOLIA", revision="1"),
asset_operations_contract="",
collateral_asset_contract="0x31857064564ed0ff978e687456963cba09c2c6985d8f9300a1de4962fafa054",
collateral_asset_contract="0x05ba91db44b3e6a4485b5dbfcb17d791faa9cb6890a42731b66b3536b28b8ed5",
collateral_asset_on_chain_id="0x1",
collateral_decimals=6,
collateral_asset_id="0x1",
starknet_domain=StarknetDomain(name="Perpetuals", version="v0", chain_id="SN_SEPOLIA", revision="1"),
vault_asset_name="XVS",
)

MAINNET_CONFIG = EndpointConfig(
Expand All @@ -54,10 +58,11 @@ class EndpointConfig:
stream_url="wss://api.starknet.extended.exchange/stream.extended.exchange/v1",
onboarding_url="https://api.starknet.extended.exchange",
signing_domain="extended.exchange",
starknet_domain=StarknetDomain(name="Perpetuals", version="v0", chain_id="SN_MAIN", revision="1"),
asset_operations_contract="",
collateral_asset_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"),
vault_asset_name="XVS",
)
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
6 changes: 2 additions & 4 deletions x10/perpetual/simple_client/simple_trading_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@
PerpetualStreamConnection,
)
from x10.perpetual.stream_client.stream_client import PerpetualStreamClient
from x10.perpetual.trading_client.markets_information_module import (
MarketsInformationModule,
)
from x10.perpetual.trading_client.info_markets_module import InfoMarketsModule
from x10.perpetual.trading_client.order_management_module import OrderManagementModule
from x10.utils.http import WrappedStreamResponse

Expand Down Expand Up @@ -81,7 +79,7 @@ def __init__(self, endpoint_config: EndpointConfig, account: StarkPerpetualAccou
)
self.__endpoint_config = endpoint_config
self.__account = account
self.__market_module = MarketsInformationModule(endpoint_config, api_key=account.api_key)
self.__market_module = InfoMarketsModule(endpoint_config, api_key=account.api_key)
self.__orders_module = OrderManagementModule(endpoint_config, api_key=account.api_key)
self.__markets: Union[None, Dict[str, MarketModel]] = None
self.__stream_client: PerpetualStreamClient = PerpetualStreamClient(api_url=endpoint_config.stream_url)
Expand Down
12 changes: 11 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 @@ -125,6 +125,16 @@ async def get_order_by_external_id(self, external_id: str) -> WrappedApiResponse

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,
market_names: Optional[List[str]] = None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from x10.utils.http import send_get_request


class MarketsInformationModule(BaseModule):
class InfoMarketsModule(BaseModule):
async def get_markets(self, *, market_names: Optional[List[str]] = None):
"""
https://api.docs.extended.exchange/#get-markets
Expand Down
16 changes: 16 additions & 0 deletions x10/perpetual/trading_client/info_module.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
from decimal import Decimal
from typing import List

from x10.perpetual.assets import AssetModel
from x10.perpetual.trading_client.base_module import BaseModule
from x10.utils.http import send_get_request
from x10.utils.model import X10BaseModel
Expand All @@ -11,3 +15,15 @@ class InfoModule(BaseModule):
async def get_settings(self):
url = self._get_url("/info/settings")
return await send_get_request(await self.get_session(), url, _SettingsModel)

async def get_assets(self):
url = self._get_url("/info/assets")
return await send_get_request(await self.get_session(), url, List[AssetModel])

async def get_assets_dict(self):
assets = await self.get_assets()
return {asset.name: asset for asset in assets.data}

async def get_asset_price(self, *, asset_name: str):
url = self._get_url("/info/assets/<asset_name>/price", asset_name=asset_name)
return await send_get_request(await self.get_session(), url, Decimal)
Loading
Loading