Skip to content

Commit 588c442

Browse files
authored
Add median price to scan UI (#2614)
* Add median price to scan UI [ci] Fixes #504 Signed-off-by: fayi-da <[email protected]> * Separate components as requested [ci] Signed-off-by: fayi-da <[email protected]> --------- Signed-off-by: fayi-da <[email protected]>
1 parent 481b2a7 commit 588c442

File tree

6 files changed

+116
-41
lines changed

6 files changed

+116
-41
lines changed

apps/common/frontend/src/components/index.ts

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -39,48 +39,48 @@ import {
3939

4040
export {
4141
ActionView,
42-
AmountDisplay,
43-
Alerting,
4442
AlertState,
45-
AuthProvider,
43+
Alerting,
44+
AmountDisplay,
4645
AnsEntry,
4746
AnsEntryDisplay,
4847
AnsEntryProps,
4948
AnsField,
50-
BaseAnsField,
5149
AnsFieldProps,
52-
UserInput,
50+
AuthProvider,
51+
BaseAnsField,
52+
BaseVotesHooks,
5353
ConfirmationDialog,
5454
CopyableTypography,
5555
Copyright,
5656
DateDisplay,
57+
DateWithDurationDisplay,
5758
DisableConditionally,
59+
DsoInfo,
60+
DsoViewPrettyJSON,
5861
ErrorBoundary,
5962
ErrorDisplay,
6063
ErrorRouterPage,
6164
Header,
6265
IntervalDisplay,
66+
ListVoteRequests,
6367
Loading,
6468
Login,
6569
LoginFailed,
6670
PartyId,
6771
PrettyJsonDiff,
6872
RateDisplay,
73+
SubscriptionButton,
6974
TitledTable,
7075
TransferButton,
71-
SubscriptionButton,
72-
DateWithDurationDisplay,
73-
DsoViewPrettyJSON,
74-
DsoInfo,
75-
VotesHooksContext,
76-
BaseVotesHooks,
77-
VotesHooks,
78-
useVotesHooks,
79-
ListVoteRequests,
80-
ViewMoreButton,
76+
UpdateId,
77+
UserInput,
8178
ValidatorLicenses,
8279
ValidatorLicensesPage,
80+
ViewMoreButton,
81+
VotesHooks,
82+
VotesHooksContext,
8383
computeDiff,
84-
UpdateId,
8584
updateIdFromEventId,
85+
useVotesHooks,
8686
};
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,21 @@
11
// Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
22
// SPDX-License-Identifier: Apache-2.0
3+
4+
import BigNumber from 'bignumber.js';
5+
36
export * from './auth';
47
export * from './amuletRules';
58
export * from './helpers';
69
export * from './voteRequests';
10+
11+
export const medianPriceVotes = (votedPrices: BigNumber[]): BigNumber | undefined => {
12+
if (votedPrices && votedPrices.length > 0) {
13+
const sorted = [...votedPrices].sort((a, b) => {
14+
return a.isEqualTo(b) ? 0 : a.isLessThan(b) ? -1 : 1;
15+
});
16+
const length = sorted.length;
17+
const half = Math.floor(length / 2);
18+
return length % 2 !== 0 ? sorted[half] : sorted[half - 1].plus(sorted[half]).multipliedBy(0.5);
19+
}
20+
return undefined;
21+
};
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import {
5+
AmountDisplay,
6+
Loading,
7+
medianPriceVotes,
8+
useVotesHooks,
9+
} from '@lfdecentralizedtrust/splice-common-frontend';
10+
import BigNumber from 'bignumber.js';
11+
import React, { useMemo } from 'react';
12+
13+
import { Stack } from '@mui/material';
14+
import Typography from '@mui/material/Typography';
15+
16+
interface MedianAmuletPriceProps {
17+
amuletName: string;
18+
}
19+
20+
export const MedianAmuletPrice: React.FC<MedianAmuletPriceProps> = props => {
21+
const { amuletName } = props;
22+
23+
const voteHooks = useVotesHooks();
24+
const amuletPriceVotesQuery = voteHooks.useAmuletPriceVotes();
25+
26+
const amuletPrices = useMemo(
27+
() =>
28+
amuletPriceVotesQuery.data
29+
?.map(v => (v.amuletPrice ? new BigNumber(v.amuletPrice) : undefined))
30+
.filter((p): p is BigNumber => !!p),
31+
[amuletPriceVotesQuery.data]
32+
);
33+
34+
const medianAmuletPrice = useMemo(
35+
() => (amuletPrices ? medianPriceVotes(amuletPrices) : undefined),
36+
[amuletPrices]
37+
);
38+
39+
if (amuletPriceVotesQuery.isLoading) {
40+
return <Loading />;
41+
}
42+
43+
if (amuletPriceVotesQuery.isError) {
44+
return <p>Error, something went wrong.</p>;
45+
}
46+
47+
return (
48+
<Stack mt={4} spacing={2} direction="column" justifyContent="center">
49+
<Typography mt={4} variant="h4">
50+
{amuletName} Price for Next Open Mining Round
51+
</Typography>
52+
<Typography id="median-amulet-price-usd" variant="h2">
53+
{medianAmuletPrice && <AmountDisplay amount={medianAmuletPrice} currency="USDUnit" />}
54+
</Typography>
55+
<Typography variant="caption">
56+
Median of {amuletName} prices voted by all Super Validators
57+
</Typography>
58+
</Stack>
59+
);
60+
};

apps/scan/frontend/src/routes/amuletPriceVotes.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,17 @@ import { Box, Container } from '@mui/material';
44

55
import Layout from '../components/Layout';
66
import ListAmuletPriceVotes from '../components/votes/ListAmuletPriceVotes';
7+
import { MedianAmuletPrice } from '../components/MedianAmuletPrice';
8+
import { useScanConfig } from '../utils';
79

810
const AmuletPriceVotes: React.FC = () => {
11+
const config = useScanConfig();
12+
913
return (
1014
<Layout>
1115
<Box bgcolor="colors.neutral.15" sx={{ flex: 1 }}>
1216
<Container maxWidth="lg" sx={{ marginTop: 2 }}>
17+
<MedianAmuletPrice amuletName={config.spliceInstanceNames.amuletName} />
1318
<ListAmuletPriceVotes />
1419
</Container>
1520
</Box>
Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,27 @@
11
// Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
22
// SPDX-License-Identifier: Apache-2.0
3-
import { AmountDisplay, Loading } from '@lfdecentralizedtrust/splice-common-frontend';
3+
4+
import {
5+
AmountDisplay,
6+
Loading,
7+
medianPriceVotes,
8+
useVotesHooks,
9+
} from '@lfdecentralizedtrust/splice-common-frontend';
410
import BigNumber from 'bignumber.js';
511
import React, { useMemo } from 'react';
612

713
import { Stack } from '@mui/material';
814
import Typography from '@mui/material/Typography';
915

10-
import { useAmuletPriceVotes } from '../../hooks/useAmuletPriceVotes';
11-
import { useSvConfig } from '../../utils';
16+
interface MedianAmuletPriceProps {
17+
amuletName: string;
18+
}
1219

13-
const MedianAmuletPrice: React.FC = () => {
14-
const config = useSvConfig();
15-
const amuletPriceVotesQuery = useAmuletPriceVotes();
16-
const amuletName = config.spliceInstanceNames.amuletName;
20+
export const MedianAmuletPrice: React.FC<MedianAmuletPriceProps> = props => {
21+
const { amuletName } = props;
1722

18-
const median = (votedPrices: BigNumber[]) => {
19-
if (votedPrices && votedPrices.length > 0) {
20-
const sorted = [...votedPrices].sort((a, b) => {
21-
return a.isEqualTo(b) ? 0 : a.isLessThan(b) ? -1 : 1;
22-
});
23-
const length = sorted.length;
24-
const half = Math.floor(length / 2);
25-
return length % 2 !== 0
26-
? sorted[half]
27-
: sorted[half - 1].plus(sorted[half]).multipliedBy(0.5);
28-
}
29-
return undefined;
30-
};
23+
const voteHooks = useVotesHooks();
24+
const amuletPriceVotesQuery = voteHooks.useAmuletPriceVotes();
3125

3226
const amuletPrices = useMemo(
3327
() =>
@@ -38,7 +32,7 @@ const MedianAmuletPrice: React.FC = () => {
3832
);
3933

4034
const medianAmuletPrice = useMemo(
41-
() => (amuletPrices ? median(amuletPrices) : undefined),
35+
() => (amuletPrices ? medianPriceVotes(amuletPrices) : undefined),
4236
[amuletPrices]
4337
);
4438

@@ -64,5 +58,3 @@ const MedianAmuletPrice: React.FC = () => {
6458
</Stack>
6559
);
6660
};
67-
68-
export default MedianAmuletPrice;

apps/sv/frontend/src/routes/amuletPrice.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,16 @@ import * as React from 'react';
55
import { Box } from '@mui/material';
66

77
import DesiredAmuletPrice from '../components/amuletprice/DesiredAmuletPrice';
8-
import MedianAmuletPrice from '../components/amuletprice/MedianAmuletPrice';
98
import OpenMiningRounds from '../components/amuletprice/OpenMiningRounds';
9+
import { MedianAmuletPrice } from '../components/amuletprice/MedianAmuletPrice';
10+
import { useSvConfig } from '../utils';
1011

1112
const AmuletPrice: React.FC = () => {
13+
const config = useSvConfig();
14+
1215
return (
1316
<Box>
14-
<MedianAmuletPrice />
17+
<MedianAmuletPrice amuletName={config.spliceInstanceNames.amuletName} />
1518
<DesiredAmuletPrice canEditVote />
1619
<OpenMiningRounds />
1720
</Box>

0 commit comments

Comments
 (0)