List both confirmed and unconfirmed transactions
This commit is contained in:
parent
c9e8368694
commit
e64b1f67c1
@ -1,3 +1,5 @@
|
|||||||
|
import java.util.Optional
|
||||||
|
import kotlin.ExperimentalUnsignedTypes
|
||||||
import uniffi.bdk.*
|
import uniffi.bdk.*
|
||||||
|
|
||||||
class LogProgress : BdkProgress {
|
class LogProgress : BdkProgress {
|
||||||
@ -10,18 +12,37 @@ class NullProgress : BdkProgress {
|
|||||||
override fun update(progress: Float, message: String?) {}
|
override fun update(progress: Float, message: String?) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getConfirmedTransaction(
|
fun getTransaction(wallet: OnlineWalletInterface, transactionId: String): Optional<Transaction> {
|
||||||
wallet: OnlineWalletInterface,
|
|
||||||
transactionId: String
|
|
||||||
): ConfirmedTransaction? {
|
|
||||||
wallet.sync(NullProgress(), null)
|
wallet.sync(NullProgress(), null)
|
||||||
return wallet.getTransactions()
|
return wallet.getTransactions()
|
||||||
.stream()
|
.stream()
|
||||||
.filter({ it.id.equals(transactionId) })
|
.filter({
|
||||||
|
when (it) {
|
||||||
|
is Transaction.Confirmed -> it.details.id.equals(transactionId)
|
||||||
|
is Transaction.Unconfirmed -> it.details.id.equals(transactionId)
|
||||||
|
}
|
||||||
|
})
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.orElse(null)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ExperimentalUnsignedTypes
|
||||||
|
val unconfirmedFirstThenByTimestampDescending =
|
||||||
|
Comparator<Transaction> { a, b ->
|
||||||
|
when {
|
||||||
|
(a is Transaction.Confirmed && b is Transaction.Confirmed) -> {
|
||||||
|
val comparison = b.confirmation.timestamp.compareTo(a.confirmation.timestamp)
|
||||||
|
when {
|
||||||
|
comparison == 0 -> b.details.id.compareTo(a.details.id)
|
||||||
|
else -> comparison
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(a is Transaction.Confirmed && b is Transaction.Unconfirmed) -> 1
|
||||||
|
(a is Transaction.Unconfirmed && b is Transaction.Confirmed) -> -1
|
||||||
|
else -> 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExperimentalUnsignedTypes
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
println("Configuring an in-memory wallet on electrum..")
|
println("Configuring an in-memory wallet on electrum..")
|
||||||
val descriptor = "pkh(cSQPHDBwXGjVzWRqAHm6zfvQhaTuj1f2bFH58h55ghbjtFwvmeXR)"
|
val descriptor = "pkh(cSQPHDBwXGjVzWRqAHm6zfvQhaTuj1f2bFH58h55ghbjtFwvmeXR)"
|
||||||
@ -41,23 +62,19 @@ fun main(args: Array<String>) {
|
|||||||
println("New wallet balance: ${wallet.getBalance()}")
|
println("New wallet balance: ${wallet.getBalance()}")
|
||||||
println("Press Enter to return funds")
|
println("Press Enter to return funds")
|
||||||
readLine()
|
readLine()
|
||||||
println(
|
println("Creating a PSBT with recipient $recipient and amount $amount satoshis...")
|
||||||
"Creating a PSBT with recipient $recipient and amount $amount satoshis..."
|
|
||||||
)
|
|
||||||
val transaction = PartiallySignedBitcoinTransaction(wallet, recipient, amount)
|
val transaction = PartiallySignedBitcoinTransaction(wallet, recipient, amount)
|
||||||
println("Signing the transaction...")
|
println("Signing the transaction...")
|
||||||
wallet.sign(transaction)
|
wallet.sign(transaction)
|
||||||
println("Broadcasting the signed transaction...")
|
println("Broadcasting the signed transaction...")
|
||||||
val transactionId = wallet.broadcast(transaction)
|
val transactionId = wallet.broadcast(transaction)
|
||||||
println("Broadcasted transaction with id $transactionId")
|
println("Broadcasted transaction with id $transactionId")
|
||||||
println("Confirming transaction...")
|
val take = 5
|
||||||
var confirmedTransaction = getConfirmedTransaction(wallet, transactionId)
|
println("Listing latest $take transactions...")
|
||||||
while (confirmedTransaction == null) {
|
wallet
|
||||||
confirmedTransaction = getConfirmedTransaction(wallet, transactionId)
|
.getTransactions()
|
||||||
}
|
.sortedWith(unconfirmedFirstThenByTimestampDescending)
|
||||||
println("Confirmed transaction: $confirmedTransaction")
|
.take(take)
|
||||||
val transactions = wallet.getTransactions()
|
.forEach { println(it) }
|
||||||
println("Listing all ${transactions.size} transactions...")
|
|
||||||
transactions.sortedByDescending { it.timestamp }.forEach { println(it) }
|
|
||||||
println("Final wallet balance: ${wallet.getBalance()}")
|
println("Final wallet balance: ${wallet.getBalance()}")
|
||||||
}
|
}
|
||||||
|
19
src/bdk.udl
19
src/bdk.udl
@ -63,15 +63,24 @@ interface DatabaseConfig {
|
|||||||
Sled(SledDbConfiguration config);
|
Sled(SledDbConfiguration config);
|
||||||
};
|
};
|
||||||
|
|
||||||
dictionary ConfirmedTransaction {
|
dictionary TransactionDetails {
|
||||||
u64? fees;
|
u64? fees;
|
||||||
u32 height;
|
|
||||||
u64 timestamp;
|
|
||||||
u64 received;
|
u64 received;
|
||||||
u64 sent;
|
u64 sent;
|
||||||
string id;
|
string id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dictionary Confirmation {
|
||||||
|
u32 height;
|
||||||
|
u64 timestamp;
|
||||||
|
};
|
||||||
|
|
||||||
|
[Enum]
|
||||||
|
interface Transaction {
|
||||||
|
Unconfirmed(TransactionDetails details);
|
||||||
|
Confirmed(TransactionDetails details, Confirmation confirmation);
|
||||||
|
};
|
||||||
|
|
||||||
interface OfflineWallet {
|
interface OfflineWallet {
|
||||||
[Throws=BdkError]
|
[Throws=BdkError]
|
||||||
constructor(string descriptor, Network network, DatabaseConfig database_config);
|
constructor(string descriptor, Network network, DatabaseConfig database_config);
|
||||||
@ -83,7 +92,7 @@ interface OfflineWallet {
|
|||||||
[Throws=BdkError]
|
[Throws=BdkError]
|
||||||
void sign([ByRef] PartiallySignedBitcoinTransaction psbt);
|
void sign([ByRef] PartiallySignedBitcoinTransaction psbt);
|
||||||
[Throws=BdkError]
|
[Throws=BdkError]
|
||||||
sequence<ConfirmedTransaction> get_transactions();
|
sequence<Transaction> get_transactions();
|
||||||
};
|
};
|
||||||
|
|
||||||
dictionary ElectrumConfig {
|
dictionary ElectrumConfig {
|
||||||
@ -123,7 +132,7 @@ interface OnlineWallet {
|
|||||||
[Throws=BdkError]
|
[Throws=BdkError]
|
||||||
void sign([ByRef] PartiallySignedBitcoinTransaction psbt);
|
void sign([ByRef] PartiallySignedBitcoinTransaction psbt);
|
||||||
[Throws=BdkError]
|
[Throws=BdkError]
|
||||||
sequence<ConfirmedTransaction> get_transactions();
|
sequence<Transaction> get_transactions();
|
||||||
|
|
||||||
// OnlineWalletInterface
|
// OnlineWalletInterface
|
||||||
Network get_network();
|
Network get_network();
|
||||||
|
33
src/lib.rs
33
src/lib.rs
@ -8,7 +8,7 @@ use bdk::blockchain::{
|
|||||||
use bdk::database::any::{AnyDatabase, SledDbConfiguration};
|
use bdk::database::any::{AnyDatabase, SledDbConfiguration};
|
||||||
use bdk::database::{AnyDatabaseConfig, ConfigurableDatabase};
|
use bdk::database::{AnyDatabaseConfig, ConfigurableDatabase};
|
||||||
use bdk::wallet::AddressIndex;
|
use bdk::wallet::AddressIndex;
|
||||||
use bdk::{Error, SignOptions, Wallet};
|
use bdk::{ConfirmationTime, Error, SignOptions, Wallet};
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::{Mutex, MutexGuard};
|
use std::sync::{Mutex, MutexGuard};
|
||||||
@ -58,15 +58,24 @@ impl WalletHolder<()> for OfflineWallet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||||
pub struct ConfirmedTransaction {
|
pub struct TransactionDetails {
|
||||||
pub fees: Option<u64>,
|
pub fees: Option<u64>,
|
||||||
pub height: u32,
|
|
||||||
pub timestamp: u64,
|
|
||||||
pub received: u64,
|
pub received: u64,
|
||||||
pub sent: u64,
|
pub sent: u64,
|
||||||
pub id: String,
|
pub id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Confirmation = ConfirmationTime;
|
||||||
|
pub enum Transaction {
|
||||||
|
Unconfirmed {
|
||||||
|
details: TransactionDetails,
|
||||||
|
},
|
||||||
|
Confirmed {
|
||||||
|
details: TransactionDetails,
|
||||||
|
confirmation: Confirmation,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
trait OfflineWalletOperations<B>: WalletHolder<B> {
|
trait OfflineWalletOperations<B>: WalletHolder<B> {
|
||||||
fn get_new_address(&self) -> String {
|
fn get_new_address(&self) -> String {
|
||||||
self.get_wallet()
|
self.get_wallet()
|
||||||
@ -92,18 +101,24 @@ trait OfflineWalletOperations<B>: WalletHolder<B> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_transactions(&self) -> Result<Vec<ConfirmedTransaction>, Error> {
|
fn get_transactions(&self) -> Result<Vec<Transaction>, Error> {
|
||||||
let transactions = self.get_wallet().list_transactions(true)?;
|
let transactions = self.get_wallet().list_transactions(true)?;
|
||||||
Ok(transactions
|
Ok(transactions
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|x| x.confirmation_time.is_some())
|
.map(|x| -> Transaction {
|
||||||
.map(|x| ConfirmedTransaction {
|
let details = TransactionDetails {
|
||||||
fees: x.fee,
|
fees: x.fee,
|
||||||
height: x.confirmation_time.clone().map_or(0, |c| c.height),
|
|
||||||
timestamp: x.confirmation_time.clone().map_or(0, |c| c.timestamp),
|
|
||||||
id: x.txid.to_string(),
|
id: x.txid.to_string(),
|
||||||
received: x.received,
|
received: x.received,
|
||||||
sent: x.sent,
|
sent: x.sent,
|
||||||
|
};
|
||||||
|
match x.confirmation_time.clone() {
|
||||||
|
Some(confirmation) => Transaction::Confirmed {
|
||||||
|
details,
|
||||||
|
confirmation,
|
||||||
|
},
|
||||||
|
None => Transaction::Unconfirmed { details },
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.collect())
|
.collect())
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user