From e823edeaa01741b20c0bb44062a63fea3959cdbf Mon Sep 17 00:00:00 2001 From: Dr-Electron Date: Sun, 20 Aug 2023 19:53:59 +0200 Subject: [PATCH 01/40] Add Delegator Component --- .../protocols/iota2.0/core-concepts/mana.md | 6 + src/components/ManaCalculator/calculator.ts | 143 +++++++ src/components/ManaCalculator/index.tsx | 349 ++++++++++++++++++ src/components/ManaCalculator/types.ts | 46 +++ src/components/ManaCalculator/utils.ts | 102 +++++ 5 files changed, 646 insertions(+) create mode 100644 src/components/ManaCalculator/calculator.ts create mode 100644 src/components/ManaCalculator/index.tsx create mode 100644 src/components/ManaCalculator/types.ts create mode 100644 src/components/ManaCalculator/utils.ts diff --git a/docs/learn/protocols/iota2.0/core-concepts/mana.md b/docs/learn/protocols/iota2.0/core-concepts/mana.md index 426b8763165..ce8fb80ebac 100644 --- a/docs/learn/protocols/iota2.0/core-concepts/mana.md +++ b/docs/learn/protocols/iota2.0/core-concepts/mana.md @@ -1,3 +1,5 @@ +import ManaCalculator from '@site/src/components/ManaCalculator'; + # Tokenomics: Mana, Accounts, Staking and Delegation Mana is a scarce resource used to access the IOTA ledger and update its state through block creation. It is a spendable asset tracked in the ledger state, powering smart contracts, DeFi applications, block creation, and various other services, and is linked to [accounts](#accounts), which allow you to [stake or delegate](#staking-and-delegation-1) mana to receive [Mana rewards](#mana-rewards). @@ -237,3 +239,7 @@ A reward scheme is always a powerful mechanism to incentivize actors to have cer - No incentives for centralizing the funds of validators and delegators. - By the construction of our reward formulas, there is no incentive for the centralization of validator funds. Technically speaking, this means that two different validators do not get more rewards by combining their stake. - Analogously, the concentration of delegator funds is disincentivized by the construction of our reward formula. As more delegated stake is concentrated on the same validator, the rewards of the delegators become smaller. Then, the delegators are incentivized to redelegate to validators with less delegated stake. In the long run, under the assumption that actors are rational, the system should stabilize around a constant ratio of delegated and validator stake among pools. + +## Mana Calculator + + diff --git a/src/components/ManaCalculator/calculator.ts b/src/components/ManaCalculator/calculator.ts new file mode 100644 index 00000000000..e1ce2e75f44 --- /dev/null +++ b/src/components/ManaCalculator/calculator.ts @@ -0,0 +1,143 @@ +import { + GENERATION_PER_SLOT, + first_slot_of_epoch, + potential_Mana, + IOTA_SUPPLY, + targetReward, + EPOCH_DURATION, +} from './utils'; +import { ValiatorParameters, ValidatorProps } from './types'; + +export function calculateManaGeneratedPerEpoch( + stake: number, + yourPool: number, + validatorParameters: ValiatorParameters, + validators: ValidatorProps[], + epoch: number, + yourRole: 'Validator' | 'Delegator', +): number { + // Initialies lockedStake array with the stake of each validator + const lockedStake: number[] = validators.map( + (validator) => validator.lockedStake, + ); + const fixedCosts: number[] = validators.map( + (validator) => validator.fixedCost, + ); + const performance: number[] = validators.map( + (validator) => validator.performanceFactor, + ); + const delegatedStake: number[] = validators.map( + (validator) => validator.delegatedStake, + ); + + if (yourRole === 'Validator') { + lockedStake.push(stake * validatorParameters.shareOfYourStakeLocked); + fixedCosts.push(validatorParameters.yourFixedCost); + performance.push(validatorParameters.yourPerformance); + delegatedStake.push( + (1 - validatorParameters.shareOfYourStakeLocked) * stake + + validatorParameters.attractedNewDelegatedStake + + validatorParameters.attractedDelegatedStakeFromOtherPools * + delegatedStake.reduce((a, b) => a + b, 0), + ); + for (let i = 0; i < validators.length; i++) { + delegatedStake[i] *= + 1 - validatorParameters.attractedDelegatedStakeFromOtherPools; + } + } + + if (yourRole === 'Delegator') { + delegatedStake[yourPool] += stake; + } + + const totalValidatorsStake = lockedStake.reduce((a, b) => a + b, 0); + const totalDelegatedStake = delegatedStake.reduce((a, b) => a + b, 0); + const totalStake = totalDelegatedStake + totalValidatorsStake; + const restOfTokenHoldings = IOTA_SUPPLY - totalStake; + if (restOfTokenHoldings < 0) { + throw new Error('Pools must have (collectively) at most iotaSupply tokens'); + } + + // Calculates profit margin of the epoch (only when there are tokens stake, otherwise, it's set to None) + let profitMargin: number | null; + if (totalStake > 0) { + profitMargin = totalValidatorsStake / (totalValidatorsStake + totalStake); + } else { + profitMargin = null; + } + + // Calculates the total rewards for each pool, already discounting the validator fixed cost + const poolRewards: number[] = new Array(lockedStake.length).fill(0); + if (totalStake > 0) { + if (totalValidatorsStake > 0) { + for (let i = 0; i < lockedStake.length; i++) { + poolRewards[i] = + ((lockedStake[i] + delegatedStake[i]) / totalStake + + lockedStake[i] / totalValidatorsStake) * + targetReward(epoch) * + (performance[i] / 2.0) - + fixedCosts[i]; + } + } else { + for (let i = 0; i < lockedStake.length; i++) { + poolRewards[i] = + ((lockedStake[i] + delegatedStake[i]) / totalStake) * + targetReward(epoch) * + (performance[i] / 2.0) - + fixedCosts[i]; + } + } + } + + // Calculates the rewards for each validator + const validatorRewards: number[] = new Array(lockedStake.length).fill(0); + for (let i = 0; i < lockedStake.length; i++) { + if (poolRewards[i] < 0) { + validatorRewards[i] = 0; + poolRewards[i] = 0; + } else if (poolRewards[i] === 0) { + validatorRewards[i] = fixedCosts[i]; + } else { + validatorRewards[i] = + fixedCosts[i] + + poolRewards[i] * profitMargin + + ((1 - profitMargin) * poolRewards[i] * lockedStake[i]) / + (delegatedStake[i] + lockedStake[i]); + } + } + + const delegatorRewards: number[] = new Array(lockedStake.length).fill(0); + for (let i = 0; i < lockedStake.length; i++) { + if (poolRewards[i] > 0) { + delegatorRewards[i] = + (poolRewards[i] * (1 - profitMargin) * delegatedStake[i]) / + (delegatedStake[i] + lockedStake[i]); + } + } + + let rewards = 0; + if (yourRole === 'Delegator') { + if (delegatorRewards[yourPool] > 0) { + rewards = (delegatorRewards[yourPool] * stake) / delegatedStake[yourPool]; + } + } + + if (yourRole === 'Validator') { + rewards = validatorRewards[lockedStake.length - 1]; + } + + return rewards; +} + +export function calculatePassiveRewards(tokens: number, epoch): number { + return potential_Mana( + tokens, + first_slot_of_epoch(epoch) - 1, + first_slot_of_epoch(epoch + 1) - 1, + GENERATION_PER_SLOT, + ); +} + +export function calculateTPS(mana: number, congestion: number): number { + return mana / congestion / EPOCH_DURATION; +} diff --git a/src/components/ManaCalculator/index.tsx b/src/components/ManaCalculator/index.tsx new file mode 100644 index 00000000000..50ba34faa6a --- /dev/null +++ b/src/components/ManaCalculator/index.tsx @@ -0,0 +1,349 @@ +import React, { useState } from 'react'; +import Select from 'react-select'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import { + calculateManaGeneratedPerEpoch, + calculatePassiveRewards, + calculateTPS, +} from './calculator'; +import { + UserType, + ValidatorProps, + DeleteValidatorEvent, + ChangeValidatorEvent, + ChangeEvent, + ChangeCongestionEvent, + CongestionType, + ManaCalculatorProps, +} from './types'; + +function ValidatorCard({ + validator, + handleDelete, + handleStakeChange, + handleDelegatedStakeChange, + handlePFChange, + handleFCChange, + id, +}: { + validator: ValidatorProps; + handleDelete: DeleteValidatorEvent; + handleStakeChange: ChangeValidatorEvent; + handleDelegatedStakeChange: ChangeValidatorEvent; + handlePFChange: ChangeValidatorEvent; + handleFCChange: ChangeValidatorEvent; + id: number; +}) { + return ( +
+
+
+
Validator {id + 1}
+ +
+
+
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+
+ ); +} + +export default function ManaCalculator() { + const [state, setState] = useState({ + validators: [ + { + lockedStake: 100, + delegatedStake: 0, + performanceFactor: 1.0, + fixedCost: 0.0, + }, + { + lockedStake: 100, + delegatedStake: 0, + performanceFactor: 1.0, + fixedCost: 0.0, + }, + { + lockedStake: 100, + delegatedStake: 0, + performanceFactor: 1.0, + fixedCost: 0.0, + }, + ], + userType: UserType.DELEGATOR, + congestion: CongestionType.LOW, + stake: 100, + delegator: { + validator: 0, + }, + } as ManaCalculatorProps); + + function handleDelete(id: number) { + const validators = state.validators.filter((_, i) => i !== id); + setState({ ...state, validators }); + } + + function handleStakeChange(value: number, id: number) { + setState({ + ...state, + validators: state.validators.map((validator, i) => { + return { + ...validator, + lockedStake: i === id ? value : validator.lockedStake, + }; + }), + }); + } + + function handleDelegatedStakeChange(value: number, id: number) { + setState({ + ...state, + validators: state.validators.map((validator, i) => { + return { + ...validator, + delegatedStake: i === id ? value : validator.delegatedStake, + }; + }), + }); + } + + function handlePFChange(value: number, id: number) { + setState({ + ...state, + validators: state.validators.map((validator, i) => { + return { + ...validator, + performanceFactor: i === id ? value : validator.performanceFactor, + }; + }), + }); + } + + function handleFCChange(value: number, id: number) { + setState({ + ...state, + validators: state.validators.map((validator, i) => { + return { + ...validator, + fixedCost: i === id ? value : validator.fixedCost, + }; + }), + }); + } + + function handleOwnStakeChange(value: number) { + setState({ + ...state, + stake: value, + }); + } + + function handleValidatorChange(value: number) { + setState({ + ...state, + delegator: { ...state.delegator, validator: value }, + }); + } + + function handleCongestionChange(value: CongestionType) { + setState({ + ...state, + congestion: value, + }); + } + + const epoch = 1154 + 1; + const manaGeneratedPerEpoch = calculateManaGeneratedPerEpoch( + state.stake, + state.delegator.validator, + null, + state.validators, + epoch, + 'Delegator', + ); + const passiveRewards = calculatePassiveRewards(state.stake, epoch); + + const grantedTPS = calculateTPS(manaGeneratedPerEpoch, state.congestion); + const additionalTPS = calculateTPS(passiveRewards, state.congestion); + const totalTPS = grantedTPS + additionalTPS; + + return ( + + +
+ {state.validators.map((validator, i) => ( +
+ +
+ ))} +
+
+
You are a:
+
+ + + + + + + + + +
+ +
Mana
+
+
+ ); +} + +function DelegatorForm({ + stake, + validators, + handleOwnStakeChange, + handleValidatorChange, +}: { + stake: number; + validators: ValidatorProps[]; + handleOwnStakeChange: ChangeEvent; + handleValidatorChange: ChangeEvent; +}) { + // Create options for validator select from validators array + const validatorOptions = validators.map((_, i) => { + return { value: i, label: `Validator ${i + 1}` }; + }); + + return ( +
+
+
Validator you delegate to:
+ handleOwnStakeChange(Number(e.target.value))} + > +
+
+ ); +} + +function ValidatorForm() { + return
Validator
; +} + +function OutputForm({ + manaGeneratedPerEpoch, + passiveRewards, + totalTPS, + handleCongestionChange, +}: { + manaGeneratedPerEpoch: number; + passiveRewards: number; + totalTPS: number; + handleCongestionChange: ChangeCongestionEvent; +}) { + return ( +
+
+
Mana generation per epoch:
+
{manaGeneratedPerEpoch}
+
+
+
Additional rewards per epoch:
+
{passiveRewards}
+
+
+
Total TPS granted with
+ handleOwnStakeChange(Number(e.target.value))} + > +
+
+ + handleOwnPFChange(Number(e.target.value))} + > +
+
+ + handleOwnFCChange(Number(e.target.value))} + > +
+
+ + + handleShareOfYourStakeLockedChange(Number(e.target.value)) + } + > +
+
+ + + handleAttractedNewDelegatedStakeChange(Number(e.target.value)) + } + > +
+
+ + + handleAttractedDelegatedStakeFromOtherPoolsChange( + Number(e.target.value), + ) + } + > +
+
+ ); } function OutputForm({ diff --git a/src/components/ManaCalculator/types.ts b/src/components/ManaCalculator/types.ts index a0f1d142b12..cbe01d7503a 100644 --- a/src/components/ManaCalculator/types.ts +++ b/src/components/ManaCalculator/types.ts @@ -11,12 +11,12 @@ export interface ValidatorProps { fixedCost: number; } -export interface ValiatorParameters { +export interface ValidatorParameters { shareOfYourStakeLocked: number; attractedNewDelegatedStake: number; attractedDelegatedStakeFromOtherPools: number; - yourFixedCost: number; - yourPerformance: number; + fixedCost: number; + performanceFactor: number; } export enum UserType { @@ -31,6 +31,13 @@ export interface ManaCalculatorProps { delegator: { validator: number; }; + validator: { + shareOfYourStakeLocked: number; + attractedNewDelegatedStake: number; + attractedDelegatedStakeFromOtherPools: number; + fixedCost: number; + performanceFactor: number; + }; stake: number; } From 55edaa68177a6a33a8636054436ec1ed82af96f0 Mon Sep 17 00:00:00 2001 From: Dr-Electron Date: Sun, 27 Aug 2023 23:17:36 +0200 Subject: [PATCH 03/40] Add accumulation tab --- src/components/ManaCalculator/calculator.ts | 40 ++- src/components/ManaCalculator/index.tsx | 268 +++++++++++++++++--- src/components/ManaCalculator/types.ts | 3 + src/components/ManaCalculator/utils.ts | 2 +- 4 files changed, 259 insertions(+), 54 deletions(-) diff --git a/src/components/ManaCalculator/calculator.ts b/src/components/ManaCalculator/calculator.ts index 5380e9e0205..1baf7e86cc1 100644 --- a/src/components/ManaCalculator/calculator.ts +++ b/src/components/ManaCalculator/calculator.ts @@ -5,18 +5,30 @@ import { IOTA_SUPPLY, targetReward, EPOCH_DURATION, + decay, } from './utils'; import { ValidatorParameters, ValidatorProps } from './types'; -export function calculateManaGeneratedPerEpoch( +export function calculateManaRewards( stake: number, yourPool: number, validatorParameters: ValidatorParameters, validators: ValidatorProps[], - epoch: number, + initialEpoch: number, + finalEpoch: number, yourRole: 'Validator' | 'Delegator', ): number { - // Initialies lockedStake array with the stake of each validator + let totalTargetReward = 0; + let epochDiff = 1; + if (finalEpoch) { + for (let i = 0; i < epochDiff; i++) { + totalTargetReward += decay(targetReward(initialEpoch + i), epochDiff - i); + } + } else { + finalEpoch = initialEpoch + 1; + totalTargetReward = targetReward(initialEpoch); + } + const lockedStake: number[] = validators.map( (validator) => validator.lockedStake, ); @@ -74,17 +86,17 @@ export function calculateManaGeneratedPerEpoch( poolRewards[i] = ((lockedStake[i] + delegatedStake[i]) / totalStake + lockedStake[i] / totalValidatorsStake) * - targetReward(epoch) * + totalTargetReward * (performance[i] / 2.0) - - fixedCosts[i]; + epochDiff * fixedCosts[i]; } } else { for (let i = 0; i < lockedStake.length; i++) { poolRewards[i] = ((lockedStake[i] + delegatedStake[i]) / totalStake) * - targetReward(epoch) * + totalTargetReward * (performance[i] / 2.0) - - fixedCosts[i]; + epochDiff * fixedCosts[i]; } } } @@ -96,10 +108,10 @@ export function calculateManaGeneratedPerEpoch( validatorRewards[i] = 0; poolRewards[i] = 0; } else if (poolRewards[i] === 0) { - validatorRewards[i] = fixedCosts[i]; + validatorRewards[i] = epochDiff * fixedCosts[i]; } else { validatorRewards[i] = - fixedCosts[i] + + epochDiff * fixedCosts[i] + poolRewards[i] * profitMargin + ((1 - profitMargin) * poolRewards[i] * lockedStake[i]) / (delegatedStake[i] + lockedStake[i]); @@ -129,11 +141,15 @@ export function calculateManaGeneratedPerEpoch( return rewards; } -export function calculatePassiveRewards(tokens: number, epoch): number { +export function calculatePassiveRewards( + tokens: number, + initialEpoch: number, + finalEpoch: number, +): number { return potential_Mana( tokens, - first_slot_of_epoch(epoch) - 1, - first_slot_of_epoch(epoch + 1) - 1, + first_slot_of_epoch(initialEpoch) - 1, + first_slot_of_epoch(finalEpoch) - 1, GENERATION_PER_SLOT, ); } diff --git a/src/components/ManaCalculator/index.tsx b/src/components/ManaCalculator/index.tsx index 163cdedf21a..3c0c7fc51aa 100644 --- a/src/components/ManaCalculator/index.tsx +++ b/src/components/ManaCalculator/index.tsx @@ -3,7 +3,7 @@ import Select from 'react-select'; import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; import { - calculateManaGeneratedPerEpoch, + calculateManaRewards, calculatePassiveRewards, calculateTPS, } from './calculator'; @@ -98,6 +98,9 @@ function ValidatorCard({ export default function ManaCalculator() { const [state, setState] = useState({ + epoch: 1154 + 1, + initialEpoch: 0, + finalEpoch: 100, validators: [ { lockedStake: 100, @@ -245,54 +248,158 @@ export default function ManaCalculator() { }); } - const epoch = 1154 + 1; - let manaGeneratedPerEpoch = calculateManaGeneratedPerEpoch( - state.stake, - state.delegator.validator, - null, - state.validators, - epoch, - 'Delegator', - ); - let passiveRewards = calculatePassiveRewards(state.stake, epoch); + function handleEpochChange(value: number) { + setState({ + ...state, + epoch: value, + }); + } + + function handleInitialEpochChange(value: number) { + setState({ + ...state, + initialEpoch: value, + }); + } - let grantedTPS = calculateTPS(manaGeneratedPerEpoch, state.congestion); - let additionalTPS = calculateTPS(passiveRewards, state.congestion); - let totalTPS = grantedTPS + additionalTPS; + function handleFinalEpochChange(value: number) { + setState({ + ...state, + finalEpoch: value, + }); + } - const delegatorResults = { - manaGeneratedPerEpoch: manaGeneratedPerEpoch, - passiveRewards: passiveRewards, - totalTPS: totalTPS, + // Calulate Mana rewards for delegator and validator + let delegatorResults = { + manaGeneratedPerEpoch: 0, + passiveRewards: 0, + totalTPS: 0, + }; + let validatorResults = { + manaGeneratedPerEpoch: 0, + passiveRewards: 0, + totalTPS: 0, }; + { + let manaGeneratedPerEpoch = calculateManaRewards( + state.stake, + state.delegator.validator, + null, + state.validators, + state.epoch, + null, + 'Delegator', + ); + let passiveRewards = calculatePassiveRewards( + state.stake, + state.epoch, + state.epoch + 1, + ); - manaGeneratedPerEpoch = calculateManaGeneratedPerEpoch( - state.stake, - state.delegator.validator, - { - performanceFactor: state.validator.performanceFactor, - fixedCost: state.validator.fixedCost, - shareOfYourStakeLocked: state.validator.shareOfYourStakeLocked, - attractedNewDelegatedStake: state.validator.attractedNewDelegatedStake, - attractedDelegatedStakeFromOtherPools: - state.validator.attractedDelegatedStakeFromOtherPools, - } as ValidatorParameters, - state.validators, - epoch, - 'Validator', - ); - grantedTPS = calculateTPS(manaGeneratedPerEpoch, state.congestion); - totalTPS = grantedTPS + additionalTPS; + let grantedTPS = calculateTPS(manaGeneratedPerEpoch, state.congestion); + let additionalTPS = calculateTPS(passiveRewards, state.congestion); + let totalTPS = grantedTPS + additionalTPS; + + delegatorResults = { + manaGeneratedPerEpoch: manaGeneratedPerEpoch, + passiveRewards: passiveRewards, + totalTPS: totalTPS, + }; + + manaGeneratedPerEpoch = calculateManaRewards( + state.stake, + state.delegator.validator, + { + performanceFactor: state.validator.performanceFactor, + fixedCost: state.validator.fixedCost, + shareOfYourStakeLocked: state.validator.shareOfYourStakeLocked, + attractedNewDelegatedStake: state.validator.attractedNewDelegatedStake, + attractedDelegatedStakeFromOtherPools: + state.validator.attractedDelegatedStakeFromOtherPools, + } as ValidatorParameters, + state.validators, + state.epoch, + null, + 'Validator', + ); + grantedTPS = calculateTPS(manaGeneratedPerEpoch, state.congestion); + totalTPS = grantedTPS + additionalTPS; + + validatorResults.manaGeneratedPerEpoch = manaGeneratedPerEpoch; + validatorResults.passiveRewards = passiveRewards; + validatorResults.totalTPS = totalTPS; + } - const validatorResults = { - manaGeneratedPerEpoch: manaGeneratedPerEpoch, - passiveRewards: passiveRewards, - totalTPS: totalTPS, + // Calulate Mana rewards for delegator and validator + let delegatorAccumulateResults = { + manaGenerated: 0, + passiveRewards: 0, + totalTPS: 0, }; + let validatorAccumulateResults = { + manaGenerated: 0, + passiveRewards: 0, + totalTPS: 0, + }; + { + let manaGenerated = calculateManaRewards( + state.stake, + state.delegator.validator, + null, + state.validators, + state.initialEpoch, + state.finalEpoch, + 'Delegator', + ); + let passiveRewards = calculatePassiveRewards( + state.stake, + state.initialEpoch, + state.finalEpoch, + ); + + let grantedTPS = calculateTPS(manaGenerated, state.congestion); + let additionalTPS = calculateTPS(passiveRewards, state.congestion); + let totalTPS = grantedTPS + additionalTPS; + + delegatorAccumulateResults.manaGenerated = manaGenerated; + delegatorAccumulateResults.passiveRewards = passiveRewards; + delegatorAccumulateResults.totalTPS = totalTPS; + + manaGenerated = calculateManaRewards( + state.stake, + state.delegator.validator, + { + performanceFactor: state.validator.performanceFactor, + fixedCost: state.validator.fixedCost, + shareOfYourStakeLocked: state.validator.shareOfYourStakeLocked, + attractedNewDelegatedStake: state.validator.attractedNewDelegatedStake, + attractedDelegatedStakeFromOtherPools: + state.validator.attractedDelegatedStakeFromOtherPools, + } as ValidatorParameters, + state.validators, + state.initialEpoch, + state.finalEpoch, + 'Validator', + ); + grantedTPS = calculateTPS(manaGenerated, state.congestion); + totalTPS = grantedTPS + additionalTPS; + + validatorAccumulateResults.manaGenerated = manaGenerated; + validatorAccumulateResults.passiveRewards = passiveRewards; + validatorAccumulateResults.totalTPS = totalTPS; + } return ( +
+ + handleEpochChange(Number(e.target.value))} + > +
{state.validators.map((validator, i) => (
@@ -360,8 +467,87 @@ export default function ManaCalculator() { - -
Mana
+ +
+ + handleInitialEpochChange(Number(e.target.value))} + > + + handleFinalEpochChange(Number(e.target.value))} + > +
+
+ {state.validators.map((validator, i) => ( +
+ +
+ ))} +
+
+
You are a:
+
+ + + + + + + + + +
); diff --git a/src/components/ManaCalculator/types.ts b/src/components/ManaCalculator/types.ts index cbe01d7503a..efbdb4dde41 100644 --- a/src/components/ManaCalculator/types.ts +++ b/src/components/ManaCalculator/types.ts @@ -25,6 +25,9 @@ export enum UserType { } export interface ManaCalculatorProps { + epoch: number; + initialEpoch: number; + finalEpoch: number; validators: ValidatorProps[]; userType: UserType; congestion: CongestionType; diff --git a/src/components/ManaCalculator/utils.ts b/src/components/ManaCalculator/utils.ts index cfa41f75b49..4906bd9f183 100644 --- a/src/components/ManaCalculator/utils.ts +++ b/src/components/ManaCalculator/utils.ts @@ -38,7 +38,7 @@ export function first_slot_of_epoch(n: number): number { } // returns the decayed value of value by n epochs -function decay(value: number, n: number): number { +export function decay(value: number, n: number): number { if (value != 0 && n != 0) { const decay = Math.exp(-BETA_PER_YEAR * EPOCH_DURATION_IN_YEARS * n); value = Math.floor(value * decay); From 9888b67eee3989994fd410f1959fcb3ed901572c Mon Sep 17 00:00:00 2001 From: Dr-Electron Date: Sun, 3 Sep 2023 20:22:10 +0200 Subject: [PATCH 04/40] Fix react-select styling --- src/components/ManaCalculator/index.tsx | 2 ++ src/components/TutorialFilters/styles.css | 35 ----------------------- src/css/custom.css | 35 +++++++++++++++++++++++ 3 files changed, 37 insertions(+), 35 deletions(-) diff --git a/src/components/ManaCalculator/index.tsx b/src/components/ManaCalculator/index.tsx index 3c0c7fc51aa..6f03b3a3774 100644 --- a/src/components/ManaCalculator/index.tsx +++ b/src/components/ManaCalculator/index.tsx @@ -579,6 +579,7 @@ function DelegatorForm({ handleValidatorChange(e.value); }} className='col col--4' + classNamePrefix='react-select' options={validatorOptions} />
@@ -710,6 +711,7 @@ function OutputForm({
Total TPS granted with
handleStakeChange(Number(e.target.value), id)} - > - -
-
- -
+
+ + handleStakeChange(Number(e.target.value), id)} + >
-
-
- -
-
- -
+
+ + + handleDelegatedStakeChange(Number(e.target.value), id) + } + > +
+
+ + handlePFChange(Number(e.target.value), id)} + > +
+
+ + handleFCChange(Number(e.target.value), id)} + >
); @@ -393,13 +384,15 @@ export default function ManaCalculator() { return ( -
- - handleEpochChange(Number(e.target.value))} - > +
+
+ + handleEpochChange(Number(e.target.value))} + > +
@@ -417,6 +410,8 @@ export default function ManaCalculator() { />
))} +
+
-
-
- - handleStakeChange(Number(e.target.value), id)} - > -
-
- - - handleDelegatedStakeChange(Number(e.target.value), id) - } - > -
-
- - handlePFChange(Number(e.target.value), id)} - > -
-
- - handleFCChange(Number(e.target.value), id)} - > +
+
+
+
Validator {id + 1}
+ + +
+
+
Stake:
+ handleStakeChange(Number(e.target.value), id)} + > +
+
+
Delegated:
+ + handleDelegatedStakeChange(Number(e.target.value), id) + } + > +
+
+
PF:
+ handlePFChange(Number(e.target.value), id)} + > +
+
+
FC:
+ handleFCChange(Number(e.target.value), id)} + > +
); @@ -393,27 +395,24 @@ export default function ManaCalculator() { onChange={(e) => handleEpochChange(Number(e.target.value))} >
- -
{state.validators.map((validator, i) => ( -
- -
+ ))}
+
+
+ {state.validators.map((validator, i) => ( + + ))} +
+
+ +
+
-
-
- {state.validators.map((validator, i) => ( - - ))} -
-
- -
-
You are a:
diff --git a/src/components/ManaCalculator/styles.css b/src/components/ManaCalculator/styles.css index 8ba719cd540..2ea9006c6ef 100644 --- a/src/components/ManaCalculator/styles.css +++ b/src/components/ManaCalculator/styles.css @@ -1,15 +1,8 @@ -.mana_card { - padding: 1em; - margin: 0 0.3em 0.3em 0; - text-align: left; - align-items: stretch; +.mana--card { + box-sizing: border-box; } -.mana_card > .row { - padding: 0.3em; -} - .row > .button { - margin: 0 var(--ifm-spacing-horizontal); + margin: 0; } .table .row { @@ -18,10 +11,15 @@ } .table .row .col { - padding: 6px; + box-sizing: border-box; +} + +.table .row .add-button { + margin: 0 calc(50% - var(--ifm-navbar-padding-horizontal)); } .table .row .col--4:nth-child(1), +.table .row .col--8:nth-child(1), .table .row .col--4:nth-child(2), .table .row .col--6:nth-child(1) { border-right: var(--ifm-table-border-width) solid From 8ecf3aae0968fcab977ac1ef97d133c30479ae7e Mon Sep 17 00:00:00 2001 From: Dr-Electron Date: Sun, 15 Oct 2023 20:39:21 +0200 Subject: [PATCH 09/40] Remove 'epoch' in TPS tab --- src/components/ManaCalculator/index.tsx | 27 ++++--------------------- src/components/ManaCalculator/utils.ts | 1 + 2 files changed, 5 insertions(+), 23 deletions(-) diff --git a/src/components/ManaCalculator/index.tsx b/src/components/ManaCalculator/index.tsx index 3c8c1d0fb2c..57cc5d5af5d 100644 --- a/src/components/ManaCalculator/index.tsx +++ b/src/components/ManaCalculator/index.tsx @@ -20,6 +20,7 @@ import { ValidatorParameters, } from './types'; import { Details } from '@docusaurus/theme-common/Details'; +import { EPOCH } from './utils'; function ValidatorCard({ validator, @@ -92,7 +93,6 @@ function ValidatorCard({ export default function ManaCalculator() { const [state, setState] = useState({ - epoch: 1154 + 1, initialEpoch: 0, finalEpoch: 100, validators: [ @@ -242,13 +242,6 @@ export default function ManaCalculator() { }); } - function handleEpochChange(value: number) { - setState({ - ...state, - epoch: value, - }); - } - function handleInitialEpochChange(value: number) { setState({ ...state, @@ -280,15 +273,11 @@ export default function ManaCalculator() { state.delegator.validator, null, state.validators, - state.epoch, + EPOCH, null, 'Delegator', ); - let passiveRewards = calculatePassiveRewards( - state.stake, - state.epoch, - state.epoch + 1, - ); + let passiveRewards = calculatePassiveRewards(state.stake, EPOCH, EPOCH + 1); let grantedTPS = calculateTPS(manaGeneratedPerEpoch, state.congestion); let additionalTPS = calculateTPS(passiveRewards, state.congestion); @@ -312,7 +301,7 @@ export default function ManaCalculator() { state.validator.attractedDelegatedStakeFromOtherPools, } as ValidatorParameters, state.validators, - state.epoch, + EPOCH, null, 'Validator', ); @@ -387,14 +376,6 @@ export default function ManaCalculator() {
-
- - handleEpochChange(Number(e.target.value))} - > -
{state.validators.map((validator, i) => ( diff --git a/src/components/ManaCalculator/utils.ts b/src/components/ManaCalculator/utils.ts index 4906bd9f183..47b916629e0 100644 --- a/src/components/ManaCalculator/utils.ts +++ b/src/components/ManaCalculator/utils.ts @@ -12,6 +12,7 @@ const REWARDS_MANA_SHARE_COEFFICIENT = 2; export const RMC_LOW_CONGESTION = 100000; export const RMC_STABLE_CONGESTION = 9000000; export const RMC_EXTREME_CONGESTION = 500000000; +export const EPOCH = 1154 + 1; // given t in seconds, returns the slot that time t belongs to function time_to_slot(t: number): number { From afae7a1ea58ebf5f3c11d20ee7191f1d61035efe Mon Sep 17 00:00:00 2001 From: Dr-Electron Date: Sun, 15 Oct 2023 20:53:54 +0200 Subject: [PATCH 10/40] Move the advanced setting to a less obvious place --- src/components/ManaCalculator/index.tsx | 339 +++++++++++------------- 1 file changed, 155 insertions(+), 184 deletions(-) diff --git a/src/components/ManaCalculator/index.tsx b/src/components/ManaCalculator/index.tsx index 57cc5d5af5d..6818d86a5a0 100644 --- a/src/components/ManaCalculator/index.tsx +++ b/src/components/ManaCalculator/index.tsx @@ -373,197 +373,168 @@ export default function ManaCalculator() { } return ( - - -
-
-
- {state.validators.map((validator, i) => ( - - ))} -
-
- -
-
-
-
-
You are a:
-
- - - - - - - - - - -
- -
+
+ + +
- - handleInitialEpochChange(Number(e.target.value))} - > - - handleFinalEpochChange(Number(e.target.value))} - > +
You are a:
-
+ + + + + + + + + + + + +
- {state.validators.map((validator, i) => ( - - ))} + + + handleInitialEpochChange(Number(e.target.value)) + } + > + + handleFinalEpochChange(Number(e.target.value))} + >
-
- -
-
-
+
+
+
You are a:
+
+ + + + + + + + + + +
+
+
-
You are a:
-
- - - - ( + - - - - - - - - + ))} +
+
+ +
+
+
); } From 3a4be25380674ab070972fa0709d8e6219692b09 Mon Sep 17 00:00:00 2001 From: Dr-Electron Date: Sun, 15 Oct 2023 21:00:35 +0200 Subject: [PATCH 11/40] =?UTF-8?q?Hide=20some=20of=20the=20validator?= =?UTF-8?q?=E2=80=99s=20settings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ManaCalculator/index.tsx | 100 ++++++++++++------------ 1 file changed, 51 insertions(+), 49 deletions(-) diff --git a/src/components/ManaCalculator/index.tsx b/src/components/ManaCalculator/index.tsx index 6818d86a5a0..18e7b18f7f4 100644 --- a/src/components/ManaCalculator/index.tsx +++ b/src/components/ManaCalculator/index.tsx @@ -621,59 +621,61 @@ function ValidatorForm({ onChange={(e) => handleOwnStakeChange(Number(e.target.value))} > -
-
Performance factor:
- handleOwnPFChange(Number(e.target.value))} - > -
+
+
+
Performance factor:
+ handleOwnPFChange(Number(e.target.value))} + > +
-
-
Fixed costs:
+
+
Fixed costs:
- handleOwnFCChange(Number(e.target.value))} - > -
-
-
Share of your stake locked:
- - handleShareOfYourStakeLockedChange(Number(e.target.value)) - } - > -
-
-
Attracted new delegated stake:
- - handleAttractedNewDelegatedStakeChange(Number(e.target.value)) - } - > -
-
-
- Attracted delegated stake from other pools: + handleOwnFCChange(Number(e.target.value))} + > +
+
+
Share of your stake locked:
+ + handleShareOfYourStakeLockedChange(Number(e.target.value)) + } + > +
+
+
Attracted new delegated stake:
+ + handleAttractedNewDelegatedStakeChange(Number(e.target.value)) + } + >
+
+
+ Attracted delegated stake from other pools: +
- - handleAttractedDelegatedStakeFromOtherPoolsChange( - Number(e.target.value), - ) - } - > -
+ + handleAttractedDelegatedStakeFromOtherPoolsChange( + Number(e.target.value), + ) + } + > +
+
); } From b3d5d4d6a08d116d084c1ff35c2d4adc10fbac9b Mon Sep 17 00:00:00 2001 From: Dr-Electron Date: Sun, 15 Oct 2023 21:23:09 +0200 Subject: [PATCH 12/40] Make needed inputs numbers --- src/components/ManaCalculator/index.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/components/ManaCalculator/index.tsx b/src/components/ManaCalculator/index.tsx index 18e7b18f7f4..78b8158e3d8 100644 --- a/src/components/ManaCalculator/index.tsx +++ b/src/components/ManaCalculator/index.tsx @@ -74,6 +74,8 @@ function ValidatorCard({
PF:
handlePFChange(Number(e.target.value), id)} > @@ -82,6 +84,8 @@ function ValidatorCard({
FC:
handleFCChange(Number(e.target.value), id)} > @@ -626,6 +630,8 @@ function ValidatorForm({
Performance factor:
handleOwnPFChange(Number(e.target.value))} > @@ -633,9 +639,10 @@ function ValidatorForm({
Fixed costs:
- handleOwnFCChange(Number(e.target.value))} > From 302bad614d02e2287f2efddd41f7eaf79b90d416 Mon Sep 17 00:00:00 2001 From: Dr-Electron Date: Mon, 16 Oct 2023 11:56:29 +0200 Subject: [PATCH 13/40] Swap 'passiveRewards' and 'manaGeneratedPerEpoch' --- src/components/ManaCalculator/index.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/ManaCalculator/index.tsx b/src/components/ManaCalculator/index.tsx index 78b8158e3d8..16717a5bab0 100644 --- a/src/components/ManaCalculator/index.tsx +++ b/src/components/ManaCalculator/index.tsx @@ -701,12 +701,12 @@ function OutputForm({ return (
-
Mana generation per epoch
-
{manaGeneratedPerEpoch}
+
Mana generation (holding IOTA)
+
{passiveRewards}
-
Additional rewards per epoch
-
{passiveRewards}
+
Mana rewards (delegation/validation)
+
{manaGeneratedPerEpoch}
From eaa86c2c67455e4fde3aa7780654355f182d0f11 Mon Sep 17 00:00:00 2001 From: Dr-Electron Date: Mon, 16 Oct 2023 14:44:38 +0200 Subject: [PATCH 14/40] Don't use micro --- src/components/ManaCalculator/index.tsx | 37 ++++++++++++------------- src/components/ManaCalculator/utils.ts | 10 +++++++ 2 files changed, 28 insertions(+), 19 deletions(-) diff --git a/src/components/ManaCalculator/index.tsx b/src/components/ManaCalculator/index.tsx index 16717a5bab0..59cff7f9438 100644 --- a/src/components/ManaCalculator/index.tsx +++ b/src/components/ManaCalculator/index.tsx @@ -20,7 +20,7 @@ import { ValidatorParameters, } from './types'; import { Details } from '@docusaurus/theme-common/Details'; -import { EPOCH } from './utils'; +import { EPOCH, fromMicro, toMicro } from './utils'; function ValidatorCard({ validator, @@ -56,17 +56,17 @@ function ValidatorCard({
Stake:
handleStakeChange(Number(e.target.value), id)} + value={fromMicro(validator.lockedStake)} + onChange={(e) => handleStakeChange(toMicro(Number(e.target.value)), id)} >
Delegated:
- handleDelegatedStakeChange(Number(e.target.value), id) + handleDelegatedStakeChange(toMicro(Number(e.target.value)), id) } >
@@ -101,27 +101,27 @@ export default function ManaCalculator() { finalEpoch: 100, validators: [ { - lockedStake: 100, - delegatedStake: 0, + lockedStake: toMicro(100), + delegatedStake: toMicro(0), performanceFactor: 1.0, fixedCost: 0.0, }, { - lockedStake: 100, - delegatedStake: 0, + lockedStake: toMicro(100), + delegatedStake: toMicro(0), performanceFactor: 1.0, fixedCost: 0.0, }, { - lockedStake: 100, - delegatedStake: 0, + lockedStake: toMicro(100), + delegatedStake: toMicro(0), performanceFactor: 1.0, fixedCost: 0.0, }, ], userType: UserType.DELEGATOR, congestion: CongestionType.LOW, - stake: 100, + stake: toMicro(100), delegator: { validator: 0, }, @@ -579,8 +579,8 @@ function DelegatorForm({
Amount you delegate:
handleOwnStakeChange(Number(e.target.value))} + value={fromMicro(stake)} + onChange={(e) => handleOwnStakeChange(toMicro(Number(e.target.value)))} >
@@ -618,11 +618,10 @@ function ValidatorForm({
Stake:
- handleOwnStakeChange(Number(e.target.value))} + value={fromMicro(stake)} + onChange={(e) => handleOwnStakeChange(toMicro(Number(e.target.value)))} >
@@ -702,11 +701,11 @@ function OutputForm({
Mana generation (holding IOTA)
-
{passiveRewards}
+
{fromMicro(passiveRewards)}
Mana rewards (delegation/validation)
-
{manaGeneratedPerEpoch}
+
{fromMicro(manaGeneratedPerEpoch)}
diff --git a/src/components/ManaCalculator/utils.ts b/src/components/ManaCalculator/utils.ts index 47b916629e0..1c0106e8f5c 100644 --- a/src/components/ManaCalculator/utils.ts +++ b/src/components/ManaCalculator/utils.ts @@ -101,3 +101,13 @@ export function targetReward(n: number): number { } return reward; } + +//returns The number of Mana/IOTA from micros +export function fromMicro(n: number): number { + return n / 1_000_000; +} + +//returns The number of micro(Mana/IOTA). +export function toMicro(n: number): number { + return n * 1_000_000; +} From 5817c2d9ced85dd45a2ebeb4cf9f9df883c807a2 Mon Sep 17 00:00:00 2001 From: oliviasaa Date: Fri, 20 Oct 2023 14:30:51 +0100 Subject: [PATCH 15/40] add mana calc text --- .../iota2.0/core-concepts/mana-calculator.md | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 docs/learn/protocols/iota2.0/core-concepts/mana-calculator.md diff --git a/docs/learn/protocols/iota2.0/core-concepts/mana-calculator.md b/docs/learn/protocols/iota2.0/core-concepts/mana-calculator.md new file mode 100644 index 00000000000..52c37ba8ffa --- /dev/null +++ b/docs/learn/protocols/iota2.0/core-concepts/mana-calculator.md @@ -0,0 +1,40 @@ +import ManaCalculator from '@site/src/components/ManaCalculator'; + +# Mana Calculator + +Mana is a scarce resource used to access the IOTA ledger and update its state through block creation. It is a spendable asset tracked in the ledger state, powering smart contracts, DeFi applications, block creation, and various other services. Our incentives scheme allows you to stake or delegate mana to receive Mana rewards, in addition to the Mana generation your IOTA holdings grant you without having to participate in any consensus-related activity. + +In this article, we introduce the Mana Calculator: a tool to help you make decisions about the type of participation that will suit you the most, to help you predict the Mana generation you’ll be granted, and to decide the number of IOTA tokens you should hold to have a particular desired level of access guaranteed in the future. + +## How to use the Calculator: Step-by-step instructions + +- **Choose the network you want to estimate the Mana Generation:** this calculator works for both Shimmer and the future IOTA 2.0 network. Those two networks will have their own type of Mana (IOTA Mana and Shimmer Mana), with their own parameters and, consequently, their own behavior. Be sure you select the correct scenario you want to simulate! + +- **Choose your role:** are you going to delegate to a validator, be a validator yourself or just hold tokens? To be a validator, you must run a node and lock your tokens while you are performing such validation services, but this will give you higher rewards. If you wish to delegate to a validator, your tokens will not be locked and you won’t need to run a node, but this will give you less rewards than validating. Finally, just holding tokens grants you a certain Mana generation, but it will be less than the validating or delegating. + +- **Input the number of tokens you own:** no matter which network and role you choose, your Mana generation will depend on how many available tokens you have. Pay attention to the units! The input should be done in IOTA or Shimmer (not microIota or Glow). + +Now you are mostly done! With the inputs above, you can already estimate how much Mana you’ll be granted per epoch. But what does it mean in tps? How many blocks per second this Mana grants you? The answer to this question depends on the size of your block and the network congestion levels. However, we can use a default block size, which will be enough for most applications, and assume certain levels of congestion. This takes us to the very last step to be taken in this calculator: + +- **Choose a congestion level:** given a certain Mana generation per epoch, this can be translated into a number of blocks issued per seconds that depends on the congestion level. Choose one of the given congestion levels (low, stable, or extreme) to estimate how many blocks per second your tokens and participation grants you! This metric is also showed in a alternative way: time until block issuance, which tells you in which periodicity you’ll be able to issue a block. + + + + +## Advanced settings + +The steps shown above are enough to roughly estimate your Mana generation and granted tps; however, if you wish, you can play with the advanced settings to have more precise results. + +- **Change the state of the system:** the default settings assume a certain level of participation in the consensus (i.e., locked stake, delegated stake and performance factor of validators). Those settings can be changed unter the “Advanced settings - State of the System” tab. You can also add or delete validators and change their fixed costs. + +- If you choose to delegate: + - **Change the validator you delegate to:** by the default settings, you'll be delegating to Validator 1 (which is pool that, technically speaking, is under the "equilibrium state", see the WP for more details). However, you can change this setting and know your rewards if you participate in other pools, with different share of delegated to locked stake, and different performance factors. + +- If you choose to validate: + - **Change the amount of stake is delegated to you:** by the default settings of the calculator, you'll be assigned a certain share of the delegated stake automatically when you start validating. However, you can change this setting and know your rewards if you manage to atract more (or less) delegated stake than the default setting. + - **Change your performance factor:** by the default settings of the calculator, your performance factor is 0.95. However, you can change this to simulate larger or smaller shares of online time. + - **Change your fixed costs:** by the default settings of the calculator, your fixed costs are zero. This setting can be changed so you spare part of the pool rowards just for yourself. However, notice that the fixed cost is a public parameter, that you define during registration. This means that the delegator know how you set this value and might consider it when choosing a validator to delegate. Furthermore, is you set this value too high, you'll be punished and won't get rewards at all. + +- **Simulate your Mana accumulation**: the default setting of the calculator assumes a stationary regime and calculates the block creation rate you guarantee depending on your stake and level of participation. However, specially in the early stages of the network you might want to save your mana to sell later. This tab simulates how much Mana you will accumulate in a certain time period. For that (besides the other already defined inputs), you just need to choose a initial and final epochs, and the tool will plot a graph of your accumulation during that period. In the same graph, you can also have an idea of how many blocks can be issued with this accumulated amount of Mana, for the different congestion levels (already defined in the non-advanced settings). + + From 6fa6a7a5a6d6c5011e7903d63809fa6162eaf3ce Mon Sep 17 00:00:00 2001 From: Dr-Electron Date: Tue, 24 Oct 2023 11:13:54 +0200 Subject: [PATCH 16/40] Update src/components/ManaCalculator/utils.ts --- src/components/ManaCalculator/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ManaCalculator/utils.ts b/src/components/ManaCalculator/utils.ts index 1c0106e8f5c..df0cfb1bd87 100644 --- a/src/components/ManaCalculator/utils.ts +++ b/src/components/ManaCalculator/utils.ts @@ -1,5 +1,5 @@ // Constants -export const IOTA_SUPPLY = 4292657708000000; +export const IOTA_SUPPLY = 4600000000000000; const SLOT_DURATION = 10; const SLOTS_IN_EPOCH = 8192; export const EPOCH_DURATION = SLOTS_IN_EPOCH * SLOT_DURATION; From 5c6832c56c104dbaa604d99d05a8b043e0e8a8ec Mon Sep 17 00:00:00 2001 From: DafPhil <91533416+DafPhil@users.noreply.github.com> Date: Thu, 26 Oct 2023 16:13:32 +0200 Subject: [PATCH 17/40] Update mana-calculator.md (#1283) --- .../iota2.0/core-concepts/mana-calculator.md | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/learn/protocols/iota2.0/core-concepts/mana-calculator.md b/docs/learn/protocols/iota2.0/core-concepts/mana-calculator.md index 52c37ba8ffa..57e64d60890 100644 --- a/docs/learn/protocols/iota2.0/core-concepts/mana-calculator.md +++ b/docs/learn/protocols/iota2.0/core-concepts/mana-calculator.md @@ -2,39 +2,39 @@ import ManaCalculator from '@site/src/components/ManaCalculator'; # Mana Calculator -Mana is a scarce resource used to access the IOTA ledger and update its state through block creation. It is a spendable asset tracked in the ledger state, powering smart contracts, DeFi applications, block creation, and various other services. Our incentives scheme allows you to stake or delegate mana to receive Mana rewards, in addition to the Mana generation your IOTA holdings grant you without having to participate in any consensus-related activity. +Mana is a reward resource generated by holding IOTA tokens. It is utilized for block issuance, access to network throughput, protection against Sybil attacks, and various other services. Our incentives scheme allows you to stake or delegate Mana to receive Mana rewards, in addition to the Mana generated simply by holding your IOTA tokens, without having to participate in any consensus-related activity. -In this article, we introduce the Mana Calculator: a tool to help you make decisions about the type of participation that will suit you the most, to help you predict the Mana generation you’ll be granted, and to decide the number of IOTA tokens you should hold to have a particular desired level of access guaranteed in the future. +Here, we introduce the Mana Calculator: a tool to help you make decisions about the type of participation that will suit you best, to help you predict the Mana generation you’ll be granted, and to decide the number of IOTA tokens you should hold to guarantee your desired level of access in the future. ## How to use the Calculator: Step-by-step instructions -- **Choose the network you want to estimate the Mana Generation:** this calculator works for both Shimmer and the future IOTA 2.0 network. Those two networks will have their own type of Mana (IOTA Mana and Shimmer Mana), with their own parameters and, consequently, their own behavior. Be sure you select the correct scenario you want to simulate! +- **Choose your network:** This calculator works for both Shimmer and the future IOTA 2.0 network. Both networks will have their own type of Mana (IOTA Mana and Shimmer Mana), with their own parameters and, consequently, their own behavior. Be sure you select the correct scenario you want to simulate! -- **Choose your role:** are you going to delegate to a validator, be a validator yourself or just hold tokens? To be a validator, you must run a node and lock your tokens while you are performing such validation services, but this will give you higher rewards. If you wish to delegate to a validator, your tokens will not be locked and you won’t need to run a node, but this will give you less rewards than validating. Finally, just holding tokens grants you a certain Mana generation, but it will be less than the validating or delegating. +- **Choose your role:** Will you delegate to a validator, become a validator yourself, or just hold tokens? To be a validator, you must run a node and lock your tokens while performing validation services, which will give you higher rewards. If you want to delegate to a validator, your tokens will not be locked and you won’t need to run a node, but this will give you fewer rewards than validating. Finally, just holding tokens grants you a certain amount of Mana, which will be less than by validating or delegating. -- **Input the number of tokens you own:** no matter which network and role you choose, your Mana generation will depend on how many available tokens you have. Pay attention to the units! The input should be done in IOTA or Shimmer (not microIota or Glow). +- **Input the number of tokens you own:** No matter which network and role you choose, your Mana generation will depend on how many available tokens you have. Pay attention to the units! The input should be done in IOTA or Shimmer (not microIota or Glow). -Now you are mostly done! With the inputs above, you can already estimate how much Mana you’ll be granted per epoch. But what does it mean in tps? How many blocks per second this Mana grants you? The answer to this question depends on the size of your block and the network congestion levels. However, we can use a default block size, which will be enough for most applications, and assume certain levels of congestion. This takes us to the very last step to be taken in this calculator: +You're almost there! With the inputs above, you can already estimate how much Mana you’ll be granted per epoch. But what does it mean in TPS? How many blocks per second does your Mana grant you? The answer depends on the size of your block and the network congestion levels. However, we can use a default block size, which will be enough for most applications, and assume certain levels of congestion. This takes us to the last step in this calculator: -- **Choose a congestion level:** given a certain Mana generation per epoch, this can be translated into a number of blocks issued per seconds that depends on the congestion level. Choose one of the given congestion levels (low, stable, or extreme) to estimate how many blocks per second your tokens and participation grants you! This metric is also showed in a alternative way: time until block issuance, which tells you in which periodicity you’ll be able to issue a block. +- **Choose a congestion level:** Given a certain Mana generation per epoch, this can be translated into a number of blocks issued per second that depends on the congestion level. Choose one of the given congestion levels (low, stable, or extreme) to estimate how many blocks per second your tokens and participation grant you! This metric is also shown in another way: time until block issuance, which tells you in which periodicity you’ll be able to issue a block. ## Advanced settings -The steps shown above are enough to roughly estimate your Mana generation and granted tps; however, if you wish, you can play with the advanced settings to have more precise results. +The steps outlined above can give you a rough estimate of your Mana generation and granted TPS. However, playing with the advanced settings will give you more precise results. -- **Change the state of the system:** the default settings assume a certain level of participation in the consensus (i.e., locked stake, delegated stake and performance factor of validators). Those settings can be changed unter the “Advanced settings - State of the System” tab. You can also add or delete validators and change their fixed costs. +- **Change the state of the system:** The calculator's default settings assume a certain level of participation in the consensus (i.e., locked stake, delegated stake, and performance factor of validators). Those settings can be changed under the “Advanced Settings - State of the System” tab. You can also add or delete validators and change their fixed costs. - If you choose to delegate: - - **Change the validator you delegate to:** by the default settings, you'll be delegating to Validator 1 (which is pool that, technically speaking, is under the "equilibrium state", see the WP for more details). However, you can change this setting and know your rewards if you participate in other pools, with different share of delegated to locked stake, and different performance factors. + - **Change the validator you delegate to:** Under the default settings, you'll delegate to Validator 1 (which is pool that, technically speaking, is under the "equilibrium state", see the WP for more details). However, you can change this setting and know your rewards if you participate in other pools, with different share of delegated to locked stake, and different performance factors. - If you choose to validate: - - **Change the amount of stake is delegated to you:** by the default settings of the calculator, you'll be assigned a certain share of the delegated stake automatically when you start validating. However, you can change this setting and know your rewards if you manage to atract more (or less) delegated stake than the default setting. - - **Change your performance factor:** by the default settings of the calculator, your performance factor is 0.95. However, you can change this to simulate larger or smaller shares of online time. - - **Change your fixed costs:** by the default settings of the calculator, your fixed costs are zero. This setting can be changed so you spare part of the pool rowards just for yourself. However, notice that the fixed cost is a public parameter, that you define during registration. This means that the delegator know how you set this value and might consider it when choosing a validator to delegate. Furthermore, is you set this value too high, you'll be punished and won't get rewards at all. + - **Change the amount of stake delegated to you:** The calculator's default settings automatically assign you a certain share of the delegated stake when you start validating. However, you can change this setting to know your rewards should you manage to attract more (or less) delegated stake than the default setting. + - **Change your performance factor:** Your performance factor under the calculator's default settings is 0.95. However, you can change this to simulate larger or smaller shares of online time. + - **Change your fixed costs:** By the default settings of the calculator, your fixed costs are zero. This setting can be changed so you spare part of the pool rowards just for yourself. However, notice that the fixed cost is a public parameter, that you define during registration. This means that the delegator knows how you set this value and might consider it when choosing a validator to delegate. Furthermore, if you set this value too high, you'll be punished and won't get any rewards. -- **Simulate your Mana accumulation**: the default setting of the calculator assumes a stationary regime and calculates the block creation rate you guarantee depending on your stake and level of participation. However, specially in the early stages of the network you might want to save your mana to sell later. This tab simulates how much Mana you will accumulate in a certain time period. For that (besides the other already defined inputs), you just need to choose a initial and final epochs, and the tool will plot a graph of your accumulation during that period. In the same graph, you can also have an idea of how many blocks can be issued with this accumulated amount of Mana, for the different congestion levels (already defined in the non-advanced settings). +- **Simulate your Mana accumulation**: the default setting of the calculator assumes a stationary regime and calculates the block creation rate you guarantee depending on your stake and level of participation. However, especially in the early stages of the network, you might want to save your Mana to sell later. This tab simulates how much Mana you'll accumulate in a certain time period. For that (besides the other already defined inputs), you just need to choose an initial and final epoch, and the tool will plot a graph of your accumulation during that period. In the same graph, you can also have an idea of how many blocks can be issued with this accumulated amount of Mana, for the different congestion levels (already defined in the non-advanced settings). From ef790cf99f2c3d3f5bf36027632cfa6424325532 Mon Sep 17 00:00:00 2001 From: DafPhil <91533416+DafPhil@users.noreply.github.com> Date: Thu, 26 Oct 2023 16:15:07 +0200 Subject: [PATCH 18/40] Update mana-calculator.md (#1284) stake IOTA tokens to get mana rewards, not stake mana to get mana rewards Co-authored-by: Dr-Electron --- docs/learn/protocols/iota2.0/core-concepts/mana-calculator.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/learn/protocols/iota2.0/core-concepts/mana-calculator.md b/docs/learn/protocols/iota2.0/core-concepts/mana-calculator.md index 57e64d60890..f88393fa97c 100644 --- a/docs/learn/protocols/iota2.0/core-concepts/mana-calculator.md +++ b/docs/learn/protocols/iota2.0/core-concepts/mana-calculator.md @@ -2,7 +2,7 @@ import ManaCalculator from '@site/src/components/ManaCalculator'; # Mana Calculator -Mana is a reward resource generated by holding IOTA tokens. It is utilized for block issuance, access to network throughput, protection against Sybil attacks, and various other services. Our incentives scheme allows you to stake or delegate Mana to receive Mana rewards, in addition to the Mana generated simply by holding your IOTA tokens, without having to participate in any consensus-related activity. +Mana is a reward resource generated by holding IOTA tokens. It is utilized for block issuance, access to network throughput, protection against Sybil attacks, and various other services. Our incentives scheme allows you to stake or delegate IOTA tokens to receive Mana rewards, in addition to the Mana generated simply by holding your IOTA tokens, without having to participate in any consensus-related activity. Here, we introduce the Mana Calculator: a tool to help you make decisions about the type of participation that will suit you best, to help you predict the Mana generation you’ll be granted, and to decide the number of IOTA tokens you should hold to guarantee your desired level of access in the future. From f8d39ebb889d631178bb8f2883ebf398c10b206a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20Esp=C3=ADn?= Date: Fri, 27 Oct 2023 21:12:36 +0200 Subject: [PATCH 19/40] feat: Flexible network configuration for Mana calculator (#1289) --- src/components/ManaCalculator/calculator.ts | 8 +- src/components/ManaCalculator/index.tsx | 109 +++++++++++++------- src/components/ManaCalculator/types.ts | 18 ++-- src/components/ManaCalculator/utils.ts | 20 ++-- 4 files changed, 96 insertions(+), 59 deletions(-) diff --git a/src/components/ManaCalculator/calculator.ts b/src/components/ManaCalculator/calculator.ts index 1baf7e86cc1..5b85bd465f9 100644 --- a/src/components/ManaCalculator/calculator.ts +++ b/src/components/ManaCalculator/calculator.ts @@ -2,7 +2,6 @@ import { GENERATION_PER_SLOT, first_slot_of_epoch, potential_Mana, - IOTA_SUPPLY, targetReward, EPOCH_DURATION, decay, @@ -17,16 +16,17 @@ export function calculateManaRewards( initialEpoch: number, finalEpoch: number, yourRole: 'Validator' | 'Delegator', + supply: number ): number { let totalTargetReward = 0; let epochDiff = 1; if (finalEpoch) { for (let i = 0; i < epochDiff; i++) { - totalTargetReward += decay(targetReward(initialEpoch + i), epochDiff - i); + totalTargetReward += decay(targetReward(initialEpoch + i, supply), epochDiff - i); } } else { finalEpoch = initialEpoch + 1; - totalTargetReward = targetReward(initialEpoch); + totalTargetReward = targetReward(initialEpoch, supply); } const lockedStake: number[] = validators.map( @@ -65,7 +65,7 @@ export function calculateManaRewards( const totalValidatorsStake = lockedStake.reduce((a, b) => a + b, 0); const totalDelegatedStake = delegatedStake.reduce((a, b) => a + b, 0); const totalStake = totalDelegatedStake + totalValidatorsStake; - const restOfTokenHoldings = IOTA_SUPPLY - totalStake; + const restOfTokenHoldings = supply - totalStake; if (restOfTokenHoldings < 0) { throw new Error('Pools must have (collectively) at most iotaSupply tokens'); } diff --git a/src/components/ManaCalculator/index.tsx b/src/components/ManaCalculator/index.tsx index 59cff7f9438..90c19ef1737 100644 --- a/src/components/ManaCalculator/index.tsx +++ b/src/components/ManaCalculator/index.tsx @@ -16,11 +16,53 @@ import { ChangeEvent, ChangeCongestionEvent, CongestionType, - ManaCalculatorProps, ValidatorParameters, + NetworkType, + ManaCalculatorProps, } from './types'; import { Details } from '@docusaurus/theme-common/Details'; -import { EPOCH, fromMicro, toMicro } from './utils'; +import { EPOCH, fromMicro, getNetworkSupply, toMicro } from './utils'; + +function getDefaultParameters(network: NetworkType): ManaCalculatorProps { + return { + initialEpoch: 0, + finalEpoch: 100, + validators: [ + { + lockedStake: toMicro(100), + delegatedStake: toMicro(0), + performanceFactor: 1.0, + fixedCost: 0.0, + }, + { + lockedStake: toMicro(100), + delegatedStake: toMicro(0), + performanceFactor: 1.0, + fixedCost: 0.0, + }, + { + lockedStake: toMicro(100), + delegatedStake: toMicro(0), + performanceFactor: 1.0, + fixedCost: 0.0, + }, + ], + userType: UserType.DELEGATOR, + congestion: CongestionType.LOW, + stake: toMicro(100), + delegator: { + validator: 0, + }, + validator: { + performanceFactor: 1.0, + fixedCost: 0.0, + shareOfYourStakeLocked: 1.0, + attractedNewDelegatedStake: 0.0, + attractedDelegatedStakeFromOtherPools: 0.1, + }, + network + } as ManaCalculatorProps +} function ValidatorCard({ validator, @@ -96,43 +138,7 @@ function ValidatorCard({ } export default function ManaCalculator() { - const [state, setState] = useState({ - initialEpoch: 0, - finalEpoch: 100, - validators: [ - { - lockedStake: toMicro(100), - delegatedStake: toMicro(0), - performanceFactor: 1.0, - fixedCost: 0.0, - }, - { - lockedStake: toMicro(100), - delegatedStake: toMicro(0), - performanceFactor: 1.0, - fixedCost: 0.0, - }, - { - lockedStake: toMicro(100), - delegatedStake: toMicro(0), - performanceFactor: 1.0, - fixedCost: 0.0, - }, - ], - userType: UserType.DELEGATOR, - congestion: CongestionType.LOW, - stake: toMicro(100), - delegator: { - validator: 0, - }, - validator: { - performanceFactor: 1.0, - fixedCost: 0.0, - shareOfYourStakeLocked: 1.0, - attractedNewDelegatedStake: 0.0, - attractedDelegatedStakeFromOtherPools: 0.1, - }, - } as ManaCalculatorProps); + const [state, setState] = useState(getDefaultParameters(NetworkType.IOTA)); function handleDelete(id: number) { const validators = state.validators.filter((_, i) => i !== id); @@ -260,6 +266,14 @@ export default function ManaCalculator() { }); } + function handleNetworkChange(value: NetworkType){ + setState({ + ...getDefaultParameters(value) + }); + } + + const supply = getNetworkSupply(state.network) + // Calulate Mana rewards for delegator and validator let delegatorResults = { manaGeneratedPerEpoch: 0, @@ -280,6 +294,7 @@ export default function ManaCalculator() { EPOCH, null, 'Delegator', + supply ); let passiveRewards = calculatePassiveRewards(state.stake, EPOCH, EPOCH + 1); @@ -308,6 +323,7 @@ export default function ManaCalculator() { EPOCH, null, 'Validator', + supply ); grantedTPS = calculateTPS(manaGeneratedPerEpoch, state.congestion); totalTPS = grantedTPS + additionalTPS; @@ -337,6 +353,7 @@ export default function ManaCalculator() { state.initialEpoch, state.finalEpoch, 'Delegator', + supply ); let passiveRewards = calculatePassiveRewards( state.stake, @@ -367,6 +384,7 @@ export default function ManaCalculator() { state.initialEpoch, state.finalEpoch, 'Validator', + supply ); grantedTPS = calculateTPS(manaGenerated, state.congestion); totalTPS = grantedTPS + additionalTPS; @@ -378,6 +396,17 @@ export default function ManaCalculator() { return (
+ handleStakeChange(toMicro(Number(e.target.value)), id)} + onChange={(e) => + handleStakeChange(toMicro(Number(e.target.value)), id) + } >
@@ -266,13 +268,13 @@ export default function ManaCalculator() { }); } - function handleNetworkChange(value: NetworkType){ + function handleNetworkChange(value: NetworkType) { setState({ - ...getDefaultParameters(value) + ...getDefaultParameters(value), }); } - const supply = getNetworkSupply(state.network) + const supply = getNetworkSupply(state.network); // Calulate Mana rewards for delegator and validator let delegatorResults = { @@ -294,7 +296,7 @@ export default function ManaCalculator() { EPOCH, null, 'Delegator', - supply + supply, ); let passiveRewards = calculatePassiveRewards(state.stake, EPOCH, EPOCH + 1); @@ -323,7 +325,7 @@ export default function ManaCalculator() { EPOCH, null, 'Validator', - supply + supply, ); grantedTPS = calculateTPS(manaGeneratedPerEpoch, state.congestion); totalTPS = grantedTPS + additionalTPS; @@ -353,7 +355,7 @@ export default function ManaCalculator() { state.initialEpoch, state.finalEpoch, 'Delegator', - supply + supply, ); let passiveRewards = calculatePassiveRewards( state.stake, @@ -384,7 +386,7 @@ export default function ManaCalculator() { state.initialEpoch, state.finalEpoch, 'Validator', - supply + supply, ); grantedTPS = calculateTPS(manaGenerated, state.congestion); totalTPS = grantedTPS + additionalTPS; @@ -404,9 +406,9 @@ export default function ManaCalculator() { classNamePrefix='react-select' options={[ { value: NetworkType.IOTA, label: `IOTA` }, - { value: NetworkType.SHIMMER, label: `Shimmer` } + { value: NetworkType.SHIMMER, label: `Shimmer` }, ]} - /> + />
@@ -609,7 +611,9 @@ function DelegatorForm({ handleOwnStakeChange(toMicro(Number(e.target.value)))} + onChange={(e) => + handleOwnStakeChange(toMicro(Number(e.target.value))) + } >
@@ -650,7 +654,9 @@ function ValidatorForm({ handleOwnStakeChange(toMicro(Number(e.target.value)))} + onChange={(e) => + handleOwnStakeChange(toMicro(Number(e.target.value))) + } >
@@ -730,11 +736,15 @@ function OutputForm({
Mana generation (by holding)
-
{fromMicro(passiveRewards)}
+
+ {fromMicro(passiveRewards)} +
Mana rewards (delegation/validation)
-
{fromMicro(manaGeneratedPerEpoch)}
+
+ {fromMicro(manaGeneratedPerEpoch)} +
diff --git a/src/components/ManaCalculator/types.ts b/src/components/ManaCalculator/types.ts index 50e0fb097ad..a7877ac86b8 100644 --- a/src/components/ManaCalculator/types.ts +++ b/src/components/ManaCalculator/types.ts @@ -41,7 +41,7 @@ export interface ManaCalculatorProps { performanceFactor: number; }; stake: number; - network: NetworkType + network: NetworkType; } export enum CongestionType { diff --git a/src/components/ManaCalculator/utils.ts b/src/components/ManaCalculator/utils.ts index 0f04d2d4680..c35ac9056a3 100644 --- a/src/components/ManaCalculator/utils.ts +++ b/src/components/ManaCalculator/utils.ts @@ -1,4 +1,4 @@ -import { NetworkType } from "./types"; +import { NetworkType } from './types'; // Constants const IOTA_SUPPLY = 4600000000000000; @@ -113,9 +113,9 @@ export function toMicro(n: number): number { } export function getNetworkSupply(network: NetworkType): number { - if(network == NetworkType.IOTA){ - return IOTA_SUPPLY + if (network == NetworkType.IOTA) { + return IOTA_SUPPLY; } else { - return SHIMMER_SUPPLY + return SHIMMER_SUPPLY; } } From c6ff575c43c41d2668dfe4b24f904915b9caeb88 Mon Sep 17 00:00:00 2001 From: Dr-Electron Date: Sat, 28 Oct 2023 16:23:41 +0200 Subject: [PATCH 21/40] Lint --- src/components/ManaCalculator/calculator.ts | 2 +- src/components/ManaCalculator/index.tsx | 18 +++++++++++------- src/components/ManaCalculator/utils.ts | 12 ------------ 3 files changed, 12 insertions(+), 20 deletions(-) diff --git a/src/components/ManaCalculator/calculator.ts b/src/components/ManaCalculator/calculator.ts index ebece5996f2..56f7fa85306 100644 --- a/src/components/ManaCalculator/calculator.ts +++ b/src/components/ManaCalculator/calculator.ts @@ -19,7 +19,7 @@ export function calculateManaRewards( supply: number, ): number { let totalTargetReward = 0; - let epochDiff = 1; + const epochDiff = 1; if (finalEpoch) { for (let i = 0; i < epochDiff; i++) { totalTargetReward += decay( diff --git a/src/components/ManaCalculator/index.tsx b/src/components/ManaCalculator/index.tsx index 9af0dc33c99..9a061a74bc4 100644 --- a/src/components/ManaCalculator/index.tsx +++ b/src/components/ManaCalculator/index.tsx @@ -282,7 +282,7 @@ export default function ManaCalculator() { passiveRewards: 0, totalTPS: 0, }; - let validatorResults = { + const validatorResults = { manaGeneratedPerEpoch: 0, passiveRewards: 0, totalTPS: 0, @@ -298,10 +298,14 @@ export default function ManaCalculator() { 'Delegator', supply, ); - let passiveRewards = calculatePassiveRewards(state.stake, EPOCH, EPOCH + 1); + const passiveRewards = calculatePassiveRewards( + state.stake, + EPOCH, + EPOCH + 1, + ); let grantedTPS = calculateTPS(manaGeneratedPerEpoch, state.congestion); - let additionalTPS = calculateTPS(passiveRewards, state.congestion); + const additionalTPS = calculateTPS(passiveRewards, state.congestion); let totalTPS = grantedTPS + additionalTPS; delegatorResults = { @@ -336,12 +340,12 @@ export default function ManaCalculator() { } // Calulate Mana rewards for delegator and validator - let delegatorAccumulateResults = { + const delegatorAccumulateResults = { manaGenerated: 0, passiveRewards: 0, totalTPS: 0, }; - let validatorAccumulateResults = { + const validatorAccumulateResults = { manaGenerated: 0, passiveRewards: 0, totalTPS: 0, @@ -357,14 +361,14 @@ export default function ManaCalculator() { 'Delegator', supply, ); - let passiveRewards = calculatePassiveRewards( + const passiveRewards = calculatePassiveRewards( state.stake, state.initialEpoch, state.finalEpoch, ); let grantedTPS = calculateTPS(manaGenerated, state.congestion); - let additionalTPS = calculateTPS(passiveRewards, state.congestion); + const additionalTPS = calculateTPS(passiveRewards, state.congestion); let totalTPS = grantedTPS + additionalTPS; delegatorAccumulateResults.manaGenerated = manaGenerated; diff --git a/src/components/ManaCalculator/utils.ts b/src/components/ManaCalculator/utils.ts index c35ac9056a3..edde60260d5 100644 --- a/src/components/ManaCalculator/utils.ts +++ b/src/components/ManaCalculator/utils.ts @@ -14,18 +14,6 @@ const BOOTSTRAPPING_DURATION = 1154; const REWARDS_MANA_SHARE_COEFFICIENT = 2; export const EPOCH = 1154 + 1; -// given t in seconds, returns the slot that time t belongs to -function time_to_slot(t: number): number { - const slot = Math.floor(t / SLOT_DURATION); - return slot; -} - -// given t in seconds, returns the epoch that time t belongs to -function time_to_epoch(t: number): number { - const epoch = Math.floor(t / EPOCH_DURATION); - return epoch; -} - // given n in slots, returns the epoch that slot n belongs to function slot_to_epoch(n: number): number { const epoch = Math.floor(n / SLOTS_IN_EPOCH); From b47899d1c55ea4d6dc8f564106ad2a26cc8148b8 Mon Sep 17 00:00:00 2001 From: Dr-Electron Date: Thu, 2 Nov 2023 23:37:57 +0100 Subject: [PATCH 22/40] Fix epochDiff --- src/components/ManaCalculator/calculator.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/ManaCalculator/calculator.ts b/src/components/ManaCalculator/calculator.ts index 56f7fa85306..a13c76fd748 100644 --- a/src/components/ManaCalculator/calculator.ts +++ b/src/components/ManaCalculator/calculator.ts @@ -19,7 +19,8 @@ export function calculateManaRewards( supply: number, ): number { let totalTargetReward = 0; - const epochDiff = 1; + let epochDiff = finalEpoch - initialEpoch; + if (finalEpoch) { for (let i = 0; i < epochDiff; i++) { totalTargetReward += decay( @@ -28,6 +29,7 @@ export function calculateManaRewards( ); } } else { + epochDiff = 1; finalEpoch = initialEpoch + 1; totalTargetReward = targetReward(initialEpoch, supply); } From b13c9b0e3605363015198de8b4bc1e5d5b5a9bf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20Esp=C3=ADn?= Date: Mon, 6 Nov 2023 00:32:51 +0100 Subject: [PATCH 23/40] feat: Improved user flow of Mana Calculator (#1314) * feat: Flexible network selector in the mana calculator * feat: Improved user flow for the Mana calculator * typo * fmt --- src/components/ManaCalculator/calculator.ts | 12 +- src/components/ManaCalculator/index.tsx | 680 ++++++++++---------- src/components/ManaCalculator/styles.css | 3 - src/components/ManaCalculator/types.ts | 1 + src/css/custom.css | 37 ++ 5 files changed, 368 insertions(+), 365 deletions(-) diff --git a/src/components/ManaCalculator/calculator.ts b/src/components/ManaCalculator/calculator.ts index a13c76fd748..16225ce9cbb 100644 --- a/src/components/ManaCalculator/calculator.ts +++ b/src/components/ManaCalculator/calculator.ts @@ -6,7 +6,7 @@ import { EPOCH_DURATION, decay, } from './utils'; -import { ValidatorParameters, ValidatorProps } from './types'; +import { UserType, ValidatorParameters, ValidatorProps } from './types'; export function calculateManaRewards( stake: number, @@ -15,7 +15,7 @@ export function calculateManaRewards( validators: ValidatorProps[], initialEpoch: number, finalEpoch: number, - yourRole: 'Validator' | 'Delegator', + userType: UserType, supply: number, ): number { let totalTargetReward = 0; @@ -47,7 +47,7 @@ export function calculateManaRewards( (validator) => validator.delegatedStake, ); - if (yourRole === 'Validator') { + if (userType == UserType.VALIDATOR) { lockedStake.push(stake * validatorParameters.shareOfYourStakeLocked); fixedCosts.push(validatorParameters.fixedCost); performance.push(validatorParameters.performanceFactor); @@ -63,7 +63,7 @@ export function calculateManaRewards( } } - if (yourRole === 'Delegator') { + if (userType == UserType.DELEGATOR) { delegatedStake[yourPool] += stake; } @@ -133,13 +133,13 @@ export function calculateManaRewards( } let rewards = 0; - if (yourRole === 'Delegator') { + if (userType == UserType.DELEGATOR) { if (delegatorRewards[yourPool] > 0) { rewards = (delegatorRewards[yourPool] * stake) / delegatedStake[yourPool]; } } - if (yourRole === 'Validator') { + if (userType == UserType.VALIDATOR) { rewards = validatorRewards[lockedStake.length - 1]; } diff --git a/src/components/ManaCalculator/index.tsx b/src/components/ManaCalculator/index.tsx index 9a061a74bc4..426a2e23c79 100644 --- a/src/components/ManaCalculator/index.tsx +++ b/src/components/ManaCalculator/index.tsx @@ -1,7 +1,5 @@ import React, { useState } from 'react'; import Select from 'react-select'; -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; import './styles.css'; import { calculateManaRewards, @@ -9,19 +7,19 @@ import { calculateTPS, } from './calculator'; import { - UserType, - ValidatorProps, - DeleteValidatorEvent, - ChangeValidatorEvent, ChangeEvent, - ChangeCongestionEvent, + ChangeValidatorEvent, CongestionType, - ValidatorParameters, - NetworkType, + DeleteValidatorEvent, ManaCalculatorProps, + NetworkType, + NewValidatorEvent, + UserType, + ValidatorParameters, + ValidatorProps, } from './types'; import { Details } from '@docusaurus/theme-common/Details'; -import { EPOCH, fromMicro, getNetworkSupply, toMicro } from './utils'; +import { fromMicro, getNetworkSupply, toMicro } from './utils'; function getDefaultParameters(network: NetworkType): ManaCalculatorProps { return { @@ -139,6 +137,72 @@ function ValidatorCard({ ); } +function useResults(state: ManaCalculatorProps) { + const passiveRewards = calculatePassiveRewards( + state.stake, + state.initialEpoch, + state.finalEpoch, + ); + + let additionalTPS = calculateTPS(passiveRewards, state.congestion); + + if (state.userType == UserType.DELEGATOR) { + const manaGenerated = calculateManaRewards( + state.stake, + state.delegator.validator, + null, + state.validators, + state.initialEpoch, + state.finalEpoch, + state.userType, + getNetworkSupply(state.network), + ); + + let passiveRewards = calculatePassiveRewards( + state.stake, + state.initialEpoch, + state.finalEpoch, + ); + + let grantedTPS = calculateTPS(manaGenerated, state.congestion); + + let totalTPS = grantedTPS + additionalTPS; + + return { + manaGenerated, + passiveRewards, + totalTPS, + }; + } else { + const manaGenerated = calculateManaRewards( + state.stake, + state.delegator.validator, + { + performanceFactor: state.validator.performanceFactor, + fixedCost: state.validator.fixedCost, + shareOfYourStakeLocked: state.validator.shareOfYourStakeLocked, + attractedNewDelegatedStake: state.validator.attractedNewDelegatedStake, + attractedDelegatedStakeFromOtherPools: + state.validator.attractedDelegatedStakeFromOtherPools, + } as ValidatorParameters, + state.validators, + state.initialEpoch, + state.finalEpoch, + state.userType, + getNetworkSupply(state.network), + ); + + const grantedTPS = calculateTPS(manaGenerated, state.congestion); + + const totalTPS = grantedTPS + additionalTPS; + return { + manaGenerated, + passiveRewards, + totalTPS, + }; + } +} + export default function ManaCalculator() { const [state, setState] = useState(getDefaultParameters(NetworkType.IOTA)); @@ -274,332 +338,246 @@ export default function ManaCalculator() { }); } - const supply = getNetworkSupply(state.network); - - // Calulate Mana rewards for delegator and validator - let delegatorResults = { - manaGeneratedPerEpoch: 0, - passiveRewards: 0, - totalTPS: 0, - }; - const validatorResults = { - manaGeneratedPerEpoch: 0, - passiveRewards: 0, - totalTPS: 0, - }; - { - let manaGeneratedPerEpoch = calculateManaRewards( - state.stake, - state.delegator.validator, - null, - state.validators, - EPOCH, - null, - 'Delegator', - supply, - ); - const passiveRewards = calculatePassiveRewards( - state.stake, - EPOCH, - EPOCH + 1, - ); - - let grantedTPS = calculateTPS(manaGeneratedPerEpoch, state.congestion); - const additionalTPS = calculateTPS(passiveRewards, state.congestion); - let totalTPS = grantedTPS + additionalTPS; - - delegatorResults = { - manaGeneratedPerEpoch: manaGeneratedPerEpoch, - passiveRewards: passiveRewards, - totalTPS: totalTPS, - }; - - manaGeneratedPerEpoch = calculateManaRewards( - state.stake, - state.delegator.validator, - { - performanceFactor: state.validator.performanceFactor, - fixedCost: state.validator.fixedCost, - shareOfYourStakeLocked: state.validator.shareOfYourStakeLocked, - attractedNewDelegatedStake: state.validator.attractedNewDelegatedStake, - attractedDelegatedStakeFromOtherPools: - state.validator.attractedDelegatedStakeFromOtherPools, - } as ValidatorParameters, - state.validators, - EPOCH, - null, - 'Validator', - supply, - ); - grantedTPS = calculateTPS(manaGeneratedPerEpoch, state.congestion); - totalTPS = grantedTPS + additionalTPS; - - validatorResults.manaGeneratedPerEpoch = manaGeneratedPerEpoch; - validatorResults.passiveRewards = passiveRewards; - validatorResults.totalTPS = totalTPS; + function handleUserChange(value: UserType) { + setState({ + ...state, + userType: value, + }); } - // Calulate Mana rewards for delegator and validator - const delegatorAccumulateResults = { - manaGenerated: 0, - passiveRewards: 0, - totalTPS: 0, - }; - const validatorAccumulateResults = { - manaGenerated: 0, - passiveRewards: 0, - totalTPS: 0, - }; - { - let manaGenerated = calculateManaRewards( - state.stake, - state.delegator.validator, - null, - state.validators, - state.initialEpoch, - state.finalEpoch, - 'Delegator', - supply, - ); - const passiveRewards = calculatePassiveRewards( - state.stake, - state.initialEpoch, - state.finalEpoch, - ); - - let grantedTPS = calculateTPS(manaGenerated, state.congestion); - const additionalTPS = calculateTPS(passiveRewards, state.congestion); - let totalTPS = grantedTPS + additionalTPS; + function handleAddValidator(value: ValidatorProps) { + state.validators.push(value); + setState({ ...state }); + } - delegatorAccumulateResults.manaGenerated = manaGenerated; - delegatorAccumulateResults.passiveRewards = passiveRewards; - delegatorAccumulateResults.totalTPS = totalTPS; + const results = useResults(state); - manaGenerated = calculateManaRewards( - state.stake, - state.delegator.validator, - { - performanceFactor: state.validator.performanceFactor, - fixedCost: state.validator.fixedCost, - shareOfYourStakeLocked: state.validator.shareOfYourStakeLocked, - attractedNewDelegatedStake: state.validator.attractedNewDelegatedStake, - attractedDelegatedStakeFromOtherPools: - state.validator.attractedDelegatedStakeFromOtherPools, - } as ValidatorParameters, - state.validators, - state.initialEpoch, - state.finalEpoch, - 'Validator', - supply, - ); - grantedTPS = calculateTPS(manaGenerated, state.congestion); - totalTPS = grantedTPS + additionalTPS; + return ( + <> + + + + +
+ + + ); +} - validatorAccumulateResults.manaGenerated = manaGenerated; - validatorAccumulateResults.passiveRewards = passiveRewards; - validatorAccumulateResults.totalTPS = totalTPS; +function AdvancedSettingsValidator({ + state, + handleAddValidator, + handleDelete, + handleDelegatedStakeChange, + handleFCChange, + handlePFChange, + handleStakeChange, +}: { + state: ManaCalculatorProps; + handleAddValidator: NewValidatorEvent; + handleDelete: DeleteValidatorEvent; + handleStakeChange: ChangeValidatorEvent; + handleDelegatedStakeChange: ChangeValidatorEvent; + handlePFChange: ChangeValidatorEvent; + handleFCChange: ChangeValidatorEvent; +}) { + function onAddValidator() { + handleAddValidator({ + lockedStake: 100, + delegatedStake: 0, + performanceFactor: 1.0, + fixedCost: 0.0, + }); } + return ( +
+
+ {state.validators.map((validator, i) => ( + + ))} +
+
+ +
+
+ ); +} +function OtherParametersSection({ + state, + handleCongestionChange, + handleInitialEpochChange, + handleFinalEpochChange, +}: { + state: ManaCalculatorProps; + handleCongestionChange: ChangeEvent; + handleInitialEpochChange: ChangeEvent; + handleFinalEpochChange: ChangeEvent; +}) { return ( -
+
+

Other parameters

+ - handleInitialEpochChange(Number(e.target.value)) - } - > - - handleFinalEpochChange(Number(e.target.value))} - > -
-
- -
-
You are a:
-
- - - - - - - - - - - - -
-
- {state.validators.map((validator, i) => ( - - ))} -
-
- -
-
+
+ + handleInitialEpochChange(Number(e.target.value))} + > +
+ + handleFinalEpochChange(Number(e.target.value))} + >
); } -function DelegatorForm({ - stake, - validators, +function RoleSection({ + state, handleOwnStakeChange, + handleUserChange, + handleOwnPFChange, + handleShareOfYourStakeLockedChange, + handleAttractedNewDelegatedStakeChange, + handleAttractedDelegatedStakeFromOtherPoolsChange, handleValidatorChange, + handleOwnFCChange, }: { - stake: number; - validators: ValidatorProps[]; + state: ManaCalculatorProps; handleOwnStakeChange: ChangeEvent; + handleUserChange: ChangeEvent; + handleOwnPFChange: ChangeEvent; + handleShareOfYourStakeLockedChange: ChangeEvent; + handleAttractedNewDelegatedStakeChange: ChangeEvent; + handleAttractedDelegatedStakeFromOtherPoolsChange: ChangeEvent; handleValidatorChange: ChangeEvent; + handleOwnFCChange: ChangeEvent; }) { - // Create options for validator select from validators array - const validatorOptions = validators.map((_, i) => { + const validatorOptions = state.validators.map((_, i) => { return { value: i, label: `Validator ${i + 1}` }; }); return ( -
-
-
Validator you delegate to:
- -
+
+

Role configuration

+ + + handleOwnStakeChange(toMicro(Number(e.target.value))) + } + > +
+ + + ) : ( + <> + + handleOwnStakeChange(toMicro(Number(e.target.value))) + } + > + + )} +
+ ); +} -
-
Amount you delegate:
- - handleOwnStakeChange(toMicro(Number(e.target.value))) - } - > -
+function NetworkSection({ + handleNetworkChange, +}: { + handleNetworkChange: ChangeEvent; +}) { + return ( +
+

Network configuration

+ + - handleOwnStakeChange(toMicro(Number(e.target.value))) - } - > -
-
+
Performance factor:
@@ -752,25 +737,8 @@ function OutputForm({
-
Total TPS granted with
-
- { + handleNetworkChange(e.value); + }} + classNamePrefix='react-select' + options={[ + { value: NetworkType.IOTA, label: `IOTA` }, + { value: NetworkType.SHIMMER, label: `Shimmer` }, + ]} + /> +
+ ); +} diff --git a/src/components/ManaCalculator/components/OtherParametersSection.tsx b/src/components/ManaCalculator/components/OtherParametersSection.tsx new file mode 100644 index 00000000000..d34f23e5f69 --- /dev/null +++ b/src/components/ManaCalculator/components/OtherParametersSection.tsx @@ -0,0 +1,49 @@ +import React from 'react'; +import { useManaState } from '../hooks/useManaState'; +import Select from 'react-select'; +import { CongestionType } from '../enums'; + +export function OtherParametersSection() { + const { + state, + handleCongestionChange, + handleInitialEpochChange, + handleFinalEpochChange, + } = useManaState(); + return ( +
+

Other parameters

+ + handleInitialEpochChange(Number(e.target.value))} + > +
+ + handleFinalEpochChange(Number(e.target.value))} + > +
+ ); +} diff --git a/src/components/ManaCalculator/components/OutputForm.tsx b/src/components/ManaCalculator/components/OutputForm.tsx new file mode 100644 index 00000000000..59a068571f1 --- /dev/null +++ b/src/components/ManaCalculator/components/OutputForm.tsx @@ -0,0 +1,27 @@ +import React from 'react'; +import { useManaState, useResults } from '../hooks'; +import { fromMicro } from '../utils'; + +export function OutputForm() { + const { state } = useManaState(); + const { manaGenerated, passiveRewards, totalTPS } = useResults(state); + return ( +
+
+
Mana generation (by holding)
+
+ {fromMicro(passiveRewards)} +
+
+
+
Mana rewards (delegation/validation)
+
{fromMicro(manaGenerated)}
+
+ +
+
Total TPS granted with
+
{totalTPS}
+
+
+ ); +} diff --git a/src/components/ManaCalculator/components/RoleSection.tsx b/src/components/ManaCalculator/components/RoleSection.tsx new file mode 100644 index 00000000000..481c36d50c5 --- /dev/null +++ b/src/components/ManaCalculator/components/RoleSection.tsx @@ -0,0 +1,74 @@ +import React from 'react'; +import { useManaState } from '../hooks'; +import Select from 'react-select'; +import { UserType } from '../enums'; +import { fromMicro, toMicro } from '../utils'; +import { ValidatorSettings } from './ValidatorSettings'; + +export function RoleSection() { + const { + state, + handleOwnStakeChange, + handleUserChange, + handleValidatorChange, + } = useManaState(); + const validatorOptions = state.validators.map((_, i) => { + return { value: i, label: `Validator ${i + 1}` }; + }); + + return ( +
+

Role configuration

+ + + handleOwnStakeChange(toMicro(Number(e.target.value))) + } + > +
+ + + ) : ( + <> + + + handleOwnStakeChange(toMicro(Number(e.target.value))) + } + > + + )} +
+ ); +} diff --git a/src/components/ManaCalculator/components/ValidatorCard.tsx b/src/components/ManaCalculator/components/ValidatorCard.tsx new file mode 100644 index 00000000000..e52ad669d49 --- /dev/null +++ b/src/components/ManaCalculator/components/ValidatorCard.tsx @@ -0,0 +1,75 @@ +import React from 'react'; +import { useManaState } from '../hooks'; +import { ValidatorProps } from '../types'; +import { fromMicro, toMicro } from '../utils'; + +export function ValidatorCard({ + validator, + id, +}: { + validator: ValidatorProps; + id: number; +}) { + const { + handleDelete, + handleStakeChange, + handleDelegatedStakeChange, + handlePFChange, + handleFCChange, + } = useManaState(); + return ( +
+
+
+
Validator {id + 1}
+ +
+
+
Stake:
+ + handleStakeChange(toMicro(Number(e.target.value)), id) + } + > +
+
+
Delegated:
+ + handleDelegatedStakeChange(toMicro(Number(e.target.value)), id) + } + > +
+
+
PF:
+ handlePFChange(Number(e.target.value), id)} + > +
+
+
FC:
+ handleFCChange(Number(e.target.value), id)} + > +
+
+
+ ); +} diff --git a/src/components/ManaCalculator/components/ValidatorSettings.tsx b/src/components/ManaCalculator/components/ValidatorSettings.tsx new file mode 100644 index 00000000000..aed802c432b --- /dev/null +++ b/src/components/ManaCalculator/components/ValidatorSettings.tsx @@ -0,0 +1,81 @@ +import React from 'react'; +import { Details } from '@docusaurus/theme-common/Details'; +import { useManaState } from '../hooks'; + +export function ValidatorSettings() { + const { + state: { + performanceFactor, + fixedCost, + shareOfYourStakeLocked, + attractedNewDelegatedStake, + attractedDelegatedStakeFromOtherPools, + }, + handleOwnPFChange, + handleOwnFCChange, + handleShareOfYourStakeLockedChange, + handleAttractedNewDelegatedStakeChange, + handleAttractedDelegatedStakeFromOtherPoolsChange, + } = useManaState(); + return ( +
+
+
+
Performance factor:
+ handleOwnPFChange(Number(e.target.value))} + > +
+ +
+
Fixed costs:
+ handleOwnFCChange(Number(e.target.value))} + > +
+
+
Share of your stake locked:
+ + handleShareOfYourStakeLockedChange(Number(e.target.value)) + } + > +
+
+
Attracted new delegated stake:
+ + handleAttractedNewDelegatedStakeChange(Number(e.target.value)) + } + > +
+
+
+ Attracted delegated stake from other pools: +
+ + handleAttractedDelegatedStakeFromOtherPoolsChange( + Number(e.target.value), + ) + } + > +
+
+
+ ); +} diff --git a/src/components/ManaCalculator/components/index.ts b/src/components/ManaCalculator/components/index.ts new file mode 100644 index 00000000000..145cf01d52a --- /dev/null +++ b/src/components/ManaCalculator/components/index.ts @@ -0,0 +1,8 @@ +export * from './AdvancedSettingsValidator'; +export * from './ManaCalculator'; +export * from './OtherParametersSection'; +export * from './ValidatorCard'; +export * from './ValidatorSettings'; +export * from './RoleSection'; +export * from './OutputForm'; +export * from './NetworkSection'; diff --git a/src/components/ManaCalculator/constants.ts b/src/components/ManaCalculator/constants.ts new file mode 100644 index 00000000000..f978c9facef --- /dev/null +++ b/src/components/ManaCalculator/constants.ts @@ -0,0 +1,16 @@ +export const IOTA_SUPPLY = 4600000000000000; +export const SHIMMER_SUPPLY = 1813620509000000; +export const SLOT_DURATION = 10; +export const SLOTS_IN_EPOCH = 8192; +export const EPOCH_DURATION = SLOTS_IN_EPOCH * SLOT_DURATION; +export const SECONDS_IN_YEAR = 60 * 60 * 24 * 365; +export const EPOCH_DURATION_IN_YEARS = EPOCH_DURATION / SECONDS_IN_YEAR; +export const BETA_PER_YEAR = 1 / 3; +export const GENERATION_PER_SLOT = Math.pow(2, -17); +export const BOOTSTRAPPING_DURATION = 1154; +export const REWARDS_MANA_SHARE_COEFFICIENT = 2; +export const EPOCH = 1154 + 1; + +export const CONGESTION_LOW = 100000; +export const CONGESTION_MEDIUM = 9000000; +export const CONGESTION_HIGH = 500000000; diff --git a/src/components/ManaCalculator/enums/index.ts b/src/components/ManaCalculator/enums/index.ts new file mode 100644 index 00000000000..531ace0d0e0 --- /dev/null +++ b/src/components/ManaCalculator/enums/index.ts @@ -0,0 +1 @@ +export * from './parameters.enum'; diff --git a/src/components/ManaCalculator/enums/parameters.enum.ts b/src/components/ManaCalculator/enums/parameters.enum.ts new file mode 100644 index 00000000000..191347c0b05 --- /dev/null +++ b/src/components/ManaCalculator/enums/parameters.enum.ts @@ -0,0 +1,21 @@ +import { + CONGESTION_HIGH, + CONGESTION_LOW, + CONGESTION_MEDIUM, +} from '../constants'; + +export enum UserType { + DELEGATOR, + VALIDATOR, +} + +export enum NetworkType { + IOTA, + SHIMMER, +} + +export enum CongestionType { + LOW = CONGESTION_LOW, + MEDIUM = CONGESTION_MEDIUM, + HIGH = CONGESTION_HIGH, +} diff --git a/src/components/ManaCalculator/hooks/index.ts b/src/components/ManaCalculator/hooks/index.ts new file mode 100644 index 00000000000..21d29e89070 --- /dev/null +++ b/src/components/ManaCalculator/hooks/index.ts @@ -0,0 +1,2 @@ +export * from './useManaState'; +export * from './useResults'; diff --git a/src/components/ManaCalculator/hooks/useManaState.ts b/src/components/ManaCalculator/hooks/useManaState.ts new file mode 100644 index 00000000000..bc2a2dd256e --- /dev/null +++ b/src/components/ManaCalculator/hooks/useManaState.ts @@ -0,0 +1,219 @@ +import { createContext, useContext } from 'react'; +import { CongestionType, NetworkType, UserType } from '../enums'; +import { ManaCalculatorProps, ValidatorProps } from '../types'; +import { toMicro } from '../utils'; + +export const ManaStateContext = createContext(null); + +export function useManaState() { + const { setState, state } = useContext(ManaStateContext); + + function handleDelete(id: number) { + const validators = state.validators.filter((_, i) => i !== id); + setState({ ...state, validators }); + } + + function handleStakeChange(value: number, id: number) { + setState({ + ...state, + validators: state.validators.map((validator, i) => { + return { + ...validator, + lockedStake: i === id ? value : validator.lockedStake, + }; + }), + }); + } + + function handleDelegatedStakeChange(value: number, id: number) { + setState({ + ...state, + validators: state.validators.map((validator, i) => { + return { + ...validator, + delegatedStake: i === id ? value : validator.delegatedStake, + }; + }), + }); + } + + function handlePFChange(value: number, id: number) { + setState({ + ...state, + validators: state.validators.map((validator, i) => { + return { + ...validator, + performanceFactor: i === id ? value : validator.performanceFactor, + }; + }), + }); + } + + function handleFCChange(value: number, id: number) { + setState({ + ...state, + validators: state.validators.map((validator, i) => { + return { + ...validator, + fixedCost: i === id ? value : validator.fixedCost, + }; + }), + }); + } + + function handleOwnStakeChange(value: number) { + setState({ + ...state, + stake: value, + }); + } + + function handleValidatorChange(value: number) { + setState({ + ...state, + delegator: { ...state.delegator, validator: value }, + }); + } + + function handleCongestionChange(value: CongestionType) { + setState({ + ...state, + congestion: value, + }); + } + + function handleOwnPFChange(value: number) { + setState({ + ...state, + validator: { ...state.validator, performanceFactor: value }, + }); + } + + function handleOwnFCChange(value: number) { + setState({ + ...state, + validator: { ...state.validator, fixedCost: value }, + }); + } + + function handleShareOfYourStakeLockedChange(value: number) { + setState({ + ...state, + validator: { ...state.validator, shareOfYourStakeLocked: value }, + }); + } + + function handleAttractedNewDelegatedStakeChange(value: number) { + setState({ + ...state, + validator: { ...state.validator, attractedNewDelegatedStake: value }, + }); + } + + function handleAttractedDelegatedStakeFromOtherPoolsChange(value: number) { + setState({ + ...state, + validator: { + ...state.validator, + attractedDelegatedStakeFromOtherPools: value, + }, + }); + } + + function handleInitialEpochChange(value: number) { + setState({ + ...state, + initialEpoch: value, + }); + } + + function handleFinalEpochChange(value: number) { + setState({ + ...state, + finalEpoch: value, + }); + } + + function handleNetworkChange(value: NetworkType) { + setState({ + ...getDefaultParameters(value), + }); + } + + function handleUserChange(value: UserType) { + setState({ + ...state, + userType: value, + }); + } + + function handleAddValidator(value: ValidatorProps) { + state.validators.push(value); + setState({ ...state }); + } + + return { + state, + handleDelete, + handleStakeChange, + handleAddValidator, + handleAttractedDelegatedStakeFromOtherPoolsChange, + handleAttractedNewDelegatedStakeChange, + handleCongestionChange, + handleDelegatedStakeChange, + handleFCChange, + handleInitialEpochChange, + handleNetworkChange, + handleFinalEpochChange, + handleOwnFCChange, + handleOwnPFChange, + handleUserChange, + handleShareOfYourStakeLockedChange, + handleOwnStakeChange, + handlePFChange, + handleValidatorChange, + }; +} + +export function getDefaultParameters( + network: NetworkType, +): ManaCalculatorProps { + return { + initialEpoch: 0, + finalEpoch: 100, + validators: [ + { + lockedStake: toMicro(100), + delegatedStake: toMicro(0), + performanceFactor: 1.0, + fixedCost: 0.0, + }, + { + lockedStake: toMicro(100), + delegatedStake: toMicro(0), + performanceFactor: 1.0, + fixedCost: 0.0, + }, + { + lockedStake: toMicro(100), + delegatedStake: toMicro(0), + performanceFactor: 1.0, + fixedCost: 0.0, + }, + ], + userType: UserType.DELEGATOR, + congestion: CongestionType.LOW, + stake: toMicro(100), + delegator: { + validator: 0, + }, + validator: { + performanceFactor: 1.0, + fixedCost: 0.0, + shareOfYourStakeLocked: 1.0, + attractedNewDelegatedStake: 0.0, + attractedDelegatedStakeFromOtherPools: 0.1, + }, + network, + } as ManaCalculatorProps; +} diff --git a/src/components/ManaCalculator/hooks/useResults.ts b/src/components/ManaCalculator/hooks/useResults.ts new file mode 100644 index 00000000000..5db9b07b6dc --- /dev/null +++ b/src/components/ManaCalculator/hooks/useResults.ts @@ -0,0 +1,66 @@ +import { + calculateManaRewards, + calculatePassiveRewards, + calculateTPS, +} from '../actions'; +import { UserType } from '../enums'; +import { ManaCalculatorProps, ValidatorParameters } from '../types'; + +export function useResults(state: ManaCalculatorProps) { + const passiveRewards = calculatePassiveRewards( + state.stake, + state.initialEpoch, + state.finalEpoch, + ); + + const additionalTPS = calculateTPS(passiveRewards, state.congestion); + + if (state.userType == UserType.DELEGATOR) { + const manaGenerated = calculateManaRewards( + state.stake, + state.delegator.validator, + null, + state.validators, + state.initialEpoch, + state.finalEpoch, + state.userType, + state.network, + ); + + const grantedTPS = calculateTPS(manaGenerated, state.congestion); + const totalTPS = grantedTPS + additionalTPS; + + return { + manaGenerated, + passiveRewards, + totalTPS, + }; + } else { + const manaGenerated = calculateManaRewards( + state.stake, + state.delegator.validator, + { + performanceFactor: state.validator.performanceFactor, + fixedCost: state.validator.fixedCost, + shareOfYourStakeLocked: state.validator.shareOfYourStakeLocked, + attractedNewDelegatedStake: state.validator.attractedNewDelegatedStake, + attractedDelegatedStakeFromOtherPools: + state.validator.attractedDelegatedStakeFromOtherPools, + } as ValidatorParameters, + state.validators, + state.initialEpoch, + state.finalEpoch, + state.userType, + state.network, + ); + + const grantedTPS = calculateTPS(manaGenerated, state.congestion); + const totalTPS = grantedTPS + additionalTPS; + + return { + manaGenerated, + passiveRewards, + totalTPS, + }; + } +} diff --git a/src/components/ManaCalculator/index.ts b/src/components/ManaCalculator/index.ts new file mode 100644 index 00000000000..067e1f026f5 --- /dev/null +++ b/src/components/ManaCalculator/index.ts @@ -0,0 +1 @@ +export { ManaCalculator as default } from './components/ManaCalculator'; diff --git a/src/components/ManaCalculator/index.tsx b/src/components/ManaCalculator/index.tsx deleted file mode 100644 index 426a2e23c79..00000000000 --- a/src/components/ManaCalculator/index.tsx +++ /dev/null @@ -1,745 +0,0 @@ -import React, { useState } from 'react'; -import Select from 'react-select'; -import './styles.css'; -import { - calculateManaRewards, - calculatePassiveRewards, - calculateTPS, -} from './calculator'; -import { - ChangeEvent, - ChangeValidatorEvent, - CongestionType, - DeleteValidatorEvent, - ManaCalculatorProps, - NetworkType, - NewValidatorEvent, - UserType, - ValidatorParameters, - ValidatorProps, -} from './types'; -import { Details } from '@docusaurus/theme-common/Details'; -import { fromMicro, getNetworkSupply, toMicro } from './utils'; - -function getDefaultParameters(network: NetworkType): ManaCalculatorProps { - return { - initialEpoch: 0, - finalEpoch: 100, - validators: [ - { - lockedStake: toMicro(100), - delegatedStake: toMicro(0), - performanceFactor: 1.0, - fixedCost: 0.0, - }, - { - lockedStake: toMicro(100), - delegatedStake: toMicro(0), - performanceFactor: 1.0, - fixedCost: 0.0, - }, - { - lockedStake: toMicro(100), - delegatedStake: toMicro(0), - performanceFactor: 1.0, - fixedCost: 0.0, - }, - ], - userType: UserType.DELEGATOR, - congestion: CongestionType.LOW, - stake: toMicro(100), - delegator: { - validator: 0, - }, - validator: { - performanceFactor: 1.0, - fixedCost: 0.0, - shareOfYourStakeLocked: 1.0, - attractedNewDelegatedStake: 0.0, - attractedDelegatedStakeFromOtherPools: 0.1, - }, - network, - } as ManaCalculatorProps; -} - -function ValidatorCard({ - validator, - handleDelete, - handleStakeChange, - handleDelegatedStakeChange, - handlePFChange, - handleFCChange, - id, -}: { - validator: ValidatorProps; - handleDelete: DeleteValidatorEvent; - handleStakeChange: ChangeValidatorEvent; - handleDelegatedStakeChange: ChangeValidatorEvent; - handlePFChange: ChangeValidatorEvent; - handleFCChange: ChangeValidatorEvent; - id: number; -}) { - return ( -
-
-
-
Validator {id + 1}
- - -
-
-
Stake:
- - handleStakeChange(toMicro(Number(e.target.value)), id) - } - > -
-
-
Delegated:
- - handleDelegatedStakeChange(toMicro(Number(e.target.value)), id) - } - > -
-
-
PF:
- handlePFChange(Number(e.target.value), id)} - > -
-
-
FC:
- handleFCChange(Number(e.target.value), id)} - > -
-
-
- ); -} - -function useResults(state: ManaCalculatorProps) { - const passiveRewards = calculatePassiveRewards( - state.stake, - state.initialEpoch, - state.finalEpoch, - ); - - let additionalTPS = calculateTPS(passiveRewards, state.congestion); - - if (state.userType == UserType.DELEGATOR) { - const manaGenerated = calculateManaRewards( - state.stake, - state.delegator.validator, - null, - state.validators, - state.initialEpoch, - state.finalEpoch, - state.userType, - getNetworkSupply(state.network), - ); - - let passiveRewards = calculatePassiveRewards( - state.stake, - state.initialEpoch, - state.finalEpoch, - ); - - let grantedTPS = calculateTPS(manaGenerated, state.congestion); - - let totalTPS = grantedTPS + additionalTPS; - - return { - manaGenerated, - passiveRewards, - totalTPS, - }; - } else { - const manaGenerated = calculateManaRewards( - state.stake, - state.delegator.validator, - { - performanceFactor: state.validator.performanceFactor, - fixedCost: state.validator.fixedCost, - shareOfYourStakeLocked: state.validator.shareOfYourStakeLocked, - attractedNewDelegatedStake: state.validator.attractedNewDelegatedStake, - attractedDelegatedStakeFromOtherPools: - state.validator.attractedDelegatedStakeFromOtherPools, - } as ValidatorParameters, - state.validators, - state.initialEpoch, - state.finalEpoch, - state.userType, - getNetworkSupply(state.network), - ); - - const grantedTPS = calculateTPS(manaGenerated, state.congestion); - - const totalTPS = grantedTPS + additionalTPS; - return { - manaGenerated, - passiveRewards, - totalTPS, - }; - } -} - -export default function ManaCalculator() { - const [state, setState] = useState(getDefaultParameters(NetworkType.IOTA)); - - function handleDelete(id: number) { - const validators = state.validators.filter((_, i) => i !== id); - setState({ ...state, validators }); - } - - function handleStakeChange(value: number, id: number) { - setState({ - ...state, - validators: state.validators.map((validator, i) => { - return { - ...validator, - lockedStake: i === id ? value : validator.lockedStake, - }; - }), - }); - } - - function handleDelegatedStakeChange(value: number, id: number) { - setState({ - ...state, - validators: state.validators.map((validator, i) => { - return { - ...validator, - delegatedStake: i === id ? value : validator.delegatedStake, - }; - }), - }); - } - - function handlePFChange(value: number, id: number) { - setState({ - ...state, - validators: state.validators.map((validator, i) => { - return { - ...validator, - performanceFactor: i === id ? value : validator.performanceFactor, - }; - }), - }); - } - - function handleFCChange(value: number, id: number) { - setState({ - ...state, - validators: state.validators.map((validator, i) => { - return { - ...validator, - fixedCost: i === id ? value : validator.fixedCost, - }; - }), - }); - } - - function handleOwnStakeChange(value: number) { - setState({ - ...state, - stake: value, - }); - } - - function handleValidatorChange(value: number) { - setState({ - ...state, - delegator: { ...state.delegator, validator: value }, - }); - } - - function handleCongestionChange(value: CongestionType) { - setState({ - ...state, - congestion: value, - }); - } - - function handleOwnPFChange(value: number) { - setState({ - ...state, - validator: { ...state.validator, performanceFactor: value }, - }); - } - - function handleOwnFCChange(value: number) { - setState({ - ...state, - validator: { ...state.validator, fixedCost: value }, - }); - } - - function handleShareOfYourStakeLockedChange(value: number) { - setState({ - ...state, - validator: { ...state.validator, shareOfYourStakeLocked: value }, - }); - } - - function handleAttractedNewDelegatedStakeChange(value: number) { - setState({ - ...state, - validator: { ...state.validator, attractedNewDelegatedStake: value }, - }); - } - - function handleAttractedDelegatedStakeFromOtherPoolsChange(value: number) { - setState({ - ...state, - validator: { - ...state.validator, - attractedDelegatedStakeFromOtherPools: value, - }, - }); - } - - function handleInitialEpochChange(value: number) { - setState({ - ...state, - initialEpoch: value, - }); - } - - function handleFinalEpochChange(value: number) { - setState({ - ...state, - finalEpoch: value, - }); - } - - function handleNetworkChange(value: NetworkType) { - setState({ - ...getDefaultParameters(value), - }); - } - - function handleUserChange(value: UserType) { - setState({ - ...state, - userType: value, - }); - } - - function handleAddValidator(value: ValidatorProps) { - state.validators.push(value); - setState({ ...state }); - } - - const results = useResults(state); - - return ( - <> - - - - -
- - - ); -} - -function AdvancedSettingsValidator({ - state, - handleAddValidator, - handleDelete, - handleDelegatedStakeChange, - handleFCChange, - handlePFChange, - handleStakeChange, -}: { - state: ManaCalculatorProps; - handleAddValidator: NewValidatorEvent; - handleDelete: DeleteValidatorEvent; - handleStakeChange: ChangeValidatorEvent; - handleDelegatedStakeChange: ChangeValidatorEvent; - handlePFChange: ChangeValidatorEvent; - handleFCChange: ChangeValidatorEvent; -}) { - function onAddValidator() { - handleAddValidator({ - lockedStake: 100, - delegatedStake: 0, - performanceFactor: 1.0, - fixedCost: 0.0, - }); - } - return ( -
-
- {state.validators.map((validator, i) => ( - - ))} -
-
- -
-
- ); -} - -function OtherParametersSection({ - state, - handleCongestionChange, - handleInitialEpochChange, - handleFinalEpochChange, -}: { - state: ManaCalculatorProps; - handleCongestionChange: ChangeEvent; - handleInitialEpochChange: ChangeEvent; - handleFinalEpochChange: ChangeEvent; -}) { - return ( -
-

Other parameters

- - handleInitialEpochChange(Number(e.target.value))} - > -
- - handleFinalEpochChange(Number(e.target.value))} - > -
- ); -} - -function RoleSection({ - state, - handleOwnStakeChange, - handleUserChange, - handleOwnPFChange, - handleShareOfYourStakeLockedChange, - handleAttractedNewDelegatedStakeChange, - handleAttractedDelegatedStakeFromOtherPoolsChange, - handleValidatorChange, - handleOwnFCChange, -}: { - state: ManaCalculatorProps; - handleOwnStakeChange: ChangeEvent; - handleUserChange: ChangeEvent; - handleOwnPFChange: ChangeEvent; - handleShareOfYourStakeLockedChange: ChangeEvent; - handleAttractedNewDelegatedStakeChange: ChangeEvent; - handleAttractedDelegatedStakeFromOtherPoolsChange: ChangeEvent; - handleValidatorChange: ChangeEvent; - handleOwnFCChange: ChangeEvent; -}) { - const validatorOptions = state.validators.map((_, i) => { - return { value: i, label: `Validator ${i + 1}` }; - }); - - return ( -
-

Role configuration

- - - handleOwnStakeChange(toMicro(Number(e.target.value))) - } - > -
- - - ) : ( - <> - - - handleOwnStakeChange(toMicro(Number(e.target.value))) - } - > - - )} -
- ); -} - -function NetworkSection({ - handleNetworkChange, -}: { - handleNetworkChange: ChangeEvent; -}) { - return ( -
-

Network configuration

- - handleOwnPFChange(Number(e.target.value))} - > -
- -
-
Fixed costs:
- handleOwnFCChange(Number(e.target.value))} - > -
-
-
Share of your stake locked:
- - handleShareOfYourStakeLockedChange(Number(e.target.value)) - } - > -
-
-
Attracted new delegated stake:
- - handleAttractedNewDelegatedStakeChange(Number(e.target.value)) - } - > -
-
-
- Attracted delegated stake from other pools: -
- - - handleAttractedDelegatedStakeFromOtherPoolsChange( - Number(e.target.value), - ) - } - > -
-
-
- ); -} - -function OutputForm({ - manaGeneratedPerEpoch, - passiveRewards, - totalTPS, -}: { - manaGeneratedPerEpoch: number; - passiveRewards: number; - totalTPS: number; -}) { - return ( -
-
-
Mana generation (by holding)
-
- {fromMicro(passiveRewards)} -
-
-
-
Mana rewards (delegation/validation)
-
- {fromMicro(manaGeneratedPerEpoch)} -
-
- -
-
Total TPS granted with
-
{totalTPS}
-
-
- ); -} diff --git a/src/components/ManaCalculator/types.ts b/src/components/ManaCalculator/types.ts deleted file mode 100644 index 2fa4f647652..00000000000 --- a/src/components/ManaCalculator/types.ts +++ /dev/null @@ -1,57 +0,0 @@ -export interface ValidatorProps { - lockedStake: number; - delegatedStake: number; - performanceFactor: number; - fixedCost: number; -} - -export interface ValidatorParameters { - shareOfYourStakeLocked: number; - attractedNewDelegatedStake: number; - attractedDelegatedStakeFromOtherPools: number; - fixedCost: number; - performanceFactor: number; -} - -export enum UserType { - DELEGATOR, - VALIDATOR, -} - -export enum NetworkType { - IOTA, - SHIMMER, -} - -export interface ManaCalculatorProps { - epoch: number; - initialEpoch: number; - finalEpoch: number; - validators: ValidatorProps[]; - userType: UserType; - congestion: CongestionType; - delegator: { - validator: number; - }; - validator: { - shareOfYourStakeLocked: number; - attractedNewDelegatedStake: number; - attractedDelegatedStakeFromOtherPools: number; - fixedCost: number; - performanceFactor: number; - }; - stake: number; - network: NetworkType; -} - -export enum CongestionType { - LOW = 100000, - MEDIUM = 9000000, - HIGH = 500000000, -} - -export type DeleteValidatorEvent = (id: number) => void; -export type ChangeValidatorEvent = (value: number, id: number) => void; -export type ChangeEvent = (value: number) => void; -export type ChangeCongestionEvent = (value: CongestionType) => void; -export type NewValidatorEvent = (value: ValidatorProps) => void; diff --git a/src/components/ManaCalculator/types/index.ts b/src/components/ManaCalculator/types/index.ts new file mode 100644 index 00000000000..c74baba6706 --- /dev/null +++ b/src/components/ManaCalculator/types/index.ts @@ -0,0 +1,2 @@ +export * from './mana-calculator.type'; +export * from './validator.type'; diff --git a/src/components/ManaCalculator/types/mana-calculator.type.ts b/src/components/ManaCalculator/types/mana-calculator.type.ts new file mode 100644 index 00000000000..7befb18e78c --- /dev/null +++ b/src/components/ManaCalculator/types/mana-calculator.type.ts @@ -0,0 +1,23 @@ +import { CongestionType, NetworkType, UserType } from '../enums'; +import { ValidatorProps } from './validator.type'; + +export interface ManaCalculatorProps { + epoch: number; + initialEpoch: number; + finalEpoch: number; + validators: ValidatorProps[]; + userType: UserType; + congestion: CongestionType; + delegator: { + validator: number; + }; + validator: { + shareOfYourStakeLocked: number; + attractedNewDelegatedStake: number; + attractedDelegatedStakeFromOtherPools: number; + fixedCost: number; + performanceFactor: number; + }; + stake: number; + network: NetworkType; +} diff --git a/src/components/ManaCalculator/types/validator.type.ts b/src/components/ManaCalculator/types/validator.type.ts new file mode 100644 index 00000000000..0de049520b5 --- /dev/null +++ b/src/components/ManaCalculator/types/validator.type.ts @@ -0,0 +1,14 @@ +export interface ValidatorProps { + lockedStake: number; + delegatedStake: number; + performanceFactor: number; + fixedCost: number; +} + +export interface ValidatorParameters { + shareOfYourStakeLocked: number; + attractedNewDelegatedStake: number; + attractedDelegatedStakeFromOtherPools: number; + fixedCost: number; + performanceFactor: number; +} diff --git a/src/components/ManaCalculator/utils.ts b/src/components/ManaCalculator/utils.ts index edde60260d5..02d17b1b40e 100644 --- a/src/components/ManaCalculator/utils.ts +++ b/src/components/ManaCalculator/utils.ts @@ -1,105 +1,29 @@ -import { NetworkType } from './types'; +import { IOTA_SUPPLY, SHIMMER_SUPPLY, SLOTS_IN_EPOCH } from './constants'; +import { NetworkType } from './enums'; -// Constants -const IOTA_SUPPLY = 4600000000000000; -const SHIMMER_SUPPLY = 1813620509000000; -const SLOT_DURATION = 10; -const SLOTS_IN_EPOCH = 8192; -export const EPOCH_DURATION = SLOTS_IN_EPOCH * SLOT_DURATION; -const SECONDS_IN_YEAR = 60 * 60 * 24 * 365; -const EPOCH_DURATION_IN_YEARS = EPOCH_DURATION / SECONDS_IN_YEAR; -const BETA_PER_YEAR = 1 / 3; -export const GENERATION_PER_SLOT = Math.pow(2, -17); -const BOOTSTRAPPING_DURATION = 1154; -const REWARDS_MANA_SHARE_COEFFICIENT = 2; -export const EPOCH = 1154 + 1; - -// given n in slots, returns the epoch that slot n belongs to -function slot_to_epoch(n: number): number { - const epoch = Math.floor(n / SLOTS_IN_EPOCH); +// Given a slot, returns the epoch that slot belongs to +export function slotToEpoch(slot: number): number { + const epoch = Math.floor(slot / SLOTS_IN_EPOCH); return epoch; } -// returns the first slot of epoch n -export function first_slot_of_epoch(n: number): number { - const slot = n * SLOTS_IN_EPOCH; +// Returns the first slot of the epoch +export function getFirstSlotOfEpoch(epoch: number): number { + const slot = epoch * SLOTS_IN_EPOCH; return slot; } -// returns the decayed value of value by n epochs -export function decay(value: number, n: number): number { - if (value != 0 && n != 0) { - const decay = Math.exp(-BETA_PER_YEAR * EPOCH_DURATION_IN_YEARS * n); - value = Math.floor(value * decay); - } - return value; -} - -// returns the potential mana generated by holding value tokens from creationSlot to consumptionSlot -export function potential_Mana( - value: number, - creationSlot: number, - consumptionSlot: number, - generationRate: number, -): number { - const i = slot_to_epoch(creationSlot); - const j = slot_to_epoch(consumptionSlot); - const n = j - i; - const slotAfterEpochi = first_slot_of_epoch(i + 1); - const firstSlotEpochJ = first_slot_of_epoch(j); - const d1 = slotAfterEpochi - creationSlot; - const d2 = consumptionSlot - firstSlotEpochJ; - let potentialMana = 0; - if (n == 0) { - potentialMana = value * (consumptionSlot - creationSlot) * generationRate; - } else if (n == 1) { - potentialMana = - value * d2 * generationRate + decay(value * d1 * generationRate, 1); - } else { - const c = - Math.exp(-BETA_PER_YEAR * EPOCH_DURATION_IN_YEARS) / - (1 - Math.exp(-BETA_PER_YEAR * EPOCH_DURATION_IN_YEARS)); - const aux = value * generationRate * c * SLOTS_IN_EPOCH; - const potentialMana_n = decay(value * d1 * generationRate, n); - const potentialMana_n_1 = decay(aux, n - 1); - const potentialMana_0 = value * d2 * generationRate + aux; - potentialMana = potentialMana_n - potentialMana_n_1 + potentialMana_0; - } - return potentialMana; -} - -// returns the target reward of a certain epoch n -export function targetReward(n: number, supply: number): number { - const finalReward = - supply * - REWARDS_MANA_SHARE_COEFFICIENT * - GENERATION_PER_SLOT * - SLOTS_IN_EPOCH; - const decayBalancingConstant = - Math.exp(1) / - (BOOTSTRAPPING_DURATION * - (1 - Math.exp(-EPOCH_DURATION_IN_YEARS * BETA_PER_YEAR))); - const initialReward = finalReward * decayBalancingConstant; - - let reward = 0; - if (n <= BOOTSTRAPPING_DURATION) { - reward = decay(initialReward, n); - } else { - reward = finalReward; - } - return reward; -} - -//returns The number of Mana/IOTA from micros +// Returns The number of Mana/IOTA from micros export function fromMicro(n: number): number { return n / 1_000_000; } -//returns The number of micro(Mana/IOTA). +// Returns The number of micro(Mana/IOTA). export function toMicro(n: number): number { return n * 1_000_000; } +// Returns the total supply given the network type export function getNetworkSupply(network: NetworkType): number { if (network == NetworkType.IOTA) { return IOTA_SUPPLY; From 09e1db93fd4431d4f2b0834fc4238d3a85b0df41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20Esp=C3=ADn?= Date: Mon, 6 Nov 2023 09:37:42 +0100 Subject: [PATCH 25/40] feat: Add user total holding input in Mana Calculator (#1316) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: Flexible network selector in the mana calculator * feat: Improved user flow for the Mana calculator * typo * chore: Refactor the Mana Calculator * :sparkles: * clean up * clean up * feat: Add user total holding input * fmt * fix * fix * fix * typos --------- Co-authored-by: Begoña Alvarez --- .../ManaCalculator/components/RoleSection.tsx | 12 ++++++++++-- .../ManaCalculator/hooks/useManaState.ts | 15 ++++++++++++--- src/components/ManaCalculator/hooks/useResults.ts | 6 +++--- .../ManaCalculator/types/mana-calculator.type.ts | 3 ++- 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/components/ManaCalculator/components/RoleSection.tsx b/src/components/ManaCalculator/components/RoleSection.tsx index 481c36d50c5..c4097ab4281 100644 --- a/src/components/ManaCalculator/components/RoleSection.tsx +++ b/src/components/ManaCalculator/components/RoleSection.tsx @@ -11,6 +11,7 @@ export function RoleSection() { handleOwnStakeChange, handleUserChange, handleValidatorChange, + handleOwnHoldChange, } = useManaState(); const validatorOptions = state.validators.map((_, i) => { return { value: i, label: `Validator ${i + 1}` }; @@ -33,12 +34,19 @@ export function RoleSection() { ]} />
+ + handleOwnHoldChange(toMicro(Number(e.target.value)))} + > +
{state.userType === UserType.VALIDATOR ? ( <> handleOwnStakeChange(toMicro(Number(e.target.value))) } @@ -62,7 +70,7 @@ export function RoleSection() { handleOwnStakeChange(toMicro(Number(e.target.value))) } diff --git a/src/components/ManaCalculator/hooks/useManaState.ts b/src/components/ManaCalculator/hooks/useManaState.ts index bc2a2dd256e..414b70a5d24 100644 --- a/src/components/ManaCalculator/hooks/useManaState.ts +++ b/src/components/ManaCalculator/hooks/useManaState.ts @@ -6,7 +6,10 @@ import { toMicro } from '../utils'; export const ManaStateContext = createContext(null); export function useManaState() { - const { setState, state } = useContext(ManaStateContext); + const { setState, state } = useContext<{ + setState: (state: ManaCalculatorProps) => void; + state: ManaCalculatorProps; + }>(ManaStateContext); function handleDelete(id: number) { const validators = state.validators.filter((_, i) => i !== id); @@ -64,7 +67,7 @@ export function useManaState() { function handleOwnStakeChange(value: number) { setState({ ...state, - stake: value, + stakedOrDelegatedTokens: value, }); } @@ -152,6 +155,10 @@ export function useManaState() { setState({ ...state }); } + function handleOwnHoldChange(value: number) { + setState({ ...state, heldTokens: value }); + } + return { state, handleDelete, @@ -172,6 +179,7 @@ export function useManaState() { handleOwnStakeChange, handlePFChange, handleValidatorChange, + handleOwnHoldChange, }; } @@ -203,7 +211,8 @@ export function getDefaultParameters( ], userType: UserType.DELEGATOR, congestion: CongestionType.LOW, - stake: toMicro(100), + stakedOrDelegatedTokens: toMicro(100), + heldTokens: toMicro(100), delegator: { validator: 0, }, diff --git a/src/components/ManaCalculator/hooks/useResults.ts b/src/components/ManaCalculator/hooks/useResults.ts index 5db9b07b6dc..cf68e0f9132 100644 --- a/src/components/ManaCalculator/hooks/useResults.ts +++ b/src/components/ManaCalculator/hooks/useResults.ts @@ -8,7 +8,7 @@ import { ManaCalculatorProps, ValidatorParameters } from '../types'; export function useResults(state: ManaCalculatorProps) { const passiveRewards = calculatePassiveRewards( - state.stake, + state.heldTokens, state.initialEpoch, state.finalEpoch, ); @@ -17,7 +17,7 @@ export function useResults(state: ManaCalculatorProps) { if (state.userType == UserType.DELEGATOR) { const manaGenerated = calculateManaRewards( - state.stake, + state.stakedOrDelegatedTokens, state.delegator.validator, null, state.validators, @@ -37,7 +37,7 @@ export function useResults(state: ManaCalculatorProps) { }; } else { const manaGenerated = calculateManaRewards( - state.stake, + state.stakedOrDelegatedTokens, state.delegator.validator, { performanceFactor: state.validator.performanceFactor, diff --git a/src/components/ManaCalculator/types/mana-calculator.type.ts b/src/components/ManaCalculator/types/mana-calculator.type.ts index 7befb18e78c..3b4ec3a46d6 100644 --- a/src/components/ManaCalculator/types/mana-calculator.type.ts +++ b/src/components/ManaCalculator/types/mana-calculator.type.ts @@ -18,6 +18,7 @@ export interface ManaCalculatorProps { fixedCost: number; performanceFactor: number; }; - stake: number; + stakedOrDelegatedTokens: number; + heldTokens: number; network: NetworkType; } From 67c2d3b508326867ab951a0cf768e81e724d38f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20Esp=C3=ADn?= Date: Mon, 6 Nov 2023 16:19:13 +0100 Subject: [PATCH 26/40] feat: Mana accumulation graph in Mana Calculator (#1317) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: Flexible network selector in the mana calculator * feat: Improved user flow for the Mana calculator * typo * chore: Refactor the Mana Calculator * :sparkles: * clean up * clean up * feat: Add user total holding input * feat: Mana accumulation graph * clean up * clean up * fmt * fix * fix * fix * improve graph * tweak * enhancement * Update src/components/ManaCalculator/hooks/useManaState.ts Co-authored-by: Dr-Electron * Update src/components/ManaCalculator/hooks/useManaState.ts Co-authored-by: Dr-Electron * fmt --------- Co-authored-by: Begoña Alvarez Co-authored-by: Dr-Electron --- package.json | 1 + .../components/ManaAcculation.tsx | 56 ++++ .../components/ManaCalculator.tsx | 2 + .../ManaCalculator/components/OutputForm.tsx | 2 +- .../ManaCalculator/components/index.ts | 1 + src/components/ManaCalculator/hooks/index.ts | 1 + .../ManaCalculator/hooks/useManaState.ts | 14 +- .../ManaCalculator/hooks/useResults.ts | 74 ++--- .../hooks/useResultsPerEpoch.ts | 52 +++ .../ManaCalculator/types/epoch-reward.type.ts | 4 + src/components/ManaCalculator/types/index.ts | 1 + yarn.lock | 299 +++++++++++++++++- 12 files changed, 456 insertions(+), 51 deletions(-) create mode 100644 src/components/ManaCalculator/components/ManaAcculation.tsx create mode 100644 src/components/ManaCalculator/hooks/useResultsPerEpoch.ts create mode 100644 src/components/ManaCalculator/types/epoch-reward.type.ts diff --git a/package.json b/package.json index 51292171830..cc6b0e9babb 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "react-player": "^2.11.2", "react-popper": "^2.3.0", "react-select": "^5.7.7", + "recharts": "^2.9.2", "rehype-jargon": "3.0.0", "rehype-katex": "4", "rehype-lodash-template": "^0.2.1", diff --git a/src/components/ManaCalculator/components/ManaAcculation.tsx b/src/components/ManaCalculator/components/ManaAcculation.tsx new file mode 100644 index 00000000000..c40404e2111 --- /dev/null +++ b/src/components/ManaCalculator/components/ManaAcculation.tsx @@ -0,0 +1,56 @@ +import React from 'react'; +import { useManaState, useResultsPerEpoch } from '../hooks'; +import { + Area, + AreaChart, + CartesianGrid, + ResponsiveContainer, + Tooltip, + XAxis, + YAxis, +} from 'recharts'; + +export function ManaAccumulation() { + const { state } = useManaState(); + const results = useResultsPerEpoch(state); + + return ( +
+
+

Mana Accumulation

+ + + + + + + + + + + + + + + + + + + +
+ ); +} diff --git a/src/components/ManaCalculator/components/ManaCalculator.tsx b/src/components/ManaCalculator/components/ManaCalculator.tsx index ec7be0c1802..7e0a15e29ed 100644 --- a/src/components/ManaCalculator/components/ManaCalculator.tsx +++ b/src/components/ManaCalculator/components/ManaCalculator.tsx @@ -8,6 +8,7 @@ import { AdvancedSettingsValidator, RoleSection, OtherParametersSection, + ManaAccumulation, } from './'; export function ManaCalculator() { @@ -21,6 +22,7 @@ export function ManaCalculator() {
+ ); } diff --git a/src/components/ManaCalculator/components/OutputForm.tsx b/src/components/ManaCalculator/components/OutputForm.tsx index 59a068571f1..0a32f742614 100644 --- a/src/components/ManaCalculator/components/OutputForm.tsx +++ b/src/components/ManaCalculator/components/OutputForm.tsx @@ -14,7 +14,7 @@ export function OutputForm() {
-
Mana rewards (delegation/validation)
+
Mana rewards
{fromMicro(manaGenerated)}
diff --git a/src/components/ManaCalculator/components/index.ts b/src/components/ManaCalculator/components/index.ts index 145cf01d52a..dfac57d8bbb 100644 --- a/src/components/ManaCalculator/components/index.ts +++ b/src/components/ManaCalculator/components/index.ts @@ -6,3 +6,4 @@ export * from './ValidatorSettings'; export * from './RoleSection'; export * from './OutputForm'; export * from './NetworkSection'; +export * from './ManaAcculation'; diff --git a/src/components/ManaCalculator/hooks/index.ts b/src/components/ManaCalculator/hooks/index.ts index 21d29e89070..1276d5e5c29 100644 --- a/src/components/ManaCalculator/hooks/index.ts +++ b/src/components/ManaCalculator/hooks/index.ts @@ -1,2 +1,3 @@ export * from './useManaState'; export * from './useResults'; +export * from './useResultsPerEpoch'; diff --git a/src/components/ManaCalculator/hooks/useManaState.ts b/src/components/ManaCalculator/hooks/useManaState.ts index 414b70a5d24..7ed14f8aae6 100644 --- a/src/components/ManaCalculator/hooks/useManaState.ts +++ b/src/components/ManaCalculator/hooks/useManaState.ts @@ -186,9 +186,19 @@ export function useManaState() { export function getDefaultParameters( network: NetworkType, ): ManaCalculatorProps { + const networkParams = { + [NetworkType.IOTA]: { + initialEpoch: 1, + finalEpoch: 365, + }, + [NetworkType.SHIMMER]: { + initialEpoch: 1, + finalEpoch: 1000, + }, + }; + return { - initialEpoch: 0, - finalEpoch: 100, + ...networkParams[network], validators: [ { lockedStake: toMicro(100), diff --git a/src/components/ManaCalculator/hooks/useResults.ts b/src/components/ManaCalculator/hooks/useResults.ts index cf68e0f9132..8e6df3ef0bb 100644 --- a/src/components/ManaCalculator/hooks/useResults.ts +++ b/src/components/ManaCalculator/hooks/useResults.ts @@ -15,52 +15,36 @@ export function useResults(state: ManaCalculatorProps) { const additionalTPS = calculateTPS(passiveRewards, state.congestion); - if (state.userType == UserType.DELEGATOR) { - const manaGenerated = calculateManaRewards( - state.stakedOrDelegatedTokens, - state.delegator.validator, - null, - state.validators, - state.initialEpoch, - state.finalEpoch, - state.userType, - state.network, - ); + const validatorParameters = + state.userType === UserType.VALIDATOR + ? ({ + performanceFactor: state.validator.performanceFactor, + fixedCost: state.validator.fixedCost, + shareOfYourStakeLocked: state.validator.shareOfYourStakeLocked, + attractedNewDelegatedStake: + state.validator.attractedNewDelegatedStake, + attractedDelegatedStakeFromOtherPools: + state.validator.attractedDelegatedStakeFromOtherPools, + } as ValidatorParameters) + : null; - const grantedTPS = calculateTPS(manaGenerated, state.congestion); - const totalTPS = grantedTPS + additionalTPS; - - return { - manaGenerated, - passiveRewards, - totalTPS, - }; - } else { - const manaGenerated = calculateManaRewards( - state.stakedOrDelegatedTokens, - state.delegator.validator, - { - performanceFactor: state.validator.performanceFactor, - fixedCost: state.validator.fixedCost, - shareOfYourStakeLocked: state.validator.shareOfYourStakeLocked, - attractedNewDelegatedStake: state.validator.attractedNewDelegatedStake, - attractedDelegatedStakeFromOtherPools: - state.validator.attractedDelegatedStakeFromOtherPools, - } as ValidatorParameters, - state.validators, - state.initialEpoch, - state.finalEpoch, - state.userType, - state.network, - ); + const manaGenerated = calculateManaRewards( + state.stakedOrDelegatedTokens, + state.delegator.validator, + validatorParameters, + state.validators, + state.initialEpoch, + state.finalEpoch, + state.userType, + state.network, + ); - const grantedTPS = calculateTPS(manaGenerated, state.congestion); - const totalTPS = grantedTPS + additionalTPS; + const grantedTPS = calculateTPS(manaGenerated, state.congestion); + const totalTPS = grantedTPS + additionalTPS; - return { - manaGenerated, - passiveRewards, - totalTPS, - }; - } + return { + manaGenerated, + passiveRewards, + totalTPS, + }; } diff --git a/src/components/ManaCalculator/hooks/useResultsPerEpoch.ts b/src/components/ManaCalculator/hooks/useResultsPerEpoch.ts new file mode 100644 index 00000000000..a76eb498468 --- /dev/null +++ b/src/components/ManaCalculator/hooks/useResultsPerEpoch.ts @@ -0,0 +1,52 @@ +import { calculateManaRewards, calculatePassiveRewards } from '../actions'; +import { UserType } from '../enums'; +import { + EpochReward, + ManaCalculatorProps, + ValidatorParameters, +} from '../types'; +import { fromMicro } from '../utils'; + +export function useResultsPerEpoch(state: ManaCalculatorProps): EpochReward[] { + const validatorParameters = + state.userType === UserType.VALIDATOR + ? ({ + performanceFactor: state.validator.performanceFactor, + fixedCost: state.validator.fixedCost, + shareOfYourStakeLocked: state.validator.shareOfYourStakeLocked, + attractedNewDelegatedStake: + state.validator.attractedNewDelegatedStake, + attractedDelegatedStakeFromOtherPools: + state.validator.attractedDelegatedStakeFromOtherPools, + } as ValidatorParameters) + : null; + const results = []; + + for (let i = state.initialEpoch; i <= state.finalEpoch; i++) { + const generatedMana = calculateManaRewards( + state.stakedOrDelegatedTokens, + state.delegator.validator, + validatorParameters, + state.validators, + state.initialEpoch, + i, + state.userType, + state.network, + ); + + const passiveRewards = calculatePassiveRewards( + state.heldTokens, + state.initialEpoch, + i, + ); + + const mana = generatedMana + passiveRewards; + + results.push({ + epoch: i, + mana: fromMicro(mana) / 1_000_000, + }); + } + + return results; +} diff --git a/src/components/ManaCalculator/types/epoch-reward.type.ts b/src/components/ManaCalculator/types/epoch-reward.type.ts new file mode 100644 index 00000000000..5b7d6e68c1c --- /dev/null +++ b/src/components/ManaCalculator/types/epoch-reward.type.ts @@ -0,0 +1,4 @@ +export interface EpochReward { + epoch: number; + mana: number; +} diff --git a/src/components/ManaCalculator/types/index.ts b/src/components/ManaCalculator/types/index.ts index c74baba6706..fc5735a62c3 100644 --- a/src/components/ManaCalculator/types/index.ts +++ b/src/components/ManaCalculator/types/index.ts @@ -1,2 +1,3 @@ export * from './mana-calculator.type'; export * from './validator.type'; +export * from './epoch-reward.type'; diff --git a/yarn.lock b/yarn.lock index 8e0e83f84f8..f6317172ba7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2845,6 +2845,7 @@ __metadata: react-player: ^2.11.2 react-popper: ^2.3.0 react-select: ^5.7.7 + recharts: ^2.9.2 rehype-jargon: 3.0.0 rehype-katex: 4 rehype-lodash-template: ^0.2.1 @@ -4678,6 +4679,75 @@ __metadata: languageName: node linkType: hard +"@types/d3-array@npm:^3.0.3": + version: 3.0.9 + resolution: "@types/d3-array@npm:3.0.9" + checksum: 5845a39e1c1063664bce6f1f2640ea54ed9f6ce81f3a72b1770fc58a8bd62131abfeb53b4af84b8bde36696adb87023a04d0876d7059b98fb07fb139248c7769 + languageName: node + linkType: hard + +"@types/d3-color@npm:*": + version: 3.1.2 + resolution: "@types/d3-color@npm:3.1.2" + checksum: e8f445a2b8c49f4f6ce53ef6bf49858902947936097140e6773411deb80db694cb2103ca62363aebf5a690986470a498756199473cd8ab056c3b79bc881eca0e + languageName: node + linkType: hard + +"@types/d3-ease@npm:^3.0.0": + version: 3.0.1 + resolution: "@types/d3-ease@npm:3.0.1" + checksum: 2b6d98a9d9f3e25b2268633fcc3d936ca6071c7f34e739e3985215fcd7bbda17bcaae98ac9ed0c0637ca2d5b906dc46326ef5a4d9926be46b46b9f321449a0b9 + languageName: node + linkType: hard + +"@types/d3-interpolate@npm:^3.0.1": + version: 3.0.3 + resolution: "@types/d3-interpolate@npm:3.0.3" + dependencies: + "@types/d3-color": "*" + checksum: 57b6c83f109a33fff8bfc7265e4cfe6608f7509d6479808176518b115fa5f245b94f4d77bf4677218e41d48585a331cef54c1a5cb9ce5d1b5d7226b4d453f0a0 + languageName: node + linkType: hard + +"@types/d3-path@npm:*": + version: 3.0.1 + resolution: "@types/d3-path@npm:3.0.1" + checksum: 27bdf617166abb08a12d147d5d1e508598a953636cc9e963c3553daf4acbdee0dbce6df0930e56fddabdddc4d421f97e9639eabeb8a27795fcf9845c6a46c3b4 + languageName: node + linkType: hard + +"@types/d3-scale@npm:^4.0.2": + version: 4.0.6 + resolution: "@types/d3-scale@npm:4.0.6" + dependencies: + "@types/d3-time": "*" + checksum: 1c76c74b0333e8a1e0a2e45d26a22a448808b5381f72359b4442d02d7c77dae976c03559569e8347635adfa77fe781a70717e331b819064aeea7b9e24028c1aa + languageName: node + linkType: hard + +"@types/d3-shape@npm:^3.1.0": + version: 3.1.4 + resolution: "@types/d3-shape@npm:3.1.4" + dependencies: + "@types/d3-path": "*" + checksum: 3d529cc96127d8d58da05bc602e51bb7946171bdae96dcce9dae81c1549d3fd3f226a4e651c3302951a1ebf7803e86388c4afcdd654b0d40d203219ce68eb383 + languageName: node + linkType: hard + +"@types/d3-time@npm:*, @types/d3-time@npm:^3.0.0": + version: 3.0.2 + resolution: "@types/d3-time@npm:3.0.2" + checksum: c70538a22902f72aef9d0237c120859cec38bd20fd839870f81d8a81f155aa5876a180fae691a75e9c8e427172d3d3f8a8ef9e8c8c2a8202b24c1d801193c5e7 + languageName: node + linkType: hard + +"@types/d3-timer@npm:^3.0.0": + version: 3.0.1 + resolution: "@types/d3-timer@npm:3.0.1" + checksum: e6b986d2e397ea38babd6799b52fb46b5d8554e2a383a8d551b803996a6470032e5c57a92ff961c5fdef71ce2b34ff206b42e9e337edc3b331b898c06d73062b + languageName: node + linkType: hard + "@types/debug@npm:^4.0.0": version: 4.1.8 resolution: "@types/debug@npm:4.1.8" @@ -6824,6 +6894,13 @@ __metadata: languageName: node linkType: hard +"classnames@npm:^2.2.5": + version: 2.3.2 + resolution: "classnames@npm:2.3.2" + checksum: 2c62199789618d95545c872787137262e741f9db13328e216b093eea91c85ef2bfb152c1f9e63027204e2559a006a92eb74147d46c800a9f96297ae1d9f96f4e + languageName: node + linkType: hard + "clean-css@npm:^5.2.2, clean-css@npm:^5.3.0": version: 5.3.2 resolution: "clean-css@npm:5.3.2" @@ -7777,6 +7854,99 @@ __metadata: languageName: node linkType: hard +"d3-array@npm:2 - 3, d3-array@npm:2.10.0 - 3, d3-array@npm:^3.1.6": + version: 3.2.4 + resolution: "d3-array@npm:3.2.4" + dependencies: + internmap: 1 - 2 + checksum: a5976a6d6205f69208478bb44920dd7ce3e788c9dceb86b304dbe401a4bfb42ecc8b04c20facde486e9adcb488b5d1800d49393a3f81a23902b68158e12cddd0 + languageName: node + linkType: hard + +"d3-color@npm:1 - 3": + version: 3.1.0 + resolution: "d3-color@npm:3.1.0" + checksum: 4931fbfda5d7c4b5cfa283a13c91a954f86e3b69d75ce588d06cde6c3628cebfc3af2069ccf225e982e8987c612aa7948b3932163ce15eb3c11cd7c003f3ee3b + languageName: node + linkType: hard + +"d3-ease@npm:^3.0.1": + version: 3.0.1 + resolution: "d3-ease@npm:3.0.1" + checksum: 06e2ee5326d1e3545eab4e2c0f84046a123dcd3b612e68858219aa034da1160333d9ce3da20a1d3486d98cb5c2a06f7d233eee1bc19ce42d1533458bd85dedcd + languageName: node + linkType: hard + +"d3-format@npm:1 - 3": + version: 3.1.0 + resolution: "d3-format@npm:3.1.0" + checksum: f345ec3b8ad3cab19bff5dead395bd9f5590628eb97a389b1dd89f0b204c7c4fc1d9520f13231c2c7cf14b7c9a8cf10f8ef15bde2befbab41454a569bd706ca2 + languageName: node + linkType: hard + +"d3-interpolate@npm:1.2.0 - 3, d3-interpolate@npm:^3.0.1": + version: 3.0.1 + resolution: "d3-interpolate@npm:3.0.1" + dependencies: + d3-color: 1 - 3 + checksum: a42ba314e295e95e5365eff0f604834e67e4a3b3c7102458781c477bd67e9b24b6bb9d8e41ff5521050a3f2c7c0c4bbbb6e187fd586daa3980943095b267e78b + languageName: node + linkType: hard + +"d3-path@npm:^3.1.0": + version: 3.1.0 + resolution: "d3-path@npm:3.1.0" + checksum: 2306f1bd9191e1eac895ec13e3064f732a85f243d6e627d242a313f9777756838a2215ea11562f0c7630c7c3b16a19ec1fe0948b1c82f3317fac55882f6ee5d8 + languageName: node + linkType: hard + +"d3-scale@npm:^4.0.2": + version: 4.0.2 + resolution: "d3-scale@npm:4.0.2" + dependencies: + d3-array: 2.10.0 - 3 + d3-format: 1 - 3 + d3-interpolate: 1.2.0 - 3 + d3-time: 2.1.1 - 3 + d3-time-format: 2 - 4 + checksum: a9c770d283162c3bd11477c3d9d485d07f8db2071665f1a4ad23eec3e515e2cefbd369059ec677c9ac849877d1a765494e90e92051d4f21111aa56791c98729e + languageName: node + linkType: hard + +"d3-shape@npm:^3.1.0": + version: 3.2.0 + resolution: "d3-shape@npm:3.2.0" + dependencies: + d3-path: ^3.1.0 + checksum: de2af5fc9a93036a7b68581ca0bfc4aca2d5a328aa7ba7064c11aedd44d24f310c20c40157cb654359d4c15c3ef369f95ee53d71221017276e34172c7b719cfa + languageName: node + linkType: hard + +"d3-time-format@npm:2 - 4": + version: 4.1.0 + resolution: "d3-time-format@npm:4.1.0" + dependencies: + d3-time: 1 - 3 + checksum: 7342bce28355378152bbd4db4e275405439cabba082d9cd01946d40581140481c8328456d91740b0fe513c51ec4a467f4471ffa390c7e0e30ea30e9ec98fcdf4 + languageName: node + linkType: hard + +"d3-time@npm:1 - 3, d3-time@npm:2.1.1 - 3, d3-time@npm:^3.0.0": + version: 3.1.0 + resolution: "d3-time@npm:3.1.0" + dependencies: + d3-array: 2 - 3 + checksum: 613b435352a78d9f31b7f68540788186d8c331b63feca60ad21c88e9db1989fe888f97f242322ebd6365e45ec3fb206a4324cd4ca0dfffa1d9b5feb856ba00a7 + languageName: node + linkType: hard + +"d3-timer@npm:^3.0.1": + version: 3.0.1 + resolution: "d3-timer@npm:3.0.1" + checksum: 1cfddf86d7bca22f73f2c427f52dfa35c49f50d64e187eb788dcad6e927625c636aa18ae4edd44d084eb9d1f81d8ca4ec305dae7f733c15846a824575b789d73 + languageName: node + linkType: hard + "debug@npm:2.6.9, debug@npm:^2.6.0": version: 2.6.9 resolution: "debug@npm:2.6.9" @@ -7814,6 +7984,13 @@ __metadata: languageName: node linkType: hard +"decimal.js-light@npm:^2.4.1": + version: 2.5.1 + resolution: "decimal.js-light@npm:2.5.1" + checksum: f5a2c7eac1c4541c8ab8a5c8abea64fc1761cefc7794bd5f8afd57a8a78d1b51785e0c4e4f85f4895a043eaa90ddca1edc3981d1263eb6ddce60f32bf5fe66c9 + languageName: node + linkType: hard + "decode-named-character-reference@npm:^1.0.0": version: 1.0.2 resolution: "decode-named-character-reference@npm:1.0.2" @@ -8189,6 +8366,15 @@ __metadata: languageName: node linkType: hard +"dom-helpers@npm:^3.4.0": + version: 3.4.0 + resolution: "dom-helpers@npm:3.4.0" + dependencies: + "@babel/runtime": ^7.1.2 + checksum: 58d9f1c4a96daf77eddc63ae1236b826e1cddd6db66bbf39b18d7e21896d99365b376593352d52a60969d67fa4a8dbef26adc1439fa2c1b355efa37cacbaf637 + languageName: node + linkType: hard + "dom-helpers@npm:^5.0.1, dom-helpers@npm:^5.2.1": version: 5.2.1 resolution: "dom-helpers@npm:5.2.1" @@ -8883,7 +9069,7 @@ __metadata: languageName: node linkType: hard -"eventemitter3@npm:^4.0.0": +"eventemitter3@npm:^4.0.0, eventemitter3@npm:^4.0.1": version: 4.0.7 resolution: "eventemitter3@npm:4.0.7" checksum: 1875311c42fcfe9c707b2712c32664a245629b42bb0a5a84439762dd0fd637fc54d078155ea83c2af9e0323c9ac13687e03cfba79b03af9f40c89b4960099374 @@ -9017,6 +9203,13 @@ __metadata: languageName: node linkType: hard +"fast-equals@npm:^5.0.0": + version: 5.0.1 + resolution: "fast-equals@npm:5.0.1" + checksum: fbb3b6a74f3a0fa930afac151ff7d01639159b4fddd2678b5d50708e0ba38e9ec14602222d10dadb8398187342692c04fbef5a62b1cfcc7942fe03e754e064bc + languageName: node + linkType: hard + "fast-glob@npm:^3.2.11, fast-glob@npm:^3.2.2, fast-glob@npm:^3.2.9, fast-glob@npm:^3.3.0": version: 3.3.0 resolution: "fast-glob@npm:3.3.0" @@ -10810,6 +11003,13 @@ __metadata: languageName: node linkType: hard +"internmap@npm:1 - 2": + version: 2.0.3 + resolution: "internmap@npm:2.0.3" + checksum: 7ca41ec6aba8f0072fc32fa8a023450a9f44503e2d8e403583c55714b25efd6390c38a87161ec456bf42d7bc83aab62eb28f5aef34876b1ac4e60693d5e1d241 + languageName: node + linkType: hard + "interpret@npm:^1.0.0": version: 1.4.0 resolution: "interpret@npm:1.4.0" @@ -15109,7 +15309,7 @@ plugin-image-zoom@flexanalytics/plugin-image-zoom: languageName: node linkType: hard -"react-is@npm:^16.13.1, react-is@npm:^16.6.0, react-is@npm:^16.7.0": +"react-is@npm:^16.10.2, react-is@npm:^16.13.1, react-is@npm:^16.6.0, react-is@npm:^16.7.0": version: 16.13.1 resolution: "react-is@npm:16.13.1" checksum: f7a19ac3496de32ca9ae12aa030f00f14a3d45374f1ceca0af707c831b2a6098ef0d6bdae51bd437b0a306d7f01d4677fcc8de7c0d331eb47ad0f46130e53c5f @@ -15320,6 +15520,18 @@ plugin-image-zoom@flexanalytics/plugin-image-zoom: languageName: node linkType: hard +"react-resize-detector@npm:^8.0.4": + version: 8.1.0 + resolution: "react-resize-detector@npm:8.1.0" + dependencies: + lodash: ^4.17.21 + peerDependencies: + react: ^16.0.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 + checksum: 45e6b87ea7331406bed2a806d0cea98c1467d53a7cfcdf19c2dd55a3460047917d3b175d9cceea6f314b65eb54858cbb981acffd007d67aa16388e517dafb83e + languageName: node + linkType: hard + "react-router-config@npm:^5.1.1": version: 5.1.1 resolution: "react-router-config@npm:5.1.1" @@ -15388,6 +15600,20 @@ plugin-image-zoom@flexanalytics/plugin-image-zoom: languageName: node linkType: hard +"react-smooth@npm:^2.0.4": + version: 2.0.5 + resolution: "react-smooth@npm:2.0.5" + dependencies: + fast-equals: ^5.0.0 + react-transition-group: 2.9.0 + peerDependencies: + prop-types: ^15.6.0 + react: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 + react-dom: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 + checksum: 914c17f741e8b533ff6e3d5e3285aea0625cdd0f98e04202d01351f9516dbdc0a0e297dc22cc2377d6916fb819da8d4ed999c0314a4c186592ca51870012e6f7 + languageName: node + linkType: hard + "react-textarea-autosize@npm:^8.3.2": version: 8.5.2 resolution: "react-textarea-autosize@npm:8.5.2" @@ -15401,6 +15627,21 @@ plugin-image-zoom@flexanalytics/plugin-image-zoom: languageName: node linkType: hard +"react-transition-group@npm:2.9.0": + version: 2.9.0 + resolution: "react-transition-group@npm:2.9.0" + dependencies: + dom-helpers: ^3.4.0 + loose-envify: ^1.4.0 + prop-types: ^15.6.2 + react-lifecycles-compat: ^3.0.4 + peerDependencies: + react: ">=15.0.0" + react-dom: ">=15.0.0" + checksum: d8c9e50aabdc2cfc324e5cdb0ad1c6eecb02e1c0cd007b26d5b30ccf49015e900683dd489348c71fba4055858308d9ba7019e0d37d0e8d37bd46ed098788f670 + languageName: node + linkType: hard + "react-transition-group@npm:^4.3.0, react-transition-group@npm:^4.4.2": version: 4.4.5 resolution: "react-transition-group@npm:4.4.5" @@ -15502,6 +15743,36 @@ plugin-image-zoom@flexanalytics/plugin-image-zoom: languageName: node linkType: hard +"recharts-scale@npm:^0.4.4": + version: 0.4.5 + resolution: "recharts-scale@npm:0.4.5" + dependencies: + decimal.js-light: ^2.4.1 + checksum: e970377190a610e684a32c7461c7684ac3603c2e0ac0020bbba1eea9d099b38138143a8e80bf769bb49c0b7cecf22a2f5c6854885efed2d56f4540d4aa7052bd + languageName: node + linkType: hard + +"recharts@npm:^2.9.2": + version: 2.9.2 + resolution: "recharts@npm:2.9.2" + dependencies: + classnames: ^2.2.5 + eventemitter3: ^4.0.1 + lodash: ^4.17.19 + react-is: ^16.10.2 + react-resize-detector: ^8.0.4 + react-smooth: ^2.0.4 + recharts-scale: ^0.4.4 + tiny-invariant: ^1.3.1 + victory-vendor: ^36.6.8 + peerDependencies: + prop-types: ^15.6.0 + react: ^16.0.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 + checksum: 77a87e3d91229ac5400240409568e3345ded50fc117e70e43e61a135b44bbc3164048704393aa988201ea2989278e1c4e96ce350f6a2f87044d1f0a48f290e84 + languageName: node + linkType: hard + "rechoir@npm:^0.6.2": version: 0.6.2 resolution: "rechoir@npm:0.6.2" @@ -17393,7 +17664,7 @@ plugin-image-zoom@flexanalytics/plugin-image-zoom: languageName: node linkType: hard -"tiny-invariant@npm:^1.0.2": +"tiny-invariant@npm:^1.0.2, tiny-invariant@npm:^1.3.1": version: 1.3.1 resolution: "tiny-invariant@npm:1.3.1" checksum: 872dbd1ff20a21303a2fd20ce3a15602cfa7fcf9b228bd694a52e2938224313b5385a1078cb667ed7375d1612194feaca81c4ecbe93121ca1baebe344de4f84c @@ -18569,6 +18840,28 @@ plugin-image-zoom@flexanalytics/plugin-image-zoom: languageName: node linkType: hard +"victory-vendor@npm:^36.6.8": + version: 36.6.11 + resolution: "victory-vendor@npm:36.6.11" + dependencies: + "@types/d3-array": ^3.0.3 + "@types/d3-ease": ^3.0.0 + "@types/d3-interpolate": ^3.0.1 + "@types/d3-scale": ^4.0.2 + "@types/d3-shape": ^3.1.0 + "@types/d3-time": ^3.0.0 + "@types/d3-timer": ^3.0.0 + d3-array: ^3.1.6 + d3-ease: ^3.0.1 + d3-interpolate: ^3.0.1 + d3-scale: ^4.0.2 + d3-shape: ^3.1.0 + d3-time: ^3.0.0 + d3-timer: ^3.0.1 + checksum: 55800076dfa6abedf7758840986a302778a904678d4b66fe47d977c48b6f9484276b780871e6e5105b31c1eb936e9f1331ee39afcc2869bf65ceb7d456143172 + languageName: node + linkType: hard + "vm-browserify@npm:^1.1.2": version: 1.1.2 resolution: "vm-browserify@npm:1.1.2" From b0f1dc7fa61d9b0b6e083ca58ec227fadfa70468 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20Esp=C3=ADn?= Date: Mon, 6 Nov 2023 16:50:21 +0100 Subject: [PATCH 27/40] feat: Block issuance rate graph in Mana Calculator (#1318) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: Flexible network selector in the mana calculator * feat: Improved user flow for the Mana calculator * typo * chore: Refactor the Mana Calculator * :sparkles: * clean up * clean up * feat: Add user total holding input * feat: Mana accumulation graph * feat: Block issuance rate graph * clean up * network params * clean up * clean up * fmt * prettify * typo * fix * fix * fix * improve graph * tweak * enhancement * Update src/components/ManaCalculator/hooks/useManaState.ts Co-authored-by: Dr-Electron * Update src/components/ManaCalculator/hooks/useManaState.ts Co-authored-by: Dr-Electron * fmt * clean up * fmt --------- Co-authored-by: Begoña Alvarez Co-authored-by: Dr-Electron --- .../components/BlocksAllowance.tsx | 51 +++++++++++++++++++ .../components/ManaAcculation.tsx | 20 +++----- .../components/ManaCalculator.tsx | 11 +++- .../ManaCalculator/components/index.ts | 1 + .../hooks/useResultsPerEpoch.ts | 18 +++++-- 5 files changed, 84 insertions(+), 17 deletions(-) create mode 100644 src/components/ManaCalculator/components/BlocksAllowance.tsx diff --git a/src/components/ManaCalculator/components/BlocksAllowance.tsx b/src/components/ManaCalculator/components/BlocksAllowance.tsx new file mode 100644 index 00000000000..724d3be3dc5 --- /dev/null +++ b/src/components/ManaCalculator/components/BlocksAllowance.tsx @@ -0,0 +1,51 @@ +import React from 'react'; +import { + Area, + AreaChart, + CartesianGrid, + ResponsiveContainer, + Tooltip, + XAxis, + YAxis, +} from 'recharts'; +import { EpochReward } from '../types'; + +export function BlocksAllowance({ results }: { results: EpochReward[] }) { + return ( +
+
+

Blocks Allowance

+ + + + + + + + + + + + + + + +
+ ); +} diff --git a/src/components/ManaCalculator/components/ManaAcculation.tsx b/src/components/ManaCalculator/components/ManaAcculation.tsx index c40404e2111..f7e9e1a7f03 100644 --- a/src/components/ManaCalculator/components/ManaAcculation.tsx +++ b/src/components/ManaCalculator/components/ManaAcculation.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import { useManaState, useResultsPerEpoch } from '../hooks'; import { Area, AreaChart, @@ -9,11 +8,9 @@ import { XAxis, YAxis, } from 'recharts'; +import { EpochReward } from '../types'; -export function ManaAccumulation() { - const { state } = useManaState(); - const results = useResultsPerEpoch(state); - +export function ManaAccumulation({ results }: { results: EpochReward[] }) { return (

@@ -21,14 +18,10 @@ export function ManaAccumulation() { - + - - - - - + diff --git a/src/components/ManaCalculator/components/ManaCalculator.tsx b/src/components/ManaCalculator/components/ManaCalculator.tsx index 7e0a15e29ed..320527574f9 100644 --- a/src/components/ManaCalculator/components/ManaCalculator.tsx +++ b/src/components/ManaCalculator/components/ManaCalculator.tsx @@ -1,7 +1,11 @@ import React, { useState } from 'react'; import '../styles.css'; import { NetworkType } from '../enums'; -import { getDefaultParameters, ManaStateContext } from '../hooks'; +import { + getDefaultParameters, + ManaStateContext, + useResultsPerEpoch, +} from '../hooks'; import { OutputForm, NetworkSection, @@ -9,10 +13,12 @@ import { RoleSection, OtherParametersSection, ManaAccumulation, + BlocksAllowance, } from './'; export function ManaCalculator() { const [state, setState] = useState(getDefaultParameters(NetworkType.IOTA)); + const results = useResultsPerEpoch(state); return ( @@ -22,7 +28,8 @@ export function ManaCalculator() {
- + +
); } diff --git a/src/components/ManaCalculator/components/index.ts b/src/components/ManaCalculator/components/index.ts index dfac57d8bbb..144baf9e54b 100644 --- a/src/components/ManaCalculator/components/index.ts +++ b/src/components/ManaCalculator/components/index.ts @@ -7,3 +7,4 @@ export * from './RoleSection'; export * from './OutputForm'; export * from './NetworkSection'; export * from './ManaAcculation'; +export * from './BlocksAllowance'; diff --git a/src/components/ManaCalculator/hooks/useResultsPerEpoch.ts b/src/components/ManaCalculator/hooks/useResultsPerEpoch.ts index a76eb498468..8126d308776 100644 --- a/src/components/ManaCalculator/hooks/useResultsPerEpoch.ts +++ b/src/components/ManaCalculator/hooks/useResultsPerEpoch.ts @@ -1,4 +1,8 @@ -import { calculateManaRewards, calculatePassiveRewards } from '../actions'; +import { + calculateManaRewards, + calculatePassiveRewards, + calculateTPS, +} from '../actions'; import { UserType } from '../enums'; import { EpochReward, @@ -23,7 +27,7 @@ export function useResultsPerEpoch(state: ManaCalculatorProps): EpochReward[] { const results = []; for (let i = state.initialEpoch; i <= state.finalEpoch; i++) { - const generatedMana = calculateManaRewards( + const manaGenerated = calculateManaRewards( state.stakedOrDelegatedTokens, state.delegator.validator, validatorParameters, @@ -40,11 +44,19 @@ export function useResultsPerEpoch(state: ManaCalculatorProps): EpochReward[] { i, ); - const mana = generatedMana + passiveRewards; + const mana = manaGenerated + passiveRewards; + + const tpsFromPassiveRewards = calculateTPS( + passiveRewards, + state.congestion, + ); + const tpsFromGeneratedMana = calculateTPS(manaGenerated, state.congestion); + const totalTps = tpsFromPassiveRewards + tpsFromGeneratedMana; results.push({ epoch: i, mana: fromMicro(mana) / 1_000_000, + totalTps, }); } From f2182f268086cf2067214d836a506db263fb7da5 Mon Sep 17 00:00:00 2001 From: Dr-Electron Date: Tue, 7 Nov 2023 17:54:44 +0100 Subject: [PATCH 28/40] Add time to issue default block (#1323) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add time to accumulate * Change var names * Use import * chore: rename vars * chore: rename vars --------- Co-authored-by: Begoña Alvarez --- package.json | 1 + .../ManaCalculator/components/OutputForm.tsx | 30 ++++++++++++++++-- .../ManaCalculator/hooks/useResults.ts | 31 +++++++++++-------- .../hooks/useResultsPerEpoch.ts | 6 ++-- yarn.lock | 8 +++++ 5 files changed, 57 insertions(+), 19 deletions(-) diff --git a/package.json b/package.json index 82f6646d693..be5fa1c364d 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "flickity-fade": "^2.0.0", "globby": "^13.1.4", "hast-util-is-element": "1.1.0", + "humanize-duration": "^3.30.0", "plugin-image-zoom": "flexanalytics/plugin-image-zoom", "raw-loader": "^4.0.2", "react": "18.2.0", diff --git a/src/components/ManaCalculator/components/OutputForm.tsx b/src/components/ManaCalculator/components/OutputForm.tsx index 0a32f742614..6104bd95563 100644 --- a/src/components/ManaCalculator/components/OutputForm.tsx +++ b/src/components/ManaCalculator/components/OutputForm.tsx @@ -1,10 +1,18 @@ import React from 'react'; import { useManaState, useResults } from '../hooks'; import { fromMicro } from '../utils'; +import humanizeDuration from 'humanize-duration'; export function OutputForm() { const { state } = useManaState(); - const { manaGenerated, passiveRewards, totalTPS } = useResults(state); + const { + generatedRewards, + passiveRewards, + totalTPS, + msToTransaction, + passiveMsToTransaction, + } = useResults(state); + return (
@@ -15,13 +23,29 @@ export function OutputForm() {
Mana rewards
-
{fromMicro(manaGenerated)}
+
{fromMicro(generatedRewards)}
-
Total TPS granted with
{totalTPS}
+
+
+ Time it takes to accumulate enough mana for a standard transaction... +
+
+
+
...as a delegator/validator
+
+ {humanizeDuration(msToTransaction * 1000)} +
+
+
+
...as a holder
+
+ {humanizeDuration(passiveMsToTransaction * 1000)} +
+
); } diff --git a/src/components/ManaCalculator/hooks/useResults.ts b/src/components/ManaCalculator/hooks/useResults.ts index 8e6df3ef0bb..e279eadf24e 100644 --- a/src/components/ManaCalculator/hooks/useResults.ts +++ b/src/components/ManaCalculator/hooks/useResults.ts @@ -13,22 +13,22 @@ export function useResults(state: ManaCalculatorProps) { state.finalEpoch, ); - const additionalTPS = calculateTPS(passiveRewards, state.congestion); + const passiveTPS = calculateTPS(passiveRewards, state.congestion); const validatorParameters = state.userType === UserType.VALIDATOR ? ({ - performanceFactor: state.validator.performanceFactor, - fixedCost: state.validator.fixedCost, - shareOfYourStakeLocked: state.validator.shareOfYourStakeLocked, - attractedNewDelegatedStake: - state.validator.attractedNewDelegatedStake, - attractedDelegatedStakeFromOtherPools: - state.validator.attractedDelegatedStakeFromOtherPools, - } as ValidatorParameters) + performanceFactor: state.validator.performanceFactor, + fixedCost: state.validator.fixedCost, + shareOfYourStakeLocked: state.validator.shareOfYourStakeLocked, + attractedNewDelegatedStake: + state.validator.attractedNewDelegatedStake, + attractedDelegatedStakeFromOtherPools: + state.validator.attractedDelegatedStakeFromOtherPools, + } as ValidatorParameters) : null; - const manaGenerated = calculateManaRewards( + const generatedRewards = calculateManaRewards( state.stakedOrDelegatedTokens, state.delegator.validator, validatorParameters, @@ -39,12 +39,17 @@ export function useResults(state: ManaCalculatorProps) { state.network, ); - const grantedTPS = calculateTPS(manaGenerated, state.congestion); - const totalTPS = grantedTPS + additionalTPS; + const generatedTPS = calculateTPS(generatedRewards, state.congestion); + const totalTPS = generatedTPS + passiveTPS; + + const msToTransaction = (1 / totalTPS) * 1_000; + const passiveMsToTransaction = (1 / passiveTPS) * 1_000; return { - manaGenerated, + generatedRewards, passiveRewards, totalTPS, + msToTransaction, + passiveMsToTransaction, }; } diff --git a/src/components/ManaCalculator/hooks/useResultsPerEpoch.ts b/src/components/ManaCalculator/hooks/useResultsPerEpoch.ts index 8126d308776..dde820bd288 100644 --- a/src/components/ManaCalculator/hooks/useResultsPerEpoch.ts +++ b/src/components/ManaCalculator/hooks/useResultsPerEpoch.ts @@ -27,7 +27,7 @@ export function useResultsPerEpoch(state: ManaCalculatorProps): EpochReward[] { const results = []; for (let i = state.initialEpoch; i <= state.finalEpoch; i++) { - const manaGenerated = calculateManaRewards( + const generatedRewards = calculateManaRewards( state.stakedOrDelegatedTokens, state.delegator.validator, validatorParameters, @@ -44,13 +44,13 @@ export function useResultsPerEpoch(state: ManaCalculatorProps): EpochReward[] { i, ); - const mana = manaGenerated + passiveRewards; + const mana = generatedRewards + passiveRewards; const tpsFromPassiveRewards = calculateTPS( passiveRewards, state.congestion, ); - const tpsFromGeneratedMana = calculateTPS(manaGenerated, state.congestion); + const tpsFromGeneratedMana = calculateTPS(generatedRewards, state.congestion); const totalTps = tpsFromPassiveRewards + tpsFromGeneratedMana; results.push({ diff --git a/yarn.lock b/yarn.lock index d5e520df5f8..126884029e9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2835,6 +2835,7 @@ __metadata: flickity-fade: ^2.0.0 globby: ^13.1.4 hast-util-is-element: 1.1.0 + humanize-duration: ^3.30.0 plugin-image-zoom: flexanalytics/plugin-image-zoom prettier: ^2.8.8 raw-loader: ^4.0.2 @@ -10752,6 +10753,13 @@ __metadata: languageName: node linkType: hard +"humanize-duration@npm:^3.30.0": + version: 3.30.0 + resolution: "humanize-duration@npm:3.30.0" + checksum: 6eaf888219801d47d42cfb03523e736367c260e3f32cddb4e30c30f49500e08e7cdfd413f02a5ed24943ef382b3e89c8a11e6eda3a432846385903a9f49e576a + languageName: node + linkType: hard + "humanize-ms@npm:^1.2.1": version: 1.2.1 resolution: "humanize-ms@npm:1.2.1" From 36f07e629ea3f12f798b82cfc21c418f61817e24 Mon Sep 17 00:00:00 2001 From: Dr-Electron Date: Tue, 7 Nov 2023 18:09:57 +0100 Subject: [PATCH 29/40] Format --- .../ManaCalculator/components/OutputForm.tsx | 4 +++- .../ManaCalculator/hooks/useResults.ts | 16 ++++++++-------- .../ManaCalculator/hooks/useResultsPerEpoch.ts | 5 ++++- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/components/ManaCalculator/components/OutputForm.tsx b/src/components/ManaCalculator/components/OutputForm.tsx index 6104bd95563..107bd458778 100644 --- a/src/components/ManaCalculator/components/OutputForm.tsx +++ b/src/components/ManaCalculator/components/OutputForm.tsx @@ -23,7 +23,9 @@ export function OutputForm() {
Mana rewards
-
{fromMicro(generatedRewards)}
+
+ {fromMicro(generatedRewards)} +
Total TPS granted with
diff --git a/src/components/ManaCalculator/hooks/useResults.ts b/src/components/ManaCalculator/hooks/useResults.ts index e279eadf24e..7fececeeda2 100644 --- a/src/components/ManaCalculator/hooks/useResults.ts +++ b/src/components/ManaCalculator/hooks/useResults.ts @@ -18,14 +18,14 @@ export function useResults(state: ManaCalculatorProps) { const validatorParameters = state.userType === UserType.VALIDATOR ? ({ - performanceFactor: state.validator.performanceFactor, - fixedCost: state.validator.fixedCost, - shareOfYourStakeLocked: state.validator.shareOfYourStakeLocked, - attractedNewDelegatedStake: - state.validator.attractedNewDelegatedStake, - attractedDelegatedStakeFromOtherPools: - state.validator.attractedDelegatedStakeFromOtherPools, - } as ValidatorParameters) + performanceFactor: state.validator.performanceFactor, + fixedCost: state.validator.fixedCost, + shareOfYourStakeLocked: state.validator.shareOfYourStakeLocked, + attractedNewDelegatedStake: + state.validator.attractedNewDelegatedStake, + attractedDelegatedStakeFromOtherPools: + state.validator.attractedDelegatedStakeFromOtherPools, + } as ValidatorParameters) : null; const generatedRewards = calculateManaRewards( diff --git a/src/components/ManaCalculator/hooks/useResultsPerEpoch.ts b/src/components/ManaCalculator/hooks/useResultsPerEpoch.ts index dde820bd288..a8f873e7c67 100644 --- a/src/components/ManaCalculator/hooks/useResultsPerEpoch.ts +++ b/src/components/ManaCalculator/hooks/useResultsPerEpoch.ts @@ -50,7 +50,10 @@ export function useResultsPerEpoch(state: ManaCalculatorProps): EpochReward[] { passiveRewards, state.congestion, ); - const tpsFromGeneratedMana = calculateTPS(generatedRewards, state.congestion); + const tpsFromGeneratedMana = calculateTPS( + generatedRewards, + state.congestion, + ); const totalTps = tpsFromPassiveRewards + tpsFromGeneratedMana; results.push({ From daed1df1717b6368ecb90993ba044c9a60a30ea4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bego=C3=B1a=20Alvarez?= Date: Tue, 7 Nov 2023 18:23:58 +0100 Subject: [PATCH 30/40] fix: remove redundant *1000 in humanized duration --- src/components/ManaCalculator/components/OutputForm.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/ManaCalculator/components/OutputForm.tsx b/src/components/ManaCalculator/components/OutputForm.tsx index 107bd458778..a20e90c000c 100644 --- a/src/components/ManaCalculator/components/OutputForm.tsx +++ b/src/components/ManaCalculator/components/OutputForm.tsx @@ -39,13 +39,13 @@ export function OutputForm() {
...as a delegator/validator
- {humanizeDuration(msToTransaction * 1000)} + {humanizeDuration(msToTransaction)}
...as a holder
- {humanizeDuration(passiveMsToTransaction * 1000)} + {humanizeDuration(passiveMsToTransaction)}
From e73ce4447364d044964d5fff2120ea1023830bb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20Esp=C3=ADn?= Date: Wed, 8 Nov 2023 16:32:45 +0100 Subject: [PATCH 31/40] feat: UI polish (#1321) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: Flexible network selector in the mana calculator * feat: Improved user flow for the Mana calculator * typo * chore: Refactor the Mana Calculator * :sparkles: * clean up * clean up * feat: Add user total holding input * feat: Mana accumulation graph * feat: Block issuance rate graph * clean up * network params * clean up * clean up * fmt * prettify * typo * fix * fix * fix * improve graph * tweak * enhancement * Update src/components/ManaCalculator/hooks/useManaState.ts Co-authored-by: Dr-Electron * Update src/components/ManaCalculator/hooks/useManaState.ts Co-authored-by: Dr-Electron * fmt * clean up * fmt * feat: UI Polish * ui polish * Add humanizer config * clean up styles * Update src/components/ManaCalculator/components/AdvancedSettingsValidator.tsx Co-authored-by: Dr-Electron * fixes * clean up --------- Co-authored-by: Begoña Alvarez Co-authored-by: Dr-Electron --- .../components/AdvancedSettingsValidator.tsx | 39 ++++-- .../components/BlocksAllowance.tsx | 11 +- .../ManaCalculator/components/CharTooltip.tsx | 21 +++ .../components/ManaAcculation.tsx | 12 +- .../components/ManaCalculator.tsx | 3 +- .../components/NetworkSection.tsx | 6 +- .../components/OtherParametersSection.tsx | 12 +- .../ManaCalculator/components/OutputForm.tsx | 61 ++++----- .../ManaCalculator/components/RoleSection.tsx | 14 +- .../components/ValidatorCard.tsx | 88 +++++------- .../components/ValidatorSettings.tsx | 126 +++++++++--------- src/components/ManaCalculator/styles.css | 78 +++++++++++ src/components/TutorialFilters/index.tsx | 1 + src/components/TutorialFilters/styles.css | 5 +- src/css/custom.css | 31 +---- 15 files changed, 293 insertions(+), 215 deletions(-) create mode 100644 src/components/ManaCalculator/components/CharTooltip.tsx diff --git a/src/components/ManaCalculator/components/AdvancedSettingsValidator.tsx b/src/components/ManaCalculator/components/AdvancedSettingsValidator.tsx index 05a2945f6fb..abff422a465 100644 --- a/src/components/ManaCalculator/components/AdvancedSettingsValidator.tsx +++ b/src/components/ManaCalculator/components/AdvancedSettingsValidator.tsx @@ -19,20 +19,37 @@ export function AdvancedSettingsValidator() { } return ( -
-
+
+
+
+
ID
+
Stake
+
+ Delegated +
+
+ Performance factor +
+
+ Fixed costs +
+
+
{validators.map((validator, i) => ( - +
+ +
))}
-
- -
+
); } diff --git a/src/components/ManaCalculator/components/BlocksAllowance.tsx b/src/components/ManaCalculator/components/BlocksAllowance.tsx index 724d3be3dc5..8c6c7fab2cf 100644 --- a/src/components/ManaCalculator/components/BlocksAllowance.tsx +++ b/src/components/ManaCalculator/components/BlocksAllowance.tsx @@ -9,14 +9,14 @@ import { YAxis, } from 'recharts'; import { EpochReward } from '../types'; +import { chartTooltip } from './CharTooltip'; export function BlocksAllowance({ results }: { results: EpochReward[] }) { return ( -
-
+ <>

Blocks Allowance

- + @@ -31,12 +31,13 @@ export function BlocksAllowance({ results }: { results: EpochReward[] }) { - + -
+ ); } diff --git a/src/components/ManaCalculator/components/CharTooltip.tsx b/src/components/ManaCalculator/components/CharTooltip.tsx new file mode 100644 index 00000000000..6e1f003490d --- /dev/null +++ b/src/components/ManaCalculator/components/CharTooltip.tsx @@ -0,0 +1,21 @@ +import React from 'react'; + +export function chartTooltip( + xLabel: string, + yLabel: string, + formatter: (value: number) => string = (v) => v.toString(), +) { + return ({ active, payload, label }) => { + if (active && payload && payload.length) { + const value = formatter(payload[0].value); + return ( +
+

{`${xLabel}: ${label}`}

+

{`${yLabel}: ${value}`}

+
+ ); + } + + return null; + }; +} diff --git a/src/components/ManaCalculator/components/ManaAcculation.tsx b/src/components/ManaCalculator/components/ManaAcculation.tsx index f7e9e1a7f03..36584a6de2d 100644 --- a/src/components/ManaCalculator/components/ManaAcculation.tsx +++ b/src/components/ManaCalculator/components/ManaAcculation.tsx @@ -9,11 +9,11 @@ import { YAxis, } from 'recharts'; import { EpochReward } from '../types'; +import { chartTooltip } from './CharTooltip'; export function ManaAccumulation({ results }: { results: EpochReward[] }) { return ( -
-
+ <>

Mana Accumulation

@@ -37,7 +37,11 @@ export function ManaAccumulation({ results }: { results: EpochReward[] }) { strokeDasharray='3 3' stroke='rgb(255, 255, 255, 0.15)' /> - + + (v * 1_000_000).toString(), + )} + /> -
+ ); } diff --git a/src/components/ManaCalculator/components/ManaCalculator.tsx b/src/components/ManaCalculator/components/ManaCalculator.tsx index 320527574f9..7086a883ebe 100644 --- a/src/components/ManaCalculator/components/ManaCalculator.tsx +++ b/src/components/ManaCalculator/components/ManaCalculator.tsx @@ -22,11 +22,12 @@ export function ManaCalculator() { return ( +

Configuration

-
+

Results

diff --git a/src/components/ManaCalculator/components/NetworkSection.tsx b/src/components/ManaCalculator/components/NetworkSection.tsx index cd2b6c05798..5bd4e0784ec 100644 --- a/src/components/ManaCalculator/components/NetworkSection.tsx +++ b/src/components/ManaCalculator/components/NetworkSection.tsx @@ -6,11 +6,11 @@ import Select from 'react-select'; export function NetworkSection() { const { handleNetworkChange } = useManaState(); return ( -
-

Network configuration

+
+

Network configuration

{ handleCongestionChange(e.value); @@ -33,17 +34,18 @@ export function OtherParametersSection() {
handleInitialEpochChange(Number(e.target.value))} >
handleFinalEpochChange(Number(e.target.value))} > +
); } diff --git a/src/components/ManaCalculator/components/OutputForm.tsx b/src/components/ManaCalculator/components/OutputForm.tsx index a20e90c000c..2f0d47b78e5 100644 --- a/src/components/ManaCalculator/components/OutputForm.tsx +++ b/src/components/ManaCalculator/components/OutputForm.tsx @@ -5,48 +5,39 @@ import humanizeDuration from 'humanize-duration'; export function OutputForm() { const { state } = useManaState(); - const { - generatedRewards, - passiveRewards, - totalTPS, - msToTransaction, - passiveMsToTransaction, - } = useResults(state); + const results = useResults(state); + const passiveRewards = fromMicro(results.passiveRewards).toFixed(2); + const manaGenerated = fromMicro(results.generatedRewards).toFixed(2); + const totalTPS = results.totalTPS.toFixed(2); + const humanizer = humanizeDuration.humanizer({ + units: ['y', 'mo', 'w', 'd', 'h', 'm', 's', 'ms'], + maxDecimalPoints: 3, + }); + const msToTransaction = humanizer(results.msToTransaction); + const passiveMsToTransaction = humanizer(results.passiveMsToTransaction); return ( -
-
-
Mana generation (by holding)
-
- {fromMicro(passiveRewards)} -
+
+
+ Mana generation (by holding):{' '} + {passiveRewards}
-
-
Mana rewards
-
- {fromMicro(generatedRewards)} -
+
+ Mana rewards: {manaGenerated}
-
-
Total TPS granted with
-
{totalTPS}
+
+ Total TPS granted: {totalTPS}
-
-
- Time it takes to accumulate enough mana for a standard transaction... -
+
+ Time it takes to accumulate enough mana for a standard transaction...
-
-
...as a delegator/validator
-
- {humanizeDuration(msToTransaction)} -
+
+ ...as a delegator/validator:{' '} + {msToTransaction}
-
-
...as a holder
-
- {humanizeDuration(passiveMsToTransaction)} -
+
+ ...as a holder:{' '} + {passiveMsToTransaction}
); diff --git a/src/components/ManaCalculator/components/RoleSection.tsx b/src/components/ManaCalculator/components/RoleSection.tsx index c4097ab4281..bbca80bebc6 100644 --- a/src/components/ManaCalculator/components/RoleSection.tsx +++ b/src/components/ManaCalculator/components/RoleSection.tsx @@ -18,11 +18,11 @@ export function RoleSection() { }); return ( -
-

Role configuration

+
+

Role configuration

handleOwnHoldChange(toMicro(Number(e.target.value)))} > @@ -45,7 +45,7 @@ export function RoleSection() { <> handleOwnStakeChange(toMicro(Number(e.target.value))) @@ -58,7 +58,7 @@ export function RoleSection() { <> handleOwnStakeChange(toMicro(Number(e.target.value))) diff --git a/src/components/ManaCalculator/components/ValidatorCard.tsx b/src/components/ManaCalculator/components/ValidatorCard.tsx index e52ad669d49..f2826461bea 100644 --- a/src/components/ManaCalculator/components/ValidatorCard.tsx +++ b/src/components/ManaCalculator/components/ValidatorCard.tsx @@ -18,58 +18,40 @@ export function ValidatorCard({ handleFCChange, } = useManaState(); return ( -
-
-
-
Validator {id + 1}
- -
-
-
Stake:
- - handleStakeChange(toMicro(Number(e.target.value)), id) - } - > -
-
-
Delegated:
- - handleDelegatedStakeChange(toMicro(Number(e.target.value)), id) - } - > -
-
-
PF:
- handlePFChange(Number(e.target.value), id)} - > -
-
-
FC:
- handleFCChange(Number(e.target.value), id)} - > -
-
-
+ <> +
Validator {id + 1}
+ handleStakeChange(toMicro(Number(e.target.value)), id)} + > + + handleDelegatedStakeChange(toMicro(Number(e.target.value)), id) + } + > + handlePFChange(Number(e.target.value), id)} + > + handleFCChange(Number(e.target.value), id)} + > + + ); } diff --git a/src/components/ManaCalculator/components/ValidatorSettings.tsx b/src/components/ManaCalculator/components/ValidatorSettings.tsx index aed802c432b..95be4df6508 100644 --- a/src/components/ManaCalculator/components/ValidatorSettings.tsx +++ b/src/components/ManaCalculator/components/ValidatorSettings.tsx @@ -5,11 +5,13 @@ import { useManaState } from '../hooks'; export function ValidatorSettings() { const { state: { - performanceFactor, - fixedCost, - shareOfYourStakeLocked, - attractedNewDelegatedStake, - attractedDelegatedStakeFromOtherPools, + validator: { + performanceFactor, + fixedCost, + shareOfYourStakeLocked, + attractedNewDelegatedStake, + attractedDelegatedStakeFromOtherPools, + }, }, handleOwnPFChange, handleOwnFCChange, @@ -18,64 +20,60 @@ export function ValidatorSettings() { handleAttractedDelegatedStakeFromOtherPoolsChange, } = useManaState(); return ( -
-
-
-
Performance factor:
- handleOwnPFChange(Number(e.target.value))} - > -
- -
-
Fixed costs:
- handleOwnFCChange(Number(e.target.value))} - > -
-
-
Share of your stake locked:
- - handleShareOfYourStakeLockedChange(Number(e.target.value)) - } - > -
-
-
Attracted new delegated stake:
- - handleAttractedNewDelegatedStakeChange(Number(e.target.value)) - } - > -
-
-
- Attracted delegated stake from other pools: -
- - handleAttractedDelegatedStakeFromOtherPoolsChange( - Number(e.target.value), - ) - } - > -
-
-
+
+ + handleOwnPFChange(Number(e.target.value))} + > +
+ + handleOwnFCChange(Number(e.target.value))} + > +
+ + + handleShareOfYourStakeLockedChange(Number(e.target.value)) + } + > +
+ + + handleAttractedNewDelegatedStakeChange(Number(e.target.value)) + } + > +
+ + + handleAttractedDelegatedStakeFromOtherPoolsChange( + Number(e.target.value), + ) + } + > +
); } diff --git a/src/components/ManaCalculator/styles.css b/src/components/ManaCalculator/styles.css index e3631c31ab6..2069f8041ff 100644 --- a/src/components/ManaCalculator/styles.css +++ b/src/components/ManaCalculator/styles.css @@ -29,3 +29,81 @@ .table .row:nth-child(even) { background: var(--ifm-table-cell-color); } + +.mana_calculator__card { + background-color: var(--ifm-color-emphasis-100); + border: 1px solid var(--ifm-color-emphasis-200); + border-radius: var(--ifm-global-radius); + color: inherit; + transition: border-color 200ms ease-in-out; + padding: 15px; + margin: 10px 0px; +} + +.mana_calculator_inner__card { + background-color: var(--ifm-color-emphasis-0); + box-shadow: none; + border: 1px solid var(--ifm-color-emphasis-300); + border-radius: var(--ifm-global-radius); + color: inherit; + transition: border-color 200ms ease-in-out; + padding: 15px; + margin: 10px 0px; +} + +.mana_calculator__card input:not([role$='combobox']) { + background-color: var(--ifm-color-emphasis-200) !important; + padding: 10px; + border-radius: 4px; + border: none; +} + +.input--vertical-spaced { + margin-bottom: 1rem; +} + +.horizontal-spaced { + margin-right: 5px; +} + +.button--remove { + padding: 10px; +} + +.row--centered { + display: flex; + align-items: center; +} + +.mana-calculator__tooltip { + background-color: var(--ifm-color-emphasis-100); + border: 1px solid var(--ifm-color-emphasis-200); + border-radius: var(--ifm-global-radius); + color: inherit; + padding: 10px; +} + +.mana-calculator__button { + background-color: var(--ifm-color-emphasis-100); + margin: 0px; + margin-top: 1rem; +} + +.mana-calculator__tooltip > p { + margin: 0; +} + +.inlined-label { + display: inline-block; + width: 150px; +} + +.inlined-long-label { + display: inline-block; + width: 350px; +} + +.mana_calculator__compact { + width: 200px; + margin-bottom: 1rem !important; +} diff --git a/src/components/TutorialFilters/index.tsx b/src/components/TutorialFilters/index.tsx index 11bf5ed4e2b..e4055bc0865 100644 --- a/src/components/TutorialFilters/index.tsx +++ b/src/components/TutorialFilters/index.tsx @@ -218,6 +218,7 @@ function TutorialFilters() { options={tags} {...selectProps} value={value} + className='react-select-spaced__control' />
); diff --git a/src/components/TutorialFilters/styles.css b/src/components/TutorialFilters/styles.css index 79141940fad..6bf6a194b53 100644 --- a/src/components/TutorialFilters/styles.css +++ b/src/components/TutorialFilters/styles.css @@ -57,10 +57,13 @@ cursor: pointer !important; background-color: var(--ifm-color-emphasis-200) !important; border: 0 !important; - margin-bottom: 1rem !important; border-radius: 6px !important; } +.react-select-spaced__control { + margin-bottom: 1rem !important; +} + .react-select__indicator { cursor: pointer; color: var(--ifm-font-color-base) !important; diff --git a/src/css/custom.css b/src/css/custom.css index 1b0bfa8f19d..a41d4ad16b2 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -477,39 +477,14 @@ ul ul .table-of-contents__link { text-align: center; } -.grouped-form { - border: 1px solid gray; - border-radius: 8px; - padding: 8px 12px; - margin: 5px 0px; -} - -.grouped-form input:not([role$='combobox']) { - background-color: var(--ifm-color-emphasis-200) !important; - padding: 10px; - border-radius: 4px; - border: none; - width: 150px; - margin-bottom: 1rem; -} - .inlined { display: inline-block; } -.inlined-label { - display: inline-block; - width: 150px; -} - -.compact { - width: 200px; -} - .react-select__control { background-color: var(--ifm-color-emphasis-200) !important; border: 0 !important; - margin-bottom: 1rem !important; + margin: 0 !important; } .react-select__placeholder { @@ -541,3 +516,7 @@ ul ul .table-of-contents__link { .react-select__multi-value__label { color: var(--ifm-font-color-base) !important; } + +.recharts-text { + fill: var(--ifm-menu-color) !important; +} From b7d163fa6e454640087e6d65dad0425b8ab074e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20Esp=C3=ADn?= Date: Wed, 8 Nov 2023 16:36:41 +0100 Subject: [PATCH 32/40] feat: Mana calculator units (#1324) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: Flexible network selector in the mana calculator * feat: Improved user flow for the Mana calculator * typo * chore: Refactor the Mana Calculator * :sparkles: * clean up * clean up * feat: Add user total holding input * feat: Mana accumulation graph * feat: Block issuance rate graph * clean up * network params * clean up * clean up * fmt * prettify * typo * fix * fix * fix * improve graph * tweak * enhancement * Update src/components/ManaCalculator/hooks/useManaState.ts Co-authored-by: Dr-Electron * Update src/components/ManaCalculator/hooks/useManaState.ts Co-authored-by: Dr-Electron * fmt * clean up * fmt * feat: UI Polish * ui polish * feat: Display units in Mana Calculator * Add humanizer config * clean up styles * Update src/components/ManaCalculator/components/AdvancedSettingsValidator.tsx Co-authored-by: Dr-Electron * fixes * clean up * more units * more decimals * smarter rounding --------- Co-authored-by: Begoña Alvarez Co-authored-by: Dr-Electron --- .../components/AdvancedSettingsValidator.tsx | 15 ++-- .../components/BlocksAllowance.tsx | 12 ++- .../ManaCalculator/components/CharTooltip.tsx | 10 +-- .../components/ManaAcculation.tsx | 17 ++-- .../components/ManaCalculator.tsx | 7 +- .../ManaCalculator/components/OutputForm.tsx | 8 +- .../ManaCalculator/components/RoleSection.tsx | 8 +- .../ManaCalculator/enums/parameters.enum.ts | 4 +- src/components/ManaCalculator/hooks/index.ts | 1 + .../hooks/useResultsPerEpoch.ts | 2 +- .../hooks/useResultsWithUnit.ts | 78 +++++++++++++++++++ src/components/ManaCalculator/styles.css | 6 +- .../ManaCalculator/types/epoch-reward.type.ts | 1 + src/components/ManaCalculator/utils.ts | 4 + 14 files changed, 136 insertions(+), 37 deletions(-) create mode 100644 src/components/ManaCalculator/hooks/useResultsWithUnit.ts diff --git a/src/components/ManaCalculator/components/AdvancedSettingsValidator.tsx b/src/components/ManaCalculator/components/AdvancedSettingsValidator.tsx index abff422a465..e29f0ae995f 100644 --- a/src/components/ManaCalculator/components/AdvancedSettingsValidator.tsx +++ b/src/components/ManaCalculator/components/AdvancedSettingsValidator.tsx @@ -4,10 +4,7 @@ import { useManaState } from '../hooks'; import { ValidatorCard } from './ValidatorCard'; export function AdvancedSettingsValidator() { - const { - handleAddValidator, - state: { validators }, - } = useManaState(); + const { handleAddValidator, state } = useManaState(); function onAddValidator() { handleAddValidator({ @@ -24,11 +21,13 @@ export function AdvancedSettingsValidator() { className='mana_calculator__card mana_calculator_inner__card table' >
-
+
ID
-
Stake
+
+ Stake ({state.network}) +
- Delegated + Delegated ({state.network})
Performance factor @@ -38,7 +37,7 @@ export function AdvancedSettingsValidator() {
- {validators.map((validator, i) => ( + {state.validators.map((validator, i) => (
diff --git a/src/components/ManaCalculator/components/BlocksAllowance.tsx b/src/components/ManaCalculator/components/BlocksAllowance.tsx index 8c6c7fab2cf..923ef8ffa03 100644 --- a/src/components/ManaCalculator/components/BlocksAllowance.tsx +++ b/src/components/ManaCalculator/components/BlocksAllowance.tsx @@ -8,10 +8,17 @@ import { XAxis, YAxis, } from 'recharts'; +import { Unit } from '../hooks'; import { EpochReward } from '../types'; import { chartTooltip } from './CharTooltip'; -export function BlocksAllowance({ results }: { results: EpochReward[] }) { +export function BlocksAllowance({ + results, + unit, +}: { + results: EpochReward[]; + unit: Unit; +}) { return ( <>

Blocks Allowance

@@ -32,12 +39,13 @@ export function BlocksAllowance({ results }: { results: EpochReward[] }) { width={100} label={{ value: 'Blocks', angle: -90, position: 'insideLeft' }} color='rgb(169, 184, 214)' + unit={unit} /> - + string = (v) => v.toString(), -) { +export function chartTooltip(xLabel: string, yLabel: string, unit: Unit) { + const unitSize = getSizeOfUnit(unit); return ({ active, payload, label }) => { if (active && payload && payload.length) { - const value = formatter(payload[0].value); + const value = payload[0].value * unitSize; return (

{`${xLabel}: ${label}`}

diff --git a/src/components/ManaCalculator/components/ManaAcculation.tsx b/src/components/ManaCalculator/components/ManaAcculation.tsx index 36584a6de2d..5ecaa23ab48 100644 --- a/src/components/ManaCalculator/components/ManaAcculation.tsx +++ b/src/components/ManaCalculator/components/ManaAcculation.tsx @@ -8,10 +8,17 @@ import { XAxis, YAxis, } from 'recharts'; +import { Unit } from '../hooks'; import { EpochReward } from '../types'; import { chartTooltip } from './CharTooltip'; -export function ManaAccumulation({ results }: { results: EpochReward[] }) { +export function ManaAccumulation({ + results, + unit, +}: { + results: EpochReward[]; + unit: Unit; +}) { return ( <>

Mana Accumulation

@@ -31,17 +38,13 @@ export function ManaAccumulation({ results }: { results: EpochReward[] }) { - - (v * 1_000_000).toString(), - )} - /> +

Configuration

@@ -29,8 +30,8 @@ export function ManaCalculator() {

Results

- - + + ); } diff --git a/src/components/ManaCalculator/components/OutputForm.tsx b/src/components/ManaCalculator/components/OutputForm.tsx index 2f0d47b78e5..2757efbc941 100644 --- a/src/components/ManaCalculator/components/OutputForm.tsx +++ b/src/components/ManaCalculator/components/OutputForm.tsx @@ -1,14 +1,14 @@ import React from 'react'; import { useManaState, useResults } from '../hooks'; -import { fromMicro } from '../utils'; +import { fromMicro, roundMax } from '../utils'; import humanizeDuration from 'humanize-duration'; export function OutputForm() { const { state } = useManaState(); const results = useResults(state); - const passiveRewards = fromMicro(results.passiveRewards).toFixed(2); - const manaGenerated = fromMicro(results.generatedRewards).toFixed(2); - const totalTPS = results.totalTPS.toFixed(2); + const passiveRewards = roundMax(fromMicro(results.passiveRewards), 6); + const manaGenerated = roundMax(fromMicro(results.generatedRewards), 6); + const totalTPS = roundMax(results.totalTPS, 2); const humanizer = humanizeDuration.humanizer({ units: ['y', 'mo', 'w', 'd', 'h', 'm', 's', 'ms'], maxDecimalPoints: 3, diff --git a/src/components/ManaCalculator/components/RoleSection.tsx b/src/components/ManaCalculator/components/RoleSection.tsx index bbca80bebc6..48c4bc26f21 100644 --- a/src/components/ManaCalculator/components/RoleSection.tsx +++ b/src/components/ManaCalculator/components/RoleSection.tsx @@ -34,7 +34,7 @@ export function RoleSection() { ]} />
- + {state.userType === UserType.VALIDATOR ? ( <> - +
- + { + let bestUnits: Unit = Unit.default; + if (!value || value === 0) { + return Unit.M; + } + const checkLength = Math.abs(value).toString().length; + + if (checkLength > UNIT_MAP.M.dp) { + bestUnits = Unit.M; + } else if (checkLength > UNIT_MAP.K.dp) { + bestUnits = Unit.K; + } else if (checkLength > UNIT_MAP.G.dp) { + bestUnits = Unit.G; + } else if (checkLength > UNIT_MAP.M.dp) { + bestUnits = Unit.M; + } else if (checkLength > UNIT_MAP.K.dp) { + bestUnits = Unit.K; + } + + return bestUnits; +}; + +interface UseResultsWithUnit { + data: EpochReward[]; + manaUnit: Unit; + blocksUnit: Unit; +} + +export function getSizeOfUnit(unit: Unit): number { + return UNIT_MAP[unit].val; +} + +export function useResultsWithUnit(results: EpochReward[]): UseResultsWithUnit { + const averageMana = + results.reduce((acc, reward) => acc + reward.mana, 0) / results.length; + const averageBlocks = + results.reduce((acc, reward) => acc + reward.totalTps, 0) / results.length; + + const manaUnit = getUnit(averageMana); + const blocksUnit = getUnit(averageBlocks); + + const manaSize = getSizeOfUnit(manaUnit); + const blocksSize = getSizeOfUnit(blocksUnit); + + const data = results.map((reward) => { + return { + ...reward, + mana: reward.mana / manaSize, + totalTps: reward.totalTps / blocksSize, + }; + }); + + return { + data, + manaUnit, + blocksUnit, + }; +} diff --git a/src/components/ManaCalculator/styles.css b/src/components/ManaCalculator/styles.css index 2069f8041ff..e95fa997a03 100644 --- a/src/components/ManaCalculator/styles.css +++ b/src/components/ManaCalculator/styles.css @@ -95,7 +95,7 @@ .inlined-label { display: inline-block; - width: 150px; + width: 200px; } .inlined-long-label { @@ -103,6 +103,10 @@ width: 350px; } +.small-row-head { + font-size: 15px; +} + .mana_calculator__compact { width: 200px; margin-bottom: 1rem !important; diff --git a/src/components/ManaCalculator/types/epoch-reward.type.ts b/src/components/ManaCalculator/types/epoch-reward.type.ts index 5b7d6e68c1c..a40280fe05f 100644 --- a/src/components/ManaCalculator/types/epoch-reward.type.ts +++ b/src/components/ManaCalculator/types/epoch-reward.type.ts @@ -1,4 +1,5 @@ export interface EpochReward { epoch: number; mana: number; + totalTps: number; } diff --git a/src/components/ManaCalculator/utils.ts b/src/components/ManaCalculator/utils.ts index 02d17b1b40e..560ee1da960 100644 --- a/src/components/ManaCalculator/utils.ts +++ b/src/components/ManaCalculator/utils.ts @@ -31,3 +31,7 @@ export function getNetworkSupply(network: NetworkType): number { return SHIMMER_SUPPLY; } } + +export const roundMax = function (num: number, places: number) { + return +(Math.round(Number(num + 'e+' + places)) + 'e-' + places); +}; From 9e1f3143fce9fec2ea05bd5b61e1751c6393421e Mon Sep 17 00:00:00 2001 From: Dr-Electron Date: Wed, 8 Nov 2023 16:50:47 +0100 Subject: [PATCH 33/40] Use BPS instead of TPS (#1327) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: Flexible network selector in the mana calculator * feat: Improved user flow for the Mana calculator * typo * chore: Refactor the Mana Calculator * :sparkles: * clean up * clean up * feat: Add user total holding input * feat: Mana accumulation graph * feat: Block issuance rate graph * clean up * network params * clean up * clean up * fmt * prettify * typo * fix * fix * fix * improve graph * tweak * enhancement * Update src/components/ManaCalculator/hooks/useManaState.ts Co-authored-by: Dr-Electron * Update src/components/ManaCalculator/hooks/useManaState.ts Co-authored-by: Dr-Electron * fmt * clean up * fmt * feat: UI Polish * ui polish * Add humanizer config * Use BPS instead of TPS * Add totalBps * Update src/components/HomeLayout/styles.css --------- Co-authored-by: marc2332 Co-authored-by: Begoña Alvarez --- .../actions/{calculateTPS.ts => calculateBPS.ts} | 2 +- src/components/ManaCalculator/actions/index.ts | 2 +- .../ManaCalculator/components/BlocksAllowance.tsx | 6 +++--- .../ManaCalculator/components/OutputForm.tsx | 4 ++-- src/components/ManaCalculator/hooks/useResults.ts | 14 +++++++------- .../ManaCalculator/hooks/useResultsPerEpoch.ts | 10 +++++----- .../ManaCalculator/types/epoch-reward.type.ts | 2 +- 7 files changed, 20 insertions(+), 20 deletions(-) rename src/components/ManaCalculator/actions/{calculateTPS.ts => calculateBPS.ts} (61%) diff --git a/src/components/ManaCalculator/actions/calculateTPS.ts b/src/components/ManaCalculator/actions/calculateBPS.ts similarity index 61% rename from src/components/ManaCalculator/actions/calculateTPS.ts rename to src/components/ManaCalculator/actions/calculateBPS.ts index 67e9163781a..adf6427c0ca 100644 --- a/src/components/ManaCalculator/actions/calculateTPS.ts +++ b/src/components/ManaCalculator/actions/calculateBPS.ts @@ -1,5 +1,5 @@ import { EPOCH_DURATION } from '../constants'; -export function calculateTPS(mana: number, congestion: number): number { +export function calculateBPS(mana: number, congestion: number): number { return mana / congestion / EPOCH_DURATION; } diff --git a/src/components/ManaCalculator/actions/index.ts b/src/components/ManaCalculator/actions/index.ts index 040ddc54aef..782afe50677 100644 --- a/src/components/ManaCalculator/actions/index.ts +++ b/src/components/ManaCalculator/actions/index.ts @@ -1,5 +1,5 @@ export * from './calculateManaRewards'; export * from './calculatePassiveRewards'; -export * from './calculateTPS'; +export * from './calculateBPS'; export * from './getPotentialMana'; export * from './decay'; diff --git a/src/components/ManaCalculator/components/BlocksAllowance.tsx b/src/components/ManaCalculator/components/BlocksAllowance.tsx index 923ef8ffa03..2f79f7fb4f1 100644 --- a/src/components/ManaCalculator/components/BlocksAllowance.tsx +++ b/src/components/ManaCalculator/components/BlocksAllowance.tsx @@ -25,7 +25,7 @@ export function BlocksAllowance({ - + @@ -48,10 +48,10 @@ export function BlocksAllowance({ diff --git a/src/components/ManaCalculator/components/OutputForm.tsx b/src/components/ManaCalculator/components/OutputForm.tsx index 2757efbc941..4a7a88340d0 100644 --- a/src/components/ManaCalculator/components/OutputForm.tsx +++ b/src/components/ManaCalculator/components/OutputForm.tsx @@ -8,7 +8,7 @@ export function OutputForm() { const results = useResults(state); const passiveRewards = roundMax(fromMicro(results.passiveRewards), 6); const manaGenerated = roundMax(fromMicro(results.generatedRewards), 6); - const totalTPS = roundMax(results.totalTPS, 2); + const totalBPS = roundMax(results.totalBPS, 2); const humanizer = humanizeDuration.humanizer({ units: ['y', 'mo', 'w', 'd', 'h', 'm', 's', 'ms'], maxDecimalPoints: 3, @@ -26,7 +26,7 @@ export function OutputForm() { Mana rewards: {manaGenerated}
- Total TPS granted: {totalTPS} + Total BPS granted: {totalBPS}
Time it takes to accumulate enough mana for a standard transaction... diff --git a/src/components/ManaCalculator/hooks/useResults.ts b/src/components/ManaCalculator/hooks/useResults.ts index 7fececeeda2..367643053c7 100644 --- a/src/components/ManaCalculator/hooks/useResults.ts +++ b/src/components/ManaCalculator/hooks/useResults.ts @@ -1,7 +1,7 @@ import { calculateManaRewards, calculatePassiveRewards, - calculateTPS, + calculateBPS, } from '../actions'; import { UserType } from '../enums'; import { ManaCalculatorProps, ValidatorParameters } from '../types'; @@ -13,7 +13,7 @@ export function useResults(state: ManaCalculatorProps) { state.finalEpoch, ); - const passiveTPS = calculateTPS(passiveRewards, state.congestion); + const passiveBPS = calculateBPS(passiveRewards, state.congestion); const validatorParameters = state.userType === UserType.VALIDATOR @@ -39,16 +39,16 @@ export function useResults(state: ManaCalculatorProps) { state.network, ); - const generatedTPS = calculateTPS(generatedRewards, state.congestion); - const totalTPS = generatedTPS + passiveTPS; + const generatedBPS = calculateBPS(generatedRewards, state.congestion); + const totalBPS = generatedBPS + passiveBPS; - const msToTransaction = (1 / totalTPS) * 1_000; - const passiveMsToTransaction = (1 / passiveTPS) * 1_000; + const msToTransaction = (1 / totalBPS) * 1_000; + const passiveMsToTransaction = (1 / passiveBPS) * 1_000; return { generatedRewards, passiveRewards, - totalTPS, + totalBPS, msToTransaction, passiveMsToTransaction, }; diff --git a/src/components/ManaCalculator/hooks/useResultsPerEpoch.ts b/src/components/ManaCalculator/hooks/useResultsPerEpoch.ts index c0e772cfd0d..90422eb8130 100644 --- a/src/components/ManaCalculator/hooks/useResultsPerEpoch.ts +++ b/src/components/ManaCalculator/hooks/useResultsPerEpoch.ts @@ -1,7 +1,7 @@ import { calculateManaRewards, calculatePassiveRewards, - calculateTPS, + calculateBPS, } from '../actions'; import { UserType } from '../enums'; import { @@ -46,20 +46,20 @@ export function useResultsPerEpoch(state: ManaCalculatorProps): EpochReward[] { const mana = generatedRewards + passiveRewards; - const tpsFromPassiveRewards = calculateTPS( + const bpsFromPassiveRewards = calculateBPS( passiveRewards, state.congestion, ); - const tpsFromGeneratedMana = calculateTPS( + const bpsFromGeneratedMana = calculateBPS( generatedRewards, state.congestion, ); - const totalTps = tpsFromPassiveRewards + tpsFromGeneratedMana; + const totalBps = bpsFromPassiveRewards + bpsFromGeneratedMana; results.push({ epoch: i, mana: fromMicro(mana), - totalTps, + totalBps, }); } diff --git a/src/components/ManaCalculator/types/epoch-reward.type.ts b/src/components/ManaCalculator/types/epoch-reward.type.ts index a40280fe05f..7cdaba7dba9 100644 --- a/src/components/ManaCalculator/types/epoch-reward.type.ts +++ b/src/components/ManaCalculator/types/epoch-reward.type.ts @@ -1,5 +1,5 @@ export interface EpochReward { epoch: number; mana: number; - totalTps: number; + totalBps: number; } From 7798427947a0f1d235e04ea2b12544615adb595c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20Esp=C3=ADn?= Date: Wed, 8 Nov 2023 17:20:13 +0100 Subject: [PATCH 34/40] feat: Final values for networks in Mana Calculator (#1325) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: Flexible network selector in the mana calculator * feat: Improved user flow for the Mana calculator * typo * chore: Refactor the Mana Calculator * :sparkles: * clean up * clean up * feat: Add user total holding input * feat: Mana accumulation graph * feat: Block issuance rate graph * clean up * network params * clean up * clean up * fmt * prettify * typo * fix * fix * fix * improve graph * tweak * enhancement * Update src/components/ManaCalculator/hooks/useManaState.ts Co-authored-by: Dr-Electron * Update src/components/ManaCalculator/hooks/useManaState.ts Co-authored-by: Dr-Electron * fmt * clean up * fmt * feat: UI Polish * ui polish * feat: Display units in Mana Calculator * feat: Final values for networks * Add humanizer config * clean up styles * Update src/components/ManaCalculator/components/AdvancedSettingsValidator.tsx Co-authored-by: Dr-Electron * fixes * tweaks * default validators * clean up * tweak * tweaks * fix * more units --------- Co-authored-by: Begoña Alvarez Co-authored-by: Dr-Electron --- .../actions/calculateManaRewards.ts | 5 +- .../actions/calculatePassiveRewards.ts | 4 +- .../ManaCalculator/actions/targetReward.ts | 9 +- .../components/BlocksAllowance.tsx | 5 +- .../components/ManaAcculation.tsx | 5 +- .../components/ManaCalculator.tsx | 4 +- src/components/ManaCalculator/constants.ts | 47 +++++++- .../ManaCalculator/enums/parameters.enum.ts | 12 +- .../ManaCalculator/hooks/useManaState.ts | 104 ++++++++++++------ .../ManaCalculator/hooks/useResults.ts | 10 +- .../hooks/useResultsPerEpoch.ts | 14 +-- .../hooks/useResultsWithUnit.ts | 18 ++- src/components/ManaCalculator/types/index.ts | 1 + .../types/mana-calculator.type.ts | 3 +- .../ManaCalculator/types/mana-state.type.ts | 7 ++ src/components/ManaCalculator/utils.ts | 57 +++++++++- 16 files changed, 224 insertions(+), 81 deletions(-) create mode 100644 src/components/ManaCalculator/types/mana-state.type.ts diff --git a/src/components/ManaCalculator/actions/calculateManaRewards.ts b/src/components/ManaCalculator/actions/calculateManaRewards.ts index b0dfb34107a..b2ea44e3863 100644 --- a/src/components/ManaCalculator/actions/calculateManaRewards.ts +++ b/src/components/ManaCalculator/actions/calculateManaRewards.ts @@ -13,6 +13,7 @@ export function calculateManaRewards( finalEpoch: number, userType: UserType, networkType: NetworkType, + generationPerSlot: number, ): number { const supply = getNetworkSupply(networkType); let totalTargetReward = 0; @@ -21,14 +22,14 @@ export function calculateManaRewards( if (finalEpoch) { for (let i = 0; i < epochDiff; i++) { totalTargetReward += decay( - targetReward(initialEpoch + i, supply), + targetReward(initialEpoch + i, supply, generationPerSlot), epochDiff - i, ); } } else { epochDiff = 1; finalEpoch = initialEpoch + 1; - totalTargetReward = targetReward(initialEpoch, supply); + totalTargetReward = targetReward(initialEpoch, supply, generationPerSlot); } const lockedStake: number[] = validators.map( diff --git a/src/components/ManaCalculator/actions/calculatePassiveRewards.ts b/src/components/ManaCalculator/actions/calculatePassiveRewards.ts index abcb739a4c8..8e78629e6a9 100644 --- a/src/components/ManaCalculator/actions/calculatePassiveRewards.ts +++ b/src/components/ManaCalculator/actions/calculatePassiveRewards.ts @@ -1,4 +1,3 @@ -import { GENERATION_PER_SLOT } from '../constants'; import { getFirstSlotOfEpoch } from '../utils'; import { getPotentialMana } from './getPotentialMana'; @@ -6,11 +5,12 @@ export function calculatePassiveRewards( tokens: number, initialEpoch: number, finalEpoch: number, + generationPerSlot: number, ): number { return getPotentialMana( tokens, getFirstSlotOfEpoch(initialEpoch) - 1, getFirstSlotOfEpoch(finalEpoch) - 1, - GENERATION_PER_SLOT, + generationPerSlot, ); } diff --git a/src/components/ManaCalculator/actions/targetReward.ts b/src/components/ManaCalculator/actions/targetReward.ts index b707e43cc46..3e7274553d2 100644 --- a/src/components/ManaCalculator/actions/targetReward.ts +++ b/src/components/ManaCalculator/actions/targetReward.ts @@ -2,18 +2,21 @@ import { BETA_PER_YEAR, BOOTSTRAPPING_DURATION, EPOCH_DURATION_IN_YEARS, - GENERATION_PER_SLOT, REWARDS_MANA_SHARE_COEFFICIENT, SLOTS_IN_EPOCH, } from '../constants'; import { decay } from './decay'; // Returns the target reward for the given epoch -export function targetReward(epoch: number, supply: number): number { +export function targetReward( + epoch: number, + supply: number, + generationPerSlot: number, +): number { const finalReward = supply * REWARDS_MANA_SHARE_COEFFICIENT * - GENERATION_PER_SLOT * + generationPerSlot * SLOTS_IN_EPOCH; const decayBalancingConstant = Math.exp(1) / diff --git a/src/components/ManaCalculator/components/BlocksAllowance.tsx b/src/components/ManaCalculator/components/BlocksAllowance.tsx index 2f79f7fb4f1..475758a1594 100644 --- a/src/components/ManaCalculator/components/BlocksAllowance.tsx +++ b/src/components/ManaCalculator/components/BlocksAllowance.tsx @@ -8,7 +8,7 @@ import { XAxis, YAxis, } from 'recharts'; -import { Unit } from '../hooks'; +import { stringifyUnit, Unit } from '../hooks'; import { EpochReward } from '../types'; import { chartTooltip } from './CharTooltip'; @@ -19,6 +19,7 @@ export function BlocksAllowance({ results: EpochReward[]; unit: Unit; }) { + const unitString = stringifyUnit(unit); return ( <>

Blocks Allowance

@@ -39,7 +40,7 @@ export function BlocksAllowance({ width={100} label={{ value: 'Blocks', angle: -90, position: 'insideLeft' }} color='rgb(169, 184, 214)' - unit={unit} + unit={unitString} />

Mana Accumulation

@@ -38,7 +39,7 @@ export function ManaAccumulation({ diff --git a/src/components/ManaCalculator/constants.ts b/src/components/ManaCalculator/constants.ts index f978c9facef..3eeccf01891 100644 --- a/src/components/ManaCalculator/constants.ts +++ b/src/components/ManaCalculator/constants.ts @@ -1,16 +1,51 @@ -export const IOTA_SUPPLY = 4600000000000000; -export const SHIMMER_SUPPLY = 1813620509000000; +import { CongestionType } from './enums/parameters.enum'; + +// GENERIC + +export const INITIAL_EPOCH = 1; +export const FINAL_EPOCH = 1000; export const SLOT_DURATION = 10; export const SLOTS_IN_EPOCH = 8192; export const EPOCH_DURATION = SLOTS_IN_EPOCH * SLOT_DURATION; export const SECONDS_IN_YEAR = 60 * 60 * 24 * 365; export const EPOCH_DURATION_IN_YEARS = EPOCH_DURATION / SECONDS_IN_YEAR; export const BETA_PER_YEAR = 1 / 3; -export const GENERATION_PER_SLOT = Math.pow(2, -17); export const BOOTSTRAPPING_DURATION = 1154; export const REWARDS_MANA_SHARE_COEFFICIENT = 2; export const EPOCH = 1154 + 1; -export const CONGESTION_LOW = 100000; -export const CONGESTION_MEDIUM = 9000000; -export const CONGESTION_HIGH = 500000000; +// IOTA + +export const IOTA_SUPPLY = 4600000000000000; + +export const IOTA_CONGESTION = { + [CongestionType.HIGH]: 350000000, + [CongestionType.MEDIUM]: 0, // Dynamic + [CongestionType.LOW]: 5000000, +}; + +export const IOTA_GENERATION_PER_SLOT = Math.pow(2, -17); + +export const IOTA_THROUGHPUT = 100; + +export const IOTA_HOLD = 600; // IOTA +export const IOTA_STAKED = 600; // IOTA +export const IOTA_DELEGATED = 600; // IOTA + +// SHIMMER + +export const SHIMMER_SUPPLY = 1813620509000000; + +export const SHIMMER_CONGESTION = { + [CongestionType.HIGH]: 350000000, + [CongestionType.MEDIUM]: 0, // Dynamic + [CongestionType.LOW]: 5000000, +}; + +export const SHIMMER_GENERATION_PER_SLOT = Math.pow(2, -16); + +export const SHIMMER_THROUGHPUT = 100; + +export const SHIMMER_HOLD = 600; // SMR +export const SHIMMER_STAKED = 600; // SMR +export const SHIMMER_DELEGATED = 600; // SMR diff --git a/src/components/ManaCalculator/enums/parameters.enum.ts b/src/components/ManaCalculator/enums/parameters.enum.ts index 8f1d2307a8d..faff9332bdb 100644 --- a/src/components/ManaCalculator/enums/parameters.enum.ts +++ b/src/components/ManaCalculator/enums/parameters.enum.ts @@ -1,9 +1,3 @@ -import { - CONGESTION_HIGH, - CONGESTION_LOW, - CONGESTION_MEDIUM, -} from '../constants'; - export enum UserType { DELEGATOR, VALIDATOR, @@ -15,7 +9,7 @@ export enum NetworkType { } export enum CongestionType { - LOW = CONGESTION_LOW, - MEDIUM = CONGESTION_MEDIUM, - HIGH = CONGESTION_HIGH, + LOW, + MEDIUM, + HIGH, } diff --git a/src/components/ManaCalculator/hooks/useManaState.ts b/src/components/ManaCalculator/hooks/useManaState.ts index 7ed14f8aae6..92f5c47b90c 100644 --- a/src/components/ManaCalculator/hooks/useManaState.ts +++ b/src/components/ManaCalculator/hooks/useManaState.ts @@ -1,7 +1,23 @@ import { createContext, useContext } from 'react'; +import { + FINAL_EPOCH, + INITIAL_EPOCH, + IOTA_DELEGATED, + IOTA_HOLD, + IOTA_STAKED, + SHIMMER_DELEGATED, + SHIMMER_HOLD, + SHIMMER_STAKED, +} from '../constants'; import { CongestionType, NetworkType, UserType } from '../enums'; -import { ManaCalculatorProps, ValidatorProps } from '../types'; -import { toMicro } from '../utils'; +import { ManaCalculatorProps, ManaState, ValidatorProps } from '../types'; +import { + getNetworkCongestion, + getNetworkGenerationPerSlot, + getNetworkSupply, + getStakedOrDelegated, + toMicro, +} from '../utils'; export const ManaStateContext = createContext(null); @@ -11,6 +27,13 @@ export function useManaState() { state: ManaCalculatorProps; }>(ManaStateContext); + return useGivenManaState(state, setState); +} + +export function useGivenManaState( + state: ManaCalculatorProps, + setState: (state: ManaCalculatorProps) => void, +) { function handleDelete(id: number) { const validators = state.validators.filter((_, i) => i !== id); setState({ ...state, validators }); @@ -67,7 +90,7 @@ export function useManaState() { function handleOwnStakeChange(value: number) { setState({ ...state, - stakedOrDelegatedTokens: value, + [getStakedOrDelegated(state.userType)]: value, }); } @@ -159,8 +182,20 @@ export function useManaState() { setState({ ...state, heldTokens: value }); } + const congestionAmount = getNetworkCongestion( + state.network, + state.congestion, + ); + const generationPerSlot = getNetworkGenerationPerSlot(state.network); + const stakedOrDelegatedTokens = state[getStakedOrDelegated(state.userType)]; + return { - state, + state: { + ...state, + congestionAmount, + generationPerSlot, + stakedOrDelegatedTokens, + } as ManaState, handleDelete, handleStakeChange, handleAddValidator, @@ -188,51 +223,54 @@ export function getDefaultParameters( ): ManaCalculatorProps { const networkParams = { [NetworkType.IOTA]: { - initialEpoch: 1, - finalEpoch: 365, + stakedTokens: toMicro(IOTA_STAKED), + delegatedTokens: toMicro(IOTA_DELEGATED), + heldTokens: toMicro(IOTA_HOLD), }, [NetworkType.SHIMMER]: { - initialEpoch: 1, - finalEpoch: 1000, + stakedTokens: toMicro(SHIMMER_STAKED), + delegatedTokens: toMicro(SHIMMER_DELEGATED), + heldTokens: toMicro(SHIMMER_HOLD), }, }; + const finalNetworkParams = networkParams[network]; + return { - ...networkParams[network], - validators: [ - { - lockedStake: toMicro(100), - delegatedStake: toMicro(0), - performanceFactor: 1.0, - fixedCost: 0.0, - }, - { - lockedStake: toMicro(100), - delegatedStake: toMicro(0), - performanceFactor: 1.0, - fixedCost: 0.0, - }, - { - lockedStake: toMicro(100), - delegatedStake: toMicro(0), - performanceFactor: 1.0, - fixedCost: 0.0, - }, - ], + ...finalNetworkParams, + initialEpoch: INITIAL_EPOCH, + finalEpoch: FINAL_EPOCH, + validators: getValidators(network), userType: UserType.DELEGATOR, congestion: CongestionType.LOW, - stakedOrDelegatedTokens: toMicro(100), - heldTokens: toMicro(100), delegator: { validator: 0, }, validator: { performanceFactor: 1.0, fixedCost: 0.0, - shareOfYourStakeLocked: 1.0, - attractedNewDelegatedStake: 0.0, + shareOfYourStakeLocked: 100.0, + attractedNewDelegatedStake: finalNetworkParams.stakedTokens * 1.5, attractedDelegatedStakeFromOtherPools: 0.1, }, network, } as ManaCalculatorProps; } + +export function getValidators(network: NetworkType): ValidatorProps[] { + const supply = getNetworkSupply(network); + + const delegated = [1.5, 1, 1.5, 2.0]; + + return delegated.flatMap((delegated) => { + const stake = [1, 1, 0.25, 0.5, 0.75, 1.12, 1.5, 1.75]; + return stake.map((stake) => { + return { + lockedStake: (supply * stake) / 100, + delegatedStake: (supply * delegated) / 100, + performanceFactor: 1.0, + fixedCost: 0.0, + }; + }); + }); +} diff --git a/src/components/ManaCalculator/hooks/useResults.ts b/src/components/ManaCalculator/hooks/useResults.ts index 367643053c7..3d883be690e 100644 --- a/src/components/ManaCalculator/hooks/useResults.ts +++ b/src/components/ManaCalculator/hooks/useResults.ts @@ -4,16 +4,17 @@ import { calculateBPS, } from '../actions'; import { UserType } from '../enums'; -import { ManaCalculatorProps, ValidatorParameters } from '../types'; +import { ManaState, ValidatorParameters } from '../types'; -export function useResults(state: ManaCalculatorProps) { +export function useResults(state: ManaState) { const passiveRewards = calculatePassiveRewards( state.heldTokens, state.initialEpoch, state.finalEpoch, + state.generationPerSlot, ); - const passiveBPS = calculateBPS(passiveRewards, state.congestion); + const passiveBPS = calculateBPS(passiveRewards, state.congestionAmount); const validatorParameters = state.userType === UserType.VALIDATOR @@ -37,9 +38,10 @@ export function useResults(state: ManaCalculatorProps) { state.finalEpoch, state.userType, state.network, + state.generationPerSlot, ); - const generatedBPS = calculateBPS(generatedRewards, state.congestion); + const generatedBPS = calculateBPS(generatedRewards, state.congestionAmount); const totalBPS = generatedBPS + passiveBPS; const msToTransaction = (1 / totalBPS) * 1_000; diff --git a/src/components/ManaCalculator/hooks/useResultsPerEpoch.ts b/src/components/ManaCalculator/hooks/useResultsPerEpoch.ts index 90422eb8130..063916fb200 100644 --- a/src/components/ManaCalculator/hooks/useResultsPerEpoch.ts +++ b/src/components/ManaCalculator/hooks/useResultsPerEpoch.ts @@ -4,14 +4,10 @@ import { calculateBPS, } from '../actions'; import { UserType } from '../enums'; -import { - EpochReward, - ManaCalculatorProps, - ValidatorParameters, -} from '../types'; +import { EpochReward, ManaState, ValidatorParameters } from '../types'; import { fromMicro } from '../utils'; -export function useResultsPerEpoch(state: ManaCalculatorProps): EpochReward[] { +export function useResultsPerEpoch(state: ManaState): EpochReward[] { const validatorParameters = state.userType === UserType.VALIDATOR ? ({ @@ -36,23 +32,25 @@ export function useResultsPerEpoch(state: ManaCalculatorProps): EpochReward[] { i, state.userType, state.network, + state.generationPerSlot, ); const passiveRewards = calculatePassiveRewards( state.heldTokens, state.initialEpoch, i, + state.generationPerSlot, ); const mana = generatedRewards + passiveRewards; const bpsFromPassiveRewards = calculateBPS( passiveRewards, - state.congestion, + state.congestionAmount, ); const bpsFromGeneratedMana = calculateBPS( generatedRewards, - state.congestion, + state.congestionAmount, ); const totalBps = bpsFromPassiveRewards + bpsFromGeneratedMana; diff --git a/src/components/ManaCalculator/hooks/useResultsWithUnit.ts b/src/components/ManaCalculator/hooks/useResultsWithUnit.ts index 73f724dad4a..66b52d00dd3 100644 --- a/src/components/ManaCalculator/hooks/useResultsWithUnit.ts +++ b/src/components/ManaCalculator/hooks/useResultsWithUnit.ts @@ -18,13 +18,19 @@ const UNIT_MAP: { [unit in Unit]: { val: number; dp: number } } = { P: { val: 1000000000000000, dp: 15 }, }; +export const stringifyUnit = (unit: Unit): string => { + if (unit == Unit.default) { + return ''; + } else { + return unit; + } +}; + const getUnit = (value: number): Unit => { let bestUnits: Unit = Unit.default; - if (!value || value === 0) { - return Unit.M; - } - const checkLength = Math.abs(value).toString().length; + const checkLength = Math.abs(value).toFixed(0).replace('.', '').length; + console.log(checkLength, value) if (checkLength > UNIT_MAP.M.dp) { bestUnits = Unit.M; } else if (checkLength > UNIT_MAP.K.dp) { @@ -54,7 +60,7 @@ export function useResultsWithUnit(results: EpochReward[]): UseResultsWithUnit { const averageMana = results.reduce((acc, reward) => acc + reward.mana, 0) / results.length; const averageBlocks = - results.reduce((acc, reward) => acc + reward.totalTps, 0) / results.length; + results.reduce((acc, reward) => acc + reward.totalBps, 0) / results.length; const manaUnit = getUnit(averageMana); const blocksUnit = getUnit(averageBlocks); @@ -66,7 +72,7 @@ export function useResultsWithUnit(results: EpochReward[]): UseResultsWithUnit { return { ...reward, mana: reward.mana / manaSize, - totalTps: reward.totalTps / blocksSize, + totalTps: reward.totalBps / blocksSize, }; }); diff --git a/src/components/ManaCalculator/types/index.ts b/src/components/ManaCalculator/types/index.ts index fc5735a62c3..1dca01c9553 100644 --- a/src/components/ManaCalculator/types/index.ts +++ b/src/components/ManaCalculator/types/index.ts @@ -1,3 +1,4 @@ export * from './mana-calculator.type'; export * from './validator.type'; export * from './epoch-reward.type'; +export * from './mana-state.type'; diff --git a/src/components/ManaCalculator/types/mana-calculator.type.ts b/src/components/ManaCalculator/types/mana-calculator.type.ts index 3b4ec3a46d6..c4467fc8e9f 100644 --- a/src/components/ManaCalculator/types/mana-calculator.type.ts +++ b/src/components/ManaCalculator/types/mana-calculator.type.ts @@ -18,7 +18,8 @@ export interface ManaCalculatorProps { fixedCost: number; performanceFactor: number; }; - stakedOrDelegatedTokens: number; + stakedTokens: number; + delegatedTokens: number; heldTokens: number; network: NetworkType; } diff --git a/src/components/ManaCalculator/types/mana-state.type.ts b/src/components/ManaCalculator/types/mana-state.type.ts new file mode 100644 index 00000000000..3361060224c --- /dev/null +++ b/src/components/ManaCalculator/types/mana-state.type.ts @@ -0,0 +1,7 @@ +import { ManaCalculatorProps } from './mana-calculator.type'; + +export interface ManaState extends ManaCalculatorProps { + congestionAmount: number; + generationPerSlot: number; + stakedOrDelegatedTokens: number; +} diff --git a/src/components/ManaCalculator/utils.ts b/src/components/ManaCalculator/utils.ts index 560ee1da960..9a6ca572255 100644 --- a/src/components/ManaCalculator/utils.ts +++ b/src/components/ManaCalculator/utils.ts @@ -1,5 +1,15 @@ -import { IOTA_SUPPLY, SHIMMER_SUPPLY, SLOTS_IN_EPOCH } from './constants'; -import { NetworkType } from './enums'; +import { + IOTA_CONGESTION, + IOTA_GENERATION_PER_SLOT, + IOTA_SUPPLY, + IOTA_THROUGHPUT, + SHIMMER_CONGESTION, + SHIMMER_GENERATION_PER_SLOT, + SHIMMER_SUPPLY, + SHIMMER_THROUGHPUT, + SLOTS_IN_EPOCH, +} from './constants'; +import { CongestionType, NetworkType, UserType } from './enums'; // Given a slot, returns the epoch that slot belongs to export function slotToEpoch(slot: number): number { @@ -32,6 +42,49 @@ export function getNetworkSupply(network: NetworkType): number { } } +export function getNetworkCongestion( + network: NetworkType, + congestionType: CongestionType, +): number { + if (congestionType === CongestionType.MEDIUM) { + const supply = getNetworkSupply(network); + const generation = getNetworkGenerationPerSlot(network); + const throughput = getNetworkThroughput(network); + + return (supply * generation) / (10 * throughput); + } else { + if (network == NetworkType.IOTA) { + return IOTA_CONGESTION[congestionType]; + } else { + return SHIMMER_CONGESTION[congestionType]; + } + } +} + +export function getNetworkGenerationPerSlot(network: NetworkType): number { + if (network == NetworkType.IOTA) { + return IOTA_GENERATION_PER_SLOT; + } else { + return SHIMMER_GENERATION_PER_SLOT; + } +} + +export function getNetworkThroughput(network: NetworkType): number { + if (network == NetworkType.IOTA) { + return IOTA_THROUGHPUT; + } else { + return SHIMMER_THROUGHPUT; + } +} + +export function getStakedOrDelegated(userType: UserType) { + if (userType == UserType.DELEGATOR) { + return 'delegatedTokens'; + } else { + return 'stakedTokens'; + } +} + export const roundMax = function (num: number, places: number) { return +(Math.round(Number(num + 'e+' + places)) + 'e-' + places); }; From c7e7722988c36cebf9426ba1b30dc59297ce5865 Mon Sep 17 00:00:00 2001 From: Dr-Electron Date: Wed, 8 Nov 2023 17:29:41 +0100 Subject: [PATCH 35/40] Format --- src/components/ManaCalculator/hooks/useResultsWithUnit.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ManaCalculator/hooks/useResultsWithUnit.ts b/src/components/ManaCalculator/hooks/useResultsWithUnit.ts index 66b52d00dd3..8e170bf2a0a 100644 --- a/src/components/ManaCalculator/hooks/useResultsWithUnit.ts +++ b/src/components/ManaCalculator/hooks/useResultsWithUnit.ts @@ -30,7 +30,7 @@ const getUnit = (value: number): Unit => { let bestUnits: Unit = Unit.default; const checkLength = Math.abs(value).toFixed(0).replace('.', '').length; - console.log(checkLength, value) + console.log(checkLength, value); if (checkLength > UNIT_MAP.M.dp) { bestUnits = Unit.M; } else if (checkLength > UNIT_MAP.K.dp) { From 5cca6c056e410e95db50e0170532636662e63b2f Mon Sep 17 00:00:00 2001 From: Dr-Electron Date: Wed, 8 Nov 2023 17:30:45 +0100 Subject: [PATCH 36/40] Remove Mana calc from Mana page --- docs/learn/protocols/iota2.0/core-concepts/mana.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/learn/protocols/iota2.0/core-concepts/mana.md b/docs/learn/protocols/iota2.0/core-concepts/mana.md index 3b82eeec6da..3f0c91df824 100644 --- a/docs/learn/protocols/iota2.0/core-concepts/mana.md +++ b/docs/learn/protocols/iota2.0/core-concepts/mana.md @@ -239,7 +239,3 @@ A reward scheme is always a powerful mechanism to incentivize actors to have cer - No incentives for centralizing the funds of validators and delegators. - By the construction of our reward formulas, there is no incentive for the centralization of validator funds. Technically speaking, this means that two different validators do not get more rewards by combining their stake. - Analogously, the concentration of delegator funds is disincentivized by the construction of our reward formula. As more delegated stake is concentrated on the same validator, the rewards of the delegators become smaller. Then, the delegators are incentivized to redelegate to validators with less delegated stake. In the long run, under the assumption that actors are rational, the system should stabilize around a constant ratio of delegated and validator stake among pools. - -## Mana Calculator - - From 5adcb2a1629dd52114292804a6d812c5e9180ead Mon Sep 17 00:00:00 2001 From: Dr-Electron Date: Wed, 8 Nov 2023 17:31:33 +0100 Subject: [PATCH 37/40] Remove unused var --- src/components/ManaCalculator/components/ManaCalculator.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/ManaCalculator/components/ManaCalculator.tsx b/src/components/ManaCalculator/components/ManaCalculator.tsx index a260e086880..c28102e6dd8 100644 --- a/src/components/ManaCalculator/components/ManaCalculator.tsx +++ b/src/components/ManaCalculator/components/ManaCalculator.tsx @@ -11,7 +11,6 @@ import { import { OutputForm, NetworkSection, - AdvancedSettingsValidator, RoleSection, OtherParametersSection, ManaAccumulation, From 4d921bfadc56563d113520e2b28fd2b18ffc85e4 Mon Sep 17 00:00:00 2001 From: Jeroen van den Hout Date: Wed, 8 Nov 2023 23:23:30 +0100 Subject: [PATCH 38/40] Fix linting errors --- .../ManaCalculator/components/CharTooltip.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/components/ManaCalculator/components/CharTooltip.tsx b/src/components/ManaCalculator/components/CharTooltip.tsx index a863582f058..bd3e9563dbb 100644 --- a/src/components/ManaCalculator/components/CharTooltip.tsx +++ b/src/components/ManaCalculator/components/CharTooltip.tsx @@ -1,9 +1,15 @@ import React from 'react'; +import { TooltipProps } from 'recharts'; import { getSizeOfUnit, Unit } from '../hooks'; export function chartTooltip(xLabel: string, yLabel: string, unit: Unit) { const unitSize = getSizeOfUnit(unit); - return ({ active, payload, label }) => { + + const ChartTooltip = ({ + active, + payload, + label, + }: TooltipProps) => { if (active && payload && payload.length) { const value = payload[0].value * unitSize; return ( @@ -16,4 +22,6 @@ export function chartTooltip(xLabel: string, yLabel: string, unit: Unit) { return null; }; + + return ChartTooltip; } From 413a470d343472e2fd07cd49edbe831de68158d2 Mon Sep 17 00:00:00 2001 From: Dr-Electron Date: Wed, 8 Nov 2023 23:36:48 +0100 Subject: [PATCH 39/40] Apply suggestions from code review Co-authored-by: Jeroen van den Hout --- docs/learn/protocols/iota2.0/core-concepts/mana-calculator.md | 4 ++-- docs/learn/protocols/iota2.0/core-concepts/mana.md | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/learn/protocols/iota2.0/core-concepts/mana-calculator.md b/docs/learn/protocols/iota2.0/core-concepts/mana-calculator.md index f88393fa97c..06d0cf24ddd 100644 --- a/docs/learn/protocols/iota2.0/core-concepts/mana-calculator.md +++ b/docs/learn/protocols/iota2.0/core-concepts/mana-calculator.md @@ -4,7 +4,7 @@ import ManaCalculator from '@site/src/components/ManaCalculator'; Mana is a reward resource generated by holding IOTA tokens. It is utilized for block issuance, access to network throughput, protection against Sybil attacks, and various other services. Our incentives scheme allows you to stake or delegate IOTA tokens to receive Mana rewards, in addition to the Mana generated simply by holding your IOTA tokens, without having to participate in any consensus-related activity. -Here, we introduce the Mana Calculator: a tool to help you make decisions about the type of participation that will suit you best, to help you predict the Mana generation you’ll be granted, and to decide the number of IOTA tokens you should hold to guarantee your desired level of access in the future. +Here, we introduce the Mana calculator: a tool to help you make decisions about the type of participation that will suit you best, to help you predict the Mana generation you’ll be granted, and to decide the number of IOTA tokens you should hold to guarantee your desired level of access in the future. ## How to use the Calculator: Step-by-step instructions @@ -14,7 +14,7 @@ Here, we introduce the Mana Calculator: a tool to help you make decisions about - **Input the number of tokens you own:** No matter which network and role you choose, your Mana generation will depend on how many available tokens you have. Pay attention to the units! The input should be done in IOTA or Shimmer (not microIota or Glow). -You're almost there! With the inputs above, you can already estimate how much Mana you’ll be granted per epoch. But what does it mean in TPS? How many blocks per second does your Mana grant you? The answer depends on the size of your block and the network congestion levels. However, we can use a default block size, which will be enough for most applications, and assume certain levels of congestion. This takes us to the last step in this calculator: +With the inputs above, you can already estimate how much Mana you’ll be granted per epoch. But what does it mean in TPS? How many blocks per second does your Mana grant you? The answer depends on the size of your block and the network congestion levels. However, we can use a default block size, which will be enough for most applications, and assume certain levels of congestion. This takes us to the last step in this calculator: - **Choose a congestion level:** Given a certain Mana generation per epoch, this can be translated into a number of blocks issued per second that depends on the congestion level. Choose one of the given congestion levels (low, stable, or extreme) to estimate how many blocks per second your tokens and participation grant you! This metric is also shown in another way: time until block issuance, which tells you in which periodicity you’ll be able to issue a block. diff --git a/docs/learn/protocols/iota2.0/core-concepts/mana.md b/docs/learn/protocols/iota2.0/core-concepts/mana.md index 3f0c91df824..5687a973808 100644 --- a/docs/learn/protocols/iota2.0/core-concepts/mana.md +++ b/docs/learn/protocols/iota2.0/core-concepts/mana.md @@ -1,5 +1,3 @@ -import ManaCalculator from '@site/src/components/ManaCalculator'; - # Tokenomics: Mana, Accounts, Staking and Delegation Mana is a scarce resource used to access the IOTA ledger and update its state through block creation. It is a spendable asset tracked in the _ledger state_, powering smart contracts, DeFi_applications, block creation, and various other services, and is linked to [accounts](#accounts), which allow you to [stake or delegate](#staking-and-delegation-1) IOTA to receive [Mana rewards](#mana-rewards). From 5a147f65678b224c5d6cf241f90662ee63ea20c5 Mon Sep 17 00:00:00 2001 From: Dr-Electron Date: Wed, 8 Nov 2023 23:39:18 +0100 Subject: [PATCH 40/40] Fix typo --- src/components/ManaCalculator/components/BlocksAllowance.tsx | 2 +- .../components/{CharTooltip.tsx => ChartTooltip.tsx} | 0 src/components/ManaCalculator/components/ManaAcculation.tsx | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename src/components/ManaCalculator/components/{CharTooltip.tsx => ChartTooltip.tsx} (100%) diff --git a/src/components/ManaCalculator/components/BlocksAllowance.tsx b/src/components/ManaCalculator/components/BlocksAllowance.tsx index 475758a1594..16b69c742a2 100644 --- a/src/components/ManaCalculator/components/BlocksAllowance.tsx +++ b/src/components/ManaCalculator/components/BlocksAllowance.tsx @@ -10,7 +10,7 @@ import { } from 'recharts'; import { stringifyUnit, Unit } from '../hooks'; import { EpochReward } from '../types'; -import { chartTooltip } from './CharTooltip'; +import { chartTooltip } from './ChartTooltip'; export function BlocksAllowance({ results, diff --git a/src/components/ManaCalculator/components/CharTooltip.tsx b/src/components/ManaCalculator/components/ChartTooltip.tsx similarity index 100% rename from src/components/ManaCalculator/components/CharTooltip.tsx rename to src/components/ManaCalculator/components/ChartTooltip.tsx diff --git a/src/components/ManaCalculator/components/ManaAcculation.tsx b/src/components/ManaCalculator/components/ManaAcculation.tsx index e2e180108ed..7b1faa850eb 100644 --- a/src/components/ManaCalculator/components/ManaAcculation.tsx +++ b/src/components/ManaCalculator/components/ManaAcculation.tsx @@ -10,7 +10,7 @@ import { } from 'recharts'; import { stringifyUnit, Unit } from '../hooks'; import { EpochReward } from '../types'; -import { chartTooltip } from './CharTooltip'; +import { chartTooltip } from './ChartTooltip'; export function ManaAccumulation({ results,