penumbra_sdk_auction/auction/dutch/actions/
schedule.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
use crate::auction::{dutch::DutchAuctionDescription, nft::AuctionNft};
use anyhow::anyhow;
use penumbra_sdk_asset::{Balance, Value};
use penumbra_sdk_proto::{core::component::auction::v1 as pb, DomainType};
use penumbra_sdk_txhash::{EffectHash, EffectingData};
use serde::{Deserialize, Serialize};

/// The maximum amount of input/output in a Dutch auction description.
/// 52 bits gives us enough headroom to do infaillible price interpolation.
pub const MAX_AUCTION_AMOUNT_RESERVES: u128 = (1 << 52) - 1;

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(
    try_from = "pb::ActionDutchAuctionSchedule",
    into = "pb::ActionDutchAuctionSchedule"
)]
pub struct ActionDutchAuctionSchedule {
    pub description: DutchAuctionDescription,
}

impl ActionDutchAuctionSchedule {
    /// Compute the value balance corresponding to this action:
    ///
    /// # Diagram
    ///
    ///  ┌────────────────────┬──────────────────────┐
    ///  │      Burn (-)      │       Mint (+)       │
    ///  ├────────────────────┼──────────────────────┤
    ///  │    input value     │  opened auction nft  │
    ///  └────────────────────┴──────────────────────┘                  
    pub fn balance(&self) -> Balance {
        let opened_auction_nft = AuctionNft::new(self.description.id(), 0u64);
        let opened_auction_nft_value = Value {
            asset_id: opened_auction_nft.metadata.id(),
            amount: 1u128.into(),
        };

        let output_nft_balance = Balance::from(opened_auction_nft_value);
        let input_balance = Balance::from(self.description.input);

        output_nft_balance - input_balance
    }
}

/* Effect hash */
impl EffectingData for ActionDutchAuctionSchedule {
    fn effect_hash(&self) -> EffectHash {
        EffectHash::from_proto_effecting_data(&self.to_proto())
    }
}

/* Protobuf impls */
impl DomainType for ActionDutchAuctionSchedule {
    type Proto = pb::ActionDutchAuctionSchedule;
}

impl From<ActionDutchAuctionSchedule> for pb::ActionDutchAuctionSchedule {
    fn from(domain: ActionDutchAuctionSchedule) -> Self {
        pb::ActionDutchAuctionSchedule {
            description: Some(domain.description.into()),
        }
    }
}

impl TryFrom<pb::ActionDutchAuctionSchedule> for ActionDutchAuctionSchedule {
    type Error = anyhow::Error;

    fn try_from(msg: pb::ActionDutchAuctionSchedule) -> Result<Self, Self::Error> {
        Ok(ActionDutchAuctionSchedule {
            description: msg
                .description
                .ok_or_else(|| {
                    anyhow!("ActionDutchAuctionSchedule message is missing a description")
                })?
                .try_into()?,
        })
    }
}