afp-sdk 0.2.2__tar.gz → 0.4.0__tar.gz
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_sdk-0.2.2 → afp_sdk-0.4.0}/CHANGELOG.md +22 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/PKG-INFO +20 -4
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/README.md +19 -3
- afp_sdk-0.4.0/afp/.ruff_cache/.gitignore +2 -0
- afp_sdk-0.4.0/afp/.ruff_cache/0.12.7/14089225400260942471 +0 -0
- afp_sdk-0.4.0/afp/.ruff_cache/CACHEDIR.TAG +1 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/api/builder.py +0 -4
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/api/trading.py +6 -2
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/bindings/bankruptcy_facet.py +36 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/bindings/clearing_facet.py +28 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/bindings/final_settlement_facet.py +54 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/bindings/margin_account.py +108 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/bindings/product_registry.py +1 -48
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/bindings/system_viewer.py +1 -7
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/config.py +8 -7
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/exchange.py +15 -4
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/schemas.py +0 -1
- afp_sdk-0.4.0/examples/.ruff_cache/.gitignore +2 -0
- afp_sdk-0.4.0/examples/.ruff_cache/0.12.7/15954160080383381829 +0 -0
- afp_sdk-0.4.0/examples/.ruff_cache/CACHEDIR.TAG +1 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/pyproject.toml +1 -1
- afp_sdk-0.4.0/tests/test_exchange_client.py +24 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/uv.lock +1 -1
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/.env.template +0 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/.envrc +0 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/LICENSE +0 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/__init__.py +0 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/api/__init__.py +0 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/api/admin.py +0 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/api/base.py +0 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/api/clearing.py +0 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/api/liquidation.py +0 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/bindings/__init__.py +0 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/bindings/auctioneer_facet.py +0 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/bindings/erc20.py +0 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/bindings/facade.py +0 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/bindings/margin_account_registry.py +0 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/bindings/mark_price_tracker_facet.py +0 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/bindings/oracle_provider.py +0 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/bindings/trading_protocol.py +0 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/decorators.py +0 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/enums.py +0 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/exceptions.py +0 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/py.typed +0 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/signing.py +0 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/validators.py +0 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/devenv.lock +0 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/devenv.nix +0 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/devenv.yaml +0 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/examples/cancel_order.py +0 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/examples/create_product.py +0 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/examples/execute_trade.py +0 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/tests/__init__.py +0 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/tests/test_decorators.py +0 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/tests/test_hashing.py +0 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/tests/test_login.py +0 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/tests/test_schemas.py +0 -0
- {afp_sdk-0.2.2 → afp_sdk-0.4.0}/tests/test_validators.py +0 -0
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
## [v0.4.0] - 2025-09-17
|
|
2
|
+
|
|
3
|
+
### Added
|
|
4
|
+
|
|
5
|
+
- Add `product_id` parameter to `Trading.open_orders()` for filtering orders by product ([#21](https://github.com/autonity/afp-sdk/pull/21))
|
|
6
|
+
|
|
7
|
+
### Removed
|
|
8
|
+
|
|
9
|
+
- Remove the `offer_price_buffer` product parameter from `Builder.create_product()` ([#23](https://github.com/autonity/afp-sdk/pull/23))
|
|
10
|
+
|
|
11
|
+
## [v0.3.0] - 2025-09-05
|
|
12
|
+
|
|
13
|
+
_First public release for Forecastathon._
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- Update the interface with the AutEx exchange ([#17](https://github.com/autonity/afp-sdk/pull/17))
|
|
18
|
+
- Update the contract bindings ([#18](https://github.com/autonity/afp-sdk/pull/18))
|
|
19
|
+
- Update Clearing System parameters for Autonity Mainnet ([#19](https://github.com/autonity/afp-sdk/pull/19))
|
|
20
|
+
|
|
1
21
|
## [v0.2.2] - 2025-09-03
|
|
2
22
|
|
|
3
23
|
### Added
|
|
@@ -45,6 +65,8 @@
|
|
|
45
65
|
|
|
46
66
|
_First release._
|
|
47
67
|
|
|
68
|
+
[v0.4.0]: https://github.com/autonity/afp-sdk/releases/tag/v0.4.0
|
|
69
|
+
[v0.3.0]: https://github.com/autonity/afp-sdk/releases/tag/v0.3.0
|
|
48
70
|
[v0.2.2]: https://github.com/autonity/afp-sdk/releases/tag/v0.2.2
|
|
49
71
|
[v0.2.1]: https://github.com/autonity/afp-sdk/releases/tag/v0.2.1
|
|
50
72
|
[v0.2.0]: https://github.com/autonity/afp-sdk/releases/tag/v0.2.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: afp-sdk
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Autonomous Futures Protocol Python SDK
|
|
5
5
|
Keywords: autonity,web3,trading,crypto,prediction,forecast,markets
|
|
6
6
|
License-Expression: MIT
|
|
@@ -38,7 +38,7 @@ pip install afp-sdk
|
|
|
38
38
|
|
|
39
39
|
The `afp` package consists of the following:
|
|
40
40
|
|
|
41
|
-
- `afp` top-level module: High-level API for interacting with the Clearing
|
|
41
|
+
- `afp` top-level module: High-level API for interacting with the AFP Clearing
|
|
42
42
|
System and the AutEx exchange.
|
|
43
43
|
- `afp.bindings` submodule: Low-level API that provides typed Python bindings
|
|
44
44
|
for the Clearing System smart contracts.
|
|
@@ -47,7 +47,7 @@ The `afp` package consists of the following:
|
|
|
47
47
|
|
|
48
48
|
### Preparation
|
|
49
49
|
|
|
50
|
-
In order to
|
|
50
|
+
In order to trade in the AFP system, traders need to prepare the following:
|
|
51
51
|
|
|
52
52
|
- The ID of a product to be traded.
|
|
53
53
|
- The address of the product's collateral token.
|
|
@@ -55,7 +55,7 @@ In order to use the AFP system, traders need to prepare the following:
|
|
|
55
55
|
balance in ATN (for paying gas fee) and in the product's collateral token.
|
|
56
56
|
- An Autonity account for signing intents. The two accounts can be the same.
|
|
57
57
|
- The address of an Autonity RPC provider. They can be found on
|
|
58
|
-
[Chainlist](https://chainlist.org/?search=autonity
|
|
58
|
+
[Chainlist](https://chainlist.org/?search=autonity).
|
|
59
59
|
|
|
60
60
|
We can store those in the following constants (using random example IDs):
|
|
61
61
|
|
|
@@ -169,6 +169,22 @@ print(fills)
|
|
|
169
169
|
|
|
170
170
|
See further code examples in the [examples](./examples/) directory.
|
|
171
171
|
|
|
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
|
+
|
|
172
188
|
## Development
|
|
173
189
|
|
|
174
190
|
The package uses [`uv`](https://docs.astral.sh/uv/) as project manager.
|
|
@@ -13,7 +13,7 @@ pip install afp-sdk
|
|
|
13
13
|
|
|
14
14
|
The `afp` package consists of the following:
|
|
15
15
|
|
|
16
|
-
- `afp` top-level module: High-level API for interacting with the Clearing
|
|
16
|
+
- `afp` top-level module: High-level API for interacting with the AFP Clearing
|
|
17
17
|
System and the AutEx exchange.
|
|
18
18
|
- `afp.bindings` submodule: Low-level API that provides typed Python bindings
|
|
19
19
|
for the Clearing System smart contracts.
|
|
@@ -22,7 +22,7 @@ The `afp` package consists of the following:
|
|
|
22
22
|
|
|
23
23
|
### Preparation
|
|
24
24
|
|
|
25
|
-
In order to
|
|
25
|
+
In order to trade in the AFP system, traders need to prepare the following:
|
|
26
26
|
|
|
27
27
|
- The ID of a product to be traded.
|
|
28
28
|
- The address of the product's collateral token.
|
|
@@ -30,7 +30,7 @@ In order to use the AFP system, traders need to prepare the following:
|
|
|
30
30
|
balance in ATN (for paying gas fee) and in the product's collateral token.
|
|
31
31
|
- An Autonity account for signing intents. The two accounts can be the same.
|
|
32
32
|
- The address of an Autonity RPC provider. They can be found on
|
|
33
|
-
[Chainlist](https://chainlist.org/?search=autonity
|
|
33
|
+
[Chainlist](https://chainlist.org/?search=autonity).
|
|
34
34
|
|
|
35
35
|
We can store those in the following constants (using random example IDs):
|
|
36
36
|
|
|
@@ -144,6 +144,22 @@ print(fills)
|
|
|
144
144
|
|
|
145
145
|
See further code examples in the [examples](./examples/) directory.
|
|
146
146
|
|
|
147
|
+
## Configuration
|
|
148
|
+
|
|
149
|
+
By default the SDK communicates with the AFP Clearing System contracts on
|
|
150
|
+
Autonity Mainnet, and the AutEx Exchange. Connection parameters can be
|
|
151
|
+
overridden with the following environment variables:
|
|
152
|
+
|
|
153
|
+
```sh
|
|
154
|
+
AFP_EXCHANGE_URL=
|
|
155
|
+
AFP_CHAIN_ID=
|
|
156
|
+
AFP_CLEARING_DIAMOND_ADDRESS=
|
|
157
|
+
AFP_MARGIN_ACCOUNT_REGISTRY_ADDRESS=
|
|
158
|
+
AFP_ORACLE_PROVIDER_ADDRESS=
|
|
159
|
+
AFP_PRODUCT_REGISTRY_ADDRESS=
|
|
160
|
+
AFP_SYSTEM_VIEWER_ADDRESS=
|
|
161
|
+
```
|
|
162
|
+
|
|
147
163
|
## Development
|
|
148
164
|
|
|
149
165
|
The package uses [`uv`](https://docs.astral.sh/uv/) as project manager.
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Signature: 8a477f597d28d172789f06886806bc55
|
|
@@ -50,7 +50,6 @@ class Builder(ClearingSystemAPI):
|
|
|
50
50
|
unit_value: Decimal,
|
|
51
51
|
initial_margin_requirement: Decimal,
|
|
52
52
|
maintenance_margin_requirement: Decimal,
|
|
53
|
-
offer_price_buffer: Decimal,
|
|
54
53
|
auction_bounty: Decimal,
|
|
55
54
|
tradeout_interval: int,
|
|
56
55
|
extended_metadata: str,
|
|
@@ -76,7 +75,6 @@ class Builder(ClearingSystemAPI):
|
|
|
76
75
|
unit_value : Decimal
|
|
77
76
|
initial_margin_requirement : Decimal
|
|
78
77
|
maintenance_margin_requirement : Decimal
|
|
79
|
-
offer_price_buffer : Decimal
|
|
80
78
|
auction_bounty : Decimal
|
|
81
79
|
tradeout_interval : int
|
|
82
80
|
extended_metadata : str
|
|
@@ -114,7 +112,6 @@ class Builder(ClearingSystemAPI):
|
|
|
114
112
|
unit_value=unit_value,
|
|
115
113
|
initial_margin_requirement=initial_margin_requirement,
|
|
116
114
|
maintenance_margin_requirement=maintenance_margin_requirement,
|
|
117
|
-
offer_price_buffer=offer_price_buffer,
|
|
118
115
|
auction_bounty=auction_bounty,
|
|
119
116
|
tradeout_interval=tradeout_interval,
|
|
120
117
|
extended_metadata=extended_metadata,
|
|
@@ -194,7 +191,6 @@ class Builder(ClearingSystemAPI):
|
|
|
194
191
|
maintenance_margin_requirement=int(
|
|
195
192
|
product.maintenance_margin_requirement * config.RATE_MULTIPLIER
|
|
196
193
|
),
|
|
197
|
-
offer_price_buffer=int(product.offer_price_buffer * config.RATE_MULTIPLIER),
|
|
198
194
|
auction_bounty=int(product.auction_bounty * config.RATE_MULTIPLIER),
|
|
199
195
|
tradeout_interval=product.tradeout_interval,
|
|
200
196
|
extended_metadata=product.extended_metadata,
|
|
@@ -226,15 +226,19 @@ class Trading(ExchangeAPI):
|
|
|
226
226
|
return self._exchange.get_order_by_id(value)
|
|
227
227
|
|
|
228
228
|
@refresh_token_on_expiry
|
|
229
|
-
def open_orders(self) -> list[Order]:
|
|
229
|
+
def open_orders(self, product_id: str | None = None) -> list[Order]:
|
|
230
230
|
"""Retrieves all open and partially filled limit orders that have been submitted
|
|
231
231
|
by the authenticated account.
|
|
232
232
|
|
|
233
|
+
Parameters
|
|
234
|
+
----------
|
|
235
|
+
product_id : str, optional
|
|
236
|
+
|
|
233
237
|
Returns
|
|
234
238
|
-------
|
|
235
239
|
list of afp.schemas.Order
|
|
236
240
|
"""
|
|
237
|
-
return self._exchange.get_open_orders()
|
|
241
|
+
return self._exchange.get_open_orders(product_id)
|
|
238
242
|
|
|
239
243
|
@refresh_token_on_expiry
|
|
240
244
|
def order_fills(
|
|
@@ -56,6 +56,11 @@ class BankruptcyFacet:
|
|
|
56
56
|
abi=ABI,
|
|
57
57
|
)
|
|
58
58
|
|
|
59
|
+
@property
|
|
60
|
+
def LossMutualized(self) -> contract.ContractEvent:
|
|
61
|
+
"""Binding for `event LossMutualized` on the BankruptcyFacet contract."""
|
|
62
|
+
return self._contract.events.LossMutualized
|
|
63
|
+
|
|
59
64
|
def last_traded_timestamp(
|
|
60
65
|
self,
|
|
61
66
|
product_id: hexbytes.HexBytes,
|
|
@@ -219,6 +224,37 @@ ABI = typing.cast(
|
|
|
219
224
|
"type": "error",
|
|
220
225
|
},
|
|
221
226
|
{"inputs": [], "name": "QueueIsEmpty", "type": "error"},
|
|
227
|
+
{
|
|
228
|
+
"anonymous": False,
|
|
229
|
+
"inputs": [
|
|
230
|
+
{
|
|
231
|
+
"indexed": True,
|
|
232
|
+
"internalType": "address",
|
|
233
|
+
"name": "bankruptAccount",
|
|
234
|
+
"type": "address",
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
"indexed": True,
|
|
238
|
+
"internalType": "address",
|
|
239
|
+
"name": "collateralToken",
|
|
240
|
+
"type": "address",
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
"indexed": False,
|
|
244
|
+
"internalType": "address",
|
|
245
|
+
"name": "caller",
|
|
246
|
+
"type": "address",
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
"indexed": False,
|
|
250
|
+
"internalType": "int256",
|
|
251
|
+
"name": "lossAmount",
|
|
252
|
+
"type": "int256",
|
|
253
|
+
},
|
|
254
|
+
],
|
|
255
|
+
"name": "LossMutualized",
|
|
256
|
+
"type": "event",
|
|
257
|
+
},
|
|
222
258
|
{
|
|
223
259
|
"inputs": [
|
|
224
260
|
{"internalType": "bytes32", "name": "productId", "type": "bytes32"},
|
|
@@ -423,6 +423,25 @@ class ClearingFacet:
|
|
|
423
423
|
),
|
|
424
424
|
)
|
|
425
425
|
|
|
426
|
+
def set_treasury(
|
|
427
|
+
self,
|
|
428
|
+
new_treasury: eth_typing.ChecksumAddress,
|
|
429
|
+
) -> contract.ContractFunction:
|
|
430
|
+
"""Binding for `setTreasury` on the ClearingFacet contract.
|
|
431
|
+
|
|
432
|
+
Parameters
|
|
433
|
+
----------
|
|
434
|
+
new_treasury : eth_typing.ChecksumAddress
|
|
435
|
+
|
|
436
|
+
Returns
|
|
437
|
+
-------
|
|
438
|
+
web3.contract.contract.ContractFunction
|
|
439
|
+
A contract function instance to be sent in a transaction.
|
|
440
|
+
"""
|
|
441
|
+
return self._contract.functions.setTreasury(
|
|
442
|
+
new_treasury,
|
|
443
|
+
)
|
|
444
|
+
|
|
426
445
|
def version(
|
|
427
446
|
self,
|
|
428
447
|
) -> str:
|
|
@@ -1003,6 +1022,15 @@ ABI = typing.cast(
|
|
|
1003
1022
|
"stateMutability": "nonpayable",
|
|
1004
1023
|
"type": "function",
|
|
1005
1024
|
},
|
|
1025
|
+
{
|
|
1026
|
+
"inputs": [
|
|
1027
|
+
{"internalType": "address", "name": "newTreasury", "type": "address"}
|
|
1028
|
+
],
|
|
1029
|
+
"name": "setTreasury",
|
|
1030
|
+
"outputs": [],
|
|
1031
|
+
"stateMutability": "nonpayable",
|
|
1032
|
+
"type": "function",
|
|
1033
|
+
},
|
|
1006
1034
|
{
|
|
1007
1035
|
"inputs": [],
|
|
1008
1036
|
"name": "version",
|
|
@@ -32,6 +32,16 @@ class FinalSettlementFacet:
|
|
|
32
32
|
abi=ABI,
|
|
33
33
|
)
|
|
34
34
|
|
|
35
|
+
@property
|
|
36
|
+
def FSPFinalized(self) -> contract.ContractEvent:
|
|
37
|
+
"""Binding for `event FSPFinalized` on the FinalSettlementFacet contract."""
|
|
38
|
+
return self._contract.events.FSPFinalized
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def FinalSettlementCloseout(self) -> contract.ContractEvent:
|
|
42
|
+
"""Binding for `event FinalSettlementCloseout` on the FinalSettlementFacet contract."""
|
|
43
|
+
return self._contract.events.FinalSettlementCloseout
|
|
44
|
+
|
|
35
45
|
def closeout_fee_rate(
|
|
36
46
|
self,
|
|
37
47
|
) -> int:
|
|
@@ -210,6 +220,50 @@ ABI = typing.cast(
|
|
|
210
220
|
"name": "ProductNotInFinalSettlement",
|
|
211
221
|
"type": "error",
|
|
212
222
|
},
|
|
223
|
+
{
|
|
224
|
+
"anonymous": False,
|
|
225
|
+
"inputs": [
|
|
226
|
+
{
|
|
227
|
+
"indexed": True,
|
|
228
|
+
"internalType": "bytes32",
|
|
229
|
+
"name": "productID",
|
|
230
|
+
"type": "bytes32",
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
"indexed": False,
|
|
234
|
+
"internalType": "uint256",
|
|
235
|
+
"name": "fsp",
|
|
236
|
+
"type": "uint256",
|
|
237
|
+
},
|
|
238
|
+
],
|
|
239
|
+
"name": "FSPFinalized",
|
|
240
|
+
"type": "event",
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
"anonymous": False,
|
|
244
|
+
"inputs": [
|
|
245
|
+
{
|
|
246
|
+
"indexed": True,
|
|
247
|
+
"internalType": "bytes32",
|
|
248
|
+
"name": "productID",
|
|
249
|
+
"type": "bytes32",
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
"indexed": False,
|
|
253
|
+
"internalType": "uint256",
|
|
254
|
+
"name": "accountLength",
|
|
255
|
+
"type": "uint256",
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
"indexed": False,
|
|
259
|
+
"internalType": "address",
|
|
260
|
+
"name": "closedBy",
|
|
261
|
+
"type": "address",
|
|
262
|
+
},
|
|
263
|
+
],
|
|
264
|
+
"name": "FinalSettlementCloseout",
|
|
265
|
+
"type": "event",
|
|
266
|
+
},
|
|
213
267
|
{
|
|
214
268
|
"inputs": [],
|
|
215
269
|
"name": "CLOSEOUT_FEE_RATE",
|
|
@@ -53,6 +53,11 @@ class MarginAccount:
|
|
|
53
53
|
abi=ABI,
|
|
54
54
|
)
|
|
55
55
|
|
|
56
|
+
@property
|
|
57
|
+
def Deposit(self) -> contract.ContractEvent:
|
|
58
|
+
"""Binding for `event Deposit` on the MarginAccount contract."""
|
|
59
|
+
return self._contract.events.Deposit
|
|
60
|
+
|
|
56
61
|
@property
|
|
57
62
|
def FeeCollected(self) -> contract.ContractEvent:
|
|
58
63
|
"""Binding for `event FeeCollected` on the MarginAccount contract."""
|
|
@@ -68,11 +73,26 @@ class MarginAccount:
|
|
|
68
73
|
"""Binding for `event Initialized` on the MarginAccount contract."""
|
|
69
74
|
return self._contract.events.Initialized
|
|
70
75
|
|
|
76
|
+
@property
|
|
77
|
+
def IntentAuthorized(self) -> contract.ContractEvent:
|
|
78
|
+
"""Binding for `event IntentAuthorized` on the MarginAccount contract."""
|
|
79
|
+
return self._contract.events.IntentAuthorized
|
|
80
|
+
|
|
81
|
+
@property
|
|
82
|
+
def IntentRevoked(self) -> contract.ContractEvent:
|
|
83
|
+
"""Binding for `event IntentRevoked` on the MarginAccount contract."""
|
|
84
|
+
return self._contract.events.IntentRevoked
|
|
85
|
+
|
|
71
86
|
@property
|
|
72
87
|
def PositionUpdated(self) -> contract.ContractEvent:
|
|
73
88
|
"""Binding for `event PositionUpdated` on the MarginAccount contract."""
|
|
74
89
|
return self._contract.events.PositionUpdated
|
|
75
90
|
|
|
91
|
+
@property
|
|
92
|
+
def Withdraw(self) -> contract.ContractEvent:
|
|
93
|
+
"""Binding for `event Withdraw` on the MarginAccount contract."""
|
|
94
|
+
return self._contract.events.Withdraw
|
|
95
|
+
|
|
76
96
|
def authorize(
|
|
77
97
|
self,
|
|
78
98
|
intent_account: eth_typing.ChecksumAddress,
|
|
@@ -789,6 +809,25 @@ ABI = typing.cast(
|
|
|
789
809
|
"name": "Unauthorized",
|
|
790
810
|
"type": "error",
|
|
791
811
|
},
|
|
812
|
+
{
|
|
813
|
+
"anonymous": False,
|
|
814
|
+
"inputs": [
|
|
815
|
+
{
|
|
816
|
+
"indexed": True,
|
|
817
|
+
"internalType": "address",
|
|
818
|
+
"name": "user",
|
|
819
|
+
"type": "address",
|
|
820
|
+
},
|
|
821
|
+
{
|
|
822
|
+
"indexed": False,
|
|
823
|
+
"internalType": "uint256",
|
|
824
|
+
"name": "amount",
|
|
825
|
+
"type": "uint256",
|
|
826
|
+
},
|
|
827
|
+
],
|
|
828
|
+
"name": "Deposit",
|
|
829
|
+
"type": "event",
|
|
830
|
+
},
|
|
792
831
|
{
|
|
793
832
|
"anonymous": False,
|
|
794
833
|
"inputs": [
|
|
@@ -840,6 +879,44 @@ ABI = typing.cast(
|
|
|
840
879
|
"name": "Initialized",
|
|
841
880
|
"type": "event",
|
|
842
881
|
},
|
|
882
|
+
{
|
|
883
|
+
"anonymous": False,
|
|
884
|
+
"inputs": [
|
|
885
|
+
{
|
|
886
|
+
"indexed": True,
|
|
887
|
+
"internalType": "address",
|
|
888
|
+
"name": "marginAccountID",
|
|
889
|
+
"type": "address",
|
|
890
|
+
},
|
|
891
|
+
{
|
|
892
|
+
"indexed": True,
|
|
893
|
+
"internalType": "address",
|
|
894
|
+
"name": "intentAccount",
|
|
895
|
+
"type": "address",
|
|
896
|
+
},
|
|
897
|
+
],
|
|
898
|
+
"name": "IntentAuthorized",
|
|
899
|
+
"type": "event",
|
|
900
|
+
},
|
|
901
|
+
{
|
|
902
|
+
"anonymous": False,
|
|
903
|
+
"inputs": [
|
|
904
|
+
{
|
|
905
|
+
"indexed": True,
|
|
906
|
+
"internalType": "address",
|
|
907
|
+
"name": "marginAccountID",
|
|
908
|
+
"type": "address",
|
|
909
|
+
},
|
|
910
|
+
{
|
|
911
|
+
"indexed": True,
|
|
912
|
+
"internalType": "address",
|
|
913
|
+
"name": "intentAccount",
|
|
914
|
+
"type": "address",
|
|
915
|
+
},
|
|
916
|
+
],
|
|
917
|
+
"name": "IntentRevoked",
|
|
918
|
+
"type": "event",
|
|
919
|
+
},
|
|
843
920
|
{
|
|
844
921
|
"anonymous": False,
|
|
845
922
|
"inputs": [
|
|
@@ -867,10 +944,41 @@ ABI = typing.cast(
|
|
|
867
944
|
"name": "costBasis",
|
|
868
945
|
"type": "int256",
|
|
869
946
|
},
|
|
947
|
+
{
|
|
948
|
+
"indexed": False,
|
|
949
|
+
"internalType": "uint256",
|
|
950
|
+
"name": "price",
|
|
951
|
+
"type": "uint256",
|
|
952
|
+
},
|
|
953
|
+
{
|
|
954
|
+
"indexed": False,
|
|
955
|
+
"internalType": "int256",
|
|
956
|
+
"name": "quantity",
|
|
957
|
+
"type": "int256",
|
|
958
|
+
},
|
|
870
959
|
],
|
|
871
960
|
"name": "PositionUpdated",
|
|
872
961
|
"type": "event",
|
|
873
962
|
},
|
|
963
|
+
{
|
|
964
|
+
"anonymous": False,
|
|
965
|
+
"inputs": [
|
|
966
|
+
{
|
|
967
|
+
"indexed": True,
|
|
968
|
+
"internalType": "address",
|
|
969
|
+
"name": "user",
|
|
970
|
+
"type": "address",
|
|
971
|
+
},
|
|
972
|
+
{
|
|
973
|
+
"indexed": False,
|
|
974
|
+
"internalType": "uint256",
|
|
975
|
+
"name": "amount",
|
|
976
|
+
"type": "uint256",
|
|
977
|
+
},
|
|
978
|
+
],
|
|
979
|
+
"name": "Withdraw",
|
|
980
|
+
"type": "event",
|
|
981
|
+
},
|
|
874
982
|
{
|
|
875
983
|
"inputs": [
|
|
876
984
|
{"internalType": "address", "name": "intentAccount", "type": "address"}
|
|
@@ -56,7 +56,6 @@ class Product:
|
|
|
56
56
|
unit_value: int
|
|
57
57
|
initial_margin_requirement: int
|
|
58
58
|
maintenance_margin_requirement: int
|
|
59
|
-
offer_price_buffer: int
|
|
60
59
|
auction_bounty: int
|
|
61
60
|
tradeout_interval: int
|
|
62
61
|
tick_size: int
|
|
@@ -221,7 +220,6 @@ class ProductRegistry:
|
|
|
221
220
|
product.unit_value,
|
|
222
221
|
product.initial_margin_requirement,
|
|
223
222
|
product.maintenance_margin_requirement,
|
|
224
|
-
product.offer_price_buffer,
|
|
225
223
|
product.auction_bounty,
|
|
226
224
|
product.tradeout_interval,
|
|
227
225
|
product.tick_size,
|
|
@@ -280,25 +278,6 @@ class ProductRegistry:
|
|
|
280
278
|
).call()
|
|
281
279
|
return int(return_value)
|
|
282
280
|
|
|
283
|
-
def offer_price_buffer(
|
|
284
|
-
self,
|
|
285
|
-
product_id: hexbytes.HexBytes,
|
|
286
|
-
) -> int:
|
|
287
|
-
"""Binding for `offerPriceBuffer` on the ProductRegistry contract.
|
|
288
|
-
|
|
289
|
-
Parameters
|
|
290
|
-
----------
|
|
291
|
-
product_id : hexbytes.HexBytes
|
|
292
|
-
|
|
293
|
-
Returns
|
|
294
|
-
-------
|
|
295
|
-
int
|
|
296
|
-
"""
|
|
297
|
-
return_value = self._contract.functions.offerPriceBuffer(
|
|
298
|
-
product_id,
|
|
299
|
-
).call()
|
|
300
|
-
return int(return_value)
|
|
301
|
-
|
|
302
281
|
def oracle_specification(
|
|
303
282
|
self,
|
|
304
283
|
product_id: hexbytes.HexBytes,
|
|
@@ -395,8 +374,7 @@ class ProductRegistry:
|
|
|
395
374
|
int(return_value[9]),
|
|
396
375
|
int(return_value[10]),
|
|
397
376
|
int(return_value[11]),
|
|
398
|
-
|
|
399
|
-
str(return_value[13]),
|
|
377
|
+
str(return_value[12]),
|
|
400
378
|
)
|
|
401
379
|
|
|
402
380
|
def proxiable_uuid(
|
|
@@ -447,7 +425,6 @@ class ProductRegistry:
|
|
|
447
425
|
product.unit_value,
|
|
448
426
|
product.initial_margin_requirement,
|
|
449
427
|
product.maintenance_margin_requirement,
|
|
450
|
-
product.offer_price_buffer,
|
|
451
428
|
product.auction_bounty,
|
|
452
429
|
product.tradeout_interval,
|
|
453
430
|
product.tick_size,
|
|
@@ -856,11 +833,6 @@ ABI = typing.cast(
|
|
|
856
833
|
"name": "maintenanceMarginRequirement",
|
|
857
834
|
"type": "uint16",
|
|
858
835
|
},
|
|
859
|
-
{
|
|
860
|
-
"internalType": "uint64",
|
|
861
|
-
"name": "offerPriceBuffer",
|
|
862
|
-
"type": "uint64",
|
|
863
|
-
},
|
|
864
836
|
{
|
|
865
837
|
"internalType": "uint64",
|
|
866
838
|
"name": "auctionBounty",
|
|
@@ -913,15 +885,6 @@ ABI = typing.cast(
|
|
|
913
885
|
"stateMutability": "view",
|
|
914
886
|
"type": "function",
|
|
915
887
|
},
|
|
916
|
-
{
|
|
917
|
-
"inputs": [
|
|
918
|
-
{"internalType": "bytes32", "name": "productId", "type": "bytes32"}
|
|
919
|
-
],
|
|
920
|
-
"name": "offerPriceBuffer",
|
|
921
|
-
"outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}],
|
|
922
|
-
"stateMutability": "view",
|
|
923
|
-
"type": "function",
|
|
924
|
-
},
|
|
925
888
|
{
|
|
926
889
|
"inputs": [
|
|
927
890
|
{"internalType": "bytes32", "name": "productId", "type": "bytes32"}
|
|
@@ -1073,11 +1036,6 @@ ABI = typing.cast(
|
|
|
1073
1036
|
"name": "maintenanceMarginRequirement",
|
|
1074
1037
|
"type": "uint16",
|
|
1075
1038
|
},
|
|
1076
|
-
{
|
|
1077
|
-
"internalType": "uint64",
|
|
1078
|
-
"name": "offerPriceBuffer",
|
|
1079
|
-
"type": "uint64",
|
|
1080
|
-
},
|
|
1081
1039
|
{
|
|
1082
1040
|
"internalType": "uint64",
|
|
1083
1041
|
"name": "auctionBounty",
|
|
@@ -1203,11 +1161,6 @@ ABI = typing.cast(
|
|
|
1203
1161
|
"name": "maintenanceMarginRequirement",
|
|
1204
1162
|
"type": "uint16",
|
|
1205
1163
|
},
|
|
1206
|
-
{
|
|
1207
|
-
"internalType": "uint64",
|
|
1208
|
-
"name": "offerPriceBuffer",
|
|
1209
|
-
"type": "uint64",
|
|
1210
|
-
},
|
|
1211
1164
|
{
|
|
1212
1165
|
"internalType": "uint64",
|
|
1213
1166
|
"name": "auctionBounty",
|
|
@@ -324,8 +324,7 @@ class SystemViewer:
|
|
|
324
324
|
int(return_value_elem[9]),
|
|
325
325
|
int(return_value_elem[10]),
|
|
326
326
|
int(return_value_elem[11]),
|
|
327
|
-
|
|
328
|
-
str(return_value_elem[13]),
|
|
327
|
+
str(return_value_elem[12]),
|
|
329
328
|
)
|
|
330
329
|
for return_value_elem in return_value
|
|
331
330
|
]
|
|
@@ -929,11 +928,6 @@ ABI = typing.cast(
|
|
|
929
928
|
"name": "maintenanceMarginRequirement",
|
|
930
929
|
"type": "uint16",
|
|
931
930
|
},
|
|
932
|
-
{
|
|
933
|
-
"internalType": "uint64",
|
|
934
|
-
"name": "offerPriceBuffer",
|
|
935
|
-
"type": "uint64",
|
|
936
|
-
},
|
|
937
931
|
{
|
|
938
932
|
"internalType": "uint64",
|
|
939
933
|
"name": "auctionBounty",
|
|
@@ -9,33 +9,34 @@ FEE_RATE_MULTIPLIER = 10**6
|
|
|
9
9
|
FULL_PRECISION_MULTIPLIER = 10**18
|
|
10
10
|
|
|
11
11
|
USER_AGENT = "afp-sdk"
|
|
12
|
+
DEFAULT_EXCHANGE_API_VERSION = 1
|
|
12
13
|
EXCHANGE_URL = os.getenv(
|
|
13
|
-
"AFP_EXCHANGE_URL", "https://afp-exchange-
|
|
14
|
+
"AFP_EXCHANGE_URL", "https://afp-exchange-stable.up.railway.app"
|
|
14
15
|
)
|
|
15
16
|
|
|
16
|
-
CHAIN_ID = int(os.getenv("AFP_CHAIN_ID",
|
|
17
|
+
CHAIN_ID = int(os.getenv("AFP_CHAIN_ID", 65000000))
|
|
17
18
|
|
|
18
19
|
CLEARING_DIAMOND_ADDRESS = Web3.to_checksum_address(
|
|
19
20
|
os.getenv(
|
|
20
|
-
"AFP_CLEARING_DIAMOND_ADDRESS", "
|
|
21
|
+
"AFP_CLEARING_DIAMOND_ADDRESS", "0x5B5411F1548254d25360d71FE40cFc1cC983B2A2"
|
|
21
22
|
)
|
|
22
23
|
)
|
|
23
24
|
MARGIN_ACCOUNT_REGISTRY_ADDRESS = Web3.to_checksum_address(
|
|
24
25
|
os.getenv(
|
|
25
26
|
"AFP_MARGIN_ACCOUNT_REGISTRY_ADDRESS",
|
|
26
|
-
"
|
|
27
|
+
"0x99f4FA9Cdce7AD227eB84907936a8FeF2095D846",
|
|
27
28
|
)
|
|
28
29
|
)
|
|
29
30
|
ORACLE_PROVIDER_ADDRESS = Web3.to_checksum_address(
|
|
30
31
|
os.getenv(
|
|
31
|
-
"AFP_ORACLE_PROVIDER_ADDRESS", "
|
|
32
|
+
"AFP_ORACLE_PROVIDER_ADDRESS", "0xF2A2A27da33D30B4BF38D7e186E7B0b1e964e55c"
|
|
32
33
|
)
|
|
33
34
|
)
|
|
34
35
|
PRODUCT_REGISTRY_ADDRESS = Web3.to_checksum_address(
|
|
35
36
|
os.getenv(
|
|
36
|
-
"AFP_PRODUCT_REGISTRY_ADDRESS", "
|
|
37
|
+
"AFP_PRODUCT_REGISTRY_ADDRESS", "0x86B3829471929B115367DA0958f56A6AB844b08e"
|
|
37
38
|
)
|
|
38
39
|
)
|
|
39
40
|
SYSTEM_VIEWER_ADDRESS = Web3.to_checksum_address(
|
|
40
|
-
os.getenv("AFP_SYSTEM_VIEWER_ADDRESS", "
|
|
41
|
+
os.getenv("AFP_SYSTEM_VIEWER_ADDRESS", "0xfF2DFcC44a95cce96E03EfC33C65c8Be671Bae5B")
|
|
41
42
|
)
|
|
@@ -71,8 +71,10 @@ class ExchangeClient:
|
|
|
71
71
|
return Order(**response.json())
|
|
72
72
|
|
|
73
73
|
# GET /orders
|
|
74
|
-
def get_open_orders(self) -> list[Order]:
|
|
75
|
-
response = self._send_request(
|
|
74
|
+
def get_open_orders(self, product_id: str | None = None) -> list[Order]:
|
|
75
|
+
response = self._send_request(
|
|
76
|
+
"GET", "/orders", params=({"product_id": product_id} if product_id else {})
|
|
77
|
+
)
|
|
76
78
|
return [Order(**item) for item in response.json()["orders"]]
|
|
77
79
|
|
|
78
80
|
# GET /orders/{order_id}
|
|
@@ -116,7 +118,13 @@ class ExchangeClient:
|
|
|
116
118
|
yield MarketDepthData.model_validate_json(line)
|
|
117
119
|
|
|
118
120
|
def _send_request(
|
|
119
|
-
self,
|
|
121
|
+
self,
|
|
122
|
+
method: str,
|
|
123
|
+
endpoint: str,
|
|
124
|
+
*,
|
|
125
|
+
stream: bool = False,
|
|
126
|
+
api_version: int = config.DEFAULT_EXCHANGE_API_VERSION,
|
|
127
|
+
**kwargs: Any,
|
|
120
128
|
) -> Response:
|
|
121
129
|
kwargs["headers"] = {
|
|
122
130
|
"Content-Type": "application/json",
|
|
@@ -126,7 +134,10 @@ class ExchangeClient:
|
|
|
126
134
|
|
|
127
135
|
try:
|
|
128
136
|
response = self._session.request(
|
|
129
|
-
method,
|
|
137
|
+
method,
|
|
138
|
+
f"{config.EXCHANGE_URL}/v{api_version}{endpoint}",
|
|
139
|
+
stream=stream,
|
|
140
|
+
**kwargs,
|
|
130
141
|
)
|
|
131
142
|
except requests.exceptions.RequestException as request_exception:
|
|
132
143
|
raise ExchangeError(
|
|
@@ -184,7 +184,6 @@ class ProductSpecification(Model):
|
|
|
184
184
|
unit_value: Annotated[Decimal, Field(gt=0)]
|
|
185
185
|
initial_margin_requirement: Annotated[Decimal, Field(gt=0)]
|
|
186
186
|
maintenance_margin_requirement: Annotated[Decimal, Field(gt=0)]
|
|
187
|
-
offer_price_buffer: Annotated[Decimal, Field(ge=0, lt=1)]
|
|
188
187
|
auction_bounty: Annotated[Decimal, Field(ge=0, le=1)]
|
|
189
188
|
tradeout_interval: Annotated[int, Field(ge=0)]
|
|
190
189
|
extended_metadata: str
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Signature: 8a477f597d28d172789f06886806bc55
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from unittest.mock import Mock
|
|
2
|
+
|
|
3
|
+
from requests import Response
|
|
4
|
+
from requests.adapters import HTTPAdapter
|
|
5
|
+
|
|
6
|
+
from afp import config
|
|
7
|
+
from afp.exchange import ExchangeClient
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def test_send_request(monkeypatch):
|
|
11
|
+
fake_response = Response()
|
|
12
|
+
fake_response.status_code = 200
|
|
13
|
+
mock_send = Mock(return_value=fake_response)
|
|
14
|
+
monkeypatch.setattr(HTTPAdapter, "send", mock_send)
|
|
15
|
+
monkeypatch.setattr(config, "EXCHANGE_URL", "https://foobar.com")
|
|
16
|
+
|
|
17
|
+
client = ExchangeClient()
|
|
18
|
+
client._send_request("POST", "/orders", api_version=2, data="hello")
|
|
19
|
+
|
|
20
|
+
mock_send.assert_called_once()
|
|
21
|
+
request = mock_send.call_args_list[0].args[0]
|
|
22
|
+
assert request.method == "POST"
|
|
23
|
+
assert request.url == "https://foobar.com/v2/orders"
|
|
24
|
+
assert request.body == "hello"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|