common_primitives/
msa.rs

1use core::fmt::Debug;
2use frame_support::{dispatch::DispatchResult, traits::Get, BoundedBTreeMap, BoundedVec};
3use parity_scale_codec::{Decode, DecodeWithMemTracking, Encode, EncodeLike, Error, MaxEncodedLen};
4use scale_info::TypeInfo;
5#[cfg(feature = "std")]
6use serde::{Deserialize, Serialize};
7use sp_runtime::{
8	traits::{AtLeast32BitUnsigned, Zero},
9	DispatchError, MultiSignature, RuntimeDebug,
10};
11extern crate alloc;
12pub use crate::schema::{IntentId, SchemaId};
13use alloc::vec::Vec;
14use serde::{ser::SerializeStruct, Serializer};
15
16/// ApplicationIndex type
17pub type ApplicationIndex = u16;
18
19/// ApplicationContext is type of ProviderRegistryEntry
20pub type ApplicationContext<NameSize, LangSize, CidSize, MaxLocaleCount> =
21	ProviderRegistryEntry<NameSize, LangSize, CidSize, MaxLocaleCount>;
22
23/// Message Source Id or msaId is the unique identifier for Message Source Accounts
24pub type MessageSourceId = u64;
25
26/// Ethereum address type alias
27pub use sp_core::H160;
28
29/// Response type for getting Ethereum address as a 20-byte array and checksummed hex string
30#[derive(TypeInfo, Encode, Decode)]
31pub struct AccountId20Response {
32	/// Ethereum address as a 20-byte array
33	pub account_id: H160,
34
35	/// Ethereum address as a checksummed 42-byte hex string (including 0x prefix)
36	pub account_id_checksummed: alloc::string::String,
37}
38
39/// A DelegatorId an MSA Id serving the role of a Delegator.
40/// Delegators delegate to Providers.
41/// Encodes and Decodes as just a `u64`
42#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
43#[derive(TypeInfo, Default, Debug, Clone, Copy, PartialEq, MaxEncodedLen, Eq)]
44pub struct DelegatorId(pub MessageSourceId);
45
46impl EncodeLike for DelegatorId {}
47
48impl Encode for DelegatorId {
49	fn encode(&self) -> Vec<u8> {
50		self.0.encode()
51	}
52}
53
54impl DecodeWithMemTracking for DelegatorId {}
55
56impl Decode for DelegatorId {
57	fn decode<I: parity_scale_codec::Input>(
58		input: &mut I,
59	) -> Result<Self, parity_scale_codec::Error> {
60		match <u64>::decode(input) {
61			Ok(x) => Ok(DelegatorId(x)),
62			_ => Err(Error::from("Could not decode DelegatorId")),
63		}
64	}
65}
66
67impl From<MessageSourceId> for DelegatorId {
68	fn from(t: MessageSourceId) -> Self {
69		DelegatorId(t)
70	}
71}
72
73impl From<DelegatorId> for MessageSourceId {
74	fn from(t: DelegatorId) -> MessageSourceId {
75		t.0
76	}
77}
78
79/// RPC response for getting delegated providers with their permissions
80#[cfg_attr(feature = "std", derive(Deserialize, Serialize))]
81#[derive(TypeInfo, RuntimeDebug, Clone, Decode, Encode, MaxEncodedLen, Eq)]
82pub struct DelegationResponse<DelegationIdType, BlockNumber> {
83	/// SchemaId of schema for which permission is/was granted
84	pub provider_id: ProviderId,
85	/// The list of schema permissions grants
86	pub permissions: Vec<DelegationGrant<DelegationIdType, BlockNumber>>,
87}
88
89/// RPC response for getting schema permission grants
90#[cfg_attr(feature = "std", derive(Deserialize))]
91#[derive(TypeInfo, RuntimeDebug, Clone, Decode, Encode, MaxEncodedLen, Eq)]
92pub struct DelegationGrant<DelegationIdType, BlockNumber> {
93	/// ID of the delegated entity for which permission is/was granted
94	pub granted_id: DelegationIdType,
95	/// Block number the permission was/will be revoked (0 = not revoked)
96	pub revoked_at: BlockNumber,
97}
98
99// Custom serialization implementation to allow for a slow roll-out of renaming
100// the `schema_id` field to `granted_id`; preserves compatibility for older clients
101// while allowing the new field name to also exist for client to update to.
102#[cfg(feature = "std")]
103impl<DelegationIdType: Serialize, BlockNumber: Serialize> Serialize
104	for DelegationGrant<DelegationIdType, BlockNumber>
105{
106	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
107	where
108		S: Serializer,
109	{
110		let mut s = serializer.serialize_struct("DelegationGrant", 3)?;
111		s.serialize_field("schema_id", &self.granted_id)?;
112		s.serialize_field("granted_id", &self.granted_id)?;
113		s.serialize_field("revoked_at", &self.revoked_at)?;
114		s.end()
115	}
116}
117
118impl<DelegationIdType, BlockNumber> PartialEq for DelegationResponse<DelegationIdType, BlockNumber>
119where
120	DelegationIdType: PartialEq,
121	BlockNumber: PartialEq,
122{
123	fn eq(&self, other: &Self) -> bool {
124		self.provider_id == other.provider_id && self.permissions == other.permissions
125	}
126}
127
128impl<DelegationIdType, BlockNumber> DelegationGrant<DelegationIdType, BlockNumber> {
129	/// Create a new SchemaGrant struct
130	pub fn new(granted_id: DelegationIdType, revoked_at: BlockNumber) -> Self {
131		DelegationGrant { granted_id, revoked_at }
132	}
133}
134
135impl<DelegatedIdType, BlockNumber> PartialEq for DelegationGrant<DelegatedIdType, BlockNumber>
136where
137	DelegatedIdType: PartialEq,
138	BlockNumber: PartialEq,
139{
140	fn eq(&self, other: &Self) -> bool {
141		self.granted_id == other.granted_id && self.revoked_at == other.revoked_at
142	}
143}
144
145/// Struct for the information of the relationship between an MSA and a Provider
146#[derive(TypeInfo, RuntimeDebug, Clone, Decode, Encode, MaxEncodedLen, Eq)]
147#[scale_info(skip_type_params(MaxGrantsPerDelegation))]
148pub struct Delegation<DelegatedIdType, BlockNumber, MaxGrantsPerDelegation>
149where
150	MaxGrantsPerDelegation: Get<u32>,
151{
152	/// Block number the grant will be revoked.
153	pub revoked_at: BlockNumber,
154	/// Schemas that the provider is allowed to use for a delegated message.
155	pub permissions: BoundedBTreeMap<DelegatedIdType, BlockNumber, MaxGrantsPerDelegation>,
156}
157
158// Cannot derive the PartialEq without a mess of impl PartialEq for MaxSchemaGrantsPerDelegation
159impl<DelegatedIdType, BlockNumber, MaxGrantsPerDelegation> PartialEq
160	for Delegation<DelegatedIdType, BlockNumber, MaxGrantsPerDelegation>
161where
162	DelegatedIdType: PartialEq,
163	BlockNumber: PartialEq,
164	MaxGrantsPerDelegation: Get<u32>,
165{
166	fn eq(&self, other: &Self) -> bool {
167		self.revoked_at == other.revoked_at && self.permissions == other.permissions
168	}
169}
170
171impl<
172		DelegatedIdType: Ord + Default,
173		BlockNumber: Ord + Copy + Zero + AtLeast32BitUnsigned + Default,
174		MaxGrantsPerDelegation: Get<u32>,
175	> Default for Delegation<DelegatedIdType, BlockNumber, MaxGrantsPerDelegation>
176{
177	/// Provides the default values for Delegation type.
178	fn default() -> Self {
179		Delegation {
180			revoked_at: BlockNumber::default(),
181			permissions:
182				BoundedBTreeMap::<DelegatedIdType, BlockNumber, MaxGrantsPerDelegation>::new(),
183		}
184	}
185}
186
187/// Provider is the recipient of a delegation.
188/// It is a subset of an MSA
189/// Encodes and Decodes as just a `u64`
190#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
191#[derive(TypeInfo, Default, Debug, Clone, Copy, PartialEq, MaxEncodedLen, Eq)]
192pub struct ProviderId(pub MessageSourceId);
193
194impl EncodeLike for ProviderId {}
195
196impl Encode for ProviderId {
197	fn encode(&self) -> Vec<u8> {
198		self.0.encode()
199	}
200}
201
202impl DecodeWithMemTracking for ProviderId {}
203
204impl Decode for ProviderId {
205	fn decode<I: parity_scale_codec::Input>(
206		input: &mut I,
207	) -> Result<Self, parity_scale_codec::Error> {
208		match <u64>::decode(input) {
209			Ok(x) => Ok(ProviderId(x)),
210			_ => Err(Error::from("Could not decode ProviderId")),
211		}
212	}
213}
214
215impl From<MessageSourceId> for ProviderId {
216	fn from(t: MessageSourceId) -> Self {
217		ProviderId(t)
218	}
219}
220
221impl From<ProviderId> for MessageSourceId {
222	fn from(t: ProviderId) -> MessageSourceId {
223		t.0
224	}
225}
226
227/// This is the metadata associated with a provider. As of now it is just a
228/// name, but it will likely be expanded in the future
229/// Generic over size constraints to be used in common types.
230#[derive(
231	MaxEncodedLen, TypeInfo, Clone, Debug, Decode, DecodeWithMemTracking, Encode, PartialEq, Eq,
232)]
233#[scale_info(skip_type_params(NameSize, LangSize, CidSize, MaxLocaleCount))]
234#[codec(mel_bound(
235	NameSize: Get<u32> + Debug + PartialEq + Eq,
236	LangSize: Get<u32> + Debug + PartialEq + Eq,
237	CidSize: Get<u32> + Debug + PartialEq + Eq,
238	MaxLocaleCount: Get<u32> + Debug + PartialEq + Eq,
239))]
240pub struct ProviderRegistryEntry<
241	NameSize: Get<u32> + Debug + PartialEq + Eq,
242	LangSize: Get<u32> + Debug + PartialEq + Eq,
243	CidSize: Get<u32> + Debug + PartialEq + Eq,
244	MaxLocaleCount: Get<u32> + Debug + PartialEq + Eq,
245> {
246	/// Default name (display name) of the provider or application.
247	pub default_name: BoundedVec<u8, NameSize>,
248
249	/// Localized names keyed by BCP 47 language code (e.g., "en-US").
250	pub localized_names:
251		BoundedBTreeMap<BoundedVec<u8, LangSize>, BoundedVec<u8, NameSize>, MaxLocaleCount>,
252
253	/// Default logo (PNG 250x100) content-addressed CID (e.g., IPFS hash).
254	pub default_logo_250_100_png_cid: BoundedVec<u8, CidSize>,
255
256	/// Localized logo CIDs keyed by BCP 47 language code.
257	pub localized_logo_250_100_png_cids:
258		BoundedBTreeMap<BoundedVec<u8, LangSize>, BoundedVec<u8, CidSize>, MaxLocaleCount>,
259}
260
261impl<NameSize, LangSize, CidSize, MaxLocaleCount> Default
262	for ProviderRegistryEntry<NameSize, LangSize, CidSize, MaxLocaleCount>
263where
264	NameSize: Get<u32> + Debug + PartialEq + Eq,
265	LangSize: Get<u32> + Debug + PartialEq + Eq,
266	CidSize: Get<u32> + Debug + PartialEq + Eq,
267	MaxLocaleCount: Get<u32> + Debug + PartialEq + Eq,
268{
269	fn default() -> Self {
270		Self {
271			default_name: BoundedVec::default(),
272			localized_names: BoundedBTreeMap::default(),
273			default_logo_250_100_png_cid: BoundedVec::default(),
274			localized_logo_250_100_png_cids: BoundedBTreeMap::default(),
275		}
276	}
277}
278
279/// RPC Response for getting ProviderApplicationContext
280#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
281#[derive(TypeInfo, Debug, Clone, Decode, Encode, PartialEq, Default)]
282pub struct ProviderApplicationContext {
283	/// The default name associated with this entry
284	pub default_name: Vec<u8>,
285	/// The provider associated with the `key`
286	pub provider_id: ProviderId,
287	/// The default Application/Provider logo
288	pub default_logo_250_100_png_bytes: Option<Vec<u8>>,
289	/// The optional application id
290	pub application_id: Option<ApplicationIndex>,
291	/// The optional localized name
292	pub localized_name: Option<Vec<u8>>,
293	/// The optional localized logo bytes
294	pub localized_logo_250_100_png_bytes: Option<Vec<u8>>,
295}
296
297/// The pointer value for the Signature Registry
298#[derive(MaxEncodedLen, TypeInfo, Debug, Clone, Decode, Encode, PartialEq, Eq)]
299pub struct SignatureRegistryPointer<BlockNumber> {
300	/// The newest signature that will be added to the registry when we get the next newest
301	pub newest: MultiSignature,
302
303	/// Block number that `newest` expires at
304	pub newest_expires_at: BlockNumber,
305
306	/// Pointer to the oldest signature in the list
307	pub oldest: MultiSignature,
308
309	/// Count of signatures in the registry
310	/// Will eventually match the `MaxSignaturesStored`, but during initialization is needed to fill the list
311	pub count: u32,
312}
313
314/// A behavior that allows looking up an MSA id
315pub trait MsaLookup {
316	/// The association between key and MSA
317	type AccountId;
318
319	/// Gets the MSA Id associated with this `AccountId` if any
320	fn get_msa_id(key: &Self::AccountId) -> Option<MessageSourceId>;
321
322	/// Gets the max MSA ID from the pallet
323	fn get_max_msa_id() -> MessageSourceId;
324}
325
326/// A behavior that allows for validating an MSA
327pub trait MsaValidator {
328	/// The association between key and MSA
329	type AccountId;
330
331	/// Check that a key is associated to an MSA and returns key information.
332	/// Returns a [`DispatchError`] if there is no MSA associated with the key
333	fn ensure_valid_msa_key(key: &Self::AccountId) -> Result<MessageSourceId, DispatchError>;
334}
335
336/// A behavior that allows for looking up delegator-provider relationships
337pub trait ProviderLookup {
338	/// Type for block number.
339	type BlockNumber;
340	/// Type for maximum number of items that can be granted to a provider.
341	type MaxGrantsPerDelegation: Get<u32>;
342	/// Schema Id is the unique identifier for a Schema
343	type DelegationId;
344
345	/// Gets the relationship information for this delegator, provider pair
346	fn get_delegation_of(
347		delegator: DelegatorId,
348		provider: ProviderId,
349	) -> Option<Delegation<Self::DelegationId, Self::BlockNumber, Self::MaxGrantsPerDelegation>>;
350}
351
352/// A behavior that allows for validating a delegator-provider relationship
353pub trait DelegationValidator {
354	/// Type for block number.
355	type BlockNumber;
356	/// Type for maximum number of items that can be granted to a provider.
357	type MaxGrantsPerDelegation: Get<u32>;
358	/// The unique identifier for a delegated item
359	type DelegationIdType;
360
361	/// Validates that the delegator and provider have a relationship at this point
362	fn ensure_valid_delegation(
363		provider: ProviderId,
364		delegator: DelegatorId,
365		block_number: Option<Self::BlockNumber>,
366	) -> Result<
367		Delegation<Self::DelegationIdType, Self::BlockNumber, Self::MaxGrantsPerDelegation>,
368		DispatchError,
369	>;
370}
371
372/// A behavior that allows for validating a schema grant
373pub trait GrantValidator<DelegationIdType, BlockNumber> {
374	/// Validates if the provider is allowed to use the particular delegated item id currently
375	fn ensure_valid_grant(
376		provider_id: ProviderId,
377		delegator_id: DelegatorId,
378		id_to_check: DelegationIdType,
379		block_number: BlockNumber,
380	) -> DispatchResult;
381}
382
383/// A trait that allows checking whether adding a key may be subsidized
384pub trait MsaKeyProvider {
385	/// the type to use for looking up keys in storage.
386	type AccountId;
387	/// Returns whether adding `new_key` to `msa_id` may be subsidized
388	fn key_eligible_for_subsidized_addition(
389		old_key: Self::AccountId,
390		new_key: Self::AccountId,
391		msa_id: MessageSourceId,
392	) -> bool;
393}
394
395/// RPC Response for getting MSA keys
396#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
397#[derive(TypeInfo, Debug, Clone, Decode, Encode, PartialEq, Default, MaxEncodedLen)]
398pub struct KeyInfoResponse<AccountId> {
399	/// The MSA associated with the `key`
400	pub msa_id: MessageSourceId,
401	/// The list of `AccountId` associated with the `msa_id`
402	pub msa_keys: Vec<AccountId>,
403}
404
405#[cfg(test)]
406mod tests {
407	use super::*;
408
409	#[test]
410	fn decoding_provider_id_failure() {
411		let mut da: &[u8] = b"\xf6\xf5";
412		let decoded = DelegatorId::decode(&mut da);
413		assert!(decoded.is_err());
414	}
415
416	#[test]
417	fn decoding_provider_id_success() {
418		let val = 16777215_u64.encode();
419		let decoded = ProviderId::decode(&mut &val[..]);
420		assert_eq!(decoded, Ok(ProviderId(16777215)))
421	}
422
423	#[test]
424	fn decoding_delegate_id_failure() {
425		let mut da: &[u8] = b"\xf6\xf5";
426		let decoded = DelegatorId::decode(&mut da);
427		assert!(decoded.is_err());
428	}
429
430	#[test]
431	fn decoding_delegator_id_success() {
432		let val = 42_u64.encode();
433		let decoded = DelegatorId::decode(&mut &val[..]);
434		assert_eq!(decoded, Ok(DelegatorId(42)))
435	}
436}