1use std::fmt::{Display, Formatter};
5
6use tabled::builder::Builder as TableBuilder;
7use tabled::settings::style::HorizontalLine;
8use tabled::settings::{Panel as TablePanel, Style as TableStyle};
9
10use crate::msgs::{
11 SuiArgument,
12 SuiCallArg,
13 SuiCommand,
14 SuiObjectArg,
15 SuiProgrammableMoveCall,
16 SuiProgrammableTransactionBlock,
17};
18
19pub struct Pretty<'a, T>(pub &'a T);
20
21impl Display for Pretty<'_, SuiProgrammableTransactionBlock> {
22 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
23 let Pretty(ptb) = self;
24 let SuiProgrammableTransactionBlock { inputs, commands } = ptb;
25 if !inputs.is_empty() {
26 let mut builder = TableBuilder::default();
27 for (i, input) in inputs.iter().enumerate() {
28 match input {
29 SuiCallArg::Pure(v) => {
30 let pure_arg = if let Some(t) = v.value_type() {
31 format!("{i:<3} Pure Arg: Type: {}, Value: {}", t, v.value())
32 } else {
33 format!("{i:<3} Pure Arg: {}", v.value())
34 };
35 builder.push_record(vec![pure_arg]);
36 }
37 SuiCallArg::Object(SuiObjectArg::ImmOrOwnedObject { object_id, .. }) => {
38 builder.push_record(vec![format!(
39 "{i:<3} Imm/Owned Object ID: {}",
40 object_id
41 )]);
42 }
43 SuiCallArg::Object(SuiObjectArg::SharedObject { object_id, .. }) => {
44 builder.push_record(vec![format!(
45 "{i:<3} Shared Object ID: {}",
46 object_id
47 )]);
48 }
49 SuiCallArg::Object(SuiObjectArg::Receiving { object_id, .. }) => {
50 builder.push_record(vec![format!(
51 "{i:<3} Receiving Object ID: {}",
52 object_id
53 )]);
54 }
55 }
56 }
57
58 let mut table = builder.build();
59 table.with(TablePanel::header("Input Objects"));
60 table.with(TableStyle::rounded().horizontals([HorizontalLine::new(
61 1,
62 TableStyle::modern().get_horizontal(),
63 )]));
64 write!(f, "\n{}", table)?;
65 } else {
66 write!(f, "\n No input objects for this transaction")?;
67 }
68
69 if !commands.is_empty() {
70 let mut builder = TableBuilder::default();
71 for (i, c) in commands.iter().enumerate() {
72 if i == commands.len() - 1 {
73 builder.push_record(vec![format!("{i:<2} {}", Pretty(c))]);
74 } else {
75 builder.push_record(vec![format!("{i:<2} {}\n", Pretty(c))]);
76 }
77 }
78 let mut table = builder.build();
79 table.with(TablePanel::header("Commands"));
80 table.with(TableStyle::rounded().horizontals([HorizontalLine::new(
81 1,
82 TableStyle::modern().get_horizontal(),
83 )]));
84 write!(f, "\n{}", table)
85 } else {
86 write!(f, "\n No commands for this transaction")
87 }
88 }
89}
90
91impl Display for Pretty<'_, SuiCommand> {
92 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
93 let Pretty(command) = self;
94 match command {
95 SuiCommand::MakeMoveVec(ty_opt, elems) => {
96 write!(f, "MakeMoveVec:\n ┌")?;
97 if let Some(ty) = ty_opt {
98 write!(f, "\n │ Type Tag: {ty}")?;
99 }
100 write!(f, "\n │ Arguments:\n │ ")?;
101 write_sep(f, elems.iter().map(Pretty), "\n │ ")?;
102 write!(f, "\n └")
103 }
104
105 SuiCommand::MoveCall(p) => write!(f, "{}", Pretty(&**p)),
106
107 SuiCommand::MergeCoins(target, coins) => {
108 write!(
109 f,
110 "MergeCoins:\n ┌\n │ Target: {}\n │ Coins: \n │ ",
111 Pretty(target)
112 )?;
113 write_sep(f, coins.iter().map(Pretty), "\n │ ")?;
114 write!(f, "\n └")
115 }
116
117 SuiCommand::SplitCoins(coin, amounts) => {
118 write!(
119 f,
120 "SplitCoins:\n ┌\n │ Coin: {}\n │ Amounts: \n │ ",
121 Pretty(coin)
122 )?;
123 write_sep(f, amounts.iter().map(Pretty), "\n │ ")?;
124 write!(f, "\n └")
125 }
126
127 SuiCommand::Publish(deps) => {
128 write!(f, "Publish:\n ┌\n │ Dependencies: \n │ ")?;
129 write_sep(f, deps, "\n │ ")?;
130 write!(f, "\n └")
131 }
132
133 SuiCommand::TransferObjects(objs, addr) => {
134 write!(f, "TransferObjects:\n ┌\n │ Arguments: \n │ ")?;
135 write_sep(f, objs.iter().map(Pretty), "\n │ ")?;
136 write!(f, "\n │ Address: {}\n └", Pretty(addr))
137 }
138
139 SuiCommand::Upgrade(deps, current_package_id, ticket) => {
140 write!(f, "Upgrade:\n ┌\n │ Dependencies: \n │ ")?;
141 write_sep(f, deps, "\n │ ")?;
142 write!(f, "\n │ Current Package ID: {current_package_id}")?;
143 write!(f, "\n │ Ticket: {}", Pretty(ticket))?;
144 write!(f, "\n └")
145 }
146 }
147 }
148}
149
150impl Display for Pretty<'_, SuiProgrammableMoveCall> {
151 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
152 let Pretty(move_call) = self;
153 let SuiProgrammableMoveCall {
154 package,
155 module,
156 function,
157 type_arguments,
158 arguments,
159 } = move_call;
160
161 write!(
162 f,
163 "MoveCall:\n ┌\n │ Function: {} \n │ Module: {}\n │ Package: {}",
164 function, module, package
165 )?;
166
167 if !type_arguments.is_empty() {
168 write!(f, "\n │ Type Arguments: \n │ ")?;
169 write_sep(f, type_arguments, "\n │ ")?;
170 }
171 if !arguments.is_empty() {
172 write!(f, "\n │ Arguments: \n │ ")?;
173 write_sep(f, arguments.iter().map(Pretty), "\n │ ")?;
174 }
175
176 write!(f, "\n └")
177 }
178}
179
180impl Display for Pretty<'_, SuiArgument> {
181 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
182 let Pretty(argument) = self;
183
184 let output = match argument {
185 SuiArgument::GasCoin => "GasCoin".to_string(),
186 SuiArgument::Input(i) => format!("Input {}", i),
187 SuiArgument::Result(i) => format!("Result {}", i),
188 SuiArgument::NestedResult(j, k) => format!("Nested Result {}: {}", j, k),
189 };
190 write!(f, "{}", output)
191 }
192}
193
194pub fn write_sep<T: Display>(
196 f: &mut Formatter<'_>,
197 items: impl IntoIterator<Item = T>,
198 sep: &str,
199) -> std::fmt::Result {
200 let mut xs = items.into_iter();
201 let Some(x) = xs.next() else {
202 return Ok(());
203 };
204 write!(f, "{x}")?;
205 for x in xs {
206 write!(f, "{sep}{x}")?;
207 }
208 Ok(())
209}