Skip to content

Commit e36ee95

Browse files
authored
[Sui]: Adds support for remaining commands/call_args/input_args in raw 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
1 parent b4bed73 commit e36ee95

File tree

8 files changed

+2171
-71
lines changed

8 files changed

+2171
-71
lines changed

rust/chains/tw_sui/src/transaction/command.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use move_core_types::identifier::Identifier;
77
use move_core_types::language_storage::TypeTag;
88
use serde::{Deserialize, Serialize};
99

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

3544
impl Command {

rust/chains/tw_sui/src/transaction/raw_types.rs

Lines changed: 206 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
1+
use move_core_types::identifier::Identifier;
12
use move_core_types::language_storage::TypeTag;
23
use serde::{Deserialize, Serialize};
34
use std::str::FromStr;
4-
use tw_coin_entry::error::prelude::SigningError;
5+
use tw_coin_entry::error::prelude::*;
6+
use tw_coin_entry::error::prelude::{SigningError, SigningErrorType, SigningResult};
57
use tw_memory::Data;
68
use tw_misc::serde::as_string;
79

810
use crate::address::SuiAddress;
911

12+
use super::sui_types::TransactionExpiration;
1013
use super::{
11-
command::Argument,
12-
sui_types::{ObjectArg, ObjectID, SequenceNumber},
14+
command::{Argument, Command},
15+
sui_types::{CallArg, ObjectArg, ObjectDigest, ObjectID, ObjectRef, SequenceNumber},
1316
};
1417

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

27+
impl TryFrom<PaymentConfig> for ObjectRef {
28+
type Error = SigningError;
29+
30+
fn try_from(config: PaymentConfig) -> Result<Self, Self::Error> {
31+
Ok((
32+
ObjectID::from_str(&config.object_id)?,
33+
SequenceNumber(config.version),
34+
ObjectDigest::from_str(&config.digest)?,
35+
))
36+
}
37+
}
38+
2439
#[derive(Debug, Deserialize, Serialize)]
2540
pub struct GasConfig {
2641
#[serde(with = "as_string")]
@@ -32,20 +47,42 @@ pub struct GasConfig {
3247

3348
#[derive(Debug, Deserialize, Serialize)]
3449
pub enum InputObjectArg {
50+
#[serde(rename_all = "camelCase")]
51+
ImmOrOwned {
52+
object_id: String,
53+
#[serde(with = "as_string")]
54+
version: u64,
55+
digest: String,
56+
},
3557
#[serde(rename_all = "camelCase")]
3658
Shared {
3759
mutable: bool,
3860
#[serde(with = "as_string")]
3961
initial_shared_version: u64,
4062
object_id: String,
4163
},
64+
#[serde(rename_all = "camelCase")]
65+
Receiving {
66+
digest: String,
67+
version: u64,
68+
object_id: String,
69+
},
4270
}
4371

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

4775
fn try_from(arg: InputObjectArg) -> Result<Self, Self::Error> {
4876
match arg {
77+
InputObjectArg::ImmOrOwned {
78+
object_id,
79+
version,
80+
digest,
81+
} => Ok(ObjectArg::ImmOrOwnedObject((
82+
ObjectID::from_str(&object_id)?,
83+
SequenceNumber(version),
84+
ObjectDigest::from_str(&digest)?,
85+
))),
4986
InputObjectArg::Shared {
5087
mutable,
5188
initial_shared_version,
@@ -55,6 +92,15 @@ impl TryFrom<InputObjectArg> for ObjectArg {
5592
initial_shared_version: SequenceNumber(initial_shared_version),
5693
mutable,
5794
}),
95+
InputObjectArg::Receiving {
96+
digest,
97+
version,
98+
object_id,
99+
} => Ok(ObjectArg::Receiving((
100+
ObjectID::from_str(&object_id)?,
101+
SequenceNumber(version),
102+
ObjectDigest::from_str(&digest)?,
103+
))),
58104
}
59105
}
60106
}
@@ -65,6 +111,17 @@ pub enum InputArg {
65111
Object(InputObjectArg),
66112
}
67113

114+
impl TryFrom<InputArg> for CallArg {
115+
type Error = SigningError;
116+
117+
fn try_from(arg: InputArg) -> Result<Self, Self::Error> {
118+
match arg {
119+
InputArg::Pure(data) => Ok(CallArg::Pure(data)),
120+
InputArg::Object(object) => Ok(CallArg::Object(object.try_into()?)),
121+
}
122+
}
123+
}
124+
68125
#[derive(Debug, Deserialize, Serialize)]
69126
#[serde(rename_all = "camelCase")]
70127
pub struct Input {
@@ -79,8 +136,17 @@ pub struct Input {
79136
#[serde(tag = "kind")]
80137
pub enum TransactionArg {
81138
GasCoin,
82-
Input { index: u16 },
83-
Result { index: u16 },
139+
Input {
140+
index: u16,
141+
},
142+
Result {
143+
index: u16,
144+
},
145+
#[serde(rename_all = "camelCase")]
146+
NestedResult {
147+
index: u16,
148+
result_index: u16,
149+
},
84150
}
85151

86152
impl From<TransactionArg> for Argument {
@@ -89,6 +155,10 @@ impl From<TransactionArg> for Argument {
89155
TransactionArg::GasCoin => Argument::GasCoin,
90156
TransactionArg::Input { index } => Argument::Input(index),
91157
TransactionArg::Result { index } => Argument::Result(index),
158+
TransactionArg::NestedResult {
159+
index,
160+
result_index,
161+
} => Argument::NestedResult(index, result_index),
92162
}
93163
}
94164
}
@@ -105,10 +175,6 @@ impl From<TypeTagWrapper> for TypeTag {
105175
#[derive(Debug, Deserialize, Serialize)]
106176
#[serde(tag = "kind")]
107177
pub enum Transaction {
108-
SplitCoins {
109-
coin: TransactionArg,
110-
amounts: Vec<TransactionArg>,
111-
},
112178
#[serde(rename_all = "camelCase")]
113179
MoveCall {
114180
target: String,
@@ -119,14 +185,144 @@ pub enum Transaction {
119185
objects: Vec<TransactionArg>,
120186
address: TransactionArg,
121187
},
188+
SplitCoins {
189+
coin: TransactionArg,
190+
amounts: Vec<TransactionArg>,
191+
},
192+
MergeCoins {
193+
destination: TransactionArg,
194+
sources: Vec<TransactionArg>,
195+
},
196+
Publish {
197+
modules: Vec<Data>,
198+
dependencies: Vec<String>,
199+
},
200+
#[serde(rename_all = "camelCase")]
201+
MakeMoveVec {
202+
type_tag: Option<TypeTagWrapper>,
203+
arguments: Vec<TransactionArg>,
204+
},
205+
#[serde(rename_all = "camelCase")]
206+
Upgrade {
207+
modules: Vec<Data>,
208+
dependencies: Vec<String>,
209+
package_id: String,
210+
ticket: TransactionArg,
211+
},
212+
}
213+
214+
impl TryFrom<Transaction> for Command {
215+
type Error = SigningError;
216+
217+
fn try_from(transaction: Transaction) -> Result<Self, Self::Error> {
218+
match transaction {
219+
Transaction::MoveCall {
220+
target,
221+
type_arguments,
222+
arguments,
223+
} => {
224+
let parts: Vec<&str> = target.split("::").collect();
225+
if parts.len() != 3 {
226+
return SigningError::err(SigningErrorType::Error_invalid_params)
227+
.context("Invalid target format for MoveCall command");
228+
}
229+
let package = ObjectID::from_str(parts[0]).context("Failed to parse package ID")?;
230+
let module = Identifier::from_str(parts[1])
231+
.tw_err(|_| SigningErrorType::Error_invalid_params)
232+
.context("Failed to parse module")?;
233+
let function = Identifier::from_str(parts[2])
234+
.tw_err(|_| SigningErrorType::Error_invalid_params)
235+
.context("Failed to parse function")?;
236+
Ok(Command::move_call(
237+
package,
238+
module,
239+
function,
240+
type_arguments.into_iter().map(|tag| tag.into()).collect(),
241+
arguments
242+
.into_iter()
243+
.map(|argument| argument.into())
244+
.collect(),
245+
))
246+
},
247+
Transaction::TransferObjects { objects, address } => Ok(Command::TransferObjects(
248+
objects.into_iter().map(|object| object.into()).collect(),
249+
address.into(),
250+
)),
251+
Transaction::SplitCoins { coin, amounts } => Ok(Command::SplitCoins(
252+
coin.into(),
253+
amounts.into_iter().map(|amount| amount.into()).collect(),
254+
)),
255+
Transaction::MergeCoins {
256+
destination,
257+
sources,
258+
} => Ok(Command::MergeCoins(
259+
destination.into(),
260+
sources.into_iter().map(|source| source.into()).collect(),
261+
)),
262+
Transaction::Publish {
263+
modules,
264+
dependencies,
265+
} => Ok(Command::Publish(
266+
modules,
267+
dependencies
268+
.into_iter()
269+
.map(|dependency| {
270+
ObjectID::from_str(&dependency).context("Failed to parse object ID")
271+
})
272+
.collect::<SigningResult<Vec<_>>>()?,
273+
)),
274+
Transaction::MakeMoveVec {
275+
type_tag,
276+
arguments,
277+
} => Ok(Command::MakeMoveVec(
278+
type_tag.map(|tag| tag.into()),
279+
arguments
280+
.into_iter()
281+
.map(|argument| argument.into())
282+
.collect(),
283+
)),
284+
Transaction::Upgrade {
285+
modules,
286+
dependencies,
287+
package_id,
288+
ticket,
289+
} => Ok(Command::Upgrade(
290+
modules,
291+
dependencies
292+
.into_iter()
293+
.map(|dependency| {
294+
ObjectID::from_str(&dependency).context("Failed to parse object ID")
295+
})
296+
.collect::<SigningResult<Vec<_>>>()?,
297+
ObjectID::from_str(&package_id).context("Failed to parse object ID")?,
298+
ticket.into(),
299+
)),
300+
}
301+
}
302+
}
303+
304+
// Taken from here: https://github.com/MystenLabs/ts-sdks/blob/68e1b649c125f031b72ff7816d1ff653ef47cb53/packages/typescript/src/transactions/data/v1.ts#L271
305+
#[derive(Debug, Deserialize, Serialize)]
306+
pub enum Expiration {
307+
None(bool),
308+
Epoch(u64),
309+
}
310+
311+
impl From<Expiration> for TransactionExpiration {
312+
fn from(expiration: Expiration) -> Self {
313+
match expiration {
314+
Expiration::None(_) => TransactionExpiration::None,
315+
Expiration::Epoch(epoch) => TransactionExpiration::Epoch(epoch),
316+
}
317+
}
122318
}
123319

124320
#[derive(Debug, Deserialize, Serialize)]
125321
#[serde(rename_all = "camelCase")]
126322
pub struct RawTransaction {
127323
pub version: u8,
128324
pub sender: SuiAddress,
129-
pub expiration: Option<u64>,
325+
pub expiration: Option<Expiration>,
130326
pub gas_config: GasConfig,
131327
pub inputs: Vec<Input>,
132328
pub transactions: Vec<Transaction>,

rust/chains/tw_sui/src/transaction/sui_types.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ impl CallArg {
6161
pub const SUI_SYSTEM_MUT: Self = Self::Object(ObjectArg::SUI_SYSTEM_MUT);
6262
}
6363

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

7780
impl ObjectArg {
@@ -84,6 +87,7 @@ impl ObjectArg {
8487
pub fn id(&self) -> ObjectID {
8588
match self {
8689
ObjectArg::ImmOrOwnedObject((id, _, _)) | ObjectArg::SharedObject { id, .. } => *id,
90+
ObjectArg::Receiving((id, _, _)) => *id,
8791
}
8892
}
8993
}

0 commit comments

Comments
 (0)