Skip to content

Commit a26b414

Browse files
0xLuccanhussein110xlukemeshaben
authored
Add section for instantiable pallets (#586)
* Add instantiable pallets * Update llms.txt * Apply suggestions from code review Co-authored-by: Nicolás Hussein <[email protected]> * Apply suggestions * Apply suggestions from code review Co-authored-by: Lucas Malizia <[email protected]> * Update llms.txt * Update develop/parachains/customize-parachain/add-pallet-instances.md Co-authored-by: Erin Shaben <[email protected]> * Add variable --------- Co-authored-by: Nicolás Hussein <[email protected]> Co-authored-by: Lucas Malizia <[email protected]> Co-authored-by: Erin Shaben <[email protected]>
1 parent 24b5dcf commit a26b414

File tree

4 files changed

+316
-0
lines changed

4 files changed

+316
-0
lines changed

develop/parachains/customize-parachain/.pages

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@ nav:
33
- index.md
44
- 'Overview (FRAME)': overview.md
55
- 'Add Existing Pallets': add-existing-pallets.md
6+
- 'Add Multiple Pallet Instances': add-pallet-instances.md
67
- 'Add Smart Contract Functionality': add-smart-contract-functionality.md
78
- 'Make a Custom Pallet': make-custom-pallet.md

develop/parachains/customize-parachain/add-existing-pallets.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,14 @@ With the pallet successfully added and configured, the runtime is ready to be co
149149
150150
<div class="grid cards" markdown>
151151
152+
- <span class="badge guide">Guide</span> __Add Multiple Pallet Instances__
153+
154+
---
155+
156+
Learn how to implement multiple instances of the same pallet in your Polkadot SDK-based runtime to create and interact with modular blockchain components.
157+
158+
[:octicons-arrow-right-24: Reference](/develop/parachains/customize-parachain/add-pallet-instances/)
159+
152160
- <span class="badge guide">Guide</span> __Make a Custom Pallet__
153161
154162
---
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
---
2+
title: Add Multiple Pallet Instances
3+
description: Learn how to implement multiple instances of the same pallet in your Polkadot SDK-based runtime to create and interact with modular blockchain components.
4+
---
5+
6+
# Add Multiple Pallet Instances
7+
8+
## Introduction
9+
10+
Running multiple instances of the same pallet within a runtime is a powerful technique in Polkadot SDK development. This approach lets you reuse pallet functionality without reimplementing it, enabling diverse use cases with the same codebase. The Polkadot SDK provides developer-friendly traits for creating instantiable pallets and, in most cases, handles unique storage allocation for different instances automatically. This guide teaches you how to implement and configure multiple instances of a pallet in your runtime.
11+
12+
## Understanding Instantiable Pallets
13+
14+
Unlike standard pallets that exist as a single instance in a runtime, instantiable pallets require special configuration through an additional [generic parameter](https://doc.rust-lang.org/reference/items/generics.html){target=\_blank} `I`.
15+
This generic `I` creates a unique [lifetime](https://doc.rust-lang.org/rust-by-example/scope/lifetime.html){target=\_blank} for each pallet instance, affecting the pallet's generic types and its configuration trait `T`.
16+
17+
You can identify an instantiable pallet by examining its `Pallet` struct definition, which will include both the standard generic `T` and the instantiation generic `I`:
18+
19+
```rust
20+
#[pallet::pallet]
21+
pub struct Pallet<T, I = ()>(PhantomData<(T, I)>);
22+
```
23+
24+
The instantiation generic also appears throughout the pallet's components, including the `Config` trait, storage items, events, errors, and genesis configuration.
25+
26+
## Adding Instantiable Pallets to Your Runtime
27+
28+
The process resembles adding a standard pallet with some key differences. In this example you will see how adding two instances of the [pallet-collective](https://github.com/paritytech/polkadot-sdk/tree/{{dependencies.repositories.polkadot_sdk.version}}/substrate/frame/collective){target=\_blank} is implemented.
29+
30+
### Define Pallet Parameters
31+
32+
First, define the parameters needed to configure the pallet instances. This step is identical whether implementing single or multiple instances:
33+
34+
```rust
35+
parameter_types! {
36+
pub const MotionDuration: BlockNumber = 24 * HOURS;
37+
pub MaxProposalWeight: Weight = Perbill::from_percent(50) * RuntimeBlockWeights::get().max_block;
38+
pub const MaxProposals: u32 = 100;
39+
pub const MaxMembers: u32 = 100;
40+
}
41+
```
42+
43+
### Configure the Pallet Instances
44+
45+
For a single instance, the configuration would look like this:
46+
47+
```rust hl_lines="1"
48+
impl pallet_collective::Config for Runtime {
49+
type RuntimeOrigin = RuntimeOrigin;
50+
type Proposal = RuntimeCall;
51+
type RuntimeEvent = RuntimeEvent;
52+
type MotionDuration = MotionDuration;
53+
type MaxProposals = MaxProposals;
54+
type MaxMembers = MaxMembers;
55+
type DefaultVote = pallet_collective::MoreThanMajorityThenPrimeDefaultVote;
56+
type SetMembersOrigin = EnsureRoot<AccountId>;
57+
type WeightInfo = pallet_collective::weights::SubstrateWeight<Runtime>;
58+
type MaxProposalWeight = MaxProposalWeight;
59+
type DisapproveOrigin = EnsureRoot<Self::AccountId>;
60+
type KillOrigin = EnsureRoot<Self::AccountId>;
61+
type Consideration = ();
62+
}
63+
```
64+
65+
For multiple instances, you need to create a unique identifier for each instance using the `Instance` type with a number suffix, then implement the configuration for each one:
66+
67+
```rust hl_lines="2-3"
68+
// Configure first instance
69+
type Collective1 = pallet_collective::Instance1;
70+
impl pallet_collective::Config<Collective1> for Runtime {
71+
type RuntimeOrigin = RuntimeOrigin;
72+
type Proposal = RuntimeCall;
73+
type RuntimeEvent = RuntimeEvent;
74+
type MotionDuration = MotionDuration;
75+
type MaxProposals = MaxProposals;
76+
type MaxMembers = MaxMembers;
77+
type DefaultVote = pallet_collective::MoreThanMajorityThenPrimeDefaultVote;
78+
type SetMembersOrigin = EnsureRoot<AccountId>;
79+
type WeightInfo = pallet_collective::weights::SubstrateWeight<Runtime>;
80+
type MaxProposalWeight = MaxProposalWeight;
81+
type DisapproveOrigin = EnsureRoot<Self::AccountId>;
82+
type KillOrigin = EnsureRoot<Self::AccountId>;
83+
type Consideration = ();
84+
}
85+
```
86+
```rust hl_lines="2-3"
87+
// Configure second instance
88+
type Collective2 = pallet_collective::Instance2;
89+
impl pallet_collective::Config<Collective2> for Runtime {
90+
type RuntimeOrigin = RuntimeOrigin;
91+
type Proposal = RuntimeCall;
92+
type RuntimeEvent = RuntimeEvent;
93+
type MotionDuration = MotionDuration;
94+
type MaxProposals = MaxProposals;
95+
type MaxMembers = MaxMembers;
96+
type DefaultVote = pallet_collective::MoreThanMajorityThenPrimeDefaultVote;
97+
type SetMembersOrigin = EnsureRoot<AccountId>;
98+
type WeightInfo = pallet_collective::weights::SubstrateWeight<Runtime>;
99+
type MaxProposalWeight = MaxProposalWeight;
100+
type DisapproveOrigin = EnsureRoot<Self::AccountId>;
101+
type KillOrigin = EnsureRoot<Self::AccountId>;
102+
type Consideration = ();
103+
}
104+
```
105+
106+
While the example above uses identical configurations for both instances, you can customize each instance's parameters to serve different purposes within your runtime.
107+
108+
### Add Pallet Instances to the Runtime
109+
110+
Finally, add both pallet instances to your runtime definition, ensuring each has:
111+
112+
- A unique pallet index
113+
- The correct instance type specified
114+
115+
```rust hl_lines="6-10"
116+
#[frame_support::runtime]
117+
mod runtime {
118+
#[runtime::runtime]
119+
// ... other runtime configuration
120+
121+
#[runtime::pallet_index(16)]
122+
pub type Collective1 = pallet_collective<Instance1>;
123+
124+
#[runtime::pallet_index(17)]
125+
pub type Collective2 = pallet_collective<Instance2>;
126+
127+
// ... other pallets
128+
}
129+
```
130+
131+
## Where to Go Next
132+
133+
If you've followed all the steps correctly, you should now be able to compile your runtime and interact with both instances of the pallet. Each instance will operate independently with its own storage, events, and configured parameters.
134+
135+
Now that you've mastered implementing multiple pallet instances, the next step is creating your own custom pallets. Explore the following resources:
136+
137+
<div class="grid cards" markdown>
138+
139+
- <span class="badge guide">Guide</span> __Make a Custom Pallet__
140+
141+
---
142+
143+
Learn how to create custom pallets using FRAME, allowing for flexible, modular, and scalable blockchain development. Follow the step-by-step guide.
144+
145+
[:octicons-arrow-right-24: Reference](/develop/parachains/customize-parachain/make-custom-pallet/)
146+
147+
</div>

llms.txt

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Doc-Page: https://docs.polkadot.com/develop/interoperability/xcm-config/
1414
Doc-Page: https://docs.polkadot.com/develop/interoperability/xcm-runtime-apis/
1515
Doc-Page: https://docs.polkadot.com/develop/networks/
1616
Doc-Page: https://docs.polkadot.com/develop/parachains/customize-parachain/add-existing-pallets/
17+
Doc-Page: https://docs.polkadot.com/develop/parachains/customize-parachain/add-pallet-instances/
1718
Doc-Page: https://docs.polkadot.com/develop/parachains/customize-parachain/add-smart-contract-functionality/
1819
Doc-Page: https://docs.polkadot.com/develop/parachains/customize-parachain/
1920
Doc-Page: https://docs.polkadot.com/develop/parachains/customize-parachain/make-custom-pallet/
@@ -3076,6 +3077,14 @@ With the pallet successfully added and configured, the runtime is ready to be co
30763077

30773078
<div class="grid cards" markdown>
30783079

3080+
- <span class="badge guide">Guide</span> __Add Multiple Pallet Instances__
3081+
3082+
---
3083+
3084+
Learn how to implement multiple instances of the same pallet in your Polkadot SDK-based runtime to create and interact with modular blockchain components.
3085+
3086+
[:octicons-arrow-right-24: Reference](/develop/parachains/customize-parachain/add-pallet-instances/)
3087+
30793088
- <span class="badge guide">Guide</span> __Make a Custom Pallet__
30803089

30813090
---
@@ -3095,6 +3104,157 @@ With the pallet successfully added and configured, the runtime is ready to be co
30953104
</div>
30963105
--- END CONTENT ---
30973106

3107+
Doc-Content: https://docs.polkadot.com/develop/parachains/customize-parachain/add-pallet-instances/
3108+
--- BEGIN CONTENT ---
3109+
---
3110+
title: Add Multiple Pallet Instances
3111+
description: Learn how to implement multiple instances of the same pallet in your Polkadot SDK-based runtime to create and interact with modular blockchain components.
3112+
---
3113+
3114+
# Add Multiple Pallet Instances
3115+
3116+
## Introduction
3117+
3118+
Running multiple instances of the same pallet within a runtime is a powerful technique in Polkadot SDK development. This approach lets you reuse pallet functionality without reimplementing it, enabling diverse use cases with the same codebase. The Polkadot SDK provides developer-friendly traits for creating instantiable pallets and, in most cases, handles unique storage allocation for different instances automatically. This guide teaches you how to implement and configure multiple instances of a pallet in your runtime.
3119+
3120+
## Understanding Instantiable Pallets
3121+
3122+
Unlike standard pallets that exist as a single instance in a runtime, instantiable pallets require special configuration through an additional [generic parameter](https://doc.rust-lang.org/reference/items/generics.html){target=\_blank} `I`.
3123+
This generic `I` creates a unique [lifetime](https://doc.rust-lang.org/rust-by-example/scope/lifetime.html){target=\_blank} for each pallet instance, affecting the pallet's generic types and its configuration trait `T`.
3124+
3125+
You can identify an instantiable pallet by examining its `Pallet` struct definition, which will include both the standard generic `T` and the instantiation generic `I`:
3126+
3127+
```rust
3128+
#[pallet::pallet]
3129+
pub struct Pallet<T, I = ()>(PhantomData<(T, I)>);
3130+
```
3131+
3132+
The instantiation generic also appears throughout the pallet's components, including the `Config` trait, storage items, events, errors, and genesis configuration.
3133+
3134+
## Adding Instantiable Pallets to Your Runtime
3135+
3136+
The process resembles adding a standard pallet with some key differences. In this example you will see how adding two instances of the [pallet-collective](https://github.com/paritytech/polkadot-sdk/tree/{{dependencies.repositories.polkadot_sdk.version}}/substrate/frame/collective){target=\_blank} is implemented.
3137+
3138+
### Define Pallet Parameters
3139+
3140+
First, define the parameters needed to configure the pallet instances. This step is identical whether implementing single or multiple instances:
3141+
3142+
```rust
3143+
parameter_types! {
3144+
pub const MotionDuration: BlockNumber = 24 * HOURS;
3145+
pub MaxProposalWeight: Weight = Perbill::from_percent(50) * RuntimeBlockWeights::get().max_block;
3146+
pub const MaxProposals: u32 = 100;
3147+
pub const MaxMembers: u32 = 100;
3148+
}
3149+
```
3150+
3151+
### Configure the Pallet Instances
3152+
3153+
For a single instance, the configuration would look like this:
3154+
3155+
```rust hl_lines="1"
3156+
impl pallet_collective::Config for Runtime {
3157+
type RuntimeOrigin = RuntimeOrigin;
3158+
type Proposal = RuntimeCall;
3159+
type RuntimeEvent = RuntimeEvent;
3160+
type MotionDuration = MotionDuration;
3161+
type MaxProposals = MaxProposals;
3162+
type MaxMembers = MaxMembers;
3163+
type DefaultVote = pallet_collective::MoreThanMajorityThenPrimeDefaultVote;
3164+
type SetMembersOrigin = EnsureRoot<AccountId>;
3165+
type WeightInfo = pallet_collective::weights::SubstrateWeight<Runtime>;
3166+
type MaxProposalWeight = MaxProposalWeight;
3167+
type DisapproveOrigin = EnsureRoot<Self::AccountId>;
3168+
type KillOrigin = EnsureRoot<Self::AccountId>;
3169+
type Consideration = ();
3170+
}
3171+
```
3172+
3173+
For multiple instances, you need to create a unique identifier for each instance using the `Instance` type with a number suffix, then implement the configuration for each one:
3174+
3175+
```rust hl_lines="2-3"
3176+
// Configure first instance
3177+
type Collective1 = pallet_collective::Instance1;
3178+
impl pallet_collective::Config<Collective1> for Runtime {
3179+
type RuntimeOrigin = RuntimeOrigin;
3180+
type Proposal = RuntimeCall;
3181+
type RuntimeEvent = RuntimeEvent;
3182+
type MotionDuration = MotionDuration;
3183+
type MaxProposals = MaxProposals;
3184+
type MaxMembers = MaxMembers;
3185+
type DefaultVote = pallet_collective::MoreThanMajorityThenPrimeDefaultVote;
3186+
type SetMembersOrigin = EnsureRoot<AccountId>;
3187+
type WeightInfo = pallet_collective::weights::SubstrateWeight<Runtime>;
3188+
type MaxProposalWeight = MaxProposalWeight;
3189+
type DisapproveOrigin = EnsureRoot<Self::AccountId>;
3190+
type KillOrigin = EnsureRoot<Self::AccountId>;
3191+
type Consideration = ();
3192+
}
3193+
```
3194+
```rust hl_lines="2-3"
3195+
// Configure second instance
3196+
type Collective2 = pallet_collective::Instance2;
3197+
impl pallet_collective::Config<Collective2> for Runtime {
3198+
type RuntimeOrigin = RuntimeOrigin;
3199+
type Proposal = RuntimeCall;
3200+
type RuntimeEvent = RuntimeEvent;
3201+
type MotionDuration = MotionDuration;
3202+
type MaxProposals = MaxProposals;
3203+
type MaxMembers = MaxMembers;
3204+
type DefaultVote = pallet_collective::MoreThanMajorityThenPrimeDefaultVote;
3205+
type SetMembersOrigin = EnsureRoot<AccountId>;
3206+
type WeightInfo = pallet_collective::weights::SubstrateWeight<Runtime>;
3207+
type MaxProposalWeight = MaxProposalWeight;
3208+
type DisapproveOrigin = EnsureRoot<Self::AccountId>;
3209+
type KillOrigin = EnsureRoot<Self::AccountId>;
3210+
type Consideration = ();
3211+
}
3212+
```
3213+
3214+
While the example above uses identical configurations for both instances, you can customize each instance's parameters to serve different purposes within your runtime.
3215+
3216+
### Add Pallet Instances to the Runtime
3217+
3218+
Finally, add both pallet instances to your runtime definition, ensuring each has:
3219+
3220+
- A unique pallet index
3221+
- The correct instance type specified
3222+
3223+
```rust hl_lines="6-10"
3224+
#[frame_support::runtime]
3225+
mod runtime {
3226+
#[runtime::runtime]
3227+
// ... other runtime configuration
3228+
3229+
#[runtime::pallet_index(16)]
3230+
pub type Collective1 = pallet_collective<Instance1>;
3231+
3232+
#[runtime::pallet_index(17)]
3233+
pub type Collective2 = pallet_collective<Instance2>;
3234+
3235+
// ... other pallets
3236+
}
3237+
```
3238+
3239+
## Where to Go Next
3240+
3241+
If you've followed all the steps correctly, you should now be able to compile your runtime and interact with both instances of the pallet. Each instance will operate independently with its own storage, events, and configured parameters.
3242+
3243+
Now that you've mastered implementing multiple pallet instances, the next step is creating your own custom pallets. Explore the following resources:
3244+
3245+
<div class="grid cards" markdown>
3246+
3247+
- <span class="badge guide">Guide</span> __Make a Custom Pallet__
3248+
3249+
---
3250+
3251+
Learn how to create custom pallets using FRAME, allowing for flexible, modular, and scalable blockchain development. Follow the step-by-step guide.
3252+
3253+
[:octicons-arrow-right-24: Reference](/develop/parachains/customize-parachain/make-custom-pallet/)
3254+
3255+
</div>
3256+
--- END CONTENT ---
3257+
30983258
Doc-Content: https://docs.polkadot.com/develop/parachains/customize-parachain/add-smart-contract-functionality/
30993259
--- BEGIN CONTENT ---
31003260
---

0 commit comments

Comments
 (0)