chia_sdk_driver/action_system/
spend_kind.rs1use chia_protocol::Bytes32;
2use chia_puzzle_types::offer::{NotarizedPayment, Payment};
3use chia_sdk_types::{
4 Conditions,
5 conditions::{AssertPuzzleAnnouncement, CreateCoin},
6 payment_assertion, tree_hash_notarized_payment,
7};
8use clvmr::{Allocator, NodePtr};
9use rand::{Rng, SeedableRng};
10use rand_chacha::ChaCha20Rng;
11
12use crate::{Output, OutputConstraints, OutputSet};
13
14mod conditions_spend;
15mod settlement_spend;
16
17pub use conditions_spend::*;
18pub use settlement_spend::*;
19
20#[derive(Debug, Clone)]
21pub enum SpendKind {
22 Conditions(ConditionsSpend),
23 Settlement(SettlementSpend),
24}
25
26impl SpendKind {
27 pub fn conditions() -> Self {
28 Self::Conditions(ConditionsSpend::new())
29 }
30
31 pub fn settlement() -> Self {
32 Self::Settlement(SettlementSpend::new())
33 }
34
35 pub fn is_conditions(&self) -> bool {
36 matches!(self, Self::Conditions(_))
37 }
38
39 pub fn is_settlement(&self) -> bool {
40 matches!(self, Self::Settlement(_))
41 }
42
43 pub fn create_coin_with_assertion(
44 &mut self,
45 allocator: &Allocator,
46 parent_puzzle_hash: Bytes32,
47 payment_assertions: &mut Vec<AssertPuzzleAnnouncement>,
48 create_coin: CreateCoin<NodePtr>,
49 ) {
50 match self {
51 SpendKind::Conditions(spend) => {
52 spend.add_conditions(Conditions::new().with(create_coin));
53 }
54 SpendKind::Settlement(spend) => {
55 let notarized_payment = NotarizedPayment::new(
57 Bytes32::default(),
58 vec![Payment::new(
59 create_coin.puzzle_hash,
60 create_coin.amount,
61 create_coin.memos,
62 )],
63 );
64 payment_assertions.push(payment_assertion(
65 parent_puzzle_hash,
66 tree_hash_notarized_payment(allocator, ¬arized_payment),
67 ));
68 spend.add_notarized_payment(notarized_payment);
69 }
70 }
71 }
72
73 pub fn create_intermediate_coin(&mut self, create_coin: CreateCoin<NodePtr>) {
74 match self {
75 Self::Conditions(spend) => {
76 spend.add_conditions(Conditions::new().with(create_coin));
77 }
78 Self::Settlement(spend) => {
79 spend.add_notarized_payment(NotarizedPayment {
80 nonce: Bytes32::new(ChaCha20Rng::from_os_rng().random()),
81 payments: vec![Payment::new(
82 create_coin.puzzle_hash,
83 create_coin.amount,
84 create_coin.memos,
85 )],
86 });
87 }
88 }
89 }
90
91 #[must_use]
92 pub fn empty_copy(&self) -> Self {
93 match self {
94 Self::Conditions(_) => Self::conditions(),
95 Self::Settlement(_) => Self::settlement(),
96 }
97 }
98}
99
100impl OutputSet for SpendKind {
101 fn has_output(&self, output: &Output) -> bool {
102 match self {
103 Self::Conditions(spend) => spend.has_output(output),
104 Self::Settlement(spend) => spend.has_output(output),
105 }
106 }
107
108 fn can_run_cat_tail(&self) -> bool {
109 match self {
110 Self::Conditions(spend) => spend.can_run_cat_tail(),
111 Self::Settlement(spend) => spend.can_run_cat_tail(),
112 }
113 }
114
115 fn missing_singleton_output(&self) -> bool {
116 match self {
117 Self::Conditions(spend) => spend.missing_singleton_output(),
118 Self::Settlement(spend) => spend.missing_singleton_output(),
119 }
120 }
121
122 fn is_allowed(&self, output: &Output, output_constraints: &OutputConstraints) -> bool {
123 match self {
124 Self::Conditions(spend) => spend.is_allowed(output, output_constraints),
125 Self::Settlement(spend) => spend.is_allowed(output, output_constraints),
126 }
127 }
128}