From 4945f45813cd42def6cb8b4a2a34dd4dcdaa560f Mon Sep 17 00:00:00 2001 From: David Date: Thu, 27 Aug 2026 14:34:35 +0200 Subject: [PATCH 1/2] chore: prepare Talus move crates 0.2.0-rc.1 --- .github/workflows/publish-crates.yml | 66 + .github/workflows/rust-ci.yml | 43 +- .gitignore | 1 - CHANGELOG.md | 31 +- CONTRIBUTING.md | 22 +- Cargo.lock | 1476 +++++++++++++++++++++++ Cargo.toml | 9 + README.md | 59 +- RELEASING.md | 47 + scripts/check-packages.sh | 68 ++ scripts/publish-crates.sh | 145 +++ sui-move-call/Cargo.toml | 17 +- sui-move-call/README.md | 47 +- sui-move-call/src/lib.rs | 76 +- sui-move-call/tests/basic.rs | 10 +- sui-move-codegen/Cargo.toml | 11 +- sui-move-codegen/README.md | 101 +- sui-move-codegen/src/ir.rs | 14 +- sui-move-codegen/src/lib.rs | 8 +- sui-move-codegen/src/render/builtins.rs | 6 +- sui-move-codegen/src/render/calls.rs | 8 +- sui-move-codegen/src/render/mod.rs | 54 +- sui-move-codegen/src/render/tx_ext.rs | 14 +- sui-move-codegen/src/render/types.rs | 56 +- sui-move-codegen/src/render/util.rs | 8 +- sui-move-codegen/src/source.rs | 2 +- sui-move-codegen/src/source_names.rs | 2 +- sui-move-derive/Cargo.toml | 19 +- sui-move-derive/README.md | 69 +- sui-move-derive/src/abilities.rs | 6 +- sui-move-derive/src/args.rs | 7 +- sui-move-derive/src/expand.rs | 60 +- sui-move-derive/src/lib.rs | 32 +- sui-move-derive/src/util.rs | 8 +- sui-move-ptb/Cargo.toml | 19 +- sui-move-ptb/README.md | 60 +- sui-move-ptb/src/lib.rs | 48 +- sui-move-ptb/tests/basic.rs | 20 +- sui-move-runtime/Cargo.toml | 21 +- sui-move-runtime/README.md | 147 +-- sui-move-runtime/src/effects.rs | 2 +- sui-move-runtime/src/handles.rs | 132 +- sui-move-runtime/src/lib.rs | 175 +-- sui-move-runtime/src/tx.rs | 34 +- sui-move/Cargo.toml | 22 +- sui-move/README.md | 47 +- sui-move/examples/custom_struct.rs | 2 +- sui-move/examples/derive_struct.rs | 14 +- sui-move/examples/tag_checked_decode.rs | 13 +- sui-move/examples/type_tags.rs | 10 +- sui-move/src/builtins.rs | 2 +- sui-move/src/decode.rs | 4 +- sui-move/src/lib.rs | 16 +- sui-move/tests/basic.rs | 9 +- sui-move/tests/derive.rs | 47 +- 55 files changed, 2683 insertions(+), 763 deletions(-) create mode 100644 .github/workflows/publish-crates.yml create mode 100644 Cargo.lock create mode 100644 RELEASING.md create mode 100755 scripts/check-packages.sh create mode 100755 scripts/publish-crates.sh diff --git a/.github/workflows/publish-crates.yml b/.github/workflows/publish-crates.yml new file mode 100644 index 0000000..51304fe --- /dev/null +++ b/.github/workflows/publish-crates.yml @@ -0,0 +1,66 @@ +name: Publish crates.io packages + +on: + workflow_dispatch: + inputs: + tag: + description: Existing release tag, such as v0.2.0 + required: true + type: string + resume: + description: Skip versions that already exist after a reviewed partial publication + required: false + default: false + type: boolean + +permissions: + contents: read + +concurrency: + group: crates-io-${{ inputs.tag }} + cancel-in-progress: false + +jobs: + publish: + name: Publish packages + runs-on: ubuntu-latest + environment: crates-io + permissions: + contents: read + id-token: write + + steps: + - name: Check out the release tag + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + with: + ref: ${{ inputs.tag }} + fetch-depth: 0 + + - name: Install Rust 1.90 + uses: actions-rust-lang/setup-rust-toolchain@166cdcfd11aee3cb47222f9ddb555ce30ddb9659 # v1 + with: + toolchain: 1.90.0 + override: true + + - name: Verify the tag and main branch + shell: bash + env: + RELEASE_TAG: ${{ inputs.tag }} + run: | + workspace_version="$(awk -F ' *= *' '$1 == "version" { gsub(/"/, "", $2); print $2; exit }' Cargo.toml)" + test "$RELEASE_TAG" = "v$workspace_version" + test "$(git rev-parse HEAD)" = "$(git rev-parse "${RELEASE_TAG}^{commit}")" + git merge-base --is-ancestor HEAD origin/main + test -z "$(git status --porcelain)" + + - name: Request a crates.io token + id: crates_io_auth + uses: rust-lang/crates-io-auth-action@c6f97d42243bad5fab37ca0427f495c86d5b1a18 # v1.0.5 + + - name: Publish packages + env: + ALLOW_EXISTING: ${{ inputs.resume }} + CARGO_REGISTRY_TOKEN: ${{ steps.crates_io_auth.outputs.token }} + PUBLISH_CRATES_CONFIRM: ${{ inputs.tag }} + RELEASE_TAG: ${{ inputs.tag }} + run: ./scripts/publish-crates.sh "$RELEASE_TAG" diff --git a/.github/workflows/rust-ci.yml b/.github/workflows/rust-ci.yml index 110d500..0db2220 100644 --- a/.github/workflows/rust-ci.yml +++ b/.github/workflows/rust-ci.yml @@ -60,7 +60,7 @@ jobs: . -> target - name: cargo clippy -D warnings - run: cargo clippy --all --all-targets -- -D warnings + run: cargo clippy --workspace --all-targets --all-features --locked -- -D warnings check: name: Cargo check @@ -81,10 +81,10 @@ jobs: . -> target - name: cargo check - run: cargo check + run: cargo check --workspace --locked - - name: cargo check --all --all-targets - run: cargo check --all --all-targets + - name: cargo check all targets + run: cargo check --workspace --all-targets --all-features --locked test: name: Tests + doctests @@ -104,8 +104,37 @@ jobs: workspaces: | . -> target - - name: cargo test --all --all-targets - run: cargo test --all --all-targets + - name: cargo test all targets + run: cargo test --workspace --all-targets --all-features --locked - name: cargo test --doc - run: cargo test --doc --all + run: cargo test --doc --workspace --all-features --locked + + - name: cargo doc + env: + RUSTDOCFLAGS: -D warnings + run: cargo doc --workspace --all-features --no-deps --locked + + msrv: + name: Rust 1.90 and package archives + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install Rust 1.90 + uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + toolchain: 1.90.0 + override: true + + - name: Cache cargo + uses: Swatinem/rust-cache@v2 + with: + workspaces: | + . -> target + + - name: Check the minimum Rust version + run: cargo check --workspace --all-targets --all-features --locked + + - name: Test package archives + run: ./scripts/check-packages.sh diff --git a/.gitignore b/.gitignore index d6c0350..7f0db60 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ target/ -Cargo.lock .DS_Store # Local configuration and credentials. diff --git a/CHANGELOG.md b/CHANGELOG.md index ad915cd..4f65171 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,25 +7,34 @@ The format is based on [Keep a Changelog], and this project adheres to ## [Unreleased] +## [0.2.0-rc.1] - 2026-08-27 + ### Added -- Add `sui-move`: core Move-shaped type layer (traits, abilities, decoding). -- Keep Move framework declarations out of the `sui-move` core so generated package bindings define +- Add `talus-sui-move`: core layer for Move types, traits, abilities, and decoding. +- Keep Move framework declarations out of the `talus-sui-move` core so generated package bindings define `UID`, `Coin`, `Balance`, containers, and other framework shapes. -- Add `sui-move-derive` and the `sui-move` `derive` feature for defining Move-shaped structs via macros. -- Add `sui-move-call`: typed Move call descriptions (`CallSpec`) plus typed wrappers for Sui `Input` kinds (pure, immutable/owned, shared, receiving). -- Add `sui-move-ptb`: minimal PTB builder that consumes `CallSpec` and produces `ProgrammableTransaction`. -- Add `sui-move-runtime`: cursor-driven runtime for the Read → Tx → Commit mental model: - - runtime-owned handles (`Object`) that auto-update from transaction effects, - - explicit input-mode views (`shared_immutable`, `shared_mutable`, `receiving`), - - finality-aware `Receipt` plus recovery hooks (`Runtime::sync_transaction`, `Read::refresh*`), - - ergonomic transaction macro (`sui_move_runtime::tx!`). -- Add `sui-move-codegen`: fetch + normalize package metadata (`NormalizedPackage`) and render typed Rust bindings (Move-shaped types + `CallSpec` builders). +- Add `talus-sui-move-derive` and the `talus-sui-move` `derive` feature for defining Rust structs + that represent Move structs. +- Add `talus-sui-move-call`: typed Move call descriptions (`CallSpec`) plus typed wrappers for Sui `Input` kinds (pure, immutable/owned, shared, receiving). +- Add `talus-sui-move-ptb`: minimal PTB builder that consumes `CallSpec` and produces `ProgrammableTransaction`. +- Add `talus-sui-move-runtime`: runtime with a cursor for the Read → Tx → Commit mental model: + - handles owned by the runtime (`Object`) that update from transaction effects, + - explicit input mode views (`shared_immutable`, `shared_mutable`, `receiving`), + - `Receipt` values that record finality plus recovery hooks (`Runtime::sync_transaction`, + `Read::refresh*`), + - ergonomic transaction macro (`talus_sui_move_runtime::tx!`). +- Add `talus-sui-move-codegen`: fetch and normalize package metadata (`NormalizedPackage`) and + render typed Rust bindings for Move types and `CallSpec` builders. ### Changed +- Publish the workspace under the `talus-sui-move-*` crates.io package names owned by Talus and use + the matching `talus_sui_move*` Rust library names. - Generated package scopes now resolve type identity by module and datatype while calls continue to use the current package address. [Keep a Changelog]: https://keepachangelog.com/en/1.1.0/ [Semantic Versioning]: https://semver.org/spec/v2.0.0.html +[Unreleased]: https://github.com/Talus-Network/move-binding/compare/v0.2.0-rc.1...HEAD +[0.2.0-rc.1]: https://github.com/Talus-Network/move-binding/compare/v0.1.0...v0.2.0-rc.1 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4501b2a..337cd64 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,7 +4,7 @@ Thank you for considering contributing to this project. These guidelines keep th and preserve the structure of the workspace. This workspace is a set of layered Rust crates for typed Sui Move interactions. Changes should -preserve the layer boundaries described in `MODEL.md`: low-level Move type modeling should not +preserve the layer boundaries described in `MODEL.md`: foundational Move type modeling should not depend on transaction building or runtime behavior, and runtime code should not hide the Read -> Tx -> Commit boundary. @@ -26,7 +26,7 @@ code. 4. Add tests for new functionality or behavior changes. 5. Do not introduce `unsafe` Rust unless the safety invariant is documented and reviewed explicitly. -6. Update documentation to complement user-facing code changes. +6. Update documentation to complement changes to the public API. 7. Update `CHANGELOG.md` for externally visible changes. ## Local Checks @@ -56,7 +56,7 @@ CI runs formatting and clippy strictly, plus stable Rust checks and tests. - Ensure your branch is up to date with `main`. - Add or update tests for public API behavior, generated output, transaction construction, and runtime cursor/effects handling. -- Update the relevant crate README when changing user-facing APIs. +- Update the relevant crate README when changing public APIs. - A maintainer will review and may request changes before merge. ## Writing Commit Messages @@ -67,7 +67,7 @@ CI runs formatting and clippy strictly, plus stable Rust checks and tests. - Use imperative tone, for example `fix: reject duplicate object inputs` instead of `fix: rejects duplicate object inputs`. - Reference a ticket if applicable. -- Add context and an explanation for non-trivial contributions. +- Add context and an explanation for complex contributions. ## Dependencies @@ -77,18 +77,7 @@ crates.io, so the workspace can be packaged predictably. ## Publishing -Publish crates in dependency order: - -1. `sui-move-derive` -2. `sui-move` -3. `sui-move-call` -4. `sui-move-ptb` -5. `sui-move-runtime` -6. `sui-move-codegen` - -Before the first crates.io release, `cargo package --workspace` is expected to fail for crates -whose normal dependencies are not published yet. Package each crate after its normal dependencies -are available in the registry. +Follow [RELEASING.md] for package validation, publication order, ownership, and trusted publishing. ## License @@ -101,3 +90,4 @@ project: [LICENSE]. [CLA]: https://gist.github.com/devops-talus/82cafc9752547baf4be140b6db1e8fd6 [CLA Assistant]: https://cla-assistant.io/Talus-Network/move-binding [Conventional Commits]: https://www.conventionalcommits.org/ +[RELEASING.md]: RELEASING.md diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..1b56f1b --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1476 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "anyhow" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" + +[[package]] +name = "async-trait" +version = "0.1.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82f6aeea286b8eb4dd3431a1be1b59d290ace00f5bfd8e2a159bc2a05e2c1667" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.4", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + +[[package]] +name = "bcs" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b6598a2f5d564fb7855dc6b06fd1c38cff5a72bd8b863a4d021938497b440a" +dependencies = [ + "serde", + "thiserror 1.0.69", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bnum" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "119771309b95163ec7aaf79810da82f7cd0599c19722d48b9c03894dca833966" + +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "bytemuck" +version = "1.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" + +[[package]] +name = "bytestring" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86566c496f2f47d9b8147a4c8b02ffdb69c919fe0c2b2e7195d22cbba0e635c9" +dependencies = [ + "bytes", +] + +[[package]] +name = "cc" +version = "1.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ad534f4357a5264cce5019c989cf66a4f0dc4e0d1b1d15f8aacec0ff7360273" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "chrono" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" +dependencies = [ + "num-traits", + "serde", +] + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "defmt" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2953bfe4f93bbd20cc71198842756f77d161884c99ebbabc41d80231ded88d1" +dependencies = [ + "bitflags", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad9c72e7ca2137e0dc3813245a0d282fd6daad32fd800af018306a9169b5fe8" +dependencies = [ + "defmt-parser", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "defmt-parser" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" +dependencies = [ + "thiserror 2.0.20", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "either" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "ethnum" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40404c3f5f511ec4da6fe866ddf6a717c309fdbb69fbbad7b0f3edab8f2e835f" + +[[package]] +name = "find-msvc-tools" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d45db016d36b838f563236e9193d0ee6ce38f3f68b6c94e914b4929c96bbb890" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "futures" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a31d2a3fbaaeb2af2368bbdd904aa8e812d3c04a1ee10d3171f52d556e5d0a3" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" + +[[package]] +name = "futures-executor" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031b47cf1a3c6cc8bc2fc76cd437f521619387907d469316e7c0bc278f1f5432" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed" + +[[package]] +name = "futures-macro" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.4", +] + +[[package]] +name = "futures-sink" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d" + +[[package]] +name = "futures-task" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" + +[[package]] +name = "futures-util" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "libc", + "r-efi", +] + +[[package]] +name = "h2" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef8e5e5a340588f4452631496976cf8636d4a7ecf600239fdc27615d2530bc16" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "http" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2a8f2913ee65f60facd6a5905613afaa448497a0230cc41ce022d93290bc2c" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23169fe34a5fbcdd3f3862e78fb9b6fccd5f02a6dc6f732547005d45631ce71c" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "hyper" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d22053281f852e11534f5198498373cbb59295120a20771d90f7ed1897490a72" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "h2", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-timeout" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" +dependencies = [ + "hyper", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "libc", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "jiff" +version = "0.2.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "668b7183bd07af9a4885f5c35b0cc5c83c4607a913c16b7e17291832910d2dcc" +dependencies = [ + "defmt", + "jiff-core", + "jiff-static", + "portable-atomic", + "portable-atomic-util", + "serde_core", +] + +[[package]] +name = "jiff-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7feca88439efe53da3754500c1851dedf3cb36c524dd5cf8225cc0794de95d09" +dependencies = [ + "defmt", +] + +[[package]] +name = "jiff-static" +version = "0.2.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a69dcb3a21cfb32ce1cd056169337ca284af0766dd766e7878819b251a49204" +dependencies = [ + "jiff-core", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "jobserver" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" +dependencies = [ + "getrandom 0.4.3", + "libc", +] + +[[package]] +name = "libc" +version = "0.2.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" + +[[package]] +name = "log" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "mio" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d65c71f1ce40ab09135ce117d742b9f8a19ff91a41a8b57ed50bc2de59c427" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "num-conv" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pkg-config" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548" + +[[package]] +name = "portable-atomic" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85" + +[[package]] +name = "portable-atomic-util" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a106d1259c23fac8e543272398ae0e3c0b8d33c88ed73d0cc71b0f1d902618" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.119", +] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "prost" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528ac67416ff8646872a3c02cad9cc4ee5dc9f9540c9b10771855c95cb2e5ae1" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-derive" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b570b25f7617e43d59005d0990ccb79e950a423952cea19671b7a876da390adf" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "prost-types" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f94967dc7688f3054c7fac87473ffae4cc4c3904800e2d9f5b857246d8963b0a" +dependencies = [ + "prost", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "roaring" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18bd8a37d17a58532776dcdf6041ce64929adca78e8489d5cacbafe99229d3e1" +dependencies = [ + "bytemuck", + "byteorder", +] + +[[package]] +name = "rustls" +version = "0.23.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0283386ce02abc0151e1761d08802dfe86c173b0b494af5cbc086574e453da06" +dependencies = [ + "log", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c3cf1d8b1e7d4927e2d154c3fcb02979afb9939629c62cd9048d4f07b60ac2" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.4", +] + +[[package]] +name = "serde_json" +version = "1.0.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_with" +version = "3.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee78f1fbe43ac4a0e47aadb3dbd357b69eb0d3793e948624cd03dd2750ab1c0a" +dependencies = [ + "base64", + "bs58", + "chrono", + "hex", + "jiff", + "serde_core", + "serde_json", + "time", +] + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" + +[[package]] +name = "socket2" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "sui-crypto" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7b8f54c4405002c9ece67cb848479f80837185a55a59d8c0a105240f737d0da" +dependencies = [ + "base64ct", + "signature", + "sui-sdk-types", +] + +[[package]] +name = "sui-rpc" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617504d5c6b748af0494b73db80fb893840522329788c48c826d8298e7edb0aa" +dependencies = [ + "base64", + "bcs", + "bytes", + "futures", + "http", + "http-body", + "hyper", + "prost", + "prost-types", + "serde", + "serde_json", + "sui-sdk-types", + "tap", + "tokio", + "tonic", + "tonic-prost", + "tower", +] + +[[package]] +name = "sui-sdk-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a22266119e43d3da1a8bc9945c8b569a513e7682f561265d70ef8b6e198dd664" +dependencies = [ + "base64ct", + "bcs", + "blake2", + "bnum", + "bs58", + "bytes", + "bytestring", + "itertools", + "roaring", + "serde", + "serde_derive", + "serde_json", + "serde_with", + "winnow", +] + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6275cddf4610d1775e6d1fe9469b2e77d0f39fd98fb7450901b821e0c53649f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" + +[[package]] +name = "talus-sui-move" +version = "0.2.0-rc.1" +dependencies = [ + "bcs", + "ethnum", + "serde", + "sui-sdk-types", + "talus-sui-move-derive", + "thiserror 1.0.69", +] + +[[package]] +name = "talus-sui-move-call" +version = "0.2.0-rc.1" +dependencies = [ + "bcs", + "serde", + "sui-sdk-types", + "talus-sui-move", + "thiserror 1.0.69", +] + +[[package]] +name = "talus-sui-move-codegen" +version = "0.2.0-rc.1" +dependencies = [ + "prettyplease", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sui-rpc", + "sui-sdk-types", + "syn 2.0.119", + "thiserror 1.0.69", +] + +[[package]] +name = "talus-sui-move-derive" +version = "0.2.0-rc.1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "talus-sui-move", +] + +[[package]] +name = "talus-sui-move-ptb" +version = "0.2.0-rc.1" +dependencies = [ + "sui-sdk-types", + "talus-sui-move", + "talus-sui-move-call", + "thiserror 1.0.69", +] + +[[package]] +name = "talus-sui-move-runtime" +version = "0.2.0-rc.1" +dependencies = [ + "serde", + "serde_json", + "sui-crypto", + "sui-rpc", + "sui-sdk-types", + "talus-sui-move", + "talus-sui-move-call", + "talus-sui-move-ptb", + "thiserror 1.0.69", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" +dependencies = [ + "thiserror-impl 2.0.20", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.4", +] + +[[package]] +name = "time" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde_core", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" + +[[package]] +name = "tinyvec" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb4ebadaa0af04fab11ae01eb5f9fdb5f9c5b875506e210e71c07873528baa7f" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed" +dependencies = [ + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.4", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3d06f0b082ba57c26b79407372e57cf2a1e28124f78e9479fe80322cf53420b" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "494815d09bf52b5548659851081238f0ca39ff638363907596da739561c62c52" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "libc", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tonic" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac2a5518c70fa84342385732db33fb3f44bc4cc748936eb5833d2df34d6445ef" +dependencies = [ + "async-trait", + "base64", + "bytes", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-timeout", + "hyper-util", + "percent-encoding", + "pin-project", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tokio-stream", + "tower", + "tower-layer", + "tower-service", + "tracing", + "webpki-roots", + "zstd", +] + +[[package]] +name = "tonic-prost" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50849f68853be452acf590cde0b146665b8d507b3b8af17261df47e02c209ea0" +dependencies = [ + "bytes", + "prost", + "tonic", +] + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "indexmap", + "pin-project-lite", + "slab", + "sync_wrapper", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "webpki-roots" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dcd9d09a39985f5344844e66b0c530a33843579125f23e21e9f0f220850f22a" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" +dependencies = [ + "memchr", +] + +[[package]] +name = "zeroize" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.16+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/Cargo.toml b/Cargo.toml index 4020b3d..246198c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,11 +10,20 @@ members = [ ] [workspace.package] +version = "0.2.0-rc.1" +edition = "2021" +rust-version = "1.90" license = "Apache-2.0" repository = "https://github.com/Talus-Network/move-binding" homepage = "https://github.com/Talus-Network/move-binding" [workspace.dependencies] +talus-sui-move = { version = "=0.2.0-rc.1", path = "sui-move" } +talus-sui-move-derive = { version = "=0.2.0-rc.1", path = "sui-move-derive" } +talus-sui-move-call = { version = "=0.2.0-rc.1", path = "sui-move-call" } +talus-sui-move-ptb = { version = "=0.2.0-rc.1", path = "sui-move-ptb" } +talus-sui-move-runtime = { version = "=0.2.0-rc.1", path = "sui-move-runtime" } +talus-sui-move-codegen = { version = "=0.2.0-rc.1", path = "sui-move-codegen" } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" thiserror = "1.0" diff --git a/README.md b/README.md index 516ab3a..9fca49e 100644 --- a/README.md +++ b/README.md @@ -5,37 +5,48 @@ Layered crates for writing typed, ergonomic Move interactions on Sui from Rust. This workspace is intentionally “deep”: each crate is a small abstraction that solves one problem, and higher layers build on lower ones. -The top-level mental model is **Read → Tx → Commit** with a **cursor** that advances your local +The primary mental model is **Read → Tx → Commit** with a **cursor** that advances your local frontier by applying transaction effects. See `MODEL.md`. ## Status -This is an early `0.1` workspace. Public APIs may change before `1.0`; treat the crate boundaries -and the `MODEL.md` invariants as more stable than individual function names. - -## Crates (low → high) - -- `sui-move`: Move-shaped types (`MoveType`, `MoveStruct`, abilities, decoding helpers). - See `sui-move/README.md`. -- `sui-move-derive`: derive macros for defining Move-shaped Rust structs. - See `sui-move-derive/README.md`. -- `sui-move-call`: typed Move call descriptions (`CallSpec`) and `ToCallArg`. - See `sui-move-call/README.md`. -- `sui-move-ptb`: build Sui `ProgrammableTransaction`s (PTBs) from `CallSpec`. - See `sui-move-ptb/README.md`. -- `sui-move-runtime`: a cursor-driven runtime for Read/Tx/Commit of PTBs and auto-updating typed - handles from transaction effects. - See `sui-move-runtime/README.md`. -- `sui-move-codegen`: generate typed Rust bindings (types + `CallSpec` builders) from on-chain Move - package metadata. - See `sui-move-codegen/README.md`. +The `0.2.0-rc.1` release candidate is the first release under crates.io package names owned by Talus. +Public APIs may change before `1.0`; treat the crate boundaries and the `MODEL.md` invariants as +more stable than individual function names. + +## Packages (low → high) + +The crates.io package names and Rust library names use the same Talus prefix. This gives consumers +one consistent name in Cargo and source code. + +| crates.io package | Rust crate | Role | +| --- | --- | --- | +| `talus-sui-move` | `talus_sui_move` | Rust representations of Move types, abilities, and decoding helpers | +| `talus-sui-move-derive` | `talus_sui_move_derive` | Derive macros for Rust structs that represent Move structs | +| `talus-sui-move-call` | `talus_sui_move_call` | Typed Move call descriptions and arguments | +| `talus-sui-move-ptb` | `talus_sui_move_ptb` | Programmable transaction construction | +| `talus-sui-move-runtime` | `talus_sui_move_runtime` | Read/Tx/Commit runtime and typed handles | +| `talus-sui-move-codegen` | `talus_sui_move_codegen` | Rust binding generation from Move package metadata | + +For example: + +```toml +[dependencies] +talus-sui-move = { version = "=0.2.0-rc.1", features = ["derive"] } +``` + +```rust +use talus_sui_move::MoveType; +``` ## Where to start -- Application code: start at `sui-move-runtime/README.md`. -- Interface crates (module/function wrappers): start at `sui-move-call/README.md`. -- Pure type modeling/decoding: start at `sui-move/README.md`. -- Generating bindings from on-chain metadata: start at `sui-move-codegen/README.md`. +- Application code: start at [`sui-move-runtime/README.md`](sui-move-runtime/README.md). +- Interface crates (module/function wrappers): start at + [`sui-move-call/README.md`](sui-move-call/README.md). +- Pure type modeling/decoding: start at [`sui-move/README.md`](sui-move/README.md). +- Generating bindings from package metadata on Sui: start at + [`sui-move-codegen/README.md`](sui-move-codegen/README.md). ## Development diff --git a/RELEASING.md b/RELEASING.md new file mode 100644 index 0000000..7d1a6db --- /dev/null +++ b/RELEASING.md @@ -0,0 +1,47 @@ +# Releasing crates + +All workspace crates use one version and one Git tag. + +## Verify + +```console +cargo fmt --all -- --check +cargo clippy --workspace --all-targets --all-features --locked -- -D warnings +cargo test --workspace --all-targets --all-features --locked +cargo test --doc --workspace --all-features --locked +RUSTDOCFLAGS="-D warnings" cargo doc --workspace --all-features --no-deps --locked +./scripts/check-packages.sh +``` + +## Tag + +Merge the release commit into `main`, then create and push a signed tag: + +```console +git tag -s v0.2.0-rc.1 -m "move-binding v0.2.0-rc.1" +git push origin v0.2.0-rc.1 +``` + +## First publication + +From the clean tagged commit: + +```console +cargo login +PUBLISH_CRATES_CONFIRM=v0.2.0-rc.1 \ + ./scripts/publish-crates.sh v0.2.0-rc.1 +``` + +After publication: + +1. Add `devops-talus` and `github:Talus-Network:engineering` as owners of every crate. +2. Configure every crate to trust `Talus-Network/move-binding`, workflow + `publish-crates.yml`, environment `crates-io`. +3. Revoke the personal token and run `cargo logout`. + +Use `ALLOW_EXISTING=1` only to resume a reviewed partial publication. + +## Later releases + +Create and push the signed tag, then dispatch `Publish crates.io packages` in GitHub Actions. +Create the GitHub release only after every crate version is visible on crates.io. diff --git a/scripts/check-packages.sh b/scripts/check-packages.sh new file mode 100755 index 0000000..517c475 --- /dev/null +++ b/scripts/check-packages.sh @@ -0,0 +1,68 @@ +#!/usr/bin/env bash + +set -euo pipefail + +release_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +cd "$release_root" + +workspace_version="$(awk -F ' *= *' '$1 == "version" { gsub(/"/, "", $2); print $2; exit }' Cargo.toml)" +if [[ -z "$workspace_version" ]]; then + echo "Could not read the workspace version." >&2 + exit 1 +fi + +packages=( + talus-sui-move-derive + talus-sui-move-codegen + talus-sui-move + talus-sui-move-call + talus-sui-move-ptb + talus-sui-move-runtime +) + +# New packages cannot resolve one another through crates.io before the first +# publication. These local patches let Cargo verify the exact package archives. +cargo_config_args=( + --config "patch.crates-io.talus-sui-move.path=\"$release_root/sui-move\"" + --config "patch.crates-io.talus-sui-move-derive.path=\"$release_root/sui-move-derive\"" + --config "patch.crates-io.talus-sui-move-call.path=\"$release_root/sui-move-call\"" + --config "patch.crates-io.talus-sui-move-ptb.path=\"$release_root/sui-move-ptb\"" + --config "patch.crates-io.talus-sui-move-runtime.path=\"$release_root/sui-move-runtime\"" + --config "patch.crates-io.talus-sui-move-codegen.path=\"$release_root/sui-move-codegen\"" +) + +package_args=(--quiet --locked --all-features) +if [[ "${ALLOW_DIRTY:-0}" == "1" || "${ALLOW_DIRTY:-0}" == "true" ]]; then + package_args+=(--allow-dirty) +fi + +target_root="${CARGO_TARGET_DIR:-$release_root/target}" + +for package in "${packages[@]}"; do + echo "Checking $package $workspace_version" + cargo "${cargo_config_args[@]}" package \ + -p "$package" \ + "${package_args[@]}" + + archive="$target_root/package/$package-$workspace_version.crate" + archive_manifest="$package-$workspace_version/Cargo.toml" + if [[ ! -f "$archive" ]]; then + echo "Cargo did not create $archive." >&2 + exit 1 + fi + + if tar -xOf "$archive" "$archive_manifest" | awk ' + /^\[/ { + dependency_section = ($0 ~ /(^\[|\.)((build|dev)-)?dependencies(\.|\])/) + } + dependency_section && /^[[:space:]]*(git|path|registry)[[:space:]]*=/ { + source_dependency = 1 + } + END { exit(source_dependency ? 0 : 1) } + '; then + echo "$package contains a source dependency in its published manifest." >&2 + exit 1 + fi +done + +echo "All package archives passed verification." diff --git a/scripts/publish-crates.sh b/scripts/publish-crates.sh new file mode 100755 index 0000000..07e9777 --- /dev/null +++ b/scripts/publish-crates.sh @@ -0,0 +1,145 @@ +#!/usr/bin/env bash + +set -euo pipefail + +release_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +cd "$release_root" + +release_tag="${1:-}" +workspace_version="$(awk -F ' *= *' '$1 == "version" { gsub(/"/, "", $2); print $2; exit }' Cargo.toml)" +expected_tag="v$workspace_version" + +if [[ -z "$release_tag" || "$release_tag" != "$expected_tag" ]]; then + echo "Usage: $0 $expected_tag" >&2 + exit 1 +fi + +if [[ "${PUBLISH_CRATES_CONFIRM:-}" != "$expected_tag" ]]; then + echo "Set PUBLISH_CRATES_CONFIRM=$expected_tag to authorize publication." >&2 + exit 1 +fi + +head_commit="$(git rev-parse HEAD)" +tag_commit="$(git rev-parse "${release_tag}^{commit}")" +if [[ "$(git cat-file -t "$release_tag")" != "tag" ]]; then + echo "$release_tag must be an annotated tag." >&2 + exit 1 +fi + +if [[ "$head_commit" != "$tag_commit" ]]; then + echo "$release_tag does not point to the current commit." >&2 + exit 1 +fi + +if [[ -n "$(git status --porcelain)" ]]; then + echo "The work tree must be clean before publication." >&2 + exit 1 +fi + +git fetch --quiet origin main +if ! git merge-base --is-ancestor "$tag_commit" origin/main; then + echo "$release_tag must point to a commit on origin/main." >&2 + exit 1 +fi + +./scripts/check-packages.sh + +packages=( + talus-sui-move-derive + talus-sui-move-codegen + talus-sui-move + talus-sui-move-call + talus-sui-move-ptb + talus-sui-move-runtime +) + +allow_existing=0 +if [[ "${ALLOW_EXISTING:-0}" == "1" || "${ALLOW_EXISTING:-0}" == "true" ]]; then + allow_existing=1 +fi + +api_resource_exists() { + local api_path="$1" + local http_status + http_status="$(curl \ + --silent \ + --show-error \ + --output /dev/null \ + --write-out '%{http_code}' \ + --header 'User-Agent: Talus move-binding release (https://github.com/Talus-Network/move-binding)' \ + "https://crates.io/api/v1/crates/$api_path")" || return 2 + + case "$http_status" in + 200) return 0 ;; + 404) return 1 ;; + *) + echo "crates.io returned HTTP $http_status for $api_path." >&2 + return 2 + ;; + esac +} + +crate_exists() { + api_resource_exists "$1/$workspace_version" +} + +existing_package_count=0 +for package in "${packages[@]}"; do + if api_resource_exists "$package"; then + existing_package_count=$((existing_package_count + 1)) + elif [[ "$?" != "1" ]]; then + exit 1 + fi +done + +if (( existing_package_count > 0 && existing_package_count < ${#packages[@]} )); then + if [[ "$allow_existing" == "0" ]]; then + echo "Only $existing_package_count of ${#packages[@]} package names exist on crates.io." >&2 + echo "Investigate the owners, or use ALLOW_EXISTING=1 for reviewed recovery." >&2 + exit 1 + fi +fi + +for package in "${packages[@]}"; do + if crate_exists "$package"; then + if [[ "$allow_existing" == "1" ]]; then + echo "$package $workspace_version already exists and may be skipped." + else + echo "$package $workspace_version already exists." >&2 + echo "Use ALLOW_EXISTING=1 only to resume a reviewed partial publication." >&2 + exit 1 + fi + elif [[ "$?" != "1" ]]; then + exit 1 + fi +done + +for package in "${packages[@]}"; do + if crate_exists "$package"; then + if [[ "$allow_existing" == "1" ]]; then + echo "$package $workspace_version already exists; skipping it." + continue + fi + echo "$package $workspace_version appeared after the initial check." >&2 + exit 1 + elif [[ "$?" != "1" ]]; then + exit 1 + fi + + cargo publish --registry crates-io --locked -p "$package" + + for attempt in {1..60}; do + if crate_exists "$package"; then + break + elif [[ "$?" != "1" ]]; then + exit 1 + fi + if [[ "$attempt" == "60" ]]; then + echo "$package $workspace_version did not appear in the crates.io API." >&2 + exit 1 + fi + sleep 5 + done +done + +echo "Published all move-binding packages for $release_tag." diff --git a/sui-move-call/Cargo.toml b/sui-move-call/Cargo.toml index 62a6670..d51cc0c 100644 --- a/sui-move-call/Cargo.toml +++ b/sui-move-call/Cargo.toml @@ -1,19 +1,24 @@ [package] -name = "sui-move-call" -version = "0.1.0" -edition = "2021" +name = "talus-sui-move-call" +version.workspace = true +edition.workspace = true +rust-version.workspace = true description = "Typed call arguments and call specifications for Move calls on Sui." readme = "README.md" +publish = ["crates-io"] license.workspace = true repository.workspace = true homepage.workspace = true +documentation = "https://docs.rs/talus-sui-move-call" +keywords = ["sui", "move", "blockchain", "transactions"] +categories = ["api-bindings", "development-tools"] [dependencies] -sui-move = { version = "0.1.0", path = "../sui-move" } -serde = { workspace = true, features = ["derive"] } +talus-sui-move = { workspace = true } +serde = { workspace = true } bcs = { workspace = true } thiserror = { workspace = true } sui-sdk-types = { workspace = true } [dev-dependencies] -sui-move = { path = "../sui-move", features = ["derive"] } +talus-sui-move = { workspace = true, features = ["derive"] } diff --git a/sui-move-call/README.md b/sui-move-call/README.md index 79cd92c..e003b0b 100644 --- a/sui-move-call/README.md +++ b/sui-move-call/README.md @@ -1,31 +1,35 @@ -# sui-move-call +# talus-sui-move-call Typed building blocks for describing Move calls on Sui. -This crate builds on top of [`sui-move`](../sui-move/README.md) and solves one problem: +The crates.io package is `talus-sui-move-call`; Rust code imports it as `talus_sui_move_call`. + +This crate builds on top of [`talus-sui-move`](https://docs.rs/talus-sui-move) and solves one problem: **describe a Move call in a typed way** (object handles + type arguments + arguments) without building or executing transactions. ## Where it fits -`sui-move-call` is the “Call” layer in the repository’s Read → Tx → Commit mental model (`MODEL.md`): +`talus-sui-move-call` is the “Call” layer in the repository’s +[Read → Tx → Commit model](https://github.com/Talus-Network/move-binding/blob/main/MODEL.md): -- **Read** (runtime) fetches objects and classifies on-chain ownership. +- **Read** (runtime) fetches objects and classifies ownership from chain state. - **Call** (this crate) describes *what* to call and how to encode arguments. - **PTB** builds a `ProgrammableTransaction` from a `CallSpec`. - **Commit** (runtime) submits and applies effects to advance the cursor. -This crate sits directly above `sui-move`: it uses `MoveType`/`MoveStruct` to build type-checked -call descriptions (`CallSpec`). Transaction-building and execution are intentionally out of scope. +This crate sits directly above `talus-sui-move`: it uses `MoveType` and `MoveStruct` to build call +descriptions (`CallSpec`) whose types are checked by Rust. Transaction building and execution are +intentionally out of scope. ## Core types - `CallSpec`: `(package, module, function)` + type arguments + call arguments -- `CallArg`: canonical call-argument representation (re-export of `sui_sdk_types::Input`) +- `CallArg`: canonical call argument representation (a public alias for `sui_sdk_types::Input`) - `ToCallArg`: convert values into `CallArg` without consuming them - `ToCallArgMut`: convert values into `CallArg` for Move `&mut` parameters (shared inputs become mutable) -- `ObjectArg`: typed object-argument trait used by generated interfaces (accepts any object +- `ObjectArg`: typed object argument trait used by generated interfaces (accepts any object handle that can be encoded as both `&` and `&mut` in Move) - `MoveObject`: typed handle for `Input::ImmutableOrOwned(ObjectReference)` - `SharedMoveObject`: typed handle for `Input::Shared(SharedInput)` @@ -37,15 +41,16 @@ refuse to convert tombstoned handles or invalid owner kinds into object inputs). ## Receiving is an input mode (not ownership) Sui's “receiving” is a distinct **transaction input mode**. It corresponds to the Move framework -type `sui::transfer::Receiving`: an ephemeral per-transaction “receiving ticket” consumed by +type `sui::transfer::Receiving`: an ephemeral “receiving ticket” consumed by `sui::transfer::receive`/`public_receive`. -It is not an on-chain owner kind, and this crate does not attempt to prove that a given reference -is valid to receive. It only models the correct wire shape (`Input::Receiving(ObjectReference)`). +It is not an owner kind recorded on chain, and this crate does not attempt to prove that a given +reference is valid to receive. It only models the correct wire shape +(`Input::Receiving(ObjectReference)`). ## Argument mapping -This crate keeps the user-facing API small, and maps typed values into Sui's on-chain input kinds: +This crate keeps its public API small and maps typed values into Sui transaction input kinds: - `T: MoveType` → `CallArg::Pure(bcs(T))` - `MoveObject` → `CallArg::ImmutableOrOwned(..)` @@ -56,7 +61,7 @@ For Move `&mut` parameters, use `CallSpec::push_arg_mut` (or implement `ToCallAr handle type). This matters for shared objects: Sui's shared input encodes mutability in the transaction input itself. -These are intentionally separate wrapper types because the on-chain input shapes differ: +These are intentionally separate wrapper types because their transaction input shapes differ: shared objects are described by `(id, initial_shared_version, mutability)`, while immutable/owned and receiving inputs use full `ObjectReference`s. @@ -69,16 +74,16 @@ The typical pattern is to write small interface functions that produce a `CallSp ```rust use std::str::FromStr; -use sui_move::prelude::*; -use sui_move_call::{CallSpec, MoveObject}; +use talus_sui_move::prelude::*; +use talus_sui_move_call::{CallSpec, MoveObject}; use sui_sdk_types::{Address, Digest, ObjectReference, TypeTag}; -#[sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] +#[talus_sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] pub struct UID { pub id: u64, } -#[sui_move::move_struct(address = "0x1", module = "vault", abilities = "key")] +#[talus_sui_move::move_struct(address = "0x1", module = "vault", abilities = "key")] pub struct Vault { pub id: UID, } @@ -114,15 +119,15 @@ fn main() { ```rust use std::str::FromStr; -use sui_move_call::{CallArg, CallSpec, ReceivingMoveObject, SharedMoveObject}; +use talus_sui_move_call::{CallArg, CallSpec, ReceivingMoveObject, SharedMoveObject}; use sui_sdk_types::{Address, Digest, ObjectReference}; -#[sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] +#[talus_sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] struct UID { id: u64, } -#[sui_move::move_struct(address = "0x1", module = "demo", abilities = "key")] +#[talus_sui_move::move_struct(address = "0x1", module = "demo", abilities = "key")] struct Thing { id: UID, } @@ -141,7 +146,7 @@ assert!(matches!(spec.arguments[0], CallArg::Shared(_))); assert!(matches!(spec.arguments[1], CallArg::Receiving(_))); ``` -## Non-goals +## Out of scope - No transaction building: this crate does not produce `ProgrammableTransaction`. - No execution/runtime: this crate does not talk to a network client or submit transactions. diff --git a/sui-move-call/src/lib.rs b/sui-move-call/src/lib.rs index 488c38c..f6550e5 100644 --- a/sui-move-call/src/lib.rs +++ b/sui-move-call/src/lib.rs @@ -4,18 +4,18 @@ use std::marker::PhantomData; use std::str::FromStr; -use sui_move::{HasKey, MoveStruct, MoveType}; use sui_sdk_types::{Address, Identifier, Mutability, ObjectReference, SharedInput, TypeTag}; +use talus_sui_move::{HasKey, MoveStruct, MoveType}; /// Canonical Sui transaction input kind. /// -/// This is a re-export of [`sui_sdk_types::Input`]. `sui-move-call` uses it directly so this -/// crate can represent every on-chain input kind without re-modeling Sui's wire types. +/// This type is an alias for [`sui_sdk_types::Input`]. `talus-sui-move-call` uses it directly so +/// this crate can represent every Sui transaction input kind without duplicating Sui's wire types. /// /// In this crate, call arguments are typically produced via [`ToCallArg`]. pub use sui_sdk_types::Input as CallArg; -/// Typed object handle for key-bearing Move structs. +/// Typed object handle for Move structs that have the `key` ability. /// /// This is a small wrapper around [`ObjectReference`] that carries the Rust type `T`. /// @@ -28,13 +28,13 @@ pub use sui_sdk_types::Input as CallArg; /// # Example /// ``` /// use std::str::FromStr; -/// use sui_move_call::MoveObject; +/// use talus_sui_move_call::MoveObject; /// use sui_sdk_types::{Address, Digest, ObjectReference}; /// -/// # #[sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] +/// # #[talus_sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] /// # struct UID { id: u64 } /// # -/// #[sui_move::move_struct(address = "0x1", module = "demo", abilities = "key")] +/// #[talus_sui_move::move_struct(address = "0x1", module = "demo", abilities = "key")] /// struct Demo { /// id: UID, /// } @@ -82,13 +82,13 @@ impl MoveObject { /// # Example /// ``` /// use std::str::FromStr; -/// use sui_move_call::SharedMoveObject; +/// use talus_sui_move_call::SharedMoveObject; /// use sui_sdk_types::Address; /// -/// # #[sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] +/// # #[talus_sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] /// # struct UID { id: u64 } /// # -/// #[sui_move::move_struct(address = "0x1", module = "demo", abilities = "key")] +/// #[talus_sui_move::move_struct(address = "0x1", module = "demo", abilities = "key")] /// struct SharedThing { /// id: UID, /// } @@ -114,7 +114,7 @@ impl SharedMoveObject { Self::new(object_id, initial_shared_version, Mutability::Mutable) } - /// Create a non-exclusive-write shared object handle. + /// Create a shared object handle with `NonExclusiveWrite` mutability. pub fn non_exclusive_write(object_id: Address, initial_shared_version: u64) -> Self { Self::new( object_id, @@ -131,7 +131,7 @@ impl SharedMoveObject { } } - /// Borrow the underlying shared-input description. + /// Borrow the underlying shared input description. pub fn shared_input(&self) -> &SharedInput { &self.input } @@ -161,9 +161,9 @@ impl SharedMoveObject { /// /// This corresponds to Sui's `Input::Receiving(ObjectReference)`. /// -/// Receiving is a **transaction input mode**, not an on-chain owner kind. It is used for the Move -/// framework concept `sui::transfer::Receiving`: an ephemeral per-transaction “receiving -/// ticket” that can be consumed by `sui::transfer::receive`/`public_receive`. +/// Receiving is a **transaction input mode**, not an owner kind recorded on chain. It is used for +/// the Move framework concept `sui::transfer::Receiving`: a temporary “receiving ticket” that +/// can be consumed by `sui::transfer::receive`/`public_receive` during one transaction. /// /// This wrapper does not validate whether the referenced object can be received in the current /// transaction; invalid uses are rejected by Sui. @@ -171,13 +171,13 @@ impl SharedMoveObject { /// # Example /// ``` /// use std::str::FromStr; -/// use sui_move_call::ReceivingMoveObject; +/// use talus_sui_move_call::ReceivingMoveObject; /// use sui_sdk_types::{Address, Digest, ObjectReference}; /// -/// # #[sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] +/// # #[talus_sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] /// # struct UID { id: u64 } /// # -/// #[sui_move::move_struct(address = "0x1", module = "demo", abilities = "key")] +/// #[talus_sui_move::move_struct(address = "0x1", module = "demo", abilities = "key")] /// struct ReceivingThing { /// id: UID, /// } @@ -232,14 +232,14 @@ pub enum CallArgError { Tombstoned { /// Object id that was attempted to be used as an argument. object_id: Address, - /// Human-readable reason (deleted, wrapped, not-exist, ...). + /// Explanation suitable for display, such as deleted, wrapped, or nonexistent. reason: &'static str, }, /// The referenced object kind does not match what the conversion requires. /// - /// This is primarily used by higher layers that classify on-chain ownership and choose the - /// correct Sui input mode (owned/immutable vs shared). + /// This is primarily used by higher layers that classify ownership from chain state and choose + /// the correct Sui input mode (owned/immutable vs shared). #[error("object {object_id} has kind {actual}, expected {expected}")] ObjectKind { /// Object id that was attempted to be used as an argument. @@ -266,16 +266,16 @@ pub enum CallArgError { /// conversion only needs an `&self`. /// /// `ToCallArg` is intentionally generic: -/// - for `T: MoveType`, it returns a `CallArg::Pure` by BCS-encoding the value +/// - for `T: MoveType`, it returns a `CallArg::Pure` by encoding the value with BCS /// - for object handle types, it returns the appropriate object input /// -/// Higher layers may implement `ToCallArg` for runtime-owned handles. Those implementations can -/// fail even without BCS encoding errors (for example, if the handle is stale/tombstoned or if its -/// on-chain kind makes it invalid for the requested input mode). +/// Higher layers may implement `ToCallArg` for handles owned by the runtime. Those implementations +/// can fail even without BCS encoding errors, for example if the handle is stale or its current +/// owner kind makes it invalid for the requested input mode. /// /// # Example /// ``` -/// use sui_move_call::{CallArg, ToCallArg}; +/// use talus_sui_move_call::{CallArg, ToCallArg}; /// /// let arg = 7u64.to_call_arg().unwrap(); /// let CallArg::Pure(bytes) = arg else { @@ -372,9 +372,9 @@ pub enum CallSpecError { /// Move call target without encoded arguments. /// -/// This is the lower-level boundary for PTB composition: generated code owns package, module, -/// function, and type arguments, while `sui-move-ptb` can wire arbitrary PTB `Argument`s including -/// previous command results. +/// This is the lower level boundary for PTB composition: generated code owns package, module, +/// function, and type arguments, while `talus-sui-move-ptb` can wire arbitrary PTB `Argument`s, +/// including previous command results. #[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub struct CallTarget { /// Package ID that contains the Move module. @@ -418,19 +418,19 @@ impl CallTarget { /// A description of a Move function call. /// -/// A `CallSpec` carries the call target plus already-encoded arguments. It is designed to be -/// consumed by a transaction-building layer. +/// A `CallSpec` carries the call target plus already encoded arguments. It is designed to be +/// consumed by a transaction building layer. /// /// # Example /// ``` /// use std::str::FromStr; -/// use sui_move_call::{CallSpec, MoveObject}; +/// use talus_sui_move_call::{CallSpec, MoveObject}; /// use sui_sdk_types::{Address, Digest, ObjectReference, TypeTag}; /// -/// # #[sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] +/// # #[talus_sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] /// # struct UID { id: u64 } /// # -/// #[sui_move::move_struct(address = "0x1", module = "vault", abilities = "key")] +/// #[talus_sui_move::move_struct(address = "0x1", module = "vault", abilities = "key")] /// struct Vault { /// id: UID, /// } @@ -501,8 +501,8 @@ impl CallSpec { /// Append an argument by converting it into a `CallArg`. /// - /// This can fail for BCS encoding errors (pure values) and, for higher-layer object handles, - /// for handle state errors (tombstoned/stale handles, kind mismatches, etc.). + /// This can fail because a pure value cannot be encoded with BCS or because a runtime object + /// handle is stale, tombstoned, or incompatible with the requested input kind. pub fn push_arg(&mut self, arg: &A) -> Result<(), CallArgError> { self.arguments.push(arg.to_call_arg()?); Ok(()) @@ -526,12 +526,12 @@ impl CallSpec { } } -/// Convenience re-exports for downstream code. +/// Common exports for downstream code. pub mod prelude { pub use crate::{ CallArg, CallArgError, CallSpec, CallSpecError, CallTarget, MoveObject, ObjectArg, ReceivingMoveObject, SharedMoveObject, ToCallArg, ToCallArgMut, }; - pub use sui_move::prelude::*; pub use sui_sdk_types::Mutability; + pub use talus_sui_move::prelude::*; } diff --git a/sui-move-call/tests/basic.rs b/sui-move-call/tests/basic.rs index f0443f3..0f979ea 100644 --- a/sui-move-call/tests/basic.rs +++ b/sui-move-call/tests/basic.rs @@ -1,22 +1,22 @@ use std::str::FromStr; -use sui_move_call::{ +use sui_sdk_types::{Address, Digest, FundsWithdrawal, ObjectReference, TypeTag, WithdrawFrom}; +use talus_sui_move_call::{ CallArg, CallArgError, CallSpec, MoveObject, ReceivingMoveObject, SharedMoveObject, ToCallArg, ToCallArgMut, }; -use sui_sdk_types::{Address, Digest, FundsWithdrawal, ObjectReference, TypeTag, WithdrawFrom}; -#[sui_move::move_struct(address = "0x2", module = "object", abilities = "copy, store")] +#[talus_sui_move::move_struct(address = "0x2", module = "object", abilities = "copy, store")] struct ID { bytes: Address, } -#[sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] +#[talus_sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] struct UID { id: ID, } -#[sui_move::move_struct(address = "0x1", module = "demo", abilities = "key")] +#[talus_sui_move::move_struct(address = "0x1", module = "demo", abilities = "key")] struct Demo { id: UID, } diff --git a/sui-move-codegen/Cargo.toml b/sui-move-codegen/Cargo.toml index e39cec3..a0a372a 100644 --- a/sui-move-codegen/Cargo.toml +++ b/sui-move-codegen/Cargo.toml @@ -1,12 +1,17 @@ [package] -name = "sui-move-codegen" -version = "0.1.0" -edition = "2021" +name = "talus-sui-move-codegen" +version.workspace = true +edition.workspace = true +rust-version.workspace = true description = "Generate typed Rust bindings (types + CallSpec builders) from Sui Move package metadata." readme = "README.md" +publish = ["crates-io"] license.workspace = true repository.workspace = true homepage.workspace = true +documentation = "https://docs.rs/talus-sui-move-codegen" +keywords = ["sui", "move", "blockchain", "codegen"] +categories = ["api-bindings", "development-tools"] [dependencies] thiserror = { workspace = true } diff --git a/sui-move-codegen/README.md b/sui-move-codegen/README.md index 777a6cc..dabe0e0 100644 --- a/sui-move-codegen/README.md +++ b/sui-move-codegen/README.md @@ -1,16 +1,18 @@ -# sui-move-codegen +# talus-sui-move-codegen Generate typed Rust bindings for a Move package on Sui. -This crate solves one problem: **turn on-chain Move package metadata into Rust source code** that -fits the layered `sui-move*` stack. +The crates.io package is `talus-sui-move-codegen`; Rust code imports it as `talus_sui_move_codegen`. -- `sui-move`: Move-shaped types (`MoveType`, `MoveStruct`, abilities) -- `sui-move-call`: `CallSpec` + typed argument traits (`ToCallArg`, `ObjectArg`) -- `sui-move-ptb`: build a Sui programmable transaction (PTB) from `CallSpec` -- `sui-move-runtime`: cursor-driven runtime for the Read → Tx → Commit mental model + auto-updating - object handles -- `sui-move-codegen` (this crate): generate the bindings (types + call builders) +This crate solves one problem: **turn Move package metadata fetched from Sui into Rust source +code** that fits the layered `talus-sui-move*` stack. + +- `talus-sui-move`: Rust representations of Move types (`MoveType`, `MoveStruct`, abilities) +- `talus-sui-move-call`: `CallSpec` + typed argument traits (`ToCallArg`, `ObjectArg`) +- `talus-sui-move-ptb`: build a Sui programmable transaction (PTB) from `CallSpec` +- `talus-sui-move-runtime`: runtime with a cursor for the Read → Tx → Commit mental model and object + handles that update after commits +- `talus-sui-move-codegen` (this crate): generate the bindings (types + call builders) ## Problem @@ -29,23 +31,23 @@ metadata. The pipeline is intentionally split in two: -1. **Source (network)**: fetch package metadata once and normalize it into a serde-friendly IR - (`NormalizedPackage`). +1. **Source (network)**: fetch package metadata once and normalize it into an IR that supports + Serde (`NormalizedPackage`). 2. **Render (offline)**: render Rust source from that IR. -Because the IR is JSON-serializable, you can commit it and re-render deterministically in CI without -needing network access. +Because the IR is serializable as JSON, you can commit it and render again deterministically in CI +without needing network access. ### Optional source parameter names -Sui package metadata contains function parameter types but not their source names. Network fetched -IR therefore uses deterministic names such as `arg0` and `arg1` by default. +Sui package metadata contains function parameter types but not their source names. IR built from +network data therefore uses deterministic names such as `arg0` and `arg1` by default. Callers that own matching Move source can overlay parameter names before saving or rendering the IR: ```rust,no_run -use sui_move_codegen::{apply_function_parameter_names_from_sources, fetch_package, GrpcClient}; +use talus_sui_move_codegen::{apply_function_parameter_names_from_sources, fetch_package, GrpcClient}; use sui_sdk_types::Address; # async fn demo() -> Result<(), Box> { @@ -59,7 +61,7 @@ apply_function_parameter_names_from_sources(&mut package, "path/to/package/sourc ``` The overlay changes names only. Package identity, function signatures, types, and abilities remain -network derived. The source is trusted metadata and is not verified against published bytecode. +derived from network data. The source is trusted metadata and is not verified against published bytecode. Source and network parameter counts must match. Rust rendering preserves source spelling in Move documentation and converts reserved Rust identifiers safely in generated APIs. @@ -71,16 +73,16 @@ Given a `NormalizedPackage` (either fetched from gRPC or loaded from JSON), this - `call_package()` / `type_package()` / `with_packages(...)` helpers for scoped package address overrides - `type_package_for(...)` / `with_package_context(...)` helpers for exact datatype origins - One Rust module per Move module (or a flat layout via `RenderOptions::flatten`) -- Move datatypes as Rust types (structs use `#[sui_move::move_struct]` via `sui-move`’s `derive` +- Move datatypes as Rust types (structs use `#[talus_sui_move::move_struct]` via `talus-sui-move`’s `derive` feature) - Move functions as generated `*_target` functions -- Optional typed Rust functions that return `sui_move_call::CallSpec` -- (optional) A `TxExt` trait implemented for `sui_move_runtime::Tx` (enable with +- Optional typed Rust functions that return `talus_sui_move_call::CallSpec` +- (optional) A `TxExt` trait implemented for `talus_sui_move_runtime::Tx` (enable with `RenderOptions::emit_tx_ext`) Those generated call builders are designed to be used directly in higher layers: -- `sui-move-ptb` can consume `CallSpec` to build a `ProgrammableTransaction` -- `sui-move-runtime` can consume `CallSpec` via its tx builder (or `sui_move_runtime::tx!`) +- `talus-sui-move-ptb` can consume `CallSpec` to build a `ProgrammableTransaction` +- `talus-sui-move-runtime` can consume `CallSpec` via its tx builder (or `talus_sui_move_runtime::tx!`) Use `with_packages` when generated calls target one deployment package while type tags retain the package that defines the Move types: @@ -191,12 +193,12 @@ assert_eq!(agent_type_package, initial_package); assert_eq!(state_v2_type_package, upgraded_package); ``` -## Example: render from an in-memory IR +## Example: render from an IR in memory ```rust use std::collections::BTreeMap; -use sui_move_codegen::ir::*; -use sui_move_codegen::render::{render_package, RenderOptions}; +use talus_sui_move_codegen::ir::*; +use talus_sui_move_codegen::render::{render_package, RenderOptions}; let pkg = NormalizedPackage { storage_id: "0x1".into(), @@ -258,8 +260,8 @@ generated Rust API: ```rust use std::collections::BTreeMap; -use sui_move_codegen::ir::*; -use sui_move_codegen::render::{render_package, RenderOptions}; +use talus_sui_move_codegen::ir::*; +use talus_sui_move_codegen::render::{render_package, RenderOptions}; let pkg = NormalizedPackage { storage_id: "0x1".into(), @@ -335,16 +337,16 @@ assert!(code.contains("push_arg_mut(arg0)")); ## Optional: runtime `Tx` extension trait -If you want a slightly more ergonomic “append a call” API on top of `sui-move-runtime`, you can -ask codegen to emit a `TxExt` trait implemented for `sui_move_runtime::Tx`. +If you want a slightly more ergonomic “append a call” API on top of `talus-sui-move-runtime`, you can +ask codegen to emit a `TxExt` trait implemented for `talus_sui_move_runtime::Tx`. The generated methods do **not** submit the transaction; they only call `Tx::call(...)`. This keeps the Read → Tx → Commit boundary explicit. ```rust use std::collections::BTreeMap; -use sui_move_codegen::ir::*; -use sui_move_codegen::render::{render_package, RenderOptions}; +use talus_sui_move_codegen::ir::*; +use talus_sui_move_codegen::render::{render_package, RenderOptions}; let pkg = NormalizedPackage { storage_id: "0x1".into(), @@ -415,13 +417,13 @@ assert!(code.contains("fn m__mutate")); ## Example: generic type params and ability bounds -Move generic constraints become Rust `where` bounds using `sui-move`’s marker traits. For example, +Move generic constraints become Rust `where` bounds using `talus-sui-move`’s marker traits. For example, `T: store` becomes `T0: MoveType + HasStore`. ```rust use std::collections::BTreeMap; -use sui_move_codegen::ir::*; -use sui_move_codegen::render::{render_package, RenderOptions}; +use talus_sui_move_codegen::ir::*; +use talus_sui_move_codegen::render::{render_package, RenderOptions}; let pkg = NormalizedPackage { storage_id: "0x1".into(), @@ -464,7 +466,7 @@ assert!(code.contains("target.push_type_arg::();")); ## Example: fetch over gRPC ```rust,no_run -use sui_move_codegen::{fetch_package, GrpcClient}; +use talus_sui_move_codegen::{fetch_package, GrpcClient}; use sui_sdk_types::Address; # async fn demo() -> Result<(), Box> { @@ -482,21 +484,21 @@ println!("{} bytes", json.len()); To keep builds deterministic, fetch metadata once and commit it as JSON, then render from JSON: -1. Fetch and save `NormalizedPackage` JSON (out-of-band; not in `build.rs`) -2. Render Rust bindings from that JSON during builds or as a pre-generation step +1. Fetch and save `NormalizedPackage` JSON (separate; not in `build.rs`) +2. Render Rust bindings from that JSON during builds or before generation This avoids putting network access in CI/build scripts. -## Cross-package type resolution +## Type resolution across packages The renderer only treats primitive Move types and datatypes from the package being rendered as intrinsic. Framework and dependency types are still ordinary package declarations, so register their generated Rust bindings explicitly: ```rust,no_run -use sui_move_codegen::fetch_package; -use sui_move_codegen::render::{render_package, RenderOptions}; -use sui_move_codegen::GrpcClient; +use talus_sui_move_codegen::fetch_package; +use talus_sui_move_codegen::render::{render_package, RenderOptions}; +use talus_sui_move_codegen::GrpcClient; use sui_sdk_types::Address; # async fn demo() -> Result<(), Box> { @@ -514,7 +516,7 @@ let code = render_package(&app, &opts); Without an external binding, an external datatype renders as a `compile_error!`. That keeps missing dependency bindings explicit instead of silently reintroducing handwritten framework mirrors into -`sui-move`. +`talus-sui-move`. ## Using the generated code @@ -523,13 +525,14 @@ expects these crates in the consumer’s `Cargo.toml`: ```toml [dependencies] -sui-move = { path = "../sui-move" } -sui-move-derive = { path = "../sui-move-derive" } -sui-move-call = { path = "../sui-move-call" } +talus-sui-move = "=0.2.0-rc.1" +talus-sui-move-derive = "=0.2.0-rc.1" +talus-sui-move-call = "=0.2.0-rc.1" ``` -If you want to execute calls, add higher layers (`sui-move-ptb`, `sui-move-runtime`) in the same -consumer crate. +If you want to execute calls, add higher layers (`talus-sui-move-ptb`, +`talus-sui-move-runtime`) in the same consumer crate. -`RenderOptions::use_aliases` only affects verbosity in the emitted source (it adds `use sui_move as -sm; use sui_move_call as sm_call;`). It does not change which crates are required. +`RenderOptions::use_aliases` only affects verbosity in the emitted source (it adds +`use talus_sui_move as sm; use talus_sui_move_call as sm_call;`). It does not change which crates +are required. diff --git a/sui-move-codegen/src/ir.rs b/sui-move-codegen/src/ir.rs index 1b19ec7..da56c07 100644 --- a/sui-move-codegen/src/ir.rs +++ b/sui-move-codegen/src/ir.rs @@ -1,4 +1,4 @@ -//! A small, serde-friendly IR for Move package metadata. +//! A small IR for Move package metadata that is compatible with Serde. //! //! This module intentionally models only what code generation needs: //! - Move datatypes (structs/enums) with field layouts and abilities @@ -22,7 +22,7 @@ pub enum Ability { Key, } -/// A fully-qualified type name: `::::`. +/// A fully qualified type name: `::::`. #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] pub struct TypeName { /// `0x...` address. @@ -36,7 +36,7 @@ pub struct TypeName { } impl TypeName { - /// Parse a fully-qualified type name like `0x2::object::UID`. + /// Parse a fully qualified type name like `0x2::object::UID`. /// /// This normalizes the address portion to the same canonical `0x...` representation used by /// the rest of the IR. @@ -112,7 +112,7 @@ pub enum TypeRef { }, /// `0x...::module::Name` Datatype { - /// Fully-qualified name. + /// Fully qualified name. type_name: TypeName, /// Type arguments. type_arguments: Vec, @@ -271,7 +271,7 @@ pub struct Variant { /// A Move datatype definition. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct Datatype { - /// Fully-qualified type name. + /// Fully qualified type name. pub type_name: TypeName, /// Move module name (redundant but convenient). pub module: String, @@ -300,7 +300,7 @@ pub struct NormalizedModule { /// A Move package. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct NormalizedPackage { - /// Storage id of this package version (on-chain object id). + /// Storage id of this package version (on chain object id). /// /// This is the concrete package object id for a specific published version. pub storage_id: String, @@ -315,7 +315,7 @@ pub struct NormalizedPackage { pub modules: BTreeMap, } -/// Function parameter-name overlay failed because source and IR arities differ. +/// Function parameter name recovery failed because source and IR arities differ. #[derive(Clone, Debug, PartialEq, Eq)] pub struct FunctionParameterNameMismatch { /// Move module name. diff --git a/sui-move-codegen/src/lib.rs b/sui-move-codegen/src/lib.rs index 4479751..8a1627c 100644 --- a/sui-move-codegen/src/lib.rs +++ b/sui-move-codegen/src/lib.rs @@ -1,12 +1,12 @@ #![doc = include_str!("../README.md")] #![deny(missing_docs)] -//! See `README.md` for the crate-level overview. +//! See `README.md` for the crate level overview. mod source; mod source_names; -/// Normalized, serde-friendly package IR. +/// Normalized package IR compatible with Serde. pub mod ir; /// Render normalized metadata into Rust source. @@ -32,7 +32,7 @@ pub enum Error { #[error("package missing from response")] MissingPackage, - /// A fully-qualified Move type name could not be parsed. + /// A fully qualified Move type name could not be parsed. #[error("invalid type name: {0}")] InvalidTypeName(String), @@ -52,7 +52,7 @@ pub enum Error { #[error("unknown reference kind: {0}")] UnknownReference(i32), - /// Unknown datatype-kind enum value. + /// Unknown datatype kind enum value. #[error("unknown datatype kind: {0}")] UnknownDatatypeKind(i32), } diff --git a/sui-move-codegen/src/render/builtins.rs b/sui-move-codegen/src/render/builtins.rs index 784f7d0..346c341 100644 --- a/sui-move-codegen/src/render/builtins.rs +++ b/sui-move-codegen/src/render/builtins.rs @@ -1,8 +1,8 @@ -//! Mapping for irreducible built-in Move types. +//! Mapping for primitive Move types that cannot be reduced further. //! //! Sui framework types such as `0x2::object::UID`, `0x2::coin::Coin`, and -//! `0x1::option::Option` are deliberately not mapped here. They are package-defined datatypes and -//! must be generated from package metadata like any other Move package. +//! `0x1::option::Option` are deliberately not mapped here. They are datatypes defined by packages +//! and must be generated from package metadata like any other Move package. use proc_macro2::TokenStream; diff --git a/sui-move-codegen/src/render/calls.rs b/sui-move-codegen/src/render/calls.rs index c6cadf3..00a83b2 100644 --- a/sui-move-codegen/src/render/calls.rs +++ b/sui-move-codegen/src/render/calls.rs @@ -1,4 +1,4 @@ -//! Call-stub rendering (Move functions → call targets and optional `CallSpec` builders). +//! Call stub rendering (Move functions → call targets and optional `CallSpec` builders). //! //! Design goals: //! - keep the generated API “honest”: it mirrors the Move signature shape (generic params, `&mut`) @@ -39,7 +39,7 @@ fn render_function( let sm_call = if opts.use_aliases { quote! { sm_call } } else { - quote! { sui_move_call } + quote! { talus_sui_move_call } }; let fn_ident = idents::ident(&f.name); @@ -130,7 +130,7 @@ fn render_params_and_pushes( let sm_call = if opts.use_aliases { quote! { sm_call } } else { - quote! { sui_move_call } + quote! { talus_sui_move_call } }; let mut params = Vec::new(); @@ -234,7 +234,7 @@ pub(super) fn type_param_bounds( let sm = if use_aliases { quote! { sm } } else { - quote! { sui_move } + quote! { talus_sui_move } }; let required = required_type_param_abilities(f, pkg); diff --git a/sui-move-codegen/src/render/mod.rs b/sui-move-codegen/src/render/mod.rs index 112c9d3..2bc7e19 100644 --- a/sui-move-codegen/src/render/mod.rs +++ b/sui-move-codegen/src/render/mod.rs @@ -6,10 +6,10 @@ //! - render Rust source from the IR in CI/builds (offline). //! //! The generated code is designed to plug into the rest of the workspace: -//! - generated types implement `sui-move` traits (`MoveType` / `MoveStruct`) and ability markers +//! - generated types implement `talus-sui-move` traits (`MoveType` / `MoveStruct`) and ability markers //! - generated call targets identify Move functions for PTB builders -//! - generated call-spec builders can return `sui-move-call::CallSpec` -//! - optionally, a `TxExt` trait is emitted to add calls directly to `sui-move-runtime::Tx` +//! - generated call specification builders can return `talus-sui-move-call::CallSpec` +//! - optionally, a `TxExt` trait is emitted to add calls directly to `talus-sui-move-runtime::Tx` use std::collections::BTreeMap; use std::fs; @@ -38,30 +38,30 @@ pub struct RenderOptions { /// Set this to `false` for consumers that compose PTBs from generated targets and explicit /// `sui_sdk_types::Argument`s. pub emit_call_specs: bool, - /// Emit runtime helpers for `sui-move-runtime` (`TxExt`). + /// Emit runtime helpers for `talus-sui-move-runtime` (`TxExt`). /// /// When enabled, generated code includes a `TxExt` trait implemented for - /// `sui_move_runtime::Tx<'_, S>`. Each Move function becomes a convenience method like + /// `talus_sui_move_runtime::Tx<'_, S>`. Each Move function becomes a convenience method like /// `module__function(...)` that appends a `MoveCall` command by calling `Tx::call(...)`. /// /// This is optional so consumers can use the generated bindings without depending on the /// runtime layer. pub emit_tx_ext: bool, - /// Emit everything into a single flat module (no per-Move-module `mod` blocks). + /// Emit everything into a single flat module, with no `mod` block for each Move module. pub flatten: bool, /// If `true`, include small aliases to reduce verbosity in generated code. /// /// Concretely, this adds: - /// - `use sui_move as sm;` - /// - `use sui_move_call as sm_call;` + /// - `use talus_sui_move as sm;` + /// - `use talus_sui_move_call as sm_call;` pub use_aliases: bool, - /// If `true`, re-export generated datatypes from the package root. + /// If `true`, export generated datatypes from the package root. pub emit_reexports: bool, /// Rust paths for Move datatypes defined outside the package currently being rendered. /// - /// This is the explicit cross-package symbol table. The renderer still treats unknown external + /// This is the explicit external symbol table. The renderer still treats unknown external /// datatypes as compile errors, but entries in this map are rendered as generated Rust paths - /// instead of being folded into the `sui-move` core. + /// instead of being folded into the `talus-sui-move` core. pub external_types: BTreeMap, } @@ -184,14 +184,14 @@ fn external_type_names(pkg: &NormalizedPackage, dt: &crate::ir::Datatype) -> Vec names } -/// Rendered package split into package-root code and one generated module block per Move module. +/// Rendered package split into package root code and one generated module block per Move module. /// /// This is useful for build scripts that need to choose their own `include!` layout without /// parsing rendered Rust source text. #[derive(Clone, Debug, PartialEq, Eq)] pub struct RenderedPackageParts { - /// Package-root code: package constants, package scoping helpers, optional `TxExt`, and - /// optional root re-exports. + /// Package root code: package constants, package scoping helpers, optional `TxExt`, and + /// optional root exports. pub root: String, /// `pub mod ... { ... }` blocks keyed by Move module name. pub modules: BTreeMap, @@ -204,8 +204,8 @@ pub struct RenderedPackageParts { /// # Example /// ``` /// use std::collections::BTreeMap; -/// use sui_move_codegen::ir::*; -/// use sui_move_codegen::render::{render_package, RenderOptions}; +/// use talus_sui_move_codegen::ir::*; +/// use talus_sui_move_codegen::render::{render_package, RenderOptions}; /// /// let pkg = NormalizedPackage { /// storage_id: "0x1".into(), @@ -229,7 +229,7 @@ pub fn render_package(pkg: &NormalizedPackage, opts: &RenderOptions) -> String { util::prettify(tokens) } -/// Render a normalized package into package-root source and per-module `pub mod ...` blocks. +/// Render a normalized package into package root source and one `pub mod ...` block for each module. /// /// Unlike [`render_package_split`], this does not write files or assume `mod.rs` plus sibling /// module files. Callers decide how to include or store the returned strings. @@ -254,7 +254,7 @@ pub fn render_package_parts(pkg: &NormalizedPackage, opts: &RenderOptions) -> Re /// /// This is convenient if you want the generated code to mirror the Move module structure on disk. /// The output directory will contain: -/// - `mod.rs` (with package scope helpers, `pub mod ...;`, and `pub use ...;` re-exports) +/// - `mod.rs` (with package scope helpers, `pub mod ...;`, and `pub use ...;` exports) /// - one `*.rs` file per Move module pub fn render_package_split( pkg: &NormalizedPackage, @@ -727,8 +727,8 @@ mod tests { let code = render_package(&demo_pkg(), &RenderOptions::default()); assert!(code.contains("thread_local!")); - assert!(code.contains("pub fn call_package() -> sui_move::prelude::Address")); - assert!(code.contains("pub fn type_package() -> sui_move::prelude::Address")); + assert!(code.contains("pub fn call_package() -> talus_sui_move::prelude::Address")); + assert!(code.contains("pub fn type_package() -> talus_sui_move::prelude::Address")); assert!(code.contains("pub fn with_packages")); assert!(!code.contains("pub fn package()")); assert!(!code.contains("pub fn with_package")); @@ -742,8 +742,8 @@ mod tests { assert!(code.contains("pub const CALL_PACKAGE")); assert!(code.contains("pub const TYPE_PACKAGE")); - assert!(code.contains("pub fn call_package() -> sui_move::prelude::Address")); - assert!(code.contains("pub fn type_package() -> sui_move::prelude::Address")); + assert!(code.contains("pub fn call_package() -> talus_sui_move::prelude::Address")); + assert!(code.contains("pub fn type_package() -> talus_sui_move::prelude::Address")); assert!(code.contains("pub fn with_packages")); assert!(code.contains("CallTarget::new(call_package(), \"m\", \"mutate\")")); assert!(code.contains("address_fn = \"__type_package_for_Obj\"")); @@ -876,17 +876,17 @@ mod tests { } #[test] - fn renders_structs_with_sui_move_move_struct_attribute() { + fn renders_structs_with_talus_sui_move_move_struct_attribute() { let opts = RenderOptions { use_aliases: false, ..RenderOptions::default() }; let code = render_package(&demo_pkg(), &opts); - assert!(code.contains("#[sui_move::move_struct")); + assert!(code.contains("#[talus_sui_move::move_struct")); } #[test] - fn external_framework_types_are_not_mapped_to_sui_move_core() { + fn external_framework_types_are_not_mapped_to_talus_sui_move_core() { let code = render_package(&demo_pkg(), &RenderOptions::default()); assert!(!code.contains("sm::types::UID")); assert!(code.contains("unknown external type `0x2::object::UID`")); @@ -1024,7 +1024,7 @@ mod tests { let code = render_package(&demo_pkg(), &opts); assert!(code.contains("pub trait TxExt")); assert!(code.contains("fn m__mutate")); - assert!(code.contains("impl<'a, S> TxExt for sui_move_runtime::Tx<'a, S>")); + assert!(code.contains("impl<'a, S> TxExt for talus_sui_move_runtime::Tx<'a, S>")); assert!(code.contains("let spec = m::mutate")); assert!(code.contains("self.call(spec)")); } @@ -1056,7 +1056,7 @@ mod tests { .duration_since(std::time::UNIX_EPOCH) .unwrap() .as_nanos(); - let dir = std::env::temp_dir().join(format!("sui-move-codegen-{unique}")); + let dir = std::env::temp_dir().join(format!("talus-sui-move-codegen-{unique}")); render_package_split(&demo_pkg(), &opts, &dir).unwrap(); diff --git a/sui-move-codegen/src/render/tx_ext.rs b/sui-move-codegen/src/render/tx_ext.rs index 49fbb2c..9735f45 100644 --- a/sui-move-codegen/src/render/tx_ext.rs +++ b/sui-move-codegen/src/render/tx_ext.rs @@ -1,4 +1,4 @@ -//! Optional runtime helpers: generate a `TxExt` trait implemented for `sui-move-runtime`. +//! Optional runtime helpers: generate a `TxExt` trait implemented for `talus-sui-move-runtime`. //! //! This layer is intentionally thin: the generated methods only append a `MoveCall` command by //! calling `Tx::call(module::function(...))`. Committing/simulating/inspecting stays explicit. @@ -37,7 +37,7 @@ pub(crate) fn render_tx_ext(pkg: &NormalizedPackage, opts: &RenderOptions) -> To } let doc = doc_lines(&[ - "Generated `sui-move-runtime` helpers for this package.".to_string(), + "Generated `talus-sui-move-runtime` helpers for this package.".to_string(), String::new(), "Each method appends a `MoveCall` command by calling `Tx::call(...)`.".to_string(), "Committing the transaction is still explicit: call `tx.commit().await`.".to_string(), @@ -49,9 +49,9 @@ pub(crate) fn render_tx_ext(pkg: &NormalizedPackage, opts: &RenderOptions) -> To #(#trait_methods)* } - impl<'a, S> TxExt for sui_move_runtime::Tx<'a, S> + impl<'a, S> TxExt for talus_sui_move_runtime::Tx<'a, S> where - S: sui_move_runtime::SuiSigner, + S: talus_sui_move_runtime::SuiSigner, { #(#impl_methods)* } @@ -101,14 +101,14 @@ fn render_method( let signature = quote! { #doc fn #tx_method_ident #fn_generics (&mut self, #(#params),*) - -> Result + -> Result #where_clause ; }; let implementation = quote! { fn #tx_method_ident #fn_generics (&mut self, #(#params),*) - -> Result + -> Result #where_clause { let spec = #call_expr?; @@ -127,7 +127,7 @@ fn render_params_and_args( let sm_call = if opts.use_aliases { quote! { sm_call } } else { - quote! { sui_move_call } + quote! { talus_sui_move_call } }; let mut params = Vec::new(); diff --git a/sui-move-codegen/src/render/types.rs b/sui-move-codegen/src/render/types.rs index cefa266..ac4fb28 100644 --- a/sui-move-codegen/src/render/types.rs +++ b/sui-move-codegen/src/render/types.rs @@ -1,6 +1,6 @@ //! Datatype rendering (`struct`/`enum`) for generated bindings. //! -//! Structs are emitted using `#[sui_move::move_struct]` so the generated code automatically +//! Structs are emitted using `#[talus_sui_move::move_struct]` so the generated code automatically //! gets `MoveType` / `MoveStruct` implementations plus ability marker traits. //! //! Enums are emitted as Rust `enum`s with manual `MoveType` / `MoveStruct` impls. (Move enum @@ -41,7 +41,7 @@ fn render_datatype_address_function(dt: &Datatype) -> TokenStream { quote! { #[doc(hidden)] #[allow(non_snake_case)] - fn #function() -> sui_move::prelude::Address { + fn #function() -> talus_sui_move::prelude::Address { type_package_for(#module, #datatype) } } @@ -131,7 +131,7 @@ fn render_struct( let macro_path = if opts.use_aliases { quote! { sm::move_struct } } else { - quote! { sui_move::move_struct } + quote! { talus_sui_move::move_struct } }; let rust_copy_derive = is_rust_copy_datatype(dt, pkg).then(|| { quote! { @@ -178,7 +178,7 @@ fn render_enum( let sm = if opts.use_aliases { quote! { sm } } else { - quote! { sui_move } + quote! { talus_sui_move } }; let struct_tag_builder = struct_tag_builder_tokens(dt, opts.use_aliases); let where_clause = where_clause(&bounds); @@ -258,7 +258,7 @@ fn ability_impls_for_datatype( let sm = if opts.use_aliases { quote! { sm } } else { - quote! { sui_move } + quote! { talus_sui_move } }; let (impl_generics, _) = impl_and_type_generics(type_params); @@ -805,22 +805,22 @@ fn render_object_id_helpers(dt: &Datatype) -> TokenStream { let type_ident = idents::ident(&dt.name); quote! { impl #type_ident { - pub fn new(bytes: sui_move::prelude::Address) -> Self { + pub fn new(bytes: talus_sui_move::prelude::Address) -> Self { Self { bytes } } - pub fn address(&self) -> sui_move::prelude::Address { + pub fn address(&self) -> talus_sui_move::prelude::Address { self.bytes } } - impl From for #type_ident { - fn from(value: sui_move::prelude::Address) -> Self { + impl From for #type_ident { + fn from(value: talus_sui_move::prelude::Address) -> Self { Self::new(value) } } - impl From<#type_ident> for sui_move::prelude::Address { + impl From<#type_ident> for talus_sui_move::prelude::Address { fn from(value: #type_ident) -> Self { value.bytes } @@ -838,24 +838,24 @@ fn render_object_uid_helpers(dt: &Datatype) -> TokenStream { let type_ident = idents::ident(&dt.name); quote! { impl #type_ident { - pub fn new(bytes: sui_move::prelude::Address) -> Self { + pub fn new(bytes: talus_sui_move::prelude::Address) -> Self { Self { id: ID::new(bytes), } } - pub fn address(&self) -> sui_move::prelude::Address { + pub fn address(&self) -> talus_sui_move::prelude::Address { self.id.bytes } } - impl From for #type_ident { - fn from(value: sui_move::prelude::Address) -> Self { + impl From for #type_ident { + fn from(value: talus_sui_move::prelude::Address) -> Self { Self::new(value) } } - impl From<#type_ident> for sui_move::prelude::Address { + impl From<#type_ident> for talus_sui_move::prelude::Address { fn from(value: #type_ident) -> Self { value.id.bytes } @@ -875,11 +875,11 @@ fn render_table_like_helpers( quote! { impl #impl_generics #type_ident #type_generics { - pub fn new(id: sui_move::prelude::Address, size: u64) -> Self { + pub fn new(id: talus_sui_move::prelude::Address, size: u64) -> Self { #constructor } - pub fn id(&self) -> sui_move::prelude::Address { + pub fn id(&self) -> talus_sui_move::prelude::Address { self.id.id.bytes } @@ -902,7 +902,7 @@ fn render_id_size_helpers(dt: &Datatype, _opts: &RenderOptions) -> TokenStream { quote! { impl #impl_generics #type_ident #type_generics { - pub fn id(&self) -> sui_move::prelude::Address { + pub fn id(&self) -> talus_sui_move::prelude::Address { self.id.id.bytes } @@ -925,14 +925,14 @@ fn render_table_vec_helpers(dt: &Datatype, _opts: &RenderOptions) -> TokenStream quote! { impl #impl_generics #type_ident #type_generics { - pub fn new(id: sui_move::prelude::Address, size: u64) -> Self { + pub fn new(id: talus_sui_move::prelude::Address, size: u64) -> Self { Self { contents: super::table::Table::new(id, size), phantom_t0: std::marker::PhantomData, } } - pub fn id(&self) -> sui_move::prelude::Address { + pub fn id(&self) -> talus_sui_move::prelude::Address { self.contents.id() } @@ -987,7 +987,7 @@ fn struct_tag_builder_tokens(dt: &Datatype, use_aliases: bool) -> TokenStream { let sm = if use_aliases { quote! { sm } } else { - quote! { sui_move } + quote! { talus_sui_move } }; let module = syn::LitStr::new(&dt.type_name.module, proc_macro2::Span::call_site()); @@ -1013,7 +1013,7 @@ fn enum_derives(abilities: &[Ability], rust_copy: bool, use_aliases: bool) -> To let sm = if use_aliases { quote! { sm } } else { - quote! { sui_move } + quote! { talus_sui_move } }; let has_copy = abilities.contains(&Ability::Copy); @@ -1043,14 +1043,14 @@ fn enum_derives(abilities: &[Ability], rust_copy: bool, use_aliases: bool) -> To } fn serde_crate_attr() -> TokenStream { - quote! { #[serde(crate = "sui_move::__private::serde")] } + quote! { #[serde(crate = "talus_sui_move::__private::serde")] } } fn type_param_bounds(dt: &Datatype, use_aliases: bool) -> Vec { let sm = if use_aliases { quote! { sm } } else { - quote! { sui_move } + quote! { talus_sui_move } }; dt.type_parameters @@ -1135,7 +1135,7 @@ fn render_type_ref( // Keep generation deterministic: unknown external types must be supplied by the // consumer (e.g. another generated package crate). let msg = format!( - "sui-move-codegen: unknown external type `{}`; generate bindings for that package too", + "talus-sui-move-codegen: unknown external type `{}`; generate bindings for that package too", display_type_name(type_name) ); let msg_lit = syn::LitStr::new(&msg, proc_macro2::Span::call_site()); @@ -1212,7 +1212,7 @@ fn render_type_ref_root( return render_external_type(external, &args); } let msg = format!( - "sui-move-codegen: unknown external type `{}`; generate bindings for that package too", + "talus-sui-move-codegen: unknown external type `{}`; generate bindings for that package too", display_type_name(type_name) ); let msg_lit = syn::LitStr::new(&msg, proc_macro2::Span::call_site()); @@ -1245,7 +1245,7 @@ fn render_external_type(external: &ExternalType, args: &[TokenStream]) -> TokenS Ok(path) => quote! { #path }, Err(_) => { let msg = format!( - "sui-move-codegen: invalid external Rust type path `{}`", + "talus-sui-move-codegen: invalid external Rust type path `{}`", external.rust_path ); let msg_lit = syn::LitStr::new(&msg, proc_macro2::Span::call_site()); @@ -1264,7 +1264,7 @@ fn prelude_type(use_aliases: bool, name: TokenStream) -> TokenStream { if use_aliases { quote! { sm::prelude::#name } } else { - quote! { sui_move::prelude::#name } + quote! { talus_sui_move::prelude::#name } } } diff --git a/sui-move-codegen/src/render/util.rs b/sui-move-codegen/src/render/util.rs index 75f9c1d..e77ee83 100644 --- a/sui-move-codegen/src/render/util.rs +++ b/sui-move-codegen/src/render/util.rs @@ -150,7 +150,7 @@ fn package_const_tokens(pkg: &NormalizedPackage, opts: &RenderOptions) -> TokenS .as_deref() .unwrap_or(pkg.storage_id.as_str()); let _ = opts; - let address_ty = quote! { sui_move::prelude::Address }; + let address_ty = quote! { talus_sui_move::prelude::Address }; quote! { /// Package address used as the target for generated Move calls. pub const CALL_PACKAGE: #address_ty = #address_ty::from_static(#call_addr); @@ -162,7 +162,7 @@ fn package_const_tokens(pkg: &NormalizedPackage, opts: &RenderOptions) -> TokenS fn package_scope_tokens(opts: &RenderOptions) -> TokenStream { let _ = opts; - let address_ty = quote! { sui_move::prelude::Address }; + let address_ty = quote! { talus_sui_move::prelude::Address }; quote! { /// Exact datatype origins grouped by module and datatype name. pub type TypeOrigins = std::collections::BTreeMap< @@ -316,9 +316,9 @@ fn aliases(opts: &RenderOptions) -> TokenStream { } quote! { #[allow(unused_imports)] - use sui_move as sm; + use talus_sui_move as sm; #[allow(unused_imports)] - use sui_move_call as sm_call; + use talus_sui_move_call as sm_call; } } diff --git a/sui-move-codegen/src/source.rs b/sui-move-codegen/src/source.rs index a58ade5..d0cec36 100644 --- a/sui-move-codegen/src/source.rs +++ b/sui-move-codegen/src/source.rs @@ -20,7 +20,7 @@ use crate::{Error, GrpcClient}; /// /// # Example /// ```rust,no_run -/// use sui_move_codegen::{fetch_package, GrpcClient}; +/// use talus_sui_move_codegen::{fetch_package, GrpcClient}; /// use sui_sdk_types::Address; /// /// # async fn demo() -> Result<(), Box> { diff --git a/sui-move-codegen/src/source_names.rs b/sui-move-codegen/src/source_names.rs index 78696db..4ff171b 100644 --- a/sui-move-codegen/src/source_names.rs +++ b/sui-move-codegen/src/source_names.rs @@ -350,7 +350,7 @@ module nexus_workflow::execution_settlement; #[test] fn applies_source_parameter_names_to_package() { let temp = std::env::temp_dir().join(format!( - "sui-move-codegen-source-names-{}", + "talus-sui-move-codegen-source-names-{}", SystemTime::now() .duration_since(UNIX_EPOCH) .expect("clock after epoch") diff --git a/sui-move-derive/Cargo.toml b/sui-move-derive/Cargo.toml index 5d40e6f..fbef175 100644 --- a/sui-move-derive/Cargo.toml +++ b/sui-move-derive/Cargo.toml @@ -1,12 +1,17 @@ [package] -name = "sui-move-derive" -version = "0.1.0" -edition = "2021" -description = "Procedural macros for sui-move typed structs." +name = "talus-sui-move-derive" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +description = "Procedural macros for typed Move structs." readme = "README.md" +publish = ["crates-io"] license.workspace = true repository.workspace = true homepage.workspace = true +documentation = "https://docs.rs/talus-sui-move-derive" +keywords = ["sui", "move", "blockchain", "proc-macro"] +categories = ["development-tools::procedural-macro-helpers"] [lib] proc-macro = true @@ -14,7 +19,9 @@ proc-macro = true [dependencies] proc-macro2 = { workspace = true } quote = { workspace = true } -syn = { workspace = true, features = ["full"] } +syn = { workspace = true } +# This development dependency uses only a path and compiles the macro examples locally. +# Cargo omits it from the published package manifest. [dev-dependencies] -sui-move = { path = "../sui-move" } +talus-sui-move = { path = "../sui-move" } diff --git a/sui-move-derive/README.md b/sui-move-derive/README.md index 1cb5116..d17f8d6 100644 --- a/sui-move-derive/README.md +++ b/sui-move-derive/README.md @@ -1,18 +1,21 @@ -# sui-move-derive +# talus-sui-move-derive -Procedural macros for [`sui-move`](../sui-move/README.md): define Move-shaped Rust types with minimal boilerplate. +Procedural macros for [`talus-sui-move`](https://docs.rs/talus-sui-move): define Rust types that +represent Move types with minimal boilerplate. The package is `talus-sui-move-derive`; Rust code +imports it as `talus_sui_move_derive`. -This crate exists to solve one problem: **turn a Rust struct into a Move-shaped type** (correct -`TypeTag`/`StructTag` + ability markers) so it can be used with `sui-move`’s type-tag plumbing and -tag-checked decoding. +This crate exists to solve one problem: **turn a Rust struct into a representation of a Move type** +with the correct `TypeTag`, `StructTag`, and ability markers. It can then use the type tag plumbing +and verified decoding in `talus-sui-move`. ## Where it fits -In the repository’s layered stack (`MODEL.md`), `sui-move-derive` is a convenience layer for the -bottom type system (`sui-move`): +In the repository’s layered +[stack](https://github.com/Talus-Network/move-binding/blob/main/MODEL.md), +`talus-sui-move-derive` is a convenience layer for the bottom type system (`talus-sui-move`): - you describe the Move identity (`address`, `module`, `abilities`) as attributes, -- the macro generates the corresponding `sui_move::MoveType` / `sui_move::MoveStruct` impls and +- the macro generates the corresponding `talus_sui_move::MoveType` / `talus_sui_move::MoveStruct` impls and ability marker impls, - higher layers (call/PTB/runtime) consume those traits for typed interactions. @@ -21,8 +24,8 @@ bottom type system (`sui-move`): Given a struct like: ```rust,no_run -use sui_move::prelude::*; -use sui_move_derive::move_struct; +use talus_sui_move::prelude::*; +use talus_sui_move_derive::move_struct; #[move_struct(address = "0x1", module = "demo", abilities = "copy, store")] pub struct Point { @@ -42,34 +45,34 @@ match tag { The macro generates: -- `impl sui_move::MoveType` and `impl sui_move::MoveStruct` +- `impl talus_sui_move::MoveType` and `impl talus_sui_move::MoveStruct` - Ability marker impls (`HasKey`, `HasStore`, `HasCopy`, `HasDrop`) based on `abilities = "..."` - `serde` derives (without requiring your crate to depend on `serde` directly) - Optional injected `PhantomData` fields for phantom type params -- Compile-time validation for common mistakes (e.g. `key` requires an `id: UID` field) +- Validation during compilation for common mistakes (e.g. `key` requires an `id: UID` field) ## Recommended usage -Most users should depend on `sui-move` and enable its `derive` feature (it re-exports these macros): +Most users should depend on `talus-sui-move` and enable its `derive` feature, which exports these macros: ```toml [dependencies] -sui-move = { path = "../sui-move", features = ["derive"] } +talus-sui-move = { version = "=0.2.0-rc.1", features = ["derive"] } ``` Then use: ```rust,ignore -use sui_move::move_struct; +use talus_sui_move::move_struct; ``` -You can also depend on `sui-move-derive` directly, but you must still depend on `sui-move` because -the generated impls reference it. +You can also depend on `talus-sui-move-derive` directly, but you must still depend on +`talus-sui-move` because the generated impls reference it. ## `#[move_module]` -`#[move_module]` is currently a no-op marker attribute. It can be used to annotate Rust `mod` -blocks that correspond to Move modules. +`#[move_module]` currently leaves the module unchanged. It can annotate Rust `mod` blocks that +correspond to Move modules. ## `#[move_struct(...)]` reference @@ -83,7 +86,7 @@ Optional arguments: - `address_fn = "path::to::fn"`: Function returning the Move address to use for `StructTag`s. `address` remains the default/documented address. - `name = "..."`: Override the Move struct name (defaults to the Rust struct name) -- `abilities = "key, store, copy, drop"`: Move abilities (comma-separated) +- `abilities = "key, store, copy, drop"`: Move abilities (separated by commas) - `copy` implies `drop` - `key` and `copy` are mutually exclusive - `phantoms = "T, U"`: Mark type parameters as phantom and inject `PhantomData` fields @@ -94,30 +97,30 @@ Optional arguments: The macro tries to make the “Move rules” visible as normal Rust type errors: -- Every type parameter gets a `T: sui_move::MoveType` bound. +- Every type parameter gets a `T: talus_sui_move::MoveType` bound. - If the struct has a Move ability (e.g. `store`), the macro adds the corresponding bounds to - each non-phantom field type (e.g. `field_ty: sui_move::HasStore`). + each field type that is not phantom (e.g. `field_ty: talus_sui_move::HasStore`). - For generic fields like `Vec`, this naturally pushes requirements onto `T` (e.g. `Vec: HasStore` implies `T: HasStore`). You can satisfy those requirements either by: -- writing normal Rust bounds (`struct Vault { ... }`), or +- writing normal Rust bounds (`struct Vault { ... }`), or - using `type_abilities = "T: store"` to have the macro add the ability bounds for you. ## Examples -### `key` objects require package-defined `id: UID` +### `key` objects require an `id: UID` type defined by a package ```rust,no_run use std::marker::PhantomData; -use sui_move::prelude::Address; -use sui_move_derive::move_struct; +use talus_sui_move::prelude::Address; +use talus_sui_move_derive::move_struct; /// Local package declaration for `0x2::object::ID`. /// -/// Framework types are ordinary Move declarations from the type-kernel perspective. In production -/// this shape should come from generated package bindings rather than from `sui-move` itself. +/// Framework types are ordinary Move declarations from the type kernel perspective. In production +/// this shape should come from generated package bindings rather than from `talus-sui-move` itself. #[move_struct(address = "0x2", module = "object", abilities = "copy, drop, store")] pub struct ID { pub bytes: Address, @@ -125,7 +128,7 @@ pub struct ID { /// Local package declaration for `0x2::object::UID`. /// -/// A `key` object is recognized by an `id` field whose type is a package-defined `UID` shape. +/// A `key` object is recognized by an `id` field whose type is a `UID` shape defined by a package. #[move_struct(address = "0x2", module = "object", abilities = "store")] pub struct UID { pub id: ID, @@ -143,7 +146,7 @@ pub struct Vault { pub balance: Vec, } -let _tag = as sui_move::MoveType>::type_tag_static(); +let _tag = as talus_sui_move::MoveType>::type_tag_static(); let _value = Vault:: { id: UID { id: ID { @@ -158,7 +161,7 @@ let _value = Vault:: { If you try to declare a `key` struct without an `id` field, it fails at compile time: ```rust,compile_fail -use sui_move_derive::move_struct; +use talus_sui_move_derive::move_struct; #[move_struct(address = "0x1", module = "broken", abilities = "key, store")] pub struct MissingId { @@ -169,9 +172,9 @@ pub struct MissingId { Similarly, invalid ability combinations are rejected: ```rust,compile_fail -use sui_move_derive::move_struct; +use talus_sui_move_derive::move_struct; -/// Minimal package-defined UID fixture for the compile-fail example. +/// Minimal UID fixture defined by a package for the compilation failure example. #[move_struct(address = "0x2", module = "object", abilities = "store")] pub struct UID { pub id: u64, diff --git a/sui-move-derive/src/abilities.rs b/sui-move-derive/src/abilities.rs index bd1bf5b..32ea309 100644 --- a/sui-move-derive/src/abilities.rs +++ b/sui-move-derive/src/abilities.rs @@ -1,9 +1,9 @@ //! Ability parsing and validation helpers. //! //! `#[move_struct]` can accept abilities in two places: -//! - Struct-level abilities via `abilities = "..."` (these drive which marker traits are -//! implemented for the struct). -//! - Type-parameter abilities via `type_abilities = "T: ..."` or via normal Rust bounds on the +//! - Abilities declared on the struct via `abilities = "..."` (these drive which marker traits +//! are implemented for the struct). +//! - Type parameter abilities via `type_abilities = "T: ..."` or via normal Rust bounds on the //! type parameter (e.g. `T: HasStore + HasCopy`). //! //! This module contains the parsing and normalization logic (e.g. `copy` implies `drop`) plus diff --git a/sui-move-derive/src/args.rs b/sui-move-derive/src/args.rs index a30e151..f24c788 100644 --- a/sui-move-derive/src/args.rs +++ b/sui-move-derive/src/args.rs @@ -1,9 +1,8 @@ //! Parsing for the `#[move_struct(...)]` attribute arguments. //! -//! The proc-macro surface accepts a compact string-based syntax (e.g. -//! `abilities = "key, store"`, `type_abilities = "T: store, copy; U: drop"`). This module turns -//! those tokens into a structured representation and produces user-facing errors for malformed -//! input. +//! The procedural macro surface accepts compact string arguments, such as +//! `abilities = "key, store"` and `type_abilities = "T: store, copy; U: drop"`. This module turns +//! those tokens into a structured representation and reports clear errors for malformed input. use std::collections::BTreeMap; diff --git a/sui-move-derive/src/expand.rs b/sui-move-derive/src/expand.rs index 797305e..089a837 100644 --- a/sui-move-derive/src/expand.rs +++ b/sui-move-derive/src/expand.rs @@ -1,12 +1,12 @@ //! Code generation for `#[move_struct]`. //! -//! The high-level expansion steps are: -//! 1. Validate input shape (named-field structs only). +//! Expansion has four steps: +//! 1. Validate input shape (named field structs only). //! 2. Inject `PhantomData` fields for phantom type parameters. -//! 3. Compute ability flags and generate appropriate `where`-bounds. +//! 3. Compute ability flags and generate appropriate constraints in `where` clauses. //! 4. Generate `MoveType`/`MoveStruct` impls and ability marker impls. //! -//! The generated code references `::sui_move` (and its `__private` re-exports) so that downstream +//! The generated code references `::talus_sui_move` and its `__private` exports so that downstream //! crates don't need direct dependencies on `serde` or `sui-sdk-types`. use std::collections::BTreeMap; @@ -143,20 +143,20 @@ pub(crate) fn expand_move_struct( let mut type_param_bounds: Vec = Vec::new(); for param in &type_param_idents { let ident = ¶m.ident; - let mut bounds: Vec = vec![parse_quote!(::sui_move::MoveType)]; + let mut bounds: Vec = vec![parse_quote!(::talus_sui_move::MoveType)]; if let Some(abilities) = type_ability_flags.get(&ident.to_string()) { if abilities.copy { - bounds.push(parse_quote!(::sui_move::HasCopy)); + bounds.push(parse_quote!(::talus_sui_move::HasCopy)); } if abilities.drop { - bounds.push(parse_quote!(::sui_move::HasDrop)); + bounds.push(parse_quote!(::talus_sui_move::HasDrop)); } if abilities.store { - bounds.push(parse_quote!(::sui_move::HasStore)); + bounds.push(parse_quote!(::talus_sui_move::HasStore)); } if abilities.key { - bounds.push(parse_quote!(::sui_move::HasKey)); + bounds.push(parse_quote!(::talus_sui_move::HasKey)); } } @@ -185,13 +185,13 @@ pub(crate) fn expand_move_struct( } let ty = &field.ty; if has_copy { - copy_bounds.push(parse_quote!(#ty: ::sui_move::HasCopy)); + copy_bounds.push(parse_quote!(#ty: ::talus_sui_move::HasCopy)); } if has_drop { - drop_bounds.push(parse_quote!(#ty: ::sui_move::HasDrop)); + drop_bounds.push(parse_quote!(#ty: ::talus_sui_move::HasDrop)); } if has_store { - store_bounds.push(parse_quote!(#ty: ::sui_move::HasStore)); + store_bounds.push(parse_quote!(#ty: ::talus_sui_move::HasStore)); } } @@ -207,21 +207,21 @@ pub(crate) fn expand_move_struct( .iter() .map(|p| { let ident = &p.ident; - quote! { <#ident as ::sui_move::MoveType>::type_tag_static() } + quote! { <#ident as ::talus_sui_move::MoveType>::type_tag_static() } }) .collect::>(); let address_expr = if let Some(address_fn) = &args.address_fn { quote! { #address_fn() } } else { - quote! { ::sui_move::parse_address(#address).expect("invalid address literal") } + quote! { ::talus_sui_move::parse_address(#address).expect("invalid address literal") } }; let struct_tag_builder = quote! { - ::sui_move::__private::sui_sdk_types::StructTag::new( + ::talus_sui_move::__private::sui_sdk_types::StructTag::new( #address_expr, - ::sui_move::parse_identifier(#module_name).expect("invalid module"), - ::sui_move::parse_identifier(#struct_name).expect("invalid struct name"), + ::talus_sui_move::parse_identifier(#module_name).expect("invalid module"), + ::talus_sui_move::parse_identifier(#struct_name).expect("invalid struct name"), vec![#(#ty_params_for_tag),*], ) }; @@ -231,8 +231,8 @@ pub(crate) fn expand_move_struct( parse_quote!(::core::cmp::PartialEq), parse_quote!(::core::cmp::Eq), parse_quote!(::core::hash::Hash), - parse_quote!(::sui_move::__private::serde::Serialize), - parse_quote!(::sui_move::__private::serde::Deserialize), + parse_quote!(::talus_sui_move::__private::serde::Serialize), + parse_quote!(::talus_sui_move::__private::serde::Deserialize), ]; let mut output_struct = input; @@ -292,7 +292,7 @@ pub(crate) fn expand_move_struct( if !serde_has_crate_override { output_struct .attrs - .push(parse_quote!(#[serde(crate = "sui_move::__private::serde")])); + .push(parse_quote!(#[serde(crate = "talus_sui_move::__private::serde")])); } output_struct.attrs.extend(serde_attrs); @@ -320,22 +320,22 @@ pub(crate) fn expand_move_struct( let mut impls = Vec::new(); if has_key { impls.push(quote! { - impl #impl_generics ::sui_move::HasKey for #struct_ident #ty_generics #key_where_clause {} + impl #impl_generics ::talus_sui_move::HasKey for #struct_ident #ty_generics #key_where_clause {} }); } if has_store { impls.push(quote! { - impl #impl_generics ::sui_move::HasStore for #struct_ident #ty_generics #store_where_clause {} + impl #impl_generics ::talus_sui_move::HasStore for #struct_ident #ty_generics #store_where_clause {} }); } if has_copy { impls.push(quote! { - impl #impl_generics ::sui_move::HasCopy for #struct_ident #ty_generics #copy_where_clause {} + impl #impl_generics ::talus_sui_move::HasCopy for #struct_ident #ty_generics #copy_where_clause {} }); } if has_drop { impls.push(quote! { - impl #impl_generics ::sui_move::HasDrop for #struct_ident #ty_generics #drop_where_clause {} + impl #impl_generics ::talus_sui_move::HasDrop for #struct_ident #ty_generics #drop_where_clause {} }); } quote! { #(#impls)* } @@ -360,16 +360,16 @@ pub(crate) fn expand_move_struct( } } - impl #impl_generics ::sui_move::MoveType for #struct_ident #ty_generics #move_type_where_clause { - fn type_tag_static() -> ::sui_move::__private::sui_sdk_types::TypeTag { - ::sui_move::__private::sui_sdk_types::TypeTag::Struct(Box::new( - ::struct_tag_static(), + impl #impl_generics ::talus_sui_move::MoveType for #struct_ident #ty_generics #move_type_where_clause { + fn type_tag_static() -> ::talus_sui_move::__private::sui_sdk_types::TypeTag { + ::talus_sui_move::__private::sui_sdk_types::TypeTag::Struct(Box::new( + ::struct_tag_static(), )) } } - impl #impl_generics ::sui_move::MoveStruct for #struct_ident #ty_generics #move_type_where_clause { - fn struct_tag_static() -> ::sui_move::__private::sui_sdk_types::StructTag { + impl #impl_generics ::talus_sui_move::MoveStruct for #struct_ident #ty_generics #move_type_where_clause { + fn struct_tag_static() -> ::talus_sui_move::__private::sui_sdk_types::StructTag { #struct_tag_builder } } diff --git a/sui-move-derive/src/lib.rs b/sui-move-derive/src/lib.rs index e8d4879..a650e98 100644 --- a/sui-move-derive/src/lib.rs +++ b/sui-move-derive/src/lib.rs @@ -9,16 +9,16 @@ mod util; /// Marker attribute for Move module namespaces. /// -/// Today this is a no-op and exists mainly to make code more readable and leave room for future -/// tooling. +/// This attribute currently leaves the module unchanged. It makes declarations easier to read and +/// leaves room for future tooling. /// /// # Example /// ```rust,no_run -/// use sui_move_derive::{move_module, move_struct}; +/// use talus_sui_move_derive::{move_module, move_struct}; /// /// #[move_module(address = "0x1", name = "vault")] /// mod vault { -/// #[sui_move_derive::move_struct(address = "0x1", module = "vault", abilities = "copy, store")] +/// #[talus_sui_move_derive::move_struct(address = "0x1", module = "vault", abilities = "copy, store")] /// pub struct Counter { /// pub value: u64, /// } @@ -31,19 +31,19 @@ pub fn move_module(_args: TokenStream, input: TokenStream) -> TokenStream { input } -/// Define a Move-shaped struct and derive `sui-move` trait implementations. +/// Define a Rust struct that represents a Move struct and derive `talus-sui-move` traits. /// /// The attribute arguments define the Move address/module/name plus ability surface, and allow /// marking type parameters as phantom. /// /// The macro generates: -/// - `impl sui_move::MoveType` and `impl sui_move::MoveStruct` +/// - `impl talus_sui_move::MoveType` and `impl talus_sui_move::MoveStruct` /// - Ability marker impls (`HasKey`, `HasStore`, `HasCopy`, `HasDrop`) -/// - `serde` derives (via `sui_move::__private`, so downstream crates don't need direct `serde`) +/// - `serde` derives (via `talus_sui_move::__private`, so downstream crates don't need direct `serde`) /// - Optional injected `PhantomData` fields (see `phantoms = "..."`) /// /// # Supported input -/// - Named-field structs only (`struct X { ... }`) +/// - Structs with named fields only (`struct X { ... }`) /// /// # Arguments /// - `address = "0x..."` (required): Move address @@ -51,23 +51,23 @@ pub fn move_module(_args: TokenStream, input: TokenStream) -> TokenStream { /// when building `StructTag`s; `address` remains the default/documented address /// - `module = "..."` (required): Move module name /// - `name = "..."` (optional): override Move struct name (defaults to Rust name) -/// - `abilities = "key, store, copy, drop"` (optional): comma-separated Move abilities -/// - `phantoms = "T, U"` (optional): comma-separated phantom type params +/// - `abilities = "key, store, copy, drop"` (optional): Move abilities separated by commas +/// - `phantoms = "T, U"` (optional): phantom type parameters separated by commas /// - `type_abilities = "T: store, copy; U: drop"` (optional): ability expectations for type params -/// - `uid_type = "path::to::UID"` (optional): override what package-defined type counts as `UID` +/// - `uid_type = "path::to::UID"` (optional): override which package type counts as `UID` /// for `key` enforcement /// /// # Example /// ```rust,no_run /// use std::marker::PhantomData; -/// use sui_move::prelude::Address; -/// use sui_move_derive::move_struct; +/// use talus_sui_move::prelude::Address; +/// use talus_sui_move_derive::move_struct; /// /// /// Local package declaration for `0x2::object::ID`. /// /// -/// /// Framework types are ordinary Move declarations from the type-kernel perspective. In +/// /// Framework types are ordinary Move declarations from the type kernel perspective. In /// /// production this shape should come from generated package bindings rather than from -/// /// `sui-move` itself. +/// /// `talus-sui-move` itself. /// #[move_struct(address = "0x2", module = "object", abilities = "copy, drop, store")] /// pub struct ID { /// pub bytes: Address, @@ -75,7 +75,7 @@ pub fn move_module(_args: TokenStream, input: TokenStream) -> TokenStream { /// /// /// Local package declaration for `0x2::object::UID`. /// /// -/// /// A `key` object is recognized by an `id` field whose type is a package-defined `UID` shape. +/// /// A `key` object is recognized by an `id` field whose type is a `UID` shape defined by a package. /// #[move_struct(address = "0x2", module = "object", abilities = "store")] /// pub struct UID { /// pub id: ID, diff --git a/sui-move-derive/src/util.rs b/sui-move-derive/src/util.rs index 1efb2bb..9b0c122 100644 --- a/sui-move-derive/src/util.rs +++ b/sui-move-derive/src/util.rs @@ -32,12 +32,12 @@ pub(crate) fn has_phantom_attr(attrs: &[Attribute]) -> bool { }) } -/// Whether a field is the package-defined `id: UID` field required by `key` objects. +/// Whether a field is the `id: UID` package field required by `key` objects. /// /// `UID` is intentionally recognized structurally, by field name and final path segment, because -/// the framework declaration is not a core `sui-move` type. Generated framework bindings and local -/// package fixtures should therefore satisfy the default rule without coupling this derive crate to a -/// handwritten core UID mirror. +/// the framework declaration is not a core `talus-sui-move` type. Generated framework bindings +/// and local package fixtures should therefore satisfy the default rule without coupling this +/// derive crate to a handwritten core UID mirror. pub(crate) fn is_uid_field(field: &Field, uid_override: Option<&syn::Type>) -> bool { let has_id_name = field.ident.as_ref().map(|i| i == "id").unwrap_or(false); if !has_id_name { diff --git a/sui-move-ptb/Cargo.toml b/sui-move-ptb/Cargo.toml index d94e4ca..de97f34 100644 --- a/sui-move-ptb/Cargo.toml +++ b/sui-move-ptb/Cargo.toml @@ -1,18 +1,23 @@ [package] -name = "sui-move-ptb" -version = "0.1.0" -edition = "2021" -description = "Programmable-transaction builder for typed Move calls on Sui." +name = "talus-sui-move-ptb" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +description = "Programmable transaction builder for typed Move calls on Sui." readme = "README.md" +publish = ["crates-io"] license.workspace = true repository.workspace = true homepage.workspace = true +documentation = "https://docs.rs/talus-sui-move-ptb" +keywords = ["sui", "move", "blockchain", "transactions"] +categories = ["api-bindings", "development-tools"] [dependencies] -sui-move = { path = "../sui-move" } -sui-move-call = { path = "../sui-move-call" } +talus-sui-move = { workspace = true } +talus-sui-move-call = { workspace = true } sui-sdk-types = { workspace = true } thiserror = { workspace = true } [dev-dependencies] -sui-move = { path = "../sui-move", features = ["derive"] } +talus-sui-move = { workspace = true, features = ["derive"] } diff --git a/sui-move-ptb/README.md b/sui-move-ptb/README.md index a943366..1049de4 100644 --- a/sui-move-ptb/README.md +++ b/sui-move-ptb/README.md @@ -1,16 +1,18 @@ -# sui-move-ptb +# talus-sui-move-ptb -Programmable-transaction building blocks for typed Move calls on Sui. +Programmable transaction building blocks for typed Move calls on Sui. -This crate sits on top of [`sui-move-call`](../sui-move-call/README.md) and solves one problem: +The crates.io package is `talus-sui-move-ptb`; Rust code imports it as `talus_sui_move_ptb`. + +This crate sits on top of [`talus-sui-move-call`](https://docs.rs/talus-sui-move-call) and solves one problem: **turn typed Move call descriptions into a `sui_sdk_types::ProgrammableTransaction`** while hiding input/argument indexing. ## Where it fits -- `sui-move`: Move-shaped types (`MoveType`, `MoveStruct`, abilities) -- `sui-move-call`: typed call descriptions (`CallSpec`, typed input wrappers) -- `sui-move-ptb`: build PTBs from `CallSpec` (this crate) +- `talus-sui-move`: Rust representations of Move types (`MoveType`, `MoveStruct`, abilities) +- `talus-sui-move-call`: typed call descriptions (`CallSpec`, typed input wrappers) +- `talus-sui-move-ptb`: build PTBs from `CallSpec` (this crate) ## The problem this crate solves @@ -23,7 +25,7 @@ Commands do **not** embed inputs directly. Instead, they refer to them by index `Argument::Input(u16)`. They can also refer to prior command results using `Argument::Result(u16)` and `Argument::NestedResult(u16, u16)`. -`sui-move-call::CallSpec` already gives you a typed way to describe a Move call target and its +`talus-sui-move-call::CallSpec` already gives you a typed way to describe a Move call target and its arguments, but it still contains the *inputs themselves* (`Vec`), not `Argument` indices. This crate is the tiny “allocation” layer that: @@ -36,7 +38,7 @@ This crate is the tiny “allocation” layer that: ## Design principles - **Canonical wire types**: this crate uses `sui_sdk_types::{Input, Command, ProgrammableTransaction}` - (via `sui_move_call::CallArg`) instead of re-modeling them. + (via `talus_sui_move_call::CallArg`) instead of modeling them again. - **Minimal surface**: one builder type (`PtbBuilder`) plus a small set of command helpers. - **No runtime**: it only builds PTBs; signing/submission belongs in a higher layer. @@ -61,22 +63,22 @@ meaningful). - `PtbBuilder`: accumulates inputs and commands, and can `call(CallSpec)` to add `Command::MoveCall` - `ptb`: convenience function that runs a closure with a fresh `PtbBuilder` and returns the finished `ProgrammableTransaction` -- `ptb!`: macro wrapper around `ptb(...)` for concise call-site syntax +- `ptb!`: macro wrapper around `ptb(...)` for concise call site syntax ## Example: build a PTB from `CallSpec` ```rust use std::str::FromStr; -use sui_move_call::{CallSpec, MoveObject}; -use sui_move_ptb::ptb; +use talus_sui_move_call::{CallSpec, MoveObject}; +use talus_sui_move_ptb::ptb; use sui_sdk_types::{Address, Digest, ObjectReference}; -#[sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] +#[talus_sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] struct UID { id: u64, } -#[sui_move::move_struct(address = "0x1", module = "vault", abilities = "key")] +#[talus_sui_move::move_struct(address = "0x1", module = "vault", abilities = "key")] struct Vault { id: UID, } @@ -109,16 +111,16 @@ Using the same typed handle multiple times produces a single PTB input (reused b ```rust use std::str::FromStr; -use sui_move_call::{CallSpec, MoveObject}; -use sui_move_ptb::ptb; +use talus_sui_move_call::{CallSpec, MoveObject}; +use talus_sui_move_ptb::ptb; use sui_sdk_types::{Address, Digest, ObjectReference}; -#[sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] +#[talus_sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] struct UID { id: u64, } -#[sui_move::move_struct(address = "0x1", module = "vault", abilities = "key")] +#[talus_sui_move::move_struct(address = "0x1", module = "vault", abilities = "key")] struct Vault { id: UID, } @@ -141,7 +143,7 @@ let pt = ptb(|tx| { }) .unwrap(); -// inputs: vault-object, 1u64, 2u64 (vault input is reused) +// inputs: vault object, 1u64, 2u64 (vault input is reused) assert_eq!(pt.inputs.len(), 3); assert_eq!(pt.commands.len(), 2); ``` @@ -154,16 +156,16 @@ permissive mode and reuses the same input index. ```rust use std::str::FromStr; -use sui_move_call::{CallArg, SharedMoveObject}; -use sui_move_ptb::PtbBuilder; +use talus_sui_move_call::{CallArg, SharedMoveObject}; +use talus_sui_move_ptb::PtbBuilder; use sui_sdk_types::{Address, Argument, Mutability}; -#[sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] +#[talus_sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] struct UID { id: u64, } -#[sui_move::move_struct(address = "0x1", module = "demo", abilities = "key")] +#[talus_sui_move::move_struct(address = "0x1", module = "demo", abilities = "key")] struct Thing { id: UID, } @@ -198,16 +200,16 @@ receiving). `PtbBuilder` detects this early. ```rust use std::str::FromStr; -use sui_move_call::{CallArg, MoveObject, ReceivingMoveObject}; -use sui_move_ptb::{BuildError, PtbBuilder}; +use talus_sui_move_call::{CallArg, MoveObject, ReceivingMoveObject}; +use talus_sui_move_ptb::{BuildError, PtbBuilder}; use sui_sdk_types::{Address, Digest, ObjectReference}; -#[sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] +#[talus_sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] struct UID { id: u64, } -#[sui_move::move_struct(address = "0x1", module = "demo", abilities = "key")] +#[talus_sui_move::move_struct(address = "0x1", module = "demo", abilities = "key")] struct Thing { id: UID, } @@ -235,13 +237,13 @@ assert!(matches!(&tx2.inputs()[0], CallArg::Receiving(_))); ```rust use std::str::FromStr; -use sui_move_call::CallSpec; +use talus_sui_move_call::CallSpec; use sui_sdk_types::Address; let package = Address::from_str("0x1").unwrap(); let spec = CallSpec::new(package, "m", "f").unwrap(); -let pt = sui_move_ptb::ptb! { +let pt = talus_sui_move_ptb::ptb! { spec; } .unwrap(); @@ -249,7 +251,7 @@ let pt = sui_move_ptb::ptb! { assert_eq!(pt.commands.len(), 1); ``` -## Non-goals +## Out of scope - No execution/runtime: this crate does not submit transactions. - No object fetching/decoding: it only wires inputs and commands. diff --git a/sui-move-ptb/src/lib.rs b/sui-move-ptb/src/lib.rs index 5f2b690..49ef80f 100644 --- a/sui-move-ptb/src/lib.rs +++ b/sui-move-ptb/src/lib.rs @@ -3,12 +3,12 @@ use std::borrow::Borrow; -use sui_move_call::{CallArg, CallArgError, CallSpec, CallSpecError, CallTarget, ToCallArg}; use sui_sdk_types::{ Address, Argument, Command, FundsWithdrawal, MakeMoveVector, MergeCoins, MoveCall, Mutability, ObjectReference, Owner, ProgrammableTransaction, Publish, SharedInput, SplitCoins, TransferObjects, TypeTag, WithdrawFrom, }; +use talus_sui_move_call::{CallArg, CallArgError, CallSpec, CallSpecError, CallTarget, ToCallArg}; /// Fixed shared object ID for `0x2::clock::Clock`. pub const CLOCK_OBJECT_ID: Address = Address::from_static("0x6"); @@ -65,7 +65,7 @@ pub enum BuildError { /// to those indices. /// /// `PtbBuilder` is the small “allocation” layer that: -/// - collects inputs (Sui `Input`s, via `sui_move_call::CallArg`) into a PTB input table, +/// - collects inputs (Sui `Input`s, via `talus_sui_move_call::CallArg`) into a PTB input table, /// - emits PTB commands, /// - returns the final `ProgrammableTransaction`. /// @@ -85,7 +85,7 @@ impl PtbBuilder { /// Borrow the accumulated PTB inputs. /// - /// These are the canonical Sui `Input`s (re-exported as `sui_move_call::CallArg`). + /// These are the canonical Sui `Input`s, also exported as `talus_sui_move_call::CallArg`. pub fn inputs(&self) -> &[CallArg] { &self.inputs } @@ -184,8 +184,8 @@ impl PtbBuilder { /// /// # Example /// ``` - /// use sui_move_call::CallArg; - /// use sui_move_ptb::PtbBuilder; + /// use talus_sui_move_call::CallArg; + /// use talus_sui_move_ptb::PtbBuilder; /// use sui_sdk_types::Argument; /// /// let mut tx = PtbBuilder::new(); @@ -202,14 +202,14 @@ impl PtbBuilder { /// Convert a typed value into an input and return the corresponding `Argument::Input`. /// - /// This uses [`ToCallArg`] from `sui-move-call`, so: + /// This uses [`ToCallArg`] from `talus-sui-move-call`, so: /// - `T: MoveType` becomes `Input::Pure(bcs(T))` /// - typed object handles become the corresponding object input kinds pub fn arg(&mut self, value: &A) -> Result { self.input(value.to_call_arg()?) } - /// Add pre-encoded BCS bytes as a pure PTB input. + /// Add already encoded BCS bytes as a pure PTB input. /// /// Prefer [`Self::arg`] when the Rust type is available. Use this for dynamic ABI edges where /// the exact Move type is discovered at runtime and the value has already been BCS encoded. @@ -250,8 +250,8 @@ impl PtbBuilder { /// Add an object input using ownership metadata returned by Sui RPC. /// - /// Shared-like objects become `Input::Shared`; immutable/address-owned objects can be used - /// only when immutable access was requested. + /// Objects with a shared input shape become `Input::Shared`. Immutable objects and objects + /// owned by an address require immutable access. pub fn object_from_owner( &mut self, object: &ObjectReference, @@ -307,7 +307,7 @@ impl PtbBuilder { /// identical ones when possible), emits `Command::MoveCall`, and returns `Argument::Result` /// pointing at the command result. /// - /// If the called function returns multiple values, you can access sub-results using + /// If the called function returns multiple values, you can access nested results using /// `Argument::nested`. pub fn call(&mut self, spec: CallSpec) -> Result { let arguments = spec @@ -331,7 +331,7 @@ impl PtbBuilder { /// /// Use this for composed PTBs where some arguments are previous command results instead of /// fresh transaction inputs. Generated bindings should still provide the [`CallTarget`], so - /// package/module/function/type-argument identity does not fall back to hand-written strings. + /// package/module/function/type argument identity does not fall back to handwritten strings. pub fn call_target( &mut self, target: CallTarget, @@ -403,8 +403,8 @@ impl PtbBuilder { Ok(Argument::Result(cmd_idx)) } - /// Build a typed Move `vector` from already-built PTB arguments. - pub fn move_vector( + /// Build a typed Move `vector` from already built PTB arguments. + pub fn move_vector( &mut self, elements: Vec, ) -> Result { @@ -426,7 +426,7 @@ impl PtbBuilder { Ok(Argument::Result(cmd_idx)) } - /// Return a nested result argument for a multi-return command. + /// Return a nested result argument for a command that returns multiple values. pub fn nested_result(&self, argument: Argument, ix: u16) -> Result { nested_result(argument, ix) } @@ -446,8 +446,8 @@ impl PtbBuilder { /// /// # Example /// ``` -/// use sui_move_call::CallSpec; -/// use sui_move_ptb::ptb; +/// use talus_sui_move_call::CallSpec; +/// use talus_sui_move_ptb::ptb; /// use sui_sdk_types::Address; /// /// let package = Address::from_hex("0x1").unwrap(); @@ -469,7 +469,7 @@ pub fn ptb( Ok(builder.finish()) } -/// Return a nested result argument for a multi-return command. +/// Return a nested result argument for a command that returns multiple values. /// /// This is a checked wrapper around [`Argument::nested`] so transaction builders can propagate a /// normal [`BuildError`] instead of panicking or unwrapping. @@ -481,17 +481,17 @@ pub fn nested_result(argument: Argument, ix: u16) -> Result { +/// let pt = talus_sui_move_ptb::ptb!(tx => { /// tx.call(spec)?; /// Ok(()) /// }) @@ -501,13 +501,13 @@ pub fn nested_result(argument: Argument, ix: u16) -> Result Option
{ diff --git a/sui-move-ptb/tests/basic.rs b/sui-move-ptb/tests/basic.rs index 246e0dc..8e6abc6 100644 --- a/sui-move-ptb/tests/basic.rs +++ b/sui-move-ptb/tests/basic.rs @@ -1,25 +1,25 @@ use std::str::FromStr; -use sui_move_call::{ - CallArg, CallSpec, CallTarget, MoveObject, ReceivingMoveObject, SharedMoveObject, -}; -use sui_move_ptb::{ptb, BuildError, PtbBuilder}; use sui_sdk_types::{ Address, Argument, Command, Digest, FundsWithdrawal, Mutability, ObjectReference, Owner, TypeTag, WithdrawFrom, }; +use talus_sui_move_call::{ + CallArg, CallSpec, CallTarget, MoveObject, ReceivingMoveObject, SharedMoveObject, +}; +use talus_sui_move_ptb::{ptb, BuildError, PtbBuilder}; -#[sui_move::move_struct(address = "0x2", module = "object", abilities = "copy, store")] +#[talus_sui_move::move_struct(address = "0x2", module = "object", abilities = "copy, store")] struct ID { bytes: Address, } -#[sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] +#[talus_sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] struct UID { id: ID, } -#[sui_move::move_struct(address = "0x1", module = "demo", abilities = "key")] +#[talus_sui_move::move_struct(address = "0x1", module = "demo", abilities = "key")] struct Thing { id: UID, } @@ -82,7 +82,7 @@ fn generic_object_helpers_build_canonical_inputs() { let CallArg::Shared(clock) = &tx.inputs()[2] else { panic!("expected shared clock input") }; - assert_eq!(clock.object_id(), sui_move_ptb::CLOCK_OBJECT_ID); + assert_eq!(clock.object_id(), talus_sui_move_ptb::CLOCK_OBJECT_ID); assert_eq!(clock.version(), 1); assert_eq!(clock.mutability(), Mutability::Immutable); } @@ -308,10 +308,10 @@ fn nested_result_helper_requires_command_result() { Argument::NestedResult(7, 2) ); assert_eq!( - sui_move_ptb::nested_result(result, 2).unwrap(), + talus_sui_move_ptb::nested_result(result, 2).unwrap(), Argument::NestedResult(7, 2) ); - let err = sui_move_ptb::nested_result(Argument::Input(0), 0).unwrap_err(); + let err = talus_sui_move_ptb::nested_result(Argument::Input(0), 0).unwrap_err(); assert!(matches!(err, BuildError::ExpectedCommandResult { .. })); } diff --git a/sui-move-runtime/Cargo.toml b/sui-move-runtime/Cargo.toml index a1e7aff..21173e8 100644 --- a/sui-move-runtime/Cargo.toml +++ b/sui-move-runtime/Cargo.toml @@ -1,23 +1,28 @@ [package] -name = "sui-move-runtime" -version = "0.1.0" -edition = "2021" -description = "Runtime layer for typed Move interactions on Sui (submit, wait, auto-update handles)." +name = "talus-sui-move-runtime" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +description = "Runtime layer for typed Move interactions on Sui with automatic handle updates." readme = "README.md" +publish = ["crates-io"] license.workspace = true repository.workspace = true homepage.workspace = true +documentation = "https://docs.rs/talus-sui-move-runtime" +keywords = ["sui", "move", "blockchain", "transactions"] +categories = ["api-bindings", "development-tools"] [dependencies] thiserror = { workspace = true } sui-sdk-types = { workspace = true } serde = { workspace = true } -sui-move = { version = "0.1.0", path = "../sui-move" } -sui-move-call = { version = "0.1.0", path = "../sui-move-call" } -sui-move-ptb = { version = "0.1.0", path = "../sui-move-ptb" } +talus-sui-move = { workspace = true } +talus-sui-move-call = { workspace = true } +talus-sui-move-ptb = { workspace = true } sui-rpc = { workspace = true } sui-crypto = { workspace = true } [dev-dependencies] serde_json = { workspace = true } -sui-move = { path = "../sui-move", features = ["derive"] } +talus-sui-move = { workspace = true, features = ["derive"] } diff --git a/sui-move-runtime/README.md b/sui-move-runtime/README.md index 6bdaebd..fcd263d 100644 --- a/sui-move-runtime/README.md +++ b/sui-move-runtime/README.md @@ -1,28 +1,32 @@ -# sui-move-runtime +# talus-sui-move-runtime Runtime layer for typed Move interactions on Sui. +The crates.io package is `talus-sui-move-runtime`; Rust code imports it as `talus_sui_move_runtime`. + This crate sits at the top of this stack: -- [`sui-move`](../sui-move/README.md): Move-shaped types (`MoveType`, `MoveStruct`, abilities) -- [`sui-move-call`](../sui-move-call/README.md): typed call descriptions (`CallSpec`) and `ToCallArg` -- [`sui-move-ptb`](../sui-move-ptb/README.md): build a `ProgrammableTransaction` (PTB) from `CallSpec` -- `sui-move-runtime` (this crate): submit/simulate/inspect PTBs + keep runtime-owned handles up to date +- [`talus-sui-move`](https://docs.rs/talus-sui-move): Rust representations of Move types + (`MoveType`, `MoveStruct`, abilities) +- [`talus-sui-move-call`](https://docs.rs/talus-sui-move-call): typed call descriptions (`CallSpec`) and `ToCallArg` +- [`talus-sui-move-ptb`](https://docs.rs/talus-sui-move-ptb): build a `ProgrammableTransaction` (PTB) from `CallSpec` +- `talus-sui-move-runtime` (this crate): submit, simulate, or inspect PTBs and keep handles up to date This crate solves one problem: **provide an ergonomic Read → Tx → Commit boundary for typed Sui interactions** while staying -truthful to Sui’s “versioned objects + effects” model (`MODEL.md`): +truthful to Sui’s +[versioned objects + effects model](https://github.com/Talus-Network/move-binding/blob/main/MODEL.md): - In **Read** you fetch objects and prepare call specs. -- In **Tx** you build a PTB and can simulate / dev-inspect / commit it. +- In **Tx** you build a PTB and can simulate, inspect, or commit it. - On **commit**, you always get a `Receipt` (digest + effects/status when available + finality - info), and the runtime advances its local cursor by applying an effects-derived patch whenever - effects are present. + info), and the runtime advances its local cursor by applying a patch derived from any available + effects. -## Quickstart (end-to-end) +## Quickstart (complete) ```rust,no_run -use sui_move_runtime::prelude::*; +use talus_sui_move_runtime::prelude::*; use sui_sdk_types::{Address, PersonalMessage, Transaction, UserSignature}; # #[derive(Clone)] @@ -36,10 +40,10 @@ use sui_sdk_types::{Address, PersonalMessage, Transaction, UserSignature}; # } # } # -# #[sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] +# #[talus_sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] # struct UID { id: u64 } # -# #[sui_move::move_struct(address = "0x1", module = "demo", abilities = "key")] +# #[talus_sui_move::move_struct(address = "0x1", module = "demo", abilities = "key")] # struct Demo { # id: UID, # } @@ -60,16 +64,16 @@ async fn demo() -> Result<(), Error> { let mut rt = Runtime::new(client, signer); - // Read: fetch a typed runtime-owned handle. + // Read: fetch a typed handle owned by the runtime. let object: Object = rt.read().object::(object_id).await?; - // Tx: one-shot build + commit with the `tx!` macro. - let receipt = sui_move_runtime::tx!(&mut rt, sender => { + // Tx: build and commit once with the `tx!` macro. + let receipt = talus_sui_move_runtime::tx!(&mut rt, sender => { touch_object(&object, 10); }) .await?; - // On-chain execution failures are recorded in the receipt (they are not transport errors). + // Execution failures are recorded in the receipt (they are not transport errors). receipt.ensure_success()?; // Back in Read: `object`'s `ObjectReference` has been updated internally. @@ -88,7 +92,7 @@ async fn demo() -> Result<(), Error> { - Ergonomic helper: - `tx!`: macro that builds a `Tx`, runs an action, and returns a future (`.await`) - Handles (all implement `ToCallArg`): - - `Object`: runtime-owned object handle; picks the correct input mode on conversion (shared defaults to immutable) + - `Object`: object handle owned by the runtime; picks the correct input mode on conversion (shared defaults to immutable) - `SharedObject`: explicit shared input (`Input::Shared`) - `ReceivingObject`: explicit receiving input (`Input::Receiving`) - Transaction actions: @@ -98,25 +102,25 @@ async fn demo() -> Result<(), Error> { ## Preflight and debugging (simulate / inspect) -If you want a one-shot action, use the `tx!` macro variants: +If you want a single action, use the `tx!` macro variants: ```rust,no_run -use sui_move_runtime::prelude::*; +use talus_sui_move_runtime::prelude::*; use sui_sdk_types::Address; -# #[sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] +# #[talus_sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] # struct UID { id: u64 } # -# #[sui_move::move_struct(address = "0x1", module = "demo", abilities = "key")] +# #[talus_sui_move::move_struct(address = "0x1", module = "demo", abilities = "key")] # struct Demo { id: UID } # # async fn demo(mut rt: Runtime, sender: Address, object: Object) -> Result<(), Error> { -let _sim = sui_move_runtime::tx!(simulate, &mut rt, sender => { +let _sim = talus_sui_move_runtime::tx!(simulate, &mut rt, sender => { CallSpec::new("0x1".parse().unwrap(), "m", "f").unwrap(); }) .await?; -let _dbg = sui_move_runtime::tx!(inspect, &mut rt, sender => { +let _dbg = talus_sui_move_runtime::tx!(inspect, &mut rt, sender => { CallSpec::new("0x1".parse().unwrap(), "m", "f").unwrap(); }) .await?; @@ -128,7 +132,7 @@ let _dbg = sui_move_runtime::tx!(inspect, &mut rt, sender => { If you need to simulate/inspect the **exact same PTB** before committing it, build a `Tx` once: ```rust,no_run -use sui_move_runtime::prelude::*; +use talus_sui_move_runtime::prelude::*; # async fn demo(mut rt: Runtime, sender: sui_sdk_types::Address) -> Result<(), Error> { let mut tx = rt.tx(sender); @@ -146,11 +150,11 @@ receipt.ensure_success()?; Sui has two related but distinct concepts: -- **On-chain owner kinds** (`sui_sdk_types::Owner`): what an object *is* right now. +- **Owner kinds from chain state** (`sui_sdk_types::Owner`): what an object *is* right now. - **Transaction input modes** (`sui_sdk_types::Input`): how you pass an object *this time*. -This crate uses on-chain ownership (from `Owner`) to choose a safe default transaction input mode -when converting an [`Object`] into an argument. +This crate uses ownership from chain state (from `Owner`) to choose a safe default transaction +input mode when converting an [`Object`] into an argument. Transaction input modes for objects have different wire shapes and are intentionally represented as distinct types: @@ -159,42 +163,42 @@ distinct types: - Shared: `Input::Shared(SharedInput)` (uses `initial_shared_version` + mutability) - Receiving: `Input::Receiving(ObjectReference)` (transaction input mode for `sui::transfer::Receiving`) -Note: receiving is not an on-chain owner kind. It is an ephemeral per-transaction “receiving -ticket” consumed by `sui::transfer::receive`/`public_receive`. +Note: receiving is not an owner kind recorded on chain. It is a temporary “receiving ticket” +consumed by `sui::transfer::receive`/`public_receive`. Note: Sui also has `Owner::ConsensusAddress { start_version, owner }` objects. They use the -shared-like input shape (`start_version` plays the same role as `initial_shared_version`). +shared input shape (`start_version` plays the same role as `initial_shared_version`). Note: child objects (`Owner::Object(_)`) cannot be used as direct transaction inputs. This crate rejects them early when you try to construct handles that would later become invalid inputs. This crate mirrors those shapes: -- Use `Read::object::(id)` to get an `Object` for owned/immutable and shared-like objects. - - Shared-like objects default to immutable shared when used as an argument. +- Use `Read::object::(id)` to get an `Object` for owned, immutable, and shared input shapes. + - Objects with a shared input shape default to immutable shared when used as an argument. - Derive explicit views when needed: `obj.shared_immutable()?`, `obj.shared_mutable()?`, `obj.receiving()?`. ### Explicit views from `Object` `Object` chooses `Input::ImmutableOrOwned` vs `Input::Shared` based on the runtime’s latest -known owner kind. When an object is shared-like, it defaults to **immutable shared**. +known owner kind. When an object has a shared input shape, it defaults to **immutable shared**. If you need a specific input mode, derive an explicit view at the moment it matters: ```rust,no_run -use sui_move_runtime::prelude::*; +use talus_sui_move_runtime::prelude::*; -#[sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] +#[talus_sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] struct UID { id: u64, } -#[sui_move::move_struct(address = "0x1", module = "demo", abilities = "key")] +#[talus_sui_move::move_struct(address = "0x1", module = "demo", abilities = "key")] struct Demo { id: UID, } -fn views(obj: Object) -> Result<(), sui_move_call::CallArgError> { +fn views(obj: Object) -> Result<(), talus_sui_move_call::CallArgError> { let _shared_mut: SharedObject = obj.shared_mutable()?; let _receiving: ReceivingObject = obj.receiving()?; Ok(()) @@ -205,15 +209,15 @@ fn views(obj: Object) -> Result<(), sui_move_call::CallArgError> { All transaction actions take a sender address and are methods on a transaction builder (`Tx`): -- `call` / `arg` / `input`: build the PTB in-place. +- `call` / `arg` / `input`: build the PTB in place. - `simulate`: calls `simulate_transaction` with checks enabled. No signature is required and the chain is not mutated. Handles are not updated. - `inspect`: calls `simulate_transaction` with checks disabled and asks gRPC for `command_outputs`. This is meant for debugging and observability, not for guaranteeing that a - real on-chain commit will succeed. + real commit on chain will succeed. - `commit`: builds a full `Transaction`, signs it, and submits it. - By default it also waits for checkpoint inclusion (`TxOptions::finality = Checkpointed`). - - When execution-only finality is requested (`TxOptions::finality = Executed`), the runtime + - When the caller requests execution finality (`TxOptions::finality = Executed`), the runtime returns as soon as the transaction is executed (effects produced). - In both cases it requests `effects.bcs` so the runtime can decode `TransactionEffects` and refresh handles. @@ -236,7 +240,7 @@ If a receipt does not contain effects (for example, because it was persisted wit can recover by digest and advance the cursor explicitly: ```rust,no_run -use sui_move_runtime::prelude::*; +use talus_sui_move_runtime::prelude::*; # async fn demo(mut rt: Runtime, receipt: Receipt) -> Result<(), Error> { if receipt.effects.is_none() { @@ -247,7 +251,7 @@ Ok(()) ``` ```rust,no_run -use sui_move_runtime::prelude::*; +use talus_sui_move_runtime::prelude::*; use std::time::Duration; use sui_sdk_types::Address; @@ -296,10 +300,10 @@ receipt.ensure_success()?; ## Building PTBs directly (more complex flows) If you need native PTB commands (coin ops, transfers, result wiring, etc), build the PTB explicitly -using `sui-move-ptb` and pass it to `commit_ptb` / `simulate_ptb` / `inspect_ptb`. +using `talus-sui-move-ptb` and pass it to `commit_ptb` / `simulate_ptb` / `inspect_ptb`. ```rust -use sui_move_runtime::prelude::*; +use talus_sui_move_runtime::prelude::*; use sui_sdk_types::Address; let package: Address = "0x1".parse().unwrap(); @@ -328,27 +332,27 @@ assert_eq!(ptb.commands.len(), 1); `simulate`/`inspect` do not sign or submit, and do not currently model explicit gas payment configuration (they rely on the simulation gRPC). -## Typed reads (tag-checked decoding) +## Typed reads with tag verification In addition to constructing handles, `Read` can fetch and decode Move object contents: -- `Read::get::(id) -> (Object, T)`: tag-check + decode and return both a handle and value. +- `Read::get::(id) -> (Object, T)`: tag check + decode and return both a handle and value. - `Read::decode(&Object) -> T`: refresh the handle and decode the latest contents. -- `*_unchecked` variants skip type-tag verification (explicit escape hatch). +- `*_unchecked` variants skip type tag verification (explicit escape hatch). -These helpers use `sui-move`’s tag-checked decoding (`MoveInstance`), so “type tag says X but -BCS layout expects Y” becomes an explicit error instead of a silent footgun. +These helpers use `talus-sui-move` decoding with tag verification (`MoveInstance`), so “type tag +says X but BCS layout expects Y” becomes an explicit error instead of a silent footgun. ```rust,no_run -use sui_move_runtime::prelude::*; +use talus_sui_move_runtime::prelude::*; use sui_sdk_types::Address; -#[sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] +#[talus_sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] struct UID { id: u64, } -#[sui_move::move_struct(address = "0x1", module = "demo", abilities = "key")] +#[talus_sui_move::move_struct(address = "0x1", module = "demo", abilities = "key")] struct Demo { id: UID, value: u64, @@ -371,7 +375,7 @@ To keep your Move interface layer usable in every context (unit tests, pure PTB write interface functions against `ToCallArg` instead of concrete handle types: ```rust -use sui_move_runtime::prelude::*; +use talus_sui_move_runtime::prelude::*; use sui_sdk_types::Address; fn transfer_any_object(obj: &impl ToCallArg, recipient: Address) -> CallSpec { @@ -385,21 +389,21 @@ fn transfer_any_object(obj: &impl ToCallArg, recipient: Address) -> CallSpec { This works with: -- `sui_move_call::MoveObject` (a plain wrapper around `ObjectReference`), and -- `sui_move_runtime::Object` (a runtime-owned handle that auto-updates on commit). +- `talus_sui_move_call::MoveObject` (a plain wrapper around `ObjectReference`), and +- `talus_sui_move_runtime::Object` (a handle owned by the runtime that updates on commit). -## How runtime-owned handles work +## How runtime handles work On Sui, mutating an object changes its `ObjectReference` (version/digest). Updating these refs manually is annoying and tends to leak plumbing into user code. -This crate makes handles *runtime-owned*: +This crate lets the runtime own handles: - `Read::object`/`Read::receiving_object` fetch the current `ObjectReference` and **intern** it in a cursor (your local frontier) keyed by `object_id`. - The returned `Object` / `ReceivingObject` is a small `Clone` handle backed by `Arc>`. - `Tx::commit` requests `effects.bcs` from gRPC, decodes `TransactionEffects`, extracts updated - object information, derives an effects-based patch, and applies it to the cursor, updating any + object information, derives a patch from those effects, and applies it to the cursor, updating any live handle cells that match those object ids. Consequences: @@ -413,18 +417,18 @@ Consequences: ### Storing handles in Rust structs -The point of runtime-owned handles is that you can store them in normal Rust state without +The point of handles owned by the runtime is that you can store them in normal Rust state without threading `&mut ObjectReference` everywhere. ```rust,no_run -use sui_move_runtime::prelude::*; +use talus_sui_move_runtime::prelude::*; -#[sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] +#[talus_sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] struct UID { id: u64, } -#[sui_move::move_struct(address = "0x1", module = "demo", abilities = "key")] +#[talus_sui_move::move_struct(address = "0x1", module = "demo", abilities = "key")] struct Demo { id: UID, } @@ -439,10 +443,10 @@ let wallet = Wallet { object: rt.read().object("0x2".parse().unwrap()).await?, }; -let ptb = sui_move_ptb::ptb! { - // any call that mutates `wallet.object` on-chain +let ptb = talus_sui_move_ptb::ptb! { + // any call that mutates `wallet.object` in chain state CallSpec::new("0x1".parse().unwrap(), "m", "f").unwrap(); -}?; +}?; rt.tx(sender).commit_ptb(ptb).await?; // The `ObjectReference` is refreshed internally after commit. @@ -453,11 +457,12 @@ let _latest = wallet.object.reference(); ## Outputs from `inspect` / decoding BCS -Dev-inspect returns per-command outputs as raw BCS blobs (`BcsValue`). This crate does not impose a -new typing layer on top of those blobs, but you can decode them using `sui_sdk_types::bcs`: +Inspection returns outputs for each command as raw BCS blobs (`BcsValue`). This crate does not +impose a new typing layer on top of those blobs, but you can decode them using +`sui_sdk_types::bcs`: ```rust -use sui_move_runtime::BcsValue; +use talus_sui_move_runtime::BcsValue; use sui_sdk_types::bcs::{FromBcs, ToBcs}; let bytes = 10u64.to_bcs().unwrap(); @@ -482,7 +487,7 @@ assert_eq!(decoded, 10); - `Read::refresh_id` / `Read::refresh_ids` refresh cursor state explicitly (external drift escape hatch). - `Read::grpc_client_mut` gives direct access to the underlying `GrpcClient` when needed. -## Non-goals +## Out of scope - No code generation: interface functions are still handwritten or derived elsewhere. -- No “live ORM”: decoding is explicit snapshot reads (`Read::get` / `Read::decode`), not a background-syncing cache. +- No “live ORM”: decoding is explicit snapshot reads (`Read::get` / `Read::decode`), not a background synchronization cache. diff --git a/sui-move-runtime/src/effects.rs b/sui-move-runtime/src/effects.rs index cb54e20..a6dabb0 100644 --- a/sui-move-runtime/src/effects.rs +++ b/sui-move-runtime/src/effects.rs @@ -5,7 +5,7 @@ use sui_sdk_types::{ TransactionEffects, }; -/// Reason an object is considered not-live in the local cursor. +/// Reason an object is considered not live in the local cursor. /// /// This is derived from transaction effects (e.g. `deleted`, `wrapped`) and is used to make stale /// handles fail early when converted into transaction inputs. diff --git a/sui-move-runtime/src/handles.rs b/sui-move-runtime/src/handles.rs index 7dcf9c5..69699a9 100644 --- a/sui-move-runtime/src/handles.rs +++ b/sui-move-runtime/src/handles.rs @@ -4,8 +4,8 @@ use std::marker::PhantomData; use std::sync::{Arc, Mutex, RwLock}; use serde::{Deserialize, Serialize}; -use sui_move_call::{CallArg, ObjectArg, ToCallArg, ToCallArgMut}; use sui_sdk_types::{Address, Mutability, ObjectReference, Owner, SharedInput}; +use talus_sui_move_call::{CallArg, ObjectArg, ToCallArg, ToCallArgMut}; use crate::effects; use crate::tx; @@ -81,35 +81,35 @@ struct TrackedObjectSnapshot { tombstone: Option, } -/// Runtime-owned handle for an on-chain object used as a transaction input. +/// Handle owned by the runtime for an on chain object used as a transaction input. /// /// This is the ergonomic “seamless handle” variant: it carries the Rust type `T` while storing /// the mutable `ObjectReference` behind interior mutability. The runtime updates it after commit. /// -/// Unlike `sui-move-call::MoveObject`, this handle also tracks: -/// - the latest known on-chain owner kind (owned/immutable/shared/...) +/// Unlike `talus-sui-move-call::MoveObject`, this handle also tracks: +/// - the latest known on chain owner kind (owned/immutable/shared/...) /// - tombstone status (deleted/wrapped/not-exist) /// /// When converted into a `CallArg`, the handle chooses the correct Sui input shape based on its /// current owner kind: -/// - immutable/address-owned → `Input::ImmutableOrOwned(ObjectReference)` -/// - shared-like (`Owner::Shared` or `Owner::ConsensusAddress`) → `Input::Shared(SharedInput)` (immutable by default) +/// - immutable or address owned → `Input::ImmutableOrOwned(ObjectReference)` +/// - shared input shape (`Owner::Shared` or `Owner::ConsensusAddress`) → `Input::Shared(SharedInput)` (immutable by default) /// /// If the object becomes a child object, is tombstoned, or the owner kind is unknown, conversion -/// fails early with a [`sui_move_call::CallArgError`]. +/// fails early with a [`talus_sui_move_call::CallArgError`]. /// -/// `Object` implements [`ToCallArg`], so you can pass it to `sui-move-call` interface functions +/// `Object` implements [`ToCallArg`], so you can pass it to `talus-sui-move-call` interface functions /// that accept `&impl ToCallArg` and push it into a `CallSpec`. /// /// # Example /// ```rust,no_run -/// use sui_move_runtime::prelude::*; +/// use talus_sui_move_runtime::prelude::*; /// -/// # #[sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] +/// # #[talus_sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] /// # struct UID { /// # id: u64, /// # } -/// # #[sui_move::move_struct(address = "0x1", module = "demo", abilities = "key, store")] +/// # #[talus_sui_move::move_struct(address = "0x1", module = "demo", abilities = "key, store")] /// # struct Demo { /// # id: UID, /// # } @@ -162,13 +162,13 @@ impl Object { /// /// This value is updated after [`crate::Tx::commit`] (if the object was changed by the /// committed transaction). It is not automatically refreshed when other transactions mutate - /// the object on-chain. + /// the object on chain. pub fn reference(&self) -> ObjectReference { self.cell.reference() } - /// Return an immutable shared view of this object, if it is shared-like on-chain. - pub fn shared_immutable(&self) -> Result, sui_move_call::CallArgError> { + /// Return an immutable shared view of this object, if it has a shared input shape on chain. + pub fn shared_immutable(&self) -> Result, talus_sui_move_call::CallArgError> { let initial_shared_version = self.shared_start_version()?; Ok(SharedObject::immutable( self.object_id(), @@ -176,8 +176,8 @@ impl Object { )) } - /// Return a mutable shared view of this object, if it is shared-like on-chain. - pub fn shared_mutable(&self) -> Result, sui_move_call::CallArgError> { + /// Return a mutable shared view of this object, if it has a shared input shape on chain. + pub fn shared_mutable(&self) -> Result, talus_sui_move_call::CallArgError> { let initial_shared_version = self.shared_start_version()?; Ok(SharedObject::mutable( self.object_id(), @@ -185,18 +185,18 @@ impl Object { )) } - /// Return a receiving view of this object, if it is address-owned. + /// Return a receiving view of this object, if it is owned by an address. /// /// Receiving is a transaction input mode used for `sui::transfer::Receiving`: it allows - /// receiving an object that was transferred to an address that is also an object ID (transfer-to-object). + /// receiving an object that was transferred to an address that is also an object ID. /// /// This helper validates only the coarse owner kind: - /// - allowed: address-owned objects - /// - rejected: shared-like, immutable, child objects, tombstoned objects + /// - allowed: objects owned by an address + /// - rejected: shared input shapes, immutable objects, child objects, and tombstoned objects /// - /// On-chain, Sui also checks that the object can be received through the specific parent - /// object you prove mutable access to (this runtime does not try to pre-validate that). - pub fn receiving(&self) -> Result, sui_move_call::CallArgError> { + /// On chain, Sui also checks that the object can be received through the specific parent + /// object for which you prove mutable access. This runtime does not validate that in advance. + pub fn receiving(&self) -> Result, talus_sui_move_call::CallArgError> { self.ensure_not_tombstoned()?; let owner = self.cell.owner.read().expect("poisoned object lock"); @@ -205,7 +205,7 @@ impl Object { cell: Arc::clone(&self.cell), phantom: PhantomData, }), - other => Err(sui_move_call::CallArgError::ObjectKind { + other => Err(talus_sui_move_call::CallArgError::ObjectKind { object_id: self.object_id(), expected: "address-owned", actual: other.label(), @@ -213,9 +213,9 @@ impl Object { } } - fn ensure_not_tombstoned(&self) -> Result<(), sui_move_call::CallArgError> { + fn ensure_not_tombstoned(&self) -> Result<(), talus_sui_move_call::CallArgError> { if let Some(reason) = self.cell.tombstone_reason() { - return Err(sui_move_call::CallArgError::Tombstoned { + return Err(talus_sui_move_call::CallArgError::Tombstoned { object_id: self.object_id(), reason: reason.label(), }); @@ -223,13 +223,13 @@ impl Object { Ok(()) } - fn shared_start_version(&self) -> Result { + fn shared_start_version(&self) -> Result { self.ensure_not_tombstoned()?; let owner = self.cell.owner.read().expect("poisoned object lock"); let kind = tx::classify_owner(&owner); if !kind.is_shared_like() { - return Err(sui_move_call::CallArgError::ObjectKind { + return Err(talus_sui_move_call::CallArgError::ObjectKind { object_id: self.object_id(), expected: "shared", actual: kind.label(), @@ -237,7 +237,7 @@ impl Object { }; let Some(initial_shared_version) = kind.shared_start_version() else { - return Err(sui_move_call::CallArgError::ObjectKind { + return Err(talus_sui_move_call::CallArgError::ObjectKind { object_id: self.object_id(), expected: "shared", actual: kind.label(), @@ -248,8 +248,8 @@ impl Object { } } -impl ToCallArg for Object { - fn to_call_arg(&self) -> Result { +impl ToCallArg for Object { + fn to_call_arg(&self) -> Result { self.ensure_not_tombstoned()?; let owner = self.cell.owner.read().expect("poisoned object lock"); @@ -259,7 +259,7 @@ impl ToCallArg for Object { } kind if kind.is_shared_like() => { let Some(initial_shared_version) = kind.shared_start_version() else { - return Err(sui_move_call::CallArgError::ObjectKind { + return Err(talus_sui_move_call::CallArgError::ObjectKind { object_id: self.object_id(), expected: "shared", actual: kind.label(), @@ -272,7 +272,7 @@ impl ToCallArg for Object { Mutability::Immutable, ))) } - other => Err(sui_move_call::CallArgError::ObjectKind { + other => Err(talus_sui_move_call::CallArgError::ObjectKind { object_id: self.object_id(), expected: "immutable-or-owned or shared", actual: other.label(), @@ -281,8 +281,8 @@ impl ToCallArg for Object { } } -impl ToCallArgMut for Object { - fn to_call_arg_mutable(&self) -> Result { +impl ToCallArgMut for Object { + fn to_call_arg_mutable(&self) -> Result { self.ensure_not_tombstoned()?; let owner = self.cell.owner.read().expect("poisoned object lock"); @@ -292,7 +292,7 @@ impl ToCallArgMut for Object { } kind if kind.is_shared_like() => { let Some(initial_shared_version) = kind.shared_start_version() else { - return Err(sui_move_call::CallArgError::ObjectKind { + return Err(talus_sui_move_call::CallArgError::ObjectKind { object_id: self.object_id(), expected: "shared", actual: kind.label(), @@ -305,7 +305,7 @@ impl ToCallArgMut for Object { Mutability::Mutable, ))) } - other => Err(sui_move_call::CallArgError::ObjectKind { + other => Err(talus_sui_move_call::CallArgError::ObjectKind { object_id: self.object_id(), expected: "immutable-or-owned or shared", actual: other.label(), @@ -314,11 +314,11 @@ impl ToCallArgMut for Object { } } -impl ObjectArg for Object {} +impl ObjectArg for Object {} -/// Runtime-owned handle for a receiving object input. +/// Handle owned by the runtime for a receiving object input. /// -/// This is the runtime-owned counterpart of Sui's `Input::Receiving`. +/// This is the runtime counterpart of Sui's `Input::Receiving`. pub struct ReceivingObject { cell: Arc, phantom: PhantomData, @@ -357,8 +357,8 @@ impl ReceivingObject { } } -impl ToCallArg for ReceivingObject { - fn to_call_arg(&self) -> Result { +impl ToCallArg for ReceivingObject { + fn to_call_arg(&self) -> Result { let obj = Object:: { cell: Arc::clone(&self.cell), phantom: PhantomData, @@ -369,7 +369,7 @@ impl ToCallArg for ReceivingObject Ok(CallArg::Receiving(self.reference())), - other => Err(sui_move_call::CallArgError::ObjectKind { + other => Err(talus_sui_move_call::CallArgError::ObjectKind { object_id: self.object_id(), expected: "address-owned", actual: other.label(), @@ -378,8 +378,8 @@ impl ToCallArg for ReceivingObject ToCallArgMut for ReceivingObject { - fn to_call_arg_mutable(&self) -> Result { +impl ToCallArgMut for ReceivingObject { + fn to_call_arg_mutable(&self) -> Result { self.to_call_arg() } } @@ -391,15 +391,15 @@ impl ToCallArgMut for ReceivingObjec /// /// # Example /// ``` -/// use sui_move_call::{CallArg, CallSpec}; -/// use sui_move_runtime::SharedObject; +/// use talus_sui_move_call::{CallArg, CallSpec}; +/// use talus_sui_move_runtime::SharedObject; /// use sui_sdk_types::Address; /// -/// # #[sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] +/// # #[talus_sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] /// # struct UID { /// # id: u64, /// # } -/// # #[sui_move::move_struct(address = "0x1", module = "demo", abilities = "key, store")] +/// # #[talus_sui_move::move_struct(address = "0x1", module = "demo", abilities = "key, store")] /// # struct Demo { /// # id: UID, /// # } @@ -479,17 +479,17 @@ impl SharedObject { } } -impl ToCallArg for SharedObject { - fn to_call_arg(&self) -> Result { +impl ToCallArg for SharedObject { + fn to_call_arg(&self) -> Result { Ok(CallArg::Shared(self.input.clone())) } } -impl ToCallArgMut for SharedObject { - fn to_call_arg_mutable(&self) -> Result { +impl ToCallArgMut for SharedObject { + fn to_call_arg_mutable(&self) -> Result { let actual = self.mutability(); if !actual.is_mutable() { - return Err(sui_move_call::CallArgError::SharedMutability { + return Err(talus_sui_move_call::CallArgError::SharedMutability { object_id: self.object_id(), actual, }); @@ -499,7 +499,7 @@ impl ToCallArgMut for SharedObject ObjectArg for SharedObject {} +impl ObjectArg for SharedObject {} #[derive(Default, Debug)] pub(crate) struct Cursor { @@ -551,7 +551,7 @@ impl Cursor { CursorSnapshot { objects } } - pub(crate) fn intern_object( + pub(crate) fn intern_object( &self, reference: ObjectReference, owner: Owner, @@ -563,7 +563,9 @@ impl Cursor { } } - pub(crate) fn intern_receiving_object( + pub(crate) fn intern_receiving_object< + T: talus_sui_move::MoveStruct + talus_sui_move::HasKey, + >( &self, reference: ObjectReference, owner: Owner, @@ -639,23 +641,23 @@ impl Cursor { #[cfg(test)] mod tests { use super::*; - use sui_move_call::ToCallArgMut; use sui_sdk_types::{ ChangedObject, Digest, ExecutionStatus, GasCostSummary, IdOperation, Mutability, ObjectIn, ObjectOut, Owner, TransactionEffects, TransactionEffectsV2, }; + use talus_sui_move_call::ToCallArgMut; - #[sui_move::move_struct(address = "0x2", module = "object", abilities = "copy, store")] + #[talus_sui_move::move_struct(address = "0x2", module = "object", abilities = "copy, store")] struct ID { bytes: Address, } - #[sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] + #[talus_sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] struct UID { id: ID, } - #[sui_move::move_struct(address = "0x1", module = "demo", abilities = "key")] + #[talus_sui_move::move_struct(address = "0x1", module = "demo", abilities = "key")] struct Demo { id: UID, } @@ -713,7 +715,7 @@ mod tests { assert!(matches!( obj.to_call_arg().unwrap_err(), - sui_move_call::CallArgError::Tombstoned { .. } + talus_sui_move_call::CallArgError::Tombstoned { .. } )); cursor.intern_object::(new, Owner::Shared(7)); @@ -838,7 +840,7 @@ mod tests { let err = obj.to_call_arg().unwrap_err(); match err { - sui_move_call::CallArgError::Tombstoned { object_id, reason } => { + talus_sui_move_call::CallArgError::Tombstoned { object_id, reason } => { assert_eq!(object_id, id); assert_eq!(reason, "not-exist"); } @@ -857,7 +859,7 @@ mod tests { let err = obj.to_call_arg().unwrap_err(); match err { - sui_move_call::CallArgError::ObjectKind { + talus_sui_move_call::CallArgError::ObjectKind { object_id, expected, actual, @@ -903,7 +905,7 @@ mod tests { let obj: Object = cursor.intern_object(reference.clone(), Owner::Shared(7)); let err = obj.receiving().unwrap_err(); match err { - sui_move_call::CallArgError::ObjectKind { + talus_sui_move_call::CallArgError::ObjectKind { object_id, expected, actual, diff --git a/sui-move-runtime/src/lib.rs b/sui-move-runtime/src/lib.rs index 63f8119..1c3a201 100644 --- a/sui-move-runtime/src/lib.rs +++ b/sui-move-runtime/src/lib.rs @@ -14,29 +14,29 @@ pub use crate::tx::{ use std::time::Duration; -/// Re-export of `sui_crypto::SuiSigner` used by [`Runtime`] and [`Tx`]. +/// Public alias for `sui_crypto::SuiSigner` used by [`Runtime`] and [`Tx`]. /// -/// This lets generated bindings name the signer bound as `sui_move_runtime::SuiSigner` without +/// This lets generated bindings name the signer bound as `talus_sui_move_runtime::SuiSigner` without /// requiring consumers to depend on `sui-crypto` directly. pub use sui_crypto::SuiSigner; use sui_sdk_types::{Address, Mutability, ProgrammableTransaction, TransactionEffects, TypeTag}; -/// Errors produced by `sui-move-runtime`. +/// Errors produced by `talus-sui-move-runtime`. /// /// This is a small umbrella enum that preserves the main failure boundary: /// - building a PTB (`Build`) /// - submitting/waiting (`Tx`) /// - fetching objects for handles over Sui gRPC (`Grpc`) -/// - simulation/dev-inspection (`Simulate`) +/// - simulation/inspection (`Simulate`) #[derive(thiserror::Error, Debug)] pub enum Error { /// Building a PTB failed. #[error(transparent)] - Build(#[from] sui_move_ptb::BuildError), + Build(#[from] talus_sui_move_ptb::BuildError), /// Constructing a generated Move call failed. #[error(transparent)] - CallSpec(#[from] sui_move_call::CallSpecError), + CallSpec(#[from] talus_sui_move_call::CallSpecError), /// Signing or submitting failed. #[error(transparent)] @@ -46,7 +46,7 @@ pub enum Error { #[error(transparent)] Grpc(#[from] tx::GrpcError), - /// Simulating or dev-inspecting failed. + /// Simulating or inspecting failed. #[error(transparent)] Simulate(#[from] tx::SimulateError), @@ -61,10 +61,10 @@ pub enum Error { object_id: Address, /// Underlying verification/BCS error. #[source] - source: sui_move::DecodeError, + source: talus_sui_move::DecodeError, }, - /// The requested object kind does not match on-chain ownership. + /// The requested object kind does not match on chain ownership. #[error("object {object_id} is {actual}, expected {expected}")] ObjectKind { /// Object id that was fetched. @@ -79,28 +79,28 @@ pub enum Error { /// Sui gRPC client used by the runtime. pub type GrpcClient = sui_rpc::Client; -/// Long-lived runtime owning a Sui gRPC client + signer + handle cursor. +/// Runtime that owns a Sui gRPC client, signer, and handle cursor. /// /// This is the entry point for the Read → Tx → Commit mental model: /// - [`Runtime::read`] for fetching/constructing typed handles /// - [`Runtime::tx`] for simulating/inspecting/committing PTBs /// -/// # Runtime-owned handles +/// # Runtime handles /// /// Handles returned by [`Read::object`] and [`Read::receiving_object`] are **interned** in the /// runtime’s cursor (your local frontier) by `object_id`. Clones of the same handle share the same /// internal cell, so they all see updates. /// -/// After [`Tx::commit`], the runtime decodes `TransactionEffects` from gRPC, derives an -/// effects-based patch, and applies it to the cursor, updating any live handle cells whose object -/// id appears in the effects. +/// After [`Tx::commit`], the runtime decodes `TransactionEffects` from gRPC, derives a patch from +/// those effects, and applies it to the cursor. This updates any live handle cells whose object id +/// appears in the effects. /// /// This is the core ergonomic win: you can store typed handles in normal Rust structs without /// threading `&mut` everywhere just to keep `ObjectReference`s current. /// /// # Example /// ```rust,no_run -/// use sui_move_runtime::prelude::*; +/// use talus_sui_move_runtime::prelude::*; /// use sui_sdk_types::{PersonalMessage, Transaction, UserSignature}; /// /// # #[derive(Clone)] @@ -141,8 +141,8 @@ impl Runtime { /// Replace the runtime cursor with a previously captured snapshot. /// - /// Prefer calling this immediately after [`Runtime::new`] and before creating any runtime-owned - /// handles. + /// Prefer calling this immediately after [`Runtime::new`] and before creating any handles owned + /// by the runtime. pub fn with_cursor_snapshot(mut self, snapshot: CursorSnapshot) -> Self { self.cursor = handles::Cursor::from_snapshot(snapshot); self @@ -160,7 +160,7 @@ impl Runtime { /// a receipt returned by a gRPC node that did not include `effects.bcs`). /// /// If the transaction effects are returned by gRPC, the runtime derives an effects patch and - /// applies it to its cursor, updating any matching runtime-owned handles. + /// applies it to its cursor, updating any matching handles owned by the runtime. pub async fn sync_transaction( &mut self, digest: sui_sdk_types::Digest, @@ -199,7 +199,7 @@ impl Runtime { Tx { rt: self, sender, - ptb: sui_move_ptb::PtbBuilder::new(), + ptb: talus_sui_move_ptb::PtbBuilder::new(), } } @@ -210,7 +210,7 @@ impl Runtime { /// Read view: read/fetch helpers and handle construction. /// -/// This view is intentionally read-only with respect to the chain: it fetches data from gRPC and +/// This view is intentionally read only with respect to the chain: it fetches data from gRPC and /// constructs typed handles, but it does not submit transactions. pub struct Read<'a, S> { rt: &'a mut Runtime, @@ -260,28 +260,29 @@ impl<'a, S: SuiSigner> Read<'a, S> { Ok(()) } - /// Refresh the reference and owner information for a runtime-owned handle. + /// Refresh the reference and owner information for a handle owned by the runtime. /// /// This is the explicit escape hatch for external drift: if another transaction changes an /// owned object (or rotates its `ObjectReference`), your local cursor does not update until you /// either commit through this runtime or refresh explicitly. - pub async fn refresh( + pub async fn refresh( &mut self, obj: &Object, ) -> Result<(), Error> { self.refresh_id(obj.object_id()).await } - /// Construct a runtime-owned object handle by fetching its latest `ObjectReference` and owner kind. + /// Construct an object handle owned by the runtime by fetching its latest `ObjectReference` and + /// owner kind. /// /// The returned [`Object`] is the default handle type used throughout this crate: /// - owned/immutable objects convert to `Input::ImmutableOrOwned(ObjectReference)` - /// - shared-like objects convert to `Input::Shared(SharedInput)` (immutable by default) + /// - objects with a shared input shape convert to `Input::Shared(SharedInput)` (immutable by default) /// /// If you need an explicit input mode, derive a view from the handle at the moment it matters: /// - `obj.shared_immutable()?` / `obj.shared_mutable()?` /// - `obj.receiving()?` - pub async fn object( + pub async fn object( &mut self, object_id: Address, ) -> Result, Error> { @@ -318,11 +319,11 @@ impl<'a, S: SuiSigner> Read<'a, S> { /// Fetch an object and decode its Move contents into `T`. /// - /// This performs a tag check (`T::type_tag_static()` must match the on-chain `TypeTag`) and + /// This performs a tag check (`T::type_tag_static()` must match the on chain `TypeTag`) and /// returns both: - /// - a runtime-owned handle (`Object`) and + /// - a handle owned by the runtime (`Object`) and /// - the decoded value (`T`). - pub async fn get( + pub async fn get( &mut self, object_id: Address, ) -> Result<(Object, T), Error> { @@ -344,15 +345,15 @@ impl<'a, S: SuiSigner> Read<'a, S> { .intern_object::(fetched.reference, fetched.owner); let got = TypeTag::Struct(Box::new(fetched.struct_tag)); - let decoded = sui_move::MoveInstance::::from_raw_type(got, &fetched.contents) + let decoded = talus_sui_move::MoveInstance::::from_raw_type(got, &fetched.contents) .map_err(|source| Error::Decode { object_id, source })? .value; Ok((obj, decoded)) } - /// Fetch an object and decode its contents as `T` without verifying the on-chain type tag. - pub async fn get_unchecked( + /// Fetch an object and decode its contents as `T` without verifying the on chain type tag. + pub async fn get_unchecked( &mut self, object_id: Address, ) -> Result<(Object, T), Error> { @@ -380,11 +381,11 @@ impl<'a, S: SuiSigner> Read<'a, S> { Ok((obj, decoded)) } - /// Fetch and decode the latest on-chain contents for a runtime-owned object handle. + /// Fetch and decode the latest on chain contents for an object handle owned by the runtime. /// - /// This performs a tag check and refreshes the runtime-owned handle's reference/owner - /// information in the cursor. - pub async fn decode( + /// This performs a tag check and refreshes the handle reference and owner information in the + /// cursor. + pub async fn decode( &mut self, obj: &Object, ) -> Result { @@ -406,18 +407,18 @@ impl<'a, S: SuiSigner> Read<'a, S> { .intern_object::(fetched.reference, fetched.owner); let got = TypeTag::Struct(Box::new(fetched.struct_tag)); - let decoded = sui_move::MoveInstance::::from_raw_type(got, &fetched.contents) + let decoded = talus_sui_move::MoveInstance::::from_raw_type(got, &fetched.contents) .map_err(|source| Error::Decode { object_id, source })? .value; Ok(decoded) } - /// Fetch and decode the latest on-chain contents for a runtime-owned object handle without tag - /// verification. + /// Fetch and decode the latest on chain contents for an object handle owned by the runtime, + /// without tag verification. /// - /// This refreshes the runtime-owned handle's reference/owner information in the cursor. - pub async fn decode_unchecked( + /// This refreshes the reference and owner information for the handle in the cursor. + pub async fn decode_unchecked( &mut self, obj: &Object, ) -> Result { @@ -449,10 +450,10 @@ impl<'a, S: SuiSigner> Read<'a, S> { /// This corresponds to Sui's `Input::Receiving`. /// /// Receiving is a transaction input mode (the Move framework type - /// `sui::transfer::Receiving`), not an on-chain owner kind. This helper only fetches the + /// `sui::transfer::Receiving`), not an on chain owner kind. This helper only fetches the /// latest reference and does not validate that the object is valid to receive in the current /// transaction. - pub async fn receiving_object( + pub async fn receiving_object( &mut self, object_id: Address, ) -> Result, Error> { @@ -476,7 +477,7 @@ impl<'a, S: SuiSigner> Read<'a, S> { /// Construct a shared object handle by fetching its initial shared version. /// /// This corresponds to Sui's `Input::Shared`. - pub async fn shared_object( + pub async fn shared_object( &mut self, object_id: Address, mutability: Mutability, @@ -510,7 +511,7 @@ impl<'a, S: SuiSigner> Read<'a, S> { } /// Convenience: immutable shared input. - pub async fn shared_immutable( + pub async fn shared_immutable( &mut self, object_id: Address, ) -> Result, Error> { @@ -518,7 +519,7 @@ impl<'a, S: SuiSigner> Read<'a, S> { } /// Convenience: mutable shared input. - pub async fn shared_mutable( + pub async fn shared_mutable( &mut self, object_id: Address, ) -> Result, Error> { @@ -530,7 +531,7 @@ impl<'a, S: SuiSigner> Read<'a, S> { pub struct Tx<'a, S> { rt: &'a mut Runtime, sender: Address, - ptb: sui_move_ptb::PtbBuilder, + ptb: talus_sui_move_ptb::PtbBuilder, } impl<'a, S: SuiSigner> Tx<'a, S> { @@ -538,35 +539,35 @@ impl<'a, S: SuiSigner> Tx<'a, S> { /// /// This is useful for accessing less common PTB commands without this crate adding extra /// wrappers. - pub fn ptb(&self) -> &sui_move_ptb::PtbBuilder { + pub fn ptb(&self) -> &talus_sui_move_ptb::PtbBuilder { &self.ptb } /// Mutably borrow the underlying PTB builder (escape hatch). - pub fn ptb_mut(&mut self) -> &mut sui_move_ptb::PtbBuilder { + pub fn ptb_mut(&mut self) -> &mut talus_sui_move_ptb::PtbBuilder { &mut self.ptb } /// Add a raw input to the transaction and return its `Argument::Input`. pub fn input( &mut self, - input: sui_move_call::CallArg, + input: talus_sui_move_call::CallArg, ) -> Result { Ok(self.ptb.input(input)?) } /// Convert a typed value into an input and return its `Argument::Input`. - pub fn arg( + pub fn arg( &mut self, value: &A, ) -> Result { Ok(self.ptb.arg(value)?) } - /// Add a Move call command from a typed [`sui_move_call::CallSpec`]. + /// Add a Move call command from a typed [`talus_sui_move_call::CallSpec`]. pub fn call( &mut self, - spec: sui_move_call::CallSpec, + spec: talus_sui_move_call::CallSpec, ) -> Result { Ok(self.ptb.call(spec)?) } @@ -634,7 +635,7 @@ impl<'a, S: SuiSigner> Tx<'a, S> { /// [`Receipt`] with `digest` and any decoded effects, and marks the observed finality as /// `Executed`. /// - /// On success, the runtime applies an effects-derived patch to its cursor, updating + /// On success, the runtime applies a patch derived from effects to its cursor, updating /// all live [`Object`] and [`ReceivingObject`] handles that match changed objects. pub async fn commit(self) -> Result { self.commit_with(TxOptions::default()).await @@ -646,14 +647,14 @@ impl<'a, S: SuiSigner> Tx<'a, S> { Self::commit_ptb_with_inner(rt, sender, ptb.finish(), opts).await } - /// Commit a pre-built PTB and wait for checkpoint inclusion. + /// Commit an already built PTB and wait for checkpoint inclusion. /// /// This is the escape hatch for advanced PTB building (coin ops, wiring, etc). pub async fn commit_ptb(self, ptb: ProgrammableTransaction) -> Result { self.commit_ptb_with(ptb, TxOptions::default()).await } - /// Commit a pre-built PTB using explicit transaction options. + /// Commit an already built PTB using explicit transaction options. pub async fn commit_ptb_with( self, ptb: ProgrammableTransaction, @@ -687,16 +688,16 @@ impl<'a, S: SuiSigner> Tx<'a, S> { Ok(receipt) } - /// Dry-run the built PTB (checks enabled) without mutating chain state. + /// Simulate the built PTB (checks enabled) without mutating chain state. /// - /// This does not update runtime-owned handles. + /// This does not update handles owned by the runtime. pub async fn simulate(&mut self) -> Result { self.simulate_with(SimulateOptions::default()).await } - /// Dry-run the built PTB with explicit simulation options. + /// Simulate the built PTB with explicit simulation options. /// - /// This does not update runtime-owned handles. + /// This does not update handles owned by the runtime. pub async fn simulate_with( &mut self, opts: SimulateOptions, @@ -705,9 +706,9 @@ impl<'a, S: SuiSigner> Tx<'a, S> { self.simulate_ptb_with(ptb, opts).await } - /// Dry-run a pre-built PTB (checks enabled) without mutating chain state. + /// Simulate an already built PTB, with checks enabled, without mutating chain state. /// - /// This does not update runtime-owned handles. + /// This does not update handles owned by the runtime. pub async fn simulate_ptb( &mut self, ptb: ProgrammableTransaction, @@ -716,9 +717,9 @@ impl<'a, S: SuiSigner> Tx<'a, S> { .await } - /// Dry-run a pre-built PTB with explicit simulation options. + /// Simulate an already built PTB with explicit simulation options. /// - /// This does not update runtime-owned handles. + /// This does not update handles owned by the runtime. pub async fn simulate_ptb_with( &mut self, ptb: ProgrammableTransaction, @@ -727,24 +728,24 @@ impl<'a, S: SuiSigner> Tx<'a, S> { Ok(tx::simulate_ptb(&mut self.rt.client, self.sender, ptb, opts).await?) } - /// Dev-inspect the built PTB (checks disabled) to retrieve command outputs for debugging. + /// Inspect the built PTB (checks disabled) to retrieve command outputs for debugging. /// - /// This does not update runtime-owned handles. + /// This does not update handles owned by the runtime. pub async fn inspect(&mut self) -> Result { self.inspect_with(InspectOptions::default()).await } - /// Dev-inspect the built PTB with explicit inspect options. + /// Inspect the built PTB with explicit inspect options. /// - /// This does not update runtime-owned handles. + /// This does not update handles owned by the runtime. pub async fn inspect_with(&mut self, opts: InspectOptions) -> Result { let ptb = self.ptb.clone().finish(); self.inspect_ptb_with(ptb, opts).await } - /// Dev-inspect a pre-built PTB (checks disabled) to retrieve command outputs for debugging. + /// Inspect an already built PTB, with checks disabled, to retrieve command outputs for debugging. /// - /// This does not update runtime-owned handles. + /// This does not update handles owned by the runtime. pub async fn inspect_ptb( &mut self, ptb: ProgrammableTransaction, @@ -752,9 +753,9 @@ impl<'a, S: SuiSigner> Tx<'a, S> { self.inspect_ptb_with(ptb, InspectOptions::default()).await } - /// Dev-inspect a pre-built PTB with explicit inspect options. + /// Inspect an already built PTB with explicit inspect options. /// - /// This does not update runtime-owned handles. + /// This does not update handles owned by the runtime. pub async fn inspect_ptb_with( &mut self, ptb: ProgrammableTransaction, @@ -764,12 +765,12 @@ impl<'a, S: SuiSigner> Tx<'a, S> { } } -/// Convenience re-exports for downstream code. +/// Common exports for downstream code. /// /// This prelude is meant for application code and examples. It includes: -/// - `sui-move-runtime` core types -/// - `sui-move-call` prelude (call building) -/// - `sui-move-ptb` prelude (PTB building) +/// - `talus-sui-move-runtime` core types +/// - `talus-sui-move-call` prelude (call building) +/// - `talus-sui-move-ptb` prelude (PTB building) pub mod prelude { pub use crate::{ BcsValue, CheckpointWaitOutcome, CommandOutputs, CursorSnapshot, EnsureSuccessError, Error, @@ -777,9 +778,9 @@ pub mod prelude { Receipt, ReceivingObject, Runtime, SharedObject, SimulateOptions, SimulationReceipt, TombstoneReason, Tx, TxOptions, }; - pub use sui_move_call::prelude::*; - pub use sui_move_ptb::prelude::*; pub use sui_sdk_types::Mutability; + pub use talus_sui_move_call::prelude::*; + pub use talus_sui_move_ptb::prelude::*; } /// Build and run a transaction in the Read → Tx → Commit mental model. @@ -793,10 +794,10 @@ pub mod prelude { /// The macro returns a **future**, so callers use `.await`: /// /// ```rust,no_run -/// use sui_move_runtime::prelude::*; +/// use talus_sui_move_runtime::prelude::*; /// /// # async fn demo(mut rt: Runtime, sender: sui_sdk_types::Address) -> Result<(), Error> { -/// let receipt = sui_move_runtime::tx!(&mut rt, sender => { +/// let receipt = talus_sui_move_runtime::tx!(&mut rt, sender => { /// CallSpec::new("0x1".parse().unwrap(), "m", "f").unwrap(); /// }) /// .await?; @@ -810,9 +811,9 @@ pub mod prelude { /// **Call list (default commit)**: each statement expression must evaluate to a `CallSpec`. /// /// ```rust,no_run -/// # use sui_move_runtime::prelude::*; +/// # use talus_sui_move_runtime::prelude::*; /// # async fn demo(mut rt: Runtime, sender: sui_sdk_types::Address) -> Result<(), Error> { -/// let _receipt = sui_move_runtime::tx!(&mut rt, sender => { +/// let _receipt = talus_sui_move_runtime::tx!(&mut rt, sender => { /// CallSpec::new("0x1".parse().unwrap(), "m", "f").unwrap(); /// CallSpec::new("0x1".parse().unwrap(), "m", "g").unwrap(); /// }) @@ -824,9 +825,9 @@ pub mod prelude { /// **Builder form**: opt into direct access to `Tx` (escape hatch for PTB wiring). /// /// ```rust,no_run -/// # use sui_move_runtime::prelude::*; +/// # use talus_sui_move_runtime::prelude::*; /// # async fn demo(mut rt: Runtime, sender: sui_sdk_types::Address) -> Result<(), Error> { -/// let _receipt = sui_move_runtime::tx!(&mut rt, sender, tx => { +/// let _receipt = talus_sui_move_runtime::tx!(&mut rt, sender, tx => { /// let _out = tx.call(CallSpec::new("0x1".parse().unwrap(), "m", "f").unwrap())?; /// }) /// .await?; @@ -837,19 +838,19 @@ pub mod prelude { /// **Action variants**: /// /// ```rust,no_run -/// # use sui_move_runtime::prelude::*; +/// # use talus_sui_move_runtime::prelude::*; /// # async fn demo(mut rt: Runtime, sender: sui_sdk_types::Address) -> Result<(), Error> { -/// let _sim = sui_move_runtime::tx!(simulate, &mut rt, sender => { +/// let _sim = talus_sui_move_runtime::tx!(simulate, &mut rt, sender => { /// CallSpec::new("0x1".parse().unwrap(), "m", "f").unwrap(); /// }) /// .await?; /// -/// let _dbg = sui_move_runtime::tx!(inspect, &mut rt, sender => { +/// let _dbg = talus_sui_move_runtime::tx!(inspect, &mut rt, sender => { /// CallSpec::new("0x1".parse().unwrap(), "m", "f").unwrap(); /// }) /// .await?; /// -/// let _receipt = sui_move_runtime::tx!( +/// let _receipt = talus_sui_move_runtime::tx!( /// commit_with(TxOptions { finality: Finality::Executed, ..Default::default() }), /// &mut rt, /// sender => { diff --git a/sui-move-runtime/src/tx.rs b/sui-move-runtime/src/tx.rs index fc8598f..c557768 100644 --- a/sui-move-runtime/src/tx.rs +++ b/sui-move-runtime/src/tx.rs @@ -43,7 +43,7 @@ pub struct TxOptions { /// Finality requested for the commit. /// /// When `Checkpointed` (default), `commit*` uses a gRPC method that also waits for checkpoint - /// inclusion ("read-your-writes" consistency on that node). + /// inclusion, so later reads from that node can observe the transaction. /// /// When `Executed`, `commit*` should only require execution (effects produced). pub finality: Finality, @@ -129,7 +129,7 @@ pub enum EnsureSuccessError { impl Receipt { /// Return `Ok(())` if the transaction executed successfully. /// - /// Failed transactions are still committed on-chain and may update gas references. + /// Failed transactions are still committed on chain and may update gas references. pub fn ensure_success(&self) -> Result<(), EnsureSuccessError> { match &self.status { Some(ExecutionStatus::Success) => Ok(()), @@ -139,7 +139,7 @@ impl Receipt { } } -/// Options for running a transaction in dry-run mode (checks enabled). +/// Options for running a transaction in simulation mode (checks enabled). #[derive(Clone, Debug)] pub struct SimulateOptions { /// Whether the server should perform gas selection automatically. @@ -147,12 +147,12 @@ pub struct SimulateOptions { /// When `true` (default), the request can omit gas payment information and the server will /// pick a gas coin and budget for simulation. /// - /// Note: this option is ignored when checks are disabled (dev-inspect mode). + /// Note: this option is ignored when checks are disabled (inspect mode). /// /// If you set this to `false`, the simulation gRPC request may require an explicit gas payment on the - /// provided transaction. The current `sui-move-runtime` simulation helper does not model + /// provided transaction. The current `talus-sui-move-runtime` simulation helper does not model /// explicit gas payment configuration, so `false` is generally only useful if your gRPC server accepts - /// omitted gas payment without auto-selection. + /// omitted gas payment without automatic selection. pub do_gas_selection: bool, } @@ -164,17 +164,17 @@ impl Default for SimulateOptions { } } -/// Options for running a transaction in dev-inspect mode (checks disabled). +/// Options for running a transaction in inspect mode (checks disabled). /// /// This is currently an empty placeholder for future knobs (e.g. requesting JSON renderings of /// outputs). #[derive(Clone, Debug, Default)] pub struct InspectOptions {} -/// Receipt for a simulated transaction (dry-run). +/// Receipt for a simulated transaction. /// /// Returned by [`crate::Tx::simulate`]. This does not mutate chain state and does not update -/// runtime-owned handles. +/// handles owned by the runtime. #[derive(Clone, Debug)] pub struct SimulationReceipt { /// Transaction digest, if returned by gRPC. @@ -183,23 +183,23 @@ pub struct SimulationReceipt { pub effects: Option, } -/// Receipt for a dev-inspected transaction (checks disabled) including command outputs. +/// Receipt for an inspected transaction, with checks disabled, including command outputs. /// /// Returned by [`crate::Tx::inspect`]. This does not mutate chain state and does not update -/// runtime-owned handles. +/// handles owned by the runtime. /// -/// `outputs[i]` corresponds to the `i`-th PTB command. +/// `outputs[i]` corresponds to the PTB command at index `i`. #[derive(Clone, Debug)] pub struct InspectReceipt { /// Transaction digest, if returned by gRPC. pub digest: Option, /// Transaction effects, if returned by gRPC. pub effects: Option, - /// Command outputs (return values + mutated-by-ref values), if requested. + /// Command outputs (return values and values mutated through references), if requested. pub outputs: Vec, } -/// Per-command outputs returned by dev-inspect. +/// Outputs returned for each command during inspection. /// /// This struct is intentionally minimal: it only contains raw BCS blobs. #[derive(Clone, Debug, Default)] @@ -210,13 +210,13 @@ pub struct CommandOutputs { pub mutated_by_ref: Vec, } -/// A raw BCS value returned by simulation/dev-inspect. +/// A raw BCS value returned by simulation or inspection. /// /// You can decode this using `sui_sdk_types::bcs` (enabled via the `serde` feature on /// `sui-sdk-types`): /// /// ``` -/// use sui_move_runtime::BcsValue; +/// use talus_sui_move_runtime::BcsValue; /// use sui_sdk_types::bcs::{FromBcs, ToBcs}; /// /// let value = BcsValue { @@ -266,7 +266,7 @@ pub enum TxError { }, } -/// Errors for simulate/dev-inspect operations. +/// Errors from simulation or inspection. #[derive(thiserror::Error, Debug)] pub enum SimulateError { /// gRPC error. diff --git a/sui-move/Cargo.toml b/sui-move/Cargo.toml index 8cb578d..d53e67e 100644 --- a/sui-move/Cargo.toml +++ b/sui-move/Cargo.toml @@ -1,24 +1,32 @@ [package] -name = "sui-move" -version = "0.1.0" -edition = "2021" -description = "Move-shaped typed layer for Rust, built on top of sui-sdk-types." +name = "talus-sui-move" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +description = "Rust type representations for Move, built on top of sui-sdk-types." readme = "README.md" +publish = ["crates-io"] license.workspace = true repository.workspace = true homepage.workspace = true +documentation = "https://docs.rs/talus-sui-move" +keywords = ["sui", "move", "blockchain", "bindings"] +categories = ["api-bindings", "development-tools"] + +[package.metadata.docs.rs] +all-features = true [dependencies] -serde = { workspace = true, features = ["derive"] } +serde = { workspace = true } bcs = { workspace = true } ethnum = { workspace = true } sui-sdk-types = { workspace = true } thiserror = { workspace = true } -sui-move-derive = { path = "../sui-move-derive", optional = true } +talus-sui-move-derive = { workspace = true, optional = true } [features] default = [] -derive = ["dep:sui-move-derive"] +derive = ["dep:talus-sui-move-derive"] [[example]] name = "derive_struct" diff --git a/sui-move/README.md b/sui-move/README.md index 431403f..f2facb4 100644 --- a/sui-move/README.md +++ b/sui-move/README.md @@ -1,25 +1,28 @@ -# sui-move +# talus-sui-move -Move-shaped type layer for Rust, built on top of `sui-sdk-types`. +Rust representations of Move types, built on top of `sui-sdk-types`. + +The crates.io package is `talus-sui-move`; Rust code imports it as `talus_sui_move`. This crate solves one problem: **represent Move types precisely in Rust** (including their -`TypeTag`/`StructTag` and ability surface), so you can build strongly-typed Sui clients and +`TypeTag`/`StructTag` and ability surface), so you can build strongly typed Sui clients and helpers that can **verify type tags and decode BCS safely**. ## Where it fits -`sui-move` is the bottom layer of this repository’s stack (`MODEL.md`). Higher layers use it to: +`talus-sui-move` is the bottom layer of this repository’s +[stack](https://github.com/Talus-Network/move-binding/blob/main/MODEL.md). Higher layers use it to: - name types precisely when building Move calls (`TypeTag`/`StructTag`), - express Move ability constraints as normal Rust bounds, -- verify on-chain type tags and decode BCS in a controlled way. +- verify type tags returned from chain state and decode BCS in a controlled way. ## Quickstart The core traits are `MoveType` and `MoveStruct`. ```rust -use sui_move::prelude::*; +use talus_sui_move::prelude::*; assert_eq!(::type_tag_static(), TypeTag::U64); assert_eq!( @@ -33,13 +36,13 @@ assert_eq!( ### `MoveType` and `MoveStruct` `MoveType` means a Rust type knows how to describe itself as a Move `TypeTag`. -`MoveStruct` is the struct-specific version that produces a `StructTag`. +`MoveStruct` is the specialization for struct types that produces a `StructTag`. For a Move struct type, you typically implement both: ```rust use serde::{Deserialize, Serialize}; -use sui_move::{parse_address, parse_identifier, HasStore, MoveStruct, MoveType}; +use talus_sui_move::{parse_address, parse_identifier, HasStore, MoveStruct, MoveType}; #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct MyCounter { @@ -68,13 +71,13 @@ impl HasStore for MyCounter {} ### Macros (feature `derive`) -If you prefer, enable the `derive` feature to use attribute macros for defining Move-shaped -structs. +If you prefer, enable the `derive` feature to use attribute macros for defining Rust structs that +represent Move structs. ```rust #[cfg(feature = "derive")] mod example { - use sui_move::move_struct; + use talus_sui_move::move_struct; #[move_struct(address = "0x2", module = "object", abilities = "store")] pub struct UID { @@ -101,7 +104,7 @@ small “ability surface” aliases: This lets you express the same constraints that Move does: ```rust -use sui_move::Storable; +use talus_sui_move::Storable; fn requires_store(_: &T) {} @@ -109,13 +112,13 @@ let x = 42u64; requires_store(&x); ``` -### Tag-checked decoding (`MoveInstance`) +### Decoding with tag verification (`MoveInstance`) When you have `(TypeTag, bytes)` from the chain, you can decode and verify the tag matches the Rust type you expect: ```rust -use sui_move::{MoveInstance, MoveType}; +use talus_sui_move::{MoveInstance, MoveType}; let value = vec![1u8, 2, 3]; let bytes = value.to_bcs().unwrap(); @@ -131,7 +134,7 @@ assert_eq!(inst.value, vec![1u8, 2, 3]); ## What’s included -### Built-in Rust types +### Standard Rust types The crate implements `MoveType` (and ability markers) for: @@ -141,23 +144,23 @@ The crate implements `MoveType` (and ability markers) for: ### Framework types are not core -`sui-move` intentionally does not export handwritten mirrors for Sui framework packages such as +`talus-sui-move` intentionally does not export handwritten mirrors for Sui framework packages such as `0x2::object::UID`, `0x2::coin::Coin`, `0x2::balance::Balance`, or `0x1::option::Option`. -Those are package-defined datatypes, not language atoms. +Those are datatypes defined by a package, not language atoms. If application code needs framework types, generate them from package metadata or define them in the consuming crate using the same `MoveType` / `MoveStruct` machinery used for user packages. This -keeps the core crate small enough to serve as the trusted type kernel for higher-level generated -bindings. +keeps the core crate small enough to serve as the trusted type kernel for generated bindings in +higher layers. ### What is deliberately excluded - Framework mirrors such as `UID`, `ID`, `Coin`, `Balance`, `Table`, and `Clock` - Package/module/function declaration IR -- Move expression/function-body IR +- Move expression/function body IR - Transaction building or execution ## Module guide -- `sui_move::prelude`: convenient imports for common traits/types -- `sui_move::decode`: ability-aware decode helpers +- `talus_sui_move::prelude`: convenient imports for common traits/types +- `talus_sui_move::decode`: decoding helpers constrained by Move abilities diff --git a/sui-move/examples/custom_struct.rs b/sui-move/examples/custom_struct.rs index d4db1b6..36caabd 100644 --- a/sui-move/examples/custom_struct.rs +++ b/sui-move/examples/custom_struct.rs @@ -1,5 +1,5 @@ use serde::{Deserialize, Serialize}; -use sui_move::{parse_address, parse_identifier, HasStore, MoveStruct, MoveType}; +use talus_sui_move::{parse_address, parse_identifier, HasStore, MoveStruct, MoveType}; #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] struct MyCounter { diff --git a/sui-move/examples/derive_struct.rs b/sui-move/examples/derive_struct.rs index c5639b6..908b4bf 100644 --- a/sui-move/examples/derive_struct.rs +++ b/sui-move/examples/derive_struct.rs @@ -1,19 +1,19 @@ -use sui_move::move_struct; +use talus_sui_move::move_struct; -/// Local declaration for the framework-shaped `0x2::object::ID` type. +/// Local declaration that mirrors the framework type `0x2::object::ID`. /// -/// `sui-move` intentionally does not export framework mirrors from its core. Generated package +/// `talus-sui-move` intentionally does not export framework mirrors from its core. Generated package /// bindings or local declarations provide these types when a package needs them. #[move_struct(address = "0x2", module = "object", abilities = "copy, store")] pub struct ID { /// Raw object address bytes. - pub bytes: sui_move::prelude::Address, + pub bytes: talus_sui_move::prelude::Address, } -/// Local declaration for the framework-shaped `0x2::object::UID` type. +/// Local declaration that mirrors the framework type `0x2::object::UID`. /// /// The derive macro only needs a field whose type represents a Move `UID`; it does not require -/// the `UID` type to be exported by `sui-move`. +/// the `UID` type to be exported by `talus-sui-move`. #[move_struct(address = "0x2", module = "object", abilities = "store")] pub struct UID { /// Inner object id. @@ -30,5 +30,5 @@ pub struct Vault { } fn main() { - let _tag = ::type_tag_static(); + let _tag = ::type_tag_static(); } diff --git a/sui-move/examples/tag_checked_decode.rs b/sui-move/examples/tag_checked_decode.rs index f6f4160..0bf3a92 100644 --- a/sui-move/examples/tag_checked_decode.rs +++ b/sui-move/examples/tag_checked_decode.rs @@ -1,13 +1,13 @@ use serde::{Deserialize, Serialize}; -use sui_move::{ +use sui_sdk_types::{StructTag, TypeTag}; +use talus_sui_move::{ decode_keyed, parse_address, parse_identifier, HasKey, HasStore, MoveStruct, MoveType, }; -use sui_sdk_types::{StructTag, TypeTag}; -/// Example key-bearing type used to demonstrate tag-checked decoding. +/// Example type with the Move `key` ability, used to demonstrate decoding that checks the tag. /// /// In real package bindings, framework and user types should be generated from package metadata. -/// This example defines a small local type so the `sui-move` kernel remains self-contained. +/// This example defines a small local type so the `talus-sui-move` kernel remains self contained. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] struct Counter { value: u64, @@ -41,5 +41,8 @@ fn main() { assert_eq!(inst.value.value, 10); let err = decode_keyed::(TypeTag::U8, &bytes).unwrap_err(); - assert!(matches!(err, sui_move::DecodeError::TypeTagMismatch { .. })); + assert!(matches!( + err, + talus_sui_move::DecodeError::TypeTagMismatch { .. } + )); } diff --git a/sui-move/examples/type_tags.rs b/sui-move/examples/type_tags.rs index 3170f5c..2085d7c 100644 --- a/sui-move/examples/type_tags.rs +++ b/sui-move/examples/type_tags.rs @@ -1,11 +1,11 @@ use serde::{Deserialize, Serialize}; -use sui_move::prelude::*; -use sui_move::{parse_address, parse_identifier}; +use talus_sui_move::prelude::*; +use talus_sui_move::{parse_address, parse_identifier}; -/// Example package-defined type used to demonstrate the kernel type-tag API. +/// Example type defined by a package and used to demonstrate the kernel type tag API. /// /// Framework declarations such as `0x2::coin::Coin` are intentionally not exported from -/// `sui-move`; they should be generated from package metadata like user-defined types. +/// `talus-sui-move`; they should be generated from package metadata like types defined by users. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] struct Counter { value: u64, @@ -31,7 +31,7 @@ impl MoveStruct for Counter { impl HasStore for Counter {} fn main() { - assert_eq!(sui_move::type_tag_of::(), TypeTag::U64); + assert_eq!(talus_sui_move::type_tag_of::(), TypeTag::U64); match Counter::type_tag_static() { TypeTag::Struct(tag) => { diff --git a/sui-move/src/builtins.rs b/sui-move/src/builtins.rs index d4b7bf9..120d5dc 100644 --- a/sui-move/src/builtins.rs +++ b/sui-move/src/builtins.rs @@ -1,4 +1,4 @@ -//! Implementations of [`MoveType`](crate::MoveType) and ability markers for Rust built-ins. +//! Implementations of [`MoveType`](crate::MoveType) and ability markers for standard Rust types. //! //! This module provides mappings for: //! - integer and boolean primitives (`u8`, `u16`, `u32`, `u64`, `u128`, `bool`) diff --git a/sui-move/src/decode.rs b/sui-move/src/decode.rs index be0a408..0cc897e 100644 --- a/sui-move/src/decode.rs +++ b/sui-move/src/decode.rs @@ -1,4 +1,4 @@ -//! Ability-aware decoding helpers. +//! Decoding helpers constrained by Move abilities. //! //! These helpers mirror the conceptual “this value is storable/copyable/keyed” boundaries that //! exist in Move, while keeping the runtime behavior small and explicit. @@ -22,7 +22,7 @@ pub fn decode_copyable(bytes: &[u8]) -> Result Deserialize<'de> for U256 { /// A Rust type that corresponds to a Move type. /// /// Implementors provide a static [`TypeTag`](sui_sdk_types::TypeTag) (including any type -/// arguments). This enables strongly-typed construction and verification of Move type tags and +/// arguments). This enables strongly typed construction and verification of Move type tags and /// safe BCS decoding. /// /// # Example /// ``` -/// use sui_move::prelude::*; +/// use talus_sui_move::prelude::*; /// /// assert_eq!(::type_tag_static(), TypeTag::U64); /// ``` @@ -177,7 +177,7 @@ pub enum DecodeError { /// /// # Example /// ``` -/// use sui_move::{MoveInstance, MoveType}; +/// use talus_sui_move::{MoveInstance, MoveType}; /// /// let value = 7u64; /// let bytes = value.to_bcs().unwrap(); @@ -216,7 +216,7 @@ impl MoveInstance { /// /// # Example /// ``` -/// use sui_move::parse_identifier; +/// use talus_sui_move::parse_identifier; /// /// assert_eq!(parse_identifier("coin").unwrap().to_string(), "coin"); /// ``` @@ -230,7 +230,7 @@ pub fn parse_identifier(value: &str) -> Result Result /// /// # Example /// ``` -/// use sui_move::{type_tag_of, MoveType}; +/// use talus_sui_move::{type_tag_of, MoveType}; /// /// assert_eq!(type_tag_of::(), ::type_tag_static()); /// ``` diff --git a/sui-move/tests/basic.rs b/sui-move/tests/basic.rs index a8cc9f9..b44091f 100644 --- a/sui-move/tests/basic.rs +++ b/sui-move/tests/basic.rs @@ -1,11 +1,11 @@ use std::str::FromStr; use serde::{Deserialize, Serialize}; -use sui_move::{ +use sui_sdk_types::{Address, StructTag, TypeTag}; +use talus_sui_move::{ decode_keyed, parse_address, parse_identifier, Copyable, HasKey, HasStore, MoveInstance, MoveStruct, MoveType, Storable, }; -use sui_sdk_types::{Address, StructTag, TypeTag}; #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] struct Counter { @@ -82,7 +82,10 @@ fn tag_verification_and_bcs_roundtrip_work_for_custom_types() { assert_eq!(inst.value, value); let err = MoveInstance::::from_raw_type(TypeTag::U64, &bytes).unwrap_err(); - assert!(matches!(err, sui_move::DecodeError::TypeTagMismatch { .. })); + assert!(matches!( + err, + talus_sui_move::DecodeError::TypeTagMismatch { .. } + )); } #[test] diff --git a/sui-move/tests/derive.rs b/sui-move/tests/derive.rs index 54ba1df..78993d5 100644 --- a/sui-move/tests/derive.rs +++ b/sui-move/tests/derive.rs @@ -2,39 +2,39 @@ use std::str::FromStr; -use sui_move::prelude::*; -use sui_move::{Copyable, MoveInstance, Storable}; +use talus_sui_move::prelude::*; +use talus_sui_move::{Copyable, MoveInstance, Storable}; mod object { - #[sui_move::move_struct(address = "0x2", module = "object", abilities = "copy, store")] + #[talus_sui_move::move_struct(address = "0x2", module = "object", abilities = "copy, store")] pub struct ID { - pub bytes: sui_move::prelude::Address, + pub bytes: talus_sui_move::prelude::Address, } - #[sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] + #[talus_sui_move::move_struct(address = "0x2", module = "object", abilities = "store")] pub struct UID { pub id: ID, } } -#[sui_move::move_module(address = "0x1", name = "vault")] +#[talus_sui_move::move_module(address = "0x1", name = "vault")] mod vault { - #[sui_move::move_struct( + #[talus_sui_move::move_struct( address = "0x1", module = "vault", abilities = "key, store", phantoms = "T", uid_type = "crate::object::UID" )] - pub struct Vault { + pub struct Vault { pub id: crate::object::UID, pub balance: Vec, } } -#[sui_move::move_module(address = "0x1", name = "wrapper")] +#[talus_sui_move::move_module(address = "0x1", name = "wrapper")] mod wrapper { - #[sui_move::move_struct( + #[talus_sui_move::move_struct( address = "0x1", module = "wrapper", abilities = "key, store", @@ -46,9 +46,9 @@ mod wrapper { } } -#[sui_move::move_module(address = "0x1", name = "bounded")] +#[talus_sui_move::move_module(address = "0x1", name = "bounded")] mod bounded { - #[sui_move::move_struct( + #[talus_sui_move::move_struct( address = "0x1", module = "bounded", abilities = "copy, store, drop", @@ -60,7 +60,7 @@ mod bounded { } mod phantom_copy { - #[sui_move::move_struct( + #[talus_sui_move::move_struct( address = "0x1", module = "phantom_copy", abilities = "copy, drop, store", @@ -72,12 +72,16 @@ mod phantom_copy { } mod conditional_abilities { - #[sui_move::move_struct(address = "0x1", module = "conditional_abilities", abilities = "store")] + #[talus_sui_move::move_struct( + address = "0x1", + module = "conditional_abilities", + abilities = "store" + )] pub struct StoreOnly { pub value: u64, } - #[sui_move::move_struct( + #[talus_sui_move::move_struct( address = "0x1", module = "conditional_abilities", abilities = "copy, drop, store" @@ -90,13 +94,13 @@ mod conditional_abilities { mod dynamic_address { use std::str::FromStr; - use sui_move::prelude::Address; + use talus_sui_move::prelude::Address; pub fn package() -> Address { Address::from_str("0x9").unwrap() } - #[sui_move::move_struct( + #[talus_sui_move::move_struct( address = "0x1", address_fn = "crate::dynamic_address::package", module = "dynamic_address", @@ -192,7 +196,10 @@ fn tag_verification_and_bcs_roundtrip() { assert_eq!(inst.value.balance, vec![1, 2, 3]); let err = MoveInstance::>::from_raw_type(TypeTag::U8, &bytes).unwrap_err(); - assert!(matches!(err, sui_move::DecodeError::TypeTagMismatch { .. })); + assert!(matches!( + err, + talus_sui_move::DecodeError::TypeTagMismatch { .. } + )); } fn require_store(_: &T) {} @@ -202,8 +209,8 @@ fn require_copy(_: &T) {} Debug, PartialEq, Eq, - sui_move::__private::serde::Serialize, - sui_move::__private::serde::Deserialize, + talus_sui_move::__private::serde::Serialize, + talus_sui_move::__private::serde::Deserialize, )] struct NonCloneType; From ed92e69a1488ce942dfdbf73be8827f000d63111 Mon Sep 17 00:00:00 2001 From: David Date: Thu, 27 Aug 2026 14:42:30 +0200 Subject: [PATCH 2/2] docs: remove release guide --- CONTRIBUTING.md | 5 ----- RELEASING.md | 47 ----------------------------------------------- 2 files changed, 52 deletions(-) delete mode 100644 RELEASING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 337cd64..58fa8e7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -75,10 +75,6 @@ Prefer crates.io dependencies with explicit versions. Git dependencies are accep they are intentional and should also include a version requirement when the crate exists on crates.io, so the workspace can be packaged predictably. -## Publishing - -Follow [RELEASING.md] for package validation, publication order, ownership, and trusted publishing. - ## License By contributing, you agree that your contributions will be licensed under the same license as the @@ -90,4 +86,3 @@ project: [LICENSE]. [CLA]: https://gist.github.com/devops-talus/82cafc9752547baf4be140b6db1e8fd6 [CLA Assistant]: https://cla-assistant.io/Talus-Network/move-binding [Conventional Commits]: https://www.conventionalcommits.org/ -[RELEASING.md]: RELEASING.md diff --git a/RELEASING.md b/RELEASING.md deleted file mode 100644 index 7d1a6db..0000000 --- a/RELEASING.md +++ /dev/null @@ -1,47 +0,0 @@ -# Releasing crates - -All workspace crates use one version and one Git tag. - -## Verify - -```console -cargo fmt --all -- --check -cargo clippy --workspace --all-targets --all-features --locked -- -D warnings -cargo test --workspace --all-targets --all-features --locked -cargo test --doc --workspace --all-features --locked -RUSTDOCFLAGS="-D warnings" cargo doc --workspace --all-features --no-deps --locked -./scripts/check-packages.sh -``` - -## Tag - -Merge the release commit into `main`, then create and push a signed tag: - -```console -git tag -s v0.2.0-rc.1 -m "move-binding v0.2.0-rc.1" -git push origin v0.2.0-rc.1 -``` - -## First publication - -From the clean tagged commit: - -```console -cargo login -PUBLISH_CRATES_CONFIRM=v0.2.0-rc.1 \ - ./scripts/publish-crates.sh v0.2.0-rc.1 -``` - -After publication: - -1. Add `devops-talus` and `github:Talus-Network:engineering` as owners of every crate. -2. Configure every crate to trust `Talus-Network/move-binding`, workflow - `publish-crates.yml`, environment `crates-io`. -3. Revoke the personal token and run `cargo logout`. - -Use `ALLOW_EXISTING=1` only to resume a reviewed partial publication. - -## Later releases - -Create and push the signed tag, then dispatch `Publish crates.io packages` in GitHub Actions. -Create the GitHub release only after every crate version is visible on crates.io.