referrerpolicy=no-referrer-when-downgrade

polkadot_sdk_docs/guides/your_first_pallet/
mod.rs

1//! # Currency Pallet
2//!
3//! By the end of this guide, you will have written a small FRAME pallet (see
4//! [`crate::polkadot_sdk::frame_runtime`]) that is capable of handling a simple crypto-currency.
5//! This pallet will:
6//!
7//! 1. Allow anyone to mint new tokens into accounts (which is obviously not a great idea for a real
8//!    system).
9//! 2. Allow any user that owns tokens to transfer them to others.
10//! 3. Track the total issuance of all tokens at all times.
11//!
12//! > This guide will build a currency pallet from scratch using only the lowest primitives of
13//! > FRAME, and is mainly intended for education, not *applicability*. For example, almost all
14//! > FRAME-based runtimes use various techniques to re-use a currency pallet instead of writing
15//! > one. Further advanced FRAME related topics are discussed in [`crate::reference_docs`].
16//!
17//! ## Writing Your First Pallet
18//!
19//! To get started, clone one of the templates mentioned in [`crate::polkadot_sdk::templates`]. We
20//! recommend using the `polkadot-sdk-minimal-template`. You might need to change small parts of
21//! this guide, namely the crate/package names, based on which template you use.
22//!
23//! > Be aware that you can read the entire source code backing this tutorial by clicking on the
24//! > `source` button at the top right of the page.
25//!
26//! You should have studied the following modules as a prelude to this guide:
27//!
28//! - [`crate::reference_docs::blockchain_state_machines`]
29//! - [`crate::reference_docs::trait_based_programming`]
30//! - [`crate::polkadot_sdk::frame_runtime`]
31//!
32//! ## Topics Covered
33//!
34//! The following FRAME topics are covered in this guide:
35//!
36//! - [`pallet::storage`]
37//! - [`pallet::call`]
38//! - [`pallet::event`]
39//! - [`pallet::error`]
40//! - Basics of testing a pallet
41//! - [Constructing a runtime](frame::runtime::prelude::construct_runtime)
42//!
43//! ### Shell Pallet
44//!
45//! Consider the following as a "shell pallet". We continue building the rest of this pallet based
46//! on this template.
47//!
48//! [`pallet::config`] and [`pallet::pallet`] are both mandatory parts of any
49//! pallet. Refer to the documentation of each to get an overview of what they do.
50#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", shell_pallet)]
51//! All of the code that follows in this guide should live inside of the `mod pallet`.
52//!
53//! ### Storage
54//!
55//! First, we will need to create two onchain storage declarations.
56//!
57//! One should be a mapping from account-ids to a balance type, and one value that is the total
58//! issuance.
59//!
60//! > For the rest of this guide, we will opt for a balance type of `u128`. For the sake of
61//! > simplicity, we are hardcoding this type. In a real pallet is best practice to define it as a
62//! > generic bounded type in the `Config` trait, and then specify it in the implementation.
63#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", Balance)]
64//! The definition of these two storage items, based on [`pallet::storage`] details, is as follows:
65#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", TotalIssuance)]
66#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", Balances)]
67//! ### Dispatchables
68//!
69//! Next, we will define the dispatchable functions. As per [`pallet::call`], these will be defined
70//! as normal `fn`s attached to `struct Pallet`.
71#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", impl_pallet)]
72//! The logic of these functions is self-explanatory. Instead, we will focus on the FRAME-related
73//! details:
74//!
75//! - Where do `T::AccountId` and `T::RuntimeOrigin` come from? These are both defined in
76//!  [`frame::prelude::frame_system::Config`], therefore we can access them in `T`.
77//! - What is `ensure_signed`, and what does it do with the aforementioned `T::RuntimeOrigin`? This
78//!   is outside the scope of this guide, and you can learn more about it in the origin reference
79//!   document ([`crate::reference_docs::frame_origin`]). For now, you should only know the
80//!   signature of the function: it takes a generic `T::RuntimeOrigin` and returns a
81//!   `Result<T::AccountId, _>`. So by the end of this function call, we know that this dispatchable
82//!   was signed by `sender`.
83#![doc = docify::embed!("../../substrate/frame/system/src/lib.rs", ensure_signed)]
84//! - Where does `mutate`, `get` and `insert` and other storage APIs come from? All of them are
85//! explained in the corresponding `type`, for example, for `Balances::<T>::insert`, you can look
86//! into [`frame::prelude::StorageMap::insert`].
87//!
88//! - The return type of all dispatchable functions is [`frame::prelude::DispatchResult`]:
89#![doc = docify::embed!("../../substrate/frame/support/src/dispatch.rs", DispatchResult)]
90//! Which is more or less a normal Rust `Result`, with a custom [`frame::prelude::DispatchError`] as
91//! the `Err` variant. We won't cover this error in detail here, but importantly you should know
92//! that there is an `impl From<&'static string> for DispatchError` provided (see
93//! [here](`frame::prelude::DispatchError#impl-From<%26str>-for-DispatchError`)). Therefore,
94//! we can use basic string literals as our error type and `.into()` them into `DispatchError`.
95//!
96//! - Why are all `get` and `mutate` functions returning an `Option`? This is the default behavior
97//!   of FRAME storage APIs. You can learn more about how to override this by looking into
98//!   [`pallet::storage`], and [`frame::prelude::ValueQuery`]/[`frame::prelude::OptionQuery`]
99//!
100//! ### Improving Errors
101//!
102//! How we handle error in the above snippets is fairly rudimentary. Let's look at how this can be
103//! improved. First, we can use [`frame::prelude::ensure`] to express the error slightly better.
104//! This macro will call `.into()` under the hood.
105#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", transfer_better)]
106//! Moreover, you will learn in the [Defensive Programming
107//! section](crate::reference_docs::defensive_programming) that it is always recommended to use
108//! safe arithmetic operations in your runtime. By using [`frame::traits::CheckedSub`], we can not
109//! only take a step in that direction, but also improve the error handing and make it slightly more
110//! ergonomic.
111#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", transfer_better_checked)]
112//! This is more or less all the logic that there is in this basic currency pallet!
113//!
114//! ### Your First (Test) Runtime
115//!
116//! The typical testing code of a pallet lives in a module that imports some preludes useful for
117//! testing, similar to:
118//!
119//! ```
120//! pub mod pallet {
121//! 	// snip -- actually pallet code.
122//! }
123//!
124//! #[cfg(test)]
125//! mod tests {
126//! 	// bring in the testing prelude of frame
127//! 	use frame::testing_prelude::*;
128//! 	// bring in all pallet items
129//! 	use super::pallet::*;
130//!
131//! 	// snip -- rest of the testing code.
132//! }
133//! ```
134//!
135//! Next, we create a "test runtime" in order to test our pallet. Recall from
136//! [`crate::polkadot_sdk::frame_runtime`] that a runtime is a collection of pallets, expressed
137//! through [`frame::runtime::prelude::construct_runtime`]. All runtimes also have to include
138//! [`frame::prelude::frame_system`]. So we expect to see a runtime with two pallet, `frame_system`
139//! and the one we just wrote.
140#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", runtime)]
141//! > [`frame::pallet_macros::derive_impl`] is a FRAME feature that enables developers to have
142//! > defaults for associated types.
143//!
144//! Recall that within our pallet, (almost) all blocks of code are generic over `<T: Config>`. And,
145//! because `trait Config: frame_system::Config`, we can get access to all items in `Config` (or
146//! `frame_system::Config`) using `T::NameOfItem`. This is all within the boundaries of how
147//! Rust traits and generics work. If unfamiliar with this pattern, read
148//! [`crate::reference_docs::trait_based_programming`] before going further.
149//!
150//! Crucially, a typical FRAME runtime contains a `struct Runtime`. The main role of this `struct`
151//! is to implement the `trait Config` of all pallets. That is, anywhere within your pallet code
152//! where you see `<T: Config>` (read: *"some type `T` that implements `Config`"*), in the runtime,
153//! it can be replaced with `<Runtime>`, because `Runtime` implements `Config` of all pallets, as we
154//! see above.
155//!
156//! Another way to think about this is that within a pallet, a lot of types are "unknown" and, we
157//! only know that they will be provided at some later point. For example, when you write
158//! `T::AccountId` (which is short for `<T as frame_system::Config>::AccountId`) in your pallet,
159//! you are in fact saying "*Some type `AccountId` that will be known later*". That "later" is in
160//! fact when you specify these types when you implement all `Config` traits for `Runtime`.
161//!
162//! As you see above, `frame_system::Config` is setting the `AccountId` to `u64`. Of course, a real
163//! runtime will not use this type, and instead reside to a proper type like a 32-byte standard
164//! public key. This is a HUGE benefit that FRAME developers can tap into: through the framework
165//! being so generic, different types can always be customized to simple things when needed.
166//!
167//! > Imagine how hard it would have been if all tests had to use a real 32-byte account id, as
168//! > opposed to just a u64 number ๐Ÿ™ˆ.
169//!
170//! ### Your First Test
171//!
172//! The above is all you need to execute the dispatchables of your pallet. The last thing you need
173//! to learn is that all of your pallet testing code should be wrapped in
174//! [`frame::testing_prelude::TestState`]. This is a type that provides access to an in-memory state
175//! to be used in our tests.
176#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", first_test)]
177//! In the first test, we simply assert that there is no total issuance, and no balance associated
178//! with Alice's account. Then, we mint some balance into Alice's, and re-check.
179//!
180//! As noted above, the `T::AccountId` is now `u64`. Moreover, `Runtime` is replacing `<T: Config>`.
181//! This is why for example you see `Balances::<Runtime>::get(..)`. Finally, notice that the
182//! dispatchables are simply functions that can be called on top of the `Pallet` struct.
183//!
184//! Congratulations! You have written your first pallet and tested it! Next, we learn a few optional
185//! steps to improve our pallet.
186//!
187//! ## Improving the Currency Pallet
188//!
189//! ### Better Test Setup
190//!
191//! Idiomatic FRAME pallets often use Builder pattern to define their initial state.
192//!
193//! > The Polkadot Blockchain Academy's Rust entrance exam has a
194//! > [section](https://github.com/Polkadot-Blockchain-Academy/pba-qualifier-exam/blob/main/src/m_builder.rs)
195//! > on this that you can use to learn the Builder Pattern.
196//!
197//! Let's see how we can implement a better test setup using this pattern. First, we define a
198//! `struct StateBuilder`.
199#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", StateBuilder)]
200//! This struct is meant to contain the same list of accounts and balances that we want to have at
201//! the beginning of each block. We hardcoded this to `let accounts = vec![(ALICE, 100), (2, 100)];`
202//! so far. Then, if desired, we attach a default value for this struct.
203#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", default_state_builder)]
204//! Like any other builder pattern, we attach functions to the type to mutate its internal
205//! properties.
206#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", impl_state_builder_add)]
207//!  Finally --the useful part-- we write our own custom `build_and_execute` function on
208//! this type. This function will do multiple things:
209//!
210//! 1. It would consume `self` to produce our `TestState` based on the properties that we attached
211//!    to `self`.
212//! 2. It would execute any test function that we pass in as closure.
213//! 3. A nifty trick, this allows our test setup to have some code that is executed both before and
214//!    after each test. For example, in this test, we do some additional checking about the
215//!    correctness of the `TotalIssuance`. We leave it up to you as an exercise to learn why the
216//!    assertion should always hold, and how it is checked.
217#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", impl_state_builder_build)]
218//! We can write tests that specifically check the initial state, and making sure our `StateBuilder`
219//! is working exactly as intended.
220#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", state_builder_works)]
221#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", state_builder_add_balance)]
222//! ### More Tests
223//!
224//! Now that we have a more ergonomic test setup, let's see how a well written test for transfer and
225//! mint would look like.
226#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", transfer_works)]
227#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", mint_works)]
228//! It is always a good idea to build a mental model where you write *at least* one test for each
229//! "success path" of a dispatchable, and one test for each "failure path", such as:
230#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", transfer_from_non_existent_fails)]
231//! We leave it up to you to write a test that triggers the `InsufficientBalance` error.
232//!
233//! ### Event and Error
234//!
235//! Our pallet is mainly missing two parts that are common in most FRAME pallets: Events, and
236//! Errors. First, let's understand what each is.
237//!
238//! - **Error**: The static string-based error scheme we used so far is good for readability, but it
239//!   has a few drawbacks. The biggest problem with strings are that they are not type safe, e.g. a
240//!   match statement cannot be exhaustive. These string literals will bloat the final wasm blob,
241//!   and are relatively heavy to transmit and encode/decode. Moreover, it is easy to mistype them
242//!   by one character. FRAME errors are exactly a solution to maintain readability, whilst fixing
243//!   the drawbacks mentioned. In short, we use an enum to represent different variants of our
244//!   error. These variants are then mapped in an efficient way (using only `u8` indices) to
245//!   [`sp_runtime::DispatchError::Module`]. Read more about this in [`pallet::error`].
246//!
247//! - **Event**: Events are akin to the return type of dispatchables. They are mostly data blobs
248//!   emitted by the runtime to let outside world know what is happening inside the pallet. Since
249//!   otherwise, the outside world does not have an easy access to the state changes. They should
250//!   represent what happened at the end of a dispatch operation. Therefore, the convention is to
251//!   use passive tense for event names (eg. `SomethingHappened`). This allows other sub-systems or
252//!   external parties (eg. a light-node, a DApp) to listen to particular events happening, without
253//!   needing to re-execute the whole state transition function.
254//!
255//! With the explanation out of the way, let's see how these components can be added. Both follow a
256//! fairly familiar syntax: normal Rust enums, with extra [`pallet::event`] and [`pallet::error`]
257//! attributes attached.
258#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", Event)]
259#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", Error)]
260//! One slightly custom part of this is the [`pallet::generate_deposit`] part. Without going into
261//! too much detail, in order for a pallet to emit events to the rest of the system, it needs to do
262//! two things:
263//!
264//! 1. Declare a type in its `Config` that refers to the overarching event type of the runtime. In
265//! short, by doing this, the pallet is expressing an important bound: `type RuntimeEvent:
266//! From<Event<Self>>`. Read: a `RuntimeEvent` exists, and it can be created from the local `enum
267//! Event` of this pallet. This enables the pallet to convert its `Event` into `RuntimeEvent`, and
268//! store it where needed.
269//!
270//! 2. But, doing this conversion and storing is too much to expect each pallet to define. FRAME
271//! provides a default way of storing events, and this is what [`pallet::generate_deposit`] is
272//! doing.
273#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", config_v2)]
274//! > These `Runtime*` types are better explained in
275//! > [`crate::reference_docs::frame_runtime_types`].
276//!
277//! Then, we can rewrite the `transfer` dispatchable as such:
278#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", transfer_v2)]
279//! Then, notice how now we would need to provide this `type RuntimeEvent` in our test runtime
280//! setup.
281#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", runtime_v2)]
282//! In this snippet, the actual `RuntimeEvent` type (right hand side of `type RuntimeEvent =
283//! RuntimeEvent`) is generated by
284//! [`construct_runtime`](frame::runtime::prelude::construct_runtime). An interesting way to inspect
285//! this type is to see its definition in rust-docs:
286//! [`crate::guides::your_first_pallet::pallet_v2::tests::runtime_v2::RuntimeEvent`].
287//!
288//!
289//! ## What Next?
290//!
291//! The following topics where used in this guide, but not covered in depth. It is suggested to
292//! study them subsequently:
293//!
294//! - [`crate::reference_docs::defensive_programming`].
295//! - [`crate::reference_docs::frame_origin`].
296//! - [`crate::reference_docs::frame_runtime_types`].
297//! - The pallet we wrote in this guide was using `dev_mode`, learn more in [`pallet::config`].
298//! - Learn more about the individual pallet items/macros, such as event and errors and call, in
299//!   [`frame::pallet_macros`].
300//!
301//! [`pallet::storage`]: frame_support::pallet_macros::storage
302//! [`pallet::call`]: frame_support::pallet_macros::call
303//! [`pallet::event`]: frame_support::pallet_macros::event
304//! [`pallet::error`]: frame_support::pallet_macros::error
305//! [`pallet::pallet`]: frame_support::pallet
306//! [`pallet::config`]: frame_support::pallet_macros::config
307//! [`pallet::generate_deposit`]: frame_support::pallet_macros::generate_deposit
308
309#[docify::export]
310#[frame::pallet(dev_mode)]
311pub mod shell_pallet {
312	use frame::prelude::*;
313
314	#[pallet::config]
315	pub trait Config: frame_system::Config {}
316
317	#[pallet::pallet]
318	pub struct Pallet<T>(_);
319}
320
321#[frame::pallet(dev_mode)]
322pub mod pallet {
323	use frame::prelude::*;
324
325	#[docify::export]
326	pub type Balance = u128;
327
328	#[pallet::config]
329	pub trait Config: frame_system::Config {}
330
331	#[pallet::pallet]
332	pub struct Pallet<T>(_);
333
334	#[docify::export]
335	/// Single storage item, of type `Balance`.
336	#[pallet::storage]
337	pub type TotalIssuance<T: Config> = StorageValue<_, Balance>;
338
339	#[docify::export]
340	/// A mapping from `T::AccountId` to `Balance`
341	#[pallet::storage]
342	pub type Balances<T: Config> = StorageMap<_, _, T::AccountId, Balance>;
343
344	#[docify::export(impl_pallet)]
345	#[pallet::call]
346	impl<T: Config> Pallet<T> {
347		/// An unsafe mint that can be called by anyone. Not a great idea.
348		pub fn mint_unsafe(
349			origin: T::RuntimeOrigin,
350			dest: T::AccountId,
351			amount: Balance,
352		) -> DispatchResult {
353			// ensure that this is a signed account, but we don't really check `_anyone`.
354			let _anyone = ensure_signed(origin)?;
355
356			// update the balances map. Notice how all `<T: Config>` remains as `<T>`.
357			Balances::<T>::mutate(dest, |b| *b = Some(b.unwrap_or(0) + amount));
358			// update total issuance.
359			TotalIssuance::<T>::mutate(|t| *t = Some(t.unwrap_or(0) + amount));
360
361			Ok(())
362		}
363
364		/// Transfer `amount` from `origin` to `dest`.
365		pub fn transfer(
366			origin: T::RuntimeOrigin,
367			dest: T::AccountId,
368			amount: Balance,
369		) -> DispatchResult {
370			let sender = ensure_signed(origin)?;
371
372			// ensure sender has enough balance, and if so, calculate what is left after `amount`.
373			let sender_balance = Balances::<T>::get(&sender).ok_or("NonExistentAccount")?;
374			if sender_balance < amount {
375				return Err("InsufficientBalance".into());
376			}
377			let remainder = sender_balance - amount;
378
379			// update sender and dest balances.
380			Balances::<T>::mutate(dest, |b| *b = Some(b.unwrap_or(0) + amount));
381			Balances::<T>::insert(&sender, remainder);
382
383			Ok(())
384		}
385	}
386
387	#[allow(unused)]
388	impl<T: Config> Pallet<T> {
389		#[docify::export]
390		pub fn transfer_better(
391			origin: T::RuntimeOrigin,
392			dest: T::AccountId,
393			amount: Balance,
394		) -> DispatchResult {
395			let sender = ensure_signed(origin)?;
396
397			let sender_balance = Balances::<T>::get(&sender).ok_or("NonExistentAccount")?;
398			ensure!(sender_balance >= amount, "InsufficientBalance");
399			let remainder = sender_balance - amount;
400
401			// .. snip
402			Ok(())
403		}
404
405		#[docify::export]
406		/// Transfer `amount` from `origin` to `dest`.
407		pub fn transfer_better_checked(
408			origin: T::RuntimeOrigin,
409			dest: T::AccountId,
410			amount: Balance,
411		) -> DispatchResult {
412			let sender = ensure_signed(origin)?;
413
414			let sender_balance = Balances::<T>::get(&sender).ok_or("NonExistentAccount")?;
415			let remainder = sender_balance.checked_sub(amount).ok_or("InsufficientBalance")?;
416
417			// .. snip
418			Ok(())
419		}
420	}
421
422	#[cfg(any(test, doc))]
423	pub(crate) mod tests {
424		use crate::guides::your_first_pallet::pallet::*;
425
426		#[docify::export(testing_prelude)]
427		use frame::testing_prelude::*;
428
429		pub(crate) const ALICE: u64 = 1;
430		pub(crate) const BOB: u64 = 2;
431		pub(crate) const CHARLIE: u64 = 3;
432
433		#[docify::export]
434		// This runtime is only used for testing, so it should be somewhere like `#[cfg(test)] mod
435		// tests { .. }`
436		mod runtime {
437			use super::*;
438			// we need to reference our `mod pallet` as an identifier to pass to
439			// `construct_runtime`.
440			// YOU HAVE TO CHANGE THIS LINE BASED ON YOUR TEMPLATE
441			use crate::guides::your_first_pallet::pallet as pallet_currency;
442
443			construct_runtime!(
444				pub enum Runtime {
445					// ---^^^^^^ This is where `enum Runtime` is defined.
446					System: frame_system,
447					Currency: pallet_currency,
448				}
449			);
450
451			#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
452			impl frame_system::Config for Runtime {
453				type Block = MockBlock<Runtime>;
454				// within pallet we just said `<T as frame_system::Config>::AccountId`, now we
455				// finally specified it.
456				type AccountId = u64;
457			}
458
459			// our simple pallet has nothing to be configured.
460			impl pallet_currency::Config for Runtime {}
461		}
462
463		pub(crate) use runtime::*;
464
465		#[allow(unused)]
466		#[docify::export]
467		fn new_test_state_basic() -> TestState {
468			let mut state = TestState::new_empty();
469			let accounts = vec![(ALICE, 100), (BOB, 100)];
470			state.execute_with(|| {
471				for (who, amount) in &accounts {
472					Balances::<Runtime>::insert(who, amount);
473					TotalIssuance::<Runtime>::mutate(|b| *b = Some(b.unwrap_or(0) + amount));
474				}
475			});
476
477			state
478		}
479
480		#[docify::export]
481		pub(crate) struct StateBuilder {
482			balances: Vec<(<Runtime as frame_system::Config>::AccountId, Balance)>,
483		}
484
485		#[docify::export(default_state_builder)]
486		impl Default for StateBuilder {
487			fn default() -> Self {
488				Self { balances: vec![(ALICE, 100), (BOB, 100)] }
489			}
490		}
491
492		#[docify::export(impl_state_builder_add)]
493		impl StateBuilder {
494			fn add_balance(
495				mut self,
496				who: <Runtime as frame_system::Config>::AccountId,
497				amount: Balance,
498			) -> Self {
499				self.balances.push((who, amount));
500				self
501			}
502		}
503
504		#[docify::export(impl_state_builder_build)]
505		impl StateBuilder {
506			pub(crate) fn build_and_execute(self, test: impl FnOnce() -> ()) {
507				let mut ext = TestState::new_empty();
508				ext.execute_with(|| {
509					for (who, amount) in &self.balances {
510						Balances::<Runtime>::insert(who, amount);
511						TotalIssuance::<Runtime>::mutate(|b| *b = Some(b.unwrap_or(0) + amount));
512					}
513				});
514
515				ext.execute_with(test);
516
517				// assertions that must always hold
518				ext.execute_with(|| {
519					assert_eq!(
520						Balances::<Runtime>::iter().map(|(_, x)| x).sum::<u128>(),
521						TotalIssuance::<Runtime>::get().unwrap_or_default()
522					);
523				})
524			}
525		}
526
527		#[docify::export]
528		#[test]
529		fn first_test() {
530			TestState::new_empty().execute_with(|| {
531				// We expect Alice's account to have no funds.
532				assert_eq!(Balances::<Runtime>::get(&ALICE), None);
533				assert_eq!(TotalIssuance::<Runtime>::get(), None);
534
535				// mint some funds into Alice's account.
536				assert_ok!(Pallet::<Runtime>::mint_unsafe(
537					RuntimeOrigin::signed(ALICE),
538					ALICE,
539					100
540				));
541
542				// re-check the above
543				assert_eq!(Balances::<Runtime>::get(&ALICE), Some(100));
544				assert_eq!(TotalIssuance::<Runtime>::get(), Some(100));
545			})
546		}
547
548		#[docify::export]
549		#[test]
550		fn state_builder_works() {
551			StateBuilder::default().build_and_execute(|| {
552				assert_eq!(Balances::<Runtime>::get(&ALICE), Some(100));
553				assert_eq!(Balances::<Runtime>::get(&BOB), Some(100));
554				assert_eq!(Balances::<Runtime>::get(&CHARLIE), None);
555				assert_eq!(TotalIssuance::<Runtime>::get(), Some(200));
556			});
557		}
558
559		#[docify::export]
560		#[test]
561		fn state_builder_add_balance() {
562			StateBuilder::default().add_balance(CHARLIE, 42).build_and_execute(|| {
563				assert_eq!(Balances::<Runtime>::get(&CHARLIE), Some(42));
564				assert_eq!(TotalIssuance::<Runtime>::get(), Some(242));
565			})
566		}
567
568		#[test]
569		#[should_panic]
570		fn state_builder_duplicate_genesis_fails() {
571			StateBuilder::default()
572				.add_balance(CHARLIE, 42)
573				.add_balance(CHARLIE, 43)
574				.build_and_execute(|| {
575					assert_eq!(Balances::<Runtime>::get(&CHARLIE), None);
576					assert_eq!(TotalIssuance::<Runtime>::get(), Some(242));
577				})
578		}
579
580		#[docify::export]
581		#[test]
582		fn mint_works() {
583			StateBuilder::default().build_and_execute(|| {
584				// given the initial state, when:
585				assert_ok!(Pallet::<Runtime>::mint_unsafe(RuntimeOrigin::signed(ALICE), BOB, 100));
586
587				// then:
588				assert_eq!(Balances::<Runtime>::get(&BOB), Some(200));
589				assert_eq!(TotalIssuance::<Runtime>::get(), Some(300));
590
591				// given:
592				assert_ok!(Pallet::<Runtime>::mint_unsafe(
593					RuntimeOrigin::signed(ALICE),
594					CHARLIE,
595					100
596				));
597
598				// then:
599				assert_eq!(Balances::<Runtime>::get(&CHARLIE), Some(100));
600				assert_eq!(TotalIssuance::<Runtime>::get(), Some(400));
601			});
602		}
603
604		#[docify::export]
605		#[test]
606		fn transfer_works() {
607			StateBuilder::default().build_and_execute(|| {
608				// given the initial state, when:
609				assert_ok!(Pallet::<Runtime>::transfer(RuntimeOrigin::signed(ALICE), BOB, 50));
610
611				// then:
612				assert_eq!(Balances::<Runtime>::get(&ALICE), Some(50));
613				assert_eq!(Balances::<Runtime>::get(&BOB), Some(150));
614				assert_eq!(TotalIssuance::<Runtime>::get(), Some(200));
615
616				// when:
617				assert_ok!(Pallet::<Runtime>::transfer(RuntimeOrigin::signed(BOB), ALICE, 50));
618
619				// then:
620				assert_eq!(Balances::<Runtime>::get(&ALICE), Some(100));
621				assert_eq!(Balances::<Runtime>::get(&BOB), Some(100));
622				assert_eq!(TotalIssuance::<Runtime>::get(), Some(200));
623			});
624		}
625
626		#[docify::export]
627		#[test]
628		fn transfer_from_non_existent_fails() {
629			StateBuilder::default().build_and_execute(|| {
630				// given the initial state, when:
631				assert_err!(
632					Pallet::<Runtime>::transfer(RuntimeOrigin::signed(CHARLIE), ALICE, 10),
633					"NonExistentAccount"
634				);
635
636				// then nothing has changed.
637				assert_eq!(Balances::<Runtime>::get(&ALICE), Some(100));
638				assert_eq!(Balances::<Runtime>::get(&BOB), Some(100));
639				assert_eq!(Balances::<Runtime>::get(&CHARLIE), None);
640				assert_eq!(TotalIssuance::<Runtime>::get(), Some(200));
641			});
642		}
643	}
644}
645
646#[frame::pallet(dev_mode)]
647pub mod pallet_v2 {
648	use super::pallet::Balance;
649	use frame::prelude::*;
650
651	#[docify::export(config_v2)]
652	#[pallet::config]
653	pub trait Config: frame_system::Config {
654		/// The overarching event type of the runtime.
655		#[allow(deprecated)]
656		type RuntimeEvent: From<Event<Self>>
657			+ IsType<<Self as frame_system::Config>::RuntimeEvent>
658			+ TryInto<Event<Self>>;
659	}
660
661	#[pallet::pallet]
662	pub struct Pallet<T>(_);
663
664	#[pallet::storage]
665	pub type Balances<T: Config> = StorageMap<_, _, T::AccountId, Balance>;
666
667	#[pallet::storage]
668	pub type TotalIssuance<T: Config> = StorageValue<_, Balance>;
669
670	#[docify::export]
671	#[pallet::error]
672	pub enum Error<T> {
673		/// Account does not exist.
674		NonExistentAccount,
675		/// Account does not have enough balance.
676		InsufficientBalance,
677	}
678
679	#[docify::export]
680	#[pallet::event]
681	#[pallet::generate_deposit(pub(super) fn deposit_event)]
682	pub enum Event<T: Config> {
683		/// A transfer succeeded.
684		Transferred { from: T::AccountId, to: T::AccountId, amount: Balance },
685	}
686
687	#[pallet::call]
688	impl<T: Config> Pallet<T> {
689		#[docify::export(transfer_v2)]
690		pub fn transfer(
691			origin: T::RuntimeOrigin,
692			dest: T::AccountId,
693			amount: Balance,
694		) -> DispatchResult {
695			let sender = ensure_signed(origin)?;
696
697			// ensure sender has enough balance, and if so, calculate what is left after `amount`.
698			let sender_balance =
699				Balances::<T>::get(&sender).ok_or(Error::<T>::NonExistentAccount)?;
700			let remainder =
701				sender_balance.checked_sub(amount).ok_or(Error::<T>::InsufficientBalance)?;
702
703			Balances::<T>::mutate(&dest, |b| *b = Some(b.unwrap_or(0) + amount));
704			Balances::<T>::insert(&sender, remainder);
705
706			Self::deposit_event(Event::<T>::Transferred { from: sender, to: dest, amount });
707
708			Ok(())
709		}
710	}
711
712	#[cfg(any(test, doc))]
713	pub mod tests {
714		use super::{super::pallet::tests::StateBuilder, *};
715		use frame::testing_prelude::*;
716		const ALICE: u64 = 1;
717		const BOB: u64 = 2;
718
719		#[docify::export]
720		pub mod runtime_v2 {
721			use super::*;
722			use crate::guides::your_first_pallet::pallet_v2 as pallet_currency;
723
724			construct_runtime!(
725				pub enum Runtime {
726					System: frame_system,
727					Currency: pallet_currency,
728				}
729			);
730
731			#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
732			impl frame_system::Config for Runtime {
733				type Block = MockBlock<Runtime>;
734				type AccountId = u64;
735			}
736
737			impl pallet_currency::Config for Runtime {
738				type RuntimeEvent = RuntimeEvent;
739			}
740		}
741
742		pub(crate) use runtime_v2::*;
743
744		#[docify::export(transfer_works_v2)]
745		#[test]
746		fn transfer_works() {
747			StateBuilder::default().build_and_execute(|| {
748				// skip the genesis block, as events are not deposited there and we need them for
749				// the final assertion.
750				System::set_block_number(ALICE);
751
752				// given the initial state, when:
753				assert_ok!(Pallet::<Runtime>::transfer(RuntimeOrigin::signed(ALICE), BOB, 50));
754
755				// then:
756				assert_eq!(Balances::<Runtime>::get(&ALICE), Some(50));
757				assert_eq!(Balances::<Runtime>::get(&BOB), Some(150));
758				assert_eq!(TotalIssuance::<Runtime>::get(), Some(200));
759
760				// now we can also check that an event has been deposited:
761				assert_eq!(
762					System::read_events_for_pallet::<Event<Runtime>>(),
763					vec![Event::Transferred { from: ALICE, to: BOB, amount: 50 }]
764				);
765			});
766		}
767	}
768}