Compare commits
No commits in common. "5bb5b7d7e061d5da6e04ec8fa103409d09a63f74" and "4c455bd1f5cc65d475262082e7fa8c0e9c9f866a" have entirely different histories.
5bb5b7d7e0
...
4c455bd1f5
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "ghost-dao-interface",
|
||||
"private": true,
|
||||
"version": "0.7.15",
|
||||
"version": "0.7.7",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@ -121,7 +121,7 @@ function App() {
|
||||
const provider = usePublicClient();
|
||||
const chainId = useChainId();
|
||||
|
||||
const isSmallerScreen = useMediaQuery("(max-width: 1130px)");
|
||||
const isSmallerScreen = useMediaQuery("(max-width: 1047px)");
|
||||
const isSmallScreen = useMediaQuery("(max-width: 600px)");
|
||||
|
||||
const {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="uuid-61b3c585-44d6-4fd8-a0e7-6a5e76478eb1" data-name="uuid-70ba15fb-c44e-4945-a02a-8d07f94a9abb" xmlns="http://www.w3.org/2000/svg" viewBox="-4 -4 513 513">
|
||||
<svg id="uuid-61b3c585-44d6-4fd8-a0e7-6a5e76478eb1" data-name="uuid-70ba15fb-c44e-4945-a02a-8d07f94a9abb" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 505 505">
|
||||
<defs>
|
||||
<style>
|
||||
.uuid-6437a6f0-42e0-4c9c-b0ef-b632253e989a {
|
||||
|
||||
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="uuid-39ebc51d-db02-45d2-ad4b-e7ae31bb915b" data-name="Ethereum" xmlns="http://www.w3.org/2000/svg" viewBox="-2 -2 254 254">
|
||||
<svg id="uuid-39ebc51d-db02-45d2-ad4b-e7ae31bb915b" data-name="Ethereum" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 250 250">
|
||||
<defs>
|
||||
<style>
|
||||
.uuid-e080659c-91a4-4965-9905-603394020b2c {
|
||||
|
||||
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="uuid-cf283373-2eb4-44d0-88d2-93533a7f4b1d" data-name="eGHST" xmlns="http://www.w3.org/2000/svg" viewBox="-2 -2 254 254">
|
||||
<svg id="uuid-cf283373-2eb4-44d0-88d2-93533a7f4b1d" data-name="eGHST" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 250 250">
|
||||
<defs>
|
||||
<style>
|
||||
.uuid-26b0e53c-73c9-4369-9725-1cee728298be {
|
||||
|
||||
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
@ -1,4 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-2 -2 258.751 258.751">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 254.751 254.751">
|
||||
<defs>
|
||||
<style>
|
||||
.uuid-67f42f03-098b-49dc-a7ed-dc13bd713387 {
|
||||
|
||||
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="uuid-0fc887e6-719b-4e51-bef8-e5c269508f6b" data-name="sGHST" xmlns="http://www.w3.org/2000/svg" viewBox="-2 -2 254 254">
|
||||
<svg id="uuid-0fc887e6-719b-4e51-bef8-e5c269508f6b" data-name="sGHST" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 250 250">
|
||||
<defs>
|
||||
<style>
|
||||
.uuid-a205ebe2-7c8f-434c-9bde-29ac218716be {
|
||||
|
||||
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
@ -130,7 +130,7 @@ const NavItem = ({
|
||||
};
|
||||
|
||||
const LinkItem = () => (
|
||||
<Link {...linkProps} {...props} underline="hover" onClick={(e) => e.stopPropagation()}>
|
||||
<Link {...linkProps} {...props} underline="hover">
|
||||
<Box
|
||||
sx={{ fontFamily: "Ubuntu" }}
|
||||
display="flex"
|
||||
|
||||
@ -2,7 +2,7 @@ import { Box, Typography, useMediaQuery, useTheme } from "@mui/material";
|
||||
|
||||
const PageTitle = ({ name, subtitle, noMargin }) => {
|
||||
const theme = useTheme();
|
||||
const mobile = useMediaQuery(theme.breakpoints.down("900"));
|
||||
const mobile = useMediaQuery(theme.breakpoints.down("700"));
|
||||
|
||||
return (
|
||||
<Box
|
||||
|
||||
@ -1,58 +0,0 @@
|
||||
import { Box, Typography, SvgIcon, useTheme } from "@mui/material";
|
||||
|
||||
import { parseKnownToken } from "../../components/Token/Token";
|
||||
import { useUnstableProvider } from "../../hooks/ghost";
|
||||
import { PrimaryButton } from "../Button"
|
||||
|
||||
const GHOST_CONNECT = 'https://git.ghostchain.io/ghostchain/ghost-extension-wallet/releases';
|
||||
|
||||
function GhostChainSelect({ small }) {
|
||||
const { providerDetail, isConnected } = useUnstableProvider();
|
||||
const theme = useTheme();
|
||||
|
||||
if (providerDetail) {
|
||||
return (
|
||||
<Box
|
||||
height="39px"
|
||||
width={small ? "100px" : "155px"}
|
||||
borderRadius="4px"
|
||||
padding="0 14px"
|
||||
border="1px solid #50759e"
|
||||
>
|
||||
<Box
|
||||
display="flex"
|
||||
flexDirection="row"
|
||||
alignItems="center"
|
||||
justifyContent="space-between"
|
||||
width="100%"
|
||||
height="100%"
|
||||
>
|
||||
<Box display="flex" flexDirection="row">
|
||||
<SvgIcon component={parseKnownToken("CSPR")} inheritViewBox />
|
||||
{!small && <Typography sx={{ paddingLeft: "6px"}}>CASPER</Typography>}
|
||||
</Box>
|
||||
<Box
|
||||
width="21px"
|
||||
height="21px"
|
||||
backgroundColor={isConnected ? theme.colors.feedback.success : theme.colors.feedback.error}
|
||||
borderRadius="50%"
|
||||
></Box>
|
||||
</Box>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Box height="39px" width={small ? "100px" : "155px"}>
|
||||
<PrimaryButton
|
||||
sx={{ margin: "0 !important", padding: "0 !important" }}
|
||||
onClick={() => window.open(GHOST_CONNECT, '_blank', 'noopener,noreferrer')}
|
||||
fullWidth
|
||||
>
|
||||
Get GHOST {small ? "" : "Connect"}
|
||||
</PrimaryButton>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
export default GhostChainSelect;
|
||||
@ -71,7 +71,7 @@ function SelectNetwork({ chainId, wrongNetworkToastId, setWrongNetworkToastId, s
|
||||
}
|
||||
|
||||
return(
|
||||
<FormControl sx={{ width: small ? "auto" : "155px" }}>
|
||||
<FormControl sx={{ width: small ? "100px" : "155px" }}>
|
||||
<Select
|
||||
labelId="network-select-helper-label"
|
||||
id="network-select-helper"
|
||||
@ -92,7 +92,7 @@ function SelectNetwork({ chainId, wrongNetworkToastId, setWrongNetworkToastId, s
|
||||
return (
|
||||
<MenuItem key={chain.name} value={chain.id}>
|
||||
<Box gap="10px" display="flex" flexDirection="row" alignItems="center">
|
||||
<SvgIcon sx={{ width: 22 }} component={parseKnownToken(chain?.nativeCurrency?.symbol)} inheritViewBox />
|
||||
<SvgIcon component={parseKnownToken(chain?.nativeCurrency?.symbol)} inheritViewBox />
|
||||
{!small && <Typography>{chain.name}</Typography>}
|
||||
</Box>
|
||||
</MenuItem>
|
||||
|
||||
@ -2,7 +2,7 @@ import { Box, Button, SvgIcon, useMediaQuery, useTheme } from "@mui/material";
|
||||
import MenuIcon from "../../assets/icons/hamburger.svg?react";
|
||||
import Wallet from "./Wallet"
|
||||
import SelectNetwork from "./SelectNetwork";
|
||||
import GhostChainSelect from "./GhostChainSelect";
|
||||
|
||||
|
||||
const PREFIX = "TopBar";
|
||||
|
||||
@ -23,8 +23,8 @@ function TopBar({
|
||||
setWrongNetworkToastId
|
||||
}) {
|
||||
const themeColor = useTheme();
|
||||
const desktop = useMediaQuery(themeColor.breakpoints.up(1130));
|
||||
const small = useMediaQuery(themeColor.breakpoints.down(600));
|
||||
const desktop = useMediaQuery(themeColor.breakpoints.up(1048));
|
||||
const small = useMediaQuery(themeColor.breakpoints.down(400));
|
||||
return (
|
||||
<Box
|
||||
display="flex"
|
||||
@ -34,14 +34,7 @@ function TopBar({
|
||||
marginRight={desktop ? "33px" : "0px"}
|
||||
>
|
||||
<Box display="flex" alignItems="center">
|
||||
<Box
|
||||
display="flex"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
width={small ? "calc(100vw - 78px)" : "500px"}
|
||||
height="40px"
|
||||
>
|
||||
<GhostChainSelect small={small} />
|
||||
<Box display="flex" justifyContent="space-between" alignItems="center" width={small ? "calc(100vw - 78px)" : "320px"}>
|
||||
<SelectNetwork
|
||||
wrongNetworkToastId={wrongNetworkToastId}
|
||||
setWrongNetworkToastId={setWrongNetworkToastId}
|
||||
|
||||
@ -11,7 +11,7 @@ const WalletButton = ({ openWallet, connect }) => {
|
||||
const { isConnected, chain } = useAccount();
|
||||
const theme = useTheme();
|
||||
const onClick = isConnected ? openWallet : connect;
|
||||
const label = isConnected ? "Wallet" : `Connect`;
|
||||
const label = isConnected ? "Open Wallet" : `Connect Wallet`;
|
||||
return (
|
||||
<Button
|
||||
id="fatso-menu-button"
|
||||
|
||||
@ -12,7 +12,6 @@ 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";
|
||||
@ -61,7 +60,7 @@ const MetricsDashboard = ({ chainId }) => {
|
||||
</Paper>
|
||||
|
||||
<Paper style={{ padding: "0px" }} fullWidth={true} >
|
||||
<ProtocolDetails theme={theme} isMobileScreen={isMobileScreen} chainId={chainId} />
|
||||
<TokenInfo isMobileScreen={isMobileScreen} chainId={chainId} />
|
||||
</Paper>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
@ -1,137 +0,0 @@
|
||||
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;
|
||||
@ -1,19 +1,14 @@
|
||||
import { createContext, useEffect, useContext, useState, useMemo, useCallback, useRef } from "react"
|
||||
import { createContext, useContext, useState, useMemo } from "react"
|
||||
import { Unstable } from "@substrate/connect-discovery"
|
||||
import { createClient } from "@polkadot-api/substrate-client"
|
||||
import { getObservableClient } from "@polkadot-api/observable-client"
|
||||
import useSWR from "swr"
|
||||
|
||||
const MAX_BLOCK_TIMEOUT = 15000
|
||||
const DEFAULT_CHAIN_ID = "0x475e48fab52f3d0587b6b03101d224560c549e984d1dee197b7d8b55830e7da3"
|
||||
const UnstableProvider = createContext(null)
|
||||
export const useUnstableProvider = () => useContext(UnstableProvider)
|
||||
|
||||
export const UnstableProviderProvider = ({ children }) => {
|
||||
const [chainId, setChainId] = useState(DEFAULT_CHAIN_ID);
|
||||
const [isConnected, setIsConnected] = useState(false);
|
||||
const [reconnectTicket, setReconnectTicket] = useState(0);
|
||||
|
||||
const { data: providerDetails } = useSWR("getGhostProviders", () =>
|
||||
Unstable.getSubstrateConnectExtensionProviders()
|
||||
);
|
||||
@ -24,66 +19,36 @@ export const UnstableProviderProvider = ({ children }) => {
|
||||
() => providerDetail ? providerDetail.provider : null
|
||||
);
|
||||
|
||||
const [chainId, setChainId] = useState(DEFAULT_CHAIN_ID);
|
||||
|
||||
const client = useMemo(() => {
|
||||
if (!provider || !chainId) return undefined;
|
||||
|
||||
const chain = provider.getChains()[chainId];
|
||||
if (!chain) return undefined;
|
||||
return createClient(chain.connect);
|
||||
}, [provider, chainId]);
|
||||
|
||||
return createClient(chain.connect)
|
||||
}, [provider, chainId, reconnectTicket]);
|
||||
const observableClient = useMemo(() => {
|
||||
return client ? getObservableClient(client) : undefined;
|
||||
}, [client]);
|
||||
|
||||
const observableClient = useMemo(() => client ? getObservableClient(client) : undefined, [client]);
|
||||
const chainHead$ = useMemo(() => observableClient?.chainHead$(), [observableClient]);
|
||||
const chainHead$ = useMemo(() => {
|
||||
return observableClient ? observableClient.chainHead$() : undefined;
|
||||
}, [observableClient]);
|
||||
|
||||
const lastBlockNumber = useRef(0);
|
||||
|
||||
useEffect(() => {
|
||||
if (!chainHead$) return;
|
||||
|
||||
lastBlockNumber.current = 0;
|
||||
let timeoutId;
|
||||
|
||||
const sub = chainHead$.bestBlocks$.subscribe({
|
||||
next: (blocks) => {
|
||||
const currentHeight = blocks.at(0)?.number ?? -1;
|
||||
|
||||
if (currentHeight > lastBlockNumber.current) {
|
||||
lastBlockNumber.current = currentHeight;
|
||||
setIsConnected(true);
|
||||
|
||||
clearTimeout(timeoutId);
|
||||
timeoutId = setTimeout(() => {
|
||||
setIsConnected(false);
|
||||
setReconnectTicket(t => t + 1);
|
||||
}, MAX_BLOCK_TIMEOUT);
|
||||
}
|
||||
},
|
||||
error: (err) => {
|
||||
setIsConnected(false);
|
||||
setTimeout(() => setReconnectTicket(t => t + 1), 1000);
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
sub.unsubscribe();
|
||||
clearTimeout(timeoutId);
|
||||
};
|
||||
}, [chainHead$]);
|
||||
|
||||
const value = useMemo(() => ({
|
||||
isConnected,
|
||||
return (
|
||||
<UnstableProvider.Provider
|
||||
value={{
|
||||
providerDetails,
|
||||
providerDetail,
|
||||
connectProviderDetail: setProviderDetail,
|
||||
provider,
|
||||
chainId,
|
||||
client,
|
||||
setChainId,
|
||||
chainHead$
|
||||
}), [isConnected, providerDetails, providerDetail, chainId, client, chainHead$]);
|
||||
|
||||
return (
|
||||
<UnstableProvider.Provider value={value}>
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</UnstableProvider.Provider>
|
||||
);
|
||||
|
||||
@ -7,50 +7,10 @@ import { config } from "../../config";
|
||||
import { isNetworkLegacyType } from "../../constants";
|
||||
import { STAKING_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,
|
||||
functionName: "gatekeeperMetadata",
|
||||
scopeKey: `gatekeeperMetadata-${chainId}-${gatekeeper}`,
|
||||
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,
|
||||
|
||||