1use std::{
2 cmp::Ordering,
3 str::{Chars, FromStr},
4};
5
6use crate::claimant::ClaimantBehavior;
7use crate::keypair::Keypair;
8use crate::xdr;
9use stellar_strkey::{
10 ed25519,
11 Strkey::{self, PublicKeyEd25519},
12};
13
14#[derive(Debug, Clone, PartialEq, Eq)]
15pub struct Asset {
16 pub code: String,
17 pub issuer: Option<String>,
18}
19impl From<&Asset> for xdr::TrustLineAsset {
20 fn from(value: &Asset) -> Self {
21 value.to_trust_line_xdr_object()
22 }
23}
24impl From<Asset> for xdr::TrustLineAsset {
25 fn from(value: Asset) -> Self {
26 value.to_trust_line_xdr_object()
27 }
28}
29impl From<&Asset> for xdr::ChangeTrustAsset {
30 fn from(value: &Asset) -> Self {
31 value.to_change_trust_xdr_object()
32 }
33}
34impl From<Asset> for xdr::ChangeTrustAsset {
35 fn from(value: Asset) -> Self {
36 value.to_change_trust_xdr_object()
37 }
38}
39
40pub trait AssetBehavior {
42 fn new(code: &str, issuer: Option<&str>) -> Result<Self, String>
43 where
44 Self: Sized;
45 fn from_operation(asset_xdr: xdr::Asset) -> Result<Self, String>
46 where
47 Self: Sized;
48 fn to_xdr_object(&self) -> xdr::Asset;
49 fn to_change_trust_xdr_object(&self) -> xdr::ChangeTrustAsset;
50 fn to_trust_line_xdr_object(&self) -> xdr::TrustLineAsset;
51 fn ascii_compare(a: &str, b: &str) -> i32;
52 fn native() -> Self
53 where
54 Self: Sized;
55 fn is_native(&self) -> bool;
56 fn compare(asset_a: &Self, asset_b: &Self) -> i32
57 where
58 Self: Sized;
59 fn get_asset_type(&self) -> String;
60 fn get_raw_asset_type(&self) -> Result<xdr::AssetType, String>;
61 fn equals(&self, asset: &Self) -> bool;
62 fn get_code(&self) -> Option<String>;
63 fn get_issuer(&self) -> Option<String>;
64 fn to_string_asset(&self) -> String;
65}
66
67impl AssetBehavior for Asset {
68 fn new(code: &str, issuer: Option<&str>) -> Result<Self, String> {
69 if code.is_empty() || code.len() > 12 || !code.chars().all(|c| c.is_ascii_alphanumeric()) {
70 return Err(
71 "Asset code is invalid (maximum alphanumeric, 12 characters at max)".to_string(),
72 );
73 }
74
75 if code.to_lowercase() != "xlm" && issuer.is_none() {
76 return Err("Issuer cannot be null".to_string());
77 }
78
79 if let Some(issuer) = issuer {
80 if Strkey::from_str(issuer).is_err() {
81 return Err("Not a valid ed25519 public key".to_string());
82 }
83 }
84
85 let code = if code.to_lowercase() == "xlm" {
86 "XLM".to_string()
87 } else {
88 code.to_string()
89 };
90
91 Ok(Self {
92 code,
93 issuer: issuer.map(String::from),
94 })
95 }
96
97 fn from_operation(asset_xdr: xdr::Asset) -> Result<Asset, String> {
98 match asset_xdr {
99 xdr::Asset::Native => Ok(Asset::native()),
100 xdr::Asset::CreditAlphanum4(alpha_num_4) => {
101 let issuer = alpha_num_4.issuer.to_string();
102 let code = alpha_num_4.asset_code.to_string();
103 Ok(Asset::new(&code, Some(&issuer))?)
104 }
105 xdr::Asset::CreditAlphanum12(alpha_num_12) => {
106 let issuer = alpha_num_12.issuer.to_string();
107 let code = alpha_num_12.asset_code.to_string();
108 Ok(Asset::new(&code, Some(&issuer))?)
109 }
110 _ => Err(format!("Invalid asset type: {:?}", asset_xdr)),
111 }
112 }
113
114 fn to_trust_line_xdr_object(&self) -> xdr::TrustLineAsset {
115 if self.is_native() {
116 xdr::TrustLineAsset::Native
117 } else if self.code.len() <= 4 {
118 let asset_code = xdr::AssetCode4::from_str(&self.code).expect("Asset code is invalid");
119 let issuer = xdr::AccountId::from_str(
120 &self
121 .issuer
122 .clone()
123 .expect("Issuer is None while not native"),
124 )
125 .expect("Issuer is invalid");
126
127 xdr::TrustLineAsset::CreditAlphanum4(xdr::AlphaNum4 { asset_code, issuer })
128 } else {
129 let asset_code = xdr::AssetCode12::from_str(&self.code).expect("Asset code is invalid");
130 let issuer = xdr::AccountId::from_str(
131 &self
132 .issuer
133 .clone()
134 .expect("Issuer is None while not native"),
135 )
136 .expect("Issuer is invalid");
137
138 xdr::TrustLineAsset::CreditAlphanum12(xdr::AlphaNum12 { asset_code, issuer })
139 }
140 }
141
142 fn to_change_trust_xdr_object(&self) -> xdr::ChangeTrustAsset {
143 if self.is_native() {
144 xdr::ChangeTrustAsset::Native
145 } else if self.code.len() <= 4 {
146 let asset_code = xdr::AssetCode4::from_str(&self.code).expect("Asset code is invalid");
147 let issuer = xdr::AccountId::from_str(
148 &self
149 .issuer
150 .clone()
151 .expect("Issuer is None while not native"),
152 )
153 .expect("Issuer is invalid");
154 xdr::ChangeTrustAsset::CreditAlphanum4(xdr::AlphaNum4 { asset_code, issuer })
155 } else {
156 let asset_code = xdr::AssetCode12::from_str(&self.code).expect("Asset code is invalid");
157 let issuer = xdr::AccountId::from_str(
158 &self
159 .issuer
160 .clone()
161 .expect("Issuer is None while not native"),
162 )
163 .expect("Issuer is invalid");
164 xdr::ChangeTrustAsset::CreditAlphanum12(xdr::AlphaNum12 { asset_code, issuer })
165 }
166 }
167
168 fn to_xdr_object(&self) -> xdr::Asset {
169 if self.is_native() {
170 xdr::Asset::Native
171 } else if self.code.len() <= 4 {
172 let asset_code = xdr::AssetCode4::from_str(&self.code).expect("Asset code is invalid");
173 let issuer = xdr::AccountId::from_str(
174 &self
175 .issuer
176 .clone()
177 .expect("Issuer is None while not native"),
178 )
179 .expect("Issuer is invalid");
180 xdr::Asset::CreditAlphanum4(xdr::AlphaNum4 { asset_code, issuer })
181 } else {
182 let asset_code = xdr::AssetCode12::from_str(&self.code).expect("Asset code is invalid");
183 let issuer = xdr::AccountId::from_str(
184 &self
185 .issuer
186 .clone()
187 .expect("Issuer is None while not native"),
188 )
189 .expect("Issuer is invalid");
190 xdr::Asset::CreditAlphanum12(xdr::AlphaNum12 { asset_code, issuer })
191 }
192 }
193
194 fn ascii_compare(a: &str, b: &str) -> i32 {
195 let result = a.as_bytes().cmp(b.as_bytes());
196 match result {
197 Ordering::Less => -1,
198 Ordering::Equal => 0,
199 Ordering::Greater => 1,
200 }
201 }
202
203 fn native() -> Self {
204 Self {
206 code: "XLM".to_string(),
207 issuer: None,
208 }
209 }
210
211 fn is_native(&self) -> bool {
212 self.issuer.is_none()
213 }
214
215 fn compare(asset_a: &Asset, asset_b: &Asset) -> i32 {
216 if asset_a.equals(asset_b) {
217 return 0;
218 }
219
220 let xdr_a_type = asset_a.get_raw_asset_type();
221 let xdr_b_type = asset_b.get_raw_asset_type();
222
223 if xdr_a_type != xdr_b_type {
224 let result = xdr_a_type.cmp(&xdr_b_type);
225 if result == Ordering::Less {
226 return -1;
227 } else {
228 return 1;
229 }
230 }
231
232 let code_compare = Self::ascii_compare(
233 &asset_a.get_code().unwrap_or("".to_owned()),
234 &asset_b.get_code().unwrap_or("".to_owned()),
235 );
236 if code_compare != 0 {
237 return code_compare;
238 }
239
240 Self::ascii_compare(
241 &asset_a.get_issuer().unwrap_or("".to_owned()),
242 &asset_b.get_issuer().unwrap_or("".to_owned()),
243 )
244 }
245
246 fn get_asset_type(&self) -> String {
247 match self.get_raw_asset_type() {
248 Ok(xdr::AssetType::Native) => "native".to_string(),
249 Ok(xdr::AssetType::CreditAlphanum4) => "credit_alphanum4".to_string(),
250 Ok(xdr::AssetType::CreditAlphanum12) => "credit_alphanum12".to_string(),
251 _ => "unknown".to_string(),
252 }
253 }
254
255 fn get_raw_asset_type(&self) -> Result<xdr::AssetType, String> {
256 if self.is_native() {
257 Ok(xdr::AssetType::Native)
258 } else if self.code.len() <= 4 {
259 Ok(xdr::AssetType::CreditAlphanum4)
260 } else {
261 Ok(xdr::AssetType::CreditAlphanum12)
262 }
263 }
264
265 fn equals(&self, asset: &Asset) -> bool {
266 self.get_code() == asset.get_code() && self.get_issuer() == asset.get_issuer()
267 }
268
269 fn get_code(&self) -> Option<String> {
270 Some(self.code.clone())
271 }
272
273 fn get_issuer(&self) -> Option<String> {
274 self.issuer.clone()
275 }
276
277 fn to_string_asset(&self) -> String {
278 if self.is_native() {
279 return "native".to_string();
280 }
281
282 match (self.get_code(), self.get_issuer()) {
283 (Some(code), Some(issuer)) => format!("{}:{}", code, issuer),
284 _ => "".to_string(),
285 }
286 }
287}
288
289impl ToString for Asset {
290 fn to_string(&self) -> String {
291 if self.is_native() {
292 return "native".to_string();
293 }
294
295 match (self.get_code(), self.get_issuer()) {
296 (Some(code), Some(issuer)) => format!("{}:{}", code, issuer),
297 _ => "".to_string(),
298 }
299 }
300}
301
302#[cfg(test)]
303mod tests {
304 use crate::xdr::WriteXdr as _;
305
306 use super::Asset;
307 use crate::asset::AssetBehavior;
308 use crate::xdr;
309
310 #[test]
311 fn test_no_issuer_for_non_xlm_asset() {
312 let err_val = Asset::new("USD", None).unwrap_err();
313 assert_eq!(err_val, "Issuer cannot be null");
314 }
315
316 #[test]
317 fn test_invalid_asset_code() {
318 let err_val = Asset::new(
319 "",
320 Some("GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ"),
321 )
322 .unwrap_err();
323 assert_eq!(
324 err_val,
325 "Asset code is invalid (maximum alphanumeric, 12 characters at max)"
326 );
327 let err_val = super::Asset::new(
328 "1234567890123",
329 Some("GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ"),
330 )
331 .unwrap_err();
332 assert_eq!(
333 err_val,
334 "Asset code is invalid (maximum alphanumeric, 12 characters at max)"
335 );
336 let err_val = Asset::new(
337 "ab_",
338 Some("GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ"),
339 )
340 .unwrap_err();
341 assert_eq!(
342 err_val,
343 "Asset code is invalid (maximum alphanumeric, 12 characters at max)"
344 );
345 }
346
347 #[test]
348 fn test_native_asset_code() {
349 let asset = Asset::native();
350 assert_eq!(asset.get_code().unwrap(), "XLM");
351 }
352
353 #[test]
354 fn test_asset_code() {
355 let issuer = "GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ";
356 let asset = Asset::new("USD", Some(issuer)).unwrap();
357 assert_eq!(asset.get_code().unwrap(), "USD");
358 }
359
360 #[test]
361 fn test_native_asset_issuer() {
362 let asset = Asset::native();
363 assert!(asset.get_issuer().is_none());
364 }
365
366 #[test]
367 fn test_non_native_asset_issuer() {
368 let issuer = "GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ";
369 let asset = Asset::new("USD", Some(issuer)).unwrap();
370 assert_eq!(asset.get_issuer(), Some(issuer.to_string()));
371 }
372
373 #[test]
374 fn test_native_asset_type() {
375 let asset = Asset::native();
376 assert_eq!(asset.get_asset_type(), "native");
377 }
378
379 #[test]
380 fn test_credit_alphanum4_asset_type() {
381 let issuer = "GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ";
382 let asset = Asset::new("ABCD", Some(issuer)).unwrap();
383 assert_eq!(asset.get_asset_type(), "credit_alphanum4");
384 }
385
386 #[test]
387 fn test_credit_alphanum12_asset_type() {
388 let issuer = "GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ";
389 let asset = Asset::new("ABCDEF", Some(issuer)).unwrap();
390 assert_eq!(asset.get_asset_type(), "credit_alphanum12");
391 }
392
393 #[test]
394 fn test_parse_native_asset() {
395 let asset = Asset::native();
396
397 let xdr = asset.to_xdr_object();
399
400 assert_eq!(
401 String::from_utf8(xdr.to_xdr(xdr::Limits::none()).unwrap()),
402 String::from_utf8([0u8, 0u8, 0u8, 0u8].to_vec())
403 );
404
405 let xdr = asset.to_change_trust_xdr_object();
406 assert_eq!(
407 String::from_utf8(xdr.to_xdr(xdr::Limits::none()).unwrap()),
408 String::from_utf8([0u8, 0u8, 0u8, 0u8].to_vec())
409 );
410
411 let xdr = asset.to_trust_line_xdr_object();
413 assert_eq!(
414 String::from_utf8(xdr.to_xdr(xdr::Limits::none()).unwrap()),
415 String::from_utf8([0u8, 0u8, 0u8, 0u8].to_vec())
416 );
417 }
418
419 #[test]
420 fn test_parse_3_alphanum_asset() {
421 let issuer = "GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ";
422 let asset = Asset::new("USD", Some(issuer)).unwrap();
423 let xdr = asset.to_xdr_object();
424
425 match xdr {
426 xdr::Asset::CreditAlphanum4(x) => {
427 assert_eq!(hex::encode(x.asset_code), hex::encode("USD\0".to_string()))
428 }
429 _ => panic!("Error"),
430 }
431
432 let xdr = asset.to_change_trust_xdr_object();
433 match xdr {
434 xdr::ChangeTrustAsset::CreditAlphanum4(x) => {
435 assert_eq!(hex::encode(x.asset_code), hex::encode("USD\0".to_string()))
436 }
437 _ => panic!("Error"),
438 }
439
440 let xdr = asset.to_trust_line_xdr_object();
441 match xdr {
442 xdr::TrustLineAsset::CreditAlphanum4(x) => {
443 assert_eq!(hex::encode(x.asset_code), hex::encode("USD\0".to_string()))
444 }
445 _ => panic!("Error"),
446 }
447 }
448
449 #[test]
450 fn test_parse_4_alphanum_asset() {
451 let issuer = "GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ";
452 let asset = Asset::new("BART", Some(issuer)).unwrap();
453 let xdr = asset.to_xdr_object();
454
455 match xdr {
456 xdr::Asset::CreditAlphanum4(x) => {
457 assert_eq!(hex::encode(x.asset_code), hex::encode("BART".to_string()))
458 }
459 _ => panic!("Error"),
460 }
461
462 let xdr = asset.to_change_trust_xdr_object();
463 match xdr {
464 xdr::ChangeTrustAsset::CreditAlphanum4(x) => {
465 assert_eq!(hex::encode(x.asset_code), hex::encode("BART".to_string()))
466 }
467 _ => panic!("Error"),
468 }
469
470 let xdr = asset.to_trust_line_xdr_object();
471 match xdr {
472 xdr::TrustLineAsset::CreditAlphanum4(x) => {
473 assert_eq!(hex::encode(x.asset_code), hex::encode("BART".to_string()))
474 }
475 _ => panic!("Error"),
476 }
477 }
478
479 #[test]
480 fn test_parse_5_alphanum_asset() {
481 let issuer = "GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ";
482 let asset = Asset::new("12345", Some(issuer)).unwrap();
483 let xdr = asset.to_xdr_object();
484
485 match xdr {
486 xdr::Asset::CreditAlphanum12(x) => assert_eq!(
487 hex::encode(x.asset_code),
488 hex::encode("12345\0\0\0\0\0\0\0".to_string())
489 ),
490 _ => panic!("Error"),
491 }
492
493 let xdr = asset.to_change_trust_xdr_object();
494 match xdr {
495 xdr::ChangeTrustAsset::CreditAlphanum12(x) => assert_eq!(
496 hex::encode(x.asset_code),
497 hex::encode("12345\0\0\0\0\0\0\0".to_string())
498 ),
499 _ => panic!("Error"),
500 }
501
502 let xdr = asset.to_trust_line_xdr_object();
503 match xdr {
504 xdr::TrustLineAsset::CreditAlphanum12(x) => assert_eq!(
505 hex::encode(x.asset_code),
506 hex::encode("12345\0\0\0\0\0\0\0".to_string())
507 ),
508 _ => panic!("Error"),
509 }
510 }
511
512 #[test]
513 fn test_parse_12_alphanum_asset() {
514 let issuer = "GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ";
515 let asset = Asset::new("123456789012", Some(issuer)).unwrap();
516 let xdr = asset.to_xdr_object();
517
518 match xdr {
519 xdr::Asset::CreditAlphanum12(x) => assert_eq!(
520 hex::encode(x.asset_code),
521 hex::encode("123456789012".to_string())
522 ),
523 _ => panic!("Error"),
524 }
525
526 let xdr = asset.to_change_trust_xdr_object();
527 match xdr {
528 xdr::ChangeTrustAsset::CreditAlphanum12(x) => assert_eq!(
529 hex::encode(x.asset_code),
530 hex::encode("123456789012".to_string())
531 ),
532 _ => panic!("Error"),
533 }
534
535 let xdr = asset.to_trust_line_xdr_object();
536 match xdr {
537 xdr::TrustLineAsset::CreditAlphanum12(x) => assert_eq!(
538 hex::encode(x.asset_code),
539 hex::encode("123456789012".to_string())
540 ),
541 _ => panic!("Error"),
542 }
543 }
544
545 #[test]
546 fn test_parse_xdr_asset() {
547 let xdr = xdr::Asset::Native;
548 let asset = Asset::from_operation(xdr).unwrap();
549 assert!(asset.is_native());
550
551 let issuer = "GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ";
552 let addr = xdr::AccountId(xdr::PublicKey::PublicKeyTypeEd25519(xdr::Uint256(
553 stellar_strkey::ed25519::PublicKey::from_string(issuer)
554 .unwrap()
555 .0,
556 )));
557
558 let mut asset_code: [u8; 4] = [0; 4];
559
560 for (i, b) in "KHL".as_bytes().iter().enumerate() {
561 asset_code[i] = *b;
562 }
563 let xdr = xdr::Asset::CreditAlphanum4(xdr::AlphaNum4 {
564 asset_code: xdr::AssetCode4(asset_code),
565 issuer: addr.clone(),
566 });
567
568 let asset = Asset::from_operation(xdr).unwrap();
569
570 assert_eq!("KHL", asset.get_code().unwrap());
571 assert_eq!(issuer.to_string(), asset.get_issuer().unwrap());
572 }
573
574 #[test]
575 fn test_parse_12_alphanum_xdr_asset() {
576 let issuer = "GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ";
577 let addr = xdr::AccountId(xdr::PublicKey::PublicKeyTypeEd25519(xdr::Uint256(
578 stellar_strkey::ed25519::PublicKey::from_string(issuer)
579 .unwrap()
580 .0,
581 )));
582 let mut asset_code: [u8; 12] = [0; 12];
583
584 for (i, b) in "KHLTOKEN".as_bytes().iter().enumerate() {
585 asset_code[i] = *b;
586 }
587 let xdr = xdr::Asset::CreditAlphanum12(xdr::AlphaNum12 {
588 asset_code: xdr::AssetCode12(asset_code),
589 issuer: addr.clone(),
590 });
591
592 let asset = Asset::from_operation(xdr).unwrap();
593 assert_eq!("KHLTOKEN", asset.get_code().unwrap());
594 assert_eq!(issuer.to_string(), asset.get_issuer().unwrap());
595 }
596
597 #[test]
598 fn test_to_string_native() {
599 let asset = Asset::native();
600 assert_eq!(asset.to_string(), "native");
601 }
602
603 #[test]
604 fn test_to_string_non_native() {
605 let asset = Asset::new(
606 "USD",
607 Some("GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ"),
608 )
609 .unwrap();
610 assert_eq!(
611 asset.to_string(),
612 "USD:GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ"
613 );
614 }
615
616 #[test]
617 fn test_compare_works() {
618 let asset_a = Asset::new(
619 "ARST",
620 Some("GB7TAYRUZGE6TVT7NHP5SMIZRNQA6PLM423EYISAOAP3MKYIQMVYP2JO"),
621 )
622 .unwrap();
623
624 let asset_b = Asset::new(
625 "USD",
626 Some("GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ"),
627 )
628 .unwrap();
629
630 Asset::compare(&asset_a, &asset_b);
631 }
632
633 #[test]
634 fn test_compare_equal_assets() {
635 let xlm = Asset::native();
636 let asset_a = Asset::new(
637 "ARST",
638 Some("GB7TAYRUZGE6TVT7NHP5SMIZRNQA6PLM423EYISAOAP3MKYIQMVYP2JO"),
639 )
640 .unwrap();
641
642 let asset_b = Asset::new(
643 "USD",
644 Some("GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ"),
645 )
646 .unwrap();
647
648 assert_eq!(Asset::compare(&xlm.clone(), &xlm), 0);
650 assert_eq!(Asset::compare(&asset_a.clone(), &asset_a), 0);
651 assert_eq!(Asset::compare(&asset_b.clone(), &asset_b), 0);
652 }
653
654 #[test]
655 fn test_compare_assets() {
656 let xlm = Asset::native();
657 let asset_a = Asset::new(
658 "ARST",
659 Some("GB7TAYRUZGE6TVT7NHP5SMIZRNQA6PLM423EYISAOAP3MKYIQMVYP2JO"),
660 )
661 .unwrap();
662
663 let asset_b = Asset::new(
664 "ARSTANUM12",
665 Some("GB7TAYRUZGE6TVT7NHP5SMIZRNQA6PLM423EYISAOAP3MKYIQMVYP2JO"),
666 )
667 .unwrap();
668
669 assert_eq!(Asset::compare(&xlm.clone(), &xlm), 0);
671 assert_eq!(Asset::compare(&xlm.clone(), &asset_a), -1);
672 assert_eq!(Asset::compare(&xlm.clone(), &asset_b), -1);
673
674 assert_eq!(Asset::compare(&asset_a.clone(), &xlm), 1);
675 assert_eq!(Asset::compare(&asset_a.clone(), &asset_a), 0);
676 assert_eq!(Asset::compare(&asset_a.clone(), &asset_b), -1);
677
678 assert_eq!(Asset::compare(&asset_b.clone(), &xlm), 1);
679 assert_eq!(Asset::compare(&asset_b.clone(), &asset_a), 1);
680 assert_eq!(Asset::compare(&asset_b.clone(), &asset_b), 0);
681 }
682
683 #[test]
684 fn test_compare_asset() {
685 let asset_arst = Asset::new(
686 "ARST",
687 Some("GB7TAYRUZGE6TVT7NHP5SMIZRNQA6PLM423EYISAOAP3MKYIQMVYP2JO"),
688 )
689 .unwrap();
690
691 let asset_usdx = Asset::new(
692 "USDA",
693 Some("GB7TAYRUZGE6TVT7NHP5SMIZRNQA6PLM423EYISAOAP3MKYIQMVYP2JO"),
694 )
695 .unwrap();
696
697 assert_eq!(Asset::compare(&asset_arst.clone(), &asset_arst), 0);
699 assert_eq!(Asset::compare(&asset_arst.clone(), &asset_usdx), -1);
700
701 assert_eq!(Asset::compare(&asset_usdx.clone(), &asset_arst), 1);
702 assert_eq!(Asset::compare(&asset_usdx.clone(), &asset_usdx), 0);
703
704 let asset_lower = Asset::new(
705 "aRST",
706 Some("GB7TAYRUZGE6TVT7NHP5SMIZRNQA6PLM423EYISAOAP3MKYIQMVYP2JO"),
707 )
708 .unwrap();
709
710 assert_eq!(Asset::compare(&asset_arst.clone(), &asset_lower), -1);
711 assert_eq!(Asset::compare(&asset_lower.clone(), &asset_arst), 1);
712 }
713
714 #[test]
715 fn test_compare_asset_issuers() {
716 let asset_a = Asset::new(
717 "ARST",
718 Some("GB7TAYRUZGE6TVT7NHP5SMIZRNQA6PLM423EYISAOAP3MKYIQMVYP2JO"),
719 )
720 .unwrap();
721
722 let asset_b = Asset::new(
723 "ARST",
724 Some("GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ"),
725 )
726 .unwrap();
727
728 assert_eq!(Asset::compare(&asset_a.clone(), &asset_b), -1);
729 assert_eq!(Asset::compare(&asset_a.clone(), &asset_a), 0);
730
731 assert_eq!(Asset::compare(&asset_b.clone(), &asset_a), 1);
732 assert_eq!(Asset::compare(&asset_b.clone(), &asset_b), 0);
733 }
734
735 #[test]
736 fn test_compare_upper_lower() {
737 let asset_a = Asset::new(
738 "B",
739 Some("GA7NLOF4EHWMJF6DBXXV2H6AYI7IHYWNFZR6R52BYBLY7TE5Q74AIDRA"),
740 )
741 .unwrap();
742
743 let asset_b = Asset::new(
744 "a",
745 Some("GA7NLOF4EHWMJF6DBXXV2H6AYI7IHYWNFZR6R52BYBLY7TE5Q74AIDRA"),
746 )
747 .unwrap();
748
749 assert_eq!(Asset::compare(&asset_a.clone(), &asset_b), -1);
750 }
751}