diff --git a/components/RewardSimulator.tsx b/components/RewardSimulator.tsx new file mode 100644 index 00000000..1f7f04ef --- /dev/null +++ b/components/RewardSimulator.tsx @@ -0,0 +1,129 @@ +import React, { useState, useEffect } from "react"; +import "katex/dist/katex.min.css"; +import Latex from "react-latex-next"; + +const RewardSimulator: React.FC = () => { + const [publisherStake, setPublisherStake] = useState(200); + const [delegatorStake, setDelegatorStake] = useState(300); + const [maxCap, setMaxCap] = useState(500); + const [delegatorFee, setDelegatorFee] = useState(2); + const [rewardRate, setRewardRate] = useState(10); + + const [publisherReward, setPublisherReward] = useState(0); + const [delegatorReward, setDelegatorReward] = useState(0); + const [publisherRewardRate, setPublisherRewardRate] = useState(0); + const [delegatorRewardRate, setDelegatorRewardRate] = useState(0); + + useEffect(() => { + const calculateRewards = () => { + const totalStake = publisherStake + delegatorStake; + const eligibleAmount = Math.min(totalStake, maxCap); + const totalReward = (rewardRate / 100) * eligibleAmount; + + const publisherRewardBase = + (rewardRate / 100) * Math.min(publisherStake, maxCap); + const delegatorRewardBase = totalReward - publisherRewardBase; + + const delegatorFeeAmount = (delegatorFee / 100) * delegatorRewardBase; + + const finalDelegatorReward = delegatorRewardBase - delegatorFeeAmount; + const finalPublisherReward = publisherRewardBase + delegatorFeeAmount; + + setPublisherReward(Number(finalPublisherReward.toFixed(2))); + setDelegatorReward(Number(finalDelegatorReward.toFixed(2))); + setPublisherRewardRate( + Number(((finalPublisherReward * 100) / publisherStake).toFixed(2)) + ); + setDelegatorRewardRate( + Number(((finalDelegatorReward * 100) / delegatorStake).toFixed(2)) + ); + }; + + calculateRewards(); + }, [publisherStake, delegatorStake, maxCap, delegatorFee, rewardRate]); + + return ( +
+

Reward Simulator

+
+
+ + setPublisherStake(Number(e.target.value))} + className="w-full p-2 border rounded bg-transparent" + /> +
+
+ + setDelegatorStake(Number(e.target.value))} + className="w-full p-2 border rounded bg-transparent" + /> +
+
+ + setMaxCap(Number(e.target.value))} + className="w-full p-2 border rounded bg-transparent" + /> +
+
+ + setDelegatorFee(Number(e.target.value))} + className="w-full p-2 border rounded bg-transparent" + /> +
+
+ + setRewardRate(Number(e.target.value))} + className="w-full p-2 border rounded bg-transparent" + /> +
+
+
+
+

Calculated Rewards:

+

+ {`Publisher Reward ($R^p_p$): ${publisherReward}`} +

+

+ {`Delegator Reward ($R^d_p$): ${delegatorReward}`} +

+
+
+

Calculated Reward Rates:

+

+ {`Publisher Reward Rate ($r^p_p$): ${publisherRewardRate}%`} +

+

+ {`Delegator Reward Rate ($r^d_p$): ${delegatorRewardRate}%`} +

