1use std::sync::{Arc, Mutex};
2
3use bindy::Result;
4use chia_bls::PublicKey;
5use chia_protocol::{Bytes, Bytes32};
6use chia_sdk_driver::SpendContext;
7use chia_sdk_types::conditions::{self, Memos, TradePrice};
8use clvm_traits::{FromClvm, ToClvm};
9use clvmr::NodePtr;
10use paste::paste;
11
12use crate::{Clvm, Program};
13
14trait Convert<T> {
15 fn convert(self, clvm: &Arc<Mutex<SpendContext>>) -> Result<T>;
16}
17
18impl Convert<Program> for NodePtr {
19 fn convert(self, clvm: &Arc<Mutex<SpendContext>>) -> Result<Program> {
20 Ok(Program(clvm.clone(), self))
21 }
22}
23
24impl Convert<NodePtr> for Program {
25 fn convert(self, _clvm: &Arc<Mutex<SpendContext>>) -> Result<NodePtr> {
26 Ok(self.1)
27 }
28}
29
30impl Convert<PublicKey> for PublicKey {
31 fn convert(self, _clvm: &Arc<Mutex<SpendContext>>) -> Result<PublicKey> {
32 Ok(self)
33 }
34}
35
36impl Convert<Bytes> for Bytes {
37 fn convert(self, _clvm: &Arc<Mutex<SpendContext>>) -> Result<Bytes> {
38 Ok(self)
39 }
40}
41
42impl Convert<Bytes32> for Bytes32 {
43 fn convert(self, _clvm: &Arc<Mutex<SpendContext>>) -> Result<Bytes32> {
44 Ok(self)
45 }
46}
47
48impl Convert<u64> for u64 {
49 fn convert(self, _clvm: &Arc<Mutex<SpendContext>>) -> Result<u64> {
50 Ok(self)
51 }
52}
53
54impl Convert<u32> for u32 {
55 fn convert(self, _clvm: &Arc<Mutex<SpendContext>>) -> Result<u32> {
56 Ok(self)
57 }
58}
59
60impl Convert<u8> for u8 {
61 fn convert(self, _clvm: &Arc<Mutex<SpendContext>>) -> Result<u8> {
62 Ok(self)
63 }
64}
65
66impl Convert<TradePrice> for TradePrice {
67 fn convert(self, _clvm: &Arc<Mutex<SpendContext>>) -> Result<TradePrice> {
68 Ok(self)
69 }
70}
71
72impl Convert<Memos<NodePtr>> for Option<Program> {
73 fn convert(self, _clvm: &Arc<Mutex<SpendContext>>) -> Result<Memos<NodePtr>> {
74 Ok(self.map_or(Memos::None, |program| Memos::Some(program.1)))
75 }
76}
77
78impl Convert<Option<Program>> for Memos<NodePtr> {
79 fn convert(self, clvm: &Arc<Mutex<SpendContext>>) -> Result<Option<Program>> {
80 Ok(match self {
81 Memos::None => None,
82 Memos::Some(value) => Some(Program(clvm.clone(), value)),
83 })
84 }
85}
86
87impl<T, U> Convert<Vec<U>> for Vec<T>
88where
89 T: Convert<U>,
90{
91 fn convert(self, clvm: &Arc<Mutex<SpendContext>>) -> Result<Vec<U>> {
92 self.into_iter()
93 .map(|value| T::convert(value, clvm))
94 .collect()
95 }
96}
97
98impl<T, U> Convert<Option<U>> for Option<T>
99where
100 T: Convert<U>,
101{
102 fn convert(self, clvm: &Arc<Mutex<SpendContext>>) -> Result<Option<U>> {
103 self.map(|value| T::convert(value, clvm)).transpose()
104 }
105}
106
107macro_rules! conditions {
108 ( $( $condition:ident $( < $( $generic:ty ),* > )? { $function:ident( $( $name:ident: $ty:ty ),* ) }, )* ) => {
109 $( #[derive(Clone)]
110 pub struct $condition {
111 $( pub $name: $ty, )*
112 } )*
113
114 $( paste! {
115 impl Clvm {
116 pub fn $function( &self, $( $name: $ty ),* ) -> Result<Program> {
117 let mut ctx = self.0.lock().unwrap();
118 $( let $name = Convert::convert($name, &self.0)?; )*
119 let ptr = conditions::$condition $( ::< $( $generic ),* > )? ::new( $( $name ),* )
120 .to_clvm(&mut **ctx)?;
121 Ok(Program(self.0.clone(), ptr))
122 }
123 }
124
125 impl Program {
126 #[allow(unused)]
127 pub fn [< parse_ $function >]( &self ) -> Result<Option<$condition>> {
128 let ctx = self.0.lock().unwrap();
129
130 let Some(condition) = conditions::$condition $( ::< $( $generic ),* > )? ::from_clvm(&**ctx, self.1).ok() else {
131 return Ok(None);
132 };
133
134 Ok(Some($condition {
135 $( $name: Convert::convert(condition.$name, &self.0.clone())?, )*
136 }))
137 }
138 }
139 } )*
140 };
141}
142
143conditions!(
144 Remark<NodePtr> {
145 remark(rest: Program)
146 },
147 AggSigParent {
148 agg_sig_parent(public_key: PublicKey, message: Bytes)
149 },
150 AggSigPuzzle {
151 agg_sig_puzzle(public_key: PublicKey, message: Bytes)
152 },
153 AggSigAmount {
154 agg_sig_amount(public_key: PublicKey, message: Bytes)
155 },
156 AggSigPuzzleAmount {
157 agg_sig_puzzle_amount(public_key: PublicKey, message: Bytes)
158 },
159 AggSigParentAmount {
160 agg_sig_parent_amount(public_key: PublicKey, message: Bytes)
161 },
162 AggSigParentPuzzle {
163 agg_sig_parent_puzzle(public_key: PublicKey, message: Bytes)
164 },
165 AggSigUnsafe {
166 agg_sig_unsafe(public_key: PublicKey, message: Bytes)
167 },
168 AggSigMe {
169 agg_sig_me(public_key: PublicKey, message: Bytes)
170 },
171 CreateCoin {
172 create_coin(puzzle_hash: Bytes32, amount: u64, memos: Option<Program>)
173 },
174 ReserveFee {
175 reserve_fee(amount: u64)
176 },
177 CreateCoinAnnouncement {
178 create_coin_announcement(message: Bytes)
179 },
180 CreatePuzzleAnnouncement {
181 create_puzzle_announcement(message: Bytes)
182 },
183 AssertCoinAnnouncement {
184 assert_coin_announcement(announcement_id: Bytes32)
185 },
186 AssertPuzzleAnnouncement {
187 assert_puzzle_announcement(announcement_id: Bytes32)
188 },
189 AssertConcurrentSpend {
190 assert_concurrent_spend(coin_id: Bytes32)
191 },
192 AssertConcurrentPuzzle {
193 assert_concurrent_puzzle(puzzle_hash: Bytes32)
194 },
195 AssertSecondsRelative {
196 assert_seconds_relative(seconds: u64)
197 },
198 AssertSecondsAbsolute {
199 assert_seconds_absolute(seconds: u64)
200 },
201 AssertHeightRelative {
202 assert_height_relative(height: u32)
203 },
204 AssertHeightAbsolute {
205 assert_height_absolute(height: u32)
206 },
207 AssertBeforeSecondsRelative {
208 assert_before_seconds_relative(seconds: u64)
209 },
210 AssertBeforeSecondsAbsolute {
211 assert_before_seconds_absolute(seconds: u64)
212 },
213 AssertBeforeHeightRelative {
214 assert_before_height_relative(height: u32)
215 },
216 AssertBeforeHeightAbsolute {
217 assert_before_height_absolute(height: u32)
218 },
219 AssertMyCoinId {
220 assert_my_coin_id(coin_id: Bytes32)
221 },
222 AssertMyParentId {
223 assert_my_parent_id(parent_id: Bytes32)
224 },
225 AssertMyPuzzleHash {
226 assert_my_puzzle_hash(puzzle_hash: Bytes32)
227 },
228 AssertMyAmount {
229 assert_my_amount(amount: u64)
230 },
231 AssertMyBirthSeconds {
232 assert_my_birth_seconds(seconds: u64)
233 },
234 AssertMyBirthHeight {
235 assert_my_birth_height(height: u32)
236 },
237 AssertEphemeral {
238 assert_ephemeral()
239 },
240 SendMessage<NodePtr> {
241 send_message(mode: u8, message: Bytes, data: Vec<Program>)
242 },
243 ReceiveMessage<NodePtr> {
244 receive_message(mode: u8, message: Bytes, data: Vec<Program>)
245 },
246 Softfork<NodePtr> {
247 softfork(cost: u64, rest: Program)
248 },
249 MeltSingleton {
250 melt_singleton()
251 },
252 TransferNft {
253 transfer_nft(launcher_id: Option<Bytes32>, trade_prices: Vec<TradePrice>, singleton_inner_puzzle_hash: Option<Bytes32>)
254 },
255 RunCatTail<NodePtr, NodePtr> {
256 run_cat_tail(program: Program, solution: Program)
257 },
258 UpdateNftMetadata<NodePtr, NodePtr> {
259 update_nft_metadata(updater_puzzle_reveal: Program, updater_solution: Program)
260 },
261 UpdateDataStoreMerkleRoot {
262 update_data_store_merkle_root(new_merkle_root: Bytes32, memos: Vec<Bytes>)
263 },
264);