1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
//! Minimal implementation of Substrate RPC APIs.
//!
//! Formatting rule(s):
//! - All the APIs must be sorted in alphabetic order.

#![deny(missing_docs)]
#![deny(unused_crate_dependencies)]

// TODO: https://github.com/rust-lang/rust/issues/82715
// This should be `no_run` eventually
/// Define a group of APIs.
///
/// Require [serde](https://crates.io/crates/serde) and [serde_json](https://crates.io/crates/serde_json) as the dependencies.
///
/// # Example
/// ```ignore
/// impl_apis! {
/// 	state {
/// 		call { params: [name, bytes], opt_params: [hash] }
/// 		get_keys { params: [prefix], opt_params: [hash] }
/// 		get_metadata { params: [], opt_params: [hash] }
/// 		get_pairs { params: [prefix], opt_params: [hash] }
/// 		get_read_proof { params: [keys], opt_params: [hash] }
/// 		get_runtime_version { params: [], opt_params: [hash] }
/// 		get_storage { params: [key], opt_params: [hash] }
/// 		get_storage_hash { params: [key], opt_params: [hash] }
/// 		get_storage_size { params: [key], opt_params: [hash] }
/// 		query_storage { params: [keys, block], opt_params: [hash] }
/// 		query_storage_at { params: [keys], opt_params: [at] }
/// 		subscribe_runtime_version { params: [], opt_params: [] }
/// 		subscribe_storage { params: [], opt_params: [keys] }
/// 		trace_block { params: [block], opt_params: [targets, storage_keys, methods] }
/// 		unsubscribe_runtime_version { params: [subscription_id], opt_params: [] }
/// 		unsubscribe_storage { params: [subscription_id], opt_params: [] }
/// 	}
/// }
/// ```
#[allow(clippy::tabs_in_doc_comments)]
#[macro_export]
macro_rules! impl_apis {
	{
		$prefix:ident {
			$(
				$method:ident {
					params: [
						$(
							$param:ident
						),*
					],
					opt_params: [
						$(
							$opt_param:ident
						),*
					]
				}
			)+
		}
	} => {
		$(
			affix::paste! {
				/// Check module's Substrate reference(s) for the detail.
				pub fn $method(
					id: usize,
					$($param: impl serde::Serialize,)*
					$($opt_param: Option<impl serde::Serialize>,)*
				) -> serde_json::Value {
					$crate::rpc(
						id,
						stringify!([<$prefix _ $method:camel>]),
						serde_json::json!([
							$($param,)*
							$($opt_param,)*
						])
					)
				}

				#[doc = concat!("Similar to [`", stringify!($method), "`], but return the method name and parameters directly.")]
				pub fn [<$method _raw>](
					$($param: impl serde::Serialize,)*
					$($opt_param: Option<impl serde::Serialize>,)*
				) -> (&'static str, serde_json::Value) {
					(
						stringify!([<$prefix _ $method:camel>]),
						serde_json::json!([
							$($param,)*
							$($opt_param,)*
						])
					)
				}
			}
		)+
	};
}

pub mod author;
pub mod babe;
pub mod chain;
pub mod grandpa;
pub mod net;
pub mod offchain;
pub mod payment;
pub mod rpc;
pub mod state;
pub mod system;

#[cfg(any(feature = "reqwest-client", feature = "ureq-client"))] pub mod client;

// TODO: optimize the option param

// crates.io
use serde_json::Value;

/// Build a JSONRPC 2.0 call.
pub fn rpc(id: usize, method: &str, params: Value) -> Value {
	let rpc = serde_json::json!({
		"jsonrpc": "2.0",
		"id": id,
		"method": method,
		"params": params
	});

	// This must not fail.
	//
	// `unwrap_or_default` is useless actually.
	#[cfg(feature = "trace")]
	tracing::trace!("Rpc({:?})", serde_json::to_string(&rpc).unwrap_or_default());

	rpc
}