chia_sdk_driver/actions/
melt_singleton.rs1use crate::{Deltas, DriverError, Id, SingletonDestination, SpendAction, SpendContext, Spends};
2
3#[derive(Debug, Clone, Copy)]
4pub struct MeltSingletonAction {
5 pub id: Id,
6 pub amount: u64,
7}
8
9impl MeltSingletonAction {
10 pub fn new(id: Id, amount: u64) -> Self {
11 Self { id, amount }
12 }
13}
14
15impl SpendAction for MeltSingletonAction {
16 fn calculate_delta(&self, deltas: &mut Deltas, _index: usize) {
17 deltas.update(self.id).output += self.amount;
18 deltas.update(Id::Xch).input += self.amount;
19 }
20
21 fn spend(
22 &self,
23 _ctx: &mut SpendContext,
24 spends: &mut Spends,
25 _index: usize,
26 ) -> Result<(), DriverError> {
27 if let Some(did) = spends.dids.get_mut(&self.id) {
28 let source = did.last_mut()?;
29 source.child_info.destination = Some(SingletonDestination::Melt);
30 } else if let Some(option) = spends.options.get_mut(&self.id) {
31 let source = option.last_mut()?;
32 source.child_info.destination = Some(SingletonDestination::Melt);
33 } else {
34 return Err(DriverError::InvalidAssetId);
35 }
36
37 Ok(())
38 }
39}
40
41#[cfg(test)]
42mod tests {
43 use anyhow::Result;
44 use chia_protocol::Bytes32;
45 use chia_puzzle_types::{
46 offer::{NotarizedPayment, Payment},
47 Memos,
48 };
49 use chia_sdk_test::Simulator;
50 use indexmap::indexmap;
51 use rstest::rstest;
52
53 use crate::{Action, Cat, CatSpend, OptionType, OptionUnderlying, Relation};
54
55 use super::*;
56
57 #[test]
58 fn test_action_melt_did() -> Result<()> {
59 let mut sim = Simulator::new();
60 let mut ctx = SpendContext::new();
61
62 let alice = sim.bls(1);
63
64 let mut spends = Spends::new(alice.puzzle_hash);
65 spends.add(alice.coin);
66
67 let deltas = spends.apply(
68 &mut ctx,
69 &[
70 Action::create_empty_did(),
71 Action::melt_singleton(Id::New(0), 1),
72 ],
73 )?;
74
75 spends.finish_with_keys(
76 &mut ctx,
77 &deltas,
78 Relation::None,
79 &indexmap! { alice.puzzle_hash => alice.pk },
80 )?;
81
82 sim.spend_coins(ctx.take(), &[alice.sk])?;
83
84 Ok(())
85 }
86
87 #[rstest]
88 #[case::normal(None)]
89 #[case::revocable(Some(Bytes32::default()))]
90 fn test_action_exercise_option(#[case] hidden_puzzle_hash: Option<Bytes32>) -> Result<()> {
91 let mut sim = Simulator::new();
92 let mut ctx = SpendContext::new();
93
94 let alice = sim.bls(2);
95 let bob = sim.bls(1);
96 let bob_hint = ctx.hint(bob.puzzle_hash)?;
97
98 let mut spends = Spends::new(alice.puzzle_hash);
99 spends.add(alice.coin);
100
101 let deltas = spends.apply(
102 &mut ctx,
103 &[
104 Action::single_issue_cat(hidden_puzzle_hash, 1),
105 Action::mint_option(
106 alice.puzzle_hash,
107 10,
108 Id::New(0),
109 1,
110 OptionType::Xch { amount: 1 },
111 1,
112 ),
113 Action::send(Id::New(1), bob.puzzle_hash, 1, bob_hint),
114 ],
115 )?;
116
117 let outputs = spends.finish_with_keys(
118 &mut ctx,
119 &deltas,
120 Relation::None,
121 &indexmap! { alice.puzzle_hash => alice.pk },
122 )?;
123
124 let underlying_cat = outputs.cats[&Id::New(0)][0];
125 let option = outputs.options[&Id::New(1)];
126
127 sim.spend_coins(ctx.take(), &[alice.sk])?;
128
129 let underlying = OptionUnderlying::new(
130 option.info.launcher_id,
131 alice.puzzle_hash,
132 10,
133 1,
134 OptionType::Xch { amount: 1 },
135 );
136
137 let underlying_spend =
138 underlying.exercise_spend(&mut ctx, option.info.inner_puzzle_hash().into(), 1)?;
139
140 let settlement_cats =
141 Cat::spend_all(&mut ctx, &[CatSpend::new(underlying_cat, underlying_spend)])?;
142
143 let mut spends = Spends::new(bob.puzzle_hash);
144 spends.add(bob.coin);
145 spends.add(option);
146 spends.add(settlement_cats[0]);
147
148 let deltas = spends.apply(
149 &mut ctx,
150 &[
151 Action::melt_singleton(Id::Existing(option.info.launcher_id), 1),
152 Action::settle(
153 Id::Xch,
154 NotarizedPayment::new(
155 option.info.launcher_id,
156 vec![Payment::new(alice.puzzle_hash, 1, Memos::None)],
157 ),
158 ),
159 ],
160 )?;
161
162 spends.finish_with_keys(
163 &mut ctx,
164 &deltas,
165 Relation::None,
166 &indexmap! { bob.puzzle_hash => bob.pk },
167 )?;
168
169 sim.spend_coins(ctx.take(), &[bob.sk])?;
170
171 Ok(())
172 }
173}