Make Balances Configurable

There is nothing new to learn in this step, just repeating the same process we did for our System Pallet for the Balances pallet.

In this case, our Config trait will only have two associated types: AccountId and Balance.

For this step, try to avoid looking at the solution, and instead refer to the changes you made to get the System Pallet configurable.

  1. Define the Config trait which will have your associated types.
  2. Make sure these types have their trait constraints defined in Config.
  3. Update your struct Pallet to use T: Config and reference your types using the T:: syntax.
  4. Update all of your functions to use the T:: syntax.
  5. Update your test, creating a struct TestConfig, and implementing Config for it, and using it to instantiate your Pallet struct.
  6. Go to your main.rs file, and implement balances::Config for the Runtime struct.
  7. Update your Runtime definition to instantiate balances::Pallet with Self.

If you have made it this far, I think it is fair to say you have made it over the hardest part of this tutorial, and the hardest part of using Rust in Substrate.

It is important to take a step back and remember that while these abstractions make your code a bit more complicated to fully understand, it also makes your code extremely flexible, at zero cost to performance and safety thanks to the Rust compiler.

#![allow(unused)]
fn main() {
use num::traits::{CheckedAdd, CheckedSub, Zero};
use std::collections::BTreeMap;

/*
	TODO: Combine all generic types and their trait bounds into a single `pub trait Config`.
	When you are done, your `Pallet` can simply be defined with `Pallet<T: Config>`.
*/

/// This is the Balances Module.
/// It is a simple module which keeps track of how much balance each account has in this state
/// machine.
#[derive(Debug)]
pub struct Pallet<AccountId, Balance> {
	// A simple storage mapping from accounts to their balances.
	balances: BTreeMap<AccountId, Balance>,
}

/*
	TODO: Update all of these functions to use your new configuration trait.
*/

impl<AccountId, Balance> Pallet<AccountId, Balance>
where
	AccountId: Ord + Clone,
	Balance: Zero + CheckedSub + CheckedAdd + Copy,
{
	/// Create a new instance of the balances module.
	pub fn new() -> Self {
		Self { balances: BTreeMap::new() }
	}

	/// Set the balance of an account `who` to some `amount`.
	pub fn set_balance(&mut self, who: &AccountId, amount: Balance) {
		self.balances.insert(who.clone(), amount);
	}

	/// Get the balance of an account `who`.
	/// If the account has no stored balance, we return zero.
	pub fn balance(&self, who: &AccountId) -> Balance {
		*self.balances.get(who).unwrap_or(&Balance::zero())
	}

	/// Transfer `amount` from one account to another.
	/// This function verifies that `from` has at least `amount` balance to transfer,
	/// and that no mathematical overflows occur.
	pub fn transfer(
		&mut self,
		caller: AccountId,
		to: AccountId,
		amount: Balance,
	) -> Result<(), &'static str> {
		let caller_balance = self.balance(&caller);
		let to_balance = self.balance(&to);

		let new_caller_balance = caller_balance.checked_sub(&amount).ok_or("Not enough funds.")?;
		let new_to_balance = to_balance.checked_add(&amount).ok_or("Overflow")?;

		self.balances.insert(caller, new_caller_balance);
		self.balances.insert(to, new_to_balance);

		Ok(())
	}
}

#[cfg(test)]
mod tests {
	/*
		TODO: Create a `struct TestConfig`, and implement `super::Config` on it with concrete types.
		Use this struct to instantiate your `Pallet`.
	*/

	#[test]
	fn init_balances() {
		let mut balances = super::Pallet::<String, u128>::new();

		assert_eq!(balances.balance(&"alice".to_string()), 0);
		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.balance(&"alice".to_string()), 100);
		assert_eq!(balances.balance(&"bob".to_string()), 0);
	}

	#[test]
	fn transfer_balance() {
		let mut balances = super::Pallet::<String, u128>::new();

		assert_eq!(
			balances.transfer("alice".to_string(), "bob".to_string(), 51),
			Err("Not enough funds.")
		);

		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.transfer("alice".to_string(), "bob".to_string(), 51), Ok(()));
		assert_eq!(balances.balance(&"alice".to_string()), 49);
		assert_eq!(balances.balance(&"bob".to_string()), 51);

		assert_eq!(
			balances.transfer("alice".to_string(), "bob".to_string(), 51),
			Err("Not enough funds.")
		);
	}
}
}
mod balances;
mod system;

// These are the concrete types we will use in our simple state machine.
// Modules are configured for these types directly, and they satisfy all of our
// trait requirements.
mod types {
	pub type AccountId = String;
	pub type Balance = u128;
	pub type BlockNumber = u32;
	pub type Nonce = u32;
}

