1+ "use client" ;
2+
3+ import { Card } from "@pythnetwork/component-library/Card" ;
4+ import { Label } from "@pythnetwork/component-library/unstyled/Label" ;
5+ import { Input } from "@pythnetwork/component-library/unstyled/TextField" ;
6+ import clsx from "clsx" ;
7+ import React , { useState , useEffect } from "react" ;
8+
9+ import styles from "./index.module.scss" ;
10+
11+ // Simple Math component for inline mathematical expressions
12+ const MathExpression : React . FC < { children : React . ReactNode } > = ( { children } ) => {
13+ return < span className = "katex" > { children } </ span > ;
14+ } ;
15+
16+ // Component for subscripts and superscripts
17+ const Sub : React . FC < { children : React . ReactNode } > = ( { children } ) => (
18+ < sub > { children } </ sub >
19+ ) ;
20+ const Sup : React . FC < { children : React . ReactNode } > = ( { children } ) => (
21+ < sup > { children } </ sup >
22+ ) ;
23+
24+ const RewardSimulator : React . FC = ( ) => {
25+ const [ publisherStake , setPublisherStake ] = useState ( 200 ) ;
26+ const [ delegatorStake , setDelegatorStake ] = useState ( 300 ) ;
27+ const [ maxCap , setMaxCap ] = useState ( 500 ) ;
28+ const [ delegatorFee , setDelegatorFee ] = useState ( 20 ) ;
29+ const [ rewardRate , setRewardRate ] = useState ( 10 ) ;
30+
31+ const [ publisherReward , setPublisherReward ] = useState ( 0 ) ;
32+ const [ delegatorReward , setDelegatorReward ] = useState ( 0 ) ;
33+ const [ publisherRewardRate , setPublisherRewardRate ] = useState ( 0 ) ;
34+ const [ delegatorRewardRate , setDelegatorRewardRate ] = useState ( 0 ) ;
35+
36+ useEffect ( ( ) => {
37+ const calculateRewards = ( ) => {
38+ const totalStake = publisherStake + delegatorStake ;
39+ const eligibleAmount = Math . min ( totalStake , maxCap ) ;
40+ const totalReward = ( rewardRate / 100 ) * eligibleAmount ;
41+
42+ const publisherRewardBase =
43+ ( rewardRate / 100 ) * Math . min ( publisherStake , maxCap ) ;
44+ const delegatorRewardBase = totalReward - publisherRewardBase ;
45+
46+ const delegatorFeeAmount = ( delegatorFee / 100 ) * delegatorRewardBase ;
47+
48+ const finalDelegatorReward = delegatorRewardBase - delegatorFeeAmount ;
49+ const finalPublisherReward = publisherRewardBase + delegatorFeeAmount ;
50+
51+ setPublisherReward ( Number ( finalPublisherReward . toFixed ( 2 ) ) ) ;
52+ setDelegatorReward ( Number ( finalDelegatorReward . toFixed ( 2 ) ) ) ;
53+ setPublisherRewardRate (
54+ Number ( ( ( finalPublisherReward * 100 ) / publisherStake ) . toFixed ( 2 ) ) ,
55+ ) ;
56+ setDelegatorRewardRate (
57+ Number ( ( ( finalDelegatorReward * 100 ) / delegatorStake ) . toFixed ( 2 ) ) ,
58+ ) ;
59+ } ;
60+
61+ calculateRewards ( ) ;
62+ } , [ publisherStake , delegatorStake , maxCap , delegatorFee , rewardRate ] ) ;
63+
64+ return (
65+ < Card
66+ variant = "secondary"
67+ title = "Reward Simulator"
68+ nonInteractive
69+ className = { clsx ( styles . card ) }
70+ >
71+ < div className = { clsx ( styles . inputGrid ) } >
72+ < div className = { clsx ( styles . inputGroup ) } >
73+ < Label htmlFor = "publisher-stake" >
74+ Publisher Stake (
75+ < MathExpression >
76+ S< Sub > p</ Sub > < Sup > p</ Sup >
77+ </ MathExpression >
78+ ):
79+ </ Label >
80+ < Input
81+ id = "publisher-stake"
82+ type = "number"
83+ value = { publisherStake }
84+ onChange = { ( e ) => {
85+ setPublisherStake ( Number ( e . target . value ) ) ;
86+ } }
87+ className = { clsx ( styles . input ) }
88+ min = "0"
89+ />
90+ </ div >
91+ < div className = { clsx ( styles . inputGroup ) } >
92+ < Label htmlFor = "delegator-stake" >
93+ Delegator Stake (
94+ < MathExpression >
95+ S< Sub > p</ Sub > < Sup > d</ Sup >
96+ </ MathExpression >
97+ ):
98+ </ Label >
99+ < Input
100+ id = "delegator-stake"
101+ type = "number"
102+ value = { delegatorStake }
103+ onChange = { ( e ) => {
104+ setDelegatorStake ( Number ( e . target . value ) ) ;
105+ } }
106+ className = { clsx ( styles . input ) }
107+ min = "0"
108+ />
109+ </ div >
110+ < div className = { clsx ( styles . inputGroup ) } >
111+ < Label htmlFor = "max-cap" >
112+ Maximum Cap (
113+ < MathExpression >
114+ C< Sub > p</ Sub >
115+ </ MathExpression >
116+ ):
117+ </ Label >
118+ < Input
119+ id = "max-cap"
120+ type = "number"
121+ value = { maxCap }
122+ onChange = { ( e ) => {
123+ setMaxCap ( Number ( e . target . value ) ) ;
124+ } }
125+ className = { clsx ( styles . input ) }
126+ min = "0"
127+ />
128+ </ div >
129+ < div className = { clsx ( styles . inputGroup ) } >
130+ < Label htmlFor = "delegator-fee" >
131+ Delegator Fee (< MathExpression > f</ MathExpression > ) (%):
132+ </ Label >
133+ < Input
134+ id = "delegator-fee"
135+ type = "number"
136+ value = { delegatorFee }
137+ onChange = { ( e ) => {
138+ setDelegatorFee ( Number ( e . target . value ) ) ;
139+ } }
140+ className = { clsx ( styles . input ) }
141+ min = "0"
142+ max = "100"
143+ step = "0.1"
144+ />
145+ </ div >
146+ < div className = { clsx ( styles . inputGroup ) } >
147+ < Label htmlFor = "reward-rate" >
148+ Reward Rate (< MathExpression > r</ MathExpression > ) (%):
149+ </ Label >
150+ < Input
151+ id = "reward-rate"
152+ type = "number"
153+ value = { rewardRate }
154+ onChange = { ( e ) => {
155+ setRewardRate ( Number ( e . target . value ) ) ;
156+ } }
157+ className = { clsx ( styles . input ) }
158+ min = "0"
159+ max = "100"
160+ step = "0.1"
161+ />
162+ </ div >
163+ </ div >
164+ < div className = { clsx ( styles . resultsSection ) } >
165+ < div className = { clsx ( styles . resultsGrid ) } >
166+ < div className = { clsx ( styles . resultGroup ) } >
167+ < h4 className = { clsx ( styles . resultTitle ) } > Calculated Rewards</ h4 >
168+ < div className = { clsx ( styles . resultValues ) } >
169+ < p className = { clsx ( styles . resultItem ) } >
170+ < span className = { clsx ( styles . resultLabel ) } >
171+ Publisher Reward (
172+ < MathExpression >
173+ R< Sup > p</ Sup > < Sub > p</ Sub >
174+ </ MathExpression >
175+ ):
176+ </ span > { " " }
177+ < span className = { clsx ( styles . resultValue ) } >
178+ { publisherReward }
179+ </ span >
180+ </ p >
181+ < p className = { clsx ( styles . resultItem ) } >
182+ < span className = { clsx ( styles . resultLabel ) } >
183+ Delegator Reward (
184+ < MathExpression >
185+ R< Sup > d</ Sup > < Sub > p</ Sub >
186+ </ MathExpression >
187+ ):
188+ </ span > { " " }
189+ < span className = { clsx ( styles . resultValue ) } >
190+ { delegatorReward }
191+ </ span >
192+ </ p >
193+ </ div >
194+ </ div >
195+ < div className = { clsx ( styles . resultGroup ) } >
196+ < h4 className = { clsx ( styles . resultTitle ) } >
197+ Calculated Reward Rates (Yearly)
198+ </ h4 >
199+ < div className = { clsx ( styles . resultValues ) } >
200+ < p className = { clsx ( styles . resultItem ) } >
201+ < span className = { clsx ( styles . resultLabel ) } >
202+ Publisher Rate (
203+ < MathExpression >
204+ r< Sup > p</ Sup > < Sub > p</ Sub >
205+ </ MathExpression >
206+ ):
207+ </ span > { " " }
208+ < span className = { clsx ( styles . resultValue ) } >
209+ { publisherRewardRate } %
210+ </ span >
211+ </ p >
212+ < p className = { clsx ( styles . resultItem ) } >
213+ < span className = { clsx ( styles . resultLabel ) } >
214+ Delegator Rate (
215+ < MathExpression >
216+ r< Sup > d</ Sup > < Sub > p</ Sub >
217+ </ MathExpression >
218+ ):
219+ </ span > { " " }
220+ < span className = { clsx ( styles . resultValue ) } >
221+ { delegatorRewardRate } %
222+ </ span >
223+ </ p >
224+ </ div >
225+ </ div >
226+ </ div >
227+ </ div >
228+ </ Card >
229+ ) ;
230+ } ;
231+
232+ export default RewardSimulator ;
0 commit comments