mech-client 0.2.21__py3-none-any.whl → 0.3.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.
- mech_client/__init__.py +1 -1
- mech_client/abis/BalanceTrackerFixedPriceNative.json +503 -0
- mech_client/abis/BalanceTrackerFixedPriceToken.json +502 -0
- mech_client/abis/BalanceTrackerNvmSubscriptionNative.json +672 -0
- mech_client/abis/IERC1155.json +295 -0
- mech_client/abis/IMech.json +165 -0
- mech_client/abis/IToken.json +880 -0
- mech_client/abis/MechMarketplace.json +1281 -0
- mech_client/cli.py +74 -19
- mech_client/configs/mechs.json +17 -5
- mech_client/fetch_ipfs_hash.py +88 -0
- mech_client/helpers/__init__.py +13 -3
- mech_client/interact.py +24 -2
- mech_client/marketplace_interact.py +880 -0
- mech_client/wss.py +89 -0
- {mech_client-0.2.21.dist-info → mech_client-0.3.0.dist-info}/METADATA +48 -5
- {mech_client-0.2.21.dist-info → mech_client-0.3.0.dist-info}/RECORD +20 -11
- {mech_client-0.2.21.dist-info → mech_client-0.3.0.dist-info}/LICENSE +0 -0
- {mech_client-0.2.21.dist-info → mech_client-0.3.0.dist-info}/WHEEL +0 -0
- {mech_client-0.2.21.dist-info → mech_client-0.3.0.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,880 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# ------------------------------------------------------------------------------
|
|
3
|
+
#
|
|
4
|
+
# Copyright 2024 Valory AG
|
|
5
|
+
#
|
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
# you may not use this file except in compliance with the License.
|
|
8
|
+
# You may obtain a copy of the License at
|
|
9
|
+
#
|
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
#
|
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
# See the License for the specific language governing permissions and
|
|
16
|
+
# limitations under the License.
|
|
17
|
+
#
|
|
18
|
+
# ------------------------------------------------------------------------------
|
|
19
|
+
|
|
20
|
+
"""This script allows sending a Request to an on-chain mech marketplace and waiting for the Deliver."""
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
import asyncio
|
|
24
|
+
import json
|
|
25
|
+
import sys
|
|
26
|
+
import time
|
|
27
|
+
from dataclasses import asdict, make_dataclass
|
|
28
|
+
from datetime import datetime
|
|
29
|
+
from pathlib import Path
|
|
30
|
+
from typing import Any, Dict, List, Optional, Tuple, cast
|
|
31
|
+
|
|
32
|
+
import requests
|
|
33
|
+
import websocket
|
|
34
|
+
from aea.crypto.base import Crypto
|
|
35
|
+
from aea_ledger_ethereum import EthereumApi, EthereumCrypto
|
|
36
|
+
from eth_utils import to_checksum_address
|
|
37
|
+
from web3.constants import ADDRESS_ZERO
|
|
38
|
+
from web3.contract import Contract as Web3Contract
|
|
39
|
+
|
|
40
|
+
from mech_client.fetch_ipfs_hash import fetch_ipfs_hash
|
|
41
|
+
from mech_client.interact import (
|
|
42
|
+
ConfirmationType,
|
|
43
|
+
MAX_RETRIES,
|
|
44
|
+
MechMarketplaceRequestConfig,
|
|
45
|
+
PRIVATE_KEY_FILE_PATH,
|
|
46
|
+
TIMEOUT,
|
|
47
|
+
WAIT_SLEEP,
|
|
48
|
+
calculate_topic_id,
|
|
49
|
+
get_contract,
|
|
50
|
+
get_mech_config,
|
|
51
|
+
)
|
|
52
|
+
from mech_client.prompt_to_ipfs import push_metadata_to_ipfs
|
|
53
|
+
from mech_client.wss import (
|
|
54
|
+
register_event_handlers,
|
|
55
|
+
wait_for_receipt,
|
|
56
|
+
watch_for_marketplace_data_url_from_wss,
|
|
57
|
+
watch_for_marketplace_request_id,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# 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
|
|
67
|
+
)
|
|
68
|
+
PAYMENT_TYPE_NVM = (
|
|
69
|
+
"803dd08fe79d91027fc9024e254a0942372b92f3ccabc1bd19f4a5c2b251c316" # nosec
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
CHAIN_TO_WRAPPED_TOKEN = {
|
|
73
|
+
1: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
|
|
74
|
+
10: "0x4200000000000000000000000000000000000006",
|
|
75
|
+
100: "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d",
|
|
76
|
+
137: "0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270",
|
|
77
|
+
8453: "0x4200000000000000000000000000000000000006",
|
|
78
|
+
42220: "0x471EcE3750Da237f93B8E339c536989b8978a438",
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
CHAIN_TO_DEFAULT_MECH_MARKETPLACE_REQUEST_CONFIG = {
|
|
83
|
+
100: {
|
|
84
|
+
"mech_marketplace_contract": "0x735FAAb1c4Ec41128c367AFb5c3baC73509f70bB",
|
|
85
|
+
"priority_mech_address": "0x478ad20eD958dCC5AD4ABa6F4E4cc51e07a840E4",
|
|
86
|
+
"response_timeout": 300,
|
|
87
|
+
"payment_data": "0x",
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
|
|
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
|
+
def fetch_mech_info(
|
|
106
|
+
ledger_api: EthereumApi,
|
|
107
|
+
mech_marketplace_contract: Web3Contract,
|
|
108
|
+
priority_mech_address: str,
|
|
109
|
+
) -> Tuple[str, int, int, str, Web3Contract]:
|
|
110
|
+
"""
|
|
111
|
+
Fetchs the info of the requested mech.
|
|
112
|
+
|
|
113
|
+
:param ledger_api: The Ethereum API used for interacting with the ledger.
|
|
114
|
+
:type ledger_api: EthereumApi
|
|
115
|
+
:param mech_marketplace_contract: The mech marketplace contract instance.
|
|
116
|
+
:type mech_marketplace_contract: Web3Contract
|
|
117
|
+
:param priority_mech_address: Requested mech address
|
|
118
|
+
:type priority_mech_address: str
|
|
119
|
+
:return: The mech info containing payment_type, service_id, max_delivery_rate, mech_payment_balance_tracker and Mech contract.
|
|
120
|
+
:rtype: Tuple[str, int, int, str, Contract]
|
|
121
|
+
"""
|
|
122
|
+
|
|
123
|
+
with open(Path(__file__).parent / "abis" / "IMech.json", encoding="utf-8") as f:
|
|
124
|
+
abi = json.load(f)
|
|
125
|
+
|
|
126
|
+
mech_contract = get_contract(
|
|
127
|
+
contract_address=priority_mech_address, abi=abi, ledger_api=ledger_api
|
|
128
|
+
)
|
|
129
|
+
payment_type_bytes = mech_contract.functions.paymentType().call()
|
|
130
|
+
max_delivery_rate = mech_contract.functions.maxDeliveryRate().call()
|
|
131
|
+
service_id = mech_contract.functions.serviceId().call()
|
|
132
|
+
payment_type = payment_type_bytes.hex()
|
|
133
|
+
|
|
134
|
+
mech_payment_balance_tracker = (
|
|
135
|
+
mech_marketplace_contract.functions.mapPaymentTypeBalanceTrackers(
|
|
136
|
+
payment_type_bytes
|
|
137
|
+
).call()
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
if payment_type not in [PAYMENT_TYPE_NATIVE, PAYMENT_TYPE_TOKEN, PAYMENT_TYPE_NVM]:
|
|
141
|
+
print(" - Invalid mech type detected.")
|
|
142
|
+
sys.exit(1)
|
|
143
|
+
|
|
144
|
+
return (
|
|
145
|
+
payment_type,
|
|
146
|
+
service_id,
|
|
147
|
+
max_delivery_rate,
|
|
148
|
+
mech_payment_balance_tracker,
|
|
149
|
+
mech_contract,
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def approve_price_tokens(
|
|
154
|
+
crypto: EthereumCrypto,
|
|
155
|
+
ledger_api: EthereumApi,
|
|
156
|
+
wrapped_token: str,
|
|
157
|
+
mech_payment_balance_tracker: str,
|
|
158
|
+
price: int,
|
|
159
|
+
) -> str:
|
|
160
|
+
"""
|
|
161
|
+
Sends the approve tx for wrapped token of the sender to the requested mech's balance payment tracker contract.
|
|
162
|
+
|
|
163
|
+
:param crypto: The Ethereum crypto object.
|
|
164
|
+
:type crypto: EthereumCrypto
|
|
165
|
+
:param ledger_api: The Ethereum API used for interacting with the ledger.
|
|
166
|
+
:type ledger_api: EthereumApi
|
|
167
|
+
:param wrapped_token: The wrapped token contract address.
|
|
168
|
+
:type wrapped_token: str
|
|
169
|
+
:param mech_payment_balance_tracker: Requested mech's balance tracker contract address
|
|
170
|
+
:type mech_payment_balance_tracker: str
|
|
171
|
+
:param price: Amount of wrapped_token to approve
|
|
172
|
+
:type price: int
|
|
173
|
+
:return: The transaction digest.
|
|
174
|
+
:rtype: str
|
|
175
|
+
"""
|
|
176
|
+
sender = crypto.address
|
|
177
|
+
|
|
178
|
+
with open(Path(__file__).parent / "abis" / "IToken.json", encoding="utf-8") as f:
|
|
179
|
+
abi = json.load(f)
|
|
180
|
+
|
|
181
|
+
token_contract = get_contract(
|
|
182
|
+
contract_address=wrapped_token, abi=abi, ledger_api=ledger_api
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
user_token_balance = token_contract.functions.balanceOf(sender).call()
|
|
186
|
+
if user_token_balance < price:
|
|
187
|
+
print(
|
|
188
|
+
f" - Sender Token balance low. Needed: {price}, Actual: {user_token_balance}"
|
|
189
|
+
)
|
|
190
|
+
print(f" - Sender Address: {sender}")
|
|
191
|
+
sys.exit(1)
|
|
192
|
+
|
|
193
|
+
tx_args = {"sender_address": sender, "value": 0, "gas": 60000}
|
|
194
|
+
raw_transaction = ledger_api.build_transaction(
|
|
195
|
+
contract_instance=token_contract,
|
|
196
|
+
method_name="approve",
|
|
197
|
+
method_args={"_to": mech_payment_balance_tracker, "_value": price},
|
|
198
|
+
tx_args=tx_args,
|
|
199
|
+
raise_on_try=True,
|
|
200
|
+
)
|
|
201
|
+
signed_transaction = crypto.sign_transaction(raw_transaction)
|
|
202
|
+
transaction_digest = ledger_api.send_signed_transaction(
|
|
203
|
+
signed_transaction,
|
|
204
|
+
raise_on_try=True,
|
|
205
|
+
)
|
|
206
|
+
return transaction_digest
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def fetch_requester_nvm_subscription_balance(
|
|
210
|
+
requester: str,
|
|
211
|
+
ledger_api: EthereumApi,
|
|
212
|
+
mech_payment_balance_tracker: str,
|
|
213
|
+
) -> int:
|
|
214
|
+
"""
|
|
215
|
+
Fetches the requester nvm subscription balance.
|
|
216
|
+
|
|
217
|
+
:param requester: The requester's address.
|
|
218
|
+
:type requester: str
|
|
219
|
+
:param ledger_api: The Ethereum API used for interacting with the ledger.
|
|
220
|
+
:type ledger_api: EthereumApi
|
|
221
|
+
:param mech_payment_balance_tracker: Requested mech's balance tracker contract address
|
|
222
|
+
:type mech_payment_balance_tracker: str
|
|
223
|
+
:return: The requester balance.
|
|
224
|
+
:rtype: int
|
|
225
|
+
"""
|
|
226
|
+
with open(
|
|
227
|
+
Path(__file__).parent / "abis" / "BalanceTrackerNvmSubscriptionNative.json",
|
|
228
|
+
encoding="utf-8",
|
|
229
|
+
) as f:
|
|
230
|
+
abi = json.load(f)
|
|
231
|
+
|
|
232
|
+
nvm_balance_tracker_contract = get_contract(
|
|
233
|
+
contract_address=mech_payment_balance_tracker, abi=abi, ledger_api=ledger_api
|
|
234
|
+
)
|
|
235
|
+
subscription_nft_address = (
|
|
236
|
+
nvm_balance_tracker_contract.functions.subscriptionNFT().call()
|
|
237
|
+
)
|
|
238
|
+
subscription_id = (
|
|
239
|
+
nvm_balance_tracker_contract.functions.subscriptionTokenId().call()
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
with open(
|
|
243
|
+
Path(__file__).parent / "abis" / "IERC1155.json",
|
|
244
|
+
encoding="utf-8",
|
|
245
|
+
) as f:
|
|
246
|
+
abi = json.load(f)
|
|
247
|
+
|
|
248
|
+
subscription_nft_contract = get_contract(
|
|
249
|
+
contract_address=subscription_nft_address, abi=abi, ledger_api=ledger_api
|
|
250
|
+
)
|
|
251
|
+
requester_balance = subscription_nft_contract.functions.balanceOf(
|
|
252
|
+
requester, subscription_id
|
|
253
|
+
).call()
|
|
254
|
+
|
|
255
|
+
return requester_balance
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def send_marketplace_request( # pylint: disable=too-many-arguments,too-many-locals
|
|
259
|
+
crypto: EthereumCrypto,
|
|
260
|
+
ledger_api: EthereumApi,
|
|
261
|
+
marketplace_contract: Web3Contract,
|
|
262
|
+
gas_limit: int,
|
|
263
|
+
prompt: str,
|
|
264
|
+
tool: str,
|
|
265
|
+
method_args_data: MechMarketplaceRequestConfig,
|
|
266
|
+
extra_attributes: Optional[Dict[str, Any]] = None,
|
|
267
|
+
price: int = 10_000_000_000_000_000,
|
|
268
|
+
retries: Optional[int] = None,
|
|
269
|
+
timeout: Optional[float] = None,
|
|
270
|
+
sleep: Optional[float] = None,
|
|
271
|
+
) -> Optional[str]:
|
|
272
|
+
"""
|
|
273
|
+
Sends a request to the mech.
|
|
274
|
+
|
|
275
|
+
:param crypto: The Ethereum crypto object.
|
|
276
|
+
:type crypto: EthereumCrypto
|
|
277
|
+
:param ledger_api: The Ethereum API used for interacting with the ledger.
|
|
278
|
+
:type ledger_api: EthereumApi
|
|
279
|
+
:param marketplace_contract: The mech marketplace contract instance.
|
|
280
|
+
:type marketplace_contract: Web3Contract
|
|
281
|
+
:param gas_limit: Gas limit.
|
|
282
|
+
:type gas_limit: int
|
|
283
|
+
:param prompt: The request prompt.
|
|
284
|
+
:type prompt: str
|
|
285
|
+
:param tool: The requested tool.
|
|
286
|
+
:type tool: str
|
|
287
|
+
:param method_args_data: Method data to use to call the marketplace contract request
|
|
288
|
+
:type method_args_data: MechMarketplaceRequestConfig
|
|
289
|
+
:param extra_attributes: Extra attributes to be included in the request metadata.
|
|
290
|
+
:type extra_attributes: Optional[Dict[str,Any]]
|
|
291
|
+
:param price: The price for the request (default: 10_000_000_000_000_000).
|
|
292
|
+
:type price: int
|
|
293
|
+
:param retries: Number of retries for sending a transaction
|
|
294
|
+
:type retries: int
|
|
295
|
+
:param timeout: Timeout to wait for the transaction
|
|
296
|
+
:type timeout: float
|
|
297
|
+
:param sleep: Amount of sleep before retrying the transaction
|
|
298
|
+
:type sleep: float
|
|
299
|
+
:return: The transaction hash.
|
|
300
|
+
:rtype: Optional[str]
|
|
301
|
+
"""
|
|
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"
|
|
309
|
+
method_args = {
|
|
310
|
+
"requestData": v1_file_hash_hex_truncated,
|
|
311
|
+
"maxDeliveryRate": method_args_data.delivery_rate,
|
|
312
|
+
"paymentType": "0x" + cast(str, method_args_data.payment_type),
|
|
313
|
+
"priorityMech": to_checksum_address(method_args_data.priority_mech_address),
|
|
314
|
+
"responseTimeout": method_args_data.response_timeout,
|
|
315
|
+
"paymentData": method_args_data.payment_data,
|
|
316
|
+
}
|
|
317
|
+
tx_args = {
|
|
318
|
+
"sender_address": crypto.address,
|
|
319
|
+
"value": price,
|
|
320
|
+
"gas": gas_limit,
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
tries = 0
|
|
324
|
+
retries = retries or MAX_RETRIES
|
|
325
|
+
timeout = timeout or TIMEOUT
|
|
326
|
+
sleep = sleep or WAIT_SLEEP
|
|
327
|
+
deadline = datetime.now().timestamp() + timeout
|
|
328
|
+
|
|
329
|
+
while tries < retries and datetime.now().timestamp() < deadline:
|
|
330
|
+
tries += 1
|
|
331
|
+
try:
|
|
332
|
+
raw_transaction = ledger_api.build_transaction(
|
|
333
|
+
contract_instance=marketplace_contract,
|
|
334
|
+
method_name=method_name,
|
|
335
|
+
method_args=method_args,
|
|
336
|
+
tx_args=tx_args,
|
|
337
|
+
raise_on_try=True,
|
|
338
|
+
)
|
|
339
|
+
signed_transaction = crypto.sign_transaction(raw_transaction)
|
|
340
|
+
transaction_digest = ledger_api.send_signed_transaction(
|
|
341
|
+
signed_transaction,
|
|
342
|
+
raise_on_try=True,
|
|
343
|
+
)
|
|
344
|
+
return transaction_digest
|
|
345
|
+
except Exception as e: # pylint: disable=broad-except
|
|
346
|
+
print(
|
|
347
|
+
f"Error occured while sending the transaction: {e}; Retrying in {sleep}"
|
|
348
|
+
)
|
|
349
|
+
time.sleep(sleep)
|
|
350
|
+
return None
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
def send_offchain_marketplace_request( # pylint: disable=too-many-arguments,too-many-locals
|
|
354
|
+
crypto: EthereumCrypto,
|
|
355
|
+
marketplace_contract: Web3Contract,
|
|
356
|
+
prompt: str,
|
|
357
|
+
tool: str,
|
|
358
|
+
method_args_data: MechMarketplaceRequestConfig,
|
|
359
|
+
extra_attributes: Optional[Dict[str, Any]] = None,
|
|
360
|
+
retries: Optional[int] = None,
|
|
361
|
+
timeout: Optional[float] = None,
|
|
362
|
+
sleep: Optional[float] = None,
|
|
363
|
+
) -> Optional[Dict]:
|
|
364
|
+
"""
|
|
365
|
+
Sends an offchain request to the mech.
|
|
366
|
+
|
|
367
|
+
:param crypto: The Ethereum crypto object.
|
|
368
|
+
:type crypto: EthereumCrypto
|
|
369
|
+
:param marketplace_contract: The mech marketplace contract instance.
|
|
370
|
+
:type marketplace_contract: Web3Contract
|
|
371
|
+
:param prompt: The request prompt.
|
|
372
|
+
:type prompt: str
|
|
373
|
+
:param tool: The requested tool.
|
|
374
|
+
:type tool: str
|
|
375
|
+
:param method_args_data: Method data to use to call the marketplace contract request
|
|
376
|
+
:type method_args_data: MechMarketplaceRequestConfig
|
|
377
|
+
:param extra_attributes: Extra attributes to be included in the request metadata.
|
|
378
|
+
:type extra_attributes: Optional[Dict[str,Any]]
|
|
379
|
+
:param retries: Number of retries for sending a transaction
|
|
380
|
+
:type retries: int
|
|
381
|
+
:param timeout: Timeout to wait for the transaction
|
|
382
|
+
:type timeout: float
|
|
383
|
+
:param sleep: Amount of sleep before retrying the transaction
|
|
384
|
+
:type sleep: float
|
|
385
|
+
:return: The dict containing request info.
|
|
386
|
+
:rtype: Optional[Dict]
|
|
387
|
+
"""
|
|
388
|
+
v1_file_hash_hex_truncated, v1_file_hash_hex, ipfs_data = fetch_ipfs_hash(
|
|
389
|
+
prompt, tool, extra_attributes
|
|
390
|
+
)
|
|
391
|
+
print(
|
|
392
|
+
f" - Prompt will shortly be uploaded to: https://gateway.autonolas.tech/ipfs/{v1_file_hash_hex}"
|
|
393
|
+
)
|
|
394
|
+
method_args = {
|
|
395
|
+
"requestData": v1_file_hash_hex_truncated,
|
|
396
|
+
"maxDeliveryRate": method_args_data.delivery_rate,
|
|
397
|
+
"paymentType": "0x" + cast(str, method_args_data.payment_type),
|
|
398
|
+
"priorityMech": to_checksum_address(method_args_data.priority_mech_address),
|
|
399
|
+
"responseTimeout": method_args_data.response_timeout,
|
|
400
|
+
"paymentData": method_args_data.payment_data,
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
tries = 0
|
|
404
|
+
retries = retries or MAX_RETRIES
|
|
405
|
+
timeout = timeout or TIMEOUT
|
|
406
|
+
sleep = sleep or WAIT_SLEEP
|
|
407
|
+
deadline = datetime.now().timestamp() + timeout
|
|
408
|
+
|
|
409
|
+
while tries < retries and datetime.now().timestamp() < deadline:
|
|
410
|
+
tries += 1
|
|
411
|
+
try:
|
|
412
|
+
nonce = marketplace_contract.functions.mapNonces(crypto.address).call()
|
|
413
|
+
delivery_rate = method_args["maxDeliveryRate"]
|
|
414
|
+
request_id = marketplace_contract.functions.getRequestId(
|
|
415
|
+
method_args["priorityMech"],
|
|
416
|
+
crypto.address,
|
|
417
|
+
method_args["requestData"],
|
|
418
|
+
method_args["maxDeliveryRate"],
|
|
419
|
+
method_args["paymentType"],
|
|
420
|
+
nonce,
|
|
421
|
+
).call()
|
|
422
|
+
request_id_int = int.from_bytes(request_id, byteorder="big")
|
|
423
|
+
signature = crypto.sign_message(request_id, is_deprecated_mode=True)
|
|
424
|
+
|
|
425
|
+
payload = {
|
|
426
|
+
"sender": crypto.address,
|
|
427
|
+
"signature": signature,
|
|
428
|
+
"ipfs_hash": v1_file_hash_hex_truncated,
|
|
429
|
+
"request_id": request_id_int,
|
|
430
|
+
"delivery_rate": delivery_rate,
|
|
431
|
+
"nonce": nonce,
|
|
432
|
+
"ipfs_data": ipfs_data,
|
|
433
|
+
}
|
|
434
|
+
# @todo changed hardcoded url
|
|
435
|
+
response = requests.post(
|
|
436
|
+
"http://localhost:8000/send_signed_requests",
|
|
437
|
+
data=payload,
|
|
438
|
+
headers={"Content-Type": "application/json"},
|
|
439
|
+
).json()
|
|
440
|
+
return response
|
|
441
|
+
|
|
442
|
+
except Exception as e: # pylint: disable=broad-except
|
|
443
|
+
print(
|
|
444
|
+
f"Error occured while sending the offchain request: {e}; Retrying in {sleep}"
|
|
445
|
+
)
|
|
446
|
+
time.sleep(sleep)
|
|
447
|
+
return None
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
def wait_for_marketplace_data_url( # pylint: disable=too-many-arguments, unused-argument
|
|
451
|
+
request_id: str,
|
|
452
|
+
wss: websocket.WebSocket,
|
|
453
|
+
mech_contract: Web3Contract,
|
|
454
|
+
subgraph_url: str,
|
|
455
|
+
deliver_signature: str,
|
|
456
|
+
ledger_api: EthereumApi,
|
|
457
|
+
crypto: Crypto,
|
|
458
|
+
confirmation_type: ConfirmationType = ConfirmationType.WAIT_FOR_BOTH,
|
|
459
|
+
) -> Any:
|
|
460
|
+
"""
|
|
461
|
+
Wait for data from on-chain/off-chain.
|
|
462
|
+
|
|
463
|
+
:param request_id: The ID of the request.
|
|
464
|
+
:type request_id: str
|
|
465
|
+
:param wss: The WebSocket connection object.
|
|
466
|
+
:type wss: websocket.WebSocket
|
|
467
|
+
:param mech_contract: The mech contract instance.
|
|
468
|
+
:type mech_contract: Web3Contract
|
|
469
|
+
:param subgraph_url: Subgraph URL.
|
|
470
|
+
:type subgraph_url: str
|
|
471
|
+
:param deliver_signature: Topic signature for MarketplaceDeliver event
|
|
472
|
+
:type deliver_signature: str
|
|
473
|
+
:param ledger_api: The Ethereum API used for interacting with the ledger.
|
|
474
|
+
:type ledger_api: EthereumApi
|
|
475
|
+
:param crypto: The cryptographic object.
|
|
476
|
+
:type crypto: Crypto
|
|
477
|
+
:param confirmation_type: The confirmation type for the interaction (default: ConfirmationType.WAIT_FOR_BOTH).
|
|
478
|
+
:type confirmation_type: ConfirmationType
|
|
479
|
+
:return: The data received from on-chain/off-chain.
|
|
480
|
+
:rtype: Any
|
|
481
|
+
"""
|
|
482
|
+
loop = asyncio.new_event_loop()
|
|
483
|
+
asyncio.set_event_loop(loop)
|
|
484
|
+
tasks = []
|
|
485
|
+
|
|
486
|
+
if confirmation_type in (
|
|
487
|
+
ConfirmationType.OFF_CHAIN,
|
|
488
|
+
ConfirmationType.WAIT_FOR_BOTH,
|
|
489
|
+
):
|
|
490
|
+
print("Off chain to be implemented")
|
|
491
|
+
|
|
492
|
+
if confirmation_type in (
|
|
493
|
+
ConfirmationType.ON_CHAIN,
|
|
494
|
+
ConfirmationType.WAIT_FOR_BOTH,
|
|
495
|
+
):
|
|
496
|
+
on_chain_task = loop.create_task(
|
|
497
|
+
watch_for_marketplace_data_url_from_wss(
|
|
498
|
+
request_id=request_id,
|
|
499
|
+
wss=wss,
|
|
500
|
+
mech_contract=mech_contract,
|
|
501
|
+
deliver_signature=deliver_signature,
|
|
502
|
+
ledger_api=ledger_api,
|
|
503
|
+
loop=loop,
|
|
504
|
+
)
|
|
505
|
+
)
|
|
506
|
+
tasks.append(on_chain_task)
|
|
507
|
+
|
|
508
|
+
if subgraph_url:
|
|
509
|
+
print("Subgraph to be implemented")
|
|
510
|
+
|
|
511
|
+
async def _wait_for_tasks() -> Any: # type: ignore
|
|
512
|
+
"""Wait for tasks to finish."""
|
|
513
|
+
(finished, *_), unfinished = await asyncio.wait(
|
|
514
|
+
tasks,
|
|
515
|
+
return_when=asyncio.FIRST_COMPLETED,
|
|
516
|
+
)
|
|
517
|
+
for task in unfinished:
|
|
518
|
+
task.cancel()
|
|
519
|
+
if unfinished:
|
|
520
|
+
await asyncio.wait(unfinished)
|
|
521
|
+
return finished.result()
|
|
522
|
+
|
|
523
|
+
result = loop.run_until_complete(_wait_for_tasks())
|
|
524
|
+
return result
|
|
525
|
+
|
|
526
|
+
|
|
527
|
+
def wait_for_offchain_marketplace_data(request_id: str) -> Any:
|
|
528
|
+
"""
|
|
529
|
+
Watches for data off-chain on mech.
|
|
530
|
+
|
|
531
|
+
:param request_id: The ID of the request.
|
|
532
|
+
:type request_id: str
|
|
533
|
+
:return: The data returned by the mech.
|
|
534
|
+
:rtype: Any
|
|
535
|
+
"""
|
|
536
|
+
while True:
|
|
537
|
+
try:
|
|
538
|
+
# @todo change hardcoded url
|
|
539
|
+
response = requests.get(
|
|
540
|
+
"http://localhost:8000/fetch_offchain_info",
|
|
541
|
+
data={"request_id": request_id},
|
|
542
|
+
).json()
|
|
543
|
+
if response:
|
|
544
|
+
return response
|
|
545
|
+
except Exception: # pylint: disable=broad-except
|
|
546
|
+
time.sleep(1)
|
|
547
|
+
|
|
548
|
+
|
|
549
|
+
def check_prepaid_balances(
|
|
550
|
+
crypto: Crypto,
|
|
551
|
+
ledger_api: EthereumApi,
|
|
552
|
+
mech_payment_balance_tracker: str,
|
|
553
|
+
payment_type: str,
|
|
554
|
+
max_delivery_rate: int,
|
|
555
|
+
) -> None:
|
|
556
|
+
"""
|
|
557
|
+
Checks the requester's prepaid balances for native and token mech.
|
|
558
|
+
|
|
559
|
+
:param crypto: The cryptographic object.
|
|
560
|
+
:type crypto: Crypto
|
|
561
|
+
:param ledger_api: The Ethereum API used for interacting with the ledger.
|
|
562
|
+
:type ledger_api: EthereumApi
|
|
563
|
+
:param mech_payment_balance_tracker: The mech's balance tracker contract address.
|
|
564
|
+
:type mech_payment_balance_tracker: str
|
|
565
|
+
:param payment_type: The payment type of the mech.
|
|
566
|
+
:type payment_type: str
|
|
567
|
+
:param max_delivery_rate: The max_delivery_rate of the mech
|
|
568
|
+
:type max_delivery_rate: int
|
|
569
|
+
"""
|
|
570
|
+
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
|
+
|
|
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)
|
|
593
|
+
|
|
594
|
+
if payment_type == PAYMENT_TYPE_TOKEN:
|
|
595
|
+
with open(
|
|
596
|
+
Path(__file__).parent / "abis" / "BalanceTrackerFixedPriceToken.json",
|
|
597
|
+
encoding="utf-8",
|
|
598
|
+
) as f:
|
|
599
|
+
abi = json.load(f)
|
|
600
|
+
|
|
601
|
+
balance_tracker_contract = get_contract(
|
|
602
|
+
contract_address=mech_payment_balance_tracker,
|
|
603
|
+
abi=abi,
|
|
604
|
+
ledger_api=ledger_api,
|
|
605
|
+
)
|
|
606
|
+
requester_balance = balance_tracker_contract.functions.mapRequesterBalances(
|
|
607
|
+
requester
|
|
608
|
+
).call()
|
|
609
|
+
if requester_balance < max_delivery_rate:
|
|
610
|
+
print(
|
|
611
|
+
f" - Sender Token deposited balance low. Needed: {max_delivery_rate}, Actual: {requester_balance}"
|
|
612
|
+
)
|
|
613
|
+
print(f" - Sender Address: {requester}")
|
|
614
|
+
print(" - Please use scripts/deposit_token.py to add balance")
|
|
615
|
+
sys.exit(1)
|
|
616
|
+
|
|
617
|
+
|
|
618
|
+
def marketplace_interact( # pylint: disable=too-many-arguments, too-many-locals, too-many-statements, too-many-return-statements
|
|
619
|
+
prompt: str,
|
|
620
|
+
priority_mech: str,
|
|
621
|
+
use_prepaid: bool = False,
|
|
622
|
+
use_offchain: bool = False,
|
|
623
|
+
tool: str = "",
|
|
624
|
+
extra_attributes: Optional[Dict[str, Any]] = None,
|
|
625
|
+
private_key_path: Optional[str] = None,
|
|
626
|
+
confirmation_type: ConfirmationType = ConfirmationType.WAIT_FOR_BOTH,
|
|
627
|
+
retries: Optional[int] = None,
|
|
628
|
+
timeout: Optional[float] = None,
|
|
629
|
+
sleep: Optional[float] = None,
|
|
630
|
+
chain_config: Optional[str] = None,
|
|
631
|
+
) -> Any:
|
|
632
|
+
"""
|
|
633
|
+
Interact with mech marketplace contract.
|
|
634
|
+
|
|
635
|
+
:param prompt: The interaction prompt.
|
|
636
|
+
:type prompt: str
|
|
637
|
+
:param priority_mech: Priority mech address to use (Optional)
|
|
638
|
+
:type priority_mech: str
|
|
639
|
+
:param use_prepaid: Whether to use prepaid model or not.
|
|
640
|
+
:type use_prepaid: bool
|
|
641
|
+
:param use_offchain: Whether to use offchain model or not.
|
|
642
|
+
:type use_offchain: bool
|
|
643
|
+
:param tool: The tool to interact with (optional).
|
|
644
|
+
:type tool: str
|
|
645
|
+
:param extra_attributes: Extra attributes to be included in the request metadata (optional).
|
|
646
|
+
:type extra_attributes: Optional[Dict[str, Any]]
|
|
647
|
+
:param private_key_path: The path to the private key file (optional).
|
|
648
|
+
:type private_key_path: Optional[str]
|
|
649
|
+
:param confirmation_type: The confirmation type for the interaction (default: ConfirmationType.WAIT_FOR_BOTH).
|
|
650
|
+
:type confirmation_type: ConfirmationType
|
|
651
|
+
:return: The data received from on-chain/off-chain.
|
|
652
|
+
:param retries: Number of retries for sending a transaction
|
|
653
|
+
:type retries: int
|
|
654
|
+
:param timeout: Timeout to wait for the transaction
|
|
655
|
+
:type timeout: float
|
|
656
|
+
:param sleep: Amount of sleep before retrying the transaction
|
|
657
|
+
:type sleep: float
|
|
658
|
+
:param chain_config: Id of the mech's chain configuration (stored configs/mechs.json)
|
|
659
|
+
:type chain_config: str:
|
|
660
|
+
:rtype: Any
|
|
661
|
+
"""
|
|
662
|
+
|
|
663
|
+
mech_config = get_mech_config(chain_config)
|
|
664
|
+
ledger_config = mech_config.ledger_config
|
|
665
|
+
priority_mech_address = priority_mech
|
|
666
|
+
mech_marketplace_contract = mech_config.mech_marketplace_contract
|
|
667
|
+
chain_id = ledger_config.chain_id
|
|
668
|
+
|
|
669
|
+
if mech_marketplace_contract == ADDRESS_ZERO:
|
|
670
|
+
print(f"Mech Marketplace not yet supported on {chain_config}")
|
|
671
|
+
return None
|
|
672
|
+
|
|
673
|
+
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
|
+
)
|
|
682
|
+
|
|
683
|
+
mech_marketplace_request_config: MechMarketplaceRequestConfig = make_dataclass(
|
|
684
|
+
"MechMarketplaceRequestConfig",
|
|
685
|
+
((k, type(v)) for k, v in config_values.items()),
|
|
686
|
+
)(**config_values)
|
|
687
|
+
|
|
688
|
+
contract_address = cast(
|
|
689
|
+
str, mech_marketplace_request_config.mech_marketplace_contract
|
|
690
|
+
)
|
|
691
|
+
|
|
692
|
+
private_key_path = private_key_path or PRIVATE_KEY_FILE_PATH
|
|
693
|
+
if not Path(private_key_path).exists():
|
|
694
|
+
raise FileNotFoundError(
|
|
695
|
+
f"Private key file `{private_key_path}` does not exist!"
|
|
696
|
+
)
|
|
697
|
+
|
|
698
|
+
wss = websocket.create_connection(mech_config.wss_endpoint)
|
|
699
|
+
crypto = EthereumCrypto(private_key_path=private_key_path)
|
|
700
|
+
ledger_api = EthereumApi(**asdict(ledger_config))
|
|
701
|
+
|
|
702
|
+
with open(
|
|
703
|
+
Path(__file__).parent / "abis" / "MechMarketplace.json", encoding="utf-8"
|
|
704
|
+
) as f:
|
|
705
|
+
abi = json.load(f)
|
|
706
|
+
|
|
707
|
+
mech_marketplace_contract = get_contract(
|
|
708
|
+
contract_address=contract_address, abi=abi, ledger_api=ledger_api
|
|
709
|
+
)
|
|
710
|
+
|
|
711
|
+
print("Fetching Mech Info...")
|
|
712
|
+
priority_mech_address = cast(
|
|
713
|
+
str, mech_marketplace_request_config.priority_mech_address
|
|
714
|
+
)
|
|
715
|
+
(
|
|
716
|
+
payment_type,
|
|
717
|
+
_,
|
|
718
|
+
max_delivery_rate,
|
|
719
|
+
mech_payment_balance_tracker,
|
|
720
|
+
mech_contract,
|
|
721
|
+
) = fetch_mech_info(
|
|
722
|
+
ledger_api,
|
|
723
|
+
mech_marketplace_contract,
|
|
724
|
+
priority_mech_address,
|
|
725
|
+
)
|
|
726
|
+
mech_marketplace_request_config.delivery_rate = max_delivery_rate
|
|
727
|
+
mech_marketplace_request_config.payment_type = payment_type
|
|
728
|
+
|
|
729
|
+
(
|
|
730
|
+
marketplace_request_event_signature,
|
|
731
|
+
marketplace_deliver_event_signature,
|
|
732
|
+
) = get_event_signatures(abi=abi)
|
|
733
|
+
|
|
734
|
+
register_event_handlers(
|
|
735
|
+
wss=wss,
|
|
736
|
+
contract_address=contract_address,
|
|
737
|
+
crypto=crypto,
|
|
738
|
+
request_signature=marketplace_request_event_signature,
|
|
739
|
+
deliver_signature=marketplace_deliver_event_signature,
|
|
740
|
+
)
|
|
741
|
+
|
|
742
|
+
if not use_prepaid:
|
|
743
|
+
price = max_delivery_rate
|
|
744
|
+
if payment_type == PAYMENT_TYPE_TOKEN:
|
|
745
|
+
print("Token Mech detected, approving wrapped token for price payment...")
|
|
746
|
+
wxdai = CHAIN_TO_WRAPPED_TOKEN[chain_id]
|
|
747
|
+
approve_tx = approve_price_tokens(
|
|
748
|
+
crypto, ledger_api, wxdai, mech_payment_balance_tracker, price
|
|
749
|
+
)
|
|
750
|
+
if not approve_tx:
|
|
751
|
+
print("Unable to approve allowance")
|
|
752
|
+
return None
|
|
753
|
+
|
|
754
|
+
transaction_url_formatted = mech_config.transaction_url.format(
|
|
755
|
+
transaction_digest=approve_tx
|
|
756
|
+
)
|
|
757
|
+
print(f" - Transaction sent: {transaction_url_formatted}")
|
|
758
|
+
print(" - Waiting for transaction receipt...")
|
|
759
|
+
wait_for_receipt(approve_tx, ledger_api)
|
|
760
|
+
# set price 0 to not send any msg.value in request transaction for token type mech
|
|
761
|
+
price = 0
|
|
762
|
+
|
|
763
|
+
else:
|
|
764
|
+
print("Prepaid request to be used, skipping payment")
|
|
765
|
+
price = 0
|
|
766
|
+
|
|
767
|
+
check_prepaid_balances(
|
|
768
|
+
crypto,
|
|
769
|
+
ledger_api,
|
|
770
|
+
mech_payment_balance_tracker,
|
|
771
|
+
payment_type,
|
|
772
|
+
max_delivery_rate,
|
|
773
|
+
)
|
|
774
|
+
|
|
775
|
+
if payment_type == PAYMENT_TYPE_NVM:
|
|
776
|
+
print("Nevermined Mech detected, subscription credits to be used")
|
|
777
|
+
requester = crypto.address
|
|
778
|
+
requester_balance = fetch_requester_nvm_subscription_balance(
|
|
779
|
+
requester, ledger_api, mech_payment_balance_tracker
|
|
780
|
+
)
|
|
781
|
+
if requester_balance < price:
|
|
782
|
+
print(
|
|
783
|
+
f" - Sender Subscription balance low. Needed: {price}, Actual: {requester_balance}"
|
|
784
|
+
)
|
|
785
|
+
print(f" - Sender Address: {requester}")
|
|
786
|
+
sys.exit(1)
|
|
787
|
+
|
|
788
|
+
# set price 0 to not send any msg.value in request transaction for nvm type mech
|
|
789
|
+
price = 0
|
|
790
|
+
|
|
791
|
+
if not use_offchain:
|
|
792
|
+
print("Sending Mech Marketplace request...")
|
|
793
|
+
transaction_digest = send_marketplace_request(
|
|
794
|
+
crypto=crypto,
|
|
795
|
+
ledger_api=ledger_api,
|
|
796
|
+
marketplace_contract=mech_marketplace_contract,
|
|
797
|
+
gas_limit=mech_config.gas_limit,
|
|
798
|
+
price=price,
|
|
799
|
+
prompt=prompt,
|
|
800
|
+
tool=tool,
|
|
801
|
+
method_args_data=mech_marketplace_request_config,
|
|
802
|
+
extra_attributes=extra_attributes,
|
|
803
|
+
retries=retries,
|
|
804
|
+
timeout=timeout,
|
|
805
|
+
sleep=sleep,
|
|
806
|
+
)
|
|
807
|
+
|
|
808
|
+
if not transaction_digest:
|
|
809
|
+
print("Unable to send request")
|
|
810
|
+
return None
|
|
811
|
+
|
|
812
|
+
transaction_url_formatted = mech_config.transaction_url.format(
|
|
813
|
+
transaction_digest=transaction_digest
|
|
814
|
+
)
|
|
815
|
+
print(f" - Transaction sent: {transaction_url_formatted}")
|
|
816
|
+
print(" - Waiting for transaction receipt...")
|
|
817
|
+
|
|
818
|
+
request_id = watch_for_marketplace_request_id(
|
|
819
|
+
marketplace_contract=mech_marketplace_contract,
|
|
820
|
+
ledger_api=ledger_api,
|
|
821
|
+
tx_hash=transaction_digest,
|
|
822
|
+
)
|
|
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}")
|
|
825
|
+
print("")
|
|
826
|
+
|
|
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
|
+
)
|
|
837
|
+
|
|
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
|
|
844
|
+
return None
|
|
845
|
+
|
|
846
|
+
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
|
+
)
|
|
858
|
+
|
|
859
|
+
if not response:
|
|
860
|
+
return None
|
|
861
|
+
|
|
862
|
+
request_id = response["request_id"]
|
|
863
|
+
print(f" - Created off-chain request with ID {request_id}")
|
|
864
|
+
print("")
|
|
865
|
+
|
|
866
|
+
# @note as we are directly querying data from done task list, we get the full data instead of the ipfs hash
|
|
867
|
+
print("Waiting for Offchain Mech Marketplace deliver...")
|
|
868
|
+
data = wait_for_offchain_marketplace_data(
|
|
869
|
+
request_id=request_id,
|
|
870
|
+
)
|
|
871
|
+
|
|
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
|
|
880
|
+
return None
|