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