chia_sdk_driver/layers/action_layer/actions/xchandles/
update.rs

1use chia_protocol::{Bytes, Bytes32};
2use chia_puzzles::{SINGLETON_LAUNCHER_HASH, SINGLETON_TOP_LAYER_V1_1_HASH};
3use chia_sdk_types::{
4    Conditions, Mod,
5    puzzles::{
6        XchandlesDataValue, XchandlesSlotValue, XchandlesUpdateActionArgs,
7        XchandlesUpdateActionSolution,
8    },
9};
10use clvm_traits::clvm_tuple;
11use clvm_utils::{ToTreeHash, TreeHash};
12use clvmr::NodePtr;
13
14use crate::{
15    DriverError, SingletonAction, Slot, Spend, SpendContext, XchandlesConstants, XchandlesRegistry,
16};
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
19pub struct XchandlesUpdateAction {
20    pub launcher_id: Bytes32,
21}
22
23impl ToTreeHash for XchandlesUpdateAction {
24    fn tree_hash(&self) -> TreeHash {
25        Self::new_args(self.launcher_id).curry_tree_hash()
26    }
27}
28
29impl SingletonAction<XchandlesRegistry> for XchandlesUpdateAction {
30    fn from_constants(constants: &XchandlesConstants) -> Self {
31        Self {
32            launcher_id: constants.launcher_id,
33        }
34    }
35}
36
37impl XchandlesUpdateAction {
38    pub fn new_args(launcher_id: Bytes32) -> XchandlesUpdateActionArgs {
39        XchandlesUpdateActionArgs {
40            singleton_mod_hash: SINGLETON_TOP_LAYER_V1_1_HASH.into(),
41            singleton_launcher_mod_hash: SINGLETON_LAUNCHER_HASH.into(),
42            slot_1st_curry_hash: Slot::<()>::first_curry_hash(launcher_id, 0).into(),
43        }
44    }
45
46    fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result<NodePtr, DriverError> {
47        ctx.curry(Self::new_args(self.launcher_id))
48    }
49
50    pub fn spent_slot_value(
51        ctx: &SpendContext,
52        solution: NodePtr,
53    ) -> Result<XchandlesSlotValue, DriverError> {
54        let solution = ctx.extract::<XchandlesUpdateActionSolution>(solution)?;
55
56        Ok(solution.current_slot_value)
57    }
58
59    pub fn created_slot_value(
60        ctx: &mut SpendContext,
61        solution: NodePtr,
62    ) -> Result<XchandlesSlotValue, DriverError> {
63        let solution = ctx.extract::<XchandlesUpdateActionSolution>(solution)?;
64
65        Ok(solution.current_slot_value.with_data(
66            solution.new_data.owner_launcher_id,
67            solution.new_data.resolved_data,
68        ))
69    }
70
71    pub fn spend(
72        self,
73        ctx: &mut SpendContext,
74        registry: &mut XchandlesRegistry,
75        slot: Slot<XchandlesSlotValue>,
76        new_owner_launcher_id: Bytes32,
77        new_resolved_data: &Bytes,
78        announcer_inner_puzzle_hash: Bytes32,
79    ) -> Result<Conditions, DriverError> {
80        // spend self
81        let slot = registry.actual_slot(slot);
82        let action_solution = ctx.alloc(&XchandlesUpdateActionSolution {
83            current_slot_value: slot.info.value.clone(),
84            new_data: XchandlesDataValue {
85                owner_launcher_id: new_owner_launcher_id,
86                resolved_data: new_resolved_data.clone(),
87            },
88            announcer_inner_puzzle_hash,
89        })?;
90        let action_puzzle = self.construct_puzzle(ctx)?;
91
92        registry.insert_action_spend(ctx, Spend::new(action_puzzle, action_solution))?;
93
94        // spend slot
95        let my_inner_puzzle_hash = registry.info.inner_puzzle_hash().into();
96
97        let msg: Bytes32 = clvm_tuple!(
98            slot.info.value.handle_hash,
99            clvm_tuple!(new_owner_launcher_id, new_resolved_data.clone())
100        )
101        .tree_hash()
102        .into();
103
104        slot.spend(ctx, my_inner_puzzle_hash)?;
105
106        Ok(Conditions::new().send_message(
107            18,
108            msg.into(),
109            vec![ctx.alloc(&registry.coin.puzzle_hash)?],
110        ))
111    }
112}