Skip to content

Commit

Permalink
[Sui]: Adds support for remaining commands/call_args/input_args in ra…
Browse files Browse the repository at this point in the history
…w json (#4252)

* [Sui]: Adds support for nested result in raw json

* Addresses review comment

* Adds missing commands/args

* Makes clippy happy

* Adds a test for all transactions
  • Loading branch information
gupnik authored Feb 5, 2025
1 parent b4bed73 commit e36ee95
Show file tree
Hide file tree
Showing 8 changed files with 2,171 additions and 71 deletions.
9 changes: 9 additions & 0 deletions rust/chains/tw_sui/src/transaction/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use move_core_types::identifier::Identifier;
use move_core_types::language_storage::TypeTag;
use serde::{Deserialize, Serialize};

// Taken from here: https://github.com/MystenLabs/sui/blob/93f02057bb55eca407f04f551e6514f123005b65/crates/sui-types/src/transaction.rs#L660
/// A single command in a programmable transaction.
#[derive(Debug, Deserialize, Serialize)]
pub enum Command {
Expand All @@ -30,6 +31,14 @@ pub enum Command {
/// Given n-values of the same type, it constructs a vector. For non objects or an empty vector,
/// the type tag must be specified.
MakeMoveVec(Option<TypeTag>, Vec<Argument>),
/// Upgrades a Move package
/// Takes (in order):
/// 1. A vector of serialized modules for the package.
/// 2. A vector of object ids for the transitive dependencies of the new package.
/// 3. The object ID of the package being upgraded.
/// 4. An argument holding the `UpgradeTicket` that must have been produced from an earlier command in the same
/// programmable transaction.
Upgrade(Vec<Vec<u8>>, Vec<ObjectID>, ObjectID, Argument),
}

impl Command {
Expand Down
216 changes: 206 additions & 10 deletions rust/chains/tw_sui/src/transaction/raw_types.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
use move_core_types::identifier::Identifier;
use move_core_types::language_storage::TypeTag;
use serde::{Deserialize, Serialize};
use std::str::FromStr;
use tw_coin_entry::error::prelude::SigningError;
use tw_coin_entry::error::prelude::*;
use tw_coin_entry::error::prelude::{SigningError, SigningErrorType, SigningResult};
use tw_memory::Data;
use tw_misc::serde::as_string;

use crate::address::SuiAddress;

use super::sui_types::TransactionExpiration;
use super::{
command::Argument,
sui_types::{ObjectArg, ObjectID, SequenceNumber},
command::{Argument, Command},
sui_types::{CallArg, ObjectArg, ObjectDigest, ObjectID, ObjectRef, SequenceNumber},
};

#[derive(Debug, Deserialize, Serialize)]
Expand All @@ -21,6 +24,18 @@ pub struct PaymentConfig {
pub digest: String,
}

impl TryFrom<PaymentConfig> for ObjectRef {
type Error = SigningError;

fn try_from(config: PaymentConfig) -> Result<Self, Self::Error> {
Ok((
ObjectID::from_str(&config.object_id)?,
SequenceNumber(config.version),
ObjectDigest::from_str(&config.digest)?,
))
}
}

#[derive(Debug, Deserialize, Serialize)]
pub struct GasConfig {
#[serde(with = "as_string")]
Expand All @@ -32,20 +47,42 @@ pub struct GasConfig {

#[derive(Debug, Deserialize, Serialize)]
pub enum InputObjectArg {
#[serde(rename_all = "camelCase")]
ImmOrOwned {
object_id: String,
#[serde(with = "as_string")]
version: u64,
digest: String,
},
#[serde(rename_all = "camelCase")]
Shared {
mutable: bool,
#[serde(with = "as_string")]
initial_shared_version: u64,
object_id: String,
},
#[serde(rename_all = "camelCase")]
Receiving {
digest: String,
version: u64,
object_id: String,
},
}

impl TryFrom<InputObjectArg> for ObjectArg {
type Error = SigningError;

fn try_from(arg: InputObjectArg) -> Result<Self, Self::Error> {
match arg {
InputObjectArg::ImmOrOwned {
object_id,
version,
digest,
} => Ok(ObjectArg::ImmOrOwnedObject((
ObjectID::from_str(&object_id)?,
SequenceNumber(version),
ObjectDigest::from_str(&digest)?,
))),
InputObjectArg::Shared {
mutable,
initial_shared_version,
Expand All @@ -55,6 +92,15 @@ impl TryFrom<InputObjectArg> for ObjectArg {
initial_shared_version: SequenceNumber(initial_shared_version),
mutable,
}),
InputObjectArg::Receiving {
digest,
version,
object_id,
} => Ok(ObjectArg::Receiving((
ObjectID::from_str(&object_id)?,
SequenceNumber(version),
ObjectDigest::from_str(&digest)?,
))),
}
}
}
Expand All @@ -65,6 +111,17 @@ pub enum InputArg {
Object(InputObjectArg),
}

impl TryFrom<InputArg> for CallArg {
type Error = SigningError;

fn try_from(arg: InputArg) -> Result<Self, Self::Error> {
match arg {
InputArg::Pure(data) => Ok(CallArg::Pure(data)),
InputArg::Object(object) => Ok(CallArg::Object(object.try_into()?)),
}
}
}

#[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Input {
Expand All @@ -79,8 +136,17 @@ pub struct Input {
#[serde(tag = "kind")]
pub enum TransactionArg {
GasCoin,
Input { index: u16 },
Result { index: u16 },
Input {
index: u16,
},
Result {
index: u16,
},
#[serde(rename_all = "camelCase")]
NestedResult {
index: u16,
result_index: u16,
},
}

impl From<TransactionArg> for Argument {
Expand All @@ -89,6 +155,10 @@ impl From<TransactionArg> for Argument {
TransactionArg::GasCoin => Argument::GasCoin,
TransactionArg::Input { index } => Argument::Input(index),
TransactionArg::Result { index } => Argument::Result(index),
TransactionArg::NestedResult {
index,
result_index,
} => Argument::NestedResult(index, result_index),
}
}
}
Expand All @@ -105,10 +175,6 @@ impl From<TypeTagWrapper> for TypeTag {
#[derive(Debug, Deserialize, Serialize)]
#[serde(tag = "kind")]
pub enum Transaction {
SplitCoins {
coin: TransactionArg,
amounts: Vec<TransactionArg>,
},
#[serde(rename_all = "camelCase")]
MoveCall {
target: String,
Expand All @@ -119,14 +185,144 @@ pub enum Transaction {
objects: Vec<TransactionArg>,
address: TransactionArg,
},
SplitCoins {
coin: TransactionArg,
amounts: Vec<TransactionArg>,
},
MergeCoins {
destination: TransactionArg,
sources: Vec<TransactionArg>,
},
Publish {
modules: Vec<Data>,
dependencies: Vec<String>,
},
#[serde(rename_all = "camelCase")]
MakeMoveVec {
type_tag: Option<TypeTagWrapper>,
arguments: Vec<TransactionArg>,
},
#[serde(rename_all = "camelCase")]
Upgrade {
modules: Vec<Data>,
dependencies: Vec<String>,
package_id: String,
ticket: TransactionArg,
},
}

impl TryFrom<Transaction> for Command {
type Error = SigningError;

fn try_from(transaction: Transaction) -> Result<Self, Self::Error> {
match transaction {
Transaction::MoveCall {
target,
type_arguments,
arguments,
} => {
let parts: Vec<&str> = target.split("::").collect();
if parts.len() != 3 {
return SigningError::err(SigningErrorType::Error_invalid_params)
.context("Invalid target format for MoveCall command");
}
let package = ObjectID::from_str(parts[0]).context("Failed to parse package ID")?;
let module = Identifier::from_str(parts[1])
.tw_err(|_| SigningErrorType::Error_invalid_params)
.context("Failed to parse module")?;
let function = Identifier::from_str(parts[2])
.tw_err(|_| SigningErrorType::Error_invalid_params)
.context("Failed to parse function")?;
Ok(Command::move_call(
package,
module,
function,
type_arguments.into_iter().map(|tag| tag.into()).collect(),
arguments
.into_iter()
.map(|argument| argument.into())
.collect(),
))
},
Transaction::TransferObjects { objects, address } => Ok(Command::TransferObjects(
objects.into_iter().map(|object| object.into()).collect(),
address.into(),
)),
Transaction::SplitCoins { coin, amounts } => Ok(Command::SplitCoins(
coin.into(),
amounts.into_iter().map(|amount| amount.into()).collect(),
)),
Transaction::MergeCoins {
destination,
sources,
} => Ok(Command::MergeCoins(
destination.into(),
sources.into_iter().map(|source| source.into()).collect(),
)),
Transaction::Publish {
modules,
dependencies,
} => Ok(Command::Publish(
modules,
dependencies
.into_iter()
.map(|dependency| {
ObjectID::from_str(&dependency).context("Failed to parse object ID")
})
.collect::<SigningResult<Vec<_>>>()?,
)),
Transaction::MakeMoveVec {
type_tag,
arguments,
} => Ok(Command::MakeMoveVec(
type_tag.map(|tag| tag.into()),
arguments
.into_iter()
.map(|argument| argument.into())
.collect(),
)),
Transaction::Upgrade {
modules,
dependencies,
package_id,
ticket,
} => Ok(Command::Upgrade(
modules,
dependencies
.into_iter()
.map(|dependency| {
ObjectID::from_str(&dependency).context("Failed to parse object ID")
})
.collect::<SigningResult<Vec<_>>>()?,
ObjectID::from_str(&package_id).context("Failed to parse object ID")?,
ticket.into(),
)),
}
}
}

// Taken from here: https://github.com/MystenLabs/ts-sdks/blob/68e1b649c125f031b72ff7816d1ff653ef47cb53/packages/typescript/src/transactions/data/v1.ts#L271
#[derive(Debug, Deserialize, Serialize)]
pub enum Expiration {
None(bool),
Epoch(u64),
}

impl From<Expiration> for TransactionExpiration {
fn from(expiration: Expiration) -> Self {
match expiration {
Expiration::None(_) => TransactionExpiration::None,
Expiration::Epoch(epoch) => TransactionExpiration::Epoch(epoch),
}
}
}

#[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RawTransaction {
pub version: u8,
pub sender: SuiAddress,
pub expiration: Option<u64>,
pub expiration: Option<Expiration>,
pub gas_config: GasConfig,
pub inputs: Vec<Input>,
pub transactions: Vec<Transaction>,
Expand Down
4 changes: 4 additions & 0 deletions rust/chains/tw_sui/src/transaction/sui_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ impl CallArg {
pub const SUI_SYSTEM_MUT: Self = Self::Object(ObjectArg::SUI_SYSTEM_MUT);
}

// Taken from here: https://github.com/MystenLabs/sui/blob/93f02057bb55eca407f04f551e6514f123005b65/crates/sui-types/src/transaction.rs#L107
#[derive(Debug, Deserialize, PartialEq, Serialize)]
pub enum ObjectArg {
// A Move object, either immutable, or owned mutable.
Expand All @@ -72,6 +73,8 @@ pub enum ObjectArg {
initial_shared_version: SequenceNumber,
mutable: bool,
},
// A Move object that can be received in this transaction.
Receiving(ObjectRef),
}

impl ObjectArg {
Expand All @@ -84,6 +87,7 @@ impl ObjectArg {
pub fn id(&self) -> ObjectID {
match self {
ObjectArg::ImmOrOwnedObject((id, _, _)) | ObjectArg::SharedObject { id, .. } => *id,
ObjectArg::Receiving((id, _, _)) => *id,
}
}
}
Expand Down
Loading

0 comments on commit e36ee95

Please sign in to comment.