Skip to main content

dpp/tokens/token_payment_info/v0/
mod.rs

1pub mod v0_accessors;
2
3use crate::balances::credits::TokenAmount;
4use crate::data_contract::TokenContractPosition;
5use crate::tokens::gas_fees_paid_by::GasFeesPaidBy;
6use crate::tokens::token_payment_info::v0::v0_accessors::TokenPaymentInfoAccessorsV0;
7use crate::ProtocolError;
8use bincode::{Decode, DecodeUntrusted, Encode};
9use derive_more::Display;
10use platform_value::btreemap_extensions::BTreeValueRemoveFromMapHelper;
11use platform_value::{Identifier, Value};
12#[cfg(feature = "serde-conversion")]
13use serde::{Deserialize, Serialize};
14use std::collections::BTreeMap;
15
16#[derive(Debug, Clone, Copy, Encode, Decode, Default, PartialEq, Display, DecodeUntrusted)]
17// `json_safe_fields` auto-injects `json_safe_option_u64` on
18// `Option<TokenAmount>` (= `Option<u64>`) fields so JSON encodes large
19// values as strings — same convention as the rest of the wire shape.
20#[cfg_attr(feature = "json-conversion", crate::serialization::json_safe_fields)]
21#[cfg_attr(
22    feature = "serde-conversion",
23    derive(Serialize, Deserialize),
24    serde(rename_all = "camelCase")
25)]
26#[display(
27    "Contract ID: {:?}, Token Position: {:?}, Min Cost: {:?}, Max Cost: {:?}, Gas Fees Paid By: {}",
28    payment_token_contract_id,
29    token_contract_position,
30    minimum_token_cost,
31    maximum_token_cost,
32    gas_fees_paid_by
33)]
34pub struct TokenPaymentInfoV0 {
35    /// By default, we use a token in the same contract, this field must be set if the document
36    /// requires payment using another contracts token.
37    pub payment_token_contract_id: Option<Identifier>,
38    /// If we are expecting to pay with a token in a contract, which token are we expecting
39    /// to pay with?
40    /// We have this set so contract owners can't switch out to more valuable token.
41    /// For example if my Data contract
42    pub token_contract_position: TokenContractPosition,
43    /// Minimum token cost, this most often should not be set
44    pub minimum_token_cost: Option<TokenAmount>,
45    /// Maximum token cost, this most often should be set
46    /// If:
47    /// - a client does not have this set
48    /// - and the data contract allows the price of NFTs to be changed by the data contract's owner or allowed party.
49    ///   Then:
50    /// - The user could see the cost changed on them
51    pub maximum_token_cost: Option<TokenAmount>,
52    /// Who the document owner asks to pay the gas fees; it must be one the document type's token
53    /// cost offers, see `GasFeesPaidBy::resolve` (acted on from protocol version 14)
54    pub gas_fees_paid_by: GasFeesPaidBy,
55}
56
57impl TokenPaymentInfoAccessorsV0 for TokenPaymentInfoV0 {
58    // Getters
59    fn payment_token_contract_id(&self) -> Option<Identifier> {
60        self.payment_token_contract_id
61    }
62
63    fn payment_token_contract_id_ref(&self) -> &Option<Identifier> {
64        &self.payment_token_contract_id
65    }
66
67    fn token_contract_position(&self) -> TokenContractPosition {
68        self.token_contract_position
69    }
70
71    fn minimum_token_cost(&self) -> Option<TokenAmount> {
72        self.minimum_token_cost
73    }
74
75    fn maximum_token_cost(&self) -> Option<TokenAmount> {
76        self.maximum_token_cost
77    }
78
79    // Setters
80    fn set_payment_token_contract_id(&mut self, id: Option<Identifier>) {
81        self.payment_token_contract_id = id;
82    }
83
84    fn set_token_contract_position(&mut self, position: TokenContractPosition) {
85        self.token_contract_position = position;
86    }
87
88    fn set_minimum_token_cost(&mut self, cost: Option<TokenAmount>) {
89        self.minimum_token_cost = cost;
90    }
91
92    fn set_maximum_token_cost(&mut self, cost: Option<TokenAmount>) {
93        self.maximum_token_cost = cost;
94    }
95
96    fn gas_fees_paid_by(&self) -> GasFeesPaidBy {
97        self.gas_fees_paid_by
98    }
99
100    fn set_gas_fees_paid_by(&mut self, payer: GasFeesPaidBy) {
101        self.gas_fees_paid_by = payer;
102    }
103}
104
105impl TryFrom<BTreeMap<String, Value>> for TokenPaymentInfoV0 {
106    type Error = ProtocolError;
107
108    fn try_from(mut map: BTreeMap<String, Value>) -> Result<Self, Self::Error> {
109        Ok(TokenPaymentInfoV0 {
110            payment_token_contract_id: map.remove_optional_identifier("paymentTokenContractId")?,
111
112            token_contract_position: map
113                .remove_optional_integer("tokenContractPosition")?
114                .unwrap_or_default(),
115
116            minimum_token_cost: map.remove_optional_integer("minimumTokenCost")?,
117
118            maximum_token_cost: map.remove_optional_integer("maximumTokenCost")?,
119
120            gas_fees_paid_by: map
121                .remove_optional_string("gasFeesPaidBy")?
122                .map(|v| match v.as_str() {
123                    "DocumentOwner" => GasFeesPaidBy::DocumentOwner,
124                    "ContractOwner" => GasFeesPaidBy::ContractOwner,
125                    "PreferContractOwner" => GasFeesPaidBy::PreferContractOwner,
126                    _ => GasFeesPaidBy::default(),
127                })
128                .unwrap_or_default(),
129        })
130    }
131}