diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index a73f021d29..cb4a49f926 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -791,7 +791,7 @@ jobs:
- test_name: lit-di-substrate-identity-multiworker-test
- test_name: lit-dr-vc-multiworker-test
- test_name: lit-resume-worker
- name: ${{ matrix.test_name || 'identity-multi-worker-test' }}
+ name: ${{ matrix.test_name }}
steps:
- uses: actions/checkout@v4
diff --git a/parachain/Cargo.lock b/parachain/Cargo.lock
index 76618ffb6a..dfde196e33 100644
--- a/parachain/Cargo.lock
+++ b/parachain/Cargo.lock
@@ -11061,6 +11061,7 @@ dependencies = [
"pallet-membership",
"pallet-message-queue",
"pallet-multisig",
+ "pallet-omni-account",
"pallet-teebag",
"pallet-transaction-payment",
"pallet-treasury",
diff --git a/parachain/pallets/omni-account/src/lib.rs b/parachain/pallets/omni-account/src/lib.rs
index 228a5a1d53..c7adbfbfff 100644
--- a/parachain/pallets/omni-account/src/lib.rs
+++ b/parachain/pallets/omni-account/src/lib.rs
@@ -1,3 +1,19 @@
+// Copyright 2020-2024 Trust Computing GmbH.
+// This file is part of Litentry.
+//
+// Litentry is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Litentry is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Litentry. If not, see .
+
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(test)]
@@ -10,9 +26,15 @@ pub use frame_system::pallet_prelude::BlockNumberFor;
pub use pallet::*;
use frame_support::pallet_prelude::*;
+use frame_support::{
+ dispatch::{GetDispatchInfo, PostDispatchInfo},
+ traits::{IsSubType, UnfilteredDispatchable},
+};
use frame_system::pallet_prelude::*;
use sp_core::H256;
use sp_core_hashing::blake2_256;
+use sp_runtime::traits::Dispatchable;
+use sp_std::boxed::Box;
use sp_std::vec::Vec;
#[derive(Encode, Decode, TypeInfo, Clone, PartialEq, Eq, RuntimeDebug)]
@@ -36,6 +58,21 @@ impl IDGraphHash for BoundedVec {
}
}
+pub type MemberCount = u32;
+
+// Customized origin for this pallet, to:
+// 1. to decouple `TEECallOrigin` and extrinsic that should be sent from `OmniAccount` origin only
+// 2. allow other pallets to specify ensure_origin using this origin
+// 3. leave room for more delicate control over OmniAccount in the future (e.g. multisig-like control)
+#[derive(PartialEq, Eq, Clone, RuntimeDebug, Encode, Decode, TypeInfo, MaxEncodedLen)]
+#[codec(mel_bound(AccountId: MaxEncodedLen))]
+pub enum RawOrigin {
+ // dispatched from OmniAccount T::AccountId
+ OmniAccount(AccountId),
+ // dispatched by a given number of members of the OmniAccount IDGraph from a given total
+ OmniAccountMembers(AccountId, MemberCount, MemberCount),
+}
+
#[frame_support::pallet]
pub mod pallet {
use super::*;
@@ -50,21 +87,45 @@ pub mod pallet {
#[pallet::config]
pub trait Config: frame_system::Config {
- /// The event type of this pallet.
+ /// The runtime origin type
+ type RuntimeOrigin: From>
+ + From>;
+
+ /// The overarching call type
+ type RuntimeCall: Parameter
+ + Dispatchable<
+ RuntimeOrigin = ::RuntimeOrigin,
+ PostInfo = PostDispatchInfo,
+ > + GetDispatchInfo
+ + From>
+ + UnfilteredDispatchable::RuntimeOrigin>
+ + IsSubType>
+ + IsType<::RuntimeCall>;
+
+ /// The event type of this pallet
type RuntimeEvent: From> + IsType<::RuntimeEvent>;
- /// The origin which can manage the pallet.
- type TEECallOrigin: EnsureOrigin;
+ /// The origin that represents the off-chain worker
+ type TEECallOrigin: EnsureOrigin<::RuntimeOrigin>;
/// The maximum number of identities an id graph can have.
#[pallet::constant]
type MaxIDGraphLength: Get;
/// AccountId converter
type AccountIdConverter: AccountIdConverter;
+ /// The origin that represents the customised OmniAccount type
+ type OmniAccountOrigin: EnsureOrigin<
+ ::RuntimeOrigin,
+ Success = Self::AccountId,
+ >;
}
+
pub type IDGraph = BoundedVec::MaxIDGraphLength>;
+ #[pallet::origin]
+ pub type Origin = RawOrigin<::AccountId>;
+
#[pallet::storage]
pub type LinkedIdentityHashes =
- StorageMap;
+ StorageMap;
#[pallet::storage]
#[pallet::getter(fn id_graphs)]
@@ -85,6 +146,10 @@ pub mod pallet {
IdentityRemoved { who: T::AccountId, identity_hashes: Vec },
/// Identity made public
IdentityMadePublic { who: T::AccountId, identity_hash: H256 },
+ /// Some call is dispatched as omni-account origin
+ DispatchedAsOmniAccount { who: T::AccountId, result: DispatchResult },
+ /// Some call is dispatched as signed origin
+ DispatchedAsSigned { who: T::AccountId, result: DispatchResult },
}
#[pallet::error]
@@ -111,14 +176,56 @@ pub mod pallet {
#[pallet::call]
impl Pallet {
+ // dispatch the `call` as RawOrigin::OmniAccount
#[pallet::call_index(0)]
#[pallet::weight((195_000_000, DispatchClass::Normal))]
+ pub fn dispatch_as_omni_account(
+ origin: OriginFor,
+ account_hash: H256,
+ call: Box<::RuntimeCall>,
+ ) -> DispatchResult {
+ let _ = T::TEECallOrigin::ensure_origin(origin)?;
+ let omni_account =
+ LinkedIdentityHashes::::get(account_hash).ok_or(Error::::IdentityNotFound)?;
+ let result = call.dispatch(RawOrigin::OmniAccount(omni_account.clone()).into());
+ Self::deposit_event(Event::DispatchedAsOmniAccount {
+ who: omni_account,
+ result: result.map(|_| ()).map_err(|e| e.error),
+ });
+ Ok(())
+ }
+
+ // dispatch the `call` as the standard (frame_system) signed origin
+ // TODO: what about other customised origin like collective?
+ #[pallet::call_index(1)]
+ #[pallet::weight((195_000_000, DispatchClass::Normal))]
+ pub fn dispatch_as_signed(
+ origin: OriginFor,
+ account_hash: H256,
+ call: Box<::RuntimeCall>,
+ ) -> DispatchResult {
+ let _ = T::TEECallOrigin::ensure_origin(origin)?;
+ let omni_account =
+ LinkedIdentityHashes::::get(account_hash).ok_or(Error::::IdentityNotFound)?;
+ let result =
+ call.dispatch(frame_system::RawOrigin::Signed(omni_account.clone()).into());
+ Self::deposit_event(Event::DispatchedAsSigned {
+ who: omni_account,
+ result: result.map(|_| ()).map_err(|e| e.error),
+ });
+ Ok(())
+ }
+
+ #[pallet::call_index(2)]
+ #[pallet::weight((195_000_000, DispatchClass::Normal))]
pub fn link_identity(
origin: OriginFor,
who: Identity,
member_account: IDGraphMember,
maybe_id_graph_hash: Option,
) -> DispatchResult {
+ // We can't use `T::OmniAccountOrigin` here as the ownership of member account needs to
+ // be firstly validated by the TEE-worker before dispatching the extrinsic
let _ = T::TEECallOrigin::ensure_origin(origin)?;
ensure!(
!LinkedIdentityHashes::::contains_key(member_account.hash),
@@ -138,7 +245,7 @@ pub mod pallet {
.try_push(member_account)
.map_err(|_| Error::::IDGraphLenLimitReached)?;
- LinkedIdentityHashes::::insert(identity_hash, ());
+ LinkedIdentityHashes::::insert(identity_hash, who_account_id.clone());
IDGraphHashes::::insert(who_account_id.clone(), id_graph.graph_hash());
IDGraphs::::insert(who_account_id.clone(), id_graph);
@@ -150,23 +257,17 @@ pub mod pallet {
Ok(())
}
- #[pallet::call_index(4)]
+ #[pallet::call_index(3)]
#[pallet::weight((195_000_000, DispatchClass::Normal))]
pub fn remove_identities(
origin: OriginFor,
- who: Identity,
identity_hashes: Vec,
) -> DispatchResult {
- let _ = T::TEECallOrigin::ensure_origin(origin)?;
+ let who = T::OmniAccountOrigin::ensure_origin(origin)?;
ensure!(!identity_hashes.is_empty(), Error::::IdentitiesEmpty);
- let who_account_id = match T::AccountIdConverter::convert(&who) {
- Some(account_id) => account_id,
- None => return Err(Error::::InvalidIdentity.into()),
- };
-
let mut id_graph_members =
- IDGraphs::::get(&who_account_id).ok_or(Error::::UnknownIDGraph)?;
+ IDGraphs::::get(&who).ok_or(Error::::UnknownIDGraph)?;
id_graph_members.retain(|member| {
if identity_hashes.contains(&member.hash) {
@@ -178,43 +279,37 @@ pub mod pallet {
});
if id_graph_members.is_empty() {
- IDGraphs::::remove(&who_account_id);
+ IDGraphs::::remove(&who);
} else {
- IDGraphs::::insert(who_account_id.clone(), id_graph_members);
+ IDGraphs::::insert(who.clone(), id_graph_members);
}
- Self::deposit_event(Event::IdentityRemoved { who: who_account_id, identity_hashes });
+ Self::deposit_event(Event::IdentityRemoved { who, identity_hashes });
Ok(())
}
- #[pallet::call_index(5)]
+ #[pallet::call_index(4)]
#[pallet::weight((195_000_000, DispatchClass::Normal))]
pub fn make_identity_public(
origin: OriginFor,
- who: Identity,
identity_hash: H256,
public_identity: MemberIdentity,
) -> DispatchResult {
- let _ = T::TEECallOrigin::ensure_origin(origin)?;
+ let who = T::OmniAccountOrigin::ensure_origin(origin)?;
ensure!(public_identity.is_public(), Error::::IdentityIsPrivate);
- let who_account_id = match T::AccountIdConverter::convert(&who) {
- Some(account_id) => account_id,
- None => return Err(Error::::InvalidIdentity.into()),
- };
-
let mut id_graph_members =
- IDGraphs::::get(&who_account_id).ok_or(Error::::UnknownIDGraph)?;
+ IDGraphs::::get(&who).ok_or(Error::::UnknownIDGraph)?;
let id_graph_link = id_graph_members
.iter_mut()
.find(|member| member.hash == identity_hash)
.ok_or(Error::::IdentityNotFound)?;
id_graph_link.id = public_identity;
- IDGraphs::::insert(who_account_id.clone(), id_graph_members);
+ IDGraphs::::insert(who.clone(), id_graph_members);
- Self::deposit_event(Event::IdentityMadePublic { who: who_account_id, identity_hash });
+ Self::deposit_event(Event::IdentityMadePublic { who, identity_hash });
Ok(())
}
@@ -270,10 +365,31 @@ pub mod pallet {
hash: owner_identity_hash,
})
.map_err(|_| Error::::IDGraphLenLimitReached)?;
- LinkedIdentityHashes::::insert(owner_identity_hash, ());
+ LinkedIdentityHashes::::insert(owner_identity_hash, owner_account_id.clone());
IDGraphs::::insert(owner_account_id.clone(), id_graph_members.clone());
Ok(id_graph_members)
}
}
}
+
+pub struct EnsureOmniAccount(PhantomData);
+impl, O>> + From>, AccountId: Decode>
+ EnsureOrigin for EnsureOmniAccount
+{
+ type Success = AccountId;
+ fn try_origin(o: O) -> Result {
+ o.into().and_then(|o| match o {
+ RawOrigin::OmniAccount(id) => Ok(id),
+ r => Err(O::from(r)),
+ })
+ }
+
+ #[cfg(feature = "runtime-benchmarks")]
+ fn try_successful_origin() -> Result {
+ let zero_account_id =
+ AccountId::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes())
+ .expect("infinite length input; no invalid inputs for type; qed");
+ Ok(O::from(RawOrigin::OmniAccount(zero_account_id)))
+ }
+}
diff --git a/parachain/pallets/omni-account/src/mock.rs b/parachain/pallets/omni-account/src/mock.rs
index fd2cdabf32..8a0178af75 100644
--- a/parachain/pallets/omni-account/src/mock.rs
+++ b/parachain/pallets/omni-account/src/mock.rs
@@ -1,4 +1,20 @@
-use crate::{self as pallet_omni_account};
+// Copyright 2020-2024 Trust Computing GmbH.
+// This file is part of Litentry.
+//
+// Litentry is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Litentry is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// 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, EnsureOmniAccount};
use core_primitives::Identity;
use frame_support::{
assert_ok,
@@ -152,10 +168,13 @@ impl pallet_omni_account::AccountIdConverter for IdentityToAccountI
}
impl pallet_omni_account::Config for TestRuntime {
+ type RuntimeOrigin = RuntimeOrigin;
+ type RuntimeCall = RuntimeCall;
type RuntimeEvent = RuntimeEvent;
type TEECallOrigin = EnsureEnclaveSigner;
type MaxIDGraphLength = ConstU32<3>;
type AccountIdConverter = IdentityToAccountIdConverter;
+ type OmniAccountOrigin = EnsureOmniAccount;
}
pub fn get_tee_signer() -> SystemAccountId {
@@ -163,11 +182,12 @@ pub fn get_tee_signer() -> SystemAccountId {
}
pub fn new_test_ext() -> sp_io::TestExternalities {
- let system = frame_system::GenesisConfig::::default();
- let mut ext: sp_io::TestExternalities = RuntimeGenesisConfig { system, ..Default::default() }
- .build_storage()
- .unwrap()
- .into();
+ let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap();
+ pallet_balances::GenesisConfig:: { balances: vec![(alice(), 10)] }
+ .assimilate_storage(&mut t)
+ .unwrap();
+
+ let mut ext: sp_io::TestExternalities = t.into();
ext.execute_with(|| {
System::set_block_number(1);
let signer = get_tee_signer();
diff --git a/parachain/pallets/omni-account/src/tests.rs b/parachain/pallets/omni-account/src/tests.rs
index 4b8b0c795e..effa5df4f6 100644
--- a/parachain/pallets/omni-account/src/tests.rs
+++ b/parachain/pallets/omni-account/src/tests.rs
@@ -1,9 +1,43 @@
+// Copyright 2020-2024 Trust Computing GmbH.
+// This file is part of Litentry.
+//
+// Litentry is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Litentry is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Litentry. If not, see .
+
use crate::{mock::*, IDGraphs, LinkedIdentityHashes, *};
use core_primitives::Identity;
use frame_support::{assert_noop, assert_ok};
-use sp_runtime::traits::BadOrigin;
+use sp_runtime::{traits::BadOrigin, ModuleError};
use sp_std::vec;
+fn remove_identity_call(hashes: Vec) -> Box {
+ let call = RuntimeCall::OmniAccount(crate::Call::remove_identities { identity_hashes: hashes });
+ Box::new(call)
+}
+
+fn make_identity_public_call(hash: H256, id: MemberIdentity) -> Box {
+ let call = RuntimeCall::OmniAccount(crate::Call::make_identity_public {
+ identity_hash: hash,
+ public_identity: id,
+ });
+ Box::new(call)
+}
+
+fn make_balance_transfer_call(dest: AccountId, value: Balance) -> Box {
+ let call = RuntimeCall::Balances(pallet_balances::Call::transfer { dest, value });
+ Box::new(call)
+}
+
#[test]
fn link_identity_works() {
new_test_ext().execute_with(|| {
@@ -326,12 +360,38 @@ fn remove_identity_works() {
member_account.clone(),
None
));
- assert_ok!(OmniAccount::remove_identities(
+
+ // normal signed origin should give `BadOrigin`, no matter
+ // it's from TEE-worker, or omni-account itself
+ assert_noop!(
+ OmniAccount::remove_identities(
+ RuntimeOrigin::signed(tee_signer.clone()),
+ identities_to_remove.clone()
+ ),
+ sp_runtime::DispatchError::BadOrigin
+ );
+
+ assert_noop!(
+ OmniAccount::remove_identities(
+ RuntimeOrigin::signed(who.clone()),
+ identities_to_remove.clone()
+ ),
+ sp_runtime::DispatchError::BadOrigin
+ );
+
+ let call = remove_identity_call(identities_to_remove.clone());
+ assert_ok!(OmniAccount::dispatch_as_omni_account(
RuntimeOrigin::signed(tee_signer.clone()),
- who_identity.clone(),
- identities_to_remove.clone()
+ who_identity_hash,
+ call
));
- System::assert_last_event(
+
+ System::assert_has_event(
+ Event::DispatchedAsOmniAccount { who: who.clone(), result: DispatchResult::Ok(()) }
+ .into(),
+ );
+
+ System::assert_has_event(
Event::IdentityRemoved { who: who.clone(), identity_hashes: identities_to_remove }
.into(),
);
@@ -345,15 +405,12 @@ fn remove_identity_works() {
assert_eq!(IDGraphs::::get(&who).unwrap(), expected_id_graph);
assert!(!LinkedIdentityHashes::::contains_key(identity_hash));
- assert_ok!(OmniAccount::remove_identities(
+ let call = remove_identity_call(vec![who_identity_hash]);
+ assert_ok!(OmniAccount::dispatch_as_omni_account(
RuntimeOrigin::signed(tee_signer.clone()),
- who_identity.clone(),
- vec![who_identity_hash],
+ who_identity_hash,
+ call
));
- System::assert_last_event(
- Event::IdentityRemoved { who: who.clone(), identity_hashes: vec![who_identity_hash] }
- .into(),
- );
assert!(!IDGraphs::::contains_key(&who));
});
@@ -363,33 +420,37 @@ fn remove_identity_works() {
fn remove_identity_empty_identity_check_works() {
new_test_ext().execute_with(|| {
let tee_signer = get_tee_signer();
- let who = Identity::from(alice());
+ let who = alice();
+ let who_identity = Identity::from(who.clone());
+ let who_identity_hash = who_identity.hash().unwrap();
assert_ok!(OmniAccount::link_identity(
RuntimeOrigin::signed(tee_signer.clone()),
- who.clone(),
+ who_identity,
IDGraphMember {
id: MemberIdentity::Private(vec![1, 2, 3]),
hash: H256::from(blake2_256(&[1, 2, 3])),
},
None
));
- assert_noop!(
- OmniAccount::remove_identities(RuntimeOrigin::signed(tee_signer.clone()), who, vec![],),
- Error::::IdentitiesEmpty
- );
- });
-}
-#[test]
-fn remove_identity_origin_check_works() {
- new_test_ext().execute_with(|| {
- let who = Identity::from(alice());
- let identities_to_remove = vec![H256::from(blake2_256(&[1, 2, 3]))];
-
- assert_noop!(
- OmniAccount::remove_identities(RuntimeOrigin::signed(bob()), who, identities_to_remove),
- BadOrigin
+ let call = remove_identity_call(vec![]);
+ // execution itself is ok, but error is shown in the dispatch result
+ assert_ok!(OmniAccount::dispatch_as_omni_account(
+ RuntimeOrigin::signed(tee_signer.clone()),
+ who_identity_hash,
+ call
+ ));
+ System::assert_has_event(
+ Event::DispatchedAsOmniAccount {
+ who,
+ result: Err(DispatchError::Module(ModuleError {
+ index: 5,
+ error: [6, 0, 0, 0],
+ message: Some("IdentitiesEmpty"),
+ })),
+ }
+ .into(),
);
});
}
@@ -400,6 +461,7 @@ fn make_identity_public_works() {
let tee_signer = get_tee_signer();
let who = alice();
let who_identity = Identity::from(who.clone());
+ let who_identity_hash = who_identity.hash().unwrap();
let private_identity = MemberIdentity::Private(vec![1, 2, 3]);
let public_identity = MemberIdentity::Public(Identity::from(bob()));
@@ -422,13 +484,19 @@ fn make_identity_public_works() {
]);
assert_eq!(IDGraphs::::get(&who).unwrap(), expected_id_graph);
- assert_ok!(OmniAccount::make_identity_public(
+ let call = make_identity_public_call(identity_hash, public_identity.clone());
+ assert_ok!(OmniAccount::dispatch_as_omni_account(
RuntimeOrigin::signed(tee_signer.clone()),
- who_identity.clone(),
- identity_hash,
- public_identity.clone()
+ who_identity_hash,
+ call
));
- System::assert_last_event(
+
+ System::assert_has_event(
+ Event::DispatchedAsOmniAccount { who: who.clone(), result: DispatchResult::Ok(()) }
+ .into(),
+ );
+
+ System::assert_has_event(
Event::IdentityMadePublic { who: who.clone(), identity_hash }.into(),
);
@@ -443,31 +511,13 @@ fn make_identity_public_works() {
});
}
-#[test]
-fn make_identity_public_origin_check_works() {
- new_test_ext().execute_with(|| {
- let who = Identity::from(alice());
- let identity = Identity::from(bob());
- let identity_hash = identity.hash().unwrap();
- let public_identity = MemberIdentity::Public(identity.clone());
-
- assert_noop!(
- OmniAccount::make_identity_public(
- RuntimeOrigin::signed(bob()),
- who,
- identity_hash,
- public_identity
- ),
- BadOrigin
- );
- });
-}
-
#[test]
fn make_identity_public_identity_not_found_works() {
new_test_ext().execute_with(|| {
let tee_signer = get_tee_signer();
- let who = Identity::from(alice());
+ let who = alice();
+ let who_identity = Identity::from(who.clone());
+ let who_identity_hash = who_identity.hash().unwrap();
let private_identity = MemberIdentity::Private(vec![1, 2, 3]);
let identity = Identity::from(bob());
@@ -475,19 +525,19 @@ fn make_identity_public_identity_not_found_works() {
let identity_hash =
H256::from(blake2_256(&Identity::from(bob()).to_did().unwrap().encode()));
+ let call = make_identity_public_call(identity_hash, public_identity.clone());
assert_noop!(
- OmniAccount::make_identity_public(
+ OmniAccount::dispatch_as_omni_account(
RuntimeOrigin::signed(tee_signer.clone()),
- who.clone(),
- identity_hash,
- public_identity.clone()
+ who_identity_hash,
+ call
),
- Error::::UnknownIDGraph
+ Error::::IdentityNotFound
);
assert_ok!(OmniAccount::link_identity(
RuntimeOrigin::signed(tee_signer.clone()),
- who.clone(),
+ who_identity,
IDGraphMember { id: private_identity.clone(), hash: identity_hash },
None
));
@@ -497,14 +547,22 @@ fn make_identity_public_identity_not_found_works() {
let other_identity_hash =
H256::from(blake2_256(&charlie_identity.to_did().unwrap().encode()));
- assert_noop!(
- OmniAccount::make_identity_public(
- RuntimeOrigin::signed(tee_signer),
+ let call = make_identity_public_call(other_identity_hash, other_identity);
+ assert_ok!(OmniAccount::dispatch_as_omni_account(
+ RuntimeOrigin::signed(tee_signer.clone()),
+ who_identity_hash,
+ call
+ ));
+ System::assert_has_event(
+ Event::DispatchedAsOmniAccount {
who,
- other_identity_hash,
- other_identity,
- ),
- Error::::IdentityNotFound
+ result: Err(DispatchError::Module(ModuleError {
+ index: 5,
+ error: [2, 0, 0, 0],
+ message: Some("IdentityNotFound"),
+ })),
+ }
+ .into(),
);
});
}
@@ -513,26 +571,68 @@ fn make_identity_public_identity_not_found_works() {
fn make_identity_public_identity_is_private_check_works() {
new_test_ext().execute_with(|| {
let tee_signer = get_tee_signer();
- let who = Identity::from(alice());
+ let who = alice();
+ let who_identity = Identity::from(who.clone());
+ let who_identity_hash = who_identity.hash().unwrap();
let private_identity = MemberIdentity::Private(vec![1, 2, 3]);
let identity_hash = Identity::from(bob()).hash().unwrap();
assert_ok!(OmniAccount::link_identity(
RuntimeOrigin::signed(tee_signer.clone()),
- who.clone(),
+ who_identity,
IDGraphMember { id: private_identity.clone(), hash: identity_hash },
None
));
- assert_noop!(
- OmniAccount::make_identity_public(
- RuntimeOrigin::signed(tee_signer),
+ let call = make_identity_public_call(identity_hash, private_identity);
+ assert_ok!(OmniAccount::dispatch_as_omni_account(
+ RuntimeOrigin::signed(tee_signer.clone()),
+ who_identity_hash,
+ call
+ ));
+ System::assert_has_event(
+ Event::DispatchedAsOmniAccount {
who,
- identity_hash,
- private_identity,
- ),
- Error::::IdentityIsPrivate
+ result: Err(DispatchError::Module(ModuleError {
+ index: 5,
+ error: [5, 0, 0, 0],
+ message: Some("IdentityIsPrivate"),
+ })),
+ }
+ .into(),
);
});
}
+
+#[test]
+fn dispatch_as_signed_works() {
+ new_test_ext().execute_with(|| {
+ let tee_signer = get_tee_signer();
+ let who = alice();
+ let who_identity = Identity::from(who.clone());
+ let who_identity_hash = who_identity.hash().unwrap();
+
+ let private_identity = MemberIdentity::Private(vec![1, 2, 3]);
+ let identity_hash = Identity::from(bob()).hash().unwrap();
+
+ assert_ok!(OmniAccount::link_identity(
+ RuntimeOrigin::signed(tee_signer.clone()),
+ who_identity,
+ IDGraphMember { id: private_identity.clone(), hash: identity_hash },
+ None
+ ));
+
+ let call = make_balance_transfer_call(bob(), 5);
+ assert_ok!(OmniAccount::dispatch_as_signed(
+ RuntimeOrigin::signed(tee_signer),
+ who_identity_hash,
+ call
+ ));
+ System::assert_has_event(
+ Event::DispatchedAsSigned { who, result: DispatchResult::Ok(()) }.into(),
+ );
+
+ assert_eq!(Balances::free_balance(bob()), 5);
+ });
+}
diff --git a/parachain/runtime/common/Cargo.toml b/parachain/runtime/common/Cargo.toml
index f93b7750a2..ffd75db923 100644
--- a/parachain/runtime/common/Cargo.toml
+++ b/parachain/runtime/common/Cargo.toml
@@ -50,6 +50,7 @@ cumulus-test-relay-sproof-builder = { workspace = true, optional = true }
pallet-asset-manager = { workspace = true }
pallet-extrinsic-filter = { workspace = true }
pallet-group = { workspace = true }
+pallet-omni-account = { workspace = true }
pallet-teebag = { workspace = true }
[features]
@@ -89,6 +90,7 @@ std = [
"core-primitives/std",
"pallet-asset-manager/std",
"pallet-extrinsic-filter/std",
+ "pallet-omni-account/std",
"pallet-teebag/std",
"orml-xtokens/std",
]
diff --git a/parachain/runtime/common/src/lib.rs b/parachain/runtime/common/src/lib.rs
index d04b9f7491..316fcc1ca1 100644
--- a/parachain/runtime/common/src/lib.rs
+++ b/parachain/runtime/common/src/lib.rs
@@ -327,3 +327,5 @@ where
Ok(frame_system::RawOrigin::Signed(signer).into())
}
}
+
+pub type EnsureOmniAccount = pallet_omni_account::EnsureOmniAccount;
diff --git a/parachain/runtime/litentry/Cargo.toml b/parachain/runtime/litentry/Cargo.toml
index 3b3a3bc1ba..86aab76cea 100644
--- a/parachain/runtime/litentry/Cargo.toml
+++ b/parachain/runtime/litentry/Cargo.toml
@@ -170,6 +170,7 @@ runtime-benchmarks = [
"cumulus-pallet-parachain-system/runtime-benchmarks",
"cumulus-pallet-xcmp-queue/runtime-benchmarks",
"pallet-score-staking/runtime-benchmarks",
+ "pallet-omni-account/runtime-benchmarks",
]
std = [
"parity-scale-codec/std",
@@ -255,6 +256,7 @@ std = [
"pallet-bridge-transfer/std",
"pallet-extrinsic-filter/std",
"pallet-bitacross/std",
+ "pallet-omni-account/std",
"pallet-identity-management/std",
"pallet-score-staking/std",
"pallet-teebag/std",
@@ -315,4 +317,5 @@ try-runtime = [
"pallet-xcm/try-runtime",
"parachain-info/try-runtime",
"pallet-score-staking/try-runtime",
+ "pallet-omni-account/try-runtime",
]
diff --git a/parachain/runtime/litentry/src/lib.rs b/parachain/runtime/litentry/src/lib.rs
index 1d81366913..2f42a4433a 100644
--- a/parachain/runtime/litentry/src/lib.rs
+++ b/parachain/runtime/litentry/src/lib.rs
@@ -66,13 +66,13 @@ pub use runtime_common::currency::*;
use runtime_common::{
impl_runtime_transaction_payment_fees, prod_or_fast, BlockHashCount, BlockLength,
CouncilInstance, CouncilMembershipInstance, DeveloperCommitteeInstance,
- DeveloperCommitteeMembershipInstance, EnsureEnclaveSigner, EnsureRootOrAllCouncil,
- EnsureRootOrAllTechnicalCommittee, EnsureRootOrHalfCouncil, EnsureRootOrHalfTechnicalCommittee,
- EnsureRootOrTwoThirdsCouncil, EnsureRootOrTwoThirdsTechnicalCommittee,
- IMPExtrinsicWhitelistInstance, NegativeImbalance, RuntimeBlockWeights, SlowAdjustingFeeUpdate,
- TechnicalCommitteeInstance, TechnicalCommitteeMembershipInstance,
- VCMPExtrinsicWhitelistInstance, MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO, WEIGHT_PER_GAS,
- WEIGHT_TO_FEE_FACTOR,
+ DeveloperCommitteeMembershipInstance, EnsureEnclaveSigner, EnsureOmniAccount,
+ EnsureRootOrAllCouncil, EnsureRootOrAllTechnicalCommittee, EnsureRootOrHalfCouncil,
+ EnsureRootOrHalfTechnicalCommittee, EnsureRootOrTwoThirdsCouncil,
+ EnsureRootOrTwoThirdsTechnicalCommittee, IMPExtrinsicWhitelistInstance, NegativeImbalance,
+ RuntimeBlockWeights, SlowAdjustingFeeUpdate, TechnicalCommitteeInstance,
+ TechnicalCommitteeMembershipInstance, VCMPExtrinsicWhitelistInstance, MAXIMUM_BLOCK_WEIGHT,
+ NORMAL_DISPATCH_RATIO, WEIGHT_PER_GAS, WEIGHT_TO_FEE_FACTOR,
};
use xcm_config::{XcmConfig, XcmOriginToTransactDispatchOrigin};
@@ -960,10 +960,13 @@ impl pallet_omni_account::AccountIdConverter for IdentityToAccountIdCon
}
impl pallet_omni_account::Config for Runtime {
+ type RuntimeOrigin = RuntimeOrigin;
+ type RuntimeCall = RuntimeCall;
type RuntimeEvent = RuntimeEvent;
type TEECallOrigin = EnsureEnclaveSigner;
type MaxIDGraphLength = ConstU32<64>;
type AccountIdConverter = IdentityToAccountIdConverter;
+ type OmniAccountOrigin = EnsureOmniAccount;
}
impl pallet_bitacross::Config for Runtime {
@@ -1316,7 +1319,8 @@ impl Contains for NormalModeFilter {
RuntimeCall::AssetsHandler(_) |
RuntimeCall::Bitacross(_) |
RuntimeCall::EvmAssertions(_) |
- RuntimeCall::ScoreStaking(_)
+ RuntimeCall::ScoreStaking(_) |
+ RuntimeCall::OmniAccount(_)
)
}
}
diff --git a/parachain/runtime/paseo/Cargo.toml b/parachain/runtime/paseo/Cargo.toml
index eb194daa05..73f1ac8494 100644
--- a/parachain/runtime/paseo/Cargo.toml
+++ b/parachain/runtime/paseo/Cargo.toml
@@ -173,6 +173,7 @@ runtime-benchmarks = [
"pallet-vc-management/runtime-benchmarks",
"pallet-account-fix/runtime-benchmarks",
"pallet-score-staking/runtime-benchmarks",
+ "pallet-omni-account/runtime-benchmarks",
]
std = [
"parity-scale-codec/std",
@@ -266,6 +267,7 @@ std = [
"pallet-extrinsic-filter/std",
"pallet-group/std",
"pallet-identity-management/std",
+ "pallet-omni-account/std",
"pallet-score-staking/std",
"pallet-teebag/std",
"pallet-vc-management/std",
@@ -327,4 +329,5 @@ try-runtime = [
"pallet-vesting/try-runtime",
"pallet-xcm/try-runtime",
"parachain-info/try-runtime",
+ "pallet-omni-account/try-runtime",
]
diff --git a/parachain/runtime/paseo/src/lib.rs b/parachain/runtime/paseo/src/lib.rs
index 1b77269ae2..98a157165b 100644
--- a/parachain/runtime/paseo/src/lib.rs
+++ b/parachain/runtime/paseo/src/lib.rs
@@ -77,7 +77,7 @@ pub use runtime_common::currency::*;
use runtime_common::{
impl_runtime_transaction_payment_fees, prod_or_fast, BlockHashCount, BlockLength,
CouncilInstance, CouncilMembershipInstance, DeveloperCommitteeInstance,
- DeveloperCommitteeMembershipInstance, EnsureRootOrAllCouncil,
+ DeveloperCommitteeMembershipInstance, EnsureOmniAccount, EnsureRootOrAllCouncil,
EnsureRootOrAllTechnicalCommittee, EnsureRootOrHalfCouncil, EnsureRootOrHalfTechnicalCommittee,
EnsureRootOrTwoThirdsCouncil, EnsureRootOrTwoThirdsTechnicalCommittee,
IMPExtrinsicWhitelistInstance, NegativeImbalance, RuntimeBlockWeights, SlowAdjustingFeeUpdate,
@@ -1003,10 +1003,13 @@ impl pallet_omni_account::AccountIdConverter for IdentityToAccountIdCon
}
impl pallet_omni_account::Config for Runtime {
+ type RuntimeOrigin = RuntimeOrigin;
+ type RuntimeCall = RuntimeCall;
type RuntimeEvent = RuntimeEvent;
type TEECallOrigin = EnsureEnclaveSigner;
type MaxIDGraphLength = ConstU32<64>;
type AccountIdConverter = IdentityToAccountIdConverter;
+ type OmniAccountOrigin = EnsureOmniAccount;
}
impl pallet_bitacross::Config for Runtime {
@@ -1377,7 +1380,8 @@ impl Contains for NormalModeFilter {
RuntimeCall::AssetsHandler(_) |
RuntimeCall::Bitacross(_) |
RuntimeCall::EvmAssertions(_) |
- RuntimeCall::ScoreStaking(_)
+ RuntimeCall::ScoreStaking(_) |
+ RuntimeCall::OmniAccount(_)
)
}
}
diff --git a/parachain/runtime/rococo/Cargo.toml b/parachain/runtime/rococo/Cargo.toml
index 231467f5bf..fdaae91906 100644
--- a/parachain/runtime/rococo/Cargo.toml
+++ b/parachain/runtime/rococo/Cargo.toml
@@ -173,6 +173,7 @@ runtime-benchmarks = [
"pallet-vc-management/runtime-benchmarks",
"pallet-account-fix/runtime-benchmarks",
"pallet-score-staking/runtime-benchmarks",
+ "pallet-omni-account/runtime-benchmarks",
]
std = [
"parity-scale-codec/std",
@@ -266,6 +267,7 @@ std = [
"pallet-extrinsic-filter/std",
"pallet-group/std",
"pallet-identity-management/std",
+ "pallet-omni-account/std",
"pallet-score-staking/std",
"pallet-teebag/std",
"pallet-vc-management/std",
@@ -327,4 +329,5 @@ try-runtime = [
"pallet-vesting/try-runtime",
"pallet-xcm/try-runtime",
"parachain-info/try-runtime",
+ "pallet-omni-account/try-runtime",
]
diff --git a/parachain/runtime/rococo/src/lib.rs b/parachain/runtime/rococo/src/lib.rs
index faf7106e51..5d2192564a 100644
--- a/parachain/runtime/rococo/src/lib.rs
+++ b/parachain/runtime/rococo/src/lib.rs
@@ -76,7 +76,7 @@ pub use runtime_common::currency::*;
use runtime_common::{
impl_runtime_transaction_payment_fees, prod_or_fast, BlockHashCount, BlockLength,
CouncilInstance, CouncilMembershipInstance, DeveloperCommitteeInstance,
- DeveloperCommitteeMembershipInstance, EnsureRootOrAllCouncil,
+ DeveloperCommitteeMembershipInstance, EnsureOmniAccount, EnsureRootOrAllCouncil,
EnsureRootOrAllTechnicalCommittee, EnsureRootOrHalfCouncil, EnsureRootOrHalfTechnicalCommittee,
EnsureRootOrTwoThirdsCouncil, EnsureRootOrTwoThirdsTechnicalCommittee,
IMPExtrinsicWhitelistInstance, NegativeImbalance, RuntimeBlockWeights, SlowAdjustingFeeUpdate,
@@ -1002,10 +1002,13 @@ impl pallet_omni_account::AccountIdConverter for IdentityToAccountIdCon
}
impl pallet_omni_account::Config for Runtime {
+ type RuntimeOrigin = RuntimeOrigin;
+ type RuntimeCall = RuntimeCall;
type RuntimeEvent = RuntimeEvent;
type TEECallOrigin = EnsureEnclaveSigner;
type MaxIDGraphLength = ConstU32<64>;
type AccountIdConverter = IdentityToAccountIdConverter;
+ type OmniAccountOrigin = EnsureOmniAccount;
}
impl pallet_bitacross::Config for Runtime {
@@ -1376,7 +1379,8 @@ impl Contains for NormalModeFilter {
RuntimeCall::AssetsHandler(_) |
RuntimeCall::Bitacross(_) |
RuntimeCall::EvmAssertions(_) |
- RuntimeCall::ScoreStaking(_)
+ RuntimeCall::ScoreStaking(_) |
+ RuntimeCall::OmniAccount(_)
)
}
}