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