1use chrono::{DateTime, Duration, Utc};
2use secrecy::{DebugSecret, Secret, SerializableSecret};
3use serde::{Deserialize, Deserializer, Serialize, Serializer};
4use zeroize::Zeroize;
5
6#[derive(Debug, Serialize)]
8pub struct TokenRequest {
9 pub username: String,
10 pub password: String,
11}
12
13#[derive(Debug, Deserialize)]
15pub struct TokenResponse {
16 pub token: String,
17}
18
19#[derive(Clone, Serialize, Deserialize)]
20pub struct Password(pub String);
21
22impl Zeroize for Password {
23 fn zeroize(&mut self) {
24 self.0.zeroize();
25 }
26}
27
28impl From<String> for Password {
29 fn from(s: String) -> Self {
30 Self(s)
31 }
32}
33
34impl SerializableSecret for Password {}
35
36impl DebugSecret for Password {}
37
38#[derive(Debug, Serialize)]
39pub struct ChangePasswordRequest {
40 pub password: Secret<Password>,
41}
42
43#[derive(Debug, Deserialize)]
44pub struct ChangePasswordResponse {
45 pub username: String,
46 pub password: Secret<Password>,
47 pub token: Secret<String>,
48}
49
50#[derive(Debug, Deserialize)]
51#[allow(clippy::struct_excessive_bools)]
52pub struct Asset {
53 pub name: String,
54 pub asset_uuid: String,
55 pub issuer: i64,
56 pub asset_id: String,
57 pub reissuance_token_id: Option<String>,
58 pub requirements: Vec<i64>,
59 pub ticker: Option<String>,
60 pub precision: i64,
61 pub domain: Option<String>,
62 pub pubkey: Option<String>,
63 pub is_registered: bool,
64 pub is_authorized: bool,
65 pub is_locked: bool,
66 pub issuer_authorization_endpoint: Option<String>,
67 pub transfer_restricted: bool,
68}
69
70#[derive(Debug, Serialize)]
71pub struct IssuanceRequest {
72 pub name: String,
73 pub amount: i64,
74 pub destination_address: String,
75 pub domain: String,
76 pub ticker: String,
77 pub pubkey: String,
78 #[serde(skip_serializing_if = "Option::is_none")]
79 pub precision: Option<i64>,
80 #[serde(skip_serializing_if = "Option::is_none")]
81 pub is_confidential: Option<bool>,
82 #[serde(skip_serializing_if = "Option::is_none")]
83 pub is_reissuable: Option<bool>,
84 #[serde(skip_serializing_if = "Option::is_none")]
85 pub reissuance_amount: Option<i64>,
86 #[serde(skip_serializing_if = "Option::is_none")]
87 pub reissuance_address: Option<String>,
88 #[serde(skip_serializing_if = "Option::is_none")]
89 pub transfer_restricted: Option<bool>,
90}
91
92#[derive(Debug, Deserialize)]
93pub struct IssuanceResponse {
94 pub name: String,
95 pub amount: i64,
96 pub destination_address: String,
97 pub domain: String,
98 pub ticker: String,
99 pub pubkey: String,
100 pub is_confidential: bool,
101 pub is_reissuable: bool,
102 pub reissuance_amount: i64,
103 pub reissuance_address: String,
104 pub asset_id: String,
105 pub reissuance_token_id: Option<String>,
106 pub asset_uuid: String,
107 pub txid: String,
108 pub vin: i64,
109 pub asset_vout: i64,
110 pub reissuance_vout: Option<i64>,
111 pub issuer_authorization_endpoint: Option<String>,
112 pub transfer_restricted: bool,
113 pub issuance_assetblinder: String,
114 pub issuance_tokenblinder: Option<String>,
115}
116
117#[derive(Debug, Serialize)]
118pub struct EditAssetRequest {
119 pub issuer_authorization_endpoint: String,
120}
121
122#[derive(Debug, Deserialize)]
123pub struct RegisteredUserResponse {
124 pub id: i64,
125 #[serde(rename = "GAID")]
126 pub gaid: Option<String>,
127 pub is_company: bool,
128 pub name: String,
129 pub categories: Vec<i64>,
130 pub creator: i64,
131}
132
133#[derive(Debug, Serialize)]
134pub struct RegisteredUserAdd {
135 pub name: String,
136 #[serde(rename = "GAID")]
137 pub gaid: Option<String>,
138 pub is_company: bool,
139}
140
141#[derive(Debug, Serialize)]
142pub struct RegisteredUserEdit {
143 pub name: Option<String>,
144}
145
146#[derive(Debug, Serialize)]
147pub struct GaidRequest {
148 pub gaid: String,
149}
150
151#[derive(Debug, Serialize)]
152pub struct CategoriesRequest {
153 pub categories: Vec<i64>,
154}
155
156#[derive(Debug, Deserialize)]
157pub struct CategoryResponse {
158 pub id: i64,
159 pub name: String,
160 pub description: Option<String>,
161 pub registered_users: Vec<i64>,
162 pub assets: Vec<String>,
163}
164
165#[derive(Debug, Serialize)]
166pub struct CategoryAdd {
167 pub name: String,
168 pub description: Option<String>,
169}
170
171#[derive(Debug, Serialize)]
172pub struct CategoryEdit {
173 pub name: Option<String>,
174 pub description: Option<String>,
175}
176
177#[derive(Debug, Deserialize)]
178pub struct ValidateGaidResponse {
179 pub is_valid: bool,
180 pub error: Option<String>,
181}
182
183#[derive(Debug, Deserialize)]
184pub struct AddressGaidResponse {
185 pub address: String,
186 pub error: Option<String>,
187}
188
189#[derive(Debug, Deserialize)]
190pub struct Manager {
191 pub username: String,
192 pub id: i64,
193 pub is_locked: bool,
194 pub assets: Vec<String>,
195}
196
197#[derive(Debug, Serialize)]
198pub struct ManagerCreate {
199 pub username: String,
200 pub password: String,
201}
202
203#[derive(Debug, Deserialize, Serialize)]
204#[serde(rename_all = "UPPERCASE")]
205pub enum Status {
206 Unconfirmed,
207 Confirmed,
208}
209
210#[derive(Debug, Deserialize, Serialize)]
211pub struct DistributionAssignment {
212 pub registered_user: i64,
213 pub amount: i64,
214 pub vout: i64,
215}
216
217#[derive(Debug, Deserialize, Serialize)]
218pub struct Transaction {
219 pub txid: String,
220 pub transaction_status: Status,
221 pub included_blockheight: i64,
222 pub confirmed_datetime: String,
223 pub assignments: Vec<DistributionAssignment>,
224}
225
226#[derive(Debug, Deserialize, Serialize)]
227pub struct Distribution {
228 pub distribution_uuid: String,
229 pub distribution_status: Status,
230 pub transactions: Vec<Transaction>,
231}
232
233#[derive(Debug, Serialize, Deserialize, Clone)]
234pub struct CreateAssetAssignmentRequest {
235 pub registered_user: i64,
236 pub amount: i64,
237 #[serde(skip_serializing_if = "Option::is_none")]
238 pub vesting_timestamp: Option<i64>, #[serde(default = "default_ready_for_distribution")]
240 pub ready_for_distribution: bool, }
242
243const fn default_ready_for_distribution() -> bool {
244 false
245}
246
247#[derive(Debug, Serialize)]
248pub struct CreateAssetAssignmentRequestWrapper {
249 pub assignments: Vec<CreateAssetAssignmentRequest>,
250}
251
252#[derive(Debug, Deserialize, Serialize)]
253pub struct Assignment {
254 pub id: i64,
255 pub registered_user: i64,
256 pub amount: i64,
257 pub receiving_address: Option<String>,
258 pub distribution_uuid: Option<String>,
259 pub ready_for_distribution: bool,
260 pub vesting_datetime: Option<String>,
261 pub vesting_timestamp: Option<i64>,
262 pub has_vested: bool,
263 pub is_distributed: bool,
264 pub creator: i64,
265 #[serde(rename = "GAID")]
266 pub gaid: Option<String>,
267 #[serde(skip_serializing_if = "Option::is_none")]
269 pub investor: Option<i64>,
270}
271
272#[derive(Debug, Deserialize, Serialize)]
273pub struct RegisteredUserSummary {
274 pub asset_uuid: String,
275 pub asset_id: String,
276 pub assignments: Vec<Assignment>,
277 pub assignments_sum: i64,
278 pub distributions: Vec<Distribution>,
279 pub distributions_sum: i64,
280 pub balance: i64,
281}
282
283#[derive(Debug, Deserialize, Serialize)]
284pub struct Activity {
285 #[serde(rename = "type")]
286 pub activity_type: String,
287 pub datetime: String,
288 pub description: String,
289 pub txid: String,
290 pub vout: i64,
291 pub blockheight: i64,
292 pub asset_blinder: String,
293 pub amount_blinder: String,
294 #[serde(rename = "registered user")]
295 pub registered_user: Option<i64>,
296 pub amount: i64,
297}
298
299#[derive(Debug, Serialize, Default)]
300pub struct AssetActivityParams {
301 #[serde(skip_serializing_if = "Option::is_none")]
302 pub start: Option<i64>,
303 #[serde(skip_serializing_if = "Option::is_none")]
304 pub count: Option<i64>,
305 #[serde(skip_serializing_if = "Option::is_none")]
306 pub sortcolumn: Option<String>,
307 #[serde(skip_serializing_if = "Option::is_none")]
308 pub sortorder: Option<String>,
309 #[serde(skip_serializing_if = "Option::is_none")]
310 pub height_start: Option<i64>,
311 #[serde(skip_serializing_if = "Option::is_none")]
312 pub height_stop: Option<i64>,
313}
314
315#[derive(Debug, Deserialize, Serialize)]
316pub struct Ownership {
317 pub owner: String,
318 pub amount: i64,
319 #[serde(rename = "GAID")]
320 pub gaid: Option<String>,
321}
322
323#[derive(Debug, Deserialize, Serialize)]
324pub struct Outpoint {
325 pub txid: String,
326 pub vout: i64,
327}
328
329pub type LostOutputs = Vec<Outpoint>;
330
331#[derive(Debug, Deserialize, Serialize)]
332pub struct GaidBalanceEntry {
333 pub asset_uuid: String,
334 pub asset_id: String,
335 pub balance: i64,
336}
337
338pub type Balance = Vec<GaidBalanceEntry>;
339
340#[derive(Debug, Deserialize, Serialize)]
341pub struct AssetLostOutputs {
342 pub lost_outputs: LostOutputs,
343 pub reissuance_lost_outputs: LostOutputs,
344}
345
346#[derive(Debug, Deserialize, Serialize)]
347pub struct AssetSummary {
348 pub asset_id: String,
349 pub reissuance_token_id: Option<String>,
350 pub issued: i64,
351 pub reissued: i64,
352 pub assigned: i64,
353 pub distributed: i64,
354 pub burned: i64,
355 pub blacklisted: i64,
356 pub registered_users: i64,
357 pub active_registered_users: i64,
358 pub active_green_subaccounts: i64,
359 #[serde(rename = "reissuance_tokens")]
360 pub reissuance_tokens: i64,
361}
362
363#[derive(Debug, Deserialize, Serialize)]
364pub struct Utxo {
365 pub txid: String,
366 pub vout: i64,
367 pub asset: String,
368 pub amount: i64,
369 pub registered_user: Option<i64>,
370 pub gaid: Option<String>,
371 pub blacklisted: bool,
372}
373
374#[derive(Debug, Deserialize, Serialize)]
375pub struct Reissuance {
376 pub txid: String,
377 pub vout: i64,
378 pub destination_address: String,
379 pub reissuance_amount: i64,
380 pub confirmed_in_block: String,
381 pub created: String,
382}
383
384#[derive(Debug, Serialize)]
385pub struct ReissueRequest {
386 pub amount_to_reissue: i64,
387}
388
389#[derive(Debug, Serialize)]
390pub struct ReissueConfirmRequest {
391 pub details: serde_json::Value,
392 pub listissuances: Vec<serde_json::Value>,
393 pub reissuance_output: serde_json::Value,
394}
395
396#[derive(Debug, Serialize)]
397pub struct BurnRequest {
398 pub amount: i64,
399}
400
401#[derive(Debug, Deserialize, Serialize)]
402pub struct BurnCreate {
403 pub command: String,
404 pub min_supported_client_script_version: i64,
405 pub base_url: String,
406 pub asset_uuid: String,
407 pub asset_id: String,
408 pub amount: f64,
409 pub utxos: Vec<Outpoint>,
410}
411
412#[derive(Debug, Serialize)]
413pub struct BurnConfirmRequest {
414 pub tx_data: serde_json::Value,
415 pub change_data: Vec<serde_json::Value>,
416}
417
418#[derive(Debug, Serialize)]
419pub struct SetAssetMemoRequest {
420 pub memo: String,
421}
422
423#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
424#[serde(rename_all = "lowercase")]
425pub enum Permission {
426 View,
427 Receive,
428 Transfer,
429 Assign,
430 Distribute,
431 Reissue,
432 Burn,
433 Acquire,
434 Manage,
435 Permissions,
436}
437
438#[derive(Debug, Deserialize, Serialize)]
439pub struct BroadcastResponse {
440 pub txid: String,
441 pub hex: String,
442}
443
444#[derive(Debug, Clone, Serialize, Deserialize)]
446pub struct TokenData {
447 #[serde(with = "secret_serde")]
448 pub token: Secret<String>,
449 pub expires_at: DateTime<Utc>,
450 pub obtained_at: DateTime<Utc>,
451}
452
453impl TokenData {
454 #[must_use]
465 pub fn new(token: String, expires_at: DateTime<Utc>) -> Self {
466 Self {
467 token: Secret::new(token),
468 expires_at,
469 obtained_at: Utc::now(),
470 }
471 }
472
473 #[must_use]
490 pub fn is_expired(&self) -> bool {
491 Utc::now() > self.expires_at
492 }
493
494 #[must_use]
511 pub fn expires_soon(&self, threshold: Duration) -> bool {
512 Utc::now() + threshold > self.expires_at
513 }
514
515 #[must_use]
529 pub fn age(&self) -> Duration {
530 Utc::now() - self.obtained_at
531 }
532}
533
534#[derive(Debug, Clone)]
536pub struct TokenInfo {
537 pub expires_at: DateTime<Utc>,
538 pub obtained_at: DateTime<Utc>,
539 pub expires_in: Duration,
540 pub age: Duration,
541 pub is_expired: bool,
542 pub expires_soon: bool,
543}
544
545impl From<&TokenData> for TokenInfo {
546 fn from(token_data: &TokenData) -> Self {
547 let now = Utc::now();
548 let expires_in = token_data.expires_at - now;
549 let expires_soon_threshold = Duration::minutes(5);
550
551 Self {
552 expires_at: token_data.expires_at,
553 obtained_at: token_data.obtained_at,
554 expires_in,
555 age: token_data.age(),
556 is_expired: token_data.is_expired(),
557 expires_soon: token_data.expires_soon(expires_soon_threshold),
558 }
559 }
560}
561
562pub mod secret_serde {
564 use super::{Deserialize, Deserializer, Secret, Serialize, Serializer};
565
566 pub fn serialize<S>(secret: &Secret<String>, serializer: S) -> Result<S::Ok, S::Error>
569 where
570 S: Serializer,
571 {
572 use secrecy::ExposeSecret;
573 secret.expose_secret().serialize(serializer)
574 }
575
576 pub fn deserialize<'de, D>(deserializer: D) -> Result<Secret<String>, D::Error>
579 where
580 D: Deserializer<'de>,
581 {
582 let s = String::deserialize(deserializer)?;
583 Ok(Secret::new(s))
584 }
585}