stellar_base/
transaction.rs

1//! Transaction that changes the ledger state.
2use std::io::{Read, Write};
3
4use crate::amount::Stroops;
5use crate::crypto::{
6    hash, DecoratedSignature, Ed25519Signer, Ed25519Verifier, KeyPair, MuxedAccount,
7};
8use crate::error::{Error, Result};
9use crate::memo::Memo;
10use crate::network::Network;
11use crate::operations::Operation;
12use crate::time_bounds::TimeBounds;
13use crate::{xdr, PublicKey};
14use ed25519::Signature;
15
16/// Minimum base fee.
17pub const MIN_BASE_FEE: Stroops = Stroops(100);
18
19/// Stellar transaction.
20#[derive(Debug, Clone, PartialEq, Eq)]
21pub struct Transaction {
22    source_account: MuxedAccount,
23    fee: Stroops,
24    sequence: i64,
25    time_bounds: Option<TimeBounds>,
26    memo: Memo,
27    operations: Vec<Operation>,
28    signatures: Vec<DecoratedSignature>,
29}
30
31/// Fee bump transaction.
32#[derive(Debug, Clone, PartialEq, Eq)]
33pub struct FeeBumpTransaction {
34    fee_source: MuxedAccount,
35    fee: Stroops,
36    inner_tx: Transaction,
37    signatures: Vec<DecoratedSignature>,
38}
39
40/// Transaction envelope.
41#[derive(Debug, Clone, PartialEq, Eq)]
42pub enum TransactionEnvelope {
43    /// Transaction
44    Transaction(Transaction),
45    /// Fee bump transaction.
46    FeeBumpTransaction(FeeBumpTransaction),
47}
48
49/// A builder to construct the properties of a `Transaction`.
50pub struct TransactionBuilder {
51    base_fee: Stroops,
52    tx: Result<Transaction>,
53}
54
55impl Transaction {
56    /// Creates a `TransactionBuilder` to configure a `Transaction`.
57    ///
58    /// This is the same as `TransactionBuilder::new`.
59    pub fn builder<S: Into<MuxedAccount>>(
60        source_account: S,
61        sequence: i64,
62        fee: Stroops,
63    ) -> TransactionBuilder {
64        TransactionBuilder::new(source_account, sequence, fee)
65    }
66
67    /// Retrieves the transaction source account.
68    pub fn source_account(&self) -> &MuxedAccount {
69        &self.source_account
70    }
71
72    /// Retrieves a mutable reference to the transaction source account.
73    pub fn source_account_mut(&mut self) -> &mut MuxedAccount {
74        &mut self.source_account
75    }
76
77    /// Retrieves the transaction fee.
78    pub fn fee(&self) -> &Stroops {
79        &self.fee
80    }
81
82    /// Retrieves a mutable reference to the transaction fee.
83    pub fn fee_mut(&mut self) -> &mut Stroops {
84        &mut self.fee
85    }
86
87    /// Retrieves the transaction sequence number.
88    pub fn sequence(&self) -> &i64 {
89        &self.sequence
90    }
91
92    /// Retrieves a mutable reference to the transaction sequence number.
93    pub fn sequence_mut(&mut self) -> &mut i64 {
94        &mut self.sequence
95    }
96
97    /// Retrieves the transaction time bounds.
98    pub fn time_bounds(&self) -> &Option<TimeBounds> {
99        &self.time_bounds
100    }
101
102    /// Retrieves a mutable reference to the transaction time bounds.
103    pub fn time_bounds_mut(&mut self) -> &mut Option<TimeBounds> {
104        &mut self.time_bounds
105    }
106
107    /// Retrieves the transaction memo.
108    pub fn memo(&self) -> &Memo {
109        &self.memo
110    }
111
112    /// Retrieves a mutable reference to the transaction memo.
113    pub fn memo_mut(&mut self) -> &mut Memo {
114        &mut self.memo
115    }
116
117    /// Retrieves the transaction operations.
118    pub fn operations(&self) -> &Vec<Operation> {
119        &self.operations
120    }
121
122    /// Retrieves a mutable reference to the transaction operations.
123    pub fn operations_mut(&mut self) -> &mut Vec<Operation> {
124        &mut self.operations
125    }
126
127    /// Retrieves the transaction signatures.
128    pub fn signatures(&self) -> &Vec<DecoratedSignature> {
129        &self.signatures
130    }
131
132    /// Retrieves a mutable reference to the transaction signatures.
133    pub fn signatures_mut(&mut self) -> &mut Vec<DecoratedSignature> {
134        &mut self.signatures
135    }
136
137    /// Creates a `TransactionEnvelope` from the transaction.
138    pub fn to_envelope(&self) -> TransactionEnvelope {
139        self.clone().into_envelope()
140    }
141
142    /// Creates a `TransactionEnvelope` from the transaction.
143    ///
144    /// This consumes the transaction and takes ownership of it.
145    pub fn into_envelope(self) -> TransactionEnvelope {
146        TransactionEnvelope::Transaction(self)
147    }
148
149    /// Sign transaction with `preimage`, and add signature.
150    ///
151    /// This signs the transaction with the preimage `x` of `hash(x)`.
152    pub fn sign_hashx(&mut self, preimage: &[u8]) -> Result<()> {
153        let signature = self.decorated_signature_from_preimage(preimage)?;
154        self.signatures.push(signature);
155        Ok(())
156    }
157
158    /// Sign transaction with `key` for `network`, and add signature.
159    pub fn sign<S, V>(&mut self, key: &KeyPair<S, V>, network: &Network) -> Result<()>
160    where
161        S: Ed25519Signer<Signature>,
162        V: Ed25519Verifier<Signature> + AsRef<[u8]>,
163    {
164        let signature = self.decorated_signature(key, network)?;
165        self.signatures.push(signature);
166        Ok(())
167    }
168
169    /// Returns the decorated signature of the transaction create with `image`.
170    pub fn decorated_signature_from_preimage(&self, preimage: &[u8]) -> Result<DecoratedSignature> {
171        DecoratedSignature::new_from_preimage(preimage)
172    }
173
174    /// Returns the decorated signature of the transaction create with `key` for `network`.
175    pub fn decorated_signature<S, V>(
176        &self,
177        key: &KeyPair<S, V>,
178        network: &Network,
179    ) -> Result<DecoratedSignature>
180    where
181        S: Ed25519Signer<Signature>,
182        V: Ed25519Verifier<Signature> + AsRef<[u8]>,
183    {
184        let tx_hash = self.hash(network)?;
185        Ok(key.sign_decorated(&tx_hash))
186    }
187
188    /// Returns the transaction hash for the transaction on `network`.
189    pub fn hash(&self, network: &Network) -> Result<Vec<u8>> {
190        let signature_data = self.signature_data(network)?;
191        Ok(hash(&signature_data))
192    }
193
194    /// Returns the transaction signature data as bytes.
195    pub fn signature_data(&self, network: &Network) -> Result<Vec<u8>> {
196        let mut base = Vec::new();
197        let tx_signature_payload = self.to_xdr_transaction_signature_payload(network)?;
198        xdr::XDRSerialize::write_xdr(&tx_signature_payload, &mut base)?;
199        Ok(base)
200    }
201
202    /// Returns the xdr object.
203    pub fn to_xdr(&self) -> Result<xdr::Transaction> {
204        let source_account = self.source_account.to_xdr()?;
205        let fee = self.fee.to_xdr_uint32()?;
206        let seq_num = xdr::SequenceNumber(self.sequence);
207        let cond = match &self.time_bounds {
208            None => xdr::Preconditions::None,
209            Some(tb) => xdr::Preconditions::Time(tb.to_xdr()?),
210        };
211        let memo = self.memo.to_xdr()?;
212        let mut operations = Vec::new();
213        for operation in self.operations() {
214            let xdr_operation = operation.to_xdr()?;
215            operations.push(xdr_operation);
216        }
217        let ext = xdr::TransactionExt::V0;
218        Ok(xdr::Transaction {
219            source_account,
220            fee,
221            seq_num,
222            cond,
223            memo,
224            operations: operations.try_into().map_err(|_| Error::XdrError)?,
225            ext,
226        })
227    }
228
229    /// Returns the transaction envelope v1 xdr object.
230    pub fn to_xdr_envelope(&self) -> Result<xdr::TransactionV1Envelope> {
231        let tx = self.to_xdr()?;
232        let signatures = signatures_to_xdr(self.signatures())?;
233        Ok(xdr::TransactionV1Envelope { tx, signatures })
234    }
235
236    /// Returns the xdr transaction signature payload object.
237    pub fn to_xdr_transaction_signature_payload(
238        &self,
239        network: &Network,
240    ) -> Result<xdr::TransactionSignaturePayload> {
241        let network_id = network
242            .network_id()
243            .try_into()
244            .map_err(|_| Error::XdrError)?;
245        let inner = self.to_xdr()?;
246        let tagged_transaction = xdr::TransactionSignaturePayloadTaggedTransaction::Tx(inner);
247        Ok(xdr::TransactionSignaturePayload {
248            network_id,
249            tagged_transaction,
250        })
251    }
252
253    /// Creates from v0 xdr object.
254    pub fn from_xdr_v0(x: &xdr::TransactionV0) -> Result<Transaction> {
255        let source_account =
256            MuxedAccount::Ed25519(PublicKey::from_slice(&x.source_account_ed25519.0)?);
257        let fee = Stroops::from_xdr_uint32(x.fee)?;
258        let sequence = x.seq_num.0;
259        let time_bounds = match &x.time_bounds {
260            None => None,
261            Some(tb) => Some(TimeBounds::from_xdr(tb)?),
262        };
263        let memo = Memo::from_xdr(&x.memo)?;
264        let mut operations = Vec::new();
265        for operation in x.operations.as_slice() {
266            let xdr_operation = Operation::from_xdr(operation)?;
267            operations.push(xdr_operation);
268        }
269        Ok(Transaction {
270            source_account,
271            fee,
272            sequence,
273            time_bounds,
274            memo,
275            operations,
276            signatures: Vec::new(),
277        })
278    }
279
280    /// Creates from xdr object.
281    pub fn from_xdr(x: &xdr::Transaction) -> Result<Transaction> {
282        let source_account = MuxedAccount::from_xdr(&x.source_account)?;
283        let fee = Stroops::from_xdr_uint32(x.fee)?;
284        let sequence = x.seq_num.0;
285        let time_bounds = match &x.cond {
286            xdr::Preconditions::None => None,
287            xdr::Preconditions::Time(tb) => Some(TimeBounds::from_xdr(tb)?),
288            xdr::Preconditions::V2(_) => return Err(Error::UnsupportedFeature),
289        };
290        let memo = Memo::from_xdr(&x.memo)?;
291        let mut operations = Vec::new();
292        for operation in x.operations.as_slice() {
293            let xdr_operation = Operation::from_xdr(operation)?;
294            operations.push(xdr_operation);
295        }
296        match &x.ext {
297            xdr::TransactionExt::V0 => {}
298            xdr::TransactionExt::V1(_) => return Err(Error::UnsupportedFeature),
299        }
300        Ok(Transaction {
301            source_account,
302            fee,
303            sequence,
304            time_bounds,
305            memo,
306            operations,
307            signatures: Vec::new(),
308        })
309    }
310
311    /// Creates from xdr v0 envelope object.
312    pub fn from_xdr_v0_envelope(x: &xdr::TransactionV0Envelope) -> Result<Transaction> {
313        let mut tx = Self::from_xdr_v0(&x.tx)?;
314        let signatures = signatures_from_xdr(&x.signatures)?;
315        tx.signatures = signatures;
316        Ok(tx)
317    }
318
319    /// Creates from xdr envelope object.
320    pub fn from_xdr_envelope(x: &xdr::TransactionV1Envelope) -> Result<Transaction> {
321        let mut tx = Self::from_xdr(&x.tx)?;
322        let signatures = signatures_from_xdr(&x.signatures)?;
323        tx.signatures = signatures;
324        Ok(tx)
325    }
326}
327
328impl FeeBumpTransaction {
329    /// Creates a new fee bump transaction.
330    pub fn new(
331        fee_source: MuxedAccount,
332        fee: Stroops,
333        inner_tx: Transaction,
334    ) -> FeeBumpTransaction {
335        FeeBumpTransaction {
336            fee_source,
337            fee,
338            inner_tx,
339            signatures: Vec::new(),
340        }
341    }
342
343    /// Retrieves the transaction fee source.
344    pub fn fee_source(&self) -> &MuxedAccount {
345        &self.fee_source
346    }
347
348    /// Retrieves a mutable reference to the transaction fee source.
349    pub fn fee_source_mut(&mut self) -> &mut MuxedAccount {
350        &mut self.fee_source
351    }
352
353    /// Retrievies the transaction fee.
354    pub fn fee(&self) -> &Stroops {
355        &self.fee
356    }
357
358    /// Retrievies a mutable reference to the transaction fee.
359    pub fn fee_mut(&mut self) -> &mut Stroops {
360        &mut self.fee
361    }
362
363    /// Retrieves the transaction inner transaction.
364    pub fn inner_transaction(&self) -> &Transaction {
365        &self.inner_tx
366    }
367
368    /// Retrieves a mutable reference to the transaction inner transaction.
369    pub fn inner_transaction_mut(&mut self) -> &mut Transaction {
370        &mut self.inner_tx
371    }
372
373    /// Retrieves the transaction signatures.
374    pub fn signatures(&self) -> &Vec<DecoratedSignature> {
375        &self.signatures
376    }
377
378    /// Retrieves a mutable reference the transaction signatures.
379    pub fn signatures_mut(&mut self) -> &mut Vec<DecoratedSignature> {
380        &mut self.signatures
381    }
382
383    /// Creates a `TransactionEnvelope` from the transaction.
384    ///
385    /// This consumes the transaction and takes ownership of it.
386    pub fn into_envelope(self) -> TransactionEnvelope {
387        TransactionEnvelope::FeeBumpTransaction(self)
388    }
389
390    /// Creates a `TransactionEnvelope` from the transaction.
391    pub fn to_envelope(&self) -> TransactionEnvelope {
392        self.clone().into_envelope()
393    }
394
395    /// Sign transaction with `preimage`, and add signature.
396    ///
397    /// This signs the transaction with the preimage `x` of `hash(x)`.
398    pub fn sign_hashx(&mut self, preimage: &[u8]) -> Result<()> {
399        let signature = self.decorated_signature_from_preimage(preimage)?;
400        self.signatures.push(signature);
401        Ok(())
402    }
403
404    /// Sign transaction with `key` for `network`, and add signature.
405    pub fn sign<S, V>(&mut self, key: &KeyPair<S, V>, network: &Network) -> Result<()>
406    where
407        S: Ed25519Signer<Signature>,
408        V: Ed25519Verifier<Signature> + AsRef<[u8]>,
409    {
410        let signature = self.decorated_signature(key, network)?;
411        self.signatures.push(signature);
412        Ok(())
413    }
414
415    /// Returns the decorated signature of the transaction create with `image`.
416    pub fn decorated_signature_from_preimage(&self, preimage: &[u8]) -> Result<DecoratedSignature> {
417        DecoratedSignature::new_from_preimage(preimage)
418    }
419
420    /// Returns the decorated signature of the transaction create with `key` for `network`.
421    pub fn decorated_signature<S, V>(
422        &self,
423        key: &KeyPair<S, V>,
424        network: &Network,
425    ) -> Result<DecoratedSignature>
426    where
427        S: Ed25519Signer<Signature>,
428        V: Ed25519Verifier<Signature> + AsRef<[u8]>,
429    {
430        let tx_hash = self.hash(network)?;
431        Ok(key.sign_decorated(&tx_hash))
432    }
433
434    /// Returns the transaction hash for the transaction on `network`.
435    pub fn hash(&self, network: &Network) -> Result<Vec<u8>> {
436        let signature_data = self.signature_data(network)?;
437        Ok(hash(&signature_data))
438    }
439
440    /// Returns the transaction signature data as bytes.
441    pub fn signature_data(&self, network: &Network) -> Result<Vec<u8>> {
442        let mut base = Vec::new();
443        let tx_signature_payload = self.to_xdr_transaction_signature_payload(network)?;
444        xdr::XDRSerialize::write_xdr(&tx_signature_payload, &mut base)?;
445        Ok(base)
446    }
447
448    /// Returns the xdr object.
449    pub fn to_xdr(&self) -> Result<xdr::FeeBumpTransaction> {
450        let fee_source = self.fee_source.to_xdr()?;
451        let fee = self.fee.to_xdr_int64()?;
452        let tx_envelope = self.inner_tx.to_xdr_envelope()?;
453        let inner_tx = xdr::FeeBumpTransactionInnerTx::Tx(tx_envelope);
454        let ext = xdr::FeeBumpTransactionExt::V0;
455        Ok(xdr::FeeBumpTransaction {
456            fee_source,
457            fee,
458            inner_tx,
459            ext,
460        })
461    }
462
463    /// Returns the fee bump transaction envelope xdr object.
464    pub fn to_xdr_envelope(&self) -> Result<xdr::FeeBumpTransactionEnvelope> {
465        let tx = self.to_xdr()?;
466        let signatures = signatures_to_xdr(self.signatures())?;
467        Ok(xdr::FeeBumpTransactionEnvelope { tx, signatures })
468    }
469
470    /// Creates from xdr object.
471    pub fn from_xdr(x: &xdr::FeeBumpTransaction) -> Result<FeeBumpTransaction> {
472        let fee_source = MuxedAccount::from_xdr(&x.fee_source)?;
473        let fee = Stroops::new(x.fee);
474        let inner_tx = match &x.inner_tx {
475            xdr::FeeBumpTransactionInnerTx::Tx(inner_tx) => {
476                Transaction::from_xdr_envelope(inner_tx)?
477            }
478        };
479        Ok(FeeBumpTransaction {
480            fee_source,
481            fee,
482            inner_tx,
483            signatures: Vec::new(),
484        })
485    }
486
487    /// Creates from xdr envelope object.
488    pub fn from_xdr_envelope(x: &xdr::FeeBumpTransactionEnvelope) -> Result<FeeBumpTransaction> {
489        let mut tx = FeeBumpTransaction::from_xdr(&x.tx)?;
490        let signatures = signatures_from_xdr(&x.signatures)?;
491        tx.signatures = signatures;
492        Ok(tx)
493    }
494
495    /// Returns the xdr transaction signature payload object.
496    pub fn to_xdr_transaction_signature_payload(
497        &self,
498        network: &Network,
499    ) -> Result<xdr::TransactionSignaturePayload> {
500        let network_id = network
501            .network_id()
502            .try_into()
503            .map_err(|_| Error::XdrError)?;
504        let inner = self.to_xdr()?;
505        let tagged_transaction =
506            xdr::TransactionSignaturePayloadTaggedTransaction::TxFeeBump(inner);
507        Ok(xdr::TransactionSignaturePayload {
508            network_id,
509            tagged_transaction,
510        })
511    }
512}
513
514impl TransactionEnvelope {
515    /// If the transaction is a Transaction, returns its value. Returns None otherwise.
516    pub fn as_transaction(&self) -> Option<&Transaction> {
517        match *self {
518            TransactionEnvelope::Transaction(ref tx) => Some(tx),
519            _ => None,
520        }
521    }
522
523    /// If the transaction is a Transaction, returns its mutable value. Returns None otherwise.
524    pub fn as_transaction_mut(&mut self) -> Option<&mut Transaction> {
525        match *self {
526            TransactionEnvelope::Transaction(ref mut tx) => Some(tx),
527            _ => None,
528        }
529    }
530
531    /// Returns true if the transaction is a Transaction.
532    pub fn is_transaction(&self) -> bool {
533        self.as_transaction().is_some()
534    }
535
536    /// If the transaction is a FeeBumpTransaction, returns its value. Returns None otherwise.
537    pub fn as_fee_bump_transaction(&self) -> Option<&FeeBumpTransaction> {
538        match *self {
539            TransactionEnvelope::FeeBumpTransaction(ref tx) => Some(tx),
540            _ => None,
541        }
542    }
543
544    /// If the transaction is a FeeBumpTransaction, returns its mutable value. Returns None otherwise.
545    pub fn as_fee_bump_transaction_mut(&mut self) -> Option<&mut FeeBumpTransaction> {
546        match *self {
547            TransactionEnvelope::FeeBumpTransaction(ref mut tx) => Some(tx),
548            _ => None,
549        }
550    }
551
552    /// Returns true if the transaction is a FeeBumpTransaction.
553    pub fn is_fee_bump_transaction(&self) -> bool {
554        self.as_fee_bump_transaction().is_some()
555    }
556
557    /// Sign transaction with `preimage`, and add signature.
558    ///
559    /// This signs the transaction with the preimage `x` of `hash(x)`.
560    pub fn sign_hashx(&mut self, preimage: &[u8]) -> Result<()> {
561        match self {
562            TransactionEnvelope::Transaction(tx) => tx.sign_hashx(preimage),
563            TransactionEnvelope::FeeBumpTransaction(tx) => tx.sign_hashx(preimage),
564        }
565    }
566
567    /// Sign transaction with `key` for `network`, and add signature.
568    pub fn sign<S, V>(&mut self, key: &KeyPair<S, V>, network: &Network) -> Result<()>
569    where
570        S: Ed25519Signer<Signature>,
571        V: Ed25519Verifier<Signature> + AsRef<[u8]>,
572    {
573        match self {
574            TransactionEnvelope::Transaction(tx) => tx.sign(key, network),
575            TransactionEnvelope::FeeBumpTransaction(tx) => tx.sign(key, network),
576        }
577    }
578
579    /// Returns the decorated signature of the transaction create with `image`.
580    pub fn decorated_signature_from_preimage(&self, preimage: &[u8]) -> Result<DecoratedSignature> {
581        match self {
582            TransactionEnvelope::Transaction(tx) => tx.decorated_signature_from_preimage(preimage),
583            TransactionEnvelope::FeeBumpTransaction(tx) => {
584                tx.decorated_signature_from_preimage(preimage)
585            }
586        }
587    }
588
589    /// Returns the decorated signature of the transaction create with `key` for `network`.
590    pub fn decorated_signature<S, V>(
591        &self,
592        key: &KeyPair<S, V>,
593        network: &Network,
594    ) -> Result<DecoratedSignature>
595    where
596        S: Ed25519Signer<Signature>,
597        V: Ed25519Verifier<Signature> + AsRef<[u8]>,
598    {
599        match self {
600            TransactionEnvelope::Transaction(tx) => tx.decorated_signature(key, network),
601            TransactionEnvelope::FeeBumpTransaction(tx) => tx.decorated_signature(key, network),
602        }
603    }
604
605    /// Returns the transaction hash for the transaction on `network`.
606    pub fn hash(&self, network: &Network) -> Result<Vec<u8>> {
607        match self {
608            TransactionEnvelope::Transaction(tx) => tx.hash(network),
609            TransactionEnvelope::FeeBumpTransaction(tx) => tx.hash(network),
610        }
611    }
612
613    /// Returns the transaction signature data as bytes.
614    pub fn signature_data(&self, network: &Network) -> Result<Vec<u8>> {
615        match self {
616            TransactionEnvelope::Transaction(tx) => tx.signature_data(network),
617            TransactionEnvelope::FeeBumpTransaction(tx) => tx.signature_data(network),
618        }
619    }
620
621    /// Returns the xdr object.
622    pub fn to_xdr(&self) -> Result<xdr::TransactionEnvelope> {
623        match self {
624            TransactionEnvelope::Transaction(tx) => {
625                let inner = tx.to_xdr_envelope()?;
626                Ok(xdr::TransactionEnvelope::Tx(inner))
627            }
628            TransactionEnvelope::FeeBumpTransaction(tx) => {
629                let inner = tx.to_xdr_envelope()?;
630                Ok(xdr::TransactionEnvelope::TxFeeBump(inner))
631            }
632        }
633    }
634
635    /// Creates from xdr object.
636    pub fn from_xdr(x: &xdr::TransactionEnvelope) -> Result<TransactionEnvelope> {
637        match x {
638            xdr::TransactionEnvelope::Tx(inner) => {
639                let tx = Transaction::from_xdr_envelope(inner)?;
640                Ok(TransactionEnvelope::Transaction(tx))
641            }
642            xdr::TransactionEnvelope::TxV0(inner) => {
643                let tx = Transaction::from_xdr_v0_envelope(inner)?;
644                Ok(TransactionEnvelope::Transaction(tx))
645            }
646            xdr::TransactionEnvelope::TxFeeBump(inner) => {
647                let tx = FeeBumpTransaction::from_xdr_envelope(inner)?;
648                Ok(TransactionEnvelope::FeeBumpTransaction(tx))
649            }
650        }
651    }
652
653    /// Returns the xdr transaction signature payload object.
654    pub fn to_xdr_transaction_signature_payload(
655        &self,
656        network: &Network,
657    ) -> Result<xdr::TransactionSignaturePayload> {
658        match self {
659            TransactionEnvelope::Transaction(tx) => {
660                tx.to_xdr_transaction_signature_payload(network)
661            }
662            TransactionEnvelope::FeeBumpTransaction(tx) => {
663                tx.to_xdr_transaction_signature_payload(network)
664            }
665        }
666    }
667}
668
669impl TransactionBuilder {
670    pub fn new<S: Into<MuxedAccount>>(
671        source_account: S,
672        sequence: i64,
673        base_fee: Stroops,
674    ) -> TransactionBuilder {
675        let tx = Transaction {
676            source_account: source_account.into(),
677            sequence,
678            fee: Stroops::new(0),
679            time_bounds: None,
680            memo: Memo::new_none(),
681            operations: Vec::new(),
682            signatures: Vec::new(),
683        };
684        let tx = if base_fee < MIN_BASE_FEE {
685            Err(Error::TransactionFeeTooLow)
686        } else {
687            Ok(tx)
688        };
689        TransactionBuilder { tx, base_fee }
690    }
691
692    pub fn with_time_bounds(mut self, time_bounds: TimeBounds) -> TransactionBuilder {
693        if let Ok(ref mut tx) = self.tx {
694            *tx.time_bounds_mut() = Some(time_bounds);
695        }
696        self
697    }
698
699    pub fn with_memo(mut self, memo: Memo) -> TransactionBuilder {
700        if let Ok(ref mut tx) = self.tx {
701            *tx.memo_mut() = memo;
702        }
703        self
704    }
705
706    pub fn add_operation(mut self, operation: Operation) -> TransactionBuilder {
707        let mut error = None;
708        if let Ok(ref mut tx) = self.tx {
709            let operations = tx.operations_mut();
710            if operations.len() > xdr::MAX_OPS_PER_TX as usize {
711                error = Some(Err(Error::TooManyOperations));
712            } else {
713                operations.push(operation);
714            }
715        }
716        if let Some(error) = error {
717            self.tx = error;
718        }
719        self
720    }
721
722    pub fn into_transaction(mut self) -> Result<Transaction> {
723        let mut error = None;
724        if let Ok(ref mut tx) = self.tx {
725            if tx.operations().is_empty() {
726                error = Some(Err(Error::MissingOperations));
727            }
728            let fee = self
729                .base_fee
730                .checked_mul(&Stroops::new(tx.operations.len() as i64))
731                .ok_or(Error::TransactionFeeOverflow)?;
732            *tx.fee_mut() = fee;
733        }
734
735        if let Some(error) = error {
736            self.tx = error;
737        }
738        self.tx
739    }
740}
741
742impl xdr::WriteXdr for TransactionEnvelope {
743    fn write_xdr<W: Write>(&self, w: &mut xdr::Limited<W>) -> xdr::Result<()> {
744        let xdr_tx = self.to_xdr().map_err(|_| xdr::Error::Invalid)?;
745        xdr_tx.write_xdr(w)
746    }
747}
748
749impl xdr::ReadXdr for TransactionEnvelope {
750    fn read_xdr<R: Read>(r: &mut xdr::Limited<R>) -> xdr::Result<Self> {
751        let xdr_result = xdr::TransactionEnvelope::read_xdr(r)?;
752        Self::from_xdr(&xdr_result).map_err(|_| xdr::Error::Invalid)
753    }
754}
755
756fn signatures_to_xdr(
757    signatures: &[DecoratedSignature],
758) -> Result<xdr::VecM<xdr::DecoratedSignature, 20>> {
759    let mut xdr_signatures = Vec::new();
760    for signature in signatures {
761        let xdr_signature = signature.to_xdr()?;
762        xdr_signatures.push(xdr_signature);
763    }
764    xdr_signatures.try_into().map_err(|_| Error::XdrError)
765}
766
767fn signatures_from_xdr(
768    xdr_signatures: &[xdr::DecoratedSignature],
769) -> Result<Vec<DecoratedSignature>> {
770    let mut signatures = Vec::new();
771    for xdr_signature in xdr_signatures {
772        let signature = DecoratedSignature::from_xdr(xdr_signature)?;
773        signatures.push(signature);
774    }
775    Ok(signatures)
776}
777
778#[cfg(test)]
779mod tests {
780    use super::Transaction;
781    use crate::amount::Stroops;
782    use crate::crypto::DalekKeyPair;
783    use crate::memo::Memo;
784    use crate::operations::Operation;
785    use crate::time_bounds::TimeBounds;
786
787    #[test]
788    fn test_transaction_builder() {
789        let kp = DalekKeyPair::random().unwrap();
790        let tx = Transaction::builder(kp.public_key(), 123, Stroops::new(100))
791            .with_memo(Memo::new_id(987))
792            .with_time_bounds(TimeBounds::always_valid())
793            .add_operation(Operation::new_inflation().build())
794            .into_transaction()
795            .unwrap();
796        assert_eq!(123, *tx.sequence());
797        assert_eq!(&Stroops::new(100), tx.fee());
798        assert!(tx.memo().is_id());
799        assert!(tx.time_bounds().is_some());
800        assert_eq!(1, tx.operations().len());
801    }
802}