chia_sdk_driver/primitives/action_layer/
catalog_registry_info.rs1use chia_protocol::Bytes32;
2use chia_puzzle_types::singleton::SingletonArgs;
3use chia_sdk_types::{
4 MerkleTree,
5 puzzles::{ActionLayerArgs, DefaultFinalizer2ndCurryArgs},
6};
7use clvm_traits::{FromClvm, ToClvm};
8use clvm_utils::{ToTreeHash, TreeHash};
9use clvmr::Allocator;
10use hex_literal::hex;
11
12use crate::{
13 ActionLayer, CatalogRefundAction, CatalogRegisterAction, DelegatedStateAction, DriverError,
14 Finalizer, Layer, Puzzle, SingletonAction, SingletonLayer,
15};
16
17use super::CatalogRegistry;
18
19pub type CatalogRegistryLayers = SingletonLayer<ActionLayer<CatalogRegistryState>>;
20
21#[must_use]
22#[derive(Debug, Clone, PartialEq, Eq, ToClvm, FromClvm, Copy)]
23#[clvm(list)]
24pub struct CatalogRegistryState {
25 pub cat_maker_puzzle_hash: Bytes32,
26 #[clvm(rest)]
27 pub registration_price: u64,
28}
29
30#[must_use]
31#[derive(Debug, Clone, PartialEq, Eq, Copy)]
32pub struct CatalogRegistryConstants {
33 pub launcher_id: Bytes32,
34 pub royalty_address: Bytes32,
35 pub royalty_basis_points: u16,
36 pub precommit_payout_puzzle_hash: Bytes32,
37 pub relative_block_height: u32,
38 pub price_singleton_launcher_id: Bytes32,
39}
40
41impl CatalogRegistryConstants {
42 pub fn get(testnet11: bool) -> Self {
43 if testnet11 {
44 return CatalogRegistryConstants {
45 launcher_id: Bytes32::from(hex!(
46 "0b705afb0d848794311970de0cb98722468fad6c8f687337735ab9e5286d7704"
47 )),
48 royalty_address: Bytes32::from(hex!(
49 "b3aea098428b2b5e6d57cf3bff6ee82e3950dec338b17df6d8ee20944787def5"
50 )),
51 royalty_basis_points: 100,
52 precommit_payout_puzzle_hash: Bytes32::from(hex!(
53 "b3aea098428b2b5e6d57cf3bff6ee82e3950dec338b17df6d8ee20944787def5"
54 )),
55 relative_block_height: 4,
56 price_singleton_launcher_id: Bytes32::from(hex!(
57 "45dff01375d9bd681d36a3a186ab3d0c86eb809d7f85fff950f0b37f068ec664"
58 )),
59 };
60 }
61
62 todo!("oops - catalog constants for mainnet are not yet available");
63 }
64
65 pub fn with_price_singleton(mut self, price_singleton_launcher_id: Bytes32) -> Self {
66 self.price_singleton_launcher_id = price_singleton_launcher_id;
67 self
68 }
69
70 pub fn with_launcher_id(mut self, launcher_id: Bytes32) -> Self {
71 self.launcher_id = launcher_id;
72 self
73 }
74}
75
76#[must_use]
77#[derive(Debug, Clone, PartialEq, Eq, Copy)]
78pub struct CatalogRegistryInfo {
79 pub state: CatalogRegistryState,
80
81 pub constants: CatalogRegistryConstants,
82}
83
84impl CatalogRegistryInfo {
85 pub fn new(state: CatalogRegistryState, constants: CatalogRegistryConstants) -> Self {
86 Self { state, constants }
87 }
88
89 pub fn with_state(mut self, state: CatalogRegistryState) -> Self {
90 self.state = state;
91 self
92 }
93
94 pub fn action_puzzle_hashes(constants: &CatalogRegistryConstants) -> [Bytes32; 3] {
95 [
96 CatalogRegisterAction::from_constants(constants)
97 .tree_hash()
98 .into(),
99 CatalogRefundAction::from_constants(constants)
100 .tree_hash()
101 .into(),
102 <DelegatedStateAction as SingletonAction<CatalogRegistry>>::from_constants(constants)
103 .tree_hash()
104 .into(),
105 ]
106 }
107
108 #[must_use]
109 pub fn into_layers(self) -> CatalogRegistryLayers {
110 SingletonLayer::new(
111 self.constants.launcher_id,
112 ActionLayer::from_action_puzzle_hashes(
113 &Self::action_puzzle_hashes(&self.constants),
114 self.state,
115 Finalizer::Default {
116 hint: self.constants.launcher_id,
117 },
118 ),
119 )
120 }
121
122 pub fn parse(
123 allocator: &mut Allocator,
124 puzzle: Puzzle,
125 constants: CatalogRegistryConstants,
126 ) -> Result<Option<Self>, DriverError> {
127 let Some(layers) = CatalogRegistryLayers::parse_puzzle(allocator, puzzle)? else {
128 return Ok(None);
129 };
130
131 let action_puzzle_hashes = Self::action_puzzle_hashes(&constants);
132 let merkle_root = MerkleTree::new(&action_puzzle_hashes).root();
133 if layers.inner_puzzle.merkle_root != merkle_root {
134 return Ok(None);
135 }
136
137 Ok(Some(Self::from_layers(&layers, constants)))
138 }
139
140 pub fn from_layers(
141 layers: &CatalogRegistryLayers,
142 constants: CatalogRegistryConstants,
143 ) -> Self {
144 Self {
145 state: layers.inner_puzzle.state,
146 constants,
147 }
148 }
149
150 pub fn puzzle_hash(&self) -> TreeHash {
151 SingletonArgs::curry_tree_hash(self.constants.launcher_id, self.inner_puzzle_hash())
152 }
153
154 pub fn inner_puzzle_hash(&self) -> TreeHash {
155 ActionLayerArgs::curry_tree_hash(
156 DefaultFinalizer2ndCurryArgs::curry_tree_hash(self.constants.launcher_id),
157 MerkleTree::new(&Self::action_puzzle_hashes(&self.constants)).root(),
158 self.state.tree_hash(),
159 )
160 }
161}