synapse-filecoin-sdk 0.1.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 (64) hide show
  1. pynapse/__init__.py +6 -0
  2. pynapse/_version.py +1 -0
  3. pynapse/contracts/__init__.py +34 -0
  4. pynapse/contracts/abi_registry.py +11 -0
  5. pynapse/contracts/addresses.json +30 -0
  6. pynapse/contracts/erc20_abi.json +92 -0
  7. pynapse/contracts/errorsAbi.json +933 -0
  8. pynapse/contracts/filecoinPayV1Abi.json +2424 -0
  9. pynapse/contracts/filecoinWarmStorageServiceAbi.json +2363 -0
  10. pynapse/contracts/filecoinWarmStorageServiceStateViewAbi.json +651 -0
  11. pynapse/contracts/generated.py +35 -0
  12. pynapse/contracts/payments_abi.json +205 -0
  13. pynapse/contracts/pdpVerifierAbi.json +1266 -0
  14. pynapse/contracts/providerIdSetAbi.json +161 -0
  15. pynapse/contracts/serviceProviderRegistryAbi.json +1479 -0
  16. pynapse/contracts/sessionKeyRegistryAbi.json +147 -0
  17. pynapse/core/__init__.py +68 -0
  18. pynapse/core/abis.py +25 -0
  19. pynapse/core/chains.py +97 -0
  20. pynapse/core/constants.py +27 -0
  21. pynapse/core/errors.py +22 -0
  22. pynapse/core/piece.py +263 -0
  23. pynapse/core/rand.py +14 -0
  24. pynapse/core/typed_data.py +320 -0
  25. pynapse/core/utils.py +30 -0
  26. pynapse/evm/__init__.py +3 -0
  27. pynapse/evm/client.py +26 -0
  28. pynapse/filbeam/__init__.py +3 -0
  29. pynapse/filbeam/service.py +39 -0
  30. pynapse/payments/__init__.py +17 -0
  31. pynapse/payments/service.py +826 -0
  32. pynapse/pdp/__init__.py +21 -0
  33. pynapse/pdp/server.py +331 -0
  34. pynapse/pdp/types.py +38 -0
  35. pynapse/pdp/verifier.py +82 -0
  36. pynapse/retriever/__init__.py +12 -0
  37. pynapse/retriever/async_chain.py +227 -0
  38. pynapse/retriever/chain.py +209 -0
  39. pynapse/session/__init__.py +12 -0
  40. pynapse/session/key.py +30 -0
  41. pynapse/session/permissions.py +57 -0
  42. pynapse/session/registry.py +90 -0
  43. pynapse/sp_registry/__init__.py +11 -0
  44. pynapse/sp_registry/capabilities.py +25 -0
  45. pynapse/sp_registry/pdp_capabilities.py +102 -0
  46. pynapse/sp_registry/service.py +446 -0
  47. pynapse/sp_registry/types.py +52 -0
  48. pynapse/storage/__init__.py +57 -0
  49. pynapse/storage/async_context.py +682 -0
  50. pynapse/storage/async_manager.py +757 -0
  51. pynapse/storage/context.py +680 -0
  52. pynapse/storage/manager.py +758 -0
  53. pynapse/synapse.py +191 -0
  54. pynapse/utils/__init__.py +25 -0
  55. pynapse/utils/constants.py +25 -0
  56. pynapse/utils/errors.py +3 -0
  57. pynapse/utils/metadata.py +35 -0
  58. pynapse/utils/piece_url.py +16 -0
  59. pynapse/warm_storage/__init__.py +13 -0
  60. pynapse/warm_storage/service.py +513 -0
  61. synapse_filecoin_sdk-0.1.0.dist-info/METADATA +74 -0
  62. synapse_filecoin_sdk-0.1.0.dist-info/RECORD +64 -0
  63. synapse_filecoin_sdk-0.1.0.dist-info/WHEEL +4 -0
  64. synapse_filecoin_sdk-0.1.0.dist-info/licenses/LICENSE.md +228 -0
