abstract_std/objects/entry/
ans_entry_convertor.rs

1use crate::{
2    constants::{ASSET_DELIMITER, TYPE_DELIMITER},
3    objects::{
4        ans_host::{AnsHostError, AnsHostResult},
5        AssetEntry, DexAssetPairing, LpToken, PoolMetadata,
6    },
7};
8
9/// A helper struct for Abstract Name Service entry conversions.
10pub struct AnsEntryConvertor<T> {
11    entry: T,
12}
13
14impl<T> AnsEntryConvertor<T> {
15    pub fn new(entry: T) -> Self {
16        Self { entry }
17    }
18}
19
20// An LP token can convert to:
21impl AnsEntryConvertor<LpToken> {
22    pub fn asset_entry(self) -> AssetEntry {
23        AssetEntry::from(self.entry.to_string())
24    }
25
26    pub fn dex_asset_pairing(self) -> AnsHostResult<DexAssetPairing> {
27        let mut assets = self.entry.assets;
28        // assets should already be sorted, but just in case
29        assets.sort();
30        assets.reverse();
31
32        Ok(DexAssetPairing::new(
33            assets.pop().unwrap(),
34            assets.pop().unwrap(),
35            self.entry.dex.as_str(),
36        ))
37    }
38}
39
40impl AnsEntryConvertor<PoolMetadata> {
41    pub fn lp_token(self) -> LpToken {
42        LpToken {
43            dex: self.entry.dex,
44            assets: self.entry.assets,
45        }
46    }
47
48    pub fn lp_token_asset(self) -> AssetEntry {
49        AnsEntryConvertor::new(self.lp_token()).asset_entry()
50    }
51}
52
53impl AnsEntryConvertor<AssetEntry> {
54    /// Try from an asset entry that should be formatted as "dex_name/asset1,asset2"
55    pub fn lp_token(self) -> AnsHostResult<LpToken> {
56        let segments = self
57            .entry
58            .as_str()
59            .split(TYPE_DELIMITER)
60            .collect::<Vec<_>>();
61
62        if segments.len() != 2 {
63            return Err(AnsHostError::FormattingError {
64                object: "lp token".to_string(),
65                expected: "type/asset1,asset2".to_string(),
66                actual: self.entry.to_string(),
67            });
68        }
69
70        // get the dex name, like "junoswap"
71        let dex_name = segments[0].to_string();
72
73        // get the assets, like "crab,junox" and split them
74        let mut assets: Vec<AssetEntry> = segments[1]
75            .split(ASSET_DELIMITER)
76            .map(AssetEntry::from)
77            .collect();
78
79        // sort the assets on name
80        assets.sort_unstable();
81
82        if assets.len() < 2 {
83            return Err(AnsHostError::FormattingError {
84                object: "lp token".into(),
85                expected: "at least 2 assets in LP token".into(),
86                actual: self.entry.to_string(),
87            });
88        }
89
90        Ok(LpToken {
91            dex: dex_name,
92            assets,
93        })
94    }
95}