Skip to content

OIS Docs #420

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 45 commits into from
Sep 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
a45ab0a
initial commit
aditya520 Sep 9, 2024
4ccbeae
(first example)
aditya520 Sep 10, 2024
9896683
fix
aditya520 Sep 10, 2024
5f069f9
Design principles and implementation of OIS
aditya520 Sep 10, 2024
1b6da69
added math
aditya520 Sep 11, 2024
48270d1
wip-added examples
aditya520 Sep 11, 2024
035583c
calculations
aditya520 Sep 11, 2024
5e8b8d2
changes
aditya520 Sep 12, 2024
b43df17
changes
aditya520 Sep 12, 2024
dd0632f
align
aditya520 Sep 12, 2024
16ba053
added publisher ranking
aditya520 Sep 12, 2024
486245f
publisher ranking done
aditya520 Sep 12, 2024
466e9d7
edits and fixes to examples
YaserJazouane Sep 12, 2024
dfafea8
minor fix
YaserJazouane Sep 12, 2024
25fc245
minor formatting changes
YaserJazouane Sep 12, 2024
6eb23c7
requested changes
aditya520 Sep 12, 2024
e24087c
tiny chnages
aditya520 Sep 13, 2024
4c21958
interactive sim
aditya520 Sep 13, 2024
196eea1
fix
aditya520 Sep 13, 2024
8118f50
pre-commit
aditya520 Sep 13, 2024
1bef4e1
initial commit of the slashing rulebook
YaserJazouane Sep 13, 2024
b8d9c3e
adding slashing rulebook
YaserJazouane Sep 13, 2024
3accfbc
Moving slashing rulebook to OIS section
YaserJazouane Sep 13, 2024
99f3547
updates to the rulebook
YaserJazouane Sep 16, 2024
8e77510
formatting
YaserJazouane Sep 16, 2024
b65bd56
added example 6
aditya520 Sep 17, 2024
4a0993b
added example 6
aditya520 Sep 17, 2024
064ab69
fix formatting
YaserJazouane Sep 17, 2024
a70548d
minor fixes to symbology
YaserJazouane Sep 17, 2024
6659f41
minor fixes to symbology
YaserJazouane Sep 17, 2024
fa0f0fd
minor fixes to symbology
YaserJazouane Sep 17, 2024
5f40c42
fixing symbology
YaserJazouane Sep 17, 2024
146f2df
Fix staking cap bar issues
cprussin Sep 18, 2024
c99b645
requested changes
aditya520 Sep 19, 2024
27172c8
requested changes
aditya520 Sep 19, 2024
9e96d69
Update pages/home/oracle-integrity-staking/examples.mdx
aditya520 Sep 19, 2024
2b96bbe
Update pages/home/oracle-integrity-staking/examples.mdx
aditya520 Sep 19, 2024
57831e0
Update pages/home/oracle-integrity-staking/examples.mdx
aditya520 Sep 19, 2024
81c9b1a
requested changes
aditya520 Sep 20, 2024
e28b451
minor changes
YaserJazouane Sep 20, 2024
4036c32
Update pages/home/oracle-integrity-staking/mathematical-representatio…
aditya520 Sep 21, 2024
5535be9
requested changes
aditya520 Sep 21, 2024
06981c9
nits
aditya520 Sep 21, 2024
34908e8
minor change
YaserJazouane Sep 21, 2024
d4dd31d
minor changes
YaserJazouane Sep 21, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 129 additions & 0 deletions components/RewardSimulator.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<div className="border border-gray-300 dark:border-gray-700 p-6 rounded-lg">
<h3 className="text-lg font-semibold mb-4">Reward Simulator</h3>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div>
<label className="block mb-2">
<Latex>{"Publisher Stake ($S_p^p$):"}</Latex>
</label>
<input
type="number"
value={publisherStake}
onChange={(e) => setPublisherStake(Number(e.target.value))}
className="w-full p-2 border rounded bg-transparent"
/>
</div>
<div>
<label className="block mb-2">
<Latex>{"Delegator Stake ($S_p^d$):"}</Latex>
</label>
<input
type="number"
value={delegatorStake}
onChange={(e) => setDelegatorStake(Number(e.target.value))}
className="w-full p-2 border rounded bg-transparent"
/>
</div>
<div>
<label className="block mb-2">
<Latex>{"Maximum Cap ($C_p$):"}</Latex>
</label>
<input
type="number"
value={maxCap}
onChange={(e) => setMaxCap(Number(e.target.value))}
className="w-full p-2 border rounded bg-transparent"
/>
</div>
<div>
<label className="block mb-2">
<Latex>{"Delegator Fee ($f$) (%):"}</Latex>
</label>
<input
type="number"
value={delegatorFee}
onChange={(e) => setDelegatorFee(Number(e.target.value))}
className="w-full p-2 border rounded bg-transparent"
/>
</div>
<div>
<label className="block mb-2">
<Latex>{"Reward Rate ($r$) (%):"}</Latex>
</label>
<input
type="number"
value={rewardRate}
onChange={(e) => setRewardRate(Number(e.target.value))}
className="w-full p-2 border rounded bg-transparent"
/>
</div>
</div>
<div className="flex mt-6">
<div className="flex-1">
<h4 className="font-semibold mb-2">Calculated Rewards:</h4>
<p>
<Latex>{`Publisher Reward ($R^p_p$): ${publisherReward}`}</Latex>
</p>
<p>
<Latex>{`Delegator Reward ($R^d_p$): ${delegatorReward}`}</Latex>
</p>
</div>
<div className="flex-1 ml-6">
<h4 className="font-semibold mb-2">Calculated Reward Rates:</h4>
<p>
<Latex>{`Publisher Reward Rate ($r^p_p$): ${publisherRewardRate}%`}</Latex>
</p>
<p>
<Latex>{`Delegator Reward Rate ($r^d_p$): ${delegatorRewardRate}%`}</Latex>
</p>
</div>
</div>
</div>
);
};

