diff --git a/package.json b/package.json index 8114c04..fc1a469 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ghost-dao-interface", "private": true, - "version": "0.7.40", + "version": "0.7.41", "type": "module", "scripts": { "dev": "vite", diff --git a/src/containers/Breakout/BreakoutModal.jsx b/src/containers/Breakout/BreakoutModal.jsx index 36971f1..58d1729 100644 --- a/src/containers/Breakout/BreakoutModal.jsx +++ b/src/containers/Breakout/BreakoutModal.jsx @@ -20,7 +20,7 @@ import { GHOST_CONNECT } from "../../constants/ecosystem"; import { useLocalStorage } from "../../hooks/localstorage"; import { useBreakoutModal } from "../../hooks/breakoutModal"; -import { useTokenSymbol, useCirculatingSupply } from "../../hooks/tokens"; +import { useTokenSymbol } from "../../hooks/tokens"; import { useEpoch, useGatekeeperApy, useGatekeeperAddress } from "../../hooks/staking"; import { useEvmNetwork, useCurrentIndex, useUnstableProvider } from "../../hooks/ghost"; import { formatNumber, shorten } from "../../helpers"; @@ -252,8 +252,7 @@ const WelcomeView = ({ const { epoch } = useEpoch(chainId); const { gatekeeperAddress } = useGatekeeperAddress(chainId); - const circulatingSupply = useCirculatingSupply(chainId, "STNK"); - const gatekeepedApy = useGatekeeperApy(chainId); + const { gatekeepedApy, apyInner } = useGatekeeperApy(chainId); const { isExtensionMissing } = useUnstableProvider(); @@ -262,16 +261,6 @@ const WelcomeView = ({ closeModal(); } - 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 callDefaultFunction = useCallback(async () => { setIsPending(true); await defaultFunction()(); @@ -314,7 +303,7 @@ const WelcomeView = ({ - {formatNumber(apyInner * gatekeepedApy, 2)}% APY + {formatNumber(gatekeepedApy, 2)}% APY { const { symbol: csprSymbol } = useTokenSymbol(chainId, "CSPR"); const { contractAddress: ftsoAddress } = useBalance(chainId, "FTSO", EMPTY_ADDRESS); const { liveBonds } = useLiveBonds(chainId); - - const circulatingSupply = useCirculatingSupply(chainId, "STNK"); - const gatekeepedApy = useGatekeeperApy(chainId); - const { epoch } = useEpoch(chainId); + const { gatekeepedApy, apyInner } = useGatekeeperApy(chainId); const maxBondDiscountTest = useMemo(() => { const sortedGhostBonds = liveBonds.filter((bond) => !bond.isSoldOut) @@ -83,16 +80,6 @@ const ProtocolDetails = ({ chainId, isMobileScreen, theme, }) => { return `Up to ${formatNumber(maxDiscount, 0)}% Discount`; }, [liveBonds]); - 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; @@ -138,7 +125,7 @@ const ProtocolDetails = ({ chainId, isMobileScreen, theme, }) => { theme={theme} url={`/${networkName.toLowerCase()}/bridge`} name={`${bridgeNumbers} Stake\u00B2`} - sideName={`${formatNumber(apyInner * gatekeepedApy, 0)}% APY`} + sideName={`${formatNumber(gatekeepedApy, 0)}% APY`} description={`Staking\u00B2 strategy further deepens long-term incentives powered by sustainable crosschain bridging revenue. ${bridgeNumbers} Stake\u00B2 your ${csprSymbol} to receive organic APY with no warm-up and no dilution.`} /> diff --git a/src/hooks/staking/index.js b/src/hooks/staking/index.js index 368a314..8cea140 100644 --- a/src/hooks/staking/index.js +++ b/src/hooks/staking/index.js @@ -8,21 +8,18 @@ import { abi as GatekeeperAbi } from "../../abi/GhostGatekeeper.json"; import { shorten } from "../../helpers"; import { DecimalBigNumber } from "../../helpers/DecimalBigNumber"; import { executeOnChainTransaction } from "../helpers"; +import { useCirculatingSupply } from "../tokens"; export const useGatekeeperApy = (chainId) => { - const { data: gatekeeper, refetch } = useReadContract({ - abi: StakingAbi, - address: STAKING_ADDRESSES[chainId], - functionName: "gatekeeper", - scopeKey: `gatekeeper-${chainId}`, - chainId: chainId, - }); + const circulatingSupply = useCirculatingSupply(chainId, "STNK"); + const { gatekeeperAddress } = useGatekeeperAddress(chainId); + const { epoch } = useEpoch(chainId); const { data: metadata, error } = useReadContract({ abi: GatekeeperAbi, - address: gatekeeper, + address: gatekeeperAddress, functionName: "metadata", - scopeKey: `gatekeeperMetadata-${chainId}-${gatekeeper}`, + scopeKey: `gatekeeperMetadata-${chainId}-${gatekeeperAddress}`, chainId: chainId, }); @@ -40,12 +37,25 @@ export const useGatekeeperApy = (chainId) => { const numerator = amountIn.mul(feeIn).add(amountOut.mul(feeOut)); const denominator = amountIn.mul(stakeRatio).sub(amountOut.mul(stakeRatio)); - if (denominator?.toString() === "0") { - return 1; + let apyInner = Infinity; + if ((circulatingSupply?._value ?? 0n) === 0n) { + return { gatekeepedApy: apyInner, apyInner}; } + const value = epoch.distribute.div(circulatingSupply); + apyInner = 100 * (Math.pow(1 + parseFloat(value.toString()), 1095) - 1); + if (apyInner === 0) apyInner = Infinity; + + if (!denominator?._value || denominator._value.isZero()) { + return { gatekeepedApy: apyInner, apyInner }; + } const result = Number(numerator.div(denominator).toString()); - return Math.pow(1 + result, power); + const gatekeepedApy = Math.pow(1 + result, power); + + return { + gatekeepedApy: apyInner + gatekeepedApy + (apyInner * gatekeepedApy) / 100, + apyInner, + } } export const useCurrentIndex = (chainId) => {