afp-sdk 0.5.4__py3-none-any.whl → 0.6.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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 +236 -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.1.dist-info}/METADATA +76 -11
  43. afp_sdk-0.6.1.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.1.dist-info}/WHEEL +0 -0
  49. {afp_sdk-0.5.4.dist-info → afp_sdk-0.6.1.dist-info}/licenses/LICENSE +0 -0
afp/validators.py CHANGED
@@ -1,18 +1,22 @@
1
- from datetime import datetime, timedelta
1
+ import re
2
+ from datetime import date, datetime, timedelta
2
3
  from decimal import Decimal
4
+ from functools import reduce
5
+ from operator import getitem
6
+ from typing import Any, Iterable
3
7
 
8
+ import requests
4
9
  from binascii import Error
5
10
  from eth_typing.evm import ChecksumAddress
6
11
  from hexbytes import HexBytes
12
+ from pydantic import AnyUrl
7
13
  from web3 import Web3
8
14
 
15
+ from .constants import MINIMUM_ORACLE_FALLBACK_INTERVAL, MONTH_CODES
16
+ from .exceptions import ValidationError
9
17
 
10
- def ensure_timestamp(value: int | datetime) -> int:
11
- return int(value.timestamp()) if isinstance(value, datetime) else value
12
18
 
13
-
14
- def ensure_datetime(value: datetime | int) -> datetime:
15
- return value if isinstance(value, datetime) else datetime.fromtimestamp(value)
19
+ # Generic type validators
16
20
 
17
21
 
18
22
  def validate_timedelta(value: timedelta) -> timedelta:
@@ -21,6 +25,12 @@ def validate_timedelta(value: timedelta) -> timedelta:
21
25
  return value
22
26
 
23
27
 
28
+ def validate_non_negative_timestamp(value: datetime) -> datetime:
29
+ if value.timestamp() < 0:
30
+ raise ValueError(f"{value} should be greater than {datetime.fromtimestamp(0)}")
31
+ return value
32
+
33
+
24
34
  def validate_hexstr(value: str, length: int | None = None) -> str:
25
35
  value = str(value)
26
36
  if not value.startswith("0x"):
@@ -45,13 +55,213 @@ def validate_address(value: str) -> ChecksumAddress:
45
55
  raise ValueError(f"{value} is not a valid blockchain address")
46
56
 
47
57
 
58
+ def validate_url(value: str) -> str:
59
+ AnyUrl(value)
60
+ return value
61
+
62
+
63
+ def validate_all_caps(value: str) -> str:
64
+ if value != value.upper():
65
+ raise ValueError(f"{value} should use capital letters only")
66
+ return value
67
+
68
+
69
+ # Live data verifiers
70
+
71
+
72
+ def verify_collateral_asset(w3: Web3, address: str) -> ChecksumAddress:
73
+ address = validate_address(address)
74
+ if len(w3.eth.get_code(address)) == 0:
75
+ raise ValidationError(
76
+ f"No contract found at collateral asset address {address}"
77
+ )
78
+ return address
79
+
80
+
81
+ def verify_oracle(w3: Web3, address: str) -> ChecksumAddress:
82
+ address = validate_address(address)
83
+ if len(w3.eth.get_code(address)) == 0:
84
+ raise ValidationError(f"No contract found at oracle address {address}")
85
+ return address
86
+
87
+
88
+ def verify_url(value: str) -> str:
89
+ try:
90
+ requests.head(value)
91
+ except requests.RequestException as ex:
92
+ raise ValidationError(f"Not possible to connect to URL {value}") from ex
93
+ return value
94
+
95
+
96
+ # Schema-specific model validators
97
+
98
+
48
99
  def validate_limit_price(
49
- value: Decimal, tick_size: int, rounding: str | None = None
100
+ value: Decimal,
101
+ min_price: Decimal,
102
+ max_price: Decimal,
103
+ tick_size: int,
104
+ rounding: str | None = None,
50
105
  ) -> Decimal:
106
+ if value < min_price:
107
+ raise ValueError(
108
+ f"IntentData: limit_price: {value} should be greater than "
109
+ f"the product's minimum price {min_price}"
110
+ )
111
+ if value > max_price:
112
+ raise ValueError(
113
+ f"IntentData: limit_price: {value} should be less than the product's "
114
+ f"maximum price {max_price}"
115
+ )
51
116
  if rounding is None:
