const TINY_BTC_AMOUNT: u32 = 294;
use super::*;
use serial_test::parallel;
use std::collections::BTreeSet;
#[test]
#[parallel]
fn success() {
initialize();
let amount: u64 = 66;
let (wallet, online) = get_funded_wallet!();
let (rcv_wallet, rcv_online) = get_funded_wallet!();
let asset = test_issue_asset_nia(&wallet, &online, None);
let transfers = test_list_transfers(&wallet, Some(&asset.asset_id));
assert_eq!(transfers.len(), 1);
assert_eq!(transfers.first().unwrap().kind, TransferKind::Issuance);
let receive_data = test_blind_receive(&rcv_wallet);
let recipient_map = HashMap::from([(
asset.asset_id.clone(),
vec![Recipient {
amount,
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data.recipient_id).unwrap(),
),
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
)]);
let bak_info_before = wallet.database.get_backup_info().unwrap().unwrap();
let txid = test_send(&wallet, &online, &recipient_map);
let bak_info_after = wallet.database.get_backup_info().unwrap().unwrap();
assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp);
assert!(!txid.is_empty());
let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid);
let tte_data = wallet
.database
.get_transfer_transport_endpoints_data(transfer.idx)
.unwrap();
assert_eq!(tte_data.len(), 1);
let ce = tte_data.first().unwrap();
assert_eq!(ce.1.endpoint, PROXY_URL);
assert!(ce.0.used);
let rcv_transfer = get_test_transfer_recipient(&rcv_wallet, &receive_data.recipient_id);
let (rcv_transfer_data, rcv_asset_transfer) =
get_test_transfer_data(&rcv_wallet, &rcv_transfer);
let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid);
let (transfer_data, asset_transfer) = get_test_transfer_data(&wallet, &transfer);
assert_eq!(rcv_transfer.ack, None);
assert_eq!(transfer.ack, None);
assert_eq!(rcv_transfer.amount, 0.to_string());
assert_eq!(transfer.amount, amount.to_string());
assert_eq!(
rcv_transfer.recipient_id,
Some(receive_data.recipient_id.clone())
);
assert_eq!(
transfer.recipient_id,
Some(receive_data.recipient_id.clone())
);
assert!(rcv_transfer.incoming);
assert!(!transfer.incoming);
assert!(rcv_transfer_data.change_utxo.is_none());
assert!(transfer_data.change_utxo.is_some());
assert_eq!(rcv_transfer_data.created_at, rcv_transfer_data.updated_at);
assert_eq!(transfer_data.created_at, transfer_data.updated_at);
assert_eq!(
rcv_transfer_data.expiration,
Some(rcv_transfer_data.created_at + DURATION_RCV_TRANSFER as i64)
);
assert_eq!(
transfer_data.expiration,
Some(transfer_data.created_at + DURATION_SEND_TRANSFER)
);
assert_eq!(rcv_transfer_data.kind, TransferKind::ReceiveBlind);
assert_eq!(transfer_data.kind, TransferKind::Send);
assert_eq!(
rcv_transfer_data.status,
TransferStatus::WaitingCounterparty
);
assert_eq!(transfer_data.status, TransferStatus::WaitingCounterparty);
assert_eq!(rcv_transfer_data.txid, None);
assert_eq!(transfer_data.txid, Some(txid.clone()));
assert!(rcv_transfer_data.receive_utxo.is_some());
assert!(transfer_data.receive_utxo.is_none());
assert!(rcv_asset_transfer.asset_id.is_none());
assert_eq!(asset_transfer.asset_id, Some(asset.asset_id.clone()));
assert!(rcv_asset_transfer.user_driven);
assert!(asset_transfer.user_driven);
stop_mining();
std::thread::sleep(Duration::from_millis(1000)); test_refresh_all(&rcv_wallet, &rcv_online);
let rcv_transfer = get_test_transfer_recipient(&rcv_wallet, &receive_data.recipient_id);
let (rcv_transfer_data, rcv_asset_transfer) =
get_test_transfer_data(&rcv_wallet, &rcv_transfer);
test_refresh_asset(&wallet, &online, &asset.asset_id);
let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid);
let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer);
assert_eq!(
rcv_transfer_data.status,
TransferStatus::WaitingConfirmations
);
assert_eq!(transfer_data.status, TransferStatus::WaitingConfirmations);
assert_eq!(transfer.ack, Some(true));
assert_eq!(rcv_transfer.amount, amount.to_string());
assert_eq!(rcv_asset_transfer.asset_id, Some(asset.asset_id.clone()));
let rcv_updated_at = rcv_transfer_data.updated_at;
let updated_at = transfer_data.updated_at;
assert!(rcv_updated_at > rcv_transfer_data.created_at);
assert!(updated_at > transfer_data.created_at);
let rcv_assets = test_list_assets(&rcv_wallet, &[]);
let nia_assets = rcv_assets.nia.unwrap();
let cfa_assets = rcv_assets.cfa.unwrap();
assert_eq!(nia_assets.len(), 1);
assert_eq!(cfa_assets.len(), 0);
let rcv_asset = nia_assets.last().unwrap();
assert_eq!(rcv_asset.asset_id, asset.asset_id);
assert_eq!(rcv_asset.ticker, TICKER);
assert_eq!(rcv_asset.name, NAME);
assert_eq!(rcv_asset.precision, PRECISION);
assert_eq!(
rcv_asset.balance,
Balance {
settled: 0,
future: amount,
spendable: 0,
}
);
mine(true);
std::thread::sleep(Duration::from_millis(1000)); test_refresh_all(&rcv_wallet, &rcv_online);
test_refresh_asset(&wallet, &online, &asset.asset_id);
let rcv_transfer = get_test_transfer_recipient(&rcv_wallet, &receive_data.recipient_id);
let (rcv_transfer_data, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer);
let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid);
let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer);
assert_eq!(rcv_transfer_data.status, TransferStatus::Settled);
assert_eq!(transfer_data.status, TransferStatus::Settled);
assert!(rcv_transfer_data.updated_at > rcv_updated_at);
assert!(transfer_data.updated_at > updated_at);
let unspents = test_list_unspents(&wallet, None, true);
let change_unspent = unspents
.into_iter()
.find(|u| Some(u.utxo.outpoint.clone()) == transfer_data.change_utxo);
assert!(change_unspent.is_some());
let transport_endpoints = vec![
format!("rpc://{PROXY_HOST_MOD_API}"),
format!("rpc://{PROXY_HOST_MOD_PROTO}"),
format!("rpc://{PROXY_HOST}"),
];
let receive_data_api_proto = rcv_wallet
.blind_receive(
None,
None,
None,
transport_endpoints.clone(),
MIN_CONFIRMATIONS,
)
.unwrap();
let recipient_map = HashMap::from([(
asset.asset_id.clone(),
vec![Recipient {
amount,
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data_api_proto.recipient_id).unwrap(),
),
transport_endpoints,
}],
)]);
let unspents = test_list_unspents(&wallet, None, false);
let unspents_color_count_before = unspents.iter().filter(|u| u.utxo.colorable).count();
let txid = test_send(&wallet, &online, &recipient_map);
assert!(!txid.is_empty());
let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid);
let tte_data = wallet
.database
.get_transfer_transport_endpoints_data(transfer.idx)
.unwrap();
assert_eq!(tte_data.len(), 3);
let mut tte_data_iter = tte_data.iter();
let (ce_0, ce_1, ce_2) = (
&tte_data_iter.next().unwrap(),
&tte_data_iter.next().unwrap(),
&tte_data_iter.next().unwrap(),
);
assert_eq!(ce_0.1.endpoint, PROXY_URL_MOD_API);
assert_eq!(ce_1.1.endpoint, PROXY_URL_MOD_PROTO);
assert_eq!(ce_2.1.endpoint, PROXY_URL);
assert!(!ce_0.0.used);
assert!(!ce_1.0.used);
assert!(ce_2.0.used);
let consignment = wallet
.rest_client
.clone()
.get_consignment(
PROXY_URL_MOD_API,
receive_data_api_proto.recipient_id.clone(),
)
.unwrap();
assert!(consignment.error.is_some());
let consignment = wallet
.rest_client
.clone()
.get_consignment(
PROXY_URL_MOD_PROTO,
receive_data_api_proto.recipient_id.clone(),
)
.unwrap();
assert!(consignment.error.is_some());
let consignment = wallet
.rest_client
.clone()
.get_consignment(PROXY_URL, receive_data_api_proto.recipient_id.clone())
.unwrap();
assert!(consignment.result.is_some());
test_refresh_all(&rcv_wallet, &rcv_online);
test_refresh_asset(&wallet, &online, &asset.asset_id);
mine(true);
test_refresh_all(&rcv_wallet, &rcv_online);
test_refresh_asset(&wallet, &online, &asset.asset_id);
let rcv_transfer =
get_test_transfer_recipient(&rcv_wallet, &receive_data_api_proto.recipient_id);
let (rcv_transfer_data, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer);
let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid);
let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer);
assert_eq!(rcv_transfer_data.status, TransferStatus::Settled);
assert_eq!(transfer_data.status, TransferStatus::Settled);
let unspents = test_list_unspents(&wallet, None, false);
let unspents_color_count_after = unspents.iter().filter(|u| u.utxo.colorable).count();
assert_eq!(unspents_color_count_after, unspents_color_count_before);
let transport_endpoints = vec![
format!("rpc://{PROXY_HOST_MOD_PROTO}"),
format!("rpc://127.6.6.6:7777/json-rpc"),
format!("rpc://{PROXY_HOST}"),
];
let receive_data_invalid_unreachable = rcv_wallet
.blind_receive(
None,
None,
None,
transport_endpoints.clone().into_iter().skip(1).collect(),
MIN_CONFIRMATIONS,
)
.unwrap();
let recipient_map = HashMap::from([(
asset.asset_id.clone(),
vec![Recipient {
amount,
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data_invalid_unreachable.recipient_id).unwrap(),
),
transport_endpoints,
}],
)]);
let unspents = test_list_unspents(&wallet, None, false);
let unspents_color_count_before = unspents.iter().filter(|u| u.utxo.colorable).count();
let txid = wallet
.send(online.clone(), recipient_map, false, 5.0, MIN_CONFIRMATIONS)
.unwrap();
assert!(!txid.is_empty());
let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid);
let tte_data = wallet
.database
.get_transfer_transport_endpoints_data(transfer.idx)
.unwrap();
assert_eq!(tte_data.len(), 3);
let mut tte_data_iter = tte_data.iter();
let (ce_0, ce_1, ce_2) = (
&tte_data_iter.next().unwrap(),
&tte_data_iter.next().unwrap(),
&tte_data_iter.next().unwrap(),
);
assert_eq!(ce_0.1.endpoint, PROXY_URL_MOD_PROTO);
assert_eq!(ce_1.1.endpoint, "http://127.6.6.6:7777/json-rpc");
assert_eq!(ce_2.1.endpoint, PROXY_URL);
assert!(!ce_0.0.used);
assert!(!ce_1.0.used);
assert!(ce_2.0.used);
let consignment = wallet
.rest_client
.clone()
.get_consignment(
PROXY_URL_MOD_PROTO,
receive_data_invalid_unreachable.recipient_id.clone(),
)
.unwrap();
assert!(consignment.error.is_some());
let consignment = wallet
.rest_client
.clone()
.get_consignment(PROXY_URL, receive_data_invalid_unreachable.recipient_id)
.unwrap();
assert!(consignment.result.is_some());
test_refresh_all(&rcv_wallet, &rcv_online);
test_refresh_asset(&wallet, &online, &asset.asset_id);
mine(true);
rcv_wallet.refresh(rcv_online, None, vec![]).unwrap();
test_refresh_asset(&wallet, &online, &asset.asset_id);
let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid);
let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer);
assert_eq!(transfer_data.status, TransferStatus::Settled);
let unspents = test_list_unspents(&wallet, None, false);
let unspents_color_count_after = unspents.iter().filter(|u| u.utxo.colorable).count();
assert_eq!(unspents_color_count_after, unspents_color_count_before - 1);
}
#[test]
#[parallel]
fn spend_all() {
initialize();
let file_str = "README.md";
let (wallet, online) = get_funded_noutxo_wallet!();
let (rcv_wallet, rcv_online) = get_funded_wallet!();
test_create_utxos(&wallet, &online, false, Some(1), None, FEE_RATE);
let asset = test_issue_asset_nia(&wallet, &online, None);
let asset_blank = test_issue_asset_cfa(
&wallet,
&online,
Some(&[AMOUNT * 2]),
Some(file_str.to_string()),
);
let unspents = test_list_unspents(&wallet, None, true);
let unspents_with_rgb_allocations: Vec<Unspent> = unspents
.into_iter()
.filter(|u| !u.rgb_allocations.is_empty())
.collect();
assert_eq!(unspents_with_rgb_allocations.len(), 1);
let allocation_asset_ids: Vec<String> = unspents_with_rgb_allocations
.first()
.unwrap()
.rgb_allocations
.clone()
.into_iter()
.map(|a| a.asset_id.unwrap_or_else(|| s!("")))
.collect();
assert!(allocation_asset_ids.contains(&asset.asset_id));
assert!(allocation_asset_ids.contains(&asset_blank.asset_id));
test_create_utxos(&wallet, &online, false, Some(1), None, FEE_RATE);
let receive_data = test_blind_receive(&rcv_wallet);
let recipient_map = HashMap::from([(
asset.asset_id.clone(),
vec![Recipient {
amount: AMOUNT,
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data.recipient_id).unwrap(),
),
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
)]);
let txid = test_send(&wallet, &online, &recipient_map);
assert!(!txid.is_empty());
let rcv_transfer = get_test_transfer_recipient(&rcv_wallet, &receive_data.recipient_id);
let (rcv_transfer_data, rcv_asset_transfer) =
get_test_transfer_data(&rcv_wallet, &rcv_transfer);
let (transfers, asset_transfers, _) = get_test_transfers_sender(&wallet, &txid);
let transfers_for_asset = transfers.get(&asset.asset_id).unwrap();
assert_eq!(transfers_for_asset.len(), 1);
let transfer = transfers_for_asset.first().unwrap();
let (transfer_data, _) = get_test_transfer_data(&wallet, transfer);
assert_eq!(asset_transfers.len(), 2);
let asset_transfer = asset_transfers
.iter()
.find(|a| a.asset_id == Some(asset.asset_id.clone()))
.unwrap();
let asset_blank_asset_transfer = asset_transfers
.iter()
.find(|a| a.asset_id == Some(asset_blank.asset_id.clone()))
.unwrap();
assert!(rcv_transfer_data.change_utxo.is_none());
assert!(transfer_data.change_utxo.is_none());
assert_eq!(
rcv_transfer_data.status,
TransferStatus::WaitingCounterparty
);
assert_eq!(transfer_data.status, TransferStatus::WaitingCounterparty);
assert!(rcv_asset_transfer.user_driven);
assert!(asset_transfer.user_driven);
assert!(!asset_blank_asset_transfer.user_driven);
stop_mining();
test_refresh_all(&rcv_wallet, &rcv_online);
let rcv_transfer = get_test_transfer_recipient(&rcv_wallet, &receive_data.recipient_id);
let (rcv_transfer_data, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer);
test_refresh_asset(&wallet, &online, &asset.asset_id);
let (transfers, _, _) = get_test_transfers_sender(&wallet, &txid);
let transfers_for_asset = transfers.get(&asset.asset_id).unwrap();
assert_eq!(transfers_for_asset.len(), 1);
let transfer = transfers_for_asset.first().unwrap();
let (transfer_data, _) = get_test_transfer_data(&wallet, transfer);
assert_eq!(
rcv_transfer_data.status,
TransferStatus::WaitingConfirmations
);
assert_eq!(transfer_data.status, TransferStatus::WaitingConfirmations);
mine(true);
rcv_wallet.refresh(rcv_online, None, vec![]).unwrap();
test_refresh_asset(&wallet, &online, &asset.asset_id);
let rcv_transfer = get_test_transfer_recipient(&rcv_wallet, &receive_data.recipient_id);
let (rcv_transfer_data, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer);
let (transfers, _, _) = get_test_transfers_sender(&wallet, &txid);
let transfers_for_asset = transfers.get(&asset.asset_id).unwrap();
assert_eq!(transfers_for_asset.len(), 1);
let transfer = transfers_for_asset.first().unwrap();
let (transfer_data, _) = get_test_transfer_data(&wallet, transfer);
assert_eq!(rcv_transfer_data.status, TransferStatus::Settled);
assert_eq!(transfer_data.status, TransferStatus::Settled);
let unspents = test_list_unspents(&wallet, None, true);
let found = unspents.iter().any(|u| {
u.rgb_allocations
.iter()
.any(|a| a.asset_id == Some(asset.asset_id.clone()))
});
assert!(!found);
let unspents = test_list_unspents(&wallet, None, true);
let found = unspents.iter().any(|u| {
u.rgb_allocations
.iter()
.any(|a| a.asset_id == Some(asset_blank.asset_id.clone()))
});
assert!(found);
}
#[test]
#[parallel]
fn send_twice_success() {
initialize();
let amount_1: u64 = 66;
let amount_2: u64 = 33;
let (wallet, online) = get_funded_wallet!();
let (rcv_wallet, rcv_online) = get_funded_wallet!();
let asset = test_issue_asset_nia(&wallet, &online, None);
let receive_data_1 = test_blind_receive(&rcv_wallet);
let recipient_map = HashMap::from([(
asset.asset_id.clone(),
vec![Recipient {
amount: amount_1,
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data_1.recipient_id).unwrap(),
),
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
)]);
let txid_1 = test_send(&wallet, &online, &recipient_map);
assert!(!txid_1.is_empty());
test_refresh_all(&rcv_wallet, &rcv_online);
test_refresh_asset(&wallet, &online, &asset.asset_id);
mine(false);
test_refresh_all(&rcv_wallet, &rcv_online);
test_refresh_asset(&wallet, &online, &asset.asset_id);
let rcv_transfer = get_test_transfer_recipient(&rcv_wallet, &receive_data_1.recipient_id);
let (rcv_transfer_data, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer);
let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid_1);
let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer);
assert_eq!(rcv_transfer.amount, amount_1.to_string());
assert_eq!(transfer.amount, amount_1.to_string());
assert_eq!(rcv_transfer_data.status, TransferStatus::Settled);
assert_eq!(transfer_data.status, TransferStatus::Settled);
let unspents = test_list_unspents(&wallet, None, true);
let change_unspent = unspents
.into_iter()
.find(|u| Some(u.utxo.outpoint.clone()) == transfer_data.change_utxo)
.unwrap();
let change_allocations = change_unspent.rgb_allocations;
assert_eq!(change_allocations.len(), 1);
assert_eq!(
change_allocations.first().unwrap().amount,
AMOUNT - amount_1
);
let receive_data_2 = test_blind_receive(&rcv_wallet);
let recipient_map = HashMap::from([(
asset.asset_id.clone(),
vec![Recipient {
amount: amount_2,
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data_2.recipient_id).unwrap(),
),
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
)]);
let txid_2 = test_send(&wallet, &online, &recipient_map);
assert!(!txid_2.is_empty());
test_refresh_all(&rcv_wallet, &rcv_online);
test_refresh_asset(&wallet, &online, &asset.asset_id);
mine(false);
rcv_wallet.refresh(rcv_online, None, vec![]).unwrap();
test_refresh_asset(&wallet, &online, &asset.asset_id);
let rcv_transfer = get_test_transfer_recipient(&rcv_wallet, &receive_data_2.recipient_id);
let (rcv_transfer_data, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer);
let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid_2);
let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer);
assert_eq!(rcv_transfer.amount, amount_2.to_string());
assert_eq!(transfer.amount, amount_2.to_string());
assert_eq!(rcv_transfer_data.status, TransferStatus::Settled);
assert_eq!(transfer_data.status, TransferStatus::Settled);
let unspents = test_list_unspents(&wallet, None, true);
let change_unspent = unspents
.into_iter()
.find(|u| Some(u.utxo.outpoint.clone()) == transfer_data.change_utxo)
.unwrap();
let change_allocations = change_unspent.rgb_allocations;
assert_eq!(change_allocations.len(), 1);
assert_eq!(
change_allocations.first().unwrap().amount,
AMOUNT - amount_1 - amount_2
);
}
#[test]
#[parallel]
fn send_blank_success() {
initialize();
fn check_state_map_asset_amount(asset_state_map: &BTreeMap<Opout, TypedState>, amount: u64) {
for typed_state in asset_state_map.values() {
if *typed_state == TypedState::Amount(amount) {
return;
}
}
panic!("unexpected");
}
let amount_1: u64 = 66;
let amount_2: u64 = 7;
let (wallet_1, online_1) = get_funded_noutxo_wallet!();
let (wallet_2, online_2) = get_funded_wallet!();
test_create_utxos(&wallet_1, &online_1, false, Some(1), None, FEE_RATE);
let asset_nia = test_issue_asset_nia(&wallet_1, &online_1, None);
let asset_nia_cid = ContractId::from_str(&asset_nia.asset_id).unwrap();
let asset_cfa = test_issue_asset_cfa(&wallet_1, &online_1, Some(&[AMOUNT * 2]), None);
let asset_cfa_cid = ContractId::from_str(&asset_cfa.asset_id).unwrap();
let unspents = test_list_unspents(&wallet_1, None, true);
let unspents_with_rgb_allocations: Vec<Unspent> = unspents
.into_iter()
.filter(|u| !u.rgb_allocations.is_empty())
.collect();
assert_eq!(unspents_with_rgb_allocations.len(), 1);
let allocation_asset_ids: Vec<String> = unspents_with_rgb_allocations
.first()
.unwrap()
.rgb_allocations
.clone()
.into_iter()
.map(|a| a.asset_id.unwrap_or_else(|| s!("")))
.collect();
assert!(allocation_asset_ids.contains(&asset_nia.asset_id));
assert!(allocation_asset_ids.contains(&asset_cfa.asset_id));
show_unspent_colorings(&wallet_1, "wallet 1 after issuance");
println!("\n=== send 1");
test_create_utxos(&wallet_1, &online_1, false, Some(1), None, FEE_RATE);
let receive_data_1 = test_blind_receive(&wallet_2);
let recipient_map = HashMap::from([(
asset_nia.asset_id.clone(),
vec![Recipient {
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data_1.recipient_id).unwrap(),
),
amount: amount_1,
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
)]);
let txid_1 = test_send(&wallet_1, &online_1, &recipient_map);
assert!(!txid_1.is_empty());
show_unspent_colorings(&wallet_1, "wallet 1 after send 1, WaitingCounterparty");
wallet_2.refresh(online_2.clone(), None, vec![]).unwrap();
test_refresh_asset(&wallet_1, &online_1, &asset_nia.asset_id);
mine(false);
wallet_2.refresh(online_2.clone(), None, vec![]).unwrap();
test_refresh_asset(&wallet_1, &online_1, &asset_nia.asset_id);
let transfers_w1 = test_list_transfers(&wallet_1, Some(&asset_nia.asset_id));
let transfer_w1 = transfers_w1.last().unwrap();
let transfers_w2 = test_list_transfers(&wallet_2, Some(&asset_nia.asset_id));
let transfer_w2 = transfers_w2.last().unwrap();
assert_eq!(transfer_w1.status, TransferStatus::Settled);
assert_eq!(transfer_w1.amount, amount_1);
assert_eq!(transfer_w1.kind, TransferKind::Send);
assert_eq!(transfer_w2.status, TransferStatus::Settled);
assert_eq!(transfer_w2.amount, amount_1);
assert_eq!(transfer_w2.kind, TransferKind::ReceiveBlind);
let change_utxo = transfer_w1.change_utxo.as_ref().unwrap();
let unspents = test_list_unspents(&wallet_1, None, true);
let change_unspent = unspents
.into_iter()
.find(|u| u.utxo.outpoint == *change_utxo)
.unwrap();
let change_allocations = change_unspent.rgb_allocations;
assert_eq!(change_allocations.len(), 2);
let ca_a1 = change_allocations
.iter()
.find(|a| a.asset_id == Some(asset_nia.asset_id.clone()))
.unwrap();
let ca_a2 = change_allocations
.iter()
.find(|a| a.asset_id == Some(asset_cfa.asset_id.clone()))
.unwrap();
assert_eq!(ca_a1.amount, AMOUNT - amount_1);
assert_eq!(ca_a1.asset_id, Some(asset_nia.asset_id.clone()));
assert!(ca_a1.settled);
assert_eq!(ca_a2.amount, AMOUNT * 2);
assert_eq!(ca_a2.asset_id, Some(asset_cfa.asset_id.clone()));
assert!(ca_a2.settled);
let mut change_outpoint_set = BTreeSet::new();
change_outpoint_set.insert(RgbOutpoint::from(change_utxo.clone()));
let state_map_nia_w1 = wallet_1
._rgb_runtime()
.unwrap()
.state_for_outpoints(asset_nia_cid, change_outpoint_set.clone())
.unwrap();
check_state_map_asset_amount(&state_map_nia_w1, ca_a1.amount);
let state_map_cfa_w1 = wallet_1
._rgb_runtime()
.unwrap()
.state_for_outpoints(asset_cfa_cid, change_outpoint_set.clone())
.unwrap();
check_state_map_asset_amount(&state_map_cfa_w1, ca_a2.amount);
let receive_data_2 = test_blind_receive(&wallet_2);
println!("\n=== send 2");
let recipient_map = HashMap::from([(
asset_cfa.asset_id.clone(),
vec![Recipient {
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data_2.recipient_id).unwrap(),
),
amount: amount_2,
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
)]);
let txid_2 = test_send(&wallet_1, &online_1, &recipient_map);
assert!(!txid_2.is_empty());
show_unspent_colorings(&wallet_1, "wallet 1 after send 2, WaitingCounterparty");
wallet_2.refresh(online_2.clone(), None, vec![]).unwrap();
test_refresh_asset(&wallet_1, &online_1, &asset_cfa.asset_id);
mine(false);
wallet_2.refresh(online_2, None, vec![]).unwrap();
test_refresh_asset(&wallet_1, &online_1, &asset_cfa.asset_id);
let transfers_w2 = test_list_transfers(&wallet_2, Some(&asset_cfa.asset_id));
let transfer_w2 = transfers_w2.last().unwrap();
let transfers_w1 = test_list_transfers(&wallet_1, Some(&asset_cfa.asset_id));
let transfer_w1 = transfers_w1.last().unwrap();
assert_eq!(transfer_w1.status, TransferStatus::Settled);
assert_eq!(transfer_w1.amount, amount_2);
assert_eq!(transfer_w1.kind, TransferKind::Send);
assert_eq!(transfer_w2.status, TransferStatus::Settled);
assert_eq!(transfer_w2.amount, amount_2);
assert_eq!(transfer_w2.kind, TransferKind::ReceiveBlind);
let change_utxo = transfer_w1.change_utxo.as_ref().unwrap();
let unspents = test_list_unspents(&wallet_1, None, true);
let change_unspent = unspents
.into_iter()
.find(|u| u.utxo.outpoint == *change_utxo)
.unwrap();
let change_allocations = change_unspent.rgb_allocations;
assert_eq!(change_allocations.len(), 2);
let ca_a1 = change_allocations
.iter()
.find(|a| a.asset_id == Some(asset_nia.asset_id.clone()))
.unwrap();
let ca_a2 = change_allocations
.iter()
.find(|a| a.asset_id == Some(asset_cfa.asset_id.clone()))
.unwrap();
assert_eq!(ca_a1.amount, AMOUNT - amount_1);
assert_eq!(ca_a1.asset_id, Some(asset_nia.asset_id.clone()));
assert!(ca_a1.settled);
assert_eq!(ca_a2.amount, AMOUNT * 2 - amount_2);
assert_eq!(ca_a2.asset_id, Some(asset_cfa.asset_id.clone()));
assert!(ca_a2.settled);
let mut change_outpoint_set = BTreeSet::new();
change_outpoint_set.insert(RgbOutpoint::from(change_utxo.clone()));
let state_map_nia_w1 = wallet_1
._rgb_runtime()
.unwrap()
.state_for_outpoints(asset_nia_cid, change_outpoint_set.clone())
.unwrap();
check_state_map_asset_amount(&state_map_nia_w1, ca_a1.amount);
let state_map_cfa_w1 = wallet_1
._rgb_runtime()
.unwrap()
.state_for_outpoints(asset_cfa_cid, change_outpoint_set.clone())
.unwrap();
check_state_map_asset_amount(&state_map_cfa_w1, ca_a2.amount);
}
#[test]
#[parallel]
fn send_received_success() {
initialize();
let amount_1a: u64 = 66;
let amount_1b: u64 = 33;
let amount_2a: u64 = 7;
let amount_2b: u64 = 4;
let file_str = "README.md";
let (wallet_1, online_1) = get_funded_wallet!();
let (wallet_2, online_2) = get_funded_wallet!(true, true);
let (wallet_3, online_3) = get_funded_wallet!();
let asset_nia = test_issue_asset_nia(&wallet_1, &online_1, None);
let asset_cfa = test_issue_asset_cfa(
&wallet_1,
&online_1,
Some(&[AMOUNT * 2]),
Some(file_str.to_string()),
);
let receive_data_a20 = test_blind_receive(&wallet_2);
let receive_data_a25 = test_blind_receive(&wallet_2);
let recipient_map = HashMap::from([
(
asset_nia.asset_id.clone(),
vec![Recipient {
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data_a20.recipient_id).unwrap(),
),
amount: amount_1a,
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
),
(
asset_cfa.asset_id.clone(),
vec![Recipient {
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data_a25.recipient_id).unwrap(),
),
amount: amount_1b,
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
),
]);
let txid_1 = test_send(&wallet_1, &online_1, &recipient_map);
assert!(!txid_1.is_empty());
wallet_2.refresh(online_2.clone(), None, vec![]).unwrap();
wallet_1.refresh(online_1.clone(), None, vec![]).unwrap();
mine(false);
wallet_2.refresh(online_2.clone(), None, vec![]).unwrap();
wallet_1.refresh(online_1, None, vec![]).unwrap();
let (transfers_w1, _, _) = get_test_transfers_sender(&wallet_1, &txid_1);
let transfers_for_asset_nia = transfers_w1.get(&asset_nia.asset_id).unwrap();
let transfers_for_asset_cfa = transfers_w1.get(&asset_cfa.asset_id).unwrap();
assert_eq!(transfers_for_asset_nia.len(), 1);
assert_eq!(transfers_for_asset_cfa.len(), 1);
let transfer_w1a = transfers_for_asset_nia.first().unwrap();
let transfer_w1b = transfers_for_asset_cfa.first().unwrap();
let transfer_w2a = get_test_transfer_recipient(&wallet_2, &receive_data_a20.recipient_id);
let transfer_w2b = get_test_transfer_recipient(&wallet_2, &receive_data_a25.recipient_id);
let (transfer_data_w1a, _) = get_test_transfer_data(&wallet_1, transfer_w1a);
let (transfer_data_w1b, _) = get_test_transfer_data(&wallet_1, transfer_w1b);
let (transfer_data_w2a, _) = get_test_transfer_data(&wallet_2, &transfer_w2a);
let (transfer_data_w2b, _) = get_test_transfer_data(&wallet_2, &transfer_w2b);
assert_eq!(transfer_w1a.amount, amount_1a.to_string());
assert_eq!(transfer_w1b.amount, amount_1b.to_string());
assert_eq!(transfer_w2a.amount, amount_1a.to_string());
assert_eq!(transfer_w2b.amount, amount_1b.to_string());
assert_eq!(transfer_data_w1a.status, TransferStatus::Settled);
assert_eq!(transfer_data_w1b.status, TransferStatus::Settled);
assert_eq!(transfer_data_w2a.status, TransferStatus::Settled);
assert_eq!(transfer_data_w2b.status, TransferStatus::Settled);
let unspents = test_list_unspents(&wallet_1, None, true);
let change_unspent = unspents
.into_iter()
.find(|u| Some(u.utxo.outpoint.clone()) == transfer_data_w1a.change_utxo)
.unwrap();
let change_allocations = change_unspent.rgb_allocations;
let change_allocation_a = change_allocations
.iter()
.find(|a| a.asset_id == Some(asset_nia.asset_id.clone()))
.unwrap();
let change_allocation_b = change_allocations
.iter()
.find(|a| a.asset_id == Some(asset_cfa.asset_id.clone()))
.unwrap();
assert_eq!(change_allocations.len(), 2);
assert_eq!(change_allocation_a.amount, AMOUNT - amount_1a);
assert_eq!(change_allocation_b.amount, AMOUNT * 2 - amount_1b);
let receive_data_b20 = test_blind_receive(&wallet_3);
let receive_data_b25 = test_blind_receive(&wallet_3);
let recipient_map = HashMap::from([
(
asset_nia.asset_id.clone(),
vec![Recipient {
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data_b20.recipient_id).unwrap(),
),
amount: amount_2a,
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
),
(
asset_cfa.asset_id.clone(),
vec![Recipient {
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data_b25.recipient_id).unwrap(),
),
amount: amount_2b,
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
),
]);
let txid_2 = test_send(&wallet_2, &online_2, &recipient_map);
assert!(!txid_2.is_empty());
wallet_3.refresh(online_3.clone(), None, vec![]).unwrap();
wallet_2.refresh(online_2.clone(), None, vec![]).unwrap();
mine(false);
wallet_3.refresh(online_3, None, vec![]).unwrap();
wallet_2.refresh(online_2, None, vec![]).unwrap();
let (transfers_w2, _, _) = get_test_transfers_sender(&wallet_2, &txid_2);
let transfers_for_asset_nia = transfers_w2.get(&asset_nia.asset_id).unwrap();
let transfers_for_asset_cfa = transfers_w2.get(&asset_cfa.asset_id).unwrap();
assert_eq!(transfers_for_asset_nia.len(), 1);
assert_eq!(transfers_for_asset_cfa.len(), 1);
let transfer_w2a = transfers_for_asset_nia.first().unwrap();
let transfer_w2b = transfers_for_asset_cfa.first().unwrap();
let transfer_w3a = get_test_transfer_recipient(&wallet_3, &receive_data_b20.recipient_id);
let transfer_w3b = get_test_transfer_recipient(&wallet_3, &receive_data_b25.recipient_id);
let (transfer_data_w2a, _) = get_test_transfer_data(&wallet_2, transfer_w2a);
let (transfer_data_w2b, _) = get_test_transfer_data(&wallet_2, transfer_w2b);
let (transfer_data_w3a, _) = get_test_transfer_data(&wallet_3, &transfer_w3a);
let (transfer_data_w3b, _) = get_test_transfer_data(&wallet_3, &transfer_w3b);
assert_eq!(transfer_w2a.amount, amount_2a.to_string());
assert_eq!(transfer_w2b.amount, amount_2b.to_string());
assert_eq!(transfer_w3a.amount, amount_2a.to_string());
assert_eq!(transfer_w3b.amount, amount_2b.to_string());
assert_eq!(transfer_data_w2a.status, TransferStatus::Settled);
assert_eq!(transfer_data_w2b.status, TransferStatus::Settled);
assert_eq!(transfer_data_w3a.status, TransferStatus::Settled);
assert_eq!(transfer_data_w3b.status, TransferStatus::Settled);
let unspents = test_list_unspents(&wallet_2, None, true);
let change_unspent = unspents
.into_iter()
.find(|u| Some(u.utxo.outpoint.clone()) == transfer_data_w2a.change_utxo)
.unwrap();
let change_allocations = change_unspent.rgb_allocations;
let change_allocation_a = change_allocations
.iter()
.find(|a| a.asset_id == Some(asset_nia.asset_id.clone()))
.unwrap();
let change_allocation_b = change_allocations
.iter()
.find(|a| a.asset_id == Some(asset_cfa.asset_id.clone()))
.unwrap();
assert_eq!(change_allocations.len(), 2);
assert_eq!(change_allocation_a.amount, amount_1a - amount_2a);
assert_eq!(change_allocation_b.amount, amount_1b - amount_2b);
let cfa_assets = wallet_3
.list_assets(vec![AssetSchema::Cfa])
.unwrap()
.cfa
.unwrap();
assert_eq!(cfa_assets.len(), 1);
let recv_asset = cfa_assets.first().unwrap();
let dst_path = recv_asset.media.as_ref().unwrap().file_path.clone();
let src_bytes = std::fs::read(PathBuf::from(file_str)).unwrap();
let dst_bytes = std::fs::read(PathBuf::from(dst_path.clone())).unwrap();
assert_eq!(src_bytes, dst_bytes);
let src_hash: sha256::Hash = Sha256Hash::hash(&src_bytes[..]);
let src_attachment_id = hex::encode(src_hash.to_byte_array());
let dst_attachment_id = Path::new(&dst_path)
.parent()
.unwrap()
.file_name()
.unwrap()
.to_string_lossy();
assert_eq!(src_attachment_id, dst_attachment_id);
}
#[test]
#[parallel]
fn send_received_cfa_success() {
initialize();
let amount_1: u64 = 66;
let amount_2: u64 = 7;
let file_str = "README.md";
let (wallet_1, online_1) = get_funded_wallet!();
let (wallet_2, online_2) = get_funded_wallet!();
let (wallet_3, online_3) = get_funded_wallet!();
let asset = test_issue_asset_cfa(&wallet_1, &online_1, None, Some(file_str.to_string()));
let receive_data_1 = test_blind_receive(&wallet_2);
let recipient_map = HashMap::from([(
asset.asset_id.clone(),
vec![Recipient {
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data_1.recipient_id).unwrap(),
),
amount: amount_1,
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
)]);
let txid_1 = test_send(&wallet_1, &online_1, &recipient_map);
assert!(!txid_1.is_empty());
wallet_2.refresh(online_2.clone(), None, vec![]).unwrap();
test_refresh_asset(&wallet_1, &online_1, &asset.asset_id);
mine(false);
wallet_2.refresh(online_2.clone(), None, vec![]).unwrap();
test_refresh_asset(&wallet_1, &online_1, &asset.asset_id);
let (transfer_w1, _, _) = get_test_transfer_sender(&wallet_1, &txid_1);
let transfer_w2 = get_test_transfer_recipient(&wallet_2, &receive_data_1.recipient_id);
let (transfer_data_w1, _) = get_test_transfer_data(&wallet_1, &transfer_w1);
let (transfer_data_w2, _) = get_test_transfer_data(&wallet_2, &transfer_w2);
assert_eq!(transfer_w1.amount, amount_1.to_string());
assert_eq!(transfer_w2.amount, amount_1.to_string());
assert_eq!(transfer_data_w1.status, TransferStatus::Settled);
assert_eq!(transfer_data_w2.status, TransferStatus::Settled);
let unspents = test_list_unspents(&wallet_1, None, true);
let change_unspent = unspents
.into_iter()
.find(|u| Some(u.utxo.outpoint.clone()) == transfer_data_w1.change_utxo)
.unwrap();
let change_allocations = change_unspent.rgb_allocations;
assert_eq!(change_allocations.len(), 1);
assert_eq!(
change_allocations.first().unwrap().amount,
AMOUNT - amount_1
);
let receive_data_2 = test_blind_receive(&wallet_3);
let recipient_map = HashMap::from([(
asset.asset_id.clone(),
vec![Recipient {
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data_2.recipient_id).unwrap(),
),
amount: amount_2,
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
)]);
let txid_2 = test_send(&wallet_2, &online_2, &recipient_map);
assert!(!txid_2.is_empty());
wallet_3.refresh(online_3.clone(), None, vec![]).unwrap();
test_refresh_asset(&wallet_2, &online_2, &asset.asset_id);
mine(false);
wallet_3.refresh(online_3, None, vec![]).unwrap();
test_refresh_asset(&wallet_2, &online_2, &asset.asset_id);
let transfer_w3 = get_test_transfer_recipient(&wallet_3, &receive_data_2.recipient_id);
let (transfer_w2, _, _) = get_test_transfer_sender(&wallet_2, &txid_2);
let (transfer_data_w3, _) = get_test_transfer_data(&wallet_3, &transfer_w3);
let (transfer_data_w2, _) = get_test_transfer_data(&wallet_2, &transfer_w2);
assert_eq!(transfer_w3.amount, amount_2.to_string());
assert_eq!(transfer_w2.amount, amount_2.to_string());
assert_eq!(transfer_data_w3.status, TransferStatus::Settled);
assert_eq!(transfer_data_w2.status, TransferStatus::Settled);
let unspents = test_list_unspents(&wallet_2, None, true);
let change_unspent = unspents
.into_iter()
.find(|u| Some(u.utxo.outpoint.clone()) == transfer_data_w2.change_utxo)
.unwrap();
let change_allocations = change_unspent.rgb_allocations;
assert_eq!(change_allocations.len(), 1);
assert_eq!(
change_allocations.first().unwrap().amount,
amount_1 - amount_2
);
let cfa_assets = wallet_3
.list_assets(vec![AssetSchema::Cfa])
.unwrap()
.cfa
.unwrap();
assert_eq!(cfa_assets.len(), 1);
let recv_asset = cfa_assets.first().unwrap();
assert_eq!(recv_asset.asset_id, asset.asset_id);
assert_eq!(recv_asset.name, NAME.to_string());
assert_eq!(recv_asset.description, Some(DESCRIPTION.to_string()));
assert_eq!(recv_asset.precision, PRECISION);
assert_eq!(
recv_asset.balance,
Balance {
settled: amount_2,
future: amount_2,
spendable: amount_2,
}
);
let media = recv_asset.media.as_ref().unwrap();
assert_eq!(media.mime, "text/plain");
let dst_path = media.file_path.clone();
let src_bytes = std::fs::read(PathBuf::from(file_str)).unwrap();
let dst_bytes = std::fs::read(PathBuf::from(dst_path.clone())).unwrap();
assert_eq!(src_bytes, dst_bytes);
let src_hash: sha256::Hash = Sha256Hash::hash(&src_bytes[..]);
let src_attachment_id = hex::encode(src_hash.to_byte_array());
let dst_attachment_id = Path::new(&dst_path)
.parent()
.unwrap()
.file_name()
.unwrap()
.to_string_lossy();
assert_eq!(src_attachment_id, dst_attachment_id);
}
#[test]
#[parallel]
fn receive_multiple_same_asset_success() {
initialize();
let amount_1: u64 = 66;
let amount_2: u64 = 33;
let (wallet, online) = get_funded_wallet!();
let (rcv_wallet, rcv_online) = get_funded_wallet!();
let asset = test_issue_asset_nia(&wallet, &online, None);
let receive_data_1 = test_blind_receive(&rcv_wallet);
let receive_data_2 = test_blind_receive(&rcv_wallet);
let recipient_map = HashMap::from([(
asset.asset_id.clone(),
vec![
Recipient {
amount: amount_1,
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data_1.recipient_id).unwrap(),
),
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
},
Recipient {
amount: amount_2,
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data_2.recipient_id).unwrap(),
),
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
},
],
)]);
let txid = test_send(&wallet, &online, &recipient_map);
assert!(!txid.is_empty());
let rcv_transfer_1 = get_test_transfer_recipient(&rcv_wallet, &receive_data_1.recipient_id);
let rcv_transfer_2 = get_test_transfer_recipient(&rcv_wallet, &receive_data_2.recipient_id);
let (rcv_transfer_data_1, rcv_asset_transfer_1) =
get_test_transfer_data(&rcv_wallet, &rcv_transfer_1);
let (rcv_transfer_data_2, rcv_asset_transfer_2) =
get_test_transfer_data(&rcv_wallet, &rcv_transfer_2);
let (transfers, asset_transfers, _) = get_test_transfers_sender(&wallet, &txid);
assert_eq!(asset_transfers.len(), 1);
assert_eq!(transfers.len(), 1);
let asset_transfer = asset_transfers.first().unwrap();
let transfers_for_asset = transfers.get(&asset.asset_id).unwrap();
assert_eq!(transfers_for_asset.len(), 2);
let transfer_1 = transfers_for_asset
.iter()
.find(|t| t.recipient_id == Some(receive_data_1.recipient_id.clone()))
.unwrap();
let transfer_2 = transfers_for_asset
.iter()
.find(|t| t.recipient_id == Some(receive_data_2.recipient_id.clone()))
.unwrap();
let (transfer_data_1, _) = get_test_transfer_data(&wallet, transfer_1);
let (transfer_data_2, _) = get_test_transfer_data(&wallet, transfer_2);
assert_eq!(rcv_transfer_1.ack, None);
assert_eq!(rcv_transfer_2.ack, None);
assert_eq!(transfer_1.ack, None);
assert_eq!(transfer_2.ack, None);
assert_eq!(rcv_transfer_1.amount, 0.to_string());
assert_eq!(rcv_transfer_2.amount, 0.to_string());
assert_eq!(transfer_1.amount, amount_1.to_string());
assert_eq!(transfer_2.amount, amount_2.to_string());
assert_eq!(
rcv_transfer_1.recipient_id,
Some(receive_data_1.recipient_id.clone())
);
assert_eq!(
rcv_transfer_2.recipient_id,
Some(receive_data_2.recipient_id.clone())
);
assert_eq!(
transfer_1.recipient_id,
Some(receive_data_1.recipient_id.clone())
);
assert_eq!(
transfer_2.recipient_id,
Some(receive_data_2.recipient_id.clone())
);
assert!(rcv_transfer_data_1.change_utxo.is_none());
assert!(rcv_transfer_data_2.change_utxo.is_none());
assert!(transfer_data_1.change_utxo.is_some());
assert!(transfer_data_2.change_utxo.is_some());
assert_eq!(transfer_data_1.change_utxo, transfer_data_2.change_utxo);
assert_eq!(
rcv_transfer_data_1.created_at,
rcv_transfer_data_1.updated_at
);
assert_eq!(
rcv_transfer_data_2.created_at,
rcv_transfer_data_2.updated_at
);
assert_eq!(transfer_data_1.created_at, transfer_data_1.updated_at);
assert_eq!(transfer_data_2.created_at, transfer_data_2.updated_at);
assert_eq!(
rcv_transfer_data_1.expiration,
Some(rcv_transfer_data_1.created_at + DURATION_RCV_TRANSFER as i64)
);
assert_eq!(
rcv_transfer_data_2.expiration,
Some(rcv_transfer_data_2.created_at + DURATION_RCV_TRANSFER as i64)
);
assert_eq!(
transfer_data_1.expiration,
Some(transfer_data_1.created_at + DURATION_SEND_TRANSFER)
);
assert_eq!(
transfer_data_2.expiration,
Some(transfer_data_2.created_at + DURATION_SEND_TRANSFER)
);
assert_eq!(rcv_transfer_data_1.kind, TransferKind::ReceiveBlind);
assert_eq!(rcv_transfer_data_2.kind, TransferKind::ReceiveBlind);
assert_eq!(transfer_data_1.kind, TransferKind::Send);
assert_eq!(transfer_data_2.kind, TransferKind::Send);
assert_eq!(
rcv_transfer_data_1.status,
TransferStatus::WaitingCounterparty
);
assert_eq!(
rcv_transfer_data_2.status,
TransferStatus::WaitingCounterparty
);
assert_eq!(transfer_data_1.status, TransferStatus::WaitingCounterparty);
assert_eq!(transfer_data_2.status, TransferStatus::WaitingCounterparty);
assert_eq!(rcv_transfer_data_1.txid, None);
assert_eq!(rcv_transfer_data_2.txid, None);
assert_eq!(transfer_data_1.txid, Some(txid.clone()));
assert_eq!(transfer_data_2.txid, Some(txid.clone()));
assert!(rcv_transfer_data_1.receive_utxo.is_some());
assert!(rcv_transfer_data_2.receive_utxo.is_some());
assert!(transfer_data_1.receive_utxo.is_none());
assert!(transfer_data_2.receive_utxo.is_none());
assert!(rcv_asset_transfer_1.asset_id.is_none());
assert!(rcv_asset_transfer_1.asset_id.is_none());
assert!(rcv_asset_transfer_2.asset_id.is_none());
assert!(rcv_asset_transfer_2.asset_id.is_none());
assert_eq!(asset_transfer.asset_id, Some(asset.asset_id.clone()));
assert!(rcv_asset_transfer_1.user_driven);
assert!(rcv_asset_transfer_2.user_driven);
assert!(asset_transfer.user_driven);
stop_mining();
std::thread::sleep(Duration::from_millis(1000)); test_refresh_all(&rcv_wallet, &rcv_online);
test_refresh_asset(&wallet, &online, &asset.asset_id);
let rcv_transfer_1 = get_test_transfer_recipient(&rcv_wallet, &receive_data_1.recipient_id);
let rcv_transfer_2 = get_test_transfer_recipient(&rcv_wallet, &receive_data_2.recipient_id);
let (rcv_transfer_data_1, rcv_asset_transfer_1) =
get_test_transfer_data(&rcv_wallet, &rcv_transfer_1);
let (rcv_transfer_data_2, rcv_asset_transfer_2) =
get_test_transfer_data(&rcv_wallet, &rcv_transfer_2);
let (transfers, _, _) = get_test_transfers_sender(&wallet, &txid);
assert_eq!(transfers.len(), 1);
let transfers_for_asset = transfers.get(&asset.asset_id).unwrap();
assert_eq!(transfers_for_asset.len(), 2);
let transfer_1 = transfers_for_asset
.iter()
.find(|t| t.recipient_id == Some(receive_data_1.recipient_id.clone()))
.unwrap();
let transfer_2 = transfers_for_asset
.iter()
.find(|t| t.recipient_id == Some(receive_data_2.recipient_id.clone()))
.unwrap();
let (transfer_data_1, _) = get_test_transfer_data(&wallet, transfer_1);
let (transfer_data_2, _) = get_test_transfer_data(&wallet, transfer_2);
assert_eq!(
rcv_transfer_data_1.status,
TransferStatus::WaitingConfirmations
);
assert_eq!(
rcv_transfer_data_2.status,
TransferStatus::WaitingConfirmations
);
assert_eq!(transfer_data_1.status, TransferStatus::WaitingConfirmations);
assert_eq!(transfer_data_2.status, TransferStatus::WaitingConfirmations);
assert_eq!(transfer_1.ack, Some(true));
assert_eq!(transfer_2.ack, Some(true));
assert_eq!(rcv_transfer_1.amount, amount_1.to_string());
assert_eq!(rcv_transfer_2.amount, amount_2.to_string());
assert_eq!(rcv_asset_transfer_1.asset_id, Some(asset.asset_id.clone()));
assert_eq!(rcv_asset_transfer_2.asset_id, Some(asset.asset_id.clone()));
let rcv_updated_at_1 = rcv_transfer_data_1.updated_at;
let rcv_updated_at_2 = rcv_transfer_data_2.updated_at;
let updated_at_1 = transfer_data_1.updated_at;
let updated_at_2 = transfer_data_2.updated_at;
assert!(rcv_updated_at_1 > rcv_transfer_data_1.created_at);
assert!(rcv_updated_at_2 > rcv_transfer_data_2.created_at);
assert!(updated_at_1 > transfer_data_1.created_at);
assert!(updated_at_2 > transfer_data_2.created_at);
mine(true);
std::thread::sleep(Duration::from_millis(1000)); rcv_wallet.refresh(rcv_online, None, vec![]).unwrap();
test_refresh_asset(&wallet, &online, &asset.asset_id);
let rcv_transfer_1 = get_test_transfer_recipient(&rcv_wallet, &receive_data_1.recipient_id);
let rcv_transfer_2 = get_test_transfer_recipient(&rcv_wallet, &receive_data_2.recipient_id);
let (rcv_transfer_data_1, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer_1);
let (rcv_transfer_data_2, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer_2);
let (transfers, _, _) = get_test_transfers_sender(&wallet, &txid);
assert_eq!(transfers.len(), 1);
let transfers_for_asset = transfers.get(&asset.asset_id).unwrap();
assert_eq!(transfers_for_asset.len(), 2);
let transfer_1 = transfers_for_asset
.iter()
.find(|t| t.recipient_id == Some(receive_data_1.recipient_id.clone()))
.unwrap();
let transfer_2 = transfers_for_asset
.iter()
.find(|t| t.recipient_id == Some(receive_data_2.recipient_id.clone()))
.unwrap();
let (transfer_data_1, _) = get_test_transfer_data(&wallet, transfer_1);
let (transfer_data_2, _) = get_test_transfer_data(&wallet, transfer_2);
assert_eq!(rcv_transfer_data_1.status, TransferStatus::Settled);
assert_eq!(rcv_transfer_data_2.status, TransferStatus::Settled);
assert_eq!(transfer_data_1.status, TransferStatus::Settled);
assert_eq!(transfer_data_2.status, TransferStatus::Settled);
assert!(rcv_transfer_data_1.updated_at > rcv_updated_at_1);
assert!(rcv_transfer_data_2.updated_at > rcv_updated_at_2);
assert!(transfer_data_1.updated_at > updated_at_1);
assert!(transfer_data_2.updated_at > updated_at_1);
let unspents = test_list_unspents(&wallet, None, true);
let change_unspent = unspents
.into_iter()
.find(|u| Some(u.utxo.outpoint.clone()) == transfer_data_1.change_utxo);
assert!(change_unspent.is_some());
}
#[test]
#[parallel]
fn receive_multiple_different_assets_success() {
initialize();
let amount_1: u64 = 66;
let amount_2: u64 = 33;
let (wallet, online) = get_funded_wallet!();
let (rcv_wallet, rcv_online) = get_funded_wallet!();
let asset_1 = test_issue_asset_nia(&wallet, &online, None);
let asset_2 = wallet
.issue_asset_cfa(
online.clone(),
s!("NAME2"),
Some(DESCRIPTION.to_string()),
PRECISION,
vec![AMOUNT * 2],
None,
)
.unwrap();
let receive_data_1 = test_blind_receive(&rcv_wallet);
let receive_data_2 = test_blind_receive(&rcv_wallet);
let recipient_map = HashMap::from([
(
asset_1.asset_id.clone(),
vec![Recipient {
amount: amount_1,
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data_1.recipient_id).unwrap(),
),
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
),
(
asset_2.asset_id.clone(),
vec![Recipient {
amount: amount_2,
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data_2.recipient_id).unwrap(),
),
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
),
]);
let txid = test_send(&wallet, &online, &recipient_map);
assert!(!txid.is_empty());
let rcv_transfer_1 = get_test_transfer_recipient(&rcv_wallet, &receive_data_1.recipient_id);
let rcv_transfer_2 = get_test_transfer_recipient(&rcv_wallet, &receive_data_2.recipient_id);
let (rcv_transfer_data_1, rcv_asset_transfer_1) =
get_test_transfer_data(&rcv_wallet, &rcv_transfer_1);
let (rcv_transfer_data_2, rcv_asset_transfer_2) =
get_test_transfer_data(&rcv_wallet, &rcv_transfer_2);
let (transfers, asset_transfers, _) = get_test_transfers_sender(&wallet, &txid);
assert_eq!(asset_transfers.len(), 2);
assert_eq!(transfers.len(), 2);
let asset_transfer_1 = asset_transfers
.iter()
.find(|a| a.asset_id == Some(asset_1.asset_id.clone()))
.unwrap();
let asset_transfer_2 = asset_transfers
.iter()
.find(|a| a.asset_id == Some(asset_2.asset_id.clone()))
.unwrap();
let transfers_for_asset_1 = transfers.get(&asset_1.asset_id).unwrap();
let transfers_for_asset_2 = transfers.get(&asset_2.asset_id).unwrap();
assert_eq!(transfers_for_asset_1.len(), 1);
assert_eq!(transfers_for_asset_2.len(), 1);
let transfer_1 = transfers_for_asset_1.first().unwrap();
let transfer_2 = transfers_for_asset_2.first().unwrap();
let (transfer_data_1, _) = get_test_transfer_data(&wallet, transfer_1);
let (transfer_data_2, _) = get_test_transfer_data(&wallet, transfer_2);
assert_eq!(rcv_transfer_1.ack, None);
assert_eq!(rcv_transfer_2.ack, None);
assert_eq!(transfer_1.ack, None);
assert_eq!(transfer_2.ack, None);
assert_eq!(rcv_transfer_1.amount, 0.to_string());
assert_eq!(rcv_transfer_2.amount, 0.to_string());
assert_eq!(transfer_1.amount, amount_1.to_string());
assert_eq!(transfer_2.amount, amount_2.to_string());
assert_eq!(
rcv_transfer_1.recipient_id,
Some(receive_data_1.recipient_id.clone())
);
assert_eq!(
rcv_transfer_2.recipient_id,
Some(receive_data_2.recipient_id.clone())
);
assert_eq!(
transfer_1.recipient_id,
Some(receive_data_1.recipient_id.clone())
);
assert_eq!(
transfer_2.recipient_id,
Some(receive_data_2.recipient_id.clone())
);
assert!(rcv_transfer_data_1.change_utxo.is_none());
assert!(rcv_transfer_data_2.change_utxo.is_none());
assert!(transfer_data_1.change_utxo.is_some());
assert!(transfer_data_2.change_utxo.is_some());
assert_eq!(transfer_data_1.change_utxo, transfer_data_2.change_utxo);
assert_eq!(
rcv_transfer_data_1.created_at,
rcv_transfer_data_1.updated_at
);
assert_eq!(
rcv_transfer_data_2.created_at,
rcv_transfer_data_2.updated_at
);
assert_eq!(transfer_data_1.created_at, transfer_data_1.updated_at);
assert_eq!(transfer_data_2.created_at, transfer_data_2.updated_at);
assert_eq!(
rcv_transfer_data_1.expiration,
Some(rcv_transfer_data_1.created_at + DURATION_RCV_TRANSFER as i64)
);
assert_eq!(
rcv_transfer_data_2.expiration,
Some(rcv_transfer_data_2.created_at + DURATION_RCV_TRANSFER as i64)
);
assert_eq!(
transfer_data_1.expiration,
Some(transfer_data_1.created_at + DURATION_SEND_TRANSFER)
);
assert_eq!(
transfer_data_2.expiration,
Some(transfer_data_2.created_at + DURATION_SEND_TRANSFER)
);
assert_eq!(rcv_transfer_data_1.kind, TransferKind::ReceiveBlind);
assert_eq!(rcv_transfer_data_2.kind, TransferKind::ReceiveBlind);
assert_eq!(transfer_data_1.kind, TransferKind::Send);
assert_eq!(transfer_data_2.kind, TransferKind::Send);
assert_eq!(
rcv_transfer_data_1.status,
TransferStatus::WaitingCounterparty
);
assert_eq!(
rcv_transfer_data_2.status,
TransferStatus::WaitingCounterparty
);
assert_eq!(transfer_data_1.status, TransferStatus::WaitingCounterparty);
assert_eq!(transfer_data_2.status, TransferStatus::WaitingCounterparty);
assert_eq!(rcv_transfer_data_1.txid, None);
assert_eq!(rcv_transfer_data_2.txid, None);
assert_eq!(transfer_data_1.txid, Some(txid.clone()));
assert_eq!(transfer_data_2.txid, Some(txid.clone()));
assert!(rcv_transfer_data_1.receive_utxo.is_some());
assert!(rcv_transfer_data_2.receive_utxo.is_some());
assert!(transfer_data_1.receive_utxo.is_none());
assert!(transfer_data_2.receive_utxo.is_none());
assert!(rcv_asset_transfer_1.asset_id.is_none());
assert!(rcv_asset_transfer_1.asset_id.is_none());
assert!(rcv_asset_transfer_2.asset_id.is_none());
assert!(rcv_asset_transfer_2.asset_id.is_none());
assert_eq!(asset_transfer_1.asset_id, Some(asset_1.asset_id.clone()));
assert_eq!(asset_transfer_2.asset_id, Some(asset_2.asset_id.clone()));
assert!(rcv_asset_transfer_1.user_driven);
assert!(rcv_asset_transfer_2.user_driven);
assert!(asset_transfer_1.user_driven);
assert!(asset_transfer_2.user_driven);
stop_mining();
std::thread::sleep(Duration::from_millis(1000)); test_refresh_all(&rcv_wallet, &rcv_online);
test_refresh_asset(&wallet, &online, &asset_1.asset_id);
let rcv_transfer_1 = get_test_transfer_recipient(&rcv_wallet, &receive_data_1.recipient_id);
let rcv_transfer_2 = get_test_transfer_recipient(&rcv_wallet, &receive_data_2.recipient_id);
let (rcv_transfer_data_1, rcv_asset_transfer_1) =
get_test_transfer_data(&rcv_wallet, &rcv_transfer_1);
let (rcv_transfer_data_2, rcv_asset_transfer_2) =
get_test_transfer_data(&rcv_wallet, &rcv_transfer_2);
let (transfers, _, _) = get_test_transfers_sender(&wallet, &txid);
assert_eq!(transfers.len(), 2);
let transfers_for_asset_1 = transfers.get(&asset_1.asset_id).unwrap();
let transfers_for_asset_2 = transfers.get(&asset_2.asset_id).unwrap();
assert_eq!(transfers_for_asset_1.len(), 1);
assert_eq!(transfers_for_asset_2.len(), 1);
let transfer_1 = transfers_for_asset_1.first().unwrap();
let transfer_2 = transfers_for_asset_2.first().unwrap();
let (transfer_data_1, _) = get_test_transfer_data(&wallet, transfer_1);
let (transfer_data_2, _) = get_test_transfer_data(&wallet, transfer_2);
assert_eq!(
rcv_transfer_data_1.status,
TransferStatus::WaitingConfirmations
);
assert_eq!(
rcv_transfer_data_2.status,
TransferStatus::WaitingConfirmations
);
assert_eq!(transfer_data_1.status, TransferStatus::WaitingConfirmations);
assert_eq!(transfer_data_2.status, TransferStatus::WaitingConfirmations);
assert_eq!(transfer_1.ack, Some(true));
assert_eq!(transfer_2.ack, Some(true));
assert_eq!(rcv_transfer_1.amount, amount_1.to_string());
assert_eq!(rcv_transfer_2.amount, amount_2.to_string());
assert_eq!(
rcv_asset_transfer_1.asset_id,
Some(asset_1.asset_id.clone())
);
assert_eq!(
rcv_asset_transfer_2.asset_id,
Some(asset_2.asset_id.clone())
);
let rcv_updated_at_1 = rcv_transfer_data_1.updated_at;
let rcv_updated_at_2 = rcv_transfer_data_2.updated_at;
let updated_at_1 = transfer_data_1.updated_at;
let updated_at_2 = transfer_data_2.updated_at;
assert!(rcv_updated_at_1 > rcv_transfer_data_1.created_at);
assert!(rcv_updated_at_2 > rcv_transfer_data_2.created_at);
assert!(updated_at_1 > transfer_data_1.created_at);
assert!(updated_at_2 > transfer_data_2.created_at);
let rcv_assets = test_list_assets(&rcv_wallet, &[]);
let nia_assets = rcv_assets.nia.unwrap();
let cfa_assets = rcv_assets.cfa.unwrap();
assert_eq!(nia_assets.len(), 1);
assert_eq!(cfa_assets.len(), 1);
let rcv_asset_nia = nia_assets.last().unwrap();
assert_eq!(rcv_asset_nia.asset_id, asset_1.asset_id);
assert_eq!(rcv_asset_nia.ticker, TICKER);
assert_eq!(rcv_asset_nia.name, NAME);
assert_eq!(rcv_asset_nia.precision, PRECISION);
assert_eq!(
rcv_asset_nia.balance,
Balance {
settled: 0,
future: amount_1,
spendable: 0,
}
);
let rcv_asset_cfa = cfa_assets.last().unwrap();
assert_eq!(rcv_asset_cfa.asset_id, asset_2.asset_id);
assert_eq!(rcv_asset_cfa.name, s!("NAME2"));
assert_eq!(rcv_asset_cfa.description, Some(DESCRIPTION.to_string()));
assert_eq!(rcv_asset_cfa.precision, PRECISION);
assert_eq!(
rcv_asset_cfa.balance,
Balance {
settled: 0,
future: amount_2,
spendable: 0,
}
);
assert_eq!(rcv_asset_cfa.media, None);
std::thread::sleep(Duration::from_millis(1000)); mine(true);
rcv_wallet.refresh(rcv_online, None, vec![]).unwrap();
test_refresh_asset(&wallet, &online, &asset_1.asset_id);
let rcv_transfer_1 = get_test_transfer_recipient(&rcv_wallet, &receive_data_1.recipient_id);
let rcv_transfer_2 = get_test_transfer_recipient(&rcv_wallet, &receive_data_2.recipient_id);
let (rcv_transfer_data_1, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer_1);
let (rcv_transfer_data_2, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer_2);
let (transfers, _, _) = get_test_transfers_sender(&wallet, &txid);
assert_eq!(transfers.len(), 2);
let transfers_for_asset_1 = transfers.get(&asset_1.asset_id).unwrap();
let transfers_for_asset_2 = transfers.get(&asset_2.asset_id).unwrap();
assert_eq!(transfers_for_asset_1.len(), 1);
assert_eq!(transfers_for_asset_2.len(), 1);
let transfer_1 = transfers_for_asset_1.first().unwrap();
let transfer_2 = transfers_for_asset_2.first().unwrap();
let (transfer_data_1, _) = get_test_transfer_data(&wallet, transfer_1);
let (transfer_data_2, _) = get_test_transfer_data(&wallet, transfer_2);
assert_eq!(rcv_transfer_data_1.status, TransferStatus::Settled);
assert_eq!(rcv_transfer_data_2.status, TransferStatus::Settled);
assert_eq!(transfer_data_1.status, TransferStatus::Settled);
assert_eq!(transfer_data_2.status, TransferStatus::Settled);
assert!(rcv_transfer_data_1.updated_at > rcv_updated_at_1);
assert!(rcv_transfer_data_2.updated_at > rcv_updated_at_2);
assert!(transfer_data_1.updated_at > updated_at_1);
assert!(transfer_data_2.updated_at > updated_at_1);
let unspents = test_list_unspents(&wallet, None, true);
let change_unspent = unspents
.into_iter()
.find(|u| Some(u.utxo.outpoint.clone()) == transfer_data_1.change_utxo);
assert!(change_unspent.is_some());
}
#[test]
#[parallel]
fn batch_donation_success() {
initialize();
let amount_a1 = 11;
let amount_a2 = 12;
let amount_b1 = 25;
let amount_b2 = 22;
let (wallet, online) = get_funded_wallet!();
let (rcv_wallet_1, rcv_online_1) = get_funded_wallet!();
let (rcv_wallet_2, rcv_online_2) = get_funded_wallet!();
let asset_a = test_issue_asset_nia(&wallet, &online, None);
let asset_b = test_issue_asset_nia(&wallet, &online, None);
let _asset_c = test_issue_asset_nia(&wallet, &online, None);
show_unspent_colorings(&wallet, "after issuances");
let unspents = test_list_unspents(&wallet, None, true);
let unspents_with_rgb_allocations = unspents
.into_iter()
.filter(|u| !u.rgb_allocations.is_empty());
assert_eq!(unspents_with_rgb_allocations.count(), 3);
let receive_data_a1 = test_blind_receive(&rcv_wallet_1);
let receive_data_a2 = test_blind_receive(&rcv_wallet_2);
let receive_data_b1 = test_blind_receive(&rcv_wallet_1);
let receive_data_b2 = test_blind_receive(&rcv_wallet_2);
let recipient_map = HashMap::from([
(
asset_a.asset_id.clone(),
vec![
Recipient {
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data_a1.recipient_id).unwrap(),
),
amount: amount_a1,
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
},
Recipient {
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data_a2.recipient_id).unwrap(),
),
amount: amount_a2,
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
},
],
),
(
asset_b.asset_id.clone(),
vec![
Recipient {
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data_b1.recipient_id).unwrap(),
),
amount: amount_b1,
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
},
Recipient {
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data_b2.recipient_id).unwrap(),
),
amount: amount_b2,
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
},
],
),
]);
let txid = wallet
.send(online, recipient_map, true, FEE_RATE, MIN_CONFIRMATIONS)
.unwrap();
assert!(!txid.is_empty());
show_unspent_colorings(&wallet, "after send");
let transfers_a = test_list_transfers(&wallet, Some(&asset_a.asset_id));
let transfer_a = transfers_a.last().unwrap();
let change_utxo = transfer_a.change_utxo.as_ref().unwrap();
let unspents = test_list_unspents(&wallet, None, false);
let change_unspent = unspents
.into_iter()
.find(|u| u.utxo.outpoint == *change_utxo)
.unwrap();
let change_allocations = change_unspent.rgb_allocations;
assert_eq!(change_allocations.len(), 2);
let allocation_a = change_allocations
.iter()
.find(|a| a.asset_id == Some(asset_a.asset_id.clone()));
let allocation_b = change_allocations
.iter()
.find(|a| a.asset_id == Some(asset_b.asset_id.clone()));
assert_eq!(allocation_a.unwrap().amount, AMOUNT - amount_a1 - amount_a2);
assert_eq!(allocation_b.unwrap().amount, AMOUNT - amount_b1 - amount_b2);
test_refresh_all(&rcv_wallet_1, &rcv_online_1);
test_refresh_all(&rcv_wallet_2, &rcv_online_2);
test_list_transfers(&rcv_wallet_1, Some(&asset_a.asset_id));
test_list_transfers(&rcv_wallet_1, Some(&asset_b.asset_id));
test_list_transfers(&rcv_wallet_2, Some(&asset_a.asset_id));
test_list_transfers(&rcv_wallet_2, Some(&asset_b.asset_id));
mine(false);
rcv_wallet_1.refresh(rcv_online_1, None, vec![]).unwrap();
rcv_wallet_2.refresh(rcv_online_2, None, vec![]).unwrap();
test_list_transfers(&rcv_wallet_1, Some(&asset_a.asset_id));
test_list_transfers(&rcv_wallet_1, Some(&asset_b.asset_id));
test_list_transfers(&rcv_wallet_2, Some(&asset_a.asset_id));
test_list_transfers(&rcv_wallet_2, Some(&asset_b.asset_id));
show_unspent_colorings(&wallet, "after send, settled");
}
#[test]
#[parallel]
fn reuse_failed_blinded_success() {
initialize();
let amount: u64 = 66;
let (wallet, online) = get_funded_wallet!();
let (rcv_wallet, _rcv_online) = get_funded_wallet!();
let asset = test_issue_asset_nia(&wallet, &online, None);
let receive_data = rcv_wallet
.blind_receive(
None,
None,
Some(60),
TRANSPORT_ENDPOINTS.clone(),
MIN_CONFIRMATIONS,
)
.unwrap();
let recipient_map = HashMap::from([(
asset.asset_id.clone(),
vec![Recipient {
amount,
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data.recipient_id).unwrap(),
),
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
)]);
let txid = test_send(&wallet, &online, &recipient_map);
assert!(!txid.is_empty());
let result = test_send_result(&wallet, &online, &recipient_map);
assert!(
matches!(result, Err(Error::InsufficientSpendableAssets { asset_id: id }) if id == asset.asset_id)
);
test_fail_transfers_txid(&wallet, &online, &txid);
let result = test_send_result(&wallet, &online, &recipient_map);
assert!(matches!(result, Err(Error::RecipientIDAlreadyUsed)));
}
#[test]
#[parallel]
fn ack() {
initialize();
let amount: u64 = 66;
let (wallet, online) = get_funded_wallet!();
let (rcv_wallet_1, rcv_online_1) = get_funded_wallet!();
let (rcv_wallet_2, rcv_online_2) = get_funded_wallet!();
let asset = test_issue_asset_nia(&wallet, &online, None);
let receive_data_1 = test_blind_receive(&rcv_wallet_1);
let receive_data_2 = test_blind_receive(&rcv_wallet_2);
let recipient_map = HashMap::from([(
asset.asset_id.clone(),
vec![
Recipient {
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data_1.recipient_id).unwrap(),
),
amount,
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
},
Recipient {
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data_2.recipient_id).unwrap(),
),
amount,
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
},
],
)]);
let txid = test_send(&wallet, &online, &recipient_map);
assert!(!txid.is_empty());
assert!(check_test_transfer_status_recipient(
&rcv_wallet_1,
&receive_data_1.recipient_id,
TransferStatus::WaitingCounterparty
));
assert!(check_test_transfer_status_recipient(
&rcv_wallet_2,
&receive_data_2.recipient_id,
TransferStatus::WaitingCounterparty
));
assert!(check_test_transfer_status_sender(
&wallet,
&txid,
TransferStatus::WaitingCounterparty
));
rcv_wallet_1.refresh(rcv_online_1, None, vec![]).unwrap();
assert!(check_test_transfer_status_recipient(
&rcv_wallet_1,
&receive_data_1.recipient_id,
TransferStatus::WaitingConfirmations
));
assert!(check_test_transfer_status_sender(
&wallet,
&txid,
TransferStatus::WaitingCounterparty
));
rcv_wallet_2.refresh(rcv_online_2, None, vec![]).unwrap();
assert!(check_test_transfer_status_recipient(
&rcv_wallet_2,
&receive_data_2.recipient_id,
TransferStatus::WaitingConfirmations
));
test_refresh_asset(&wallet, &online, &asset.asset_id);
assert!(check_test_transfer_status_sender(
&wallet,
&txid,
TransferStatus::WaitingConfirmations
));
}
#[test]
#[parallel]
fn nack() {
initialize();
let amount: u64 = 66;
let (wallet, online) = get_funded_wallet!();
let (rcv_wallet, _rcv_online) = get_funded_wallet!();
let asset = test_issue_asset_nia(&wallet, &online, None);
let receive_data = test_blind_receive(&rcv_wallet);
let recipient_map = HashMap::from([(
asset.asset_id.clone(),
vec![Recipient {
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data.recipient_id).unwrap(),
),
amount,
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
)]);
let txid = test_send(&wallet, &online, &recipient_map);
assert!(!txid.is_empty());
assert!(check_test_transfer_status_recipient(
&rcv_wallet,
&receive_data.recipient_id,
TransferStatus::WaitingCounterparty
));
assert!(check_test_transfer_status_sender(
&wallet,
&txid,
TransferStatus::WaitingCounterparty
));
rcv_wallet
.rest_client
.post_ack(PROXY_URL, receive_data.recipient_id, false)
.unwrap();
test_refresh_asset(&wallet, &online, &asset.asset_id);
assert!(check_test_transfer_status_sender(
&wallet,
&txid,
TransferStatus::Failed
));
}
#[test]
#[parallel]
fn expire() {
initialize();
let amount: u64 = 66;
let (wallet, online) = get_funded_wallet!();
let (rcv_wallet, _rcv_online) = get_funded_wallet!();
let asset = test_issue_asset_nia(&wallet, &online, None);
let receive_data = test_blind_receive(&rcv_wallet);
let recipient_map = HashMap::from([(
asset.asset_id,
vec![Recipient {
amount,
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data.recipient_id).unwrap(),
),
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
)]);
let txid = test_send(&wallet, &online, &recipient_map);
assert!(!txid.is_empty());
let (transfer, _, batch_transfer) = get_test_transfer_sender(&wallet, &txid);
let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer);
assert_eq!(
transfer_data.expiration,
Some(transfer_data.created_at + DURATION_SEND_TRANSFER)
);
let mut updated_transfer: DbBatchTransferActMod = batch_transfer.into();
updated_transfer.expiration = ActiveValue::Set(Some(transfer_data.created_at + 1));
wallet
.database
.update_batch_transfer(&mut updated_transfer)
.unwrap();
std::thread::sleep(std::time::Duration::from_millis(2000));
let mut db_data = wallet.database.get_db_data(false).unwrap();
wallet._handle_expired_transfers(&mut db_data).unwrap();
let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid);
let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer);
assert_eq!(transfer_data.status, TransferStatus::Failed);
}
#[test]
#[parallel]
fn no_change_on_pending_send() {
initialize();
let amount_1: u64 = 66;
let amount_2: u64 = 32;
let (wallet, online) = get_funded_noutxo_wallet!();
let (rcv_wallet, rcv_online) = get_funded_wallet!();
let num_utxos_created = test_create_utxos(&wallet, &online, true, Some(3), None, FEE_RATE);
assert_eq!(num_utxos_created, 3);
let asset_1 = test_issue_asset_nia(&wallet, &online, None);
let unspents = test_list_unspents(&wallet, None, false);
let unspent_1 = unspents
.iter()
.find(|u| {
u.rgb_allocations
.iter()
.any(|a| a.asset_id == Some(asset_1.asset_id.clone()))
})
.unwrap();
let asset_2 = test_issue_asset_nia(&wallet, &online, Some(&[AMOUNT * 2]));
show_unspent_colorings(&wallet, "before 1st send");
let receive_data = test_blind_receive(&rcv_wallet);
let recipient_map = HashMap::from([(
asset_1.asset_id.clone(),
vec![Recipient {
amount: amount_1,
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data.recipient_id).unwrap(),
),
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
)]);
let txid_1 = test_send(&wallet, &online, &recipient_map);
assert!(!txid_1.is_empty());
show_unspent_colorings(&wallet, "before 2nd send");
let receive_data = test_blind_receive(&rcv_wallet);
let recipient_map = HashMap::from([(
asset_2.asset_id.clone(),
vec![Recipient {
amount: amount_2,
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data.recipient_id).unwrap(),
),
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
)]);
let txid_2 = test_send(&wallet, &online, &recipient_map);
assert!(!txid_2.is_empty());
assert!(!unspent_1.rgb_allocations.iter().any(|a| !a.settled));
test_fail_transfers_txid(&wallet, &online, &txid_2);
stop_mining();
show_unspent_colorings(&wallet, "before refresh");
rcv_wallet.refresh(rcv_online, None, vec![]).unwrap();
test_refresh_asset(&wallet, &online, &asset_1.asset_id);
show_unspent_colorings(&wallet, "before 3rd send");
let receive_data = test_blind_receive(&rcv_wallet);
let recipient_map = HashMap::from([(
asset_2.asset_id,
vec![Recipient {
amount: amount_2,
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data.recipient_id).unwrap(),
),
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
)]);
let txid_3 = test_send(&wallet, &online, &recipient_map);
assert!(!txid_3.is_empty());
show_unspent_colorings(&wallet, "after 3rd send");
assert!(!unspent_1.rgb_allocations.iter().any(|a| !a.settled));
resume_mining();
}
#[test]
#[parallel]
fn fail() {
initialize();
let (wallet, online) = get_funded_wallet!();
let (rcv_wallet, _rcv_online) = get_funded_wallet!();
let mut wallet_1_alloc = get_test_wallet(true, Some(1));
let online_1_alloc = test_go_online(&mut wallet_1_alloc, true, None);
fund_wallet(test_get_address(&wallet_1_alloc));
mine(false);
test_create_utxos(
&wallet_1_alloc,
&online_1_alloc,
true,
Some(1),
None,
FEE_RATE,
);
let asset_1_alloc = test_issue_asset_nia(&wallet_1_alloc, &online_1_alloc, None);
let receive_data = rcv_wallet
.blind_receive(
None,
None,
Some(60),
TRANSPORT_ENDPOINTS.clone(),
MIN_CONFIRMATIONS,
)
.unwrap();
let recipient_map = HashMap::from([(
asset_1_alloc.asset_id,
vec![Recipient {
amount: AMOUNT / 2,
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data.recipient_id).unwrap(),
),
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
)]);
let result = test_send_result(&wallet_1_alloc, &online_1_alloc, &recipient_map);
assert!(matches!(result, Err(Error::InsufficientAllocationSlots)));
let asset = test_issue_asset_nia(&wallet, &online, None);
let receive_data = rcv_wallet
.blind_receive(
None,
None,
Some(60),
TRANSPORT_ENDPOINTS.clone(),
MIN_CONFIRMATIONS,
)
.unwrap();
let recipient_map = HashMap::from([(
s!("rgb1inexistent"),
vec![Recipient {
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data.recipient_id).unwrap(),
),
amount: AMOUNT / 2,
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
)]);
let result = test_send_result(&wallet, &online, &recipient_map);
assert!(matches!(result, Err(Error::AssetNotFound { asset_id: _ })));
let recipient_map = HashMap::from([(
asset.asset_id.clone(),
vec![Recipient {
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data.recipient_id).unwrap(),
),
amount: AMOUNT + 1,
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
)]);
let result = test_send_result(&wallet, &online, &recipient_map);
assert!(
matches!(result, Err(Error::InsufficientTotalAssets { asset_id: t }) if t == asset.asset_id)
);
let transport_endpoints = vec![];
let recipient_map = HashMap::from([(
asset.asset_id.clone(),
vec![Recipient {
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data.recipient_id).unwrap(),
),
amount: AMOUNT / 2,
transport_endpoints,
}],
)]);
let result = test_send_begin_result(&wallet, &online, &recipient_map);
let msg = s!("must provide at least a transport endpoint");
assert!(matches!(
result,
Err(Error::InvalidTransportEndpoints { details: m }) if m == msg
));
let transport_endpoints = vec![s!("malformed")];
let recipient_map = HashMap::from([(
asset.asset_id.clone(),
vec![Recipient {
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data.recipient_id).unwrap(),
),
amount: AMOUNT / 2,
transport_endpoints,
}],
)]);
let result = test_send_begin_result(&wallet, &online, &recipient_map);
assert!(matches!(
result,
Err(Error::InvalidTransportEndpoint { details: _ })
));
let transport_endpoints = vec![format!("unknown:{PROXY_HOST}")];
let recipient_map = HashMap::from([(
asset.asset_id.clone(),
vec![Recipient {
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data.recipient_id).unwrap(),
),
amount: AMOUNT / 2,
transport_endpoints,
}],
)]);
let result = test_send_begin_result(&wallet, &online, &recipient_map);
assert!(matches!(
result,
Err(Error::InvalidTransportEndpoint { details: _ })
));
let transport_endpoints = vec![
format!("rpc://127.6.6.6:7777/json-rpc"),
format!("rpc://{PROXY_HOST_MOD_PROTO}"),
];
let recipient_map = HashMap::from([(
asset.asset_id.clone(),
vec![Recipient {
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data.recipient_id).unwrap(),
),
amount: AMOUNT / 2,
transport_endpoints,
}],
)]);
let result = test_send_begin_result(&wallet, &online, &recipient_map);
let msg = s!("no valid transport endpoints");
assert!(matches!(
result,
Err(Error::InvalidTransportEndpoints { details: m }) if m == msg
));
let transport_endpoints = vec![
format!("rgbhttpjsonrpc:127.0.0.1:3000/json-rpc"),
format!("rgbhttpjsonrpc:127.0.0.1:3001/json-rpc"),
format!("rgbhttpjsonrpc:127.0.0.1:3002/json-rpc"),
format!("rgbhttpjsonrpc:127.0.0.1:3003/json-rpc"),
];
let recipient_map = HashMap::from([(
asset.asset_id.clone(),
vec![Recipient {
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data.recipient_id).unwrap(),
),
amount: AMOUNT / 2,
transport_endpoints,
}],
)]);
let result = test_send_begin_result(&wallet, &online, &recipient_map);
let msg = s!("library supports at max 3 transport endpoints");
assert!(matches!(
result,
Err(Error::InvalidTransportEndpoints { details: m }) if m == msg
));
let recipient_map = HashMap::from([(
asset.asset_id.clone(),
vec![Recipient {
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data.recipient_id).unwrap(),
),
amount: AMOUNT / 2,
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
)]);
let result = wallet.send_begin(
online.clone(),
recipient_map.clone(),
false,
0.9,
MIN_CONFIRMATIONS,
);
assert!(matches!(result, Err(Error::InvalidFeeRate { details: m }) if m == FEE_MSG_LOW));
let result = wallet.send_begin(
online.clone(),
recipient_map,
false,
1000.1,
MIN_CONFIRMATIONS,
);
assert!(matches!(result, Err(Error::InvalidFeeRate { details: m }) if m == FEE_MSG_HIGH));
let blinded_utxo = SecretSeal::from_str(&receive_data.recipient_id).unwrap();
let recipient_map = HashMap::from([(
asset.asset_id.clone(),
vec![
Recipient {
recipient_data: RecipientData::BlindedUTXO(blinded_utxo),
amount: AMOUNT / 2,
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
},
Recipient {
recipient_data: RecipientData::BlindedUTXO(blinded_utxo),
amount: AMOUNT / 3,
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
},
],
)]);
let result = test_send_begin_result(&wallet, &online, &recipient_map);
assert!(matches!(result, Err(Error::RecipientIDDuplicated)));
let recipient_map = HashMap::from([(
asset.asset_id,
vec![Recipient {
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data.recipient_id).unwrap(),
),
amount: 0,
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
)]);
let result = test_send_begin_result(&wallet, &online, &recipient_map);
assert!(matches!(result, Err(Error::InvalidAmountZero)));
}
#[test]
#[parallel]
fn pending_incoming_transfer_fail() {
initialize();
let amount_1: u64 = 66;
let amount_2: u64 = 33;
let (wallet, online) = get_funded_wallet!();
let (rcv_wallet, rcv_online) = get_funded_noutxo_wallet!();
test_create_utxos(&rcv_wallet, &rcv_online, false, Some(1), None, FEE_RATE);
let asset = test_issue_asset_nia(&wallet, &online, None);
let receive_data_1 = test_blind_receive(&rcv_wallet);
let recipient_map = HashMap::from([(
asset.asset_id.clone(),
vec![Recipient {
amount: amount_1,
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data_1.recipient_id).unwrap(),
),
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
)]);
let txid_1 = test_send(&wallet, &online, &recipient_map);
assert!(!txid_1.is_empty());
test_refresh_all(&rcv_wallet, &rcv_online);
test_refresh_asset(&wallet, &online, &asset.asset_id);
mine(false);
test_refresh_all(&rcv_wallet, &rcv_online);
test_refresh_asset(&wallet, &online, &asset.asset_id);
show_unspent_colorings(&wallet, "sender after 1st send, settled");
show_unspent_colorings(&rcv_wallet, "receiver after 1st send, settled");
let _receive_data_2 = test_blind_receive(&rcv_wallet);
show_unspent_colorings(&rcv_wallet, "receiver after 2nd blind");
let receive_data = test_blind_receive(&wallet);
let recipient_map = HashMap::from([(
asset.asset_id.clone(),
vec![Recipient {
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data.recipient_id).unwrap(),
),
amount: amount_2,
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
)]);
show_unspent_colorings(&wallet, "sender after 2nd send, WaitingCounterparty");
show_unspent_colorings(&rcv_wallet, "receiver after 2nd send, WaitingCounterparty");
let result = test_send_result(&rcv_wallet, &rcv_online, &recipient_map);
assert!(
matches!(result, Err(Error::InsufficientSpendableAssets { asset_id: t }) if t == asset.asset_id)
);
test_refresh_all(&rcv_wallet, &rcv_online);
test_refresh_asset(&wallet, &online, &asset.asset_id);
let result = test_send_result(&rcv_wallet, &rcv_online, &recipient_map);
assert!(
matches!(result, Err(Error::InsufficientSpendableAssets { asset_id: t }) if t == asset.asset_id)
);
}
#[test]
#[parallel]
fn pending_outgoing_transfer_fail() {
initialize();
let amount: u64 = 66;
let (wallet, online) = get_funded_wallet!();
let (rcv_wallet, rcv_online) = get_funded_wallet!();
let asset = test_issue_asset_nia(&wallet, &online, None);
let receive_data = test_blind_receive(&rcv_wallet);
let recipient_map = HashMap::from([(
asset.asset_id.clone(),
vec![Recipient {
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data.recipient_id).unwrap(),
),
amount,
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
)]);
let txid = test_send(&wallet, &online, &recipient_map);
assert!(!txid.is_empty());
let receive_data = test_blind_receive(&rcv_wallet);
let recipient_map = HashMap::from([(
asset.asset_id.clone(),
vec![Recipient {
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data.recipient_id).unwrap(),
),
amount: amount / 2,
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
)]);
let result = test_send_result(&wallet, &online, &recipient_map);
assert!(
matches!(result, Err(Error::InsufficientSpendableAssets { asset_id: t }) if t == asset.asset_id)
);
rcv_wallet.refresh(rcv_online, None, vec![]).unwrap();
test_refresh_asset(&wallet, &online, &asset.asset_id);
let result = test_send_result(&wallet, &online, &recipient_map);
assert!(
matches!(result, Err(Error::InsufficientSpendableAssets { asset_id: t }) if t == asset.asset_id)
);
}
#[test]
#[parallel]
fn pending_transfer_input_fail() {
initialize();
let amount: u64 = 66;
let (wallet, online) = get_funded_noutxo_wallet!();
let (rcv_wallet, _rcv_online) = get_funded_wallet!();
test_create_utxos(&wallet, &online, false, Some(1), None, FEE_RATE);
let asset = test_issue_asset_nia(&wallet, &online, None);
let _receive_data = test_blind_receive(&wallet);
show_unspent_colorings(&wallet, "sender after blind");
let receive_data = test_blind_receive(&rcv_wallet);
let recipient_map = HashMap::from([(
asset.asset_id.clone(),
vec![Recipient {
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data.recipient_id).unwrap(),
),
amount,
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
)]);
let result = test_send_result(&wallet, &online, &recipient_map);
assert!(
matches!(result, Err(Error::InsufficientSpendableAssets { asset_id: t }) if t == asset.asset_id)
);
}
#[test]
#[parallel]
fn already_used_fail() {
initialize();
let amount: u64 = 66;
let (wallet, online) = get_funded_wallet!();
let (rcv_wallet, _rcv_online) = get_funded_wallet!();
let asset = test_issue_asset_nia(&wallet, &online, Some(&[AMOUNT, AMOUNT * 2, AMOUNT * 3]));
let receive_data = rcv_wallet
.blind_receive(
None,
None,
Some(60),
TRANSPORT_ENDPOINTS.clone(),
MIN_CONFIRMATIONS,
)
.unwrap();
let recipient_map = HashMap::from([(
asset.asset_id,
vec![Recipient {
amount,
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data.recipient_id).unwrap(),
),
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
)]);
let txid = test_send(&wallet, &online, &recipient_map);
assert!(!txid.is_empty());
let result = test_send_result(&wallet, &online, &recipient_map);
assert!(matches!(result, Err(Error::RecipientIDAlreadyUsed)));
}
#[test]
#[parallel]
fn cfa_blank_success() {
initialize();
let (wallet, online) = get_funded_wallet!();
let (rcv_wallet, _rcv_online) = get_funded_wallet!();
let asset_nia = test_issue_asset_nia(&wallet, &online, None);
let _asset_cfa = test_issue_asset_cfa(&wallet, &online, None, None);
let receive_data = test_blind_receive(&rcv_wallet);
let recipient_map = HashMap::from([(
asset_nia.asset_id,
vec![Recipient {
amount: 1,
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data.recipient_id).unwrap(),
),
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
)]);
let result = test_send_begin_result(&wallet, &online, &recipient_map);
assert!(!result.unwrap().is_empty());
}
#[test]
#[parallel]
fn psbt_rgb_consumer_success() {
initialize();
let (wallet, online) = get_funded_noutxo_wallet!();
let (rcv_wallet, _rcv_online) = get_funded_wallet!();
println!("utxo 1");
let num_utxos_created = test_create_utxos(&wallet, &online, true, Some(1), None, FEE_RATE);
assert_eq!(num_utxos_created, 1);
println!("issue 1");
let asset_nia_a = test_issue_asset_nia(&wallet, &online, None);
println!("utxo 2");
let num_utxos_created = test_create_utxos(&wallet, &online, false, Some(1), None, FEE_RATE);
assert_eq!(num_utxos_created, 1);
println!("send_begin 1");
let receive_data_1 = test_blind_receive(&rcv_wallet);
let recipient_map = HashMap::from([(
asset_nia_a.asset_id,
vec![Recipient {
amount: 1,
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data_1.recipient_id).unwrap(),
),
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
)]);
let result = test_send_begin_result(&wallet, &online, &recipient_map);
assert!(!result.unwrap().is_empty());
println!("issue 2");
let asset_nia_b = test_issue_asset_nia(&wallet, &online, None);
println!("send_begin 2");
let receive_data_2 = test_blind_receive(&rcv_wallet);
let recipient_map = HashMap::from([(
asset_nia_b.asset_id.clone(),
vec![Recipient {
amount: 1,
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data_2.recipient_id).unwrap(),
),
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
)]);
let result = test_send_begin_result(&wallet, &online, &recipient_map);
assert!(!result.unwrap().is_empty());
println!("exhaust allocations on current UTXO");
let new_allocation_count = (MAX_ALLOCATIONS_PER_UTXO - 2).max(0);
for _ in 0..new_allocation_count {
let _receive_data = test_blind_receive(&wallet);
}
println!("issue 3");
let asset_nia_c = test_issue_asset_nia(&wallet, &online, None);
test_fail_transfers_all(&wallet, &online);
println!("utxo 3");
let num_utxos_created = test_create_utxos(&wallet, &online, false, Some(1), None, FEE_RATE);
assert_eq!(num_utxos_created, 1);
println!("send_begin 3");
let receive_data_3a = test_blind_receive(&rcv_wallet);
let receive_data_3b = test_blind_receive(&rcv_wallet);
let recipient_map = HashMap::from([
(
asset_nia_b.asset_id,
vec![Recipient {
amount: 1,
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data_3a.recipient_id).unwrap(),
),
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
),
(
asset_nia_c.asset_id,
vec![Recipient {
amount: 1,
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data_3b.recipient_id).unwrap(),
),
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
),
]);
let result = test_send_begin_result(&wallet, &online, &recipient_map);
assert!(!result.unwrap().is_empty());
}
#[test]
#[parallel]
fn insufficient_bitcoins() {
initialize();
let (wallet, online) = get_funded_noutxo_wallet!();
let (rcv_wallet, _rcv_online) = get_funded_wallet!();
let num_utxos_created = test_create_utxos(
&wallet,
&online,
false,
Some(1),
Some(TINY_BTC_AMOUNT),
FEE_RATE,
);
assert_eq!(num_utxos_created, 1);
test_drain_to_keep(&wallet, &online, &test_get_address(&rcv_wallet));
let asset_nia_a = test_issue_asset_nia(&wallet, &online, None);
let unspents = test_list_unspents(&wallet, None, false);
assert_eq!(unspents.len(), 1);
let receive_data_1 = test_blind_receive(&rcv_wallet);
let recipient_map = HashMap::from([(
asset_nia_a.asset_id,
vec![Recipient {
amount: 1,
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data_1.recipient_id).unwrap(),
),
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
)]);
let result = test_send_begin_result(&wallet, &online, &recipient_map);
assert!(matches!(
result,
Err(Error::InsufficientBitcoins {
needed: _,
available: _
})
));
fund_wallet(test_get_address(&wallet));
let num_utxos_created = test_create_utxos(
&wallet,
&online,
false,
Some(1),
Some(TINY_BTC_AMOUNT),
FEE_RATE,
);
assert_eq!(num_utxos_created, 1);
test_drain_to_keep(&wallet, &online, &test_get_address(&rcv_wallet));
let unspents = test_list_unspents(&wallet, None, false);
assert_eq!(unspents.len(), 2);
let txid = test_send(&wallet, &online, &recipient_map);
assert!(!txid.is_empty());
}
#[test]
#[parallel]
fn insufficient_allocations_fail() {
initialize();
let (wallet, online) = get_funded_noutxo_wallet!();
let (rcv_wallet, _rcv_online) = get_funded_wallet!();
let num_utxos_created = test_create_utxos(
&wallet,
&online,
false,
Some(1),
Some(TINY_BTC_AMOUNT),
FEE_RATE,
);
assert_eq!(num_utxos_created, 1);
let asset_nia_a = test_issue_asset_nia(&wallet, &online, None);
let unspents = test_list_unspents(&wallet, None, false);
assert_eq!(unspents.len(), 2);
let receive_data_1 = test_blind_receive(&rcv_wallet);
let recipient_map = HashMap::from([(
asset_nia_a.asset_id,
vec![Recipient {
amount: 1,
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data_1.recipient_id).unwrap(),
),
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
)]);
let result = test_send_begin_result(&wallet, &online, &recipient_map);
assert!(matches!(result, Err(Error::InsufficientAllocationSlots)));
println!("utxo 2");
let num_utxos_created = test_create_utxos(&wallet, &online, false, Some(1), None, FEE_RATE);
assert_eq!(num_utxos_created, 1);
let unspents = test_list_unspents(&wallet, None, false);
assert_eq!(unspents.len(), 3);
let txid = test_send(&wallet, &online, &recipient_map);
assert!(!txid.is_empty());
}
#[test]
#[parallel]
fn insufficient_allocations_success() {
initialize();
let (wallet, online) = get_funded_noutxo_wallet!();
let (rcv_wallet, _rcv_online) = get_funded_wallet!();
let num_utxos_created =
test_create_utxos(&wallet, &online, false, Some(1), Some(300), FEE_RATE);
assert_eq!(num_utxos_created, 1);
let asset_nia_a = test_issue_asset_nia(&wallet, &online, None);
let num_utxos_created = test_create_utxos(&wallet, &online, false, Some(2), None, FEE_RATE);
assert_eq!(num_utxos_created, 2);
let receive_data_1 = test_blind_receive(&rcv_wallet);
let recipient_map = HashMap::from([(
asset_nia_a.asset_id,
vec![Recipient {
amount: 1,
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data_1.recipient_id).unwrap(),
),
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
)]);
let result = test_send_begin_result(&wallet, &online, &recipient_map);
assert!(!result.unwrap().is_empty());
}
#[test]
#[parallel]
fn send_to_oneself() {
initialize();
let amount: u64 = 66;
let (wallet, online) = get_funded_wallet!();
let asset = test_issue_asset_nia(&wallet, &online, None);
let receive_data = test_blind_receive(&wallet);
let recipient_map = HashMap::from([(
asset.asset_id,
vec![Recipient {
amount,
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data.recipient_id).unwrap(),
),
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
)]);
let txid = test_send(&wallet, &online, &recipient_map);
assert!(!txid.is_empty());
stop_mining();
wallet.refresh(online.clone(), None, vec![]).unwrap();
wallet.refresh(online.clone(), None, vec![]).unwrap();
mine(true);
wallet.refresh(online.clone(), None, vec![]).unwrap();
let batch_transfers = get_test_batch_transfers(&wallet, &txid);
assert_eq!(batch_transfers.len(), 2);
for batch_transfer in batch_transfers {
assert_eq!(batch_transfer.status, TransferStatus::Settled);
}
}
#[test]
#[parallel]
fn send_received_back_success() {
initialize();
let amount_1: u64 = 66;
let amount_2: u64 = 33;
let (wallet, online) = get_funded_wallet!();
let (rcv_wallet, rcv_online) = get_funded_wallet!();
let asset = test_issue_asset_nia(&wallet, &online, None);
let receive_data_1 = test_blind_receive(&rcv_wallet);
let recipient_map = HashMap::from([(
asset.asset_id.clone(),
vec![Recipient {
amount: amount_1,
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data_1.recipient_id).unwrap(),
),
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
)]);
let txid_1 = test_send(&wallet, &online, &recipient_map);
assert!(!txid_1.is_empty());
test_refresh_all(&rcv_wallet, &rcv_online);
test_refresh_asset(&wallet, &online, &asset.asset_id);
mine(false);
test_refresh_all(&rcv_wallet, &rcv_online);
test_refresh_asset(&wallet, &online, &asset.asset_id);
let rcv_transfer = get_test_transfer_recipient(&rcv_wallet, &receive_data_1.recipient_id);
let (rcv_transfer_data, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer);
let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid_1);
let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer);
assert_eq!(rcv_transfer_data.status, TransferStatus::Settled);
assert_eq!(transfer_data.status, TransferStatus::Settled);
assert_eq!(rcv_transfer.amount, amount_1.to_string());
assert_eq!(transfer.amount, amount_1.to_string());
let unspents = test_list_unspents(&wallet, None, true);
let change_unspent = unspents
.into_iter()
.find(|u| Some(u.utxo.outpoint.clone()) == transfer_data.change_utxo)
.unwrap();
let change_allocations = change_unspent.rgb_allocations;
assert_eq!(change_allocations.len(), 1);
assert_eq!(
change_allocations.first().unwrap().amount,
AMOUNT - amount_1
);
let receive_data_2 = test_blind_receive(&wallet);
let recipient_map = HashMap::from([(
asset.asset_id.clone(),
vec![Recipient {
amount: amount_2,
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data_2.recipient_id).unwrap(),
),
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
)]);
let txid_2 = test_send(&rcv_wallet, &rcv_online, &recipient_map);
assert!(!txid_2.is_empty());
wallet.refresh(online.clone(), None, vec![]).unwrap();
test_refresh_asset(&rcv_wallet, &rcv_online, &asset.asset_id);
mine(false);
wallet.refresh(online.clone(), None, vec![]).unwrap();
test_refresh_asset(&rcv_wallet, &rcv_online, &asset.asset_id);
let rcv_transfer = get_test_transfer_recipient(&wallet, &receive_data_2.recipient_id);
let (rcv_transfer_data, _) = get_test_transfer_data(&wallet, &rcv_transfer);
let (transfer, _, _) = get_test_transfer_sender(&rcv_wallet, &txid_2);
let (transfer_data, _) = get_test_transfer_data(&rcv_wallet, &transfer);
assert_eq!(rcv_transfer_data.status, TransferStatus::Settled);
assert_eq!(transfer_data.status, TransferStatus::Settled);
assert_eq!(rcv_transfer.amount, amount_2.to_string());
assert_eq!(transfer.amount, amount_2.to_string());
let unspents = test_list_unspents(&rcv_wallet, None, true);
let change_unspent = unspents
.into_iter()
.find(|u| Some(u.utxo.outpoint.clone()) == transfer_data.change_utxo)
.unwrap();
let change_allocations = change_unspent.rgb_allocations;
assert_eq!(change_allocations.len(), 1);
assert_eq!(
change_allocations.first().unwrap().amount,
amount_1 - amount_2
);
show_unspent_colorings(&wallet, "wallet before 3rd transfer");
show_unspent_colorings(&rcv_wallet, "rcv_wallet before 3rd transfer");
let receive_data_3 = test_blind_receive(&rcv_wallet);
let change_3 = 5;
let amount_3 = test_get_asset_balance(&wallet, &asset.asset_id).spendable - change_3;
let recipient_map = HashMap::from([(
asset.asset_id.clone(),
vec![Recipient {
amount: amount_3, recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data_3.recipient_id).unwrap(),
),
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
)]);
let txid_3 = test_send(&wallet, &online, &recipient_map);
assert!(!txid_3.is_empty());
show_unspent_colorings(&wallet, "wallet after 3rd transfer");
show_unspent_colorings(&rcv_wallet, "rcv_wallet after 3rd transfer");
test_refresh_all(&rcv_wallet, &rcv_online);
test_refresh_asset(&wallet, &online, &asset.asset_id);
mine(false);
rcv_wallet.refresh(rcv_online, None, vec![]).unwrap();
test_refresh_asset(&wallet, &online, &asset.asset_id);
let rcv_transfer = get_test_transfer_recipient(&rcv_wallet, &receive_data_3.recipient_id);
let (rcv_transfer_data, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer);
let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid_3);
let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer);
assert_eq!(rcv_transfer_data.status, TransferStatus::Settled);
assert_eq!(transfer_data.status, TransferStatus::Settled);
assert_eq!(rcv_transfer.amount, amount_3.to_string());
assert_eq!(transfer.amount, amount_3.to_string());
let unspents = test_list_unspents(&wallet, None, true);
let change_unspent = unspents
.into_iter()
.find(|u| Some(u.utxo.outpoint.clone()) == transfer_data.change_utxo)
.unwrap();
let change_allocations = change_unspent.rgb_allocations;
assert_eq!(change_allocations.len(), 1);
assert_eq!(change_allocations.first().unwrap().amount, change_3);
}
#[test]
#[parallel]
fn witness_success() {
initialize();
let amount: u64 = 66;
let (wallet, online) = get_funded_wallet!();
let (rcv_wallet, rcv_online) = get_funded_wallet!();
let asset = test_issue_asset_nia(&wallet, &online, None);
let receive_data = test_witness_receive(&rcv_wallet);
let receive_data_2 = test_witness_receive(&rcv_wallet);
let receive_data_3 = test_witness_receive(&rcv_wallet);
let recipient_map = HashMap::from([(
asset.asset_id.clone(),
vec![
Recipient {
amount,
recipient_data: RecipientData::WitnessData {
script_buf: ScriptBuf::from_hex(&receive_data.recipient_id).unwrap(),
amount_sat: 1000,
blinding: None,
},
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
},
Recipient {
amount: amount * 2,
recipient_data: RecipientData::WitnessData {
script_buf: ScriptBuf::from_hex(&receive_data_2.recipient_id).unwrap(),
amount_sat: 1200,
blinding: Some(7777),
},
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
},
Recipient {
amount: amount * 3,
recipient_data: RecipientData::WitnessData {
script_buf: ScriptBuf::from_hex(&receive_data_3.recipient_id).unwrap(),
amount_sat: 1400,
blinding: Some(8888),
},
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
},
],
)]);
_test_create_utxos(&wallet, &online, false, None, None, FEE_RATE);
let txid = test_send(&wallet, &online, &recipient_map);
assert!(!txid.is_empty());
stop_mining();
test_refresh_all(&rcv_wallet, &rcv_online);
let rcv_transfer = get_test_transfer_recipient(&rcv_wallet, &receive_data.recipient_id);
let (rcv_transfer_data, rcv_asset_transfer) =
get_test_transfer_data(&rcv_wallet, &rcv_transfer);
test_refresh_asset(&wallet, &online, &asset.asset_id);
let batch_transfers = get_test_batch_transfers(&wallet, &txid);
let batch_transfer = batch_transfers.first().unwrap();
let asset_transfer = get_test_asset_transfer(&wallet, batch_transfer.idx);
let transfers = get_test_transfers(&wallet, asset_transfer.idx);
for transfer in transfers {
let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer);
assert_eq!(transfer_data.status, TransferStatus::WaitingConfirmations);
assert_eq!(transfer.ack, Some(true));
}
assert_eq!(rcv_transfer_data.kind, TransferKind::ReceiveWitness);
assert_eq!(
rcv_transfer_data.status,
TransferStatus::WaitingConfirmations
);
assert_eq!(rcv_transfer.amount, amount.to_string());
assert_eq!(rcv_asset_transfer.asset_id, Some(asset.asset_id.clone()));
let rcv_assets = test_list_assets(&rcv_wallet, &[]);
let nia_assets = rcv_assets.nia.unwrap();
let cfa_assets = rcv_assets.cfa.unwrap();
assert_eq!(nia_assets.len(), 1);
assert_eq!(cfa_assets.len(), 0);
let rcv_asset = nia_assets.last().unwrap();
assert_eq!(rcv_asset.asset_id, asset.asset_id);
assert_eq!(rcv_asset.ticker, TICKER);
assert_eq!(rcv_asset.name, NAME);
assert_eq!(rcv_asset.precision, PRECISION);
assert_eq!(
rcv_asset.balance,
Balance {
settled: 0,
future: amount * 6,
spendable: 0,
}
);
mine(true);
test_refresh_all(&rcv_wallet, &rcv_online);
test_refresh_asset(&wallet, &online, &asset.asset_id);
let rcv_transfer = get_test_transfer_recipient(&rcv_wallet, &receive_data.recipient_id);
let (rcv_transfer_data, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer);
let batch_transfers = get_test_batch_transfers(&wallet, &txid);
let batch_transfer = batch_transfers.first().unwrap();
let asset_transfer = get_test_asset_transfer(&wallet, batch_transfer.idx);
let transfers = get_test_transfers(&wallet, asset_transfer.idx);
for transfer in transfers {
let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer);
assert_eq!(transfer_data.status, TransferStatus::Settled);
let unspents = test_list_unspents(&wallet, None, true);
let change_unspent = unspents
.into_iter()
.find(|u| Some(u.utxo.outpoint.clone()) == transfer_data.change_utxo);
assert!(change_unspent.is_some());
}
assert_eq!(rcv_transfer_data.status, TransferStatus::Settled);
let balances = test_get_btc_balance(&rcv_wallet, &rcv_online);
assert!(matches!(
balances.colored,
Balance {
settled: 8600,
future: 8600,
spendable: 8600,
}
));
}
#[test]
fn min_confirmations() {
initialize();
let amount: u64 = 66;
let min_confirmations = 2;
let (wallet, online) = get_funded_wallet!();
let (rcv_wallet, rcv_online) = get_funded_wallet!();
let asset = test_issue_asset_nia(&wallet, &online, None);
let receive_data = rcv_wallet
.blind_receive(
None,
None,
None,
TRANSPORT_ENDPOINTS.clone(),
min_confirmations,
)
.unwrap();
let recipient_map = HashMap::from([(
asset.asset_id.clone(),
vec![Recipient {
amount,
recipient_data: RecipientData::BlindedUTXO(
SecretSeal::from_str(&receive_data.recipient_id).unwrap(),
),
transport_endpoints: TRANSPORT_ENDPOINTS.clone(),
}],
)]);
let txid = wallet
.send(
online.clone(),
recipient_map,
false,
FEE_RATE,
min_confirmations,
)
.unwrap();
assert!(!txid.is_empty());
let rcv_transfer = get_test_transfer_recipient(&rcv_wallet, &receive_data.recipient_id);
let (rcv_transfer_data, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer);
let (_, rcv_batch_transfer) = get_test_transfer_related(&rcv_wallet, &rcv_transfer);
let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid);
let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer);
let (_, batch_transfer) = get_test_transfer_related(&wallet, &transfer);
assert_eq!(rcv_batch_transfer.min_confirmations, min_confirmations);
assert_eq!(batch_transfer.min_confirmations, min_confirmations);
assert_eq!(
rcv_transfer_data.status,
TransferStatus::WaitingCounterparty
);
assert_eq!(transfer_data.status, TransferStatus::WaitingCounterparty);
stop_mining();
test_refresh_all(&rcv_wallet, &rcv_online);
test_refresh_asset(&wallet, &online, &asset.asset_id);
let (rcv_transfer_data, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer);
let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer);
assert_eq!(
rcv_transfer_data.status,
TransferStatus::WaitingConfirmations
);
assert_eq!(transfer_data.status, TransferStatus::WaitingConfirmations);
mine(true);
test_refresh_all(&rcv_wallet, &rcv_online);
test_refresh_asset(&wallet, &online, &asset.asset_id);
let (rcv_transfer_data, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer);
let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer);
assert_eq!(
rcv_transfer_data.status,
TransferStatus::WaitingConfirmations
);
assert_eq!(transfer_data.status, TransferStatus::WaitingConfirmations);
mine(false);
rcv_wallet.refresh(rcv_online, None, vec![]).unwrap();
test_refresh_asset(&wallet, &online, &asset.asset_id);
let (rcv_transfer_data, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer);
let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer);
assert_eq!(rcv_transfer_data.status, TransferStatus::Settled);
assert_eq!(transfer_data.status, TransferStatus::Settled);
}