You can start by looking at the trait:
/// Means of changing one type into another in a manner dependent on the source type.
/// This variant is different to `Lookup` in that it doesn't (can cannot) require any
/// context.
pub trait StaticLookup {
/// Type to lookup from.
type Source: Codec + Clone + PartialEq + Debug + TypeInfo;
/// Type to lookup into.
type Target;
/// Attempt a lookup.
fn lookup(s: Self::Source) -> Result<Self::Target, LookupError>;
/// Convert from Target back to Source.
fn unlookup(t: Self::Target) -> Self::Source;
}
Static lookup just describes some logic which converts from one type to another. In the most basic implementation, you can simply create the "identity lookup" conversion, taking an existing type and mapping it to itself:
/// A lookup implementation returning the input value.
#[derive(Default)]
pub struct IdentityLookup<T>(PhantomData<T>);
impl<T: Codec + Clone + PartialEq + Debug + TypeInfo> StaticLookup for IdentityLookup<T> {
type Source = T;
type Target = T;
fn lookup(x: T) -> Result<T, LookupError> {
Ok(x)
}
fn unlookup(x: T) -> T {
x
}
}
However, with this abstraction, you can also program more complex lookup patterns, for example converting domain name (like shawntabrizi.dot
) or index to the appropriate account id.
From Pallet Indices:
impl<T: Config> StaticLookup for Pallet<T> {
type Source = MultiAddress<T::AccountId, T::AccountIndex>;
type Target = T::AccountId;
fn lookup(a: Self::Source) -> Result<Self::Target, LookupError> {
Self::lookup_address(a).ok_or(LookupError)
}
fn unlookup(a: Self::Target) -> Self::Source {
MultiAddress::Id(a)
}
}
This abstraction allows substrate developers to be more flexible on the input users give to pallets when referencing an account, and allow the underlying pallet logic to handle the conversion to an appropriate account id.