pallet_msa/
types.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
//! Types for the MSA Pallet
#![cfg_attr(not(feature = "std"), no_std)]

use super::*;
use parity_scale_codec::{Decode, Encode};

use core::fmt::Debug;

pub use common_primitives::msa::{
	Delegation, DelegatorId, KeyInfoResponse, MessageSourceId, ProviderId,
};
use common_primitives::{node::BlockNumber, schema::SchemaId};

use common_primitives::{
	signatures::{get_eip712_encoding_prefix, AccountAddressMapper, EthereumAddressMapper},
	utils::to_abi_compatible_number,
};
use scale_info::TypeInfo;
use sp_core::U256;

/// Dispatch Empty
pub const EMPTY_FUNCTION: fn(MessageSourceId) -> DispatchResult = |_| Ok(());

/// A type definition for the payload of adding an MSA key - `pallet_msa::add_public_key_to_msa`
#[derive(
	TypeInfo, RuntimeDebugNoBound, Clone, Decode, DecodeWithMemTracking, Encode, PartialEq, Eq,
)]
#[scale_info(skip_type_params(T))]
pub struct AddKeyData<T: Config> {
	/// Message Source Account identifier
	pub msa_id: MessageSourceId,
	/// The block number at which the signed proof for add_public_key_to_msa expires.
	pub expiration: BlockNumberFor<T>,
	/// The public key to be added.
	pub new_public_key: T::AccountId,
}

impl<T: Config> EIP712Encode for AddKeyData<T> {
	fn encode_eip_712(&self) -> Box<[u8]> {
		lazy_static! {
			// get prefix and domain separator
			static ref PREFIX_DOMAIN_SEPARATOR: Box<[u8]> =
				get_eip712_encoding_prefix("0xcccccccccccccccccccccccccccccccccccccccc");

			// signed payload
			static ref MAIN_TYPE_HASH: [u8; 32] = sp_io::hashing::keccak_256(
				b"AddKeyData(uint64 msaId,uint32 expiration,address newPublicKey)",
			);
		}
		let coded_owner_msa_id = to_abi_compatible_number(self.msa_id);
		let expiration: U256 = self.expiration.into();
		let coded_expiration = to_abi_compatible_number(expiration.as_u128());
		let converted_public_key = T::ConvertIntoAccountId32::convert(self.new_public_key.clone());
		let mut zero_prefixed_address = [0u8; 32];
		zero_prefixed_address[12..]
			.copy_from_slice(&EthereumAddressMapper::to_ethereum_address(converted_public_key).0);
		let message = sp_io::hashing::keccak_256(
			&[
				MAIN_TYPE_HASH.as_slice(),
				&coded_owner_msa_id,
				&coded_expiration,
				&zero_prefixed_address,
			]
			.concat(),
		);
		let combined = [PREFIX_DOMAIN_SEPARATOR.as_ref(), &message].concat();
		combined.into_boxed_slice()
	}
}

/// Structure that is signed for granting permissions to a Provider
#[derive(TypeInfo, Clone, Debug, Decode, DecodeWithMemTracking, Encode, PartialEq, Eq)]
pub struct AddProvider {
	/// The provider being granted permissions
	pub authorized_msa_id: MessageSourceId,
	/// Schemas for which publishing grants are authorized.
	/// This is private intended for internal use only.
	pub schema_ids: Vec<SchemaId>,
	/// The block number at which the proof for grant_delegation expires.
	pub expiration: BlockNumber,
}

impl EIP712Encode for AddProvider {
	fn encode_eip_712(&self) -> Box<[u8]> {
		lazy_static! {
			// get prefix and domain separator
			static ref PREFIX_DOMAIN_SEPARATOR: Box<[u8]> =
				get_eip712_encoding_prefix("0xcccccccccccccccccccccccccccccccccccccccc");

			// signed payload
			static ref MAIN_TYPE_HASH: [u8; 32] = sp_io::hashing::keccak_256(
				b"AddProvider(uint64 authorizedMsaId,uint16[] schemaIds,uint32 expiration)"
			);
		}
		let coded_authorized_msa_id = to_abi_compatible_number(self.authorized_msa_id);
		let schema_ids: Vec<u8> = self
			.schema_ids
			.iter()
			.flat_map(|schema_id| to_abi_compatible_number(*schema_id))
			.collect();
		let schema_ids = sp_io::hashing::keccak_256(&schema_ids);
		let coded_expiration = to_abi_compatible_number(self.expiration);
		let message = sp_io::hashing::keccak_256(
			&[MAIN_TYPE_HASH.as_slice(), &coded_authorized_msa_id, &schema_ids, &coded_expiration]
				.concat(),
		);
		let combined = [PREFIX_DOMAIN_SEPARATOR.as_ref(), &message].concat();
		combined.into_boxed_slice()
	}
}

impl AddProvider {
	/// Create new `AddProvider`
	pub fn new(
		authorized_msa_id: MessageSourceId,
		schema_ids: Option<Vec<SchemaId>>,
		expiration: BlockNumber,
	) -> Self {
		let schema_ids = schema_ids.unwrap_or_default();

		Self { authorized_msa_id, schema_ids, expiration }
	}
}

/// The interface for mutating schemas permissions in a delegation relationship.
pub trait PermittedDelegationSchemas<T: Config> {
	/// Attempt to insert a new schema. Dispatches error when the max allowed schemas are exceeded.
	fn try_insert_schema(&mut self, schema_id: SchemaId) -> Result<(), DispatchError>;

	/// Attempt to insert a collection of schemas. Dispatches error when the max allowed schemas are exceeded.
	fn try_insert_schemas(&mut self, schema_ids: Vec<SchemaId>) -> Result<(), DispatchError> {
		for schema_id in schema_ids.into_iter() {
			self.try_insert_schema(schema_id)?;
		}

		Ok(())
	}

	/// Attempt get and mutate a collection of schemas. Dispatches error when a schema cannot be found.
	fn try_get_mut_schemas(
		&mut self,
		schema_ids: Vec<SchemaId>,
		block_number: BlockNumberFor<T>,
	) -> Result<(), DispatchError> {
		for schema_id in schema_ids.into_iter() {
			self.try_get_mut_schema(schema_id, block_number)?;
		}
		Ok(())
	}

	/// Attempt get and mutate a schema. Dispatches error when a schema cannot be found.
	fn try_get_mut_schema(
		&mut self,
		schema_id: SchemaId,
		block_number: BlockNumberFor<T>,
	) -> Result<(), DispatchError>;
}

/// Implementation of SchemaPermission trait on Delegation type.
impl<T: Config> PermittedDelegationSchemas<T>
	for Delegation<SchemaId, BlockNumberFor<T>, T::MaxSchemaGrantsPerDelegation>
{
	/// Attempt to insert a new schema. Dispatches error when the max allowed schemas are exceeded.
	fn try_insert_schema(&mut self, schema_id: SchemaId) -> Result<(), DispatchError> {
		self.schema_permissions
			.try_insert(schema_id, Default::default())
			.map_err(|_| Error::<T>::ExceedsMaxSchemaGrantsPerDelegation)?;
		Ok(())
	}

	/// Attempt get and mutate a schema. Dispatches error when a schema cannot be found.
	fn try_get_mut_schema(
		&mut self,
		schema_id: SchemaId,
		block_number: BlockNumberFor<T>,
	) -> Result<(), DispatchError> {
		let schema = self
			.schema_permissions
			.get_mut(&schema_id)
			.ok_or(Error::<T>::SchemaNotGranted)?;

		*schema = block_number;

		Ok(())
	}
}