naeural-client 3.0.8__py3-none-any.whl → 3.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.
naeural_client/_ver.py CHANGED
@@ -1,4 +1,4 @@
1
- __VER__ = "3.0.8"
1
+ __VER__ = "3.1.0"
2
2
 
3
3
  if __name__ == "__main__":
4
4
  with open("pyproject.toml", "rt") as fd:
@@ -328,7 +328,7 @@ class GenericSession(BaseDecentrAIObject):
328
328
  self.__fill_config(
329
329
  host=self.__host,
330
330
  port=self.__port,
331
- user=self.__port,
331
+ user=self.__user,
332
332
  pwd=self.__pwd,
333
333
  secured=self.__secured,
334
334
  )
@@ -3000,6 +3000,7 @@ class GenericSession(BaseDecentrAIObject):
3000
3000
 
3001
3001
  eth: bool, optional
3002
3002
  If True, will use the nodes eth addresses instead of internal. Defaults to False.
3003
+ It will also display extra info about node wallets (ETH and $R1 balances)
3003
3004
 
3004
3005
  all_info: bool, optional
3005
3006
  If True, will return all the information. Defaults to False.
@@ -3032,10 +3033,17 @@ class GenericSession(BaseDecentrAIObject):
3032
3033
  if all_info:
3033
3034
  mapping = OrderedDict({
3034
3035
  # we assign dummy integer values to the computed columns
3035
- # and we will fillter them
3036
+ # and we will filter them
3036
3037
  'ETH Address': 1,
3037
3038
  **mapping
3038
3039
  })
3040
+ if eth or all_info:
3041
+ mapping = OrderedDict({
3042
+ **mapping,
3043
+ 'ETH' : 2,
3044
+ '$R1' : 3,
3045
+ })
3046
+ # end if eth or all_info
3039
3047
  res = OrderedDict()
3040
3048
  for k in mapping:
3041
3049
  res[k] = []
@@ -3074,6 +3082,7 @@ class GenericSession(BaseDecentrAIObject):
3074
3082
  continue
3075
3083
  for key, column in reverse_mapping.items():
3076
3084
  if isinstance(key, int):
3085
+ # if the key is an integer, then it is a computed column
3077
3086
  continue
3078
3087
  val = node_info.get(key, None)
3079
3088
  if key == PAYLOAD_DATA.NETMON_LAST_REMOTE_TIME:
@@ -3088,16 +3097,26 @@ class GenericSession(BaseDecentrAIObject):
3088
3097
  # again self.get_node_alias(best_super) might not work if using the hb data
3089
3098
  best_super_alias = node_info.get(PAYLOAD_DATA.NETMON_EEID, None)
3090
3099
  val = self.bc_engine._add_prefix(val)
3100
+ add_balance = False
3091
3101
  if all_info:
3092
3102
  val_eth = self.bc_engine.node_address_to_eth_address(val)
3093
3103
  res['ETH Address'].append(val_eth)
3104
+ eth_addr = val_eth
3105
+ add_balance = True
3094
3106
  elif eth:
3095
3107
  val = self.bc_engine.node_address_to_eth_address(val)
3108
+ eth_addr = val
3109
+ add_balance = True
3110
+ if add_balance:
3111
+ eth_balance = self.bc_engine.web3_get_balance_eth(val)
3112
+ r1_balance = self.bc_engine.web3_get_balance_r1(val)
3113
+ res['ETH'].append(round(eth_balance,4))
3114
+ res['$R1'].append(round(r1_balance,4))
3096
3115
  elif key == PAYLOAD_DATA.NETMON_WHITELIST:
3097
3116
  val = client_is_allowed
3098
3117
  elif key in [PAYLOAD_DATA.NETMON_STATUS_KEY, PAYLOAD_DATA.NETMON_NODE_VERSION]:
3099
3118
  val = val.split(' ')[0]
3100
- res[column].append(val)
3119
+ res[column].append(val)
3101
3120
  # end for
3102
3121
  # end if
3103
3122
  pd.options.display.float_format = '{:.1f}'.format
naeural_client/bc/base.py CHANGED
@@ -815,7 +815,7 @@ class BaseBlockEngine(_EVMMixin):
815
815
 
816
816
  """
817
817
  if from_file and os.path.isfile(source):
818
- self.P("Reading SK from '{}'".format(source), verbosity=1)
818
+ self.P("Reading SK from '{}'".format(source), verbosity=2)
819
819
  with open(source, 'rt') as fh:
820
820
  data = fh.read()
821
821
  else:
naeural_client/bc/evm.py CHANGED
@@ -1,5 +1,8 @@
1
+ import json
1
2
  import os
2
3
 
4
+ from collections import namedtuple
5
+
3
6
  from eth_account import Account
4
7
  from eth_utils import keccak, to_checksum_address
5
8
  from eth_account.messages import encode_defunct
@@ -10,346 +13,769 @@ EE_VPN_IMPL = str(os.environ.get(EE_VPN_IMPL_ENV_KEY, False)).lower() in [
10
13
  'true', '1', 'yes', 'y', 't', 'on'
11
14
  ]
12
15
 
13
- if EE_VPN_IMPL:
16
+ Web3Vars = namedtuple("Web3Vars", [
17
+ "w3", "rpc_url", "nd_contract_address", "r1_contract_address", "network"
18
+ ])
19
+
20
+
21
+ if not EE_VPN_IMPL:
22
+ from web3 import Web3
23
+ else:
14
24
  class Web3:
15
25
  """
16
26
  VPS enabled. Web3 is not available.