// This is our main Runtime.
// It accumulates all of the different pallets we want to use.
#[derive(Debug)]
pub struct Runtime {
	system: system::Pallet<Self>,
	balances: balances::Pallet<types::AccountId, types::Balance>,
}

impl system::Config for Runtime {
	type AccountId = types::AccountId;
	type BlockNumber = types::BlockNumber;
	type Nonce = types::Nonce;
}

/*
	TODO:
	Implement the `balances::Config` trait you created on your `Runtime`.
	Use `Self` to satisfy the generic parameter required for `balances::Pallet`.
*/

impl Runtime {
	// Create a new instance of the main Runtime, by creating a new instance of each pallet.
	fn new() -> Self {
		Self { system: system::Pallet::new(), balances: balances::Pallet::new() }
	}
}

fn main() {
	let mut runtime = Runtime::new();
	let alice = "alice".to_string();
	let bob = "bob".to_string();
	let charlie = "charlie".to_string();

	runtime.balances.set_balance(&alice, 100);

	// start emulating a block
	runtime.system.inc_block_number();
	assert_eq!(runtime.system.block_number(), 1);

	// first transaction
	runtime.system.inc_nonce(&alice);
	let _res = runtime
		.balances
		.transfer(alice.clone(), bob, 30)
		.map_err(|e| eprintln!("{}", e));

	// second transaction
	runtime.system.inc_nonce(&alice);
	let _res = runtime.balances.transfer(alice, charlie, 20).map_err(|e| eprintln!("{}", e));

	println!("{:#?}", runtime);
}
#![allow(unused)]
fn main() {
use num::traits::{CheckedAdd, CheckedSub, Zero};
use std::collections::BTreeMap;

/// The configuration trait for the Balances Module.
/// Contains the basic types needed for handling balances.
pub trait Config {
	/// A type which can identify an account in our state machine.
	/// On a real blockchain, you would want this to be a cryptographic public key.
	type AccountId: Ord + Clone;
	/// A type which can represent the balance of an account.
	/// Usually this is a large unsigned integer.
	type Balance: Zero + CheckedSub + CheckedAdd + Copy;
}

/// This is the Balances Module.
/// It is a simple module which keeps track of how much balance each account has in this state
/// machine.
#[derive(Debug)]
pub struct Pallet<T: Config> {
	// A simple storage mapping from accounts to their balances.
	balances: BTreeMap<T::AccountId, T::Balance>,
}

impl<T: Config> Pallet<T> {
	// Create a new instance of the balances module.
	pub fn new() -> Self {
		Self { balances: BTreeMap::new() }
	}

	/// Set the balance of an account `who` to some `amount`.
	pub fn set_balance(&mut self, who: &T::AccountId, amount: T::Balance) {
		self.balances.insert(who.clone(), amount);
	}

	/// Get the balance of an account `who`.
	/// If the account has no stored balance, we return zero.
	pub fn balance(&self, who: &T::AccountId) -> T::Balance {
		*self.balances.get(who).unwrap_or(&T::Balance::zero())
	}

	/// Transfer `amount` from one account to another.
	/// This function verifies that `from` has at least `amount` balance to transfer,
	/// and that no mathematical overflows occur.
	pub fn transfer(
		&mut self,
		caller: T::AccountId,
		to: T::AccountId,
		amount: T::Balance,
	) -> Result<(), &'static str> {
		let caller_balance = self.balance(&caller);
		let to_balance = self.balance(&to);

		let new_caller_balance = caller_balance.checked_sub(&amount).ok_or("Not enough funds.")?;
		let new_to_balance = to_balance.checked_add(&amount).ok_or("Overflow")?;

		self.balances.insert(caller, new_caller_balance);
		self.balances.insert(to, new_to_balance);

		Ok(())
	}
}

#[cfg(test)]
mod tests {
	struct TestConfig;
	impl super::Config for TestConfig {
		type AccountId = String;
		type Balance = u128;
	}

	#[test]
	fn init_balances() {
		let mut balances = super::Pallet::<TestConfig>::new();

		assert_eq!(balances.balance(&"alice".to_string()), 0);
		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.balance(&"alice".to_string()), 100);
		assert_eq!(balances.balance(&"bob".to_string()), 0);
	}

	#[test]
	fn transfer_balance() {
		let mut balances = super::Pallet::<TestConfig>::new();

		assert_eq!(
			balances.transfer("alice".to_string(), "bob".to_string(), 51),
			Err("Not enough funds.")
		);

		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.transfer("alice".to_string(), "bob".to_string(), 51), Ok(()));
		assert_eq!(balances.balance(&"alice".to_string()), 49);
		assert_eq!(balances.balance(&"bob".to_string()), 51);

		assert_eq!(
			balances.transfer("alice".to_string(), "bob".to_string(), 51),
			Err("Not enough funds.")
		);
	}
}
}
mod balances;
mod system;

