odra_core/call_result.rs
1use crate::casper_types::bytesrepr::{Bytes, ToBytes};
2use crate::prelude::*;
3use crate::utils::extract_event_name;
4use casper_event_standard::EventInstance;
5
6/// Represents the result of a contract call. Includes external contracts calls.
7///
8/// The result contains the address of the called contract, the address of the caller, the amount of gas
9/// used, the result of the call, and the events emitted by the contract.
10#[derive(Debug, Clone)]
11pub(crate) struct CallResult {
12 contract_address: Address,
13 caller: Address,
14 gas_used: u64,
15 result: OdraResult<Bytes>,
16 events: BTreeMap<Address, Vec<Bytes>>
17}
18
19impl CallResult {
20 /// Creates a new `CallResult` instance with the specified parameters.
21 pub fn new(
22 contract_address: Address,
23 caller: Address,
24 gas_used: u64,
25 result: OdraResult<Bytes>,
26 events: BTreeMap<Address, Vec<Bytes>>
27 ) -> Self {
28 Self {
29 contract_address,
30 caller,
31 gas_used,
32 result,
33 events
34 }
35 }
36
37 /// Returns the result of the contract call as a [Bytes] object.
38 ///
39 /// # Panics
40 ///
41 /// Panics if the result is an error.
42 pub fn bytes(&self) -> Bytes {
43 match &self.result {
44 Ok(result) => result.clone(),
45 Err(error) => {
46 panic!("Last call result is an error: {:?}", error);
47 }
48 }
49 }
50
51 /// Returns the result of the contract call as a [OdraResult] object.
52 pub fn result(&self) -> OdraResult<Bytes> {
53 self.result.clone()
54 }
55
56 /// Returns the error of the contract call as an `OdraError` object.
57 pub fn error(&self) -> OdraError {
58 match &self.result {
59 Ok(_) => {
60 panic!("Last call result is not an error");
61 }
62 Err(error) => error.clone()
63 }
64 }
65
66 /// Returns the address of the caller.
67 pub fn caller(&self) -> Address {
68 self.caller
69 }
70
71 /// Returns the amount of gas used in the contract call.
72 pub fn gas_used(&self) -> u64 {
73 self.gas_used
74 }
75
76 /// Returns the address of the contract.
77 pub fn contract_address(&self) -> Address {
78 self.contract_address
79 }
80
81 /// Returns the names of the events emitted by the contract at the given address.
82 pub fn event_names(&self, contract_address: &Address) -> Vec<String> {
83 self.events
84 .get(contract_address)
85 .unwrap_or(&vec![])
86 .iter()
87 .map(|event_bytes| extract_event_name(event_bytes).unwrap())
88 .collect()
89 }
90
91 /// Returns the events emitted by the contract at the given address.
92 pub fn contract_events(&self, contract_address: &Address) -> Vec<Bytes> {
93 self.events.get(contract_address).unwrap_or(&vec![]).clone()
94 }
95
96 /// Checks if the specified event has been emitted by the contract at the given address.
97 pub fn emitted(&self, contract_address: &Address, event_name: &str) -> bool {
98 self.event_names(contract_address)
99 .contains(&event_name.to_string())
100 }
101
102 /// Checks if the specified event instance has been emitted by the contract at the given address.
103 pub fn emitted_event<T: ToBytes + EventInstance>(
104 &self,
105 contract_address: &Address,
106 event: &T
107 ) -> bool {
108 self.contract_events(contract_address)
109 .contains(&Bytes::from(event.to_bytes().unwrap()))
110 }
111
112 /// Returns a wrapper [ContractCallResult] object containing the current `CallResult` and the given contract address.
113 pub fn contract_last_call(self, contract_address: Address) -> ContractCallResult {
114 ContractCallResult {
115 call_result: self,
116 contract_address
117 }
118 }
119}
120
121/// Represents the result of a contract call.
122///
123/// It may represent not the original call but the an external call.
124/// However the result and gas used come from the original call.
125#[derive(Debug, Clone)]
126pub struct ContractCallResult {
127 call_result: CallResult,
128 contract_address: Address
129}
130
131impl ContractCallResult {
132 /// Returns the address of the contract.
133 ///
134 /// # Returns
135 ///
136 /// The address of the contract.
137 pub fn contract_address(&self) -> Address {
138 self.contract_address
139 }
140
141 /// Returns the address of the callee contract.
142 ///
143 /// # Returns
144 ///
145 /// The address of the callee contract.
146 pub fn callee_contract_address(&self) -> Address {
147 self.call_result.contract_address()
148 }
149
150 /// Returns the result of the original contract call as a [Bytes] object.
151 ///
152 /// # Panics
153 ///
154 /// Panics if the result is an error.
155 pub fn callee_contract_bytes(&self) -> Bytes {
156 self.call_result.bytes()
157 }
158
159 /// Returns the result of the original contract call as a [OdraResult] object.
160 pub fn callee_contract_result(&self) -> OdraResult<Bytes> {
161 self.call_result.result()
162 }
163
164 /// Returns the error of the original contract call as an `OdraError` object.
165 pub fn callee_contract_error(&self) -> OdraError {
166 self.call_result.error()
167 }
168
169 /// Returns the address of the original contract caller.
170 pub fn callee_contract_caller(&self) -> Address {
171 self.call_result.caller()
172 }
173
174 /// Returns the amount of gas used in the original contract call.
175 pub fn callee_contract_gas_used(&self) -> u64 {
176 self.call_result.gas_used()
177 }
178
179 /// Returns the names of the events emitted by the contract call.
180 ///
181 /// # Returns
182 ///
183 /// A vector containing the names of the events emitted by the contract call.
184 pub fn event_names(&self) -> Vec<String> {
185 self.call_result.event_names(&self.contract_address)
186 }
187
188 /// Returns the events emitted by the contract call.
189 ///
190 /// # Returns
191 ///
192 /// A vector containing the events emitted by the contract call.
193 pub fn events(&self) -> Vec<Bytes> {
194 self.call_result.contract_events(&self.contract_address)
195 }
196
197 /// Checks if an event with the specified name was emitted by the contract call.
198 ///
199 /// # Arguments
200 ///
201 /// * `event_name` - The name of the event to check.
202 ///
203 /// # Returns
204 ///
205 /// `true` if the event was emitted, otherwise `false`.
206 pub fn emitted(&self, event_name: &str) -> bool {
207 self.call_result.emitted(&self.contract_address, event_name)
208 }
209
210 /// Checks if the specified event instance was emitted by the contract call.
211 ///
212 /// # Arguments
213 ///
214 /// * `event` - The event instance to check.
215 ///
216 /// # Returns
217 ///
218 /// `true` if the event was emitted, otherwise `false`.
219 pub fn emitted_event<T: ToBytes + EventInstance>(&self, event: &T) -> bool {
220 self.call_result
221 .emitted_event(&self.contract_address, event)
222 }
223}