Skip to content

Commit e3021a3

Browse files
committed
Add more address balance transfer helpers to test tx builder
1 parent 28dd2b8 commit e3021a3

File tree

5 files changed

+145
-142
lines changed

5 files changed

+145
-142
lines changed

crates/sui-core/src/unit_tests/coin_deny_list_tests.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use move_core_types::identifier::Identifier;
1010
use move_core_types::language_storage::{StructTag, TypeTag};
1111
use std::sync::Arc;
1212
use sui_protocol_config::{Chain, PerObjectCongestionControlMode, ProtocolConfig, ProtocolVersion};
13-
use sui_test_transaction_builder::TestTransactionBuilder;
13+
use sui_test_transaction_builder::{FundSource, TestTransactionBuilder};
1414
use sui_types::base_types::{ObjectID, ObjectRef, SuiAddress, dbg_addr};
1515
use sui_types::crypto::{AccountKeyPair, get_account_key_pair};
1616
use sui_types::deny_list_v1::{CoinDenyCap, RegulatedCoinMetadata};
@@ -238,7 +238,11 @@ async fn test_regulated_coin_v2_funds_withdraw_deny() {
238238
env_gas_ref,
239239
env.authority.reference_gas_price_for_testing().unwrap(),
240240
)
241-
.transfer_funds_to_address_balance(100_000_000, regulated_coin_type.clone(), denied_address)
241+
.transfer_funds_to_address_balance(
242+
FundSource::address_fund(),
243+
vec![(100_000_000, denied_address)],
244+
regulated_coin_type.clone(),
245+
)
242246
.build_and_sign(&env.keypair);
243247
let effects = send_and_confirm_transaction_(&env.authority, None, tx, true)
244248
.await

crates/sui-e2e-tests/tests/address_balance_tests.rs

