├── .cargo └── config.toml ├── .github ├── CODEOWNERS └── workflows │ ├── ci.yml │ └── rustdoc.yml ├── .gitignore ├── Cargo.toml ├── LICENSE ├── Makefile ├── README.md └── crates ├── sui-crypto ├── CHANGELOG.md ├── Cargo.toml ├── Makefile ├── README.md └── src │ ├── bls12381.rs │ ├── ed25519.rs │ ├── lib.rs │ ├── multisig.rs │ ├── passkey.rs │ ├── secp256k1.rs │ ├── secp256r1.rs │ ├── simple.rs │ └── zklogin │ ├── mod.rs │ ├── poseidon │ ├── constants.rs │ └── mod.rs │ ├── tests.rs │ └── verify.rs ├── sui-graphql-client-build ├── Cargo.toml ├── README.md ├── schema.graphql └── src │ └── lib.rs ├── sui-graphql-client ├── CHANGELOG.md ├── Cargo.toml ├── README.md ├── build.rs ├── examples │ └── custom_query.rs ├── queries │ ├── coin_metadata.graphql │ ├── custom_query.graphql │ ├── epoch_total_checkpoints.graphql │ ├── object.graphql │ └── objects.graphql └── src │ ├── error.rs │ ├── faucet.rs │ ├── lib.rs │ ├── query_types │ ├── active_validators.rs │ ├── balance.rs │ ├── chain.rs │ ├── checkpoint.rs │ ├── coin.rs │ ├── dry_run.rs │ ├── dynamic_fields.rs │ ├── epoch.rs │ ├── events.rs │ ├── execute_tx.rs │ ├── mod.rs │ ├── normalized_move │ │ ├── function.rs │ │ ├── mod.rs │ │ └── module.rs │ ├── object.rs │ ├── packages.rs │ ├── protocol_config.rs │ ├── service_config.rs │ ├── suins.rs │ └── transaction.rs │ └── streams.rs ├── sui-sdk-types ├── CHANGELOG.md ├── Cargo.toml ├── Makefile ├── README.md └── src │ ├── address.rs │ ├── checkpoint.rs │ ├── crypto │ ├── bls12381.rs │ ├── ed25519.rs │ ├── intent.rs │ ├── mod.rs │ ├── multisig.rs │ ├── passkey.rs │ ├── secp256k1.rs │ ├── secp256r1.rs │ ├── signature.rs │ ├── validator.rs │ └── zklogin.rs │ ├── digest.rs │ ├── effects │ ├── fixtures │ │ ├── genesis-transaction-effects │ │ └── pyth-wormhole-v2 │ ├── mod.rs │ ├── v1.rs │ └── v2.rs │ ├── events.rs │ ├── execution_status.rs │ ├── framework.rs │ ├── gas.rs │ ├── hash.rs │ ├── lib.rs │ ├── object.rs │ ├── object_id.rs │ ├── serialization_proptests.rs │ ├── transaction │ ├── fixtures │ │ ├── authenticator_state_update │ │ ├── genesis-transaction │ │ └── wormhole-pyth-transaction │ ├── mod.rs │ └── serialization.rs │ ├── type_tag │ ├── mod.rs │ ├── parse.rs │ └── serialization.rs │ └── u256.rs └── sui-transaction-builder ├── .gitignore ├── Cargo.toml ├── src ├── error.rs ├── lib.rs └── unresolved.rs └── tests ├── test_example_v1 ├── Move.toml └── sources │ └── test_example.move └── test_example_v2 ├── Move.toml └── sources └── test_example.move /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | # This is required to enable running wasm tests 2 | [target.wasm32-unknown-unknown] 3 | rustflags = ['--cfg', 'getrandom_backend="wasm_js"'] 4 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @bmwill 2 | 3 | /.github/ @bmwill 4 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | pull_request: 6 | workflow_dispatch: 7 | schedule: [cron: "40 1 * * *"] 8 | 9 | permissions: 10 | contents: read 11 | 12 | env: 13 | RUSTFLAGS: -Dwarnings 14 | 15 | jobs: 16 | test: 17 | runs-on: ubuntu-latest 18 | 19 | steps: 20 | - name: Checkout repository 21 | uses: actions/checkout@v4 22 | 23 | - name: rust version 24 | run: | 25 | rustc --version 26 | cargo --version 27 | 28 | - uses: taiki-e/install-action@cargo-hack 29 | - uses: taiki-e/install-action@cargo-nextest 30 | 31 | - name: feature compatibility 32 | run: make check-features 33 | 34 | - name: rustfmt 35 | run: make check-fmt 36 | 37 | - name: clippy 38 | run: make clippy 39 | 40 | - name: Run tests 41 | run: make test 42 | 43 | - name: rustdoc 44 | run: make doc 45 | 46 | wasm: 47 | runs-on: ubuntu-latest 48 | 49 | steps: 50 | - name: Checkout repository 51 | uses: actions/checkout@v4 52 | 53 | - name: rust version 54 | run: | 55 | rustc --version 56 | cargo --version 57 | 58 | - uses: taiki-e/install-action@wasm-pack 59 | 60 | - name: Install clang 61 | run: sudo apt-get install -y clang 62 | 63 | - name: Run tests in wasm 64 | run: RUSTFLAGS='-Dwarnings --cfg getrandom_backend="wasm_js"' make wasm 65 | 66 | run_tests_with_network: 67 | runs-on: ubuntu-latest 68 | env: 69 | EPOCH_DURATION_MS: 10000 70 | services: 71 | postgres: # we need this postgres instance for running a local network with indexer and graphql 72 | image: postgres 73 | env: 74 | POSTGRES_USER: postgres 75 | POSTGRES_PASSWORD: postgrespw 76 | POSTGRES_DB: sui_indexer_v2 77 | POSTGRES_HOST_AUTH_METHOD: trust 78 | options: >- 79 | --health-cmd pg_isready 80 | --health-interval 10s 81 | --health-timeout 5s 82 | --health-retries 5 83 | ports: 84 | - 5432:5432 85 | steps: 86 | - name: Checkout repository 87 | uses: actions/checkout@v4 88 | 89 | - name: rust version 90 | run: | 91 | rustc --version 92 | cargo --version 93 | 94 | - uses: taiki-e/install-action@cargo-nextest 95 | 96 | - name: Get the Sui testnet binary and start a local network 97 | shell: bash 98 | env: 99 | SUI_BINARY_VERSION: "1.48.0" # used for downloading a specific Sui binary versions that matches the GraphQL schema for local network tests 100 | SUI_NETWORK_RELEASE: "testnet" # which release to use 101 | run: | 102 | ASSET_NAME="sui-$SUI_NETWORK_RELEASE-v$SUI_BINARY_VERSION-ubuntu-x86_64.tgz" 103 | download_url="https://github.com/mystenlabs/sui/releases/download/$SUI_NETWORK_RELEASE-v$SUI_BINARY_VERSION/$ASSET_NAME" 104 | 105 | echo "Downloading testnet binary from $download_url" 106 | wget -q $download_url -O sui.tgz 107 | tar -zxvf sui.tgz ./sui 108 | chmod +x ./sui 109 | echo "Starting local network with a faucet, an indexer (port 5432) and GraphQL. Epoch duration is set to $EPOCH_DURATION_MS ms" 110 | echo "$(pwd)" >> $GITHUB_PATH # we need it on the path for calling sui move build for some tests 111 | ./sui start --force-regenesis --with-faucet --with-indexer --with-graphql --pg-port 5432 --pg-db-name sui_indexer_v2 --epoch-duration-ms $EPOCH_DURATION_MS & 112 | 113 | - name: Run tests that require local network (GraphQL Client and Tx Builder) 114 | env: 115 | NETWORK: "local" # other expected options are mainnet, testnet, or devnet, or an actual URL to a GraphQL server: http://localhost:port 116 | run: | 117 | sleep $((EPOCH_DURATION_MS / 1000)) # wait for the network to get to epoch #2 118 | make test-with-localnet 119 | -------------------------------------------------------------------------------- /.github/workflows/rustdoc.yml: -------------------------------------------------------------------------------- 1 | name: rustdoc 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | workflow_dispatch: 7 | 8 | env: 9 | RUSTFLAGS: -D warnings 10 | 11 | jobs: 12 | rustdoc: 13 | runs-on: ubuntu-latest 14 | permissions: 15 | contents: write 16 | 17 | steps: 18 | - name: Checkout repository 19 | uses: actions/checkout@v4 20 | 21 | - name: rustdoc 22 | run: make doc 23 | 24 | - name: Deploy Docs 25 | uses: peaceiris/actions-gh-pages@v3 26 | with: 27 | github_token: ${{ secrets.GITHUB_TOKEN }} 28 | publish_branch: gh-pages 29 | publish_dir: ./target/doc 30 | force_orphan: true 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = ["crates/*"] 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Set the default target of this Makefile 2 | .PHONY: all 3 | all:: ci ## Default target, runs the CI process 4 | 5 | .PHONY: check-features 6 | check-features: ## Check feature flags for crates 7 | $(MAKE) -C crates/sui-sdk-types check-features 8 | $(MAKE) -C crates/sui-crypto check-features 9 | 10 | .PHONY: check-fmt 11 | check-fmt: ## Check code formatting 12 | cargo fmt -- --config imports_granularity=Item --config format_code_in_doc_comments=true --check 13 | 14 | .PHONY: fmt 15 | fmt: ## Format code 16 | cargo fmt -- --config imports_granularity=Item --config format_code_in_doc_comments=true 17 | 18 | .PHONY: clippy 19 | clippy: ## Run Clippy linter 20 | cargo clippy --all-features --all-targets 21 | 22 | .PHONY: test 23 | test: ## Run unit tests 24 | cargo nextest run --all-features -p sui-sdk-types -p sui-crypto 25 | cargo test --all-features --doc 26 | 27 | package_%.json: crates/sui-transaction-builder/tests/%/Move.toml crates/sui-transaction-builder/tests/%/sources/*.move ## Generate JSON files for tests 28 | cd crates/sui-transaction-builder/tests/$(*F) && sui move build --ignore-chain --dump-bytecode-as-base64 > ../../$@ 29 | 30 | .PHONY: test-with-localnet 31 | test-with-localnet: package_test_example_v1.json package_test_example_v2.json ## Run tests with localnet 32 | cargo nextest run -p sui-graphql-client -p sui-transaction-builder 33 | 34 | .PHONY: wasm 35 | wasm: ## Build WASM modules 36 | $(MAKE) -C crates/sui-sdk-types wasm 37 | $(MAKE) -C crates/sui-crypto wasm 38 | 39 | .PHONY: doc 40 | doc: ## Generate documentation 41 | RUSTDOCFLAGS="-Dwarnings --cfg=doc_cfg -Zunstable-options --generate-link-to-definition" RUSTC_BOOTSTRAP=1 cargo doc --all-features --no-deps 42 | 43 | .PHONY: doc-open 44 | doc-open: ## Generate and open documentation 45 | RUSTDOCFLAGS="--cfg=doc_cfg -Zunstable-options --generate-link-to-definition" RUSTC_BOOTSTRAP=1 cargo doc --all-features --no-deps --open 46 | 47 | .PHONY: ci 48 | ci: check-features check-fmt test wasm ## Run the full CI process 49 | 50 | .PHONY: ci-full 51 | ci-full: ci doc ## Run the full CI process and generate documentation 52 | 53 | .PHONY: clean 54 | clean: ## Clean build artifacts 55 | cargo clean 56 | 57 | .PHONY: clean-all 58 | clean-all: clean ## Clean all generated files, including those ignored by Git. Force removal. 59 | git clean -dXf 60 | 61 | .PHONY: help 62 | help: ## Show this help 63 | @echo "Available targets:" 64 | @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sui Sdk 2 | 3 | A rust Sdk for integrating with the [Sui blockchain](https://docs.sui.io/). 4 | 5 | > [!NOTE] 6 | > This is project is under development and many features may still be under 7 | > development or missing. 8 | 9 | ## Overview 10 | 11 | This repository contains a collection of libraries for integrating with the Sui blockchain. 12 | 13 | A few of the project's high-level goals are as follows: 14 | 15 | * **Be modular** - user's should only need to pay the cost (in terms of dependencies/compilation time) for the features that they use. 16 | * **Be light** - strive to have a minimal dependency footprint. 17 | * **Support developers** - provide all needed types, abstractions and APIs to enable developers to build robust applications on Sui. 18 | * **Support wasm** - where possible, libraries should be usable in wasm environments. 19 | 20 | ## Crates 21 | 22 | In an effort to be modular, functionality is split between a number of crates. 23 | 24 | * [`sui-sdk-types`](crates/sui-sdk-types) 25 | [![sui-sdk-types on crates.io](https://img.shields.io/crates/v/sui-sdk-types)](https://crates.io/crates/sui-sdk-types) 26 | [![Documentation (latest release)](https://img.shields.io/badge/docs-latest-brightgreen)](https://docs.rs/sui-sdk-types) 27 | [![Documentation (master)](https://img.shields.io/badge/docs-master-59f)](https://mystenlabs.github.io/sui-rust-sdk/sui_sdk_types/) 28 | * [`sui-crypto`](crates/sui-crypto) 29 | [![sui-crypto on crates.io](https://img.shields.io/crates/v/sui-crypto)](https://crates.io/crates/sui-crypto) 30 | [![Documentation (latest release)](https://img.shields.io/badge/docs-latest-brightgreen)](https://docs.rs/sui-crypto) 31 | [![Documentation (master)](https://img.shields.io/badge/docs-master-59f)](https://mystenlabs.github.io/sui-rust-sdk/sui_crypto/) 32 | * [`sui-graphql-client`](crates/sui-crypto) 33 | [![sui-graphql-client on crates.io](https://img.shields.io/crates/v/sui-graphql-client)](https://crates.io/crates/sui-graphql-client) 34 | [![Documentation (latest release)](https://img.shields.io/badge/docs-latest-brightgreen)](https://docs.rs/sui-graphql-client) 35 | [![Documentation (master)](https://img.shields.io/badge/docs-master-59f)](https://mystenlabs.github.io/sui-rust-sdk/sui-graphql-client/) 36 | 37 | ## License 38 | 39 | This project is available under the terms of the [Apache 2.0 license](LICENSE). 40 | -------------------------------------------------------------------------------- /crates/sui-crypto/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # [0.0.4] - 2025-03-31 2 | 3 | - Update to use version 0.0.4 of `sui-sdk-types` 4 | 5 | # [0.0.3] - 2025-03-20 6 | 7 | - Update to use version 0.0.3 of `sui-sdk-types` 8 | 9 | # [0.0.2] - 2025-01-06 10 | 11 | ## Added 12 | 13 | - Added support for multisig verification and aggregation ([#25]) 14 | - Added blanket implementation for SuiSigner and SuiVerifier ([`bc481a1`]) 15 | - Added support for der and pem format for public and private keys ([`df32a46`]) 16 | - Added a `SimpleKeypair` type which could be either an ed25519, secp256k1, or secp256r1 keypair ([`8d64c06`]) 17 | - Added support for verifying passkey authenticators ([#81]) 18 | 19 | [#25]: https://github.com/mystenlabs/sui-rust-sdk/pull/25 20 | [`bc481a1`]: https://github.com/mystenlabs/sui-rust-sdk/commit/bc481a1ea156e6ccb528b5b49e62a511be5ba60a 21 | [`df32a46`]: https://github.com/mystenlabs/sui-rust-sdk/commit/df32a46bfbecbbbf4ec7e9c1974eef0916ccd359 22 | [`8d64c06`]: https://github.com/mystenlabs/sui-rust-sdk/commit/8d64c06628b9494c674c27158ce74036fe45080e 23 | [#81]: https://github.com/MystenLabs/sui-rust-sdk/pull/81 24 | 25 | # [0.0.1] - 2024-09-25 26 | 27 | Initial release 28 | 29 | [0.0.4]: https://github.com/mystenlabs/sui-rust-sdk/releases/tag/sui-crypto-0.0.4 30 | [0.0.3]: https://github.com/mystenlabs/sui-rust-sdk/releases/tag/sui-crypto-0.0.3 31 | [0.0.2]: https://github.com/mystenlabs/sui-rust-sdk/releases/tag/sui-crypto-0.0.2 32 | [0.0.1]: https://github.com/mystenlabs/sui-rust-sdk/releases/tag/sui-crypto-0.0.1 33 | -------------------------------------------------------------------------------- /crates/sui-crypto/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sui-crypto" 3 | version = "0.0.4" 4 | authors = ["Brandon Williams "] 5 | repository = "https://github.com/mystenlabs/sui-rust-sdk/" 6 | license = "Apache-2.0" 7 | edition = "2021" 8 | readme = "README.md" 9 | description = "Defines the interface for signing and verying messages in the Sui ecosystem" 10 | 11 | [package.metadata.docs.rs] 12 | # To build locally: 13 | # RUSTDOCFLAGS="--cfg=doc_cfg -Zunstable-options --generate-link-to-definition" RUSTC_BOOTSTRAP=1 cargo doc --all-features --no-deps --open 14 | all-features = true 15 | rustdoc-args = [ 16 | # Enable doc_cfg showing the required features. 17 | "--cfg=doc_cfg", 18 | 19 | # Generate links to definition in rustdoc source code pages 20 | # https://github.com/rust-lang/rust/pull/84176 21 | "-Zunstable-options", "--generate-link-to-definition" 22 | ] 23 | 24 | [features] 25 | default = [] 26 | ed25519 = ["dep:ed25519-dalek", "dep:rand_core"] 27 | secp256r1 = ["dep:p256", "dep:rand_core"] 28 | passkey = ["secp256r1", "dep:sha2"] 29 | secp256k1 = ["dep:k256", "dep:rand_core", "signature/std"] 30 | zklogin = [ 31 | "dep:ark-bn254", 32 | "dep:ark-ff", 33 | "dep:ark-groth16", 34 | "dep:ark-snark", 35 | "dep:ark-std", 36 | "dep:base64ct", 37 | "dep:bnum", 38 | "dep:itertools", 39 | "dep:serde", 40 | "dep:serde_derive", 41 | "dep:serde_json", 42 | "signature/std", 43 | ] 44 | pem = [ 45 | "dep:pkcs8", 46 | "dep:pem-rfc7468", 47 | "ed25519-dalek?/pkcs8", 48 | "p256?/pkcs8", 49 | "k256?/pkcs8", 50 | "ed25519-dalek?/pem", 51 | "p256?/pem", 52 | "k256?/pem", 53 | ] 54 | 55 | [dependencies] 56 | signature = "2.2" 57 | sui-sdk-types = { version = "0.0.4", path = "../sui-sdk-types", default-features = false, features = ["hash", "serde"] } 58 | 59 | # RNG support 60 | rand_core = { version = "0.6.4", optional = true } 61 | 62 | # ed25519 support 63 | ed25519-dalek = { version = "2.1.1", optional = true } 64 | 65 | # secp256r1 support 66 | p256 = { version = "0.13.2", default-features = false, features = ["ecdsa", "std"], optional = true } 67 | 68 | # passkey verification support 69 | sha2 = { version = "0.10.8", optional = true } 70 | 71 | # secp256k1 support 72 | k256 = { version = "0.13.4", default-features = false, features = ["ecdsa"], optional = true } 73 | 74 | # zklogin verification support 75 | ark-bn254 = { version = "0.4.0", optional = true } 76 | ark-ff = { version = "0.4.2", features = ["asm"], optional = true } 77 | ark-groth16 = { version = "0.4.0", default-features = false, optional = true } 78 | ark-snark = { version = "0.4.0", optional = true } 79 | ark-std = { version = "0.4.0", optional = true } 80 | base64ct = { version = "1.6.0", features = ["alloc"], optional = true } 81 | bnum = { version = "0.12.0", optional = true } 82 | itertools = { version = "0.13.0", optional = true } 83 | serde = { version = "1.0.210", optional = true } 84 | serde_derive = { version = "1.0.210", optional = true } 85 | serde_json = { version = "1.0.128", optional = true } 86 | 87 | # pkcs8 der and pem support 88 | pkcs8 = { version = "0.10", optional = true, features = ["std"] } 89 | pem-rfc7468 = { version = "0.7", optional = true, features = ["std"] } 90 | 91 | [dev-dependencies] 92 | bcs = { version = "0.1.6" } 93 | hex = "0.4.3" 94 | serde_json = { version = "1.0.128" } 95 | 96 | # proptest support in tests 97 | proptest = { version = "1.6.0", default-features = false, features = ["std"] } 98 | test-strategy = "0.4.0" 99 | 100 | [target.wasm32-unknown-unknown.dev-dependencies] 101 | wasm-bindgen-test = "0.3" 102 | getrandom_2 = { version = "0.2", package = "getrandom", features = ["js"] } 103 | getrandom_3 = { version = "0.3", package = "getrandom", features = ["wasm_js"] } 104 | 105 | [lints.rust] 106 | unexpected_cfgs = { level = "warn", check-cfg = ['cfg(doc_cfg)'] } 107 | -------------------------------------------------------------------------------- /crates/sui-crypto/Makefile: -------------------------------------------------------------------------------- 1 | # Set the default target of this Makefile 2 | .PHONY: all 3 | all:: check-features clippy test wasm 4 | 5 | .PHONY: check-features 6 | check-features: 7 | cargo hack check --feature-powerset --no-dev-deps 8 | 9 | .PHONY: clippy 10 | clippy: 11 | cargo clippy --all-features --all-targets 12 | 13 | .PHONY: test 14 | test: 15 | cargo nextest run --all-features 16 | cargo test --doc 17 | 18 | .PHONY: wasm 19 | wasm: 20 | CC=clang wasm-pack test -r --node --all-features 21 | 22 | %: 23 | $(MAKE) -C ../.. $@ 24 | -------------------------------------------------------------------------------- /crates/sui-crypto/README.md: -------------------------------------------------------------------------------- 1 | # sui-crypto 2 | 3 | [![sui-crypto on crates.io](https://img.shields.io/crates/v/sui-crypto)](https://crates.io/crates/sui-crypto) 4 | [![Documentation (latest release)](https://img.shields.io/badge/docs-latest-brightgreen)](https://docs.rs/sui-crypto) 5 | [![Documentation (master)](https://img.shields.io/badge/docs-master-59f)](https://mystenlabs.github.io/sui-rust-sdk/sui_crypto/) 6 | 7 | The `sui-crypto` crate provides the interface for signing and verifying 8 | transactions and messages in the Sui ecosystem. 9 | -------------------------------------------------------------------------------- /crates/sui-crypto/src/bls12381.rs: -------------------------------------------------------------------------------- 1 | #[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] 2 | pub struct Bls12381PrivateKey([u8; Self::LENGTH]); 3 | 4 | impl Bls12381PrivateKey { 5 | /// The length of an bls12381 private key in bytes. 6 | pub const LENGTH: usize = 32; 7 | } 8 | -------------------------------------------------------------------------------- /crates/sui-crypto/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(doc_cfg, feature(doc_cfg))] 2 | 3 | use sui_sdk_types::PersonalMessage; 4 | use sui_sdk_types::Transaction; 5 | use sui_sdk_types::UserSignature; 6 | 7 | pub use signature::Error as SignatureError; 8 | pub use signature::Signer; 9 | pub use signature::Verifier; 10 | 11 | #[cfg(feature = "ed25519")] 12 | #[cfg_attr(doc_cfg, doc(cfg(feature = "ed25519")))] 13 | pub mod ed25519; 14 | 15 | #[allow(unused)] 16 | mod bls12381; 17 | 18 | #[cfg(feature = "secp256k1")] 19 | #[cfg_attr(doc_cfg, doc(cfg(feature = "secp256k1")))] 20 | pub mod secp256k1; 21 | 22 | #[cfg(feature = "secp256r1")] 23 | #[cfg_attr(doc_cfg, doc(cfg(feature = "secp256r1")))] 24 | pub mod secp256r1; 25 | 26 | #[cfg(feature = "passkey")] 27 | #[cfg_attr(doc_cfg, doc(cfg(feature = "passkey")))] 28 | pub mod passkey; 29 | 30 | #[cfg(feature = "zklogin")] 31 | #[cfg_attr(doc_cfg, doc(cfg(feature = "zklogin")))] 32 | pub mod zklogin; 33 | 34 | #[cfg(any( 35 | feature = "ed25519", 36 | feature = "secp256r1", 37 | feature = "secp256k1", 38 | feature = "zklogin" 39 | ))] 40 | #[cfg_attr( 41 | doc_cfg, 42 | doc(cfg(any( 43 | feature = "ed25519", 44 | feature = "secp256r1", 45 | feature = "secp256k1", 46 | feature = "zklogin" 47 | ))) 48 | )] 49 | pub mod simple; 50 | 51 | #[cfg(any( 52 | feature = "ed25519", 53 | feature = "secp256r1", 54 | feature = "secp256k1", 55 | feature = "zklogin" 56 | ))] 57 | #[cfg_attr( 58 | doc_cfg, 59 | doc(cfg(any( 60 | feature = "ed25519", 61 | feature = "secp256r1", 62 | feature = "secp256k1", 63 | feature = "zklogin" 64 | ))) 65 | )] 66 | pub mod multisig; 67 | 68 | #[cfg(any( 69 | feature = "ed25519", 70 | feature = "secp256r1", 71 | feature = "secp256k1", 72 | feature = "zklogin" 73 | ))] 74 | #[cfg_attr( 75 | doc_cfg, 76 | doc(cfg(any( 77 | feature = "ed25519", 78 | feature = "secp256r1", 79 | feature = "secp256k1", 80 | feature = "zklogin" 81 | ))) 82 | )] 83 | #[doc(inline)] 84 | pub use multisig::UserSignatureVerifier; 85 | 86 | /// Interface for signing user transactions and messages in Sui 87 | /// 88 | /// # Note 89 | /// 90 | /// There is a blanket implementation of `SuiSigner` for all `T` where `T: 91 | /// `[`Signer`]`<`[`UserSignature`]`>` so it is generally recommended for a signer to implement 92 | /// `Signer` and rely on the blanket implementation which handles the proper 93 | /// construction of the signing message. 94 | pub trait SuiSigner { 95 | fn sign_transaction(&self, transaction: &Transaction) -> Result; 96 | fn sign_personal_message( 97 | &self, 98 | message: &PersonalMessage<'_>, 99 | ) -> Result; 100 | } 101 | 102 | impl> SuiSigner for T { 103 | fn sign_transaction(&self, transaction: &Transaction) -> Result { 104 | let msg = transaction.signing_digest(); 105 | self.try_sign(&msg) 106 | } 107 | 108 | fn sign_personal_message( 109 | &self, 110 | message: &PersonalMessage<'_>, 111 | ) -> Result { 112 | let msg = message.signing_digest(); 113 | self.try_sign(&msg) 114 | } 115 | } 116 | 117 | /// Interface for verifying user transactions and messages in Sui 118 | /// 119 | /// # Note 120 | /// 121 | /// There is a blanket implementation of `SuiVerifier` for all `T` where `T: 122 | /// `[`Verifier`]`<`[`UserSignature`]`>` so it is generally recommended for a signer to implement 123 | /// `Verifier` and rely on the blanket implementation which handles the proper 124 | /// construction of the signing message. 125 | pub trait SuiVerifier { 126 | fn verify_transaction( 127 | &self, 128 | transaction: &Transaction, 129 | signature: &UserSignature, 130 | ) -> Result<(), SignatureError>; 131 | fn verify_personal_message( 132 | &self, 133 | message: &PersonalMessage<'_>, 134 | signature: &UserSignature, 135 | ) -> Result<(), SignatureError>; 136 | } 137 | 138 | impl> SuiVerifier for T { 139 | fn verify_transaction( 140 | &self, 141 | transaction: &Transaction, 142 | signature: &UserSignature, 143 | ) -> Result<(), SignatureError> { 144 | let message = transaction.signing_digest(); 145 | self.verify(&message, signature) 146 | } 147 | 148 | fn verify_personal_message( 149 | &self, 150 | message: &PersonalMessage<'_>, 151 | signature: &UserSignature, 152 | ) -> Result<(), SignatureError> { 153 | let message = message.signing_digest(); 154 | self.verify(&message, signature) 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /crates/sui-crypto/src/passkey.rs: -------------------------------------------------------------------------------- 1 | use crate::secp256r1::Secp256r1VerifyingKey; 2 | use crate::SignatureError; 3 | use signature::Verifier; 4 | use sui_sdk_types::PasskeyAuthenticator; 5 | use sui_sdk_types::SimpleSignature; 6 | use sui_sdk_types::UserSignature; 7 | 8 | #[derive(Default, Clone, Debug)] 9 | pub struct PasskeyVerifier {} 10 | 11 | impl PasskeyVerifier { 12 | pub fn new() -> Self { 13 | Self {} 14 | } 15 | } 16 | 17 | impl Verifier for PasskeyVerifier { 18 | fn verify( 19 | &self, 20 | message: &[u8], 21 | authenticator: &PasskeyAuthenticator, 22 | ) -> Result<(), SignatureError> { 23 | let SimpleSignature::Secp256r1 { 24 | signature, 25 | public_key, 26 | } = authenticator.signature() 27 | else { 28 | return Err(SignatureError::from_source("not a secp256r1 signature")); 29 | }; 30 | 31 | if message != authenticator.challenge() { 32 | return Err(SignatureError::from_source( 33 | "passkey challenge does not match expected message", 34 | )); 35 | } 36 | 37 | // Construct passkey signing message = authenticator_data || sha256(client_data_json). 38 | let mut message = authenticator.authenticator_data().to_owned(); 39 | let client_data_hash = { 40 | use sha2::Digest; 41 | 42 | let mut hasher = sha2::Sha256::new(); 43 | hasher.update(authenticator.client_data_json().as_bytes()); 44 | hasher.finalize() 45 | }; 46 | message.extend_from_slice(&client_data_hash); 47 | 48 | let verifying_key = Secp256r1VerifyingKey::new(&public_key)?; 49 | 50 | verifying_key.verify(&message, &signature) 51 | } 52 | } 53 | 54 | impl Verifier for PasskeyVerifier { 55 | fn verify(&self, message: &[u8], signature: &UserSignature) -> Result<(), SignatureError> { 56 | let UserSignature::Passkey(authenticator) = signature else { 57 | return Err(SignatureError::from_source("not a passkey authenticator")); 58 | }; 59 | 60 | >::verify(self, message, authenticator) 61 | } 62 | } 63 | 64 | #[cfg(test)] 65 | mod test { 66 | use super::*; 67 | use crate::SuiVerifier; 68 | use sui_sdk_types::Transaction; 69 | 70 | #[cfg(target_arch = "wasm32")] 71 | use wasm_bindgen_test::wasm_bindgen_test as test; 72 | 73 | #[test] 74 | fn transaction_signing_fixture() { 75 | let transaction = "AAAAACdZawPnpJRjmVcwDu6xrIumtq5NLO+6GHbs0iGdCoD7AQ0T0TolicYERdSvyCRjSSduDZLbSpBsZBoib+lF48EBcgAAAAAAAAAgpQr/Mudl9BdzyBdkbqTlqBw4/aJ21kAD/jpJKa05im4nWWsD56SUY5lXMA7usayLprauTSzvuhh27NIhnQqA++gDAAAAAAAAgIQeAAAAAAAA"; 76 | let signature = "BiVJlg3liA6MaHQ0Fw9kdmBbj+SuuaKGMseZXPO6gx2XYx0AAAAAhgF7InR5cGUiOiJ3ZWJhdXRobi5nZXQiLCJjaGFsbGVuZ2UiOiJXellBZmVvbHcweU15bEFheDRvbzNjVC1rdEVaM0xmenZXcURqakxKZVRvIiwib3JpZ2luIjoiaHR0cDovL2xvY2FsaG9zdDo1MTczIiwiY3Jvc3NPcmlnaW4iOmZhbHNlfWICfOgpQ38QYao9Gj0/bqmWYNkuxvbuN3lz4uzFcXeVMEVivX41eC9H+tk+UnvUvKzThtf+uMLFzerU0zZLi8le4QJJsAUcyjsP/1UPAesax8UOC14M62FjAqtqaR46wR7jCg=="; 77 | 78 | let transaction: Transaction = { 79 | use base64ct::Encoding; 80 | let bytes = base64ct::Base64::decode_vec(transaction).unwrap(); 81 | bcs::from_bytes(&bytes).unwrap() 82 | }; 83 | let signature = UserSignature::from_base64(signature).unwrap(); 84 | 85 | let verifier = PasskeyVerifier::default(); 86 | verifier 87 | .verify_transaction(&transaction, &signature) 88 | .unwrap(); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /crates/sui-crypto/src/zklogin/mod.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use crate::SignatureError; 4 | use poseidon::POSEIDON; 5 | use signature::Verifier; 6 | use sui_sdk_types::Jwk; 7 | use sui_sdk_types::JwkId; 8 | use sui_sdk_types::UserSignature; 9 | use sui_sdk_types::ZkLoginAuthenticator; 10 | use sui_sdk_types::ZkLoginInputs; 11 | 12 | mod poseidon; 13 | mod verify; 14 | 15 | #[cfg(test)] 16 | mod tests; 17 | 18 | pub struct ZkloginVerifier { 19 | proof_verifying_key: verify::VerifyingKey, 20 | jwks: HashMap, 21 | } 22 | 23 | impl ZkloginVerifier { 24 | fn new(proof_verifying_key: verify::VerifyingKey) -> Self { 25 | Self { 26 | proof_verifying_key, 27 | jwks: Default::default(), 28 | } 29 | } 30 | 31 | pub fn new_mainnet() -> Self { 32 | Self::new(verify::VerifyingKey::new_mainnet()) 33 | } 34 | 35 | pub fn new_dev() -> Self { 36 | Self::new(verify::VerifyingKey::new_dev()) 37 | } 38 | 39 | pub fn jwks(&self) -> &HashMap { 40 | &self.jwks 41 | } 42 | 43 | pub fn jwks_mut(&mut self) -> &mut HashMap { 44 | &mut self.jwks 45 | } 46 | } 47 | 48 | impl Verifier for ZkloginVerifier { 49 | fn verify( 50 | &self, 51 | message: &[u8], 52 | signature: &ZkLoginAuthenticator, 53 | ) -> Result<(), SignatureError> { 54 | // 1. check that we have a valid corrisponding Jwk 55 | let jwt_details = JwtDetails::from_zklogin_inputs(&signature.inputs)?; 56 | let jwk = self.jwks.get(&jwt_details.id).ok_or_else(|| { 57 | SignatureError::from_source(format!( 58 | "unable to find corrisponding jwk with id '{:?}' for provided authenticator", 59 | jwt_details.id 60 | )) 61 | })?; 62 | 63 | // 2. verify that the provided SimpleSignature is valid 64 | crate::simple::SimpleVerifier.verify(message, &signature.signature)?; 65 | 66 | // 3. verify groth16 proof 67 | self.proof_verifying_key.verify_zklogin( 68 | jwk, 69 | &signature.inputs, 70 | &signature.signature, 71 | signature.max_epoch, 72 | ) 73 | } 74 | } 75 | 76 | impl Verifier for ZkloginVerifier { 77 | fn verify(&self, message: &[u8], signature: &UserSignature) -> Result<(), SignatureError> { 78 | let UserSignature::ZkLogin(zklogin_authenticator) = signature else { 79 | return Err(SignatureError::from_source("not a zklogin signature")); 80 | }; 81 | 82 | self.verify(message, zklogin_authenticator.as_ref()) 83 | } 84 | } 85 | 86 | /// A structed of parsed JWT details, consists of kid, header, iss. 87 | #[derive(Debug, Clone, PartialEq, Eq)] 88 | struct JwtDetails { 89 | header: JwtHeader, 90 | id: JwkId, 91 | } 92 | 93 | impl JwtDetails { 94 | fn from_zklogin_inputs(inputs: &ZkLoginInputs) -> Result { 95 | let header = JwtHeader::from_base64(&inputs.header_base64)?; 96 | let id = JwkId { 97 | iss: inputs.iss().map_err(SignatureError::from_source)?, 98 | kid: header.kid.clone(), 99 | }; 100 | Ok(JwtDetails { header, id }) 101 | } 102 | } 103 | 104 | /// Struct that represents a standard JWT header according to 105 | /// https://openid.net/specs/openid-connect-core-1_0.html 106 | #[derive(Debug, Clone, PartialEq, Eq)] 107 | struct JwtHeader { 108 | alg: String, 109 | kid: String, 110 | typ: Option, 111 | } 112 | 113 | impl JwtHeader { 114 | fn from_base64(s: &str) -> Result { 115 | use base64ct::Base64UrlUnpadded; 116 | use base64ct::Encoding; 117 | 118 | #[derive(serde_derive::Serialize, serde_derive::Deserialize)] 119 | struct Header { 120 | alg: String, 121 | kid: String, 122 | #[serde(skip_serializing_if = "Option::is_none")] 123 | typ: Option, 124 | } 125 | 126 | let header_bytes = Base64UrlUnpadded::decode_vec(s) 127 | .map_err(|e| SignatureError::from_source(e.to_string()))?; 128 | let Header { alg, kid, typ } = 129 | serde_json::from_slice(&header_bytes).map_err(SignatureError::from_source)?; 130 | if alg != "RS256" { 131 | return Err(SignatureError::from_source("jwt alg must be RS256")); 132 | } 133 | Ok(Self { alg, kid, typ }) 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /crates/sui-crypto/src/zklogin/tests.rs: -------------------------------------------------------------------------------- 1 | use signature::Signer; 2 | use sui_sdk_types::PersonalMessage; 3 | 4 | use crate::ed25519::Ed25519PrivateKey; 5 | use crate::SuiVerifier; 6 | 7 | use super::*; 8 | 9 | /// Returns a valid zklogin material for testing only. 10 | fn test_zklogin_material() -> (Jwk, JwkId, ZkLoginInputs, Ed25519PrivateKey, u64) { 11 | let inputs = serde_json::json!({ 12 | "proof_points": { 13 | "a": [ 14 | "17318089125952421736342263717932719437717844282410187957984751939942898251250", 15 | "11373966645469122582074082295985388258840681618268593976697325892280915681207", 16 | "1" 17 | ], 18 | "b": [ 19 | [ 20 | "5939871147348834997361720122238980177152303274311047249905942384915768690895", 21 | "4533568271134785278731234570361482651996740791888285864966884032717049811708" 22 | ], 23 | [ 24 | "10564387285071555469753990661410840118635925466597037018058770041347518461368", 25 | "12597323547277579144698496372242615368085801313343155735511330003884767957854" 26 | ], 27 | ["1","0"] 28 | ], 29 | "c": [ 30 | "15791589472556826263231644728873337629015269984699404073623603352537678813171", 31 | "4547866499248881449676161158024748060485373250029423904113017422539037162527", 32 | "1" 33 | ] 34 | }, 35 | "iss_base64_details": { 36 | "value": "wiaXNzIjoiaHR0cHM6Ly9pZC50d2l0Y2gudHYvb2F1dGgyIiw", 37 | "index_mod_4": 2 38 | }, 39 | "header_base64": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEifQ", 40 | "address_seed": "20794788559620669596206457022966176986688727876128223628113916380927502737911" 41 | }); 42 | 43 | let zklogin_inputs: ZkLoginInputs = serde_json::from_value(inputs).unwrap(); 44 | 45 | let key = Ed25519PrivateKey::new([ 46 | 155, 244, 154, 106, 7, 85, 249, 83, 129, 31, 206, 18, 95, 38, 131, 213, 4, 41, 195, 187, 47 | 73, 224, 116, 20, 126, 0, 137, 165, 46, 174, 21, 95, 48 | ]); 49 | 50 | let jwk: Jwk = serde_json::from_str(r#"{"alg":"RS256","e":"AQAB","kid":"1","kty":"RSA","n":"6lq9MQ-q6hcxr7kOUp-tHlHtdcDsVLwVIw13iXUCvuDOeCi0VSuxCCUY6UmMjy53dX00ih2E4Y4UvlrmmurK0eG26b-HMNNAvCGsVXHU3RcRhVoHDaOwHwU72j7bpHn9XbP3Q3jebX6KIfNbei2MiR0Wyb8RZHE-aZhRYO8_-k9G2GycTpvc-2GBsP8VHLUKKfAs2B6sW3q3ymU6M0L-cFXkZ9fHkn9ejs-sqZPhMJxtBPBxoUIUQFTgv4VXTSv914f_YkNw-EjuwbgwXMvpyr06EyfImxHoxsZkFYB-qBYHtaMxTnFsZBr6fn8Ha2JqT1hoP7Z5r5wxDu3GQhKkHw","use":"sig"}"#).unwrap(); 51 | let jwk_id = JwkId { 52 | iss: "https://id.twitch.tv/oauth2".to_string(), 53 | kid: "1".to_string(), 54 | }; 55 | let max_epoch = 10; 56 | (jwk, jwk_id, zklogin_inputs, key, max_epoch) 57 | } 58 | 59 | #[test] 60 | fn zklogin_sign_personal_message() { 61 | let message = PersonalMessage(b"hello world".into()); 62 | 63 | let (jwk, jwk_id, inputs, key, max_epoch) = test_zklogin_material(); 64 | let signature = key.sign(&message.signing_digest()); 65 | let zklogin_authenticator = ZkLoginAuthenticator { 66 | inputs, 67 | max_epoch, 68 | signature, 69 | }; 70 | let mut verifier = ZkloginVerifier::new_dev(); 71 | verifier.jwks_mut().insert(jwk_id, jwk); 72 | 73 | verifier 74 | .verify(&message.signing_digest(), &zklogin_authenticator) 75 | .unwrap(); 76 | 77 | let user_signature = UserSignature::ZkLogin(zklogin_authenticator.into()); 78 | verifier 79 | .verify_personal_message(&message, &user_signature) 80 | .unwrap(); 81 | } 82 | -------------------------------------------------------------------------------- /crates/sui-graphql-client-build/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sui-graphql-client-build" 3 | version = "0.0.4" 4 | authors = ["Stefan Stanciulescu ", "Brandon Williams "] 5 | repository = "https://github.com/mystenlabs/sui-rust-sdk/" 6 | license = "Apache-2.0" 7 | edition = "2021" 8 | readme = "README.md" 9 | description = "Sui GraphQL RPC Client for the Sui Blockchain" 10 | 11 | [dependencies] 12 | cynic-codegen = "3.7.3" 13 | -------------------------------------------------------------------------------- /crates/sui-graphql-client-build/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | This crate provides a function to register a schema to enable building custom queries using cynic derive macros queries. Call 3 | this function in a `build.rs` file in your crate if you need to build custom queries. 4 | 5 | ### Usage 6 | 1. Add this crate as a build dependency in your `Cargo.toml` file. 7 | ```toml 8 | [build-dependencies] 9 | sui-graphql-client-build = { git = "https://github.com/mystenlabs/sui-rust-sdk", package = "sui-graphql-client-build", branch = "master" } 10 | ``` 11 | 12 | 2. Add a `build.rs` file in your crate root directory and call the `register_schema` function in it. 13 | ```rust,ignore 14 | // build.rs file 15 | fn main() { 16 | let schema_name = "MYSCHEMA"; 17 | sui_graphql_client_build::register_schema(schema_name); 18 | } 19 | ``` 20 | 21 | 3. Add the `cynic` and `sui-graphql-client` dependencies in your `Cargo.toml` file. You should have something like this. 22 | ```toml 23 | # Cargo.toml 24 | # ... 25 | [dependencies] 26 | cynic = "3.8.0" 27 | sui-graphql-client = { git = "https://github.com/mystenlabs/sui-rust-sdk", package = "sui-graphql-client", branch = "master" } 28 | 29 | [build-dependencies] 30 | sui-graphql-client-build = { git = "https://github.com/mystenlabs/sui-rust-sdk", package = "sui-graphql-client-build", branch = "master" } 31 | ``` 32 | 33 | 4. If using `cynic`, use the cynic generator to generate the Rust types from the GraphQL schema. \ 34 | Go to and paste the URL to the GraphQL service or manually copy paste the schema. \ 35 | Then you can select the fields in the query you want to have, and the generator will generate the Rust types for you. 36 | 37 | 5. In your Rust code, you can now use the custom query types generated by `cynic`. 38 | 39 | ```rust,ignore 40 | // lib.rs 41 | // Custom query 42 | use cynic::QueryBuilder; 43 | use sui_graphql_client::{query_types::schema, Client}; 44 | 45 | #[derive(cynic::QueryFragment, Debug)] 46 | #[cynic(schema = "MYSCHEMA", graphql_type = "Query")] 47 | pub struct MyQuery { 48 | pub chain_identifier: String, 49 | } 50 | 51 | #[tokio::main] 52 | async fn main() { 53 | let client = Client::new_mainnet(); 54 | let operation = MyQuery::build(()); 55 | let q = client.run_query(&operation).await.unwrap(); 56 | println!("{:?}", q); 57 | } 58 | ``` 59 | 60 | 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: 61 | 62 | 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. 63 | -------------------------------------------------------------------------------- /crates/sui-graphql-client-build/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Mysten Labs, Inc. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #![doc = include_str!("../README.md")] 5 | 6 | /// Register the schema to enable building custom queries using cynic derive macros queries. Call 7 | /// this function in a `build.rs` file in your crate if you need to build custom queries. 8 | /// 9 | /// Examples 10 | /// ```rust,ignore 11 | /// // build.rs file 12 | /// fn main() { 13 | /// let schema_name = "MYSCHEMA" 14 | /// sui_graphql_client_build::register_schema(schema_name); 15 | /// } 16 | /// 17 | /// // Cargo.toml 18 | /// ... 19 | /// [dependencies] 20 | /// cynic = "3.8.0" 21 | /// ... 22 | /// [build-dependencies] 23 | /// sui_graphql_client_build = "VERSION_HERE" 24 | /// 25 | /// // lib.rs 26 | /// // Custom query 27 | /// use cynic::QueryBuilder; 28 | /// use sui_graphql_client::{query_types::schema, Client}; 29 | /// 30 | /// #[derive(cynic::QueryFragment, Debug)] 31 | /// #[cynic(schema = "MYSCHEMA", graphql_type = "Query")] 32 | /// pub struct MyQuery { 33 | /// pub chain_identifier: String, 34 | /// } 35 | /// 36 | /// #[tokio::main] 37 | /// async fn main() { 38 | /// let client = Client::new_mainnet(); 39 | /// let operation = MyQuery::build(()); 40 | /// let q = client.run_query(&operation).await.unwrap(); 41 | /// println!("{:?}", q); 42 | /// } 43 | /// ``` 44 | pub fn register_schema(schema_name: &str) { 45 | let sdl = include_str!("../schema.graphql"); 46 | cynic_codegen::register_schema(schema_name) 47 | .from_sdl(sdl) 48 | .expect("Failed to find GraphQL Schema") 49 | .as_default() 50 | .unwrap(); 51 | } 52 | -------------------------------------------------------------------------------- /crates/sui-graphql-client/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 0.0.1 - 2024-09-25 2 | 3 | Initial release 4 | -------------------------------------------------------------------------------- /crates/sui-graphql-client/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sui-graphql-client" 3 | version = "0.0.4" 4 | authors = ["Stefan Stanciulescu ", "Brandon Williams "] 5 | license = "Apache-2.0" 6 | edition = "2021" 7 | readme = "README.md" 8 | description = "Sui GraphQL RPC Client for the Sui Blockchain" 9 | 10 | [dependencies] 11 | anyhow = "1.0.71" 12 | async-stream = "0.3.3" 13 | async-trait = "0.1.61" 14 | base64ct = { version = "1.6.0", features = ["alloc", "std"] } 15 | bcs = "0.1.4" 16 | chrono = "0.4.26" 17 | cynic = "3.7.3" 18 | futures = "0.3.29" 19 | reqwest = { version = "0.12", default-features = false, features = ["rustls-tls", "json"] } 20 | serde = { version = "1.0.144" } 21 | serde_json = {version = "1.0.95"} 22 | sui-types = { package = "sui-sdk-types", version = "0.0.4", path = "../sui-sdk-types", features = ["serde"] } 23 | tracing = "0.1.37" 24 | thiserror = "2.0.12" 25 | tokio = "1.36.0" 26 | url = "2.5.3" 27 | 28 | [dev-dependencies] 29 | sui-types = { package = "sui-sdk-types", version = "0.0.4", path = "../sui-sdk-types", features = ["serde", "rand", "hash"] } 30 | rand = "0.8.5" 31 | tokio = { version = "1.40.0", features = ["full"] } 32 | 33 | [build-dependencies] 34 | sui-graphql-client-build = { version = "0.0.4", path = "../sui-graphql-client-build" } 35 | -------------------------------------------------------------------------------- /crates/sui-graphql-client/build.rs: -------------------------------------------------------------------------------- 1 | /// Register Sui RPC schema for creating structs for queries 2 | fn main() { 3 | sui_graphql_client_build::register_schema("rpc"); 4 | } 5 | -------------------------------------------------------------------------------- /crates/sui-graphql-client/examples/custom_query.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Mysten Labs, Inc. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use anyhow::Result; 5 | use cynic::QueryBuilder; 6 | 7 | use sui_graphql_client::query_types::schema; 8 | use sui_graphql_client::query_types::BigInt; 9 | use sui_graphql_client::Client; 10 | 11 | // The data returned by the custom query. 12 | #[derive(cynic::QueryFragment, Debug)] 13 | #[cynic(schema = "rpc", graphql_type = "Epoch")] 14 | pub struct EpochData { 15 | pub epoch_id: u64, 16 | pub reference_gas_price: Option, 17 | pub total_gas_fees: Option, 18 | pub total_checkpoints: Option, 19 | pub total_transactions: Option, 20 | } 21 | 22 | // The variables to pass to the custom query. 23 | // If an epoch id is passed, then the query will return the data for that epoch. 24 | // Otherwise, the query will return the data for the last known epoch. 25 | #[derive(cynic::QueryVariables, Debug)] 26 | pub struct CustomVariables { 27 | pub id: Option, 28 | } 29 | 30 | // The custom query. Note that the variables need to be explicitly declared. 31 | #[derive(cynic::QueryFragment, Debug)] 32 | #[cynic(schema = "rpc", graphql_type = "Query", variables = "CustomVariables")] 33 | pub struct CustomQuery { 34 | #[arguments(id: $id)] 35 | pub epoch: Option, 36 | } 37 | 38 | // Custom query with no variables. 39 | #[derive(cynic::QueryFragment, Debug)] 40 | #[cynic(schema = "rpc", graphql_type = "Query")] 41 | pub struct ChainIdQuery { 42 | chain_identifier: String, 43 | } 44 | 45 | #[tokio::main] 46 | async fn main() -> Result<()> { 47 | let client = Client::new_devnet(); 48 | 49 | // Query the data for the last known epoch. Note that id variable is None, so last epoch data 50 | // will be returned. 51 | let operation = CustomQuery::build(CustomVariables { id: None }); 52 | let response = client 53 | .run_query::(&operation) 54 | .await; 55 | println!("{:?}", response); 56 | 57 | // Query the data for epoch 1. 58 | let epoch_id = 1; 59 | let operation = CustomQuery::build(CustomVariables { id: Some(epoch_id) }); 60 | let response = client 61 | .run_query::(&operation) 62 | .await; 63 | println!("{:?}", response); 64 | 65 | // When the query has no variables, just pass () as the type argument 66 | let operation = ChainIdQuery::build(()); 67 | let response = client.run_query::(&operation).await?; 68 | if let Some(chain_id) = response.data { 69 | println!("Chain ID: {}", chain_id.chain_identifier); 70 | } 71 | 72 | Ok(()) 73 | } 74 | -------------------------------------------------------------------------------- /crates/sui-graphql-client/queries/coin_metadata.graphql: -------------------------------------------------------------------------------- 1 | query CoinMetadataQuery($coinType: String!) { 2 | coinMetadata(coinType: $coinType) { 3 | decimals 4 | description 5 | iconUrl 6 | name 7 | symbol 8 | supply 9 | version 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /crates/sui-graphql-client/queries/custom_query.graphql: -------------------------------------------------------------------------------- 1 | query CustomQuery($id: UInt53) { 2 | epoch(id: $id) { 3 | epochId 4 | referenceGasPrice 5 | totalGasFees 6 | totalCheckpoints 7 | totalTransactions 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /crates/sui-graphql-client/queries/epoch_total_checkpoints.graphql: -------------------------------------------------------------------------------- 1 | query EpochTotalCheckpoints($id: UInt53){ 2 | epoch(id: $id) { 3 | totalCheckpoints 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /crates/sui-graphql-client/queries/object.graphql: -------------------------------------------------------------------------------- 1 | query ObjectQuery($address: SuiAddress!, $version: UInt53) { 2 | object(address: $address, version: $version) { 3 | bcs 4 | } 5 | } 6 | 7 | -------------------------------------------------------------------------------- /crates/sui-graphql-client/queries/objects.graphql: -------------------------------------------------------------------------------- 1 | query ObjectsQuery($after: String, $before: String, $filter: ObjectFilter, $first: Int, $last: Int) { 2 | objects( 3 | after: $after, 4 | before: $before, 5 | filter: $filter, 6 | first: $first, 7 | last: $last 8 | ) { 9 | pageInfo { 10 | endCursor 11 | hasNextPage 12 | hasPreviousPage 13 | startCursor 14 | } 15 | nodes { 16 | bcs 17 | } 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /crates/sui-graphql-client/src/error.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Mysten Labs, Inc. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use std::num::ParseIntError; 5 | use std::num::TryFromIntError; 6 | 7 | use cynic::GraphQlError; 8 | 9 | use sui_types::AddressParseError; 10 | use sui_types::DigestParseError; 11 | use sui_types::TypeParseError; 12 | 13 | type BoxError = Box; 14 | 15 | pub type Result = std::result::Result; 16 | 17 | /// General error type for the client. It is used to wrap all the possible errors that can occur. 18 | #[derive(Debug)] 19 | pub struct Error { 20 | inner: Box, 21 | } 22 | 23 | /// Error type for the client. It is split into multiple fields to allow for more granular error 24 | /// handling. The `source` field is used to store the original error. 25 | #[derive(Debug)] 26 | struct InnerError { 27 | /// Error kind. 28 | kind: Kind, 29 | /// Errors returned by the GraphQL server. 30 | query_errors: Option>, 31 | /// The original error. 32 | source: Option, 33 | } 34 | 35 | #[derive(Debug)] 36 | #[non_exhaustive] 37 | pub enum Kind { 38 | Deserialization, 39 | Parse, 40 | Query, 41 | Other, 42 | } 43 | 44 | impl std::error::Error for Error { 45 | fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { 46 | self.inner.source.as_deref().map(|e| e as _) 47 | } 48 | } 49 | 50 | impl Error { 51 | // Public accessors 52 | 53 | /// Returns the kind of error. 54 | pub fn kind(&self) -> &Kind { 55 | &self.inner.kind 56 | } 57 | 58 | /// Original GraphQL query errors. 59 | pub fn graphql_errors(&self) -> Option<&[GraphQlError]> { 60 | self.inner.query_errors.as_deref() 61 | } 62 | 63 | // Private constructors 64 | 65 | /// Convert the given error into a generic error. 66 | pub fn from_error>(kind: Kind, error: E) -> Self { 67 | Self { 68 | inner: Box::new(InnerError { 69 | kind, 70 | source: Some(error.into()), 71 | query_errors: None, 72 | }), 73 | } 74 | } 75 | 76 | /// Special constructor for queries that expect to return data but it's none. 77 | pub fn empty_response_error() -> Self { 78 | Self { 79 | inner: Box::new(InnerError { 80 | kind: Kind::Query, 81 | source: Some("Expected a non-empty response data from query".into()), 82 | query_errors: None, 83 | }), 84 | } 85 | } 86 | 87 | /// Create a Query kind of error with the original graphql errors. 88 | pub fn graphql_error(errors: Vec) -> Self { 89 | Self { 90 | inner: Box::new(InnerError { 91 | kind: Kind::Query, 92 | source: None, 93 | query_errors: Some(errors), 94 | }), 95 | } 96 | } 97 | } 98 | 99 | impl std::fmt::Display for Kind { 100 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 101 | match self { 102 | Kind::Deserialization => write!(f, "Deserialization error:"), 103 | Kind::Parse => write!(f, "Parse error:"), 104 | Kind::Query => write!(f, "Query error:"), 105 | Kind::Other => write!(f, "Error:"), 106 | } 107 | } 108 | } 109 | 110 | impl std::fmt::Display for Error { 111 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 112 | write!(f, "{}", self.inner.kind)?; 113 | 114 | if let Some(source) = &self.inner.source { 115 | writeln!(f, " {}", source)?; 116 | } 117 | Ok(()) 118 | } 119 | } 120 | 121 | impl From for Error { 122 | fn from(error: bcs::Error) -> Self { 123 | Self::from_error(Kind::Deserialization, error) 124 | } 125 | } 126 | 127 | impl From for Error { 128 | fn from(error: reqwest::Error) -> Self { 129 | Self::from_error(Kind::Other, error) 130 | } 131 | } 132 | 133 | impl From for Error { 134 | fn from(error: url::ParseError) -> Self { 135 | Self::from_error(Kind::Parse, error) 136 | } 137 | } 138 | 139 | impl From for Error { 140 | fn from(error: ParseIntError) -> Self { 141 | Self::from_error(Kind::Parse, error) 142 | } 143 | } 144 | 145 | impl From for Error { 146 | fn from(error: AddressParseError) -> Self { 147 | Self::from_error(Kind::Parse, error) 148 | } 149 | } 150 | 151 | impl From for Error { 152 | fn from(error: base64ct::Error) -> Self { 153 | Self::from_error(Kind::Parse, error) 154 | } 155 | } 156 | 157 | impl From for Error { 158 | fn from(error: chrono::ParseError) -> Self { 159 | Self::from_error(Kind::Parse, error) 160 | } 161 | } 162 | 163 | impl From for Error { 164 | fn from(error: DigestParseError) -> Self { 165 | Self::from_error(Kind::Parse, error) 166 | } 167 | } 168 | 169 | impl From for Error { 170 | fn from(error: TryFromIntError) -> Self { 171 | Self::from_error(Kind::Parse, error) 172 | } 173 | } 174 | 175 | impl From for Error { 176 | fn from(error: TypeParseError) -> Self { 177 | Self::from_error(Kind::Parse, error) 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /crates/sui-graphql-client/src/faucet.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Mysten Labs, Inc. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use sui_types::Address; 5 | use sui_types::TransactionDigest; 6 | 7 | use anyhow::bail; 8 | use reqwest::StatusCode; 9 | use reqwest::Url; 10 | use serde::Deserialize; 11 | use serde::Serialize; 12 | use serde_json::json; 13 | use sui_types::ObjectId; 14 | use thiserror::Error; 15 | use tracing::error as tracing_error; 16 | use tracing::info; 17 | 18 | pub const FAUCET_DEVNET_HOST: &str = "https://faucet.devnet.sui.io"; 19 | pub const FAUCET_TESTNET_HOST: &str = "https://faucet.testnet.sui.io"; 20 | pub const FAUCET_LOCAL_HOST: &str = "http://localhost:9123"; 21 | 22 | pub const FAUCET_REQUEST_PATH: &str = "v2/gas"; 23 | 24 | pub struct FaucetClient { 25 | faucet_url: Url, 26 | inner: reqwest::Client, 27 | } 28 | 29 | #[derive(Serialize, Deserialize, Debug)] 30 | pub enum RequestStatus { 31 | Success, 32 | Failure(FaucetError), 33 | } 34 | 35 | #[derive(Serialize, Deserialize, Debug)] 36 | pub struct FaucetResponse { 37 | pub status: RequestStatus, 38 | pub coins_sent: Option>, 39 | } 40 | 41 | #[derive(Serialize, Deserialize, Debug, Clone)] 42 | #[serde(rename_all = "camelCase")] 43 | pub struct CoinInfo { 44 | pub amount: u64, 45 | pub id: ObjectId, 46 | pub transfer_tx_digest: TransactionDigest, 47 | } 48 | 49 | #[derive(Serialize, Deserialize, Error, Debug, PartialEq, Eq)] 50 | pub enum FaucetError { 51 | #[error("Missing X-Turnstile-Token header. For testnet tokens, please use the Web UI: https://faucet.sui.io")] 52 | MissingTurnstileTokenHeader, 53 | 54 | #[error("Request limit exceeded. {0}")] 55 | TooManyRequests(String), 56 | 57 | #[error("Internal error: {0}")] 58 | Internal(String), 59 | 60 | #[error("Invalid user agent: {0}")] 61 | InvalidUserAgent(String), 62 | } 63 | 64 | impl FaucetClient { 65 | /// Construct a new `FaucetClient` with the given faucet service URL. This [`FaucetClient`] 66 | /// expects that the service provides this endpoint: /v2/gas. As such, do not 67 | /// provide the request endpoint, just the top level service endpoint. 68 | pub fn new(faucet_url: &str) -> Self { 69 | let inner = reqwest::Client::new(); 70 | let faucet_url = Url::parse(faucet_url).expect("Invalid faucet URL"); 71 | FaucetClient { faucet_url, inner } 72 | } 73 | 74 | /// Set to local faucet. 75 | pub fn local() -> Self { 76 | Self { 77 | faucet_url: Url::parse(FAUCET_LOCAL_HOST).expect("Invalid faucet URL"), 78 | inner: reqwest::Client::new(), 79 | } 80 | } 81 | 82 | /// Set to devnet faucet. 83 | pub fn devnet() -> Self { 84 | Self { 85 | faucet_url: Url::parse(FAUCET_DEVNET_HOST).expect("Invalid faucet URL"), 86 | inner: reqwest::Client::new(), 87 | } 88 | } 89 | 90 | /// Set to testnet faucet. 91 | pub fn testnet() -> Self { 92 | Self { 93 | faucet_url: Url::parse(FAUCET_TESTNET_HOST).expect("Invalid faucet URL"), 94 | inner: reqwest::Client::new(), 95 | } 96 | } 97 | 98 | /// Make a faucet request. It returns a [`FaucetResponse`] type, which upon success contains 99 | /// the information about the coin sent. 100 | pub async fn request(&self, address: Address) -> Result { 101 | let address = address.to_string(); 102 | let json_body = json![{ 103 | "FixedAmountRequest": { 104 | "recipient": &address 105 | } 106 | }]; 107 | 108 | let url = format!("{}{}", self.faucet_url, FAUCET_REQUEST_PATH); 109 | info!( 110 | "Requesting gas from faucet for address {} : {}", 111 | address, url 112 | ); 113 | let resp = self 114 | .inner 115 | .post(url) 116 | .header("content-type", "application/json") 117 | .json(&json_body) 118 | .send() 119 | .await?; 120 | match resp.status() { 121 | StatusCode::ACCEPTED | StatusCode::CREATED | StatusCode::OK => { 122 | let faucet_resp: FaucetResponse = resp.json().await?; 123 | 124 | match faucet_resp.status { 125 | RequestStatus::Success => { 126 | info!("Faucet request was successful: {:?}", faucet_resp); 127 | Ok(faucet_resp) 128 | } 129 | RequestStatus::Failure(err) => { 130 | tracing_error!("Faucet request was unsuccessful: {:?}", err); 131 | bail!("Faucet request was unsuccessful: {:?}", err) 132 | } 133 | } 134 | } 135 | StatusCode::TOO_MANY_REQUESTS => { 136 | tracing_error!("Faucet service received too many requests from this IP address."); 137 | bail!("Faucet service received too many requests from this IP address. Please try again after 60 minutes."); 138 | } 139 | StatusCode::SERVICE_UNAVAILABLE => { 140 | tracing_error!("Faucet service is currently overloaded or unavailable."); 141 | bail!("Faucet service is currently overloaded or unavailable. Please try again later."); 142 | } 143 | status_code => { 144 | tracing_error!("Faucet request was unsuccessful: {status_code}"); 145 | bail!("Faucet request was unsuccessful: {status_code}"); 146 | } 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /crates/sui-graphql-client/src/query_types/active_validators.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Mysten Labs, Inc. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use crate::query_types::schema; 5 | use crate::query_types::Address; 6 | use crate::query_types::Base64; 7 | use crate::query_types::BigInt; 8 | use crate::query_types::GQLAddress; 9 | use crate::query_types::MoveObject; 10 | use crate::query_types::PageInfo; 11 | 12 | #[derive(cynic::QueryFragment, Debug)] 13 | #[cynic( 14 | schema = "rpc", 15 | graphql_type = "Query", 16 | variables = "ActiveValidatorsArgs" 17 | )] 18 | pub struct ActiveValidatorsQuery { 19 | #[arguments(id: $id)] 20 | pub epoch: Option, 21 | } 22 | 23 | #[derive(cynic::QueryVariables, Debug)] 24 | pub struct ActiveValidatorsArgs<'a> { 25 | pub id: Option, 26 | pub after: Option<&'a str>, 27 | pub before: Option<&'a str>, 28 | pub first: Option, 29 | pub last: Option, 30 | } 31 | 32 | #[derive(cynic::QueryFragment, Debug)] 33 | #[cynic( 34 | schema = "rpc", 35 | graphql_type = "Epoch", 36 | variables = "ActiveValidatorsArgs" 37 | )] 38 | pub struct EpochValidator { 39 | pub validator_set: Option, 40 | } 41 | 42 | #[derive(cynic::QueryFragment, Debug)] 43 | #[cynic( 44 | schema = "rpc", 45 | graphql_type = "ValidatorSet", 46 | variables = "ActiveValidatorsArgs" 47 | )] 48 | pub struct ValidatorSet { 49 | #[arguments(after: $after, before: $before, first: $first, last: $last)] 50 | pub active_validators: ValidatorConnection, 51 | } 52 | 53 | #[derive(cynic::QueryFragment, Debug)] 54 | #[cynic(schema = "rpc", graphql_type = "ValidatorConnection")] 55 | pub struct ValidatorConnection { 56 | pub page_info: PageInfo, 57 | pub nodes: Vec, 58 | } 59 | 60 | /// Represents a validator in the system. 61 | #[derive(cynic::QueryFragment, Debug)] 62 | #[cynic(schema = "rpc", graphql_type = "Validator")] 63 | pub struct Validator { 64 | /// The APY of this validator in basis points. 65 | /// To get the APY in percentage, divide by 100. 66 | pub apy: Option, 67 | /// The validator's address. 68 | pub address: GQLAddress, 69 | /// The fee charged by the validator for staking services. 70 | pub commission_rate: Option, 71 | /// Validator's credentials. 72 | pub credentials: Option, 73 | /// Validator's description. 74 | pub description: Option, 75 | /// Number of exchange rates in the table. 76 | pub exchange_rates_size: Option, 77 | /// The reference gas price for this epoch. 78 | pub gas_price: Option, 79 | /// Validator's name. 80 | pub name: Option, 81 | /// Validator's url containing their custom image. 82 | pub image_url: Option, 83 | /// The proposed next epoch fee for the validator's staking services. 84 | pub next_epoch_commission_rate: Option, 85 | /// Validator's credentials for the next epoch. 86 | pub next_epoch_credentials: Option, 87 | /// The validator's gas price quote for the next epoch. 88 | pub next_epoch_gas_price: Option, 89 | /// The total number of SUI tokens in this pool plus 90 | /// the pending stake amount for this epoch. 91 | pub next_epoch_stake: Option, 92 | /// The validator's current valid `Cap` object. Validators can delegate 93 | /// the operation ability to another address. The address holding this `Cap` object 94 | /// can then update the reference gas price and tallying rule on behalf of the validator. 95 | pub operation_cap: Option, 96 | /// Pending pool token withdrawn during the current epoch, emptied at epoch boundaries. 97 | pub pending_pool_token_withdraw: Option, 98 | /// Pending stake amount for this epoch. 99 | pub pending_stake: Option, 100 | /// Pending stake withdrawn during the current epoch, emptied at epoch boundaries. 101 | pub pending_total_sui_withdraw: Option, 102 | /// Total number of pool tokens issued by the pool. 103 | pub pool_token_balance: Option, 104 | /// Validator's homepage URL. 105 | pub project_url: Option, 106 | /// The epoch stake rewards will be added here at the end of each epoch. 107 | pub rewards_pool: Option, 108 | /// The epoch at which this pool became active. 109 | pub staking_pool_activation_epoch: Option, 110 | /// The ID of this validator's `0x3::staking_pool::StakingPool`. 111 | pub staking_pool_id: Address, 112 | /// The total number of SUI tokens in this pool. 113 | pub staking_pool_sui_balance: Option, 114 | /// The voting power of this validator in basis points (e.g., 100 = 1% voting power). 115 | pub voting_power: Option, 116 | } 117 | 118 | /// The credentials related fields associated with a validator. 119 | #[derive(cynic::QueryFragment, Debug)] 120 | #[cynic(schema = "rpc", graphql_type = "ValidatorCredentials")] 121 | #[allow(non_snake_case)] 122 | pub struct ValidatorCredentials { 123 | pub protocol_pub_key: Option, 124 | pub network_pub_key: Option, 125 | pub worker_pub_key: Option, 126 | pub proof_of_possession: Option, 127 | pub net_address: Option, 128 | // TODO need to fix this in the graphQL schema ugh. p2P -> p2p 129 | // pub p2P_address: Option, 130 | pub primary_address: Option, 131 | pub worker_address: Option, 132 | } 133 | -------------------------------------------------------------------------------- /crates/sui-graphql-client/src/query_types/balance.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Mysten Labs, Inc. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use crate::query_types::schema; 5 | use crate::query_types::BigInt; 6 | use crate::Address; 7 | 8 | #[derive(cynic::QueryFragment, Debug)] 9 | #[cynic(schema = "rpc", graphql_type = "Query", variables = "BalanceArgs")] 10 | pub struct BalanceQuery { 11 | #[arguments(address: $address)] 12 | pub owner: Option, 13 | } 14 | 15 | #[derive(cynic::QueryFragment, Debug)] 16 | #[cynic(schema = "rpc", graphql_type = "Owner", variables = "BalanceArgs")] 17 | pub struct Owner { 18 | #[arguments(type: $coin_type)] 19 | pub balance: Option, 20 | } 21 | 22 | #[derive(cynic::QueryFragment, Debug)] 23 | #[cynic(schema = "rpc", graphql_type = "Balance")] 24 | pub struct Balance { 25 | pub total_balance: Option, 26 | } 27 | 28 | #[derive(cynic::QueryVariables, Debug)] 29 | pub struct BalanceArgs { 30 | pub address: Address, 31 | pub coin_type: Option, 32 | } 33 | -------------------------------------------------------------------------------- /crates/sui-graphql-client/src/query_types/chain.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Mysten Labs, Inc. 2 | // SPDX-License-Identifier: Apache-2.0 3 | use crate::query_types::schema; 4 | 5 | // =========================================================================== 6 | // Chain Identifier Query 7 | // =========================================================================== 8 | 9 | #[derive(cynic::QueryFragment, Debug)] 10 | #[cynic(schema = "rpc", graphql_type = "Query")] 11 | pub struct ChainIdentifierQuery { 12 | pub chain_identifier: String, 13 | } 14 | -------------------------------------------------------------------------------- /crates/sui-graphql-client/src/query_types/checkpoint.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Mysten Labs, Inc. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use base64ct::Encoding; 5 | use sui_types::CheckpointSummary; 6 | 7 | use crate::error; 8 | use crate::error::Error; 9 | use crate::error::Kind; 10 | use crate::query_types::schema; 11 | use crate::query_types::Base64; 12 | use crate::query_types::PageInfo; 13 | 14 | // =========================================================================== 15 | // Checkpoint Queries 16 | // =========================================================================== 17 | 18 | #[derive(cynic::QueryFragment, Debug)] 19 | #[cynic(schema = "rpc", graphql_type = "Query", variables = "CheckpointArgs")] 20 | pub struct CheckpointQuery { 21 | #[arguments(id: $id)] 22 | pub checkpoint: Option, 23 | } 24 | 25 | #[derive(cynic::QueryFragment, Debug)] 26 | #[cynic(schema = "rpc", graphql_type = "Query", variables = "CheckpointArgs")] 27 | pub struct CheckpointTotalTxQuery { 28 | #[arguments(id: $id)] 29 | pub checkpoint: Option, 30 | } 31 | 32 | #[derive(cynic::QueryFragment, Debug)] 33 | #[cynic(schema = "rpc", graphql_type = "Checkpoint")] 34 | pub struct CheckpointTotalTx { 35 | pub network_total_transactions: Option, 36 | } 37 | 38 | #[derive(cynic::QueryFragment, Debug)] 39 | #[cynic(schema = "rpc", graphql_type = "Query", variables = "CheckpointsArgs")] 40 | pub struct CheckpointsQuery { 41 | pub checkpoints: CheckpointConnection, 42 | } 43 | 44 | #[derive(cynic::QueryFragment, Debug)] 45 | #[cynic(schema = "rpc", graphql_type = "CheckpointConnection")] 46 | pub struct CheckpointConnection { 47 | pub nodes: Vec, 48 | pub page_info: PageInfo, 49 | } 50 | 51 | #[derive(cynic::QueryVariables, Debug)] 52 | pub struct CheckpointsArgs<'a> { 53 | pub first: Option, 54 | pub after: Option<&'a str>, 55 | pub last: Option, 56 | pub before: Option<&'a str>, 57 | } 58 | 59 | // =========================================================================== 60 | // Checkpoint Query Args 61 | // =========================================================================== 62 | 63 | #[derive(cynic::QueryVariables, Debug)] 64 | pub struct CheckpointArgs { 65 | pub id: CheckpointId, 66 | } 67 | 68 | #[derive(cynic::InputObject, Debug)] 69 | #[cynic(schema = "rpc", graphql_type = "CheckpointId")] 70 | pub struct CheckpointId { 71 | pub digest: Option, 72 | pub sequence_number: Option, 73 | } 74 | // =========================================================================== 75 | // Checkpoint Types 76 | // =========================================================================== 77 | 78 | #[derive(cynic::QueryFragment, Debug)] 79 | #[cynic(schema = "rpc", graphql_type = "Checkpoint")] 80 | pub struct Checkpoint { 81 | pub bcs: Option, 82 | } 83 | 84 | impl TryInto for Checkpoint { 85 | type Error = error::Error; 86 | 87 | fn try_into(self) -> Result { 88 | let checkpoint = self 89 | .bcs 90 | .map(|x| base64ct::Base64::decode_vec(&x.0)) 91 | .transpose()? 92 | .map(|bcs| { 93 | bcs::from_bytes::(&bcs).map_err(|e| { 94 | Error::from_error( 95 | Kind::Other, 96 | format!("Failed to deserialize checkpoint summary: {}", e), 97 | ) 98 | }) 99 | }) 100 | .transpose()?; 101 | checkpoint.ok_or_else(|| Error::from_error(Kind::Other, "Checkpoint summary is missing")) 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /crates/sui-graphql-client/src/query_types/coin.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Mysten Labs, Inc. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // =========================================================================== 5 | // Coin(s) Queries 6 | // =========================================================================== 7 | 8 | #[derive(cynic::QueryFragment, Debug)] 9 | #[cynic(schema = "rpc", graphql_type = "Query", variables = "CoinMetadataArgs")] 10 | pub struct CoinMetadataQuery { 11 | #[arguments(coinType: $coin_type)] 12 | pub coin_metadata: Option, 13 | } 14 | 15 | // =========================================================================== 16 | // Coin(s) Query Args 17 | // =========================================================================== 18 | 19 | #[derive(cynic::QueryVariables, Debug)] 20 | pub struct CoinMetadataArgs<'a> { 21 | pub coin_type: &'a str, 22 | } 23 | 24 | // =========================================================================== 25 | // Types 26 | // =========================================================================== 27 | 28 | use crate::query_types::schema; 29 | use crate::query_types::BigInt; 30 | 31 | /// The coin metadata associated with the given coin type. 32 | #[derive(cynic::QueryFragment, Debug)] 33 | #[cynic(schema = "rpc", graphql_type = "CoinMetadata")] 34 | pub struct CoinMetadata { 35 | /// The number of decimal places used to represent the token. 36 | pub decimals: Option, 37 | /// Optional description of the token, provided by the creator of the token. 38 | pub description: Option, 39 | /// Icon URL of the coin. 40 | pub icon_url: Option, 41 | /// Full, official name of the token. 42 | pub name: Option, 43 | /// The token's identifying abbreviation. 44 | pub symbol: Option, 45 | /// The overall quantity of tokens that will be issued. 46 | pub supply: Option, 47 | /// Version of the token. 48 | pub version: u64, 49 | } 50 | -------------------------------------------------------------------------------- /crates/sui-graphql-client/src/query_types/dry_run.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Mysten Labs, Inc. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use sui_types::ObjectReference; 5 | 6 | use crate::query_types::schema; 7 | use crate::query_types::Address; 8 | 9 | use super::transaction::TxBlockEffects; 10 | 11 | #[derive(cynic::QueryFragment, Debug)] 12 | #[cynic(schema = "rpc", graphql_type = "Query", variables = "DryRunArgs")] 13 | pub struct DryRunQuery { 14 | #[arguments(txBytes: $tx_bytes, skipChecks: $skip_checks, txMeta: $tx_meta)] 15 | pub dry_run_transaction_block: DryRunResult, 16 | } 17 | 18 | #[derive(cynic::QueryFragment, Debug)] 19 | #[cynic(schema = "rpc", graphql_type = "DryRunResult")] 20 | pub struct DryRunResult { 21 | pub error: Option, 22 | pub transaction: Option, 23 | } 24 | 25 | #[derive(cynic::QueryVariables, Debug)] 26 | pub struct DryRunArgs { 27 | pub tx_bytes: String, 28 | pub skip_checks: bool, 29 | pub tx_meta: Option, 30 | } 31 | 32 | #[derive(cynic::InputObject, Debug)] 33 | #[cynic(schema = "rpc", graphql_type = "TransactionMetadata")] 34 | pub struct TransactionMetadata { 35 | pub gas_budget: Option, 36 | pub gas_objects: Option>, 37 | pub gas_price: Option, 38 | pub gas_sponsor: Option
, 39 | pub sender: Option
, 40 | } 41 | 42 | #[derive(cynic::InputObject, Debug)] 43 | #[cynic(schema = "rpc", graphql_type = "ObjectRef")] 44 | pub struct ObjectRef { 45 | pub address: Address, 46 | pub digest: String, 47 | pub version: u64, 48 | } 49 | 50 | impl From for ObjectRef { 51 | fn from(value: ObjectReference) -> Self { 52 | let address: Address = (*value.object_id()).into(); 53 | ObjectRef { 54 | address, 55 | version: value.version(), 56 | digest: value.digest().to_string(), 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /crates/sui-graphql-client/src/query_types/dynamic_fields.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Mysten Labs, Inc. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use std::str::FromStr; 5 | 6 | use base64ct::Encoding; 7 | use sui_types::TypeTag; 8 | 9 | use crate::error; 10 | use crate::query_types::schema; 11 | use crate::query_types::Address; 12 | use crate::query_types::Base64; 13 | use crate::query_types::JsonValue; 14 | use crate::query_types::MoveObjectContents; 15 | use crate::query_types::MoveValue; 16 | use crate::query_types::PageInfo; 17 | use crate::DynamicFieldOutput; 18 | 19 | #[derive(cynic::QueryFragment, Debug)] 20 | #[cynic( 21 | schema = "rpc", 22 | graphql_type = "Query", 23 | variables = "DynamicFieldConnectionArgs" 24 | )] 25 | pub struct DynamicFieldsOwnerQuery { 26 | #[arguments(address: $address)] 27 | pub owner: Option, 28 | } 29 | #[derive(cynic::QueryFragment, Debug)] 30 | #[cynic( 31 | schema = "rpc", 32 | graphql_type = "Owner", 33 | variables = "DynamicFieldConnectionArgs" 34 | )] 35 | pub struct ObjectOwner { 36 | #[arguments(after: $after, before: $before, first: $first, last: $last)] 37 | pub dynamic_fields: DynamicFieldConnection, 38 | } 39 | 40 | #[derive(cynic::QueryFragment, Debug)] 41 | #[cynic(schema = "rpc", graphql_type = "Query", variables = "DynamicFieldArgs")] 42 | pub struct DynamicFieldQuery { 43 | #[arguments(address: $address)] 44 | pub owner: Option, 45 | } 46 | 47 | #[derive(cynic::QueryFragment, Debug)] 48 | #[cynic(schema = "rpc", graphql_type = "Owner", variables = "DynamicFieldArgs")] 49 | pub struct OwnerField { 50 | #[arguments(name: $name)] 51 | pub dynamic_field: Option, 52 | } 53 | 54 | #[derive(cynic::QueryVariables, Debug)] 55 | pub struct DynamicFieldArgs { 56 | pub address: Address, 57 | pub name: DynamicFieldName, 58 | } 59 | 60 | #[derive(cynic::QueryVariables, Debug)] 61 | pub struct DynamicFieldsQueryArgs { 62 | pub address: Address, 63 | } 64 | 65 | #[derive(cynic::QueryVariables, Debug)] 66 | pub struct DynamicFieldConnectionArgs<'a> { 67 | pub address: Address, 68 | pub after: Option<&'a str>, 69 | pub before: Option<&'a str>, 70 | pub first: Option, 71 | pub last: Option, 72 | } 73 | 74 | #[derive(cynic::QueryFragment, Debug)] 75 | #[cynic(schema = "rpc", graphql_type = "DynamicFieldConnection")] 76 | pub struct DynamicFieldConnection { 77 | pub nodes: Vec, 78 | pub page_info: PageInfo, 79 | } 80 | 81 | #[derive(cynic::QueryFragment, Debug)] 82 | #[cynic(schema = "rpc", graphql_type = "DynamicField")] 83 | pub struct DynamicField { 84 | pub value: Option, 85 | pub name: Option, 86 | } 87 | 88 | #[derive(cynic::InlineFragments, Debug)] 89 | #[cynic(schema = "rpc", graphql_type = "DynamicFieldValue")] 90 | pub enum DynamicFieldValue { 91 | MoveObject(MoveObjectContents), 92 | MoveValue(MoveValue), 93 | #[cynic(fallback)] 94 | Unknown, 95 | } 96 | 97 | #[derive(cynic::InputObject, Debug)] 98 | #[cynic(schema = "rpc", graphql_type = "DynamicFieldName")] 99 | pub struct DynamicFieldName { 100 | #[cynic(rename = "type")] 101 | pub type_: String, 102 | pub bcs: Base64, 103 | } 104 | 105 | #[derive(cynic::QueryFragment, Debug)] 106 | #[cynic(schema = "rpc", graphql_type = "Owner", variables = "DynamicFieldArgs")] 107 | pub struct DynamicObjectField { 108 | #[arguments(name: $name)] 109 | pub dynamic_object_field: Option, 110 | } 111 | #[derive(cynic::QueryFragment, Debug)] 112 | #[cynic(schema = "rpc", graphql_type = "Query", variables = "DynamicFieldArgs")] 113 | pub struct DynamicObjectFieldQuery { 114 | #[arguments(address: $address)] 115 | pub owner: Option, 116 | } 117 | 118 | impl DynamicFieldValue { 119 | /// Returns the JSON representation of the field value, if available. 120 | pub fn field_value_json(&self) -> Option { 121 | match self { 122 | DynamicFieldValue::MoveObject(mo) => { 123 | mo.contents.as_ref().and_then(|mv| mv.json.clone()) 124 | } 125 | DynamicFieldValue::MoveValue(mv) => mv.json.clone(), 126 | _ => None, 127 | } 128 | } 129 | 130 | /// Return the typename and bcs of this dynamic field value. 131 | pub fn type_bcs(&self) -> Option<(TypeTag, Vec)> { 132 | match self { 133 | DynamicFieldValue::MoveObject(mo) => mo.contents.as_ref().map(|o| { 134 | ( 135 | TypeTag::from_str(&o.type_.repr.clone()).expect("Invalid TypeTag"), 136 | base64ct::Base64::decode_vec(&o.bcs.0).expect("Invalid Base64"), 137 | ) 138 | }), 139 | DynamicFieldValue::MoveValue(mv) => Some(( 140 | TypeTag::from_str(&mv.type_.repr.clone()).expect("Invalid TypeTag"), 141 | base64ct::Base64::decode_vec(&mv.bcs.0).expect("Invalid Base64"), 142 | )), 143 | _ => None, 144 | } 145 | } 146 | } 147 | 148 | impl DynamicField { 149 | /// Returns the JSON representation of the field value, if available. 150 | pub fn field_value_json(&self) -> Option { 151 | self.value.as_ref().and_then(|v| v.field_value_json()) 152 | } 153 | } 154 | 155 | impl TryFrom for DynamicFieldOutput { 156 | type Error = error::Error; 157 | 158 | fn try_from(val: DynamicField) -> Result { 159 | let typetag = TypeTag::from_str( 160 | val.name 161 | .as_ref() 162 | .expect("There should be a name in this dynamic field") 163 | .type_ 164 | .repr 165 | .as_str(), 166 | )?; 167 | Ok(DynamicFieldOutput { 168 | name: crate::DynamicFieldName { 169 | type_: typetag, 170 | bcs: base64ct::Base64::decode_vec(val.name.as_ref().unwrap().bcs.0.as_ref()) 171 | .unwrap(), 172 | json: val.name.as_ref().unwrap().json.clone(), 173 | }, 174 | value_as_json: val.field_value_json(), 175 | value: val.value.and_then(|x| x.type_bcs()), 176 | }) 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /crates/sui-graphql-client/src/query_types/epoch.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Mysten Labs, Inc. 2 | // SPDX-License-Identifier: Apache-2.0 3 | // 4 | use super::PageInfo; 5 | use crate::query_types::schema; 6 | use crate::query_types::Address; 7 | use crate::query_types::BigInt; 8 | use crate::query_types::DateTime; 9 | use crate::query_types::ProtocolConfigs; 10 | 11 | // =========================================================================== 12 | // Epoch Queries 13 | // =========================================================================== 14 | #[derive(cynic::QueryFragment, Debug)] 15 | #[cynic(schema = "rpc", graphql_type = "Query", variables = "EpochArgs")] 16 | pub struct EpochQuery { 17 | #[arguments(id: $id)] 18 | pub epoch: Option, 19 | } 20 | 21 | #[derive(cynic::QueryFragment, Debug)] 22 | #[cynic(schema = "rpc", graphql_type = "Query", variables = "EpochsArgs")] 23 | pub struct EpochsQuery { 24 | #[arguments(first: $first, after: $after, last: $last, before: $before)] 25 | pub epochs: EpochConnection, 26 | } 27 | 28 | #[derive(cynic::QueryFragment, Debug)] 29 | #[cynic(schema = "rpc", graphql_type = "Query", variables = "EpochArgs")] 30 | pub struct EpochSummaryQuery { 31 | #[arguments(id: $id)] 32 | pub epoch: Option, 33 | } 34 | 35 | #[derive(cynic::QueryFragment, Debug)] 36 | #[cynic(schema = "rpc", graphql_type = "EpochConnection")] 37 | pub struct EpochConnection { 38 | pub nodes: Vec, 39 | pub page_info: PageInfo, 40 | } 41 | // =========================================================================== 42 | // Epoch Summary Args 43 | // =========================================================================== 44 | 45 | #[derive(cynic::QueryVariables, Debug)] 46 | pub struct EpochArgs { 47 | pub id: Option, 48 | } 49 | 50 | #[derive(cynic::QueryVariables, Debug)] 51 | pub struct EpochsArgs<'a> { 52 | pub first: Option, 53 | pub after: Option<&'a str>, 54 | pub last: Option, 55 | pub before: Option<&'a str>, 56 | } 57 | 58 | /// A summary of the epoch. 59 | #[derive(cynic::QueryFragment, Debug)] 60 | #[cynic(schema = "rpc", graphql_type = "Epoch")] 61 | pub struct EpochSummary { 62 | /// The epoch number. 63 | pub epoch_id: u64, 64 | /// The reference gas price throughout this epoch. 65 | pub reference_gas_price: Option, 66 | /// The total number of checkpoints in this epoch. 67 | pub total_checkpoints: Option, 68 | /// The total number of transactions in this epoch. 69 | pub total_transactions: Option, 70 | } 71 | 72 | // =========================================================================== 73 | // Epoch Types 74 | // =========================================================================== 75 | 76 | #[derive(cynic::QueryFragment, Debug, Clone)] 77 | #[cynic(schema = "rpc", graphql_type = "Epoch")] 78 | pub struct Epoch { 79 | /// The epoch's id as a sequence number that starts at 0 and is incremented by one at every epoch change. 80 | pub epoch_id: u64, 81 | /// The storage fees paid for transactions executed during the epoch. 82 | pub fund_inflow: Option, 83 | /// The storage fee rebates paid to users who deleted the data associated with past 84 | /// transactions. 85 | pub fund_outflow: Option, 86 | /// The storage fund available in this epoch. 87 | /// This fund is used to redistribute storage fees from past transactions 88 | /// to future validators. 89 | pub fund_size: Option, 90 | /// A commitment by the committee at the end of epoch on the contents of the live object set at 91 | /// that time. This can be used to verify state snapshots. 92 | pub live_object_set_digest: Option, 93 | /// The difference between the fund inflow and outflow, representing 94 | /// the net amount of storage fees accumulated in this epoch. 95 | pub net_inflow: Option, 96 | /// The epoch's corresponding protocol configuration, including the feature flags and the 97 | /// configuration options. 98 | pub protocol_configs: Option, 99 | /// The minimum gas price that a quorum of validators are guaranteed to sign a transaction for. 100 | pub reference_gas_price: Option, 101 | /// The epoch's starting timestamp. 102 | pub start_timestamp: DateTime, 103 | /// The epoch's ending timestamp. Note that this is available only on epochs that have ended. 104 | pub end_timestamp: Option, 105 | /// The value of the `version` field of `0x5`, the `0x3::sui::SuiSystemState` object. This 106 | /// version changes whenever the fields contained in the system state object (held in a dynamic 107 | /// field attached to `0x5`) change. 108 | pub system_state_version: Option, 109 | /// The total number of checkpoints in this epoch. 110 | pub total_checkpoints: Option, 111 | /// The total amount of gas fees (in MIST) that were paid in this epoch. 112 | pub total_gas_fees: Option, 113 | /// The total MIST rewarded as stake. 114 | pub total_stake_rewards: Option, 115 | /// The amount added to total gas fees to make up the total stake rewards. 116 | pub total_stake_subsidies: Option, 117 | /// The total number of transaction in this epoch. 118 | pub total_transactions: Option, 119 | /// Validator related properties. For active validators, see `active_validators` API. 120 | pub validator_set: Option, 121 | } 122 | 123 | #[derive(cynic::QueryFragment, Debug, Clone)] 124 | #[cynic(schema = "rpc", graphql_type = "ValidatorSet")] 125 | pub struct ValidatorSet { 126 | /// Object ID of the `Table` storing the inactive staking pools. 127 | pub inactive_pools_id: Option
, 128 | /// Size of the inactive pools `Table`. 129 | pub inactive_pools_size: Option, 130 | /// Object ID of the wrapped object `TableVec` storing the pending active validators. 131 | pub pending_active_validators_id: Option
, 132 | /// Size of the pending active validators table. 133 | pub pending_active_validators_size: Option, 134 | /// Validators that are pending removal from the active validator set, expressed as indices in 135 | /// to `activeValidators`. 136 | pub pending_removals: Option>, 137 | /// Object ID of the `Table` storing the mapping from staking pool ids to the addresses 138 | /// of the corresponding validators. This is needed because a validator's address 139 | /// can potentially change but the object ID of its pool will not. 140 | pub staking_pool_mappings_id: Option
, 141 | /// Size of the stake pool mappings `Table`. 142 | pub staking_pool_mappings_size: Option, 143 | /// Total amount of stake for all active validators at the beginning of the epoch. 144 | pub total_stake: Option, 145 | /// Size of the validator candidates `Table`. 146 | pub validator_candidates_size: Option, 147 | /// Object ID of the `Table` storing the validator candidates. 148 | pub validator_candidates_id: Option
, 149 | } 150 | -------------------------------------------------------------------------------- /crates/sui-graphql-client/src/query_types/events.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Mysten Labs, Inc. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use crate::query_types::schema; 5 | use crate::query_types::transaction::TransactionBlockDigest; 6 | use crate::query_types::Address; 7 | use crate::query_types::Base64; 8 | use crate::query_types::PageInfo; 9 | 10 | // =========================================================================== 11 | // Events Queries 12 | // =========================================================================== 13 | 14 | #[derive(cynic::QueryFragment, Debug)] 15 | #[cynic(schema = "rpc", graphql_type = "Query", variables = "EventsQueryArgs")] 16 | pub struct EventsQuery { 17 | #[arguments(after: $after, before: $before, filter: $filter, first: $first, last: $last)] 18 | pub events: EventConnection, 19 | } 20 | 21 | // =========================================================================== 22 | // Events Query Args 23 | // =========================================================================== 24 | 25 | #[derive(cynic::QueryVariables, Debug)] 26 | pub struct EventsQueryArgs<'a> { 27 | pub filter: Option, 28 | pub after: Option<&'a str>, 29 | pub before: Option<&'a str>, 30 | pub first: Option, 31 | pub last: Option, 32 | } 33 | 34 | // =========================================================================== 35 | // Events Types 36 | // =========================================================================== 37 | 38 | #[derive(cynic::QueryFragment, Debug)] 39 | #[cynic(schema = "rpc", graphql_type = "EventConnection")] 40 | pub struct EventConnection { 41 | pub page_info: PageInfo, 42 | pub nodes: Vec, 43 | } 44 | 45 | #[derive(Clone, cynic::InputObject, Debug)] 46 | #[cynic(schema = "rpc", graphql_type = "EventFilter")] 47 | pub struct EventFilter { 48 | pub emitting_module: Option, 49 | pub event_type: Option, 50 | pub sender: Option
, 51 | pub transaction_digest: Option, 52 | } 53 | 54 | #[derive(cynic::QueryFragment, Debug)] 55 | #[cynic(schema = "rpc", graphql_type = "Event")] 56 | pub struct Event { 57 | pub bcs: Base64, 58 | pub transaction_block: Option, 59 | } 60 | -------------------------------------------------------------------------------- /crates/sui-graphql-client/src/query_types/execute_tx.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Mysten Labs, Inc. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use crate::query_types::schema; 5 | use crate::query_types::Base64; 6 | 7 | #[derive(cynic::QueryFragment, Debug)] 8 | #[cynic( 9 | schema = "rpc", 10 | graphql_type = "Mutation", 11 | variables = "ExecuteTransactionArgs" 12 | )] 13 | pub struct ExecuteTransactionQuery { 14 | #[arguments(signatures: $signatures, txBytes: $tx_bytes)] 15 | pub execute_transaction_block: ExecutionResult, 16 | } 17 | 18 | #[derive(cynic::QueryVariables, Debug)] 19 | pub struct ExecuteTransactionArgs { 20 | pub signatures: Vec, 21 | pub tx_bytes: String, 22 | } 23 | 24 | #[derive(cynic::QueryFragment, Debug)] 25 | #[cynic(schema = "rpc", graphql_type = "ExecutionResult")] 26 | pub struct ExecutionResult { 27 | pub errors: Option>, 28 | pub effects: TransactionBlockEffects, 29 | } 30 | 31 | #[derive(cynic::QueryFragment, Debug)] 32 | #[cynic(schema = "rpc", graphql_type = "TransactionBlockEffects")] 33 | pub struct TransactionBlockEffects { 34 | pub bcs: Base64, 35 | } 36 | -------------------------------------------------------------------------------- /crates/sui-graphql-client/src/query_types/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Mysten Labs, Inc. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | mod active_validators; 5 | mod balance; 6 | mod chain; 7 | mod checkpoint; 8 | mod coin; 9 | mod dry_run; 10 | mod dynamic_fields; 11 | mod epoch; 12 | mod events; 13 | mod execute_tx; 14 | mod normalized_move; 15 | mod object; 16 | mod packages; 17 | mod protocol_config; 18 | mod service_config; 19 | mod suins; 20 | mod transaction; 21 | 22 | pub use active_validators::ActiveValidatorsArgs; 23 | pub use active_validators::ActiveValidatorsQuery; 24 | pub use active_validators::EpochValidator; 25 | pub use active_validators::Validator; 26 | pub use active_validators::ValidatorConnection; 27 | pub use active_validators::ValidatorSet; 28 | pub use balance::Balance; 29 | pub use balance::BalanceArgs; 30 | pub use balance::BalanceQuery; 31 | pub use balance::Owner; 32 | pub use chain::ChainIdentifierQuery; 33 | pub use checkpoint::CheckpointArgs; 34 | pub use checkpoint::CheckpointId; 35 | pub use checkpoint::CheckpointQuery; 36 | pub use checkpoint::CheckpointTotalTxQuery; 37 | pub use checkpoint::CheckpointsArgs; 38 | pub use checkpoint::CheckpointsQuery; 39 | pub use coin::CoinMetadata; 40 | pub use coin::CoinMetadataArgs; 41 | pub use coin::CoinMetadataQuery; 42 | pub use dry_run::DryRunArgs; 43 | pub use dry_run::DryRunQuery; 44 | pub use dry_run::DryRunResult; 45 | pub use dry_run::TransactionMetadata; 46 | pub use dynamic_fields::DynamicFieldArgs; 47 | pub use dynamic_fields::DynamicFieldConnectionArgs; 48 | pub use dynamic_fields::DynamicFieldName; 49 | pub use dynamic_fields::DynamicFieldQuery; 50 | pub use dynamic_fields::DynamicFieldsOwnerQuery; 51 | pub use dynamic_fields::DynamicObjectFieldQuery; 52 | pub use epoch::Epoch; 53 | pub use epoch::EpochArgs; 54 | pub use epoch::EpochQuery; 55 | pub use epoch::EpochSummaryQuery; 56 | pub use epoch::EpochsArgs; 57 | pub use epoch::EpochsQuery; 58 | pub use events::Event; 59 | pub use events::EventConnection; 60 | pub use events::EventFilter; 61 | pub use events::EventsQuery; 62 | pub use events::EventsQueryArgs; 63 | pub use execute_tx::ExecuteTransactionArgs; 64 | pub use execute_tx::ExecuteTransactionQuery; 65 | pub use execute_tx::ExecutionResult; 66 | pub use normalized_move::MoveAbility; 67 | pub use normalized_move::MoveFunction; 68 | pub use normalized_move::MoveFunctionTypeParameter; 69 | pub use normalized_move::MoveModule; 70 | pub use normalized_move::MoveVisibility; 71 | pub use normalized_move::NormalizedMoveFunctionQuery; 72 | pub use normalized_move::NormalizedMoveFunctionQueryArgs; 73 | pub use normalized_move::NormalizedMoveModuleQuery; 74 | pub use normalized_move::NormalizedMoveModuleQueryArgs; 75 | pub use normalized_move::OpenMoveType; 76 | pub use object::ObjectFilter; 77 | pub use object::ObjectKey; 78 | pub use object::ObjectQuery; 79 | pub use object::ObjectQueryArgs; 80 | pub use object::ObjectsQuery; 81 | pub use object::ObjectsQueryArgs; 82 | pub use packages::LatestPackageQuery; 83 | pub use packages::MovePackage; 84 | pub use packages::MovePackageConnection; 85 | pub use packages::MovePackageVersionFilter; 86 | pub use packages::PackageArgs; 87 | pub use packages::PackageByNameArgs; 88 | pub use packages::PackageByNameQuery; 89 | pub use packages::PackageCheckpointFilter; 90 | pub use packages::PackageQuery; 91 | pub use packages::PackageVersionsArgs; 92 | pub use packages::PackageVersionsQuery; 93 | pub use packages::PackagesQuery; 94 | pub use packages::PackagesQueryArgs; 95 | pub use protocol_config::ProtocolConfigQuery; 96 | pub use protocol_config::ProtocolConfigs; 97 | pub use protocol_config::ProtocolVersionArgs; 98 | pub use service_config::Feature; 99 | pub use service_config::ServiceConfig; 100 | pub use service_config::ServiceConfigQuery; 101 | pub use suins::DefaultSuinsNameQuery; 102 | pub use suins::DefaultSuinsNameQueryArgs; 103 | pub use suins::ResolveSuinsQuery; 104 | pub use suins::ResolveSuinsQueryArgs; 105 | pub use transaction::TransactionBlock; 106 | pub use transaction::TransactionBlockArgs; 107 | pub use transaction::TransactionBlockEffectsQuery; 108 | pub use transaction::TransactionBlockQuery; 109 | pub use transaction::TransactionBlockWithEffects; 110 | pub use transaction::TransactionBlockWithEffectsQuery; 111 | pub use transaction::TransactionBlocksEffectsQuery; 112 | pub use transaction::TransactionBlocksQuery; 113 | pub use transaction::TransactionBlocksQueryArgs; 114 | pub use transaction::TransactionBlocksWithEffectsQuery; 115 | pub use transaction::TransactionsFilter; 116 | 117 | use sui_types::Address; 118 | 119 | use cynic::impl_scalar; 120 | use serde_json::Value as JsonValue; 121 | 122 | use crate::error; 123 | 124 | #[cynic::schema("rpc")] 125 | pub mod schema {} 126 | 127 | // =========================================================================== 128 | // Scalars 129 | // =========================================================================== 130 | 131 | impl_scalar!(Address, schema::SuiAddress); 132 | impl_scalar!(u64, schema::UInt53); 133 | impl_scalar!(JsonValue, schema::JSON); 134 | 135 | #[derive(cynic::Scalar, Debug, Clone)] 136 | #[cynic(graphql_type = "Base64")] 137 | pub struct Base64(pub String); 138 | 139 | #[derive(cynic::Scalar, Debug, Clone)] 140 | #[cynic(graphql_type = "BigInt")] 141 | pub struct BigInt(pub String); 142 | 143 | #[derive(cynic::Scalar, Debug, Clone)] 144 | #[cynic(graphql_type = "DateTime")] 145 | pub struct DateTime(pub String); 146 | 147 | // =========================================================================== 148 | // Types used in several queries 149 | // =========================================================================== 150 | 151 | #[derive(cynic::QueryFragment, Debug)] 152 | #[cynic(schema = "rpc", graphql_type = "Address")] 153 | pub struct GQLAddress { 154 | pub address: Address, 155 | } 156 | 157 | #[derive(cynic::QueryFragment, Debug)] 158 | #[cynic(schema = "rpc", graphql_type = "MoveObject")] 159 | pub struct MoveObject { 160 | pub bcs: Option, 161 | } 162 | 163 | #[derive(cynic::QueryFragment, Debug)] 164 | #[cynic(schema = "rpc", graphql_type = "MoveObject")] 165 | pub struct MoveObjectContents { 166 | pub contents: Option, 167 | } 168 | 169 | #[derive(cynic::QueryFragment, Debug)] 170 | #[cynic(schema = "rpc", graphql_type = "MoveValue")] 171 | pub struct MoveValue { 172 | pub type_: MoveType, 173 | pub bcs: Base64, 174 | pub json: Option, 175 | } 176 | 177 | #[derive(cynic::QueryFragment, Debug)] 178 | #[cynic(schema = "rpc", graphql_type = "MoveType")] 179 | pub struct MoveType { 180 | pub repr: String, 181 | } 182 | // =========================================================================== 183 | // Utility Types 184 | // =========================================================================== 185 | 186 | #[derive(Clone, Default, cynic::QueryFragment, Debug)] 187 | #[cynic(schema = "rpc", graphql_type = "PageInfo")] 188 | /// Information about pagination in a connection. 189 | pub struct PageInfo { 190 | /// When paginating backwards, are there more items? 191 | pub has_previous_page: bool, 192 | /// Are there more items when paginating forwards? 193 | pub has_next_page: bool, 194 | /// When paginating backwards, the cursor to continue. 195 | pub start_cursor: Option, 196 | /// When paginating forwards, the cursor to continue. 197 | pub end_cursor: Option, 198 | } 199 | 200 | impl TryFrom for u64 { 201 | type Error = error::Error; 202 | 203 | fn try_from(value: BigInt) -> Result { 204 | Ok(value.0.parse::()?) 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /crates/sui-graphql-client/src/query_types/normalized_move/function.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Mysten Labs, Inc. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use crate::query_types::schema; 5 | use crate::query_types::Address; 6 | use crate::query_types::MoveFunction; 7 | 8 | #[derive(cynic::QueryFragment, Debug)] 9 | #[cynic( 10 | schema = "rpc", 11 | graphql_type = "Query", 12 | variables = "NormalizedMoveFunctionQueryArgs" 13 | )] 14 | pub struct NormalizedMoveFunctionQuery { 15 | #[arguments(address: $address, version: $version)] 16 | pub package: Option, 17 | } 18 | 19 | #[derive(cynic::QueryVariables, Debug)] 20 | pub struct NormalizedMoveFunctionQueryArgs<'a> { 21 | pub address: Address, 22 | pub version: Option, 23 | pub module: &'a str, 24 | pub function: &'a str, 25 | } 26 | 27 | #[derive(cynic::QueryFragment, Debug)] 28 | #[cynic( 29 | schema = "rpc", 30 | graphql_type = "MovePackage", 31 | variables = "NormalizedMoveFunctionQueryArgs" 32 | )] 33 | pub struct MovePackage { 34 | #[arguments(name: $module)] 35 | pub module: Option, 36 | } 37 | 38 | #[derive(cynic::QueryFragment, Debug)] 39 | #[cynic( 40 | schema = "rpc", 41 | graphql_type = "MoveModule", 42 | variables = "NormalizedMoveFunctionQueryArgs" 43 | )] 44 | pub struct MoveModule { 45 | #[arguments(name: $function)] 46 | pub function: Option, 47 | } 48 | -------------------------------------------------------------------------------- /crates/sui-graphql-client/src/query_types/normalized_move/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Mysten Labs, Inc. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | mod function; 5 | mod module; 6 | 7 | pub use function::NormalizedMoveFunctionQuery; 8 | pub use function::NormalizedMoveFunctionQueryArgs; 9 | pub use module::MoveModule; 10 | pub use module::NormalizedMoveModuleQuery; 11 | pub use module::NormalizedMoveModuleQueryArgs; 12 | 13 | use crate::query_types::schema; 14 | 15 | #[derive(cynic::Enum, Clone, Copy, Debug)] 16 | #[cynic(schema = "rpc", graphql_type = "MoveAbility")] 17 | pub enum MoveAbility { 18 | Copy, 19 | Drop, 20 | Key, 21 | Store, 22 | } 23 | 24 | #[derive(cynic::Enum, Clone, Copy, Debug)] 25 | #[cynic(schema = "rpc", graphql_type = "MoveVisibility")] 26 | pub enum MoveVisibility { 27 | Public, 28 | Private, 29 | Friend, 30 | } 31 | 32 | #[derive(cynic::QueryFragment, Debug)] 33 | #[cynic(schema = "rpc", graphql_type = "MoveFunction")] 34 | pub struct MoveFunction { 35 | pub is_entry: Option, 36 | pub name: String, 37 | pub parameters: Option>, 38 | #[cynic(rename = "return")] 39 | pub return_: Option>, 40 | pub type_parameters: Option>, 41 | pub visibility: Option, 42 | } 43 | 44 | #[derive(cynic::QueryFragment, Debug)] 45 | #[cynic(schema = "rpc", graphql_type = "MoveFunctionTypeParameter")] 46 | pub struct MoveFunctionTypeParameter { 47 | pub constraints: Vec, 48 | } 49 | 50 | #[derive(cynic::QueryFragment, Debug)] 51 | #[cynic(schema = "rpc", graphql_type = "OpenMoveType")] 52 | pub struct OpenMoveType { 53 | pub repr: String, 54 | } 55 | -------------------------------------------------------------------------------- /crates/sui-graphql-client/src/query_types/normalized_move/module.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Mysten Labs, Inc. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use crate::query_types::schema; 5 | use crate::query_types::Address; 6 | use crate::query_types::MoveAbility; 7 | use crate::query_types::MoveFunction; 8 | use crate::query_types::PageInfo; 9 | 10 | #[derive(cynic::QueryFragment, Debug)] 11 | #[cynic( 12 | schema = "rpc", 13 | graphql_type = "Query", 14 | variables = "NormalizedMoveModuleQueryArgs" 15 | )] 16 | pub struct NormalizedMoveModuleQuery { 17 | #[arguments(address: $package, version: $version)] 18 | pub package: Option, 19 | } 20 | 21 | #[derive(cynic::QueryVariables, Debug)] 22 | pub struct NormalizedMoveModuleQueryArgs<'a> { 23 | pub package: Address, 24 | pub module: &'a str, 25 | pub version: Option, 26 | pub after_enums: Option<&'a str>, 27 | pub after_functions: Option<&'a str>, 28 | pub after_structs: Option<&'a str>, 29 | pub after_friends: Option<&'a str>, 30 | pub before_enums: Option<&'a str>, 31 | pub before_functions: Option<&'a str>, 32 | pub before_structs: Option<&'a str>, 33 | pub before_friends: Option<&'a str>, 34 | pub first_enums: Option, 35 | pub first_functions: Option, 36 | pub first_structs: Option, 37 | pub first_friends: Option, 38 | pub last_enums: Option, 39 | pub last_functions: Option, 40 | pub last_structs: Option, 41 | pub last_friends: Option, 42 | } 43 | 44 | #[derive(cynic::QueryFragment, Debug)] 45 | #[cynic( 46 | schema = "rpc", 47 | graphql_type = "MovePackage", 48 | variables = "NormalizedMoveModuleQueryArgs" 49 | )] 50 | pub struct MovePackage { 51 | #[arguments(name: $module)] 52 | pub module: Option, 53 | } 54 | 55 | #[derive(cynic::QueryFragment, Debug)] 56 | #[cynic( 57 | schema = "rpc", 58 | graphql_type = "MoveModule", 59 | variables = "NormalizedMoveModuleQueryArgs" 60 | )] 61 | pub struct MoveModule { 62 | pub file_format_version: i32, 63 | #[arguments(after: $after_enums, before:$before_enums, first: $first_enums, last: $last_enums)] 64 | pub enums: Option, 65 | #[arguments(after: $after_friends, before: $before_friends, first: $first_friends, last: $last_friends)] 66 | pub friends: MoveModuleConnection, 67 | #[arguments(after: $after_functions, before: $before_functions, first: $first_functions, last: $last_functions)] 68 | pub functions: Option, 69 | #[arguments(after: $after_structs, before: $before_structs, first: $first_structs, last: $last_structs)] 70 | pub structs: Option, 71 | } 72 | 73 | #[derive(cynic::QueryFragment, Debug)] 74 | #[cynic(schema = "rpc", graphql_type = "MoveStructConnection")] 75 | pub struct MoveStructConnection { 76 | pub page_info: PageInfo, 77 | pub nodes: Vec, 78 | } 79 | 80 | #[derive(cynic::QueryFragment, Debug)] 81 | #[cynic(schema = "rpc", graphql_type = "MoveStruct")] 82 | pub struct MoveStruct { 83 | pub abilities: Option>, 84 | pub name: String, 85 | pub fields: Option>, 86 | pub type_parameters: Option>, 87 | } 88 | 89 | #[derive(cynic::QueryFragment, Debug)] 90 | #[cynic(schema = "rpc", graphql_type = "MoveModuleConnection")] 91 | pub struct MoveModuleConnection { 92 | pub nodes: Vec, 93 | pub page_info: PageInfo, 94 | } 95 | 96 | #[derive(cynic::QueryFragment, Debug)] 97 | #[cynic(schema = "rpc", graphql_type = "MoveModule")] 98 | pub struct MoveModule2 { 99 | pub name: String, 100 | } 101 | 102 | #[derive(cynic::QueryFragment, Debug)] 103 | #[cynic(schema = "rpc", graphql_type = "MoveFunctionConnection")] 104 | pub struct MoveFunctionConnection { 105 | pub nodes: Vec, 106 | pub page_info: PageInfo, 107 | } 108 | 109 | #[derive(cynic::QueryFragment, Debug)] 110 | #[cynic(schema = "rpc", graphql_type = "MoveEnumConnection")] 111 | pub struct MoveEnumConnection { 112 | pub nodes: Vec, 113 | pub page_info: PageInfo, 114 | } 115 | 116 | #[derive(cynic::QueryFragment, Debug)] 117 | #[cynic(schema = "rpc", graphql_type = "MoveEnum")] 118 | pub struct MoveEnum { 119 | pub abilities: Option>, 120 | pub name: String, 121 | pub type_parameters: Option>, 122 | pub variants: Option>, 123 | } 124 | 125 | #[derive(cynic::QueryFragment, Debug)] 126 | #[cynic(schema = "rpc", graphql_type = "MoveEnumVariant")] 127 | pub struct MoveEnumVariant { 128 | pub fields: Option>, 129 | pub name: String, 130 | } 131 | 132 | #[derive(cynic::QueryFragment, Debug)] 133 | #[cynic(schema = "rpc", graphql_type = "MoveField")] 134 | pub struct MoveField { 135 | pub name: String, 136 | #[cynic(rename = "type")] 137 | pub type_: Option, 138 | } 139 | 140 | #[derive(cynic::QueryFragment, Debug)] 141 | #[cynic(schema = "rpc", graphql_type = "OpenMoveType")] 142 | pub struct OpenMoveType { 143 | pub repr: String, 144 | } 145 | 146 | #[derive(cynic::QueryFragment, Debug)] 147 | #[cynic(schema = "rpc", graphql_type = "MoveStructTypeParameter")] 148 | pub struct MoveStructTypeParameter { 149 | pub constraints: Vec, 150 | pub is_phantom: bool, 151 | } 152 | -------------------------------------------------------------------------------- /crates/sui-graphql-client/src/query_types/object.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Mysten Labs, Inc. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use crate::query_types::schema; 5 | use crate::query_types::Address; 6 | use crate::query_types::Base64; 7 | use crate::query_types::MoveObjectContents; 8 | use crate::query_types::PageInfo; 9 | 10 | // =========================================================================== 11 | // Object(s) Queries 12 | // =========================================================================== 13 | 14 | #[derive(cynic::QueryFragment, Debug)] 15 | #[cynic(schema = "rpc", graphql_type = "Query", variables = "ObjectQueryArgs")] 16 | pub struct ObjectQuery { 17 | #[arguments(address: $address, version: $version)] 18 | pub object: Option, 19 | } 20 | 21 | #[derive(cynic::QueryFragment, Debug)] 22 | #[cynic(schema = "rpc", graphql_type = "Query", variables = "ObjectsQueryArgs")] 23 | pub struct ObjectsQuery { 24 | #[arguments(after: $after, before: $before, filter: $filter, first: $first, last: $last)] 25 | pub objects: ObjectConnection, 26 | } 27 | 28 | // =========================================================================== 29 | // Object(s) Query Args 30 | // =========================================================================== 31 | 32 | #[derive(cynic::QueryVariables, Debug)] 33 | pub struct ObjectQueryArgs { 34 | pub address: Address, 35 | pub version: Option, 36 | } 37 | 38 | #[derive(cynic::QueryVariables, Debug)] 39 | pub struct ObjectsQueryArgs<'a> { 40 | pub after: Option<&'a str>, 41 | pub before: Option<&'a str>, 42 | pub filter: Option>, 43 | pub first: Option, 44 | pub last: Option, 45 | } 46 | 47 | // =========================================================================== 48 | // Object(s) Types 49 | // =========================================================================== 50 | 51 | #[derive(cynic::QueryFragment, Debug)] 52 | #[cynic(schema = "rpc", graphql_type = "Object")] 53 | pub struct Object { 54 | pub as_move_object: Option, 55 | pub bcs: Option, 56 | } 57 | 58 | #[derive(Clone, Default, cynic::InputObject, Debug)] 59 | #[cynic(schema = "rpc", graphql_type = "ObjectFilter")] 60 | pub struct ObjectFilter<'a> { 61 | #[cynic(rename = "type")] 62 | pub type_: Option<&'a str>, 63 | pub owner: Option
, 64 | pub object_ids: Option>, 65 | } 66 | 67 | #[derive(Clone, cynic::InputObject, Debug)] 68 | #[cynic(schema = "rpc", graphql_type = "ObjectKey")] 69 | pub struct ObjectKey { 70 | pub object_id: Address, 71 | pub version: u64, 72 | } 73 | 74 | #[derive(cynic::QueryFragment, Debug)] 75 | #[cynic(schema = "rpc", graphql_type = "ObjectConnection")] 76 | pub struct ObjectConnection { 77 | pub page_info: PageInfo, 78 | pub nodes: Vec, 79 | } 80 | -------------------------------------------------------------------------------- /crates/sui-graphql-client/src/query_types/packages.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Mysten Labs, Inc. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use sui_types::Address; 5 | 6 | use crate::query_types::schema; 7 | use crate::query_types::Base64; 8 | use crate::query_types::PageInfo; 9 | 10 | // =========================================================================== 11 | // Package by address (and optional version) 12 | // =========================================================================== 13 | 14 | #[derive(cynic::QueryFragment, Debug)] 15 | #[cynic(schema = "rpc", graphql_type = "Query", variables = "PackageArgs")] 16 | pub struct PackageQuery { 17 | #[arguments(address: $address, version: $version)] 18 | pub package: Option, 19 | } 20 | 21 | // =========================================================================== 22 | // Latest Package 23 | // =========================================================================== 24 | 25 | #[derive(cynic::QueryFragment, Debug)] 26 | #[cynic(schema = "rpc", graphql_type = "Query", variables = "PackageArgs")] 27 | pub struct LatestPackageQuery { 28 | #[arguments(address: $address)] 29 | pub latest_package: Option, 30 | } 31 | 32 | #[derive(cynic::QueryVariables, Debug)] 33 | pub struct PackageArgs { 34 | pub address: Address, 35 | pub version: Option, 36 | } 37 | 38 | // =========================================================================== 39 | // Package By Name 40 | // =========================================================================== 41 | 42 | #[derive(cynic::QueryFragment, Debug)] 43 | #[cynic( 44 | schema = "rpc", 45 | graphql_type = "Query", 46 | variables = "PackageByNameArgs" 47 | )] 48 | pub struct PackageByNameQuery { 49 | #[arguments(name: "")] 50 | pub package_by_name: Option, 51 | } 52 | 53 | #[derive(cynic::QueryVariables, Debug)] 54 | pub struct PackageByNameArgs<'a> { 55 | pub name: &'a str, 56 | } 57 | 58 | #[derive(cynic::QueryFragment, Debug)] 59 | #[cynic(schema = "rpc", graphql_type = "MovePackage")] 60 | pub struct MovePackage { 61 | pub package_bcs: Option, 62 | } 63 | 64 | // =========================================================================== 65 | // Packages 66 | // =========================================================================== 67 | 68 | #[derive(cynic::QueryFragment, Debug)] 69 | #[cynic( 70 | schema = "rpc", 71 | graphql_type = "Query", 72 | variables = "PackagesQueryArgs" 73 | )] 74 | pub struct PackagesQuery { 75 | #[arguments(after: $after, before: $before, filter: $filter, first: $first, last: $last)] 76 | pub packages: MovePackageConnection, 77 | } 78 | 79 | #[derive(cynic::QueryVariables, Debug)] 80 | pub struct PackagesQueryArgs<'a> { 81 | pub after: Option<&'a str>, 82 | pub before: Option<&'a str>, 83 | pub filter: Option, 84 | pub first: Option, 85 | pub last: Option, 86 | } 87 | 88 | #[derive(cynic::InputObject, Debug)] 89 | #[cynic(schema = "rpc", graphql_type = "MovePackageCheckpointFilter")] 90 | pub struct PackageCheckpointFilter { 91 | pub after_checkpoint: Option, 92 | pub before_checkpoint: Option, 93 | } 94 | 95 | #[derive(cynic::QueryFragment, Debug)] 96 | #[cynic(schema = "rpc", graphql_type = "MovePackageConnection")] 97 | pub struct MovePackageConnection { 98 | pub nodes: Vec, 99 | pub page_info: PageInfo, 100 | } 101 | 102 | // =========================================================================== 103 | // PackagesVersions 104 | // =========================================================================== 105 | 106 | #[derive(cynic::QueryFragment, Debug)] 107 | #[cynic( 108 | schema = "rpc", 109 | graphql_type = "Query", 110 | variables = "PackageVersionsArgs" 111 | )] 112 | pub struct PackageVersionsQuery { 113 | #[arguments(address: $address, after: $after, first: $first, last: $last, before: $before, filter:$filter)] 114 | pub package_versions: MovePackageConnection, 115 | } 116 | 117 | #[derive(cynic::QueryVariables, Debug)] 118 | pub struct PackageVersionsArgs<'a> { 119 | pub address: Address, 120 | pub after: Option<&'a str>, 121 | pub first: Option, 122 | pub last: Option, 123 | pub before: Option<&'a str>, 124 | pub filter: Option, 125 | } 126 | 127 | #[derive(cynic::InputObject, Debug)] 128 | #[cynic(schema = "rpc", graphql_type = "MovePackageVersionFilter")] 129 | pub struct MovePackageVersionFilter { 130 | pub after_version: Option, 131 | pub before_version: Option, 132 | } 133 | -------------------------------------------------------------------------------- /crates/sui-graphql-client/src/query_types/protocol_config.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Mysten Labs, Inc. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use crate::query_types::schema; 5 | 6 | // =========================================================================== 7 | // Protocol Config Queries 8 | // =========================================================================== 9 | 10 | #[derive(cynic::QueryFragment, Debug)] 11 | #[cynic( 12 | schema = "rpc", 13 | graphql_type = "Query", 14 | variables = "ProtocolVersionArgs" 15 | )] 16 | pub struct ProtocolConfigQuery { 17 | #[arguments(protocolVersion: $id)] 18 | pub protocol_config: ProtocolConfigs, 19 | } 20 | 21 | // =========================================================================== 22 | // Protocol Version Args 23 | // =========================================================================== 24 | 25 | #[derive(cynic::QueryVariables, Debug)] 26 | pub struct ProtocolVersionArgs { 27 | pub id: Option, 28 | } 29 | 30 | // =========================================================================== 31 | // Protocol Config Types 32 | // =========================================================================== 33 | 34 | /// Information about the configuration of the protocol. 35 | /// Constants that control how the chain operates. 36 | /// These can only change during protocol upgrades which happen on epoch boundaries. 37 | #[derive(cynic::QueryFragment, Clone, Debug)] 38 | #[cynic(schema = "rpc", graphql_type = "ProtocolConfigs")] 39 | pub struct ProtocolConfigs { 40 | /// The protocol is not required to change on every epoch boundary, so the protocol version 41 | /// tracks which change to the protocol these configs are from. 42 | pub protocol_version: u64, 43 | /// List all available feature flags and their values. Feature flags are a form of boolean 44 | /// configuration that are usually used to gate features while they are in development. Once a 45 | /// flag has been enabled, it is rare for it to be disabled. 46 | pub feature_flags: Vec, 47 | /// List all available configurations and their values. These configurations can take any value 48 | /// (but they will all be represented in string form), and do not include feature flags. 49 | pub configs: Vec, 50 | } 51 | 52 | /// Feature flags are a form of boolean configuration that are usually used to gate features while 53 | /// they are in development. Once a lag has been enabled, it is rare for it to be disabled. 54 | #[derive(cynic::QueryFragment, Clone, Debug)] 55 | #[cynic(schema = "rpc", graphql_type = "ProtocolConfigFeatureFlag")] 56 | pub struct ProtocolConfigFeatureFlag { 57 | pub key: String, 58 | pub value: bool, 59 | } 60 | 61 | /// A key-value protocol configuration attribute. 62 | #[derive(cynic::QueryFragment, Clone, Debug)] 63 | #[cynic(schema = "rpc", graphql_type = "ProtocolConfigAttr")] 64 | pub struct ProtocolConfigAttr { 65 | pub key: String, 66 | pub value: Option, 67 | } 68 | -------------------------------------------------------------------------------- /crates/sui-graphql-client/src/query_types/service_config.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Mysten Labs, Inc. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use crate::query_types::schema; 5 | 6 | // =========================================================================== 7 | // Service Config Query 8 | // =========================================================================== 9 | 10 | #[derive(cynic::QueryFragment, Debug)] 11 | #[cynic(schema = "rpc", graphql_type = "Query")] 12 | pub struct ServiceConfigQuery { 13 | pub service_config: ServiceConfig, 14 | } 15 | 16 | // =========================================================================== 17 | // Service Config Types 18 | // =========================================================================== 19 | 20 | // Information about the configuration of the GraphQL service. 21 | #[derive(cynic::QueryFragment, Debug)] 22 | #[cynic(schema = "rpc", graphql_type = "ServiceConfig")] 23 | pub struct ServiceConfig { 24 | /// Default number of elements allowed on a single page of a connection. 25 | pub default_page_size: i32, 26 | /// List of all features that are enabled on this RPC service. 27 | pub enabled_features: Vec, 28 | // TODO This field is retrieved as a string, instead of i32 29 | /// Maximum estimated cost of a database query used to serve a GraphQL request. This is 30 | /// measured in the same units that the database uses in EXPLAIN queries. 31 | // pub max_db_query_cost: i32, 32 | /// Maximum nesting allowed in struct fields when calculating the layout of a single Move Type. 33 | pub max_move_value_depth: i32, 34 | /// The maximum number of output nodes in a GraphQL response. 35 | /// Non-connection nodes have a count of 1, while connection nodes are counted as 36 | /// the specified 'first' or 'last' number of items, or the default_page_size 37 | /// as set by the server if those arguments are not set. 38 | /// Counts accumulate multiplicatively down the query tree. For example, if a query starts 39 | /// with a connection of first: 10 and has a field to a connection with last: 20, the count 40 | /// at the second level would be 200 nodes. This is then summed to the count of 10 nodes 41 | /// at the first level, for a total of 210 nodes. 42 | pub max_output_nodes: i32, 43 | /// Maximum number of elements allowed on a single page of a connection. 44 | pub max_page_size: i32, 45 | /// The maximum depth a GraphQL query can be to be accepted by this service. 46 | pub max_query_depth: i32, 47 | /// The maximum number of nodes (field names) the service will accept in a single query. 48 | pub max_query_nodes: i32, 49 | /// Maximum length of a query payload string. 50 | pub max_query_payload_size: i32, 51 | /// Maximum nesting allowed in type arguments in Move Types resolved by this service. 52 | pub max_type_argument_depth: i32, 53 | /// Maximum number of type arguments passed into a generic instantiation of a Move Type resolved 54 | /// by this service. 55 | pub max_type_argument_width: i32, 56 | /// Maximum number of structs that need to be processed when calculating the layout of a single 57 | /// Move Type. 58 | pub max_type_nodes: i32, 59 | /// Maximum time in milliseconds spent waiting for a response from fullnode after issuing a 60 | /// a transaction to execute. Note that the transaction may still succeed even in the case of a 61 | /// timeout. Transactions are idempotent, so a transaction that times out should be resubmitted 62 | /// until the network returns a definite response (success or failure, not timeout). 63 | pub mutation_timeout_ms: i32, 64 | /// Maximum time in milliseconds that will be spent to serve one query request. 65 | pub request_timeout_ms: i32, 66 | } 67 | 68 | #[derive(cynic::Enum, Clone, Copy, Debug)] 69 | #[cynic( 70 | schema = "rpc", 71 | graphql_type = "Feature", 72 | rename_all = "SCREAMING_SNAKE_CASE" 73 | )] 74 | pub enum Feature { 75 | Analytics, 76 | Coins, 77 | DynamicFields, 78 | NameService, 79 | Subscriptions, 80 | SystemState, 81 | MoveRegistry, 82 | } 83 | -------------------------------------------------------------------------------- /crates/sui-graphql-client/src/query_types/suins.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Mysten Labs, Inc. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // =========================================================================== 5 | // Suins Queries 6 | // =========================================================================== 7 | 8 | use crate::query_types::schema; 9 | use crate::query_types::Address as SdkAddress; 10 | 11 | #[derive(cynic::QueryFragment, Debug)] 12 | #[cynic( 13 | schema = "rpc", 14 | graphql_type = "Query", 15 | variables = "ResolveSuinsQueryArgs" 16 | )] 17 | pub struct ResolveSuinsQuery { 18 | #[arguments(domain: $name)] 19 | pub resolve_suins_address: Option, 20 | } 21 | 22 | #[derive(cynic::QueryVariables, Debug)] 23 | pub struct ResolveSuinsQueryArgs<'a> { 24 | pub name: &'a str, 25 | } 26 | 27 | #[derive(cynic::QueryFragment, Debug)] 28 | #[cynic(schema = "rpc", graphql_type = "Address")] 29 | pub struct DomainAddress { 30 | pub address: SdkAddress, 31 | } 32 | 33 | #[derive(cynic::QueryFragment, Debug)] 34 | #[cynic( 35 | schema = "rpc", 36 | graphql_type = "Query", 37 | variables = "DefaultSuinsNameQueryArgs" 38 | )] 39 | pub struct DefaultSuinsNameQuery { 40 | #[arguments(address: $address)] 41 | pub address: Option, 42 | } 43 | 44 | #[derive(cynic::QueryVariables, Debug)] 45 | pub struct DefaultSuinsNameQueryArgs { 46 | pub address: SdkAddress, 47 | } 48 | 49 | #[derive(cynic::QueryFragment, Debug)] 50 | #[cynic(schema = "rpc", graphql_type = "Address")] 51 | pub struct AddressDefaultSuins { 52 | pub default_suins_name: Option, 53 | } 54 | -------------------------------------------------------------------------------- /crates/sui-graphql-client/src/streams.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Mysten Labs, Inc. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use crate::error; 5 | use crate::query_types::PageInfo; 6 | use crate::Direction; 7 | use crate::Page; 8 | use crate::PaginationFilter; 9 | 10 | use futures::Stream; 11 | use std::future::Future; 12 | use std::pin::Pin; 13 | use std::task::Context; 14 | use std::task::Poll; 15 | 16 | /// A stream that yields items from a paginated query with support for bidirectional pagination. 17 | pub struct PageStream { 18 | query_fn: F, 19 | direction: Direction, 20 | current_page: Option<(PageInfo, std::vec::IntoIter)>, 21 | current_future: Option>>, 22 | finished: bool, 23 | is_first_page: bool, 24 | } 25 | 26 | impl PageStream { 27 | pub fn new(query_fn: F, direction: Direction) -> Self { 28 | Self { 29 | query_fn, 30 | direction, 31 | current_page: None, 32 | current_future: None, 33 | finished: false, 34 | is_first_page: true, 35 | } 36 | } 37 | } 38 | 39 | impl Stream for PageStream 40 | where 41 | T: Clone + Unpin, 42 | F: Fn(PaginationFilter) -> Fut, 43 | F: Unpin, 44 | Fut: Future, error::Error>>, 45 | { 46 | type Item = Result; 47 | 48 | fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { 49 | if self.finished { 50 | return Poll::Ready(None); 51 | } 52 | 53 | loop { 54 | let direction = self.direction.clone(); 55 | // If we have a current page, return the next item 56 | if let Some((page_info, iter)) = &mut self.current_page { 57 | if let Some(item) = iter.next() { 58 | return Poll::Ready(Some(Ok(item))); 59 | } 60 | 61 | // For backward pagination, we check for previous page 62 | // For the first page in backward pagination, we don't need to check has_previous_page 63 | let should_continue = match direction { 64 | Direction::Forward => page_info.has_next_page, 65 | Direction::Backward => page_info.has_previous_page, 66 | }; 67 | if !should_continue { 68 | self.finished = true; 69 | return Poll::Ready(None); 70 | } 71 | } 72 | 73 | // Get cursor from current page 74 | let current_cursor = self 75 | .current_page 76 | .as_ref() 77 | .and_then(|(page_info, _iter)| { 78 | match self.direction { 79 | Direction::Forward => page_info 80 | .has_next_page 81 | .then(|| page_info.end_cursor.clone()), 82 | Direction::Backward => { 83 | // For the first page in backward pagination, we don't use a cursor 84 | // This ensures we start from the last page 85 | if self.is_first_page { 86 | None 87 | } else { 88 | page_info 89 | .has_previous_page 90 | .then(|| page_info.start_cursor.clone()) 91 | } 92 | } 93 | } 94 | }) 95 | .flatten(); 96 | 97 | // If there's no future yet, create one 98 | if self.current_future.is_none() { 99 | if self.is_first_page && current_cursor.is_some() { 100 | self.is_first_page = false; 101 | } 102 | let filter = PaginationFilter { 103 | direction: self.direction.clone(), 104 | cursor: current_cursor, 105 | limit: None, 106 | }; 107 | let future = (self.query_fn)(filter); 108 | self.current_future = Some(Box::pin(future)); 109 | } 110 | 111 | // Poll the future 112 | match self.current_future.as_mut().unwrap().as_mut().poll(cx) { 113 | Poll::Ready(Ok(page)) => { 114 | self.current_future = None; 115 | 116 | if page.is_empty() { 117 | self.finished = true; 118 | return Poll::Ready(None); 119 | } 120 | 121 | let (page_info, data) = page.into_parts(); 122 | // For backward pagination, we need to reverse the items 123 | let iter = match self.direction { 124 | Direction::Forward => data.into_iter(), 125 | Direction::Backward => { 126 | let mut vec = data; 127 | vec.reverse(); 128 | vec.into_iter() 129 | } 130 | }; 131 | self.current_page = Some((page_info, iter)); 132 | 133 | if self.is_first_page { 134 | self.is_first_page = false; 135 | } 136 | } 137 | Poll::Ready(Err(e)) => { 138 | if self.is_first_page { 139 | self.is_first_page = false; 140 | } 141 | self.finished = true; 142 | self.current_future = None; 143 | return Poll::Ready(Some(Err(e))); 144 | } 145 | Poll::Pending => return Poll::Pending, 146 | } 147 | } 148 | } 149 | } 150 | 151 | /// Creates a new `PageStream` for a paginated query. 152 | /// 153 | /// Examples 154 | /// 155 | /// ```rust,ignore 156 | /// use futures::StreamExt; 157 | /// use sui_graphql_client::streams::stream_paginated_query; 158 | /// use sui_graphql_client::Client; 159 | /// use sui_graphql_client::PaginationFilter; 160 | /// use sui_graphql_client::Direction; 161 | /// 162 | /// let client = Client::new_testnet(); 163 | /// let stream = stream_paginated_query(|pagination_filter, Direction::Forward| { 164 | /// client.coins(owner, coin_type, pagination_filter) 165 | /// }); 166 | /// 167 | /// while let Some(result) = stream.next().await { 168 | /// match result { 169 | /// Ok(coin) => println!("Got coin: {:?}", coin), 170 | /// Err(e) => eprintln!("Error: {}", e), 171 | /// } 172 | /// } 173 | /// ``` 174 | pub fn stream_paginated_query(query_fn: F, direction: Direction) -> PageStream 175 | where 176 | F: Fn(PaginationFilter) -> Fut, 177 | Fut: Future, error::Error>>, 178 | { 179 | PageStream::new(query_fn, direction) 180 | } 181 | -------------------------------------------------------------------------------- /crates/sui-sdk-types/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # [0.0.4] - 2025-03-31 2 | 3 | ## Added 4 | 5 | - Added new `EndOfEpochTransactionKind::StoreExecutionTimeObservations` type [#105] 6 | 7 | [#105]: https://github.com/MystenLabs/sui-rust-sdk/pull/105 8 | 9 | # [0.0.3] - 2025-03-20 10 | 11 | ## Added 12 | 13 | - Added `Object::as_struct` getter [#87] 14 | - Added `ZkLoginPublicIdentifier::derive_address` with provides an iterator 15 | over the valid derived addresses [`a9a930d`] 16 | - Added documentation for a number of types. 17 | - Added support for the `ConsensusCommitPrologueV4` system transaction [`5e11579`] 18 | 19 | ## Changed 20 | 21 | - Renamed `to_address` to `derive_address` for all authenticators [`2442379`] 22 | 23 | [`2442379`]: https://github.com/mystenlabs/sui-rust-sdk/commit/2442379f19bdae8c560d9879ee291560a7cd2e1c 24 | [`a9a930d`]: https://github.com/mystenlabs/sui-rust-sdk/commit/a9a930d9f8afbfc025f8978e317025798d225790 25 | [`5e11579`]: https://github.com/mystenlabs/sui-rust-sdk/commit/5e11579031793f086178332219f5847ec94da0c4 26 | [#87]: https://github.com/MystenLabs/sui-rust-sdk/pull/87 27 | 28 | # [0.0.2] - 2025-01-06 29 | 30 | ## Added 31 | 32 | - Added `proptest::Arbitrary` impls via the `proptest` feature [`6918fd8`] 33 | - Added From impl for TypeTag [#77] 34 | 35 | ## Changed 36 | 37 | - Update the passkey challenge format to use the same signing message as other key types ([`c5a25ce`]) 38 | - Flattened the `types` module into the top-level ([`dc54c46`]) 39 | - Folded the `EffectsObjectChange` type into the `ChangedObject` struct ([`aa546ca`]) 40 | 41 | ## Removed 42 | 43 | - Removed the `unresolved` module and moved it to the `sui-transaction-builder` crate ([`d965897`]) 44 | - Removed the `schemars` feature ([`bc6dd37`]) 45 | 46 | [`c5a25ce`]: https://github.com/mystenlabs/sui-rust-sdk/commit/c5a25ce356a8cbe42ddcc6ec6bab380007790b44 47 | [`6918fd8`]: https://github.com/mystenlabs/sui-rust-sdk/commit/6918fd88d40734b8c15fb5c519e9a40aec53eb74 48 | [#77]: https://github.com/mystenlabs/sui-rust-sdk/pull/77 49 | [`d965897`]: https://github.com/mystenlabs/sui-rust-sdk/commit/d9658978a4c6e928d036fbedaab9326d5e28de87 50 | [`dc54c46`]: https://github.com/mystenlabs/sui-rust-sdk/commit/dc54c469f9d006f02d82ec5781d73e8e09ae26ae 51 | [`aa546ca`]: https://github.com/mystenlabs/sui-rust-sdk/commit/aa546ca91249932da3f8e3d55ba6e52e40cd8929 52 | [`bc6dd37`]: https://github.com/mystenlabs/sui-rust-sdk/commit/bc6dd3732973ed3c1c3ae811a818fc8504a99f0b 53 | 54 | # [0.0.1] - 2024-09-25 55 | 56 | Initial release 57 | 58 | [0.0.4]: https://github.com/mystenlabs/sui-rust-sdk/releases/tag/sui-sdk-types-0.0.4 59 | [0.0.3]: https://github.com/mystenlabs/sui-rust-sdk/releases/tag/sui-sdk-types-0.0.3 60 | [0.0.2]: https://github.com/mystenlabs/sui-rust-sdk/releases/tag/sui-sdk-types-0.0.2 61 | [0.0.1]: https://github.com/mystenlabs/sui-rust-sdk/releases/tag/sui-sdk-types-0.0.1 62 | -------------------------------------------------------------------------------- /crates/sui-sdk-types/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sui-sdk-types" 3 | version = "0.0.4" 4 | authors = ["Brandon Williams "] 5 | repository = "https://github.com/mystenlabs/sui-rust-sdk/" 6 | license = "Apache-2.0" 7 | edition = "2021" 8 | readme = "README.md" 9 | description = "Core types for the Sui Sdk" 10 | 11 | [package.metadata.docs.rs] 12 | # To build locally: 13 | # RUSTDOCFLAGS="--cfg=doc_cfg -Zunstable-options --generate-link-to-definition" RUSTC_BOOTSTRAP=1 cargo doc --all-features --no-deps --open 14 | all-features = true 15 | rustdoc-args = [ 16 | # Enable doc_cfg showing the required features. 17 | "--cfg=doc_cfg", 18 | 19 | # Generate links to definition in rustdoc source code pages 20 | # https://github.com/rust-lang/rust/pull/84176 21 | "-Zunstable-options", "--generate-link-to-definition" 22 | ] 23 | 24 | [features] 25 | default = [] 26 | serde = ["dep:serde", "dep:serde_derive", "dep:serde_with", "dep:bcs", "dep:serde_json", "roaring/std", "dep:itertools"] 27 | rand = ["dep:rand_core"] 28 | hash = ["dep:blake2"] 29 | proptest = ["dep:proptest", "dep:test-strategy", "serde"] 30 | 31 | [dependencies] 32 | base64ct = { version = "1.6.0", features = ["alloc"] } 33 | bs58 = "0.5.1" 34 | hex = "0.4.3" 35 | roaring = { version = "0.10.9", default-features = false } 36 | bnum = "0.12.0" 37 | winnow = "0.7" 38 | 39 | # Serialization and Deserialization support 40 | serde = { version = "1.0.210", optional = true } 41 | serde_derive = { version = "1.0.210", optional = true } 42 | serde_with = { version = "3.9", default-features = false, features = ["alloc"], optional = true } 43 | bcs = { version = "0.1.6", optional = true } 44 | serde_json = { version = "1.0.128", optional = true } 45 | itertools = { version = "0.13.0", optional = true } 46 | 47 | # RNG support 48 | rand_core = { version = "0.6.4", optional = true } 49 | 50 | # Hash support 51 | blake2 = { version = "0.10.6", optional = true } 52 | 53 | # proptest support 54 | proptest = { version = "1.6.0", default-features = false, features = ["std"], optional = true } 55 | test-strategy = { version = "0.4", optional = true } 56 | 57 | [dev-dependencies] 58 | bcs = "0.1.6" 59 | serde_json = "1.0.128" 60 | num-bigint = "0.4.6" 61 | paste = "1.0.15" 62 | 63 | [target.wasm32-unknown-unknown.dev-dependencies] 64 | wasm-bindgen-test = "0.3" 65 | getrandom = { version = "0.3", features = ["wasm_js"] } 66 | 67 | [lints.rust] 68 | unexpected_cfgs = { level = "warn", check-cfg = ['cfg(doc_cfg)'] } 69 | -------------------------------------------------------------------------------- /crates/sui-sdk-types/Makefile: -------------------------------------------------------------------------------- 1 | # Set the default target of this Makefile 2 | .PHONY: all 3 | all:: check-features clippy test wasm 4 | 5 | .PHONY: check-features 6 | check-features: 7 | cargo hack check --feature-powerset --no-dev-deps 8 | 9 | .PHONY: clippy 10 | clippy: 11 | cargo clippy --all-features --all-targets 12 | 13 | .PHONY: test 14 | test: 15 | cargo nextest run --all-features 16 | cargo test --all-features --doc 17 | 18 | .PHONY: wasm 19 | wasm: 20 | CC=clang wasm-pack test --node --all-features 21 | 22 | %: 23 | $(MAKE) -C ../.. $@ 24 | -------------------------------------------------------------------------------- /crates/sui-sdk-types/README.md: -------------------------------------------------------------------------------- 1 | # sui-sdk-types 2 | 3 | [![sui-sdk-types on crates.io](https://img.shields.io/crates/v/sui-sdk-types)](https://crates.io/crates/sui-sdk-types) 4 | [![Documentation (latest release)](https://img.shields.io/badge/docs-latest-brightgreen)](https://docs.rs/sui-sdk-types) 5 | [![Documentation (master)](https://img.shields.io/badge/docs-master-59f)](https://mystenlabs.github.io/sui-rust-sdk/sui_sdk_types/) 6 | 7 | The `sui-sdk-types` crate provides the definitions of the core types that are 8 | part of the public API of the Sui blockchain. 9 | -------------------------------------------------------------------------------- /crates/sui-sdk-types/src/crypto/bls12381.rs: -------------------------------------------------------------------------------- 1 | //! Implementation of bls12381 min-sig public-key cryptogrophy. 2 | 3 | /// A bls12381 min-sig public key. 4 | /// 5 | /// # BCS 6 | /// 7 | /// The BCS serialized form for this type is defined by the following ABNF: 8 | /// 9 | /// ```text 10 | /// bls-public-key = %x60 96OCTECT 11 | /// ``` 12 | /// 13 | /// Due to historical reasons, even though a min-sig `Bls12381PublicKey` has a fixed-length of 96, 14 | /// Sui's binary representation of a min-sig `Bls12381PublicKey` is prefixed with its length 15 | /// meaning its serialized binary form (in bcs) is 97 bytes long vs a more compact 96 bytes. 16 | #[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] 17 | #[cfg_attr( 18 | feature = "serde", 19 | derive(serde_derive::Serialize, serde_derive::Deserialize) 20 | )] 21 | #[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))] 22 | pub struct Bls12381PublicKey( 23 | #[cfg_attr( 24 | feature = "serde", 25 | serde( 26 | with = "::serde_with::As::<::serde_with::IfIsHumanReadable>" 27 | ) 28 | )] 29 | [u8; Self::LENGTH], 30 | ); 31 | 32 | impl Bls12381PublicKey { 33 | /// The length of an bls12381 public key in bytes. 34 | pub const LENGTH: usize = 96; 35 | 36 | pub const fn new(bytes: [u8; Self::LENGTH]) -> Self { 37 | Self(bytes) 38 | } 39 | 40 | #[cfg(feature = "rand")] 41 | #[cfg_attr(doc_cfg, doc(cfg(feature = "rand")))] 42 | pub fn generate(mut rng: R) -> Self 43 | where 44 | R: rand_core::RngCore + rand_core::CryptoRng, 45 | { 46 | let mut buf: [u8; Self::LENGTH] = [0; Self::LENGTH]; 47 | rng.fill_bytes(&mut buf); 48 | Self::new(buf) 49 | } 50 | 51 | /// Return the underlying byte array of an Bls12381PublicKey. 52 | pub const fn into_inner(self) -> [u8; Self::LENGTH] { 53 | self.0 54 | } 55 | 56 | pub const fn inner(&self) -> &[u8; Self::LENGTH] { 57 | &self.0 58 | } 59 | 60 | pub const fn as_bytes(&self) -> &[u8] { 61 | &self.0 62 | } 63 | 64 | pub fn from_bytes>(bytes: T) -> Result { 65 | <[u8; Self::LENGTH]>::try_from(bytes.as_ref()).map(Self) 66 | } 67 | } 68 | 69 | impl std::str::FromStr for Bls12381PublicKey { 70 | type Err = base64ct::Error; 71 | 72 | fn from_str(s: &str) -> Result { 73 | super::Base64FromStr96::from_str(s).map(|a| Self(a.0)) 74 | } 75 | } 76 | 77 | impl AsRef<[u8]> for Bls12381PublicKey { 78 | fn as_ref(&self) -> &[u8] { 79 | &self.0 80 | } 81 | } 82 | 83 | impl AsRef<[u8; Self::LENGTH]> for Bls12381PublicKey { 84 | fn as_ref(&self) -> &[u8; Self::LENGTH] { 85 | &self.0 86 | } 87 | } 88 | 89 | impl From for [u8; Bls12381PublicKey::LENGTH] { 90 | fn from(public_key: Bls12381PublicKey) -> Self { 91 | public_key.into_inner() 92 | } 93 | } 94 | 95 | impl From<[u8; Self::LENGTH]> for Bls12381PublicKey { 96 | fn from(public_key: [u8; Self::LENGTH]) -> Self { 97 | Self::new(public_key) 98 | } 99 | } 100 | 101 | impl std::fmt::Display for Bls12381PublicKey { 102 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 103 | std::fmt::Display::fmt(&super::Base64Display96(&self.0), f) 104 | } 105 | } 106 | 107 | impl std::fmt::Debug for Bls12381PublicKey { 108 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 109 | f.debug_tuple("Bls12381PublicKey") 110 | .field(&format_args!("\"{}\"", self)) 111 | .finish() 112 | } 113 | } 114 | 115 | /// A bls12381 min-sig signature. 116 | /// 117 | /// # BCS 118 | /// 119 | /// The BCS serialized form for this type is defined by the following ABNF: 120 | /// 121 | /// ```text 122 | /// bls-signature = 48OCTECT 123 | /// ``` 124 | #[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] 125 | #[cfg_attr( 126 | feature = "serde", 127 | derive(serde_derive::Serialize, serde_derive::Deserialize) 128 | )] 129 | #[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))] 130 | pub struct Bls12381Signature( 131 | #[cfg_attr( 132 | feature = "serde", 133 | serde( 134 | with = "::serde_with::As::<::serde_with::IfIsHumanReadable>" 135 | ) 136 | )] 137 | [u8; Self::LENGTH], 138 | ); 139 | 140 | impl Bls12381Signature { 141 | /// The length of an bls12381 signature key in bytes. 142 | pub const LENGTH: usize = 48; 143 | 144 | pub const fn new(bytes: [u8; Self::LENGTH]) -> Self { 145 | Self(bytes) 146 | } 147 | 148 | #[cfg(feature = "rand")] 149 | #[cfg_attr(doc_cfg, doc(cfg(feature = "rand")))] 150 | pub fn generate(mut rng: R) -> Self 151 | where 152 | R: rand_core::RngCore + rand_core::CryptoRng, 153 | { 154 | let mut buf: [u8; Self::LENGTH] = [0; Self::LENGTH]; 155 | rng.fill_bytes(&mut buf); 156 | Self::new(buf) 157 | } 158 | 159 | /// Return the underlying byte array of an Bls12381Signature. 160 | pub const fn into_inner(self) -> [u8; Self::LENGTH] { 161 | self.0 162 | } 163 | 164 | pub const fn inner(&self) -> &[u8; Self::LENGTH] { 165 | &self.0 166 | } 167 | 168 | pub const fn as_bytes(&self) -> &[u8] { 169 | &self.0 170 | } 171 | 172 | pub fn from_bytes>(bytes: T) -> Result { 173 | <[u8; Self::LENGTH]>::try_from(bytes.as_ref()).map(Self) 174 | } 175 | } 176 | 177 | impl std::str::FromStr for Bls12381Signature { 178 | type Err = base64ct::Error; 179 | 180 | fn from_str(s: &str) -> Result { 181 | super::Base64FromStr48::from_str(s).map(|a| Self::new(a.0)) 182 | } 183 | } 184 | 185 | impl AsRef<[u8]> for Bls12381Signature { 186 | fn as_ref(&self) -> &[u8] { 187 | &self.0 188 | } 189 | } 190 | 191 | impl AsRef<[u8; Self::LENGTH]> for Bls12381Signature { 192 | fn as_ref(&self) -> &[u8; Self::LENGTH] { 193 | &self.0 194 | } 195 | } 196 | 197 | impl From for [u8; Bls12381Signature::LENGTH] { 198 | fn from(signature: Bls12381Signature) -> Self { 199 | signature.into_inner() 200 | } 201 | } 202 | 203 | impl From<[u8; Self::LENGTH]> for Bls12381Signature { 204 | fn from(signature: [u8; Self::LENGTH]) -> Self { 205 | Self::new(signature) 206 | } 207 | } 208 | 209 | impl std::fmt::Display for Bls12381Signature { 210 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 211 | std::fmt::Display::fmt(&super::Base64Display48(&self.0), f) 212 | } 213 | } 214 | 215 | impl std::fmt::Debug for Bls12381Signature { 216 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 217 | f.debug_tuple("Bls12381Signature") 218 | .field(&format_args!("\"{}\"", self)) 219 | .finish() 220 | } 221 | } 222 | -------------------------------------------------------------------------------- /crates/sui-sdk-types/src/crypto/ed25519.rs: -------------------------------------------------------------------------------- 1 | //! Implementation of ed25519 public-key cryptogrophy. 2 | 3 | /// An ed25519 public key. 4 | /// 5 | /// # BCS 6 | /// 7 | /// The BCS serialized form for this type is defined by the following ABNF: 8 | /// 9 | /// ```text 10 | /// ed25519-public-key = 32OCTECT 11 | /// ``` 12 | #[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] 13 | #[cfg_attr( 14 | feature = "serde", 15 | derive(serde_derive::Serialize, serde_derive::Deserialize) 16 | )] 17 | #[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))] 18 | pub struct Ed25519PublicKey( 19 | #[cfg_attr( 20 | feature = "serde", 21 | serde(with = "::serde_with::As::<::serde_with::IfIsHumanReadable>") 22 | )] 23 | [u8; Self::LENGTH], 24 | ); 25 | 26 | impl Ed25519PublicKey { 27 | /// The length of an ed25519 public key in bytes. 28 | pub const LENGTH: usize = 32; 29 | 30 | pub const fn new(bytes: [u8; Self::LENGTH]) -> Self { 31 | Self(bytes) 32 | } 33 | 34 | #[cfg(feature = "rand")] 35 | #[cfg_attr(doc_cfg, doc(cfg(feature = "rand")))] 36 | pub fn generate(mut rng: R) -> Self 37 | where 38 | R: rand_core::RngCore + rand_core::CryptoRng, 39 | { 40 | let mut buf: [u8; Self::LENGTH] = [0; Self::LENGTH]; 41 | rng.fill_bytes(&mut buf); 42 | Self::new(buf) 43 | } 44 | 45 | /// Return the underlying byte array of an Ed25519PublicKey. 46 | pub const fn into_inner(self) -> [u8; Self::LENGTH] { 47 | self.0 48 | } 49 | 50 | pub const fn inner(&self) -> &[u8; Self::LENGTH] { 51 | &self.0 52 | } 53 | 54 | pub const fn as_bytes(&self) -> &[u8] { 55 | &self.0 56 | } 57 | 58 | pub fn from_bytes>(bytes: T) -> Result { 59 | <[u8; Self::LENGTH]>::try_from(bytes.as_ref()).map(Self) 60 | } 61 | } 62 | 63 | impl std::str::FromStr for Ed25519PublicKey { 64 | type Err = base64ct::Error; 65 | 66 | fn from_str(s: &str) -> Result { 67 | super::Base64FromStr32::from_str(s).map(|a| Self::new(a.0)) 68 | } 69 | } 70 | 71 | impl AsRef<[u8]> for Ed25519PublicKey { 72 | fn as_ref(&self) -> &[u8] { 73 | &self.0 74 | } 75 | } 76 | 77 | impl AsRef<[u8; Self::LENGTH]> for Ed25519PublicKey { 78 | fn as_ref(&self) -> &[u8; Self::LENGTH] { 79 | &self.0 80 | } 81 | } 82 | 83 | impl From for [u8; Ed25519PublicKey::LENGTH] { 84 | fn from(public_key: Ed25519PublicKey) -> Self { 85 | public_key.into_inner() 86 | } 87 | } 88 | 89 | impl From<[u8; Self::LENGTH]> for Ed25519PublicKey { 90 | fn from(public_key: [u8; Self::LENGTH]) -> Self { 91 | Self::new(public_key) 92 | } 93 | } 94 | 95 | impl std::fmt::Display for Ed25519PublicKey { 96 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 97 | std::fmt::Display::fmt(&super::Base64Display32(&self.0), f) 98 | } 99 | } 100 | 101 | impl std::fmt::Debug for Ed25519PublicKey { 102 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 103 | f.debug_tuple("Ed25519PublicKey") 104 | .field(&format_args!("\"{}\"", self)) 105 | .finish() 106 | } 107 | } 108 | 109 | /// An ed25519 signature. 110 | /// 111 | /// # BCS 112 | /// 113 | /// The BCS serialized form for this type is defined by the following ABNF: 114 | /// 115 | /// ```text 116 | /// ed25519-signature = 64OCTECT 117 | /// ``` 118 | #[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] 119 | #[cfg_attr( 120 | feature = "serde", 121 | derive(serde_derive::Serialize, serde_derive::Deserialize) 122 | )] 123 | #[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))] 124 | pub struct Ed25519Signature( 125 | #[cfg_attr( 126 | feature = "serde", 127 | serde( 128 | with = "::serde_with::As::<::serde_with::IfIsHumanReadable>" 129 | ) 130 | )] 131 | [u8; Self::LENGTH], 132 | ); 133 | 134 | impl Ed25519Signature { 135 | /// The length of an ed25519 signature key in bytes. 136 | pub const LENGTH: usize = 64; 137 | 138 | pub const fn new(bytes: [u8; Self::LENGTH]) -> Self { 139 | Self(bytes) 140 | } 141 | 142 | #[cfg(feature = "rand")] 143 | #[cfg_attr(doc_cfg, doc(cfg(feature = "rand")))] 144 | pub fn generate(mut rng: R) -> Self 145 | where 146 | R: rand_core::RngCore + rand_core::CryptoRng, 147 | { 148 | let mut buf: [u8; Self::LENGTH] = [0; Self::LENGTH]; 149 | rng.fill_bytes(&mut buf); 150 | Self::new(buf) 151 | } 152 | 153 | /// Return the underlying byte array of an Ed25519Signature. 154 | pub const fn into_inner(self) -> [u8; Self::LENGTH] { 155 | self.0 156 | } 157 | 158 | pub const fn inner(&self) -> &[u8; Self::LENGTH] { 159 | &self.0 160 | } 161 | 162 | pub const fn as_bytes(&self) -> &[u8] { 163 | &self.0 164 | } 165 | 166 | pub fn from_bytes>(bytes: T) -> Result { 167 | <[u8; Self::LENGTH]>::try_from(bytes.as_ref()).map(Self) 168 | } 169 | } 170 | 171 | impl std::str::FromStr for Ed25519Signature { 172 | type Err = base64ct::Error; 173 | 174 | fn from_str(s: &str) -> Result { 175 | super::Base64FromStr64::from_str(s).map(|a| Self::new(a.0)) 176 | } 177 | } 178 | 179 | impl AsRef<[u8]> for Ed25519Signature { 180 | fn as_ref(&self) -> &[u8] { 181 | &self.0 182 | } 183 | } 184 | 185 | impl AsRef<[u8; Self::LENGTH]> for Ed25519Signature { 186 | fn as_ref(&self) -> &[u8; Self::LENGTH] { 187 | &self.0 188 | } 189 | } 190 | 191 | impl From for [u8; Ed25519Signature::LENGTH] { 192 | fn from(signature: Ed25519Signature) -> Self { 193 | signature.into_inner() 194 | } 195 | } 196 | 197 | impl From<[u8; Self::LENGTH]> for Ed25519Signature { 198 | fn from(signature: [u8; Self::LENGTH]) -> Self { 199 | Self::new(signature) 200 | } 201 | } 202 | 203 | impl std::fmt::Display for Ed25519Signature { 204 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 205 | std::fmt::Display::fmt(&super::Base64Display64(&self.0), f) 206 | } 207 | } 208 | 209 | impl std::fmt::Debug for Ed25519Signature { 210 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 211 | f.debug_tuple("Ed25519Signature") 212 | .field(&format_args!("\"{}\"", self)) 213 | .finish() 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /crates/sui-sdk-types/src/crypto/intent.rs: -------------------------------------------------------------------------------- 1 | /// A Signing Intent 2 | /// 3 | /// An intent is a compact struct serves as the domain separator for a message that a signature 4 | /// commits to. It consists of three parts: 5 | /// 1. [enum IntentScope] (what the type of the message is) 6 | /// 2. [enum IntentVersion] 7 | /// 3. [enum AppId] (what application that the signature refers to). 8 | /// 9 | /// The serialization of an Intent is a 3-byte array where each field is represented by a byte and 10 | /// it is prepended onto a message before it is signed in Sui. 11 | /// 12 | /// # BCS 13 | /// 14 | /// The BCS serialized form for this type is defined by the following ABNF: 15 | /// 16 | /// ```text 17 | /// intent = intent-scope intent-version intent-app-id 18 | /// ``` 19 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] 20 | pub struct Intent { 21 | pub scope: IntentScope, 22 | pub version: IntentVersion, 23 | pub app_id: IntentAppId, 24 | } 25 | 26 | impl Intent { 27 | pub fn new(scope: IntentScope, version: IntentVersion, app_id: IntentAppId) -> Self { 28 | Self { 29 | scope, 30 | version, 31 | app_id, 32 | } 33 | } 34 | 35 | pub fn to_bytes(self) -> [u8; 3] { 36 | [self.scope as u8, self.version as u8, self.app_id as u8] 37 | } 38 | 39 | pub fn scope(self) -> IntentScope { 40 | self.scope 41 | } 42 | 43 | pub fn version(self) -> IntentVersion { 44 | self.version 45 | } 46 | 47 | pub fn app_id(self) -> IntentAppId { 48 | self.app_id 49 | } 50 | } 51 | 52 | /// Byte signifying the scope of an [`Intent`] 53 | /// 54 | /// # BCS 55 | /// 56 | /// The BCS serialized form for this type is defined by the following ABNF: 57 | /// 58 | /// ```text 59 | /// intent-scope = u8 60 | /// ``` 61 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] 62 | #[repr(u8)] 63 | #[non_exhaustive] 64 | pub enum IntentScope { 65 | TransactionData = 0, // Used for a user signature on a transaction data. 66 | TransactionEffects = 1, // Used for an authority signature on transaction effects. 67 | CheckpointSummary = 2, // Used for an authority signature on a checkpoint summary. 68 | PersonalMessage = 3, // Used for a user signature on a personal message. 69 | SenderSignedTransaction = 4, // Used for an authority signature on a user signed transaction. 70 | ProofOfPossession = 5, // Used as a signature representing an authority's proof of possession of its authority protocol key. 71 | HeaderDigest = 6, // Used for narwhal authority signature on header digest. 72 | BridgeEventUnused = 7, // for bridge purposes but it's currently not included in messages. 73 | ConsensusBlock = 8, // Used for consensus authority signature on block's digest 74 | } 75 | 76 | /// Byte signifying the version of an [`Intent`] 77 | /// 78 | /// # BCS 79 | /// 80 | /// The BCS serialized form for this type is defined by the following ABNF: 81 | /// 82 | /// ```text 83 | /// intent-version = u8 84 | /// ``` 85 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] 86 | #[repr(u8)] 87 | #[non_exhaustive] 88 | pub enum IntentVersion { 89 | V0 = 0, 90 | } 91 | 92 | /// Byte signifying the application id of an [`Intent`] 93 | /// 94 | /// # BCS 95 | /// 96 | /// The BCS serialized form for this type is defined by the following ABNF: 97 | /// 98 | /// ```text 99 | /// intent-app-id = u8 100 | /// ``` 101 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] 102 | #[repr(u8)] 103 | #[non_exhaustive] 104 | pub enum IntentAppId { 105 | Sui = 0, 106 | Narwhal = 1, 107 | Consensus = 2, 108 | } 109 | -------------------------------------------------------------------------------- /crates/sui-sdk-types/src/crypto/mod.rs: -------------------------------------------------------------------------------- 1 | mod bls12381; 2 | mod ed25519; 3 | mod intent; 4 | mod multisig; 5 | mod passkey; 6 | mod secp256k1; 7 | mod secp256r1; 8 | mod signature; 9 | mod validator; 10 | mod zklogin; 11 | 12 | pub use bls12381::Bls12381PublicKey; 13 | pub use bls12381::Bls12381Signature; 14 | pub use ed25519::Ed25519PublicKey; 15 | pub use ed25519::Ed25519Signature; 16 | pub use intent::Intent; 17 | pub use intent::IntentAppId; 18 | pub use intent::IntentScope; 19 | pub use intent::IntentVersion; 20 | pub use multisig::MultisigAggregatedSignature; 21 | pub use multisig::MultisigCommittee; 22 | pub use multisig::MultisigMember; 23 | pub use multisig::MultisigMemberPublicKey; 24 | pub use multisig::MultisigMemberSignature; 25 | pub use passkey::PasskeyAuthenticator; 26 | pub use passkey::PasskeyPublicKey; 27 | pub use secp256k1::Secp256k1PublicKey; 28 | pub use secp256k1::Secp256k1Signature; 29 | pub use secp256r1::Secp256r1PublicKey; 30 | pub use secp256r1::Secp256r1Signature; 31 | pub use signature::SignatureScheme; 32 | pub use signature::SimpleSignature; 33 | pub use signature::UserSignature; 34 | pub use validator::ValidatorAggregatedSignature; 35 | pub use validator::ValidatorCommittee; 36 | pub use validator::ValidatorCommitteeMember; 37 | pub use validator::ValidatorSignature; 38 | pub use zklogin::Bn254FieldElement; 39 | pub use zklogin::CircomG1; 40 | pub use zklogin::CircomG2; 41 | pub use zklogin::Jwk; 42 | pub use zklogin::JwkId; 43 | pub use zklogin::ZkLoginAuthenticator; 44 | pub use zklogin::ZkLoginClaim; 45 | pub use zklogin::ZkLoginInputs; 46 | pub use zklogin::ZkLoginProof; 47 | pub use zklogin::ZkLoginPublicIdentifier; 48 | 49 | // 50 | // Implement various base64 fixed-size array helpers 51 | // 52 | 53 | /// Utility for calculating base64 encoding lenghths. 54 | /// 55 | /// In the Base64 encoding each character is used to represent 6 bits (log2(64) = 6). This means 56 | /// that 4 characters are used to represnet 4*6 = 24 bits = 3 bytes. So you need 4*(`n`/3) 57 | /// characters in order to represent `n` bytes, and this needs to be rounded up to a multiple of 4. 58 | /// The number of unused padding characters resulting from the rounding will be 0, 1, 2, or 3. 59 | const fn base64_encoded_length(len: usize) -> usize { 60 | ((4 * len / 3) + 3) & !3 61 | } 62 | 63 | macro_rules! impl_base64_helper { 64 | ($base:ident, $display:ident, $fromstr:ident, $test_module:ident, $array_length:literal) => { 65 | #[allow(unused)] 66 | struct $base; 67 | 68 | impl $base { 69 | const LENGTH: usize = $array_length; 70 | #[allow(unused)] 71 | const ENCODED_LENGTH: usize = base64_encoded_length(Self::LENGTH); 72 | } 73 | 74 | #[allow(unused)] 75 | struct $display<'a>(&'a [u8; $base::LENGTH]); 76 | 77 | impl<'a> std::fmt::Display for $display<'a> { 78 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 79 | let mut buf = [0; $base::ENCODED_LENGTH]; 80 | let encoded = 81 | ::encode(self.0, &mut buf).unwrap(); 82 | f.write_str(encoded) 83 | } 84 | } 85 | 86 | #[allow(unused)] 87 | #[derive(Debug, PartialEq)] 88 | #[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))] 89 | struct $fromstr([u8; $base::LENGTH]); 90 | 91 | impl std::str::FromStr for $fromstr { 92 | type Err = base64ct::Error; 93 | 94 | fn from_str(s: &str) -> Result { 95 | let mut buf = [0; $base::LENGTH]; 96 | let decoded = ::decode(s, &mut buf)?; 97 | assert_eq!(decoded.len(), $base::LENGTH); 98 | Ok(Self(buf)) 99 | } 100 | } 101 | 102 | #[cfg(feature = "serde")] 103 | #[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))] 104 | impl serde_with::SerializeAs<[u8; Self::LENGTH]> for $base { 105 | fn serialize_as( 106 | source: &[u8; Self::LENGTH], 107 | serializer: S, 108 | ) -> Result 109 | where 110 | S: serde::Serializer, 111 | { 112 | let display = $display(source); 113 | serde_with::DisplayFromStr::serialize_as(&display, serializer) 114 | } 115 | } 116 | 117 | #[cfg(feature = "serde")] 118 | #[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))] 119 | impl<'de> serde_with::DeserializeAs<'de, [u8; Self::LENGTH]> for $base { 120 | fn deserialize_as(deserializer: D) -> Result<[u8; Self::LENGTH], D::Error> 121 | where 122 | D: serde::Deserializer<'de>, 123 | { 124 | let array: $fromstr = serde_with::DisplayFromStr::deserialize_as(deserializer)?; 125 | Ok(array.0) 126 | } 127 | } 128 | 129 | #[cfg(test)] 130 | mod $test_module { 131 | use super::$display; 132 | use super::$fromstr; 133 | use test_strategy::proptest; 134 | 135 | #[cfg(target_arch = "wasm32")] 136 | use wasm_bindgen_test::wasm_bindgen_test as test; 137 | 138 | #[proptest] 139 | fn roundtrip_display_fromstr(array: $fromstr) { 140 | let s = $display(&array.0).to_string(); 141 | let a = s.parse::<$fromstr>().unwrap(); 142 | assert_eq!(array, a); 143 | } 144 | } 145 | }; 146 | } 147 | 148 | impl_base64_helper!(Base64Array32, Base64Display32, Base64FromStr32, test32, 32); 149 | impl_base64_helper!(Base64Array33, Base64Display33, Base64FromStr33, test33, 33); 150 | impl_base64_helper!(Base64Array34, Base64Display34, Base64FromStr34, test34, 34); 151 | impl_base64_helper!(Base64Array48, Base64Display48, Base64FromStr48, test48, 48); 152 | impl_base64_helper!(Base64Array64, Base64Display64, Base64FromStr64, test64, 64); 153 | impl_base64_helper!(Base64Array96, Base64Display96, Base64FromStr96, test96, 96); 154 | -------------------------------------------------------------------------------- /crates/sui-sdk-types/src/crypto/secp256k1.rs: -------------------------------------------------------------------------------- 1 | //! Implementation of secp256k1 public-key cryptogrophy. 2 | 3 | /// A secp256k1 public key. 4 | /// 5 | /// # BCS 6 | /// 7 | /// The BCS serialized form for this type is defined by the following ABNF: 8 | /// 9 | /// ```text 10 | /// secp256k1-public-key = 33OCTECT 11 | /// ``` 12 | #[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] 13 | #[cfg_attr( 14 | feature = "serde", 15 | derive(serde_derive::Serialize, serde_derive::Deserialize) 16 | )] 17 | #[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))] 18 | pub struct Secp256k1PublicKey( 19 | #[cfg_attr( 20 | feature = "serde", 21 | serde( 22 | with = "::serde_with::As::<::serde_with::IfIsHumanReadable>" 23 | ) 24 | )] 25 | [u8; Self::LENGTH], 26 | ); 27 | 28 | impl Secp256k1PublicKey { 29 | /// The length of an secp256k1 public key in bytes. 30 | pub const LENGTH: usize = 33; 31 | 32 | pub const fn new(bytes: [u8; Self::LENGTH]) -> Self { 33 | Self(bytes) 34 | } 35 | 36 | #[cfg(feature = "rand")] 37 | #[cfg_attr(doc_cfg, doc(cfg(feature = "rand")))] 38 | pub fn generate(mut rng: R) -> Self 39 | where 40 | R: rand_core::RngCore + rand_core::CryptoRng, 41 | { 42 | let mut buf: [u8; Self::LENGTH] = [0; Self::LENGTH]; 43 | rng.fill_bytes(&mut buf); 44 | Self::new(buf) 45 | } 46 | 47 | /// Return the underlying byte array of an Secp256k1PublicKey. 48 | pub const fn into_inner(self) -> [u8; Self::LENGTH] { 49 | self.0 50 | } 51 | 52 | pub const fn inner(&self) -> &[u8; Self::LENGTH] { 53 | &self.0 54 | } 55 | 56 | pub const fn as_bytes(&self) -> &[u8] { 57 | &self.0 58 | } 59 | 60 | pub fn from_bytes>(bytes: T) -> Result { 61 | <[u8; Self::LENGTH]>::try_from(bytes.as_ref()).map(Self) 62 | } 63 | } 64 | 65 | impl std::str::FromStr for Secp256k1PublicKey { 66 | type Err = base64ct::Error; 67 | 68 | fn from_str(s: &str) -> Result { 69 | super::Base64FromStr33::from_str(s).map(|a| Self::new(a.0)) 70 | } 71 | } 72 | 73 | impl AsRef<[u8]> for Secp256k1PublicKey { 74 | fn as_ref(&self) -> &[u8] { 75 | &self.0 76 | } 77 | } 78 | 79 | impl AsRef<[u8; Self::LENGTH]> for Secp256k1PublicKey { 80 | fn as_ref(&self) -> &[u8; Self::LENGTH] { 81 | &self.0 82 | } 83 | } 84 | 85 | impl From for [u8; Secp256k1PublicKey::LENGTH] { 86 | fn from(public_key: Secp256k1PublicKey) -> Self { 87 | public_key.into_inner() 88 | } 89 | } 90 | 91 | impl From<[u8; Self::LENGTH]> for Secp256k1PublicKey { 92 | fn from(public_key: [u8; Self::LENGTH]) -> Self { 93 | Self::new(public_key) 94 | } 95 | } 96 | 97 | impl std::fmt::Display for Secp256k1PublicKey { 98 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 99 | std::fmt::Display::fmt(&super::Base64Display33(&self.0), f) 100 | } 101 | } 102 | 103 | impl std::fmt::Debug for Secp256k1PublicKey { 104 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 105 | f.debug_tuple("Secp256k1PublicKey") 106 | .field(&format_args!("\"{}\"", self)) 107 | .finish() 108 | } 109 | } 110 | 111 | /// A secp256k1 signature. 112 | /// 113 | /// # BCS 114 | /// 115 | /// The BCS serialized form for this type is defined by the following ABNF: 116 | /// 117 | /// ```text 118 | /// secp256k1-signature = 64OCTECT 119 | /// ``` 120 | #[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] 121 | #[cfg_attr( 122 | feature = "serde", 123 | derive(serde_derive::Serialize, serde_derive::Deserialize) 124 | )] 125 | #[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))] 126 | pub struct Secp256k1Signature( 127 | #[cfg_attr( 128 | feature = "serde", 129 | serde( 130 | with = "::serde_with::As::<::serde_with::IfIsHumanReadable>" 131 | ) 132 | )] 133 | [u8; Self::LENGTH], 134 | ); 135 | 136 | impl Secp256k1Signature { 137 | /// The length of an secp256k1 signature key in bytes. 138 | pub const LENGTH: usize = 64; 139 | 140 | pub const fn new(bytes: [u8; Self::LENGTH]) -> Self { 141 | Self(bytes) 142 | } 143 | 144 | #[cfg(feature = "rand")] 145 | #[cfg_attr(doc_cfg, doc(cfg(feature = "rand")))] 146 | pub fn generate(mut rng: R) -> Self 147 | where 148 | R: rand_core::RngCore + rand_core::CryptoRng, 149 | { 150 | let mut buf: [u8; Self::LENGTH] = [0; Self::LENGTH]; 151 | rng.fill_bytes(&mut buf); 152 | Self::new(buf) 153 | } 154 | 155 | /// Return the underlying byte array of an Secp256k1Signature. 156 | pub const fn into_inner(self) -> [u8; Self::LENGTH] { 157 | self.0 158 | } 159 | 160 | pub const fn inner(&self) -> &[u8; Self::LENGTH] { 161 | &self.0 162 | } 163 | 164 | pub const fn as_bytes(&self) -> &[u8] { 165 | &self.0 166 | } 167 | 168 | pub fn from_bytes>(bytes: T) -> Result { 169 | <[u8; Self::LENGTH]>::try_from(bytes.as_ref()).map(Self) 170 | } 171 | } 172 | 173 | impl std::str::FromStr for Secp256k1Signature { 174 | type Err = base64ct::Error; 175 | 176 | fn from_str(s: &str) -> Result { 177 | super::Base64FromStr64::from_str(s).map(|a| Self::new(a.0)) 178 | } 179 | } 180 | 181 | impl AsRef<[u8]> for Secp256k1Signature { 182 | fn as_ref(&self) -> &[u8] { 183 | &self.0 184 | } 185 | } 186 | 187 | impl AsRef<[u8; Self::LENGTH]> for Secp256k1Signature { 188 | fn as_ref(&self) -> &[u8; Self::LENGTH] { 189 | &self.0 190 | } 191 | } 192 | 193 | impl From for [u8; Secp256k1Signature::LENGTH] { 194 | fn from(signature: Secp256k1Signature) -> Self { 195 | signature.into_inner() 196 | } 197 | } 198 | 199 | impl From<[u8; Self::LENGTH]> for Secp256k1Signature { 200 | fn from(signature: [u8; Self::LENGTH]) -> Self { 201 | Self::new(signature) 202 | } 203 | } 204 | 205 | impl std::fmt::Display for Secp256k1Signature { 206 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 207 | std::fmt::Display::fmt(&super::Base64Display64(&self.0), f) 208 | } 209 | } 210 | 211 | impl std::fmt::Debug for Secp256k1Signature { 212 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 213 | f.debug_tuple("Secp256k1Signature") 214 | .field(&format_args!("\"{}\"", self)) 215 | .finish() 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /crates/sui-sdk-types/src/crypto/secp256r1.rs: -------------------------------------------------------------------------------- 1 | //! Implementation of secp256r1 public-key cryptogrophy. 2 | 3 | /// A secp256r1 public key. 4 | /// 5 | /// # BCS 6 | /// 7 | /// The BCS serialized form for this type is defined by the following ABNF: 8 | /// 9 | /// ```text 10 | /// secp256r1-public-key = 33OCTECT 11 | /// ``` 12 | #[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] 13 | #[cfg_attr( 14 | feature = "serde", 15 | derive(serde_derive::Serialize, serde_derive::Deserialize) 16 | )] 17 | #[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))] 18 | pub struct Secp256r1PublicKey( 19 | #[cfg_attr( 20 | feature = "serde", 21 | serde( 22 | with = "::serde_with::As::<::serde_with::IfIsHumanReadable>" 23 | ) 24 | )] 25 | [u8; Self::LENGTH], 26 | ); 27 | 28 | impl Secp256r1PublicKey { 29 | /// The length of an secp256r1 public key in bytes. 30 | pub const LENGTH: usize = 33; 31 | 32 | pub const fn new(bytes: [u8; Self::LENGTH]) -> Self { 33 | Self(bytes) 34 | } 35 | 36 | #[cfg(feature = "rand")] 37 | #[cfg_attr(doc_cfg, doc(cfg(feature = "rand")))] 38 | pub fn generate(mut rng: R) -> Self 39 | where 40 | R: rand_core::RngCore + rand_core::CryptoRng, 41 | { 42 | let mut buf: [u8; Self::LENGTH] = [0; Self::LENGTH]; 43 | rng.fill_bytes(&mut buf); 44 | Self::new(buf) 45 | } 46 | 47 | /// Return the underlying byte array of an Secp256r1PublicKey. 48 | pub const fn into_inner(self) -> [u8; Self::LENGTH] { 49 | self.0 50 | } 51 | 52 | pub const fn inner(&self) -> &[u8; Self::LENGTH] { 53 | &self.0 54 | } 55 | 56 | pub const fn as_bytes(&self) -> &[u8] { 57 | &self.0 58 | } 59 | 60 | pub fn from_bytes>(bytes: T) -> Result { 61 | <[u8; Self::LENGTH]>::try_from(bytes.as_ref()).map(Self) 62 | } 63 | } 64 | 65 | impl std::str::FromStr for Secp256r1PublicKey { 66 | type Err = base64ct::Error; 67 | 68 | fn from_str(s: &str) -> Result { 69 | super::Base64FromStr33::from_str(s).map(|a| Self::new(a.0)) 70 | } 71 | } 72 | 73 | impl AsRef<[u8]> for Secp256r1PublicKey { 74 | fn as_ref(&self) -> &[u8] { 75 | &self.0 76 | } 77 | } 78 | 79 | impl AsRef<[u8; Self::LENGTH]> for Secp256r1PublicKey { 80 | fn as_ref(&self) -> &[u8; Self::LENGTH] { 81 | &self.0 82 | } 83 | } 84 | 85 | impl From for [u8; Secp256r1PublicKey::LENGTH] { 86 | fn from(public_key: Secp256r1PublicKey) -> Self { 87 | public_key.into_inner() 88 | } 89 | } 90 | 91 | impl From<[u8; Self::LENGTH]> for Secp256r1PublicKey { 92 | fn from(public_key: [u8; Self::LENGTH]) -> Self { 93 | Self::new(public_key) 94 | } 95 | } 96 | 97 | impl std::fmt::Display for Secp256r1PublicKey { 98 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 99 | std::fmt::Display::fmt(&super::Base64Display33(&self.0), f) 100 | } 101 | } 102 | 103 | impl std::fmt::Debug for Secp256r1PublicKey { 104 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 105 | f.debug_tuple("Secp256r1PublicKey") 106 | .field(&format_args!("\"{}\"", self)) 107 | .finish() 108 | } 109 | } 110 | 111 | /// A secp256r1 signature. 112 | /// 113 | /// # BCS 114 | /// 115 | /// The BCS serialized form for this type is defined by the following ABNF: 116 | /// 117 | /// ```text 118 | /// secp256r1-signature = 64OCTECT 119 | /// ``` 120 | #[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] 121 | #[cfg_attr( 122 | feature = "serde", 123 | derive(serde_derive::Serialize, serde_derive::Deserialize) 124 | )] 125 | #[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))] 126 | pub struct Secp256r1Signature( 127 | #[cfg_attr( 128 | feature = "serde", 129 | serde( 130 | with = "::serde_with::As::<::serde_with::IfIsHumanReadable>" 131 | ) 132 | )] 133 | [u8; Self::LENGTH], 134 | ); 135 | 136 | impl Secp256r1Signature { 137 | /// The length of an secp256r1 signature key in bytes. 138 | pub const LENGTH: usize = 64; 139 | 140 | pub const fn new(bytes: [u8; Self::LENGTH]) -> Self { 141 | Self(bytes) 142 | } 143 | 144 | #[cfg(feature = "rand")] 145 | #[cfg_attr(doc_cfg, doc(cfg(feature = "rand")))] 146 | pub fn generate(mut rng: R) -> Self 147 | where 148 | R: rand_core::RngCore + rand_core::CryptoRng, 149 | { 150 | let mut buf: [u8; Self::LENGTH] = [0; Self::LENGTH]; 151 | rng.fill_bytes(&mut buf); 152 | Self::new(buf) 153 | } 154 | 155 | /// Return the underlying byte array of an Secp256r1Signature. 156 | pub const fn into_inner(self) -> [u8; Self::LENGTH] { 157 | self.0 158 | } 159 | 160 | pub const fn inner(&self) -> &[u8; Self::LENGTH] { 161 | &self.0 162 | } 163 | 164 | pub const fn as_bytes(&self) -> &[u8] { 165 | &self.0 166 | } 167 | 168 | pub fn from_bytes>(bytes: T) -> Result { 169 | <[u8; Self::LENGTH]>::try_from(bytes.as_ref()).map(Self) 170 | } 171 | } 172 | 173 | impl std::str::FromStr for Secp256r1Signature { 174 | type Err = base64ct::Error; 175 | 176 | fn from_str(s: &str) -> Result { 177 | super::Base64FromStr64::from_str(s).map(|a| Self::new(a.0)) 178 | } 179 | } 180 | 181 | impl AsRef<[u8]> for Secp256r1Signature { 182 | fn as_ref(&self) -> &[u8] { 183 | &self.0 184 | } 185 | } 186 | 187 | impl AsRef<[u8; Self::LENGTH]> for Secp256r1Signature { 188 | fn as_ref(&self) -> &[u8; Self::LENGTH] { 189 | &self.0 190 | } 191 | } 192 | 193 | impl From for [u8; Secp256r1Signature::LENGTH] { 194 | fn from(signature: Secp256r1Signature) -> Self { 195 | signature.into_inner() 196 | } 197 | } 198 | 199 | impl From<[u8; Self::LENGTH]> for Secp256r1Signature { 200 | fn from(signature: [u8; Self::LENGTH]) -> Self { 201 | Self::new(signature) 202 | } 203 | } 204 | 205 | impl std::fmt::Display for Secp256r1Signature { 206 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 207 | std::fmt::Display::fmt(&super::Base64Display64(&self.0), f) 208 | } 209 | } 210 | 211 | impl std::fmt::Debug for Secp256r1Signature { 212 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 213 | f.debug_tuple("Secp256r1Signature") 214 | .field(&format_args!("\"{}\"", self)) 215 | .finish() 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /crates/sui-sdk-types/src/crypto/validator.rs: -------------------------------------------------------------------------------- 1 | use super::Bls12381PublicKey; 2 | use super::Bls12381Signature; 3 | use crate::checkpoint::EpochId; 4 | use crate::checkpoint::StakeUnit; 5 | 6 | /// The Validator Set for a particular epoch. 7 | /// 8 | /// # BCS 9 | /// 10 | /// The BCS serialized form for this type is defined by the following ABNF: 11 | /// 12 | /// ```text 13 | /// validator-committee = u64 ; epoch 14 | /// (vector validator-committee-member) 15 | /// ``` 16 | #[derive(Clone, Debug, PartialEq, Eq)] 17 | #[cfg_attr( 18 | feature = "serde", 19 | derive(serde_derive::Serialize, serde_derive::Deserialize) 20 | )] 21 | #[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))] 22 | pub struct ValidatorCommittee { 23 | #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))] 24 | pub epoch: EpochId, 25 | pub members: Vec, 26 | } 27 | 28 | /// A member of a Validator Committee 29 | /// 30 | /// # BCS 31 | /// 32 | /// The BCS serialized form for this type is defined by the following ABNF: 33 | /// 34 | /// ```text 35 | /// validator-committee-member = bls-public-key 36 | /// u64 ; stake 37 | /// ``` 38 | #[derive(Clone, Debug, PartialEq, Eq)] 39 | #[cfg_attr( 40 | feature = "serde", 41 | derive(serde_derive::Serialize, serde_derive::Deserialize) 42 | )] 43 | #[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))] 44 | pub struct ValidatorCommitteeMember { 45 | pub public_key: Bls12381PublicKey, 46 | #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))] 47 | pub stake: StakeUnit, 48 | } 49 | 50 | /// An aggregated signature from multiple Validators. 51 | /// 52 | /// # BCS 53 | /// 54 | /// The BCS serialized form for this type is defined by the following ABNF: 55 | /// 56 | /// ```text 57 | /// validator-aggregated-signature = u64 ; epoch 58 | /// bls-signature 59 | /// roaring-bitmap 60 | /// roaring-bitmap = bytes ; where the contents of the bytes are valid 61 | /// ; according to the serialized spec for 62 | /// ; roaring bitmaps 63 | /// ``` 64 | /// 65 | /// See [here](https://github.com/RoaringBitmap/RoaringFormatSpec) for the specification for the 66 | /// serialized format of RoaringBitmaps. 67 | #[derive(Clone, Debug, PartialEq)] 68 | #[cfg_attr( 69 | feature = "serde", 70 | derive(serde_derive::Serialize, serde_derive::Deserialize) 71 | )] 72 | #[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))] 73 | pub struct ValidatorAggregatedSignature { 74 | #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))] 75 | pub epoch: EpochId, 76 | pub signature: Bls12381Signature, 77 | #[cfg_attr(feature = "serde", serde(with = "RoaringBitMapSerialization"))] 78 | #[cfg_attr( 79 | feature = "proptest", 80 | strategy(proptest::strategy::Just(roaring::RoaringBitmap::default())) 81 | )] 82 | pub bitmap: roaring::RoaringBitmap, 83 | } 84 | 85 | #[cfg(feature = "serde")] 86 | type RoaringBitMapSerialization = ::serde_with::As< 87 | ::serde_with::IfIsHumanReadable< 88 | crate::_serde::Base64RoaringBitmap, 89 | crate::_serde::BinaryRoaringBitmap, 90 | >, 91 | >; 92 | 93 | /// A signature from a Validator 94 | /// 95 | /// # BCS 96 | /// 97 | /// The BCS serialized form for this type is defined by the following ABNF: 98 | /// 99 | /// ```text 100 | /// validator-signature = u64 ; epoch 101 | /// bls-public-key 102 | /// bls-signature 103 | /// ``` 104 | #[derive(Clone, Debug, PartialEq, Eq)] 105 | #[cfg_attr( 106 | feature = "serde", 107 | derive(serde_derive::Serialize, serde_derive::Deserialize) 108 | )] 109 | #[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))] 110 | pub struct ValidatorSignature { 111 | #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))] 112 | pub epoch: EpochId, 113 | pub public_key: Bls12381PublicKey, 114 | pub signature: Bls12381Signature, 115 | } 116 | 117 | #[cfg(test)] 118 | mod test { 119 | use super::*; 120 | 121 | #[cfg(target_arch = "wasm32")] 122 | use wasm_bindgen_test::wasm_bindgen_test as test; 123 | 124 | #[cfg(feature = "serde")] 125 | #[test] 126 | fn aggregated_signature_fixture() { 127 | use base64ct::Base64; 128 | use base64ct::Encoding; 129 | 130 | const FIXTURE: &str = "CgAAAAAAAACZrBcXiqa0ttztfwrBxKzQRzIRnZhbmsQV7tqNXwiZQrRC+dVDbdua1Ety9uy2pCUSOjAAAAEAAAAAAAAAEAAAAAAA"; 131 | let bcs = Base64::decode_vec(FIXTURE).unwrap(); 132 | 133 | let signature: ValidatorAggregatedSignature = bcs::from_bytes(&bcs).unwrap(); 134 | let bytes = bcs::to_bytes(&signature).unwrap(); 135 | assert_eq!(bcs, bytes); 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /crates/sui-sdk-types/src/effects/fixtures/pyth-wormhole-v2: -------------------------------------------------------------------------------- 1 | AQBxAQAAAAAAADD/ZgAAAAAAMFOkAAAAAACErqIAAAAAAKykAQAAAAAAIBCPYA+f9gSzNLSje+MDzPBWDpqOpvQtu0265MXZW+b0AQIAAAAABiAUOBQJ3auLAOalC/9VMSUvsGa4bGQIrv54Y9OPBTaCZSBfH+wRRkJ05GUEx5PgsOOZpCEz81F9jCwUs1QiCd7RJSB/dI73DesmbvxRruLA4jmbOvqqDLs9E48R9B4xRvFxliCkMQ+AHI708jHheH8XEQqOL8fZuZdvGapkNADXidx6YCDoOQnM87HQH0Ys2HGVTLXmeiKIS1cvDQ66s7GXTwep9iDzrbQP2ziz+UBMRJyRCs9/hA/QRXyiFeygwWoorSC8oHJFfAUAAAAABwDfsrwrJ0TtGHdDd8yWiMqQf/Y5ABWAGpp5F+c4igzSAXFFfAUAAAAAIE/hKIavOElJNi9oycylqwwaBvy65KYtZpZpa/ic9btdAUAhOGNsBSJ7Juz36JIt1lS7+erxBqLssNEpdqT0mgJcASCzIfIG8wVyJl+x603CZfPIJOiXdeeOToIvMw2ScfbXhQFAIThjbAUieybs9+iSLdZUu/nq8Qai7LDRKXak9JoCXAAp43l4yxyVAb2l18EF8k8AWLwWaGN+MH+8KQ26SMuRjQFxRXwFAAAAACAjeAkD8+4odPp/GKagENbhaDDEETChFL3KHwtoOstwqAIrBTMBAAAAAAEgIwJnUenWsvcLmhn8VhByWalfsneOAsROaNGrwFORRxcCKwUzAQAAAAAAQ/UKD1xU1f+MryF7jcAB0mCQmTDBDkiSpVDTjKgxrIwBZkV8BQAAAAAggW4m8TzLR7RwNJ6Y5fV4G6h0IOJUaEr+AlNVmW54CEUAAqIS3mqd+jpp4iOHrPuvuxqeWRvZ1jbniV3PyN4F8zEBILT9ipeCItE9/jn1YBCgglORjN3drDkNk+6KljN+4/tCAAKiEt5qnfo6aeIjh6z7r7sanlkb2dY254ldz8jeBfMxAG4xom6fkD23sYkZ1L3Xt2NO6JC8YxvxFub58kqxbxMVAXFFfAUAAAAAIFShCPnpAkWYcQs6KUMEkX8m9ooVCOdF4pYlqYaCoLJ/AiEFMwEAAAAAASDPtuHwQK4s4+UwqTrq3/bFFYMWXh5tDxpRZgRl6w7NKwIhBTMBAAAAAACxekdIzh6eFTiGKR5XKaOuU/ZZbTOlpq9O821/DATnDwFxRXwFAAAAACDOI6egg8J0DcW3oHwv7gx+extRP+rwsFcBmzT9BG3XjwEQ9MLvfppjRFP6IXIsAXemx5INW8XqjrHVyJqCtmwdhQEgoCVrzLe9kHaWXQtdKSSTg3pfJJQSGoAhLCcR8brohHMBEPTC736aY0RT+iFyLAF3pseSDVvF6o6x1ciagrZsHYUA1ryZCBZDguHKlJ7hgJz+ClK87tLP81wEk/9SIc9VhJ4BcUV8BQAAAAAgLcR1vBnI7FlviKMyYBLmQuBrQ7UOrpg/Y885zwxgSkoBeduVmmW91BnKot19QOnyvWNCy1a+eAGOKX2zdoH81EwBIDBa+gO4/a/yPShaSlaQNF3/pL9353W4y07ZI/UXYElGAXnblZplvdQZyqLdfUDp8r1jQstWvngBjil9s3aB/NRMAPKOTkCpaUihmAX+dqTaNzomLarEdYi6x41zAzvOe1o4AXFFfAUAAAAAIJ3O01ezKrtkQg5/8qAnvYpcGH+HDpVx0rsqvp1jSWWrAu7/MgEAAAAAASAFHDvRmwDMmYiEY6Pj5pKOMwcY0C48eJq8iULP9ehWiwLu/zIBAAAAAAADrquX+Wz5h3/uKIMxXUWVUrK5Ie3BbXzqxuq5RN2IkZwAL0V8BQAAAAAgLspOAeF/5kiBhwlV/KcFy6rZwFRIv+b7k/uHl/BGP24AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgAaN+EBAAAAACCaysdBaTW8trki4GHjgSqZA8USG9oJpcz/AOwM6Y452R+TECOO6SmPtwPDQZAws1siuxzDcRPju1AHyZrseeW4AC9FfAUAAAAAIEmPLFNSCbMo85TwVtzEhwPvCRNQxVnnToHKf3uSXjWvAA== 2 | -------------------------------------------------------------------------------- /crates/sui-sdk-types/src/effects/mod.rs: -------------------------------------------------------------------------------- 1 | mod v1; 2 | mod v2; 3 | 4 | pub use v1::ModifiedAtVersion; 5 | pub use v1::ObjectReferenceWithOwner; 6 | pub use v1::TransactionEffectsV1; 7 | pub use v2::ChangedObject; 8 | pub use v2::IdOperation; 9 | pub use v2::ObjectIn; 10 | pub use v2::ObjectOut; 11 | pub use v2::TransactionEffectsV2; 12 | pub use v2::UnchangedSharedKind; 13 | pub use v2::UnchangedSharedObject; 14 | 15 | use crate::execution_status::ExecutionStatus; 16 | 17 | /// The output or effects of executing a transaction 18 | /// 19 | /// # BCS 20 | /// 21 | /// The BCS serialized form for this type is defined by the following ABNF: 22 | /// 23 | /// ```text 24 | /// transaction-effects = %x00 effects-v1 25 | /// =/ %x01 effects-v2 26 | /// ``` 27 | #[derive(Eq, PartialEq, Clone, Debug)] 28 | #[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))] 29 | pub enum TransactionEffects { 30 | V1(Box), 31 | V2(Box), 32 | } 33 | 34 | impl TransactionEffects { 35 | /// Return the status of the transaction. 36 | pub fn status(&self) -> &ExecutionStatus { 37 | match self { 38 | TransactionEffects::V1(e) => e.status(), 39 | TransactionEffects::V2(e) => e.status(), 40 | } 41 | } 42 | 43 | /// Return the epoch in which this transaction was executed. 44 | pub fn epoch(&self) -> u64 { 45 | match self { 46 | TransactionEffects::V1(e) => e.epoch(), 47 | TransactionEffects::V2(e) => e.epoch(), 48 | } 49 | } 50 | 51 | /// Return the gas cost summary of the transaction. 52 | pub fn gas_summary(&self) -> &crate::gas::GasCostSummary { 53 | match self { 54 | TransactionEffects::V1(e) => e.gas_summary(), 55 | TransactionEffects::V2(e) => e.gas_summary(), 56 | } 57 | } 58 | } 59 | 60 | #[cfg(feature = "serde")] 61 | #[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))] 62 | mod serialization { 63 | use super::TransactionEffects; 64 | use super::TransactionEffectsV1; 65 | use super::TransactionEffectsV2; 66 | 67 | use serde::Deserialize; 68 | use serde::Deserializer; 69 | use serde::Serialize; 70 | use serde::Serializer; 71 | 72 | #[derive(serde_derive::Serialize)] 73 | #[serde(tag = "version")] 74 | enum ReadableEffectsRef<'a> { 75 | #[serde(rename = "1")] 76 | V1(&'a TransactionEffectsV1), 77 | #[serde(rename = "2")] 78 | V2(&'a TransactionEffectsV2), 79 | } 80 | 81 | #[derive(serde_derive::Deserialize)] 82 | #[serde(tag = "version")] 83 | pub enum ReadableEffects { 84 | #[serde(rename = "1")] 85 | V1(Box), 86 | #[serde(rename = "2")] 87 | V2(Box), 88 | } 89 | 90 | #[derive(serde_derive::Serialize)] 91 | enum BinaryEffectsRef<'a> { 92 | V1(&'a TransactionEffectsV1), 93 | V2(&'a TransactionEffectsV2), 94 | } 95 | 96 | #[derive(serde_derive::Deserialize)] 97 | pub enum BinaryEffects { 98 | V1(Box), 99 | V2(Box), 100 | } 101 | 102 | impl Serialize for TransactionEffects { 103 | fn serialize(&self, serializer: S) -> Result 104 | where 105 | S: Serializer, 106 | { 107 | if serializer.is_human_readable() { 108 | let readable = match self { 109 | TransactionEffects::V1(fx) => ReadableEffectsRef::V1(fx), 110 | TransactionEffects::V2(fx) => ReadableEffectsRef::V2(fx), 111 | }; 112 | readable.serialize(serializer) 113 | } else { 114 | let binary = match self { 115 | TransactionEffects::V1(fx) => BinaryEffectsRef::V1(fx), 116 | TransactionEffects::V2(fx) => BinaryEffectsRef::V2(fx), 117 | }; 118 | binary.serialize(serializer) 119 | } 120 | } 121 | } 122 | 123 | impl<'de> Deserialize<'de> for TransactionEffects { 124 | fn deserialize(deserializer: D) -> Result 125 | where 126 | D: Deserializer<'de>, 127 | { 128 | if deserializer.is_human_readable() { 129 | ReadableEffects::deserialize(deserializer).map(|readable| match readable { 130 | ReadableEffects::V1(fx) => Self::V1(fx), 131 | ReadableEffects::V2(fx) => Self::V2(fx), 132 | }) 133 | } else { 134 | BinaryEffects::deserialize(deserializer).map(|binary| match binary { 135 | BinaryEffects::V1(fx) => Self::V1(fx), 136 | BinaryEffects::V2(fx) => Self::V2(fx), 137 | }) 138 | } 139 | } 140 | } 141 | 142 | #[cfg(test)] 143 | mod tests { 144 | use super::TransactionEffects; 145 | 146 | use base64ct::Base64; 147 | use base64ct::Encoding; 148 | 149 | #[cfg(target_arch = "wasm32")] 150 | use wasm_bindgen_test::wasm_bindgen_test as test; 151 | 152 | #[test] 153 | fn effects_fixtures() { 154 | const GENESIS_EFFECTS: &str = include_str!("fixtures/genesis-transaction-effects"); 155 | const PYTH_WORMHOLE_V2: &str = include_str!("fixtures/pyth-wormhole-v2"); 156 | 157 | for fixture in [GENESIS_EFFECTS, PYTH_WORMHOLE_V2] { 158 | let fixture = Base64::decode_vec(fixture.trim()).unwrap(); 159 | let fx: TransactionEffects = bcs::from_bytes(&fixture).unwrap(); 160 | assert_eq!(bcs::to_bytes(&fx).unwrap(), fixture); 161 | 162 | let json = serde_json::to_string_pretty(&fx).unwrap(); 163 | println!("{json}"); 164 | assert_eq!(fx, serde_json::from_str(&json).unwrap()); 165 | } 166 | } 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /crates/sui-sdk-types/src/events.rs: -------------------------------------------------------------------------------- 1 | use super::Address; 2 | use super::Identifier; 3 | use super::ObjectId; 4 | use super::StructTag; 5 | use super::TypeTag; 6 | 7 | /// Events emitted during the successful execution of a transaction 8 | /// 9 | /// # BCS 10 | /// 11 | /// The BCS serialized form for this type is defined by the following ABNF: 12 | /// 13 | /// ```text 14 | /// transaction-events = vector event 15 | /// ``` 16 | #[derive(Eq, PartialEq, Clone, Debug)] 17 | #[cfg_attr( 18 | feature = "serde", 19 | derive(serde_derive::Serialize, serde_derive::Deserialize) 20 | )] 21 | #[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))] 22 | pub struct TransactionEvents(pub Vec); 23 | 24 | /// An event 25 | /// 26 | /// # BCS 27 | /// 28 | /// The BCS serialized form for this type is defined by the following ABNF: 29 | /// 30 | /// ```text 31 | /// event = object-id identifier address struct-tag bytes 32 | /// ``` 33 | #[derive(PartialEq, Eq, Debug, Clone)] 34 | #[cfg_attr( 35 | feature = "serde", 36 | derive(serde_derive::Serialize, serde_derive::Deserialize) 37 | )] 38 | #[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))] 39 | pub struct Event { 40 | /// Package id of the top-level function invoked by a MoveCall command which triggered this 41 | /// event to be emitted. 42 | pub package_id: ObjectId, 43 | 44 | /// Module name of the top-level function invoked by a MoveCall command which triggered this 45 | /// event to be emitted. 46 | pub module: Identifier, 47 | 48 | /// Address of the account that sent the transaction where this event was emitted. 49 | pub sender: Address, 50 | 51 | /// The type of the event emitted 52 | #[cfg_attr(feature = "serde", serde(rename = "type"))] 53 | pub type_: StructTag, 54 | 55 | /// BCS serialized bytes of the event 56 | #[cfg_attr( 57 | feature = "serde", 58 | serde(with = "crate::_serde::ReadableBase64Encoded") 59 | )] 60 | pub contents: Vec, 61 | } 62 | 63 | #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] 64 | #[cfg_attr( 65 | feature = "serde", 66 | derive(serde_derive::Serialize, serde_derive::Deserialize) 67 | )] 68 | #[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))] 69 | pub struct BalanceChange { 70 | /// Owner of the balance change 71 | pub address: Address, 72 | 73 | /// Type of the Coin 74 | pub coin_type: TypeTag, 75 | 76 | /// The amount indicate the balance value changes. 77 | /// 78 | /// A negative amount means spending coin value and positive means receiving coin value. 79 | #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))] 80 | pub amount: i128, 81 | } 82 | -------------------------------------------------------------------------------- /crates/sui-sdk-types/src/framework.rs: -------------------------------------------------------------------------------- 1 | //! Rust definitions of move/sui framework types. 2 | 3 | use super::Object; 4 | use super::ObjectId; 5 | use super::TypeTag; 6 | use std::borrow::Cow; 7 | 8 | #[derive(Debug, Clone)] 9 | pub struct Coin<'a> { 10 | coin_type: Cow<'a, TypeTag>, 11 | id: ObjectId, 12 | balance: u64, 13 | } 14 | 15 | impl<'a> Coin<'a> { 16 | pub fn coin_type(&self) -> &TypeTag { 17 | &self.coin_type 18 | } 19 | 20 | pub fn id(&self) -> &ObjectId { 21 | &self.id 22 | } 23 | 24 | pub fn balance(&self) -> u64 { 25 | self.balance 26 | } 27 | 28 | pub fn try_from_object(object: &'a Object) -> Option { 29 | match &object.data { 30 | super::ObjectData::Struct(move_struct) => { 31 | let coin_type = move_struct.type_.is_coin()?; 32 | 33 | let contents = &move_struct.contents; 34 | if contents.len() != ObjectId::LENGTH + std::mem::size_of::() { 35 | return None; 36 | } 37 | 38 | let id = ObjectId::new((&contents[..ObjectId::LENGTH]).try_into().unwrap()); 39 | let balance = 40 | u64::from_le_bytes((&contents[ObjectId::LENGTH..]).try_into().unwrap()); 41 | 42 | Some(Self { 43 | coin_type: Cow::Borrowed(coin_type), 44 | id, 45 | balance, 46 | }) 47 | } 48 | _ => None, // package 49 | } 50 | } 51 | 52 | pub fn into_owned(self) -> Coin<'static> { 53 | Coin { 54 | coin_type: Cow::Owned(self.coin_type.into_owned()), 55 | id: self.id, 56 | balance: self.balance, 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /crates/sui-sdk-types/src/gas.rs: -------------------------------------------------------------------------------- 1 | /// Summary of gas charges. 2 | /// 3 | /// Storage is charged independently of computation. 4 | /// There are 3 parts to the storage charges: 5 | /// `storage_cost`: it is the charge of storage at the time the transaction is executed. 6 | /// The cost of storage is the number of bytes of the objects being mutated 7 | /// multiplied by a variable storage cost per byte 8 | /// `storage_rebate`: this is the amount a user gets back when manipulating an object. 9 | /// The `storage_rebate` is the `storage_cost` for an object minus fees. 10 | /// `non_refundable_storage_fee`: not all the value of the object storage cost is 11 | /// given back to user and there is a small fraction that 12 | /// is kept by the system. This value tracks that charge. 13 | /// 14 | /// When looking at a gas cost summary the amount charged to the user is 15 | /// `computation_cost + storage_cost - storage_rebate` 16 | /// and that is the amount that is deducted from the gas coins. 17 | /// `non_refundable_storage_fee` is collected from the objects being mutated/deleted 18 | /// and it is tracked by the system in storage funds. 19 | /// 20 | /// Objects deleted, including the older versions of objects mutated, have the storage field 21 | /// on the objects added up to a pool of "potential rebate". This rebate then is reduced 22 | /// by the "nonrefundable rate" such that: 23 | /// `potential_rebate(storage cost of deleted/mutated objects) = 24 | /// storage_rebate + non_refundable_storage_fee` 25 | /// 26 | /// # BCS 27 | /// 28 | /// The BCS serialized form for this type is defined by the following ABNF: 29 | /// 30 | /// ```text 31 | /// gas-cost-summary = u64 ; computation-cost 32 | /// u64 ; storage-cost 33 | /// u64 ; storage-rebate 34 | /// u64 ; non-refundable-storage-fee 35 | /// ``` 36 | #[derive(Clone, Debug, Default, PartialEq, Eq)] 37 | #[cfg_attr( 38 | feature = "serde", 39 | derive(serde_derive::Serialize, serde_derive::Deserialize) 40 | )] 41 | #[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))] 42 | pub struct GasCostSummary { 43 | /// Cost of computation/execution 44 | #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))] 45 | pub computation_cost: u64, 46 | 47 | /// Storage cost, it's the sum of all storage cost for all objects created or mutated. 48 | #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))] 49 | pub storage_cost: u64, 50 | 51 | /// The amount of storage cost refunded to the user for all objects deleted or mutated in the 52 | /// transaction. 53 | #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))] 54 | pub storage_rebate: u64, 55 | 56 | /// The fee for the rebate. The portion of the storage rebate kept by the system. 57 | #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))] 58 | pub non_refundable_storage_fee: u64, 59 | } 60 | 61 | impl GasCostSummary { 62 | /// Create a new gas cost summary. 63 | /// 64 | /// # Arguments 65 | /// * `computation_cost` - Cost of computation cost/execution. 66 | /// * `storage_cost` - Storage cost, it's the sum of all storage cost for all objects created or mutated. 67 | /// * `storage_rebate` - The amount of storage cost refunded to the user for all objects deleted or mutated in the transaction. 68 | /// * `non_refundable_storage_fee` - The fee for the rebate. The portion of the storage rebate kept by the system. 69 | pub fn new( 70 | computation_cost: u64, 71 | storage_cost: u64, 72 | storage_rebate: u64, 73 | non_refundable_storage_fee: u64, 74 | ) -> GasCostSummary { 75 | GasCostSummary { 76 | computation_cost, 77 | storage_cost, 78 | storage_rebate, 79 | non_refundable_storage_fee, 80 | } 81 | } 82 | 83 | /// The total gas used, which is the sum of computation and storage costs. 84 | pub fn gas_used(&self) -> u64 { 85 | self.computation_cost + self.storage_cost 86 | } 87 | 88 | /// The net gas usage, which is the total gas used minus the storage rebate. 89 | /// A positive number means used gas; negative number means refund. 90 | pub fn net_gas_usage(&self) -> i64 { 91 | self.gas_used() as i64 - self.storage_rebate as i64 92 | } 93 | } 94 | 95 | impl std::fmt::Display for GasCostSummary { 96 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 97 | write!(f, "computation_cost: {}, ", self.computation_cost)?; 98 | write!(f, "storage_cost: {}, ", self.storage_cost)?; 99 | write!(f, "storage_rebate: {}, ", self.storage_rebate)?; 100 | write!( 101 | f, 102 | "non_refundable_storage_fee: {}", 103 | self.non_refundable_storage_fee 104 | ) 105 | } 106 | } 107 | 108 | #[cfg(test)] 109 | mod test { 110 | use super::*; 111 | 112 | #[cfg(target_arch = "wasm32")] 113 | use wasm_bindgen_test::wasm_bindgen_test as test; 114 | 115 | #[test] 116 | #[cfg(feature = "serde")] 117 | fn formats() { 118 | let actual = GasCostSummary { 119 | computation_cost: 42, 120 | storage_cost: u64::MAX, 121 | storage_rebate: 0, 122 | non_refundable_storage_fee: 9, 123 | }; 124 | 125 | println!("{}", serde_json::to_string(&actual).unwrap()); 126 | println!("{:?}", bcs::to_bytes(&actual).unwrap()); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /crates/sui-sdk-types/src/object_id.rs: -------------------------------------------------------------------------------- 1 | use super::Address; 2 | 3 | /// An `ObjectId` is a 32-byte identifier used to uniquely identify an object on the Sui 4 | /// blockchain. 5 | /// 6 | /// ## Relationship to Address 7 | /// 8 | /// [`Address`]es and `ObjectId`s share the same 32-byte addressable space but are derived 9 | /// leveraging different domain-separator values to ensure, cryptographically, that there won't be 10 | /// any overlap, e.g. there can't be a valid `Object` whose `ObjectId` is equal to that of the 11 | /// `Address` of a user account. 12 | /// 13 | /// # BCS 14 | /// 15 | /// An `ObjectId`'s BCS serialized form is defined by the following: 16 | /// 17 | /// ```text 18 | /// object-id = 32*OCTET 19 | /// ``` 20 | #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 21 | #[cfg_attr( 22 | feature = "serde", 23 | derive(serde_derive::Serialize, serde_derive::Deserialize) 24 | )] 25 | #[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))] 26 | pub struct ObjectId(Address); 27 | 28 | impl ObjectId { 29 | pub const LENGTH: usize = Address::LENGTH; 30 | pub const ZERO: Self = Self(Address::ZERO); 31 | 32 | /// Generates a new ObjectId from the provided byte array. 33 | pub const fn new(bytes: [u8; Self::LENGTH]) -> Self { 34 | Self(Address::new(bytes)) 35 | } 36 | 37 | /// Returns the underlying byte array of an ObjectId. 38 | pub const fn into_inner(self) -> [u8; Self::LENGTH] { 39 | self.0.into_inner() 40 | } 41 | 42 | /// Returns a reference to the underlying byte array of an ObjectId. 43 | pub const fn inner(&self) -> &[u8; Self::LENGTH] { 44 | self.0.inner() 45 | } 46 | 47 | /// Returns a slice of bytes of an ObjectId. 48 | pub const fn as_bytes(&self) -> &[u8] { 49 | self.0.as_bytes() 50 | } 51 | 52 | /// Returns the underlying Address of an ObjectId. 53 | pub const fn as_address(&self) -> &Address { 54 | &self.0 55 | } 56 | } 57 | 58 | impl AsRef<[u8]> for ObjectId { 59 | fn as_ref(&self) -> &[u8] { 60 | self.0.as_ref() 61 | } 62 | } 63 | 64 | impl AsRef<[u8; 32]> for ObjectId { 65 | fn as_ref(&self) -> &[u8; 32] { 66 | self.0.as_ref() 67 | } 68 | } 69 | 70 | impl From for [u8; 32] { 71 | fn from(object_id: ObjectId) -> Self { 72 | object_id.into_inner() 73 | } 74 | } 75 | 76 | impl From<[u8; 32]> for ObjectId { 77 | fn from(object_id: [u8; 32]) -> Self { 78 | Self::new(object_id) 79 | } 80 | } 81 | 82 | impl From
for ObjectId { 83 | fn from(value: Address) -> Self { 84 | Self(value) 85 | } 86 | } 87 | 88 | impl From for Vec { 89 | fn from(value: ObjectId) -> Self { 90 | value.0.into() 91 | } 92 | } 93 | 94 | impl std::str::FromStr for ObjectId { 95 | type Err = super::address::AddressParseError; 96 | 97 | fn from_str(s: &str) -> Result { 98 | Address::from_str(s).map(Self) 99 | } 100 | } 101 | 102 | impl std::fmt::Display for ObjectId { 103 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 104 | self.0.fmt(f) 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /crates/sui-sdk-types/src/serialization_proptests.rs: -------------------------------------------------------------------------------- 1 | use crate::*; 2 | use test_strategy::proptest; 3 | 4 | #[cfg(target_arch = "wasm32")] 5 | use wasm_bindgen_test::wasm_bindgen_test as test; 6 | 7 | macro_rules! serialization_test { 8 | ($type:ident) => { 9 | paste::item! { 10 | #[cfg_attr(target_arch = "wasm32", proptest(cases = 50))] 11 | #[cfg_attr(not(target_arch = "wasm32"), proptest)] 12 | #[allow(non_snake_case)] 13 | fn [< test_roundtrip_ $type >] (instance: $type) { 14 | assert_roundtrip(&instance); 15 | } 16 | 17 | #[proptest] 18 | #[allow(non_snake_case)] 19 | fn [< fuzz_deserialization_ $type >] ( 20 | #[strategy(proptest::collection::vec(proptest::arbitrary::any::(), 0..=2048))] 21 | bytes: Vec, 22 | ) { 23 | let _: Result<$type, _> = bcs::from_bytes(&bytes); 24 | } 25 | } 26 | }; 27 | } 28 | 29 | fn assert_roundtrip(instance: &T) 30 | where 31 | T: serde::Serialize + for<'de> serde::Deserialize<'de> + PartialEq + std::fmt::Debug, 32 | { 33 | // println!("{instance:?}"); 34 | let bcs_bytes = bcs::to_bytes(instance).unwrap(); 35 | let deser_from_bcs_bytes = bcs::from_bytes::(&bcs_bytes).unwrap(); 36 | assert_eq!(instance, &deser_from_bcs_bytes); 37 | 38 | let json = serde_json::to_string(instance).unwrap(); 39 | let deser_from_json = serde_json::from_str::(&json).unwrap(); 40 | assert_eq!(instance, &deser_from_json); 41 | } 42 | 43 | serialization_test!(Address); 44 | serialization_test!(CheckpointCommitment); 45 | serialization_test!(CheckpointContents); 46 | serialization_test!(CheckpointData); 47 | serialization_test!(CheckpointSequenceNumber); 48 | serialization_test!(CheckpointSummary); 49 | serialization_test!(CheckpointTimestamp); 50 | serialization_test!(CheckpointTransaction); 51 | serialization_test!(CheckpointTransactionInfo); 52 | serialization_test!(EndOfEpochData); 53 | serialization_test!(SignedCheckpointSummary); 54 | serialization_test!(Bls12381PublicKey); 55 | serialization_test!(Bls12381Signature); 56 | serialization_test!(Bn254FieldElement); 57 | serialization_test!(ZkLoginClaim); 58 | serialization_test!(Ed25519PublicKey); 59 | serialization_test!(Ed25519Signature); 60 | serialization_test!(Jwk); 61 | serialization_test!(JwkId); 62 | serialization_test!(MultisigAggregatedSignature); 63 | serialization_test!(MultisigCommittee); 64 | serialization_test!(MultisigMember); 65 | serialization_test!(MultisigMemberPublicKey); 66 | serialization_test!(MultisigMemberSignature); 67 | serialization_test!(Secp256k1PublicKey); 68 | serialization_test!(Secp256k1Signature); 69 | serialization_test!(Secp256r1PublicKey); 70 | serialization_test!(Secp256r1Signature); 71 | serialization_test!(SimpleSignature); 72 | serialization_test!(UserSignature); 73 | serialization_test!(ValidatorAggregatedSignature); 74 | serialization_test!(ValidatorCommittee); 75 | serialization_test!(ValidatorCommitteeMember); 76 | serialization_test!(ValidatorSignature); 77 | serialization_test!(ZkLoginAuthenticator); 78 | serialization_test!(ZkLoginInputs); 79 | serialization_test!(ZkLoginProof); 80 | serialization_test!(ZkLoginPublicIdentifier); 81 | serialization_test!(CircomG1); 82 | serialization_test!(CircomG2); 83 | serialization_test!(PasskeyAuthenticator); 84 | serialization_test!(CheckpointContentsDigest); 85 | serialization_test!(CheckpointDigest); 86 | serialization_test!(ConsensusCommitDigest); 87 | serialization_test!(Digest); 88 | serialization_test!(EffectsAuxiliaryDataDigest); 89 | serialization_test!(ObjectDigest); 90 | serialization_test!(TransactionDigest); 91 | serialization_test!(TransactionEffectsDigest); 92 | serialization_test!(TransactionEventsDigest); 93 | serialization_test!(ChangedObject); 94 | serialization_test!(IdOperation); 95 | serialization_test!(ModifiedAtVersion); 96 | serialization_test!(ObjectIn); 97 | serialization_test!(ObjectOut); 98 | serialization_test!(ObjectReferenceWithOwner); 99 | serialization_test!(TransactionEffects); 100 | serialization_test!(TransactionEffectsV1); 101 | serialization_test!(TransactionEffectsV2); 102 | serialization_test!(UnchangedSharedKind); 103 | serialization_test!(UnchangedSharedObject); 104 | serialization_test!(BalanceChange); 105 | serialization_test!(Event); 106 | serialization_test!(TransactionEvents); 107 | serialization_test!(CommandArgumentError); 108 | serialization_test!(ExecutionError); 109 | serialization_test!(ExecutionStatus); 110 | serialization_test!(MoveLocation); 111 | serialization_test!(PackageUpgradeError); 112 | serialization_test!(TypeArgumentError); 113 | serialization_test!(GasCostSummary); 114 | serialization_test!(GenesisObject); 115 | serialization_test!(Object); 116 | serialization_test!(ObjectReference); 117 | serialization_test!(Owner); 118 | serialization_test!(TypeOrigin); 119 | serialization_test!(UpgradeInfo); 120 | serialization_test!(ObjectId); 121 | serialization_test!(ActiveJwk); 122 | serialization_test!(Argument); 123 | serialization_test!(AuthenticatorStateExpire); 124 | serialization_test!(AuthenticatorStateUpdate); 125 | serialization_test!(ChangeEpoch); 126 | serialization_test!(Command); 127 | serialization_test!(ConsensusCommitPrologue); 128 | serialization_test!(ConsensusCommitPrologueV2); 129 | serialization_test!(ConsensusCommitPrologueV3); 130 | serialization_test!(ConsensusCommitPrologueV4); 131 | serialization_test!(CanceledTransaction); 132 | serialization_test!(ConsensusDeterminedVersionAssignments); 133 | serialization_test!(VersionAssignment); 134 | serialization_test!(EndOfEpochTransactionKind); 135 | serialization_test!(GasPayment); 136 | serialization_test!(GenesisTransaction); 137 | serialization_test!(Input); 138 | serialization_test!(MakeMoveVector); 139 | serialization_test!(MergeCoins); 140 | serialization_test!(MoveCall); 141 | serialization_test!(ProgrammableTransaction); 142 | serialization_test!(Publish); 143 | serialization_test!(RandomnessStateUpdate); 144 | serialization_test!(SignedTransaction); 145 | serialization_test!(SplitCoins); 146 | serialization_test!(SystemPackage); 147 | serialization_test!(Transaction); 148 | serialization_test!(TransactionExpiration); 149 | serialization_test!(TransactionKind); 150 | serialization_test!(TransferObjects); 151 | serialization_test!(Upgrade); 152 | serialization_test!(Identifier); 153 | serialization_test!(StructTag); 154 | serialization_test!(TypeTag); 155 | -------------------------------------------------------------------------------- /crates/sui-sdk-types/src/transaction/fixtures/authenticator_state_update: -------------------------------------------------------------------------------- 1 | AARpAQAAAAAAAAoAAAAAAAAABRhodHRwczovL3d3dy5mYWNlYm9vay5jb20oMjdmMTRiZjllM2U5ZDFjN2JhNjkxYzllZTkxYTVmZDkyZWIzZDQwYwNSU0EEQVFBQtYCd1BHTy1IbUdvR2V5Z2t4VUR0QWdRdTV2WlRFbGhiSHJiTlVoSWFlMGRVd3BUREhIWUpLWTZuc2tUWUxON1NxczR4M3pYVUpyNlNpbGJCSVVBZktScWhEa0RQV1hlYXMxb3haRXFNYUQyYVdpa1RQaDBCSkNjLV9ZRDhUU0xvVW5RQWFjRWlnNzM0MnlZQVZRemdYLVV4WTR0U2tlQTA2cWJURDQ1OXhvZU9FUG5RRUY2T0RoeEpHbmFrSllLcVJVbnNTRG80d0o2NUlTS3g4Y3ROWHR4WEtjWlA5cnZOZmM3SW5PYUp5S1JvRDBVbHpCSEdVNU5lRk42VUpGaTFGamdlQ1pZT1M3VmpSNmZYbVJlenZXcUsxTlVaeG5vOHZBYXlpZllQcXQtMWxONTlWdnpmdjJucnVzQVg0cjRWMXY4YzVqc3UycHNwY0pSQlZvRlZSQWp3BVJTMjU2aQEAAAAAAAAYaHR0cHM6Ly93d3cuZmFjZWJvb2suY29tKGVjMTFkNTAzNDFjMDhlODI4OTk2NTBlNmFmY2M2NjY4ZjJhMGE0MjADUlNBBEFRQULWAi1ySjBIdmx4aXFPY3dmcFA2THNBWW8wYWFHTm1vaEVCRnIxSnVXQ0dWdm5QYjNaNUFrZDV3X2J4UU1SbE9Nb3QxNUl5cmhXRm9uV0NGcjlIMDJmOUU5R09FYXJvQWowenhRbkNYY3VHV2IxQkZONlJmb0dORnBlZTFNcVNEVjNpa1NJc1NJM0pMLXpfMXVCdERzUTFBdGJZTUtzQjU3MnY2NGJhcFc0V2pEamVrejBwUS1lUGl6VldtOW1OTlF4a0FfZmgzcDFoVzNLc3NYZ25hc1diS0pPRFQ1STZobnpkNHdoeGoyMm9MRTh4SkNZVEZlb3VrODZ0ZUtJLW52Sy1MbWF4b2V0QmhuRG4zUVM1cE5fb2lJZkRxaktQWEdhemVHMnF3R0FFOFZQZUlTUHZ6WUlzdEdiRWgzTkN6RkVvQjdhN0FQRjFuTEVvN0xjbzlhV2pZUQVSUzI1NmkBAAAAAAAAG2h0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbSg5MzRhNTgxNjQ2OGI5NTcwMzk1M2QxNGU5ZjE1ZGY1ZDA5YTQwMWU0A1JTQQRBUUFC1gJ1aFdScEozUE5aYWlCbXEzUDkxQTZRQjBiMjhMZVF2Vi1ISTBUQUVjTjVuZmZRUG05NHctaFkyUzZtVGhiN3hYTENHSGNQM2JocFdsMzFnaVpKRmx2ekhlNmRiLVRzUGw4SFNMZ0xJak1iTVQ4aVlXcVpQYTJlb2RpakVKcmtPNlNQZXg1akhMelN3R3NvUmRTZlc4aEZlVEZRazh4dFBYbTdHbEVFbzltRkVLVUFhQXJUOWFjZEU4aDUzVlI3WmtKa2lwaUxDdHgwcmh5U0EyVzRyRUFjaW5MRzNBcEc3MDlwT3c2c1ZqQTJJQVFtWlZZcmZRN2N1cm1GcUtXTF9GNTM0a0RoUUpMMmhNZHJ1YmhIY3FDeGV0eWlfVTdXRFdEa1lDSl9DZXRqRHNJMHlmd0Iyc1IwMXZuNkx1RERvNmhvOHBXSmNIT092WFlVblNNRkFsZXcFUlMyNTZpAQAAAAAAABtodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20oOTNiNDk1MTYyYWYwYzg3Y2M3YTUxNjg2Mjk0MDk3MDQwZGFmM2I0MwNSU0EEQVFBQtYCM05Yd0FTTmZfNy05aE9XREt5WjM5cWd6LXlsX25wdUlzQmd4bmhOb0U3V3lRUWwtbXVhalBzUVJkRnFNLUhXc0FBYlNfV3RMcm1mMmFSU21qWEJtOHdYSEllSmpjclppV2VVblN5ZlpMRHIxM2p4WGhOMHJEdmRpWkVzQWxhS3VoLWlDZ3dDX3BYZDBUdFdwYVlsdjVGRmd1dVNpdEtUT2lEUjZ6M2VTWlVkMFhOeHI4UE9DRFE3VmxHXzRIeXpoc083bk93Z2l2Ty1QemVrREViY29MSTkzVTh1ektaWFlIU1J4WVdob1NwNDdQYk05RDVXYnV3WHFibVhScDlUamlKVXk2R3FFT0o0SzJGTnZxZS1nNkMzQm5wUFZ1SFpOYVZmOFFHUDgwNnJXcldQZEowaXJHQmhnLUVhc0Mtc2RGU3JIM2t4TXhCRmZWc3VqNjlVLTdRBVJTMjU2aQEAAAAAAAAbaHR0cHM6Ly9pZC50d2l0Y2gudHYvb2F1dGgyATEDUlNBBEFRQULWAjZscTlNUS1xNmhjeHI3a09VcC10SGxIdGRjRHNWTHdWSXcxM2lYVUN2dURPZUNpMFZTdXhDQ1VZNlVtTWp5NTNkWDAwaWgyRTRZNFV2bHJtbXVySzBlRzI2Yi1ITU5OQXZDR3NWWEhVM1JjUmhWb0hEYU93SHdVNzJqN2JwSG45WGJQM1EzamViWDZLSWZOYmVpMk1pUjBXeWI4UlpIRS1hWmhSWU84Xy1rOUcyR3ljVHB2Yy0yR0JzUDhWSExVS0tmQXMyQjZzVzNxM3ltVTZNMEwtY0ZYa1o5ZkhrbjllanMtc3FaUGhNSnh0QlBCeG9VSVVRRlRndjRWWFRTdjkxNGZfWWtOdy1FanV3Ymd3WE12cHlyMDZFeWZJbXhIb3hzWmtGWUItcUJZSHRhTXhUbkZzWkJyNmZuOEhhMkpxVDFob1A3WjVyNXd4RHUzR1FoS2tIdwVSUzI1NmkBAAAAAAAAmSrgAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAA== 2 | -------------------------------------------------------------------------------- /crates/sui-sdk-types/src/transaction/fixtures/wormhole-pyth-transaction: -------------------------------------------------------------------------------- 1 | AAALAQGuq5f5bPmHf+4ogzFdRZVSsrkh7cFtfOrG6rlE3YiRnEAAAAAAAAAAAAC6B7gHAQAAAAMNAqkkqR+B2ZrTEj0MrF7FkK+vgn+jbLBE8ZwQLGSzsFBLHnSSQbhdfyDjHplBY2SYj0IsWLLzewrLAGBe9GORJZUBA0hqmLStg2FxI8mAp69K/a9+tRh6DhUN2iFVkwOfTYbcVPVD+uM1X6apuVa+WpMgKKPYcN4XKU3y8ouFNHkBOAIABGeyfpBJ2R7DPww7Ume+TMCEeRaMsP2w9pxEAbENXID8MVURf0zAH1T+uTs4tGT/GY6Q6Lm9e0joSCQoJVtppC0ABrSYDAFbm2AV7iSPFhLm3HPhwaGLPZFmrf7ELDy1TVS2EAUQBJ+Iswd35rsGMiCWUbT+Y5y72L1LKwHtp8ml/7oAB5idJHMpZwNQecSuRHVf4cPvllc1BsVn2ahoyE8LDeMzT/o3HEyy0QrzHJEvTu+bE8SYrZFD/EBGRmiGpFixl1kBCKr06IO2vsDsVyGbPbtbpVWPPrS5Sf7GRQ26Sp/AWXxQW/gptaTSs29Fl8vnRgBjQnxEXcLsG2+0VE4uN5HOxfoBChhN2f1fmItDiIiaFkXzCNkT+UmlA4LtYDi+uOoHAL/0RhLXR7hXzS7p2Vvq9CKL5Xl3/uO4/sj5B+bXALcffn4BC9tmtpPUxnNPon8sltMAaXDEYRK2mqw0Ov45Q+P3sK2BUCSelrZw4JzDNZuEm+N/mh25kDwxtAy3EpVFT+h1/KMBDD7Q9AVXoawj1r78XIDGsQslF6wUq7G0KOkH6Av23k5wQcVZM8QeTKC6iFlv9002iq+xzG+U3jw+xG85KY8BvNcADQwXr12bQHFxwLyU2mP6MQmX6KGfnHdv8kc42pTD4fEaa3JJYwaJB65upo3BuX+2LapZiKGt/Slt8W4wa18OMg0ADh9qqgBawIhlSyTDGuQdK/JaSryh4/QPVefZ4a+CYvF2CgSPL6OSiFqDJSx/9ajwS6mhHPTrJXdshpYGDOc30R4BEJyU2xqX5ixcvId1co/UC4rtVgCpPOK9b2CZQV8BdHORdLVeuSp9Oofjl+DUtVbVdE6awaouuUla1jDh48odi9cAEiC1vGoh3YIXfR4XEZLJREbfdjjp280XJs2I7Xc+WWvfGiIxHKpFMpRj6ZsFr9dV0VJRI737BdZsXtH6uokbLYYBZhRBqQAAAAAAGuEB+u2sWFHjK5sjtflBGowrrEquPtTde4Ed0acupKpxAAAAAALwtWUBQVVXVgAAAAAAB/qmOQAAJxAmcGqoFzwyGGBL+CWPM8oI0FKRTwEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYBAAAAAAAAAAABAR+TECOO6SmPtwPDQZAws1siuxzDcRPju1AHyZrseeW4hmQMAQAAAAAAAKUOow5QTkFVAQAAAAO4AQAAAAMNAqkkqR+B2ZrTEj0MrF7FkK+vgn+jbLBE8ZwQLGSzsFBLHnSSQbhdfyDjHplBY2SYj0IsWLLzewrLAGBe9GORJZUBA0hqmLStg2FxI8mAp69K/a9+tRh6DhUN2iFVkwOfTYbcVPVD+uM1X6apuVa+WpMgKKPYcN4XKU3y8ouFNHkBOAIABGeyfpBJ2R7DPww7Ume+TMCEeRaMsP2w9pxEAbENXID8MVURf0zAH1T+uTs4tGT/GY6Q6Lm9e0joSCQoJVtppC0ABrSYDAFbm2AV7iSPFhLm3HPhwaGLPZFmrf7ELDy1TVS2EAUQBJ+Iswd35rsGMiCWUbT+Y5y72L1LKwHtp8ml/7oAB5idJHMpZwNQecSuRHVf4cPvllc1BsVn2ahoyE8LDeMzT/o3HEyy0QrzHJEvTu+bE8SYrZFD/EBGRmiGpFixl1kBCKr06IO2vsDsVyGbPbtbpVWPPrS5Sf7GRQ26Sp/AWXxQW/gptaTSs29Fl8vnRgBjQnxEXcLsG2+0VE4uN5HOxfoBChhN2f1fmItDiIiaFkXzCNkT+UmlA4LtYDi+uOoHAL/0RhLXR7hXzS7p2Vvq9CKL5Xl3/uO4/sj5B+bXALcffn4BC9tmtpPUxnNPon8sltMAaXDEYRK2mqw0Ov45Q+P3sK2BUCSelrZw4JzDNZuEm+N/mh25kDwxtAy3EpVFT+h1/KMBDD7Q9AVXoawj1r78XIDGsQslF6wUq7G0KOkH6Av23k5wQcVZM8QeTKC6iFlv9002iq+xzG+U3jw+xG85KY8BvNcADQwXr12bQHFxwLyU2mP6MQmX6KGfnHdv8kc42pTD4fEaa3JJYwaJB65upo3BuX+2LapZiKGt/Slt8W4wa18OMg0ADh9qqgBawIhlSyTDGuQdK/JaSryh4/QPVefZ4a+CYvF2CgSPL6OSiFqDJSx/9ajwS6mhHPTrJXdshpYGDOc30R4BEJyU2xqX5ixcvId1co/UC4rtVgCpPOK9b2CZQV8BdHORdLVeuSp9Oofjl+DUtVbVdE6awaouuUla1jDh48odi9cAEiC1vGoh3YIXfR4XEZLJREbfdjjp280XJs2I7Xc+WWvfGiIxHKpFMpRj6ZsFr9dV0VJRI737BdZsXtH6uokbLYYBZhRBqQAAAAAAGuEB+u2sWFHjK5sjtflBGowrrEquPtTde4Ed0acupKpxAAAAAALwtWUBQVVXVgAAAAAAB/qmOQAAJxAmcGqoFzwyGGBL+CWPM8oI0FKRTwMAVQDWg1rR93PeSjeBFetoJL0MDkLYTRyE2XUOhT+2tsd5SgAAAAAriin5AAAAAAAHbs/////4AAAAAGYUQakAAAAAZhRBqAAAAAAroGo4AAAAAAAIIuwKLVSVy/SaALRvNKuxC40EvMmhTcJNhPRamT70Mdg/L9pgzFF3uvz47oVRLwoprzj2tNe0Wn4AVQAck4SRmO54NkuVYEp4nzxHxUlFg3pi/e15gY0yRmL4FKZX2RGfJvt9pcttoj/z+k6vbyyzhxZrQZ0rfxdNw9njX2VEkISLn5XVmnyQ08fYrCHuH/G7jrEREKrDnt8o9QqE8dWqMr12teUtQ+bxbrDNBQPqQeSR1dYuNnyAD/99htj/y1cCF7VI1F9ayl3I9msAVQAJ98HX37t98rj+PT2H7pSiJZ0hLaTzDB8FQNBm36RHIwAAAABKFqzAAAAAAAATDIf////4AAAAAGYUQakAAAAAZhRBqAAAAABKDM7kAAAAAAAUD/YKRlYh9/j9P0RO59IHOzNva7uZi1XVUKtdqL2zrPWZXsOLJKMmSG2STfIvJNZEZVIr+njrENVduuRmU7C4qi2vKE3wxMcB2oqWkd/eSM2qWLDApcGLwwdClVLq9KKLoqqdDWquyenWT+vwKRfFKbuwFXxtTKxqOdFhZbVaLQFRcn+W1z4n3zSJY6kP2RiQpuv2kevc4kofG916dt0+FH7XU5WunX1LXnnOzKXfBGh4YUHRhEoSD/99htj/y1cCF7VI1F9ayl3I9msAVQADrk2yntSuM9MjVoiVqgAzfmWONIs3UJ9Tcq5R8K8A1QAAAABUNXjEAAAAAAAW8rr////4AAAAAGYUQakAAAAAZhRBqAAAAABURe+AAAAAAAATXIEKfMP4zuRvCdw9L4ZIIuRx0YMLYKtr4oWLWn2nRu8zvI5XIOpJ2cwpdKPN9iMDZQfVI0WSTCEIinsvxv1/49nGpj2vzMBT9+fVMjYUMR8GmhrApcGLwwdClVLq9KKLoqqdDWquyenWT+vwKRfFKbuwFXxtTKxqOdFhZbVaLQFRcn+W1z4n3zSJY6kP2RiQpuv2kevc4kofG916dt0+FH7XU5WunX1LXnnOzKXfBGh4YUHRhEoSD/99htj/y1cCF7VI1F9ayl3I9msACAEAAAAAAAAAAAgBAAAAAAAAAAAIAQAAAAAAAAABAccmZSWHjJfQUxOR3tuMTEwTxBk54ozTb4kyTTyq6OZCMQUzAQAAAAABAQH6PVF+auJkdwgxP4Ef5/SB+CVM1zgHPj4j38o7V4wh0uDYAAQAAAAAAQEBfFt4N8RKabRpMlRjrAZzrBqoQ1/0TdtBkcmuOARjZH/q/zIBAAAAAAEHAFMG9k4xK1gXZjUcB695xy/LHNJRRxV/3C+K123po/tqA3ZhYRBwYXJzZV9hbmRfdmVyaWZ5AAMBAAABAQABAgAABOIN3zavQSpAlvkBT0pWWvnoEtuaBcxAJUhGz27QrZEEcHl0aDJjcmVhdGVfYXV0aGVudGljYXRlZF9wcmljZV9pbmZvc191c2luZ19hY2N1bXVsYXRvcgAEAQMAAQQAAwAAAAABAgACAAMBBQABBgABBwAABOIN3zavQSpAlvkBT0pWWvnoEtuaBcxAJUhGz27QrZEEcHl0aBh1cGRhdGVfc2luZ2xlX3ByaWNlX2ZlZWQABQEDAAMBAAAAAQgAAwIAAAABAgAABOIN3zavQSpAlvkBT0pWWvnoEtuaBcxAJUhGz27QrZEEcHl0aBh1cGRhdGVfc2luZ2xlX3ByaWNlX2ZlZWQABQEDAAMDAAAAAQkAAwIAAQABAgAABOIN3zavQSpAlvkBT0pWWvnoEtuaBcxAJUhGz27QrZEEcHl0aBh1cGRhdGVfc2luZ2xlX3ByaWNlX2ZlZWQABQEDAAMEAAAAAQoAAwIAAgABAgAABOIN3zavQSpAlvkBT0pWWvnoEtuaBcxAJUhGz27QrZERaG90X3BvdGF0b192ZWN0b3IHZGVzdHJveQEHBOIN3zavQSpAlvkBT0pWWvnoEtuaBcxAJUhGz27QrZEKcHJpY2VfaW5mbwlQcmljZUluZm8AAQMFAAAAAqIS3mqd+jpp4iOHrPuvuxqeWRvZ1jbniV3PyN4F8zEBoCb3bQ+t5PUzXG/b/sSfGBnLtJkwovpY3s4bWwe3VkyZXTQFAAAAACDM0m0tZuhnQr6RtwGRcdiJQGD5DXcz7biqvE7lpUDTtAKiEt5qnfo6aeIjh6z7r7sanlkb2dY254ldz8jeBfMx7gIAAAAAAAAAZc0dAAAAAAA= 2 | -------------------------------------------------------------------------------- /crates/sui-sdk-types/src/u256.rs: -------------------------------------------------------------------------------- 1 | // Before we can expose this in the public interface it likely needs to be wrapped so that the type 2 | // from our dependency doesn't leak 3 | pub(crate) type U256 = bnum::BUintD8<32>; 4 | 5 | // This is a constant time assert to ensure that the backing storage for U256 is 32 bytes long 6 | #[allow(unused)] 7 | const ASSERT_32_BYTES: () = { 8 | let u256 = U256::ZERO; 9 | 10 | let _digits: &[u8; 32] = u256.digits(); 11 | }; 12 | 13 | // This is a constant time assert to ensure endianness of the underlying storage is as expected 14 | #[allow(unused)] 15 | const ASSERT_ENDIANNESS: () = { 16 | const fn const_bytes_equal(lhs: &[u8], rhs: &[u8]) -> bool { 17 | if lhs.len() != rhs.len() { 18 | return false; 19 | } 20 | let mut i = 0; 21 | while i < lhs.len() { 22 | if lhs[i] != rhs[i] { 23 | return false; 24 | } 25 | i += 1; 26 | } 27 | true 28 | } 29 | 30 | let one_platform = U256::ONE; 31 | let one_le = { 32 | let mut buf = [0; 32]; 33 | buf[0] = 1; 34 | buf 35 | }; 36 | 37 | let one_be = { 38 | let mut buf = [0; 32]; 39 | buf[31] = 1; 40 | buf 41 | }; 42 | 43 | // To little endian 44 | let le = one_platform.to_le(); 45 | assert!(const_bytes_equal(&one_le, le.digits().as_slice())); 46 | 47 | // To big endian 48 | let be = one_platform.to_be(); 49 | assert!(const_bytes_equal(&one_be, be.digits().as_slice())); 50 | 51 | // From little endian 52 | assert!(const_bytes_equal( 53 | one_platform.digits().as_slice(), 54 | U256::from_le(U256::from_digits(one_le)).digits().as_slice() 55 | )); 56 | 57 | // From big endian 58 | assert!(const_bytes_equal( 59 | one_platform.digits().as_slice(), 60 | U256::from_be(U256::from_digits(one_be)).digits().as_slice() 61 | )); 62 | }; 63 | 64 | #[cfg(test)] 65 | mod test { 66 | use super::*; 67 | use num_bigint::BigUint; 68 | use proptest::prelude::*; 69 | use std::str::FromStr; 70 | use test_strategy::proptest; 71 | 72 | #[cfg(target_arch = "wasm32")] 73 | use wasm_bindgen_test::wasm_bindgen_test as test; 74 | 75 | #[test] 76 | fn endianness() { 77 | let one_platform = U256::ONE; 78 | let one_le = { 79 | let mut buf = [0; 32]; 80 | buf[0] = 1; 81 | buf 82 | }; 83 | 84 | let one_be = { 85 | let mut buf = [0; 32]; 86 | buf[31] = 1; 87 | buf 88 | }; 89 | 90 | // To little endian 91 | let le = one_platform.to_le(); 92 | assert_eq!(one_le, *le.digits()); 93 | 94 | // To big endian 95 | let be = one_platform.to_be(); 96 | assert_eq!(one_be, *be.digits()); 97 | 98 | // From little endian 99 | assert_eq!(one_platform, U256::from_le(U256::from_digits(one_le))); 100 | // From big endian 101 | assert_eq!(one_platform, U256::from_be(U256::from_digits(one_be))); 102 | } 103 | 104 | #[proptest] 105 | fn dont_crash_on_large_inputs( 106 | #[strategy(proptest::collection::vec(any::(), 33..1024))] bytes: Vec, 107 | ) { 108 | let big_int = BigUint::from_bytes_be(&bytes); 109 | let radix10 = big_int.to_str_radix(10); 110 | 111 | // doesn't crash 112 | let _ = U256::from_str_radix(&radix10, 10); 113 | } 114 | 115 | #[proptest] 116 | fn valid_u256_strings( 117 | #[strategy(proptest::collection::vec(any::(), 1..=32))] bytes: Vec, 118 | ) { 119 | let big_int = BigUint::from_bytes_be(&bytes); 120 | let radix10 = big_int.to_str_radix(10); 121 | 122 | let u256 = U256::from_str_radix(&radix10, 10).unwrap(); 123 | 124 | assert_eq!(radix10, u256.to_str_radix(10)); 125 | 126 | let from_str = U256::from_str(&radix10).unwrap(); 127 | assert_eq!(from_str, u256); 128 | assert_eq!(radix10, from_str.to_string()); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /crates/sui-transaction-builder/.gitignore: -------------------------------------------------------------------------------- 1 | package_test_example*.json 2 | -------------------------------------------------------------------------------- /crates/sui-transaction-builder/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sui-transaction-builder" 3 | version = "0.0.4" 4 | authors = ["Stefan Stanciulescu ", "Brandon Williams "] 5 | license = "Apache-2.0" 6 | edition = "2021" 7 | description = "Transaction API for the Rust SDK for the Sui Blockchain" 8 | 9 | [dependencies] 10 | base64ct = { version = "1.6", features = ["std"] } 11 | bcs = "0.1.6" 12 | serde = { version = "1.0", features = ["derive"] } 13 | serde_with = { version = "3.9", default-features = false, features = ["alloc"] } 14 | sui-types = { package = "sui-sdk-types", version = "0.0.4", path = "../sui-sdk-types", features = ["serde", "hash"] } 15 | thiserror = "2.0" 16 | serde_json = { version = "1.0.128" } 17 | 18 | [dev-dependencies] 19 | anyhow = "1.0" 20 | rand = "0.8" 21 | serde_json = "1.0" 22 | sui-crypto = { package = "sui-crypto", path = "../sui-crypto" , features = ["ed25519"] } 23 | sui-graphql-client = { package = "sui-graphql-client", path = "../sui-graphql-client" } 24 | sui-types = { package = "sui-sdk-types", path = "../sui-sdk-types", features = ["rand"] } 25 | tokio = { version = "1.0", features = ["full"] } 26 | -------------------------------------------------------------------------------- /crates/sui-transaction-builder/src/error.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Mysten Labs, Inc. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use base64ct::Error as Base64Error; 5 | use sui_types::ObjectId; 6 | 7 | #[derive(thiserror::Error, Debug, Clone)] 8 | #[non_exhaustive] 9 | pub enum Error { 10 | #[error("Conversion error due to input issue: {0}")] 11 | Input(String), 12 | #[error("Gas object should be an immutable or owned object")] 13 | WrongGasObject, 14 | #[error("Decoding error: {0}")] 15 | Decoding(#[from] Base64Error), 16 | #[error("Missing object id")] 17 | MissingObjectId, 18 | #[error("Missing version for object {0}")] 19 | MissingVersion(ObjectId), 20 | #[error("Missing digest for object {0}")] 21 | MissingDigest(ObjectId), 22 | #[error("Missing sender")] 23 | MissingSender, 24 | #[error("Missing gas objects")] 25 | MissingGasObjects, 26 | #[error("Missing gas budget")] 27 | MissingGasBudget, 28 | #[error("Missing gas price")] 29 | MissingGasPrice, 30 | #[error("Missing object kind for object {0}")] 31 | MissingObjectKind(ObjectId), 32 | #[error("Missing initial shared version for object {0}")] 33 | MissingInitialSharedVersion(ObjectId), 34 | #[error("Missing pure value")] 35 | MissingPureValue, 36 | #[error("Unknown shared object mutability for object {0}")] 37 | SharedObjectMutability(ObjectId), 38 | #[error("Unsupported literal")] 39 | UnsupportedLiteral, 40 | } 41 | -------------------------------------------------------------------------------- /crates/sui-transaction-builder/tests/test_example_v1/Move.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "test_example" 3 | edition = "2024.beta" # edition = "legacy" to use legacy (pre-2024) Move 4 | # license = "" # e.g., "MIT", "GPL", "Apache 2.0" 5 | # authors = ["..."] # e.g., ["Joe Smith (joesmith@noemail.com)", "John Snow (johnsnow@noemail.com)"] 6 | 7 | [dependencies] 8 | Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "framework/testnet" } 9 | 10 | # For remote import, use the `{ git = "...", subdir = "...", rev = "..." }`. 11 | # Revision can be a branch, a tag, and a commit hash. 12 | # MyRemotePackage = { git = "https://some.remote/host.git", subdir = "remote/path", rev = "main" } 13 | 14 | # For local dependencies use `local = path`. Path is relative to the package root 15 | # Local = { local = "../path/to" } 16 | 17 | # To resolve a version conflict and force a specific version for dependency 18 | # override use `override = true` 19 | # Override = { local = "../conflicting/version", override = true } 20 | 21 | [addresses] 22 | test_example = "0x0" 23 | 24 | # Named addresses will be accessible in Move as `@name`. They're also exported: 25 | # for example, `std = "0x1"` is exported by the Standard Library. 26 | # alice = "0xA11CE" 27 | 28 | [dev-dependencies] 29 | # The dev-dependencies section allows overriding dependencies for `--test` and 30 | # `--dev` modes. You can introduce test-only dependencies here. 31 | # Local = { local = "../path/to/dev-build" } 32 | 33 | [dev-addresses] 34 | # The dev-addresses section allows overwriting named addresses for the `--test` 35 | # and `--dev` modes. 36 | # alice = "0xB0B" 37 | 38 | -------------------------------------------------------------------------------- /crates/sui-transaction-builder/tests/test_example_v1/sources/test_example.move: -------------------------------------------------------------------------------- 1 | module test_example::test_example { 2 | use std::string::String; 3 | public struct Object has key { 4 | id: UID, // required 5 | name: String, 6 | } 7 | 8 | /// Creates a new Object with a Unique ID 9 | public fun new(name: String, ctx: &mut TxContext): Object { 10 | Object { 11 | id: object::new(ctx), // creates a new UID 12 | name, 13 | } 14 | } 15 | } 16 | 17 | -------------------------------------------------------------------------------- /crates/sui-transaction-builder/tests/test_example_v2/Move.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "test_example" 3 | edition = "2024.beta" # edition = "legacy" to use legacy (pre-2024) Move 4 | # license = "" # e.g., "MIT", "GPL", "Apache 2.0" 5 | # authors = ["..."] # e.g., ["Joe Smith (joesmith@noemail.com)", "John Snow (johnsnow@noemail.com)"] 6 | 7 | [dependencies] 8 | Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "framework/testnet" } 9 | 10 | # For remote import, use the `{ git = "...", subdir = "...", rev = "..." }`. 11 | # Revision can be a branch, a tag, and a commit hash. 12 | # MyRemotePackage = { git = "https://some.remote/host.git", subdir = "remote/path", rev = "main" } 13 | 14 | # For local dependencies use `local = path`. Path is relative to the package root 15 | # Local = { local = "../path/to" } 16 | 17 | # To resolve a version conflict and force a specific version for dependency 18 | # override use `override = true` 19 | # Override = { local = "../conflicting/version", override = true } 20 | 21 | [addresses] 22 | test_example = "0x0" 23 | 24 | # Named addresses will be accessible in Move as `@name`. They're also exported: 25 | # for example, `std = "0x1"` is exported by the Standard Library. 26 | # alice = "0xA11CE" 27 | 28 | [dev-dependencies] 29 | # The dev-dependencies section allows overriding dependencies for `--test` and 30 | # `--dev` modes. You can introduce test-only dependencies here. 31 | # Local = { local = "../path/to/dev-build" } 32 | 33 | [dev-addresses] 34 | # The dev-addresses section allows overwriting named addresses for the `--test` 35 | # and `--dev` modes. 36 | # alice = "0xB0B" 37 | 38 | -------------------------------------------------------------------------------- /crates/sui-transaction-builder/tests/test_example_v2/sources/test_example.move: -------------------------------------------------------------------------------- 1 | module test_example::test_example { 2 | use std::string::{Self, String}; 3 | 4 | public struct Object has key { 5 | id: UID, // required 6 | name: String, 7 | } 8 | 9 | /// Creates a new Object with a Unique ID 10 | public fun new(name: String, ctx: &mut TxContext): Object { 11 | Object { 12 | id: object::new(ctx), // creates a new UID 13 | name, 14 | } 15 | } 16 | 17 | public fun default_name(ctx: &mut TxContext): Object { 18 | let default: String = string::utf8(b"default"); 19 | Object { 20 | id: object::new(ctx), 21 | name: default, 22 | } 23 | } 24 | } 25 | 26 | --------------------------------------------------------------------------------