multiversx_sc/types/interaction/tx_data/
function_call.rs1use multiversx_sc_codec::{
2 DecodeErrorHandler, EncodeErrorHandler, TopDecodeMulti, TopDecodeMultiInput, TopEncodeMulti,
3 TopEncodeMultiOutput,
4};
5
6use crate::{
7 abi::{TypeAbi, TypeAbiFrom, TypeName},
8 api::{
9 ESDT_MULTI_TRANSFER_FUNC_NAME, ESDT_NFT_TRANSFER_FUNC_NAME, ESDT_TRANSFER_FUNC_NAME,
10 ManagedTypeApi,
11 },
12 types::{
13 EsdtTokenPaymentRefs, ManagedAddress, ManagedArgBuffer, ManagedBuffer,
14 MultiEgldOrEsdtPayment, MultiValueEncoded,
15 },
16};
17
18#[derive(Clone)]
22pub struct FunctionCall<Api>
23where
24 Api: ManagedTypeApi,
25{
26 pub function_name: ManagedBuffer<Api>,
27 pub arg_buffer: ManagedArgBuffer<Api>,
28}
29
30impl<Api> FunctionCall<Api>
31where
32 Api: ManagedTypeApi,
33{
34 pub fn new<N: Into<ManagedBuffer<Api>>>(function_name: N) -> Self {
38 FunctionCall {
39 function_name: function_name.into(),
40 arg_buffer: ManagedArgBuffer::new(),
41 }
42 }
43
44 pub fn empty() -> Self {
46 FunctionCall::new(ManagedBuffer::new())
47 }
48
49 pub fn is_empty(&self) -> bool {
53 self.function_name.is_empty()
54 }
55
56 pub fn argument<T: TopEncodeMulti>(mut self, arg: &T) -> Self {
60 self.arg_buffer.push_multi_arg(arg);
61 self
62 }
63
64 pub fn arguments_raw(mut self, raw: ManagedArgBuffer<Api>) -> Self {
65 self.arg_buffer = raw;
66 self
67 }
68}
69
70impl<Api> From<()> for FunctionCall<Api>
71where
72 Api: ManagedTypeApi,
73{
74 fn from(_: ()) -> Self {
75 FunctionCall::empty()
76 }
77}
78
79#[cfg(feature = "contract-call-legacy")]
80impl<Api, R> From<crate::types::ContractCallNoPayment<Api, R>> for FunctionCall<Api>
81where
82 Api: crate::api::CallTypeApi,
83{
84 fn from(ccnp: crate::types::ContractCallNoPayment<Api, R>) -> Self {
85 ccnp.function_call
86 }
87}
88
89impl<Api> TopEncodeMulti for FunctionCall<Api>
90where
91 Api: ManagedTypeApi,
92{
93 fn multi_encode_or_handle_err<O, H>(&self, output: &mut O, h: H) -> Result<(), H::HandledErr>
94 where
95 O: TopEncodeMultiOutput,
96 H: EncodeErrorHandler,
97 {
98 if self.function_name.is_empty() {
99 return Ok(());
100 }
101 output.push_single_value(&self.function_name, h)?;
102 for arg in self.arg_buffer.raw_arg_iter() {
103 output.push_single_value(&*arg, h)?;
104 }
105
106 Ok(())
107 }
108}
109
110impl<Api> TopDecodeMulti for FunctionCall<Api>
111where
112 Api: ManagedTypeApi,
113{
114 fn multi_decode_or_handle_err<I, H>(input: &mut I, h: H) -> Result<Self, H::HandledErr>
115 where
116 I: TopDecodeMultiInput,
117 H: DecodeErrorHandler,
118 {
119 if !input.has_next() {
120 return Ok(FunctionCall::empty());
121 }
122
123 let function_name = ManagedBuffer::<Api>::multi_decode_or_handle_err(input, h)?;
124 let args =
125 MultiValueEncoded::<Api, ManagedBuffer<Api>>::multi_decode_or_handle_err(input, h)?;
126 Ok(FunctionCall {
127 function_name,
128 arg_buffer: args.to_arg_buffer(),
129 })
130 }
131}
132
133impl<Api> TypeAbiFrom<Self> for FunctionCall<Api> where Api: ManagedTypeApi {}
134
135impl<Api> TypeAbi for FunctionCall<Api>
136where
137 Api: ManagedTypeApi,
138{
139 type Unmanaged = Self;
140
141 fn type_name() -> TypeName {
142 crate::abi::type_name_variadic::<ManagedBuffer<Api>>()
143 }
144
145 fn type_name_rust() -> TypeName {
146 "FunctionCall<$API>".into()
147 }
148
149 fn is_variadic() -> bool {
150 true
151 }
152}
153
154impl<Api> FunctionCall<Api>
155where
156 Api: ManagedTypeApi,
157{
158 pub(crate) fn convert_to_single_transfer_fungible_call(
160 self,
161 payment: EsdtTokenPaymentRefs<'_, Api>,
162 ) -> FunctionCall<Api> {
163 FunctionCall::new(ESDT_TRANSFER_FUNC_NAME)
166 .argument(&payment.token_identifier.as_managed_buffer())
167 .argument(&payment.amount)
168 .argument(&self)
169 }
170
171 pub(crate) fn convert_to_single_transfer_nft_call(
179 self,
180 to: &ManagedAddress<Api>,
181 payment: EsdtTokenPaymentRefs<'_, Api>,
182 ) -> FunctionCall<Api> {
183 FunctionCall::new(ESDT_NFT_TRANSFER_FUNC_NAME)
186 .argument(&payment.token_identifier.as_managed_buffer())
187 .argument(&payment.token_nonce)
188 .argument(&payment.amount)
189 .argument(to)
190 .argument(&self)
191 }
192
193 pub(crate) fn convert_to_multi_transfer_esdt_call(
195 self,
196 to: &ManagedAddress<Api>,
197 payments: &MultiEgldOrEsdtPayment<Api>,
198 ) -> FunctionCall<Api> {
199 let mut result = FunctionCall::new(ESDT_MULTI_TRANSFER_FUNC_NAME)
200 .argument(&to)
201 .argument(&payments.len());
202
203 for payment in payments {
204 result = result
206 .argument(&payment.token_identifier.token_id)
207 .argument(&payment.token_nonce)
208 .argument(&payment.amount);
209 }
210
211 result.argument(&self)
212 }
213}