chia_sdk_driver/primitives/action_layer/
uniqueness_prelauncher.rs

1use chia_protocol::{Bytes32, Coin, CoinSpend};
2use chia_puzzles::SINGLETON_LAUNCHER_HASH;
3use chia_sdk_types::{
4    Mod,
5    puzzles::{UniquenessPrelauncher1stCurryArgs, UniquenessPrelauncher2ndCurryArgs},
6};
7use clvm_traits::ToClvm;
8use clvm_utils::{CurriedProgram, ToTreeHash, TreeHash, tree_hash};
9use clvmr::{Allocator, NodePtr};
10
11use crate::{DriverError, Launcher, SpendContext};
12
13#[derive(Debug, Clone)]
14#[must_use]
15pub struct UniquenessPrelauncher<V> {
16    pub coin: Coin,
17    pub value: V,
18}
19
20impl<V> UniquenessPrelauncher<V> {
21    pub fn from_coin(coin: Coin, value: V) -> Self {
22        Self { coin, value }
23    }
24
25    pub fn new(
26        allocator: &mut Allocator,
27        parent_coin_id: Bytes32,
28        value: V,
29    ) -> Result<Self, DriverError>
30    where
31        V: ToClvm<Allocator> + Clone,
32    {
33        let value_ptr = value.to_clvm(allocator)?;
34        let value_hash = tree_hash(allocator, value_ptr);
35
36        Ok(Self::from_coin(
37            Coin::new(
38                parent_coin_id,
39                UniquenessPrelauncher::<V>::puzzle_hash(value_hash).into(),
40                0,
41            ),
42            value,
43        ))
44    }
45
46    pub fn first_curry_hash() -> TreeHash {
47        UniquenessPrelauncher1stCurryArgs {
48            launcher_puzzle_hash: SINGLETON_LAUNCHER_HASH.into(),
49        }
50        .curry_tree_hash()
51    }
52
53    pub fn puzzle_hash(value_hash: TreeHash) -> TreeHash {
54        CurriedProgram {
55            program: Self::first_curry_hash(),
56            args: UniquenessPrelauncher2ndCurryArgs { value: value_hash },
57        }
58        .tree_hash()
59    }
60
61    pub fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result<NodePtr, DriverError>
62    where
63        V: ToClvm<Allocator> + Clone,
64    {
65        let prog_1st_curry = ctx.curry(UniquenessPrelauncher1stCurryArgs {
66            launcher_puzzle_hash: SINGLETON_LAUNCHER_HASH.into(),
67        })?;
68
69        ctx.alloc(&CurriedProgram {
70            program: prog_1st_curry,
71            args: UniquenessPrelauncher2ndCurryArgs {
72                value: self.value.clone(),
73            },
74        })
75    }
76
77    pub fn spend(self, ctx: &mut SpendContext) -> Result<Launcher, DriverError>
78    where
79        V: ToClvm<Allocator> + Clone,
80    {
81        let puzzle_reveal = self.construct_puzzle(ctx)?;
82        let puzzle_reveal = ctx.serialize(&puzzle_reveal)?;
83
84        let solution = ctx.serialize(&NodePtr::NIL)?;
85
86        ctx.insert(CoinSpend::new(self.coin, puzzle_reveal, solution));
87
88        Ok(Launcher::new(self.coin.coin_id(), 1))
89    }
90}