export default RewardSimulator;
88 changes: 88 additions & 0 deletions components/StakingCapBar.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<div
className="rounded-lg relative border border-4 border-[#7142CF] p-1 bg-white whitespace-nowrap"
style={{
width: `${totalLength}px`,
height: `${height}px`,
}}
role="progressbar"
aria-valuenow={totalFillPercentage}
aria-valuemin={0}
aria-valuemax={100}
>
<Bar color="#5c48e4" fillPercent={clampedFillPercentage}>
{firstFillLabel}
</Bar>
<Bar color="#f0b6bb" fillPercent={clampedSecondFillPercentage}>
{secondFillLabel}
</Bar>
<div className="absolute right-0 bottom-full mb-[1.65rem]">
{totalLabel && <Label>{totalLabel}</Label>}
</div>
</div>
);
}

type BarProps = {
fillPercent: number;
children?: ReactNode | undefined;
color: string;
};

const Bar = ({ fillPercent, children, color }: BarProps) => (
<div
className="inline-block h-full transition-all duration-300 ease-in-out relative"
style={{
backgroundColor: color,
width: `${fillPercent}%`,
}}
>
{children && <Label>{children}</Label>}
</div>
);

const Label = ({ children }: { children: ReactNode }) => (
<div
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"
style={{
transition: "left 300ms ease-in-out",
}}
>
{children}
</div>
);
25 changes: 25 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
1 change: 1 addition & 0 deletions pages/home/_meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
},

"pyth-token": "PYTH Token",
"oracle-integrity-staking": "Oracle Integrity Staking (OIS)",
"metrics": "Pyth Metrics",
"whitepaper": "Whitepaper",
"security": "Security"
Expand Down
36 changes: 36 additions & 0 deletions pages/home/oracle-integrity-staking.mdx
Original file line number Diff line number Diff line change
@@ -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.
5 changes: 5 additions & 0 deletions pages/home/oracle-integrity-staking/_meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"mathematical-representation": "Mathematical Representation",
"examples": "Examples",
"slashing-rulebook": "Slashing Rulebook"
}
Loading
Loading