action_layer_driver/singleton/
types.rs

1//! Core types for singleton management
2
3use chia::protocol::{Bytes32, Coin};
4use chia::puzzles::{EveProof, LineageProof, Proof};
5use clvm_utils::TreeHash;
6
7/// Lineage information for generating proofs
8#[derive(Debug, Clone)]
9pub enum SingletonLineage {
10    /// First spend after launch (eve proof)
11    Eve {
12        /// The parent coin ID of the launcher (funding coin ID)
13        launcher_parent_id: Bytes32,
14        /// The singleton amount
15        amount: u64,
16    },
17    /// Subsequent spends (lineage proof)
18    Lineage {
19        /// The parent singleton coin
20        parent_coin: Coin,
21        /// The parent's inner puzzle hash
22        parent_inner_hash: TreeHash,
23    },
24}
25
26impl SingletonLineage {
27    /// Convert to a Proof for use in singleton solutions
28    pub fn to_proof(&self) -> Proof {
29        match self {
30            SingletonLineage::Eve {
31                launcher_parent_id,
32                amount,
33            } => Proof::Eve(EveProof {
34                parent_parent_coin_info: *launcher_parent_id,
35                parent_amount: *amount,
36            }),
37            SingletonLineage::Lineage {
38                parent_coin,
39                parent_inner_hash,
40            } => Proof::Lineage(LineageProof {
41                parent_parent_coin_info: parent_coin.parent_coin_info,
42                parent_inner_puzzle_hash: (*parent_inner_hash).into(),
43                parent_amount: parent_coin.amount,
44            }),
45        }
46    }
47
48    /// Create eve lineage from funding coin info
49    pub fn eve(funding_coin_id: Bytes32, singleton_amount: u64) -> Self {
50        SingletonLineage::Eve {
51            launcher_parent_id: funding_coin_id,
52            amount: singleton_amount,
53        }
54    }
55
56    /// Create lineage proof from parent coin and inner hash
57    pub fn lineage(parent_coin: Coin, parent_inner_hash: TreeHash) -> Self {
58        SingletonLineage::Lineage {
59            parent_coin,
60            parent_inner_hash,
61        }
62    }
63}
64
65/// Tracks an on-chain singleton's current state
66#[derive(Debug, Clone)]
67pub struct SingletonCoin {
68    /// The launcher ID (singleton identity)
69    pub launcher_id: Bytes32,
70    /// The current unspent coin
71    pub coin: Coin,
72    /// Lineage for proof generation
73    pub lineage: SingletonLineage,
74}
75
76impl SingletonCoin {
77    /// Create a new SingletonCoin
78    pub fn new(launcher_id: Bytes32, coin: Coin, lineage: SingletonLineage) -> Self {
79        Self {
80            launcher_id,
81            coin,
82            lineage,
83        }
84    }
85
86    /// Get the proof for spending this singleton
87    pub fn proof(&self) -> Proof {
88        self.lineage.to_proof()
89    }
90
91    /// Get the coin ID
92    pub fn coin_id(&self) -> Bytes32 {
93        self.coin.coin_id()
94    }
95}
96
97/// Result of launching a singleton
98#[derive(Debug, Clone)]
99pub struct LaunchResult {
100    /// The launcher ID (singleton identity, same as network_id for network singletons)
101    pub launcher_id: Bytes32,
102    /// The newly created singleton coin
103    pub coin: Coin,
104    /// Conditions to include in the funding coin spend
105    pub conditions: chia_wallet_sdk::types::Conditions,
106}
107
108/// Result of an action spend (generic over action-specific output)
109#[derive(Debug, Clone)]
110pub struct ActionSpendResult<T> {
111    /// The recreated singleton coin (None if melted)
112    pub new_coin: Option<Coin>,
113    /// New lineage for next spend (None if melted)
114    pub new_lineage: Option<SingletonLineage>,
115    /// Action-specific output (child launcher IDs, etc.)
116    pub output: T,
117}
118
119impl<T> ActionSpendResult<T> {
120    /// Create result for a normal action (singleton recreated)
121    pub fn normal(new_coin: Coin, new_lineage: SingletonLineage, output: T) -> Self {
122        Self {
123            new_coin: Some(new_coin),
124            new_lineage: Some(new_lineage),
125            output,
126        }
127    }
128
129    /// Create result for a melt action (singleton destroyed)
130    pub fn melted(output: T) -> Self {
131        Self {
132            new_coin: None,
133            new_lineage: None,
134            output,
135        }
136    }
137
138    /// Check if the singleton was melted
139    pub fn is_melted(&self) -> bool {
140        self.new_coin.is_none()
141    }
142}
143
144/// Marker type for actions that produce no specific output
145#[derive(Debug, Clone, Copy, Default)]
146pub struct NoOutput;
147
148/// Marker type for actions that melt (destroy) the singleton
149#[derive(Debug, Clone, Copy)]
150pub struct Melted;