penumbra_sdk_asset/asset/
cache.rs1use std::{collections::BTreeMap, ops::Deref, sync::Arc};
2
3use super::{denom_metadata, Id, Metadata, REGISTRY};
4use crate::asset::denom_metadata::Unit;
5
6#[derive(Clone, Default, Debug)]
14pub struct Cache {
15 cache: BTreeMap<Id, Metadata>,
16 units: BTreeMap<String, Unit>,
17}
18
19impl Cache {
20 pub fn get_by_id(&self, id: Id) -> Option<Metadata> {
21 self.cache.get(&id).cloned()
22 }
23
24 pub fn get_unit(&self, raw_denom: &str) -> Option<Unit> {
25 self.units.get(raw_denom).cloned()
26 }
27
28 pub fn with_known_assets() -> Self {
29 let mut cache = Cache::default();
30
31 let known_assets = vec![
32 Metadata {
33 inner: Arc::new(denom_metadata::Inner::new(
34 "upenumbra".to_string(),
35 vec![
36 denom_metadata::BareDenomUnit {
37 exponent: 6,
38 denom: "penumbra".to_string(),
39 },
40 denom_metadata::BareDenomUnit {
41 exponent: 3,
42 denom: "mpenumbra".to_string(),
43 },
44 ],
45 )),
46 },
47 Metadata {
48 inner: Arc::new(denom_metadata::Inner::new(
49 "ugn".to_string(),
50 vec![
51 denom_metadata::BareDenomUnit {
52 exponent: 6,
53 denom: "gn".to_string(),
54 },
55 denom_metadata::BareDenomUnit {
56 exponent: 3,
57 denom: "mgn".to_string(),
58 },
59 ],
60 )),
61 },
62 Metadata {
63 inner: Arc::new(denom_metadata::Inner::new(
64 "ugm".to_string(),
65 vec![
66 denom_metadata::BareDenomUnit {
67 exponent: 6,
68 denom: "gm".to_string(),
69 },
70 denom_metadata::BareDenomUnit {
71 exponent: 3,
72 denom: "mgm".to_string(),
73 },
74 ],
75 )),
76 },
77 Metadata {
78 inner: Arc::new(denom_metadata::Inner::new(
79 "wtest_usd".to_string(),
80 vec![denom_metadata::BareDenomUnit {
81 exponent: 6,
82 denom: "test_usd".to_string(),
83 }],
84 )),
85 },
86 Metadata {
87 inner: Arc::new(denom_metadata::Inner::new(
88 "test_sat".to_string(),
89 vec![denom_metadata::BareDenomUnit {
90 exponent: 8,
91 denom: "test_btc".to_string(),
92 }],
93 )),
94 },
95 Metadata {
96 inner: Arc::new(denom_metadata::Inner::new(
97 "utest_atom".to_string(),
98 vec![
99 denom_metadata::BareDenomUnit {
100 exponent: 6,
101 denom: "test_atom".to_string(),
102 },
103 denom_metadata::BareDenomUnit {
104 exponent: 3,
105 denom: "mtest_atom".to_string(),
106 },
107 ],
108 )),
109 },
110 Metadata {
111 inner: Arc::new(denom_metadata::Inner::new(
112 "utest_osmo".to_string(),
113 vec![
114 denom_metadata::BareDenomUnit {
115 exponent: 6,
116 denom: "test_osmo".to_string(),
117 },
118 denom_metadata::BareDenomUnit {
119 exponent: 3,
120 denom: "mtest_osmo".to_string(),
121 },
122 ],
123 )),
124 },
125 Metadata {
126 inner: Arc::new(denom_metadata::Inner::new(
127 "uubtc".to_string(),
128 vec![denom_metadata::BareDenomUnit {
129 exponent: 6,
130 denom: "ubtc".to_string(),
131 }],
132 )),
133 },
134 Metadata {
135 inner: Arc::new(denom_metadata::Inner::new(
136 "ucube".to_string(),
137 vec![denom_metadata::BareDenomUnit {
138 exponent: 1,
139 denom: "cube".to_string(),
140 }],
141 )),
142 },
143 Metadata {
144 inner: Arc::new(denom_metadata::Inner::new(
145 "unala".to_string(),
146 vec![
147 denom_metadata::BareDenomUnit {
148 exponent: 6,
149 denom: "nala".to_string(),
150 },
151 denom_metadata::BareDenomUnit {
152 exponent: 3,
153 denom: "mnala".to_string(),
154 },
155 ],
156 )),
157 },
158 ];
159
160 cache.extend(known_assets);
161
162 cache
163 }
164}
165
166impl Deref for Cache {
169 type Target = BTreeMap<Id, Metadata>;
170
171 fn deref(&self) -> &Self::Target {
172 &self.cache
173 }
174}
175
176impl From<Cache> for BTreeMap<Id, Metadata> {
177 fn from(cache: Cache) -> Self {
178 cache
179 .cache
180 .into_iter()
181 .map(|(id, denom)| (id, denom))
182 .collect()
183 }
184}
185
186impl TryFrom<BTreeMap<Id, Metadata>> for Cache {
187 type Error = anyhow::Error;
188
189 fn try_from(map: BTreeMap<Id, Metadata>) -> Result<Self, Self::Error> {
190 let mut cache = BTreeMap::default();
191 let mut units: BTreeMap<String, Unit> = BTreeMap::default();
192 for (provided_id, denom) in map.into_iter() {
193 if let Some(denom) = REGISTRY.parse_denom(&denom.base_denom().denom) {
194 let id = denom.id();
195 if provided_id != id {
196 anyhow::bail!(
197 "provided id {} for denom {} does not match computed id {}",
198 provided_id,
199 denom,
200 id
201 );
202 }
203 cache.insert(id, denom.clone());
204 units.insert(denom.base_denom().denom, denom.base_unit());
205 } else {
206 anyhow::bail!("invalid base denom {}", denom.base_denom().denom);
207 }
208 }
209 Ok(Self { cache, units })
210 }
211}
212
213impl Extend<Metadata> for Cache {
216 fn extend<T>(&mut self, iter: T)
217 where
218 T: IntoIterator<Item = Metadata>,
219 {
220 for denom in iter {
221 let id = denom.id();
222 self.cache.insert(id, denom.clone());
223
224 for unit in denom.units() {
225 self.units.insert(unit.to_string(), unit);
226 }
227 }
228 }
229}
230
231impl FromIterator<Metadata> for Cache {
232 fn from_iter<T: IntoIterator<Item = Metadata>>(iter: T) -> Self {
233 let mut cache = Cache::default();
234 cache.extend(iter);
235 cache
236 }
237}