OpenZeppelin Pallet Abstractions

Introduction

openzeppelin-pallet-abstractions is a Rust macro library designed to simplify and secure the configuration of Polkadot parachain runtimes. By reducing repetitive boilerplate and providing sensible defaults, the library helps developers configure their runtimes with fewer lines of code while ensuring flexibility for customizations.

Note: This library has not been audited yet and should not be used in production environments.

1. Installation

To start using the openzeppelin-pallet-abstractions, add it as a dependency in your Cargo.toml file:

[dependencies]
openzeppelin-pallet-abstractions = { git = "https://github.com/OpenZeppelin/openzeppelin-pallet-abstractions", tag = "v0.1.0" }

Then, import the required macros in your runtime configuration file.

2. Basic Usage

The library offers a collection of macros for configuring various core runtime elements such as system settings, assets, governance, consensus mechanisms, EVM integration, and XCM compatibility. Let’s walk through a basic example setup:

1. System configuration

The impl_openzeppelin_system! macro facilitates the setup of foundational runtime components by implementing the SystemConfig trait for your custom runtime structure.

use openzeppelin_pallet_abstractions::{impl_openzeppelin_system, SystemConfig};

pub struct OpenZeppelinRuntime;

impl SystemConfig for OpenZeppelinRuntime {
    type AccountId = AccountId;
    type ExistentialDeposit = ConstU128<EXISTENTIAL_DEPOSIT>;
    type PreimageOrigin = EnsureRoot<AccountId>;
    type ScheduleOrigin = EnsureRoot<AccountId>;
    type Version = Version;
    // Additional configurations...
}
impl_openzeppelin_system!(OpenZeppelinRuntime);

This expands to configure multiple core pallets like frame_system, pallet_timestamp, parachain_info, and others essential for a functioning parachain runtime.

2. Additional configurations

Further configuration can be achieved for pallets grouped by functionality, such as Assets, Consensus, EVM, Governance, and XCM. Each grouping has its own macro and configuration trait, making it easier to set up advanced components without redundant code.

Example setup for additional configurations in an EVM-based runtime:

use openzeppelin_pallet_abstractions::{
    impl_openzeppelin_assets, impl_openzeppelin_consensus, impl_openzeppelin_evm,
    impl_openzeppelin_governance, impl_openzeppelin_xcm, AssetsConfig,
    ConsensusConfig, EvmConfig, GovernanceConfig, XcmConfig,
};

impl ConsensusConfig for OpenZeppelinRuntime {
    type CollatorSelectionUpdateOrigin = CollatorSelectionUpdateOrigin;
}

impl GovernanceConfig for OpenZeppelinRuntime {
    type ConvictionVoteLockingPeriod = ConstU32<{ 7 * DAYS }>;
    type DispatchWhitelistedOrigin = EitherOf<EnsureRoot<AccountId>, WhitelistedCaller>;
    // Additional configurations...
}

// Further configuration implementations...

impl_openzeppelin_assets!(OpenZeppelinRuntime);
impl_openzeppelin_consensus!(OpenZeppelinRuntime);
impl_openzeppelin_governance!(OpenZeppelinRuntime);
impl_openzeppelin_xcm!(OpenZeppelinRuntime);
impl_openzeppelin_evm!(OpenZeppelinRuntime);
3. Advanced Configuration Options

Each macro allows optional parameters to override the default values. This enables fine-tuning of runtime settings according to the specific needs of your parachain while retaining the benefits of standardized, secure defaults.

Default Overrides: Customize specific parameters like ExistentialDeposit, BaseXcmWeight, or AssetId while relying on default values for other settings. Custom Implementations: Integrate custom types (like EitherOf, ConstU32) or origins (EnsureRoot, WhitelistedCaller) for advanced use cases.

4. Security Considerations

While the library is built with security in mind, it’s essential to review each configuration for your specific runtime and context.

5. Contributing and Feedback

We encourage contributions from the community to improve the library. Please refer to the CONTRIBUTING.md for guidelines.

3. Using Procedural Macros in OpenZeppelin Pallet Abstractions

1. construct_runtime! Macro

The construct_runtime! macro simplifies the assembly of runtime modules by abstracting over both OpenZeppelin abstractions and standard pallets. This is useful for developers aiming to build a runtime quickly, without manually managing each pallet’s configuration.

Usage Example

To use the macro, annotate a module with #[openzeppelin_construct_runtime] and define structs for each desired abstraction or regular pallet. Here’s a basic example:

#[openzeppelin_construct_runtime]
mod runtime {
    #[abstraction]
    struct System; // Available abstractions: System, Consensus, XCM, Assets, Governance, EVM.
    #[pallet]
    type Pallet = pallet_crate; // Regular pallets defined with `#[pallet]` mimic the `construct_runtime!` structure.
}

Note: Pallet index assignments are handled automatically by this macro. If you require explicit control over pallet indices, please consider submitting a feature request.

