Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sui-sdk-types: some refactors and doc additions #90

Merged
merged 9 commits into from
Jan 22, 2025
8 changes: 4 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ check-features: ## Check feature flags for crates

.PHONY: check-fmt
check-fmt: ## Check code formatting
cargo fmt -- --config imports_granularity=Item --check
cargo fmt -- --config imports_granularity=Item --config format_code_in_doc_comments=true --check

.PHONY: fmt
fmt: ## Format code
cargo fmt -- --config imports_granularity=Item
cargo fmt -- --config imports_granularity=Item --config format_code_in_doc_comments=true

.PHONY: clippy
clippy: ## Run Clippy linter
Expand All @@ -22,7 +22,7 @@ clippy: ## Run Clippy linter
.PHONY: test
test: ## Run unit tests
cargo nextest run --all-features -p sui-sdk-types -p sui-crypto
cargo test --doc
cargo test --all-features --doc

package_%.json: crates/sui-transaction-builder/tests/%/Move.toml crates/sui-transaction-builder/tests/%/sources/*.move ## Generate JSON files for tests
cd crates/sui-transaction-builder/tests/$(*F) && sui move build --ignore-chain --dump-bytecode-as-base64 > ../../$@
Expand All @@ -38,7 +38,7 @@ wasm: ## Build WASM modules

.PHONY: doc
doc: ## Generate documentation
RUSTDOCFLAGS="--cfg=doc_cfg -Zunstable-options --generate-link-to-definition" RUSTC_BOOTSTRAP=1 cargo doc --all-features --no-deps
RUSTDOCFLAGS="-Dwarnings --cfg=doc_cfg -Zunstable-options --generate-link-to-definition" RUSTC_BOOTSTRAP=1 cargo doc --all-features --no-deps

.PHONY: doc-open
doc-open: ## Generate and open documentation
Expand Down
4 changes: 2 additions & 2 deletions crates/sui-graphql-client-build/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ sui-graphql-client-build = { git = "https://github.com/mystenlabs/sui-rust-sdk",
```

4. If using `cynic`, use the cynic generator to generate the Rust types from the GraphQL schema. \
Go to https://generator.cynic-rs.dev/ and paste the URL to the GraphQL service or manually copy paste the schema. \
Go to <https://generator.cynic-rs.dev/> and paste the URL to the GraphQL service or manually copy paste the schema. \
Then you can select the fields in the query you want to have, and the generator will generate the Rust types for you.

5. In your Rust code, you can now use the custom query types generated by `cynic`.
Expand All @@ -57,6 +57,6 @@ async fn main() {
}
```

6. For `UInt53`, you can use `u64` type directly as the `sui-graphql-client`'s schema implements the `impl_scalar`. Similarly for other types (Base64, DateTime). See more available types here: https://github.com/MystenLabs/sui-rust-sdk/blob/02639f6b09375fe03fa2243868be17bec1dfa33c/crates/sui-graphql-client/src/query_types/mod.rs?plain=1#L124-L126
6. For `UInt53`, you can use `u64` type directly as the `sui-graphql-client`'s schema implements the `impl_scalar`. Similarly for other types (Base64, DateTime). See more available types here: <https://github.com/MystenLabs/sui-rust-sdk/blob/02639f6b09375fe03fa2243868be17bec1dfa33c/crates/sui-graphql-client/src/query_types/mod.rs?plain=1#L124-L126>

7. Read the `cynic` [documentation](https://cynic-rs.dev/) to learn how to work with it, particularly when it comes to passing arguments to the query.
2 changes: 1 addition & 1 deletion crates/sui-graphql-client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ async fn main() -> Result<()> {
```

### Example for custom faucet service.
Note that this [`FaucetClient`] is explicitly designed to work with two endpoints: `v1/gas`, and `v1/status`. When passing in the custom faucet URL, skip the final endpoint and only pass in the top-level url (e.g., `https://faucet.devnet.sui.io`).
Note that this `FaucetClient` is explicitly designed to work with two endpoints: `v1/gas`, and `v1/status`. When passing in the custom faucet URL, skip the final endpoint and only pass in the top-level url (e.g., `https://faucet.devnet.sui.io`).
```rust, no_run
use sui_graphql_client::faucet::FaucetClient;
use sui_types::Address;
Expand Down
21 changes: 10 additions & 11 deletions crates/sui-graphql-client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,7 @@ impl Client {

/// Get the list of active validators for the provided epoch, including related metadata.
/// If no epoch is provided, it will return the active validators for the current epoch.
pub async fn active_validators<'a>(
pub async fn active_validators(
&self,
epoch: Option<u64>,
pagination_filter: PaginationFilter,
Expand Down Expand Up @@ -571,7 +571,7 @@ impl Client {
///
/// If `coin_type` is not provided, it will default to `0x2::coin::Coin`, which will return all
/// coins. For SUI coin, pass in the coin type: `0x2::coin::Coin<0x2::sui::SUI>`.
pub async fn coins<'a>(
pub async fn coins(
&self,
owner: Address,
coin_type: Option<&str>,
Expand Down Expand Up @@ -675,7 +675,7 @@ impl Client {
}

/// Get a page of [`CheckpointSummary`] for the provided parameters.
pub async fn checkpoints<'a>(
pub async fn checkpoints(
&self,
pagination_filter: PaginationFilter,
) -> Result<Page<CheckpointSummary>> {
Expand Down Expand Up @@ -742,12 +742,11 @@ impl Client {
///
/// # Example
/// ```rust,ignore
///
/// let client = sui_graphql_client::Client::new_devnet();
/// let address = Address::from_str("0x5").unwrap();
/// let df = client.dynamic_field_with_name(address, "u64", 2u64).await.unwrap();
///
/// # alternatively, pass in the bcs bytes
/// // alternatively, pass in the bcs bytes
/// let bcs = base64ct::Base64::decode_vec("AgAAAAAAAAA=").unwrap();
/// let df = client.dynamic_field(address, "u64", BcsName(bcs)).await.unwrap();
/// ```
Expand Down Expand Up @@ -824,7 +823,7 @@ impl Client {
/// dynamic fields on wrapped objects.
///
/// This returns [`Page`] of [`DynamicFieldOutput`]s.
pub async fn dynamic_fields<'a>(
pub async fn dynamic_fields(
&self,
address: Address,
pagination_filter: PaginationFilter,
Expand Down Expand Up @@ -1475,9 +1474,9 @@ impl Client {
}

/// Get a page of transactions based on the provided filters.
pub async fn transactions<'a>(
pub async fn transactions(
&self,
filter: Option<TransactionsFilter<'a>>,
filter: Option<TransactionsFilter<'_>>,
pagination_filter: PaginationFilter,
) -> Result<Page<SignedTransaction>> {
let (after, before, first, last) = self.pagination_filter(pagination_filter).await;
Expand Down Expand Up @@ -1513,9 +1512,9 @@ impl Client {
}

/// Get a page of transactions' effects based on the provided filters.
pub async fn transactions_effects<'a>(
pub async fn transactions_effects(
&self,
filter: Option<TransactionsFilter<'a>>,
filter: Option<TransactionsFilter<'_>>,
pagination_filter: PaginationFilter,
) -> Result<Page<TransactionEffects>> {
let (after, before, first, last) = self.pagination_filter(pagination_filter).await;
Expand Down Expand Up @@ -2002,7 +2001,7 @@ mod tests {
_ => return,
};
let key = Ed25519PublicKey::generate(rand::thread_rng());
let address = key.to_address();
let address = key.derive_address();
faucet.request_and_wait(address).await.unwrap();

const MAX_RETRIES: u32 = 10;
Expand Down
4 changes: 3 additions & 1 deletion crates/sui-graphql-client/src/streams.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ where
/// Creates a new `PageStream` for a paginated query.
///
/// Examples
///
/// ```rust,ignore
/// use futures::StreamExt;
/// use sui_graphql_client::streams::stream_paginated_query;
Expand All @@ -160,8 +161,9 @@ where
///
/// let client = Client::new_testnet();
/// let stream = stream_paginated_query(|pagination_filter, Direction::Forward| {
/// client.coins(owner, coin_type, pagination_filter })
/// client.coins(owner, coin_type, pagination_filter)
/// });
///
/// while let Some(result) = stream.next().await {
/// match result {
/// Ok(coin) => println!("Got coin: {:?}", coin),
Expand Down
1 change: 0 additions & 1 deletion crates/sui-sdk-types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ test-strategy = { version = "0.4", optional = true }
bcs = "0.1.6"
serde_json = "1.0.128"
num-bigint = "0.4.6"
jsonschema = { version = "0.20", default-features = false }
paste = "1.0.15"

[target.wasm32-unknown-unknown.dev-dependencies]
Expand Down
55 changes: 55 additions & 0 deletions crates/sui-sdk-types/src/address.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,58 @@
/// Unique identifier for an Account on the Sui blockchain.
///
/// An `Address` is a 32-byte pseudonymous identifier used to uniquely identify an account and
/// asset-ownership on the Sui blockchain. Often, human-readable addresses are encoded in
/// hexadecimal with a `0x` prefix. For example, this is a valid Sui address:
/// `0x02a212de6a9dfa3a69e22387acfbafbb1a9e591bd9d636e7895dcfc8de05f331`.
///
/// ```
/// use sui_sdk_types::Address;
///
/// let hex = "0x02a212de6a9dfa3a69e22387acfbafbb1a9e591bd9d636e7895dcfc8de05f331";
/// let address = Address::from_hex(hex).unwrap();
/// println!("Address: {}", address);
/// assert_eq!(hex, address.to_string());
/// ```
///
/// # Deriving an Address
///
/// Addresses are cryptographically derived from a number of user account authenticators, the simplest
/// of which is an [`Ed25519PublicKey`](crate::Ed25519PublicKey).
///
/// Deriving an address consists of the Blake2b256 hash of the sequence of bytes of its
/// corresponding authenticator, prefixed with a domain-separator. For each authenticator, this
/// domain-separator is the single byte-value of its [`SignatureScheme`](crate::SignatureScheme)
/// flag. E.g. `hash(signature schema flag || authenticator bytes)`.
///
/// Each authenticator includes a convince method for deriving its `Address` as well as
/// documentation for the specifics of how the derivation is done. See
/// [`Ed25519PublicKey::derive_address`] for an example.
///
/// [`Ed25519PublicKey::derive_address`]: crate::Ed25519PublicKey::derive_address
///
/// ## Relationship to ObjectIds
///
/// [`ObjectId`]s and `Address`es share the same 32-byte addressable space but are derived
/// leveraging different domain-separator values to ensure, cryptographically, that there won't be
/// any overlap, e.g. there can't be a valid `Object` who's `ObjectId` is equal to that of the
/// `Address` of a user account.
///
/// [`ObjectId`]: crate::ObjectId
///
/// # BCS
///
/// An `Address`'s BCS serialized form is simply the sequence of 32-bytes of the address.
///
/// ```
/// use sui_sdk_types::Address;
///
/// let bytes = [
/// 0x02, 0xa2, 0x12, 0xde, 0x6a, 0x9d, 0xfa, 0x3a, 0x69, 0xe2, 0x23, 0x87, 0xac, 0xfb, 0xaf,
/// 0xbb, 0x1a, 0x9e, 0x59, 0x1b, 0xd9, 0xd6, 0x36, 0xe7, 0x89, 0x5d, 0xcf, 0xc8, 0xde, 0x05,
/// 0xf3, 0x31,
/// ];
/// let address: Address = bcs::from_bytes(&bytes).unwrap();
/// ```
#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(
feature = "serde",
Expand Down
34 changes: 26 additions & 8 deletions crates/sui-sdk-types/src/crypto/zklogin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,30 @@ pub struct CircomG1(pub [Bn254FieldElement; 3]);
#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
pub struct CircomG2(pub [[Bn254FieldElement; 2]; 3]);

/// A wrapper struct to retrofit in [enum PublicKey] for zkLogin.
/// Useful to construct [struct MultiSigPublicKey].
/// Public Key equivalent for Zklogin authenticators
///
/// A `ZkLoginPublicIdentifier` is the equivalent of a public key for other account authenticators,
/// and contains the information required to derive the onchain account [`Address`] for a Zklogin
/// authenticator.
///
/// ## Note
///
/// Due to a historical bug that was introduced in the Sui Typescript SDK when the zklogin
/// authenticator was first introduced, there are now possibly two "valid" addresses for each
/// zklogin authenticator depending on the bit-pattern of the `address_seed` value.
///
/// The original bug incorrectly derived a zklogin's address by stripping any leading
/// zero-bytes that could have been present in the 32-byte length `address_seed` value prior to
/// hashing, leading to a different derived address. This incorrectly derived address was
/// presented to users of various wallets, leading them to sending funds to these addresses
/// that they couldn't access. Instead of letting these users lose any assets that were sent to
/// these addrsses, the Sui network decided to change the protocol to allow for a zklogin
/// authenticator who's `address_seed` value had leading zero-bytes be authorized to sign for
/// both the addresses derived from both the unpadded and padded `address_seed` value.
///
/// [`Address`]: crate::Address
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
//TODO ensure iss is less than 255 bytes long
pub struct ZkLoginPublicIdentifier {
iss: String,
address_seed: Bn254FieldElement,
Expand Down Expand Up @@ -297,7 +316,8 @@ mod serialization {
}

let Readable { iss, address_seed } = Deserialize::deserialize(deserializer)?;
Ok(Self { iss, address_seed })
Self::new(iss, address_seed)
.ok_or_else(|| serde::de::Error::custom("invalid zklogin public identifier"))
} else {
let bytes: Cow<'de, [u8]> = Bytes::deserialize_as(deserializer)?;
let iss_len = *bytes
Expand All @@ -315,10 +335,8 @@ mod serialization {
.map_err(serde::de::Error::custom)
.map(Bn254FieldElement)?;

Ok(Self {
iss: iss.into(),
address_seed,
})
Self::new(iss.into(), address_seed)
.ok_or_else(|| serde::de::Error::custom("invalid zklogin public identifier"))
}
}
}
Expand Down
Loading
Loading