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,77 @@
|
||||
[package]
|
||||
name = "pezpallet-asset-rewards"
|
||||
version = "0.1.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license = "Apache-2.0"
|
||||
homepage.workspace = true
|
||||
repository.workspace = true
|
||||
description = "FRAME asset rewards pallet"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
||||
[dependencies]
|
||||
codec = { workspace = true }
|
||||
pezframe-benchmarking = { workspace = true, optional = true }
|
||||
pezframe-support = { workspace = true, features = ["experimental"] }
|
||||
pezframe-system = { workspace = true }
|
||||
scale-info = { workspace = true, features = ["derive"] }
|
||||
pezsp-api = { workspace = true }
|
||||
pezsp-arithmetic = { workspace = true }
|
||||
pezsp-core = { workspace = true }
|
||||
pezsp-io = { workspace = true }
|
||||
pezsp-runtime = { workspace = true }
|
||||
pezsp-std = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
pezpallet-assets = { workspace = true }
|
||||
pezpallet-assets-freezer = { workspace = true }
|
||||
pezpallet-balances = { workspace = true }
|
||||
primitive-types = { workspace = true, features = [
|
||||
"codec",
|
||||
"num-traits",
|
||||
"scale-info",
|
||||
] }
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = [
|
||||
"codec/std",
|
||||
"pezframe-benchmarking?/std",
|
||||
"pezframe-support/std",
|
||||
"pezframe-system/std",
|
||||
"pezpallet-assets-freezer/std",
|
||||
"pezpallet-assets/std",
|
||||
"pezpallet-balances/std",
|
||||
"primitive-types/std",
|
||||
"scale-info/std",
|
||||
"pezsp-api/std",
|
||||
"pezsp-arithmetic/std",
|
||||
"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-freezer/runtime-benchmarks",
|
||||
"pezpallet-assets/runtime-benchmarks",
|
||||
"pezpallet-balances/runtime-benchmarks",
|
||||
"pezsp-api/runtime-benchmarks",
|
||||
"pezsp-io/runtime-benchmarks",
|
||||
"pezsp-runtime/runtime-benchmarks",
|
||||
]
|
||||
try-runtime = [
|
||||
"pezframe-support/try-runtime",
|
||||
"pezframe-system/try-runtime",
|
||||
"pezpallet-assets-freezer/try-runtime",
|
||||
"pezpallet-assets/try-runtime",
|
||||
"pezpallet-balances/try-runtime",
|
||||
"pezsp-runtime/try-runtime",
|
||||
]
|
||||
@@ -0,0 +1,359 @@
|
||||
// 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.
|
||||
|
||||
//! Asset Rewards pallet benchmarking.
|
||||
|
||||
use super::*;
|
||||
use crate::Pallet as AssetRewards;
|
||||
use pezframe_benchmarking::{v2::*, whitelisted_caller, BenchmarkError};
|
||||
use pezframe_support::{
|
||||
assert_ok,
|
||||
traits::{
|
||||
fungibles::{Create, Inspect, Mutate},
|
||||
Consideration, EnsureOrigin, Footprint,
|
||||
},
|
||||
};
|
||||
use pezframe_system::{Pallet as System, RawOrigin};
|
||||
use pezsp_runtime::{traits::One, Saturating};
|
||||
use pezsp_std::prelude::*;
|
||||
|
||||
/// Benchmark Helper
|
||||
pub trait BenchmarkHelper<AssetId> {
|
||||
/// Returns the staked asset id.
|
||||
///
|
||||
/// If the asset does not exist, it will be created by the benchmark.
|
||||
fn staked_asset() -> AssetId;
|
||||
/// Returns the reward asset id.
|
||||
///
|
||||
/// If the asset does not exist, it will be created by the benchmark.
|
||||
fn reward_asset() -> AssetId;
|
||||
}
|
||||
|
||||
fn pool_expire<T: Config>() -> DispatchTime<BlockNumberFor<T>> {
|
||||
DispatchTime::At(BlockNumberFor::<T>::from(100u32))
|
||||
}
|
||||
|
||||
fn create_reward_pool<T: Config>() -> Result<T::RuntimeOrigin, BenchmarkError>
|
||||
where
|
||||
T::Assets: Create<T::AccountId> + Mutate<T::AccountId>,
|
||||
{
|
||||
let caller_origin =
|
||||
T::CreatePoolOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
|
||||
let caller = T::CreatePoolOrigin::ensure_origin(caller_origin.clone()).unwrap();
|
||||
|
||||
let footprint = Footprint::from_mel::<(PoolId, PoolInfoFor<T>)>();
|
||||
T::Consideration::ensure_successful(&caller, footprint);
|
||||
|
||||
let staked_asset = T::BenchmarkHelper::staked_asset();
|
||||
let reward_asset = T::BenchmarkHelper::reward_asset();
|
||||
|
||||
let min_staked_balance =
|
||||
T::Assets::minimum_balance(staked_asset.clone()).max(T::Balance::one());
|
||||
if !T::Assets::asset_exists(staked_asset.clone()) {
|
||||
assert_ok!(T::Assets::create(
|
||||
staked_asset.clone(),
|
||||
caller.clone(),
|
||||
true,
|
||||
min_staked_balance
|
||||
));
|
||||
}
|
||||
let min_reward_balance =
|
||||
T::Assets::minimum_balance(reward_asset.clone()).max(T::Balance::one());
|
||||
if !T::Assets::asset_exists(reward_asset.clone()) {
|
||||
assert_ok!(T::Assets::create(
|
||||
reward_asset.clone(),
|
||||
caller.clone(),
|
||||
true,
|
||||
min_reward_balance
|
||||
));
|
||||
}
|
||||
|
||||
assert_ok!(AssetRewards::<T>::create_pool(
|
||||
caller_origin.clone(),
|
||||
Box::new(staked_asset),
|
||||
Box::new(reward_asset),
|
||||
// reward rate per block
|
||||
min_reward_balance,
|
||||
pool_expire::<T>(),
|
||||
Some(caller),
|
||||
));
|
||||
|
||||
Ok(caller_origin)
|
||||
}
|
||||
|
||||
fn mint_into<T: Config>(caller: &T::AccountId, asset: &T::AssetId) -> T::Balance
|
||||
where
|
||||
T::Assets: Mutate<T::AccountId>,
|
||||
{
|
||||
let min_balance = T::Assets::minimum_balance(asset.clone());
|
||||
assert_ok!(T::Assets::mint_into(
|
||||
asset.clone(),
|
||||
&caller,
|
||||
min_balance.saturating_mul(10u32.into())
|
||||
));
|
||||
min_balance
|
||||
}
|
||||
|
||||
fn assert_last_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) {
|
||||
System::<T>::assert_last_event(generic_event.into());
|
||||
}
|
||||
|
||||
#[benchmarks(where T::Assets: Create<T::AccountId> + Mutate<T::AccountId>)]
|
||||
mod benchmarks {
|
||||
use super::*;
|
||||
|
||||
#[benchmark]
|
||||
fn create_pool() -> Result<(), BenchmarkError> {
|
||||
let caller_origin =
|
||||
T::CreatePoolOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
|
||||
let caller = T::CreatePoolOrigin::ensure_origin(caller_origin.clone()).unwrap();
|
||||
|
||||
let footprint = Footprint::from_mel::<(PoolId, PoolInfoFor<T>)>();
|
||||
T::Consideration::ensure_successful(&caller, footprint);
|
||||
|
||||
let staked_asset = T::BenchmarkHelper::staked_asset();
|
||||
let reward_asset = T::BenchmarkHelper::reward_asset();
|
||||
|
||||
let min_balance = T::Assets::minimum_balance(staked_asset.clone()).max(T::Balance::one());
|
||||
if !T::Assets::asset_exists(staked_asset.clone()) {
|
||||
assert_ok!(T::Assets::create(staked_asset.clone(), caller.clone(), true, min_balance));
|
||||
}
|
||||
let min_balance = T::Assets::minimum_balance(reward_asset.clone()).max(T::Balance::one());
|
||||
if !T::Assets::asset_exists(reward_asset.clone()) {
|
||||
assert_ok!(T::Assets::create(reward_asset.clone(), caller.clone(), true, min_balance));
|
||||
}
|
||||
|
||||
#[extrinsic_call]
|
||||
_(
|
||||
caller_origin as T::RuntimeOrigin,
|
||||
Box::new(staked_asset.clone()),
|
||||
Box::new(reward_asset.clone()),
|
||||
min_balance,
|
||||
pool_expire::<T>(),
|
||||
Some(caller.clone()),
|
||||
);
|
||||
|
||||
assert_last_event::<T>(
|
||||
Event::PoolCreated {
|
||||
creator: caller.clone(),
|
||||
admin: caller,
|
||||
staked_asset_id: staked_asset,
|
||||
reward_asset_id: reward_asset,
|
||||
reward_rate_per_block: min_balance,
|
||||
expiry_block: pool_expire::<T>()
|
||||
.evaluate(T::BlockNumberProvider::current_block_number()),
|
||||
pool_id: 0,
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn stake() -> Result<(), BenchmarkError> {
|
||||
create_reward_pool::<T>()?;
|
||||
|
||||
let staker: T::AccountId = whitelisted_caller();
|
||||
let min_balance = mint_into::<T>(&staker, &T::BenchmarkHelper::staked_asset());
|
||||
|
||||
// stake first to get worth case benchmark.
|
||||
assert_ok!(AssetRewards::<T>::stake(
|
||||
RawOrigin::Signed(staker.clone()).into(),
|
||||
0,
|
||||
min_balance
|
||||
));
|
||||
|
||||
#[extrinsic_call]
|
||||
_(RawOrigin::Signed(staker.clone()), 0, min_balance);
|
||||
|
||||
assert_last_event::<T>(Event::Staked { staker, pool_id: 0, amount: min_balance }.into());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn unstake() -> Result<(), BenchmarkError> {
|
||||
create_reward_pool::<T>()?;
|
||||
|
||||
let staker: T::AccountId = whitelisted_caller();
|
||||
let min_balance = mint_into::<T>(&staker, &T::BenchmarkHelper::staked_asset());
|
||||
|
||||
assert_ok!(AssetRewards::<T>::stake(
|
||||
RawOrigin::Signed(staker.clone()).into(),
|
||||
0,
|
||||
min_balance,
|
||||
));
|
||||
|
||||
#[extrinsic_call]
|
||||
_(RawOrigin::Signed(staker.clone()), 0, min_balance, None);
|
||||
|
||||
assert_last_event::<T>(
|
||||
Event::Unstaked { caller: staker.clone(), staker, pool_id: 0, amount: min_balance }
|
||||
.into(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn harvest_rewards() -> Result<(), BenchmarkError> {
|
||||
create_reward_pool::<T>()?;
|
||||
|
||||
let pool_acc = AssetRewards::<T>::pool_account_id(&0u32);
|
||||
let min_reward_balance = mint_into::<T>(&pool_acc, &T::BenchmarkHelper::reward_asset());
|
||||
|
||||
let staker = whitelisted_caller();
|
||||
let _ = mint_into::<T>(&staker, &T::BenchmarkHelper::staked_asset());
|
||||
assert_ok!(AssetRewards::<T>::stake(
|
||||
RawOrigin::Signed(staker.clone()).into(),
|
||||
0,
|
||||
T::Balance::one(),
|
||||
));
|
||||
|
||||
T::BlockNumberProvider::set_block_number(
|
||||
T::BlockNumberProvider::current_block_number() + BlockNumberFor::<T>::one(),
|
||||
);
|
||||
|
||||
#[extrinsic_call]
|
||||
_(RawOrigin::Signed(staker.clone()), 0, None);
|
||||
|
||||
assert_last_event::<T>(
|
||||
Event::RewardsHarvested {
|
||||
caller: staker.clone(),
|
||||
staker,
|
||||
pool_id: 0,
|
||||
amount: min_reward_balance,
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn set_pool_reward_rate_per_block() -> Result<(), BenchmarkError> {
|
||||
let caller_origin = create_reward_pool::<T>()?;
|
||||
|
||||
// stake first to get worth case benchmark.
|
||||
{
|
||||
let staker: T::AccountId = whitelisted_caller();
|
||||
let min_balance = mint_into::<T>(&staker, &T::BenchmarkHelper::staked_asset());
|
||||
|
||||
assert_ok!(AssetRewards::<T>::stake(RawOrigin::Signed(staker).into(), 0, min_balance));
|
||||
}
|
||||
|
||||
let new_reward_rate_per_block =
|
||||
T::Assets::minimum_balance(T::BenchmarkHelper::reward_asset()).max(T::Balance::one()) +
|
||||
T::Balance::one();
|
||||
|
||||
#[extrinsic_call]
|
||||
_(caller_origin as T::RuntimeOrigin, 0, new_reward_rate_per_block);
|
||||
|
||||
assert_last_event::<T>(
|
||||
Event::PoolRewardRateModified { pool_id: 0, new_reward_rate_per_block }.into(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn set_pool_admin() -> Result<(), BenchmarkError> {
|
||||
let caller_origin = create_reward_pool::<T>()?;
|
||||
let new_admin: T::AccountId = whitelisted_caller();
|
||||
|
||||
#[extrinsic_call]
|
||||
_(caller_origin as T::RuntimeOrigin, 0, new_admin.clone());
|
||||
|
||||
assert_last_event::<T>(Event::PoolAdminModified { pool_id: 0, new_admin }.into());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn set_pool_expiry_block() -> Result<(), BenchmarkError> {
|
||||
let create_origin = create_reward_pool::<T>()?;
|
||||
|
||||
// stake first to get worth case benchmark.
|
||||
{
|
||||
let staker: T::AccountId = whitelisted_caller();
|
||||
let min_balance = mint_into::<T>(&staker, &T::BenchmarkHelper::staked_asset());
|
||||
|
||||
assert_ok!(AssetRewards::<T>::stake(RawOrigin::Signed(staker).into(), 0, min_balance));
|
||||
}
|
||||
|
||||
let new_expiry_block = pool_expire::<T>()
|
||||
.evaluate(T::BlockNumberProvider::current_block_number()) +
|
||||
BlockNumberFor::<T>::one();
|
||||
|
||||
#[extrinsic_call]
|
||||
_(create_origin as T::RuntimeOrigin, 0, DispatchTime::At(new_expiry_block));
|
||||
|
||||
assert_last_event::<T>(
|
||||
Event::PoolExpiryBlockModified { pool_id: 0, new_expiry_block }.into(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn deposit_reward_tokens() -> Result<(), BenchmarkError> {
|
||||
create_reward_pool::<T>()?;
|
||||
let caller = whitelisted_caller();
|
||||
|
||||
let reward_asset = T::BenchmarkHelper::reward_asset();
|
||||
let pool_acc = AssetRewards::<T>::pool_account_id(&0u32);
|
||||
let min_balance = mint_into::<T>(&caller, &reward_asset);
|
||||
|
||||
let balance_before = T::Assets::balance(reward_asset.clone(), &pool_acc);
|
||||
|
||||
#[extrinsic_call]
|
||||
_(RawOrigin::Signed(caller), 0, min_balance);
|
||||
|
||||
let balance_after = T::Assets::balance(reward_asset, &pool_acc);
|
||||
|
||||
assert_eq!(balance_after, balance_before + min_balance);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn cleanup_pool() -> Result<(), BenchmarkError> {
|
||||
let create_origin = create_reward_pool::<T>()?;
|
||||
let caller = T::CreatePoolOrigin::ensure_origin(create_origin.clone()).unwrap();
|
||||
|
||||
// deposit rewards tokens to get worth case benchmark.
|
||||
{
|
||||
let caller = whitelisted_caller();
|
||||
let reward_asset = T::BenchmarkHelper::reward_asset();
|
||||
let min_balance = mint_into::<T>(&caller, &reward_asset);
|
||||
assert_ok!(AssetRewards::<T>::deposit_reward_tokens(
|
||||
RawOrigin::Signed(caller).into(),
|
||||
0,
|
||||
min_balance
|
||||
));
|
||||
}
|
||||
|
||||
#[extrinsic_call]
|
||||
_(RawOrigin::Signed(caller), 0);
|
||||
|
||||
assert_last_event::<T>(Event::PoolCleanedUp { pool_id: 0 }.into());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl_benchmark_test_suite!(AssetRewards, crate::mock::new_test_ext(), crate::mock::MockRuntime);
|
||||
}
|
||||
@@ -0,0 +1,964 @@
|
||||
// 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.
|
||||
|
||||
//! # FRAME Staking Rewards Pallet
|
||||
//!
|
||||
//! Allows accounts to be rewarded for holding `fungible` asset/s, for example LP tokens.
|
||||
//!
|
||||
//! ## Overview
|
||||
//!
|
||||
//! Initiate an incentive program for a fungible asset by creating a new pool.
|
||||
//!
|
||||
//! During pool creation, a 'staking asset', 'reward asset', 'reward rate per block', 'expiry
|
||||
//! block', and 'admin' are specified.
|
||||
//!
|
||||
//! Once created, holders of the 'staking asset' can 'stake' them in a corresponding pool, which
|
||||
//! creates a Freeze on the asset.
|
||||
//!
|
||||
//! Once staked, rewards denominated in 'reward asset' begin accumulating to the staker,
|
||||
//! proportional to their share of the total staked tokens in the pool.
|
||||
//!
|
||||
//! Reward assets pending distribution are held in an account unique to each pool.
|
||||
//!
|
||||
//! Care should be taken by the pool operator to keep pool accounts adequately funded with the
|
||||
//! reward asset.
|
||||
//!
|
||||
//! The pool admin may increase reward rate per block, increase expiry block, and change admin.
|
||||
//!
|
||||
//! ## Disambiguation
|
||||
//!
|
||||
//! While this pallet shares some terminology with the `staking-pool` and similar native staking
|
||||
//! related pallets, it is distinct and is entirely unrelated to native staking.
|
||||
//!
|
||||
//! ## Permissioning
|
||||
//!
|
||||
//! Currently, pool creation and management restricted to a configured Origin.
|
||||
//!
|
||||
//! Future iterations of this pallet may allow permissionless creation and management of pools.
|
||||
//!
|
||||
//! Note: The permissioned origin must return an AccountId. This can be achieved for any Origin by
|
||||
//! wrapping it with `EnsureSuccess`.
|
||||
//!
|
||||
//! ## Implementation Notes
|
||||
//!
|
||||
//! Internal logic functions such as `update_pool_and_staker_rewards` were deliberately written
|
||||
//! without side-effects.
|
||||
//!
|
||||
//! Storage interaction such as reads and writes are instead all performed in the top level
|
||||
//! pallet Call method, which while slightly more verbose, makes it easier to understand the
|
||||
//! code and reason about how storage reads and writes occur in the pallet.
|
||||
//!
|
||||
//! ## Rewards Algorithm
|
||||
//!
|
||||
//! The rewards algorithm is based on the Synthetix [StakingRewards.sol](https://github.com/Synthetixio/synthetix/blob/develop/contracts/StakingRewards.sol)
|
||||
//! smart contract.
|
||||
//!
|
||||
//! Rewards are calculated JIT (just-in-time), and all operations are O(1) making the approach
|
||||
//! scalable to many pools and stakers.
|
||||
//!
|
||||
//! ### Resources
|
||||
//!
|
||||
//! - [This video series](https://www.youtube.com/watch?v=6ZO5aYg1GI8), which walks through the math
|
||||
//! of the algorithm.
|
||||
//! - [This dev.to article](https://dev.to/heymarkkop/understanding-sushiswaps-masterchef-staking-rewards-1m6f),
|
||||
//! which explains the algorithm of the SushiSwap MasterChef staking. While not identical to the
|
||||
//! Synthetix approach, they are quite similar.
|
||||
#![deny(missing_docs)]
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
pub use pallet::*;
|
||||
|
||||
use codec::{Codec, Decode, Encode, MaxEncodedLen};
|
||||
use pezframe_support::{
|
||||
ensure,
|
||||
traits::{
|
||||
fungibles::{Inspect, Mutate},
|
||||
schedule::DispatchTime,
|
||||
tokens::Balance,
|
||||
Consideration, RewardsPool,
|
||||
},
|
||||
PalletId,
|
||||
};
|
||||
use scale_info::TypeInfo;
|
||||
use pezsp_core::Get;
|
||||
use pezsp_runtime::{
|
||||
traits::{BadOrigin, BlockNumberProvider, EnsureAdd, MaybeDisplay, Zero},
|
||||
DispatchError, DispatchResult,
|
||||
};
|
||||
use pezsp_std::boxed::Box;
|
||||
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
pub mod benchmarking;
|
||||
#[cfg(test)]
|
||||
mod mock;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
mod weights;
|
||||
|
||||
pub use weights::WeightInfo;
|
||||
|
||||
/// Unique id type for each pool.
|
||||
pub type PoolId = u32;
|
||||
|
||||
/// Multiplier to maintain precision when calculating rewards.
|
||||
pub(crate) const PRECISION_SCALING_FACTOR: u16 = 4096;
|
||||
|
||||
/// Convenience alias for `PoolInfo`.
|
||||
pub type PoolInfoFor<T> = PoolInfo<
|
||||
<T as pezframe_system::Config>::AccountId,
|
||||
<T as Config>::AssetId,
|
||||
<T as Config>::Balance,
|
||||
BlockNumberFor<T>,
|
||||
>;
|
||||
|
||||
/// The block number type for the pallet.
|
||||
///
|
||||
/// This type is derived from the `BlockNumberProvider` associated type in the `Config` trait.
|
||||
/// It represents the block number type that the pallet uses for scheduling and expiration.
|
||||
pub type BlockNumberFor<T> =
|
||||
<<T as Config>::BlockNumberProvider as BlockNumberProvider>::BlockNumber;
|
||||
|
||||
/// The state of a staker in a pool.
|
||||
#[derive(Debug, Default, Clone, Decode, Encode, MaxEncodedLen, TypeInfo)]
|
||||
pub struct PoolStakerInfo<Balance> {
|
||||
/// Amount of tokens staked.
|
||||
amount: Balance,
|
||||
/// Accumulated, unpaid rewards.
|
||||
rewards: Balance,
|
||||
/// Reward per token value at the time of the staker's last interaction with the contract.
|
||||
reward_per_token_paid: Balance,
|
||||
}
|
||||
|
||||
/// The state and configuration of an incentive pool.
|
||||
#[derive(Debug, Clone, Decode, Encode, Default, PartialEq, Eq, MaxEncodedLen, TypeInfo)]
|
||||
pub struct PoolInfo<AccountId, AssetId, Balance, BlockNumber> {
|
||||
/// The asset staked in this pool.
|
||||
staked_asset_id: AssetId,
|
||||
/// The asset distributed as rewards by this pool.
|
||||
reward_asset_id: AssetId,
|
||||
/// The amount of tokens rewarded per block.
|
||||
reward_rate_per_block: Balance,
|
||||
/// The block the pool will cease distributing rewards.
|
||||
expiry_block: BlockNumber,
|
||||
/// The account authorized to manage this pool.
|
||||
admin: AccountId,
|
||||
/// The total amount of tokens staked in this pool.
|
||||
total_tokens_staked: Balance,
|
||||
/// Total rewards accumulated per token, up to the `last_update_block`.
|
||||
reward_per_token_stored: Balance,
|
||||
/// Last block number the pool was updated.
|
||||
last_update_block: BlockNumber,
|
||||
/// The account that holds the pool's rewards.
|
||||
account: AccountId,
|
||||
}
|
||||
|
||||
pezsp_api::decl_runtime_apis! {
|
||||
/// The runtime API for the asset rewards pallet.
|
||||
pub trait AssetRewards<Cost: MaybeDisplay + Codec> {
|
||||
/// Get the cost of creating a pool.
|
||||
///
|
||||
/// This is especially useful when the cost is dynamic.
|
||||
fn pool_creation_cost() -> Cost;
|
||||
}
|
||||
}
|
||||
|
||||
#[pezframe_support::pallet]
|
||||
pub mod pallet {
|
||||
use super::*;
|
||||
use pezframe_support::{
|
||||
pezpallet_prelude::*,
|
||||
traits::{
|
||||
fungibles::MutateFreeze,
|
||||
tokens::{AssetId, Fortitude, Preservation},
|
||||
Consideration, Footprint, RewardsPool,
|
||||
},
|
||||
};
|
||||
use pezframe_system::pezpallet_prelude::{
|
||||
ensure_signed, BlockNumberFor as SystemBlockNumberFor, OriginFor,
|
||||
};
|
||||
use pezsp_runtime::{
|
||||
traits::{
|
||||
AccountIdConversion, BadOrigin, EnsureAdd, EnsureAddAssign, EnsureDiv, EnsureMul,
|
||||
EnsureSub, EnsureSubAssign,
|
||||
},
|
||||
DispatchResult,
|
||||
};
|
||||
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T>(_);
|
||||
|
||||
/// A reason for the pallet placing a hold on funds.
|
||||
#[pallet::composite_enum]
|
||||
pub enum FreezeReason {
|
||||
/// Funds are staked in the pallet.
|
||||
#[codec(index = 0)]
|
||||
Staked,
|
||||
}
|
||||
|
||||
/// A reason for the pallet placing a hold on funds.
|
||||
#[pallet::composite_enum]
|
||||
pub enum HoldReason {
|
||||
/// Cost associated with storing pool information on-chain.
|
||||
#[codec(index = 0)]
|
||||
PoolCreation,
|
||||
}
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config: pezframe_system::Config {
|
||||
/// Overarching event type.
|
||||
#[allow(deprecated)]
|
||||
type RuntimeEvent: From<Event<Self>> + IsType<<Self as pezframe_system::Config>::RuntimeEvent>;
|
||||
|
||||
/// The pallet's unique identifier, used to derive the pool's account ID.
|
||||
///
|
||||
/// The account ID is derived once during pool creation and stored in the storage.
|
||||
#[pallet::constant]
|
||||
type PalletId: Get<PalletId>;
|
||||
|
||||
/// Identifier for each type of asset.
|
||||
type AssetId: AssetId + Member + Parameter;
|
||||
|
||||
/// The type in which the assets are measured.
|
||||
type Balance: Balance + TypeInfo;
|
||||
|
||||
/// The origin with permission to create pools.
|
||||
///
|
||||
/// The Origin must return an AccountId.
|
||||
type CreatePoolOrigin: EnsureOrigin<Self::RuntimeOrigin, Success = Self::AccountId>;
|
||||
|
||||
/// Registry of assets that can be configured to either stake for rewards, or be offered as
|
||||
/// rewards for staking.
|
||||
type Assets: Inspect<Self::AccountId, AssetId = Self::AssetId, Balance = Self::Balance>
|
||||
+ Mutate<Self::AccountId>;
|
||||
|
||||
/// Freezer for the Assets.
|
||||
type AssetsFreezer: MutateFreeze<
|
||||
Self::AccountId,
|
||||
Id = Self::RuntimeFreezeReason,
|
||||
AssetId = Self::AssetId,
|
||||
Balance = Self::Balance,
|
||||
>;
|
||||
|
||||
/// The overarching freeze reason.
|
||||
type RuntimeFreezeReason: From<FreezeReason>;
|
||||
|
||||
/// Means for associating a cost with the on-chain storage of pool information, which
|
||||
/// is incurred by the pool creator.
|
||||
///
|
||||
/// The passed `Footprint` specifically accounts for the storage footprint of the pool's
|
||||
/// information itself, excluding any potential storage footprint related to the stakers.
|
||||
type Consideration: Consideration<Self::AccountId, Footprint>;
|
||||
|
||||
/// Weight information for extrinsics in this pallet.
|
||||
type WeightInfo: WeightInfo;
|
||||
|
||||
/// Provider for the current block number.
|
||||
///
|
||||
/// This provider is used to determine the current block number for the pallet.
|
||||
/// It must return monotonically increasing values when called from consecutive blocks.
|
||||
///
|
||||
/// It can be configured to use the local block number (via `pezframe_system::Pallet`) or a
|
||||
/// remote block number (e.g., from a relay chain). However, note that using a remote
|
||||
/// block number might have implications for the behavior of the pallet, especially if the
|
||||
/// remote block number advances faster than the local block number.
|
||||
///
|
||||
/// It is recommended to use the local block number for solo chains and relay chains.
|
||||
type BlockNumberProvider: BlockNumberProvider;
|
||||
|
||||
/// Helper for benchmarking.
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
type BenchmarkHelper: benchmarking::BenchmarkHelper<Self::AssetId>;
|
||||
}
|
||||
|
||||
/// State of pool stakers.
|
||||
#[pallet::storage]
|
||||
pub type PoolStakers<T: Config> = StorageDoubleMap<
|
||||
_,
|
||||
Blake2_128Concat,
|
||||
PoolId,
|
||||
Blake2_128Concat,
|
||||
T::AccountId,
|
||||
PoolStakerInfo<T::Balance>,
|
||||
>;
|
||||
|
||||
/// State and configuration of each staking pool.
|
||||
#[pallet::storage]
|
||||
pub type Pools<T: Config> = StorageMap<_, Blake2_128Concat, PoolId, PoolInfoFor<T>>;
|
||||
|
||||
/// The cost associated with storing pool information on-chain which was incurred by the pool
|
||||
/// creator.
|
||||
///
|
||||
/// This cost may be [`None`], as determined by [`Config::Consideration`].
|
||||
#[pallet::storage]
|
||||
pub type PoolCost<T: Config> =
|
||||
StorageMap<_, Blake2_128Concat, PoolId, (T::AccountId, T::Consideration)>;
|
||||
|
||||
/// Stores the [`PoolId`] to use for the next pool.
|
||||
///
|
||||
/// Incremented when a new pool is created.
|
||||
#[pallet::storage]
|
||||
pub type NextPoolId<T: Config> = StorageValue<_, PoolId, ValueQuery>;
|
||||
|
||||
#[pallet::event]
|
||||
#[pallet::generate_deposit(pub(super) fn deposit_event)]
|
||||
pub enum Event<T: Config> {
|
||||
/// An account staked some tokens in a pool.
|
||||
Staked {
|
||||
/// The account that staked assets.
|
||||
staker: T::AccountId,
|
||||
/// The pool.
|
||||
pool_id: PoolId,
|
||||
/// The staked asset amount.
|
||||
amount: T::Balance,
|
||||
},
|
||||
/// An account unstaked some tokens from a pool.
|
||||
Unstaked {
|
||||
/// The account that signed transaction.
|
||||
caller: T::AccountId,
|
||||
/// The account that unstaked assets.
|
||||
staker: T::AccountId,
|
||||
/// The pool.
|
||||
pool_id: PoolId,
|
||||
/// The unstaked asset amount.
|
||||
amount: T::Balance,
|
||||
},
|
||||
/// An account harvested some rewards.
|
||||
RewardsHarvested {
|
||||
/// The account that signed transaction.
|
||||
caller: T::AccountId,
|
||||
/// The staker whos rewards were harvested.
|
||||
staker: T::AccountId,
|
||||
/// The pool.
|
||||
pool_id: PoolId,
|
||||
/// The amount of harvested tokens.
|
||||
amount: T::Balance,
|
||||
},
|
||||
/// A new reward pool was created.
|
||||
PoolCreated {
|
||||
/// The account that created the pool.
|
||||
creator: T::AccountId,
|
||||
/// The unique ID for the new pool.
|
||||
pool_id: PoolId,
|
||||
/// The staking asset.
|
||||
staked_asset_id: T::AssetId,
|
||||
/// The reward asset.
|
||||
reward_asset_id: T::AssetId,
|
||||
/// The initial reward rate per block.
|
||||
reward_rate_per_block: T::Balance,
|
||||
/// The block the pool will cease to accumulate rewards.
|
||||
expiry_block: BlockNumberFor<T>,
|
||||
/// The account allowed to modify the pool.
|
||||
admin: T::AccountId,
|
||||
},
|
||||
/// A pool reward rate was modified by the admin.
|
||||
PoolRewardRateModified {
|
||||
/// The modified pool.
|
||||
pool_id: PoolId,
|
||||
/// The new reward rate per block.
|
||||
new_reward_rate_per_block: T::Balance,
|
||||
},
|
||||
/// A pool admin was modified.
|
||||
PoolAdminModified {
|
||||
/// The modified pool.
|
||||
pool_id: PoolId,
|
||||
/// The new admin.
|
||||
new_admin: T::AccountId,
|
||||
},
|
||||
/// A pool expiry block was modified by the admin.
|
||||
PoolExpiryBlockModified {
|
||||
/// The modified pool.
|
||||
pool_id: PoolId,
|
||||
/// The new expiry block.
|
||||
new_expiry_block: BlockNumberFor<T>,
|
||||
},
|
||||
/// A pool information was cleared after it's completion.
|
||||
PoolCleanedUp {
|
||||
/// The cleared pool.
|
||||
pool_id: PoolId,
|
||||
},
|
||||
}
|
||||
|
||||
#[pallet::error]
|
||||
pub enum Error<T> {
|
||||
/// The staker does not have enough tokens to perform the operation.
|
||||
NotEnoughTokens,
|
||||
/// An operation was attempted on a non-existent pool.
|
||||
NonExistentPool,
|
||||
/// An operation was attempted for a non-existent staker.
|
||||
NonExistentStaker,
|
||||
/// An operation was attempted with a non-existent asset.
|
||||
NonExistentAsset,
|
||||
/// There was an error converting a block number.
|
||||
BlockNumberConversionError,
|
||||
/// The expiry block must be in the future.
|
||||
ExpiryBlockMustBeInTheFuture,
|
||||
/// Insufficient funds to create the freeze.
|
||||
InsufficientFunds,
|
||||
/// The expiry block can be only extended.
|
||||
ExpiryCut,
|
||||
/// The reward rate per block can be only increased.
|
||||
RewardRateCut,
|
||||
/// The pool still has staked tokens or rewards.
|
||||
NonEmptyPool,
|
||||
}
|
||||
|
||||
#[pallet::hooks]
|
||||
impl<T: Config> Hooks<SystemBlockNumberFor<T>> for Pallet<T> {
|
||||
fn integrity_test() {
|
||||
// The AccountId is at least 16 bytes to contain the unique PalletId.
|
||||
let pool_id: PoolId = 1;
|
||||
assert!(
|
||||
<pezframe_support::PalletId as AccountIdConversion<T::AccountId>>::try_into_sub_account(
|
||||
&T::PalletId::get(), pool_id,
|
||||
)
|
||||
.is_some()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Pallet's callable functions.
|
||||
#[pallet::call(weight(<T as Config>::WeightInfo))]
|
||||
impl<T: Config> Pallet<T> {
|
||||
/// Create a new reward pool.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - `origin`: must be `Config::CreatePoolOrigin`;
|
||||
/// - `staked_asset_id`: the asset to be staked in the pool;
|
||||
/// - `reward_asset_id`: the asset to be distributed as rewards;
|
||||
/// - `reward_rate_per_block`: the amount of reward tokens distributed per block;
|
||||
/// - `expiry`: the block number at which the pool will cease to accumulate rewards. The
|
||||
/// [`DispatchTime::After`] variant evaluated at the execution time.
|
||||
/// - `admin`: the account allowed to extend the pool expiration, increase the rewards rate
|
||||
/// and receive the unutilized reward tokens back after the pool completion. If `None`,
|
||||
/// the caller is set as an admin.
|
||||
#[pallet::call_index(0)]
|
||||
pub fn create_pool(
|
||||
origin: OriginFor<T>,
|
||||
staked_asset_id: Box<T::AssetId>,
|
||||
reward_asset_id: Box<T::AssetId>,
|
||||
reward_rate_per_block: T::Balance,
|
||||
expiry: DispatchTime<BlockNumberFor<T>>,
|
||||
admin: Option<T::AccountId>,
|
||||
) -> DispatchResult {
|
||||
let creator = T::CreatePoolOrigin::ensure_origin(origin)?;
|
||||
<Self as RewardsPool<_>>::create_pool(
|
||||
&creator,
|
||||
*staked_asset_id,
|
||||
*reward_asset_id,
|
||||
reward_rate_per_block,
|
||||
expiry,
|
||||
&admin.unwrap_or_else(|| creator.clone()),
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Stake additional tokens in a pool.
|
||||
///
|
||||
/// A freeze is placed on the staked tokens.
|
||||
#[pallet::call_index(1)]
|
||||
pub fn stake(origin: OriginFor<T>, pool_id: PoolId, amount: T::Balance) -> DispatchResult {
|
||||
let staker = ensure_signed(origin)?;
|
||||
|
||||
// Always start by updating staker and pool rewards.
|
||||
let pool_info = Pools::<T>::get(pool_id).ok_or(Error::<T>::NonExistentPool)?;
|
||||
let staker_info = PoolStakers::<T>::get(pool_id, &staker).unwrap_or_default();
|
||||
let (mut pool_info, mut staker_info) =
|
||||
Self::update_pool_and_staker_rewards(&pool_info, &staker_info)?;
|
||||
|
||||
T::AssetsFreezer::increase_frozen(
|
||||
pool_info.staked_asset_id.clone(),
|
||||
&FreezeReason::Staked.into(),
|
||||
&staker,
|
||||
amount,
|
||||
)?;
|
||||
|
||||
// Update Pools.
|
||||
pool_info.total_tokens_staked.ensure_add_assign(amount)?;
|
||||
|
||||
Pools::<T>::insert(pool_id, pool_info);
|
||||
|
||||
// Update PoolStakers.
|
||||
staker_info.amount.ensure_add_assign(amount)?;
|
||||
PoolStakers::<T>::insert(pool_id, &staker, staker_info);
|
||||
|
||||
// Emit event.
|
||||
Self::deposit_event(Event::Staked { staker, pool_id, amount });
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Unstake tokens from a pool.
|
||||
///
|
||||
/// Removes the freeze on the staked tokens.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - origin: must be the `staker` if the pool is still active. Otherwise, any account.
|
||||
/// - pool_id: the pool to unstake from.
|
||||
/// - amount: the amount of tokens to unstake.
|
||||
/// - staker: the account to unstake from. If `None`, the caller is used.
|
||||
#[pallet::call_index(2)]
|
||||
pub fn unstake(
|
||||
origin: OriginFor<T>,
|
||||
pool_id: PoolId,
|
||||
amount: T::Balance,
|
||||
staker: Option<T::AccountId>,
|
||||
) -> DispatchResult {
|
||||
let caller = ensure_signed(origin)?;
|
||||
let staker = staker.unwrap_or(caller.clone());
|
||||
|
||||
// Always start by updating the pool rewards.
|
||||
let pool_info = Pools::<T>::get(pool_id).ok_or(Error::<T>::NonExistentPool)?;
|
||||
let now = T::BlockNumberProvider::current_block_number();
|
||||
ensure!(now > pool_info.expiry_block || caller == staker, BadOrigin);
|
||||
|
||||
let staker_info = PoolStakers::<T>::get(pool_id, &staker).unwrap_or_default();
|
||||
let (mut pool_info, mut staker_info) =
|
||||
Self::update_pool_and_staker_rewards(&pool_info, &staker_info)?;
|
||||
|
||||
// Check the staker has enough staked tokens.
|
||||
ensure!(staker_info.amount >= amount, Error::<T>::NotEnoughTokens);
|
||||
|
||||
// Unfreeze staker assets.
|
||||
T::AssetsFreezer::decrease_frozen(
|
||||
pool_info.staked_asset_id.clone(),
|
||||
&FreezeReason::Staked.into(),
|
||||
&staker,
|
||||
amount,
|
||||
)?;
|
||||
|
||||
// Update Pools.
|
||||
pool_info.total_tokens_staked.ensure_sub_assign(amount)?;
|
||||
Pools::<T>::insert(pool_id, pool_info);
|
||||
|
||||
// Update PoolStakers.
|
||||
staker_info.amount.ensure_sub_assign(amount)?;
|
||||
|
||||
if staker_info.amount.is_zero() && staker_info.rewards.is_zero() {
|
||||
PoolStakers::<T>::remove(&pool_id, &staker);
|
||||
} else {
|
||||
PoolStakers::<T>::insert(&pool_id, &staker, staker_info);
|
||||
}
|
||||
|
||||
// Emit event.
|
||||
Self::deposit_event(Event::Unstaked { caller, staker, pool_id, amount });
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Harvest unclaimed pool rewards.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - origin: must be the `staker` if the pool is still active. Otherwise, any account.
|
||||
/// - pool_id: the pool to harvest from.
|
||||
/// - staker: the account for which to harvest rewards. If `None`, the caller is used.
|
||||
#[pallet::call_index(3)]
|
||||
pub fn harvest_rewards(
|
||||
origin: OriginFor<T>,
|
||||
pool_id: PoolId,
|
||||
staker: Option<T::AccountId>,
|
||||
) -> DispatchResult {
|
||||
let caller = ensure_signed(origin)?;
|
||||
let staker = staker.unwrap_or(caller.clone());
|
||||
|
||||
// Always start by updating the pool and staker rewards.
|
||||
let pool_info = Pools::<T>::get(pool_id).ok_or(Error::<T>::NonExistentPool)?;
|
||||
let now = T::BlockNumberProvider::current_block_number();
|
||||
ensure!(now > pool_info.expiry_block || caller == staker, BadOrigin);
|
||||
|
||||
let staker_info =
|
||||
PoolStakers::<T>::get(pool_id, &staker).ok_or(Error::<T>::NonExistentStaker)?;
|
||||
let (pool_info, mut staker_info) =
|
||||
Self::update_pool_and_staker_rewards(&pool_info, &staker_info)?;
|
||||
|
||||
// Transfer unclaimed rewards from the pool to the staker.
|
||||
T::Assets::transfer(
|
||||
pool_info.reward_asset_id,
|
||||
&pool_info.account,
|
||||
&staker,
|
||||
staker_info.rewards,
|
||||
// Could kill the account, but only if the pool was already almost empty.
|
||||
Preservation::Expendable,
|
||||
)?;
|
||||
|
||||
// Emit event.
|
||||
Self::deposit_event(Event::RewardsHarvested {
|
||||
caller,
|
||||
staker: staker.clone(),
|
||||
pool_id,
|
||||
amount: staker_info.rewards,
|
||||
});
|
||||
|
||||
// Reset staker rewards.
|
||||
staker_info.rewards = 0u32.into();
|
||||
|
||||
if staker_info.amount.is_zero() {
|
||||
PoolStakers::<T>::remove(&pool_id, &staker);
|
||||
} else {
|
||||
PoolStakers::<T>::insert(&pool_id, &staker, staker_info);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Modify a pool reward rate.
|
||||
///
|
||||
/// Currently the reward rate can only be increased.
|
||||
///
|
||||
/// Only the pool admin may perform this operation.
|
||||
#[pallet::call_index(4)]
|
||||
pub fn set_pool_reward_rate_per_block(
|
||||
origin: OriginFor<T>,
|
||||
pool_id: PoolId,
|
||||
new_reward_rate_per_block: T::Balance,
|
||||
) -> DispatchResult {
|
||||
let caller = T::CreatePoolOrigin::ensure_origin(origin.clone())
|
||||
.or_else(|_| ensure_signed(origin))?;
|
||||
<Self as RewardsPool<_>>::set_pool_reward_rate_per_block(
|
||||
&caller,
|
||||
pool_id,
|
||||
new_reward_rate_per_block,
|
||||
)
|
||||
}
|
||||
|
||||
/// Modify a pool admin.
|
||||
///
|
||||
/// Only the pool admin may perform this operation.
|
||||
#[pallet::call_index(5)]
|
||||
pub fn set_pool_admin(
|
||||
origin: OriginFor<T>,
|
||||
pool_id: PoolId,
|
||||
new_admin: T::AccountId,
|
||||
) -> DispatchResult {
|
||||
let caller = T::CreatePoolOrigin::ensure_origin(origin.clone())
|
||||
.or_else(|_| ensure_signed(origin))?;
|
||||
<Self as RewardsPool<_>>::set_pool_admin(&caller, pool_id, new_admin)
|
||||
}
|
||||
|
||||
/// Set when the pool should expire.
|
||||
///
|
||||
/// Currently the expiry block can only be extended.
|
||||
///
|
||||
/// Only the pool admin may perform this operation.
|
||||
#[pallet::call_index(6)]
|
||||
pub fn set_pool_expiry_block(
|
||||
origin: OriginFor<T>,
|
||||
pool_id: PoolId,
|
||||
new_expiry: DispatchTime<BlockNumberFor<T>>,
|
||||
) -> DispatchResult {
|
||||
let caller = T::CreatePoolOrigin::ensure_origin(origin.clone())
|
||||
.or_else(|_| ensure_signed(origin))?;
|
||||
<Self as RewardsPool<_>>::set_pool_expiry_block(&caller, pool_id, new_expiry)
|
||||
}
|
||||
|
||||
/// Convenience method to deposit reward tokens into a pool.
|
||||
///
|
||||
/// This method is not strictly necessary (tokens could be transferred directly to the
|
||||
/// pool pot address), but is provided for convenience so manual derivation of the
|
||||
/// account id is not required.
|
||||
#[pallet::call_index(7)]
|
||||
pub fn deposit_reward_tokens(
|
||||
origin: OriginFor<T>,
|
||||
pool_id: PoolId,
|
||||
amount: T::Balance,
|
||||
) -> DispatchResult {
|
||||
let caller = ensure_signed(origin)?;
|
||||
let pool_info = Pools::<T>::get(pool_id).ok_or(Error::<T>::NonExistentPool)?;
|
||||
T::Assets::transfer(
|
||||
pool_info.reward_asset_id,
|
||||
&caller,
|
||||
&pool_info.account,
|
||||
amount,
|
||||
Preservation::Preserve,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Cleanup a pool.
|
||||
///
|
||||
/// Origin must be the pool admin.
|
||||
///
|
||||
/// Cleanup storage, release any associated storage cost and return the remaining reward
|
||||
/// tokens to the admin.
|
||||
#[pallet::call_index(8)]
|
||||
pub fn cleanup_pool(origin: OriginFor<T>, pool_id: PoolId) -> DispatchResult {
|
||||
let who = ensure_signed(origin)?;
|
||||
|
||||
let pool_info = Pools::<T>::get(pool_id).ok_or(Error::<T>::NonExistentPool)?;
|
||||
ensure!(pool_info.admin == who, BadOrigin);
|
||||
|
||||
let stakers = PoolStakers::<T>::iter_key_prefix(pool_id).next();
|
||||
ensure!(stakers.is_none(), Error::<T>::NonEmptyPool);
|
||||
|
||||
let pool_balance = T::Assets::reducible_balance(
|
||||
pool_info.reward_asset_id.clone(),
|
||||
&pool_info.account,
|
||||
Preservation::Expendable,
|
||||
Fortitude::Polite,
|
||||
);
|
||||
T::Assets::transfer(
|
||||
pool_info.reward_asset_id,
|
||||
&pool_info.account,
|
||||
&pool_info.admin,
|
||||
pool_balance,
|
||||
Preservation::Expendable,
|
||||
)?;
|
||||
|
||||
if let Some((who, cost)) = PoolCost::<T>::take(pool_id) {
|
||||
T::Consideration::drop(cost, &who)?;
|
||||
}
|
||||
|
||||
Pools::<T>::remove(pool_id);
|
||||
|
||||
Self::deposit_event(Event::PoolCleanedUp { pool_id });
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> Pallet<T> {
|
||||
/// The pool creation footprint.
|
||||
///
|
||||
/// The footprint specifically accounts for the storage footprint of the pool's information
|
||||
/// itself, excluding any potential storage footprint related to the stakers.
|
||||
pub fn pool_creation_footprint() -> Footprint {
|
||||
Footprint::from_mel::<(PoolId, PoolInfoFor<T>)>()
|
||||
}
|
||||
|
||||
/// Derive a pool account ID from the pool's ID.
|
||||
pub fn pool_account_id(id: &PoolId) -> T::AccountId {
|
||||
T::PalletId::get().into_sub_account_truncating(id)
|
||||
}
|
||||
|
||||
/// Computes update pool and staker reward state.
|
||||
///
|
||||
/// Should be called prior to any operation involving a staker.
|
||||
///
|
||||
/// Returns the updated pool and staker info.
|
||||
///
|
||||
/// NOTE: this function has no side-effects. Side-effects such as storage modifications are
|
||||
/// the responsibility of the caller.
|
||||
pub fn update_pool_and_staker_rewards(
|
||||
pool_info: &PoolInfoFor<T>,
|
||||
staker_info: &PoolStakerInfo<T::Balance>,
|
||||
) -> Result<(PoolInfoFor<T>, PoolStakerInfo<T::Balance>), DispatchError> {
|
||||
let reward_per_token = Self::reward_per_token(&pool_info)?;
|
||||
let pool_info = Self::update_pool_rewards(pool_info, reward_per_token)?;
|
||||
|
||||
let mut new_staker_info = staker_info.clone();
|
||||
new_staker_info.rewards = Self::derive_rewards(&staker_info, &reward_per_token)?;
|
||||
new_staker_info.reward_per_token_paid = pool_info.reward_per_token_stored;
|
||||
return Ok((pool_info, new_staker_info));
|
||||
}
|
||||
|
||||
/// Computes update pool reward state.
|
||||
///
|
||||
/// Should be called every time the pool is adjusted, and a staker is not involved.
|
||||
///
|
||||
/// Returns the updated pool and staker info.
|
||||
///
|
||||
/// NOTE: this function has no side-effects. Side-effects such as storage modifications are
|
||||
/// the responsibility of the caller.
|
||||
pub fn update_pool_rewards(
|
||||
pool_info: &PoolInfoFor<T>,
|
||||
reward_per_token: T::Balance,
|
||||
) -> Result<PoolInfoFor<T>, DispatchError> {
|
||||
let mut new_pool_info = pool_info.clone();
|
||||
new_pool_info.last_update_block = T::BlockNumberProvider::current_block_number();
|
||||
new_pool_info.reward_per_token_stored = reward_per_token;
|
||||
|
||||
Ok(new_pool_info)
|
||||
}
|
||||
|
||||
/// Derives the current reward per token for this pool.
|
||||
pub(super) fn reward_per_token(
|
||||
pool_info: &PoolInfoFor<T>,
|
||||
) -> Result<T::Balance, DispatchError> {
|
||||
if pool_info.total_tokens_staked.is_zero() {
|
||||
return Ok(pool_info.reward_per_token_stored);
|
||||
}
|
||||
|
||||
let rewardable_blocks_elapsed: u32 =
|
||||
match Self::last_block_reward_applicable(pool_info.expiry_block)
|
||||
.ensure_sub(pool_info.last_update_block)?
|
||||
.try_into()
|
||||
{
|
||||
Ok(b) => b,
|
||||
Err(_) => return Err(Error::<T>::BlockNumberConversionError.into()),
|
||||
};
|
||||
|
||||
Ok(pool_info.reward_per_token_stored.ensure_add(
|
||||
pool_info
|
||||
.reward_rate_per_block
|
||||
.ensure_mul(rewardable_blocks_elapsed.into())?
|
||||
.ensure_mul(PRECISION_SCALING_FACTOR.into())?
|
||||
.ensure_div(pool_info.total_tokens_staked)?,
|
||||
)?)
|
||||
}
|
||||
|
||||
/// Derives the amount of rewards earned by a staker.
|
||||
///
|
||||
/// This is a helper function for `update_pool_rewards` and should not be called directly.
|
||||
fn derive_rewards(
|
||||
staker_info: &PoolStakerInfo<T::Balance>,
|
||||
reward_per_token: &T::Balance,
|
||||
) -> Result<T::Balance, DispatchError> {
|
||||
Ok(staker_info
|
||||
.amount
|
||||
.ensure_mul(reward_per_token.ensure_sub(staker_info.reward_per_token_paid)?)?
|
||||
.ensure_div(PRECISION_SCALING_FACTOR.into())?
|
||||
.ensure_add(staker_info.rewards)?)
|
||||
}
|
||||
|
||||
fn last_block_reward_applicable(pool_expiry_block: BlockNumberFor<T>) -> BlockNumberFor<T> {
|
||||
let now = T::BlockNumberProvider::current_block_number();
|
||||
if now < pool_expiry_block {
|
||||
now
|
||||
} else {
|
||||
pool_expiry_block
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> RewardsPool<T::AccountId> for Pallet<T> {
|
||||
type AssetId = T::AssetId;
|
||||
type BlockNumber = BlockNumberFor<T>;
|
||||
type PoolId = PoolId;
|
||||
type Balance = T::Balance;
|
||||
|
||||
fn create_pool(
|
||||
creator: &T::AccountId,
|
||||
staked_asset_id: T::AssetId,
|
||||
reward_asset_id: T::AssetId,
|
||||
reward_rate_per_block: T::Balance,
|
||||
expiry: DispatchTime<BlockNumberFor<T>>,
|
||||
admin: &T::AccountId,
|
||||
) -> Result<PoolId, DispatchError> {
|
||||
// Ensure the assets exist.
|
||||
ensure!(T::Assets::asset_exists(staked_asset_id.clone()), Error::<T>::NonExistentAsset);
|
||||
ensure!(T::Assets::asset_exists(reward_asset_id.clone()), Error::<T>::NonExistentAsset);
|
||||
|
||||
// Check the expiry block.
|
||||
let now = T::BlockNumberProvider::current_block_number();
|
||||
let expiry_block = expiry.evaluate(now);
|
||||
ensure!(expiry_block > now, Error::<T>::ExpiryBlockMustBeInTheFuture);
|
||||
|
||||
let pool_id = NextPoolId::<T>::try_mutate(|id| -> Result<PoolId, DispatchError> {
|
||||
let current_id = *id;
|
||||
*id = id.ensure_add(1)?;
|
||||
Ok(current_id)
|
||||
})?;
|
||||
|
||||
let footprint = Self::pool_creation_footprint();
|
||||
let cost = T::Consideration::new(creator, footprint)?;
|
||||
PoolCost::<T>::insert(pool_id, (creator.clone(), cost));
|
||||
|
||||
// Create the pool.
|
||||
let pool = PoolInfoFor::<T> {
|
||||
staked_asset_id: staked_asset_id.clone(),
|
||||
reward_asset_id: reward_asset_id.clone(),
|
||||
reward_rate_per_block,
|
||||
total_tokens_staked: 0u32.into(),
|
||||
reward_per_token_stored: 0u32.into(),
|
||||
last_update_block: 0u32.into(),
|
||||
expiry_block,
|
||||
admin: admin.clone(),
|
||||
account: Self::pool_account_id(&pool_id),
|
||||
};
|
||||
|
||||
// Insert it into storage.
|
||||
Pools::<T>::insert(pool_id, pool);
|
||||
|
||||
// Emit created event.
|
||||
Self::deposit_event(Event::PoolCreated {
|
||||
creator: creator.clone(),
|
||||
pool_id,
|
||||
staked_asset_id,
|
||||
reward_asset_id,
|
||||
reward_rate_per_block,
|
||||
expiry_block,
|
||||
admin: admin.clone(),
|
||||
});
|
||||
|
||||
Ok(pool_id)
|
||||
}
|
||||
|
||||
fn set_pool_reward_rate_per_block(
|
||||
admin: &T::AccountId,
|
||||
pool_id: PoolId,
|
||||
new_reward_rate_per_block: T::Balance,
|
||||
) -> DispatchResult {
|
||||
let pool_info = Pools::<T>::get(pool_id).ok_or(Error::<T>::NonExistentPool)?;
|
||||
ensure!(pool_info.admin == *admin, BadOrigin);
|
||||
ensure!(
|
||||
new_reward_rate_per_block > pool_info.reward_rate_per_block,
|
||||
Error::<T>::RewardRateCut
|
||||
);
|
||||
|
||||
// Always start by updating the pool rewards.
|
||||
let rewards_per_token = Self::reward_per_token(&pool_info)?;
|
||||
let mut pool_info = Self::update_pool_rewards(&pool_info, rewards_per_token)?;
|
||||
|
||||
pool_info.reward_rate_per_block = new_reward_rate_per_block;
|
||||
Pools::<T>::insert(pool_id, pool_info);
|
||||
|
||||
Self::deposit_event(Event::PoolRewardRateModified { pool_id, new_reward_rate_per_block });
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_pool_admin(
|
||||
admin: &T::AccountId,
|
||||
pool_id: PoolId,
|
||||
new_admin: T::AccountId,
|
||||
) -> DispatchResult {
|
||||
let mut pool_info = Pools::<T>::get(pool_id).ok_or(Error::<T>::NonExistentPool)?;
|
||||
ensure!(pool_info.admin == *admin, BadOrigin);
|
||||
|
||||
pool_info.admin = new_admin.clone();
|
||||
Pools::<T>::insert(pool_id, pool_info);
|
||||
|
||||
Self::deposit_event(Event::PoolAdminModified { pool_id, new_admin });
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_pool_expiry_block(
|
||||
admin: &T::AccountId,
|
||||
pool_id: PoolId,
|
||||
new_expiry: DispatchTime<BlockNumberFor<T>>,
|
||||
) -> DispatchResult {
|
||||
let now = T::BlockNumberProvider::current_block_number();
|
||||
let new_expiry_block = new_expiry.evaluate(now);
|
||||
ensure!(new_expiry_block > now, Error::<T>::ExpiryBlockMustBeInTheFuture);
|
||||
|
||||
let pool_info = Pools::<T>::get(pool_id).ok_or(Error::<T>::NonExistentPool)?;
|
||||
ensure!(pool_info.admin == *admin, BadOrigin);
|
||||
ensure!(new_expiry_block > pool_info.expiry_block, Error::<T>::ExpiryCut);
|
||||
|
||||
// Always start by updating the pool rewards.
|
||||
let reward_per_token = Self::reward_per_token(&pool_info)?;
|
||||
let mut pool_info = Self::update_pool_rewards(&pool_info, reward_per_token)?;
|
||||
|
||||
pool_info.expiry_block = new_expiry_block;
|
||||
Pools::<T>::insert(pool_id, pool_info);
|
||||
|
||||
Self::deposit_event(Event::PoolExpiryBlockModified { pool_id, new_expiry_block });
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
// 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.
|
||||
|
||||
//! Test environment for Asset Rewards pallet.
|
||||
|
||||
use super::*;
|
||||
use crate as pezpallet_asset_rewards;
|
||||
use core::default::Default;
|
||||
use pezframe_support::{
|
||||
construct_runtime, derive_impl,
|
||||
instances::Instance1,
|
||||
parameter_types,
|
||||
traits::{
|
||||
tokens::fungible::{HoldConsideration, NativeFromLeft, NativeOrWithId, UnionOf},
|
||||
AsEnsureOriginWithArg, ConstU128, ConstU32, EnsureOrigin, LinearStoragePrice,
|
||||
},
|
||||
PalletId,
|
||||
};
|
||||
use pezframe_system::EnsureSigned;
|
||||
use pezsp_runtime::{traits::IdentityLookup, BuildStorage};
|
||||
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
use self::benchmarking::BenchmarkHelper;
|
||||
|
||||
type Block = pezframe_system::mocking::MockBlock<MockRuntime>;
|
||||
|
||||
construct_runtime!(
|
||||
pub enum MockRuntime
|
||||
{
|
||||
System: pezframe_system,
|
||||
Balances: pezpallet_balances,
|
||||
Assets: pezpallet_assets::<Instance1>,
|
||||
AssetsFreezer: pezpallet_assets_freezer::<Instance1>,
|
||||
StakingRewards: pezpallet_asset_rewards,
|
||||
}
|
||||
);
|
||||
|
||||
#[derive_impl(pezframe_system::config_preludes::TestDefaultConfig)]
|
||||
impl pezframe_system::Config for MockRuntime {
|
||||
type AccountId = u128;
|
||||
type Lookup = IdentityLookup<Self::AccountId>;
|
||||
type Block = Block;
|
||||
type AccountData = pezpallet_balances::AccountData<u128>;
|
||||
}
|
||||
|
||||
impl pezpallet_balances::Config for MockRuntime {
|
||||
type Balance = u128;
|
||||
type DustRemoval = ();
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type ExistentialDeposit = ConstU128<100>;
|
||||
type AccountStore = System;
|
||||
type WeightInfo = ();
|
||||
type MaxLocks = ();
|
||||
type MaxReserves = ConstU32<50>;
|
||||
type ReserveIdentifier = [u8; 8];
|
||||
type FreezeIdentifier = RuntimeFreezeReason;
|
||||
type MaxFreezes = ConstU32<50>;
|
||||
type RuntimeHoldReason = RuntimeHoldReason;
|
||||
type RuntimeFreezeReason = RuntimeFreezeReason;
|
||||
type DoneSlashHandler = ();
|
||||
}
|
||||
|
||||
impl pezpallet_assets::Config<Instance1> for MockRuntime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type Balance = u128;
|
||||
type RemoveItemsLimit = ConstU32<1000>;
|
||||
type AssetId = u32;
|
||||
type AssetIdParameter = u32;
|
||||
type ReserveData = ();
|
||||
type Currency = Balances;
|
||||
type CreateOrigin = AsEnsureOriginWithArg<EnsureSigned<Self::AccountId>>;
|
||||
type ForceOrigin = pezframe_system::EnsureRoot<Self::AccountId>;
|
||||
type AssetDeposit = ConstU128<1>;
|
||||
type AssetAccountDeposit = ConstU128<10>;
|
||||
type MetadataDepositBase = ConstU128<1>;
|
||||
type MetadataDepositPerByte = ConstU128<1>;
|
||||
type ApprovalDeposit = ConstU128<1>;
|
||||
type StringLimit = ConstU32<50>;
|
||||
type Freezer = AssetsFreezer;
|
||||
type Holder = ();
|
||||
type Extra = ();
|
||||
type WeightInfo = ();
|
||||
type CallbackHandle = ();
|
||||
pezpallet_assets::runtime_benchmarks_enabled! {
|
||||
type BenchmarkHelper = ();
|
||||
}
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub const StakingRewardsPalletId: PalletId = PalletId(*b"py/stkrd");
|
||||
pub const Native: NativeOrWithId<u32> = NativeOrWithId::Native;
|
||||
pub const PermissionedAccountId: u128 = 0;
|
||||
}
|
||||
|
||||
/// Give Root Origin permission to create pools.
|
||||
pub struct MockPermissionedOrigin;
|
||||
impl EnsureOrigin<RuntimeOrigin> for MockPermissionedOrigin {
|
||||
type Success = <MockRuntime as pezframe_system::Config>::AccountId;
|
||||
|
||||
fn try_origin(origin: RuntimeOrigin) -> Result<Self::Success, RuntimeOrigin> {
|
||||
match origin.clone().into() {
|
||||
Ok(pezframe_system::RawOrigin::Root) => Ok(PermissionedAccountId::get()),
|
||||
_ => Err(origin),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
fn try_successful_origin() -> Result<RuntimeOrigin, ()> {
|
||||
Ok(RuntimeOrigin::root())
|
||||
}
|
||||
}
|
||||
|
||||
/// Allow Freezes for the `Assets` pallet
|
||||
impl pezpallet_assets_freezer::Config<pezpallet_assets_freezer::Instance1> for MockRuntime {
|
||||
type RuntimeFreezeReason = RuntimeFreezeReason;
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
}
|
||||
|
||||
pub type NativeAndAssets = UnionOf<Balances, Assets, NativeFromLeft, NativeOrWithId<u32>, u128>;
|
||||
|
||||
pub type NativeAndAssetsFreezer =
|
||||
UnionOf<Balances, AssetsFreezer, NativeFromLeft, NativeOrWithId<u32>, u128>;
|
||||
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
pub struct AssetRewardsBenchmarkHelper;
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
impl BenchmarkHelper<NativeOrWithId<u32>> for AssetRewardsBenchmarkHelper {
|
||||
fn staked_asset() -> NativeOrWithId<u32> {
|
||||
NativeOrWithId::<u32>::WithId(101)
|
||||
}
|
||||
fn reward_asset() -> NativeOrWithId<u32> {
|
||||
NativeOrWithId::<u32>::WithId(102)
|
||||
}
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub const CreationHoldReason: RuntimeHoldReason =
|
||||
RuntimeHoldReason::StakingRewards(pezpallet_asset_rewards::HoldReason::PoolCreation);
|
||||
}
|
||||
|
||||
impl Config for MockRuntime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type AssetId = NativeOrWithId<u32>;
|
||||
type Balance = <Self as pezpallet_balances::Config>::Balance;
|
||||
type Assets = NativeAndAssets;
|
||||
type AssetsFreezer = NativeAndAssetsFreezer;
|
||||
type PalletId = StakingRewardsPalletId;
|
||||
type CreatePoolOrigin = MockPermissionedOrigin;
|
||||
type WeightInfo = ();
|
||||
type RuntimeFreezeReason = RuntimeFreezeReason;
|
||||
type Consideration = HoldConsideration<
|
||||
u128,
|
||||
Balances,
|
||||
CreationHoldReason,
|
||||
LinearStoragePrice<ConstU128<100>, ConstU128<0>, u128>,
|
||||
>;
|
||||
type BlockNumberProvider = pezframe_system::Pallet<Self>;
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
type BenchmarkHelper = AssetRewardsBenchmarkHelper;
|
||||
}
|
||||
|
||||
pub(crate) fn new_test_ext() -> pezsp_io::TestExternalities {
|
||||
let mut t = pezframe_system::GenesisConfig::<MockRuntime>::default().build_storage().unwrap();
|
||||
|
||||
pezpallet_assets::GenesisConfig::<MockRuntime, Instance1> {
|
||||
// Genesis assets: id, owner, is_sufficient, min_balance
|
||||
// pub assets: Vec<(T::AssetId, T::AccountId, bool, T::Balance)>,
|
||||
assets: vec![(1, 1, true, 1), (10, 1, true, 1), (20, 1, true, 1)],
|
||||
// Genesis metadata: id, name, symbol, decimals
|
||||
// pub metadata: Vec<(T::AssetId, Vec<u8>, Vec<u8>, u8)>,
|
||||
metadata: vec![
|
||||
(1, b"test".to_vec(), b"TST".to_vec(), 18),
|
||||
(10, b"test10".to_vec(), b"T10".to_vec(), 18),
|
||||
(20, b"test20".to_vec(), b"T20".to_vec(), 18),
|
||||
],
|
||||
// Genesis accounts: id, account_id, balance
|
||||
// pub accounts: Vec<(T::AssetId, T::AccountId, T::Balance)>,
|
||||
accounts: vec![
|
||||
(1, 1, 10000),
|
||||
(1, 2, 20000),
|
||||
(1, 3, 30000),
|
||||
(1, 4, 40000),
|
||||
(1, 10, 40000),
|
||||
(1, 20, 40000),
|
||||
],
|
||||
next_asset_id: None,
|
||||
reserves: vec![],
|
||||
}
|
||||
.assimilate_storage(&mut t)
|
||||
.unwrap();
|
||||
|
||||
let pool_zero_account_id = 31086825966906540362769395565;
|
||||
pezpallet_balances::GenesisConfig::<MockRuntime> {
|
||||
balances: vec![
|
||||
(0, 10000),
|
||||
(1, 10000),
|
||||
(2, 20000),
|
||||
(3, 30000),
|
||||
(4, 40000),
|
||||
(10, 40000),
|
||||
(20, 40000),
|
||||
(pool_zero_account_id, 100_000), // Top up the default pool account id
|
||||
],
|
||||
..Default::default()
|
||||
}
|
||||
.assimilate_storage(&mut t)
|
||||
.unwrap();
|
||||
|
||||
let mut ext = pezsp_io::TestExternalities::new(t);
|
||||
ext.execute_with(|| System::set_block_number(1));
|
||||
ext
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,391 @@
|
||||
// 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.
|
||||
|
||||
// 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_asset_rewards`
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE BIZINIKIWI BENCHMARK CLI VERSION 32.0.0
|
||||
//! DATE: 2025-02-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! WORST CASE MAP SIZE: `1000000`
|
||||
//! HOSTNAME: `4563561839a5`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
|
||||
//! WASM-EXECUTION: `Compiled`, CHAIN: `None`, DB CACHE: `1024`
|
||||
|
||||
// Executed Command:
|
||||
// frame-omni-bencher
|
||||
// v1
|
||||
// benchmark
|
||||
// pallet
|
||||
// --extrinsic=*
|
||||
// --runtime=target/production/wbuild/kitchensink-runtime/kitchensink_runtime.wasm
|
||||
// --pallet=pezpallet_asset_rewards
|
||||
// --header=/__w/pezkuwi-sdk/pezkuwi-sdk/bizinikiwi/HEADER-APACHE2
|
||||
// --output=/__w/pezkuwi-sdk/pezkuwi-sdk/bizinikiwi/pezframe/asset-rewards/src/weights.rs
|
||||
// --wasm-execution=compiled
|
||||
// --steps=50
|
||||
// --repeat=20
|
||||
// --heap-pages=4096
|
||||
// --template=bizinikiwi/.maintain/frame-weight-template.hbs
|
||||
// --no-storage-info
|
||||
// --no-min-squares
|
||||
// --no-median-slopes
|
||||
// --genesis-builder-policy=none
|
||||
// --exclude-pallets=pezpallet_xcm,pezpallet_xcm_benchmarks::fungible,pezpallet_xcm_benchmarks::generic,pezpallet_nomination_pools,pezpallet_remark,pezpallet_transaction_storage,pezpallet_election_provider_multi_block,pezpallet_election_provider_multi_block::signed,pezpallet_election_provider_multi_block::unsigned,pezpallet_election_provider_multi_block::verifier
|
||||
|
||||
#![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_asset_rewards`.
|
||||
pub trait WeightInfo {
|
||||
fn create_pool() -> Weight;
|
||||
fn stake() -> Weight;
|
||||
fn unstake() -> Weight;
|
||||
fn harvest_rewards() -> Weight;
|
||||
fn set_pool_reward_rate_per_block() -> Weight;
|
||||
fn set_pool_admin() -> Weight;
|
||||
fn set_pool_expiry_block() -> Weight;
|
||||
fn deposit_reward_tokens() -> Weight;
|
||||
fn cleanup_pool() -> Weight;
|
||||
}
|
||||
|
||||
/// Weights for `pezpallet_asset_rewards` using the Bizinikiwi node and recommended hardware.
|
||||
pub struct BizinikiwiWeight<T>(PhantomData<T>);
|
||||
impl<T: pezframe_system::Config> WeightInfo for BizinikiwiWeight<T> {
|
||||
/// Storage: `Assets::Asset` (r:2 w:0)
|
||||
/// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`)
|
||||
/// Storage: `AssetRewards::NextPoolId` (r:1 w:1)
|
||||
/// Proof: `AssetRewards::NextPoolId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
/// Storage: `System::Account` (r:1 w:1)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Holds` (r:1 w:1)
|
||||
/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(427), added: 2902, mode: `MaxEncodedLen`)
|
||||
/// Storage: `AssetRewards::PoolCost` (r:0 w:1)
|
||||
/// Proof: `AssetRewards::PoolCost` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`)
|
||||
/// Storage: `AssetRewards::Pools` (r:0 w:1)
|
||||
/// Proof: `AssetRewards::Pools` (`max_values`: None, `max_size`: Some(150), added: 2625, mode: `MaxEncodedLen`)
|
||||
fn create_pool() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `169`
|
||||
// Estimated: `6360`
|
||||
// Minimum execution time: 51_207_000 picoseconds.
|
||||
Weight::from_parts(52_880_000, 6360)
|
||||
.saturating_add(T::DbWeight::get().reads(5_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(5_u64))
|
||||
}
|
||||
/// Storage: `AssetRewards::Pools` (r:1 w:1)
|
||||
/// Proof: `AssetRewards::Pools` (`max_values`: None, `max_size`: Some(150), added: 2625, mode: `MaxEncodedLen`)
|
||||
/// Storage: `AssetRewards::PoolStakers` (r:1 w:1)
|
||||
/// Proof: `AssetRewards::PoolStakers` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`)
|
||||
/// Storage: `AssetsFreezer::Freezes` (r:1 w:1)
|
||||
/// Proof: `AssetsFreezer::Freezes` (`max_values`: None, `max_size`: Some(105), added: 2580, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Assets::Account` (r:1 w:0)
|
||||
/// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`)
|
||||
/// Storage: `AssetsFreezer::FrozenBalances` (r:1 w:1)
|
||||
/// Proof: `AssetsFreezer::FrozenBalances` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`)
|
||||
fn stake() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `638`
|
||||
// Estimated: `3615`
|
||||
// Minimum execution time: 44_515_000 picoseconds.
|
||||
Weight::from_parts(45_206_000, 3615)
|
||||
.saturating_add(T::DbWeight::get().reads(5_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(4_u64))
|
||||
}
|
||||
/// Storage: `AssetRewards::Pools` (r:1 w:1)
|
||||
/// Proof: `AssetRewards::Pools` (`max_values`: None, `max_size`: Some(150), added: 2625, mode: `MaxEncodedLen`)
|
||||
/// Storage: `AssetRewards::PoolStakers` (r:1 w:1)
|
||||
/// Proof: `AssetRewards::PoolStakers` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`)
|
||||
/// Storage: `AssetsFreezer::Freezes` (r:1 w:1)
|
||||
/// Proof: `AssetsFreezer::Freezes` (`max_values`: None, `max_size`: Some(105), added: 2580, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Assets::Account` (r:1 w:0)
|
||||
/// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`)
|
||||
/// Storage: `AssetsFreezer::FrozenBalances` (r:1 w:1)
|
||||
/// Proof: `AssetsFreezer::FrozenBalances` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`)
|
||||
fn unstake() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `638`
|
||||
// Estimated: `3615`
|
||||
// Minimum execution time: 46_068_000 picoseconds.
|
||||
Weight::from_parts(46_950_000, 3615)
|
||||
.saturating_add(T::DbWeight::get().reads(5_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(4_u64))
|
||||
}
|
||||
/// Storage: `AssetRewards::Pools` (r:1 w:0)
|
||||
/// Proof: `AssetRewards::Pools` (`max_values`: None, `max_size`: Some(150), added: 2625, mode: `MaxEncodedLen`)
|
||||
/// Storage: `AssetRewards::PoolStakers` (r:1 w:1)
|
||||
/// Proof: `AssetRewards::PoolStakers` (`max_values`: None, `max_size`: Some(116), added: 2591, 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:2 w:2)
|
||||
/// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`)
|
||||
fn harvest_rewards() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `766`
|
||||
// Estimated: `6208`
|
||||
// Minimum execution time: 60_648_000 picoseconds.
|
||||
Weight::from_parts(62_025_000, 6208)
|
||||
.saturating_add(T::DbWeight::get().reads(5_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(4_u64))
|
||||
}
|
||||
/// Storage: `AssetRewards::Pools` (r:1 w:1)
|
||||
/// Proof: `AssetRewards::Pools` (`max_values`: None, `max_size`: Some(150), added: 2625, mode: `MaxEncodedLen`)
|
||||
fn set_pool_reward_rate_per_block() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `218`
|
||||
// Estimated: `3615`
|
||||
// Minimum execution time: 12_600_000 picoseconds.
|
||||
Weight::from_parts(13_049_000, 3615)
|
||||
.saturating_add(T::DbWeight::get().reads(1_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(1_u64))
|
||||
}
|
||||
/// Storage: `AssetRewards::Pools` (r:1 w:1)
|
||||
/// Proof: `AssetRewards::Pools` (`max_values`: None, `max_size`: Some(150), added: 2625, mode: `MaxEncodedLen`)
|
||||
fn set_pool_admin() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `218`
|
||||
// Estimated: `3615`
|
||||
// Minimum execution time: 12_074_000 picoseconds.
|
||||
Weight::from_parts(12_344_000, 3615)
|
||||
.saturating_add(T::DbWeight::get().reads(1_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(1_u64))
|
||||
}
|
||||
/// Storage: `AssetRewards::Pools` (r:1 w:1)
|
||||
/// Proof: `AssetRewards::Pools` (`max_values`: None, `max_size`: Some(150), added: 2625, mode: `MaxEncodedLen`)
|
||||
fn set_pool_expiry_block() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `218`
|
||||
// Estimated: `3615`
|
||||
// Minimum execution time: 13_587_000 picoseconds.
|
||||
Weight::from_parts(14_037_000, 3615)
|
||||
.saturating_add(T::DbWeight::get().reads(1_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(1_u64))
|
||||
}
|
||||
/// Storage: `AssetRewards::Pools` (r:1 w:0)
|
||||
/// Proof: `AssetRewards::Pools` (`max_values`: None, `max_size`: Some(150), added: 2625, 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:2 w:2)
|
||||
/// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`)
|
||||
/// Storage: `System::Account` (r:1 w:1)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
fn deposit_reward_tokens() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `585`
|
||||
// Estimated: `6208`
|
||||
// Minimum execution time: 51_501_000 picoseconds.
|
||||
Weight::from_parts(52_593_000, 6208)
|
||||
.saturating_add(T::DbWeight::get().reads(5_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(4_u64))
|
||||
}
|
||||
/// Storage: `AssetRewards::Pools` (r:1 w:1)
|
||||
/// Proof: `AssetRewards::Pools` (`max_values`: None, `max_size`: Some(150), added: 2625, mode: `MaxEncodedLen`)
|
||||
/// Storage: `AssetRewards::PoolStakers` (r:1 w:0)
|
||||
/// Proof: `AssetRewards::PoolStakers` (`max_values`: None, `max_size`: Some(116), added: 2591, 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:2 w:2)
|
||||
/// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`)
|
||||
/// Storage: `System::Account` (r:2 w:2)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
/// Storage: `AssetRewards::PoolCost` (r:1 w:1)
|
||||
/// Proof: `AssetRewards::PoolCost` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Holds` (r:1 w:1)
|
||||
/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(427), added: 2902, mode: `MaxEncodedLen`)
|
||||
fn cleanup_pool() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `943`
|
||||
// Estimated: `6208`
|
||||
// Minimum execution time: 98_758_000 picoseconds.
|
||||
Weight::from_parts(100_771_000, 6208)
|
||||
.saturating_add(T::DbWeight::get().reads(9_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(8_u64))
|
||||
}
|
||||
}
|
||||
|
||||
// For backwards compatibility and tests.
|
||||
impl WeightInfo for () {
|
||||
/// Storage: `Assets::Asset` (r:2 w:0)
|
||||
/// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`)
|
||||
/// Storage: `AssetRewards::NextPoolId` (r:1 w:1)
|
||||
/// Proof: `AssetRewards::NextPoolId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
/// Storage: `System::Account` (r:1 w:1)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Holds` (r:1 w:1)
|
||||
/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(427), added: 2902, mode: `MaxEncodedLen`)
|
||||
/// Storage: `AssetRewards::PoolCost` (r:0 w:1)
|
||||
/// Proof: `AssetRewards::PoolCost` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`)
|
||||
/// Storage: `AssetRewards::Pools` (r:0 w:1)
|
||||
/// Proof: `AssetRewards::Pools` (`max_values`: None, `max_size`: Some(150), added: 2625, mode: `MaxEncodedLen`)
|
||||
fn create_pool() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `169`
|
||||
// Estimated: `6360`
|
||||
// Minimum execution time: 51_207_000 picoseconds.
|
||||
Weight::from_parts(52_880_000, 6360)
|
||||
.saturating_add(RocksDbWeight::get().reads(5_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(5_u64))
|
||||
}
|
||||
/// Storage: `AssetRewards::Pools` (r:1 w:1)
|
||||
/// Proof: `AssetRewards::Pools` (`max_values`: None, `max_size`: Some(150), added: 2625, mode: `MaxEncodedLen`)
|
||||
/// Storage: `AssetRewards::PoolStakers` (r:1 w:1)
|
||||
/// Proof: `AssetRewards::PoolStakers` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`)
|
||||
/// Storage: `AssetsFreezer::Freezes` (r:1 w:1)
|
||||
/// Proof: `AssetsFreezer::Freezes` (`max_values`: None, `max_size`: Some(105), added: 2580, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Assets::Account` (r:1 w:0)
|
||||
/// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`)
|
||||
/// Storage: `AssetsFreezer::FrozenBalances` (r:1 w:1)
|
||||
/// Proof: `AssetsFreezer::FrozenBalances` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`)
|
||||
fn stake() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `638`
|
||||
// Estimated: `3615`
|
||||
// Minimum execution time: 44_515_000 picoseconds.
|
||||
Weight::from_parts(45_206_000, 3615)
|
||||
.saturating_add(RocksDbWeight::get().reads(5_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(4_u64))
|
||||
}
|
||||
/// Storage: `AssetRewards::Pools` (r:1 w:1)
|
||||
/// Proof: `AssetRewards::Pools` (`max_values`: None, `max_size`: Some(150), added: 2625, mode: `MaxEncodedLen`)
|
||||
/// Storage: `AssetRewards::PoolStakers` (r:1 w:1)
|
||||
/// Proof: `AssetRewards::PoolStakers` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`)
|
||||
/// Storage: `AssetsFreezer::Freezes` (r:1 w:1)
|
||||
/// Proof: `AssetsFreezer::Freezes` (`max_values`: None, `max_size`: Some(105), added: 2580, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Assets::Account` (r:1 w:0)
|
||||
/// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`)
|
||||
/// Storage: `AssetsFreezer::FrozenBalances` (r:1 w:1)
|
||||
/// Proof: `AssetsFreezer::FrozenBalances` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`)
|
||||
fn unstake() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `638`
|
||||
// Estimated: `3615`
|
||||
// Minimum execution time: 46_068_000 picoseconds.
|
||||
Weight::from_parts(46_950_000, 3615)
|
||||
.saturating_add(RocksDbWeight::get().reads(5_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(4_u64))
|
||||
}
|
||||
/// Storage: `AssetRewards::Pools` (r:1 w:0)
|
||||
/// Proof: `AssetRewards::Pools` (`max_values`: None, `max_size`: Some(150), added: 2625, mode: `MaxEncodedLen`)
|
||||
/// Storage: `AssetRewards::PoolStakers` (r:1 w:1)
|
||||
/// Proof: `AssetRewards::PoolStakers` (`max_values`: None, `max_size`: Some(116), added: 2591, 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:2 w:2)
|
||||
/// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`)
|
||||
fn harvest_rewards() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `766`
|
||||
// Estimated: `6208`
|
||||
// Minimum execution time: 60_648_000 picoseconds.
|
||||
Weight::from_parts(62_025_000, 6208)
|
||||
.saturating_add(RocksDbWeight::get().reads(5_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(4_u64))
|
||||
}
|
||||
/// Storage: `AssetRewards::Pools` (r:1 w:1)
|
||||
/// Proof: `AssetRewards::Pools` (`max_values`: None, `max_size`: Some(150), added: 2625, mode: `MaxEncodedLen`)
|
||||
fn set_pool_reward_rate_per_block() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `218`
|
||||
// Estimated: `3615`
|
||||
// Minimum execution time: 12_600_000 picoseconds.
|
||||
Weight::from_parts(13_049_000, 3615)
|
||||
.saturating_add(RocksDbWeight::get().reads(1_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(1_u64))
|
||||
}
|
||||
/// Storage: `AssetRewards::Pools` (r:1 w:1)
|
||||
/// Proof: `AssetRewards::Pools` (`max_values`: None, `max_size`: Some(150), added: 2625, mode: `MaxEncodedLen`)
|
||||
fn set_pool_admin() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `218`
|
||||
// Estimated: `3615`
|
||||
// Minimum execution time: 12_074_000 picoseconds.
|
||||
Weight::from_parts(12_344_000, 3615)
|
||||
.saturating_add(RocksDbWeight::get().reads(1_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(1_u64))
|
||||
}
|
||||
/// Storage: `AssetRewards::Pools` (r:1 w:1)
|
||||
/// Proof: `AssetRewards::Pools` (`max_values`: None, `max_size`: Some(150), added: 2625, mode: `MaxEncodedLen`)
|
||||
fn set_pool_expiry_block() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `218`
|
||||
// Estimated: `3615`
|
||||
// Minimum execution time: 13_587_000 picoseconds.
|
||||
Weight::from_parts(14_037_000, 3615)
|
||||
.saturating_add(RocksDbWeight::get().reads(1_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(1_u64))
|
||||
}
|
||||
/// Storage: `AssetRewards::Pools` (r:1 w:0)
|
||||
/// Proof: `AssetRewards::Pools` (`max_values`: None, `max_size`: Some(150), added: 2625, 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:2 w:2)
|
||||
/// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`)
|
||||
/// Storage: `System::Account` (r:1 w:1)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
fn deposit_reward_tokens() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `585`
|
||||
// Estimated: `6208`
|
||||
// Minimum execution time: 51_501_000 picoseconds.
|
||||
Weight::from_parts(52_593_000, 6208)
|
||||
.saturating_add(RocksDbWeight::get().reads(5_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(4_u64))
|
||||
}
|
||||
/// Storage: `AssetRewards::Pools` (r:1 w:1)
|
||||
/// Proof: `AssetRewards::Pools` (`max_values`: None, `max_size`: Some(150), added: 2625, mode: `MaxEncodedLen`)
|
||||
/// Storage: `AssetRewards::PoolStakers` (r:1 w:0)
|
||||
/// Proof: `AssetRewards::PoolStakers` (`max_values`: None, `max_size`: Some(116), added: 2591, 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:2 w:2)
|
||||
/// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`)
|
||||
/// Storage: `System::Account` (r:2 w:2)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
/// Storage: `AssetRewards::PoolCost` (r:1 w:1)
|
||||
/// Proof: `AssetRewards::PoolCost` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Holds` (r:1 w:1)
|
||||
/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(427), added: 2902, mode: `MaxEncodedLen`)
|
||||
fn cleanup_pool() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `943`
|
||||
// Estimated: `6208`
|
||||
// Minimum execution time: 98_758_000 picoseconds.
|
||||
Weight::from_parts(100_771_000, 6208)
|
||||
.saturating_add(RocksDbWeight::get().reads(9_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(8_u64))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user