use std::ops::Deref;
use std::sync::Arc;
use bark::actions::WalletActionId;
use bitcoin::{Amount, OutPoint, SignedAmount, Transaction, Txid};
use bitcoin::secp256k1::PublicKey;
#[cfg(feature = "utoipa")]
use utoipa::ToSchema;
use ark::{Vtxo, VtxoId};
use ark::vtxo::{Bare, Full, VtxoPolicyKind};
use bark::movement::MovementId;
use bark::vtxo::VtxoState;
use bitcoin_ext::{BlockDelta, BlockHeight};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
pub struct BlockRef {
pub height: BlockHeight,
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
pub hash: bitcoin::BlockHash,
}
impl From<bitcoin_ext::BlockRef> for BlockRef {
fn from(v: bitcoin_ext::BlockRef) -> Self {
BlockRef {
height: v.height,
hash: v.hash,
}
}
}
impl From<BlockRef> for bitcoin_ext::BlockRef {
fn from(v: BlockRef) -> Self {
bitcoin_ext::BlockRef {
height: v.height,
hash: v.hash,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
pub struct UtxoInfo {
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
pub outpoint: OutPoint,
#[serde(rename = "amount_sat", with = "bitcoin::amount::serde::as_sat")]
#[cfg_attr(feature = "utoipa", schema(value_type = u64))]
pub amount: Amount,
pub confirmation_height: Option<u32>,
}
impl From<bark::UtxoInfo> for UtxoInfo {
fn from(v: bark::UtxoInfo) -> Self {
UtxoInfo {
outpoint: v.outpoint,
amount: v.amount,
confirmation_height: v.confirmation_height,
}
}
}
impl From<bark::onchain::Utxo> for UtxoInfo {
fn from(v: bark::onchain::Utxo) -> Self {
match v {
bark::onchain::Utxo::Local(o) => UtxoInfo {
outpoint: o.outpoint,
amount: o.amount,
confirmation_height: o.confirmation_height,
},
bark::onchain::Utxo::Exit(e) => UtxoInfo {
outpoint: e.vtxo.point(),
amount: e.vtxo.amount(),
confirmation_height: Some(e.height),
},
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
pub struct VtxoInfo {
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
pub id: VtxoId,
#[serde(rename = "amount_sat", with = "bitcoin::amount::serde::as_sat")]
#[cfg_attr(feature = "utoipa", schema(value_type = u64))]
pub amount: Amount,
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
pub policy_type: VtxoPolicyKind,
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
pub user_pubkey: PublicKey,
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
pub server_pubkey: PublicKey,
pub expiry_height: BlockHeight,
pub exit_delta: BlockDelta,
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
pub chain_anchor: OutPoint,
pub exit_depth: Option<u16>,
}
impl<'a> From<&'a Vtxo<Bare>> for VtxoInfo {
fn from(v: &'a Vtxo<Bare>) -> VtxoInfo {
VtxoInfo {
id: v.id(),
amount: v.amount(),
policy_type: v.policy().policy_type(),
user_pubkey: v.user_pubkey(),
server_pubkey: v.server_pubkey(),
expiry_height: v.expiry_height(),
exit_delta: v.exit_delta(),
chain_anchor: v.chain_anchor(),
exit_depth: None,
}
}
}
impl<'a> From<&'a Vtxo<Full>> for VtxoInfo {
fn from(v: &'a Vtxo<Full>) -> VtxoInfo {
VtxoInfo {
id: v.id(),
amount: v.amount(),
policy_type: v.policy().policy_type(),
user_pubkey: v.user_pubkey(),
server_pubkey: v.server_pubkey(),
expiry_height: v.expiry_height(),
exit_delta: v.exit_delta(),
chain_anchor: v.chain_anchor(),
exit_depth: Some(v.exit_depth()),
}
}
}
impl From<Vtxo<Bare>> for VtxoInfo {
fn from(v: Vtxo<Bare>) -> VtxoInfo {
VtxoInfo::from(&v)
}
}
impl From<Vtxo<Full>> for VtxoInfo {
fn from(v: Vtxo<Full>) -> VtxoInfo {
VtxoInfo::from(&v)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
pub struct WalletVtxoInfo {
#[serde(flatten)]
pub vtxo: VtxoInfo,
pub state: VtxoStateInfo,
}
impl From<bark::WalletVtxo> for WalletVtxoInfo {
fn from(v: bark::WalletVtxo) -> Self {
WalletVtxoInfo {
vtxo: v.vtxo.into(),
state: v.state.into(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
pub struct EncodedVtxo(pub String);
impl Deref for WalletVtxoInfo {
type Target = VtxoInfo;
fn deref(&self) -> &Self::Target {
&self.vtxo
}
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
#[serde(tag = "type", rename_all = "kebab-case")]
pub enum VtxoStateInfo {
Spendable,
Spent,
Locked {
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "utoipa", schema(value_type = u32))]
movement_id: Option<MovementId>,
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
action_id: Option<WalletActionId>,
},
}
impl From<VtxoState> for VtxoStateInfo {
fn from(state: VtxoState) -> Self {
match state {
VtxoState::Spendable => VtxoStateInfo::Spendable,
VtxoState::Spent => VtxoStateInfo::Spent,
VtxoState::Locked { holder } => {
match holder {
Some(bark::vtxo::VtxoLockHolder::Movement { id }) => {
VtxoStateInfo::Locked { movement_id: Some(id), action_id: None }
},
Some(bark::vtxo::VtxoLockHolder::Action { id }) => {
VtxoStateInfo::Locked { movement_id: None, action_id: Some(id) }
},
None => VtxoStateInfo::Locked { movement_id: None, action_id: None },
}
},
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
pub struct TransactionInfo {
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
pub txid: Txid,
#[serde(with = "bitcoin::consensus::serde::With::<bitcoin::consensus::serde::Hex>")]
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
pub tx: Transaction,
}
impl From<bark::exit::TransactionInfo> for TransactionInfo {
fn from(v: bark::exit::TransactionInfo) -> Self {
TransactionInfo { txid: v.txid, tx: v.tx }
}
}
impl From<Transaction> for TransactionInfo {
fn from(v: Transaction) -> Self {
TransactionInfo { txid: v.compute_txid(), tx: v }
}
}
impl From<Arc<Transaction>> for TransactionInfo {
fn from(v: Arc<Transaction>) -> Self {
TransactionInfo { txid: v.compute_txid(), tx: (*v).clone() }
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
pub struct WalletTxInfo {
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
pub txid: Txid,
#[serde(with = "bitcoin::consensus::serde::With::<bitcoin::consensus::serde::Hex>")]
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
pub tx: Transaction,
#[serde(rename = "onchain_fee_sat", default, with = "bitcoin::amount::serde::as_sat::opt", skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "utoipa", schema(value_type = Option<u64>))]
pub onchain_fees: Option<Amount>,
#[serde(rename = "balance_change_sat", with = "bitcoin::amount::serde::as_sat")]
#[cfg_attr(feature = "utoipa", schema(value_type = i64))]
pub balance_change: SignedAmount,
pub confirmation: Option<BlockRef>,
}
impl From<bark::onchain::WalletTxInfo> for WalletTxInfo {
fn from(v: bark::onchain::WalletTxInfo) -> Self {
WalletTxInfo {
txid: v.txid,
tx: (*v.tx).clone(),
onchain_fees: v.onchain_fees,
balance_change: v.balance_change,
confirmation: v.confirmation.map(Into::into),
}
}
}