referrerpolicy=no-referrer-when-downgrade
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
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
// This file is part of Substrate.

// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// 	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! # Default Config Pallet Example
//!
//! A simple example of a FRAME pallet that utilizes [`frame_support::derive_impl`] to demonstrate
//! the simpler way to implement `Config` trait of pallets. This example only showcases this in a
//! `mock.rs` environment, but the same applies to a real runtime as well.
//!
//! See the source code of [`tests`] for a real examples.
//!
//! Study the following types:
//!
//! - [`pallet::DefaultConfig`], and how it differs from [`pallet::Config`].
//! - [`struct@pallet::config_preludes::TestDefaultConfig`] and how it implements
//!   [`pallet::DefaultConfig`].
//! - Notice how [`pallet::DefaultConfig`] is independent of [`frame_system::Config`].

#![cfg_attr(not(feature = "std"), no_std)]

extern crate alloc;

#[frame_support::pallet]
pub mod pallet {
	use frame_support::pallet_prelude::*;

	/// This pallet is annotated to have a default config. This will auto-generate
	/// [`DefaultConfig`].
	///
	/// It will be an identical, but won't have anything that is `#[pallet::no_default]`.
	#[pallet::config(with_default)]
	pub trait Config: frame_system::Config {
		/// The overarching event type. This is coming from the runtime, and cannot have a default.
		/// In general, `Runtime*`-oriented types cannot have a sensible default.
		#[pallet::no_default] // optional. `RuntimeEvent` is automatically excluded as well.
		type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;

		/// The overarching task type.
		#[pallet::no_default]
		type RuntimeTask: Task;

		/// An input parameter to this pallet. This value can have a default, because it is not
		/// reliant on `frame_system::Config` or the overarching runtime in any way.
		type WithDefaultValue: Get<u32>;

		/// Same as [`Config::WithDefaultValue`], but we don't intend to define a default for this
		/// in our tests below.
		type OverwrittenDefaultValue: Get<u32>;

		/// An input parameter that relies on `<Self as frame_system::Config>::AccountId`. This can
		/// too have a default, as long as as it is present in `frame_system::DefaultConfig`.
		type CanDeriveDefaultFromSystem: Get<Self::AccountId>;

		/// We might chose to declare as one that doesn't have a default, for whatever semantical
		/// reason.
		#[pallet::no_default]
		type HasNoDefault: Get<u32>;

		/// Some types can technically have no default, such as those the rely on
		/// `frame_system::Config` but are not present in `frame_system::DefaultConfig`. For
		/// example, a `RuntimeCall` cannot reasonably have a default.
		#[pallet::no_default] // if we skip this, there will be a compiler error.
		type CannotHaveDefault: Get<Self::RuntimeCall>;

		/// Something that is a normal type, with default.
		type WithDefaultType;

		/// Same as [`Config::WithDefaultType`], but we don't intend to define a default for this
		/// in our tests below.
		type OverwrittenDefaultType;
	}

	/// Container for different types that implement [`DefaultConfig`]` of this pallet.
	pub mod config_preludes {
		// This will help use not need to disambiguate anything when using `derive_impl`.
		use super::*;
		use frame_support::derive_impl;

		/// A type providing default configurations for this pallet in testing environment.
		pub struct TestDefaultConfig;

		#[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)]
		impl frame_system::DefaultConfig for TestDefaultConfig {}

		#[frame_support::register_default_impl(TestDefaultConfig)]
		impl DefaultConfig for TestDefaultConfig {
			type WithDefaultValue = frame_support::traits::ConstU32<42>;
			type OverwrittenDefaultValue = frame_support::traits::ConstU32<42>;

			// `frame_system::config_preludes::TestDefaultConfig` declares account-id as u64.
			type CanDeriveDefaultFromSystem = frame_support::traits::ConstU64<42>;

			type WithDefaultType = u32;
			type OverwrittenDefaultType = u32;
		}

		/// A type providing default configurations for this pallet in another environment. Examples
		/// could be a parachain, or a solochain.
		///
		/// Appropriate derive for `frame_system::DefaultConfig` needs to be provided. In this
		/// example, we simple derive `frame_system::config_preludes::TestDefaultConfig` again.
		pub struct OtherDefaultConfig;

		#[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)]
		impl frame_system::DefaultConfig for OtherDefaultConfig {}

