sui_indexer_alt_jsonrpc/api/objects/
mod.rs1use filter::SuiObjectResponseQuery;
5use futures::future;
6use jsonrpsee::core::RpcResult;
7use jsonrpsee::proc_macros::rpc;
8use mysten_common::ZipDebugEqIteratorExt;
9use sui_json_rpc_types::Page;
10use sui_json_rpc_types::SuiGetPastObjectRequest;
11use sui_json_rpc_types::SuiObjectDataOptions;
12use sui_json_rpc_types::SuiObjectResponse;
13use sui_json_rpc_types::SuiPastObjectResponse;
14use sui_open_rpc::Module;
15use sui_open_rpc_macros::open_rpc;
16use sui_types::base_types::ObjectID;
17use sui_types::base_types::SequenceNumber;
18use sui_types::base_types::SuiAddress;
19
20use crate::api::objects::error::Error;
21use crate::api::rpc_module::RpcModule;
22use crate::context::Context;
23use crate::error::InternalContext;
24use crate::error::invalid_params;
25
26mod error;
27pub(crate) mod filter;
28pub(crate) mod response;
29
30#[open_rpc(namespace = "sui", tag = "Objects API")]
31#[rpc(server, namespace = "sui")]
32trait ObjectsApi {
33 #[method(name = "getObject")]
35 async fn get_object(
36 &self,
37 object_id: ObjectID,
39 options: Option<SuiObjectDataOptions>,
41 ) -> RpcResult<SuiObjectResponse>;
42
43 #[method(name = "multiGetObjects")]
45 async fn multi_get_objects(
46 &self,
47 object_ids: Vec<ObjectID>,
49 options: Option<SuiObjectDataOptions>,
51 ) -> RpcResult<Vec<SuiObjectResponse>>;
52
53 #[method(name = "tryGetPastObject")]
59 async fn try_get_past_object(
60 &self,
61 object_id: ObjectID,
63 version: SequenceNumber,
65 options: Option<SuiObjectDataOptions>,
67 ) -> RpcResult<SuiPastObjectResponse>;
68
69 #[method(name = "tryMultiGetPastObjects")]
75 async fn try_multi_get_past_objects(
76 &self,
77 past_objects: Vec<SuiGetPastObjectRequest>,
79 options: Option<SuiObjectDataOptions>,
81 ) -> RpcResult<Vec<SuiPastObjectResponse>>;
82}
83
84#[open_rpc(namespace = "suix", tag = "Query Objects API")]
85#[rpc(server, namespace = "suix")]
86trait QueryObjectsApi {
87 #[method(name = "getOwnedObjects")]
101 async fn get_owned_objects(
102 &self,
103 address: SuiAddress,
105 query: Option<SuiObjectResponseQuery>,
107 cursor: Option<String>,
109 limit: Option<usize>,
111 ) -> RpcResult<Page<SuiObjectResponse, String>>;
112}
113
114pub(crate) struct Objects(pub Context);
115
116pub(crate) struct QueryObjects(pub Context);
117
118#[async_trait::async_trait]
119impl ObjectsApiServer for Objects {
120 async fn get_object(
121 &self,
122 object_id: ObjectID,
123 options: Option<SuiObjectDataOptions>,
124 ) -> RpcResult<SuiObjectResponse> {
125 let Self(ctx) = self;
126 let options = options.unwrap_or_default();
127 Ok(response::live_object(ctx, object_id, &options)
128 .await
129 .with_internal_context(|| {
130 format!("Failed to get object {object_id} at latest version")
131 })?)
132 }
133
134 async fn multi_get_objects(
135 &self,
136 object_ids: Vec<ObjectID>,
137 options: Option<SuiObjectDataOptions>,
138 ) -> RpcResult<Vec<SuiObjectResponse>> {
139 let Self(ctx) = self;
140 let config = &ctx.config().objects;
141 if object_ids.len() > config.max_multi_get_objects {
142 return Err(invalid_params(Error::TooManyKeys {
143 requested: object_ids.len(),
144 max: config.max_multi_get_objects,
145 })
146 .into());
147 }
148
149 let options = options.unwrap_or_default();
150
151 let obj_futures = object_ids
152 .iter()
153 .map(|id| response::live_object(ctx, *id, &options));
154
155 Ok(future::join_all(obj_futures)
156 .await
157 .into_iter()
158 .zip_debug_eq(object_ids)
159 .map(|(r, o)| {
160 r.with_internal_context(|| format!("Failed to get object {o} at latest version"))
161 })
162 .collect::<Result<Vec<_>, _>>()?)
163 }
164
165 async fn try_get_past_object(
166 &self,
167 object_id: ObjectID,
168 version: SequenceNumber,
169 options: Option<SuiObjectDataOptions>,
170 ) -> RpcResult<SuiPastObjectResponse> {
171 let Self(ctx) = self;
172 let options = options.unwrap_or_default();
173 Ok(response::past_object(ctx, object_id, version, &options)
174 .await
175 .with_internal_context(|| {
176 format!(
177 "Failed to get object {object_id} at version {}",
178 version.value()
179 )
180 })?)
181 }
182
183 async fn try_multi_get_past_objects(
184 &self,
185 past_objects: Vec<SuiGetPastObjectRequest>,
186 options: Option<SuiObjectDataOptions>,
187 ) -> RpcResult<Vec<SuiPastObjectResponse>> {
188 let Self(ctx) = self;
189 let config = &ctx.config().objects;
190 if past_objects.len() > config.max_multi_get_objects {
191 return Err(invalid_params(Error::TooManyKeys {
192 requested: past_objects.len(),
193 max: config.max_multi_get_objects,
194 })
195 .into());
196 }
197
198 let options = options.unwrap_or_default();
199
200 let obj_futures = past_objects
201 .iter()
202 .map(|obj| response::past_object(ctx, obj.object_id, obj.version, &options));
203
204 Ok(future::join_all(obj_futures)
205 .await
206 .into_iter()
207 .zip_debug_eq(past_objects)
208 .map(|(r, o)| {
209 let id = o.object_id;
210 let v = o.version;
211 r.with_internal_context(|| format!("Failed to get object {id} at version {v}"))
212 })
213 .collect::<Result<Vec<_>, _>>()?)
214 }
215}
216
217#[async_trait::async_trait]
218impl QueryObjectsApiServer for QueryObjects {
219 async fn get_owned_objects(
220 &self,
221 address: SuiAddress,
222 query: Option<SuiObjectResponseQuery>,
223 cursor: Option<String>,
224 limit: Option<usize>,
225 ) -> RpcResult<Page<SuiObjectResponse, String>> {
226 let Self(ctx) = self;
227
228 let query = query.unwrap_or_default();
229
230 let Page {
231 data: object_ids,
232 next_cursor,
233 has_next_page,
234 } = filter::owned_objects(ctx, address, &query.filter, cursor, limit).await?;
235
236 let options = query.options.unwrap_or_default();
237
238 let obj_futures = object_ids
239 .iter()
240 .map(|id| response::live_object(ctx, *id, &options));
241
242 let data = future::join_all(obj_futures)
243 .await
244 .into_iter()
245 .zip_debug_eq(object_ids)
246 .map(|(r, id)| {
247 r.with_internal_context(|| format!("Failed to get object {id} at latest version"))
248 })
249 .collect::<Result<Vec<_>, _>>()?;
250
251 Ok(Page {
252 data,
253 next_cursor,
254 has_next_page,
255 })
256 }
257}
258
259impl RpcModule for Objects {
260 fn schema(&self) -> Module {
261 ObjectsApiOpenRpc::module_doc()
262 }
263
264 fn into_impl(self) -> jsonrpsee::RpcModule<Self> {
265 self.into_rpc()
266 }
267}
268
269impl RpcModule for QueryObjects {
270 fn schema(&self) -> Module {
271 QueryObjectsApiOpenRpc::module_doc()
272 }
273
274 fn into_impl(self) -> jsonrpsee::RpcModule<Self> {
275 self.into_rpc()
276 }
277}