| 
 | 1 | +/*  | 
 | 2 | +	Copyright 2024 Supercomputing Systems AG  | 
 | 3 | +	Licensed under the Apache License, Version 2.0 (the "License");  | 
 | 4 | +	you may not use this file except in compliance with the License.  | 
 | 5 | +	You may obtain a copy of the License at  | 
 | 6 | +
  | 
 | 7 | +		http://www.apache.org/licenses/LICENSE-2.0  | 
 | 8 | +
  | 
 | 9 | +	Unless required by applicable law or agreed to in writing, software  | 
 | 10 | +	distributed under the License is distributed on an "AS IS" BASIS,  | 
 | 11 | +	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  | 
 | 12 | +	See the License for the specific language governing permissions and  | 
 | 13 | +	limitations under the License.  | 
 | 14 | +*/  | 
 | 15 | + | 
 | 16 | +//! This example shows how to call the unstable rpc api with self defined functions.  | 
 | 17 | +//! This includes simple requests as well as subscription.  | 
 | 18 | +
  | 
 | 19 | +use codec::Encode;  | 
 | 20 | +use serde_json::Value;  | 
 | 21 | +use sp_core::Bytes;  | 
 | 22 | +use sp_keyring::AccountKeyring;  | 
 | 23 | +use substrate_api_client::{  | 
 | 24 | +	ac_compose_macros::rpc_params,  | 
 | 25 | +	ac_primitives::AssetRuntimeConfig,  | 
 | 26 | +	extrinsic::BalancesExtrinsics,  | 
 | 27 | +	rpc::{HandleSubscription, JsonrpseeClient, Request, Subscribe},  | 
 | 28 | +	Api,  | 
 | 29 | +};  | 
 | 30 | + | 
 | 31 | +// To test this example with CI we run it against the Substrate kitchensink node, which uses the asset pallet.  | 
 | 32 | +// Therefore, we need to use the `AssetRuntimeConfig` in this example.  | 
 | 33 | +// ! However, most Substrate runtimes do not use the asset pallet at all. So if you run an example against your own node  | 
 | 34 | +// you most likely should use `DefaultRuntimeConfig` instead.  | 
 | 35 | + | 
 | 36 | +#[tokio::main]  | 
 | 37 | +async fn main() {  | 
 | 38 | +	env_logger::init();  | 
 | 39 | + | 
 | 40 | +	// Initialize api and set the signer (sender) that is used to sign the extrinsics.  | 
 | 41 | +	let signer = AccountKeyring::Alice.pair();  | 
 | 42 | +	let client = JsonrpseeClient::with_default_url().await.unwrap();  | 
 | 43 | +	let mut api = Api::<AssetRuntimeConfig, _>::new(client).await.unwrap();  | 
 | 44 | +	api.set_signer(signer.into());  | 
 | 45 | + | 
 | 46 | +	// Retrieve all available rpc methods:  | 
 | 47 | +	let json_value: Value = api.client().request("rpc_methods", rpc_params![]).await.unwrap();  | 
 | 48 | +	let json_string = serde_json::to_string(&json_value).unwrap();  | 
 | 49 | +	println!("Available methods: {json_string} \n");  | 
 | 50 | + | 
 | 51 | +	// Since it's an unstable api and might change anytime, we first check if our calls are still  | 
 | 52 | +	// available:  | 
 | 53 | +	let chain_name_request = "chainSpec_unstable_chainName";  | 
 | 54 | +	let chain_genesis_hash_request = "chainSpec_unstable_genesisHash";  | 
 | 55 | +	let transaction_submit_watch = "transaction_unstable_submitAndWatch";  | 
 | 56 | +	let transaction_unwatch = "transaction_unstable_unwatch";  | 
 | 57 | + | 
 | 58 | +	let request_vec = [  | 
 | 59 | +		chain_name_request,  | 
 | 60 | +		chain_genesis_hash_request,  | 
 | 61 | +		transaction_submit_watch,  | 
 | 62 | +		transaction_unwatch,  | 
 | 63 | +	];  | 
 | 64 | +	for request in request_vec {  | 
 | 65 | +		if !json_string.contains(request) {  | 
 | 66 | +			panic!("Api has changed, please update the call {request}.");  | 
 | 67 | +		}  | 
 | 68 | +	}  | 
 | 69 | + | 
 | 70 | +	// Submit the above defiend rpc requests:  | 
 | 71 | +	let chain_name: String = api.client().request(chain_name_request, rpc_params![]).await.unwrap();  | 
 | 72 | +	println!("Our chain is called: {chain_name}");  | 
 | 73 | + | 
 | 74 | +	let genesishash: String =  | 
 | 75 | +		api.client().request(chain_genesis_hash_request, rpc_params![]).await.unwrap();  | 
 | 76 | +	println!("Chain genesis Hash: {genesishash}");  | 
 | 77 | + | 
 | 78 | +	// Submit and watch a transaction:  | 
 | 79 | +	let bob = AccountKeyring::Bob.to_account_id();  | 
 | 80 | +	let encoded_extrinsic: Bytes = api  | 
 | 81 | +		.balance_transfer_allow_death(bob.into(), 1000)  | 
 | 82 | +		.await  | 
 | 83 | +		.unwrap()  | 
 | 84 | +		.encode()  | 
 | 85 | +		.into();  | 
 | 86 | + | 
 | 87 | +	let mut subscription = api  | 
 | 88 | +		.client()  | 
 | 89 | +		.subscribe::<Value>(  | 
 | 90 | +			transaction_submit_watch,  | 
 | 91 | +			rpc_params![encoded_extrinsic],  | 
 | 92 | +			transaction_unwatch,  | 
 | 93 | +		)  | 
 | 94 | +		.await  | 
 | 95 | +		.unwrap();  | 
 | 96 | +	while let Some(notification) = subscription.next().await {  | 
 | 97 | +		let notification = notification.unwrap();  | 
 | 98 | +		println!("Subscription notification: {notification:?}");  | 
 | 99 | +		let event_object_string = notification["event"].as_str().unwrap();  | 
 | 100 | +		//let event_object_string = serde_json::from_string().unwrap();  | 
 | 101 | +		match event_object_string {  | 
 | 102 | +			"finalized" => break,  | 
 | 103 | +			"bestChainBlockIncluded" | "validated" => println!("Got {event_object_string} event"),  | 
 | 104 | +			_ => panic!("Unexpected event: {event_object_string}"),  | 
 | 105 | +		};  | 
 | 106 | +	}  | 
 | 107 | +	println!("Transaction got finalized, unsubscribing.");  | 
 | 108 | +	subscription.unsubscribe().await.unwrap();  | 
 | 109 | +}  | 
0 commit comments