Refactoring Checkpoint: (WIP)
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
[package]
|
||||
name = "pezpallet-tiki"
|
||||
description = "PezkuwiChain Tiki (Role NFT) Management Pallet"
|
||||
version = "1.0.0"
|
||||
authors.workspace = true
|
||||
homepage.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
publish = false
|
||||
repository.workspace = true
|
||||
documentation = "https://docs.rs/pezpallet-tiki"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
||||
[dependencies]
|
||||
codec = { workspace = true, default-features = false, features = ["derive"] }
|
||||
pezframe-benchmarking = { optional = true, workspace = true }
|
||||
pezframe-support = { default-features = false, workspace = true }
|
||||
pezframe-system = { default-features = false, workspace = true }
|
||||
log = { default-features = false, workspace = true }
|
||||
pezpallet-balances = { default-features = false, optional = true, workspace = true }
|
||||
pezpallet-identity = { default-features = false, workspace = true }
|
||||
pezpallet-identity-kyc = { workspace = true, default-features = false }
|
||||
pezpallet-nfts = { default-features = false, workspace = true }
|
||||
scale-info = { default-features = false, features = [
|
||||
"derive",
|
||||
], workspace = true }
|
||||
serde = { version = "1.0", default-features = false, features = ["derive"] }
|
||||
pezsp-runtime = { default-features = false, workspace = true }
|
||||
pezsp-std = { default-features = false, workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
pezsp-core = { workspace = true }
|
||||
pezsp-io = { workspace = true }
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = [
|
||||
"codec/std",
|
||||
"pezframe-benchmarking?/std",
|
||||
"pezframe-support/std",
|
||||
"pezframe-system/std",
|
||||
"log/std",
|
||||
"pezpallet-balances/std",
|
||||
"pezpallet-identity-kyc/std",
|
||||
"pezpallet-identity/std",
|
||||
"pezpallet-nfts/std",
|
||||
"scale-info/std",
|
||||
"serde/std",
|
||||
"pezsp-core/std",
|
||||
"pezsp-io/std",
|
||||
"pezsp-runtime/std",
|
||||
"pezsp-std/std",
|
||||
]
|
||||
runtime-benchmarks = [
|
||||
"dep:pezframe-benchmarking",
|
||||
"dep:pezpallet-balances",
|
||||
"pezframe-benchmarking/runtime-benchmarks",
|
||||
"pezframe-support/runtime-benchmarks",
|
||||
"pezframe-system/runtime-benchmarks",
|
||||
"pezpallet-balances/runtime-benchmarks",
|
||||
"pezpallet-identity-kyc/runtime-benchmarks",
|
||||
"pezpallet-identity/runtime-benchmarks",
|
||||
"pezpallet-nfts/runtime-benchmarks",
|
||||
"pezsp-io/runtime-benchmarks",
|
||||
"pezsp-runtime/runtime-benchmarks",
|
||||
]
|
||||
try-runtime = [
|
||||
"pezframe-support/try-runtime",
|
||||
"pezframe-system/try-runtime",
|
||||
"pezpallet-balances/try-runtime",
|
||||
"pezpallet-identity-kyc/try-runtime",
|
||||
"pezpallet-identity/try-runtime",
|
||||
"pezpallet-nfts/try-runtime",
|
||||
"pezsp-runtime/try-runtime",
|
||||
]
|
||||
@@ -0,0 +1,174 @@
|
||||
//! Benchmarking setup for pezpallet-tiki
|
||||
use super::*;
|
||||
|
||||
#[allow(unused)]
|
||||
use crate::Pallet as Tiki;
|
||||
use pezframe_benchmarking::v2::*;
|
||||
use pezframe_system::RawOrigin;
|
||||
// Gerekli trait'leri import ediyoruz
|
||||
use pezframe_support::traits::{Currency, Get};
|
||||
use pezpallet_balances::Pallet as Balances;
|
||||
use pezsp_runtime::traits::StaticLookup;
|
||||
extern crate alloc;
|
||||
use alloc::vec;
|
||||
|
||||
// Gerekli trait kısıtlamalarını ana benchmarks bloğuna ekliyoruz.
|
||||
#[benchmarks(
|
||||
where
|
||||
T::CollectionId: Copy + Default + PartialOrd,
|
||||
T: pezpallet_balances::Config,
|
||||
)]
|
||||
mod benchmarks {
|
||||
use super::*;
|
||||
|
||||
// Bu yardımcı fonksiyon, runtime'da tanımlanan Tiki koleksiyonunu oluşturur.
|
||||
fn ensure_collection_exists<T: Config>()
|
||||
where
|
||||
T::CollectionId: Copy + Default + PartialOrd,
|
||||
T: pezpallet_balances::Config,
|
||||
{
|
||||
let collection_id = T::TikiCollectionId::get();
|
||||
// Koleksiyon sahibi olarak fonlanmış `whitelisted_caller`'ı kullanıyoruz.
|
||||
let caller: T::AccountId = whitelisted_caller();
|
||||
|
||||
// Fund the caller account with sufficient balance for NFT deposits
|
||||
// Use a very large balance to ensure all deposit requirements can be met
|
||||
let funding = Balances::<T>::minimum_balance() * 1_000_000_000u32.into();
|
||||
Balances::<T>::make_free_balance_be(&caller, funding);
|
||||
|
||||
// `while` döngüsü, 'Step' trait'ine olan ihtiyacı ortadan kaldırır.
|
||||
while pezpallet_nfts::NextCollectionId::<T>::get().unwrap_or_default() <= collection_id {
|
||||
let _ = pezpallet_nfts::Pallet::<T>::force_create(
|
||||
RawOrigin::Root.into(),
|
||||
T::Lookup::unlookup(caller.clone()),
|
||||
pezpallet_nfts::CollectionConfig {
|
||||
settings: Default::default(),
|
||||
max_supply: None,
|
||||
mint_settings: Default::default(),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper to ensure user has a citizen NFT
|
||||
fn ensure_citizen_nft<T: Config>(who: T::AccountId) -> Result<(), DispatchError>
|
||||
where
|
||||
T::CollectionId: Copy + Default + PartialOrd,
|
||||
T: pezpallet_balances::Config,
|
||||
{
|
||||
ensure_collection_exists::<T>();
|
||||
|
||||
// Fund the user account with sufficient balance for NFT deposits
|
||||
// Use a very large balance to ensure all deposit requirements can be met
|
||||
let funding = Balances::<T>::minimum_balance() * 1_000_000_000u32.into();
|
||||
Balances::<T>::make_free_balance_be(&who, funding);
|
||||
|
||||
if Tiki::<T>::citizen_nft(&who).is_none() {
|
||||
Tiki::<T>::mint_citizen_nft_for_user(&who)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn grant_tiki() -> Result<(), BenchmarkError> {
|
||||
// NFT'yi alacak 'dest' hesabı olarak fonlanmış `whitelisted_caller`'ı kullanıyoruz.
|
||||
let dest: T::AccountId = whitelisted_caller();
|
||||
// Appointed role kullan (Serok yerine Wezir)
|
||||
let tiki = crate::Tiki::Wezir;
|
||||
|
||||
// Ensure the dest account has a citizen NFT before granting a tiki
|
||||
ensure_citizen_nft::<T>(dest.clone())?;
|
||||
|
||||
#[extrinsic_call]
|
||||
_(RawOrigin::Root, T::Lookup::unlookup(dest.clone()), tiki.clone());
|
||||
|
||||
// For non-unique roles, check user has the role
|
||||
assert!(Tiki::<T>::user_tikis(&dest).contains(&tiki));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn revoke_tiki() -> Result<(), BenchmarkError> {
|
||||
// NFT'yi alacak 'dest' hesabı olarak fonlanmış `whitelisted_caller`'ı kullanıyoruz.
|
||||
let dest: T::AccountId = whitelisted_caller();
|
||||
let tiki = crate::Tiki::Wezir; // Use appointed role
|
||||
|
||||
// Ensure the dest account has a citizen NFT and the tiki before revoking
|
||||
ensure_citizen_nft::<T>(dest.clone())?;
|
||||
Tiki::<T>::internal_grant_role(&dest, tiki.clone())?; // Use internal function to grant without origin check
|
||||
|
||||
// Verify the role was granted
|
||||
assert!(Tiki::<T>::user_tikis(&dest).contains(&tiki));
|
||||
|
||||
#[extrinsic_call]
|
||||
_(RawOrigin::Root, T::Lookup::unlookup(dest.clone()), tiki.clone());
|
||||
|
||||
// User should no longer have this role
|
||||
assert!(!Tiki::<T>::user_tikis(&dest).contains(&tiki));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn force_mint_citizen_nft() -> Result<(), BenchmarkError> {
|
||||
let dest: T::AccountId = whitelisted_caller();
|
||||
|
||||
// Ensure collection exists first
|
||||
ensure_collection_exists::<T>();
|
||||
|
||||
// Henüz vatandaş olmamalı
|
||||
assert!(Tiki::<T>::citizen_nft(&dest).is_none());
|
||||
|
||||
#[extrinsic_call]
|
||||
_(RawOrigin::Root, T::Lookup::unlookup(dest.clone()));
|
||||
|
||||
// Vatandaş olduğundan emin ol
|
||||
assert!(Tiki::<T>::citizen_nft(&dest).is_some());
|
||||
assert!(Tiki::<T>::is_citizen(&dest));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn grant_earned_role() -> Result<(), BenchmarkError> {
|
||||
let dest: T::AccountId = whitelisted_caller();
|
||||
let tiki = crate::Tiki::Axa; // Earned bir rol
|
||||
|
||||
// Ön koşul: Vatandaş olmalı
|
||||
ensure_citizen_nft::<T>(dest.clone())?;
|
||||
|
||||
#[extrinsic_call]
|
||||
_(RawOrigin::Root, T::Lookup::unlookup(dest.clone()), tiki.clone());
|
||||
|
||||
// Rolün verildiğini doğrula
|
||||
assert!(Tiki::<T>::has_tiki(&dest, &tiki));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn grant_elected_role() -> Result<(), BenchmarkError> {
|
||||
let dest: T::AccountId = whitelisted_caller();
|
||||
let tiki = crate::Tiki::Parlementer; // Elected bir rol
|
||||
|
||||
// Ön koşul: Vatandaş olmalı
|
||||
ensure_citizen_nft::<T>(dest.clone())?;
|
||||
|
||||
#[extrinsic_call]
|
||||
_(RawOrigin::Root, T::Lookup::unlookup(dest.clone()), tiki.clone());
|
||||
|
||||
// Rolün verildiğini doğrula
|
||||
assert!(Tiki::<T>::has_tiki(&dest, &tiki));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Temporarily skip this benchmark due to KYC complexity in benchmark environment
|
||||
// #[benchmark]
|
||||
// fn apply_for_citizenship() -> Result<(), BenchmarkError> {
|
||||
// // KYC setup is complex in benchmark environment
|
||||
// // This functionality is covered by force_mint_citizen_nft benchmark
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
impl_benchmark_test_suite!(Tiki, crate::mock::new_test_ext(), crate::mock::Test);
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
//! Custom Origin verification mechanisms based on Tiki ownership.
|
||||
//!
|
||||
//! This module provides `EnsureOrigin` implementations that verify
|
||||
//! the caller holds a specific Tiki role (Serok, Wezir, or Parlementer).
|
||||
//!
|
||||
//! # Feature Unification Note
|
||||
//!
|
||||
//! Due to Cargo's feature unification behavior, this pallet must be excluded
|
||||
//! from `cargo check --benches` operations when its `runtime-benchmarks` feature
|
||||
//! is not explicitly enabled. The CI workflow (tests-misc.yml) handles this
|
||||
//! by excluding pezpallet-tiki and all its dependents.
|
||||
//!
|
||||
//! The issue: When building with `--benches`, other packages may enable
|
||||
//! `pezframe-support/runtime-benchmarks`, which makes `EnsureOrigin::try_successful_origin`
|
||||
//! a required trait method. However, if `pezpallet-tiki/runtime-benchmarks` is not enabled,
|
||||
//! our cfg-gated method won't be compiled, causing E0046 errors.
|
||||
//!
|
||||
//! CI exclusion: .github/workflows/tests-misc.yml excludes this pallet with:
|
||||
//! `--exclude pezpallet-tiki` in the `cargo check --benches` command.
|
||||
|
||||
use crate::{Config, Pallet as TikiPallet};
|
||||
use pezframe_support::traits::EnsureOrigin;
|
||||
use pezframe_system::ensure_signed;
|
||||
use pezsp_std::marker::PhantomData;
|
||||
|
||||
// --- Marker Trait for Tiki Roles ---
|
||||
|
||||
/// A trait to return a specific `Tiki` enum variant.
|
||||
///
|
||||
/// This trait is implemented by marker structs to identify which
|
||||
/// Tiki role is required for origin verification.
|
||||
pub trait GetTiki {
|
||||
/// Returns the specific Tiki variant this marker represents.
|
||||
fn tiki() -> crate::Tiki;
|
||||
}
|
||||
|
||||
// --- Marker Structs for Each Role ---
|
||||
|
||||
/// Marker struct representing the `Serok` (President/Leader) role.
|
||||
///
|
||||
/// Use with `EnsureTiki` to require the caller holds the Serok Tiki:
|
||||
/// ```ignore
|
||||
/// type SerokOrigin = EnsureTiki<Runtime, SerokRole>;
|
||||
/// ```
|
||||
pub struct SerokRole;
|
||||
|
||||
impl GetTiki for SerokRole {
|
||||
fn tiki() -> crate::Tiki {
|
||||
crate::Tiki::Serok
|
||||
}
|
||||
}
|
||||
|
||||
/// Marker struct representing the `Wezir` (Minister/Advisor) role.
|
||||
///
|
||||
/// Use with `EnsureTiki` to require the caller holds the Wezir Tiki:
|
||||
/// ```ignore
|
||||
/// type WezirOrigin = EnsureTiki<Runtime, WezirRole>;
|
||||
/// ```
|
||||
pub struct WezirRole;
|
||||
|
||||
impl GetTiki for WezirRole {
|
||||
fn tiki() -> crate::Tiki {
|
||||
crate::Tiki::Wezir
|
||||
}
|
||||
}
|
||||
|
||||
/// Marker struct representing the `Parlementer` (Parliamentarian) role.
|
||||
///
|
||||
/// Use with `EnsureTiki` to require the caller holds the Parlementer Tiki:
|
||||
/// ```ignore
|
||||
/// type ParlementerOrigin = EnsureTiki<Runtime, ParlementerRole>;
|
||||
/// ```
|
||||
pub struct ParlementerRole;
|
||||
|
||||
impl GetTiki for ParlementerRole {
|
||||
fn tiki() -> crate::Tiki {
|
||||
crate::Tiki::Parlementer
|
||||
}
|
||||
}
|
||||
|
||||
// --- EnsureOrigin Implementation ---
|
||||
|
||||
/// An `EnsureOrigin` implementation that requires ownership of a specific Tiki.
|
||||
///
|
||||
/// This struct verifies that the origin is a signed account that currently
|
||||
/// holds the Tiki role specified by the `I: GetTiki` type parameter.
|
||||
///
|
||||
/// # Type Parameters
|
||||
///
|
||||
/// * `T` - The runtime configuration type implementing `Config`
|
||||
/// * `I` - A marker type implementing `GetTiki` to specify which Tiki role is required
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```ignore
|
||||
/// // Require the caller to hold the Serok Tiki
|
||||
/// type SerokOrigin = EnsureTiki<Runtime, SerokRole>;
|
||||
///
|
||||
/// // Use in a pallet's dispatchable
|
||||
/// #[pallet::call]
|
||||
/// impl<T: Config> Pallet<T> {
|
||||
/// pub fn privileged_action(origin: OriginFor<T>) -> DispatchResult {
|
||||
/// let who = T::SerokOrigin::ensure_origin(origin)?;
|
||||
/// // ... action requiring Serok authority
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub struct EnsureTiki<T, I>(PhantomData<(T, I)>);
|
||||
|
||||
impl<T, I> EnsureOrigin<T::RuntimeOrigin> for EnsureTiki<T, I>
|
||||
where
|
||||
T: Config,
|
||||
I: GetTiki,
|
||||
{
|
||||
type Success = T::AccountId;
|
||||
|
||||
fn try_origin(o: T::RuntimeOrigin) -> Result<Self::Success, T::RuntimeOrigin> {
|
||||
// First, verify the origin is a signed account
|
||||
let who = match ensure_signed(o.clone()) {
|
||||
Ok(account) => account,
|
||||
Err(_) => return Err(o),
|
||||
};
|
||||
|
||||
// Get the required Tiki role from the marker type
|
||||
let required_tiki = I::tiki();
|
||||
|
||||
// Check if the caller currently holds this Tiki
|
||||
match TikiPallet::<T>::tiki_holder(required_tiki) {
|
||||
Some(holder) if holder == who => Ok(who),
|
||||
_ => Err(o),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
fn try_successful_origin() -> Result<T::RuntimeOrigin, ()> {
|
||||
use codec::Decode;
|
||||
use pezsp_runtime::traits::TrailingZeroInput;
|
||||
|
||||
// Generate a deterministic zero-filled account for benchmarking
|
||||
let zero_account = T::AccountId::decode(&mut TrailingZeroInput::zeroes())
|
||||
.expect("infinite length input; no invalid inputs for type; qed");
|
||||
|
||||
Ok(T::RuntimeOrigin::from(pezframe_system::RawOrigin::Signed(zero_account)))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
impl<T, I> pezframe_support::traits::EnsureOriginWithArg<T::RuntimeOrigin, ()> for EnsureTiki<T, I>
|
||||
where
|
||||
T: Config,
|
||||
I: GetTiki,
|
||||
{
|
||||
type Success = T::AccountId;
|
||||
|
||||
fn try_origin(o: T::RuntimeOrigin, _: &()) -> Result<Self::Success, T::RuntimeOrigin> {
|
||||
<Self as EnsureOrigin<T::RuntimeOrigin>>::try_origin(o)
|
||||
}
|
||||
|
||||
fn try_successful_origin(_: &()) -> Result<T::RuntimeOrigin, ()> {
|
||||
use codec::Decode;
|
||||
use pezsp_runtime::traits::TrailingZeroInput;
|
||||
|
||||
// Generate a deterministic zero-filled account for benchmarking
|
||||
let zero_account = T::AccountId::decode(&mut TrailingZeroInput::zeroes())
|
||||
.expect("infinite length input; no invalid inputs for type; qed");
|
||||
|
||||
Ok(T::RuntimeOrigin::from(pezframe_system::RawOrigin::Signed(zero_account)))
|
||||
}
|
||||
}
|
||||
|
||||
// Convenience type aliases
|
||||
pub type EnsureSerok<T> = EnsureTiki<T, SerokRole>;
|
||||
pub type EnsureWezir<T> = EnsureTiki<T, WezirRole>;
|
||||
pub type EnsureParlementer<T> = EnsureTiki<T, ParlementerRole>;
|
||||
@@ -0,0 +1,864 @@
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
//! # Tiki (Role) Pallet
|
||||
//!
|
||||
//! A pallet for managing citizenship and role-based NFTs with automated and governance-driven
|
||||
//! assignment.
|
||||
//!
|
||||
//! ## Overview
|
||||
//!
|
||||
//! The Tiki pallet implements a comprehensive role management system using non-transferable NFTs
|
||||
//! to represent citizenship status and various roles within the ecosystem. Each role grants
|
||||
//! specific permissions, rights, and social standing.
|
||||
//!
|
||||
//! ## Core Concepts
|
||||
//!
|
||||
//! ### Citizenship NFT
|
||||
//! - Automatically minted upon KYC approval
|
||||
//! - Represents "Welati" (Citizen) status
|
||||
//! - Non-transferable and permanent
|
||||
//! - Required prerequisite for all other roles
|
||||
//!
|
||||
//! ### Role Types (Tiki)
|
||||
//!
|
||||
//! Roles are assigned through different mechanisms:
|
||||
//!
|
||||
//! 1. **Automatic** - System-assigned upon conditions (e.g., Citizenship after KYC)
|
||||
//! 2. **Appointed** - Admin-assigned governmental positions (e.g., Ministers, Judges)
|
||||
//! 3. **Elected** - Community-voted positions (e.g., Parliament members)
|
||||
//! 4. **Earned** - Achievement-based roles (e.g., Educator, Expert)
|
||||
//!
|
||||
//! ### Role Categories
|
||||
//!
|
||||
//! - **Governance**: Serok (President), SerokWeziran (Prime Minister), Ministers
|
||||
//! - **Judicial**: Dadger (Judge), Dozger (Prosecutor), Hiquqnas (Lawyer)
|
||||
//! - **Administrative**: Qeydkar (Registrar), Xezinedar (Treasurer), OperatorêTorê (Network
|
||||
//! Operator)
|
||||
//! - **Educational**: Mamoste (Teacher), Perwerdekar (Educator), Rewsenbîr (Intellectual)
|
||||
//! - **Economic**: Bazargan (Merchant), Navbeynkar (Mediator)
|
||||
//! - **Community**: Parlementer (Parliament Member), ModeratorêCivakê (Community Moderator)
|
||||
//! - **Expert**: Axa (Elder/Expert), Pêseng (Pioneer), Hekem (Wise), Sêwirmend (Counselor)
|
||||
//!
|
||||
//! ## NFT Implementation
|
||||
//!
|
||||
//! - Built on top of `pezpallet-nfts` for standard NFT functionality
|
||||
//! - All Tiki NFTs are non-transferable (soulbound)
|
||||
//! - Transfer attempts are blocked automatically via hooks
|
||||
//! - Each role is represented by a unique NFT item in the TikiCollectionId
|
||||
//!
|
||||
//! ## Role Management
|
||||
//!
|
||||
//! ### Granting Roles
|
||||
//! - Some roles are unique (only one holder at a time)
|
||||
//! - Users can hold multiple compatible roles
|
||||
//! - Maximum roles per user is configurable
|
||||
//! - Trust score requirements for certain roles
|
||||
//!
|
||||
//! ### Revoking Roles
|
||||
//! - Admin can revoke appointed roles
|
||||
//! - Automatic revocation on condition changes
|
||||
//! - Role history maintained for governance transparency
|
||||
//!
|
||||
//! ## Interface
|
||||
//!
|
||||
//! ### Extrinsics
|
||||
//!
|
||||
//! - `grant_tiki(who, tiki, assignment_type)` - Assign a role to a user (admin)
|
||||
//! - `revoke_tiki(who, tiki)` - Remove a role from a user (admin)
|
||||
//! - `force_mint_citizen_nft(who)` - Manually mint citizenship NFT (admin)
|
||||
//!
|
||||
//! ### Storage
|
||||
//!
|
||||
//! - `CitizenNft` - Mapping of accounts to their citizenship NFT IDs
|
||||
//! - `UserTikis` - List of roles held by each user
|
||||
//! - `TikiHolder` - Reverse mapping for unique roles to their holders
|
||||
//! - `NextItemId` - Counter for NFT item ID generation
|
||||
//!
|
||||
//! ### Hooks
|
||||
//!
|
||||
//! - `on_initialize` - Automatic citizenship NFT minting for newly approved KYC users
|
||||
//! - NFT transfer blocking for all Tiki NFTs
|
||||
//!
|
||||
//! ## Dependencies
|
||||
//!
|
||||
//! This pallet requires integration with:
|
||||
//! - `pezpallet-identity-kyc` - KYC status and approval notifications
|
||||
//! - `pezpallet-nfts` - Underlying NFT infrastructure
|
||||
//! - `pezpallet-trust` - Trust score verification for role eligibility
|
||||
//!
|
||||
//! ## Runtime Integration Example
|
||||
//!
|
||||
//! ```ignore
|
||||
//! impl pezpallet_tiki::Config for Runtime {
|
||||
//! type RuntimeEvent = RuntimeEvent;
|
||||
//! type AdminOrigin = EnsureRoot<AccountId>;
|
||||
//! type WeightInfo = pezpallet_tiki::weights::BizinikiwiWeight<Runtime>;
|
||||
//! type TikiCollectionId = ConstU32<1>; // Tiki collection ID
|
||||
//! type MaxTikisPerUser = ConstU32<20>; // Max 20 roles per user
|
||||
//! type Tiki = pezpallet_tiki::Tiki;
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
pub use pallet::*;
|
||||
|
||||
use alloc::{format, vec::Vec};
|
||||
use pezframe_support::pezpallet_prelude::{MaybeSerializeDeserialize, Parameter, RuntimeDebug};
|
||||
use scale_info::TypeInfo;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use pezsp_runtime::DispatchError;
|
||||
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
mod benchmarking;
|
||||
#[cfg(test)]
|
||||
mod mock;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
pub mod weights;
|
||||
pub use weights::*;
|
||||
pub mod ensure;
|
||||
pub mod migrations; // Storage migrations // For origin validation
|
||||
|
||||
#[pezframe_support::pallet]
|
||||
pub mod pallet {
|
||||
use super::*;
|
||||
use pezframe_support::pezpallet_prelude::*;
|
||||
use pezframe_system::pezpallet_prelude::*;
|
||||
use pezsp_runtime::traits::StaticLookup;
|
||||
|
||||
#[pallet::pallet]
|
||||
#[pallet::storage_version(migrations::STORAGE_VERSION)]
|
||||
pub struct Pallet<T>(_);
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config:
|
||||
pezframe_system::Config + pezpallet_nfts::Config<ItemId = u32> + pezpallet_identity_kyc::Config
|
||||
{
|
||||
type RuntimeEvent: From<Event<Self>> + IsType<<Self as pezframe_system::Config>::RuntimeEvent>;
|
||||
type AdminOrigin: EnsureOrigin<Self::RuntimeOrigin>;
|
||||
type WeightInfo: weights::WeightInfo;
|
||||
|
||||
/// Collection ID holding Tiki (Role) NFTs.
|
||||
#[pallet::constant]
|
||||
type TikiCollectionId: Get<Self::CollectionId>;
|
||||
|
||||
/// Technical upper limit for maximum number of Tikis (roles) a user can hold.
|
||||
#[pallet::constant]
|
||||
type MaxTikisPerUser: Get<u32>;
|
||||
|
||||
/// Tiki enum type to be used within the pallet.
|
||||
type Tiki: Parameter
|
||||
+ From<Tiki>
|
||||
+ Into<u32>
|
||||
+ MaxEncodedLen
|
||||
+ TypeInfo
|
||||
+ Copy
|
||||
+ MaybeSerializeDeserialize
|
||||
+ 'static;
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
DecodeWithMemTracking,
|
||||
Clone,
|
||||
Eq,
|
||||
PartialEq,
|
||||
RuntimeDebug,
|
||||
TypeInfo,
|
||||
MaxEncodedLen,
|
||||
Copy,
|
||||
)]
|
||||
pub enum RoleAssignmentType {
|
||||
/// Automatically assigned roles (like Welati after KYC)
|
||||
Automatic,
|
||||
/// Admin-assigned roles (like Wezir, Dadger)
|
||||
Appointed,
|
||||
/// Community-elected roles (like Parlementer) - assigned by pezpallet-voting
|
||||
Elected,
|
||||
/// Earned roles (Axa, roles obtained through exams)
|
||||
Earned,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
DecodeWithMemTracking,
|
||||
Clone,
|
||||
Eq,
|
||||
PartialEq,
|
||||
RuntimeDebug,
|
||||
TypeInfo,
|
||||
MaxEncodedLen,
|
||||
Copy,
|
||||
)]
|
||||
#[repr(u32)]
|
||||
pub enum Tiki {
|
||||
Welati,
|
||||
Parlementer,
|
||||
SerokiMeclise,
|
||||
Serok,
|
||||
Wezir,
|
||||
EndameDiwane,
|
||||
Dadger,
|
||||
Dozger,
|
||||
Hiquqnas,
|
||||
Noter,
|
||||
Xezinedar,
|
||||
Bacgir,
|
||||
GerinendeyeCavkaniye,
|
||||
OperatorêTorê,
|
||||
PisporêEwlehiyaSîber,
|
||||
GerinendeyeDaneye,
|
||||
Berdevk,
|
||||
Qeydkar,
|
||||
Balyoz,
|
||||
Navbeynkar,
|
||||
ParêzvaneÇandî,
|
||||
Mufetîs,
|
||||
KalîteKontrolker,
|
||||
Mela,
|
||||
Feqî,
|
||||
Perwerdekar,
|
||||
Rewsenbîr,
|
||||
RêveberêProjeyê,
|
||||
SerokêKomele,
|
||||
ModeratorêCivakê,
|
||||
Axa,
|
||||
Pêseng,
|
||||
Sêwirmend,
|
||||
Hekem,
|
||||
Mamoste,
|
||||
// Newly added economic roles
|
||||
Bazargan,
|
||||
// Government roles
|
||||
SerokWeziran,
|
||||
WezireDarayiye,
|
||||
WezireParez,
|
||||
WezireDad,
|
||||
WezireBelaw,
|
||||
WezireTend,
|
||||
WezireAva,
|
||||
WezireCand,
|
||||
}
|
||||
|
||||
impl From<Tiki> for u32 {
|
||||
fn from(val: Tiki) -> Self {
|
||||
val as u32
|
||||
}
|
||||
}
|
||||
|
||||
/// Holds citizenship NFT ID for each user
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn citizen_nft)]
|
||||
pub type CitizenNft<T: Config> =
|
||||
StorageMap<_, Blake2_128Concat, T::AccountId, u32, OptionQuery>;
|
||||
|
||||
/// List of Tikis (roles) owned by each user
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn user_tikis)]
|
||||
pub type UserTikis<T: Config> = StorageMap<
|
||||
_,
|
||||
Blake2_128Concat,
|
||||
T::AccountId,
|
||||
BoundedVec<Tiki, T::MaxTikisPerUser>,
|
||||
ValueQuery,
|
||||
>;
|
||||
|
||||
/// Shows which user a specific Tiki belongs to (for unique roles)
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn tiki_holder)]
|
||||
pub type TikiHolder<T: Config> =
|
||||
StorageMap<_, Blake2_128Concat, Tiki, T::AccountId, OptionQuery>;
|
||||
|
||||
/// Item ID to be used for next NFT
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn next_item_id)]
|
||||
pub type NextItemId<T: Config> = StorageValue<_, u32, ValueQuery>;
|
||||
|
||||
#[pallet::error]
|
||||
pub enum Error<T> {
|
||||
/// Role already belongs to someone else
|
||||
RoleAlreadyTaken,
|
||||
/// Specified person is not the holder of this role
|
||||
NotTheHolder,
|
||||
/// Role not assigned
|
||||
RoleNotAssigned,
|
||||
/// A user has reached maximum role count
|
||||
ExceedsMaxRolesPerUser,
|
||||
/// KYC not completed
|
||||
KycNotCompleted,
|
||||
/// Citizenship NFT already exists
|
||||
CitizenNftAlreadyExists,
|
||||
/// Citizenship NFT not found
|
||||
CitizenNftNotFound,
|
||||
/// User already has this role
|
||||
UserAlreadyHasRole,
|
||||
/// Insufficient Trust Score
|
||||
InsufficientTrustScore,
|
||||
/// This role type cannot be assigned with this method
|
||||
InvalidRoleAssignmentMethod,
|
||||
}
|
||||
|
||||
#[pallet::event]
|
||||
#[pallet::generate_deposit(pub(super) fn deposit_event)]
|
||||
pub enum Event<T: Config> {
|
||||
/// New citizenship NFT minted
|
||||
CitizenNftMinted { who: T::AccountId, nft_id: u32 },
|
||||
/// New Tiki (role) granted
|
||||
TikiGranted { who: T::AccountId, tiki: Tiki },
|
||||
/// Tiki (role) revoked
|
||||
TikiRevoked { who: T::AccountId, tiki: Tiki },
|
||||
/// NFT transfer blocked
|
||||
TransferBlocked {
|
||||
collection_id: T::CollectionId,
|
||||
item_id: u32,
|
||||
from: T::AccountId,
|
||||
to: T::AccountId,
|
||||
},
|
||||
}
|
||||
|
||||
#[pallet::hooks]
|
||||
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
|
||||
fn on_initialize(_block_number: BlockNumberFor<T>) -> Weight {
|
||||
// Check newly KYC-approved users and mint citizenship NFT
|
||||
Self::check_and_mint_citizen_nfts();
|
||||
|
||||
T::DbWeight::get().reads_writes(10, 5)
|
||||
}
|
||||
}
|
||||
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {
|
||||
/// Admin tarafından belirli bir kullanıcıya Tiki (rol) verme
|
||||
#[pallet::call_index(0)]
|
||||
#[pallet::weight(<T as crate::pallet::Config>::WeightInfo::grant_tiki())]
|
||||
pub fn grant_tiki(
|
||||
origin: OriginFor<T>,
|
||||
dest: <T::Lookup as StaticLookup>::Source,
|
||||
tiki: Tiki,
|
||||
) -> DispatchResult {
|
||||
T::AdminOrigin::ensure_origin(origin)?;
|
||||
let dest_account = T::Lookup::lookup(dest)?;
|
||||
|
||||
// Check if the role can be appointed
|
||||
ensure!(
|
||||
Self::can_grant_role_type(&tiki, &RoleAssignmentType::Appointed),
|
||||
Error::<T>::InvalidRoleAssignmentMethod
|
||||
);
|
||||
|
||||
Self::internal_grant_role(&dest_account, tiki)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Admin tarafından belirli bir kullanıcıdan Tiki (rol) alma
|
||||
#[pallet::call_index(1)]
|
||||
#[pallet::weight(<T as crate::pallet::Config>::WeightInfo::revoke_tiki())]
|
||||
pub fn revoke_tiki(
|
||||
origin: OriginFor<T>,
|
||||
target: <T::Lookup as StaticLookup>::Source,
|
||||
tiki: Tiki,
|
||||
) -> DispatchResult {
|
||||
T::AdminOrigin::ensure_origin(origin)?;
|
||||
let target_account = T::Lookup::lookup(target)?;
|
||||
|
||||
Self::internal_revoke_role(&target_account, tiki)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Manually mint citizenship NFT (for testing/emergency)
|
||||
#[pallet::call_index(2)]
|
||||
#[pallet::weight(<T as crate::pallet::Config>::WeightInfo::grant_tiki())]
|
||||
pub fn force_mint_citizen_nft(
|
||||
origin: OriginFor<T>,
|
||||
dest: <T::Lookup as StaticLookup>::Source,
|
||||
) -> DispatchResult {
|
||||
T::AdminOrigin::ensure_origin(origin)?;
|
||||
let dest_account = T::Lookup::lookup(dest)?;
|
||||
|
||||
Self::mint_citizen_nft_for_user(&dest_account)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Grant role through election system (called from pezpallet-voting)
|
||||
#[pallet::call_index(3)]
|
||||
#[pallet::weight(<T as crate::pallet::Config>::WeightInfo::grant_tiki())]
|
||||
pub fn grant_elected_role(
|
||||
origin: OriginFor<T>,
|
||||
dest: <T::Lookup as StaticLookup>::Source,
|
||||
tiki: Tiki,
|
||||
) -> DispatchResult {
|
||||
T::AdminOrigin::ensure_origin(origin)?; // pezpallet-voting will call with Root origin
|
||||
let dest_account = T::Lookup::lookup(dest)?;
|
||||
|
||||
// Check if the role can be granted through election
|
||||
ensure!(
|
||||
Self::can_grant_role_type(&tiki, &RoleAssignmentType::Elected),
|
||||
Error::<T>::InvalidRoleAssignmentMethod
|
||||
);
|
||||
|
||||
Self::internal_grant_role(&dest_account, tiki)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Grant role through exam/test system
|
||||
#[pallet::call_index(4)]
|
||||
#[pallet::weight(<T as crate::pallet::Config>::WeightInfo::grant_tiki())]
|
||||
pub fn grant_earned_role(
|
||||
origin: OriginFor<T>,
|
||||
dest: <T::Lookup as StaticLookup>::Source,
|
||||
tiki: Tiki,
|
||||
) -> DispatchResult {
|
||||
T::AdminOrigin::ensure_origin(origin)?; // For now admin, later exam pallet
|
||||
let dest_account = T::Lookup::lookup(dest)?;
|
||||
|
||||
// Check if the role can be earned
|
||||
ensure!(
|
||||
Self::can_grant_role_type(&tiki, &RoleAssignmentType::Earned),
|
||||
Error::<T>::InvalidRoleAssignmentMethod
|
||||
);
|
||||
|
||||
Self::internal_grant_role(&dest_account, tiki)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Apply for citizenship after KYC completion
|
||||
#[pallet::call_index(5)]
|
||||
#[pallet::weight(<T as crate::pallet::Config>::WeightInfo::grant_tiki())]
|
||||
pub fn apply_for_citizenship(origin: OriginFor<T>) -> DispatchResult {
|
||||
let who = ensure_signed(origin)?;
|
||||
|
||||
// Check if user's KYC is approved
|
||||
let kyc_status = pezpallet_identity_kyc::Pallet::<T>::kyc_status_of(&who);
|
||||
ensure!(
|
||||
kyc_status == pezpallet_identity_kyc::types::KycLevel::Approved,
|
||||
Error::<T>::KycNotCompleted
|
||||
);
|
||||
|
||||
// Mint citizenship NFT
|
||||
Self::mint_citizen_nft_for_user(&who)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Check NFT transfer for transfer blocking system
|
||||
#[pallet::call_index(6)]
|
||||
#[pallet::weight(<T as crate::pallet::Config>::WeightInfo::grant_tiki())]
|
||||
pub fn check_transfer_permission(
|
||||
_origin: OriginFor<T>,
|
||||
collection_id: T::CollectionId,
|
||||
item_id: u32,
|
||||
from: T::AccountId,
|
||||
to: T::AccountId,
|
||||
) -> DispatchResult {
|
||||
// Tiki NFT koleksiyonu ise transfer'e izin verme
|
||||
if collection_id == T::TikiCollectionId::get() {
|
||||
Self::deposit_event(Event::TransferBlocked { collection_id, item_id, from, to });
|
||||
return Err(DispatchError::Other("Citizen NFTs are non-transferable"));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// Pallet's helper functions
|
||||
impl<T: Config> Pallet<T> {
|
||||
/// Checks newly KYC-completed users and mints citizenship NFT
|
||||
fn check_and_mint_citizen_nfts() {
|
||||
// Check all approved users in KYC pallet
|
||||
for (account, kyc_status) in pezpallet_identity_kyc::KycStatuses::<T>::iter() {
|
||||
// Check if KYC is approved
|
||||
if kyc_status == pezpallet_identity_kyc::types::KycLevel::Approved {
|
||||
// Check if citizenship NFT exists
|
||||
if Self::citizen_nft(&account).is_none() {
|
||||
// Mint NFT (log error but continue on failure)
|
||||
if Self::mint_citizen_nft_for_user(&account).is_err() {
|
||||
log::warn!("Failed to mint citizen NFT for account: {:?}", account);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Mints citizenship NFT for specific user
|
||||
pub fn mint_citizen_nft_for_user(user: &T::AccountId) -> DispatchResult {
|
||||
// Check if NFT already exists
|
||||
ensure!(Self::citizen_nft(user).is_none(), Error::<T>::CitizenNftAlreadyExists);
|
||||
|
||||
let collection_id = T::TikiCollectionId::get();
|
||||
let next_id_u32 = Self::next_item_id();
|
||||
|
||||
// Mint the NFT - use force_mint in benchmarks to bypass balance/origin requirements
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
pezpallet_nfts::Pallet::<T>::force_mint(
|
||||
T::RuntimeOrigin::from(pezframe_system::RawOrigin::Root),
|
||||
collection_id,
|
||||
next_id_u32,
|
||||
T::Lookup::unlookup(user.clone()),
|
||||
Default::default(),
|
||||
)?;
|
||||
|
||||
#[cfg(not(feature = "runtime-benchmarks"))]
|
||||
pezpallet_nfts::Pallet::<T>::force_mint(
|
||||
T::RuntimeOrigin::from(pezframe_system::RawOrigin::Root),
|
||||
collection_id,
|
||||
next_id_u32,
|
||||
T::Lookup::unlookup(user.clone()),
|
||||
Default::default(),
|
||||
)?;
|
||||
|
||||
// Make NFT non-transferable
|
||||
Self::lock_nft_transfer(&collection_id, &next_id_u32)?;
|
||||
|
||||
// Update storage
|
||||
CitizenNft::<T>::insert(user, next_id_u32);
|
||||
NextItemId::<T>::put(next_id_u32.saturating_add(1));
|
||||
|
||||
// Automatically add Welati role
|
||||
UserTikis::<T>::mutate(user, |tikis| {
|
||||
let _ = tikis.try_push(Tiki::Welati);
|
||||
});
|
||||
|
||||
// Set NFT metadata
|
||||
Self::update_nft_metadata(user)?;
|
||||
|
||||
Self::deposit_event(Event::CitizenNftMinted { who: user.clone(), nft_id: next_id_u32 });
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Internal role granting function (to avoid code duplication)
|
||||
pub fn internal_grant_role(dest_account: &T::AccountId, tiki: Tiki) -> DispatchResult {
|
||||
// Check if citizenship NFT exists
|
||||
ensure!(Self::citizen_nft(dest_account).is_some(), Error::<T>::CitizenNftNotFound);
|
||||
|
||||
// If this role is unique (can belong to only one person), check
|
||||
if Self::is_unique_role(&tiki) {
|
||||
ensure!(Self::tiki_holder(tiki).is_none(), Error::<T>::RoleAlreadyTaken);
|
||||
}
|
||||
|
||||
// Check if user already has this role
|
||||
let user_tikis = Self::user_tikis(dest_account);
|
||||
ensure!(!user_tikis.contains(&tiki), Error::<T>::UserAlreadyHasRole);
|
||||
|
||||
// Add to user's Tiki list
|
||||
UserTikis::<T>::try_mutate(dest_account, |tikis| {
|
||||
tikis.try_push(tiki).map_err(|_| Error::<T>::ExceedsMaxRolesPerUser)
|
||||
})?;
|
||||
|
||||
// If unique role, also add to TikiHolder
|
||||
if Self::is_unique_role(&tiki) {
|
||||
TikiHolder::<T>::insert(tiki, dest_account);
|
||||
}
|
||||
|
||||
// Update NFT metadata
|
||||
Self::update_nft_metadata(dest_account)?;
|
||||
|
||||
Self::deposit_event(Event::TikiGranted { who: dest_account.clone(), tiki });
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Internal role revocation function
|
||||
pub fn internal_revoke_role(target_account: &T::AccountId, tiki: Tiki) -> DispatchResult {
|
||||
// Check if user has this role
|
||||
let user_tikis = Self::user_tikis(target_account);
|
||||
let _position =
|
||||
user_tikis.iter().position(|&r| r == tiki).ok_or(Error::<T>::RoleNotAssigned)?;
|
||||
|
||||
// Welati role cannot be removed
|
||||
ensure!(tiki != Tiki::Welati, Error::<T>::RoleNotAssigned);
|
||||
|
||||
// Remove from user's Tiki list
|
||||
UserTikis::<T>::mutate(target_account, |tikis| {
|
||||
if let Some(pos) = tikis.iter().position(|&r| r == tiki) {
|
||||
tikis.swap_remove(pos);
|
||||
}
|
||||
});
|
||||
|
||||
// If unique role, also remove from TikiHolder
|
||||
if Self::is_unique_role(&tiki) {
|
||||
TikiHolder::<T>::remove(tiki);
|
||||
}
|
||||
|
||||
// Update NFT metadata
|
||||
Self::update_nft_metadata(target_account)?;
|
||||
|
||||
Self::deposit_event(Event::TikiRevoked { who: target_account.clone(), tiki });
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Makes NFT non-transferable
|
||||
fn lock_nft_transfer(collection_id: &T::CollectionId, item_id: &u32) -> DispatchResult {
|
||||
// Mark NFT with lock attribute - use force_set_attribute in benchmarks to bypass
|
||||
// deposits
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
let _ = pezpallet_nfts::Pallet::<T>::force_set_attribute(
|
||||
T::RuntimeOrigin::from(pezframe_system::RawOrigin::Root),
|
||||
None,
|
||||
*collection_id,
|
||||
Some(*item_id),
|
||||
pezpallet_nfts::AttributeNamespace::Pallet,
|
||||
b"locked"
|
||||
.to_vec()
|
||||
.try_into()
|
||||
.map_err(|_| DispatchError::Other("Key too long"))?,
|
||||
b"true"
|
||||
.to_vec()
|
||||
.try_into()
|
||||
.map_err(|_| DispatchError::Other("Value too long"))?,
|
||||
);
|
||||
|
||||
#[cfg(not(feature = "runtime-benchmarks"))]
|
||||
let _ = pezpallet_nfts::Pallet::<T>::set_attribute(
|
||||
T::RuntimeOrigin::from(pezframe_system::RawOrigin::Root),
|
||||
*collection_id,
|
||||
Some(*item_id),
|
||||
pezpallet_nfts::AttributeNamespace::Pallet,
|
||||
b"locked"
|
||||
.to_vec()
|
||||
.try_into()
|
||||
.map_err(|_| DispatchError::Other("Key too long"))?,
|
||||
b"true"
|
||||
.to_vec()
|
||||
.try_into()
|
||||
.map_err(|_| DispatchError::Other("Value too long"))?,
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Updates NFT metadata based on user's roles
|
||||
fn update_nft_metadata(user: &T::AccountId) -> DispatchResult {
|
||||
let nft_id_u32 = Self::citizen_nft(user).ok_or(Error::<T>::CitizenNftNotFound)?;
|
||||
let collection_id = T::TikiCollectionId::get();
|
||||
let user_tikis = Self::user_tikis(user);
|
||||
|
||||
let total_score = Self::get_tiki_score(user);
|
||||
|
||||
// Short metadata - only basic information
|
||||
let metadata = format!(
|
||||
r#"{{"citizen":true,"roles":{},"score":{}}}"#,
|
||||
user_tikis.len(),
|
||||
total_score
|
||||
);
|
||||
|
||||
// Set metadata - log error but don't crash
|
||||
if pezpallet_nfts::Pallet::<T>::set_metadata(
|
||||
T::RuntimeOrigin::from(pezframe_system::RawOrigin::Root),
|
||||
collection_id,
|
||||
nft_id_u32,
|
||||
metadata
|
||||
.as_bytes()
|
||||
.to_vec()
|
||||
.try_into()
|
||||
.map_err(|_| DispatchError::Other("Metadata too long"))?,
|
||||
)
|
||||
.is_err()
|
||||
{
|
||||
log::warn!("Failed to set metadata for NFT: {:?}", nft_id_u32);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Checks if a specific role is unique (can belong to only one person)
|
||||
pub fn is_unique_role(tiki: &Tiki) -> bool {
|
||||
matches!(tiki, Tiki::Serok | Tiki::SerokiMeclise | Tiki::Xezinedar | Tiki::Balyoz)
|
||||
}
|
||||
|
||||
/// Returns the assignment type of a specific role
|
||||
pub fn get_role_assignment_type(tiki: &Tiki) -> RoleAssignmentType {
|
||||
match tiki {
|
||||
// Automatic roles
|
||||
Tiki::Welati => RoleAssignmentType::Automatic,
|
||||
|
||||
// Elected roles
|
||||
Tiki::Parlementer | Tiki::SerokiMeclise | Tiki::Serok =>
|
||||
RoleAssignmentType::Elected,
|
||||
|
||||
// Earned roles (automatically given by pezpallet-referral)
|
||||
Tiki::Axa |
|
||||
Tiki::Mamoste |
|
||||
Tiki::Rewsenbîr |
|
||||
Tiki::SerokêKomele |
|
||||
Tiki::ModeratorêCivakê => RoleAssignmentType::Earned,
|
||||
|
||||
// Appointed roles (default)
|
||||
_ => RoleAssignmentType::Appointed,
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks the granting method of a specific role
|
||||
pub fn can_grant_role_type(tiki: &Tiki, assignment_type: &RoleAssignmentType) -> bool {
|
||||
let required_type = Self::get_role_assignment_type(tiki);
|
||||
match (&required_type, assignment_type) {
|
||||
// Automatic roles can only be given by the system
|
||||
(RoleAssignmentType::Automatic, RoleAssignmentType::Automatic) => true,
|
||||
// Appointed roles can be given by admin
|
||||
(RoleAssignmentType::Appointed, RoleAssignmentType::Appointed) => true,
|
||||
// Elected roles can be given by election system
|
||||
(RoleAssignmentType::Elected, RoleAssignmentType::Elected) => true,
|
||||
// Earned roles can be given by exam/test system
|
||||
(RoleAssignmentType::Earned, RoleAssignmentType::Earned) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// KYC sonrası otomatik Welati rolü verme
|
||||
pub fn auto_grant_citizenship(account: &T::AccountId) -> DispatchResult {
|
||||
// KYC kontrolü
|
||||
let kyc_status = pezpallet_identity_kyc::Pallet::<T>::kyc_status_of(account);
|
||||
if kyc_status == pezpallet_identity_kyc::types::KycLevel::Approved {
|
||||
// Vatandaşlık NFT'si yoksa bas
|
||||
if Self::citizen_nft(account).is_none() {
|
||||
Self::mint_citizen_nft_for_user(account)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Kullanıcının belirli bir Tiki'ye sahip olup olmadığını kontrol eder
|
||||
pub fn has_tiki(who: &T::AccountId, tiki: &Tiki) -> bool {
|
||||
Self::user_tikis(who).contains(tiki)
|
||||
}
|
||||
|
||||
/// Kullanıcının vatandaş olup olmadığını kontrol eder
|
||||
pub fn is_citizen(who: &T::AccountId) -> bool {
|
||||
Self::citizen_nft(who).is_some()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Diğer paletlerin, bu paletten Tiki puanlarını sorgulaması için kullanılacak trait
|
||||
pub trait TikiScoreProvider<AccountId> {
|
||||
fn get_tiki_score(who: &AccountId) -> u32;
|
||||
}
|
||||
|
||||
/// Diğer paletlerin, Tiki sahipliğini sorgulaması için kullanılacak trait
|
||||
pub trait TikiProvider<AccountId> {
|
||||
fn has_tiki(who: &AccountId, tiki: &Tiki) -> bool;
|
||||
fn get_user_tikis(who: &AccountId) -> Vec<Tiki>;
|
||||
fn is_citizen(who: &AccountId) -> bool;
|
||||
}
|
||||
|
||||
/// Trait implementasyonları
|
||||
impl<T: Config> TikiScoreProvider<T::AccountId> for Pallet<T> {
|
||||
fn get_tiki_score(who: &T::AccountId) -> u32 {
|
||||
let tikis = Self::user_tikis(who);
|
||||
tikis.iter().map(Self::get_bonus_for_tiki).sum()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> TikiProvider<T::AccountId> for Pallet<T> {
|
||||
fn has_tiki(who: &T::AccountId, tiki: &Tiki) -> bool {
|
||||
Self::has_tiki(who, tiki)
|
||||
}
|
||||
|
||||
fn get_user_tikis(who: &T::AccountId) -> Vec<Tiki> {
|
||||
Self::user_tikis(who).into_inner()
|
||||
}
|
||||
|
||||
fn is_citizen(who: &T::AccountId) -> bool {
|
||||
Self::is_citizen(who)
|
||||
}
|
||||
}
|
||||
|
||||
// Puanlama mantığını ayrı bir impl bloğunda tutarak kodu daha düzenli hale getiriyoruz.
|
||||
impl<T: Config> Pallet<T> {
|
||||
/// Belirli bir Tiki'nin Trust Puanı'na olan katkısını döndürür.
|
||||
pub fn get_bonus_for_tiki(tiki: &Tiki) -> u32 {
|
||||
match tiki {
|
||||
// Anayasa v5.0'da Belirlenen Özel Puanlar
|
||||
Tiki::Axa => 250,
|
||||
Tiki::RêveberêProjeyê => 250,
|
||||
Tiki::ModeratorêCivakê => 200,
|
||||
Tiki::SerokêKomele => 100,
|
||||
Tiki::Mela => 50,
|
||||
Tiki::Feqî => 50,
|
||||
|
||||
// Hiyerarşik Devlet Puanları
|
||||
// Yargı
|
||||
Tiki::EndameDiwane => 175,
|
||||
Tiki::Dadger => 150,
|
||||
Tiki::Dozger => 120,
|
||||
Tiki::Hiquqnas => 75,
|
||||
// Yürütme
|
||||
Tiki::Serok => 200,
|
||||
Tiki::Wezir => 100,
|
||||
Tiki::SerokWeziran => 125,
|
||||
Tiki::WezireDarayiye => 100,
|
||||
Tiki::WezireParez => 100,
|
||||
Tiki::WezireDad => 100,
|
||||
Tiki::WezireBelaw => 100,
|
||||
Tiki::WezireTend => 100,
|
||||
Tiki::WezireAva => 100,
|
||||
Tiki::WezireCand => 100,
|
||||
|
||||
// Yasama
|
||||
Tiki::SerokiMeclise => 150,
|
||||
Tiki::Parlementer => 100,
|
||||
|
||||
// Atanmış Üst Düzey Memurlar
|
||||
Tiki::Xezinedar => 100,
|
||||
Tiki::PisporêEwlehiyaSîber => 100,
|
||||
Tiki::Mufetîs => 90,
|
||||
Tiki::Balyoz => 80,
|
||||
Tiki::Berdevk => 70,
|
||||
|
||||
// Diğer Memurlar ve Uzmanlar
|
||||
Tiki::Mamoste => 70,
|
||||
Tiki::OperatorêTorê => 60,
|
||||
Tiki::Noter => 50,
|
||||
Tiki::Bacgir => 50,
|
||||
Tiki::Perwerdekar => 40,
|
||||
Tiki::Rewsenbîr => 40,
|
||||
Tiki::GerinendeyeCavkaniye => 40,
|
||||
Tiki::GerinendeyeDaneye => 40,
|
||||
Tiki::KalîteKontrolker => 30,
|
||||
Tiki::Navbeynkar => 30,
|
||||
Tiki::Hekem => 30,
|
||||
Tiki::Qeydkar => 25,
|
||||
Tiki::ParêzvaneÇandî => 25,
|
||||
Tiki::Sêwirmend => 20,
|
||||
Tiki::Bazargan => 60, // Yeni eklenen ekonomik rol
|
||||
|
||||
// Temel Vatandaşlık ve Diğerleri
|
||||
Tiki::Welati => 10,
|
||||
// Yukarıdaki listede olmayan diğer tüm roller 5 puan alır.
|
||||
_ => 5,
|
||||
}
|
||||
}
|
||||
}
|
||||
// CitizenNftProvider trait implementation for pezpallet-identity-kyc integration
|
||||
impl<T: Config> pezpallet_identity_kyc::types::CitizenNftProvider<T::AccountId> for Pallet<T> {
|
||||
fn mint_citizen_nft(who: &T::AccountId) -> pezsp_runtime::DispatchResult {
|
||||
Self::mint_citizen_nft_for_user(who)
|
||||
}
|
||||
|
||||
fn mint_citizen_nft_confirmed(who: &T::AccountId) -> pezsp_runtime::DispatchResult {
|
||||
// For self-confirmation, we use the same mint function with force_mint
|
||||
Self::mint_citizen_nft_for_user(who)
|
||||
}
|
||||
|
||||
fn burn_citizen_nft(who: &T::AccountId) -> pezsp_runtime::DispatchResult {
|
||||
use pezframe_support::traits::Get;
|
||||
// Get the citizen NFT item ID
|
||||
let item_id = Self::citizen_nft(who).ok_or(Error::<T>::CitizenNftNotFound)?;
|
||||
let collection_id = T::TikiCollectionId::get();
|
||||
|
||||
// Burn the NFT using pezpallet_nfts burn function
|
||||
pezpallet_nfts::Pallet::<T>::burn(
|
||||
T::RuntimeOrigin::from(pezframe_system::RawOrigin::Signed(who.clone())),
|
||||
collection_id,
|
||||
item_id,
|
||||
)?;
|
||||
|
||||
// Remove from our storage
|
||||
CitizenNft::<T>::remove(who);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
//! Storage migrations for pezpallet-tiki
|
||||
|
||||
use super::*;
|
||||
use pezframe_support::{
|
||||
traits::{Get, GetStorageVersion, OnRuntimeUpgrade, StorageVersion},
|
||||
weights::Weight,
|
||||
};
|
||||
use pezsp_std::marker::PhantomData;
|
||||
|
||||
/// Current storage version
|
||||
pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
|
||||
|
||||
/// Migration from v0 to v1
|
||||
/// This is a template migration that can be customized based on actual storage changes
|
||||
pub mod v1 {
|
||||
use super::*;
|
||||
|
||||
pub struct MigrateToV1<T>(PhantomData<T>);
|
||||
|
||||
impl<T: Config> OnRuntimeUpgrade for MigrateToV1<T> {
|
||||
fn on_runtime_upgrade() -> Weight {
|
||||
let current = Pallet::<T>::on_chain_storage_version();
|
||||
|
||||
log::info!(
|
||||
"🔄 Running migration for pezpallet-tiki from {:?} to {:?}",
|
||||
current,
|
||||
STORAGE_VERSION
|
||||
);
|
||||
|
||||
if current == StorageVersion::new(0) {
|
||||
// Perform migration logic here
|
||||
// Example: Iterate over storage and transform data
|
||||
|
||||
let migrated = 0u64;
|
||||
let mut weight = Weight::zero();
|
||||
|
||||
// Example: Migrate CitizenNft storage if format changed
|
||||
// for (account, nft_id) in CitizenNft::<T>::iter() {
|
||||
// // Transform data if needed
|
||||
// migrated += 1;
|
||||
// }
|
||||
|
||||
// Update storage version
|
||||
STORAGE_VERSION.put::<Pallet<T>>();
|
||||
|
||||
log::info!("✅ Migrated {} entries in pezpallet-tiki", migrated);
|
||||
|
||||
// Return weight used
|
||||
// Reads: migrated items + version read
|
||||
// Writes: migrated items + version write
|
||||
weight = weight
|
||||
.saturating_add(T::DbWeight::get().reads_writes(migrated + 1, migrated + 1));
|
||||
|
||||
weight
|
||||
} else {
|
||||
log::info!("👌 pezpallet-tiki migration not needed, current version is {:?}", current);
|
||||
T::DbWeight::get().reads(1)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
fn pre_upgrade() -> Result<pezsp_std::vec::Vec<u8>, pezsp_runtime::TryRuntimeError> {
|
||||
use codec::Encode;
|
||||
|
||||
let current = Pallet::<T>::on_chain_storage_version();
|
||||
|
||||
log::info!("🔍 Pre-upgrade check for pezpallet-tiki");
|
||||
log::info!(" Current version: {:?}", current);
|
||||
|
||||
// Encode current storage counts for verification
|
||||
let citizen_count = CitizenNft::<T>::iter().count() as u32;
|
||||
let user_tikis_count = UserTikis::<T>::iter().count() as u32;
|
||||
let tiki_holder_count = TikiHolder::<T>::iter().count() as u32;
|
||||
|
||||
log::info!(" CitizenNft entries: {}", citizen_count);
|
||||
log::info!(" UserTikis entries: {}", user_tikis_count);
|
||||
log::info!(" TikiHolder entries: {}", tiki_holder_count);
|
||||
|
||||
Ok((citizen_count, user_tikis_count, tiki_holder_count).encode())
|
||||
}
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
fn post_upgrade(state: pezsp_std::vec::Vec<u8>) -> Result<(), pezsp_runtime::TryRuntimeError> {
|
||||
use codec::Decode;
|
||||
|
||||
let (pre_citizen_count, pre_user_tikis_count, pre_tiki_holder_count): (u32, u32, u32) =
|
||||
Decode::decode(&mut &state[..]).map_err(|_| "Failed to decode pre-upgrade state")?;
|
||||
|
||||
log::info!("🔍 Post-upgrade check for pezpallet-tiki");
|
||||
|
||||
// Verify storage version was updated
|
||||
let current_version = Pallet::<T>::on_chain_storage_version();
|
||||
assert_eq!(current_version, STORAGE_VERSION, "Storage version not updated correctly");
|
||||
log::info!("✅ Storage version updated to {:?}", current_version);
|
||||
|
||||
// Verify storage counts (should be same or more, never less)
|
||||
let post_citizen_count = CitizenNft::<T>::iter().count() as u32;
|
||||
let post_user_tikis_count = UserTikis::<T>::iter().count() as u32;
|
||||
let post_tiki_holder_count = TikiHolder::<T>::iter().count() as u32;
|
||||
|
||||
log::info!(" CitizenNft entries: {} -> {}", pre_citizen_count, post_citizen_count);
|
||||
log::info!(
|
||||
" UserTikis entries: {} -> {}",
|
||||
pre_user_tikis_count,
|
||||
post_user_tikis_count
|
||||
);
|
||||
log::info!(
|
||||
" TikiHolder entries: {} -> {}",
|
||||
pre_tiki_holder_count,
|
||||
post_tiki_holder_count
|
||||
);
|
||||
|
||||
assert!(
|
||||
post_citizen_count >= pre_citizen_count,
|
||||
"CitizenNft entries decreased during migration"
|
||||
);
|
||||
assert!(
|
||||
post_user_tikis_count >= pre_user_tikis_count,
|
||||
"UserTikis entries decreased during migration"
|
||||
);
|
||||
assert!(
|
||||
post_tiki_holder_count >= pre_tiki_holder_count,
|
||||
"TikiHolder entries decreased during migration"
|
||||
);
|
||||
|
||||
log::info!("✅ Post-upgrade checks passed for pezpallet-tiki");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Example migration for future version changes
|
||||
/// This demonstrates how to handle storage item renames or format changes
|
||||
pub mod v2 {
|
||||
use super::*;
|
||||
|
||||
/// Example: Migration when storage format changes
|
||||
pub struct MigrateToV2<T>(PhantomData<T>);
|
||||
|
||||
impl<T: Config> OnRuntimeUpgrade for MigrateToV2<T> {
|
||||
fn on_runtime_upgrade() -> Weight {
|
||||
let current = Pallet::<T>::on_chain_storage_version();
|
||||
|
||||
if current < StorageVersion::new(2) {
|
||||
log::info!("🔄 Running migration for pezpallet-tiki to v2");
|
||||
|
||||
// Example migration logic
|
||||
// 1. Create new storage with modified format
|
||||
// 2. Migrate data from old storage to new
|
||||
// 3. Remove old storage
|
||||
// 4. Update version
|
||||
|
||||
// For now, this is just a template
|
||||
STORAGE_VERSION.put::<Pallet<T>>();
|
||||
|
||||
log::info!("✅ Completed migration to pezpallet-tiki v2");
|
||||
|
||||
T::DbWeight::get().reads_writes(1, 1)
|
||||
} else {
|
||||
log::info!("👌 pezpallet-tiki v2 migration not needed");
|
||||
T::DbWeight::get().reads(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::mock::{new_test_ext, Test};
|
||||
use pezframe_support::traits::OnRuntimeUpgrade;
|
||||
|
||||
#[test]
|
||||
fn test_migration_v1() {
|
||||
new_test_ext().execute_with(|| {
|
||||
// Set initial storage version to 0
|
||||
StorageVersion::new(0).put::<Pallet<Test>>();
|
||||
|
||||
// Run migration
|
||||
let weight = v1::MigrateToV1::<Test>::on_runtime_upgrade();
|
||||
|
||||
// Verify version was updated
|
||||
assert_eq!(Pallet::<Test>::on_chain_storage_version(), STORAGE_VERSION);
|
||||
|
||||
// Verify weight is non-zero
|
||||
assert!(weight != Weight::zero());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_migration_idempotent() {
|
||||
new_test_ext().execute_with(|| {
|
||||
// Set current version
|
||||
STORAGE_VERSION.put::<Pallet<Test>>();
|
||||
|
||||
// Run migration again
|
||||
let weight = v1::MigrateToV1::<Test>::on_runtime_upgrade();
|
||||
|
||||
// Should be a no-op
|
||||
assert_eq!(weight, pezframe_support::weights::constants::RocksDbWeight::get().reads(1));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,290 @@
|
||||
use crate as pezpallet_tiki;
|
||||
use crate::Tiki as TikiEnum;
|
||||
use pezframe_support::{
|
||||
assert_ok, construct_runtime, parameter_types,
|
||||
traits::{AsEnsureOriginWithArg, ConstU128, ConstU16, ConstU32, ConstU64},
|
||||
};
|
||||
use pezsp_core::H256;
|
||||
use pezsp_runtime::{
|
||||
traits::{BlakeTwo256, IdentityLookup},
|
||||
BuildStorage,
|
||||
};
|
||||
|
||||
type Block = pezframe_system::mocking::MockBlock<Test>;
|
||||
pub type AccountId = u64;
|
||||
pub type Balance = u128;
|
||||
|
||||
// Runtime'ı oluştur - Identity ve IdentityKyc pallet'lerini de ekle
|
||||
construct_runtime!(
|
||||
pub enum Test
|
||||
{
|
||||
System: pezframe_system::{Pallet, Call, Config<T>, Storage, Event<T>},
|
||||
Balances: pezpallet_balances::{Pallet, Call, Storage, Event<T>},
|
||||
Identity: pezpallet_identity::{Pallet, Call, Storage, Event<T>},
|
||||
IdentityKyc: pezpallet_identity_kyc::{Pallet, Call, Storage, Event<T>},
|
||||
Nfts: pezpallet_nfts::{Pallet, Call, Storage, Event<T>},
|
||||
Tiki: pezpallet_tiki::{Pallet, Call, Storage, Event<T>},
|
||||
}
|
||||
);
|
||||
|
||||
impl pezframe_system::Config for Test {
|
||||
type BaseCallFilter = pezframe_support::traits::Everything;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = pezframe_support::weights::constants::RocksDbWeight;
|
||||
type RuntimeOrigin = RuntimeOrigin;
|
||||
type RuntimeCall = RuntimeCall;
|
||||
type Nonce = u64;
|
||||
type Hash = H256;
|
||||
type Hashing = BlakeTwo256;
|
||||
type AccountId = AccountId;
|
||||
type Lookup = IdentityLookup<Self::AccountId>;
|
||||
type Block = Block;
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type BlockHashCount = ConstU64<250>;
|
||||
type Version = ();
|
||||
type PalletInfo = PalletInfo;
|
||||
type AccountData = pezpallet_balances::AccountData<Balance>;
|
||||
type OnNewAccount = ();
|
||||
type OnKilledAccount = ();
|
||||
type SystemWeightInfo = ();
|
||||
type SS58Prefix = ConstU16<42>;
|
||||
type OnSetCode = ();
|
||||
type MaxConsumers = ConstU32<16>;
|
||||
type RuntimeTask = ();
|
||||
type SingleBlockMigrations = ();
|
||||
type MultiBlockMigrator = ();
|
||||
type PreInherents = ();
|
||||
type PostInherents = ();
|
||||
type PostTransactions = (); // Eksik olan trait
|
||||
type ExtensionsWeightInfo = ();
|
||||
}
|
||||
|
||||
impl pezpallet_balances::Config for Test {
|
||||
type Balance = Balance;
|
||||
type DustRemoval = ();
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type ExistentialDeposit = ConstU128<1>;
|
||||
type AccountStore = System;
|
||||
type WeightInfo = ();
|
||||
type MaxLocks = ConstU32<50>;
|
||||
type MaxReserves = ();
|
||||
type ReserveIdentifier = [u8; 8];
|
||||
type FreezeIdentifier = ();
|
||||
type MaxFreezes = ();
|
||||
type RuntimeHoldReason = ();
|
||||
type RuntimeFreezeReason = ();
|
||||
type DoneSlashHandler = ();
|
||||
}
|
||||
|
||||
// pezpallet_identity::Config implementasyonu
|
||||
parameter_types! {
|
||||
pub const BasicDeposit: Balance = 1000;
|
||||
pub const ByteDeposit: Balance = 10;
|
||||
pub const SubAccountDeposit: Balance = 100;
|
||||
pub const MaxSubAccounts: u32 = 10;
|
||||
pub const MaxRegistrars: u32 = 10;
|
||||
pub const UsernameDeposit: Balance = 100;
|
||||
pub const PendingUsernameExpiration: u64 = 100;
|
||||
pub const UsernameGracePeriod: u64 = 50;
|
||||
pub const MaxSuffixLength: u32 = 10;
|
||||
pub const MaxUsernameLength: u32 = 32;
|
||||
}
|
||||
|
||||
impl pezpallet_identity::Config for Test {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type Currency = Balances;
|
||||
type BasicDeposit = BasicDeposit;
|
||||
type ByteDeposit = ByteDeposit;
|
||||
type SubAccountDeposit = SubAccountDeposit;
|
||||
type MaxSubAccounts = MaxSubAccounts;
|
||||
type IdentityInformation = pezpallet_identity::legacy::IdentityInfo<MaxAdditionalFields>;
|
||||
type MaxRegistrars = MaxRegistrars;
|
||||
type Slashed = ();
|
||||
type ForceOrigin = pezframe_system::EnsureRoot<AccountId>;
|
||||
type RegistrarOrigin = pezframe_system::EnsureRoot<AccountId>;
|
||||
type WeightInfo = ();
|
||||
type OffchainSignature = pezsp_runtime::testing::TestSignature;
|
||||
type SigningPublicKey =
|
||||
<pezsp_runtime::testing::TestSignature as pezsp_runtime::traits::Verify>::Signer;
|
||||
type UsernameAuthorityOrigin = pezframe_system::EnsureRoot<AccountId>;
|
||||
type UsernameDeposit = UsernameDeposit;
|
||||
type PendingUsernameExpiration = PendingUsernameExpiration;
|
||||
type UsernameGracePeriod = UsernameGracePeriod;
|
||||
type MaxSuffixLength = MaxSuffixLength;
|
||||
type MaxUsernameLength = MaxUsernameLength;
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub const MaxAdditionalFields: u32 = 10;
|
||||
}
|
||||
|
||||
// pezpallet_identity_kyc::Config parameters
|
||||
parameter_types! {
|
||||
pub const KycApplicationDepositAmount: Balance = 100;
|
||||
pub const MaxCidLength: u32 = 100;
|
||||
}
|
||||
|
||||
// Mock implementation for OnKycApproved hook (updated for new trait signature)
|
||||
pub struct MockOnKycApproved;
|
||||
impl pezpallet_identity_kyc::types::OnKycApproved<AccountId> for MockOnKycApproved {
|
||||
fn on_kyc_approved(_who: &AccountId, _referrer: &AccountId) {
|
||||
// No-op for tests
|
||||
}
|
||||
}
|
||||
|
||||
// Mock implementation for OnCitizenshipRevoked hook
|
||||
pub struct MockOnCitizenshipRevoked;
|
||||
impl pezpallet_identity_kyc::types::OnCitizenshipRevoked<AccountId> for MockOnCitizenshipRevoked {
|
||||
fn on_citizenship_revoked(_who: &AccountId) {
|
||||
// No-op for tests
|
||||
}
|
||||
}
|
||||
|
||||
// Mock implementation for CitizenNftProvider
|
||||
pub struct MockCitizenNftProvider;
|
||||
impl pezpallet_identity_kyc::types::CitizenNftProvider<AccountId> for MockCitizenNftProvider {
|
||||
fn mint_citizen_nft(_who: &AccountId) -> pezsp_runtime::DispatchResult {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn mint_citizen_nft_confirmed(_who: &AccountId) -> pezsp_runtime::DispatchResult {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn burn_citizen_nft(_who: &AccountId) -> pezsp_runtime::DispatchResult {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl pezpallet_identity_kyc::Config for Test {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type Currency = Balances;
|
||||
type WeightInfo = ();
|
||||
type GovernanceOrigin = pezframe_system::EnsureRoot<AccountId>;
|
||||
type KycApplicationDeposit = KycApplicationDepositAmount;
|
||||
type MaxStringLength = ConstU32<50>;
|
||||
type MaxCidLength = MaxCidLength;
|
||||
type OnKycApproved = MockOnKycApproved;
|
||||
type OnCitizenshipRevoked = MockOnCitizenshipRevoked;
|
||||
type CitizenNftProvider = MockCitizenNftProvider;
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub Features: pezpallet_nfts::PalletFeatures = pezpallet_nfts::PalletFeatures::default();
|
||||
}
|
||||
|
||||
impl pezpallet_nfts::Config for Test {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type CollectionId = u32;
|
||||
type ItemId = u32;
|
||||
type Currency = Balances;
|
||||
type ForceOrigin = pezframe_system::EnsureRoot<AccountId>;
|
||||
type CreateOrigin = AsEnsureOriginWithArg<pezframe_system::EnsureSigned<AccountId>>;
|
||||
type Locker = ();
|
||||
type CollectionDeposit = ConstU128<0>;
|
||||
type ItemDeposit = ConstU128<0>;
|
||||
type MetadataDepositBase = ConstU128<0>;
|
||||
type AttributeDepositBase = ConstU128<0>;
|
||||
type DepositPerByte = ConstU128<0>;
|
||||
type StringLimit = ConstU32<256>;
|
||||
type KeyLimit = ConstU32<64>;
|
||||
type ValueLimit = ConstU32<256>;
|
||||
type ApprovalsLimit = ConstU32<10>;
|
||||
type ItemAttributesApprovalsLimit = ConstU32<20>;
|
||||
type MaxTips = ConstU32<10>;
|
||||
type MaxDeadlineDuration = ConstU64<10000>;
|
||||
type MaxAttributesPerCall = ConstU32<10>;
|
||||
type Features = Features;
|
||||
type OffchainSignature = pezsp_runtime::testing::TestSignature;
|
||||
type OffchainPublic = <Self::OffchainSignature as pezsp_runtime::traits::Verify>::Signer;
|
||||
type WeightInfo = ();
|
||||
type BlockNumberProvider = System;
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
type Helper = ();
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub const TikiCollectionId: u32 = 0;
|
||||
pub const MaxTikisPerUser: u32 = 100;
|
||||
}
|
||||
|
||||
impl crate::Config for Test {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type AdminOrigin = pezframe_system::EnsureRoot<AccountId>;
|
||||
type WeightInfo = ();
|
||||
type TikiCollectionId = TikiCollectionId;
|
||||
type MaxTikisPerUser = MaxTikisPerUser;
|
||||
type Tiki = TikiEnum;
|
||||
}
|
||||
|
||||
// Helper functions for tests
|
||||
// Updated for trustless model - directly sets KYC status and hash
|
||||
pub fn setup_kyc_for_user(account: AccountId) {
|
||||
// Give balance to user
|
||||
let _ = Balances::force_set_balance(RuntimeOrigin::root(), account, 10000);
|
||||
|
||||
// Directly set KYC status to Approved (for test purposes)
|
||||
// In real runtime this would go through apply_for_citizenship -> approve_referral ->
|
||||
// confirm_citizenship
|
||||
pezpallet_identity_kyc::KycStatuses::<Test>::insert(
|
||||
account,
|
||||
pezpallet_identity_kyc::types::KycLevel::Approved,
|
||||
);
|
||||
|
||||
// Set identity hash
|
||||
pezpallet_identity_kyc::IdentityHashes::<Test>::insert(
|
||||
account,
|
||||
pezsp_core::H256::from_low_u64_be(account),
|
||||
);
|
||||
}
|
||||
|
||||
// Legacy function - kept for backwards compatibility
|
||||
pub fn setup_identity_for_user(account: AccountId) {
|
||||
setup_kyc_for_user(account);
|
||||
}
|
||||
|
||||
pub fn advance_blocks(blocks: u64) {
|
||||
for _i in 0..blocks {
|
||||
let current_block = System::block_number();
|
||||
System::set_block_number(current_block + 1);
|
||||
// Trigger hooks for the new block
|
||||
<pezpallet_tiki::Pallet<Test> as pezframe_support::traits::Hooks<u64>>::on_initialize(
|
||||
current_block + 1,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_test_ext() -> pezsp_io::TestExternalities {
|
||||
let mut t = pezframe_system::GenesisConfig::<Test>::default().build_storage().unwrap();
|
||||
|
||||
pezpallet_balances::GenesisConfig::<Test> {
|
||||
balances: vec![(1, 10000), (2, 10000), (3, 10000), (4, 10000), (5, 10000)],
|
||||
dev_accounts: Default::default(),
|
||||
}
|
||||
.assimilate_storage(&mut t)
|
||||
.unwrap();
|
||||
|
||||
let mut ext = pezsp_io::TestExternalities::new(t);
|
||||
ext.execute_with(|| {
|
||||
System::set_block_number(1);
|
||||
|
||||
// Tiki koleksiyonunu oluştur - mint permissions ile
|
||||
assert_ok!(Nfts::force_create(
|
||||
RuntimeOrigin::root(),
|
||||
1, // owner
|
||||
pezpallet_nfts::CollectionConfig {
|
||||
settings: pezpallet_nfts::CollectionSettings::all_enabled(),
|
||||
max_supply: None,
|
||||
mint_settings: pezpallet_nfts::MintSettings {
|
||||
mint_type: pezpallet_nfts::MintType::Public,
|
||||
price: None,
|
||||
start_block: None,
|
||||
end_block: None,
|
||||
default_item_settings: pezpallet_nfts::ItemSettings::all_enabled(),
|
||||
},
|
||||
}
|
||||
));
|
||||
});
|
||||
ext
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,298 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
|
||||
//! Autogenerated weights for `pezpallet_tiki`
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE BIZINIKIWI BENCHMARK CLI VERSION 32.0.0
|
||||
//! DATE: 2025-12-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! WORST CASE MAP SIZE: `1000000`
|
||||
//! HOSTNAME: `MamostePC`, CPU: `11th Gen Intel(R) Core(TM) i9-11950H @ 2.60GHz`
|
||||
//! WASM-EXECUTION: `Compiled`, CHAIN: `None`, DB CACHE: `1024`
|
||||
|
||||
// Executed Command:
|
||||
// ./target/release/frame-omni-bencher
|
||||
// v1
|
||||
// benchmark
|
||||
// pallet
|
||||
// --runtime
|
||||
// target/release/wbuild/people-pezkuwichain-runtime/people_pezkuwichain_runtime.compact.compressed.wasm
|
||||
// --pallets
|
||||
// pezpallet_tiki
|
||||
// -e
|
||||
// all
|
||||
// --steps
|
||||
// 50
|
||||
// --repeat
|
||||
// 20
|
||||
// --output
|
||||
// pezcumulus/teyrchains/pezpallets/tiki/src/weights.rs
|
||||
// --template
|
||||
// bizinikiwi/.maintain/frame-weight-template.hbs
|
||||
|
||||
#![cfg_attr(rustfmt, rustfmt_skip)]
|
||||
#![allow(unused_parens)]
|
||||
#![allow(unused_imports)]
|
||||
#![allow(missing_docs)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
use pezframe_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
|
||||
use core::marker::PhantomData;
|
||||
|
||||
/// Weight functions needed for `pezpallet_tiki`.
|
||||
pub trait WeightInfo {
|
||||
fn grant_tiki() -> Weight;
|
||||
fn revoke_tiki() -> Weight;
|
||||
fn force_mint_citizen_nft() -> Weight;
|
||||
fn grant_earned_role() -> Weight;
|
||||
fn grant_elected_role() -> Weight;
|
||||
}
|
||||
|
||||
/// Weights for `pezpallet_tiki` using the Bizinikiwi node and recommended hardware.
|
||||
pub struct BizinikiwiWeight<T>(PhantomData<T>);
|
||||
impl<T: pezframe_system::Config> WeightInfo for BizinikiwiWeight<T> {
|
||||
/// Storage: `Tiki::CitizenNft` (r:1 w:0)
|
||||
/// Proof: `Tiki::CitizenNft` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Tiki::UserTikis` (r:1 w:1)
|
||||
/// Proof: `Tiki::UserTikis` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::Collection` (r:1 w:1)
|
||||
/// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::ItemConfigOf` (r:1 w:0)
|
||||
/// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::CollectionConfigOf` (r:1 w:0)
|
||||
/// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::ItemMetadataOf` (r:1 w:1)
|
||||
/// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`)
|
||||
fn grant_tiki() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `848`
|
||||
// Estimated: `3812`
|
||||
// Minimum execution time: 50_144_000 picoseconds.
|
||||
Weight::from_parts(51_105_000, 3812)
|
||||
.saturating_add(T::DbWeight::get().reads(6_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(3_u64))
|
||||
}
|
||||
/// Storage: `Tiki::UserTikis` (r:1 w:1)
|
||||
/// Proof: `Tiki::UserTikis` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Tiki::CitizenNft` (r:1 w:0)
|
||||
/// Proof: `Tiki::CitizenNft` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::Collection` (r:1 w:1)
|
||||
/// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::ItemConfigOf` (r:1 w:0)
|
||||
/// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::CollectionConfigOf` (r:1 w:0)
|
||||
/// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::ItemMetadataOf` (r:1 w:1)
|
||||
/// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`)
|
||||
fn revoke_tiki() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `850`
|
||||
// Estimated: `3812`
|
||||
// Minimum execution time: 48_006_000 picoseconds.
|
||||
Weight::from_parts(49_738_000, 3812)
|
||||
.saturating_add(T::DbWeight::get().reads(6_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(3_u64))
|
||||
}
|
||||
/// Storage: `Tiki::CitizenNft` (r:1 w:1)
|
||||
/// Proof: `Tiki::CitizenNft` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Tiki::NextItemId` (r:1 w:1)
|
||||
/// Proof: `Tiki::NextItemId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::Item` (r:1 w:1)
|
||||
/// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::Collection` (r:1 w:1)
|
||||
/// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::CollectionConfigOf` (r:1 w:0)
|
||||
/// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::ItemConfigOf` (r:1 w:1)
|
||||
/// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::Attribute` (r:1 w:1)
|
||||
/// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Tiki::UserTikis` (r:1 w:1)
|
||||
/// Proof: `Tiki::UserTikis` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::ItemMetadataOf` (r:1 w:1)
|
||||
/// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::Account` (r:0 w:1)
|
||||
/// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`)
|
||||
fn force_mint_citizen_nft() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `439`
|
||||
// Estimated: `4326`
|
||||
// Minimum execution time: 106_450_000 picoseconds.
|
||||
Weight::from_parts(111_649_000, 4326)
|
||||
.saturating_add(T::DbWeight::get().reads(9_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(9_u64))
|
||||
}
|
||||
/// Storage: `Tiki::CitizenNft` (r:1 w:0)
|
||||
/// Proof: `Tiki::CitizenNft` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Tiki::UserTikis` (r:1 w:1)
|
||||
/// Proof: `Tiki::UserTikis` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::Collection` (r:1 w:1)
|
||||
/// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::ItemConfigOf` (r:1 w:0)
|
||||
/// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::CollectionConfigOf` (r:1 w:0)
|
||||
/// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::ItemMetadataOf` (r:1 w:1)
|
||||
/// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`)
|
||||
fn grant_earned_role() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `848`
|
||||
// Estimated: `3812`
|
||||
// Minimum execution time: 51_486_000 picoseconds.
|
||||
Weight::from_parts(53_580_000, 3812)
|
||||
.saturating_add(T::DbWeight::get().reads(6_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(3_u64))
|
||||
}
|
||||
/// Storage: `Tiki::CitizenNft` (r:1 w:0)
|
||||
/// Proof: `Tiki::CitizenNft` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Tiki::UserTikis` (r:1 w:1)
|
||||
/// Proof: `Tiki::UserTikis` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::Collection` (r:1 w:1)
|
||||
/// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::ItemConfigOf` (r:1 w:0)
|
||||
/// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::CollectionConfigOf` (r:1 w:0)
|
||||
/// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::ItemMetadataOf` (r:1 w:1)
|
||||
/// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`)
|
||||
fn grant_elected_role() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `848`
|
||||
// Estimated: `3812`
|
||||
// Minimum execution time: 52_085_000 picoseconds.
|
||||
Weight::from_parts(53_750_000, 3812)
|
||||
.saturating_add(T::DbWeight::get().reads(6_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(3_u64))
|
||||
}
|
||||
}
|
||||
|
||||
// For backwards compatibility and tests.
|
||||
impl WeightInfo for () {
|
||||
/// Storage: `Tiki::CitizenNft` (r:1 w:0)
|
||||
/// Proof: `Tiki::CitizenNft` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Tiki::UserTikis` (r:1 w:1)
|
||||
/// Proof: `Tiki::UserTikis` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::Collection` (r:1 w:1)
|
||||
/// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::ItemConfigOf` (r:1 w:0)
|
||||
/// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::CollectionConfigOf` (r:1 w:0)
|
||||
/// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::ItemMetadataOf` (r:1 w:1)
|
||||
/// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`)
|
||||
fn grant_tiki() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `848`
|
||||
// Estimated: `3812`
|
||||
// Minimum execution time: 50_144_000 picoseconds.
|
||||
Weight::from_parts(51_105_000, 3812)
|
||||
.saturating_add(RocksDbWeight::get().reads(6_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(3_u64))
|
||||
}
|
||||
/// Storage: `Tiki::UserTikis` (r:1 w:1)
|
||||
/// Proof: `Tiki::UserTikis` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Tiki::CitizenNft` (r:1 w:0)
|
||||
/// Proof: `Tiki::CitizenNft` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::Collection` (r:1 w:1)
|
||||
/// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::ItemConfigOf` (r:1 w:0)
|
||||
/// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::CollectionConfigOf` (r:1 w:0)
|
||||
/// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::ItemMetadataOf` (r:1 w:1)
|
||||
/// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`)
|
||||
fn revoke_tiki() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `850`
|
||||
// Estimated: `3812`
|
||||
// Minimum execution time: 48_006_000 picoseconds.
|
||||
Weight::from_parts(49_738_000, 3812)
|
||||
.saturating_add(RocksDbWeight::get().reads(6_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(3_u64))
|
||||
}
|
||||
/// Storage: `Tiki::CitizenNft` (r:1 w:1)
|
||||
/// Proof: `Tiki::CitizenNft` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Tiki::NextItemId` (r:1 w:1)
|
||||
/// Proof: `Tiki::NextItemId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::Item` (r:1 w:1)
|
||||
/// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::Collection` (r:1 w:1)
|
||||
/// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::CollectionConfigOf` (r:1 w:0)
|
||||
/// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::ItemConfigOf` (r:1 w:1)
|
||||
/// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::Attribute` (r:1 w:1)
|
||||
/// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Tiki::UserTikis` (r:1 w:1)
|
||||
/// Proof: `Tiki::UserTikis` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::ItemMetadataOf` (r:1 w:1)
|
||||
/// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::Account` (r:0 w:1)
|
||||
/// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`)
|
||||
fn force_mint_citizen_nft() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `439`
|
||||
// Estimated: `4326`
|
||||
// Minimum execution time: 106_450_000 picoseconds.
|
||||
Weight::from_parts(111_649_000, 4326)
|
||||
.saturating_add(RocksDbWeight::get().reads(9_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(9_u64))
|
||||
}
|
||||
/// Storage: `Tiki::CitizenNft` (r:1 w:0)
|
||||
/// Proof: `Tiki::CitizenNft` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Tiki::UserTikis` (r:1 w:1)
|
||||
/// Proof: `Tiki::UserTikis` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::Collection` (r:1 w:1)
|
||||
/// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::ItemConfigOf` (r:1 w:0)
|
||||
/// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::CollectionConfigOf` (r:1 w:0)
|
||||
/// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::ItemMetadataOf` (r:1 w:1)
|
||||
/// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`)
|
||||
fn grant_earned_role() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `848`
|
||||
// Estimated: `3812`
|
||||
// Minimum execution time: 51_486_000 picoseconds.
|
||||
Weight::from_parts(53_580_000, 3812)
|
||||
.saturating_add(RocksDbWeight::get().reads(6_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(3_u64))
|
||||
}
|
||||
/// Storage: `Tiki::CitizenNft` (r:1 w:0)
|
||||
/// Proof: `Tiki::CitizenNft` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Tiki::UserTikis` (r:1 w:1)
|
||||
/// Proof: `Tiki::UserTikis` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::Collection` (r:1 w:1)
|
||||
/// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::ItemConfigOf` (r:1 w:0)
|
||||
/// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::CollectionConfigOf` (r:1 w:0)
|
||||
/// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Nfts::ItemMetadataOf` (r:1 w:1)
|
||||
/// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`)
|
||||
fn grant_elected_role() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `848`
|
||||
// Estimated: `3812`
|
||||
// Minimum execution time: 52_085_000 picoseconds.
|
||||
Weight::from_parts(53_750_000, 3812)
|
||||
.saturating_add(RocksDbWeight::get().reads(6_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(3_u64))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user