Compare commits

..

No commits in common. "bc5f88d57255773178f3134dc5a74f1927bbb639" and "856bf01ffe1fa3d7c56cfb63fc1db9e15e3153ff" have entirely different histories.

53 changed files with 237 additions and 1304 deletions

View File

@ -1,7 +1,7 @@
{ {
"name": "ghost-dao-interface", "name": "ghost-dao-interface",
"private": true, "private": true,
"version": "0.2.0", "version": "0.1.2",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
@ -18,8 +18,6 @@
"@mui/icons-material": "^6.4.7", "@mui/icons-material": "^6.4.7",
"@mui/material": "^6.4.7", "@mui/material": "^6.4.7",
"@mui/utils": "^6.4.6", "@mui/utils": "^6.4.6",
"@polkadot-api/utils": "~0.1.2",
"@polkadot-labs/hdkd-helpers": "^0.0.20",
"@tanstack/react-query": "^5.67.2", "@tanstack/react-query": "^5.67.2",
"@tanstack/react-query-devtools": "^5.67.2", "@tanstack/react-query-devtools": "^5.67.2",
"@wagmi/core": "^2.17.3", "@wagmi/core": "^2.17.3",

View File

@ -32,12 +32,6 @@ importers:
'@mui/utils': '@mui/utils':
specifier: ^6.4.6 specifier: ^6.4.6
version: 6.4.6(@types/react@19.0.10)(react@19.0.0) version: 6.4.6(@types/react@19.0.10)(react@19.0.0)
'@polkadot-api/utils':
specifier: 0.1.2
version: 0.1.2
'@polkadot-labs/hdkd-helpers':
specifier: ^0.0.20
version: 0.0.20
'@tanstack/react-query': '@tanstack/react-query':
specifier: ^5.67.2 specifier: ^5.67.2
version: 5.67.2(react@19.0.0) version: 5.67.2(react@19.0.0)
@ -729,10 +723,6 @@ packages:
resolution: {integrity: sha512-HxngEd2XUcg9xi20JkwlLCtYwfoFw4JGkuZpT+WlsPD4gB/cxkvTD8fSsoAnphGZhFdZYKeQIPCuFlWPm1uE0g==} resolution: {integrity: sha512-HxngEd2XUcg9xi20JkwlLCtYwfoFw4JGkuZpT+WlsPD4gB/cxkvTD8fSsoAnphGZhFdZYKeQIPCuFlWPm1uE0g==}
engines: {node: ^14.21.3 || >=16} engines: {node: ^14.21.3 || >=16}
'@noble/curves@1.9.6':
resolution: {integrity: sha512-GIKz/j99FRthB8icyJQA51E8Uk5hXmdyThjgQXRKiv9h0zeRlzSCLIzFw6K1LotZ3XuB7yzlf76qk7uBmTdFqA==}
engines: {node: ^14.21.3 || >=16}
'@noble/hashes@1.4.0': '@noble/hashes@1.4.0':
resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==}
engines: {node: '>= 16'} engines: {node: '>= 16'}
@ -753,12 +743,6 @@ packages:
resolution: {integrity: sha512-IHnV6A+zxU7XwmKFinmYjUcwlyK9+xkG3/s9KcQhI9BjQKycrJ1JRO+FbNYPwZiPKW3je/DR0k7w8/gLa5eaxQ==} resolution: {integrity: sha512-IHnV6A+zxU7XwmKFinmYjUcwlyK9+xkG3/s9KcQhI9BjQKycrJ1JRO+FbNYPwZiPKW3je/DR0k7w8/gLa5eaxQ==}
deprecated: 'The package is now available as "qr": npm install qr' deprecated: 'The package is now available as "qr": npm install qr'
'@polkadot-api/utils@0.1.2':
resolution: {integrity: sha512-yhs5k2a8N1SBJcz7EthZoazzLQUkZxbf+0271Xzu42C5AEM9K9uFLbsB+ojzHEM72O5X8lPtSwGKNmS7WQyDyg==}
'@polkadot-labs/hdkd-helpers@0.0.20':
resolution: {integrity: sha512-P3o1FpPqLACaHhDT/J6O3xYQIBdOs0FDJtZQI8/LGotgIGp85mKDnH/cSSK3QC2i67ZY/d/POs8K0jEspLMiGg==}
'@popperjs/core@2.11.8': '@popperjs/core@2.11.8':
resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==}
@ -929,9 +913,6 @@ packages:
'@scure/bip39@1.6.0': '@scure/bip39@1.6.0':
resolution: {integrity: sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==} resolution: {integrity: sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==}
'@scure/sr25519@0.2.0':
resolution: {integrity: sha512-uUuLP7Z126XdSizKtrCGqYyR3b3hYtJ6Fg/XFUXmc2//k2aXHDLqZwFeXxL97gg4XydPROPVnuaHGF2+xriSKg==}
'@socket.io/component-emitter@3.1.2': '@socket.io/component-emitter@3.1.2':
resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==} resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==}
@ -2394,9 +2375,6 @@ packages:
engines: {node: '>=16.0.0'} engines: {node: '>=16.0.0'}
hasBin: true hasBin: true
scale-ts@1.6.1:
resolution: {integrity: sha512-PBMc2AWc6wSEqJYBDPcyCLUj9/tMKnLX70jLOSndMtcUoLQucP/DM0vnQo1wJAYjTrQiq8iG9rD0q6wFzgjH7g==}
scheduler@0.25.0: scheduler@0.25.0:
resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==} resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==}
@ -3578,10 +3556,6 @@ snapshots:
dependencies: dependencies:
'@noble/hashes': 1.8.0 '@noble/hashes': 1.8.0
'@noble/curves@1.9.6':
dependencies:
'@noble/hashes': 1.8.0
'@noble/hashes@1.4.0': {} '@noble/hashes@1.4.0': {}
'@noble/hashes@1.7.0': {} '@noble/hashes@1.7.0': {}
@ -3592,16 +3566,6 @@ snapshots:
'@paulmillr/qr@0.2.1': {} '@paulmillr/qr@0.2.1': {}
'@polkadot-api/utils@0.1.2': {}
'@polkadot-labs/hdkd-helpers@0.0.20':
dependencies:
'@noble/curves': 1.9.6
'@noble/hashes': 1.8.0
'@scure/base': 1.2.6
'@scure/sr25519': 0.2.0
scale-ts: 1.6.1
'@popperjs/core@2.11.8': {} '@popperjs/core@2.11.8': {}
'@reown/appkit-common@1.7.8(bufferutil@4.0.9)(utf-8-validate@5.0.10)(zod@3.22.4)': '@reown/appkit-common@1.7.8(bufferutil@4.0.9)(utf-8-validate@5.0.10)(zod@3.22.4)':
@ -3972,11 +3936,6 @@ snapshots:
'@noble/hashes': 1.8.0 '@noble/hashes': 1.8.0
'@scure/base': 1.2.6 '@scure/base': 1.2.6
'@scure/sr25519@0.2.0':
dependencies:
'@noble/curves': 1.9.6
'@noble/hashes': 1.8.0
'@socket.io/component-emitter@3.1.2': {} '@socket.io/component-emitter@3.1.2': {}
'@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.26.9)': '@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.26.9)':
@ -5512,8 +5471,8 @@ snapshots:
ox@0.6.7(zod@3.22.4): ox@0.6.7(zod@3.22.4):
dependencies: dependencies:
'@adraffy/ens-normalize': 1.11.0 '@adraffy/ens-normalize': 1.11.0
'@noble/curves': 1.9.2 '@noble/curves': 1.8.1
'@noble/hashes': 1.8.0 '@noble/hashes': 1.7.1
'@scure/bip32': 1.6.2 '@scure/bip32': 1.6.2
'@scure/bip39': 1.5.4 '@scure/bip39': 1.5.4
abitype: 1.0.8(zod@3.22.4) abitype: 1.0.8(zod@3.22.4)
@ -5883,8 +5842,6 @@ snapshots:
sass-embedded-win32-ia32: 1.85.1 sass-embedded-win32-ia32: 1.85.1
sass-embedded-win32-x64: 1.85.1 sass-embedded-win32-x64: 1.85.1
scale-ts@1.6.1: {}
scheduler@0.25.0: {} scheduler@0.25.0: {}
scss@0.2.4: scss@0.2.4:

View File

