git.delta.rocks / unique-network / refs/commits / d23689511691

difftreelog

Merge pull request #579 from UniqueNetwork/doc/app-promotion

Yaroslav Bolyukin2022-09-13parents: #848ef93 #11a57bd.patch.diff
in: master
added `doc` to app promotion

16 files changed

modifiedCargo.lockdiffbeforeafterboth
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -5733,7 +5733,7 @@
 
 [[package]]
 name = "pallet-evm-contract-helpers"
-version = "0.2.0"
+version = "0.3.0"
 dependencies = [
  "ethereum",
  "evm-coder",
@@ -12316,7 +12316,7 @@
 
 [[package]]
 name = "unique-rpc"
-version = "0.1.1"
+version = "0.1.2"
 dependencies = [
  "app-promotion-rpc",
  "fc-db",
modifiednode/cli/CHANGELOG.mddiffbeforeafterboth
--- a/node/cli/CHANGELOG.md
+++ b/node/cli/CHANGELOG.md
@@ -1,4 +1,10 @@
 <!-- bureaucrate goes here -->
+
+## [v0.9.27] 2022-09-08
+
+### Added
+-  Support RPC for `AppPromotion` pallet. 
+
 ## [v0.9.27] 2022-08-16
 
 ### Other changes
modifiednode/rpc/CHANGELOG.mddiffbeforeafterboth
--- a/node/rpc/CHANGELOG.md
+++ b/node/rpc/CHANGELOG.md
@@ -1,4 +1,9 @@
 <!-- bureaucrate goes here -->
+## [v0.1.2] 2022-09-08
+
+### Added
+-  Support RPC for `AppPromotion` pallet. 
+
 ## [v0.1.1] 2022-08-16
 
 ### Other changes
modifiednode/rpc/Cargo.tomldiffbeforeafterboth
--- a/node/rpc/Cargo.toml
+++ b/node/rpc/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "unique-rpc"
-version = "0.1.1"
+version = "0.1.2"
 authors = ['Unique Network <support@uniquenetwork.io>']
 license = 'GPLv3'
 edition = "2021"
modifiedpallets/app-promotion/src/benchmarking.rsdiffbeforeafterboth
--- a/pallets/app-promotion/src/benchmarking.rs
+++ b/pallets/app-promotion/src/benchmarking.rs
@@ -112,6 +112,7 @@
 		let share = Perbill::from_rational(1u32, 20);
 		let _ = <T as Config>::Currency::make_free_balance_be(&caller,  Perbill::from_rational(1u32, 2) * BalanceOf::<T>::max_value());
 		(0..10).map(|_| {
+			// used to change block number
 			<frame_system::Pallet<T>>::finalize();
 			PromototionPallet::<T>::stake(RawOrigin::Signed(caller.clone()).into(), share * <T as Config>::Currency::total_balance(&caller))
 		}).collect::<Result<Vec<_>, _>>()?;
modifiedpallets/app-promotion/src/lib.rsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
1616
17//! # App promotion17//! # App Promotion pallet
18//!18//!
19//! The app promotion pallet is designed to ... .19//! The pallet implements the mechanics of staking and sponsoring collections/contracts.
20//!
21//! - [`Config`]
22//! - [`Pallet`]
23//! - [`Error`]
24//! - [`Event`]
25//!
26//! ## Overview
27//! The App Promotion pallet allows fund holders to stake at a certain daily rate of return.
28//! The mechanics implemented in the pallet allow it to act as a sponsor for collections / contracts,
29//! the list of which is set by the pallet administrator.
30//!
20//!31//!
21//! ## Interface32//! ## Interface
33//! The pallet provides interfaces for funds, collection/contract operations (see [types] module).
34
22//!35//!
23//! ### Dispatchable Functions36//! ### Dispatchable Functions
37//! - [`set_admin_address`][`Pallet::set_admin_address`] - sets an address as the the admin.
38//! - [`stake`][`Pallet::stake`] - stakes the amount of native tokens.
39//! - [`unstake`][`Pallet::unstake`] - unstakes all stakes.
40//! - [`sponsor_collection`][`Pallet::sponsor_collection`] - sets the pallet to be the sponsor for the collection.
41//! - [`stop_sponsoring_collection`][`Pallet::stop_sponsoring_collection`] - removes the pallet as the sponsor for the collection.
42//! - [`sponsor_contract`][`Pallet::sponsor_contract`] - sets the pallet to be the sponsor for the contract.
43//! - [`stop_sponsoring_contract`][`Pallet::stop_sponsoring_contract`] - removes the pallet as the sponsor for the contract.
44//! - [`payout_stakers`][`Pallet::payout_stakers`] - recalculates interest for the specified number of stakers.
24//!45//!
2546
26// #![recursion_limit = "1024"]47// #![recursion_limit = "1024"]
95 /// Type for interacting with conrtacts116 /// Type for interacting with conrtacts
96 type ContractHandler: ContractHandler<AccountId = Self::CrossAccountId, ContractId = H160>;117 type ContractHandler: ContractHandler<AccountId = Self::CrossAccountId, ContractId = H160>;
97118
98 /// ID for treasury119 /// `AccountId` for treasury
99 type TreasuryAccountId: Get<Self::AccountId>;120 type TreasuryAccountId: Get<Self::AccountId>;
100121
101 /// The app's pallet id, used for deriving its sovereign account ID.122 /// The app's pallet id, used for deriving its sovereign account address.
102 #[pallet::constant]123 #[pallet::constant]
103 type PalletId: Get<PalletId>;124 type PalletId: Get<PalletId>;
104125
138 /// Staking recalculation was performed159 /// Staking recalculation was performed
139 ///160 ///
140 /// # Arguments161 /// # Arguments
141 /// * AccountId: ID of the staker.162 /// * AccountId: account of the staker.
142 /// * Balance : recalculation base163 /// * Balance : recalculation base
143 /// * Balance : total income164 /// * Balance : total income
144 StakingRecalculation(165 StakingRecalculation(
153 /// Staking was performed174 /// Staking was performed
154 ///175 ///
155 /// # Arguments176 /// # Arguments
156 /// * AccountId: ID of the staker177 /// * AccountId: account of the staker
157 /// * Balance : staking amount178 /// * Balance : staking amount
158 Stake(T::AccountId, BalanceOf<T>),179 Stake(T::AccountId, BalanceOf<T>),
159180
160 /// Unstaking was performed181 /// Unstaking was performed
161 ///182 ///
162 /// # Arguments183 /// # Arguments
163 /// * AccountId: ID of the staker184 /// * AccountId: account of the staker
164 /// * Balance : unstaking amount185 /// * Balance : unstaking amount
165 Unstake(T::AccountId, BalanceOf<T>),186 Unstake(T::AccountId, BalanceOf<T>),
166187
167 /// The admin was set188 /// The admin was set
168 ///189 ///
169 /// # Arguments190 /// # Arguments
170 /// * AccountId: ID of the admin191 /// * AccountId: account address of the admin
171 SetAdmin(T::AccountId),192 SetAdmin(T::AccountId),
172 }193 }
173194
187 IncorrectLockedBalanceOperation,208 IncorrectLockedBalanceOperation,
188 }209 }
189210
211 /// Stores the total staked amount.
190 #[pallet::storage]212 #[pallet::storage]
191 pub type TotalStaked<T: Config> = StorageValue<Value = BalanceOf<T>, QueryKind = ValueQuery>;213 pub type TotalStaked<T: Config> = StorageValue<Value = BalanceOf<T>, QueryKind = ValueQuery>;
192214
215 /// Stores the `admin` account. Some extrinsics can only be executed if they were signed by `admin`.
193 #[pallet::storage]216 #[pallet::storage]
194 pub type Admin<T: Config> = StorageValue<Value = T::AccountId, QueryKind = OptionQuery>;217 pub type Admin<T: Config> = StorageValue<Value = T::AccountId, QueryKind = OptionQuery>;
195218
196 /// Amount of tokens staked by account in the blocknumber.219 /// Stores the amount of tokens staked by account in the blocknumber.
220 ///
221 /// * **Key1** - Staker account.
222 /// * **Key2** - Relay block number when the stake was made.
223 /// * **(Balance, BlockNumber)** - Balance of the stake.
224 /// The number of the relay block in which we must perform the interest recalculation
197 #[pallet::storage]225 #[pallet::storage]
198 pub type Staked<T: Config> = StorageNMap<226 pub type Staked<T: Config> = StorageNMap<
199 Key = (227 Key = (
204 QueryKind = ValueQuery,232 QueryKind = ValueQuery,
205 >;233 >;
234
206 /// Amount of stakes for an Account235 /// Stores amount of stakes for an `Account`.
236 ///
237 /// * **Key** - Staker account.
238 /// * **Value** - Amount of stakes.
207 #[pallet::storage]239 #[pallet::storage]
208 pub type StakesPerAccount<T: Config> =240 pub type StakesPerAccount<T: Config> =
209 StorageMap<_, Blake2_128Concat, T::AccountId, u8, ValueQuery>;241 StorageMap<_, Blake2_128Concat, T::AccountId, u8, ValueQuery>;
210242
243 /// Stores amount of stakes for an `Account`.
244 ///
245 /// * **Key** - Staker account.
246 /// * **Value** - Amount of stakes.
211 #[pallet::storage]247 #[pallet::storage]
212 pub type PendingUnstake<T: Config> = StorageMap<248 pub type PendingUnstake<T: Config> = StorageMap<
213 _,249 _,
252 T::BlockNumber: From<u32> + Into<u32>,288 T::BlockNumber: From<u32> + Into<u32>,
253 <<T as Config>::Currency as Currency<T::AccountId>>::Balance: Sum + From<u128>,289 <<T as Config>::Currency as Currency<T::AccountId>>::Balance: Sum + From<u128>,
254 {290 {
291 /// Sets an address as the the admin.
292 ///
293 /// # Permissions
294 ///
295 /// * Sudo
296 ///
297 /// # Arguments
298 ///
299 /// * `admin`: account of the new admin.
255 #[pallet::weight(T::WeightInfo::set_admin_address())]300 #[pallet::weight(T::WeightInfo::set_admin_address())]
256 pub fn set_admin_address(origin: OriginFor<T>, admin: T::CrossAccountId) -> DispatchResult {301 pub fn set_admin_address(origin: OriginFor<T>, admin: T::CrossAccountId) -> DispatchResult {
257 ensure_root(origin)?;302 ensure_root(origin)?;
263 Ok(())308 Ok(())
264 }309 }
265310
311 /// Stakes the amount of native tokens.
312 /// Sets `amount` to the locked state.
313 /// The maximum number of stakes for a staker is 10.
314 ///
315 /// # Arguments
316 ///
317 /// * `amount`: in native tokens.
266 #[pallet::weight(T::WeightInfo::stake())]318 #[pallet::weight(T::WeightInfo::stake())]
267 pub fn stake(staker: OriginFor<T>, amount: BalanceOf<T>) -> DispatchResult {319 pub fn stake(staker: OriginFor<T>, amount: BalanceOf<T>) -> DispatchResult {
268 let staker_id = ensure_signed(staker)?;320 let staker_id = ensure_signed(staker)?;
280 let balance =332 let balance =
281 <<T as Config>::Currency as Currency<T::AccountId>>::free_balance(&staker_id);333 <<T as Config>::Currency as Currency<T::AccountId>>::free_balance(&staker_id);
282334
335 // checks that we can lock `amount` on the `staker` account.
283 <<T as Config>::Currency as Currency<T::AccountId>>::ensure_can_withdraw(336 <<T as Config>::Currency as Currency<T::AccountId>>::ensure_can_withdraw(
284 &staker_id,337 &staker_id,
285 amount,338 amount,
293346
294 let block_number = T::RelayBlockNumberProvider::current_block_number();347 let block_number = T::RelayBlockNumberProvider::current_block_number();
295348
349 // Calculation of the number of recalculation periods,
350 // after how much the first interest calculation should be performed for the stake
296 let recalculate_after_interval: T::BlockNumber =351 let recalculate_after_interval: T::BlockNumber =
297 if block_number % T::RecalculationInterval::get() == 0u32.into() {352 if block_number % T::RecalculationInterval::get() == 0u32.into() {
298 1u32.into()353 1u32.into()
299 } else {354 } else {
300 2u32.into()355 2u32.into()
301 };356 };
302357
358 // Сalculation of the number of the relay block
359 // in which it is necessary to accrue remuneration for the stake.
303 let recalc_block = (block_number / T::RecalculationInterval::get()360 let recalc_block = (block_number / T::RecalculationInterval::get()
304 + recalculate_after_interval)361 + recalculate_after_interval)
305 * T::RecalculationInterval::get();362 * T::RecalculationInterval::get();
327 Ok(())384 Ok(())
328 }385 }
329386
387 /// Unstakes all stakes.
388 /// Moves the sum of all stakes to the `reserved` state.
389 /// After the end of `PendingInterval` this sum becomes completely
390 /// free for further use.
330 #[pallet::weight(T::WeightInfo::unstake())]391 #[pallet::weight(T::WeightInfo::unstake())]
331 pub fn unstake(staker: OriginFor<T>) -> DispatchResultWithPostInfo {392 pub fn unstake(staker: OriginFor<T>) -> DispatchResultWithPostInfo {
332 let staker_id = ensure_signed(staker)?;393 let staker_id = ensure_signed(staker)?;
394
395 // calculate block number where the sum would be free
333 let block = <frame_system::Pallet<T>>::block_number() + T::PendingInterval::get();396 let block = <frame_system::Pallet<T>>::block_number() + T::PendingInterval::get();
397
334 let mut pendings = <PendingUnstake<T>>::get(block);398 let mut pendings = <PendingUnstake<T>>::get(block);
335399
400 // checks that we can do unreserve stakes in the block
336 ensure!(!pendings.is_full(), Error::<T>::PendingForBlockOverflow);401 ensure!(!pendings.is_full(), Error::<T>::PendingForBlockOverflow);
337402
338 let mut total_stakes = 0u64;403 let mut total_stakes = 0u64;
371 Ok(None.into())436 Ok(None.into())
372 }437 }
373438
439 /// Sets the pallet to be the sponsor for the collection.
440 ///
441 /// # Permissions
442 ///
443 /// * Pallet admin
444 ///
445 /// # Arguments
446 ///
447 /// * `collection_id`: ID of the collection that will be sponsored by `pallet_id`
374 #[pallet::weight(T::WeightInfo::sponsor_collection())]448 #[pallet::weight(T::WeightInfo::sponsor_collection())]
375 pub fn sponsor_collection(449 pub fn sponsor_collection(
376 admin: OriginFor<T>,450 admin: OriginFor<T>,
385 T::CollectionHandler::set_sponsor(Self::account_id(), collection_id)459 T::CollectionHandler::set_sponsor(Self::account_id(), collection_id)
386 }460 }
461
462 /// Removes the pallet as the sponsor for the collection.
463 /// Returns [`NoPermission`][`Error::NoPermission`]
464 /// if the pallet wasn't the sponsor.
465 ///
466 /// # Permissions
467 ///
468 /// * Pallet admin
469 ///
470 /// # Arguments
471 ///
472 /// * `collection_id`: ID of the collection that is sponsored by `pallet_id`
387 #[pallet::weight(T::WeightInfo::stop_sponsoring_collection())]473 #[pallet::weight(T::WeightInfo::stop_sponsoring_collection())]
388 pub fn stop_sponsoring_collection(474 pub fn stop_sponsoring_collection(
389 admin: OriginFor<T>,475 admin: OriginFor<T>,
404 T::CollectionHandler::remove_collection_sponsor(collection_id)490 T::CollectionHandler::remove_collection_sponsor(collection_id)
405 }491 }
406492
493 /// Sets the pallet to be the sponsor for the contract.
494 ///
495 /// # Permissions
496 ///
497 /// * Pallet admin
498 ///
499 /// # Arguments
500 ///
501 /// * `contract_id`: the contract address that will be sponsored by `pallet_id`
407 #[pallet::weight(T::WeightInfo::sponsor_contract())]502 #[pallet::weight(T::WeightInfo::sponsor_contract())]
408 pub fn sponsor_contract(admin: OriginFor<T>, contract_id: H160) -> DispatchResult {503 pub fn sponsor_contract(admin: OriginFor<T>, contract_id: H160) -> DispatchResult {
409 let admin_id = ensure_signed(admin)?;504 let admin_id = ensure_signed(admin)?;
419 )514 )
420 }515 }
421516
517 /// Removes the pallet as the sponsor for the contract.
518 /// Returns [`NoPermission`][`Error::NoPermission`]
519 /// if the pallet wasn't the sponsor.
520 ///
521 /// # Permissions
522 ///
523 /// * Pallet admin
524 ///
525 /// # Arguments
526 ///
527 /// * `contract_id`: the contract address that is sponsored by `pallet_id`
422 #[pallet::weight(T::WeightInfo::stop_sponsoring_contract())]528 #[pallet::weight(T::WeightInfo::stop_sponsoring_contract())]
423 pub fn stop_sponsoring_contract(admin: OriginFor<T>, contract_id: H160) -> DispatchResult {529 pub fn stop_sponsoring_contract(admin: OriginFor<T>, contract_id: H160) -> DispatchResult {
424 let admin_id = ensure_signed(admin)?;530 let admin_id = ensure_signed(admin)?;
437 T::ContractHandler::remove_contract_sponsor(contract_id)543 T::ContractHandler::remove_contract_sponsor(contract_id)
438 }544 }
439545
546 /// Recalculates interest for the specified number of stakers.
547 /// If all stakers are not recalculated, the next call of the extrinsic
548 /// will continue the recalculation, from those stakers for whom this
549 /// was not perform in last call.
550 ///
551 /// # Permissions
552 ///
553 /// * Pallet admin
554 ///
555 /// # Arguments
556 ///
557 /// * `stakers_number`: the number of stakers for which recalculation will be performed
440 #[pallet::weight(T::WeightInfo::payout_stakers(stakers_number.unwrap_or(20) as u32))]558 #[pallet::weight(T::WeightInfo::payout_stakers(stakers_number.unwrap_or(20) as u32))]
441 pub fn payout_stakers(admin: OriginFor<T>, stakers_number: Option<u8>) -> DispatchResult {559 pub fn payout_stakers(admin: OriginFor<T>, stakers_number: Option<u8>) -> DispatchResult {
442 let admin_id = ensure_signed(admin)?;560 let admin_id = ensure_signed(admin)?;
446 Error::<T>::NoPermission564 Error::<T>::NoPermission
447 );565 );
448566
567 // calculate the number of the current recalculation block,
568 // this is necessary in order to understand which stakers we should calculate interest
449 let current_recalc_block =569 let current_recalc_block =
450 Self::get_current_recalc_block(T::RelayBlockNumberProvider::current_block_number());570 Self::get_current_recalc_block(T::RelayBlockNumberProvider::current_block_number());
571
572 // calculate the number of the next recalculation block,
573 // this value is set for the stakers to whom the recalculation will be performed
451 let next_recalc_block = current_recalc_block + T::RecalculationInterval::get();574 let next_recalc_block = current_recalc_block + T::RecalculationInterval::get();
452575
453 let mut storage_iterator = Self::get_next_calculated_key()576 let mut storage_iterator = Self::get_next_calculated_key()
454 .map_or(Staked::<T>::iter(), |key| Staked::<T>::iter_from(key));577 .map_or(Staked::<T>::iter(), |key| Staked::<T>::iter_from(key));
455578
456 NextCalculatedRecord::<T>::set(None);579 NextCalculatedRecord::<T>::set(None);
457
458 // {
459 // let mut stakers_number = stakers_number.unwrap_or(20);
460 // let mut last_id = admin_id;
461 // let mut income_acc = BalanceOf::<T>::default();
462 // let mut amount_acc = BalanceOf::<T>::default();
463
464 // while let Some((
465 // (current_id, staked_block),
466 // (amount, next_recalc_block_for_stake),
467 // )) = storage_iterator.next()
468 // {
469 // if last_id != current_id {
470 // if income_acc != BalanceOf::<T>::default() {
471 // <T::Currency as Currency<T::AccountId>>::transfer(
472 // &T::TreasuryAccountId::get(),
473 // &last_id,
474 // income_acc,
475 // ExistenceRequirement::KeepAlive,
476 // )
477 // .and_then(|_| Self::add_lock_balance(&last_id, income_acc))?;
478
479 // Self::deposit_event(Event::StakingRecalculation(
480 // last_id, amount, income_acc,
481 // ));
482 // }
483
484 // if stakers_number == 0 {
485 // NextCalculatedRecord::<T>::set(Some((current_id, staked_block)));
486 // break;
487 // }
488 // stakers_number -= 1;
489 // income_acc = BalanceOf::<T>::default();
490 // last_id = current_id;
491 // };
492 // if current_recalc_block >= next_recalc_block_for_stake {
493 // Self::recalculate_and_insert_stake(
494 // &last_id,
495 // staked_block,
496 // next_recalc_block,
497 // amount,
498 // ((current_recalc_block - next_recalc_block_for_stake)
499 // / T::RecalculationInterval::get())
500 // .into() + 1,
501 // &mut income_acc,
502 // );
503 // }
504 // }
505 // }
506580
507 {581 {
508 let mut stakers_number = stakers_number.unwrap_or(20);582 let mut stakers_number = stakers_number.unwrap_or(20);
509 let last_id = RefCell::new(None);583 let last_id = RefCell::new(None);
510 let income_acc = RefCell::new(BalanceOf::<T>::default());584 let income_acc = RefCell::new(BalanceOf::<T>::default());
511 let amount_acc = RefCell::new(BalanceOf::<T>::default());585 let amount_acc = RefCell::new(BalanceOf::<T>::default());
512586
587 // this closure is used to perform some of the actions if we break the loop because we reached the number of stakers for recalculation,
588 // but there were unrecalculated records in the storage.
513 let flush_stake = || -> DispatchResult {589 let flush_stake = || -> DispatchResult {
514 if let Some(last_id) = &*last_id.borrow() {590 if let Some(last_id) = &*last_id.borrow() {
515 if !income_acc.borrow().is_zero() {591 if !income_acc.borrow().is_zero() {
578}654}
579655
580impl<T: Config> Pallet<T> {656impl<T: Config> Pallet<T> {
657 /// The account address of the app promotion pot.
658 ///
659 /// This actually does computation. If you need to keep using it, then make sure you cache the
660 /// value and only call this once.
581 pub fn account_id() -> T::AccountId {661 pub fn account_id() -> T::AccountId {
582 T::PalletId::get().into_account_truncating()662 T::PalletId::get().into_account_truncating()
583 }663 }
584664
665 /// Unlocks the balance that was locked by the pallet.
666 ///
667 /// - `staker`: staker account.
668 /// - `amount`: amount of unlocked funds.
585 fn unlock_balance(staker: &T::AccountId, amount: BalanceOf<T>) -> DispatchResult {669 fn unlock_balance(staker: &T::AccountId, amount: BalanceOf<T>) -> DispatchResult {
586 let locked_balance = Self::get_locked_balance(staker)670 let locked_balance = Self::get_locked_balance(staker)
587 .map(|l| l.amount)671 .map(|l| l.amount)
598 Ok(())682 Ok(())
599 }683 }
600684
685 /// Adds the balance to locked by the pallet.
686 ///
687 /// - `staker`: staker account.
688 /// - `amount`: amount of added locked funds.
601 fn add_lock_balance(staker: &T::AccountId, amount: BalanceOf<T>) -> DispatchResult {689 fn add_lock_balance(staker: &T::AccountId, amount: BalanceOf<T>) -> DispatchResult {
602 Self::get_locked_balance(staker)690 Self::get_locked_balance(staker)
603 .map_or(<BalanceOf<T>>::default(), |l| l.amount)691 .map_or(<BalanceOf<T>>::default(), |l| l.amount)
606 .ok_or(ArithmeticError::Overflow.into())694 .ok_or(ArithmeticError::Overflow.into())
607 }695 }
608696
697 /// Sets the new state of a balance locked by the pallet.
698 ///
699 /// - `staker`: staker account.
700 /// - `amount`: amount of locked funds.
609 fn set_lock_unchecked(staker: &T::AccountId, amount: BalanceOf<T>) {701 fn set_lock_unchecked(staker: &T::AccountId, amount: BalanceOf<T>) {
610 if amount.is_zero() {702 if amount.is_zero() {
611 <T::Currency as LockableCurrency<T::AccountId>>::remove_lock(LOCK_IDENTIFIER, &staker);703 <T::Currency as LockableCurrency<T::AccountId>>::remove_lock(LOCK_IDENTIFIER, &staker);
619 }711 }
620 }712 }
621713
714 /// Returns the balance locked by the pallet for the staker.
715 ///
716 /// - `staker`: staker account.
622 pub fn get_locked_balance(717 pub fn get_locked_balance(
623 staker: impl EncodeLike<T::AccountId>,718 staker: impl EncodeLike<T::AccountId>,
624 ) -> Option<BalanceLock<BalanceOf<T>>> {719 ) -> Option<BalanceLock<BalanceOf<T>>> {
627 .find(|l| l.id == LOCK_IDENTIFIER)722 .find(|l| l.id == LOCK_IDENTIFIER)
628 }723 }
629724
725 /// Returns the total staked balance for the staker.
726 ///
727 /// - `staker`: staker account.
630 pub fn total_staked_by_id(staker: impl EncodeLike<T::AccountId>) -> Option<BalanceOf<T>> {728 pub fn total_staked_by_id(staker: impl EncodeLike<T::AccountId>) -> Option<BalanceOf<T>> {
631 let staked = Staked::<T>::iter_prefix((staker,))729 let staked = Staked::<T>::iter_prefix((staker,))
632 .into_iter()730 .into_iter()
640 }738 }
641 }739 }
642740
741 /// Returns all relay block numbers when stake was made,
742 /// the amount of the stake.
743 ///
744 /// - `staker`: staker account.
643 pub fn total_staked_by_id_per_block(745 pub fn total_staked_by_id_per_block(
644 staker: impl EncodeLike<T::AccountId>,746 staker: impl EncodeLike<T::AccountId>,
645 ) -> Option<Vec<(T::BlockNumber, BalanceOf<T>)>> {747 ) -> Option<Vec<(T::BlockNumber, BalanceOf<T>)>> {
655 }757 }
656 }758 }
657759
760 /// Returns the total staked balance for the staker.
761 /// If `staker` is `None`, returns the total amount staked.
762 /// - `staker`: staker account.
658 pub fn cross_id_total_staked(staker: Option<T::CrossAccountId>) -> Option<BalanceOf<T>> {763 pub fn cross_id_total_staked(staker: Option<T::CrossAccountId>) -> Option<BalanceOf<T>> {
659 staker.map_or(Some(<TotalStaked<T>>::get()), |s| {764 staker.map_or(Some(<TotalStaked<T>>::get()), |s| {
660 Self::total_staked_by_id(s.as_sub())765 Self::total_staked_by_id(s.as_sub())
667 // .unwrap_or_default()772 // .unwrap_or_default()
668 // }773 // }
669774
775 /// Returns all relay block numbers when stake was made,
776 /// the amount of the stake.
777 ///
778 /// - `staker`: staker account.
670 pub fn cross_id_total_staked_per_block(779 pub fn cross_id_total_staked_per_block(
671 staker: T::CrossAccountId,780 staker: T::CrossAccountId,
672 ) -> Vec<(T::BlockNumber, BalanceOf<T>)> {781 ) -> Vec<(T::BlockNumber, BalanceOf<T>)> {
704 (current_relay_block / T::RecalculationInterval::get()) * T::RecalculationInterval::get()813 (current_relay_block / T::RecalculationInterval::get()) * T::RecalculationInterval::get()
705 }814 }
706
707 // fn get_next_recalc_block(current_relay_block: T::BlockNumber) -> T::BlockNumber {
708 // Self::get_current_recalc_block(current_relay_block) + T::RecalculationInterval::get()
709 // }
710815
711 fn get_next_calculated_key() -> Option<Vec<u8>> {816 fn get_next_calculated_key() -> Option<Vec<u8>> {
712 Self::get_next_calculated_record().map(|key| Staked::<T>::hashed_key_for(key))817 Self::get_next_calculated_record().map(|key| Staked::<T>::hashed_key_for(key))
717where822where
718 <<T as Config>::Currency as Currency<T::AccountId>>::Balance: Sum,823 <<T as Config>::Currency as Currency<T::AccountId>>::Balance: Sum,
719{824{
825 /// Returns the amount reserved by the pending.
826 /// If `staker` is `None`, returns the total pending.
827 ///
828 /// -`staker`: staker account.
829 ///
720 /// Since user funds are not transferred anywhere by staking, overflow protection is provided830 /// Since user funds are not transferred anywhere by staking, overflow protection is provided
721 /// at the level of the associated type `Balance` of `Currency` trait. In order to overflow,831 /// at the level of the associated type `Balance` of `Currency` trait. In order to overflow,
722 /// the staker must have more funds on his account than the maximum set for `Balance` type.832 /// the staker must have more funds on his account than the maximum set for `Balance` type.
740 )850 )
741 }851 }
742852
853 /// Returns all parachain block numbers when unreserve is expected,
854 /// the amount of the unreserved funds.
855 ///
856 /// - `staker`: staker account.
743 pub fn cross_id_pending_unstake_per_block(857 pub fn cross_id_pending_unstake_per_block(
744 staker: T::CrossAccountId,858 staker: T::CrossAccountId,
745 ) -> Vec<(T::BlockNumber, BalanceOf<T>)> {859 ) -> Vec<(T::BlockNumber, BalanceOf<T>)> {
modifiedpallets/app-promotion/src/types.rsdiffbeforeafterboth
--- a/pallets/app-promotion/src/types.rs
+++ b/pallets/app-promotion/src/types.rs
@@ -9,7 +9,10 @@
 use sp_std::borrow::ToOwned;
 use pallet_evm_contract_helpers::{Pallet as EvmHelpersPallet, Config as EvmHelpersConfig};
 
+/// This trait was defined because `LockableCurrency`
+/// has no way to know the state of the lock for an account.
 pub trait ExtendedLockableCurrency<AccountId: Parameter>: LockableCurrency<AccountId> {
+	/// Returns lock balance for an account. Allows to determine the cause of the lock.
 	fn locks<KArg>(who: KArg) -> WeakBoundedVec<BalanceLock<Self::Balance>, Self::MaxLocks>
 	where
 		KArg: EncodeLike<AccountId>;
@@ -25,18 +28,28 @@
 		Self::locks(who)
 	}
 }
-
+/// Trait for interacting with collections.
 pub trait CollectionHandler {
 	type CollectionId;
 	type AccountId;
 
+	/// Sets sponsor for a collection.
+	///
+	/// - `sponsor_id`: the account of the sponsor-to-be.
+	/// - `collection_id`: ID of the modified collection.
 	fn set_sponsor(
 		sponsor_id: Self::AccountId,
 		collection_id: Self::CollectionId,
 	) -> DispatchResult;
 
+	/// Removes sponsor for a collection.
+	///
+	/// - `collection_id`: ID of the modified collection.
 	fn remove_collection_sponsor(collection_id: Self::CollectionId) -> DispatchResult;
 
+	/// Retuns the current sponsor for a collection if one is set.
+	///
+	/// - `collection_id`: ID of the collection.
 	fn sponsor(collection_id: Self::CollectionId)
 		-> Result<Option<Self::AccountId>, DispatchError>;
 }
@@ -66,18 +79,28 @@
 			.map(|acc| acc.to_owned()))
 	}
 }
-
+/// Trait for interacting with contracts.
 pub trait ContractHandler {
 	type ContractId;
 	type AccountId;
 
+	/// Sets sponsor for a contract.
+	///
+	/// - `sponsor_id`: the account of the sponsor-to-be.
+	/// - `contract_address`: the address of the modified contract.
 	fn set_sponsor(
 		sponsor_id: Self::AccountId,
 		contract_address: Self::ContractId,
 	) -> DispatchResult;
 
+	/// Removes sponsor for a contract.
+	///
+	/// - `contract_address`: the address of the modified contract.
 	fn remove_contract_sponsor(contract_address: Self::ContractId) -> DispatchResult;
 
+	/// Retuns the current sponsor for a contract if one is set.
+	///
+	/// - `contract_address`: the contract address.
 	fn sponsor(
 		contract_address: Self::ContractId,
 	) -> Result<Option<Self::AccountId>, DispatchError>;
modifiedpallets/evm-contract-helpers/CHANGELOG.mddiffbeforeafterboth
--- a/pallets/evm-contract-helpers/CHANGELOG.md
+++ b/pallets/evm-contract-helpers/CHANGELOG.md
@@ -2,29 +2,35 @@
 
 All notable changes to this project will be documented in this file.
 
+## [v0.3.0] 2022-09-05
+
+### Added
+
+-   Methods `force_set_sponsor` , `force_remove_sponsor` to be able to administer sponsorships with other pallets. Added to implement `AppPromotion` pallet logic.
+
 ## [v0.2.0] - 2022-08-19
 
 ### Added
 
- - Set arbitrary evm address as contract sponsor.
- - Ability to remove current sponsor.
+-   Set arbitrary evm address as contract sponsor.
+-   Ability to remove current sponsor.
 
 ### Removed
- - Remove methods
-   + sponsoring_enabled
-   + toggle_sponsoring
 
- ### Changed
+-   Remove methods
+    -   sponsoring_enabled
+    -   toggle_sponsoring
 
- - Change `toggle_sponsoring` to `self_sponsored_enable`.
+### Changed
 
+-   Change `toggle_sponsoring` to `self_sponsored_enable`.
 
 ## [v0.1.2] 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
 
-- build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b
\ No newline at end of file
+-   build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b
modifiedpallets/evm-contract-helpers/Cargo.tomldiffbeforeafterboth
--- a/pallets/evm-contract-helpers/Cargo.toml
+++ b/pallets/evm-contract-helpers/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "pallet-evm-contract-helpers"
-version = "0.2.0"
+version = "0.3.0"
 license = "GPLv3"
 edition = "2021"
 
modifiedpallets/evm-contract-helpers/src/lib.rsdiffbeforeafterboth
--- a/pallets/evm-contract-helpers/src/lib.rs
+++ b/pallets/evm-contract-helpers/src/lib.rs
@@ -216,9 +216,10 @@
 			Ok(())
 		}
 
-		/// TO-DO
-		///
+		/// Force set `sponsor` for `contract`.
 		///
+		/// Differs from `set_sponsor` in that confirmation
+		/// from the sponsor is not required.
 		pub fn force_set_sponsor(
 			contract_address: H160,
 			sponsor: &T::CrossAccountId,
@@ -269,9 +270,10 @@
 			Self::force_remove_sponsor(contract_address)
 		}
 
-		/// TO-DO
-		///
+		/// Force remove `sponsor` for `contract`.
 		///
+		/// Differs from `remove_sponsor` in that
+		/// it doesn't require consent from the `owner` of the contract.
 		pub fn force_remove_sponsor(contract_address: H160) -> DispatchResult {
 			Sponsoring::<T>::remove(contract_address);
 
modifiedpallets/unique/CHANGELOG.mddiffbeforeafterboth
--- a/pallets/unique/CHANGELOG.md
+++ b/pallets/unique/CHANGELOG.md
@@ -4,7 +4,7 @@
 
 <!-- bureaucrate goes here -->
 
-## [v0.1.4] 2022-09-5
+## [v0.1.4] 2022-09-05
 
 ### Added
 
modifiedpallets/unique/src/lib.rsdiffbeforeafterboth
--- a/pallets/unique/src/lib.rs
+++ b/pallets/unique/src/lib.rs
@@ -1105,6 +1105,15 @@
 }
 
 impl<T: Config> Pallet<T> {
+	/// Force set `sponsor` for `collection`.
+	///
+	/// Differs from [`set_collection_sponsor`][`Pallet::set_collection_sponsor`] in that confirmation
+	/// from the `sponsor` is not required.
+	///
+	/// # Arguments
+	///
+	/// * `sponsor`: ID of the account of the sponsor-to-be.
+	/// * `collection_id`: ID of the modified collection.
 	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()?;
@@ -1125,6 +1134,14 @@
 		target_collection.save()
 	}
 
+	/// Force remove `sponsor` for `collection`.
+	///
+	/// Differs from `remove_sponsor` in that
+	/// it doesn't require consent from the `owner` of the collection.
+	///
+	/// # Arguments
+	///
+	/// * `collection_id`: ID of the modified collection.
 	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()?;
modifiedprimitives/common/CHANGELOG.mddiffbeforeafterboth
--- a/primitives/common/CHANGELOG.md
+++ b/primitives/common/CHANGELOG.md
@@ -1,4 +1,9 @@
 <!-- bureaucrate goes here -->
+## [v0.9.27] 2022-09-08
+
+### Added
+-  Relay block constants. In particular, it is necessary to add the `AppPromotion` pallet at runtime.
+
 ## [v0.9.25] 2022-08-16
 
 ### Other changes
modifiedruntime/opal/CHANGELOG.mddiffbeforeafterboth
--- a/runtime/opal/CHANGELOG.md
+++ b/runtime/opal/CHANGELOG.md
@@ -3,16 +3,23 @@
 All notable changes to this project will be documented in this file.
 
 <!-- bureaucrate goes here -->
+
+## [v0.9.27] 2022-09-08
+
+### Added
+
+-   `AppPromotion` pallet to runtime.
+
 ## [v0.9.27] 2022-08-16
 
 ### Bugfixes
 
-- Add missing config keys 74f532ac28dce15c15e7d576c074a58eba658c08
+-   Add missing config keys 74f532ac28dce15c15e7d576c074a58eba658c08
 
 ### 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
 
-- build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b
+-   build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b
modifiedruntime/quartz/CHANGELOG.mddiffbeforeafterboth
--- a/runtime/quartz/CHANGELOG.md
+++ b/runtime/quartz/CHANGELOG.md
@@ -3,17 +3,23 @@
 All notable changes to this project will be documented in this file.
 
 <!-- bureaucrate goes here -->
+
+## [v0.9.27] 2022-09-08
+
+### Added
+
+-   `AppPromotion` pallet to runtime.
+
 ## [v0.9.27] 2022-08-16
 
 ### Bugfixes
 
-- Add missing config keys 74f532ac28dce15c15e7d576c074a58eba658c08
+-   Add missing config keys 74f532ac28dce15c15e7d576c074a58eba658c08
 
 ### 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
 
-- build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b
-
+-   build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b
modifiedruntime/unique/CHANGELOG.mddiffbeforeafterboth
--- a/runtime/unique/CHANGELOG.md
+++ b/runtime/unique/CHANGELOG.md
@@ -3,16 +3,23 @@
 All notable changes to this project will be documented in this file.
 
 <!-- bureaucrate goes here -->
+
+## [v0.9.27] 2022-09-08
+
+### Added
+
+-   `AppPromotion` pallet to runtime.
+
 ## [v0.9.27] 2022-08-16
 
 ### Bugfixes
 
-- Add missing config keys 74f532ac28dce15c15e7d576c074a58eba658c08
+-   Add missing config keys 74f532ac28dce15c15e7d576c074a58eba658c08
 
 ### 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
 
-- build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b
+-   build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b