52
117
  num_fractional_digits = abs(int(value.normalize().as_tuple().exponent))
53
118
  if num_fractional_digits > tick_size:
54
119
  raise ValueError(
55
- f"Limit price {value} can have at most {tick_size} fractional digits"
120
+ f"IntentData: limit_price: {value} should have at most "
121
+ f"{tick_size} fractional digits"
56
122
  )
57
123
  return value.quantize(Decimal("10") ** -tick_size, rounding=rounding)
124
+
125
+
126
+ def validate_price_limits(min_price: Decimal, max_price: Decimal) -> None:
127
+ if min_price >= max_price:
128
+ raise ValueError(
129
+ f"PredictionProductV1.min_price {min_price} "
130
+ f"should be less than PredictionProductV1.max_price {max_price}"
131
+ )
132
+
133
+
134
+ def validate_time_limits(
135
+ start_time: datetime, earliest_fsp_submission_time: datetime
136
+ ) -> None:
137
+ if start_time >= earliest_fsp_submission_time:
138
+ raise ValueError(
139
+ f"BaseProduct.start_time {start_time} should be less than "
140
+ "ExpirySpecification.earliest_fsp_submission_time "
141
+ f"{earliest_fsp_submission_time}"
142
+ )
143
+
144
+
145
+ def validate_matching_fsp_types(
146
+ outcome_space_fsp_type: str, outcome_point_fsp_type: str
147
+ ) -> None:
148
+ if outcome_space_fsp_type != outcome_point_fsp_type:
149
+ raise ValueError(
150
+ f"OutcomeSpace.fsp_type '{outcome_space_fsp_type}' should match "
151
+ f"OutcomePoint.fsp_type '{outcome_point_fsp_type}'"
152
+ )
153
+
154
+
155
+ def validate_oracle_fallback_time(
156
+ fallback_time: datetime, earliest_fsp_submission_time: datetime
157
+ ) -> None:
158
+ earliest_fallback_time = (
159
+ earliest_fsp_submission_time + MINIMUM_ORACLE_FALLBACK_INTERVAL
160
+ )
161
+ if fallback_time < earliest_fallback_time:
162
+ raise ValueError(
163
+ f"OracleFallback: fallback_time {fallback_time} "
164
+ f"should be at least {MINIMUM_ORACLE_FALLBACK_INTERVAL} after "
165
+ "ExpirySpecification.earliest_fsp_submission_time "
166
+ f"{earliest_fsp_submission_time}"
167
+ )
168
+
169
+
170
+ def validate_oracle_fallback_fsp(
171
+ fallback_fsp: Decimal, min_price: Decimal, max_price: Decimal
172
+ ) -> None:
173
+ if not (min_price <= fallback_fsp <= max_price):
174
+ raise ValueError(
175
+ f"OracleFallback: fallback_fsp {fallback_fsp} should be between "
176
+ f"PredictionProductV1.min_price {min_price} and "
177
+ f"PredictionProductV1.max_price {max_price}"
178
+ )
179
+
180
+
181
+ def validate_outcome_space_template_variables(
182
+ values: Iterable[str], outcome_point_dict: dict[Any, Any]
183
+ ) -> None:
184
+ for value in values:
185
+ for variable in re.findall(r"{(.*?)}", value):
186
+ try:
187
+ referred_value = reduce(
188
+ getitem, variable.split("."), outcome_point_dict
189
+ )
190
+ except (TypeError, KeyError):
191
+ raise ValueError(
192
+ f"OutcomeSpace: Invalid template variable '{variable}'"
193
+ )
194
+ if isinstance(referred_value, dict) or isinstance(referred_value, list): # type: ignore
195
+ raise ValueError(
196
+ f"OutcomeSpace: Template variable '{variable}' "
197
+ "should not refer to a nested object or list"
198
+ )
199
+
200
+
201
+ def validate_symbol(symbol: str, frequency: str, release_date: date) -> None:
202
+ match frequency:
203
+ case "daily":
204
+ pattern = (
205
+ r"[A-Z]{1,8}(?P<day>(0[1-9]|[1-2][0-9]|3[01]))"
206
+ r"(?P<month>[FGHJKMNQUVXZ])(?P<year>[0-9]{2})"
207
+ )
208
+ case "weekly" | "fortnightly":
209
+ pattern = (
210
+ r"[A-Z]{1,8}(?P<weekno>(0[1-9]|[1-4][0-9]|5[0-3]))"
211
+ r"W(?P<year>[0-9]{2})"
212
+ )
213
+ case "semimonthly":
214
+ pattern = (
215
+ r"[A-Z]{1,8}(?P<occurrence>[12])"
216
+ r"(?P<month>[FGHJKMNQUVXZ])(?P<year>[0-9]{2})"
217
+ )
218
+ case "monthly" | "quarterly":
219
+ pattern = r"[A-Z]{1,8}(?P<month>[FGHJKMNQUVXZ])(?P<year>[0-9]{2})"
220
+ case "yearly":
221
+ pattern = r"[A-Z]{1,8}(?P<year>[0-9]{4})"
222
+ case _:
223
+ raise ValueError(
224
+ f"OutcomeSpaceTimeSeries: frequency: Unexpected value '{frequency}'"
225
+ )
226
+ if match := re.fullmatch(pattern, symbol):
227
+ groups = match.groupdict()
228
+
229
+ if "day" in groups and int(groups["day"]) != release_date.day:
230
+ raise ValueError(
231
+ f"ProductMetadata: symbol: Day component of symbol '{symbol}' "
232
+ f"should match TemporalObservation.release_date {release_date}"
233
+ )
234
+ if "month" in groups and MONTH_CODES[groups["month"]] != release_date.month:
235
+ raise ValueError(
236
+ f"ProductMetadata: symbol: Month component of symbol '{symbol}' "
237
+ f"should match TemporalObservation.release_date {release_date}"
238
+ )
239
+ if "year" in groups and int(groups["year"]) % 2000 != release_date.year % 2000:
240
+ raise ValueError(
241
+ f"ProductMetadata: symbol: Year component of symbol '{symbol}' "
242
+ f"should match TemporalObservation.release_date {release_date}"
243
+ )
244
+ if (
245
+ "weekno" in groups
246
+ and int(groups["weekno"]) != release_date.isocalendar().week
247
+ ):
248
+ raise ValueError(
249
+ f"ProductMetadata: symbol: Week number component of symbol '{symbol}' "
250
+ f"should match TemporalObservation.release_date {release_date}"
251
+ )
252
+ if "occurrence" in groups and int(
253
+ groups["occurrence"]
254
+ ) != _semimonthly_occurrence(release_date.day):
255
+ raise ValueError(
256
+ f"ProductMetadata: symbol: Occurrence component of symbol '{symbol}' "
257
+ f"should match TemporalObservation.release_date {release_date}"
258
+ )
259
+ else:
260
+ raise ValueError(
261
+ f"ProductMetadata: symbol: Symbol '{symbol}' should match regexp pattern "
262
+ f"'{pattern}' for OutcomeSpaceTimeSeries.frequency '{frequency}'"
263
+ )
264
+
265
+
266
+ def _semimonthly_occurrence(day_of_month: int) -> int:
267
+ return 1 if day_of_month <= 15 else 2
@@ -1,22 +1,26 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: afp-sdk
3
- Version: 0.5.4
3
+ Version: 0.6.1
4
4
  Summary: Autonomous Futures Protocol Python SDK
