chia_sdk_driver/primitives/singleton.rs
1use chia_protocol::{Bytes32, Coin};
2use chia_puzzle_types::{singleton::SingletonArgs, LineageProof, Proof};
3use clvm_utils::TreeHash;
4
5/// A generic singleton primitive, which can be extended with the [`SingletonInfo`] trait.
6#[must_use]
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub struct Singleton<I> {
9 /// The coin that this [`Singleton`] represents. Its puzzle hash should match the singleton outer puzzle hash.
10 pub coin: Coin,
11
12 /// The proof is needed by the singleton puzzle to prove that this coin is a legitimate singleton.
13 /// It's typically obtained by looking up and parsing the parent coin.
14 ///
15 /// Note that while the proof will be a [`LineageProof`] for most coins,
16 /// for the first singleton in the lineage it will be an [`EveProof`](chia_puzzle_types::EveProof) instead.
17 /// However, the eve coin is typically unhinted and spent in the same transaction as it was created,
18 /// so this is not relevant for database storage or syncing unspent coins.
19 pub proof: Proof,
20
21 /// The information needed to construct the outer puzzle.
22 pub info: I,
23}
24
25impl<I> Singleton<I>
26where
27 I: SingletonInfo,
28{
29 pub fn new(coin: Coin, proof: Proof, info: I) -> Self {
30 Self { coin, proof, info }
31 }
32
33 /// Creates a [`LineageProof`] for which would be valid for any children created by this [`Singleton`].
34 pub fn child_lineage_proof(&self) -> LineageProof {
35 LineageProof {
36 parent_parent_coin_info: self.coin.parent_coin_info,
37 parent_inner_puzzle_hash: self.info.inner_puzzle_hash().into(),
38 parent_amount: self.coin.amount,
39 }
40 }
41
42 /// Creates a new [`Singleton`] that represents a child of this one.
43 ///
44 /// You can specify the new [`SingletonInfo`] to use for the child.
45 ///
46 /// It's important to use the right [`SingletonInfo`] instead of modifying it afterward,
47 /// otherwise the puzzle hash of the child will not match the one expected by the coin.
48 pub fn child_with<N>(&self, info: N, amount: u64) -> Singleton<N>
49 where
50 N: SingletonInfo,
51 {
52 Singleton::new(
53 Coin::new(
54 self.coin.coin_id(),
55 SingletonArgs::curry_tree_hash(info.launcher_id(), info.inner_puzzle_hash()).into(),
56 amount,
57 ),
58 Proof::Lineage(self.child_lineage_proof()),
59 info,
60 )
61 }
62}
63
64pub trait SingletonInfo {
65 fn launcher_id(&self) -> Bytes32;
66
67 /// Calculates the inner puzzle hash of the singleton.
68 ///
69 /// This does not include the [`SingletonLayer`](crate::SingletonLayer).
70 fn inner_puzzle_hash(&self) -> TreeHash;
71
72 /// Calculates the full puzzle hash of the the outer [`SingletonLayer`](crate::SingletonLayer).
73 fn puzzle_hash(&self) -> TreeHash {
74 SingletonArgs::curry_tree_hash(self.launcher_id(), self.inner_puzzle_hash())
75 }
76}