cargo_tangle/command/service/
request.rs

1use color_eyre::Result;
2use dialoguer::console::style;
3use blueprint_clients::tangle::client::OnlineClient;
4use blueprint_crypto::sp_core::SpSr25519;
5use blueprint_crypto::tangle_pair_signer::TanglePairSigner;
6use blueprint_keystore::{Keystore, KeystoreConfig};
7use tangle_subxt::tangle_testnet_runtime::api::runtime_types::sp_arithmetic::per_things::Percent;
8use tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::types::{
9    Asset, AssetSecurityRequirement, MembershipModel,
10};
11use crate::wait_for_in_block_success;
12use tangle_subxt::subxt::utils::AccountId32;
13use blueprint_keystore::backends::Backend;
14
15/// Requests a service from the Tangle Network.
16///
17/// # Arguments
18///
19/// * `ws_rpc_url` - WebSocket RPC URL for the Tangle Network
20/// * `blueprint_id` - ID of the blueprint to request
21/// * `min_exposure_percent` - Minimum exposure percentage
22/// * `max_exposure_percent` - Maximum exposure percentage
23/// * `target_operators` - List of target operators
24/// * `value` - Value to stake
25/// * `keystore_uri` - URI for the keystore
26///
27/// # Errors
28///
29/// Returns an error if:
30/// * Failed to connect to the Tangle Network
31/// * Failed to sign or submit the transaction
32/// * Transaction failed
33///
34/// # Panics
35///
36/// Panics if:
37/// * Failed to create keystore
38/// * Failed to get keys from keystore
39pub async fn request_service(
40    ws_rpc_url: String,
41    blueprint_id: u64,
42    min_exposure_percent: u8,
43    max_exposure_percent: u8,
44    target_operators: Vec<AccountId32>,
45    value: u128,
46    keystore_uri: String,
47    // keystore_password: Option<String>, // TODO: Add keystore password support
48) -> Result<()> {
49    let client = OnlineClient::from_url(ws_rpc_url.clone()).await?;
50
51    // Get the next service ID before submitting the request
52    let next_service_id_storage = tangle_subxt::tangle_testnet_runtime::api::storage()
53        .services()
54        .next_instance_id();
55    let next_service_id = client
56        .storage()
57        .at_latest()
58        .await?
59        .fetch_or_default(&next_service_id_storage)
60        .await?;
61
62    let config = KeystoreConfig::new().fs_root(keystore_uri.clone());
63    let keystore = Keystore::new(config).expect("Failed to create keystore");
64    let public = keystore.first_local::<SpSr25519>().unwrap();
65    let pair = keystore.get_secret::<SpSr25519>(&public).unwrap();
66    let signer = TanglePairSigner::new(pair.0);
67
68    let min_operators = u32::try_from(target_operators.len())
69        .map_err(|_| color_eyre::eyre::eyre!("Too many operators"))?;
70    let security_requirements = vec![AssetSecurityRequirement {
71        asset: Asset::Custom(0),
72        min_exposure_percent: Percent(min_exposure_percent),
73        max_exposure_percent: Percent(max_exposure_percent),
74    }];
75
76    println!(
77        "{}",
78        style(format!(
79            "Preparing service request for blueprint ID: {}",
80            blueprint_id
81        ))
82        .cyan()
83    );
84    println!(
85        "{}",
86        style(format!(
87            "Target operators: {} (min: {})",
88            target_operators.len(),
89            min_operators
90        ))
91        .dim()
92    );
93    println!(
94        "{}",
95        style(format!(
96            "Exposure range: {}% - {}%",
97            min_exposure_percent, max_exposure_percent
98        ))
99        .dim()
100    );
101
102    let call = tangle_subxt::tangle_testnet_runtime::api::tx()
103        .services()
104        .request(
105            None,
106            blueprint_id,
107            Vec::new(),
108            target_operators,
109            Vec::default(),
110            security_requirements,
111            1000,
112            Asset::Custom(0),
113            value,
114            MembershipModel::Fixed { min_operators },
115        );
116
117    println!("{}", style("Submitting Service Request...").cyan());
118    let res = client
119        .tx()
120        .sign_and_submit_then_watch_default(&call, &signer)
121        .await?;
122    wait_for_in_block_success(res).await;
123
124    println!(
125        "{}",
126        style("Service Request submitted successfully").green()
127    );
128
129    println!(
130        "{}",
131        style(format!("Service ID: {}", next_service_id))
132            .green()
133            .bold()
134    );
135
136    Ok(())
137}