Skip to main content

fiber_types/
config.rs

1use crate::gen::fiber as molecule_fiber;
2use crate::primitives::u8_32_as_byte_32;
3use ckb_types::packed::{OutPoint, Script};
4use ckb_types::prelude::Pack;
5use molecule::prelude::{Builder, Entity};
6use serde::{Deserialize, Serialize};
7use serde_with::serde_as;
8
9// Serde converters for CKB types
10serde_with::serde_conv!(
11    ScriptHashTypeWrapper,
12    ckb_types::core::ScriptHashType,
13    |s: &ckb_types::core::ScriptHashType| -> String {
14        use ckb_types::core::ScriptHashType;
15        let v = match s {
16            ScriptHashType::Type => "type",
17            ScriptHashType::Data => "data",
18            ScriptHashType::Data1 => "data1",
19            ScriptHashType::Data2 => "data2",
20            _ => "unknown",
21        };
22        v.to_string()
23    },
24    |s: String| {
25        use ckb_types::core::ScriptHashType;
26        let v = match s.to_lowercase().as_str() {
27            "type" => ScriptHashType::Type,
28            "data" => ScriptHashType::Data,
29            "data1" => ScriptHashType::Data1,
30            "data2" => ScriptHashType::Data2,
31            _ => return Err("invalid hash type"),
32        };
33        Ok(v)
34    }
35);
36
37serde_with::serde_conv!(
38    DepTypeWrapper,
39    ckb_types::core::DepType,
40    |s: &ckb_types::core::DepType| -> String {
41        use ckb_types::core::DepType;
42        let v = match s {
43            DepType::Code => "code",
44            DepType::DepGroup => "dep_group",
45        };
46        v.to_string()
47    },
48    |s: String| {
49        let v = match s.to_lowercase().as_str() {
50            "code" => ckb_types::core::DepType::Code,
51            "dep_group" => ckb_types::core::DepType::DepGroup,
52            _ => return Err("invalid dep type"),
53        };
54        Ok(v)
55    }
56);
57
58/// UDT argument information.
59#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash)]
60pub struct UdtArgInfo {
61    /// Name of the UDT
62    pub name: String,
63    /// UDT script configuration
64    pub script: UdtScript,
65    /// Auto-accept amount for this UDT
66    pub auto_accept_amount: Option<u128>,
67    /// Cell dependencies for this UDT
68    pub cell_deps: Vec<UdtDep>,
69}
70
71/// UDT script configuration.
72#[serde_as]
73#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash, Default)]
74pub struct UdtScript {
75    /// Code hash of the UDT script
76    pub code_hash: ckb_types::H256,
77    /// Hash type of the UDT script
78    #[serde_as(as = "ScriptHashTypeWrapper")]
79    pub hash_type: ckb_types::core::ScriptHashType,
80    /// Arguments for the UDT script
81    pub args: String,
82}
83
84/// UDT cell dependency configuration.
85#[serde_as]
86#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash)]
87pub struct UdtCellDep {
88    /// The outpoint of the cell dependency
89    pub out_point: ckb_jsonrpc_types::OutPoint,
90    /// The dependency type
91    #[serde_as(as = "DepTypeWrapper")]
92    pub dep_type: ckb_types::core::DepType,
93}
94
95/// UDT dependency (either cell dep or type ID).
96#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash)]
97pub struct UdtDep {
98    /// Cell dependency (if using direct reference)
99    #[serde(default)]
100    pub cell_dep: Option<UdtCellDep>,
101    /// Type ID script (if using type ID reference)
102    #[serde(default)]
103    pub type_id: Option<ckb_jsonrpc_types::Script>,
104}
105
106impl UdtDep {
107    /// Create a UdtDep with a cell dependency.
108    pub fn with_cell_dep(cell_dep: UdtCellDep) -> Self {
109        Self {
110            cell_dep: Some(cell_dep),
111            type_id: None,
112        }
113    }
114
115    /// Create a UdtDep with a type ID script.
116    pub fn with_type_id(type_id: ckb_jsonrpc_types::Script) -> Self {
117        Self {
118            cell_dep: None,
119            type_id: Some(type_id),
120        }
121    }
122}
123
124/// Collection of UDT configuration information.
125#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash, Default)]
126pub struct UdtCfgInfos(pub Vec<UdtArgInfo>);
127
128impl std::str::FromStr for UdtCfgInfos {
129    type Err = serde_json::Error;
130
131    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
132        serde_json::from_str(s)
133    }
134}
135
136// UdtCfgInfos molecule conversions
137
138impl From<UdtCfgInfos> for molecule_fiber::UdtCfgInfos {
139    fn from(udt_cfg_infos: UdtCfgInfos) -> Self {
140        molecule_fiber::UdtCfgInfos::new_builder()
141            .set(
142                udt_cfg_infos
143                    .0
144                    .into_iter()
145                    .map(|udt_arg_info| udt_arg_info.into())
146                    .collect(),
147            )
148            .build()
149    }
150}
151
152impl TryFrom<molecule_fiber::UdtCfgInfos> for UdtCfgInfos {
153    type Error = anyhow::Error;
154
155    fn try_from(udt_cfg_infos: molecule_fiber::UdtCfgInfos) -> Result<Self, Self::Error> {
156        Ok(UdtCfgInfos(
157            udt_cfg_infos
158                .into_iter()
159                .map(|udt_arg_info| udt_arg_info.try_into())
160                .collect::<Result<Vec<_>, _>>()?,
161        ))
162    }
163}
164
165// UdtArgInfo molecule conversions
166
167impl From<UdtArgInfo> for molecule_fiber::UdtArgInfo {
168    fn from(udt_arg_info: UdtArgInfo) -> Self {
169        let builder = molecule_fiber::UdtArgInfo::new_builder()
170            .name(udt_arg_info.name.pack())
171            .script(udt_arg_info.script.into())
172            .cell_deps(
173                molecule_fiber::UdtCellDeps::new_builder()
174                    .set(udt_arg_info.cell_deps.into_iter().map(Into::into).collect())
175                    .build(),
176            );
177        let builder = if let Some(amount) = udt_arg_info.auto_accept_amount {
178            builder.auto_accept_amount(
179                molecule_fiber::Uint128Opt::new_builder()
180                    .set(Some(amount.pack()))
181                    .build(),
182            )
183        } else {
184            builder
185        };
186        builder.build()
187    }
188}
189
190impl TryFrom<molecule_fiber::UdtArgInfo> for UdtArgInfo {
191    type Error = anyhow::Error;
192
193    fn try_from(udt_arg_info: molecule_fiber::UdtArgInfo) -> Result<Self, Self::Error> {
194        use ckb_types::prelude::Unpack;
195        Ok(UdtArgInfo {
196            name: String::from_utf8(udt_arg_info.name().unpack()).unwrap_or_default(),
197            script: udt_arg_info.script().try_into()?,
198            auto_accept_amount: udt_arg_info
199                .auto_accept_amount()
200                .to_opt()
201                .map(|amount| amount.unpack()),
202            cell_deps: udt_arg_info
203                .cell_deps()
204                .into_iter()
205                .map(|cell_dep| cell_dep.try_into())
206                .collect::<Result<Vec<_>, _>>()?,
207        })
208    }
209}
210
211// UdtScript molecule conversions
212
213impl From<UdtScript> for molecule_fiber::UdtScript {
214    fn from(udt_script: UdtScript) -> Self {
215        use ckb_types::core::ScriptHashType;
216        let code_hash_bytes: [u8; 32] = udt_script.code_hash.into();
217        molecule_fiber::UdtScript::new_builder()
218            .code_hash(u8_32_as_byte_32(&code_hash_bytes))
219            .hash_type(
220                match udt_script.hash_type {
221                    ScriptHashType::Type => 1u8,
222                    ScriptHashType::Data => 0u8,
223                    ScriptHashType::Data1 => 2u8,
224                    ScriptHashType::Data2 => 4u8,
225                    _ => panic!("unsupported hash type: {:?}", udt_script.hash_type),
226                }
227                .into(),
228            )
229            .args(udt_script.args.pack())
230            .build()
231    }
232}
233
234impl TryFrom<molecule_fiber::UdtScript> for UdtScript {
235    type Error = anyhow::Error;
236
237    fn try_from(udt_script: molecule_fiber::UdtScript) -> Result<Self, Self::Error> {
238        use ckb_types::core::ScriptHashType;
239        use ckb_types::prelude::Unpack;
240        let hash_type: u8 = udt_script.hash_type().into();
241        Ok(UdtScript {
242            code_hash: ckb_types::H256::from_slice(udt_script.code_hash().as_slice())?,
243            hash_type: match hash_type {
244                0 => ScriptHashType::Data,
245                1 => ScriptHashType::Type,
246                2 => ScriptHashType::Data1,
247                4 => ScriptHashType::Data2,
248                _ => return Err(anyhow::anyhow!("Invalid hash_type: {}", hash_type)),
249            },
250            args: String::from_utf8(udt_script.args().unpack()).unwrap_or_default(),
251        })
252    }
253}
254
255// UdtDep molecule conversions
256
257impl From<UdtDep> for molecule_fiber::UdtDep {
258    fn from(udt_dep: UdtDep) -> Self {
259        match udt_dep {
260            UdtDep {
261                cell_dep: Some(cell_dep),
262                type_id: None,
263            } => molecule_fiber::UdtDep::new_builder()
264                .set(molecule_fiber::UdtDepUnion::UdtCellDep(cell_dep.into()))
265                .build(),
266            UdtDep {
267                cell_dep: None,
268                type_id: Some(type_id),
269            } => molecule_fiber::UdtDep::new_builder()
270                .set(molecule_fiber::UdtDepUnion::Script(Script::from(type_id)))
271                .build(),
272            _ => panic!("UdtDep must have exactly one of cell_dep or type_id"),
273        }
274    }
275}
276
277impl TryFrom<molecule_fiber::UdtDep> for UdtDep {
278    type Error = anyhow::Error;
279
280    fn try_from(udt_dep: molecule_fiber::UdtDep) -> Result<Self, Self::Error> {
281        match udt_dep.to_enum() {
282            molecule_fiber::UdtDepUnion::UdtCellDep(cell_dep) => Ok(UdtDep {
283                cell_dep: Some(cell_dep.try_into()?),
284                type_id: None,
285            }),
286            molecule_fiber::UdtDepUnion::Script(type_id) => Ok(UdtDep {
287                cell_dep: None,
288                type_id: Some(type_id.into()),
289            }),
290        }
291    }
292}
293
294// UdtCellDep molecule conversions
295
296impl From<UdtCellDep> for molecule_fiber::UdtCellDep {
297    fn from(udt_cell_dep: UdtCellDep) -> Self {
298        use molecule::prelude::Entity;
299        molecule_fiber::UdtCellDep::new_builder()
300            .out_point(OutPoint::from(udt_cell_dep.out_point))
301            .dep_type(
302                match udt_cell_dep.dep_type {
303                    ckb_types::core::DepType::Code => 0u8,
304                    ckb_types::core::DepType::DepGroup => 1u8,
305                }
306                .into(),
307            )
308            .build()
309    }
310}
311
312impl TryFrom<molecule_fiber::UdtCellDep> for UdtCellDep {
313    type Error = anyhow::Error;
314
315    fn try_from(udt_cell_dep: molecule_fiber::UdtCellDep) -> Result<Self, Self::Error> {
316        let dep_type: u8 = udt_cell_dep.dep_type().into();
317        Ok(UdtCellDep {
318            out_point: udt_cell_dep.out_point().into(),
319            dep_type: match dep_type {
320                0 => ckb_types::core::DepType::Code,
321                1 => ckb_types::core::DepType::DepGroup,
322                _ => return Err(anyhow::anyhow!("Invalid dep_type: {}", dep_type)),
323            },
324        })
325    }
326}
327
328impl From<UdtCellDep> for ckb_types::packed::CellDep {
329    fn from(udt_cell_dep: UdtCellDep) -> Self {
330        let out_point: ckb_types::packed::OutPoint = udt_cell_dep.out_point.into();
331        ckb_types::packed::CellDep::new_builder()
332            .out_point(out_point)
333            .dep_type(udt_cell_dep.dep_type)
334            .build()
335    }
336}
337
338impl From<&UdtCellDep> for ckb_types::packed::CellDep {
339    fn from(udt_cell_dep: &UdtCellDep) -> Self {
340        let out_point: ckb_types::packed::OutPoint = udt_cell_dep.out_point.clone().into();
341        ckb_types::packed::CellDep::new_builder()
342            .out_point(out_point)
343            .dep_type(udt_cell_dep.dep_type)
344            .build()
345    }
346}
347
348impl TryFrom<ckb_types::packed::CellDep> for UdtCellDep {
349    type Error = anyhow::Error;
350
351    fn try_from(cell_dep: ckb_types::packed::CellDep) -> Result<Self, Self::Error> {
352        let dep_type: u8 = cell_dep.dep_type().into();
353        Ok(UdtCellDep {
354            out_point: cell_dep.out_point().into(),
355            dep_type: match dep_type {
356                0 => ckb_types::core::DepType::Code,
357                1 => ckb_types::core::DepType::DepGroup,
358                _ => return Err(anyhow::anyhow!("Invalid dep_type: {}", dep_type)),
359            },
360        })
361    }
362}