audit_trails/client/
read_only.rs1use std::ops::Deref;
11
12#[cfg(not(target_arch = "wasm32"))]
13use iota_interaction::IotaClient;
14use iota_interaction::IotaClientTrait;
15#[cfg(target_arch = "wasm32")]
16use iota_interaction_ts::bindings::WasmIotaClient;
17use iota_sdk_types::{Address, ObjectId, ProgrammableTransaction, TransactionKind};
18use product_common::core_client::CoreClientReadOnly;
19use product_common::network_name::NetworkName;
20use serde::de::DeserializeOwned;
21
22use super::network_id;
23use crate::core::trail::{AuditTrailHandle, AuditTrailReadOnly};
24use crate::error::Error;
25use crate::iota_interaction_adapter::IotaClientAdapter;
26use crate::package;
27
28#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
33pub struct PackageOverrides {
34 pub audit_trail: Option<ObjectId>,
36 pub tf_component: Option<ObjectId>,
38}
39
40#[derive(Clone)]
48pub struct AuditTrailClientReadOnly {
49 iota_client: IotaClientAdapter,
51 audit_trail_pkg_id: ObjectId,
53 pub(crate) tf_components_pkg_id: ObjectId,
55 network: NetworkName,
57 chain_id: String,
59}
60
61impl Deref for AuditTrailClientReadOnly {
62 type Target = IotaClientAdapter;
63 fn deref(&self) -> &Self::Target {
64 &self.iota_client
65 }
66}
67
68impl AuditTrailClientReadOnly {
69 pub const fn network(&self) -> &NetworkName {
71 &self.network
72 }
73
74 pub fn chain_id(&self) -> &str {
76 &self.chain_id
77 }
78
79 pub fn package_id(&self) -> ObjectId {
83 self.audit_trail_pkg_id
84 }
85
86 pub fn tf_components_package_id(&self) -> ObjectId {
88 self.tf_components_pkg_id
89 }
90
91 pub const fn iota_client(&self) -> &IotaClientAdapter {
93 &self.iota_client
94 }
95
96 pub fn trail<'a>(&'a self, trail_id: ObjectId) -> AuditTrailHandle<'a, Self> {
101 AuditTrailHandle::new(self, trail_id)
102 }
103
104 pub async fn new(
115 #[cfg(target_arch = "wasm32")] iota_client: WasmIotaClient,
116 #[cfg(not(target_arch = "wasm32"))] iota_client: IotaClient,
117 ) -> Result<Self, Error> {
118 let client = IotaClientAdapter::new(iota_client);
119 let network = network_id(&client).await?;
120 Self::new_internal(client, network, PackageOverrides::default()).await
121 }
122
123 async fn new_internal(
124 iota_client: IotaClientAdapter,
125 network: NetworkName,
126 package_overrides: PackageOverrides,
127 ) -> Result<Self, Error> {
128 let chain_id = network.as_ref().to_string();
129 let (network, package_ids) = package::resolve_package_ids(&network, &package_overrides).await?;
130
131 Ok(Self {
132 iota_client,
133 audit_trail_pkg_id: package_ids.audit_trail_package_id,
134 tf_components_pkg_id: package_ids.tf_components_package_id,
135 network,
136 chain_id,
137 })
138 }
139
140 pub async fn new_with_package_overrides(
153 #[cfg(target_arch = "wasm32")] iota_client: WasmIotaClient,
154 #[cfg(not(target_arch = "wasm32"))] iota_client: IotaClient,
155 package_overrides: PackageOverrides,
156 ) -> Result<Self, Error> {
157 let client = IotaClientAdapter::new(iota_client);
158 let network = network_id(&client).await?;
159 Self::new_internal(client, network, package_overrides).await
160 }
161}
162
163#[cfg_attr(not(feature = "send-sync"), async_trait::async_trait(?Send))]
164#[cfg_attr(feature = "send-sync", async_trait::async_trait)]
165impl CoreClientReadOnly for AuditTrailClientReadOnly {
166 fn package_id(&self) -> ObjectId {
167 self.audit_trail_pkg_id
168 }
169
170 fn tf_components_package_id(&self) -> Option<ObjectId> {
171 Some(self.tf_components_pkg_id)
172 }
173
174 fn network_name(&self) -> &NetworkName {
175 &self.network
176 }
177
178 fn client_adapter(&self) -> &IotaClientAdapter {
179 &self.iota_client
180 }
181}
182
183#[cfg_attr(not(feature = "send-sync"), async_trait::async_trait(?Send))]
184#[cfg_attr(feature = "send-sync", async_trait::async_trait)]
185impl AuditTrailReadOnly for AuditTrailClientReadOnly {
186 async fn execute_read_only_transaction<T: DeserializeOwned>(
191 &self,
192 tx: ProgrammableTransaction,
193 ) -> Result<T, Error> {
194 let inspection_result = self
195 .iota_client
196 .read_api()
197 .dev_inspect_transaction_block(Address::ZERO, TransactionKind::Programmable(tx), None, None, None)
198 .await
199 .map_err(|err| Error::UnexpectedApiResponse(format!("Failed to inspect transaction block: {err}")))?;
200
201 let execution_results = inspection_result
202 .results
203 .ok_or_else(|| Error::UnexpectedApiResponse("DevInspectResults missing 'results' field".to_string()))?;
204
205 let (return_value_bytes, _) = execution_results
206 .first()
207 .ok_or_else(|| Error::UnexpectedApiResponse("Execution results list is empty".to_string()))?
208 .return_values
209 .first()
210 .ok_or_else(|| Error::InvalidArgument("should have at least one return value".to_string()))?;
211
212 let deserialized_output = bcs::from_bytes::<T>(return_value_bytes)?;
213
214 Ok(deserialized_output)
215 }
216}