use std::str::FromStr;
use iota_sdk::{
client::api::input_selection::{Error, InputSelection, Requirement},
types::block::{
address::{Address, AliasAddress, Bech32Address, NftAddress},
output::{AliasId, NftId},
protocol::protocol_parameters,
},
};
use crate::client::{
addresses, build_inputs, build_outputs, is_remainder_or_return, unsorted_eq,
Build::{Alias, Basic, Nft},
ALIAS_ID_0, ALIAS_ID_1, BECH32_ADDRESS_ALIAS_1, BECH32_ADDRESS_ED25519_0, BECH32_ADDRESS_ED25519_1,
BECH32_ADDRESS_NFT_1, BECH32_ADDRESS_REMAINDER, NFT_ID_0, NFT_ID_1,
};
#[test]
fn input_amount_equal_output_amount() {
let protocol_parameters = protocol_parameters();
let inputs = build_inputs([Basic(
1_000_000,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
None,
None,
)]);
let outputs = build_outputs([Basic(
1_000_000,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
None,
None,
)]);
let selected = InputSelection::new(
inputs.clone(),
outputs.clone(),
addresses([BECH32_ADDRESS_ED25519_0]),
protocol_parameters,
)
.select()
.unwrap();
assert!(unsorted_eq(&selected.inputs, &inputs));
assert!(unsorted_eq(&selected.outputs, &outputs));
}
#[test]
fn input_amount_lower_than_output_amount() {
let protocol_parameters = protocol_parameters();
let inputs = build_inputs([Basic(
1_000_000,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
None,
None,
)]);
let outputs = build_outputs([Basic(
2_000_000,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
None,
None,
)]);
let selected = InputSelection::new(
inputs,
outputs,
addresses([BECH32_ADDRESS_ED25519_0]),
protocol_parameters,
)
.select();
assert!(matches!(
selected,
Err(Error::InsufficientAmount {
found: 1_000_000,
required: 2_000_000,
})
));
}
#[test]
fn input_amount_lower_than_output_amount_2() {
let protocol_parameters = protocol_parameters();
let inputs = build_inputs([
Basic(1_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None),
Basic(2_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None),
]);
let outputs = build_outputs([Basic(
3_500_000,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
None,
None,
)]);
let selected = InputSelection::new(
inputs,
outputs,
addresses([BECH32_ADDRESS_ED25519_0]),
protocol_parameters,
)
.select();
assert!(matches!(
selected,
Err(Error::InsufficientAmount {
found: 3_000_000,
required: 3_500_000,
})
));
}
#[test]
fn input_amount_greater_than_output_amount() {
let protocol_parameters = protocol_parameters();
let inputs = build_inputs([Basic(
2_000_000,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
None,
None,
)]);
let outputs = build_outputs([Basic(
500_000,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
None,
None,
)]);
let selected = InputSelection::new(
inputs.clone(),
outputs.clone(),
addresses([BECH32_ADDRESS_ED25519_0]),
protocol_parameters,
)
.select()
.unwrap();
assert!(unsorted_eq(&selected.inputs, &inputs));
assert_eq!(selected.outputs.len(), 2);
assert!(selected.outputs.contains(&outputs[0]));
selected.outputs.iter().for_each(|output| {
if !outputs.contains(output) {
assert!(is_remainder_or_return(
output,
1_500_000,
BECH32_ADDRESS_ED25519_0,
None,
));
}
});
}
#[test]
fn input_amount_greater_than_output_amount_with_remainder_address() {
let protocol_parameters = protocol_parameters();
let remainder_address = Address::try_from_bech32(BECH32_ADDRESS_REMAINDER).unwrap();
let inputs = build_inputs([Basic(
2_000_000,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
None,
None,
)]);
let outputs = build_outputs([Basic(
500_000,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
None,
None,
)]);
let selected = InputSelection::new(
inputs.clone(),
outputs.clone(),
addresses([BECH32_ADDRESS_ED25519_0]),
protocol_parameters,
)
.remainder_address(remainder_address)
.select()
.unwrap();
assert!(unsorted_eq(&selected.inputs, &inputs));
assert_eq!(selected.outputs.len(), 2);
assert!(selected.outputs.contains(&outputs[0]));
selected.outputs.iter().for_each(|output| {
if !outputs.contains(output) {
assert!(is_remainder_or_return(
output,
1_500_000,
BECH32_ADDRESS_REMAINDER,
None,
));
}
});
}
#[test]
fn two_same_inputs_one_needed() {
let protocol_parameters = protocol_parameters();
let inputs = build_inputs([
Basic(2_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None),
Basic(2_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None),
]);
let outputs = build_outputs([Basic(
500_000,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
None,
None,
)]);
let selected = InputSelection::new(
inputs,
outputs.clone(),
addresses([BECH32_ADDRESS_ED25519_0]),
protocol_parameters,
)
.select()
.unwrap();
assert_eq!(selected.inputs.len(), 1);
assert_eq!(selected.outputs.len(), 2);
assert!(selected.outputs.contains(&outputs[0]));
selected.outputs.iter().for_each(|output| {
if !outputs.contains(output) {
assert!(is_remainder_or_return(
output,
1_500_000,
BECH32_ADDRESS_ED25519_0,
None,
));
}
});
}
#[test]
fn two_inputs_one_needed() {
let protocol_parameters = protocol_parameters();
let inputs = build_inputs([
Basic(1_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None),
Basic(2_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None),
]);
let outputs = build_outputs([Basic(
1_000_000,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
None,
None,
)]);
let selected = InputSelection::new(
inputs.clone(),
outputs.clone(),
addresses([BECH32_ADDRESS_ED25519_0]),
protocol_parameters,
)
.select()
.unwrap();
assert_eq!(selected.inputs, [inputs[0].clone()]);
assert!(unsorted_eq(&selected.outputs, &outputs));
}
#[test]
fn two_inputs_one_needed_reversed() {
let protocol_parameters = protocol_parameters();
let inputs = build_inputs([
Basic(2_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None),
Basic(1_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None),
]);
let outputs = build_outputs([Basic(
1_000_000,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
None,
None,
)]);
let selected = InputSelection::new(
inputs.clone(),
outputs.clone(),
addresses([BECH32_ADDRESS_ED25519_0]),
protocol_parameters,
)
.select()
.unwrap();
assert_eq!(selected.inputs, [inputs[1].clone()]);
assert!(unsorted_eq(&selected.outputs, &outputs));
}
#[test]
fn two_inputs_both_needed() {
let protocol_parameters = protocol_parameters();
let inputs = build_inputs([
Basic(1_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None),
Basic(2_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None),
]);
let outputs = build_outputs([Basic(
3_000_000,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
None,
None,
)]);
let selected = InputSelection::new(
inputs.clone(),
outputs.clone(),
addresses([BECH32_ADDRESS_ED25519_0]),
protocol_parameters,
)
.select()
.unwrap();
assert!(unsorted_eq(&selected.inputs, &inputs));
assert!(unsorted_eq(&selected.outputs, &outputs));
}
#[test]
fn two_inputs_remainder() {
let protocol_parameters = protocol_parameters();
let inputs = build_inputs([
Basic(1_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None),
Basic(2_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None),
]);
let outputs = build_outputs([Basic(
2_500_000,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
None,
None,
)]);
let selected = InputSelection::new(
inputs.clone(),
outputs.clone(),
addresses([BECH32_ADDRESS_ED25519_0]),
protocol_parameters,
)
.select()
.unwrap();
assert!(unsorted_eq(&selected.inputs, &inputs));
assert_eq!(selected.outputs.len(), 2);
assert!(selected.outputs.contains(&outputs[0]));
selected.outputs.iter().for_each(|output| {
if !outputs.contains(output) {
assert!(is_remainder_or_return(output, 500_000, BECH32_ADDRESS_ED25519_0, None));
}
});
}
#[test]
fn not_enough_storage_deposit_for_remainder() {
let protocol_parameters = protocol_parameters();
let inputs = build_inputs([Basic(
1_000_001,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
None,
None,
)]);
let outputs = build_outputs([Basic(
1_000_000,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
None,
None,
)]);
let selected = InputSelection::new(
inputs,
outputs,
addresses([BECH32_ADDRESS_ED25519_0]),
protocol_parameters,
)
.select();
assert!(matches!(
selected,
Err(Error::InsufficientAmount {
found: 1_000_001,
required: 1_213_000,
})
));
}
#[test]
fn ed25519_sender() {
let protocol_parameters = protocol_parameters();
let sender = Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap();
let inputs = build_inputs([
Basic(2_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None),
Basic(2_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None),
Basic(1_000_000, BECH32_ADDRESS_ED25519_1, None, None, None, None, None, None),
Basic(2_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None),
Basic(2_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None),
]);
let outputs = build_outputs([Basic(
2_000_000,
BECH32_ADDRESS_ED25519_0,
None,
Some(BECH32_ADDRESS_ED25519_1),
None,
None,
None,
None,
)]);
let selected = InputSelection::new(
inputs,
outputs,
addresses([BECH32_ADDRESS_ED25519_0, BECH32_ADDRESS_ED25519_1]),
protocol_parameters,
)
.select()
.unwrap();
assert_eq!(selected.inputs.len(), 2);
assert!(
selected
.inputs
.iter()
.any(|input| *input.output.as_basic().address() == sender)
);
assert_eq!(selected.outputs.len(), 2);
}
#[test]
fn missing_ed25519_sender() {
let protocol_parameters = protocol_parameters();
let inputs = build_inputs([Basic(
5_000_000,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
None,
None,
)]);
let outputs = build_outputs([Basic(
1_000_000,
BECH32_ADDRESS_ED25519_0,
None,
Some(BECH32_ADDRESS_ED25519_1),
None,
None,
None,
None,
)]);
let selected = InputSelection::new(
inputs,
outputs,
addresses([BECH32_ADDRESS_ED25519_0]),
protocol_parameters,
)
.select();
assert!(matches!(
selected,
Err(Error::UnfulfillableRequirement(Requirement::Sender(sender))) if sender == Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap()
));
}
#[test]
fn alias_sender() {
let protocol_parameters = protocol_parameters();
let alias_id_1 = AliasId::from_str(ALIAS_ID_1).unwrap();
let inputs = build_inputs([
Basic(2_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None),
Basic(2_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None),
Alias(
1_000_000,
alias_id_1,
0,
BECH32_ADDRESS_ED25519_0,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
),
Basic(2_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None),
Basic(2_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None),
]);
let outputs = build_outputs([Basic(
2_000_000,
BECH32_ADDRESS_ED25519_0,
None,
Some(BECH32_ADDRESS_ALIAS_1),
None,
None,
None,
None,
)]);
let selected = InputSelection::new(
inputs,
outputs.clone(),
addresses([BECH32_ADDRESS_ED25519_0]),
protocol_parameters,
)
.select()
.unwrap();
assert_eq!(selected.inputs.len(), 2);
assert!(
selected
.inputs
.iter()
.any(|input| input.output.is_alias() && *input.output.as_alias().alias_id() == alias_id_1)
);
assert_eq!(selected.outputs.len(), 2);
assert!(selected.outputs.contains(&outputs[0]));
}
#[test]
fn alias_sender_zero_id() {
let protocol_parameters = protocol_parameters();
let alias_id_0 = AliasId::from_str(ALIAS_ID_0).unwrap();
let inputs = build_inputs([
Basic(2_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None),
Alias(
1_000_000,
alias_id_0,
0,
BECH32_ADDRESS_ED25519_0,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
),
]);
let alias_id = AliasId::from(inputs[1].output_id());
let outputs = build_outputs([Basic(
2_000_000,
BECH32_ADDRESS_ED25519_0,
None,
Some(
&Bech32Address::try_new("rms", AliasAddress::from(alias_id))
.unwrap()
.to_string(),
),
None,
None,
None,
None,
)]);
let selected = InputSelection::new(
inputs.clone(),
outputs,
addresses([BECH32_ADDRESS_ED25519_0]),
protocol_parameters,
)
.select()
.unwrap();
assert!(unsorted_eq(&selected.inputs, &inputs));
assert_eq!(selected.outputs.len(), 2);
assert!(
selected
.outputs
.iter()
.any(|output| output.is_alias() && *output.as_alias().alias_id() == alias_id)
);
}
#[test]
fn missing_alias_sender() {
let protocol_parameters = protocol_parameters();
let inputs = build_inputs([Basic(
5_000_000,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
None,
None,
)]);
let outputs = build_outputs([Basic(
1_000_000,
BECH32_ADDRESS_ED25519_0,
None,
Some(BECH32_ADDRESS_ALIAS_1),
None,
None,
None,
None,
)]);
let selected = InputSelection::new(
inputs,
outputs,
addresses([BECH32_ADDRESS_ED25519_0]),
protocol_parameters,
)
.select();
assert!(matches!(
selected,
Err(Error::UnfulfillableRequirement(Requirement::Sender(sender))) if sender == Address::try_from_bech32(BECH32_ADDRESS_ALIAS_1).unwrap()
));
}
#[test]
fn nft_sender() {
let protocol_parameters = protocol_parameters();
let nft_id_1 = NftId::from_str(NFT_ID_1).unwrap();
let inputs = build_inputs([
Basic(2_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None),
Basic(2_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None),
Nft(
1_000_000,
nft_id_1,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
None,
None,
),
Basic(2_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None),
Basic(2_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None),
]);
let outputs = build_outputs([Basic(
2_000_000,
BECH32_ADDRESS_ED25519_0,
None,
Some(BECH32_ADDRESS_NFT_1),
None,
None,
None,
None,
)]);
let selected = InputSelection::new(
inputs.clone(),
outputs.clone(),
addresses([BECH32_ADDRESS_ED25519_0]),
protocol_parameters,
)
.select()
.unwrap();
assert_eq!(selected.inputs.len(), 2);
assert!(
selected
.inputs
.iter()
.any(|input| input.output.is_nft() && *input.output.as_nft().nft_id() == nft_id_1)
);
assert_eq!(selected.outputs.len(), 2);
assert!(selected.outputs.contains(&inputs[2].output));
assert!(selected.outputs.contains(&outputs[0]));
}
#[test]
fn nft_sender_zero_id() {
let protocol_parameters = protocol_parameters();
let nft_id_0 = NftId::from_str(NFT_ID_0).unwrap();
let inputs = build_inputs([
Basic(2_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None),
Nft(
1_000_000,
nft_id_0,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
None,
None,
),
]);
let nft_id = NftId::from(inputs[1].output_id());
let outputs = build_outputs([Basic(
2_000_000,
BECH32_ADDRESS_ED25519_0,
None,
Some(
&Bech32Address::try_new("rms", NftAddress::from(nft_id))
.unwrap()
.to_string(),
),
None,
None,
None,
None,
)]);
let selected = InputSelection::new(
inputs.clone(),
outputs,
addresses([BECH32_ADDRESS_ED25519_0]),
protocol_parameters,
)
.select()
.unwrap();
assert!(unsorted_eq(&selected.inputs, &inputs));
assert_eq!(selected.outputs.len(), 2);
assert!(
selected
.outputs
.iter()
.any(|output| output.is_nft() && *output.as_nft().nft_id() == nft_id)
);
}
#[test]
fn missing_nft_sender() {
let protocol_parameters = protocol_parameters();
let inputs = build_inputs([Basic(
5_000_000,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
None,
None,
)]);
let outputs = build_outputs([Basic(
1_000_000,
BECH32_ADDRESS_ED25519_0,
None,
Some(BECH32_ADDRESS_NFT_1),
None,
None,
None,
None,
)]);
let selected = InputSelection::new(
inputs,
outputs,
addresses([BECH32_ADDRESS_ED25519_0]),
protocol_parameters,
)
.select();
assert!(matches!(
selected,
Err(Error::UnfulfillableRequirement(Requirement::Sender(sender))) if sender == Address::try_from_bech32(BECH32_ADDRESS_NFT_1).unwrap()
));
}
#[test]
fn simple_remainder() {
let protocol_parameters = protocol_parameters();
let inputs = build_inputs([Basic(
1_000_000,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
None,
None,
)]);
let outputs = build_outputs([Basic(
500_000,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
None,
None,
)]);
let selected = InputSelection::new(
inputs.clone(),
outputs.clone(),
addresses([BECH32_ADDRESS_ED25519_0]),
protocol_parameters,
)
.select()
.unwrap();
assert!(unsorted_eq(&selected.inputs, &inputs));
assert_eq!(selected.outputs.len(), 2);
assert!(selected.outputs.contains(&outputs[0]));
selected.outputs.iter().for_each(|output| {
if !outputs.contains(output) {
assert!(is_remainder_or_return(output, 500_000, BECH32_ADDRESS_ED25519_0, None));
}
});
}
#[test]
fn remainder_lower_than_rent() {
let protocol_parameters = protocol_parameters();
let inputs = build_inputs([Basic(
1_000_000,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
None,
None,
)]);
let outputs = build_outputs([Basic(
800_000,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
None,
None,
)]);
let selected = InputSelection::new(
inputs,
outputs,
addresses([BECH32_ADDRESS_ED25519_0]),
protocol_parameters,
)
.select();
assert!(matches!(
selected,
Err(Error::InsufficientAmount {
found: 1_000_000,
required: 1_013_000,
})
));
}
#[test]
fn remainder_lower_than_rent_2() {
let protocol_parameters = protocol_parameters();
let inputs = build_inputs([
Basic(1_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None),
Basic(2_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None),
]);
let outputs = build_outputs([Basic(
2_800_000,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
None,
None,
)]);
let selected = InputSelection::new(
inputs,
outputs,
addresses([BECH32_ADDRESS_ED25519_0]),
protocol_parameters,
)
.select();
assert!(matches!(
selected,
Err(Error::InsufficientAmount {
found: 3_000_000,
required: 3_013_000,
})
));
}
#[test]
fn one_provided_one_needed() {
let protocol_parameters = protocol_parameters();
let inputs = build_inputs([Basic(
1_000_000,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
None,
None,
)]);
let outputs = build_outputs([Basic(
1_000_000,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
None,
None,
)]);
let selected = InputSelection::new(
inputs.clone(),
outputs.clone(),
addresses([BECH32_ADDRESS_ED25519_0]),
protocol_parameters,
)
.select()
.unwrap();
assert!(unsorted_eq(&selected.inputs, &inputs));
assert!(unsorted_eq(&selected.outputs, &outputs));
}
#[test]
fn insufficient_amount() {
let protocol_parameters = protocol_parameters();
let inputs = build_inputs([Basic(
1_000_000,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
None,
None,
)]);
let outputs = build_outputs([Basic(
1_250_000,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
None,
None,
)]);
let selected = InputSelection::new(
inputs,
outputs,
addresses([BECH32_ADDRESS_ED25519_0]),
protocol_parameters,
)
.select();
assert!(matches!(
selected,
Err(Error::InsufficientAmount {
found: 1_000_000,
required: 1_250_000,
})
));
}
#[test]
fn two_inputs_remainder_2() {
let protocol_parameters = protocol_parameters();
let inputs = build_inputs([
Basic(1_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None),
Basic(2_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None),
]);
let outputs = build_outputs([Basic(
500_000,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
None,
None,
)]);
let selected = InputSelection::new(
inputs.clone(),
outputs.clone(),
addresses([BECH32_ADDRESS_ED25519_0]),
protocol_parameters,
)
.select()
.unwrap();
assert_eq!(selected.inputs.len(), 1);
assert!(selected.inputs.contains(&inputs[0]));
assert_eq!(selected.outputs.len(), 2);
assert!(selected.outputs.contains(&outputs[0]));
selected.outputs.iter().for_each(|output| {
if !outputs.contains(output) {
assert!(is_remainder_or_return(output, 500_000, BECH32_ADDRESS_ED25519_0, None));
}
});
}
#[test]
fn two_inputs_remainder_3() {
let protocol_parameters = protocol_parameters();
let inputs = build_inputs([
Basic(1_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None),
Basic(2_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None),
]);
let outputs = build_outputs([Basic(
1_750_000,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
None,
None,
)]);
let selected = InputSelection::new(
inputs.clone(),
outputs.clone(),
addresses([BECH32_ADDRESS_ED25519_0]),
protocol_parameters,
)
.select()
.unwrap();
assert!(unsorted_eq(&selected.inputs, &inputs));
assert_eq!(selected.outputs.len(), 2);
assert!(selected.outputs.contains(&outputs[0]));
selected.outputs.iter().for_each(|output| {
if !outputs.contains(output) {
assert!(is_remainder_or_return(
output,
1_250_000,
BECH32_ADDRESS_ED25519_0,
None
));
}
});
}
#[test]
fn another_input_required_to_cover_remainder_rent() {
let protocol_parameters = protocol_parameters();
let inputs = build_inputs([
Basic(500_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None),
Basic(600_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None),
Basic(700_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None),
]);
let outputs = build_outputs([Basic(
1_000_000,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
None,
None,
)]);
let selected = InputSelection::new(
inputs.clone(),
outputs.clone(),
addresses([BECH32_ADDRESS_ED25519_0]),
protocol_parameters,
)
.select()
.unwrap();
assert!(unsorted_eq(&selected.inputs, &inputs));
assert_eq!(selected.outputs.len(), 2);
assert!(selected.outputs.contains(&outputs[0]));
selected.outputs.iter().for_each(|output| {
if !outputs.contains(output) {
assert!(is_remainder_or_return(output, 800_000, BECH32_ADDRESS_ED25519_0, None));
}
});
}
#[test]
fn sender_already_selected() {
let protocol_parameters = protocol_parameters();
let inputs = build_inputs([Basic(
1_000_000,
BECH32_ADDRESS_ED25519_1,
None,
None,
None,
None,
None,
None,
)]);
let outputs = build_outputs([Basic(
1_000_000,
BECH32_ADDRESS_ED25519_0,
None,
Some(BECH32_ADDRESS_ED25519_1),
None,
None,
None,
None,
)]);
let selected = InputSelection::new(
inputs.clone(),
outputs.clone(),
addresses([BECH32_ADDRESS_ED25519_0, BECH32_ADDRESS_ED25519_1]),
protocol_parameters,
)
.required_inputs([*inputs[0].output_id()])
.select()
.unwrap();
assert!(unsorted_eq(&selected.inputs, &inputs));
assert!(unsorted_eq(&selected.outputs, &outputs));
}
#[test]
fn single_mandatory_input() {
let protocol_parameters = protocol_parameters();
let inputs = build_inputs([Basic(
1_000_000,
BECH32_ADDRESS_ED25519_1,
None,
None,
None,
None,
None,
None,
)]);
let outputs = build_outputs([Basic(
1_000_000,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
None,
None,
)]);
let selected = InputSelection::new(
inputs.clone(),
outputs.clone(),
addresses([BECH32_ADDRESS_ED25519_0, BECH32_ADDRESS_ED25519_1]),
protocol_parameters,
)
.required_inputs([*inputs[0].output_id()])
.select()
.unwrap();
assert!(unsorted_eq(&selected.inputs, &inputs));
assert!(unsorted_eq(&selected.outputs, &outputs));
}
#[test]
fn too_many_inputs() {
let protocol_parameters = protocol_parameters();
let inputs = build_inputs(
std::iter::repeat_with(|| Basic(1_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None))
.take(129),
);
let outputs = build_outputs([Basic(
129_000_000,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
None,
None,
)]);
let selected = InputSelection::new(
inputs,
outputs,
addresses([BECH32_ADDRESS_ED25519_0]),
protocol_parameters,
)
.select();
assert_eq!(
selected.unwrap_err(),
iota_sdk::client::api::input_selection::Error::InvalidInputCount(129)
)
}
#[test]
fn more_than_max_inputs_only_one_needed() {
let protocol_parameters = protocol_parameters();
let mut inputs = build_inputs(
std::iter::repeat_with(|| Basic(1_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None))
.take(1000),
);
let needed_input = build_inputs([Basic(
129_000_000,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
None,
None,
)]);
inputs.push(needed_input[0].clone());
let outputs = build_outputs([Basic(
129_000_000,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
None,
None,
)]);
let selected = InputSelection::new(
inputs,
outputs.clone(),
addresses([BECH32_ADDRESS_ED25519_0]),
protocol_parameters,
)
.select()
.unwrap();
assert!(unsorted_eq(&selected.inputs, &needed_input));
assert!(unsorted_eq(&selected.outputs, &outputs));
}
#[test]
fn too_many_outputs() {
let protocol_parameters = protocol_parameters();
let inputs = build_inputs([Basic(
2_000_000_000,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
None,
None,
)]);
let outputs = build_outputs(
std::iter::repeat_with(|| Basic(1_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None))
.take(129),
);
let selected = InputSelection::new(
inputs,
outputs,
addresses([BECH32_ADDRESS_ED25519_0]),
protocol_parameters,
)
.select();
assert_eq!(
selected.unwrap_err(),
iota_sdk::client::api::input_selection::Error::InvalidOutputCount(129)
)
}
#[test]
fn too_many_outputs_with_remainder() {
let protocol_parameters = protocol_parameters();
let inputs = build_inputs([Basic(
2_000_000_000,
BECH32_ADDRESS_ED25519_0,
None,
None,
None,
None,
None,
None,
)]);
let outputs = build_outputs(
std::iter::repeat_with(|| Basic(1_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None))
.take(128),
);
let selected = InputSelection::new(
inputs,
outputs,
addresses([BECH32_ADDRESS_ED25519_0]),
protocol_parameters,
)
.select();
assert_eq!(
selected.unwrap_err(),
iota_sdk::client::api::input_selection::Error::InvalidOutputCount(129)
)
}