multiversx_chain_vm/host/context/
tx_async_call_data.rs1use 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}