chia_sdk_driver/layers/action_layer/actions/catalog/
register.rs1use chia_protocol::Bytes32;
2use chia_puzzle_types::singleton::SingletonStruct;
3use chia_sdk_types::{
4 Conditions, Mod, announcement_id,
5 puzzles::{
6 ANY_METADATA_UPDATER_HASH, CatalogRegisterActionArgs, CatalogRegisterActionSolution,
7 CatalogSlotValue, DefaultCatMakerArgs, NftPack, PrecommitSpendMode,
8 },
9};
10use clvm_traits::{FromClvm, ToClvm, clvm_tuple};
11use clvm_utils::{ToTreeHash, TreeHash};
12use clvmr::NodePtr;
13
14use crate::{
15 CatalogPrecommitValue, CatalogRegistry, CatalogRegistryConstants, DriverError, HashedPtr,
16 PrecommitCoin, PrecommitLayer, SingletonAction, Slot, Spend, SpendContext,
17 UniquenessPrelauncher,
18};
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub struct CatalogRegisterAction {
22 pub launcher_id: Bytes32,
23 pub royalty_puzzle_hash_hash: Bytes32,
24 pub trade_price_percentage: u16,
25 pub relative_block_height: u32,
26 pub payout_puzzle_hash: Bytes32,
27}
28
29impl ToTreeHash for CatalogRegisterAction {
30 fn tree_hash(&self) -> TreeHash {
31 Self::new_args(
32 self.launcher_id,
33 self.royalty_puzzle_hash_hash,
34 self.trade_price_percentage,
35 self.relative_block_height,
36 self.payout_puzzle_hash,
37 )
38 .curry_tree_hash()
39 }
40}
41
42impl SingletonAction<CatalogRegistry> for CatalogRegisterAction {
43 fn from_constants(constants: &CatalogRegistryConstants) -> Self {
44 Self {
45 launcher_id: constants.launcher_id,
46 royalty_puzzle_hash_hash: constants.royalty_address.tree_hash().into(),
47 trade_price_percentage: constants.royalty_basis_points,
48 relative_block_height: constants.relative_block_height,
49 payout_puzzle_hash: constants.precommit_payout_puzzle_hash,
50 }
51 }
52}
53
54impl CatalogRegisterAction {
55 pub fn new_args(
56 launcher_id: Bytes32,
57 royalty_puzzle_hash_hash: Bytes32,
58 trade_price_percentage: u16,
59 relative_block_height: u32,
60 payout_puzzle_hash: Bytes32,
61 ) -> CatalogRegisterActionArgs {
62 CatalogRegisterActionArgs {
63 nft_pack: NftPack::new(royalty_puzzle_hash_hash, trade_price_percentage),
64 uniqueness_prelauncher_1st_curry_hash: UniquenessPrelauncher::<()>::first_curry_hash()
65 .into(),
66 precommit_1st_curry_hash: PrecommitLayer::<()>::first_curry_hash(
67 SingletonStruct::new(launcher_id).tree_hash().into(),
68 relative_block_height,
69 payout_puzzle_hash,
70 )
71 .into(),
72 slot_1st_curry_hash: Slot::<CatalogSlotValue>::first_curry_hash(launcher_id, 0).into(),
73 }
74 }
75
76 pub fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result<NodePtr, DriverError> {
77 ctx.curry(Self::new_args(
78 self.launcher_id,
79 self.royalty_puzzle_hash_hash,
80 self.trade_price_percentage,
81 self.relative_block_height,
82 self.payout_puzzle_hash,
83 ))
84 }
85
86 pub fn spent_slot_values(
87 &self,
88 ctx: &SpendContext,
89 solution: NodePtr,
90 ) -> Result<[CatalogSlotValue; 2], DriverError> {
91 let params = CatalogRegisterActionSolution::<NodePtr, ()>::from_clvm(ctx, solution)?;
92
93 Ok([
94 CatalogSlotValue::new(
95 params.left_tail_hash,
96 params.left_left_tail_hash,
97 params.right_tail_hash,
98 ),
99 CatalogSlotValue::new(
100 params.right_tail_hash,
101 params.left_tail_hash,
102 params.right_right_tail_hash,
103 ),
104 ])
105 }
106
107 pub fn created_slot_values(
108 &self,
109 ctx: &SpendContext,
110 solution: NodePtr,
111 ) -> Result<[CatalogSlotValue; 3], DriverError> {
112 let params = CatalogRegisterActionSolution::<NodePtr, ()>::from_clvm(ctx, solution)?;
113
114 Ok([
115 CatalogSlotValue::new(
116 params.left_tail_hash,
117 params.left_left_tail_hash,
118 params.tail_hash,
119 ),
120 CatalogSlotValue::new(
121 params.tail_hash,
122 params.left_tail_hash,
123 params.right_tail_hash,
124 ),
125 CatalogSlotValue::new(
126 params.right_tail_hash,
127 params.tail_hash,
128 params.right_right_tail_hash,
129 ),
130 ])
131 }
132
133 #[allow(clippy::too_many_arguments)]
134 pub fn spend(
135 self,
136 ctx: &mut SpendContext,
137 catalog: &mut CatalogRegistry,
138 tail_hash: Bytes32,
139 left_slot: Slot<CatalogSlotValue>,
140 right_slot: Slot<CatalogSlotValue>,
141 precommit_coin: &PrecommitCoin<CatalogPrecommitValue>,
142 eve_nft_inner_spend: Spend,
143 ) -> Result<Conditions, DriverError> {
144 let mut register_announcement =
146 clvm_tuple!(tail_hash, precommit_coin.value.initial_inner_puzzle_hash)
147 .tree_hash()
148 .to_vec();
149 register_announcement.insert(0, b'r');
150
151 let initial_inner_puzzle_hash = precommit_coin.value.initial_inner_puzzle_hash;
153 let my_inner_puzzle_hash = catalog.info.inner_puzzle_hash().into();
154 precommit_coin.spend(ctx, PrecommitSpendMode::REGISTER, my_inner_puzzle_hash)?;
155
156 let uniqueness_prelauncher =
158 UniquenessPrelauncher::<Bytes32>::new(ctx, catalog.coin.coin_id(), tail_hash)?;
159 let nft_launcher = uniqueness_prelauncher.spend(ctx)?;
160
161 let (_, nft) = nft_launcher.mint_eve_nft(
163 ctx,
164 initial_inner_puzzle_hash,
165 HashedPtr::NIL,
166 ANY_METADATA_UPDATER_HASH.into(),
167 catalog.info.constants.royalty_address,
168 catalog.info.constants.royalty_basis_points,
169 )?;
170
171 let _new_nft = nft.spend(ctx, eve_nft_inner_spend)?;
173
174 let (left_slot, right_slot) = catalog.actual_neigbors(tail_hash, left_slot, right_slot);
176 let my_solution = CatalogRegisterActionSolution {
177 cat_maker_reveal: ctx.curry(DefaultCatMakerArgs::new(
178 precommit_coin.asset_id.tree_hash().into(),
179 ))?,
180 cat_maker_solution: (),
181 tail_hash,
182 initial_nft_owner_ph: initial_inner_puzzle_hash,
183 refund_puzzle_hash_hash: precommit_coin.refund_puzzle_hash.tree_hash().into(),
184 left_tail_hash: left_slot.info.value.asset_id,
185 left_left_tail_hash: left_slot.info.value.neighbors.left_value,
186 right_tail_hash: right_slot.info.value.asset_id,
187 right_right_tail_hash: right_slot.info.value.neighbors.right_value,
188 my_id: catalog.coin.coin_id(),
189 };
190 let my_solution = my_solution.to_clvm(ctx)?;
191 let my_puzzle = self.construct_puzzle(ctx)?;
192
193 catalog.insert_action_spend(ctx, Spend::new(my_puzzle, my_solution))?;
194
195 left_slot.spend(ctx, my_inner_puzzle_hash)?;
197 right_slot.spend(ctx, my_inner_puzzle_hash)?;
198
199 Ok(
200 Conditions::new().assert_puzzle_announcement(announcement_id(
201 catalog.coin.puzzle_hash,
202 register_announcement,
203 )),
204 )
205 }
206}