diff --git a/crates/iota-transactional-test-runner/src/args.rs b/crates/iota-transactional-test-runner/src/args.rs index 5cb60c093ce..a2a4e5267bc 100644 --- a/crates/iota-transactional-test-runner/src/args.rs +++ b/crates/iota-transactional-test-runner/src/args.rs @@ -105,11 +105,15 @@ pub struct ConsensusCommitPrologueCommand { pub struct ProgrammableTransactionCommand { #[arg(long)] pub sender: Option, - #[arg(long)] + #[clap(long = "sponsor")] + pub sponsor: Option, + #[arg(long = "gas-budget")] pub gas_budget: Option, #[arg(long)] pub gas_price: Option, - #[arg(long)] + #[clap(long = "gas-payment", value_parser = parse_fake_id)] + pub gas_payment: Option, + #[arg(long = "dev-inspect")] pub dev_inspect: bool, #[arg( long, diff --git a/crates/iota-transactional-test-runner/src/test_adapter.rs b/crates/iota-transactional-test-runner/src/test_adapter.rs index a14230ed8a0..33ea17ae301 100644 --- a/crates/iota-transactional-test-runner/src/test_adapter.rs +++ b/crates/iota-transactional-test-runner/src/test_adapter.rs @@ -62,7 +62,7 @@ use iota_types::{ Argument, CallArg, Command, ProgrammableTransaction, Transaction, TransactionData, TransactionDataAPI, TransactionKind, VerifiedTransaction, }, - utils::to_sender_signed_transaction, + utils::{to_sender_signed_transaction, to_sender_signed_transaction_with_multi_signers}, }; use move_binary_format::CompiledModule; use move_bytecode_utils::module_cache::GetModule; @@ -748,8 +748,10 @@ impl MoveTestAdapter<'_> for IotaTestAdapter { } IotaSubcommand::ProgrammableTransaction(ProgrammableTransactionCommand { sender, + sponsor, gas_budget, gas_price, + gas_payment, dev_inspect, inputs, }) => { @@ -795,15 +797,21 @@ impl MoveTestAdapter<'_> for IotaTestAdapter { let summary = if !dev_inspect { let gas_budget = gas_budget.unwrap_or(DEFAULT_GAS_BUDGET); let gas_price = gas_price.unwrap_or(self.gas_price); - let transaction = self.sign_txn(sender, |sender, gas| { - TransactionData::new_programmable( - sender, - vec![gas], - ProgrammableTransaction { inputs, commands }, - gas_budget, - gas_price, - ) - }); + let transaction = self.sign_sponsor_txn( + sender, + sponsor, + gas_payment, + |sender, sponsor, gas| { + TransactionData::new_programmable_allow_sponsor( + sender, + vec![gas], + ProgrammableTransaction { inputs, commands }, + gas_budget, + gas_price, + sponsor, + ) + }, + ); self.execute_txn(transaction).await? } else { assert!( @@ -1387,13 +1395,49 @@ impl IotaTestAdapter { ObjectRef, ) -> TransactionData, ) -> Transaction { - let test_account = self.get_sender(sender); - let gas_payment = self - .get_object(&test_account.gas, None) + self.sign_sponsor_txn(sender, None, None, move |sender, _, gas| { + txn_data(sender, gas) + }) + } + + fn sign_sponsor_txn( + &self, + sender: Option, + sponsor: Option, + payment: Option, + txn_data: impl FnOnce( + // sender + IotaAddress, + // sponsor + IotaAddress, + // gas + ObjectRef, + ) -> TransactionData, + ) -> Transaction { + let sender = self.get_sender(sender); + let sponsor = sponsor.map_or(sender, |a| self.get_sender(Some(a))); + + let payment = if let Some(payment) = payment { + self.fake_to_real_object_id(payment) + .expect("Could not find specified payment object") + } else { + sponsor.gas + }; + + let payment_ref = self + .get_object(&payment, None) .unwrap() .compute_object_reference(); - let data = txn_data(test_account.address, gas_payment); - to_sender_signed_transaction(data, &test_account.key_pair) + + let data = txn_data(sender.address, sponsor.address, payment_ref); + if sender.address == sponsor.address { + to_sender_signed_transaction(data, &sender.key_pair) + } else { + to_sender_signed_transaction_with_multi_signers( + data, + vec![&sender.key_pair, &sponsor.key_pair], + ) + } } fn get_sender(&self, sender: Option) -> &TestAccount {