use crate::contract::object::ObjectError;
use bitcoin::{Address, Script, XOnlyPublicKey};
use miniscript::{Descriptor, DescriptorTrait};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::convert::TryFrom;
#[derive(Serialize, Deserialize, JsonSchema, Clone, Debug)]
#[serde(untagged)]
pub enum ExtendedAddress {
Address(Address),
Descriptor(Descriptor<XOnlyPublicKey>),
OpReturn(OpReturn),
Unknown(bitcoin::Script),
}
impl ExtendedAddress {
pub fn make_op_return<'a, I: ?Sized>(data: &'a I) -> Result<Self, ObjectError>
where
&'a [u8]: From<&'a I>,
{
let slice: &[u8] = data.into();
if slice.len() > 40 {
return Err(ObjectError::OpReturnTooLong);
}
Ok(ExtendedAddress::OpReturn(OpReturn(
bitcoin::Script::new_op_return(slice),
)))
}
}
#[derive(Serialize, Deserialize, JsonSchema, Clone, Debug)]
#[serde(try_from = "Script")]
#[serde(into = "Script")]
pub struct OpReturn(Script);
impl TryFrom<Script> for OpReturn {
type Error = &'static str;
fn try_from(s: Script) -> std::result::Result<Self, Self::Error> {
if s.is_op_return() {
Ok(OpReturn(s))
} else {
Err("Not an Op Return")
}
}
}
impl From<OpReturn> for Script {
fn from(o: OpReturn) -> Self {
o.0
}
}
impl From<Address> for ExtendedAddress {
fn from(a: Address) -> Self {
ExtendedAddress::Address(a)
}
}
impl From<Descriptor<XOnlyPublicKey>> for ExtendedAddress {
fn from(a: Descriptor<XOnlyPublicKey>) -> Self {
ExtendedAddress::Descriptor(a)
}
}
impl From<ExtendedAddress> for Script {
fn from(s: ExtendedAddress) -> Self {
match s {
ExtendedAddress::Address(a) => a.script_pubkey(),
ExtendedAddress::OpReturn(OpReturn(s)) => s,
ExtendedAddress::Unknown(s) => s,
ExtendedAddress::Descriptor(d) => d.script_pubkey(),
}
}
}
impl From<&ExtendedAddress> for Script {
fn from(s: &ExtendedAddress) -> Self {
match s {
ExtendedAddress::Address(a) => a.script_pubkey(),
ExtendedAddress::OpReturn(OpReturn(s)) => s.clone(),
ExtendedAddress::Unknown(s) => s.clone(),
ExtendedAddress::Descriptor(d) => {
let r = d.script_pubkey();
r
}
}
}
}