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 pallet_revive::{
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<EventLog> {
98 pub addr: Address,
100 pub events: EventLog,
102 pub trace: Option<CallTrace>,
104 pub code_hash: H256,
106}
107
108impl<EventLog> BareInstantiationResult<EventLog> {
109 pub fn call(&self) -> Address {
112 self.addr
113 }
114}
115
116impl<EventLog> Debug for BareInstantiationResult<EventLog>
119where
120 EventLog: Debug,
121{
122 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
123 f.debug_struct("BareInstantiationResult")
125 .field("addr", &self.addr)
126 .field("events", &self.events)
127 .field("trace", &self.trace)
128 .finish()
129 }
130}
131
132pub struct InstantiationResult<E: Environment, EventLog, Abi> {
134 pub addr: Address,
136 pub dry_run: InstantiateDryRunResult<E, Abi>,
139 pub events: EventLog,
141 pub trace: Option<CallTrace>,
143 pub code_hash: H256,
145}
146
147impl<E: Environment, EventLog, Abi> InstantiationResult<E, EventLog, Abi> {
148 pub fn call_builder<Contract>(&self) -> <Contract as ContractCallBuilder>::Type<Abi>
154 where
155 Contract: ContractCallBuilder,
156 <Contract as ContractCallBuilder>::Type<Abi>: FromAddr,
157 {
158 <<Contract as ContractCallBuilder>::Type<Abi> as FromAddr>::from_addr(self.addr)
159 }
160
161 pub fn call_builder_abi<Contract, CallAbi>(
168 &self,
169 ) -> <Contract as ContractCallBuilder>::Type<CallAbi>
170 where
171 Contract: ContractCallBuilder,
172 <Contract as ContractCallBuilder>::Type<CallAbi>: FromAddr,
173 {
174 <<Contract as ContractCallBuilder>::Type<CallAbi> as FromAddr>::from_addr(
175 self.addr,
176 )
177 }
178}
179
180impl<E: Environment, EventLog, Abi> Debug for InstantiationResult<E, EventLog, Abi>
183where
184 E::AccountId: Debug,
185 E::Balance: Debug,
186 E::EventRecord: Debug,
187 EventLog: Debug,
188{
189 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
190 f.debug_struct("InstantiationResult")
192 .field("addr", &self.addr)
193 .field("dry_run", &self.dry_run)
194 .field("events", &self.events)
195 .finish()
196 }
197}
198
199pub struct UploadResult<E: Environment, EventLog> {
201 pub code_hash: H256,
203 pub dry_run: CodeUploadResult<E::Balance>,
205 pub events: EventLog,
207}
208
209impl<E: Environment, EventLog> Debug for UploadResult<E, EventLog>
212where
213 E::Balance: Debug,
214 H256: Debug,
215 EventLog: Debug,
216{
217 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
218 f.debug_struct("UploadResult")
219 .field("code_hash", &self.code_hash)
220 .field("dry_run", &self.dry_run)
221 .field("events", &self.events)
222 .finish()
223 }
224}
225
226pub struct CallResult<E: Environment, V, EventLog, Abi> {
228 pub dry_run: CallDryRunResult<E, V, Abi>,
230 pub events: EventLog,
232 pub trace: Option<CallTrace>,
234}
235
236impl<E: Environment, V: DecodeMessageResult<Abi>, EventLog, Abi>
237 CallResult<E, V, EventLog, Abi>
238{
239 pub fn message_result(&self) -> MessageResult<V> {
246 self.dry_run.message_result()
247 }
248
249 pub fn return_value(self) -> V {
254 self.dry_run.return_value()
255 }
256}
257
258impl<E: Environment, V, EventLog, Abi> CallResult<E, V, EventLog, Abi> {
259 pub fn return_data(&self) -> &[u8] {
263 &self.dry_run.exec_return_value().data
264 }
265}
266
267impl<E: Environment, V, EventLog, Abi> Debug for CallResult<E, V, EventLog, Abi>
269where
270 E: Debug,
271 E::Balance: Debug,
272 E::EventRecord: Debug,
273 V: Debug,
274 EventLog: Debug,
275{
276 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
277 f.debug_struct("CallResult")
278 .field("dry_run", &self.dry_run)
279 .field("events", &self.events)
280 .field("trace", &self.trace)
281 .finish()
282 }
283}
284
285pub struct CallDryRunResult<E: Environment, V, Abi> {
287 pub exec_result: ContractExecResultFor<E>,
289 pub trace: Option<CallTrace>,
291 pub _marker: PhantomData<(V, Abi)>,
293}
294
295impl<E: Environment, V, Abi> Debug for CallDryRunResult<E, V, Abi>
298where
299 E::Balance: Debug,
300 E::EventRecord: Debug,
301{
302 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
303 f.debug_struct("CallDryRunResult")
304 .field("exec_result", &self.exec_result)
305 .finish()
306 }
307}
308
309impl<E: Environment, V, Abi> CallDryRunResult<E, V, Abi> {
310 pub fn is_err(&self) -> bool {
312 self.exec_result.result.is_err() || self.did_revert()
313 }
314
315 pub fn exec_return_value(&self) -> &ExecReturnValue {
319 self.exec_result
320 .result
321 .as_ref()
322 .unwrap_or_else(|call_err| panic!("Call dry-run failed: {call_err:?}"))
323 }
324
325 pub fn did_revert(&self) -> bool {
327 let res = self.exec_result.result.clone().expect("no result found");
328 res.did_revert()
329 }
330
331 pub fn return_data(&self) -> &[u8] {
335 &self.exec_return_value().data
336 }
337}
338
339impl<E: Environment, V: DecodeMessageResult<Abi>, Abi> CallDryRunResult<E, V, Abi> {
340 pub fn message_result(&self) -> MessageResult<V> {
346 let data = &self.exec_return_value().data;
347 DecodeMessageResult::decode_output(data.as_ref(), self.did_revert()).unwrap_or_else(|env_err| {
348 panic!(
349 "Decoding dry run result to ink! message return type failed: {env_err:?} {:?}\n\n\
350 Attempt to stringify returned data: {:?}",
351 self.exec_return_value(),
352 String::from_utf8_lossy(&self.exec_return_value().data[..])
353 )
354 })
355 }
356
357 pub fn return_value(&self) -> V {
362 self.message_result()
363 .unwrap_or_else(|lang_err| {
364 panic!(
365 "Encountered a `LangError` while decoding dry run result to ink! message: {lang_err:?}"
366 )
367 })
368 }
369}
370
371pub struct InstantiateDryRunResult<E: Environment, Abi> {
373 pub contract_result: ContractInstantiateResultFor<E>,
375 pub _marker: PhantomData<Abi>,
377}
378
379impl<E: Environment, Abi> From<ContractInstantiateResultFor<E>>
380 for InstantiateDryRunResult<E, Abi>
381{
382 fn from(contract_result: ContractInstantiateResultFor<E>) -> Self {
383 Self {
384 contract_result,
385 _marker: PhantomData,
386 }
387 }
388}
389
390impl<E: Environment, Abi> InstantiateDryRunResult<E, Abi> {
391 pub fn is_err(&self) -> bool {
393 self.contract_result.result.is_err() || self.did_revert()
394 }
395
396 pub fn instantiate_return_value(&self) -> &InstantiateReturnValue {
400 self.contract_result
401 .result
402 .as_ref()
403 .unwrap_or_else(|call_err| panic!("Instantiate dry-run failed: {call_err:?}"))
404 }
405
406 pub fn constructor_result<V: DecodeMessageResult<Abi>>(
412 &self,
413 ) -> ConstructorResult<V> {
414 let data = &self.instantiate_return_value().result.data;
415 DecodeMessageResult::decode_output(data.as_ref(), self.did_revert()).unwrap_or_else(|env_err| {
416 panic!("Decoding dry run result to constructor return type failed: {env_err:?}")
417 })
418 }
419
420 pub fn return_data(&self) -> &[u8] {
424 &self.instantiate_return_value().result.data
425 }
426
427 pub fn did_revert(&self) -> bool {
429 let res = self.instantiate_return_value().clone().result;
430 res.did_revert()
431 }
432}
433
434impl<E, Abi> Debug for InstantiateDryRunResult<E, Abi>
435where
436 E: Environment,
437 E::AccountId: Debug,
438 E::Balance: Debug,
439 E::EventRecord: Debug,
440{
441 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
442 f.debug_struct("InstantiateDryRunResult")
443 .field("contract_result", &self.contract_result)
444 .finish()
445 }
446}