diff --git a/package.json b/package.json
index 2f6197c..23175c3 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "ghost-dao-interface",
"private": true,
- "version": "0.1.6",
+ "version": "0.2.0",
"type": "module",
"scripts": {
"dev": "vite",
@@ -18,6 +18,8 @@
"@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",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 892912f..d27005f 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -32,6 +32,12 @@ 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)
@@ -723,6 +729,10 @@ 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'}
@@ -743,6 +753,12 @@ 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==}
@@ -913,6 +929,9 @@ 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==}
@@ -2375,6 +2394,9 @@ 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==}
@@ -3556,6 +3578,10 @@ 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': {}
@@ -3566,6 +3592,16 @@ 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)':
@@ -3936,6 +3972,11 @@ 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)':
@@ -5471,8 +5512,8 @@ snapshots:
ox@0.6.7(zod@3.22.4):
dependencies:
'@adraffy/ens-normalize': 1.11.0
- '@noble/curves': 1.8.1
- '@noble/hashes': 1.7.1
+ '@noble/curves': 1.9.2
+ '@noble/hashes': 1.8.0
'@scure/bip32': 1.6.2
'@scure/bip39': 1.5.4
abitype: 1.0.8(zod@3.22.4)
@@ -5842,6 +5883,8 @@ 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:
diff --git a/src/App.jsx b/src/App.jsx
index 1986763..7a17edf 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -27,6 +27,7 @@ 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";
@@ -187,6 +188,7 @@ function App() {
} />
} />
} />
+ } />
} />
>
}
diff --git a/src/components/NavItem/NavItem.jsx b/src/components/NavItem/NavItem.jsx
index 0d98aca..b711209 100644
--- a/src/components/NavItem/NavItem.jsx
+++ b/src/components/NavItem/NavItem.jsx
@@ -132,6 +132,7 @@ const NavItem = ({
const LinkItem = () => (
{
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");
@@ -91,11 +92,14 @@ const NavContent = ({ chainId, addressChainId }) => {
{ghstSymbol} Price: {formatCurrency(ghstPrice, 2)}
+
+ Ghosted Supply: {formatCurrency(ghostedSupplyPrice, 2)}
+
-
+
@@ -141,6 +145,7 @@ const NavContent = ({ chainId, addressChainId }) => {
/>
+
{
>
}
-
{
+const SwapCollection = ({ UpperSwapCard, LowerSwapCard, arrowOnClick, iconNotNeeded }) => {
const theme = useTheme();
return (
{UpperSwapCard}
- {
}}
/>
-
+ )}
+ {iconNotNeeded && }
{LowerSwapCard}
diff --git a/src/components/TopBar/Wallet/InitialWalletView.tsx b/src/components/TopBar/Wallet/InitialWalletView.tsx
index ff3b40a..f15ad4f 100644
--- a/src/components/TopBar/Wallet/InitialWalletView.tsx
+++ b/src/components/TopBar/Wallet/InitialWalletView.tsx
@@ -152,7 +152,7 @@ function InitialWalletView({ address, chainId, onClose }) {
fullWidth
onClick={() => onBtnClick("uniswap", DAI_ADDRESSES[chainId], FTSO_ADDRESSES[chainId])}
>
- FTSO-gDAI on Uniswap
+ {`${tokens?.ftso?.symbol}-${tokens?.dai?.symbol} on Uniswap`}
diff --git a/src/config.js b/src/config.js
index bf33239..e340f2c 100644
--- a/src/config.js
+++ b/src/config.js
@@ -6,7 +6,6 @@ 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'),
diff --git a/src/constants/addresses.js b/src/constants/addresses.js
index fa6582b..c22cc5c 100644
--- a/src/constants/addresses.js
+++ b/src/constants/addresses.js
@@ -1,32 +1,32 @@
import { NetworkId } from "../constants";
export const STAKING_ADDRESSES = {
- [NetworkId.TESTNET_SEPOLIA]: "0x47b662aC17937938ff8938Fe9513beF38e60E40C",
+ [NetworkId.TESTNET_SEPOLIA]: "0xd90E63E88282596E1ea33765b41Ba3d650f4aD52",
[NetworkId.TESTNET_HOODI]: "0x25F62eDc6C89FF84E957C22336A35d2dfc861a86",
};
export const BOND_DEPOSITORY_ADDRESSES = {
- [NetworkId.TESTNET_SEPOLIA]: "0xcBdad2E86a60fcfF4ecD88D7067D403710D82340",
+ [NetworkId.TESTNET_SEPOLIA]: "0xdcE486113280e49ca2fB200258E5Ee1B2D21D495",
[NetworkId.TESTNET_HOODI]: "0x6Ad50B1E293E68B2fC230c576220a93A9D311571",
};
export const DAO_TREASURY_ADDRESSES = {
- [NetworkId.TESTNET_SEPOLIA]: "0xed487AF8a6d1d1334e4b899FEb3f39402637Bc85",
+ [NetworkId.TESTNET_SEPOLIA]: "0x93dd30f819403710de7933B79A74C4A42438458D",
[NetworkId.TESTNET_HOODI]: "0x1a1b29b18f714fac9dDabEf530dFc4f85b56A6e8",
};
export const FTSO_DAI_LP_ADDRESSES = {
- [NetworkId.TESTNET_SEPOLIA]: "0x0000000000000000000000000000000000000000", // TBD
+ [NetworkId.TESTNET_SEPOLIA]: "0x1394dC3f7bABaa2F0CA80353648087DAB1BF3fd6",
[NetworkId.TESTNET_HOODI]: "0xf7B2d44209E70782d93A70F7D8eC50010dF7ae50",
};
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]: "0x1E392913CB9CeFAd0466D1525a9Ee144E74a233A",
+ [NetworkId.TESTNET_SEPOLIA]: "0x5f63a27a9214a0352F2EF8dAF1eD4974d713192B",
[NetworkId.TESTNET_HOODI]: "0x80c6676c334BCcE60b3CC852085B72143379CE58",
};
@@ -36,35 +36,39 @@ export const WETH_ADDRESSES = {
};
export const GHST_ADDRESSES = {
- [NetworkId.TESTNET_SEPOLIA]: "0xfd210d7ac18Bc7dcE7d72ffd99a20a9F3b44d4F4",
+ [NetworkId.TESTNET_SEPOLIA]: "0xdf2e5306A3dCcfA4e21bbF4226C17Ff5B008dDC4",
[NetworkId.TESTNET_HOODI]: "0xE98f7426457E6533B206e91B7EcA97aa8A258B46",
};
export const STNK_ADDRESSES = {
- [NetworkId.TESTNET_SEPOLIA]: "0x0cC9868D981852C804C610176b519c48808C26a9",
+ [NetworkId.TESTNET_SEPOLIA]: "0x02C296A27eA779d5a16F934337c12062C5E3c0D9",
[NetworkId.TESTNET_HOODI]: "0xF07e9303A9f16Afd82f4f57Fd6fca68Aa0AB6D7F",
};
export const FTSO_ADDRESSES = {
- [NetworkId.TESTNET_SEPOLIA]: "0x730EEf44f2a676d4081a2F3B53D10d5e4c15C2Bc",
+ [NetworkId.TESTNET_SEPOLIA]: "0xcFedFFEB3FdeCd2196820Ba3b71f3F84A1255f93",
[NetworkId.TESTNET_HOODI]: "0xb184e423811b644A1924334E63985c259F5D0033",
};
export const DISTRIBUTOR_ADDRESSES = {
- [NetworkId.TESTNET_SEPOLIA]: "0x1A848562b86DB7Be5558C1fa8D85326b163c2fFA",
+ [NetworkId.TESTNET_SEPOLIA]: "0x8fbF8eB4Fcd451EF62Aee33508D46FE120963194",
[NetworkId.TESTNET_HOODI]: "0xdF49dC81c457c6f92e26cf6d686C7a8715255842",
};
export const GHOST_GOVERNANCE_ADDRESSES = {
- [NetworkId.TESTNET_SEPOLIA]: "0xc19f2680B1d64A507B7f3498E9B83B0A069C68Cc",
+ [NetworkId.TESTNET_SEPOLIA]: "0xDab0c51918E6990d8763FAC8a04AE159e44e0c4f",
[NetworkId.TESTNET_HOODI]: "0x1B96B792840d4d19d5097ee007392Ed4d851e64F",
};
export const BONDING_CALCULATOR_ADDRESSES = {
- [NetworkId.TESTNET_SEPOLIA]: "0xAbE29450bAC493c6D25C467E0f809301084B6a27",
+ [NetworkId.TESTNET_SEPOLIA]: "0x4896bFc6256A57Df826d7144E48c9633d51d6319",
[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",
diff --git a/src/containers/Bridge/Bridge.jsx b/src/containers/Bridge/Bridge.jsx
new file mode 100644
index 0000000..2917aff
--- /dev/null
+++ b/src/containers/Bridge/Bridge.jsx
@@ -0,0 +1,662 @@
+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 (
+
+
+
+
+
+ TX Hash
+
+ {currentRecord?.transactionHash.slice(0, 9)}...{currentRecord?.transactionHash.slice(-9)}
+
+
+
+ }
+ open={activeTxIndex > -1}
+ onClose={() => setActiveTxIndex(-1)}
+ minHeight={"100px"}
+ >
+
+
+ handleMouseEnter(0)}
+ >
+
+ Finalization
+ {blockNumber?.toString()} blocks left
+
+
+
+
+ handleMouseEnter(1)}
+ >
+
+
+
+
+
+ Slow claps
+ {clappedValidators} / {validators.length}
+
+
+
+
+
+ handleMouseEnter(2)}
+ >
+
+ Applaused
+ Check Receiver
+
+
+
+
+
+ Session Index:
+ {currentRecord?.sessionIndex}
+
+
+ Receiver Address:
+ {currentRecord?.receiver}
+
+
+ Sent Amount:
+ {formatCurrency(
+ new DecimalBigNumber(
+ BigInt(currentRecord ? currentRecord.amount : "0"),
+ 18
+ ).toString(), 9, ghstSymbol)
+ }
+
+
+ Executed at:
+ {
+ new Date(currentRecord ? currentRecord.timestamp : 0).toLocaleString('en-US')
+ }
+
+
+
+
+
+ removeStoredRecord()}
+ >
+ Erase Record
+
+
+
+ This will remove the transaction record from the session storage, but it will not cancel the bridge transaction.
+
+
+
+
+
+
+ {
+ bridgeAction
+ ? `Bridge $${ghstSymbol}`
+ : "Transaction history"
+ }
+
+ }
+ topRight={
+ setBridgeAction(!bridgeAction)}
+ />
+ }
+
+ enableBackground
+ fullWidth
+ >
+
+ {bridgeAction && (
+ <>
+ setReceiver(event.currentTarget.value)}
+ inputProps={{ "data-testid": "fromInput" }}
+ placeholder="Ghost address (sf prefixed)"
+ type="text"
+ />}
+ LowerSwapCard={ setAmount(event.currentTarget.value)}
+ inputProps={{ "data-testid": "fromInput" }}
+ endString={"Max"}
+ endStringOnClick={() => setAmount(ghstBalance.toString())}
+ />}
+ />
+
+
+ {gatekeeperAddressEmpty && (
+
+
+
+ There is no connected gatekeeper on {chainName} network. Propose gatekeeper on this network to make validators listen to it.
+
+
+
+ )}
+ {!gatekeeperAddressEmpty && (
+ <>
+ {!isVerySmallScreen && Gatekeeper:}
+
+ {gatekeeperAddress.slice(0, 10) + "..." + gatekeeperAddress.slice(-8)}
+
+ >
+ )}
+
+ {incomingCommission && validators?.length ? (
+
+
+
+ GHOST Wallet is not detected on your browser. Download
+
+ GHOST Wallet
+ to see full detalization for bridge transaction.
+
+
+
+ )
+ : (
+
+
+ {!isVerySmallScreen && Est. Commission:}
+ unknown
+
+
+ {!isVerySmallScreen && Number of validators:}
+ unknown
+
+
+ )}
+
+
+ ghostOrConnect()}
+ >
+ {address === "" ?
+ "Connect"
+ :
+ "Bridge"
+ }
+
+ >
+ )}
+ {!bridgeAction && (
+
+
+ Amount
+ Datetime
+ Status
+
+
+ {filteredStoredTransactions
+ .map((obj, idx) => (
+ setActiveTxIndex(idx)}
+ >
+
+
+ {formatCurrency(
+ new DecimalBigNumber(BigInt(obj.amount), 18).toString(),
+ 3,
+ ghstSymbol
+ )}
+
+
+
+
+
+ {new Date(obj.timestamp).toLocaleDateString('en-US')}
+
+
+ {new Date(obj.timestamp).toLocaleTimeString('en-US')}
+
+
+
+
+
+ {idx % 2 === 0 ?
+
+ :
+
+ }
+
+
+
+ ))}
+
+
+ )}
+
+
+
+
+
+ )
+}
+
+export default Bridge;
diff --git a/src/containers/Dex/PoolContainer.jsx b/src/containers/Dex/PoolContainer.jsx
index e69bf7d..559140d 100644
--- a/src/containers/Dex/PoolContainer.jsx
+++ b/src/containers/Dex/PoolContainer.jsx
@@ -68,9 +68,6 @@ const PoolContainer = ({
);
const onSwap = () => {
- // const oldAmountTop = amountTop;
- // const oldAmountBottom = amountBottom;
- // setAmountBottom(oldAmountTop);
setAmountTop(amountBottom);
onCardsSwap();
}
diff --git a/src/containers/Faucet/Faucet.jsx b/src/containers/Faucet/Faucet.jsx
index 64688b1..0d0eba0 100644
--- a/src/containers/Faucet/Faucet.jsx
+++ b/src/containers/Faucet/Faucet.jsx
@@ -30,14 +30,6 @@ const Faucet = ({ chainId, address, config, connect }) => {
const isSemiSmallScreen = useMediaQuery("(max-width: 480px)");
const isVerySmallScreen = useMediaQuery("(max-width: 379px)");
- 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 });
- const { totalSupply: reserveTotalSupply, refetch: refetchReserveTotalSupply } = useTotalSupply(chainId, "GDAI");
- const { symbol: faucetSymbol } = useTokenSymbol(chainId, "GDAI");
-
const [isMint, setIsMint] = useState(true);
const [isPending, setIsPending] = useState(false);
const [balance, setBalance] = useState(new DecimalBigNumber(0, 0));
@@ -52,6 +44,15 @@ const Faucet = ({ chainId, address, config, connect }) => {
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" });
}, [])
@@ -98,11 +99,11 @@ const Faucet = ({ chainId, address, config, connect }) => {
}, [amount, daiConversionRate, nativeInfo]);
const contractBalanceFree = useMemo(() => {
- const realContractBalance = contractBalance ? contractBalance : 0n;
+ const realContractBalance = contractBalance ? contractBalance.value : 0n;
const preparedContractBalance = new DecimalBigNumber(realContractBalance, nativeInfo.decimals);
const preparedAccumulatedDonation = new DecimalBigNumber(
accumulatedDonation._value,
- accumulatedDonation._decimals + nativeInfo.decimals - 18
+ nativeInfo.decimals && 18
);
return preparedContractBalance.sub(preparedAccumulatedDonation);
}, [contractBalance, accumulatedDonation]);
@@ -212,10 +213,12 @@ const Faucet = ({ chainId, address, config, connect }) => {
inputWidth={isVerySmallScreen ? "100px" : isSemiSmallScreen ? "180px" : "250px"}
tokenName={faucetSymbol}
token={}
- info={`${isSemiSmallScreen ? "" : "Balance: "}${formatCurrency(daiBalance.toString(), 4, faucetSymbol)}`}
+ info={`${formatCurrency(daiBalance.toString(), 4, faucetSymbol)}`}
value={amount}
onChange={event => setAmount(event.currentTarget.value)}
inputProps={{ "data-testid": "fromInput" }}
+ endString={"Max"}
+ endStringOnClick={() => setAmount(daiBalance.toString())}
/>}
{
<>
{!isVerySmallScreen && Accumulated {nativeInfo.symbol}:}
- {formatNumber(contractBalanceFree, 5)}
+ {formatCurrency(contractBalanceFree, 5, nativeInfo.symbol)}
{!isVerySmallScreen && You will get:}
diff --git a/src/hooks/prices/index.js b/src/hooks/prices/index.js
index f3a9a21..ee53e2b 100644
--- a/src/hooks/prices/index.js
+++ b/src/hooks/prices/index.js
@@ -1,6 +1,6 @@
import { useReadContract } from "wagmi";
-import { useCurrentIndex } from "../staking";
+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";
@@ -20,13 +20,19 @@ export const useFtsoPrice = (chainId) => {
"GDAI",
);
- const stableReserves = DAI_ADDRESSES[chainId].toUpperCase() === tokens.token0.toUpperCase()
- ? reserves.reserve0._value
- : DAI_ADDRESSES[chainId].toUpperCase() === tokens.token1.toUpperCase() ? reserves.reserve1._value : 0n;
+ const reserveAddress = DAI_ADDRESSES[chainId];
+ const ftsoAddress = FTSO_ADDRESSES[chainId];
+ if (!reserveAddress || !ftsoAddress) {
+ return new DecimalBigNumber(0n, 9);
+ }
- const ftsoReserves = FTSO_ADDRESSES[chainId].toUpperCase() === tokens.token0.toUpperCase()
+ const stableReserves = reserveAddress.toUpperCase() === tokens.token0.toUpperCase()
? reserves.reserve0._value
- : FTSO_ADDRESSES[chainId].toUpperCase() === tokens.token1.toUpperCase() ? reserves.reserve1._value : 0n;
+ : reserveAddress.toUpperCase() === tokens.token1.toUpperCase() ? reserves.reserve1._value : 0n;
+
+ const ftsoReserves = ftsoAddress.toUpperCase() === tokens.token0.toUpperCase()
+ ? reserves.reserve0._value
+ : ftsoAddress.toUpperCase() === tokens.token1.toUpperCase() ? reserves.reserve1._value : 0n;
let price = 0n
if (ftsoReserves > 0n)
@@ -46,3 +52,10 @@ export const useGhstPrice = (chainId) => {
return ftsoPrice.mul(currentIndex);
};
+
+export const useGhostedSupplyPrice = (chainId) => {
+ const ghstPrice = useGhstPrice(chainId);
+ const ghostedSupply = useGhostedSupply(chainId);
+
+ return ghstPrice.mul(ghostedSupply);
+}
diff --git a/src/hooks/staking/index.js b/src/hooks/staking/index.js
index b540a97..c5d7d9e 100644
--- a/src/hooks/staking/index.js
+++ b/src/hooks/staking/index.js
@@ -83,6 +83,36 @@ 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,
@@ -186,6 +216,24 @@ 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,
@@ -211,8 +259,11 @@ const executeOnChainTransaction = async (
});
toast.success(messages.successMsg);
+
+ return txHash;
} catch (err) {
console.error(err);
toast.error(messages.errorMsg)
+ return undefined;
}
}
diff --git a/src/main.jsx b/src/main.jsx
index 4624117..dbbd427 100644
--- a/src/main.jsx
+++ b/src/main.jsx
@@ -14,7 +14,6 @@ const queryClient = new QueryClient();
const TRACKING_ID = import.meta.env.VITE_APP_TRACKING_ID;
ReactGA.initialize(TRACKING_ID);
-
ReactDOM.createRoot(document.getElementById('root')).render(
<>
diff --git a/src/themes/darkPalette.js b/src/themes/darkPalette.js
index 1dcdabb..ebe1a59 100644
--- a/src/themes/darkPalette.js
+++ b/src/themes/darkPalette.js
@@ -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: "#F06F73", // idk where this is - done
+ warning: "#49A1F2", // idk where this is - done
pnlGain: "#60C45B", // green positive % - done
},
gray: {