chia_sdk_driver/actions/
create_did.rs

1use chia_protocol::Bytes32;
2
3use crate::{
4    Asset, Deltas, DriverError, HashedPtr, Id, SingletonSpends, SpendAction, SpendContext,
5    SpendKind, Spends,
6};
7
8#[derive(Debug, Clone, Copy)]
9pub struct CreateDidAction {
10    pub recovery_list_hash: Option<Bytes32>,
11    pub num_verifications_required: u64,
12    pub metadata: HashedPtr,
13    pub amount: u64,
14}
15
16impl CreateDidAction {
17    pub fn new(
18        recovery_list_hash: Option<Bytes32>,
19        num_verifications_required: u64,
20        metadata: HashedPtr,
21        amount: u64,
22    ) -> Self {
23        Self {
24            recovery_list_hash,
25            num_verifications_required,
26            metadata,
27            amount,
28        }
29    }
30}
31
32impl Default for CreateDidAction {
33    fn default() -> Self {
34        Self::new(None, 1, HashedPtr::NIL, 1)
35    }
36}
37
38impl SpendAction for CreateDidAction {
39    fn calculate_delta(&self, deltas: &mut Deltas, index: usize) {
40        deltas.update(Id::New(index)).input += self.amount;
41        deltas.update(Id::Xch).output += self.amount;
42        deltas.set_needed(Id::Xch);
43    }
44
45    fn spend(
46        &self,
47        ctx: &mut SpendContext,
48        spends: &mut Spends,
49        index: usize,
50    ) -> Result<(), DriverError> {
51        let (source, launcher) = spends.xch.create_launcher(self.amount)?;
52        let source = &mut spends.xch.items[source];
53
54        let (parent_conditions, eve_did) = launcher.create_eve_did(
55            ctx,
56            source.asset.p2_puzzle_hash(),
57            self.recovery_list_hash,
58            self.num_verifications_required,
59            self.metadata,
60        )?;
61
62        match &mut source.kind {
63            SpendKind::Conditions(spend) => {
64                spend.add_conditions(parent_conditions);
65            }
66            SpendKind::Settlement(_) => {
67                return Err(DriverError::CannotEmitConditions);
68            }
69        }
70
71        spends
72            .dids
73            .insert(Id::New(index), SingletonSpends::new(eve_did, true));
74
75        Ok(())
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use anyhow::Result;
82    use chia_sdk_test::Simulator;
83    use indexmap::indexmap;
84
85    use crate::{Action, Relation};
86
87    use super::*;
88
89    #[test]
90    fn test_action_create_did() -> Result<()> {
91        let mut sim = Simulator::new();
92        let mut ctx = SpendContext::new();
93
94        let alice = sim.bls(1);
95
96        let mut spends = Spends::new(alice.puzzle_hash);
97        spends.add(alice.coin);
98
99        let deltas = spends.apply(&mut ctx, &[Action::create_empty_did()])?;
100
101        let outputs = spends.finish_with_keys(
102            &mut ctx,
103            &deltas,
104            Relation::None,
105            &indexmap! { alice.puzzle_hash => alice.pk },
106        )?;
107
108        sim.spend_coins(ctx.take(), &[alice.sk])?;
109
110        let did = outputs.dids[&Id::New(0)];
111        assert_ne!(sim.coin_state(did.coin.coin_id()), None);
112        assert_eq!(did.info.recovery_list_hash, None);
113        assert_eq!(did.info.num_verifications_required, 1);
114        assert_eq!(did.info.metadata, HashedPtr::NIL);
115        assert_eq!(did.info.p2_puzzle_hash, alice.puzzle_hash);
116        assert_eq!(did.coin.amount, 1);
117
118        Ok(())
119    }
120}