action_layer_driver/singleton/
helpers.rs1use chia::protocol::{Bytes32, Coin};
6use chia::puzzles::singleton::SingletonArgs;
7use chia::puzzles::{EveProof, LineageProof, Proof};
8use chia_wallet_sdk::driver::{Launcher, SpendContext};
9use chia_wallet_sdk::types::Conditions;
10use clvm_utils::TreeHash;
11use clvmr::NodePtr;
12
13use super::driver::SINGLETON_LAUNCHER_PUZZLE_HASH;
14use crate::DriverError;
15
16pub fn create_eve_proof(launcher_parent_coin_id: Bytes32, singleton_amount: u64) -> Proof {
22 Proof::Eve(EveProof {
23 parent_parent_coin_info: launcher_parent_coin_id,
24 parent_amount: singleton_amount,
25 })
26}
27
28pub fn create_lineage_proof(parent_coin: &Coin, parent_inner_puzzle_hash: TreeHash) -> Proof {
30 Proof::Lineage(LineageProof {
31 parent_parent_coin_info: parent_coin.parent_coin_info,
32 parent_inner_puzzle_hash: parent_inner_puzzle_hash.into(),
33 parent_amount: parent_coin.amount,
34 })
35}
36
37pub fn singleton_puzzle_hash(launcher_id: Bytes32, inner_puzzle_hash: TreeHash) -> Bytes32 {
43 SingletonArgs::curry_tree_hash(launcher_id, inner_puzzle_hash).into()
44}
45
46pub fn child_singleton_puzzle_hash(
48 child_launcher_id: Bytes32,
49 child_inner_puzzle_hash: TreeHash,
50) -> Bytes32 {
51 SingletonArgs::curry_tree_hash(child_launcher_id, child_inner_puzzle_hash).into()
52}
53
54pub fn expected_child_launcher_id(parent_singleton_coin_id: Bytes32) -> Bytes32 {
56 Coin::new(
57 parent_singleton_coin_id,
58 Bytes32::new(SINGLETON_LAUNCHER_PUZZLE_HASH),
59 0,
60 )
61 .coin_id()
62}
63
64#[derive(Debug, Clone)]
70pub struct ChildLaunchResult {
71 pub child_launcher_id: Bytes32,
72 pub child_singleton: Coin,
73}
74
75pub fn spawn_child_singleton(
80 ctx: &mut SpendContext,
81 parent_coin_id: Bytes32,
82 child_inner_puzzle_hash: TreeHash,
83) -> Result<ChildLaunchResult, DriverError> {
84 let child_launcher_coin = Coin::new(
86 parent_coin_id,
87 Bytes32::new(SINGLETON_LAUNCHER_PUZZLE_HASH),
88 0,
89 );
90 let child_launcher_id = child_launcher_coin.coin_id();
91
92 let (_child_conds, child_singleton_info) =
94 Launcher::from_coin(child_launcher_coin, Conditions::new())
95 .with_singleton_amount(1)
96 .mint_vault(ctx, child_inner_puzzle_hash, ())
97 .map_err(|e| DriverError::Launcher(format!("child spawn: {:?}", e)))?;
98
99 Ok(ChildLaunchResult {
100 child_launcher_id,
101 child_singleton: child_singleton_info.coin,
102 })
103}
104
105use chia::puzzles::singleton::{SingletonSolution, SingletonStruct};
110use clvm_utils::CurriedProgram;
111
112pub fn build_singleton_puzzle(
114 ctx: &mut SpendContext,
115 launcher_id: Bytes32,
116 inner_puzzle: NodePtr,
117) -> Result<NodePtr, DriverError> {
118 let singleton_mod_hash = TreeHash::new(chia_puzzles::SINGLETON_TOP_LAYER_V1_1_HASH);
119 let singleton_ptr = ctx
120 .puzzle(singleton_mod_hash, &chia_puzzles::SINGLETON_TOP_LAYER_V1_1)
121 .map_err(|e| DriverError::PuzzleLoad(format!("singleton: {:?}", e)))?;
122
123 ctx.alloc(&CurriedProgram {
124 program: singleton_ptr,
125 args: SingletonArgs {
126 singleton_struct: SingletonStruct::new(launcher_id),
127 inner_puzzle,
128 },
129 })
130 .map_err(|e| DriverError::Alloc(format!("singleton curry: {:?}", e)))
131}
132
133pub fn build_singleton_solution(
135 ctx: &mut SpendContext,
136 proof: Proof,
137 amount: u64,
138 inner_solution: NodePtr,
139) -> Result<NodePtr, DriverError> {
140 ctx.alloc(&SingletonSolution {
141 lineage_proof: proof,
142 amount,
143 inner_solution,
144 })
145 .map_err(|e| DriverError::Alloc(format!("singleton solution: {:?}", e)))
146}
147
148pub fn create_singleton_coin_spend(
150 ctx: &mut SpendContext,
151 singleton_coin: &Coin,
152 singleton_puzzle: NodePtr,
153 singleton_solution: NodePtr,
154) -> Result<(), DriverError> {
155 use chia::protocol::CoinSpend;
156
157 let puzzle_reveal = ctx
158 .serialize(&singleton_puzzle)
159 .map_err(|e| DriverError::Serialize(format!("{:?}", e)))?;
160 let solution = ctx
161 .serialize(&singleton_solution)
162 .map_err(|e| DriverError::Serialize(format!("{:?}", e)))?;
163
164 let coin_spend = CoinSpend::new(*singleton_coin, puzzle_reveal, solution);
165 ctx.insert(coin_spend);
166 Ok(())
167}
168
169pub fn launch_singleton(
173 ctx: &mut SpendContext,
174 funding_coin: &Coin,
175 inner_puzzle_hash: Bytes32,
176 singleton_amount: u64,
177) -> Result<super::LaunchResult, DriverError> {
178 let launcher = Launcher::new(funding_coin.coin_id(), singleton_amount);
179 let launcher_id = launcher.coin().coin_id();
180
181 let (launcher_conditions, singleton_coin) = launcher
182 .spend(ctx, inner_puzzle_hash, ())
183 .map_err(|e| DriverError::Launcher(format!("{:?}", e)))?;
184
185 Ok(super::LaunchResult {
186 launcher_id,
187 coin: singleton_coin,
188 conditions: launcher_conditions,
189 })
190}