1

I'm working on a feature that requires pallet-nfts ForceOrigin to only be callable by an account configured inside a separated pallet's storage. For example in pallet-A I have the following

#[pallet::storage]
pub type Authority<T: Config> = StorageValue<_, T::AccountId, OptionQuery>;

Now I need to configure pallet-nfts ForceOrigin to take this Authority as the allowed origin. For this I'm trying to use EnsureOriginBy like this

impl pallet_nfts::Config for Runtime {
    ...
    type ForceOrigin = EnsureSignedBy<Authority, AccountId>;
    ...
}

How could I define Authority in the runtime config to get the value in pallet-A storage?

I have an alternative solution which is to define the account directly in the runtime config

pub const Authority: AccountId = AccountId::from(hex_literal::hex!("00000000000000000000000000000000000"));

But this would mean that the only way to change this authority is via a runtime upgrade and not though a call to a setAuthority() extrinsic in pallet-A

2 Answers 2

1

type Who in EnsureSignedBy<Who, AccountId> is bounded by SortedMembers trait. Implement this either for your pallet or for a custom struct:

pub struct AuthorityProvider<T: crate::Config>(sp_std::marker::PhantomData);

impl<T: crate::Config> SortedMembers<T::AccountId> for AuthorityProvider<T> {
   fn sorted_members() -> Vec<T::AccountId> {
       if let Some(authority) = Authority::<T>::get() {
           return vec![authority]
       }
       vec![]
   }

   fn contains(who: &T::AccountId) -> bool {
       if let Some(authority) = Authority::<T>::get() {
           return authority == who
       }
       false
   }
}

Then pass it to EnsureSignedBy:

type ForceOrigin = EnsureSignedBy<pallet_a::AuthorityProvider<Runtime>, AccountId>;
2
  • This worked flawlessly, thank you Commented Apr 15 at 19:10
  • glad it helped. please, upvote or accept as answer :)
    – dastansam
    Commented Apr 16 at 8:20
0

You can write your own EnsureOrigin implementation:

struct EnsureAuthority<T>(core::marker::PhantomData<T>);

impl<T> EnsureOrigin<T::RuntimeOrigin> for EnsureAuthority<T> 
where
   T: Config,
   T::RuntimeOrigin: Into<Result<RawOrigin<T::AccountId>, T::RuntimeOrigin>> + From<RawOrigin<T::AccountId>,
{
    type Success = ();
    fn try_origin(o: T::RuntimeOrigin) -> Result<Self::Success, O> {
        match o.clone().into()? {
             RawOrigin::Signed(s) if Authority::<T>::get().map_or(false, |a| a == s) => Ok(()),
             r => Err(r.into()),
        }
    }

    #[cfg(feature = "runtime-benchmarks")]
    fn try_successful_origin() -> Result<T::RuntimeOrigin, ()> {
        Ok(Authority::<T>::get().ok_or(())?)
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.