diff --git a/crates/sui-graphql-client/src/lib.rs b/crates/sui-graphql-client/src/lib.rs index 9d890a069..a3ed92b50 100644 --- a/crates/sui-graphql-client/src/lib.rs +++ b/crates/sui-graphql-client/src/lib.rs @@ -30,6 +30,8 @@ use query_types::ObjectQuery; use query_types::ObjectQueryArgs; use query_types::ObjectsQuery; use query_types::ObjectsQueryArgs; +use query_types::PackageQuery; +use query_types::PackageQueryArgs; use query_types::PageInfo; use query_types::ProtocolConfigQuery; use query_types::ProtocolConfigs; @@ -671,6 +673,44 @@ impl Client { } } + // =========================================================================== + // Package API + // =========================================================================== + + // TODO: We should return maybe the MovePackage type, but the `data` field is not accessible. + // We might want to expose an API for getting the package or the struct depending what the + // object is. + /// Get a package's content by its address and optionally, a specific version. + pub async fn package( + &self, + address: Address, + version: Option, + ) -> Result, Error> { + let operation = PackageQuery::build(PackageQueryArgs { address, version }); + let response = self.run_query(&operation).await?; + + if let Some(errors) = response.errors { + return Err(Error::msg(format!("{:?}", errors))); + } + + if let Some(data) = response.data { + let package = data + .package + .and_then(|p| p.bcs) + .map(|bcs| base64ct::Base64::decode_vec(bcs.0.as_str())) + .transpose() + .map_err(|e| Error::msg(format!("Cannot decode Base64 package bcs bytes: {e}")))? + .map(|b| bcs::from_bytes::(&b)) + .transpose() + .map_err(|e| { + Error::msg(format!("Cannot decode bcs bytes into MovePackage: {e}")) + })?; + Ok(package) + } else { + Ok(None) + } + } + // =========================================================================== // Transaction API // =========================================================================== @@ -1061,4 +1101,20 @@ mod tests { ); } } + + #[tokio::test] + async fn test_package_query() { + let client = Client::new_testnet(); + let package = client + .package( + "0x29100e79cce427714a2059aee4f858a0406fc34c7f50c93fb75c915b618feacf" + .parse() + .unwrap(), + None, + ) + .await; + println!("{:?}", package); + + assert!(package.is_ok()); + } } diff --git a/crates/sui-graphql-client/src/query_types/mod.rs b/crates/sui-graphql-client/src/query_types/mod.rs index fcc7e84a0..85b4cf359 100644 --- a/crates/sui-graphql-client/src/query_types/mod.rs +++ b/crates/sui-graphql-client/src/query_types/mod.rs @@ -10,6 +10,7 @@ mod epoch; mod events; mod execute_tx; mod object; +mod package; mod protocol_config; mod service_config; mod transaction; @@ -49,6 +50,8 @@ pub use object::ObjectQuery; pub use object::ObjectQueryArgs; pub use object::ObjectsQuery; pub use object::ObjectsQueryArgs; +pub use package::PackageQuery; +pub use package::PackageQueryArgs; pub use protocol_config::ProtocolConfigQuery; pub use protocol_config::ProtocolConfigs; pub use protocol_config::ProtocolVersionArgs; diff --git a/crates/sui-graphql-client/src/query_types/package.rs b/crates/sui-graphql-client/src/query_types/package.rs new file mode 100644 index 000000000..68cfe83cf --- /dev/null +++ b/crates/sui-graphql-client/src/query_types/package.rs @@ -0,0 +1,25 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +use crate::query_types::schema; +use crate::query_types::Address; +use crate::query_types::Base64; + +#[derive(cynic::QueryFragment, Debug)] +#[cynic(schema = "rpc", graphql_type = "Query", variables = "PackageQueryArgs")] +pub struct PackageQuery { + #[arguments(address: $address, version: $version)] + pub package: Option, +} + +#[derive(cynic::QueryFragment, Debug)] +#[cynic(schema = "rpc", graphql_type = "MovePackage")] +pub struct MovePackage { + pub bcs: Option, +} + +#[derive(cynic::QueryVariables, Debug)] +pub struct PackageQueryArgs { + pub address: Address, + pub version: Option, +}