x10-python-trading-starknet 0.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. x10/__init__.py +0 -0
  2. x10/config.py +13 -0
  3. x10/errors.py +2 -0
  4. x10/perpetual/__init__.py +0 -0
  5. x10/perpetual/accounts.py +86 -0
  6. x10/perpetual/amounts.py +55 -0
  7. x10/perpetual/assets.py +71 -0
  8. x10/perpetual/balances.py +15 -0
  9. x10/perpetual/candles.py +18 -0
  10. x10/perpetual/configuration.py +86 -0
  11. x10/perpetual/fees.py +16 -0
  12. x10/perpetual/funding_rates.py +11 -0
  13. x10/perpetual/markets.py +125 -0
  14. x10/perpetual/order_object.py +201 -0
  15. x10/perpetual/orderbook.py +211 -0
  16. x10/perpetual/orderbooks.py +17 -0
  17. x10/perpetual/orders.py +179 -0
  18. x10/perpetual/positions.py +51 -0
  19. x10/perpetual/simple_client/simple_trading_client.py +216 -0
  20. x10/perpetual/stream_client/__init__.py +3 -0
  21. x10/perpetual/stream_client/perpetual_stream_connection.py +108 -0
  22. x10/perpetual/stream_client/stream_client.py +83 -0
  23. x10/perpetual/trades.py +38 -0
  24. x10/perpetual/trading_client/__init__.py +3 -0
  25. x10/perpetual/trading_client/account_module.py +209 -0
  26. x10/perpetual/trading_client/base_module.py +58 -0
  27. x10/perpetual/trading_client/info_module.py +13 -0
  28. x10/perpetual/trading_client/markets_information_module.py +76 -0
  29. x10/perpetual/trading_client/order_management_module.py +81 -0
  30. x10/perpetual/trading_client/testnet_module.py +68 -0
  31. x10/perpetual/trading_client/trading_client.py +123 -0
  32. x10/perpetual/transfer_object.py +80 -0
  33. x10/perpetual/transfers.py +39 -0
  34. x10/perpetual/user_client/__init__.py +0 -0
  35. x10/perpetual/user_client/l1_signing.py +0 -0
  36. x10/perpetual/user_client/onboarding.py +231 -0
  37. x10/perpetual/user_client/user_client.py +199 -0
  38. x10/perpetual/withdrawal_object.py +29 -0
  39. x10/perpetual/withdrawals.py +29 -0
  40. x10/utils/__init__.py +2 -0
  41. x10/utils/date.py +11 -0
  42. x10/utils/http.py +239 -0
  43. x10/utils/log.py +5 -0
  44. x10/utils/model.py +66 -0
  45. x10/utils/nonce.py +11 -0
  46. x10/utils/string.py +10 -0
  47. x10_python_trading_starknet-0.0.1.dist-info/LICENSE +21 -0
  48. x10_python_trading_starknet-0.0.1.dist-info/METADATA +413 -0
  49. x10_python_trading_starknet-0.0.1.dist-info/RECORD +50 -0
  50. x10_python_trading_starknet-0.0.1.dist-info/WHEEL +4 -0
