Skip to content

Commit 4c21958

Browse files
committed
interactive sim
1 parent e24087c commit 4c21958

File tree

6 files changed

+174
-22
lines changed

6 files changed

+174
-22
lines changed

components/RewardSimulator.tsx

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

components/StakingCapBar.tsx

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,28 +11,30 @@ interface StakingCapBarProps {
1111
}
1212

1313
export default function StakingCapBar({
14-
totalLength = 300,
14+
totalLength = 500,
1515
height = 80,
1616
fillPercentage,
1717
secondFillPercentage,
1818
firstFillLabel,
1919
secondFillLabel,
2020
totalLabel
2121
}: StakingCapBarProps) {
22-
// Ensure fillPercentages are between 0 and 100
22+
const borderWidth = 4
23+
const gapWidth = 2
2324
const clampedFillPercentage = Math.min(100, Math.max(0, fillPercentage))
2425
const clampedSecondFillPercentage = Math.min(100 - clampedFillPercentage, Math.max(0, secondFillPercentage))
2526
const totalFillPercentage = clampedFillPercentage + clampedSecondFillPercentage
2627

2728
return (
2829
<div className="flex flex-col items-start">
2930
<div
30-
className="rounded overflow-hidden relative"
31+
className="rounded-lg overflow-hidden relative"
3132
style={{
3233
width: `${totalLength}px`,
3334
height: `${height}px`,
34-
border: '2px solid #7142CF',
35-
backgroundColor: '#FFFFFF'
35+
border: `${borderWidth}px solid #7142CF`,
36+
backgroundColor: '#FFFFFF',
37+
padding: `${gapWidth}px`
3638
}}
3739
role="progressbar"
3840
aria-valuenow={totalFillPercentage}
@@ -44,43 +46,45 @@ export default function StakingCapBar({
4446
className="h-full transition-all duration-300 ease-in-out relative"
4547
style={{
4648
width: `${clampedFillPercentage}%`,
47-
backgroundColor: '#7142CF'
49+
backgroundColor: '#5c48e4'
4850
}}
4951
>
5052
{firstFillLabel && (
5153
<div
52-
className="absolute bottom-0 left-1/2 transform -translate-x-1/2 translate-y-full mt-1 text-xs font-medium text-gray-700 whitespace-nowrap"
54+
className="absolute top-full left-full transform -translate-x-1/2 mt-2 text-xs font-medium text-gray-700 whitespace-nowrap"
5355
style={{
5456
transition: 'left 300ms ease-in-out'
5557
}}
5658
>
57-
{firstFillLabel}: {clampedFillPercentage}%
59+
{firstFillLabel}
5860
</div>
5961
)}
6062
</div>
6163
<div
6264
className="h-full transition-all duration-300 ease-in-out relative"
6365
style={{
6466
width: `${clampedSecondFillPercentage}%`,
65-
backgroundColor: '#7142CF'
67+
backgroundColor: '#f0b6bb'
6668
}}
6769
>
6870
{secondFillLabel && (
6971
<div
70-
className="absolute bottom-0 left-1/2 transform -translate-x-1/2 translate-y-full mt-1 text-xs font-medium text-gray-700 whitespace-nowrap"
72+
className="absolute top-full left-full transform -translate-x-1/2 mt-2 text-xs font-medium text-gray-700 whitespace-nowrap"
7173
style={{
7274
transition: 'left 300ms ease-in-out'
7375
}}
7476
>
75-
{secondFillLabel}: {clampedSecondFillPercentage}%
77+
{secondFillLabel}
7678
</div>
7779
)}
7880
</div>
7981
</div>
8082
</div>
8183
{totalLabel && (
82-
<div className="mt-6 text-sm font-medium text-gray-700">
83-
{totalLabel}: {totalFillPercentage}%
84+
<div
85+
className="absolute top-full right-0 transform translate-x-1/2 mt-2 text-xs font-medium text-gray-700 whitespace-nowrap"
86+
>
87+
{totalLabel}
8488
</div>
8589
)}
8690
</div>

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/oracle-integrity-staking.mdx

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,27 @@ This document outlines the design principles and implementation details of the O
44

55
## Design Principles
66

7-
OIS's economic design focuses on awarding and penalizing Stakers over the primary dimension of data accuracy.
8-
Stakers receive rewards from an open-ended pool for helping to ensure data quality. They will also have their stake slashed as a penalty for failing to maintain data accuracy.
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.
910

1011
The core design principles behind OIS include the following:
1112

12-
- Integrity Staking secures all current and future price feeds produced by the Pyth Network.
13+
- Oracle Integrity Staking secures all current and future price feeds produced by the Pyth Network.
1314
- Data Publishers are individually responsible for data accuracy.
14-
- Rewards and penalties are proportionate to the stake assigned to each publisher. Delegators share in the risk-reward of the publisher(s) they assign their stake to.
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.
1516
- A higher number of publishers for each price feed contributes positively to the security of such feed.
16-
- Staking for OIS is complementary to Staking for Governance, and eligible $PYTH tokens can be used for both purposes.
17-
- The ability to slash stake in OIS requires **unlocked** \$PYTH tokens, whereas Staking for Governance can use both locked and unlocked $PYTH tokens.
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.
1819
- All parameter related to the OIS protocol are subject to the governance of the Pyth DAO.
1920

2021
## Implementation
2122

2223
OIS implements the design principles above through the following structure:
2324

24-
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.
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.
2526

26-
2. Each publisher is programmatically assigned a staking pool where they can self-stake and to which other stakers can delegate
27+
2. Each publisher is programmatically assigned a staking pool where they can self-stake and to which other stakers can delegate.
2728
- The staking pool assigned to each publisher covers all price feeds/symbols they publish.
2829
- Each staking pool has a soft cap. This soft cap dynamically expands and shrinks given the number of symbols published by the assigned publisher.
2930
- Price feeds with a low number of publishers contribute more to the cap's expansion.

pages/home/oracle-integrity-staking/examples.mdx

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import StakingCapBar from "@/components/StakingCapBar";
22

3+
34
# Examples
45

56
This reference page provides examples of various scenarios to illustrate the Mathematical Representations of OIS.
@@ -26,7 +27,9 @@ $$
2627
\end{aligned}
2728
$$
2829

29-
<StakingCapBar fillPercentage={100} labelText="100" secondFillPercentage={0} secondFillLabel="0" totalLabel="50"/>
30+
{/* <div className="flex justify-center">
31+
<StakingCapBar fillPercentage={20} labelText="100" secondFillPercentage={10} />
32+
</div> */}
3033

3134
## Example 2: Publisher and Delegator Stake
3235

@@ -112,3 +115,12 @@ $$
112115
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.
113116

114117
{/* <StakingCapBar fillPercentage={50} secondFillPercentage={20} labelText="100" /> */}
118+
119+
120+
## Interactive Reward Simulator
121+
122+
Use the simulator below to calculate publisher and delegator rewards based on your inputs.
123+
124+
import RewardSimulator from '@/components/RewardSimulator';
125+
126+
<RewardSimulator />

0 commit comments

Comments
 (0)