multiversx_sc/types/interaction/
tx.rs

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