blueprint_client_tangle/
services.rs

1use crate::error::Error;
2use crate::error::{Result, TangleDispatchError};
3use blueprint_std::string::ToString;
4use blueprint_std::vec::Vec;
5use subxt::backend::BlockRef;
6use subxt::utils::AccountId32;
7use subxt::utils::H256;
8use subxt::{Config, OnlineClient};
9use tangle_subxt::subxt;
10use tangle_subxt::tangle_testnet_runtime::api;
11use tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services;
12use tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::types::AssetSecurityCommitment;
13use tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::service::ServiceBlueprint;
14use tangle_subxt::tangle_testnet_runtime::api::services::calls::types::request::RequestArgs;
15
16/// A client for interacting with the services API
17#[derive(Debug, Clone)]
18pub struct TangleServicesClient<C: Config> {
19    pub rpc_client: OnlineClient<C>,
20}
21
22impl<C: Config> TangleServicesClient<C> {
23    /// Create a new services client
24    #[must_use]
25    pub fn new(rpc_client: OnlineClient<C>) -> Self {
26        Self { rpc_client }
27    }
28}
29
30impl<C: Config> blueprint_std::ops::Deref for TangleServicesClient<C> {
31    type Target = OnlineClient<C>;
32
33    fn deref(&self) -> &Self::Target {
34        &self.rpc_client
35    }
36}
37
38/// A list of services provided by an operator, along with their blueprint
39pub type RpcServicesWithBlueprint = services::service::RpcServicesWithBlueprint;
40
41impl<C: Config> TangleServicesClient<C>
42where
43    BlockRef<<C as Config>::Hash>: From<BlockRef<H256>>,
44{
45    /// Get the Blueprint with the given ID at the given block
46    ///
47    /// # Errors
48    ///
49    /// Returns an error if the Blueprint could not be fetched
50    pub async fn get_blueprint_by_id(
51        &self,
52        at: [u8; 32],
53        blueprint_id: u64,
54    ) -> Result<Option<ServiceBlueprint>> {
55        let call = api::storage().services().blueprints(blueprint_id);
56        let at = BlockRef::from_hash(H256::from_slice(&at));
57        let ret = self.rpc_client.storage().at(at).fetch(&call).await?;
58        match ret {
59            Some(blueprints) => Ok(Some(blueprints.1)),
60            None => Ok(None),
61        }
62    }
63
64    /// Get the Blueprints provided by the operator at `address`
65    ///
66    /// # Errors
67    ///
68    /// Returns an error if the Blueprints could not be fetched
69    pub async fn query_operator_blueprints(
70        &self,
71        at_block: [u8; 32],
72        address: AccountId32,
73    ) -> Result<Vec<RpcServicesWithBlueprint>> {
74        let call = api::apis()
75            .services_api()
76            .query_services_with_blueprints_by_operator(address);
77        let at = BlockRef::from_hash(H256::from_slice(&at_block));
78        let ret = self
79            .rpc_client
80            .runtime_api()
81            .at(at)
82            .call(call)
83            .await?
84            .map_err(TangleDispatchError)?;
85
86        Ok(ret)
87    }
88
89    /// Query the current Blueprint owner
90    #[allow(clippy::missing_errors_doc)]
91    pub async fn current_blueprint_owner(
92        &self,
93        at: [u8; 32],
94        blueprint_id: u64,
95    ) -> Result<AccountId32> {
96        let call = api::storage().services().blueprints(blueprint_id);
97        let at = BlockRef::from_hash(H256::from_slice(&at));
98        let ret = self.rpc_client.storage().at(at).fetch(&call).await?;
99        match ret {
100            Some(blueprints) => Ok(blueprints.0),
101            None => Err(Error::Other("Blueprint not found".to_string())),
102        }
103    }
104
105    /// Get the current service operators with their restake exposure
106    #[allow(clippy::missing_errors_doc)]
107    pub async fn current_service_operators(
108        &self,
109        at: [u8; 32],
110        service_id: u64,
111    ) -> Result<Vec<(AccountId32, Vec<AssetSecurityCommitment<u128>>)>> {
112        let call = api::storage().services().instances(service_id);
113        let at = BlockRef::from_hash(H256::from_slice(&at));
114        let ret = self.rpc_client.storage().at(at).fetch(&call).await?;
115        match ret {
116            Some(instances) => {
117                let mut ret = Vec::new();
118                for (account, security_commitments) in instances.operator_security_commitments.0 {
119                    ret.push((account, security_commitments.0));
120                }
121                Ok(ret)
122            }
123            None => Ok(Vec::new()),
124        }
125    }
126
127    /// Get the current service operators with their restake exposure
128    #[allow(clippy::missing_errors_doc)]
129    pub async fn current_service_request_arguments(&self, service_id: u64) -> Result<RequestArgs> {
130        let call = api::storage().services().instances(service_id);
131        let ret = self
132            .rpc_client
133            .storage()
134            .at_latest()
135            .await?
136            .fetch(&call)
137            .await?;
138        match ret {
139            Some(instances) => Ok(instances.args.0),
140            None => Ok(Vec::new()),
141        }
142    }
143}