chia_sdk_driver/layers/
p2_delegated_conditions_layer.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
use chia_bls::PublicKey;
use chia_sdk_types::Condition;
use clvm_traits::{FromClvm, ToClvm};
use clvm_utils::{CurriedProgram, TreeHash};
use clvmr::{Allocator, NodePtr};
use hex_literal::hex;

use crate::{DriverError, Layer, Puzzle, SpendContext};

/// The p2 delegated conditions [`Layer`] allows a certain key to spend the coin.
/// To do so, a list of additional conditions is signed and passed in the solution.
/// Typically, the [`StandardLayer`](crate::StandardLayer) is used instead, since it adds more flexibility.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct P2DelegatedConditionsLayer {
    /// The public key that has the ability to spend the coin.
    pub public_key: PublicKey,
}

impl Layer for P2DelegatedConditionsLayer {
    type Solution = P2DelegatedConditionsSolution;

    fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result<NodePtr, DriverError> {
        let curried = CurriedProgram {
            program: ctx.p2_delegated_conditions_puzzle()?,
            args: P2DelegatedConditionsArgs::new(self.public_key),
        };
        ctx.alloc(&curried)
    }

    fn construct_solution(
        &self,
        ctx: &mut SpendContext,
        solution: Self::Solution,
    ) -> Result<NodePtr, DriverError> {
        ctx.alloc(&solution)
    }

    fn parse_puzzle(allocator: &Allocator, puzzle: Puzzle) -> Result<Option<Self>, DriverError> {
        let Some(puzzle) = puzzle.as_curried() else {
            return Ok(None);
        };

        if puzzle.mod_hash != P2_DELEGATED_CONDITIONS_PUZZLE_HASH {
            return Ok(None);
        }

        let args = P2DelegatedConditionsArgs::from_clvm(allocator, puzzle.args)?;

        Ok(Some(Self {
            public_key: args.public_key,
        }))
    }

    fn parse_solution(
        allocator: &Allocator,
        solution: NodePtr,
    ) -> Result<Self::Solution, DriverError> {
        Ok(P2DelegatedConditionsSolution::from_clvm(
            allocator, solution,
        )?)
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, ToClvm, FromClvm)]
#[clvm(curry)]
pub struct P2DelegatedConditionsArgs {
    pub public_key: PublicKey,
}

impl P2DelegatedConditionsArgs {
    pub fn new(public_key: PublicKey) -> Self {
        Self { public_key }
    }
}

#[derive(Debug, Clone, PartialEq, Eq, ToClvm, FromClvm)]
#[clvm(list)]
pub struct P2DelegatedConditionsSolution<T = NodePtr> {
    pub conditions: Vec<Condition<T>>,
}

impl P2DelegatedConditionsSolution {
    pub fn new(conditions: Vec<Condition>) -> Self {
        Self { conditions }
    }
}

pub const P2_DELEGATED_CONDITIONS_PUZZLE: [u8; 137] = hex!(
    "
    ff02ffff01ff04ffff04ff04ffff04ff05ffff04ffff02ff06ffff04ff02ffff
    04ff0bff80808080ff80808080ff0b80ffff04ffff01ff32ff02ffff03ffff07
    ff0580ffff01ff0bffff0102ffff02ff06ffff04ff02ffff04ff09ff80808080
    ffff02ff06ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff05
    8080ff0180ff018080
    "
);

pub const P2_DELEGATED_CONDITIONS_PUZZLE_HASH: TreeHash = TreeHash::new(hex!(
    "0ff94726f1a8dea5c3f70d3121945190778d3b2b3fcda3735a1f290977e98341"
));