// These are the concrete types we will use in our simple state machine.
// Modules are configured for these types directly, and they satisfy all of our
// trait requirements.
mod types {
	pub type AccountId = String;
	pub type Balance = u128;
	pub type BlockNumber = u32;
	pub type Nonce = u32;
}

// This is our main Runtime.
// It accumulates all of the different pallets we want to use.
#[derive(Debug)]
pub struct Runtime {
	system: system::Pallet<Self>,
	balances: balances::Pallet<Self>,
}

impl system::Config for Runtime {
	type AccountId = types::AccountId;
	type BlockNumber = types::BlockNumber;
	type Nonce = types::Nonce;
}

impl balances::Config for Runtime {
	type AccountId = types::AccountId;
	type Balance = types::Balance;
}

impl Runtime {
	// Create a new instance of the main Runtime, by creating a new instance of each pallet.
	fn new() -> Self {
		Self { system: system::Pallet::new(), balances: balances::Pallet::new() }
	}
}

fn main() {
	let mut runtime = Runtime::new();
	let alice = "alice".to_string();
	let bob = "bob".to_string();
	let charlie = "charlie".to_string();

	runtime.balances.set_balance(&alice, 100);

	// start emulating a block
	runtime.system.inc_block_number();
	assert_eq!(runtime.system.block_number(), 1);

	// first transaction
	runtime.system.inc_nonce(&alice);
	let _res = runtime
		.balances
		.transfer(alice.clone(), bob, 30)
		.map_err(|e| eprintln!("{}", e));

	// second transaction
	runtime.system.inc_nonce(&alice);
	let _res = runtime.balances.transfer(alice, charlie, 20).map_err(|e| eprintln!("{}", e));

	println!("{:#?}", runtime);
}
diff --git a/src/balances.rs b/src/balances.rs
index e333e0d9..9f5c4531 100644
--- a/src/balances.rs
+++ b/src/balances.rs
@@ -1,6 +1,11 @@
 use num::traits::{CheckedAdd, CheckedSub, Zero};
 use std::collections::BTreeMap;
 
+/*
+	TODO: Combine all generic types and their trait bounds into a single `pub trait Config`.
+	When you are done, your `Pallet` can simply be defined with `Pallet<T: Config>`.
+*/
+
 /// This is the Balances Module.
 /// It is a simple module which keeps track of how much balance each account has in this state
 /// machine.
@@ -10,6 +15,10 @@ pub struct Pallet<AccountId, Balance> {
 	balances: BTreeMap<AccountId, Balance>,
 }
 
+/*
+	TODO: Update all of these functions to use your new configuration trait.
+*/
+
 impl<AccountId, Balance> Pallet<AccountId, Balance>
 where
 	AccountId: Ord + Clone,
