1#[cfg(feature = "std")]
16use std::fmt::Debug;
17use std::path::PathBuf;
18
19use super::{
20 H256,
21 InstantiateDryRunResult,
22 Keypair,
23 ReviveApi,
24 builders::{
25 CreateBuilderPartial,
26 constructor_exec_input,
27 },
28 deposit_limit_to_balance,
29 events::{
30 CodeStoredEvent,
31 EventWithTopics,
32 },
33 log_error,
34 log_info,
35 sr25519,
36};
37use crate::{
38 ContractsBackend,
39 E2EBackend,
40 backend::{
41 BuilderClient,
42 ChainBackend,
43 },
44 client_utils::{
45 ContractsRegistry,
46 salt,
47 },
48 contract_results::{
49 BareInstantiationResult,
50 CallDryRunResult,
51 CallResult,
52 ContractResult,
53 UploadResult,
54 },
55 error::DryRunError,
56 events,
57 events::ContractInstantiatedEvent,
58};
59use ink::H160;
60use ink_env::{
61 Environment,
62 call::{
63 Call,
64 ExecutionInput,
65 utils::{
66 DecodeMessageResult,
67 ReturnType,
68 Set,
69 },
70 },
71};
72use ink_primitives::{
73 DepositLimit,
74 abi::AbiEncodeWith,
75};
76use ink_revive_types::evm::CallTrace;
77use jsonrpsee::core::async_trait;
78use scale::{
79 Decode,
80 Encode,
81};
82use sp_weights::Weight;
83use subxt::{
84 blocks::ExtrinsicEvents,
85 config::{
86 DefaultExtrinsicParams,
87 ExtrinsicParams,
88 HashFor,
89 },
90 error::DispatchError,
91 events::EventDetails,
92 ext::scale_value::{
93 Composite,
94 Value,
95 ValueDef,
96 },
97 storage::dynamic,
98 tx::Signer,
99};
100
101pub type Error = crate::error::Error<DispatchError>;
102
103pub type CallBuilderFinal<E, Args, RetType, Abi> = ink_env::call::CallBuilder<
105 E,
106 Set<Call>,
107 Set<ExecutionInput<Args, Abi>>,
108 Set<ReturnType<RetType>>,
109>;
110
111pub struct Client<C, E>
116where
117 C: subxt::Config,
118 E: Environment,
119{
120 api: ReviveApi<C, E>,
121 contracts: ContractsRegistry,
122 url: String,
123}
124
125impl<C, E> Client<C, E>
126where
127 C: subxt::Config,
128 C::AccountId:
129 From<sr25519::PublicKey> + scale::Codec + serde::de::DeserializeOwned + Debug,
130 C::Address: From<sr25519::PublicKey>,
131 C::Signature: From<sr25519::Signature>,
132 <C::ExtrinsicParams as ExtrinsicParams<C>>::Params:
133 From<<DefaultExtrinsicParams<C> as ExtrinsicParams<C>>::Params>,
134 E: Environment,
135 E::AccountId: Debug,
136 E::EventRecord: Debug,
137 E::Balance: Debug + scale::HasCompact + serde::Serialize,
138 H256: Debug + scale::Encode,
139{
140 pub async fn new<P: Into<PathBuf>>(
142 client: subxt::backend::rpc::RpcClient,
143 contracts: impl IntoIterator<Item = P>,
144 url: String,
145 ) -> Result<Self, subxt::Error> {
146 Ok(Self {
147 api: ReviveApi::new(client).await?,
148 contracts: ContractsRegistry::new(contracts),
149 url,
150 })
151 }
152
153 async fn exec_upload(
155 &mut self,
156 signer: &Keypair,
157 code: Vec<u8>,
158 storage_deposit_limit: Option<E::Balance>,
159 ) -> Result<UploadResult<E, ExtrinsicEvents<C>>, Error> {
160 let dry_run = self
161 .api
162 .upload_dry_run(signer, code.clone(), storage_deposit_limit)
163 .await;
164 log_info(&format!("upload dry run: {dry_run:?}"));
165 if let Err(err) = dry_run {
166 let dispatch_err = self.runtime_dispatch_error_to_subxt_dispatch_error(&err);
167 return Err(Error::UploadDryRun(dispatch_err))
168 }
169
170 let storage_deposit_limit = match storage_deposit_limit {
171 None => {
172 dry_run
173 .as_ref()
174 .expect("would have returned already")
175 .deposit
176 }
177 Some(limit) => limit,
178 };
179
180 let (tx_events, trace) =
181 self.api.upload(signer, code, storage_deposit_limit).await;
182
183 let mut hash = None;
184 for evt in tx_events.iter() {
185 let evt = evt.unwrap_or_else(|err| {
186 panic!("unable to unwrap event: {err:?}");
187 });
188
189 if let Some(uploaded) =
190 evt.as_event::<CodeStoredEvent>().unwrap_or_else(|err| {
191 panic!("event conversion to `Uploaded` failed: {err:?}");
192 })
193 {
194 log_info(&format!(
195 "contract was uploaded with hash {:?}",
196 uploaded.code_hash
197 ));
198 hash = Some(uploaded.code_hash);
199 break
200 } else if is_extrinsic_failed_event(&evt) {
201 let metadata = self.api.client.metadata();
202 let dispatch_error =
203 DispatchError::decode_from(evt.field_bytes(), metadata)
204 .map_err(|e| Error::Decoding(e.to_string()))?;
205
206 log_error(&format!(
207 "extrinsic for upload failed: {dispatch_error} {trace:?}"
208 ));
209 return Err(Error::UploadExtrinsic(dispatch_error, trace))
210 }
211 }
212
213 let code_hash = match hash {
219 Some(hash) => hash,
220 None => {
221 dry_run
222 .as_ref()
223 .unwrap_or_else(|err| panic!("must have worked: {err:?}"))
224 .code_hash
225 }
226 };
227
228 Ok(UploadResult {
229 dry_run,
230 code_hash,
231 events: tx_events,
232 })
233 }
234
235 #[allow(clippy::type_complexity)]
239 fn contract_result_to_result<V>(
240 &self,
241 contract_result: ContractResult<V, E::Balance>,
242 ) -> Result<ContractResult<V, E::Balance>, DryRunError<DispatchError>> {
243 if let Err(error) = contract_result.result {
244 let subxt_dispatch_err =
245 self.runtime_dispatch_error_to_subxt_dispatch_error(&error);
246 Err(DryRunError::<DispatchError> {
247 error: subxt_dispatch_err,
248 })
249 } else {
250 Ok(contract_result)
251 }
252 }
253
254 fn runtime_dispatch_error_to_subxt_dispatch_error(
257 &self,
258 dispatch_error: &sp_runtime::DispatchError,
259 ) -> DispatchError {
260 let dispatch_err_encoded = Encode::encode(&dispatch_error);
261 DispatchError::decode_from(dispatch_err_encoded, self.api.client.metadata())
262 .expect("failed to decode valid dispatch error")
263 }
264
265 pub fn url(&self) -> &str {
267 &self.url
268 }
269
270 fn derive_keypair_address(&self, signer: &Keypair) -> H160 {
273 let account_id = <Keypair as subxt::tx::Signer<C>>::account_id(signer);
274 let account_bytes = account_id.encode();
275 crate::AccountIdMapper::to_address(account_bytes.as_ref())
276 }
277
278 async fn fetch_original_account(
283 &self,
284 addr: &H160,
285 ) -> Result<Option<E::AccountId>, Error> {
286 let original_account_entry = subxt::dynamic::storage(
287 "Revive",
288 "OriginalAccount",
289 vec![Value::from_bytes(addr)],
290 );
291 let best_block = self.api.best_block().await;
292 let raw_value = self
293 .api
294 .client
295 .storage()
296 .at(best_block)
297 .fetch(&original_account_entry)
298 .await
299 .map_err(|err| {
300 Error::Other(format!("Unable to fetch original account: {err:?}"))
301 })?;
302 Ok(match raw_value {
303 Some(value) => {
304 let raw_account_id = value.as_type::<[u8; 32]>().map_err(|err| {
305 Error::Decoding(format!("unable to deserialize AccountId: {err}"))
306 })?;
307 let account: E::AccountId = Decode::decode(&mut &raw_account_id[..])
308 .map_err(|err| {
309 Error::Decoding(format!("unable to decode AccountId: {err}"))
310 })?;
311 Some(account)
312 }
313 None => None,
314 })
315 }
316
317 pub async fn to_account_id(&self, addr: &H160) -> Result<E::AccountId, Error> {
321 match self.fetch_original_account(addr).await? {
322 Some(v) => Ok(v),
323 None => {
324 let fallback = to_fallback_account_id(addr);
325 let account_id = E::AccountId::decode(&mut &fallback[..]).unwrap();
326 Ok(account_id)
327 }
328 }
329 }
330}
331
332fn to_fallback_account_id(address: &H160) -> [u8; 32] {
334 let mut account_id = [0xEE; 32];
335 account_id[..20].copy_from_slice(address.as_bytes());
336 account_id
337}
338
339#[async_trait]
340impl<C, E> ChainBackend for Client<C, E>
341where
342 C: subxt::Config + Send + Sync,
343 C::AccountId: Clone
344 + Debug
345 + Send
346 + Sync
347 + core::fmt::Display
348 + scale::Codec
349 + From<sr25519::PublicKey>
350 + serde::de::DeserializeOwned,
351 C::Address: From<sr25519::PublicKey>,
352 C::Signature: From<sr25519::Signature>,
353 C::Address: Send + Sync,
354 <C::ExtrinsicParams as ExtrinsicParams<C>>::Params:
355 From<<DefaultExtrinsicParams<C> as ExtrinsicParams<C>>::Params>,
356 E: Environment,
357 E::AccountId: Debug + Send + Sync,
358 E::Balance: Clone
359 + Debug
360 + Send
361 + Sync
362 + TryFrom<u128>
363 + scale::HasCompact
364 + serde::Serialize,
365 E::EventRecord: Debug,
366{
367 type AccountId = E::AccountId;
368 type Balance = E::Balance;
369 type Error = Error;
370 type EventLog = ExtrinsicEvents<C>;
371
372 async fn create_and_fund_account(
373 &mut self,
374 origin: &Keypair,
375 amount: Self::Balance,
376 ) -> Keypair {
377 let (_, phrase, _) =
378 <sp_core::sr25519::Pair as sp_core::Pair>::generate_with_phrase(None);
379 let phrase =
380 subxt_signer::bip39::Mnemonic::parse(phrase).expect("valid phrase expected");
381 let keypair = Keypair::from_phrase(&phrase, None).expect("valid phrase expected");
382 let account_id = <Keypair as Signer<C>>::account_id(&keypair);
383 let origin_account_id = origin.public_key().to_account_id();
384
385 self.api
386 .transfer_allow_death(origin, account_id.clone(), amount)
387 .await
388 .unwrap_or_else(|err| {
389 panic!(
390 "transfer from {origin_account_id} to {account_id} failed with {err:?}"
391 )
392 });
393
394 log_info(&format!(
395 "transfer from {origin_account_id} to {account_id} succeeded",
396 ));
397
398 keypair
399 }
400
401 async fn free_balance(
402 &mut self,
403 account: Self::AccountId,
404 ) -> Result<Self::Balance, Self::Error> {
405 let account_addr = subxt::dynamic::storage(
406 "System",
407 "Account",
408 vec![
409 Value::from_bytes(&account),
412 ],
413 );
414
415 let best_block = self.api.best_block().await;
416
417 let account = self
418 .api
419 .client
420 .storage()
421 .at(best_block)
422 .fetch_or_default(&account_addr)
423 .await
424 .unwrap_or_else(|err| {
425 panic!("unable to fetch balance: {err:?}");
426 })
427 .to_value()
428 .unwrap_or_else(|err| {
429 panic!("unable to decode account info: {err:?}");
430 });
431
432 let account_data = get_composite_field_value(&account, "data")?;
433 let balance = get_composite_field_value(account_data, "free")?;
434 let balance = balance.as_u128().ok_or_else(|| {
435 Error::Balance(format!("{balance:?} should convert to u128"))
436 })?;
437 let balance = E::Balance::try_from(balance).map_err(|_| {
438 Error::Balance(format!("{balance:?} failed to convert from u128"))
439 })?;
440
441 log_info(&format!("balance of contract {account:?} is {balance:?}"));
442 Ok(balance)
443 }
444
445 async fn runtime_call<'a>(
446 &mut self,
447 origin: &Keypair,
448 pallet_name: &'a str,
449 call_name: &'a str,
450 call_data: Vec<Value>,
451 ) -> Result<Self::EventLog, Self::Error> {
452 let (tx_events, trace) = self
453 .api
454 .runtime_call(origin, pallet_name, call_name, call_data)
455 .await;
456
457 for evt in tx_events.iter() {
458 let evt = evt.unwrap_or_else(|err| {
459 panic!("unable to unwrap event: {err:?}");
460 });
461
462 if is_extrinsic_failed_event(&evt) {
463 let metadata = self.api.client.metadata();
464 let dispatch_error =
465 subxt::error::DispatchError::decode_from(evt.field_bytes(), metadata)
466 .map_err(|e| Error::Decoding(e.to_string()))?;
467 log_error(&format!(
468 "extrinsic for `runtime_call` failed: {dispatch_error} {trace:?}"
469 ));
470 return Err(Error::CallExtrinsic(dispatch_error, trace))
471 }
472 }
473
474 Ok(tx_events)
475 }
476
477 async fn transfer_allow_death(
478 &mut self,
479 origin: &Keypair,
480 dest: Self::AccountId,
481 value: Self::Balance,
482 ) -> Result<(), Self::Error> {
483 let dest = dest.encode();
484 let dest: C::AccountId = Decode::decode(&mut &dest[..]).unwrap();
485 self.api
486 .transfer_allow_death(origin, dest, value)
487 .await
488 .map_err(|err| Error::Balance(format!("{err:?}")))
489 }
490}
491
492#[async_trait]
493impl<C, E> BuilderClient<E> for Client<C, E>
494where
495 C: subxt::Config + Send + Sync,
496 C::AccountId: Clone
497 + Debug
498 + Send
499 + Sync
500 + core::fmt::Display
501 + scale::Codec
502 + From<sr25519::PublicKey>
503 + From<[u8; 32]>
504 + serde::de::DeserializeOwned,
505 C::Address: From<sr25519::PublicKey>,
506 C::Signature: From<sr25519::Signature>,
507 C::Address: Send + Sync,
508 <C::ExtrinsicParams as ExtrinsicParams<C>>::Params:
509 From<<DefaultExtrinsicParams<C> as ExtrinsicParams<C>>::Params>,
510 E: Environment,
511 E::AccountId: Debug + Send + Sync,
512 E::EventRecord: Debug,
513 E::Balance:
514 Clone + Debug + Send + Sync + From<u128> + scale::HasCompact + serde::Serialize,
515 H256: Debug + Send + Sync + scale::Encode,
516{
517 fn load_code(&self, contract_name: &str) -> Vec<u8> {
518 self.contracts.load_code(contract_name)
519 }
520
521 async fn bare_instantiate<
522 Contract: Clone,
523 Args: Send + Sync + AbiEncodeWith<Abi> + Clone,
524 R,
525 Abi: Send + Sync + Clone,
526 >(
527 &mut self,
528 code: Vec<u8>,
529 caller: &Keypair,
530 constructor: &mut CreateBuilderPartial<E, Contract, Args, R, Abi>,
531 value: E::Balance,
532 gas_limit: Weight,
533 storage_deposit_limit: DepositLimit<E::Balance>,
534 ) -> Result<BareInstantiationResult<E, Self::EventLog>, Self::Error> {
535 let data = constructor_exec_input(constructor.clone());
536 let ret = self
537 .raw_instantiate(code, caller, data, value, gas_limit, storage_deposit_limit)
538 .await?;
539 Ok(ret)
540 }
541
542 async fn raw_instantiate(
543 &mut self,
544 code: Vec<u8>,
545 caller: &Keypair,
546 constructor: Vec<u8>,
547 value: E::Balance,
548 gas_limit: Weight,
549 storage_deposit_limit: DepositLimit<E::Balance>,
550 ) -> Result<BareInstantiationResult<E, Self::EventLog>, Self::Error> {
551 let storage_deposit_limit = deposit_limit_to_balance::<E>(storage_deposit_limit);
552 let (events, trace) = self
553 .api
554 .instantiate_with_code(
555 value,
556 gas_limit.into(),
557 storage_deposit_limit,
558 code.clone(),
559 constructor.clone(),
560 salt(),
561 caller,
562 )
563 .await;
564
565 let mut addr = None;
566 for evt in events.iter() {
567 let evt = evt.unwrap_or_else(|err| {
568 panic!("unable to unwrap event: {err:?}");
569 });
570 if let Some(instantiated) = evt
571 .as_event::<ContractInstantiatedEvent>()
572 .unwrap_or_else(|err| {
573 panic!("event conversion to `Instantiated` failed: {err:?}");
574 })
575 {
576 log_info(&format!(
577 "contract was instantiated at {:?}",
578 instantiated.contract
579 ));
580 addr = Some(instantiated.contract);
581
582 } else if is_extrinsic_failed_event(&evt) {
586 let metadata = self.api.client.metadata();
587 let dispatch_error =
588 subxt::error::DispatchError::decode_from(evt.field_bytes(), metadata)
589 .map_err(|e| Error::Decoding(e.to_string()))?;
590 log_error(&format!(
591 "extrinsic for instantiate failed: {dispatch_error} {trace:?}"
592 ));
593 return Err(Error::InstantiateExtrinsic(dispatch_error, trace))
594 }
595 }
596 let addr = addr.expect("cannot extract contract address from events");
597 let mut account_id = [0xEE; 32];
598 account_id[..20].copy_from_slice(addr.as_bytes());
599
600 Ok(BareInstantiationResult {
601 addr,
604 account_id: E::AccountId::decode(&mut &account_id[..]).unwrap(),
605 events,
606 trace,
607 code_hash: H256(crate::client_utils::code_hash(&code[..])),
608 })
609 }
610
611 async fn exec_instantiate(
612 &mut self,
613 signer: &Keypair,
614 contract_name: &str,
615 data: Vec<u8>,
616 value: E::Balance,
617 gas_limit: Weight,
618 storage_deposit_limit: E::Balance,
619 ) -> Result<BareInstantiationResult<E, Self::EventLog>, Self::Error> {
620 let code = self.contracts.load_code(contract_name);
621 self.raw_instantiate(
622 code,
623 signer,
624 data,
625 value,
626 gas_limit,
627 DepositLimit::Balance(storage_deposit_limit),
628 )
629 .await
630 }
631
632 async fn bare_instantiate_dry_run<
637 Contract: Clone,
638 Args: Send + Sync + AbiEncodeWith<Abi> + Clone,
639 R,
640 Abi: Send + Sync + Clone,
641 >(
642 &mut self,
643 contract_name: &str,
644 caller: &Keypair,
645 constructor: &mut CreateBuilderPartial<E, Contract, Args, R, Abi>,
646 value: E::Balance,
647 storage_deposit_limit: DepositLimit<E::Balance>,
648 ) -> Result<InstantiateDryRunResult<E, Abi>, Self::Error> {
649 let code = self.contracts.load_code(contract_name);
650 let data = constructor_exec_input(constructor.clone());
651 self.raw_instantiate_dry_run(code, caller, data, value, storage_deposit_limit)
652 .await
653 }
654
655 async fn raw_instantiate_dry_run<Abi: Sync + Clone>(
660 &mut self,
661 code: Vec<u8>,
662 caller: &Keypair,
663 data: Vec<u8>,
664 value: E::Balance,
665 storage_deposit_limit: DepositLimit<E::Balance>,
666 ) -> Result<InstantiateDryRunResult<E, Abi>, Self::Error> {
667 let _ = self.map_account(caller).await;
669
670 let result = self
671 .api
672 .instantiate_with_code_dry_run(
673 value,
674 storage_deposit_limit,
675 code,
676 data,
677 salt(),
678 caller,
679 )
680 .await;
681
682 log_info(&format!("instantiate dry run: {:?}", &result.result));
683 let result = self
684 .contract_result_to_result(result)
685 .map_err(Error::InstantiateDryRun)?;
686
687 Ok(result.into())
699 }
700
701 async fn bare_upload(
702 &mut self,
703 contract_name: &str,
704 caller: &Keypair,
705 storage_deposit_limit: Option<E::Balance>,
706 ) -> Result<UploadResult<E, Self::EventLog>, Self::Error> {
707 let code = self.contracts.load_code(contract_name);
708 let ret = self
709 .exec_upload(caller, code, storage_deposit_limit)
710 .await?;
711 log_info(&format!("contract stored with hash {:?}", ret.code_hash));
712 Ok(ret)
713 }
714
715 async fn bare_remove_code(
716 &mut self,
717 caller: &Keypair,
718 code_hash: H256,
719 ) -> Result<Self::EventLog, Self::Error> {
720 let (tx_events, trace) = self.api.remove_code(caller, code_hash).await;
721
722 for evt in tx_events.iter() {
723 let evt = evt.unwrap_or_else(|err| {
724 panic!("unable to unwrap event: {err:?}");
725 });
726
727 if is_extrinsic_failed_event(&evt) {
728 let metadata = self.api.client.metadata();
729 let dispatch_error =
730 DispatchError::decode_from(evt.field_bytes(), metadata)
731 .map_err(|e| Error::Decoding(e.to_string()))?;
732 log_error(&format!(
733 "extrinsic for remove code failed: {dispatch_error} {trace:?}"
734 ));
735 return Err(Error::RemoveCodeExtrinsic(dispatch_error, trace))
736 }
737 }
738
739 Ok(tx_events)
740 }
741
742 async fn bare_call<
743 Args: Sync + AbiEncodeWith<Abi> + Clone,
744 RetType: Send + DecodeMessageResult<Abi>,
745 Abi: Sync + Clone,
746 >(
747 &mut self,
748 caller: &Keypair,
749 message: &CallBuilderFinal<E, Args, RetType, Abi>,
750 value: E::Balance,
751 gas_limit: Weight,
752 storage_deposit_limit: DepositLimit<E::Balance>,
753 ) -> Result<(Self::EventLog, Option<CallTrace>), Self::Error>
754 where
755 CallBuilderFinal<E, Args, RetType, Abi>: Clone,
756 {
757 let addr = *message.clone().params().callee();
758 let exec_input = message.clone().params().exec_input().encode();
759 log_info(&format!("call: {exec_input:02X?}"));
760 self.raw_call(
761 addr,
762 exec_input,
763 value,
764 gas_limit,
765 storage_deposit_limit,
766 caller,
767 )
768 .await
769 }
770
771 async fn raw_call(
772 &mut self,
773 dest: H160,
774 input_data: Vec<u8>,
775 value: E::Balance,
776 gas_limit: Weight,
777 storage_deposit_limit: DepositLimit<E::Balance>,
778 signer: &Keypair,
779 ) -> Result<(Self::EventLog, Option<CallTrace>), Self::Error> {
780 let (tx_events, trace) = self
781 .api
782 .call(
783 dest,
784 value,
785 gas_limit.into(),
786 deposit_limit_to_balance::<E>(storage_deposit_limit),
787 input_data,
788 signer,
789 )
790 .await;
791
792 for evt in tx_events.iter() {
793 let evt = evt.unwrap_or_else(|err| {
794 panic!("unable to unwrap event: {err:?}");
795 });
796
797 if is_extrinsic_failed_event(&evt) {
798 let metadata = self.api.client.metadata();
799 let dispatch_error =
800 DispatchError::decode_from(evt.field_bytes(), metadata)
801 .map_err(|e| Error::Decoding(e.to_string()))?;
802 log_error(&format!(
803 "Attempt to stringify returned data: {:?}",
804 String::from_utf8_lossy(&trace.clone().unwrap().output[..])
805 ));
806 log_error(&format!(
807 "extrinsic for `raw_call` failed: {dispatch_error} {trace:?}"
808 ));
809 return Err(Error::CallExtrinsic(dispatch_error, trace))
810 }
811 }
812
813 Ok((tx_events, trace))
814 }
815
816 async fn bare_call_dry_run<
823 Args: Sync + AbiEncodeWith<Abi> + Clone,
824 RetType: Send + DecodeMessageResult<Abi>,
825 Abi: Sync + Clone,
826 >(
827 &mut self,
828 caller: &Keypair,
829 message: &CallBuilderFinal<E, Args, RetType, Abi>,
830 value: E::Balance,
831 storage_deposit_limit: DepositLimit<E::Balance>,
832 ) -> Result<CallDryRunResult<E, RetType, Abi>, Self::Error>
833 where
834 CallBuilderFinal<E, Args, RetType, Abi>: Clone,
835 {
836 let _ = self.map_account(caller).await;
838
839 let dest = *message.clone().params().callee();
840 let exec_input = message.clone().params().exec_input().encode();
841
842 let (exec_result, trace) = self
843 .api
844 .call_dry_run(dest, exec_input, value, storage_deposit_limit, caller)
845 .await;
846 log_info(&format!("call dry run result: {:?}", &exec_result.result));
847
848 if exec_result.result.is_ok() && exec_result.clone().result.unwrap().did_revert()
849 {
850 log_error(&format!(
851 "Attempt to stringify returned data: {:?}",
852 String::from_utf8_lossy(&exec_result.clone().result.unwrap().data[..])
853 ));
854 }
855
856 let exec_result = self
857 .contract_result_to_result(exec_result)
858 .map_err(Error::CallDryRun)?;
859
860 Ok(CallDryRunResult {
861 exec_result,
862 trace,
863 _marker: Default::default(),
864 })
865 }
866
867 async fn raw_call_dry_run<
868 RetType: Send + DecodeMessageResult<Abi>,
869 Abi: Sync + Clone,
870 >(
871 &mut self,
872 dest: H160,
873 input_data: Vec<u8>,
874 value: E::Balance,
875 storage_deposit_limit: DepositLimit<E::Balance>,
876 signer: &Keypair,
877 ) -> Result<CallDryRunResult<E, RetType, Abi>, Self::Error> {
878 let (exec_result, trace) = self
879 .api
880 .call_dry_run(dest, input_data, value, storage_deposit_limit, signer)
881 .await;
882 Ok(CallDryRunResult {
883 exec_result,
884 trace,
885 _marker: Default::default(),
886 })
887 }
888
889 async fn map_account(
892 &mut self,
893 caller: &Keypair,
894 ) -> Result<Option<Self::EventLog>, Self::Error> {
895 let addr = self.derive_keypair_address(caller);
896 if self.fetch_original_account(&addr).await?.is_some() {
897 return Ok(None);
898 }
899 let (tx_events, trace) = self.api.map_account(caller).await;
900
901 for evt in tx_events.iter() {
902 let evt = evt.unwrap_or_else(|err| {
903 panic!("unable to unwrap event: {err:?}");
904 });
905
906 if is_extrinsic_failed_event(&evt) {
907 let metadata = self.api.client.metadata();
908 let dispatch_error =
909 DispatchError::decode_from(evt.field_bytes(), metadata)
910 .map_err(|e| Error::Decoding(e.to_string()))?;
911 log_error(&format!(
912 "extrinsic for `map_account` failed: {dispatch_error} {trace:?}"
913 ));
914 return Err(Error::CallExtrinsic(dispatch_error, trace))
915 }
916 }
917
918 Ok(Some(tx_events))
919 }
920
921 async fn to_account_id(&mut self, addr: &H160) -> Result<E::AccountId, Self::Error> {
922 let contract_info_address =
923 dynamic("Revive", "OriginalAccount", vec![Value::from_bytes(addr)]);
924 let raw_value = self
925 .api
926 .client
927 .storage()
928 .at_latest()
929 .await
930 .map_err(|err| Error::Other(format!("failed to fetch latest: {err:?}")))?
931 .fetch(&contract_info_address)
932 .await
933 .map_err(|err| {
934 Error::Other(format!("failed to fetch account info: {err:?}"))
935 })?;
936 match raw_value {
937 None => {
938 let fallback = to_fallback_account_id(addr);
941 tracing::debug!(
942 "No address suffix was found in the node for H160 address {:?}, using fallback {:?}",
943 addr,
944 fallback
945 );
946 let account_id = E::AccountId::decode(&mut &fallback[..]).unwrap();
947 Ok(account_id)
948 }
949 Some(raw_value) => {
950 let raw_account_id = raw_value.as_type::<[u8; 32]>().expect("oh");
951 let account: E::AccountId = Decode::decode(&mut &raw_account_id[..])
952 .map_err(|err| {
953 panic!("AccountId from `[u8; 32]` deserialization error: {}", err)
954 })?;
955 Ok(account)
956 }
957 }
958 }
959}
960
961impl<C, E> ContractsBackend<E> for Client<C, E>
962where
963 C: subxt::Config + Send + Sync,
964 C::AccountId: Clone
965 + Debug
966 + Send
967 + Sync
968 + core::fmt::Display
969 + scale::Codec
970 + From<sr25519::PublicKey>
971 + serde::de::DeserializeOwned,
972 C::Address: From<sr25519::PublicKey>,
973 C::Signature: From<sr25519::Signature>,
974 C::Address: Send + Sync,
975 E: Environment,
976 E::AccountId: Debug + Send + Sync,
977 E::Balance:
978 Clone + Debug + Send + Sync + From<u128> + scale::HasCompact + serde::Serialize,
979 H256: Debug + Send + scale::Encode,
980{
981 type Error = Error;
982 type EventLog = ExtrinsicEvents<C>;
983}
984
985impl<C, E> E2EBackend<E> for Client<C, E>
986where
987 C: subxt::Config + Send + Sync,
988 C::AccountId: Clone
989 + Debug
990 + Send
991 + Sync
992 + core::fmt::Display
993 + scale::Codec
994 + From<sr25519::PublicKey>
995 + From<[u8; 32]>
996 + serde::de::DeserializeOwned,
997 C::Address: From<sr25519::PublicKey>,
998 C::Signature: From<sr25519::Signature>,
999 C::Address: Send + Sync,
1000 <C::ExtrinsicParams as ExtrinsicParams<C>>::Params:
1001 From<<DefaultExtrinsicParams<C> as ExtrinsicParams<C>>::Params>,
1002 E: Environment,
1003 E::AccountId: Debug + Send + Sync,
1004 E::EventRecord: Debug,
1005 E::Balance:
1006 Clone + Debug + Send + Sync + From<u128> + scale::HasCompact + serde::Serialize,
1007 H256: Debug + Send + Sync + scale::Encode,
1008{
1009}
1010
1011fn get_composite_field_value<'a, T>(
1017 value: &'a Value<T>,
1018 field_name: &str,
1019) -> Result<&'a Value<T>, Error> {
1020 if let ValueDef::Composite(Composite::Named(fields)) = &value.value {
1021 let (_, field) = fields
1022 .iter()
1023 .find(|(name, _)| name == field_name)
1024 .ok_or_else(|| {
1025 Error::Balance(format!("No field named '{field_name}' found"))
1026 })?;
1027 Ok(field)
1028 } else {
1029 Err(Error::Balance(
1030 "Expected a composite type with named fields".into(),
1031 ))
1032 }
1033}
1034
1035fn is_extrinsic_failed_event<C: subxt::Config>(event: &EventDetails<C>) -> bool {
1037 event.pallet_name() == "System" && event.variant_name() == "ExtrinsicFailed"
1038}
1039
1040impl<E: Environment, V, C: subxt::Config, Abi> CallResult<E, V, ExtrinsicEvents<C>, Abi> {
1041 pub fn contains_event(&self, pallet_name: &str, variant_name: &str) -> bool {
1043 self.events.iter().any(|event| {
1044 let event = event.expect("unable to extract event");
1045 tracing::debug!(
1046 "found event with pallet: {:?}, variant: {:?}",
1047 event.pallet_name(),
1048 event.variant_name()
1049 );
1050 event.pallet_name() == pallet_name && event.variant_name() == variant_name
1051 })
1052 }
1053
1054 #[allow(clippy::result_large_err)] pub fn contract_emitted_events(
1057 &self,
1058 ) -> Result<Vec<EventWithTopics<events::ContractEmitted>>, subxt::Error>
1059 where
1060 HashFor<C>: Into<sp_core::H256>,
1061 {
1062 let mut events_with_topics = Vec::new();
1063 for event in self.events.iter() {
1064 let event = event?;
1065 if let Some(decoded_event) = event.as_event::<events::ContractEmitted>()? {
1066 let topics = decoded_event.topics.clone();
1067 let event_with_topics = EventWithTopics {
1068 event: decoded_event,
1069 topics,
1070 };
1071 events_with_topics.push(event_with_topics);
1072 }
1073 }
1074 Ok(events_with_topics)
1075 }
1076}