Add Wallet.listTransactions()
This commit is contained in:
parent
cd813a14b1
commit
b437b78668
@ -16,10 +16,10 @@ interface LibJna : Library {
|
|||||||
class ByReference : FfiResult_char_ptr_t(), Structure.ByReference
|
class ByReference : FfiResult_char_ptr_t(), Structure.ByReference
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
var ok: String = ""
|
var ok: String? = null
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
var err: Short = 0
|
var err: Short? = null
|
||||||
|
|
||||||
override fun getFieldOrder() = listOf("ok", "err")
|
override fun getFieldOrder() = listOf("ok", "err")
|
||||||
}
|
}
|
||||||
@ -38,7 +38,7 @@ interface LibJna : Library {
|
|||||||
class ByReference : FfiResultVoid_t(), Structure.ByReference
|
class ByReference : FfiResultVoid_t(), Structure.ByReference
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
var err: Short = 0
|
var err: Short? = null
|
||||||
|
|
||||||
override fun getFieldOrder() = listOf("err")
|
override fun getFieldOrder() = listOf("err")
|
||||||
}
|
}
|
||||||
@ -97,10 +97,10 @@ interface LibJna : Library {
|
|||||||
class ByReference : FfiResult_OpaqueWallet_ptr_t(), Structure.ByReference
|
class ByReference : FfiResult_OpaqueWallet_ptr_t(), Structure.ByReference
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
var ok: OpaqueWallet_t = OpaqueWallet_t()
|
var ok: OpaqueWallet_t? = null
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
var err: Short = 0
|
var err: Short? = null
|
||||||
|
|
||||||
override fun getFieldOrder() = listOf("ok", "err")
|
override fun getFieldOrder() = listOf("ok", "err")
|
||||||
}
|
}
|
||||||
@ -224,10 +224,10 @@ interface LibJna : Library {
|
|||||||
class ByReference : FfiResultVec_LocalUtxo_t(), Structure.ByReference
|
class ByReference : FfiResultVec_LocalUtxo_t(), Structure.ByReference
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
var ok: Vec_LocalUtxo_t = Vec_LocalUtxo_t()
|
var ok: Vec_LocalUtxo_t? = null
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
var err: Short = 0
|
var err: Short? = null
|
||||||
|
|
||||||
override fun getFieldOrder() = listOf("ok", "err")
|
override fun getFieldOrder() = listOf("ok", "err")
|
||||||
}
|
}
|
||||||
@ -249,10 +249,10 @@ interface LibJna : Library {
|
|||||||
class ByReference : FfiResult_uint64_t(), Structure.ByReference
|
class ByReference : FfiResult_uint64_t(), Structure.ByReference
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
var ok: Long = Long.MIN_VALUE
|
var ok: Long? = null
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
var err: Short = 0
|
var err: Short? = null
|
||||||
|
|
||||||
override fun getFieldOrder() = listOf("ok", "err")
|
override fun getFieldOrder() = listOf("ok", "err")
|
||||||
}
|
}
|
||||||
@ -288,4 +288,101 @@ interface LibJna : Library {
|
|||||||
// void free_database_config (
|
// void free_database_config (
|
||||||
// DatabaseConfig_t * database_config);
|
// DatabaseConfig_t * database_config);
|
||||||
fun free_database_config(database_config: DatabaseConfig_t)
|
fun free_database_config(database_config: DatabaseConfig_t)
|
||||||
|
|
||||||
|
// typedef struct {
|
||||||
|
//
|
||||||
|
// char * txid;
|
||||||
|
//
|
||||||
|
// uint64_t timestamp;
|
||||||
|
//
|
||||||
|
// uint64_t received;
|
||||||
|
//
|
||||||
|
// uint64_t sent;
|
||||||
|
//
|
||||||
|
// uint64_t fees;
|
||||||
|
//
|
||||||
|
// int32_t height;
|
||||||
|
//
|
||||||
|
// } TransactionDetails_t;
|
||||||
|
open class TransactionDetails_t : Structure() {
|
||||||
|
|
||||||
|
class ByValue : TransactionDetails_t(), Structure.ByValue
|
||||||
|
class ByReference : TransactionDetails_t(), Structure.ByReference
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
var txid: String? = null
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
var timestamp: Long? = null
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
var received: Long? = null
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
var sent: Long? = null
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
var fees: Long? = null
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
var height: Int? = null
|
||||||
|
|
||||||
|
override fun getFieldOrder() = listOf("txid", "timestamp", "received", "sent", "fees", "height")
|
||||||
|
}
|
||||||
|
|
||||||
|
// typedef struct {
|
||||||
|
//
|
||||||
|
// TransactionDetails_t * ptr;
|
||||||
|
//
|
||||||
|
// size_t len;
|
||||||
|
//
|
||||||
|
// size_t cap;
|
||||||
|
//
|
||||||
|
// } Vec_TransactionDetails_t;
|
||||||
|
open class Vec_TransactionDetails_t : Structure() {
|
||||||
|
|
||||||
|
class ByReference : Vec_TransactionDetails_t(), Structure.ByReference
|
||||||
|
class ByValue : Vec_TransactionDetails_t(), Structure.ByValue
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
var ptr: TransactionDetails_t.ByReference? = null
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
var len: NativeLong? = null
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
var cap: NativeLong? = null
|
||||||
|
|
||||||
|
override fun getFieldOrder() = listOf("ptr", "len", "cap")
|
||||||
|
}
|
||||||
|
|
||||||
|
// typedef struct {
|
||||||
|
//
|
||||||
|
// Vec_TransactionDetails_t ok;
|
||||||
|
//
|
||||||
|
// FfiError_t err;
|
||||||
|
//
|
||||||
|
// } FfiResult_Vec_TransactionDetails_t;
|
||||||
|
open class FfiResult_Vec_TransactionDetails_t : Structure() {
|
||||||
|
|
||||||
|
class ByValue : FfiResult_Vec_TransactionDetails_t(), Structure.ByValue
|
||||||
|
class ByReference : FfiResult_Vec_TransactionDetails_t(), Structure.ByReference
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
var ok: Vec_TransactionDetails_t? = null
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
var err: Short? = null
|
||||||
|
|
||||||
|
override fun getFieldOrder() = listOf("ok", "err")
|
||||||
|
}
|
||||||
|
|
||||||
|
// FfiResult_Vec_TransactionDetails_t list_transactions (
|
||||||
|
// OpaqueWallet_t const * opaque_wallet);
|
||||||
|
fun list_transactions(opaque_wallet: OpaqueWallet_t): FfiResult_Vec_TransactionDetails_t.ByValue
|
||||||
|
|
||||||
|
|
||||||
|
// void free_vectxdetails_result (
|
||||||
|
// FfiResult_Vec_TransactionDetails_t txdetails_result);
|
||||||
|
fun free_vectxdetails_result(txdetails_result: FfiResult_Vec_TransactionDetails_t.ByValue)
|
||||||
}
|
}
|
||||||
|
@ -12,8 +12,8 @@ class StringResult constructor(private val ffiResultCharPtrT: LibJna.FfiResult_c
|
|||||||
private val log: Logger = LoggerFactory.getLogger(StringResult::class.java)
|
private val log: Logger = LoggerFactory.getLogger(StringResult::class.java)
|
||||||
|
|
||||||
fun value(): String {
|
fun value(): String {
|
||||||
val err = ffiResultCharPtrT.err
|
val err = ffiResultCharPtrT.err!!
|
||||||
val ok = ffiResultCharPtrT.ok
|
val ok = ffiResultCharPtrT.ok!!
|
||||||
when {
|
when {
|
||||||
err > 0 -> {
|
err > 0 -> {
|
||||||
throw FfiException(err)
|
throw FfiException(err)
|
||||||
|
@ -12,8 +12,8 @@ class UInt64Result constructor(private val ffiResultUint64T: LibJna.FfiResult_ui
|
|||||||
private val log: Logger = LoggerFactory.getLogger(UInt64Result::class.java)
|
private val log: Logger = LoggerFactory.getLogger(UInt64Result::class.java)
|
||||||
|
|
||||||
fun value(): Long {
|
fun value(): Long {
|
||||||
val err = ffiResultUint64T.err
|
val err = ffiResultUint64T.err!!
|
||||||
val ok = ffiResultUint64T.ok
|
val ok = ffiResultUint64T.ok!!
|
||||||
when {
|
when {
|
||||||
err > 0 -> {
|
err > 0 -> {
|
||||||
throw FfiException(err)
|
throw FfiException(err)
|
||||||
|
@ -12,7 +12,7 @@ class VoidResult constructor(private val ffiResultVoidT: LibJna.FfiResultVoid_t.
|
|||||||
private val log: Logger = LoggerFactory.getLogger(VoidResult::class.java)
|
private val log: Logger = LoggerFactory.getLogger(VoidResult::class.java)
|
||||||
|
|
||||||
fun value(): Unit {
|
fun value(): Unit {
|
||||||
val err = ffiResultVoidT.err
|
val err = ffiResultVoidT.err!!
|
||||||
|
|
||||||
when {
|
when {
|
||||||
err > 0 -> {
|
err > 0 -> {
|
||||||
|
@ -12,8 +12,8 @@ class VecLocalUtxoResult(private val ffiResultVecLocalUtxoT: LibJna.FfiResultVec
|
|||||||
private val log: Logger = LoggerFactory.getLogger(VecLocalUtxoResult::class.java)
|
private val log: Logger = LoggerFactory.getLogger(VecLocalUtxoResult::class.java)
|
||||||
|
|
||||||
fun value(): Array<LibJna.LocalUtxo_t.ByReference> {
|
fun value(): Array<LibJna.LocalUtxo_t.ByReference> {
|
||||||
val err = ffiResultVecLocalUtxoT.err
|
val err = ffiResultVecLocalUtxoT.err!!
|
||||||
val ok = ffiResultVecLocalUtxoT.ok
|
val ok = ffiResultVecLocalUtxoT.ok!!
|
||||||
when {
|
when {
|
||||||
err > 0 -> {
|
err > 0 -> {
|
||||||
throw FfiException(err)
|
throw FfiException(err)
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
package org.bitcoindevkit.bdk.wallet
|
||||||
|
|
||||||
|
import org.bitcoindevkit.bdk.FfiException
|
||||||
|
import org.bitcoindevkit.bdk.LibBase
|
||||||
|
import org.bitcoindevkit.bdk.LibJna
|
||||||
|
import org.slf4j.Logger
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
|
||||||
|
class VecTxDetailsResult(private val ffiResultVecTransactionDetailsT: LibJna.FfiResult_Vec_TransactionDetails_t.ByValue) :
|
||||||
|
LibBase() {
|
||||||
|
|
||||||
|
private val log: Logger = LoggerFactory.getLogger(VecTxDetailsResult::class.java)
|
||||||
|
|
||||||
|
fun value(): Array<LibJna.TransactionDetails_t.ByReference> {
|
||||||
|
val err = ffiResultVecTransactionDetailsT.err!!
|
||||||
|
val ok = ffiResultVecTransactionDetailsT.ok!!
|
||||||
|
when {
|
||||||
|
err > 0 -> {
|
||||||
|
throw FfiException(err)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
val first = ok.ptr!!
|
||||||
|
return first.toArray(ok.len!!.toInt()) as Array<LibJna.TransactionDetails_t.ByReference>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun finalize() {
|
||||||
|
libJna.free_vectxdetails_result(ffiResultVecTransactionDetailsT)
|
||||||
|
log.debug("$ffiResultVecTransactionDetailsT freed")
|
||||||
|
}
|
||||||
|
}
|
@ -48,4 +48,9 @@ class Wallet constructor(
|
|||||||
val longResult = UInt64Result(libJna.balance(wallet))
|
val longResult = UInt64Result(libJna.balance(wallet))
|
||||||
return longResult.value()
|
return longResult.value()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun listTransactionDetails(): Array<LibJna.TransactionDetails_t.ByReference> {
|
||||||
|
val vecTxDetailsResult = VecTxDetailsResult(libJna.list_transactions((wallet)))
|
||||||
|
return vecTxDetailsResult.value()
|
||||||
|
}
|
||||||
}
|
}
|
@ -12,14 +12,14 @@ class WalletResult constructor(private val ffiResultOpaqueWalletPtrT: LibJna.Ffi
|
|||||||
private val log: Logger = LoggerFactory.getLogger(WalletResult::class.java)
|
private val log: Logger = LoggerFactory.getLogger(WalletResult::class.java)
|
||||||
|
|
||||||
fun value(): LibJna.OpaqueWallet_t {
|
fun value(): LibJna.OpaqueWallet_t {
|
||||||
val err = ffiResultOpaqueWalletPtrT.err
|
val err = ffiResultOpaqueWalletPtrT.err!!
|
||||||
val ok = ffiResultOpaqueWalletPtrT.ok
|
val ok = ffiResultOpaqueWalletPtrT.ok
|
||||||
when {
|
when {
|
||||||
err > 0 -> {
|
err > 0 -> {
|
||||||
throw FfiException(err)
|
throw FfiException(err)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
return ok
|
return ok!!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,4 +105,26 @@ abstract class LibTest : LibBase() {
|
|||||||
//log.debug("balance from kotlin: $balance")
|
//log.debug("balance from kotlin: $balance")
|
||||||
assertTrue(balance > 0)
|
assertTrue(balance > 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun walletTxDetails() {
|
||||||
|
val wallet = Wallet(desc, change, blockchainConfig, databaseConfig)
|
||||||
|
wallet.sync()
|
||||||
|
val txDetails = wallet.listTransactionDetails()
|
||||||
|
assertTrue(txDetails.isNotEmpty())
|
||||||
|
|
||||||
|
txDetails.iterator().forEach {
|
||||||
|
//log.debug("txDetails.txid: ${it.txid}")
|
||||||
|
assertNotNull(it.txid)
|
||||||
|
//log.debug("txDetails.timestamp: ${it.timestamp}")
|
||||||
|
assertTrue(it.timestamp!! > 0)
|
||||||
|
//log.debug("txDetails.received: ${it.received}")
|
||||||
|
//log.debug("txDetails.sent: ${it.sent}")
|
||||||
|
assertTrue(it.received!! > 0 || it.sent!! > 0)
|
||||||
|
//log.debug("txDetails.fees: ${it.fees}")
|
||||||
|
assertTrue(it.fees!! > 0)
|
||||||
|
//log.debug("txDetails.fees: ${it.height}")
|
||||||
|
assertTrue(it.height!! >= -1)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
43
cc/bdk_ffi.h
43
cc/bdk_ffi.h
@ -214,6 +214,49 @@ typedef struct {
|
|||||||
FfiResult_uint64_t balance (
|
FfiResult_uint64_t balance (
|
||||||
OpaqueWallet_t const * opaque_wallet);
|
OpaqueWallet_t const * opaque_wallet);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
char * txid;
|
||||||
|
|
||||||
|
uint64_t timestamp;
|
||||||
|
|
||||||
|
uint64_t received;
|
||||||
|
|
||||||
|
uint64_t sent;
|
||||||
|
|
||||||
|
uint64_t fees;
|
||||||
|
|
||||||
|
int32_t height;
|
||||||
|
|
||||||
|
} TransactionDetails_t;
|
||||||
|
|
||||||
|
/** \brief
|
||||||
|
* Same as [`Vec<T>`][`rust::Vec`], but with guaranteed `#[repr(C)]` layout
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
TransactionDetails_t * ptr;
|
||||||
|
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
size_t cap;
|
||||||
|
|
||||||
|
} Vec_TransactionDetails_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
Vec_TransactionDetails_t ok;
|
||||||
|
|
||||||
|
FfiError_t err;
|
||||||
|
|
||||||
|
} FfiResult_Vec_TransactionDetails_t;
|
||||||
|
|
||||||
|
FfiResult_Vec_TransactionDetails_t list_transactions (
|
||||||
|
OpaqueWallet_t const * opaque_wallet);
|
||||||
|
|
||||||
|
void free_vectxdetails_result (
|
||||||
|
FfiResult_Vec_TransactionDetails_t txdetails_result);
|
||||||
|
|
||||||
BlockchainConfig_t * new_electrum_config (
|
BlockchainConfig_t * new_electrum_config (
|
||||||
char const * url,
|
char const * url,
|
||||||
char const * socks5,
|
char const * socks5,
|
||||||
|
@ -152,6 +152,53 @@ int main (int argc, char const * const argv[])
|
|||||||
free_uint64_result(balance_result);
|
free_uint64_result(balance_result);
|
||||||
free_wallet_result(wallet_result);
|
free_wallet_result(wallet_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// test get transaction details
|
||||||
|
{
|
||||||
|
char const *desc = "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)";
|
||||||
|
char const *change = "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/1/*)";
|
||||||
|
|
||||||
|
BlockchainConfig_t *bc_config = new_electrum_config("ssl://electrum.blockstream.info:60002", NULL, 5, 30);
|
||||||
|
DatabaseConfig_t *db_config = new_memory_config();
|
||||||
|
|
||||||
|
// new wallet
|
||||||
|
FfiResult_OpaqueWallet_ptr_t wallet_result = new_wallet_result(desc,change,bc_config,db_config);
|
||||||
|
assert(wallet_result.err == FFI_ERROR_NONE);
|
||||||
|
assert(wallet_result.ok != NULL);
|
||||||
|
|
||||||
|
free_blockchain_config(bc_config);
|
||||||
|
free_database_config(db_config);
|
||||||
|
|
||||||
|
OpaqueWallet_t *wallet = wallet_result.ok;
|
||||||
|
|
||||||
|
// sync wallet
|
||||||
|
FfiResultVoid_t sync_result = sync_wallet(wallet);
|
||||||
|
assert(sync_result.err == FFI_ERROR_NONE);
|
||||||
|
free_void_result(sync_result);
|
||||||
|
|
||||||
|
// list transactions
|
||||||
|
FfiResult_Vec_TransactionDetails_t txdetails_result = list_transactions(wallet);
|
||||||
|
assert(txdetails_result.ok.len > 0);
|
||||||
|
assert(txdetails_result.err == FFI_ERROR_NONE);
|
||||||
|
|
||||||
|
TransactionDetails_t * txdetails_ptr = txdetails_result.ok.ptr;
|
||||||
|
for (int i = 0; i < txdetails_result.ok.len; i++) {
|
||||||
|
//printf("%d: txid: %s\n", i, txdetails_ptr[i].txid);
|
||||||
|
assert(txdetails_ptr[i].txid != NULL);
|
||||||
|
//printf("%d: timestamp: %ld\n", i, txdetails_ptr[i].timestamp);
|
||||||
|
assert(txdetails_ptr[i].timestamp > 0);
|
||||||
|
//printf("%d: received: %ld\n", i, txdetails_ptr[i].received);
|
||||||
|
//printf("%d: sent: %ld\n", i, txdetails_ptr[i].sent);
|
||||||
|
assert(txdetails_ptr[i].received > 0 || txdetails_ptr[i].sent > 0);
|
||||||
|
//printf("%d: fees: %ld\n", i, txdetails_ptr[i].fees);
|
||||||
|
assert(txdetails_ptr[i].fees > 0);
|
||||||
|
//printf("%d: height: %d\n", i, txdetails_ptr[i].height);
|
||||||
|
assert(txdetails_ptr[i].height >= -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
free_vectxdetails_result(txdetails_result);
|
||||||
|
free_wallet_result(wallet_result);
|
||||||
|
}
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -15,9 +15,11 @@ use database::DatabaseConfig;
|
|||||||
|
|
||||||
use crate::error::FfiError;
|
use crate::error::FfiError;
|
||||||
use crate::types::{FfiResult, FfiResultVoid};
|
use crate::types::{FfiResult, FfiResultVoid};
|
||||||
|
use crate::wallet::transaction::{LocalUtxo, TransactionDetails};
|
||||||
|
|
||||||
mod blockchain;
|
mod blockchain;
|
||||||
mod database;
|
mod database;
|
||||||
|
mod transaction;
|
||||||
|
|
||||||
// create a new wallet
|
// create a new wallet
|
||||||
|
|
||||||
@ -145,64 +147,27 @@ fn balance(opaque_wallet: &OpaqueWallet) -> FfiResult<u64> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Non-opaque returned values
|
#[ffi_export]
|
||||||
|
fn list_transactions(opaque_wallet: &OpaqueWallet) -> FfiResult<repr_c::Vec<TransactionDetails>> {
|
||||||
|
let transactions_result = opaque_wallet.raw.list_transactions(false);
|
||||||
|
|
||||||
#[derive_ReprC]
|
match transactions_result {
|
||||||
#[repr(C)]
|
Ok(v) => FfiResult {
|
||||||
#[derive(Debug, Clone)]
|
ok: {
|
||||||
pub struct OutPoint {
|
let ve: Vec<TransactionDetails> =
|
||||||
/// The referenced transaction's txid, as hex string
|
v.iter().map(|t| TransactionDetails::from(t)).collect();
|
||||||
pub txid: char_p_boxed,
|
repr_c::Vec::from(ve)
|
||||||
/// The index of the referenced output in its transaction's vout
|
},
|
||||||
pub vout: u32,
|
err: FfiError::None,
|
||||||
}
|
},
|
||||||
|
Err(e) => FfiResult {
|
||||||
impl From<&bdk::bitcoin::OutPoint> for OutPoint {
|
ok: repr_c::Vec::EMPTY,
|
||||||
fn from(op: &bdk::bitcoin::OutPoint) -> Self {
|
err: FfiError::from(&e),
|
||||||
OutPoint {
|
},
|
||||||
txid: char_p_boxed::try_from(op.txid.to_string()).unwrap(),
|
|
||||||
vout: op.vout,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive_ReprC]
|
#[ffi_export]
|
||||||
#[repr(C)]
|
fn free_vectxdetails_result(txdetails_result: FfiResult<repr_c::Vec<TransactionDetails>>) {
|
||||||
#[derive(Debug, Clone)]
|
drop(txdetails_result)
|
||||||
pub struct TxOut {
|
|
||||||
/// The value of the output, in satoshis
|
|
||||||
pub value: u64,
|
|
||||||
/// The script which must satisfy for the output to be spent, as hex string
|
|
||||||
pub script_pubkey: char_p_boxed,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&bdk::bitcoin::TxOut> for TxOut {
|
|
||||||
fn from(to: &bdk::bitcoin::TxOut) -> Self {
|
|
||||||
TxOut {
|
|
||||||
value: to.value,
|
|
||||||
script_pubkey: char_p_boxed::try_from(to.script_pubkey.to_string()).unwrap(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive_ReprC]
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct LocalUtxo {
|
|
||||||
/// Reference to a transaction output
|
|
||||||
pub outpoint: OutPoint,
|
|
||||||
/// Transaction output
|
|
||||||
pub txout: TxOut,
|
|
||||||
/// Type of keychain, as short 0 for "external" or 1 for "internal"
|
|
||||||
pub keychain: u16,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&bdk::LocalUtxo> for LocalUtxo {
|
|
||||||
fn from(lu: &bdk::LocalUtxo) -> Self {
|
|
||||||
LocalUtxo {
|
|
||||||
outpoint: OutPoint::from(&lu.outpoint),
|
|
||||||
txout: TxOut::from(&lu.txout),
|
|
||||||
keychain: lu.keychain as u16,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
99
src/wallet/transaction.rs
Normal file
99
src/wallet/transaction.rs
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
|
use ::safer_ffi::prelude::*;
|
||||||
|
use safer_ffi::char_p::char_p_boxed;
|
||||||
|
|
||||||
|
// Non-opaque returned values
|
||||||
|
|
||||||
|
#[derive_ReprC]
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct TransactionDetails {
|
||||||
|
// TODO Optional transaction
|
||||||
|
// pub transaction: Option<Transaction>,
|
||||||
|
/// Transaction id
|
||||||
|
pub txid: char_p_boxed,
|
||||||
|
/// Timestamp
|
||||||
|
pub timestamp: u64,
|
||||||
|
/// Received value (sats)
|
||||||
|
pub received: u64,
|
||||||
|
/// Sent value (sats)
|
||||||
|
pub sent: u64,
|
||||||
|
/// Fee value (sats)
|
||||||
|
pub fees: u64,
|
||||||
|
/// Confirmed in block height, `None` means unconfirmed
|
||||||
|
pub height: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&bdk::TransactionDetails> for TransactionDetails {
|
||||||
|
fn from(op: &bdk::TransactionDetails) -> Self {
|
||||||
|
TransactionDetails {
|
||||||
|
txid: char_p_boxed::try_from(op.txid.to_string()).unwrap(),
|
||||||
|
timestamp: op.timestamp,
|
||||||
|
received: op.received,
|
||||||
|
sent: op.sent,
|
||||||
|
fees: op.fees,
|
||||||
|
height: op.height.map(|h| h as i32).unwrap_or(-1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive_ReprC]
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct OutPoint {
|
||||||
|
/// The referenced transaction's txid, as hex string
|
||||||
|
pub txid: char_p_boxed,
|
||||||
|
/// The index of the referenced output in its transaction's vout
|
||||||
|
pub vout: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&bdk::bitcoin::OutPoint> for OutPoint {
|
||||||
|
fn from(op: &bdk::bitcoin::OutPoint) -> Self {
|
||||||
|
OutPoint {
|
||||||
|
txid: char_p_boxed::try_from(op.txid.to_string()).unwrap(),
|
||||||
|
vout: op.vout,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive_ReprC]
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct TxOut {
|
||||||
|
/// The value of the output, in satoshis
|
||||||
|
pub value: u64,
|
||||||
|
/// The script which must satisfy for the output to be spent, as hex string
|
||||||
|
pub script_pubkey: char_p_boxed,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&bdk::bitcoin::TxOut> for TxOut {
|
||||||
|
fn from(to: &bdk::bitcoin::TxOut) -> Self {
|
||||||
|
TxOut {
|
||||||
|
value: to.value,
|
||||||
|
script_pubkey: char_p_boxed::try_from(to.script_pubkey.to_string()).unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive_ReprC]
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct LocalUtxo {
|
||||||
|
/// Reference to a transaction output
|
||||||
|
pub outpoint: OutPoint,
|
||||||
|
/// Transaction output
|
||||||
|
pub txout: TxOut,
|
||||||
|
/// Type of keychain, as short 0 for "external" or 1 for "internal"
|
||||||
|
pub keychain: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&bdk::LocalUtxo> for LocalUtxo {
|
||||||
|
fn from(lu: &bdk::LocalUtxo) -> Self {
|
||||||
|
LocalUtxo {
|
||||||
|
outpoint: OutPoint::from(&lu.outpoint),
|
||||||
|
txout: TxOut::from(&lu.txout),
|
||||||
|
keychain: lu.keychain as u16,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user