feat: add list addresses method to gui daemon interface

This commit is contained in:
Michael Mallan 2025-05-05 16:21:13 +01:00
parent 619ea6923f
commit 8b8b48142f
No known key found for this signature in database
GPG Key ID: 5177CDCEDB0EABEB
7 changed files with 124 additions and 7 deletions

View File

@ -13,7 +13,9 @@ use tracing::{error, info};
pub mod error; pub mod error;
pub mod jsonrpc; pub mod jsonrpc;
use liana::miniscript::bitcoin::{address, psbt::Psbt, Address, Network, OutPoint, Txid}; use liana::miniscript::bitcoin::{
address, bip32::ChildNumber, psbt::Psbt, Address, Network, OutPoint, Txid,
};
use lianad::{ use lianad::{
commands::{CoinStatus, CreateRecoveryResult, LabelItem}, commands::{CoinStatus, CreateRecoveryResult, LabelItem},
config::Config, config::Config,
@ -87,6 +89,24 @@ impl<C: Client + Send + Sync + Debug> Daemon for Lianad<C> {
self.call("getnewaddress", Option::<Request>::None) self.call("getnewaddress", Option::<Request>::None)
} }
async fn list_revealed_addresses(
&self,
is_change: bool,
exclude_used: bool,
limit: usize,
start_index: Option<ChildNumber>,
) -> Result<ListRevealedAddressesResult, DaemonError> {
self.call(
"listrevealedaddresses",
Some(vec![
json!(is_change),
json!(exclude_used),
json!(limit),
json!(start_index), // a `null` argument is parsed as `None` by the command
]),
)
}
async fn update_deriv_indexes( async fn update_deriv_indexes(
&self, &self,
receive: Option<u32>, receive: Option<u32>,

View File

@ -6,7 +6,9 @@ use tokio::sync::Mutex;
use super::{model::*, node, Daemon, DaemonBackend, DaemonError}; use super::{model::*, node, Daemon, DaemonBackend, DaemonError};
use crate::dir::LianaDirectory; use crate::dir::LianaDirectory;
use async_trait::async_trait; use async_trait::async_trait;
use liana::miniscript::bitcoin::{address, psbt::Psbt, Address, Network, OutPoint, Txid}; use liana::miniscript::bitcoin::{
address, bip32::ChildNumber, psbt::Psbt, Address, Network, OutPoint, Txid,
};
use lianad::{ use lianad::{
commands::{CoinStatus, LabelItem}, commands::{CoinStatus, LabelItem},
config::Config, config::Config,
@ -103,6 +105,21 @@ impl Daemon for EmbeddedDaemon {
self.command(|daemon| Ok(daemon.get_new_address())).await self.command(|daemon| Ok(daemon.get_new_address())).await
} }
async fn list_revealed_addresses(
&self,
is_change: bool,
exclude_used: bool,
limit: usize,
start_index: Option<ChildNumber>,
) -> Result<ListRevealedAddressesResult, DaemonError> {
self.command(|daemon| {
daemon
.list_revealed_addresses(is_change, exclude_used, limit, start_index)
.map_err(|e| DaemonError::Unexpected(e.to_string()))
})
.await
}
async fn update_deriv_indexes( async fn update_deriv_indexes(
&self, &self,
receive: Option<u32>, receive: Option<u32>,

View File

@ -11,7 +11,10 @@ use std::iter::FromIterator;
use async_trait::async_trait; use async_trait::async_trait;
use liana::miniscript::bitcoin::{ use liana::miniscript::bitcoin::{
address, bip32::Fingerprint, psbt::Psbt, secp256k1, Address, Network, OutPoint, Txid, address,
bip32::{ChildNumber, Fingerprint},
psbt::Psbt,
secp256k1, Address, Network, OutPoint, Txid,
}; };
use lianad::bip329::Labels; use lianad::bip329::Labels;
use lianad::commands::UpdateDerivIndexesResult; use lianad::commands::UpdateDerivIndexesResult;
@ -104,6 +107,13 @@ pub trait Daemon: Debug {
async fn stop(&self) -> Result<(), DaemonError>; async fn stop(&self) -> Result<(), DaemonError>;
async fn get_info(&self) -> Result<model::GetInfoResult, DaemonError>; async fn get_info(&self) -> Result<model::GetInfoResult, DaemonError>;
async fn get_new_address(&self) -> Result<model::GetAddressResult, DaemonError>; async fn get_new_address(&self) -> Result<model::GetAddressResult, DaemonError>;
async fn list_revealed_addresses(
&self,
is_change: bool,
exclude_used: bool,
limit: usize,
start_index: Option<ChildNumber>,
) -> Result<model::ListRevealedAddressesResult, DaemonError>;
async fn update_deriv_indexes( async fn update_deriv_indexes(
&self, &self,
receive: Option<u32>, receive: Option<u32>,

View File

@ -12,7 +12,8 @@ pub use liana::{
}; };
pub use lianad::commands::{ pub use lianad::commands::{
CreateSpendResult, GetAddressResult, GetInfoResult, GetLabelsResult, LabelItem, ListCoinsEntry, CreateSpendResult, GetAddressResult, GetInfoResult, GetLabelsResult, LabelItem, ListCoinsEntry,
ListCoinsResult, ListSpendEntry, ListSpendResult, ListTransactionsResult, TransactionInfo, ListCoinsResult, ListRevealedAddressesEntry, ListRevealedAddressesResult, ListSpendEntry,
ListSpendResult, ListTransactionsResult, TransactionInfo,
}; };
pub type Coin = ListCoinsEntry; pub type Coin = ListCoinsEntry;

View File

@ -347,6 +347,21 @@ pub struct Address {
pub derivation_index: bip32::ChildNumber, pub derivation_index: bip32::ChildNumber,
} }
#[derive(Deserialize)]
pub struct RevealedAddress {
#[serde(deserialize_with = "deser_addr_assume_checked")]
pub address: bitcoin::Address,
pub derivation_index: bip32::ChildNumber,
pub label: Option<String>,
pub used_count: u32,
}
#[derive(Deserialize)]
pub struct ListRevealedAddresses {
pub addresses: Vec<RevealedAddress>,
pub continue_from: Option<bip32::ChildNumber>,
}
pub mod payload { pub mod payload {
use liana::{descriptors::LianaDescriptor, miniscript::bitcoin}; use liana::{descriptors::LianaDescriptor, miniscript::bitcoin};
use serde::{Serialize, Serializer}; use serde::{Serialize, Serializer};

View File

@ -9,7 +9,9 @@ use async_trait::async_trait;
use chrono::Utc; use chrono::Utc;
use liana::{ use liana::{
descriptors::LianaDescriptor, descriptors::LianaDescriptor,
miniscript::bitcoin::{address, psbt::Psbt, Address, Network, OutPoint, Txid}, miniscript::bitcoin::{
address, bip32::ChildNumber, psbt::Psbt, Address, Network, OutPoint, Txid,
},
}; };
use lianad::{ use lianad::{
bip329::Labels, bip329::Labels,
@ -610,6 +612,57 @@ impl Daemon for BackendWalletClient {
}) })
} }
async fn list_revealed_addresses(
&self,
is_change: bool,
exclude_used: bool,
limit: usize,
start_index: Option<ChildNumber>,
) -> Result<ListRevealedAddressesResult, DaemonError> {
let mut query = Vec::<(&str, String)>::new();
query.push(("is_change_address", is_change.to_string()));
query.push(("exclude_used", exclude_used.to_string()));
query.push(("limit", limit.to_string()));
if let Some(start) = start_index {
query.push(("start_derivation_index", start.to_string()));
}
let response: Response = self
.inner
.request(
Method::GET,
&format!(
"{}/v1/wallets/{}/addresses",
self.inner.url, self.wallet_uuid
),
)
.await
.query(&query)
.send()
.await?;
if !response.status().is_success() {
return Err(DaemonError::Http(
Some(response.status().into()),
response.text().await?,
));
}
let res: api::ListRevealedAddresses = response.json().await?;
Ok(ListRevealedAddressesResult {
addresses: res
.addresses
.into_iter()
.map(|addr| ListRevealedAddressesEntry {
index: addr.derivation_index,
address: addr.address,
label: addr.label,
used_count: addr.used_count,
})
.collect(),
continue_from: res.continue_from,
})
}
async fn update_deriv_indexes( async fn update_deriv_indexes(
&self, &self,
_receive: Option<u32>, _receive: Option<u32>,

View File

@ -1412,11 +1412,12 @@ impl ListAddressesResult {
} }
/// A revealed address entry in the list returned by [`DaemonControl::list_revealed_addresses`]. /// A revealed address entry in the list returned by [`DaemonControl::list_revealed_addresses`].
#[derive(Debug, Clone, Serialize, PartialEq, Eq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct ListRevealedAddressesEntry { pub struct ListRevealedAddressesEntry {
/// The address's derivation index. /// The address's derivation index.
pub index: ChildNumber, pub index: ChildNumber,
/// The address. /// The address.
#[serde(deserialize_with = "deser_addr_assume_checked")]
pub address: bitcoin::Address, pub address: bitcoin::Address,
/// Label assigned to the address, if any. /// Label assigned to the address, if any.
pub label: Option<String>, pub label: Option<String>,
@ -1428,7 +1429,7 @@ pub struct ListRevealedAddressesEntry {
} }
/// Result of a [`DaemonControl::list_revealed_addresses`] request. /// Result of a [`DaemonControl::list_revealed_addresses`] request.
#[derive(Debug, Clone, Serialize, PartialEq, Eq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct ListRevealedAddressesResult { pub struct ListRevealedAddressesResult {
/// Revealed addresses in order of descending derivation index. /// Revealed addresses in order of descending derivation index.
pub addresses: Vec<ListRevealedAddressesEntry>, pub addresses: Vec<ListRevealedAddressesEntry>,