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,
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) = Self::create_account(public_key)?;
509
510 let event = Event::MsaCreated { msa_id: new_msa_id, key: new_public_key };
511 offchain_index_event::<T>(Some(&event), new_msa_id);
512 Self::deposit_event(event);
513 Ok(())
514 }
515
516 #[pallet::call_index(1)]
538 #[pallet::weight(T::WeightInfo::create_sponsored_account_with_delegation(
539 add_provider_payload.schema_ids.len() as u32
540 ))]
541 pub fn create_sponsored_account_with_delegation(
542 origin: OriginFor<T>,
543 delegator_key: T::AccountId,
544 proof: MultiSignature,
545 add_provider_payload: AddProvider,
546 ) -> DispatchResult {
547 let provider_key = ensure_signed(origin)?;
548
549 ensure!(
550 Self::verify_signature(&proof, &delegator_key, &add_provider_payload),
551 Error::<T>::InvalidSignature
552 );
553
554 Self::register_signature(&proof, add_provider_payload.expiration.into())?;
555
556 let provider_msa_id = Self::ensure_valid_msa_key(&provider_key)?;
557 ensure!(
558 add_provider_payload.authorized_msa_id == provider_msa_id,
559 Error::<T>::UnauthorizedProvider
560 );
561
562 ensure!(
564 Self::is_registered_provider(provider_msa_id),
565 Error::<T>::ProviderNotRegistered
566 );
567
568 let (new_delegator_msa_id, new_delegator_public_key) =
569 Self::create_account(delegator_key)?;
570 Self::add_provider(
571 ProviderId(provider_msa_id),
572 DelegatorId(new_delegator_msa_id),
573 add_provider_payload.schema_ids,
574 )?;
575 let event =
576 Event::MsaCreated { msa_id: new_delegator_msa_id, key: new_delegator_public_key };
577 offchain_index_event::<T>(Some(&event), new_delegator_msa_id);
578 Self::deposit_event(event);
579 Self::deposit_event(Event::DelegationGranted {
580 delegator_id: DelegatorId(new_delegator_msa_id),
581 provider_id: ProviderId(provider_msa_id),
582 });
583 Ok(())
584 }
585
586 #[pallet::call_index(2)]
598 #[pallet::weight(T::WeightInfo::create_provider())]
599 pub fn create_provider(origin: OriginFor<T>, provider_name: Vec<u8>) -> DispatchResult {
600 let provider_key = ensure_signed(origin)?;
601 let provider_msa_id = Self::ensure_valid_msa_key(&provider_key)?;
602 Self::create_provider_for(provider_msa_id, provider_name)?;
603 Self::deposit_event(Event::ProviderCreated {
604 provider_id: ProviderId(provider_msa_id),
605 });
606 Ok(())
607 }
608
609 #[pallet::call_index(3)]
630 #[pallet::weight(T::WeightInfo::grant_delegation(add_provider_payload.schema_ids.len() as u32))]
631 pub fn grant_delegation(
632 origin: OriginFor<T>,
633 delegator_key: T::AccountId,
634 proof: MultiSignature,
635 add_provider_payload: AddProvider,
636 ) -> DispatchResult {
637 let provider_key = ensure_signed(origin)?;
638
639 ensure!(
640 Self::verify_signature(&proof, &delegator_key, &add_provider_payload),
641 Error::<T>::AddProviderSignatureVerificationFailed
642 );
643
644 Self::register_signature(&proof, add_provider_payload.expiration.into())?;
645 let (provider_id, delegator_id) =
646 Self::ensure_valid_registered_provider(&delegator_key, &provider_key)?;
647
648 ensure!(
649 add_provider_payload.authorized_msa_id == provider_id.0,
650 Error::<T>::UnauthorizedDelegator
651 );
652
653 Self::upsert_schema_permissions(
654 provider_id,
655 delegator_id,
656 add_provider_payload.schema_ids,
657 )?;
658 Self::deposit_event(Event::DelegationGranted { delegator_id, provider_id });
659
660 Ok(())
661 }
662
663 #[pallet::call_index(4)]
675 #[pallet::weight((T::WeightInfo::revoke_delegation_by_delegator(), DispatchClass::Normal, Pays::No))]
676 pub fn revoke_delegation_by_delegator(
677 origin: OriginFor<T>,
678 #[pallet::compact] provider_msa_id: MessageSourceId,
679 ) -> DispatchResult {
680 let who = ensure_signed(origin)?;
681
682 match PublicKeyToMsaId::<T>::get(&who) {
683 Some(delegator_msa_id) => {
684 let delegator_id = DelegatorId(delegator_msa_id);
685 let provider_id = ProviderId(provider_msa_id);
686 Self::revoke_provider(provider_id, delegator_id)?;
687 Self::deposit_event(Event::DelegationRevoked { delegator_id, provider_id });
688 },
689 None => {
690 log::error!(
691 "TransactionExtension did not catch invalid MSA for account {who:?}, "
692 );
693 },
694 }
695
696 Ok(())
697 }
698
699 #[pallet::call_index(5)]
725 #[pallet::weight(T::WeightInfo::add_public_key_to_msa())]
726 pub fn add_public_key_to_msa(
727 origin: OriginFor<T>,
728 msa_owner_public_key: T::AccountId,
729 msa_owner_proof: MultiSignature,
730 new_key_owner_proof: MultiSignature,
731 add_key_payload: AddKeyData<T>,
732 ) -> DispatchResult {
733 let _ = ensure_signed(origin)?;
734
735 ensure!(
736 Self::verify_signature(&msa_owner_proof, &msa_owner_public_key, &add_key_payload),
737 Error::<T>::MsaOwnershipInvalidSignature
738 );
739
740 ensure!(
741 Self::verify_signature(
742 &new_key_owner_proof,
743 &add_key_payload.new_public_key,
744 &add_key_payload
745 ),
746 Error::<T>::NewKeyOwnershipInvalidSignature
747 );
748
749 Self::register_signature(&msa_owner_proof, add_key_payload.expiration)?;
750 Self::register_signature(&new_key_owner_proof, add_key_payload.expiration)?;
751
752 let msa_id = add_key_payload.msa_id;
753
754 Self::ensure_msa_owner(&msa_owner_public_key, msa_id)?;
755
756 Self::add_key(msa_id, &add_key_payload.new_public_key.clone())?;
757
758 let event =
759 Event::PublicKeyAdded { msa_id, key: add_key_payload.new_public_key.clone() };
760 offchain_index_event::<T>(Some(&event), msa_id);
761 Self::deposit_event(event);
762
763 Ok(())
764 }
765
766 #[pallet::call_index(6)]
781 #[pallet::weight((T::WeightInfo::delete_msa_public_key(), DispatchClass::Normal, Pays::No))]
782 pub fn delete_msa_public_key(
783 origin: OriginFor<T>,
784 public_key_to_delete: T::AccountId,
785 ) -> DispatchResult {
786 let who = ensure_signed(origin)?;
787
788 match PublicKeyToMsaId::<T>::get(&who) {
789 Some(who_msa_id) => {
790 Self::delete_key_for_msa(who_msa_id, &public_key_to_delete)?;
791
792 let event = Event::PublicKeyDeleted { key: public_key_to_delete };
794 offchain_index_event::<T>(Some(&event), who_msa_id);
795 Self::deposit_event(event);
796 },
797 None => {
798 log::error!(
799 "TransactionExtension did not catch invalid MSA for account {who:?}"
800 );
801 },
802 }
803 Ok(())
804 }
805
806 #[pallet::call_index(7)]
818 #[pallet::weight((T::WeightInfo::revoke_delegation_by_provider(), DispatchClass::Normal, Pays::No))]
819 pub fn revoke_delegation_by_provider(
820 origin: OriginFor<T>,
821 #[pallet::compact] delegator: MessageSourceId,
822 ) -> DispatchResult {
823 let who = ensure_signed(origin)?;
824
825 match PublicKeyToMsaId::<T>::get(&who) {
829 Some(msa_id) => {
830 let provider_id = ProviderId(msa_id);
831 let delegator_id = DelegatorId(delegator);
832 Self::revoke_provider(provider_id, delegator_id)?;
833 Self::deposit_event(Event::DelegationRevoked { provider_id, delegator_id })
834 },
835 None => {
836 log::error!(
837 "TransactionExtension did not catch invalid MSA for account {who:?}"
838 );
839 },
840 }
841
842 Ok(())
843 }
844
845 #[pallet::call_index(10)]
867 #[pallet::weight((T::WeightInfo::retire_msa(), DispatchClass::Normal, Pays::No))]
868 pub fn retire_msa(origin: OriginFor<T>) -> DispatchResult {
869 let who = ensure_signed(origin)?;
871
872 match PublicKeyToMsaId::<T>::get(&who) {
875 Some(msa_id) => {
876 Self::delete_key_for_msa(msa_id, &who)?;
877 let event = Event::PublicKeyDeleted { key: who };
878 offchain_index_event::<T>(Some(&event), msa_id);
879 Self::deposit_event(event);
880 Self::deposit_event(Event::MsaRetired { msa_id });
881 },
882 None => {
883 log::error!(
884 "TransactionExtension did not catch invalid MSA for account {who:?}"
885 );
886 },
887 }
888 Ok(())
889 }
890
891 #[pallet::call_index(11)]
896 #[pallet::weight(T::WeightInfo::propose_to_be_provider())]
897 pub fn propose_to_be_provider(
898 origin: OriginFor<T>,
899 provider_name: Vec<u8>,
900 ) -> DispatchResult {
901 let bounded_name: BoundedVec<u8, T::MaxProviderNameSize> =
902 provider_name.try_into().map_err(|_| Error::<T>::ExceedsMaxProviderNameSize)?;
903
904 let proposer = ensure_signed(origin)?;
905 Self::ensure_valid_msa_key(&proposer)?;
906
907 let proposal: Box<T::Proposal> = Box::new(
908 (Call::<T>::create_provider_via_governance {
909 provider_key: proposer.clone(),
910 provider_name: bounded_name.into(),
911 })
912 .into(),
913 );
914 let threshold = 1;
915 T::ProposalProvider::propose(proposer, threshold, proposal)?;
916 Ok(())
917 }
918
919 #[pallet::call_index(12)]
929 #[pallet::weight(T::WeightInfo::create_provider_via_governance())]
930 pub fn create_provider_via_governance(
931 origin: OriginFor<T>,
932 provider_key: T::AccountId,
933 provider_name: Vec<u8>,
934 ) -> DispatchResult {
935 T::CreateProviderViaGovernanceOrigin::ensure_origin(origin)?;
936 let provider_msa_id = Self::ensure_valid_msa_key(&provider_key)?;
937 Self::create_provider_for(provider_msa_id, provider_name)?;
938 Self::deposit_event(Event::ProviderCreated {
939 provider_id: ProviderId(provider_msa_id),
940 });
941 Ok(())
942 }
943
944 #[pallet::call_index(13)]
946 #[pallet::weight(T::WeightInfo::reindex_offchain())]
947 pub fn reindex_offchain(
948 origin: OriginFor<T>,
949 event: OffchainReplayEvent<T>,
950 ) -> DispatchResult {
951 let _ = ensure_signed(origin)?;
952 match event {
953 OffchainReplayEvent::MsaPallet(MsaOffchainReplayEvent::KeyReIndex {
954 msa_id,
955 index_key,
956 }) => {
957 match index_key {
959 Some(key) => {
960 let event = Event::PublicKeyAdded { msa_id, key };
961 offchain_index_event::<T>(Some(&event), msa_id);
962 },
963 None => {
964 offchain_index_event::<T>(None, msa_id);
965 },
966 }
967 },
968 }
969
970 Ok(())
971 }
972
973 #[pallet::call_index(14)]
994 #[pallet::weight((T::WeightInfo::withdraw_tokens(), DispatchClass::Normal, Pays::No))]
995 pub fn withdraw_tokens(
996 origin: OriginFor<T>,
997 _msa_owner_public_key: T::AccountId,
998 msa_owner_proof: MultiSignature,
999 authorization_payload: AuthorizedKeyData<T>,
1000 ) -> DispatchResult {
1001 let public_key = ensure_signed(origin)?;
1002
1003 Self::register_signature(&msa_owner_proof, authorization_payload.expiration)?;
1004
1005 let msa_id = authorization_payload.msa_id;
1006
1007 let msa_address = Self::msa_id_to_eth_address(msa_id);
1009
1010 let mut bytes = &EthereumAddressMapper::to_bytes32(&msa_address.0)[..];
1012 let msa_account_id = T::AccountId::decode(&mut bytes).map_err(|_| {
1013 log::error!("Failed to decode MSA account ID from Ethereum address");
1014 Error::<T>::NoKeyExists
1015 })?;
1016
1017 let msa_balance = T::Currency::reducible_balance(
1019 &msa_account_id,
1020 Preservation::Expendable,
1021 Fortitude::Polite,
1022 );
1023 ensure!(msa_balance > Zero::zero(), Error::<T>::InsufficientBalanceToWithdraw);
1024
1025 let result = <T as pallet::Config>::Currency::transfer(
1027 &msa_account_id,
1028 &public_key,
1029 msa_balance,
1030 Preservation::Expendable,
1031 );
1032 ensure!(result.is_ok(), Error::<T>::UnexpectedTokenTransferError);
1033
1034 Ok(())
1035 }
1036
1037 #[pallet::call_index(15)]
1059 #[pallet::weight(T::WeightInfo::add_recovery_commitment())]
1060 pub fn add_recovery_commitment(
1061 origin: OriginFor<T>,
1062 msa_owner_key: T::AccountId,
1063 proof: MultiSignature,
1064 payload: RecoveryCommitmentPayload<T>,
1065 ) -> DispatchResult {
1066 let _origin_key = ensure_signed(origin)?;
1067
1068 ensure!(
1070 Self::verify_signature(&proof, &msa_owner_key, &payload),
1071 Error::<T>::InvalidSignature
1072 );
1073
1074 Self::register_signature(&proof, payload.expiration)?;
1076
1077 let msa_id = Self::ensure_valid_msa_key(&msa_owner_key)?;
1079
1080 MsaIdToRecoveryCommitment::<T>::insert(msa_id, payload.recovery_commitment);
1082 Self::deposit_event(Event::RecoveryCommitmentAdded {
1083 who: msa_owner_key,
1084 msa_id,
1085 recovery_commitment: payload.recovery_commitment,
1086 });
1087
1088 Ok(())
1089 }
1090
1091 #[pallet::call_index(16)]
1101 #[pallet::weight(T::WeightInfo::approve_recovery_provider())]
1102 pub fn approve_recovery_provider(
1103 origin: OriginFor<T>,
1104 provider_key: T::AccountId,
1105 ) -> DispatchResult {
1106 T::RecoveryProviderApprovalOrigin::ensure_origin(origin)?;
1107
1108 let provider_msa_id = Self::ensure_valid_msa_key(&provider_key)?;
1109 ensure!(
1110 Self::is_registered_provider(provider_msa_id),
1111 Error::<T>::ProviderNotRegistered
1112 );
1113
1114 if Self::is_approved_recovery_provider(&ProviderId(provider_msa_id)) {
1116 return Ok(());
1117 }
1118
1119 RecoveryProviders::<T>::insert(ProviderId(provider_msa_id), true);
1120
1121 Self::deposit_event(Event::RecoveryProviderApproved {
1122 provider_id: ProviderId(provider_msa_id),
1123 });
1124
1125 Ok(())
1126 }
1127
1128 #[pallet::call_index(17)]
1139 #[pallet::weight(T::WeightInfo::remove_recovery_provider())]
1140 pub fn remove_recovery_provider(
1141 origin: OriginFor<T>,
1142 provider: ProviderId,
1143 ) -> DispatchResult {
1144 T::RecoveryProviderApprovalOrigin::ensure_origin(origin)?;
1145
1146 RecoveryProviders::<T>::remove(provider);
1147 Self::deposit_event(Event::RecoveryProviderRemoved { provider_id: provider });
1148 Ok(())
1149 }
1150
1151 #[pallet::call_index(18)]
1166 #[pallet::weight(T::WeightInfo::recover_account())]
1167 pub fn recover_account(
1168 origin: OriginFor<T>,
1169 intermediary_hash_a: RecoveryHash,
1170 intermediary_hash_b: RecoveryHash,
1171 new_control_key_proof: MultiSignature,
1172 add_key_payload: AddKeyData<T>,
1173 ) -> DispatchResult {
1174 let provider_key = ensure_signed(origin)?;
1175
1176 let provider_msa_id = Self::ensure_approved_recovery_provider(&provider_key)?;
1177
1178 let recovery_commitment = Self::ensure_valid_recovery_commitment(
1179 intermediary_hash_a,
1180 intermediary_hash_b,
1181 add_key_payload.msa_id,
1182 )?;
1183
1184 Self::ensure_valid_new_key_owner(&new_control_key_proof, &add_key_payload)?;
1185
1186 Self::add_key(add_key_payload.msa_id, &add_key_payload.new_public_key.clone())?;
1187
1188 let event = Event::PublicKeyAdded {
1189 msa_id: add_key_payload.msa_id,
1190 key: add_key_payload.new_public_key.clone(),
1191 };
1192 offchain_index_event::<T>(Some(&event), add_key_payload.msa_id);
1193 Self::deposit_event(event);
1194
1195 MsaIdToRecoveryCommitment::<T>::remove(add_key_payload.msa_id);
1197
1198 Self::deposit_event(Event::AccountRecovered {
1200 msa_id: add_key_payload.msa_id,
1201 recovery_provider: ProviderId(provider_msa_id),
1202 new_control_key: add_key_payload.new_public_key.clone(),
1203 });
1204
1205 Self::deposit_event(Event::RecoveryCommitmentInvalidated {
1206 msa_id: add_key_payload.msa_id,
1207 recovery_commitment,
1208 });
1209
1210 Ok(())
1211 }
1212 }
1213}
1214
1215impl<T: Config> Pallet<T> {
1216 pub fn is_approved_recovery_provider(provider: &ProviderId) -> bool {
1224 RecoveryProviders::<T>::get(provider).unwrap_or(false)
1225 }
1226
1227 pub fn compute_recovery_commitment(
1236 intermediary_hash_a: RecoveryHash,
1237 intermediary_hash_b: RecoveryHash,
1238 ) -> RecoveryCommitment {
1239 let mut input = Vec::with_capacity(64);
1240 input.extend_from_slice(&intermediary_hash_a);
1241 input.extend_from_slice(&intermediary_hash_b);
1242 keccak_256(&input)
1243 }
1244
1245 fn ensure_approved_recovery_provider(
1257 provider_key: &T::AccountId,
1258 ) -> Result<MessageSourceId, DispatchError> {
1259 let provider_msa_id = Self::ensure_valid_msa_key(provider_key)?;
1260
1261 ensure!(
1262 Self::is_approved_recovery_provider(&ProviderId(provider_msa_id)),
1263 Error::<T>::NotAuthorizedRecoveryProvider
1264 );
1265
1266 Ok(provider_msa_id)
1267 }
1268
1269 fn ensure_valid_recovery_commitment(
1283 intermediary_hash_a: RecoveryHash,
1284 intermediary_hash_b: RecoveryHash,
1285 msa_id: MessageSourceId,
1286 ) -> Result<RecoveryCommitment, DispatchError> {
1287 let recovery_commitment: RecoveryCommitment =
1288 Self::compute_recovery_commitment(intermediary_hash_a, intermediary_hash_b);
1289
1290 let stored_commitment: RecoveryCommitment =
1291 MsaIdToRecoveryCommitment::<T>::get(msa_id).ok_or(Error::<T>::NoRecoveryCommitment)?;
1292
1293 ensure!(recovery_commitment == stored_commitment, Error::<T>::InvalidRecoveryCommitment);
1294
1295 Ok(recovery_commitment)
1296 }
1297
1298 fn ensure_valid_new_key_owner(
1308 new_control_key_proof: &MultiSignature,
1309 add_key_payload: &AddKeyData<T>,
1310 ) -> DispatchResult {
1311 ensure!(
1314 Self::verify_signature(
1315 new_control_key_proof,
1316 &add_key_payload.new_public_key,
1317 add_key_payload
1318 ),
1319 Error::<T>::NewKeyOwnershipInvalidSignature
1320 );
1321 Self::register_signature(new_control_key_proof, add_key_payload.expiration)?;
1322
1323 Ok(())
1324 }
1325
1326 pub fn create_account(
1334 key: T::AccountId,
1335 ) -> Result<(MessageSourceId, T::AccountId), DispatchError> {
1336 let next_msa_id = Self::get_next_msa_id()?;
1337 Self::add_key(next_msa_id, &key)?;
1338 let _ = Self::set_msa_identifier(next_msa_id);
1339
1340 Ok((next_msa_id, key))
1341 }
1342
1343 pub fn get_next_msa_id() -> Result<MessageSourceId, DispatchError> {
1349 let next = CurrentMsaIdentifierMaximum::<T>::get()
1350 .checked_add(1)
1351 .ok_or(Error::<T>::MsaIdOverflow)?;
1352
1353 Ok(next)
1354 }
1355
1356 pub fn set_msa_identifier(identifier: MessageSourceId) -> DispatchResult {
1358 CurrentMsaIdentifierMaximum::<T>::set(identifier);
1359
1360 Ok(())
1361 }
1362
1363 pub fn create_registered_provider(
1365 provider_id: ProviderId,
1366 name: BoundedVec<u8, T::MaxProviderNameSize>,
1367 ) -> DispatchResult {
1368 ProviderToRegistryEntry::<T>::try_mutate(provider_id, |maybe_metadata| -> DispatchResult {
1369 ensure!(maybe_metadata.take().is_none(), Error::<T>::DuplicateProviderRegistryEntry);
1370 *maybe_metadata = Some(ProviderRegistryEntry { provider_name: name });
1371 Ok(())
1372 })
1373 }
1374
1375 pub fn grant_permissions_for_schemas(
1377 delegator_id: DelegatorId,
1378 provider_id: ProviderId,
1379 schema_ids: Vec<SchemaId>,
1380 ) -> DispatchResult {
1381 Self::try_mutate_delegation(delegator_id, provider_id, |delegation, is_new_delegation| {
1382 ensure!(!is_new_delegation, Error::<T>::DelegationNotFound);
1383 Self::ensure_all_schema_ids_are_valid(&schema_ids)?;
1384
1385 PermittedDelegationSchemas::<T>::try_insert_schemas(delegation, schema_ids)?;
1386
1387 Ok(())
1388 })
1389 }
1390
1391 pub fn revoke_permissions_for_schemas(
1393 delegator_id: DelegatorId,
1394 provider_id: ProviderId,
1395 schema_ids: Vec<SchemaId>,
1396 ) -> DispatchResult {
1397 Self::try_mutate_delegation(delegator_id, provider_id, |delegation, is_new_delegation| {
1398 ensure!(!is_new_delegation, Error::<T>::DelegationNotFound);
1399 Self::ensure_all_schema_ids_are_valid(&schema_ids)?;
1400
1401 let current_block = frame_system::Pallet::<T>::block_number();
1402
1403 PermittedDelegationSchemas::<T>::try_get_mut_schemas(
1404 delegation,
1405 schema_ids,
1406 current_block,
1407 )?;
1408
1409 Ok(())
1410 })
1411 }
1412
1413 pub fn add_key(msa_id: MessageSourceId, key: &T::AccountId) -> DispatchResult {
1420 PublicKeyToMsaId::<T>::try_mutate(key, |maybe_msa_id| {
1421 ensure!(maybe_msa_id.is_none(), Error::<T>::KeyAlreadyRegistered);
1422 *maybe_msa_id = Some(msa_id);
1423
1424 <PublicKeyCountForMsaId<T>>::try_mutate(msa_id, |key_count| {
1426 let incremented_key_count =
1428 key_count.checked_add(1).ok_or(ArithmeticError::Overflow)?;
1429
1430 ensure!(
1431 incremented_key_count <= T::MaxPublicKeysPerMsa::get(),
1432 Error::<T>::KeyLimitExceeded
1433 );
1434
1435 *key_count = incremented_key_count;
1436 Ok(())
1437 })
1438 })
1439 }
1440
1441 pub fn ensure_all_schema_ids_are_valid(schema_ids: &[SchemaId]) -> DispatchResult {
1448 ensure!(
1449 schema_ids.len() <= T::MaxSchemaGrantsPerDelegation::get() as usize,
1450 Error::<T>::ExceedsMaxSchemaGrantsPerDelegation
1451 );
1452
1453 let are_schemas_valid = T::SchemaValidator::are_all_schema_ids_valid(schema_ids);
1454
1455 ensure!(are_schemas_valid, Error::<T>::InvalidSchemaId);
1456
1457 Ok(())
1458 }
1459
1460 pub fn is_registered_provider(msa_id: MessageSourceId) -> bool {
1462 ProviderToRegistryEntry::<T>::contains_key(ProviderId(msa_id))
1463 }
1464
1465 pub fn ensure_valid_registered_provider(
1475 delegator_key: &T::AccountId,
1476 provider_key: &T::AccountId,
1477 ) -> Result<(ProviderId, DelegatorId), DispatchError> {
1478 let provider_msa_id = Self::ensure_valid_msa_key(provider_key)?;
1479 let delegator_msa_id = Self::ensure_valid_msa_key(delegator_key)?;
1480
1481 ensure!(delegator_msa_id != provider_msa_id, Error::<T>::InvalidSelfProvider);
1483
1484 ensure!(Self::is_registered_provider(provider_msa_id), Error::<T>::ProviderNotRegistered);
1486
1487 Ok((provider_msa_id.into(), delegator_msa_id.into()))
1488 }
1489
1490 pub fn ensure_msa_owner(who: &T::AccountId, msa_id: MessageSourceId) -> DispatchResult {
1497 let provider_msa_id = Self::ensure_valid_msa_key(who)?;
1498 ensure!(provider_msa_id == msa_id, Error::<T>::NotMsaOwner);
1499
1500 Ok(())
1501 }
1502
1503 pub fn verify_signature<P>(
1510 signature: &MultiSignature,
1511 signer: &T::AccountId,
1512 payload: &P,
1513 ) -> bool
1514 where
1515 P: Encode + EIP712Encode,
1516 {
1517 let key = T::ConvertIntoAccountId32::convert((*signer).clone());
1518
1519 check_signature(signature, key, payload)
1520 }
1521
1522 pub fn add_provider(
1528 provider_id: ProviderId,
1529 delegator_id: DelegatorId,
1530 schema_ids: Vec<SchemaId>,
1531 ) -> DispatchResult {
1532 Self::try_mutate_delegation(delegator_id, provider_id, |delegation, is_new_delegation| {
1533 ensure!(is_new_delegation, Error::<T>::DuplicateProvider);
1534 Self::ensure_all_schema_ids_are_valid(&schema_ids)?;
1535
1536 PermittedDelegationSchemas::<T>::try_insert_schemas(delegation, schema_ids)?;
1537
1538 Ok(())
1539 })
1540 }
1541
1542 pub fn upsert_schema_permissions(
1547 provider_id: ProviderId,
1548 delegator_id: DelegatorId,
1549 schema_ids: Vec<SchemaId>,
1550 ) -> DispatchResult {
1551 Self::try_mutate_delegation(delegator_id, provider_id, |delegation, _is_new_delegation| {
1552 Self::ensure_all_schema_ids_are_valid(&schema_ids)?;
1553
1554 let mut revoke_ids: Vec<SchemaId> = Vec::new();
1556 let mut update_ids: Vec<SchemaId> = Vec::new();
1557 let mut insert_ids: Vec<SchemaId> = Vec::new();
1558
1559 let existing_keys = delegation.schema_permissions.keys();
1560
1561 for existing_schema_id in existing_keys {
1562 if !schema_ids.contains(existing_schema_id) {
1563 if let Some(block) = delegation.schema_permissions.get(existing_schema_id) {
1564 if *block == BlockNumberFor::<T>::zero() {
1565 revoke_ids.push(*existing_schema_id);
1566 }
1567 }
1568 }
1569 }
1570 for schema_id in &schema_ids {
1571 if !delegation.schema_permissions.contains_key(schema_id) {
1572 insert_ids.push(*schema_id);
1573 } else {
1574 update_ids.push(*schema_id);
1575 }
1576 }
1577
1578 let current_block = frame_system::Pallet::<T>::block_number();
1579
1580 PermittedDelegationSchemas::<T>::try_get_mut_schemas(
1582 delegation,
1583 revoke_ids,
1584 current_block,
1585 )?;
1586
1587 PermittedDelegationSchemas::<T>::try_get_mut_schemas(
1589 delegation,
1590 update_ids,
1591 BlockNumberFor::<T>::zero(),
1592 )?;
1593
1594 PermittedDelegationSchemas::<T>::try_insert_schemas(delegation, insert_ids)?;
1596 delegation.revoked_at = BlockNumberFor::<T>::zero();
1597 Ok(())
1598 })
1599 }
1600
1601 pub fn create_provider_for(
1609 provider_msa_id: MessageSourceId,
1610 provider_name: Vec<u8>,
1611 ) -> DispatchResult {
1612 let bounded_name: BoundedVec<u8, T::MaxProviderNameSize> =
1613 provider_name.try_into().map_err(|_| Error::<T>::ExceedsMaxProviderNameSize)?;
1614
1615 ProviderToRegistryEntry::<T>::try_mutate(
1616 ProviderId(provider_msa_id),
1617 |maybe_metadata| -> DispatchResult {
1618 ensure!(
1619 maybe_metadata.take().is_none(),
1620 Error::<T>::DuplicateProviderRegistryEntry
1621 );
1622 *maybe_metadata = Some(ProviderRegistryEntry { provider_name: bounded_name });
1623 Ok(())
1624 },
1625 )?;
1626 Ok(())
1627 }
1628
1629 pub fn try_mutate_delegation<R, E: From<DispatchError>>(
1633 delegator_id: DelegatorId,
1634 provider_id: ProviderId,
1635 f: impl FnOnce(
1636 &mut Delegation<SchemaId, BlockNumberFor<T>, T::MaxSchemaGrantsPerDelegation>,
1637 bool,
1638 ) -> Result<R, E>,
1639 ) -> Result<R, E> {
1640 DelegatorAndProviderToDelegation::<T>::try_mutate_exists(
1641 delegator_id,
1642 provider_id,
1643 |maybe_delegation_info| {
1644 let is_new = maybe_delegation_info.is_none();
1645 let mut delegation = maybe_delegation_info.take().unwrap_or_default();
1646
1647 let result = f(&mut delegation, is_new)?;
1648
1649 *maybe_delegation_info = Some(delegation);
1651 Ok(result)
1652 },
1653 )
1654 }
1655
1656 pub fn delete_key_for_msa(msa_id: MessageSourceId, key: &T::AccountId) -> DispatchResult {
1662 PublicKeyToMsaId::<T>::try_mutate_exists(key, |maybe_msa_id| {
1663 ensure!(maybe_msa_id.is_some(), Error::<T>::NoKeyExists);
1664
1665 *maybe_msa_id = None;
1667
1668 <PublicKeyCountForMsaId<T>>::try_mutate_exists(msa_id, |key_count| {
1669 match key_count {
1670 Some(1) => *key_count = None,
1671 Some(count) => *count = *count - 1u8,
1672 None => (),
1673 }
1674
1675 Ok(())
1676 })
1677 })
1678 }
1679
1680 pub fn revoke_provider(provider_id: ProviderId, delegator_id: DelegatorId) -> DispatchResult {
1687 DelegatorAndProviderToDelegation::<T>::try_mutate_exists(
1688 delegator_id,
1689 provider_id,
1690 |maybe_info| -> DispatchResult {
1691 let mut info = maybe_info.take().ok_or(Error::<T>::DelegationNotFound)?;
1692
1693 ensure!(
1694 info.revoked_at == BlockNumberFor::<T>::default(),
1695 Error::<T>::DelegationRevoked
1696 );
1697
1698 let current_block = frame_system::Pallet::<T>::block_number();
1699 info.revoked_at = current_block;
1700 *maybe_info = Some(info);
1701 Ok(())
1702 },
1703 )?;
1704
1705 Ok(())
1706 }
1707
1708 pub fn get_owner_of(key: &T::AccountId) -> Option<MessageSourceId> {
1710 PublicKeyToMsaId::<T>::get(key)
1711 }
1712
1713 pub fn ensure_valid_msa_key(key: &T::AccountId) -> Result<MessageSourceId, DispatchError> {
1715 let msa_id = PublicKeyToMsaId::<T>::get(key).ok_or(Error::<T>::NoKeyExists)?;
1716 Ok(msa_id)
1717 }
1718
1719 pub fn get_granted_schemas_by_msa_id(
1726 delegator: DelegatorId,
1727 provider: Option<ProviderId>,
1728 ) -> Result<Vec<DelegationResponse<SchemaId, BlockNumberFor<T>>>, DispatchError> {
1729 let delegations = match provider {
1730 Some(provider_id) => vec![(
1731 provider_id,
1732 Self::get_delegation_of(delegator, provider_id)
1733 .ok_or(Error::<T>::DelegationNotFound)?,
1734 )],
1735 None => DelegatorAndProviderToDelegation::<T>::iter_prefix(delegator).collect(),
1736 };
1737
1738 let mut result = vec![];
1739 for (provider_id, provider_info) in delegations {
1740 let schema_permissions = provider_info.schema_permissions;
1741 if provider.is_some() && schema_permissions.is_empty() {
1743 return Err(Error::<T>::SchemaNotGranted.into());
1744 }
1745
1746 let mut schema_list = Vec::new();
1747 for (schema_id, revoked_at) in schema_permissions {
1748 if provider_info.revoked_at > BlockNumberFor::<T>::zero() &&
1749 (revoked_at > provider_info.revoked_at ||
1750 revoked_at == BlockNumberFor::<T>::zero())
1751 {
1752 schema_list
1753 .push(SchemaGrant { schema_id, revoked_at: provider_info.revoked_at });
1754 } else {
1755 schema_list.push(SchemaGrant { schema_id, revoked_at });
1756 }
1757 }
1758
1759 result.push(DelegationResponse { provider_id, permissions: schema_list });
1760 }
1761
1762 Ok(result)
1763 }
1764
1765 pub fn msa_id_to_eth_address(id: MessageSourceId) -> H160 {
1771 const DOMAIN_PREFIX: u8 = 0xD9;
1775
1776 lazy_static! {
1777 static ref MSA_ADDRESS_SALT: [u8; 32] = keccak_256(b"MSA Generated");
1779 }
1780 let input_value = id.to_be_bytes();
1781
1782 let mut hash_input = [0u8; 41];
1783 hash_input[0] = DOMAIN_PREFIX;
1784 hash_input[1..9].copy_from_slice(&input_value);
1785 hash_input[9..].copy_from_slice(&(*MSA_ADDRESS_SALT));
1786
1787 let hash = keccak_256(&hash_input);
1788 H160::from_slice(&hash[12..])
1789 }
1790
1791 pub fn validate_eth_address_for_msa(address: &H160, msa_id: MessageSourceId) -> bool {
1793 let generated_address = Self::msa_id_to_eth_address(msa_id);
1794 *address == generated_address
1795 }
1796
1797 pub fn eth_address_to_checksummed_string(address: &H160) -> alloc::string::String {
1801 let addr_bytes = address.0;
1802 let addr_hex = hex::encode(addr_bytes);
1803 let hash = keccak_256(addr_hex.as_bytes());
1804
1805 let mut result = alloc::string::String::with_capacity(42);
1806 result.push_str("0x");
1807
1808 for (i, c) in addr_hex.chars().enumerate() {
1809 let hash_byte = hash[i / 2];
1810 let bit = if i % 2 == 0 { (hash_byte >> 4) & 0xf } else { hash_byte & 0xf };
1811
1812 result.push(if c.is_ascii_hexdigit() && c.is_ascii_alphabetic() {
1813 if bit >= 8 {
1814 c.to_ascii_uppercase()
1815 } else {
1816 c
1817 }
1818 } else {
1819 c
1820 });
1821 }
1822
1823 result
1824 }
1825
1826 pub fn register_signature(
1838 signature: &MultiSignature,
1839 signature_expires_at: BlockNumberFor<T>,
1840 ) -> DispatchResult {
1841 let current_block =
1842 Self::check_signature_against_registry(signature, signature_expires_at)?;
1843
1844 Self::enqueue_signature(signature, signature_expires_at, current_block)
1845 }
1846
1847 pub fn check_signature_against_registry(
1856 signature: &MultiSignature,
1857 signature_expires_at: BlockNumberFor<T>,
1858 ) -> Result<BlockNumberFor<T>, DispatchError> {
1859 let current_block: BlockNumberFor<T> = frame_system::Pallet::<T>::block_number();
1860
1861 let max_lifetime = Self::mortality_block_limit(current_block);
1862 ensure!(max_lifetime > signature_expires_at, Error::<T>::ProofNotYetValid);
1863 ensure!(current_block < signature_expires_at, Error::<T>::ProofHasExpired);
1864
1865 ensure!(
1867 !<PayloadSignatureRegistryList<T>>::contains_key(signature),
1868 Error::<T>::SignatureAlreadySubmitted
1869 );
1870 if let Some(signature_pointer) = PayloadSignatureRegistryPointer::<T>::get() {
1871 ensure!(signature_pointer.newest != *signature, Error::<T>::SignatureAlreadySubmitted);
1872 }
1873
1874 Ok(current_block)
1875 }
1876
1877 fn enqueue_signature(
1900 signature: &MultiSignature,
1901 signature_expires_at: BlockNumberFor<T>,
1902 current_block: BlockNumberFor<T>,
1903 ) -> DispatchResult {
1904 let pointer =
1906 PayloadSignatureRegistryPointer::<T>::get().unwrap_or(SignatureRegistryPointer {
1907 newest: signature.clone(),
1908 newest_expires_at: signature_expires_at,
1909 oldest: signature.clone(),
1910 count: 0,
1911 });
1912
1913 ensure!(
1915 !(pointer.count != 0 && pointer.newest.eq(signature)),
1916 Error::<T>::SignatureAlreadySubmitted
1917 );
1918
1919 let mut oldest: MultiSignature = pointer.oldest.clone();
1921
1922 let is_registry_full: bool = pointer.count == T::MaxSignaturesStored::get().unwrap_or(0);
1924
1925 if is_registry_full {
1927 let (expire_block_number, next_oldest) =
1928 PayloadSignatureRegistryList::<T>::get(pointer.oldest.clone())
1929 .ok_or(Error::<T>::SignatureRegistryCorrupted)?;
1930
1931 ensure!(
1932 current_block.gt(&expire_block_number),
1933 Error::<T>::SignatureRegistryLimitExceeded
1934 );
1935
1936 oldest = next_oldest.clone();
1938
1939 <PayloadSignatureRegistryList<T>>::remove(pointer.oldest);
1940 }
1941
1942 if pointer.count != 0 {
1944 <PayloadSignatureRegistryList<T>>::insert(
1945 pointer.newest,
1946 (pointer.newest_expires_at, signature.clone()),
1947 );
1948 }
1949
1950 PayloadSignatureRegistryPointer::<T>::put(SignatureRegistryPointer {
1952 count: if is_registry_full { pointer.count } else { pointer.count + 1 },
1954 newest: signature.clone(),
1955 newest_expires_at: signature_expires_at,
1956 oldest,
1957 });
1958
1959 Ok(())
1960 }
1961
1962 fn mortality_block_limit(current_block: BlockNumberFor<T>) -> BlockNumberFor<T> {
1966 let mortality_size = T::MortalityWindowSize::get();
1967 current_block + BlockNumberFor::<T>::from(mortality_size)
1968 }
1969}
1970
1971#[cfg(feature = "runtime-benchmarks")]
1972impl<T: Config> MsaBenchmarkHelper<T::AccountId> for Pallet<T> {
1973 fn set_delegation_relationship(
1975 provider: ProviderId,
1976 delegator: DelegatorId,
1977 schemas: Vec<SchemaId>,
1978 ) -> DispatchResult {
1979 Self::add_provider(provider, delegator, schemas)?;
1980 Ok(())
1981 }
1982
1983 fn add_key(msa_id: MessageSourceId, key: T::AccountId) -> DispatchResult {
1985 Self::add_key(msa_id, &key)?;
1986 Ok(())
1987 }
1988}
1989
1990#[cfg(feature = "runtime-benchmarks")]
1991impl<T: Config> RegisterProviderBenchmarkHelper for Pallet<T> {
1992 fn create(provider_id: MessageSourceId, name: Vec<u8>) -> DispatchResult {
1994 let name = BoundedVec::<u8, T::MaxProviderNameSize>::try_from(name).expect("error");
1995 Self::create_registered_provider(provider_id.into(), name)?;
1996
1997 Ok(())
1998 }
1999}
2000
2001impl<T: Config> MsaLookup for Pallet<T> {
2002 type AccountId = T::AccountId;
2003
2004 fn get_msa_id(key: &Self::AccountId) -> Option<MessageSourceId> {
2005 Self::get_owner_of(key)
2006 }
2007}
2008
2009impl<T: Config> MsaValidator for Pallet<T> {
2010 type AccountId = T::AccountId;
2011
2012 fn ensure_valid_msa_key(key: &T::AccountId) -> Result<MessageSourceId, DispatchError> {
2013 Self::ensure_valid_msa_key(key)
2014 }
2015}
2016
2017impl<T: Config> ProviderLookup for Pallet<T> {
2018 type BlockNumber = BlockNumberFor<T>;
2019 type MaxSchemaGrantsPerDelegation = T::MaxSchemaGrantsPerDelegation;
2020 type SchemaId = SchemaId;
2021
2022 fn get_delegation_of(
2023 delegator: DelegatorId,
2024 provider: ProviderId,
2025 ) -> Option<Delegation<SchemaId, Self::BlockNumber, Self::MaxSchemaGrantsPerDelegation>> {
2026 DelegatorAndProviderToDelegation::<T>::get(delegator, provider)
2027 }
2028}
2029
2030impl<T: Config> DelegationValidator for Pallet<T> {
2031 type BlockNumber = BlockNumberFor<T>;
2032 type MaxSchemaGrantsPerDelegation = T::MaxSchemaGrantsPerDelegation;
2033 type SchemaId = SchemaId;
2034
2035 fn ensure_valid_delegation(
2045 provider_id: ProviderId,
2046 delegator_id: DelegatorId,
2047 block_number: Option<BlockNumberFor<T>>,
2048 ) -> Result<
2049 Delegation<SchemaId, BlockNumberFor<T>, T::MaxSchemaGrantsPerDelegation>,
2050 DispatchError,
2051 > {
2052 let info = DelegatorAndProviderToDelegation::<T>::get(delegator_id, provider_id)
2053 .ok_or(Error::<T>::DelegationNotFound)?;
2054 let current_block = frame_system::Pallet::<T>::block_number();
2055 let requested_block = match block_number {
2056 Some(block_number) => {
2057 ensure!(
2058 current_block >= block_number,
2059 Error::<T>::CannotPredictValidityPastCurrentBlock
2060 );
2061 block_number
2062 },
2063 None => current_block,
2064 };
2065
2066 if info.revoked_at == BlockNumberFor::<T>::zero() {
2067 return Ok(info);
2068 }
2069 ensure!(info.revoked_at >= requested_block, Error::<T>::DelegationRevoked);
2070
2071 Ok(info)
2072 }
2073}
2074
2075impl<T: Config> TargetValidator for Pallet<T> {
2076 fn validate(target: MessageSourceId) -> bool {
2077 Self::is_registered_provider(target)
2078 }
2079}
2080
2081impl<T: Config> SchemaGrantValidator<BlockNumberFor<T>> for Pallet<T> {
2082 fn ensure_valid_schema_grant(
2091 provider: ProviderId,
2092 delegator: DelegatorId,
2093 schema_id: SchemaId,
2094 block_number: BlockNumberFor<T>,
2095 ) -> DispatchResult {
2096 let provider_info = Self::ensure_valid_delegation(provider, delegator, Some(block_number))?;
2097
2098 let schema_permission_revoked_at_block_number = provider_info
2099 .schema_permissions
2100 .get(&schema_id)
2101 .ok_or(Error::<T>::SchemaNotGranted)?;
2102
2103 if *schema_permission_revoked_at_block_number == BlockNumberFor::<T>::zero() {
2104 return Ok(());
2105 }
2106
2107 ensure!(
2108 block_number <= *schema_permission_revoked_at_block_number,
2109 Error::<T>::SchemaNotGranted
2110 );
2111
2112 Ok(())
2113 }
2114}
2115
2116impl<T: Config> MsaKeyProvider for Pallet<T> {
2117 type AccountId = T::AccountId;
2118 fn key_eligible_for_subsidized_addition(
2124 old_key: Self::AccountId,
2125 new_key: Self::AccountId,
2126 msa_id: MessageSourceId,
2127 ) -> bool {
2128 let new_address32 = T::ConvertIntoAccountId32::convert((new_key).clone());
2129 if EthereumAddressMapper::is_ethereum_address(&new_address32) {
2130 if let Some(stored_msa_id) = Self::get_msa_id(&old_key) {
2131 return stored_msa_id == msa_id && PublicKeyCountForMsaId::<T>::get(msa_id).eq(&1u8);
2132 }
2133 }
2134 false
2135 }
2136}
2137
2138#[derive(Encode, Decode, DecodeWithMemTracking, Clone, Eq, PartialEq, TypeInfo)]
2143#[scale_info(skip_type_params(T))]
2144pub struct CheckFreeExtrinsicUse<T: Config + Send + Sync>(PhantomData<T>);
2145
2146impl<T: Config + Send + Sync> CheckFreeExtrinsicUse<T> {
2147 pub fn validate_delegation_by_delegator(
2158 account_id: &T::AccountId,
2159 provider_msa_id: &MessageSourceId,
2160 ) -> TransactionValidity {
2161 const TAG_PREFIX: &str = "DelegatorDelegationRevocation";
2162 let delegator_msa_id: DelegatorId = Pallet::<T>::ensure_valid_msa_key(account_id)
2163 .map_err(|_| InvalidTransaction::Custom(ValidityError::InvalidMsaKey as u8))?
2164 .into();
2165 let provider_msa_id = ProviderId(*provider_msa_id);
2166
2167 Pallet::<T>::ensure_valid_delegation(provider_msa_id, delegator_msa_id, None)
2168 .map_err(|_| InvalidTransaction::Custom(ValidityError::InvalidDelegation as u8))?;
2169 ValidTransaction::with_tag_prefix(TAG_PREFIX).and_provides(account_id).build()
2170 }
2171
2172 pub fn validate_delegation_by_provider(
2183 account_id: &T::AccountId,
2184 delegator_msa_id: &MessageSourceId,
2185 ) -> TransactionValidity {
2186 const TAG_PREFIX: &str = "ProviderDelegationRevocation";
2187
2188 let provider_msa_id: ProviderId = Pallet::<T>::ensure_valid_msa_key(account_id)
2189 .map_err(|_| InvalidTransaction::Custom(ValidityError::InvalidMsaKey as u8))?
2190 .into();
2191 let delegator_msa_id = DelegatorId(*delegator_msa_id);
2192
2193 Pallet::<T>::ensure_valid_delegation(provider_msa_id, delegator_msa_id, None)
2195 .map_err(|_| InvalidTransaction::Custom(ValidityError::InvalidDelegation as u8))?;
2196 ValidTransaction::with_tag_prefix(TAG_PREFIX).and_provides(account_id).build()
2197 }
2198
2199 pub fn validate_key_delete(
2212 signing_public_key: &T::AccountId,
2213 public_key_to_delete: &T::AccountId,
2214 ) -> TransactionValidity {
2215 const TAG_PREFIX: &str = "KeyRevocation";
2216
2217 ensure!(
2218 signing_public_key != public_key_to_delete,
2219 InvalidTransaction::Custom(ValidityError::InvalidSelfRemoval as u8)
2220 );
2221
2222 let maybe_owner_msa_id: MessageSourceId =
2223 Pallet::<T>::ensure_valid_msa_key(signing_public_key)
2224 .map_err(|_| InvalidTransaction::Custom(ValidityError::InvalidMsaKey as u8))?;
2225
2226 let msa_id_for_key_to_delete: MessageSourceId =
2227 Pallet::<T>::ensure_valid_msa_key(public_key_to_delete)
2228 .map_err(|_| InvalidTransaction::Custom(ValidityError::InvalidMsaKey as u8))?;
2229
2230 ensure!(
2231 maybe_owner_msa_id == msa_id_for_key_to_delete,
2232 InvalidTransaction::Custom(ValidityError::NotKeyOwner as u8)
2233 );
2234
2235 ValidTransaction::with_tag_prefix(TAG_PREFIX)
2236 .and_provides(signing_public_key)
2237 .build()
2238 }
2239
2240 pub fn ensure_msa_can_retire(account_id: &T::AccountId) -> TransactionValidity {
2256 const TAG_PREFIX: &str = "MSARetirement";
2257 let msa_id = Pallet::<T>::ensure_valid_msa_key(account_id)
2258 .map_err(|_| InvalidTransaction::Custom(ValidityError::InvalidMsaKey as u8))?;
2259
2260 ensure!(
2261 !Pallet::<T>::is_registered_provider(msa_id),
2262 InvalidTransaction::Custom(
2263 ValidityError::InvalidRegisteredProviderCannotBeRetired as u8
2264 )
2265 );
2266
2267 let msa_handle = T::HandleProvider::get_handle_for_msa(msa_id);
2268 ensure!(
2269 msa_handle.is_none(),
2270 InvalidTransaction::Custom(ValidityError::HandleNotRetired as u8)
2271 );
2272
2273 let key_count = PublicKeyCountForMsaId::<T>::get(msa_id);
2274 ensure!(
2275 key_count == 1,
2276 InvalidTransaction::Custom(ValidityError::InvalidMoreThanOneKeyExists as u8)
2277 );
2278
2279 let delegator_id = DelegatorId(msa_id);
2280 let has_active_delegations: bool = DelegatorAndProviderToDelegation::<T>::iter_key_prefix(
2281 delegator_id,
2282 )
2283 .any(|provider_id| {
2284 Pallet::<T>::ensure_valid_delegation(provider_id, delegator_id, None).is_ok()
2285 });
2286
2287 ensure!(
2288 !has_active_delegations,
2289 InvalidTransaction::Custom(ValidityError::InvalidNonZeroProviderDelegations as u8)
2290 );
2291
2292 let msa_address = Pallet::<T>::msa_id_to_eth_address(msa_id);
2294
2295 let mut bytes = &EthereumAddressMapper::to_bytes32(&msa_address.0)[..];
2297 let msa_account_id = T::AccountId::decode(&mut bytes).map_err(|_| {
2298 log::error!("Failed to decode MSA account ID from Ethereum address");
2299 InvalidTransaction::Custom(ValidityError::InvalidMsaKey as u8)
2300 })?;
2301
2302 let msa_balance = T::Currency::reducible_balance(
2304 &msa_account_id,
2305 Preservation::Expendable,
2306 Fortitude::Polite,
2307 );
2308 ensure!(
2309 msa_balance == Zero::zero(),
2310 InvalidTransaction::Custom(ValidityError::InvalidMsaHoldingTokenCannotBeRetired as u8)
2311 );
2312
2313 ValidTransaction::with_tag_prefix(TAG_PREFIX).and_provides(account_id).build()
2314 }
2315
2316 pub fn validate_msa_token_withdrawal(
2331 receiver_account_id: &T::AccountId,
2332 msa_owner_public_key: &T::AccountId,
2333 msa_owner_proof: &MultiSignature,
2334 authorization_payload: &AuthorizedKeyData<T>,
2335 ) -> TransactionValidity {
2336 const TAG_PREFIX: &str = "MsaTokenWithdrawal";
2337
2338 ensure!(
2339 *receiver_account_id == authorization_payload.authorized_public_key,
2340 InvalidTransaction::Custom(ValidityError::NotKeyOwner as u8)
2341 );
2342
2343 ensure!(
2344 authorization_payload.discriminant == PayloadTypeDiscriminator::AuthorizedKeyData,
2345 InvalidTransaction::Custom(ValidityError::MsaOwnershipInvalidSignature as u8)
2346 );
2347 ensure!(
2348 Pallet::<T>::verify_signature(
2349 msa_owner_proof,
2350 msa_owner_public_key,
2351 authorization_payload
2352 ),
2353 InvalidTransaction::Custom(ValidityError::MsaOwnershipInvalidSignature as u8)
2354 );
2355
2356 ensure!(
2358 !PublicKeyToMsaId::<T>::contains_key(receiver_account_id),
2359 InvalidTransaction::Custom(ValidityError::IneligibleOrigin as u8)
2360 );
2361
2362 Pallet::<T>::check_signature_against_registry(
2363 msa_owner_proof,
2364 authorization_payload.expiration,
2365 )
2366 .map_err(|_| {
2367 InvalidTransaction::Custom(ValidityError::MsaOwnershipInvalidSignature as u8)
2368 })?;
2369
2370 let msa_id = authorization_payload.msa_id;
2371
2372 Pallet::<T>::ensure_msa_owner(msa_owner_public_key, msa_id)
2373 .map_err(|_| InvalidTransaction::Custom(ValidityError::InvalidMsaKey as u8))?;
2374
2375 let msa_address = Pallet::<T>::msa_id_to_eth_address(msa_id);
2377
2378 let mut bytes = &EthereumAddressMapper::to_bytes32(&msa_address.0)[..];
2380 let msa_account_id = T::AccountId::decode(&mut bytes).map_err(|_| {
2381 log::error!("Failed to decode MSA account ID from Ethereum address");
2382 InvalidTransaction::Custom(ValidityError::InvalidMsaKey as u8)
2383 })?;
2384
2385 let msa_balance = T::Currency::reducible_balance(
2387 &msa_account_id,
2388 Preservation::Expendable,
2389 Fortitude::Polite,
2390 );
2391 ensure!(
2392 msa_balance > Zero::zero(),
2393 InvalidTransaction::Custom(ValidityError::InsufficientBalanceToWithdraw as u8)
2394 );
2395 ValidTransaction::with_tag_prefix(TAG_PREFIX)
2396 .and_provides(receiver_account_id)
2397 .build()
2398 }
2399}
2400
2401pub enum ValidityError {
2403 InvalidDelegation,
2405 InvalidMsaKey,
2407 InvalidRegisteredProviderCannotBeRetired,
2409 InvalidMoreThanOneKeyExists,
2411 InvalidSelfRemoval,
2413 NotKeyOwner,
2415 InvalidNonZeroProviderDelegations,
2417 HandleNotRetired,
2419 MsaOwnershipInvalidSignature,
2421 InsufficientBalanceToWithdraw,
2423 IneligibleOrigin,
2425 InvalidMsaHoldingTokenCannotBeRetired,
2427}
2428
2429impl<T: Config + Send + Sync> CheckFreeExtrinsicUse<T> {
2430 pub fn new() -> Self {
2432 Self(PhantomData)
2433 }
2434}
2435
2436impl<T: Config + Send + Sync> core::fmt::Debug for CheckFreeExtrinsicUse<T> {
2437 #[cfg(feature = "std")]
2438 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
2439 write!(f, "CheckFreeExtrinsicUse<{:?}>", self.0)
2440 }
2441 #[cfg(not(feature = "std"))]
2442 fn fmt(&self, _: &mut core::fmt::Formatter) -> core::fmt::Result {
2443 Ok(())
2444 }
2445}
2446
2447#[derive(RuntimeDebugNoBound)]
2449pub enum Val {
2450 Valid,
2452 Refund(Weight),
2454}
2455
2456#[derive(RuntimeDebugNoBound)]
2458pub enum Pre {
2459 Valid,
2461 Refund(Weight),
2463}
2464
2465impl<T: Config + Send + Sync> TransactionExtension<T::RuntimeCall> for CheckFreeExtrinsicUse<T>
2466where
2467 T::RuntimeCall: Dispatchable<Info = DispatchInfo> + IsSubType<Call<T>>,
2468 <T as frame_system::Config>::RuntimeOrigin: AsSystemOriginSigner<T::AccountId> + Clone,
2469{
2470 const IDENTIFIER: &'static str = "CheckFreeExtrinsicUse";
2471 type Implicit = ();
2472 type Val = Val;
2473 type Pre = Pre;
2474
2475 fn weight(&self, call: &T::RuntimeCall) -> Weight {
2476 match call.is_sub_type() {
2477 Some(Call::revoke_delegation_by_provider { .. }) =>
2478 T::WeightInfo::check_free_extrinsic_use_revoke_delegation_by_provider(),
2479 Some(Call::revoke_delegation_by_delegator { .. }) =>
2480 T::WeightInfo::check_free_extrinsic_use_revoke_delegation_by_delegator(),
2481 Some(Call::delete_msa_public_key { .. }) =>
2482 T::WeightInfo::check_free_extrinsic_use_delete_msa_public_key(),
2483 Some(Call::retire_msa { .. }) => T::WeightInfo::check_free_extrinsic_use_retire_msa(),
2484 Some(Call::withdraw_tokens { .. }) =>
2485 T::WeightInfo::check_free_extrinsic_use_withdraw_tokens(),
2486 _ => Weight::zero(),
2487 }
2488 }
2489
2490 fn validate(
2491 &self,
2492 origin: <T as frame_system::Config>::RuntimeOrigin,
2493 call: &T::RuntimeCall,
2494 _info: &DispatchInfoOf<T::RuntimeCall>,
2495 _len: usize,
2496 _self_implicit: Self::Implicit,
2497 _inherited_implication: &impl Encode,
2498 _source: TransactionSource,
2499 ) -> ValidateResult<Self::Val, T::RuntimeCall> {
2500 let weight = self.weight(call);
2501 let Some(who) = origin.as_system_origin_signer() else {
2502 return Ok((ValidTransaction::default(), Val::Refund(weight), origin));
2503 };
2504 let validity = match call.is_sub_type() {
2505 Some(Call::revoke_delegation_by_provider { delegator, .. }) =>
2506 Self::validate_delegation_by_provider(who, delegator),
2507 Some(Call::revoke_delegation_by_delegator { provider_msa_id, .. }) =>
2508 Self::validate_delegation_by_delegator(who, provider_msa_id),
2509 Some(Call::delete_msa_public_key { public_key_to_delete, .. }) =>
2510 Self::validate_key_delete(who, public_key_to_delete),
2511 Some(Call::retire_msa { .. }) => Self::ensure_msa_can_retire(who),
2512 Some(Call::withdraw_tokens {
2513 msa_owner_public_key,
2514 msa_owner_proof,
2515 authorization_payload,
2516 }) => Self::validate_msa_token_withdrawal(
2517 who,
2518 msa_owner_public_key,
2519 msa_owner_proof,
2520 authorization_payload,
2521 ),
2522 _ => Ok(Default::default()),
2523 };
2524 validity.map(|v| (v, Val::Valid, origin))
2525 }
2526
2527 fn prepare(
2528 self,
2529 val: Self::Val,
2530 _origin: &<T as frame_system::Config>::RuntimeOrigin,
2531 _call: &T::RuntimeCall,
2532 _info: &DispatchInfoOf<T::RuntimeCall>,
2533 _len: usize,
2534 ) -> Result<Self::Pre, TransactionValidityError> {
2535 match val {
2536 Val::Valid => Ok(Pre::Valid),
2537 Val::Refund(w) => Ok(Pre::Refund(w)),
2538 }
2539 }
2540
2541 fn post_dispatch_details(
2542 pre: Self::Pre,
2543 _info: &DispatchInfo,
2544 _post_info: &PostDispatchInfoOf<T::RuntimeCall>,
2545 _len: usize,
2546 _result: &sp_runtime::DispatchResult,
2547 ) -> Result<Weight, TransactionValidityError> {
2548 match pre {
2549 Pre::Valid => Ok(Weight::zero()),
2550 Pre::Refund(w) => Ok(w),
2551 }
2552 }
2553}