dpp/address_funds/fee_strategy/
mod.rs1pub mod deduct_fee_from_inputs_and_outputs;
2
3pub use deduct_fee_from_inputs_and_outputs::FeeDeductionResult;
4
5use bincode::{Decode, Encode};
6#[cfg(feature = "serde-conversion")]
7use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq, Hash)]
10pub enum AddressFundsFeeStrategyStep {
11 DeductFromInput(u16),
14 ReduceOutput(u16),
17}
18
19impl Default for AddressFundsFeeStrategyStep {
20 fn default() -> Self {
21 AddressFundsFeeStrategyStep::DeductFromInput(0)
22 }
23}
24
25pub type AddressFundsFeeStrategy = Vec<AddressFundsFeeStrategyStep>;
26
27#[cfg(feature = "serde-conversion")]
32impl Serialize for AddressFundsFeeStrategyStep {
33 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
34 where
35 S: serde::Serializer,
36 {
37 use serde::ser::SerializeStruct;
38
39 let mut state = serializer.serialize_struct("AddressFundsFeeStrategyStep", 2)?;
40 match self {
41 AddressFundsFeeStrategyStep::DeductFromInput(index) => {
42 state.serialize_field("type", "deductFromInput")?;
43 state.serialize_field("index", index)?;
44 }
45 AddressFundsFeeStrategyStep::ReduceOutput(index) => {
46 state.serialize_field("type", "reduceOutput")?;
47 state.serialize_field("index", index)?;
48 }
49 }
50 state.end()
51 }
52}
53
54#[cfg(feature = "serde-conversion")]
55impl<'de> Deserialize<'de> for AddressFundsFeeStrategyStep {
56 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
57 where
58 D: serde::Deserializer<'de>,
59 {
60 use serde::de::{self, MapAccess, Visitor};
61 use std::fmt;
62
63 struct StepVisitor;
64
65 impl<'de> Visitor<'de> for StepVisitor {
66 type Value = AddressFundsFeeStrategyStep;
67
68 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
69 formatter.write_str("an AddressFundsFeeStrategyStep struct with type and index")
70 }
71
72 fn visit_map<V>(self, mut map: V) -> Result<AddressFundsFeeStrategyStep, V::Error>
73 where
74 V: MapAccess<'de>,
75 {
76 let mut step_type: Option<String> = None;
77 let mut index: Option<u16> = None;
78
79 while let Some(key) = map.next_key::<String>()? {
80 match key.as_str() {
81 "type" => {
82 if step_type.is_some() {
83 return Err(de::Error::duplicate_field("type"));
84 }
85 step_type = Some(map.next_value()?);
86 }
87 "index" => {
88 if index.is_some() {
89 return Err(de::Error::duplicate_field("index"));
90 }
91 index = Some(map.next_value()?);
92 }
93 _ => {
94 let _: serde::de::IgnoredAny = map.next_value()?;
95 }
96 }
97 }
98
99 let step_type = step_type.ok_or_else(|| de::Error::missing_field("type"))?;
100 let index = index.ok_or_else(|| de::Error::missing_field("index"))?;
101
102 match step_type.as_str() {
103 "deductFromInput" => Ok(AddressFundsFeeStrategyStep::DeductFromInput(index)),
104 "reduceOutput" => Ok(AddressFundsFeeStrategyStep::ReduceOutput(index)),
105 other => Err(de::Error::unknown_variant(
106 other,
107 &["deductFromInput", "reduceOutput"],
108 )),
109 }
110 }
111 }
112
113 deserializer.deserialize_struct(
114 "AddressFundsFeeStrategyStep",
115 &["type", "index"],
116 StepVisitor,
117 )
118 }
119}
120
121#[cfg(all(test, feature = "serde-conversion"))]
122mod tests {
123 use super::*;
124
125 #[test]
126 fn deduct_from_input_serializes_with_type_and_index() {
127 let step = AddressFundsFeeStrategyStep::DeductFromInput(7);
128 let json = serde_json::to_value(&step).unwrap();
129 assert_eq!(
130 json,
131 serde_json::json!({ "type": "deductFromInput", "index": 7 })
132 );
133 }
134
135 #[test]
136 fn reduce_output_serializes_with_type_and_index() {
137 let step = AddressFundsFeeStrategyStep::ReduceOutput(3);
138 let json = serde_json::to_value(&step).unwrap();
139 assert_eq!(
140 json,
141 serde_json::json!({ "type": "reduceOutput", "index": 3 })
142 );
143 }
144
145 #[test]
146 fn deserializes_from_type_and_index() {
147 let step: AddressFundsFeeStrategyStep =
148 serde_json::from_value(serde_json::json!({ "type": "deductFromInput", "index": 9 }))
149 .unwrap();
150 assert_eq!(step, AddressFundsFeeStrategyStep::DeductFromInput(9));
151
152 let step: AddressFundsFeeStrategyStep =
153 serde_json::from_value(serde_json::json!({ "type": "reduceOutput", "index": 2 }))
154 .unwrap();
155 assert_eq!(step, AddressFundsFeeStrategyStep::ReduceOutput(2));
156 }
157
158 #[test]
159 fn rejects_unknown_variant() {
160 let result: Result<AddressFundsFeeStrategyStep, _> =
161 serde_json::from_value(serde_json::json!({ "type": "burn", "index": 0 }));
162 assert!(result.is_err());
163 }
164
165 #[test]
166 fn round_trips_through_json() {
167 for original in [
168 AddressFundsFeeStrategyStep::DeductFromInput(0),
169 AddressFundsFeeStrategyStep::DeductFromInput(42),
170 AddressFundsFeeStrategyStep::ReduceOutput(0),
171 AddressFundsFeeStrategyStep::ReduceOutput(42),
172 ] {
173 let json = serde_json::to_string(&original).unwrap();
174 let restored: AddressFundsFeeStrategyStep = serde_json::from_str(&json).unwrap();
175 assert_eq!(original, restored);
176 }
177 }
178}