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 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 const EMPTY_FUNCTION: fn(MessageSourceId) -> DispatchResult = |_| Ok(());
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}