1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
5pub struct AfterBlockHeight(pub u64);
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct EpochNo(pub String);
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct StakeAddress(pub String);
14
15#[derive(Debug, Clone, Serialize, Deserialize)]
17pub struct TxHash(pub String);
18
19#[derive(Debug, Clone, Serialize, Deserialize)]
21pub struct AssetPolicy(pub String);
22
23#[derive(Debug, Clone, Serialize, Deserialize)]
25pub struct AssetName(pub String);
26
27#[derive(Debug, Clone, Serialize, Deserialize)]
29pub struct AssetPolicyNft(pub String);
30
31#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct AssetNameNft(pub String);
34
35#[derive(Debug, Clone, Serialize, Deserialize)]
37pub struct VoterId(pub String);
38
39#[derive(Debug, Clone, Serialize, Deserialize)]
41pub struct DrepId(pub String);
42
43#[derive(Debug, Clone, Serialize, Deserialize)]
45pub struct CcHotId(pub String);
46
47#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
49pub struct Extended(pub bool);
50
51#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
53pub struct History(pub bool);
54
55#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
57pub struct IncludeNextEpoch(pub bool);
58
59#[derive(Debug, Clone, Serialize, Deserialize)]
61pub struct PoolBech32(pub String);
62
63#[derive(Debug, Clone, Serialize, Deserialize)]
65pub struct ScriptHash(pub String);
66
67#[derive(Debug, Clone, Serialize, Deserialize)]
69pub struct ProposalId(pub String);
70
71impl AfterBlockHeight {
74 pub fn new(height: u64) -> Self {
75 Self(height)
76 }
77
78 pub fn value(&self) -> u64 {
79 self.0
80 }
81}
82
83impl EpochNo {
84 pub fn new<S: Into<String>>(epoch: S) -> Self {
85 Self(epoch.into())
86 }
87
88 pub fn value(&self) -> &str {
89 &self.0
90 }
91}
92
93impl StakeAddress {
94 pub fn new<S: Into<String>>(address: S) -> Self {
95 Self(address.into())
96 }
97
98 pub fn value(&self) -> &str {
99 &self.0
100 }
101
102 pub fn validate(&self) -> bool {
104 self.0.starts_with("stake1")
105 }
106}
107
108impl TxHash {
109 pub fn new<S: Into<String>>(hash: S) -> Self {
110 Self(hash.into())
111 }
112
113 pub fn value(&self) -> &str {
114 &self.0
115 }
116
117 pub fn validate(&self) -> bool {
119 self.0.chars().all(|c| c.is_ascii_hexdigit())
120 }
121}
122
123impl AssetPolicy {
124 pub fn new<S: Into<String>>(policy: S) -> Self {
125 Self(policy.into())
126 }
127
128 pub fn value(&self) -> &str {
129 &self.0
130 }
131
132 pub fn validate(&self) -> bool {
134 self.0.chars().all(|c| c.is_ascii_hexdigit())
135 }
136}
137
138impl AssetName {
139 pub fn new<S: Into<String>>(name: S) -> Self {
140 Self(name.into())
141 }
142
143 pub fn value(&self) -> &str {
144 &self.0
145 }
146
147 pub fn validate(&self) -> bool {
149 self.0.chars().all(|c| c.is_ascii_hexdigit())
150 }
151}
152
153impl AssetPolicyNft {
154 pub fn new<S: Into<String>>(policy: S) -> Self {
155 Self(policy.into())
156 }
157
158 pub fn value(&self) -> &str {
159 &self.0
160 }
161
162 pub fn validate(&self) -> bool {
164 self.0.chars().all(|c| c.is_ascii_hexdigit())
165 }
166}
167
168impl AssetNameNft {
169 pub fn new<S: Into<String>>(name: S) -> Self {
170 Self(name.into())
171 }
172
173 pub fn value(&self) -> &str {
174 &self.0
175 }
176
177 pub fn validate(&self) -> bool {
179 self.0.chars().all(|c| c.is_ascii_hexdigit())
180 }
181}
182
183impl VoterId {
184 pub fn new<S: Into<String>>(voter_id: S) -> Self {
185 Self(voter_id.into())
186 }
187
188 pub fn value(&self) -> &str {
189 &self.0
190 }
191
192 pub fn validate(&self) -> bool {
194 self.0.starts_with("drep1") || self.0.starts_with("pool1") || self.0.starts_with("cc_hot1")
195 }
196}
197
198impl DrepId {
199 pub fn new<S: Into<String>>(drep_id: S) -> Self {
200 Self(drep_id.into())
201 }
202
203 pub fn value(&self) -> &str {
204 &self.0
205 }
206
207 pub fn validate(&self) -> bool {
209 self.0.starts_with("drep1")
210 }
211}
212
213impl CcHotId {
214 pub fn new<S: Into<String>>(cc_hot_id: S) -> Self {
215 Self(cc_hot_id.into())
216 }
217
218 pub fn value(&self) -> &str {
219 &self.0
220 }
221
222 pub fn validate(&self) -> bool {
224 self.0.starts_with("cc_hot1")
225 }
226}
227
228impl Extended {
229 pub fn new(extended: bool) -> Self {
230 Self(extended)
231 }
232
233 pub fn value(&self) -> bool {
234 self.0
235 }
236}
237
238impl History {
239 pub fn new(history: bool) -> Self {
240 Self(history)
241 }
242
243 pub fn value(&self) -> bool {
244 self.0
245 }
246}
247
248impl IncludeNextEpoch {
249 pub fn new(include: bool) -> Self {
250 Self(include)
251 }
252
253 pub fn value(&self) -> bool {
254 self.0
255 }
256}
257
258impl PoolBech32 {
259 pub fn new<S: Into<String>>(pool_id: S) -> Self {
260 Self(pool_id.into())
261 }
262
263 pub fn value(&self) -> &str {
264 &self.0
265 }
266
267 pub fn validate(&self) -> bool {
269 self.0.starts_with("pool1")
270 }
271}
272
273impl ScriptHash {
274 pub fn new<S: Into<String>>(hash: S) -> Self {
275 Self(hash.into())
276 }
277
278 pub fn value(&self) -> &str {
279 &self.0
280 }
281
282 pub fn validate(&self) -> bool {
284 self.0.chars().all(|c| c.is_ascii_hexdigit())
285 }
286}
287
288impl ProposalId {
289 pub fn new<S: Into<String>>(proposal_id: S) -> Self {
290 Self(proposal_id.into())
291 }
292
293 pub fn value(&self) -> &str {
294 &self.0
295 }
296
297 pub fn validate(&self) -> bool {
299 self.0.starts_with("gov_action1")
300 }
301}
302
303#[cfg(test)]
305mod tests {
306 use super::*;
307
308 #[test]
309 fn test_stake_address_validation() {
310 let valid =
311 StakeAddress::new("stake1u8yxtugdv63wxafy9d00nuz6hjyyp4qnggvc9a3vxh8yl0ckml2uz");
312 let invalid = StakeAddress::new("invalid_address");
313
314 assert!(valid.validate());
315 assert!(!invalid.validate());
316 }
317 #[test]
318 fn test_tx_hash_validation() {
319 let valid = TxHash::new("f144a8264acf4bdfe2e1241170969c930d64ab6b0996a4a45237b623f1dd670e");
320 let invalid = TxHash::new("invalid_hash!");
321
322 assert!(valid.validate());
323 assert!(!invalid.validate());
324 }
325
326 }