x10/__init__.py ADDED
File without changes
x10/config.py ADDED
@@ -0,0 +1,13 @@
1
+ import importlib.metadata
2
+
3
+ TRADING_API_URL_DEV = "http://api.testnet.extended.exchange/api/v1"
4
+ STREAM_API_URL_DEV = "wss://api.testnet.extended.exchange/stream.extended.exchange/v1"
5
+
6
+ BTC_USD_MARKET = "BTC-USD"
7
+ SOL_USD_MARKET = "SOL-USD"
8
+ ADA_USD_MARKET = "ADA-USD"
9
+ ETH_USD_MARKET = "ETH-USD"
10
+
11
+ DEFAULT_REQUEST_TIMEOUT_SECONDS = 500
12
+ SDK_VERSION = importlib.metadata.version("x10-python-trading")
13
+ USER_AGENT = f"X10PythonTradingClient/{SDK_VERSION}"
x10/errors.py ADDED
@@ -0,0 +1,2 @@
1
+ class X10Error(Exception):
2
+ pass
File without changes
@@ -0,0 +1,86 @@
1
+ from decimal import Decimal
2
+ from typing import Dict, List, Optional, Tuple
3
+
4
+ from fast_stark_crypto import sign
5
+ from pydantic import AliasChoices, Field
6
+
7
+ from x10.perpetual.balances import BalanceModel
8
+ from x10.perpetual.fees import TradingFeeModel
9
+ from x10.perpetual.orders import OpenOrderModel
10
+ from x10.perpetual.positions import PositionModel
11
+ from x10.perpetual.trades import AccountTradeModel
12
+ from x10.utils.model import X10BaseModel
13
+ from x10.utils.string import is_hex_string
14
+
15
+
16
+ class StarkPerpetualAccount:
17
+ __vault: int
18
+ __private_key: int
19
+ __public_key: int
20
+ __trading_fee: Dict[str, TradingFeeModel]
21
+
22
+ def __init__(self, vault: int | str, private_key: str, public_key: str, api_key: str):
23
+ assert is_hex_string(private_key)
24
+ assert is_hex_string(public_key)
25
+
26
+ if isinstance(vault, str):
27
+ vault = int(vault)
28
+ elif isinstance(vault, int):
29
+ self.__vault = vault
30
+ else:
31
+ raise ValueError("Invalid vault type")
32
+
33
+ self.__vault = vault
34
+ self.__private_key = int(private_key, base=16)
35
+ self.__public_key = int(public_key, base=16)
36
+ self.__api_key = api_key
37
+ self.__trading_fee = {}
38
+
39
+ @property
40
+ def vault(self):
41
+ return self.__vault
42
+
43
+ @property
44
+ def public_key(self):
45
+ return self.__public_key
46
+
47
+ @property
48
+ def api_key(self):
49
+ return self.__api_key
50
+
51
+ @property
52
+ def trading_fee(self):
53
+ return self.__trading_fee
54
+
55
+ def sign(self, msg_hash: int) -> Tuple[int, int]:
56
+ return sign(private_key=self.__private_key, msg_hash=msg_hash)
57
+
58
+
59
+ class AccountStreamDataModel(X10BaseModel):
60
+ orders: Optional[List[OpenOrderModel]] = None
61
+ positions: Optional[List[PositionModel]] = None
62
+ trades: Optional[List[AccountTradeModel]] = None
63
+ balance: Optional[BalanceModel] = None
64
+
65
+
66
+ class AccountLeverage(X10BaseModel):
67
+ market: str
68
+ leverage: Decimal
69
+
70
+
71
+ class AccountModel(X10BaseModel):
72
+ id: int = Field(validation_alias=AliasChoices("accountId", "id"), serialization_alias="id")
73
+ description: str
74
+ account_index: int
75
+ status: str
76
+ l2_key: str
77
+ l2_vault: int
78
+ api_keys: Optional[List[str]] = None
79
+
80
+
81
+ class ApiKeyResponseModel(X10BaseModel):
82
+ key: str
83
+
84
+
85
+ class ApiKeyRequestModel(X10BaseModel):
86
+ description: str
@@ -0,0 +1,55 @@
1
+ import decimal
2
+ from dataclasses import dataclass
3
+ from decimal import Decimal
4
+
5
+ from x10.perpetual.assets import Asset
6
+
7
+ ROUNDING_SELL_CONTEXT = decimal.Context(rounding=decimal.ROUND_DOWN)
8
+ ROUNDING_BUY_CONTEXT = decimal.Context(rounding=decimal.ROUND_UP)
9
+ ROUNDING_FEE_CONTEXT = decimal.Context(rounding=decimal.ROUND_UP)
10
+
11
+
12
+ @dataclass
13
+ class HumanReadableAmount:
14
+ value: Decimal
15
+ asset: Asset
16
+
17
+ def to_l1_amount(self) -> "L1Amount":
18
+ converted_value = self.asset.convert_internal_quantity_to_l1_quantity(self.value)
19
+ return L1Amount(converted_value, self.asset)
20
+
21
+ def to_stark_amount(self, rounding_context: decimal.Context) -> "StarkAmount":
22
+ converted_value = self.asset.convert_human_readable_to_stark_quantity(self.value, rounding_context)
23
+ return StarkAmount(converted_value, self.asset)
24
+
25
+
26
+ @dataclass
27
+ class L1Amount:
28
+ value: int
29
+ asset: Asset
30
+
31
+ def to_internal_amount(self) -> HumanReadableAmount:
32
+ converted_value = self.asset.convert_l1_quantity_to_internal_quantity(self.value)
33
+ return HumanReadableAmount(converted_value, self.asset)
34
+
35
+
36
+ @dataclass
37
+ class StarkAmount:
38
+ value: int
39
+ asset: Asset
40
+
41
+ def to_internal_amount(self) -> HumanReadableAmount:
42
+ converted_value = self.asset.convert_stark_to_internal_quantity(self.value)
43
+ return HumanReadableAmount(converted_value, self.asset)
44
+
45
+ def negate(self) -> "StarkAmount":
46
+ return StarkAmount(-self.value, self.asset)
47
+
48
+
49
+ @dataclass
50
+ class StarkOrderAmounts:
51
+ collateral_amount_internal: HumanReadableAmount
52
+ synthetic_amount_internal: HumanReadableAmount
53
+ fee_amount_internal: HumanReadableAmount
54
+ fee_rate: Decimal
55
+ rounding_context: decimal.Context
@@ -0,0 +1,71 @@
1
+ from dataclasses import dataclass
2
+ from decimal import Context, Decimal
3
+ from enum import Enum
4
+ from typing import Optional
5
+
6
+ from x10.utils.model import HexValue, X10BaseModel
7
+
8
+
9
+ @dataclass
10
+ class Asset:
11
+ id: int
12
+ name: str
13
+ precision: int
14
+ active: bool
15
+ is_collateral: bool
16
+ settlement_external_id: str
17
+ settlement_resolution: int
18
+ l1_external_id: str
19
+ l1_resolution: int
20
+
21
+ def convert_human_readable_to_stark_quantity(self, internal: Decimal, rounding_context: Context) -> int:
22
+ return int(
23
+ rounding_context.multiply(internal, Decimal(self.settlement_resolution)).to_integral(
24
+ context=rounding_context
25
+ )
26
+ )
27
+
28
+ def convert_stark_to_internal_quantity(self, stark: int) -> Decimal:
29
+ return Decimal(stark) / Decimal(self.settlement_resolution)
30
+
31
+ def convert_l1_quantity_to_internal_quantity(self, l1: int) -> Decimal:
32
+ return Decimal(l1) / Decimal(self.l1_resolution)
33
+
34
+ def convert_internal_quantity_to_l1_quantity(self, internal: Decimal) -> int:
35
+ if not self.is_collateral:
36
+ raise ValueError("Only collateral assets have an L1 representation")
37
+ return int(internal * Decimal(self.l1_resolution))
38
+
39
+
40
+ class AssetOperationType(str, Enum):
41
+ CLAIM = "CLAIM"
42
+ DEPOSIT = "DEPOSIT"
43
+ FAST_WITHDRAWAL = "FAST_WITHDRAWAL"
44
+ SLOW_WITHDRAWAL = "SLOW_WITHDRAWAL"
45
+ TRANSFER = "TRANSFER"
46
+
47
+
48
+ class AssetOperationStatus(Enum):
49
+ # Technical status
50
+ UNKNOWN = "UNKNOWN"
51
+
52
+ CREATED = "CREATED"
53
+ IN_PROGRESS = "IN_PROGRESS"
54
+ REJECTED = "REJECTED"
55
+ READY_FOR_CLAIM = "READY_FOR_CLAIM"
56
+ COMPLETED = "COMPLETED"
57
+
58
+
59
+ class AssetOperationModel(X10BaseModel):
60
+ id: str
61
+ type: AssetOperationType
62
+ status: AssetOperationStatus
63
+ amount: Decimal
64
+ fee: Decimal
65
+ asset: int
66
+ time: int
67
+ account_id: int
68
+
69
+ # When operation type is `TRANSFER`
70
+ counterparty_account_id: Optional[int] = None
71
+ transaction_hash: Optional[HexValue] = None
@@ -0,0 +1,15 @@
1
+ from decimal import Decimal
2
+
3
+ from x10.utils.model import X10BaseModel
4
+
5
+
6
+ class BalanceModel(X10BaseModel):
7
+ collateral_name: str
8
+ balance: Decimal
9
+ equity: Decimal
10
+ available_for_trade: Decimal
11
+ available_for_withdrawal: Decimal
12
+ unrealised_pnl: Decimal
13
+ initial_margin: Decimal
14
+ margin_ratio: Decimal
15
+ updated_time: int
@@ -0,0 +1,18 @@
1
+ from decimal import Decimal
2
+ from typing import Literal
3
+
4
+ from pydantic import AliasChoices, Field
5
+
6
+ from x10.utils.model import X10BaseModel
7
+
8
+ CandleType = Literal["trades", "mark-prices", "index-prices"]
9
+ CandleInterval = Literal["PT1M", "PT5M", "PT15M", "PT30M", "PT1H", "PT2H", "PT4H", "P1D"]
10
+
11
+
12
+ class CandleModel(X10BaseModel):
13
+ open: Decimal = Field(validation_alias=AliasChoices("open", "o"), serialization_alias="o")
14
+ low: Decimal = Field(validation_alias=AliasChoices("low", "l"), serialization_alias="l")
15
+ high: Decimal = Field(validation_alias=AliasChoices("high", "h"), serialization_alias="h")
16
+ close: Decimal = Field(validation_alias=AliasChoices("close", "c"), serialization_alias="c")
17
+ volume: Decimal = Field(validation_alias=AliasChoices("volume", "v"), serialization_alias="v")
18
+ timestamp: int = Field(validation_alias=AliasChoices("timestamp", "T"), serialization_alias="T")
@@ -0,0 +1,86 @@
1
+ from dataclasses import dataclass
2
+
3
+
4
+ @dataclass
5
+ class StarknetDomain:
6
+ name: str
7
+ version: str
8
+ chain_id: str
9
+ revision: str
10
+
11
+
12
+ @dataclass
13
+ class EndpointConfig:
14
+ chain_rpc_url: str
15
+ api_base_url: str
16
+ stream_url: str
17
+ onboarding_url: str
18
+ signing_domain: str
19
+ collateral_asset_contract: str
20
+ asset_operations_contract: str
21
+ collateral_asset_on_chain_id: str
22
+ collateral_decimals: int
23
+ collateral_asset_id: str
24
+ starknet_domain: StarknetDomain
25
+
26
+
27
+ TESTNET_CONFIG = EndpointConfig(
28
+ chain_rpc_url="https://rpc.sepolia.org",
29
+ api_base_url="https://api.testnet.extended.exchange/api/v1",
30
+ stream_url="wss://api.testnet.extended.exchange/stream.extended.exchange/v1",
31
+ onboarding_url="https://api.testnet.extended.exchange",
32
+ signing_domain="testnet.extended.exchange",
33
+ collateral_asset_contract="0x0C9165046063B7bCD05C6924Bbe05ed535c140a1",
34
+ asset_operations_contract="0xe42bb60Fab4EA4905832AEbDf0f001c784dA271b",
35
+ collateral_asset_on_chain_id="0x31857064564ed0ff978e687456963cba09c2c6985d8f9300a1de4962fafa054",
36
+ collateral_decimals=6,
37
+ collateral_asset_id="0x1",
38
+ starknet_domain=StarknetDomain(name="Perpetuals", version="v0", chain_id="SN_SEPOLIA", revision="1"),
39
+ )
40
+
41
+ MAINNET_CONFIG = EndpointConfig(
42
+ chain_rpc_url="https://cloudflare-eth.com",
43
+ api_base_url="https://api.extended.exchange/api/v1",
44
+ stream_url="wss://api.extended.exchange/stream.extended.exchange/v1",
45
+ onboarding_url="https://api.extended.exchange",
46
+ signing_domain="extended.exchange",
47
+ collateral_asset_contract="0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
48
+ asset_operations_contract="0x1cE5D7f52A8aBd23551e91248151CA5A13353C65",
49
+ collateral_asset_on_chain_id="0x2893294412a4c8f915f75892b395ebbf6859ec246ec365c3b1f56f47c3a0a5d",
50
+ collateral_decimals=6,
51
+ collateral_asset_id="0x1",
52
+ starknet_domain=StarknetDomain(name="Perpetuals", version="v0", chain_id="SN_MAINNET", revision="1"),
53
+ )
54
+
55
+ """
56
+ Identical to the MAINNET_CONFIG, but with a different signing domain.
57
+ Use it for accounts that were created before the signing domain was changed.
58
+ """
59
+ MAINNET_CONFIG_LEGACY_SIGNING_DOMAIN = EndpointConfig(
60
+ chain_rpc_url="https://cloudflare-eth.com",
61
+ api_base_url="https://api.extended.exchange/api/v1",
62
+ stream_url="wss://api.extended.exchange/stream.extended.exchange/v1",
63
+ onboarding_url="https://api.extended.exchange",
64
+ signing_domain="x10.exchange",
65
+ collateral_asset_contract="0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
66
+ asset_operations_contract="0x1cE5D7f52A8aBd23551e91248151CA5A13353C65",
67
+ collateral_asset_on_chain_id="0x2893294412a4c8f915f75892b395ebbf6859ec246ec365c3b1f56f47c3a0a5d",
68
+ collateral_decimals=6,
69
+ collateral_asset_id="0x1",
70
+ starknet_domain=StarknetDomain(name="Perpetuals", version="v0", chain_id="SN_MAINNET", revision="1"),
71
+ )
72
+
73
+
74
+ STARKNET_TESTNET_CONFIG = EndpointConfig(
75
+ chain_rpc_url="https://rpc.sepolia.org",
76
+ api_base_url="https://api.starknet.sepolia.extended.exchange/api/v1",
77
+ stream_url="wss://api.starknet.sepolia.extended.exchange/stream.extended.exchange/v1",
78
+ onboarding_url="https://api.starknet.sepolia.extended.exchange",
79
+ signing_domain="starknet.sepolia.extended.exchange",
80
+ collateral_asset_contract="0x0C9165046063B7bCD05C6924Bbe05ed535c140a1",
81
+ asset_operations_contract="0xe42bb60Fab4EA4905832AEbDf0f001c784dA271b",
82
+ collateral_asset_on_chain_id="0x31857064564ed0ff978e687456963cba09c2c6985d8f9300a1de4962fafa054",
83
+ collateral_decimals=6,
84
+ starknet_domain=StarknetDomain(name="Perpetuals", version="v0", chain_id="SN_SEPOLIA", revision="1"),
85
+ collateral_asset_id="0x1",
86
+ )
x10/perpetual/fees.py ADDED
@@ -0,0 +1,16 @@
1
+ from decimal import Decimal
2
+
3
+ from x10.utils.model import X10BaseModel
4
+
5
+
6
+ class TradingFeeModel(X10BaseModel):
7
+ market: str
8
+ maker_fee_rate: Decimal
9
+ taker_fee_rate: Decimal
10
+
11
+
12
+ DEFAULT_FEES = TradingFeeModel(
13
+ market="BTC-USD",
14
+ maker_fee_rate=(Decimal("2") / Decimal("10000")),
15
+ taker_fee_rate=(Decimal("5") / Decimal("10000")),
16
+ )
@@ -0,0 +1,11 @@
1
+ from decimal import Decimal
2
+
3
+ from pydantic import AliasChoices, Field
4
+
5
+ from x10.utils.model import X10BaseModel
6
+
7
+
8
+ class FundingRateModel(X10BaseModel):
9
+ market: str = Field(validation_alias=AliasChoices("market", "m"), serialization_alias="m")
10
+ funding_rate: Decimal = Field(validation_alias=AliasChoices("funding_rate", "f"), serialization_alias="f")
11
+ timestamp: int = Field(validation_alias=AliasChoices("timestamp", "T"), serialization_alias="T")
@@ -0,0 +1,125 @@
1
+ from decimal import ROUND_CEILING, Decimal
2
+ from functools import cached_property
3
+ from typing import List
4
+
5
+ from x10.perpetual.assets import Asset
6
+ from x10.utils.model import X10BaseModel
7
+
8
+
9
+ class RiskFactorConfig(X10BaseModel):
10
+ upper_bound: Decimal
11
+ risk_factor: Decimal
12
+
13
+ @cached_property
14
+ def max_leverage(self) -> Decimal:
15
+ return round(Decimal(1) / self.risk_factor, 2)
16
+
17
+
18
+ class MarketStatsModel(X10BaseModel):
19
+ daily_volume: Decimal
20
+ daily_volume_base: Decimal
21
+ daily_price_change: Decimal
22
+ daily_low: Decimal
23
+ daily_high: Decimal
24
+ last_price: Decimal
25
+ ask_price: Decimal
26
+ bid_price: Decimal
27
+ mark_price: Decimal
28
+ index_price: Decimal
29
+ funding_rate: Decimal
30
+ next_funding_rate: int
31
+ open_interest: Decimal
32
+ open_interest_base: Decimal
33
+
34
+
35
+ class TradingConfigModel(X10BaseModel):
36
+ min_order_size: Decimal
37
+ min_order_size_change: Decimal
38
+ min_price_change: Decimal
39
+ max_market_order_value: Decimal
40
+ max_limit_order_value: Decimal
41
+ max_position_value: Decimal
42
+ max_leverage: Decimal
43
+ max_num_orders: int
44
+ limit_price_cap: Decimal
45
+ limit_price_floor: Decimal
46
+ risk_factor_config: List[RiskFactorConfig]
47
+
48
+ @cached_property
49
+ def price_precision(self) -> int:
50
+ return abs(int(self.min_price_change.log10().to_integral_exact(ROUND_CEILING)))
51
+
52
+ @cached_property
53
+ def quantity_precision(self) -> int:
54
+ return abs(int(self.min_order_size_change.log10().to_integral_exact(ROUND_CEILING)))
55
+
56
+ def max_leverage_for_position_value(self, position_value: Decimal) -> Decimal:
57
+ filtered = [x for x in self.risk_factor_config if x.upper_bound >= position_value]
58
+ return filtered[0].max_leverage if filtered else Decimal(0)
59
+
60
+ def max_position_value_for_leverage(self, leverage: Decimal) -> Decimal:
61
+ filtered = [x for x in self.risk_factor_config if x.max_leverage >= leverage]
62
+ return filtered[-1].upper_bound if filtered else Decimal(0)
63
+
64
+ def round_order_size(self, order_size: Decimal, rounding_direction: str = ROUND_CEILING) -> Decimal:
65
+ order_size = (order_size / self.min_order_size_change).to_integral_exact(
66
+ rounding_direction
67
+ ) * self.min_order_size_change
68
+ return order_size
69
+
70
+ def calculate_order_size_from_value(
71
+ self, order_value: Decimal, order_price: Decimal, rounding_direction: str = ROUND_CEILING
72
+ ) -> Decimal:
73
+ order_size = order_value / order_price
74
+ if order_size > 0:
75
+ return self.round_order_size(order_size, rounding_direction=rounding_direction)
76
+ else:
77
+ return Decimal(0)
78
+
79
+
80
+ class L2ConfigModel(X10BaseModel):
81
+ type: str
82
+ collateral_id: str
83
+ collateral_resolution: int
84
+ synthetic_id: str
85
+ synthetic_resolution: int
86
+
87
+
88
+ class MarketModel(X10BaseModel):
89
+ name: str
90
+ asset_name: str
91
+ asset_precision: int
92
+ collateral_asset_name: str
93
+ collateral_asset_precision: int
94
+ active: bool
95
+ market_stats: MarketStatsModel
96
+ trading_config: TradingConfigModel
97
+ l2_config: L2ConfigModel
98
+
99
+ @cached_property
100
+ def synthetic_asset(self) -> Asset:
101
+ return Asset(
102
+ id=1,
103
+ name=self.asset_name,
104
+ precision=self.asset_precision,
105
+ active=self.active,
106
+ is_collateral=False,
107
+ settlement_external_id=self.l2_config.synthetic_id,
108
+ settlement_resolution=self.l2_config.synthetic_resolution,
109
+ l1_external_id="",
110
+ l1_resolution=0,
111
+ )
112
+
113
+ @cached_property
114
+ def collateral_asset(self) -> Asset:
115
+ return Asset(
116
+ id=2,
117
+ name=self.collateral_asset_name,
118
+ precision=self.collateral_asset_precision,
119
+ active=self.active,
120
+ is_collateral=True,
121
+ settlement_external_id=self.l2_config.collateral_id,
122
+ settlement_resolution=self.l2_config.collateral_resolution,
123
+ l1_external_id="",
124
+ l1_resolution=0,
125
+ )