✨Works out of the box guarantee. If you face any issue at all, hit us up on Telegram and we will write the integration for you.

Polkadot
Substrate Quickstart

Integrate with Reclaim Pallet

Pre-requisite

You need to be familiar with Substrate Framework (opens in a new tab).

At this stage, we assume that you are familiar with the steps at ReactJs.

You can access the code of this walkthrough on Gitlab (opens in a new tab)

Integration with Reclaim Pallet using node template

Please note that pallet_integration_with_reclaim pallet is an example pallet that represents your pallet which you want to intergrate Reclaim with.

Clone the Substrate node with reclaim repo.

This Substrate node with reclaim (opens in a new tab) serves as a node template which enables you to use ReclaimVerifier trait in your pallets.

There are two pallets already configured:

  • pallet_reclaim: contains the reclaim logic to verify proofs and implements ReclaimVerifier
  • pallet_integration_with_reclaim: Example pallet that aims to store if the account is verified and uses ReclaimVerifier as an associated type in your pallet Config
git clone https://gitlab.reclaimprotocol.org/integrations/onchain/substrate-sdk
cd substrate-sdk
cargo test

Code Discovery (pallet-reclaim/src/traits.rs)

This file defines the ReclaimVerifier trait which is an interface for verifying proofs in the Reclaim logic.

use frame_support::dispatch::DispatchResult;
 
pub trait ReclaimVerifier<Proof> {
    fn verify_proof(proof: &Proof) -> DispatchResult;
}
 
impl<Proof> ReclaimVerifier<Proof> for () {
    fn verify_proof(_proof: &Proof) -> DispatchResult {
    unimplemented!()
}
 

Code Discovery (pallet-reclaim/src/lib.rs)

Examine the core logic of the Reclaim pallet in lib.rs. This includes the implementation of the Reclaim logic, storage items, and the public functions that interact with the blockchain.

  • Implements ReclaimVerifier
impl<T> ReclaimVerifier<Proof> for Pallet<T>
where
    T: Config,
{
    fn verify_proof(proof: &Proof) -> DispatchResult {
        let config = <PReclaimConfig<T>>::get().unwrap();
        let epoch_count = config.current_epoch;
        let current_epoch = <Epochs<T>>::get(epoch_count);
        .....
        ...
    	Ok(())
    }
 
}
 
  • Extrinsics for Reclaim Protocol
// For Management. Setup Variables for Reclaim Protocol
pub fn init(origin: OriginFor<T>) -> DispatchResult{
    ...
}
 
// For Management. Only callabe by reclaim manager account (initializer account)
pub fn add_epoch(
    origin: OriginFor<T>,
    witness: BoundedVec<Witness, ConstU32<100>>,
    minimum_witness: u128,
) -> DispatchResult{
    ....
}
 
// Anyone can call to check if their proofs are valid.
pub fn verify_proof(
    origin: OriginFor<T>,
    claim_info: ClaimInfo,
    signed_claim: SignedClaim,
) -> DispatchResult
 

Code Discovery (pallet-integration-with-reclaim/src/lib.rs)

This file illustrates how to use the ReclaimVerifier trait in another pallet, which stores verification status for accounts.

  • ReclaimVerifier is added to Config
pub trait Config: frame_system::Config {
    type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
    type ReclaimVerifier: ReclaimVerifier<Proof>;
    type WeightInfo: WeightInfo;
}
  • Storage to persist if an account is verified
pub(super) type AccountVerified<T: Config> = StorageMap<_, Identity, T::AccountId, bool, OptionQuery>;
  • Extrinsic to Verify if user's proof is valid and store that user's account is verified
#[pallet::call_index(0)]
#[pallet::weight(<T as pallet::Config>::WeightInfo::verify_user())]
pub fn verify_user(origin: OriginFor<T>, proof: Proof) -> DispatchResult {
    let who = ensure_signed(origin)?;
    // call `verify_proof`. If verification failed, It will raise `Reclaim` error and revert.
    T::ReclaimVerifier::verify_proof(&proof)?;
    <AccountVerified<T>>::set(&who, Some(true));
    Self::deposit_event(Event::UserVerified { account_id: who });
    Ok(())
}

Code Discovery (pallet-integration-with-reclaim/src/mock.rs)

In mock.rs, set up the testing environment for the integration pallet. This involves configuring mock traits and runtime for unit tests.

impl pallet_reclaim::Config for Test {
    type RuntimeEvent = RuntimeEvent;
    type Signature = sp_core::ecdsa::Signature;
    type PublicKey = sp_core::ecdsa::Public;
    type WeightInfo = ();
}
 
impl pallet_integration_with_reclaim::Config for Test {
    type RuntimeEvent = RuntimeEvent;
    // ReclaimVerifier assigned to Reclaim Pallet which implements it
    type ReclaimVerifier = pallet_reclaim::Pallet<Test>;
    type WeightInfo = ();
}
 

Code Discovery (runtime/src/lib.rs)

In your runtime's lib.rs, integrate the pallets to the runtime configuration, ensuring they are included in the construct_runtime! macro.

  • Implement Configs for Runtime
impl pallet_reclaim::Config for Runtime {
    type RuntimeEvent = RuntimeEvent;
    type Signature = sp_core::ecdsa::Signature;
    type PublicKey = sp_core::ecdsa::Public;
    type WeightInfo = pallet_reclaim::weights::SubstrateWeightInfo<Runtime>;
}
 
impl pallet_integration_with_reclaim::Config for Runtime {
    type RuntimeEvent = RuntimeEvent;
    type ReclaimVerifier = pallet_reclaim::Pallet<Runtime>;
    type WeightInfo = pallet_integration_with_reclaim::weights::SubstrateWeightInfo<Runtime>;
}
  • Include the pallets in Runtime
construct_runtime!(
    pub struct Runtime {
        System: frame_system,
        Timestamp: pallet_timestamp,
        Aura: pallet_aura,
        Grandpa: pallet_grandpa,
        Balances: pallet_balances,
        TransactionPayment: pallet_transaction_payment,
        Sudo: pallet_sudo,
        Reclaim: pallet_reclaim,
        IntegrationWithReclaim: pallet_integration_with_reclaim,
    }
);
 
  • Add pallets to benches module
mod benches {
    define_benchmarks!(
        [frame_benchmarking, BaselineBench::<Runtime>]
        [frame_system, SystemBench::<Runtime>]
        [pallet_balances, Balances]
        [pallet_timestamp, Timestamp]
        [pallet_sudo, Sudo]
        [pallet_reclaim, Reclaim]
        [pallet_integration_with_reclaim, IntegrationWithReclaim]
    );
}