penumbra_sdk_shielded_pool/genesis/
allocation.rs

1use penumbra_sdk_asset::{
2    asset::{self, Metadata, Unit},
3    Value,
4};
5use penumbra_sdk_keys::Address;
6use penumbra_sdk_num::Amount;
7use penumbra_sdk_proto::{penumbra::core::component::shielded_pool::v1 as pb, DomainType};
8use serde::{Deserialize, Serialize};
9
10/// A (transparent) genesis allocation.
11#[derive(Clone, Serialize, Deserialize)]
12#[serde(
13    try_from = "pb::genesis_content::Allocation",
14    into = "pb::genesis_content::Allocation"
15)]
16pub struct Allocation {
17    pub raw_amount: Amount,
18    pub raw_denom: String,
19    pub address: Address,
20}
21
22impl Allocation {
23    pub fn denom(&self) -> Metadata {
24        self.unit().base()
25    }
26
27    pub fn unit(&self) -> Unit {
28        asset::REGISTRY.parse_unit(&self.raw_denom)
29    }
30
31    pub fn amount(&self) -> Amount {
32        let unit = self.unit();
33        self.raw_amount * (10u128.pow(unit.exponent().into()).into())
34    }
35
36    pub fn value(&self) -> Value {
37        Value {
38            amount: self.amount(),
39            asset_id: self.unit().id(),
40        }
41    }
42}
43
44impl From<Allocation> for pb::genesis_content::Allocation {
45    fn from(a: Allocation) -> Self {
46        pb::genesis_content::Allocation {
47            amount: Some(a.raw_amount.into()),
48            denom: a.raw_denom,
49            address: Some(a.address.into()),
50        }
51    }
52}
53
54impl TryFrom<pb::genesis_content::Allocation> for Allocation {
55    type Error = anyhow::Error;
56
57    fn try_from(msg: pb::genesis_content::Allocation) -> Result<Self, Self::Error> {
58        Ok(Allocation {
59            raw_amount: msg
60                .amount
61                .ok_or_else(|| anyhow::anyhow!("missing amount field in proto"))?
62                .try_into()?,
63            raw_denom: msg.denom,
64            address: msg
65                .address
66                .ok_or_else(|| anyhow::anyhow!("missing address field in proto"))?
67                .try_into()?,
68        })
69    }
70}
71
72// Implement Debug manually so we can use the Display impl for the address,
73// rather than dumping all the internal address components.
74impl std::fmt::Debug for Allocation {
75    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
76        f.debug_struct("Allocation")
77            .field("amount", &self.raw_amount)
78            .field("denom", &self.raw_denom)
79            .field("address", &self.address.to_string())
80            .finish()
81    }
82}
83
84impl DomainType for Allocation {
85    type Proto = pb::genesis_content::Allocation;
86}