1#![cfg_attr(not(feature = "std"), no_std)]
21
22pub use ac_primitives as primitives;
24pub use log;
25
26mod rpc;
27
28#[macro_export]
37macro_rules! compose_call {
38($node_metadata: expr, $pallet_name: expr, $call_name: expr $(, $args: expr) *) => {
39 {
40 let maybe_pallet = $node_metadata.pallet_by_name($pallet_name);
41 let maybe_call = match maybe_pallet {
42 Some(pallet) => {
43 $crate::compose_call_for_pallet_metadata!(pallet, $call_name $(, ($args)) *)
44 },
45 None => None,
46 };
47 maybe_call
48 }
49
50 };
51}
52
53#[macro_export]
61macro_rules! compose_call_for_pallet_metadata {
62($pallet_metadata: expr, $call_name: expr $(, $args: expr) *) => {
63 {
64
65 let maybe_call_variant = $pallet_metadata.call_variant_by_name($call_name);
66 match maybe_call_variant {
67 Some(call_variant) => Some(([$pallet_metadata.index(), call_variant.index as u8] $(, ($args)) *)),
68 None => None,
69 }
70
71 }
72
73 };
74}
75
76#[macro_export]
83macro_rules! compose_extrinsic_offline {
84 ($signer: expr,
85 $call: expr,
86 $params: expr) => {{
87 use $crate::primitives::extrinsics::{
88 ExtrinsicParams, SignExtrinsic, SignedPayload, UncheckedExtrinsic,
89 };
90
91 let extra = $params.transaction_extension();
92 let raw_payload = SignedPayload::from_raw($call.clone(), extra, $params.implicit());
93
94 let signature = raw_payload.using_encoded(|payload| $signer.sign(payload));
95
96 UncheckedExtrinsic::new_signed($call, $signer.extrinsic_address(), signature, extra)
97 }};
98}
99
100#[macro_export]
110macro_rules! compose_extrinsic_with_nonce {
111 ($api: expr,
112 $nonce: expr,
113 $pallet_name: expr,
114 $call_name: expr
115 $(, $args: expr) *) => {
116 {
117 use $crate::log::debug;
118 use $crate::primitives::UncheckedExtrinsic;
119
120 debug!("Composing generic extrinsic for module {:?} and call {:?}", $pallet_name, $call_name);
121
122 let metadata = $api.metadata();
123 let maybe_call = $crate::compose_call!(metadata, $pallet_name, $call_name $(, ($args)) *);
124
125 let maybe_extrinsic = match maybe_call {
126 Some(call) => {
127 let extrinsic = if let Some(signer) = $api.signer() {
128 $crate::compose_extrinsic_offline!(
129 signer,
130 call.clone(),
131 $api.extrinsic_params($nonce)
132 )
133 } else {
134 UncheckedExtrinsic::new_bare(call.clone())
135 };
136 Some(extrinsic)
137 },
138 None => None,
139 };
140 maybe_extrinsic
141
142
143 }
144 };
145}
146
147#[macro_export]
153#[cfg(feature = "sync-api")]
154macro_rules! compose_extrinsic {
155 ($api: expr,
156 $pallet_name: expr,
157 $call_name: expr
158 $(, $args: expr) *) => {
159 {
160 let nonce = $api.get_nonce().unwrap_or_default();
161 let maybe_extrinisc = $crate::compose_extrinsic_with_nonce!($api, nonce, $pallet_name, $call_name $(, ($args)) *);
162 maybe_extrinisc
163 }
164 };
165}
166
167#[macro_export]
173#[cfg(not(feature = "sync-api"))]
174macro_rules! compose_extrinsic {
175 ($api: expr,
176 $pallet_name: expr,
177 $call_name: expr
178 $(, $args: expr) *) => {
179 {
180 let nonce = $api.get_nonce().await.unwrap_or_default();
181 let maybe_extrinisc = $crate::compose_extrinsic_with_nonce!($api, nonce, $pallet_name, $call_name $(, ($args)) *);
182 maybe_extrinisc
183 }
184 };
185}
186
187#[cfg(test)]
188mod tests {
189 use super::*;
190 use ac_node_api::Metadata;
191 use codec::Decode;
192 use frame_metadata::RuntimeMetadataPrefixed;
193 use std::fs;
194
195 #[test]
196 fn macro_compose_call_for_pallet_metadata_works() {
197 let encoded_metadata = fs::read("../ksm_metadata_v14.bin").unwrap();
198 let runtime_metadata_prefixed =
199 RuntimeMetadataPrefixed::decode(&mut encoded_metadata.as_slice()).unwrap();
200 let metadata = Metadata::try_from(runtime_metadata_prefixed).unwrap();
201
202 let pallet_metadata = metadata.pallet_by_name("Balances").unwrap();
203
204 let extra_parameter = 10000;
205 let expected_call_one = ([4, 0], extra_parameter);
206 let call_one = compose_call_for_pallet_metadata!(
207 &pallet_metadata,
208 "transfer_allow_death",
209 extra_parameter
210 )
211 .unwrap();
212 assert_eq!(expected_call_one, call_one);
213 let expected_call_two = ([4, 8], extra_parameter);
214 let call_two = compose_call_for_pallet_metadata!(
215 &pallet_metadata,
216 "force_set_balance",
217 extra_parameter
218 )
219 .unwrap();
220 assert_eq!(expected_call_two, call_two);
221 }
222
223 #[test]
224 fn macro_compose_call_for_pallet_metadata_returns_none_for_unknown_function() {
225 let encoded_metadata = fs::read("../ksm_metadata_v14.bin").unwrap();
226 let runtime_metadata_prefixed =
227 RuntimeMetadataPrefixed::decode(&mut encoded_metadata.as_slice()).unwrap();
228 let metadata = Metadata::try_from(runtime_metadata_prefixed).unwrap();
229
230 let pallet_metadata = metadata.pallet_by_name("Balances").unwrap();
231 let non_existent_function = "obladi";
232
233 let option = compose_call_for_pallet_metadata!(&pallet_metadata, non_existent_function);
234 assert!(option.is_none());
235 }
236
237 #[test]
238 fn macro_compose_call_returns_none_for_unknown_function() {
239 let encoded_metadata = fs::read("../ksm_metadata_v14.bin").unwrap();
240 let runtime_metadata_prefixed =
241 RuntimeMetadataPrefixed::decode(&mut encoded_metadata.as_slice()).unwrap();
242 let metadata = Metadata::try_from(runtime_metadata_prefixed).unwrap();
243
244 let pallet_name = "Balances";
245 let non_existent_function = "obladi";
246
247 let option = compose_call!(&metadata, pallet_name, non_existent_function);
248 assert!(option.is_none());
249 }
250
251 #[test]
252 fn macro_compose_call_returns_none_for_unknown_pallet() {
253 let encoded_metadata = fs::read("../ksm_metadata_v14.bin").unwrap();
254 let runtime_metadata_prefixed =
255 RuntimeMetadataPrefixed::decode(&mut encoded_metadata.as_slice()).unwrap();
256 let metadata = Metadata::try_from(runtime_metadata_prefixed).unwrap();
257
258 let pallet_name = "Balance";
259 let non_existent_function = "force_set_balance";
260
261 let option = compose_call!(&metadata, pallet_name, non_existent_function);
262 assert!(option.is_none());
263 }
264
265 #[test]
266 fn macro_compose_call_works_for_valid_input() {
267 let encoded_metadata = fs::read("../ksm_metadata_v14.bin").unwrap();
268 let runtime_metadata_prefixed =
269 RuntimeMetadataPrefixed::decode(&mut encoded_metadata.as_slice()).unwrap();
270 let metadata = Metadata::try_from(runtime_metadata_prefixed).unwrap();
271
272 let pallet_name = "Balances";
273 let non_existent_function = "force_set_balance";
274 let extra_parameter = 10000;
275
276 let expected_call = ([4, 8], extra_parameter);
277 let call =
278 compose_call!(&metadata, pallet_name, non_existent_function, extra_parameter).unwrap();
279 assert_eq!(call, expected_call);
280 }
281}