use crate::{Addr, AddrBytes, OutputType, Sats};
use bitcoin::ScriptBuf;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize, Serializer, ser::SerializeStruct};
#[derive(Debug, Clone, Deserialize, JsonSchema)]
pub struct TxOut {
#[serde(
rename = "scriptpubkey",
serialize_with = "serialize_with_script_pubkey"
)]
#[schemars(
with = "String",
example = "00143b064c595a95f977f00352d6e917501267cacdc6"
)]
pub script_pubkey: ScriptBuf,
#[allow(dead_code)]
#[serde(skip, rename = "scriptpubkey_asm")]
#[schemars(
with = "String",
example = "OP_0 OP_PUSHBYTES_20 3b064c595a95f977f00352d6e917501267cacdc6"
)]
script_pubkey_asm: (),
#[allow(dead_code)]
#[serde(skip, rename = "scriptpubkey_type")]
#[schemars(with = "OutputType", example = &"v0_p2wpkh")]
script_pubkey_type: (),
#[allow(dead_code)]
#[serde(skip, rename = "scriptpubkey_address")]
#[schemars(with = "Option<Addr>", example = Some("bc1q8vryck26jhuh0uqr2ttwj96szfnu4nwxfmu39y".to_string()))]
script_pubkey_addr: (),
#[schemars(example = Sats::new(7782))]
pub value: Sats,
}
impl TxOut {
pub fn addr(&self) -> Option<Addr> {
Addr::try_from(&self.script_pubkey).ok()
}
pub fn addr_bytes(&self) -> Option<AddrBytes> {
AddrBytes::try_from(&self.script_pubkey).ok()
}
pub fn type_(&self) -> OutputType {
OutputType::from(&self.script_pubkey)
}
pub fn script_pubkey_asm(&self) -> String {
self.script_pubkey.to_asm_string()
}
}
impl From<bitcoin::TxOut> for TxOut {
#[inline]
fn from(txout: bitcoin::TxOut) -> Self {
Self {
script_pubkey: txout.script_pubkey,
value: txout.value.into(),
script_pubkey_asm: (),
script_pubkey_addr: (),
script_pubkey_type: (),
}
}
}
impl From<(ScriptBuf, Sats)> for TxOut {
#[inline]
fn from((script, value): (ScriptBuf, Sats)) -> Self {
Self {
script_pubkey: script,
script_pubkey_addr: (),
script_pubkey_asm: (),
script_pubkey_type: (),
value,
}
}
}
impl Serialize for TxOut {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let output_type = self.type_();
let addr = match output_type {
OutputType::P2PK65 | OutputType::P2PK33 => None,
_ => self.addr(),
};
let field_count = if addr.is_some() { 5 } else { 4 };
let mut state = serializer.serialize_struct("TxOut", field_count)?;
state.serialize_field("scriptpubkey", &self.script_pubkey.to_hex_string())?;
state.serialize_field("scriptpubkey_asm", &self.script_pubkey_asm())?;
state.serialize_field("scriptpubkey_type", &output_type)?;
if let Some(addr) = &addr {
state.serialize_field("scriptpubkey_address", addr)?;
}
state.serialize_field("value", &self.value)?;
state.end()
}
}