difftreelog
Merge pull request #727 from UniqueNetwork/feature/shortTimingsAppPromotion
in: master
Feature/short timings app promotion
2 files changed
runtime/common/config/pallets/app_promotion.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/>.1617use crate::{18 runtime_common::config::pallets::{TreasuryAccountId, RelayChainBlockNumberProvider},19 Runtime, Balances, BlockNumber, Unique, RuntimeEvent, EvmContractHelpers,20};2122use frame_support::{parameter_types, PalletId};23use sp_arithmetic::Perbill;24use up_common::{25 constants::{UNIQUE, RELAY_DAYS},26 types::Balance,27};2829#[cfg(all(not(feature = "unique-runtime"), not(feature = "quartz-runtime")))]30parameter_types! {31 pub const AppPromotionId: PalletId = PalletId(*b"appstake");32 pub const RecalculationInterval: BlockNumber = 20;33 pub const PendingInterval: BlockNumber = 10;34 pub const Nominal: Balance = UNIQUE;35 // pub const Day: BlockNumber = DAYS;36 pub IntervalIncome: Perbill = Perbill::from_rational(RecalculationInterval::get(), RELAY_DAYS) * Perbill::from_rational(5u32, 10_000);37}3839#[cfg(any(feature = "unique-runtime", feature = "quartz-runtime"))]40parameter_types! {41 pub const AppPromotionId: PalletId = PalletId(*b"appstake");42 pub const RecalculationInterval: BlockNumber = RELAY_DAYS;43 pub const PendingInterval: BlockNumber = 7 * RELAY_DAYS;44 pub const Nominal: Balance = UNIQUE;45 // pub const Day: BlockNumber = RELAY_DAYS;46 pub IntervalIncome: Perbill = Perbill::from_rational(5u32, 10_000);47}4849impl pallet_app_promotion::Config for Runtime {50 type PalletId = AppPromotionId;51 type CollectionHandler = Unique;52 type ContractHandler = EvmContractHelpers;53 type Currency = Balances;54 type WeightInfo = pallet_app_promotion::weights::SubstrateWeight<Self>;55 type TreasuryAccountId = TreasuryAccountId;56 type RelayBlockNumberProvider = RelayChainBlockNumberProvider<Runtime>;57 type RecalculationInterval = RecalculationInterval;58 type PendingInterval = PendingInterval;59 // type Day = Day;60 type Nominal = Nominal;61 type IntervalIncome = IntervalIncome;62 type RuntimeEvent = RuntimeEvent;63}tests/src/app-promotion.test.tsdiffbeforeafterboth--- a/tests/src/app-promotion.test.ts
+++ b/tests/src/app-promotion.test.ts
@@ -24,12 +24,8 @@
let nominal: bigint;
let palletAddress: string;
let accounts: IKeyringPair[];
-const LOCKING_PERIOD = 20n; // 20 blocks of relay
-const UNLOCKING_PERIOD = 10n; // 10 blocks of parachain
-const rewardAvailableInBlock = (stakedInBlock: bigint) => {
- if (stakedInBlock % LOCKING_PERIOD === 0n) return stakedInBlock + 20n;
- return (stakedInBlock - stakedInBlock % LOCKING_PERIOD) + (LOCKING_PERIOD * 2n);
-};
+const LOCKING_PERIOD = 8n; // 8 blocks of relay
+const UNLOCKING_PERIOD = 4n; // 4 blocks of parachain
describe('App promotion', () => {
before(async function () {
@@ -548,7 +544,7 @@
expect(totalStakedAfter).to.equal(totalStakedBefore + (100n * nominal) + totalPayout);
// staker can unstake
await helper.staking.unstake(staker);
- expect(await helper.staking.getTotalStaked()).to.be.equal(totalStakedAfter - calculateIncome(100n * nominal, 10n));
+ expect(await helper.staking.getTotalStaked()).to.be.equal(totalStakedAfter - calculateIncome(100n * nominal));
});
itSub('should credit 0.05% for staking period', async ({helper}) => {
@@ -564,11 +560,11 @@
await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stake2.block));
const payoutToStaker = (await helper.admin.payoutStakers(palletAdmin, 100)).find((payout) => payout.staker === staker.address)?.payout;
- expect(payoutToStaker + 300n * nominal).to.equal(calculateIncome(300n * nominal, 10n));
+ expect(payoutToStaker + 300n * nominal).to.equal(calculateIncome(300n * nominal));
const totalStakedPerBlock = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
- expect(totalStakedPerBlock[0].amount).to.equal(calculateIncome(100n * nominal, 10n));
- expect(totalStakedPerBlock[1].amount).to.equal(calculateIncome(200n * nominal, 10n));
+ expect(totalStakedPerBlock[0].amount).to.equal(calculateIncome(100n * nominal));
+ expect(totalStakedPerBlock[1].amount).to.equal(calculateIncome(200n * nominal));
});
itSub('shoud be paid for more than one period if payments was missed', async ({helper}) => {
@@ -581,7 +577,7 @@
await helper.admin.payoutStakers(palletAdmin, 100);
[stake] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
- const frozenBalanceShouldBe = calculateIncome(100n * nominal, 10n, 2);
+ const frozenBalanceShouldBe = calculateIncome(100n * nominal, 2);
expect(stake.amount).to.be.equal(frozenBalanceShouldBe);
const stakerFullBalance = await helper.balance.getSubstrateFull(staker.address);
@@ -615,12 +611,12 @@
await helper.admin.payoutStakers(palletAdmin, 100);
[stake] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
- expect(stake.amount).to.equal(calculateIncome(100n * nominal, 10n));
+ expect(stake.amount).to.equal(calculateIncome(100n * nominal));
await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stake.block) + LOCKING_PERIOD);
await helper.admin.payoutStakers(palletAdmin, 100);
[stake] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
- expect(stake.amount).to.equal(calculateIncome(100n * nominal, 10n, 2));
+ expect(stake.amount).to.equal(calculateIncome(100n * nominal, 2));
});
itSub.skip('can be paid 1000 rewards in a time', async ({helper}) => {
@@ -653,16 +649,22 @@
});
});
-function calculateIncome(base: bigint, calcPeriod: bigint, iter = 0): bigint {
+function calculateIncome(base: bigint, iter = 0, calcPeriod: bigint = UNLOCKING_PERIOD): bigint {
const DAY = 7200n;
const ACCURACY = 1_000_000_000n;
+ // 5n / 10_000n = 0.05% p/day
const income = base + base * (ACCURACY * (calcPeriod * 5n) / (10_000n * DAY)) / ACCURACY ;
if (iter > 1) {
- return calculateIncome(income, calcPeriod, iter - 1);
+ return calculateIncome(income, iter - 1, calcPeriod);
} else return income;
}
+function rewardAvailableInBlock(stakedInBlock: bigint) {
+ if (stakedInBlock % LOCKING_PERIOD === 0n) return stakedInBlock + LOCKING_PERIOD;
+ return (stakedInBlock - stakedInBlock % LOCKING_PERIOD) + (LOCKING_PERIOD * 2n);
+}
+
// Wait while promotion period less than specified block, to avoid boundary cases
// 0 if this should be the beginning of the period.
async function waitPromotionPeriodDoesntEnd(helper: DevUniqueHelper, waitBlockLessThan = LOCKING_PERIOD / 3n) {