Skip to content

Commit 8387777

Browse files
aditya520YaserJazouanecprussinguibescos
authored
OIS Docs (#420)
* initial commit * (first example) * fix * Design principles and implementation of OIS * added math * wip-added examples * calculations * changes * changes * align * added publisher ranking * publisher ranking done * edits and fixes to examples * minor fix * minor formatting changes * requested changes * tiny chnages * interactive sim * fix * pre-commit * initial commit of the slashing rulebook * adding slashing rulebook * Moving slashing rulebook to OIS section * updates to the rulebook * formatting * added example 6 * added example 6 * fix formatting * minor fixes to symbology * minor fixes to symbology * minor fixes to symbology * fixing symbology * Fix staking cap bar issues * requested changes * requested changes * Update pages/home/oracle-integrity-staking/examples.mdx Co-authored-by: guibescos <59208140+guibescos@users.noreply.github.com> * Update pages/home/oracle-integrity-staking/examples.mdx Co-authored-by: guibescos <59208140+guibescos@users.noreply.github.com> * Update pages/home/oracle-integrity-staking/examples.mdx Co-authored-by: guibescos <59208140+guibescos@users.noreply.github.com> * requested changes * minor changes * Update pages/home/oracle-integrity-staking/mathematical-representation.mdx Co-authored-by: guibescos <59208140+guibescos@users.noreply.github.com> * requested changes * nits * minor change * minor changes --------- Co-authored-by: yj <47570215+YaserJazouane@users.noreply.github.com> Co-authored-by: Connor Prussin <connor@prussin.net> Co-authored-by: guibescos <59208140+guibescos@users.noreply.github.com>
1 parent 95e46e9 commit 8387777

13 files changed

+808
-15
lines changed

components/RewardSimulator.tsx

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import React, { useState, useEffect } from "react";
2+
import "katex/dist/katex.min.css";
3+
import Latex from "react-latex-next";
4+
5+
const RewardSimulator: React.FC = () => {
6+
const [publisherStake, setPublisherStake] = useState(200);
7+
const [delegatorStake, setDelegatorStake] = useState(300);
8+
const [maxCap, setMaxCap] = useState(500);
9+
const [delegatorFee, setDelegatorFee] = useState(2);
10+
const [rewardRate, setRewardRate] = useState(10);
11+
12+
const [publisherReward, setPublisherReward] = useState(0);
13+
const [delegatorReward, setDelegatorReward] = useState(0);
14+
const [publisherRewardRate, setPublisherRewardRate] = useState(0);
15+
const [delegatorRewardRate, setDelegatorRewardRate] = useState(0);
16+
17+
useEffect(() => {
18+
const calculateRewards = () => {
19+
const totalStake = publisherStake + delegatorStake;
20+
const eligibleAmount = Math.min(totalStake, maxCap);
21+
const totalReward = (rewardRate / 100) * eligibleAmount;
22+
23+
const publisherRewardBase =
24+
(rewardRate / 100) * Math.min(publisherStake, maxCap);
25+
const delegatorRewardBase = totalReward - publisherRewardBase;
26+
27+
const delegatorFeeAmount = (delegatorFee / 100) * delegatorRewardBase;
28+
29+
const finalDelegatorReward = delegatorRewardBase - delegatorFeeAmount;
30+
const finalPublisherReward = publisherRewardBase + delegatorFeeAmount;
31+
32+
setPublisherReward(Number(finalPublisherReward.toFixed(2)));
33+
setDelegatorReward(Number(finalDelegatorReward.toFixed(2)));
34+
setPublisherRewardRate(
35+
Number(((finalPublisherReward * 100) / publisherStake).toFixed(2))
36+
);
37+
setDelegatorRewardRate(
38+
Number(((finalDelegatorReward * 100) / delegatorStake).toFixed(2))
39+
);
40+
};
41+
42+
calculateRewards();
43+
}, [publisherStake, delegatorStake, maxCap, delegatorFee, rewardRate]);
44+
45+
return (
46+
<div className="border border-gray-300 dark:border-gray-700 p-6 rounded-lg">
47+
<h3 className="text-lg font-semibold mb-4">Reward Simulator</h3>
48+
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
49+
<div>
50+
<label className="block mb-2">
51+
<Latex>{"Publisher Stake ($S_p^p$):"}</Latex>
52+
</label>
53+
<input
54+
type="number"
55+
value={publisherStake}
56+
onChange={(e) => setPublisherStake(Number(e.target.value))}
57+
className="w-full p-2 border rounded bg-transparent"
58+
/>
59+
</div>
60+
<div>
61+
<label className="block mb-2">
62+
<Latex>{"Delegator Stake ($S_p^d$):"}</Latex>
63+
</label>
64+
<input
65+
type="number"
66+
value={delegatorStake}
67+
onChange={(e) => setDelegatorStake(Number(e.target.value))}
68+
className="w-full p-2 border rounded bg-transparent"
69+
/>
70+
</div>
71+
<div>
72+
<label className="block mb-2">
73+
<Latex>{"Maximum Cap ($C_p$):"}</Latex>
74+
</label>
75+
<input
76+
type="number"
77+
value={maxCap}
78+
onChange={(e) => setMaxCap(Number(e.target.value))}
79+
className="w-full p-2 border rounded bg-transparent"
80+
/>
81+
</div>
82+
<div>
83+
<label className="block mb-2">
84+
<Latex>{"Delegator Fee ($f$) (%):"}</Latex>
85+
</label>
86+
<input
87+
type="number"
88+
value={delegatorFee}
89+
onChange={(e) => setDelegatorFee(Number(e.target.value))}
90+
className="w-full p-2 border rounded bg-transparent"
91+
/>
92+
</div>
93+
<div>
94+
<label className="block mb-2">
95+
<Latex>{"Reward Rate ($r$) (%):"}</Latex>
96+
</label>
97+
<input
98+
type="number"
99+
value={rewardRate}
100+
onChange={(e) => setRewardRate(Number(e.target.value))}
101+
className="w-full p-2 border rounded bg-transparent"
102+
/>
103+
</div>
104+
</div>
105+
<div className="flex mt-6">
106+
<div className="flex-1">
107+
<h4 className="font-semibold mb-2">Calculated Rewards:</h4>
108+
<p>
109+
<Latex>{`Publisher Reward ($R^p_p$): ${publisherReward}`}</Latex>
110+
</p>
111+
<p>
112+
<Latex>{`Delegator Reward ($R^d_p$): ${delegatorReward}`}</Latex>
113+
</p>
114+
</div>
115+
<div className="flex-1 ml-6">
116+
<h4 className="font-semibold mb-2">Calculated Reward Rates:</h4>
117+
<p>
118+
<Latex>{`Publisher Reward Rate ($r^p_p$): ${publisherRewardRate}%`}</Latex>
119+
</p>
120+
<p>
121+
<Latex>{`Delegator Reward Rate ($r^d_p$): ${delegatorRewardRate}%`}</Latex>
122+
</p>
123+
</div>
124+
</div>
125+
</div>
126+
);
127+
};
128+
129+
export default RewardSimulator;

components/StakingCapBar.tsx

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import React, { type ReactNode, useMemo } from "react";
2+
3+
interface StakingCapBarProps {
4+
totalLength?: number;
5+
height?: number;
6+
fillPercentage: number;
7+
secondFillPercentage: number;
8+
firstFillLabel?: string;
9+
secondFillLabel?: string;
10+
totalLabel?: string;
11+
}
12+
13+
export default function StakingCapBar({
14+
totalLength = 500,
15+
height = 80,
16+
fillPercentage,
17+
secondFillPercentage,
18+
firstFillLabel,
19+
secondFillLabel,
20+
totalLabel,
21+
}: StakingCapBarProps) {
22+
const clampedFillPercentage = useMemo(
23+
() => Math.min(100, Math.max(0, fillPercentage)),
24+
[fillPercentage]
25+
);
26+
const clampedSecondFillPercentage = useMemo(
27+
() =>
28+
Math.min(100 - clampedFillPercentage, Math.max(0, secondFillPercentage)),
29+
[clampedFillPercentage, secondFillPercentage]
30+
);
31+
const totalFillPercentage = useMemo(
32+
() => clampedFillPercentage + clampedSecondFillPercentage,
33+
[clampedFillPercentage, clampedSecondFillPercentage]
34+
);
35+
36+
return (
37+
<div
38+
className="rounded-lg relative border border-4 border-[#7142CF] p-1 bg-white whitespace-nowrap"
39+
style={{
40+
width: `${totalLength}px`,
41+
height: `${height}px`,
42+
}}
43+
role="progressbar"
44+
aria-valuenow={totalFillPercentage}
45+
aria-valuemin={0}
46+
aria-valuemax={100}
47+
>
48+
<Bar color="#5c48e4" fillPercent={clampedFillPercentage}>
49+
{firstFillLabel}
50+
</Bar>
51+
<Bar color="#f0b6bb" fillPercent={clampedSecondFillPercentage}>
52+
{secondFillLabel}
53+
</Bar>
54+
<div className="absolute right-0 bottom-full mb-[1.65rem]">
55+
{totalLabel && <Label>{totalLabel}</Label>}
56+
</div>
57+
</div>
58+
);
59+
}
60+
61+
type BarProps = {
62+
fillPercent: number;
63+
children?: ReactNode | undefined;
64+
color: string;
65+
};
66+
67+
const Bar = ({ fillPercent, children, color }: BarProps) => (
68+
<div
69+
className="inline-block h-full transition-all duration-300 ease-in-out relative"
70+
style={{
71+
backgroundColor: color,
72+
width: `${fillPercent}%`,
73+
}}
74+
>
75+
{children && <Label>{children}</Label>}
76+
</div>
77+
);
78+
79+
const Label = ({ children }: { children: ReactNode }) => (
80+
<div
81+
className="absolute top-full left-full transform -translate-x-1/2 mt-2 text-xs font-medium text-gray-800 dark:text-gray-200 whitespace-nowrap"
82+
style={{
83+
transition: "left 300ms ease-in-out",
84+
}}
85+
>
86+
{children}
87+
</div>
88+
);

package-lock.json

Lines changed: 25 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"react": "^18.2.0",
3030
"react-dom": "^18.2.0",
3131
"react-gtm-module": "^2.0.11",
32+
"react-latex-next": "^3.0.0",
3233
"react-syntax-highlighter": "^15.5.0",
3334
"sharp": "^0.33.2",
3435
"toml": "^3.0.0",

pages/home/_meta.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
},
3333

