Skip to main content

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

1use chia_protocol::Bytes32;
2use chia_puzzle_types::offer::{NotarizedPayment, Payment};
3use chia_puzzles::SETTLEMENT_PAYMENT_HASH;
4use chia_sdk_types::{
5    Conditions, Mod, announcement_id,
6    puzzles::{
7        DefaultCatMakerArgs, PuzzleAndSolution, XchandlesExtendActionArgs,
8        XchandlesExtendActionSolution, XchandlesFactorPricingPuzzleArgs, XchandlesHandleSlotValue,
9        XchandlesPricingSolution, XchandlesSlotNonce,
10    },
11};
12use clvm_traits::clvm_tuple;
13use clvm_utils::{ToTreeHash, TreeHash};
14use clvmr::NodePtr;
15
16use crate::{
17    DriverError, SingletonAction, Slot, Spend, SpendContext, XchandlesConstants, XchandlesRegistry,
18    XchandlesRegistryCreatedAnnouncementPrefix,
19};
20
21use super::{XchandlesExtendActionLog, run_pricing_output};
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24pub struct XchandlesExtendAction {
25    pub launcher_id: Bytes32,
26    pub payout_puzzle_hash: Bytes32,
27}
28
29impl ToTreeHash for XchandlesExtendAction {
30    fn tree_hash(&self) -> TreeHash {
31        Self::new_args(self.launcher_id, self.payout_puzzle_hash).curry_tree_hash()
32    }
33}
34
35impl SingletonAction<XchandlesRegistry> for XchandlesExtendAction {
36    fn from_constants(constants: &XchandlesConstants) -> Self {
37        Self {
38            launcher_id: constants.launcher_id,
39            payout_puzzle_hash: constants.precommit_payout_puzzle_hash,
40        }
41    }
42}
43
44impl XchandlesExtendAction {
45    pub fn new_args(
46        launcher_id: Bytes32,
47        payout_puzzle_hash: Bytes32,
48    ) -> XchandlesExtendActionArgs {
49        XchandlesExtendActionArgs {
50            offer_mod_hash: SETTLEMENT_PAYMENT_HASH.into(),
51            payout_puzzle_hash,
52            handle_slot_1st_curry_hash: Slot::<()>::first_curry_hash(
53                launcher_id,
54                XchandlesSlotNonce::HANDLE.to_u64(),
55            )
56            .into(),
57        }
58    }
59
60    fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result<NodePtr, DriverError> {
61        ctx.curry(Self::new_args(self.launcher_id, self.payout_puzzle_hash))
62    }
63
64    pub fn get_log(
65        ctx: &mut SpendContext,
66        solution: NodePtr,
67    ) -> Result<XchandlesExtendActionLog, DriverError> {
68        let solution =
69            ctx.extract::<XchandlesExtendActionSolution<NodePtr, NodePtr, NodePtr, ()>>(solution)?;
70
71        let pricing_solution =
72            ctx.extract::<XchandlesPricingSolution>(solution.pricing_puzzle_and_solution.solution)?;
73        let spent_slot = XchandlesHandleSlotValue::new(
74            solution.counter,
75            pricing_solution.handle.tree_hash().into(),
76            solution.neighbors.left_value,
77            solution.neighbors.right_value,
78            pricing_solution.current_expiration,
79            solution.rest.owner_launcher_id,
80            solution.rest.resolved_launcher_id,
81        );
82
83        let (total_price, registered_time) = run_pricing_output(
84            ctx,
85            solution.pricing_puzzle_and_solution.puzzle,
86            solution.pricing_puzzle_and_solution.solution,
87        )?;
88
89        let created_slot = XchandlesHandleSlotValue::new(
90            solution.counter + 1,
91            spent_slot.handle_hash,
92            solution.neighbors.left_value,
93            solution.neighbors.right_value,
94            pricing_solution.current_expiration + registered_time,
95            solution.rest.owner_launcher_id,
96            solution.rest.resolved_launcher_id,
97        );
98
99        Ok(XchandlesExtendActionLog {
100            spent_slot,
101            created_slot,
102            total_price,
103            registered_time,
104        })
105    }
106
107    #[allow(clippy::too_many_arguments)]
108    pub fn spend(
109        self,
110        ctx: &mut SpendContext,
111        registry: &mut XchandlesRegistry,
112        handle: &str,
113        slot: Slot<XchandlesHandleSlotValue>,
114        payment_asset_id: Bytes32,
115        base_handle_price: u64,
116        registration_period: u64,
117        num_periods: u64,
118        buy_time: u64,
119    ) -> Result<(Conditions, NotarizedPayment), DriverError> {
120        let spender_inner_puzzle_hash = registry.info.inner_puzzle_hash().into();
121
122        // spend self
123        let cat_maker_puzzle_reveal = ctx.curry(DefaultCatMakerArgs::new(
124            payment_asset_id.tree_hash().into(),
125        ))?;
126        let pricing_puzzle_reveal = ctx.curry(XchandlesFactorPricingPuzzleArgs {
127            base_price: base_handle_price,
128            registration_period,
129        })?;
130
131        let slot = registry.actual_handle_slot(slot);
132        let action_solution = ctx.alloc(&XchandlesExtendActionSolution {
133            counter: slot.info.value.counter,
134            pricing_puzzle_and_solution: PuzzleAndSolution::new(
135                pricing_puzzle_reveal,
136                XchandlesPricingSolution {
137                    buy_time,
138                    current_expiration: slot.info.value.expiration,
139                    handle: handle.to_string(),
140                    num_periods,
141                },
142            ),
143            neighbors: slot.info.value.neighbors,
144            rest: slot.info.value.rest_data(),
145            cat_maker_and_solution: PuzzleAndSolution::new(cat_maker_puzzle_reveal, ()),
146        })?;
147        let action_puzzle = self.construct_puzzle(ctx)?;
148
149        registry.insert_action_spend(ctx, Spend::new(action_puzzle, action_solution))?;
150
151        let renew_amount =
152            XchandlesFactorPricingPuzzleArgs::get_price(base_handle_price, handle, num_periods);
153
154        let notarized_payment = NotarizedPayment {
155            nonce: clvm_tuple!(handle.to_string(), slot.info.value.expiration)
156                .tree_hash()
157                .into(),
158            payments: vec![Payment::new(
159                registry.info.constants.precommit_payout_puzzle_hash,
160                renew_amount,
161                ctx.hint(registry.info.constants.precommit_payout_puzzle_hash)?,
162            )],
163        };
164
165        // spend slot
166        slot.spend(ctx, spender_inner_puzzle_hash)?;
167
168        Ok((
169            Conditions::new().assert_puzzle_announcement(announcement_id(
170                registry.coin.puzzle_hash,
171                XchandlesRegistryCreatedAnnouncementPrefix::extend(renew_amount, handle),
172            )),
173            notarized_payment,
174        ))
175    }
176}