17
27
  """
18
- else:
19
- from web3 import Web3
20
-
21
28
 
29
+ # A minimal ERC20 ABI for balanceOf, transfer, and decimals functions.
30
+ ERC20_ABI = [
31
+ {
32
+ "constant": True,
33
+ "inputs": [{"name": "_owner", "type": "address"}],
34
+ "name": "balanceOf",
35
+ "outputs": [{"name": "balance", "type": "uint256"}],
36
+ "payable": False,
37
+ "stateMutability": "view",
38
+ "type": "function"
39
+ },
40
+ {
41
+ "constant": False,
42
+ "inputs": [
43
+ {"name": "_to", "type": "address"},
44
+ {"name": "_value", "type": "uint256"}
45
+ ],
46
+ "name": "transfer",
47
+ "outputs": [{"name": "success", "type": "bool"}],
48
+ "payable": False,
49
+ "stateMutability": "nonpayable",
50
+ "type": "function"
51
+ },
52
+ {
53
+ "constant": True,
54
+ "inputs": [],
55
+ "name": "decimals",
56
+ "outputs": [{"name": "", "type": "uint8"}],
57
+ "payable": False,
58
+ "stateMutability": "view",
59
+ "type": "function"
60
+ }
61
+ ]
22
62
 
23
63
  class _EVMMixin:
24
64
 
25
-
26
- @staticmethod
27
- def is_valid_evm_address(address: str) -> bool:
28
- """
29
- Check if the input string is a valid Ethereum (EVM) address using basic heuristics.
30
-
31
- Parameters
32
- ----------
33
- address : str
34
- The address string to verify.
35
-
36
- Returns
37
- -------
38
- bool
39
- True if `address` meets the basic criteria for an EVM address, False otherwise.
40
- """
41
- # Basic checks:
42
- # A) Must start with '0x'
43
- # B) Must be exactly 42 characters in total
44
- # C) All remaining characters must be valid hexadecimal digits
45
- if not address.startswith("0x"):
46
- return False
47
- if len(address) != 42:
48
- return False
65
+ # EVM address methods
66
+ if True:
67
+ @staticmethod
68
+ def is_valid_evm_address(address: str) -> bool:
69
+ """
70
+ Check if the input string is a valid Ethereum (EVM) address using basic heuristics.
71
+
72
+ Parameters
73
+ ----------
74
+ address : str
75
+ The address string to verify.
76
+
77
+ Returns
78
+ -------
79
+ bool
80
+ True if `address` meets the basic criteria for an EVM address, False otherwise.
81
+ """
82
+ # Basic checks:
83
+ # A) Must start with '0x'
84
+ # B) Must be exactly 42 characters in total
85
+ # C) All remaining characters must be valid hexadecimal digits
86
+ if not address.startswith("0x"):
87
+ return False
88
+ if len(address) != 42:
89
+ return False
90
+
91
+ hex_part = address[2:]
92
+ # Ensure all characters in the hex part are valid hex digits
93
+ return all(c in "0123456789abcdefABCDEF" for c in hex_part)
49
94
 
50
- hex_part = address[2:]
51
- # Ensure all characters in the hex part are valid hex digits
52
- return all(c in "0123456789abcdefABCDEF" for c in hex_part)
53
-
54
- @staticmethod
55
- def is_valid_eth_address(address: str) -> bool:
56
- """
57
- Check if the input string is a valid Ethereum (EVM) address using basic heuristics.
95
+ @staticmethod
96
+ def is_valid_eth_address(address: str) -> bool:
97
+ """
98
+ Check if the input string is a valid Ethereum (EVM) address using basic heuristics.
99
+
100
+ Parameters
101
+ ----------
102
+ address : str
103
+ The address string to verify.
104
+
105
+ Returns
106
+ -------
107
+ bool
108
+ True if `address` meets the basic criteria for an EVM address, False otherwise.
109
+ """
110
+ return _EVMMixin.is_valid_evm_address(address)
111
+
112
+
113
+ def _get_eth_address(self, pk=None):
114
+ if pk is None:
115
+ pk = self.public_key
116
+ raw_public_key = pk.public_numbers()
117
+
118
+ # Compute Ethereum-compatible address
119
+ x = raw_public_key.x.to_bytes(32, 'big')
120
+ y = raw_public_key.y.to_bytes(32, 'big')
121
+ uncompressed_key = b'\x04' + x + y
122
+ keccak_hash = keccak(uncompressed_key[1:]) # Remove 0x04 prefix
123
+ eth_address = "0x" + keccak_hash[-20:].hex()
124
+ eth_address = to_checksum_address(eth_address)
125
+ return eth_address
126
+
127
+
128
+ def _get_eth_account(self):
129
+ private_key_bytes = self.private_key.private_numbers().private_value.to_bytes(32, 'big')
130
+ return Account.from_key(private_key_bytes)
131
+
132
+
133
+ def node_address_to_eth_address(self, address):
134
+ """
135
+ Converts a node address to an Ethereum address.
136
+
137
+ Parameters
138
+ ----------
139
+ address : str
140
+ The node address convert.
141
+
142
+ Returns
143
+ -------
144
+ str
145
+ The Ethereum address.
146
+ """
147
+ public_key = self._address_to_pk(address)
148
+ return self._get_eth_address(pk=public_key)
149
+
150
+
151
+ def is_node_address_in_eth_addresses(self, node_address: str, lst_eth_addrs) -> bool:
152
+ """
153
+ Check if the node address is in the list of Ethereum addresses
154
+
155
+ Parameters
156
+ ----------
157
+ node_address : str
158
+ the node address.
159
+
160
+ lst_eth_addrs : list
161
+ list of Ethereum addresses.
58
162
 
59
- Parameters
60
- ----------
61
- address : str
62
- The address string to verify.
163
+ Returns
164
+ -------
165
+ bool
166
+ True if the node address is in the list of Ethereum addresses.
63
167
 
64
- Returns
65
- -------
66
- bool
67
- True if `address` meets the basic criteria for an EVM address, False otherwise.
68
- """
69
- return _EVMMixin.is_valid_evm_address(address)
168
+ """
169
+ eth_addr = self.node_address_to_eth_address(node_address)
170
+ return eth_addr in lst_eth_addrs
70
171
 
71
172
 
72
- @staticmethod
73
- def get_evm_network() -> str:
74
- """
75
- Get the current network
173
+ # EVM networks
174
+ if True:
175
+ def reset_network(self, network: str):
176
+ assert network.lower() in dAuth.EVM_NET_DATA, f"Invalid network: {network}"
177
+ os.environ[dAuth.DAUTH_NET_ENV_KEY] = network
178
+ return
179
+
180
+ def get_evm_network(self) -> str:
181
+ """
182
+ Get the current network
183
+
184
+ Returns
185
+ -------
186
+ str
187
+ the network name.
188
+
189
+ """
190
+ network = os.environ.get(dAuth.DAUTH_NET_ENV_KEY, dAuth.DAUTH_SDK_NET_DEFAULT)
191
+ if not hasattr(self, "current_evm_network") or self.current_evm_network != network:
192
+ self.current_evm_network = network
193
+ network_data = self.get_network_data(network)
194
+ rpc_url = network_data[dAuth.EvmNetData.DAUTH_RPC_KEY]
195
+ self.web3 = Web3(Web3.HTTPProvider(rpc_url))
196
+ self.P(f"Resetting Web3 for {network=} via {rpc_url=}...")
197
+ return network
198
+
199
+ @property
200
+ def evm_network(self):
201
+ return self.get_evm_network()
76
202
 
77
- Returns
78
- -------
79
- str
80
- the network name.
203
+
204
+ def get_network_data(self, network: str) -> dict:
205
+ assert isinstance(network, str) and network.lower() in dAuth.EVM_NET_DATA, f"Invalid network: {network}"
206
+ return dAuth.EVM_NET_DATA[network.lower()]
207
+
81
208
 
82
- """
83
- return os.environ.get(dAuth.DAUTH_NET_ENV_KEY, dAuth.DAUTH_SDK_NET_DEFAULT)
84
-
85
- @property
86
- def evm_network(self):
87
- return self.get_evm_network()
88
-
89
- def get_network_data(self, network=None):
90
- assert isinstance(network, str) and network.lower() in dAuth.EVM_NET_DATA, f"Invalid network: {network}"
91
- return dAuth.EVM_NET_DATA[network.lower()]
209
+ @property
210
+ def network_rpc(self):
211
+ return self.get_network_data(self.evm_network)[dAuth.EvmNetData.DAUTH_RPC_KEY]
92
212
 
93
-
94
- def web3_is_node_licensed(self, address : str, network=None, debug=False) -> bool:
95
- """
96
- Check if the address is allowed to send commands to the node
97
213
 