5
5
  Keywords: autonity,web3,trading,crypto,prediction,forecast,markets
6
6
  License-Expression: MIT
7
7
  License-File: LICENSE
8
8
  Classifier: Development Status :: 4 - Beta
9
9
  Classifier: Programming Language :: Python
10
- Classifier: Programming Language :: Python :: 3.11
11
10
  Classifier: Programming Language :: Python :: 3.12
12
11
  Classifier: Programming Language :: Python :: 3.13
12
+ Classifier: Programming Language :: Python :: 3.14
13
+ Requires-Dist: dag-cbor>=0.3.3
13
14
  Requires-Dist: decorator>=5.2.1
14
15
  Requires-Dist: inflection>=0.5.1
16
+ Requires-Dist: ipld-car>=0.0.1
17
+ Requires-Dist: multiformats>=0.3.1.post4
15
18
  Requires-Dist: pydantic>=2.10.6
16
19
  Requires-Dist: requests>=2.32.0
20
+ Requires-Dist: rfc8785>=0.1.4
17
21
  Requires-Dist: siwe>=4.4.0
18
22
  Requires-Dist: web3>=7.6.0
19
- Requires-Python: >=3.11
23
+ Requires-Python: >=3.12
20
24
  Project-URL: Changes, https://github.com/autonity/afp-sdk/blob/master/CHANGELOG.md
