From 850841ac5cdfe6611970c870c5b5c7042a4e5fcd Mon Sep 17 00:00:00 2001 From: Igor Papandinas <26460174+ipapandinas@users.noreply.github.com> Date: Mon, 26 Aug 2024 14:26:19 +0200 Subject: [PATCH 1/3] support tier threshold derivation --- tests/staking/tier-threshold.test.ts | 264 +++++++++++++++++++++++---- 1 file changed, 228 insertions(+), 36 deletions(-) diff --git a/tests/staking/tier-threshold.test.ts b/tests/staking/tier-threshold.test.ts index 3dabd06..1fe93d4 100644 --- a/tests/staking/tier-threshold.test.ts +++ b/tests/staking/tier-threshold.test.ts @@ -1,27 +1,218 @@ import { expect } from 'vitest' +import { u16 } from '@polkadot/types' import { given } from '../../helpers' +const TIER_DERIVATION_PALLET_VERSION = 8 + +type TierConfig = { + rewardPortion: string[] + slotsPerTier: string[] + tierThresholds: string[] +} + +const calculateNumberOfSlots = (slotsPerTier: string[]): number => { + return slotsPerTier.reduce((acc, val) => acc + Number(val), 0) +} + given('astar')('Number of slots adjusted based on price', async ({ networks: { astar } }) => { const advanceNextEra = async () => { const state = await astar.api.query.dappStaking.activeProtocolState() await astar.dev.newBlock({ count: 1, unsafeBlockHeight: state.nextEraStart.toNumber() }) } - // set price to $0.10 - await astar.dev.setStorage({ - priceAggregator: { - valuesCircularBuffer: { - head: 1, - buffer: [ - 100_000_000_000_000_000n, // $0.10 - ], + const palletVersion = (await astar.api.query.dappStaking.palletVersion()).toNumber() + + if (palletVersion >= TIER_DERIVATION_PALLET_VERSION) { + // set total issuance to 8.4B (dApp staking v3 launch) + // set price to $0.10 + await astar.dev.setStorage({ + balances: { + totalIssuance: 8_400_000_000_000_000_000_000_000_000n, // 8.4B + }, + dappStaking: { + staticTierParams: { + // Permill percentages + rewardPortion: [ + 250000, // 25% + 470000, // 47% + 250000, // 25% + 30000, // 3% + ], + // Permill percentages + slotDistribution: [ + 50000, // 5% + 200000, // 20% + 300000, // 30% + 450000, // 45% + ], + // Perbill percentages + // percentages below are calulated based on total issuance at the time when dApp staking v3 was launched (8.4B) + tierThresholds: [ + { + DynamicPercentage: { + percentage: 35_700_000, // 3.57% + minimumRequiredPercentage: 23_800_000, // 2.38% + }, + }, + { + DynamicPercentage: { + percentage: 8_900_000, // 0.89% + minimumRequiredPercentage: 6_000_000, // 0.6% + }, + }, + { + DynamicPercentage: { + percentage: 2_380_000, // 0.238% + minimumRequiredPercentage: 1_790_000, // 0.179% + }, + }, + { + FixedPercentage: { + requiredPercentage: 200_000, // 0.02% + }, + }, + ], + }, + }, + priceAggregator: { + valuesCircularBuffer: { + head: 1, + buffer: [ + 100_000_000_000_000_000n, // $0.10 + ], + }, + }, + }) + + await advanceNextEra() + + let config = (await astar.api.query.dappStaking.tierConfig()).toHuman() as TierConfig + let numberOfSlots = calculateNumberOfSlots(config.slotsPerTier) + + expect(numberOfSlots).toEqual(149) + expect(config).toMatchInlineSnapshot(` + { + "rewardPortion": [ + "25.00%", + "47.00%", + "25.00%", + "3.00%", + ], + "slotsPerTier": [ + "7", + "30", + "45", + "67", + ], + "tierThresholds": [ + "199,920,000,434,962,152,673,349,634", + "50,400,000,109,654,324,178,165,454", + "15,036,000,032,713,540,046,486,027", + "1,680,000,003,655,144,139,272,182", + ], + } + `) + + // set price to $0.50 + await astar.dev.setStorage({ + priceAggregator: { + valuesCircularBuffer: { + head: 1, + buffer: [ + 500_000_000_000_000_000n, // $0.50 + ], + }, + }, + }) + + await advanceNextEra() + + config = (await astar.api.query.dappStaking.tierConfig()).toHuman() as TierConfig + numberOfSlots = calculateNumberOfSlots(config.slotsPerTier) + + expect(numberOfSlots).toEqual(549) + expect(config).toMatchInlineSnapshot(` + { + "rewardPortion": [ + "25.00%", + "47.00%", + "25.00%", + "3.00%", + ], + "slotsPerTier": [ + "27", + "110", + "165", + "247", + ], + "tierThresholds": [ + "199,920,000,869,924,305,146,779,267", + "50,400,000,219,308,648,356,330,908", + "15,036,000,065,427,080,092,972,054", + "1,680,000,007,310,288,278,544,364", + ], + } + `) + + // set price to $0.05 + await astar.dev.setStorage({ + priceAggregator: { + valuesCircularBuffer: { + head: 1, + buffer: [ + 50_000_000_000_000_000n, // $0.05 + ], + }, + }, + }) + + await advanceNextEra() + + config = (await astar.api.query.dappStaking.tierConfig()).toHuman() as TierConfig + numberOfSlots = calculateNumberOfSlots(config.slotsPerTier) + + expect(numberOfSlots).toEqual(100) + expect(config).toMatchInlineSnapshot(` + { + "rewardPortion": [ + "25.00%", + "47.00%", + "25.00%", + "3.00%", + ], + "slotsPerTier": [ + "5", + "20", + "30", + "45", + ], + "tierThresholds": [ + "299,880,001,957,329,686,580,253,351", + "74,760,000,487,961,742,592,836,270", + "19,992,000,130,488,645,772,016,890", + "1,680,000,010,965,432,417,816,545", + ], + } + `) + } + + // LEGACY TEST + else { + // set price to $0.10 + await astar.dev.setStorage({ + priceAggregator: { + valuesCircularBuffer: { + head: 1, + buffer: [ + 100_000_000_000_000_000n, // $0.10 + ], + }, }, - }, - }) + }) - await advanceNextEra() + await advanceNextEra() - expect((await astar.api.query.dappStaking.tierConfig()).toHuman()).toMatchInlineSnapshot(` + expect((await astar.api.query.dappStaking.tierConfig()).toHuman()).toMatchInlineSnapshot(` { "numberOfSlots": "150", "rewardPortion": [ @@ -64,21 +255,21 @@ given('astar')('Number of slots adjusted based on price', async ({ networks: { a } `) - // set price to $0.50 - await astar.dev.setStorage({ - priceAggregator: { - valuesCircularBuffer: { - head: 1, - buffer: [ - 500_000_000_000_000_000n, // $0.50 - ], + // set price to $0.50 + await astar.dev.setStorage({ + priceAggregator: { + valuesCircularBuffer: { + head: 1, + buffer: [ + 500_000_000_000_000_000n, // $0.50 + ], + }, }, - }, - }) + }) - await advanceNextEra() + await advanceNextEra() - expect((await astar.api.query.dappStaking.tierConfig()).toHuman()).toMatchInlineSnapshot(` + expect((await astar.api.query.dappStaking.tierConfig()).toHuman()).toMatchInlineSnapshot(` { "numberOfSlots": "550", "rewardPortion": [ @@ -121,21 +312,21 @@ given('astar')('Number of slots adjusted based on price', async ({ networks: { a } `) - // set price to $0.05 - await astar.dev.setStorage({ - priceAggregator: { - valuesCircularBuffer: { - head: 1, - buffer: [ - 50_000_000_000_000_000n, // $0.05 - ], + // set price to $0.05 + await astar.dev.setStorage({ + priceAggregator: { + valuesCircularBuffer: { + head: 1, + buffer: [ + 50_000_000_000_000_000n, // $0.05 + ], + }, }, - }, - }) + }) - await advanceNextEra() + await advanceNextEra() - expect((await astar.api.query.dappStaking.tierConfig()).toHuman()).toMatchInlineSnapshot(` + expect((await astar.api.query.dappStaking.tierConfig()).toHuman()).toMatchInlineSnapshot(` { "numberOfSlots": "100", "rewardPortion": [ @@ -177,4 +368,5 @@ given('astar')('Number of slots adjusted based on price', async ({ networks: { a ], } `) + } }) From f4096ec73152362e5f3c312e310f10e77b850434 Mon Sep 17 00:00:00 2001 From: Igor Papandinas <26460174+ipapandinas@users.noreply.github.com> Date: Mon, 26 Aug 2024 14:36:25 +0200 Subject: [PATCH 2/3] improve TS typing --- tests/staking/tier-threshold.test.ts | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/tests/staking/tier-threshold.test.ts b/tests/staking/tier-threshold.test.ts index 1fe93d4..96528e6 100644 --- a/tests/staking/tier-threshold.test.ts +++ b/tests/staking/tier-threshold.test.ts @@ -1,17 +1,18 @@ import { expect } from 'vitest' -import { u16 } from '@polkadot/types' +import { Perbill } from '@polkadot/types/interfaces' +import { Struct, Vec, u16, u128 } from '@polkadot/types' import { given } from '../../helpers' const TIER_DERIVATION_PALLET_VERSION = 8 -type TierConfig = { - rewardPortion: string[] - slotsPerTier: string[] - tierThresholds: string[] +interface TiersConfigurationV8 extends Struct { + readonly slotsPerTier: Vec + readonly rewardPortion: Vec + readonly tierThresholds: Vec } -const calculateNumberOfSlots = (slotsPerTier: string[]): number => { - return slotsPerTier.reduce((acc, val) => acc + Number(val), 0) +const calculateNumberOfSlots = (slotsPerTier: u16[]): number => { + return slotsPerTier.reduce((acc, val) => acc + val.toNumber(), 0) } given('astar')('Number of slots adjusted based on price', async ({ networks: { astar } }) => { @@ -86,7 +87,7 @@ given('astar')('Number of slots adjusted based on price', async ({ networks: { a await advanceNextEra() - let config = (await astar.api.query.dappStaking.tierConfig()).toHuman() as TierConfig + let config = await astar.api.query.dappStaking.tierConfig() let numberOfSlots = calculateNumberOfSlots(config.slotsPerTier) expect(numberOfSlots).toEqual(149) @@ -127,7 +128,7 @@ given('astar')('Number of slots adjusted based on price', async ({ networks: { a await advanceNextEra() - config = (await astar.api.query.dappStaking.tierConfig()).toHuman() as TierConfig + config = await astar.api.query.dappStaking.tierConfig() numberOfSlots = calculateNumberOfSlots(config.slotsPerTier) expect(numberOfSlots).toEqual(549) @@ -168,7 +169,7 @@ given('astar')('Number of slots adjusted based on price', async ({ networks: { a await advanceNextEra() - config = (await astar.api.query.dappStaking.tierConfig()).toHuman() as TierConfig + config = await astar.api.query.dappStaking.tierConfig() numberOfSlots = calculateNumberOfSlots(config.slotsPerTier) expect(numberOfSlots).toEqual(100) From 35d2bccf18fb406dc1ae6abad39199ab9b1f13d0 Mon Sep 17 00:00:00 2001 From: Igor Papandinas <26460174+ipapandinas@users.noreply.github.com> Date: Mon, 26 Aug 2024 14:41:51 +0200 Subject: [PATCH 3/3] fix v8 test --- tests/staking/tier-threshold.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/staking/tier-threshold.test.ts b/tests/staking/tier-threshold.test.ts index 96528e6..0bbbc3b 100644 --- a/tests/staking/tier-threshold.test.ts +++ b/tests/staking/tier-threshold.test.ts @@ -91,7 +91,7 @@ given('astar')('Number of slots adjusted based on price', async ({ networks: { a let numberOfSlots = calculateNumberOfSlots(config.slotsPerTier) expect(numberOfSlots).toEqual(149) - expect(config).toMatchInlineSnapshot(` + expect(config.toHuman()).toMatchInlineSnapshot(` { "rewardPortion": [ "25.00%", @@ -132,7 +132,7 @@ given('astar')('Number of slots adjusted based on price', async ({ networks: { a numberOfSlots = calculateNumberOfSlots(config.slotsPerTier) expect(numberOfSlots).toEqual(549) - expect(config).toMatchInlineSnapshot(` + expect(config.toHuman()).toMatchInlineSnapshot(` { "rewardPortion": [ "25.00%", @@ -173,7 +173,7 @@ given('astar')('Number of slots adjusted based on price', async ({ networks: { a numberOfSlots = calculateNumberOfSlots(config.slotsPerTier) expect(numberOfSlots).toEqual(100) - expect(config).toMatchInlineSnapshot(` + expect(config.toHuman()).toMatchInlineSnapshot(` { "rewardPortion": [ "25.00%",