1use std::{
20 fmt::{self, Debug},
21 str::FromStr,
22};
23
24#[cfg(feature = "async")]
25use darkfi_serial::async_trait;
26use darkfi_serial::{SerialDecodable, SerialEncodable};
27
28use super::{crypto::ContractId, ContractError, GenericResult};
29use crate::crypto::{DAO_CONTRACT_ID, DEPLOYOOOR_CONTRACT_ID, MONEY_CONTRACT_ID};
30
31#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, SerialEncodable, SerialDecodable)]
32pub struct TransactionHash(pub [u8; 32]);
34
35impl TransactionHash {
36 pub fn new(data: [u8; 32]) -> Self {
37 Self(data)
38 }
39
40 pub fn none() -> Self {
41 Self([0; 32])
42 }
43
44 #[inline]
45 pub fn inner(&self) -> &[u8; 32] {
46 &self.0
47 }
48
49 pub fn as_string(&self) -> String {
50 blake3::Hash::from_bytes(self.0).to_string()
51 }
52}
53
54impl FromStr for TransactionHash {
55 type Err = ContractError;
56
57 fn from_str(tx_hash_str: &str) -> GenericResult<Self> {
58 let Ok(hash) = blake3::Hash::from_str(tx_hash_str) else {
59 return Err(ContractError::HexFmtErr);
60 };
61 Ok(Self(*hash.as_bytes()))
62 }
63}
64
65impl fmt::Display for TransactionHash {
66 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
67 write!(f, "{}", self.as_string())
68 }
69}
70
71#[derive(Clone, Eq, PartialEq, SerialEncodable, SerialDecodable)]
75pub struct ContractCall {
76 pub contract_id: ContractId,
78 pub data: Vec<u8>,
80}
81impl ContractCall {
84 pub fn is_money_fee(&self) -> bool {
86 self.matches_contract_call_type(*MONEY_CONTRACT_ID, 0x00)
87 }
88
89 pub fn is_money_genesis_mint(&self) -> bool {
91 self.matches_contract_call_type(*MONEY_CONTRACT_ID, 0x01)
92 }
93
94 pub fn is_money_pow_reward(&self) -> bool {
96 self.matches_contract_call_type(*MONEY_CONTRACT_ID, 0x02)
97 }
98
99 pub fn is_money_transfer(&self) -> bool {
101 self.matches_contract_call_type(*MONEY_CONTRACT_ID, 0x03)
102 }
103
104 pub fn is_money_otc_swap(&self) -> bool {
106 self.matches_contract_call_type(*MONEY_CONTRACT_ID, 0x04)
107 }
108
109 pub fn is_money_auth_token_mint(&self) -> bool {
111 self.matches_contract_call_type(*MONEY_CONTRACT_ID, 0x05)
112 }
113
114 pub fn is_money_auth_token_freeze(&self) -> bool {
116 self.matches_contract_call_type(*MONEY_CONTRACT_ID, 0x06)
117 }
118
119 pub fn is_money_token_mint(&self) -> bool {
121 self.matches_contract_call_type(*MONEY_CONTRACT_ID, 0x07)
122 }
123
124 pub fn is_dao_mint(&self) -> bool {
126 self.matches_contract_call_type(*DAO_CONTRACT_ID, 0x00)
127 }
128
129 pub fn is_dao_propose(&self) -> bool {
131 self.matches_contract_call_type(*DAO_CONTRACT_ID, 0x01)
132 }
133
134 pub fn is_dao_vote(&self) -> bool {
136 self.matches_contract_call_type(*DAO_CONTRACT_ID, 0x02)
137 }
138
139 pub fn is_dao_exec(&self) -> bool {
141 self.matches_contract_call_type(*DAO_CONTRACT_ID, 0x03)
142 }
143
144 pub fn is_dao_auth_money_transfer(&self) -> bool {
146 self.matches_contract_call_type(*DAO_CONTRACT_ID, 0x04)
147 }
148
149 pub fn is_deployment(&self) -> bool {
151 self.matches_contract_call_type(*DEPLOYOOOR_CONTRACT_ID, 0x00)
152 }
153
154 pub fn matches_contract_call_type(&self, contract_id: ContractId, func_code: u8) -> bool {
156 !self.data.is_empty() && self.contract_id == contract_id && self.data[0] == func_code
157 }
158}
159
160impl Debug for ContractCall {
162 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
163 write!(f, "ContractCall(id={:?}", self.contract_id.inner())?;
164 let calldata = &self.data;
165 if !calldata.is_empty() {
166 write!(f, ", function_code={}", calldata[0])?;
167 }
168 write!(f, ")")
169 }
170}