afp-sdk 0.4.0__py3-none-any.whl → 0.5.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.
- afp/__init__.py +12 -7
- afp/afp.py +210 -0
- afp/api/admin.py +32 -18
- afp/api/base.py +82 -29
- afp/api/{clearing.py → margin_account.py} +172 -104
- afp/api/{builder.py → product.py} +136 -42
- afp/api/trading.py +12 -29
- afp/auth.py +66 -0
- afp/bindings/facade.py +25 -13
- afp/config.py +22 -36
- afp/constants.py +52 -0
- afp/decorators.py +3 -1
- afp/enums.py +6 -0
- afp/exceptions.py +7 -3
- afp/exchange.py +26 -11
- afp/{signing.py → hashing.py} +4 -12
- afp/schemas.py +23 -3
- afp/validators.py +1 -0
- {afp_sdk-0.4.0.dist-info → afp_sdk-0.5.1.dist-info}/METADATA +54 -50
- afp_sdk-0.5.1.dist-info/RECORD +37 -0
- {afp_sdk-0.4.0.dist-info → afp_sdk-0.5.1.dist-info}/WHEEL +1 -1
- afp/.ruff_cache/.gitignore +0 -2
- afp/.ruff_cache/0.12.7/14089225400260942471 +0 -0
- afp/.ruff_cache/CACHEDIR.TAG +0 -1
- afp/api/liquidation.py +0 -167
- afp_sdk-0.4.0.dist-info/RECORD +0 -38
- {afp_sdk-0.4.0.dist-info → afp_sdk-0.5.1.dist-info}/licenses/LICENSE +0 -0
afp/decorators.py
CHANGED
|
@@ -45,8 +45,10 @@ def convert_web3_error(*contract_abis: ABI) -> Callable[..., Any]:
|
|
|
45
45
|
)
|
|
46
46
|
if reason == "no data":
|
|
47
47
|
reason = "Unspecified reason"
|
|
48
|
+
if reason is None:
|
|
49
|
+
reason = "Unknown error"
|
|
48
50
|
raise ClearingSystemError(
|
|
49
|
-
"Contract call reverted" + f": {reason}" if reason else ""
|
|
51
|
+
"Contract call reverted" + (f": {reason}" if reason else "")
|
|
50
52
|
) from contract_error
|
|
51
53
|
except Web3RPCError as rpc_error:
|
|
52
54
|
reason = None
|
afp/enums.py
CHANGED
afp/exceptions.py
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
|
-
class
|
|
1
|
+
class AFPException(Exception):
|
|
2
2
|
pass
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
class
|
|
5
|
+
class ConfigurationError(AFPException):
|
|
6
6
|
pass
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
class
|
|
9
|
+
class ClearingSystemError(AFPException):
|
|
10
|
+
pass
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ExchangeError(AFPException):
|
|
10
14
|
pass
|
|
11
15
|
|
|
12
16
|
|
afp/exchange.py
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import json
|
|
2
|
+
import re
|
|
2
3
|
from typing import Any, Generator
|
|
3
4
|
|
|
4
5
|
import requests
|
|
5
6
|
from requests import Response, Session
|
|
6
7
|
|
|
7
|
-
from . import
|
|
8
|
+
from . import constants
|
|
8
9
|
from .exceptions import (
|
|
9
10
|
AuthenticationError,
|
|
10
11
|
AuthorizationError,
|
|
@@ -15,7 +16,8 @@ from .exceptions import (
|
|
|
15
16
|
from .schemas import (
|
|
16
17
|
ExchangeParameters,
|
|
17
18
|
ExchangeProduct,
|
|
18
|
-
|
|
19
|
+
ExchangeProductListingSubmission,
|
|
20
|
+
ExchangeProductUpdateSubmission,
|
|
19
21
|
LoginSubmission,
|
|
20
22
|
MarketDepthData,
|
|
21
23
|
Order,
|
|
@@ -26,11 +28,16 @@ from .schemas import (
|
|
|
26
28
|
|
|
27
29
|
|
|
28
30
|
class ExchangeClient:
|
|
31
|
+
_base_url: str
|
|
29
32
|
_session: Session
|
|
30
33
|
|
|
31
|
-
def __init__(self):
|
|
34
|
+
def __init__(self, base_url: str):
|
|
35
|
+
self._base_url = re.sub(r"/$", "", base_url)
|
|
32
36
|
self._session = Session()
|
|
33
37
|
|
|
38
|
+
def __repr__(self) -> str:
|
|
39
|
+
return f"{self.__class__.__name__}(base_url={self._base_url})"
|
|
40
|
+
|
|
34
41
|
# POST /nonce
|
|
35
42
|
def generate_login_nonce(self) -> str:
|
|
36
43
|
response = self._send_request("GET", "/nonce")
|
|
@@ -54,14 +61,22 @@ class ExchangeClient:
|
|
|
54
61
|
return ExchangeProduct(**response.json())
|
|
55
62
|
|
|
56
63
|
# POST /products
|
|
57
|
-
def
|
|
64
|
+
def list_product(
|
|
65
|
+
self, listing_submission: ExchangeProductListingSubmission
|
|
66
|
+
) -> None:
|
|
58
67
|
self._send_request(
|
|
59
|
-
"POST", "/products", data=
|
|
68
|
+
"POST", "/products", data=listing_submission.model_dump_json()
|
|
60
69
|
)
|
|
61
70
|
|
|
62
|
-
#
|
|
63
|
-
def
|
|
64
|
-
self
|
|
71
|
+
# PATCH /products
|
|
72
|
+
def update_product_listing(
|
|
73
|
+
self, product_id: str, update_submission: ExchangeProductUpdateSubmission
|
|
74
|
+
) -> None:
|
|
75
|
+
self._send_request(
|
|
76
|
+
"PATCH",
|
|
77
|
+
f"/products/{product_id}",
|
|
78
|
+
data=update_submission.model_dump_json(),
|
|
79
|
+
)
|
|
65
80
|
|
|
66
81
|
# POST /orders
|
|
67
82
|
def submit_order(self, order_submission: OrderSubmission) -> Order:
|
|
@@ -123,19 +138,19 @@ class ExchangeClient:
|
|
|
123
138
|
endpoint: str,
|
|
124
139
|
*,
|
|
125
140
|
stream: bool = False,
|
|
126
|
-
api_version: int =
|
|
141
|
+
api_version: int = constants.DEFAULT_EXCHANGE_API_VERSION,
|
|
127
142
|
**kwargs: Any,
|
|
128
143
|
) -> Response:
|
|
129
144
|
kwargs["headers"] = {
|
|
130
145
|
"Content-Type": "application/json",
|
|
131
146
|
"Accept": "application/x-ndjson" if stream else "application/json",
|
|
132
|
-
"User-Agent":
|
|
147
|
+
"User-Agent": constants.USER_AGENT,
|
|
133
148
|
}
|
|
134
149
|
|
|
135
150
|
try:
|
|
136
151
|
response = self._session.request(
|
|
137
152
|
method,
|
|
138
|
-
f"{
|
|
153
|
+
f"{self._base_url}/v{api_version}{endpoint}",
|
|
139
154
|
stream=stream,
|
|
140
155
|
**kwargs,
|
|
141
156
|
)
|
afp/{signing.py → hashing.py}
RENAMED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
from typing import Any, cast
|
|
2
2
|
|
|
3
3
|
from eth_abi.packed import encode_packed
|
|
4
|
-
from eth_account import messages
|
|
5
4
|
from eth_typing.evm import ChecksumAddress
|
|
6
|
-
from eth_account.signers.local import LocalAccount
|
|
7
5
|
from hexbytes import HexBytes
|
|
8
6
|
from web3 import Web3
|
|
9
7
|
|
|
10
|
-
from . import
|
|
8
|
+
from . import constants
|
|
11
9
|
from .bindings import clearing_facet
|
|
12
10
|
from .schemas import IntentData, OrderSide
|
|
13
11
|
|
|
@@ -44,7 +42,7 @@ def generate_intent_hash(
|
|
|
44
42
|
HexBytes(intent_data.product_id),
|
|
45
43
|
int(intent_data.limit_price * 10**tick_size),
|
|
46
44
|
intent_data.quantity,
|
|
47
|
-
int(intent_data.max_trading_fee_rate *
|
|
45
|
+
int(intent_data.max_trading_fee_rate * constants.FEE_RATE_MULTIPLIER),
|
|
48
46
|
int(intent_data.good_until_time.timestamp()),
|
|
49
47
|
ORDER_SIDE_MAPPING[intent_data.side],
|
|
50
48
|
]
|
|
@@ -57,13 +55,7 @@ def generate_order_cancellation_hash(nonce: int, intent_hash: str) -> HexBytes:
|
|
|
57
55
|
return Web3.keccak(encode_packed(types, values))
|
|
58
56
|
|
|
59
57
|
|
|
60
|
-
def generate_product_id(
|
|
58
|
+
def generate_product_id(builder_address: ChecksumAddress, symbol: str) -> HexBytes:
|
|
61
59
|
types = ["address", "string"]
|
|
62
|
-
values: list[Any] = [
|
|
60
|
+
values: list[Any] = [builder_address, symbol]
|
|
63
61
|
return Web3.keccak(encode_packed(types, values))
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
def sign_message(account: LocalAccount, message: bytes) -> HexBytes:
|
|
67
|
-
eip191_message = messages.encode_defunct(message)
|
|
68
|
-
signed_message = account.sign_message(eip191_message)
|
|
69
|
-
return signed_message.signature
|
afp/schemas.py
CHANGED
|
@@ -15,7 +15,7 @@ from pydantic import (
|
|
|
15
15
|
)
|
|
16
16
|
|
|
17
17
|
from . import validators
|
|
18
|
-
from .enums import OrderSide, OrderState, OrderType, TradeState
|
|
18
|
+
from .enums import ListingState, OrderSide, OrderState, OrderType, TradeState
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
# Use datetime internally but UNIX timestamp in client-server communication
|
|
@@ -53,18 +53,29 @@ class ExchangeParameters(Model):
|
|
|
53
53
|
trading_fee_rate: Decimal
|
|
54
54
|
|
|
55
55
|
|
|
56
|
-
#
|
|
56
|
+
# Admin API
|
|
57
57
|
|
|
58
58
|
|
|
59
|
-
class
|
|
59
|
+
class ExchangeProductListingSubmission(Model):
|
|
60
60
|
id: Annotated[str, AfterValidator(validators.validate_hexstr32)]
|
|
61
61
|
|
|
62
62
|
|
|
63
|
+
class ExchangeProductUpdateSubmission(Model):
|
|
64
|
+
listing_state: ListingState
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
# Trading API
|
|
68
|
+
|
|
69
|
+
|
|
63
70
|
class ExchangeProduct(Model):
|
|
64
71
|
id: str
|
|
65
72
|
symbol: str
|
|
66
73
|
tick_size: int
|
|
67
74
|
collateral_asset: str
|
|
75
|
+
listing_state: ListingState
|
|
76
|
+
|
|
77
|
+
def __str__(self) -> str:
|
|
78
|
+
return self.id
|
|
68
79
|
|
|
69
80
|
|
|
70
81
|
class IntentData(Model):
|
|
@@ -152,6 +163,12 @@ class MarketDepthData(Model):
|
|
|
152
163
|
# Clearing API
|
|
153
164
|
|
|
154
165
|
|
|
166
|
+
class Transaction(Model):
|
|
167
|
+
hash: str
|
|
168
|
+
data: dict[str, Any]
|
|
169
|
+
receipt: dict[str, Any]
|
|
170
|
+
|
|
171
|
+
|
|
155
172
|
class Position(Model):
|
|
156
173
|
id: str
|
|
157
174
|
quantity: int
|
|
@@ -188,6 +205,9 @@ class ProductSpecification(Model):
|
|
|
188
205
|
tradeout_interval: Annotated[int, Field(ge=0)]
|
|
189
206
|
extended_metadata: str
|
|
190
207
|
|
|
208
|
+
def __str__(self) -> str:
|
|
209
|
+
return self.id
|
|
210
|
+
|
|
191
211
|
|
|
192
212
|
# Liquidation API
|
|
193
213
|
|
afp/validators.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: afp-sdk
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.1
|
|
4
4
|
Summary: Autonomous Futures Protocol Python SDK
|
|
5
5
|
Keywords: autonity,web3,trading,crypto,prediction,forecast,markets
|
|
6
6
|
License-Expression: MIT
|
|
@@ -25,6 +25,10 @@ Description-Content-Type: text/markdown
|
|
|
25
25
|
|
|
26
26
|
# Autonomous Futures Protocol Python SDK
|
|
27
27
|
|
|
28
|
+
Decentralized clearing and creation of Forecast Futures on any timeseries.
|
|
29
|
+
|
|
30
|
+

|
|
31
|
+
|
|
28
32
|
## Installation
|
|
29
33
|
|
|
30
34
|
This library is published on PyPI as the [afp-sdk](https://pypi.org/project/afp-sdk/)
|
|
@@ -34,6 +38,11 @@ package. It can be installed in a virtualenv with:
|
|
|
34
38
|
pip install afp-sdk
|
|
35
39
|
```
|
|
36
40
|
|
|
41
|
+
## Documentation
|
|
42
|
+
|
|
43
|
+
See [afp.autonity.org](https://afp.autonity.org/) for the Autonomous Futures Protocol
|
|
44
|
+
documentation, including the Python SDK reference.
|
|
45
|
+
|
|
37
46
|
## Overview
|
|
38
47
|
|
|
39
48
|
The `afp` package consists of the following:
|
|
@@ -43,6 +52,13 @@ The `afp` package consists of the following:
|
|
|
43
52
|
- `afp.bindings` submodule: Low-level API that provides typed Python bindings
|
|
44
53
|
for the Clearing System smart contracts.
|
|
45
54
|
|
|
55
|
+
## Configuration
|
|
56
|
+
|
|
57
|
+
By default the SDK communicates with the AFP Clearing System contracts on
|
|
58
|
+
Autonity Mainnet, and the AutEx Exchange. Connection parameters can be
|
|
59
|
+
overridden via the `afp.AFP` constructor and environment variables; see the
|
|
60
|
+
documentation of the `afp.AFP` class for the available parameters.
|
|
61
|
+
|
|
46
62
|
## Usage
|
|
47
63
|
|
|
48
64
|
### Preparation
|
|
@@ -53,7 +69,8 @@ In order to trade in the AFP system, traders need to prepare the following:
|
|
|
53
69
|
- The address of the product's collateral token.
|
|
54
70
|
- An Autonity account for managing the margin account. It needs to hold a
|
|
55
71
|
balance in ATN (for paying gas fee) and in the product's collateral token.
|
|
56
|
-
- An Autonity account for signing intents
|
|
72
|
+
- An Autonity account for signing intents and submitting trades to the
|
|
73
|
+
exchange. The two accounts can be the same.
|
|
57
74
|
- The address of an Autonity RPC provider. They can be found on
|
|
58
75
|
[Chainlist](https://chainlist.org/?search=autonity).
|
|
59
76
|
|
|
@@ -64,57 +81,60 @@ import os
|
|
|
64
81
|
|
|
65
82
|
PRODUCT_ID = "0x38d502bb683f53ec7c3d7a14b4aa47ac717659e121426131c0189c15bf4b9460"
|
|
66
83
|
COLLATERAL_ASSET = "0xD1A1e4035a164cF42228A8aAaBC2c0Ac9e49687B"
|
|
67
|
-
|
|
68
|
-
INTENT_ACCOUNT_PRIVATE_KEY = os.environ["INTENT_ACCOUNT_PRIVATE_KEY"]
|
|
84
|
+
PRIVATE_KEY = os.environ["PRIVATE_KEY"]
|
|
69
85
|
AUTONITY_RPC_URL = "https://bakerloo.autonity-apis.com"
|
|
70
86
|
```
|
|
71
87
|
|
|
72
|
-
|
|
88
|
+
### Configuration
|
|
73
89
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
MARGIN_ACCOUNT_ID = Account.from_key(MARGIN_ACCOUNT_PRIVATE_KEY).address
|
|
78
|
-
INTENT_ACCOUNT_ID = Account.from_key(INTENT_ACCOUNT_PRIVATE_KEY).address
|
|
79
|
-
```
|
|
90
|
+
An application instance can be created with the `afp.AFP()` constructor. An instance
|
|
91
|
+
is associated with a trading venue and a margin account.
|
|
80
92
|
|
|
81
|
-
|
|
93
|
+
The required constructor arguments are the RPC provider URL and the authenticator of
|
|
94
|
+
the blockchain account that manages the margin account.
|
|
82
95
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
96
|
+
An "authenticator" is a service that implements the `afp.Authenticator` protocol.
|
|
97
|
+
Available options are `afp.PrivateKeyAuthenticator` that reads the private key
|
|
98
|
+
from a constructor argument, and `afp.KeyfileAuthenticator` that reads the private
|
|
99
|
+
key from an encrypted keyfile.
|
|
86
100
|
|
|
87
101
|
```py
|
|
88
102
|
import afp
|
|
89
103
|
|
|
90
|
-
|
|
104
|
+
app = afp.AFP(
|
|
105
|
+
rpc_url=AUTONITY_RPC_URL,
|
|
106
|
+
authenticator=afp.PrivateKeyAuthenticator(PRIVATE_KEY),
|
|
107
|
+
)
|
|
91
108
|
```
|
|
92
109
|
|
|
93
|
-
|
|
94
|
-
`clearing.deposit_into_margin_account()`.
|
|
110
|
+
### Margin Account API
|
|
95
111
|
|
|
96
|
-
|
|
97
|
-
|
|
112
|
+
Margin accounts can be managed via the `MarginAccount` session object. It
|
|
113
|
+
connects to the specified Autonity RPC provider and communicates with the
|
|
114
|
+
Clearing System smart contracts.
|
|
98
115
|
|
|
99
|
-
|
|
100
|
-
|
|
116
|
+
```py
|
|
117
|
+
margin_account = app.MarginAccount()
|
|
101
118
|
```
|
|
102
119
|
|
|
103
|
-
|
|
104
|
-
if the intent account and the margin account are different.
|
|
120
|
+
Collateral can be deposited into the margin account with `margin_account.deposit()`.
|
|
105
121
|
|
|
106
122
|
```py
|
|
107
|
-
|
|
123
|
+
from decimal import Decimal
|
|
124
|
+
|
|
125
|
+
margin_account.deposit(COLLATERAL_ASSET, Decimal("100.00"))
|
|
126
|
+
print(margin_account.capital(COLLATERAL_ASSET))
|
|
108
127
|
```
|
|
109
128
|
|
|
110
129
|
### Trading API
|
|
111
130
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
131
|
+
Functions of the trading API can be accessed via the `Trading` session object.
|
|
132
|
+
It communicates with the AutEx exchange and authenticates on creation with the
|
|
133
|
+
intent account's private key. The intent account authenticator is optional, it
|
|
134
|
+
defaults to the authenticator set in the `AFP` constructor.
|
|
115
135
|
|
|
116
136
|
```py
|
|
117
|
-
trading =
|
|
137
|
+
trading = app.Trading()
|
|
118
138
|
```
|
|
119
139
|
|
|
120
140
|
To start trading a product, its parameters shall be retrieved from the server.
|
|
@@ -169,28 +189,12 @@ print(fills)
|
|
|
169
189
|
|
|
170
190
|
See further code examples in the [examples](./examples/) directory.
|
|
171
191
|
|
|
172
|
-
## Configuration
|
|
173
|
-
|
|
174
|
-
By default the SDK communicates with the AFP Clearing System contracts on
|
|
175
|
-
Autonity Mainnet, and the AutEx Exchange. Connection parameters can be
|
|
176
|
-
overridden with the following environment variables:
|
|
177
|
-
|
|
178
|
-
```sh
|
|
179
|
-
AFP_EXCHANGE_URL=
|
|
180
|
-
AFP_CHAIN_ID=
|
|
181
|
-
AFP_CLEARING_DIAMOND_ADDRESS=
|
|
182
|
-
AFP_MARGIN_ACCOUNT_REGISTRY_ADDRESS=
|
|
183
|
-
AFP_ORACLE_PROVIDER_ADDRESS=
|
|
184
|
-
AFP_PRODUCT_REGISTRY_ADDRESS=
|
|
185
|
-
AFP_SYSTEM_VIEWER_ADDRESS=
|
|
186
|
-
```
|
|
187
|
-
|
|
188
192
|
## Development
|
|
189
193
|
|
|
190
194
|
The package uses [`uv`](https://docs.astral.sh/uv/) as project manager.
|
|
191
195
|
|
|
192
|
-
-
|
|
193
|
-
-
|
|
194
|
-
-
|
|
195
|
-
-
|
|
196
|
-
-
|
|
196
|
+
- Install dependencies with the `uv sync` command.
|
|
197
|
+
- Execute linters with the `uv run poe lint` command.
|
|
198
|
+
- Run tests with the `uv run poe test` command.
|
|
199
|
+
- Check distributions before release with the `uv run poe check-dist` command.
|
|
200
|
+
- Generate markdown API documentation with the `uv run poe doc-gen` command.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
afp/__init__.py,sha256=tvvXz4miC3QI8wy4vjAAf_LtL-19eEgBRA6dnrh3LA8,349
|
|
2
|
+
afp/afp.py,sha256=1xpocnWjALP6QlA-Hn7G2znttJ-ikcb2WA9sLueY3zc,9107
|
|
3
|
+
afp/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
afp/api/admin.py,sha256=6TiWCo0SB41CtXYTkTYYGQY7MrdB6OMTyU3-0J0V_7o,2170
|
|
5
|
+
afp/api/base.py,sha256=5X1joEwFX4gxYUDCSTvp_hSFCfLZCktnW-UtZFxDquk,4471
|
|
6
|
+
afp/api/margin_account.py,sha256=sC1DF7J3QTHR7cXcRjTG33oZswVy6qr9xnevQbrQ-ew,15256
|
|
7
|
+
afp/api/product.py,sha256=2N4bPBahuw19GcBbBL20oQ5RFRuUxa5LOZzmN7hs39U,10156
|
|
8
|
+
afp/api/trading.py,sha256=exQQ3LJA6XCbRAUBuYVjSJ5PHFi4COyqDORxC37LLfQ,10379
|
|
9
|
+
afp/auth.py,sha256=sV_9E6CgRWV1xYoppc4IdrnqNo5ZNDBIp6QF3fQbMWE,2055
|
|
10
|
+
afp/bindings/__init__.py,sha256=_n9xoogYi8AAlSx_PE-wjnwP1ujVyDUwoRM0BSm243U,1271
|
|
11
|
+
afp/bindings/auctioneer_facet.py,sha256=4p906zdU2lUsqpWlsiLE3dlxTPrlNpqk8DtjiQUWJ8M,23919
|
|
12
|
+
afp/bindings/bankruptcy_facet.py,sha256=-Kp4Ap5PLAmo_tFrp-1s_yAh0mtHS20z3BC5YIrVjrU,12548
|
|
13
|
+
afp/bindings/clearing_facet.py,sha256=cfyDo-s9_DesbK1Oe-8rfbTCS3HBX9X-L6HbzSydEFk,34898
|
|
14
|
+
afp/bindings/erc20.py,sha256=-jw7ohcEbUL7g3PpK3-a5_7ClUDCDHt1bezm-w7exzo,10822
|
|
15
|
+
afp/bindings/facade.py,sha256=8IehHRqmt9xVe4OJLVAfedprv1fc6mLj7COOjpI_AwA,2588
|
|
16
|
+
afp/bindings/final_settlement_facet.py,sha256=1U5F3WFvf4GUml3gb90YF9RZK_xCwBsX2zRQ8sWSkR0,9470
|
|
17
|
+
afp/bindings/margin_account.py,sha256=hqvHpfM62SAEXSt__NZzAQGu9z7DnIa9LbSgHHkhsKE,45872
|
|
18
|
+
afp/bindings/margin_account_registry.py,sha256=mx9sAU6HuC09d-LAf9bzP57HPLa3M6qXpN7Lj-uiXSc,18800
|
|
19
|
+
afp/bindings/mark_price_tracker_facet.py,sha256=vnVsAmpts_2Sv9Jmx3JlON8X8FJd9D2jOFhqSwXIA7A,2830
|
|
20
|
+
afp/bindings/oracle_provider.py,sha256=CMpVAXdUuTP_W9ZE297B-m9MjuW90yCOhNLMVl3kCf0,15863
|
|
21
|
+
afp/bindings/product_registry.py,sha256=-_h786jzMCsaTqqnoxpmVgBkGf45eCUMthp_PkqrET0,42137
|
|
22
|
+
afp/bindings/system_viewer.py,sha256=0FivdhpfXMrBesXcHkfO9uELyr7GiRmGe36xS5sURGE,41094
|
|
23
|
+
afp/bindings/trading_protocol.py,sha256=ZloF3REbjFq9v0UGVsM0_Lk0EhfWJKdeJ0PzVEnyZo0,39573
|
|
24
|
+
afp/config.py,sha256=_WKywiuty8poE1A0v46uBe1JGpfCzRlxCPamKennfpE,699
|
|
25
|
+
afp/constants.py,sha256=XIph4R0Tx-BPw_NZJgWUtb7NdS9sYzEciFRSStm3VMs,1840
|
|
26
|
+
afp/decorators.py,sha256=SEUQtbgPGc4iVPtBQV2eiCejcDAVImmXcI0uPXFhtJA,2774
|
|
27
|
+
afp/enums.py,sha256=U5b_3RteMiVJozp4WYAKzUfPXI1RdJLEK19jAg-LN8Q,588
|
|
28
|
+
afp/exceptions.py,sha256=frdS-EH84K0fOf92RgRgNkTe3VII2m36XNCS8eyXLLM,390
|
|
29
|
+
afp/exchange.py,sha256=MXQ-RhcI76l6bA9_IDTUq0RQGfwxBisrRhl6eC_yH4I,5983
|
|
30
|
+
afp/hashing.py,sha256=gBCWN93-ydRPlgnnorSvDQlylcnglrAypRDb-1K-20I,1949
|
|
31
|
+
afp/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
32
|
+
afp/schemas.py,sha256=M6qr0GhCeT7KevzOso5dIhydYzaYx78Rs66IWdadJO8,5284
|
|
33
|
+
afp/validators.py,sha256=zQvPu3HDu6ADnEE72EJlS5hc1-xfru78Mzd74s1u_EM,1841
|
|
34
|
+
afp_sdk-0.5.1.dist-info/licenses/LICENSE,sha256=ZdaKItgc2ppfqta2OJV0oHpSJiK87PUxmUkUo-_0SB8,1065
|
|
35
|
+
afp_sdk-0.5.1.dist-info/WHEEL,sha256=lh7MMMfiuFQLQaR9J7pNBODdWf-aa5UOeuuDAol3xps,79
|
|
36
|
+
afp_sdk-0.5.1.dist-info/METADATA,sha256=RM6EyQq2W_ZlrkRtYcGf85pZg7S15poSNJq7CUEHz0w,6354
|
|
37
|
+
afp_sdk-0.5.1.dist-info/RECORD,,
|
afp/.ruff_cache/.gitignore
DELETED
|
Binary file
|
afp/.ruff_cache/CACHEDIR.TAG
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
Signature: 8a477f597d28d172789f06886806bc55
|
afp/api/liquidation.py
DELETED
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
from decimal import Decimal
|
|
2
|
-
from functools import cache
|
|
3
|
-
from typing import Iterable
|
|
4
|
-
|
|
5
|
-
from hexbytes import HexBytes
|
|
6
|
-
from web3 import Web3
|
|
7
|
-
|
|
8
|
-
from .. import validators
|
|
9
|
-
from ..bindings import (
|
|
10
|
-
BidData,
|
|
11
|
-
ClearingDiamond,
|
|
12
|
-
ProductRegistry,
|
|
13
|
-
Side as OnChainOrderSide,
|
|
14
|
-
)
|
|
15
|
-
from ..bindings.facade import CLEARING_DIAMOND_ABI
|
|
16
|
-
from ..bindings.product_registry import ABI as PRODUCT_REGISTRY_ABI
|
|
17
|
-
from ..decorators import convert_web3_error
|
|
18
|
-
from ..enums import OrderSide
|
|
19
|
-
from ..schemas import AuctionData, Bid
|
|
20
|
-
from .base import ClearingSystemAPI
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
class Liquidation(ClearingSystemAPI):
|
|
24
|
-
"""API for participating in liquidation auctions.
|
|
25
|
-
|
|
26
|
-
Parameters
|
|
27
|
-
----------
|
|
28
|
-
private_key : str
|
|
29
|
-
The private key of the blockchain account that participates in a liquidation
|
|
30
|
-
auction.
|
|
31
|
-
autonity_rpc_url : str
|
|
32
|
-
The URL of a JSON-RPC provider for Autonity. (HTTPS only.)
|
|
33
|
-
"""
|
|
34
|
-
|
|
35
|
-
@staticmethod
|
|
36
|
-
def create_bid(product_id: str, price: Decimal, quantity: int, side: str) -> Bid:
|
|
37
|
-
"""Create a bid to be submitted to a liquidation auction.
|
|
38
|
-
|
|
39
|
-
Parameters
|
|
40
|
-
----------
|
|
41
|
-
product_id : str
|
|
42
|
-
price: Decimal
|
|
43
|
-
quantity: int
|
|
44
|
-
side: str
|
|
45
|
-
|
|
46
|
-
Returns
|
|
47
|
-
-------
|
|
48
|
-
afp.schemas.Bid
|
|
49
|
-
"""
|
|
50
|
-
return Bid(
|
|
51
|
-
product_id=product_id,
|
|
52
|
-
price=price,
|
|
53
|
-
quantity=quantity,
|
|
54
|
-
side=getattr(OrderSide, side.upper()),
|
|
55
|
-
)
|
|
56
|
-
|
|
57
|
-
### Transactions ###
|
|
58
|
-
|
|
59
|
-
@convert_web3_error(CLEARING_DIAMOND_ABI)
|
|
60
|
-
def request_liquidation(self, margin_account_id: str, collateral_asset: str) -> str:
|
|
61
|
-
"""Request a liquidation auction to be started.
|
|
62
|
-
|
|
63
|
-
Parameters
|
|
64
|
-
----------
|
|
65
|
-
margin_account_id : str
|
|
66
|
-
The ID of the margin account to be liquidated.
|
|
67
|
-
collateral_asset : str
|
|
68
|
-
The address of the collateral token that the margin account is trading with.
|
|
69
|
-
|
|
70
|
-
Returns
|
|
71
|
-
-------
|
|
72
|
-
str
|
|
73
|
-
The hash of the transaction.
|
|
74
|
-
"""
|
|
75
|
-
margin_account_id = validators.validate_address(margin_account_id)
|
|
76
|
-
collateral_asset = validators.validate_address(collateral_asset)
|
|
77
|
-
|
|
78
|
-
clearing_contract = ClearingDiamond(self._w3)
|
|
79
|
-
tx_hash = clearing_contract.request_liquidation(
|
|
80
|
-
margin_account_id, collateral_asset
|
|
81
|
-
).transact()
|
|
82
|
-
self._w3.eth.wait_for_transaction_receipt(tx_hash)
|
|
83
|
-
return Web3.to_hex(tx_hash)
|
|
84
|
-
|
|
85
|
-
@convert_web3_error(CLEARING_DIAMOND_ABI, PRODUCT_REGISTRY_ABI)
|
|
86
|
-
def submit_bids(
|
|
87
|
-
self, margin_account_id: str, collateral_asset: str, bids: Iterable[Bid]
|
|
88
|
-
) -> str:
|
|
89
|
-
"""Submit bids to a liquidation auction.
|
|
90
|
-
|
|
91
|
-
Parameters
|
|
92
|
-
----------
|
|
93
|
-
margin_account_id : str
|
|
94
|
-
The ID of the margin account that is being liquidated.
|
|
95
|
-
collateral_asset : str
|
|
96
|
-
The address of the collateral token that the margin account is trading with.
|
|
97
|
-
bids: list of afp.schemas.Bid
|
|
98
|
-
|
|
99
|
-
Returns
|
|
100
|
-
-------
|
|
101
|
-
str
|
|
102
|
-
The hash of the transaction.
|
|
103
|
-
"""
|
|
104
|
-
margin_account_id = validators.validate_address(margin_account_id)
|
|
105
|
-
collateral_asset = validators.validate_address(collateral_asset)
|
|
106
|
-
|
|
107
|
-
converted_bids = [
|
|
108
|
-
BidData(
|
|
109
|
-
product_id=HexBytes(bid.product_id),
|
|
110
|
-
price=int(bid.price * 10 ** self._tick_size(bid.product_id)),
|
|
111
|
-
quantity=bid.quantity,
|
|
112
|
-
side=getattr(OnChainOrderSide, bid.side.name),
|
|
113
|
-
)
|
|
114
|
-
for bid in bids
|
|
115
|
-
]
|
|
116
|
-
|
|
117
|
-
clearing_contract = ClearingDiamond(self._w3)
|
|
118
|
-
tx_hash = clearing_contract.bid_auction(
|
|
119
|
-
margin_account_id, collateral_asset, converted_bids
|
|
120
|
-
).transact()
|
|
121
|
-
self._w3.eth.wait_for_transaction_receipt(tx_hash)
|
|
122
|
-
return Web3.to_hex(tx_hash)
|
|
123
|
-
|
|
124
|
-
### Views ###
|
|
125
|
-
|
|
126
|
-
@convert_web3_error(CLEARING_DIAMOND_ABI)
|
|
127
|
-
def auction_data(
|
|
128
|
-
self, margin_account_id: str, collateral_asset: str
|
|
129
|
-
) -> AuctionData:
|
|
130
|
-
"""Returns information on a liquidation auction.
|
|
131
|
-
|
|
132
|
-
Parameters
|
|
133
|
-
----------
|
|
134
|
-
margin_account_id : str
|
|
135
|
-
The ID of the margin account to be liquidated.
|
|
136
|
-
collateral_asset : str
|
|
137
|
-
The address of the collateral token that the margin account is trading with.
|
|
138
|
-
|
|
139
|
-
Returns
|
|
140
|
-
-------
|
|
141
|
-
str
|
|
142
|
-
The hash of the transaction.
|
|
143
|
-
"""
|
|
144
|
-
margin_account_id = validators.validate_address(margin_account_id)
|
|
145
|
-
collateral_asset = validators.validate_address(collateral_asset)
|
|
146
|
-
|
|
147
|
-
clearing_contract = ClearingDiamond(self._w3)
|
|
148
|
-
data = clearing_contract.auction_data(margin_account_id, collateral_asset)
|
|
149
|
-
divisor = 10 ** self._decimals(collateral_asset)
|
|
150
|
-
return AuctionData(
|
|
151
|
-
start_block=data.start_block,
|
|
152
|
-
margin_account_equity_at_initiation=(
|
|
153
|
-
Decimal(data.mae_at_initiation) / divisor
|
|
154
|
-
),
|
|
155
|
-
maintenance_margin_used_at_initiation=(
|
|
156
|
-
Decimal(data.mmu_at_initiation) / divisor
|
|
157
|
-
),
|
|
158
|
-
margin_account_equity_now=(Decimal(data.mae_now) / divisor),
|
|
159
|
-
maintenance_margin_used_now=(Decimal(data.mmu_now) / divisor),
|
|
160
|
-
)
|
|
161
|
-
|
|
162
|
-
### Internal getters ###
|
|
163
|
-
|
|
164
|
-
@cache
|
|
165
|
-
def _tick_size(self, product_id: str) -> int:
|
|
166
|
-
product_registry_contract = ProductRegistry(self._w3)
|
|
167
|
-
return product_registry_contract.tick_size(HexBytes(product_id))
|