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