Skip to content

Commit

Permalink
Tutorials > Polkadot SDK > Parachains > Build Custom Pallet > Build t…
Browse files Browse the repository at this point in the history
…he Pallet (#232)

* wip: build-pallet

* Page ready

* Improvements

* Extract code snippets

* Description and grammarly

* fix: typo

* Add suggestions

* Update tutorials/polkadot-sdk/parachains/build-custom-pallet/build-pallet.md

Co-authored-by: Nicolás Hussein <[email protected]>

* Add root origin reference

* Apply suggestions from code review

Co-authored-by: Erin Shaben <[email protected]>

* Apply fmt

* Apply suggestions from code review

Co-authored-by: Erin Shaben <[email protected]>

* Apply suggestions from code review

Co-authored-by: Nicolás Hussein <[email protected]>

* Apply fixes

---------

Co-authored-by: nhussein11 <[email protected]>
Co-authored-by: Nicolás Hussein <[email protected]>
Co-authored-by: Erin Shaben <[email protected]>
  • Loading branch information
4 people authored Dec 12, 2024
1 parent 8df580b commit 215e49a
Show file tree
Hide file tree
Showing 10 changed files with 548 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[package]
name = "custom-pallet"
version = "0.1.0"
license.workspace = true
authors.workspace = true
homepage.workspace = true
repository.workspace = true
edition.workspace = true

[dependencies]
codec = { features = ["derive"], workspace = true }
scale-info = { features = ["derive"], workspace = true }
frame-support.workspace = true
frame-system.workspace = true

[features]
default = ["std"]
std = ["codec/std", "frame-support/std", "frame-system/std", "scale-info/std"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#[pallet::call]
impl<T: Config> Pallet<T> {
#[pallet::call_index(0)]
#[pallet::weight(0)]
pub fn set_counter_value(origin: OriginFor<T>, new_value: u32) -> DispatchResult {}

#[pallet::call_index(1)]
#[pallet::weight(0)]
pub fn increment(origin: OriginFor<T>, amount_to_increment: u32) -> DispatchResult {}

#[pallet::call_index(2)]
#[pallet::weight(0)]
pub fn decrement(origin: OriginFor<T>, amount_to_decrement: u32) -> DispatchResult {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<div id="termynal" data-termynal>
<span data-ty="input"><span class="file-path"></span>cargo build --release</span>
<span data-ty>Compiling solochain-template-node</span>
<span data-ty>Finished `release` profile [optimized] target(s) in 27.12s</span>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
#![cfg_attr(not(feature = "std"), no_std)]

pub use pallet::*;

#[frame_support::pallet(dev_mode)]
pub mod pallet {
use super::*;
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;

#[pallet::pallet]
pub struct Pallet<T>(_);

// Configuration trait for the pallet
#[pallet::config]
pub trait Config: frame_system::Config {
// Defines the event type for the pallet
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;

// Defines the maximum value the counter can hold
#[pallet::constant]
type CounterMaxValue: Get<u32>;
}

#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
/// The counter value has been set to a new value by Root.
CounterValueSet {
/// The new value set.
counter_value: u32,
},
/// A user has successfully incremented the counter.
CounterIncremented {
/// The new value set.
counter_value: u32,
/// The account who incremented the counter.
who: T::AccountId,
/// The amount by which the counter was incremented.
incremented_amount: u32,
},
/// A user has successfully decremented the counter.
CounterDecremented {
/// The new value set.
counter_value: u32,
/// The account who decremented the counter.
who: T::AccountId,
/// The amount by which the counter was decremented.
decremented_amount: u32,
},
}

/// Storage for the current value of the counter.
#[pallet::storage]
pub type CounterValue<T> = StorageValue<_, u32>;

/// Storage map to track the number of interactions performed by each account.
#[pallet::storage]
pub type UserInteractions<T: Config> = StorageMap<_, Twox64Concat, T::AccountId, u32>;

#[pallet::error]
pub enum Error<T> {
/// The counter value exceeds the maximum allowed value.
CounterValueExceedsMax,
/// The counter value cannot be decremented below zero.
CounterValueBelowZero,
/// Overflow occurred in the counter.
CounterOverflow,
/// Overflow occurred in user interactions.
UserInteractionOverflow,
}

#[pallet::call]
impl<T: Config> Pallet<T> {
/// Set the value of the counter.
///
/// The dispatch origin of this call must be _Root_.
///
/// - `new_value`: The new value to set for the counter.
///
/// Emits `CounterValueSet` event when successful.
#[pallet::call_index(0)]
#[pallet::weight(0)]
pub fn set_counter_value(origin: OriginFor<T>, new_value: u32) -> DispatchResult {
ensure_root(origin)?;

ensure!(
new_value <= T::CounterMaxValue::get(),
Error::<T>::CounterValueExceedsMax
);

CounterValue::<T>::put(new_value);

Self::deposit_event(Event::<T>::CounterValueSet {
counter_value: new_value,
});

Ok(())
}

/// Increment the counter by a specified amount.
///
/// This function can be called by any signed account.
///
/// - `amount_to_increment`: The amount by which to increment the counter.
///
/// Emits `CounterIncremented` event when successful.
#[pallet::call_index(1)]
#[pallet::weight(0)]
pub fn increment(origin: OriginFor<T>, amount_to_increment: u32) -> DispatchResult {
let who = ensure_signed(origin)?;

let current_value = CounterValue::<T>::get().unwrap_or(0);

let new_value = current_value
.checked_add(amount_to_increment)
.ok_or(Error::<T>::CounterOverflow)?;

ensure!(
new_value <= T::CounterMaxValue::get(),
Error::<T>::CounterValueExceedsMax
);

CounterValue::<T>::put(new_value);

UserInteractions::<T>::try_mutate(&who, |interactions| -> Result<_, Error<T>> {
let new_interactions = interactions
.unwrap_or(0)
.checked_add(1)
.ok_or(Error::<T>::UserInteractionOverflow)?;
*interactions = Some(new_interactions); // Store the new value

Ok(())
})?;

Self::deposit_event(Event::<T>::CounterIncremented {
counter_value: new_value,
who,
incremented_amount: amount_to_increment,
});

Ok(())
}

/// Decrement the counter by a specified amount.
///
/// This function can be called by any signed account.
///
/// - `amount_to_decrement`: The amount by which to decrement the counter.
///
/// Emits `CounterDecremented` event when successful.
#[pallet::call_index(2)]
#[pallet::weight(0)]
pub fn decrement(origin: OriginFor<T>, amount_to_decrement: u32) -> DispatchResult {
let who = ensure_signed(origin)?;

let current_value = CounterValue::<T>::get().unwrap_or(0);

let new_value = current_value
.checked_sub(amount_to_decrement)
.ok_or(Error::<T>::CounterValueBelowZero)?;

CounterValue::<T>::put(new_value);

UserInteractions::<T>::try_mutate(&who, |interactions| -> Result<_, Error<T>> {
let new_interactions = interactions
.unwrap_or(0)
.checked_add(1)
.ok_or(Error::<T>::UserInteractionOverflow)?;
*interactions = Some(new_interactions); // Store the new value

Ok(())
})?;

Self::deposit_event(Event::<T>::CounterDecremented {
counter_value: new_value,
who,
decremented_amount: amount_to_decrement,
});

Ok(())
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#![cfg_attr(not(feature = "std"), no_std)]

pub use pallet::*;

#[frame_support::pallet(dev_mode)]
pub mod pallet {
use super::*;
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;

#[pallet::pallet]
pub struct Pallet<T>(_);

#[pallet::config]
pub trait Config: frame_system::Config {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ b. Click **Switch** to connect to the respective network

![](/images/tutorials/interoperability/xcm-transfers/from-relaychain-to-parachain/from-relaychain-to-parachain-01.webp)


This reserve-backed transfer method facilitates asset transfers from a local chain to a destination chain by trusting a third party called a reserve to store the real assets. Fees on the destination chain are deducted from the asset specified in the assets vector at the `fee_asset_item` index, covering up to the specified `weight_limit.` The operation fails if the required weight exceeds this limit, potentially putting the transferred assets at risk.

The following steps outline how to execute a reserve-backed transfer from the Polkadot relay chain to the Astar parachain.
Expand Down Expand Up @@ -76,6 +75,7 @@ The following steps outline how to execute a reserve-backed transfer from the Po
3. **beneficiary** - defines the recipient of the assets within the destination context, typically represented as an `AccountId32` value. This example uses the following account present in the destination chain:
```bash
X2mE9hCGX771c3zzV6tPa8U2cDz4U4zkqUdmBrQn83M3cm7
```
Expand All @@ -102,6 +102,7 @@ After submitting the transaction from the relay chain, confirm its success by ch
To programmatically execute the reserve-backed asset transfer between the relay chain and the parachain, you can use [Polkadot API (PAPI)](/develop/toolkit/api-libraries/papi.md){target=\_blank}. PAPI is a robust toolkit that simplifies interactions with Polkadot-based chains. For this project, you'll first need to set up your environment, install necessary dependencies, and create a script to handle the transfer process.
1. Start by creating a folder for your project:
```bash
mkdir reserve-backed-asset-transfer
cd reserve-backed-asset
Expand Down
3 changes: 2 additions & 1 deletion tutorials/polkadot-sdk/parachains/.pages
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ title: Parachains
nav:
- index.md
- local-chain
- connect-to-relay-chain
- connect-to-relay-chain
- build-custom-pallet
4 changes: 4 additions & 0 deletions tutorials/polkadot-sdk/parachains/build-custom-pallet/.pages
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
title: Build Custom Pallet
nav:
- index.md
- 'Build Pallet': build-pallet.md
Loading

0 comments on commit 215e49a

Please sign in to comment.