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 pub fn source_account(&self) -> &Option<MuxedAccount> {
38 &self.source_account
39 }
40
41 pub fn source_account_mut(&mut self) -> &mut Option<MuxedAccount> {
43 &mut self.source_account
44 }
45
46 pub fn inflation_destination(&self) -> &Option<PublicKey> {
48 &self.inflation_destination
49 }
50
51 pub fn inflation_destination_mut(&mut self) -> &mut Option<PublicKey> {
53 &mut self.inflation_destination
54 }
55
56 pub fn clear_flags(&self) -> &Option<AccountFlags> {
58 &self.clear_flags
59 }
60
61 pub fn clear_flags_mut(&mut self) -> &mut Option<AccountFlags> {
63 &mut self.clear_flags
64 }
65
66 pub fn set_flags(&self) -> &Option<AccountFlags> {
68 &self.set_flags
69 }
70
71 pub fn set_flags_mut(&mut self) -> &mut Option<AccountFlags> {
73 &mut self.set_flags
74 }
75
76 pub fn master_weight(&self) -> &Option<u32> {
78 &self.master_weight
79 }
80
81 pub fn master_weight_mut(&mut self) -> &mut Option<u32> {
83 &mut self.master_weight
84 }
85
86 pub fn low_threshold(&self) -> &Option<u32> {
88 &self.low_threshold
89 }
90
91 pub fn low_threshold_mut(&mut self) -> &mut Option<u32> {
93 &mut self.low_threshold
94 }
95
96 pub fn medium_threshold(&self) -> &Option<u32> {
98 &self.medium_threshold
99 }
100
101 pub fn medium_threshold_mut(&mut self) -> &mut Option<u32> {
103 &mut self.medium_threshold
104 }
105
106 pub fn high_threshold(&self) -> &Option<u32> {
108 &self.high_threshold
109 }
110
111 pub fn high_threshold_mut(&mut self) -> &mut Option<u32> {
113 &mut self.high_threshold
114 }
115
116 pub fn home_domain(&self) -> &Option<String> {
118 &self.home_domain
119 }
120
121 pub fn home_domain_mut(&mut self) -> &mut Option<String> {
123 &mut self.home_domain
124 }
125
126 pub fn signer(&self) -> &Option<Signer> {
128 &self.signer
129 }
130
131 pub fn signer_mut(&mut self) -> &mut Option<Signer> {
133 &mut self.signer
134 }
135
136 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 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}