cargo_tangle/command/
register.rs1use blueprint_clients::tangle::client::OnlineClient;
2use blueprint_core::{debug, info};
3use blueprint_crypto::sp_core::SpSr25519;
4use blueprint_crypto::tangle_pair_signer::TanglePairSigner;
5use blueprint_keystore::backends::Backend;
6use blueprint_keystore::{Keystore, KeystoreConfig};
7use blueprint_runner::tangle::config::decompress_pubkey;
8use blueprint_tangle_extra::serde::new_bounded_string;
9use color_eyre::Result;
10use dialoguer::console::style;
11use tangle_subxt::subxt;
12use tangle_subxt::subxt::error::DispatchError;
13use tangle_subxt::subxt::tx::Signer;
14use tangle_subxt::tangle_testnet_runtime::api;
15use tangle_subxt::tangle_testnet_runtime::api::runtime_types::pallet_multi_asset_delegation as mad;
16
17pub async fn register(
39 ws_rpc_url: impl AsRef<str>,
40 blueprint_id: u64,
41 keystore_uri: String,
42 rpc_address: impl AsRef<str>,
43 ) -> Result<()> {
45 let client = OnlineClient::from_url(ws_rpc_url.as_ref()).await?;
46
47 let config = KeystoreConfig::new().fs_root(keystore_uri.clone());
48 let keystore = Keystore::new(config).expect("Failed to create keystore");
49 let public = keystore
50 .first_local::<SpSr25519>()
51 .map_err(|e| color_eyre::eyre::eyre!("Failed to get public key: {}", e))?;
52 let pair = keystore
53 .get_secret::<SpSr25519>(&public)
54 .map_err(|e| color_eyre::eyre::eyre!("Failed to get secret key: {}", e))?;
55 let signer = TanglePairSigner::new(pair.0);
56
57 let account_id = signer.account_id();
59 println!(
60 "{}",
61 style(format!(
62 "Starting registration process for Operator ID: {}",
63 account_id
64 ))
65 .cyan()
66 );
67
68 let ecdsa_public = keystore
69 .first_local::<blueprint_crypto::sp_core::SpEcdsa>()
70 .map_err(|e| color_eyre::eyre::eyre!("Missing ECDSA key: {}", e))?;
71
72 let preferences =
73 tangle_subxt::tangle_testnet_runtime::api::services::calls::types::register::Preferences {
74 key: decompress_pubkey(&ecdsa_public.0.0).unwrap(),
75 rpc_address: new_bounded_string(rpc_address.as_ref()),
76 };
77
78 info!("Joining operators...");
79 let join_call = api::tx()
80 .multi_asset_delegation()
81 .join_operators(1_000_000_000_000_000);
82 let join_res = client
83 .tx()
84 .sign_and_submit_then_watch_default(&join_call, &signer)
85 .await?;
86
87 match join_res.wait_for_finalized_success().await {
89 Ok(events) => {
90 info!("Successfully joined operators with events: {:?}", events);
91 }
92 Err(e) => {
93 match e {
94 subxt::Error::Runtime(DispatchError::Module(module))
95 if module.as_root_error::<api::Error>().is_ok_and(|e| {
96 matches!(
97 e,
98 api::Error::MultiAssetDelegation(mad::pallet::Error::AlreadyOperator)
99 )
100 }) =>
101 {
102 println!(
103 "{}",
104 style("Account is already an operator, skipping join step...").yellow()
105 );
106 info!(
107 "Account {} is already an operator, continuing with registration",
108 account_id
109 );
110 }
111
112 _ => {
113 return Err(e.into());
115 }
116 }
117 }
118 }
119
120 println!(
121 "{}",
122 style(format!(
123 "PreRegistering for blueprint with ID: {}...",
124 blueprint_id
125 ))
126 .cyan()
127 );
128
129 let preregister_call = api::tx().services().pre_register(blueprint_id);
130 let preregister_res = client
131 .tx()
132 .sign_and_submit_then_watch_default(&preregister_call, &signer)
133 .await?;
134
135 let events = preregister_res.wait_for_finalized_success().await?;
137 info!(
138 "Successfully preregistered for blueprint with ID: {} with events: {:?}",
139 blueprint_id, events
140 );
141
142 println!(
143 "{}",
144 style(format!("Registering for blueprint ID: {}...", blueprint_id)).cyan()
145 );
146 let registration_args = tangle_subxt::tangle_testnet_runtime::api::services::calls::types::register::RegistrationArgs::new();
147 let register_call =
148 api::tx()
149 .services()
150 .register(blueprint_id, preferences, registration_args, 0);
151 let register_res = client
152 .tx()
153 .sign_and_submit_then_watch_default(®ister_call, &signer)
154 .await?;
155
156 let events = register_res.wait_for_finalized_success().await?;
158 info!(
159 "Successfully registered for blueprint with ID: {} with events: {:?}",
160 blueprint_id, events
161 );
162
163 println!("{}", style("Verifying registration...").cyan());
165 let latest_block = client.blocks().at_latest().await?;
166 let latest_block_hash = latest_block.hash();
167 debug!("Latest block: {:?}", latest_block.number());
168
169 let services_client =
171 blueprint_clients::tangle::services::TangleServicesClient::new(client.clone());
172
173 debug!("Querying blueprints for account: {:?}", account_id);
174
175 let block_hash = latest_block_hash.0;
177 let blueprints = services_client
178 .query_operator_blueprints(block_hash, account_id.clone())
179 .await?;
180
181 info!("Found {} blueprints for operator", blueprints.len());
182 for (i, blueprint) in blueprints.iter().enumerate() {
183 info!("Blueprint {}: {:?}", i, blueprint);
184 }
185
186 println!("{}", style("Registration process completed").green());
187 Ok(())
188}