chia_sdk_driver/layers/
nft_ownership_layer.rs

1use 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/// The NFT ownership [`Layer`] keeps track of the current DID that owns the NFT.
11/// It also contains a transfer layer, which is used to transfer ownership of the NFT.
12/// The inner puzzle layer is commonly used for determining ownership (in the key sense, not DID).
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub struct NftOwnershipLayer<T, I> {
15    /// The DID owner of this NFT, if it's currently assigned to one.
16    pub current_owner: Option<Bytes32>,
17    /// The transfer layer, which is used to transfer ownership of the NFT.
18    pub transfer_layer: T,
19    /// The inner puzzle layer, commonly used for determining ownership.
20    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}