Skip to main content

drive/state_transition_action/shielded/shielded_withdrawal/
mod.rs

1/// transformer
2pub mod transformer;
3/// v0
4pub mod v0;
5
6use crate::state_transition_action::shielded::shielded_withdrawal::v0::ShieldedWithdrawalTransitionActionV0;
7use crate::state_transition_action::shielded::ShieldedActionNote;
8use derive_more::From;
9use dpp::document::Document;
10use dpp::fee::Credits;
11use dpp::identity::core_script::CoreScript;
12use dpp::withdrawal::Pooling;
13
14/// Shielded withdrawal transition action
15#[derive(Debug, Clone, From)]
16pub enum ShieldedWithdrawalTransitionAction {
17    /// v0
18    V0(ShieldedWithdrawalTransitionActionV0),
19}
20
21impl ShieldedWithdrawalTransitionAction {
22    /// Get withdrawal amount
23    pub fn amount(&self) -> Credits {
24        match self {
25            ShieldedWithdrawalTransitionAction::V0(transition) => transition.amount,
26        }
27    }
28    /// Get notes
29    pub fn notes(&self) -> &[ShieldedActionNote] {
30        match self {
31            ShieldedWithdrawalTransitionAction::V0(transition) => &transition.notes,
32        }
33    }
34    /// Get anchor
35    pub fn anchor(&self) -> &[u8; 32] {
36        match self {
37            ShieldedWithdrawalTransitionAction::V0(transition) => &transition.anchor,
38        }
39    }
40    /// Get core fee per byte
41    pub fn core_fee_per_byte(&self) -> u32 {
42        match self {
43            ShieldedWithdrawalTransitionAction::V0(transition) => transition.core_fee_per_byte,
44        }
45    }
46    /// Get pooling strategy
47    pub fn pooling(&self) -> Pooling {
48        match self {
49            ShieldedWithdrawalTransitionAction::V0(transition) => transition.pooling,
50        }
51    }
52    /// Get output script
53    pub fn output_script(&self) -> &CoreScript {
54        match self {
55            ShieldedWithdrawalTransitionAction::V0(transition) => &transition.output_script,
56        }
57    }
58    /// Fee amount (value_balance - amount), paid to proposers
59    pub fn fee_amount(&self) -> Credits {
60        match self {
61            ShieldedWithdrawalTransitionAction::V0(transition) => transition.fee_amount,
62        }
63    }
64    /// Get prepared withdrawal document
65    pub fn prepared_withdrawal_document(&self) -> &Document {
66        match self {
67            ShieldedWithdrawalTransitionAction::V0(transition) => {
68                &transition.prepared_withdrawal_document
69            }
70        }
71    }
72    /// Get prepared withdrawal document owned
73    pub fn prepared_withdrawal_document_owned(self) -> Document {
74        match self {
75            ShieldedWithdrawalTransitionAction::V0(transition) => {
76                transition.prepared_withdrawal_document
77            }
78        }
79    }
80}
81
82#[cfg(test)]
83mod tests {
84    use super::*;
85    use dpp::document::DocumentV0;
86    use dpp::prelude::Identifier;
87
88    fn make_note() -> ShieldedActionNote {
89        ShieldedActionNote {
90            nullifier: [0x77; 32],
91            cmx: [0x88; 32],
92            cv_net: [0x22; 32],
93            encrypted_note: vec![0xFE, 0xED],
94        }
95    }
96
97    fn make_document() -> Document {
98        Document::V0(DocumentV0 {
99            id: Identifier::from([0x11; 32]),
100            owner_id: Identifier::from([0x22; 32]),
101            properties: Default::default(),
102            revision: Some(1),
103            created_at: None,
104            updated_at: None,
105            transferred_at: None,
106            created_at_block_height: None,
107            updated_at_block_height: None,
108            transferred_at_block_height: None,
109            created_at_core_block_height: None,
110            updated_at_core_block_height: None,
111            transferred_at_core_block_height: None,
112            creator_id: None,
113        })
114    }
115
116    fn make_action() -> ShieldedWithdrawalTransitionAction {
117        let v0 = ShieldedWithdrawalTransitionActionV0 {
118            amount: 25000,
119            notes: vec![make_note(), make_note()],
120            anchor: [0x99; 32],
121            core_fee_per_byte: 42,
122            pooling: Pooling::Never,
123            output_script: CoreScript::from_bytes(vec![0x76, 0xA9, 0x14]),
124            fee_amount: 500,
125            current_total_balance: 300000,
126            prepared_withdrawal_document: make_document(),
127        };
128        ShieldedWithdrawalTransitionAction::from(v0)
129    }
130
131    #[test]
132    fn test_from_v0() {
133        let action = make_action();
134        assert!(matches!(action, ShieldedWithdrawalTransitionAction::V0(_)));
135    }
136
137    #[test]
138    fn test_amount() {
139        let action = make_action();
140        assert_eq!(action.amount(), 25000);
141    }
142
143    #[test]
144    fn test_notes() {
145        let action = make_action();
146        let notes = action.notes();
147        assert_eq!(notes.len(), 2);
148        assert_eq!(notes[0].nullifier, [0x77; 32]);
149        assert_eq!(notes[1].cmx, [0x88; 32]);
150    }
151
152    #[test]
153    fn test_anchor() {
154        let action = make_action();
155        assert_eq!(*action.anchor(), [0x99; 32]);
156    }
157
158    #[test]
159    fn test_core_fee_per_byte() {
160        let action = make_action();
161        assert_eq!(action.core_fee_per_byte(), 42);
162    }
163
164    #[test]
165    fn test_pooling() {
166        let action = make_action();
167        assert!(matches!(action.pooling(), Pooling::Never));
168    }
169
170    #[test]
171    fn test_pooling_variants() {
172        let mut v0 = ShieldedWithdrawalTransitionActionV0 {
173            amount: 0,
174            notes: vec![],
175            anchor: [0; 32],
176            core_fee_per_byte: 0,
177            pooling: Pooling::IfAvailable,
178            output_script: CoreScript::from_bytes(vec![]),
179            fee_amount: 0,
180            current_total_balance: 0,
181            prepared_withdrawal_document: make_document(),
182        };
183        let action_if_avail = ShieldedWithdrawalTransitionAction::from(v0.clone());
184        assert!(matches!(action_if_avail.pooling(), Pooling::IfAvailable));
185
186        v0.pooling = Pooling::Standard;
187        let action_standard = ShieldedWithdrawalTransitionAction::from(v0);
188        assert!(matches!(action_standard.pooling(), Pooling::Standard));
189    }
190
191    #[test]
192    fn test_output_script() {
193        let action = make_action();
194        let script = action.output_script();
195        assert_eq!(script.as_bytes(), &[0x76, 0xA9, 0x14]);
196    }
197
198    #[test]
199    fn test_fee_amount() {
200        let action = make_action();
201        assert_eq!(action.fee_amount(), 500);
202    }
203
204    #[test]
205    fn test_prepared_withdrawal_document_ref() {
206        let action = make_action();
207        let doc = action.prepared_withdrawal_document();
208        match doc {
209            Document::V0(v0) => {
210                assert_eq!(v0.id, Identifier::from([0x11; 32]));
211                assert_eq!(v0.owner_id, Identifier::from([0x22; 32]));
212            }
213        }
214    }
215
216    #[test]
217    fn test_prepared_withdrawal_document_owned() {
218        let action = make_action();
219        let doc = action.prepared_withdrawal_document_owned();
220        match doc {
221            Document::V0(v0) => {
222                assert_eq!(v0.id, Identifier::from([0x11; 32]));
223            }
224        }
225    }
226
227    #[test]
228    fn test_clone() {
229        let action = make_action();
230        let cloned = action.clone();
231        assert_eq!(cloned.amount(), 25000);
232        assert_eq!(cloned.fee_amount(), 500);
233        assert_eq!(cloned.core_fee_per_byte(), 42);
234        assert_eq!(cloned.notes().len(), 2);
235    }
236
237    #[test]
238    fn test_debug() {
239        let action = make_action();
240        let debug_str = format!("{:?}", action);
241        assert!(debug_str.contains("V0"));
242    }
243}