@@ -0,0 +1,102 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Dict, List, Tuple
4
+
5
+ from multiformats import multibase
6
+ from web3 import Web3
7
+
8
+ from .capabilities import capabilities_list_to_object, decode_address_capability
9
+ from .types import PDPOffering, ProviderWithProduct
10
+
11
+ CAP_SERVICE_URL = "serviceURL"
12
+ CAP_MIN_PIECE_SIZE = "minPieceSizeInBytes"
13
+ CAP_MAX_PIECE_SIZE = "maxPieceSizeInBytes"
14
+ CAP_STORAGE_PRICE = "storagePricePerTibPerDay"
15
+ CAP_MIN_PROVING_PERIOD = "minProvingPeriodInEpochs"
16
+ CAP_LOCATION = "location"
17
+ CAP_PAYMENT_TOKEN = "paymentTokenAddress"
18
+ CAP_IPNI_PIECE = "ipniPiece"
19
+ CAP_IPNI_IPFS = "ipniIpfs"
20
+ CAP_IPNI_PEER_ID = "ipniPeerId"
21
+ CAP_IPNI_PEER_ID_LEGACY = "IPNIPeerID"
22
+
23
+
24
+ def decode_pdp_offering(provider: ProviderWithProduct) -> PDPOffering:
25
+ capabilities = capabilities_list_to_object(provider.product.capability_keys, provider.product_capability_values)
26
+ return decode_pdp_capabilities(capabilities)
27
+
28
+
29
+ def _hex_to_int(hex_value: str) -> int:
30
+ return int(hex_value, 16)
31
+
32
+
33
+ def _hex_to_str(hex_value: str) -> str:
34
+ return Web3.to_text(hexstr=hex_value)
35
+
36
+
37
+ def decode_pdp_capabilities(capabilities: Dict[str, str]) -> PDPOffering:
38
+ required = {
39
+ "service_url": _hex_to_str(capabilities[CAP_SERVICE_URL]),
40
+ "min_piece_size_in_bytes": _hex_to_int(capabilities[CAP_MIN_PIECE_SIZE]),
41
+ "max_piece_size_in_bytes": _hex_to_int(capabilities[CAP_MAX_PIECE_SIZE]),
42
+ "storage_price_per_tib_per_day": _hex_to_int(capabilities[CAP_STORAGE_PRICE]),
43
+ "min_proving_period_in_epochs": _hex_to_int(capabilities[CAP_MIN_PROVING_PERIOD]),
44
+ "location": _hex_to_str(capabilities[CAP_LOCATION]),
45
+ "payment_token_address": decode_address_capability(capabilities[CAP_PAYMENT_TOKEN]),
46
+ }
47
+ ipni_piece = capabilities.get(CAP_IPNI_PIECE) == "0x01"
48
+ ipni_ipfs = capabilities.get(CAP_IPNI_IPFS) == "0x01"
49
+ peer_hex = capabilities.get(CAP_IPNI_PEER_ID) or capabilities.get(CAP_IPNI_PEER_ID_LEGACY)
50
+ ipni_peer_id = None
51
+ if peer_hex:
52
+ try:
53
+ ipni_peer_id = multibase.encode("base58btc", Web3.to_bytes(hexstr=peer_hex)).decode()
54
+ except Exception:
55
+ ipni_peer_id = None
56
+ return PDPOffering(
57
+ ipni_piece=ipni_piece,
58
+ ipni_ipfs=ipni_ipfs,
59
+ ipni_peer_id=ipni_peer_id,
60
+ **required,
61
+ )
62
+
63
+
64
+ def encode_pdp_capabilities(pdp_offering: PDPOffering, capabilities: Dict[str, str] | None = None) -> Tuple[List[str], List[bytes]]:
65
+ keys: List[str] = []
66
+ values: List[bytes] = []
67
+
68
+ def add(key: str, value: bytes):
69
+ keys.append(key)
70
+ values.append(value)
71
+
72
+ add(CAP_SERVICE_URL, Web3.to_bytes(text=pdp_offering.service_url))
73
+ add(CAP_MIN_PIECE_SIZE, pdp_offering.min_piece_size_in_bytes.to_bytes(32, "big"))
74
+ add(CAP_MAX_PIECE_SIZE, pdp_offering.max_piece_size_in_bytes.to_bytes(32, "big"))
75
+ if pdp_offering.ipni_piece:
76
+ add(CAP_IPNI_PIECE, b"\x01")
77
+ if pdp_offering.ipni_ipfs:
78
+ add(CAP_IPNI_IPFS, b"\x01")
79
+ add(CAP_STORAGE_PRICE, pdp_offering.storage_price_per_tib_per_day.to_bytes(32, "big"))
80
+ add(CAP_MIN_PROVING_PERIOD, pdp_offering.min_proving_period_in_epochs.to_bytes(32, "big"))
81
+ add(CAP_LOCATION, Web3.to_bytes(text=pdp_offering.location))
82
+ add(CAP_PAYMENT_TOKEN, Web3.to_bytes(hexstr=pdp_offering.payment_token_address))
83
+
84
+ if pdp_offering.ipni_peer_id:
85
+ try:
86
+ peer_bytes = multibase.decode(pdp_offering.ipni_peer_id)
87
+ add(CAP_IPNI_PEER_ID, peer_bytes)
88
+ except Exception:
89
+ pass
90
+
91
+ if capabilities:
92
+ for key, value in capabilities.items():
93
+ keys.append(key)
94
+ if value is None or value == "":
95
+ values.append(b"\x01")
96
+ else:
97
+ if value.startswith("0x"):
98
+ values.append(Web3.to_bytes(hexstr=value))
99
+ else:
100
+ values.append(Web3.to_bytes(text=value))
101
+
102
+ return keys, values
@@ -0,0 +1,446 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import List, Optional, Tuple
5
+
6
+ from eth_account import Account
7
+ from web3 import AsyncWeb3, Web3
8
+
9
+ from pynapse.contracts import SERVICE_PROVIDER_REGISTRY_ABI
10
+ from pynapse.core.chains import Chain
11
+ from .pdp_capabilities import encode_pdp_capabilities
12
+ from .types import PDPOffering, ProviderInfo, ProviderRegistrationInfo, ProviderWithProduct, ServiceProduct
13
+
14
+
15
+ class SyncSPRegistryService:
16
+ def __init__(self, web3: Web3, chain: Chain, private_key: Optional[str] = None) -> None:
17
+ self._web3 = web3
18
+ self._chain = chain
19
+ self._private_key = private_key
20
+ self._contract = web3.eth.contract(address=chain.contracts.sp_registry, abi=SERVICE_PROVIDER_REGISTRY_ABI)
21
+
22
+ def get_provider(self, provider_id: int) -> ProviderInfo:
23
+ info = self._contract.functions.getProvider(provider_id).call()
24
+ provider_id = int(info[0])
25
+ inner = info[1]
26
+ return ProviderInfo(
27
+ provider_id=provider_id,
28
+ service_provider=inner[0],
29
+ payee=inner[1],
30
+ name=inner[2],
31
+ description=inner[3],
32
+ is_active=inner[4],
33
+ )
34
+
35
+ def get_provider_by_address(self, address: str) -> Optional[ProviderInfo]:
36
+ info = self._contract.functions.getProviderByAddress(address).call()
37
+ provider_id = int(info[0])
38
+ if provider_id == 0:
39
+ return None
40
+ inner = info[1]
41
+ return ProviderInfo(
42
+ provider_id=provider_id,
43
+ service_provider=inner[0],
44
+ payee=inner[1],
45
+ name=inner[2],
46
+ description=inner[3],
47
+ is_active=inner[4],
48
+ )
49
+
50
+ def get_provider_id_by_address(self, address: str) -> int:
51
+ return int(self._contract.functions.getProviderIdByAddress(address).call())
52
+
53
+ def get_provider_count(self) -> int:
54
+ return int(self._contract.functions.getProviderCount().call())
55
+
56
+ def is_provider_active(self, provider_id: int) -> bool:
57
+ return bool(self._contract.functions.isProviderActive(provider_id).call())
58
+
59
+ def is_registered_provider(self, address: str) -> bool:
60
+ return bool(self._contract.functions.isRegisteredProvider(address).call())
61
+
62
+ def get_provider_with_product(self, provider_id: int, product_type: int) -> ProviderWithProduct:
63
+ data = self._contract.functions.getProviderWithProduct(provider_id, product_type).call()
64
+ provider_id = int(data[0])
65
+ provider_info_tuple = data[1]
66
+ product_tuple = data[2]
67
+ values = data[3]
68
+
69
+ provider_info = ProviderInfo(
70
+ provider_id=provider_id,
71
+ service_provider=provider_info_tuple[0],
72
+ payee=provider_info_tuple[1],
73
+ name=provider_info_tuple[2],
74
+ description=provider_info_tuple[3],
75
+ is_active=provider_info_tuple[4],
76
+ )
77
+ product = ServiceProduct(
78
+ product_type=int(product_tuple[0]),
79
+ capability_keys=list(product_tuple[1]),
80
+ is_active=product_tuple[2],
81
+ )
82
+ return ProviderWithProduct(
83
+ provider_id=provider_id,
84
+ provider_info=provider_info,
85
+ product=product,
86
+ product_capability_values=list(values),
87
+ )
88
+
89
+ def get_providers_by_product_type(self, product_type: int, only_active: bool, offset: int, limit: int):
90
+ result = self._contract.functions.getProvidersByProductType(product_type, only_active, offset, limit).call()
91
+ providers = []
92
+ for item in result[0]:
93
+ providers.append(self._convert_provider_with_product(item))
94
+ return providers, bool(result[1])
95
+
96
+ def get_all_active_providers(self) -> List[ProviderInfo]:
97
+ providers: List[ProviderInfo] = []
98
+ limit = 50
99
+ offset = 0
100
+ has_more = True
101
+ while has_more:
102
+ result = self._contract.functions.getAllActiveProviders(offset, limit).call()
103
+ for info in result[0]:
104
+ providers.append(
105
+ ProviderInfo(
106
+ provider_id=int(info[0]),
107
+ service_provider=info[1][0],
108
+ payee=info[1][1],
109
+ name=info[1][2],
110
+ description=info[1][3],
111
+ is_active=info[1][4],
112
+ )
113
+ )
114
+ has_more = bool(result[1])
115
+ offset += limit
116
+ return providers
117
+
118
+ def register_provider(self, account: str, info: ProviderRegistrationInfo, product_type: int = 1) -> str:
119
+ if not self._private_key:
120
+ raise ValueError("private_key required for register_provider")
121
+ keys, values = encode_pdp_capabilities(info.pdp_offering, info.capabilities)
122
+ txn = self._contract.functions.registerProvider(
123
+ info.payee,
124
+ info.name,
125
+ info.description,
126
+ product_type,
127
+ keys,
128
+ values,
129
+ ).build_transaction(
130
+ {
131
+ "from": account,
132
+ "nonce": self._web3.eth.get_transaction_count(account),
133
+ }
134
+ )
135
+ signed = self._web3.eth.account.sign_transaction(txn, private_key=self._private_key)
136
+ tx_hash = self._web3.eth.send_raw_transaction(signed.rawTransaction)
137
+ return tx_hash.hex()
138
+
139
+ def update_provider_info(self, account: str, name: str, description: str) -> str:
140
+ if not self._private_key:
141
+ raise ValueError("private_key required for update_provider_info")
142
+ txn = self._contract.functions.updateProviderInfo(name, description).build_transaction(
143
+ {
144
+ "from": account,
145
+ "nonce": self._web3.eth.get_transaction_count(account),
146
+ }
147
+ )
148
+ signed = self._web3.eth.account.sign_transaction(txn, private_key=self._private_key)
149
+ tx_hash = self._web3.eth.send_raw_transaction(signed.rawTransaction)
150
+ return tx_hash.hex()
151
+
152
+ def remove_provider(self, account: str) -> str:
153
+ if not self._private_key:
154
+ raise ValueError("private_key required for remove_provider")
155
+ txn = self._contract.functions.removeProvider().build_transaction(
156
+ {
157
+ "from": account,
158
+ "nonce": self._web3.eth.get_transaction_count(account),
159
+ }
160
+ )
161
+ signed = self._web3.eth.account.sign_transaction(txn, private_key=self._private_key)
162
+ tx_hash = self._web3.eth.send_raw_transaction(signed.rawTransaction)
163
+ return tx_hash.hex()
164
+
165
+ def add_product(self, account: str, product_type: int, pdp_offering: PDPOffering, capabilities: Optional[dict] = None) -> str:
166
+ if not self._private_key:
167
+ raise ValueError("private_key required for add_product")
168
+ keys, values = encode_pdp_capabilities(pdp_offering, capabilities)
169
+ txn = self._contract.functions.addProduct(product_type, keys, values).build_transaction(
170
+ {
171
+ "from": account,
172
+ "nonce": self._web3.eth.get_transaction_count(account),
173
+ }
174
+ )
175
+ signed = self._web3.eth.account.sign_transaction(txn, private_key=self._private_key)
176
+ tx_hash = self._web3.eth.send_raw_transaction(signed.rawTransaction)
177
+ return tx_hash.hex()
178
+
179
+ def update_product(self, account: str, product_type: int, pdp_offering: PDPOffering, capabilities: Optional[dict] = None) -> str:
180
+ if not self._private_key:
181
+ raise ValueError("private_key required for update_product")
182
+ keys, values = encode_pdp_capabilities(pdp_offering, capabilities)
183
+ txn = self._contract.functions.updateProduct(product_type, keys, values).build_transaction(
184
+ {
185
+ "from": account,
186
+ "nonce": self._web3.eth.get_transaction_count(account),
187
+ }
188
+ )
189
+ signed = self._web3.eth.account.sign_transaction(txn, private_key=self._private_key)
190
+ tx_hash = self._web3.eth.send_raw_transaction(signed.rawTransaction)
191
+ return tx_hash.hex()
192
+
193
+ def remove_product(self, account: str, product_type: int) -> str:
194
+ if not self._private_key:
195
+ raise ValueError("private_key required for remove_product")
196
+ txn = self._contract.functions.removeProduct(product_type).build_transaction(
197
+ {
198
+ "from": account,
199
+ "nonce": self._web3.eth.get_transaction_count(account),
200
+ }
201
+ )
202
+ signed = self._web3.eth.account.sign_transaction(txn, private_key=self._private_key)
203
+ tx_hash = self._web3.eth.send_raw_transaction(signed.rawTransaction)
204
+ return tx_hash.hex()
205
+
206
+ def _convert_provider_with_product(self, data) -> ProviderWithProduct:
207
+ provider_id = int(data[0])
208
+ provider_info_tuple = data[1]
209
+ product_tuple = data[2]
210
+ values = data[3]
211
+ provider_info = ProviderInfo(
212
+ provider_id=provider_id,
213
+ service_provider=provider_info_tuple[0],
214
+ payee=provider_info_tuple[1],
215
+ name=provider_info_tuple[2],
216
+ description=provider_info_tuple[3],
217
+ is_active=provider_info_tuple[4],
218
+ )
219
+ product = ServiceProduct(
220
+ product_type=int(product_tuple[0]),
221
+ capability_keys=list(product_tuple[1]),
222
+ is_active=product_tuple[2],
223
+ )
224
+ return ProviderWithProduct(
225
+ provider_id=provider_id,
226
+ provider_info=provider_info,
227
+ product=product,
228
+ product_capability_values=list(values),
229
+ )
230
+
231
+
232
+ class AsyncSPRegistryService:
233
+ def __init__(self, web3: AsyncWeb3, chain: Chain, private_key: Optional[str] = None) -> None:
234
+ self._web3 = web3
235
+ self._chain = chain
236
+ self._private_key = private_key
237
+ self._contract = web3.eth.contract(address=chain.contracts.sp_registry, abi=SERVICE_PROVIDER_REGISTRY_ABI)
238
+
239
+ async def get_provider(self, provider_id: int) -> ProviderInfo:
240
+ info = await self._contract.functions.getProvider(provider_id).call()
241
+ provider_id = int(info[0])
242
+ inner = info[1]
243
+ return ProviderInfo(
244
+ provider_id=provider_id,
245
+ service_provider=inner[0],
246
+ payee=inner[1],
247
+ name=inner[2],
248
+ description=inner[3],
249
+ is_active=inner[4],
250
+ )
251
+
252
+ async def get_provider_by_address(self, address: str) -> Optional[ProviderInfo]:
253
+ info = await self._contract.functions.getProviderByAddress(address).call()
254
+ provider_id = int(info[0])
255
+ if provider_id == 0:
256
+ return None
257
+ inner = info[1]
258
+ return ProviderInfo(
259
+ provider_id=provider_id,
260
+ service_provider=inner[0],
261
+ payee=inner[1],
262
+ name=inner[2],
263
+ description=inner[3],
264
+ is_active=inner[4],
265
+ )
266
+
267
+ async def get_provider_id_by_address(self, address: str) -> int:
268
+ return int(await self._contract.functions.getProviderIdByAddress(address).call())
269
+
270
+ async def get_provider_count(self) -> int:
271
+ return int(await self._contract.functions.getProviderCount().call())
272
+
273
+ async def is_provider_active(self, provider_id: int) -> bool:
274
+ return bool(await self._contract.functions.isProviderActive(provider_id).call())
275
+
276
+ async def is_registered_provider(self, address: str) -> bool:
277
+ return bool(await self._contract.functions.isRegisteredProvider(address).call())
278
+
279
+ async def get_provider_with_product(self, provider_id: int, product_type: int) -> ProviderWithProduct:
280
+ data = await self._contract.functions.getProviderWithProduct(provider_id, product_type).call()
281
+ provider_id = int(data[0])
282
+ provider_info_tuple = data[1]
283
+ product_tuple = data[2]
284
+ values = data[3]
285
+
286
+ provider_info = ProviderInfo(
287
+ provider_id=provider_id,
288
+ service_provider=provider_info_tuple[0],
289
+ payee=provider_info_tuple[1],
290
+ name=provider_info_tuple[2],
291
+ description=provider_info_tuple[3],
292
+ is_active=provider_info_tuple[4],
293
+ )
294
+ product = ServiceProduct(
295
+ product_type=int(product_tuple[0]),
296
+ capability_keys=list(product_tuple[1]),
297
+ is_active=product_tuple[2],
298
+ )
299
+ return ProviderWithProduct(
300
+ provider_id=provider_id,
301
+ provider_info=provider_info,
302
+ product=product,
303
+ product_capability_values=list(values),
304
+ )
305
+
306
+ async def get_providers_by_product_type(self, product_type: int, only_active: bool, offset: int, limit: int):
307
+ result = await self._contract.functions.getProvidersByProductType(product_type, only_active, offset, limit).call()
308
+ providers = []
309
+ for item in result[0]:
310
+ providers.append(self._convert_provider_with_product(item))
311
+ return providers, bool(result[1])
312
+
313
+ async def get_all_active_providers(self) -> List[ProviderInfo]:
314
+ providers: List[ProviderInfo] = []
315
+ limit = 50
316
+ offset = 0
317
+ has_more = True
318
+ while has_more:
319
+ result = await self._contract.functions.getAllActiveProviders(offset, limit).call()
320
+ for info in result[0]:
321
+ providers.append(
322
+ ProviderInfo(
323
+ provider_id=int(info[0]),
324
+ service_provider=info[1][0],
325
+ payee=info[1][1],
326
+ name=info[1][2],
327
+ description=info[1][3],
328
+ is_active=info[1][4],
329
+ )
330
+ )
331
+ has_more = bool(result[1])
332
+ offset += limit
333
+ return providers
334
+
335
+ async def register_provider(self, account: str, info: ProviderRegistrationInfo, product_type: int = 1) -> str:
336
+ if not self._private_key:
337
+ raise ValueError("private_key required for register_provider")
338
+ keys, values = encode_pdp_capabilities(info.pdp_offering, info.capabilities)
339
+ txn = await self._contract.functions.registerProvider(
340
+ info.payee,
341
+ info.name,
342
+ info.description,
343
+ product_type,
344
+ keys,
345
+ values,
346
+ ).build_transaction(
347
+ {
348
+ "from": account,
349
+ "nonce": await self._web3.eth.get_transaction_count(account),
350
+ }
351
+ )
352
+ signed = Account.sign_transaction(txn, private_key=self._private_key)
353
+ tx_hash = await self._web3.eth.send_raw_transaction(signed.rawTransaction)
354
+ return tx_hash.hex()
355
+
356
+ async def update_provider_info(self, account: str, name: str, description: str) -> str:
357
+ if not self._private_key:
358
+ raise ValueError("private_key required for update_provider_info")
359
+ txn = await self._contract.functions.updateProviderInfo(name, description).build_transaction(
360
+ {
361
+ "from": account,
362
+ "nonce": await self._web3.eth.get_transaction_count(account),
363
+ }
364
+ )
365
+ signed = Account.sign_transaction(txn, private_key=self._private_key)
366
+ tx_hash = await self._web3.eth.send_raw_transaction(signed.rawTransaction)
367
+ return tx_hash.hex()
368
+
369
+ async def remove_provider(self, account: str) -> str:
370
+ if not self._private_key:
371
+ raise ValueError("private_key required for remove_provider")
372
+ txn = await self._contract.functions.removeProvider().build_transaction(
373
+ {
374
+ "from": account,
375
+ "nonce": await self._web3.eth.get_transaction_count(account),
376
+ }
377
+ )
378
+ signed = Account.sign_transaction(txn, private_key=self._private_key)
379
+ tx_hash = await self._web3.eth.send_raw_transaction(signed.rawTransaction)
380
+ return tx_hash.hex()
381
+
382
+ async def add_product(self, account: str, product_type: int, pdp_offering: PDPOffering, capabilities: Optional[dict] = None) -> str:
383
+ if not self._private_key:
384
+ raise ValueError("private_key required for add_product")
385
+ keys, values = encode_pdp_capabilities(pdp_offering, capabilities)
386
+ txn = await self._contract.functions.addProduct(product_type, keys, values).build_transaction(
387
+ {
388
+ "from": account,
389
+ "nonce": await self._web3.eth.get_transaction_count(account),
390
+ }
391
+ )
392
+ signed = Account.sign_transaction(txn, private_key=self._private_key)
393
+ tx_hash = await self._web3.eth.send_raw_transaction(signed.rawTransaction)
394
+ return tx_hash.hex()
395
+
396
+ async def update_product(self, account: str, product_type: int, pdp_offering: PDPOffering, capabilities: Optional[dict] = None) -> str:
397
+ if not self._private_key:
398
+ raise ValueError("private_key required for update_product")
399
+ keys, values = encode_pdp_capabilities(pdp_offering, capabilities)
400
+ txn = await self._contract.functions.updateProduct(product_type, keys, values).build_transaction(
401
+ {
402
+ "from": account,
403
+ "nonce": await self._web3.eth.get_transaction_count(account),
404
+ }
405
+ )
406
+ signed = Account.sign_transaction(txn, private_key=self._private_key)
407
+ tx_hash = await self._web3.eth.send_raw_transaction(signed.rawTransaction)
408
+ return tx_hash.hex()
409
+
410
+ async def remove_product(self, account: str, product_type: int) -> str:
411
+ if not self._private_key:
412
+ raise ValueError("private_key required for remove_product")
413
+ txn = await self._contract.functions.removeProduct(product_type).build_transaction(
414
+ {
415
+ "from": account,
416
+ "nonce": await self._web3.eth.get_transaction_count(account),
417
+ }
418
+ )
419
+ signed = Account.sign_transaction(txn, private_key=self._private_key)
420
+ tx_hash = await self._web3.eth.send_raw_transaction(signed.rawTransaction)
421
+ return tx_hash.hex()
422
+
423
+ def _convert_provider_with_product(self, data) -> ProviderWithProduct:
424
+ provider_id = int(data[0])
425
+ provider_info_tuple = data[1]
426
+ product_tuple = data[2]
427
+ values = data[3]
428
+ provider_info = ProviderInfo(
429
+ provider_id=provider_id,
430
+ service_provider=provider_info_tuple[0],
431
+ payee=provider_info_tuple[1],
432
+ name=provider_info_tuple[2],
433
+ description=provider_info_tuple[3],
434
+ is_active=provider_info_tuple[4],
435
+ )
436
+ product = ServiceProduct(
437
+ product_type=int(product_tuple[0]),
438
+ capability_keys=list(product_tuple[1]),
439
+ is_active=product_tuple[2],
440
+ )
441
+ return ProviderWithProduct(
442
+ provider_id=provider_id,
443
+ provider_info=provider_info,
444
+ product=product,
445
+ product_capability_values=list(values),
446
+ )
@@ -0,0 +1,52 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Dict, List, Optional
5
+
6
+
7
+ @dataclass
8
+ class ProviderInfo:
9
+ provider_id: int
10
+ service_provider: str
11
+ payee: str
12
+ name: str
13
+ description: str
14
+ is_active: bool
15
+
16
+
17
+ @dataclass
18
+ class ServiceProduct:
19
+ product_type: int
20
+ capability_keys: List[str]
21
+ is_active: bool
22
+
23
+
24
+ @dataclass
25
+ class ProviderWithProduct:
26
+ provider_id: int
27
+ provider_info: ProviderInfo
28
+ product: ServiceProduct
29
+ product_capability_values: List[bytes]
30
+
31
+
32
+ @dataclass
33
+ class PDPOffering:
34
+ service_url: str
35
+ min_piece_size_in_bytes: int
36
+ max_piece_size_in_bytes: int
37
+ storage_price_per_tib_per_day: int
38
+ min_proving_period_in_epochs: int
39
+ location: str
40
+ payment_token_address: str
41
+ ipni_piece: bool = False
42
+ ipni_ipfs: bool = False
43
+ ipni_peer_id: Optional[str] = None
44
+
45
+
46
+ @dataclass
47
+ class ProviderRegistrationInfo:
48
+ payee: str
49
+ name: str
50
+ description: str
51
+ pdp_offering: PDPOffering
52
+ capabilities: Optional[Dict[str, str]] = None
@@ -0,0 +1,57 @@
1
+ from .context import (
2
+ ProviderSelectionResult,
3
+ StorageContext,
4
+ StorageContextOptions,
5
+ UploadResult,
6
+ )
7
+ from .manager import (
8
+ DataSetMatch,
9
+ PreflightInfo,
10
+ ProviderFilter,
11
+ ServiceParameters,
12
+ StorageInfo,
13
+ StorageManager,
14
+ StoragePricing,
15
+ )
16
+ from .async_context import (
17
+ AsyncProviderSelectionResult,
18
+ AsyncStorageContext,
19
+ AsyncStorageContextOptions,
20
+ AsyncUploadResult,
21
+ )
22
+ from .async_manager import (
23
+ AsyncDataSetMatch,
24
+ AsyncPreflightInfo,
25
+ AsyncProviderFilter,
26
+ AsyncServiceParameters,
27
+ AsyncStorageInfo,
28
+ AsyncStorageManager,
29
+ AsyncStoragePricing,
30
+ )
31
+
32
+ __all__ = [
33
+ # Sync classes
34
+ "DataSetMatch",
35
+ "PreflightInfo",
36
+ "ProviderFilter",
37
+ "ProviderSelectionResult",
38
+ "ServiceParameters",
39
+ "StorageContext",
40
+ "StorageContextOptions",
41
+ "StorageInfo",
42
+ "StorageManager",
43
+ "StoragePricing",
44
+ "UploadResult",
45
+ # Async classes
46
+ "AsyncDataSetMatch",
47
+ "AsyncPreflightInfo",
48
+ "AsyncProviderFilter",
49
+ "AsyncProviderSelectionResult",
50
+ "AsyncServiceParameters",
51
+ "AsyncStorageContext",
52
+ "AsyncStorageContextOptions",
53
+ "AsyncStorageInfo",
54
+ "AsyncStorageManager",
55
+ "AsyncStoragePricing",
56
+ "AsyncUploadResult",
57
+ ]