ac_primitives/extrinsics/
signer.rs

1/*
2   Copyright 2019 Supercomputing Systems AG
3
4   Licensed under the Apache License, Version 2.0 (the "License");
5   you may not use this file except in compliance with the License.
6   You may obtain a copy of the License at
7
8	   http://www.apache.org/licenses/LICENSE-2.0
9
10   Unless required by applicable law or agreed to in writing, software
11   distributed under the License is distributed on an "AS IS" BASIS,
12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   See the License for the specific language governing permissions and
14   limitations under the License.
15
16*/
17
18//! Signer used to sign extrinsic.
19
20use crate::config::Config;
21use codec::{Decode, Encode};
22use core::marker::PhantomData;
23use sp_core::{crypto::AccountId32, Pair};
24use sp_runtime::MultiAddress;
25
26pub trait SignExtrinsic<AccountId: Clone + Encode> {
27	type Signature: Encode;
28	type ExtrinsicAddress: Clone + Encode;
29
30	/// Sign a given payload and return the resulting Signature.
31	fn sign(&self, payload: &[u8]) -> Self::Signature;
32
33	/// Return the public account id of the key pair.
34	fn public_account_id(&self) -> &AccountId;
35
36	/// Return the public address of the key pair. This is needed for the
37	/// extrinsic creation, as substrate requires a Lookup transformation
38	/// from Address to AccoundId.
39	fn extrinsic_address(&self) -> Self::ExtrinsicAddress;
40}
41
42#[derive(Encode, Decode, Clone, PartialEq)]
43pub struct ExtrinsicSigner<T: Config> {
44	signer: T::CryptoKey,
45	account_id: T::AccountId,
46	extrinsic_address: T::Address,
47	_phantom: PhantomData<T::Signature>,
48}
49
50impl<T: Config> ExtrinsicSigner<T> {
51	pub fn new(signer: T::CryptoKey) -> Self {
52		let account_id: T::AccountId = signer.public().into();
53		let extrinsic_address: T::Address = account_id.clone().into();
54		Self { signer, account_id, extrinsic_address, _phantom: Default::default() }
55	}
56
57	pub fn signer(&self) -> &T::CryptoKey {
58		&self.signer
59	}
60}
61
62impl<T: Config> SignExtrinsic<T::AccountId> for ExtrinsicSigner<T> {
63	type Signature = T::Signature;
64	type ExtrinsicAddress = T::Address;
65
66	fn sign(&self, payload: &[u8]) -> Self::Signature {
67		self.signer.sign(payload).into()
68	}
69
70	fn public_account_id(&self) -> &T::AccountId {
71		&self.account_id
72	}
73
74	fn extrinsic_address(&self) -> Self::ExtrinsicAddress {
75		self.extrinsic_address.clone()
76	}
77}
78
79impl<T, Signer> From<Signer> for ExtrinsicSigner<T>
80where
81	T: Config,
82	Signer: Pair + Into<T::CryptoKey>,
83{
84	fn from(value: Signer) -> Self {
85		ExtrinsicSigner::<T>::new(value.into())
86	}
87}
88
89/// Extrinsic Signer implementation, that does not enforce Runtime as input.
90/// This is especially useful in no-std environments, where the runtime is not
91/// available.
92#[derive(Encode, Decode, Clone, PartialEq)]
93pub struct StaticExtrinsicSigner<Signer, Signature> {
94	signer: Signer,
95	account_id: AccountId32,
96	extrinsic_address: MultiAddress<AccountId32, ()>,
97	_phantom: PhantomData<Signature>,
98}
99
100impl<Signer, Signature> StaticExtrinsicSigner<Signer, Signature>
101where
102	Signer: Pair,
103	Signer::Public: Into<AccountId32>,
104	Signature: From<Signer::Signature> + Encode + Clone,
105{
106	pub fn new(signer: Signer) -> Self {
107		let account_id = signer.public().into();
108		let extrinsic_address = MultiAddress::from(account_id.clone());
109		Self { signer, account_id, extrinsic_address, _phantom: Default::default() }
110	}
111
112	pub fn signer(&self) -> &Signer {
113		&self.signer
114	}
115}
116
117impl<Signer, Signature> SignExtrinsic<AccountId32> for StaticExtrinsicSigner<Signer, Signature>
118where
119	Signer: Pair,
120	Signature: From<Signer::Signature> + Encode + Clone,
121{
122	type Signature = Signature;
123	type ExtrinsicAddress = MultiAddress<AccountId32, ()>;
124
125	fn sign(&self, payload: &[u8]) -> Self::Signature {
126		self.signer.sign(payload).into()
127	}
128
129	fn public_account_id(&self) -> &AccountId32 {
130		&self.account_id
131	}
132
133	fn extrinsic_address(&self) -> Self::ExtrinsicAddress {
134		self.extrinsic_address.clone()
135	}
136}
137
138#[cfg(test)]
139mod tests {
140	use super::*;
141	use crate::AssetRuntimeConfig;
142	use sp_core::sr25519;
143	use sp_keyring::Sr25519Keyring;
144	use sp_runtime::MultiSignature;
145
146	#[test]
147	fn test_extrinsic_signer_clone() {
148		let pair = Sr25519Keyring::Alice.pair();
149		let signer = ExtrinsicSigner::<AssetRuntimeConfig>::new(pair);
150
151		let _signer2 = signer.clone();
152	}
153
154	#[test]
155	fn test_static_extrinsic_signer_clone() {
156		let pair = Sr25519Keyring::Alice.pair();
157		let signer = StaticExtrinsicSigner::<_, MultiSignature>::new(pair);
158
159		let _signer2 = signer.clone();
160	}
161
162	#[test]
163	fn test_extrinsic_signer_from_sr25519_pair() {
164		let alice: sr25519::Pair = Pair::from_string(
165			"0xe5be9a5092b81bca64be81d212e7f2f9eba183bb7a90954f7b76361f6edb5c0a",
166			None,
167		)
168		.unwrap();
169
170		let es_converted: ExtrinsicSigner<AssetRuntimeConfig> = alice.clone().into();
171		let es_new = ExtrinsicSigner::<AssetRuntimeConfig>::new(alice.clone());
172
173		assert_eq!(es_converted.signer.public(), es_new.signer.public());
174	}
175}