		#[frame_support::register_default_impl(OtherDefaultConfig)]
		impl DefaultConfig for OtherDefaultConfig {
			type WithDefaultValue = frame_support::traits::ConstU32<66>;
			type OverwrittenDefaultValue = frame_support::traits::ConstU32<66>;
			type CanDeriveDefaultFromSystem = frame_support::traits::ConstU64<42>;
			type WithDefaultType = u32;
			type OverwrittenDefaultType = u32;
		}
	}

	#[pallet::pallet]
	pub struct Pallet<T>(_);

	#[pallet::event]
	pub enum Event<T: Config> {}
}

#[cfg(any(test, doc))]
pub mod tests {
	use super::*;
	use frame_support::{derive_impl, parameter_types};
	use pallet::{self as pallet_default_config_example, config_preludes::*};

	type Block = frame_system::mocking::MockBlock<Runtime>;

	frame_support::construct_runtime!(
		pub enum Runtime {
			System: frame_system,
			DefaultPallet: pallet_default_config_example,
		}
	);

	#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
	impl frame_system::Config for Runtime {
		// these items are defined by frame-system as `no_default`, so we must specify them here.
		type Block = Block;

		// all of this is coming from `frame_system::config_preludes::TestDefaultConfig`.

		// type Nonce = u32;
		// type BlockNumber = u32;
		// type Hash = sp_core::hash::H256;
		// type Hashing = sp_runtime::traits::BlakeTwo256;
		// type AccountId = u64;
		// type Lookup = sp_runtime::traits::IdentityLookup<u64>;
		// type BlockHashCount = frame_support::traits::ConstU32<10>;
		// type MaxConsumers = frame_support::traits::ConstU32<16>;
		// type AccountData = ();
		// type OnNewAccount = ();
		// type OnKilledAccount = ();
		// type SystemWeightInfo = ();
		// type SS58Prefix = ();
		// type Version = ();
		// type BlockWeights = ();
		// type BlockLength = ();
		// type DbWeight = ();
		// type BaseCallFilter = frame_support::traits::Everything;
		// type BlockHashCount = frame_support::traits::ConstU64<10>;
		// type OnSetCode = ();

		// These are marked as `#[inject_runtime_type]`. Hence, they are being injected as
		// types generated by `construct_runtime`.

		// type RuntimeOrigin = RuntimeOrigin;
		// type RuntimeCall = RuntimeCall;
		// type RuntimeEvent = RuntimeEvent;
		// type PalletInfo = PalletInfo;

		// you could still overwrite any of them if desired.
		type SS58Prefix = frame_support::traits::ConstU16<456>;
	}

	parameter_types! {
		pub const SomeCall: RuntimeCall = RuntimeCall::System(frame_system::Call::<Runtime>::remark { remark: alloc::vec![] });
	}

	#[derive_impl(TestDefaultConfig as pallet::DefaultConfig)]
	impl pallet_default_config_example::Config for Runtime {
		// These two both cannot have defaults.
		type RuntimeEvent = RuntimeEvent;
		type RuntimeTask = RuntimeTask;

		type HasNoDefault = frame_support::traits::ConstU32<1>;
		type CannotHaveDefault = SomeCall;

		type OverwrittenDefaultValue = frame_support::traits::ConstU32<678>;
		type OverwrittenDefaultType = u128;
	}

	#[test]
	fn it_works() {
		use frame_support::traits::Get;
		use pallet::{Config, DefaultConfig};

		// assert one of the value types that is not overwritten.
		assert_eq!(
			<<Runtime as Config>::WithDefaultValue as Get<u32>>::get(),
			<<TestDefaultConfig as DefaultConfig>::WithDefaultValue as Get<u32>>::get()
		);

		// assert one of the value types that is overwritten.
		assert_eq!(<<Runtime as Config>::OverwrittenDefaultValue as Get<u32>>::get(), 678u32);

		// assert one of the types that is not overwritten.
		assert_eq!(
			std::any::TypeId::of::<<Runtime as Config>::WithDefaultType>(),
			std::any::TypeId::of::<<TestDefaultConfig as DefaultConfig>::WithDefaultType>()
		);

		// assert one of the types that is overwritten.
		assert_eq!(
			std::any::TypeId::of::<<Runtime as Config>::OverwrittenDefaultType>(),
			std::any::TypeId::of::<u128>()
		)
	}
}