afp-sdk 0.5.4__py3-none-any.whl → 0.6.0__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 (49) hide show
  1. afp/__init__.py +4 -1
  2. afp/afp.py +11 -0
  3. afp/api/admin.py +1 -1
  4. afp/api/base.py +11 -2
  5. afp/api/margin_account.py +12 -148
  6. afp/api/product.py +302 -148
  7. afp/api/trading.py +10 -19
  8. afp/auth.py +14 -0
  9. afp/bindings/__init__.py +30 -16
  10. afp/bindings/admin_facet.py +890 -0
  11. afp/bindings/clearing_facet.py +356 -773
  12. afp/bindings/facade.py +9 -6
  13. afp/bindings/final_settlement_facet.py +258 -99
  14. afp/bindings/margin_account.py +524 -839
  15. afp/bindings/margin_account_facet.py +722 -0
  16. afp/bindings/margin_account_registry.py +184 -310
  17. afp/bindings/mark_price_tracker_facet.py +74 -16
  18. afp/bindings/product_registry.py +1577 -541
  19. afp/bindings/product_registry_facet.py +1467 -0
  20. afp/bindings/system_viewer.py +592 -369
  21. afp/bindings/types.py +223 -0
  22. afp/config.py +4 -0
  23. afp/constants.py +49 -6
  24. afp/decorators.py +25 -3
  25. afp/dtos.py +142 -0
  26. afp/exceptions.py +10 -0
  27. afp/exchange.py +10 -8
  28. afp/hashing.py +7 -5
  29. afp/ipfs.py +245 -0
  30. afp/json-schemas/bafyreiaw34o6l3rmatabzbds2i2myazdw2yolevcpsoyd2i2g3ms7wa2eq.json +1 -0
  31. afp/json-schemas/bafyreibnfg6nq74dvpkre5rakkccij7iadp5rxpim7omsatjnrpmj3y7v4.json +1 -0
  32. afp/json-schemas/bafyreicgr6dfo5yduixjkcifghiulskfegwojvuwodtouvivl362zndhxe.json +1 -0
  33. afp/json-schemas/bafyreicheoypx6synljushh7mq2572iyhlolf4nake2p5dwobgnj3r5eua.json +1 -0
  34. afp/json-schemas/bafyreid35a67db4sqh4fs6boddyt2xvscbqy6nqvsp5jjur56qhkw4ixre.json +1 -0
  35. afp/json-schemas/bafyreidzs7okcpqiss6ztftltyptqwnw5e5opsy5yntospekjha4kpykaa.json +1 -0
  36. afp/json-schemas/bafyreifcec2km7hxwq6oqzjlspni2mgipetjb7pqtaewh2efislzoctboi.json +1 -0
  37. afp/json-schemas/bafyreihn3oiaxffe4e2w7pwtreadpw3obfd7gqlogbcxm56jc2hzfvco74.json +1 -0
  38. afp/json-schemas/bafyreihur3dzwhja6uxsbcw6eeoj3xmmc4e3zkmyzpot5v5dleevxe5zam.json +1 -0
  39. afp/schemas.py +227 -177
  40. afp/types.py +169 -0
  41. afp/validators.py +218 -8
  42. {afp_sdk-0.5.4.dist-info → afp_sdk-0.6.0.dist-info}/METADATA +73 -10
  43. afp_sdk-0.6.0.dist-info/RECORD +50 -0
  44. afp/bindings/auctioneer_facet.py +0 -752
  45. afp/bindings/bankruptcy_facet.py +0 -391
  46. afp/bindings/trading_protocol.py +0 -1158
  47. afp_sdk-0.5.4.dist-info/RECORD +0 -37
  48. {afp_sdk-0.5.4.dist-info → afp_sdk-0.6.0.dist-info}/WHEEL +0 -0
  49. {afp_sdk-0.5.4.dist-info → afp_sdk-0.6.0.dist-info}/licenses/LICENSE +0 -0
