mech-client 0.3.0__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 (33) hide show
  1. mech_client/__init__.py +1 -1
  2. mech_client/abis/AgentMech.json +718 -0
  3. mech_client/abis/AgentRegistry.json +1037 -0
  4. mech_client/abis/AgreementStoreManager.base.json +766 -0
  5. mech_client/abis/AgreementStoreManager.gnosis.json +766 -0
  6. mech_client/abis/BalanceTrackerNvmSubscriptionToken.json +660 -0
  7. mech_client/abis/DIDRegistry.base.json +2476 -0
  8. mech_client/abis/DIDRegistry.gnosis.json +2476 -0
  9. mech_client/abis/EscrowPaymentCondition.base.json +717 -0
  10. mech_client/abis/EscrowPaymentCondition.gnosis.json +717 -0
  11. mech_client/abis/LockPaymentCondition.base.json +874 -0
  12. mech_client/abis/LockPaymentCondition.gnosis.json +874 -0
  13. mech_client/abis/NFTSalesTemplate.base.json +698 -0
  14. mech_client/abis/NFTSalesTemplate.gnosis.json +698 -0
  15. mech_client/abis/NeverminedConfig.base.json +587 -0
  16. mech_client/abis/NeverminedConfig.gnosis.json +587 -0
  17. mech_client/abis/SubscriptionNFT.base.json +300 -0
  18. mech_client/abis/SubscriptionNFT.gnosis.json +300 -0
  19. mech_client/abis/SubscriptionToken.base.json +1393 -0
  20. mech_client/abis/TransferNFTCondition.base.json +1062 -0
  21. mech_client/abis/TransferNFTCondition.gnosis.json +1062 -0
  22. mech_client/cli.py +99 -10
  23. mech_client/configs/mechs.json +3 -9
  24. mech_client/interact.py +14 -39
  25. mech_client/marketplace_interact.py +199 -156
  26. mech_client/mech_tool_management.py +11 -5
  27. mech_client/subgraph.py +21 -35
  28. mech_client/wss.py +7 -6
  29. {mech_client-0.3.0.dist-info → mech_client-0.6.0.dist-info}/METADATA +45 -13
  30. {mech_client-0.3.0.dist-info → mech_client-0.6.0.dist-info}/RECORD +33 -13
  31. {mech_client-0.3.0.dist-info → mech_client-0.6.0.dist-info}/LICENSE +0 -0
  32. {mech_client-0.3.0.dist-info → mech_client-0.6.0.dist-info}/WHEEL +0 -0
  33. {mech_client-0.3.0.dist-info → mech_client-0.6.0.dist-info}/entry_points.txt +0 -0
@@ -26,8 +26,9 @@ import sys
26
26
  import time
27
27
  from dataclasses import asdict, make_dataclass
28
28
  from datetime import datetime
29
+ from enum import Enum
29
30
  from pathlib import Path
30
- from typing import Any, Dict, List, Optional, Tuple, cast
31
+ from typing import Any, Dict, Optional, Tuple, cast
31
32
 
32
33
  import requests
33
34
  import websocket
@@ -45,8 +46,8 @@ from mech_client.interact import (
45
46
  PRIVATE_KEY_FILE_PATH,
46
47
  TIMEOUT,
47
48
  WAIT_SLEEP,
48
- calculate_topic_id,
49
49
  get_contract,
50
+ get_event_signatures,
50
51
  get_mech_config,
51
52
  )
52
53
  from mech_client.prompt_to_ipfs import push_metadata_to_ipfs
@@ -54,54 +55,70 @@ from mech_client.wss import (
54
55
  register_event_handlers,
55
56
  wait_for_receipt,
56
57
  watch_for_marketplace_data_url_from_wss,
57
- watch_for_marketplace_request_id,
58
+ watch_for_marketplace_request_ids,
58
59
  )
59
60
 
60
61
 
61
62
  # false positives for [B105:hardcoded_password_string] Possible hardcoded password
