diff --git a/controller/tests/contract_self_spend_custom.rs b/controller/tests/contract_self_spend_custom.rs index 2bd51ee..6ab7637 100644 --- a/controller/tests/contract_self_spend_custom.rs +++ b/controller/tests/contract_self_spend_custom.rs @@ -137,7 +137,7 @@ fn contract_self_spend_custom_tx_impl(test_dir: &'static str) -> Result<(), libw assert_eq!( commits[15].output.value, 3 * consensus::REWARD - - selection_args.sum_output_amounts() + - selection_args.sum_output_amounts()? - my_fee_contribution(3, 6, 1, 1)?.fee() ); Ok(()) diff --git a/libwallet/src/contract/selection.rs b/libwallet/src/contract/selection.rs index 0d15e4b..2a740f9 100644 --- a/libwallet/src/contract/selection.rs +++ b/libwallet/src/contract/selection.rs @@ -92,7 +92,7 @@ where // Σmy_inputs >= Σmy_outputs + my_fee_cost // Each party later balances the equation by adding an additional output (change output or receiver output) let net_change = setup_args.net_change.unwrap(); - let custom_outputs_amount_sum = setup_args.selection_args.sum_output_amounts(); + let custom_outputs_amount_sum = setup_args.selection_args.sum_output_amounts()?; let pay_amount = if net_change < 0 { net_change.abs() as u64 } else { @@ -260,7 +260,7 @@ fn build_output_amount_list( setup_args: &ContractSetupArgsAPI, ) -> Result, Error> { let expected_net_change = setup_args.net_change.unwrap(); - let mut my_output_amounts = setup_args.selection_args.output_amounts(); + let mut my_output_amounts = setup_args.selection_args.output_amounts()?; let custom_outputs_sum = my_output_amounts.iter().sum::(); // We know that `Σmy_inputs >= Σmy_outputs + my_fee_cost` holds so we balance the equation by adding // an additional output holding the missing amount (change output or receiver output) diff --git a/libwallet/src/contract/types.rs b/libwallet/src/contract/types.rs index fe34dc1..1c21668 100644 --- a/libwallet/src/contract/types.rs +++ b/libwallet/src/contract/types.rs @@ -14,6 +14,7 @@ //! Types related to a contract +use crate::error::Error; use crate::grin_core::consensus; use crate::slate_versions::ser as dalek_ser; use ed25519_dalek::PublicKey as DalekPublicKey; @@ -49,25 +50,32 @@ impl OutputSelectionArgs { } } /// Returns the outputs we have to create - pub fn output_amounts(&self) -> Vec { - if self.make_outputs.is_some() { - let output_amounts: Vec = self.make_outputs.as_ref().unwrap()[..] + // TODO: move consensus code outside of here. Consider turning make_outputs to Vec + pub fn output_amounts(&self) -> Result, Error> { + match self.make_outputs.as_ref() { + Some(s) => s .split(",") - // TODO: move consensus code outside of here. Consider turning make_outputs to Vec - .map(|amt| (amt.parse::().unwrap() * consensus::GRIN_BASE as f64) as u64) - .collect(); - output_amounts - } else { - vec![] + .map(|amt| { + amt.parse::() + .map(|g| (g * consensus::GRIN_BASE as f64) as u64) + .map_err(|e| { + Error::GenericError(format!("Invalid output amount '{}': {}", amt, e)) + }) + }) + .collect(), + None => Ok(vec![]), } } /// Returns the sum of our output amounts - pub fn sum_output_amounts(&self) -> u64 { - self.output_amounts().iter().sum() + pub fn sum_output_amounts(&self) -> Result { + Ok(self.output_amounts()?.iter().sum()) } - /// Returns the number of custom outputs + /// Returns the number of custom outputs (count only; does not parse the amounts) pub fn num_custom_outputs(&self) -> usize { - self.output_amounts().len() + self.make_outputs + .as_ref() + .map(|s| s.split(",").count()) + .unwrap_or(0) } // TODO: make sure to validate this: if custom outputs are specified, it has to be a payjoin.