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