Developers Home»Tutorials»Add the Nicks Pallet to your Runtime

Add the Nicks Pallet to your Runtime

As you saw in the Create your first Substrate blockchain tutorial, the Substrate node template provides a working runtime that you can use to start building your own blockchain. The node template includes a runtime that is constructed using FRAME development framework and a few modules—called pallets—to get you started. In this tutorial, you'll learn how to add the Nicks pallet to the node template. You can follow similar patterns to add other FRAME pallets to your runtime. However, you need to configure each pallet with the specific settings it requires to use it. This tutorial illustrates how to configure the settings each pallet requires but not the specific settings that apply to each pallet you decide to add to your runtime.

Before you begin

Before we even get started, let's layout our objectives:

Add the Nicks pallet to your node template

Implement the Nicks pallet configuration trait.

Use the front-end template to interact with the Nicks pallet.

Learning outcomes

  • Learn how to integrate a FRAME pallet to your node and runtime
  • Familiarize yourself with customizing a pallet's configuration trait
  • Learn how to publish a custom pallet to crates.io

Add the Nicks pallet to the node template

The Nicks pallet allows blockchain users to pay a deposit to reserve a nickname and associate it with an account they control.

To add the Nicks pallet to the Substrate node template:

  1. Open a terminal shell and change to the root directory for the node template.

  2. Open the runtime/Cargo.toml configuration file in a text editor.

  3. Import the pallet-nicks crate to make it available to the node template runtime by adding it to the list of dependencies.

    [dependencies.pallet-nicks]
    default-features = false
    git = 'https://github.com/paritytech/substrate.git'
    tag = 'devhub/latest'
    version = '4.0.0-dev'
    

    In this dependencies.pallet-nicks section, default-features = false specifies that the default features to be used are the features defined for the std native Rust binary listed in the features section.

    It is important to note that the Substrate runtime compiles to both a native Rust std binary and a WebAssembly (Wasm) binary. For more information about compiling std and no_std features, see the Rust Embedded Book.

    The remaining lines specify that Cargo should use the pallet-nicks crate from the paritytech/substrate repository with the commit tag identified using the devhub/latest tag.

    For an introduction to editing Cargo.toml files, see the Cargo reference documentation.

  4. Add the pallet-nicks crate to the list of features to be included in the std feature set by adding the following line features section.

    [features]
    default = ['std']
    std = [
        ...
        'pallet-aura/std',
        'pallet-balances/std',
        'pallet-nicks/std',
        ...
    ]
    

    If you forget to update the features section, you might see errors similar to the following when you build the native binaries:

    error[E0425]: cannot find function `memory_teardown` in module `sandbox`
      --> ~/.cargo/git/checkouts/substrate-7e08433d4c370a21/83a6f1a/primitives/sandbox/src/../without_std.rs:53:12
       |
    53 |         sandbox::memory_teardown(self.memory_idx);
       |                  ^^^^^^^^^^^^^^^ not found in `sandbox`
    
    error[E0425]: cannot find function `memory_new` in module `sandbox`
      --> ~/.cargo/git/checkouts/substrate-7e08433d4c370a21/83a6f1a/primitives/sandbox/src/../without_std.rs:72:18
       |
    72 |         match sandbox::memory_new(initial, maximum) {
       |
    ...
    
  5. Check that the new dependencies resolve correctly by running the following command:

    cargo check -p node-template-runtime
    

Review the configuration trait for the Nicks pallet

Every pallet has a Rust trait called Config that is used to configure the parameters and types that the pallet needs from the runtime.

If you review the comments for the runtime in the node template, you will see examples of using the Config configuration trait to define and tune parameters for each pallet.

Most of the pallet-specific code required to add a pallet is implemented using the Config trait. To see what you need to implement for the Nicks pallet specifically, see the pallet_nicks::Config documentation or the definition of the trait itself in the source code of the Nicks pallet.

In the source code for the nicks pallet, the Config trait declares the following types:

pub trait Config: frame_system::Config {
    /// The overarching event type.
    type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;

    /// The currency trait.
    type Currency: ReservableCurrency<Self::AccountId>;

    /// Reservation fee.
    #[pallet::constant]
    type ReservationFee: Get<BalanceOf<Self>>;

    /// What to do with slashed funds.
    type Slashed: OnUnbalanced<NegativeImbalanceOf<Self>>;

    /// The origin which may forcibly set or remove a name. Root can always do this.
    type ForceOrigin: EnsureOrigin<Self::Origin>;

    /// The minimum length a name may be.
    #[pallet::constant]
    type MinLength: Get<u32>;

    /// The maximum length a name may be.
    #[pallet::constant]
    type MaxLength: Get<u32>;
}

Review the implementation of the Balances pallet

Just like you used the Balances pallet as a template for importing the Nicks pallet, you can use the Balances pallet as an example to see how to implement the Config interface for the Nicks pallet.

  1. Open the runtime/src/lib.rs file in a text editor.

  2. Locate the Balances pallet section and note that the implementation consists of two parts:

    • The parameter_types! block where constant values are defined.

      parameter_types! {
          // The u128 constant value 500 is aliased to a type named ExistentialDeposit.
          pub const ExistentialDeposit: u128 = 500;
          // A heuristic that is used for weight estimation.
          pub const MaxLocks: u32 = 50;
      }
      
      
    • The impl block where the types and values defined by the Config interface are configured.

      impl pallet_balances::Config for Runtime {
          // The previously defined parameter_type is used as a configuration parameter.
          type MaxLocks = MaxLocks;
      
          // The "Balance" that appears after the equal sign is an alias for the u128 type.
          type Balance = Balance;
      
          // The empty value, (), is used to specify a no-op callback function.
          type DustRemoval = ();
      
          // The previously defined parameter_type is used as a configuration parameter.
          type ExistentialDeposit = ExistentialDeposit;
      
          // The FRAME runtime system is used to track the accounts that hold balances.
          type AccountStore = System;
      
          // Weight information is supplied to the Balances pallet by the node template runtime.
          // type WeightInfo = (); // old way
          type WeightInfo = pallet_balances::weights::SubstrateWeight<Runtime>;
      
          // The ubiquitous event type.
          type Event = Event;
      }
      

The impl pallet_balances::Config block allows you to configure the types and parameters that are specified by the Balances pallet Config trait. For example, this impl block configures the Balances pallet to use the u128 type to track balances. If you were developing a chain where it was important to optimize storage, you could use any unsigned integer type that was at least 32-bits in size because the Balance type for the Balances pallet Config trait is bound by the AtLeast32BitUnsigned trait.

Implement the Nicks pallet Config trait

Now that you have seen an example of how the Config trait is implemented for the Balances pallet, you're ready to implement the Config trait for the Nicks pallet.

To implement the nicks pallet in your runtime:

  1. Open the runtime/src/lib.rs file in a text editor.

  2. After the last line of the Balances code block, add the following code block for the Nicks pallet:

    /// Add this code block to your template for Nicks:
    parameter_types! {
        // Choose a fee that incentivizes desireable behavior.
        pub const NickReservationFee: u128 = 100;
        pub const MinNickLength: u32 = 8;
        // Maximum bounds on storage are important to secure your chain.
        pub const MaxNickLength: u32 = 32;
    }
    
    impl pallet_nicks::Config for Runtime {
        // The Balances pallet implements the ReservableCurrency trait.
        // `Balances` is defined in `construct_runtime!` macro. See below.
        // https://docs.substrate.io/rustdocs/latest/pallet_balances/index.html#implementations-2
        type Currency = Balances;
    
        // Use the NickReservationFee from the parameter_types block.
        type ReservationFee = NickReservationFee;
    
        // No action is taken when deposits are forfeited.
        type Slashed = ();
    
        // Configure the FRAME System Root origin as the Nick pallet admin.
        // https://docs.substrate.io/rustdocs/latest/frame_system/enum.RawOrigin.html#variant.Root
        type ForceOrigin = frame_system::EnsureRoot<AccountId>;
    
        // Use the MinNickLength from the parameter_types block.
        type MinLength = MinNickLength;
    
        // Use the MaxNickLength from the parameter_types block.
        type MaxLength = MaxNickLength;
    
        // The ubiquitous event type.
        type Event = Event;
    }
    
  3. Identify the types that the Nicks pallet exposes.

    You can find a complete list of types in the construct_runtime! macro documentation.

    The Nicks pallet uses the following types:

    • Pallet Storage: Because it uses the #[pallet::storage] macro.
    • Pallet Events: Because it uses the #[pallet::events] macro. You will notice that in the case of the Nicks pallet, the Event keyword is parameterized with respect to a type, T; this is because at least one of the events defined by the Nicks pallet depends on a type that is configured with the Config configuration trait.
    • Callable Functions: Because it has dispatchable functions in the #[pallet::call] macro.
    • The Pallet type from the #[pallet::pallet] macro.
  4. Add Nicks to the construct_runtime! macro.

    For example:

    construct_runtime!(
        pub enum Runtime where
            Block = Block,
            NodeBlock = opaque::Block,
            UncheckedExtrinsic = UncheckedExtrinsic
        {
            /* --snip-- */
            Balances: pallet_balances,
    
            /*** Add This Line ***/
            Nicks: pallet_nicks,
        }
    );
    
  5. Check that the new dependencies resolve correctly by running the following command:

    cargo check -p node-template-runtime
    

    If there are no errors, you are ready to compile.

  6. Compile the node in release mode by running the following command:

    cargo build --release
    

Start the blockchain node and use the Nicks pallet

After your node compiles, you are ready to start the node that has been enhanced with nickname capabilities from the Nicks pallet and interact with it using the front-end template.

Start the local Substrate node

To start the local Substrate node:

  1. Open a terminal shell, if necessary.

  2. Change to the root directory of the Substrate node template.

  3. Start the node in development mode by running the following command:

    ./target/release/node-template --dev
    

    The node-template command-line options specify how you want the running node to operate. In this case, the --dev option specifies that the node runs in developer mode using the predefined development chain specification. By default, this option also deletes all active data—such as keys, the blockchain database, and networking information when you stop the node by pressing Control-c. Using the --dev option ensures that you have a clean working state any time you stop and restart the node.

  4. Verify your node is up and running successfully by reviewing the output displayed in the terminal.

    If the number after finalized is increasing in the console output, your blockchain is producing new blocks and reaching consensus about the state they describe.

  5. Keep the terminal that displays the node output open to continue.

Start the front-end template

Now that you have added a new pallet to your runtime, you can use the Substrate front-end template to interact with the node template and access the Nicks pallet.

To start the front-end template:

  1. Open a new terminal shell on your computer.

  2. In the new terminal, change to the root directory where you installed the front-end template.

  3. Start the web server for the front-end template by running the following command:

    yarn start
    
  4. Open http://localhost:8000/ in a browser to view the front-end template.

Set a nickname using the Nicks pallet

After you start the front-end template, you can use it to interact with the Nicks pallet you just added to the runtime.

To set a nickname for an account:

  1. Check the account selection list to verify that the Alice account is currently selected.

  2. In the Pallet Interactor component, verify that Extrinsic is selected.

  3. Select nicks from the list of pallets available to call.

  4. Select the setName dispatchable as the function to call from the nicks pallet.

  5. Type a name that is longer than the MinNickLength (8 characters)and no longer than the MaxNickLength (32 characters).

  6. Click Signed to execute the function.

    Set a name

  7. Observe the status of the call and the events emitted by the Nicks pallet.

Query information for an account using the Nicks pallet

Next, you can use Query capability to read the value of Alice's nickname from the runtime storage for the Nicks pallet.

To return the information stored for Alice:

  1. In the Pallet Interactor component, select Query.

  2. Select nicks from the list of pallets available to query.

  3. Select the nameOf.

  4. Copy and paste the address for the alice account in the Account field, then click Query.

    Read a name

    The return type is a tuple that contains two values:

    • The hex-encoded nickname for the Alice account.

    • The amount that was reserved from Alice's account to secure the nickname.

    If you were to query the Nicks pallet for the nameOf for Bob's account, you would see the None value returned because Bob has not invoked the setName dispatchable and deposited the funds to reserve a nickname.

    Read an empty name

Explore more advanced topics

This tutorial uses the Signed button to invoke the killName dispatchable function and uses Bob's account ID as the function's argument. The killName function must be called by the ForceOrigin that was configured with the Nicks pallet's Config interface in the previous section. You may recall that we configured this to be the FRAME system's Root origin. The node template's chain specification file is used to configure the Sudo pallet to give Alice access to this origin.

The front-end template makes it easy to use the Sudo pallet to dispatch a call from the Root origin - just use the SUDO button to invoke the dispatchable. Since we just used the Signed button as opposed to the SUDO button, the function was dispatched by the Signed origin associated with Alice's account as opposed to the Root origin.

`BadOrigin` Error

You will notice that even though the function call was successfully dispatched, a BadOrigin error was emitted and is visible in the Events pane. This means that Alice's account was still charged fees for the dispatch, but there weren't any state changes executed because the Nicks pallet follows the important verify-first-write-last pattern. Now use the SUDO button to dispatch the same call with the same parameter.

Nicks Pallet Error

The Sudo pallet emits a Sudid event to inform network participants that the Root origin dispatched a call, however, you will notice that the inner dispatch failed with a DispatchError (the Sudo pallet's sudo function is the "outer" dispatch). In particular, this was an instance of the DispatchError::Module variant, which reports two pieces of metadata: an index number and an error number. The index number relates to the pallet from which the error originated; it corresponds with the index (position) of the pallet within the construct_runtime! macro. The error number corresponds with the index of the relevant variant from that pallet's Error enum. When using these numbers to find pallet errors, remember that the first position corresponds with index zero. In the screenshot above, the index is 9 (the tenth pallet) and the error is 2 (the third error). Depending on the position of the Nicks pallet in your construct_runtime! macro, you may see a different number for index. Regardless of the value of index, you should see that the error value is 2, which corresponds to the third variant of the Nick's pallet's Error enum, the Unnamed variant. This shouldn't be a surprise since Bob has not yet reserved a nickname, thus it cannot be cleared!

You should confirm that Alice can use the SUDO button to invoke the killName dispatchable and forcibly clear the nickname associated with any account (including her own) that actually has a nickname associated with it. Here are some other things you may want to try:

  • Add a nickname that is shorter than the MinNickLength or longer than the MaxNickLength that you configured with the Nick's pallet's Config configuration trait.
  • Add a nickname for Bob then use Alice's account and the SUDO button to forcibly kill Bob's nickname. Switch back to Bob's account and dispatch the clearName function.

Adding other FRAME pallets

This tutorial illustrated how to add a pallet to the runtime using the Nicks pallet as an example. However, it is important to note that each pallet is a little different. If you aren't sure how to add a specific pallet, the best place to look is the runtime from the main Substrate repository. Unlike the node template used in tutorials, the runtime in the main Substrate repository includes most of the pallets available in the library of core FRAME pallets.

Refer to the bin/node/runtime/Cargo.toml file for the main Substrate node runtime to see examples of how to import different pallet dependencies. Refer to the bin/node/runtime/src/lib.rs file for the main Substrate node runtime to see examples of how to configure the runtime to include each pallet. Generally, you can copy the code from the main Substrate node runtime as a starting point to include a pallet in your own runtime.

Learn More

Learn how to add a more complex pallet to the Node Template by going through the Add the Contracts Pallet guide or complete the Forkless Upgrade a Chain tutorial to learn how Substrate enables forkless runtime upgrades and follow steps to perform two distinct types of upgrades.

Publish your own pallet

By now you should have successfully imported the Nicks pallet. In future, you will write your own pallets to execute your application-specific logic. In those cases, you may want to share these pallets with others.

In this section, we will cover how to publish your own pallet for open source usage.

Option 1: Publishing on GitHub

To publish your pallet on GitHub, you need to create a GitHub repository and push your pallet's code to it.

Once published, other developers could refer to your pallet in their Cargo.toml using the following snippet:

runtime/Cargo.toml

[dependencies.your-pallet-name]
default_features = false
git = 'https://github.com/your-username/your-pallet'
version = '1.0.0'
branch = 'master'

# You may choose to refer to a specific commit or tag instead of branch
# rev = '<git-commit>'
# tag = '<some tag>

Option 2: Publishing on crates.io

crates.io allows permissionless publishing of any Rust module. You could learn the procedure by following their guide on how to publish on crates.io.

Once published, other developers could refer to your pallet in their Cargo.toml using the following snippet:

runtime/Cargo.toml

[dependencies.your-pallet-name]
default_features = false
version = 'some-compatible-version'

We do not specify any target destination on the above, and by default it will search for the package in crates.io repository.

Next steps

  • Follow the tutorials that demonstrate Substrate development concepts and techniques.
  • Browse How-to Guides for examples of common runtime development patterns.
  • Explore the FRAME examples to learn what's available in the FRAME library.
Last edit: on

Run into problems?
Let us Know