Implement fee inclusive transactions (#657)

* Add amount_includes_fee option in TX building

* Add --amount_includes_fee CLI option

* Implement send 'max' amount

Co-authored-by: cliik <cliik@example.com>
This commit is contained in:
cliik
2022-07-26 09:15:53 +00:00
committed by GitHub
parent 7b1eab62b1
commit ef3fadbd24
10 changed files with 270 additions and 17 deletions
+17 -4
View File
@@ -322,6 +322,8 @@ where
#[derive(Clone)]
pub struct SendArgs {
pub amount: u64,
pub amount_includes_fee: bool,
pub use_max_amount: bool,
pub minimum_confirmations: u64,
pub selection_strategy: String,
pub estimate_selection_strategies: bool,
@@ -353,6 +355,15 @@ where
K: keychain::Keychain + 'static,
{
let mut slate = Slate::blank(2, false);
let mut amount = args.amount;
if args.use_max_amount {
controller::owner_single_use(None, keychain_mask, Some(owner_api), |api, m| {
let (_, wallet_info) =
api.retrieve_summary_info(m, true, args.minimum_confirmations)?;
amount = wallet_info.amount_currently_spendable;
Ok(())
})?;
};
controller::owner_single_use(None, keychain_mask, Some(owner_api), |api, m| {
if args.estimate_selection_strategies {
let strategies = vec!["smallest", "all"]
@@ -360,7 +371,8 @@ where
.map(|strategy| {
let init_args = InitTxArgs {
src_acct_name: None,
amount: args.amount,
amount: amount,
amount_includes_fee: Some(args.amount_includes_fee),
minimum_confirmations: args.minimum_confirmations,
max_outputs: args.max_outputs as u32,
num_change_outputs: args.change_outputs as u32,
@@ -372,12 +384,13 @@ where
Ok((strategy, slate.amount, slate.fee_fields))
})
.collect::<Result<Vec<_>, grin_wallet_libwallet::Error>>()?;
display::estimate(args.amount, strategies, dark_scheme);
display::estimate(amount, strategies, dark_scheme);
return Ok(());
} else {
let init_args = InitTxArgs {
src_acct_name: None,
amount: args.amount,
amount: amount,
amount_includes_fee: Some(args.amount_includes_fee),
minimum_confirmations: args.minimum_confirmations,
max_outputs: args.max_outputs as u32,
num_change_outputs: args.change_outputs as u32,
@@ -394,7 +407,7 @@ where
Ok(s) => {
info!(
"Tx created: {} grin to {} (strategy '{}')",
core::amount_to_hr_string(args.amount, false),
core::amount_to_hr_string(amount, false),
args.dest,
args.selection_strategy,
);
+41
View File
@@ -354,6 +354,47 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), libwallet::Error>
Ok(())
})?;
// try to send a transaction with amount inclusive of fees, but amount too
// small to cover fees. Should fail.
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |sender_api, m| {
// note this will increment the block count as part of the transaction "Posting"
let args = InitTxArgs {
src_acct_name: None,
amount: 1,
amount_includes_fee: Some(true),
minimum_confirmations: 2,
max_outputs: 500,
num_change_outputs: 1,
selection_strategy_is_use_all: true,
..Default::default()
};
let res = sender_api.init_send_tx(m, args);
assert!(res.is_err());
Ok(())
})?;
// try to build a transaction with amount inclusive of fees. Confirm that tx
// amount + fee is equal to the originally specified amount
let amount = 60_000_000_000;
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |sender_api, m| {
// note this will increment the block count as part of the transaction "Posting"
let args = InitTxArgs {
src_acct_name: None,
amount: amount,
amount_includes_fee: Some(true),
minimum_confirmations: 2,
max_outputs: 500,
num_change_outputs: 1,
selection_strategy_is_use_all: true,
..Default::default()
};
let slate_i = sender_api.init_send_tx(m, args)?;
assert_eq!(slate_i.state, SlateState::Standard1);
let total_spend: u64 = slate_i.amount + slate_i.fee_fields.fee();
assert_eq!(amount, total_spend);
Ok(())
})?;
// let logging finish
stopper.store(false, Ordering::Relaxed);
thread::sleep(Duration::from_millis(200));