62
- PAYMENT_TYPE_NATIVE = (
63
- "ba699a34be8fe0e7725e93dcbce1701b0211a8ca61330aaeb8a05bf2ec7abed1" # nosec
64
- )
65
- PAYMENT_TYPE_TOKEN = (
66
- "3679d66ef546e66ce9057c4a052f317b135bc8e8c509638f7966edfd4fcf45e9" # nosec
63
+ class PaymentType(Enum):
64
+ """Payment type."""
65
+
66
+ NATIVE = "ba699a34be8fe0e7725e93dcbce1701b0211a8ca61330aaeb8a05bf2ec7abed1" # nosec
67
+ TOKEN = "3679d66ef546e66ce9057c4a052f317b135bc8e8c509638f7966edfd4fcf45e9" # nosec
68
+ NATIVE_NVM = (
69
+ "803dd08fe79d91027fc9024e254a0942372b92f3ccabc1bd19f4a5c2b251c316" # nosec
70
+ )
71
+ TOKEN_NVM = (
72
+ "0d6fd99afa9c4c580fab5e341922c2a5c4b61d880da60506193d7bf88944dd14" # nosec
73
+ )
74
+
75
+
76
+ IPFS_URL_TEMPLATE = "https://gateway.autonolas.tech/ipfs/f01701220{}"
77
+ ABI_DIR_PATH = Path(__file__).parent / "abis"
78
+ IMECH_ABI_PATH = ABI_DIR_PATH / "IMech.json"
79
+ ITOKEN_ABI_PATH = ABI_DIR_PATH / "IToken.json"
80
+ IERC1155_ABI_PATH = ABI_DIR_PATH / "IERC1155.json"
81
+ MARKETPLACE_ABI_PATH = ABI_DIR_PATH / "MechMarketplace.json"
82
+
83
+ BALANCE_TRACKER_NATIVE_ABI_PATH = ABI_DIR_PATH / "BalanceTrackerFixedPriceNative.json"
84
+ BALANCE_TRACKER_TOKEN_ABI_PATH = ABI_DIR_PATH / "BalanceTrackerFixedPriceToken.json"
85
+ BALANCE_TRACKER_NVM_NATIVE_ABI_PATH = (
86
+ ABI_DIR_PATH / "BalanceTrackerNvmSubscriptionNative.json"
67
87
  )
68
- PAYMENT_TYPE_NVM = (
69
- "803dd08fe79d91027fc9024e254a0942372b92f3ccabc1bd19f4a5c2b251c316" # nosec
88
+ BALANCE_TRACKER_NVM_TOKEN_ABI_PATH = (
89
+ ABI_DIR_PATH / "BalanceTrackerNvmSubscriptionToken.json"
70
90
  )
71
91
 
72
- CHAIN_TO_WRAPPED_TOKEN = {
73
- 1: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
74
- 10: "0x4200000000000000000000000000000000000006",
75
- 100: "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d",
76
- 137: "0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270",
77
- 8453: "0x4200000000000000000000000000000000000006",
78
- 42220: "0x471EcE3750Da237f93B8E339c536989b8978a438",
92
+
93
+ PAYMENT_TYPE_TO_ABI_PATH: Dict[str, Path] = {
94
+ PaymentType.NATIVE.value: BALANCE_TRACKER_NATIVE_ABI_PATH,
95
+ PaymentType.TOKEN.value: BALANCE_TRACKER_TOKEN_ABI_PATH,
96
+ PaymentType.NATIVE_NVM.value: BALANCE_TRACKER_NVM_NATIVE_ABI_PATH,
97
+ PaymentType.TOKEN_NVM.value: BALANCE_TRACKER_NVM_TOKEN_ABI_PATH,
98
+ }
99
+
100
+ CHAIN_TO_PRICE_TOKEN = {
101
+ 1: "0x0001A500A6B18995B03f44bb040A5fFc28E45CB0",
102
+ 10: "0xFC2E6e6BCbd49ccf3A5f029c79984372DcBFE527",
103
+ 100: "0xcE11e14225575945b8E6Dc0D4F2dD4C570f79d9f",
104
+ 137: "0xFEF5d947472e72Efbb2E388c730B7428406F2F95",
105
+ 8453: "0x54330d28ca3357F294334BDC454a032e7f353416",
106
+ 42220: "0xFEF5d947472e72Efbb2E388c730B7428406F2F95",
79
107
  }
80
108
 
81
109
 
82
110
  CHAIN_TO_DEFAULT_MECH_MARKETPLACE_REQUEST_CONFIG = {
83
111
  100: {
84
- "mech_marketplace_contract": "0x735FAAb1c4Ec41128c367AFb5c3baC73509f70bB",
85
- "priority_mech_address": "0x478ad20eD958dCC5AD4ABa6F4E4cc51e07a840E4",
86
112
  "response_timeout": 300,
87
113
  "payment_data": "0x",
88
- }
114
+ },
115
+ 8453: {
116
+ "response_timeout": 300,
117
+ "payment_data": "0x",
118
+ },
89
119
  }
90
120
 
91
121
 
92
- def get_event_signatures(abi: List) -> Tuple[str, str]:
93
- """Calculate `Marketplace Request` and `Marketplace Deliver` event topics"""
94
- marketplace_request, marketplace_deliver = "", ""
95
- for obj in abi:
96
- if obj["type"] != "event":
97
- continue
98
- if obj["name"] == "MarketplaceDeliver":
99
- marketplace_deliver = calculate_topic_id(event=obj)
100
- if obj["name"] == "MarketplaceRequest":
101
- marketplace_request = calculate_topic_id(event=obj)
102
- return marketplace_request, marketplace_deliver
103
-
104
-
105
122
  def fetch_mech_info(
106
123
  ledger_api: EthereumApi,
107
124
  mech_marketplace_contract: Web3Contract,
@@ -120,7 +137,7 @@ def fetch_mech_info(
120
137
  :rtype: Tuple[str, int, int, str, Contract]
121
138
  """
122
139
 
123
- with open(Path(__file__).parent / "abis" / "IMech.json", encoding="utf-8") as f:
140
+ with open(IMECH_ABI_PATH, encoding="utf-8") as f:
124
141
  abi = json.load(f)
125
142
 
126
143
  mech_contract = get_contract(
@@ -137,7 +154,7 @@ def fetch_mech_info(
137
154
  ).call()
138
155
  )
139
156
 
140
- if payment_type not in [PAYMENT_TYPE_NATIVE, PAYMENT_TYPE_TOKEN, PAYMENT_TYPE_NVM]:
157
+ if payment_type not in PaymentType._value2member_map_: # pylint: disable=W0212
141
158
  print(" - Invalid mech type detected.")
142
159
  sys.exit(1)
143
160
 
@@ -175,7 +192,7 @@ def approve_price_tokens(
175
192
  """
176
193
  sender = crypto.address
177
194
 
178
- with open(Path(__file__).parent / "abis" / "IToken.json", encoding="utf-8") as f:
195
+ with open(ITOKEN_ABI_PATH, encoding="utf-8") as f:
179
196
  abi = json.load(f)
180
197
 
181
198
  token_contract = get_contract(
@@ -210,6 +227,7 @@ def fetch_requester_nvm_subscription_balance(
210
227
  requester: str,
211
228
  ledger_api: EthereumApi,
212
229
  mech_payment_balance_tracker: str,
230
+ payment_type: str,
213
231
  ) -> int:
214
232
  """
215
233
  Fetches the requester nvm subscription balance.
@@ -220,11 +238,13 @@ def fetch_requester_nvm_subscription_balance(
220
238
  :type ledger_api: EthereumApi
221
239
  :param mech_payment_balance_tracker: Requested mech's balance tracker contract address
222
240
  :type mech_payment_balance_tracker: str
241
+ :param payment_type: Requested mech's payment type
242
+ :type payment_type: str
223
243
  :return: The requester balance.
224
244
  :rtype: int
225
245
  """
226
246
  with open(
227
- Path(__file__).parent / "abis" / "BalanceTrackerNvmSubscriptionNative.json",
247
+ PAYMENT_TYPE_TO_ABI_PATH[payment_type],
228
248
  encoding="utf-8",
229
249
  ) as f:
230
250
  abi = json.load(f)
@@ -239,10 +259,7 @@ def fetch_requester_nvm_subscription_balance(
239
259
  nvm_balance_tracker_contract.functions.subscriptionTokenId().call()
240
260
  )
241
261
 
242
- with open(
243
- Path(__file__).parent / "abis" / "IERC1155.json",
244
- encoding="utf-8",
245
- ) as f:
262
+ with open(IERC1155_ABI_PATH, encoding="utf-8") as f:
246
263
  abi = json.load(f)
247
264
 
248
265
  subscription_nft_contract = get_contract(
@@ -260,8 +277,8 @@ def send_marketplace_request( # pylint: disable=too-many-arguments,too-many-loc
260
277
  ledger_api: EthereumApi,
261
278
  marketplace_contract: Web3Contract,
262
279
  gas_limit: int,
263
- prompt: str,
264
- tool: str,
280
+ prompts: tuple,
281
+ tools: tuple,
265
282
  method_args_data: MechMarketplaceRequestConfig,
266
283
  extra_attributes: Optional[Dict[str, Any]] = None,
267
284
  price: int = 10_000_000_000_000_000,
@@ -280,10 +297,10 @@ def send_marketplace_request( # pylint: disable=too-many-arguments,too-many-loc
280
297
  :type marketplace_contract: Web3Contract
281
298
  :param gas_limit: Gas limit.
282
299
  :type gas_limit: int
283
- :param prompt: The request prompt.
284
- :type prompt: str
285
- :param tool: The requested tool.
286
- :type tool: str
300
+ :param prompts: The request prompts.
301
+ :type prompts: tuple
302
+ :param tools: The requested tools.
303
+ :type tools: tuple
287
304
  :param method_args_data: Method data to use to call the marketplace contract request
288
305
  :type method_args_data: MechMarketplaceRequestConfig
289
306
  :param extra_attributes: Extra attributes to be included in the request metadata.
@@ -299,21 +316,40 @@ def send_marketplace_request( # pylint: disable=too-many-arguments,too-many-loc
299
316
  :return: The transaction hash.
300
317
  :rtype: Optional[str]
301
318
  """
302
- v1_file_hash_hex_truncated, v1_file_hash_hex = push_metadata_to_ipfs(
303
- prompt, tool, extra_attributes
304
- )
305
- print(
306
- f" - Prompt uploaded: https://gateway.autonolas.tech/ipfs/{v1_file_hash_hex}"
307
- )
308
- method_name = "request"
319
+ num_requests = len(prompts)
320
+
309
321
  method_args = {
310
- "requestData": v1_file_hash_hex_truncated,
311
322
  "maxDeliveryRate": method_args_data.delivery_rate,
312
323
  "paymentType": "0x" + cast(str, method_args_data.payment_type),
313
324
  "priorityMech": to_checksum_address(method_args_data.priority_mech_address),
314
325
  "responseTimeout": method_args_data.response_timeout,
315
326
  "paymentData": method_args_data.payment_data,
316
327
  }
328
+
329
+ if num_requests == 1:
330
+ v1_file_hash_hex_truncated, v1_file_hash_hex = push_metadata_to_ipfs(
331
+ prompts[0], tools[0], extra_attributes
332
+ )
333
+ print(
334
+ f" - Prompt uploaded: https://gateway.autonolas.tech/ipfs/{v1_file_hash_hex}"
335
+ )
336
+ method_name = "request"
337
+ method_args["requestData"] = v1_file_hash_hex_truncated
338
+
339
+ else:
340
+ request_datas = []
341
+ for prompt, tool in zip(prompts, tools):
342
+ v1_file_hash_hex_truncated, v1_file_hash_hex = push_metadata_to_ipfs(
343
+ prompt, tool, extra_attributes
344
+ )
345
+ print(
346
+ f" - Prompt uploaded: https://gateway.autonolas.tech/ipfs/{v1_file_hash_hex}"
347
+ )
348
+ request_datas.append(v1_file_hash_hex_truncated)
349
+
350
+ method_name = "requestBatch"
351
+ method_args["requestDatas"] = request_datas
352
+
317
353
  tx_args = {
318
354
  "sender_address": crypto.address,
319
355
  "value": price,
@@ -356,6 +392,7 @@ def send_offchain_marketplace_request( # pylint: disable=too-many-arguments,too
356
392
  prompt: str,
357
393
  tool: str,
358
394
  method_args_data: MechMarketplaceRequestConfig,
395
+ nonce: int,
359
396
  extra_attributes: Optional[Dict[str, Any]] = None,
360
397
  retries: Optional[int] = None,
361
398
  timeout: Optional[float] = None,
@@ -374,6 +411,8 @@ def send_offchain_marketplace_request( # pylint: disable=too-many-arguments,too
374
411
  :type tool: str
375
412
  :param method_args_data: Method data to use to call the marketplace contract request
376
413
  :type method_args_data: MechMarketplaceRequestConfig
414
+ :param nonce: Nonce to use to order offchain tasks
415
+ :type nonce: int
377
416
  :param extra_attributes: Extra attributes to be included in the request metadata.
378
417
  :type extra_attributes: Optional[Dict[str,Any]]
379
418
  :param retries: Number of retries for sending a transaction
@@ -409,7 +448,6 @@ def send_offchain_marketplace_request( # pylint: disable=too-many-arguments,too
409
448
  while tries < retries and datetime.now().timestamp() < deadline:
410
449
  tries += 1
411
450
  try:
412
- nonce = marketplace_contract.functions.mapNonces(crypto.address).call()
413
451
  delivery_rate = method_args["maxDeliveryRate"]
414
452
  request_id = marketplace_contract.functions.getRequestId(
415
453
  method_args["priorityMech"],
@@ -568,34 +606,12 @@ def check_prepaid_balances(
568
606
  :type max_delivery_rate: int
569
607
  """
570
608
  requester = crypto.address
571
- if payment_type == PAYMENT_TYPE_NATIVE:
572
- with open(
573
- Path(__file__).parent / "abis" / "BalanceTrackerFixedPriceNative.json",
574
- encoding="utf-8",
575
- ) as f:
576
- abi = json.load(f)
577
609
 
578
- balance_tracker_contract = get_contract(
579
- contract_address=mech_payment_balance_tracker,
580
- abi=abi,
581
- ledger_api=ledger_api,
582
- )
583
- requester_balance = balance_tracker_contract.functions.mapRequesterBalances(
584
- requester
585
- ).call()
586
- if requester_balance < max_delivery_rate:
587
- print(
588
- f" - Sender Native deposited balance low. Needed: {max_delivery_rate}, Actual: {requester_balance}"
589
- )
590
- print(f" - Sender Address: {requester}")
591
- print(" - Please use scripts/deposit_native.py to add balance")
592
- sys.exit(1)
610
+ if payment_type in [PaymentType.NATIVE.value, PaymentType.TOKEN.value]:
611
+ payment_type_name = PaymentType(payment_type).name.lower()
612
+ payment_type_abi_path = PAYMENT_TYPE_TO_ABI_PATH[payment_type]
593
613
 
594
- if payment_type == PAYMENT_TYPE_TOKEN:
595
- with open(
596
- Path(__file__).parent / "abis" / "BalanceTrackerFixedPriceToken.json",
597
- encoding="utf-8",
598
- ) as f:
614
+ with open(payment_type_abi_path, encoding="utf-8") as f:
599
615
  abi = json.load(f)
600
616
 
601
617
  balance_tracker_contract = get_contract(
@@ -608,19 +624,21 @@ def check_prepaid_balances(
608
624
  ).call()
609
625
  if requester_balance < max_delivery_rate:
610
626
  print(
611
- f" - Sender Token deposited balance low. Needed: {max_delivery_rate}, Actual: {requester_balance}"
627
+ f" - Sender {payment_type_name} deposited balance low. Needed: {max_delivery_rate}, Actual: {requester_balance}"
612
628
  )
613
629
  print(f" - Sender Address: {requester}")
614
- print(" - Please use scripts/deposit_token.py to add balance")
630
+ print(
631
+ f" - Please use scripts/deposit_{payment_type_name}.py to add balance"
632
+ )
615
633
  sys.exit(1)
616
634
 
617
635
 
618
636
  def marketplace_interact( # pylint: disable=too-many-arguments, too-many-locals, too-many-statements, too-many-return-statements
619
- prompt: str,
637
+ prompts: tuple,
620
638
  priority_mech: str,
621
639
  use_prepaid: bool = False,
622
640
  use_offchain: bool = False,
623
- tool: str = "",
641
+ tools: tuple = (),
624
642
  extra_attributes: Optional[Dict[str, Any]] = None,
625
643
  private_key_path: Optional[str] = None,
626
644
  confirmation_type: ConfirmationType = ConfirmationType.WAIT_FOR_BOTH,
@@ -632,16 +650,16 @@ def marketplace_interact( # pylint: disable=too-many-arguments, too-many-locals
632
650
  """
633
651
  Interact with mech marketplace contract.
634
652
 
635
- :param prompt: The interaction prompt.
636
- :type prompt: str
653
+ :param prompts: The interaction prompts.
654
+ :type prompts: tuple
637
655
  :param priority_mech: Priority mech address to use (Optional)
638
656
  :type priority_mech: str
639
657
  :param use_prepaid: Whether to use prepaid model or not.
640
658
  :type use_prepaid: bool
641
659
  :param use_offchain: Whether to use offchain model or not.
642
660
  :type use_offchain: bool
643
- :param tool: The tool to interact with (optional).
644
- :type tool: str
661
+ :param tools: The tools to interact with (optional).
662
+ :type tools: tuple
645
663
  :param extra_attributes: Extra attributes to be included in the request metadata (optional).
646
664
  :type extra_attributes: Optional[Dict[str, Any]]
647
665
  :param private_key_path: The path to the private key file (optional).
@@ -665,21 +683,23 @@ def marketplace_interact( # pylint: disable=too-many-arguments, too-many-locals
665
683
  priority_mech_address = priority_mech
666
684
  mech_marketplace_contract = mech_config.mech_marketplace_contract
667
685
  chain_id = ledger_config.chain_id
686
+ num_requests = len(prompts)
668
687
 
669
688
  if mech_marketplace_contract == ADDRESS_ZERO:
670
689
  print(f"Mech Marketplace not yet supported on {chain_config}")
671
690
  return None
672
691
 
673
692
  config_values = CHAIN_TO_DEFAULT_MECH_MARKETPLACE_REQUEST_CONFIG[chain_id].copy()
674
- if priority_mech_address is not None:
675
- print("Custom Mech detected")
676
- config_values.update(
677
- {
678
- "priority_mech_address": priority_mech_address,
679
- "mech_marketplace_contract": mech_marketplace_contract,
680
- }
681
- )
693
+ if priority_mech_address is None:
694
+ print("Priority Mech Address not provided")
695
+ return None
682
696
 
697
+ config_values.update(
698
+ {
699
+ "priority_mech_address": priority_mech_address,
700
+ "mech_marketplace_contract": mech_marketplace_contract,
701
+ }
702
+ )
683
703
  mech_marketplace_request_config: MechMarketplaceRequestConfig = make_dataclass(
684
704
  "MechMarketplaceRequestConfig",
685
705
  ((k, type(v)) for k, v in config_values.items()),
@@ -699,9 +719,7 @@ def marketplace_interact( # pylint: disable=too-many-arguments, too-many-locals
699
719
  crypto = EthereumCrypto(private_key_path=private_key_path)
700
720
  ledger_api = EthereumApi(**asdict(ledger_config))
701
721
 
702
- with open(
703
- Path(__file__).parent / "abis" / "MechMarketplace.json", encoding="utf-8"
704
- ) as f:
722
+ with open(MARKETPLACE_ABI_PATH, encoding="utf-8") as f:
705
723
  abi = json.load(f)
706
724
 
707
725
  mech_marketplace_contract = get_contract(
@@ -726,26 +744,28 @@ def marketplace_interact( # pylint: disable=too-many-arguments, too-many-locals
726
744
  mech_marketplace_request_config.delivery_rate = max_delivery_rate
727
745
  mech_marketplace_request_config.payment_type = payment_type
728
746
 
747
+ with open(IMECH_ABI_PATH, encoding="utf-8") as f:
748
+ abi = json.load(f)
749
+
729
750
  (
730
751
  marketplace_request_event_signature,
731
752
  marketplace_deliver_event_signature,
732
753
  ) = get_event_signatures(abi=abi)
733
-
734
754
  register_event_handlers(
735
755
  wss=wss,
736
- contract_address=contract_address,
756
+ contract_address=priority_mech_address,
737
757
  crypto=crypto,
738
758
  request_signature=marketplace_request_event_signature,
739
759
  deliver_signature=marketplace_deliver_event_signature,
740
760
  )
741
761
 
742
762
  if not use_prepaid:
743
- price = max_delivery_rate
744
- if payment_type == PAYMENT_TYPE_TOKEN:
763
+ price = max_delivery_rate * num_requests
764
+ if payment_type == PaymentType.TOKEN.value:
745
765
  print("Token Mech detected, approving wrapped token for price payment...")
746
- wxdai = CHAIN_TO_WRAPPED_TOKEN[chain_id]
766
+ price_token = CHAIN_TO_PRICE_TOKEN[chain_id]
747
767
  approve_tx = approve_price_tokens(
748
- crypto, ledger_api, wxdai, mech_payment_balance_tracker, price
768
+ crypto, ledger_api, price_token, mech_payment_balance_tracker, price
749
769
  )
750
770
  if not approve_tx:
751
771
  print("Unable to approve allowance")
@@ -772,11 +792,14 @@ def marketplace_interact( # pylint: disable=too-many-arguments, too-many-locals
772
792
  max_delivery_rate,
773
793
  )
774
794
 
775
- if payment_type == PAYMENT_TYPE_NVM:
776
- print("Nevermined Mech detected, subscription credits to be used")
795
+ if payment_type in [PaymentType.NATIVE_NVM.value, PaymentType.TOKEN_NVM.value]:
796
+ nvm_mech_type = PaymentType(payment_type).name.lower()
797
+ print(
798
+ f"{nvm_mech_type} Nevermined Mech detected, subscription credits to be used"
799
+ )
777
800
  requester = crypto.address
778
801
  requester_balance = fetch_requester_nvm_subscription_balance(
779
- requester, ledger_api, mech_payment_balance_tracker
802
+ requester, ledger_api, mech_payment_balance_tracker, payment_type
780
803
  )
781
804
  if requester_balance < price:
782
805
  print(
@@ -796,8 +819,8 @@ def marketplace_interact( # pylint: disable=too-many-arguments, too-many-locals
796
819
  marketplace_contract=mech_marketplace_contract,
797
820
  gas_limit=mech_config.gas_limit,
798
821
  price=price,
799
- prompt=prompt,
800
- tool=tool,
822
+ prompts=prompts,
823
+ tools=tools,
801
824
  method_args_data=mech_marketplace_request_config,
802
825
  extra_attributes=extra_attributes,
803
826
  retries=retries,
@@ -815,66 +838,86 @@ def marketplace_interact( # pylint: disable=too-many-arguments, too-many-locals
815
838
  print(f" - Transaction sent: {transaction_url_formatted}")
816
839
  print(" - Waiting for transaction receipt...")
817
840
 
818
- request_id = watch_for_marketplace_request_id(
841
+ request_ids = watch_for_marketplace_request_ids(
819
842
  marketplace_contract=mech_marketplace_contract,
820
843
  ledger_api=ledger_api,
821
844
  tx_hash=transaction_digest,
822
845
  )
823
- request_id_int = int.from_bytes(bytes.fromhex(request_id), byteorder="big")
824
- print(f" - Created on-chain request with ID {request_id_int}")
846
+ request_id_ints = [
847
+ int.from_bytes(bytes.fromhex(request_id), byteorder="big")
848
+ for request_id in request_ids
849
+ ]
850
+ if len(request_id_ints) == 1:
851
+ print(f" - Created on-chain request with ID {request_id_ints[0]}")
852
+ else:
853
+ print(
854
+ f" - Created on-chain requests with IDs: {', '.join(str(rid) for rid in request_id_ints)}"
855
+ )
825
856
  print("")
826
857
 
827
- data_url = wait_for_marketplace_data_url(
828
- request_id=request_id,
829
- wss=wss,
830
- mech_contract=mech_contract,
831
- subgraph_url=mech_config.subgraph_url,
832
- deliver_signature=marketplace_deliver_event_signature,
833
- ledger_api=ledger_api,
834
- crypto=crypto,
835
- confirmation_type=confirmation_type,
836
- )
858
+ for request_id, request_id_int in zip(request_ids, request_id_ints):
859
+ data_url = wait_for_marketplace_data_url(
860
+ request_id=request_id,
861
+ wss=wss,
862
+ mech_contract=mech_contract,
863
+ subgraph_url=mech_config.subgraph_url,
864
+ deliver_signature=marketplace_deliver_event_signature,
865
+ ledger_api=ledger_api,
866
+ crypto=crypto,
867
+ confirmation_type=confirmation_type,
868
+ )
837
869
 
838
- if data_url:
839
- print(f" - Data arrived: {data_url}")
840
- data = requests.get(f"{data_url}/{request_id_int}", timeout=30).json()
841
- print(" - Data from agent:")
842
- print(json.dumps(data, indent=2))
843
- return data
870
+ if data_url:
871
+ print(f" - Data arrived: {data_url}")
872
+ data = requests.get(f"{data_url}/{request_id_int}", timeout=30).json()
873
+ print(" - Data from agent:")
874
+ print(json.dumps(data, indent=2))
844
875
  return None
845
876
 
846
877
  print("Sending Offchain Mech Marketplace request...")
847
- response = send_offchain_marketplace_request(
848
- crypto=crypto,
849
- marketplace_contract=mech_marketplace_contract,
850
- prompt=prompt,
851
- tool=tool,
852
- method_args_data=mech_marketplace_request_config,
853
- extra_attributes=extra_attributes,
854
- retries=retries,
855
- timeout=timeout,
856
- sleep=sleep,
857
- )
878
+ curr_nonce = mech_marketplace_contract.functions.mapNonces(crypto.address).call() # type: ignore
879
+ responses = []
858
880
 
859
- if not response:
881
+ for i in range(num_requests):
882
+ response = send_offchain_marketplace_request(
883
+ crypto=crypto,
884
+ marketplace_contract=mech_marketplace_contract,
885
+ prompt=prompts[0],
886
+ tool=tools[0],
887
+ method_args_data=mech_marketplace_request_config,
888
+ nonce=curr_nonce + i,
889
+ extra_attributes=extra_attributes,
890
+ retries=retries,
891
+ timeout=timeout,
892
+ sleep=sleep,
893
+ )
894
+ responses.append(response)
895
+
896
+ if not responses and len(responses) != num_requests:
860
897
  return None
861
898
 
862
- request_id = response["request_id"]
863
- print(f" - Created off-chain request with ID {request_id}")
899
+ request_ids = [resp["request_id"] for resp in responses if resp is not None]
900
+ if len(request_ids) == 1:
901
+ print(f" - Created off-chain request with ID {request_ids[0]}")
902
+ else:
903
+ print(
904
+ f" - Created off-chain requests with IDs: {', '.join(str(rid) for rid in request_ids)}"
905
+ )
864
906
  print("")
865
907
 
866
908
  # @note as we are directly querying data from done task list, we get the full data instead of the ipfs hash
867
909
  print("Waiting for Offchain Mech Marketplace deliver...")
868
- data = wait_for_offchain_marketplace_data(
869
- request_id=request_id,
870
- )
871
910
 
872
- if data:
873
- task_result = data["task_result"]
874
- data_url = f"https://gateway.autonolas.tech/ipfs/f01701220{task_result}"
875
- print(f" - Data arrived: {data_url}")
876
- data = requests.get(f"{data_url}/{request_id}", timeout=30).json()
877
- print(" - Data from agent:")
878
- print(json.dumps(data, indent=2))
879
- return data
911
+ for request_id in request_ids:
912
+ data = wait_for_offchain_marketplace_data(
913
+ request_id=request_id,
914
+ )
915
+
916
+ if data:
917
+ task_result = data["task_result"]
918
+ data_url = IPFS_URL_TEMPLATE.format(task_result)
919
+ print(f" - Data arrived: {data_url}")
920
+ data = requests.get(f"{data_url}/{request_id}", timeout=30).json()
921
+ print(" - Data from agent:")
922
+ print(json.dumps(data, indent=2))
880
923
  return None
@@ -7,7 +7,13 @@ from typing import Any, Dict, List, Optional, Tuple, Union
7
7
  import requests
8
8
  from aea_ledger_ethereum import EthereumApi
9
9
 
10
- from mech_client.interact import fetch_tools, get_abi, get_contract, get_mech_config
10
+ from mech_client.interact import (
11
+ AGENT_REGISTRY_ABI_PATH,
12
+ fetch_tools,
13
+ get_abi,
14
+ get_contract,
15
+ get_mech_config,
16
+ )
11
17
 
12
18
 
13
19
  def get_total_supply(chain_config: str = "gnosis") -> int:
@@ -27,7 +33,7 @@ def get_total_supply(chain_config: str = "gnosis") -> int:
27
33
  ledger_api = EthereumApi(**asdict(ledger_config))
28
34
 
29
35
  # Fetch ABI and create contract instance
30
- abi = get_abi(mech_config.agent_registry_contract, mech_config.contract_abi_url)
36
+ abi = get_abi(AGENT_REGISTRY_ABI_PATH)
31
37
  contract = get_contract(mech_config.agent_registry_contract, abi, ledger_api)
32
38
 
33
39
  # Call the totalSupply function
@@ -58,7 +64,7 @@ def get_agent_tools(
58
64
  agent_id=agent_id,
59
65
  ledger_api=ledger_api,
60
66
  agent_registry_contract=mech_config.agent_registry_contract,
61
- contract_abi_url=mech_config.contract_abi_url,
67
+ contract_abi_path=AGENT_REGISTRY_ABI_PATH,
62
68
  include_metadata=include_metadata,
63
69
  )
64
70
  except (requests.exceptions.RequestException, json.JSONDecodeError, KeyError) as e:
@@ -155,7 +161,7 @@ def get_tool_description(unique_identifier: str, chain_config: str = "gnosis") -
155
161
  agent_id=agent_id,
156
162
  ledger_api=ledger_api,
157
163
  agent_registry_contract=mech_config.agent_registry_contract,
158
- contract_abi_url=mech_config.contract_abi_url,
164
+ contract_abi_path=AGENT_REGISTRY_ABI_PATH,
159
165
  include_metadata=True,
160
166
  )
161
167
  if isinstance(tools_result, tuple) and len(tools_result) == 2:
@@ -188,7 +194,7 @@ def get_tool_io_schema(
188
194
  agent_id=agent_id,
189
195
  ledger_api=ledger_api,
190
196
  agent_registry_contract=mech_config.agent_registry_contract,
191
- contract_abi_url=mech_config.contract_abi_url,
197
+ contract_abi_path=AGENT_REGISTRY_ABI_PATH,
192
198
  include_metadata=True,
193
199
  )
194
200
  if isinstance(tools_result, tuple) and len(tools_result) == 2: