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 jsonrpsee::core::async_trait;
77use pallet_revive::evm::CallTrace;
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 "extrinsic for `raw_call` failed: {dispatch_error} {trace:?}"
804 ));
805 return Err(Error::CallExtrinsic(dispatch_error, trace))
806 }
807 }
808
809 Ok((tx_events, trace))
810 }
811
812 async fn bare_call_dry_run<
819 Args: Sync + AbiEncodeWith<Abi> + Clone,
820 RetType: Send + DecodeMessageResult<Abi>,
821 Abi: Sync + Clone,
822 >(
823 &mut self,
824 caller: &Keypair,
825 message: &CallBuilderFinal<E, Args, RetType, Abi>,
826 value: E::Balance,
827 storage_deposit_limit: DepositLimit<E::Balance>,
828 ) -> Result<CallDryRunResult<E, RetType, Abi>, Self::Error>
829 where
830 CallBuilderFinal<E, Args, RetType, Abi>: Clone,
831 {
832 let _ = self.map_account(caller).await;
834
835 let dest = *message.clone().params().callee();
836 let exec_input = message.clone().params().exec_input().encode();
837
838 let (exec_result, trace) = self
839 .api
840 .call_dry_run(dest, exec_input, value, storage_deposit_limit, caller)
841 .await;
842 log_info(&format!("call dry run result: {:?}", &exec_result.result));
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: DepositLimit<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}