chia_sdk_driver/primitives/vault/
p2_conditions_or_singleton.rs1use chia_protocol::Bytes32;
2use chia_sdk_types::{
3 Mod,
4 puzzles::{SingletonMember, SingletonMemberSolution},
5};
6use clvm_utils::{ToTreeHash, TreeHash};
7use clvmr::NodePtr;
8
9use crate::{
10 DriverError, InnerPuzzleSpend, MipsSpend, MofN, Spend, SpendContext, mips_puzzle_hash,
11};
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
14pub struct P2ConditionsOrSingleton {
15 pub launcher_id: Bytes32,
16 pub nonce: usize,
17 pub fixed_conditions_hash: Bytes32,
18}
19
20impl P2ConditionsOrSingleton {
21 pub fn new(launcher_id: Bytes32, nonce: usize, fixed_conditions_hash: Bytes32) -> Self {
22 Self {
23 launcher_id,
24 nonce,
25 fixed_conditions_hash,
26 }
27 }
28
29 pub fn fixed_conditions_hash(quoted_conditions_hash: Bytes32) -> Bytes32 {
30 mips_puzzle_hash(0, vec![], quoted_conditions_hash.into(), false).into()
31 }
32
33 pub fn from_quoted_conditions_hash(
34 launcher_id: Bytes32,
35 nonce: usize,
36 quoted_conditions_hash: Bytes32,
37 ) -> Self {
38 Self {
39 launcher_id,
40 nonce,
41 fixed_conditions_hash: Self::fixed_conditions_hash(quoted_conditions_hash),
42 }
43 }
44
45 pub fn fixed_path_hash(&self) -> TreeHash {
46 self.fixed_conditions_hash.into()
47 }
48
49 pub fn p2_singleton_path_hash(&self) -> TreeHash {
50 mips_puzzle_hash(
51 self.nonce,
52 vec![],
53 SingletonMember::new(self.launcher_id).curry_tree_hash(),
54 false,
55 )
56 }
57
58 pub fn p2_singleton_spend(
59 &self,
60 ctx: &mut SpendContext,
61 singleton_inner_puzzle_hash: Bytes32,
62 singleton_amount: u64,
63 delegated_spend: Spend,
64 ) -> Result<Spend, DriverError> {
65 let mut mips = MipsSpend::new(delegated_spend);
66
67 let fixed_hash = self.fixed_path_hash();
68 let p2_singleton_hash = self.p2_singleton_path_hash();
69 let custody_hash = self.tree_hash();
70
71 mips.members.insert(
72 custody_hash,
73 InnerPuzzleSpend::m_of_n(0, vec![], 1, vec![fixed_hash, p2_singleton_hash]),
74 );
75
76 let puzzle = ctx.curry(SingletonMember::new(self.launcher_id))?;
77 let solution = ctx.alloc(&SingletonMemberSolution::new(
78 singleton_inner_puzzle_hash,
79 singleton_amount,
80 ))?;
81
82 mips.members.insert(
83 p2_singleton_hash,
84 InnerPuzzleSpend::new(self.nonce, vec![], Spend::new(puzzle, solution)),
85 );
86
87 mips.spend(ctx, custody_hash)
88 }
89
90 pub fn fixed_spend(
91 &self,
92 ctx: &mut SpendContext,
93 delegated_spend: Spend,
94 ) -> Result<Spend, DriverError> {
95 let mut mips = MipsSpend::new(Spend::new(NodePtr::NIL, NodePtr::NIL));
96
97 let fixed_hash = self.fixed_path_hash();
98 let p2_singleton_hash = self.p2_singleton_path_hash();
99 let custody_hash = self.tree_hash();
100
101 mips.members.insert(
102 custody_hash,
103 InnerPuzzleSpend::m_of_n(0, vec![], 1, vec![fixed_hash, p2_singleton_hash]),
104 );
105
106 mips.members.insert(
107 fixed_hash,
108 InnerPuzzleSpend::new(0, vec![], delegated_spend),
109 );
110
111 mips.spend(ctx, custody_hash)
112 }
113}
114
115impl ToTreeHash for P2ConditionsOrSingleton {
116 fn tree_hash(&self) -> TreeHash {
117 let fixed_hash = self.fixed_path_hash();
118
119 let p2_singleton_hash = self.p2_singleton_path_hash();
120
121 mips_puzzle_hash(
122 0,
123 vec![],
124 MofN::new(1, vec![fixed_hash, p2_singleton_hash]).inner_puzzle_hash(),
125 true,
126 )
127 }
128}