Supported Abstractions and their Pallets:
  • System — frame_system, pallet_timestamp, parachain_info, pallet_scheduler, pallet_preimage, pallet_proxy, pallet_balances, pallet_utility, cumulus_pallet_parachain_system, pallet_multisig, pallet_session

  • Assets — pallet_assets, pallet_transaction_payment, pallet_asset_manager

  • Consensus — pallet_authorship, pallet_aura, cumulus_pallet_aura_ext, pallet_collator_selection

  • Governance — pallet_sudo, pallet_treasury, pallet_conviction_voting, pallet_whitelist, pallet_custom_origins, pallet_referenda

  • XCM — pallet_message_queue, cumulus_pallet_xcmp_queue, pallet_xcm, cumulus_pallet_xcm, pallet_xcm_transactor, orml_xtokens, pallet_xcm_weight_trader

  • EVM — pallet_ethereum, pallet_evm, pallet_base_fee, pallet_evm_chain_id, pallet_erc20_xcm_bridge

2. impl_runtime_apis! Macro

The The impl_runtime_apis! macro provides a clean interface for implementing runtime APIs. This macro reduces boilerplate by allowing you to specify types and structs, automatically generating the required API implementations.

Usage Example

To use this macro, annotate a module with #[openzeppelin_runtime_apis] and define the types and abstractions needed.

#[openzeppelin_runtime_apis]
mod apis {
    type Runtime = Runtime;   // The runtime generated by `construct_runtime!`
    type Block = Block;       // Block type required by all abstractions

    #[abstraction]
    mod assets {
        type TransactionPayment = TransactionPayment;
        type RuntimeCall = RuntimeCall;
        type Balance = Balance;
    }

    // Additional `impl` blocks can be added as necessary.
}
Supported Abstractions, APIs, and Required Configurations:
Abstraction name Implemented APIs Required configs

EVM

* fp_rpc::EthereumRuntimeRPCApi
* fp_rpc::ConvertTransactionRuntimeApi

* RuntimeCall — runtime call generated by construct_runtime macro
* Executive — frame_executive::Executive specification used by parachain system
* Ethereum — pallet_ethereum pallet struct generated by construct_runtime macro

assets

* pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi
* pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi

* TransactionPayment — pallet_transaction_payment struct pallet generated by construct_runtime macro
* RuntimeCall — runtime call generated by construct_runtime macro
* Balance — type used for balance specification (e.g., in pallet_balances config)

consensus

* sp_consensus_aura::AuraApi
* sp_session::SessionKeys
* cumulus_primitives_aura::AuraUnincludedSegmentApi (if async-backing feature is enabled)

* SessionKeys — struct generated by impl_opaque_keys macro
* Aura — pallet_aura struct pallet generated by construct_runtime macro (only if async-backing feature is not enabled)
* SlotDuration — constant used for slot duration definition (only if async-backing feature is enabled)
* ConsensusHook — type used in cumulus_pallet_parachain_system::Config::ConsensusHook (only if async-backing feature is enabled)

system

* sp_api::Core
* sp_api::Metadata
* sp_block_builder::BlockBuilder
* sp_transaction_pool::runtime_api::TaggedTransactionQueue
* sp_offchain::OffchainWorkerApi
* frame_system_rpc_runtime_api::AccountNonceApi
* cumulus_primitives_core::CollectCollationInfo
* frame_try_runtime::TryRuntime (under a try-runtime feature)
* sp_genesis_builder::GenesisBuilder

* Executive — frame_executive::Executive specification used by parachain system
* System — frame_system pallet struct generated by construct_runtime macro
* ParachainSystem — cumulus_pallet_parachain_system pallet struct generated by construct_runtime macro
* RuntimeVersion — runtime version, generated by sp_version::runtime_version
* AccountId — account id type specified in frame_system::Config
* Nonce — nonce type specified in frame_system::Config
* RuntimeGenesisConfig — type generated by construct_runtime macro
* RuntimeBlockWeights — type implementing Get<BlockWeights>, often built by BlockWeights::builder

benchmarks

* frame_benchmarking::Benchmark (under runtime-benchmarks feature)

* Assets — pallet_assets pallet struct generated by construct_runtime macro
* AssetManager — pallet_asset_manager pallet struct generated by construct_runtime macro
* AssetType — struct describing foreign assets in XCM configuration
* RuntimeOrigin — type generated by construct_runtime macro
* RelayLocation — Location type pointing to the relaychain
* System — frame_system pallet struct generated by construct_runtime macro
* ParachainSystem — cumulus_pallet_parachain_system pallet struct generated by construct_runtime macro
* ExistentialDeposit — type describing existential deposit
* AssetId — type describing internal asset id
* XCMConfig — struct implementing xcm_executor::Config, generated by XCM abstraction as XcmExecutorConfig
* AccountId — account id type specified in frame_system::Config
* Cents — constant representing 1/100 of the native token
* FeeAssetId — asset for XCM fees, generated by XCM abstraction
* TransactionByteFee — fee per byte of data, generated by assets abstraction
* Address — type describing address format for accounts
* Balances — pallet_balances pallet struct generated by construct_runtime macro

This macro allows for clear modularization of APIs, facilitating easier maintenance and extension of runtime functionalities.