1use std::{
16 fmt,
17 fmt::Debug,
18 marker::PhantomData,
19};
20
21use frame_support::pallet_prelude::{
22 Decode,
23 Encode,
24};
25use ink::codegen::ContractCallBuilder;
26use ink_env::{
27 Environment,
28 call::{
29 FromAddr,
30 utils::DecodeMessageResult,
31 },
32};
33use ink_primitives::{
34 Address,
35 ConstructorResult,
36 H256,
37 MessageResult,
38};
39use ink_revive_types::{
40 CodeUploadResult,
41 ExecReturnValue,
42 InstantiateReturnValue,
43 StorageDeposit,
44 evm::CallTrace,
45};
46use sp_runtime::{
47 DispatchError,
48 Weight,
49};
50
51pub type ContractInstantiateResultFor<E> =
53 ContractResult<InstantiateReturnValue, <E as Environment>::Balance>;
54
55#[derive(Debug, Clone, Eq, PartialEq, Encode, Decode)]
67pub struct ContractResult<R, Balance> {
68 pub gas_consumed: Weight,
70 pub gas_required: Weight,
81 pub storage_deposit: StorageDeposit<Balance>,
88 pub result: Result<R, DispatchError>,
90}
91
92pub type ContractExecResultFor<E> =
94 ContractResult<ExecReturnValue, <E as Environment>::Balance>;
95
96pub struct BareInstantiationResult<E: Environment, EventLog> {
98 pub addr: Address,
100 pub account_id: E::AccountId,
102 pub events: EventLog,
104 pub trace: Option<CallTrace>,
106 pub code_hash: H256,
108}
109
110impl<E: Environment, EventLog> Debug for BareInstantiationResult<E, EventLog>
113where
114 EventLog: Debug,
115{
116 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
117 f.debug_struct("BareInstantiationResult")
118 .field("addr", &self.addr)
119 .field("account_id", &self.account_id.encode())
120 .field("events", &self.events)
121 .field("trace", &self.trace)
122 .field("code_hash", &self.code_hash)
123 .finish()
124 }
125}
126
127pub struct InstantiationResult<E: Environment, EventLog, Abi> {
129 pub addr: Address,
131 pub account_id: E::AccountId,
133 pub dry_run: InstantiateDryRunResult<E, Abi>,
136 pub events: EventLog,
138 pub trace: Option<CallTrace>,
140 pub code_hash: H256,
142}
143
144impl<E: Environment, EventLog, Abi> InstantiationResult<E, EventLog, Abi> {
145 pub fn call_builder<Contract>(&self) -> <Contract as ContractCallBuilder>::Type<Abi>
151 where
152 Contract: ContractCallBuilder,
153 <Contract as ContractCallBuilder>::Type<Abi>: FromAddr,
154 {
155 <<Contract as ContractCallBuilder>::Type<Abi> as FromAddr>::from_addr(self.addr)
156 }
157
158 pub fn call_builder_abi<Contract, CallAbi>(
165 &self,
166 ) -> <Contract as ContractCallBuilder>::Type<CallAbi>
167 where
168 Contract: ContractCallBuilder,
169 <Contract as ContractCallBuilder>::Type<CallAbi>: FromAddr,
170 {
171 <<Contract as ContractCallBuilder>::Type<CallAbi> as FromAddr>::from_addr(
172 self.addr,
173 )
174 }
175}
176
177impl<E: Environment, EventLog, Abi> Debug for InstantiationResult<E, EventLog, Abi>
180where
181 E::AccountId: Debug,
182 E::Balance: Debug,
183 E::EventRecord: Debug,
184 EventLog: Debug,
185{
186 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
187 f.debug_struct("InstantiationResult")
189 .field("addr", &self.addr)
190 .field("dry_run", &self.dry_run)
191 .field("events", &self.events)
192 .finish()
193 }
194}
195
196pub struct UploadResult<E: Environment, EventLog> {
198 pub code_hash: H256,
200 pub dry_run: CodeUploadResult<E::Balance>,
202 pub events: EventLog,
204}
205
206impl<E: Environment, EventLog> Debug for UploadResult<E, EventLog>
209where
210 E::Balance: Debug,
211 H256: Debug,
212 EventLog: Debug,
213{
214 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
215 f.debug_struct("UploadResult")
216 .field("code_hash", &self.code_hash)
217 .field("dry_run", &self.dry_run)
218 .field("events", &self.events)
219 .finish()
220 }
221}
222
223pub struct CallResult<E: Environment, V, EventLog, Abi> {
225 pub dry_run: CallDryRunResult<E, V, Abi>,
227 pub events: EventLog,
229 pub trace: Option<CallTrace>,
231}
232
233impl<E: Environment, V: DecodeMessageResult<Abi>, EventLog, Abi>
234 CallResult<E, V, EventLog, Abi>
235{
236 pub fn message_result(&self) -> MessageResult<V> {
243 self.dry_run.message_result()
244 }
245
246 pub fn return_value(self) -> V {
251 self.dry_run.return_value()
252 }
253}
254
255impl<E: Environment, V, EventLog, Abi> CallResult<E, V, EventLog, Abi> {
256 pub fn return_data(&self) -> &[u8] {
260 &self.dry_run.exec_return_value().data
261 }
262
263 pub fn extract_error(&self) -> Option<String> {
266 if !self.dry_run.did_revert() {
267 return None;
268 }
269
270 if let Some(trace) = &self.trace {
272 for call in &trace.calls {
274 if let Some(error) = &call.error {
275 return Some(error.clone());
276 }
277 }
278
279 if let Some(error) = &trace.error {
281 return Some(error.clone());
282 }
283 }
284 Some(format!("{:?}", self.return_data()))
286 }
287}
288
289impl<E: Environment, V, EventLog, Abi> Debug for CallResult<E, V, EventLog, Abi>
291where
292 E: Debug,
293 E::Balance: Debug,
294 E::EventRecord: Debug,
295 V: Debug,
296 EventLog: Debug,
297{
298 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
299 f.debug_struct("CallResult")
300 .field("dry_run", &self.dry_run)
301 .field("events", &self.events)
302 .field("trace", &self.trace)
303 .finish()
304 }
305}
306
307pub struct CallDryRunResult<E: Environment, V, Abi> {
309 pub exec_result: ContractExecResultFor<E>,
311 pub trace: Option<CallTrace>,
313 pub _marker: PhantomData<(V, Abi)>,
315}
316
317impl<E: Environment, V, Abi> Debug for CallDryRunResult<E, V, Abi>
320where
321 E::Balance: Debug,
322 E::EventRecord: Debug,
323{
324 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
325 f.debug_struct("CallDryRunResult")
326 .field("exec_result", &self.exec_result)
327 .field("trace", &self.trace)
328 .finish()
329 }
330}
331
332impl<E: Environment, V, Abi> CallDryRunResult<E, V, Abi> {
333 pub fn is_err(&self) -> bool {
335 self.exec_result.result.is_err() || self.did_revert()
336 }
337
338 pub fn exec_return_value(&self) -> &ExecReturnValue {
342 self.exec_result
343 .result
344 .as_ref()
345 .unwrap_or_else(|call_err| panic!("Call dry-run failed: {call_err:?}"))
346 }
347
348 pub fn did_revert(&self) -> bool {
350 let res = self.exec_result.result.clone().expect("no result found");
351 res.did_revert()
352 }
353
354 pub fn return_data(&self) -> &[u8] {
358 &self.exec_return_value().data
359 }
360}
361
362impl<E: Environment, V: DecodeMessageResult<Abi>, Abi> CallDryRunResult<E, V, Abi> {
363 pub fn message_result(&self) -> MessageResult<V> {
369 let data = &self.exec_return_value().data;
370 DecodeMessageResult::decode_output(data.as_ref(), self.did_revert()).unwrap_or_else(|env_err| {
371 panic!(
372 "Decoding dry run result to ink! message return type failed: {env_err:?} {:?}\n\n\
373 Attempt to stringify returned data: {:?}",
374 self.exec_return_value(),
375 String::from_utf8_lossy(&self.exec_return_value().data[..])
376 )
377 })
378 }
379
380 pub fn return_value(&self) -> V {
385 self.message_result()
386 .unwrap_or_else(|lang_err| {
387 panic!(
388 "Encountered a `LangError` while decoding dry run result to ink! message: {lang_err:?}"
389 )
390 })
391 }
392}
393
394#[derive(Clone)]
396pub struct InstantiateDryRunResult<E: Environment, Abi> {
397 pub contract_result: ContractInstantiateResultFor<E>,
399 pub _marker: PhantomData<Abi>,
401}
402
403impl<E: Environment, Abi> From<ContractInstantiateResultFor<E>>
404 for InstantiateDryRunResult<E, Abi>
405{
406 fn from(contract_result: ContractInstantiateResultFor<E>) -> Self {
407 Self {
408 contract_result,
409 _marker: PhantomData,
410 }
411 }
412}
413
414impl<E: Environment, Abi> InstantiateDryRunResult<E, Abi> {
415 pub fn is_err(&self) -> bool {
417 self.contract_result.result.is_err() || self.did_revert()
418 }
419
420 pub fn instantiate_return_value(&self) -> &InstantiateReturnValue {
424 self.contract_result
425 .result
426 .as_ref()
427 .unwrap_or_else(|call_err| panic!("Instantiate dry-run failed: {call_err:?}"))
428 }
429
430 pub fn constructor_result<V: DecodeMessageResult<Abi>>(
436 &self,
437 ) -> ConstructorResult<V> {
438 let data = &self.instantiate_return_value().result.data;
439 DecodeMessageResult::decode_output(data.as_ref(), self.did_revert()).unwrap_or_else(|env_err| {
440 panic!("Decoding dry run result to constructor return type failed: {env_err:?}")
441 })
442 }
443
444 pub fn return_data(&self) -> &[u8] {
448 &self.instantiate_return_value().result.data
449 }
450
451 pub fn did_revert(&self) -> bool {
453 let res = self.instantiate_return_value().clone().result;
454 res.did_revert()
455 }
456}
457
458impl<E, Abi> Debug for InstantiateDryRunResult<E, Abi>
459where
460 E: Environment,
461 E::AccountId: Debug,
462 E::Balance: Debug,
463 E::EventRecord: Debug,
464{
465 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
466 f.debug_struct("InstantiateDryRunResult")
467 .field("contract_result", &self.contract_result)
468 .finish()
469 }
470}