Compare commits

..

No commits in common. "5bb5b7d7e061d5da6e04ec8fa103409d09a63f74" and "4c455bd1f5cc65d475262082e7fa8c0e9c9f866a" have entirely different histories.

19 changed files with 54 additions and 333 deletions

View File

@ -1,7 +1,7 @@
{ {
"name": "ghost-dao-interface", "name": "ghost-dao-interface",
"private": true, "private": true,
"version": "0.7.15", "version": "0.7.7",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",

View File

@ -121,7 +121,7 @@ function App() {
const provider = usePublicClient(); const provider = usePublicClient();
const chainId = useChainId(); const chainId = useChainId();
const isSmallerScreen = useMediaQuery("(max-width: 1130px)"); const isSmallerScreen = useMediaQuery("(max-width: 1047px)");
const isSmallScreen = useMediaQuery("(max-width: 600px)"); const isSmallScreen = useMediaQuery("(max-width: 600px)");
const { const {

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?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> <defs>
<style> <style>
.uuid-6437a6f0-42e0-4c9c-b0ef-b632253e989a { .uuid-6437a6f0-42e0-4c9c-b0ef-b632253e989a {

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?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> <defs>
<style> <style>
.uuid-e080659c-91a4-4965-9905-603394020b2c { .uuid-e080659c-91a4-4965-9905-603394020b2c {

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?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> <defs>
<style> <style>
.uuid-26b0e53c-73c9-4369-9725-1cee728298be { .uuid-26b0e53c-73c9-4369-9725-1cee728298be {

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -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> <defs>
<style> <style>
.uuid-67f42f03-098b-49dc-a7ed-dc13bd713387 { .uuid-67f42f03-098b-49dc-a7ed-dc13bd713387 {

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?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> <defs>
<style> <style>
.uuid-a205ebe2-7c8f-434c-9bde-29ac218716be { .uuid-a205ebe2-7c8f-434c-9bde-29ac218716be {

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -118,19 +118,19 @@ const NavItem = ({
const match = currentLocation.pathname === to || currentLocation.pathname === `/${to}`; const match = currentLocation.pathname === to || currentLocation.pathname === `/${to}`;
const linkProps = props.href const linkProps = props.href
? { ? {
href: props.href, href: props.href,
target: "_blank", target: "_blank",
className: `external-site-link ${className}`, className: `external-site-link ${className}`,
} }
: { : {
component: NavLink, component: NavLink,
to: to, to: to,
className: `button-dapp-menu ${className}`, className: `button-dapp-menu ${className}`,
}; };
const LinkItem = () => ( const LinkItem = () => (
<Link {...linkProps} {...props} underline="hover" onClick={(e) => e.stopPropagation()}> <Link {...linkProps} {...props} underline="hover">
<Box <Box
sx={{ fontFamily: "Ubuntu" }} sx={{ fontFamily: "Ubuntu" }}
display="flex" display="flex"

View File

@ -2,7 +2,7 @@ import { Box, Typography, useMediaQuery, useTheme } from "@mui/material";
const PageTitle = ({ name, subtitle, noMargin }) => { const PageTitle = ({ name, subtitle, noMargin }) => {
const theme = useTheme(); const theme = useTheme();
const mobile = useMediaQuery(theme.breakpoints.down("900")); const mobile = useMediaQuery(theme.breakpoints.down("700"));
return ( return (
<Box <Box

View File

@ -136,7 +136,7 @@ const NavContent = ({ chainId, addressChainId }) => {
</AccordionDetails> </AccordionDetails>
} }
/> />
<NavItem icon={StakeIcon} label={`(3, 3) Stake`} to={`/${chainName}/stake`} /> <NavItem icon={StakeIcon} label={`(3, 3) Stake`} to={`/${chainName}/stake`} />
<NavItem <NavItem
defaultExpanded defaultExpanded
icon={BondIcon} icon={BondIcon}
@ -180,7 +180,7 @@ const NavContent = ({ chainId, addressChainId }) => {
</AccordionDetails> </AccordionDetails>
} }
/> />
<NavItem icon={ForkRightIcon} label={`${bridgeNumbers} Stake\u00B2`} to={`/${chainName}/bridge`} /> <NavItem icon={ForkRightIcon} label={`${bridgeNumbers} Stake\u00B2`} to={`/${chainName}/bridge`} />
{isGovernanceAvailable(chainId, addressChainId) && <NavItem icon={GavelIcon} label={`Governance`} to={`/${chainName}/governance`} />} {isGovernanceAvailable(chainId, addressChainId) && <NavItem icon={GavelIcon} label={`Governance`} to={`/${chainName}/governance`} />}
<Box className="menu-divider"> <Box className="menu-divider">
<Divider /> <Divider />

View File

@ -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;

View File

@ -71,7 +71,7 @@ function SelectNetwork({ chainId, wrongNetworkToastId, setWrongNetworkToastId, s
} }
return( return(
<FormControl sx={{ width: small ? "auto" : "155px" }}> <FormControl sx={{ width: small ? "100px" : "155px" }}>
<Select <Select
labelId="network-select-helper-label" labelId="network-select-helper-label"
id="network-select-helper" id="network-select-helper"
@ -92,7 +92,7 @@ function SelectNetwork({ chainId, wrongNetworkToastId, setWrongNetworkToastId, s
return ( return (
<MenuItem key={chain.name} value={chain.id}> <MenuItem key={chain.name} value={chain.id}>
<Box gap="10px" display="flex" flexDirection="row" alignItems="center"> <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>} {!small && <Typography>{chain.name}</Typography>}
</Box> </Box>
</MenuItem> </MenuItem>

View File

@ -2,7 +2,7 @@ import { Box, Button, SvgIcon, useMediaQuery, useTheme } from "@mui/material";
import MenuIcon from "../../assets/icons/hamburger.svg?react"; import MenuIcon from "../../assets/icons/hamburger.svg?react";
import Wallet from "./Wallet" import Wallet from "./Wallet"
import SelectNetwork from "./SelectNetwork"; import SelectNetwork from "./SelectNetwork";
import GhostChainSelect from "./GhostChainSelect";
const PREFIX = "TopBar"; const PREFIX = "TopBar";
@ -23,8 +23,8 @@ function TopBar({
setWrongNetworkToastId setWrongNetworkToastId
}) { }) {
const themeColor = useTheme(); const themeColor = useTheme();
const desktop = useMediaQuery(themeColor.breakpoints.up(1130)); const desktop = useMediaQuery(themeColor.breakpoints.up(1048));
const small = useMediaQuery(themeColor.breakpoints.down(600)); const small = useMediaQuery(themeColor.breakpoints.down(400));
return ( return (
<Box <Box
display="flex" display="flex"
@ -34,14 +34,7 @@ function TopBar({
marginRight={desktop ? "33px" : "0px"} marginRight={desktop ? "33px" : "0px"}
> >
<Box display="flex" alignItems="center"> <Box display="flex" alignItems="center">
<Box <Box display="flex" justifyContent="space-between" alignItems="center" width={small ? "calc(100vw - 78px)" : "320px"}>
display="flex"
justifyContent="space-between"
alignItems="center"
width={small ? "calc(100vw - 78px)" : "500px"}
height="40px"
>
<GhostChainSelect small={small} />
<SelectNetwork <SelectNetwork
wrongNetworkToastId={wrongNetworkToastId} wrongNetworkToastId={wrongNetworkToastId}
setWrongNetworkToastId={setWrongNetworkToastId} setWrongNetworkToastId={setWrongNetworkToastId}

View File

@ -11,7 +11,7 @@ const WalletButton = ({ openWallet, connect }) => {
const { isConnected, chain } = useAccount(); const { isConnected, chain } = useAccount();
const theme = useTheme(); const theme = useTheme();
const onClick = isConnected ? openWallet : connect; const onClick = isConnected ? openWallet : connect;
const label = isConnected ? "Wallet" : `Connect`; const label = isConnected ? "Open Wallet" : `Connect Wallet`;
return ( return (
<Button <Button
id="fatso-menu-button" id="fatso-menu-button"

View File

@ -12,7 +12,6 @@ import {
CurrentIndex, CurrentIndex,
} from "./components/Metric"; } from "./components/Metric";
import TokenInfo from "./components/TokenInfo"; import TokenInfo from "./components/TokenInfo";
import ProtocolDetails from "./components/ProtocolDetails";
import Paper from "../../components/Paper/Paper"; import Paper from "../../components/Paper/Paper";
import PageTitle from "../../components/PageTitle/PageTitle"; import PageTitle from "../../components/PageTitle/PageTitle";
@ -61,7 +60,7 @@ const MetricsDashboard = ({ chainId }) => {
</Paper> </Paper>
<Paper style={{ padding: "0px" }} fullWidth={true} > <Paper style={{ padding: "0px" }} fullWidth={true} >
<ProtocolDetails theme={theme} isMobileScreen={isMobileScreen} chainId={chainId} /> <TokenInfo isMobileScreen={isMobileScreen} chainId={chainId} />
</Paper> </Paper>
</Grid> </Grid>
</Grid> </Grid>

View File

@ -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;

View File

@ -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 { Unstable } from "@substrate/connect-discovery"
import { createClient } from "@polkadot-api/substrate-client" import { createClient } from "@polkadot-api/substrate-client"
import { getObservableClient } from "@polkadot-api/observable-client" import { getObservableClient } from "@polkadot-api/observable-client"
import useSWR from "swr" import useSWR from "swr"
const MAX_BLOCK_TIMEOUT = 15000
const DEFAULT_CHAIN_ID = "0x475e48fab52f3d0587b6b03101d224560c549e984d1dee197b7d8b55830e7da3" const DEFAULT_CHAIN_ID = "0x475e48fab52f3d0587b6b03101d224560c549e984d1dee197b7d8b55830e7da3"
const UnstableProvider = createContext(null) const UnstableProvider = createContext(null)
export const useUnstableProvider = () => useContext(UnstableProvider) export const useUnstableProvider = () => useContext(UnstableProvider)
export const UnstableProviderProvider = ({ children }) => { 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", () => const { data: providerDetails } = useSWR("getGhostProviders", () =>
Unstable.getSubstrateConnectExtensionProviders() Unstable.getSubstrateConnectExtensionProviders()
); );
@ -24,66 +19,36 @@ export const UnstableProviderProvider = ({ children }) => {
() => providerDetail ? providerDetail.provider : null () => providerDetail ? providerDetail.provider : null
); );
const [chainId, setChainId] = useState(DEFAULT_CHAIN_ID);
const client = useMemo(() => { const client = useMemo(() => {
if (!provider || !chainId) return undefined; if (!provider || !chainId) return undefined;
const chain = provider.getChains()[chainId]; const chain = provider.getChains()[chainId];
if (!chain) return undefined; if (!chain) return undefined;
return createClient(chain.connect);
}, [provider, chainId]);
return createClient(chain.connect) const observableClient = useMemo(() => {
}, [provider, chainId, reconnectTicket]); return client ? getObservableClient(client) : undefined;
}, [client]);
const observableClient = useMemo(() => client ? getObservableClient(client) : undefined, [client]); const chainHead$ = useMemo(() => {
const chainHead$ = useMemo(() => observableClient?.chainHead$(), [observableClient]); 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,
providerDetails,
providerDetail,
connectProviderDetail: setProviderDetail,
chainId,
client,
setChainId,
chainHead$
}), [isConnected, providerDetails, providerDetail, chainId, client, chainHead$]);
return ( return (
<UnstableProvider.Provider value={value}> <UnstableProvider.Provider
value={{
providerDetails,
providerDetail,
connectProviderDetail: setProviderDetail,
provider,
chainId,
client,
setChainId,
chainHead$
}}
>
{children} {children}
</UnstableProvider.Provider> </UnstableProvider.Provider>
); );

View File

@ -7,50 +7,10 @@ import { config } from "../../config";
import { isNetworkLegacyType } from "../../constants"; import { isNetworkLegacyType } from "../../constants";
import { STAKING_ADDRESSES } from "../../constants/addresses"; import { STAKING_ADDRESSES } from "../../constants/addresses";
import { abi as StakingAbi } from "../../abi/GhostStaking.json"; import { abi as StakingAbi } from "../../abi/GhostStaking.json";
import { abi as GatekeeperAbi } from "../../abi/GhostGatekeeper.json";
import { shorten } from "../../helpers"; import { shorten } from "../../helpers";
import { DecimalBigNumber } from "../../helpers/DecimalBigNumber"; 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) => { export const useCurrentIndex = (chainId) => {
const { data: index, refetch } = useReadContract({ const { data: index, refetch } = useReadContract({
abi: StakingAbi, abi: StakingAbi,