@ -27,7 +27,6 @@ const StakeContainer = lazy(() => import("./containers/Stake/StakeContainer"));
const TreasuryDashboard = lazy(() => import("./containers/TreasuryDashboard/TreasuryDashboard")); const TreasuryDashboard = lazy(() => import("./containers/TreasuryDashboard/TreasuryDashboard"));
const Faucet = lazy(() => import("./containers/Faucet/Faucet")); const Faucet = lazy(() => import("./containers/Faucet/Faucet"));
const Dex = lazy(() => import("./containers/Dex/Dex")); const Dex = lazy(() => import("./containers/Dex/Dex"));
const Bridge = lazy(() => import("./containers/Bridge/Bridge"));
const NotFound = lazy(() => import("./containers/NotFound/NotFound")); const NotFound = lazy(() => import("./containers/NotFound/NotFound"));
const PREFIX = "App"; const PREFIX = "App";
@ -188,7 +187,6 @@ function App() {
<Route path="/bonds/:id" element={<BondModalContainer connect={tryConnectInjected} address={address} chainId={addressChainId ? addressChainId : chainId} />} /> <Route path="/bonds/:id" element={<BondModalContainer connect={tryConnectInjected} address={address} chainId={addressChainId ? addressChainId : chainId} />} />
<Route path="/stake" element={<StakeContainer connect={tryConnectInjected} address={address} chainId={addressChainId ? addressChainId : chainId}/>} /> <Route path="/stake" element={<StakeContainer connect={tryConnectInjected} address={address} chainId={addressChainId ? addressChainId : chainId}/>} />
<Route path="/faucet" element={<Faucet config={config} connect={tryConnectInjected} address={address} chainId={addressChainId ? addressChainId : chainId} />} /> <Route path="/faucet" element={<Faucet config={config} connect={tryConnectInjected} address={address} chainId={addressChainId ? addressChainId : chainId} />} />
<Route path="/bridge" element={<Bridge config={config} connect={tryConnectInjected} address={address} chainId={addressChainId ? addressChainId : chainId} />} />
<Route path="/dex/:name" element={<Dex connect={tryConnectInjected} address={address} chainId={addressChainId ? addressChainId : chainId} />} /> <Route path="/dex/:name" element={<Dex connect={tryConnectInjected} address={address} chainId={addressChainId ? addressChainId : chainId} />} />
</> </>
} }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -132,7 +132,6 @@ const NavItem = ({
const LinkItem = () => ( const LinkItem = () => (
<Link {...linkProps} {...props} underline="hover"> <Link {...linkProps} {...props} underline="hover">
<Box <Box
sx={{ fontFamily: "Ubuntu" }}
display="flex" display="flex"
flexDirection="row" flexDirection="row"
alignItems="center" alignItems="center"

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("700")); const mobile = useMediaQuery(theme.breakpoints.down("sm"));
return ( return (
<Box <Box

View File

@ -47,8 +47,7 @@ import BondDiscount from "../../containers/Bond/components/BondDiscount";
import DashboardIcon from '@mui/icons-material/Dashboard'; import DashboardIcon from '@mui/icons-material/Dashboard';
import ShowerIcon from '@mui/icons-material/Shower'; import ShowerIcon from '@mui/icons-material/Shower';
import { useTokenSymbol } from "../../hooks/tokens"; import { useFtsoPrice, useGhstPrice } from "../../hooks/prices";
import { useFtsoPrice, useGhstPrice, useGhostedSupplyPrice } from "../../hooks/prices";
import { useLiveBonds } from "../../hooks/bonds/index"; import { useLiveBonds } from "../../hooks/bonds/index";
const PREFIX = "NavContent"; const PREFIX = "NavContent";
@ -67,10 +66,6 @@ const NavContent = ({ chainId, addressChainId }) => {
const { liveBonds: ghostBonds } = useLiveBonds(chainId); const { liveBonds: ghostBonds } = useLiveBonds(chainId);
const ftsoPrice = useFtsoPrice(chainId); const ftsoPrice = useFtsoPrice(chainId);
const ghstPrice = useGhstPrice(chainId); const ghstPrice = useGhstPrice(chainId);
const ghostedSupplyPrice = useGhostedSupplyPrice(chainId);
const { symbol: ftsoSymbol } = useTokenSymbol(chainId, "FTSO");
const { symbol: ghstSymbol } = useTokenSymbol(chainId, "GHST");
return ( return (
<Paper className="dapp-sidebar"> <Paper className="dapp-sidebar">
@ -87,19 +82,16 @@ const NavContent = ({ chainId, addressChainId }) => {
</Link> </Link>
<Box display="flex" flexDirection="column" mt="10px"> <Box display="flex" flexDirection="column" mt="10px">
<Box fontSize="12px" fontWeight="500" lineHeight={"15px"}> <Box fontSize="12px" fontWeight="500" lineHeight={"15px"}>
{ftsoSymbol} Price: {formatCurrency(ftsoPrice, 2)} FTSO Price: {formatCurrency(ftsoPrice, 2)}
</Box> </Box>
<Box fontSize="12px" fontWeight="500" lineHeight="15px"> <Box fontSize="12px" fontWeight="500" lineHeight="15px">
{ghstSymbol} Price: {formatCurrency(ghstPrice, 2)} GHST Price: {formatCurrency(ghstPrice, 2)}
</Box>
<Box fontSize="12px" fontWeight="500" lineHeight={"15px"}>
Ghosted Supply: {formatCurrency(ghostedSupplyPrice, 2)}
</Box> </Box>
</Box> </Box>
</Box> </Box>
<Box className="menu-divider"> <Box className="menu-divider">
<Divider /> <Divider />
</Box> </Box>
<div className="dapp-menu-links"> <div className="dapp-menu-links">
@ -145,7 +137,6 @@ const NavContent = ({ chainId, addressChainId }) => {
/> />
<NavItem icon={StakeIcon} label={`Stake`} to="/stake" /> <NavItem icon={StakeIcon} label={`Stake`} to="/stake" />
<NavItem icon={ShowerIcon} label={`Faucet`} to="/faucet" /> <NavItem icon={ShowerIcon} label={`Faucet`} to="/faucet" />
<NavItem icon={PublicIcon} label={`Bridge`} to="/bridge" />
<NavItem <NavItem
icon={CurrencyExchangeIcon} icon={CurrencyExchangeIcon}
label={`Dex`} label={`Dex`}
@ -176,6 +167,7 @@ const NavContent = ({ chainId, addressChainId }) => {
</> </>
} }
<NavItem icon={PublicIcon} label={`Bridge`} href="https://bridge.ghostchain.io/" />
<NavItem <NavItem
to='' to=''
icon={PublicIcon} icon={PublicIcon}

View File

@ -28,14 +28,14 @@ const StyledArrow = styled(Box)(
}, },
); );
const SwapCollection = ({ UpperSwapCard, LowerSwapCard, arrowOnClick, iconNotNeeded }) => { const SwapCollection = ({ UpperSwapCard, LowerSwapCard, arrowOnClick }) => {
const theme = useTheme(); const theme = useTheme();
return ( return (
<Box display="flex" flexDirection="column" maxWidth="476px"> <Box display="flex" flexDirection="column" maxWidth="476px">
{UpperSwapCard} {UpperSwapCard}
<Box display="flex" flexDirection="row" justifyContent="center"> <Box display="flex" flexDirection="row" justifyContent="center">
{!iconNotNeeded && (<StyledArrow <StyledArrow
width="21px" width="21px"
height="21px" height="21px"
borderRadius="6px" borderRadius="6px"
@ -55,8 +55,7 @@ const SwapCollection = ({ UpperSwapCard, LowerSwapCard, arrowOnClick, iconNotNee
}} }}
/> />
</Box> </Box>
</StyledArrow>)} </StyledArrow>
{iconNotNeeded && <Box height="21px" />}
</Box> </Box>
<Box marginTop="-7px">{LowerSwapCard}</Box> <Box marginTop="-7px">{LowerSwapCard}</Box>
</Box> </Box>

View File

@ -1,8 +1,8 @@
import { SvgIcon } from "@mui/material"; import { SvgIcon } from "@mui/material";
import { styled } from "@mui/material/styles"; import { styled } from "@mui/material/styles";
import FtsoIcon from "../../assets/tokens/FTSO.svg?react"; import FtsoIcon from "../../assets/tokens/eGHST.svg?react";
import StnkIcon from "../../assets/tokens/STNK.svg?react"; import StnkIcon from "../../assets/tokens/sGHST.svg?react";
import GhstIcon from "../../assets/tokens/GHST.svg?react"; import GhstIcon from "../../assets/tokens/GHST.svg?react";
import DaiIcon from "../../assets/tokens/DAI.svg?react"; import DaiIcon from "../../assets/tokens/DAI.svg?react";
import WethIcon from "../../assets/tokens/wETH.svg?react"; import WethIcon from "../../assets/tokens/wETH.svg?react";
@ -30,27 +30,15 @@ const Token = ({ name, viewBox = "0 0 260 260", fontSize = "large", ...props })
case "FTSO": case "FTSO":
icon = FtsoIcon; icon = FtsoIcon;
break; break;
case "ECSPR":
icon = FtsoIcon;
break;
case "STNK": case "STNK":
icon = StnkIcon; icon = StnkIcon;
break; break;
case "SCSPR":
icon = StnkIcon;
break;
case "GHST": case "GHST":
icon = GhstIcon; icon = GhstIcon;
break; break;
case "CSPR":
icon = GhstIcon;
break;
case "GDAI": case "GDAI":
icon = DaiIcon; icon = DaiIcon;
break; break;
case "DAI":
icon = DaiIcon;
break;
case "ETH": case "ETH":
icon = WethIcon; icon = WethIcon;
break; break;

View File

@ -14,7 +14,7 @@ import EthIcon from "../../assets/tokens/ETH.svg?react";
import { useSwitchChain } from 'wagmi'; import { useSwitchChain } from 'wagmi';
import toast from "react-hot-toast"; import toast from "react-hot-toast";
function SelectNetwork({ chainId, wrongNetworkToastId, setWrongNetworkToastId, small }) { function SelectNetwork({ chainId, wrongNetworkToastId, setWrongNetworkToastId }) {
const theme = useTheme(); const theme = useTheme();
const { chains, switchChain } = useSwitchChain(); const { chains, switchChain } = useSwitchChain();
@ -37,7 +37,7 @@ function SelectNetwork({ chainId, wrongNetworkToastId, setWrongNetworkToastId, s
} }
return( return(
<FormControl sx={{ width: small ? "100px" : "155px" }}> <FormControl sx={{ width: "155px" }}>
<Select <Select
labelId="network-select-helper-label" labelId="network-select-helper-label"
id="network-select-helper" id="network-select-helper"
@ -58,7 +58,7 @@ function SelectNetwork({ chainId, wrongNetworkToastId, setWrongNetworkToastId, s
<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 component={EthIcon} viewBox="0 0 32 32" /> <SvgIcon component={EthIcon} viewBox="0 0 32 32" />
{!small && <Typography>{chain.name}</Typography>} <Typography>{chain.name}</Typography>
</Box> </Box>
</MenuItem> </MenuItem>
) )

View File

@ -23,7 +23,6 @@ function TopBar({
}) { }) {
const themeColor = useTheme(); const themeColor = useTheme();
const desktop = useMediaQuery(themeColor.breakpoints.up(1048)); const desktop = useMediaQuery(themeColor.breakpoints.up(1048));
const small = useMediaQuery(themeColor.breakpoints.down(400));
return ( return (
<Box <Box
display="flex" display="flex"
@ -33,12 +32,11 @@ function TopBar({
marginRight={desktop ? "33px" : "0px"} marginRight={desktop ? "33px" : "0px"}
> >
<Box display="flex" alignItems="center"> <Box display="flex" alignItems="center">
<Box display="flex" justifyContent="space-between" alignItems="center" width={small ? "calc(100vw - 78px)" : "320px"}> <Box display="flex" justifyContent="space-between" alignItems="center" width="320px">
<SelectNetwork <SelectNetwork
wrongNetworkToastId={wrongNetworkToastId} wrongNetworkToastId={wrongNetworkToastId}
setWrongNetworkToastId={setWrongNetworkToastId} setWrongNetworkToastId={setWrongNetworkToastId}
chainId={chainId} chainId={chainId}
small={small}
/> />
<Wallet address={address} connect={connect} chainId={chainId} /> <Wallet address={address} connect={connect} chainId={chainId} />
</Box> </Box>

View File

@ -152,7 +152,7 @@ function InitialWalletView({ address, chainId, onClose }) {
fullWidth fullWidth
onClick={() => onBtnClick("uniswap", DAI_ADDRESSES[chainId], FTSO_ADDRESSES[chainId])} onClick={() => onBtnClick("uniswap", DAI_ADDRESSES[chainId], FTSO_ADDRESSES[chainId])}
> >
<Typography>{`${tokens?.ftso?.symbol}-${tokens?.dai?.symbol} on Uniswap`}</Typography> <Typography>FTSO-gDAI on Uniswap</Typography>
</SecondaryButton> </SecondaryButton>
</Box> </Box>

View File

@ -18,7 +18,7 @@ import GhostStyledIcon from "../../Icon/GhostIcon";
import TokenStack from "../../TokenStack/TokenStack"; import TokenStack from "../../TokenStack/TokenStack";
import { PrimaryButton, SecondaryButton } from "../../Button"; import { PrimaryButton, SecondaryButton } from "../../Button";
import { useBalance, useTokenSymbol } from "../../../hooks/tokens"; import { useBalance } from "../../../hooks/tokens";
import { useDaiPrice, useFtsoPrice, useStnkPrice, useGhstPrice } from "../../../hooks/prices"; import { useDaiPrice, useFtsoPrice, useStnkPrice, useGhstPrice } from "../../../hooks/prices";
import { useLpValuation } from "../../../hooks/treasury"; import { useLpValuation } from "../../../hooks/treasury";
import { useAccount } from "wagmi"; import { useAccount } from "wagmi";
@ -76,7 +76,7 @@ export const Token = (props) => {
const navigate = useNavigate(); const navigate = useNavigate();
const useLink = (symbol, fromAddress, toAddress, isPool) => { const useLink = (symbol, fromAddress, toAddress, isPool) => {
if (symbol.toUpperCase() === "GDAI") { if (symbol === "GDAI") {
navigate({ pathname: "/faucet" }) navigate({ pathname: "/faucet" })
} else { } else {
navigate({ navigate({
@ -133,7 +133,7 @@ export const Token = (props) => {
onClick={() => useLink(symbol, daiAddress, address, isPool)} onClick={() => useLink(symbol, daiAddress, address, isPool)}
fullWidth fullWidth
> >
<Typography>Get on {symbol.toUpperCase() === "GDAI" ? "Faucet" : "Uniswap"}</Typography> <Typography>Get on {symbol === "GDAI" ? "Faucet" : "Uniswap"}</Typography>
</SecondaryButton> </SecondaryButton>
</Box> </Box>
</Box> </Box>
@ -178,15 +178,9 @@ export const useWallet = (chainId, userAddress) => {
const ghstPrice = useGhstPrice(chainId); const ghstPrice = useGhstPrice(chainId);
const lpDaiFtsoPrice = useLpValuation(chainId, "GDAI_FTSO", 1000000000000000000n); const lpDaiFtsoPrice = useLpValuation(chainId, "GDAI_FTSO", 1000000000000000000n);
const { symbol: daiSymbol } = useTokenSymbol(chainId, "GDAI");
const { symbol: ftsoSymbol } = useTokenSymbol(chainId, "FTSO");
const { symbol: stnkSymbol } = useTokenSymbol(chainId, "STNK");
const { symbol: ghstSymbol } = useTokenSymbol(chainId, "GHST");
const { symbol: lpDaiFtsoSymbol } = useTokenSymbol(chainId, "GDAI_FTSO");
const tokens = { const tokens = {
dai: { dai: {
symbol: daiSymbol, symbol: "GDAI",
address: daiAddress, address: daiAddress,
balance: daiBalance, balance: daiBalance,
price: daiPrice, price: daiPrice,
@ -194,7 +188,7 @@ export const useWallet = (chainId, userAddress) => {
externalUrl: "https://ghostchain.io/wp-content/uploads/2025/03/gDAI.svg", externalUrl: "https://ghostchain.io/wp-content/uploads/2025/03/gDAI.svg",
}, },
ftso: { ftso: {
symbol: ftsoSymbol, symbol: "FTSO",
address: ftsoAddress, address: ftsoAddress,
balance: ftsoBalance, balance: ftsoBalance,
price: ftsoPrice, price: ftsoPrice,
@ -202,7 +196,7 @@ export const useWallet = (chainId, userAddress) => {
externalUrl: "https://ghostchain.io/wp-content/uploads/2025/03/eGHST.svg", externalUrl: "https://ghostchain.io/wp-content/uploads/2025/03/eGHST.svg",
}, },
stnk: { stnk: {
symbol: stnkSymbol, symbol: "STNK",
address: stnkAddress, address: stnkAddress,
balance: stnkBalance, balance: stnkBalance,
price: stnkPrice, price: stnkPrice,
@ -210,7 +204,7 @@ export const useWallet = (chainId, userAddress) => {
externalUrl: "https://ghostchain.io/wp-content/uploads/2025/03/sGHST.svg", externalUrl: "https://ghostchain.io/wp-content/uploads/2025/03/sGHST.svg",
}, },
ghst: { ghst: {
symbol: ghstSymbol, symbol: "GHST",
address: ghstAddress, address: ghstAddress,
balance: ghstBalance, balance: ghstBalance,
price: ghstPrice, price: ghstPrice,
@ -219,7 +213,7 @@ export const useWallet = (chainId, userAddress) => {
}, },
daiFtso: { daiFtso: {
isPool: true, isPool: true,
symbol: lpDaiFtsoSymbol, symbol: "UNI-V2",
address: lpDaiFtsoBalanceAddress, address: lpDaiFtsoBalanceAddress,
balance: lpDaiFtsoBalance, balance: lpDaiFtsoBalance,
price: lpDaiFtsoPrice, price: lpDaiFtsoPrice,
@ -254,8 +248,8 @@ export const Tokens = ({ address, tokens, onClose }) => {
return ( return (
<> <>
{alwaysShowTokens.map((token, i) => ( {alwaysShowTokens.map(token => (
<Token key={i} {...tokenProps(token)} /> <Token key={token.symbol} {...tokenProps(token)} />
))} ))}
</> </>
); );

View File

@ -6,6 +6,7 @@ export const config = createConfig({
transports: { transports: {
[sepolia.id]: fallback([ [sepolia.id]: fallback([
http('https://ethereum-sepolia-rpc.publicnode.com'), http('https://ethereum-sepolia-rpc.publicnode.com'),
http('https://rpc-sepolia.rockx.com/'),
http('https://1rpc.io/sepolia'), http('https://1rpc.io/sepolia'),
http('https://eth-sepolia.public.blastapi.io'), http('https://eth-sepolia.public.blastapi.io'),
http('https://0xrpc.io/sep'), http('https://0xrpc.io/sep'),

View File

@ -1,32 +1,32 @@
import { NetworkId } from "../constants"; import { NetworkId } from "../constants";
export const STAKING_ADDRESSES = { export const STAKING_ADDRESSES = {
[NetworkId.TESTNET_SEPOLIA]: "0xd90E63E88282596E1ea33765b41Ba3d650f4aD52", [NetworkId.TESTNET_SEPOLIA]: "0xb22Ad3b4a23EaEA8c06CD151D7C0e3758d0FB580",
[NetworkId.TESTNET_HOODI]: "0x25F62eDc6C89FF84E957C22336A35d2dfc861a86", [NetworkId.TESTNET_HOODI]: "0x25F62eDc6C89FF84E957C22336A35d2dfc861a86",
}; };
export const BOND_DEPOSITORY_ADDRESSES = { export const BOND_DEPOSITORY_ADDRESSES = {
[NetworkId.TESTNET_SEPOLIA]: "0xdcE486113280e49ca2fB200258E5Ee1B2D21D495", [NetworkId.TESTNET_SEPOLIA]: "0x8773AC3258b31D3ACfc99Ffd13768ccB170fcF9f",
[NetworkId.TESTNET_HOODI]: "0x6Ad50B1E293E68B2fC230c576220a93A9D311571", [NetworkId.TESTNET_HOODI]: "0x6Ad50B1E293E68B2fC230c576220a93A9D311571",
}; };
export const DAO_TREASURY_ADDRESSES = { export const DAO_TREASURY_ADDRESSES = {
[NetworkId.TESTNET_SEPOLIA]: "0x93dd30f819403710de7933B79A74C4A42438458D", [NetworkId.TESTNET_SEPOLIA]: "0x2AAd1EA51044e69756880f580C13a92D910af238",
[NetworkId.TESTNET_HOODI]: "0x1a1b29b18f714fac9dDabEf530dFc4f85b56A6e8", [NetworkId.TESTNET_HOODI]: "0x1a1b29b18f714fac9dDabEf530dFc4f85b56A6e8",
}; };
export const FTSO_DAI_LP_ADDRESSES = { export const FTSO_DAI_LP_ADDRESSES = {
[NetworkId.TESTNET_SEPOLIA]: "0x1394dC3f7bABaa2F0CA80353648087DAB1BF3fd6", [NetworkId.TESTNET_SEPOLIA]: "0x64B19626bd074cf7B1019798846c363bbA8A0d53",
[NetworkId.TESTNET_HOODI]: "0xf7B2d44209E70782d93A70F7D8eC50010dF7ae50", [NetworkId.TESTNET_HOODI]: "0xf7B2d44209E70782d93A70F7D8eC50010dF7ae50", // TBD
}; };
export const FTSO_STNK_LP_ADDRESSES = { export const FTSO_STNK_LP_ADDRESSES = {
[NetworkId.TESTNET_SEPOLIA]: "0x29965676fc00C3eA9717B2A02739d294399a382e",
[NetworkId.TESTNET_SEPOLIA]: "0x0000000000000000000000000000000000000000", // TBD [NetworkId.TESTNET_SEPOLIA]: "0x0000000000000000000000000000000000000000", // TBD
[NetworkId.TESTNET_SEPOLIA]: "0x0000000000000000000000000000000000000000",
} }
export const DAI_ADDRESSES = { export const DAI_ADDRESSES = {
[NetworkId.TESTNET_SEPOLIA]: "0x5f63a27a9214a0352F2EF8dAF1eD4974d713192B", [NetworkId.TESTNET_SEPOLIA]: "0xc7Afd3bC4c74f6E07880447b1759d5d639F2525F",
[NetworkId.TESTNET_HOODI]: "0x80c6676c334BCcE60b3CC852085B72143379CE58", [NetworkId.TESTNET_HOODI]: "0x80c6676c334BCcE60b3CC852085B72143379CE58",
}; };
@ -36,39 +36,35 @@ export const WETH_ADDRESSES = {
}; };
export const GHST_ADDRESSES = { export const GHST_ADDRESSES = {
[NetworkId.TESTNET_SEPOLIA]: "0xdf2e5306A3dCcfA4e21bbF4226C17Ff5B008dDC4", [NetworkId.TESTNET_SEPOLIA]: "0x4643076087234d9B81974beF1eC9c25F3A0202B9",
[NetworkId.TESTNET_HOODI]: "0xE98f7426457E6533B206e91B7EcA97aa8A258B46", [NetworkId.TESTNET_HOODI]: "0xE98f7426457E6533B206e91B7EcA97aa8A258B46",
}; };
export const STNK_ADDRESSES = { export const STNK_ADDRESSES = {
[NetworkId.TESTNET_SEPOLIA]: "0x02C296A27eA779d5a16F934337c12062C5E3c0D9", [NetworkId.TESTNET_SEPOLIA]: "0x84060da636f5a83f2668ad238f09f8c667a1ec8b",
[NetworkId.TESTNET_HOODI]: "0xF07e9303A9f16Afd82f4f57Fd6fca68Aa0AB6D7F", [NetworkId.TESTNET_HOODI]: "0xF07e9303A9f16Afd82f4f57Fd6fca68Aa0AB6D7F",
}; };
export const FTSO_ADDRESSES = { export const FTSO_ADDRESSES = {
[NetworkId.TESTNET_SEPOLIA]: "0xcFedFFEB3FdeCd2196820Ba3b71f3F84A1255f93", [NetworkId.TESTNET_SEPOLIA]: "0x0eF2E888710E9f1d5E734f9ce30FAD40c832D5F3",
[NetworkId.TESTNET_HOODI]: "0xb184e423811b644A1924334E63985c259F5D0033", [NetworkId.TESTNET_HOODI]: "0xb184e423811b644A1924334E63985c259F5D0033",
}; };
export const DISTRIBUTOR_ADDRESSES = { export const DISTRIBUTOR_ADDRESSES = {
[NetworkId.TESTNET_SEPOLIA]: "0x8fbF8eB4Fcd451EF62Aee33508D46FE120963194", [NetworkId.TESTNET_SEPOLIA]: "0xE433D078a555163dC6B53968E72418B6a1618f04",
[NetworkId.TESTNET_HOODI]: "0xdF49dC81c457c6f92e26cf6d686C7a8715255842", [NetworkId.TESTNET_HOODI]: "0xdF49dC81c457c6f92e26cf6d686C7a8715255842",
}; };
export const GHOST_GOVERNANCE_ADDRESSES = { export const GHOST_GOVERNANCE_ADDRESSES = {
[NetworkId.TESTNET_SEPOLIA]: "0xDab0c51918E6990d8763FAC8a04AE159e44e0c4f", [NetworkId.TESTNET_SEPOLIA]: "0xD40E6442Ee01c234CD8AaF335122CfbB2aec8548",
[NetworkId.TESTNET_HOODI]: "0x1B96B792840d4d19d5097ee007392Ed4d851e64F", [NetworkId.TESTNET_HOODI]: "0x1B96B792840d4d19d5097ee007392Ed4d851e64F",
}; };
export const BONDING_CALCULATOR_ADDRESSES = { export const BONDING_CALCULATOR_ADDRESSES = {
[NetworkId.TESTNET_SEPOLIA]: "0x4896bFc6256A57Df826d7144E48c9633d51d6319", [NetworkId.TESTNET_SEPOLIA]: "0x29a6bb5De7a1049632E107544CaEF05e518451e7",
[NetworkId.TESTNET_HOODI]: "0x2635d526Ad24b98082563937f7b996075052c6Fd", [NetworkId.TESTNET_HOODI]: "0x2635d526Ad24b98082563937f7b996075052c6Fd",
} }
export const GATEKEEPER_ADDRESSES = {
[NetworkId.TESTNET_SEPOLIA]: "0xc85129A097773B7F8970a7364c928C05f265E6A1",
}
export const UNISWAP_V2_ROUTER = { export const UNISWAP_V2_ROUTER = {
[NetworkId.TESTNET_SEPOLIA]: "0xee567fe1712faf6149d80da1e6934e354124cfe3", [NetworkId.TESTNET_SEPOLIA]: "0xee567fe1712faf6149d80da1e6934e354124cfe3",
[NetworkId.TESTNET_HOODI]: "0xD41daF947c6FFEf344754B99ad09466FBCBb7583", [NetworkId.TESTNET_HOODI]: "0xD41daF947c6FFEf344754B99ad09466FBCBb7583",

View File

@ -17,7 +17,6 @@ import { ClaimBonds } from "./components/ClaimBonds";
import { useLiveBonds } from "../../hooks/bonds"; import { useLiveBonds } from "../../hooks/bonds";
import { useTotalReserves } from "../../hooks/treasury"; import { useTotalReserves } from "../../hooks/treasury";
import { useFtsoPrice } from "../../hooks/prices"; import { useFtsoPrice } from "../../hooks/prices";
import { useTokenSymbol } from "../../hooks/tokens";
const Bonds = ({ chainId, address, connect }) => { const Bonds = ({ chainId, address, connect }) => {
const [isZoomed] = useState(false); const [isZoomed] = useState(false);
@ -35,8 +34,6 @@ const Bonds = ({ chainId, address, connect }) => {
const totalReserves = useTotalReserves(chainId); const totalReserves = useTotalReserves(chainId);
const ftsoPrice = useFtsoPrice(chainId); const ftsoPrice = useFtsoPrice(chainId);
const { symbol: ftsoSymbol } = useTokenSymbol(chainId, "FTSO");
useEffect(() => { useEffect(() => {
const interval = setInterval(() => { const interval = setInterval(() => {
const date = Math.round(Date.now() / 1000); const date = Math.round(Date.now() / 1000);
@ -47,7 +44,7 @@ const Bonds = ({ chainId, address, connect }) => {
return ( return (
<Box> <Box>
<PageTitle name={"Protocol Bonding"} subtitle={`Buy ${ftsoSymbol} from the protocol at a discount`} /> <PageTitle name={"Protocol Bonding"} subtitle="Buy FTSO from the protocol at a discount" />
<Container <Container
style={{ style={{
paddingLeft: isSmallScreen || isVerySmallScreen ? "0" : "3.3rem", paddingLeft: isSmallScreen || isVerySmallScreen ? "0" : "3.3rem",
@ -67,7 +64,7 @@ const Bonds = ({ chainId, address, connect }) => {
isLoading={false} isLoading={false}
/> />
<Metric <Metric
label={`${ftsoSymbol} price`} label={`FTSO price`}
metric={formatCurrency(ftsoPrice, 2)} metric={formatCurrency(ftsoPrice, 2)}
isLoading={false} isLoading={false}
/> />

View File

@ -9,7 +9,7 @@ const BondInfoText = () => {
fontSize="0.875em" fontSize="0.875em"
lineHeight="15px" lineHeight="15px"
> >
Important: Bonding is the act of selling naked assets or liquidity tokens for ghostDAO native token at a discount. Important: Bonding is the act of selling naked assets such as gDAI (reserve bonds) or liquidity tokens such as gDAI-FTSO SLP (liquidity bonds) for FTSO at a discount.
&nbsp;<Link &nbsp;<Link
color={theme.colors.primary[300]} color={theme.colors.primary[300]}
href="https://ghostchain.io/ghostdao_litepaper" href="https://ghostchain.io/ghostdao_litepaper"

View File

@ -37,9 +37,6 @@ const BondInputArea = ({
const { currentIndex } = useCurrentIndex(chainId); const { currentIndex } = useCurrentIndex(chainId);
const { balance } = useBalance(chainId, bond.quoteToken.quoteTokenAddress, address); const { balance } = useBalance(chainId, bond.quoteToken.quoteTokenAddress, address);
const { symbol: ftsoSymbol } = useTokenSymbol(chainId, "FTSO");
const { symbol: ghstSymbol } = useTokenSymbol(chainId, "GHST");
const [amount, setAmount] = useState(""); const [amount, setAmount] = useState("");
const [checked, setChecked] = useState(false); const [checked, setChecked] = useState(false);
const [confirmOpen, setConfirmOpen] = useState(false); const [confirmOpen, setConfirmOpen] = useState(false);
@ -167,11 +164,11 @@ const BondInputArea = ({
title={"You Will Get"} title={"You Will Get"}
balance={ balance={
<span> <span>
{formatCurrency(amountInBaseToken, formatDecimals, ftsoSymbol)} {formatCurrency(amountInBaseToken, formatDecimals, "FTSO")}
{" "} {" "}
{!!currentIndex && ( {!!currentIndex && (
<span> <span>
({formatCurrency(amountInBaseToken.div(currentIndex), formatDecimals, ghstSymbol)}) ({formatCurrency(amountInBaseToken.div(currentIndex), formatDecimals, "GHST")})
</span> </span>
)} )}
</span> </span>
@ -185,8 +182,8 @@ const BondInputArea = ({
balance={ balance={
<span> <span>
{bond.baseToken.tokenAddress.toUpperCase() === bond.quoteToken.quoteTokenAddress.toUpperCase() {bond.baseToken.tokenAddress.toUpperCase() === bond.quoteToken.quoteTokenAddress.toUpperCase()
? `${formatCurrency(baseTokenString, formatDecimals, ftsoSymbol)}` ? `${formatCurrency(baseTokenString, formatDecimals, "FTSO")}`
: `${formatCurrency(baseTokenString, formatDecimals, ftsoSymbol)} (≈${formatCurrency(baseTokenString.div(currentIndex), formatDecimals, ghstSymbol)})`} : `${formatCurrency(baseTokenString, formatDecimals, "FTSO")} (≈${formatCurrency(baseTokenString.div(currentIndex), formatDecimals, "GHST")})`}
</span> </span>
} }
/> />
@ -194,7 +191,7 @@ const BondInputArea = ({
<DataRow <DataRow
title="Discount" title="Discount"
balance={<BondDiscount discount={bond.discount} textOnly />} balance={<BondDiscount discount={bond.discount} textOnly />}
tooltip={`The bond discount is the percentage difference between ${ftsoSymbol} market value and the bond's price`} tooltip="The bond discount is the percentage difference between FTSO market value and the bond's price"
/> />
<DataRow <DataRow

View File

@ -170,7 +170,7 @@ const payoutTokenCapacity = (bond) => {
const payoutTokenCapacity = bond.maxPayout.inBaseToken.lt(bond.capacity.inBaseToken) const payoutTokenCapacity = bond.maxPayout.inBaseToken.lt(bond.capacity.inBaseToken)
? bond.maxPayout.inBaseToken ? bond.maxPayout.inBaseToken
: bond.capacity.inBaseToken; : bond.capacity.inBaseToken;
return `${formatNumber(payoutTokenCapacity, 4)} ${bond.baseToken.name}`; return `${formatNumber(payoutTokenCapacity, 4)} FTSO`;
}; };
const BondRow = ({ bond, secondsTo }) => { const BondRow = ({ bond, secondsTo }) => {

View File

@ -19,7 +19,6 @@ import { formatCurrency } from "../../../helpers";
import { useCurrentIndex, useEpoch, useWarmupLength, useWarmupInfo } from "../../../hooks/staking"; import { useCurrentIndex, useEpoch, useWarmupLength, useWarmupInfo } from "../../../hooks/staking";
import { useNotes, redeem } from "../../../hooks/bonds"; import { useNotes, redeem } from "../../../hooks/bonds";
import { useTokenSymbol } from "../../../hooks/tokens";
export const ClaimBonds = ({ chainId, address, secondsTo }) => { export const ClaimBonds = ({ chainId, address, secondsTo }) => {
const isSmallScreen = useScreenSize("md"); const isSmallScreen = useScreenSize("md");
@ -38,10 +37,6 @@ export const ClaimBonds = ({ chainId, address, secondsTo }) => {
const { currentIndex, refetch: currentIndexRefetch } = useCurrentIndex(chainId); const { currentIndex, refetch: currentIndexRefetch } = useCurrentIndex(chainId);
const { notes, refetch: notesRefetch } = useNotes(chainId, address); const { notes, refetch: notesRefetch } = useNotes(chainId, address);
const { symbol: ftsoSymbol } = useTokenSymbol(chainId, "FTSO");
const { symbol: stnkSymbol } = useTokenSymbol(chainId, "STNK");
const { symbol: ghstSymbol } = useTokenSymbol(chainId, "GHST");
if (!notes || notes.length === 0) return null; if (!notes || notes.length === 0) return null;
const totalClaimableBalance = new DecimalBigNumber( const totalClaimableBalance = new DecimalBigNumber(
@ -96,8 +91,8 @@ export const ClaimBonds = ({ chainId, address, secondsTo }) => {
onChange={(_, view) => setIsPayoutGhstInner(view === 1)} onChange={(_, view) => setIsPayoutGhstInner(view === 1)}
TabIndicatorProps={{ style: { display: "none" } }} TabIndicatorProps={{ style: { display: "none" } }}
> >
<Tab aria-label="payout-stnk-button" label={stnkSymbol} style={{ fontSize: "1rem" }} /> <Tab aria-label="payout-stnk-button" label="STNK" style={{ fontSize: "1rem" }} />
<Tab aria-label="payout-ghst-button" label={ghstSymbol} style={{ fontSize: "1rem" }} /> <Tab aria-label="payout-ghst-button" label="GHST" style={{ fontSize: "1rem" }} />
</Tabs> </Tabs>
</Box> </Box>
@ -110,8 +105,8 @@ export const ClaimBonds = ({ chainId, address, secondsTo }) => {
<Box mt="4px" mb="8px"> <Box mt="4px" mb="8px">
<Typography variant="h4" align="center"> <Typography variant="h4" align="center">
{isPayoutGhst {isPayoutGhst
? formatCurrency(totalClaimableBalance, 5, ghstSymbol) ? formatCurrency(totalClaimableBalance, 5, "GHST")
: formatCurrency(currentIndex.mul(totalClaimableBalance), 5, stnkSymbol) : formatCurrency(currentIndex.mul(totalClaimableBalance), 5, "STNK")
} }
</Typography> </Typography>
</Box> </Box>
@ -157,8 +152,8 @@ export const ClaimBonds = ({ chainId, address, secondsTo }) => {
<Typography>Payout</Typography> <Typography>Payout</Typography>
<Typography> <Typography>
{isPayoutGhst {isPayoutGhst
? formatCurrency(note.payout, 5, ghstSymbol) ? formatCurrency(note.payout, 5, "GHST")
: formatCurrency(currentIndex.mul(note.payout), 5, stnkSymbol) : formatCurrency(currentIndex.mul(note.payout), 5, "STNK")
} }
</Typography> </Typography>
</Box> </Box>
@ -213,8 +208,8 @@ export const ClaimBonds = ({ chainId, address, secondsTo }) => {
<TableCell style={{ padding: "8px 0" }}> <TableCell style={{ padding: "8px 0" }}>
<Typography> <Typography>
{isPayoutGhst {isPayoutGhst
? formatCurrency(note.payout, 5, ghstSymbol) ? formatCurrency(note.payout, 5, "GHST")
: formatCurrency(currentIndex.mul(note.payout), 5, stnkSymbol) : formatCurrency(currentIndex.mul(note.payout), 5, "STNK")
} }
</Typography> </Typography>
</TableCell> </TableCell>

View File

@ -1,662 +0,0 @@
import { useEffect, useState, useMemo, useCallback } from "react";
import {
Box,
Container,
Typography,
Link,
Table,
TableBody,
TableCell,
TableHead,
TableRow,
TableContainer,
useMediaQuery,
useTheme
} from "@mui/material";
import { ss58Decode } from "@polkadot-labs/hdkd-helpers";
import { toHex } from "@polkadot-api/utils";
import { useBlockNumber, useTransactionConfirmations } from "wagmi";
import PendingActionsIcon from '@mui/icons-material/PendingActions';
import PublicIcon from '@mui/icons-material/Public';
import ArrowRightIcon from '@mui/icons-material/ArrowRight';
import HourglassBottomIcon from '@mui/icons-material/HourglassBottom';
import ThumbUpIcon from '@mui/icons-material/ThumbUp';
import ThumbDownAltIcon from '@mui/icons-material/ThumbDownAlt';
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
import CheckIcon from '@mui/icons-material/Check';
import PageTitle from "../../components/PageTitle/PageTitle";
import Paper from "../../components/Paper/Paper";
import SwapCard from "../../components/Swap/SwapCard";
import SwapCollection from "../../components/Swap/SwapCollection";
import TokenStack from "../../components/TokenStack/TokenStack";
import GhostStyledIcon from "../../components/Icon/GhostIcon";
import Modal from "../../components/Modal/Modal";
import { PrimaryButton } from "../../components/Button";
import { GATEKEEPER_ADDRESSES } from "../../constants/addresses";
import { DecimalBigNumber } from "../../helpers/DecimalBigNumber";
import { formatCurrency } from "../../helpers";
import { useTokenSymbol, useBalance } from "../../hooks/tokens";
import { useGatekeeperAddress, ghost } from "../../hooks/staking";
const STORAGE_PREFIX = "storedTransactions"
const Bridge = ({ chainId, address, config, connect }) => {
const theme = useTheme();
const isSmallScreen = useMediaQuery("(max-width: 650px)");
const isSemiSmallScreen = useMediaQuery("(max-width: 480px)");
const isVerySmallScreen = useMediaQuery("(max-width: 379px)");
const [isPending, setIsPending] = useState(false);
const [bridgeAction, setBridgeAction] = useState(true);
const [activeTxIndex, setActiveTxIndex] = useState(-1);
const [txStep, setTxStep] = useState(0);
const [receiver, setReceiver] = useState("");
const [convertedReceiver, setConvertedReceiver] = useState(undefined);
const [amount, setAmount] = useState("");
// ReceivedClaps && ApplausesForTransaction
// session_index
// transaction_hash
// keccak256(receiver, amount, chain_id)
// const initialStoredTransactions = sessionStorage.getItem(STORAGE_PREFIX);
const initialStoredTransactions = JSON.stringify([
{
sessionIndex: 23,
transactionHash: "0x11111111111111111",
receiver: "sfAasdadasasads",
amount: "2312323232223232",
chainId: 11155111,
timestamp: Date.now()
},
{
sessionIndex: 23,
transactionHash: "0x2222222222222222222",
receiver: "sfAasdadasasads",
amount: "1122232232",
chainId: 1,
timestamp: Date.now()
},
{
sessionIndex: 24,
transactionHash: "0x333333333333333333",
receiver: "sfAasdadasasads",
amount: "99999999999999992",
chainId: 11155111,
timestamp: Date.now()
},
{
sessionIndex: 23,
transactionHash: "0x4444444444444444444",
receiver: "sfAasdadasasads",
amount: "2312323232223232",
chainId: 11155111,
timestamp: Date.now()
},
{
sessionIndex: 23,
transactionHash: "0x555555555555555555555",
receiver: "sfAasdadasasads",
amount: "1122232232",
chainId: 1,
timestamp: Date.now()
},
{
sessionIndex: 24,
transactionHash: "0x66666666666666666666666666",
receiver: "sfAasdadasasads",
amount: "99999999999999992",
chainId: 11155111,
timestamp: Date.now()
},
{
sessionIndex: 23,
transactionHash: "0x77777777777777777777777777",
receiver: "sfAasdadasasads",
amount: "2312323232223232",
chainId: 11155111,
timestamp: Date.now()
},
{
sessionIndex: 23,
transactionHash: "0x888888888888888888888888888",
receiver: "sfAasdadasasads",
amount: "1122232232",
chainId: 1,
timestamp: Date.now()
},
{
sessionIndex: 24,
transactionHash: "0x999999999999999999999",
receiver: "sfAasdadasasads",
amount: "99999999999999992",
chainId: 11155111,
timestamp: Date.now()
},
{
sessionIndex: 23,
transactionHash: "0x10101010101010101010",
receiver: "sfAasdadasasads",
amount: "2312323232223232",
chainId: 11155111,
timestamp: Date.now()
},
{
sessionIndex: 23,
transactionHash: "0x12121212121212212",
receiver: "sfAasdadasasads",
amount: "1122232232",
chainId: 1,
timestamp: Date.now()
},
{
sessionIndex: 24,
transactionHash: "0x1313131313131313131",
receiver: "sfAasdadasasads",
amount: "99999999999999992",
chainId: 11155111,
timestamp: Date.now()
}
]);
const [storedTransactions, setStoredTransactions] = useState(
initialStoredTransactions ? JSON.parse(initialStoredTransactions) : []
);
const incomingCommission = new DecimalBigNumber(69n, 100);
const validators = ["first", "second", "third"];
const clappedValidators = 1;
const { data: blockNumber } = useBlockNumber({ watch: true });
// const { data: txtx } = useTransactionConfirmations({
// hash: "0xdb30adfa3bfc58539bc3a9a92f0dcace8f251af90f8a4f525b57d95d28103afc",
// refetchInterval: 5000
// });
// console.log(txtx)
const { gatekeeperAddress } = useGatekeeperAddress(chainId);
const { symbol: ghstSymbol } = useTokenSymbol(chainId, "GHST");
const {
balance: ghstBalance,
refetch: ghstBalanceRefetch
} = useBalance(chainId, "GHST", address);
useEffect(() => {
try {
const [publicKey, prefix] = ss58Decode(receiver);
if (prefix !== 1995 && prefix !== 1996) {
throw new Error("bad prefix");
}
setConvertedReceiver(toHex(publicKey));
} catch {
setConvertedReceiver(undefined);
}
}, [receiver])
const chainExplorerUrl = useMemo(() => {
const client = config?.getClient();
return client?.chain?.blockExplorers?.default?.url;
}, [config]);
const chainName = useMemo(() => {
const client = config?.getClient();
return client?.chain?.name;
}, [config]);
const currentRecord = useMemo(() => {
if (activeTxIndex === -1) return undefined
return storedTransactions.at(activeTxIndex)
}, [activeTxIndex, storedTransactions]);
const gatekeeperAddressEmpty = useMemo(() => {
if (gatekeeperAddress === "0x0000000000000000000000000000000000000000") {
return true;
}
return false;
}, [gatekeeperAddress]);
const preparedAmount = useMemo(() => {
try {
return BigInt(parseFloat(amount) * Math.pow(10, 18));
} catch {
return 0n;
}
}, [amount])
const filteredStoredTransactions = useMemo(() => {
return storedTransactions.filter(obj => obj.chainId === chainId);
}, [storedTransactions, chainId]);
const removeStoredRecord = useCallback(() => {
const newStoredTransactions = storedTransactions.filter((_, index) => index !== activeTxIndex)
setStoredTransactions(newStoredTransactions);
sessionStorage.setItem(STORAGE_PREFIX, JSON.stringify(newStoredTransactions));
setActiveTxIndex(-1);
}, [storedTransactions, activeTxIndex, setStoredTransactions, setActiveTxIndex]);
const handleMouseEnter = (index) => {
setTxStep(index);
}
const ghostOrConnect = async () => {
if (address === "") {
connect();
} else {
setIsPending(true);
const txHash = await ghost(chainId, address, convertedReceiver, preparedAmount);
await ghstBalanceRefetch();
setReceiver("");
setAmount("");
setIsPending(false);
}
}
return (
<Box height="calc(100vh - 43px)">
<PageTitle name="GHOST Bridge" subtitle="The only pure Web3 decentralized bridge." />
<Container
style={{
paddingLeft: isSmallScreen || isVerySmallScreen ? "0" : "3.3rem",
paddingRight: isSmallScreen || isVerySmallScreen ? "0" : "3.3rem",
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "calc(100vh - 153px)"
}}
>
<Modal
data-testid="transaction-details-modal"
maxWidth="476px"
headerContent={
<Box display="flex" flexDirection="row">
<Typography variant="h5">
TX Hash&nbsp;
<Link
sx={{
margin: "0px",
font: "inherit",
letterSpacing: "inherit",
textDecoration: "underline",
color: theme.colors.gray[10],
textUnderlineOffset: "0.23rem",
cursor: "pointer",
textDecorationThickness: "3px",
"&:hover": {
textDecoration: "underline",
}
}}
target="_blank"
rel="noopener noreferrer"
href={currentRecord
? `${chainExplorerUrl}/tx/${currentRecord.transactionHash}`
: ""
}
>
{currentRecord?.transactionHash.slice(0, 9)}...{currentRecord?.transactionHash.slice(-9)}
</Link>
</Typography>
</Box>
}
open={activeTxIndex > -1}
onClose={() => setActiveTxIndex(-1)}
minHeight={"100px"}
>
<Box display="flex" gap="1.5rem" flexDirection="column" marginTop=".8rem">
<Box display="flex" flexDirection="row" justifyContent="space-between" alignItems="center">
<Box
sx={{
transition: "all 0.2s ease",
transform: txStep === 0 && "scale(1.1)",
color: txStep === 0 && theme.colors.primary[300]
}}
width="120px"
display="flex"
flexDirection="column"
justifyContent="start"
alignItems="center"
onMouseEnter={() => handleMouseEnter(0)}
>
<GhostStyledIcon
sx={{ width: "35px", height: "35px" }}
viewBox="0 0 25 25"
component={HourglassBottomIcon}
/>
<Typography variant="caption">Finalization</Typography>
<Typography variant="caption">{blockNumber?.toString()} blocks left</Typography>
</Box>
<GhostStyledIcon
sx={{ transition: "all 0.2s ease", opacity: txStep < 1 && "0.2" }}
component={ArrowRightIcon}
/>
<Box
sx={{
transition: "all 0.2s ease",
opacity: txStep < 1 && "0.2",
transform: txStep === 1 && "scale(1.1)",
color: txStep === 1 && theme.colors.primary[300]
}}
width="120px"
display="flex"
flexDirection="column"
justifyContent="start"
alignItems="center"
onMouseEnter={() => handleMouseEnter(1)}
>
<Box display="flex" flexDirection="row" justifyContent="center" alignItems="center">
<GhostStyledIcon
sx={{ width: "35px", height: "35px" }}
viewBox="0 0 25 25"
component={ThumbUpIcon}
/>
<GhostStyledIcon
sx={{ width: "35px", height: "35px" }}
viewBox="0 0 25 25"
component={ThumbDownAltIcon}
/>
</Box>
<Box display="flex" flexDirection="column" justifyContent="center" alignItems="center">
<Typography variant="caption">Slow claps</Typography>
<Typography variant="caption">{clappedValidators} / {validators.length}</Typography>
</Box>
</Box>
<GhostStyledIcon
sx={{ transition: "all 0.2s ease", opacity: txStep < 2 && "0.2" }}
component={ArrowRightIcon}
/>
<Box
sx={{
transition: "all 0.2s ease",
opacity: txStep < 2 && "0.2",
transform: txStep === 2 && "scale(1.1)",
color: txStep === 2 && theme.colors.primary[300]
}}
width="120px"
display="flex"
flexDirection="column"
justifyContent="start"
alignItems="center"
onMouseEnter={() => handleMouseEnter(2)}
>
<GhostStyledIcon
sx={{ width: "35px", height: "35px" }}
viewBox="0 0 25 25"
component={CheckCircleIcon}
/>
<Typography variant="caption">Applaused</Typography>
<Typography variant="caption">Check Receiver</Typography>
</Box>
</Box>
<Box display="flex" flexDirection="column" gap="5px" padding="0.6rem 0">
<Box display="flex" flexDirection="row" justifyContent="space-between">
<Typography variant="body2">Session Index:</Typography>
<Typography variant="body2">{currentRecord?.sessionIndex}</Typography>
</Box>
<Box display="flex" flexDirection="row" justifyContent="space-between">
<Typography variant="body2">Receiver Address:</Typography>
<Typography variant="body2">{currentRecord?.receiver}</Typography>
</Box>
<Box display="flex" flexDirection="row" justifyContent="space-between">
<Typography variant="body2">Sent Amount:</Typography>
<Typography variant="body2">{formatCurrency(
new DecimalBigNumber(
BigInt(currentRecord ? currentRecord.amount : "0"),
18
).toString(), 9, ghstSymbol)
}</Typography>
</Box>
<Box display="flex" flexDirection="row" justifyContent="space-between">
<Typography variant="body2">Executed at:</Typography>
<Typography variant="body2">{
new Date(currentRecord ? currentRecord.timestamp : 0).toLocaleString('en-US')
}</Typography>
</Box>
</Box>
<Box display="flex" flexDirection="column" gap="5px">
<PrimaryButton
fullWidth
disabled={address === ""}
loading={false}
onClick={() => removeStoredRecord()}
>
Erase Record
</PrimaryButton>
<Typography variant="body2" sx={{ fontStyle: "italic" }}>
This will remove the transaction record from the session storage, but it will not cancel the bridge transaction.
</Typography>
</Box>
</Box>
</Modal>
<Box width="100%" maxWidth="476px" display="flex" alignItems="center" justifyContent="center" flexDirection="column">
<Paper
headerContent={
<Box alignItems="center" justifyContent="space-between" display="flex" width="100%">
<Typography variant="h4">{
bridgeAction
? `Bridge $${ghstSymbol}`
: "Transaction history"
}</Typography>
</Box>
}
topRight={
<GhostStyledIcon
component={bridgeAction ? PendingActionsIcon : PublicIcon}
viewBox="0 0 23 23"
style={{ display: "flex", alignItems: "center", cursor: "pointer" }}
onClick={() => setBridgeAction(!bridgeAction)}
/>
}
enableBackground
fullWidth
>
<Box minHeight="300px" display="flex" flexDirection="column" gap="5px">
{bridgeAction && (
<>
<SwapCollection
iconNotNeeded
UpperSwapCard={<SwapCard
id={`bridge-token-receiver`}
inputWidth={isVerySmallScreen ? "100px" : isSemiSmallScreen ? "180px" : "250px"}
value={receiver}
onChange={event => setReceiver(event.currentTarget.value)}
inputProps={{ "data-testid": "fromInput" }}
placeholder="Ghost address (sf prefixed)"
type="text"
/>}
LowerSwapCard={<SwapCard
id={`bridge-token-amount`}
inputWidth={isVerySmallScreen ? "100px" : isSemiSmallScreen ? "180px" : "250px"}
info={`${formatCurrency(ghstBalance.toString(), 4, ghstSymbol)}`}
value={amount}
onChange={event => setAmount(event.currentTarget.value)}
inputProps={{ "data-testid": "fromInput" }}
endString={"Max"}
endStringOnClick={() => setAmount(ghstBalance.toString())}
/>}
/>
<Box
mb="20px"
mt="20px"
flexDirection="column"
display="flex"
gap="10px"
justifyContent="space-between"
>
<Box display="flex" justifyContent={isVerySmallScreen ? "end" : "space-between"}>
{gatekeeperAddressEmpty && (
<Box maxWidth="416px" display="flex" justifyContent={isVerySmallScreen ? "end" : "space-between"}>
<Typography mr="10px" variant="body2" color="textSecondary">
<em>
There is no connected gatekeeper on {chainName} network. Propose gatekeeper on this network to make validators listen to it.
</em>
</Typography>
</Box>
)}
{!gatekeeperAddressEmpty && (
<>
{!isVerySmallScreen && <Typography fontSize="12px" lineHeight="15px">Gatekeeper:</Typography>}
<Link
fontSize="12px"
lineHeight="15px"
target="_blank"
rel="noopener noreferrer"
href={`${chainExplorerUrl}/token/${gatekeeperAddress}`}
>
{gatekeeperAddress.slice(0, 10) + "..." + gatekeeperAddress.slice(-8)}
</Link>
</>
)}
</Box>
{incomingCommission && validators?.length ? (
<Box maxWidth="416px" display="flex" justifyContent={isVerySmallScreen ? "end" : "space-between"}>
<Typography mr="10px" variant="body2" color="textSecondary">
<em>
GHOST Wallet is not detected on your browser. Download&nbsp;
<Link
target="_blank"
rel="noopener noreferrer"
href="https://git.ghostchain.io/ghostchain/ghost-extension-wallet/releases"
>
GHOST Wallet
</Link>&nbsp; to see full detalization for bridge transaction.
</em>
</Typography>
</Box>
)
: (
<Box display="flex" flexDirection="column" gap="0px">
<Box maxWidth="416px" display="flex" justifyContent={isVerySmallScreen ? "end" : "space-between"}>
{!isVerySmallScreen && <Typography fontSize="12px" lineHeight="15px">Est. Commission:</Typography>}
<Typography fontSize="12px" lineHeight="15px">unknown</Typography>
</Box>
<Box maxWidth="416px" display="flex" justifyContent={isVerySmallScreen ? "end" : "space-between"}>
{!isVerySmallScreen && <Typography fontSize="12px" lineHeight="15px">Number of validators:</Typography>}
<Typography fontSize="12px" lineHeight="15px">unknown</Typography>
</Box>
</Box>
)}
</Box>
<PrimaryButton
fullWidth
disabled={
address === "" || gatekeeperAddressEmpty || !convertedReceiver ||
preparedAmount === 0n || ghstBalance._value < preparedAmount
}
loading={isPending}
onClick={() => ghostOrConnect()}
>
{address === "" ?
"Connect"
:
"Bridge"
}
</PrimaryButton>
</>
)}
{!bridgeAction && (
<Box>
<Box display="grid" gridTemplateColumns="1fr 1fr 60px" sx={{ padding: "0.6rem", borderBottom: "1px solid" }}>
<Typography variant="subtitle1" sx={{ fontWeight: "bold" }}>Amount</Typography>
<Typography variant="subtitle1" sx={{ fontWeight: "bold" }}>Datetime</Typography>
<Typography variant="subtitle1" sx={{ justifySelf: "center", fontWeight: "bold" }}>Status</Typography>
</Box>
<Box display="flex" flexDirection="column" sx={{
height: "250px",
overflowY: "scroll",
"-ms-overflow-style": "thin !important",
"scrollbar-width": "thin !important",
}}>
{filteredStoredTransactions
.map((obj, idx) => (
<Box
display="grid"
gridTemplateColumns="1fr 1fr 60px"
sx={{
borderBottom: "1px solid",
padding: "0.6rem",
paddingTop: "1.2rem",
cursor: 'pointer',
'&:hover': {
background: theme.colors.paper.cardHover
}
}}
key={obj.transactionHash}
onClick={() => setActiveTxIndex(idx)}
>
<Box display="flex" flexDirection="column" justifyContent="center">
<Typography variant="subtitle2">
{formatCurrency(
new DecimalBigNumber(BigInt(obj.amount), 18).toString(),
3,
ghstSymbol
)}
</Typography>
</Box>
<Box display="flex" flexDirection="column">
<Typography variant="subtitle2">
{new Date(obj.timestamp).toLocaleDateString('en-US')}
</Typography>
<Typography variant="subtitle2">
{new Date(obj.timestamp).toLocaleTimeString('en-US')}
</Typography>
</Box>
<Box display="flex" justifyContent="center" alignItems="center">
<Box
display="flex"
justifyContent="center"
alignItems="center"
sx={{
width: "25px",
height: "25px",
background: idx % 2 === 0
? theme.colors.feedback.warning
: theme.colors.feedback.success,
borderRadius: "100%",
boxShadow: "0px 0px 1px black"
}}
>
{idx % 2 === 0 ?
<GhostStyledIcon
sx={{ width: "20px", height: "20px" }}
viewBox="0 0 25 25"
component={HourglassBottomIcon}
/>
:
<GhostStyledIcon
sx={{ width: "20px", height: "20px" }}
viewBox="0 0 25 25"
component={CheckIcon}
/>
}
</Box>
</Box>
</Box>
))}
</Box>
</Box>
)}
</Box>
</Paper>
</Box>
</Container>
</Box>
)
}
export default Bridge;

View File

@ -68,6 +68,9 @@ const PoolContainer = ({
); );
const onSwap = () => { const onSwap = () => {
// const oldAmountTop = amountTop;
// const oldAmountBottom = amountBottom;
// setAmountBottom(oldAmountTop);
setAmountTop(amountBottom); setAmountTop(amountBottom);
onCardsSwap(); onCardsSwap();
} }

View File

@ -42,11 +42,6 @@ const TokenModal = ({ chainId, account, listOpen, setListOpen, setTokenAddress }
const { balance: stnkBalance } = useBalance(chainId, "STNK", account); const { balance: stnkBalance } = useBalance(chainId, "STNK", account);
const { balance: ghstBalance } = useBalance(chainId, "GHST", account); const { balance: ghstBalance } = useBalance(chainId, "GHST", account);
const { symbol: daiSymbol } = useTokenSymbol(chainId, "GDAI");
const { symbol: ftsoSymbol } = useTokenSymbol(chainId, "FTSO");
const { symbol: stnkSymbol } = useTokenSymbol(chainId, "STNK");
const { symbol: ghstSymbol } = useTokenSymbol(chainId, "GHST");
const searchToken = useMemo(() => { const searchToken = useMemo(() => {
return [{ return [{
name: searchSymbol, name: searchSymbol,
@ -59,31 +54,31 @@ const TokenModal = ({ chainId, account, listOpen, setListOpen, setTokenAddress }
const knownTokens = useMemo(() => { const knownTokens = useMemo(() => {
return [ return [
{ {
name: daiSymbol, name: "gDAI",
icons: ["GDAI"], icons: ["GDAI"],
balance: daiBalance, balance: daiBalance,
address: DAI_ADDRESSES[chainId] address: DAI_ADDRESSES[chainId]
}, },
{ {
name: ftsoSymbol, name: "FTSO",
icons: ["FTSO"], icons: ["FTSO"],
balance: ftsoBalance, balance: ftsoBalance,
address: FTSO_ADDRESSES[chainId] address: FTSO_ADDRESSES[chainId]
}, },
{ {
name: stnkSymbol, name: "STNK",
icons: ["STNK"], icons: ["STNK"],
balance: stnkBalance, balance: stnkBalance,
address: STNK_ADDRESSES[chainId] address: STNK_ADDRESSES[chainId]
}, },
{ {
name: ghstSymbol, name: "GHST",
icons: ["GHST"], icons: ["GHST"],
balance: ghstBalance, balance: ghstBalance,
address: GHST_ADDRESSES[chainId] address: GHST_ADDRESSES[chainId]
} }
] ]
}, [daiSymbol, ftsoSymbol, stnkSymbol, ghstSymbol, daiBalance, ftsoBalance, stnkBalance, ghstBalance]); }, [daiBalance, ghstBalance, stnkBalance, ghstBalance]);
useEffect(() => { useEffect(() => {
if (isAddress(userInput)) { if (isAddress(userInput)) {

View File

@ -9,49 +9,33 @@ import Paper from "../../components/Paper/Paper";
import SwapCard from "../../components/Swap/SwapCard"; import SwapCard from "../../components/Swap/SwapCard";
import TokenStack from "../../components/TokenStack/TokenStack"; import TokenStack from "../../components/TokenStack/TokenStack";
import { PrimaryButton } from "../../components/Button"; import { PrimaryButton } from "../../components/Button";
import { Tab, Tabs } from "../../components/Tabs/Tabs";
import { DAI_ADDRESSES } from "../../constants/addresses"; import { DAI_ADDRESSES } from "../../constants/addresses";
import { DecimalBigNumber } from "../../helpers/DecimalBigNumber"; import { DecimalBigNumber } from "../../helpers/DecimalBigNumber";
import { formatCurrency, formatNumber } from "../../helpers"; import { formatCurrency, formatNumber } from "../../helpers";
import { import { useBalance as useTokenBalance, useConversionRate, mintDai } from "../../hooks/tokens";
useBalance as useTokenBalance,
useTokenSymbol,
useTotalSupply,
useConversionRate,
useAccumulatedDonation,
mintDai,
burnDai
} from "../../hooks/tokens";
const Faucet = ({ chainId, address, config, connect }) => { const Faucet = ({ chainId, address, config, connect }) => {
const isSmallScreen = useMediaQuery("(max-width: 650px)"); const isSmallScreen = useMediaQuery("(max-width: 650px)");
const isSemiSmallScreen = useMediaQuery("(max-width: 480px)"); const isSemiSmallScreen = useMediaQuery("(max-width: 480px)");
const isVerySmallScreen = useMediaQuery("(max-width: 379px)"); const isVerySmallScreen = useMediaQuery("(max-width: 379px)");
const [isMint, setIsMint] = useState(true); const daiConversionRate = useConversionRate(chainId, "GDAI");
const { balance: daiBalance, refetch: daiBalanceRefetch } = useTokenBalance(chainId, "GDAI", address);
const { data: nativeBalance, refetch: balanceRefetch } = useBalance({ address });
const [isPending, setIsPending] = useState(false); const [isPending, setIsPending] = useState(false);
const [balance, setBalance] = useState(new DecimalBigNumber(0, 0)); const [balance, setBalance] = useState(new DecimalBigNumber(0, 0));
const [amount, setAmount] = useState(""); const [amount, setAmount] = useState("");
const [faucetToken, setFaucetToken] = useState({
name: "",
address: "",
});
const [scanInfo, setScanInfo] = useState({ const [scanInfo, setScanInfo] = useState({
name: "", name: "",
url: "", url: "",
}); });
const [nativeInfo, setNativeInfo] = useState({
decimals: 18,
name: "",
symbol: "",
})
const daiConversionRate = useConversionRate(chainId, "GDAI");
const accumulatedDonation = useAccumulatedDonation(chainId, "GDAI");
const { balance: daiBalance, refetch: daiBalanceRefetch } = useTokenBalance(chainId, "GDAI", address);
const { data: nativeBalance, refetch: balanceRefetch } = useBalance({ address });
const { data: contractBalance, refetch: contractBalanceRefetch } = useBalance({ address: DAI_ADDRESSES[chainId] });
const { totalSupply: reserveTotalSupply, refetch: refetchReserveTotalSupply } = useTotalSupply(chainId, "GDAI");
const { symbol: faucetSymbol } = useTokenSymbol(chainId, "GDAI");
useEffect(() => { useEffect(() => {
ReactGA.send({ hitType: "pageview", page: "/faucet" }); ReactGA.send({ hitType: "pageview", page: "/faucet" });
@ -67,71 +51,44 @@ const Faucet = ({ chainId, address, config, connect }) => {
let scanName = ""; let scanName = "";
let scanUrl = ""; let scanUrl = "";
const tokenName = "gDAI";
const tokenAddress = DAI_ADDRESSES[chainId];
const client = config?.getClient(); const client = config?.getClient();
scanName = client?.chain?.blockExplorers?.default?.name; scanName = client?.chain?.blockExplorers?.default?.name;
scanUrl = client?.chain?.blockExplorers?.default?.url; scanUrl = client?.chain?.blockExplorers?.default?.url;
setFaucetToken({
name: tokenName,
address: tokenAddress,
});
setScanInfo({ setScanInfo({
name: scanName, name: scanName,
url: scanUrl, url: scanUrl,
}) })
setNativeInfo(client?.chain?.nativeCurrency)
}, [chainId]); }, [chainId]);
const changeIsMinted = (value) => {
if (accumulatedDonation) {
setAmount("");
setIsMint(value);
}
}
const preparedAmount = useMemo(() => { const preparedAmount = useMemo(() => {
if (address === "") new DecimalBigNumber("0", 0); if (address === "") new DecimalBigNumber("0", 0);
const decimals = isMint ? nativeInfo.decimals : 18; return new DecimalBigNumber(amount, 18);
return new DecimalBigNumber(amount, decimals); }, [amount, balance])
}, [amount, balance, nativeInfo])
const estimatedAmountIn = useMemo(() => { const estimatedAmount = useMemo(() => {
const rate = new DecimalBigNumber(daiConversionRate.toString(), 0); const rate = new DecimalBigNumber(daiConversionRate.toString(), 0);
const value = new DecimalBigNumber(amount, nativeInfo.decimals); const value = new DecimalBigNumber(amount, 18);
return value.mul(rate); return value.mul(rate);
}, [amount, daiConversionRate, nativeInfo]); }, [amount, daiConversionRate])
const contractBalanceFree = useMemo(() => { const mintOrConnect = async () => {
const realContractBalance = contractBalance ? contractBalance.value : 0n;
const preparedContractBalance = new DecimalBigNumber(realContractBalance, nativeInfo.decimals);
const preparedAccumulatedDonation = new DecimalBigNumber(
accumulatedDonation._value,
nativeInfo.decimals && 18
);
return preparedContractBalance.sub(preparedAccumulatedDonation);
}, [contractBalance, accumulatedDonation]);
const estimatedAmountOut = useMemo(() => {
const value = new DecimalBigNumber(amount, nativeInfo.decimals);
if (reserveTotalSupply._value > 0n) {
return value.mul(contractBalanceFree).div(reserveTotalSupply);
}
return new DecimalBigNumber(0n, nativeInfo.decimals);
}, [amount, contractBalanceFree, reserveTotalSupply, nativeInfo]);
const actionOrConnect = async () => {
if (address === "") { if (address === "") {
connect(); connect();
} else { } else {
setIsPending(true); setIsPending(true);
await mintDai(chainId, address, preparedAmount._value.toString());
if (isMint) {
await mintDai(chainId, address, preparedAmount._value.toString());
} else {
await burnDai(chainId, address, preparedAmount._value.toString());
}
await balanceRefetch(); await balanceRefetch();
await daiBalanceRefetch(); await daiBalanceRefetch();
await contractBalanceRefetch();
await refetchReserveTotalSupply();
setAmount(""); setAmount("");
setIsPending(false); setIsPending(false);
} }
@ -159,7 +116,7 @@ const Faucet = ({ chainId, address, config, connect }) => {
<meta name="twitter:image" content="https://ghostchain.io/wp-content/uploads/2025/03/ghostFaucet-Featured_Image.png" /> <meta name="twitter:image" content="https://ghostchain.io/wp-content/uploads/2025/03/ghostFaucet-Featured_Image.png" />
</Helmet> </Helmet>
<PageTitle name={`${faucetSymbol} Faucet`} subtitle={`Swap Sepolia ${nativeInfo.symbol} for ${faucetSymbol}.`} /> <PageTitle name={"gDAI Faucet"} subtitle="Swap Sepolia ETH for gDAI." />
<Container <Container
style={{ style={{
paddingLeft: isSmallScreen || isVerySmallScreen ? "0" : "3.3rem", paddingLeft: isSmallScreen || isVerySmallScreen ? "0" : "3.3rem",
@ -174,21 +131,10 @@ const Faucet = ({ chainId, address, config, connect }) => {
<Paper <Paper
headerContent={ headerContent={
<Box alignItems="center" justifyContent="space-between" display="flex" width="100%"> <Box alignItems="center" justifyContent="space-between" display="flex" width="100%">
<Tabs <Typography variant="h4">Get {faucetToken.name}</Typography>
centered
textColor="primary"
indicatorColor="primary"
value={isMint ? 0 : 1}
aria-label="Faucet menu"
onChange={(_, view) => changeIsMinted(view === 0)}
TabIndicatorProps={{ style: { display: "none" } }}
>
<Tab aria-label="faucet-mint-button" label="Mint" style={{ fontSize: "1.5rem" }} />
{accumulatedDonation && <Tab aria-label="faucet-burn-button" label="Burn" style={{ fontSize: "1.5rem" }} />}
</Tabs>
{!isSemiSmallScreen && <PrimaryButton {!isSemiSmallScreen && <PrimaryButton
variant="text" variant="text"
href={`${scanInfo.url}/token/${DAI_ADDRESSES[chainId]}`} href={`${scanInfo.url}/token/${faucetToken.address}`}
> >
Check on {scanInfo.name} Check on {scanInfo.name}
</PrimaryButton>} </PrimaryButton>}
@ -198,28 +144,16 @@ const Faucet = ({ chainId, address, config, connect }) => {
fullWidth fullWidth
> >
<Box> <Box>
{isMint && <SwapCard <SwapCard
id={`faucet-sepolia-eth`} id={`faucet-sepolia-eth`}
inputWidth={isVerySmallScreen ? "100px" : isSemiSmallScreen ? "180px" : "250px"} inputWidth={isVerySmallScreen ? "100px" : isSemiSmallScreen ? "180px" : "250px"}
tokenName={nativeInfo.symbol} tokenName={"ETH"}
token={<TokenStack tokens={[nativeInfo.symbol]} sx={{ fontSize: "21px" }} />} token={<TokenStack tokens={["ETH"]} sx={{ fontSize: "21px" }} />}
info={`${isSemiSmallScreen ? "" : "Balance: "}${formatCurrency(balance.toString(), 4, nativeInfo.symbol)}`} info={`${isSemiSmallScreen ? "" : "Balance: "}${formatCurrency(balance.toString(), 4, "ETH")}`}
value={amount} value={amount}
onChange={event => setAmount(event.currentTarget.value)} onChange={event => setAmount(event.currentTarget.value)}
inputProps={{ "data-testid": "fromInput" }} inputProps={{ "data-testid": "fromInput" }}
/>} />
{!isMint && <SwapCard
id={`faucet-sepolia-eth`}
inputWidth={isVerySmallScreen ? "100px" : isSemiSmallScreen ? "180px" : "250px"}
tokenName={faucetSymbol}
token={<TokenStack tokens={[faucetSymbol]} sx={{ fontSize: "21px" }} />}
info={`${formatCurrency(daiBalance.toString(), 4, faucetSymbol)}`}
value={amount}
onChange={event => setAmount(event.currentTarget.value)}
inputProps={{ "data-testid": "fromInput" }}
endString={"Max"}
endStringOnClick={() => setAmount(daiBalance.toString())}
/>}
<Box <Box
mb="20px" mb="20px"
mt="20px" mt="20px"
@ -227,56 +161,35 @@ const Faucet = ({ chainId, address, config, connect }) => {
display="flex" display="flex"
justifyContent="space-between" justifyContent="space-between"
> >
{isMint && ( <Box maxWidth="416px" display="flex" justifyContent={isVerySmallScreen ? "end" : "space-between"}>
<> {!isVerySmallScreen && <Typography fontSize="12px" lineHeight="15px">ETH multiplier:</Typography>}
<Box maxWidth="416px" display="flex" justifyContent={isVerySmallScreen ? "end" : "space-between"}> <Typography fontSize="12px" lineHeight="15px">{formatNumber(daiConversionRate, 2)}</Typography>
{!isVerySmallScreen && <Typography fontSize="12px" lineHeight="15px">{nativeInfo.symbol} multiplier:</Typography>} </Box>
<Typography fontSize="12px" lineHeight="15px">{formatNumber(daiConversionRate, 2)}</Typography> <Box maxWidth="416px" display="flex" justifyContent={isVerySmallScreen ? "end" : "space-between"}>
</Box> {!isVerySmallScreen && <Typography fontSize="12px" lineHeight="15px">You will get:</Typography>}
<Box maxWidth="416px" display="flex" justifyContent={isVerySmallScreen ? "end" : "space-between"}> <Typography fontSize="12px" lineHeight="15px">{formatCurrency(estimatedAmount, 5, faucetToken.name)}</Typography>
{!isVerySmallScreen && <Typography fontSize="12px" lineHeight="15px">You will get:</Typography>} </Box>
<Typography fontSize="12px" lineHeight="15px">{formatCurrency(estimatedAmountIn, 5, faucetSymbol)}</Typography> <Box display="flex" justifyContent={isVerySmallScreen ? "end" : "space-between"}>
</Box> {!isVerySmallScreen && <Typography fontSize="12px" lineHeight="15px">Your {faucetToken.name} balance:</Typography>}
<Box display="flex" justifyContent={isVerySmallScreen ? "end" : "space-between"}> <Typography fontSize="12px" lineHeight="15px">{formatCurrency(daiBalance, 5, faucetToken.name)}</Typography>
{!isVerySmallScreen && <Typography fontSize="12px" lineHeight="15px">Your {faucetSymbol} balance:</Typography>} </Box>
<Typography fontSize="12px" lineHeight="15px">{formatCurrency(daiBalance, 5, faucetSymbol)}</Typography>
</Box>
</>
)}
{!isMint && (
<>
<Box maxWidth="416px" display="flex" justifyContent={isVerySmallScreen ? "end" : "space-between"}>
{!isVerySmallScreen && <Typography fontSize="12px" lineHeight="15px">Accumulated {nativeInfo.symbol}:</Typography>}
<Typography fontSize="12px" lineHeight="15px">{formatCurrency(contractBalanceFree, 5, nativeInfo.symbol)}</Typography>
</Box>
<Box maxWidth="416px" display="flex" justifyContent={isVerySmallScreen ? "end" : "space-between"}>
{!isVerySmallScreen && <Typography fontSize="12px" lineHeight="15px">You will get:</Typography>}
<Typography fontSize="12px" lineHeight="15px">{formatCurrency(estimatedAmountOut, 5, nativeInfo.symbol)}</Typography>
</Box>
<Box display="flex" justifyContent={isVerySmallScreen ? "end" : "space-between"}>
{!isVerySmallScreen && <Typography fontSize="12px" lineHeight="15px">Your {nativeInfo.symbol} balance:</Typography>}
<Typography fontSize="12px" lineHeight="15px">{formatCurrency(balance, 5, nativeInfo.symbol)}</Typography>
</Box>
</>
)}
</Box> </Box>
<PrimaryButton <PrimaryButton
fullWidth fullWidth
disabled={ disabled={
address !== "" && ( address !== "" && (
preparedAmount?._value === 0n || preparedAmount?.eq(new DecimalBigNumber(0, 18)) ||
isPending || balance?.lt(preparedAmount) ||
(isMint && balance?.lt(preparedAmount)) || isPending
(!isMint && daiBalance?.lt(preparedAmount))
) )
} }
loading={isPending} loading={isPending}
onClick={() => actionOrConnect()} onClick={() => mintOrConnect()}
> >
{address === "" ? {address === "" ?
"Connect" "Connect"
: :
isMint ? "Mint" : "Burn" "Mint"
} }
</PrimaryButton> </PrimaryButton>
</Box> </Box>

View File

@ -28,39 +28,21 @@ const Stake = ({ chainId, address, isOpened, closeModal, connect }) => {
case (upperToken === "FTSO" && bottomToken === "STNK"): case (upperToken === "FTSO" && bottomToken === "STNK"):
setAction("STAKE") setAction("STAKE")
break; break;
case (upperToken === "eCSPR" && bottomToken === "sCSPR"):
setAction("STAKE")
break;
case (upperToken === "FTSO" && bottomToken === "GHST"): case (upperToken === "FTSO" && bottomToken === "GHST"):
setAction("STAKE") setAction("STAKE")
break; break;
case (upperToken === "eCSPR" && bottomToken === "CSPR"):
setAction("STAKE")
break;
case (upperToken === "STNK" && bottomToken === "FTSO"): case (upperToken === "STNK" && bottomToken === "FTSO"):
setAction("UNSTAKE") setAction("UNSTAKE")
break; break;
case (upperToken === "sCSPR" && bottomToken === "eCSPR"):
setAction("UNSTAKE")
break;
case (upperToken === "GHST" && bottomToken === "FTSO"): case (upperToken === "GHST" && bottomToken === "FTSO"):
setAction("UNSTAKE") setAction("UNSTAKE")
break; break;
case (upperToken === "CSPR" && bottomToken === "eCSPR"):
setAction("UNSTAKE")
break;
case (upperToken === "STNK" && bottomToken === "GHST"): case (upperToken === "STNK" && bottomToken === "GHST"):
setAction("WRAP") setAction("WRAP")
break; break;
case (upperToken === "sCSPR" && bottomToken === "CSPR"):
setAction("WRAP")
break;
case (upperToken === "GHST" && bottomToken === "STNK"): case (upperToken === "GHST" && bottomToken === "STNK"):
setAction("UNWRAP") setAction("UNWRAP")
break; break;
case (upperToken === "CSPR" && bottomToken === "sCSPR"):
setAction("UNWRAP")
break;
default: default:
setAction("STAKE") setAction("STAKE")
} }

View File

@ -16,7 +16,6 @@ import { ClaimsArea } from "./components/ClaimsArea";
import { Apy, CurrentIndex, TotalDeposit } from "./components/Metric"; import { Apy, CurrentIndex, TotalDeposit } from "./components/Metric";
import { useEpoch } from "../../hooks/staking"; import { useEpoch } from "../../hooks/staking";
import { useTokenSymbol } from "../../hooks/tokens";
export const StakeContainer = ({ chainId, address, connect }) => { export const StakeContainer = ({ chainId, address, connect }) => {
const [isModalOpened, handleModal] = useState(false); const [isModalOpened, handleModal] = useState(false);
@ -25,9 +24,6 @@ export const StakeContainer = ({ chainId, address, connect }) => {
const isSmallScreen = useMediaQuery("(max-width: 650px)"); const isSmallScreen = useMediaQuery("(max-width: 650px)");
const isVerySmallScreen = useMediaQuery("(max-width: 379px)"); const isVerySmallScreen = useMediaQuery("(max-width: 379px)");
const { symbol: ftsoSymbol } = useTokenSymbol(chainId, "FTSO");
const { symbol: stnkSymbol } = useTokenSymbol(chainId, "STNK");
const { epoch, refetch: refetchEpoch } = useEpoch(chainId); const { epoch, refetch: refetchEpoch } = useEpoch(chainId);
useEffect(() => { useEffect(() => {
@ -48,7 +44,7 @@ export const StakeContainer = ({ chainId, address, connect }) => {
return ( return (
<Box > <Box >
<PageTitle name="Protocol Staking" subtitle={`Stake your ${ftsoSymbol} to earn rebase yields`} /> <PageTitle name="Protocol Staking" subtitle="Stake your FTSO to earn rebase yields" />
<Container <Container
style={{ style={{
paddingLeft: isSmallScreen || isVerySmallScreen ? "0" : "3.3rem", paddingLeft: isSmallScreen || isVerySmallScreen ? "0" : "3.3rem",
@ -75,13 +71,13 @@ export const StakeContainer = ({ chainId, address, connect }) => {
> >
<Grid container spacing={1}> <Grid container spacing={1}>
<Grid item xs={isSmallScreen ? 12 : 4}> <Grid item xs={isSmallScreen ? 12 : 4}>
<Apy stnkSymbol={stnkSymbol} distribute={epoch.distribute} chainId={chainId} /> <Apy distribute={epoch.distribute} chainId={chainId} />
</Grid> </Grid>
<Grid item xs={isSmallScreen ? 12 : 4}> <Grid item xs={isSmallScreen ? 12 : 4}>
<TotalDeposit stnkSymbol={stnkSymbol} chainId={chainId} /> <TotalDeposit chainId={chainId} />
</Grid> </Grid>
<Grid item xs={isSmallScreen ? 12 : 4}> <Grid item xs={isSmallScreen ? 12 : 4}>
<CurrentIndex ftsoSymbol={ftsoSymbol} chainId={chainId} /> <CurrentIndex chainId={chainId} />
</Grid> </Grid>
</Grid> </Grid>

View File

@ -22,7 +22,7 @@ const ClaimConfirmationModal = (props) => {
await forfeit(props.chainId, props.receiver); await forfeit(props.chainId, props.receiver);
break; break;
case "CLAIM": case "CLAIM":
await claim(props.chainId, props.receiver, props.outputToken === "STNK" || props.outputToken === "sCSPR"); await claim(props.chainId, props.receiver, props.outputToken === "STNK");
break; break;
default: default:
console.log("Unknown action") console.log("Unknown action")
@ -55,7 +55,7 @@ const ClaimConfirmationModal = (props) => {
/> />
<Box display="flex" flexDirection="row" justifyContent="center"> <Box display="flex" flexDirection="row" justifyContent="center">
<Typography> <Typography>
{props.outputTokenName} {props.outputToken}
</Typography> </Typography>
</Box> </Box>
</Box> </Box>

View File

@ -28,7 +28,7 @@ import { prettifySecondsInDays } from "../../../helpers/timeUtil";
import { formatNumber } from "../../../helpers"; import { formatNumber } from "../../../helpers";
import { STAKING_ADDRESSES } from "../../../constants/addresses"; import { STAKING_ADDRESSES } from "../../../constants/addresses";
import { useCurrentIndex, useWarmupInfo } from "../../../hooks/staking"; import { useCurrentIndex, useWarmupInfo } from "../../../hooks/staking";
import { useBalanceForShares, useTokenSymbol } from "../../../hooks/tokens"; import { useBalanceForShares } from "../../../hooks/tokens";
import ClaimConfirmationModal from "./ClaimConfirmationModal"; import ClaimConfirmationModal from "./ClaimConfirmationModal";
@ -61,10 +61,6 @@ export const ClaimsArea = ({ chainId, address, epoch }) => {
const { currentIndex, refetch: currentIndexRefetch } = useCurrentIndex(chainId); const { currentIndex, refetch: currentIndexRefetch } = useCurrentIndex(chainId);
const { balanceForShares } = useBalanceForShares(chainId, "STNK", claim.shares); const { balanceForShares } = useBalanceForShares(chainId, "STNK", claim.shares);
const { symbol: ftsoSymbol } = useTokenSymbol(chainId, "FTSO");
const { symbol: stnkSymbol } = useTokenSymbol(chainId, "STNK");
const { symbol: ghstSymbol } = useTokenSymbol(chainId, "GHST");
const closeConfirmationModal = () => { const closeConfirmationModal = () => {
setConfirmationModalOpen(false); setConfirmationModalOpen(false);
claimRefetch(); claimRefetch();
@ -89,7 +85,6 @@ export const ClaimsArea = ({ chainId, address, epoch }) => {
receiver={address} receiver={address}
receiveAmount={claim.expiry > epoch.number ? claim.deposit : isPayoutGhst ? balanceForShares.div(currentIndex) : balanceForShares} receiveAmount={claim.expiry > epoch.number ? claim.deposit : isPayoutGhst ? balanceForShares.div(currentIndex) : balanceForShares}
outputToken={claim.expiry > epoch.number ? "FTSO" : isPayoutGhst ? "GHST" : "STNK"} outputToken={claim.expiry > epoch.number ? "FTSO" : isPayoutGhst ? "GHST" : "STNK"}
outputTokenName={claim.expiry > epoch.number ? ftsoSymbol : isPayoutGhst ? ghstSymbol : stnkSymbol}
action={claim.expiry > epoch.number ? "forfeit" : "claim"} action={claim.expiry > epoch.number ? "forfeit" : "claim"}
chainId={chainId} chainId={chainId}
/> />
@ -103,7 +98,7 @@ export const ClaimsArea = ({ chainId, address, epoch }) => {
justifyContent="space-between" justifyContent="space-between"
flexDirection={isSmallScreen ? "column" : "row"} flexDirection={isSmallScreen ? "column" : "row"}
> >
<Typography variant="h6">Your active {isPayoutGhst ? ghstSymbol : stnkSymbol} claim</Typography> <Typography variant="h6">Your active {isPayoutGhst ? "GHST" : "STNK"} claim</Typography>
<Tabs <Tabs
centered centered
textColor="primary" textColor="primary"
@ -113,8 +108,8 @@ export const ClaimsArea = ({ chainId, address, epoch }) => {
onChange={(_, view) => setIsPayoutGhstInner(view === 1)} onChange={(_, view) => setIsPayoutGhstInner(view === 1)}
TabIndicatorProps={{ style: { display: "none" } }} TabIndicatorProps={{ style: { display: "none" } }}
> >
<Tab aria-label="payout-stnk-button" label={stnkSymbol} style={{ fontSize: "1rem" }} /> <Tab aria-label="payout-stnk-button" label="STNK" style={{ fontSize: "1rem" }} />
<Tab aria-label="payout-ghst-button" label={ghstSymbol} style={{ fontSize: "1rem" }} /> <Tab aria-label="payout-ghst-button" label="GHST" style={{ fontSize: "1rem" }} />
</Tabs> </Tabs>
</Box> </Box>
} }
@ -129,8 +124,6 @@ export const ClaimsArea = ({ chainId, address, epoch }) => {
claim={claim} claim={claim}
epoch={epoch} epoch={epoch}
isClaimable={claim.expiry > epoch.number} isClaimable={claim.expiry > epoch.number}
stnkSymbol={stnkSymbol}
ghstSymbol={ghstSymbol}
/> />
) : ( ) : (
<Table> <Table>
@ -149,8 +142,6 @@ export const ClaimsArea = ({ chainId, address, epoch }) => {
claim={claim} claim={claim}
epoch={epoch} epoch={epoch}
isClaimable={claim.expiry > epoch.number} isClaimable={claim.expiry > epoch.number}
stnkSymbol={stnkSymbol}
ghstSymbol={ghstSymbol}
/> />
</Table> </Table>
@ -160,21 +151,21 @@ export const ClaimsArea = ({ chainId, address, epoch }) => {
); );
}; };
const ClaimInfo = ({ setConfirmationModalOpen, prepareBalance, claim, epoch, isClaimable, isPayoutGhst, stnkSymbol, ghstSymbol }) => { const ClaimInfo = ({ setConfirmationModalOpen, prepareBalance, claim, epoch, isClaimable, isPayoutGhst }) => {
return ( return (
<TableBody> <TableBody>
<TableRow> <TableRow>
<TableCell style={{ padding: "8px 8px 8px 0" }}> <TableCell style={{ padding: "8px 8px 8px 0" }}>
<Box display="flex" flexDirection="row" alignItems="center" style={{ whiteSpace: "nowrap" }}> <Box display="flex" flexDirection="row" alignItems="center" style={{ whiteSpace: "nowrap" }}>
<Token key={isPayoutGhst ? ghstSymbol : stnkSymbol} name={isPayoutGhst ? ghstSymbol : stnkSymbol} /> <Token key={isPayoutGhst ? "GHST" : "STNK"} name={isPayoutGhst ? "GHST" : "STNK"} />
<Box marginLeft="14px" marginRight="10px"> <Box marginLeft="14px" marginRight="10px">
<Typography>{isPayoutGhst ? ghstSymbol : stnkSymbol}</Typography> <Typography>{isPayoutGhst ? "GHST" : "STNK"}</Typography>
</Box> </Box>
</Box> </Box>
</TableCell> </TableCell>
<TableCell style={{ padding: "8px 8px 8px 0" }}> <TableCell style={{ padding: "8px 8px 8px 0" }}>
<Typography gutterBottom={false} style={{ lineHeight: 1.4 }}> <Typography gutterBottom={false} style={{ lineHeight: 1.4 }}>
{`${formatNumber(prepareBalance, 5)} ${isPayoutGhst ? ghstSymbol : stnkSymbol}`} {`${formatNumber(prepareBalance, 5)} ${isPayoutGhst ? "GHST" : "STNK"}`}
</Typography> </Typography>
</TableCell> </TableCell>
<TableCell style={{ padding: "8px 8px 8px 0" }}> <TableCell style={{ padding: "8px 8px 8px 0" }}>
@ -191,13 +182,13 @@ const ClaimInfo = ({ setConfirmationModalOpen, prepareBalance, claim, epoch, isC
); );
}; };
const MobileClaimInfo = ({ setConfirmationModalOpen, prepareBalance, epoch, claim, isPayoutGhst, isClaimable, ghstSymbol, stnkSymbol }) => { const MobileClaimInfo = ({ setConfirmationModalOpen, prepareBalance, epoch, claim, isPayoutGhst, isClaimable }) => {
return ( return (
<Box mt="10px"> <Box mt="10px">
<Box display="flex" flexDirection="row" alignItems="center" style={{ whiteSpace: "nowrap" }}> <Box display="flex" flexDirection="row" alignItems="center" style={{ whiteSpace: "nowrap" }}>
<Token key={isPayoutGhst ? ghstSymbol : stnkSymbol} name={isPayoutGhst ? ghstSymbol : stnkSymbol} /> <Token key={isPayoutGhst ? "GHST" : "STNK"} name={isPayoutGhst ? "GHST" : "STNK"} />
<Box marginLeft="14px" marginRight="10px"> <Box marginLeft="14px" marginRight="10px">
<Typography>{isPayoutGhst ? ghstSymbol : stnkSymbol}</Typography> <Typography>{isPayoutGhst ? "GHST" : "STNK"}</Typography>
</Box> </Box>
</Box> </Box>

View File

@ -18,7 +18,7 @@ import { DecimalBigNumber } from "../../../helpers/DecimalBigNumber";
import { formatCurrency } from "../../../helpers"; import { formatCurrency } from "../../../helpers";
import { useLpValuation } from "../../../hooks/treasury"; import { useLpValuation } from "../../../hooks/treasury";
import { useTotalSupply, useTokenSymbol } from "../../../hooks/tokens"; import { useTotalSupply } from "../../../hooks/tokens";
import { import {
DAI_ADDRESSES, DAI_ADDRESSES,
@ -31,13 +31,10 @@ const FarmPools = ({ chainId }) => {
const { totalSupply: daiFtsoUniTotalSupply } = useTotalSupply(chainId, "GDAI_FTSO"); const { totalSupply: daiFtsoUniTotalSupply } = useTotalSupply(chainId, "GDAI_FTSO");
const daiFtsoUniValuation = useLpValuation(chainId, "GDAI_FTSO", daiFtsoUniTotalSupply._value); const daiFtsoUniValuation = useLpValuation(chainId, "GDAI_FTSO", daiFtsoUniTotalSupply._value);
const { symbol: daiSymbol } = useTokenSymbol(chainId, "GDAI");
const { symbol: ftsoSymbol } = useTokenSymbol(chainId, "FTSO");
const pools = [ const pools = [
{ {
icons: ["FTSO", "GDAI"], icons: ["FTSO", "GDAI"],
name: `${ftsoSymbol}-${daiSymbol}`, name: "FTSO-gDAI",
dex: "Uniswap V2", dex: "Uniswap V2",
url: "/dex/uniswap", url: "/dex/uniswap",
tvl: daiFtsoUniValuation, tvl: daiFtsoUniValuation,
@ -64,7 +61,7 @@ const FarmPools = ({ chainId }) => {
return ( return (
<Paper headerText="Farm Pools" fullWidth enableBackground> <Paper headerText="Farm Pools" fullWidth enableBackground>
<TableContainer> <TableContainer>
<Table aria-label="Farm pools" style={{ tableLayout: "fixed" }}> <Table aria-label="Available bonds" style={{ tableLayout: "fixed" }}>
<TableHead> <TableHead>
<TableRow> <TableRow>
<TableCell style={{ padding: "8px 0", width: "30%" }}>Asset</TableCell> <TableCell style={{ padding: "8px 0", width: "30%" }}>Asset</TableCell>

View File

@ -13,7 +13,7 @@ export const CurrentIndex = props => {
const _props = { const _props = {
...props, ...props,
label: `Current Index`, label: `Current Index`,
tooltip: `The current index indicates the amount of ${props.ftsoSymbol} a holder would possess if they had staked and maintained 1 ${props.ftsoSymbol} since its launch.`, tooltip: `The current index indicates the amount of FTSO a holder would possess if they had staked and maintained 1 FTSO since its launch.`,
}; };
if (currentIndex) _props.metric = `${formatNumber(currentIndex, 2)}`; if (currentIndex) _props.metric = `${formatNumber(currentIndex, 2)}`;
@ -35,7 +35,7 @@ export const Apy = props => {
const _props = { const _props = {
...props, ...props,
label: "APY", label: "APY",
tooltip: `The annualized rate of return, accounting for compounding from ${props.stnkSymbol}s exponential rebasing.`, tooltip: "The annualized rate of return, accounting for compounding from STNKs exponential rebasing.",
}; };
if (apy) _props.metric = `${formatNumber(apy, 2)}${apy === Infinity ? "" : "%"}`; if (apy) _props.metric = `${formatNumber(apy, 2)}${apy === Infinity ? "" : "%"}`;
@ -52,7 +52,7 @@ export const TotalDeposit = props => {
const _props = { const _props = {
...props, ...props,
label: "Total Deposit", label: "Total Deposit",
tooltip: `The total stablecoin reserves in the ghostDAO treasury backing the entire circulating supply of ${props.stnkSymbol}.`, tooltip: "The total stablecoin reserves in the ghostDAO treasury backing the entire circulating supply of STNK.",
}; };
if (deposit) _props.metric = `${formatCurrency(deposit, 2)}`; if (deposit) _props.metric = `${formatCurrency(deposit, 2)}`;

View File

@ -39,7 +39,7 @@ const StakeConfirmationModal = (props) => {
checkedIcon={<CheckBoxOutlined viewBox="0 0 24 24" />} checkedIcon={<CheckBoxOutlined viewBox="0 0 24 24" />}
/> />
} }
label={`I understand the ${props.ftsoSymbol} Im staking will only be available to claim ${warmupLength.toString()} epochs after my transaction is confirmed`} label={`I understand the FTSO (eGHST) Im staking will only be available to claim ${warmupLength.toString()} epochs after my transaction is confirmed`}
/> />
</Box> </Box>
</> </>
@ -115,7 +115,7 @@ const StakeConfirmationModal = (props) => {
/> />
<Box display="flex" flexDirection="row" justifyContent="center"> <Box display="flex" flexDirection="row" justifyContent="center">
<Typography> <Typography>
{props.upperToken === "FTSO" ? props.ftsoSymbol : props.upperToken === "STNK" ? props.stnkSymbol : props.ghstSymbol} {props.upperToken}
</Typography> </Typography>
</Box> </Box>
</Box> </Box>
@ -127,7 +127,7 @@ const StakeConfirmationModal = (props) => {
/> />
<Box display="flex" flexDirection="row" justifyContent="center"> <Box display="flex" flexDirection="row" justifyContent="center">
<Typography> <Typography>
{props.bottomToken === "FTSO" ? props.ftsoSymbol : props.bottomToken === "STNK" ? props.stnkSymbol : props.ghstSymbol} {props.bottomToken}
</Typography> </Typography>
</Box> </Box>
</Box> </Box>
@ -141,7 +141,7 @@ const StakeConfirmationModal = (props) => {
owner={props.address} owner={props.address}
spender={STAKING_ADDRESSES[props.chainId]} spender={STAKING_ADDRESSES[props.chainId]}
decimals={props.spendDecimals} decimals={props.spendDecimals}
approvalText={"Approve " + props.upperToken === "FTSO" ? props.ftsoSymbol : props.upperToken === "STNK" ? props.stnkSymbol : props.ghstSymbol} approvalText={"Approve " + props.upperToken}
approvalPendingText={"Approving..."} approvalPendingText={"Approving..."}
connect={props.connect} connect={props.connect}
isVertical isVertical

View File

@ -23,7 +23,7 @@ import {
STAKING_ADDRESSES, STAKING_ADDRESSES,
} from "../../../constants/addresses"; } from "../../../constants/addresses";
import { useCurrentIndex } from "../../../hooks/staking"; import { useCurrentIndex } from "../../../hooks/staking";
import { useBalance, useTokenSymbol } from "../../../hooks/tokens"; import { useBalance } from "../../../hooks/tokens";
import { formatNumber } from "../../../helpers"; import { formatNumber } from "../../../helpers";
const PREFIX = "StakeInputArea"; const PREFIX = "StakeInputArea";
@ -106,10 +106,6 @@ export const StakeInputArea = ({
const { balance: stnkBalance, refetch: stnkRefetch } = useBalance(chainId, "STNK", address); const { balance: stnkBalance, refetch: stnkRefetch } = useBalance(chainId, "STNK", address);
const { balance: ghstBalance, refetch: ghstRefetch } = useBalance(chainId, "GHST", address); const { balance: ghstBalance, refetch: ghstRefetch } = useBalance(chainId, "GHST", address);
const { symbol: ftsoSymbol } = useTokenSymbol(chainId, "FTSO");
const { symbol: stnkSymbol } = useTokenSymbol(chainId, "STNK");
const { symbol: ghstSymbol } = useTokenSymbol(chainId, "GHST");
const setIsClaimInner = (value) => { const setIsClaimInner = (value) => {
setIsClaim(value); setIsClaim(value);
localStorage.setItem("stake-isClaim", value); localStorage.setItem("stake-isClaim", value);
@ -185,37 +181,15 @@ export const StakeInputArea = ({
} }
const SwapCardTemplate = (tokenName, tokenAmount, isUpper, handleModal) => { const SwapCardTemplate = (tokenName, tokenAmount, isUpper, handleModal) => {
const balance = tokenName === "STNK" || tokenName === "sCSPR" ? const balance = tokenName === "STNK" ?
stnkBalance : tokenName === "FTSO" || tokenName === "eCSPR" ? stnkBalance : tokenName === "FTSO" ?
ftsoBalance : ghstBalance; ftsoBalance : ghstBalance;
let realTokenName = "";
switch (tokenName.toUpperCase()) {
case "FTSO":
realTokenName = ftsoSymbol;
break;
case "ECSPR":
realTokenName = ftsoSymbol;
break;
case "STNK":
realTokenName = stnkSymbol;
break;
case "SCSPR":
realTokenName = stnkSymbol;
break;
case "GHST":
realTokenName = ghstSymbol;
break;
case "CSPR":
realTokenName = ghstSymbol;
break;
}
return ( return (
<SwapCard <SwapCard
id={`${tokenName.toLowerCase()}-input`} id={`${tokenName.toLowerCase()}-input`}
token={tokenName} token={tokenName}
tokenName={realTokenName} tokenName={tokenName}
tokenOnClick={() => handleModal(true)} tokenOnClick={() => handleModal(true)}
inputProps={{ "data-testid": `${tokenName.toLowerCase()}-input`, min: "0" }} inputProps={{ "data-testid": `${tokenName.toLowerCase()}-input`, min: "0" }}
value={tokenAmount} value={tokenAmount}
@ -254,30 +228,24 @@ export const StakeInputArea = ({
{upperTokenModalOpen && ( {upperTokenModalOpen && (
<TokenModal <TokenModal
open={upperTokenModalOpen} open={upperTokenModalOpen}
handleSelect={data => handleTokenModalInput(data.token, data.isUpper)} handleSelect={data => handleTokenModalInput(data.name, data.isUpper)}
handleClose={() => setUpperTokenModalOpen(false)} handleClose={() => setUpperTokenModalOpen(false)}
ftsoBalance={formatNumber(ftsoBalance, formatDecimals)} ftsoBalance={formatNumber(ftsoBalance, formatDecimals)}
stnkBalance={formatNumber(stnkBalance, formatDecimals)} stnkBalance={formatNumber(stnkBalance, formatDecimals)}
ghstBalance={formatNumber(ghstBalance, formatDecimals)} ghstBalance={formatNumber(ghstBalance, formatDecimals)}
isUpper={true} isUpper={true}
ftsoSymbol={ftsoSymbol}
stnkSymbol={stnkSymbol}
ghstSymbol={ghstSymbol}
/> />
)} )}
{bottomTokenModalOpen && ( {bottomTokenModalOpen && (
<TokenModal <TokenModal
open={bottomTokenModalOpen} open={bottomTokenModalOpen}
handleSelect={data => handleTokenModalInput(data.token, data.isUpper)} handleSelect={data => handleTokenModalInput(data.name, data.isUpper)}
handleClose={() => setBottomTokenModalOpen(false)} handleClose={() => setBottomTokenModalOpen(false)}
ftsoBalance={formatNumber(ftsoBalance, formatDecimals)} ftsoBalance={formatNumber(ftsoBalance, formatDecimals)}
stnkBalance={formatNumber(stnkBalance, formatDecimals)} stnkBalance={formatNumber(stnkBalance, formatDecimals)}
ghstBalance={formatNumber(ghstBalance, formatDecimals)} ghstBalance={formatNumber(ghstBalance, formatDecimals)}
tokenToExclude={upperToken} tokenToExclude={upperToken}
isUpper={false} isUpper={false}
ftsoSymbol={ftsoSymbol}
stnkSymbol={stnkSymbol}
ghstSymbol={ghstSymbol}
/> />
)} )}
@ -324,9 +292,6 @@ export const StakeInputArea = ({
receiveDecimals={bottomToken === "GHST" ? 18 : 9} receiveDecimals={bottomToken === "GHST" ? 18 : 9}
isClaim={isClaim} isClaim={isClaim}
isTrigger={isTrigger} isTrigger={isTrigger}
ftsoSymbol={ftsoSymbol}
stnkSymbol={stnkSymbol}
ghstSymbol={ghstSymbol}
/> />
</> </>
); );

View File

@ -13,23 +13,20 @@ const TokenModal = ({
ghstBalance = "0.00", ghstBalance = "0.00",
tokenToExclude, tokenToExclude,
isUpper, isUpper,
ftsoSymbol,
stnkSymbol,
ghstSymbol
}) => { }) => {
const theme = useTheme(); const theme = useTheme();
const TokenItem = ({ token, name, exclude, isUpper, balance = "0", icon, address = "", price, decimals, ...props }) => { const TokenItem = ({ name, exclude, isUpper, balance = "0", icon, address = "", price, decimals, ...props }) => {
if (name === exclude) { if (name === exclude) {
return <></>; return <></>;
} }
return ( return (
<ListItem <ListItem
key={token} key={name}
button="true" button
onClick={() => { onClick={() => {
handleSelect({token, isUpper}); handleSelect({name, isUpper});
handleClose(); handleClose();
}} }}
sx={{ borderBottom: `1px solid ${theme.colors.gray[500]}` }} sx={{ borderBottom: `1px solid ${theme.colors.gray[500]}` }}
@ -38,7 +35,7 @@ const TokenModal = ({
{icon ? ( {icon ? (
<Avatar src={icon} sx={{ width: "15px", height: "15px" }} /> <Avatar src={icon} sx={{ width: "15px", height: "15px" }} />
) : ( ) : (
<Token name={token} sx={{ fontSize: "15px" }} /> <Token name={name} sx={{ fontSize: "15px" }} />
)} )}
<ListItemText <ListItemText
@ -69,9 +66,9 @@ const TokenModal = ({
</Link> </Link>
</Box> </Box>
<List> <List>
{<TokenItem isUpper={isUpper} exclude={tokenToExclude} token="FTSO" name={ftsoSymbol} balance={ftsoBalance} />} {<TokenItem isUpper={isUpper} exclude={tokenToExclude} name="FTSO" balance={ftsoBalance} />}
{<TokenItem isUpper={isUpper} exclude={tokenToExclude} token="STNK" name={stnkSymbol} balance={stnkBalance} />} {<TokenItem isUpper={isUpper} exclude={tokenToExclude} name="STNK" balance={stnkBalance} />}
{<TokenItem isUpper={isUpper} exclude={tokenToExclude} token="GHST" name={ghstSymbol} balance={ghstBalance} />} {<TokenItem isUpper={isUpper} exclude={tokenToExclude} name="GHST" balance={ghstBalance} />}
</List> </List>
</Box> </Box>
</Dialog> </Dialog>

View File

@ -17,17 +17,11 @@ import Paper from "../../components/Paper/Paper";
import PageTitle from "../../components/PageTitle/PageTitle"; import PageTitle from "../../components/PageTitle/PageTitle";
import SafariFooter from "../../components/SafariFooter/SafariFooter"; import SafariFooter from "../../components/SafariFooter/SafariFooter";
import { useTokenSymbol } from "../../hooks/tokens";
const MetricsDashboard = ({ chainId }) => { const MetricsDashboard = ({ chainId }) => {
const theme = useTheme(); const theme = useTheme();
const isMobileScreen = useMediaQuery("(max-width: 885px)"); const isMobileScreen = useMediaQuery("(max-width: 885px)");
const isVeryMobileScreen = useMediaQuery("(max-width: 560px)"); const isVeryMobileScreen = useMediaQuery("(max-width: 560px)");
const { symbol: ftsoSymbol } = useTokenSymbol(chainId, "FTSO");
const { symbol: stnkSymbol } = useTokenSymbol(chainId, "STNK");
const { symbol: ghstSymbol } = useTokenSymbol(chainId, "GHST");
const xsCalculator = useMemo(() => { const xsCalculator = useMemo(() => {
return isMobileScreen ? isVeryMobileScreen ? 12 : 6 : 4; return isMobileScreen ? isVeryMobileScreen ? 12 : 6 : 4;
}, [isMobileScreen, isVeryMobileScreen]) }, [isMobileScreen, isVeryMobileScreen])
@ -39,22 +33,22 @@ const MetricsDashboard = ({ chainId }) => {
<Paper fullWidth enableBackground> <Paper fullWidth enableBackground>
<Grid container spacing={2}> <Grid container spacing={2}>
<Grid item xs={xsCalculator}> <Grid item xs={xsCalculator}>
<TreasuryMarketCap ftsoSymbol={ftsoSymbol} chainId={chainId} /> <TreasuryMarketCap chainId={chainId} />
</Grid> </Grid>
<Grid item xs={xsCalculator}> <Grid item xs={xsCalculator}>
<FatsoPrice ftsoSymbol={ftsoSymbol} chainId={chainId} /> <FatsoPrice chainId={chainId} />
</Grid> </Grid>
<Grid item xs={xsCalculator}> <Grid item xs={xsCalculator}>
<GhostPrice ghstSymbol={ghstSymbol} ftsoSymbol={ftsoSymbol} chainId={chainId} /> <GhostPrice chainId={chainId} />
</Grid> </Grid>
<Grid item xs={xsCalculator}> <Grid item xs={xsCalculator}>
<CirculatingSupply stnkSymbol={stnkSymbol} chainId={chainId} /> <CirculatingSupply chainId={chainId} />
</Grid> </Grid>
<Grid item xs={xsCalculator}> <Grid item xs={xsCalculator}>
<FatsoBacking ftsoSymbol={ftsoSymbol} chainId={chainId} /> <FatsoBacking chainId={chainId} />
</Grid> </Grid>
<Grid item xs={xsCalculator}> <Grid item xs={xsCalculator}>
<CurrentIndex ftsoSymbol={ftsoSymbol} chainId={chainId} /> <CurrentIndex chainId={chainId} />
</Grid> </Grid>
</Grid> </Grid>
</Paper> </Paper>

View File

@ -15,10 +15,10 @@ export const CurrentIndex = props => {
const _props = { const _props = {
...props, ...props,
label: `Current Index`, label: `Current Index`,
tooltip: `The current index indicates the amount of ${props.ftsoSymbol} a holder would possess if they had staked and maintained 1 ${props.ftsoSymbol} since its launch.`, tooltip: `The current index indicates the amount of FTSO a holder would possess if they had staked and maintained 1 FTSO since its launch.`,
}; };
if (currentIndex) _props.metric = `${formatNumber(currentIndex, 2)} ${props.ftsoSymbol}`; if (currentIndex) _props.metric = `${formatNumber(currentIndex, 2)} FTSO`;
else _props.isLoading = true; else _props.isLoading = true;
return <Metric {..._props} />; return <Metric {..._props} />;
@ -31,8 +31,8 @@ export const GhostPrice = props => {
const _props = { const _props = {
...props, ...props,
label: `${props.ghstSymbol} Price`, label: "GHST " + `Price`,
tooltip: `1 ${props.ghstSymbol} = 1 ${props.ftsoSymbol} x Current Index`, tooltip: "1 GHST = 1 FTSO x Current Index",
}; };
if (ghstPrice) _props.metric = formatCurrency(ghstPrice, 2); if (ghstPrice) _props.metric = formatCurrency(ghstPrice, 2);
@ -46,8 +46,8 @@ export const FatsoPrice = props => {
const _props = { const _props = {
...props, ...props,
label: `${props.ftsoSymbol} Price`, label: "FTSO " + `Price`,
tooltip: `Weighted ${props.ftsoSymbol} Price Across V2 DEXs on the chosen EVM Chain`, tooltip: `Weighted FTSO Price Across V2 DEXs on the chosen EVM Chain`,
}; };
if (ftsoPrice) _props.metric = formatCurrency(ftsoPrice, 2); if (ftsoPrice) _props.metric = formatCurrency(ftsoPrice, 2);
@ -63,7 +63,7 @@ export const CirculatingSupply = props => {
const _props = { const _props = {
...props, ...props,
label: `Circulating / Total`, label: `Circulating / Total`,
tooltip: `Circulating supply refers to the amount of ${props.stnkSymbol} in circulation, excluding those held by the protocol in its treasury. However, ${props.stnkSymbol} allocated to Protocol-Owned Liquidity is considered part of the circulating supply.`, tooltip: `Circulating supply refers to the amount of STNK in circulation, excluding those held by the protocol in its treasury. However, STNK allocated to Protocol-Owned Liquidity is considered part of the circulating supply.`,
}; };
if (circulatingSupply && totalSupply) _props.metric = `${formatNumber(circulatingSupply, 0)}/${formatNumber(totalSupply, 0)}`; if (circulatingSupply && totalSupply) _props.metric = `${formatNumber(circulatingSupply, 0)}/${formatNumber(totalSupply, 0)}`;
@ -83,8 +83,8 @@ export const FatsoBacking = props => {
const _props = { const _props = {
...props, ...props,
label: `Backing per ${props.ftsoSymbol}`, label: `Backing per FTSO`,
tooltip: `The total amount of stablecoins held by the ghostDAO treasury to support the value of each ${props.ftsoSymbol} in circulation.` tooltip: `The total amount of stablecoins held by the ghostDAO treasury to support the value of each FTSO in circulation.`
}; };
if (backing) _props.metric = formatCurrency(backing, 2); if (backing) _props.metric = formatCurrency(backing, 2);
@ -101,7 +101,7 @@ export const TreasuryMarketCap = props => {
const _props = { const _props = {
...props, ...props,
label: `Market Cap`, label: `Market Cap`,
tooltip: `Market Cap = ${props.ftsoSymbol} Price × ${props.ftsoSymbol} Total Supply` tooltip: `Market Cap = FTSO Price × FTSO Total Supply`
}; };
if (marketCap) _props.metric = formatCurrency(marketCap, 2); if (marketCap) _props.metric = formatCurrency(marketCap, 2);

View File

@ -7,7 +7,7 @@ import { SecondaryButton } from "../../../components/Button";
import { formatNumber, formatCurrency } from "../../../helpers"; import { formatNumber, formatCurrency } from "../../../helpers";
import { DecimalBigNumber } from "../../../helpers/DecimalBigNumber"; import { DecimalBigNumber } from "../../../helpers/DecimalBigNumber";
import { useBalance, useTokenSymbol } from "../../../hooks/tokens"; import { useBalance } from "../../../hooks/tokens";
import { import {
useFtsoPrice, useFtsoPrice,
useStnkPrice, useStnkPrice,
@ -79,11 +79,6 @@ const TokenInfo = ({ chainId, isMobileScreen }) => {
const ghstPrice = useGhstPrice(chainId); const ghstPrice = useGhstPrice(chainId);
const daiPrice = useDaiPrice(chainId); const daiPrice = useDaiPrice(chainId);
const { symbol: daiSymbol } = useTokenSymbol(chainId, "GDAI");
const { symbol: ftsoSymbol } = useTokenSymbol(chainId, "FTSO");
const { symbol: stnkSymbol } = useTokenSymbol(chainId, "STNK");
const { symbol: ghstSymbol } = useTokenSymbol(chainId, "GHST");
const { balance: ftsoBalance, contractAddress: ftsoAddress } = useBalance(chainId, "FTSO", address); const { balance: ftsoBalance, contractAddress: ftsoAddress } = useBalance(chainId, "FTSO", address);
const { balance: stnkBalance, contractAddress: stnkAddress } = useBalance(chainId, "STNK", address); const { balance: stnkBalance, contractAddress: stnkAddress } = useBalance(chainId, "STNK", address);
const { balance: ghstBalance, contractAddress: ghstAddress } = useBalance(chainId, "GHST", address); const { balance: ghstBalance, contractAddress: ghstAddress } = useBalance(chainId, "GHST", address);
@ -100,10 +95,10 @@ const TokenInfo = ({ chainId, isMobileScreen }) => {
to: `${ftsoAddress}`, to: `${ftsoAddress}`,
})} })}
theme={theme} theme={theme}
tokenName={ftsoSymbol} tokenName="FTSO"
balance={ftsoBalance} balance={ftsoBalance}
price={ftsoPrice} price={ftsoPrice}
description={`${ftsoSymbol} is the native token of the ghostDAO protocol, fully backed by stablecoin reserves held in the ghostDAO treasury.`} description="FTSO is the native token of the ghostDAO protocol, fully backed by stablecoin reserves held in the ghostDAO treasury."
/> />
<TokenTab <TokenTab
isMobileScreen={isMobileScreen} isMobileScreen={isMobileScreen}
@ -113,10 +108,10 @@ const TokenInfo = ({ chainId, isMobileScreen }) => {
to: `${stnkAddress}`, to: `${stnkAddress}`,
})} })}
theme={theme} theme={theme}
tokenName={stnkSymbol} tokenName="STNK"
balance={stnkBalance} balance={stnkBalance}
price={stnkPrice} price={stnkPrice}
description={`${stnkSymbol} is a receipt for staked ${ftsoSymbol}, growing with staking rewards. When unstaked, its burned for ${ftsoSymbol} at a 1:1 ratio.`} description="STNK is a receipt for staked FTSO, growing with staking rewards. When unstaked, its burned for FTSO at a 1:1 ratio."
/> />
<TokenTab <TokenTab
isMobileScreen={isMobileScreen} isMobileScreen={isMobileScreen}
@ -126,20 +121,20 @@ const TokenInfo = ({ chainId, isMobileScreen }) => {
to: `${ghstAddress}`, to: `${ghstAddress}`,
})} })}
theme={theme} theme={theme}
tokenName={ghstSymbol} tokenName="GHST"
balance={ghstBalance} balance={ghstBalance}
price={ghstPrice} price={ghstPrice}
description={`${ghstSymbol} enables ghostDAO to have on-chain governance and to be truly cross-chain. ${ghstSymbol} Price = ${ftsoSymbol} Price x Current Index.`} description="GHST enables ghostDAO to have on-chain governance and to be truly cross-chain. GHST Price = FTSO Price x Current Index."
/> />
<TokenTab <TokenTab
isMobileScreen={isMobileScreen} isMobileScreen={isMobileScreen}
tokenUrl="/faucet" tokenUrl="/faucet"
tokenUrlParams="" tokenUrlParams=""
theme={theme} theme={theme}
tokenName={daiSymbol} tokenName="gDAI"
balance={daiBalance} balance={daiBalance}
price={daiPrice} price={daiPrice}
description={`${ftsoSymbol} is backed by a treasury reserve of crypto assets, with ${daiSymbol} being the primary and most liquid asset.`} description="FTSO is backed by a treasury reserve of crypto assets, with gDAI being the primary and most liquid asset."
/> />
</Box> </Box>
</Grid> </Grid>

View File

@ -14,8 +14,7 @@ import { abi as TreasuryAbi } from "../../abi/GhostTreasury.json";
import { abi as BondingCalculatorAbi } from "../../abi/GhostBondingCalculator.json"; import { abi as BondingCalculatorAbi } from "../../abi/GhostBondingCalculator.json";
import { useFtsoPrice } from "../prices"; import { useFtsoPrice } from "../prices";
import { useTokenSymbol, useTokenSymbols } from "../tokens"; import { getTokenAddress, getTokenIcons, getTokenName, getBondNameDisplayName, getTokenPurchaseLink } from "../helpers";
import { getTokenAddress, getTokenIcons, getBondNameDisplayName, getTokenPurchaseLink } from "../helpers";
import { DecimalBigNumber } from "../../helpers/DecimalBigNumber"; import { DecimalBigNumber } from "../../helpers/DecimalBigNumber";
import { shorten } from "../../helpers"; import { shorten } from "../../helpers";
@ -105,9 +104,6 @@ export const useLiveBonds = (chainId) => {
}) })
}); });
const { symbols: quoteTokenSymbols } = useTokenSymbols(chainId, markets?.map(m => m.result?.at(1)));
const { symbol: baseTokenSymbol } = useTokenSymbol(chainId, "FTSO");
const liveBonds = liveIndexesRaw ? liveIndexesRaw.map((bondIndex, index) => { const liveBonds = liveIndexesRaw ? liveIndexesRaw.map((bondIndex, index) => {
const id = Number(bondIndex); const id = Number(bondIndex);
@ -123,7 +119,6 @@ export const useLiveBonds = (chainId) => {
const markdown = markdowns?.at(index).result const markdown = markdowns?.at(index).result
? new DecimalBigNumber(markdowns.at(index).result, quoteTokenDecimals) ? new DecimalBigNumber(markdowns.at(index).result, quoteTokenDecimals)
: new DecimalBigNumber(1n, 0); : new DecimalBigNumber(1n, 0);
const quoteTokenSymbol = quoteTokenSymbols?.at(index).result ? quoteTokenSymbols.at(index).result : "";
const quoteTokenPerBaseToken = new DecimalBigNumber(marketPrice, 9); const quoteTokenPerBaseToken = new DecimalBigNumber(marketPrice, 9);
const priceInUsd = quoteTokenPerUsd.mul(quoteTokenPerBaseToken).mul(markdown); const priceInUsd = quoteTokenPerUsd.mul(quoteTokenPerBaseToken).mul(markdown);
@ -145,20 +140,19 @@ export const useLiveBonds = (chainId) => {
); );
const zero = new DecimalBigNumber(0n, 0); const zero = new DecimalBigNumber(0n, 0);
const bondName = `${baseTokenSymbol}/${quoteTokenSymbol}`;
return { return {
id, id,
discount, discount,
displayName: getBondNameDisplayName(chainId, bondName, quoteTokenAddress), displayName: getBondNameDisplayName(chainId, markets?.at(index).result?.at(1)),
baseToken: { baseToken: {
name: quoteTokenSymbol, name: "FTSO",
purchaseUrl: getTokenPurchaseLink(chainId, ""), purchaseUrl: getTokenPurchaseLink(chainId, ""),
icons: ["FTSO"], icons: ["FTSO"],
tokenAddress: getTokenAddress(chainId, "FTSO") tokenAddress: getTokenAddress(chainId, "FTSO")
}, },
quoteToken: { quoteToken: {
name: quoteTokenName, name: getTokenName(chainId, quoteTokenAddress),
purchaseUrl: getTokenPurchaseLink(chainId, quoteTokenAddress), purchaseUrl: getTokenPurchaseLink(chainId, quoteTokenAddress),
icons: getTokenIcons(chainId, quoteTokenAddress), icons: getTokenIcons(chainId, quoteTokenAddress),
decimals: quoteTokenDecimals, decimals: quoteTokenDecimals,
@ -235,17 +229,14 @@ export const useNotes = (chainId, address) => {
}), }),
}); });
const { symbols: quoteTokenSymbols } = useTokenSymbols(chainId, markets?.map(m => m.result?.at(1)));
const notes = indexesFor ? indexesFor.map((noteIndex, index) => { const notes = indexesFor ? indexesFor.map((noteIndex, index) => {
const id = Number(noteIndex); const id = Number(noteIndex);
const quoteTokenAddress = markets?.at(index).result?.at(1) ? markets.at(index).result.at(1) : ""; const quoteTokenAddress = markets?.at(index).result?.at(1) ? markets.at(index).result.at(1) : "";
const quoteTokenSymbol = quoteTokenSymbols?.at(index).result ? quoteTokenSymbols.at(index).result : "";
return { return {
id, id,
quoteToken: { quoteToken: {
name: quoteTokenSymbol, name: getTokenName(chainId, quoteTokenAddress),
icons: getTokenIcons(chainId, quoteTokenAddress), icons: getTokenIcons(chainId, quoteTokenAddress),
}, },
vesting: terms?.at(index).result?.at(2) ? terms.at(index).result.at(2) : 0, vesting: terms?.at(index).result?.at(2) ? terms.at(index).result.at(2) : 0,

View File

@ -12,98 +12,59 @@ import { abi as StinkyAbi } from "../abi/Stinky.json";
import { abi as GhostAbi } from "../abi/Ghost.json"; import { abi as GhostAbi } from "../abi/Ghost.json";
import { abi as Erc20Abi } from "../abi/ERC20.json"; import { abi as Erc20Abi } from "../abi/ERC20.json";
// TBD: should be extended on new tokens
export const getTokenAbi = (name) => { export const getTokenAbi = (name) => {
let abi = Erc20Abi; let abi = Erc20Abi;
switch (name?.toUpperCase()) { switch (name?.toUpperCase()) {
case "DAI":
abi = DaiAbi;
break;
case "GDAI": case "GDAI":
abi = DaiAbi; abi = DaiAbi;
break; break;
case "FTSO": case "FTSO":
abi = FatsoAbi; abi = FatsoAbi;
break; break;
case "ECSPR":
abi = FatsoAbi;
break;
case "STNK": case "STNK":
abi = StinkyAbi; abi = StinkyAbi;
break; break;
case "SCSPR":
abi = StinkyAbi;
break;
case "GHST": case "GHST":
abi = GhostAbi; abi = GhostAbi;
break; break;
case "CSPR":
abi = GhostAbi;
break;
} }
return abi; return abi;
} }
// TBD: should be extended on new tokens
export const getTokenDecimals = (name) => { export const getTokenDecimals = (name) => {
let decimals = 18; let decimals = 18;
switch (name?.toUpperCase()) { switch (name?.toUpperCase()) {
case "DAI":
decimals = 18;
break;
case "GDAI": case "GDAI":
decimals = 18; decimals = 18;
break; break;
case "FTSO": case "FTSO":
decimals = 9; decimals = 9;
break; break;
case "ECSPR":
decimals = 9;
break;
case "STNK": case "STNK":
decimals = 9; decimals = 9;
break; break;
case "SCSPR":
decimals = 9;
break;
case "GHST": case "GHST":
decimals = 18; decimals = 18;
break; break;
case "CSPR":
decimals = 18;
break;
} }
return decimals; return decimals;
} }
// TBD: should be extended on new tokens
export const getTokenAddress = (chainId, name) => { export const getTokenAddress = (chainId, name) => {
let address = name; let address = name;
switch (name?.toUpperCase()) { switch (name?.toUpperCase()) {
case "DAI":
address = DAI_ADDRESSES[chainId];
break;
case "GDAI": case "GDAI":
address = DAI_ADDRESSES[chainId]; address = DAI_ADDRESSES[chainId];
break; break;
case "FTSO": case "FTSO":
address = FTSO_ADDRESSES[chainId]; address = FTSO_ADDRESSES[chainId];
break; break;
case "ECSPR":
address = FTSO_ADDRESSES[chainId];
break;
case "STNK": case "STNK":
address = STNK_ADDRESSES[chainId]; address = STNK_ADDRESSES[chainId];
break; break;
case "SCSPR":
address = STNK_ADDRESSES[chainId];
break;
case "GHST": case "GHST":
address = GHST_ADDRESSES[chainId]; address = GHST_ADDRESSES[chainId];
break; break;
case "CSPR":
address = GHST_ADDRESSES[chainId];
break;
case "GDAI_FTSO": case "GDAI_FTSO":
address = FTSO_DAI_LP_ADDRESSES[chainId]; address = FTSO_DAI_LP_ADDRESSES[chainId];
break; break;
@ -111,7 +72,6 @@ export const getTokenAddress = (chainId, name) => {
return address; return address;
} }
// TBD: should be extended on new tokens
export const getTokenIcons = (chainId, address) => { export const getTokenIcons = (chainId, address) => {
let icons = [""]; let icons = [""];
switch (address) { switch (address) {
@ -134,11 +94,39 @@ export const getTokenIcons = (chainId, address) => {
return icons; return icons;
} }
export const getBondNameDisplayName = (chainId, stringValue, tokenAddress) => { export const getTokenName = (chainId, address) => {
if (tokenAddress.toUpperCase() === FTSO_DAI_LP_ADDRESSES[chainId].toUpperCase()) { let name = "";
stringValue = `LP ${stringValue}`; switch (address) {
case DAI_ADDRESSES[chainId]:
name = "gDAI";
break;
case FTSO_ADDRESSES[chainId]:
name = "FTSO";
break;
case STNK_ADDRESSES[chainId]:
name = "STNK";
break;
case GHST_ADDRESSES[chainId]:
name = "GHST";
break;
case FTSO_DAI_LP_ADDRESSES[chainId]:
name = "UNI-V2";
break;
} }
return stringValue; return name;
}
export const getBondNameDisplayName = (chainId, tokenAddress) => {
let bondName = "";
switch (tokenAddress) {
case DAI_ADDRESSES[chainId]:
bondName = "FTSO/gDAI";
break;
case FTSO_DAI_LP_ADDRESSES[chainId]:
bondName = "LP FTSO/gDAI"
break;
}
return bondName;
} }
export const getTokenPurchaseLink = (chainId, tokenAddress) => { export const getTokenPurchaseLink = (chainId, tokenAddress) => {

View File

@ -1,6 +1,6 @@
import { useReadContract } from "wagmi"; import { useReadContract } from "wagmi";
import { useCurrentIndex, useGhostedSupply } from "../staking"; import { useCurrentIndex } from "../staking";
import { useUniswapV2PairReserves } from "../uniswapv2"; import { useUniswapV2PairReserves } from "../uniswapv2";
import { DecimalBigNumber } from "../../helpers/DecimalBigNumber"; import { DecimalBigNumber } from "../../helpers/DecimalBigNumber";
import { FTSO_DAI_LP_ADDRESSES, DAI_ADDRESSES, FTSO_ADDRESSES } from "../../constants/addresses"; import { FTSO_DAI_LP_ADDRESSES, DAI_ADDRESSES, FTSO_ADDRESSES } from "../../constants/addresses";
@ -20,19 +20,13 @@ export const useFtsoPrice = (chainId) => {
"GDAI", "GDAI",
); );
const reserveAddress = DAI_ADDRESSES[chainId]; const stableReserves = DAI_ADDRESSES[chainId].toUpperCase() === tokens.token0.toUpperCase()
const ftsoAddress = FTSO_ADDRESSES[chainId];
if (!reserveAddress || !ftsoAddress) {
return new DecimalBigNumber(0n, 9);
}
const stableReserves = reserveAddress.toUpperCase() === tokens.token0.toUpperCase()
? reserves.reserve0._value ? reserves.reserve0._value
: reserveAddress.toUpperCase() === tokens.token1.toUpperCase() ? reserves.reserve1._value : 0n; : DAI_ADDRESSES[chainId].toUpperCase() === tokens.token1.toUpperCase() ? reserves.reserve1._value : 0n;
const ftsoReserves = ftsoAddress.toUpperCase() === tokens.token0.toUpperCase() const ftsoReserves = FTSO_ADDRESSES[chainId].toUpperCase() === tokens.token0.toUpperCase()
? reserves.reserve0._value ? reserves.reserve0._value
: ftsoAddress.toUpperCase() === tokens.token1.toUpperCase() ? reserves.reserve1._value : 0n; : FTSO_ADDRESSES[chainId].toUpperCase() === tokens.token1.toUpperCase() ? reserves.reserve1._value : 0n;
let price = 0n let price = 0n
if (ftsoReserves > 0n) if (ftsoReserves > 0n)
@ -52,10 +46,3 @@ export const useGhstPrice = (chainId) => {
return ftsoPrice.mul(currentIndex); return ftsoPrice.mul(currentIndex);
}; };
export const useGhostedSupplyPrice = (chainId) => {
const ghstPrice = useGhstPrice(chainId);
const ghostedSupply = useGhostedSupply(chainId);
return ghstPrice.mul(ghostedSupply);
}

View File

@ -83,36 +83,6 @@ export const useWarmupInfo = (chainId, address) => {
return { warmupInfo, refetch } return { warmupInfo, refetch }
} }
export const useGatekeeperAddress = (chainId) => {
const { data: info, refetch } = useReadContract({
abi: StakingAbi,
address: STAKING_ADDRESSES[chainId],
functionName: "gatekeeper",
scopeKey: `gatekeeper-${chainId}`,
chainId: chainId,
});
const gatekeeperAddress = info ? info : "0x0000000000000000000000000000000000000000";
return { gatekeeperAddress, refetch };
}
export const useGhostedSupply = (chainId) => {
const { data: info, refetch } = useReadContract({
abi: StakingAbi,
address: STAKING_ADDRESSES[chainId],
functionName: "ghostedSupply",
scopeKey: `ghostedSupply-${chainId}`,
chainId: chainId,
});
const ghostedSupply = new DecimalBigNumber(
info ? info : 0n,
18
);
return ghostedSupply;
}
export const stake = async (chainId, account, amount, isRebase, isClaim) => { export const stake = async (chainId, account, amount, isRebase, isClaim) => {
const args = [ const args = [
amount, amount,
@ -216,24 +186,6 @@ export const wrap = async (chainId, account, amount) => {
); );
} }
export const ghost = async (chainId, account, receiver, amount) => {
const messages = {
replacedMsg: "Bridge transaction was replaced. Wait for inclusion please.",
successMsg: `Amount successfully bridged! Check tx hash status or wait for slow clap finalization.`,
errorMsg: "Bridge transaction failed. Check logs for error detalization.",
};
const txHash = await executeOnChainTransaction(
chainId,
"ghost",
[receiver, amount],
account,
messages
);
return txHash;
}
const executeOnChainTransaction = async ( const executeOnChainTransaction = async (
chainId, chainId,
functionName, functionName,
@ -259,11 +211,8 @@ const executeOnChainTransaction = async (
}); });
toast.success(messages.successMsg); toast.success(messages.successMsg);
return txHash;
} catch (err) { } catch (err) {
console.error(err); console.error(err);
toast.error(messages.errorMsg) toast.error(messages.errorMsg)
return undefined;
} }
} }

View File

@ -1,4 +1,4 @@
import { useReadContract, useReadContracts, useToken, useBalance as useInnerBalance } from "wagmi"; import { useReadContract, useToken, useBalance as useInnerBalance } from "wagmi";
import { simulateContract, writeContract, waitForTransactionReceipt } from "@wagmi/core"; import { simulateContract, writeContract, waitForTransactionReceipt } from "@wagmi/core";
import toast from "react-hot-toast"; import toast from "react-hot-toast";
@ -72,23 +72,6 @@ export const useTokenSymbol = (chainId, name) => {
return { symbol, refetch }; return { symbol, refetch };
} }
export const useTokenSymbols = (chainId, names) => {
const { data: symbols } = useReadContracts({
contracts: names?.map((name) => {
const contractAddress = getTokenAddress(chainId, name);
return {
abi: getTokenAbi(name),
address: contractAddress,
functionName: "symbol",
scopeKey: `symbol-${contractAddress}-${chainId}`,
chainId: chainId,
}
})
});
return { symbols };
}
export const useConversionRate = (chainId, name) => { export const useConversionRate = (chainId, name) => {
const contractAddress = getTokenAddress(chainId, name); const contractAddress = getTokenAddress(chainId, name);
const { data: rateRaw } = useReadContract({ const { data: rateRaw } = useReadContract({
@ -105,22 +88,6 @@ export const useConversionRate = (chainId, name) => {
return rate; return rate;
} }
export const useAccumulatedDonation = (chainId, name) => {
const contractAddress = getTokenAddress(chainId, name);
const { data: donationRaw } = useReadContract({
abi: getTokenAbi(name),
address: contractAddress,
functionName: "accumulatedDonation",
scopeKey: `accumulatedDonation-${contractAddress}-${chainId}`,
chainId: chainId,
});
const preparedDonationRaw = donationRaw ? donationRaw : 0n;
const accumulatedDonation = new DecimalBigNumber(preparedDonationRaw, 0);
return accumulatedDonation;
}
export const useCirculatingSupply = (chainId, name) => { export const useCirculatingSupply = (chainId, name) => {
const contractAddress = getTokenAddress(chainId, name); const contractAddress = getTokenAddress(chainId, name);
const { data: circulatingSupplyRaw } = useReadContract({ const { data: circulatingSupplyRaw } = useReadContract({
@ -204,28 +171,3 @@ export const mintDai = async (chainId, account, value) => {
toast.error("Minting gDAI from the faucet failed. Check logs for error detalization.") toast.error("Minting gDAI from the faucet failed. Check logs for error detalization.")
} }
} }
export const burnDai = async (chainId, account, value) => {
try {
const { request } = await simulateContract(config, {
abi: getTokenAbi("GDAI"),
address: getTokenAddress(chainId, "GDAI"),
functionName: 'burn',
args: [value],
account: account,
chainId: chainId
});
const txHash = await writeContract(config, request);
await waitForTransactionReceipt(config, {
hash: txHash,
onReplaced: () => toast("Burn transaction was replaced. Wait for inclusion please."),
chainId
});
toast.success("gDAI successfully burned for native coins! Check your wallet balance.");
} catch (err) {
console.error(err);
toast.error("Burning gDAI from the faucet failed. Check logs for error detalization.")
}
}

View File

@ -14,6 +14,7 @@ const queryClient = new QueryClient();
const TRACKING_ID = import.meta.env.VITE_APP_TRACKING_ID; const TRACKING_ID = import.meta.env.VITE_APP_TRACKING_ID;
ReactGA.initialize(TRACKING_ID); ReactGA.initialize(TRACKING_ID);
ReactDOM.createRoot(document.getElementById('root')).render( ReactDOM.createRoot(document.getElementById('root')).render(
<> <>
<BackgroundCanvas /> <BackgroundCanvas />

View File

@ -18,7 +18,7 @@ export const darkPalette = {
success: "#60C45B", // idk where this is - done success: "#60C45B", // idk where this is - done
userFeedback: "#49A1F2", // idk where this is userFeedback: "#49A1F2", // idk where this is
error: "#F06F73", // red negative % - done error: "#F06F73", // red negative % - done
warning: "#49A1F2", // idk where this is - done warning: "#F06F73", // idk where this is - done
pnlGain: "#60C45B", // green positive % - done pnlGain: "#60C45B", // green positive % - done
}, },
gray: { gray: {