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,68 @@
|
||||
[package]
|
||||
name = "pezpallet-child-bounties"
|
||||
version = "27.0.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license = "Apache-2.0"
|
||||
homepage.workspace = true
|
||||
repository.workspace = true
|
||||
description = "FRAME pallet to manage child bounties"
|
||||
readme = "README.md"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
||||
[dependencies]
|
||||
codec = { features = ["derive"], workspace = true }
|
||||
pezframe-benchmarking = { optional = true, workspace = true }
|
||||
pezframe-support = { workspace = true }
|
||||
pezframe-system = { workspace = true }
|
||||
log = { workspace = true }
|
||||
pezpallet-bounties = { workspace = true }
|
||||
pezpallet-treasury = { workspace = true }
|
||||
scale-info = { features = ["derive"], workspace = true }
|
||||
pezsp-core = { workspace = true }
|
||||
pezsp-io = { workspace = true }
|
||||
pezsp-runtime = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
pezpallet-balances = { workspace = true, default-features = true }
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = [
|
||||
"codec/std",
|
||||
"pezframe-benchmarking?/std",
|
||||
"pezframe-support/std",
|
||||
"pezframe-system/std",
|
||||
"log/std",
|
||||
"pezpallet-balances/std",
|
||||
"pezpallet-bounties/std",
|
||||
"pezpallet-treasury/std",
|
||||
"scale-info/std",
|
||||
"pezsp-core/std",
|
||||
"pezsp-io/std",
|
||||
"pezsp-runtime/std",
|
||||
]
|
||||
runtime-benchmarks = [
|
||||
"pezframe-benchmarking",
|
||||
"pezframe-benchmarking/runtime-benchmarks",
|
||||
"pezframe-support/runtime-benchmarks",
|
||||
"pezframe-system/runtime-benchmarks",
|
||||
"pezpallet-balances/runtime-benchmarks",
|
||||
"pezpallet-bounties/runtime-benchmarks",
|
||||
"pezpallet-treasury/runtime-benchmarks",
|
||||
"pezsp-io/runtime-benchmarks",
|
||||
"pezsp-runtime/runtime-benchmarks",
|
||||
]
|
||||
try-runtime = [
|
||||
"pezframe-support/try-runtime",
|
||||
"pezframe-system/try-runtime",
|
||||
"pezpallet-balances/try-runtime",
|
||||
"pezpallet-bounties/try-runtime",
|
||||
"pezpallet-treasury/try-runtime",
|
||||
"pezsp-runtime/try-runtime",
|
||||
]
|
||||
@@ -0,0 +1,29 @@
|
||||
# Child Bounties Pallet ( `pezpallet-child-bounties` )
|
||||
|
||||
## Child Bounty
|
||||
|
||||
> NOTE: This pallet is tightly coupled with `pezpallet-treasury` and `pezpallet-bounties`.
|
||||
|
||||
With child bounties, a large bounty proposal can be divided into smaller chunks,
|
||||
for parallel execution, and for efficient governance and tracking of spent funds.
|
||||
A child bounty is a smaller piece of work, extracted from a parent bounty.
|
||||
A curator is assigned after the child bounty is created by the parent bounty curator,
|
||||
to be delegated with the responsibility of assigning a payout address once
|
||||
the specified set of tasks is completed.
|
||||
|
||||
## Interface
|
||||
|
||||
### Dispatchable Functions
|
||||
|
||||
Child Bounty protocol:
|
||||
|
||||
- `add_child_bounty` - Add a child bounty for a parent bounty to for dividing the work in
|
||||
smaller tasks.
|
||||
- `propose_curator` - Assign an account to a child bounty as candidate curator.
|
||||
- `accept_curator` - Accept a child bounty assignment from the parent bounty curator,
|
||||
setting a curator deposit.
|
||||
- `award_child_bounty` - Close and pay out the specified amount for the completed work.
|
||||
- `claim_child_bounty` - Claim a specific child bounty amount from the payout address.
|
||||
- `unassign_curator` - Unassign an accepted curator from a specific child bounty.
|
||||
- `close_child_bounty` - Cancel the child bounty for a specific treasury amount
|
||||
and close the bounty.
|
||||
@@ -0,0 +1,418 @@
|
||||
// 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.
|
||||
|
||||
//! Child-bounties pallet benchmarking.
|
||||
|
||||
#![cfg(feature = "runtime-benchmarks")]
|
||||
|
||||
use alloc::vec;
|
||||
use pezframe_benchmarking::{v2::*, BenchmarkError};
|
||||
use pezframe_support::ensure;
|
||||
use pezframe_system::RawOrigin;
|
||||
use pezpallet_bounties::Pallet as Bounties;
|
||||
use pezpallet_treasury::Pallet as Treasury;
|
||||
use pezsp_runtime::traits::BlockNumberProvider;
|
||||
|
||||
use crate::*;
|
||||
|
||||
const SEED: u32 = 0;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct BenchmarkChildBounty<T: Config> {
|
||||
/// Bounty ID.
|
||||
bounty_id: BountyIndex,
|
||||
/// ChildBounty ID.
|
||||
child_bounty_id: BountyIndex,
|
||||
/// The account proposing it.
|
||||
caller: T::AccountId,
|
||||
/// The master curator account.
|
||||
curator: T::AccountId,
|
||||
/// The child-bounty curator account.
|
||||
child_curator: T::AccountId,
|
||||
/// The (total) amount that should be paid if the bounty is rewarded.
|
||||
value: BalanceOf<T>,
|
||||
/// The curator fee. included in value.
|
||||
fee: BalanceOf<T>,
|
||||
/// The (total) amount that should be paid if the child-bounty is rewarded.
|
||||
child_bounty_value: BalanceOf<T>,
|
||||
/// The child-bounty curator fee. included in value.
|
||||
child_bounty_fee: BalanceOf<T>,
|
||||
/// Bounty description.
|
||||
reason: Vec<u8>,
|
||||
}
|
||||
|
||||
fn set_block_number<T: Config>(n: BlockNumberFor<T>) {
|
||||
<T as pezpallet_treasury::Config>::BlockNumberProvider::set_block_number(n);
|
||||
}
|
||||
|
||||
fn setup_bounty<T: Config>(
|
||||
user: u32,
|
||||
description: u32,
|
||||
) -> (T::AccountId, T::AccountId, BalanceOf<T>, BalanceOf<T>, Vec<u8>) {
|
||||
let caller = account("caller", user, SEED);
|
||||
let value: BalanceOf<T> = T::BountyValueMinimum::get().saturating_mul(100u32.into());
|
||||
let fee = value / 2u32.into();
|
||||
let deposit = T::BountyDepositBase::get() +
|
||||
T::DataDepositPerByte::get() * T::MaximumReasonLength::get().into();
|
||||
let _ = T::Currency::make_free_balance_be(&caller, deposit + T::Currency::minimum_balance());
|
||||
let curator = account("curator", user, SEED);
|
||||
let _ = T::Currency::make_free_balance_be(
|
||||
&curator,
|
||||
fee / 2u32.into() + T::Currency::minimum_balance(),
|
||||
);
|
||||
let reason = vec![0; description as usize];
|
||||
(caller, curator, fee, value, reason)
|
||||
}
|
||||
|
||||
fn setup_child_bounty<T: Config>(user: u32, description: u32) -> BenchmarkChildBounty<T> {
|
||||
let (caller, curator, fee, value, reason) = setup_bounty::<T>(user, description);
|
||||
let child_curator = account("child-curator", user, SEED);
|
||||
let _ = T::Currency::make_free_balance_be(
|
||||
&child_curator,
|
||||
fee / 2u32.into() + T::Currency::minimum_balance(),
|
||||
);
|
||||
let child_bounty_value = (value - fee) / 4u32.into();
|
||||
let child_bounty_fee = child_bounty_value / 2u32.into();
|
||||
|
||||
BenchmarkChildBounty::<T> {
|
||||
bounty_id: 0,
|
||||
child_bounty_id: 0,
|
||||
caller,
|
||||
curator,
|
||||
child_curator,
|
||||
value,
|
||||
fee,
|
||||
child_bounty_value,
|
||||
child_bounty_fee,
|
||||
reason,
|
||||
}
|
||||
}
|
||||
|
||||
fn activate_bounty<T: Config>(
|
||||
user: u32,
|
||||
description: u32,
|
||||
) -> Result<BenchmarkChildBounty<T>, BenchmarkError> {
|
||||
let mut child_bounty_setup = setup_child_bounty::<T>(user, description);
|
||||
let curator_lookup = T::Lookup::unlookup(child_bounty_setup.curator.clone());
|
||||
Bounties::<T>::propose_bounty(
|
||||
RawOrigin::Signed(child_bounty_setup.caller.clone()).into(),
|
||||
child_bounty_setup.value,
|
||||
child_bounty_setup.reason.clone(),
|
||||
)?;
|
||||
|
||||
child_bounty_setup.bounty_id = pezpallet_bounties::BountyCount::<T>::get() - 1;
|
||||
|
||||
let approve_origin =
|
||||
T::SpendOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
|
||||
Bounties::<T>::approve_bounty(approve_origin, child_bounty_setup.bounty_id)?;
|
||||
set_block_number::<T>(T::SpendPeriod::get());
|
||||
Treasury::<T>::on_initialize(pezframe_system::Pallet::<T>::block_number());
|
||||
Bounties::<T>::propose_curator(
|
||||
RawOrigin::Root.into(),
|
||||
child_bounty_setup.bounty_id,
|
||||
curator_lookup,
|
||||
child_bounty_setup.fee,
|
||||
)?;
|
||||
Bounties::<T>::accept_curator(
|
||||
RawOrigin::Signed(child_bounty_setup.curator.clone()).into(),
|
||||
child_bounty_setup.bounty_id,
|
||||
)?;
|
||||
|
||||
Ok(child_bounty_setup)
|
||||
}
|
||||
|
||||
fn activate_child_bounty<T: Config>(
|
||||
user: u32,
|
||||
description: u32,
|
||||
) -> Result<BenchmarkChildBounty<T>, BenchmarkError> {
|
||||
let mut bounty_setup = activate_bounty::<T>(user, description)?;
|
||||
let child_curator_lookup = T::Lookup::unlookup(bounty_setup.child_curator.clone());
|
||||
|
||||
Pallet::<T>::add_child_bounty(
|
||||
RawOrigin::Signed(bounty_setup.curator.clone()).into(),
|
||||
bounty_setup.bounty_id,
|
||||
bounty_setup.child_bounty_value,
|
||||
bounty_setup.reason.clone(),
|
||||
)?;
|
||||
|
||||
bounty_setup.child_bounty_id = ParentTotalChildBounties::<T>::get(bounty_setup.bounty_id) - 1;
|
||||
|
||||
Pallet::<T>::propose_curator(
|
||||
RawOrigin::Signed(bounty_setup.curator.clone()).into(),
|
||||
bounty_setup.bounty_id,
|
||||
bounty_setup.child_bounty_id,
|
||||
child_curator_lookup,
|
||||
bounty_setup.child_bounty_fee,
|
||||
)?;
|
||||
|
||||
Pallet::<T>::accept_curator(
|
||||
RawOrigin::Signed(bounty_setup.child_curator.clone()).into(),
|
||||
bounty_setup.bounty_id,
|
||||
bounty_setup.child_bounty_id,
|
||||
)?;
|
||||
|
||||
Ok(bounty_setup)
|
||||
}
|
||||
|
||||
fn setup_pot_account<T: Config>() {
|
||||
let pot_account = Bounties::<T>::account_id();
|
||||
let value = T::Currency::minimum_balance().saturating_mul(1_000_000_000u32.into());
|
||||
let _ = T::Currency::make_free_balance_be(&pot_account, value);
|
||||
}
|
||||
|
||||
fn assert_last_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) {
|
||||
pezframe_system::Pallet::<T>::assert_last_event(generic_event.into());
|
||||
}
|
||||
|
||||
#[benchmarks]
|
||||
mod benchmarks {
|
||||
use super::*;
|
||||
|
||||
#[benchmark]
|
||||
fn add_child_bounty(
|
||||
d: Linear<0, { T::MaximumReasonLength::get() }>,
|
||||
) -> Result<(), BenchmarkError> {
|
||||
setup_pot_account::<T>();
|
||||
let bounty_setup = activate_bounty::<T>(0, d)?;
|
||||
|
||||
#[extrinsic_call]
|
||||
_(
|
||||
RawOrigin::Signed(bounty_setup.curator),
|
||||
bounty_setup.bounty_id,
|
||||
bounty_setup.child_bounty_value,
|
||||
bounty_setup.reason.clone(),
|
||||
);
|
||||
|
||||
assert_last_event::<T>(
|
||||
Event::Added {
|
||||
index: bounty_setup.bounty_id,
|
||||
child_index: bounty_setup.child_bounty_id,
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn propose_curator() -> Result<(), BenchmarkError> {
|
||||
setup_pot_account::<T>();
|
||||
let bounty_setup = activate_bounty::<T>(0, T::MaximumReasonLength::get())?;
|
||||
let child_curator_lookup = T::Lookup::unlookup(bounty_setup.child_curator.clone());
|
||||
|
||||
Pallet::<T>::add_child_bounty(
|
||||
RawOrigin::Signed(bounty_setup.curator.clone()).into(),
|
||||
bounty_setup.bounty_id,
|
||||
bounty_setup.child_bounty_value,
|
||||
bounty_setup.reason.clone(),
|
||||
)?;
|
||||
let child_bounty_id = ParentTotalChildBounties::<T>::get(bounty_setup.bounty_id) - 1;
|
||||
|
||||
#[extrinsic_call]
|
||||
_(
|
||||
RawOrigin::Signed(bounty_setup.curator),
|
||||
bounty_setup.bounty_id,
|
||||
child_bounty_id,
|
||||
child_curator_lookup,
|
||||
bounty_setup.child_bounty_fee,
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn accept_curator() -> Result<(), BenchmarkError> {
|
||||
setup_pot_account::<T>();
|
||||
let mut bounty_setup = activate_bounty::<T>(0, T::MaximumReasonLength::get())?;
|
||||
let child_curator_lookup = T::Lookup::unlookup(bounty_setup.child_curator.clone());
|
||||
|
||||
Pallet::<T>::add_child_bounty(
|
||||
RawOrigin::Signed(bounty_setup.curator.clone()).into(),
|
||||
bounty_setup.bounty_id,
|
||||
bounty_setup.child_bounty_value,
|
||||
bounty_setup.reason.clone(),
|
||||
)?;
|
||||
bounty_setup.child_bounty_id =
|
||||
ParentTotalChildBounties::<T>::get(bounty_setup.bounty_id) - 1;
|
||||
|
||||
Pallet::<T>::propose_curator(
|
||||
RawOrigin::Signed(bounty_setup.curator.clone()).into(),
|
||||
bounty_setup.bounty_id,
|
||||
bounty_setup.child_bounty_id,
|
||||
child_curator_lookup,
|
||||
bounty_setup.child_bounty_fee,
|
||||
)?;
|
||||
|
||||
#[extrinsic_call]
|
||||
_(
|
||||
RawOrigin::Signed(bounty_setup.child_curator),
|
||||
bounty_setup.bounty_id,
|
||||
bounty_setup.child_bounty_id,
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Worst case when curator is inactive and any sender un-assigns the curator,
|
||||
// or if `BountyUpdatePeriod` is large enough and `RejectOrigin` executes the call.
|
||||
#[benchmark]
|
||||
fn unassign_curator() -> Result<(), BenchmarkError> {
|
||||
setup_pot_account::<T>();
|
||||
let bounty_setup = activate_child_bounty::<T>(0, T::MaximumReasonLength::get())?;
|
||||
Treasury::<T>::on_initialize(pezframe_system::Pallet::<T>::block_number());
|
||||
let bounty_update_period = T::BountyUpdatePeriod::get();
|
||||
let inactivity_timeout = T::SpendPeriod::get().saturating_add(bounty_update_period);
|
||||
set_block_number::<T>(inactivity_timeout.saturating_add(1u32.into()));
|
||||
|
||||
// If `BountyUpdatePeriod` overflows the inactivity timeout the benchmark still
|
||||
// executes the slash
|
||||
let origin: T::RuntimeOrigin = if Pallet::<T>::treasury_block_number() <= inactivity_timeout
|
||||
{
|
||||
let child_curator = bounty_setup.child_curator;
|
||||
T::RejectOrigin::try_successful_origin()
|
||||
.unwrap_or_else(|_| RawOrigin::Signed(child_curator).into())
|
||||
} else {
|
||||
let caller = whitelisted_caller();
|
||||
RawOrigin::Signed(caller).into()
|
||||
};
|
||||
|
||||
#[extrinsic_call]
|
||||
_(origin as T::RuntimeOrigin, bounty_setup.bounty_id, bounty_setup.child_bounty_id);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn award_child_bounty() -> Result<(), BenchmarkError> {
|
||||
setup_pot_account::<T>();
|
||||
let bounty_setup = activate_child_bounty::<T>(0, T::MaximumReasonLength::get())?;
|
||||
let beneficiary_account = account::<T::AccountId>("beneficiary", 0, SEED);
|
||||
let beneficiary = T::Lookup::unlookup(beneficiary_account.clone());
|
||||
|
||||
#[extrinsic_call]
|
||||
_(
|
||||
RawOrigin::Signed(bounty_setup.child_curator),
|
||||
bounty_setup.bounty_id,
|
||||
bounty_setup.child_bounty_id,
|
||||
beneficiary,
|
||||
);
|
||||
|
||||
assert_last_event::<T>(
|
||||
Event::Awarded {
|
||||
index: bounty_setup.bounty_id,
|
||||
child_index: bounty_setup.child_bounty_id,
|
||||
beneficiary: beneficiary_account,
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn claim_child_bounty() -> Result<(), BenchmarkError> {
|
||||
setup_pot_account::<T>();
|
||||
let bounty_setup = activate_child_bounty::<T>(0, T::MaximumReasonLength::get())?;
|
||||
let beneficiary_account = account("beneficiary", 0, SEED);
|
||||
let beneficiary = T::Lookup::unlookup(beneficiary_account);
|
||||
|
||||
Pallet::<T>::award_child_bounty(
|
||||
RawOrigin::Signed(bounty_setup.child_curator.clone()).into(),
|
||||
bounty_setup.bounty_id,
|
||||
bounty_setup.child_bounty_id,
|
||||
beneficiary,
|
||||
)?;
|
||||
|
||||
let beneficiary_account = account("beneficiary", 0, SEED);
|
||||
|
||||
set_block_number::<T>(T::SpendPeriod::get() + T::BountyDepositPayoutDelay::get());
|
||||
ensure!(
|
||||
T::Currency::free_balance(&beneficiary_account).is_zero(),
|
||||
"Beneficiary already has balance."
|
||||
);
|
||||
|
||||
#[extrinsic_call]
|
||||
_(
|
||||
RawOrigin::Signed(bounty_setup.curator),
|
||||
bounty_setup.bounty_id,
|
||||
bounty_setup.child_bounty_id,
|
||||
);
|
||||
|
||||
ensure!(
|
||||
!T::Currency::free_balance(&beneficiary_account).is_zero(),
|
||||
"Beneficiary didn't get paid."
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Best case scenario.
|
||||
#[benchmark]
|
||||
fn close_child_bounty_added() -> Result<(), BenchmarkError> {
|
||||
setup_pot_account::<T>();
|
||||
let mut bounty_setup = activate_bounty::<T>(0, T::MaximumReasonLength::get())?;
|
||||
|
||||
Pallet::<T>::add_child_bounty(
|
||||
RawOrigin::Signed(bounty_setup.curator.clone()).into(),
|
||||
bounty_setup.bounty_id,
|
||||
bounty_setup.child_bounty_value,
|
||||
bounty_setup.reason.clone(),
|
||||
)?;
|
||||
bounty_setup.child_bounty_id =
|
||||
ParentTotalChildBounties::<T>::get(bounty_setup.bounty_id) - 1;
|
||||
|
||||
#[extrinsic_call]
|
||||
close_child_bounty(RawOrigin::Root, bounty_setup.bounty_id, bounty_setup.child_bounty_id);
|
||||
|
||||
assert_last_event::<T>(
|
||||
Event::Canceled {
|
||||
index: bounty_setup.bounty_id,
|
||||
child_index: bounty_setup.child_bounty_id,
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Worst case scenario.
|
||||
#[benchmark]
|
||||
fn close_child_bounty_active() -> Result<(), BenchmarkError> {
|
||||
setup_pot_account::<T>();
|
||||
let bounty_setup = activate_child_bounty::<T>(0, T::MaximumReasonLength::get())?;
|
||||
Treasury::<T>::on_initialize(pezframe_system::Pallet::<T>::block_number());
|
||||
|
||||
#[extrinsic_call]
|
||||
close_child_bounty(RawOrigin::Root, bounty_setup.bounty_id, bounty_setup.child_bounty_id);
|
||||
|
||||
assert_last_event::<T>(
|
||||
Event::Canceled {
|
||||
index: bounty_setup.bounty_id,
|
||||
child_index: bounty_setup.child_bounty_id,
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl_benchmark_test_suite! {
|
||||
Pallet,
|
||||
tests::new_test_ext(),
|
||||
tests::Test
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,996 @@
|
||||
// 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.
|
||||
|
||||
//! # Child Bounties Pallet ( `pezpallet-child-bounties` )
|
||||
//!
|
||||
//! ## Child Bounty
|
||||
//!
|
||||
//! > NOTE: This pallet is tightly coupled with `pezpallet-treasury` and `pezpallet-bounties`.
|
||||
//!
|
||||
//! With child bounties, a large bounty proposal can be divided into smaller chunks,
|
||||
//! for parallel execution, and for efficient governance and tracking of spent funds.
|
||||
//! A child bounty is a smaller piece of work, extracted from a parent bounty.
|
||||
//! A curator is assigned after the child bounty is created by the parent bounty curator,
|
||||
//! to be delegated with the responsibility of assigning a payout address once the specified
|
||||
//! set of tasks is completed.
|
||||
//!
|
||||
//! ## Interface
|
||||
//!
|
||||
//! ### Dispatchable Functions
|
||||
//!
|
||||
//! Child Bounty protocol:
|
||||
//! - `add_child_bounty` - Add a child bounty for a parent bounty to for dividing the work in
|
||||
//! smaller tasks.
|
||||
//! - `propose_curator` - Assign an account to a child bounty as candidate curator.
|
||||
//! - `accept_curator` - Accept a child bounty assignment from the parent bounty curator, setting a
|
||||
//! curator deposit.
|
||||
//! - `award_child_bounty` - Close and pay out the specified amount for the completed work.
|
||||
//! - `claim_child_bounty` - Claim a specific child bounty amount from the payout address.
|
||||
//! - `unassign_curator` - Unassign an accepted curator from a specific child bounty.
|
||||
//! - `close_child_bounty` - Cancel the child bounty for a specific treasury amount and close the
|
||||
//! bounty.
|
||||
|
||||
// Most of the business logic in this pallet has been
|
||||
// originally contributed by "https://github.com/shamb0",
|
||||
// as part of the PR - https://github.com/pezkuwichain/kurdistan-sdk/issues/74.
|
||||
// The code has been moved here and then refactored in order to
|
||||
// extract child bounties as a separate pallet.
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
mod benchmarking;
|
||||
pub mod migration;
|
||||
mod tests;
|
||||
pub mod weights;
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
/// The log target for this pallet.
|
||||
const LOG_TARGET: &str = "runtime::child-bounties";
|
||||
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use pezframe_support::traits::{
|
||||
Currency,
|
||||
ExistenceRequirement::{AllowDeath, KeepAlive},
|
||||
Get, OnUnbalanced, ReservableCurrency, WithdrawReasons,
|
||||
};
|
||||
|
||||
use pezsp_runtime::{
|
||||
traits::{
|
||||
AccountIdConversion, BadOrigin, BlockNumberProvider, CheckedSub, Saturating, StaticLookup,
|
||||
Zero,
|
||||
},
|
||||
DispatchResult, RuntimeDebug,
|
||||
};
|
||||
|
||||
use pezframe_support::pezpallet_prelude::*;
|
||||
use pezframe_system::pezpallet_prelude::{
|
||||
ensure_signed, BlockNumberFor as SystemBlockNumberFor, OriginFor,
|
||||
};
|
||||
use pezpallet_bounties::BountyStatus;
|
||||
use scale_info::TypeInfo;
|
||||
pub use weights::WeightInfo;
|
||||
|
||||
pub use pallet::*;
|
||||
|
||||
pub type BalanceOf<T> = pezpallet_treasury::BalanceOf<T>;
|
||||
pub type BountiesError<T> = pezpallet_bounties::Error<T>;
|
||||
pub type BountyIndex = pezpallet_bounties::BountyIndex;
|
||||
pub type AccountIdLookupOf<T> = <<T as pezframe_system::Config>::Lookup as StaticLookup>::Source;
|
||||
pub type BlockNumberFor<T> =
|
||||
<<T as pezpallet_treasury::Config>::BlockNumberProvider as BlockNumberProvider>::BlockNumber;
|
||||
|
||||
/// A child bounty proposal.
|
||||
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
|
||||
pub struct ChildBounty<AccountId, Balance, BlockNumber> {
|
||||
/// The parent of this child-bounty.
|
||||
pub parent_bounty: BountyIndex,
|
||||
/// The (total) amount that should be paid if this child-bounty is rewarded.
|
||||
pub value: Balance,
|
||||
/// The child bounty curator fee.
|
||||
pub fee: Balance,
|
||||
/// The deposit of child-bounty curator.
|
||||
pub curator_deposit: Balance,
|
||||
/// The status of this child-bounty.
|
||||
pub status: ChildBountyStatus<AccountId, BlockNumber>,
|
||||
}
|
||||
|
||||
/// The status of a child-bounty.
|
||||
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
|
||||
pub enum ChildBountyStatus<AccountId, BlockNumber> {
|
||||
/// The child-bounty is added and waiting for curator assignment.
|
||||
Added,
|
||||
/// A curator has been proposed by the parent bounty curator. Waiting for
|
||||
/// acceptance from the child-bounty curator.
|
||||
CuratorProposed {
|
||||
/// The assigned child-bounty curator of this bounty.
|
||||
curator: AccountId,
|
||||
},
|
||||
/// The child-bounty is active and waiting to be awarded.
|
||||
Active {
|
||||
/// The curator of this child-bounty.
|
||||
curator: AccountId,
|
||||
},
|
||||
/// The child-bounty is awarded and waiting to released after a delay.
|
||||
PendingPayout {
|
||||
/// The curator of this child-bounty.
|
||||
curator: AccountId,
|
||||
/// The beneficiary of the child-bounty.
|
||||
beneficiary: AccountId,
|
||||
/// When the child-bounty can be claimed.
|
||||
unlock_at: BlockNumber,
|
||||
},
|
||||
}
|
||||
|
||||
#[pezframe_support::pallet]
|
||||
pub mod pallet {
|
||||
|
||||
use super::*;
|
||||
|
||||
/// The in-code storage version.
|
||||
const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
|
||||
|
||||
#[pallet::pallet]
|
||||
#[pallet::storage_version(STORAGE_VERSION)]
|
||||
pub struct Pallet<T>(_);
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config:
|
||||
pezframe_system::Config + pezpallet_treasury::Config + pezpallet_bounties::Config
|
||||
{
|
||||
/// Maximum number of child bounties that can be added to a parent bounty.
|
||||
#[pallet::constant]
|
||||
type MaxActiveChildBountyCount: Get<u32>;
|
||||
|
||||
/// Minimum value for a child-bounty.
|
||||
#[pallet::constant]
|
||||
type ChildBountyValueMinimum: Get<BalanceOf<Self>>;
|
||||
|
||||
/// The overarching event type.
|
||||
#[allow(deprecated)]
|
||||
type RuntimeEvent: From<Event<Self>> + IsType<<Self as pezframe_system::Config>::RuntimeEvent>;
|
||||
|
||||
/// Weight information for extrinsics in this pallet.
|
||||
type WeightInfo: WeightInfo;
|
||||
}
|
||||
|
||||
#[pallet::error]
|
||||
pub enum Error<T> {
|
||||
/// The parent bounty is not in active state.
|
||||
ParentBountyNotActive,
|
||||
/// The bounty balance is not enough to add new child-bounty.
|
||||
InsufficientBountyBalance,
|
||||
/// Number of child bounties exceeds limit `MaxActiveChildBountyCount`.
|
||||
TooManyChildBounties,
|
||||
}
|
||||
|
||||
#[pallet::event]
|
||||
#[pallet::generate_deposit(pub(super) fn deposit_event)]
|
||||
pub enum Event<T: Config> {
|
||||
/// A child-bounty is added.
|
||||
Added { index: BountyIndex, child_index: BountyIndex },
|
||||
/// A child-bounty is awarded to a beneficiary.
|
||||
Awarded { index: BountyIndex, child_index: BountyIndex, beneficiary: T::AccountId },
|
||||
/// A child-bounty is claimed by beneficiary.
|
||||
Claimed {
|
||||
index: BountyIndex,
|
||||
child_index: BountyIndex,
|
||||
payout: BalanceOf<T>,
|
||||
beneficiary: T::AccountId,
|
||||
},
|
||||
/// A child-bounty is cancelled.
|
||||
Canceled { index: BountyIndex, child_index: BountyIndex },
|
||||
}
|
||||
|
||||
/// DEPRECATED: Replaced with `ParentTotalChildBounties` storage item keeping dedicated counts
|
||||
/// for each parent bounty. Number of total child bounties. Will be removed in May 2025.
|
||||
#[pallet::storage]
|
||||
pub type ChildBountyCount<T: Config> = StorageValue<_, BountyIndex, ValueQuery>;
|
||||
|
||||
/// Number of active child bounties per parent bounty.
|
||||
/// Map of parent bounty index to number of child bounties.
|
||||
#[pallet::storage]
|
||||
pub type ParentChildBounties<T: Config> =
|
||||
StorageMap<_, Twox64Concat, BountyIndex, u32, ValueQuery>;
|
||||
|
||||
/// Number of total child bounties per parent bounty, including completed bounties.
|
||||
#[pallet::storage]
|
||||
pub type ParentTotalChildBounties<T: Config> =
|
||||
StorageMap<_, Twox64Concat, BountyIndex, u32, ValueQuery>;
|
||||
|
||||
/// Child bounties that have been added.
|
||||
#[pallet::storage]
|
||||
pub type ChildBounties<T: Config> = StorageDoubleMap<
|
||||
_,
|
||||
Twox64Concat,
|
||||
BountyIndex,
|
||||
Twox64Concat,
|
||||
BountyIndex,
|
||||
ChildBounty<T::AccountId, BalanceOf<T>, BlockNumberFor<T>>,
|
||||
>;
|
||||
|
||||
/// The description of each child-bounty. Indexed by `(parent_id, child_id)`.
|
||||
///
|
||||
/// This item replaces the `ChildBountyDescriptions` storage item from the V0 storage version.
|
||||
#[pallet::storage]
|
||||
pub type ChildBountyDescriptionsV1<T: Config> = StorageDoubleMap<
|
||||
_,
|
||||
Twox64Concat,
|
||||
BountyIndex,
|
||||
Twox64Concat,
|
||||
BountyIndex,
|
||||
BoundedVec<u8, T::MaximumReasonLength>,
|
||||
>;
|
||||
|
||||
/// The mapping of the child bounty ids from storage version `V0` to the new `V1` version.
|
||||
///
|
||||
/// The `V0` ids based on total child bounty count [`ChildBountyCount`]`. The `V1` version ids
|
||||
/// based on the child bounty count per parent bounty [`ParentTotalChildBounties`].
|
||||
/// The item intended solely for client convenience and not used in the pallet's core logic.
|
||||
#[pallet::storage]
|
||||
pub type V0ToV1ChildBountyIds<T: Config> =
|
||||
StorageMap<_, Twox64Concat, BountyIndex, (BountyIndex, BountyIndex)>;
|
||||
|
||||
/// The cumulative child-bounty curator fee for each parent bounty.
|
||||
#[pallet::storage]
|
||||
pub type ChildrenCuratorFees<T: Config> =
|
||||
StorageMap<_, Twox64Concat, BountyIndex, BalanceOf<T>, ValueQuery>;
|
||||
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {
|
||||
/// Add a new child-bounty.
|
||||
///
|
||||
/// The dispatch origin for this call must be the curator of parent
|
||||
/// bounty and the parent bounty must be in "active" state.
|
||||
///
|
||||
/// Child-bounty gets added successfully & fund gets transferred from
|
||||
/// parent bounty to child-bounty account, if parent bounty has enough
|
||||
/// funds, else the call fails.
|
||||
///
|
||||
/// Upper bound to maximum number of active child bounties that can be
|
||||
/// added are managed via runtime trait config
|
||||
/// [`Config::MaxActiveChildBountyCount`].
|
||||
///
|
||||
/// If the call is success, the status of child-bounty is updated to
|
||||
/// "Added".
|
||||
///
|
||||
/// - `parent_bounty_id`: Index of parent bounty for which child-bounty is being added.
|
||||
/// - `value`: Value for executing the proposal.
|
||||
/// - `description`: Text description for the child-bounty.
|
||||
#[pallet::call_index(0)]
|
||||
#[pallet::weight(<T as Config>::WeightInfo::add_child_bounty(description.len() as u32))]
|
||||
pub fn add_child_bounty(
|
||||
origin: OriginFor<T>,
|
||||
#[pallet::compact] parent_bounty_id: BountyIndex,
|
||||
#[pallet::compact] value: BalanceOf<T>,
|
||||
description: Vec<u8>,
|
||||
) -> DispatchResult {
|
||||
let signer = ensure_signed(origin)?;
|
||||
|
||||
// Verify the arguments.
|
||||
let bounded_description =
|
||||
description.try_into().map_err(|_| BountiesError::<T>::ReasonTooBig)?;
|
||||
ensure!(value >= T::ChildBountyValueMinimum::get(), BountiesError::<T>::InvalidValue);
|
||||
ensure!(
|
||||
ParentChildBounties::<T>::get(parent_bounty_id) <=
|
||||
T::MaxActiveChildBountyCount::get() as u32,
|
||||
Error::<T>::TooManyChildBounties,
|
||||
);
|
||||
|
||||
let (curator, _) = Self::ensure_bounty_active(parent_bounty_id)?;
|
||||
ensure!(signer == curator, BountiesError::<T>::RequireCurator);
|
||||
|
||||
// Read parent bounty account info.
|
||||
let parent_bounty_account =
|
||||
pezpallet_bounties::Pallet::<T>::bounty_account_id(parent_bounty_id);
|
||||
|
||||
// Ensure parent bounty has enough balance after adding child-bounty.
|
||||
let bounty_balance = T::Currency::free_balance(&parent_bounty_account);
|
||||
let new_bounty_balance = bounty_balance
|
||||
.checked_sub(&value)
|
||||
.ok_or(Error::<T>::InsufficientBountyBalance)?;
|
||||
T::Currency::ensure_can_withdraw(
|
||||
&parent_bounty_account,
|
||||
value,
|
||||
WithdrawReasons::TRANSFER,
|
||||
new_bounty_balance,
|
||||
)?;
|
||||
|
||||
// Get child-bounty ID.
|
||||
let child_bounty_id = ParentTotalChildBounties::<T>::get(parent_bounty_id);
|
||||
let child_bounty_account =
|
||||
Self::child_bounty_account_id(parent_bounty_id, child_bounty_id);
|
||||
|
||||
// Transfer funds from parent bounty to child-bounty.
|
||||
T::Currency::transfer(&parent_bounty_account, &child_bounty_account, value, KeepAlive)?;
|
||||
|
||||
// Increment the active child-bounty count.
|
||||
ParentChildBounties::<T>::mutate(parent_bounty_id, |count| count.saturating_inc());
|
||||
ParentTotalChildBounties::<T>::insert(
|
||||
parent_bounty_id,
|
||||
child_bounty_id.saturating_add(1),
|
||||
);
|
||||
|
||||
// Create child-bounty instance.
|
||||
Self::create_child_bounty(
|
||||
parent_bounty_id,
|
||||
child_bounty_id,
|
||||
value,
|
||||
bounded_description,
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Propose curator for funded child-bounty.
|
||||
///
|
||||
/// The dispatch origin for this call must be curator of parent bounty.
|
||||
///
|
||||
/// Parent bounty must be in active state, for this child-bounty call to
|
||||
/// work.
|
||||
///
|
||||
/// Child-bounty must be in "Added" state, for processing the call. And
|
||||
/// state of child-bounty is moved to "CuratorProposed" on successful
|
||||
/// call completion.
|
||||
///
|
||||
/// - `parent_bounty_id`: Index of parent bounty.
|
||||
/// - `child_bounty_id`: Index of child bounty.
|
||||
/// - `curator`: Address of child-bounty curator.
|
||||
/// - `fee`: payment fee to child-bounty curator for execution.
|
||||
#[pallet::call_index(1)]
|
||||
#[pallet::weight(<T as Config>::WeightInfo::propose_curator())]
|
||||
pub fn propose_curator(
|
||||
origin: OriginFor<T>,
|
||||
#[pallet::compact] parent_bounty_id: BountyIndex,
|
||||
#[pallet::compact] child_bounty_id: BountyIndex,
|
||||
curator: AccountIdLookupOf<T>,
|
||||
#[pallet::compact] fee: BalanceOf<T>,
|
||||
) -> DispatchResult {
|
||||
let signer = ensure_signed(origin)?;
|
||||
let child_bounty_curator = T::Lookup::lookup(curator)?;
|
||||
|
||||
let (curator, _) = Self::ensure_bounty_active(parent_bounty_id)?;
|
||||
ensure!(signer == curator, BountiesError::<T>::RequireCurator);
|
||||
|
||||
// Mutate the child-bounty instance.
|
||||
ChildBounties::<T>::try_mutate_exists(
|
||||
parent_bounty_id,
|
||||
child_bounty_id,
|
||||
|maybe_child_bounty| -> DispatchResult {
|
||||
let child_bounty =
|
||||
maybe_child_bounty.as_mut().ok_or(BountiesError::<T>::InvalidIndex)?;
|
||||
|
||||
// Ensure child-bounty is in expected state.
|
||||
ensure!(
|
||||
child_bounty.status == ChildBountyStatus::Added,
|
||||
BountiesError::<T>::UnexpectedStatus,
|
||||
);
|
||||
|
||||
// Ensure child-bounty curator fee is less than child-bounty value.
|
||||
ensure!(fee < child_bounty.value, BountiesError::<T>::InvalidFee);
|
||||
|
||||
// Add child-bounty curator fee to the cumulative sum. To be
|
||||
// subtracted from the parent bounty curator when claiming
|
||||
// bounty.
|
||||
ChildrenCuratorFees::<T>::mutate(parent_bounty_id, |value| {
|
||||
*value = value.saturating_add(fee)
|
||||
});
|
||||
|
||||
// Update the child-bounty curator fee.
|
||||
child_bounty.fee = fee;
|
||||
|
||||
// Update the child-bounty state.
|
||||
child_bounty.status =
|
||||
ChildBountyStatus::CuratorProposed { curator: child_bounty_curator };
|
||||
|
||||
Ok(())
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// Accept the curator role for the child-bounty.
|
||||
///
|
||||
/// The dispatch origin for this call must be the curator of this
|
||||
/// child-bounty.
|
||||
///
|
||||
/// A deposit will be reserved from the curator and refund upon
|
||||
/// successful payout or cancellation.
|
||||
///
|
||||
/// Fee for curator is deducted from curator fee of parent bounty.
|
||||
///
|
||||
/// Parent bounty must be in active state, for this child-bounty call to
|
||||
/// work.
|
||||
///
|
||||
/// Child-bounty must be in "CuratorProposed" state, for processing the
|
||||
/// call. And state of child-bounty is moved to "Active" on successful
|
||||
/// call completion.
|
||||
///
|
||||
/// - `parent_bounty_id`: Index of parent bounty.
|
||||
/// - `child_bounty_id`: Index of child bounty.
|
||||
#[pallet::call_index(2)]
|
||||
#[pallet::weight(<T as Config>::WeightInfo::accept_curator())]
|
||||
pub fn accept_curator(
|
||||
origin: OriginFor<T>,
|
||||
#[pallet::compact] parent_bounty_id: BountyIndex,
|
||||
#[pallet::compact] child_bounty_id: BountyIndex,
|
||||
) -> DispatchResult {
|
||||
let signer = ensure_signed(origin)?;
|
||||
|
||||
let (parent_curator, _) = Self::ensure_bounty_active(parent_bounty_id)?;
|
||||
// Mutate child-bounty.
|
||||
ChildBounties::<T>::try_mutate_exists(
|
||||
parent_bounty_id,
|
||||
child_bounty_id,
|
||||
|maybe_child_bounty| -> DispatchResult {
|
||||
let child_bounty =
|
||||
maybe_child_bounty.as_mut().ok_or(BountiesError::<T>::InvalidIndex)?;
|
||||
|
||||
// Ensure child-bounty is in expected state.
|
||||
if let ChildBountyStatus::CuratorProposed { ref curator } = child_bounty.status
|
||||
{
|
||||
ensure!(signer == *curator, BountiesError::<T>::RequireCurator);
|
||||
|
||||
// Reserve child-bounty curator deposit.
|
||||
let deposit = Self::calculate_curator_deposit(
|
||||
&parent_curator,
|
||||
curator,
|
||||
&child_bounty.fee,
|
||||
);
|
||||
|
||||
T::Currency::reserve(curator, deposit)?;
|
||||
child_bounty.curator_deposit = deposit;
|
||||
|
||||
child_bounty.status =
|
||||
ChildBountyStatus::Active { curator: curator.clone() };
|
||||
Ok(())
|
||||
} else {
|
||||
Err(BountiesError::<T>::UnexpectedStatus.into())
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// Unassign curator from a child-bounty.
|
||||
///
|
||||
/// The dispatch origin for this call can be either `RejectOrigin`, or
|
||||
/// the curator of the parent bounty, or any signed origin.
|
||||
///
|
||||
/// For the origin other than T::RejectOrigin and the child-bounty
|
||||
/// curator, parent bounty must be in active state, for this call to
|
||||
/// work. We allow child-bounty curator and T::RejectOrigin to execute
|
||||
/// this call irrespective of the parent bounty state.
|
||||
///
|
||||
/// If this function is called by the `RejectOrigin` or the
|
||||
/// parent bounty curator, we assume that the child-bounty curator is
|
||||
/// malicious or inactive. As a result, child-bounty curator deposit is
|
||||
/// slashed.
|
||||
///
|
||||
/// If the origin is the child-bounty curator, we take this as a sign
|
||||
/// that they are unable to do their job, and are willingly giving up.
|
||||
/// We could slash the deposit, but for now we allow them to unreserve
|
||||
/// their deposit and exit without issue. (We may want to change this if
|
||||
/// it is abused.)
|
||||
///
|
||||
/// Finally, the origin can be anyone iff the child-bounty curator is
|
||||
/// "inactive". Expiry update due of parent bounty is used to estimate
|
||||
/// inactive state of child-bounty curator.
|
||||
///
|
||||
/// This allows anyone in the community to call out that a child-bounty
|
||||
/// curator is not doing their due diligence, and we should pick a new
|
||||
/// one. In this case the child-bounty curator deposit is slashed.
|
||||
///
|
||||
/// State of child-bounty is moved to Added state on successful call
|
||||
/// completion.
|
||||
///
|
||||
/// - `parent_bounty_id`: Index of parent bounty.
|
||||
/// - `child_bounty_id`: Index of child bounty.
|
||||
#[pallet::call_index(3)]
|
||||
#[pallet::weight(<T as Config>::WeightInfo::unassign_curator())]
|
||||
pub fn unassign_curator(
|
||||
origin: OriginFor<T>,
|
||||
#[pallet::compact] parent_bounty_id: BountyIndex,
|
||||
#[pallet::compact] child_bounty_id: BountyIndex,
|
||||
) -> DispatchResult {
|
||||
let maybe_sender = ensure_signed(origin.clone())
|
||||
.map(Some)
|
||||
.or_else(|_| T::RejectOrigin::ensure_origin(origin).map(|_| None))?;
|
||||
|
||||
ChildBounties::<T>::try_mutate_exists(
|
||||
parent_bounty_id,
|
||||
child_bounty_id,
|
||||
|maybe_child_bounty| -> DispatchResult {
|
||||
let child_bounty =
|
||||
maybe_child_bounty.as_mut().ok_or(BountiesError::<T>::InvalidIndex)?;
|
||||
|
||||
let slash_curator =
|
||||
|curator: &T::AccountId, curator_deposit: &mut BalanceOf<T>| {
|
||||
let imbalance =
|
||||
T::Currency::slash_reserved(curator, *curator_deposit).0;
|
||||
T::OnSlash::on_unbalanced(imbalance);
|
||||
*curator_deposit = Zero::zero();
|
||||
};
|
||||
|
||||
match child_bounty.status {
|
||||
ChildBountyStatus::Added => {
|
||||
// No curator to unassign at this point.
|
||||
return Err(BountiesError::<T>::UnexpectedStatus.into());
|
||||
},
|
||||
ChildBountyStatus::CuratorProposed { ref curator } => {
|
||||
// A child-bounty curator has been proposed, but not accepted yet.
|
||||
// Either `RejectOrigin`, parent bounty curator or the proposed
|
||||
// child-bounty curator can unassign the child-bounty curator.
|
||||
ensure!(
|
||||
maybe_sender.map_or(true, |sender| {
|
||||
sender == *curator ||
|
||||
Self::ensure_bounty_active(parent_bounty_id)
|
||||
.map_or(false, |(parent_curator, _)| {
|
||||
sender == parent_curator
|
||||
})
|
||||
}),
|
||||
BadOrigin
|
||||
);
|
||||
// Continue to change bounty status below.
|
||||
},
|
||||
ChildBountyStatus::Active { ref curator } => {
|
||||
// The child-bounty is active.
|
||||
match maybe_sender {
|
||||
// If the `RejectOrigin` is calling this function, slash the curator
|
||||
// deposit.
|
||||
None => {
|
||||
slash_curator(curator, &mut child_bounty.curator_deposit);
|
||||
// Continue to change child-bounty status below.
|
||||
},
|
||||
Some(sender) if sender == *curator => {
|
||||
// This is the child-bounty curator, willingly giving up their
|
||||
// role. Give back their deposit.
|
||||
T::Currency::unreserve(curator, child_bounty.curator_deposit);
|
||||
// Reset curator deposit.
|
||||
child_bounty.curator_deposit = Zero::zero();
|
||||
// Continue to change bounty status below.
|
||||
},
|
||||
Some(sender) => {
|
||||
let (parent_curator, update_due) =
|
||||
Self::ensure_bounty_active(parent_bounty_id)?;
|
||||
if sender == parent_curator ||
|
||||
update_due < Self::treasury_block_number()
|
||||
{
|
||||
// Slash the child-bounty curator if
|
||||
// + the call is made by the parent bounty curator.
|
||||
// + or the curator is inactive.
|
||||
slash_curator(curator, &mut child_bounty.curator_deposit);
|
||||
// Continue to change bounty status below.
|
||||
} else {
|
||||
// Curator has more time to give an update.
|
||||
return Err(BountiesError::<T>::Premature.into());
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
ChildBountyStatus::PendingPayout { ref curator, .. } => {
|
||||
let (parent_curator, _) = Self::ensure_bounty_active(parent_bounty_id)?;
|
||||
ensure!(
|
||||
maybe_sender.map_or(true, |sender| parent_curator == sender),
|
||||
BadOrigin,
|
||||
);
|
||||
slash_curator(curator, &mut child_bounty.curator_deposit);
|
||||
// Continue to change child-bounty status below.
|
||||
},
|
||||
};
|
||||
// Move the child-bounty state to Added.
|
||||
child_bounty.status = ChildBountyStatus::Added;
|
||||
Ok(())
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// Award child-bounty to a beneficiary.
|
||||
///
|
||||
/// The beneficiary will be able to claim the funds after a delay.
|
||||
///
|
||||
/// The dispatch origin for this call must be the parent curator or
|
||||
/// curator of this child-bounty.
|
||||
///
|
||||
/// Parent bounty must be in active state, for this child-bounty call to
|
||||
/// work.
|
||||
///
|
||||
/// Child-bounty must be in active state, for processing the call. And
|
||||
/// state of child-bounty is moved to "PendingPayout" on successful call
|
||||
/// completion.
|
||||
///
|
||||
/// - `parent_bounty_id`: Index of parent bounty.
|
||||
/// - `child_bounty_id`: Index of child bounty.
|
||||
/// - `beneficiary`: Beneficiary account.
|
||||
#[pallet::call_index(4)]
|
||||
#[pallet::weight(<T as Config>::WeightInfo::award_child_bounty())]
|
||||
pub fn award_child_bounty(
|
||||
origin: OriginFor<T>,
|
||||
#[pallet::compact] parent_bounty_id: BountyIndex,
|
||||
#[pallet::compact] child_bounty_id: BountyIndex,
|
||||
beneficiary: AccountIdLookupOf<T>,
|
||||
) -> DispatchResult {
|
||||
let signer = ensure_signed(origin)?;
|
||||
let beneficiary = T::Lookup::lookup(beneficiary)?;
|
||||
|
||||
// Ensure parent bounty exists, and is active.
|
||||
let (parent_curator, _) = Self::ensure_bounty_active(parent_bounty_id)?;
|
||||
|
||||
ChildBounties::<T>::try_mutate_exists(
|
||||
parent_bounty_id,
|
||||
child_bounty_id,
|
||||
|maybe_child_bounty| -> DispatchResult {
|
||||
let child_bounty =
|
||||
maybe_child_bounty.as_mut().ok_or(BountiesError::<T>::InvalidIndex)?;
|
||||
|
||||
// Ensure child-bounty is in active state.
|
||||
if let ChildBountyStatus::Active { ref curator } = child_bounty.status {
|
||||
ensure!(
|
||||
signer == *curator || signer == parent_curator,
|
||||
BountiesError::<T>::RequireCurator,
|
||||
);
|
||||
// Move the child-bounty state to pending payout.
|
||||
child_bounty.status = ChildBountyStatus::PendingPayout {
|
||||
curator: signer,
|
||||
beneficiary: beneficiary.clone(),
|
||||
unlock_at: Self::treasury_block_number() +
|
||||
T::BountyDepositPayoutDelay::get(),
|
||||
};
|
||||
Ok(())
|
||||
} else {
|
||||
Err(BountiesError::<T>::UnexpectedStatus.into())
|
||||
}
|
||||
},
|
||||
)?;
|
||||
|
||||
// Trigger the event Awarded.
|
||||
Self::deposit_event(Event::<T>::Awarded {
|
||||
index: parent_bounty_id,
|
||||
child_index: child_bounty_id,
|
||||
beneficiary,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Claim the payout from an awarded child-bounty after payout delay.
|
||||
///
|
||||
/// The dispatch origin for this call may be any signed origin.
|
||||
///
|
||||
/// Call works independent of parent bounty state, No need for parent
|
||||
/// bounty to be in active state.
|
||||
///
|
||||
/// The Beneficiary is paid out with agreed bounty value. Curator fee is
|
||||
/// paid & curator deposit is unreserved.
|
||||
///
|
||||
/// Child-bounty must be in "PendingPayout" state, for processing the
|
||||
/// call. And instance of child-bounty is removed from the state on
|
||||
/// successful call completion.
|
||||
///
|
||||
/// - `parent_bounty_id`: Index of parent bounty.
|
||||
/// - `child_bounty_id`: Index of child bounty.
|
||||
#[pallet::call_index(5)]
|
||||
#[pallet::weight(<T as Config>::WeightInfo::claim_child_bounty())]
|
||||
pub fn claim_child_bounty(
|
||||
origin: OriginFor<T>,
|
||||
#[pallet::compact] parent_bounty_id: BountyIndex,
|
||||
#[pallet::compact] child_bounty_id: BountyIndex,
|
||||
) -> DispatchResult {
|
||||
ensure_signed(origin)?;
|
||||
|
||||
// Ensure child-bounty is in expected state.
|
||||
ChildBounties::<T>::try_mutate_exists(
|
||||
parent_bounty_id,
|
||||
child_bounty_id,
|
||||
|maybe_child_bounty| -> DispatchResult {
|
||||
let child_bounty =
|
||||
maybe_child_bounty.as_mut().ok_or(BountiesError::<T>::InvalidIndex)?;
|
||||
|
||||
if let ChildBountyStatus::PendingPayout {
|
||||
ref curator,
|
||||
ref beneficiary,
|
||||
ref unlock_at,
|
||||
} = child_bounty.status
|
||||
{
|
||||
// Ensure block number is elapsed for processing the
|
||||
// claim.
|
||||
ensure!(
|
||||
Self::treasury_block_number() >= *unlock_at,
|
||||
BountiesError::<T>::Premature,
|
||||
);
|
||||
|
||||
// Make curator fee payment.
|
||||
let child_bounty_account =
|
||||
Self::child_bounty_account_id(parent_bounty_id, child_bounty_id);
|
||||
let balance = T::Currency::free_balance(&child_bounty_account);
|
||||
let curator_fee = child_bounty.fee.min(balance);
|
||||
let payout = balance.saturating_sub(curator_fee);
|
||||
|
||||
// Unreserve the curator deposit. Should not fail
|
||||
// because the deposit is always reserved when curator is
|
||||
// assigned.
|
||||
let _ = T::Currency::unreserve(curator, child_bounty.curator_deposit);
|
||||
|
||||
// Make payout to child-bounty curator.
|
||||
// Should not fail because curator fee is always less than bounty value.
|
||||
let fee_transfer_result = T::Currency::transfer(
|
||||
&child_bounty_account,
|
||||
curator,
|
||||
curator_fee,
|
||||
AllowDeath,
|
||||
);
|
||||
debug_assert!(fee_transfer_result.is_ok());
|
||||
|
||||
// Make payout to beneficiary.
|
||||
// Should not fail.
|
||||
let payout_transfer_result = T::Currency::transfer(
|
||||
&child_bounty_account,
|
||||
beneficiary,
|
||||
payout,
|
||||
AllowDeath,
|
||||
);
|
||||
debug_assert!(payout_transfer_result.is_ok());
|
||||
|
||||
// Trigger the Claimed event.
|
||||
Self::deposit_event(Event::<T>::Claimed {
|
||||
index: parent_bounty_id,
|
||||
child_index: child_bounty_id,
|
||||
payout,
|
||||
beneficiary: beneficiary.clone(),
|
||||
});
|
||||
|
||||
// Update the active child-bounty tracking count.
|
||||
ParentChildBounties::<T>::mutate(parent_bounty_id, |count| {
|
||||
count.saturating_dec()
|
||||
});
|
||||
|
||||
// Remove the child-bounty description.
|
||||
ChildBountyDescriptionsV1::<T>::remove(parent_bounty_id, child_bounty_id);
|
||||
|
||||
// Remove the child-bounty instance from the state.
|
||||
*maybe_child_bounty = None;
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
Err(BountiesError::<T>::UnexpectedStatus.into())
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// Cancel a proposed or active child-bounty. Child-bounty account funds
|
||||
/// are transferred to parent bounty account. The child-bounty curator
|
||||
/// deposit may be unreserved if possible.
|
||||
///
|
||||
/// The dispatch origin for this call must be either parent curator or
|
||||
/// `T::RejectOrigin`.
|
||||
///
|
||||
/// If the state of child-bounty is `Active`, curator deposit is
|
||||
/// unreserved.
|
||||
///
|
||||
/// If the state of child-bounty is `PendingPayout`, call fails &
|
||||
/// returns `PendingPayout` error.
|
||||
///
|
||||
/// For the origin other than T::RejectOrigin, parent bounty must be in
|
||||
/// active state, for this child-bounty call to work. For origin
|
||||
/// T::RejectOrigin execution is forced.
|
||||
///
|
||||
/// Instance of child-bounty is removed from the state on successful
|
||||
/// call completion.
|
||||
///
|
||||
/// - `parent_bounty_id`: Index of parent bounty.
|
||||
/// - `child_bounty_id`: Index of child bounty.
|
||||
#[pallet::call_index(6)]
|
||||
#[pallet::weight(<T as Config>::WeightInfo::close_child_bounty_added()
|
||||
.max(<T as Config>::WeightInfo::close_child_bounty_active()))]
|
||||
pub fn close_child_bounty(
|
||||
origin: OriginFor<T>,
|
||||
#[pallet::compact] parent_bounty_id: BountyIndex,
|
||||
#[pallet::compact] child_bounty_id: BountyIndex,
|
||||
) -> DispatchResult {
|
||||
let maybe_sender = ensure_signed(origin.clone())
|
||||
.map(Some)
|
||||
.or_else(|_| T::RejectOrigin::ensure_origin(origin).map(|_| None))?;
|
||||
|
||||
// Ensure parent bounty exist, get parent curator.
|
||||
let (parent_curator, _) = Self::ensure_bounty_active(parent_bounty_id)?;
|
||||
|
||||
ensure!(maybe_sender.map_or(true, |sender| parent_curator == sender), BadOrigin);
|
||||
|
||||
Self::impl_close_child_bounty(parent_bounty_id, child_bounty_id)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[pallet::hooks]
|
||||
impl<T: Config> Hooks<SystemBlockNumberFor<T>> for Pallet<T> {
|
||||
fn integrity_test() {
|
||||
let parent_bounty_id: BountyIndex = 1;
|
||||
let child_bounty_id: BountyIndex = 2;
|
||||
let _: T::AccountId = T::PalletId::get()
|
||||
.try_into_sub_account(("cb", parent_bounty_id, child_bounty_id))
|
||||
.expect(
|
||||
"The `AccountId` type must be large enough to fit the child bounty account ID.",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> Pallet<T> {
|
||||
/// Get the block number used in the treasury pallet.
|
||||
///
|
||||
/// It may be configured to use the relay chain block number on a teyrchain.
|
||||
pub fn treasury_block_number() -> BlockNumberFor<T> {
|
||||
<T as pezpallet_treasury::Config>::BlockNumberProvider::current_block_number()
|
||||
}
|
||||
|
||||
// This function will calculate the deposit of a curator.
|
||||
fn calculate_curator_deposit(
|
||||
parent_curator: &T::AccountId,
|
||||
child_curator: &T::AccountId,
|
||||
bounty_fee: &BalanceOf<T>,
|
||||
) -> BalanceOf<T> {
|
||||
if parent_curator == child_curator {
|
||||
return Zero::zero();
|
||||
}
|
||||
|
||||
// We just use the same logic from the parent bounties pallet.
|
||||
pezpallet_bounties::Pallet::<T>::calculate_curator_deposit(bounty_fee)
|
||||
}
|
||||
|
||||
/// The account ID of a child-bounty account.
|
||||
pub fn child_bounty_account_id(
|
||||
parent_bounty_id: BountyIndex,
|
||||
child_bounty_id: BountyIndex,
|
||||
) -> T::AccountId {
|
||||
// This function is taken from the parent (bounties) pallet, but the
|
||||
// prefix is changed to have different AccountId when the index of
|
||||
// parent and child is same.
|
||||
T::PalletId::get().into_sub_account_truncating(("cb", parent_bounty_id, child_bounty_id))
|
||||
}
|
||||
|
||||
fn create_child_bounty(
|
||||
parent_bounty_id: BountyIndex,
|
||||
child_bounty_id: BountyIndex,
|
||||
child_bounty_value: BalanceOf<T>,
|
||||
description: BoundedVec<u8, T::MaximumReasonLength>,
|
||||
) {
|
||||
let child_bounty = ChildBounty {
|
||||
parent_bounty: parent_bounty_id,
|
||||
value: child_bounty_value,
|
||||
fee: 0u32.into(),
|
||||
curator_deposit: 0u32.into(),
|
||||
status: ChildBountyStatus::Added,
|
||||
};
|
||||
ChildBounties::<T>::insert(parent_bounty_id, child_bounty_id, &child_bounty);
|
||||
ChildBountyDescriptionsV1::<T>::insert(parent_bounty_id, child_bounty_id, description);
|
||||
Self::deposit_event(Event::Added { index: parent_bounty_id, child_index: child_bounty_id });
|
||||
}
|
||||
|
||||
fn ensure_bounty_active(
|
||||
bounty_id: BountyIndex,
|
||||
) -> Result<(T::AccountId, BlockNumberFor<T>), DispatchError> {
|
||||
let parent_bounty = pezpallet_bounties::Bounties::<T>::get(bounty_id)
|
||||
.ok_or(BountiesError::<T>::InvalidIndex)?;
|
||||
if let BountyStatus::Active { curator, update_due } = parent_bounty.get_status() {
|
||||
Ok((curator, update_due))
|
||||
} else {
|
||||
Err(Error::<T>::ParentBountyNotActive.into())
|
||||
}
|
||||
}
|
||||
|
||||
fn impl_close_child_bounty(
|
||||
parent_bounty_id: BountyIndex,
|
||||
child_bounty_id: BountyIndex,
|
||||
) -> DispatchResult {
|
||||
ChildBounties::<T>::try_mutate_exists(
|
||||
parent_bounty_id,
|
||||
child_bounty_id,
|
||||
|maybe_child_bounty| -> DispatchResult {
|
||||
let child_bounty =
|
||||
maybe_child_bounty.as_mut().ok_or(BountiesError::<T>::InvalidIndex)?;
|
||||
|
||||
match &child_bounty.status {
|
||||
ChildBountyStatus::Added | ChildBountyStatus::CuratorProposed { .. } => {
|
||||
// Nothing extra to do besides the removal of the child-bounty below.
|
||||
},
|
||||
ChildBountyStatus::Active { curator } => {
|
||||
// Cancelled by parent curator or RejectOrigin,
|
||||
// refund deposit of the working child-bounty curator.
|
||||
let _ = T::Currency::unreserve(curator, child_bounty.curator_deposit);
|
||||
// Then execute removal of the child-bounty below.
|
||||
},
|
||||
ChildBountyStatus::PendingPayout { .. } => {
|
||||
// Child-bounty is already in pending payout. If parent
|
||||
// curator or RejectOrigin wants to close this
|
||||
// child-bounty, it should mean the child-bounty curator
|
||||
// was acting maliciously. So first unassign the
|
||||
// child-bounty curator, slashing their deposit.
|
||||
return Err(BountiesError::<T>::PendingPayout.into());
|
||||
},
|
||||
}
|
||||
|
||||
// Revert the curator fee back to parent bounty curator &
|
||||
// reduce the active child-bounty count.
|
||||
ChildrenCuratorFees::<T>::mutate(parent_bounty_id, |value| {
|
||||
*value = value.saturating_sub(child_bounty.fee)
|
||||
});
|
||||
ParentChildBounties::<T>::mutate(parent_bounty_id, |count| {
|
||||
*count = count.saturating_sub(1)
|
||||
});
|
||||
|
||||
// Transfer fund from child-bounty to parent bounty.
|
||||
let parent_bounty_account =
|
||||
pezpallet_bounties::Pallet::<T>::bounty_account_id(parent_bounty_id);
|
||||
let child_bounty_account =
|
||||
Self::child_bounty_account_id(parent_bounty_id, child_bounty_id);
|
||||
let balance = T::Currency::free_balance(&child_bounty_account);
|
||||
let transfer_result = T::Currency::transfer(
|
||||
&child_bounty_account,
|
||||
&parent_bounty_account,
|
||||
balance,
|
||||
AllowDeath,
|
||||
); // Should not fail; child bounty account gets this balance during creation.
|
||||
debug_assert!(transfer_result.is_ok());
|
||||
|
||||
// Remove the child-bounty description.
|
||||
ChildBountyDescriptionsV1::<T>::remove(parent_bounty_id, child_bounty_id);
|
||||
|
||||
*maybe_child_bounty = None;
|
||||
|
||||
Self::deposit_event(Event::<T>::Canceled {
|
||||
index: parent_bounty_id,
|
||||
child_index: child_bounty_id,
|
||||
});
|
||||
Ok(())
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Implement ChildBountyManager to connect with the bounties pallet. This is
|
||||
/// where we pass the active child bounties and child curator fees to the parent
|
||||
/// bounty.
|
||||
///
|
||||
/// Function `children_curator_fees` not only returns the fee but also removes cumulative curator
|
||||
/// fees during call.
|
||||
impl<T: Config> pezpallet_bounties::ChildBountyManager<BalanceOf<T>> for Pallet<T> {
|
||||
/// Returns number of active child bounties for `bounty_id`
|
||||
fn child_bounties_count(
|
||||
bounty_id: pezpallet_bounties::BountyIndex,
|
||||
) -> pezpallet_bounties::BountyIndex {
|
||||
ParentChildBounties::<T>::get(bounty_id)
|
||||
}
|
||||
|
||||
/// Returns cumulative child bounty curator fees for `bounty_id` also removing the associated
|
||||
/// storage item. This function is assumed to be called when parent bounty is claimed.
|
||||
fn children_curator_fees(bounty_id: pezpallet_bounties::BountyIndex) -> BalanceOf<T> {
|
||||
// This is asked for when the parent bounty is being claimed. No use of
|
||||
// keeping it in state after that. Hence removing.
|
||||
let children_fee_total = ChildrenCuratorFees::<T>::get(bounty_id);
|
||||
ChildrenCuratorFees::<T>::remove(bounty_id);
|
||||
children_fee_total
|
||||
}
|
||||
|
||||
/// Clean up the storage on a parent bounty removal.
|
||||
fn bounty_removed(bounty_id: BountyIndex) {
|
||||
debug_assert!(ParentChildBounties::<T>::get(bounty_id).is_zero());
|
||||
debug_assert!(ChildrenCuratorFees::<T>::get(bounty_id).is_zero());
|
||||
debug_assert!(ChildBounties::<T>::iter_key_prefix(bounty_id).count().is_zero());
|
||||
debug_assert!(ChildBountyDescriptionsV1::<T>::iter_key_prefix(bounty_id).count().is_zero());
|
||||
ParentChildBounties::<T>::remove(bounty_id);
|
||||
ParentTotalChildBounties::<T>::remove(bounty_id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
// 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.
|
||||
|
||||
use super::*;
|
||||
use core::marker::PhantomData;
|
||||
use pezframe_support::{
|
||||
storage_alias,
|
||||
traits::{Get, UncheckedOnRuntimeUpgrade},
|
||||
};
|
||||
|
||||
use alloc::collections::BTreeSet;
|
||||
#[cfg(feature = "try-runtime")]
|
||||
use alloc::vec::Vec;
|
||||
#[cfg(feature = "try-runtime")]
|
||||
use pezframe_support::ensure;
|
||||
|
||||
pub mod v1 {
|
||||
use super::*;
|
||||
|
||||
/// Creates a new ids for the child balances based on the child bounty count per parent bounty
|
||||
/// instead of the total child bounty count. Translates the existing child bounties to the new
|
||||
/// ids. Creates the `V0ToV1ChildBountyIds` map from `old_child_id` to new (`parent_id`,
|
||||
/// `new_child_id`).
|
||||
///
|
||||
/// `TransferWeight` returns `Weight` of `T::Currency::transfer` and `T::Currency::free_balance`
|
||||
/// operation which is performed during this migration.
|
||||
pub struct MigrateToV1Impl<T, TransferWeight>(PhantomData<(T, TransferWeight)>);
|
||||
|
||||
#[storage_alias]
|
||||
type ChildBountyDescriptions<T: Config + pezpallet_bounties::Config> = StorageMap<
|
||||
Pallet<T>,
|
||||
Twox64Concat,
|
||||
BountyIndex,
|
||||
BoundedVec<u8, <T as pezpallet_bounties::Config>::MaximumReasonLength>,
|
||||
>;
|
||||
|
||||
impl<T: Config, TransferWeight: Get<Weight>> UncheckedOnRuntimeUpgrade
|
||||
for MigrateToV1Impl<T, TransferWeight>
|
||||
{
|
||||
fn on_runtime_upgrade() -> pezframe_support::weights::Weight {
|
||||
// increment reads/writes after the action
|
||||
let mut reads = 0u64;
|
||||
let mut writes = 0u64;
|
||||
let mut transfer_weights: Weight = Weight::zero();
|
||||
|
||||
// keep ids order roughly the same with the old order
|
||||
let mut old_bounty_ids = BTreeSet::new();
|
||||
// first iteration collect all existing ids not to mutate map as we iterate it
|
||||
for (parent_bounty_id, old_child_bounty_id) in ChildBounties::<T>::iter_keys() {
|
||||
reads += 1;
|
||||
old_bounty_ids.insert((parent_bounty_id, old_child_bounty_id));
|
||||
}
|
||||
|
||||
log::info!(
|
||||
target: LOG_TARGET,
|
||||
"Migrating {} child bounties",
|
||||
old_bounty_ids.len(),
|
||||
);
|
||||
|
||||
for (parent_bounty_id, old_child_bounty_id) in old_bounty_ids {
|
||||
// assign new child bounty id
|
||||
let new_child_bounty_id = ParentTotalChildBounties::<T>::get(parent_bounty_id);
|
||||
reads += 1;
|
||||
ParentTotalChildBounties::<T>::insert(
|
||||
parent_bounty_id,
|
||||
new_child_bounty_id.saturating_add(1),
|
||||
);
|
||||
writes += 1;
|
||||
|
||||
V0ToV1ChildBountyIds::<T>::insert(
|
||||
old_child_bounty_id,
|
||||
(parent_bounty_id, new_child_bounty_id),
|
||||
);
|
||||
writes += 1;
|
||||
|
||||
let old_child_bounty_account =
|
||||
Self::old_child_bounty_account_id(old_child_bounty_id);
|
||||
let new_child_bounty_account =
|
||||
Pallet::<T>::child_bounty_account_id(parent_bounty_id, new_child_bounty_id);
|
||||
let old_balance = T::Currency::free_balance(&old_child_bounty_account);
|
||||
log::info!(
|
||||
"Transferring {:?} funds from old child bounty account {:?} to new child bounty account {:?}",
|
||||
old_balance, old_child_bounty_account, new_child_bounty_account
|
||||
);
|
||||
if let Err(err) = T::Currency::transfer(
|
||||
&old_child_bounty_account,
|
||||
&new_child_bounty_account,
|
||||
old_balance,
|
||||
AllowDeath,
|
||||
) {
|
||||
log::error!(
|
||||
target: LOG_TARGET,
|
||||
"Error transferring funds: {:?}",
|
||||
err
|
||||
);
|
||||
}
|
||||
transfer_weights += TransferWeight::get();
|
||||
|
||||
log::info!(
|
||||
target: LOG_TARGET,
|
||||
"Remapped parent bounty {} child bounty id {}->{}",
|
||||
parent_bounty_id,
|
||||
old_child_bounty_id,
|
||||
new_child_bounty_id,
|
||||
);
|
||||
|
||||
let bounty_description = ChildBountyDescriptions::<T>::take(old_child_bounty_id);
|
||||
writes += 1;
|
||||
let child_bounty = ChildBounties::<T>::take(parent_bounty_id, old_child_bounty_id);
|
||||
writes += 1;
|
||||
|
||||
// should always be some
|
||||
if let Some(taken) = child_bounty {
|
||||
ChildBounties::<T>::insert(parent_bounty_id, new_child_bounty_id, taken);
|
||||
writes += 1;
|
||||
} else {
|
||||
log::error!(
|
||||
"child bounty with old id {} not found, should be impossible",
|
||||
old_child_bounty_id
|
||||
);
|
||||
}
|
||||
if let Some(bounty_description) = bounty_description {
|
||||
super::super::ChildBountyDescriptionsV1::<T>::insert(
|
||||
parent_bounty_id,
|
||||
new_child_bounty_id,
|
||||
bounty_description,
|
||||
);
|
||||
writes += 1;
|
||||
} else {
|
||||
log::error!(
|
||||
"child bounty description with old id {} not found, should be impossible",
|
||||
old_child_bounty_id
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
log::info!(
|
||||
target: LOG_TARGET,
|
||||
"Migration done, reads: {}, writes: {}, transfer weights: {}",
|
||||
reads, writes, transfer_weights
|
||||
);
|
||||
|
||||
T::DbWeight::get().reads_writes(reads, writes) + transfer_weights
|
||||
}
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
fn pre_upgrade() -> Result<Vec<u8>, pezsp_runtime::TryRuntimeError> {
|
||||
let old_child_bounty_count = ChildBounties::<T>::iter_keys().count() as u32;
|
||||
let old_child_bounty_descriptions =
|
||||
v1::ChildBountyDescriptions::<T>::iter_keys().count() as u32;
|
||||
let old_child_bounty_ids = ChildBounties::<T>::iter_keys().collect::<Vec<_>>();
|
||||
Ok((old_child_bounty_count, old_child_bounty_descriptions, old_child_bounty_ids)
|
||||
.encode())
|
||||
}
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
fn post_upgrade(state: Vec<u8>) -> Result<(), pezsp_runtime::TryRuntimeError> {
|
||||
type StateType = (u32, u32, Vec<(u32, u32)>);
|
||||
let (old_child_bounty_count, old_child_bounty_descriptions, old_child_bounty_ids) =
|
||||
StateType::decode(&mut &state[..]).expect("Can't decode previous state");
|
||||
let new_child_bounty_count = ChildBounties::<T>::iter_keys().count() as u32;
|
||||
let new_child_bounty_descriptions =
|
||||
super::super::ChildBountyDescriptionsV1::<T>::iter_keys().count() as u32;
|
||||
|
||||
ensure!(
|
||||
old_child_bounty_count == new_child_bounty_count,
|
||||
"child bounty count doesn't match"
|
||||
);
|
||||
ensure!(
|
||||
old_child_bounty_descriptions == new_child_bounty_descriptions,
|
||||
"child bounty descriptions count doesn't match"
|
||||
);
|
||||
|
||||
let old_child_bounty_descriptions_storage =
|
||||
v1::ChildBountyDescriptions::<T>::iter_keys().count();
|
||||
log::info!("old child bounty descriptions: {}", old_child_bounty_descriptions_storage);
|
||||
ensure!(
|
||||
old_child_bounty_descriptions_storage == 0,
|
||||
"Old bounty descriptions should have been drained."
|
||||
);
|
||||
|
||||
for (_, old_child_bounty_id) in old_child_bounty_ids {
|
||||
let old_account_id = Self::old_child_bounty_account_id(old_child_bounty_id);
|
||||
let balance = T::Currency::total_balance(&old_account_id);
|
||||
if !balance.is_zero() {
|
||||
log::error!(
|
||||
"Old child bounty id {} still has balance {:?}",
|
||||
old_child_bounty_id,
|
||||
balance
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config, TransferWeight: Get<Weight>> MigrateToV1Impl<T, TransferWeight> {
|
||||
fn old_child_bounty_account_id(id: BountyIndex) -> T::AccountId {
|
||||
// This function is taken from the parent (bounties) pallet, but the
|
||||
// prefix is changed to have different AccountId when the index of
|
||||
// parent and child is same.
|
||||
T::PalletId::get().into_sub_account_truncating(("cb", id))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Migrate the pallet storage from `0` to `1`.
|
||||
pub type MigrateV0ToV1<T, TransferWeight> = pezframe_support::migrations::VersionedMigration<
|
||||
0,
|
||||
1,
|
||||
v1::MigrateToV1Impl<T, TransferWeight>,
|
||||
Pallet<T>,
|
||||
<T as pezframe_system::Config>::DbWeight,
|
||||
>;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,370 @@
|
||||
// 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_child_bounties`
|
||||
//!
|
||||
//! 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_child_bounties
|
||||
// --header=/__w/pezkuwi-sdk/pezkuwi-sdk/bizinikiwi/HEADER-APACHE2
|
||||
// --output=/__w/pezkuwi-sdk/pezkuwi-sdk/bizinikiwi/pezframe/child-bounties/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_child_bounties`.
|
||||
pub trait WeightInfo {
|
||||
fn add_child_bounty(d: u32, ) -> Weight;
|
||||
fn propose_curator() -> Weight;
|
||||
fn accept_curator() -> Weight;
|
||||
fn unassign_curator() -> Weight;
|
||||
fn award_child_bounty() -> Weight;
|
||||
fn claim_child_bounty() -> Weight;
|
||||
fn close_child_bounty_added() -> Weight;
|
||||
fn close_child_bounty_active() -> Weight;
|
||||
}
|
||||
|
||||
/// Weights for `pezpallet_child_bounties` using the Bizinikiwi node and recommended hardware.
|
||||
pub struct BizinikiwiWeight<T>(PhantomData<T>);
|
||||
impl<T: pezframe_system::Config> WeightInfo for BizinikiwiWeight<T> {
|
||||
/// Storage: `ChildBounties::ParentChildBounties` (r:1 w:1)
|
||||
/// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Bounties::Bounties` (r:1 w:0)
|
||||
/// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`)
|
||||
/// Storage: `System::Account` (r:2 w:2)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
/// Storage: `ChildBounties::ParentTotalChildBounties` (r:1 w:1)
|
||||
/// Proof: `ChildBounties::ParentTotalChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`)
|
||||
/// Storage: `ChildBounties::ChildBountyDescriptionsV1` (r:0 w:1)
|
||||
/// Proof: `ChildBounties::ChildBountyDescriptionsV1` (`max_values`: None, `max_size`: Some(326), added: 2801, mode: `MaxEncodedLen`)
|
||||
/// Storage: `ChildBounties::ChildBounties` (r:0 w:1)
|
||||
/// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`)
|
||||
/// The range of component `d` is `[0, 300]`.
|
||||
fn add_child_bounty(_d: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `335`
|
||||
// Estimated: `6196`
|
||||
// Minimum execution time: 63_099_000 picoseconds.
|
||||
Weight::from_parts(65_468_602, 6196)
|
||||
.saturating_add(T::DbWeight::get().reads(5_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(6_u64))
|
||||
}
|
||||
/// Storage: `Bounties::Bounties` (r:1 w:0)
|
||||
/// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`)
|
||||
/// Storage: `ChildBounties::ChildBounties` (r:1 w:1)
|
||||
/// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`)
|
||||
/// Storage: `ChildBounties::ChildrenCuratorFees` (r:1 w:1)
|
||||
/// Proof: `ChildBounties::ChildrenCuratorFees` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`)
|
||||
fn propose_curator() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `420`
|
||||
// Estimated: `3642`
|
||||
// Minimum execution time: 16_789_000 picoseconds.
|
||||
Weight::from_parts(17_457_000, 3642)
|
||||
.saturating_add(T::DbWeight::get().reads(3_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(2_u64))
|
||||
}
|
||||
/// Storage: `Bounties::Bounties` (r:1 w:0)
|
||||
/// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`)
|
||||
/// Storage: `ChildBounties::ChildBounties` (r:1 w:1)
|
||||
/// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`)
|
||||
/// Storage: `System::Account` (r:1 w:1)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
fn accept_curator() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `589`
|
||||
// Estimated: `3642`
|
||||
// Minimum execution time: 31_248_000 picoseconds.
|
||||
Weight::from_parts(32_220_000, 3642)
|
||||
.saturating_add(T::DbWeight::get().reads(3_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(2_u64))
|
||||
}
|
||||
/// Storage: `ChildBounties::ChildBounties` (r:1 w:1)
|
||||
/// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Bounties::Bounties` (r:1 w:0)
|
||||
/// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`)
|
||||
/// Storage: `System::Account` (r:1 w:1)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
fn unassign_curator() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `589`
|
||||
// Estimated: `3642`
|
||||
// Minimum execution time: 41_761_000 picoseconds.
|
||||
Weight::from_parts(42_828_000, 3642)
|
||||
.saturating_add(T::DbWeight::get().reads(3_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(2_u64))
|
||||
}
|
||||
/// Storage: `Bounties::Bounties` (r:1 w:0)
|
||||
/// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`)
|
||||
/// Storage: `ChildBounties::ChildBounties` (r:1 w:1)
|
||||
/// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`)
|
||||
fn award_child_bounty() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `486`
|
||||
// Estimated: `3642`
|
||||
// Minimum execution time: 18_804_000 picoseconds.
|
||||
Weight::from_parts(19_178_000, 3642)
|
||||
.saturating_add(T::DbWeight::get().reads(2_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(1_u64))
|
||||
}
|
||||
/// Storage: `ChildBounties::ChildBounties` (r:1 w:1)
|
||||
/// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`)
|
||||
/// Storage: `System::Account` (r:3 w:3)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
/// Storage: `ChildBounties::ParentChildBounties` (r:1 w:1)
|
||||
/// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`)
|
||||
/// Storage: `ChildBounties::ChildBountyDescriptionsV1` (r:0 w:1)
|
||||
/// Proof: `ChildBounties::ChildBountyDescriptionsV1` (`max_values`: None, `max_size`: Some(326), added: 2801, mode: `MaxEncodedLen`)
|
||||
fn claim_child_bounty() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `499`
|
||||
// Estimated: `8799`
|
||||
// Minimum execution time: 104_497_000 picoseconds.
|
||||
Weight::from_parts(106_660_000, 8799)
|
||||
.saturating_add(T::DbWeight::get().reads(5_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(6_u64))
|
||||
}
|
||||
/// Storage: `Bounties::Bounties` (r:1 w:0)
|
||||
/// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`)
|
||||
/// Storage: `ChildBounties::ChildBounties` (r:1 w:1)
|
||||
/// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`)
|
||||
/// Storage: `ChildBounties::ChildrenCuratorFees` (r:1 w:1)
|
||||
/// Proof: `ChildBounties::ChildrenCuratorFees` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`)
|
||||
/// Storage: `ChildBounties::ParentChildBounties` (r:1 w:1)
|
||||
/// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`)
|
||||
/// Storage: `System::Account` (r:2 w:2)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
/// Storage: `ChildBounties::ChildBountyDescriptionsV1` (r:0 w:1)
|
||||
/// Proof: `ChildBounties::ChildBountyDescriptionsV1` (`max_values`: None, `max_size`: Some(326), added: 2801, mode: `MaxEncodedLen`)
|
||||
fn close_child_bounty_added() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `629`
|
||||
// Estimated: `6196`
|
||||
// Minimum execution time: 69_986_000 picoseconds.
|
||||
Weight::from_parts(72_530_000, 6196)
|
||||
.saturating_add(T::DbWeight::get().reads(6_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(6_u64))
|
||||
}
|
||||
/// Storage: `Bounties::Bounties` (r:1 w:0)
|
||||
/// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`)
|
||||
/// Storage: `ChildBounties::ChildBounties` (r:1 w:1)
|
||||
/// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`)
|
||||
/// Storage: `System::Account` (r:3 w:3)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
/// Storage: `ChildBounties::ChildrenCuratorFees` (r:1 w:1)
|
||||
/// Proof: `ChildBounties::ChildrenCuratorFees` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`)
|
||||
/// Storage: `ChildBounties::ParentChildBounties` (r:1 w:1)
|
||||
/// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`)
|
||||
/// Storage: `ChildBounties::ChildBountyDescriptionsV1` (r:0 w:1)
|
||||
/// Proof: `ChildBounties::ChildBountyDescriptionsV1` (`max_values`: None, `max_size`: Some(326), added: 2801, mode: `MaxEncodedLen`)
|
||||
fn close_child_bounty_active() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `812`
|
||||
// Estimated: `8799`
|
||||
// Minimum execution time: 85_462_000 picoseconds.
|
||||
Weight::from_parts(86_891_000, 8799)
|
||||
.saturating_add(T::DbWeight::get().reads(7_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(7_u64))
|
||||
}
|
||||
}
|
||||
|
||||
// For backwards compatibility and tests.
|
||||
impl WeightInfo for () {
|
||||
/// Storage: `ChildBounties::ParentChildBounties` (r:1 w:1)
|
||||
/// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Bounties::Bounties` (r:1 w:0)
|
||||
/// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`)
|
||||
/// Storage: `System::Account` (r:2 w:2)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
/// Storage: `ChildBounties::ParentTotalChildBounties` (r:1 w:1)
|
||||
/// Proof: `ChildBounties::ParentTotalChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`)
|
||||
/// Storage: `ChildBounties::ChildBountyDescriptionsV1` (r:0 w:1)
|
||||
/// Proof: `ChildBounties::ChildBountyDescriptionsV1` (`max_values`: None, `max_size`: Some(326), added: 2801, mode: `MaxEncodedLen`)
|
||||
/// Storage: `ChildBounties::ChildBounties` (r:0 w:1)
|
||||
/// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`)
|
||||
/// The range of component `d` is `[0, 300]`.
|
||||
fn add_child_bounty(_d: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `335`
|
||||
// Estimated: `6196`
|
||||
// Minimum execution time: 63_099_000 picoseconds.
|
||||
Weight::from_parts(65_468_602, 6196)
|
||||
.saturating_add(RocksDbWeight::get().reads(5_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(6_u64))
|
||||
}
|
||||
/// Storage: `Bounties::Bounties` (r:1 w:0)
|
||||
/// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`)
|
||||
/// Storage: `ChildBounties::ChildBounties` (r:1 w:1)
|
||||
/// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`)
|
||||
/// Storage: `ChildBounties::ChildrenCuratorFees` (r:1 w:1)
|
||||
/// Proof: `ChildBounties::ChildrenCuratorFees` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`)
|
||||
fn propose_curator() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `420`
|
||||
// Estimated: `3642`
|
||||
// Minimum execution time: 16_789_000 picoseconds.
|
||||
Weight::from_parts(17_457_000, 3642)
|
||||
.saturating_add(RocksDbWeight::get().reads(3_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(2_u64))
|
||||
}
|
||||
/// Storage: `Bounties::Bounties` (r:1 w:0)
|
||||
/// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`)
|
||||
/// Storage: `ChildBounties::ChildBounties` (r:1 w:1)
|
||||
/// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`)
|
||||
/// Storage: `System::Account` (r:1 w:1)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
fn accept_curator() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `589`
|
||||
// Estimated: `3642`
|
||||
// Minimum execution time: 31_248_000 picoseconds.
|
||||
Weight::from_parts(32_220_000, 3642)
|
||||
.saturating_add(RocksDbWeight::get().reads(3_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(2_u64))
|
||||
}
|
||||
/// Storage: `ChildBounties::ChildBounties` (r:1 w:1)
|
||||
/// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Bounties::Bounties` (r:1 w:0)
|
||||
/// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`)
|
||||
/// Storage: `System::Account` (r:1 w:1)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
fn unassign_curator() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `589`
|
||||
// Estimated: `3642`
|
||||
// Minimum execution time: 41_761_000 picoseconds.
|
||||
Weight::from_parts(42_828_000, 3642)
|
||||
.saturating_add(RocksDbWeight::get().reads(3_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(2_u64))
|
||||
}
|
||||
/// Storage: `Bounties::Bounties` (r:1 w:0)
|
||||
/// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`)
|
||||
/// Storage: `ChildBounties::ChildBounties` (r:1 w:1)
|
||||
/// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`)
|
||||
fn award_child_bounty() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `486`
|
||||
// Estimated: `3642`
|
||||
// Minimum execution time: 18_804_000 picoseconds.
|
||||
Weight::from_parts(19_178_000, 3642)
|
||||
.saturating_add(RocksDbWeight::get().reads(2_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(1_u64))
|
||||
}
|
||||
/// Storage: `ChildBounties::ChildBounties` (r:1 w:1)
|
||||
/// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`)
|
||||
/// Storage: `System::Account` (r:3 w:3)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
/// Storage: `ChildBounties::ParentChildBounties` (r:1 w:1)
|
||||
/// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`)
|
||||
/// Storage: `ChildBounties::ChildBountyDescriptionsV1` (r:0 w:1)
|
||||
/// Proof: `ChildBounties::ChildBountyDescriptionsV1` (`max_values`: None, `max_size`: Some(326), added: 2801, mode: `MaxEncodedLen`)
|
||||
fn claim_child_bounty() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `499`
|
||||
// Estimated: `8799`
|
||||
// Minimum execution time: 104_497_000 picoseconds.
|
||||
Weight::from_parts(106_660_000, 8799)
|
||||
.saturating_add(RocksDbWeight::get().reads(5_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(6_u64))
|
||||
}
|
||||
/// Storage: `Bounties::Bounties` (r:1 w:0)
|
||||
/// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`)
|
||||
/// Storage: `ChildBounties::ChildBounties` (r:1 w:1)
|
||||
/// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`)
|
||||
/// Storage: `ChildBounties::ChildrenCuratorFees` (r:1 w:1)
|
||||
/// Proof: `ChildBounties::ChildrenCuratorFees` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`)
|
||||
/// Storage: `ChildBounties::ParentChildBounties` (r:1 w:1)
|
||||
/// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`)
|
||||
/// Storage: `System::Account` (r:2 w:2)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
/// Storage: `ChildBounties::ChildBountyDescriptionsV1` (r:0 w:1)
|
||||
/// Proof: `ChildBounties::ChildBountyDescriptionsV1` (`max_values`: None, `max_size`: Some(326), added: 2801, mode: `MaxEncodedLen`)
|
||||
fn close_child_bounty_added() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `629`
|
||||
// Estimated: `6196`
|
||||
// Minimum execution time: 69_986_000 picoseconds.
|
||||
Weight::from_parts(72_530_000, 6196)
|
||||
.saturating_add(RocksDbWeight::get().reads(6_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(6_u64))
|
||||
}
|
||||
/// Storage: `Bounties::Bounties` (r:1 w:0)
|
||||
/// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`)
|
||||
/// Storage: `ChildBounties::ChildBounties` (r:1 w:1)
|
||||
/// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`)
|
||||
/// Storage: `System::Account` (r:3 w:3)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
/// Storage: `ChildBounties::ChildrenCuratorFees` (r:1 w:1)
|
||||
/// Proof: `ChildBounties::ChildrenCuratorFees` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`)
|
||||
/// Storage: `ChildBounties::ParentChildBounties` (r:1 w:1)
|
||||
/// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`)
|
||||
/// Storage: `ChildBounties::ChildBountyDescriptionsV1` (r:0 w:1)
|
||||
/// Proof: `ChildBounties::ChildBountyDescriptionsV1` (`max_values`: None, `max_size`: Some(326), added: 2801, mode: `MaxEncodedLen`)
|
||||
fn close_child_bounty_active() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `812`
|
||||
// Estimated: `8799`
|
||||
// Minimum execution time: 85_462_000 picoseconds.
|
||||
Weight::from_parts(86_891_000, 8799)
|
||||
.saturating_add(RocksDbWeight::get().reads(7_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(7_u64))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user