Skip to content
This repository was archived by the owner on Oct 11, 2024. It is now read-only.

Commit 411e434

Browse files
committed
further formatting and 12 day epoch avg apy
1 parent 8ebbe4e commit 411e434

File tree

2 files changed

+165
-155
lines changed

2 files changed

+165
-155
lines changed

ts/pages/staking/staking_pool.tsx

Lines changed: 157 additions & 147 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { InfoTooltip } from 'ts/components/ui/info_tooltip';
1414
import { useAPIClient } from 'ts/hooks/use_api_client';
1515

1616
import { State } from 'ts/redux/reducer';
17-
import { PoolEpochRewards, PoolWithHistoricalStats, WebsitePaths } from 'ts/types';
17+
import { EpochPoolStats, PoolEpochRewards, PoolWithHistoricalStats, WebsitePaths } from 'ts/types';
1818
import { errorReporter } from 'ts/utils/error_reporter';
1919
import { formatEther, formatPercent, formatZrx } from 'ts/utils/format_number';
2020
import { stakingUtils } from 'ts/utils/staking_utils';
@@ -61,34 +61,39 @@ export const StakingPool: React.FC<StakingPoolProps & RouteChildrenProps> = (pro
6161
const apiClient = useAPIClient(networkId);
6262
const [stakingPool, setStakingPool] = useState<PoolWithHistoricalStats | undefined>(undefined);
6363
const [epochRewards, setEpochRewards] = useState<PoolEpochRewards[] | undefined>(undefined);
64-
const [stakingPoolAPY, setStakingPoolAPY] = useState<number | undefined>(undefined);
64+
const [stakingPoolAPY3Epochs, setStakingPoolAPY3Epochs] = useState<number | undefined>(undefined);
65+
const [stakingPoolAPY12Epochs, setStakingPoolAPY12Epochs] = useState<number | undefined>(undefined);
6566

6667
useEffect(() => {
67-
const calcAverageEpochApy = (numEpochs: number, rewards: PoolEpochRewards[]) => {
68-
const rewardsToAverage =
69-
rewards.length > numEpochs ? rewards.slice(Math.max(rewards.length - numEpochs, 0)) : rewards;
68+
const calcShortTermAndLongTermAPY = (rewards: PoolEpochRewards[]) => {
69+
const average = (arr: number[]) => arr.reduce((sum, el) => sum + el, 0) / arr.length;
7070

71-
const historicalAPYs = rewardsToAverage.map((reward) => {
71+
const epochRewardAPYs = rewards.map((reward) => {
7272
return reward.apy;
7373
});
74-
const average = (arr: number[]) => arr.reduce((sum, el) => sum + el, 0) / arr.length;
75-
setStakingPoolAPY(average(historicalAPYs));
74+
const rewardsToAverageShortTerm =
75+
epochRewardAPYs.length > 3 ? epochRewardAPYs.slice(Math.max(rewards.length - 3, 0)) : epochRewardAPYs;
76+
77+
const rewardsToAverageLongTerm =
78+
epochRewardAPYs.length > 12 ? epochRewardAPYs.slice(Math.max(rewards.length - 12, 0)) : epochRewardAPYs;
79+
80+
setStakingPoolAPY3Epochs(average(rewardsToAverageShortTerm));
81+
setStakingPoolAPY12Epochs(average(rewardsToAverageLongTerm));
7682
};
7783
apiClient
7884
.getStakingPoolByIdAsync(poolId)
7985
.then((res) => {
8086
setStakingPool(res.stakingPool);
81-
apiClient
82-
.getStakingPoolRewardsAsync(poolId)
83-
.then((resRewards) => {
84-
// fix this, shouldnt be unnecessarily nested
85-
setEpochRewards(resRewards.stakingPoolRewards.epochRewards);
86-
calcAverageEpochApy(7, resRewards.stakingPoolRewards.epochRewards);
87-
})
88-
.catch((err: Error) => {
89-
logUtils.warn(err);
90-
errorReporter.report(err);
91-
});
87+
})
88+
.catch((err: Error) => {
89+
logUtils.warn(err);
90+
errorReporter.report(err);
91+
});
92+
apiClient
93+
.getStakingPoolRewardsAsync(poolId)
94+
.then((resRewards) => {
95+
setEpochRewards(resRewards.stakingPoolRewards.epochRewards);
96+
calcShortTermAndLongTermAPY(resRewards.stakingPoolRewards.epochRewards);
9297
})
9398
.catch((err: Error) => {
9499
logUtils.warn(err);
@@ -101,143 +106,148 @@ export const StakingPool: React.FC<StakingPoolProps & RouteChildrenProps> = (pro
101106
return <Redirect to={WebsitePaths.Staking} />;
102107
}
103108

104-
if (!stakingPool) {
105-
return null;
106-
}
107-
108-
const currentEpoch = stakingPool.currentEpochStats;
109-
const nextEpoch = stakingPool.nextEpochStats;
109+
let currentEpoch: EpochPoolStats,
110+
nextEpoch,
111+
historicalEpochs,
112+
zrxStakeChangeBetweenEpochs: number,
113+
zrxToStaked = null;
114+
if (stakingPool) {
115+
currentEpoch = stakingPool.currentEpochStats;
116+
nextEpoch = stakingPool.nextEpochStats;
110117

111-
// Reminder: stake change can be negative
112-
const zrxStakeChangeBetweenEpochs = new BigNumber(nextEpoch.zrxStaked || 0)
113-
.minus(new BigNumber(currentEpoch.zrxStaked || 0))
114-
.toNumber();
118+
// Reminder: stake change can be negative
119+
zrxStakeChangeBetweenEpochs = new BigNumber(nextEpoch.zrxStaked || 0)
120+
.minus(new BigNumber(currentEpoch.zrxStaked || 0))
121+
.toNumber();
115122

116-
// Only allow epochs that have finished into historical data
117-
const historicalEpochs = epochRewards
118-
? epochRewards
119-
.filter((x) => !!x.epochEndTimestamp)
120-
.sort((a, b) => {
121-
return a.epochId - b.epochId;
122-
})
123-
: null;
123+
// Only allow epochs that have finished into historical data
124+
historicalEpochs = epochRewards
125+
? epochRewards
126+
.filter((x) => !!x.epochEndTimestamp)
127+
.sort((a, b) => {
128+
return a.epochId - b.epochId;
129+
})
130+
: null;
124131

125-
const fullyStakedZrx = nextEpoch.zrxStaked / (nextEpoch.approximateStakeRatio || 1);
126-
const zrxToStaked = Math.max(fullyStakedZrx - nextEpoch.zrxStaked, 0);
132+
const fullyStakedZrx = nextEpoch.zrxStaked / (nextEpoch.approximateStakeRatio || 1);
133+
zrxToStaked = Math.max(fullyStakedZrx - nextEpoch.zrxStaked, 0);
134+
}
127135

128136
return (
129137
<StakingPageLayout isHome={true} title="Staking pool">
130-
<DashboardHero
131-
title={stakingUtils.getPoolDisplayName(stakingPool)}
132-
websiteUrl={stakingPool.metaData.websiteUrl}
133-
poolId={stakingPool.poolId}
134-
operatorAddress={stakingPool.operatorAddress}
135-
isVerified={stakingPool.metaData.isVerified}
136-
estimatedStake={nextEpoch.approximateStakeRatio * 100}
137-
zrxToStaked={zrxToStaked}
138-
rewardsShared={(1 - nextEpoch.operatorShare) * 100}
139-
iconUrl={stakingPool.metaData.logoUrl}
140-
networkId={networkId}
141-
tabs={[
142-
{
143-
title: 'Current Epoch',
144-
metrics: [
145-
// todo(johnrjj) Cutting volume for MVP
146-
// {
147-
// title: 'Total Volume',
148-
// number: '1.23M USD',
149-
// },
150-
{
151-
title: 'APY (last 7 epochs)',
152-
number: `${formatPercent(stakingPoolAPY * 100 || 0).minimized}%`,
153-
},
154-
{
155-
title: 'Fees Generated',
156-
// 4 decimals looks better here to keep it from wrapping
157-
number: `${
158-
formatEther(currentEpoch.totalProtocolFeesGeneratedInEth, {
159-
decimals: 4,
160-
decimalsRounded: 4,
161-
}).minimized
162-
} ETH`,
163-
},
164-
{
165-
title: 'ZRX Staked',
166-
number: `${formatZrx(nextEpoch.zrxStaked, { bigUnitPostfix: true }).formatted}`,
167-
headerComponent: () => (
168-
<InfoTooltip id="next-epoch-staked-balance">
169-
<div>
170-
<div>
171-
<TooltipLabel>Current Epoch:</TooltipLabel>{' '}
172-
{
173-
formatZrx(currentEpoch.zrxStaked, {
174-
decimals: 2,
175-
decimalsRounded: 2,
176-
roundDown: true,
177-
}).full
178-
}
179-
</div>
138+
{stakingPool && (
139+
<DashboardHero
140+
title={stakingUtils.getPoolDisplayName(stakingPool)}
141+
websiteUrl={stakingPool.metaData.websiteUrl}
142+
poolId={stakingPool.poolId}
143+
operatorAddress={stakingPool.operatorAddress}
144+
isVerified={stakingPool.metaData.isVerified}
145+
estimatedStake={nextEpoch.approximateStakeRatio * 100}
146+
zrxToStaked={zrxToStaked}
147+
rewardsShared={(1 - nextEpoch.operatorShare) * 100}
148+
iconUrl={stakingPool.metaData.logoUrl}
149+
networkId={networkId}
150+
tabs={[
151+
{
152+
title: 'Current Epoch',
153+
metrics: [
154+
// todo(johnrjj) Cutting volume for MVP
155+
// {
156+
// title: 'Total Volume',
157+
// number: '1.23M USD',
158+
// },
159+
{
160+
title: 'APY (last 3 epochs)',
161+
number: `${formatPercent(stakingPoolAPY3Epochs * 100 || 0).minimized}%`,
162+
},
163+
{
164+
title: 'Fees Generated',
165+
// 4 decimals looks better here to keep it from wrapping
166+
number: `${
167+
formatEther(currentEpoch.totalProtocolFeesGeneratedInEth, {
168+
decimals: 2,
169+
decimalsRounded: 2,
170+
}).minimized
171+
} ETH`,
172+
},
173+
{
174+
title: 'ZRX Staked',
175+
number: `${formatZrx(nextEpoch.zrxStaked, { bigUnitPostfix: true }).formatted}`,
176+
headerComponent: () => (
177+
<InfoTooltip id="next-epoch-staked-balance">
180178
<div>
181-
<TooltipLabel>Pending Epoch:</TooltipLabel>{' '}
182-
{
183-
formatZrx(zrxStakeChangeBetweenEpochs, {
184-
decimals: 2,
185-
decimalsRounded: 2,
186-
roundDown: true,
187-
positiveSign: zrxStakeChangeBetweenEpochs >= 0,
188-
}).full
189-
}
179+
<div>
180+
<TooltipLabel>Current Epoch:</TooltipLabel>{' '}
181+
{
182+
formatZrx(currentEpoch.zrxStaked, {
183+
decimals: 2,
184+
decimalsRounded: 2,
185+
roundDown: true,
186+
}).full
187+
}
188+
</div>
189+
<div>
190+
<TooltipLabel>Pending Epoch:</TooltipLabel>{' '}
191+
{
192+
formatZrx(zrxStakeChangeBetweenEpochs, {
193+
decimals: 2,
194+
decimalsRounded: 2,
195+
roundDown: true,
196+
positiveSign: zrxStakeChangeBetweenEpochs >= 0,
197+
}).full
198+
}
199+
</div>
190200
</div>
191-
</div>
192-
</InfoTooltip>
193-
),
194-
},
201+
</InfoTooltip>
202+
),
203+
},
195204

196-
{
197-
title: 'Rewards Shared',
198-
// No good way to show rewards shared of an epoch in progress (currentEpoch) right now.
199-
// Defaulting to dash ('-') for now
200-
number: `${
201-
formatEther('0', {
202-
zeroStyled: true,
203-
}).formatted
204-
} ETH`,
205-
},
206-
],
207-
},
208-
{
209-
title: 'All Time',
210-
metrics: [
211-
{
212-
title: 'ZRX Staked',
213-
number: `${formatZrx(currentEpoch.zrxStaked).minimized}`,
214-
},
215-
{
216-
title: 'Fees Generated',
217-
number: `${
218-
formatEther(stakingPool.allTimeStats.protocolFeesGeneratedInEth, {
219-
decimalsRounded: 4,
220-
decimals: 4,
221-
}).formatted
222-
} ETH`,
223-
},
224-
{
225-
title: 'Rewards Shared',
226-
number: `${
227-
formatEther(stakingPool.allTimeStats.membersRewardsPaidInEth, {
228-
decimals: 4,
229-
decimalsRounded: 4,
230-
}).formatted
231-
} ETH`,
232-
},
233-
{
234-
title: 'Number of trades',
235-
number: stakingPool.allTimeStats.numberOfFills,
236-
},
237-
],
238-
},
239-
]}
240-
/>
205+
{
206+
title: 'Rewards Shared',
207+
// No good way to show rewards shared of an epoch in progress (currentEpoch) right now.
208+
// Defaulting to dash ('-') for now
209+
number: `${
210+
formatEther('0', {
211+
zeroStyled: true,
212+
}).formatted
213+
} ETH`,
214+
},
215+
],
216+
},
217+
{
218+
title: 'All Time',
219+
metrics: [
220+
{
221+
title: 'APY (last 12 epochs)',
222+
number: `${formatPercent(stakingPoolAPY12Epochs * 100 || 0).minimized}%`,
223+
},
224+
{
225+
title: 'Fees Generated',
226+
number: `${
227+
formatEther(stakingPool.allTimeStats.protocolFeesGeneratedInEth, {
228+
decimalsRounded: 2,
229+
decimals: 2,
230+
}).formatted
231+
} ETH`,
232+
},
233+
{
234+
title: 'ZRX Staked',
235+
number: `${formatZrx(nextEpoch.zrxStaked, { bigUnitPostfix: true }).formatted}`,
236+
},
237+
{
238+
title: 'Rewards Shared',
239+
number: `${
240+
formatEther(stakingPool.allTimeStats.membersRewardsPaidInEth, {
241+
decimals: 2,
242+
decimalsRounded: 2,
243+
}).formatted
244+
} ETH`,
245+
},
246+
],
247+
},
248+
]}
249+
/>
250+
)}
241251
{/* TODO(johnrjj) Copy from account page when finished */}
242252
{/* <ActionsWrapper>
243253
<ActionsInner>

ts/utils/utils.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -405,14 +405,14 @@ export const utils = {
405405
return configs.BACKEND_BASE_PROD_URL;
406406
},
407407
getAPIBaseUrl(networkId: Network): string {
408-
// if (environments.isDevelopment()) {
409-
// return configs.API_BASE_DEV_URL;
410-
// } else if (networkId === Network.Kovan) {
411-
// return configs.API_BASE_KOVAN_URL;
412-
// } else if (environments.isDogfood()) {
413-
// return configs.API_BASE_STAGING_URL;
414-
// }
415-
return configs.API_BASE_STAGING_URL;
408+
if (environments.isDevelopment()) {
409+
return configs.API_BASE_DEV_URL;
410+
} else if (networkId === Network.Kovan) {
411+
return configs.API_BASE_KOVAN_URL;
412+
} else if (environments.isDogfood()) {
413+
return configs.API_BASE_STAGING_URL;
414+
}
415+
return configs.API_BASE_PROD_URL;
416416
},
417417
isExternallyInjected(providerType: ProviderType, injectedProviderName: string): boolean {
418418
return providerType === ProviderType.Injected && injectedProviderName !== constants.PROVIDER_NAME_PUBLIC;

0 commit comments

Comments
 (0)