├── .gitignore ├── .gitattributes ├── .github └── workflows │ ├── link-check.yml │ └── test-code.yml ├── src ├── tests.rs ├── mock.rs └── lib.rs ├── Cargo.toml ├── LICENSE ├── README.md └── HOWTO.md /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | 4 | Cargo.lock 5 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/workflows/link-check.yml: -------------------------------------------------------------------------------- 1 | name: Check Links 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - master 7 | push: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | markdown-link-check: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v2 16 | - uses: gaurav-nelson/github-action-markdown-link-check@v1 17 | with: 18 | use-quiet-mode: 'yes' 19 | -------------------------------------------------------------------------------- /src/tests.rs: -------------------------------------------------------------------------------- 1 | use crate::{Error, mock::*}; 2 | use frame_support::{assert_ok, assert_noop}; 3 | 4 | #[test] 5 | fn it_works_for_default_value() { 6 | new_test_ext().execute_with(|| { 7 | // Dispatch a signed extrinsic. 8 | assert_ok!(TemplateModule::do_something(Origin::signed(1), 42)); 9 | // Read pallet storage and assert an expected result. 10 | assert_eq!(TemplateModule::something(), Some(42)); 11 | }); 12 | } 13 | 14 | #[test] 15 | fn correct_error_for_none_value() { 16 | new_test_ext().execute_with(|| { 17 | // Ensure the expected error is thrown when no value is present. 18 | assert_noop!( 19 | TemplateModule::cause_error(Origin::signed(1)), 20 | Error::::NoneValue 21 | ); 22 | }); 23 | } 24 | -------------------------------------------------------------------------------- /.github/workflows/test-code.yml: -------------------------------------------------------------------------------- 1 | name: Test Code 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - master 7 | push: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | test-code: 13 | runs-on: ubuntu-18.04 14 | 15 | steps: 16 | - name: Checkout Code 17 | uses: actions/checkout@v2 18 | 19 | # Steps taken from https://github.com/actions/cache/blob/master/examples.md#rust---cargo 20 | - name: Cache cargo registry 21 | uses: actions/cache@v2 22 | with: 23 | path: | 24 | ~/.cargo/registry 25 | ~/.cargo/git 26 | target 27 | key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }} 28 | 29 | - name: Install toolchain 30 | uses: actions-rs/toolchain@v1 31 | with: 32 | profile: minimal 33 | toolchain: nightly-2020-05-07 34 | components: rustfmt, clippy 35 | target: wasm32-unknown-unknown 36 | override: true 37 | default: true 38 | 39 | - name: Check Code 40 | run: cargo check 41 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ['Substrate DevHub '] 3 | description = 'FRAME pallet template for defining custom runtime logic.' 4 | edition = '2018' 5 | homepage = 'https://substrate.dev' 6 | license = 'Unlicense' 7 | name = 'pallet-template' 8 | repository = 'https://github.com/substrate-developer-hub/substrate-node-template/' 9 | version = '3.0.0' 10 | 11 | [package.metadata.docs.rs] 12 | targets = ['x86_64-unknown-linux-gnu'] 13 | 14 | # alias "parity-scale-code" to "codec" 15 | [dependencies.codec] 16 | default-features = false 17 | features = ['derive'] 18 | package = 'parity-scale-codec' 19 | version = '2.0.0' 20 | 21 | [dependencies] 22 | frame-support = { default-features = false, version = '3.0.0' } 23 | frame-system = { default-features = false, version = '3.0.0' } 24 | 25 | [dev-dependencies] 26 | serde = { version = "1.0.119" } 27 | sp-core = { default-features = false, version = '3.0.0' } 28 | sp-io = { default-features = false, version = '3.0.0' } 29 | sp-runtime = { default-features = false, version = '3.0.0' } 30 | 31 | [features] 32 | default = ['std'] 33 | std = [ 34 | 'codec/std', 35 | 'frame-support/std', 36 | 'frame-system/std', 37 | ] 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /src/mock.rs: -------------------------------------------------------------------------------- 1 | use crate as pallet_template; 2 | use sp_core::H256; 3 | use frame_support::parameter_types; 4 | use sp_runtime::{ 5 | traits::{BlakeTwo256, IdentityLookup}, testing::Header, 6 | }; 7 | use frame_system as system; 8 | 9 | type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; 10 | type Block = frame_system::mocking::MockBlock; 11 | 12 | // Configure a mock runtime to test the pallet. 13 | frame_support::construct_runtime!( 14 | pub enum Test where 15 | Block = Block, 16 | NodeBlock = Block, 17 | UncheckedExtrinsic = UncheckedExtrinsic, 18 | { 19 | System: frame_system::{Module, Call, Config, Storage, Event}, 20 | TemplateModule: pallet_template::{Module, Call, Storage, Event}, 21 | } 22 | ); 23 | 24 | parameter_types! { 25 | pub const BlockHashCount: u64 = 250; 26 | pub const SS58Prefix: u8 = 42; 27 | } 28 | 29 | impl system::Config for Test { 30 | type BaseCallFilter = (); 31 | type BlockWeights = (); 32 | type BlockLength = (); 33 | type DbWeight = (); 34 | type Origin = Origin; 35 | type Call = Call; 36 | type Index = u64; 37 | type BlockNumber = u64; 38 | type Hash = H256; 39 | type Hashing = BlakeTwo256; 40 | type AccountId = u64; 41 | type Lookup = IdentityLookup; 42 | type Header = Header; 43 | type Event = Event; 44 | type BlockHashCount = BlockHashCount; 45 | type Version = (); 46 | type PalletInfo = PalletInfo; 47 | type AccountData = (); 48 | type OnNewAccount = (); 49 | type OnKilledAccount = (); 50 | type SystemWeightInfo = (); 51 | type SS58Prefix = SS58Prefix; 52 | } 53 | 54 | impl pallet_template::Config for Test { 55 | type Event = Event; 56 | } 57 | 58 | // Build genesis storage according to the mock runtime. 59 | pub fn new_test_ext() -> sp_io::TestExternalities { 60 | system::GenesisConfig::default().build_storage::().unwrap().into() 61 | } 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > :information_source: This repository has been deprecated in favor of the [Substrate Node Template](https://github.com/substrate-developer-hub/substrate-node-template). 2 | > 3 | > You can still create your own custom pallets in their own crate by extracting the [`/pallet/template/`](https://github.com/substrate-developer-hub/substrate-node-template/tree/master/pallets/template) folder of the `substrate-node-template` project. 4 | 5 | 6 | # Substrate Pallet Template 7 | 8 | This is a template for a Substrate pallet which lives as its own crate so it can be imported into multiple runtimes. It is based on the ["template" pallet](https://github.com/paritytech/substrate/tree/master/bin/node-template/pallets/template) that is included with the [Substrate node template](https://github.com/paritytech/substrate/tree/master/bin/node-template). 9 | 10 | Check out the [HOWTO](HOWTO.md) to learn how to use this for your own runtime module. 11 | 12 | This README should act as a general template for distributing your pallet to others. 13 | 14 | ## Purpose 15 | 16 | This pallet acts as a template for building other pallets. 17 | 18 | It currently allows a user to put a `u32` value into storage, which triggers a runtime event. 19 | 20 | ## Dependencies 21 | 22 | ### Traits 23 | 24 | This pallet does not depend on any externally defined traits. 25 | 26 | ### Pallets 27 | 28 | This pallet does not depend on any other FRAME pallet or externally developed modules. 29 | 30 | ## Installation 31 | 32 | ### Runtime `Cargo.toml` 33 | 34 | To add this pallet to your runtime, simply include the following to your runtime's `Cargo.toml` file: 35 | 36 | ```TOML 37 | [dependencies.pallet-template] 38 | default_features = false 39 | git = 'https://github.com/substrate-developer-hub/substrate-pallet-template.git' 40 | ``` 41 | 42 | and update your runtime's `std` feature to include this pallet: 43 | 44 | ```TOML 45 | std = [ 46 | # --snip-- 47 | 'pallet-template/std', 48 | ] 49 | ``` 50 | 51 | ### Runtime `lib.rs` 52 | 53 | You should implement it's trait like so: 54 | 55 | ```rust 56 | /// Used for test_module 57 | impl pallet_template::Config for Runtime { 58 | type Event = Event; 59 | } 60 | ``` 61 | 62 | and include it in your `construct_runtime!` macro: 63 | 64 | ```rust 65 | TemplatePallet: pallet_template::{Module, Call, Storage, Event}, 66 | ``` 67 | 68 | ### Genesis Configuration 69 | 70 | This template pallet does not have any genesis configuration. 71 | 72 | ## Reference Docs 73 | 74 | You can view the reference docs for this pallet by running: 75 | 76 | ``` 77 | cargo doc --open 78 | ``` 79 | -------------------------------------------------------------------------------- /HOWTO.md: -------------------------------------------------------------------------------- 1 | # How to Use 2 | 3 | Simply fork this project and start your runtime development in `lib.rs`. 4 | 5 | ## Update Your Package Information 6 | 7 | In the `Cargo.toml` file of this template, you should update the name and authors of this pallet: 8 | 9 | ```rust 10 | [package] 11 | name = "" 12 | version = "0.1.0" 13 | description = '' 14 | authors = [""] 15 | edition = '2018' 16 | homepage = '' 17 | license = 'Unlicense' 18 | ``` 19 | 20 | ## Updating Your Dependencies 21 | 22 | For the time being, Substrate does not have any releases on Cargo, which means there is some magic involved with ensuring that all the dependencies of your pallet and the downstream runtime are the same. 23 | 24 | This repository has all Substrate dependencies use: 25 | 26 | ``` 27 | rev = '40a16efefc070faf5a25442bc3ae1d0ea2478eee' 28 | ``` 29 | 30 | > **Note:** Be sure to purge your projects of any `Cargo.lock` files when making changes like this! 31 | 32 | ## Adding New Dependencies 33 | 34 | Substrate FRAME can support any Rust libraries that can compile to Wasm. In general, this means that the libraries you use must compile with `no_std` enabled. 35 | 36 | This also means you need to import your dependencies to only use their `std` feature when this pallet uses its `std` dependency. 37 | 38 | The common pattern here look like: 39 | 40 | 1. Import your library with `default-features = false` 41 | 42 | ```TOML 43 | [dependencies.codec] 44 | default-features = false 45 | features = ['derive'] 46 | package = 'parity-scale-codec' 47 | version = '1.3.0' 48 | ``` 49 | 50 | 2. Add your library to the `std` feature with its `std` feature enabled 51 | 52 | ```TOML 53 | std = [ 54 | 'codec/std', 55 | # --snip-- 56 | ] 57 | ``` 58 | 59 | We won't teach you the details of using Cargo, but feel free to [become a master](https://doc.rust-lang.org/cargo/). 60 | 61 | ## Building and Testing 62 | 63 | Before you release your pallet, you should check that it can: 64 | 65 | 1. Build to Native: 66 | 67 | ``` 68 | cargo build --release 69 | ``` 70 | 71 | 2. Pass your tests: 72 | 73 | ``` 74 | cargo test 75 | ``` 76 | 77 | ## Update the README 78 | 79 | Finally, update the [README](README.md) included with this template with the appropriate information for your pallet. 80 | 81 | ## Common Issues 82 | 83 | Unfortunately keeping things modular can be a little tricky. Here are some common issues you may face. 84 | 85 | ### Developer Dependencies 86 | 87 | When running `cargo build`, everything can compile fine, but when running `cargo test`, you may run into an import error like: 88 | 89 | ```rust 90 | error[E0432]: unresolved import `sp_core` 91 | --> src/lib.rs:72:6 92 | | 93 | 72 | use sp_core::H256; 94 | | ^^^^^^^ use of undeclared type or module `sp_core` 95 | 96 | error: aborting due to previous error 97 | ``` 98 | 99 | You may need to specify some developer dependency which is needed for your tests: 100 | 101 | ``` 102 | [dev-dependencies.sp-core] 103 | default-features = false 104 | git = 'https://github.com/paritytech/substrate.git' 105 | rev = '40a16efefc070faf5a25442bc3ae1d0ea2478eee' 106 | ``` 107 | 108 | > **Note:** `dev-dependencies` will always use `std`, so you should not set `default-features = false`. 109 | 110 | 111 | ### Using Mismatching Substrate Dependencies 112 | 113 | We mentioned above how it is important that your runtime and your module have exactly the same dependency on the Substrate project. If they do not, you will get a lot of `trait bound` errors like this: 114 | 115 | ```rust 116 | error[E0277]: the trait bound `Runtime: frame_system::Trait` is not satisfied in `Event` 117 | | 118 | 112 | impl system::Trait for Runtime { 119 | | ^^^^^^^^^^^^^ within `Event`, the trait `frame_system::Trait` is not implemented for `Runtime` 120 | | 121 | = note: required because it appears within the type `Event` 122 | 123 | error[E0277]: the trait bound `Runtime: frame_system::Trait` is not satisfied 124 | | 125 | 196 | impl test_module::Trait for Runtime { 126 | | ^^^^^^^^^^^^^^^^^^ the trait `frame_system::Trait` is not implemented for `Runtime` 127 | ``` 128 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "std"), no_std)] 2 | 3 | /// Edit this file to define custom logic or remove it if it is not needed. 4 | /// Learn more about FRAME and the core library of Substrate FRAME pallets: 5 | /// https://substrate.dev/docs/en/knowledgebase/runtime/frame 6 | 7 | use frame_support::{decl_module, decl_storage, decl_event, decl_error, dispatch, traits::Get}; 8 | use frame_system::ensure_signed; 9 | 10 | #[cfg(test)] 11 | mod mock; 12 | 13 | #[cfg(test)] 14 | mod tests; 15 | 16 | /// Configure the pallet by specifying the parameters and types on which it depends. 17 | pub trait Config: frame_system::Config { 18 | /// Because this pallet emits events, it depends on the runtime's definition of an event. 19 | type Event: From> + Into<::Event>; 20 | } 21 | 22 | // The pallet's runtime storage items. 23 | // https://substrate.dev/docs/en/knowledgebase/runtime/storage 24 | decl_storage! { 25 | // A unique name is used to ensure that the pallet's storage items are isolated. 26 | // This name may be updated, but each pallet in the runtime must use a unique name. 27 | // ---------------------------------vvvvvvvvvvvvvv 28 | trait Store for Module as TemplateModule { 29 | // Learn more about declaring storage items: 30 | // https://substrate.dev/docs/en/knowledgebase/runtime/storage#declaring-storage-items 31 | Something get(fn something): Option; 32 | } 33 | } 34 | 35 | // Pallets use events to inform users when important changes are made. 36 | // https://substrate.dev/docs/en/knowledgebase/runtime/events 37 | decl_event!( 38 | pub enum Event where AccountId = ::AccountId { 39 | /// Event documentation should end with an array that provides descriptive names for event 40 | /// parameters. [something, who] 41 | SomethingStored(u32, AccountId), 42 | } 43 | ); 44 | 45 | // Errors inform users that something went wrong. 46 | decl_error! { 47 | pub enum Error for Module { 48 | /// Error names should be descriptive. 49 | NoneValue, 50 | /// Errors should have helpful documentation associated with them. 51 | StorageOverflow, 52 | } 53 | } 54 | 55 | // Dispatchable functions allows users to interact with the pallet and invoke state changes. 56 | // These functions materialize as "extrinsics", which are often compared to transactions. 57 | // Dispatchable functions must be annotated with a weight and must return a DispatchResult. 58 | decl_module! { 59 | pub struct Module for enum Call where origin: T::Origin { 60 | // Errors must be initialized if they are used by the pallet. 61 | type Error = Error; 62 | 63 | // Events must be initialized if they are used by the pallet. 64 | fn deposit_event() = default; 65 | 66 | /// An example dispatchable that takes a singles value as a parameter, writes the value to 67 | /// storage and emits an event. This function must be dispatched by a signed extrinsic. 68 | #[weight = 10_000 + T::DbWeight::get().writes(1)] 69 | pub fn do_something(origin, something: u32) -> dispatch::DispatchResult { 70 | // Check that the extrinsic was signed and get the signer. 71 | // This function will return an error if the extrinsic is not signed. 72 | // https://substrate.dev/docs/en/knowledgebase/runtime/origin 73 | let who = ensure_signed(origin)?; 74 | 75 | // Update storage. 76 | Something::put(something); 77 | 78 | // Emit an event. 79 | Self::deposit_event(RawEvent::SomethingStored(something, who)); 80 | // Return a successful DispatchResult 81 | Ok(()) 82 | } 83 | 84 | /// An example dispatchable that may throw a custom error. 85 | #[weight = 10_000 + T::DbWeight::get().reads_writes(1,1)] 86 | pub fn cause_error(origin) -> dispatch::DispatchResult { 87 | let _who = ensure_signed(origin)?; 88 | 89 | // Read a value from storage. 90 | match Something::get() { 91 | // Return an error if the value has not been set. 92 | None => Err(Error::::NoneValue)?, 93 | Some(old) => { 94 | // Increment the value read from storage; will error in the event of overflow. 95 | let new = old.checked_add(1).ok_or(Error::::StorageOverflow)?; 96 | // Update the value in storage with the incremented result. 97 | Something::put(new); 98 | Ok(()) 99 | }, 100 | } 101 | } 102 | } 103 | } 104 | --------------------------------------------------------------------------------