chia_sdk_driver/clear_signing/
vault_spend.rs1use chia_consensus::opcodes::SEND_MESSAGE;
2use chia_protocol::Bytes32;
3use chia_sdk_types::Condition;
4use clvm_traits::FromClvm;
5use clvmr::{Allocator, NodePtr};
6use num_bigint::BigInt;
7
8use crate::{DriverError, Facts, Spend, VaultMessage, parse_delegated_spend, parse_vault_message};
9
10#[derive(Debug, Clone)]
11pub struct VaultSpendSummary {
12 pub child: Option<VaultOutput>,
13 pub drop_coins: Vec<DropCoin>,
14 pub messages: Vec<VaultMessage>,
15}
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
18pub struct VaultOutput {
19 pub custody_hash: Bytes32,
20 pub amount: u64,
21}
22
23impl VaultOutput {
24 pub fn new(custody_hash: Bytes32, amount: u64) -> Self {
25 Self {
26 custody_hash,
27 amount,
28 }
29 }
30}
31
32#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
33pub struct DropCoin {
34 pub puzzle_hash: Bytes32,
35 pub amount: u64,
36}
37
38impl DropCoin {
39 pub fn new(puzzle_hash: Bytes32, amount: u64) -> Self {
40 Self {
41 puzzle_hash,
42 amount,
43 }
44 }
45}
46
47pub fn parse_vault_delegated_spend(
48 facts: &mut Facts,
49 allocator: &mut Allocator,
50 delegated_spend: Spend,
51) -> Result<VaultSpendSummary, DriverError> {
52 let conditions = parse_delegated_spend(allocator, delegated_spend)?;
53
54 let mut child = None;
55 let mut drop_coins = Vec::new();
56 let mut messages = Vec::new();
57
58 for condition in conditions {
59 match condition {
60 Condition::AssertPuzzleAnnouncement(condition) => {
61 facts.assert_puzzle_announcement(condition.announcement_id);
62 }
63 Condition::AssertConcurrentSpend(condition) => {
64 facts.assert_spend(condition.coin_id);
65 }
66 Condition::AssertBeforeSecondsAbsolute(condition) => {
67 facts.update_actual_expiration_time(condition.seconds);
68 }
69 Condition::ReserveFee(condition) => {
70 facts.add_reserved_fees(condition.amount);
71 }
72 Condition::CreateCoin(condition) => {
73 if condition.amount % 2 == 1 {
83 child = Some(VaultOutput {
84 custody_hash: condition.puzzle_hash,
85 amount: condition.amount,
86 });
87 } else {
88 drop_coins.push(DropCoin {
89 puzzle_hash: condition.puzzle_hash,
90 amount: condition.amount,
91 });
92 }
93 }
94 Condition::SendMessage(condition) => {
95 let vault_message = parse_vault_message(allocator, condition)?;
100 messages.push(vault_message);
101 }
102 Condition::Other(condition) => {
103 let (opcode, _) = <(BigInt, NodePtr)>::from_clvm(allocator, condition)?;
104
105 if opcode == BigInt::from(SEND_MESSAGE) {
109 return Err(DriverError::InvalidVaultMessageFormat);
110 }
111 }
112 _ => {}
113 }
114 }
115
116 Ok(VaultSpendSummary {
117 child,
118 drop_coins,
119 messages,
120 })
121}