fuel_tx/transaction/types/
input.rs

1use crate::{
2    TxPointer,
3    UtxoId,
4};
5use alloc::vec::Vec;
6use coin::*;
7use consts::*;
8use contract::*;
9use fuel_crypto::{
10    Hasher,
11    PublicKey,
12};
13use fuel_types::{
14    Address,
15    AssetId,
16    Bytes32,
17    ContractId,
18    MessageId,
19    Nonce,
20    Word,
21    bytes,
22    bytes::Bytes,
23    canonical,
24    canonical::{
25        Deserialize,
26        Error,
27        Output,
28        Serialize,
29    },
30};
31use message::*;
32
33pub mod coin;
34mod consts;
35pub mod contract;
36pub mod message;
37mod predicate;
38mod repr;
39
40pub use predicate::PredicateCode;
41pub use repr::InputRepr;
42
43#[cfg(all(test, feature = "std"))]
44mod ser_de_tests;
45
46pub trait AsField<Type> {
47    fn as_field(&self) -> Option<&Type>;
48
49    fn as_mut_field(&mut self) -> Option<&mut Type>;
50}
51
52/// The empty field used by sub-types of the specification.
53#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
54#[cfg_attr(
55    feature = "da-compression",
56    derive(fuel_compression::Compress, fuel_compression::Decompress)
57)]
58#[cfg_attr(feature = "da-compression", compress(discard(Type)))]
59pub struct Empty<Type>(
60    #[cfg_attr(feature = "da-compression", compress(skip))]
61    ::core::marker::PhantomData<Type>,
62);
63
64impl<Type> Empty<Type> {
65    /// Creates `Self`.
66    pub const fn new() -> Self {
67        Self(::core::marker::PhantomData {})
68    }
69}
70
71impl<Type> Default for Empty<Type> {
72    fn default() -> Self {
73        Self::new()
74    }
75}
76
77impl<Type: Serialize + Default> Serialize for Empty<Type> {
78    #[inline(always)]
79    fn size_static(&self) -> usize {
80        Type::default().size_static()
81    }
82
83    #[inline(always)]
84    fn size_dynamic(&self) -> usize {
85        0
86    }
87
88    #[inline(always)]
89    fn encode_static<O: Output + ?Sized>(&self, buffer: &mut O) -> Result<(), Error> {
90        Type::default().encode_static(buffer)
91    }
92}
93
94impl<Type: Deserialize> Deserialize for Empty<Type> {
95    #[inline(always)]
96    fn decode_static<I: canonical::Input + ?Sized>(
97        buffer: &mut I,
98    ) -> Result<Self, Error> {
99        Type::decode_static(buffer)?;
100        Ok(Default::default())
101    }
102}
103
104impl<Type> AsField<Type> for Empty<Type> {
105    #[inline(always)]
106    fn as_field(&self) -> Option<&Type> {
107        None
108    }
109
110    fn as_mut_field(&mut self) -> Option<&mut Type> {
111        None
112    }
113}
114
115impl AsField<u8> for u8 {
116    #[inline(always)]
117    fn as_field(&self) -> Option<&u8> {
118        Some(self)
119    }
120
121    fn as_mut_field(&mut self) -> Option<&mut u8> {
122        Some(self)
123    }
124}
125
126impl AsField<u16> for u16 {
127    #[inline(always)]
128    fn as_field(&self) -> Option<&u16> {
129        Some(self)
130    }
131
132    fn as_mut_field(&mut self) -> Option<&mut u16> {
133        Some(self)
134    }
135}
136
137impl AsField<u64> for u64 {
138    #[inline(always)]
139    fn as_field(&self) -> Option<&u64> {
140        Some(self)
141    }
142
143    fn as_mut_field(&mut self) -> Option<&mut u64> {
144        Some(self)
145    }
146}
147
148impl AsField<Bytes> for Bytes {
149    #[inline(always)]
150    fn as_field(&self) -> Option<&Bytes> {
151        Some(self)
152    }
153
154    fn as_mut_field(&mut self) -> Option<&mut Bytes> {
155        Some(self)
156    }
157}
158
159impl AsField<PredicateCode> for PredicateCode {
160    #[inline(always)]
161    fn as_field(&self) -> Option<&PredicateCode> {
162        Some(self)
163    }
164
165    fn as_mut_field(&mut self) -> Option<&mut PredicateCode> {
166        Some(self)
167    }
168}
169
170#[derive(
171    Debug,
172    Clone,
173    PartialEq,
174    Eq,
175    Hash,
176    strum_macros::EnumCount,
177    serde::Serialize,
178    serde::Deserialize,
179)]
180#[cfg_attr(
181    feature = "da-compression",
182    derive(fuel_compression::Compress, fuel_compression::Decompress)
183)]
184pub enum Input {
185    CoinSigned(CoinSigned),
186    CoinPredicate(CoinPredicate),
187    Contract(Contract),
188    MessageCoinSigned(MessageCoinSigned),
189    MessageCoinPredicate(MessageCoinPredicate),
190    MessageDataSigned(MessageDataSigned),
191    MessageDataPredicate(MessageDataPredicate),
192}
193
194impl Default for Input {
195    fn default() -> Self {
196        Self::contract(
197            Default::default(),
198            Default::default(),
199            Default::default(),
200            Default::default(),
201            Default::default(),
202        )
203    }
204}
205
206impl Input {
207    pub const fn repr(&self) -> InputRepr {
208        InputRepr::from_input(self)
209    }
210
211    pub fn owner(pk: &PublicKey) -> Address {
212        let owner: [u8; Address::LEN] = pk.hash().into();
213
214        owner.into()
215    }
216
217    pub const fn coin_predicate(
218        utxo_id: UtxoId,
219        owner: Address,
220        amount: Word,
221        asset_id: AssetId,
222        tx_pointer: TxPointer,
223        predicate_gas_used: Word,
224        predicate: Vec<u8>,
225        predicate_data: Vec<u8>,
226    ) -> Self {
227        Self::CoinPredicate(CoinPredicate {
228            utxo_id,
229            owner,
230            amount,
231            asset_id,
232            tx_pointer,
233            witness_index: Empty::new(),
234            predicate_gas_used,
235            predicate: PredicateCode::new(predicate),
236            predicate_data: Bytes::new(predicate_data),
237        })
238    }
239
240    pub const fn coin_signed(
241        utxo_id: UtxoId,
242        owner: Address,
243        amount: Word,
244        asset_id: AssetId,
245        tx_pointer: TxPointer,
246        witness_index: u16,
247    ) -> Self {
248        Self::CoinSigned(CoinSigned {
249            utxo_id,
250            owner,
251            amount,
252            asset_id,
253            tx_pointer,
254            witness_index,
255            predicate_gas_used: Empty::new(),
256            predicate: Empty::new(),
257            predicate_data: Empty::new(),
258        })
259    }
260
261    pub const fn contract(
262        utxo_id: UtxoId,
263        balance_root: Bytes32,
264        state_root: Bytes32,
265        tx_pointer: TxPointer,
266        contract_id: ContractId,
267    ) -> Self {
268        Self::Contract(Contract {
269            utxo_id,
270            balance_root,
271            state_root,
272            tx_pointer,
273            contract_id,
274        })
275    }
276
277    pub const fn message_coin_signed(
278        sender: Address,
279        recipient: Address,
280        amount: Word,
281        nonce: Nonce,
282        witness_index: u16,
283    ) -> Self {
284        Self::MessageCoinSigned(MessageCoinSigned {
285            sender,
286            recipient,
287            amount,
288            nonce,
289            witness_index,
290            predicate_gas_used: Empty::new(),
291            data: Empty::new(),
292            predicate: Empty::new(),
293            predicate_data: Empty::new(),
294        })
295    }
296
297    pub const fn message_coin_predicate(
298        sender: Address,
299        recipient: Address,
300        amount: Word,
301        nonce: Nonce,
302        predicate_gas_used: Word,
303        predicate: Vec<u8>,
304        predicate_data: Vec<u8>,
305    ) -> Self {
306        Self::MessageCoinPredicate(MessageCoinPredicate {
307            sender,
308            recipient,
309            amount,
310            nonce,
311            witness_index: Empty::new(),
312            predicate_gas_used,
313            data: Empty::new(),
314            predicate: PredicateCode::new(predicate),
315            predicate_data: Bytes::new(predicate_data),
316        })
317    }
318
319    pub const fn message_data_signed(
320        sender: Address,
321        recipient: Address,
322        amount: Word,
323        nonce: Nonce,
324        witness_index: u16,
325        data: Vec<u8>,
326    ) -> Self {
327        Self::MessageDataSigned(MessageDataSigned {
328            sender,
329            recipient,
330            amount,
331            nonce,
332            witness_index,
333            data: Bytes::new(data),
334            predicate: Empty::new(),
335            predicate_data: Empty::new(),
336            predicate_gas_used: Empty::new(),
337        })
338    }
339
340    pub const fn message_data_predicate(
341        sender: Address,
342        recipient: Address,
343        amount: Word,
344        nonce: Nonce,
345        predicate_gas_used: Word,
346        data: Vec<u8>,
347        predicate: Vec<u8>,
348        predicate_data: Vec<u8>,
349    ) -> Self {
350        Self::MessageDataPredicate(MessageDataPredicate {
351            sender,
352            recipient,
353            amount,
354            nonce,
355            witness_index: Empty::new(),
356            predicate_gas_used,
357            data: Bytes::new(data),
358            predicate: PredicateCode::new(predicate),
359            predicate_data: Bytes::new(predicate_data),
360        })
361    }
362
363    pub const fn utxo_id(&self) -> Option<&UtxoId> {
364        match self {
365            Self::CoinSigned(CoinSigned { utxo_id, .. })
366            | Self::CoinPredicate(CoinPredicate { utxo_id, .. })
367            | Self::Contract(Contract { utxo_id, .. }) => Some(utxo_id),
368            Self::MessageCoinSigned(_) => None,
369            Self::MessageCoinPredicate(_) => None,
370            Self::MessageDataSigned(_) => None,
371            Self::MessageDataPredicate(_) => None,
372        }
373    }
374
375    pub const fn input_owner(&self) -> Option<&Address> {
376        match self {
377            Self::CoinSigned(CoinSigned { owner, .. })
378            | Self::CoinPredicate(CoinPredicate { owner, .. }) => Some(owner),
379            Self::MessageCoinSigned(MessageCoinSigned { recipient, .. })
380            | Self::MessageCoinPredicate(MessageCoinPredicate { recipient, .. })
381            | Self::MessageDataSigned(MessageDataSigned { recipient, .. })
382            | Self::MessageDataPredicate(MessageDataPredicate { recipient, .. }) => {
383                Some(recipient)
384            }
385            Self::Contract(_) => None,
386        }
387    }
388
389    pub const fn asset_id<'a>(
390        &'a self,
391        base_asset_id: &'a AssetId,
392    ) -> Option<&'a AssetId> {
393        match self {
394            Input::CoinSigned(CoinSigned { asset_id, .. })
395            | Input::CoinPredicate(CoinPredicate { asset_id, .. }) => Some(asset_id),
396            Input::MessageCoinSigned(_)
397            | Input::MessageCoinPredicate(_)
398            | Input::MessageDataSigned(_)
399            | Input::MessageDataPredicate(_) => Some(base_asset_id),
400            Input::Contract(_) => None,
401        }
402    }
403
404    pub const fn contract_id(&self) -> Option<&ContractId> {
405        match self {
406            Self::Contract(Contract { contract_id, .. }) => Some(contract_id),
407            _ => None,
408        }
409    }
410
411    pub const fn amount(&self) -> Option<Word> {
412        match self {
413            Input::CoinSigned(CoinSigned { amount, .. })
414            | Input::CoinPredicate(CoinPredicate { amount, .. })
415            | Input::MessageCoinSigned(MessageCoinSigned { amount, .. })
416            | Input::MessageCoinPredicate(MessageCoinPredicate { amount, .. })
417            | Input::MessageDataSigned(MessageDataSigned { amount, .. })
418            | Input::MessageDataPredicate(MessageDataPredicate { amount, .. }) => {
419                Some(*amount)
420            }
421            Input::Contract(_) => None,
422        }
423    }
424
425    pub const fn witness_index(&self) -> Option<u16> {
426        match self {
427            Input::CoinSigned(CoinSigned { witness_index, .. })
428            | Input::MessageCoinSigned(MessageCoinSigned { witness_index, .. })
429            | Input::MessageDataSigned(MessageDataSigned { witness_index, .. }) => {
430                Some(*witness_index)
431            }
432            Input::CoinPredicate(_)
433            | Input::Contract(_)
434            | Input::MessageCoinPredicate(_)
435            | Input::MessageDataPredicate(_) => None,
436        }
437    }
438
439    pub fn predicate_offset(&self) -> Option<usize> {
440        match self {
441            Input::CoinPredicate(_) => InputRepr::Coin.coin_predicate_offset(),
442            Input::MessageCoinPredicate(_) => InputRepr::Message.data_offset(),
443            Input::MessageDataPredicate(MessageDataPredicate { data, .. }) => {
444                InputRepr::Message.data_offset().map(|o| {
445                    o.saturating_add(bytes::padded_len(data).unwrap_or(usize::MAX))
446                })
447            }
448            Input::CoinSigned(_)
449            | Input::Contract(_)
450            | Input::MessageCoinSigned(_)
451            | Input::MessageDataSigned(_) => None,
452        }
453    }
454
455    pub fn predicate_data_offset(&self) -> Option<usize> {
456        match self {
457            Input::CoinPredicate(CoinPredicate { predicate, .. })
458            | Input::MessageCoinPredicate(MessageCoinPredicate { predicate, .. })
459            | Input::MessageDataPredicate(MessageDataPredicate { predicate, .. }) => {
460                self.predicate_offset().map(|o| {
461                    o.saturating_add(bytes::padded_len(predicate).unwrap_or(usize::MAX))
462                })
463            }
464            Input::CoinSigned(_)
465            | Input::Contract(_)
466            | Input::MessageCoinSigned(_)
467            | Input::MessageDataSigned(_) => None,
468        }
469    }
470
471    pub fn predicate_len(&self) -> Option<usize> {
472        match self {
473            Input::CoinPredicate(CoinPredicate { predicate, .. })
474            | Input::MessageCoinPredicate(MessageCoinPredicate { predicate, .. })
475            | Input::MessageDataPredicate(MessageDataPredicate { predicate, .. }) => {
476                Some(predicate.len())
477            }
478            Input::CoinSigned(_)
479            | Input::MessageCoinSigned(_)
480            | Input::MessageDataSigned(_) => Some(0),
481            Input::Contract(_) => None,
482        }
483    }
484
485    pub fn predicate_data_len(&self) -> Option<usize> {
486        match self {
487            Input::CoinPredicate(CoinPredicate { predicate_data, .. })
488            | Input::MessageCoinPredicate(MessageCoinPredicate {
489                predicate_data, ..
490            })
491            | Input::MessageDataPredicate(MessageDataPredicate {
492                predicate_data, ..
493            }) => Some(predicate_data.len()),
494            Input::CoinSigned(_)
495            | Input::MessageCoinSigned(_)
496            | Input::MessageDataSigned(_) => Some(0),
497            Input::Contract(_) => None,
498        }
499    }
500
501    pub fn predicate_gas_used(&self) -> Option<Word> {
502        match self {
503            Input::CoinPredicate(CoinPredicate {
504                predicate_gas_used, ..
505            })
506            | Input::MessageCoinPredicate(MessageCoinPredicate {
507                predicate_gas_used,
508                ..
509            })
510            | Input::MessageDataPredicate(MessageDataPredicate {
511                predicate_gas_used,
512                ..
513            }) => Some(*predicate_gas_used),
514            Input::CoinSigned(_)
515            | Input::MessageCoinSigned(_)
516            | Input::MessageDataSigned(_)
517            | Input::Contract(_) => None,
518        }
519    }
520
521    pub fn set_predicate_gas_used(&mut self, gas: Word) {
522        match self {
523            Input::CoinPredicate(CoinPredicate {
524                predicate_gas_used, ..
525            })
526            | Input::MessageCoinPredicate(MessageCoinPredicate {
527                predicate_gas_used,
528                ..
529            })
530            | Input::MessageDataPredicate(MessageDataPredicate {
531                predicate_gas_used,
532                ..
533            }) => *predicate_gas_used = gas,
534            Input::CoinSigned(_)
535            | Input::MessageCoinSigned(_)
536            | Input::MessageDataSigned(_)
537            | Input::Contract(_) => {}
538        }
539    }
540
541    pub fn message_id(&self) -> Option<MessageId> {
542        match self {
543            Self::MessageCoinSigned(message) => Some(message.message_id()),
544            Self::MessageCoinPredicate(message) => Some(message.message_id()),
545            Self::MessageDataPredicate(message) => Some(message.message_id()),
546            Self::MessageDataSigned(message) => Some(message.message_id()),
547            _ => None,
548        }
549    }
550
551    pub const fn tx_pointer(&self) -> Option<&TxPointer> {
552        match self {
553            Input::CoinSigned(CoinSigned { tx_pointer, .. })
554            | Input::CoinPredicate(CoinPredicate { tx_pointer, .. })
555            | Input::Contract(Contract { tx_pointer, .. }) => Some(tx_pointer),
556            _ => None,
557        }
558    }
559
560    pub fn input_data(&self) -> Option<&[u8]> {
561        match self {
562            Input::MessageDataSigned(MessageDataSigned { data, .. })
563            | Input::MessageDataPredicate(MessageDataPredicate { data, .. }) => {
564                Some(data)
565            }
566            _ => None,
567        }
568    }
569
570    pub fn input_data_len(&self) -> Option<usize> {
571        match self {
572            Input::MessageDataSigned(MessageDataSigned { data, .. })
573            | Input::MessageDataPredicate(MessageDataPredicate { data, .. }) => {
574                Some(data.len())
575            }
576            Input::MessageCoinSigned(_) | Input::MessageCoinPredicate(_) => Some(0),
577            _ => None,
578        }
579    }
580
581    pub fn input_predicate(&self) -> Option<&[u8]> {
582        match self {
583            Input::CoinPredicate(CoinPredicate { predicate, .. })
584            | Input::MessageCoinPredicate(MessageCoinPredicate { predicate, .. })
585            | Input::MessageDataPredicate(MessageDataPredicate { predicate, .. }) => {
586                Some(predicate)
587            }
588
589            _ => None,
590        }
591    }
592
593    pub fn input_predicate_data(&self) -> Option<&[u8]> {
594        match self {
595            Input::CoinPredicate(CoinPredicate { predicate_data, .. })
596            | Input::MessageCoinPredicate(MessageCoinPredicate {
597                predicate_data, ..
598            })
599            | Input::MessageDataPredicate(MessageDataPredicate {
600                predicate_data, ..
601            }) => Some(predicate_data),
602
603            _ => None,
604        }
605    }
606
607    /// Return a tuple containing the predicate, its data and used gas if the input is of
608    /// type `CoinPredicate` or `MessageCoinPredicate` or `MessageDataPredicate`
609    pub fn predicate(&self) -> Option<(&[u8], &[u8], &Word)> {
610        match self {
611            Input::CoinPredicate(CoinPredicate {
612                predicate,
613                predicate_data,
614                predicate_gas_used,
615                ..
616            })
617            | Input::MessageCoinPredicate(MessageCoinPredicate {
618                predicate,
619                predicate_data,
620                predicate_gas_used,
621                ..
622            })
623            | Input::MessageDataPredicate(MessageDataPredicate {
624                predicate,
625                predicate_data,
626                predicate_gas_used,
627                ..
628            }) => Some((
629                predicate.as_slice(),
630                predicate_data.as_slice(),
631                predicate_gas_used,
632            )),
633
634            _ => None,
635        }
636    }
637
638    pub const fn is_coin(&self) -> bool {
639        self.is_coin_signed() | self.is_coin_predicate()
640    }
641
642    pub const fn is_coin_signed(&self) -> bool {
643        matches!(self, Input::CoinSigned(_))
644    }
645
646    pub const fn is_coin_predicate(&self) -> bool {
647        matches!(self, Input::CoinPredicate(_))
648    }
649
650    pub const fn is_message(&self) -> bool {
651        self.is_message_coin_signed()
652            | self.is_message_coin_predicate()
653            | self.is_message_data_signed()
654            | self.is_message_data_predicate()
655    }
656
657    pub const fn is_message_coin_signed(&self) -> bool {
658        matches!(self, Input::MessageCoinSigned(_))
659    }
660
661    pub const fn is_message_coin_predicate(&self) -> bool {
662        matches!(self, Input::MessageCoinPredicate(_))
663    }
664
665    pub const fn is_message_data_signed(&self) -> bool {
666        matches!(self, Input::MessageDataSigned(_))
667    }
668
669    pub const fn is_message_data_predicate(&self) -> bool {
670        matches!(self, Input::MessageDataPredicate(_))
671    }
672
673    pub const fn is_contract(&self) -> bool {
674        matches!(self, Input::Contract(_))
675    }
676
677    pub const fn coin_predicate_offset() -> usize {
678        INPUT_COIN_FIXED_SIZE
679    }
680
681    pub const fn message_data_offset() -> usize {
682        INPUT_MESSAGE_FIXED_SIZE
683    }
684
685    pub const fn balance_root(&self) -> Option<&Bytes32> {
686        match self {
687            Input::Contract(Contract { balance_root, .. }) => Some(balance_root),
688            _ => None,
689        }
690    }
691
692    pub const fn state_root(&self) -> Option<&Bytes32> {
693        match self {
694            Input::Contract(Contract { state_root, .. }) => Some(state_root),
695            _ => None,
696        }
697    }
698
699    pub const fn sender(&self) -> Option<&Address> {
700        match self {
701            Input::MessageCoinSigned(MessageCoinSigned { sender, .. })
702            | Input::MessageCoinPredicate(MessageCoinPredicate { sender, .. })
703            | Input::MessageDataSigned(MessageDataSigned { sender, .. })
704            | Input::MessageDataPredicate(MessageDataPredicate { sender, .. }) => {
705                Some(sender)
706            }
707            _ => None,
708        }
709    }
710
711    pub const fn recipient(&self) -> Option<&Address> {
712        match self {
713            Input::MessageCoinSigned(MessageCoinSigned { recipient, .. })
714            | Input::MessageCoinPredicate(MessageCoinPredicate { recipient, .. })
715            | Input::MessageDataSigned(MessageDataSigned { recipient, .. })
716            | Input::MessageDataPredicate(MessageDataPredicate { recipient, .. }) => {
717                Some(recipient)
718            }
719            _ => None,
720        }
721    }
722
723    pub const fn nonce(&self) -> Option<&Nonce> {
724        match self {
725            Input::MessageCoinSigned(MessageCoinSigned { nonce, .. })
726            | Input::MessageCoinPredicate(MessageCoinPredicate { nonce, .. })
727            | Input::MessageDataSigned(MessageDataSigned { nonce, .. })
728            | Input::MessageDataPredicate(MessageDataPredicate { nonce, .. }) => {
729                Some(nonce)
730            }
731            _ => None,
732        }
733    }
734
735    /// Empties fields that should be zero during the signing.
736    pub fn prepare_sign(&mut self) {
737        match self {
738            Input::CoinSigned(coin) => coin.prepare_sign(),
739            Input::CoinPredicate(coin) => coin.prepare_sign(),
740            Input::Contract(contract) => contract.prepare_sign(),
741            Input::MessageCoinSigned(message) => message.prepare_sign(),
742            Input::MessageCoinPredicate(message) => message.prepare_sign(),
743            Input::MessageDataSigned(message) => message.prepare_sign(),
744            Input::MessageDataPredicate(message) => message.prepare_sign(),
745        }
746    }
747
748    pub fn compute_message_id(
749        sender: &Address,
750        recipient: &Address,
751        nonce: &Nonce,
752        amount: Word,
753        data: &[u8],
754    ) -> MessageId {
755        compute_message_id(sender, recipient, nonce, amount, data)
756    }
757
758    pub fn predicate_owner<P>(predicate: P) -> Address
759    where
760        P: AsRef<[u8]>,
761    {
762        use crate::Contract;
763
764        let root = Contract::root_from_code(predicate);
765
766        let mut hasher = Hasher::default();
767
768        hasher.input(ContractId::SEED);
769        hasher.input(root);
770
771        (*hasher.digest()).into()
772    }
773
774    pub fn is_predicate_owner_valid<P>(owner: &Address, predicate: P) -> bool
775    where
776        P: AsRef<[u8]>,
777    {
778        owner == &Self::predicate_owner(predicate)
779    }
780}
781
782impl Serialize for Input {
783    fn size_static(&self) -> usize {
784        (match self {
785            Input::CoinSigned(coin) => coin.size_static(),
786            Input::CoinPredicate(coin) => coin.size_static(),
787            Input::Contract(contract) => contract.size_static(),
788            Input::MessageCoinSigned(message) => message.size_static(),
789            Input::MessageCoinPredicate(message) => message.size_static(),
790            Input::MessageDataSigned(message) => message.size_static(),
791            Input::MessageDataPredicate(message) => message.size_static(),
792        })
793        .saturating_add(8) // Discriminant
794    }
795
796    fn size_dynamic(&self) -> usize {
797        match self {
798            Input::CoinSigned(coin) => coin.size_dynamic(),
799            Input::CoinPredicate(coin) => coin.size_dynamic(),
800            Input::Contract(contract) => contract.size_dynamic(),
801            Input::MessageCoinSigned(message) => message.size_dynamic(),
802            Input::MessageCoinPredicate(message) => message.size_dynamic(),
803            Input::MessageDataSigned(message) => message.size_dynamic(),
804            Input::MessageDataPredicate(message) => message.size_dynamic(),
805        }
806    }
807
808    fn encode_static<O: Output + ?Sized>(&self, buffer: &mut O) -> Result<(), Error> {
809        let discr = InputRepr::from(self);
810        discr.encode_static(buffer)?;
811        match self {
812            Input::CoinSigned(coin) => coin.encode_static(buffer),
813            Input::CoinPredicate(coin) => coin.encode_static(buffer),
814            Input::Contract(contract) => contract.encode_static(buffer),
815            Input::MessageCoinSigned(message) => message.encode_static(buffer),
816            Input::MessageCoinPredicate(message) => message.encode_static(buffer),
817            Input::MessageDataSigned(message) => message.encode_static(buffer),
818            Input::MessageDataPredicate(message) => message.encode_static(buffer),
819        }
820    }
821
822    fn encode_dynamic<O: Output + ?Sized>(&self, buffer: &mut O) -> Result<(), Error> {
823        let discr = InputRepr::from(self);
824        discr.encode_dynamic(buffer)?;
825        match self {
826            Input::CoinSigned(coin) => coin.encode_dynamic(buffer),
827            Input::CoinPredicate(coin) => coin.encode_dynamic(buffer),
828            Input::Contract(contract) => contract.encode_dynamic(buffer),
829            Input::MessageCoinSigned(message) => message.encode_dynamic(buffer),
830            Input::MessageCoinPredicate(message) => message.encode_dynamic(buffer),
831            Input::MessageDataSigned(message) => message.encode_dynamic(buffer),
832            Input::MessageDataPredicate(message) => message.encode_dynamic(buffer),
833        }
834    }
835}
836
837impl Deserialize for Input {
838    fn decode_static<I: canonical::Input + ?Sized>(
839        buffer: &mut I,
840    ) -> Result<Self, Error> {
841        Ok(
842            match <InputRepr as Deserialize>::decode(buffer)
843                .map_err(|_| Error::UnknownDiscriminant)?
844            {
845                InputRepr::Coin => {
846                    let coin = CoinFull::decode_static(buffer)?;
847                    if coin.predicate.capacity() == 0 {
848                        Input::CoinSigned(coin.into_signed())
849                    } else {
850                        Input::CoinPredicate(coin.into_predicate())
851                    }
852                }
853                InputRepr::Contract => {
854                    let contract = Contract::decode_static(buffer)?;
855                    Input::Contract(contract)
856                }
857                InputRepr::Message => {
858                    let message = FullMessage::decode_static(buffer)?;
859                    match (
860                        message.data.capacity() == 0,
861                        message.predicate.capacity() == 0,
862                    ) {
863                        (true, true) => {
864                            Input::MessageCoinSigned(message.into_coin_signed())
865                        }
866                        (true, false) => {
867                            Input::MessageCoinPredicate(message.into_coin_predicate())
868                        }
869                        (false, true) => {
870                            Input::MessageDataSigned(message.into_message_data_signed())
871                        }
872                        (false, false) => Input::MessageDataPredicate(
873                            message.into_message_data_predicate(),
874                        ),
875                    }
876                }
877            },
878        )
879    }
880
881    fn decode_dynamic<I: canonical::Input + ?Sized>(
882        &mut self,
883        buffer: &mut I,
884    ) -> Result<(), Error> {
885        match self {
886            Input::CoinSigned(coin) => coin.decode_dynamic(buffer),
887            Input::CoinPredicate(coin) => coin.decode_dynamic(buffer),
888            Input::Contract(contract) => contract.decode_dynamic(buffer),
889            Input::MessageCoinSigned(message) => message.decode_dynamic(buffer),
890            Input::MessageCoinPredicate(message) => message.decode_dynamic(buffer),
891            Input::MessageDataSigned(message) => message.decode_dynamic(buffer),
892            Input::MessageDataPredicate(message) => message.decode_dynamic(buffer),
893        }
894    }
895}
896
897#[cfg(all(test, feature = "std"))]
898mod snapshot_tests;
899
900#[cfg(feature = "typescript")]
901pub mod typescript {
902    use wasm_bindgen::prelude::*;
903
904    use super::*;
905
906    use crate::{
907        TxPointer,
908        UtxoId,
909    };
910    use fuel_types::{
911        Address,
912        AssetId,
913        Bytes32,
914        Word,
915    };
916
917    use alloc::{
918        boxed::Box,
919        format,
920        string::String,
921        vec::Vec,
922    };
923
924    #[derive(Clone, Eq, Hash, PartialEq, serde::Serialize, serde::Deserialize)]
925    #[wasm_bindgen]
926    pub struct Input(#[wasm_bindgen(skip)] pub Box<crate::Input>);
927
928    #[wasm_bindgen]
929    impl Input {
930        #[wasm_bindgen(js_name = toJSON)]
931        pub fn to_json(&self) -> String {
932            serde_json::to_string(&self.0).expect("unable to json format")
933        }
934
935        #[wasm_bindgen(js_name = toString)]
936        pub fn typescript_to_string(&self) -> String {
937            format!("{:?}", self.0)
938        }
939
940        #[wasm_bindgen(js_name = to_bytes)]
941        pub fn typescript_to_bytes(&self) -> Vec<u8> {
942            use fuel_types::canonical::Serialize;
943            self.0.to_bytes()
944        }
945
946        #[wasm_bindgen(js_name = from_bytes)]
947        pub fn typescript_from_bytes(value: &[u8]) -> Result<Input, js_sys::Error> {
948            use fuel_types::canonical::Deserialize;
949            crate::Input::from_bytes(value)
950                .map(|v| Input(Box::new(v)))
951                .map_err(|e| js_sys::Error::new(&format!("{:?}", e)))
952        }
953
954        #[wasm_bindgen]
955        pub fn coin_predicate(
956            utxo_id: UtxoId,
957            owner: Address,
958            amount: Word,
959            asset_id: AssetId,
960            tx_pointer: TxPointer,
961            predicate_gas_used: Word,
962            predicate: Vec<u8>,
963            predicate_data: Vec<u8>,
964        ) -> Input {
965            Input(Box::new(crate::Input::CoinPredicate(CoinPredicate {
966                utxo_id,
967                owner,
968                amount,
969                asset_id,
970                tx_pointer,
971                witness_index: Empty::new(),
972                predicate_gas_used,
973                predicate: PredicateCode::new(predicate),
974                predicate_data: Bytes::new(predicate_data),
975            })))
976        }
977
978        #[wasm_bindgen]
979        pub fn coin_signed(
980            utxo_id: UtxoId,
981            owner: Address,
982            amount: Word,
983            asset_id: AssetId,
984            tx_pointer: TxPointer,
985            witness_index: u16,
986        ) -> Input {
987            Input(Box::new(crate::Input::CoinSigned(CoinSigned {
988                utxo_id,
989                owner,
990                amount,
991                asset_id,
992                tx_pointer,
993                witness_index,
994                predicate_gas_used: Empty::new(),
995                predicate: Empty::new(),
996                predicate_data: Empty::new(),
997            })))
998        }
999
1000        #[wasm_bindgen]
1001        pub fn contract(
1002            utxo_id: UtxoId,
1003            balance_root: Bytes32,
1004            state_root: Bytes32,
1005            tx_pointer: TxPointer,
1006            contract_id: ContractId,
1007        ) -> Input {
1008            Input(Box::new(crate::Input::Contract(Contract {
1009                utxo_id,
1010                balance_root,
1011                state_root,
1012                tx_pointer,
1013                contract_id,
1014            })))
1015        }
1016
1017        #[wasm_bindgen]
1018        pub fn message_coin_signed(
1019            sender: Address,
1020            recipient: Address,
1021            amount: Word,
1022            nonce: Nonce,
1023            witness_index: u16,
1024        ) -> Input {
1025            Input(Box::new(crate::Input::MessageCoinSigned(
1026                MessageCoinSigned {
1027                    sender,
1028                    recipient,
1029                    amount,
1030                    nonce,
1031                    witness_index,
1032                    predicate_gas_used: Empty::new(),
1033                    data: Empty::new(),
1034                    predicate: Empty::new(),
1035                    predicate_data: Empty::new(),
1036                },
1037            )))
1038        }
1039
1040        #[wasm_bindgen]
1041        pub fn message_coin_predicate(
1042            sender: Address,
1043            recipient: Address,
1044            amount: Word,
1045            nonce: Nonce,
1046            predicate_gas_used: Word,
1047            predicate: Vec<u8>,
1048            predicate_data: Vec<u8>,
1049        ) -> Input {
1050            Input(Box::new(crate::Input::MessageCoinPredicate(
1051                MessageCoinPredicate {
1052                    sender,
1053                    recipient,
1054                    amount,
1055                    nonce,
1056                    witness_index: Empty::new(),
1057                    predicate_gas_used,
1058                    data: Empty::new(),
1059                    predicate: PredicateCode::new(predicate),
1060                    predicate_data: Bytes::new(predicate_data),
1061                },
1062            )))
1063        }
1064
1065        #[wasm_bindgen]
1066        pub fn message_data_signed(
1067            sender: Address,
1068            recipient: Address,
1069            amount: Word,
1070            nonce: Nonce,
1071            witness_index: u16,
1072            data: Vec<u8>,
1073        ) -> Input {
1074            Input(Box::new(crate::Input::MessageDataSigned(
1075                MessageDataSigned {
1076                    sender,
1077                    recipient,
1078                    amount,
1079                    nonce,
1080                    witness_index,
1081                    data: Bytes::new(data),
1082                    predicate: Empty::new(),
1083                    predicate_data: Empty::new(),
1084                    predicate_gas_used: Empty::new(),
1085                },
1086            )))
1087        }
1088
1089        #[wasm_bindgen]
1090        pub fn message_data_predicate(
1091            sender: Address,
1092            recipient: Address,
1093            amount: Word,
1094            nonce: Nonce,
1095            predicate_gas_used: Word,
1096            data: Vec<u8>,
1097            predicate: Vec<u8>,
1098            predicate_data: Vec<u8>,
1099        ) -> Input {
1100            Input(Box::new(crate::Input::MessageDataPredicate(
1101                MessageDataPredicate {
1102                    sender,
1103                    recipient,
1104                    amount,
1105                    nonce,
1106                    witness_index: Empty::new(),
1107                    predicate_gas_used,
1108                    data: Bytes::new(data),
1109                    predicate: PredicateCode::new(predicate),
1110                    predicate_data: Bytes::new(predicate_data),
1111                },
1112            )))
1113        }
1114    }
1115}