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}