98
- Parameters
99
- ----------
100
- address : str
101
- the address to check.
102
- """
103
- if EE_VPN_IMPL:
104
- self.P("VPN implementation. Skipping Ethereum check.", color='r')
105
- return False
214
+ @property
215
+ def nd_contract_address(self):
216
+ return self.get_network_data(self.evm_network)[dAuth.EvmNetData.DAUTH_ND_ADDR_KEY]
106
217
 
107
- if network is None:
108
- network = self.evm_network
109
-
110
- assert self.is_valid_eth_address(address), "Invalid Ethereum address"
218
+ @property
219
+ def r1_contract_address(self):
220
+ return self.get_network_data(self.evm_network)[dAuth.EvmNetData.DAUTH_R1_ADDR_KEY]
221
+
222
+
223
+ def _get_web3_vars(self, network=None) -> Web3Vars:
224
+ if network is None:
225
+ network = self.evm_network
226
+ w3 = self.web3
227
+ rpc_url = self.network_rpc
228
+ nd_contract_address = self.nd_contract_address
229
+ r1_contract_address = self.r1_contract_address
230
+ else:
231
+ network_data = self.get_network_data(network)
232
+ nd_contract_address = network_data[dAuth.EvmNetData.DAUTH_ND_ADDR_KEY]
233
+ rpc_url = network_data[dAuth.EvmNetData.DAUTH_RPC_KEY]
234
+ r1_contract_address = network_data[dAuth.EvmNetData.DAUTH_R1_ADDR_KEY]
235
+ w3 = Web3(Web3.HTTPProvider(rpc_url))
236
+ self.P(f"Created temporary Web3 for {network=} via {rpc_url=}...", verbosity=2)
237
+ result = Web3Vars(
238
+ w3=w3, rpc_url=rpc_url, nd_contract_address=nd_contract_address,
239
+ r1_contract_address=r1_contract_address, network=network
240
+ )
241
+ return result
242
+
243
+
244
+ # EVM signing methods (internal)
245
+ if True:
246
+ def eth_hash_message(self, types, values, as_hex=False):
247
+ """
248
+ Hashes a message using the keccak256 algorithm.
249
+
250
+ Parameters
251
+ ----------
252
+ types : list
253
+ The types of the values.
254
+
255
+ values : list of any
256
+ The values to hash.
257
+
258
+ Returns
259
+ -------
260
+ bytes
261
+ The hash of the message in hexadecimal format.
262
+ """
263
+ message = Web3.solidity_keccak(types, values)
264
+ if as_hex:
265
+ return message.hex()
266
+ return message
111
267
 
112
- network_data = self.get_network_data(network)
113
268
 
114
- contract_address = network_data[dAuth.EvmNetData.DAUTH_ND_ADDR_KEY]
115
- rpc_url = network_data[dAuth.EvmNetData.DAUTH_RPC_KEY]
269
+ def eth_sign_message(self, types, values):
270
+ """
271
+ Signs a message using the private key.
272
+
273
+ Parameters
274
+ ----------
275
+ types : list
276
+ The types of the values.
116
277
 
117
- if debug:
118
- self.P(f"Checking if {address} ({network}) is allowed via {rpc_url}...")
119
-
120
- w3 = Web3(Web3.HTTPProvider(rpc_url))
121
-
122
- contract_abi = dAuth.DAUTH_ABI_IS_NODE_ACTIVE
278
+ values : list of any
279
+ The values to sign.
123
280
 
