stellar_base/operations/
set_options.rs

1use crate::account::AccountFlags;
2use crate::crypto::{MuxedAccount, PublicKey, Signer};
3use crate::error::{Error, Result};
4use crate::operations::Operation;
5use crate::xdr;
6
7#[derive(Debug, Clone, PartialEq, Eq)]
8pub struct SetOptionsOperation {
9    source_account: Option<MuxedAccount>,
10    inflation_destination: Option<PublicKey>,
11    clear_flags: Option<AccountFlags>,
12    set_flags: Option<AccountFlags>,
13    master_weight: Option<u32>,
14    low_threshold: Option<u32>,
15    medium_threshold: Option<u32>,
16    high_threshold: Option<u32>,
17    home_domain: Option<String>,
18    signer: Option<Signer>,
19}
20
21#[derive(Debug, Default)]
22pub struct SetOptionsOperationBuilder {
23    source_account: Option<MuxedAccount>,
24    inflation_destination: Option<PublicKey>,
25    clear_flags: Option<AccountFlags>,
26    set_flags: Option<AccountFlags>,
27    master_weight: Option<u32>,
28    low_threshold: Option<u32>,
29    medium_threshold: Option<u32>,
30    high_threshold: Option<u32>,
31    home_domain: Option<String>,
32    signer: Option<Signer>,
33}
34
35impl SetOptionsOperation {
36    /// Retrieves the operation source account.
37    pub fn source_account(&self) -> &Option<MuxedAccount> {
38        &self.source_account
39    }
40
41    /// Retrieves a reference to the operation source account.
42    pub fn source_account_mut(&mut self) -> &mut Option<MuxedAccount> {
43        &mut self.source_account
44    }
45
46    /// Retrieves the operation inflation destination.
47    pub fn inflation_destination(&self) -> &Option<PublicKey> {
48        &self.inflation_destination
49    }
50
51    /// Retrieves a mutable reference to the operation inflation destination.
52    pub fn inflation_destination_mut(&mut self) -> &mut Option<PublicKey> {
53        &mut self.inflation_destination
54    }
55
56    /// Retrieves the operation clear flags.
57    pub fn clear_flags(&self) -> &Option<AccountFlags> {
58        &self.clear_flags
59    }
60
61    /// Retrieves a mutable reference to the operation clear flags.
62    pub fn clear_flags_mut(&mut self) -> &mut Option<AccountFlags> {
63        &mut self.clear_flags
64    }
65
66    /// Retrieves the operation set flags.
67    pub fn set_flags(&self) -> &Option<AccountFlags> {
68        &self.set_flags
69    }
70
71    /// Retrieves a mutable reference to the operation set flags.
72    pub fn set_flags_mut(&mut self) -> &mut Option<AccountFlags> {
73        &mut self.set_flags
74    }
75
76    /// Retrieves the operation master weight.
77    pub fn master_weight(&self) -> &Option<u32> {
78        &self.master_weight
79    }
80
81    /// Retrieves a mutable reference to the operation master weight.
82    pub fn master_weight_mut(&mut self) -> &mut Option<u32> {
83        &mut self.master_weight
84    }
85
86    /// Retrieves the operation low threshold.
87    pub fn low_threshold(&self) -> &Option<u32> {
88        &self.low_threshold
89    }
90
91    /// Retrieves a mutable reference to the operation low threshold.
92    pub fn low_threshold_mut(&mut self) -> &mut Option<u32> {
93        &mut self.low_threshold
94    }
95
96    /// Retrieves the operation medium threshold.
97    pub fn medium_threshold(&self) -> &Option<u32> {
98        &self.medium_threshold
99    }
100
101    /// Retrieves a mutable reference to the operation medium threshold.
102    pub fn medium_threshold_mut(&mut self) -> &mut Option<u32> {
103        &mut self.medium_threshold
104    }
105
106    /// Retrieves the operation high threshold.
107    pub fn high_threshold(&self) -> &Option<u32> {
108        &self.high_threshold
109    }
110
111    /// Retrieves a mutable reference to the operation high threshold.
112    pub fn high_threshold_mut(&mut self) -> &mut Option<u32> {
113        &mut self.high_threshold
114    }
115
116    /// Retrieves the operation home domain.
117    pub fn home_domain(&self) -> &Option<String> {
118        &self.home_domain
119    }
120
121    /// Retrieves a mutable reference to the operation home domain.
122    pub fn home_domain_mut(&mut self) -> &mut Option<String> {
123        &mut self.home_domain
124    }
125
126    /// Retrieves the operation signer.
127    pub fn signer(&self) -> &Option<Signer> {
128        &self.signer
129    }
130
131    /// Retrieves a mutable reference the operation signer.
132    pub fn signer_mut(&mut self) -> &mut Option<Signer> {
133        &mut self.signer
134    }
135
136    /// Returns the xdr operation body.
137    pub fn to_xdr_operation_body(&self) -> Result<xdr::OperationBody> {
138        let inflation_dest = self
139            .inflation_destination
140            .as_ref()
141            .map(|d| d.to_xdr_account_id())
142            .transpose()?;
143        let clear_flags = self.clear_flags.map(|f| f.bits());
144        let set_flags = self.set_flags.map(|f| f.bits());
145        let signer = self.signer.as_ref().map(|s| s.to_xdr()).transpose()?;
146
147        let home_domain: Option<xdr::String32> = match &self.home_domain {
148            Some(home_domain) => {
149                if home_domain.len() > 32 {
150                    return Err(Error::HomeDomainTooLong);
151                }
152                Some(home_domain.as_bytes().to_vec().try_into().unwrap())
153            }
154            None => None,
155        };
156
157        let inner = xdr::SetOptionsOp {
158            inflation_dest,
159            clear_flags,
160            set_flags,
161            master_weight: self.master_weight,
162            low_threshold: self.low_threshold,
163            med_threshold: self.medium_threshold,
164            high_threshold: self.high_threshold,
165            home_domain,
166            signer,
167        };
168
169        Ok(xdr::OperationBody::SetOptions(inner))
170    }
171
172    /// Creates from the xdr operation body.
173    pub fn from_xdr_operation_body(
174        source_account: Option<MuxedAccount>,
175        x: &xdr::SetOptionsOp,
176    ) -> Result<SetOptionsOperation> {
177        let inflation_destination = x
178            .inflation_dest
179            .as_ref()
180            .map(PublicKey::from_xdr_account_id)
181            .transpose()?;
182        let clear_flags = x
183            .clear_flags
184            .map(|f| AccountFlags::from_bits(f).ok_or(Error::InvalidAccountFlags))
185            .transpose()?;
186        let set_flags = x
187            .set_flags
188            .map(|f| AccountFlags::from_bits(f).ok_or(Error::InvalidAccountFlags))
189            .transpose()?;
190        let home_domain = x.home_domain.as_ref().map(|h| h.to_string());
191        let signer = x.signer.as_ref().map(Signer::from_xdr).transpose()?;
192        Ok(SetOptionsOperation {
193            source_account,
194            inflation_destination,
195            clear_flags,
196            set_flags,
197            master_weight: x.master_weight,
198            low_threshold: x.low_threshold,
199            medium_threshold: x.med_threshold,
200            high_threshold: x.high_threshold,
201            home_domain,
202            signer,
203        })
204    }
205}
206
207impl SetOptionsOperationBuilder {
208    pub fn new() -> SetOptionsOperationBuilder {
209        Default::default()
210    }
211
212    pub fn with_source_account<S>(mut self, source: S) -> SetOptionsOperationBuilder
213    where
214        S: Into<MuxedAccount>,
215    {
216        self.source_account = Some(source.into());
217        self
218    }
219
220    pub fn with_inflation_destination(
221        mut self,
222        destination: Option<PublicKey>,
223    ) -> SetOptionsOperationBuilder {
224        self.inflation_destination = destination;
225        self
226    }
227
228    pub fn with_clear_flags(mut self, flags: Option<AccountFlags>) -> SetOptionsOperationBuilder {
229        self.clear_flags = flags;
230        self
231    }
232
233    pub fn with_set_flags(mut self, flags: Option<AccountFlags>) -> SetOptionsOperationBuilder {
234        self.set_flags = flags;
235        self
236    }
237
238    pub fn with_master_weight(mut self, weight: Option<u32>) -> SetOptionsOperationBuilder {
239        self.master_weight = weight;
240        self
241    }
242
243    pub fn with_low_threshold(mut self, weight: Option<u32>) -> SetOptionsOperationBuilder {
244        self.low_threshold = weight;
245        self
246    }
247    pub fn with_medium_threshold(mut self, weight: Option<u32>) -> SetOptionsOperationBuilder {
248        self.medium_threshold = weight;
249        self
250    }
251
252    pub fn with_high_threshold(mut self, weight: Option<u32>) -> SetOptionsOperationBuilder {
253        self.high_threshold = weight;
254        self
255    }
256
257    pub fn with_signer(mut self, signer: Option<Signer>) -> SetOptionsOperationBuilder {
258        self.signer = signer;
259        self
260    }
261
262    pub fn build(self) -> Result<Operation> {
263        Ok(Operation::SetOptions(SetOptionsOperation {
264            source_account: self.source_account,
265            inflation_destination: self.inflation_destination,
266            clear_flags: self.clear_flags,
267            set_flags: self.set_flags,
268            master_weight: self.master_weight,
269            low_threshold: self.low_threshold,
270            medium_threshold: self.medium_threshold,
271            high_threshold: self.high_threshold,
272            home_domain: self.home_domain,
273            signer: self.signer,
274        }))
275    }
276}
277
278#[cfg(test)]
279mod tests {
280    use crate::account::AccountFlags;
281    use crate::crypto::{Signer, SignerKey};
282    use crate::network::Network;
283    use crate::operations::tests::*;
284    use crate::operations::Operation;
285    use crate::transaction::{Transaction, TransactionEnvelope, MIN_BASE_FEE};
286    use crate::xdr::{XDRDeserialize, XDRSerialize};
287
288    #[test]
289    fn test_set_options() {
290        let kp = keypair0();
291        let kp1 = keypair1();
292
293        let op = Operation::new_set_options()
294            .with_inflation_destination(Some(kp1.public_key()))
295            .with_set_flags(Some(
296                AccountFlags::AUTH_REQUIRED | AccountFlags::AUTH_IMMUTABLE,
297            ))
298            .build()
299            .unwrap();
300        let mut tx = Transaction::builder(kp.public_key(), 3556091187167235, MIN_BASE_FEE)
301            .add_operation(op)
302            .into_transaction()
303            .unwrap();
304        tx.sign(kp.as_ref(), &Network::new_test()).unwrap();
305        let envelope = tx.to_envelope();
306        let xdr = envelope.xdr_base64().unwrap();
307        let expected = "AAAAAgAAAADg3G3hclysZlFitS+s5zWyiiJD5B0STWy5LXCj6i5yxQAAAGQADKI/AAAAAwAAAAAAAAAAAAAAAQAAAAAAAAAFAAAAAQAAAAAlyvHaD8duz+iEXkJUUbsHkklIlH46oMrMMYrt0odkfgAAAAAAAAABAAAABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB6i5yxQAAAEBtYhsjGguNMF06uqEn/cUIdy9eAp/X2jlhTRiVcIGUQJ2U/45eFGXZ8AjgE5P/fWoQYlsUihurccOMwu891EAD";
308        assert_eq!(expected, xdr);
309        let back = TransactionEnvelope::from_xdr_base64(&xdr).unwrap();
310        assert_eq!(envelope, back);
311    }
312
313    #[test]
314    fn test_set_options_with_source_account() {
315        let kp = keypair0();
316        let kp2 = keypair2();
317
318        let op = Operation::new_set_options()
319            .with_source_account(kp2.public_key())
320            .build()
321            .unwrap();
322        let mut tx = Transaction::builder(kp.public_key(), 3556091187167235, MIN_BASE_FEE)
323            .add_operation(op)
324            .into_transaction()
325            .unwrap();
326        tx.sign(kp.as_ref(), &Network::new_test()).unwrap();
327        let envelope = tx.to_envelope();
328        let xdr = envelope.xdr_base64().unwrap();
329        let expected = "AAAAAgAAAADg3G3hclysZlFitS+s5zWyiiJD5B0STWy5LXCj6i5yxQAAAGQADKI/AAAAAwAAAAAAAAAAAAAAAQAAAAEAAAAAfhHLNNY19eGrAtSgLD3VpaRm2AjNjxIBWQg9zS4VWZgAAAAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHqLnLFAAAAQBf+wJNmYicge0JOI5iRVzprRG7AXpfQWCHRCIjqiXvJ0MRv71eSyPdJgUVlcStKM8prTF2TPuO8uWPk2kIRKAo=";
330        assert_eq!(expected, xdr);
331        let back = TransactionEnvelope::from_xdr_base64(&xdr).unwrap();
332        assert_eq!(envelope, back);
333    }
334
335    #[test]
336    fn test_set_options_with_set_flags() {
337        let kp = keypair0();
338
339        let op = Operation::new_set_options()
340            .with_set_flags(Some(
341                AccountFlags::AUTH_REQUIRED | AccountFlags::AUTH_IMMUTABLE,
342            ))
343            .build()
344            .unwrap();
345        let mut tx = Transaction::builder(kp.public_key(), 3556091187167235, MIN_BASE_FEE)
346            .add_operation(op)
347            .into_transaction()
348            .unwrap();
349        tx.sign(kp.as_ref(), &Network::new_test()).unwrap();
350        let envelope = tx.to_envelope();
351        let xdr = envelope.xdr_base64().unwrap();
352        let expected = "AAAAAgAAAADg3G3hclysZlFitS+s5zWyiiJD5B0STWy5LXCj6i5yxQAAAGQADKI/AAAAAwAAAAAAAAAAAAAAAQAAAAAAAAAFAAAAAAAAAAAAAAABAAAABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB6i5yxQAAAECKOes75G40HX5JiVxydn+pu/DTZSGRf0A9eKdDXdS3Znog4kDjnw0vgZ7efMGl8NYW165N13sBub8Dnrc1E+MA";
353        assert_eq!(expected, xdr);
354        let back = TransactionEnvelope::from_xdr_base64(&xdr).unwrap();
355        assert_eq!(envelope, back);
356    }
357
358    #[test]
359    fn test_set_options_with_clear_flags() {
360        let kp = keypair0();
361
362        let op = Operation::new_set_options()
363            .with_clear_flags(Some(
364                AccountFlags::AUTH_REQUIRED | AccountFlags::AUTH_IMMUTABLE,
365            ))
366            .build()
367            .unwrap();
368        let mut tx = Transaction::builder(kp.public_key(), 3556091187167235, MIN_BASE_FEE)
369            .add_operation(op)
370            .into_transaction()
371            .unwrap();
372        tx.sign(kp.as_ref(), &Network::new_test()).unwrap();
373        let envelope = tx.to_envelope();
374        let xdr = envelope.xdr_base64().unwrap();
375        let expected = "AAAAAgAAAADg3G3hclysZlFitS+s5zWyiiJD5B0STWy5LXCj6i5yxQAAAGQADKI/AAAAAwAAAAAAAAAAAAAAAQAAAAAAAAAFAAAAAAAAAAEAAAAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB6i5yxQAAAEAXg+D6BNKJyRzCHu2np0PSWoAcFanuZa2gfS8a1iAB62buUwxezc/RULixb5W2rQwBxbSyaIrFA/3QJBf480UA";
376        assert_eq!(expected, xdr);
377        let back = TransactionEnvelope::from_xdr_base64(&xdr).unwrap();
378        assert_eq!(envelope, back);
379    }
380
381    #[test]
382    fn test_set_options_with_weights() {
383        let kp = keypair0();
384
385        let op = Operation::new_set_options()
386            .with_master_weight(Some(1))
387            .with_low_threshold(Some(2))
388            .with_medium_threshold(Some(3))
389            .with_high_threshold(Some(4))
390            .build()
391            .unwrap();
392        let mut tx = Transaction::builder(kp.public_key(), 3556091187167235, MIN_BASE_FEE)
393            .add_operation(op)
394            .into_transaction()
395            .unwrap();
396        tx.sign(kp.as_ref(), &Network::new_test()).unwrap();
397        let envelope = tx.to_envelope();
398        let xdr = envelope.xdr_base64().unwrap();
399        let expected = "AAAAAgAAAADg3G3hclysZlFitS+s5zWyiiJD5B0STWy5LXCj6i5yxQAAAGQADKI/AAAAAwAAAAAAAAAAAAAAAQAAAAAAAAAFAAAAAAAAAAAAAAAAAAAAAQAAAAEAAAABAAAAAgAAAAEAAAADAAAAAQAAAAQAAAAAAAAAAAAAAAAAAAAB6i5yxQAAAECfQ+WZfpgizILpZL84nvzoDM5+JMQOlA0+9FQZjj6Xr+njvLP/84HFz+lgK3/orX/1MdoBQb61sybrfC1kjdcA";
400        assert_eq!(expected, xdr);
401        let back = TransactionEnvelope::from_xdr_base64(&xdr).unwrap();
402        assert_eq!(envelope, back);
403    }
404
405    #[test]
406    fn test_set_options_with_signer() {
407        let kp = keypair0();
408        let kp2 = keypair2();
409
410        let signer_key = SignerKey::Ed25519(kp2.public_key());
411        let signer = Signer::new(signer_key, 8);
412
413        let op = Operation::new_set_options()
414            .with_signer(Some(signer))
415            .build()
416            .unwrap();
417        let mut tx = Transaction::builder(kp.public_key(), 3556091187167235, MIN_BASE_FEE)
418            .add_operation(op)
419            .into_transaction()
420            .unwrap();
421        tx.sign(kp.as_ref(), &Network::new_test()).unwrap();
422        let envelope = tx.to_envelope();
423        let xdr = envelope.xdr_base64().unwrap();
424        let expected = "AAAAAgAAAADg3G3hclysZlFitS+s5zWyiiJD5B0STWy5LXCj6i5yxQAAAGQADKI/AAAAAwAAAAAAAAAAAAAAAQAAAAAAAAAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAH4RyzTWNfXhqwLUoCw91aWkZtgIzY8SAVkIPc0uFVmYAAAACAAAAAAAAAAB6i5yxQAAAEDlGdxaTcfjFp4ukgepGrUe2ALXJZvDRBIGWw3ROBsQlxFV9kgx2YvszPy4DWtXQNvc3i0KxrUrR+r2liPGr/QJ";
425        assert_eq!(expected, xdr);
426        let back = TransactionEnvelope::from_xdr_base64(&xdr).unwrap();
427        assert_eq!(envelope, back);
428    }
429}