difftreelog
add force methods for collection in `Unique` , add events Stake, Unstake, SetAdmin
in: master
8 files changed
Cargo.lockdiffbeforeafterboth--- a/Cargo.lock
+++ b/Cargo.lock
@@ -6473,7 +6473,7 @@
[[package]]
name = "pallet-unique"
-version = "0.1.3"
+version = "0.1.4"
dependencies = [
"ethereum",
"evm-coder",
pallets/app-promotion/src/benchmarking.rsdiffbeforeafterboth--- a/pallets/app-promotion/src/benchmarking.rs
+++ b/pallets/app-promotion/src/benchmarking.rs
@@ -54,7 +54,7 @@
payout_stakers{
let pallet_admin = account::<T::AccountId>("admin", 0, SEED);
- let share = Perbill::from_rational(1u32, 10);
+ let share = Perbill::from_rational(1u32, 100);
PromototionPallet::<T>::set_admin_address(RawOrigin::Root.into(), T::CrossAccountId::from_sub(pallet_admin.clone()))?;
let _ = <T as Config>::Currency::make_free_balance_be(&pallet_admin, Perbill::from_rational(1u32, 2) * BalanceOf::<T>::max_value());
let staker: T::AccountId = account("caller", 0, SEED);
pallets/app-promotion/src/lib.rsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! # App promotion18//!19//! The app promotion pallet is designed to ... .20//!21//! ## Interface22//!23//! ### Dispatchable Functions24//!25//! * `start_inflation` - This method sets the inflation start date. Can be only called once.26//! Inflation start block can be backdated and will catch up. The method will create Treasury27//! account if it does not exist and perform the first inflation deposit.2829// #![recursion_limit = "1024"]30#![cfg_attr(not(feature = "std"), no_std)]3132#[cfg(feature = "runtime-benchmarks")]33mod benchmarking;34#[cfg(test)]35mod tests;36pub mod types;37pub mod weights;3839use sp_std::{40 vec::{Vec},41 vec,42 iter::Sum,43 borrow::ToOwned,44 cell::RefCell,45};46use sp_core::H160;47use codec::EncodeLike;48use pallet_balances::BalanceLock;49pub use types::*;5051// use up_common::constants::{DAYS, UNIQUE};52use up_data_structs::CollectionId;5354use frame_support::{55 dispatch::{DispatchResult},56 traits::{57 Currency, Get, LockableCurrency, WithdrawReasons, tokens::Balance, ExistenceRequirement,58 },59 ensure,60};6162use weights::WeightInfo;6364pub use pallet::*;65use pallet_evm::account::CrossAccountId;66use sp_runtime::{67 Perbill,68 traits::{BlockNumberProvider, CheckedAdd, CheckedSub, AccountIdConversion, Zero},69 ArithmeticError,70};7172pub const LOCK_IDENTIFIER: [u8; 8] = *b"appstake";73const PENDING_LIMIT_PER_BLOCK: u32 = 3;7475type BalanceOf<T> =76 <<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;7778// const SECONDS_TO_BLOCK: u32 = 6;79// const DAY: u32 = 60 * 60 * 24 / SECONDS_TO_BLOCK;80// const WEEK: u32 = 7 * DAY;81// const TWO_WEEK: u32 = 2 * WEEK;82// const YEAR: u32 = DAY * 365;8384#[frame_support::pallet]85pub mod pallet {86 use super::*;87 use frame_support::{88 Blake2_128Concat, Twox64Concat, pallet_prelude::*, storage::Key, PalletId,89 traits::ReservableCurrency,90 };91 use frame_system::pallet_prelude::*;9293 #[pallet::config]94 pub trait Config: frame_system::Config + pallet_evm::account::Config {95 type Currency: ExtendedLockableCurrency<Self::AccountId>96 + ReservableCurrency<Self::AccountId>;9798 type CollectionHandler: CollectionHandler<99 AccountId = Self::AccountId,100 CollectionId = CollectionId,101 >;102103 type ContractHandler: ContractHandler<AccountId = Self::CrossAccountId, ContractId = H160>;104105 type TreasuryAccountId: Get<Self::AccountId>;106107 /// The app's pallet id, used for deriving its sovereign account ID.108 #[pallet::constant]109 type PalletId: Get<PalletId>;110111 /// In relay blocks.112 #[pallet::constant]113 type RecalculationInterval: Get<Self::BlockNumber>;114 /// In relay blocks.115 #[pallet::constant]116 type PendingInterval: Get<Self::BlockNumber>;117118 /// In chain blocks.119 #[pallet::constant]120 type Day: Get<Self::BlockNumber>; // useless121122 #[pallet::constant]123 type Nominal: Get<BalanceOf<Self>>;124125 #[pallet::constant]126 type IntervalIncome: Get<Perbill>;127128 /// Weight information for extrinsics in this pallet.129 type WeightInfo: WeightInfo;130131 // The relay block number provider132 type RelayBlockNumberProvider: BlockNumberProvider<BlockNumber = Self::BlockNumber>;133134 /// Events compatible with [`frame_system::Config::Event`].135 type Event: IsType<<Self as frame_system::Config>::Event> + From<Event<Self>>;136 }137138 #[pallet::pallet]139 #[pallet::generate_store(pub(super) trait Store)]140 pub struct Pallet<T>(_);141142 #[pallet::event]143 #[pallet::generate_deposit(fn deposit_event)]144 pub enum Event<T: Config> {145 StakingRecalculation(146 /// An recalculated staker147 T::AccountId,148 /// Base on which interest is calculated149 BalanceOf<T>,150 /// Amount of accrued interest151 BalanceOf<T>,152 ),153 }154155 #[pallet::error]156 pub enum Error<T> {157 /// Error due to action requiring admin to be set158 AdminNotSet,159 /// No permission to perform an action160 NoPermission,161 /// Insufficient funds to perform an action162 NotSufficientFounds,163 PendingForBlockOverflow,164 /// An error related to the fact that an invalid argument was passed to perform an action165 InvalidArgument,166 }167168 #[pallet::storage]169 pub type TotalStaked<T: Config> = StorageValue<Value = BalanceOf<T>, QueryKind = ValueQuery>;170171 #[pallet::storage]172 pub type Admin<T: Config> = StorageValue<Value = T::AccountId, QueryKind = OptionQuery>;173174 /// Amount of tokens staked by account in the blocknumber.175 #[pallet::storage]176 pub type Staked<T: Config> = StorageNMap<177 Key = (178 Key<Blake2_128Concat, T::AccountId>,179 Key<Twox64Concat, T::BlockNumber>,180 ),181 Value = (BalanceOf<T>, T::BlockNumber),182 QueryKind = ValueQuery,183 >;184 /// Amount of stakes for an Account185 #[pallet::storage]186 pub type StakesPerAccount<T: Config> =187 StorageMap<_, Blake2_128Concat, T::AccountId, u8, ValueQuery>;188189 /// Amount of tokens pending unstake per user per block.190 // #[pallet::storage]191 // pub type PendingUnstake<T: Config> = StorageNMap<192 // Key = (193 // Key<Blake2_128Concat, T::AccountId>,194 // Key<Twox64Concat, T::BlockNumber>,195 // ),196 // Value = BalanceOf<T>,197 // QueryKind = ValueQuery,198 // >;199 #[pallet::storage]200 pub type PendingUnstake<T: Config> = StorageMap<201 _,202 Twox64Concat,203 T::BlockNumber,204 BoundedVec<(T::AccountId, BalanceOf<T>), ConstU32<PENDING_LIMIT_PER_BLOCK>>,205 ValueQuery,206 >;207208 /// A block when app-promotion has started .I think this is redundant, because we only need `NextInterestBlock`.209 #[pallet::storage]210 pub type StartBlock<T: Config> = StorageValue<Value = T::BlockNumber, QueryKind = ValueQuery>;211212 // /// Next target block when interest is recalculated213 // #[pallet::storage]214 // #[pallet::getter(fn get_interest_block)]215 // pub type NextInterestBlock<T: Config> =216 // StorageValue<Value = T::BlockNumber, QueryKind = ValueQuery>;217218 /// Stores hash a record for which the last revenue recalculation was performed.219 /// If `None`, then recalculation has not yet been performed or calculations have been completed for all stakers.220 #[pallet::storage]221 #[pallet::getter(fn get_next_calculated_record)]222 pub type NextCalculatedRecord<T: Config> =223 StorageValue<Value = (T::AccountId, T::BlockNumber), QueryKind = OptionQuery>;224225 #[pallet::hooks]226 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {227 fn on_initialize(current_block_number: T::BlockNumber) -> Weight228 where229 <T as frame_system::Config>::BlockNumber: From<u32>,230 {231 let mut consumed_weight = 0;232 let mut add_weight = |reads, writes, weight| {233 consumed_weight += T::DbWeight::get().reads_writes(reads, writes);234 consumed_weight += weight;235 };236237 let block_pending = PendingUnstake::<T>::take(current_block_number);238239 add_weight(0, 1, 0);240241 if !block_pending.is_empty() {242 block_pending.into_iter().for_each(|(staker, amount)| {243 <T::Currency as ReservableCurrency<T::AccountId>>::unreserve(&staker, amount);244 });245 }246247 consumed_weight248 }249 }250251 #[pallet::call]252 impl<T: Config> Pallet<T>253 where254 T::BlockNumber: From<u32> + Into<u32>,255 <<T as Config>::Currency as Currency<T::AccountId>>::Balance: Sum + From<u128>,256 {257 #[pallet::weight(T::WeightInfo::set_admin_address())]258 pub fn set_admin_address(origin: OriginFor<T>, admin: T::CrossAccountId) -> DispatchResult {259 ensure_root(origin)?;260 <Admin<T>>::set(Some(admin.as_sub().to_owned()));261262 Ok(())263 }264265 // #[pallet::weight(T::WeightInfo::start_app_promotion())]266 // pub fn start_app_promotion(267 // origin: OriginFor<T>,268 // promotion_start_relay_block: Option<T::BlockNumber>,269 // ) -> DispatchResult270 // where271 // <T as frame_system::Config>::BlockNumber: From<u32>,272 // {273 // ensure_root(origin)?;274275 // // Start app-promotion mechanics if it has not been yet initialized276 // if <StartBlock<T>>::get() == 0u32.into() {277 // let start_block = promotion_start_relay_block278 // .unwrap_or(T::RelayBlockNumberProvider::current_block_number());279280 // // Set promotion global start block281 // <StartBlock<T>>::set(start_block);282283 // <NextInterestBlock<T>>::set(start_block + T::RecalculationInterval::get());284 // }285286 // Ok(())287 // }288289 // #[pallet::weight(T::WeightInfo::stop_app_promotion())]290 // pub fn stop_app_promotion(origin: OriginFor<T>) -> DispatchResult291 // where292 // <T as frame_system::Config>::BlockNumber: From<u32>,293 // {294 // ensure_root(origin)?;295296 // if <StartBlock<T>>::get() != 0u32.into() {297 // <StartBlock<T>>::set(T::BlockNumber::default());298 // <NextInterestBlock<T>>::set(T::BlockNumber::default());299 // }300301 // Ok(())302 // }303304 #[pallet::weight(T::WeightInfo::stake())]305 pub fn stake(staker: OriginFor<T>, amount: BalanceOf<T>) -> DispatchResult {306 let staker_id = ensure_signed(staker)?;307308 ensure!(309 StakesPerAccount::<T>::get(&staker_id) < 10,310 Error::<T>::NoPermission311 );312313 ensure!(314 amount >= Into::<BalanceOf<T>>::into(100u128) * T::Nominal::get(),315 ArithmeticError::Underflow316 );317318 let balance =319 <<T as Config>::Currency as Currency<T::AccountId>>::free_balance(&staker_id);320321 ensure!(balance >= amount, ArithmeticError::Underflow);322323 <<T as Config>::Currency as Currency<T::AccountId>>::ensure_can_withdraw(324 &staker_id,325 amount,326 WithdrawReasons::all(),327 balance - amount,328 )?;329330 Self::add_lock_balance(&staker_id, amount)?;331332 let block_number = T::RelayBlockNumberProvider::current_block_number();333 let recalc_block = (block_number / T::RecalculationInterval::get() + 2u32.into())334 * T::RecalculationInterval::get();335336 <Staked<T>>::insert((&staker_id, block_number), {337 let mut balance_and_recalc_block = <Staked<T>>::get((&staker_id, block_number));338 balance_and_recalc_block.0 = balance_and_recalc_block339 .0340 .checked_add(&amount)341 .ok_or(ArithmeticError::Overflow)?;342 balance_and_recalc_block.1 = recalc_block;343 balance_and_recalc_block344 });345346 <TotalStaked<T>>::set(347 <TotalStaked<T>>::get()348 .checked_add(&amount)349 .ok_or(ArithmeticError::Overflow)?,350 );351352 StakesPerAccount::<T>::mutate(&staker_id, |stakes| *stakes += 1);353 Ok(())354 }355356 #[pallet::weight(T::WeightInfo::unstake())]357 pub fn unstake(staker: OriginFor<T>) -> DispatchResultWithPostInfo {358 let staker_id = ensure_signed(staker)?;359 let block = <frame_system::Pallet<T>>::block_number() + T::PendingInterval::get();360 let mut pendings = <PendingUnstake<T>>::get(block);361362 ensure!(!pendings.is_full(), Error::<T>::PendingForBlockOverflow);363364 let mut total_stakes = 0u64;365366 let total_staked: BalanceOf<T> = Staked::<T>::drain_prefix((&staker_id,))367 .map(|(_, (amount, _))| {368 total_stakes += 1;369 amount370 })371 .sum();372373 if total_staked.is_zero() {374 return Ok(None.into()); // TO-DO375 }376377 pendings378 .try_push((staker_id.clone(), total_staked))379 .map_err(|_| Error::<T>::PendingForBlockOverflow)?;380381 <PendingUnstake<T>>::insert(block, pendings);382383 Self::unlock_balance_unchecked(&staker_id, total_staked);384385 <T::Currency as ReservableCurrency<T::AccountId>>::reserve(&staker_id, total_staked)?;386387 TotalStaked::<T>::set(388 TotalStaked::<T>::get()389 .checked_sub(&total_staked)390 .ok_or(ArithmeticError::Underflow)?,391 );392393 StakesPerAccount::<T>::remove(&staker_id);394395 Ok(None.into())396 }397398 #[pallet::weight(T::WeightInfo::sponsor_collection())]399 pub fn sponsor_collection(400 admin: OriginFor<T>,401 collection_id: CollectionId,402 ) -> DispatchResult {403 let admin_id = ensure_signed(admin)?;404 ensure!(405 admin_id == Admin::<T>::get().ok_or(Error::<T>::AdminNotSet)?,406 Error::<T>::NoPermission407 );408409 T::CollectionHandler::set_sponsor(Self::account_id(), collection_id)410 }411 #[pallet::weight(T::WeightInfo::stop_sponsoring_collection())]412 pub fn stop_sponsoring_collection(413 admin: OriginFor<T>,414 collection_id: CollectionId,415 ) -> DispatchResult {416 let admin_id = ensure_signed(admin)?;417418 ensure!(419 admin_id == Admin::<T>::get().ok_or(Error::<T>::AdminNotSet)?,420 Error::<T>::NoPermission421 );422423 ensure!(424 T::CollectionHandler::get_sponsor(collection_id)?425 .ok_or(<Error<T>>::InvalidArgument)?426 == Self::account_id(),427 <Error<T>>::NoPermission428 );429 T::CollectionHandler::remove_collection_sponsor(collection_id)430 }431432 #[pallet::weight(T::WeightInfo::sponsor_contract())]433 pub fn sponsor_conract(admin: OriginFor<T>, contract_id: H160) -> DispatchResult {434 let admin_id = ensure_signed(admin)?;435436 ensure!(437 admin_id == Admin::<T>::get().ok_or(Error::<T>::AdminNotSet)?,438 Error::<T>::NoPermission439 );440441 T::ContractHandler::set_sponsor(442 T::CrossAccountId::from_sub(Self::account_id()),443 contract_id,444 )445 }446447 #[pallet::weight(T::WeightInfo::stop_sponsoring_contract())]448 pub fn stop_sponsoring_contract(admin: OriginFor<T>, contract_id: H160) -> DispatchResult {449 let admin_id = ensure_signed(admin)?;450451 ensure!(452 admin_id == Admin::<T>::get().ok_or(Error::<T>::AdminNotSet)?,453 Error::<T>::NoPermission454 );455456 ensure!(457 T::ContractHandler::get_sponsor(contract_id)?.ok_or(<Error<T>>::InvalidArgument)?458 == T::CrossAccountId::from_sub(Self::account_id()),459 <Error<T>>::NoPermission460 );461 T::ContractHandler::remove_contract_sponsor(contract_id)462 }463464 #[pallet::weight(0)]465 pub fn payout_stakers(admin: OriginFor<T>, stakers_number: Option<u8>) -> DispatchResult {466 let admin_id = ensure_signed(admin)?;467468 ensure!(469 admin_id == Admin::<T>::get().ok_or(Error::<T>::AdminNotSet)?,470 Error::<T>::NoPermission471 );472473 let current_recalc_block =474 Self::get_current_recalc_block(T::RelayBlockNumberProvider::current_block_number());475 let next_recalc_block = current_recalc_block + T::RecalculationInterval::get();476477 let mut storage_iterator = Self::get_next_calculated_key()478 .map_or(Staked::<T>::iter(), |key| Staked::<T>::iter_from(key));479480 NextCalculatedRecord::<T>::set(None);481482 // {483 // let mut stakers_number = stakers_number.unwrap_or(20);484 // let mut last_id = admin_id;485 // let mut income_acc = BalanceOf::<T>::default();486 // let mut amount_acc = BalanceOf::<T>::default();487488 // while let Some((489 // (current_id, staked_block),490 // (amount, next_recalc_block_for_stake),491 // )) = storage_iterator.next()492 // {493 // if last_id != current_id {494 // if income_acc != BalanceOf::<T>::default() {495 // <T::Currency as Currency<T::AccountId>>::transfer(496 // &T::TreasuryAccountId::get(),497 // &last_id,498 // income_acc,499 // ExistenceRequirement::KeepAlive,500 // )501 // .and_then(|_| Self::add_lock_balance(&last_id, income_acc))?;502503 // Self::deposit_event(Event::StakingRecalculation(504 // last_id, amount, income_acc,505 // ));506 // }507508 // if stakers_number == 0 {509 // NextCalculatedRecord::<T>::set(Some((current_id, staked_block)));510 // break;511 // }512 // stakers_number -= 1;513 // income_acc = BalanceOf::<T>::default();514 // last_id = current_id;515 // };516 // if current_recalc_block >= next_recalc_block_for_stake {517 // Self::recalculate_and_insert_stake(518 // &last_id,519 // staked_block,520 // next_recalc_block,521 // amount,522 // ((current_recalc_block - next_recalc_block_for_stake)523 // / T::RecalculationInterval::get())524 // .into() + 1,525 // &mut income_acc,526 // );527 // }528 // }529 // }530 531 {532 let mut stakers_number = stakers_number.unwrap_or(20);533 let last_id = RefCell::new(None);534 let income_acc = RefCell::new(BalanceOf::<T>::default());535 let amount_acc = RefCell::new(BalanceOf::<T>::default());536 537 let flush_stake = || -> DispatchResult {538 if let Some(last_id) = &*last_id.borrow() {539 if !income_acc.borrow().is_zero() {540 <T::Currency as Currency<T::AccountId>>::transfer(541 &T::TreasuryAccountId::get(),542 last_id,543 *income_acc.borrow(),544 ExistenceRequirement::KeepAlive,545 )546 .and_then(|_| Self::add_lock_balance(last_id, *income_acc.borrow()))?;547548 Self::deposit_event(Event::StakingRecalculation(549 last_id.clone(),550 *amount_acc.borrow(),551 *income_acc.borrow(),552 ));553 }554555 *income_acc.borrow_mut() = BalanceOf::<T>::default();556 *amount_acc.borrow_mut() = BalanceOf::<T>::default();557 }558 Ok(())559 };560561 while let Some((562 (current_id, staked_block),563 (amount, next_recalc_block_for_stake),564 )) = storage_iterator.next()565 {566 if stakers_number == 0 {567 NextCalculatedRecord::<T>::set(Some((current_id, staked_block)));568 break;569 }570 stakers_number -= 1;571 if last_id.borrow().as_ref() != Some(¤t_id) {572 flush_stake()?;573 };574 *last_id.borrow_mut() = Some(current_id.clone());575 if current_recalc_block >= next_recalc_block_for_stake {576 *amount_acc.borrow_mut() += amount; 577 Self::recalculate_and_insert_stake(578 ¤t_id,579 staked_block,580 next_recalc_block,581 amount,582 ((current_recalc_block - next_recalc_block_for_stake)583 / T::RecalculationInterval::get())584 .into() + 1,585 &mut *income_acc.borrow_mut(),586 );587 }588 }589 flush_stake()?;590 }591592593 Ok(())594 }595 }596}597598impl<T: Config> Pallet<T> {599 pub fn account_id() -> T::AccountId {600 T::PalletId::get().into_account_truncating()601 }602603 fn unlock_balance_unchecked(staker: &T::AccountId, amount: BalanceOf<T>) {604 let mut locked_balance = Self::get_locked_balance(staker).map(|l| l.amount).unwrap();605 locked_balance -= amount;606 Self::set_lock_unchecked(staker, locked_balance);607 }608609 fn add_lock_balance(staker: &T::AccountId, amount: BalanceOf<T>) -> DispatchResult {610 Self::get_locked_balance(staker)611 .map_or(<BalanceOf<T>>::default(), |l| l.amount)612 .checked_add(&amount)613 .map(|new_lock| Self::set_lock_unchecked(staker, new_lock))614 .ok_or(ArithmeticError::Overflow.into())615 }616617 fn set_lock_unchecked(staker: &T::AccountId, amount: BalanceOf<T>) {618 if amount.is_zero() {619 <T::Currency as LockableCurrency<T::AccountId>>::remove_lock(LOCK_IDENTIFIER, &staker);620 } else {621 <T::Currency as LockableCurrency<T::AccountId>>::set_lock(622 LOCK_IDENTIFIER,623 staker,624 amount,625 WithdrawReasons::all(),626 )627 }628 }629630 pub fn get_locked_balance(631 staker: impl EncodeLike<T::AccountId>,632 ) -> Option<BalanceLock<BalanceOf<T>>> {633 <T::Currency as ExtendedLockableCurrency<T::AccountId>>::locks(staker)634 .into_iter()635 .find(|l| l.id == LOCK_IDENTIFIER)636 }637638 pub fn total_staked_by_id(staker: impl EncodeLike<T::AccountId>) -> Option<BalanceOf<T>> {639 let staked = Staked::<T>::iter_prefix((staker,))640 .into_iter()641 .fold(<BalanceOf<T>>::default(), |acc, (_, (amount, _))| {642 acc + amount643 });644 if staked != <BalanceOf<T>>::default() {645 Some(staked)646 } else {647 None648 }649 }650651 pub fn total_staked_by_id_per_block(652 staker: impl EncodeLike<T::AccountId>,653 ) -> Option<Vec<(T::BlockNumber, BalanceOf<T>)>> {654 let mut staked = Staked::<T>::iter_prefix((staker,))655 .into_iter()656 .map(|(block, (amount, _))| (block, amount))657 .collect::<Vec<_>>();658 staked.sort_by_key(|(block, _)| *block);659 if !staked.is_empty() {660 Some(staked)661 } else {662 None663 }664 }665666 pub fn cross_id_total_staked(staker: Option<T::CrossAccountId>) -> Option<BalanceOf<T>> {667 staker.map_or(Some(<TotalStaked<T>>::get()), |s| {668 Self::total_staked_by_id(s.as_sub())669 })670 // Self::total_staked_by_id(staker.as_sub())671 }672673 pub fn cross_id_locked_balance(staker: T::CrossAccountId) -> BalanceOf<T> {674 Self::get_locked_balance(staker.as_sub())675 .map(|l| l.amount)676 .unwrap_or_default()677 }678679 pub fn cross_id_total_staked_per_block(680 staker: T::CrossAccountId,681 ) -> Vec<(T::BlockNumber, BalanceOf<T>)> {682 Self::total_staked_by_id_per_block(staker.as_sub()).unwrap_or_default()683 }684685 fn recalculate_and_insert_stake(686 staker: &T::AccountId,687 staked_block: T::BlockNumber,688 next_recalc_block: T::BlockNumber,689 base: BalanceOf<T>,690 iters: u32,691 income_acc: &mut BalanceOf<T>,692 ) {693 let income = Self::calculate_income(base, iters);694695 base.checked_add(&income).map(|res| {696 <Staked<T>>::insert((staker, staked_block), (res, next_recalc_block));697 *income_acc += income;698 });699 }700701 fn calculate_income<I>(base: I, iters: u32) -> I702 where703 I: EncodeLike<BalanceOf<T>> + Balance,704 {705 let mut income = base;706707 (0..iters).for_each(|_| income += T::IntervalIncome::get() * income);708709 income - base710 }711712 fn get_current_recalc_block(current_relay_block: T::BlockNumber) -> T::BlockNumber {713 (current_relay_block / T::RecalculationInterval::get()) * T::RecalculationInterval::get()714 }715716 // fn get_next_recalc_block(current_relay_block: T::BlockNumber) -> T::BlockNumber {717 // Self::get_current_recalc_block(current_relay_block) + T::RecalculationInterval::get()718 // }719720 fn get_next_calculated_key() -> Option<Vec<u8>> {721 Self::get_next_calculated_record().map(|key| Staked::<T>::hashed_key_for(key))722 }723}724725impl<T: Config> Pallet<T>726where727 <<T as Config>::Currency as Currency<T::AccountId>>::Balance: Sum,728{729 pub fn cross_id_pending_unstake(staker: Option<T::CrossAccountId>) -> BalanceOf<T> {730 staker.map_or(731 PendingUnstake::<T>::iter_values()732 .flat_map(|pendings| pendings.into_iter().map(|(_, amount)| amount))733 .sum(),734 |s| {735 PendingUnstake::<T>::iter_values()736 .flatten()737 .filter_map(|(id, amount)| {738 if id == *s.as_sub() {739 Some(amount)740 } else {741 None742 }743 })744 .sum()745 },746 )747 }748749 pub fn cross_id_pending_unstake_per_block(750 staker: T::CrossAccountId,751 ) -> Vec<(T::BlockNumber, BalanceOf<T>)> {752 let mut unsorted_res = vec![];753 PendingUnstake::<T>::iter().for_each(|(block, pendings)| {754 pendings.into_iter().for_each(|(id, amount)| {755 if id == *staker.as_sub() {756 unsorted_res.push((block, amount));757 };758 })759 });760761 unsorted_res.sort_by_key(|(block, _)| *block);762 unsorted_res763 }764}pallets/app-promotion/src/types.rsdiffbeforeafterboth--- a/pallets/app-promotion/src/types.rs
+++ b/pallets/app-promotion/src/types.rs
@@ -5,7 +5,7 @@
use pallet_balances::{BalanceLock, Config as BalancesConfig, Pallet as PalletBalances};
use pallet_common::CollectionHandle;
-use pallet_unique::{Event as UniqueEvent, Error as UniqueError};
+
use sp_runtime::DispatchError;
use up_data_structs::{CollectionId, SponsorshipState};
use sp_std::borrow::ToOwned;
@@ -53,36 +53,11 @@
sponsor_id: Self::AccountId,
collection_id: Self::CollectionId,
) -> DispatchResult {
- let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
- target_collection.check_is_internal()?;
- target_collection.set_sponsor(sponsor_id.clone())?;
-
- Self::deposit_event(UniqueEvent::<T>::CollectionSponsorSet(
- collection_id,
- sponsor_id.clone(),
- ));
-
- ensure!(
- target_collection.confirm_sponsorship(&sponsor_id)?,
- UniqueError::<T>::ConfirmUnsetSponsorFail
- );
-
- Self::deposit_event(UniqueEvent::<T>::SponsorshipConfirmed(
- collection_id,
- sponsor_id,
- ));
-
- target_collection.save()
+ Self::force_set_sponsor(sponsor_id, collection_id)
}
fn remove_collection_sponsor(collection_id: Self::CollectionId) -> DispatchResult {
- let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
- target_collection.check_is_internal()?;
- target_collection.sponsorship = SponsorshipState::Disabled;
-
- Self::deposit_event(UniqueEvent::<T>::CollectionSponsorRemoved(collection_id));
-
- target_collection.save()
+ Self::force_remove_collection_sponsor(collection_id)
}
fn get_sponsor(
pallets/unique/CHANGELOG.mddiffbeforeafterboth--- a/pallets/unique/CHANGELOG.md
+++ b/pallets/unique/CHANGELOG.md
@@ -3,22 +3,27 @@
All notable changes to this project will be documented in this file.
<!-- bureaucrate goes here -->
+
+## [v0.1.4] 2022-09-5
+
+### Added
+
## [v0.1.3] 2022-08-16
### Other changes
-- build: Upgrade polkadot to v0.9.27 2c498572636f2b34d53b1c51b7283a761a7dc90a
+- build: Upgrade polkadot to v0.9.27 2c498572636f2b34d53b1c51b7283a761a7dc90a
-- build: Upgrade polkadot to v0.9.26 85515e54c4ca1b82a2630034e55dcc804c643bf8
+- build: Upgrade polkadot to v0.9.26 85515e54c4ca1b82a2630034e55dcc804c643bf8
-- refactor: Remove `#[transactional]` from extrinsics 7fd36cea2f6e00c02c67ccc1de9649ae404efd31
+- refactor: Remove `#[transactional]` from extrinsics 7fd36cea2f6e00c02c67ccc1de9649ae404efd31
Every extrinsic now runs in transaction implicitly, and
`#[transactional]` on pallet dispatchable is now meaningless
Upstream-Change: https://github.com/paritytech/substrate/issues/10806
-- refactor: Switch to new prefix removal methods 26734e9567589d75cdd99e404eabf11d5a97d975
+- refactor: Switch to new prefix removal methods 26734e9567589d75cdd99e404eabf11d5a97d975
New methods allows to call `remove_prefix` with limit multiple times
in the same block
@@ -27,10 +32,12 @@
Upstream-Change: https://github.com/paritytech/substrate/pull/11490
-- build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b
+- build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b
## [v0.1.1] - 2022-07-25
+
### Added
-- Method for creating `ERC721Metadata` compatible NFT collection.
-- Method for creating `ERC721Metadata` compatible ReFungible collection.
-- Method for creating ReFungible collection.
+
+- Method for creating `ERC721Metadata` compatible NFT collection.
+- Method for creating `ERC721Metadata` compatible ReFungible collection.
+- Method for creating ReFungible collection.
pallets/unique/Cargo.tomldiffbeforeafterboth--- a/pallets/unique/Cargo.toml
+++ b/pallets/unique/Cargo.toml
@@ -9,7 +9,7 @@
license = 'GPLv3'
name = 'pallet-unique'
repository = 'https://github.com/UniqueNetwork/unique-chain'
-version = "0.1.3"
+version = "0.1.4"
[package.metadata.docs.rs]
targets = ['x86_64-unknown-linux-gnu']
pallets/unique/src/lib.rsdiffbeforeafterboth--- a/pallets/unique/src/lib.rs
+++ b/pallets/unique/src/lib.rs
@@ -1103,3 +1103,35 @@
}
}
}
+
+impl<T: Config> Pallet<T> {
+ pub fn force_set_sponsor(sponsor: T::AccountId, collection_id: CollectionId) -> DispatchResult {
+ let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
+ target_collection.check_is_internal()?;
+ target_collection.set_sponsor(sponsor.clone())?;
+
+ Self::deposit_event(Event::<T>::CollectionSponsorSet(
+ collection_id,
+ sponsor.clone(),
+ ));
+
+ ensure!(
+ target_collection.confirm_sponsorship(&sponsor)?,
+ Error::<T>::ConfirmUnsetSponsorFail
+ );
+
+ Self::deposit_event(Event::<T>::SponsorshipConfirmed(collection_id, sponsor));
+
+ target_collection.save()
+ }
+
+ pub fn force_remove_collection_sponsor(collection_id: CollectionId) -> DispatchResult {
+ let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
+ target_collection.check_is_internal()?;
+ target_collection.sponsorship = SponsorshipState::Disabled;
+
+ Self::deposit_event(Event::<T>::CollectionSponsorRemoved(collection_id));
+
+ target_collection.save()
+ }
+}
runtime/common/config/pallets/app_promotion.rsdiffbeforeafterboth--- a/runtime/common/config/pallets/app_promotion.rs
+++ b/runtime/common/config/pallets/app_promotion.rs
@@ -22,7 +22,7 @@
use frame_support::{parameter_types, PalletId};
use sp_arithmetic::Perbill;
use up_common::{
- constants::{DAYS, UNIQUE, RELAY_DAYS},
+ constants::{ UNIQUE, RELAY_DAYS},
types::Balance,
};
@@ -32,7 +32,7 @@
pub const RecalculationInterval: BlockNumber = 20;
pub const PendingInterval: BlockNumber = 10;
pub const Nominal: Balance = UNIQUE;
- pub const Day: BlockNumber = DAYS;
+ // pub const Day: BlockNumber = DAYS;
pub IntervalIncome: Perbill = Perbill::from_rational(RecalculationInterval::get(), RELAY_DAYS) * Perbill::from_rational(5u32, 10_000);
}
@@ -42,7 +42,7 @@
pub const RecalculationInterval: BlockNumber = RELAY_DAYS;
pub const PendingInterval: BlockNumber = 7 * RELAY_DAYS;
pub const Nominal: Balance = UNIQUE;
- pub const Day: BlockNumber = RELAY_DAYS;
+ // pub const Day: BlockNumber = RELAY_DAYS;
pub IntervalIncome: Perbill = Perbill::from_rational(5u32, 10_000);
}
@@ -56,7 +56,7 @@
type RelayBlockNumberProvider = RelayChainBlockNumberProvider<Runtime>;
type RecalculationInterval = RecalculationInterval;
type PendingInterval = PendingInterval;
- type Day = Day;
+ // type Day = Day;
type Nominal = Nominal;
type IntervalIncome = IntervalIncome;
type Event = Event;