support for native reserve added; e.g. mordor testnet
Signed-off-by: Uncle Fatso <uncle.fatso@ghostchain.io>
This commit is contained in:
parent
e6ed1596ef
commit
494df5f139
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "ghost-dao-interface",
|
||||
"private": true,
|
||||
"version": "0.2.16",
|
||||
"version": "0.3.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@ -14,7 +14,7 @@ import Sidebar from "./components/Sidebar/Sidebar";
|
||||
import TopBar from "./components/TopBar/TopBar";
|
||||
|
||||
import { shouldTriggerSafetyCheck } from "./helpers";
|
||||
import { isNetworkAvailable } from "./constants";
|
||||
import { isNetworkAvailable, isNetworkLegacy } from "./constants";
|
||||
import useTheme from "./hooks/useTheme";
|
||||
import { useUnstableProvider } from "./hooks/ghost";
|
||||
import { dark as darkTheme } from "./themes/dark.js";
|
||||
@ -27,6 +27,7 @@ const BondModalContainer = lazy(() => import("./containers/Bond/BondModal"));
|
||||
const StakeContainer = lazy(() => import("./containers/Stake/StakeContainer"));
|
||||
const TreasuryDashboard = lazy(() => import("./containers/TreasuryDashboard/TreasuryDashboard"));
|
||||
const Faucet = lazy(() => import("./containers/Faucet/Faucet"));
|
||||
const Wrapper = lazy(() => import("./containers/WethWrapper/WethWrapper"));
|
||||
const Dex = lazy(() => import("./containers/Dex/Dex"));
|
||||
const Bridge = lazy(() => import("./containers/Bridge/Bridge"));
|
||||
const NotFound = lazy(() => import("./containers/NotFound/NotFound"));
|
||||
@ -206,7 +207,10 @@ function App() {
|
||||
<Route path="/bonds" element={<Bonds connect={tryConnectInjected} address={address} chainId={addressChainId ? addressChainId : chainId} />} />
|
||||
<Route path="/bonds/:id" element={<BondModalContainer connect={tryConnectInjected} address={address} chainId={addressChainId ? addressChainId : chainId} />} />
|
||||
<Route path="/stake" element={<StakeContainer connect={tryConnectInjected} address={address} chainId={addressChainId ? addressChainId : chainId}/>} />
|
||||
<Route path="/faucet" element={<Faucet config={config} connect={tryConnectInjected} address={address} chainId={addressChainId ? addressChainId : chainId} />} />
|
||||
{isNetworkLegacy(chainId)
|
||||
? <Route path="/faucet" element={<Faucet config={config} connect={tryConnectInjected} address={address} chainId={addressChainId ? addressChainId : chainId} />} />
|
||||
: <Route path="/wrapper" element={<Wrapper 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
1
src/abi/WETH9.json
Normal file
1
src/abi/WETH9.json
Normal file
@ -0,0 +1 @@
|
||||
{"abi":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"src","type":"address"},{"indexed":true,"internalType":"address","name":"guy","type":"address"},{"indexed":false,"internalType":"uint256","name":"wad","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"dst","type":"address"},{"indexed":false,"internalType":"uint256","name":"wad","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"src","type":"address"},{"indexed":true,"internalType":"address","name":"dst","type":"address"},{"indexed":false,"internalType":"uint256","name":"wad","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"src","type":"address"},{"indexed":false,"internalType":"uint256","name":"wad","type":"uint256"}],"name":"Withdrawal","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"guy","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]}
|
||||
@ -37,7 +37,7 @@ import BondIcon from "../Icon/BondIcon";
|
||||
import StakeIcon from "../Icon/StakeIcon";
|
||||
import WrapIcon from "../Icon/WrapIcon";
|
||||
|
||||
import { isNetworkAvailable } from "../../constants";
|
||||
import { isNetworkAvailable, isNetworkLegacy } from "../../constants";
|
||||
import { AVAILABLE_DEXES } from "../../constants/dexes";
|
||||
import { ECOSYSTEM } from "../../constants/ecosystem";
|
||||
import { DecimalBigNumber } from "../../helpers/DecimalBigNumber";
|
||||
@ -46,6 +46,7 @@ import BondDiscount from "../../containers/Bond/components/BondDiscount";
|
||||
|
||||
import DashboardIcon from '@mui/icons-material/Dashboard';
|
||||
import ShowerIcon from '@mui/icons-material/Shower';
|
||||
import WifiProtectedSetupIcon from '@mui/icons-material/WifiProtectedSetup';
|
||||
|
||||
import { useTokenSymbol } from "../../hooks/tokens";
|
||||
import { useFtsoPrice, useGhstPrice, useGhostedSupplyPrice } from "../../hooks/prices";
|
||||
@ -148,7 +149,10 @@ const NavContent = ({ chainId, addressChainId }) => {
|
||||
}
|
||||
/>
|
||||
<NavItem icon={StakeIcon} label={`Stake`} to="/stake" />
|
||||
<NavItem icon={ShowerIcon} label={`Faucet`} to="/faucet" />
|
||||
{isNetworkLegacy(chainId)
|
||||
? <NavItem icon={ShowerIcon} label={`Faucet`} to="/faucet" />
|
||||
: <NavItem icon={WifiProtectedSetupIcon} label={`Wrapper`} to="/wrapper" />
|
||||
}
|
||||
<NavItem icon={PublicIcon} label={`Bridge`} to="/bridge" />
|
||||
<NavItem
|
||||
icon={CurrencyExchangeIcon}
|
||||
|
||||
@ -57,6 +57,9 @@ const Token = ({ name, viewBox = "0 0 260 260", fontSize = "large", ...props })
|
||||
case "WETH":
|
||||
icon = WethIcon;
|
||||
break;
|
||||
case "METC":
|
||||
icon = WethIcon;
|
||||
break;
|
||||
default:
|
||||
icon = UnknownIcon;
|
||||
}
|
||||
|
||||
@ -1,8 +1,28 @@
|
||||
import { defineChain } from 'viem'
|
||||
import { http, fallback, createConfig } from 'wagmi'
|
||||
import { sepolia, hoodi } from 'wagmi/chains'
|
||||
|
||||
const mordor = defineChain({
|
||||
id: 63,
|
||||
name: 'Mordor',
|
||||
nativeCurrency: {
|
||||
decimals: 18,
|
||||
name: 'METC',
|
||||
symbol: 'METC',
|
||||
},
|
||||
rpcUrls: {
|
||||
default: { http: ['https://rpc.mordor.etccooperative.org'] },
|
||||
},
|
||||
blockExplorers: {
|
||||
default: {
|
||||
name: 'Blockscout',
|
||||
url: 'https://etc-mordor.blockscout.com/'
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
export const config = createConfig({
|
||||
chains: [sepolia, hoodi],
|
||||
chains: [sepolia, hoodi, mordor],
|
||||
transports: {
|
||||
[sepolia.id]: fallback([
|
||||
http('https://ethereum-sepolia-rpc.publicnode.com'),
|
||||
@ -16,6 +36,9 @@ export const config = createConfig({
|
||||
[hoodi.id]: fallback([
|
||||
http('https://rpc.hoodi.ethpandaops.io'),
|
||||
http('https://0xrpc.io/hoodi'),
|
||||
]),
|
||||
[mordor.id]: fallback([
|
||||
http('https://rpc.mordor.etccooperative.org'),
|
||||
])
|
||||
},
|
||||
})
|
||||
|
||||
@ -1,10 +1,29 @@
|
||||
export enum NetworkId {
|
||||
TESTNET_SEPOLIA = 11155111,
|
||||
TESTNET_HOODI = 560048,
|
||||
TESTNET_MORDOR = 63,
|
||||
}
|
||||
|
||||
export const isNetworkAvailable = (chainId, addressChainId) => {
|
||||
chainId = addressChainId ? addressChainId : chainId;
|
||||
let exists = false;
|
||||
switch (chainId) {
|
||||
case 11155111:
|
||||
exists = true
|
||||
break;
|
||||
case 560048:
|
||||
exists = true
|
||||
break;
|
||||
case 63:
|
||||
exists = true
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return exists;
|
||||
}
|
||||
|
||||
export const isNetworkLegacy = (chainId) => {
|
||||
let exists = false;
|
||||
switch (chainId) {
|
||||
case 11155111:
|
||||
|
||||
@ -3,78 +3,98 @@ import { NetworkId } from "../constants";
|
||||
export const STAKING_ADDRESSES = {
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0xd90E63E88282596E1ea33765b41Ba3d650f4aD52",
|
||||
[NetworkId.TESTNET_HOODI]: "0x25F62eDc6C89FF84E957C22336A35d2dfc861a86",
|
||||
[NetworkId.TESTNET_MORDOR]: "0xC25C9C56a89ebd6ef291b415d00ACfa7913c55e7",
|
||||
};
|
||||
|
||||
export const BOND_DEPOSITORY_ADDRESSES = {
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0xdcE486113280e49ca2fB200258E5Ee1B2D21D495",
|
||||
[NetworkId.TESTNET_HOODI]: "0x6Ad50B1E293E68B2fC230c576220a93A9D311571",
|
||||
[NetworkId.TESTNET_MORDOR]: "0x7C85cDEddBAd0f50453d373F7332BEa11ECa7BAf",
|
||||
};
|
||||
|
||||
export const DAO_TREASURY_ADDRESSES = {
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0x93dd30f819403710de7933B79A74C4A42438458D",
|
||||
[NetworkId.TESTNET_HOODI]: "0x1a1b29b18f714fac9dDabEf530dFc4f85b56A6e8",
|
||||
[NetworkId.TESTNET_MORDOR]: "0x5883C8e2259556B534036c7fDF4555E09dE9f243",
|
||||
};
|
||||
|
||||
export const FTSO_DAI_LP_ADDRESSES = {
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0x1394dC3f7bABaa2F0CA80353648087DAB1BF3fd6",
|
||||
[NetworkId.TESTNET_HOODI]: "0xf7B2d44209E70782d93A70F7D8eC50010dF7ae50",
|
||||
[NetworkId.TESTNET_MORDOR]: "0xE6546D12665dB5B22Cb92FB9e0221aE51A57aeaa",
|
||||
};
|
||||
|
||||
export const FTSO_STNK_LP_ADDRESSES = {
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0x0000000000000000000000000000000000000000", // TBD
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0x0000000000000000000000000000000000000000",
|
||||
[NetworkId.TESTNET_MORDOR]: "0x0000000000000000000000000000000000000000",
|
||||
}
|
||||
|
||||
export const DAI_ADDRESSES = {
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0x5f63a27a9214a0352F2EF8dAF1eD4974d713192B",
|
||||
[NetworkId.TESTNET_HOODI]: "0x80c6676c334BCcE60b3CC852085B72143379CE58",
|
||||
[NetworkId.TESTNET_MORDOR]: "0x6af91B3763b5d020E0985f85555EB50e5852d7AC",
|
||||
};
|
||||
|
||||
export const WETH_ADDRESSES = {
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0xfff9976782d46cc05630d1f6ebab18b2324d6b14",
|
||||
[NetworkId.TESTNET_HOODI]: "0xE69a5c6dd88cA798b93c3C92fc50c51Fd5305eB4",
|
||||
[NetworkId.TESTNET_MORDOR]: "0x6af91B3763b5d020E0985f85555EB50e5852d7AC",
|
||||
};
|
||||
|
||||
export const GHST_ADDRESSES = {
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0xdf2e5306A3dCcfA4e21bbF4226C17Ff5B008dDC4",
|
||||
[NetworkId.TESTNET_HOODI]: "0xE98f7426457E6533B206e91B7EcA97aa8A258B46",
|
||||
[NetworkId.TESTNET_MORDOR]: "0x14b5787F8a1E62786F50A7998A9b14aa24298423",
|
||||
};
|
||||
|
||||
export const STNK_ADDRESSES = {
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0x02C296A27eA779d5a16F934337c12062C5E3c0D9",
|
||||
[NetworkId.TESTNET_HOODI]: "0xF07e9303A9f16Afd82f4f57Fd6fca68Aa0AB6D7F",
|
||||
[NetworkId.TESTNET_MORDOR]: "0x137bA9403885D8ECEa95AaFBb8734F5a16121bAC",
|
||||
};
|
||||
|
||||
export const FTSO_ADDRESSES = {
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0xcFedFFEB3FdeCd2196820Ba3b71f3F84A1255f93",
|
||||
[NetworkId.TESTNET_HOODI]: "0xb184e423811b644A1924334E63985c259F5D0033",
|
||||
[NetworkId.TESTNET_MORDOR]: "0xeA170CC0faceC531a6a9e93a28C4330Ac50343a1",
|
||||
};
|
||||
|
||||
export const DISTRIBUTOR_ADDRESSES = {
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0x8fbF8eB4Fcd451EF62Aee33508D46FE120963194",
|
||||
[NetworkId.TESTNET_HOODI]: "0xdF49dC81c457c6f92e26cf6d686C7a8715255842",
|
||||
[NetworkId.TESTNET_MORDOR]: "0xaf5e76706520db7fb01096E322940206bf3fce57",
|
||||
};
|
||||
|
||||
export const GHOST_GOVERNANCE_ADDRESSES = {
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0xDab0c51918E6990d8763FAC8a04AE159e44e0c4f",
|
||||
[NetworkId.TESTNET_HOODI]: "0x1B96B792840d4d19d5097ee007392Ed4d851e64F",
|
||||
[NetworkId.TESTNET_MORDOR]: "0x3dD438416D9593A58193fC52850E588efAa3D57E",
|
||||
};
|
||||
|
||||
export const BONDING_CALCULATOR_ADDRESSES = {
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0x4896bFc6256A57Df826d7144E48c9633d51d6319",
|
||||
[NetworkId.TESTNET_HOODI]: "0x2635d526Ad24b98082563937f7b996075052c6Fd",
|
||||
[NetworkId.TESTNET_MORDOR]: "0x0c4C7C49a173E2a3f9Eed93125F3F146D8e17bCb",
|
||||
}
|
||||
|
||||
export const GATEKEEPER_ADDRESSES = {
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0xc85129A097773B7F8970a7364c928C05f265E6A1",
|
||||
[NetworkId.TESTNET_MORDOR]: "0xA59cB4ff90bE2206121aE61eEB68d0AeC7BA095f",
|
||||
}
|
||||
|
||||
export const UNISWAP_V2_ROUTER = {
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0xee567fe1712faf6149d80da1e6934e354124cfe3",
|
||||
[NetworkId.TESTNET_HOODI]: "0xD41daF947c6FFEf344754B99ad09466FBCBb7583",
|
||||
[NetworkId.TESTNET_MORDOR]: "0x90ecf6a29798E3cf31EB7DCE64a372AC40d83F83",
|
||||
};
|
||||
|
||||
export const UNISWAP_V2_FACTORY = {
|
||||
[NetworkId.TESTNET_SEPOLIA]: "0xF62c03E08ada871A0bEb309762E260a7a6a880E6",
|
||||
[NetworkId.TESTNET_HOODI]: "0xF140342cB5C29C1468d91Aee408d7b7271C48b5A",
|
||||
[NetworkId.TESTNET_MORDOR]: "0x909f96C1a436B3386E9962e30f3Ce753070ff524",
|
||||
};
|
||||
|
||||
export const CEX_TICKERS = {
|
||||
[NetworkId.TESTNET_MORDOR]: "ETCUSDT",
|
||||
}
|
||||
|
||||
@ -18,4 +18,11 @@ export const AVAILABLE_DEXES = {
|
||||
viewBox: "0 0 195 230",
|
||||
},
|
||||
],
|
||||
[NetworkId.TESTNET_MORDOR]: [
|
||||
{
|
||||
name: "Uniswap",
|
||||
icon: UniswapIcon,
|
||||
viewBox: "0 0 195 230",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
@ -19,6 +19,7 @@ import TokenStack from "../../components/TokenStack/TokenStack";
|
||||
import { DecimalBigNumber } from "../../helpers/DecimalBigNumber";
|
||||
import { formatNumber } from "../../helpers/";
|
||||
import { useBalance, useTokenSymbol } from "../../hooks/tokens";
|
||||
import { isNetworkLegacy } from "../../constants";
|
||||
import { DAI_ADDRESSES, FTSO_ADDRESSES, STNK_ADDRESSES, GHST_ADDRESSES } from "../../constants/addresses";
|
||||
|
||||
const TokenModal = ({ chainId, account, listOpen, setListOpen, setTokenAddress }) => {
|
||||
@ -60,7 +61,7 @@ const TokenModal = ({ chainId, account, listOpen, setListOpen, setTokenAddress }
|
||||
return [
|
||||
{
|
||||
name: daiSymbol,
|
||||
icons: ["GDAI"],
|
||||
icons: isNetworkLegacy(chainId) ? ["GDAI"] : ["WETH"],
|
||||
balance: daiBalance,
|
||||
address: DAI_ADDRESSES[chainId]
|
||||
},
|
||||
|
||||
@ -6,6 +6,7 @@ import Token from "../../../components/Token/Token";
|
||||
import { SecondaryButton } from "../../../components/Button";
|
||||
import { formatNumber, formatCurrency } from "../../../helpers";
|
||||
import { DecimalBigNumber } from "../../../helpers/DecimalBigNumber";
|
||||
import { isNetworkLegacy } from "../../../constants"
|
||||
|
||||
import { useBalance, useTokenSymbol } from "../../../hooks/tokens";
|
||||
import {
|
||||
@ -133,7 +134,7 @@ const TokenInfo = ({ chainId, isMobileScreen }) => {
|
||||
/>
|
||||
<TokenTab
|
||||
isMobileScreen={isMobileScreen}
|
||||
tokenUrl="/faucet"
|
||||
tokenUrl={isNetworkLegacy(chainId) ? "/faucet" : "/wrapper"}
|
||||
tokenUrlParams=""
|
||||
theme={theme}
|
||||
tokenName={daiSymbol}
|
||||
|
||||
260
src/containers/WethWrapper/WethWrapper.jsx
Normal file
260
src/containers/WethWrapper/WethWrapper.jsx
Normal file
@ -0,0 +1,260 @@
|
||||
import { useState, useEffect, useMemo } from "react";
|
||||
import { Box, Container, Typography, useMediaQuery } from "@mui/material";
|
||||
import { useConfig, useBalance } from "wagmi";
|
||||
import { Helmet } from "react-helmet";
|
||||
import ReactGA from "react-ga4";
|
||||
|
||||
import PageTitle from "../../components/PageTitle/PageTitle";
|
||||
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,
|
||||
depositNative,
|
||||
withdrawWeth
|
||||
} from "../../hooks/tokens";
|
||||
|
||||
const WethWrapper = ({ chainId, address, config, connect }) => {
|
||||
const isSmallScreen = useMediaQuery("(max-width: 650px)");
|
||||
const isSemiSmallScreen = useMediaQuery("(max-width: 480px)");
|
||||
const isVerySmallScreen = useMediaQuery("(max-width: 379px)");
|
||||
|
||||
const [chainName, setChainName] = useState("");
|
||||
const [isMint, setIsMint] = useState(true);
|
||||
const [isPending, setIsPending] = useState(false);
|
||||
const [balance, setBalance] = useState(new DecimalBigNumber(0, 0));
|
||||
const [amount, setAmount] = useState("");
|
||||
const [scanInfo, setScanInfo] = useState({
|
||||
name: "",
|
||||
url: "",
|
||||
});
|
||||
const [nativeInfo, setNativeInfo] = useState({
|
||||
decimals: 18,
|
||||
name: "",
|
||||
symbol: "",
|
||||
})
|
||||
|
||||
const { balance: daiBalance, refetch: daiBalanceRefetch } = useTokenBalance(chainId, "GDAI", address);
|
||||
const { data: nativeBalance, refetch: balanceRefetch } = useBalance({ address });
|
||||
const { symbol: faucetSymbol } = useTokenSymbol(chainId, "GDAI");
|
||||
|
||||
useEffect(() => {
|
||||
ReactGA.send({ hitType: "pageview", page: "/faucet" });
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
const value = nativeBalance ? nativeBalance.value : 0n;
|
||||
const decimals = nativeBalance ? nativeBalance.decimals : 18;
|
||||
setBalance(new DecimalBigNumber(value, decimals));
|
||||
}, [nativeBalance]);
|
||||
|
||||
useEffect(() => {
|
||||
let scanName = "";
|
||||
let scanUrl = "";
|
||||
|
||||
const client = config?.getClient();
|
||||
scanName = client?.chain?.blockExplorers?.default?.name;
|
||||
scanUrl = client?.chain?.blockExplorers?.default?.url;
|
||||
|
||||
setScanInfo({
|
||||
name: scanName,
|
||||
url: scanUrl,
|
||||
})
|
||||
|
||||
setChainName(client?.chain?.name);
|
||||
|
||||
setNativeInfo(client?.chain?.nativeCurrency)
|
||||
}, [chainId]);
|
||||
|
||||
const changeIsMinted = (value) => {
|
||||
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])
|
||||
|
||||
const estimatedAmountIn = useMemo(() => {
|
||||
return new DecimalBigNumber(amount, nativeInfo.decimals);
|
||||
}, [amount, nativeInfo]);
|
||||
|
||||
const estimatedAmountOut = useMemo(() => {
|
||||
return new DecimalBigNumber(amount, nativeInfo.decimals);
|
||||
}, [amount, nativeInfo]);
|
||||
|
||||
const actionOrConnect = async () => {
|
||||
if (address === "") {
|
||||
connect();
|
||||
} else {
|
||||
setIsPending(true);
|
||||
|
||||
if (isMint) {
|
||||
await depositNative(chainId, address, preparedAmount._value.toString());
|
||||
} else {
|
||||
await withdrawWeth(chainId, address, preparedAmount._value.toString());
|
||||
}
|
||||
|
||||
await balanceRefetch();
|
||||
await daiBalanceRefetch();
|
||||
setAmount("");
|
||||
setIsPending(false);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Box height="calc(100vh - 43px)">
|
||||
<Helmet>
|
||||
<title>ghostWrapper | WETH9</title>
|
||||
<meta name="description" content="Standard WETH9 wrapper. Convert native coin to WETH9 representation directly to your wallet." />
|
||||
<meta name="keywords" content="weth, weth9, ghostFaucet, web3 faucet, ethereum, sepolia, polygon, bnb, bsc, AVAX" />
|
||||
|
||||
<meta property="og:image" content="https://ghostchain.io/wp-content/uploads/2025/03/ghostFaucet-Featured_Image.png" />
|
||||
<meta property="og:title" content="ghostDAO | The DeFi 2.0 cross-chain reserve currency" />
|
||||
<meta property="og:image:type" content="image/png" />
|
||||
<meta property="og:image:width" content="1200" />
|
||||
<meta property="og:image:height" content="630" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:description" content="Standard WETH9 wrapper. Convert native coin to WETH9 representation directly to your wallet." />
|
||||
|
||||
<meta name="twitter:card" content="summary" />
|
||||
<meta name="twitter:site" content="@realGhostChain" />
|
||||
<meta name="twitter:title" content="ghostDAO | The DeFi 2.0 cross-chain reserve currency" />
|
||||
<meta name="twitter:description" content="Standard WETH9 wrapper. Convert native coin to WETH9 representation directly to your wallet." />
|
||||
<meta name="twitter:image" content="https://ghostchain.io/wp-content/uploads/2025/03/ghostFaucet-Featured_Image.png" />
|
||||
</Helmet>
|
||||
|
||||
<PageTitle name={`${faucetSymbol} Faucet`} subtitle={`Swap ${chainName} ${nativeInfo.symbol} for ${faucetSymbol}.`} />
|
||||
<Container
|
||||
style={{
|
||||
paddingLeft: isSmallScreen || isVerySmallScreen ? "0" : "3.3rem",
|
||||
paddingRight: isSmallScreen || isVerySmallScreen ? "0" : "3.3rem",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
height: "calc(100vh - 153px)"
|
||||
}}
|
||||
>
|
||||
<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%">
|
||||
<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" }} />
|
||||
<Tab aria-label="faucet-burn-button" label="Burn" style={{ fontSize: "1.5rem" }} />
|
||||
</Tabs>
|
||||
{!isSemiSmallScreen && <PrimaryButton
|
||||
variant="text"
|
||||
href={`${scanInfo.url}/token/${DAI_ADDRESSES[chainId]}`}
|
||||
>
|
||||
Check on {scanInfo.name}
|
||||
</PrimaryButton>}
|
||||
</Box>
|
||||
}
|
||||
enableBackground
|
||||
fullWidth
|
||||
>
|
||||
<Box>
|
||||
{isMint && <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)}`}
|
||||
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"
|
||||
flexDirection="column"
|
||||
display="flex"
|
||||
justifyContent="space-between"
|
||||
>
|
||||
{isMint && (
|
||||
<>
|
||||
<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>
|
||||
</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>
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
{!isMint && (
|
||||
<>
|
||||
<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))
|
||||
)
|
||||
}
|
||||
loading={isPending}
|
||||
onClick={() => actionOrConnect()}
|
||||
>
|
||||
{address === "" ?
|
||||
"Connect"
|
||||
:
|
||||
isMint ? "Mint" : "Burn"
|
||||
}
|
||||
</PrimaryButton>
|
||||
</Box>
|
||||
</Paper>
|
||||
</Box>
|
||||
</Container>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
export default WethWrapper;
|
||||
@ -4,6 +4,7 @@ import {
|
||||
STNK_ADDRESSES,
|
||||
GHST_ADDRESSES,
|
||||
FTSO_DAI_LP_ADDRESSES,
|
||||
WETH_ADDRESSES,
|
||||
} from "../constants/addresses";
|
||||
|
||||
import { abi as DaiAbi } from "../abi/Reserve.json";
|
||||
@ -11,6 +12,7 @@ import { abi as FatsoAbi } from "../abi/Fatso.json";
|
||||
import { abi as StinkyAbi } from "../abi/Stinky.json";
|
||||
import { abi as GhostAbi } from "../abi/Ghost.json";
|
||||
import { abi as Erc20Abi } from "../abi/ERC20.json";
|
||||
import { abi as WethAbi } from "../abi/WETH9.json";
|
||||
|
||||
// TBD: should be extended on new tokens
|
||||
export const getTokenAbi = (name) => {
|
||||
@ -40,6 +42,9 @@ export const getTokenAbi = (name) => {
|
||||
case "CSPR":
|
||||
abi = GhostAbi;
|
||||
break;
|
||||
case "WETH":
|
||||
abi = WethAbi;
|
||||
break;
|
||||
}
|
||||
return abi;
|
||||
}
|
||||
@ -72,6 +77,9 @@ export const getTokenDecimals = (name) => {
|
||||
case "CSPR":
|
||||
decimals = 18;
|
||||
break;
|
||||
case "WETH":
|
||||
decimals = 18;
|
||||
break;
|
||||
}
|
||||
return decimals;
|
||||
}
|
||||
@ -107,6 +115,9 @@ export const getTokenAddress = (chainId, name) => {
|
||||
case "GDAI_FTSO":
|
||||
address = FTSO_DAI_LP_ADDRESSES[chainId];
|
||||
break;
|
||||
case "WETH":
|
||||
address = WETH_ADDRESSES[chainId];
|
||||
break;
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
@ -1,12 +1,79 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { useReadContract } from "wagmi";
|
||||
|
||||
import { useCurrentIndex, useGhostedSupply } from "../staking";
|
||||
import { useUniswapV2PairReserves } from "../uniswapv2";
|
||||
import { DecimalBigNumber } from "../../helpers/DecimalBigNumber";
|
||||
import { FTSO_DAI_LP_ADDRESSES, DAI_ADDRESSES, FTSO_ADDRESSES } from "../../constants/addresses";
|
||||
import {
|
||||
FTSO_DAI_LP_ADDRESSES,
|
||||
DAI_ADDRESSES,
|
||||
FTSO_ADDRESSES,
|
||||
CEX_TICKERS
|
||||
} from "../../constants/addresses";
|
||||
|
||||
const cexPriceGetters = new Map();
|
||||
|
||||
function callWithCacheTTL(fn, ttlMs = 5000) {
|
||||
let lastFetchTime = 0;
|
||||
let cachedValue;
|
||||
let inFlight = null;
|
||||
|
||||
return function(...args) {
|
||||
const now = Date.now();
|
||||
|
||||
if ((now - lastFetchTime) < ttlMs) {
|
||||
return inFlight ? inFlight : Promise.resolve(cachedValue);
|
||||
}
|
||||
|
||||
lastFetchTime = now;
|
||||
inFlight = Promise.resolve(fn(...args))
|
||||
.then(res => {
|
||||
cachedValue = res;
|
||||
inFlight = null;
|
||||
return res;
|
||||
})
|
||||
.catch(err => {
|
||||
inFlight = null;
|
||||
throw err;
|
||||
});
|
||||
|
||||
return inFlight;
|
||||
}
|
||||
}
|
||||
|
||||
export const useDaiPrice = (chainId) => {
|
||||
const daiPrice = new DecimalBigNumber(1000000000000000000n, 18);
|
||||
const [daiPrice, setDaiPrice] = useState(new DecimalBigNumber(1000000000000000000n, 18));
|
||||
const cexTicker = CEX_TICKERS[chainId];
|
||||
|
||||
useEffect(() => {
|
||||
if (!cexTicker) {
|
||||
setDaiPrice(new DecimalBigNumber(1000000000000000000n, 18));
|
||||
return;
|
||||
}
|
||||
|
||||
let getCexPriceCached = cexPriceGetters.get(chainId);
|
||||
if (!getCexPriceCached) {
|
||||
getCexPriceCached = callWithCacheTTL(() => {
|
||||
return fetch(`https://api.binance.com/api/v3/ticker/price?symbol=${cexTicker}`)
|
||||
.then(res => {
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||
return res.json();
|
||||
});
|
||||
}, 5000);
|
||||
cexPriceGetters.set(chainId, getCexPriceCached);
|
||||
}
|
||||
|
||||
getCexPriceCached()
|
||||
.then(price => {
|
||||
const coinPrice = Number(price?.price ?? 0.0);
|
||||
const priceInWei = Math.floor(coinPrice * 1e18)
|
||||
setDaiPrice(new DecimalBigNumber(BigInt(priceInWei), 18));
|
||||
})
|
||||
.catch(error => {
|
||||
setDaiPrice(new DecimalBigNumber(0n, 18));
|
||||
});
|
||||
}, [chainId, cexTicker])
|
||||
|
||||
return daiPrice;
|
||||
};
|
||||
|
||||
@ -20,6 +87,7 @@ export const useFtsoPrice = (chainId) => {
|
||||
"GDAI",
|
||||
);
|
||||
|
||||
const reservePrice = useDaiPrice(chainId);
|
||||
const reserveAddress = DAI_ADDRESSES[chainId];
|
||||
const ftsoAddress = FTSO_ADDRESSES[chainId];
|
||||
if (!reserveAddress || !ftsoAddress) {
|
||||
@ -37,8 +105,9 @@ export const useFtsoPrice = (chainId) => {
|
||||
let price = 0n
|
||||
if (ftsoReserves > 0n)
|
||||
price = stableReserves / ftsoReserves;
|
||||
price = price * reservePrice._value;
|
||||
|
||||
return new DecimalBigNumber(price, 9);
|
||||
return new DecimalBigNumber(price, 27);
|
||||
};
|
||||
|
||||
export const useStnkPrice = (chainId) => {
|
||||
|
||||
@ -229,3 +229,53 @@ export const burnDai = async (chainId, account, value) => {
|
||||
toast.error("Burning gDAI from the faucet failed. Check logs for error detalization.")
|
||||
}
|
||||
}
|
||||
|
||||
export const depositNative = async (chainId, account, value) => {
|
||||
try {
|
||||
const { request } = await simulateContract(config, {
|
||||
abi: getTokenAbi("WETH"),
|
||||
address: getTokenAddress(chainId, "WETH"),
|
||||
functionName: 'deposit',
|
||||
account: account,
|
||||
chainId: chainId,
|
||||
value: value
|
||||
});
|
||||
|
||||
const txHash = await writeContract(config, request);
|
||||
await waitForTransactionReceipt(config, {
|
||||
hash: txHash,
|
||||
onReplaced: () => toast("WETH9 deposit transaction was replaced. Wait for inclusion please."),
|
||||
chainId
|
||||
});
|
||||
|
||||
toast.success("WETH9 successfully minted to your wallet! Check your wallet balance.");
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
toast.error("WETH9 wrapping failed. Check logs for error detalization.")
|
||||
}
|
||||
}
|
||||
|
||||
export const withdrawWeth = async (chainId, account, value) => {
|
||||
try {
|
||||
const { request } = await simulateContract(config, {
|
||||
abi: getTokenAbi("WETH"),
|
||||
address: getTokenAddress(chainId, "WETH"),
|
||||
functionName: 'withdraw',
|
||||
args: [value],
|
||||
account: account,
|
||||
chainId: chainId
|
||||
});
|
||||
|
||||
const txHash = await writeContract(config, request);
|
||||
await waitForTransactionReceipt(config, {
|
||||
hash: txHash,
|
||||
onReplaced: () => toast("WETH9 withdraw transaction was replaced. Wait for inclusion please."),
|
||||
chainId
|
||||
});
|
||||
|
||||
toast.success("WETH9 successfully burned for native coins! Check your wallet balance.");
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
toast.error("WETH9 unwrapping failed. Check logs for error detalization.")
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,9 +3,23 @@ import { useReadContract } from "wagmi";
|
||||
import { DAO_TREASURY_ADDRESSES } from "../../constants/addresses";
|
||||
import { abi as TreasuryAbi } from "../../abi/GhostTreasury.json";
|
||||
|
||||
import { useDaiPrice } from "../prices/index";
|
||||
|
||||
import { DecimalBigNumber } from "../../helpers/DecimalBigNumber";
|
||||
import { getTokenAddress } from "../helpers";
|
||||
|
||||
export const useOrinalCoefficient = (chainId) => {
|
||||
const { data: original } = useReadContract({
|
||||
abi: TreasuryAbi,
|
||||
address: DAO_TREASURY_ADDRESSES[chainId],
|
||||
functionName: "originalCoefficient",
|
||||
scopeKey: `originalCoefficient-${chainId}`,
|
||||
chainId: chainId
|
||||
});
|
||||
|
||||
return new DecimalBigNumber(original ? original : 1000000000000000000n, 18);
|
||||
}
|
||||
|
||||
export const useTotalReserves = (chainId) => {
|
||||
const { data: totalReservesRaw } = useReadContract({
|
||||
abi: TreasuryAbi,
|
||||
@ -15,10 +29,13 @@ export const useTotalReserves = (chainId) => {
|
||||
chainId: chainId,
|
||||
});
|
||||
|
||||
const original = useOrinalCoefficient(chainId);
|
||||
const price = useDaiPrice(chainId);
|
||||
|
||||
const totalReservesPrepared = totalReservesRaw ? totalReservesRaw : 0n;
|
||||
const totalReserves = new DecimalBigNumber(totalReservesPrepared, 9);
|
||||
|
||||
return totalReserves;
|
||||
return totalReserves.mul(price).div(original);
|
||||
};
|
||||
|
||||
export const useLpValuation = (chainId, pairAddress, pairSupply) => {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user