dpp/tokens/token_payment_info/v1/
mod.rs1pub mod v1_accessors;
2
3use crate::balances::credits::TokenAmount;
4use crate::data_contract::TokenContractPosition;
5use crate::shielded::SerializedAction;
6use crate::tokens::gas_fees_paid_by::GasFeesPaidBy;
7use crate::tokens::token_payment_info::v0::v0_accessors::TokenPaymentInfoAccessorsV0;
8use crate::tokens::token_payment_info::v0::TokenPaymentInfoV0;
9use crate::ProtocolError;
10use bincode::{Decode, DecodeUntrusted, Encode};
11use platform_value::btreemap_extensions::{
12 BTreeValueRemoveFromMapHelper, BTreeValueRemoveInnerValueFromMapHelper,
13};
14use platform_value::{Identifier, Value};
15#[cfg(feature = "serde-conversion")]
16use serde::{Deserialize, Serialize};
17use std::collections::BTreeMap;
18use std::fmt;
19
20#[derive(Debug, Clone, Encode, Decode, PartialEq, DecodeUntrusted)]
26#[cfg_attr(feature = "json-conversion", crate::serialization::json_safe_fields)]
29#[cfg_attr(
30 feature = "serde-conversion",
31 derive(Serialize, Deserialize),
32 serde(rename_all = "camelCase")
33)]
34pub struct TokenShieldedPayment {
35 pub amount: TokenAmount,
38 pub actions: Vec<SerializedAction>,
40 pub anchor: [u8; 32],
42 pub proof: Vec<u8>,
44 pub binding_signature: [u8; 64],
46}
47
48#[cfg(all(feature = "json-conversion", feature = "serde-conversion"))]
49impl crate::serialization::JsonConvertible for TokenShieldedPayment {}
50
51#[cfg(all(feature = "value-conversion", feature = "serde-conversion"))]
52impl crate::serialization::ValueConvertible for TokenShieldedPayment {}
53
54impl Default for TokenShieldedPayment {
55 fn default() -> Self {
56 Self {
57 amount: 0,
58 actions: vec![],
59 anchor: [0u8; 32],
60 proof: vec![],
61 binding_signature: [0u8; 64],
62 }
63 }
64}
65
66impl fmt::Display for TokenShieldedPayment {
67 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68 write!(
69 f,
70 "Shielded Payment: amount {}, actions {}",
71 self.amount,
72 self.actions.len()
73 )
74 }
75}
76
77impl TryFrom<BTreeMap<String, Value>> for TokenShieldedPayment {
78 type Error = ProtocolError;
79
80 fn try_from(mut map: BTreeMap<String, Value>) -> Result<Self, Self::Error> {
81 let actions = map
88 .remove_inner_value_array::<Vec<Value>>("actions")?
89 .into_iter()
90 .map(|value| {
91 let mut action = value.into_btree_string_map()?;
92 Ok(SerializedAction {
93 nullifier: action.remove_bytes_32("nullifier")?.to_buffer(),
94 rk: action.remove_bytes_32("rk")?.to_buffer(),
95 cmx: action.remove_bytes_32("cmx")?.to_buffer(),
96 encrypted_note: action.remove_binary_data("encryptedNote")?.0,
97 cv_net: action.remove_bytes_32("cvNet")?.to_buffer(),
98 spend_auth_sig: fixed_64(
99 action.remove_binary_data("spendAuthSig")?.0,
100 "spendAuthSig",
101 )?,
102 })
103 })
104 .collect::<Result<Vec<_>, ProtocolError>>()?;
105 Ok(TokenShieldedPayment {
106 amount: map.remove_integer("amount")?,
107 actions,
108 anchor: map.remove_bytes_32("anchor")?.to_buffer(),
109 proof: map.remove_binary_data("proof")?.0,
110 binding_signature: fixed_64(
111 map.remove_binary_data("bindingSignature")?.0,
112 "bindingSignature",
113 )?,
114 })
115 }
116}
117
118fn fixed_64(bytes: Vec<u8>, field: &str) -> Result<[u8; 64], ProtocolError> {
119 let len = bytes.len();
120 bytes
121 .try_into()
122 .map_err(|_| ProtocolError::DecodingError(format!("{field} must be 64 bytes, got {len}")))
123}
124
125#[derive(Debug, Clone, Encode, Decode, Default, PartialEq, DecodeUntrusted)]
130#[cfg_attr(feature = "json-conversion", crate::serialization::json_safe_fields)]
131#[cfg_attr(
132 feature = "serde-conversion",
133 derive(Serialize, Deserialize),
134 serde(rename_all = "camelCase")
135)]
136pub struct TokenPaymentInfoV1 {
137 pub payment_token_contract_id: Option<Identifier>,
140 pub token_contract_position: TokenContractPosition,
142 pub minimum_token_cost: Option<TokenAmount>,
144 pub maximum_token_cost: Option<TokenAmount>,
146 pub gas_fees_paid_by: GasFeesPaidBy,
148 pub shielded_payment: Box<TokenShieldedPayment>,
151}
152
153impl fmt::Display for TokenPaymentInfoV1 {
154 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
155 write!(
156 f,
157 "Contract ID: {:?}, Token Position: {:?}, Min Cost: {:?}, Max Cost: {:?}, Gas Fees Paid By: {}, {}",
158 self.payment_token_contract_id,
159 self.token_contract_position,
160 self.minimum_token_cost,
161 self.maximum_token_cost,
162 self.gas_fees_paid_by,
163 self.shielded_payment
164 )
165 }
166}
167
168impl TokenPaymentInfoV1 {
169 pub fn from_v0(v0: TokenPaymentInfoV0, shielded_payment: TokenShieldedPayment) -> Self {
171 Self {
172 payment_token_contract_id: v0.payment_token_contract_id,
173 token_contract_position: v0.token_contract_position,
174 minimum_token_cost: v0.minimum_token_cost,
175 maximum_token_cost: v0.maximum_token_cost,
176 gas_fees_paid_by: v0.gas_fees_paid_by,
177 shielded_payment: Box::new(shielded_payment),
178 }
179 }
180
181 pub fn into_v0(self) -> TokenPaymentInfoV0 {
183 TokenPaymentInfoV0 {
184 payment_token_contract_id: self.payment_token_contract_id,
185 token_contract_position: self.token_contract_position,
186 minimum_token_cost: self.minimum_token_cost,
187 maximum_token_cost: self.maximum_token_cost,
188 gas_fees_paid_by: self.gas_fees_paid_by,
189 }
190 }
191
192 pub fn shielded_payment(&self) -> &TokenShieldedPayment {
194 &self.shielded_payment
195 }
196}
197
198impl TokenPaymentInfoAccessorsV0 for TokenPaymentInfoV1 {
199 fn payment_token_contract_id(&self) -> Option<Identifier> {
200 self.payment_token_contract_id
201 }
202
203 fn payment_token_contract_id_ref(&self) -> &Option<Identifier> {
204 &self.payment_token_contract_id
205 }
206
207 fn token_contract_position(&self) -> TokenContractPosition {
208 self.token_contract_position
209 }
210
211 fn minimum_token_cost(&self) -> Option<TokenAmount> {
212 self.minimum_token_cost
213 }
214
215 fn maximum_token_cost(&self) -> Option<TokenAmount> {
216 self.maximum_token_cost
217 }
218
219 fn set_payment_token_contract_id(&mut self, id: Option<Identifier>) {
220 self.payment_token_contract_id = id;
221 }
222
223 fn set_token_contract_position(&mut self, position: TokenContractPosition) {
224 self.token_contract_position = position;
225 }
226
227 fn set_minimum_token_cost(&mut self, cost: Option<TokenAmount>) {
228 self.minimum_token_cost = cost;
229 }
230
231 fn set_maximum_token_cost(&mut self, cost: Option<TokenAmount>) {
232 self.maximum_token_cost = cost;
233 }
234
235 fn gas_fees_paid_by(&self) -> GasFeesPaidBy {
236 self.gas_fees_paid_by
237 }
238
239 fn set_gas_fees_paid_by(&mut self, payer: GasFeesPaidBy) {
240 self.gas_fees_paid_by = payer;
241 }
242}
243
244impl TryFrom<BTreeMap<String, Value>> for TokenPaymentInfoV1 {
245 type Error = ProtocolError;
246
247 fn try_from(mut map: BTreeMap<String, Value>) -> Result<Self, Self::Error> {
248 let shielded_map: BTreeMap<String, Value> = map
249 .remove_map_as_btree_map_keep_values_as_platform_value::<String, Value>(
250 "shieldedPayment",
251 )?;
252 let shielded_payment: TokenShieldedPayment = shielded_map.try_into()?;
253 let v0: TokenPaymentInfoV0 = map.try_into()?;
254 Ok(TokenPaymentInfoV1::from_v0(v0, shielded_payment))
255 }
256}