3434
"pyth-token": "PYTH Token",
35+
"oracle-integrity-staking": "Oracle Integrity Staking (OIS)",
3536
"metrics": "Pyth Metrics",
3637
"whitepaper": "Whitepaper",
3738
"security": "Security"
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Oracle Integrity Staking (OIS)
2+
3+
This document outlines the design principles and implementation details of the [Oracle Integrity Staking (OIS)](https://staking.pyth.network/) protocol.
4+
5+
## Design Principles
6+
7+
OIS's economic design focuses on awarding and penalizing stakers over the primary dimension of data accuracy.
8+
9+
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.
10+
11+
The core design principles behind OIS include the following:
12+
13+
- Oracle Integrity Staking secures all current and future price feeds produced by the Pyth Network.
14+
- Data Publishers are individually responsible for data accuracy.
15+
- 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.
16+
- A higher number of publishers for each price feed contributes positively to the security of such feed.
17+
- Staking for **OIS** is complementary to staking for **governance**, and eligible $PYTH tokens can be used for both purposes.
18+
- The ability to slash stake in OIS requires **unlocked** \$PYTH tokens, whereas staking for governance can use both locked and unlocked $PYTH tokens.
19+
- All parameter related to the OIS protocol are subject to the governance of the Pyth DAO.
20+
21+
## Implementation
22+
23+
OIS implements the design principles above through the following structure:
24+
25+
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.
26+
27+
2. Each publisher is programmatically assigned a staking pool where they can self-stake and to which other stakers can delegate.
28+
- The staking pool assigned to each publisher covers all price feeds/symbols they publish.
29+
- Each staking pool has a soft cap. This soft cap dynamically expands and shrinks given the number of symbols published by the assigned publisher.
30+
- Price feeds with a low number of publishers contribute more to the cap's expansion.
31+
- 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.
32+
- The OIS protocol prioritizes self-stake attributed to the **publisher's stake** when distributing rewards to the publisher's pool.
33+
- All staking pools charge the same delegation fee for stakers who are delegating stake to one or many pools.
34+
3. Each pool has a maximum reward rate per epoch, which applies only to the staked amount within the soft cap.
35+
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.
36+
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.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"mathematical-representation": "Mathematical Representation",
3+
"examples": "Examples",
4+
"slashing-rulebook": "Slashing Rulebook"
5+
}

0 commit comments

Comments
 (0)