diff --git a/client/src/format.rs b/client/src/format.rs index 6a7b789..ceb52eb 100644 --- a/client/src/format.rs +++ b/client/src/format.rs @@ -3,8 +3,7 @@ use colored::{Color, Colorize}; use jsonrpsee::core::Serialize; use serde::Deserialize; use spaces_protocol::{ - bitcoin::{Amount, Network, OutPoint}, - Covenant, + bitcoin::{Amount, Network, OutPoint}, Covenant }; use spaces_wallet::{ address::SpaceAddress, @@ -37,6 +36,12 @@ struct FormatRpcError { message: String, } +#[derive(Tabled)] +#[tabled(rename_all = "UPPERCASE")] +struct PendingSpaces { + space: String, +} + #[derive(Tabled)] #[tabled(rename_all = "UPPERCASE")] struct WinningSpaces { @@ -272,9 +277,13 @@ pub fn print_list_spaces_response( ) { match format { Format::Text => { + let mut pendings = Vec::new(); let mut outbids = Vec::new(); let mut winnings = Vec::new(); let mut owned = Vec::new(); + for slabel in response.pending { + pendings.push(PendingSpaces { space: slabel.to_string() }); + } for res in response.outbid { let space = res.spaceout.space.as_ref().expect("space"); let mut outbid = OutbidSpaces { @@ -342,6 +351,12 @@ pub fn print_list_spaces_response( owned.push(registered); } + if !pendings.is_empty() { + println!("⏳ PENDING ({} spaces): ", pendings.len().to_string().bold()); + let table = ascii_table(pendings); + println!("{}", table); + } + if !outbids.is_empty() { println!("⚠️ OUTBID ({} spaces): ", outbids.len().to_string().bold()); let table = ascii_table(outbids); diff --git a/client/src/wallets.rs b/client/src/wallets.rs index 597ed4b..fda04a4 100644 --- a/client/src/wallets.rs +++ b/client/src/wallets.rs @@ -101,6 +101,7 @@ pub struct WalletInfoWithProgress { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ListSpacesResponse { + pub pending: Vec, pub winning: Vec, pub outbid: Vec, pub owned: Vec, @@ -816,12 +817,15 @@ impl RpcWallet { let unspent = wallet.list_unspent_with_details(state)?; let recent_events = wallet.list_recent_events()?; - let mut res = ListSpacesResponse { - winning: vec![], - outbid: vec![], - owned: vec![], - }; + let mut pending = vec![]; + let mut outbid = vec![]; for (txid, event) in recent_events { + let tx = wallet.get_tx(txid); + if tx.as_ref().is_some_and(|tx| !tx.chain_position.is_confirmed()) { + pending.push(SLabel::from_str(event.space.as_ref().unwrap()).expect("valid space name")); + continue; + } + if unspent.iter().any(|out| { out.space .as_ref() @@ -833,9 +837,12 @@ impl RpcWallet { let spacehash = SpaceKey::from(Sha256::hash(name.as_ref())); let space = state.get_space_info(&spacehash)?; if let Some(space) = space { - let tx = wallet.get_tx(txid); + if space.spaceout.space.as_ref().unwrap().is_owned() { + continue; + } + if tx.is_none() { - res.outbid.push(space); + outbid.push(space); continue; } @@ -845,10 +852,13 @@ impl RpcWallet { { continue; } - res.outbid.push(space); + + outbid.push(space); } } + let mut owned = vec![]; + let mut winning = vec![]; for wallet_output in unspent.into_iter().filter(|output| output.space.is_some()) { let entry = FullSpaceOut { txid: wallet_output.output.outpoint.txid, @@ -860,15 +870,19 @@ impl RpcWallet { }, }; - let space = entry.spaceout.space.as_ref().expect("space"); - if matches!(space.covenant, spaces_protocol::Covenant::Bid { .. }) { - res.winning.push(entry); - } else if matches!(space.covenant, spaces_protocol::Covenant::Transfer { .. }) { - res.owned.push(entry); + if entry.spaceout.space.as_ref().expect("space").is_owned() { + owned.push(entry); + } else { + winning.push(entry); } } - Ok(res) + Ok(ListSpacesResponse { + pending, + winning, + outbid, + owned, + }) } fn list_transactions( diff --git a/client/tests/integration_tests.rs b/client/tests/integration_tests.rs index 5078763..e14fa27 100644 --- a/client/tests/integration_tests.rs +++ b/client/tests/integration_tests.rs @@ -44,9 +44,13 @@ async fn it_should_open_a_space_for_auction(rig: &TestRig) -> anyhow::Result<()> assert!(tx_res.error.is_none(), "expect no errors for simple open"); } assert_eq!(response.result.len(), 2, "must be 2 transactions"); + let alices_spaces = rig.spaced.client.wallet_list_spaces(ALICE).await?; + assert!(alices_spaces.pending.first().is_some_and(|s| s.to_string() == TEST_SPACE), "must be a pending space"); rig.mine_blocks(1, None).await?; rig.wait_until_synced().await?; + let alices_spaces = rig.spaced.client.wallet_list_spaces(ALICE).await?; + assert!(alices_spaces.pending.is_empty(), "must have no pending spaces"); let fullspaceout = rig.spaced.client.get_space(TEST_SPACE).await?; let fullspaceout = fullspaceout.expect("a fullspace out"); @@ -96,8 +100,11 @@ async fn it_should_allow_outbidding(rig: &TestRig) -> anyhow::Result<()> { .expect("send request"); println!("{}", serde_json::to_string_pretty(&result).unwrap()); - rig.mine_blocks(1, None).await?; + let bob_spaces_updated = rig.spaced.client.wallet_list_spaces(BOB).await?; + assert!(bob_spaces_updated.pending.first().is_some_and(|s| s.to_string() == TEST_SPACE), "must be a pending space"); + + rig.mine_blocks(1, None).await?; rig.wait_until_synced().await?; rig.wait_until_wallet_synced(BOB).await?; rig.wait_until_wallet_synced(ALICE).await?; @@ -125,6 +132,7 @@ async fn it_should_allow_outbidding(rig: &TestRig) -> anyhow::Result<()> { alices_balance.balance + Amount::from_sat(TEST_INITIAL_BID + 662), "alice must be refunded this exact amount" ); + assert!(bob_spaces_updated.pending.is_empty(), "must have no pending spaces"); let fullspaceout = rig.spaced.client.get_space(TEST_SPACE).await?; let fullspaceout = fullspaceout.expect("a fullspace out"); diff --git a/wallet/src/tx_event.rs b/wallet/src/tx_event.rs index dfeabd1..cd3e2c5 100644 --- a/wallet/src/tx_event.rs +++ b/wallet/src/tx_event.rs @@ -206,7 +206,7 @@ impl TxEvent { Ok(None) } - /// Retrieve all spaces the wallet has bid on in the last 2 weeks + /// Retrieve all spaces the wallet has done any operation with pub fn get_latest_events( db_tx: &rusqlite::Transaction, ) -> rusqlite::Result> { @@ -216,8 +216,7 @@ impl TxEvent { WHERE id IN ( SELECT MAX(id) FROM {table} - WHERE type IN ('bid', 'open') - AND created_at >= strftime('%s', 'now', '-14 days') + WHERE space IS NOT NULL GROUP BY space ) ORDER BY id DESC",