1#![cfg_attr(not(feature = "std"), no_std)]
3
4use super::*;
5use parity_scale_codec::{Decode, Encode};
6
7use core::fmt::Debug;
8
9pub use common_primitives::msa::{
10	ApplicationIndex, Delegation, DelegatorId, KeyInfoResponse, MessageSourceId, ProviderId,
11};
12use common_primitives::{node::BlockNumber, schema::SchemaId};
13
14use common_primitives::{
15	signatures::{get_eip712_encoding_prefix, AccountAddressMapper, EthereumAddressMapper},
16	utils::to_abi_compatible_number,
17};
18use scale_info::TypeInfo;
19use sp_core::U256;
20
21pub type LogoCid<T> = BoundedVec<u8, <T as Config>::MaxLogoCidSize>;
23
24#[derive(
27	TypeInfo, RuntimeDebugNoBound, Clone, Decode, DecodeWithMemTracking, Encode, PartialEq, Eq,
28)]
29#[scale_info(skip_type_params(T))]
30pub struct AddKeyData<T: Config> {
31	pub msa_id: MessageSourceId,
33	pub expiration: BlockNumberFor<T>,
35	pub new_public_key: T::AccountId,
37}
38
39impl<T: Config> EIP712Encode for AddKeyData<T> {
40	fn encode_eip_712(&self, chain_id: u32) -> Box<[u8]> {
41		lazy_static! {
42			static ref MAIN_TYPE_HASH: [u8; 32] = sp_io::hashing::keccak_256(
44				b"AddKeyData(uint64 msaId,uint32 expiration,address newPublicKey)",
45			);
46		}
47		let prefix_domain_separator: Box<[u8]> =
49			get_eip712_encoding_prefix("0xcccccccccccccccccccccccccccccccccccccccc", chain_id);
50		let coded_owner_msa_id = to_abi_compatible_number(self.msa_id);
51		let expiration: U256 = self.expiration.into();
52		let coded_expiration = to_abi_compatible_number(expiration.as_u128());
53		let converted_public_key = T::ConvertIntoAccountId32::convert(self.new_public_key.clone());
54		let mut zero_prefixed_address = [0u8; 32];
55		zero_prefixed_address[12..]
56			.copy_from_slice(&EthereumAddressMapper::to_ethereum_address(converted_public_key).0);
57		let message = sp_io::hashing::keccak_256(
58			&[
59				MAIN_TYPE_HASH.as_slice(),
60				&coded_owner_msa_id,
61				&coded_expiration,
62				&zero_prefixed_address,
63			]
64			.concat(),
65		);
66		let combined = [prefix_domain_separator.as_ref(), &message].concat();
67		combined.into_boxed_slice()
68	}
69}
70
71#[derive(
73	Encode, Decode, DecodeWithMemTracking, Clone, Copy, PartialEq, Eq, RuntimeDebugNoBound, TypeInfo,
74)]
75pub enum PayloadTypeDiscriminator {
76	Unknown,
78	AuthorizedKeyData,
80	RecoveryCommitmentPayload,
82}
83
84#[derive(
87	TypeInfo, RuntimeDebugNoBound, Clone, Decode, DecodeWithMemTracking, Encode, PartialEq, Eq,
88)]
89#[scale_info(skip_type_params(T))]
90pub struct AuthorizedKeyData<T: Config> {
91	pub discriminant: PayloadTypeDiscriminator,
93	pub msa_id: MessageSourceId,
95	pub expiration: BlockNumberFor<T>,
97	pub authorized_public_key: T::AccountId,
99}
100
101impl<T: Config> EIP712Encode for AuthorizedKeyData<T> {
102	fn encode_eip_712(&self, chain_id: u32) -> Box<[u8]> {
103		lazy_static! {
104			static ref MAIN_TYPE_HASH: [u8; 32] = sp_io::hashing::keccak_256(
106				b"AuthorizedKeyData(uint64 msaId,uint32 expiration,address authorizedPublicKey)",
107			);
108		}
109		let prefix_domain_separator: Box<[u8]> =
111			get_eip712_encoding_prefix("0xcccccccccccccccccccccccccccccccccccccccc", chain_id);
112		let coded_owner_msa_id = to_abi_compatible_number(self.msa_id);
113		let expiration: U256 = self.expiration.into();
114		let coded_expiration = to_abi_compatible_number(expiration.as_u128());
115		let converted_public_key =
116			T::ConvertIntoAccountId32::convert(self.authorized_public_key.clone());
117		let mut zero_prefixed_address = [0u8; 32];
118		zero_prefixed_address[12..]
119			.copy_from_slice(&EthereumAddressMapper::to_ethereum_address(converted_public_key).0);
120		let message = sp_io::hashing::keccak_256(
121			&[
122				MAIN_TYPE_HASH.as_slice(),
123				&coded_owner_msa_id,
124				&coded_expiration,
125				&zero_prefixed_address,
126			]
127			.concat(),
128		);
129		let combined = [prefix_domain_separator.as_ref(), &message].concat();
130		combined.into_boxed_slice()
131	}
132}
133
134#[derive(TypeInfo, Clone, Debug, Decode, DecodeWithMemTracking, Encode, PartialEq, Eq)]
136pub struct AddProvider {
137	pub authorized_msa_id: MessageSourceId,
139	pub schema_ids: Vec<SchemaId>,
142	pub expiration: BlockNumber,
144}
145
146impl EIP712Encode for AddProvider {
147	fn encode_eip_712(&self, chain_id: u32) -> Box<[u8]> {
148		lazy_static! {
149			static ref MAIN_TYPE_HASH: [u8; 32] = sp_io::hashing::keccak_256(
151				b"AddProvider(uint64 authorizedMsaId,uint16[] schemaIds,uint32 expiration)"
152			);
153		}
154		let prefix_domain_separator: Box<[u8]> =
156			get_eip712_encoding_prefix("0xcccccccccccccccccccccccccccccccccccccccc", chain_id);
157		let coded_authorized_msa_id = to_abi_compatible_number(self.authorized_msa_id);
158		let schema_ids: Vec<u8> = self
159			.schema_ids
160			.iter()
161			.flat_map(|schema_id| to_abi_compatible_number(*schema_id))
162			.collect();
163		let schema_ids = sp_io::hashing::keccak_256(&schema_ids);
164		let coded_expiration = to_abi_compatible_number(self.expiration);
165		let message = sp_io::hashing::keccak_256(
166			&[MAIN_TYPE_HASH.as_slice(), &coded_authorized_msa_id, &schema_ids, &coded_expiration]
167				.concat(),
168		);
169		let combined = [prefix_domain_separator.as_ref(), &message].concat();
170		combined.into_boxed_slice()
171	}
172}
173
174impl AddProvider {
175	pub fn new(
177		authorized_msa_id: MessageSourceId,
178		schema_ids: Option<Vec<SchemaId>>,
179		expiration: BlockNumber,
180	) -> Self {
181		let schema_ids = schema_ids.unwrap_or_default();
182
183		Self { authorized_msa_id, schema_ids, expiration }
184	}
185}
186
187pub type RecoveryHash = [u8; 32]; pub type RecoveryCommitment = RecoveryHash; #[derive(
197	TypeInfo, RuntimeDebugNoBound, Clone, Decode, DecodeWithMemTracking, Encode, PartialEq, Eq,
198)]
199#[scale_info(skip_type_params(T))]
200pub struct RecoveryCommitmentPayload<T: Config> {
201	pub discriminant: PayloadTypeDiscriminator,
203	pub recovery_commitment: RecoveryCommitment,
205	pub expiration: BlockNumberFor<T>,
207}
208
209impl<T: Config> EIP712Encode for RecoveryCommitmentPayload<T> {
210	fn encode_eip_712(&self, chain_id: u32) -> Box<[u8]> {
211		lazy_static! {
212			static ref MAIN_TYPE_HASH: [u8; 32] = sp_io::hashing::keccak_256(
214				b"RecoveryCommitmentPayload(bytes recoveryCommitment,uint32 expiration)",
215			);
216		}
217		let prefix_domain_separator: Box<[u8]> =
219			get_eip712_encoding_prefix("0xcccccccccccccccccccccccccccccccccccccccc", chain_id);
220		let hashed_recovery = sp_io::hashing::keccak_256(&self.recovery_commitment);
221		let expiration: U256 = self.expiration.into();
222		let coded_expiration = to_abi_compatible_number(expiration.as_u128());
223		let message = sp_io::hashing::keccak_256(
224			&[MAIN_TYPE_HASH.as_slice(), hashed_recovery.as_slice(), &coded_expiration].concat(),
225		);
226		let combined = [prefix_domain_separator.as_ref(), &message].concat();
227		combined.into_boxed_slice()
228	}
229}
230
231pub trait PermittedDelegationSchemas<T: Config> {
233	fn try_insert_schema(&mut self, schema_id: SchemaId) -> Result<(), DispatchError>;
235
236	fn try_insert_schemas(&mut self, schema_ids: Vec<SchemaId>) -> Result<(), DispatchError> {
238		for schema_id in schema_ids.into_iter() {
239			self.try_insert_schema(schema_id)?;
240		}
241
242		Ok(())
243	}
244
245	fn try_get_mut_schemas(
247		&mut self,
248		schema_ids: Vec<SchemaId>,
249		block_number: BlockNumberFor<T>,
250	) -> Result<(), DispatchError> {
251		for schema_id in schema_ids.into_iter() {
252			self.try_get_mut_schema(schema_id, block_number)?;
253		}
254		Ok(())
255	}
256
257	fn try_get_mut_schema(
259		&mut self,
260		schema_id: SchemaId,
261		block_number: BlockNumberFor<T>,
262	) -> Result<(), DispatchError>;
263}
264
265impl<T: Config> PermittedDelegationSchemas<T>
267	for Delegation<SchemaId, BlockNumberFor<T>, T::MaxSchemaGrantsPerDelegation>
268{
269	fn try_insert_schema(&mut self, schema_id: SchemaId) -> Result<(), DispatchError> {
271		self.schema_permissions
272			.try_insert(schema_id, Default::default())
273			.map_err(|_| Error::<T>::ExceedsMaxSchemaGrantsPerDelegation)?;
274		Ok(())
275	}
276
277	fn try_get_mut_schema(
279		&mut self,
280		schema_id: SchemaId,
281		block_number: BlockNumberFor<T>,
282	) -> Result<(), DispatchError> {
283		let schema = self
284			.schema_permissions
285			.get_mut(&schema_id)
286			.ok_or(Error::<T>::SchemaNotGranted)?;
287
288		*schema = block_number;
289
290		Ok(())
291	}
292}
293
294#[cfg(any(test, feature = "runtime-benchmarks"))]
296pub fn compute_cid(bytes: &[u8]) -> Vec<u8> {
297	let cid = compute_cid_v1(bytes).expect("Failed to compute CID");
298	let encoded = multibase::encode(multibase::Base::Base58Btc, cid);
300	encoded.into_bytes()
301}