Skip to content

Commit

Permalink
sui-transaction-builder: introduce a crate for building transaction (#41
Browse files Browse the repository at this point in the history
)
  • Loading branch information
stefan-mysten authored Dec 5, 2024
1 parent b2e9b83 commit 85b9a86
Show file tree
Hide file tree
Showing 12 changed files with 1,227 additions and 26 deletions.
18 changes: 18 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,27 @@ jobs:
echo "Downloading testnet binary from $download_url"
wget -q $download_url -O sui.tgz
tar -zxvf sui.tgz ./sui
chmod +x ./sui
echo "Starting local network with a faucet, an indexer (port 5432) and GraphQL. Epoch duration is set to $EPOCH_DURATION_MS ms"
echo "$(pwd)" >> $GITHUB_PATH # we need it on the path for calling sui move build for some tests
./sui start --force-regenesis --with-faucet --with-indexer --with-graphql --pg-port 5432 --pg-db-name sui_indexer_v2 --epoch-duration-ms $EPOCH_DURATION_MS &
- name: Set up the CLI environment (need a client.yaml for calling some Sui commands)
shell: bash
run: |
mkdir -p $HOME/.sui/sui_config
tee $HOME/.sui/sui_config/client.yaml <<EOF
---
keystore:
File: home/.sui/sui_config/sui.keystore
envs:
- alias: localnet
rpc: "http://127.0.0.1:9000"
ws: ~
active_env: localnet
active_address: "0x14e7ac25259adcc373c96627893976d4fe562a3f3fedce493fc187c5ebd53eee"
EOF
- name: Run tests that require local network (GraphQL Client and Tx Builder)
env:
NETWORK: "local" # other expected options are mainnet, testnet, or devnet, or an actual URL to a GraphQL server: http://localhost:port
Expand Down
7 changes: 5 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,12 @@ test:
cargo nextest run --all-features -p sui-sdk-types -p sui-crypto
cargo test --doc

