chia_sdk_driver/layers/datalayer/
writer_layer.rs

1use chia_puzzle_types::standard::StandardSolution;
2use chia_sdk_types::{
3    puzzles::{WriterLayerArgs, WriterLayerSolution, WRITER_LAYER_PUZZLE_HASH},
4    Conditions,
5};
6use clvm_traits::{clvm_quote, FromClvm};
7use clvm_utils::{ToTreeHash, TreeHash};
8use clvmr::{Allocator, NodePtr};
9
10use crate::{DriverError, Layer, Puzzle, Spend, SpendContext, StandardLayer};
11
12/// The Writer [`Layer`] removes an authorized puzzle's ability to change the list of authorized puzzles.
13/// It's typically used with [`DelegationLayer`](crate::DelegationLayer).
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub struct WriterLayer<I> {
16    /// The inner puzzle layer, commonly used for determining ownership.
17    pub inner_puzzle: I,
18}
19
20impl<I> WriterLayer<I> {
21    pub fn new(inner_puzzle: I) -> Self {
22        Self { inner_puzzle }
23    }
24}
25
26impl<I> Layer for WriterLayer<I>
27where
28    I: Layer,
29{
30    type Solution = I::Solution;
31
32    fn parse_puzzle(allocator: &Allocator, puzzle: Puzzle) -> Result<Option<Self>, DriverError> {
33        let Some(puzzle) = puzzle.as_curried() else {
34            return Ok(None);
35        };
36
37        if puzzle.mod_hash != WRITER_LAYER_PUZZLE_HASH {
38            return Ok(None);
39        }
40
41        let args = WriterLayerArgs::<NodePtr>::from_clvm(allocator, puzzle.args)?;
42
43        let Some(inner_puzzle) =
44            I::parse_puzzle(allocator, Puzzle::parse(allocator, args.inner_puzzle))?
45        else {
46            return Ok(None);
47        };
48
49        Ok(Some(Self { inner_puzzle }))
50    }
51
52    fn parse_solution(
53        allocator: &Allocator,
54        solution: NodePtr,
55    ) -> Result<Self::Solution, DriverError> {
56        let inner_solution =
57            WriterLayerSolution::<NodePtr>::from_clvm(allocator, solution)?.inner_solution;
58
59        I::parse_solution(allocator, inner_solution)
60    }
61
62    fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result<NodePtr, DriverError> {
63        let inner_puzzle = self.inner_puzzle.construct_puzzle(ctx)?;
64        let curried = ctx.curry(WriterLayerArgs::new(inner_puzzle))?;
65        ctx.alloc(&curried)
66    }
67
68    fn construct_solution(
69        &self,
70        ctx: &mut SpendContext,
71        solution: Self::Solution,
72    ) -> Result<NodePtr, DriverError> {
73        let inner_solution = self.inner_puzzle.construct_solution(ctx, solution)?;
74
75        ctx.alloc(&WriterLayerSolution::<NodePtr> { inner_solution })
76    }
77}
78
79impl<I> ToTreeHash for WriterLayer<I>
80where
81    I: ToTreeHash,
82{
83    fn tree_hash(&self) -> TreeHash {
84        let inner_puzzle_hash = self.inner_puzzle.tree_hash();
85
86        WriterLayerArgs::curry_tree_hash(inner_puzzle_hash)
87    }
88}
89
90impl WriterLayer<StandardLayer> {
91    pub fn spend(
92        self,
93        ctx: &mut SpendContext,
94        output_conditions: Conditions,
95    ) -> Result<Spend, DriverError> {
96        let dp = ctx.alloc(&clvm_quote!(output_conditions))?;
97        let solution = self.construct_solution(
98            ctx,
99            StandardSolution {
100                original_public_key: None,
101                delegated_puzzle: dp,
102                solution: NodePtr::NIL,
103            },
104        )?;
105        let puzzle = self.construct_puzzle(ctx)?;
106
107        Ok(Spend { puzzle, solution })
108    }
109}