neo3/neo_clients/rpc/
rpc_client.rs

1use async_trait::async_trait;
2use futures_util::lock::Mutex;
3use getset::{Getters, Setters};
4use primitive_types::{H160, H256};
5use serde::{de::DeserializeOwned, Deserialize, Serialize};
6use serde_json::{json, value::Value};
7use std::{
8	collections::HashMap,
9	convert::TryFrom,
10	fmt::{Debug, Display},
11	future::Future,
12	net::Ipv4Addr,
13	pin::Pin,
14	str::FromStr,
15	sync::Arc,
16	time::Duration,
17};
18use tracing::{debug, trace};
19use tracing_futures::Instrument;
20use url::{Host, ParseError, Url};
21
22// Replace the generic import with specific imports
23use crate::{
24	neo_builder::{
25		CallFlags, InteropService, ScriptBuilder, TransactionBuilder, TransactionSigner,
26	},
27	neo_clients::{
28		APITrait, Http, HttpProvider, HttpRateLimitRetryPolicy, JsonRpcProvider, ProviderError,
29		RetryClient, RwClient,
30	},
31};
32
33use crate::{
34	builder::{Signer, Transaction, TransactionSendToken},
35	codec::NeoSerializable,
36	config::NEOCONFIG,
37	neo_crypto::utils::{FromBase64String, FromHexString, ToHexString},
38	neo_protocol::*,
39	neo_types::ScriptHashExtension,
40	prelude::Base64Encode,
41	Address, ContractManifest, ContractParameter, ContractState, InvocationResult,
42	NativeContractState, NefFile, StackItem, ValueExtension,
43};
44
45/// Node Clients
46#[derive(Copy, Clone)]
47pub enum NeoClient {
48	/// RNEO
49	NEO,
50}
51
52impl FromStr for NeoClient {
53	type Err = ProviderError;
54
55	fn from_str(s: &str) -> Result<Self, Self::Err> {
56		let first_segment = s
57			.split('/')
58			.next()
59			.ok_or(ProviderError::ParseError("Invalid client string format".to_string()))?;
60		match first_segment.to_lowercase().as_str() {
61			"neo" => Ok(NeoClient::NEO),
62			_ => Err(ProviderError::UnsupportedNodeClient),
63		}
64	}
65}
66
67/// An abstract provider for interacting with the [Neo JSON RPC
68/// API](https://github.com/neo/wiki/JSON-RPC). Must be instantiated
69/// with a data transport which implements the `JsonRpcClient` trait
70/// (e.g. HTTP, Websockets etc.)
71///
72/// # Example
73///
74/// ```no_run
75/// use neo3::neo_clients::{HttpProvider, RpcClient, APITrait};
76/// use neo3::neo_config::NeoConstants;
77///
78/// async fn foo() -> Result<(), Box<dyn std::error::Error>> {
79///     let provider = HttpProvider::new(NeoConstants::SEED_1)?;
80///     let client = RpcClient::new(provider);
81///
82///     let block = client.get_block_by_index(100u32, false).await?;
83///     println!("Got block: {}", serde_json::to_string(&block)?);
84///     Ok(())
85/// }
86/// ```
87#[derive(Clone, Debug, Getters)]
88pub struct RpcClient<P> {
89	provider: P,
90	nns: Option<Address>,
91	interval: Option<Duration>,
92	from: Option<Address>,
93	_node_client: Arc<Mutex<Option<NeoVersion>>>,
94	// #[getset(get = "pub")]
95	// allow_transmission_on_fault: bool,
96}
97
98impl<P> AsRef<P> for RpcClient<P> {
99	fn as_ref(&self) -> &P {
100		&self.provider
101	}
102}
103
104// JSON RPC bindings
105impl<P: JsonRpcProvider> RpcClient<P> {
106	/// Instantiate a new provider with a backend.
107	pub fn new(provider: P) -> Self {
108		Self {
109			provider,
110			nns: None,
111			interval: None,
112			from: None,
113			_node_client: Arc::new(Mutex::new(None)),
114			// allow_transmission_on_fault: false,
115		}
116	}
117
118	/// Returns the type of node we're connected to, while also caching the value for use
119	/// in other node-specific API calls, such as the get_block_receipts call.
120	pub async fn node_client(&self) -> Result<NeoVersion, ProviderError> {
121		let mut node_client = self._node_client.lock().await;
122
123		if let Some(ref node_client) = *node_client {
124			Ok(node_client.clone())
125		} else {
126			let client_version = self.get_version().await?;
127			*node_client = Some(client_version.clone());
128			Ok(client_version)
129		}
130	}
131
132	#[must_use]
133	/// Set the default sender on the provider
134	pub fn with_sender(mut self, address: impl Into<Address>) -> Self {
135		self.from = Some(address.into());
136		self
137	}
138
139	/// Make an RPC request via the internal connection, and return the result.
140	pub async fn request<T, R>(&self, method: &str, params: T) -> Result<R, ProviderError>
141	where
142		T: Debug + Serialize + Send + Sync,
143		R: Serialize + DeserializeOwned + Debug + Send,
144	{
145		let span = tracing::trace_span!("rpc: ", method = method, params = ?serde_json::to_string(&params)?);
146		// https://docs.rs/tracing/0.1.22/tracing/span/struct.Span.html#in-asynchronous-code
147		let res = async move {
148			// trace!("tx");
149			let fetched = self.provider.fetch(method, params).await;
150			let res: R = fetched.map_err(Into::into)?;
151			// debug!("Response: = {:?}", res);
152			trace!(rx = ?serde_json::to_string(&res)?);
153			Ok::<_, ProviderError>(res)
154		}
155		.instrument(span)
156		.await?;
157		Ok(res)
158	}
159}
160
161#[cfg_attr(target_arch = "wasm32", async_trait(? Send))]
162#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
163impl<P: JsonRpcProvider> APITrait for RpcClient<P> {
164	type Error = ProviderError;
165	type Provider = P;
166
167	fn rpc_client(&self) -> &RpcClient<Self::Provider> {
168		self
169	}
170
171	async fn network(&self) -> Result<u32, ProviderError> {
172		// trace!("network = {:?}", self.get_version().await.unwrap());
173		if NEOCONFIG.lock().map_err(|_| ProviderError::LockError)?.network.is_none() {
174			let version = self.get_version().await?;
175			let protocol = version.protocol.ok_or(ProviderError::ProtocolNotFound)?;
176			return Ok(protocol.network);
177		}
178		NEOCONFIG
179			.lock()
180			.map_err(|_| ProviderError::LockError)?
181			.network
182			.ok_or(ProviderError::NetworkNotFound)
183	}
184
185	//////////////////////// Neo methods////////////////////////////
186
187	// Blockchain methods
188	/// Gets the hash of the latest block in the blockchain.
189	/// - Returns: The request object
190	async fn get_best_block_hash(&self) -> Result<H256, ProviderError> {
191		self.request("getbestblockhash", Vec::<H256>::new()).await
192	}
193
194	/// Gets the block hash of the corresponding block based on the specified block index.
195	/// - Parameter blockIndex: The block index
196	/// - Returns: The request object
197	async fn get_block_hash(&self, block_index: u32) -> Result<H256, ProviderError> {
198		self.request("getblockhash", [block_index.to_value()].to_vec()).await
199	}
200
201	/// Gets the corresponding block information according to the specified block hash.
202	/// - Parameters:
203	///   - blockHash: The block hash
204	///   - returnFullTransactionObjects: Whether to get block information with all transaction objects or just the block header
205	/// - Returns: The request object
206	async fn get_block(&self, block_hash: H256, full_tx: bool) -> Result<NeoBlock, ProviderError> {
207		Ok(if full_tx {
208			self.request("getblock", [block_hash.to_value(), 1.to_value()]).await?
209		} else {
210			self.get_block_header(block_hash).await?
211		})
212	}
213
214	/// Gets the block by hash string.
215	/// - Parameters:
216	///   - hash: The block hash as a string
217	///   - full_tx: Whether to get block information with all transaction objects or just the block header
218	/// - Returns: The request object
219	async fn get_block_by_hash(
220		&self,
221		hash: &str,
222		full_tx: bool,
223	) -> Result<NeoBlock, ProviderError> {
224		let block_hash = H256::from_str(hash)
225			.map_err(|e| ProviderError::ParseError(format!("Invalid block hash: {}", e)))?;
226		self.get_block(block_hash, full_tx).await
227	}
228
229	/// Gets the corresponding block information for the specified block hash.
230	/// - Parameter blockHash: The block hash
231	/// - Returns: The request object
232	async fn get_raw_block(&self, block_hash: H256) -> Result<String, ProviderError> {
233		self.request("getblock", [block_hash.to_value(), 0.to_value()]).await
234	}
235
236	// Node methods
237	/// Gets the block header count of the blockchain.
238	/// - Returns: The request object
239	async fn get_block_header_count(&self) -> Result<u32, ProviderError> {
240		self.request("getblockheadercount", Vec::<u32>::new()).await
241	}
242
243	/// Gets the block count of the blockchain.
244	/// - Returns: The request object
245	async fn get_block_count(&self) -> Result<u32, ProviderError> {
246		self.request("getblockcount", Vec::<u32>::new()).await
247	}
248
249	/// Gets the corresponding block header information according to the specified block hash.
250	/// - Parameter blockHash: The block hash
251	/// - Returns: The request object
252	async fn get_block_header(&self, block_hash: H256) -> Result<NeoBlock, ProviderError> {
253		self.request("getblockheader", vec![block_hash.to_value(), 1.to_value()]).await
254	}
255
256	/// Gets the corresponding block header information according to the specified index.
257	/// - Parameter blockIndex: The block index
258	/// - Returns: The request object
259	async fn get_block_header_by_index(&self, index: u32) -> Result<NeoBlock, ProviderError> {
260		self.request("getblockheader", vec![index.to_value(), 1.to_value()]).await
261	}
262
263	/// Gets the corresponding block header information according to the specified block hash.
264	/// - Parameter blockHash: The block hash
265	/// - Returns: The request object
266	async fn get_raw_block_header(&self, block_hash: H256) -> Result<String, ProviderError> {
267		self.request("getblockheader", vec![block_hash.to_value(), 0.to_value()]).await
268	}
269
270	/// Gets the corresponding block header information according to the specified index.
271	/// - Parameter blockIndex: The block index
272	/// - Returns: The request object
273	async fn get_raw_block_header_by_index(&self, index: u32) -> Result<String, ProviderError> {
274		self.request("getblockheader", vec![index.to_value(), 0.to_value()]).await
275	}
276
277	/// Gets the native contracts list, which includes the basic information of native contracts and the contract descriptive file `manifest.json`.
278	/// - Returns: The request object
279	async fn get_native_contracts(&self) -> Result<Vec<NativeContractState>, ProviderError> {
280		self.request("getnativecontracts", Vec::<NativeContractState>::new()).await
281	}
282
283	/// Gets the contract information.
284	/// - Parameter contractHash: The contract script hash
285	/// - Returns: The request object
286	async fn get_contract_state(&self, hash: H160) -> Result<ContractState, ProviderError> {
287		self.request("getcontractstate", vec![hash.to_hex()]).await
288	}
289
290	/// Gets the contract information.
291	/// - Parameter contractHash: The contract script hash
292	/// - Returns: The request object
293	async fn get_contract_state_by_id(&self, id: i64) -> Result<ContractState, ProviderError> {
294		self.request("getcontractstate", vec![id.to_value()]).await
295	}
296
297	/// Gets the native contract information by its name.
298	///
299	/// This RPC only works for native contracts.
300	/// - Parameter contractName: The name of the native contract
301	/// - Returns: The request object
302	async fn get_native_contract_state(&self, name: &str) -> Result<ContractState, ProviderError> {
303		self.request("getcontractstate", vec![name.to_value()]).await
304	}
305
306	/// Gets a list of unconfirmed or confirmed transactions in memory.
307	/// - Returns: The request object
308	async fn get_mem_pool(&self) -> Result<MemPoolDetails, ProviderError> {
309		self.request("getrawmempool", vec![1.to_value()]).await
310	}
311
312	/// Gets a list of confirmed transactions in memory.
313	/// - Returns: The request object
314	async fn get_raw_mem_pool(&self) -> Result<Vec<H256>, ProviderError> {
315		self.request("getrawmempool", Vec::<H256>::new()).await
316	}
317
318	/// Gets the corresponding transaction information based on the specified transaction hash.
319	/// - Parameter txHash: The transaction hash
320	/// - Returns: The request object
321	async fn get_transaction(&self, hash: H256) -> Result<RTransaction, ProviderError> {
322		self.request("getrawtransaction", vec![hash.to_value(), 1.to_value()]).await
323	}
324
325	/// Gets the corresponding transaction information based on the specified transaction hash.
326	/// - Parameter txHash: The transaction hash
327	/// - Returns: The request object
328	async fn get_raw_transaction(&self, tx_hash: H256) -> Result<String, ProviderError> {
329		self.request("getrawtransaction", vec![tx_hash.to_value(), 0.to_value()]).await
330	}
331
332	/// Gets the stored value according to the contract hash and the key.
333	/// - Parameters:
334	///   - contractHash: The contract hash
335	///   - keyHexString: The key to look up in storage as a hexadecimal string
336	/// - Returns: The request object
337	async fn get_storage(&self, contract_hash: H160, key: &str) -> Result<String, ProviderError> {
338		let params: [String; 2] =
339			[contract_hash.to_hex(), Base64Encode::to_base64(&key.to_string())];
340		self.request("getstorage", params.to_vec()).await
341	}
342
343	/// Finds the storage entries of a contract based on the prefix and  start index.
344	/// - Parameters:
345	///   - contractHash: The contract hash
346	///   - prefix_hex_string: The prefix to filter the storage entries
347	///   - start_index: the start index
348	/// - Returns: The request object
349	async fn find_storage(
350		&self,
351		contract_hash: H160,
352		prefix_hex_string: &str,
353		start_index: u64,
354	) -> Result<String, ProviderError> {
355		//let params = [contract_hash.to_hex(), Base64Encode::to_base64(&prefix_hex_string.to_string()), start_index.to_value()];
356		let params = json!([
357			contract_hash.to_hex(),
358			Base64Encode::to_base64(&prefix_hex_string.to_string()),
359			start_index
360		]);
361		self.request("findstorage", params).await
362	}
363
364	/// Finds the storage entries of a contract based on the prefix and  start index.
365	/// - Parameters:
366	///   - contract_id: The contract id
367	///   - prefix_hex_string: The prefix to filter the storage entries
368	///   - start_index: the start index
369	/// - Returns: The request object
370	async fn find_storage_with_id(
371		&self,
372		contract_id: i64,
373		prefix_hex_string: &str,
374		start_index: u64,
375	) -> Result<String, ProviderError> {
376		//let params = [contract_hash.to_hex(), Base64Encode::to_base64(&prefix_hex_string.to_string()), start_index.to_value()];
377		let params = json!([
378			contract_id,
379			Base64Encode::to_base64(&prefix_hex_string.to_string()),
380			start_index
381		]);
382		self.request("findstorage", params).await
383	}
384
385	/// Gets the transaction height with the specified transaction hash.
386	/// - Parameter txHash: The transaction hash
387	/// - Returns: The request object
388	async fn get_transaction_height(&self, tx_hash: H256) -> Result<u32, ProviderError> {
389		let params = [tx_hash.to_value()];
390		self.request("gettransactionheight", params.to_vec()).await
391	}
392
393	/// Gets the validators of the next block.
394	/// - Returns: The request object
395	async fn get_next_block_validators(&self) -> Result<Vec<Validator>, ProviderError> {
396		self.request("getnextblockvalidators", Vec::<Validator>::new()).await
397	}
398
399	/// Gets the public key list of current Neo committee members.
400	/// - Returns: The request object
401	async fn get_committee(&self) -> Result<Vec<String>, ProviderError> {
402		self.request("getcommittee", Vec::<String>::new()).await
403	}
404
405	/// Gets the current number of connections for the node.
406	/// - Returns: The request object
407	async fn get_connection_count(&self) -> Result<u32, ProviderError> {
408		self.request("getconnectioncount", Vec::<u32>::new()).await
409	}
410
411	/// Gets a list of nodes that the node is currently connected or disconnected from.
412	/// - Returns: The request object
413	async fn get_peers(&self) -> Result<Peers, ProviderError> {
414		self.request("getpeers", Vec::<Peers>::new()).await
415	}
416
417	/// Gets the version information of the node.
418	/// - Returns: The request object
419	async fn get_version(&self) -> Result<NeoVersion, ProviderError> {
420		self.request("getversion", Vec::<NeoVersion>::new()).await
421	}
422
423	/// Broadcasts a transaction over the NEO network.
424	/// - Parameter rawTransactionHex: The raw transaction in hexadecimal
425	/// - Returns: The request object
426	async fn send_raw_transaction(&self, hex: String) -> Result<RawTransaction, ProviderError> {
427		self.request("sendrawtransaction", vec![Base64Encode::to_base64(&hex)]).await
428	}
429
430	/// Sends a transaction to the network
431	///
432	/// # Arguments
433	///
434	/// * `tx` - The transaction to send
435	///
436	/// # Returns
437	///
438	/// A `Result` containing the transaction hash or a `ProviderError`
439	async fn send_transaction<'a>(&self, tx: Transaction<'a, P>) -> Result<H256, ProviderError> {
440		let tx_hex = hex::encode(tx.to_array());
441		let result = self.send_raw_transaction(tx_hex).await?;
442
443		// Convert the transaction hash to H256
444		let tx_hash = H256::from_str(&result.hash.to_string()).map_err(|e| {
445			ProviderError::ParseError(format!("Failed to parse transaction hash: {}", e))
446		})?;
447
448		Ok(tx_hash)
449	}
450
451	/// Broadcasts a new block over the NEO network.
452	/// - Parameter serializedBlockAsHex: The block in hexadecimal
453	/// - Returns: The request object
454	async fn submit_block(&self, hex: String) -> Result<SubmitBlock, ProviderError> {
455		self.request("submitblock", vec![hex.to_value()]).await
456	}
457
458	/// Broadcasts the node's address to the network
459	async fn broadcast_address(&self) -> Result<bool, ProviderError> {
460		self.request("broadcastaddr", Vec::<String>::new()).await
461	}
462
463	/// Broadcasts a block to the network
464	async fn broadcast_block(&self, block: NeoBlock) -> Result<bool, ProviderError> {
465		let block_json = serde_json::to_string(&block)
466			.map_err(|e| ProviderError::ParseError(format!("Failed to serialize block: {}", e)))?;
467
468		self.request("broadcastblock", vec![block_json.to_value()]).await
469	}
470
471	/// Broadcasts a request for blocks to the network
472	///
473	/// # Arguments
474	///
475	/// * `hash` - The hash of the block to start from
476	/// * `count` - The number of blocks to request
477	///
478	/// # Returns
479	///
480	/// A `Result` containing a boolean indicating success or a `ProviderError`
481	async fn broadcast_get_blocks(&self, hash: &str, count: u32) -> Result<bool, ProviderError> {
482		let hash_obj = H256::from_str(hash)
483			.map_err(|e| ProviderError::ParseError(format!("Invalid block hash: {}", e)))?;
484
485		self.request("broadcastgetblocks", vec![hash_obj.to_value(), count.to_value()])
486			.await
487	}
488
489	/// Broadcasts a transaction to the network
490	///
491	/// # Arguments
492	///
493	/// * `tx` - The transaction to broadcast
494	///
495	/// # Returns
496	///
497	/// A `Result` containing a boolean indicating success or a `ProviderError`
498	async fn broadcast_transaction(&self, tx: RTransaction) -> Result<bool, ProviderError> {
499		let tx_json = serde_json::to_string(&tx).map_err(|e| {
500			ProviderError::ParseError(format!("Failed to serialize transaction: {}", e))
501		})?;
502
503		self.request("broadcasttransaction", vec![tx_json.to_value()]).await
504	}
505
506	/// Creates a contract deployment transaction
507	async fn create_contract_deployment_transaction(
508		&self,
509		nef: NefFile,
510		manifest: ContractManifest,
511		signers: Vec<Signer>,
512	) -> Result<TransactionBuilder<P>, ProviderError> {
513		let nef_bytes = nef.to_array();
514		let manifest_json = serde_json::to_string(&manifest).map_err(|e| {
515			ProviderError::ParseError(format!("Failed to serialize manifest: {}", e))
516		})?;
517
518		let mut script_builder = ScriptBuilder::new();
519		script_builder
520			.push_data(manifest_json.as_bytes().to_vec())
521			.push_data(nef_bytes)
522			.sys_call(InteropService::SystemContractCall);
523
524		let mut builder = TransactionBuilder::new();
525		builder.extend_script(script_builder.to_bytes());
526
527		// Add signers to the transaction
528		// Note: Signers will be added when the transaction is built
529
530		Ok(builder)
531	}
532
533	/// Creates a contract update transaction
534	async fn create_contract_update_transaction(
535		&self,
536		contract_hash: H160,
537		nef: NefFile,
538		manifest: ContractManifest,
539		signers: Vec<Signer>,
540	) -> Result<TransactionBuilder<P>, ProviderError> {
541		let nef_bytes = nef.to_array();
542		let manifest_json = serde_json::to_string(&manifest).map_err(|e| {
543			ProviderError::ParseError(format!("Failed to serialize manifest: {}", e))
544		})?;
545
546		let mut script_builder = ScriptBuilder::new();
547		script_builder
548			.push_data(manifest_json.as_bytes().to_vec())
549			.push_data(nef_bytes)
550			.push_data(contract_hash.to_vec())
551			.sys_call(InteropService::SystemContractCall);
552
553		let mut builder = TransactionBuilder::new();
554		builder.extend_script(script_builder.to_bytes());
555
556		// Add signers to the transaction
557		// Note: Signers will be added when the transaction is built
558
559		Ok(builder)
560	}
561
562	/// Creates an invocation transaction
563	async fn create_invocation_transaction(
564		&self,
565		contract_hash: H160,
566		method: &str,
567		parameters: Vec<ContractParameter>,
568		signers: Vec<Signer>,
569	) -> Result<TransactionBuilder<P>, ProviderError> {
570		let mut script_builder = ScriptBuilder::new();
571		script_builder
572			.contract_call(&contract_hash, method, &parameters, None)
573			.map_err(|e| {
574				ProviderError::ParseError(format!("Failed to create contract call: {}", e))
575			})?;
576
577		let mut builder = TransactionBuilder::new();
578		builder.extend_script(script_builder.to_bytes());
579
580		// Add signers to the transaction
581		// Note: Signers will be added when the transaction is built
582
583		Ok(builder)
584	}
585
586	// MARK: SmartContract Methods
587
588	/// Invokes the function with `functionName` of the smart contract with the specified contract hash.
589	/// - Parameters:
590	///   - contractHash: The contract hash to invoke
591	///   - functionName: The function to invoke
592	///   - contractParams: The parameters of the function
593	///   - signers: The signers
594	/// - Returns: The request object
595	async fn invoke_function(
596		&self,
597		contract_hash: &H160,
598		method: String,
599		params: Vec<ContractParameter>,
600		signers: Option<Vec<Signer>>,
601	) -> Result<InvocationResult, ProviderError> {
602		match signers {
603			Some(signers) => {
604				let signers: Vec<TransactionSigner> = signers.iter().map(|f| f.into()).collect();
605				self.request(
606					"invokefunction",
607					json!([contract_hash.to_hex(), method, params, signers,]),
608				)
609				.await
610			},
611			None => {
612				let signers: Vec<TransactionSigner> = vec![];
613				self.request(
614					"invokefunction",
615					json!([
616						//ScriptHashExtension::to_hex_big_endian(contract_hash),
617						contract_hash.to_hex(),
618						method,
619						params,
620						signers
621					]), // 	ScriptHashExtension::to_hex_big_endian(contract_hash),
622					    // 	method,
623					    // 	params,
624					    // 	signers
625					    // ]),
626				)
627				.await
628			},
629		}
630	}
631
632	/// Invokes a script.
633	/// - Parameters:
634	///   - scriptHex: The script to invoke
635	///   - signers: The signers
636	/// - Returns: The request object
637	async fn invoke_script(
638		&self,
639		hex: String,
640		signers: Vec<Signer>,
641	) -> Result<InvocationResult, ProviderError> {
642		let signers: Vec<TransactionSigner> =
643			signers.into_iter().map(|signer| signer.into()).collect::<Vec<_>>();
644		let hex_bytes = hex::decode(&hex)
645			.map_err(|e| ProviderError::ParseError(format!("Failed to parse hex: {}", e)))?;
646		let script_base64 = serde_json::to_value(hex_bytes.to_base64())?;
647		let signers_json = serde_json::to_value(&signers)?;
648		self.request("invokescript", [script_base64, signers_json]).await
649	}
650
651	/// Gets the unclaimed GAS of the account with the specified script hash.
652	/// - Parameter scriptHash: The account's script hash
653	/// - Returns: The request object
654	async fn get_unclaimed_gas(&self, hash: H160) -> Result<UnclaimedGas, ProviderError> {
655		self.request("getunclaimedgas", [hash.to_address()]).await
656	}
657
658	/// Gets a list of plugins loaded by the node.
659	/// - Returns: The request object
660	async fn list_plugins(&self) -> Result<Vec<Plugin>, ProviderError> {
661		self.request("listplugins", Vec::<u32>::new()).await
662	}
663
664	/// Verifies whether the address is a valid NEO address.
665	/// - Parameter address: The address to verify
666	/// - Returns: The request object
667	async fn validate_address(&self, address: &str) -> Result<ValidateAddress, ProviderError> {
668		self.request("validateaddress", vec![address.to_value()]).await
669	}
670
671	/// Closes the current wallet.
672	/// - Returns: The request object
673	async fn close_wallet(&self) -> Result<bool, ProviderError> {
674		self.request("closewallet", Vec::<u32>::new()).await
675	}
676
677	/// Exports the private key of the specified script hash.
678	/// - Parameter scriptHash: The account's script hash
679	/// - Returns: The request object
680	async fn dump_priv_key(&self, script_hash: H160) -> Result<String, ProviderError> {
681		let params = [script_hash.to_address()].to_vec();
682		self.request("dumpprivkey", params).await
683	}
684
685	/// Gets the wallet balance of the corresponding token.
686	/// - Parameter tokenHash: The token hash
687	/// - Returns: The request object
688	async fn get_wallet_balance(&self, token_hash: H160) -> Result<Balance, ProviderError> {
689		self.request("getwalletbalance", vec![token_hash.to_value()]).await
690	}
691
692	/// Creates a new address.
693	/// - Returns: The request object
694	async fn get_new_address(&self) -> Result<String, ProviderError> {
695		self.request("getnewaddress", Vec::<u32>::new()).await
696	}
697
698	/// Gets the amount of unclaimed GAS in the wallet.
699	/// - Returns: The request object
700	async fn get_wallet_unclaimed_gas(&self) -> Result<String, ProviderError> {
701		self.request("getwalletunclaimedgas", Vec::<String>::new()).await
702	}
703
704	/// Imports a private key to the wallet.
705	/// - Parameter privateKeyInWIF: The private key in WIF-format
706	/// - Returns: The request object
707	async fn import_priv_key(&self, priv_key: String) -> Result<NeoAddress, ProviderError> {
708		let params = [priv_key.to_value()].to_vec();
709		self.request("importprivkey", params).await
710	}
711
712	/// Calculates the network fee for the specified transaction.
713	/// - Parameter txBase64: The transaction in hexadecimal
714	/// - Returns: The request object
715	async fn calculate_network_fee(
716		&self,
717		txBase64: String,
718	) -> Result<NeoNetworkFee, ProviderError> {
719		self.request("calculatenetworkfee", vec![Base64Encode::to_base64(&txBase64)])
720			.await
721	}
722
723	/// Lists all the addresses in the current wallet.
724	/// - Returns: The request object
725	async fn list_address(&self) -> Result<Vec<NeoAddress>, ProviderError> {
726		self.request("listaddress", Vec::<NeoAddress>::new()).await
727	}
728
729	/// Opens the specified wallet.
730	/// - Parameters:
731	///   - walletPath: The wallet file path
732	///   - password: The password for the wallet
733	/// - Returns: The request object
734	async fn open_wallet(&self, path: String, password: String) -> Result<bool, ProviderError> {
735		self.request("openwallet", vec![path.to_value(), password.to_value()]).await
736	}
737
738	/// Transfers an amount of a token from an account to another account.
739	/// - Parameters:
740	///   - tokenHash: The token hash of the NEP-17 contract
741	///   - from: The transferring account's script hash
742	///   - to: The recipient
743	///   - amount: The transfer amount in token fractions
744	/// - Returns: The request object
745	async fn send_from(
746		&self,
747		token_hash: H160,
748		from: H160,
749		to: H160,
750		amount: u32,
751	) -> Result<RTransaction, ProviderError> {
752		// let params =
753		// 	[token_hash.to_value(), from.to_value(), to.to_value(), amount.to_value()].to_vec();
754		let params = json!([token_hash.to_hex(), from.to_address(), to.to_address(), amount,]);
755		self.request("sendfrom", params).await
756	}
757
758	/// Initiates multiple transfers to multiple accounts from one specific account in a transaction.
759	/// - Parameters:
760	///   - from: The transferring account's script hash
761	///   - txSendTokens: a list of ``TransactionSendToken`` objects, that each contains the token hash, the recipient and the transfer amount.
762	/// - Returns: The request object
763	async fn send_many(
764		&self,
765		from: Option<H160>,
766		send_tokens: Vec<TransactionSendToken>,
767	) -> Result<RTransaction, ProviderError> {
768		let params = match from {
769			Some(f) => json!([f.to_address(), send_tokens]),
770			None => json!([send_tokens]),
771		};
772		//let params = [from.unwrap().to_value(), send_tokens.to_value()].to_vec();
773		self.request("sendmany", params).await
774	}
775
776	/// Transfers an amount of a token to another account.
777	/// - Parameters:
778	///   - tokenHash: The token hash of the NEP-17 contract
779	///   - to: The recipient
780	///   - amount: The transfer amount in token fractions
781	/// - Returns: The request object
782	async fn send_to_address(
783		&self,
784		token_hash: H160,
785		to: H160,
786		amount: u32,
787	) -> Result<RTransaction, ProviderError> {
788		let params = json!([token_hash.to_hex(), to.to_address(), amount]);
789		self.request("sendtoaddress", params).await
790	}
791
792	async fn cancel_transaction(
793		&self,
794		txHash: H256,
795		signers: Vec<H160>,
796		extra_fee: Option<u64>,
797	) -> Result<RTransaction, ProviderError> {
798		//to be implemented
799		if signers.is_empty() {
800			return Err(ProviderError::CustomError("signers must not be empty".into()));
801		}
802		let signer_addresses: Vec<String> =
803			signers.into_iter().map(|signer| signer.to_address()).collect();
804		let params = json!([
805			hex::encode(txHash.0),
806			signer_addresses,
807			extra_fee.map_or("".to_string(), |fee| fee.to_string())
808		]);
809		// let params = [from.to_value(), vec![send_token.to_value()].into()].to_vec();
810		self.request("canceltransaction", params).await
811	}
812
813	/// Gets the application logs of the specified transaction hash.
814	/// - Parameter txHash: The transaction hash
815	/// - Returns: The request object
816	async fn get_application_log(&self, tx_hash: H256) -> Result<ApplicationLog, ProviderError> {
817		self.request("getapplicationlog", vec![hex::encode(tx_hash.0).to_value()]).await
818	}
819
820	/// Gets the balance of all NEP-17 token assets in the specified script hash.
821	/// - Parameter scriptHash: The account's script hash
822	/// - Returns: The request object
823	async fn get_nep17_balances(&self, script_hash: H160) -> Result<Nep17Balances, ProviderError> {
824		self.request("getnep17balances", [script_hash.to_address().to_value()].to_vec())
825			.await
826	}
827
828	/// Gets all the NEP-17 transaction information occurred in the specified script hash.
829	/// - Parameter scriptHash: The account's script hash
830	/// - Returns: The request object
831	async fn get_nep17_transfers(
832		&self,
833		script_hash: H160,
834	) -> Result<Nep17Transfers, ProviderError> {
835		let params = json!([script_hash.to_address()]);
836		self.request("getnep17transfers", params).await
837	}
838
839	/// Gets all the NEP17 transaction information occurred in the specified script hash since the specified time.
840	/// - Parameters:
841	///   - scriptHash: The account's script hash
842	///   - from: The timestamp transactions occurred since
843	/// - Returns: The request object
844	async fn get_nep17_transfers_from(
845		&self,
846		script_hash: H160,
847		from: u64,
848	) -> Result<Nep17Transfers, ProviderError> {
849		// let params = [script_hash.to_value(), from.to_value()].to_vec();
850		self.request("getnep17transfers", json!([script_hash.to_address(), from])).await
851	}
852
853	/// Gets all the NEP17 transaction information occurred in the specified script hash in the specified time range.
854	/// - Parameters:
855	///   - scriptHash: The account's script hash
856	///   - from: The start timestamp
857	///   - to: The end timestamp
858	/// - Returns: The request object
859	async fn get_nep17_transfers_range(
860		&self,
861		script_hash: H160,
862		from: u64,
863		to: u64,
864	) -> Result<Nep17Transfers, ProviderError> {
865		let params = json!([script_hash.to_address(), from, to]);
866		self.request("getnep17transfers", params).await
867	}
868
869	/// Gets all NEP-11 balances of the specified account.
870	/// - Parameter scriptHash: The account's script hash
871	/// - Returns: The request object
872	async fn get_nep11_balances(&self, script_hash: H160) -> Result<Nep11Balances, ProviderError> {
873		let params = json!([script_hash.to_address()]);
874		self.request("getnep11balances", params).await
875	}
876
877	/// Gets all NEP-11 transaction of the given account.
878	/// - Parameter scriptHash: The account's script hash
879	/// - Returns: The request object
880	async fn get_nep11_transfers(
881		&self,
882		script_hash: H160,
883	) -> Result<Nep11Transfers, ProviderError> {
884		let params = json!([script_hash.to_address()]);
885		self.request("getnep11transfers", params).await
886	}
887
888	/// Gets all NEP-11 transaction of the given account since the given time.
889	/// - Parameters:
890	///   - scriptHash: The account's script hash
891	///   - from: The date from when to report transactions
892	/// - Returns: The request object
893	async fn get_nep11_transfers_from(
894		&self,
895		script_hash: H160,
896		from: u64,
897	) -> Result<Nep11Transfers, ProviderError> {
898		let params = json!([script_hash.to_address(), from]);
899		self.request("getnep11transfers", params).await
900	}
901
902	/// Gets all NEP-11 transactions of the given account in the time span between `from` and `to`.
903	/// - Parameters:
904	///   - scriptHash: The account's script hash
905	///   - from: The start timestamp
906	///   - to: The end timestamp
907	/// - Returns: The request object
908	async fn get_nep11_transfers_range(
909		&self,
910		script_hash: H160,
911		from: u64,
912		to: u64,
913	) -> Result<Nep11Transfers, ProviderError> {
914		let params = json!([script_hash.to_address(), from, to]);
915		self.request("getnep11transfers", params).await
916	}
917
918	/// Gets the properties of the token with `tokenId` from the NEP-11 contract with `scriptHash`.
919	///
920	/// The properties are a mapping from the property name string to the value string.
921	/// The value is plain text if the key is one of the properties defined in the NEP-11 standard.
922	/// Otherwise, the value is a Base64-encoded byte array.
923	///
924	/// To receive custom property values that consist of nested types (e.g., Maps or Arrays) use ``invokeFunction(_:_:_:)``  to directly invoke the method `properties` of the NEP-11 smart contract.
925	/// - Parameters:
926	///   - scriptHash: The account's script hash
927	///   - tokenId: The ID of the token as a hexadecimal string
928	/// - Returns: The request object
929	async fn get_nep11_properties(
930		&self,
931		script_hash: H160,
932		token_id: &str,
933	) -> Result<HashMap<String, String>, ProviderError> {
934		let params = json!([script_hash.to_address(), token_id]);
935		self.request("getnep11properties", params).await
936	}
937
938	/// Gets the state root by the block height.
939	/// - Parameter blockIndex: The block index
940	/// - Returns: The request object
941	async fn get_state_root(&self, block_index: u32) -> Result<StateRoot, ProviderError> {
942		let params = json!([block_index]);
943		self.request("getstateroot", params).await
944	}
945
946	/// Gets the proof based on the root hash, the contract hash and the storage key.
947	/// - Parameters:
948	///   - rootHash: The root hash
949	///   - contractHash: The contract hash
950	///   - storageKeyHex: The storage key
951	/// - Returns: The request object
952	async fn get_proof(
953		&self,
954		root_hash: H256,
955		contract_hash: H160,
956		key: &str,
957	) -> Result<String, ProviderError> {
958		self.request(
959			"getproof",
960			json!([
961				hex::encode(root_hash.0),
962				contract_hash.to_hex(),
963				Base64Encode::to_base64(&key.to_string())
964			]),
965		)
966		.await
967	}
968
969	/// Verifies the proof data and gets the value of the storage corresponding to the key.
970	/// - Parameters:
971	///   - rootHash: The root hash
972	///   - proof: The proof data of the state root
973	/// - Returns: The request object
974	async fn verify_proof(&self, root_hash: H256, proof: &str) -> Result<String, ProviderError> {
975		let params = json!([hex::encode(root_hash.0), Base64Encode::to_base64(&proof.to_string())]);
976		self.request("verifyproof", params).await
977	}
978
979	/// Gets the state root height.
980	/// - Returns: The request object
981	async fn get_state_height(&self) -> Result<StateHeight, ProviderError> {
982		self.request("getstateheight", Vec::<StateHeight>::new()).await
983	}
984
985	/// Gets the state.
986	/// - Parameters:
987	///   - rootHash: The root hash
988	///   - contractHash: The contract hash
989	///   - keyHex: The storage key
990	/// - Returns: The request object
991	async fn get_state(
992		&self,
993		root_hash: H256,
994		contract_hash: H160,
995		key: &str,
996	) -> Result<String, ProviderError> {
997		self.request(
998			"getstate",
999			json!([
1000				hex::encode(root_hash.0),
1001				contract_hash.to_hex(),
1002				Base64Encode::to_base64(&key.to_string())
1003			]), //key.to_base64()],
1004		)
1005		.await
1006	}
1007
1008	/// Gets a list of states that match the provided key prefix.
1009	///
1010	/// Includes proofs of the first and last entry.
1011	/// - Parameters:
1012	///   - rootHash: The root hash
1013	///   - contractHash: The contact hash
1014	///   - keyPrefixHex: The key prefix
1015	///   - startKeyHex: The start key
1016	///   - countFindResultItems: The number of results. An upper limit is defined in the Neo core
1017	/// - Returns: The request object
1018	async fn find_states(
1019		&self,
1020		root_hash: H256,
1021		contract_hash: H160,
1022		key_prefix: &str,
1023		start_key: Option<&str>,
1024		count: Option<u32>,
1025	) -> Result<States, ProviderError> {
1026		let mut params = json!([
1027			hex::encode(root_hash.0),
1028			contract_hash.to_hex(),
1029			Base64Encode::to_base64(&key_prefix.to_string())
1030		]);
1031		if let (Some(start_key), Some(count)) = (start_key, count) {
1032			params = json!([
1033				hex::encode(root_hash.0),
1034				contract_hash.to_hex(),
1035				Base64Encode::to_base64(&key_prefix.to_string()),
1036				Base64Encode::to_base64(&start_key.to_string()),
1037				count,
1038			]);
1039		} else if let Some(count) = count {
1040			params = json!([
1041				hex::encode(root_hash.0),
1042				contract_hash.to_hex(),
1043				Base64Encode::to_base64(&key_prefix.to_string()),
1044				"".to_string(),
1045				count,
1046			]);
1047		} else if let Some(start_key) = start_key {
1048			params = json!([
1049				hex::encode(root_hash.0),
1050				contract_hash.to_hex(),
1051				Base64Encode::to_base64(&key_prefix.to_string()),
1052				Base64Encode::to_base64(&start_key.to_string()),
1053			]);
1054		}
1055
1056		self.request("findstates", params).await
1057	}
1058
1059	async fn get_block_by_index(
1060		&self,
1061		index: u32,
1062		full_tx: bool,
1063	) -> Result<NeoBlock, ProviderError> {
1064		// let full_tx = if full_tx { 1 } else { 0 };
1065		// self.request("getblock", vec![index.to_value(), 1.to_value()]).await
1066		return Ok(if full_tx {
1067			self.request("getblock", vec![index.to_value(), 1.to_value()]).await?
1068		} else {
1069			self.get_block_header_by_index(index).await?
1070		});
1071	}
1072
1073	async fn get_raw_block_by_index(&self, index: u32) -> Result<String, ProviderError> {
1074		self.request("getblock", vec![index.to_value(), 0.to_value()]).await
1075	}
1076
1077	/// Invokes the function with `functionName` of the smart contract with the specified contract hash.
1078	///
1079	/// Includes diagnostics from the invocation.
1080	/// - Parameters:
1081	///   - contractHash: The contract hash to invoke
1082	///   - functionName: The function to invoke
1083	///   - contractParams: The parameters of the function
1084	///   - signers: The signers
1085	/// - Returns: The request object
1086	async fn invoke_function_diagnostics(
1087		&self,
1088		contract_hash: H160,
1089		function_name: String,
1090		params: Vec<ContractParameter>,
1091		signers: Vec<Signer>,
1092	) -> Result<InvocationResult, ProviderError> {
1093		let signers: Vec<TransactionSigner> = signers.iter().map(|f| f.into()).collect();
1094		let params = json!([contract_hash.to_hex(), function_name, params, signers, true]);
1095		self.request("invokefunction", params).await
1096	}
1097
1098	/// Invokes a script.
1099	///
1100	/// Includes diagnostics from the invocation.
1101	/// - Parameters:
1102	///   - scriptHex: The script to invoke
1103	///   - signers: The signers
1104	/// - Returns: The request object
1105	async fn invoke_script_diagnostics(
1106		&self,
1107		hex: String,
1108		signers: Vec<Signer>,
1109	) -> Result<InvocationResult, ProviderError> {
1110		let signers: Vec<TransactionSigner> =
1111			signers.into_iter().map(|signer| signer.into()).collect::<Vec<_>>();
1112		let hex_bytes = hex::decode(&hex)
1113			.map_err(|e| ProviderError::ParseError(format!("Failed to parse hex: {}", e)))?;
1114		let script_base64 = serde_json::to_value(hex_bytes.to_base64())?;
1115		let signers_json = serde_json::to_value(&signers)?;
1116		let params = vec![script_base64, signers_json, true.to_value()];
1117		self.request("invokescript", params).await
1118	}
1119
1120	/// Returns the results from an iterator.
1121	///
1122	/// The results are limited to `count` items. If `count` is greater than `MaxIteratorResultItems` in the Neo Node's configuration file, this request fails.
1123	/// - Parameters:
1124	///   - sessionId: The session id
1125	///   - iteratorId: The iterator id
1126	///   - count: The maximal number of stack items returned
1127	/// - Returns: The request object
1128	async fn traverse_iterator(
1129		&self,
1130		session_id: String,
1131		iterator_id: String,
1132		count: u32,
1133	) -> Result<Vec<StackItem>, ProviderError> {
1134		let params = vec![session_id.to_value(), iterator_id.to_value(), count.to_value()];
1135		self.request("traverseiterator", params).await
1136	}
1137
1138	async fn terminate_session(&self, session_id: &str) -> Result<bool, ProviderError> {
1139		self.request("terminatesession", vec![session_id.to_value()]).await
1140	}
1141
1142	async fn invoke_contract_verify(
1143		&self,
1144		hash: H160,
1145		params: Vec<ContractParameter>,
1146		signers: Vec<Signer>,
1147	) -> Result<InvocationResult, ProviderError> {
1148		let signers: Vec<TransactionSigner> =
1149			signers.into_iter().map(|signer| signer.into()).collect::<Vec<_>>();
1150		let params = json!([hash.to_hex(), params, signers]);
1151		self.request("invokecontractverify", params).await
1152	}
1153
1154	fn get_raw_mempool<'life0, 'async_trait>(
1155		&'life0 self,
1156	) -> Pin<Box<dyn Future<Output = Result<MemPoolDetails, Self::Error>> + Send + 'async_trait>>
1157	where
1158		'life0: 'async_trait,
1159		Self: 'async_trait,
1160	{
1161		Box::pin(async move { self.get_mem_pool().await })
1162	}
1163
1164	fn import_private_key<'life0, 'async_trait>(
1165		&'life0 self,
1166		wif: String,
1167	) -> Pin<Box<dyn Future<Output = Result<NeoAddress, Self::Error>> + Send + 'async_trait>>
1168	where
1169		'life0: 'async_trait,
1170		Self: 'async_trait,
1171	{
1172		Box::pin(async move { self.import_priv_key(wif).await })
1173	}
1174
1175	fn get_block_header_hash<'life0, 'async_trait>(
1176		&'life0 self,
1177		hash: H256,
1178	) -> Pin<Box<dyn Future<Output = Result<NeoBlock, Self::Error>> + Send + 'async_trait>>
1179	where
1180		'life0: 'async_trait,
1181		Self: 'async_trait,
1182	{
1183		Box::pin(async move { self.get_block_header(hash).await })
1184	}
1185
1186	async fn send_to_address_send_token(
1187		&self,
1188		send_token: &TransactionSendToken,
1189	) -> Result<RTransaction, ProviderError> {
1190		// let params = [send_token.to_value()].to_vec();
1191		let params = json!([send_token.token.to_hex(), send_token.address, send_token.value,]);
1192		self.request("sendtoaddress", params).await
1193	}
1194
1195	async fn send_from_send_token(
1196		&self,
1197		send_token: &TransactionSendToken,
1198		from: H160,
1199	) -> Result<RTransaction, ProviderError> {
1200		let params = json!([
1201			send_token.token.to_hex(),
1202			from.to_address(),
1203			send_token.address,
1204			send_token.value,
1205		]);
1206		// let params = [from.to_value(), vec![send_token.to_value()].into()].to_vec();
1207		self.request("sendfrom", params).await
1208	}
1209}
1210
1211impl<P: JsonRpcProvider> RpcClient<P> {
1212	/// Sets the default polling interval for event filters and pending transactions
1213	/// (default: 7 seconds)
1214	pub fn set_interval<T: Into<Duration>>(&mut self, interval: T) -> &mut Self {
1215		self.interval = Some(interval.into());
1216		self
1217	}
1218
1219	/// Sets the default polling interval for event filters and pending transactions
1220	/// (default: 7 seconds)
1221	#[must_use]
1222	pub fn interval<T: Into<Duration>>(mut self, interval: T) -> Self {
1223		self.set_interval(interval);
1224		self
1225	}
1226}
1227
1228#[cfg(all(feature = "ipc", any(unix, windows)))]
1229impl RpcClient<crate::Ipc> {
1230	#[cfg_attr(unix, doc = "Connects to the Unix socket at the provided path.")]
1231	#[cfg_attr(windows, doc = "Connects to the named pipe at the provided path.\n")]
1232	#[cfg_attr(
1233		windows,
1234		doc = r"Note: the path must be the fully qualified, like: `\\.\pipe\<name>`."
1235	)]
1236	pub async fn connect_ipc(path: impl AsRef<std::path::Path>) -> Result<Self, ProviderError> {
1237		let ipc = crate::Ipc::connect(path).await?;
1238		Ok(Self::new(ipc))
1239	}
1240}
1241
1242impl RpcClient<Http> {
1243	/// The Url to which requests are made
1244	pub fn url(&self) -> &Url {
1245		self.provider.url()
1246	}
1247
1248	/// Mutable access to the Url to which requests are made
1249	pub fn url_mut(&mut self) -> &mut Url {
1250		self.provider.url_mut()
1251	}
1252}
1253
1254impl<Read, Write> RpcClient<RwClient<Read, Write>>
1255where
1256	Read: JsonRpcProvider + 'static,
1257	<Read as JsonRpcProvider>::Error: Sync + Send + 'static + Display,
1258	Write: JsonRpcProvider + 'static,
1259	<Write as JsonRpcProvider>::Error: Sync + Send + 'static + Display,
1260{
1261	/// Creates a new [RpcClient] with a [RwClient]
1262	pub fn rw(r: Read, w: Write) -> Self {
1263		Self::new(RwClient::new(r, w))
1264	}
1265}