multiversx_sc/types/interaction/
tx.rs

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