afp/bindings/types.py ADDED
@@ -0,0 +1,223 @@
1
+ import enum
2
+ import typing
3
+ from dataclasses import dataclass
4
+
5
+ import eth_typing
6
+ import hexbytes
7
+
8
+
9
+ class Side(enum.IntEnum):
10
+ """Port of `enum Side` on the ClearingFacet contract."""
11
+
12
+ BID = 0
13
+ ASK = 1
14
+
15
+
16
+ class ProductState(enum.IntEnum):
17
+ """Port of `enum ProductState` on the ProductRegistry contract."""
18
+
19
+ NOT_EXIST = 0
20
+ PENDING = 1
21
+ LIVE = 2
22
+ TRADEOUT = 3
23
+ FINAL_SETTLEMENT = 4
24
+ EXPIRED = 5
25
+
26
+
27
+ @dataclass
28
+ class ClearingConfig:
29
+ """Port of `struct ClearingConfig` on the AdminFacet contract."""
30
+
31
+ clearing_fee_rate: int
32
+ max_trading_fee_rate: int
33
+
34
+
35
+ @dataclass
36
+ class MarkPriceConfig:
37
+ """Port of `struct MarkPriceConfig` on the AdminFacet contract."""
38
+
39
+ mark_price_interval: int
40
+
41
+
42
+ @dataclass
43
+ class FinalSettlementConfig:
44
+ """Port of `struct FinalSettlementConfig` on the AdminFacet contract."""
45
+
46
+ closeout_fee_rate: int
47
+ closeout_reward_rate: int
48
+
49
+
50
+ @dataclass
51
+ class ProductConfig:
52
+ """Port of `struct ProductConfig` on the AdminFacet contract."""
53
+
54
+ clearing_payout_ratio: int
55
+ maintenance_deposit_interval: int
56
+ min_product_maintenance_fee: int
57
+
58
+
59
+ @dataclass
60
+ class Config:
61
+ """Port of `struct Config` on the AdminFacet contract."""
62
+
63
+ clearing_config: ClearingConfig
64
+ mark_price_config: MarkPriceConfig
65
+ final_settlement_config: FinalSettlementConfig
66
+ product_config: ProductConfig
67
+
68
+
69
+ @dataclass
70
+ class IntentData:
71
+ """Port of `struct IntentData` on the ClearingFacet contract."""
72
+
73
+ nonce: int
74
+ trading_protocol_id: eth_typing.ChecksumAddress
75
+ product_id: hexbytes.HexBytes
76
+ limit_price: int
77
+ quantity: int
78
+ max_trading_fee_rate: int
79
+ good_until: int
80
+ side: Side
81
+ referral: eth_typing.ChecksumAddress
82
+
83
+
84
+ @dataclass
85
+ class Intent:
86
+ """Port of `struct Intent` on the ClearingFacet contract."""
87
+
88
+ margin_account_id: eth_typing.ChecksumAddress
89
+ intent_account_id: eth_typing.ChecksumAddress
90
+ hash: hexbytes.HexBytes
91
+ data: IntentData
92
+ signature: hexbytes.HexBytes
93
+
94
+
95
+ @dataclass
96
+ class Trade:
97
+ """Port of `struct Trade` on the ClearingFacet contract."""
98
+
99
+ product_id: hexbytes.HexBytes
100
+ protocol_id: eth_typing.ChecksumAddress
101
+ trade_id: int
102
+ price: int
103
+ timestamp: int
104
+ quantity: int
105
+ accounts: typing.List[eth_typing.ChecksumAddress]
106
+ quantities: typing.List[int]
107
+ fee_rates: typing.List[int]
108
+ intents: typing.List[Intent]
109
+
110
+
111
+ @dataclass
112
+ class Settlement:
113
+ """Port of `struct Settlement` on the MarginAccountFacet contract."""
114
+
115
+ product_id: hexbytes.HexBytes
116
+ quantity: int
117
+ price: int
118
+
119
+
120
+ @dataclass
121
+ class MarginData:
122
+ """Port of `struct MarginData` on the IMarginAccountFacet contract."""
123
+
124
+ capital: int
125
+ mae: int
126
+ mmu: int
127
+ pnl: int
128
+
129
+
130
+ @dataclass
131
+ class PositionData:
132
+ """Port of `struct PositionData` on the MarginAccountFacet contract."""
133
+
134
+ product_id: hexbytes.HexBytes
135
+ quantity: int
136
+ cost_basis: int
137
+ maintenance_margin: int
138
+ pnl: int
139
+
140
+
141
+ @dataclass
142
+ class ExpirySpecification:
143
+ """Port of `struct ExpirySpecification` on the ProductRegistryFacet contract."""
144
+
145
+ earliest_fsp_submission_time: int
146
+ tradeout_interval: int
147
+
148
+
149
+ @dataclass
150
+ class PendingStakeData:
151
+ """Port of `struct PendingStakeData` on the ProductRegistry contract."""
152
+
153
+ payout: int
154
+ active_at: int
155
+
156
+
157
+ @dataclass
158
+ class BuilderStakeData:
159
+ """Port of `struct BuilderStakeData` on the ProductRegistry contract."""
160
+
161
+ payout_remaining: int
162
+ claimable_rewards: int
163
+ pending_stake_data: PendingStakeData
164
+
165
+
166
+ @dataclass
167
+ class ProductMetadata:
168
+ """Port of `struct ProductMetadata` on the ProductRegistryFacet contract."""
169
+
170
+ builder: eth_typing.ChecksumAddress
171
+ symbol: str
172
+ description: str
173
+
174
+
175
+ @dataclass
176
+ class OracleSpecification:
177
+ """Port of `struct OracleSpecification` on the ProductRegistryFacet contract."""
178
+
179
+ oracle_address: eth_typing.ChecksumAddress
180
+ fsv_decimals: int
181
+ fsp_alpha: int
182
+ fsp_beta: int
183
+ fsv_calldata: hexbytes.HexBytes
184
+
185
+
186
+ @dataclass
187
+ class BaseProduct:
188
+ """Port of `struct BaseProduct` on the ProductRegistryFacet contract."""
189
+
190
+ metadata: ProductMetadata
191
+ oracle_spec: OracleSpecification
192
+ collateral_asset: eth_typing.ChecksumAddress
193
+ start_time: int
194
+ point_value: int
195
+ price_decimals: int
196
+ extended_metadata: str
197
+
198
+
199
+ @dataclass
200
+ class MarginSpecification:
201
+ """Port of `struct MarginSpecification` on the ProductRegistryFacet contract."""
202
+
203
+ imr: int
204
+ mmr: int
205
+
206
+
207
+ @dataclass
208
+ class FuturesProductV1:
209
+ """Port of `struct FuturesProductV1` on the ProductRegistryFacet contract."""
210
+
211
+ base: BaseProduct
212
+ expiry_spec: ExpirySpecification
213
+ margin_spec: MarginSpecification
214
+
215
+
216
+ @dataclass
217
+ class PredictionProductV1:
218
+ """Port of `struct PredictionProductV1` on the ProductRegistryFacet contract."""
219
+
220
+ base: BaseProduct
221
+ expiry_spec: ExpirySpecification
222
+ max_price: int
223
+ min_price: int
afp/config.py CHANGED
@@ -9,6 +9,10 @@ from .auth import Authenticator
9
9
  class Config:
