Compare commits
No commits in common. "bc5f88d57255773178f3134dc5a74f1927bbb639" and "856bf01ffe1fa3d7c56cfb63fc1db9e15e3153ff" have entirely different histories.
bc5f88d572
...
856bf01ffe
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "ghost-dao-interface",
|
||||
"private": true,
|
||||
"version": "0.2.0",
|
||||
"version": "0.1.2",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
@ -18,8 +18,6 @@
|
||||
"@mui/icons-material": "^6.4.7",
|
||||
"@mui/material": "^6.4.7",
|
||||
"@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-devtools": "^5.67.2",
|
||||
"@wagmi/core": "^2.17.3",
|
||||
|
@ -32,12 +32,6 @@ importers:
|
||||
'@mui/utils':
|
||||
specifier: ^6.4.6
|
||||
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':
|
||||
specifier: ^5.67.2
|
||||
version: 5.67.2(react@19.0.0)
|
||||
@ -729,10 +723,6 @@ packages:
|
||||
resolution: {integrity: sha512-HxngEd2XUcg9xi20JkwlLCtYwfoFw4JGkuZpT+WlsPD4gB/cxkvTD8fSsoAnphGZhFdZYKeQIPCuFlWPm1uE0g==}
|
||||
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':
|
||||
resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==}
|
||||
engines: {node: '>= 16'}
|
||||
@ -753,12 +743,6 @@ packages:
|
||||
resolution: {integrity: sha512-IHnV6A+zxU7XwmKFinmYjUcwlyK9+xkG3/s9KcQhI9BjQKycrJ1JRO+FbNYPwZiPKW3je/DR0k7w8/gLa5eaxQ==}
|
||||
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':
|
||||
resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==}
|
||||
|
||||
@ -929,9 +913,6 @@ packages:
|
||||
'@scure/bip39@1.6.0':
|
||||
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':
|
||||
resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==}
|
||||
|
||||
@ -2394,9 +2375,6 @@ packages:
|
||||
engines: {node: '>=16.0.0'}
|
||||
hasBin: true
|
||||
|
||||
scale-ts@1.6.1:
|
||||
resolution: {integrity: sha512-PBMc2AWc6wSEqJYBDPcyCLUj9/tMKnLX70jLOSndMtcUoLQucP/DM0vnQo1wJAYjTrQiq8iG9rD0q6wFzgjH7g==}
|
||||
|
||||
scheduler@0.25.0:
|
||||
resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==}
|
||||
|
||||
@ -3578,10 +3556,6 @@ snapshots:
|
||||
dependencies:
|
||||
'@noble/hashes': 1.8.0
|
||||
|
||||
'@noble/curves@1.9.6':
|
||||
dependencies:
|
||||
'@noble/hashes': 1.8.0
|
||||
|
||||
'@noble/hashes@1.4.0': {}
|
||||
|
||||
'@noble/hashes@1.7.0': {}
|
||||
@ -3592,16 +3566,6 @@ snapshots:
|
||||
|
||||
'@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': {}
|
||||
|
||||
'@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
|
||||
'@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': {}
|
||||
|
||||
'@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):
|
||||
dependencies:
|
||||
'@adraffy/ens-normalize': 1.11.0
|
||||
'@noble/curves': 1.9.2
|
||||
'@noble/hashes': 1.8.0
|
||||
'@noble/curves': 1.8.1
|
||||
'@noble/hashes': 1.7.1
|
||||
'@scure/bip32': 1.6.2
|
||||
'@scure/bip39': 1.5.4
|
||||
abitype: 1.0.8(zod@3.22.4)
|
||||
@ -5883,8 +5842,6 @@ snapshots:
|
||||
sass-embedded-win32-ia32: 1.85.1
|
||||
sass-embedded-win32-x64: 1.85.1
|
||||
|
||||
scale-ts@1.6.1: {}
|
||||
|
||||
scheduler@0.25.0: {}
|
||||
|
||||
scss@0.2.4:
|
||||
|
@ -27,7 +27,6 @@ const StakeContainer = lazy(() => import("./containers/Stake/StakeContainer"));
|
||||
const TreasuryDashboard = lazy(() => import("./containers/TreasuryDashboard/TreasuryDashboard"));
|
||||
const Faucet = lazy(() => import("./containers/Faucet/Faucet"));
|
||||
const Dex = lazy(() => import("./containers/Dex/Dex"));
|
||||
const Bridge = lazy(() => import("./containers/Bridge/Bridge"));
|
||||
const NotFound = lazy(() => import("./containers/NotFound/NotFound"));
|
||||
|
||||
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="/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="/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} />} />
|
||||
</>
|
||||
}
|
||||
|
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
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
@ -132,7 +132,6 @@ const NavItem = ({
|
||||
const LinkItem = () => (
|
||||
<Link {...linkProps} {...props} underline="hover">
|
||||
<Box
|
||||
sx={{ fontFamily: "Ubuntu" }}
|
||||
display="flex"
|
||||
flexDirection="row"
|
||||
alignItems="center"
|
||||
|
@ -2,7 +2,7 @@ import { Box, Typography, useMediaQuery, useTheme } from "@mui/material";
|
||||
|
||||
const PageTitle = ({ name, subtitle, noMargin }) => {
|
||||
const theme = useTheme();
|
||||
const mobile = useMediaQuery(theme.breakpoints.down("700"));
|
||||
const mobile = useMediaQuery(theme.breakpoints.down("sm"));
|
||||
|
||||
return (
|
||||
<Box
|
||||
|
@ -47,8 +47,7 @@ import BondDiscount from "../../containers/Bond/components/BondDiscount";
|
||||
import DashboardIcon from '@mui/icons-material/Dashboard';
|
||||
import ShowerIcon from '@mui/icons-material/Shower';
|
||||
|
||||
import { useTokenSymbol } from "../../hooks/tokens";
|
||||
import { useFtsoPrice, useGhstPrice, useGhostedSupplyPrice } from "../../hooks/prices";
|
||||
import { useFtsoPrice, useGhstPrice } from "../../hooks/prices";
|
||||
import { useLiveBonds } from "../../hooks/bonds/index";
|
||||
|
||||
const PREFIX = "NavContent";
|
||||
@ -67,10 +66,6 @@ const NavContent = ({ chainId, addressChainId }) => {
|
||||
const { liveBonds: ghostBonds } = useLiveBonds(chainId);
|
||||
const ftsoPrice = useFtsoPrice(chainId);
|
||||
const ghstPrice = useGhstPrice(chainId);
|
||||
const ghostedSupplyPrice = useGhostedSupplyPrice(chainId);
|
||||
|
||||
const { symbol: ftsoSymbol } = useTokenSymbol(chainId, "FTSO");
|
||||
const { symbol: ghstSymbol } = useTokenSymbol(chainId, "GHST");
|
||||
|
||||
return (
|
||||
<Paper className="dapp-sidebar">
|
||||
@ -87,13 +82,10 @@ const NavContent = ({ chainId, addressChainId }) => {
|
||||
</Link>
|
||||
<Box display="flex" flexDirection="column" mt="10px">
|
||||
<Box fontSize="12px" fontWeight="500" lineHeight={"15px"}>
|
||||
{ftsoSymbol} Price: {formatCurrency(ftsoPrice, 2)}
|
||||
FTSO Price: {formatCurrency(ftsoPrice, 2)}
|
||||
</Box>
|
||||
<Box fontSize="12px" fontWeight="500" lineHeight="15px">
|
||||
{ghstSymbol} Price: {formatCurrency(ghstPrice, 2)}
|
||||
</Box>
|
||||
<Box fontSize="12px" fontWeight="500" lineHeight={"15px"}>
|
||||
Ghosted Supply: {formatCurrency(ghostedSupplyPrice, 2)}
|
||||
GHST Price: {formatCurrency(ghstPrice, 2)}
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
@ -145,7 +137,6 @@ const NavContent = ({ chainId, addressChainId }) => {
|
||||
/>
|
||||
<NavItem icon={StakeIcon} label={`Stake`} to="/stake" />
|
||||
<NavItem icon={ShowerIcon} label={`Faucet`} to="/faucet" />
|
||||
<NavItem icon={PublicIcon} label={`Bridge`} to="/bridge" />
|
||||
<NavItem
|
||||
icon={CurrencyExchangeIcon}
|
||||
label={`Dex`}
|
||||
@ -176,6 +167,7 @@ const NavContent = ({ chainId, addressChainId }) => {
|
||||
</>
|
||||
}
|
||||
|
||||
<NavItem icon={PublicIcon} label={`Bridge`} href="https://bridge.ghostchain.io/" />
|
||||
<NavItem
|
||||
to=''
|
||||
icon={PublicIcon}
|
||||
|
@ -28,14 +28,14 @@ const StyledArrow = styled(Box)(
|
||||
},
|
||||
);
|
||||
|
||||
const SwapCollection = ({ UpperSwapCard, LowerSwapCard, arrowOnClick, iconNotNeeded }) => {
|
||||
const SwapCollection = ({ UpperSwapCard, LowerSwapCard, arrowOnClick }) => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<Box display="flex" flexDirection="column" maxWidth="476px">
|
||||
{UpperSwapCard}
|
||||
<Box display="flex" flexDirection="row" justifyContent="center">
|
||||
{!iconNotNeeded && (<StyledArrow
|
||||
<StyledArrow
|
||||
width="21px"
|
||||
height="21px"
|
||||
borderRadius="6px"
|
||||
@ -55,8 +55,7 @@ const SwapCollection = ({ UpperSwapCard, LowerSwapCard, arrowOnClick, iconNotNee
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</StyledArrow>)}
|
||||
{iconNotNeeded && <Box height="21px" />}
|
||||
</StyledArrow>
|
||||
</Box>
|
||||
<Box marginTop="-7px">{LowerSwapCard}</Box>
|
||||
</Box>
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { SvgIcon } from "@mui/material";
|
||||
import { styled } from "@mui/material/styles";
|
||||
|
||||
import FtsoIcon from "../../assets/tokens/FTSO.svg?react";
|
||||
import StnkIcon from "../../assets/tokens/STNK.svg?react";
|
||||
import FtsoIcon from "../../assets/tokens/eGHST.svg?react";
|
||||
import StnkIcon from "../../assets/tokens/sGHST.svg?react";
|
||||
import GhstIcon from "../../assets/tokens/GHST.svg?react";
|
||||
import DaiIcon from "../../assets/tokens/DAI.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":
|
||||
icon = FtsoIcon;
|
||||
break;
|
||||
case "ECSPR":
|
||||
icon = FtsoIcon;
|
||||
break;
|
||||
case "STNK":
|
||||
icon = StnkIcon;
|
||||
break;
|
||||
case "SCSPR":
|
||||
icon = StnkIcon;
|
||||
break;
|
||||
case "GHST":
|
||||
icon = GhstIcon;
|
||||
break;
|
||||
case "CSPR":
|
||||
icon = GhstIcon;
|
||||
break;
|
||||
case "GDAI":
|
||||
icon = DaiIcon;
|
||||
break;
|
||||
case "DAI":
|
||||
icon = DaiIcon;
|
||||
break;
|
||||
case "ETH":
|
||||
icon = WethIcon;
|
||||
break;
|
||||
|
@ -14,7 +14,7 @@ import EthIcon from "../../assets/tokens/ETH.svg?react";
|
||||
import { useSwitchChain } from 'wagmi';
|
||||
import toast from "react-hot-toast";
|
||||
|
||||
function SelectNetwork({ chainId, wrongNetworkToastId, setWrongNetworkToastId, small }) {
|
||||
function SelectNetwork({ chainId, wrongNetworkToastId, setWrongNetworkToastId }) {
|
||||
const theme = useTheme();
|
||||
const { chains, switchChain } = useSwitchChain();
|
||||
|
||||
@ -37,7 +37,7 @@ function SelectNetwork({ chainId, wrongNetworkToastId, setWrongNetworkToastId, s
|
||||
}
|
||||
|
||||
return(
|
||||
<FormControl sx={{ width: small ? "100px" : "155px" }}>
|
||||
<FormControl sx={{ width: "155px" }}>
|
||||
<Select
|
||||
labelId="network-select-helper-label"
|
||||
id="network-select-helper"
|
||||
@ -58,7 +58,7 @@ function SelectNetwork({ chainId, wrongNetworkToastId, setWrongNetworkToastId, s
|
||||
<MenuItem key={chain.name} value={chain.id}>
|
||||
<Box gap="10px" display="flex" flexDirection="row" alignItems="center">
|
||||
<SvgIcon component={EthIcon} viewBox="0 0 32 32" />
|
||||
{!small && <Typography>{chain.name}</Typography>}
|
||||
<Typography>{chain.name}</Typography>
|
||||
</Box>
|
||||
</MenuItem>
|
||||
)
|
||||
|
@ -23,7 +23,6 @@ function TopBar({
|
||||
}) {
|
||||
const themeColor = useTheme();
|
||||
const desktop = useMediaQuery(themeColor.breakpoints.up(1048));
|
||||
const small = useMediaQuery(themeColor.breakpoints.down(400));
|
||||
return (
|
||||
<Box
|
||||
display="flex"
|
||||
@ -33,12 +32,11 @@ function TopBar({
|
||||
marginRight={desktop ? "33px" : "0px"}
|
||||
>
|
||||
<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
|
||||
wrongNetworkToastId={wrongNetworkToastId}
|
||||
setWrongNetworkToastId={setWrongNetworkToastId}
|
||||
chainId={chainId}
|
||||
small={small}
|
||||
/>
|
||||
<Wallet address={address} connect={connect} chainId={chainId} />
|
||||
</Box>
|
||||
|
@ -152,7 +152,7 @@ function InitialWalletView({ address, chainId, onClose }) {
|
||||
fullWidth
|
||||
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>
|
||||
</Box>
|
||||
|
||||
|
@ -18,7 +18,7 @@ import GhostStyledIcon from "../../Icon/GhostIcon";
|
||||
import TokenStack from "../../TokenStack/TokenStack";
|
||||
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 { useLpValuation } from "../../../hooks/treasury";
|
||||
import { useAccount } from "wagmi";
|
||||
@ -76,7 +76,7 @@ export const Token = (props) => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const useLink = (symbol, fromAddress, toAddress, isPool) => {
|
||||
if (symbol.toUpperCase() === "GDAI") {
|
||||
if (symbol === "GDAI") {
|
||||
navigate({ pathname: "/faucet" })
|
||||
} else {
|
||||
navigate({
|
||||
@ -133,7 +133,7 @@ export const Token = (props) => {
|
||||
onClick={() => useLink(symbol, daiAddress, address, isPool)}
|
||||
fullWidth
|
||||
>
|
||||
<Typography>Get on {symbol.toUpperCase() === "GDAI" ? "Faucet" : "Uniswap"}</Typography>
|
||||
<Typography>Get on {symbol === "GDAI" ? "Faucet" : "Uniswap"}</Typography>
|
||||
</SecondaryButton>
|
||||
</Box>
|
||||
</Box>
|
||||
@ -178,15 +178,9 @@ export const useWallet = (chainId, userAddress) => {
|
||||
const ghstPrice = useGhstPrice(chainId);
|
||||
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 = {
|
||||
dai: {
|
||||
symbol: daiSymbol,
|
||||
symbol: "GDAI",
|
||||
address: daiAddress,
|
||||
balance: daiBalance,
|
||||
price: daiPrice,
|
||||
@ -194,7 +188,7 @@ export const useWallet = (chainId, userAddress) => {
|
||||
externalUrl: "https://ghostchain.io/wp-content/uploads/2025/03/gDAI.svg",
|
||||
},
|
||||
ftso: {
|
||||
symbol: ftsoSymbol,
|
||||
symbol: "FTSO",
|
||||
address: ftsoAddress,
|
||||
balance: ftsoBalance,
|
||||
price: ftsoPrice,
|
||||
@ -202,7 +196,7 @@ export const useWallet = (chainId, userAddress) => {
|
||||
externalUrl: "https://ghostchain.io/wp-content/uploads/2025/03/eGHST.svg",
|
||||
},
|
||||
stnk: {
|
||||
symbol: stnkSymbol,
|
||||
symbol: "STNK",
|
||||
address: stnkAddress,
|
||||
balance: stnkBalance,
|
||||
price: stnkPrice,
|
||||
@ -210,7 +204,7 @@ export const useWallet = (chainId, userAddress) => {
|
||||
externalUrl: "https://ghostchain.io/wp-content/uploads/2025/03/sGHST.svg",
|
||||
},
|
||||
ghst: {
|
||||
symbol: ghstSymbol,
|
||||
symbol: "GHST",
|
||||
address: ghstAddress,
|
||||
balance: ghstBalance,
|
||||
price: ghstPrice,
|
||||
@ -219,7 +213,7 @@ export const useWallet = (chainId, userAddress) => {
|
||||
},
|
||||
daiFtso: {
|
||||
isPool: true,
|
||||
symbol: lpDaiFtsoSymbol,
|
||||
symbol: "UNI-V2",
|
||||
address: lpDaiFtsoBalanceAddress,
|
||||
balance: lpDaiFtsoBalance,
|
||||
price: lpDaiFtsoPrice,
|
||||
@ -254,8 +248,8 @@ export const Tokens = ({ address, tokens, onClose }) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
{alwaysShowTokens.map((token, i) => (
|
||||
<Token key={i} {...tokenProps(token)} />
|
||||
{alwaysShowTokens.map(token => (
|
||||
<Token key={token.symbol} {...tokenProps(token)} />
|
||||
))}
|
||||
</>
|
||||
);
|
||||
|
@ -6,6 +6,7 @@ export const config = createConfig({
|
||||
transports: {
|
||||
[sepolia.id]: fallback([
|
||||
http('https://ethereum-sepolia-rpc.publicnode.com'),
|
||||
http('https://rpc-sepolia.rockx.com/'),
|
||||
http('https://1rpc.io/sepolia'),
|
||||
http('https://eth-sepolia.public.blastapi.io'),
|
||||
http('https://0xrpc.io/sep'),
|
||||
|
@ -1,32 +1,32 @@
|
||||
import { NetworkId } from "../constants";
|
||||
|
||||
export const STAKING_ADDRESSES = {
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0xd90E63E88282596E1ea33765b41Ba3d650f4aD52",
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0xb22Ad3b4a23EaEA8c06CD151D7C0e3758d0FB580",
|
||||
[NetworkId.TESTNET_HOODI]: "0x25F62eDc6C89FF84E957C22336A35d2dfc861a86",
|
||||
};
|
||||
|
||||
export const BOND_DEPOSITORY_ADDRESSES = {
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0xdcE486113280e49ca2fB200258E5Ee1B2D21D495",
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0x8773AC3258b31D3ACfc99Ffd13768ccB170fcF9f",
|
||||
[NetworkId.TESTNET_HOODI]: "0x6Ad50B1E293E68B2fC230c576220a93A9D311571",
|
||||
};
|
||||
|
||||
export const DAO_TREASURY_ADDRESSES = {
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0x93dd30f819403710de7933B79A74C4A42438458D",
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0x2AAd1EA51044e69756880f580C13a92D910af238",
|
||||
[NetworkId.TESTNET_HOODI]: "0x1a1b29b18f714fac9dDabEf530dFc4f85b56A6e8",
|
||||
};
|
||||
|
||||
export const FTSO_DAI_LP_ADDRESSES = {
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0x1394dC3f7bABaa2F0CA80353648087DAB1BF3fd6",
|
||||
[NetworkId.TESTNET_HOODI]: "0xf7B2d44209E70782d93A70F7D8eC50010dF7ae50",
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0x64B19626bd074cf7B1019798846c363bbA8A0d53",
|
||||
[NetworkId.TESTNET_HOODI]: "0xf7B2d44209E70782d93A70F7D8eC50010dF7ae50", // TBD
|
||||
};
|
||||
|
||||
export const FTSO_STNK_LP_ADDRESSES = {
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0x29965676fc00C3eA9717B2A02739d294399a382e",
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0x0000000000000000000000000000000000000000", // TBD
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0x0000000000000000000000000000000000000000",
|
||||
}
|
||||
|
||||
export const DAI_ADDRESSES = {
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0x5f63a27a9214a0352F2EF8dAF1eD4974d713192B",
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0xc7Afd3bC4c74f6E07880447b1759d5d639F2525F",
|
||||
[NetworkId.TESTNET_HOODI]: "0x80c6676c334BCcE60b3CC852085B72143379CE58",
|
||||
};
|
||||
|
||||
@ -36,39 +36,35 @@ export const WETH_ADDRESSES = {
|
||||
};
|
||||
|
||||
export const GHST_ADDRESSES = {
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0xdf2e5306A3dCcfA4e21bbF4226C17Ff5B008dDC4",
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0x4643076087234d9B81974beF1eC9c25F3A0202B9",
|
||||
[NetworkId.TESTNET_HOODI]: "0xE98f7426457E6533B206e91B7EcA97aa8A258B46",
|
||||
};
|
||||
|
||||
export const STNK_ADDRESSES = {
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0x02C296A27eA779d5a16F934337c12062C5E3c0D9",
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0x84060da636f5a83f2668ad238f09f8c667a1ec8b",
|
||||
[NetworkId.TESTNET_HOODI]: "0xF07e9303A9f16Afd82f4f57Fd6fca68Aa0AB6D7F",
|
||||
};
|
||||
|
||||
export const FTSO_ADDRESSES = {
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0xcFedFFEB3FdeCd2196820Ba3b71f3F84A1255f93",
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0x0eF2E888710E9f1d5E734f9ce30FAD40c832D5F3",
|
||||
[NetworkId.TESTNET_HOODI]: "0xb184e423811b644A1924334E63985c259F5D0033",
|
||||
};
|
||||
|
||||
export const DISTRIBUTOR_ADDRESSES = {
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0x8fbF8eB4Fcd451EF62Aee33508D46FE120963194",
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0xE433D078a555163dC6B53968E72418B6a1618f04",
|
||||
[NetworkId.TESTNET_HOODI]: "0xdF49dC81c457c6f92e26cf6d686C7a8715255842",
|
||||
};
|
||||
|
||||
export const GHOST_GOVERNANCE_ADDRESSES = {
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0xDab0c51918E6990d8763FAC8a04AE159e44e0c4f",
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0xD40E6442Ee01c234CD8AaF335122CfbB2aec8548",
|
||||
[NetworkId.TESTNET_HOODI]: "0x1B96B792840d4d19d5097ee007392Ed4d851e64F",
|
||||
};
|
||||
|
||||
export const BONDING_CALCULATOR_ADDRESSES = {
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0x4896bFc6256A57Df826d7144E48c9633d51d6319",
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0x29a6bb5De7a1049632E107544CaEF05e518451e7",
|
||||
[NetworkId.TESTNET_HOODI]: "0x2635d526Ad24b98082563937f7b996075052c6Fd",
|
||||
}
|
||||
|
||||
export const GATEKEEPER_ADDRESSES = {
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0xc85129A097773B7F8970a7364c928C05f265E6A1",
|
||||
}
|
||||
|
||||
export const UNISWAP_V2_ROUTER = {
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0xee567fe1712faf6149d80da1e6934e354124cfe3",
|
||||
[NetworkId.TESTNET_HOODI]: "0xD41daF947c6FFEf344754B99ad09466FBCBb7583",
|
||||
|
@ -17,7 +17,6 @@ import { ClaimBonds } from "./components/ClaimBonds";
|
||||
import { useLiveBonds } from "../../hooks/bonds";
|
||||
import { useTotalReserves } from "../../hooks/treasury";
|
||||
import { useFtsoPrice } from "../../hooks/prices";
|
||||
import { useTokenSymbol } from "../../hooks/tokens";
|
||||
|
||||
const Bonds = ({ chainId, address, connect }) => {
|
||||
const [isZoomed] = useState(false);
|
||||
@ -35,8 +34,6 @@ const Bonds = ({ chainId, address, connect }) => {
|
||||
const totalReserves = useTotalReserves(chainId);
|
||||
const ftsoPrice = useFtsoPrice(chainId);
|
||||
|
||||
const { symbol: ftsoSymbol } = useTokenSymbol(chainId, "FTSO");
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
const date = Math.round(Date.now() / 1000);
|
||||
@ -47,7 +44,7 @@ const Bonds = ({ chainId, address, connect }) => {
|
||||
|
||||
return (
|
||||
<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
|
||||
style={{
|
||||
paddingLeft: isSmallScreen || isVerySmallScreen ? "0" : "3.3rem",
|
||||
@ -67,7 +64,7 @@ const Bonds = ({ chainId, address, connect }) => {
|
||||
isLoading={false}
|
||||
/>
|
||||
<Metric
|
||||
label={`${ftsoSymbol} price`}
|
||||
label={`FTSO price`}
|
||||
metric={formatCurrency(ftsoPrice, 2)}
|
||||
isLoading={false}
|
||||
/>
|
||||
|
@ -9,7 +9,7 @@ const BondInfoText = () => {
|
||||
fontSize="0.875em"
|
||||
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.
|
||||
<Link
|
||||
color={theme.colors.primary[300]}
|
||||
href="https://ghostchain.io/ghostdao_litepaper"
|
||||
|
@ -37,9 +37,6 @@ const BondInputArea = ({
|
||||
const { currentIndex } = useCurrentIndex(chainId);
|
||||
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 [checked, setChecked] = useState(false);
|
||||
const [confirmOpen, setConfirmOpen] = useState(false);
|
||||
@ -167,11 +164,11 @@ const BondInputArea = ({
|
||||
title={"You Will Get"}
|
||||
balance={
|
||||
<span>
|
||||
{formatCurrency(amountInBaseToken, formatDecimals, ftsoSymbol)}
|
||||
{formatCurrency(amountInBaseToken, formatDecimals, "FTSO")}
|
||||
{" "}
|
||||
{!!currentIndex && (
|
||||
<span>
|
||||
(≈{formatCurrency(amountInBaseToken.div(currentIndex), formatDecimals, ghstSymbol)})
|
||||
(≈{formatCurrency(amountInBaseToken.div(currentIndex), formatDecimals, "GHST")})
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
@ -185,8 +182,8 @@ const BondInputArea = ({
|
||||
balance={
|
||||
<span>
|
||||
{bond.baseToken.tokenAddress.toUpperCase() === bond.quoteToken.quoteTokenAddress.toUpperCase()
|
||||
? `${formatCurrency(baseTokenString, formatDecimals, ftsoSymbol)}`
|
||||
: `${formatCurrency(baseTokenString, formatDecimals, ftsoSymbol)} (≈${formatCurrency(baseTokenString.div(currentIndex), formatDecimals, ghstSymbol)})`}
|
||||
? `${formatCurrency(baseTokenString, formatDecimals, "FTSO")}`
|
||||
: `${formatCurrency(baseTokenString, formatDecimals, "FTSO")} (≈${formatCurrency(baseTokenString.div(currentIndex), formatDecimals, "GHST")})`}
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
@ -194,7 +191,7 @@ const BondInputArea = ({
|
||||
<DataRow
|
||||
title="Discount"
|
||||
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
|
||||
|
@ -170,7 +170,7 @@ const payoutTokenCapacity = (bond) => {
|
||||
const payoutTokenCapacity = bond.maxPayout.inBaseToken.lt(bond.capacity.inBaseToken)
|
||||
? bond.maxPayout.inBaseToken
|
||||
: bond.capacity.inBaseToken;
|
||||
return `${formatNumber(payoutTokenCapacity, 4)} ${bond.baseToken.name}`;
|
||||
return `${formatNumber(payoutTokenCapacity, 4)} FTSO`;
|
||||
};
|
||||
|
||||
const BondRow = ({ bond, secondsTo }) => {
|
||||
|
@ -19,7 +19,6 @@ import { formatCurrency } from "../../../helpers";
|
||||
|
||||
import { useCurrentIndex, useEpoch, useWarmupLength, useWarmupInfo } from "../../../hooks/staking";
|
||||
import { useNotes, redeem } from "../../../hooks/bonds";
|
||||
import { useTokenSymbol } from "../../../hooks/tokens";
|
||||
|
||||
export const ClaimBonds = ({ chainId, address, secondsTo }) => {
|
||||
const isSmallScreen = useScreenSize("md");
|
||||
@ -38,10 +37,6 @@ export const ClaimBonds = ({ chainId, address, secondsTo }) => {
|
||||
const { currentIndex, refetch: currentIndexRefetch } = useCurrentIndex(chainId);
|
||||
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;
|
||||
|
||||
const totalClaimableBalance = new DecimalBigNumber(
|
||||
@ -96,8 +91,8 @@ export const ClaimBonds = ({ chainId, address, secondsTo }) => {
|
||||
onChange={(_, view) => setIsPayoutGhstInner(view === 1)}
|
||||
TabIndicatorProps={{ style: { display: "none" } }}
|
||||
>
|
||||
<Tab aria-label="payout-stnk-button" label={stnkSymbol} style={{ fontSize: "1rem" }} />
|
||||
<Tab aria-label="payout-ghst-button" label={ghstSymbol} style={{ fontSize: "1rem" }} />
|
||||
<Tab aria-label="payout-stnk-button" label="STNK" style={{ fontSize: "1rem" }} />
|
||||
<Tab aria-label="payout-ghst-button" label="GHST" style={{ fontSize: "1rem" }} />
|
||||
</Tabs>
|
||||
</Box>
|
||||
|
||||
@ -110,8 +105,8 @@ export const ClaimBonds = ({ chainId, address, secondsTo }) => {
|
||||
<Box mt="4px" mb="8px">
|
||||
<Typography variant="h4" align="center">
|
||||
{isPayoutGhst
|
||||
? formatCurrency(totalClaimableBalance, 5, ghstSymbol)
|
||||
: formatCurrency(currentIndex.mul(totalClaimableBalance), 5, stnkSymbol)
|
||||
? formatCurrency(totalClaimableBalance, 5, "GHST")
|
||||
: formatCurrency(currentIndex.mul(totalClaimableBalance), 5, "STNK")
|
||||
}
|
||||
</Typography>
|
||||
</Box>
|
||||
@ -157,8 +152,8 @@ export const ClaimBonds = ({ chainId, address, secondsTo }) => {
|
||||
<Typography>Payout</Typography>
|
||||
<Typography>
|
||||
{isPayoutGhst
|
||||
? formatCurrency(note.payout, 5, ghstSymbol)
|
||||
: formatCurrency(currentIndex.mul(note.payout), 5, stnkSymbol)
|
||||
? formatCurrency(note.payout, 5, "GHST")
|
||||
: formatCurrency(currentIndex.mul(note.payout), 5, "STNK")
|
||||
}
|
||||
</Typography>
|
||||
</Box>
|
||||
@ -213,8 +208,8 @@ export const ClaimBonds = ({ chainId, address, secondsTo }) => {
|
||||
<TableCell style={{ padding: "8px 0" }}>
|
||||
<Typography>
|
||||
{isPayoutGhst
|
||||
? formatCurrency(note.payout, 5, ghstSymbol)
|
||||
: formatCurrency(currentIndex.mul(note.payout), 5, stnkSymbol)
|
||||
? formatCurrency(note.payout, 5, "GHST")
|
||||
: formatCurrency(currentIndex.mul(note.payout), 5, "STNK")
|
||||
}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
|
@ -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
|
||||
<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
|
||||
<Link
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href="https://git.ghostchain.io/ghostchain/ghost-extension-wallet/releases"
|
||||
>
|
||||
GHOST Wallet
|
||||
</Link> 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;
|
@ -68,6 +68,9 @@ const PoolContainer = ({
|
||||
);
|
||||
|
||||
const onSwap = () => {
|
||||
// const oldAmountTop = amountTop;
|
||||
// const oldAmountBottom = amountBottom;
|
||||
// setAmountBottom(oldAmountTop);
|
||||
setAmountTop(amountBottom);
|
||||
onCardsSwap();
|
||||
}
|
||||
|
@ -42,11 +42,6 @@ const TokenModal = ({ chainId, account, listOpen, setListOpen, setTokenAddress }
|
||||
const { balance: stnkBalance } = useBalance(chainId, "STNK", 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(() => {
|
||||
return [{
|
||||
name: searchSymbol,
|
||||
@ -59,31 +54,31 @@ const TokenModal = ({ chainId, account, listOpen, setListOpen, setTokenAddress }
|
||||
const knownTokens = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
name: daiSymbol,
|
||||
name: "gDAI",
|
||||
icons: ["GDAI"],
|
||||
balance: daiBalance,
|
||||
address: DAI_ADDRESSES[chainId]
|
||||
},
|
||||
{
|
||||
name: ftsoSymbol,
|
||||
name: "FTSO",
|
||||
icons: ["FTSO"],
|
||||
balance: ftsoBalance,
|
||||
address: FTSO_ADDRESSES[chainId]
|
||||
},
|
||||
{
|
||||
name: stnkSymbol,
|
||||
name: "STNK",
|
||||
icons: ["STNK"],
|
||||
balance: stnkBalance,
|
||||
address: STNK_ADDRESSES[chainId]
|
||||
},
|
||||
{
|
||||
name: ghstSymbol,
|
||||
name: "GHST",
|
||||
icons: ["GHST"],
|
||||
balance: ghstBalance,
|
||||
address: GHST_ADDRESSES[chainId]
|
||||
}
|
||||
]
|
||||
}, [daiSymbol, ftsoSymbol, stnkSymbol, ghstSymbol, daiBalance, ftsoBalance, stnkBalance, ghstBalance]);
|
||||
}, [daiBalance, ghstBalance, stnkBalance, ghstBalance]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isAddress(userInput)) {
|
||||
|
@ -9,49 +9,33 @@ import Paper from "../../components/Paper/Paper";
|
||||
import SwapCard from "../../components/Swap/SwapCard";
|
||||
import TokenStack from "../../components/TokenStack/TokenStack";
|
||||
import { PrimaryButton } from "../../components/Button";
|
||||
import { Tab, Tabs } from "../../components/Tabs/Tabs";
|
||||
|
||||
import { DAI_ADDRESSES } from "../../constants/addresses";
|
||||
import { DecimalBigNumber } from "../../helpers/DecimalBigNumber";
|
||||
import { formatCurrency, formatNumber } from "../../helpers";
|
||||
|
||||
import {
|
||||
useBalance as useTokenBalance,
|
||||
useTokenSymbol,
|
||||
useTotalSupply,
|
||||
useConversionRate,
|
||||
useAccumulatedDonation,
|
||||
mintDai,
|
||||
burnDai
|
||||
} from "../../hooks/tokens";
|
||||
import { useBalance as useTokenBalance, useConversionRate, mintDai } from "../../hooks/tokens";
|
||||
|
||||
const Faucet = ({ chainId, address, config, connect }) => {
|
||||
const isSmallScreen = useMediaQuery("(max-width: 650px)");
|
||||
const isSemiSmallScreen = useMediaQuery("(max-width: 480px)");
|
||||
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 [balance, setBalance] = useState(new DecimalBigNumber(0, 0));
|
||||
const [amount, setAmount] = useState("");
|
||||
const [faucetToken, setFaucetToken] = useState({
|
||||
name: "",
|
||||
address: "",
|
||||
});
|
||||
const [scanInfo, setScanInfo] = useState({
|
||||
name: "",
|
||||
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(() => {
|
||||
ReactGA.send({ hitType: "pageview", page: "/faucet" });
|
||||
@ -67,71 +51,44 @@ const Faucet = ({ chainId, address, config, connect }) => {
|
||||
let scanName = "";
|
||||
let scanUrl = "";
|
||||
|
||||
const tokenName = "gDAI";
|
||||
const tokenAddress = DAI_ADDRESSES[chainId];
|
||||
|
||||
const client = config?.getClient();
|
||||
scanName = client?.chain?.blockExplorers?.default?.name;
|
||||
scanUrl = client?.chain?.blockExplorers?.default?.url;
|
||||
|
||||
setFaucetToken({
|
||||
name: tokenName,
|
||||
address: tokenAddress,
|
||||
});
|
||||
|
||||
setScanInfo({
|
||||
name: scanName,
|
||||
url: scanUrl,
|
||||
})
|
||||
|
||||
setNativeInfo(client?.chain?.nativeCurrency)
|
||||
}, [chainId]);
|
||||
|
||||
const changeIsMinted = (value) => {
|
||||
if (accumulatedDonation) {
|
||||
setAmount("");
|
||||
setIsMint(value);
|
||||
}
|
||||
}
|
||||
|
||||
const preparedAmount = useMemo(() => {
|
||||
if (address === "") new DecimalBigNumber("0", 0);
|
||||
const decimals = isMint ? nativeInfo.decimals : 18;
|
||||
return new DecimalBigNumber(amount, decimals);
|
||||
}, [amount, balance, nativeInfo])
|
||||
return new DecimalBigNumber(amount, 18);
|
||||
}, [amount, balance])
|
||||
|
||||
const estimatedAmountIn = useMemo(() => {
|
||||
const estimatedAmount = useMemo(() => {
|
||||
const rate = new DecimalBigNumber(daiConversionRate.toString(), 0);
|
||||
const value = new DecimalBigNumber(amount, nativeInfo.decimals);
|
||||
const value = new DecimalBigNumber(amount, 18);
|
||||
return value.mul(rate);
|
||||
}, [amount, daiConversionRate, nativeInfo]);
|
||||
}, [amount, daiConversionRate])
|
||||
|
||||
const contractBalanceFree = useMemo(() => {
|
||||
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 () => {
|
||||
const mintOrConnect = async () => {
|
||||
if (address === "") {
|
||||
connect();
|
||||
} else {
|
||||
setIsPending(true);
|
||||
|
||||
if (isMint) {
|
||||
await mintDai(chainId, address, preparedAmount._value.toString());
|
||||
} else {
|
||||
await burnDai(chainId, address, preparedAmount._value.toString());
|
||||
}
|
||||
|
||||
await balanceRefetch();
|
||||
await daiBalanceRefetch();
|
||||
await contractBalanceRefetch();
|
||||
await refetchReserveTotalSupply();
|
||||
setAmount("");
|
||||
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" />
|
||||
</Helmet>
|
||||
|
||||
<PageTitle name={`${faucetSymbol} Faucet`} subtitle={`Swap Sepolia ${nativeInfo.symbol} for ${faucetSymbol}.`} />
|
||||
<PageTitle name={"gDAI Faucet"} subtitle="Swap Sepolia ETH for gDAI." />
|
||||
<Container
|
||||
style={{
|
||||
paddingLeft: isSmallScreen || isVerySmallScreen ? "0" : "3.3rem",
|
||||
@ -174,21 +131,10 @@ const Faucet = ({ chainId, address, config, connect }) => {
|
||||
<Paper
|
||||
headerContent={
|
||||
<Box alignItems="center" justifyContent="space-between" display="flex" width="100%">
|
||||
<Tabs
|
||||
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>
|
||||
<Typography variant="h4">Get {faucetToken.name}</Typography>
|
||||
{!isSemiSmallScreen && <PrimaryButton
|
||||
variant="text"
|
||||
href={`${scanInfo.url}/token/${DAI_ADDRESSES[chainId]}`}
|
||||
href={`${scanInfo.url}/token/${faucetToken.address}`}
|
||||
>
|
||||
Check on {scanInfo.name}
|
||||
</PrimaryButton>}
|
||||
@ -198,28 +144,16 @@ const Faucet = ({ chainId, address, config, connect }) => {
|
||||
fullWidth
|
||||
>
|
||||
<Box>
|
||||
{isMint && <SwapCard
|
||||
<SwapCard
|
||||
id={`faucet-sepolia-eth`}
|
||||
inputWidth={isVerySmallScreen ? "100px" : isSemiSmallScreen ? "180px" : "250px"}
|
||||
tokenName={nativeInfo.symbol}
|
||||
token={<TokenStack tokens={[nativeInfo.symbol]} sx={{ fontSize: "21px" }} />}
|
||||
info={`${isSemiSmallScreen ? "" : "Balance: "}${formatCurrency(balance.toString(), 4, nativeInfo.symbol)}`}
|
||||
tokenName={"ETH"}
|
||||
token={<TokenStack tokens={["ETH"]} sx={{ fontSize: "21px" }} />}
|
||||
info={`${isSemiSmallScreen ? "" : "Balance: "}${formatCurrency(balance.toString(), 4, "ETH")}`}
|
||||
value={amount}
|
||||
onChange={event => setAmount(event.currentTarget.value)}
|
||||
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
|
||||
mb="20px"
|
||||
mt="20px"
|
||||
@ -227,56 +161,35 @@ const Faucet = ({ chainId, address, config, connect }) => {
|
||||
display="flex"
|
||||
justifyContent="space-between"
|
||||
>
|
||||
{isMint && (
|
||||
<>
|
||||
<Box maxWidth="416px" display="flex" justifyContent={isVerySmallScreen ? "end" : "space-between"}>
|
||||
{!isVerySmallScreen && <Typography fontSize="12px" lineHeight="15px">{nativeInfo.symbol} multiplier:</Typography>}
|
||||
{!isVerySmallScreen && <Typography fontSize="12px" lineHeight="15px">ETH multiplier:</Typography>}
|
||||
<Typography fontSize="12px" lineHeight="15px">{formatNumber(daiConversionRate, 2)}</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(estimatedAmountIn, 5, faucetSymbol)}</Typography>
|
||||
<Typography fontSize="12px" lineHeight="15px">{formatCurrency(estimatedAmount, 5, faucetToken.name)}</Typography>
|
||||
</Box>
|
||||
<Box display="flex" justifyContent={isVerySmallScreen ? "end" : "space-between"}>
|
||||
{!isVerySmallScreen && <Typography fontSize="12px" lineHeight="15px">Your {faucetSymbol} balance:</Typography>}
|
||||
<Typography fontSize="12px" lineHeight="15px">{formatCurrency(daiBalance, 5, faucetSymbol)}</Typography>
|
||||
{!isVerySmallScreen && <Typography fontSize="12px" lineHeight="15px">Your {faucetToken.name} balance:</Typography>}
|
||||
<Typography fontSize="12px" lineHeight="15px">{formatCurrency(daiBalance, 5, faucetToken.name)}</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>
|
||||
<PrimaryButton
|
||||
fullWidth
|
||||
disabled={
|
||||
address !== "" && (
|
||||
preparedAmount?._value === 0n ||
|
||||
isPending ||
|
||||
(isMint && balance?.lt(preparedAmount)) ||
|
||||
(!isMint && daiBalance?.lt(preparedAmount))
|
||||
preparedAmount?.eq(new DecimalBigNumber(0, 18)) ||
|
||||
balance?.lt(preparedAmount) ||
|
||||
isPending
|
||||
)
|
||||
}
|
||||
loading={isPending}
|
||||
onClick={() => actionOrConnect()}
|
||||
onClick={() => mintOrConnect()}
|
||||
>
|
||||
{address === "" ?
|
||||
"Connect"
|
||||
:
|
||||
isMint ? "Mint" : "Burn"
|
||||
"Mint"
|
||||
}
|
||||
</PrimaryButton>
|
||||
</Box>
|
||||
|
@ -28,39 +28,21 @@ const Stake = ({ chainId, address, isOpened, closeModal, connect }) => {
|
||||
case (upperToken === "FTSO" && bottomToken === "STNK"):
|
||||
setAction("STAKE")
|
||||
break;
|
||||
case (upperToken === "eCSPR" && bottomToken === "sCSPR"):
|
||||
setAction("STAKE")
|
||||
break;
|
||||
case (upperToken === "FTSO" && bottomToken === "GHST"):
|
||||
setAction("STAKE")
|
||||
break;
|
||||
case (upperToken === "eCSPR" && bottomToken === "CSPR"):
|
||||
setAction("STAKE")
|
||||
break;
|
||||
case (upperToken === "STNK" && bottomToken === "FTSO"):
|
||||
setAction("UNSTAKE")
|
||||
break;
|
||||
case (upperToken === "sCSPR" && bottomToken === "eCSPR"):
|
||||
setAction("UNSTAKE")
|
||||
break;
|
||||
case (upperToken === "GHST" && bottomToken === "FTSO"):
|
||||
setAction("UNSTAKE")
|
||||
break;
|
||||
case (upperToken === "CSPR" && bottomToken === "eCSPR"):
|
||||
setAction("UNSTAKE")
|
||||
break;
|
||||
case (upperToken === "STNK" && bottomToken === "GHST"):
|
||||
setAction("WRAP")
|
||||
break;
|
||||
case (upperToken === "sCSPR" && bottomToken === "CSPR"):
|
||||
setAction("WRAP")
|
||||
break;
|
||||
case (upperToken === "GHST" && bottomToken === "STNK"):
|
||||
setAction("UNWRAP")
|
||||
break;
|
||||
case (upperToken === "CSPR" && bottomToken === "sCSPR"):
|
||||
setAction("UNWRAP")
|
||||
break;
|
||||
default:
|
||||
setAction("STAKE")
|
||||
}
|
||||
|
@ -16,7 +16,6 @@ import { ClaimsArea } from "./components/ClaimsArea";
|
||||
import { Apy, CurrentIndex, TotalDeposit } from "./components/Metric";
|
||||
|
||||
import { useEpoch } from "../../hooks/staking";
|
||||
import { useTokenSymbol } from "../../hooks/tokens";
|
||||
|
||||
export const StakeContainer = ({ chainId, address, connect }) => {
|
||||
const [isModalOpened, handleModal] = useState(false);
|
||||
@ -25,9 +24,6 @@ export const StakeContainer = ({ chainId, address, connect }) => {
|
||||
const isSmallScreen = useMediaQuery("(max-width: 650px)");
|
||||
const isVerySmallScreen = useMediaQuery("(max-width: 379px)");
|
||||
|
||||
const { symbol: ftsoSymbol } = useTokenSymbol(chainId, "FTSO");
|
||||
const { symbol: stnkSymbol } = useTokenSymbol(chainId, "STNK");
|
||||
|
||||
const { epoch, refetch: refetchEpoch } = useEpoch(chainId);
|
||||
|
||||
useEffect(() => {
|
||||
@ -48,7 +44,7 @@ export const StakeContainer = ({ chainId, address, connect }) => {
|
||||
|
||||
return (
|
||||
<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
|
||||
style={{
|
||||
paddingLeft: isSmallScreen || isVerySmallScreen ? "0" : "3.3rem",
|
||||
@ -75,13 +71,13 @@ export const StakeContainer = ({ chainId, address, connect }) => {
|
||||
>
|
||||
<Grid container spacing={1}>
|
||||
<Grid item xs={isSmallScreen ? 12 : 4}>
|
||||
<Apy stnkSymbol={stnkSymbol} distribute={epoch.distribute} chainId={chainId} />
|
||||
<Apy distribute={epoch.distribute} chainId={chainId} />
|
||||
</Grid>
|
||||
<Grid item xs={isSmallScreen ? 12 : 4}>
|
||||
<TotalDeposit stnkSymbol={stnkSymbol} chainId={chainId} />
|
||||
<TotalDeposit chainId={chainId} />
|
||||
</Grid>
|
||||
<Grid item xs={isSmallScreen ? 12 : 4}>
|
||||
<CurrentIndex ftsoSymbol={ftsoSymbol} chainId={chainId} />
|
||||
<CurrentIndex chainId={chainId} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
|
@ -22,7 +22,7 @@ const ClaimConfirmationModal = (props) => {
|
||||
await forfeit(props.chainId, props.receiver);
|
||||
break;
|
||||
case "CLAIM":
|
||||
await claim(props.chainId, props.receiver, props.outputToken === "STNK" || props.outputToken === "sCSPR");
|
||||
await claim(props.chainId, props.receiver, props.outputToken === "STNK");
|
||||
break;
|
||||
default:
|
||||
console.log("Unknown action")
|
||||
@ -55,7 +55,7 @@ const ClaimConfirmationModal = (props) => {
|
||||
/>
|
||||
<Box display="flex" flexDirection="row" justifyContent="center">
|
||||
<Typography>
|
||||
{props.outputTokenName}
|
||||
{props.outputToken}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
|
@ -28,7 +28,7 @@ import { prettifySecondsInDays } from "../../../helpers/timeUtil";
|
||||
import { formatNumber } from "../../../helpers";
|
||||
import { STAKING_ADDRESSES } from "../../../constants/addresses";
|
||||
import { useCurrentIndex, useWarmupInfo } from "../../../hooks/staking";
|
||||
import { useBalanceForShares, useTokenSymbol } from "../../../hooks/tokens";
|
||||
import { useBalanceForShares } from "../../../hooks/tokens";
|
||||
|
||||
import ClaimConfirmationModal from "./ClaimConfirmationModal";
|
||||
|
||||
@ -61,10 +61,6 @@ export const ClaimsArea = ({ chainId, address, epoch }) => {
|
||||
const { currentIndex, refetch: currentIndexRefetch } = useCurrentIndex(chainId);
|
||||
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 = () => {
|
||||
setConfirmationModalOpen(false);
|
||||
claimRefetch();
|
||||
@ -89,7 +85,6 @@ export const ClaimsArea = ({ chainId, address, epoch }) => {
|
||||
receiver={address}
|
||||
receiveAmount={claim.expiry > epoch.number ? claim.deposit : isPayoutGhst ? balanceForShares.div(currentIndex) : balanceForShares}
|
||||
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"}
|
||||
chainId={chainId}
|
||||
/>
|
||||
@ -103,7 +98,7 @@ export const ClaimsArea = ({ chainId, address, epoch }) => {
|
||||
justifyContent="space-between"
|
||||
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
|
||||
centered
|
||||
textColor="primary"
|
||||
@ -113,8 +108,8 @@ export const ClaimsArea = ({ chainId, address, epoch }) => {
|
||||
onChange={(_, view) => setIsPayoutGhstInner(view === 1)}
|
||||
TabIndicatorProps={{ style: { display: "none" } }}
|
||||
>
|
||||
<Tab aria-label="payout-stnk-button" label={stnkSymbol} style={{ fontSize: "1rem" }} />
|
||||
<Tab aria-label="payout-ghst-button" label={ghstSymbol} style={{ fontSize: "1rem" }} />
|
||||
<Tab aria-label="payout-stnk-button" label="STNK" style={{ fontSize: "1rem" }} />
|
||||
<Tab aria-label="payout-ghst-button" label="GHST" style={{ fontSize: "1rem" }} />
|
||||
</Tabs>
|
||||
</Box>
|
||||
}
|
||||
@ -129,8 +124,6 @@ export const ClaimsArea = ({ chainId, address, epoch }) => {
|
||||
claim={claim}
|
||||
epoch={epoch}
|
||||
isClaimable={claim.expiry > epoch.number}
|
||||
stnkSymbol={stnkSymbol}
|
||||
ghstSymbol={ghstSymbol}
|
||||
/>
|
||||
) : (
|
||||
<Table>
|
||||
@ -149,8 +142,6 @@ export const ClaimsArea = ({ chainId, address, epoch }) => {
|
||||
claim={claim}
|
||||
epoch={epoch}
|
||||
isClaimable={claim.expiry > epoch.number}
|
||||
stnkSymbol={stnkSymbol}
|
||||
ghstSymbol={ghstSymbol}
|
||||
/>
|
||||
</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 (
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell style={{ padding: "8px 8px 8px 0" }}>
|
||||
<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">
|
||||
<Typography>{isPayoutGhst ? ghstSymbol : stnkSymbol}</Typography>
|
||||
<Typography>{isPayoutGhst ? "GHST" : "STNK"}</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</TableCell>
|
||||
<TableCell style={{ padding: "8px 8px 8px 0" }}>
|
||||
<Typography gutterBottom={false} style={{ lineHeight: 1.4 }}>
|
||||
{`${formatNumber(prepareBalance, 5)} ${isPayoutGhst ? ghstSymbol : stnkSymbol}`}
|
||||
{`${formatNumber(prepareBalance, 5)} ${isPayoutGhst ? "GHST" : "STNK"}`}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
<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 (
|
||||
<Box mt="10px">
|
||||
<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">
|
||||
<Typography>{isPayoutGhst ? ghstSymbol : stnkSymbol}</Typography>
|
||||
<Typography>{isPayoutGhst ? "GHST" : "STNK"}</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
|
@ -18,7 +18,7 @@ import { DecimalBigNumber } from "../../../helpers/DecimalBigNumber";
|
||||
import { formatCurrency } from "../../../helpers";
|
||||
|
||||
import { useLpValuation } from "../../../hooks/treasury";
|
||||
import { useTotalSupply, useTokenSymbol } from "../../../hooks/tokens";
|
||||
import { useTotalSupply } from "../../../hooks/tokens";
|
||||
|
||||
import {
|
||||
DAI_ADDRESSES,
|
||||
@ -31,13 +31,10 @@ const FarmPools = ({ chainId }) => {
|
||||
const { totalSupply: daiFtsoUniTotalSupply } = useTotalSupply(chainId, "GDAI_FTSO");
|
||||
const daiFtsoUniValuation = useLpValuation(chainId, "GDAI_FTSO", daiFtsoUniTotalSupply._value);
|
||||
|
||||
const { symbol: daiSymbol } = useTokenSymbol(chainId, "GDAI");
|
||||
const { symbol: ftsoSymbol } = useTokenSymbol(chainId, "FTSO");
|
||||
|
||||
const pools = [
|
||||
{
|
||||
icons: ["FTSO", "GDAI"],
|
||||
name: `${ftsoSymbol}-${daiSymbol}`,
|
||||
name: "FTSO-gDAI",
|
||||
dex: "Uniswap V2",
|
||||
url: "/dex/uniswap",
|
||||
tvl: daiFtsoUniValuation,
|
||||
@ -64,7 +61,7 @@ const FarmPools = ({ chainId }) => {
|
||||
return (
|
||||
<Paper headerText="Farm Pools" fullWidth enableBackground>
|
||||
<TableContainer>
|
||||
<Table aria-label="Farm pools" style={{ tableLayout: "fixed" }}>
|
||||
<Table aria-label="Available bonds" style={{ tableLayout: "fixed" }}>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell style={{ padding: "8px 0", width: "30%" }}>Asset</TableCell>
|
||||
|
@ -13,7 +13,7 @@ export const CurrentIndex = props => {
|
||||
const _props = {
|
||||
...props,
|
||||
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)}`;
|
||||
@ -35,7 +35,7 @@ export const Apy = props => {
|
||||
const _props = {
|
||||
...props,
|
||||
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 STNK’s exponential rebasing.",
|
||||
};
|
||||
|
||||
if (apy) _props.metric = `${formatNumber(apy, 2)}${apy === Infinity ? "" : "%"}`;
|
||||
@ -52,7 +52,7 @@ export const TotalDeposit = props => {
|
||||
const _props = {
|
||||
...props,
|
||||
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)}`;
|
||||
|
@ -39,7 +39,7 @@ const StakeConfirmationModal = (props) => {
|
||||
checkedIcon={<CheckBoxOutlined viewBox="0 0 24 24" />}
|
||||
/>
|
||||
}
|
||||
label={`I understand the ${props.ftsoSymbol} I’m staking will only be available to claim ${warmupLength.toString()} epochs after my transaction is confirmed`}
|
||||
label={`I understand the FTSO (eGHST) I’m staking will only be available to claim ${warmupLength.toString()} epochs after my transaction is confirmed`}
|
||||
/>
|
||||
</Box>
|
||||
</>
|
||||
@ -115,7 +115,7 @@ const StakeConfirmationModal = (props) => {
|
||||
/>
|
||||
<Box display="flex" flexDirection="row" justifyContent="center">
|
||||
<Typography>
|
||||
{props.upperToken === "FTSO" ? props.ftsoSymbol : props.upperToken === "STNK" ? props.stnkSymbol : props.ghstSymbol}
|
||||
{props.upperToken}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
@ -127,7 +127,7 @@ const StakeConfirmationModal = (props) => {
|
||||
/>
|
||||
<Box display="flex" flexDirection="row" justifyContent="center">
|
||||
<Typography>
|
||||
{props.bottomToken === "FTSO" ? props.ftsoSymbol : props.bottomToken === "STNK" ? props.stnkSymbol : props.ghstSymbol}
|
||||
{props.bottomToken}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
@ -141,7 +141,7 @@ const StakeConfirmationModal = (props) => {
|
||||
owner={props.address}
|
||||
spender={STAKING_ADDRESSES[props.chainId]}
|
||||
decimals={props.spendDecimals}
|
||||
approvalText={"Approve " + props.upperToken === "FTSO" ? props.ftsoSymbol : props.upperToken === "STNK" ? props.stnkSymbol : props.ghstSymbol}
|
||||
approvalText={"Approve " + props.upperToken}
|
||||
approvalPendingText={"Approving..."}
|
||||
connect={props.connect}
|
||||
isVertical
|
||||
|
@ -23,7 +23,7 @@ import {
|
||||
STAKING_ADDRESSES,
|
||||
} from "../../../constants/addresses";
|
||||
import { useCurrentIndex } from "../../../hooks/staking";
|
||||
import { useBalance, useTokenSymbol } from "../../../hooks/tokens";
|
||||
import { useBalance } from "../../../hooks/tokens";
|
||||
import { formatNumber } from "../../../helpers";
|
||||
|
||||
const PREFIX = "StakeInputArea";
|
||||
@ -106,10 +106,6 @@ export const StakeInputArea = ({
|
||||
const { balance: stnkBalance, refetch: stnkRefetch } = useBalance(chainId, "STNK", 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) => {
|
||||
setIsClaim(value);
|
||||
localStorage.setItem("stake-isClaim", value);
|
||||
@ -185,37 +181,15 @@ export const StakeInputArea = ({
|
||||
}
|
||||
|
||||
const SwapCardTemplate = (tokenName, tokenAmount, isUpper, handleModal) => {
|
||||
const balance = tokenName === "STNK" || tokenName === "sCSPR" ?
|
||||
stnkBalance : tokenName === "FTSO" || tokenName === "eCSPR" ?
|
||||
const balance = tokenName === "STNK" ?
|
||||
stnkBalance : tokenName === "FTSO" ?
|
||||
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 (
|
||||
<SwapCard
|
||||
id={`${tokenName.toLowerCase()}-input`}
|
||||
token={tokenName}
|
||||
tokenName={realTokenName}
|
||||
tokenName={tokenName}
|
||||
tokenOnClick={() => handleModal(true)}
|
||||
inputProps={{ "data-testid": `${tokenName.toLowerCase()}-input`, min: "0" }}
|
||||
value={tokenAmount}
|
||||
@ -254,30 +228,24 @@ export const StakeInputArea = ({
|
||||
{upperTokenModalOpen && (
|
||||
<TokenModal
|
||||
open={upperTokenModalOpen}
|
||||
handleSelect={data => handleTokenModalInput(data.token, data.isUpper)}
|
||||
handleSelect={data => handleTokenModalInput(data.name, data.isUpper)}
|
||||
handleClose={() => setUpperTokenModalOpen(false)}
|
||||
ftsoBalance={formatNumber(ftsoBalance, formatDecimals)}
|
||||
stnkBalance={formatNumber(stnkBalance, formatDecimals)}
|
||||
ghstBalance={formatNumber(ghstBalance, formatDecimals)}
|
||||
isUpper={true}
|
||||
ftsoSymbol={ftsoSymbol}
|
||||
stnkSymbol={stnkSymbol}
|
||||
ghstSymbol={ghstSymbol}
|
||||
/>
|
||||
)}
|
||||
{bottomTokenModalOpen && (
|
||||
<TokenModal
|
||||
open={bottomTokenModalOpen}
|
||||
handleSelect={data => handleTokenModalInput(data.token, data.isUpper)}
|
||||
handleSelect={data => handleTokenModalInput(data.name, data.isUpper)}
|
||||
handleClose={() => setBottomTokenModalOpen(false)}
|
||||
ftsoBalance={formatNumber(ftsoBalance, formatDecimals)}
|
||||
stnkBalance={formatNumber(stnkBalance, formatDecimals)}
|
||||
ghstBalance={formatNumber(ghstBalance, formatDecimals)}
|
||||
tokenToExclude={upperToken}
|
||||
isUpper={false}
|
||||
ftsoSymbol={ftsoSymbol}
|
||||
stnkSymbol={stnkSymbol}
|
||||
ghstSymbol={ghstSymbol}
|
||||
/>
|
||||
)}
|
||||
|
||||
@ -324,9 +292,6 @@ export const StakeInputArea = ({
|
||||
receiveDecimals={bottomToken === "GHST" ? 18 : 9}
|
||||
isClaim={isClaim}
|
||||
isTrigger={isTrigger}
|
||||
ftsoSymbol={ftsoSymbol}
|
||||
stnkSymbol={stnkSymbol}
|
||||
ghstSymbol={ghstSymbol}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
@ -13,23 +13,20 @@ const TokenModal = ({
|
||||
ghstBalance = "0.00",
|
||||
tokenToExclude,
|
||||
isUpper,
|
||||
ftsoSymbol,
|
||||
stnkSymbol,
|
||||
ghstSymbol
|
||||
}) => {
|
||||
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) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
return (
|
||||
<ListItem
|
||||
key={token}
|
||||
button="true"
|
||||
key={name}
|
||||
button
|
||||
onClick={() => {
|
||||
handleSelect({token, isUpper});
|
||||
handleSelect({name, isUpper});
|
||||
handleClose();
|
||||
}}
|
||||
sx={{ borderBottom: `1px solid ${theme.colors.gray[500]}` }}
|
||||
@ -38,7 +35,7 @@ const TokenModal = ({
|
||||
{icon ? (
|
||||
<Avatar src={icon} sx={{ width: "15px", height: "15px" }} />
|
||||
) : (
|
||||
<Token name={token} sx={{ fontSize: "15px" }} />
|
||||
<Token name={name} sx={{ fontSize: "15px" }} />
|
||||
)}
|
||||
|
||||
<ListItemText
|
||||
@ -69,9 +66,9 @@ const TokenModal = ({
|
||||
</Link>
|
||||
</Box>
|
||||
<List>
|
||||
{<TokenItem isUpper={isUpper} exclude={tokenToExclude} token="FTSO" name={ftsoSymbol} balance={ftsoBalance} />}
|
||||
{<TokenItem isUpper={isUpper} exclude={tokenToExclude} token="STNK" name={stnkSymbol} balance={stnkBalance} />}
|
||||
{<TokenItem isUpper={isUpper} exclude={tokenToExclude} token="GHST" name={ghstSymbol} balance={ghstBalance} />}
|
||||
{<TokenItem isUpper={isUpper} exclude={tokenToExclude} name="FTSO" balance={ftsoBalance} />}
|
||||
{<TokenItem isUpper={isUpper} exclude={tokenToExclude} name="STNK" balance={stnkBalance} />}
|
||||
{<TokenItem isUpper={isUpper} exclude={tokenToExclude} name="GHST" balance={ghstBalance} />}
|
||||
</List>
|
||||
</Box>
|
||||
</Dialog>
|
||||
|
@ -17,17 +17,11 @@ import Paper from "../../components/Paper/Paper";
|
||||
import PageTitle from "../../components/PageTitle/PageTitle";
|
||||
import SafariFooter from "../../components/SafariFooter/SafariFooter";
|
||||
|
||||
import { useTokenSymbol } from "../../hooks/tokens";
|
||||
|
||||
const MetricsDashboard = ({ chainId }) => {
|
||||
const theme = useTheme();
|
||||
const isMobileScreen = useMediaQuery("(max-width: 885px)");
|
||||
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(() => {
|
||||
return isMobileScreen ? isVeryMobileScreen ? 12 : 6 : 4;
|
||||
}, [isMobileScreen, isVeryMobileScreen])
|
||||
@ -39,22 +33,22 @@ const MetricsDashboard = ({ chainId }) => {
|
||||
<Paper fullWidth enableBackground>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={xsCalculator}>
|
||||
<TreasuryMarketCap ftsoSymbol={ftsoSymbol} chainId={chainId} />
|
||||
<TreasuryMarketCap chainId={chainId} />
|
||||
</Grid>
|
||||
<Grid item xs={xsCalculator}>
|
||||
<FatsoPrice ftsoSymbol={ftsoSymbol} chainId={chainId} />
|
||||
<FatsoPrice chainId={chainId} />
|
||||
</Grid>
|
||||
<Grid item xs={xsCalculator}>
|
||||
<GhostPrice ghstSymbol={ghstSymbol} ftsoSymbol={ftsoSymbol} chainId={chainId} />
|
||||
<GhostPrice chainId={chainId} />
|
||||
</Grid>
|
||||
<Grid item xs={xsCalculator}>
|
||||
<CirculatingSupply stnkSymbol={stnkSymbol} chainId={chainId} />
|
||||
<CirculatingSupply chainId={chainId} />
|
||||
</Grid>
|
||||
<Grid item xs={xsCalculator}>
|
||||
<FatsoBacking ftsoSymbol={ftsoSymbol} chainId={chainId} />
|
||||
<FatsoBacking chainId={chainId} />
|
||||
</Grid>
|
||||
<Grid item xs={xsCalculator}>
|
||||
<CurrentIndex ftsoSymbol={ftsoSymbol} chainId={chainId} />
|
||||
<CurrentIndex chainId={chainId} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Paper>
|
||||
|
@ -15,10 +15,10 @@ export const CurrentIndex = props => {
|
||||
const _props = {
|
||||
...props,
|
||||
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;
|
||||
|
||||
return <Metric {..._props} />;
|
||||
@ -31,8 +31,8 @@ export const GhostPrice = props => {
|
||||
|
||||
const _props = {
|
||||
...props,
|
||||
label: `${props.ghstSymbol} Price`,
|
||||
tooltip: `1 ${props.ghstSymbol} = 1 ${props.ftsoSymbol} x Current Index`,
|
||||
label: "GHST " + `Price`,
|
||||
tooltip: "1 GHST = 1 FTSO x Current Index",
|
||||
};
|
||||
|
||||
if (ghstPrice) _props.metric = formatCurrency(ghstPrice, 2);
|
||||
@ -46,8 +46,8 @@ export const FatsoPrice = props => {
|
||||
|
||||
const _props = {
|
||||
...props,
|
||||
label: `${props.ftsoSymbol} Price`,
|
||||
tooltip: `Weighted ${props.ftsoSymbol} Price Across V2 DEXs on the chosen EVM Chain`,
|
||||
label: "FTSO " + `Price`,
|
||||
tooltip: `Weighted FTSO Price Across V2 DEXs on the chosen EVM Chain`,
|
||||
};
|
||||
|
||||
if (ftsoPrice) _props.metric = formatCurrency(ftsoPrice, 2);
|
||||
@ -63,7 +63,7 @@ export const CirculatingSupply = props => {
|
||||
const _props = {
|
||||
...props,
|
||||
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)}`;
|
||||
@ -83,8 +83,8 @@ export const FatsoBacking = props => {
|
||||
|
||||
const _props = {
|
||||
...props,
|
||||
label: `Backing per ${props.ftsoSymbol}`,
|
||||
tooltip: `The total amount of stablecoins held by the ghostDAO treasury to support the value of each ${props.ftsoSymbol} in circulation.`
|
||||
label: `Backing per FTSO`,
|
||||
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);
|
||||
@ -101,7 +101,7 @@ export const TreasuryMarketCap = props => {
|
||||
const _props = {
|
||||
...props,
|
||||
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);
|
||||
|
@ -7,7 +7,7 @@ import { SecondaryButton } from "../../../components/Button";
|
||||
import { formatNumber, formatCurrency } from "../../../helpers";
|
||||
import { DecimalBigNumber } from "../../../helpers/DecimalBigNumber";
|
||||
|
||||
import { useBalance, useTokenSymbol } from "../../../hooks/tokens";
|
||||
import { useBalance } from "../../../hooks/tokens";
|
||||
import {
|
||||
useFtsoPrice,
|
||||
useStnkPrice,
|
||||
@ -79,11 +79,6 @@ const TokenInfo = ({ chainId, isMobileScreen }) => {
|
||||
const ghstPrice = useGhstPrice(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: stnkBalance, contractAddress: stnkAddress } = useBalance(chainId, "STNK", address);
|
||||
const { balance: ghstBalance, contractAddress: ghstAddress } = useBalance(chainId, "GHST", address);
|
||||
@ -100,10 +95,10 @@ const TokenInfo = ({ chainId, isMobileScreen }) => {
|
||||
to: `${ftsoAddress}`,
|
||||
})}
|
||||
theme={theme}
|
||||
tokenName={ftsoSymbol}
|
||||
tokenName="FTSO"
|
||||
balance={ftsoBalance}
|
||||
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
|
||||
isMobileScreen={isMobileScreen}
|
||||
@ -113,10 +108,10 @@ const TokenInfo = ({ chainId, isMobileScreen }) => {
|
||||
to: `${stnkAddress}`,
|
||||
})}
|
||||
theme={theme}
|
||||
tokenName={stnkSymbol}
|
||||
tokenName="STNK"
|
||||
balance={stnkBalance}
|
||||
price={stnkPrice}
|
||||
description={`${stnkSymbol} is a receipt for staked ${ftsoSymbol}, growing with staking rewards. When unstaked, it’s burned for ${ftsoSymbol} at a 1:1 ratio.`}
|
||||
description="STNK is a receipt for staked FTSO, growing with staking rewards. When unstaked, it’s burned for FTSO at a 1:1 ratio."
|
||||
/>
|
||||
<TokenTab
|
||||
isMobileScreen={isMobileScreen}
|
||||
@ -126,20 +121,20 @@ const TokenInfo = ({ chainId, isMobileScreen }) => {
|
||||
to: `${ghstAddress}`,
|
||||
})}
|
||||
theme={theme}
|
||||
tokenName={ghstSymbol}
|
||||
tokenName="GHST"
|
||||
balance={ghstBalance}
|
||||
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
|
||||
isMobileScreen={isMobileScreen}
|
||||
tokenUrl="/faucet"
|
||||
tokenUrlParams=""
|
||||
theme={theme}
|
||||
tokenName={daiSymbol}
|
||||
tokenName="gDAI"
|
||||
balance={daiBalance}
|
||||
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>
|
||||
</Grid>
|
||||
|
@ -14,8 +14,7 @@ import { abi as TreasuryAbi } from "../../abi/GhostTreasury.json";
|
||||
import { abi as BondingCalculatorAbi } from "../../abi/GhostBondingCalculator.json";
|
||||
|
||||
import { useFtsoPrice } from "../prices";
|
||||
import { useTokenSymbol, useTokenSymbols } from "../tokens";
|
||||
import { getTokenAddress, getTokenIcons, getBondNameDisplayName, getTokenPurchaseLink } from "../helpers";
|
||||
import { getTokenAddress, getTokenIcons, getTokenName, getBondNameDisplayName, getTokenPurchaseLink } from "../helpers";
|
||||
import { DecimalBigNumber } from "../../helpers/DecimalBigNumber";
|
||||
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 id = Number(bondIndex);
|
||||
|
||||
@ -123,7 +119,6 @@ export const useLiveBonds = (chainId) => {
|
||||
const markdown = markdowns?.at(index).result
|
||||
? new DecimalBigNumber(markdowns.at(index).result, quoteTokenDecimals)
|
||||
: new DecimalBigNumber(1n, 0);
|
||||
const quoteTokenSymbol = quoteTokenSymbols?.at(index).result ? quoteTokenSymbols.at(index).result : "";
|
||||
|
||||
const quoteTokenPerBaseToken = new DecimalBigNumber(marketPrice, 9);
|
||||
const priceInUsd = quoteTokenPerUsd.mul(quoteTokenPerBaseToken).mul(markdown);
|
||||
@ -145,20 +140,19 @@ export const useLiveBonds = (chainId) => {
|
||||
);
|
||||
|
||||
const zero = new DecimalBigNumber(0n, 0);
|
||||
const bondName = `${baseTokenSymbol}/${quoteTokenSymbol}`;
|
||||
|
||||
return {
|
||||
id,
|
||||
discount,
|
||||
displayName: getBondNameDisplayName(chainId, bondName, quoteTokenAddress),
|
||||
displayName: getBondNameDisplayName(chainId, markets?.at(index).result?.at(1)),
|
||||
baseToken: {
|
||||
name: quoteTokenSymbol,
|
||||
name: "FTSO",
|
||||
purchaseUrl: getTokenPurchaseLink(chainId, ""),
|
||||
icons: ["FTSO"],
|
||||
tokenAddress: getTokenAddress(chainId, "FTSO")
|
||||
},
|
||||
quoteToken: {
|
||||
name: quoteTokenName,
|
||||
name: getTokenName(chainId, quoteTokenAddress),
|
||||
purchaseUrl: getTokenPurchaseLink(chainId, quoteTokenAddress),
|
||||
icons: getTokenIcons(chainId, quoteTokenAddress),
|
||||
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 id = Number(noteIndex);
|
||||
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 {
|
||||
id,
|
||||
quoteToken: {
|
||||
name: quoteTokenSymbol,
|
||||
name: getTokenName(chainId, quoteTokenAddress),
|
||||
icons: getTokenIcons(chainId, quoteTokenAddress),
|
||||
},
|
||||
vesting: terms?.at(index).result?.at(2) ? terms.at(index).result.at(2) : 0,
|
||||
|
@ -12,98 +12,59 @@ import { abi as StinkyAbi } from "../abi/Stinky.json";
|
||||
import { abi as GhostAbi } from "../abi/Ghost.json";
|
||||
import { abi as Erc20Abi } from "../abi/ERC20.json";
|
||||
|
||||
// TBD: should be extended on new tokens
|
||||
export const getTokenAbi = (name) => {
|
||||
let abi = Erc20Abi;
|
||||
switch (name?.toUpperCase()) {
|
||||
case "DAI":
|
||||
abi = DaiAbi;
|
||||
break;
|
||||
case "GDAI":
|
||||
abi = DaiAbi;
|
||||
break;
|
||||
case "FTSO":
|
||||
abi = FatsoAbi;
|
||||
break;
|
||||
case "ECSPR":
|
||||
abi = FatsoAbi;
|
||||
break;
|
||||
case "STNK":
|
||||
abi = StinkyAbi;
|
||||
break;
|
||||
case "SCSPR":
|
||||
abi = StinkyAbi;
|
||||
break;
|
||||
case "GHST":
|
||||
abi = GhostAbi;
|
||||
break;
|
||||
case "CSPR":
|
||||
abi = GhostAbi;
|
||||
break;
|
||||
}
|
||||
return abi;
|
||||
}
|
||||
|
||||
// TBD: should be extended on new tokens
|
||||
export const getTokenDecimals = (name) => {
|
||||
let decimals = 18;
|
||||
switch (name?.toUpperCase()) {
|
||||
case "DAI":
|
||||
decimals = 18;
|
||||
break;
|
||||
case "GDAI":
|
||||
decimals = 18;
|
||||
break;
|
||||
case "FTSO":
|
||||
decimals = 9;
|
||||
break;
|
||||
case "ECSPR":
|
||||
decimals = 9;
|
||||
break;
|
||||
case "STNK":
|
||||
decimals = 9;
|
||||
break;
|
||||
case "SCSPR":
|
||||
decimals = 9;
|
||||
break;
|
||||
case "GHST":
|
||||
decimals = 18;
|
||||
break;
|
||||
case "CSPR":
|
||||
decimals = 18;
|
||||
break;
|
||||
}
|
||||
return decimals;
|
||||
}
|
||||
|
||||
// TBD: should be extended on new tokens
|
||||
export const getTokenAddress = (chainId, name) => {
|
||||
let address = name;
|
||||
switch (name?.toUpperCase()) {
|
||||
case "DAI":
|
||||
address = DAI_ADDRESSES[chainId];
|
||||
break;
|
||||
case "GDAI":
|
||||
address = DAI_ADDRESSES[chainId];
|
||||
break;
|
||||
case "FTSO":
|
||||
address = FTSO_ADDRESSES[chainId];
|
||||
break;
|
||||
case "ECSPR":
|
||||
address = FTSO_ADDRESSES[chainId];
|
||||
break;
|
||||
case "STNK":
|
||||
address = STNK_ADDRESSES[chainId];
|
||||
break;
|
||||
case "SCSPR":
|
||||
address = STNK_ADDRESSES[chainId];
|
||||
break;
|
||||
case "GHST":
|
||||
address = GHST_ADDRESSES[chainId];
|
||||
break;
|
||||
case "CSPR":
|
||||
address = GHST_ADDRESSES[chainId];
|
||||
break;
|
||||
case "GDAI_FTSO":
|
||||
address = FTSO_DAI_LP_ADDRESSES[chainId];
|
||||
break;
|
||||
@ -111,7 +72,6 @@ export const getTokenAddress = (chainId, name) => {
|
||||
return address;
|
||||
}
|
||||
|
||||
// TBD: should be extended on new tokens
|
||||
export const getTokenIcons = (chainId, address) => {
|
||||
let icons = [""];
|
||||
switch (address) {
|
||||
@ -134,11 +94,39 @@ export const getTokenIcons = (chainId, address) => {
|
||||
return icons;
|
||||
}
|
||||
|
||||
export const getBondNameDisplayName = (chainId, stringValue, tokenAddress) => {
|
||||
if (tokenAddress.toUpperCase() === FTSO_DAI_LP_ADDRESSES[chainId].toUpperCase()) {
|
||||
stringValue = `LP ${stringValue}`;
|
||||
export const getTokenName = (chainId, address) => {
|
||||
let name = "";
|
||||
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) => {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { useReadContract } from "wagmi";
|
||||
|
||||
import { useCurrentIndex, useGhostedSupply } from "../staking";
|
||||
import { useCurrentIndex } from "../staking";
|
||||
import { useUniswapV2PairReserves } from "../uniswapv2";
|
||||
import { DecimalBigNumber } from "../../helpers/DecimalBigNumber";
|
||||
import { FTSO_DAI_LP_ADDRESSES, DAI_ADDRESSES, FTSO_ADDRESSES } from "../../constants/addresses";
|
||||
@ -20,19 +20,13 @@ export const useFtsoPrice = (chainId) => {
|
||||
"GDAI",
|
||||
);
|
||||
|
||||
const reserveAddress = DAI_ADDRESSES[chainId];
|
||||
const ftsoAddress = FTSO_ADDRESSES[chainId];
|
||||
if (!reserveAddress || !ftsoAddress) {
|
||||
return new DecimalBigNumber(0n, 9);
|
||||
}
|
||||
|
||||
const stableReserves = reserveAddress.toUpperCase() === tokens.token0.toUpperCase()
|
||||
const stableReserves = DAI_ADDRESSES[chainId].toUpperCase() === tokens.token0.toUpperCase()
|
||||
? 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
|
||||
: ftsoAddress.toUpperCase() === tokens.token1.toUpperCase() ? reserves.reserve1._value : 0n;
|
||||
: FTSO_ADDRESSES[chainId].toUpperCase() === tokens.token1.toUpperCase() ? reserves.reserve1._value : 0n;
|
||||
|
||||
let price = 0n
|
||||
if (ftsoReserves > 0n)
|
||||
@ -52,10 +46,3 @@ export const useGhstPrice = (chainId) => {
|
||||
|
||||
return ftsoPrice.mul(currentIndex);
|
||||
};
|
||||
|
||||
export const useGhostedSupplyPrice = (chainId) => {
|
||||
const ghstPrice = useGhstPrice(chainId);
|
||||
const ghostedSupply = useGhostedSupply(chainId);
|
||||
|
||||
return ghstPrice.mul(ghostedSupply);
|
||||
}
|
||||
|
@ -83,36 +83,6 @@ export const useWarmupInfo = (chainId, address) => {
|
||||
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) => {
|
||||
const args = [
|
||||
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 (
|
||||
chainId,
|
||||
functionName,
|
||||
@ -259,11 +211,8 @@ const executeOnChainTransaction = async (
|
||||
});
|
||||
|
||||
toast.success(messages.successMsg);
|
||||
|
||||
return txHash;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
toast.error(messages.errorMsg)
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
@ -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 toast from "react-hot-toast";
|
||||
|
||||
@ -72,23 +72,6 @@ export const useTokenSymbol = (chainId, name) => {
|
||||
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) => {
|
||||
const contractAddress = getTokenAddress(chainId, name);
|
||||
const { data: rateRaw } = useReadContract({
|
||||
@ -105,22 +88,6 @@ export const useConversionRate = (chainId, name) => {
|
||||
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) => {
|
||||
const contractAddress = getTokenAddress(chainId, name);
|
||||
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.")
|
||||
}
|
||||
}
|
||||
|
||||
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.")
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ const queryClient = new QueryClient();
|
||||
const TRACKING_ID = import.meta.env.VITE_APP_TRACKING_ID;
|
||||
ReactGA.initialize(TRACKING_ID);
|
||||
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')).render(
|
||||
<>
|
||||
<BackgroundCanvas />
|
||||
|
@ -18,7 +18,7 @@ export const darkPalette = {
|
||||
success: "#60C45B", // idk where this is - done
|
||||
userFeedback: "#49A1F2", // idk where this is
|
||||
error: "#F06F73", // red negative % - done
|
||||
warning: "#49A1F2", // idk where this is - done
|
||||
warning: "#F06F73", // idk where this is - done
|
||||
pnlGain: "#60C45B", // green positive % - done
|
||||
},
|
||||
gray: {
|
||||
|
Loading…
Reference in New Issue
Block a user