1#![doc = include_str!("../README.md")]
11#![allow(clippy::expect_used)]
25#![cfg_attr(not(feature = "std"), no_std)]
26#![deny(
28 rustdoc::broken_intra_doc_links,
29 rustdoc::missing_crate_level_docs,
30 rustdoc::invalid_codeblock_attributes,
31 missing_docs
32)]
33
34extern crate alloc;
35use frame_support::{
36 dispatch::{DispatchInfo, DispatchResult, PostDispatchInfo},
37 pallet_prelude::*,
38 traits::{
39 tokens::{
40 fungible::{Inspect as InspectFungible, Mutate},
41 Fortitude, Preservation,
42 },
43 IsSubType,
44 },
45};
46use lazy_static::lazy_static;
47use parity_scale_codec::{Decode, Encode};
48
49use common_runtime::signature::check_signature;
50
51#[cfg(feature = "runtime-benchmarks")]
52use common_primitives::benchmarks::{MsaBenchmarkHelper, RegisterProviderBenchmarkHelper};
53
54use alloc::{boxed::Box, vec, vec::Vec};
55use common_primitives::{
56 capacity::TargetValidator,
57 handles::HandleProvider,
58 msa::*,
59 node::{EIP712Encode, ProposalProvider},
60 schema::{SchemaId, SchemaValidator},
61 signatures::{AccountAddressMapper, EthereumAddressMapper},
62};
63use frame_system::pallet_prelude::*;
64use scale_info::TypeInfo;
65use sp_core::crypto::AccountId32;
66use sp_io::hashing::keccak_256;
67#[allow(deprecated)]
68#[allow(unused)]
69use sp_runtime::{
70 traits::{
71 AsSystemOriginSigner, BlockNumberProvider, Convert, DispatchInfoOf, Dispatchable,
72 PostDispatchInfoOf, TransactionExtension, ValidateResult, Zero,
73 },
74 ArithmeticError, DispatchError, MultiSignature, Weight,
75};
76
77pub use pallet::*;
78pub use types::{
79 AddKeyData, AddProvider, AuthorizedKeyData, PermittedDelegationSchemas, RecoveryCommitment,
80 RecoveryCommitmentPayload, EMPTY_FUNCTION,
81};
82pub use weights::*;
83
84pub mod offchain_storage;
86use crate::types::{PayloadTypeDiscriminator, RecoveryHash};
87pub use offchain_storage::*;
88
89#[cfg(feature = "runtime-benchmarks")]
90mod benchmarking;
91
92#[cfg(test)]
93mod tests;
94
95pub mod types;
96
97pub mod weights;
98
99#[frame_support::pallet]
100pub mod pallet {
101 use crate::types::RecoveryHash;
102
103 use super::*;
104
105 #[pallet::config]
106 pub trait Config: frame_system::Config {
107 #[allow(deprecated)]
109 type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
110
111 type WeightInfo: WeightInfo;
113
114 type ConvertIntoAccountId32: Convert<Self::AccountId, AccountId32>;
116
117 #[pallet::constant]
119 type MaxPublicKeysPerMsa: Get<u8>;
120
121 #[pallet::constant]
123 type MaxSchemaGrantsPerDelegation: Get<u32>;
124
125 #[pallet::constant]
127 type MaxProviderNameSize: Get<u32>;
128
129 type SchemaValidator: SchemaValidator<SchemaId>;
131
132 type HandleProvider: HandleProvider;
134
135 #[pallet::constant]
137 type MortalityWindowSize: Get<u32>;
138
139 #[pallet::constant]
141 type MaxSignaturesStored: Get<Option<u32>>;
142
143 type CreateProviderViaGovernanceOrigin: EnsureOrigin<Self::RuntimeOrigin>;
145
146 type RecoveryProviderApprovalOrigin: EnsureOrigin<Self::RuntimeOrigin>;
148
149 type Proposal: Parameter
151 + Dispatchable<RuntimeOrigin = Self::RuntimeOrigin, PostInfo = PostDispatchInfo>
152 + From<Call<Self>>;
153
154 type ProposalProvider: ProposalProvider<Self::AccountId, Self::Proposal>;
156
157 type Currency: Mutate<Self::AccountId> + InspectFungible<Self::AccountId>;
159 }
160
161 const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
162
163 #[pallet::pallet]
164 #[pallet::storage_version(STORAGE_VERSION)]
165 pub struct Pallet<T>(_);
166
167 #[pallet::storage]
172 pub type CurrentMsaIdentifierMaximum<T> = StorageValue<_, MessageSourceId, ValueQuery>;
173
174 #[pallet::storage]
178 pub type DelegatorAndProviderToDelegation<T: Config> = StorageDoubleMap<
179 _,
180 Twox64Concat,
181 DelegatorId,
182 Twox64Concat,
183 ProviderId,
184 Delegation<SchemaId, BlockNumberFor<T>, T::MaxSchemaGrantsPerDelegation>,
185 OptionQuery,
186 >;
187
188 #[pallet::storage]
192 pub type RecoveryProviders<T: Config> =
193 StorageMap<_, Twox64Concat, ProviderId, bool, OptionQuery>;
194
195 #[pallet::storage]
199 pub type ProviderToRegistryEntry<T: Config> = StorageMap<
200 _,
201 Twox64Concat,
202 ProviderId,
203 ProviderRegistryEntry<T::MaxProviderNameSize>,
204 OptionQuery,
205 >;
206
207 #[pallet::storage]
211 pub type PublicKeyToMsaId<T: Config> =
212 StorageMap<_, Twox64Concat, T::AccountId, MessageSourceId, OptionQuery>;
213
214 #[pallet::storage]
218 pub(super) type PublicKeyCountForMsaId<T: Config> =
219 StorageMap<_, Twox64Concat, MessageSourceId, u8, ValueQuery>;
220
221 #[pallet::storage]
238 pub(super) type PayloadSignatureRegistryList<T: Config> = StorageMap<
239 _, Twox64Concat, MultiSignature, (BlockNumberFor<T>, MultiSignature), OptionQuery, GetDefault, T::MaxSignaturesStored, >;
247
248 #[pallet::storage]
252 pub(super) type PayloadSignatureRegistryPointer<T: Config> =
253 StorageValue<_, SignatureRegistryPointer<BlockNumberFor<T>>>;
254
255 #[pallet::storage]
258 #[pallet::whitelist_storage]
259 pub(super) type OffchainIndexEventCount<T: Config> = StorageValue<_, u16, ValueQuery>;
260
261 #[pallet::storage]
265 pub type MsaIdToRecoveryCommitment<T: Config> =
266 StorageMap<_, Twox64Concat, MessageSourceId, RecoveryCommitment, OptionQuery>;
267
268 #[pallet::event]
269 #[pallet::generate_deposit(pub (super) fn deposit_event)]
270 pub enum Event<T: Config> {
271 MsaCreated {
273 msa_id: MessageSourceId,
275
276 key: T::AccountId,
278 },
279 PublicKeyAdded {
281 msa_id: MessageSourceId,
283
284 key: T::AccountId,
286 },
287 PublicKeyDeleted {
289 key: T::AccountId,
291 },
292 DelegationGranted {
294 provider_id: ProviderId,
296
297 delegator_id: DelegatorId,
299 },
300 ProviderCreated {
302 provider_id: ProviderId,
304 },
305 DelegationRevoked {
307 provider_id: ProviderId,
309
310 delegator_id: DelegatorId,
312 },
313 MsaRetired {
315 msa_id: MessageSourceId,
317 },
318 DelegationUpdated {
320 provider_id: ProviderId,
322
323 delegator_id: DelegatorId,
325 },
326 RecoveryCommitmentAdded {
328 who: T::AccountId,
330
331 msa_id: MessageSourceId,
333
334 recovery_commitment: RecoveryCommitment,
336 },
337 RecoveryProviderApproved {
339 provider_id: ProviderId,
341 },
342 RecoveryProviderRemoved {
344 provider_id: ProviderId,
346 },
347 AccountRecovered {
349 msa_id: MessageSourceId,
351 recovery_provider: ProviderId,
353 new_control_key: T::AccountId,
355 },
356 RecoveryCommitmentInvalidated {
358 msa_id: MessageSourceId,
360 recovery_commitment: RecoveryCommitment,
362 },
363 }
364
365 #[pallet::error]
366 pub enum Error<T> {
367 KeyAlreadyRegistered,
369
370 MsaIdOverflow,
372
373 MsaOwnershipInvalidSignature,
375
376 NotMsaOwner,
378
379 InvalidSignature,
381
382 NotKeyOwner,
384
385 NoKeyExists,
387
388 KeyLimitExceeded,
390
391 InvalidSelfRemoval,
393
394 InvalidSelfProvider,
396
397 InvalidSchemaId,
399
400 DuplicateProvider,
402
403 AddProviderSignatureVerificationFailed,
405
406 UnauthorizedDelegator,
408
409 UnauthorizedProvider,
411
412 DelegationRevoked,
414
415 DelegationNotFound,
417
418 DuplicateProviderRegistryEntry,
420
421 ExceedsMaxProviderNameSize,
423
424 ExceedsMaxSchemaGrantsPerDelegation,
426
427 SchemaNotGranted,
429
430 ProviderNotRegistered,
432
433 ProofHasExpired,
435
436 ProofNotYetValid,
438
439 SignatureAlreadySubmitted,
441
442 NewKeyOwnershipInvalidSignature,
444
445 CannotPredictValidityPastCurrentBlock,
447
448 SignatureRegistryLimitExceeded,
450
451 SignatureRegistryCorrupted,
453
454 InsufficientBalanceToWithdraw,
456
457 UnexpectedTokenTransferError,
459
460 NotAuthorizedRecoveryProvider,
462
463 InvalidRecoveryCommitment,
465
466 NoRecoveryCommitment,
468 }
469
470 impl<T: Config> BlockNumberProvider for Pallet<T> {
471 type BlockNumber = BlockNumberFor<T>;
472
473 fn current_block_number() -> Self::BlockNumber {
474 frame_system::Pallet::<T>::block_number()
475 }
476 }
477
478 #[pallet::hooks]
479 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
480 fn on_initialize(_block_number: BlockNumberFor<T>) -> Weight {
481 <OffchainIndexEventCount<T>>::set(0u16);
482 T::DbWeight::get().reads_writes(1u64, 1u64)
484 }
485
486 fn offchain_worker(block_number: BlockNumberFor<T>) {
487 log::info!("Running offchain workers! {block_number:?}");
488 do_offchain_worker::<T>(block_number)
489 }
490 }
491
492 #[pallet::call]
493 impl<T: Config> Pallet<T> {
494 #[pallet::call_index(0)]
504 #[pallet::weight(T::WeightInfo::create())]
505 pub fn create(origin: OriginFor<T>) -> DispatchResult {
506 let public_key = ensure_signed(origin)?;
507
508 let (new_msa_id, new_public_key) =
509 Self::create_account(public_key, |_| -> DispatchResult { Ok(()) })?;
510
511 let event = Event::MsaCreated { msa_id: new_msa_id, key: new_public_key };
512 offchain_index_event::<T>(Some(&event), new_msa_id);
513 Self::deposit_event(event);
514 Ok(())
515 }
516
517 #[pallet::call_index(1)]
539 #[pallet::weight(T::WeightInfo::create_sponsored_account_with_delegation(
540 add_provider_payload.schema_ids.len() as u32
541 ))]
542 pub fn create_sponsored_account_with_delegation(
543 origin: OriginFor<T>,
544 delegator_key: T::AccountId,
545 proof: MultiSignature,
546 add_provider_payload: AddProvider,
547 ) -> DispatchResult {
548 let provider_key = ensure_signed(origin)?;
549
550 ensure!(
551 Self::verify_signature(&proof, &delegator_key, &add_provider_payload),
552 Error::<T>::InvalidSignature
553 );
554
555 Self::register_signature(&proof, add_provider_payload.expiration.into())?;
556
557 let provider_msa_id = Self::ensure_valid_msa_key(&provider_key)?;
558 ensure!(
559 add_provider_payload.authorized_msa_id == provider_msa_id,
560 Error::<T>::UnauthorizedProvider
561 );
562
563 ensure!(
565 Self::is_registered_provider(provider_msa_id),
566 Error::<T>::ProviderNotRegistered
567 );
568
569 let (new_delegator_msa_id, new_delegator_public_key) =
570 Self::create_account(delegator_key, |new_msa_id| -> DispatchResult {
571 Self::add_provider(
572 ProviderId(provider_msa_id),
573 DelegatorId(new_msa_id),
574 add_provider_payload.schema_ids,
575 )?;
576 Ok(())
577 })?;
578
579 let event =
580 Event::MsaCreated { msa_id: new_delegator_msa_id, key: new_delegator_public_key };
581 offchain_index_event::<T>(Some(&event), new_delegator_msa_id);
582 Self::deposit_event(event);
583 Self::deposit_event(Event::DelegationGranted {
584 delegator_id: DelegatorId(new_delegator_msa_id),
585 provider_id: ProviderId(provider_msa_id),
586 });
587 Ok(())
588 }
589
590 #[pallet::call_index(2)]
602 #[pallet::weight(T::WeightInfo::create_provider())]
603 pub fn create_provider(origin: OriginFor<T>, provider_name: Vec<u8>) -> DispatchResult {
604 let provider_key = ensure_signed(origin)?;
605 let provider_msa_id = Self::ensure_valid_msa_key(&provider_key)?;
606 Self::create_provider_for(provider_msa_id, provider_name)?;
607 Self::deposit_event(Event::ProviderCreated {
608 provider_id: ProviderId(provider_msa_id),
609 });
610 Ok(())
611 }
612
613 #[pallet::call_index(3)]
634 #[pallet::weight(T::WeightInfo::grant_delegation(add_provider_payload.schema_ids.len() as u32))]
635 pub fn grant_delegation(
636 origin: OriginFor<T>,
637 delegator_key: T::AccountId,
638 proof: MultiSignature,
639 add_provider_payload: AddProvider,
640 ) -> DispatchResult {
641 let provider_key = ensure_signed(origin)?;
642
643 ensure!(
644 Self::verify_signature(&proof, &delegator_key, &add_provider_payload),
645 Error::<T>::AddProviderSignatureVerificationFailed
646 );
647
648 Self::register_signature(&proof, add_provider_payload.expiration.into())?;
649 let (provider_id, delegator_id) =
650 Self::ensure_valid_registered_provider(&delegator_key, &provider_key)?;
651
652 ensure!(
653 add_provider_payload.authorized_msa_id == provider_id.0,
654 Error::<T>::UnauthorizedDelegator
655 );
656
657 Self::upsert_schema_permissions(
658 provider_id,
659 delegator_id,
660 add_provider_payload.schema_ids,
661 )?;
662 Self::deposit_event(Event::DelegationGranted { delegator_id, provider_id });
663
664 Ok(())
665 }
666
667 #[pallet::call_index(4)]
679 #[pallet::weight((T::WeightInfo::revoke_delegation_by_delegator(), DispatchClass::Normal, Pays::No))]
680 pub fn revoke_delegation_by_delegator(
681 origin: OriginFor<T>,
682 #[pallet::compact] provider_msa_id: MessageSourceId,
683 ) -> DispatchResult {
684 let who = ensure_signed(origin)?;
685
686 match PublicKeyToMsaId::<T>::get(&who) {
687 Some(delegator_msa_id) => {
688 let delegator_id = DelegatorId(delegator_msa_id);
689 let provider_id = ProviderId(provider_msa_id);
690 Self::revoke_provider(provider_id, delegator_id)?;
691 Self::deposit_event(Event::DelegationRevoked { delegator_id, provider_id });
692 },
693 None => {
694 log::error!(
695 "TransactionExtension did not catch invalid MSA for account {who:?}, "
696 );
697 },
698 }
699
700 Ok(())
701 }
702
703 #[pallet::call_index(5)]
729 #[pallet::weight(T::WeightInfo::add_public_key_to_msa())]
730 pub fn add_public_key_to_msa(
731 origin: OriginFor<T>,
732 msa_owner_public_key: T::AccountId,
733 msa_owner_proof: MultiSignature,
734 new_key_owner_proof: MultiSignature,
735 add_key_payload: AddKeyData<T>,
736 ) -> DispatchResult {
737 let _ = ensure_signed(origin)?;
738
739 ensure!(
740 Self::verify_signature(&msa_owner_proof, &msa_owner_public_key, &add_key_payload),
741 Error::<T>::MsaOwnershipInvalidSignature
742 );
743
744 ensure!(
745 Self::verify_signature(
746 &new_key_owner_proof,
747 &add_key_payload.new_public_key,
748 &add_key_payload
749 ),
750 Error::<T>::NewKeyOwnershipInvalidSignature
751 );
752
753 Self::register_signature(&msa_owner_proof, add_key_payload.expiration)?;
754 Self::register_signature(&new_key_owner_proof, add_key_payload.expiration)?;
755
756 let msa_id = add_key_payload.msa_id;
757
758 Self::ensure_msa_owner(&msa_owner_public_key, msa_id)?;
759
760 Self::add_key(
761 msa_id,
762 &add_key_payload.new_public_key.clone(),
763 |msa_id| -> DispatchResult {
764 let event = Event::PublicKeyAdded {
765 msa_id,
766 key: add_key_payload.new_public_key.clone(),
767 };
768 offchain_index_event::<T>(Some(&event), msa_id);
769 Self::deposit_event(event);
770 Ok(())
771 },
772 )?;
773
774 Ok(())
775 }
776
777 #[pallet::call_index(6)]
792 #[pallet::weight((T::WeightInfo::delete_msa_public_key(), DispatchClass::Normal, Pays::No))]
793 pub fn delete_msa_public_key(
794 origin: OriginFor<T>,
795 public_key_to_delete: T::AccountId,
796 ) -> DispatchResult {
797 let who = ensure_signed(origin)?;
798
799 match PublicKeyToMsaId::<T>::get(&who) {
800 Some(who_msa_id) => {
801 Self::delete_key_for_msa(who_msa_id, &public_key_to_delete)?;
802
803 let event = Event::PublicKeyDeleted { key: public_key_to_delete };
805 offchain_index_event::<T>(Some(&event), who_msa_id);
806 Self::deposit_event(event);
807 },
808 None => {
809 log::error!(
810 "TransactionExtension did not catch invalid MSA for account {who:?}"
811 );
812 },
813 }
814 Ok(())
815 }
816
817 #[pallet::call_index(7)]
829 #[pallet::weight((T::WeightInfo::revoke_delegation_by_provider(), DispatchClass::Normal, Pays::No))]
830 pub fn revoke_delegation_by_provider(
831 origin: OriginFor<T>,
832 #[pallet::compact] delegator: MessageSourceId,
833 ) -> DispatchResult {
834 let who = ensure_signed(origin)?;
835
836 match PublicKeyToMsaId::<T>::get(&who) {
840 Some(msa_id) => {
841 let provider_id = ProviderId(msa_id);
842 let delegator_id = DelegatorId(delegator);
843 Self::revoke_provider(provider_id, delegator_id)?;
844 Self::deposit_event(Event::DelegationRevoked { provider_id, delegator_id })
845 },
846 None => {
847 log::error!(
848 "TransactionExtension did not catch invalid MSA for account {who:?}"
849 );
850 },
851 }
852
853 Ok(())
854 }
855
856 #[pallet::call_index(10)]
878 #[pallet::weight((T::WeightInfo::retire_msa(), DispatchClass::Normal, Pays::No))]
879 pub fn retire_msa(origin: OriginFor<T>) -> DispatchResult {
880 let who = ensure_signed(origin)?;
882
883 match PublicKeyToMsaId::<T>::get(&who) {
886 Some(msa_id) => {
887 Self::delete_key_for_msa(msa_id, &who)?;
888 let event = Event::PublicKeyDeleted { key: who };
889 offchain_index_event::<T>(Some(&event), msa_id);
890 Self::deposit_event(event);
891 Self::deposit_event(Event::MsaRetired { msa_id });
892 },
893 None => {
894 log::error!(
895 "TransactionExtension did not catch invalid MSA for account {who:?}"
896 );
897 },
898 }
899 Ok(())
900 }
901
902 #[pallet::call_index(11)]
907 #[pallet::weight(T::WeightInfo::propose_to_be_provider())]
908 pub fn propose_to_be_provider(
909 origin: OriginFor<T>,
910 provider_name: Vec<u8>,
911 ) -> DispatchResult {
912 let bounded_name: BoundedVec<u8, T::MaxProviderNameSize> =
913 provider_name.try_into().map_err(|_| Error::<T>::ExceedsMaxProviderNameSize)?;
914
915 let proposer = ensure_signed(origin)?;
916 Self::ensure_valid_msa_key(&proposer)?;
917
918 let proposal: Box<T::Proposal> = Box::new(
919 (Call::<T>::create_provider_via_governance {
920 provider_key: proposer.clone(),
921 provider_name: bounded_name.into(),
922 })
923 .into(),
924 );
925 let threshold = 1;
926 T::ProposalProvider::propose(proposer, threshold, proposal)?;
927 Ok(())
928 }
929
930 #[pallet::call_index(12)]
940 #[pallet::weight(T::WeightInfo::create_provider_via_governance())]
941 pub fn create_provider_via_governance(
942 origin: OriginFor<T>,
943 provider_key: T::AccountId,
944 provider_name: Vec<u8>,
945 ) -> DispatchResult {
946 T::CreateProviderViaGovernanceOrigin::ensure_origin(origin)?;
947 let provider_msa_id = Self::ensure_valid_msa_key(&provider_key)?;
948 Self::create_provider_for(provider_msa_id, provider_name)?;
949 Self::deposit_event(Event::ProviderCreated {
950 provider_id: ProviderId(provider_msa_id),
951 });
952 Ok(())
953 }
954
955 #[pallet::call_index(13)]
957 #[pallet::weight(T::WeightInfo::reindex_offchain())]
958 pub fn reindex_offchain(
959 origin: OriginFor<T>,
960 event: OffchainReplayEvent<T>,
961 ) -> DispatchResult {
962 let _ = ensure_signed(origin)?;
963 match event {
964 OffchainReplayEvent::MsaPallet(MsaOffchainReplayEvent::KeyReIndex {
965 msa_id,
966 index_key,
967 }) => {
968 match index_key {
970 Some(key) => {
971 let event = Event::PublicKeyAdded { msa_id, key };
972 offchain_index_event::<T>(Some(&event), msa_id);
973 },
974 None => {
975 offchain_index_event::<T>(None, msa_id);
976 },
977 }
978 },
979 }
980
981 Ok(())
982 }
983
984 #[pallet::call_index(14)]
1005 #[pallet::weight((T::WeightInfo::withdraw_tokens(), DispatchClass::Normal, Pays::No))]
1006 pub fn withdraw_tokens(
1007 origin: OriginFor<T>,
1008 _msa_owner_public_key: T::AccountId,
1009 msa_owner_proof: MultiSignature,
1010 authorization_payload: AuthorizedKeyData<T>,
1011 ) -> DispatchResult {
1012 let public_key = ensure_signed(origin)?;
1013
1014 Self::register_signature(&msa_owner_proof, authorization_payload.expiration)?;
1015
1016 let msa_id = authorization_payload.msa_id;
1017
1018 let msa_address = Self::msa_id_to_eth_address(msa_id);
1020
1021 let mut bytes = &EthereumAddressMapper::to_bytes32(&msa_address.0)[..];
1023 let msa_account_id = T::AccountId::decode(&mut bytes).map_err(|_| {
1024 log::error!("Failed to decode MSA account ID from Ethereum address");
1025 Error::<T>::NoKeyExists
1026 })?;
1027
1028 let msa_balance = T::Currency::reducible_balance(
1030 &msa_account_id,
1031 Preservation::Expendable,
1032 Fortitude::Polite,
1033 );
1034 ensure!(msa_balance > Zero::zero(), Error::<T>::InsufficientBalanceToWithdraw);
1035
1036 let result = <T as pallet::Config>::Currency::transfer(
1038 &msa_account_id,
1039 &public_key,
1040 msa_balance,
1041 Preservation::Expendable,
1042 );
1043 ensure!(result.is_ok(), Error::<T>::UnexpectedTokenTransferError);
1044
1045 Ok(())
1046 }
1047
1048 #[pallet::call_index(15)]
1070 #[pallet::weight(T::WeightInfo::add_recovery_commitment())]
1071 pub fn add_recovery_commitment(
1072 origin: OriginFor<T>,
1073 msa_owner_key: T::AccountId,
1074 proof: MultiSignature,
1075 payload: RecoveryCommitmentPayload<T>,
1076 ) -> DispatchResult {
1077 let _origin_key = ensure_signed(origin)?;
1078
1079 ensure!(
1081 Self::verify_signature(&proof, &msa_owner_key, &payload),
1082 Error::<T>::InvalidSignature
1083 );
1084
1085 Self::register_signature(&proof, payload.expiration)?;
1087
1088 let msa_id = Self::ensure_valid_msa_key(&msa_owner_key)?;
1090
1091 MsaIdToRecoveryCommitment::<T>::insert(msa_id, payload.recovery_commitment);
1093 Self::deposit_event(Event::RecoveryCommitmentAdded {
1094 who: msa_owner_key,
1095 msa_id,
1096 recovery_commitment: payload.recovery_commitment,
1097 });
1098
1099 Ok(())
1100 }
1101
1102 #[pallet::call_index(16)]
1112 #[pallet::weight(T::WeightInfo::approve_recovery_provider())]
1113 pub fn approve_recovery_provider(
1114 origin: OriginFor<T>,
1115 provider_key: T::AccountId,
1116 ) -> DispatchResult {
1117 T::RecoveryProviderApprovalOrigin::ensure_origin(origin)?;
1118
1119 let provider_msa_id = Self::ensure_valid_msa_key(&provider_key)?;
1120 ensure!(
1121 Self::is_registered_provider(provider_msa_id),
1122 Error::<T>::ProviderNotRegistered
1123 );
1124
1125 if Self::is_approved_recovery_provider(&ProviderId(provider_msa_id)) {
1127 return Ok(());
1128 }
1129
1130 RecoveryProviders::<T>::insert(ProviderId(provider_msa_id), true);
1131
1132 Self::deposit_event(Event::RecoveryProviderApproved {
1133 provider_id: ProviderId(provider_msa_id),
1134 });
1135
1136 Ok(())
1137 }
1138
1139 #[pallet::call_index(17)]
1150 #[pallet::weight(T::WeightInfo::remove_recovery_provider())]
1151 pub fn remove_recovery_provider(
1152 origin: OriginFor<T>,
1153 provider: ProviderId,
1154 ) -> DispatchResult {
1155 T::RecoveryProviderApprovalOrigin::ensure_origin(origin)?;
1156
1157 RecoveryProviders::<T>::remove(provider);
1158 Self::deposit_event(Event::RecoveryProviderRemoved { provider_id: provider });
1159 Ok(())
1160 }
1161
1162 #[pallet::call_index(18)]
1177 #[pallet::weight(T::WeightInfo::recover_account())]
1178 pub fn recover_account(
1179 origin: OriginFor<T>,
1180 intermediary_hash_a: RecoveryHash,
1181 intermediary_hash_b: RecoveryHash,
1182 new_control_key_proof: MultiSignature,
1183 add_key_payload: AddKeyData<T>,
1184 ) -> DispatchResult {
1185 let provider_key = ensure_signed(origin)?;
1186
1187 let provider_msa_id = Self::ensure_approved_recovery_provider(&provider_key)?;
1188
1189 let recovery_commitment = Self::ensure_valid_recovery_commitment(
1190 intermediary_hash_a,
1191 intermediary_hash_b,
1192 add_key_payload.msa_id,
1193 )?;
1194
1195 Self::ensure_valid_new_key_owner(&new_control_key_proof, &add_key_payload)?;
1196
1197 Self::add_key(
1198 add_key_payload.msa_id,
1199 &add_key_payload.new_public_key.clone(),
1200 |msa_id| -> DispatchResult {
1201 let event = Event::PublicKeyAdded {
1202 msa_id,
1203 key: add_key_payload.new_public_key.clone(),
1204 };
1205 offchain_index_event::<T>(Some(&event), msa_id);
1206 Self::deposit_event(event);
1207 Ok(())
1208 },
1209 )?;
1210
1211 MsaIdToRecoveryCommitment::<T>::remove(add_key_payload.msa_id);
1213
1214 Self::deposit_event(Event::AccountRecovered {
1216 msa_id: add_key_payload.msa_id,
1217 recovery_provider: ProviderId(provider_msa_id),
1218 new_control_key: add_key_payload.new_public_key.clone(),
1219 });
1220
1221 Self::deposit_event(Event::RecoveryCommitmentInvalidated {
1222 msa_id: add_key_payload.msa_id,
1223 recovery_commitment,
1224 });
1225
1226 Ok(())
1227 }
1228 }
1229}
1230
1231impl<T: Config> Pallet<T> {
1232 pub fn is_approved_recovery_provider(provider: &ProviderId) -> bool {
1240 RecoveryProviders::<T>::get(provider).unwrap_or(false)
1241 }
1242
1243 pub fn compute_recovery_commitment(
1252 intermediary_hash_a: RecoveryHash,
1253 intermediary_hash_b: RecoveryHash,
1254 ) -> RecoveryCommitment {
1255 let mut input = Vec::with_capacity(64);
1256 input.extend_from_slice(&intermediary_hash_a);
1257 input.extend_from_slice(&intermediary_hash_b);
1258 keccak_256(&input)
1259 }
1260
1261 fn ensure_approved_recovery_provider(
1273 provider_key: &T::AccountId,
1274 ) -> Result<MessageSourceId, DispatchError> {
1275 let provider_msa_id = Self::ensure_valid_msa_key(provider_key)?;
1276
1277 ensure!(
1278 Self::is_approved_recovery_provider(&ProviderId(provider_msa_id)),
1279 Error::<T>::NotAuthorizedRecoveryProvider
1280 );
1281
1282 Ok(provider_msa_id)
1283 }
1284
1285 fn ensure_valid_recovery_commitment(
1299 intermediary_hash_a: RecoveryHash,
1300 intermediary_hash_b: RecoveryHash,
1301 msa_id: MessageSourceId,
1302 ) -> Result<RecoveryCommitment, DispatchError> {
1303 let recovery_commitment: RecoveryCommitment =
1304 Self::compute_recovery_commitment(intermediary_hash_a, intermediary_hash_b);
1305
1306 let stored_commitment: RecoveryCommitment =
1307 MsaIdToRecoveryCommitment::<T>::get(msa_id).ok_or(Error::<T>::NoRecoveryCommitment)?;
1308
1309 ensure!(recovery_commitment == stored_commitment, Error::<T>::InvalidRecoveryCommitment);
1310
1311 Ok(recovery_commitment)
1312 }
1313
1314 fn ensure_valid_new_key_owner(
1324 new_control_key_proof: &MultiSignature,
1325 add_key_payload: &AddKeyData<T>,
1326 ) -> DispatchResult {
1327 ensure!(
1330 Self::verify_signature(
1331 new_control_key_proof,
1332 &add_key_payload.new_public_key,
1333 add_key_payload
1334 ),
1335 Error::<T>::NewKeyOwnershipInvalidSignature
1336 );
1337 Self::register_signature(new_control_key_proof, add_key_payload.expiration)?;
1338
1339 Ok(())
1340 }
1341
1342 pub fn create_account<F>(
1350 key: T::AccountId,
1351 on_success: F,
1352 ) -> Result<(MessageSourceId, T::AccountId), DispatchError>
1353 where
1354 F: FnOnce(MessageSourceId) -> DispatchResult,
1355 {
1356 let next_msa_id = Self::get_next_msa_id()?;
1357 Self::add_key(next_msa_id, &key, on_success)?;
1358 let _ = Self::set_msa_identifier(next_msa_id);
1359
1360 Ok((next_msa_id, key))
1361 }
1362
1363 pub fn get_next_msa_id() -> Result<MessageSourceId, DispatchError> {
1369 let next = CurrentMsaIdentifierMaximum::<T>::get()
1370 .checked_add(1)
1371 .ok_or(Error::<T>::MsaIdOverflow)?;
1372
1373 Ok(next)
1374 }
1375
1376 pub fn set_msa_identifier(identifier: MessageSourceId) -> DispatchResult {
1378 CurrentMsaIdentifierMaximum::<T>::set(identifier);
1379
1380 Ok(())
1381 }
1382
1383 pub fn create_registered_provider(
1385 provider_id: ProviderId,
1386 name: BoundedVec<u8, T::MaxProviderNameSize>,
1387 ) -> DispatchResult {
1388 ProviderToRegistryEntry::<T>::try_mutate(provider_id, |maybe_metadata| -> DispatchResult {
1389 ensure!(maybe_metadata.take().is_none(), Error::<T>::DuplicateProviderRegistryEntry);
1390 *maybe_metadata = Some(ProviderRegistryEntry { provider_name: name });
1391 Ok(())
1392 })
1393 }
1394
1395 pub fn grant_permissions_for_schemas(
1397 delegator_id: DelegatorId,
1398 provider_id: ProviderId,
1399 schema_ids: Vec<SchemaId>,
1400 ) -> DispatchResult {
1401 Self::try_mutate_delegation(delegator_id, provider_id, |delegation, is_new_delegation| {
1402 ensure!(!is_new_delegation, Error::<T>::DelegationNotFound);
1403 Self::ensure_all_schema_ids_are_valid(&schema_ids)?;
1404
1405 PermittedDelegationSchemas::<T>::try_insert_schemas(delegation, schema_ids)?;
1406
1407 Ok(())
1408 })
1409 }
1410
1411 pub fn revoke_permissions_for_schemas(
1413 delegator_id: DelegatorId,
1414 provider_id: ProviderId,
1415 schema_ids: Vec<SchemaId>,
1416 ) -> DispatchResult {
1417 Self::try_mutate_delegation(delegator_id, provider_id, |delegation, is_new_delegation| {
1418 ensure!(!is_new_delegation, Error::<T>::DelegationNotFound);
1419 Self::ensure_all_schema_ids_are_valid(&schema_ids)?;
1420
1421 let current_block = frame_system::Pallet::<T>::block_number();
1422
1423 PermittedDelegationSchemas::<T>::try_get_mut_schemas(
1424 delegation,
1425 schema_ids,
1426 current_block,
1427 )?;
1428
1429 Ok(())
1430 })
1431 }
1432
1433 pub fn add_key<F>(msa_id: MessageSourceId, key: &T::AccountId, on_success: F) -> DispatchResult
1440 where
1441 F: FnOnce(MessageSourceId) -> DispatchResult,
1442 {
1443 PublicKeyToMsaId::<T>::try_mutate(key, |maybe_msa_id| {
1444 ensure!(maybe_msa_id.is_none(), Error::<T>::KeyAlreadyRegistered);
1445 *maybe_msa_id = Some(msa_id);
1446
1447 <PublicKeyCountForMsaId<T>>::try_mutate(msa_id, |key_count| {
1449 let incremented_key_count =
1451 key_count.checked_add(1).ok_or(ArithmeticError::Overflow)?;
1452
1453 ensure!(
1454 incremented_key_count <= T::MaxPublicKeysPerMsa::get(),
1455 Error::<T>::KeyLimitExceeded
1456 );
1457
1458 *key_count = incremented_key_count;
1459 on_success(msa_id)
1460 })
1461 })
1462 }
1463
1464 pub fn ensure_all_schema_ids_are_valid(schema_ids: &[SchemaId]) -> DispatchResult {
1471 ensure!(
1472 schema_ids.len() <= T::MaxSchemaGrantsPerDelegation::get() as usize,
1473 Error::<T>::ExceedsMaxSchemaGrantsPerDelegation
1474 );
1475
1476 let are_schemas_valid = T::SchemaValidator::are_all_schema_ids_valid(schema_ids);
1477
1478 ensure!(are_schemas_valid, Error::<T>::InvalidSchemaId);
1479
1480 Ok(())
1481 }
1482
1483 pub fn is_registered_provider(msa_id: MessageSourceId) -> bool {
1485 ProviderToRegistryEntry::<T>::contains_key(ProviderId(msa_id))
1486 }
1487
1488 pub fn ensure_valid_registered_provider(
1498 delegator_key: &T::AccountId,
1499 provider_key: &T::AccountId,
1500 ) -> Result<(ProviderId, DelegatorId), DispatchError> {
1501 let provider_msa_id = Self::ensure_valid_msa_key(provider_key)?;
1502 let delegator_msa_id = Self::ensure_valid_msa_key(delegator_key)?;
1503
1504 ensure!(delegator_msa_id != provider_msa_id, Error::<T>::InvalidSelfProvider);
1506
1507 ensure!(Self::is_registered_provider(provider_msa_id), Error::<T>::ProviderNotRegistered);
1509
1510 Ok((provider_msa_id.into(), delegator_msa_id.into()))
1511 }
1512
1513 pub fn ensure_msa_owner(who: &T::AccountId, msa_id: MessageSourceId) -> DispatchResult {
1520 let provider_msa_id = Self::ensure_valid_msa_key(who)?;
1521 ensure!(provider_msa_id == msa_id, Error::<T>::NotMsaOwner);
1522
1523 Ok(())
1524 }
1525
1526 pub fn verify_signature<P>(
1533 signature: &MultiSignature,
1534 signer: &T::AccountId,
1535 payload: &P,
1536 ) -> bool
1537 where
1538 P: Encode + EIP712Encode,
1539 {
1540 let key = T::ConvertIntoAccountId32::convert((*signer).clone());
1541
1542 check_signature(signature, key, payload)
1543 }
1544
1545 pub fn add_provider(
1551 provider_id: ProviderId,
1552 delegator_id: DelegatorId,
1553 schema_ids: Vec<SchemaId>,
1554 ) -> DispatchResult {
1555 Self::try_mutate_delegation(delegator_id, provider_id, |delegation, is_new_delegation| {
1556 ensure!(is_new_delegation, Error::<T>::DuplicateProvider);
1557 Self::ensure_all_schema_ids_are_valid(&schema_ids)?;
1558
1559 PermittedDelegationSchemas::<T>::try_insert_schemas(delegation, schema_ids)?;
1560
1561 Ok(())
1562 })
1563 }
1564
1565 pub fn upsert_schema_permissions(
1570 provider_id: ProviderId,
1571 delegator_id: DelegatorId,
1572 schema_ids: Vec<SchemaId>,
1573 ) -> DispatchResult {
1574 Self::try_mutate_delegation(delegator_id, provider_id, |delegation, _is_new_delegation| {
1575 Self::ensure_all_schema_ids_are_valid(&schema_ids)?;
1576
1577 let mut revoke_ids: Vec<SchemaId> = Vec::new();
1579 let mut update_ids: Vec<SchemaId> = Vec::new();
1580 let mut insert_ids: Vec<SchemaId> = Vec::new();
1581
1582 let existing_keys = delegation.schema_permissions.keys();
1583
1584 for existing_schema_id in existing_keys {
1585 if !schema_ids.contains(existing_schema_id) {
1586 if let Some(block) = delegation.schema_permissions.get(existing_schema_id) {
1587 if *block == BlockNumberFor::<T>::zero() {
1588 revoke_ids.push(*existing_schema_id);
1589 }
1590 }
1591 }
1592 }
1593 for schema_id in &schema_ids {
1594 if !delegation.schema_permissions.contains_key(schema_id) {
1595 insert_ids.push(*schema_id);
1596 } else {
1597 update_ids.push(*schema_id);
1598 }
1599 }
1600
1601 let current_block = frame_system::Pallet::<T>::block_number();
1602
1603 PermittedDelegationSchemas::<T>::try_get_mut_schemas(
1605 delegation,
1606 revoke_ids,
1607 current_block,
1608 )?;
1609
1610 PermittedDelegationSchemas::<T>::try_get_mut_schemas(
1612 delegation,
1613 update_ids,
1614 BlockNumberFor::<T>::zero(),
1615 )?;
1616
1617 PermittedDelegationSchemas::<T>::try_insert_schemas(delegation, insert_ids)?;
1619 delegation.revoked_at = BlockNumberFor::<T>::zero();
1620 Ok(())
1621 })
1622 }
1623
1624 pub fn create_provider_for(
1632 provider_msa_id: MessageSourceId,
1633 provider_name: Vec<u8>,
1634 ) -> DispatchResult {
1635 let bounded_name: BoundedVec<u8, T::MaxProviderNameSize> =
1636 provider_name.try_into().map_err(|_| Error::<T>::ExceedsMaxProviderNameSize)?;
1637
1638 ProviderToRegistryEntry::<T>::try_mutate(
1639 ProviderId(provider_msa_id),
1640 |maybe_metadata| -> DispatchResult {
1641 ensure!(
1642 maybe_metadata.take().is_none(),
1643 Error::<T>::DuplicateProviderRegistryEntry
1644 );
1645 *maybe_metadata = Some(ProviderRegistryEntry { provider_name: bounded_name });
1646 Ok(())
1647 },
1648 )?;
1649 Ok(())
1650 }
1651
1652 pub fn try_mutate_delegation<R, E: From<DispatchError>>(
1656 delegator_id: DelegatorId,
1657 provider_id: ProviderId,
1658 f: impl FnOnce(
1659 &mut Delegation<SchemaId, BlockNumberFor<T>, T::MaxSchemaGrantsPerDelegation>,
1660 bool,
1661 ) -> Result<R, E>,
1662 ) -> Result<R, E> {
1663 DelegatorAndProviderToDelegation::<T>::try_mutate_exists(
1664 delegator_id,
1665 provider_id,
1666 |maybe_delegation_info| {
1667 let is_new = maybe_delegation_info.is_none();
1668 let mut delegation = maybe_delegation_info.take().unwrap_or_default();
1669
1670 let result = f(&mut delegation, is_new)?;
1671
1672 *maybe_delegation_info = Some(delegation);
1674 Ok(result)
1675 },
1676 )
1677 }
1678
1679 pub fn delete_key_for_msa(msa_id: MessageSourceId, key: &T::AccountId) -> DispatchResult {
1685 PublicKeyToMsaId::<T>::try_mutate_exists(key, |maybe_msa_id| {
1686 ensure!(maybe_msa_id.is_some(), Error::<T>::NoKeyExists);
1687
1688 *maybe_msa_id = None;
1690
1691 <PublicKeyCountForMsaId<T>>::try_mutate_exists(msa_id, |key_count| {
1692 match key_count {
1693 Some(1) => *key_count = None,
1694 Some(count) => *count = *count - 1u8,
1695 None => (),
1696 }
1697
1698 Ok(())
1699 })
1700 })
1701 }
1702
1703 pub fn revoke_provider(provider_id: ProviderId, delegator_id: DelegatorId) -> DispatchResult {
1710 DelegatorAndProviderToDelegation::<T>::try_mutate_exists(
1711 delegator_id,
1712 provider_id,
1713 |maybe_info| -> DispatchResult {
1714 let mut info = maybe_info.take().ok_or(Error::<T>::DelegationNotFound)?;
1715
1716 ensure!(
1717 info.revoked_at == BlockNumberFor::<T>::default(),
1718 Error::<T>::DelegationRevoked
1719 );
1720
1721 let current_block = frame_system::Pallet::<T>::block_number();
1722 info.revoked_at = current_block;
1723 *maybe_info = Some(info);
1724 Ok(())
1725 },
1726 )?;
1727
1728 Ok(())
1729 }
1730
1731 pub fn get_owner_of(key: &T::AccountId) -> Option<MessageSourceId> {
1733 PublicKeyToMsaId::<T>::get(key)
1734 }
1735
1736 pub fn ensure_valid_msa_key(key: &T::AccountId) -> Result<MessageSourceId, DispatchError> {
1738 let msa_id = PublicKeyToMsaId::<T>::get(key).ok_or(Error::<T>::NoKeyExists)?;
1739 Ok(msa_id)
1740 }
1741
1742 pub fn get_granted_schemas_by_msa_id(
1749 delegator: DelegatorId,
1750 provider: Option<ProviderId>,
1751 ) -> Result<Vec<DelegationResponse<SchemaId, BlockNumberFor<T>>>, DispatchError> {
1752 let delegations = match provider {
1753 Some(provider_id) => vec![(
1754 provider_id,
1755 Self::get_delegation_of(delegator, provider_id)
1756 .ok_or(Error::<T>::DelegationNotFound)?,
1757 )],
1758 None => DelegatorAndProviderToDelegation::<T>::iter_prefix(delegator).collect(),
1759 };
1760
1761 let mut result = vec![];
1762 for (provider_id, provider_info) in delegations {
1763 let schema_permissions = provider_info.schema_permissions;
1764 if provider.is_some() && schema_permissions.is_empty() {
1766 return Err(Error::<T>::SchemaNotGranted.into());
1767 }
1768
1769 let mut schema_list = Vec::new();
1770 for (schema_id, revoked_at) in schema_permissions {
1771 if provider_info.revoked_at > BlockNumberFor::<T>::zero() &&
1772 (revoked_at > provider_info.revoked_at ||
1773 revoked_at == BlockNumberFor::<T>::zero())
1774 {
1775 schema_list
1776 .push(SchemaGrant { schema_id, revoked_at: provider_info.revoked_at });
1777 } else {
1778 schema_list.push(SchemaGrant { schema_id, revoked_at });
1779 }
1780 }
1781
1782 result.push(DelegationResponse { provider_id, permissions: schema_list });
1783 }
1784
1785 Ok(result)
1786 }
1787
1788 pub fn msa_id_to_eth_address(id: MessageSourceId) -> H160 {
1794 const DOMAIN_PREFIX: u8 = 0xD9;
1798
1799 lazy_static! {
1800 static ref MSA_ADDRESS_SALT: [u8; 32] = keccak_256(b"MSA Generated");
1802 }
1803 let input_value = id.to_be_bytes();
1804
1805 let mut hash_input = [0u8; 41];
1806 hash_input[0] = DOMAIN_PREFIX;
1807 hash_input[1..9].copy_from_slice(&input_value);
1808 hash_input[9..].copy_from_slice(&(*MSA_ADDRESS_SALT));
1809
1810 let hash = keccak_256(&hash_input);
1811 H160::from_slice(&hash[12..])
1812 }
1813
1814 pub fn validate_eth_address_for_msa(address: &H160, msa_id: MessageSourceId) -> bool {
1816 let generated_address = Self::msa_id_to_eth_address(msa_id);
1817 *address == generated_address
1818 }
1819
1820 pub fn eth_address_to_checksummed_string(address: &H160) -> alloc::string::String {
1824 let addr_bytes = address.0;
1825 let addr_hex = hex::encode(addr_bytes);
1826 let hash = keccak_256(addr_hex.as_bytes());
1827
1828 let mut result = alloc::string::String::with_capacity(42);
1829 result.push_str("0x");
1830
1831 for (i, c) in addr_hex.chars().enumerate() {
1832 let hash_byte = hash[i / 2];
1833 let bit = if i % 2 == 0 { (hash_byte >> 4) & 0xf } else { hash_byte & 0xf };
1834
1835 result.push(if c.is_ascii_hexdigit() && c.is_ascii_alphabetic() {
1836 if bit >= 8 {
1837 c.to_ascii_uppercase()
1838 } else {
1839 c
1840 }
1841 } else {
1842 c
1843 });
1844 }
1845
1846 result
1847 }
1848
1849 pub fn register_signature(
1861 signature: &MultiSignature,
1862 signature_expires_at: BlockNumberFor<T>,
1863 ) -> DispatchResult {
1864 let current_block =
1865 Self::check_signature_against_registry(signature, signature_expires_at)?;
1866
1867 Self::enqueue_signature(signature, signature_expires_at, current_block)
1868 }
1869
1870 pub fn check_signature_against_registry(
1879 signature: &MultiSignature,
1880 signature_expires_at: BlockNumberFor<T>,
1881 ) -> Result<BlockNumberFor<T>, DispatchError> {
1882 let current_block: BlockNumberFor<T> = frame_system::Pallet::<T>::block_number();
1883
1884 let max_lifetime = Self::mortality_block_limit(current_block);
1885 ensure!(max_lifetime > signature_expires_at, Error::<T>::ProofNotYetValid);
1886 ensure!(current_block < signature_expires_at, Error::<T>::ProofHasExpired);
1887
1888 ensure!(
1890 !<PayloadSignatureRegistryList<T>>::contains_key(signature),
1891 Error::<T>::SignatureAlreadySubmitted
1892 );
1893 if let Some(signature_pointer) = PayloadSignatureRegistryPointer::<T>::get() {
1894 ensure!(signature_pointer.newest != *signature, Error::<T>::SignatureAlreadySubmitted);
1895 }
1896
1897 Ok(current_block)
1898 }
1899
1900 fn enqueue_signature(
1923 signature: &MultiSignature,
1924 signature_expires_at: BlockNumberFor<T>,
1925 current_block: BlockNumberFor<T>,
1926 ) -> DispatchResult {
1927 let pointer =
1929 PayloadSignatureRegistryPointer::<T>::get().unwrap_or(SignatureRegistryPointer {
1930 newest: signature.clone(),
1931 newest_expires_at: signature_expires_at,
1932 oldest: signature.clone(),
1933 count: 0,
1934 });
1935
1936 ensure!(
1938 !(pointer.count != 0 && pointer.newest.eq(signature)),
1939 Error::<T>::SignatureAlreadySubmitted
1940 );
1941
1942 let mut oldest: MultiSignature = pointer.oldest.clone();
1944
1945 let is_registry_full: bool = pointer.count == T::MaxSignaturesStored::get().unwrap_or(0);
1947
1948 if is_registry_full {
1950 let (expire_block_number, next_oldest) =
1951 PayloadSignatureRegistryList::<T>::get(pointer.oldest.clone())
1952 .ok_or(Error::<T>::SignatureRegistryCorrupted)?;
1953
1954 ensure!(
1955 current_block.gt(&expire_block_number),
1956 Error::<T>::SignatureRegistryLimitExceeded
1957 );
1958
1959 oldest = next_oldest.clone();
1961
1962 <PayloadSignatureRegistryList<T>>::remove(pointer.oldest);
1963 }
1964
1965 if pointer.count != 0 {
1967 <PayloadSignatureRegistryList<T>>::insert(
1968 pointer.newest,
1969 (pointer.newest_expires_at, signature.clone()),
1970 );
1971 }
1972
1973 PayloadSignatureRegistryPointer::<T>::put(SignatureRegistryPointer {
1975 count: if is_registry_full { pointer.count } else { pointer.count + 1 },
1977 newest: signature.clone(),
1978 newest_expires_at: signature_expires_at,
1979 oldest,
1980 });
1981
1982 Ok(())
1983 }
1984
1985 fn mortality_block_limit(current_block: BlockNumberFor<T>) -> BlockNumberFor<T> {
1989 let mortality_size = T::MortalityWindowSize::get();
1990 current_block + BlockNumberFor::<T>::from(mortality_size)
1991 }
1992}
1993
1994#[cfg(feature = "runtime-benchmarks")]
1995impl<T: Config> MsaBenchmarkHelper<T::AccountId> for Pallet<T> {
1996 fn set_delegation_relationship(
1998 provider: ProviderId,
1999 delegator: DelegatorId,
2000 schemas: Vec<SchemaId>,
2001 ) -> DispatchResult {
2002 Self::add_provider(provider, delegator, schemas)?;
2003 Ok(())
2004 }
2005
2006 fn add_key(msa_id: MessageSourceId, key: T::AccountId) -> DispatchResult {
2008 Self::add_key(msa_id, &key, EMPTY_FUNCTION)?;
2009 Ok(())
2010 }
2011}
2012
2013#[cfg(feature = "runtime-benchmarks")]
2014impl<T: Config> RegisterProviderBenchmarkHelper for Pallet<T> {
2015 fn create(provider_id: MessageSourceId, name: Vec<u8>) -> DispatchResult {
2017 let name = BoundedVec::<u8, T::MaxProviderNameSize>::try_from(name).expect("error");
2018 Self::create_registered_provider(provider_id.into(), name)?;
2019
2020 Ok(())
2021 }
2022}
2023
2024impl<T: Config> MsaLookup for Pallet<T> {
2025 type AccountId = T::AccountId;
2026
2027 fn get_msa_id(key: &Self::AccountId) -> Option<MessageSourceId> {
2028 Self::get_owner_of(key)
2029 }
2030}
2031
2032impl<T: Config> MsaValidator for Pallet<T> {
2033 type AccountId = T::AccountId;
2034
2035 fn ensure_valid_msa_key(key: &T::AccountId) -> Result<MessageSourceId, DispatchError> {
2036 Self::ensure_valid_msa_key(key)
2037 }
2038}
2039
2040impl<T: Config> ProviderLookup for Pallet<T> {
2041 type BlockNumber = BlockNumberFor<T>;
2042 type MaxSchemaGrantsPerDelegation = T::MaxSchemaGrantsPerDelegation;
2043 type SchemaId = SchemaId;
2044
2045 fn get_delegation_of(
2046 delegator: DelegatorId,
2047 provider: ProviderId,
2048 ) -> Option<Delegation<SchemaId, Self::BlockNumber, Self::MaxSchemaGrantsPerDelegation>> {
2049 DelegatorAndProviderToDelegation::<T>::get(delegator, provider)
2050 }
2051}
2052
2053impl<T: Config> DelegationValidator for Pallet<T> {
2054 type BlockNumber = BlockNumberFor<T>;
2055 type MaxSchemaGrantsPerDelegation = T::MaxSchemaGrantsPerDelegation;
2056 type SchemaId = SchemaId;
2057
2058 fn ensure_valid_delegation(
2068 provider_id: ProviderId,
2069 delegator_id: DelegatorId,
2070 block_number: Option<BlockNumberFor<T>>,
2071 ) -> Result<
2072 Delegation<SchemaId, BlockNumberFor<T>, T::MaxSchemaGrantsPerDelegation>,
2073 DispatchError,
2074 > {
2075 let info = DelegatorAndProviderToDelegation::<T>::get(delegator_id, provider_id)
2076 .ok_or(Error::<T>::DelegationNotFound)?;
2077 let current_block = frame_system::Pallet::<T>::block_number();
2078 let requested_block = match block_number {
2079 Some(block_number) => {
2080 ensure!(
2081 current_block >= block_number,
2082 Error::<T>::CannotPredictValidityPastCurrentBlock
2083 );
2084 block_number
2085 },
2086 None => current_block,
2087 };
2088
2089 if info.revoked_at == BlockNumberFor::<T>::zero() {
2090 return Ok(info);
2091 }
2092 ensure!(info.revoked_at >= requested_block, Error::<T>::DelegationRevoked);
2093
2094 Ok(info)
2095 }
2096}
2097
2098impl<T: Config> TargetValidator for Pallet<T> {
2099 fn validate(target: MessageSourceId) -> bool {
2100 Self::is_registered_provider(target)
2101 }
2102}
2103
2104impl<T: Config> SchemaGrantValidator<BlockNumberFor<T>> for Pallet<T> {
2105 fn ensure_valid_schema_grant(
2114 provider: ProviderId,
2115 delegator: DelegatorId,
2116 schema_id: SchemaId,
2117 block_number: BlockNumberFor<T>,
2118 ) -> DispatchResult {
2119 let provider_info = Self::ensure_valid_delegation(provider, delegator, Some(block_number))?;
2120
2121 let schema_permission_revoked_at_block_number = provider_info
2122 .schema_permissions
2123 .get(&schema_id)
2124 .ok_or(Error::<T>::SchemaNotGranted)?;
2125
2126 if *schema_permission_revoked_at_block_number == BlockNumberFor::<T>::zero() {
2127 return Ok(());
2128 }
2129
2130 ensure!(
2131 block_number <= *schema_permission_revoked_at_block_number,
2132 Error::<T>::SchemaNotGranted
2133 );
2134
2135 Ok(())
2136 }
2137}
2138
2139impl<T: Config> MsaKeyProvider for Pallet<T> {
2140 type AccountId = T::AccountId;
2141 fn key_eligible_for_subsidized_addition(
2147 old_key: Self::AccountId,
2148 new_key: Self::AccountId,
2149 msa_id: MessageSourceId,
2150 ) -> bool {
2151 let new_address32 = T::ConvertIntoAccountId32::convert((new_key).clone());
2152 if EthereumAddressMapper::is_ethereum_address(&new_address32) {
2153 if let Some(stored_msa_id) = Self::get_msa_id(&old_key) {
2154 return stored_msa_id == msa_id && PublicKeyCountForMsaId::<T>::get(msa_id).eq(&1u8);
2155 }
2156 }
2157 false
2158 }
2159}
2160
2161#[derive(Encode, Decode, DecodeWithMemTracking, Clone, Eq, PartialEq, TypeInfo)]
2166#[scale_info(skip_type_params(T))]
2167pub struct CheckFreeExtrinsicUse<T: Config + Send + Sync>(PhantomData<T>);
2168
2169impl<T: Config + Send + Sync> CheckFreeExtrinsicUse<T> {
2170 pub fn validate_delegation_by_delegator(
2181 account_id: &T::AccountId,
2182 provider_msa_id: &MessageSourceId,
2183 ) -> TransactionValidity {
2184 const TAG_PREFIX: &str = "DelegatorDelegationRevocation";
2185 let delegator_msa_id: DelegatorId = Pallet::<T>::ensure_valid_msa_key(account_id)
2186 .map_err(|_| InvalidTransaction::Custom(ValidityError::InvalidMsaKey as u8))?
2187 .into();
2188 let provider_msa_id = ProviderId(*provider_msa_id);
2189
2190 Pallet::<T>::ensure_valid_delegation(provider_msa_id, delegator_msa_id, None)
2191 .map_err(|_| InvalidTransaction::Custom(ValidityError::InvalidDelegation as u8))?;
2192 ValidTransaction::with_tag_prefix(TAG_PREFIX).and_provides(account_id).build()
2193 }
2194
2195 pub fn validate_delegation_by_provider(
2206 account_id: &T::AccountId,
2207 delegator_msa_id: &MessageSourceId,
2208 ) -> TransactionValidity {
2209 const TAG_PREFIX: &str = "ProviderDelegationRevocation";
2210
2211 let provider_msa_id: ProviderId = Pallet::<T>::ensure_valid_msa_key(account_id)
2212 .map_err(|_| InvalidTransaction::Custom(ValidityError::InvalidMsaKey as u8))?
2213 .into();
2214 let delegator_msa_id = DelegatorId(*delegator_msa_id);
2215
2216 Pallet::<T>::ensure_valid_delegation(provider_msa_id, delegator_msa_id, None)
2218 .map_err(|_| InvalidTransaction::Custom(ValidityError::InvalidDelegation as u8))?;
2219 ValidTransaction::with_tag_prefix(TAG_PREFIX).and_provides(account_id).build()
2220 }
2221
2222 pub fn validate_key_delete(
2235 signing_public_key: &T::AccountId,
2236 public_key_to_delete: &T::AccountId,
2237 ) -> TransactionValidity {
2238 const TAG_PREFIX: &str = "KeyRevocation";
2239
2240 ensure!(
2241 signing_public_key != public_key_to_delete,
2242 InvalidTransaction::Custom(ValidityError::InvalidSelfRemoval as u8)
2243 );
2244
2245 let maybe_owner_msa_id: MessageSourceId =
2246 Pallet::<T>::ensure_valid_msa_key(signing_public_key)
2247 .map_err(|_| InvalidTransaction::Custom(ValidityError::InvalidMsaKey as u8))?;
2248
2249 let msa_id_for_key_to_delete: MessageSourceId =
2250 Pallet::<T>::ensure_valid_msa_key(public_key_to_delete)
2251 .map_err(|_| InvalidTransaction::Custom(ValidityError::InvalidMsaKey as u8))?;
2252
2253 ensure!(
2254 maybe_owner_msa_id == msa_id_for_key_to_delete,
2255 InvalidTransaction::Custom(ValidityError::NotKeyOwner as u8)
2256 );
2257
2258 ValidTransaction::with_tag_prefix(TAG_PREFIX)
2259 .and_provides(signing_public_key)
2260 .build()
2261 }
2262
2263 pub fn ensure_msa_can_retire(account_id: &T::AccountId) -> TransactionValidity {
2279 const TAG_PREFIX: &str = "MSARetirement";
2280 let msa_id = Pallet::<T>::ensure_valid_msa_key(account_id)
2281 .map_err(|_| InvalidTransaction::Custom(ValidityError::InvalidMsaKey as u8))?;
2282
2283 ensure!(
2284 !Pallet::<T>::is_registered_provider(msa_id),
2285 InvalidTransaction::Custom(
2286 ValidityError::InvalidRegisteredProviderCannotBeRetired as u8
2287 )
2288 );
2289
2290 let msa_handle = T::HandleProvider::get_handle_for_msa(msa_id);
2291 ensure!(
2292 msa_handle.is_none(),
2293 InvalidTransaction::Custom(ValidityError::HandleNotRetired as u8)
2294 );
2295
2296 let key_count = PublicKeyCountForMsaId::<T>::get(msa_id);
2297 ensure!(
2298 key_count == 1,
2299 InvalidTransaction::Custom(ValidityError::InvalidMoreThanOneKeyExists as u8)
2300 );
2301
2302 let delegator_id = DelegatorId(msa_id);
2303 let has_active_delegations: bool = DelegatorAndProviderToDelegation::<T>::iter_key_prefix(
2304 delegator_id,
2305 )
2306 .any(|provider_id| {
2307 Pallet::<T>::ensure_valid_delegation(provider_id, delegator_id, None).is_ok()
2308 });
2309
2310 ensure!(
2311 !has_active_delegations,
2312 InvalidTransaction::Custom(ValidityError::InvalidNonZeroProviderDelegations as u8)
2313 );
2314
2315 let msa_address = Pallet::<T>::msa_id_to_eth_address(msa_id);
2317
2318 let mut bytes = &EthereumAddressMapper::to_bytes32(&msa_address.0)[..];
2320 let msa_account_id = T::AccountId::decode(&mut bytes).map_err(|_| {
2321 log::error!("Failed to decode MSA account ID from Ethereum address");
2322 InvalidTransaction::Custom(ValidityError::InvalidMsaKey as u8)
2323 })?;
2324
2325 let msa_balance = T::Currency::reducible_balance(
2327 &msa_account_id,
2328 Preservation::Expendable,
2329 Fortitude::Polite,
2330 );
2331 ensure!(
2332 msa_balance == Zero::zero(),
2333 InvalidTransaction::Custom(ValidityError::InvalidMsaHoldingTokenCannotBeRetired as u8)
2334 );
2335
2336 ValidTransaction::with_tag_prefix(TAG_PREFIX).and_provides(account_id).build()
2337 }
2338
2339 pub fn validate_msa_token_withdrawal(
2354 receiver_account_id: &T::AccountId,
2355 msa_owner_public_key: &T::AccountId,
2356 msa_owner_proof: &MultiSignature,
2357 authorization_payload: &AuthorizedKeyData<T>,
2358 ) -> TransactionValidity {
2359 const TAG_PREFIX: &str = "MsaTokenWithdrawal";
2360
2361 ensure!(
2362 *receiver_account_id == authorization_payload.authorized_public_key,
2363 InvalidTransaction::Custom(ValidityError::NotKeyOwner as u8)
2364 );
2365
2366 ensure!(
2367 authorization_payload.discriminant == PayloadTypeDiscriminator::AuthorizedKeyData,
2368 InvalidTransaction::Custom(ValidityError::MsaOwnershipInvalidSignature as u8)
2369 );
2370 ensure!(
2371 Pallet::<T>::verify_signature(
2372 msa_owner_proof,
2373 msa_owner_public_key,
2374 authorization_payload
2375 ),
2376 InvalidTransaction::Custom(ValidityError::MsaOwnershipInvalidSignature as u8)
2377 );
2378
2379 ensure!(
2381 !PublicKeyToMsaId::<T>::contains_key(receiver_account_id),
2382 InvalidTransaction::Custom(ValidityError::IneligibleOrigin as u8)
2383 );
2384
2385 Pallet::<T>::check_signature_against_registry(
2386 msa_owner_proof,
2387 authorization_payload.expiration,
2388 )
2389 .map_err(|_| {
2390 InvalidTransaction::Custom(ValidityError::MsaOwnershipInvalidSignature as u8)
2391 })?;
2392
2393 let msa_id = authorization_payload.msa_id;
2394
2395 Pallet::<T>::ensure_msa_owner(msa_owner_public_key, msa_id)
2396 .map_err(|_| InvalidTransaction::Custom(ValidityError::InvalidMsaKey as u8))?;
2397
2398 let msa_address = Pallet::<T>::msa_id_to_eth_address(msa_id);
2400
2401 let mut bytes = &EthereumAddressMapper::to_bytes32(&msa_address.0)[..];
2403 let msa_account_id = T::AccountId::decode(&mut bytes).map_err(|_| {
2404 log::error!("Failed to decode MSA account ID from Ethereum address");
2405 InvalidTransaction::Custom(ValidityError::InvalidMsaKey as u8)
2406 })?;
2407
2408 let msa_balance = T::Currency::reducible_balance(
2410 &msa_account_id,
2411 Preservation::Expendable,
2412 Fortitude::Polite,
2413 );
2414 ensure!(
2415 msa_balance > Zero::zero(),
2416 InvalidTransaction::Custom(ValidityError::InsufficientBalanceToWithdraw as u8)
2417 );
2418 ValidTransaction::with_tag_prefix(TAG_PREFIX)
2419 .and_provides(receiver_account_id)
2420 .build()
2421 }
2422}
2423
2424pub enum ValidityError {
2426 InvalidDelegation,
2428 InvalidMsaKey,
2430 InvalidRegisteredProviderCannotBeRetired,
2432 InvalidMoreThanOneKeyExists,
2434 InvalidSelfRemoval,
2436 NotKeyOwner,
2438 InvalidNonZeroProviderDelegations,
2440 HandleNotRetired,
2442 MsaOwnershipInvalidSignature,
2444 InsufficientBalanceToWithdraw,
2446 IneligibleOrigin,
2448 InvalidMsaHoldingTokenCannotBeRetired,
2450}
2451
2452impl<T: Config + Send + Sync> CheckFreeExtrinsicUse<T> {
2453 pub fn new() -> Self {
2455 Self(PhantomData)
2456 }
2457}
2458
2459impl<T: Config + Send + Sync> core::fmt::Debug for CheckFreeExtrinsicUse<T> {
2460 #[cfg(feature = "std")]
2461 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
2462 write!(f, "CheckFreeExtrinsicUse<{:?}>", self.0)
2463 }
2464 #[cfg(not(feature = "std"))]
2465 fn fmt(&self, _: &mut core::fmt::Formatter) -> core::fmt::Result {
2466 Ok(())
2467 }
2468}
2469
2470#[derive(RuntimeDebugNoBound)]
2472pub enum Val {
2473 Valid,
2475 Refund(Weight),
2477}
2478
2479#[derive(RuntimeDebugNoBound)]
2481pub enum Pre {
2482 Valid,
2484 Refund(Weight),
2486}
2487
2488impl<T: Config + Send + Sync> TransactionExtension<T::RuntimeCall> for CheckFreeExtrinsicUse<T>
2489where
2490 T::RuntimeCall: Dispatchable<Info = DispatchInfo> + IsSubType<Call<T>>,
2491 <T as frame_system::Config>::RuntimeOrigin: AsSystemOriginSigner<T::AccountId> + Clone,
2492{
2493 const IDENTIFIER: &'static str = "CheckFreeExtrinsicUse";
2494 type Implicit = ();
2495 type Val = Val;
2496 type Pre = Pre;
2497
2498 fn weight(&self, call: &T::RuntimeCall) -> Weight {
2499 match call.is_sub_type() {
2500 Some(Call::revoke_delegation_by_provider { .. }) =>
2501 T::WeightInfo::check_free_extrinsic_use_revoke_delegation_by_provider(),
2502 Some(Call::revoke_delegation_by_delegator { .. }) =>
2503 T::WeightInfo::check_free_extrinsic_use_revoke_delegation_by_delegator(),
2504 Some(Call::delete_msa_public_key { .. }) =>
2505 T::WeightInfo::check_free_extrinsic_use_delete_msa_public_key(),
2506 Some(Call::retire_msa { .. }) => T::WeightInfo::check_free_extrinsic_use_retire_msa(),
2507 Some(Call::withdraw_tokens { .. }) =>
2508 T::WeightInfo::check_free_extrinsic_use_withdraw_tokens(),
2509 _ => Weight::zero(),
2510 }
2511 }
2512
2513 fn validate(
2514 &self,
2515 origin: <T as frame_system::Config>::RuntimeOrigin,
2516 call: &T::RuntimeCall,
2517 _info: &DispatchInfoOf<T::RuntimeCall>,
2518 _len: usize,
2519 _self_implicit: Self::Implicit,
2520 _inherited_implication: &impl Encode,
2521 _source: TransactionSource,
2522 ) -> ValidateResult<Self::Val, T::RuntimeCall> {
2523 let weight = self.weight(call);
2524 let Some(who) = origin.as_system_origin_signer() else {
2525 return Ok((ValidTransaction::default(), Val::Refund(weight), origin));
2526 };
2527 let validity = match call.is_sub_type() {
2528 Some(Call::revoke_delegation_by_provider { delegator, .. }) =>
2529 Self::validate_delegation_by_provider(who, delegator),
2530 Some(Call::revoke_delegation_by_delegator { provider_msa_id, .. }) =>
2531 Self::validate_delegation_by_delegator(who, provider_msa_id),
2532 Some(Call::delete_msa_public_key { public_key_to_delete, .. }) =>
2533 Self::validate_key_delete(who, public_key_to_delete),
2534 Some(Call::retire_msa { .. }) => Self::ensure_msa_can_retire(who),
2535 Some(Call::withdraw_tokens {
2536 msa_owner_public_key,
2537 msa_owner_proof,
2538 authorization_payload,
2539 }) => Self::validate_msa_token_withdrawal(
2540 who,
2541 msa_owner_public_key,
2542 msa_owner_proof,
2543 authorization_payload,
2544 ),
2545 _ => Ok(Default::default()),
2546 };
2547 validity.map(|v| (v, Val::Valid, origin))
2548 }
2549
2550 fn prepare(
2551 self,
2552 val: Self::Val,
2553 _origin: &<T as frame_system::Config>::RuntimeOrigin,
2554 _call: &T::RuntimeCall,
2555 _info: &DispatchInfoOf<T::RuntimeCall>,
2556 _len: usize,
2557 ) -> Result<Self::Pre, TransactionValidityError> {
2558 match val {
2559 Val::Valid => Ok(Pre::Valid),
2560 Val::Refund(w) => Ok(Pre::Refund(w)),
2561 }
2562 }
2563
2564 fn post_dispatch_details(
2565 pre: Self::Pre,
2566 _info: &DispatchInfo,
2567 _post_info: &PostDispatchInfoOf<T::RuntimeCall>,
2568 _len: usize,
2569 _result: &sp_runtime::DispatchResult,
2570 ) -> Result<Weight, TransactionValidityError> {
2571 match pre {
2572 Pre::Valid => Ok(Weight::zero()),
2573 Pre::Refund(w) => Ok(w),
2574 }
2575 }
2576}