change dashboard table
Signed-off-by: Uncle Fatso <uncle.fatso@ghostchain.io>
This commit is contained in:
parent
be5b102522
commit
e102d819a0
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "ghost-dao-interface",
|
||||
"private": true,
|
||||
"version": "0.7.13",
|
||||
"version": "0.7.14",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
1
src/abi/GhostGatekeeper.json
Normal file
1
src/abi/GhostGatekeeper.json
Normal file
File diff suppressed because one or more lines are too long
@ -12,6 +12,7 @@ import {
|
||||
CurrentIndex,
|
||||
} from "./components/Metric";
|
||||
import TokenInfo from "./components/TokenInfo";
|
||||
import ProtocolDetails from "./components/ProtocolDetails";
|
||||
|
||||
import Paper from "../../components/Paper/Paper";
|
||||
import PageTitle from "../../components/PageTitle/PageTitle";
|
||||
@ -60,7 +61,7 @@ const MetricsDashboard = ({ chainId }) => {
|
||||
</Paper>
|
||||
|
||||
<Paper style={{ padding: "0px" }} fullWidth={true} >
|
||||
<TokenInfo isMobileScreen={isMobileScreen} chainId={chainId} />
|
||||
<ProtocolDetails theme={theme} isMobileScreen={isMobileScreen} chainId={chainId} />
|
||||
</Paper>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
137
src/containers/TreasuryDashboard/components/ProtocolDetails.jsx
Normal file
137
src/containers/TreasuryDashboard/components/ProtocolDetails.jsx
Normal file
@ -0,0 +1,137 @@
|
||||
import { useMemo } from "react";
|
||||
import { Grid, Box, Typography } from "@mui/material";
|
||||
import { useConfig } from "wagmi";
|
||||
import { useNavigate, createSearchParams } from "react-router-dom";
|
||||
|
||||
import { formatNumber } from "../../../helpers";
|
||||
import { useEpoch, useGatekeeperApy } from "../../../hooks/staking";
|
||||
import { useTokenSymbol, useBalance, useCirculatingSupply } from "../../../hooks/tokens";
|
||||
import { SecondaryButton } from "../../../components/Button";
|
||||
import { DecimalBigNumber } from "../../../helpers/DecimalBigNumber";
|
||||
|
||||
import { GATEKEEPER_ADDRESSES, EMPTY_ADDRESS } from "../../../constants/addresses";
|
||||
|
||||
const ProtocolDetail = ({ isMobileScreen, theme, name, sideName, url, urlParams, description }) => {
|
||||
const navigate = useNavigate();
|
||||
return (
|
||||
<Box position="relative" width={`${isMobileScreen ? "100%" : "48%"}`}>
|
||||
<Box
|
||||
borderRadius="9px"
|
||||
padding="12px"
|
||||
sx={{ backgroundColor: theme.colors.paper.card }}
|
||||
display="flex"
|
||||
flexDirection="column"
|
||||
justifyContent="space-between"
|
||||
>
|
||||
<Box display="flex" gap={"3px"} alignItems="center" justifyContent="space-between">
|
||||
<Typography fontSize="20px" fontWeight="bold" lineHeight="33px">
|
||||
{name}
|
||||
</Typography>
|
||||
<Typography color={theme.colors.primary[300]} fontSize="20px" fontWeight="bold" lineHeight="33px">
|
||||
{sideName}
|
||||
</Typography>
|
||||
</Box>
|
||||
<>
|
||||
<Box my="18px">
|
||||
<Typography color={theme.colors.gray[40]} mt="9px">
|
||||
{description}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<Box display="flex" justifyContent="center" width="100%">
|
||||
<SecondaryButton
|
||||
onClick={() => urlParams
|
||||
? navigate({
|
||||
pathname: url,
|
||||
search: urlParams.toString()
|
||||
})
|
||||
: navigate(url, { replace: true })
|
||||
}
|
||||
fullWidth
|
||||
>
|
||||
{name}
|
||||
</SecondaryButton>
|
||||
</Box>
|
||||
</>
|
||||
</Box>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
const ProtocolDetails = ({ chainId, isMobileScreen, theme, }) => {
|
||||
const config = useConfig();
|
||||
const nativeSymbol = config?.getClient()?.chain?.nativeCurrency?.symbol;
|
||||
const networkName = config?.getClient()?.chain?.name;
|
||||
|
||||
const { symbol: ftsoSymbol } = useTokenSymbol(chainId, "FTSO");
|
||||
const { symbol: csprSymbol } = useTokenSymbol(chainId, "CSPR");
|
||||
const { contractAddress: ftsoAddress } = useBalance(chainId, "FTSO", EMPTY_ADDRESS);
|
||||
|
||||
const circulatingSupply = useCirculatingSupply(chainId, "STNK");
|
||||
const gatekeepedApy = useGatekeeperApy(chainId);
|
||||
const { epoch } = useEpoch(chainId);
|
||||
|
||||
const apyInner = useMemo(() => {
|
||||
let apy = Infinity;
|
||||
if (circulatingSupply._value > 0n) {
|
||||
const value = epoch.distribute.div(circulatingSupply);
|
||||
apy = 100 * (Math.pow(1 + parseFloat(value.toString()), 1095) - 1);
|
||||
if (apy === 0) apy = Infinity;
|
||||
}
|
||||
return apy;
|
||||
}, [circulatingSupply, epoch]);
|
||||
|
||||
const bridgeNumbers = useMemo(() => {
|
||||
const connectedNetworks = Object.keys(GATEKEEPER_ADDRESSES).length;
|
||||
const number = 1 + connectedNetworks * 3;
|
||||
return `(${number}, ${number})`;
|
||||
}, [chainId]);
|
||||
|
||||
return (
|
||||
<Grid container spacing={0} justifyContent={"center"}>
|
||||
<Box display="flex" flexWrap="wrap" justifyContent="space-between" mt="10px" gap="25px">
|
||||
<ProtocolDetail
|
||||
isMobileScreen={isMobileScreen}
|
||||
theme={theme}
|
||||
url={`/${networkName.toLowerCase()}/dex/uniswap`}
|
||||
urlParams={createSearchParams({
|
||||
from: EMPTY_ADDRESS,
|
||||
to: `${ftsoAddress}`,
|
||||
})}
|
||||
name="(3, 3) Swap"
|
||||
sideName="Unlock Magic"
|
||||
description={`Buying strategy expands bond capacity triggering a positive loop to strengthen the Treasury and attract more stakers. Swap ${nativeSymbol} for ${ftsoSymbol} to unlock (3, 3) Stake.`}
|
||||
/>
|
||||
|
||||
<ProtocolDetail
|
||||
isMobileScreen={isMobileScreen}
|
||||
theme={theme}
|
||||
url={`/${networkName.toLowerCase()}/bonds`}
|
||||
name="(1, 1) Bond"
|
||||
sideName="Up to 40% Discount"
|
||||
description={`Bonding strategy grows Treasury and builds Protocol Owned Liquidity (POL) by allowing usersto acquire ${csprSymbol} at a discount. Take advantage of the next available bond.`}
|
||||
/>
|
||||
|
||||
<ProtocolDetail
|
||||
isMobileScreen={isMobileScreen}
|
||||
theme={theme}
|
||||
url={`/${networkName.toLowerCase()}/stake`}
|
||||
name="(3, 3) Stake"
|
||||
sideName={`${formatNumber(apyInner, 0)}% APY`}
|
||||
description={`Staking enables (3, 3) coordination by aligning long-term incentives, sustainably backed (1, 1) Bonds, LP fees, and Farming. Stake ${ftsoSymbol} to earn rewards and unlock ${bridgeNumbers} Stake\u00B2.`}
|
||||
/>
|
||||
|
||||
<ProtocolDetail
|
||||
isMobileScreen={isMobileScreen}
|
||||
theme={theme}
|
||||
url={`/${networkName.toLowerCase()}/bridge`}
|
||||
name={`${bridgeNumbers} Stake\u00B2`}
|
||||
sideName={`${formatNumber(apyInner * gatekeepedApy, 0)}% APY`}
|
||||
description={`Staking\u00B2 strategy further deepens long-term incentives powered by sustainable cross-chain bridging revenue. ${bridgeNumbers} Stake\u00B2 your ${csprSymbol} to receive organic APY with no warmup and dillution.`}
|
||||
/>
|
||||
</Box>
|
||||
</Grid>
|
||||
)
|
||||
}
|
||||
|
||||
export default ProtocolDetails;
|
||||
@ -5,12 +5,52 @@ import toast from "react-hot-toast";
|
||||
import { config } from "../../config";
|
||||
|
||||
import { isNetworkLegacyType } from "../../constants";
|
||||
import { STAKING_ADDRESSES } from "../../constants/addresses";
|
||||
import { STAKING_ADDRESSES, GATEKEEPER_ADDRESSES } from "../../constants/addresses";
|
||||
import { abi as StakingAbi } from "../../abi/GhostStaking.json";
|
||||
import { abi as GatekeeperAbi } from "../../abi/GhostGatekeeper.json";
|
||||
|
||||
import { shorten } from "../../helpers";
|
||||
import { DecimalBigNumber } from "../../helpers/DecimalBigNumber";
|
||||
|
||||
export const useGatekeeperApy = (chainId) => {
|
||||
const { data: gatekeeper, refetch } = useReadContract({
|
||||
abi: StakingAbi,
|
||||
address: STAKING_ADDRESSES[chainId],
|
||||
functionName: "gatekeeper",
|
||||
scopeKey: `gatekeeper-${chainId}`,
|
||||
chainId: chainId,
|
||||
});
|
||||
|
||||
const { data: metadata, error } = useReadContract({
|
||||
abi: GatekeeperAbi,
|
||||
address: GATEKEEPER_ADDRESSES[chainId],
|
||||
functionName: "gatekeeperMetadata",
|
||||
scopeKey: `gatekeeperMetadata-${chainId}`,
|
||||
chainId: chainId,
|
||||
});
|
||||
|
||||
const amountIn = new DecimalBigNumber(metadata?.amountIn ?? 0n, 18);
|
||||
const amountOut = new DecimalBigNumber(metadata?.amountOut ?? 0n, 18);
|
||||
|
||||
const deployedAt = metadata?.deployedAt ?? 0;
|
||||
const unixSeconds = Math.floor(Date.now() / 1000);
|
||||
const power = 365 * 86400 / (unixSeconds - deployedAt);
|
||||
|
||||
const feeIn = new DecimalBigNumber(6900n, 2);
|
||||
const feeOut = new DecimalBigNumber(6900n, 2);
|
||||
const stakeRatio = new DecimalBigNumber(69000n, 3);
|
||||
|
||||
const numerator = amountIn.mul(feeIn).add(amountOut.mul(feeOut));
|
||||
const denominator = amountIn.mul(stakeRatio).sub(amountOut.mul(stakeRatio));
|
||||
|
||||
if (denominator?.toString() === "0") {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const result = Number(numerator.div(denominator).toString());
|
||||
return Math.pow(1 + result, power);
|
||||
}
|
||||
|
||||
export const useCurrentIndex = (chainId) => {
|
||||
const { data: index, refetch } = useReadContract({
|
||||
abi: StakingAbi,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user