chia_sdk_driver/layers/
option_contract_layer.rs1use chia_protocol::Bytes32;
2use chia_sdk_types::{
3 puzzles::{OptionContractArgs, OptionContractSolution, OPTION_CONTRACT_HASH},
4 Mod,
5};
6use clvm_traits::FromClvm;
7use clvm_utils::{ToTreeHash, TreeHash};
8use clvmr::{Allocator, NodePtr};
9
10use crate::{DriverError, Layer, Puzzle, SpendContext};
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub struct OptionContractLayer<I> {
16 pub underlying_coin_id: Bytes32,
17 pub underlying_delegated_puzzle_hash: Bytes32,
18 pub inner_puzzle: I,
19}
20
21impl<I> OptionContractLayer<I> {
22 pub fn new(
23 underlying_coin_id: Bytes32,
24 underlying_delegated_puzzle_hash: Bytes32,
25 inner_puzzle: I,
26 ) -> Self {
27 Self {
28 underlying_coin_id,
29 underlying_delegated_puzzle_hash,
30 inner_puzzle,
31 }
32 }
33}
34
35impl<I> Layer for OptionContractLayer<I>
36where
37 I: Layer,
38 I::Solution: FromClvm<Allocator>,
39{
40 type Solution = OptionContractSolution<I::Solution>;
41
42 fn parse_puzzle(allocator: &Allocator, puzzle: Puzzle) -> Result<Option<Self>, DriverError> {
43 let Some(puzzle) = puzzle.as_curried() else {
44 return Ok(None);
45 };
46
47 if puzzle.mod_hash != OPTION_CONTRACT_HASH {
48 return Ok(None);
49 }
50
51 let args = OptionContractArgs::<NodePtr>::from_clvm(allocator, puzzle.args)?;
52
53 let Some(inner_puzzle) =
54 I::parse_puzzle(allocator, Puzzle::parse(allocator, args.inner_puzzle))?
55 else {
56 return Ok(None);
57 };
58
59 Ok(Some(Self {
60 underlying_coin_id: args.underlying_coin_id,
61 underlying_delegated_puzzle_hash: args.underlying_delegated_puzzle_hash,
62 inner_puzzle,
63 }))
64 }
65
66 fn parse_solution(
67 allocator: &Allocator,
68 solution: NodePtr,
69 ) -> Result<Self::Solution, DriverError> {
70 Ok(Self::Solution::from_clvm(allocator, solution)?)
71 }
72
73 fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result<NodePtr, DriverError> {
74 let inner_puzzle = self.inner_puzzle.construct_puzzle(ctx)?;
75 ctx.curry(OptionContractArgs::new(
76 self.underlying_coin_id,
77 self.underlying_delegated_puzzle_hash,
78 inner_puzzle,
79 ))
80 }
81
82 fn construct_solution(
83 &self,
84 ctx: &mut SpendContext,
85 solution: Self::Solution,
86 ) -> Result<NodePtr, DriverError> {
87 let inner_solution = self
88 .inner_puzzle
89 .construct_solution(ctx, solution.inner_solution)?;
90 ctx.alloc(&OptionContractSolution::new(inner_solution))
91 }
92}
93
94impl<I> ToTreeHash for OptionContractLayer<I>
95where
96 I: ToTreeHash,
97 I: ToTreeHash,
98{
99 fn tree_hash(&self) -> TreeHash {
100 let inner_puzzle_hash = self.inner_puzzle.tree_hash();
101 OptionContractArgs::new(
102 self.underlying_coin_id,
103 self.underlying_delegated_puzzle_hash,
104 inner_puzzle_hash,
105 )
106 .curry_tree_hash()
107 }
108}