iota_sdk/apis/read.rs
1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5use std::{collections::BTreeMap, sync::Arc};
6
7use fastcrypto::encoding::Base64;
8use futures::{StreamExt, stream};
9use futures_core::Stream;
10use iota_json_rpc_api::{
11 GovernanceReadApiClient, IndexerApiClient, MoveUtilsClient, ReadApiClient, WriteApiClient,
12};
13#[cfg(feature = "iota-names")]
14use iota_json_rpc_types::IotaNameRecord;
15use iota_json_rpc_types::{
16 Checkpoint, CheckpointId, CheckpointPage, DevInspectArgs, DevInspectResults,
17 DryRunTransactionBlockResponse, DynamicFieldPage, IotaData, IotaGetPastObjectRequest,
18 IotaMoveNormalizedModule, IotaObjectDataOptions, IotaObjectResponse, IotaObjectResponseQuery,
19 IotaPastObjectResponse, IotaTransactionBlockEffects, IotaTransactionBlockResponse,
20 IotaTransactionBlockResponseOptions, IotaTransactionBlockResponseQuery,
21 IotaTransactionBlockResponseQueryV2, ObjectsPage, ProtocolConfigResponse,
22 TransactionBlocksPage, TransactionFilter,
23};
24use iota_sdk_types::{Address, ObjectId, TransactionKind};
25use iota_types::{
26 base_types::{SequenceNumber, TransactionDigest},
27 dynamic_field::DynamicFieldName,
28 iota_serde::BigInt,
29 messages_checkpoint::CheckpointSequenceNumber,
30 transaction::TransactionData,
31};
32use jsonrpsee::core::client::Subscription;
33
34use crate::{
35 RpcClient,
36 error::{Error, IotaRpcResult},
37};
38
39/// Defines methods for retrieving data about objects and transactions.
40#[derive(Debug)]
41pub struct ReadApi {
42 api: Arc<RpcClient>,
43}
44
45impl ReadApi {
46 pub(crate) fn new(api: Arc<RpcClient>) -> Self {
47 Self { api }
48 }
49
50 /// Get the objects owned by the given address.
51 /// Results are paginated.
52 ///
53 /// Note that if the address owns more than
54 /// [`QUERY_MAX_RESULT_LIMIT`](iota_json_rpc_api::QUERY_MAX_RESULT_LIMIT)
55 /// objects (default is 50), the pagination may not be accurate as the
56 /// previous page may have been updated before the next page is fetched.
57 ///
58 /// # Examples
59 ///
60 /// ```rust,no_run
61 /// use std::str::FromStr;
62 ///
63 /// use iota_sdk::IotaClientBuilder;
64 /// use iota_sdk_types::Address;
65 ///
66 /// #[tokio::main]
67 /// async fn main() -> Result<(), anyhow::Error> {
68 /// let iota = IotaClientBuilder::default().build_testnet().await?;
69 /// let address = Address::from_str("0x0000....0000")?;
70 /// let owned_objects = iota
71 /// .read_api()
72 /// .get_owned_objects(address, None, None, None)
73 /// .await?;
74 /// Ok(())
75 /// }
76 /// ```
77 pub async fn get_owned_objects(
78 &self,
79 address: Address,
80 query: impl Into<Option<IotaObjectResponseQuery>>,
81 cursor: impl Into<Option<ObjectId>>,
82 limit: impl Into<Option<usize>>,
83 ) -> IotaRpcResult<ObjectsPage> {
84 Ok(self
85 .api
86 .http
87 .get_owned_objects(address, query.into(), cursor.into(), limit.into())
88 .await?)
89 }
90
91 /// Get the dynamic fields owned by the given [ObjectId].
92 /// Results are paginated.
93 ///
94 /// If the field is a dynamic field, this method returns the ID of the Field
95 /// object, which contains both the name and the value.
96 ///
97 /// If the field is a dynamic object field, it returns the ID of the Object,
98 /// which is the value of the field.
99 ///
100 /// # Examples
101 ///
102 /// ```rust,no_run
103 /// use std::str::FromStr;
104 ///
105 /// use iota_sdk::IotaClientBuilder;
106 /// use iota_sdk_types::{Address, ObjectId};
107 ///
108 /// #[tokio::main]
109 /// async fn main() -> Result<(), anyhow::Error> {
110 /// let iota = IotaClientBuilder::default().build_testnet().await?;
111 /// let address = Address::from_str("0x0000....0000")?;
112 /// let owned_objects = iota
113 /// .read_api()
114 /// .get_owned_objects(address, None, None, None)
115 /// .await?;
116 /// // this code example assumes that there are previous owned objects
117 /// let object = owned_objects
118 /// .data
119 /// .get(0)
120 /// .expect(&format!("No owned objects for this address {}", address));
121 /// let object_data = object.data.as_ref().expect(&format!(
122 /// "No object data for this IotaObjectResponse {:?}",
123 /// object
124 /// ));
125 /// let object_id = object_data.object_id;
126 /// let dynamic_fields = iota
127 /// .read_api()
128 /// .get_dynamic_fields(object_id, None, None)
129 /// .await?;
130 /// Ok(())
131 /// }
132 /// ```
133 pub async fn get_dynamic_fields(
134 &self,
135 object_id: ObjectId,
136 cursor: impl Into<Option<ObjectId>>,
137 limit: impl Into<Option<usize>>,
138 ) -> IotaRpcResult<DynamicFieldPage> {
139 Ok(self
140 .api
141 .http
142 .get_dynamic_fields(object_id, cursor.into(), limit.into())
143 .await?)
144 }
145
146 /// Get information for a specified dynamic field object by its parent
147 /// object ID and field name.
148 pub async fn get_dynamic_field_object(
149 &self,
150 parent_object_id: ObjectId,
151 name: DynamicFieldName,
152 ) -> IotaRpcResult<IotaObjectResponse> {
153 Ok(self
154 .api
155 .http
156 .get_dynamic_field_object(parent_object_id, name)
157 .await?)
158 }
159
160 /// Get information for a specified dynamic field object by its parent
161 /// object ID and field name with options.
162 pub async fn get_dynamic_field_object_v2(
163 &self,
164 parent_object_id: ObjectId,
165 name: DynamicFieldName,
166 options: impl Into<Option<IotaObjectDataOptions>>,
167 ) -> IotaRpcResult<IotaObjectResponse> {
168 Ok(self
169 .api
170 .http
171 .get_dynamic_field_object_v2(parent_object_id, name, options.into())
172 .await?)
173 }
174
175 /// Get a parsed past object and version for the provided object ID.
176 ///
177 /// An object's version increases when the object is mutated, though it is
178 /// not guaranteed that it increases always by 1. A past object can be used
179 /// to understand how the object changed over time, i.e. what was the total
180 /// balance at a specific version.
181 ///
182 /// # Examples
183 ///
184 /// ```rust,no_run
185 /// use std::str::FromStr;
186 ///
187 /// use iota_sdk::{IotaClientBuilder, rpc_types::IotaObjectDataOptions};
188 /// use iota_sdk_types::{Address, ObjectId};
189 ///
190 /// #[tokio::main]
191 /// async fn main() -> Result<(), anyhow::Error> {
192 /// let iota = IotaClientBuilder::default().build_testnet().await?;
193 /// let address = Address::from_str("0x0000....0000")?;
194 /// let owned_objects = iota
195 /// .read_api()
196 /// .get_owned_objects(address, None, None, None)
197 /// .await?;
198 /// // this code example assumes that there are previous owned objects
199 /// let object = owned_objects
200 /// .data
201 /// .get(0)
202 /// .expect(&format!("No owned objects for this address {}", address));
203 /// let object_data = object.data.as_ref().expect(&format!(
204 /// "No object data for this IotaObjectResponse {:?}",
205 /// object
206 /// ));
207 /// let object_id = object_data.object_id;
208 /// let version = object_data.version;
209 /// let past_object = iota
210 /// .read_api()
211 /// .try_get_parsed_past_object(
212 /// object_id,
213 /// version,
214 /// IotaObjectDataOptions {
215 /// show_type: true,
216 /// show_owner: true,
217 /// show_previous_transaction: true,
218 /// show_display: true,
219 /// show_content: true,
220 /// show_bcs: true,
221 /// show_storage_rebate: true,
222 /// },
223 /// )
224 /// .await?;
225 /// Ok(())
226 /// }
227 /// ```
228 pub async fn try_get_parsed_past_object(
229 &self,
230 object_id: ObjectId,
231 version: SequenceNumber,
232 options: IotaObjectDataOptions,
233 ) -> IotaRpcResult<IotaPastObjectResponse> {
234 Ok(self
235 .api
236 .http
237 .try_get_past_object(object_id, version.into(), Some(options))
238 .await?)
239 }
240
241 /// Get a list of parsed past objects.
242 ///
243 /// See [Self::try_get_parsed_past_object] for more details about past
244 /// objects.
245 ///
246 /// # Examples
247 ///
248 /// ```rust,no_run
249 /// use std::str::FromStr;
250 ///
251 /// use iota_sdk::{
252 /// IotaClientBuilder,
253 /// rpc_types::{IotaGetPastObjectRequest, IotaObjectDataOptions},
254 /// };
255 /// use iota_sdk_types::{Address, ObjectId};
256 ///
257 /// #[tokio::main]
258 /// async fn main() -> Result<(), anyhow::Error> {
259 /// let iota = IotaClientBuilder::default().build_testnet().await?;
260 /// let address = Address::from_str("0x0000....0000")?;
261 /// let owned_objects = iota
262 /// .read_api()
263 /// .get_owned_objects(address, None, None, None)
264 /// .await?;
265 /// // this code example assumes that there are previous owned objects
266 /// let object = owned_objects
267 /// .data
268 /// .get(0)
269 /// .expect(&format!("No owned objects for this address {}", address));
270 /// let object_data = object.data.as_ref().expect(&format!(
271 /// "No object data for this IotaObjectResponse {:?}",
272 /// object
273 /// ));
274 /// let object_id = object_data.object_id;
275 /// let version = object_data.version;
276 /// let past_object = iota
277 /// .read_api()
278 /// .try_get_parsed_past_object(
279 /// object_id,
280 /// version,
281 /// IotaObjectDataOptions {
282 /// show_type: true,
283 /// show_owner: true,
284 /// show_previous_transaction: true,
285 /// show_display: true,
286 /// show_content: true,
287 /// show_bcs: true,
288 /// show_storage_rebate: true,
289 /// },
290 /// )
291 /// .await?;
292 /// let past_object = past_object.into_object()?;
293 /// let multi_past_object = iota
294 /// .read_api()
295 /// .try_multi_get_parsed_past_object(
296 /// vec![IotaGetPastObjectRequest {
297 /// object_id: past_object.object_id,
298 /// version: past_object.version,
299 /// }],
300 /// IotaObjectDataOptions {
301 /// show_type: true,
302 /// show_owner: true,
303 /// show_previous_transaction: true,
304 /// show_display: true,
305 /// show_content: true,
306 /// show_bcs: true,
307 /// show_storage_rebate: true,
308 /// },
309 /// )
310 /// .await?;
311 /// Ok(())
312 /// }
313 /// ```
314 pub async fn try_multi_get_parsed_past_object(
315 &self,
316 past_objects: Vec<IotaGetPastObjectRequest>,
317 options: IotaObjectDataOptions,
318 ) -> IotaRpcResult<Vec<IotaPastObjectResponse>> {
319 Ok(self
320 .api
321 .http
322 .try_multi_get_past_objects(past_objects, Some(options))
323 .await?)
324 }
325
326 /// Get an object by object ID with optional fields enabled by
327 /// [IotaObjectDataOptions].
328 ///
329 /// # Examples
330 ///
331 /// ```rust,no_run
332 /// use std::str::FromStr;
333 ///
334 /// use iota_sdk::{IotaClientBuilder, rpc_types::IotaObjectDataOptions};
335 /// use iota_sdk_types::Address;
336 ///
337 /// #[tokio::main]
338 /// async fn main() -> Result<(), anyhow::Error> {
339 /// let iota = IotaClientBuilder::default().build_testnet().await?;
340 /// let address = Address::from_str("0x0000....0000")?;
341 /// let owned_objects = iota
342 /// .read_api()
343 /// .get_owned_objects(address, None, None, None)
344 /// .await?;
345 /// // this code example assumes that there are previous owned objects
346 /// let object = owned_objects
347 /// .data
348 /// .get(0)
349 /// .expect(&format!("No owned objects for this address {}", address));
350 /// let object_data = object.data.as_ref().expect(&format!(
351 /// "No object data for this IotaObjectResponse {:?}",
352 /// object
353 /// ));
354 /// let object_id = object_data.object_id;
355 /// let object = iota
356 /// .read_api()
357 /// .get_object_with_options(
358 /// object_id,
359 /// IotaObjectDataOptions {
360 /// show_type: true,
361 /// show_owner: true,
362 /// show_previous_transaction: true,
363 /// show_display: true,
364 /// show_content: true,
365 /// show_bcs: true,
366 /// show_storage_rebate: true,
367 /// },
368 /// )
369 /// .await?;
370 /// Ok(())
371 /// }
372 /// ```
373 pub async fn get_object_with_options(
374 &self,
375 object_id: ObjectId,
376 options: IotaObjectDataOptions,
377 ) -> IotaRpcResult<IotaObjectResponse> {
378 Ok(self.api.http.get_object(object_id, Some(options)).await?)
379 }
380
381 /// Get a list of objects by their object IDs with optional fields enabled
382 /// by [IotaObjectDataOptions].
383 ///
384 /// # Examples
385 ///
386 /// ```rust,no_run
387 /// use std::str::FromStr;
388 ///
389 /// use iota_sdk::{IotaClientBuilder, rpc_types::IotaObjectDataOptions};
390 /// use iota_sdk_types::Address;
391 ///
392 /// #[tokio::main]
393 /// async fn main() -> Result<(), anyhow::Error> {
394 /// let iota = IotaClientBuilder::default().build_testnet().await?;
395 /// let address = Address::from_str("0x0000....0000")?;
396 /// let owned_objects = iota
397 /// .read_api()
398 /// .get_owned_objects(address, None, None, None)
399 /// .await?;
400 /// // this code example assumes that there are previous owned objects
401 /// let object = owned_objects
402 /// .data
403 /// .get(0)
404 /// .expect(&format!("No owned objects for this address {}", address));
405 /// let object_data = object.data.as_ref().expect(&format!(
406 /// "No object data for this IotaObjectResponse {:?}",
407 /// object
408 /// ));
409 /// let object_id = object_data.object_id;
410 /// let object_ids = vec![object_id]; // and other object ids
411 /// let object = iota
412 /// .read_api()
413 /// .multi_get_object_with_options(
414 /// object_ids,
415 /// IotaObjectDataOptions {
416 /// show_type: true,
417 /// show_owner: true,
418 /// show_previous_transaction: true,
419 /// show_display: true,
420 /// show_content: true,
421 /// show_bcs: true,
422 /// show_storage_rebate: true,
423 /// },
424 /// )
425 /// .await?;
426 /// Ok(())
427 /// }
428 /// ```
429 pub async fn multi_get_object_with_options(
430 &self,
431 object_ids: Vec<ObjectId>,
432 options: IotaObjectDataOptions,
433 ) -> IotaRpcResult<Vec<IotaObjectResponse>> {
434 Ok(self
435 .api
436 .http
437 .multi_get_objects(object_ids, Some(options))
438 .await?)
439 }
440
441 /// Get a [bcs] serialized object's bytes by object ID.
442 pub async fn get_move_object_bcs(&self, object_id: ObjectId) -> IotaRpcResult<Vec<u8>> {
443 let resp = self
444 .get_object_with_options(object_id, IotaObjectDataOptions::default().with_bcs())
445 .await?
446 .into_object()
447 .map_err(|e| Error::Data(format!("Can't get bcs of object {object_id}: {e:?}")))?;
448 // unwrap: requested bcs data
449 let move_object = resp.bcs.unwrap();
450 let raw_move_obj = move_object.try_into_move().ok_or(Error::Data(format!(
451 "Object {object_id} is not a MoveObject"
452 )))?;
453 Ok(raw_move_obj.bcs_bytes)
454 }
455
456 /// Get the total number of transaction blocks known to server.
457 ///
458 /// # Examples
459 ///
460 /// ```rust,no_run
461 /// use iota_sdk::IotaClientBuilder;
462 ///
463 /// #[tokio::main]
464 /// async fn main() -> Result<(), anyhow::Error> {
465 /// let iota = IotaClientBuilder::default().build_testnet().await?;
466 /// let total_transaction_blocks = iota.read_api().get_total_transaction_blocks().await?;
467 /// Ok(())
468 /// }
469 /// ```
470 pub async fn get_total_transaction_blocks(&self) -> IotaRpcResult<u64> {
471 Ok(*self.api.http.get_total_transaction_blocks().await?)
472 }
473
474 /// Get a transaction and its effects by its digest with optional fields
475 /// enabled by [IotaTransactionBlockResponseOptions].
476 pub async fn get_transaction_with_options(
477 &self,
478 digest: TransactionDigest,
479 options: IotaTransactionBlockResponseOptions,
480 ) -> IotaRpcResult<IotaTransactionBlockResponse> {
481 Ok(self
482 .api
483 .http
484 .get_transaction_block(digest, Some(options))
485 .await?)
486 }
487
488 /// Get a list of transactions and their effects by their digests with
489 /// optional fields enabled by [IotaTransactionBlockResponseOptions].
490 pub async fn multi_get_transactions_with_options(
491 &self,
492 digests: Vec<TransactionDigest>,
493 options: IotaTransactionBlockResponseOptions,
494 ) -> IotaRpcResult<Vec<IotaTransactionBlockResponse>> {
495 Ok(self
496 .api
497 .http
498 .multi_get_transaction_blocks(digests, Some(options))
499 .await?)
500 }
501
502 /// Get filtered transaction blocks information.
503 /// Results are paginated.
504 pub async fn query_transaction_blocks(
505 &self,
506 query: IotaTransactionBlockResponseQuery,
507 cursor: impl Into<Option<TransactionDigest>>,
508 limit: impl Into<Option<usize>>,
509 descending_order: bool,
510 ) -> IotaRpcResult<TransactionBlocksPage> {
511 let query_v2 = IotaTransactionBlockResponseQueryV2 {
512 filter: query.filter.as_ref().map(|f| f.as_v2()),
513 options: query.options,
514 };
515 self.query_transaction_blocks_v2(query_v2, cursor, limit, descending_order)
516 .await
517 }
518
519 /// Get filtered transaction blocks information.
520 /// Results are paginated.
521 pub async fn query_transaction_blocks_v2(
522 &self,
523 query: IotaTransactionBlockResponseQueryV2,
524 cursor: impl Into<Option<TransactionDigest>>,
525 limit: impl Into<Option<usize>>,
526 descending_order: bool,
527 ) -> IotaRpcResult<TransactionBlocksPage> {
528 Ok(self
529 .api
530 .http
531 .query_transaction_blocks_v2(query, cursor.into(), limit.into(), Some(descending_order))
532 .await?)
533 }
534
535 /// Get the first four bytes of the chain's genesis checkpoint digest in hex
536 /// format.
537 pub async fn get_chain_identifier(&self) -> IotaRpcResult<String> {
538 Ok(self.api.http.get_chain_identifier().await?)
539 }
540
541 /// Get a checkpoint by its ID.
542 pub async fn get_checkpoint(&self, id: CheckpointId) -> IotaRpcResult<Checkpoint> {
543 Ok(self.api.http.get_checkpoint(id).await?)
544 }
545
546 /// Return a list of checkpoints.
547 /// Results are paginated.
548 pub async fn get_checkpoints(
549 &self,
550 cursor: impl Into<Option<BigInt<u64>>>,
551 limit: impl Into<Option<usize>>,
552 descending_order: bool,
553 ) -> IotaRpcResult<CheckpointPage> {
554 Ok(self
555 .api
556 .http
557 .get_checkpoints(cursor.into(), limit.into(), descending_order)
558 .await?)
559 }
560
561 /// Get the sequence number of the latest checkpoint that has been executed.
562 pub async fn get_latest_checkpoint_sequence_number(
563 &self,
564 ) -> IotaRpcResult<CheckpointSequenceNumber> {
565 Ok(*self
566 .api
567 .http
568 .get_latest_checkpoint_sequence_number()
569 .await?)
570 }
571
572 /// Get a stream of transactions.
573 pub fn get_transactions_stream(
574 &self,
575 query: IotaTransactionBlockResponseQuery,
576 cursor: impl Into<Option<TransactionDigest>>,
577 descending_order: bool,
578 ) -> impl Stream<Item = IotaTransactionBlockResponse> + '_ {
579 let query_v2 = IotaTransactionBlockResponseQueryV2 {
580 filter: query.filter.as_ref().map(|f| f.as_v2()),
581 options: query.options,
582 };
583
584 self.get_transactions_stream_v2(query_v2, cursor, descending_order)
585 }
586
587 /// Get a stream of transactions.
588 pub fn get_transactions_stream_v2(
589 &self,
590 query: IotaTransactionBlockResponseQueryV2,
591 cursor: impl Into<Option<TransactionDigest>>,
592 descending_order: bool,
593 ) -> impl Stream<Item = IotaTransactionBlockResponse> + '_ {
594 let cursor = cursor.into();
595
596 stream::unfold(
597 (vec![], cursor, true, query),
598 move |(mut data, cursor, first, query)| async move {
599 if let Some(item) = data.pop() {
600 Some((item, (data, cursor, false, query)))
601 } else if (cursor.is_none() && first) || cursor.is_some() {
602 let page = self
603 .query_transaction_blocks_v2(
604 query.clone(),
605 cursor,
606 Some(100),
607 descending_order,
608 )
609 .await
610 .ok()?;
611 let mut data = page.data;
612 data.reverse();
613 data.pop()
614 .map(|item| (item, (data, page.next_cursor, false, query)))
615 } else {
616 None
617 }
618 },
619 )
620 }
621
622 /// Subscribe to a stream of transactions.
623 ///
624 /// This is only available through WebSockets.
625 pub async fn subscribe_transaction(
626 &self,
627 filter: TransactionFilter,
628 ) -> IotaRpcResult<impl Stream<Item = IotaRpcResult<IotaTransactionBlockEffects>>> {
629 let Some(c) = &self.api.ws else {
630 return Err(Error::Subscription(
631 "Subscription only supported by WebSocket client.".to_string(),
632 ));
633 };
634 let subscription: Subscription<IotaTransactionBlockEffects> =
635 c.subscribe_transaction(filter).await?;
636 Ok(subscription.map(|item| Ok(item?)))
637 }
638
639 /// Get move modules by package ID, keyed by name.
640 pub async fn get_normalized_move_modules_by_package(
641 &self,
642 package: ObjectId,
643 ) -> IotaRpcResult<BTreeMap<String, IotaMoveNormalizedModule>> {
644 Ok(self
645 .api
646 .http
647 .get_normalized_move_modules_by_package(package)
648 .await?)
649 }
650
651 // TODO(devx): we can probably cache this given an epoch
652 /// Get the reference gas price.
653 pub async fn get_reference_gas_price(&self) -> IotaRpcResult<u64> {
654 Ok(*self.api.http.get_reference_gas_price().await?)
655 }
656
657 /// Dry run a transaction block given the provided transaction data.
658 ///
659 /// This simulates running the transaction, including all standard checks,
660 /// without actually running it. This is useful for estimating the gas fees
661 /// of a transaction before executing it. You can also use it to identify
662 /// any side-effects of a transaction before you execute it on the network.
663 pub async fn dry_run_transaction_block(
664 &self,
665 tx: TransactionData,
666 ) -> IotaRpcResult<DryRunTransactionBlockResponse> {
667 Ok(self
668 .api
669 .http
670 .dry_run_transaction_block(Base64::from_bytes(&bcs::to_bytes(&tx)?))
671 .await?)
672 }
673
674 /// Use this function to inspect the current state of the network by running
675 /// a programmable transaction block without committing its effects on
676 /// chain.
677 ///
678 /// Unlike a dry run, this method will not validate whether the transaction
679 /// block would succeed or fail under normal circumstances, e.g.:
680 ///
681 /// - Transaction inputs are not checked for ownership (i.e. you can
682 /// construct calls involving objects you do not own)
683 /// - Calls are not checked for visibility (you can call private functions
684 /// on modules)
685 /// - Inputs of any type can be constructed and passed in, including coins
686 /// and other objects that would usually need to be constructed with a
687 /// move call
688 /// - Function returns do not need to be used, even if they do not have
689 /// `drop`
690 ///
691 /// This method's output includes a breakdown of results returned by every
692 /// transaction in the block, as well as the transaction's effects.
693 ///
694 /// To run an accurate simulation of a transaction and understand whether
695 /// it will successfully validate and run, use
696 /// [Self::dry_run_transaction_block] instead.
697 pub async fn dev_inspect_transaction_block(
698 &self,
699 sender_address: Address,
700 tx: TransactionKind,
701 gas_price: impl Into<Option<BigInt<u64>>>,
702 epoch: impl Into<Option<BigInt<u64>>>,
703 additional_args: impl Into<Option<DevInspectArgs>>,
704 ) -> IotaRpcResult<DevInspectResults> {
705 Ok(self
706 .api
707 .http
708 .dev_inspect_transaction_block(
709 sender_address,
710 Base64::from_bytes(&bcs::to_bytes(&tx)?),
711 gas_price.into(),
712 epoch.into(),
713 additional_args.into(),
714 )
715 .await?)
716 }
717
718 /// Get the protocol config by version.
719 ///
720 /// The version defaults to the current version.
721 pub async fn get_protocol_config(
722 &self,
723 version: impl Into<Option<BigInt<u64>>>,
724 ) -> IotaRpcResult<ProtocolConfigResponse> {
725 Ok(self.api.http.get_protocol_config(version.into()).await?)
726 }
727
728 /// Get an object by ID before the given version.
729 pub async fn try_get_object_before_version(
730 &self,
731 object_id: ObjectId,
732 version: SequenceNumber,
733 ) -> IotaRpcResult<IotaPastObjectResponse> {
734 Ok(self
735 .api
736 .http
737 .try_get_object_before_version(object_id, version)
738 .await?)
739 }
740
741 #[cfg(feature = "iota-names")]
742 /// Return the resolved record for the given name.
743 pub async fn iota_names_lookup(&self, name: &str) -> IotaRpcResult<Option<IotaNameRecord>> {
744 Ok(self.api.http.iota_names_lookup(name).await?)
745 }
746
747 #[cfg(feature = "iota-names")]
748 /// Return the resolved name for the given address.
749 pub async fn iota_names_reverse_lookup(
750 &self,
751 address: Address,
752 ) -> IotaRpcResult<Option<String>> {
753 Ok(self.api.http.iota_names_reverse_lookup(address).await?)
754 }
755
756 #[cfg(feature = "iota-names")]
757 /// Find all registration NFTs for the given address.
758 pub async fn iota_names_find_all_registration_nfts(
759 &self,
760 address: Address,
761 cursor: Option<ObjectId>,
762 limit: Option<usize>,
763 options: Option<IotaObjectDataOptions>,
764 ) -> IotaRpcResult<ObjectsPage> {
765 Ok(self
766 .api
767 .http
768 .iota_names_find_all_registration_nfts(address, cursor, limit, options)
769 .await?)
770 }
771}