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            encrypted_note: vec![0xFE, 0xED],
93        }
94    }
95
96    fn make_document() -> Document {
97        Document::V0(DocumentV0 {
98            id: Identifier::from([0x11; 32]),
99            owner_id: Identifier::from([0x22; 32]),
100            properties: Default::default(),
101            revision: Some(1),
102            created_at: None,
103            updated_at: None,
104            transferred_at: None,
105            created_at_block_height: None,
106            updated_at_block_height: None,
107            transferred_at_block_height: None,
108            created_at_core_block_height: None,
109            updated_at_core_block_height: None,
110            transferred_at_core_block_height: None,
111            creator_id: None,
112        })
113    }
114
115    fn make_action() -> ShieldedWithdrawalTransitionAction {
116        let v0 = ShieldedWithdrawalTransitionActionV0 {
117            amount: 25000,
118            notes: vec![make_note(), make_note()],
119            anchor: [0x99; 32],
120            core_fee_per_byte: 42,
121            pooling: Pooling::Never,
122            output_script: CoreScript::from_bytes(vec![0x76, 0xA9, 0x14]),
123            fee_amount: 500,
124            current_total_balance: 300000,
125            prepared_withdrawal_document: make_document(),
126        };
127        ShieldedWithdrawalTransitionAction::from(v0)
128    }
129
130    #[test]
131    fn test_from_v0() {
132        let action = make_action();
133        assert!(matches!(action, ShieldedWithdrawalTransitionAction::V0(_)));
134    }
135
136    #[test]
137    fn test_amount() {
138        let action = make_action();
139        assert_eq!(action.amount(), 25000);
140    }
141
142    #[test]
143    fn test_notes() {
144        let action = make_action();
145        let notes = action.notes();
146        assert_eq!(notes.len(), 2);
147        assert_eq!(notes[0].nullifier, [0x77; 32]);
148        assert_eq!(notes[1].cmx, [0x88; 32]);
149    }
150
151    #[test]
152    fn test_anchor() {
153        let action = make_action();
154        assert_eq!(*action.anchor(), [0x99; 32]);
155    }
156
157    #[test]
158    fn test_core_fee_per_byte() {
159        let action = make_action();
160        assert_eq!(action.core_fee_per_byte(), 42);
161    }
162
163    #[test]
164    fn test_pooling() {
165        let action = make_action();
166        assert!(matches!(action.pooling(), Pooling::Never));
167    }
168
169    #[test]
170    fn test_pooling_variants() {
171        let mut v0 = ShieldedWithdrawalTransitionActionV0 {
172            amount: 0,
173            notes: vec![],
174            anchor: [0; 32],
175            core_fee_per_byte: 0,
176            pooling: Pooling::IfAvailable,
177            output_script: CoreScript::from_bytes(vec![]),
178            fee_amount: 0,
179            current_total_balance: 0,
180            prepared_withdrawal_document: make_document(),
181        };
182        let action_if_avail = ShieldedWithdrawalTransitionAction::from(v0.clone());
183        assert!(matches!(action_if_avail.pooling(), Pooling::IfAvailable));
184
185        v0.pooling = Pooling::Standard;
186        let action_standard = ShieldedWithdrawalTransitionAction::from(v0);
187        assert!(matches!(action_standard.pooling(), Pooling::Standard));
188    }
189
190    #[test]
191    fn test_output_script() {
192        let action = make_action();
193        let script = action.output_script();
194        assert_eq!(script.as_bytes(), &[0x76, 0xA9, 0x14]);
195    }
196
197    #[test]
198    fn test_fee_amount() {
199        let action = make_action();
200        assert_eq!(action.fee_amount(), 500);
201    }
202
203    #[test]
204    fn test_prepared_withdrawal_document_ref() {
205        let action = make_action();
206        let doc = action.prepared_withdrawal_document();
207        match doc {
208            Document::V0(v0) => {
209                assert_eq!(v0.id, Identifier::from([0x11; 32]));
210                assert_eq!(v0.owner_id, Identifier::from([0x22; 32]));
211            }
212        }
213    }
214
215    #[test]
216    fn test_prepared_withdrawal_document_owned() {
217        let action = make_action();
218        let doc = action.prepared_withdrawal_document_owned();
219        match doc {
220            Document::V0(v0) => {
221                assert_eq!(v0.id, Identifier::from([0x11; 32]));
222            }
223        }
224    }
225
226    #[test]
227    fn test_clone() {
228        let action = make_action();
229        let cloned = action.clone();
230        assert_eq!(cloned.amount(), 25000);
231        assert_eq!(cloned.fee_amount(), 500);
232        assert_eq!(cloned.core_fee_per_byte(), 42);
233        assert_eq!(cloned.notes().len(), 2);
234    }
235
236    #[test]
237    fn test_debug() {
238        let action = make_action();
239        let debug_str = format!("{:?}", action);
240        assert!(debug_str.contains("V0"));
241    }
242}