Skip to main content

chia_sdk_driver/primitives/vault/
p2_conditions_or_singleton.rs

1use 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}