mirror of
https://github.com/jwinterm/grin-wallet.git
synced 2026-10-17 07:11:36 +02:00
simplify contract amounts
This commit is contained in:
+51
-46
@@ -1740,30 +1740,27 @@ fn set_proof_sender(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ContractNewArgs {
|
fn contract_net_change(receive: Option<u64>, send: Option<u64>) -> Result<Option<i64>, Error> {
|
||||||
fn get_net_change(&self) -> Result<i64, Error> {
|
if receive.is_some() && send.is_some() {
|
||||||
if self.receive.is_some() && self.send.is_some() {
|
return Err(Error::ArgumentError(
|
||||||
return Err(Error::ArgumentError(
|
"Can't pass both --receive and --send parameters.".into(),
|
||||||
"Can't pass both --receive and --send parameters.".into(),
|
));
|
||||||
));
|
|
||||||
}
|
|
||||||
let to_i64 = |v: u64| {
|
|
||||||
i64::try_from(v).map_err(|_| Error::ArgumentError(format!("Amount {} is too large", v)))
|
|
||||||
};
|
|
||||||
match self.receive {
|
|
||||||
None => match self.send {
|
|
||||||
None => Err(Error::ArgumentError(
|
|
||||||
"Send or receive not specified.".into(),
|
|
||||||
)),
|
|
||||||
Some(v) => Ok(-to_i64(v)?), // negative net change on send
|
|
||||||
},
|
|
||||||
Some(v) => to_i64(v), // positive net change on receive
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
let to_i64 = |v: u64| {
|
||||||
|
i64::try_from(v).map_err(|_| Error::ArgumentError(format!("Amount {} is too large", v)))
|
||||||
|
};
|
||||||
|
Ok(match (receive, send) {
|
||||||
|
(Some(value), _) => Some(to_i64(value)?),
|
||||||
|
(_, Some(value)) => Some(-to_i64(value)?),
|
||||||
|
(None, None) => None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ContractNewArgs {
|
||||||
// Create a ContractNewArgsAPI from the ContractNewArgs
|
// Create a ContractNewArgsAPI from the ContractNewArgs
|
||||||
fn to_api_args(&self) -> Result<ContractNewArgsAPI, Error> {
|
fn to_api_args(&self) -> Result<ContractNewArgsAPI, Error> {
|
||||||
let net_change = self.get_net_change()?;
|
let net_change = contract_net_change(self.receive, self.send)?
|
||||||
|
.ok_or_else(|| Error::ArgumentError("Send or receive not specified.".into()))?;
|
||||||
Ok(ContractNewArgsAPI {
|
Ok(ContractNewArgsAPI {
|
||||||
ttl_blocks: self.ttl_blocks,
|
ttl_blocks: self.ttl_blocks,
|
||||||
setup_args: ContractSetupArgsAPI {
|
setup_args: ContractSetupArgsAPI {
|
||||||
@@ -1850,42 +1847,18 @@ pub struct ContractSetupArgs {
|
|||||||
pub proof_type: Option<ProofType>,
|
pub proof_type: Option<ProofType>,
|
||||||
/// Early payment proof memo
|
/// Early payment proof memo
|
||||||
pub memo: Option<PaymentMemo>,
|
pub memo: Option<PaymentMemo>,
|
||||||
|
|
||||||
// Future features
|
|
||||||
/// Whether we should automatically sign a receive of any value
|
|
||||||
// pub auto_receive: Option<bool>,
|
|
||||||
/// Add outputs
|
|
||||||
pub add_outputs: bool, // lock outputs early
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ContractSetupArgs {
|
impl ContractSetupArgs {
|
||||||
fn get_net_change(&self) -> Result<Option<i64>, Error> {
|
|
||||||
if self.receive.is_some() && self.send.is_some() {
|
|
||||||
return Err(Error::ArgumentError(
|
|
||||||
"Can't pass both --receive and --send parameters.".into(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
let to_i64 = |v: u64| {
|
|
||||||
i64::try_from(v).map_err(|_| Error::ArgumentError(format!("Amount {} is too large", v)))
|
|
||||||
};
|
|
||||||
let net_change = match (self.receive, self.send) {
|
|
||||||
(Some(v), _) => Some(to_i64(v)?),
|
|
||||||
(_, Some(v)) => Some(-to_i64(v)?),
|
|
||||||
(None, None) => None,
|
|
||||||
};
|
|
||||||
Ok(net_change)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a ContractSetupArgsAPI from the ContractSetupArgs
|
// Create a ContractSetupArgsAPI from the ContractSetupArgs
|
||||||
fn to_api_args(&self, slate: &Slate) -> Result<ContractSetupArgsAPI, Error> {
|
fn to_api_args(&self, slate: &Slate) -> Result<ContractSetupArgsAPI, Error> {
|
||||||
let net_change = match self.get_net_change()? {
|
let net_change = match contract_net_change(self.receive, self.send)? {
|
||||||
Some(value) => Some(value),
|
Some(value) => Some(value),
|
||||||
None => initial_net_change(&slate.state, slate.amount)?,
|
None => initial_net_change(&slate.state, slate.amount)?,
|
||||||
};
|
};
|
||||||
Ok(ContractSetupArgsAPI {
|
Ok(ContractSetupArgsAPI {
|
||||||
fee_rate: self.fee_rate,
|
fee_rate: self.fee_rate,
|
||||||
net_change: net_change,
|
net_change: net_change,
|
||||||
add_outputs: self.add_outputs,
|
|
||||||
selection_args: OutputSelectionArgs {
|
selection_args: OutputSelectionArgs {
|
||||||
minimum_confirmations: self.minimum_confirmations,
|
minimum_confirmations: self.minimum_confirmations,
|
||||||
use_inputs: match self.use_inputs.as_ref() {
|
use_inputs: match self.use_inputs.as_ref() {
|
||||||
@@ -2182,6 +2155,32 @@ mod contract_tests {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn contract_amounts() {
|
||||||
|
for (receive, send, expected) in [
|
||||||
|
(None, None, None),
|
||||||
|
(Some(0), None, Some(0)),
|
||||||
|
(None, Some(0), Some(0)),
|
||||||
|
(Some(i64::MAX as u64), None, Some(i64::MAX)),
|
||||||
|
(None, Some(i64::MAX as u64), Some(-i64::MAX)),
|
||||||
|
] {
|
||||||
|
assert_eq!(contract_net_change(receive, send).unwrap(), expected);
|
||||||
|
}
|
||||||
|
let too_large = i64::MAX as u64 + 1;
|
||||||
|
for (receive, send) in [(Some(too_large), None), (None, Some(too_large))] {
|
||||||
|
assert!(matches!(
|
||||||
|
contract_net_change(receive, send),
|
||||||
|
Err(Error::ArgumentError(message))
|
||||||
|
if message == format!("Amount {} is too large", too_large)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
assert!(matches!(
|
||||||
|
contract_net_change(Some(too_large), Some(1)),
|
||||||
|
Err(Error::ArgumentError(message))
|
||||||
|
if message == "Can't pass both --receive and --send parameters."
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn contract_sign_args() {
|
fn contract_sign_args() {
|
||||||
let args = ContractSetupArgs {
|
let args = ContractSetupArgs {
|
||||||
@@ -2194,7 +2193,6 @@ mod contract_tests {
|
|||||||
minimum_confirmations: None,
|
minimum_confirmations: None,
|
||||||
fee_rate: Some(2),
|
fee_rate: Some(2),
|
||||||
outfile: None,
|
outfile: None,
|
||||||
add_outputs: false,
|
|
||||||
proof_type: Some(ProofType::Invoice),
|
proof_type: Some(ProofType::Invoice),
|
||||||
memo: Some(PaymentMemo::new("payment".into()).unwrap()),
|
memo: Some(PaymentMemo::new("payment".into()).unwrap()),
|
||||||
};
|
};
|
||||||
@@ -2212,6 +2210,7 @@ mod contract_tests {
|
|||||||
set_proof_sender(&mut api_args.proof_args, Some(&sender), Some(&fallback)).unwrap();
|
set_proof_sender(&mut api_args.proof_args, Some(&sender), Some(&fallback)).unwrap();
|
||||||
assert_eq!(api_args.fee_rate, Some(2));
|
assert_eq!(api_args.fee_rate, Some(2));
|
||||||
assert_eq!(api_args.net_change, Some(1));
|
assert_eq!(api_args.net_change, Some(1));
|
||||||
|
assert!(!api_args.add_outputs);
|
||||||
assert_eq!(api_args.proof_args.proof_type, ProofType::Invoice);
|
assert_eq!(api_args.proof_args.proof_type, ProofType::Invoice);
|
||||||
assert_eq!(api_args.proof_args.sender_address, Some(sender.pub_key));
|
assert_eq!(api_args.proof_args.sender_address, Some(sender.pub_key));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -2305,5 +2304,11 @@ mod contract_tests {
|
|||||||
Err(Error::ArgumentError(message))
|
Err(Error::ArgumentError(message))
|
||||||
if message == "Can't pass both --receive and --send parameters."
|
if message == "Can't pass both --receive and --send parameters."
|
||||||
));
|
));
|
||||||
|
invalid.receive = None;
|
||||||
|
invalid.send = None;
|
||||||
|
assert!(matches!(
|
||||||
|
invalid.to_api_args(),
|
||||||
|
Err(Error::ArgumentError(message)) if message == "Send or receive not specified."
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -452,18 +452,11 @@ where
|
|||||||
|
|
||||||
/// Compares the setup args provided at call with those in the Context and checks whether they conflict.
|
/// Compares the setup args provided at call with those in the Context and checks whether they conflict.
|
||||||
/// This is relevant to see if there's any conflict in the arguments provided at step1 with step3.
|
/// This is relevant to see if there's any conflict in the arguments provided at step1 with step3.
|
||||||
|
/// The caller resolves net_change with get_net_change before this check
|
||||||
pub fn verify_setup_args_consistency(
|
pub fn verify_setup_args_consistency(
|
||||||
ctx_setup_args: &ContractSetupArgsAPI,
|
ctx_setup_args: &ContractSetupArgsAPI,
|
||||||
cur_setup_args: &ContractSetupArgsAPI,
|
cur_setup_args: &ContractSetupArgsAPI,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Compare net_change
|
|
||||||
if ctx_setup_args.net_change.unwrap() != cur_setup_args.net_change.unwrap() {
|
|
||||||
return Err(Error::GenericError(format!(
|
|
||||||
"Inconsistent net change. Ctx net_change:{}, Current net_change: {}",
|
|
||||||
ctx_setup_args.net_change.unwrap(),
|
|
||||||
cur_setup_args.net_change.unwrap()
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
// Compare num_participants
|
// Compare num_participants
|
||||||
if ctx_setup_args.num_participants != cur_setup_args.num_participants {
|
if ctx_setup_args.num_participants != cur_setup_args.num_participants {
|
||||||
return Err(Error::GenericError(format!(
|
return Err(Error::GenericError(format!(
|
||||||
@@ -567,23 +560,14 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn fee_rate_consistency() {
|
fn fee_rate_consistency() {
|
||||||
let setup = ContractSetupArgsAPI {
|
let setup = ContractSetupArgsAPI {
|
||||||
net_change: Some(-1),
|
|
||||||
fee_rate: Some(2),
|
fee_rate: Some(2),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
assert!(verify_setup_args_consistency(&setup, &setup).is_ok());
|
assert!(verify_setup_args_consistency(&setup, &setup).is_ok());
|
||||||
assert!(verify_setup_args_consistency(
|
assert!(verify_setup_args_consistency(&setup, &ContractSetupArgsAPI::default()).is_ok());
|
||||||
&setup,
|
|
||||||
&ContractSetupArgsAPI {
|
|
||||||
net_change: Some(-1),
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.is_ok());
|
|
||||||
let err = verify_setup_args_consistency(
|
let err = verify_setup_args_consistency(
|
||||||
&setup,
|
&setup,
|
||||||
&ContractSetupArgsAPI {
|
&ContractSetupArgsAPI {
|
||||||
net_change: Some(-1),
|
|
||||||
fee_rate: Some(3),
|
fee_rate: Some(3),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1183,7 +1183,6 @@ pub fn parse_contract_setup_args(
|
|||||||
receive: receive,
|
receive: receive,
|
||||||
send: send,
|
send: send,
|
||||||
as_json: as_json,
|
as_json: as_json,
|
||||||
add_outputs: false,
|
|
||||||
use_inputs: use_inputs,
|
use_inputs: use_inputs,
|
||||||
make_outputs: make_outputs,
|
make_outputs: make_outputs,
|
||||||
minimum_confirmations,
|
minimum_confirmations,
|
||||||
|
|||||||
Reference in New Issue
Block a user