@@ -55,6 +64,11 @@ where
 
 #[cfg(test)]
 mod tests {
+	/*
+		TODO: Create a `struct TestConfig`, and implement `super::Config` on it with concrete types.
+		Use this struct to instantiate your `Pallet`.
+	*/
+
 	#[test]
 	fn init_balances() {
 		let mut balances = super::Pallet::<String, u128>::new();
diff --git a/src/main.rs b/src/main.rs
index 40dc8ac5..343797ef 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -25,6 +25,12 @@ impl system::Config for Runtime {
 	type Nonce = types::Nonce;
 }
 
+/*
+	TODO:
+	Implement the `balances::Config` trait you created on your `Runtime`.
+	Use `Self` to satisfy the generic parameter required for `balances::Pallet`.
+*/
+
 impl Runtime {
 	// Create a new instance of the main Runtime, by creating a new instance of each pallet.
 	fn new() -> Self {
diff --git a/src/balances.rs b/src/balances.rs
index 9f5c4531..43b49262 100644
--- a/src/balances.rs
+++ b/src/balances.rs
@@ -1,43 +1,41 @@
 use num::traits::{CheckedAdd, CheckedSub, Zero};
 use std::collections::BTreeMap;
 
-/*
-	TODO: Combine all generic types and their trait bounds into a single `pub trait Config`.
-	When you are done, your `Pallet` can simply be defined with `Pallet<T: Config>`.
-*/
+/// The configuration trait for the Balances Module.
+/// Contains the basic types needed for handling balances.
+pub trait Config {
+	/// A type which can identify an account in our state machine.
+	/// On a real blockchain, you would want this to be a cryptographic public key.
+	type AccountId: Ord + Clone;
+	/// A type which can represent the balance of an account.
+	/// Usually this is a large unsigned integer.
+	type Balance: Zero + CheckedSub + CheckedAdd + Copy;
+}
 
 /// This is the Balances Module.
 /// It is a simple module which keeps track of how much balance each account has in this state
 /// machine.
 #[derive(Debug)]
-pub struct Pallet<AccountId, Balance> {
+pub struct Pallet<T: Config> {
 	// A simple storage mapping from accounts to their balances.
-	balances: BTreeMap<AccountId, Balance>,
+	balances: BTreeMap<T::AccountId, T::Balance>,
 }
 
-/*
-	TODO: Update all of these functions to use your new configuration trait.
-*/
-
-impl<AccountId, Balance> Pallet<AccountId, Balance>
-where
-	AccountId: Ord + Clone,
-	Balance: Zero + CheckedSub + CheckedAdd + Copy,
-{
-	/// Create a new instance of the balances module.
+impl<T: Config> Pallet<T> {
+	// Create a new instance of the balances module.
 	pub fn new() -> Self {
 		Self { balances: BTreeMap::new() }
 	}
 
 	/// Set the balance of an account `who` to some `amount`.
-	pub fn set_balance(&mut self, who: &AccountId, amount: Balance) {
+	pub fn set_balance(&mut self, who: &T::AccountId, amount: T::Balance) {
 		self.balances.insert(who.clone(), amount);
 	}
 
 	/// Get the balance of an account `who`.
 	/// If the account has no stored balance, we return zero.
-	pub fn balance(&self, who: &AccountId) -> Balance {
-		*self.balances.get(who).unwrap_or(&Balance::zero())
+	pub fn balance(&self, who: &T::AccountId) -> T::Balance {
+		*self.balances.get(who).unwrap_or(&T::Balance::zero())
 	}
 
 	/// Transfer `amount` from one account to another.
@@ -45,9 +43,9 @@ where
 	/// and that no mathematical overflows occur.
 	pub fn transfer(
 		&mut self,
-		caller: AccountId,
-		to: AccountId,
-		amount: Balance,
+		caller: T::AccountId,
+		to: T::AccountId,
+		amount: T::Balance,
 	) -> Result<(), &'static str> {
 		let caller_balance = self.balance(&caller);
 		let to_balance = self.balance(&to);
@@ -64,14 +62,15 @@ where
 
 #[cfg(test)]
 mod tests {
-	/*
-		TODO: Create a `struct TestConfig`, and implement `super::Config` on it with concrete types.
-		Use this struct to instantiate your `Pallet`.
-	*/
+	struct TestConfig;
+	impl super::Config for TestConfig {
+		type AccountId = String;
+		type Balance = u128;
+	}
 
 	#[test]
 	fn init_balances() {
-		let mut balances = super::Pallet::<String, u128>::new();
+		let mut balances = super::Pallet::<TestConfig>::new();
 
 		assert_eq!(balances.balance(&"alice".to_string()), 0);
 		balances.set_balance(&"alice".to_string(), 100);
@@ -81,7 +80,7 @@ mod tests {
 
 	#[test]
 	fn transfer_balance() {
-		let mut balances = super::Pallet::<String, u128>::new();
+		let mut balances = super::Pallet::<TestConfig>::new();
 
 		assert_eq!(
 			balances.transfer("alice".to_string(), "bob".to_string(), 51),
diff --git a/src/main.rs b/src/main.rs
index 343797ef..fe677ae7 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -16,7 +16,7 @@ mod types {
 #[derive(Debug)]
 pub struct Runtime {
 	system: system::Pallet<Self>,
-	balances: balances::Pallet<types::AccountId, types::Balance>,
+	balances: balances::Pallet<Self>,
 }
 
 impl system::Config for Runtime {
@@ -25,11 +25,10 @@ impl system::Config for Runtime {
 	type Nonce = types::Nonce;
 }
 
-/*
-	TODO:
-	Implement the `balances::Config` trait you created on your `Runtime`.
-	Use `Self` to satisfy the generic parameter required for `balances::Pallet`.
-*/
+impl balances::Config for Runtime {
+	type AccountId = types::AccountId;
+	type Balance = types::Balance;
+}
 
 impl Runtime {
 	// Create a new instance of the main Runtime, by creating a new instance of each pallet.