124
- contract = w3.eth.contract(address=contract_address, abi=contract_abi)
125
-
126
- result = contract.functions.isNodeActive(address).call()
127
- return result
128
-
129
-
130
- def web3_get_oracles(self, network=None, debug=False) -> list:
131
- """
132
- Get the list of oracles from the contract
133
-
134
- Parameters
135
- ----------
136
- network : str, optional
137
- the network to use. The default is None.
138
-
139
- Returns
140
- -------
141
- list
142
- the list of oracles addresses.
143
-
144
- """
145
- if network is None:
146
- network = self.evm_network
147
-
148
- network_data = self.get_network_data(network)
281
+ Returns
282
+ -------
283
+ str
284
+ The signature of the message.
285
+
286
+ Notes
287
+ -----
288
+
289
+ This function is using the `eth_account` property generated from the private key via
290
+ the `_get_eth_account` method at the time of the object creation.
291
+ """
292
+ message_hash = self.eth_hash_message(types, values, as_hex=False)
293
+ signable_message = encode_defunct(primitive=message_hash)
294
+ signed_message = Account.sign_message(signable_message, private_key=self.eth_account.key)
295
+ if hasattr(signed_message, "message_hash"): # backward compatibility
296
+ signed_message_hash = signed_message.message_hash
297
+ else:
298
+ signed_message_hash = signed_message.messageHash
299
+ return {
300
+ "message_hash": message_hash.hex(),
301
+ "r": hex(signed_message.r),
302
+ "s": hex(signed_message.s),
303
+ "v": signed_message.v,
304
+ "signature": signed_message.signature.hex(),
305
+ "signed_message": signed_message_hash.hex(),
306
+ "sender" : self.eth_address,
307
+ "eth_signed_data" : types,
308
+ }
309
+
310
+ def eth_sign_text(self, message, signature_only=True):
311
+ """
312
+ Signs a text message using the private key.
313
+
314
+ Parameters
315
+ ----------
316
+ message : str
317
+ The message to sign.
318
+
319
+ signature_only : bool, optional
320
+ Whether to return only the signature. The default is True
321
+
322
+ Returns
323
+ -------
324
+ str
325
+ The signature of the message.
326
+ """
327
+ types = ["string"]
328
+ values = [message]
329
+ result = self.eth_sign_message(types, values)
330
+ if signature_only:
331
+ return result["signature"]
332
+ return result
333
+
334
+
335
+
336
+ def eth_sign_node_epochs(
337
+ self,
338
+ node,
339
+ epochs,
340
+ epochs_vals,
341
+ signature_only=True,
342
+ use_evm_node_addr=True
343
+ ):
344
+ """
345
+ Signs the node availability
346
+
347
+ Parameters
348
+ ----------
349
+ node : str
350
+ The node address to sign. Either the node address or the Ethereum address based on `use_evm_node_addr`.
351
+
352
+ epochs : list of int
353
+ The epochs to sign.
354
+
355
+ epochs_vals : list of int
356
+ The values for each epoch.
357
+
358
+ signature_only : bool, optional
359
+ Whether to return only the signature. The default is True.
360
+
361
+ use_evm_node_addr : bool, optional
362
+ Whether to use the Ethereum address of the node. The default is True.
363
+
364
+ Returns
365
+ -------
366
+ str
367
+ The signature of the message.
368
+ """
369
+ if use_evm_node_addr:
370
+ types = ["address", "uint256[]", "uint256[]"]
371
+ else:
372
+ types = ["string", "uint256[]", "uint256[]"]
373
+ values = [node, epochs, epochs_vals]
374
+ result = self.eth_sign_message(types, values)
375
+ if signature_only:
376
+ return result["signature"]
377
+ return result
149
378
 
150
- contract_address = network_data[dAuth.EvmNetData.DAUTH_ND_ADDR_KEY]
151
- rpc_url = network_data[dAuth.EvmNetData.DAUTH_RPC_KEY]
152
-
153
- if debug:
154
- self.P(f"Getting oracles for {network} via {rpc_url}...")
155
379
 
156
- w3 = Web3(Web3.HTTPProvider(rpc_url))
157
-
158
- contract_abi = dAuth.DAUTH_ABI_GET_SIGNERS
159
-
160
- contract = w3.eth.contract(address=contract_address, abi=contract_abi)
161
-
162
- result = contract.functions.getSigners().call()
163
- return result
164
-
165
-
166
-
167
- ### ETH
168
-
169
- def _get_eth_address(self, pk=None):
170
- if pk is None:
171
- pk = self.public_key
172
- raw_public_key = pk.public_numbers()
173
-
174
- # Compute Ethereum-compatible address
175
- x = raw_public_key.x.to_bytes(32, 'big')
176
- y = raw_public_key.y.to_bytes(32, 'big')
177
- uncompressed_key = b'\x04' + x + y
178
- keccak_hash = keccak(uncompressed_key[1:]) # Remove 0x04 prefix
179
- eth_address = "0x" + keccak_hash[-20:].hex()
180
- eth_address = to_checksum_address(eth_address)
181
- return eth_address
182
-
183
- def _get_eth_account(self):
184
- private_key_bytes = self.private_key.private_numbers().private_value.to_bytes(32, 'big')
185
- return Account.from_key(private_key_bytes)
186
-
187
-
188
- def node_address_to_eth_address(self, address):
189
- """
190
- Converts a node address to an Ethereum address.
191
-
192
- Parameters
193
- ----------
194
- address : str
195
- The node address convert.
380
+ ### Web3 functions
381
+ if True:
382
+ def web3_hash_message(self, types, values, as_hex=False):
383
+ """
384
+ Hashes a message using the keccak256 algorithm.
385
+
386
+ Parameters
387
+ ----------
388
+ types : list
389
+ The types of the values.
390
+
391
+ values : list of any
392
+ The values to hash.
393
+
394
+ Returns
395
+ -------
396
+ bytes
397
+ The hash of the message in hexadecimal format.
398
+ """
399
+ return self.eth_hash_message(types, values, as_hex=as_hex)
400
+
401
+ def web3_sign_message(self, types, values):
402
+ """
403
+ Signs a message using the private key.
404
+
405
+ Parameters
406
+ ----------
407
+ types : list
408
+ The types of the values.
409
+
410
+ values : list of any
411
+ The values to sign.
196
412
 
197
- Returns
198
- -------
199
- str
200
- The Ethereum address.
201
- """
202
- public_key = self._address_to_pk(address)
203
- return self._get_eth_address(pk=public_key)
204
-
205
- def is_node_address_in_eth_addresses(self, node_address: str, lst_eth_addrs) -> bool:
206
- """
207
- Check if the node address is in the list of Ethereum addresses
413
+ Returns
414
+ -------
415
+ str
416
+ The signature of the message.
417
+
418
+ Notes
419
+ -----
208
420
 
209
- Parameters
210
- ----------
211
- node_address : str
212
- the node address.
421
+ """
422
+ return self.eth_sign_message(types, values)
423
+
424
+ def web3_is_node_licensed(self, address : str, network=None, debug=False) -> bool:
425
+ """
426
+ Check if the address is allowed to send commands to the node
427
+
428
+ Parameters
429
+ ----------
430
+ address : str
431
+ the address to check.
432
+ """
433
+ if EE_VPN_IMPL:
434
+ self.P("VPN implementation. Skipping Ethereum check.", color='r')
435
+ return False
213
436
 
214
- lst_eth_addrs : list
215
- list of Ethereum addresses.
216
-
217
- Returns
218
- -------
219
- bool
220
- True if the node address is in the list of Ethereum addresses.
437
+ w3vars = self._get_web3_vars(network)
438
+
439
+ assert self.is_valid_eth_address(address), "Invalid Ethereum address"
440
+
441
+ if debug:
442
+ self.P(f"Checking if {address} ({network}) is allowed...")
443
+
444
+ contract_abi = dAuth.DAUTH_ABI_IS_NODE_ACTIVE
445
+ contract = w3vars.w3.eth.contract(address=w3vars.nd_contract_address, abi=contract_abi)
221
446
 
222
- """
223
- eth_addr = self.node_address_to_eth_address(node_address)
224
- return eth_addr in lst_eth_addrs
447
+ result = contract.functions.isNodeActive(address).call()
448
+ return result
225
449
 
226
450
 
227
- def eth_hash_message(self, types, values, as_hex=False):
228
- """
229
- Hashes a message using the keccak256 algorithm.
451
+ def web3_get_oracles(self, network=None, debug=False) -> list:
452
+ """
453
+ Get the list of oracles from the contract
230
454
 
231
- Parameters
232
- ----------
233
- types : list
234
- The types of the values.
235
-
236
- values : list of any
237
- The values to hash.
455
+ Parameters
456
+ ----------
457
+ network : str, optional
458
+ the network to use. The default is None.
238
459
 
239
- Returns
240
- -------
241
- bytes
242
- The hash of the message in hexadecimal format.
243
- """
244
- message = Web3.solidity_keccak(types, values)
245
- if as_hex:
246
- return message.hex()
247
- return message
248
-
249
-
250
- def eth_sign_message(self, types, values):
251
- """
252
- Signs a message using the private key.
460
+ Returns
461
+ -------
462
+ list
463
+ the list of oracles addresses.
253
464
 
254
- Parameters
255
- ----------
256
- types : list
257
- The types of the values.
258
-
259
- values : list of any
260
- The values to sign.
465
+ """
466
+ w3vars = self._get_web3_vars(network)
261
467
 