Lines changed: 14 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ use sui_keys::keystore::AccountKeystore;
99
use sui_macros::*;
1010
use sui_protocol_config::{ProtocolConfig, ProtocolVersion};
1111
use sui_sdk::wallet_context::WalletContext;
12-
use sui_test_transaction_builder::TestTransactionBuilder;
12+
use sui_test_transaction_builder::{FundSource, TestTransactionBuilder};
1313
use sui_types::{
1414
SUI_ACCUMULATOR_ROOT_OBJECT_ID, SUI_FRAMEWORK_PACKAGE_ID,
1515
accumulator_metadata::AccumulatorOwner,
1616
accumulator_root::{AccumulatorValue, U128},
1717
balance::Balance,
18-
base_types::{ObjectID, ObjectRef, SuiAddress},
18+
base_types::{ObjectID, ObjectRef, SuiAddress, dbg_addr},
1919
digests::{ChainIdentifier, CheckpointDigest},
2020
effects::{InputConsensusObject, TransactionEffectsAPI},
2121
gas::GasCostSummary,
@@ -364,7 +364,7 @@ async fn test_multiple_settlement_txns() {
364364
.map(|_| (1u64, SuiAddress::random_for_testing_only()))
365365
.collect::<Vec<_>>();
366366

367-
let tx = make_send_to_multi_account_tx(&amounts_and_recipients, sender, gas, rgp);
367+
let tx = make_send_to_multi_account_tx(amounts_and_recipients.clone(), sender, gas, rgp);
368368

369369
let res = test_cluster.sign_and_execute_transaction(&tx).await;
370370
let gas = res.effects.unwrap().gas_object().reference.to_object_ref();
@@ -644,37 +644,12 @@ fn withdraw_from_balance_tx_with_reservation(
644644
gas: ObjectRef,
645645
rgp: u64,
646646
) -> TransactionData {
647-
let mut builder = ProgrammableTransactionBuilder::new();
648-
649-
// Add withdraw reservation
650-
let withdraw_arg = sui_types::transaction::FundsWithdrawalArg::balance_from_sender(
651-
reservation_amount,
652-
sui_types::type_input::TypeInput::from(sui_types::gas_coin::GAS::type_tag()),
653-
);
654-
let withdraw_arg = builder.funds_withdrawal(withdraw_arg).unwrap();
655-
656-
let amount_arg = builder.pure(U256::from(amount)).unwrap();
657-
658-
let split_withdraw_arg = builder.programmable_move_call(
659-
SUI_FRAMEWORK_PACKAGE_ID,
660-
Identifier::new("funds_accumulator").unwrap(),
661-
Identifier::new("withdrawal_split").unwrap(),
662-
vec!["0x2::balance::Balance<0x2::sui::SUI>".parse().unwrap()],
663-
vec![withdraw_arg, amount_arg],
664-
);
665-
666-
let coin = builder.programmable_move_call(
667-
SUI_FRAMEWORK_PACKAGE_ID,
668-
Identifier::new("coin").unwrap(),
669-
Identifier::new("redeem_funds").unwrap(),
670-
vec!["0x2::sui::SUI".parse().unwrap()],
671-
vec![split_withdraw_arg],
672-
);
673-
674-
builder.transfer_arg(sender, coin);
675-
676-
let tx = TransactionKind::ProgrammableTransaction(builder.finish());
677-
TransactionData::new(tx, sender, gas, 10000000, rgp)
647+
TestTransactionBuilder::new(sender, gas, rgp)
648+
.transfer_sui_to_address_balance(
649+
FundSource::address_fund_with_reservation(reservation_amount),
650+
vec![(amount, dbg_addr(2))],
651+
)
652+
.build()
678653
}
679654

680655
fn make_send_to_account_tx(
@@ -684,39 +659,18 @@ fn make_send_to_account_tx(
684659
gas: ObjectRef,
685660
rgp: u64,
686661
) -> TransactionData {
687-
make_send_to_multi_account_tx(&[(amount, recipient)], sender, gas, rgp)
662+
make_send_to_multi_account_tx(vec![(amount, recipient)], sender, gas, rgp)
688663
}
689664

690665
fn make_send_to_multi_account_tx(
691-
amounts_and_recipients: &[(u64, SuiAddress)],
666+
amounts_and_recipients: Vec<(u64, SuiAddress)>,
692667
sender: SuiAddress,
693668
gas: ObjectRef,
694669
rgp: u64,
695670
) -> TransactionData {
696-
let mut builder = ProgrammableTransactionBuilder::new();
697-
698-
for (amount, recipient) in amounts_and_recipients {
699-
let amount_arg = builder.pure(*amount).unwrap();
700-
let recipient_arg = builder.pure(recipient).unwrap();
701-
let coin = builder.command(Command::SplitCoins(Argument::GasCoin, vec![amount_arg]));
702-
703-
let Argument::Result(coin_idx) = coin else {
704-
panic!("coin is not a result");
705-
};
706-
707-
let coin = Argument::NestedResult(coin_idx, 0);
708-
709-
builder.programmable_move_call(
710-
SUI_FRAMEWORK_PACKAGE_ID,
711-
Identifier::new("coin").unwrap(),
712-
Identifier::new("send_funds").unwrap(),
713-
vec!["0x2::sui::SUI".parse().unwrap()],
714-
vec![coin, recipient_arg],
715-
);
716-
}
717-
718-
let tx = TransactionKind::ProgrammableTransaction(builder.finish());
719-
TransactionData::new(tx, sender, gas, 10000000, rgp)
671+
TestTransactionBuilder::new(sender, gas, rgp)
672+
.transfer_sui_to_address_balance(FundSource::coin(gas), amounts_and_recipients)
673+
.build()
720674
}
721675

722676
#[sim_test]

crates/sui-test-transaction-builder/src/lib.rs

Lines changed: 125 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// SPDX-License-Identifier: Apache-2.0
33

44
use move_core_types::ident_str;
5+
use move_core_types::u256::U256;
56
use shared_crypto::intent::{Intent, IntentMessage};
67
use std::path::PathBuf;
78
use sui_genesis_builder::validator_info::GenesisValidatorMetadata;
@@ -10,23 +11,52 @@ use sui_sdk::rpc_types::{
1011
SuiObjectDataOptions, SuiTransactionBlockEffectsAPI, SuiTransactionBlockResponse,
1112
};
1213
use sui_sdk::wallet_context::WalletContext;
13-
use sui_types::SUI_RANDOMNESS_STATE_OBJECT_ID;
14+
use sui_types::balance::Balance;
1415
use sui_types::base_types::{FullObjectRef, ObjectID, ObjectRef, SequenceNumber, SuiAddress};
1516
use sui_types::crypto::{AccountKeyPair, Signature, Signer, get_key_pair};
1617
use sui_types::digests::TransactionDigest;
1718
use sui_types::gas_coin::GAS;
1819
use sui_types::multisig::{BitmapUnit, MultiSig, MultiSigPublicKey};
1920
use sui_types::multisig_legacy::{MultiSigLegacy, MultiSigPublicKeyLegacy};
2021
use sui_types::object::Owner;
22+
use sui_types::programmable_transaction_builder::ProgrammableTransactionBuilder;
2123
use sui_types::signature::GenericSignature;
2224
use sui_types::sui_system_state::SUI_SYSTEM_MODULE_NAME;
2325
use sui_types::transaction::{
24-
CallArg, DEFAULT_VALIDATOR_GAS_PRICE, ObjectArg, ProgrammableTransaction,
25-
SharedObjectMutability, TEST_ONLY_GAS_UNIT_FOR_HEAVY_COMPUTATION_STORAGE,
26-
TEST_ONLY_GAS_UNIT_FOR_TRANSFER, Transaction, TransactionData,
26+
Argument, CallArg, DEFAULT_VALIDATOR_GAS_PRICE, FundsWithdrawalArg, ObjectArg,
27+
ProgrammableTransaction, SharedObjectMutability,
28+
TEST_ONLY_GAS_UNIT_FOR_HEAVY_COMPUTATION_STORAGE, TEST_ONLY_GAS_UNIT_FOR_TRANSFER, Transaction,
29+
TransactionData,
2730
};
31+
use sui_types::{Identifier, SUI_FRAMEWORK_PACKAGE_ID, SUI_RANDOMNESS_STATE_OBJECT_ID};
2832
use sui_types::{SUI_SYSTEM_PACKAGE_ID, TypeTag};
2933

34+
#[derive(Clone)]
35+
pub enum FundSource {
36+
Coin(ObjectRef),
37+
AddressFund {
38+
/// If None, it will be set the same as the total transfer amount.
39+
reservation: Option<u64>,
40+
},
41+
// TODO: Add object fund source
42+
}
43+
44+
impl FundSource {
45+
pub fn coin(coin: ObjectRef) -> Self {
46+
Self::Coin(coin)
47+
}
48+
49+
pub fn address_fund() -> Self {
50+
Self::AddressFund { reservation: None }
51+
}
52+
53+
pub fn address_fund_with_reservation(reservation: u64) -> Self {
54+
Self::AddressFund {
55+
reservation: Some(reservation),
56+
}
57+
}
58+
}
59+
3060
pub struct TestTransactionBuilder {
3161
test_data: TestTransactionData,
3262
sender: SuiAddress,
@@ -295,27 +325,31 @@ impl TestTransactionBuilder {
295325
self
296326
}
297327

298-
pub fn transfer_sui_to_address_balance(mut self, amount: u64, recipient: SuiAddress) -> Self {
328+
pub fn transfer_sui_to_address_balance(
329+
mut self,
330+
source: FundSource,
331+
amounts_and_recipients: Vec<(u64, SuiAddress)>,
332+
) -> Self {
299333
self.test_data =
300334
TestTransactionData::TransferFundsToAddressBalance(TransferFundsToAddressBalanceData {
301-
amount,
335+
source,
336+
amounts_and_recipients,
302337
type_arg: GAS::type_tag(),
303-
recipient,
304338
});
305339
self
306340
}
307341

308342
pub fn transfer_funds_to_address_balance(
309343
mut self,
310-
amount: u64,
344+
source: FundSource,
345+
amounts_and_recipients: Vec<(u64, SuiAddress)>,
311346
type_arg: TypeTag,
312-
recipient: SuiAddress,
313347
) -> Self {
314348
self.test_data =
315349
TestTransactionData::TransferFundsToAddressBalance(TransferFundsToAddressBalanceData {
316-
amount,
350+
source,
351+
amounts_and_recipients,
317352
type_arg,
318-
recipient,
319353
});
320354
self
321355
}
@@ -395,17 +429,87 @@ impl TestTransactionBuilder {
395429
self.gas_price,
396430
),
397431
TestTransactionData::TransferFundsToAddressBalance(data) => {
398-
TransactionData::new_transfer_funds_to_address_balance(
399-
data.recipient,
432+
let mut builder = ProgrammableTransactionBuilder::new();
433+
let source = match data.source.clone() {
434+
FundSource::Coin(coin) => {
435+
if coin == self.gas_object {
436+
Argument::GasCoin
437+
} else {
438+
builder.obj(ObjectArg::ImmOrOwnedObject(coin)).unwrap()
439+
}
440+
}
441+
FundSource::AddressFund { reservation } => {
442+
let reservation = reservation.unwrap_or_else(|| {
443+
data.amounts_and_recipients
444+
.iter()
445+
.map(|(amount, _)| *amount)
446+
.sum::<u64>()
447+
});
448+
builder
449+
.funds_withdrawal(FundsWithdrawalArg::balance_from_sender(
450+
reservation,
451+
data.type_arg.clone().into(),
452+
))
453+
.unwrap()
454+
}
455+
};
456+
for (amount, recipient) in data.amounts_and_recipients {
457+
let balance = match data.source.clone() {
458+
FundSource::Coin(_) => {
459+
let amount_arg = builder.pure(amount).unwrap();
460+
let coin = builder.programmable_move_call(
461+
SUI_FRAMEWORK_PACKAGE_ID,
462+
Identifier::new("coin").unwrap(),
463+
Identifier::new("split").unwrap(),
464+
vec![data.type_arg.clone()],
465+
vec![source, amount_arg],
466+
);
467+
builder.programmable_move_call(
468+
SUI_FRAMEWORK_PACKAGE_ID,
469+
Identifier::new("coin").unwrap(),
470+
Identifier::new("into_balance").unwrap(),
471+
vec![data.type_arg.clone()],
472+
vec![coin],
473+
)
474+
}
475+
FundSource::AddressFund { .. } => {
476+
let amount_arg = builder.pure(U256::from(amount)).unwrap();
477+
let split = builder.programmable_move_call(
478+
SUI_FRAMEWORK_PACKAGE_ID,
479+
Identifier::new("funds_accumulator").unwrap(),
480+
Identifier::new("withdrawal_split").unwrap(),
481+
vec![Balance::type_tag(data.type_arg.clone())],
482+
vec![source, amount_arg],
483+
);
484+
builder.programmable_move_call(
485+
SUI_FRAMEWORK_PACKAGE_ID,
486+
Identifier::new("balance").unwrap(),
487+
Identifier::new("redeem_funds").unwrap(),
488+
vec![data.type_arg.clone()],
489+
vec![split],
490+
)
491+
}
492+
};
493+
494+
let recipient_arg = builder.pure(recipient).unwrap();
495+
builder.programmable_move_call(
496+
SUI_FRAMEWORK_PACKAGE_ID,
497+
Identifier::new("balance").unwrap(),
498+
Identifier::new("send_funds").unwrap(),
499+
vec![data.type_arg.clone()],
500+
vec![balance, recipient_arg],
501+
);
502+
}
503+
let pt = builder.finish();
504+
TransactionData::new_programmable(
400505
self.sender,
401-
data.amount,
402-
data.type_arg,
403-
self.gas_object,
404-
self.gas_budget
405-
.unwrap_or(self.gas_price * TEST_ONLY_GAS_UNIT_FOR_TRANSFER),
506+
vec![self.gas_object],
507+
pt,
508+
self.gas_budget.unwrap_or(
509+
self.gas_price * TEST_ONLY_GAS_UNIT_FOR_HEAVY_COMPUTATION_STORAGE,
510+
),
406511
self.gas_price,
407512
)
408-
.unwrap()
409513
}
410514
TestTransactionData::SplitCoin(data) => TransactionData::new_split_coin(
411515
self.sender,
@@ -548,9 +652,9 @@ struct TransferSuiData {
548652
}
549653

550654
struct TransferFundsToAddressBalanceData {
551-
amount: u64,
655+
source: FundSource,
656+
amounts_and_recipients: Vec<(u64, SuiAddress)>,
552657
type_arg: TypeTag,
553-
recipient: SuiAddress,
554658
}
555659

556660
struct SplitCoinData {

0 commit comments

Comments
 (0)