1use std::io::{self, Error, ErrorKind};
3
4use crate::{choices, codec::serde::hex_0x_utxo::Hex0xUtxo, ids, jsonrpc, txs};
5use serde::{Deserialize, Serialize};
6use serde_with::{serde_as, DisplayFromStr};
7
8#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)]
10pub struct IssueTxRequest {
11 pub jsonrpc: String,
12 pub id: u32,
13
14 pub method: String,
15
16 #[serde(skip_serializing_if = "Option::is_none")]
17 pub params: Option<IssueTxParams>,
18}
19
20impl Default for IssueTxRequest {
21 fn default() -> Self {
22 Self {
23 jsonrpc: String::from(super::DEFAULT_VERSION),
24 id: super::DEFAULT_ID,
25 method: String::new(),
26 params: None,
27 }
28 }
29}
30
31impl IssueTxRequest {
32 pub fn encode_json(&self) -> io::Result<String> {
33 serde_json::to_string(&self)
34 .map_err(|e| Error::new(ErrorKind::Other, format!("failed to serialize JSON {}", e)))
35 }
36}
37
38#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)]
39#[serde(rename_all = "camelCase")]
40pub struct IssueTxParams {
41 pub tx: String,
42 pub encoding: String,
43}
44
45#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)]
47pub struct IssueTxResponse {
48 pub jsonrpc: String,
49 pub id: u32,
50
51 #[serde(skip_serializing_if = "Option::is_none")]
52 pub result: Option<IssueTxResult>,
53
54 #[serde(skip_serializing_if = "Option::is_none")]
55 pub error: Option<super::ResponseError>,
56}
57
58impl Default for IssueTxResponse {
59 fn default() -> Self {
60 Self {
61 jsonrpc: "2.0".to_string(),
62 id: 1,
63 result: None,
64 error: None,
65 }
66 }
67}
68
69#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)]
71pub struct IssueTxResult {
72 #[serde(rename = "txID")]
73 pub tx_id: ids::Id,
74}
75
76impl Default for IssueTxResult {
77 fn default() -> Self {
78 Self {
79 tx_id: ids::Id::empty(),
80 }
81 }
82}
83
84#[test]
86fn test_issue_tx() {
87 use std::str::FromStr;
88
89 let resp: IssueTxResponse = serde_json::from_str(
90 "
91
92{
93 \"jsonrpc\": \"2.0\",
94 \"result\": {
95 \"txID\": \"G3BuH6ytQ2averrLxJJugjWZHTRubzCrUZEXoheG5JMqL5ccY\"
96 },
97 \"id\": 1
98}
99
100",
101 )
102 .unwrap();
103
104 let expected = IssueTxResponse {
105 jsonrpc: "2.0".to_string(),
106 id: 1,
107 result: Some(IssueTxResult {
108 tx_id: ids::Id::from_str("G3BuH6ytQ2averrLxJJugjWZHTRubzCrUZEXoheG5JMqL5ccY").unwrap(),
109 }),
110 error: None,
111 };
112 assert_eq!(resp, expected);
113}
114
115#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)]
117pub struct GetTxStatusResponse {
118 pub jsonrpc: String,
119 pub id: u32,
120
121 #[serde(skip_serializing_if = "Option::is_none")]
122 pub result: Option<GetTxStatusResult>,
123
124 #[serde(skip_serializing_if = "Option::is_none")]
125 pub error: Option<jsonrpc::ResponseError>,
126}
127
128impl Default for GetTxStatusResponse {
129 fn default() -> Self {
130 Self {
131 jsonrpc: "2.0".to_string(),
132 id: 1,
133 result: Some(GetTxStatusResult::default()),
134 error: None,
135 }
136 }
137}
138
139#[serde_as]
141#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)]
142pub struct GetTxStatusResult {
143 #[serde_as(as = "DisplayFromStr")]
144 pub status: choices::status::Status,
145}
146
147impl Default for GetTxStatusResult {
148 fn default() -> Self {
149 Self {
150 status: choices::status::Status::Unknown(String::new()),
151 }
152 }
153}
154
155#[test]
157fn test_get_tx_status() {
158 let resp: GetTxStatusResponse = serde_json::from_str(
160 "
161
162{
163 \"jsonrpc\": \"2.0\",
164 \"result\": {
165 \"status\": \"Accepted\"
166 },
167 \"id\": 1
168}
169
170",
171 )
172 .unwrap();
173
174 let expected = GetTxStatusResponse {
175 jsonrpc: "2.0".to_string(),
176 id: 1,
177 result: Some(GetTxStatusResult {
178 status: choices::status::Status::Accepted,
179 }),
180 error: None,
181 };
182 assert_eq!(resp, expected);
183}
184
185#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)]
187pub struct GetUtxosRequest {
188 pub jsonrpc: String,
189 pub id: u32,
190
191 pub method: String,
192
193 #[serde(skip_serializing_if = "Option::is_none")]
194 pub params: Option<GetUtxosParams>,
195}
196
197impl Default for GetUtxosRequest {
198 fn default() -> Self {
199 Self {
200 jsonrpc: String::from(super::DEFAULT_VERSION),
201 id: super::DEFAULT_ID,
202 method: String::new(),
203 params: None,
204 }
205 }
206}
207
208impl GetUtxosRequest {
209 pub fn encode_json(&self) -> io::Result<String> {
210 serde_json::to_string(&self)
211 .map_err(|e| Error::new(ErrorKind::Other, format!("failed to serialize JSON {}", e)))
212 }
213}
214
215#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)]
217#[serde(rename_all = "camelCase")]
218pub struct GetUtxosParams {
219 pub addresses: Vec<String>,
220 pub limit: u32,
221 pub encoding: String,
222}
223
224#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)]
226pub struct GetUtxosResponse {
227 pub jsonrpc: String,
228 pub id: u32,
229
230 #[serde(skip_serializing_if = "Option::is_none")]
231 pub result: Option<GetUtxosResult>,
232
233 #[serde(skip_serializing_if = "Option::is_none")]
234 pub error: Option<super::ResponseError>,
235}
236
237#[serde_as]
239#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)]
240#[serde(rename_all = "camelCase")]
241#[derive(Default)]
242pub struct GetUtxosResult {
243 #[serde_as(as = "DisplayFromStr")]
244 pub num_fetched: u32,
245
246 #[serde_as(as = "Option<Vec<Hex0xUtxo>>")]
247 #[serde(skip_serializing_if = "Option::is_none")]
248 pub utxos: Option<Vec<txs::utxo::Utxo>>,
249
250 #[serde(skip_serializing_if = "Option::is_none")]
251 pub end_index: Option<super::EndIndex>,
252 #[serde(skip_serializing_if = "Option::is_none")]
253 pub encoding: Option<String>,
254}
255
256#[test]
258fn test_get_utxos_empty() {
259 let resp: GetUtxosResponse = serde_json::from_str(
261 "
262
263{
264 \"jsonrpc\": \"2.0\",
265 \"result\": {
266 \"numFetched\": \"0\",
267 \"utxos\": [],
268 \"endIndex\": {
269 \"address\": \"P-custom152qlr6zunz7nw2kc4lfej3cn3wk46u3002k4w5\",
270 \"utxo\": \"11111111111111111111111111111111LpoYY\"
271 },
272 \"encoding\":\"hex\"
273 },
274 \"id\": 1
275}
276
277",
278 )
279 .unwrap();
280
281 let expected = GetUtxosResponse {
282 jsonrpc: "2.0".to_string(),
283 id: 1,
284 result: Some(GetUtxosResult {
285 num_fetched: 0,
286 utxos: Some(Vec::new()),
287 end_index: Some(super::EndIndex {
288 address: String::from("P-custom152qlr6zunz7nw2kc4lfej3cn3wk46u3002k4w5"),
289 utxo: String::from("11111111111111111111111111111111LpoYY"),
290 }),
291 encoding: Some(String::from("hex")),
292 }),
293 error: None,
294 };
295 assert_eq!(resp, expected);
296}
297
298#[test]
300fn test_get_utxos_non_empty() {
301 let resp: GetUtxosResponse = serde_json::from_str(
303 "
304
305{
306 \"jsonrpc\": \"2.0\",
307 \"result\": {
308 \"numFetched\": \"1\",
309 \"utxos\": [
310 \"0x000000000000000000000000000000000000000000000000000000000000000000000000000088eec2e099c6a528e689618e8721e04ae85ea574c7a15a7968644d14d54780140000000702c68af0bb1400000000000000000000000000010000000165844a05405f3662c1928142c6c2a783ef871de939b564db\"
311 ],
312 \"endIndex\": {
313 \"address\": \"X-avax1x459sj0ssujguq723cljfty4jlae28evjzt7xz\",
314 \"utxo\": \"LUC1cmcxnfNR9LdkACS2ccGKLEK7SYqB4gLLTycQfg1koyfSq\"
315 },
316 \"encoding\": \"hex\"
317 },
318 \"id\": 1
319}
320
321",
322 )
323 .unwrap();
324
325 let raw_utxo = String::from("0x000000000000000000000000000000000000000000000000000000000000000000000000000088eec2e099c6a528e689618e8721e04ae85ea574c7a15a7968644d14d54780140000000702c68af0bb1400000000000000000000000000010000000165844a05405f3662c1928142c6c2a783ef871de939b564db");
326 let utxo = txs::utxo::Utxo::from_hex(&raw_utxo).unwrap();
327
328 let expected = GetUtxosResponse {
329 jsonrpc: "2.0".to_string(),
330 id: 1,
331 result: Some(GetUtxosResult {
332 num_fetched: 1,
333 utxos: Some(vec![utxo]),
334 end_index: Some(super::EndIndex {
335 address: String::from("X-avax1x459sj0ssujguq723cljfty4jlae28evjzt7xz"),
336 utxo: String::from("LUC1cmcxnfNR9LdkACS2ccGKLEK7SYqB4gLLTycQfg1koyfSq"),
337 }),
338 encoding: Some(String::from("hex")),
339 }),
340 error: None,
341 };
342 assert_eq!(resp, expected);
343}
344
345#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)]
347pub struct GetBalanceResponse {
348 pub jsonrpc: String,
349 pub id: u32,
350
351 #[serde(skip_serializing_if = "Option::is_none")]
352 pub result: Option<GetBalanceResult>,
353
354 #[serde(skip_serializing_if = "Option::is_none")]
355 pub error: Option<jsonrpc::ResponseError>,
356}
357
358#[serde_as]
360#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone, Default)]
361pub struct GetBalanceResult {
362 #[serde_as(as = "DisplayFromStr")]
363 pub balance: u64,
364
365 #[serde(rename = "utxoIDs")]
366 pub utxo_ids: Option<Vec<txs::utxo::Id>>,
367}
368
369#[test]
371fn test_get_balance() {
372 use std::str::FromStr;
373
374 let resp: GetBalanceResponse = serde_json::from_str(
376 "
377
378{
379 \"jsonrpc\": \"2.0\",
380 \"result\": {
381 \"balance\": \"299999999999900\",
382 \"utxoIDs\": [
383 {
384 \"txID\": \"WPQdyLNqHfiEKp4zcCpayRHYDVYuh1hqs9c1RqgZXS4VPgdvo\",
385 \"outputIndex\": 1
386 }
387 ]
388 },
389 \"id\": 1
390}
391
392",
393 )
394 .unwrap();
395
396 let expected = GetBalanceResponse {
397 jsonrpc: "2.0".to_string(),
398 id: 1,
399 result: Some(GetBalanceResult {
400 balance: 299999999999900,
401 utxo_ids: Some(vec![txs::utxo::Id {
402 tx_id: ids::Id::from_str("WPQdyLNqHfiEKp4zcCpayRHYDVYuh1hqs9c1RqgZXS4VPgdvo")
403 .unwrap(),
404 output_index: 1,
405 ..txs::utxo::Id::default()
406 }]),
407 }),
408 error: None,
409 };
410 assert_eq!(resp, expected);
411}
412
413#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)]
415pub struct GetAssetDescriptionResponse {
416 pub jsonrpc: String,
417 pub id: u32,
418
419 #[serde(skip_serializing_if = "Option::is_none")]
420 pub result: Option<GetAssetDescriptionResult>,
421
422 #[serde(skip_serializing_if = "Option::is_none")]
423 pub error: Option<jsonrpc::ResponseError>,
424}
425
426#[serde_as]
428#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone, Default)]
429pub struct GetAssetDescriptionResult {
430 #[serde(rename = "assetID")]
431 pub asset_id: ids::Id,
432
433 pub name: String,
434 pub symbol: String,
435
436 #[serde_as(as = "DisplayFromStr")]
437 pub denomination: usize,
438}
439
440#[test]
442fn test_get_asset_description() {
443 use std::str::FromStr;
444
445 let resp: GetAssetDescriptionResponse = serde_json::from_str(
447 "
448
449{
450 \"jsonrpc\": \"2.0\",
451 \"result\": {
452 \"assetID\": \"2fombhL7aGPwj3KH4bfrmJwW6PVnMobf9Y2fn9GwxiAAJyFDbe\",
453 \"name\": \"Avalanche\",
454 \"symbol\": \"AVAX\",
455 \"denomination\": \"9\"
456 },
457 \"id\": 1
458}
459
460",
461 )
462 .unwrap();
463
464 let expected = GetAssetDescriptionResponse {
465 jsonrpc: "2.0".to_string(),
466 id: 1,
467 result: Some(GetAssetDescriptionResult {
468 asset_id: ids::Id::from_str("2fombhL7aGPwj3KH4bfrmJwW6PVnMobf9Y2fn9GwxiAAJyFDbe")
469 .unwrap(),
470 name: String::from("Avalanche"),
471 symbol: String::from("AVAX"),
472 denomination: 9,
473 }),
474 error: None,
475 };
476 assert_eq!(resp, expected);
477}
478
479#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)]
481pub struct IssueStopVertexRequest {
482 pub jsonrpc: String,
483 pub id: u32,
484
485 pub method: String,
486
487 #[serde(skip_serializing_if = "Option::is_none")]
488 pub params: Option<IssueStopVertexParams>,
489}
490
491impl Default for IssueStopVertexRequest {
492 fn default() -> Self {
493 Self {
494 jsonrpc: String::from(super::DEFAULT_VERSION),
495 id: super::DEFAULT_ID,
496 method: String::new(),
497 params: None,
498 }
499 }
500}
501
502impl IssueStopVertexRequest {
503 pub fn encode_json(&self) -> io::Result<String> {
504 serde_json::to_string(&self)
505 .map_err(|e| Error::new(ErrorKind::Other, format!("failed to serialize JSON {}", e)))
506 }
507}
508
509#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)]
510#[serde(rename_all = "camelCase")]
511pub struct IssueStopVertexParams;