21
25
  Project-URL: Homepage, https://github.com/autonity/afp-sdk
22
26
  Project-URL: Issues, https://github.com/autonity/afp-sdk/issues
@@ -187,14 +191,75 @@ fills = trading.order_fills(product_id=PRODUCT_ID)
187
191
  print(fills)
188
192
  ```
189
193
 
190
- See further code examples in the [examples](./examples/) directory.
194
+ ### Product API
191
195
 
192
- ## Development
196
+ Use the `Product` session object to validate a product schema, pin the
197
+ specification to IPFS, and register it on-chain.
198
+
199
+ In order to use the product API for product building, connection parameters of
200
+ an IPFS pinning service like [Filebase](https://filebase.com/) should be
201
+ included in the `AFP` constructor parameters.
202
+
203
+ ```py
204
+ IPFS_API_URL = "https://rpc.filebase.io"
205
+ IPFS_API_KEY = os.environ["IPFS_API_KEY"]
206
+
207
+ app = afp.AFP(
208
+ rpc_url=AUTONITY_RPC_URL,
209
+ authenticator=afp.PrivateKeyAuthenticator(PRIVATE_KEY),
210
+ ipfs_api_url=IPFS_API_URL,
211
+ ipfs_api_key=IPFS_API_KEY,
212
+ )
213
+
214
+ product = app.Product()
215
+ ```
216
+
217
+ A JSON product specification can be parsed and validated with
218
+ `product.validate_json()`.
219
+
220
+ ```py
221
+ with open("product-spec.json") as spec_file:
222
+ specification = product.validate_json(spec_file.read())
223
+ ```
224
+
225
+ Alternatively, it can also be validated from a Python dictionary.
193
226
 
194
- The package uses [`uv`](https://docs.astral.sh/uv/) as project manager.
227
+ ```py
228
+ spec_dict = {
229
+ "product": {...},
230
+ "outcome_space": {...},
231
+ "outcome_point": {...},
232
+ "oracle_config": {...},
233
+ "oracle_fallback": {...},
234
+ }
235
+ specification = product.validate(spec_dict)
236
+ ```
237
+
238
+ Product specifications are stored at two different places, the `PredictionProductV1`
239
+ object is stored on-chain in the Product Registry contract, while the rest of the
240
+ product specification is referred to as _extended metadata_ and it is uploaded to IPFS.
241
+
242
+ The first step therefore is to upload the extended metadata of the product to
243
+ IPFS and to pin the root node of the DAG. `product.pin()` returns a modified
244
+ copy of the specification that incudes the extended metadata CID.
245
+
246
+ ```py
247
+ pinned_specification = product.pin(specification)
248
+ ```
249
+
250
+ The product can then be registered with the Product Registry contract via a
251
+ blockchain transaction.
252
+
253
+ ```
254
+ tx = product.register(
255
+ pinned_specification, initial_builder_stake=Decimal("10")
256
+ )
257
+ ```
258
+
259
+ See further code examples in the
260
+ [examples](https://github.com/autonity/afp-sdk/tree/master/examples/) directory.
261
+
262
+ ## Development
195
263
 
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.
264
+ See [DEVELOPMENT.md](https://github.com/autonity/afp-sdk/blob/master/DEVELOPMENT.md)
265
+ for developer documentation.
@@ -0,0 +1,50 @@
1
+ afp/__init__.py,sha256=ESBx9plb3ESlRQgTPSFbwQHuqIETv4biDN22CBhQp6g,423
2
+ afp/afp.py,sha256=onXjJX6I45oOS5jxWpLipBfKiYMdTxc6IU0oTQ0CHl4,9781
3
+ afp/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ afp/api/admin.py,sha256=r5B1aQLBKy3VOiJxFU7Q6jAGau0E2QbxhBoXrl2Wm3Q,2167
5
+ afp/api/base.py,sha256=IIkCslGziKRN8FVPVMwSHYKmIxFbj4GO2ivA_puavrU,4696
6
+ afp/api/margin_account.py,sha256=lHj1d1E4SgKlmffFa7c3wD430XokEe2pDJZDfIegpiU,10927
7
+ afp/api/product.py,sha256=WT886LGLU7qNAbuTrrvcHfhTVvCDzrN-OnFZrZ8-x60,16175
8
+ afp/api/trading.py,sha256=UhiasWbexPK_4HWBTgQSmt54MrddfHkYi-ocPdvITPQ,17385
9
+ afp/auth.py,sha256=WX4IhwdLdTU1DZsE88xFxyjolKN82hOQLB6-MczJKg0,2476
10
+ afp/bindings/__init__.py,sha256=GGEdCeRvCX5BviL59ogv_zD8zumr2a6VAp9ReGp2zpU,1318
11
+ afp/bindings/admin_facet.py,sha256=6WHLgaqfFO_IfA5B3u9CICMfHxZH7nA4DAxXQEgJ0Ug,31285
12
+ afp/bindings/clearing_facet.py,sha256=LXOcXBCh4Mu_I_t9edTXz-h5Mtt6CQwrjVYAckS3nT0,22096
13
+ afp/bindings/erc20.py,sha256=-jw7ohcEbUL7g3PpK3-a5_7ClUDCDHt1bezm-w7exzo,10822
14
+ afp/bindings/facade.py,sha256=oMJts0LlkOG58EZuw20WeBquSF96gDvg2KGzea0QEH8,2696
15
+ afp/bindings/final_settlement_facet.py,sha256=M7d3HllvU2ZHCiro9X_2hWYzLCFFb5WoKaemlKO9YJI,14934
16
+ afp/bindings/margin_account.py,sha256=wdbXVYshAjklo08f-j2FxMsbigrpy9LiWki1O1ZWAyQ,35371
17
+ afp/bindings/margin_account_facet.py,sha256=pT2Hkluq1qLOQ5Qm71UR3j6GO_OAwAjIy51k1DDe8Os,23839
18
+ afp/bindings/margin_account_registry.py,sha256=-3beQiHtk-lz4lVTwZPZU9K9vHRlUEfzvbbVk9KMdCg,15182
19
+ afp/bindings/mark_price_tracker_facet.py,sha256=KWbPS-1JxyzctVoXH3Df8N12obqd4dxjnMe8E1r30SQ,5323
20
+ afp/bindings/oracle_provider.py,sha256=CMpVAXdUuTP_W9ZE297B-m9MjuW90yCOhNLMVl3kCf0,15863
21
+ afp/bindings/product_registry.py,sha256=2rGNVG_GxGIJfW5xOhIIVzq_IT5aVCmMrC46jm1ewh8,86610
22
+ afp/bindings/product_registry_facet.py,sha256=CE3vpSFIj54d3tQdHMfQz-kquqhhzjvQsAqzD_oKhIU,58313
23
+ afp/bindings/system_viewer.py,sha256=Cs2yNe3kBe833I_NnWg1nABIIan6iPQO9ot5U5naWe0,49734
24
+ afp/bindings/types.py,sha256=97x8_Nqfj13PJ2MVzIQ5afeynWiNlMUI2N0L8-8YTbc,4853
25
+ afp/config.py,sha256=xsMgKL1bvxt1wzdln2D9mSX5Eutz87CqF2xct0Xpzwk,780
26
+ afp/constants.py,sha256=2ntRfbRM6N1oIuotxXUBHDMF_aqmemTHVRRl2kHmRgE,3448
27
+ afp/decorators.py,sha256=r_wXmqNExg_inDRFg7rD2qMdWzDmZylyf8v_TPc2wvk,3650
28
+ afp/dtos.py,sha256=oNTWZloMkCX2wfbd5yLe53zLm8U1u6WBwM6OF5UmhLc,3618
29
+ afp/enums.py,sha256=9JhwdLcTNhyKabKdrALAlCeL3C5XfeXYSSSXSCsuTzE,688
30
+ afp/exceptions.py,sha256=UpGb0U9K-5q41wT3PH4bTKGzhxkKCtLR2Dn0hTc907M,540
31
+ afp/exchange.py,sha256=sNayosHN6WxVDH4cUDrt76agdrzPjTVFC2ANNtitQkU,7695
32
+ afp/hashing.py,sha256=4qNPJalunK5KLiu4hRDRv32QiuErPQYKCMMkSExZoWo,2020
33
+ afp/ipfs.py,sha256=fZr3-BGy7BYpM_D8JNme543-Cb1WZi7yqSFJE0Al4j0,9619
34
+ afp/json-schemas/bafyreiaw34o6l3rmatabzbds2i2myazdw2yolevcpsoyd2i2g3ms7wa2eq.json,sha256=yfPc3gzknuKbGoF97uECbf_VdDfKxROhc_oFLc-Hm1U,6683
35
+ afp/json-schemas/bafyreibnfg6nq74dvpkre5rakkccij7iadp5rxpim7omsatjnrpmj3y7v4.json,sha256=IBMLm62G6JkyblvCLfyM4tjWyOH2bDLslDh2WdozFe8,674
36
+ afp/json-schemas/bafyreicgr6dfo5yduixjkcifghiulskfegwojvuwodtouvivl362zndhxe.json,sha256=UALQI3ttQoNSSFcbr5dCAd537dwqGkwKEB59dhtj9bA,1324
37
+ afp/json-schemas/bafyreicheoypx6synljushh7mq2572iyhlolf4nake2p5dwobgnj3r5eua.json,sha256=-MN9Qh0XZFBv3R8JFiMiHSInyJnN9riE4VkkrA22Z8o,3060
38
+ afp/json-schemas/bafyreid35a67db4sqh4fs6boddyt2xvscbqy6nqvsp5jjur56qhkw4ixre.json,sha256=FtJuOsQpsAGNUIHo88PccuABJcuaUdljyWv128iNt7I,10833
39
+ afp/json-schemas/bafyreidzs7okcpqiss6ztftltyptqwnw5e5opsy5yntospekjha4kpykaa.json,sha256=be7XVUuH1mLEoar_A-AAUpH5xrFEUNCeQRkqfOWyDPY,2470
40
+ afp/json-schemas/bafyreifcec2km7hxwq6oqzjlspni2mgipetjb7pqtaewh2efislzoctboi.json,sha256=iJGiFgmbyVyAyG5ty-3tbhHay4Ucb5nvKzVV9N2s864,783
41
+ afp/json-schemas/bafyreihn3oiaxffe4e2w7pwtreadpw3obfd7gqlogbcxm56jc2hzfvco74.json,sha256=_tEqw3mqsdUP_sFwr8S1QZCbXxd3yJYjCHRuYnvoV2Y,4343
42
+ afp/json-schemas/bafyreihur3dzwhja6uxsbcw6eeoj3xmmc4e3zkmyzpot5v5dleevxe5zam.json,sha256=q-JNlC9Znh983Lp0qU8RYdj7VMtKCo4QRUS9OzchEeE,1427
43
+ afp/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
44
+ afp/schemas.py,sha256=Qqjkx9IoKJPni_Tup_cgBPTTVfyfexyAjAe5CAU75RM,9456
45
+ afp/types.py,sha256=mI_PFMlVQvP9BJ50jzgvmUQPhTuP7TPP-JQOLvJr6mY,4691
46
+ afp/validators.py,sha256=ogUzfJcqOsjosP0KncbxfbWVAOcjwEsE3LMmK4aeBFI,9256
47
+ afp_sdk-0.6.1.dist-info/licenses/LICENSE,sha256=ZdaKItgc2ppfqta2OJV0oHpSJiK87PUxmUkUo-_0SB8,1065
48
+ afp_sdk-0.6.1.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
49
+ afp_sdk-0.6.1.dist-info/METADATA,sha256=S286Fl-xYd50GYH4HnY_XdNXwi15IvXzICi15KvQKb0,8107
50
+ afp_sdk-0.6.1.dist-info/RECORD,,