From d9c713d46ae8c55b097cca60a84f870677aa5d9e Mon Sep 17 00:00:00 2001 From: Francisco Silva Date: Thu, 12 Dec 2024 15:29:37 +0000 Subject: [PATCH 01/29] using single storage unbounded instead of pallet::without_storage_info --- parachain/pallets/omni-account/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parachain/pallets/omni-account/src/lib.rs b/parachain/pallets/omni-account/src/lib.rs index 5e55ec4b0f..2cb0aad7db 100644 --- a/parachain/pallets/omni-account/src/lib.rs +++ b/parachain/pallets/omni-account/src/lib.rs @@ -66,7 +66,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] - #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::config] @@ -113,6 +112,7 @@ pub mod pallet { /// A map between OmniAccount and its MemberAccounts (a bounded vector of MemberAccount) #[pallet::storage] + #[pallet::unbounded] #[pallet::getter(fn account_store)] pub type AccountStore = StorageMap>; From b7d0f003276d2079cef913cc47b0be5f0a15e424 Mon Sep 17 00:00:00 2001 From: Francisco Silva Date: Thu, 12 Dec 2024 15:36:14 +0000 Subject: [PATCH 02/29] adding integrity_test hook --- parachain/pallets/omni-account/src/lib.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/parachain/pallets/omni-account/src/lib.rs b/parachain/pallets/omni-account/src/lib.rs index 2cb0aad7db..8ac7092df9 100644 --- a/parachain/pallets/omni-account/src/lib.rs +++ b/parachain/pallets/omni-account/src/lib.rs @@ -103,6 +103,15 @@ pub mod pallet { /// Convert an `Identity` to OmniAccount type type OmniAccountConverter: OmniAccountConverter; + + #[pallet::hooks] + impl Hooks> for Pallet { + fn integrity_test() { + assert!( + ::MaxAccountStoreLength::get() > 0, + "MaxAccountStoreLength must be greater than 0" + ); + } } pub type MemberAccounts = BoundedVec::MaxAccountStoreLength>; From 2a7e9345c11a866dcee2973203526819106fe31a Mon Sep 17 00:00:00 2001 From: Francisco Silva Date: Thu, 12 Dec 2024 15:37:52 +0000 Subject: [PATCH 03/29] adding new types to the pallet config --- parachain/pallets/omni-account/src/lib.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/parachain/pallets/omni-account/src/lib.rs b/parachain/pallets/omni-account/src/lib.rs index 8ac7092df9..ae4b0f95b2 100644 --- a/parachain/pallets/omni-account/src/lib.rs +++ b/parachain/pallets/omni-account/src/lib.rs @@ -28,7 +28,7 @@ pub use pallet::*; use frame_support::pallet_prelude::*; use frame_support::{ dispatch::{GetDispatchInfo, PostDispatchInfo}, - traits::{IsSubType, UnfilteredDispatchable}, + traits::{InstanceFilter, IsSubType, UnfilteredDispatchable}, }; use frame_system::pallet_prelude::*; use sp_core::H256; @@ -104,6 +104,20 @@ pub mod pallet { /// Convert an `Identity` to OmniAccount type type OmniAccountConverter: OmniAccountConverter; + /// The permissions that a member account can have + type Permission: Parameter + + Member + + Ord + + PartialOrd + + Default + + InstanceFilter<::RuntimeCall> + + MaxEncodedLen; + + /// The maximum number of permissions that a member account can have + #[pallet::constant] + type MaxPermissions: Get; + } + #[pallet::hooks] impl Hooks> for Pallet { fn integrity_test() { @@ -111,6 +125,10 @@ pub mod pallet { ::MaxAccountStoreLength::get() > 0, "MaxAccountStoreLength must be greater than 0" ); + assert!( + ::MaxPermissions::get() > 0, + "MaxPermissions must be greater than 0" + ); } } From caf080f295ba80958d339ee35747be3921c9e220 Mon Sep 17 00:00:00 2001 From: Francisco Silva Date: Thu, 12 Dec 2024 15:38:34 +0000 Subject: [PATCH 04/29] adding storage item for account member permissions --- parachain/pallets/omni-account/src/lib.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/parachain/pallets/omni-account/src/lib.rs b/parachain/pallets/omni-account/src/lib.rs index ae4b0f95b2..b53b63083f 100644 --- a/parachain/pallets/omni-account/src/lib.rs +++ b/parachain/pallets/omni-account/src/lib.rs @@ -149,6 +149,14 @@ pub mod pallet { pub type MemberAccountHash = StorageMap; + /// A map between hash of MemberAccount and its permissions + #[pallet::storage] + pub type MemberAccountPermissions = StorageMap< + Hasher = Blake2_128Concat, + Key = H256, + Value = BoundedVec, + >; + #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { From 24e1fdf99e13bdf77df7f78bafdc230e93df77bf Mon Sep 17 00:00:00 2001 From: Francisco Silva Date: Thu, 12 Dec 2024 15:39:00 +0000 Subject: [PATCH 05/29] adding new errors --- parachain/pallets/omni-account/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/parachain/pallets/omni-account/src/lib.rs b/parachain/pallets/omni-account/src/lib.rs index b53b63083f..df595fd2ab 100644 --- a/parachain/pallets/omni-account/src/lib.rs +++ b/parachain/pallets/omni-account/src/lib.rs @@ -188,6 +188,8 @@ pub mod pallet { InvalidAccount, UnknownAccountStore, EmptyAccount, + NoPermission, + PermissionsLenLimitReached, } #[pallet::call] From 82a36d64e6bb31c59326ebc4a6dc1217e2957798 Mon Sep 17 00:00:00 2001 From: Francisco Silva Date: Thu, 12 Dec 2024 15:40:34 +0000 Subject: [PATCH 06/29] storing default permission on create_account_store --- parachain/pallets/omni-account/src/lib.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/parachain/pallets/omni-account/src/lib.rs b/parachain/pallets/omni-account/src/lib.rs index df595fd2ab..25665f6b56 100644 --- a/parachain/pallets/omni-account/src/lib.rs +++ b/parachain/pallets/omni-account/src/lib.rs @@ -425,6 +425,12 @@ pub mod pallet { MemberAccountHash::::insert(hash, omni_account.clone()); AccountStore::::insert(omni_account.clone(), member_accounts.clone()); + let mut permissions = BoundedVec::::new(); + permissions + .try_push(T::Permission::default()) + .map_err(|_| Error::::PermissionsLenLimitReached)?; + MemberAccountPermissions::::insert(hash, permissions); + Self::deposit_event(Event::AccountStoreCreated { who: omni_account.clone() }); Self::deposit_event(Event::AccountStoreUpdated { who: omni_account, From 1516f2ee595eb5a4eec44701d7c2938a87abaf32 Mon Sep 17 00:00:00 2001 From: Francisco Silva Date: Thu, 12 Dec 2024 16:18:13 +0000 Subject: [PATCH 07/29] adding comments --- parachain/pallets/omni-account/src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/parachain/pallets/omni-account/src/lib.rs b/parachain/pallets/omni-account/src/lib.rs index 25665f6b56..17db667d20 100644 --- a/parachain/pallets/omni-account/src/lib.rs +++ b/parachain/pallets/omni-account/src/lib.rs @@ -105,6 +105,9 @@ pub mod pallet { type OmniAccountConverter: OmniAccountConverter; /// The permissions that a member account can have + /// The instance filter determines whether a given call may can be dispatched under this type. + /// + /// IMPORTANT: `Default` must be provided and MUST BE the the *most permissive* value. type Permission: Parameter + Member + Ord From eada06f78c569c7be26e49777dba4f84159da644 Mon Sep 17 00:00:00 2001 From: Francisco Silva Date: Thu, 12 Dec 2024 16:18:49 +0000 Subject: [PATCH 08/29] adding default permissions --- parachain/pallets/omni-account/src/lib.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/parachain/pallets/omni-account/src/lib.rs b/parachain/pallets/omni-account/src/lib.rs index 17db667d20..03dcdb090d 100644 --- a/parachain/pallets/omni-account/src/lib.rs +++ b/parachain/pallets/omni-account/src/lib.rs @@ -34,7 +34,7 @@ use frame_system::pallet_prelude::*; use sp_core::H256; use sp_runtime::traits::Dispatchable; use sp_std::boxed::Box; -use sp_std::vec::Vec; +use sp_std::{vec, vec::Vec}; pub type MemberCount = u32; @@ -152,12 +152,19 @@ pub mod pallet { pub type MemberAccountHash = StorageMap; + #[pallet::type_value] + pub fn DefaultPermissions() -> BoundedVec { + BoundedVec::try_from(vec![T::Permission::default()]).expect("default permission") + } + /// A map between hash of MemberAccount and its permissions #[pallet::storage] pub type MemberAccountPermissions = StorageMap< Hasher = Blake2_128Concat, Key = H256, Value = BoundedVec, + QueryKind = ValueQuery, + OnEmpty = DefaultPermissions, >; #[pallet::event] From dc9a0f1f704c869061cba8de1b80362b083b4904 Mon Sep 17 00:00:00 2001 From: Francisco Silva Date: Thu, 12 Dec 2024 16:19:57 +0000 Subject: [PATCH 09/29] small refactoring --- parachain/pallets/omni-account/src/lib.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/parachain/pallets/omni-account/src/lib.rs b/parachain/pallets/omni-account/src/lib.rs index 03dcdb090d..bc0ba70516 100644 --- a/parachain/pallets/omni-account/src/lib.rs +++ b/parachain/pallets/omni-account/src/lib.rs @@ -431,15 +431,14 @@ pub mod pallet { member_accounts .try_push(identity.into()) .map_err(|_| Error::::AccountStoreLenLimitReached)?; - - MemberAccountHash::::insert(hash, omni_account.clone()); - AccountStore::::insert(omni_account.clone(), member_accounts.clone()); - let mut permissions = BoundedVec::::new(); permissions .try_push(T::Permission::default()) .map_err(|_| Error::::PermissionsLenLimitReached)?; + + MemberAccountHash::::insert(hash, omni_account.clone()); MemberAccountPermissions::::insert(hash, permissions); + AccountStore::::insert(omni_account.clone(), member_accounts.clone()); Self::deposit_event(Event::AccountStoreCreated { who: omni_account.clone() }); Self::deposit_event(Event::AccountStoreUpdated { From 7d6241ba708e40a7703610e7ee6c1d66eece4ae1 Mon Sep 17 00:00:00 2001 From: Francisco Silva Date: Thu, 12 Dec 2024 16:20:47 +0000 Subject: [PATCH 10/29] implementing ensure_permission --- parachain/pallets/omni-account/src/lib.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/parachain/pallets/omni-account/src/lib.rs b/parachain/pallets/omni-account/src/lib.rs index bc0ba70516..242ee5f263 100644 --- a/parachain/pallets/omni-account/src/lib.rs +++ b/parachain/pallets/omni-account/src/lib.rs @@ -215,6 +215,7 @@ pub mod pallet { let _ = T::TEECallOrigin::ensure_origin(origin)?; let omni_account = MemberAccountHash::::get(member_account_hash) .ok_or(Error::::AccountNotFound)?; + Self::ensure_permission(call.as_ref(), member_account_hash)?; let result = call.dispatch(RawOrigin::OmniAccount(omni_account.clone()).into()); system::Pallet::::inc_account_nonce(&omni_account); Self::deposit_event(Event::DispatchedAsOmniAccount { @@ -236,6 +237,7 @@ pub mod pallet { let _ = T::TEECallOrigin::ensure_origin(origin)?; let omni_account = MemberAccountHash::::get(member_account_hash) .ok_or(Error::::AccountNotFound)?; + Self::ensure_permission(call.as_ref(), member_account_hash)?; let result: Result< PostDispatchInfo, sp_runtime::DispatchErrorWithPostInfo, @@ -448,6 +450,19 @@ pub mod pallet { Ok(member_accounts) } + + fn ensure_permission( + call: &::RuntimeCall, + member_account_hash: H256, + ) -> Result<(), Error> { + let permissions = MemberAccountPermissions::::get(member_account_hash); + ensure!( + permissions.iter().any(|permission| permission.filter(call)), + Error::::NoPermission + ); + + Ok(()) + } } } From eb1eaaa8f1d51ef87c7f5b295b9e38d82311326c Mon Sep 17 00:00:00 2001 From: Francisco Silva Date: Thu, 12 Dec 2024 16:21:14 +0000 Subject: [PATCH 11/29] updating mock --- parachain/pallets/omni-account/src/mock.rs | 60 +++++++++++++++++++++- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/parachain/pallets/omni-account/src/mock.rs b/parachain/pallets/omni-account/src/mock.rs index b7ab3f457c..3338da7ef7 100644 --- a/parachain/pallets/omni-account/src/mock.rs +++ b/parachain/pallets/omni-account/src/mock.rs @@ -14,17 +14,18 @@ // You should have received a copy of the GNU General Public License // along with Litentry. If not, see . -use crate::{self as pallet_omni_account, Encode, EnsureOmniAccount}; +use crate::{self as pallet_omni_account, Decode, Encode, EnsureOmniAccount, MaxEncodedLen}; use core_primitives::{DefaultOmniAccountConverter, Identity, MemberAccount}; use frame_support::{ assert_ok, derive_impl, pallet_prelude::EnsureOrigin, parameter_types, - traits::{ConstU32, ConstU64}, + traits::{ConstU32, ConstU64, InstanceFilter}, }; use frame_system::EnsureRoot; pub use pallet_teebag::test_util::get_signer; use pallet_teebag::test_util::{TEST8_CERT, TEST8_SIGNER_PUB, TEST8_TIMESTAMP, URL}; +use sp_core::RuntimeDebug; use sp_keyring::AccountKeyring; use sp_runtime::{ traits::{IdentifyAccount, IdentityLookup, Verify}, @@ -158,6 +159,59 @@ impl pallet_teebag::Config for Test { type WeightInfo = (); } +#[derive( + Copy, + Clone, + PartialEq, + Eq, + Ord, + PartialOrd, + Encode, + Decode, + RuntimeDebug, + MaxEncodedLen, + scale_info::TypeInfo, +)] +pub enum Permission { + All, + Balances, + RemoveAccount, + RequestEthereumIntent, +} + +impl Default for Permission { + fn default() -> Self { + Self::All + } +} + +impl InstanceFilter for Permission { + fn filter(&self, call: &RuntimeCall) -> bool { + match self { + Permission::All => true, + Permission::Balances => matches!(call, RuntimeCall::Balances { .. }), + Permission::RemoveAccount => matches!( + call, + RuntimeCall::OmniAccount(pallet_omni_account::Call::remove_accounts { .. }) + ), + Permission::RequestEthereumIntent => { + if let RuntimeCall::OmniAccount(pallet_omni_account::Call::request_intent { + intent, + }) = call + { + matches!( + intent, + pallet_omni_account::Intent::TransferEthereum(_) + | pallet_omni_account::Intent::CallEthereum(_) + ) + } else { + false + } + }, + } + } +} + impl pallet_omni_account::Config for Test { type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; @@ -166,6 +220,8 @@ impl pallet_omni_account::Config for Test { type MaxAccountStoreLength = ConstU32<3>; type OmniAccountOrigin = EnsureOmniAccount; type OmniAccountConverter = DefaultOmniAccountConverter; + type MaxPermissions = ConstU32<3>; + type Permission = Permission; } pub fn get_tee_signer() -> SystemAccountId { From 824e98263f1a18910939b5ca57b289ef03438e21 Mon Sep 17 00:00:00 2001 From: Francisco Silva Date: Thu, 12 Dec 2024 16:57:38 +0000 Subject: [PATCH 12/29] adding optional permissions to add_account, set defaults if None --- parachain/pallets/omni-account/src/lib.rs | 11 ++++++++++- parachain/pallets/omni-account/src/tests.rs | 19 ++++++++++++++++--- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/parachain/pallets/omni-account/src/lib.rs b/parachain/pallets/omni-account/src/lib.rs index 242ee5f263..e278a6b204 100644 --- a/parachain/pallets/omni-account/src/lib.rs +++ b/parachain/pallets/omni-account/src/lib.rs @@ -266,7 +266,8 @@ pub mod pallet { #[pallet::weight((195_000_000, DispatchClass::Normal))] pub fn add_account( origin: OriginFor, - member_account: MemberAccount, // account to be added + member_account: MemberAccount, // account to be added + permissions: Option>, // permissions for the account ) -> DispatchResult { // mutation of AccountStore requires `OmniAccountOrigin`, same as "remove" and "publicize" let who = T::OmniAccountOrigin::ensure_origin(origin)?; @@ -282,8 +283,16 @@ pub mod pallet { member_accounts .try_push(member_account) .map_err(|_| Error::::AccountStoreLenLimitReached)?; + let member_permissions: BoundedVec = { + let p = match permissions { + Some(p) => p, + None => vec![T::Permission::default()], + }; + p.try_into().map_err(|_| Error::::PermissionsLenLimitReached)? + }; MemberAccountHash::::insert(hash, who.clone()); + MemberAccountPermissions::::insert(hash, member_permissions); AccountStore::::insert(who.clone(), member_accounts.clone()); Self::deposit_event(Event::AccountAdded { diff --git a/parachain/pallets/omni-account/src/tests.rs b/parachain/pallets/omni-account/src/tests.rs index bddfa5e51b..7c0c4d92ff 100644 --- a/parachain/pallets/omni-account/src/tests.rs +++ b/parachain/pallets/omni-account/src/tests.rs @@ -23,7 +23,10 @@ use sp_runtime::{traits::BadOrigin, ModuleError}; use sp_std::vec; fn add_account_call(account: MemberAccount) -> Box { - let call = RuntimeCall::OmniAccount(crate::Call::add_account { member_account: account }); + let call = RuntimeCall::OmniAccount(crate::Call::add_account { + member_account: account, + permissions: None, + }); Box::new(call) } @@ -163,6 +166,16 @@ fn add_account_works() { assert!(MemberAccountHash::::contains_key(bob.hash())); assert!(MemberAccountHash::::contains_key(charlie.hash())); + assert!(MemberAccountPermissions::::contains_key(bob.hash())); + assert_eq!( + MemberAccountPermissions::::get(bob.hash()).to_vec(), + vec![Permission::All] + ); + assert!(MemberAccountPermissions::::contains_key(charlie.hash())); + assert_eq!( + MemberAccountPermissions::::get(charlie.hash()).to_vec(), + vec![Permission::All] + ); }); } @@ -173,12 +186,12 @@ fn add_account_origin_check_works() { let bob = private_member_account(bob()); assert_noop!( - OmniAccount::add_account(RuntimeOrigin::signed(tee_signer), bob.clone()), + OmniAccount::add_account(RuntimeOrigin::signed(tee_signer), bob.clone(), None), BadOrigin ); assert_noop!( - OmniAccount::add_account(RuntimeOrigin::signed(alice().omni_account), bob), + OmniAccount::add_account(RuntimeOrigin::signed(alice().omni_account), bob, None), BadOrigin ); }); From 2ef4b14654714aea6dbc75286d8794ab6901b302 Mon Sep 17 00:00:00 2001 From: Francisco Silva Date: Fri, 13 Dec 2024 09:59:07 +0000 Subject: [PATCH 13/29] setting permissions on update_account_store_by_one --- parachain/pallets/omni-account/src/lib.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/parachain/pallets/omni-account/src/lib.rs b/parachain/pallets/omni-account/src/lib.rs index e278a6b204..ab1f8f3b2a 100644 --- a/parachain/pallets/omni-account/src/lib.rs +++ b/parachain/pallets/omni-account/src/lib.rs @@ -394,8 +394,13 @@ pub mod pallet { .try_push(member_account.clone()) .map_err(|_| Error::::AccountStoreLenLimitReached)?; } + let mut permissions = BoundedVec::::new(); + permissions + .try_push(T::Permission::default()) + .map_err(|_| Error::::PermissionsLenLimitReached)?; MemberAccountHash::::insert(member_account.hash(), who_account.clone()); + MemberAccountPermissions::::insert(member_account.hash(), permissions); AccountStore::::insert(who_account.clone(), member_accounts.clone()); Self::deposit_event(Event::AccountStoreUpdated { who: who_account, From 16bd79eb79a5405cff4a524b28431c27e104cf27 Mon Sep 17 00:00:00 2001 From: Francisco Silva Date: Fri, 13 Dec 2024 11:52:13 +0000 Subject: [PATCH 14/29] improving ensure_permission --- parachain/pallets/omni-account/src/lib.rs | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/parachain/pallets/omni-account/src/lib.rs b/parachain/pallets/omni-account/src/lib.rs index ab1f8f3b2a..9a045ace99 100644 --- a/parachain/pallets/omni-account/src/lib.rs +++ b/parachain/pallets/omni-account/src/lib.rs @@ -469,12 +469,30 @@ pub mod pallet { call: &::RuntimeCall, member_account_hash: H256, ) -> Result<(), Error> { - let permissions = MemberAccountPermissions::::get(member_account_hash); + let member_permissions = MemberAccountPermissions::::get(member_account_hash); + ensure!( - permissions.iter().any(|permission| permission.filter(call)), + member_permissions.iter().any(|permission| permission.filter(call)), Error::::NoPermission ); + if let Some(Call::add_account { permissions: ref new_account_permissions, .. }) = + call.is_sub_type() + { + // If member has default permission, they can add accounts with any permission + if member_permissions.contains(&T::Permission::default()) { + return Ok(()); + } + + if let Some(new_account_permissions) = new_account_permissions { + // an account can only add another account with the same or less permissions + ensure!( + new_account_permissions.iter().all(|p| member_permissions.contains(p)), + Error::::NoPermission + ) + } + } + Ok(()) } } From 0a16d34fba63e9f1aebb126b6f5a04e43b745863 Mon Sep 17 00:00:00 2001 From: Francisco Silva Date: Fri, 13 Dec 2024 11:53:43 +0000 Subject: [PATCH 15/29] updating mock --- parachain/pallets/omni-account/src/mock.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/parachain/pallets/omni-account/src/mock.rs b/parachain/pallets/omni-account/src/mock.rs index 3338da7ef7..ad464295c6 100644 --- a/parachain/pallets/omni-account/src/mock.rs +++ b/parachain/pallets/omni-account/src/mock.rs @@ -97,6 +97,10 @@ pub fn charlie() -> Accounts { create_accounts(AccountKeyring::Charlie) } +pub fn dave() -> Accounts { + create_accounts(AccountKeyring::Dave) +} + pub fn public_member_account(accounts: Accounts) -> MemberAccount { MemberAccount::Public(accounts.identity) } @@ -175,7 +179,8 @@ impl pallet_teebag::Config for Test { pub enum Permission { All, Balances, - RemoveAccount, + AddAccounts, + RemoveAccounts, RequestEthereumIntent, } @@ -190,10 +195,14 @@ impl InstanceFilter for Permission { match self { Permission::All => true, Permission::Balances => matches!(call, RuntimeCall::Balances { .. }), - Permission::RemoveAccount => matches!( + Permission::RemoveAccounts => matches!( call, RuntimeCall::OmniAccount(pallet_omni_account::Call::remove_accounts { .. }) ), + Permission::AddAccounts => matches!( + call, + RuntimeCall::OmniAccount(pallet_omni_account::Call::add_account { .. }) + ), Permission::RequestEthereumIntent => { if let RuntimeCall::OmniAccount(pallet_omni_account::Call::request_intent { intent, From efce87477c5b07af3c31e45e9ffb5982ac666c6c Mon Sep 17 00:00:00 2001 From: Francisco Silva Date: Fri, 13 Dec 2024 11:54:44 +0000 Subject: [PATCH 16/29] refactoring add_account_call util --- parachain/pallets/omni-account/src/tests.rs | 43 +++++++++++---------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/parachain/pallets/omni-account/src/tests.rs b/parachain/pallets/omni-account/src/tests.rs index 7c0c4d92ff..f09afd9f56 100644 --- a/parachain/pallets/omni-account/src/tests.rs +++ b/parachain/pallets/omni-account/src/tests.rs @@ -22,11 +22,12 @@ use sp_core::H160; use sp_runtime::{traits::BadOrigin, ModuleError}; use sp_std::vec; -fn add_account_call(account: MemberAccount) -> Box { - let call = RuntimeCall::OmniAccount(crate::Call::add_account { - member_account: account, - permissions: None, - }); +fn add_account_call>( + account: MemberAccount, + permissions: Option::Permission>>, +) -> Box { + let call = + RuntimeCall::OmniAccount(crate::Call::add_account { member_account: account, permissions }); Box::new(call) } @@ -84,7 +85,7 @@ fn create_account_store_works() { fn add_account_without_creating_store_fails() { new_test_ext().execute_with(|| { let tee_signer = get_tee_signer(); - let call = add_account_call(private_member_account(bob())); + let call = add_account_call::(private_member_account(bob()), None); assert_noop!( OmniAccount::dispatch_as_omni_account( @@ -113,7 +114,7 @@ fn add_account_works() { alice().identity, )); - let call = add_account_call(bob.clone()); + let call = add_account_call::(bob.clone(), None); assert_ok!(OmniAccount::dispatch_as_omni_account( RuntimeOrigin::signed(tee_signer.clone()), alice().identity.hash(), @@ -140,7 +141,7 @@ fn add_account_works() { expected_member_accounts ); - let call = add_account_call(charlie.clone()); + let call = add_account_call::(charlie.clone(), None); assert_ok!(OmniAccount::dispatch_as_omni_account( RuntimeOrigin::signed(tee_signer.clone()), alice().identity.hash(), @@ -208,7 +209,7 @@ fn add_account_with_already_linked_account_fails() { alice().identity.clone(), )); - let call = add_account_call(bob.clone()); + let call = add_account_call::(bob.clone(), None); assert_ok!(OmniAccount::dispatch_as_omni_account( RuntimeOrigin::signed(tee_signer.clone()), alice().identity.hash(), @@ -239,7 +240,7 @@ fn add_account_with_already_linked_account_fails() { charlie().identity, )); - let call = add_account_call(public_member_account(alice())); + let call = add_account_call::(public_member_account(alice()), None); assert_ok!(OmniAccount::dispatch_as_omni_account( RuntimeOrigin::signed(tee_signer.clone()), charlie().identity.hash(), @@ -280,10 +281,10 @@ fn add_account_store_len_limit_reached_works() { AccountStore::::insert(alice().omni_account, member_accounts); - let call = add_account_call(MemberAccount::Private( - vec![7, 8, 9], - H256::from(blake2_256(&[7, 8, 9])), - )); + let call = add_account_call::( + MemberAccount::Private(vec![7, 8, 9], H256::from(blake2_256(&[7, 8, 9]))), + None, + ); assert_ok!(OmniAccount::dispatch_as_omni_account( RuntimeOrigin::signed(tee_signer.clone()), @@ -316,7 +317,7 @@ fn remove_account_works() { alice().identity, )); - let call = add_account_call(bob.clone()); + let call = add_account_call::(bob.clone(), None); assert_ok!(OmniAccount::dispatch_as_omni_account( RuntimeOrigin::signed(tee_signer.clone()), alice().identity.hash(), @@ -402,7 +403,7 @@ fn remove_account_empty_account_check_works() { )); let bob = private_member_account(bob()); - let call = add_account_call(bob); + let call = add_account_call::(bob, None); assert_ok!(OmniAccount::dispatch_as_omni_account( RuntimeOrigin::signed(tee_signer.clone()), alice().identity.hash(), @@ -442,7 +443,7 @@ fn publicize_account_works() { alice().identity.clone(), )); - let call = add_account_call(private_bob.clone()); + let call = add_account_call::(private_bob.clone(), None); assert_ok!(OmniAccount::dispatch_as_omni_account( RuntimeOrigin::signed(tee_signer.clone()), alice().identity.hash(), @@ -517,7 +518,7 @@ fn publicize_account_identity_not_found_works() { alice().identity, )); - let call = add_account_call(bob.clone()); + let call = add_account_call::(bob.clone(), None); assert_ok!(OmniAccount::dispatch_as_omni_account( RuntimeOrigin::signed(tee_signer.clone()), alice().identity.hash(), @@ -555,7 +556,7 @@ fn request_intent_works() { alice().identity )); - let call = add_account_call(bob); + let call = add_account_call::(bob, None); assert_ok!(OmniAccount::dispatch_as_omni_account( RuntimeOrigin::signed(tee_signer.clone()), alice().identity.hash(), @@ -602,7 +603,7 @@ fn dispatch_as_signed_works() { alice().identity, )); - let call = add_account_call(private_member_account(bob())); + let call = add_account_call::(private_member_account(bob()), None); assert_ok!(OmniAccount::dispatch_as_omni_account( RuntimeOrigin::signed(tee_signer.clone()), alice().identity.hash(), @@ -638,7 +639,7 @@ fn dispatch_as_omni_account_increments_omni_account_nonce() { assert_eq!(System::account_nonce(alice().omni_account), 0); - let call = add_account_call(bob.clone()); + let call = add_account_call::(bob.clone(), None); assert_ok!(OmniAccount::dispatch_as_omni_account( RuntimeOrigin::signed(tee_signer.clone()), alice().identity.hash(), From d673c04aecd6b70170be9992837691332da860b0 Mon Sep 17 00:00:00 2001 From: Francisco Silva Date: Fri, 13 Dec 2024 11:55:01 +0000 Subject: [PATCH 17/29] adding tests for permissions --- parachain/pallets/omni-account/src/tests.rs | 89 +++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/parachain/pallets/omni-account/src/tests.rs b/parachain/pallets/omni-account/src/tests.rs index f09afd9f56..f3c559b2da 100644 --- a/parachain/pallets/omni-account/src/tests.rs +++ b/parachain/pallets/omni-account/src/tests.rs @@ -677,3 +677,92 @@ fn dispatch_as_signed_account_increments_omni_account_nonce() { assert_eq!(System::account_nonce(alice().omni_account), 1); }); } + +#[test] +fn ensure_permission_works() { + new_test_ext().execute_with(|| { + // Create account store + let tee_signer = get_tee_signer(); + + assert_ok!(OmniAccount::create_account_store( + RuntimeOrigin::signed(tee_signer.clone()), + alice().identity, + )); + + // Add account member without permissions to remove accounts + let bob = private_member_account(bob()); + let bob_permissions = vec![Permission::RequestEthereumIntent, Permission::AddAccounts]; + + let call = add_account_call::(bob.clone(), Some(bob_permissions.clone())); + assert_ok!(OmniAccount::dispatch_as_omni_account( + RuntimeOrigin::signed(tee_signer.clone()), + alice().identity.hash(), + call, + )); + + // An account with no permissions cannot remove accounts + let call = remove_accounts_call(vec![alice().identity.hash()]); + assert_noop!( + OmniAccount::dispatch_as_omni_account( + RuntimeOrigin::signed(tee_signer.clone()), + bob.hash(), + call, + ), + Error::::NoPermission + ); + + // An Account cannot be added with more permissions than the account that added it + let charlie = private_member_account(charlie()); + let charlie_permissions = vec![Permission::All]; + let call = add_account_call::(charlie.clone(), Some(charlie_permissions)); + assert_noop!( + OmniAccount::dispatch_as_omni_account( + RuntimeOrigin::signed(tee_signer.clone()), + bob.hash(), + call, + ), + Error::::NoPermission + ); + + let mut charlie_permissions = vec![Permission::Balances]; + charlie_permissions.extend_from_slice(&bob_permissions); + let call = add_account_call::(charlie.clone(), Some(charlie_permissions)); + assert_noop!( + OmniAccount::dispatch_as_omni_account( + RuntimeOrigin::signed(tee_signer.clone()), + bob.hash(), + call, + ), + Error::::NoPermission + ); + + let charlie_permissions = vec![Permission::RequestEthereumIntent, Permission::AddAccounts]; + let call = add_account_call::(charlie, Some(charlie_permissions)); + assert_ok!(OmniAccount::dispatch_as_omni_account( + RuntimeOrigin::signed(tee_signer.clone()), + bob.hash(), + call, + )); + + // Permissions should also work for dispatch_as_signed + assert_ok!(Balances::transfer_keep_alive( + RuntimeOrigin::signed(alice().native_account), + alice().omni_account, + 6 + )); + let call = make_balance_transfer_call(dave().native_account, 5); + assert_noop!( + OmniAccount::dispatch_as_signed( + RuntimeOrigin::signed(tee_signer.clone()), + bob.hash(), + call.clone() + ), + Error::::NoPermission + ); + assert_ok!(OmniAccount::dispatch_as_signed( + RuntimeOrigin::signed(tee_signer), + alice().identity.hash(), + call + )); + }); +} From ae2444b68aa60c773f4ebfe2264b9bec0ef982d5 Mon Sep 17 00:00:00 2001 From: Francisco Silva Date: Fri, 13 Dec 2024 13:14:02 +0000 Subject: [PATCH 18/29] updating mock --- parachain/pallets/omni-account/src/mock.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/parachain/pallets/omni-account/src/mock.rs b/parachain/pallets/omni-account/src/mock.rs index ad464295c6..f3de2d65ee 100644 --- a/parachain/pallets/omni-account/src/mock.rs +++ b/parachain/pallets/omni-account/src/mock.rs @@ -193,17 +193,17 @@ impl Default for Permission { impl InstanceFilter for Permission { fn filter(&self, call: &RuntimeCall) -> bool { match self { - Permission::All => true, - Permission::Balances => matches!(call, RuntimeCall::Balances { .. }), - Permission::RemoveAccounts => matches!( + Self::All => true, + Self::Balances => matches!(call, RuntimeCall::Balances { .. }), + Self::RemoveAccounts => matches!( call, RuntimeCall::OmniAccount(pallet_omni_account::Call::remove_accounts { .. }) ), - Permission::AddAccounts => matches!( + Self::AddAccounts => matches!( call, RuntimeCall::OmniAccount(pallet_omni_account::Call::add_account { .. }) ), - Permission::RequestEthereumIntent => { + Self::RequestEthereumIntent => { if let RuntimeCall::OmniAccount(pallet_omni_account::Call::request_intent { intent, }) = call From 34544626892b0d946edd3627778ac313725e78c4 Mon Sep 17 00:00:00 2001 From: Francisco Silva Date: Fri, 13 Dec 2024 13:34:00 +0000 Subject: [PATCH 19/29] adding Permission type to runtimes --- parachain/runtime/litentry/src/lib.rs | 86 +++++++++++++++++++++++++++ parachain/runtime/paseo/src/lib.rs | 86 +++++++++++++++++++++++++++ 2 files changed, 172 insertions(+) diff --git a/parachain/runtime/litentry/src/lib.rs b/parachain/runtime/litentry/src/lib.rs index ff555e4d85..b1416f43f2 100644 --- a/parachain/runtime/litentry/src/lib.rs +++ b/parachain/runtime/litentry/src/lib.rs @@ -1112,6 +1112,90 @@ impl pallet_identity_management::Config for Runtime { type MaxOIDCClientRedirectUris = ConstU32<10>; } +#[derive( + Copy, + Clone, + PartialEq, + Eq, + Ord, + PartialOrd, + Encode, + Decode, + MaxEncodedLen, + RuntimeDebug, + scale_info::TypeInfo, +)] +pub enum OmniAccountPermission { + All, + AccountManagement, + RequestNativeIntent, + RequestEthereumIntent, + RequestSolanaIntent, +} + +impl Default for OmniAccountPermission { + fn default() -> Self { + Self::All + } +} + +impl InstanceFilter for OmniAccountPermission { + fn filter(&self, call: &RuntimeCall) -> bool { + match self { + Self::All => true, + Self::AccountManagement => { + matches!( + call, + RuntimeCall::OmniAccount(pallet_omni_account::Call::add_account { .. }) + | RuntimeCall::OmniAccount( + pallet_omni_account::Call::remove_accounts { .. } + ) | RuntimeCall::OmniAccount( + pallet_omni_account::Call::publicize_account { .. } + ) + ) + }, + Self::RequestNativeIntent => { + if let RuntimeCall::OmniAccount(pallet_omni_account::Call::request_intent { + intent, + }) = call + { + matches!( + intent, + pallet_omni_account::Intent::SystemRemark(_) + | pallet_omni_account::Intent::TransferNative(_) + ) + } else { + false + } + }, + Self::RequestEthereumIntent => { + if let RuntimeCall::OmniAccount(pallet_omni_account::Call::request_intent { + intent, + }) = call + { + matches!( + intent, + pallet_omni_account::Intent::TransferEthereum(_) + | pallet_omni_account::Intent::CallEthereum(_) + ) + } else { + false + } + }, + Self::RequestSolanaIntent => { + if let RuntimeCall::OmniAccount(pallet_omni_account::Call::request_intent { + intent, + }) = call + { + matches!(intent, pallet_omni_account::Intent::TransferSolana(_)) + } else { + false + } + }, + } + } +} + impl pallet_omni_account::Config for Runtime { type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; @@ -1120,6 +1204,8 @@ impl pallet_omni_account::Config for Runtime { type MaxAccountStoreLength = ConstU32<64>; type OmniAccountOrigin = EnsureOmniAccount; type OmniAccountConverter = DefaultOmniAccountConverter; + type MaxPermissions = ConstU32<4>; + type Permission = OmniAccountPermission; } impl pallet_evm_assertions::Config for Runtime { diff --git a/parachain/runtime/paseo/src/lib.rs b/parachain/runtime/paseo/src/lib.rs index ea8c148dc5..a2732f2e9f 100644 --- a/parachain/runtime/paseo/src/lib.rs +++ b/parachain/runtime/paseo/src/lib.rs @@ -1156,6 +1156,90 @@ impl pallet_identity_management::Config for Runtime { type MaxOIDCClientRedirectUris = ConstU32<10>; } +#[derive( + Copy, + Clone, + PartialEq, + Eq, + Ord, + PartialOrd, + Encode, + Decode, + MaxEncodedLen, + RuntimeDebug, + scale_info::TypeInfo, +)] +pub enum OmniAccountPermission { + All, + AccountManagement, + RequestNativeIntent, + RequestEthereumIntent, + RequestSolanaIntent, +} + +impl Default for OmniAccountPermission { + fn default() -> Self { + Self::All + } +} + +impl InstanceFilter for OmniAccountPermission { + fn filter(&self, call: &RuntimeCall) -> bool { + match self { + Self::All => true, + Self::AccountManagement => { + matches!( + call, + RuntimeCall::OmniAccount(pallet_omni_account::Call::add_account { .. }) + | RuntimeCall::OmniAccount( + pallet_omni_account::Call::remove_accounts { .. } + ) | RuntimeCall::OmniAccount( + pallet_omni_account::Call::publicize_account { .. } + ) + ) + }, + Self::RequestNativeIntent => { + if let RuntimeCall::OmniAccount(pallet_omni_account::Call::request_intent { + intent, + }) = call + { + matches!( + intent, + pallet_omni_account::Intent::SystemRemark(_) + | pallet_omni_account::Intent::TransferNative(_) + ) + } else { + false + } + }, + Self::RequestEthereumIntent => { + if let RuntimeCall::OmniAccount(pallet_omni_account::Call::request_intent { + intent, + }) = call + { + matches!( + intent, + pallet_omni_account::Intent::TransferEthereum(_) + | pallet_omni_account::Intent::CallEthereum(_) + ) + } else { + false + } + }, + Self::RequestSolanaIntent => { + if let RuntimeCall::OmniAccount(pallet_omni_account::Call::request_intent { + intent, + }) = call + { + matches!(intent, pallet_omni_account::Intent::TransferSolana(_)) + } else { + false + } + }, + } + } +} + impl pallet_omni_account::Config for Runtime { type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; @@ -1164,6 +1248,8 @@ impl pallet_omni_account::Config for Runtime { type MaxAccountStoreLength = ConstU32<64>; type OmniAccountOrigin = EnsureOmniAccount; type OmniAccountConverter = DefaultOmniAccountConverter; + type MaxPermissions = ConstU32<4>; + type Permission = OmniAccountPermission; } impl pallet_evm_assertions::Config for Runtime { From 5b36919359d835e6a44604bee3245f4d4254dde0 Mon Sep 17 00:00:00 2001 From: Francisco Silva Date: Fri, 13 Dec 2024 15:32:14 +0000 Subject: [PATCH 20/29] updating permissions mock and tests --- parachain/pallets/omni-account/src/mock.rs | 60 +++++++++++++++------ parachain/pallets/omni-account/src/tests.rs | 41 +++++++++----- 2 files changed, 72 insertions(+), 29 deletions(-) diff --git a/parachain/pallets/omni-account/src/mock.rs b/parachain/pallets/omni-account/src/mock.rs index f3de2d65ee..c6cd643d1c 100644 --- a/parachain/pallets/omni-account/src/mock.rs +++ b/parachain/pallets/omni-account/src/mock.rs @@ -176,33 +176,49 @@ impl pallet_teebag::Config for Test { MaxEncodedLen, scale_info::TypeInfo, )] -pub enum Permission { +pub enum OmniAccountPermission { All, - Balances, - AddAccounts, - RemoveAccounts, + AccountManagement, + RequestNativeIntent, RequestEthereumIntent, + RequestSolanaIntent, } -impl Default for Permission { +impl Default for OmniAccountPermission { fn default() -> Self { Self::All } } -impl InstanceFilter for Permission { +impl InstanceFilter for OmniAccountPermission { fn filter(&self, call: &RuntimeCall) -> bool { match self { Self::All => true, - Self::Balances => matches!(call, RuntimeCall::Balances { .. }), - Self::RemoveAccounts => matches!( - call, - RuntimeCall::OmniAccount(pallet_omni_account::Call::remove_accounts { .. }) - ), - Self::AddAccounts => matches!( - call, - RuntimeCall::OmniAccount(pallet_omni_account::Call::add_account { .. }) - ), + Self::AccountManagement => { + matches!( + call, + RuntimeCall::OmniAccount(pallet_omni_account::Call::add_account { .. }) + | RuntimeCall::OmniAccount( + pallet_omni_account::Call::remove_accounts { .. } + ) | RuntimeCall::OmniAccount( + pallet_omni_account::Call::publicize_account { .. } + ) + ) + }, + Self::RequestNativeIntent => { + if let RuntimeCall::OmniAccount(pallet_omni_account::Call::request_intent { + intent, + }) = call + { + matches!( + intent, + pallet_omni_account::Intent::SystemRemark(_) + | pallet_omni_account::Intent::TransferNative(_) + ) + } else { + false + } + }, Self::RequestEthereumIntent => { if let RuntimeCall::OmniAccount(pallet_omni_account::Call::request_intent { intent, @@ -217,6 +233,16 @@ impl InstanceFilter for Permission { false } }, + Self::RequestSolanaIntent => { + if let RuntimeCall::OmniAccount(pallet_omni_account::Call::request_intent { + intent, + }) = call + { + matches!(intent, pallet_omni_account::Intent::TransferSolana(_)) + } else { + false + } + }, } } } @@ -229,8 +255,8 @@ impl pallet_omni_account::Config for Test { type MaxAccountStoreLength = ConstU32<3>; type OmniAccountOrigin = EnsureOmniAccount; type OmniAccountConverter = DefaultOmniAccountConverter; - type MaxPermissions = ConstU32<3>; - type Permission = Permission; + type MaxPermissions = ConstU32<4>; + type Permission = OmniAccountPermission; } pub fn get_tee_signer() -> SystemAccountId { diff --git a/parachain/pallets/omni-account/src/tests.rs b/parachain/pallets/omni-account/src/tests.rs index f3c559b2da..ae409a28d7 100644 --- a/parachain/pallets/omni-account/src/tests.rs +++ b/parachain/pallets/omni-account/src/tests.rs @@ -22,7 +22,7 @@ use sp_core::H160; use sp_runtime::{traits::BadOrigin, ModuleError}; use sp_std::vec; -fn add_account_call>( +fn add_account_call>( account: MemberAccount, permissions: Option::Permission>>, ) -> Box { @@ -170,12 +170,12 @@ fn add_account_works() { assert!(MemberAccountPermissions::::contains_key(bob.hash())); assert_eq!( MemberAccountPermissions::::get(bob.hash()).to_vec(), - vec![Permission::All] + vec![OmniAccountPermission::All] ); assert!(MemberAccountPermissions::::contains_key(charlie.hash())); assert_eq!( MemberAccountPermissions::::get(charlie.hash()).to_vec(), - vec![Permission::All] + vec![OmniAccountPermission::All] ); }); } @@ -691,7 +691,11 @@ fn ensure_permission_works() { // Add account member without permissions to remove accounts let bob = private_member_account(bob()); - let bob_permissions = vec![Permission::RequestEthereumIntent, Permission::AddAccounts]; + let bob_permissions = vec![ + OmniAccountPermission::RequestEthereumIntent, + OmniAccountPermission::RequestSolanaIntent, + OmniAccountPermission::AccountManagement, + ]; let call = add_account_call::(bob.clone(), Some(bob_permissions.clone())); assert_ok!(OmniAccount::dispatch_as_omni_account( @@ -700,8 +704,9 @@ fn ensure_permission_works() { call, )); - // An account with no permissions cannot remove accounts - let call = remove_accounts_call(vec![alice().identity.hash()]); + // An Account cannot be added with more permissions than the account that added it + let charlie = private_member_account(charlie()); + let call = add_account_call::(charlie.clone(), None); // default permission assert_noop!( OmniAccount::dispatch_as_omni_account( RuntimeOrigin::signed(tee_signer.clone()), @@ -711,9 +716,7 @@ fn ensure_permission_works() { Error::::NoPermission ); - // An Account cannot be added with more permissions than the account that added it - let charlie = private_member_account(charlie()); - let charlie_permissions = vec![Permission::All]; + let charlie_permissions = vec![OmniAccountPermission::All]; let call = add_account_call::(charlie.clone(), Some(charlie_permissions)); assert_noop!( OmniAccount::dispatch_as_omni_account( @@ -724,7 +727,7 @@ fn ensure_permission_works() { Error::::NoPermission ); - let mut charlie_permissions = vec![Permission::Balances]; + let mut charlie_permissions = vec![OmniAccountPermission::RequestNativeIntent]; charlie_permissions.extend_from_slice(&bob_permissions); let call = add_account_call::(charlie.clone(), Some(charlie_permissions)); assert_noop!( @@ -736,14 +739,28 @@ fn ensure_permission_works() { Error::::NoPermission ); - let charlie_permissions = vec![Permission::RequestEthereumIntent, Permission::AddAccounts]; - let call = add_account_call::(charlie, Some(charlie_permissions)); + let charlie_permissions = vec![ + OmniAccountPermission::RequestEthereumIntent, + OmniAccountPermission::RequestSolanaIntent, + ]; + let call = add_account_call::(charlie.clone(), Some(charlie_permissions)); assert_ok!(OmniAccount::dispatch_as_omni_account( RuntimeOrigin::signed(tee_signer.clone()), bob.hash(), call, )); + // An account with no permissions cannot remove accounts + let call = remove_accounts_call(vec![alice().identity.hash()]); + assert_noop!( + OmniAccount::dispatch_as_omni_account( + RuntimeOrigin::signed(tee_signer.clone()), + charlie.hash(), + call, + ), + Error::::NoPermission + ); + // Permissions should also work for dispatch_as_signed assert_ok!(Balances::transfer_keep_alive( RuntimeOrigin::signed(alice().native_account), From 7d0663cd00561f2bfb1b79e5c133f08f458f81e3 Mon Sep 17 00:00:00 2001 From: Francisco Silva Date: Fri, 13 Dec 2024 16:06:12 +0000 Subject: [PATCH 21/29] adding set_permissions call --- parachain/pallets/omni-account/src/lib.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/parachain/pallets/omni-account/src/lib.rs b/parachain/pallets/omni-account/src/lib.rs index 9a045ace99..b3ab9131c7 100644 --- a/parachain/pallets/omni-account/src/lib.rs +++ b/parachain/pallets/omni-account/src/lib.rs @@ -188,6 +188,8 @@ pub mod pallet { IntentRequested { who: T::AccountId, intent: Intent }, /// Intent is executed IntentExecuted { who: T::AccountId, intent: Intent, result: IntentExecutionResult }, + /// Member permission set + AccountPermissionsSet { who: T::AccountId, member_account_hash: H256 }, } #[pallet::error] @@ -422,6 +424,21 @@ pub mod pallet { Self::deposit_event(Event::IntentExecuted { who, intent, result }); Ok(()) } + + #[pallet::call_index(9)] + #[pallet::weight((195_000_000, DispatchClass::Normal))] + pub fn set_permissions( + origin: OriginFor, + member_account_hash: H256, + permissions: Vec, + ) -> DispatchResult { + let who = T::OmniAccountOrigin::ensure_origin(origin)?; + let member_permissions: BoundedVec = + { permissions.try_into().map_err(|_| Error::::PermissionsLenLimitReached)? }; + MemberAccountPermissions::::insert(member_account_hash, member_permissions); + Self::deposit_event(Event::AccountPermissionsSet { who, member_account_hash }); + Ok(()) + } } impl Pallet { From 44bc0b1c64d716d8b6e65fc580adc868ff476de5 Mon Sep 17 00:00:00 2001 From: Francisco Silva Date: Fri, 13 Dec 2024 16:06:33 +0000 Subject: [PATCH 22/29] adjusting ensure_permission --- parachain/pallets/omni-account/src/lib.rs | 46 +++++++++++++++-------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/parachain/pallets/omni-account/src/lib.rs b/parachain/pallets/omni-account/src/lib.rs index b3ab9131c7..c9fd1a0baf 100644 --- a/parachain/pallets/omni-account/src/lib.rs +++ b/parachain/pallets/omni-account/src/lib.rs @@ -493,21 +493,37 @@ pub mod pallet { Error::::NoPermission ); - if let Some(Call::add_account { permissions: ref new_account_permissions, .. }) = - call.is_sub_type() - { - // If member has default permission, they can add accounts with any permission - if member_permissions.contains(&T::Permission::default()) { - return Ok(()); - } - - if let Some(new_account_permissions) = new_account_permissions { - // an account can only add another account with the same or less permissions - ensure!( - new_account_permissions.iter().all(|p| member_permissions.contains(p)), - Error::::NoPermission - ) - } + match call.is_sub_type() { + Some(Call::add_account { permissions: ref new_account_permissions, .. }) => { + // If member has default permission, they can add accounts with any permission + if member_permissions.contains(&T::Permission::default()) { + return Ok(()); + } + match new_account_permissions { + Some(new_permissions) => { + // an account can only add another account with the same or less permissions + if !new_permissions.iter().all(|p| member_permissions.contains(p)) { + return Err(Error::::NoPermission); + } + }, + None => { + // None is equivalent to default permission. It should not be allowed + // if the member_permissions have no default permission + return Err(Error::::NoPermission); + }, + } + }, + Some(Call::set_permissions { permissions: ref new_permissions, .. }) => { + // If member has default permission, they can set permissions to any value + if member_permissions.contains(&T::Permission::default()) { + return Ok(()); + } + // an account can only set permissions to the same or less permissions + if !new_permissions.iter().all(|p| member_permissions.contains(p)) { + return Err(Error::::NoPermission); + } + }, + _ => return Ok(()), } Ok(()) From 0984565ef048f6f5e0ae312c0c64e7e44822c4e5 Mon Sep 17 00:00:00 2001 From: Francisco Silva Date: Fri, 13 Dec 2024 16:06:49 +0000 Subject: [PATCH 23/29] updating mock --- parachain/pallets/omni-account/src/mock.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parachain/pallets/omni-account/src/mock.rs b/parachain/pallets/omni-account/src/mock.rs index c6cd643d1c..1c51bff75f 100644 --- a/parachain/pallets/omni-account/src/mock.rs +++ b/parachain/pallets/omni-account/src/mock.rs @@ -202,7 +202,7 @@ impl InstanceFilter for OmniAccountPermission { pallet_omni_account::Call::remove_accounts { .. } ) | RuntimeCall::OmniAccount( pallet_omni_account::Call::publicize_account { .. } - ) + ) | RuntimeCall::OmniAccount(pallet_omni_account::Call::set_permissions { .. }) ) }, Self::RequestNativeIntent => { From e04a8c098accbf06d8d94b920a3ee766941f48d2 Mon Sep 17 00:00:00 2001 From: Francisco Silva Date: Fri, 13 Dec 2024 16:07:00 +0000 Subject: [PATCH 24/29] updating permission filters in the runtimes --- parachain/runtime/litentry/src/lib.rs | 2 +- parachain/runtime/paseo/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/parachain/runtime/litentry/src/lib.rs b/parachain/runtime/litentry/src/lib.rs index b1416f43f2..80e06926d1 100644 --- a/parachain/runtime/litentry/src/lib.rs +++ b/parachain/runtime/litentry/src/lib.rs @@ -1151,7 +1151,7 @@ impl InstanceFilter for OmniAccountPermission { pallet_omni_account::Call::remove_accounts { .. } ) | RuntimeCall::OmniAccount( pallet_omni_account::Call::publicize_account { .. } - ) + ) | RuntimeCall::OmniAccount(pallet_omni_account::Call::set_permissions { .. }) ) }, Self::RequestNativeIntent => { diff --git a/parachain/runtime/paseo/src/lib.rs b/parachain/runtime/paseo/src/lib.rs index a2732f2e9f..8fbbce8fee 100644 --- a/parachain/runtime/paseo/src/lib.rs +++ b/parachain/runtime/paseo/src/lib.rs @@ -1195,7 +1195,7 @@ impl InstanceFilter for OmniAccountPermission { pallet_omni_account::Call::remove_accounts { .. } ) | RuntimeCall::OmniAccount( pallet_omni_account::Call::publicize_account { .. } - ) + ) | RuntimeCall::OmniAccount(pallet_omni_account::Call::set_permissions { .. }) ) }, Self::RequestNativeIntent => { From 63784d00114277af7936f038fc600587ed45f8c1 Mon Sep 17 00:00:00 2001 From: Francisco Silva Date: Fri, 13 Dec 2024 16:07:37 +0000 Subject: [PATCH 25/29] adding tests for set_permissions call --- parachain/pallets/omni-account/src/tests.rs | 103 ++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/parachain/pallets/omni-account/src/tests.rs b/parachain/pallets/omni-account/src/tests.rs index ae409a28d7..7cc813cd81 100644 --- a/parachain/pallets/omni-account/src/tests.rs +++ b/parachain/pallets/omni-account/src/tests.rs @@ -51,6 +51,15 @@ fn make_balance_transfer_call(dest: AccountId, value: Balance) -> Box, +) -> Box { + let call = + RuntimeCall::OmniAccount(crate::Call::set_permissions { member_account_hash, permissions }); + Box::new(call) +} + #[test] fn create_account_store_works() { new_test_ext().execute_with(|| { @@ -783,3 +792,97 @@ fn ensure_permission_works() { )); }); } + +#[test] +fn set_permissions_works() { + new_test_ext().execute_with(|| { + // Create account store and add accounts + let tee_signer = get_tee_signer(); + + assert_ok!(OmniAccount::create_account_store( + RuntimeOrigin::signed(tee_signer.clone()), + alice().identity, + )); + + let bob = private_member_account(bob()); + let bob_permissions = vec![ + OmniAccountPermission::RequestEthereumIntent, + OmniAccountPermission::RequestSolanaIntent, + OmniAccountPermission::AccountManagement, + ]; + + let call = add_account_call::(bob.clone(), Some(bob_permissions.clone())); + assert_ok!(OmniAccount::dispatch_as_omni_account( + RuntimeOrigin::signed(tee_signer.clone()), + alice().identity.hash(), + call, + )); + + let charlie = private_member_account(charlie()); + let charlie_permissions = vec![OmniAccountPermission::RequestNativeIntent]; + let call = add_account_call::(charlie.clone(), Some(charlie_permissions.clone())); + assert_ok!(OmniAccount::dispatch_as_omni_account( + RuntimeOrigin::signed(tee_signer.clone()), + alice().identity.hash(), + call, + )); + + // Assert Set permissions + + // The caller cannot upgrade his permissions + let new_permissions = vec![OmniAccountPermission::All]; + let call = set_permissions_call(bob.hash(), new_permissions.clone()); + assert_noop!( + OmniAccount::dispatch_as_omni_account( + RuntimeOrigin::signed(tee_signer.clone()), + bob.hash(), + call, + ), + Error::::NoPermission + ); + + // The caller cannot set a permission that he does not have + let new_permissions = vec![OmniAccountPermission::RequestNativeIntent]; + let call = set_permissions_call(alice().identity.hash(), new_permissions.clone()); + assert_noop!( + OmniAccount::dispatch_as_omni_account( + RuntimeOrigin::signed(tee_signer.clone()), + bob.hash(), + call, + ), + Error::::NoPermission + ); + + // The caller can set permissions he has + let new_permissions = vec![ + OmniAccountPermission::AccountManagement, + OmniAccountPermission::RequestSolanaIntent, + ]; + let call = set_permissions_call(charlie.hash(), new_permissions.clone()); + assert_ok!(OmniAccount::dispatch_as_omni_account( + RuntimeOrigin::signed(tee_signer.clone()), + bob.hash(), + call, + )); + + // The caller most have permission to set_permissions + let call = set_permissions_call(bob.hash(), charlie_permissions); + assert_noop!( + OmniAccount::dispatch_as_omni_account( + RuntimeOrigin::signed(tee_signer.clone()), + charlie.hash(), + call, + ), + Error::::NoPermission + ); + + // The caller can set any permissions as if she has default permissions (All) + let new_permissions = vec![OmniAccountPermission::All]; + let call = set_permissions_call(charlie.hash(), new_permissions.clone()); + assert_ok!(OmniAccount::dispatch_as_omni_account( + RuntimeOrigin::signed(tee_signer.clone()), + alice().identity.hash(), + call, + )); + }); +} From a893cd662e43757390402c36466a618b38e21117 Mon Sep 17 00:00:00 2001 From: Francisco Silva Date: Fri, 13 Dec 2024 16:53:36 +0000 Subject: [PATCH 26/29] adding temporary fix for add_account --- .../identity/litentry/core/native-task/receiver/src/lib.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tee-worker/identity/litentry/core/native-task/receiver/src/lib.rs b/tee-worker/identity/litentry/core/native-task/receiver/src/lib.rs index 719bc0ef80..4fc9be5d06 100644 --- a/tee-worker/identity/litentry/core/native-task/receiver/src/lib.rs +++ b/tee-worker/identity/litentry/core/native-task/receiver/src/lib.rs @@ -384,6 +384,10 @@ fn handle_trusted_call> = None; // default permissions + OpaqueCall::from_tuple(&compose_call!( &metadata, "OmniAccount", @@ -393,7 +397,8 @@ fn handle_trusted_call Date: Sat, 14 Dec 2024 09:35:02 +0000 Subject: [PATCH 27/29] update storage on remove accounts --- parachain/pallets/omni-account/src/lib.rs | 1 + parachain/pallets/omni-account/src/tests.rs | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/parachain/pallets/omni-account/src/lib.rs b/parachain/pallets/omni-account/src/lib.rs index c9fd1a0baf..2960a670f9 100644 --- a/parachain/pallets/omni-account/src/lib.rs +++ b/parachain/pallets/omni-account/src/lib.rs @@ -321,6 +321,7 @@ pub mod pallet { member_accounts.retain(|member| { if member_account_hashes.contains(&member.hash()) { MemberAccountHash::::remove(member.hash()); + MemberAccountPermissions::::remove(member.hash()); false } else { true diff --git a/parachain/pallets/omni-account/src/tests.rs b/parachain/pallets/omni-account/src/tests.rs index 7cc813cd81..d30e0d2008 100644 --- a/parachain/pallets/omni-account/src/tests.rs +++ b/parachain/pallets/omni-account/src/tests.rs @@ -175,13 +175,13 @@ fn add_account_works() { ); assert!(MemberAccountHash::::contains_key(bob.hash())); - assert!(MemberAccountHash::::contains_key(charlie.hash())); assert!(MemberAccountPermissions::::contains_key(bob.hash())); + assert!(MemberAccountHash::::contains_key(charlie.hash())); + assert!(MemberAccountPermissions::::contains_key(charlie.hash())); assert_eq!( MemberAccountPermissions::::get(bob.hash()).to_vec(), vec![OmniAccountPermission::All] ); - assert!(MemberAccountPermissions::::contains_key(charlie.hash())); assert_eq!( MemberAccountPermissions::::get(charlie.hash()).to_vec(), vec![OmniAccountPermission::All] @@ -389,6 +389,7 @@ fn remove_account_works() { expected_member_accounts ); assert!(!MemberAccountHash::::contains_key(bob.hash())); + assert!(!MemberAccountPermissions::::contains_key(bob.hash())); let call = remove_accounts_call(vec![alice().identity.hash()]); assert_ok!(OmniAccount::dispatch_as_omni_account( From ade319b60323b976a693eea5e14f12428d656e1a Mon Sep 17 00:00:00 2001 From: Francisco Silva Date: Mon, 16 Dec 2024 15:31:41 +0000 Subject: [PATCH 28/29] setting default permission when empty, only if the sender has default permission --- parachain/pallets/omni-account/src/lib.rs | 18 ++++++++++-------- parachain/pallets/omni-account/src/tests.rs | 2 +- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/parachain/pallets/omni-account/src/lib.rs b/parachain/pallets/omni-account/src/lib.rs index 2960a670f9..d724e324af 100644 --- a/parachain/pallets/omni-account/src/lib.rs +++ b/parachain/pallets/omni-account/src/lib.rs @@ -285,13 +285,13 @@ pub mod pallet { member_accounts .try_push(member_account) .map_err(|_| Error::::AccountStoreLenLimitReached)?; - let member_permissions: BoundedVec = { - let p = match permissions { - Some(p) => p, - None => vec![T::Permission::default()], - }; - p.try_into().map_err(|_| Error::::PermissionsLenLimitReached)? - }; + let member_permissions: BoundedVec = permissions + .map_or_else( + || vec![T::Permission::default()], + |p| if p.is_empty() { vec![T::Permission::default()] } else { p }, + ) + .try_into() + .map_err(|_| Error::::PermissionsLenLimitReached)?; MemberAccountHash::::insert(hash, who.clone()); MemberAccountPermissions::::insert(hash, member_permissions); @@ -503,7 +503,9 @@ pub mod pallet { match new_account_permissions { Some(new_permissions) => { // an account can only add another account with the same or less permissions - if !new_permissions.iter().all(|p| member_permissions.contains(p)) { + if new_permissions.is_empty() + || !new_permissions.iter().all(|p| member_permissions.contains(p)) + { return Err(Error::::NoPermission); } }, diff --git a/parachain/pallets/omni-account/src/tests.rs b/parachain/pallets/omni-account/src/tests.rs index d30e0d2008..451fe6a1fd 100644 --- a/parachain/pallets/omni-account/src/tests.rs +++ b/parachain/pallets/omni-account/src/tests.rs @@ -123,7 +123,7 @@ fn add_account_works() { alice().identity, )); - let call = add_account_call::(bob.clone(), None); + let call = add_account_call::(bob.clone(), Some(vec![])); assert_ok!(OmniAccount::dispatch_as_omni_account( RuntimeOrigin::signed(tee_signer.clone()), alice().identity.hash(), From 0a29a43cc17653e7a07cd7dbc755c413e2e42d9d Mon Sep 17 00:00:00 2001 From: Francisco Silva Date: Tue, 17 Dec 2024 11:42:20 +0100 Subject: [PATCH 29/29] Adjusting worker to allow managing AccountStore member permissions (#3210) --- common/primitives/core/src/omni_account.rs | 10 ++++ .../identity/app-libs/stf/src/trusted_call.rs | 13 +++-- .../interfaces/omniAccount/definitions.ts | 3 ++ .../trusted_operations/definitions.ts | 3 +- .../core/native-task/receiver/src/lib.rs | 20 +++++-- .../common/utils/native-request-helpers.ts | 44 +++++++++++++-- .../native_request_vc.test.ts | 10 ++-- .../integration-tests/omni_account.test.ts | 53 ++++++++++++++++++- 8 files changed, 138 insertions(+), 18 deletions(-) diff --git a/common/primitives/core/src/omni_account.rs b/common/primitives/core/src/omni_account.rs index fb2adc411f..f86227bf5b 100644 --- a/common/primitives/core/src/omni_account.rs +++ b/common/primitives/core/src/omni_account.rs @@ -57,3 +57,13 @@ impl OmniAccountConverter for DefaultOmniAccountConverter { identity.to_omni_account() } } + +// This type must be kept in sync with the `Permission` type used in the runtime. +#[derive(Encode, Decode, Clone, Debug, PartialEq, Eq)] +pub enum OmniAccountPermission { + All, + AccountManagement, + RequestNativeIntent, + RequestEthereumIntent, + RequestSolanaIntent, +} diff --git a/tee-worker/identity/app-libs/stf/src/trusted_call.rs b/tee-worker/identity/app-libs/stf/src/trusted_call.rs index 0ec7a6b566..afad348a0c 100644 --- a/tee-worker/identity/app-libs/stf/src/trusted_call.rs +++ b/tee-worker/identity/app-libs/stf/src/trusted_call.rs @@ -53,8 +53,8 @@ use itp_utils::stringify::account_id_to_string; use litentry_hex_utils::hex_encode; pub use litentry_primitives::{ aes_encrypt_default, all_evm_web3networks, all_substrate_web3networks, AesOutput, Assertion, - ErrorDetail, IMPError, Identity, Intent, LitentryMultiSignature, ParentchainBlockNumber, - RequestAesKey, VCMPError, ValidationData, Web3Network, + ErrorDetail, IMPError, Identity, Intent, LitentryMultiSignature, OmniAccountPermission, + ParentchainBlockNumber, RequestAesKey, VCMPError, ValidationData, Web3Network, }; use log::*; use sp_core::{ @@ -144,11 +144,13 @@ pub enum TrustedCall { #[codec(index = 27)] create_account_store(Identity), #[codec(index = 28)] - add_account(Identity, Identity, ValidationData, bool), + add_account(Identity, Identity, ValidationData, bool, Option>), #[codec(index = 29)] remove_accounts(Identity, Vec), #[codec(index = 30)] publicize_account(Identity, Identity), + #[codec(index = 31)] + set_permissions(Identity, Identity, Vec), // original integritee trusted calls, starting from index 50 #[codec(index = 50)] @@ -244,6 +246,7 @@ impl TrustedCall { Self::add_account(sender_identity, ..) => sender_identity, Self::remove_accounts(sender_identity, ..) => sender_identity, Self::publicize_account(sender_identity, ..) => sender_identity, + Self::set_permissions(sender_identity, ..) => sender_identity, } } @@ -262,6 +265,7 @@ impl TrustedCall { Self::add_account(..) => "add_account", Self::remove_accounts(..) => "remove_account", Self::publicize_account(..) => "publicize_account", + Self::set_permissions(..) => "set_permissions", _ => "unsupported_trusted_call", } } @@ -920,7 +924,8 @@ where | TrustedCall::create_account_store(..) | TrustedCall::add_account(..) | TrustedCall::remove_accounts(..) - | TrustedCall::publicize_account(..) => { + | TrustedCall::publicize_account(..) + | TrustedCall::set_permissions(..) => { error!("please use author_submitNativeRequest instead"); Ok(TrustedCallResult::Empty) }, diff --git a/tee-worker/identity/client-api/parachain-api/prepare-build/interfaces/omniAccount/definitions.ts b/tee-worker/identity/client-api/parachain-api/prepare-build/interfaces/omniAccount/definitions.ts index 31a433be2e..03ea397d7e 100644 --- a/tee-worker/identity/client-api/parachain-api/prepare-build/interfaces/omniAccount/definitions.ts +++ b/tee-worker/identity/client-api/parachain-api/prepare-build/interfaces/omniAccount/definitions.ts @@ -36,5 +36,8 @@ export default { Private: "(Bytes,H256)", }, }, + OmniAccountPermission: { + _enum: ["All", "AccountManagement", "RequestNativeIntent", "RequestEthereumIntent", "RequestSolanaIntent"], + }, }, }; diff --git a/tee-worker/identity/client-api/parachain-api/prepare-build/interfaces/trusted_operations/definitions.ts b/tee-worker/identity/client-api/parachain-api/prepare-build/interfaces/trusted_operations/definitions.ts index 260a989129..9a3d818f71 100644 --- a/tee-worker/identity/client-api/parachain-api/prepare-build/interfaces/trusted_operations/definitions.ts +++ b/tee-worker/identity/client-api/parachain-api/prepare-build/interfaces/trusted_operations/definitions.ts @@ -86,9 +86,10 @@ export default { clean_id_graphs: "(LitentryIdentity)", request_intent: "(LitentryIdentity, Intent)", create_account_store: "(LitentryIdentity)", - add_account: "(LitentryIdentity, LitentryIdentity, LitentryValidationData, bool)", + add_account: "(LitentryIdentity, LitentryIdentity, LitentryValidationData, bool, Option>)", remove_accounts: "(LitentryIdentity, Vec)", publicize_account: "(LitentryIdentity, LitentryIdentity)", + set_permissions: "(LitentryIdentity, LitentryIdentity, Vec)", }, }, TrustedOperationStatus: { diff --git a/tee-worker/identity/litentry/core/native-task/receiver/src/lib.rs b/tee-worker/identity/litentry/core/native-task/receiver/src/lib.rs index 4fc9be5d06..a2ef326732 100644 --- a/tee-worker/identity/litentry/core/native-task/receiver/src/lib.rs +++ b/tee-worker/identity/litentry/core/native-task/receiver/src/lib.rs @@ -322,7 +322,7 @@ fn handle_trusted_call { + TrustedCall::add_account(who, identity, validation_data, public_account, permissions) => { let omni_account = match get_omni_account(context.ocall_api.clone(), &who) { Ok(account) => account, Err(e) => { @@ -384,10 +384,6 @@ fn handle_trusted_call> = None; // default permissions - OpaqueCall::from_tuple(&compose_call!( &metadata, "OmniAccount", @@ -426,6 +422,20 @@ fn handle_trusted_call + OpaqueCall::from_tuple(&compose_call!( + &metadata, + "OmniAccount", + "dispatch_as_omni_account", + who.hash(), + OpaqueCall::from_tuple(&compose_call!( + &metadata, + "OmniAccount", + "set_permissions", + identity.hash(), + permissions + )) + )), TrustedCall::request_vc(signer, who, assertion, maybe_key, req_ext_hash) => { let result = handle_request_vc( context.clone(), diff --git a/tee-worker/identity/ts-tests/integration-tests/common/utils/native-request-helpers.ts b/tee-worker/identity/ts-tests/integration-tests/common/utils/native-request-helpers.ts index 252ad58ede..4e307bee44 100644 --- a/tee-worker/identity/ts-tests/integration-tests/common/utils/native-request-helpers.ts +++ b/tee-worker/identity/ts-tests/integration-tests/common/utils/native-request-helpers.ts @@ -12,6 +12,7 @@ import { TCAuthentication, Intent, LitentryValidationData, + OmniAccountPermission, } from 'parachain-api'; import { Signer, createLitentryMultiSignature } from '../utils'; import { aesKey } from '../call'; @@ -125,15 +126,38 @@ export async function createAuthenticatedTrustedCallAddAccount( senderIdentity: CorePrimitivesIdentity, identity: CorePrimitivesIdentity, validationData: string, - publicAccount = false + publicAccount = false, + permissions: OmniAccountPermission[] ) { return createAuthenticatedTrustedCall( parachainApi, - ['add_account', '(LitentryIdentity, LitentryIdentity, LitentryValidationData, bool)'], + [ + 'add_account', + '(LitentryIdentity, LitentryIdentity, LitentryValidationData, bool, Option>)', + ], sender, mrenclave, nonce, - [senderIdentity, identity, validationData, publicAccount] + [senderIdentity, identity, validationData, publicAccount, permissions] + ); +} + +export async function createAuthenticatedTrustedCallSetPermissions( + parachainApi: ApiPromise, + mrenclave: string, + nonce: Codec, + sender: Signer, + senderIdentity: CorePrimitivesIdentity, + identity: CorePrimitivesIdentity, + permissions: OmniAccountPermission[] +) { + return createAuthenticatedTrustedCall( + parachainApi, + ['set_permissions', '(LitentryIdentity, LitentryIdentity, Vec)'], + sender, + mrenclave, + nonce, + [senderIdentity, identity, permissions] ); } @@ -365,3 +389,17 @@ export async function buildWeb3ValidationData( throw new Error(`[buildValidation]: Unsupported network ${network}.`); } + +type OmniAccountPermissionString = + | 'All' + | 'AccountManagement' + | 'RequestNativeIntent' + | 'RequestEthereumIntent' + | 'RequestSolanaIntent'; + +export function createOmniAccountPermission( + api: ApiPromise, + permission: OmniAccountPermissionString +): OmniAccountPermission { + return api.createType('OmniAccountPermission', permission); +} diff --git a/tee-worker/identity/ts-tests/integration-tests/native_request_vc.test.ts b/tee-worker/identity/ts-tests/integration-tests/native_request_vc.test.ts index 998d79d88f..7746cf6979 100644 --- a/tee-worker/identity/ts-tests/integration-tests/native_request_vc.test.ts +++ b/tee-worker/identity/ts-tests/integration-tests/native_request_vc.test.ts @@ -30,6 +30,7 @@ import { createAuthenticatedTrustedCallAddAccount, createAuthenticatedTrustedCallRequestBatchVc, createAuthenticatedTrustedCallRequestVc, + createOmniAccountPermission, getOmniAccount, getOmniAccountNonce, sendRequestFromTrustedCall, @@ -126,7 +127,8 @@ describe('Test native vc_request', function () { aliceSubstrateIdentity, twitterIdentity, twitterValidationData.toHex(), - true // public account + true, // public account + [createOmniAccountPermission(context.api, 'All')] ); await sendRequestFromTrustedCall(context, teeShieldingKey, addTwitterAccountCall); accountStore = await context.api.query.omniAccount.accountStore(omniAccount); @@ -153,7 +155,8 @@ describe('Test native vc_request', function () { aliceSubstrateIdentity, evmIdentity, evmValidationData.toHex(), - true // public account + true, // public account + [createOmniAccountPermission(context.api, 'All')] ); await sendRequestFromTrustedCall(context, teeShieldingKey, addEvmAccountCall); accountStore = await context.api.query.omniAccount.accountStore(omniAccount); @@ -180,7 +183,8 @@ describe('Test native vc_request', function () { aliceSubstrateIdentity, bitcoinIdentity, bitcoinValidationData.toHex(), - true // public account + true, // public account + [createOmniAccountPermission(context.api, 'All')] ); await sendRequestFromTrustedCall(context, teeShieldingKey, addBitcoinAccountCall); accountStore = await context.api.query.omniAccount.accountStore(omniAccount); diff --git a/tee-worker/identity/ts-tests/integration-tests/omni_account.test.ts b/tee-worker/identity/ts-tests/integration-tests/omni_account.test.ts index 08134e7911..f45303a28a 100644 --- a/tee-worker/identity/ts-tests/integration-tests/omni_account.test.ts +++ b/tee-worker/identity/ts-tests/integration-tests/omni_account.test.ts @@ -19,6 +19,8 @@ import { createAuthenticatedTrustedCallPublicizeAccount, fundAccount, createAuthenticatedTrustedCallTransferNativeIntent, + createOmniAccountPermission, + createAuthenticatedTrustedCallSetPermissions, } from './common/utils/native-request-helpers'; import { CorePrimitivesIdentity, CorePrimitivesOmniAccountMemberAccount } from 'parachain-api'; import { encodeAddress } from '@polkadot/util-crypto'; @@ -87,7 +89,9 @@ describe('Omni Account', function () { aliceWallet, aliceIdentity, bobIdentity, - validationData.toHex() + validationData.toHex(), + false, + [createOmniAccountPermission(context.api, 'All')] ); await sendRequestFromTrustedCall(context, teeShieldingKey, addAccountCall); @@ -126,7 +130,8 @@ describe('Omni Account', function () { aliceIdentity, twitterIdentity, validationData.toHex(), - true // public account + true, // public account + [createOmniAccountPermission(context.api, 'All')] ); await sendRequestFromTrustedCall(context, teeShieldingKey, addAccountCall); @@ -232,4 +237,48 @@ describe('Omni Account', function () { 'omni account balance should be decreased by 10' ); }); + + step('test set_permissions', async function () { + const currentNonce = 5; + const bob = context.web3Wallets['substrate']['Bob'] as SubstrateSigner; + const bobIdentity = await bob.getIdentity(context); + + // current permissions + let accountPermissions = await context.api.query.omniAccount.memberAccountPermissions(bobIdentity.hash); + assert.equal(accountPermissions.length, 1, 'permissions length should be 1 before set permissions'); + assert.equal( + accountPermissions[0].toString(), + 'All', + 'permission is not the expected permission before set permissions' + ); + + const newPermissions = [ + createOmniAccountPermission(context.api, 'RequestNativeIntent'), + createOmniAccountPermission(context.api, 'RequestEthereumIntent'), + ]; + const setPermissionsCall = await createAuthenticatedTrustedCallSetPermissions( + context.api, + context.mrEnclave, + context.api.createType('Index', currentNonce), + aliceWallet, + aliceIdentity, + bobIdentity, + newPermissions + ); + await sendRequestFromTrustedCall(context, teeShieldingKey, setPermissionsCall); + + accountPermissions = await context.api.query.omniAccount.memberAccountPermissions(bobIdentity.hash); + + assert.equal(accountPermissions.length, 2, 'permissions length should be 2'); + assert.equal( + accountPermissions[0].toString(), + 'RequestNativeIntent', + 'permission 1 is not the expected permission' + ); + assert.equal( + accountPermissions[1].toString(), + 'RequestEthereumIntent', + 'permission 2 is not the expected permission' + ); + }); });