1use crate::Error;
2use bitcoin::hashes::Hash;
3use bitcoin::hex::DisplayHex;
4use bitcoin::hex::FromHex;
5use bitcoin::Txid;
6use serde::Serialize;
7use serde::Serializer;
8use std::num::NonZeroU64;
9
10pub mod packet;
11
12#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
14pub struct AssetId {
15 pub txid: Txid,
16 pub group_index: u16,
17}
18
19impl AssetId {
20 fn encode(&self, buf: &mut Vec<u8>) {
21 let mut txid_bytes = self.txid.to_byte_array();
23 txid_bytes.reverse();
24 buf.extend_from_slice(&txid_bytes);
25 buf.extend_from_slice(&self.group_index.to_le_bytes());
26 }
27}
28
29impl std::fmt::Display for AssetId {
30 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31 write!(
32 f,
33 "{}{}",
34 self.txid,
35 self.group_index.to_le_bytes().to_lower_hex_string()
36 )
37 }
38}
39
40impl Serialize for AssetId {
41 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
42 where
43 S: Serializer,
44 {
45 serializer.collect_str(self)
46 }
47}
48
49impl std::str::FromStr for AssetId {
50 type Err = Error;
51
52 fn from_str(s: &str) -> Result<Self, Self::Err> {
53 if s.len() != 68 {
54 return Err(Error::ad_hoc(format!(
55 "invalid asset ID format '{}', expected 68 hex chars (txid + 2-byte LE group index)",
56 s
57 )));
58 }
59
60 let txid: Txid = s[..64]
61 .parse()
62 .map_err(|e| Error::ad_hoc(format!("invalid txid in asset ID: {}", e)))?;
63
64 let group_index_bytes = <[u8; 2]>::from_hex(&s[64..])
65 .map_err(|e| Error::ad_hoc(format!("invalid group index in asset ID: {}", e)))?;
66 let group_index = u16::from_le_bytes(group_index_bytes);
67
68 Ok(Self { txid, group_index })
69 }
70}
71
72#[derive(Clone, Debug)]
74pub enum ControlAssetConfig {
75 New {
77 amount: NonZeroU64,
79 },
80 Existing {
82 id: AssetId,
84 },
85}
86
87impl ControlAssetConfig {
88 pub fn new(amount: u64) -> Result<Self, Error> {
94 let amount =
95 NonZeroU64::new(amount).ok_or(Error::ad_hoc("control asset amount cannot be zero"))?;
96
97 Ok(Self::New { amount })
98 }
99
100 pub fn existing(id: AssetId) -> Self {
106 Self::Existing { id }
107 }
108}