diff --git a/crates/sui-json-rpc/src/api.rs b/crates/sui-json-rpc/src/api.rs index 9113196f7ca93..bda35dd7aca9e 100644 --- a/crates/sui-json-rpc/src/api.rs +++ b/crates/sui-json-rpc/src/api.rs @@ -73,6 +73,14 @@ pub trait RpcReadApi { ) -> RpcResult>; /// Return the list of objects owned by an object. + #[method(name = "getObjectsOwnedByObject")] + async fn get_objects_owned_by_object( + &self, + /// the ID of the owner object + object_id: ObjectID, + ) -> RpcResult>; + + /// Return the list of dynamic field objects owned by an object. #[method(name = "getDynamicFields")] async fn get_dynamic_fields( &self, diff --git a/crates/sui-json-rpc/src/gateway_api.rs b/crates/sui-json-rpc/src/gateway_api.rs index 2d172630b3c29..34ab3c9191131 100644 --- a/crates/sui-json-rpc/src/gateway_api.rs +++ b/crates/sui-json-rpc/src/gateway_api.rs @@ -136,6 +136,14 @@ impl RpcReadApiServer for GatewayReadApiImpl { Ok(self.client.get_objects_owned_by_address(address).await?) } + async fn get_objects_owned_by_object( + &self, + object_id: ObjectID, + ) -> RpcResult> { + debug!("get_objects_own_by_object : {}", object_id); + Ok(self.client.get_objects_owned_by_object(object_id).await?) + } + async fn get_dynamic_fields( &self, _parent_object_id: ObjectID, diff --git a/crates/sui-json-rpc/src/read_api.rs b/crates/sui-json-rpc/src/read_api.rs index a493eab3d60f0..8b8273b7c90c4 100644 --- a/crates/sui-json-rpc/src/read_api.rs +++ b/crates/sui-json-rpc/src/read_api.rs @@ -73,6 +73,36 @@ impl RpcReadApiServer for ReadApi { .collect()) } + async fn get_objects_owned_by_object( + &self, + object_id: ObjectID, + ) -> RpcResult> { + let dynamic_fields: DynamicFieldPage = + self.get_dynamic_fields(object_id, None, None).await?; + + let mut object_info = vec![]; + for info in dynamic_fields.data { + // TODO: Remove this + // This is very expensive, it's only for backward compatibilities and should be removed asap. + let object = self + .state + .get_object_read(&info.object_id) + .await + .and_then(|read| read.into_object()) + .map_err(|e| anyhow!(e))?; + object_info.push(SuiObjectInfo { + object_id: object.id(), + version: object.version(), + digest: object.digest(), + // Package cannot be owned by object, safe to unwrap. + type_: format!("{}", object.type_().unwrap()), + owner: object.owner, + previous_transaction: object.previous_transaction, + }); + } + Ok(object_info) + } + async fn get_dynamic_fields( &self, parent_object_id: ObjectID, @@ -84,10 +114,8 @@ impl RpcReadApiServer for ReadApi { .state .get_dynamic_fields(parent_object_id, cursor, limit + 1) .map_err(|e| anyhow!("{e}"))?; - let next_cursor = data.get(limit).map(|info| info.object_id); data.truncate(limit); - Ok(DynamicFieldPage { data, next_cursor }) } diff --git a/crates/sui-open-rpc/spec/openrpc.json b/crates/sui-open-rpc/spec/openrpc.json index 014cf8acb96ae..06fac833c8430 100644 --- a/crates/sui-open-rpc/spec/openrpc.json +++ b/crates/sui-open-rpc/spec/openrpc.json @@ -423,7 +423,7 @@ "name": "Read API" } ], - "description": "Return the list of objects owned by an object.", + "description": "Return the list of dynamic field objects owned by an object.", "params": [ { "name": "parent_object_id", @@ -898,6 +898,91 @@ } ] }, + { + "name": "sui_getObjectsOwnedByObject", + "tags": [ + { + "name": "Read API" + } + ], + "description": "Return the list of objects owned by an object.", + "params": [ + { + "name": "object_id", + "description": "the ID of the owner object", + "required": true, + "schema": { + "$ref": "#/components/schemas/ObjectID" + } + } + ], + "result": { + "name": "Vec", + "required": true, + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ObjectInfo" + } + } + }, + "examples": [ + { + "name": "Get objects owned by an object", + "params": [ + { + "name": "object_id", + "value": "0x8196d048b7a6d04c8edc89579d86fd3fc90c52f9" + } + ], + "result": { + "name": "Result", + "value": [ + { + "objectId": "0xa14c6b812b94fe613c5bcebb5eeb1d449e251616", + "version": 0, + "digest": "bVfXH96xVNDcns23swBX0KkyaEysNSzcGj6JgCnQJO4=", + "type": "0x2::coin::Coin<0x2::sui::SUI>", + "owner": { + "ObjectOwner": "0x8196d048b7a6d04c8edc89579d86fd3fc90c52f9" + }, + "previousTransaction": "wdRMavXi+s3thNA7U3NRTxbj1m4ACBBRZLtzoe1YssE=" + }, + { + "objectId": "0x8b0cbf377792e206e6b80d4d5eea64e2e70563b1", + "version": 0, + "digest": "WJAmxON/lBpFHvggmg+/vxtUmyuya46u4IiVFG3ye8M=", + "type": "0x2::coin::Coin<0x2::sui::SUI>", + "owner": { + "ObjectOwner": "0x8196d048b7a6d04c8edc89579d86fd3fc90c52f9" + }, + "previousTransaction": "zyYQwUsuJ8Hu1WwztXkDQVDqRrzPdlPgC28ktjvQTaY=" + }, + { + "objectId": "0x8bc160c74cd844f922623fa58cdd6ef2d0531ce3", + "version": 0, + "digest": "WfMui9DNX54cTteFYCsUTXmIN9uwFHTINWbFsqU1QQ0=", + "type": "0x2::coin::Coin<0x2::sui::SUI>", + "owner": { + "ObjectOwner": "0x8196d048b7a6d04c8edc89579d86fd3fc90c52f9" + }, + "previousTransaction": "2qHdP8SvMhjXbMeqa+GABOXjjLNcyvGLfxpOPcex5/8=" + }, + { + "objectId": "0xd3dbd682f600d1f62dc0921f7f7dbfca95055adc", + "version": 0, + "digest": "XhR6Hu4u3SNxRHRERonJRvaaWFkkuRxLiubUzW4eAvY=", + "type": "0x2::coin::Coin<0x2::sui::SUI>", + "owner": { + "ObjectOwner": "0x8196d048b7a6d04c8edc89579d86fd3fc90c52f9" + }, + "previousTransaction": "ZY0hvOm4i9zu4SlBRO7EfPOTiLtoD2m3QmvFKSlpL9w=" + } + ] + } + } + ] + }, { "name": "sui_getRawObject", "tags": [