1010use anyhow:: Result ;
1111use hashi:: cli:: client:: CreateProposalParams ;
1212use hashi:: cli:: client:: build_create_proposal_transaction;
13+ use hashi:: cli:: client:: build_vote_transaction;
14+ use hashi:: cli:: upgrade:: build_execute_proposal_transaction;
15+ use hashi:: cli:: upgrade:: build_upgrade_execution_transaction;
16+ use hashi:: cli:: upgrade:: build_upgrade_package;
17+ use hashi:: cli:: upgrade:: extract_new_package_id_from_response;
18+ use hashi:: cli:: upgrade:: extract_proposal_id_from_response;
1319use hashi:: config:: HashiIds ;
14- use hashi:: sui_tx_executor:: SUI_CLOCK_OBJECT_ID ;
1520use hashi:: sui_tx_executor:: SuiTxExecutor ;
1621use std:: path:: Path ;
1722use std:: path:: PathBuf ;
1823use sui_sdk_types:: Address ;
1924use sui_sdk_types:: Identifier ;
2025use sui_sdk_types:: StructTag ;
2126use sui_sdk_types:: TypeTag ;
22- use sui_transaction_builder:: Function ;
23- use sui_transaction_builder:: ObjectInput ;
24- use sui_transaction_builder:: TransactionBuilder ;
2527
2628use crate :: TestNetworks ;
2729use crate :: sui_network:: sui_binary;
@@ -94,57 +96,6 @@ pub fn prepare_upgrade_package(test_dir: &Path, original_package_id: Address) ->
9496 Ok ( dst)
9597}
9698
97- /// Build the upgraded package and return the compiled modules + digest.
98- pub fn build_upgrade_package (
99- package_path : & Path ,
100- client_config : Option < & Path > ,
101- ) -> Result < ( sui_sdk_types:: Publish , Vec < u8 > ) > {
102- let mut cmd = std:: process:: Command :: new ( sui_binary ( ) ) ;
103- cmd. arg ( "move" ) ;
104-
105- if let Some ( config) = client_config {
106- cmd. arg ( "--client.config" ) . arg ( config) ;
107- }
108-
109- cmd. arg ( "-p" )
110- . arg ( package_path)
111- . arg ( "build" )
112- . arg ( "-e" )
113- . arg ( "testnet" )
114- . arg ( "--dump-bytecode-as-base64" ) ;
115-
116- let output = cmd. output ( ) ?;
117- anyhow:: ensure!(
118- output. status. success( ) ,
119- "sui move build failed:\n stdout: {}\n stderr: {}" ,
120- output. stdout. escape_ascii( ) ,
121- output. stderr. escape_ascii( )
122- ) ;
123-
124- #[ derive( serde:: Deserialize ) ]
125- struct MoveBuildOutput {
126- modules : Vec < String > ,
127- dependencies : Vec < Address > ,
128- digest : Vec < u8 > ,
129- }
130-
131- let build_output: MoveBuildOutput = serde_json:: from_slice ( & output. stdout ) ?;
132- let digest = build_output. digest . clone ( ) ;
133- let modules = build_output
134- . modules
135- . into_iter ( )
136- . map ( |b64| <base64ct:: Base64 as base64ct:: Encoding >:: decode_vec ( & b64) )
137- . collect :: < Result < Vec < _ > , _ > > ( ) ?;
138-
139- Ok ( (
140- sui_sdk_types:: Publish {
141- modules,
142- dependencies : build_output. dependencies ,
143- } ,
144- digest,
145- ) )
146- }
147-
14899/// Run the full upgrade lifecycle: prepare → build → propose → vote → execute+publish+finalize.
149100///
150101/// Returns the new package ID on success.
@@ -171,7 +122,7 @@ pub async fn execute_full_upgrade(networks: &mut TestNetworks) -> Result<Address
171122
172123 // 2. Build the upgrade
173124 tracing:: info!( "building upgrade package from {}" , upgrade_path. display( ) ) ;
174- let ( compiled, digest) = build_upgrade_package ( & upgrade_path, client_config) ?;
125+ let ( compiled, digest) = build_upgrade_package ( sui_binary ( ) , & upgrade_path, client_config) ?;
175126 tracing:: info!( "upgrade package built, digest: {digest:?}" ) ;
176127
177128 // 3. Propose the upgrade
@@ -189,17 +140,7 @@ pub async fn execute_full_upgrade(networks: &mut TestNetworks) -> Result<Address
189140 "create Upgrade proposal failed"
190141 ) ;
191142
192- let proposal_id = response
193- . transaction ( )
194- . events ( )
195- . events ( )
196- . iter ( )
197- . find ( |e| e. contents ( ) . name ( ) . contains ( "ProposalCreatedEvent" ) )
198- . ok_or_else ( || anyhow:: anyhow!( "ProposalCreatedEvent not found" ) )
199- . and_then ( |e| {
200- let ( id, _ts) : ( Address , u64 ) = bcs:: from_bytes ( e. contents ( ) . value ( ) ) ?;
201- Ok ( id)
202- } ) ?;
143+ let proposal_id = extract_proposal_id_from_response ( & response) ?;
203144 tracing:: info!( "upgrade proposal {proposal_id} created" ) ;
204145
205146 // 4. All other nodes vote (upgrade requires 100% quorum)
@@ -211,28 +152,8 @@ pub async fn execute_full_upgrade(networks: &mut TestNetworks) -> Result<Address
211152 ) ) ) ;
212153
213154 for executor in & mut executors[ 1 ..] {
214- let mut builder = TransactionBuilder :: new ( ) ;
215- let hashi_arg = builder. object (
216- ObjectInput :: new ( hashi_ids. hashi_object_id )
217- . as_shared ( )
218- . with_mutable ( true ) ,
219- ) ;
220- let proposal_id_arg = builder. pure ( & proposal_id) ;
221- let clock_arg = builder. object (
222- ObjectInput :: new ( SUI_CLOCK_OBJECT_ID )
223- . as_shared ( )
224- . with_mutable ( false ) ,
225- ) ;
226- builder. move_call (
227- Function :: new (
228- hashi_ids. package_id ,
229- Identifier :: from_static ( "proposal" ) ,
230- Identifier :: from_static ( "vote" ) ,
231- )
232- . with_type_args ( vec ! [ upgrade_type_tag. clone( ) ] ) ,
233- vec ! [ hashi_arg, proposal_id_arg, clock_arg] ,
234- ) ;
235- let vote_resp = executor. execute ( builder) . await ?;
155+ let vote_tx = build_vote_transaction ( hashi_ids, proposal_id, upgrade_type_tag. clone ( ) ) ;
156+ let vote_resp = executor. execute ( vote_tx) . await ?;
236157 anyhow:: ensure!(
237158 vote_resp. transaction( ) . effects( ) . status( ) . success( ) ,
238159 "vote on Upgrade proposal failed"
@@ -242,69 +163,15 @@ pub async fn execute_full_upgrade(networks: &mut TestNetworks) -> Result<Address
242163
243164 // 5. Execute upgrade + publish + finalize in one PTB
244165 tracing:: info!( "executing upgrade (execute + publish + finalize in one PTB)..." ) ;
245- let mut builder = TransactionBuilder :: new ( ) ;
246- let hashi_arg = builder. object (
247- ObjectInput :: new ( hashi_ids. hashi_object_id )
248- . as_shared ( )
249- . with_mutable ( true ) ,
250- ) ;
251- let proposal_id_arg = builder. pure ( & proposal_id) ;
252- let clock_arg = builder. object (
253- ObjectInput :: new ( SUI_CLOCK_OBJECT_ID )
254- . as_shared ( )
255- . with_mutable ( false ) ,
256- ) ;
257-
258- // Step A: upgrade::execute → UpgradeTicket
259- let ticket = builder. move_call (
260- Function :: new (
261- hashi_ids. package_id ,
262- Identifier :: from_static ( "upgrade" ) ,
263- Identifier :: from_static ( "execute" ) ,
264- ) ,
265- vec ! [ hashi_arg, proposal_id_arg, clock_arg] ,
266- ) ;
267-
268- // Step B: publish upgrade → UpgradeReceipt
269- let receipt = builder. upgrade (
270- compiled. modules ,
271- compiled. dependencies ,
272- hashi_ids. package_id ,
273- ticket,
274- ) ;
275-
276- // Step C: finalize_upgrade
277- let hashi_arg2 = builder. object (
278- ObjectInput :: new ( hashi_ids. hashi_object_id )
279- . as_shared ( )
280- . with_mutable ( true ) ,
281- ) ;
282- builder. move_call (
283- Function :: new (
284- hashi_ids. package_id ,
285- Identifier :: from_static ( "upgrade" ) ,
286- Identifier :: from_static ( "finalize_upgrade" ) ,
287- ) ,
288- vec ! [ hashi_arg2, receipt] ,
289- ) ;
290-
291- let upgrade_resp = executors[ 0 ] . execute ( builder) . await ?;
166+ let upgrade_tx = build_upgrade_execution_transaction ( hashi_ids, proposal_id, compiled) ;
167+ let upgrade_resp = executors[ 0 ] . execute ( upgrade_tx) . await ?;
292168 anyhow:: ensure!(
293169 upgrade_resp. transaction( ) . effects( ) . status( ) . success( ) ,
294170 "upgrade execute+publish+finalize failed: {:?}" ,
295171 upgrade_resp. transaction( ) . effects( ) . status( )
296172 ) ;
297173
298- let new_package_id = upgrade_resp
299- . transaction ( )
300- . effects ( )
301- . changed_objects ( )
302- . iter ( )
303- . find ( |o| o. object_type ( ) == "package" )
304- . ok_or_else ( || anyhow:: anyhow!( "new package not found in upgrade effects" ) ) ?
305- . object_id ( )
306- . parse :: < Address > ( ) ?;
307-
174+ let new_package_id = extract_new_package_id_from_response ( & upgrade_resp) ?;
308175 tracing:: info!( "upgrade complete! new package: {new_package_id}" ) ;
309176 Ok ( new_package_id)
310177}
@@ -333,17 +200,7 @@ pub async fn disable_version(
333200 "create DisableVersion proposal failed"
334201 ) ;
335202
336- let proposal_id = response
337- . transaction ( )
338- . events ( )
339- . events ( )
340- . iter ( )
341- . find ( |e| e. contents ( ) . name ( ) . contains ( "ProposalCreatedEvent" ) )
342- . ok_or_else ( || anyhow:: anyhow!( "ProposalCreatedEvent not found" ) )
343- . and_then ( |e| {
344- let ( id, _ts) : ( Address , u64 ) = bcs:: from_bytes ( e. contents ( ) . value ( ) ) ?;
345- Ok ( id)
346- } ) ?;
203+ let proposal_id = extract_proposal_id_from_response ( & response) ?;
347204
348205 let disable_version_type = TypeTag :: Struct ( Box :: new ( StructTag :: new (
349206 hashi_ids. package_id ,
@@ -353,55 +210,21 @@ pub async fn disable_version(
353210 ) ) ) ;
354211
355212 for executor in & mut executors[ 1 ..] {
356- let mut builder = TransactionBuilder :: new ( ) ;
357- let hashi_arg = builder. object (
358- ObjectInput :: new ( hashi_ids. hashi_object_id )
359- . as_shared ( )
360- . with_mutable ( true ) ,
361- ) ;
362- let proposal_id_arg = builder. pure ( & proposal_id) ;
363- let clock_arg = builder. object (
364- ObjectInput :: new ( SUI_CLOCK_OBJECT_ID )
365- . as_shared ( )
366- . with_mutable ( false ) ,
367- ) ;
368- builder. move_call (
369- Function :: new (
370- hashi_ids. package_id ,
371- Identifier :: from_static ( "proposal" ) ,
372- Identifier :: from_static ( "vote" ) ,
373- )
374- . with_type_args ( vec ! [ disable_version_type. clone( ) ] ) ,
375- vec ! [ hashi_arg, proposal_id_arg, clock_arg] ,
376- ) ;
377- let vote_resp = executor. execute ( builder) . await ?;
213+ let vote_tx = build_vote_transaction ( hashi_ids, proposal_id, disable_version_type. clone ( ) ) ;
214+ let vote_resp = executor. execute ( vote_tx) . await ?;
378215 anyhow:: ensure!(
379216 vote_resp. transaction( ) . effects( ) . status( ) . success( ) ,
380217 "vote on DisableVersion proposal failed"
381218 ) ;
382219 }
383220
384- let mut builder = TransactionBuilder :: new ( ) ;
385- let hashi_arg = builder. object (
386- ObjectInput :: new ( hashi_ids. hashi_object_id )
387- . as_shared ( )
388- . with_mutable ( true ) ,
389- ) ;
390- let proposal_id_arg = builder. pure ( & proposal_id) ;
391- let clock_arg = builder. object (
392- ObjectInput :: new ( SUI_CLOCK_OBJECT_ID )
393- . as_shared ( )
394- . with_mutable ( false ) ,
395- ) ;
396- builder. move_call (
397- Function :: new (
398- execute_package_id,
399- Identifier :: from_static ( "disable_version" ) ,
400- Identifier :: from_static ( "execute" ) ,
401- ) ,
402- vec ! [ hashi_arg, proposal_id_arg, clock_arg] ,
403- ) ;
404- let exec_resp = executors[ 0 ] . execute ( builder) . await ?;
221+ let execute_tx = build_execute_proposal_transaction (
222+ hashi_ids,
223+ proposal_id,
224+ execute_package_id,
225+ "disable_version" ,
226+ ) ?;
227+ let exec_resp = executors[ 0 ] . execute ( execute_tx) . await ?;
405228 anyhow:: ensure!(
406229 exec_resp. transaction( ) . effects( ) . status( ) . success( ) ,
407230 "execute DisableVersion proposal failed"
0 commit comments