use derive_more::derive::Debug;
use dutils::error::ContextWrapper;
use fixedstr::str8;
use crate::utils::{fixed::Fixed128, sha256::IntoHash256};
use super::inscriptions::Outpoint;
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Clone, Copy, Debug, derive_more::From, Eq, PartialEq, Hash)]
pub struct OriginalBrc4Ticker(pub [u8; 4]);
#[cfg(feature = "schema")]
impl schemars::JsonSchema for OriginalBrc4Ticker {
fn schema_name() -> std::borrow::Cow<'static, str> {
"Brc4 token tick".into()
}
fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
schemars::json_schema!({
"type": "string",
"pattern": "^.{4}$",
"description": "4 byte sized token tick"
})
}
}
impl std::fmt::Display for OriginalBrc4Ticker {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&String::from_utf8_lossy(&self.0))
}
}
impl OriginalBrc4Ticker {
pub fn from_u32(v: u32) -> Self {
Self(v.to_le_bytes())
}
}
impl serde::Serialize for OriginalBrc4Ticker {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_bytes(&self.0)
}
}
impl<'de> serde::Deserialize<'de> for OriginalBrc4Ticker {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let bytes = Vec::<u8>::deserialize(deserializer)?;
if bytes.len() != 4 {
return Err(serde::de::Error::invalid_length(bytes.len(), &"an array of length 4"));
}
let mut array = [0u8; 4];
array.copy_from_slice(&bytes);
Ok(OriginalBrc4Ticker(array))
}
}
#[derive(Clone, Debug, derive_more::From, serde::Serialize, serde::Deserialize, Eq, PartialEq, Hash)]
#[serde(transparent)]
pub struct Brc4Ticker(pub str8);
impl Brc4Ticker {
pub fn from_u32(v: u32) -> Self {
v.to_le_bytes().as_slice().try_into().unwrap()
}
pub fn as_str(&self) -> &str {
self.0.as_str()
}
}
impl IntoHash256 for Brc4Ticker {
fn hash_256(&self) -> super::hash::Hash256 {
"@brc4ticker_".hash_256().chain_hash(&self.0.as_bytes())
}
}
impl<'a> TryFrom<&'a [u8]> for Brc4Ticker {
type Error = <[u8; 4] as TryFrom<&'a [u8]>>::Error;
fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
<[u8; 4]>::try_from(value).map(|v| {
let v = String::from_utf8_lossy(&v).to_lowercase();
assert!(v.len() <= 7, "all brc4 tickers must fit into 6 bytes in lowercase form");
Self(str8::make(&v))
})
}
}
impl TryFrom<OriginalBrc4Ticker> for Brc4Ticker {
type Error = <Self as TryFrom<&'static [u8]>>::Error;
fn try_from(value: OriginalBrc4Ticker) -> Result<Self, Self::Error> {
value.0.as_slice().try_into()
}
}
impl std::str::FromStr for Brc4Ticker {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.starts_with("0x") && s.len() > 4 {
let x = u32::from_str_radix(&s[2..], 16).anyhow()?;
Ok(Self::from_u32(x))
} else {
s.as_bytes().try_into().anyhow()
}
}
}
impl std::fmt::Display for Brc4Ticker {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.0.as_str())
}
}
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
pub enum Brc4OpErr {
NotDeployed,
AlreadyDeployed,
ReachDecBound,
ReachLimBound,
SupplyMinted,
InsufficientBalance,
Transferred,
}
#[derive(Clone, Copy, serde::Serialize, serde::Deserialize)]
#[serde(untagged)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
pub enum InscriptionProtocolErr {
Brc4(Brc4OpErr),
Bellmap(BellmapOpErr),
}
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, Copy, Eq, PartialEq, Hash)]
#[repr(u8)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
pub enum BellmapOpErr {
LowFee,
InvalidHeight,
AlreadyExists,
}
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
pub enum Brc4Op {
Mint {
tick: OriginalBrc4Ticker,
amt: Fixed128<18>,
},
Deploy {
tick: OriginalBrc4Ticker,
max: Fixed128<18>,
lim: Fixed128<18>,
dec: u8,
},
Transfer {
tick: OriginalBrc4Ticker,
amt: Fixed128<18>,
},
Transferred {
tick: OriginalBrc4Ticker,
amt: Fixed128<18>,
},
}
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
pub struct SnsValue {
pub name: String,
pub avatar: Option<Outpoint>,
pub rev: Option<String>,
pub relay: Option<Outpoint>,
}
#[derive(Clone, serde::Serialize, serde::Deserialize, Debug, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
pub enum InscriptionProtocol {
Brc4 { operation: Brc4Op, error: Option<Brc4Err> },
Bellmap { block: u32, error: Option<BellmapOpErr> },
Numbers(i128),
Sns(SnsValue),
}
impl InscriptionProtocol {
pub fn is_token(&self) -> bool {
matches!(self, InscriptionProtocol::Brc4 { .. })
}
}
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
pub enum Brc4Err {
NotDeployed,
AlreadyDeployed,
ReachDecBound,
ReachLimBound,
SupplyMinted,
InsufficientBalance,
Transferred,
AlreadySpent,
}