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