multiversx_chain_vm/host/context/
tx_async_call_data.rs

1use crate::{
2    builtin_functions::BuiltinFunctionContainer,
3    host::context::{TxInput, TxResult},
4    types::{top_encode_u64, VMAddress, H256},
5};
6
7use num_bigint::BigUint;
8
9use super::{CallType, CallbackPayments, Promise, TxFunctionName};
10
11#[derive(Debug, Clone)]
12pub struct AsyncCallTxData {
13    pub from: VMAddress,
14    pub to: VMAddress,
15    pub call_value: BigUint,
16    pub endpoint_name: TxFunctionName,
17    pub arguments: Vec<Vec<u8>>,
18    pub tx_hash: H256,
19}
20
21pub fn async_call_tx_input(async_call: &AsyncCallTxData, call_type: CallType) -> TxInput {
22    TxInput {
23        from: async_call.from.clone(),
24        to: async_call.to.clone(),
25        egld_value: async_call.call_value.clone(),
26        esdt_values: Vec::new(),
27        func_name: async_call.endpoint_name.clone(),
28        args: async_call.arguments.clone(),
29        call_type,
30        gas_limit: 1000,
31        gas_price: 0,
32        tx_hash: async_call.tx_hash.clone(),
33        ..Default::default()
34    }
35}
36
37fn result_status_bytes(result_status: u64) -> Vec<u8> {
38    if result_status == 0 {
39        vec![0x00]
40    } else {
41        top_encode_u64(result_status)
42    }
43}
44
45fn real_recipient(
46    async_data: &AsyncCallTxData,
47    builtin_functions: &BuiltinFunctionContainer,
48) -> VMAddress {
49    let tx_input = async_call_tx_input(async_data, CallType::AsyncCall);
50    let transfers = builtin_functions.extract_token_transfers(&tx_input);
51    transfers.real_recipient
52}
53
54pub fn async_callback_tx_input(
55    async_data: &AsyncCallTxData,
56    async_result: &TxResult,
57    builtin_functions: &BuiltinFunctionContainer,
58) -> TxInput {
59    let mut args: Vec<Vec<u8>> = vec![result_status_bytes(async_result.result_status.as_u64())];
60    if async_result.result_status.is_success() {
61        args.extend_from_slice(async_result.result_values.as_slice());
62    } else {
63        args.push(async_result.result_message.clone().into_bytes());
64    }
65    let callback_payments =
66        extract_callback_payments(&async_data.from, async_result, builtin_functions);
67    TxInput {
68        from: real_recipient(async_data, builtin_functions),
69        to: async_data.from.clone(),
70        egld_value: 0u32.into(),
71        esdt_values: Vec::new(),
72        func_name: TxFunctionName::CALLBACK,
73        args,
74        call_type: CallType::AsyncCallback,
75        gas_limit: 1000,
76        gas_price: 0,
77        tx_hash: async_data.tx_hash.clone(),
78        callback_payments,
79        ..Default::default()
80    }
81}
82
83fn extract_callback_payments(
84    callback_contract_address: &VMAddress,
85    async_result: &TxResult,
86    builtin_functions: &BuiltinFunctionContainer,
87) -> CallbackPayments {
88    let mut callback_payments = CallbackPayments::default();
89    for async_call in &async_result.all_calls {
90        let tx_input = async_call_tx_input(async_call, CallType::AsyncCall);
91        let token_transfers = builtin_functions.extract_token_transfers(&tx_input);
92        if &token_transfers.real_recipient == callback_contract_address {
93            if !token_transfers.is_empty() {
94                callback_payments.esdt_values = token_transfers.transfers;
95            } else {
96                callback_payments
97                    .egld_value
98                    .clone_from(&async_call.call_value);
99            }
100            break;
101        }
102    }
103    callback_payments
104}
105
106pub fn async_promise_callback_tx_input(
107    promise: &Promise,
108    async_result: &TxResult,
109    builtin_functions: &BuiltinFunctionContainer,
110) -> TxInput {
111    let callback_name = if async_result.result_status.is_success() {
112        promise.success_callback.clone()
113    } else {
114        promise.error_callback.clone()
115    };
116
117    let mut callback_input =
118        async_callback_tx_input(&promise.call, async_result, builtin_functions);
119    callback_input.func_name = callback_name;
120    callback_input.promise_callback_closure_data = Some(promise.callback_closure_data.clone());
121    callback_input
122}
123
124pub fn merge_results(mut original: TxResult, mut new: TxResult) -> TxResult {
125    if original.result_status.is_success() {
126        original.result_values.append(&mut new.result_values);
127        original.result_logs.append(&mut new.result_logs);
128        original.result_message = new.result_message;
129        original
130    } else {
131        new
132    }
133}