use std::{fmt, str::FromStr};
use bitcoin::ScriptBuf;
use brk_error::Error;
use derive_more::Deref;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use vecdb::Formattable;
use crate::AddrBytes;
use super::OutputType;
#[derive(Debug, Clone, Deref, Serialize, Deserialize, JsonSchema)]
#[serde(transparent)]
#[schemars(
example = &"04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f",
example = &"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
example = &"bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq"
)]
pub struct Addr(String);
impl Addr {
pub fn script(&self) -> Result<ScriptBuf, Error> {
AddrBytes::addr_to_script(&self.0)
}
}
impl From<String> for Addr {
#[inline]
fn from(addr: String) -> Self {
Self(addr)
}
}
impl TryFrom<&ScriptBuf> for Addr {
type Error = Error;
fn try_from(script: &ScriptBuf) -> Result<Self, Self::Error> {
Self::try_from((script, OutputType::from(script)))
}
}
impl TryFrom<(&ScriptBuf, OutputType)> for Addr {
type Error = Error;
fn try_from((script, output_type): (&ScriptBuf, OutputType)) -> Result<Self, Self::Error> {
match output_type {
OutputType::P2PK65 | OutputType::P2PK33 => {
let bytes = AddrBytes::try_from((script, output_type))?;
Ok(Self(bytes_to_hex(bytes.as_slice())))
}
_ if output_type.is_addr() => {
let addr = bitcoin::Address::from_script(script, bitcoin::Network::Bitcoin)
.map_err(|_| Error::InvalidAddr)?;
Ok(Self(addr.to_string()))
}
_ => Err(Error::InvalidAddr),
}
}
}
impl TryFrom<&AddrBytes> for Addr {
type Error = Error;
fn try_from(bytes: &AddrBytes) -> Result<Self, Self::Error> {
Self::try_from(&bytes.to_script_pubkey())
}
}
fn bytes_to_hex(bytes: &[u8]) -> String {
let mut hex_string = String::with_capacity(bytes.len() * 2);
for byte in bytes {
use std::fmt::Write;
write!(&mut hex_string, "{:02x}", byte).unwrap();
}
hex_string
}
impl FromStr for Addr {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let _ = AddrBytes::addr_to_script(s)?;
Ok(Self(s.to_string()))
}
}
impl Formattable for Addr {
fn write_to(&self, buf: &mut Vec<u8>) {
buf.extend_from_slice(self.0.as_bytes());
}
fn fmt_json(&self, buf: &mut Vec<u8>) {
buf.push(b'"');
self.write_to(buf);
buf.push(b'"');
}
}
impl fmt::Display for Addr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.0)
}
}