chia_sdk_driver/primitives/action_layer/
precommit_coin.rs1use chia_protocol::{Bytes32, Coin};
2use chia_puzzle_types::{
3 cat::{CatArgs, CatSolution},
4 CoinProof, LineageProof,
5};
6use chia_sdk_types::puzzles::{PrecommitLayerSolution, PrecommitSpendMode};
7use clvm_traits::ToClvm;
8use clvm_utils::TreeHash;
9use clvmr::{Allocator, NodePtr};
10
11use crate::{CatLayer, DriverError, Layer, PrecommitLayer, Spend, SpendContext};
12
13#[derive(Debug, Clone)]
14#[must_use]
15pub struct PrecommitCoin<V> {
16 pub coin: Coin,
17 pub asset_id: Bytes32,
18 pub proof: LineageProof,
19 pub inner_puzzle_hash: Bytes32,
20
21 pub controller_singleton_struct_hash: Bytes32,
22 pub relative_block_height: u32,
23 pub payout_puzzle_hash: Bytes32,
24 pub refund_puzzle_hash: Bytes32,
25 pub value: V,
26}
27
28impl<V> PrecommitCoin<V> {
29 #[allow(clippy::too_many_arguments)]
30 pub fn new(
31 ctx: &mut SpendContext,
32 parent_coin_id: Bytes32,
33 proof: LineageProof,
34 asset_id: Bytes32,
35 controller_singleton_struct_hash: Bytes32,
36 relative_block_height: u32,
37 payout_puzzle_hash: Bytes32,
38 refund_puzzle_hash: Bytes32,
39 value: V,
40 precommit_amount: u64,
41 ) -> Result<Self, DriverError>
42 where
43 V: ToClvm<Allocator> + Clone,
44 {
45 let value_ptr = ctx.alloc(&value)?;
46 let value_hash = ctx.tree_hash(value_ptr);
47
48 let inner_puzzle_hash = PrecommitLayer::<V>::puzzle_hash(
49 controller_singleton_struct_hash,
50 relative_block_height,
51 payout_puzzle_hash,
52 refund_puzzle_hash,
53 value_hash,
54 );
55
56 Ok(Self {
57 coin: Coin::new(
58 parent_coin_id,
59 CatArgs::curry_tree_hash(asset_id, inner_puzzle_hash).into(),
60 precommit_amount,
61 ),
62 proof,
63 asset_id,
64 inner_puzzle_hash: inner_puzzle_hash.into(),
65 controller_singleton_struct_hash,
66 relative_block_height,
67 payout_puzzle_hash,
68 refund_puzzle_hash,
69 value,
70 })
71 }
72
73 pub fn puzzle_hash(
74 asset_id: Bytes32,
75 controller_singleton_struct_hash: Bytes32,
76 relative_block_height: u32,
77 payout_puzzle_hash: Bytes32,
78 refund_puzzle_hash: Bytes32,
79 value_hash: TreeHash,
80 ) -> TreeHash {
81 CatArgs::curry_tree_hash(
82 asset_id,
83 PrecommitLayer::<V>::puzzle_hash(
84 controller_singleton_struct_hash,
85 relative_block_height,
86 payout_puzzle_hash,
87 refund_puzzle_hash,
88 value_hash,
89 ),
90 )
91 }
92
93 pub fn inner_puzzle(&self, ctx: &mut SpendContext) -> Result<NodePtr, DriverError>
94 where
95 V: Clone + ToClvm<Allocator>,
96 {
97 PrecommitLayer::<V>::new(
98 self.controller_singleton_struct_hash,
99 self.relative_block_height,
100 self.payout_puzzle_hash,
101 self.refund_puzzle_hash,
102 self.value.clone(),
103 )
104 .construct_puzzle(ctx)
105 }
106
107 pub fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result<NodePtr, DriverError>
108 where
109 V: Clone + ToClvm<Allocator>,
110 {
111 let inner_puzzle = self.inner_puzzle(ctx)?;
112
113 CatLayer::<NodePtr>::new(self.asset_id, inner_puzzle).construct_puzzle(ctx)
114 }
115
116 pub fn construct_solution(
117 &self,
118 ctx: &mut SpendContext,
119 mode: PrecommitSpendMode,
120 singleton_inner_puzzle_hash: Bytes32,
121 ) -> Result<NodePtr, DriverError>
122 where
123 V: ToClvm<Allocator> + Clone,
124 {
125 let layers = CatLayer::<NodePtr>::new(self.asset_id, self.inner_puzzle(ctx)?);
126
127 let inner_puzzle_solution = ctx.alloc(&PrecommitLayerSolution {
128 mode,
129 my_amount: self.coin.amount,
130 singleton_inner_puzzle_hash,
131 })?;
132
133 layers.construct_solution(
134 ctx,
135 CatSolution {
136 inner_puzzle_solution,
137 lineage_proof: Some(self.proof),
138 prev_coin_id: self.coin.coin_id(),
139 this_coin_info: self.coin,
140 next_coin_proof: CoinProof {
141 parent_coin_info: self.coin.parent_coin_info,
142 inner_puzzle_hash: self.inner_puzzle_hash,
143 amount: self.coin.amount,
144 },
145 prev_subtotal: 0,
146 extra_delta: 0,
147 },
148 )
149 }
150
151 pub fn spend(
152 &self,
153 ctx: &mut SpendContext,
154 mode: PrecommitSpendMode,
155 spender_inner_puzzle_hash: Bytes32,
156 ) -> Result<(), DriverError>
157 where
158 V: ToClvm<Allocator> + Clone,
159 {
160 let puzzle = self.construct_puzzle(ctx)?;
161 let solution = self.construct_solution(ctx, mode, spender_inner_puzzle_hash)?;
162
163 ctx.spend(self.coin, Spend::new(puzzle, solution))
164 }
165}