chia_sdk_driver/primitives/action_layer/
xchandles_registry_info.rs1use chia_protocol::Bytes32;
2use chia_puzzle_types::singleton::SingletonArgs;
3use chia_sdk_types::{
4 MerkleTree, Mod,
5 puzzles::{
6 ActionLayerArgs, DefaultCatMakerArgs, DefaultFinalizer2ndCurryArgs,
7 XchandlesFactorPricingPuzzleArgs,
8 },
9};
10use clvm_traits::{FromClvm, ToClvm};
11use clvm_utils::{ToTreeHash, TreeHash};
12use clvmr::Allocator;
13
14use crate::{
15 ActionLayer, DelegatedStateAction, DriverError, Finalizer, Layer, Puzzle, SingletonAction,
16 SingletonLayer, XchandlesExpireAction, XchandlesExpirePricingPuzzle, XchandlesExtendAction,
17 XchandlesOracleAction, XchandlesRefundAction, XchandlesRegisterAction, XchandlesUpdateAction,
18};
19
20use super::XchandlesRegistry;
21
22pub type XchandlesRegistryLayers = SingletonLayer<ActionLayer<XchandlesRegistryState>>;
23
24#[must_use]
25#[derive(Debug, Clone, PartialEq, Eq, ToClvm, FromClvm, Copy)]
26#[clvm(list)]
27pub struct XchandlesRegistryState {
28 pub cat_maker_puzzle_hash: Bytes32,
29 pub pricing_puzzle_hash: Bytes32,
30 #[clvm(rest)]
31 pub expired_handle_pricing_puzzle_hash: Bytes32,
32}
33
34impl XchandlesRegistryState {
35 pub fn from(
36 payment_cat_tail_hash_hash: Bytes32,
37 base_price: u64,
38 registration_period: u64,
39 ) -> Self {
40 Self {
41 cat_maker_puzzle_hash: DefaultCatMakerArgs::new(payment_cat_tail_hash_hash)
42 .curry_tree_hash()
43 .into(),
44 pricing_puzzle_hash: XchandlesFactorPricingPuzzleArgs {
45 base_price,
46 registration_period,
47 }
48 .curry_tree_hash()
49 .into(),
50 expired_handle_pricing_puzzle_hash: XchandlesExpirePricingPuzzle::curry_tree_hash(
51 base_price,
52 registration_period,
53 )
54 .into(),
55 }
56 }
57}
58
59#[must_use]
60#[derive(Debug, Clone, PartialEq, Eq, Copy, ToClvm, FromClvm)]
61#[clvm(list)]
62pub struct XchandlesConstants {
63 pub launcher_id: Bytes32,
64 pub precommit_payout_puzzle_hash: Bytes32,
65 pub relative_block_height: u32,
66 pub price_singleton_launcher_id: Bytes32,
67}
68
69impl XchandlesConstants {
70 pub fn new(
71 launcher_id: Bytes32,
72 precommit_payout_puzzle_hash: Bytes32,
73 relative_block_height: u32,
74 price_singleton_launcher_id: Bytes32,
75 ) -> Self {
76 Self {
77 launcher_id,
78 precommit_payout_puzzle_hash,
79 relative_block_height,
80 price_singleton_launcher_id,
81 }
82 }
83
84 pub fn with_price_singleton(mut self, price_singleton_launcher_id: Bytes32) -> Self {
85 self.price_singleton_launcher_id = price_singleton_launcher_id;
86 self
87 }
88
89 pub fn with_launcher_id(mut self, launcher_id: Bytes32) -> Self {
90 self.launcher_id = launcher_id;
91 self
92 }
93}
94
95#[must_use]
96#[derive(Debug, Clone, PartialEq, Eq, Copy)]
97pub struct XchandlesRegistryInfo {
98 pub state: XchandlesRegistryState,
99
100 pub constants: XchandlesConstants,
101}
102
103impl XchandlesRegistryInfo {
104 pub fn new(state: XchandlesRegistryState, constants: XchandlesConstants) -> Self {
105 Self { state, constants }
106 }
107
108 pub fn with_state(mut self, state: XchandlesRegistryState) -> Self {
109 self.state = state;
110 self
111 }
112
113 pub fn action_puzzle_hashes(constants: &XchandlesConstants) -> [Bytes32; 7] {
114 [
115 XchandlesExpireAction::from_constants(constants)
116 .tree_hash()
117 .into(),
118 XchandlesExtendAction::from_constants(constants)
119 .tree_hash()
120 .into(),
121 XchandlesOracleAction::from_constants(constants)
122 .tree_hash()
123 .into(),
124 XchandlesRegisterAction::from_constants(constants)
125 .tree_hash()
126 .into(),
127 XchandlesUpdateAction::from_constants(constants)
128 .tree_hash()
129 .into(),
130 XchandlesRefundAction::from_constants(constants)
131 .tree_hash()
132 .into(),
133 <DelegatedStateAction as SingletonAction<XchandlesRegistry>>::from_constants(constants)
134 .tree_hash()
135 .into(),
136 ]
137 }
138
139 #[must_use]
140 pub fn into_layers(self) -> XchandlesRegistryLayers {
141 SingletonLayer::new(
142 self.constants.launcher_id,
143 ActionLayer::from_action_puzzle_hashes(
144 &Self::action_puzzle_hashes(&self.constants),
145 self.state,
146 Finalizer::Default {
147 hint: self.constants.launcher_id,
148 },
149 ),
150 )
151 }
152
153 pub fn parse(
154 allocator: &mut Allocator,
155 puzzle: Puzzle,
156 constants: XchandlesConstants,
157 ) -> Result<Option<Self>, DriverError> {
158 let Some(layers) = XchandlesRegistryLayers::parse_puzzle(allocator, puzzle)? else {
159 return Ok(None);
160 };
161
162 let action_puzzle_hashes = Self::action_puzzle_hashes(&constants);
163 let merkle_root = MerkleTree::new(&action_puzzle_hashes).root();
164 if layers.inner_puzzle.merkle_root != merkle_root {
165 return Ok(None);
166 }
167
168 Ok(Some(Self::from_layers(&layers, constants)))
169 }
170
171 pub fn from_layers(layers: &XchandlesRegistryLayers, constants: XchandlesConstants) -> Self {
172 Self {
173 state: layers.inner_puzzle.state,
174 constants,
175 }
176 }
177
178 pub fn puzzle_hash(&self) -> TreeHash {
179 SingletonArgs::curry_tree_hash(self.constants.launcher_id, self.inner_puzzle_hash())
180 }
181
182 pub fn inner_puzzle_hash(&self) -> TreeHash {
183 ActionLayerArgs::curry_tree_hash(
184 DefaultFinalizer2ndCurryArgs::curry_tree_hash(self.constants.launcher_id),
185 MerkleTree::new(&Self::action_puzzle_hashes(&self.constants)).root(),
186 self.state.tree_hash(),
187 )
188 }
189}