262
- Returns
263
- -------
264
- str
265
- The signature of the message.
266
- """
267
- message_hash = self.eth_hash_message(types, values, as_hex=False)
268
- signable_message = encode_defunct(primitive=message_hash)
269
- signed_message = Account.sign_message(signable_message, private_key=self.eth_account.key)
270
- if hasattr(signed_message, "message_hash"): # backward compatibility
271
- signed_message_hash = signed_message.message_hash
272
- else:
273
- signed_message_hash = signed_message.messageHash
274
- return {
275
- "message_hash": message_hash.hex(),
276
- "r": hex(signed_message.r),
277
- "s": hex(signed_message.s),
278
- "v": signed_message.v,
279
- "signature": signed_message.signature.hex(),
280
- "signed_message": signed_message_hash.hex(),
281
- "sender" : self.eth_address,
282
- "eth_signed_data" : types,
283
- }
284
-
285
- def eth_sign_text(self, message, signature_only=True):
286
- """
287
- Signs a text message using the private key.
468
+ if debug:
469
+ self.P(f"Getting oracles for {w3vars.network} via {w3vars.rpc_url}...")
470
+
471
+ contract_abi = dAuth.DAUTH_ABI_GET_SIGNERS
472
+ contract = w3vars.w3.eth.contract(
473
+ address=w3vars.nd_contract_address, abi=contract_abi
474
+ )
288
475
 
289
- Parameters
290
- ----------
291
- message : str
292
- The message to sign.
293
-
294
- signature_only : bool, optional
295
- Whether to return only the signature. The default is True
476
+ result = contract.functions.getSigners().call()
477
+ return result
296
478
 
