feat: Rebrand Polkadot/Substrate references to PezkuwiChain
This commit systematically rebrands various references from Parity Technologies' Polkadot/Substrate ecosystem to PezkuwiChain within the kurdistan-sdk. Key changes include: - Updated external repository URLs (zombienet-sdk, parity-db, parity-scale-codec, wasm-instrument) to point to pezkuwichain forks. - Modified internal documentation and code comments to reflect PezkuwiChain naming and structure. - Replaced direct references to with or specific paths within the for XCM, Pezkuwi, and other modules. - Cleaned up deprecated issue and PR references in various and files, particularly in and modules. - Adjusted image and logo URLs in documentation to point to PezkuwiChain assets. - Removed or rephrased comments related to external Polkadot/Substrate PRs and issues. This is a significant step towards fully customizing the SDK for the PezkuwiChain ecosystem.
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
[package]
|
||||
name = "pezpallet-token-wrapper"
|
||||
version = "1.0.0"
|
||||
description = "Token Wrapper Pallet for wrapping native HEZ into wHEZ asset"
|
||||
authors.workspace = true
|
||||
homepage.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
publish = false
|
||||
repository.workspace = true
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
||||
[dependencies]
|
||||
codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [
|
||||
"derive",
|
||||
"max-encoded-len",
|
||||
] }
|
||||
scale-info = { default-features = false, features = [
|
||||
"derive",
|
||||
], workspace = true }
|
||||
serde = { version = "1.0", default-features = false, features = [
|
||||
"derive",
|
||||
], optional = true }
|
||||
|
||||
pezframe-benchmarking = { optional = true, workspace = true }
|
||||
pezframe-support = { default-features = false, workspace = true }
|
||||
pezframe-system = { default-features = false, workspace = true }
|
||||
pezsp-core = { workspace = true, default-features = false, optional = true }
|
||||
pezsp-io = { workspace = true, default-features = false, optional = true }
|
||||
pezsp-runtime = { default-features = false, workspace = true }
|
||||
pezsp-std = { default-features = false, workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
pezpallet-assets = { workspace = true }
|
||||
pezpallet-balances = { workspace = true }
|
||||
serde = { version = "1.0" }
|
||||
pezsp-core = { workspace = true }
|
||||
pezsp-io = { workspace = true }
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = [
|
||||
"codec/std",
|
||||
"pezframe-benchmarking?/std",
|
||||
"pezframe-support/std",
|
||||
"pezframe-system/std",
|
||||
"pezpallet-assets/std",
|
||||
"pezpallet-balances/std",
|
||||
"scale-info/std",
|
||||
"serde",
|
||||
"pezsp-core?/std",
|
||||
"pezsp-io?/std",
|
||||
"pezsp-runtime/std",
|
||||
"pezsp-std/std",
|
||||
]
|
||||
runtime-benchmarks = [
|
||||
"pezframe-benchmarking/runtime-benchmarks",
|
||||
"pezframe-support/runtime-benchmarks",
|
||||
"pezframe-system/runtime-benchmarks",
|
||||
"pezpallet-assets/runtime-benchmarks",
|
||||
"pezpallet-balances/runtime-benchmarks",
|
||||
"pezsp-core",
|
||||
"pezsp-io",
|
||||
"pezsp-io?/runtime-benchmarks",
|
||||
"pezsp-runtime/runtime-benchmarks",
|
||||
]
|
||||
try-runtime = [
|
||||
"pezframe-support/try-runtime",
|
||||
"pezframe-system/try-runtime",
|
||||
"pezpallet-assets/try-runtime",
|
||||
"pezpallet-balances/try-runtime",
|
||||
"pezsp-runtime/try-runtime",
|
||||
]
|
||||
@@ -0,0 +1,68 @@
|
||||
//! Benchmarking setup for pezpallet-token-wrapper
|
||||
|
||||
#![cfg(feature = "runtime-benchmarks")]
|
||||
|
||||
use super::*;
|
||||
#[allow(unused)]
|
||||
use crate::Pallet as TokenWrapper;
|
||||
use pezframe_benchmarking::v2::*;
|
||||
use pezframe_support::traits::Currency;
|
||||
use pezframe_system::RawOrigin;
|
||||
|
||||
#[benchmarks]
|
||||
mod benchmarks {
|
||||
use super::*;
|
||||
|
||||
#[benchmark]
|
||||
fn wrap() {
|
||||
let caller: T::AccountId = whitelisted_caller();
|
||||
let pezpallet_account = Pallet::<T>::account_id();
|
||||
let amount = 10_000u32.into();
|
||||
|
||||
// Fund both caller and pallet account
|
||||
let funding = <T::Currency as Currency<T::AccountId>>::minimum_balance()
|
||||
.saturating_mul(1000u32.into());
|
||||
|
||||
T::Currency::make_free_balance_be(&caller, funding);
|
||||
T::Currency::make_free_balance_be(&pezpallet_account, funding);
|
||||
|
||||
// Create asset
|
||||
let _ =
|
||||
T::Assets::create(T::WrapperAssetId::get(), pezpallet_account.clone(), true, 1u32.into());
|
||||
|
||||
#[extrinsic_call]
|
||||
_(RawOrigin::Signed(caller.clone()), amount);
|
||||
|
||||
// Verify
|
||||
assert!(T::Assets::balance(T::WrapperAssetId::get(), &caller) >= amount);
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn unwrap() {
|
||||
let caller: T::AccountId = whitelisted_caller();
|
||||
let pezpallet_account = Pallet::<T>::account_id();
|
||||
let amount = 10_000u32.into();
|
||||
|
||||
// Fund both accounts
|
||||
let funding = <T::Currency as Currency<T::AccountId>>::minimum_balance()
|
||||
.saturating_mul(1000u32.into());
|
||||
|
||||
T::Currency::make_free_balance_be(&caller, funding);
|
||||
T::Currency::make_free_balance_be(&pezpallet_account, funding);
|
||||
|
||||
// Create asset
|
||||
let _ =
|
||||
T::Assets::create(T::WrapperAssetId::get(), pezpallet_account.clone(), true, 1u32.into());
|
||||
|
||||
// Wrap first
|
||||
let _ = Pallet::<T>::wrap(RawOrigin::Signed(caller.clone()).into(), amount);
|
||||
|
||||
#[extrinsic_call]
|
||||
_(RawOrigin::Signed(caller.clone()), amount);
|
||||
|
||||
// Verify
|
||||
assert_eq!(T::Assets::balance(T::WrapperAssetId::get(), &caller), 0u32.into());
|
||||
}
|
||||
|
||||
impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test);
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
//! # Token Wrapper Pallet
|
||||
//!
|
||||
//! A pallet for wrapping native tokens (HEZ) into fungible assets (wHEZ)
|
||||
//! to enable DEX operations between native and asset tokens.
|
||||
//!
|
||||
//! ## Overview
|
||||
//!
|
||||
//! This pallet provides:
|
||||
//! - `wrap`: Convert native HEZ to wHEZ (Asset ID 0)
|
||||
//! - `unwrap`: Convert wHEZ back to native HEZ
|
||||
//!
|
||||
//! The pallet maintains a 1:1 backing between HEZ and wHEZ.
|
||||
|
||||
pub use pallet::*;
|
||||
pub use weights::WeightInfo;
|
||||
pub mod weights;
|
||||
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
mod benchmarking;
|
||||
#[cfg(test)]
|
||||
mod mock;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use pezframe_support::{
|
||||
dispatch::DispatchResult,
|
||||
pezpallet_prelude::*,
|
||||
traits::{
|
||||
fungibles::{Create, Inspect, Mutate},
|
||||
Currency, ExistenceRequirement,
|
||||
},
|
||||
PalletId,
|
||||
};
|
||||
use pezframe_system::pezpallet_prelude::*;
|
||||
use pezsp_runtime::traits::{AccountIdConversion, Saturating, Zero};
|
||||
|
||||
#[pezframe_support::pallet]
|
||||
pub mod pallet {
|
||||
use super::*;
|
||||
|
||||
type BalanceOf<T> =
|
||||
<<T as Config>::Currency as Currency<<T as pezframe_system::Config>::AccountId>>::Balance;
|
||||
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T>(_);
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config: pezframe_system::Config {
|
||||
/// Weight information for extrinsics in this pallet.
|
||||
type WeightInfo: crate::WeightInfo;
|
||||
|
||||
/// Native currency (HEZ)
|
||||
type Currency: Currency<Self::AccountId>;
|
||||
|
||||
/// Asset ID type
|
||||
type AssetId: Parameter + Member + Copy + MaybeSerializeDeserialize + MaxEncodedLen;
|
||||
|
||||
/// Fungible assets (for wHEZ)
|
||||
type Assets: Inspect<Self::AccountId, AssetId = Self::AssetId, Balance = BalanceOf<Self>>
|
||||
+ Mutate<Self::AccountId>
|
||||
+ Create<Self::AccountId>;
|
||||
|
||||
/// Pallet ID for the wrapper account
|
||||
#[pallet::constant]
|
||||
type PalletId: Get<PalletId>;
|
||||
|
||||
/// Asset ID for wrapped token (wHEZ)
|
||||
#[pallet::constant]
|
||||
type WrapperAssetId: Get<Self::AssetId>;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// STORAGE ITEMS
|
||||
// ============================================================================
|
||||
|
||||
/// Total amount of native tokens locked in wrapper
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn total_locked)]
|
||||
pub type TotalLocked<T: Config> = StorageValue<_, BalanceOf<T>, ValueQuery>;
|
||||
|
||||
// ============================================================================
|
||||
// EVENTS
|
||||
// ============================================================================
|
||||
|
||||
#[pallet::event]
|
||||
#[pallet::generate_deposit(pub(super) fn deposit_event)]
|
||||
pub enum Event<T: Config> {
|
||||
/// Native token wrapped into asset token. [who, amount]
|
||||
Wrapped { who: T::AccountId, amount: BalanceOf<T> },
|
||||
/// Asset token unwrapped back to native. [who, amount]
|
||||
Unwrapped { who: T::AccountId, amount: BalanceOf<T> },
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// ERRORS
|
||||
// ============================================================================
|
||||
|
||||
#[pallet::error]
|
||||
pub enum Error<T> {
|
||||
/// Insufficient balance for wrapping
|
||||
InsufficientBalance,
|
||||
/// Insufficient wrapped tokens for unwrapping
|
||||
InsufficientWrappedBalance,
|
||||
/// Transfer failed
|
||||
TransferFailed,
|
||||
/// Mint failed
|
||||
MintFailed,
|
||||
/// Burn failed
|
||||
BurnFailed,
|
||||
/// Amount is zero
|
||||
ZeroAmount,
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// DISPATCHABLE FUNCTIONS
|
||||
// ============================================================================
|
||||
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {
|
||||
/// Wrap native tokens (HEZ) into wrapped asset tokens (wHEZ)
|
||||
///
|
||||
/// - `amount`: The amount of native tokens to wrap
|
||||
///
|
||||
/// This will:
|
||||
/// 1. Transfer native tokens from user to pallet account (lock)
|
||||
/// 2. Mint equivalent amount of wrapped tokens to user
|
||||
///
|
||||
/// Emits `Wrapped` event.
|
||||
#[pallet::call_index(0)]
|
||||
#[pallet::weight(T::WeightInfo::wrap())]
|
||||
pub fn wrap(
|
||||
origin: OriginFor<T>,
|
||||
#[pallet::compact] amount: BalanceOf<T>,
|
||||
) -> DispatchResult {
|
||||
let who = ensure_signed(origin)?;
|
||||
|
||||
// Ensure amount is not zero
|
||||
ensure!(!amount.is_zero(), Error::<T>::ZeroAmount);
|
||||
|
||||
// Check balance
|
||||
ensure!(T::Currency::free_balance(&who) >= amount, Error::<T>::InsufficientBalance);
|
||||
|
||||
// Transfer native tokens to pallet account (lock them)
|
||||
T::Currency::transfer(
|
||||
&who,
|
||||
&Self::account_id(),
|
||||
amount,
|
||||
ExistenceRequirement::KeepAlive,
|
||||
)
|
||||
.map_err(|_| Error::<T>::TransferFailed)?;
|
||||
|
||||
// Update total locked
|
||||
TotalLocked::<T>::mutate(|total| {
|
||||
*total = total.saturating_add(amount);
|
||||
});
|
||||
|
||||
// Mint wrapped tokens to user
|
||||
T::Assets::mint_into(T::WrapperAssetId::get(), &who, amount)
|
||||
.map_err(|_| Error::<T>::MintFailed)?;
|
||||
|
||||
Self::deposit_event(Event::Wrapped { who, amount });
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Unwrap wrapped asset tokens (wHEZ) back to native tokens (HEZ)
|
||||
///
|
||||
/// - `amount`: The amount of wrapped tokens to unwrap
|
||||
///
|
||||
/// This will:
|
||||
/// 1. Burn wrapped tokens from user
|
||||
/// 2. Transfer equivalent native tokens back to user (unlock)
|
||||
///
|
||||
/// Emits `Unwrapped` event.
|
||||
#[pallet::call_index(1)]
|
||||
#[pallet::weight(T::WeightInfo::unwrap())]
|
||||
pub fn unwrap(
|
||||
origin: OriginFor<T>,
|
||||
#[pallet::compact] amount: BalanceOf<T>,
|
||||
) -> DispatchResult {
|
||||
let who = ensure_signed(origin)?;
|
||||
|
||||
// Ensure amount is not zero
|
||||
ensure!(!amount.is_zero(), Error::<T>::ZeroAmount);
|
||||
|
||||
// Check wrapped token balance
|
||||
let wrapped_balance = T::Assets::balance(T::WrapperAssetId::get(), &who);
|
||||
ensure!(wrapped_balance >= amount, Error::<T>::InsufficientWrappedBalance);
|
||||
|
||||
// Burn wrapped tokens from user
|
||||
T::Assets::burn_from(
|
||||
T::WrapperAssetId::get(),
|
||||
&who,
|
||||
amount,
|
||||
pezframe_support::traits::tokens::Preservation::Expendable,
|
||||
pezframe_support::traits::tokens::Precision::Exact,
|
||||
pezframe_support::traits::tokens::Fortitude::Force,
|
||||
)
|
||||
.map_err(|_| Error::<T>::BurnFailed)?;
|
||||
|
||||
// Update total locked
|
||||
TotalLocked::<T>::mutate(|total| {
|
||||
*total = total.saturating_sub(amount);
|
||||
});
|
||||
|
||||
// Transfer native tokens back to user (unlock)
|
||||
T::Currency::transfer(
|
||||
&Self::account_id(),
|
||||
&who,
|
||||
amount,
|
||||
ExistenceRequirement::AllowDeath,
|
||||
)
|
||||
.map_err(|_| Error::<T>::TransferFailed)?;
|
||||
|
||||
Self::deposit_event(Event::Unwrapped { who, amount });
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// HELPER FUNCTIONS
|
||||
// ============================================================================
|
||||
|
||||
impl<T: Config> Pallet<T> {
|
||||
/// Get the account ID of the pallet
|
||||
pub fn account_id() -> T::AccountId {
|
||||
T::PalletId::get().into_account_truncating()
|
||||
}
|
||||
|
||||
/// Get the total supply of wrapped tokens
|
||||
pub fn total_wrapped() -> BalanceOf<T> {
|
||||
T::Assets::total_issuance(T::WrapperAssetId::get())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
use crate as pezpallet_token_wrapper;
|
||||
use pezframe_support::{
|
||||
construct_runtime, parameter_types,
|
||||
traits::{AsEnsureOriginWithArg, ConstU128, ConstU32, Everything},
|
||||
PalletId,
|
||||
};
|
||||
use pezframe_system as system;
|
||||
use pezsp_core::H256;
|
||||
use pezsp_runtime::{
|
||||
traits::{BlakeTwo256, IdentityLookup},
|
||||
BuildStorage,
|
||||
};
|
||||
|
||||
pub type AccountId = u64;
|
||||
pub type Balance = u128;
|
||||
pub type AssetId = u32;
|
||||
|
||||
// Configure a mock runtime to test the pallet.
|
||||
construct_runtime!(
|
||||
pub enum Test {
|
||||
System: pezframe_system,
|
||||
Balances: pezpallet_balances,
|
||||
Assets: pezpallet_assets,
|
||||
TokenWrapper: pezpallet_token_wrapper,
|
||||
}
|
||||
);
|
||||
|
||||
parameter_types! {
|
||||
pub const BlockHashCount: u64 = 250;
|
||||
pub const SS58Prefix: u8 = 42;
|
||||
}
|
||||
|
||||
impl system::Config for Test {
|
||||
type BaseCallFilter = Everything;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
type RuntimeOrigin = RuntimeOrigin;
|
||||
type RuntimeCall = RuntimeCall;
|
||||
type RuntimeTask = ();
|
||||
type Nonce = u64;
|
||||
type Hash = H256;
|
||||
type Hashing = BlakeTwo256;
|
||||
type AccountId = AccountId;
|
||||
type Lookup = IdentityLookup<Self::AccountId>;
|
||||
type Block = pezframe_system::mocking::MockBlock<Test>;
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type BlockHashCount = BlockHashCount;
|
||||
type Version = ();
|
||||
type PalletInfo = PalletInfo;
|
||||
type AccountData = pezpallet_balances::AccountData<Balance>;
|
||||
type OnNewAccount = ();
|
||||
type OnKilledAccount = ();
|
||||
type SystemWeightInfo = ();
|
||||
type SS58Prefix = SS58Prefix;
|
||||
type OnSetCode = ();
|
||||
type MaxConsumers = ConstU32<16>;
|
||||
type ExtensionsWeightInfo = ();
|
||||
type SingleBlockMigrations = ();
|
||||
type MultiBlockMigrator = ();
|
||||
type PreInherents = ();
|
||||
type PostInherents = ();
|
||||
type PostTransactions = ();
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub const ExistentialDeposit: Balance = 1;
|
||||
}
|
||||
|
||||
impl pezpallet_balances::Config for Test {
|
||||
type MaxLocks = ConstU32<50>;
|
||||
type MaxReserves = ConstU32<50>;
|
||||
type ReserveIdentifier = [u8; 8];
|
||||
type Balance = Balance;
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type DustRemoval = ();
|
||||
type ExistentialDeposit = ExistentialDeposit;
|
||||
type AccountStore = System;
|
||||
type WeightInfo = ();
|
||||
type FreezeIdentifier = ();
|
||||
type MaxFreezes = ();
|
||||
type RuntimeHoldReason = ();
|
||||
type RuntimeFreezeReason = ();
|
||||
type DoneSlashHandler = ();
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub const AssetDeposit: Balance = 100;
|
||||
pub const ApprovalDeposit: Balance = 1;
|
||||
pub const StringLimit: u32 = 50;
|
||||
pub const MetadataDepositBase: Balance = 10;
|
||||
pub const MetadataDepositPerByte: Balance = 1;
|
||||
}
|
||||
|
||||
impl pezpallet_assets::Config for Test {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type Balance = Balance;
|
||||
type AssetId = AssetId;
|
||||
type AssetIdParameter = u32;
|
||||
type Currency = Balances;
|
||||
type CreateOrigin = AsEnsureOriginWithArg<pezframe_system::EnsureSigned<AccountId>>;
|
||||
type ForceOrigin = pezframe_system::EnsureRoot<AccountId>;
|
||||
type AssetDeposit = AssetDeposit;
|
||||
type AssetAccountDeposit = ConstU128<1>;
|
||||
type MetadataDepositBase = MetadataDepositBase;
|
||||
type MetadataDepositPerByte = MetadataDepositPerByte;
|
||||
type ApprovalDeposit = ApprovalDeposit;
|
||||
type StringLimit = StringLimit;
|
||||
type Freezer = ();
|
||||
type Extra = ();
|
||||
type CallbackHandle = ();
|
||||
type WeightInfo = ();
|
||||
type RemoveItemsLimit = ConstU32<1000>;
|
||||
type Holder = ();
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub const TokenWrapperPalletId: PalletId = PalletId(*b"py/wrper");
|
||||
pub const WrapperAssetId: u32 = 0;
|
||||
}
|
||||
|
||||
impl pezpallet_token_wrapper::Config for Test {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type WeightInfo = crate::weights::BizinikiwiWeight<Test>;
|
||||
type Currency = Balances;
|
||||
type Assets = Assets;
|
||||
type PalletId = TokenWrapperPalletId;
|
||||
type WrapperAssetId = WrapperAssetId;
|
||||
}
|
||||
|
||||
// Build genesis storage according to the mock runtime.
|
||||
pub fn new_test_ext() -> pezsp_io::TestExternalities {
|
||||
use pezframe_support::assert_ok;
|
||||
|
||||
let mut storage = system::GenesisConfig::<Test>::default().build_storage().unwrap();
|
||||
|
||||
pezpallet_balances::GenesisConfig::<Test> {
|
||||
balances: vec![(1, 10000), (2, 5000), (3, 3000)],
|
||||
dev_accounts: None,
|
||||
}
|
||||
.assimilate_storage(&mut storage)
|
||||
.unwrap();
|
||||
|
||||
let mut ext = pezsp_io::TestExternalities::new(storage);
|
||||
ext.execute_with(|| {
|
||||
System::set_block_number(1);
|
||||
|
||||
// Create wHEZ asset (Asset ID 0)
|
||||
assert_ok!(Assets::force_create(
|
||||
RuntimeOrigin::root(),
|
||||
0, // Asset ID
|
||||
TokenWrapper::account_id(), // Owner = pallet account
|
||||
true, // is_sufficient
|
||||
1, // min_balance
|
||||
));
|
||||
});
|
||||
ext
|
||||
}
|
||||
@@ -0,0 +1,256 @@
|
||||
use super::*;
|
||||
use crate::mock::*;
|
||||
use pezframe_support::{assert_noop, assert_ok};
|
||||
|
||||
#[test]
|
||||
fn wrap_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let user = 1;
|
||||
let amount = 1000;
|
||||
|
||||
assert_eq!(Balances::free_balance(&user), 10000);
|
||||
assert_eq!(Assets::balance(0, &user), 0);
|
||||
|
||||
assert_ok!(TokenWrapper::wrap(RuntimeOrigin::signed(user), amount));
|
||||
|
||||
assert_eq!(Balances::free_balance(&user), 10000 - amount);
|
||||
assert_eq!(Assets::balance(0, &user), amount);
|
||||
assert_eq!(TokenWrapper::total_locked(), amount);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unwrap_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let user = 1;
|
||||
let amount = 1000;
|
||||
|
||||
assert_ok!(TokenWrapper::wrap(RuntimeOrigin::signed(user), amount));
|
||||
let native_balance = Balances::free_balance(&user);
|
||||
|
||||
assert_ok!(TokenWrapper::unwrap(RuntimeOrigin::signed(user), amount));
|
||||
|
||||
assert_eq!(Balances::free_balance(&user), native_balance + amount);
|
||||
assert_eq!(Assets::balance(0, &user), 0);
|
||||
assert_eq!(TokenWrapper::total_locked(), 0);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wrap_fails_insufficient_balance() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let user = 1;
|
||||
let amount = 20000;
|
||||
|
||||
assert_noop!(
|
||||
TokenWrapper::wrap(RuntimeOrigin::signed(user), amount),
|
||||
Error::<Test>::InsufficientBalance
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unwrap_fails_insufficient_wrapped_balance() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let user = 1;
|
||||
let amount = 1000;
|
||||
|
||||
assert_noop!(
|
||||
TokenWrapper::unwrap(RuntimeOrigin::signed(user), amount),
|
||||
Error::<Test>::InsufficientWrappedBalance
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// EDGE CASE TESTS
|
||||
// ============================================================================
|
||||
|
||||
#[test]
|
||||
fn wrap_fails_zero_amount() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let user = 1;
|
||||
|
||||
assert_noop!(TokenWrapper::wrap(RuntimeOrigin::signed(user), 0), Error::<Test>::ZeroAmount);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unwrap_fails_zero_amount() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let user = 1;
|
||||
let amount = 1000;
|
||||
|
||||
// First wrap some tokens
|
||||
assert_ok!(TokenWrapper::wrap(RuntimeOrigin::signed(user), amount));
|
||||
|
||||
// Try to unwrap zero
|
||||
assert_noop!(
|
||||
TokenWrapper::unwrap(RuntimeOrigin::signed(user), 0),
|
||||
Error::<Test>::ZeroAmount
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multi_user_concurrent_wrap_unwrap() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let user1 = 1;
|
||||
let user2 = 2;
|
||||
let user3 = 3;
|
||||
|
||||
let amount1 = 1000;
|
||||
let amount2 = 2000;
|
||||
let amount3 = 1500;
|
||||
|
||||
// All users wrap
|
||||
assert_ok!(TokenWrapper::wrap(RuntimeOrigin::signed(user1), amount1));
|
||||
assert_ok!(TokenWrapper::wrap(RuntimeOrigin::signed(user2), amount2));
|
||||
assert_ok!(TokenWrapper::wrap(RuntimeOrigin::signed(user3), amount3));
|
||||
|
||||
// Verify balances
|
||||
assert_eq!(Assets::balance(0, &user1), amount1);
|
||||
assert_eq!(Assets::balance(0, &user2), amount2);
|
||||
assert_eq!(Assets::balance(0, &user3), amount3);
|
||||
|
||||
// Verify total locked
|
||||
assert_eq!(TokenWrapper::total_locked(), amount1 + amount2 + amount3);
|
||||
|
||||
// User 2 unwraps
|
||||
assert_ok!(TokenWrapper::unwrap(RuntimeOrigin::signed(user2), amount2));
|
||||
assert_eq!(Assets::balance(0, &user2), 0);
|
||||
assert_eq!(TokenWrapper::total_locked(), amount1 + amount3);
|
||||
|
||||
// User 1 and 3 still have their wrapped tokens
|
||||
assert_eq!(Assets::balance(0, &user1), amount1);
|
||||
assert_eq!(Assets::balance(0, &user3), amount3);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiple_wrap_operations_same_user() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let user = 1;
|
||||
|
||||
// Multiple wraps
|
||||
assert_ok!(TokenWrapper::wrap(RuntimeOrigin::signed(user), 100));
|
||||
assert_ok!(TokenWrapper::wrap(RuntimeOrigin::signed(user), 200));
|
||||
assert_ok!(TokenWrapper::wrap(RuntimeOrigin::signed(user), 300));
|
||||
|
||||
// Verify accumulated balance
|
||||
assert_eq!(Assets::balance(0, &user), 600);
|
||||
assert_eq!(TokenWrapper::total_locked(), 600);
|
||||
|
||||
// Partial unwrap
|
||||
assert_ok!(TokenWrapper::unwrap(RuntimeOrigin::signed(user), 250));
|
||||
assert_eq!(Assets::balance(0, &user), 350);
|
||||
assert_eq!(TokenWrapper::total_locked(), 350);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn events_emitted_correctly() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let user = 1;
|
||||
let amount = 1000;
|
||||
|
||||
// Wrap and check event
|
||||
assert_ok!(TokenWrapper::wrap(RuntimeOrigin::signed(user), amount));
|
||||
System::assert_has_event(Event::Wrapped { who: user, amount }.into());
|
||||
|
||||
// Unwrap and check event
|
||||
assert_ok!(TokenWrapper::unwrap(RuntimeOrigin::signed(user), amount));
|
||||
System::assert_has_event(Event::Unwrapped { who: user, amount }.into());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn total_locked_tracking_accuracy() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_eq!(TokenWrapper::total_locked(), 0);
|
||||
|
||||
let user1 = 1;
|
||||
let user2 = 2;
|
||||
|
||||
// User 1 wraps
|
||||
assert_ok!(TokenWrapper::wrap(RuntimeOrigin::signed(user1), 1000));
|
||||
assert_eq!(TokenWrapper::total_locked(), 1000);
|
||||
|
||||
// User 2 wraps
|
||||
assert_ok!(TokenWrapper::wrap(RuntimeOrigin::signed(user2), 500));
|
||||
assert_eq!(TokenWrapper::total_locked(), 1500);
|
||||
|
||||
// User 1 unwraps partially
|
||||
assert_ok!(TokenWrapper::unwrap(RuntimeOrigin::signed(user1), 300));
|
||||
assert_eq!(TokenWrapper::total_locked(), 1200);
|
||||
|
||||
// User 2 unwraps all
|
||||
assert_ok!(TokenWrapper::unwrap(RuntimeOrigin::signed(user2), 500));
|
||||
assert_eq!(TokenWrapper::total_locked(), 700);
|
||||
|
||||
// User 1 unwraps remaining
|
||||
assert_ok!(TokenWrapper::unwrap(RuntimeOrigin::signed(user1), 700));
|
||||
assert_eq!(TokenWrapper::total_locked(), 0);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn large_amount_wrap_unwrap() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let user = 1;
|
||||
// User has 10000 initial balance
|
||||
let large_amount = 9000; // Leave some for existential deposit
|
||||
|
||||
assert_ok!(TokenWrapper::wrap(RuntimeOrigin::signed(user), large_amount));
|
||||
assert_eq!(Assets::balance(0, &user), large_amount);
|
||||
assert_eq!(TokenWrapper::total_locked(), large_amount);
|
||||
|
||||
assert_ok!(TokenWrapper::unwrap(RuntimeOrigin::signed(user), large_amount));
|
||||
assert_eq!(Assets::balance(0, &user), 0);
|
||||
assert_eq!(TokenWrapper::total_locked(), 0);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pezpallet_account_balance_consistency() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let user = 1;
|
||||
let amount = 1000;
|
||||
let pezpallet_account = TokenWrapper::account_id();
|
||||
|
||||
let initial_pallet_balance = Balances::free_balance(&pezpallet_account);
|
||||
|
||||
// Wrap - pallet account should receive native tokens
|
||||
assert_ok!(TokenWrapper::wrap(RuntimeOrigin::signed(user), amount));
|
||||
assert_eq!(Balances::free_balance(&pezpallet_account), initial_pallet_balance + amount);
|
||||
|
||||
// Unwrap - pallet account should release native tokens
|
||||
assert_ok!(TokenWrapper::unwrap(RuntimeOrigin::signed(user), amount));
|
||||
assert_eq!(Balances::free_balance(&pezpallet_account), initial_pallet_balance);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wrap_unwrap_maintains_1_to_1_backing() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let users = vec![1, 2, 3];
|
||||
let amounts = vec![1000, 2000, 1500];
|
||||
|
||||
// All users wrap
|
||||
for (user, amount) in users.iter().zip(amounts.iter()) {
|
||||
assert_ok!(TokenWrapper::wrap(RuntimeOrigin::signed(*user), *amount));
|
||||
}
|
||||
|
||||
let total_wrapped = amounts.iter().sum::<u128>();
|
||||
let pezpallet_account = TokenWrapper::account_id();
|
||||
let pezpallet_balance = Balances::free_balance(&pezpallet_account);
|
||||
|
||||
// Pallet should hold exactly the amount of wrapped tokens
|
||||
// (Note: may include existential deposit, so check >= total_wrapped)
|
||||
assert!(pezpallet_balance >= total_wrapped);
|
||||
assert_eq!(TokenWrapper::total_locked(), total_wrapped);
|
||||
|
||||
// Verify total supply matches
|
||||
assert_eq!(Assets::total_issuance(0), total_wrapped);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
// 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_token_wrapper`
|
||||
//!
|
||||
//! 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/asset-hub-pezkuwichain-runtime/asset_hub_pezkuwichain_runtime.compact.compressed.wasm
|
||||
// --pallets
|
||||
// pezpallet_token_wrapper
|
||||
// -e
|
||||
// all
|
||||
// --steps
|
||||
// 50
|
||||
// --repeat
|
||||
// 20
|
||||
// --output
|
||||
// pezcumulus/teyrchains/pallets/token-wrapper/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_token_wrapper`.
|
||||
pub trait WeightInfo {
|
||||
fn wrap() -> Weight;
|
||||
fn unwrap() -> Weight;
|
||||
}
|
||||
|
||||
/// Weights for `pezpallet_token_wrapper` using the Bizinikiwi node and recommended hardware.
|
||||
pub struct BizinikiwiWeight<T>(PhantomData<T>);
|
||||
impl<T: pezframe_system::Config> WeightInfo for BizinikiwiWeight<T> {
|
||||
/// Storage: `System::Account` (r:1 w:1)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
/// Storage: `TokenWrapper::TotalLocked` (r:1 w:1)
|
||||
/// Proof: `TokenWrapper::TotalLocked` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Assets::Asset` (r:1 w:1)
|
||||
/// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Assets::Account` (r:1 w:1)
|
||||
/// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`)
|
||||
fn wrap() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `631`
|
||||
// Estimated: `3675`
|
||||
// Minimum execution time: 61_975_000 picoseconds.
|
||||
Weight::from_parts(63_198_000, 3675)
|
||||
.saturating_add(T::DbWeight::get().reads(4_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(4_u64))
|
||||
}
|
||||
/// Storage: `Assets::Account` (r:1 w:1)
|
||||
/// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Assets::Asset` (r:1 w:1)
|
||||
/// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`)
|
||||
/// Storage: `AssetsFreezer::FrozenBalances` (r:1 w:1)
|
||||
/// Proof: `AssetsFreezer::FrozenBalances` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`)
|
||||
/// Storage: `AssetsFreezer::Freezes` (r:1 w:1)
|
||||
/// Proof: `AssetsFreezer::Freezes` (`max_values`: None, `max_size`: Some(105), added: 2580, mode: `MaxEncodedLen`)
|
||||
/// Storage: `TokenWrapper::TotalLocked` (r:1 w:1)
|
||||
/// Proof: `TokenWrapper::TotalLocked` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`)
|
||||
/// Storage: `System::Account` (r:1 w:1)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
fn unwrap() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `713`
|
||||
// Estimated: `3675`
|
||||
// Minimum execution time: 87_171_000 picoseconds.
|
||||
Weight::from_parts(89_650_000, 3675)
|
||||
.saturating_add(T::DbWeight::get().reads(6_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(6_u64))
|
||||
}
|
||||
}
|
||||
|
||||
// For backwards compatibility and tests.
|
||||
impl WeightInfo for () {
|
||||
/// Storage: `System::Account` (r:1 w:1)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
/// Storage: `TokenWrapper::TotalLocked` (r:1 w:1)
|
||||
/// Proof: `TokenWrapper::TotalLocked` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Assets::Asset` (r:1 w:1)
|
||||
/// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Assets::Account` (r:1 w:1)
|
||||
/// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`)
|
||||
fn wrap() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `631`
|
||||
// Estimated: `3675`
|
||||
// Minimum execution time: 61_975_000 picoseconds.
|
||||
Weight::from_parts(63_198_000, 3675)
|
||||
.saturating_add(RocksDbWeight::get().reads(4_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(4_u64))
|
||||
}
|
||||
/// Storage: `Assets::Account` (r:1 w:1)
|
||||
/// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Assets::Asset` (r:1 w:1)
|
||||
/// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`)
|
||||
/// Storage: `AssetsFreezer::FrozenBalances` (r:1 w:1)
|
||||
/// Proof: `AssetsFreezer::FrozenBalances` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`)
|
||||
/// Storage: `AssetsFreezer::Freezes` (r:1 w:1)
|
||||
/// Proof: `AssetsFreezer::Freezes` (`max_values`: None, `max_size`: Some(105), added: 2580, mode: `MaxEncodedLen`)
|
||||
/// Storage: `TokenWrapper::TotalLocked` (r:1 w:1)
|
||||
/// Proof: `TokenWrapper::TotalLocked` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`)
|
||||
/// Storage: `System::Account` (r:1 w:1)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
fn unwrap() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `713`
|
||||
// Estimated: `3675`
|
||||
// Minimum execution time: 87_171_000 picoseconds.
|
||||
Weight::from_parts(89_650_000, 3675)
|
||||
.saturating_add(RocksDbWeight::get().reads(6_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(6_u64))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user