1use sui_types::Address;
2use sui_types::Command;
3use sui_types::ObjectDigest;
4use sui_types::ObjectId;
5use sui_types::TransactionExpiration;
6use sui_types::Version;
7
8#[derive(serde::Serialize, serde::Deserialize)]
11#[serde(rename = "UnresolvedTransaction")]
12pub struct Transaction {
13 #[serde(flatten)]
14 pub ptb: ProgrammableTransaction,
15 pub sender: Address,
16 #[serde(skip_serializing_if = "Option::is_none")]
17 pub gas_payment: Option<GasPayment>,
18 pub expiration: TransactionExpiration,
19}
20
21#[derive(serde::Serialize, serde::Deserialize)]
22#[serde(rename = "UnresolvedProgrammableTransaction")]
23pub struct ProgrammableTransaction {
24 pub inputs: Vec<Input>,
25 pub commands: Vec<Command>,
26}
27
28#[derive(serde::Serialize, serde::Deserialize)]
29#[serde(rename = "UnresolvedGasPayment")]
30pub struct GasPayment {
31 #[serde(default, skip_serializing_if = "Vec::is_empty")]
32 pub objects: Vec<ObjectReference>,
33 pub owner: Address,
34 #[serde(
35 with = "OptionReadableDisplay",
36 default,
37 skip_serializing_if = "Option::is_none"
38 )]
39 pub price: Option<u64>,
40 #[serde(
41 with = "OptionReadableDisplay",
42 default,
43 skip_serializing_if = "Option::is_none"
44 )]
45 pub budget: Option<u64>,
46}
47
48#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
49#[serde(rename = "UnresolvedObjectReference")]
50pub struct ObjectReference {
51 pub object_id: ObjectId,
52 #[serde(
53 with = "OptionReadableDisplay",
54 default,
55 skip_serializing_if = "Option::is_none"
56 )]
57 pub version: Option<Version>,
58 #[serde(skip_serializing_if = "Option::is_none")]
59 pub digest: Option<ObjectDigest>,
60}
61
62#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
63#[serde(rename = "UnresolvedInputKind")]
64#[serde(rename_all = "snake_case")]
65pub enum InputKind {
66 Pure,
67 Shared,
68 Receiving,
69 ImmutableOrOwned,
70 Literal,
71}
72
73#[derive(Clone, Debug, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
80#[serde(rename = "UnresolvedInput")]
81pub struct Input {
82 #[serde(skip_serializing_if = "Option::is_none")]
83 pub kind: Option<InputKind>,
84 #[serde(skip_serializing_if = "Option::is_none")]
85 pub value: Option<Value>,
86 #[serde(skip_serializing_if = "Option::is_none")]
87 pub object_id: Option<ObjectId>,
89 #[serde(
95 with = "OptionReadableDisplay",
96 default,
97 skip_serializing_if = "Option::is_none",
98 alias = "initial_shared_version"
99 )]
100 pub version: Option<Version>,
101 #[serde(skip_serializing_if = "Option::is_none")]
104 pub digest: Option<ObjectDigest>,
105 #[serde(skip_serializing_if = "Option::is_none")]
107 pub mutable: Option<bool>,
108}
109
110#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
111#[serde(rename = "UnresolvedValue")]
112#[serde(try_from = "serde_json::Value", into = "serde_json::Value")]
113pub enum Value {
114 Null,
115 Bool(bool),
116 Number(u64),
117 String(String),
118 Array(Vec<Value>),
119}
120
121impl Input {
122 pub fn owned(object_id: ObjectId, version: u64, digest: ObjectDigest) -> Self {
124 Self {
125 kind: Some(InputKind::ImmutableOrOwned),
126 object_id: Some(object_id),
127 version: Some(version),
128 digest: Some(digest),
129 ..Default::default()
130 }
131 }
132
133 pub fn immutable(object_id: ObjectId, version: u64, digest: ObjectDigest) -> Self {
135 Self {
136 kind: Some(InputKind::ImmutableOrOwned),
137 object_id: Some(object_id),
138 version: Some(version),
139 digest: Some(digest),
140 ..Default::default()
141 }
142 }
143
144 pub fn receiving(object_id: ObjectId, version: u64, digest: ObjectDigest) -> Self {
146 Self {
147 kind: Some(InputKind::Receiving),
148 object_id: Some(object_id),
149 version: Some(version),
150 digest: Some(digest),
151 ..Default::default()
152 }
153 }
154
155 pub fn shared(object_id: ObjectId, initial_shared_version: u64, mutable: bool) -> Self {
159 Self {
160 kind: Some(InputKind::Shared),
161 object_id: Some(object_id),
162 version: Some(initial_shared_version),
163 mutable: Some(mutable),
164 ..Default::default()
165 }
166 }
167
168 pub fn by_id(object_id: ObjectId) -> Self {
170 Self {
171 object_id: Some(object_id),
172 ..Default::default()
173 }
174 }
175
176 pub fn with_immutable_kind(self) -> Self {
178 Self {
179 kind: Some(InputKind::ImmutableOrOwned),
180 ..self
181 }
182 }
183
184 pub fn with_owned_kind(self) -> Self {
186 Self {
187 kind: Some(InputKind::ImmutableOrOwned),
188 ..self
189 }
190 }
191
192 pub fn with_receiving_kind(self) -> Self {
194 Self {
195 kind: Some(InputKind::Receiving),
196 ..self
197 }
198 }
199
200 pub fn with_shared_kind(self) -> Self {
202 Self {
203 kind: Some(InputKind::Shared),
204 ..self
205 }
206 }
207
208 pub fn with_version(self, version: u64) -> Self {
210 Self {
211 version: Some(version),
212 ..self
213 }
214 }
215
216 pub fn with_digest(self, digest: ObjectDigest) -> Self {
218 Self {
219 digest: Some(digest),
220 ..self
221 }
222 }
223
224 pub fn with_initial_shared_version(self, initial_version: u64) -> Self {
228 Self {
229 kind: Some(InputKind::Shared),
230 version: Some(initial_version),
231 ..self
232 }
233 }
234
235 pub fn by_val(self) -> Self {
237 Self {
238 kind: Some(InputKind::Shared),
239 mutable: Some(true),
240 ..self
241 }
242 }
243
244 pub fn by_ref(self) -> Self {
247 Self {
248 kind: Some(InputKind::Shared),
249 mutable: Some(false),
250 ..self
251 }
252 }
253
254 pub fn by_mut(self) -> Self {
257 Self {
258 kind: Some(InputKind::Shared),
259 mutable: Some(true),
260 ..self
261 }
262 }
263}
264
265impl TryFrom<serde_json::Value> for Value {
266 type Error = &'static str;
267
268 fn try_from(value: serde_json::Value) -> Result<Self, Self::Error> {
269 let v = match value {
270 serde_json::Value::Null => Self::Null,
271 serde_json::Value::Bool(b) => Self::Bool(b),
272 serde_json::Value::Number(n) => {
273 Self::Number(n.as_u64().ok_or("expected unsigned integer")?)
274 }
275 serde_json::Value::String(s) => Self::String(s),
276 serde_json::Value::Array(a) => Self::Array(
277 a.into_iter()
278 .map(Self::try_from)
279 .collect::<Result<_, _>>()?,
280 ),
281 serde_json::Value::Object(_) => return Err("objects are not supported"),
282 };
283
284 Ok(v)
285 }
286}
287
288impl From<Value> for serde_json::Value {
289 fn from(value: Value) -> Self {
290 match value {
291 Value::Null => Self::Null,
292 Value::Bool(b) => Self::Bool(b),
293 Value::Number(n) => Self::Number(n.into()),
294 Value::String(s) => Self::String(s),
295 Value::Array(a) => Self::Array(a.into_iter().map(Into::into).collect()),
296 }
297 }
298}
299
300impl From<&sui_types::Object> for Input {
301 fn from(object: &sui_types::Object) -> Self {
302 use sui_types::Owner;
303
304 let input = Input::by_id(object.object_id())
305 .with_digest(object.digest())
306 .with_version(object.version());
307 match object.owner() {
308 Owner::Address(_) => input,
309 Owner::Object(_) => input,
310 Owner::Shared(at_version) => input.with_initial_shared_version(*at_version),
311 Owner::Immutable => input.with_immutable_kind(),
312 Owner::ConsensusAddress { start_version, .. } => {
313 input.with_initial_shared_version(*start_version)
314 }
315 }
316 }
317}
318
319impl From<ObjectId> for Input {
320 fn from(object_id: ObjectId) -> Self {
321 Input::by_id(object_id)
322 }
323}
324
325pub(crate) type OptionReadableDisplay =
326 ::serde_with::As<Option<::serde_with::IfIsHumanReadable<::serde_with::DisplayFromStr>>>;