297
- Returns
298
- -------
299
- str
300
- The signature of the message.
301
- """
302
- types = ["string"]
303
- values = [message]
304
- result = self.eth_sign_message(types, values)
305
- if signature_only:
306
- return result["signature"]
307
- return result
308
-
309
479
 
480
+ def web3_get_balance_eth(self, address=None, network=None):
481
+ """
482
+ Get the ETH balance of the address
483
+
484
+ Parameters
485
+ ----------
486
+ address : str
487
+ The address to check.
488
+
489
+ Returns
490
+ -------
491
+ float
492
+ The balance of the address.
493
+ """
494
+ if address is None:
495
+ address = self.eth_address
496
+ assert self.is_valid_eth_address(address), "Invalid Ethereum address"
497
+ w3vars = self._get_web3_vars(network)
498
+ balance_wei = w3vars.w3.eth.get_balance(address)
499
+ balance_eth = w3vars.w3.from_wei(balance_wei, 'ether')
500
+ return float(balance_eth)
501
+
502
+
503
+ def web3_send_eth(
504
+ self,
505
+ to_address,
506
+ amount_eth,
507
+ extra_buffer_eth=0.005,
508
+ network=None,
509
+ wait_for_tx=True,
510
+ timeout=120,
511
+ return_receipt=False,
512
+ raise_if_error=False,
513
+ ):
514
+ """
515
+ Send ETH from the account associated with this object to another address,
516
+ ensuring there is enough balance to cover the transfer amount, gas costs,
517
+ and an additional buffer.
518
+
519
+ Parameters
520
+ ----------
521
+ to_address : str
522
+ The recipient Ethereum address.
523
+
524
+ amount_eth : float
525
+ The amount of ETH to send.
526
+
527
+ extra_buffer_eth : float, optional
528
+ An additional amount (in ETH) as a safety margin. Default is 0.005 ETH.
529
+
530
+ network : str, optional
531
+ The network to use. Default is None.
532
+
533
+ wait_for_tx : bool, optional
534
+ Whether to wait for the transaction to be mined. Default is True.
535
+
536
+ timeout : int, optional
537
+ The maximum time to wait for the transaction to be mined, in seconds. Default is 120 seconds.
538
+
539
+ return_receipt : bool, optional
540
+ If True, returns the transaction receipt instead of the transaction hash. Default is False.
541
+
542
+ raise_if_error : bool, optional
543
+ If True, raises an exception if the transaction fails. Default is False.
544
+
545
+ Returns
546
+ -------
547
+ str
548
+ The transaction hash of the broadcasted transaction.
549
+ """
550
+ w3vars = self._get_web3_vars(network=network)
551
+ network = w3vars.network
552
+
553
+ # Get the sender's address from the object's stored attribute (assumed available)
554
+ from_address = self.eth_address
555
+
556
+ # Fetch the current balance (in Wei)
557
+ balance_wei = w3vars.w3.eth.get_balance(from_address)
558
+
559
+ # Define gas parameters for a standard ETH transfer.
560
+ gas_limit = 21000 # typical gas limit for a simple ETH transfer
561
+ gas_price = w3vars.w3.to_wei('50', 'gwei') # example gas price; you may choose a dynamic approach
562
+
563
+ # Calculate the total gas cost.
564
+ gas_cost = gas_limit * gas_price
565
+
566
+ # Convert transfer amount and buffer to Wei.
567
+ amount_wei = w3vars.w3.to_wei(amount_eth, 'ether')
568
+ extra_buffer = w3vars.w3.to_wei(extra_buffer_eth, 'ether')
569
+
570
+ # Compute the total cost: amount to send + gas cost + extra buffer.
571
+ total_cost = amount_wei + gas_cost + extra_buffer
572
+
573
+ # Check if the balance is sufficient.
574
+ if balance_wei < total_cost:
575
+ msg = "Insufficient funds: your balance is less than the required amount plus gas cost and buffer."
576
+ if raise_if_error:
577
+ raise Exception(msg)
578
+ else:
579
+ self.P(msg, color='r')
580
+ return None
581
+
582
+ # Get the nonce for the transaction.
583
+ nonce = w3vars.w3.eth.get_transaction_count(from_address)
584
+
585
+ chain_id = w3vars.w3.eth.chain_id
586
+
587
+ # Build the transaction dictionary.
588
+ tx = {
589
+ 'nonce': nonce,
590
+ 'to': to_address,
591
+ 'value': amount_wei,
592
+ 'gas': gas_limit,
593
+ 'gasPrice': gas_price,
594
+ 'chainId': chain_id,
595
+ }
596
+
597
+ self.P(f"Executing transaction on {network} via {w3vars.rpc_url}:\n {json.dumps(tx, indent=2)}", verbosity=2)
598
+
599
+ # Sign the transaction with the account's private key.
600
+ signed_tx = w3vars.w3.eth.account.sign_transaction(tx, self.eth_account.key)
601
+
602
+ # Broadcast the signed transaction.
603
+ tx_hash = w3vars.w3.eth.send_raw_transaction(signed_tx.raw_transaction)
604
+
605
+ if wait_for_tx:
606
+ # Wait for the transaction receipt with the specified timeout.
607
+ self.P("Waiting for transaction to be mined...", verbosity=2)
608
+ tx_receipt = w3vars.w3.eth.wait_for_transaction_receipt(tx_hash, timeout=timeout)
609
+ tx_hash_hex = tx_receipt.transactionHash.hex()
610
+ self.P(f"Transaction mined: {tx_hash_hex}", color='g', verbosity=2)
611
+ if return_receipt:
612
+ return tx_receipt
613
+ else:
614
+ return tx_hash_hex
615
+ else:
616
+ return tx_hash.hex()
617
+
618
+
619
+ def web3_get_balance_r1(self, address=None, network=None):
620
+ """
621
+ Get the R1 balance of the address
622
+
623
+ Parameters
624
+ ----------
625
+ address : str
626
+ The address to check.
627
+
628
+ Returns
629
+ -------
630
+ float
631
+ The balance of the address.
632
+ """
633
+ if address is None:
634
+ address = self.eth_address
635
+ assert self.is_valid_eth_address(address), "Invalid Ethereum address"
636
+ w3vars = self._get_web3_vars(network)
637
+
638
+ token_contract = w3vars.w3.eth.contract(
639
+ address=w3vars.r1_contract_address, abi=ERC20_ABI
640
+ )
641
+
642
+ try:
643
+ decimals = token_contract.functions.decimals().call()
644
+ except Exception:
645
+ decimals = 18 # default to 18 if the decimals call fails
646
+
647
+ raw_balance = token_contract.functions.balanceOf(address).call()
648
+ human_balance = raw_balance / (10 ** decimals)
649
+ return float(human_balance)
310
650
 
311
- def eth_sign_node_epochs(
312
- self,
313
- node,
314
- epochs,
315
- epochs_vals,
316
- signature_only=True,
317
- use_evm_node_addr=True
318
- ):
319
- """
320
- Signs the node availability
651
+ def web3_send_r1(
652
+ self,
653
+ to_address: str,
654
+ amount: float,
655
+ extra_buffer_eth: float = 0.005,
656
+ wait_for_tx: bool = False,
657
+ timeout: int = 120,
658
+ network: str = None,
659
+ return_receipt=False,
660
+ raise_if_error=False,
661
+ ):
662
+ """
663
+ Send R1 tokens from the default account (self.eth_address) to the specified address.
664
+
665
+ Parameters
666
+ ----------
667
+ to_address : str
668
+ The recipient's Ethereum address.
669
+
670
+ amount : float
671
+ The amount of R1 tokens to send (in human-readable units).
672
+
673
+ extra_buffer_eth : float, optional
674
+ Additional ETH (in Ether) as a buffer for gas fees. Default is 0.005 ETH.
675
+
676
+ wait_for_tx : bool, optional
677
+ If True, waits for the transaction to be mined and returns the receipt.
678
+ If False, returns immediately with the transaction hash.
679
+
680
+ timeout : int, optional
681
+ Maximum number of seconds to wait for the transaction receipt. Default is 120.
682
+
683
+ network : str, optional
684
+ The network to use. If None, uses the default self.evm_network.
321
685
 
322
- Parameters
323
- ----------
324
- node : str
325
- The node address to sign. Either the node address or the Ethereum address based on `use_evm_node_addr`.
326
-
327
- epochs : list of int
328
- The epochs to sign.
329
-
330
- epochs_vals : list of int
331
- The values for each epoch.
332
-
333
- signature_only : bool, optional
334
- Whether to return only the signature. The default is True.
335
-
336
- use_evm_node_addr : bool, optional
337
- Whether to use the Ethereum address of the node. The default is True.
686
+ return_receipt: bool, optional
687
+ If True, returns the transaction receipt instead of the transaction hash.
688
+
689
+ raise_if_error : bool, optional
690
+ If True, raises an exception if the transaction fails. Default is False.
691
+
692
+ Returns
693
+ -------
694
+ If wait_for_tx is False, returns the transaction hash as a string.
695
+ If wait_for_tx is True, returns the transaction receipt as a dict.
696
+ """
697
+ # Validate the recipient address.
698
+ assert self.is_valid_eth_address(to_address), "Invalid Ethereum address"
699
+
700
+ # Retrieve the Web3 instance, RPC URL, and the R1 contract address.
701
+ # Note: This follows the same pattern as web3_get_balance_r1.
702
+ w3vars = self._get_web3_vars(network)
703
+ network = w3vars.network
704
+
705
+ # Create the token contract instance.
706
+ token_contract = w3vars.w3.eth.contract(
707
+ address=w3vars.r1_contract_address, abi=ERC20_ABI
708
+ )
709
+
710
+ # Get the token's decimals (default to 18 if not available).
711
+ try:
712
+ decimals = token_contract.functions.decimals().call()
713
+ except Exception:
714
+ decimals = 18
715
+
716
+ # Convert the human-readable amount to the token's smallest unit.
717
+ token_amount = int(amount * (10 ** decimals))
718
+
719
+ # Ensure the sender has enough R1 token balance.
720
+ sender_balance = token_contract.functions.balanceOf(self.eth_address).call()
721
+ if sender_balance < token_amount:
722
+ msg = "Insufficient funds: your $R1 balance is less than the required amount."
723
+ if raise_if_error:
724
+ raise Exception(msg)
725
+ else:
726
+ self.P(msg, color='r')
727
+ return None
728
+
729
+ # Estimate gas fees for the token transfer.
730
+ gas_price = w3vars.w3.to_wei('50', 'gwei') # Adjust as needed or use a dynamic gas strategy.
731
+ estimated_gas = token_contract.functions.transfer(
732
+ to_address, token_amount
733
+ ).estimate_gas(
734
+ {'from': self.eth_address}
735
+ )
736
+ gas_cost = estimated_gas * gas_price
737
+
738
+ # Check that the sender's ETH balance can cover gas costs plus an extra buffer.
739
+ eth_balance = w3vars.w3.eth.get_balance(self.eth_address)
740
+ extra_buffer = w3vars.w3.to_wei(extra_buffer_eth, 'ether')
741
+ if eth_balance < gas_cost + extra_buffer:
742
+ raise Exception("Insufficient ETH balance to cover gas fees and extra buffer.")
743
+
744
+ # Get the transaction count for the nonce.
745
+ nonce = w3vars.w3.eth.get_transaction_count(self.eth_address)
746
+
747
+ # Programmatically determine the chainId.
748
+ chain_id = w3vars.w3.eth.chain_id
749
+
750
+ # Build the transaction for the ERC20 transfer.
751
+ tx = token_contract.functions.transfer(to_address, token_amount).build_transaction({
752
+ 'from': self.eth_address,
753
+ 'nonce': nonce,
754
+ 'gas': estimated_gas,
755
+ 'gasPrice': gas_price,
756
+ 'chainId': chain_id,
757
+ })
758
+
759
+ self.P(f"Executing transaction on {network} via {w3vars.rpc_url}:\n {json.dumps(dict(tx), indent=2)}", verbosity=2)
760
+
761
+ # Sign the transaction using the internal account (via _get_eth_account).
762
+ eth_account = self._get_eth_account()
763
+ signed_tx = w3vars.w3.eth.account.sign_transaction(tx, eth_account.key)
764
+
765
+ # Broadcast the transaction.
766
+ tx_hash = w3vars.w3.eth.send_raw_transaction(signed_tx.raw_transaction)
767
+
768
+ if wait_for_tx:
769
+ # Wait for the transaction receipt if required.
770
+ tx_receipt = w3vars.w3.eth.wait_for_transaction_receipt(tx_hash, timeout=timeout)
771
+ tx_hash_hex = tx_receipt.transactionHash.hex()
772
+ self.P(f"Transaction mined: {tx_hash_hex}", color='g', verbosity=2)
773
+ if return_receipt:
774
+ return tx_receipt
775
+ else:
776
+ return tx_hash_hex
777
+ else:
778
+ return tx_hash.hex()
338
779
 
