iota_grpc_client/api/state/
owned_objects.rs

1// Copyright (c) 2026 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4//! High-level API for listing owned objects.
5//!
6//! # Available Read Mask Fields
7//!
8//! Object fields mirror those of `GetObjects`:
9//! - `reference` - the object reference (includes sub-fields below)
10//!   - `reference.object_id` - the object ID
11//!   - `reference.version` - the object version
12//!   - `reference.digest` - the object digest
13//! - `object_type` - the Move type of the object
14//! - `owner` - the object owner
15//! - `bcs` - the full BCS-encoded object
16
17use iota_grpc_types::v1::{
18    object::Object,
19    state_service::{ListOwnedObjectsRequest, state_service_client::StateServiceClient},
20    types::Address as ProtoAddress,
21};
22use iota_sdk_types::{Address, StructTag};
23
24use crate::{
25    Client, InterceptedChannel,
26    api::{LIST_OWNED_OBJECTS_READ_MASK, define_list_query, field_mask_with_default},
27};
28
29define_list_query! {
30    /// Builder for listing objects owned by an address.
31    ///
32    /// Created by [`Client::list_owned_objects`]. Await directly for a
33    /// single page, or call [`.collect(limit)`](Self::collect) to
34    /// auto-paginate.
35    pub struct ListOwnedObjectsQuery {
36        service_client: StateServiceClient<InterceptedChannel>,
37        request: ListOwnedObjectsRequest,
38        item: Object,
39        rpc_method: list_owned_objects,
40        items_field: objects,
41    }
42}
43
44impl Client {
45    /// List objects owned by an address.
46    ///
47    /// Returns a query builder. Await it directly for a single page
48    /// (with access to `next_page_token`), or call `.collect(limit)` to
49    /// auto-paginate through all results.
50    ///
51    /// # Parameters
52    ///
53    /// - `owner` - The address that owns the objects.
54    /// - `object_type` - Optional type filter as a [`StructTag`].
55    /// - `page_size` - Optional maximum number of objects per page.
56    /// - `page_token` - Optional continuation token from a previous page.
57    /// - `read_mask` - Optional field mask. If `None`, uses
58    ///   [`LIST_OWNED_OBJECTS_READ_MASK`].
59    ///
60    /// # Examples
61    ///
62    /// Single page:
63    /// ```no_run
64    /// # use iota_grpc_client::Client;
65    /// # use iota_sdk_types::Address;
66    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
67    /// let client = Client::connect("http://localhost:9000").await?;
68    /// let owner: Address = "0x1".parse()?;
69    ///
70    /// let page = client
71    ///     .list_owned_objects(owner, None, None, None, None)
72    ///     .await?;
73    /// for obj in &page.body().items {
74    ///     println!("Owned object: {:?}", obj);
75    /// }
76    /// if let Some(token) = &page.body().next_page_token {
77    ///     // Fetch the next page using the token
78    ///     let next = client
79    ///         .list_owned_objects(owner, None, None, Some(token.clone()), None)
80    ///         .await?;
81    /// }
82    /// # Ok(())
83    /// # }
84    /// ```
85    ///
86    /// Auto-paginate:
87    /// ```no_run
88    /// # use iota_grpc_client::Client;
89    /// # use iota_sdk_types::Address;
90    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
91    /// let client = Client::connect("http://localhost:9000").await?;
92    /// let owner: Address = "0x1".parse()?;
93    ///
94    /// let all = client
95    ///     .list_owned_objects(owner, None, Some(50), None, None)
96    ///     .collect(Some(500))
97    ///     .await?;
98    /// for obj in all.body() {
99    ///     println!("Owned object: {:?}", obj);
100    /// }
101    /// # Ok(())
102    /// # }
103    /// ```
104    pub fn list_owned_objects(
105        &self,
106        owner: Address,
107        object_type: Option<StructTag>,
108        page_size: Option<u32>,
109        page_token: Option<prost::bytes::Bytes>,
110        read_mask: Option<&str>,
111    ) -> ListOwnedObjectsQuery {
112        let mut base_request = ListOwnedObjectsRequest::default()
113            .with_owner(ProtoAddress::default().with_address(Vec::from(owner)))
114            .with_read_mask(field_mask_with_default(
115                read_mask,
116                LIST_OWNED_OBJECTS_READ_MASK,
117            ));
118
119        if let Some(t) = object_type {
120            base_request = base_request.with_object_type(t.to_string());
121        }
122
123        ListOwnedObjectsQuery::new(
124            self.state_service_client(),
125            base_request,
126            self.max_decoding_message_size(),
127            page_size,
128            page_token,
129        )
130    }
131}