Skip to main content

multiversx_sc/types/interaction/
tx.rs

1use crate::types::{
2    BigUint, CodeMetadata, EgldOrEsdtTokenIdentifier, EgldOrEsdtTokenPayment,
3    EgldOrEsdtTokenPaymentRefs, EgldOrMultiEsdtPayment, EsdtTokenIdentifier, EsdtTokenPayment,
4    EsdtTokenPaymentRefs, EsdtTokenPaymentVec, ManagedAddress, ManagedBuffer, ManagedVec,
5    TxPaymentCompose, heap::H256,
6};
7
8use alloc::borrow::ToOwned;
9use multiversx_sc_codec::TopEncodeMulti;
10
11use super::{
12    AnnotatedValue, Code, DeployCall, Egld, EgldPayment, ExplicitGas, FromSource, FunctionCall,
13    ManagedArgBuffer, OriginalResultMarker, RHList, RHListAppendNoRet, RHListAppendRet, RHListItem,
14    TxCodeSource, TxCodeValue, TxData, TxDataFunctionCall, TxEgldValue, TxEnv,
15    TxEnvMockDeployAddress, TxEnvWithTxHash, TxFrom, TxFromSourceValue, TxFromSpecified, TxGas,
16    TxGasValue, TxPayment, TxPaymentEgldOnly, TxProxyTrait, TxResultHandler, TxTo, TxToSpecified,
17    UpgradeCall,
18};
19
20/// Universal representation of a blockchain transaction.
21///
22/// Uses 7 generic type arguments to encode all aspects of the transaction.
23///
24/// It is future-like, does nothing by itself, it needs a specialized method call to actually run or send it.
25///
26/// Rationale: https://twitter.com/andreimmarinica/status/1777157322155966601
27#[must_use]
28pub struct Tx<Env, From, To, Payment, Gas, Data, RH>
29where
30    Env: TxEnv,
31    From: TxFrom<Env>,
32    To: TxTo<Env>,
33    Payment: TxPayment<Env>,
34    Gas: TxGas<Env>,
35    Data: TxData<Env>,
36    RH: TxResultHandler<Env>,
37{
38    pub env: Env,
39    pub from: From,
40    pub to: To,
41    pub payment: Payment,
42    pub gas: Gas,
43    pub data: Data,
44    pub result_handler: RH,
45}
46
47impl<Env, From, To, Payment, Gas, Data, RH> Tx<Env, From, To, Payment, Gas, Data, RH>
48where
49    Env: TxEnv,
50    From: TxFrom<Env>,
51    To: TxTo<Env>,
52    Payment: TxPayment<Env>,
53    Gas: TxGas<Env>,
54    Data: TxDataFunctionCall<Env>,
55    RH: TxResultHandler<Env>,
56{
57    /// Converts object to a MultiversX transaction data field string.
58    pub fn to_call_data_string(&self) -> ManagedBuffer<Env::Api> {
59        self.data.to_call_data_string()
60    }
61}
62
63pub type TxBaseWithEnv<Env> = Tx<Env, (), (), (), (), (), ()>;
64
65impl<Env> TxBaseWithEnv<Env>
66where
67    Env: TxEnv,
68{
69    /// Constructor, needs to take an environment object.
70    #[inline]
71    pub fn new_with_env(env: Env) -> Self {
72        Tx {
73            env,
74            from: (),
75            to: (),
76            payment: (),
77            gas: (),
78            data: (),
79            result_handler: (),
80        }
81    }
82}
83
84impl<Env, To, Payment, Gas, Data, RH> Tx<Env, (), To, Payment, Gas, Data, RH>
85where
86    Env: TxEnv,
87    To: TxTo<Env>,
88    Payment: TxPayment<Env>,
89    Gas: TxGas<Env>,
90    Data: TxData<Env>,
91    RH: TxResultHandler<Env>,
92{
93    /// Specifies transaction sender.
94    pub fn from<From>(self, from: From) -> Tx<Env, From, To, Payment, Gas, Data, RH>
95    where
96        From: TxFrom<Env>,
97    {
98        Tx {
99            env: self.env,
100            from,
101            to: self.to,
102            payment: self.payment,
103            gas: self.gas,
104            data: self.data,
105            result_handler: self.result_handler,
106        }
107    }
108}
109
110impl<Env, From, Payment, Gas, Data, RH> Tx<Env, From, (), Payment, Gas, Data, RH>
111where
112    Env: TxEnv,
113    From: TxFrom<Env>,
114    Payment: TxPayment<Env>,
115    Gas: TxGas<Env>,
116    Data: TxData<Env>,
117    RH: TxResultHandler<Env>,
118{
119    /// Specifies the recipient of the transaction.
120    ///
121    /// Allows argument to also be `()`.
122    pub fn to<To>(self, to: To) -> Tx<Env, From, To, Payment, Gas, Data, RH>
123    where
124        To: TxTo<Env>,
125    {
126        Tx {
127            env: self.env,
128            from: self.from,
129            to,
130            payment: self.payment,
131            gas: self.gas,
132            data: self.data,
133            result_handler: self.result_handler,
134        }
135    }
136}
137
138impl<Env, From, To, OldPayment, Gas, Data, RH> Tx<Env, From, To, OldPayment, Gas, Data, RH>
139where
140    Env: TxEnv,
141    From: TxFrom<Env>,
142    To: TxTo<Env>,
143    OldPayment: TxPayment<Env>,
144    Gas: TxGas<Env>,
145    Data: TxData<Env>,
146    RH: TxResultHandler<Env>,
147{
148    /// Adds any payment to a transaction, using the payment compose mechanism.
149    ///
150    /// # Compose Mechanism
151    ///
152    /// The `payment` method is generic and flexible, allowing you to add any type of payment to a transaction.
153    /// It uses the [`TxPaymentCompose`] trait to determine how to combine the existing payment (if any)
154    /// with the new payment being added. This enables a fluent and type-safe way to build up complex payment scenarios.
155    ///
156    /// - If no payment has been added yet (i.e., the payment type is `()`), the new payment is simply set as the transaction's payment.
157    /// - If a payment already exists, the `compose` method is called, which merges the new payment with the existing one according to the rules defined by their types.
158    /// - This allows for single or multiple ESDT payments, EGLD payments, or combinations thereof, all handled transparently.
159    ///
160    /// ## Example
161    ///
162    /// ```ignore
163    /// let tx = Tx::new_with_env(env)
164    ///     .to(address)
165    ///     .payment(esdt_payment)
166    ///     .payment(another_esdt_payment)
167    ///     .payment(egld_payment);
168    /// ```
169    ///
170    /// Each call to `.payment(...)` will combine the new payment with the previous one, producing the correct payment type for the transaction.
171    ///
172    /// This mechanism is extensible and supports custom payment types as long as they implement the required traits.
173    pub fn payment<NewPayment>(
174        self,
175        payment: NewPayment,
176    ) -> Tx<Env, From, To, <OldPayment as TxPaymentCompose<Env, NewPayment>>::Output, Gas, Data, RH>
177    where
178        NewPayment: TxPayment<Env>,
179        OldPayment: TxPaymentCompose<Env, NewPayment>,
180    {
181        Tx {
182            env: self.env,
183            from: self.from,
184            to: self.to,
185            payment: self.payment.compose(payment),
186            gas: self.gas,
187            data: self.data,
188            result_handler: self.result_handler,
189        }
190    }
191}
192
193impl<Env, From, To, Gas, Data, RH> Tx<Env, From, To, (), Gas, Data, RH>
194where
195    Env: TxEnv,
196    From: TxFrom<Env>,
197    To: TxTo<Env>,
198    Gas: TxGas<Env>,
199    Data: TxData<Env>,
200    RH: TxResultHandler<Env>,
201{
202    /// Adds EGLD value to a transaction.
203    ///
204    /// Accepts any type that can represent and EGLD amount: BigUint, &BigUint, etc.
205    pub fn egld<EgldValue>(
206        self,
207        egld_value: EgldValue,
208    ) -> Tx<Env, From, To, Egld<EgldValue>, Gas, Data, RH>
209    where
210        EgldValue: TxEgldValue<Env>,
211    {
212        self.payment(Egld(egld_value))
213    }
214
215    /// Backwards compatibility. Use method `egld` instead.
216    pub fn with_egld_transfer(
217        self,
218        egld_amount: BigUint<Env::Api>,
219    ) -> Tx<Env, From, To, EgldPayment<Env::Api>, Gas, Data, RH> {
220        self.egld(egld_amount)
221    }
222
223    /// Adds the first single, owned ESDT token payment to a transaction.
224    ///
225    /// Since this is the first ESDT payment, a single payment tx is produced.
226    ///
227    /// Can subsequently be called again for multiple payments.
228    #[deprecated(
229        since = "0.65.0",
230        note = "Use .payment(...) instead, also try to migrate to `Payment` as the unique payment type."
231    )]
232    pub fn esdt<P: Into<EsdtTokenPayment<Env::Api>>>(
233        self,
234        payment: P,
235    ) -> Tx<Env, From, To, EsdtTokenPayment<Env::Api>, Gas, Data, RH> {
236        self.payment(payment.into())
237    }
238
239    /// Sets a single token payment, with the token identifier and amount kept as references.
240    ///
241    /// This is handy when we only want one ESDT transfer and we want to avoid unnecessary object clones.
242    pub fn single_esdt<'a>(
243        self,
244        token_identifier: &'a EsdtTokenIdentifier<Env::Api>,
245        token_nonce: u64,
246        amount: &'a BigUint<Env::Api>,
247    ) -> Tx<Env, From, To, EsdtTokenPaymentRefs<'a, Env::Api>, Gas, Data, RH> {
248        self.payment(EsdtTokenPaymentRefs {
249            token_identifier,
250            token_nonce,
251            amount,
252        })
253    }
254
255    /// Syntactic sugar for `self.payment(EgldOrEsdtTokenPaymentRefs::new(...)`. Takes references.
256    pub fn egld_or_single_esdt<'a>(
257        self,
258        token_identifier: &'a EgldOrEsdtTokenIdentifier<Env::Api>,
259        token_nonce: u64,
260        amount: &'a BigUint<Env::Api>,
261    ) -> Tx<Env, From, To, EgldOrEsdtTokenPaymentRefs<'a, Env::Api>, Gas, Data, RH> {
262        self.payment(EgldOrEsdtTokenPaymentRefs::new(
263            token_identifier,
264            token_nonce,
265            amount,
266        ))
267    }
268
269    /// Sets a collection of ESDT transfers as the payment of the transaction.
270    ///
271    /// Can be formed from single ESDT payments, but the result will always be a collection.
272    ///
273    /// Always converts the argument into an owned collection of ESDT payments. For work with references, use `.payment(&p)` instead.
274    #[deprecated(
275        since = "0.65.0",
276        note = "Use .payment(...) instead, it should support all the same, plus composition of payments"
277    )]
278    pub fn multi_esdt<IntoMulti>(
279        self,
280        payments: IntoMulti,
281    ) -> Tx<Env, From, To, EsdtTokenPaymentVec<Env::Api>, Gas, Data, RH>
282    where
283        IntoMulti: Into<EsdtTokenPaymentVec<Env::Api>>,
284    {
285        self.payment(payments.into())
286    }
287
288    /// Backwards compatibility.
289    pub fn with_esdt_transfer<P: Into<EsdtTokenPayment<Env::Api>>>(
290        self,
291        payment: P,
292    ) -> Tx<Env, From, To, EsdtTokenPaymentVec<Env::Api>, Gas, Data, RH> {
293        self.payment(EsdtTokenPaymentVec::new())
294            .with_esdt_transfer(payment)
295    }
296
297    /// Backwards compatibility.
298    pub fn with_multi_token_transfer(
299        self,
300        payments: EsdtTokenPaymentVec<Env::Api>,
301    ) -> Tx<Env, From, To, EsdtTokenPaymentVec<Env::Api>, Gas, Data, RH> {
302        self.multi_esdt(payments)
303    }
304
305    /// Backwards compatibility.
306    pub fn with_egld_or_single_esdt_transfer<P: Into<EgldOrEsdtTokenPayment<Env::Api>>>(
307        self,
308        payment: P,
309    ) -> Tx<Env, From, To, EgldOrEsdtTokenPayment<Env::Api>, Gas, Data, RH> {
310        self.payment(payment.into())
311    }
312
313    /// Converts argument to `EgldOrMultiEsdtPayment`, then sets it as payment.
314    ///
315    /// In most cases, `payment` should be used instead.
316    pub fn egld_or_multi_esdt<P: Into<EgldOrMultiEsdtPayment<Env::Api>>>(
317        self,
318        payment: P,
319    ) -> Tx<Env, From, To, EgldOrMultiEsdtPayment<Env::Api>, Gas, Data, RH> {
320        self.payment(payment.into())
321    }
322}
323
324impl<Env, From, To, Gas, Data, RH> Tx<Env, From, To, EsdtTokenPayment<Env::Api>, Gas, Data, RH>
325where
326    Env: TxEnv,
327    From: TxFrom<Env>,
328    To: TxTo<Env>,
329    Gas: TxGas<Env>,
330    Data: TxData<Env>,
331    RH: TxResultHandler<Env>,
332{
333    /// Adds the second ESDT token transfer to a contract call.
334    ///
335    /// Can be called multiple times on the same call.
336    ///
337    /// When the Tx already contains a single (owned) ESDT payment,
338    /// adding the second one will convert it to a list.
339    #[deprecated(
340        since = "0.65.0",
341        note = "Use .payment(...) instead, also try to migrate to `Payment` as the unique payment type."
342    )]
343    pub fn esdt<P: Into<EsdtTokenPayment<Env::Api>>>(
344        self,
345        payment: P,
346    ) -> Tx<Env, From, To, EsdtTokenPaymentVec<Env::Api>, Gas, Data, RH> {
347        let mut payments = ManagedVec::new();
348        payments.push(self.payment);
349        payments.push(payment.into());
350        Tx {
351            env: self.env,
352            from: self.from,
353            to: self.to,
354            payment: payments,
355            gas: self.gas,
356            data: self.data,
357            result_handler: self.result_handler,
358        }
359    }
360}
361
362impl<Env, From, To, Gas, Data, RH> Tx<Env, From, To, EsdtTokenPaymentVec<Env::Api>, Gas, Data, RH>
363where
364    Env: TxEnv,
365    From: TxFrom<Env>,
366    To: TxTo<Env>,
367    Gas: TxGas<Env>,
368    Data: TxData<Env>,
369    RH: TxResultHandler<Env>,
370{
371    /// Adds a single ESDT token transfer to a contract call.
372    ///
373    /// Can be called multiple times on the same call.
374    #[deprecated(
375        since = "0.65.0",
376        note = "Use .payment(...) instead, also try to migrate to `Payment` as the unique payment type."
377    )]
378    pub fn esdt<P: Into<EsdtTokenPayment<Env::Api>>>(
379        mut self,
380        payment: P,
381    ) -> Tx<Env, From, To, EsdtTokenPaymentVec<Env::Api>, Gas, Data, RH> {
382        self.payment.push(payment.into());
383        self
384    }
385
386    /// When the Tx already contains an owned collection of ESDT payments,
387    /// calling `multi_esdt` is equivalent to `esdt`, it just adds another payment to the list.
388    ///
389    /// Can be called multiple times.
390    #[deprecated(
391        since = "0.65.0",
392        note = "Use .payment(...) instead, it should support all the same, plus composition of payments"
393    )]
394    pub fn multi_esdt<P: Into<EsdtTokenPayment<Env::Api>>>(
395        self,
396        payment: P,
397    ) -> Tx<Env, From, To, EsdtTokenPaymentVec<Env::Api>, Gas, Data, RH> {
398        self.esdt(payment)
399    }
400
401    /// Backwards compatibility.
402    pub fn with_esdt_transfer<P: Into<EsdtTokenPayment<Env::Api>>>(
403        self,
404        payment: P,
405    ) -> Tx<Env, From, To, EsdtTokenPaymentVec<Env::Api>, Gas, Data, RH> {
406        self.multi_esdt(payment)
407    }
408}
409
410impl<Env, From, To, Payment, Data, RH> Tx<Env, From, To, Payment, (), Data, RH>
411where
412    Env: TxEnv,
413    From: TxFrom<Env>,
414    To: TxTo<Env>,
415    Payment: TxPayment<Env>,
416    Data: TxData<Env>,
417    RH: TxResultHandler<Env>,
418{
419    /// Sets an explicit gas limit to the call.
420    #[inline]
421    pub fn gas<GasValue>(
422        self,
423        gas_value: GasValue,
424    ) -> Tx<Env, From, To, Payment, ExplicitGas<GasValue>, Data, RH>
425    where
426        GasValue: TxGasValue<Env>,
427    {
428        Tx {
429            env: self.env,
430            from: self.from,
431            to: self.to,
432            payment: self.payment,
433            gas: ExplicitGas(gas_value),
434            data: self.data,
435            result_handler: self.result_handler,
436        }
437    }
438
439    /// Backwards compatibility.
440    #[inline]
441    pub fn with_gas_limit(
442        self,
443        gas_limit: u64,
444    ) -> Tx<Env, From, To, Payment, ExplicitGas<u64>, Data, RH> {
445        Tx {
446            env: self.env,
447            from: self.from,
448            to: self.to,
449            payment: self.payment,
450            gas: ExplicitGas(gas_limit),
451            data: self.data,
452            result_handler: self.result_handler,
453        }
454    }
455}
456
457impl<Env, From, To, Payment, Gas, RH> Tx<Env, From, To, Payment, Gas, (), RH>
458where
459    Env: TxEnv,
460    From: TxFrom<Env>,
461    To: TxTo<Env>,
462    Payment: TxPayment<Env>,
463    Gas: TxGas<Env>,
464    RH: TxResultHandler<Env>,
465{
466    /// Sets the data field. Do not use directly.
467    #[inline]
468    #[doc(hidden)]
469    pub fn raw_data<Data>(self, data: Data) -> Tx<Env, From, To, Payment, Gas, Data, RH>
470    where
471        Data: TxData<Env>,
472    {
473        Tx {
474            env: self.env,
475            from: self.from,
476            to: self.to,
477            payment: self.payment,
478            gas: self.gas,
479            data,
480            result_handler: self.result_handler,
481        }
482    }
483
484    /// Starts a contract call, serialized by hand.
485    ///
486    /// Whenever possible, should use proxies instead, since manual serialization is not type-safe.
487    #[inline]
488    pub fn raw_call<N: Into<ManagedBuffer<Env::Api>>>(
489        self,
490        function_name: N,
491    ) -> Tx<Env, From, To, Payment, Gas, FunctionCall<Env::Api>, RH> {
492        self.raw_data(FunctionCall::new(function_name))
493    }
494}
495
496impl<Env, From, To, Payment, Gas, RH> Tx<Env, From, To, Payment, Gas, FunctionCall<Env::Api>, RH>
497where
498    Env: TxEnv,
499    From: TxFrom<Env>,
500    To: TxTo<Env>,
501    Payment: TxPayment<Env>,
502    Gas: TxGas<Env>,
503    RH: TxResultHandler<Env>,
504{
505    /// Converts tx to a simple FunctionCall, to be used as argument or data in contracts.
506    pub fn into_function_call(self) -> FunctionCall<Env::Api> {
507        self.data
508    }
509}
510
511impl<Env, From, To, Payment, Gas, RH> Tx<Env, From, To, Payment, Gas, FunctionCall<Env::Api>, RH>
512where
513    Env: TxEnv,
514    From: TxFrom<Env>,
515    To: TxToSpecified<Env>,
516    Payment: TxPayment<Env>,
517    Gas: TxGas<Env>,
518    RH: TxResultHandler<Env>,
519{
520    /// Produces the normalized function call, i.e. with builtin function calls for ESDT transfers.
521    ///
522    /// The resulting transaction can differ from the input in several ways:
523    /// - the recipient is changed (some builtin functions are called with recipient = sender),
524    /// - the function call becomes a builtin function call.
525    ///
526    /// ## Important
527    ///
528    /// Do not call this before sending transactions! Normalization is don automatically whenever necessary.
529    /// Only use when you need the normalized data, e.g. for a multisig.
530    ///
531    /// ## Warning
532    ///
533    /// To produce owned values, some clones are performed.
534    /// It is not optimized for contracts, but can be used nonetheless.
535    #[allow(clippy::type_complexity)]
536    pub fn normalize(
537        self,
538    ) -> Tx<
539        Env,
540        From,
541        ManagedAddress<Env::Api>,
542        EgldPayment<Env::Api>,
543        Gas,
544        FunctionCall<Env::Api>,
545        RH,
546    > {
547        let (norm_to, norm_egld, norm_fc) = self.payment.with_normalized(
548            &self.env,
549            &self.from,
550            self.to,
551            self.data,
552            |norm_to, norm_egld, norm_fc| (norm_to.clone(), norm_egld.clone(), norm_fc),
553        );
554
555        Tx {
556            env: self.env,
557            from: self.from,
558            to: norm_to,
559            payment: Egld(norm_egld),
560            gas: self.gas,
561            data: norm_fc,
562            result_handler: self.result_handler,
563        }
564    }
565}
566
567impl<Env, From, Payment, Gas> Tx<Env, From, (), Payment, Gas, (), ()>
568where
569    Env: TxEnv,
570    From: TxFrom<Env>,
571    Payment: TxPayment<Env>,
572    Gas: TxGas<Env>,
573{
574    /// Merges the argument data into the current tx.
575    /// Used for function calls originating in legacy proxies.
576    ///
577    /// Different environment in the argument allowed because of compatibility with old proxies.
578    ///
579    /// Method still subject to considerable change.
580    pub fn legacy_proxy_call<Env2, To, O>(
581        self,
582        call: Tx<Env2, (), To, (), (), FunctionCall<Env::Api>, OriginalResultMarker<O>>,
583    ) -> Tx<Env, From, To, Payment, Gas, FunctionCall<Env::Api>, OriginalResultMarker<O>>
584    where
585        Env2: TxEnv<Api = Env::Api>,
586        To: TxTo<Env> + TxTo<Env2>,
587    {
588        Tx {
589            env: self.env,
590            from: self.from,
591            to: call.to,
592            payment: self.payment,
593            gas: self.gas,
594            data: call.data,
595            result_handler: call.result_handler,
596        }
597    }
598}
599
600impl<Env, From, To, Payment, Gas, RH> Tx<Env, From, To, Payment, Gas, FunctionCall<Env::Api>, RH>
601where
602    Env: TxEnv,
603    From: TxFrom<Env>,
604    To: TxTo<Env>,
605    Payment: TxPayment<Env>,
606    Gas: TxGas<Env>,
607    RH: TxResultHandler<Env>,
608{
609    /// Adds argument to function call.
610    ///
611    /// Whenever possible, use proxies instead.
612    ///
613    /// It serializes the value, but does not enforce type safety.
614    #[inline]
615    pub fn argument<T: TopEncodeMulti>(mut self, arg: &T) -> Self {
616        self.data = self.data.argument(arg);
617        self
618    }
619
620    /// Adds serialized argument to function call.
621    ///
622    /// Whenever possible, use proxies instead.
623    ///
624    /// Does not serialize, does not enforce type safety.
625    #[inline]
626    pub fn arguments_raw(mut self, raw: ManagedArgBuffer<Env::Api>) -> Self {
627        self.data.arg_buffer = raw;
628        self
629    }
630}
631
632impl<Env, From, To, Payment, Gas, Data> Tx<Env, From, To, Payment, Gas, Data, ()>
633where
634    Env: TxEnv,
635    From: TxFrom<Env>,
636    To: TxTo<Env>,
637    Payment: TxPayment<Env>,
638    Gas: TxGas<Env>,
639    Data: TxData<Env>,
640{
641    /// Type marker to set the original contract or VM function return type.
642    ///
643    /// Only the compile-time type annotation is given.
644    #[inline]
645    pub fn original_result<OriginalResult>(
646        self,
647    ) -> Tx<Env, From, To, Payment, Gas, Data, OriginalResultMarker<OriginalResult>> {
648        Tx {
649            env: self.env,
650            from: self.from,
651            to: self.to,
652            payment: self.payment,
653            gas: self.gas,
654            data: self.data,
655            result_handler: OriginalResultMarker::new(),
656        }
657    }
658}
659
660impl<Env, From, To, Gas> Tx<Env, From, To, (), Gas, (), ()>
661where
662    Env: TxEnv,
663    From: TxFrom<Env>,
664    To: TxTo<Env>,
665    Gas: TxGas<Env>,
666{
667    /// Starts a proxy call, deploy, or upgrade.
668    ///
669    /// The proxy object will be given, the subsequent call will be from a proxy context, containing all the contract endpoint names.
670    pub fn typed<Proxy>(self, proxy: Proxy) -> Proxy::TxProxyMethods
671    where
672        Proxy: TxProxyTrait<Env, From, To, Gas>,
673    {
674        proxy.proxy_methods(self)
675    }
676}
677
678impl<Env, From, To, Payment, Gas, Data, ResultList>
679    Tx<Env, From, To, Payment, Gas, Data, ResultList>
680where
681    Env: TxEnv,
682    From: TxFrom<Env>,
683    To: TxTo<Env>,
684    Payment: TxPayment<Env>,
685    Gas: TxGas<Env>,
686    Data: TxData<Env>,
687    ResultList: RHList<Env>,
688{
689    /// Adds a result handler that doesn't return anything.
690    #[inline]
691    pub fn with_result<ResultHandler>(
692        self,
693        result_handler: ResultHandler,
694    ) -> Tx<Env, From, To, Payment, Gas, Data, ResultList::NoRetOutput>
695    where
696        ResultHandler: RHListItem<Env, ResultList::OriginalResult, Returns = ()>,
697        ResultList: RHListAppendNoRet<Env, ResultHandler>,
698    {
699        Tx {
700            env: self.env,
701            from: self.from,
702            to: self.to,
703            payment: self.payment,
704            gas: self.gas,
705            data: self.data,
706            result_handler: self.result_handler.append_no_ret(result_handler),
707        }
708    }
709
710    /// Adds a result handler that can also return processed data.
711    #[inline]
712    pub fn returns<RH>(
713        self,
714        item: RH,
715    ) -> Tx<Env, From, To, Payment, Gas, Data, ResultList::RetOutput>
716    where
717        RH: RHListItem<Env, ResultList::OriginalResult>,
718        ResultList: RHListAppendRet<Env, RH>,
719    {
720        Tx {
721            env: self.env,
722            from: self.from,
723            to: self.to,
724            payment: self.payment,
725            gas: self.gas,
726            data: self.data,
727            result_handler: self.result_handler.append_ret(item),
728        }
729    }
730}
731
732impl<Env, From, To, Payment, Gas, RH> Tx<Env, From, To, Payment, Gas, (), RH>
733where
734    Env: TxEnv,
735    From: TxFrom<Env>,
736    To: TxTo<Env>,
737    Payment: TxPaymentEgldOnly<Env>,
738    Gas: TxGas<Env>,
739    RH: TxResultHandler<Env>,
740{
741    /// Starts a contract deploy call, serialized by hand.
742    ///
743    /// Whenever possible, should use proxies instead, since manual serialization is not type-safe.
744    pub fn raw_deploy(self) -> Tx<Env, From, To, Payment, Gas, DeployCall<Env, ()>, RH> {
745        self.raw_data(DeployCall::default())
746    }
747}
748
749impl<Env, From, To, Payment, Gas, RH> Tx<Env, From, To, Payment, Gas, UpgradeCall<Env, ()>, RH>
750where
751    Env: TxEnv,
752    From: TxFrom<Env>,
753    To: TxTo<Env>,
754    Payment: TxPaymentEgldOnly<Env>,
755    Gas: TxGas<Env>,
756    RH: TxResultHandler<Env>,
757{
758    /// Sets upgrade code source as explicit code bytes.
759    pub fn code<CodeValue>(
760        self,
761        code: CodeValue,
762    ) -> Tx<Env, From, To, Payment, Gas, UpgradeCall<Env, Code<CodeValue>>, RH>
763    where
764        CodeValue: TxCodeValue<Env>,
765    {
766        Tx {
767            env: self.env,
768            from: self.from,
769            to: self.to,
770            payment: self.payment,
771            gas: self.gas,
772            data: self.data.code_source(Code(code)),
773            result_handler: self.result_handler,
774        }
775    }
776
777    /// Sets upgrade code source as another deployed contract code.
778    pub fn from_source<FromSourceValue>(
779        self,
780        source_address: FromSourceValue,
781    ) -> Tx<Env, From, To, Payment, Gas, UpgradeCall<Env, FromSource<FromSourceValue>>, RH>
782    where
783        FromSourceValue: TxFromSourceValue<Env>,
784    {
785        Tx {
786            env: self.env,
787            from: self.from,
788            to: self.to,
789            payment: self.payment,
790            gas: self.gas,
791            data: self.data.code_source(FromSource(source_address)),
792            result_handler: self.result_handler,
793        }
794    }
795}
796
797impl<Env, From, To, Payment, Gas, RH> Tx<Env, From, To, Payment, Gas, DeployCall<Env, ()>, RH>
798where
799    Env: TxEnv,
800    From: TxFrom<Env>,
801    To: TxTo<Env>,
802    Payment: TxPaymentEgldOnly<Env>,
803    Gas: TxGas<Env>,
804    RH: TxResultHandler<Env>,
805{
806    /// Sets deploy code source as explicit code bytes.
807    pub fn code<CodeValue>(
808        self,
809        code: CodeValue,
810    ) -> Tx<Env, From, To, Payment, Gas, DeployCall<Env, Code<CodeValue>>, RH>
811    where
812        CodeValue: TxCodeValue<Env>,
813    {
814        Tx {
815            env: self.env,
816            from: self.from,
817            to: self.to,
818            payment: self.payment,
819            gas: self.gas,
820            data: self.data.code_source(Code(code)),
821            result_handler: self.result_handler,
822        }
823    }
824
825    /// Sets deploy code source as another deployed contract code.
826    pub fn from_source<FromSourceValue>(
827        self,
828        source_address: FromSourceValue,
829    ) -> Tx<Env, From, To, Payment, Gas, DeployCall<Env, FromSource<FromSourceValue>>, RH>
830    where
831        FromSourceValue: TxFromSourceValue<Env>,
832    {
833        Tx {
834            env: self.env,
835            from: self.from,
836            to: self.to,
837            payment: self.payment,
838            gas: self.gas,
839            data: self.data.code_source(FromSource(source_address)),
840            result_handler: self.result_handler,
841        }
842    }
843}
844
845impl<Env, From, To, Payment, Gas, CodeSource, RH>
846    Tx<Env, From, To, Payment, Gas, DeployCall<Env, CodeSource>, RH>
847where
848    Env: TxEnv,
849    From: TxFrom<Env>,
850    To: TxTo<Env>,
851    Payment: TxPaymentEgldOnly<Env>,
852    Gas: TxGas<Env>,
853    CodeSource: TxCodeSource<Env>,
854    RH: TxResultHandler<Env>,
855{
856    /// Sets code metadata to deploy.
857    pub fn code_metadata(mut self, code_metadata: CodeMetadata) -> Self {
858        self.data = self.data.code_metadata(code_metadata);
859        self
860    }
861
862    /// Adds argument to a contract deploy.
863    ///
864    /// Whenever possible, use proxies instead.
865    ///
866    /// It serializes the value, but does not enforce type safety.
867    #[inline]
868    pub fn argument<T: TopEncodeMulti>(mut self, arg: &T) -> Self {
869        self.data = self.data.argument(arg);
870        self
871    }
872
873    /// Adds serialized argument to a contract deploy.
874    ///
875    /// Whenever possible, use proxies instead.
876    ///
877    /// Does not serialize, does not enforce type safety.
878    #[inline]
879    pub fn arguments_raw(mut self, raw: ManagedArgBuffer<Env::Api>) -> Self {
880        self.data.arg_buffer = raw;
881        self
882    }
883}
884
885impl<Env, From, To, Payment, Gas, CodeSource, RH>
886    Tx<Env, From, To, Payment, Gas, DeployCall<Env, CodeSource>, RH>
887where
888    Env: TxEnvMockDeployAddress,
889    From: TxFromSpecified<Env>,
890    To: TxTo<Env>,
891    Payment: TxPaymentEgldOnly<Env>,
892    Gas: TxGas<Env>,
893    CodeSource: TxCodeSource<Env>,
894    RH: TxResultHandler<Env>,
895{
896    /// Sets the new mock address to be used for the newly deployed contract.
897    ///
898    /// Only allowed in tests.
899    pub fn new_address<NA>(mut self, new_address: NA) -> Self
900    where
901        NA: AnnotatedValue<Env, ManagedAddress<Env::Api>>,
902    {
903        self.env.mock_deploy_new_address(&self.from, new_address);
904        self
905    }
906}
907
908impl<Env, From, To, Payment, Gas, RH> Tx<Env, From, To, Payment, Gas, (), RH>
909where
910    Env: TxEnv,
911    From: TxFrom<Env>,
912    To: TxTo<Env>,
913    Payment: TxPaymentEgldOnly<Env>,
914    Gas: TxGas<Env>,
915    RH: TxResultHandler<Env>,
916{
917    /// Starts a contract deploy upgrade, serialized by hand.
918    ///
919    /// Whenever possible, should use proxies instead, since manual serialization is not type-safe.
920    pub fn raw_upgrade(self) -> Tx<Env, From, To, Payment, Gas, UpgradeCall<Env, ()>, RH> {
921        self.raw_data(UpgradeCall::default())
922    }
923}
924
925impl<Env, From, To, Payment, Gas, CodeSource, RH>
926    Tx<Env, From, To, Payment, Gas, UpgradeCall<Env, CodeSource>, RH>
927where
928    Env: TxEnv,
929    From: TxFrom<Env>,
930    To: TxTo<Env>,
931    Payment: TxPaymentEgldOnly<Env>,
932    Gas: TxGas<Env>,
933    CodeSource: TxCodeSource<Env>,
934    RH: TxResultHandler<Env>,
935{
936    pub fn code_metadata(mut self, code_metadata: CodeMetadata) -> Self {
937        self.data = self.data.code_metadata(code_metadata);
938        self
939    }
940
941    /// Adds argument to upgrade call.
942    ///
943    /// Whenever possible, use proxies instead.
944    ///
945    /// It serializes the value, but does not enforce type safety.
946    #[inline]
947    pub fn argument<T: TopEncodeMulti>(mut self, arg: &T) -> Self {
948        self.data = self.data.argument(arg);
949        self
950    }
951
952    /// Adds serialized argument to an upgrade call.
953    ///
954    /// Whenever possible, use proxies instead.
955    ///
956    /// Doesa not serialize, does not enforce type safety.
957    #[inline]
958    pub fn arguments_raw(mut self, raw: ManagedArgBuffer<Env::Api>) -> Self {
959        self.data.arg_buffer = raw;
960        self
961    }
962}
963
964impl<Env, From, To, Payment, Gas, Data, RH> Tx<Env, From, To, Payment, Gas, Data, RH>
965where
966    Env: TxEnvWithTxHash,
967    From: TxFrom<Env>,
968    To: TxTo<Env>,
969    Payment: TxPayment<Env>,
970    Gas: TxGas<Env>,
971    Data: TxData<Env>,
972    RH: TxResultHandler<Env>,
973{
974    /// Sets the mock transaction ID to be used in a test.
975    ///
976    /// Transaction ids help identifying transactions in tests,
977    /// but they are not used in the actual transaction sending process, so they can be set to any value.
978    ///
979    /// They also show up when generating Mandos (scenario) JSON.
980    pub fn id(mut self, id: &str) -> Self {
981        self.env.set_tx_id(id.to_owned());
982        self
983    }
984
985    /// Sets the mock transaction hash to be used in a test.
986    ///
987    /// Only allowed in tests.
988    pub fn tx_hash<H>(mut self, tx_hash: H) -> Self
989    where
990        H256: core::convert::From<H>,
991    {
992        self.env.set_tx_hash(H256::from(tx_hash));
993        self
994    }
995}