package_%.json: crates/sui-transaction-builder/tests/%/Move.toml crates/sui-transaction-builder/tests/%/sources/*.move
cd crates/sui-transaction-builder/tests/$(*F) && sui move build --dump-bytecode-as-base64 > ../../$@

.PHONY: test-with-localnet
test-with-localnet:
cargo nextest run -p sui-graphql-client
test-with-localnet: package_test_example_v1.json package_test_example_v2.json
cargo nextest run -p sui-graphql-client -p sui-transaction-builder

.PHONY: wasm
wasm:
Expand Down
2 changes: 1 addition & 1 deletion crates/sui-graphql-client/src/query_types/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ pub struct Object {
pub bcs: Option<Base64>,
}

#[derive(Clone, cynic::InputObject, Debug)]
#[derive(Clone, Default, cynic::InputObject, Debug)]
#[cynic(schema = "rpc", graphql_type = "ObjectFilter")]
pub struct ObjectFilter<'a> {
#[cynic(rename = "type")]
Expand Down
100 changes: 77 additions & 23 deletions crates/sui-sdk-types/src/types/transaction/unresolved.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,60 +226,91 @@ impl Input {
}

/// Set the object kind to immutable.
pub fn with_immutable_kind(&mut self) {
self.kind = Some(InputKind::ImmutableOrOwned);
pub fn with_immutable_kind(self) -> Self {
Self {
kind: Some(InputKind::ImmutableOrOwned),
..self
}
}

/// Set the object kind to owned.
pub fn with_owned_kind(&mut self) {
self.kind = Some(InputKind::ImmutableOrOwned);
pub fn with_owned_kind(self) -> Self {
Self {
kind: Some(InputKind::ImmutableOrOwned),
..self
}
}

/// Set the object kind to receiving.
pub fn with_receiving_kind(&mut self) {
self.kind = Some(InputKind::Receiving);
pub fn with_receiving_kind(self) -> Self {
Self {
kind: Some(InputKind::Receiving),
..self
}
}

/// Set the object kind to shared.
pub fn with_shared_kind(&mut self) {
self.kind = Some(InputKind::Shared);
pub fn with_shared_kind(self) -> Self {
Self {
kind: Some(InputKind::Shared),
..self
}
}

/// Set the specified version.
pub fn with_version(&mut self, version: u64) {
self.version = Some(version);
pub fn with_version(self, version: u64) -> Self {
Self {
version: Some(version),
..self
}
}

/// Set the specified digest.
pub fn with_digest(&mut self, digest: ObjectDigest) {
self.digest = Some(digest);
pub fn with_digest(self, digest: ObjectDigest) -> Self {
Self {
digest: Some(digest),
..self
}
}

// Shared fields

/// Set the initial shared version.
pub fn with_initial_shared_version(&mut self, initial: u64) {
self.version = Some(initial);
pub fn with_initial_shared_version(self, initial_version: u64) -> Self {
Self {
kind: Some(InputKind::Shared),
version: Some(initial_version),
..self
}
}

/// Make the object shared and set `mutable` to true when the input is used by value.
pub fn by_val(&mut self) {
self.kind = Some(InputKind::Shared);
self.mutable = Some(true);
pub fn by_val(self) -> Self {
Self {
kind: Some(InputKind::Shared),
mutable: Some(true),
..self
}
}

/// Make the object shared and set `mutable` to false when the input is used by
/// reference.
pub fn by_ref(&mut self) {
self.kind = Some(InputKind::Shared);
self.mutable = Some(false);
pub fn by_ref(self) -> Self {
Self {
kind: Some(InputKind::Shared),
mutable: Some(false),
..self
}
}

/// Make the object shared and set `mutable` to true when the input is used by mutable
/// reference.
pub fn by_mut(&mut self) {
self.kind = Some(InputKind::Shared);
self.mutable = Some(true);
pub fn by_mut(self) -> Self {
Self {
kind: Some(InputKind::Shared),
mutable: Some(true),
..self
}
}
}

Expand Down Expand Up @@ -321,3 +352,26 @@ impl From<Value> for serde_json::Value {
}
}
}

#[cfg(all(feature = "serde", feature = "hash"))]
impl From<&crate::types::Object> for Input {
fn from(object: &crate::types::Object) -> Self {
use crate::types::object::Owner;

let input = Input::by_id(object.object_id())
.with_digest(object.digest())
.with_version(object.version());
match object.owner() {
Owner::Address(_) => input,
Owner::Object(_) => input,
Owner::Shared(at_version) => input.with_initial_shared_version(*at_version),
Owner::Immutable => input.with_immutable_kind(),
}
}
}

impl From<ObjectId> for Input {
fn from(object_id: ObjectId) -> Self {
Input::by_id(object_id)
}
}
1 change: 1 addition & 0 deletions crates/sui-transaction-builder/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package_test_example*.json
26 changes: 26 additions & 0 deletions crates/sui-transaction-builder/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[package]
name = "sui-transaction-builder"
version = "0.1.0"
authors = ["Stefan Stanciulescu <[email protected]>", "Brandon Williams <[email protected]>"]
license = "Apache-2.0"
edition = "2021"
publish = false
readme = "README.md"
description = "Transaction API for the Rust SDK for the Sui Blockchain"

[dependencies]
base64ct = "1.6"
bcs = "0.1.6"
serde = { version = "1.0", features = ["derive"] }
sui-types = { package = "sui-sdk-types", path = "../sui-sdk-types", features = ["serde", "hash"] }
sui-graphql-client = { package = "sui-graphql-client", path = "../sui-graphql-client" }
thiserror = "2.0"

[dev-dependencies]
anyhow = "1.0"
rand = "0.8"
serde_json = "1.0"
sui-crypto = { package = "sui-crypto", path = "../sui-crypto" , features = ["ed25519"] }
sui-types = { package = "sui-sdk-types", path = "../sui-sdk-types", features = ["rand"] }
tokio = { version = "1.0", features = ["full"] }

40 changes: 40 additions & 0 deletions crates/sui-transaction-builder/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

use base64ct::Error as Base64Error;
use sui_types::types::ObjectId;

#[derive(thiserror::Error, Debug, Clone)]
#[non_exhaustive]
pub enum Error {
#[error("Conversion error due to input issue: {0}")]
Input(String),
#[error("Gas object should be an immutable or owned object")]
WrongGasObject,
#[error("Decoding error: {0}")]
Decoding(#[from] Base64Error),
#[error("Missing object id")]
MissingObjectId,
#[error("Missing version for object {0}")]
MissingVersion(ObjectId),
#[error("Missing digest for object {0}")]
MissingDigest(ObjectId),
#[error("Missing sender")]
MissingSender,
#[error("Missing gas objects")]
MissingGasObjects,
#[error("Missing gas budget")]
MissingGasBudget,
#[error("Missing gas price")]
MissingGasPrice,
#[error("Missing object kind for object {0}")]
MissingObjectKind(ObjectId),
#[error("Missing initial shared version for object {0}")]
MissingInitialSharedVersion(ObjectId),
#[error("Missing pure value")]
MissingPureValue,
#[error("Unknown shared object mutability for object {0}")]
SharedObjectMutability(ObjectId),
#[error("Unsupported literal")]
UnsupportedLiteral,
}
Loading

0 comments on commit 85b9a86

Please sign in to comment.