339
- Returns
340
- -------
341
- str
342
- The signature of the message.
343
- """
344
- if use_evm_node_addr:
345
- types = ["address", "uint256[]", "uint256[]"]
346
- else:
347
- types = ["string", "uint256[]", "uint256[]"]
348
- values = [node, epochs, epochs_vals]
349
- result = self.eth_sign_message(types, values)
350
- if signature_only:
351
- return result["signature"]
352
- return result
353
-
354
780
 
355
-
781
+
@@ -76,6 +76,8 @@ def get_nodes(args):
76
76
  log_with_color(f"No supervisors or no comms available in {elapsed:.1f}s. Please check your settings.", color='r')
77
77
  else:
78
78
  log_with_color(f"<{network}> {prefix}odes reported by <{supervisor}> '{super_alias}' in {elapsed:.1f}s ({nr_supers} supervisors seen):", color='b')
79
+ import pandas as pd
80
+ pd.set_option('display.float_format', '{:.4f}'.format)
79
81
  log_with_color(f"{df}")
80
82
  return
81
83
 
@@ -2,6 +2,7 @@ class EvmNetData:
2
2
  DAUTH_URL_KEY = 'EE_DAUTH_URL'
3
3
  DAUTH_ND_ADDR_KEY = 'EE_DAUTH_ND_ADDR'
4
4
  DAUTH_RPC_KEY = 'EE_DAUTH_RPC'
5
+ DAUTH_R1_ADDR_KEY = 'EE_DAUTH_R1_ADDR'
5
6
 
6
7
  EE_GENESIS_EPOCH_DATE_KEY = 'EE_GENESIS_EPOCH_DATE'
7
8
  EE_EPOCH_INTERVALS_KEY = 'EE_EPOCH_INTERVALS'
@@ -15,6 +16,7 @@ EVM_NET_DATA = {
15
16
  'mainnet': {
16
17
  EvmNetData.DAUTH_URL_KEY : "https://dauth.ratio1.ai/get_auth_data",
17
18
  EvmNetData.DAUTH_ND_ADDR_KEY : "0xE20198EE2B76eED916A568a47cdea9681f7c79BF",
19
+ EvmNetData.DAUTH_R1_ADDR_KEY : "0xc992DcaB6D3F8783fBf0c935E7bCeB20aa50A6f1",
18
20
  EvmNetData.DAUTH_RPC_KEY : "https://base-mainnet.public.blastapi.io",
19
21
  EvmNetData.EE_GENESIS_EPOCH_DATE_KEY : "2025-02-05 16:00:00",
20
22
  EvmNetData.EE_EPOCH_INTERVALS_KEY : 24,
@@ -26,6 +28,7 @@ EVM_NET_DATA = {
26
28
  'testnet': {
27
29
  EvmNetData.DAUTH_URL_KEY : "https://testnet-dauth.ratio1.ai/get_auth_data",
28
30
  EvmNetData.DAUTH_ND_ADDR_KEY : "0xE20198EE2B76eED916A568a47cdea9681f7c79BF",
31
+ EvmNetData.DAUTH_R1_ADDR_KEY : "0xc992DcaB6D3F8783fBf0c935E7bCeB20aa50A6f1",
29
32
  EvmNetData.DAUTH_RPC_KEY : "https://base-sepolia.public.blastapi.io",
30
33
  EvmNetData.EE_GENESIS_EPOCH_DATE_KEY : "2025-02-05 16:00:00",
31
34
  EvmNetData.EE_EPOCH_INTERVALS_KEY : 24,
@@ -38,6 +41,7 @@ EVM_NET_DATA = {
38
41
  'devnet' : {
39
42
  EvmNetData.DAUTH_URL_KEY : "https://devnet-dauth.ratio1.ai/get_auth_data",
40
43
  EvmNetData.DAUTH_ND_ADDR_KEY : "0x9f49fc29366F1C8285d42e7E82cA0bb668B32CeA",
44
+ EvmNetData.DAUTH_R1_ADDR_KEY : "0xEF38a3d84D3E3111fb7b794Ba3240187b8B32825",
41
45
  EvmNetData.DAUTH_RPC_KEY : "https://base-sepolia.public.blastapi.io",
42
46
  EvmNetData.EE_GENESIS_EPOCH_DATE_KEY : "2025-02-12 16:00:00",
43
47
  EvmNetData.EE_EPOCH_INTERVALS_KEY : 1,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: naeural_client
3
- Version: 3.0.8
3
+ Version: 3.1.0
4
4
  Summary: `naeural_client` is the Python SDK required for client app development for the Naeural Edge Protocol Edge Protocol framework
5
5
  Project-URL: Homepage, https://github.com/NaeuralEdgeProtocol/naeural_client
6
6
  Project-URL: Bug Tracker, https://github.com/NaeuralEdgeProtocol/naeural_client/issues
@@ -1,10 +1,10 @@
1
1
  naeural_client/__init__.py,sha256=YimqgDbjLuywsf8zCWE0EaUXH4MBUrqLxt0TDV558hQ,632
2
- naeural_client/_ver.py,sha256=agGbq5olvN2ffZrM6LrywhSzIGk7JKT-eRMKkI0bRjM,330
2
+ naeural_client/_ver.py,sha256=38HgbYd0O610ADMgWk8TVOk4AsO8FARwG5095hnCzG4,330
3
3
  naeural_client/base_decentra_object.py,sha256=C4iwZTkhKNBS4VHlJs5DfElRYLo4Q9l1V1DNVSk1fyQ,4412
4
4
  naeural_client/plugins_manager_mixin.py,sha256=X1JdGLDz0gN1rPnTN_5mJXR8JmqoBFQISJXmPR9yvCo,11106
5
5
  naeural_client/base/__init__.py,sha256=hACh83_cIv7-PwYMM3bQm2IBmNqiHw-3PAfDfAEKz9A,259
6
6
  naeural_client/base/distributed_custom_code_presets.py,sha256=cvz5R88P6Z5V61Ce1vHVVh8bOkgXd6gve_vdESDNAsg,2544
7
- naeural_client/base/generic_session.py,sha256=UVrcCfq9W-wBCF8b3XTFtNzXJ2NDaBJKPx5NWwIW1Xk,115925
7
+ naeural_client/base/generic_session.py,sha256=eIN-VG1Mr7Z8fqZBngUvS29a0QdAnxT1TIgZxjvXEHE,116714
8
8
  naeural_client/base/instance.py,sha256=bDb9y9ez1vLEGGOCAACQoil7Dw-h7UAwCc18IEfqEas,20789
9
9
  naeural_client/base/pipeline.py,sha256=GYqDd59QQEn7_MTM_dhWsZtdit5q3rECC8HEivWXowo,60068
10
10
  naeural_client/base/plugin_template.py,sha256=7YAFaND2iXoZLgtunjYkFf_TBGieFr3VdNLO3vCqzmM,138795
@@ -14,17 +14,17 @@ naeural_client/base/webapp_pipeline.py,sha256=ZNGqZ36DY076XVDfGu2Q61kCt3kxIJ4Mi4
14
14
  naeural_client/base/payload/__init__.py,sha256=y8fBI8tG2ObNfaXFWjyWZXwu878FRYj_I8GIbHT4GKE,29
15
15
  naeural_client/base/payload/payload.py,sha256=x-au7l67Z_vfn_4R2C_pjZCaFuUVXHngJiGOfIAYVdE,2690
16
16
  naeural_client/bc/__init__.py,sha256=FQj23D1PrY06NUOARiKQi4cdj0-VxnoYgYDEht8lpr8,158
17
- naeural_client/bc/base.py,sha256=zhfzFFMYSmWB-2KLclvnEF35jobrNLFLIFc4ZvxCcE0,44568
17
+ naeural_client/bc/base.py,sha256=CNFhPYMj45oVoP0xU9w8VzLUOBHgSljj8pFIzxjUwLg,44568
18
18
  naeural_client/bc/chain.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
19
  naeural_client/bc/ec.py,sha256=FwlkWmJvQ9aHuf_BZX1CWSUAxw6OZ9jBparLIWcs_e4,18933
20
- naeural_client/bc/evm.py,sha256=3QwHxU5nOM03OmcxtxaqCBaoft2o-QuAQ-hWD-miKJI,8937
20
+ naeural_client/bc/evm.py,sha256=mb1jltZ-KYSQVY75CSXtr8OtXwQyaMGVSl67-UCs620,23869
21
21
  naeural_client/certs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
22
  naeural_client/certs/r9092118.ala.eu-central-1.emqxsl.com.crt,sha256=y-6io0tseyx9-a4Pmde1z1gPULtJNSYUpG_YFkYaMKU,1337
23
23
  naeural_client/certs/s624dbd4.ala.us-east-1.emqxsl.com.crt,sha256=y-6io0tseyx9-a4Pmde1z1gPULtJNSYUpG_YFkYaMKU,1337
24
24
  naeural_client/cli/README.md,sha256=WPdI_EjzAbUW1aPyj1sSR8rLydcJKZtoiaEtklQrjHo,74
25
25
  naeural_client/cli/cli.py,sha256=MH43FKpUfEG5Y8x8n1KZQh3UaSiLOwyvrWiYp_wLVW4,4070
26
26
  naeural_client/cli/cli_commands.py,sha256=XfZGVCSD2-rUr2EdQXOxxN2VwQd2f2aTMeSgRzXnuvs,3829
27
- naeural_client/cli/nodes.py,sha256=53-Ht42Xiq3rJEVA2ErZHLLC9OUjh6-rNGrc2RA-U8o,5733
27
+ naeural_client/cli/nodes.py,sha256=F7_qGplqOnrU2vLqBYFFn3ifgSoWHarHPrx89I6JI9w,5816
28
28
  naeural_client/cli/oracles.py,sha256=Y_PzHshfSERS_Utjjtw5d_BsQRdGr6P4L6uW8yTdA0M,4809
29
29
  naeural_client/code_cheker/__init__.py,sha256=pwkdeZGVL16ZA4Qf2mRahEhoOvKhL7FyuQbMFLr1E5M,33
30
30
  naeural_client/code_cheker/base.py,sha256=lT5DRIFO5rqzsMNCmdMRfkAeevmezozehyfgmhnKpuI,19074
@@ -38,7 +38,7 @@ naeural_client/const/apps.py,sha256=ePBiJXLuPfFOKuw-LJrT9OWbaodU7QApfDurIPNDoB4,
38
38
  naeural_client/const/base.py,sha256=zfJyGGdrNz_OA5i_6cQxH2lEeJ4PO3092NrwM_gZ_U8,5670
39
39
  naeural_client/const/comms.py,sha256=La6JXWHexH8CfcBCKyT4fCIoeaoZlcm7KtZ57ab4ZgU,2201
40
40
  naeural_client/const/environment.py,sha256=RpdDhDgB8NgRoFTk28eODigf9y0WcT9lul6mBOD029w,879
41
- naeural_client/const/evm_net.py,sha256=IEX8t7OcDwONfYcqooZjmgsbFeWy6VynKHK-7nZD0KM,2891
41
+ naeural_client/const/evm_net.py,sha256=ZBlnyuNrcaLzyisckgDE_1bnM2udPo0vmOAesyS98V0,3220
42
42
  naeural_client/const/formatter.py,sha256=AW3bWlqf39uaqV4BBUuW95qKYfF2OkkU4f9hy3kSVhM,200
43
43
  naeural_client/const/heartbeat.py,sha256=xHZBX_NzHTklwA2_AEKR0SGdlbavMT4nirqjQg8WlTU,2550
44
44
  naeural_client/const/misc.py,sha256=VDCwwpf5bl9ltx9rzT2WPVP8B3mZFRufU1tSS5MO240,413
@@ -96,8 +96,8 @@ naeural_client/utils/comm_utils.py,sha256=4cS9llRr_pK_3rNgDcRMCQwYPO0kcNU7AdWy_L
96
96
  naeural_client/utils/config.py,sha256=upTCJWpZ-Or8V_71DHrIZ429LKn08KNySKcw0WIADcc,10348
97
97
  naeural_client/utils/dotenv.py,sha256=_AgSo35n7EnQv5yDyu7C7i0kHragLJoCGydHjvOkrYY,2008
98
98
  naeural_client/utils/oracle_sync/oracle_tester.py,sha256=X-923ccjkr6_kzbbiuAAcWSIhMtBDOH2VURjTh55apQ,27235
99
- naeural_client-3.0.8.dist-info/METADATA,sha256=YL5ezBTn3NKUskdV7k5H1DuWYtHlMI9Q0bWiDYjVTrA,12353
100
- naeural_client-3.0.8.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
101
- naeural_client-3.0.8.dist-info/entry_points.txt,sha256=CTua17GUrRa4aXeafezGC9TiWKGKQzwTjQmB2jyj22g,91
102
- naeural_client-3.0.8.dist-info/licenses/LICENSE,sha256=cvOsJVslde4oIaTCadabXnPqZmzcBO2f2zwXZRmJEbE,11311
103
- naeural_client-3.0.8.dist-info/RECORD,,
99
+ naeural_client-3.1.0.dist-info/METADATA,sha256=vsuimbxed9PBhcijsT7y795y4TEaztysc2tCnIogIEY,12353
100
+ naeural_client-3.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
101
+ naeural_client-3.1.0.dist-info/entry_points.txt,sha256=CTua17GUrRa4aXeafezGC9TiWKGKQzwTjQmB2jyj22g,91
102
+ naeural_client-3.1.0.dist-info/licenses/LICENSE,sha256=cvOsJVslde4oIaTCadabXnPqZmzcBO2f2zwXZRmJEbE,11311
103
+ naeural_client-3.1.0.dist-info/RECORD,,