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