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.
Files changed (58) hide show
  1. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/CHANGELOG.md +22 -0
  2. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/PKG-INFO +20 -4
  3. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/README.md +19 -3
  4. afp_sdk-0.4.0/afp/.ruff_cache/.gitignore +2 -0
  5. afp_sdk-0.4.0/afp/.ruff_cache/0.12.7/14089225400260942471 +0 -0
  6. afp_sdk-0.4.0/afp/.ruff_cache/CACHEDIR.TAG +1 -0
  7. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/api/builder.py +0 -4
  8. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/api/trading.py +6 -2
  9. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/bindings/bankruptcy_facet.py +36 -0
  10. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/bindings/clearing_facet.py +28 -0
  11. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/bindings/final_settlement_facet.py +54 -0
  12. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/bindings/margin_account.py +108 -0
  13. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/bindings/product_registry.py +1 -48
  14. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/bindings/system_viewer.py +1 -7
  15. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/config.py +8 -7
  16. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/exchange.py +15 -4
  17. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/schemas.py +0 -1
  18. afp_sdk-0.4.0/examples/.ruff_cache/.gitignore +2 -0
  19. afp_sdk-0.4.0/examples/.ruff_cache/0.12.7/15954160080383381829 +0 -0
  20. afp_sdk-0.4.0/examples/.ruff_cache/CACHEDIR.TAG +1 -0
  21. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/pyproject.toml +1 -1
  22. afp_sdk-0.4.0/tests/test_exchange_client.py +24 -0
  23. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/uv.lock +1 -1
  24. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/.env.template +0 -0
  25. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/.envrc +0 -0
  26. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/LICENSE +0 -0
  27. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/__init__.py +0 -0
  28. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/api/__init__.py +0 -0
  29. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/api/admin.py +0 -0
  30. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/api/base.py +0 -0
  31. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/api/clearing.py +0 -0
  32. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/api/liquidation.py +0 -0
  33. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/bindings/__init__.py +0 -0
  34. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/bindings/auctioneer_facet.py +0 -0
  35. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/bindings/erc20.py +0 -0
  36. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/bindings/facade.py +0 -0
  37. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/bindings/margin_account_registry.py +0 -0
  38. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/bindings/mark_price_tracker_facet.py +0 -0
  39. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/bindings/oracle_provider.py +0 -0
  40. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/bindings/trading_protocol.py +0 -0
  41. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/decorators.py +0 -0
  42. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/enums.py +0 -0
  43. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/exceptions.py +0 -0
  44. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/py.typed +0 -0
  45. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/signing.py +0 -0
  46. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/afp/validators.py +0 -0
  47. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/devenv.lock +0 -0
  48. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/devenv.nix +0 -0
  49. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/devenv.yaml +0 -0
  50. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/examples/cancel_order.py +0 -0
  51. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/examples/create_product.py +0 -0
  52. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/examples/execute_trade.py +0 -0
  53. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/tests/__init__.py +0 -0
  54. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/tests/test_decorators.py +0 -0
  55. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/tests/test_hashing.py +0 -0
  56. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/tests/test_login.py +0 -0
  57. {afp_sdk-0.2.2 → afp_sdk-0.4.0}/tests/test_schemas.py +0 -0
  58. {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.2.2
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 use the AFP system, traders need to prepare the following:
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&testnets=true).
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 use the AFP system, traders need to prepare the following:
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&testnets=true).
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.
@@ -0,0 +1,2 @@
1
+ # Automatically created by ruff.
2
+ *
@@ -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
- int(return_value[12]),
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
- int(return_value_elem[12]),
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-staging.up.railway.app"
14
+ "AFP_EXCHANGE_URL", "https://afp-exchange-stable.up.railway.app"
14
15
  )
15
16
 
16
- CHAIN_ID = int(os.getenv("AFP_CHAIN_ID", 65010004))
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", "0xB894bFf368Bf1EA89c18612670B7E072866a5264"
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
- "0xDA71FdE0E7cfFf445e848EAdB3B2255B68Ed6ef6",
27
+ "0x99f4FA9Cdce7AD227eB84907936a8FeF2095D846",
27
28
  )
28
29
  )
29
30
  ORACLE_PROVIDER_ADDRESS = Web3.to_checksum_address(
30
31
  os.getenv(
31
- "AFP_ORACLE_PROVIDER_ADDRESS", "0x626da921088a5A00C75C208Decbb60E816488481"
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", "0x9b92EAC112c996a513e515Cf8c3BDd83619F730D"
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", "0xcB3F71Db710544283a1FfB38FE1bEC554d0634A5")
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("GET", "/orders")
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, method: str, endpoint: str, stream: bool = False, **kwargs: Any
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, f"{config.EXCHANGE_URL}{endpoint}", stream=stream, **kwargs
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
@@ -0,0 +1,2 @@
1
+ # Automatically created by ruff.
2
+ *
@@ -0,0 +1 @@
1
+ Signature: 8a477f597d28d172789f06886806bc55
@@ -4,7 +4,7 @@ build-backend = "uv_build"
4
4
 
5
5
  [project]
6
6
  name = "afp-sdk"
7
- version = "0.2.2"
7
+ version = "0.4.0"
8
8
  description = "Autonomous Futures Protocol Python SDK"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -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"
@@ -13,7 +13,7 @@ wheels = [
13
13
 
14
14
  [[package]]
15
15
  name = "afp-sdk"
16
- version = "0.2.2"
16
+ version = "0.4.0"
17
17
  source = { editable = "." }
18
18
  dependencies = [
19
19
  { name = "decorator" },
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