dpp/tokens/
gas_fees_paid_by.rs1use crate::consensus::basic::data_contract::UnknownGasFeesPaidByError;
2use crate::consensus::basic::BasicError;
3use crate::consensus::ConsensusError;
4#[cfg(all(feature = "json-conversion", feature = "serde-conversion"))]
5use crate::serialization::JsonConvertible;
6#[cfg(all(feature = "value-conversion", feature = "serde-conversion"))]
7use crate::serialization::ValueConvertible;
8use crate::ProtocolError;
9use bincode::{Decode, DecodeUntrusted, Encode};
10use derive_more::Display;
11#[cfg(feature = "serde-conversion")]
12use serde::{Deserialize, Serialize};
13
14#[derive(Debug, Clone, Copy, Encode, Decode, Default, PartialEq, Display, DecodeUntrusted)]
15#[cfg_attr(feature = "serde-conversion", derive(Serialize, Deserialize))]
16pub enum GasFeesPaidBy {
28 #[default]
33 DocumentOwner = 0,
34 ContractOwner = 1,
41 PreferContractOwner = 2,
49}
50
51impl GasFeesPaidBy {
52 pub fn resolve(offered_by_contract: Self, requested: Self) -> Option<Self> {
65 match (offered_by_contract, requested) {
66 (_, GasFeesPaidBy::DocumentOwner) => Some(GasFeesPaidBy::DocumentOwner),
67 (GasFeesPaidBy::DocumentOwner, GasFeesPaidBy::PreferContractOwner) => {
68 Some(GasFeesPaidBy::DocumentOwner)
69 }
70 (GasFeesPaidBy::DocumentOwner, GasFeesPaidBy::ContractOwner) => None,
71 (GasFeesPaidBy::PreferContractOwner, GasFeesPaidBy::PreferContractOwner) => {
72 Some(GasFeesPaidBy::PreferContractOwner)
73 }
74 (GasFeesPaidBy::PreferContractOwner, GasFeesPaidBy::ContractOwner) => None,
75 (GasFeesPaidBy::ContractOwner, GasFeesPaidBy::PreferContractOwner) => {
76 Some(GasFeesPaidBy::PreferContractOwner)
77 }
78 (GasFeesPaidBy::ContractOwner, GasFeesPaidBy::ContractOwner) => {
79 Some(GasFeesPaidBy::ContractOwner)
80 }
81 }
82 }
83}
84
85#[cfg(all(feature = "json-conversion", feature = "serde-conversion"))]
86impl JsonConvertible for GasFeesPaidBy {}
87
88#[cfg(all(feature = "value-conversion", feature = "serde-conversion"))]
89impl ValueConvertible for GasFeesPaidBy {}
90
91impl From<GasFeesPaidBy> for u8 {
92 fn from(value: GasFeesPaidBy) -> Self {
93 match value {
94 GasFeesPaidBy::DocumentOwner => 0,
95 GasFeesPaidBy::ContractOwner => 1,
96 GasFeesPaidBy::PreferContractOwner => 2,
97 }
98 }
99}
100
101impl TryFrom<u8> for GasFeesPaidBy {
102 type Error = ProtocolError;
103
104 fn try_from(value: u8) -> Result<Self, Self::Error> {
105 match value {
106 0 => Ok(GasFeesPaidBy::DocumentOwner),
107 1 => Ok(GasFeesPaidBy::ContractOwner),
108 2 => Ok(GasFeesPaidBy::PreferContractOwner),
109 value => Err(ProtocolError::ConsensusError(
110 ConsensusError::BasicError(BasicError::UnknownGasFeesPaidByError(
111 UnknownGasFeesPaidByError::new(vec![0, 1, 2], value as u64),
112 ))
113 .into(),
114 )),
115 }
116 }
117}
118
119impl TryFrom<u64> for GasFeesPaidBy {
120 type Error = ProtocolError;
121
122 fn try_from(value: u64) -> Result<Self, Self::Error> {
123 u8::try_from(value)
124 .map_err(|_| {
125 ProtocolError::ConsensusError(
126 ConsensusError::BasicError(BasicError::UnknownGasFeesPaidByError(
127 UnknownGasFeesPaidByError::new(vec![0, 1, 2], value),
128 ))
129 .into(),
130 )
131 })?
132 .try_into()
133 }
134}
135
136#[cfg(test)]
137mod resolve_tests {
138 use super::GasFeesPaidBy::{ContractOwner, DocumentOwner, PreferContractOwner};
139 use super::*;
140
141 #[test]
142 fn should_let_the_document_owner_opt_out_of_any_offer() {
143 for offered in [DocumentOwner, PreferContractOwner, ContractOwner] {
144 assert_eq!(
145 GasFeesPaidBy::resolve(offered, DocumentOwner),
146 Some(DocumentOwner)
147 );
148 }
149 }
150
151 #[test]
152 fn should_accept_a_preference_from_every_contract() {
153 assert_eq!(
154 GasFeesPaidBy::resolve(DocumentOwner, PreferContractOwner),
155 Some(DocumentOwner)
156 );
157 assert_eq!(
158 GasFeesPaidBy::resolve(PreferContractOwner, PreferContractOwner),
159 Some(PreferContractOwner)
160 );
161 assert_eq!(
162 GasFeesPaidBy::resolve(ContractOwner, PreferContractOwner),
163 Some(PreferContractOwner)
164 );
165 }
166
167 #[test]
168 fn should_honour_an_insistence_only_when_the_contract_commits_to_paying() {
169 assert_eq!(GasFeesPaidBy::resolve(DocumentOwner, ContractOwner), None);
170 assert_eq!(
171 GasFeesPaidBy::resolve(PreferContractOwner, ContractOwner),
172 None
173 );
174 assert_eq!(
175 GasFeesPaidBy::resolve(ContractOwner, ContractOwner),
176 Some(ContractOwner)
177 );
178 }
179}
180
181#[cfg(all(
182 test,
183 feature = "json-conversion",
184 feature = "value-conversion",
185 feature = "serde-conversion"
186))]
187mod json_convertible_tests {
188 use super::*;
189 use platform_value::platform_value;
190 use serde_json::json;
191
192 #[test]
196 fn json_round_trip_document_owner() {
197 use crate::serialization::JsonConvertible;
198 let original = GasFeesPaidBy::DocumentOwner;
199 let json = original.to_json().expect("to_json");
200 assert_eq!(json, json!("DocumentOwner"));
201 let recovered = GasFeesPaidBy::from_json(json).expect("from_json");
202 assert_eq!(original, recovered);
203 }
204
205 #[test]
206 fn json_round_trip_contract_owner() {
207 use crate::serialization::JsonConvertible;
208 let original = GasFeesPaidBy::ContractOwner;
209 let json = original.to_json().expect("to_json");
210 assert_eq!(json, json!("ContractOwner"));
211 let recovered = GasFeesPaidBy::from_json(json).expect("from_json");
212 assert_eq!(original, recovered);
213 }
214
215 #[test]
216 fn json_round_trip_prefer_contract_owner() {
217 use crate::serialization::JsonConvertible;
218 let original = GasFeesPaidBy::PreferContractOwner;
219 let json = original.to_json().expect("to_json");
220 assert_eq!(json, json!("PreferContractOwner"));
221 let recovered = GasFeesPaidBy::from_json(json).expect("from_json");
222 assert_eq!(original, recovered);
223 }
224
225 #[test]
226 fn value_round_trip_document_owner() {
227 use crate::serialization::ValueConvertible;
228 let original = GasFeesPaidBy::DocumentOwner;
229 let value = original.to_object().expect("to_object");
230 assert_eq!(value, platform_value!("DocumentOwner"));
231 let recovered = GasFeesPaidBy::from_object(value).expect("from_object");
232 assert_eq!(original, recovered);
233 }
234
235 #[test]
236 fn value_round_trip_contract_owner() {
237 use crate::serialization::ValueConvertible;
238 let original = GasFeesPaidBy::ContractOwner;
239 let value = original.to_object().expect("to_object");
240 assert_eq!(value, platform_value!("ContractOwner"));
241 let recovered = GasFeesPaidBy::from_object(value).expect("from_object");
242 assert_eq!(original, recovered);
243 }
244
245 #[test]
246 fn value_round_trip_prefer_contract_owner() {
247 use crate::serialization::ValueConvertible;
248 let original = GasFeesPaidBy::PreferContractOwner;
249 let value = original.to_object().expect("to_object");
250 assert_eq!(value, platform_value!("PreferContractOwner"));
251 let recovered = GasFeesPaidBy::from_object(value).expect("from_object");
252 assert_eq!(original, recovered);
253 }
254}