10
10
  authenticator: Authenticator | None
11
11
 
12
+ # IPFS client parameters
13
+ ipfs_api_url: str
14
+ ipfs_api_key: str | None
15
+
12
16
  # Venue parameters
13
17
  exchange_url: str
14
18
 
afp/constants.py CHANGED
@@ -1,4 +1,5 @@
1
1
  import os
2
+ from datetime import timedelta
2
3
  from importlib import metadata
3
4
  from types import SimpleNamespace
4
5
 
@@ -17,6 +18,45 @@ RATE_MULTIPLIER = 10**4
17
18
  FEE_RATE_MULTIPLIER = 10**6
18
19
  FULL_PRECISION_MULTIPLIER = 10**18
19
20
 
21
+ # IPFS client constants
22
+ IPFS_CID_ENCODING = "base32"
23
+ IPFS_REQUEST_TIMEOUT = 30
24
+ JSON_SCHEMAS_DIRECTORY = os.path.join(os.path.dirname(__file__), "json-schemas")
25
+
26
+ # Product schema constants
27
+ MINIMUM_ORACLE_FALLBACK_INTERVAL = timedelta(days=7)
28
+ MONTH_CODES = {
29
+ "F": 1,
30
+ "G": 2,
31
+ "H": 3,
32
+ "J": 4,
33
+ "K": 5,
34
+ "M": 6,
35
+ "N": 7,
36
+ "Q": 8,
37
+ "U": 9,
38
+ "V": 10,
39
+ "X": 11,
40
+ "Z": 12,
41
+ }
42
+
43
+ schema_cids = SimpleNamespace(
44
+ # afp-product-schemas v0.2.0
45
+ ORACLE_CONFIG_V020="bafyreifcec2km7hxwq6oqzjlspni2mgipetjb7pqtaewh2efislzoctboi",
46
+ ORACLE_CONFIG_PROTOTYPE1_V020="bafyreiaw34o6l3rmatabzbds2i2myazdw2yolevcpsoyd2i2g3ms7wa2eq",
47
+ ORACLE_FALLBACK_V020="bafyreicgr6dfo5yduixjkcifghiulskfegwojvuwodtouvivl362zndhxe",
48
+ OUTCOME_POINT_V020="bafyreibnfg6nq74dvpkre5rakkccij7iadp5rxpim7omsatjnrpmj3y7v4",
49
+ OUTCOME_POINT_EVENT_V020="bafyreihur3dzwhja6uxsbcw6eeoj3xmmc4e3zkmyzpot5v5dleevxe5zam",
50
+ OUTCOME_POINT_TIME_SERIES_V020=(
51
+ "bafyreidzs7okcpqiss6ztftltyptqwnw5e5opsy5yntospekjha4kpykaa"
52
+ ),
53
+ OUTCOME_SPACE_V020="bafyreicheoypx6synljushh7mq2572iyhlolf4nake2p5dwobgnj3r5eua",
54
+ OUTCOME_SPACE_SCALAR_V020="bafyreihn3oiaxffe4e2w7pwtreadpw3obfd7gqlogbcxm56jc2hzfvco74",
55
+ OUTCOME_SPACE_TIME_SERIES_V020=(
56
+ "bafyreid35a67db4sqh4fs6boddyt2xvscbqy6nqvsp5jjur56qhkw4ixre"
57
+ ),
58
+ )
59
+
20
60
  defaults = SimpleNamespace(
21
61
  # Authentication parameters
22
62
  KEYFILE=os.getenv("AFP_KEYFILE", None),
@@ -24,8 +64,11 @@ defaults = SimpleNamespace(
24
64
  PRIVATE_KEY=os.getenv("AFP_PRIVATE_KEY", None),
25
65
  # Venue parameters
26
66
  EXCHANGE_URL=os.getenv(
27
- "AFP_EXCHANGE_URL", "https://afp-exchange-stable.up.railway.app"
67
+ "AFP_EXCHANGE_URL", "https://afp-exchange-stable.up.railway.app/"
28
68
  ),
69
+ # IPFS client parameters
70
+ IPFS_API_URL=os.getenv("AFP_IPFS_API_URL", "http://localhost:5001"),
71
+ IPFS_API_KEY=os.getenv("AFP_IPFS_API_KEY", None),
29
72
  # Blockchain parameters
30
73
  RPC_URL=os.getenv("AFP_RPC_URL", None),
31
74
  CHAIN_ID=int(os.getenv("AFP_CHAIN_ID", 65000000)),
@@ -37,19 +80,19 @@ defaults = SimpleNamespace(
37
80
  TIMEOUT_SECONDS=int(os.getenv("AFP_TIMEOUT_SECONDS", 10)),
38
81
  # Clearing System parameters
39
82
  CLEARING_DIAMOND_ADDRESS=os.getenv(
40
- "AFP_CLEARING_DIAMOND_ADDRESS", "0x5B5411F1548254d25360d71FE40cFc1cC983B2A2"
83
+ "AFP_CLEARING_DIAMOND_ADDRESS", "0x08e725d38BCABCf62806E84bE044dF67E8b476Ae"
41
84
  ),
42
85
  MARGIN_ACCOUNT_REGISTRY_ADDRESS=os.getenv(
43
86
  "AFP_MARGIN_ACCOUNT_REGISTRY_ADDRESS",
44
- "0x99f4FA9Cdce7AD227eB84907936a8FeF2095D846",
87
+ "0x1FAa342Ea34332ee1186FE48f03894F70F7fFc4f",
45
88
  ),
46
89
  ORACLE_PROVIDER_ADDRESS=os.getenv(
47
- "AFP_ORACLE_PROVIDER_ADDRESS", "0xF2A2A27da33D30B4BF38D7e186E7B0b1e964e55c"
90
+ "AFP_ORACLE_PROVIDER_ADDRESS", "0x06CaDDDf6CC08048596aE051c8ce644725219C73"
48
91
  ),
49
92
  PRODUCT_REGISTRY_ADDRESS=os.getenv(
50
- "AFP_PRODUCT_REGISTRY_ADDRESS", "0x86B3829471929B115367DA0958f56A6AB844b08e"
93
+ "AFP_PRODUCT_REGISTRY_ADDRESS", "0xB605fc6B76eA4592CaA3AEd26EFd3edbAc5A3A24"
51
94
  ),
52
95
  SYSTEM_VIEWER_ADDRESS=os.getenv(
53
- "AFP_SYSTEM_VIEWER_ADDRESS", "0xfF2DFcC44a95cce96E03EfC33C65c8Be671Bae5B"
96
+ "AFP_SYSTEM_VIEWER_ADDRESS", "0xBeC22149650CcaC2a1233c7b489aFF3ea24df36d"
54
97
  ),
55
98
  )
afp/decorators.py CHANGED
@@ -1,10 +1,12 @@
1
1
  from collections.abc import Callable
2
2
  from itertools import chain
3
- from typing import Any
3
+ from typing import Any, cast
4
4
 
5
5
  import inflection
6
6
  from decorator import decorator
7
- from eth_typing.abi import ABI
7
+ from eth_abi.exceptions import InsufficientDataBytes
8
+ from eth_typing.abi import ABI, ABIError, ABIFunction
9
+ from eth_typing.encoding import HexStr
8
10
  from eth_utils import abi
9
11
  from hexbytes import HexBytes
10
12
  from web3.exceptions import (
@@ -13,6 +15,7 @@ from web3.exceptions import (
13
15
  Web3Exception,
14
16
  Web3RPCError,
15
17
  )
18
+ from web3._utils import contracts, normalizers
16
19
 
17
20
  from .api.base import ExchangeAPI
18
21
  from .exceptions import ClearingSystemError, AuthenticationError
@@ -71,6 +74,25 @@ def _decode_custom_error(data: str, *contract_abis: ABI) -> str | None:
71
74
  selector_candidate = abi.function_signature_to_4byte_selector(signature)
72
75
  if selector == selector_candidate:
73
76
  error = error_candidate["name"]
77
+ args = _decode_transaction_args(error_candidate, data)
74
78
  # Convert 'ErrorType' to 'Error type'
75
- return inflection.humanize(inflection.underscore(error))
79
+ error = inflection.humanize(inflection.underscore(error))
80
+ if args:
81
+ error += ": " + ", ".join(f"{key}='{val}'" for key, val in args.items())
82
+ return error
76
83
  return None
84
+
85
+
86
+ def _decode_transaction_args(error_abi: ABIError, data: str) -> dict[str, str]:
87
+ try:
88
+ args = contracts.decode_transaction_data( # type: ignore
89
+ cast(ABIFunction, error_abi),
90
+ cast(HexStr, data),
91
+ normalizers=normalizers.BASE_RETURN_NORMALIZERS, # type: ignore
92
+ )
93
+ except InsufficientDataBytes:
94
+ return {}
95
+ return {
96
+ key: HexBytes(val).to_0x_hex() if isinstance(val, bytes) else str(val)
97
+ for key, val in args.items()
98
+ }
afp/dtos.py ADDED
@@ -0,0 +1,142 @@
1
+ """Internal schemas."""
2
+
3
+ from decimal import Decimal
4
+ from typing import Annotated, Literal
5
+
6
+ from pydantic import AfterValidator, ConfigDict, Field, computed_field
7
+
8
+ from . import validators
9
+ from .enums import ListingState, OrderSide, OrderState, OrderType, TradeState
10
+ from .schemas import (
11
+ Intent,
12
+ OracleConfig,
13
+ OracleConfigPrototype1,
14
+ OracleFallback,
15
+ OrderCancellationData,
16
+ OutcomePoint,
17
+ OutcomePointEvent,
18
+ OutcomePointTimeSeries,
19
+ OutcomeSpace,
20
+ OutcomeSpaceScalar,
21
+ OutcomeSpaceTimeSeries,
22
+ Timestamp,
23
+ )
24
+ from .types import IPLD_LINK, AliasedModel, Model
25
+
26
+
27
+ class PaginationFilter(Model):
28
+ batch: Annotated[None | int, Field(gt=0, exclude=True)]
29
+ batch_size: Annotated[None | int, Field(gt=0, exclude=True)]
30
+ newest_first: Annotated[None | bool, Field(exclude=True)]
31
+
32
+ @computed_field
33
+ @property
34
+ def page(self) -> None | int:
35
+ return self.batch
36
+
37
+ @computed_field
38
+ @property
39
+ def page_size(self) -> None | int:
40
+ return self.batch_size
41
+
42
+ @computed_field
43
+ @property
44
+ def sort(self) -> None | Literal["ASC", "DESC"]:
45
+ match self.newest_first:
46
+ case None:
47
+ return None
48
+ case True:
49
+ return "DESC"
50
+ case False:
51
+ return "ASC"
52
+
53
+
54
+ # Authentication
55
+
56
+
57
+ class LoginSubmission(AliasedModel):
58
+ message: str
59
+ signature: str
60
+
61
+
62
+ class ExchangeParameters(AliasedModel):
63
+ trading_protocol_id: str
64
+ maker_trading_fee_rate: Decimal
65
+ taker_trading_fee_rate: Decimal
66
+
67
+
68
+ # Admin API
69
+
70
+
71
+ class ExchangeProductListingSubmission(AliasedModel):
72
+ id: Annotated[str, AfterValidator(validators.validate_hexstr32)]
73
+
74
+
75
+ class ExchangeProductUpdateSubmission(AliasedModel):
76
+ listing_state: ListingState
77
+
78
+
79
+ # Trading API
80
+
81
+
82
+ class ExchangeProductFilter(PaginationFilter):
83
+ pass
84
+
85
+
86
+ class OrderFilter(PaginationFilter):
87
+ intent_account_id: str
88
+ product_id: None | Annotated[str, AfterValidator(validators.validate_hexstr32)]
89
+ type: None | OrderType
90
+ states: Annotated[list[OrderState], Field(exclude=True)]
91
+ side: None | OrderSide
92
+ start: None | Timestamp
93
+ end: None | Timestamp
94
+
95
+ @computed_field
96
+ @property
97
+ def state(self) -> str | None:
98
+ return ",".join(self.states) if self.states else None
99
+
100
+
101
+ class OrderSubmission(AliasedModel):
102
+ type: OrderType
103
+ intent: Intent | None = None
104
+ cancellation_data: OrderCancellationData | None = None
105
+
106
+
107
+ class OrderFillFilter(PaginationFilter):
108
+ intent_account_id: str
109
+ product_id: None | Annotated[str, AfterValidator(validators.validate_hexstr32)]
110
+ intent_hash: None | Annotated[str, AfterValidator(validators.validate_hexstr32)]
111
+ start: None | Timestamp
112
+ end: None | Timestamp
113
+ trade_states: Annotated[list[TradeState], Field(exclude=True)]
114
+
115
+ @computed_field
116
+ @property
117
+ def trade_state(self) -> str | None:
118
+ return ",".join(self.trade_states) if self.trade_states else None
119
+
120
+
121
+ # IPFS Client
122
+
123
+
124
+ class ExtendedMetadata(Model):
125
+ outcome_space: OutcomeSpaceTimeSeries | OutcomeSpaceScalar | OutcomeSpace
126
+ outcome_point: OutcomePointEvent | OutcomePointTimeSeries | OutcomePoint
127
+ oracle_config: OracleConfigPrototype1 | OracleConfig
128
+ oracle_fallback: OracleFallback
129
+
130
+
131
+ class ComponentLink(AliasedModel):
132
+ model_config = AliasedModel.model_config | ConfigDict(arbitrary_types_allowed=True)
133
+
134
+ data: IPLD_LINK
135
+ schema_: Annotated[IPLD_LINK, Field(alias="schema")]
136
+
137
+
138
+ class ExtendedMetadataDAG(Model):
139
+ outcome_space: ComponentLink
140
+ outcome_point: ComponentLink
141
+ oracle_config: ComponentLink
142
+ oracle_fallback: ComponentLink
afp/exceptions.py CHANGED
@@ -2,6 +2,9 @@ class AFPException(Exception):
2
2
  pass
3
3
 
4
4
 
5
+ # API-specific exceptions
6
+
7
+
5
8
  class ConfigurationError(AFPException):
6
9
  pass
7
10
 
@@ -10,10 +13,17 @@ class ClearingSystemError(AFPException):
10
13
  pass
11
14
 
12
15
 
16
+ class IPFSError(AFPException):
17
+ pass
18
+
19
+
13
20
  class ExchangeError(AFPException):
14
21
  pass
15
22
 
16
23
 
24
+ # Exchange error sub-types
25
+
26
+
17
27
  class AuthenticationError(ExchangeError):
18
28
  pass
19
29
 
afp/exchange.py CHANGED
@@ -6,6 +6,16 @@ import requests
6
6
  from requests import Response, Session
7
7
 
8
8
  from . import constants
9
+ from .dtos import (
10
+ ExchangeParameters,
11
+ ExchangeProductFilter,
12
+ ExchangeProductListingSubmission,
13
+ ExchangeProductUpdateSubmission,
14
+ LoginSubmission,
15
+ OrderFilter,
16
+ OrderFillFilter,
17
+ OrderSubmission,
18
+ )
9
19
  from .exceptions import (
10
20
  AuthenticationError,
11
21
  AuthorizationError,
@@ -15,19 +25,11 @@ from .exceptions import (
15
25
  ValidationError,
16
26
  )
17
27
  from .schemas import (
18
- ExchangeParameters,
19
28
  ExchangeProduct,
20
- ExchangeProductFilter,
21
- ExchangeProductListingSubmission,
22
- ExchangeProductUpdateSubmission,
23
- LoginSubmission,
24
29
  MarketDepthData,
25
30
  OHLCVItem,
26
31
  Order,
27
- OrderFilter,
28
32
  OrderFill,
29
- OrderFillFilter,
30
- OrderSubmission,
31
33
  )
32
34
 
33
35
 
afp/hashing.py CHANGED
@@ -6,13 +6,13 @@ from hexbytes import HexBytes
6
6
  from web3 import Web3
7
7
 
8
8
  from . import constants
9
- from .bindings import clearing_facet
9
+ from .bindings import Side as OnChainSide
10
10
  from .schemas import IntentData, OrderSide
11
11
 
12
12
 
13
13
  ORDER_SIDE_MAPPING: dict[OrderSide, int] = {
14
- OrderSide.BID: clearing_facet.Side.BID.value,
15
- OrderSide.ASK: clearing_facet.Side.ASK.value,
14
+ OrderSide.BID: OnChainSide.BID.value,
15
+ OrderSide.ASK: OnChainSide.ASK.value,
16
16
  }
17
17
 
18
18
 
@@ -28,11 +28,12 @@ def generate_intent_hash(
28
28
  "uint256", # nonce
29
29
  "address", # trading_protocol_id
30
30
  "bytes32", # product_id
31
- "uint256", # limit_price
31
+ "int256", # limit_price
32
32
  "uint256", # quantity
33
- "uint256", # max_trading_fee_rate
33
+ "uint32", # max_trading_fee_rate
34
34
  "uint256", # good_until_time
35
35
  "uint8", # side
36
+ "address", # referral
36
37
  ]
37
38
  values: list[Any] = [
38
39
  margin_account_id,
@@ -45,6 +46,7 @@ def generate_intent_hash(
45
46
  int(intent_data.max_trading_fee_rate * constants.FEE_RATE_MULTIPLIER),
46
47
  int(intent_data.good_until_time.timestamp()),
47
48
  ORDER_SIDE_MAPPING[intent_data.side],
49
+ cast(ChecksumAddress, intent_data.referral),
48
50
  ]
49
51
  return Web3.keccak(encode_packed(types, values))
50
52