+
+
+
+ ); +}; + +export default RewardSimulator; diff --git a/components/StakingCapBar.tsx b/components/StakingCapBar.tsx new file mode 100644 index 00000000..4840e260 --- /dev/null +++ b/components/StakingCapBar.tsx @@ -0,0 +1,88 @@ +import React, { type ReactNode, useMemo } from "react"; + +interface StakingCapBarProps { + totalLength?: number; + height?: number; + fillPercentage: number; + secondFillPercentage: number; + firstFillLabel?: string; + secondFillLabel?: string; + totalLabel?: string; +} + +export default function StakingCapBar({ + totalLength = 500, + height = 80, + fillPercentage, + secondFillPercentage, + firstFillLabel, + secondFillLabel, + totalLabel, +}: StakingCapBarProps) { + const clampedFillPercentage = useMemo( + () => Math.min(100, Math.max(0, fillPercentage)), + [fillPercentage] + ); + const clampedSecondFillPercentage = useMemo( + () => + Math.min(100 - clampedFillPercentage, Math.max(0, secondFillPercentage)), + [clampedFillPercentage, secondFillPercentage] + ); + const totalFillPercentage = useMemo( + () => clampedFillPercentage + clampedSecondFillPercentage, + [clampedFillPercentage, clampedSecondFillPercentage] + ); + + return ( +
+ + {firstFillLabel} + + + {secondFillLabel} + +
+ {totalLabel && } +
+
+ ); +} + +type BarProps = { + fillPercent: number; + children?: ReactNode | undefined; + color: string; +}; + +const Bar = ({ fillPercent, children, color }: BarProps) => ( +
+ {children && } +
+); + +const Label = ({ children }: { children: ReactNode }) => ( +
+ {children} +
+); diff --git a/package-lock.json b/package-lock.json index ef0dff3d..5f21869e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,6 +27,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-gtm-module": "^2.0.11", + "react-latex-next": "^3.0.0", "react-syntax-highlighter": "^15.5.0", "sharp": "^0.33.2", "toml": "^3.0.0", @@ -23264,6 +23265,22 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, + "node_modules/react-latex-next": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/react-latex-next/-/react-latex-next-3.0.0.tgz", + "integrity": "sha512-x70f1b1G7TronVigsRgKHKYYVUNfZk/3bciFyYX1lYLQH2y3/TXku3+5Vap8MDbJhtopePSYBsYWS6jhzIdz+g==", + "dependencies": { + "katex": "^0.16.0" + }, + "engines": { + "node": ">=12", + "npm": ">=5" + }, + "peerDependencies": { + "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" + } + }, "node_modules/react-markdown": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-9.0.1.tgz", @@ -44348,6 +44365,14 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, + "react-latex-next": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/react-latex-next/-/react-latex-next-3.0.0.tgz", + "integrity": "sha512-x70f1b1G7TronVigsRgKHKYYVUNfZk/3bciFyYX1lYLQH2y3/TXku3+5Vap8MDbJhtopePSYBsYWS6jhzIdz+g==", + "requires": { + "katex": "^0.16.0" + } + }, "react-markdown": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-9.0.1.tgz", diff --git a/package.json b/package.json index 1610aaac..c0f13d21 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-gtm-module": "^2.0.11", + "react-latex-next": "^3.0.0", "react-syntax-highlighter": "^15.5.0", "sharp": "^0.33.2", "toml": "^3.0.0", diff --git a/pages/home/_meta.json b/pages/home/_meta.json index fa7c78fb..cb30232f 100644 --- a/pages/home/_meta.json +++ b/pages/home/_meta.json @@ -32,6 +32,7 @@ }, "pyth-token": "PYTH Token", + "oracle-integrity-staking": "Oracle Integrity Staking (OIS)", "metrics": "Pyth Metrics", "whitepaper": "Whitepaper", "security": "Security" diff --git a/pages/home/oracle-integrity-staking.mdx b/pages/home/oracle-integrity-staking.mdx new file mode 100644 index 00000000..43991c3f --- /dev/null +++ b/pages/home/oracle-integrity-staking.mdx @@ -0,0 +1,36 @@ +# Oracle Integrity Staking (OIS) + +This document outlines the design principles and implementation details of the [Oracle Integrity Staking (OIS)](https://staking.pyth.network/) protocol. + +## Design Principles + +OIS's economic design focuses on awarding and penalizing stakers over the primary dimension of data accuracy. + +Stakers are incentivized to help maintain data quality by receiving rewards from an open-ended pool. However, they also face the risk of having their stake slashed as a penalty for failing to maintain data accuracy. + +The core design principles behind OIS include the following: + +- Oracle Integrity Staking secures all current and future price feeds produced by the Pyth Network. +- Data Publishers are individually responsible for data accuracy. +- Rewards and penalties are proportionate to the stake assigned to each publisher. Delegators share the risks and rewards of the publisher(s) to whom they assign their stake. +- A higher number of publishers for each price feed contributes positively to the security of such feed. +- Staking for **OIS** is complementary to staking for **governance**, and eligible $PYTH tokens can be used for both purposes. +- The ability to slash stake in OIS requires **unlocked** \$PYTH tokens, whereas staking for governance can use both locked and unlocked $PYTH tokens. +- All parameter related to the OIS protocol are subject to the governance of the Pyth DAO. + +## Implementation + +OIS implements the design principles above through the following structure: + +1. OIS is subject to the same 7-day epoch as governance voting. All parameters used in the OIS protocol are captured at each start of the epoch on Thursdays at 0:00 UTC and remain constant until the end of the epoch. Staking into OIS is also subject to warmup and cooldown period prior and post epoch respectively. + +2. Each publisher is programmatically assigned a staking pool where they can self-stake and to which other stakers can delegate. + - The staking pool assigned to each publisher covers all price feeds/symbols they publish. + - Each staking pool has a soft cap. This soft cap dynamically expands and shrinks given the number of symbols published by the assigned publisher. + - Price feeds with a low number of publishers contribute more to the cap's expansion. + - Staking into the pool can exceed the soft cap. However no rewards are paid for the excess amount. On the contrary, the excess amount is subject to the penalty if the assigned publisher's data is inaccurate. + - The OIS protocol prioritizes self-stake attributed to the **publisher's stake** when distributing rewards to the publisher's pool. + - All staking pools charge the same delegation fee for stakers who are delegating stake to one or many pools. +3. Each pool has a maximum reward rate per epoch, which applies only to the staked amount within the soft cap. +4. The total amount of rewards paid to all pools is bound by the same cap relative to the amount of rewards available to the OIS protocol. +5. Slashing of stake has a hard percentage cap and only impacts pools that assigned to publishers responsible for the poor data quality. Both self-stakers and delegators are also slashed proportionally to their staked amount in the impacted pools. diff --git a/pages/home/oracle-integrity-staking/_meta.json b/pages/home/oracle-integrity-staking/_meta.json new file mode 100644 index 00000000..6133b40e --- /dev/null +++ b/pages/home/oracle-integrity-staking/_meta.json @@ -0,0 +1,5 @@ +{ + "mathematical-representation": "Mathematical Representation", + "examples": "Examples", + "slashing-rulebook": "Slashing Rulebook" +} diff --git a/pages/home/oracle-integrity-staking/examples.mdx b/pages/home/oracle-integrity-staking/examples.mdx new file mode 100644 index 00000000..6191889d --- /dev/null +++ b/pages/home/oracle-integrity-staking/examples.mdx @@ -0,0 +1,179 @@ +import RewardSimulator from "@/components/RewardSimulator"; + +# Examples + +This reference page provides examples of various scenarios to illustrate the Mathematical Representations of OIS. + +NOTE: All the symbols used in the examples are explained in the [Mathematical Representation](/home/pyth-token/oracle-integrity-staking/mathematical-representation) section. + +## Example 1: Only Publisher Stake + +This example takes the case of one pool where the pool has stake from only the publisher. + +$$ +\begin{aligned} +{S^p_p} &= 100 \\ +{S^d_p} &= 0 \\ +{S^p} &= {S^p_p} + {S^d_p} = 100 + 0 = 100 \\ +{C}_p &= 500 \\ +\text{Total Amount eligible for Rewards} \quad{E_p} &= min({S}_p, {C}_p) = min(500, 100) = 100 \\ +\text{Annual Rate of Rewards} \quad{r} &= 10\% \\ + +\text{Total Rewards for one year} \quad{R_p} &= {r} \times {E_p} = 10\% \times 100 = 10 \\ +\text{Publisher Rewards} \quad{R^p_p} &= {r} \times min({S^p_p}, {C}_p) = 10\% \times 100 = 10 \\ +\text{Delegator Rewards} \quad{R^d_p} &= {R_p} - {R^p_p} = 10 - 10 = 0 \\ +\text{Effective Publisher APY} \quad{r^p_p} &= \frac{R^p_p}{S^p_p} = \frac{10}{100} = 10\% \\ +\text{Effective Delegator APY} \quad{r^d_p} &= \frac{R^d_p}{S^d_p} = \frac{0}{0} = 0\% \\ +\end{aligned} +$$ + +## Example 2: Publisher and Delegator Stake + +This example takes the case where the pool has stake from both the publisher and the delegator. + +$$ +\begin{aligned} +{S^p_p} &= 100 \\ +{S^d_p} &= 100 \\ +{S_p} &= {S^p_p} + {S^d_p} = 100 + 100 = 200 \\ +{C}_p &= 500 \\ +\text{Total Amount eligible for Rewards} \quad{E_p} &= min({S}_p, {C}_p) = min(500, 200) = 200 \\ +\text{Annual Rate of Rewards} \quad{r} &= 10\% \\ + +\text{Total Rewards for one year} \quad{R_p} &= {r} \times {E_p} = 10\% \times 200 = 20 \\ +\text{Publisher Rewards} \quad{R^p_p} &= {r} \times min({S^p_p}, {C}_p) = 10\% \times 100 = 10 \\ +\text{Delegator Rewards} \quad{R^d_p} &= {R_p} - {R^p_p} = 20 - 10 = 10 \\ +\text{Effective Publisher APY} \quad{r^p_p} &= \frac{R^p_p}{S^p_p} = \frac{10}{100} = 10\% \\ +\text{Effective Delegator APY} \quad{r^d_p} &= \frac{R^d_p}{S^d_p} = \frac{10}{100} = 10\% \\ +\end{aligned} +$$ + +## Example 3: Publisher and Delegator Stake more than the Cap + +This example takes the case where the combined stake of both the publisher and the delegator exceeds the cap. + +$$ +\begin{aligned} +{S^p_p} &= 300 \\ +{S^d_p} &= 300 \\ +{S_p} &= {S^p_p} + {S^d_p} = 300 + 300 = 600 \\ +{C}_p &= 500 \\ +\text{Total Amount eligible for Rewards} \quad{E_p} &= min({S}_p, {C}_p) = min(500, 600) = 500 \\ +\text{Annual Rate of Rewards} \quad{r} &= 10\% \\ + +\text{Total Rewards for one year} \quad{R_p} &= {r} \times {E_p} = 10\% \times 500 = 50 \\ +\text{Publisher Rewards} \quad{R^p_p} &= {r} \times min({S^p_p}, {C}_p) = 10\% \times 300 = 30 \\ +\text{Delegator Rewards} \quad{R^d_p} &= {R_p} - {R^p_p} = 50 - 30 = 20 \\ +\text{Effective Publisher APY} \quad{r^p_p} &= \frac{R^p_p}{S^p_p} = \frac{30}{300} = 10\% \\ +\text{Effective Delegator APY} \quad{r^d_p} &= \frac{R^d_p}{S^d_p} = \frac{20}{300} = 6.67\% \\ +\end{aligned} +$$ + +## Example 4: Introducing Delegator Fees + +This example demonstrates how the delegation fee affect the reward distribution between the publisher and the delegator. + +$$ +\begin{aligned} +\quad{S^p_p} &= 200 \\ +\quad{S^d_p} &= 300 \\ +\quad{S_p} &= {S^p_p} + {S^d_p} = 200 + 300 = 500 \\ +\quad{C}_p &= 500 \\ +\quad{E_p} &= min({S}_p, {C}_p) = min(500, 500) = 500 \\ +\quad{r} &= 10\% \\ +\quad{f} &= 2\% \\ + +\quad{R_p} &= {r} \times {R_p} = 10\% \times 500 = 50 \\ +\quad{R^p_p} &= {r} \times min({S^p_p}, {C}_p) = 10\% \times 200 = 20 \\ +\quad{R^d_p} &= {R_p} - {R^p_p} = 50 - 20 = 30 \\ +\text{Fee paid by Delegator} \quad{F^d_p} &= {f} \times {R^d_p} = 2\% \times 30 = 0.6 \\ +\text{Final Delegator Rewards} \quad{R^d_p} &= {R^d_p} - {F^d_p} = 30 - 0.6 = 29.4 \\ +\text{Total Publisher Rewards} \quad{R^p_p} &= {R^p_p} + {F^d_p} = 20 + 0.6 = 20.6 \\ +\text{Effective Publisher APY} \quad{r^p_p} &= \frac{R^p_p}{S^p_p} = \frac{20.6}{200} = 10.3\% \\ +\text{Effective Delegator APY} \quad{r^d_p} &= \frac{R^d_p}{S^d_p} = \frac{29.4}{300} = 9.8\% \\ +\end{aligned} +$$ + +In the example, the delegator pays a 2\% fee on their rewards to the publisher. This fee is deducted from the delegator's reward and added to the publisher's reward. + +## Example 5: Slashing event on the pool + +This example demonstrates the impact of a slashing event on the staked PYTH tokens and rewards distributed to both the publisher and the delegator. + +$$ +\begin{aligned} +\quad{S^p_p} &= 300 \\ +\quad{S^d_p} &= 200 \\ +\quad{S_p} &= {S^p_p} + {S^d_p} = 300 + 200 = 500 \\ + +\text{Maximum slashing rate}\quad{z} &= 5\% \\ + +\text{Publisher Stake post slashing}\quad{S^p_p} &= (1 - 5\%) \times 300 = 285 \\ +\text{Delegator Stake post slashing}\quad{S^d_p} &= (1 - 5\%) \times 200 = 190 \\ + +\end{aligned} +$$ + +In this example, the stake is uniformly slashed by 5\%, affecting both the publisher and the delegator. Slashing impact the total stake into the pool, regardless of the Cap. + +## Example 6: Increasing the cap of the pool + +This example shows how a publisher can increase the cap of the pool assigned to them. +As described in the [Mathematical Representation](/home/pyth-token/oracle-integrity-staking/mathematical-representation#pool-cap), the cap is calculated as: + +$$ +\large{{\bold{C_p}} = M \cdot \sum_{s \in \text{Symbols\_p}} \frac{1}{\max(n_s, Z)}} +$$ + +In this scenario, let's assume that + +- The constant parameter representing the target stake per symbol $M$ is 100 +- The constant parameter to control cap contribution $Z$ is 5 +- Current symbols published are \{$s_{1}$,.., $s_{5}$\} where for every symbol currently published $n_s$ = 5 (for i = 1 .. 5 $n_{s_i}$ = 5) + +The cap of the pool is calculated as follows: + +$$ +\begin{aligned} +\quad{C_p} &= M \cdot \sum_{s \in \text{\{$s_{1}$,.., $s_{5}$\}}} \frac{1}{\max(n_s, Z)} \\ +&= 100 \cdot \sum_{s \in \text{\{$s_{1}$,.., $s_{5}$\}}} \frac{1}{\max(5, 5)} \\ +&= 100 \cdot \sum_{s \in \text{\{$s_{1}$,.., $s_{5}$\}}} \frac{1}{5} \\ +&= 100 \cdot 1 = 100 \\ +\end{aligned} +$$ + +Here publisher has 2 options to increase the cap of the pool assigned to it. + +### Option 1: Publish new symbol with a low number of publishers + +Assume the publisher decides to publish a new symbol with only 3 publishers, $n_{s_{low}}$ = 3. + +The new pool cap would change as the sum of the current cap from the 5 symbols published plus the cap gained from publishing $s_{low}$ (where $n_{s_{low}}$ = 3 + 1 = 4) + +$$ +\begin{aligned} +C_{p_{option1}} &= 100 + 100 \cdot \frac{1}{\max(4, 5)} \\ +&= 100 + 100 \cdot \frac{1}{5} \\ +&= 100 + 20 = 120 +\end{aligned} +$$ + +### Option 2: Publish additional symbols where the cap of 32 publishers is not reached + +Assuming there is room to publish 5 more symbols \{$s_{6}$,.., $s_{10}$\} where each have currently 9 publishers ( for i = 6 .. 10 $n_{s_i}$ = 9) + +The new pool cap would change as the sum of the current cap from the 5 symbols published plus the cap gained from publishing the additional symbols \{$s_{6}$,.., $s_{10}$\} (where for i = 6 .. 10 $n_{s_i}$ = 10) + +$$ +\begin{aligned} +C_{p_{option2}} &= 100 + 100 \cdot \sum_{s \in \text{\{$s_{6}$,.., $s_{10}$\}}} \frac{1}{\max(10, 5)} \\ +&= 100 + 100 \cdot 5 \cdot \frac{1}{10} \\ +&= 100 + 50 = 150 +\end{aligned} +$$ + +## Reward Calculator + +Use the calculator below to calculate publisher and delegator rewards based on your inputs. + + diff --git a/pages/home/oracle-integrity-staking/mathematical-representation.mdx b/pages/home/oracle-integrity-staking/mathematical-representation.mdx new file mode 100644 index 00000000..8879978e --- /dev/null +++ b/pages/home/oracle-integrity-staking/mathematical-representation.mdx @@ -0,0 +1,94 @@ +# Mathematical Representation + +This section outlines the mathematical representation of the Oracle Integrity Staking (OIS) protocol. + +As explained in the [implementation](./implementation.mdx) section, every publisher is assigned a staking pool where they can self-stake and to which other stakers can delegate. + +## Pool Cap + +The **pool cap** is calculated as follows: + +$$ +\large{\text{Pool Cap}: {\bold{C_p}} = M \cdot \sum_{s \in \text{Symbols\_p}} \frac{1}{\max(n_s, Z)}} +$$ + +Where: + +- $M$ is a constant parameter representing the target stake per symbol. +- $\text{Symbols\_p}$ is the set of symbols published by the publisher $p$. +- $n_s$ be the number of publishers for symbol $s$. +- $Z$ is a constant parameter to control cap contribution from symbols with a low number of publishers. + +This formula ensures that symbols with a lower number of publishers contribute more to the overall cap, while symbols with a higher number of publishers contribute less. This is because the contribution of each symbol is inversely proportional to the number of publishers (or Z, whichever is larger). + +## Reward + +The reward $R_p$ distributed to each pool is calculated as follows: + +$$ +\large{\bold{R_p} = y \cdot \min(S_p, C_p)} +$$ + +Where: + +- $y$ is the cap to the rate of rewards for any pool +- $S_p$ be the stake assigned to the publisher p pool , made of self-staked amount $S^{p}_{p}$ and delegated stake $S^{d}_{p}$ , or $S_{p} = S^{p}_{p} + S^{d}_{p}$. +- $C_p$ be the stake cap for the pool assigned to publisher p. + +The total amount of rewards distributed to all pools is bound by the same cap relative to the amount of rewards available to the OIS protocol. + +$$ +\large{\sum_{p \in \text{Publishers}} R_p \leq y \cdot \min(N \cdot M, \sum_{p=1}^{P} S_p)} +$$ + +Where: + +- $N$ is the total number of symbols in the system. +- $P$ is the total number of publishers in the system. + +Whereas the reward component relative to the amount self-staked by the publisher $p$ is defined as: + +$$ +\large{\bold{R^{p}_{p}} = y \cdot \min(S^p_p, C_p) = R_p - R^d_p} +$$ + +Where: + +- $R^d_p$ is the reward component relative to the amount delegated to the publisher $p$. + +## Slashing + +Slashing is an important aspect of the OIS protocol to ensure the integrity of the system. + +The slashed amount for each pool is calculated as follows: + +$$ +\large{\bold{SL_p} = w \cdot S_p = w \cdot (S^{p}_{p} + S^{d}_{p})} +$$ + +Where: + +- $SL_p$ is the slashed amount for the publisher $p$ pool. +- $w$ is the slashing rate. +- $S_p$ is the stake assigned to the publisher $p$ pool , made of self-staked amount $S^{p}_{p}$ and delegated stake $S^{d}_{p}$ , or $S_{p} = S^{p}_{p} + S^{d}_{p}$. + +Here $SL_p$ is uniformly allocated to both the self-staking publisher and delegators in the pool, pro-rata to their respective stake. + +Subsequently, the rewards received by a publisher and delegators into a pool, net of any slashed amounts can be expressed as below: + +$$ +\large{\bold{\Pi^p_p} = ( R^p_p + f \cdot R^d_p ) - w \cdot S^p_p} +$$ + +$$ +\large{\bold{\Pi^d_p} = R^d_p - ( f \cdot R^d_p + w \cdot S^d_p )} +$$ + +Where: + +- $\Pi^p_p$ is the net reward received by the publisher $p$ after slashing. +- $\Pi^d_p$ is the net reward received by the delegators after slashing. +- $f$ is the delegation fee charged by the pool. +- $w$ is the slashing rate. +- $S^p_p$ is the amount self-staked by the publisher $p$. +- $S^d_p$ is the amount delegated to the publisher $p$. diff --git a/pages/home/oracle-integrity-staking/publisher-quality-ranking.mdx b/pages/home/oracle-integrity-staking/publisher-quality-ranking.mdx new file mode 100644 index 00000000..4f7a3347 --- /dev/null +++ b/pages/home/oracle-integrity-staking/publisher-quality-ranking.mdx @@ -0,0 +1,112 @@ +# Publisher Quality Ranking + +This document introduces a quality ranking system to ensure high-quality pricing data on Pythnet. The ranking system will use **three** metrics to evaluate each publisher's performance: + +- Uptime (40% weight), +- Price Deviation (40% weight), +- Lack of Stalled Prices (20% weight). + +The ranking will be calculated **monthly** to ensure that only the top-performing publishers remain permissioned for each price feed on Pythnet. + +**Important: Publishers with an uptime of at least 50% will be included in the ranking. If a publisher's uptime is less than 50%, then the deviation and the stalled score of the publisher will be 0 to reflect their ineligibility.** + +Publishers in Pythtest conformance who are not publishing on Pythnet and pass this uptime condition will also be ranked together with the Pythnet publishers for each symbol. + +Checkout [Publisher Rankings](https://www.pyth.network/publishers/ranking) on the main website to see the updated rank of the publishers. + +## Metrics Used for Ranking + +The three metrics used for ranking are: + +### Uptime + +This metric measures the percentage of time a publisher is available and actively publishing data. A higher numerical score indicates a higher uptime maintained for the price feed. Score range: **0-1**. + +### Price Deviation + +This metric measures deviations that occur between a publishers' price and the aggregate price, normalized by the aggregate confidence interval. A higher numerical score indicates a lower degree of price deviation. Score range: **0-1**. + +### Lack of Stalled Prices + +This metric penalizes publishers reporting the same value for the price of an asset for at least 100 consecutive slots because such instances indicate potential data staleness. Publishers with fewer stalled prices will get a higher score. Score range: **0-1**. + +## Ranking Algorithm + +Each metric is assigned a weight as mentioned above, and the score for each metric is calculated based on the publisher's performance. +The scores from each metrics are aggregated with respect to their weights to get the final score for each publisher. +The weight distribution is as follows: + +- Uptime: 40% +- Price Deviation: 40% +- Lack of Stalled Prices: 20% + +Publishers are then sorted based on their final scores with the highest score indicating the best performance. +As mentioned earlier, the score for each metric range from 0 to 1, where 1 represents the best performance. +Each publisher will also be assigned a rank based on their final scores, where lower ranks are assigned to publishers with higher scores indicating better performance. + +## Metric Calculations + +This section provides a detailed breakdown of how each metric is calculated. + +### Uptime + +Uptime measures a publisher's reliability and availability. If a publisher consistently provides data without interruptions, it indicates a high level of reliability. This is aligned with the current conformance testing/PRP, which checks the publsiher's availability based on price publication within 10 slots. + +$$ +\text{Score}_{\text{Uptime}} = \frac{\text{Publisher Slot Count}}{\text{Aggregate Slot Count}} +$$ + +Uptime is given **40% weight** in the final ranking. + +**Reason for Weight:** Uptime is the most critical metric because consistent data availability is fundamental for ensuring a data feed's overall quality and reliability. A publisher that is frequently unable to publish for every set number of slots or unavailable would significantly disrupt the service, hence the high weight of 40%. + +### Price Deviation + +This metric evaluates the deviations between the publisher's price and the aggregate price, normalized by the aggregate's confidence interval. + +$$ +\text{Penalty}_{\text{Deviation}} = +\frac{1}{N} \sum_{i=1}^{N} \left( \frac{|P_i - A_i|}{{CI}_i} \right)^2 +$$ + +$$ +\text{Score}_{\text{Deviation}} = \frac{{\text{NumPublishers}}-{\text{Rank}}(\text{Penalty}_\text{Deviation}) + 1}{\text{NumPublishers}} +$$ + +Where: + +- $N$ is the total number of prices +- $P_i$ is the publisher's price at instance $i$ +- $A_i$ is the aggregate price at instance $i$ +- ${CI}_i$ is the aggregate confidence interval at instance $i$ + +It is calculated similarly to a z-score, where the aggregate price $A_i$ is the mean, and the aggregate confidence interval $CI_i$ is the Standard Deviation. A higher deviation score indicates that the publisher's prices are significantly inconsistent with the aggregate prices, especially when these deviations exceed the confidence interval. The $\text{Score}_{\text{Deviation}}$ is calculated by ranking the $\text{Penalty}_{\text{Deviation}}$ among all publishers and expressing this rank as a percentage of the total number of publishers. + +Price deviation is given **40% weight** in the final ranking. + +**Reason for Weight:** To maintain trust in the data published on a feed, it is crucial to ensure that reported prices are within a reasonable range of the aggregate price when adjusted for confidence intervals. Significant inconsistencies can undermine confidence in the published data, hence the weight of 40%. + +### Lack of Stalled Prices + +This metric checks if the publisher is reporting the same price continuously for a specified duration. Repeated prices over an extended period can indicate data staleness or a problem with the data feed. + +$$ +\text{Penalty}_{\text{Stalled}} = \frac{1}{N} \sum_{i=T+1}^{N} \mathbf{1} \left( P_i = P_{i-1} = \cdots = P_{i-T} \right) +$$ + +$$ +\text{Score}_{\text{Stalled}} = \max \text((1 - \text{Penalty}_{\text{Stalled}} \times 10) , 0) +$$ + +Where: + +- $N$ is the total number of slots for the aggregate price. +- $T$ is the duration threshold for staleness in slot. The threshold is $100$ slots (or about $40$ seconds) for all the symbols but can change in the future on a per-symbol basis. +- $P_i$ is the price reported by the publisher at time $i$. +- $\mathbf{1}(\cdot)$ is an indicator function that returns 1 if the condition inside it is true and 0 otherwise. +- $\text{Penalty}_{\text{Stalled}}$ calculates the fraction of time periods where the price remains unchanged for T consecutive intervals. +- $\text{Score}_{\text{Stalled}} $ adjusts the raw stalled penalty multiplied by $10$ to a score out of 1, which penalizes higher staleness rates. It means that if a publisher publishes stalled prices more than 10% of the times, it will get the score of 0. + +This metric is given **20% weight** in the final ranking. + +**Reason for Weight:** Staleness in data can mislead users into thinking the market conditions are unchanged, which can be detrimental in volatile market conditions. While important, measuring data staleness is deemed relatively less critical than evaluating uptime and price accuracy, hence a weight of 20%. diff --git a/pages/home/oracle-integrity-staking/slashing-rulebook.mdx b/pages/home/oracle-integrity-staking/slashing-rulebook.mdx new file mode 100644 index 00000000..52928773 --- /dev/null +++ b/pages/home/oracle-integrity-staking/slashing-rulebook.mdx @@ -0,0 +1,104 @@ +# Purpose and Scope + +This Pyth Slashing Rulebook (this ”Rulebook”) outlines the Terms & Conditions for slashing PYTH that has been staked for price feed accuracy on the Pyth network. This document develops the rules that the DAO must adhere to when assessing conditions and amounts of slashing. + +## Upholding Pyth Data quality + +### Role of Data Publishers + +- **Primary Source of Data:** Data publishers are the backbone of Pyth’s Price Feeds. They are the primary source of price data for the various assets that the Pyth Network serves data for +- **Data Collection:** Publishers are responsible for computing price data. This could involve accessing data from exchanges, trading platforms, or other price information sources +- **Data Submission:** Publishers submit their respective measurement of price to the Pyth Network, ensuring a constant stream of accurate and timely information +- **Maintaining Data Quality:** The most crucial role of publishers is ensuring the quality and integrity of the data they provide. This involves: + - **Reliable Sources:** Sourcing data from the necessary sources to produce high quality measurements of price data + - **Data Validation:** Implementing validation processes to verify the accuracy of the data before submission + - **Transparency:** Providing transparency into their data sources and methodologies so that users of the Pyth Network can assess the reliability of the data + - **Timeliness:** Ensuring data is submitted in a timely manner to reflect real-time market conditions + +### Responsibility for Data Quality + +Data publishers have a significant responsibility for maintaining data quality within the Pyth Network. This responsibility is not just ethical, but also incentivized through the network's structure: + +- **Staking and Slashing:** Publishers can stake PYTH tokens as collateral. In the event of data inaccuracies or inconsistencies, a portion of this stake can be slashed as a penalty. This mechanism ensures that publishers are discouraged from providing inaccurate data +- **Reputation:** The reputation of data publishers within the Pyth Network is directly linked to the quality of data they provide. Publishers with a track record of providing accurate data are more likely to rank higher and attract more adoption + +### Importance of Data Quality + +The Pyth Network is designed to provide reliable and trustworthy financial data to decentralized applications and smart contracts. The quality of the data it provides is paramount for the functioning of these applications and the overall success of the network. Therefore, the role of data publishers and their commitment to data quality cannot be overstated. + +## Staking + +Staking through OIS is a program to enhance the security of price feeds produced by publisher on the Pyth Network. + +Per the design of OIS, a pool aligned with a data publisher accepts stake from the publisher itself and from delegators. The additional stake allows such publisher to earn a delegation fee to contribute to the costs of providing data to the Pyth Network. Data publishers compete with one another to increase the number of price feeds they contribute to, and/or increase the quality of data that allows them to be selected to publish and/or enable higher staking cap for the pool each publisher is aligned to. + +## Slashing + +In the event of a Pyth data inaccuracy that can be verified against independent data references, a portion of the stake can be reduced from the pools aligned with the publishers responsible for the erroneous data. + +### Slashing Conditions + +A data quality issue happens when the aggregated price from Pyth is deemed inaccurate. Such inaccuracy has to fulfil the following criteria: + +- Prevalent prices for the asset(s) in question and related crosses using the most liquid venues at the time of the incident were at least 250 bps away from the price produced by Pyth +- The price deviation have lasted for at least 60 seconds +- Confidence Intervals prints from Pyth do not show an abnormal deviation during the misprint +- The market conditions are normal and the incident is not related to one or many macro events that make the accurate pricing of assets not feasible + +### Slashing Calculation and Distribution + +If slashing event confirmed, the Pythian Council will process calculation and distribution of the slashed stake according to the following: + +- **Stake Slashed** + - capped at 5% of the total amount staked (including the amount delegated) into pools associated with publishers identified as directly responsible for poor data quality. distribution of the slashed amount is uniform amongst publishers and delegator(s) + - In the case the total amount staked by the stakers responsible for the data quality issue is nil, no slashing takes place +- **Temporary or Permanent Removal:** + - Stakers responsible for more than 4 slashing events per calendar year may be excluded permanently from the network exclusion from the set of stakers and/or publishers + +### Slashing Process + +#### Evidence Collection & Analysis + +- The Pythian Council is tasked by the DAO to review the evidence presented by the protocols impacted by the potential Pyth data misprint +- The Pythian Council will review the evidence compares the evidence collected for the potential losses and against historical data +- In the case that the evidence corroborates, the Pythian Council will identify the publishers responsible for the slashing and define a slashable amount, up to 5% of the total amount staked into the pools of the publishers responsible the event + +#### Reporting + +- The Pythian Council is responsible to report on with reasonable details on the evidence found that led to the slashing event through [forum.pyth.network](http://forum.pyth.network). Such report should include: + - a recap of the slashing event and evidence collected + - a recap of the impact and the list of stakers impacted + - a recap of the slashing amount +- Such report is deemed definitive and not subject to further discussion in the absence of new evidence + +#### Timeline + +- The Pythian Council is responsible for analysing and delivering its conclusions within the same epoch when the potential slashing event happened or during the following epoch at the latest + +#### Post Slashing + +- Stakers continue staking with the residual amount post slashing. No forced unstaking happens post slashing +- The Pyth DAO controls the slashed amount upon execution of the slashing + +## Change Process + +The Pyth DAO is responsible for implementing procedures for proposing, reviewing, approving, and adopting changes to the rules, policies, or procedures related to this Rulebook. + +### Change Proposal + +1. **Initiation:** Any interested party in the Pyth DAO may propose a change to this Rulebook through the Pyth DAO Forum via the existing Pyth Improvement Proposal (PIP) process defined in the Pyth Constitution +2. **Submission:** Proposed changes should be submitted through the standard governance system for the Pyth DAO members to vote on +3. **Content:** an Operational PIP for making changes to this Rulebook should include: + - Abstract - that summarises the PIP + - Rationale - that explains why the Pyth community should implement the PIP and how it aligns with community’s mission and values + - Key Terms - a detailed description of the technical and/or commercial terms associated with the PIP + - Implementation Plan - steps envisioned to implement the PIP, including resources needed for each step and timelines. The implementation plan may include binding on-chain actions that will automatically execute when the PIP passes. + +### Review and Approval + +The decision on whether to approve a PIP related to this Rulebook remains with the Pyth DAO. A simple majority is required to approve Operational PIPs that make amendments to this Rulebook and its associated procedures. + +### Implementation + +1. **Effective Date:** Approved changes will become effective from the time they are approved or on the specified date +2. **Transition Period:** If necessary, a transition period may be established to allow the Pyth DAO and the Pythian Council to adjust to the new rules or procedures diff --git a/pages/home/pyth-token.mdx b/pages/home/pyth-token.mdx index fac25eb9..86989696 100644 --- a/pages/home/pyth-token.mdx +++ b/pages/home/pyth-token.mdx @@ -1,23 +1,38 @@ -# What is PYTH? +import { Steps } from "nextra/components"; - PYTH is the governance token of the Pyth Network. +# PYTH Token - PYTH Token holders can access Pyth governance through the convenient staking and governance [frontend](https://staking.pyth.network/). +The Pyth Network, as a distributed system, needs to have a constitution and a clear governance system. - Pyth Network’s governance system allows anyone with PYTH Tokens to participate. Token holders must stake their tokens in the Pyth staking program to vote on community governance proposals. Governance uses a 1:1 coin-voting system, where each staked token confers one vote. +PYTH is the governance token of the Pyth Network, and the [Pyth DAO constitution](https://github.com/pyth-network/governance/blob/main/docs/constitution/pyth-dao-constitution.md) is the governance framework for the Pyth DAO. The constitution outlines the rules and procedures of the Pyth DAO. These rules and procedures are generally enforced through on-chain contracts and the associated parameters, unless specified by the Pyth DAO for actuation off-chain. - Any PYTH Token holder can submit proposals to the Pyth DAO as long as they have 0.25% of the total PYTH tokens staked. +## PYTH Token Staking - A proposal is considered passed if it meets the following conditions at the end of the 7 day voting period: - - More yesses have been cast than nos. - - The "Approval Quorum" has been met. This is a percentage of staked tokens that must have voted yes for the proposal to pass. The threshold can vary depending on the type of proposal. The current thresholds can be found in the "Governances" sections of the [parameters of the DAO](https://app.realms.today/dao/PYTH/params) as "Community Vote Threshold Percentage". It is expressed as a percentage of staked tokens at the start of the voting period for the proposal. +PYTH Token can be staked for Governance and Oracle Integrity. - Proposals are binding on-chain: each proposal has one or more associated instructions that are executed when the proposal passes. Community governance proposals can relate to all of the following: + +### Staking PYTH for Governance - - Determine the size of update fees. - - Determine the reward distribution mechanism for publishers. - - Approve other software updates to on-chain programs across blockchains. - - Determine the price feeds are listed on Pyth and their reference data (e.g., number of decimal places in the price, reference exchanges). - - Choose the publishers that are permissioned to provide data for each price feed +PYTH token holders can participate in Pyth governance through staking and [governance](https://staking.pyth.network/). Token holders use their staked tokens in the Pyth staking program to vote on community governance proposals. + +Governance uses a 1:1 coin-voting system, where each staked token confers one vote. + +Any PYTH Token holder can submit proposals to the Pyth DAO as long as they have **0.25% **of the total PYTH tokens staked. +At the end of the **7 day** voting period, a proposal is passes if it meets the following conditions: + +- **More yesses** have been cast than nos. +- The "**Approval Quorum**" has been met. \ + **Approval Quorum** is a percentage of staked PYTH tokens that must have voted yes for the proposal to pass. "Community Vote Threshold Percentage" is expressed as percentage of staked tokens at the start of the voting period for the proposal. This percentage threshold can vary depending on the type of proposal. The current threshold can be found in the "Governances" sections of the [parameters of the DAO](https://app.realms.today/dao/PYTH/params). Please note that the scope of community governance proposals may be expanded if the PYTH token holders (or the Pyth DAO) decide so. + +### Staking PYTH for Oracle Integrity + +The Pyth Network is built to provide decentralized applications with reliable and trustworthy data. The quality of the data it provides is paramount for these application's functions and the network's overall success. + +Pyth's [Oracle Integrity Staking (OIS)](/home/pyth-token/oracle-integrity-staking) concentrates on producing quality data in the hands of a limited set of semi-trusted entities to achieve more coverage and lower latency than the competition. The responsibility of publishers over data quality is not just ethical but also incentivized through economics: + +- **Staking and Slashing:** Publishers can self-stake PYTH tokens as collateral. It also allows other stakers to choose publishers to delegate their PYTH tokens. In the event of data inaccuracies or inconsistencies, a portion of this stake can be slashed as a penalty. This mechanism ensures that publishers have a vested interest in providing accurate data +- **Reputation:** The reputation of data publishers is directly linked to the quality of data they provide. Publishers with a track record of providing accurate data are more likely to be trusted and attract more interest. + + diff --git a/tsconfig.json b/tsconfig.json index 50bcb22f..68ce12fa 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,7 +13,11 @@ "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, - "jsx": "preserve" + "jsx": "preserve", + "baseUrl": ".", + "paths": { + "@/components/*": ["components/*"] + } }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], "exclude": ["node_modules"]