calldata preparation and parsing added
Signed-off-by: Uncle Fatso <uncle.fatso@ghostchain.io>
This commit is contained in:
parent
982e191474
commit
126a890999
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "ghost-dao-interface",
|
"name": "ghost-dao-interface",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.5.9",
|
"version": "0.5.10",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@ -14,7 +14,7 @@ import Sidebar from "./components/Sidebar/Sidebar";
|
|||||||
import TopBar from "./components/TopBar/TopBar";
|
import TopBar from "./components/TopBar/TopBar";
|
||||||
|
|
||||||
import { shouldTriggerSafetyCheck } from "./helpers";
|
import { shouldTriggerSafetyCheck } from "./helpers";
|
||||||
import { isNetworkAvailable, isNetworkLegacy } from "./constants";
|
import { isNetworkAvailable, isNetworkLegacy, isGovernanceAvailable } from "./constants";
|
||||||
import useTheme from "./hooks/useTheme";
|
import useTheme from "./hooks/useTheme";
|
||||||
import { useUnstableProvider } from "./hooks/ghost";
|
import { useUnstableProvider } from "./hooks/ghost";
|
||||||
import { dark as darkTheme } from "./themes/dark.js";
|
import { dark as darkTheme } from "./themes/dark.js";
|
||||||
@ -216,9 +216,9 @@ function App() {
|
|||||||
}
|
}
|
||||||
<Route path="/bridge" element={<Bridge config={config} connect={tryConnectInjected} address={address} chainId={addressChainId ? addressChainId : chainId} />} />
|
<Route path="/bridge" element={<Bridge config={config} connect={tryConnectInjected} address={address} chainId={addressChainId ? addressChainId : chainId} />} />
|
||||||
<Route path="/dex/:name" element={<Dex connect={tryConnectInjected} address={address} chainId={addressChainId ? addressChainId : chainId} />} />
|
<Route path="/dex/:name" element={<Dex connect={tryConnectInjected} address={address} chainId={addressChainId ? addressChainId : chainId} />} />
|
||||||
<Route path="/governance" element={<Governance config={config} connect={tryConnectInjected} address={address} chainId={addressChainId ? addressChainId : chainId} />} />
|
{isGovernanceAvailable(chainId, addressChainId) && <Route path="/governance" element={<Governance config={config} connect={tryConnectInjected} address={address} chainId={addressChainId ? addressChainId : chainId} />} />}
|
||||||
<Route path="/governance/:id" element={<ProposalDetails config={config} connect={tryConnectInjected} address={address} chainId={addressChainId ? addressChainId : chainId} />} />
|
{isGovernanceAvailable(chainId, addressChainId) && <Route path="/governance/:id" element={<ProposalDetails config={config} connect={tryConnectInjected} address={address} chainId={addressChainId ? addressChainId : chainId} />} />}
|
||||||
<Route path="/governance/create" element={<NewProposal config={config} connect={tryConnectInjected} address={address} chainId={addressChainId ? addressChainId : chainId} />} />
|
{isGovernanceAvailable(chainId, addressChainId) && <Route path="/governance/create" element={<NewProposal config={config} connect={tryConnectInjected} address={address} chainId={addressChainId ? addressChainId : chainId} />} />}
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
<Route path="/empty" element={<NotFound
|
<Route path="/empty" element={<NotFound
|
||||||
|
|||||||
1
src/abi/GhostDistributor.json
Normal file
1
src/abi/GhostDistributor.json
Normal file
File diff suppressed because one or more lines are too long
1
src/abi/Governor.json
Normal file
1
src/abi/Governor.json
Normal file
File diff suppressed because one or more lines are too long
1
src/abi/GovernorStorage.json
Normal file
1
src/abi/GovernorStorage.json
Normal file
File diff suppressed because one or more lines are too long
1
src/abi/GovernorVotesQuorumFraction.json
Normal file
1
src/abi/GovernorVotesQuorumFraction.json
Normal file
File diff suppressed because one or more lines are too long
@ -32,6 +32,7 @@ const Select = ({
|
|||||||
onChange,
|
onChange,
|
||||||
options,
|
options,
|
||||||
inputWidth,
|
inputWidth,
|
||||||
|
renderValue = null,
|
||||||
width = "100%",
|
width = "100%",
|
||||||
}) => {
|
}) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
@ -56,6 +57,7 @@ const Select = ({
|
|||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
inputWidth={inputWidth}
|
inputWidth={inputWidth}
|
||||||
IconComponent={KeyboardArrowDownIcon}
|
IconComponent={KeyboardArrowDownIcon}
|
||||||
|
renderValue={renderValue}
|
||||||
displayEmpty
|
displayEmpty
|
||||||
>
|
>
|
||||||
{options.map((opt) => (
|
{options.map((opt) => (
|
||||||
|
|||||||
@ -39,7 +39,7 @@ import BondIcon from "../Icon/BondIcon";
|
|||||||
import StakeIcon from "../Icon/StakeIcon";
|
import StakeIcon from "../Icon/StakeIcon";
|
||||||
import WrapIcon from "../Icon/WrapIcon";
|
import WrapIcon from "../Icon/WrapIcon";
|
||||||
|
|
||||||
import { isNetworkAvailable, isNetworkLegacy } from "../../constants";
|
import { isNetworkAvailable, isNetworkLegacy, isGovernanceAvailable } from "../../constants";
|
||||||
import { AVAILABLE_DEXES } from "../../constants/dexes";
|
import { AVAILABLE_DEXES } from "../../constants/dexes";
|
||||||
import { ECOSYSTEM } from "../../constants/ecosystem";
|
import { ECOSYSTEM } from "../../constants/ecosystem";
|
||||||
import { DecimalBigNumber } from "../../helpers/DecimalBigNumber";
|
import { DecimalBigNumber } from "../../helpers/DecimalBigNumber";
|
||||||
@ -180,7 +180,7 @@ const NavContent = ({ chainId, addressChainId }) => {
|
|||||||
/>
|
/>
|
||||||
<NavItem icon={StakeIcon} label={`Stake`} to="/stake" />
|
<NavItem icon={StakeIcon} label={`Stake`} to="/stake" />
|
||||||
<NavItem icon={ForkRightIcon} label={`Bridge`} to="/bridge" />
|
<NavItem icon={ForkRightIcon} label={`Bridge`} to="/bridge" />
|
||||||
<NavItem icon={GavelIcon} label={`Governance`} to="/governance" />
|
{isGovernanceAvailable(chainId, addressChainId) && <NavItem icon={GavelIcon} label={`Governance`} to="/governance" />}
|
||||||
<Box className="menu-divider">
|
<Box className="menu-divider">
|
||||||
<Divider />
|
<Divider />
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@ -4,6 +4,19 @@ export enum NetworkId {
|
|||||||
TESTNET_MORDOR = 63,
|
TESTNET_MORDOR = 63,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const isGovernanceAvailable = (chainId, addressChainId) => {
|
||||||
|
chainId = addressChainId ? addressChainId : chainId;
|
||||||
|
let exists = false;
|
||||||
|
switch (chainId) {
|
||||||
|
case 11155111:
|
||||||
|
exists = true
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return exists;
|
||||||
|
}
|
||||||
|
|
||||||
export const isNetworkAvailable = (chainId, addressChainId) => {
|
export const isNetworkAvailable = (chainId, addressChainId) => {
|
||||||
chainId = addressChainId ? addressChainId : chainId;
|
chainId = addressChainId ? addressChainId : chainId;
|
||||||
let exists = false;
|
let exists = false;
|
||||||
|
|||||||
@ -1,25 +1,25 @@
|
|||||||
import { NetworkId } from "../constants";
|
import { NetworkId } from "../constants";
|
||||||
|
|
||||||
export const STAKING_ADDRESSES = {
|
export const STAKING_ADDRESSES = {
|
||||||
[NetworkId.TESTNET_SEPOLIA]: "0xC2C579631Bf6daA93252154080fecfd68c6aa506",//"0xd90E63E88282596E1ea33765b41Ba3d650f4aD52",
|
[NetworkId.TESTNET_SEPOLIA]: "0xC2C579631Bf6daA93252154080fecfd68c6aa506",
|
||||||
[NetworkId.TESTNET_HOODI]: "0x25F62eDc6C89FF84E957C22336A35d2dfc861a86",
|
[NetworkId.TESTNET_HOODI]: "0x25F62eDc6C89FF84E957C22336A35d2dfc861a86",
|
||||||
[NetworkId.TESTNET_MORDOR]: "0xC25C9C56a89ebd6ef291b415d00ACfa7913c55e7",
|
[NetworkId.TESTNET_MORDOR]: "0xC25C9C56a89ebd6ef291b415d00ACfa7913c55e7",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const BOND_DEPOSITORY_ADDRESSES = {
|
export const BOND_DEPOSITORY_ADDRESSES = {
|
||||||
[NetworkId.TESTNET_SEPOLIA]: "0x46BF6F7c3e96351eab7542f2B14c9f2ac6d08dF0",//"0xdcE486113280e49ca2fB200258E5Ee1B2D21D495",
|
[NetworkId.TESTNET_SEPOLIA]: "0x46BF6F7c3e96351eab7542f2B14c9f2ac6d08dF0",
|
||||||
[NetworkId.TESTNET_HOODI]: "0x6Ad50B1E293E68B2fC230c576220a93A9D311571",
|
[NetworkId.TESTNET_HOODI]: "0x6Ad50B1E293E68B2fC230c576220a93A9D311571",
|
||||||
[NetworkId.TESTNET_MORDOR]: "0x7C85cDEddBAd0f50453d373F7332BEa11ECa7BAf",
|
[NetworkId.TESTNET_MORDOR]: "0x7C85cDEddBAd0f50453d373F7332BEa11ECa7BAf",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DAO_TREASURY_ADDRESSES = {
|
export const DAO_TREASURY_ADDRESSES = {
|
||||||
[NetworkId.TESTNET_SEPOLIA]: "0x05D797f9F34844594C956da58f1785997397f02E",//"0x93dd30f819403710de7933B79A74C4A42438458D",
|
[NetworkId.TESTNET_SEPOLIA]: "0x05D797f9F34844594C956da58f1785997397f02E",
|
||||||
[NetworkId.TESTNET_HOODI]: "0x1a1b29b18f714fac9dDabEf530dFc4f85b56A6e8",
|
[NetworkId.TESTNET_HOODI]: "0x1a1b29b18f714fac9dDabEf530dFc4f85b56A6e8",
|
||||||
[NetworkId.TESTNET_MORDOR]: "0x5883C8e2259556B534036c7fDF4555E09dE9f243",
|
[NetworkId.TESTNET_MORDOR]: "0x5883C8e2259556B534036c7fDF4555E09dE9f243",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const FTSO_DAI_LP_ADDRESSES = {
|
export const FTSO_DAI_LP_ADDRESSES = {
|
||||||
[NetworkId.TESTNET_SEPOLIA]: "0x1394dC3f7bABaa2F0CA80353648087DAB1BF3fd6", // TBD
|
[NetworkId.TESTNET_SEPOLIA]: "0xCd1505E5d169525e0241c177aF5929A92E02276D",
|
||||||
[NetworkId.TESTNET_HOODI]: "0xf7B2d44209E70782d93A70F7D8eC50010dF7ae50",
|
[NetworkId.TESTNET_HOODI]: "0xf7B2d44209E70782d93A70F7D8eC50010dF7ae50",
|
||||||
[NetworkId.TESTNET_MORDOR]: "0xE6546D12665dB5B22Cb92FB9e0221aE51A57aeaa",
|
[NetworkId.TESTNET_MORDOR]: "0xE6546D12665dB5B22Cb92FB9e0221aE51A57aeaa",
|
||||||
};
|
};
|
||||||
@ -31,7 +31,7 @@ export const FTSO_STNK_LP_ADDRESSES = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const RESERVE_ADDRESSES = {
|
export const RESERVE_ADDRESSES = {
|
||||||
[NetworkId.TESTNET_SEPOLIA]: "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14",//"0x5f63a27a9214a0352F2EF8dAF1eD4974d713192B",
|
[NetworkId.TESTNET_SEPOLIA]: "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14",
|
||||||
[NetworkId.TESTNET_HOODI]: "0x80c6676c334BCcE60b3CC852085B72143379CE58",
|
[NetworkId.TESTNET_HOODI]: "0x80c6676c334BCcE60b3CC852085B72143379CE58",
|
||||||
[NetworkId.TESTNET_MORDOR]: "0x6af91B3763b5d020E0985f85555EB50e5852d7AC",
|
[NetworkId.TESTNET_MORDOR]: "0x6af91B3763b5d020E0985f85555EB50e5852d7AC",
|
||||||
};
|
};
|
||||||
@ -43,37 +43,35 @@ export const WETH_ADDRESSES = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const GHST_ADDRESSES = {
|
export const GHST_ADDRESSES = {
|
||||||
[NetworkId.TESTNET_SEPOLIA]: "0x1eCee8BfceC44e535B3Ee92Aca70507668781392",//"0xdf2e5306A3dCcfA4e21bbF4226C17Ff5B008dDC4",
|
[NetworkId.TESTNET_SEPOLIA]: "0x1eCee8BfceC44e535B3Ee92Aca70507668781392",
|
||||||
[NetworkId.TESTNET_HOODI]: "0xE98f7426457E6533B206e91B7EcA97aa8A258B46",
|
[NetworkId.TESTNET_HOODI]: "0xE98f7426457E6533B206e91B7EcA97aa8A258B46",
|
||||||
[NetworkId.TESTNET_MORDOR]: "0x14b5787F8a1E62786F50A7998A9b14aa24298423",
|
[NetworkId.TESTNET_MORDOR]: "0x14b5787F8a1E62786F50A7998A9b14aa24298423",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const STNK_ADDRESSES = {
|
export const STNK_ADDRESSES = {
|
||||||
[NetworkId.TESTNET_SEPOLIA]: "0xa31cf59baC26Dd8A8b422b999eB1Ba541C941EA7",//"0x02C296A27eA779d5a16F934337c12062C5E3c0D9",
|
[NetworkId.TESTNET_SEPOLIA]: "0xa31cf59baC26Dd8A8b422b999eB1Ba541C941EA7",
|
||||||
[NetworkId.TESTNET_HOODI]: "0xF07e9303A9f16Afd82f4f57Fd6fca68Aa0AB6D7F",
|
[NetworkId.TESTNET_HOODI]: "0xF07e9303A9f16Afd82f4f57Fd6fca68Aa0AB6D7F",
|
||||||
[NetworkId.TESTNET_MORDOR]: "0x137bA9403885D8ECEa95AaFBb8734F5a16121bAC",
|
[NetworkId.TESTNET_MORDOR]: "0x137bA9403885D8ECEa95AaFBb8734F5a16121bAC",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const FTSO_ADDRESSES = {
|
export const FTSO_ADDRESSES = {
|
||||||
[NetworkId.TESTNET_SEPOLIA]: "0x7ebd1224D36d64eA09312073e60f352d1383801A",//"0xcFedFFEB3FdeCd2196820Ba3b71f3F84A1255f93",
|
[NetworkId.TESTNET_SEPOLIA]: "0x7ebd1224D36d64eA09312073e60f352d1383801A",
|
||||||
[NetworkId.TESTNET_HOODI]: "0xb184e423811b644A1924334E63985c259F5D0033",
|
[NetworkId.TESTNET_HOODI]: "0xb184e423811b644A1924334E63985c259F5D0033",
|
||||||
[NetworkId.TESTNET_MORDOR]: "0xeA170CC0faceC531a6a9e93a28C4330Ac50343a1",
|
[NetworkId.TESTNET_MORDOR]: "0xeA170CC0faceC531a6a9e93a28C4330Ac50343a1",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DISTRIBUTOR_ADDRESSES = {
|
export const DISTRIBUTOR_ADDRESSES = {
|
||||||
[NetworkId.TESTNET_SEPOLIA]: "0xfa524772eec78FAeD0db2cF8A831FDDa9F5B0544",//"0x8fbF8eB4Fcd451EF62Aee33508D46FE120963194",
|
[NetworkId.TESTNET_SEPOLIA]: "0xfa524772eec78FAeD0db2cF8A831FDDa9F5B0544",
|
||||||
[NetworkId.TESTNET_HOODI]: "0xdF49dC81c457c6f92e26cf6d686C7a8715255842",
|
[NetworkId.TESTNET_HOODI]: "0xdF49dC81c457c6f92e26cf6d686C7a8715255842",
|
||||||
[NetworkId.TESTNET_MORDOR]: "0xaf5e76706520db7fb01096E322940206bf3fce57",
|
[NetworkId.TESTNET_MORDOR]: "0xaf5e76706520db7fb01096E322940206bf3fce57",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const GHOST_GOVERNANCE_ADDRESSES = {
|
export const GHOST_GOVERNANCE_ADDRESSES = {
|
||||||
[NetworkId.TESTNET_SEPOLIA]: "0x4823F1DC785D721eAdD2bD218E1eeD63aF67fBF4",
|
[NetworkId.TESTNET_SEPOLIA]: "0x4823F1DC785D721eAdD2bD218E1eeD63aF67fBF4",
|
||||||
[NetworkId.TESTNET_HOODI]: "0x1B96B792840d4d19d5097ee007392Ed4d851e64F",
|
|
||||||
[NetworkId.TESTNET_MORDOR]: "0x3dD438416D9593A58193fC52850E588efAa3D57E",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const BONDING_CALCULATOR_ADDRESSES = {
|
export const BONDING_CALCULATOR_ADDRESSES = {
|
||||||
[NetworkId.TESTNET_SEPOLIA]: "0xfA821181de76D3EAdb404dDe971A6d28289F22b3",//"0x4896bFc6256A57Df826d7144E48c9633d51d6319",
|
[NetworkId.TESTNET_SEPOLIA]: "0xfA821181de76D3EAdb404dDe971A6d28289F22b3",
|
||||||
[NetworkId.TESTNET_HOODI]: "0x2635d526Ad24b98082563937f7b996075052c6Fd",
|
[NetworkId.TESTNET_HOODI]: "0x2635d526Ad24b98082563937f7b996075052c6Fd",
|
||||||
[NetworkId.TESTNET_MORDOR]: "0x0c4C7C49a173E2a3f9Eed93125F3F146D8e17bCb",
|
[NetworkId.TESTNET_MORDOR]: "0x0c4C7C49a173E2a3f9Eed93125F3F146D8e17bCb",
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { useState, useMemo } from "react";
|
import { useState, useMemo } from "react";
|
||||||
|
import toast from "react-hot-toast";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
@ -24,6 +25,7 @@ import ArrowUpIcon from "../../assets/icons/arrow-up.svg?react";
|
|||||||
import Paper from "../../components/Paper/Paper";
|
import Paper from "../../components/Paper/Paper";
|
||||||
import PageTitle from "../../components/PageTitle/PageTitle";
|
import PageTitle from "../../components/PageTitle/PageTitle";
|
||||||
import { PrimaryButton, TertiaryButton } from "../../components/Button";
|
import { PrimaryButton, TertiaryButton } from "../../components/Button";
|
||||||
|
import { useTokenSymbol } from "../../hooks/tokens";
|
||||||
|
|
||||||
import ProposalModal from "./components/ProposalModal";
|
import ProposalModal from "./components/ProposalModal";
|
||||||
import { parseFunctionCalldata } from "./components/functions/index";
|
import { parseFunctionCalldata } from "./components/functions/index";
|
||||||
@ -35,6 +37,8 @@ const NewProposal = ({ config, address, connect, chainId }) => {
|
|||||||
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
|
const { symbol: ftsoSymbol } = useTokenSymbol(chainId, "FTSO");
|
||||||
|
|
||||||
const [isModalOpened, setIsModalOpened] = useState(false);
|
const [isModalOpened, setIsModalOpened] = useState(false);
|
||||||
const [proposalFunctions, setProposalFunctions] = useState([]);
|
const [proposalFunctions, setProposalFunctions] = useState([]);
|
||||||
|
|
||||||
@ -47,13 +51,20 @@ const NewProposal = ({ config, address, connect, chainId }) => {
|
|||||||
}, [config]);
|
}, [config]);
|
||||||
|
|
||||||
const submitProposal = () => {
|
const submitProposal = () => {
|
||||||
alert("Proposal created");
|
toast.success("Coming soon! It's already connected to the chain data!", { duration: 5000 });
|
||||||
setProposalFunctions([]);
|
setProposalFunctions([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ProposalModal addCalldata={addCalldata} isOpened={isModalOpened} closeModal={() => setIsModalOpened(false)} />
|
<ProposalModal
|
||||||
|
nativeCurrency={nativeCurrency}
|
||||||
|
ftsoSymbol={ftsoSymbol}
|
||||||
|
chainId={chainId}
|
||||||
|
addCalldata={addCalldata}
|
||||||
|
isOpened={isModalOpened}
|
||||||
|
closeModal={() => setIsModalOpened(false)}
|
||||||
|
/>
|
||||||
<Box>
|
<Box>
|
||||||
<PageTitle name="Create Proposal" subtitle="Cool text describing what's goinf on there" />
|
<PageTitle name="Create Proposal" subtitle="Cool text describing what's goinf on there" />
|
||||||
<Container
|
<Container
|
||||||
@ -92,28 +103,19 @@ const NewProposal = ({ config, address, connect, chainId }) => {
|
|||||||
<Typography variant="subtitle1">
|
<Typography variant="subtitle1">
|
||||||
Create new proposal by adding functions below
|
Create new proposal by adding functions below
|
||||||
</Typography>
|
</Typography>
|
||||||
<Link
|
|
||||||
color={theme.colors.primary[300]}
|
<PrimaryButton
|
||||||
|
variant="text"
|
||||||
href="https://forum.ghostchain.io"
|
href="https://forum.ghostchain.io"
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
display="flex"
|
|
||||||
alignItems="center"
|
|
||||||
>
|
>
|
||||||
Learn more
|
Learn more
|
||||||
<GhostStyledIcon
|
</PrimaryButton>
|
||||||
style={{ marginTop: "7px" }}
|
|
||||||
viewBox="0 0 30 30"
|
|
||||||
className="external-site-link-icon"
|
|
||||||
component={ArrowUpIcon}
|
|
||||||
/>
|
|
||||||
</Link>
|
|
||||||
</Box>}
|
</Box>}
|
||||||
|
|
||||||
</Box>
|
</Box>
|
||||||
<Box>
|
<Box display="flex" flexDirection="column" alignItems="center">
|
||||||
<TertiaryButton fullWidth onClick={() => setIsModalOpened(true)}>Add New</TertiaryButton>
|
<TertiaryButton sx={{ maxWidth: isSemiSmallScreen ? "100%" : "350px" }} fullWidth onClick={() => setIsModalOpened(true)}>Add New</TertiaryButton>
|
||||||
<PrimaryButton fullWidth onClick={() => submitProposal()}>Submit Proposal</PrimaryButton>
|
<PrimaryButton sx={{ maxWidth: isSemiSmallScreen ? "100%" : "350px" }} fullWidth onClick={() => submitProposal()}>Submit Proposal</PrimaryButton>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Paper>
|
</Paper>
|
||||||
@ -138,8 +140,8 @@ const NewProposal = ({ config, address, connect, chainId }) => {
|
|||||||
<TableCell align="center" style={{ padding: "8px 0" }}>Value</TableCell>
|
<TableCell align="center" style={{ padding: "8px 0" }}>Value</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
<TableBody>{proposalFunctions.map((calldata, index) => {
|
<TableBody>{proposalFunctions.map((metadata, index) => {
|
||||||
return parseFunctionCalldata(calldata, index, nativeCurrency, removeCalldata);
|
return parseFunctionCalldata(metadata, index, chainId, nativeCurrency, removeCalldata);
|
||||||
})}</TableBody>
|
})}</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
</TableContainer>
|
</TableContainer>
|
||||||
|
|||||||
@ -25,8 +25,10 @@ export const MinQuorumPercentage = props => {
|
|||||||
label: `Min Quorum`,
|
label: `Min Quorum`,
|
||||||
tooltip: `Minimum $${props.ghstSymbol} turnout required for the proposal to become valid`,
|
tooltip: `Minimum $${props.ghstSymbol} turnout required for the proposal to become valid`,
|
||||||
};
|
};
|
||||||
|
const tokenValue = formatCurrency(value?.toString(), 2, props.ghstSymbol);
|
||||||
|
const percentageValue = formatNumber(percentage * 100, 2);
|
||||||
|
|
||||||
if (percentage) _props.metric = `${formatCurrency(value?.toString(), 2, props.ghstSymbol)} (${formatNumber(percentage * 100, 2)}%)`;
|
if (percentage) _props.metric = `${tokenValue} (${percentageValue}%)`;
|
||||||
else _props.isLoading = true;
|
else _props.isLoading = true;
|
||||||
|
|
||||||
return <Metric {..._props} />;
|
return <Metric {..._props} />;
|
||||||
@ -41,22 +43,22 @@ export const ProposalThreshold = props => {
|
|||||||
tooltip: `Minimum $${props.ghstSymbol} required to be locked to create a proposal`,
|
tooltip: `Minimum $${props.ghstSymbol} required to be locked to create a proposal`,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (threshold) _props.metric = `${formatCurrency(threshold.toString(), 0, props.ghstSymbol)}`;
|
if (threshold) _props.metric = `${formatCurrency(threshold.toString(), 2, props.ghstSymbol)}`;
|
||||||
else _props.isLoading = true;
|
else _props.isLoading = true;
|
||||||
|
|
||||||
return <Metric {..._props} />;
|
return <Metric {..._props} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ProposalsCount = props => {
|
export const ProposalsCount = props => {
|
||||||
const { proposalsCount } = useProposalCount(props.chainId);
|
const { proposalCount } = useProposalCount(props.chainId);
|
||||||
|
|
||||||
const _props = {
|
const _props = {
|
||||||
...props,
|
...props,
|
||||||
label: `Proposals Count`,
|
label: `Proposal Count`,
|
||||||
tooltip: `Total proposals created`,
|
tooltip: `Total proposals created`,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (proposalsCount) _props.metric = `${formatNumber(proposalsCount.toString(), 0)}`;
|
if (proposalCount || proposalCount === 0n) _props.metric = `${formatNumber(proposalCount.toString(), 0)}`;
|
||||||
else _props.isLoading = true;
|
else _props.isLoading = true;
|
||||||
|
|
||||||
return <Metric {..._props} />;
|
return <Metric {..._props} />;
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { useState, useEffect, useMemo, useCallback } from "react";
|
import { useState, useEffect, useMemo, useCallback } from "react";
|
||||||
import { Box, Typography } from "@mui/material";
|
import { Box, Typography, useTheme } from "@mui/material";
|
||||||
|
|
||||||
import Modal from "../../../components/Modal/Modal";
|
import Modal from "../../../components/Modal/Modal";
|
||||||
import Select from "../../../components/Select/Select";
|
import Select from "../../../components/Select/Select";
|
||||||
@ -12,7 +12,7 @@ import {
|
|||||||
allPossibleFunctions
|
allPossibleFunctions
|
||||||
} from "./functions";
|
} from "./functions";
|
||||||
|
|
||||||
const ProposalModal = ({ isOpened, closeModal, addCalldata }) => {
|
const ProposalModal = ({ isOpened, closeModal, nativeCurrency, ftsoSymbol, addCalldata, chainId }) => {
|
||||||
const [selectedOption, setSelectedOption] = useState();
|
const [selectedOption, setSelectedOption] = useState();
|
||||||
const [renderArguments, setRenderArguments] = useState(false);
|
const [renderArguments, setRenderArguments] = useState(false);
|
||||||
|
|
||||||
@ -29,10 +29,10 @@ const ProposalModal = ({ isOpened, closeModal, addCalldata }) => {
|
|||||||
}, [selectedOption, renderArguments]);
|
}, [selectedOption, renderArguments]);
|
||||||
|
|
||||||
const handleCalldata = useCallback(() => {
|
const handleCalldata = useCallback(() => {
|
||||||
addCalldata(getFunctionCalldata(selectedOption));
|
addCalldata(getFunctionCalldata(selectedOption, chainId));
|
||||||
setSelectedOption(null);
|
setSelectedOption(null);
|
||||||
closeModal();
|
closeModal();
|
||||||
}, [selectedOption]);
|
}, [selectedOption, chainId]);
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
setSelectedOption(null);
|
setSelectedOption(null);
|
||||||
@ -45,7 +45,7 @@ const ProposalModal = ({ isOpened, closeModal, addCalldata }) => {
|
|||||||
handleClose();
|
handleClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
const ArgumentsSteps = useMemo(() => getFunctionArguments(selectedOption), [selectedOption]);
|
const ArgumentsSteps = useMemo(() => getFunctionArguments(selectedOption, chainId), [selectedOption]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
@ -62,6 +62,9 @@ const ProposalModal = ({ isOpened, closeModal, addCalldata }) => {
|
|||||||
<Box minHeight="220px" display="flex" alignItems="start" justifyContent="space-between" flexDirection="column">
|
<Box minHeight="220px" display="flex" alignItems="start" justifyContent="space-between" flexDirection="column">
|
||||||
{renderArguments
|
{renderArguments
|
||||||
? <ArgumentsSteps
|
? <ArgumentsSteps
|
||||||
|
nativeCurrency={nativeCurrency}
|
||||||
|
ftsoSymbol={ftsoSymbol}
|
||||||
|
chainId={chainId}
|
||||||
addCalldata={handleAddCalldata}
|
addCalldata={handleAddCalldata}
|
||||||
toInitialStep={() => setRenderArguments(false)}
|
toInitialStep={() => setRenderArguments(false)}
|
||||||
/>
|
/>
|
||||||
@ -79,6 +82,7 @@ const ProposalModal = ({ isOpened, closeModal, addCalldata }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const InitialStep = ({ selectedOption, handleChange, handleCalldata, handleProceed, ready }) => {
|
const InitialStep = ({ selectedOption, handleChange, handleCalldata, handleProceed, ready }) => {
|
||||||
|
const theme = useTheme();
|
||||||
const functionDescription = useMemo(() => getFunctionDescription(selectedOption), [selectedOption]);
|
const functionDescription = useMemo(() => getFunctionDescription(selectedOption), [selectedOption]);
|
||||||
return (
|
return (
|
||||||
<Box minHeight="220px" display="flex" alignItems="start" justifyContent="space-between" flexDirection="column">
|
<Box minHeight="220px" display="flex" alignItems="start" justifyContent="space-between" flexDirection="column">
|
||||||
@ -87,6 +91,17 @@ const InitialStep = ({ selectedOption, handleChange, handleCalldata, handleProce
|
|||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
options={allPossibleFunctions}
|
options={allPossibleFunctions}
|
||||||
inputWidth="100%"
|
inputWidth="100%"
|
||||||
|
renderValue={(selected) => {
|
||||||
|
if (!selected || selected.length === 0) {
|
||||||
|
return (
|
||||||
|
<span style={{ color: theme.colors.gray[500], opacity: 0.7 }}>
|
||||||
|
Select function
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return allPossibleFunctions.find(opt => opt.value === selected)?.label || selected;
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<Typography align="center" variant="body2">{functionDescription}</Typography>
|
<Typography align="center" variant="body2">{functionDescription}</Typography>
|
||||||
{ready
|
{ready
|
||||||
|
|||||||
@ -120,22 +120,12 @@ const ProposalsList = ({ chainId, config }) => {
|
|||||||
Proposals
|
Proposals
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Link
|
<PrimaryButton
|
||||||
color={theme.colors.primary[300]}
|
variant="text"
|
||||||
href="https://forum.ghostchain.io"
|
href="https://forum.ghostchain.io"
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
display="flex"
|
|
||||||
alignItems="center"
|
|
||||||
>
|
>
|
||||||
View Forum
|
View Forum
|
||||||
<GhostStyledIcon
|
</PrimaryButton>
|
||||||
style={{ marginTop: "7px" }}
|
|
||||||
viewBox="0 0 30 30"
|
|
||||||
className="external-site-link-icon"
|
|
||||||
component={ArrowUpIcon}
|
|
||||||
/>
|
|
||||||
</Link>
|
|
||||||
</Box>
|
</Box>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@ -165,7 +155,7 @@ const ProposalTable = ({ children }) => (
|
|||||||
<Table aria-label="Available bonds" style={{ tableLayout: "fixed" }}>
|
<Table aria-label="Available bonds" style={{ tableLayout: "fixed" }}>
|
||||||
<TableHead>
|
<TableHead>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell align="center" style={{ width: "100px", padding: "8px 0" }}>Proposal ID</TableCell>
|
<TableCell align="center" style={{ padding: "8px 0" }}>Proposal ID</TableCell>
|
||||||
<TableCell align="center" style={{ padding: "8px 0" }}>Status</TableCell>
|
<TableCell align="center" style={{ padding: "8px 0" }}>Status</TableCell>
|
||||||
<TableCell align="center" style={{ padding: "8px 0" }}>Vote Ends</TableCell>
|
<TableCell align="center" style={{ padding: "8px 0" }}>Vote Ends</TableCell>
|
||||||
<TableCell align="center" style={{ padding: "8px 0" }}>Voting Stats</TableCell>
|
<TableCell align="center" style={{ padding: "8px 0" }}>Voting Stats</TableCell>
|
||||||
@ -222,14 +212,14 @@ const ProposalRow = ({ proposal, blockNumber, openProposal, chainId }) => {
|
|||||||
{(proposal.status === "Active" || proposal.status === "Succeeded") && <PrimaryButton
|
{(proposal.status === "Active" || proposal.status === "Succeeded") && <PrimaryButton
|
||||||
fullWidth
|
fullWidth
|
||||||
onClick={() => openProposal()}
|
onClick={() => openProposal()}
|
||||||
sx={{ maxWidth: "150px" }}
|
sx={{ maxWidth: "130px" }}
|
||||||
>
|
>
|
||||||
{proposal.status === "Succeeded" ? "Execute" : "Vote"}
|
{proposal.status === "Succeeded" ? "Execute" : "Vote"}
|
||||||
</PrimaryButton>}
|
</PrimaryButton>}
|
||||||
{(proposal.status !== "Active" && proposal.status !== "Succeeded") && <TertiaryButton
|
{(proposal.status !== "Active" && proposal.status !== "Succeeded") && <TertiaryButton
|
||||||
fullWidth
|
fullWidth
|
||||||
onClick={() => openProposal()}
|
onClick={() => openProposal()}
|
||||||
sx={{ maxWidth: "150px" }}
|
sx={{ maxWidth: "130px" }}
|
||||||
>
|
>
|
||||||
View
|
View
|
||||||
</TertiaryButton>}
|
</TertiaryButton>}
|
||||||
|
|||||||
@ -1,11 +1,26 @@
|
|||||||
import { Box, Typography, TableCell, TableRow, useTheme } from "@mui/material";
|
import { useMemo } from "react";
|
||||||
import { TertiaryButton } from "../../../../components/Button";
|
import { encodeFunctionData } from 'viem';
|
||||||
|
|
||||||
|
|
||||||
|
import {
|
||||||
|
DAO_TREASURY_ADDRESSES,
|
||||||
|
} from "../../../../constants/addresses";
|
||||||
|
import { abi as TreasuryAbi } from "../../../../abi/GhostTreasury.json";
|
||||||
|
|
||||||
|
import { ParsedCell } from "./index";
|
||||||
|
|
||||||
export const prepareAuditReservesCalldata = (chainId) => {
|
export const prepareAuditReservesCalldata = (chainId) => {
|
||||||
return "0xauditReserves";
|
const value = 0n;
|
||||||
|
const label = "Audit Reserves";
|
||||||
|
const target = DAO_TREASURY_ADDRESSES[chainId];
|
||||||
|
const calldata = encodeFunctionData({
|
||||||
|
abi: TreasuryAbi,
|
||||||
|
functionName: 'auditReserves',
|
||||||
|
});
|
||||||
|
return { label, target, calldata, value };
|
||||||
}
|
}
|
||||||
|
|
||||||
export const prepareAuditReservesDescription = "Explanation about what is audit reserves, pros and cons should be here, we need to fill as much text here as possible to make initial screen usable and not empty.";
|
export const prepareAuditReservesDescription = "Audit Reserves function audits and updates the protocol's total reserve value. It sums the value of all approved reserve and liquidity tokens, then stores and logs the new total.";
|
||||||
|
|
||||||
export const AuditReservesSteps = () => {
|
export const AuditReservesSteps = () => {
|
||||||
return null;
|
return null;
|
||||||
@ -20,26 +35,5 @@ export const AuditReservesParsed = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const AuditReservesParsedCell = (props) => {
|
const AuditReservesParsedCell = (props) => {
|
||||||
return (
|
return <ParsedCell {...props} />
|
||||||
<TableRow id={props.id + `--proposalFunction`} data-testid={props.id + `--proposalFunction`}>
|
|
||||||
<TableCell align="center" style={{ padding: "8px 0" }}>
|
|
||||||
<Typography>Audit Reserves</Typography>
|
|
||||||
</TableCell>
|
|
||||||
|
|
||||||
<TableCell align="center" style={{ padding: "8px 0" }}>
|
|
||||||
<Typography>{props.target}</Typography>
|
|
||||||
</TableCell>
|
|
||||||
|
|
||||||
<TableCell align="center" style={{ padding: "8px 0" }}>
|
|
||||||
<Typography>{props.value} {props.nativeCoin}</Typography>
|
|
||||||
</TableCell>
|
|
||||||
|
|
||||||
{props.remove && <TableCell>
|
|
||||||
<div style={{ display: 'flex', gap: '8px' }}>
|
|
||||||
<TertiaryButton fullWidth onClick={() => alert("Do we need it????")}>Edit</TertiaryButton>
|
|
||||||
<TertiaryButton fullWidth onClick={() => props.remove()}>Delete</TertiaryButton>
|
|
||||||
</div>
|
|
||||||
</TableCell>}
|
|
||||||
</TableRow>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,14 +1,32 @@
|
|||||||
import { useRef, useState } from "react";
|
import { useRef, useMemo, useState, useEffect } from "react";
|
||||||
|
import { encodeFunctionData } from 'viem';
|
||||||
import { Box, Typography, TableRow, TableCell, useTheme } from "@mui/material";
|
import { Box, Typography, TableRow, TableCell, useTheme } from "@mui/material";
|
||||||
|
|
||||||
|
import Select from "../../../../components/Select/Select";
|
||||||
import { PrimaryButton, TertiaryButton } from "../../../../components/Button";
|
import { PrimaryButton, TertiaryButton } from "../../../../components/Button";
|
||||||
import { BooleanTrigger, ArgumentInput } from "./index";
|
import { shorten } from "../../../../helpers";
|
||||||
|
import { BooleanTrigger, ArgumentInput, ParsedCell } from "./index";
|
||||||
|
|
||||||
export const prepareCreateBondCalldata = (chainId) => {
|
import {
|
||||||
return "0xcreateBond";
|
RESERVE_ADDRESSES,
|
||||||
|
FTSO_DAI_LP_ADDRESSES,
|
||||||
|
BOND_DEPOSITORY_ADDRESSES,
|
||||||
|
} from "../../../../constants/addresses";
|
||||||
|
import { abi as DepositoryAbi } from "../../../../abi/GhostBondDepository.json";
|
||||||
|
|
||||||
|
export const prepareCreateBondCalldata = (chainId, markets, terms, quoteToken, intervals, booleans) => {
|
||||||
|
const value = 0n;
|
||||||
|
const label = "Create Bond";
|
||||||
|
const target = BOND_DEPOSITORY_ADDRESSES[chainId];
|
||||||
|
const calldata = encodeFunctionData({
|
||||||
|
abi: DepositoryAbi,
|
||||||
|
functionName: 'create',
|
||||||
|
args: [markets, terms, quoteToken, intervals, booleans]
|
||||||
|
});
|
||||||
|
return { label, target, calldata, value };
|
||||||
}
|
}
|
||||||
|
|
||||||
export const prepareCreateBondDescription = "Explanation about what is bond creation, pros and cons should be here, we need to fill as much text here as possible to make initial screen usable and not empty.";
|
export const prepareCreateBondDescription = "Create Bond function creates a new bond market by processing pricing, capacity, and term inputs. It initializes and stores the new bond market's complete configuration in the protocol.";
|
||||||
|
|
||||||
export const CreateBondParsed = (props) => {
|
export const CreateBondParsed = (props) => {
|
||||||
return (
|
return (
|
||||||
@ -19,41 +37,21 @@ export const CreateBondParsed = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const CreateBondParsedCell = (props) => {
|
const CreateBondParsedCell = (props) => {
|
||||||
return (
|
return <ParsedCell {...props} />
|
||||||
<TableRow id={props.id + `--proposalFunction`} data-testid={props.id + `--proposalFunction`}>
|
|
||||||
<TableCell align="center" style={{ padding: "8px 0" }}>
|
|
||||||
<Typography>Create Bond</Typography>
|
|
||||||
</TableCell>
|
|
||||||
|
|
||||||
<TableCell align="center" style={{ padding: "8px 0" }}>
|
|
||||||
<Typography>{props.target}</Typography>
|
|
||||||
</TableCell>
|
|
||||||
|
|
||||||
<TableCell align="center" style={{ padding: "8px 0" }}>
|
|
||||||
<Typography>{props.value} {props.nativeCoin}</Typography>
|
|
||||||
</TableCell>
|
|
||||||
|
|
||||||
{props.remove && <TableCell>
|
|
||||||
<div style={{ display: 'flex', gap: '8px' }}>
|
|
||||||
<TertiaryButton fullWidth onClick={() => alert("Do we need it????")}>Edit</TertiaryButton>
|
|
||||||
<TertiaryButton fullWidth onClick={() => props.remove()}>Delete</TertiaryButton>
|
|
||||||
</div>
|
|
||||||
</TableCell>}
|
|
||||||
</TableRow>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CreateBondSteps = ({ toInitialStep, addCalldata }) => {
|
export const CreateBondSteps = ({ nativeCurrency, ftsoSymbol, chainId, toInitialStep, addCalldata }) => {
|
||||||
const [step, setStep] = useState(1);
|
const [step, setStep] = useState(1);
|
||||||
|
const [nextDisabled, setNextDisabled] = useState(false);
|
||||||
|
|
||||||
const [capacity, setCapacity] = useState();
|
const [capacity, setCapacity] = useState();
|
||||||
const [initialPrice, setInitialPrice] = useState();
|
const [initialPrice, setInitialPrice] = useState();
|
||||||
const [debtBuffer, setDebtBuffer] = useState();
|
const [debtBuffer, setDebtBuffer] = useState();
|
||||||
|
|
||||||
const [bondVesting, setBondVesting] = useState();
|
const [depositInterval, setDepositInterval] = useState();
|
||||||
const [bondDuration, setBondDuration] = useState();
|
const [tuneInterval, setTuneInterval] = useState();
|
||||||
|
|
||||||
const [tokenAddress, setTokenAddress] = useState("");
|
const [tokenAddress, setTokenAddress] = useState();
|
||||||
const [capacityInQuote, setCapacityInQuote] = useState(true);
|
const [capacityInQuote, setCapacityInQuote] = useState(true);
|
||||||
const [fixedTerm, setFixedTerm] = useState(false);
|
const [fixedTerm, setFixedTerm] = useState(false);
|
||||||
|
|
||||||
@ -61,7 +59,12 @@ export const CreateBondSteps = ({ toInitialStep, addCalldata }) => {
|
|||||||
const [conclusionTimestamp, setConclusionTimestamp] = useState();
|
const [conclusionTimestamp, setConclusionTimestamp] = useState();
|
||||||
|
|
||||||
const handleProceed = () => {
|
const handleProceed = () => {
|
||||||
addCalldata(prepareCreateBondCalldata())
|
const markets = [capacity, initialPrice, debtBuffer];
|
||||||
|
const terms = [vestingLength, conclusionTimestamp];
|
||||||
|
const intervals = [depositInterval, tuneInterval];
|
||||||
|
const booleans = [capacityInQuote, fixedTerm];
|
||||||
|
|
||||||
|
addCalldata(prepareCreateBondCalldata(chainId, markets, terms, tokenAddress, intervals, booleans))
|
||||||
}
|
}
|
||||||
|
|
||||||
const incrementStep = () => {
|
const incrementStep = () => {
|
||||||
@ -73,17 +76,42 @@ export const CreateBondSteps = ({ toInitialStep, addCalldata }) => {
|
|||||||
else toInitialStep();
|
else toInitialStep();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isNextDisabled = useMemo(() => {
|
||||||
|
switch (step) {
|
||||||
|
case 1:
|
||||||
|
return tokenAddress === undefined;
|
||||||
|
case 2:
|
||||||
|
return !capacity || !initialPrice || !debtBuffer;
|
||||||
|
case 3:
|
||||||
|
return !depositInterval || !tuneInterval;
|
||||||
|
case 4:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}, [step, tokenAddress, capacity, initialPrice, debtBuffer, depositInterval, tuneInterval]);
|
||||||
|
|
||||||
|
const possibleTokens = [
|
||||||
|
{ value: FTSO_DAI_LP_ADDRESSES[chainId], label: `${ftsoSymbol}-${nativeCurrency} LP: ${shorten(FTSO_DAI_LP_ADDRESSES[chainId])}` },
|
||||||
|
{ value: RESERVE_ADDRESSES[chainId], label: `${ftsoSymbol}: ${shorten(RESERVE_ADDRESSES[chainId])}` },
|
||||||
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box height="100%" width="100%" display="flex" flexDirection="column" justifyContent="space-between">
|
<Box height="100%" width="100%" display="flex" flexDirection="column" justifyContent="space-between">
|
||||||
{step === 1 && <AddressAndBooleansArguments
|
{step === 1 && <TokenAndBooleansArguments
|
||||||
tokenAddress={tokenAddress}
|
possibleTokens={possibleTokens}
|
||||||
setTokenAddress={setTokenAddress}
|
setTokenAddress={setTokenAddress}
|
||||||
|
nativeCurrency={nativeCurrency}
|
||||||
|
ftsoSymbol={ftsoSymbol}
|
||||||
capacityInQuote={capacityInQuote}
|
capacityInQuote={capacityInQuote}
|
||||||
setCapacityInQuote={setCapacityInQuote}
|
setCapacityInQuote={setCapacityInQuote}
|
||||||
fixedTerm={fixedTerm}
|
fixedTerm={fixedTerm}
|
||||||
setFixedTerm={setFixedTerm}
|
setFixedTerm={setFixedTerm}
|
||||||
/>}
|
/>}
|
||||||
{step === 2 && <MarketArguments
|
{step === 2 && <MarketArguments
|
||||||
|
capacityInQuote={capacityInQuote}
|
||||||
|
nativeCurrency={nativeCurrency}
|
||||||
|
ftsoSymbol={ftsoSymbol}
|
||||||
capacity={capacity}
|
capacity={capacity}
|
||||||
setCapacity={setCapacity}
|
setCapacity={setCapacity}
|
||||||
initialPrice={initialPrice}
|
initialPrice={initialPrice}
|
||||||
@ -91,13 +119,13 @@ export const CreateBondSteps = ({ toInitialStep, addCalldata }) => {
|
|||||||
debtBuffer={debtBuffer}
|
debtBuffer={debtBuffer}
|
||||||
setDebtBuffer={setDebtBuffer}
|
setDebtBuffer={setDebtBuffer}
|
||||||
/>}
|
/>}
|
||||||
{step === 3 && <TermsArguments
|
{step === 3 && <IntervalsArguments
|
||||||
bondVesting={bondVesting}
|
depositInterval={depositInterval}
|
||||||
setBondVesting={setBondVesting}
|
setDepositInterval={setDepositInterval}
|
||||||
bondDuration={bondDuration}
|
tuneInterval={tuneInterval}
|
||||||
setBondDuration={setBondDuration}
|
setTuneInterval={setTuneInterval}
|
||||||
/>}
|
/>}
|
||||||
{step === 4 && <IntervalsArguments
|
{step === 4 && <TermsAgruments
|
||||||
fixedTerm={fixedTerm}
|
fixedTerm={fixedTerm}
|
||||||
vestingLength={vestingLength}
|
vestingLength={vestingLength}
|
||||||
setVestingLength={setVestingLength}
|
setVestingLength={setVestingLength}
|
||||||
@ -107,7 +135,7 @@ export const CreateBondSteps = ({ toInitialStep, addCalldata }) => {
|
|||||||
<Box width="100%" sx={{ marginTop: "20px" }} display="flex" flexDirection="column" gap="5px">
|
<Box width="100%" sx={{ marginTop: "20px" }} display="flex" flexDirection="column" gap="5px">
|
||||||
<Box display="flex" gap="10px">
|
<Box display="flex" gap="10px">
|
||||||
<TertiaryButton onClick={() => decrementStep()} fullWidth>Back</TertiaryButton>
|
<TertiaryButton onClick={() => decrementStep()} fullWidth>Back</TertiaryButton>
|
||||||
<TertiaryButton disabled={step === 4} onClick={() => incrementStep()} fullWidth>Next</TertiaryButton>
|
<TertiaryButton disabled={isNextDisabled} onClick={() => incrementStep()} fullWidth>Next</TertiaryButton>
|
||||||
</Box>
|
</Box>
|
||||||
{step === 4 && <PrimaryButton onClick={() => handleProceed()} fullWidth>Create Function</PrimaryButton>}
|
{step === 4 && <PrimaryButton onClick={() => handleProceed()} fullWidth>Create Function</PrimaryButton>}
|
||||||
</Box>
|
</Box>
|
||||||
@ -116,6 +144,9 @@ export const CreateBondSteps = ({ toInitialStep, addCalldata }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const MarketArguments = ({
|
const MarketArguments = ({
|
||||||
|
capacityInQuote,
|
||||||
|
nativeCurrency,
|
||||||
|
ftsoSymbol,
|
||||||
capacity,
|
capacity,
|
||||||
setCapacity,
|
setCapacity,
|
||||||
initialPrice,
|
initialPrice,
|
||||||
@ -126,57 +157,57 @@ const MarketArguments = ({
|
|||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<ArgumentInput
|
<ArgumentInput
|
||||||
endString="CSPR or LP"
|
endString={capacityInQuote ? nativeCurrency : ftsoSymbol}
|
||||||
label="Bond Capacity"
|
label="Bond Capacity"
|
||||||
value={capacity}
|
value={capacity ?? ""}
|
||||||
setValue={setCapacity}
|
setValue={setCapacity}
|
||||||
tooltip="Bond capacity"
|
tooltip={`Bond market capacity, denominated in ${capacityInQuote ? nativeCurrency : ftsoSymbol}. This determines how the total bond supply is capped`}
|
||||||
/>
|
/>
|
||||||
<ArgumentInput
|
<ArgumentInput
|
||||||
endString="???"
|
endString={nativeCurrency}
|
||||||
label="Bond Initial Price"
|
label="Bond Initial Price"
|
||||||
value={initialPrice}
|
value={initialPrice ?? ""}
|
||||||
setValue={setInitialPrice}
|
setValue={setInitialPrice}
|
||||||
tooltip="Bond initial price"
|
tooltip={`The initial price used to bootstrap the Bond Control Variable (BCV). This price will dynamically adjust based on market demand once trading begins`}
|
||||||
/>
|
/>
|
||||||
<ArgumentInput
|
<ArgumentInput
|
||||||
endString="%"
|
endString="%"
|
||||||
label="Debt buffer"
|
label="Debt buffer"
|
||||||
value={debtBuffer}
|
value={debtBuffer ?? ""}
|
||||||
setValue={setDebtBuffer}
|
setValue={setDebtBuffer}
|
||||||
tooltip="Debt buffer description"
|
tooltip="Safety threshold (in basis points) to cap rapid bond sales. For example, 30,000 equals a 30% buffer above the target debt level"
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const TermsArguments = ({
|
|
||||||
bondVesting,
|
|
||||||
setBondVesting,
|
|
||||||
bondDuration,
|
|
||||||
setBondDuration,
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<Box>
|
|
||||||
<ArgumentInput
|
|
||||||
endString="seconds"
|
|
||||||
label="Bond Vesting"
|
|
||||||
value={bondVesting}
|
|
||||||
setValue={setBondVesting}
|
|
||||||
tooltip="Bond vesting"
|
|
||||||
/>
|
|
||||||
<ArgumentInput
|
|
||||||
endString="seconds"
|
|
||||||
label="Bond Duration"
|
|
||||||
value={bondDuration}
|
|
||||||
setValue={setBondDuration}
|
|
||||||
tooltip="Bond duration"
|
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const IntervalsArguments = ({
|
const IntervalsArguments = ({
|
||||||
|
depositInterval,
|
||||||
|
setDepositInterval,
|
||||||
|
tuneInterval,
|
||||||
|
setTuneInterval,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
<ArgumentInput
|
||||||
|
endString="seconds"
|
||||||
|
label="Deposit Interval"
|
||||||
|
value={depositInterval ?? ""}
|
||||||
|
setValue={setDepositInterval}
|
||||||
|
tooltip="Target timeframe for selling out the market. It regulates price sensitivity: a shorter interval causes the price to drop faster during periods of inactivity"
|
||||||
|
/>
|
||||||
|
<ArgumentInput
|
||||||
|
endString="seconds"
|
||||||
|
label="Tune interval"
|
||||||
|
value={tuneInterval ?? ""}
|
||||||
|
setValue={setTuneInterval}
|
||||||
|
tooltip="The frequency at which the system ensures the bond's internal price stays aligned with the target market price by auto-tuning at specific intervals"
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const TermsAgruments = ({
|
||||||
fixedTerm,
|
fixedTerm,
|
||||||
vestingLength,
|
vestingLength,
|
||||||
setVestingLength,
|
setVestingLength,
|
||||||
@ -187,40 +218,52 @@ const IntervalsArguments = ({
|
|||||||
<Box>
|
<Box>
|
||||||
<ArgumentInput
|
<ArgumentInput
|
||||||
endString="seconds"
|
endString="seconds"
|
||||||
label={fixedTerm ? "Vesting Length" : "Vested Timestamp"}
|
label={fixedTerm ? "Vesting Duration" : "Vested Timestamp"}
|
||||||
value={vestingLength}
|
value={vestingLength ?? ""}
|
||||||
setValue={setVestingLength}
|
setValue={setVestingLength}
|
||||||
tooltip={fixedTerm ? "Vesting length what is" : "Vested timestamp what is"}
|
tooltip={`Determines the vesting schedule: ${fixedTerm
|
||||||
|
? "a relative time offset from the point of purchase"
|
||||||
|
: "a static maturity timestamp"}`}
|
||||||
/>
|
/>
|
||||||
<ArgumentInput
|
<ArgumentInput
|
||||||
endString="seconds"
|
endString="seconds"
|
||||||
label="Bond Conclusion"
|
label="Bond Conclusion"
|
||||||
value={conclusionTimestamp}
|
value={conclusionTimestamp ?? ""}
|
||||||
setValue={setConclusionTimestamp}
|
setValue={setConclusionTimestamp}
|
||||||
tooltip="Bond conclusion timestamp"
|
tooltip="The timestamp that marks the end of the market's lifespan. It defines the point at which the market stops accepting new deposits and the decay mechanism ceases"
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const AddressAndBooleansArguments = ({
|
const TokenAndBooleansArguments = ({
|
||||||
tokenAddress,
|
possibleTokens,
|
||||||
|
nativeCurrency,
|
||||||
|
ftsoSymbol,
|
||||||
setTokenAddress,
|
setTokenAddress,
|
||||||
capacityInQuote,
|
capacityInQuote,
|
||||||
setCapacityInQuote,
|
setCapacityInQuote,
|
||||||
fixedTerm,
|
fixedTerm,
|
||||||
setFixedTerm,
|
setFixedTerm,
|
||||||
}) => {
|
}) => {
|
||||||
|
const theme = useTheme();
|
||||||
|
const [selectedOption, setSelectedOption] = useState();
|
||||||
|
|
||||||
|
const handleChange = (event) => {
|
||||||
|
setSelectedOption(event.target.value);
|
||||||
|
setTokenAddress(event.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<BooleanTrigger
|
<BooleanTrigger
|
||||||
value={capacityInQuote}
|
value={capacityInQuote}
|
||||||
label="Capacity in Quote"
|
label="Capacity Type"
|
||||||
leftText="CSPR?"
|
leftText={nativeCurrency}
|
||||||
rightText="LP?"
|
rightText={ftsoSymbol}
|
||||||
setLeftValue={() => setCapacityInQuote(true)}
|
setLeftValue={() => setCapacityInQuote(true)}
|
||||||
setRightValue={() => setCapacityInQuote(false)}
|
setRightValue={() => setCapacityInQuote(false)}
|
||||||
tooltip="WTF is this"
|
tooltip="Capacity is set in terms of the asset being paid, otherwise it is set in the asset being earned"
|
||||||
/>
|
/>
|
||||||
<BooleanTrigger
|
<BooleanTrigger
|
||||||
value={fixedTerm}
|
value={fixedTerm}
|
||||||
@ -229,15 +272,24 @@ const AddressAndBooleansArguments = ({
|
|||||||
rightText="No"
|
rightText="No"
|
||||||
setLeftValue={() => setFixedTerm(true)}
|
setLeftValue={() => setFixedTerm(true)}
|
||||||
setRightValue={() => setFixedTerm(false)}
|
setRightValue={() => setFixedTerm(false)}
|
||||||
tooltip="Fixed term... No idea what it is"
|
tooltip="Determines whether the bond has a fixed expiration date or a fixed duration starting from the time of purchase"
|
||||||
/>
|
/>
|
||||||
<ArgumentInput
|
<Select
|
||||||
placeholder="0x"
|
value={selectedOption ?? ""}
|
||||||
inputType="text"
|
onChange={handleChange}
|
||||||
label="Token Address"
|
options={possibleTokens}
|
||||||
value={tokenAddress}
|
inputWidth="100%"
|
||||||
setValue={setTokenAddress}
|
renderValue={(selected) => {
|
||||||
tooltip="Token used as deposit for the bond"
|
if (!selected || selected.length === 0) {
|
||||||
|
return (
|
||||||
|
<span style={{ color: theme.colors.gray[500], opacity: 0.7 }}>
|
||||||
|
Select payment token
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return possibleTokens.find(opt => opt.value === selected)?.label || selected;
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1,15 +1,29 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
import { encodeFunctionData } from 'viem';
|
||||||
import { Box, Typography, TableRow, TableCell, useTheme } from "@mui/material";
|
import { Box, Typography, TableRow, TableCell, useTheme } from "@mui/material";
|
||||||
|
|
||||||
import { PrimaryButton, TertiaryButton } from "../../../../components/Button";
|
import { PrimaryButton, TertiaryButton } from "../../../../components/Button";
|
||||||
|
|
||||||
import { BooleanTrigger, ArgumentInput } from "./index";
|
import {
|
||||||
|
DISTRIBUTOR_ADDRESSES,
|
||||||
|
} from "../../../../constants/addresses";
|
||||||
|
import { abi as DistributorAbi } from "../../../../abi/GhostDistributor.json";
|
||||||
|
|
||||||
export const prepareSetAdjustmentCalldata = (chainId) => {
|
import { BooleanTrigger, ArgumentInput, ParsedCell } from "./index";
|
||||||
return "0xsetAdjustment";
|
|
||||||
|
export const prepareSetAdjustmentCalldata = (chainId, rateChange, targetRate, increase) => {
|
||||||
|
const value = 0n;
|
||||||
|
const label = "Set Adjustment";
|
||||||
|
const target = DISTRIBUTOR_ADDRESSES[chainId];
|
||||||
|
const calldata = encodeFunctionData({
|
||||||
|
abi: DistributorAbi,
|
||||||
|
functionName: 'setAdjustment',
|
||||||
|
args: [rateChange, targetRate, increase]
|
||||||
|
});
|
||||||
|
return { label, target, calldata, value };
|
||||||
}
|
}
|
||||||
|
|
||||||
export const prepareSetAdjustmentDescription = "Explanation about what is set adjustment (APY change), pros and cons should be here, we need to fill as much text here as possible to make initial screen usable and not empty.";
|
export const prepareSetAdjustmentDescription = "Set Adjustment function schedules a gradual change to the staking APY. It increases or decreases the staking APY by a specified rate per epoch until a target rate reached.";
|
||||||
|
|
||||||
export const SetAdjustmentParsed = (props) => {
|
export const SetAdjustmentParsed = (props) => {
|
||||||
return (
|
return (
|
||||||
@ -20,37 +34,16 @@ export const SetAdjustmentParsed = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const SetAdjustmentParsedCell = (props) => {
|
const SetAdjustmentParsedCell = (props) => {
|
||||||
return (
|
return <ParsedCell {...props} />
|
||||||
<TableRow id={props.id + `--proposalFunction`} data-testid={props.id + `--proposalFunction`}>
|
|
||||||
<TableCell align="center" style={{ padding: "8px 0" }}>
|
|
||||||
<Typography>Set Adjustment</Typography>
|
|
||||||
</TableCell>
|
|
||||||
|
|
||||||
<TableCell align="center" style={{ padding: "8px 0" }}>
|
|
||||||
<Typography>{props.target}</Typography>
|
|
||||||
</TableCell>
|
|
||||||
|
|
||||||
<TableCell align="center" style={{ padding: "8px 0" }}>
|
|
||||||
<Typography>{props.value} {props.nativeCoin}</Typography>
|
|
||||||
</TableCell>
|
|
||||||
|
|
||||||
{props.remove && <TableCell>
|
|
||||||
<div style={{ display: 'flex', gap: '8px' }}>
|
|
||||||
<TertiaryButton fullWidth onClick={() => alert("Do we need it????")}>Edit</TertiaryButton>
|
|
||||||
<TertiaryButton fullWidth onClick={() => props.remove()}>Delete</TertiaryButton>
|
|
||||||
</div>
|
|
||||||
</TableCell>}
|
|
||||||
</TableRow>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SetAdjustmentSteps = ({ toInitialStep, addCalldata }) => {
|
export const SetAdjustmentSteps = ({ chainId, toInitialStep, addCalldata }) => {
|
||||||
const [rate, setRate] = useState();
|
const [rate, setRate] = useState();
|
||||||
const [target, setTarget] = useState();
|
const [target, setTarget] = useState();
|
||||||
const [increase, setIncrease] = useState(false);
|
const [increase, setIncrease] = useState(false);
|
||||||
|
|
||||||
const handleProceed = () => {
|
const handleProceed = () => {
|
||||||
addCalldata(prepareSetAdjustmentCalldata())
|
addCalldata(prepareSetAdjustmentCalldata(chainId, rate, target, increase));
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -63,21 +56,21 @@ export const SetAdjustmentSteps = ({ toInitialStep, addCalldata }) => {
|
|||||||
setLeftValue={() => setIncrease(true)}
|
setLeftValue={() => setIncrease(true)}
|
||||||
setRightValue={() => setIncrease(false)}
|
setRightValue={() => setIncrease(false)}
|
||||||
label="Direction"
|
label="Direction"
|
||||||
tooltip="To add or not to add"
|
tooltip="Determines the direction of the adjustment. When Add the parameter value will gradually increase; when Sub, it will decrease toward the target rate"
|
||||||
/>
|
/>
|
||||||
<ArgumentInput
|
<ArgumentInput
|
||||||
endString="%"
|
endString="%"
|
||||||
label="Change Rate"
|
label="Change Rate"
|
||||||
value={rate}
|
value={rate ?? ""}
|
||||||
setValue={setRate}
|
setValue={setRate}
|
||||||
tooltip="APY will change each time by this value, by basis points"
|
tooltip="Each epoch, the current staking reward rate changes by this amount until the target rate is reached"
|
||||||
/>
|
/>
|
||||||
<ArgumentInput
|
<ArgumentInput
|
||||||
endString="%"
|
endString="%"
|
||||||
label="Target Rate"
|
label="Target Rate"
|
||||||
value={target}
|
value={target ?? ""}
|
||||||
setValue={setTarget}
|
setValue={setTarget}
|
||||||
tooltip="APY will change until it reaches this value, it's in basis points"
|
tooltip="The final desired value for the reward rate, the adjustment process will continue automatically until this specific level is reached"
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
<Box width="100%" sx={{ marginTop: "20px" }} display="flex" flexDirection="column" gap="5px">
|
<Box width="100%" sx={{ marginTop: "20px" }} display="flex" flexDirection="column" gap="5px">
|
||||||
@ -85,7 +78,13 @@ export const SetAdjustmentSteps = ({ toInitialStep, addCalldata }) => {
|
|||||||
<TertiaryButton onClick={toInitialStep} fullWidth>Back</TertiaryButton>
|
<TertiaryButton onClick={toInitialStep} fullWidth>Back</TertiaryButton>
|
||||||
<TertiaryButton disabled fullWidth>Next</TertiaryButton>
|
<TertiaryButton disabled fullWidth>Next</TertiaryButton>
|
||||||
</Box>
|
</Box>
|
||||||
<PrimaryButton onClick={() => handleProceed()} fullWidth>Create Function</PrimaryButton>
|
<PrimaryButton
|
||||||
|
disabled={!target || !rate}
|
||||||
|
onClick={() => handleProceed()}
|
||||||
|
fullWidth
|
||||||
|
>
|
||||||
|
Create Function
|
||||||
|
</PrimaryButton>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,14 +1,23 @@
|
|||||||
import { useRef } from "react";
|
import { useRef, useMemo } from "react";
|
||||||
import { Box, Typography, useTheme } from "@mui/material";
|
import { Box, Typography, Link, TableCell, TableRow, useTheme } from "@mui/material";
|
||||||
|
import { decodeFunctionData } from 'viem';
|
||||||
|
|
||||||
import { StyledInputBase } from "../../../../components/Swap/SwapCard";
|
import { StyledInputBase } from "../../../../components/Swap/SwapCard";
|
||||||
|
import { TertiaryButton } from "../../../../components/Button";
|
||||||
import InfoTooltip from "../../../../components/Tooltip/InfoTooltip";
|
import InfoTooltip from "../../../../components/Tooltip/InfoTooltip";
|
||||||
|
|
||||||
|
import { abi as TreasuryAbi } from "../../../../abi/GhostTreasury.json";
|
||||||
|
import { abi as DistributorAbi } from "../../../../abi/GhostDistributor.json";
|
||||||
|
import { abi as DepositoryAbi } from "../../../../abi/GhostBondDepository.json";
|
||||||
|
|
||||||
|
import { config } from "../../../../config";
|
||||||
|
import { shorten, formatCurrency } from "../../../../helpers";
|
||||||
|
|
||||||
import { prepareAuditReservesDescription, prepareAuditReservesCalldata, AuditReservesSteps, AuditReservesParsed } from "./AuditReserves";
|
import { prepareAuditReservesDescription, prepareAuditReservesCalldata, AuditReservesSteps, AuditReservesParsed } from "./AuditReserves";
|
||||||
import { prepareSetAdjustmentDescription, prepareSetAdjustmentCalldata, SetAdjustmentSteps, SetAdjustmentParsed } from "./SetAdjustment";
|
import { prepareSetAdjustmentDescription, prepareSetAdjustmentCalldata, SetAdjustmentSteps, SetAdjustmentParsed } from "./SetAdjustment";
|
||||||
import { prepareCreateBondDescription, prepareCreateBondCalldata, CreateBondSteps, CreateBondParsed } from "./CreateBond";
|
import { prepareCreateBondDescription, prepareCreateBondCalldata, CreateBondSteps, CreateBondParsed } from "./CreateBond";
|
||||||
|
|
||||||
const DEFAULT_DESCRIPTION = "Select function for the proposal to start. Make sure you are ready to fill the proposal, here should be pretty long text just to fill space. Here we are trying to make everything looks cool."
|
const DEFAULT_DESCRIPTION = "Please select the function to include in your proposal. Multi-functional proposals are allowed, but each included function should be clearly specified."
|
||||||
|
|
||||||
export const allPossibleFunctions = [
|
export const allPossibleFunctions = [
|
||||||
{ value: "auditReserves", label: "Audit Reserves" },
|
{ value: "auditReserves", label: "Audit Reserves" },
|
||||||
@ -16,34 +25,61 @@ export const allPossibleFunctions = [
|
|||||||
{ value: "createBond", label: "Create Bond" },
|
{ value: "createBond", label: "Create Bond" },
|
||||||
];
|
];
|
||||||
|
|
||||||
export const parseFunctionCalldata = (calldata, index, nativeCoin, removeCalldata) => {
|
const allAbis = [TreasuryAbi, DistributorAbi, DepositoryAbi];
|
||||||
const target = "0x5324..123123";
|
|
||||||
const value = 0;
|
const identifyAction = (calldata) => {
|
||||||
|
let decoded = { functionName: "Unknown", args: [] };
|
||||||
|
for (const abi of allAbis) {
|
||||||
|
try {
|
||||||
|
decoded = decodeFunctionData({
|
||||||
|
abi: abi,
|
||||||
|
data: calldata,
|
||||||
|
});
|
||||||
|
return decoded;
|
||||||
|
} catch (err) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return decoded;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const parseFunctionCalldata = (metadata, index, chainId, nativeCoin, removeCalldata) => {
|
||||||
|
const { label, calldata, target, value } = metadata;
|
||||||
|
const { functionName, args } = identifyAction(calldata);
|
||||||
|
|
||||||
const remove = () => removeCalldata(index);
|
const remove = () => removeCalldata(index);
|
||||||
|
|
||||||
switch (true) {
|
console.log(`function arguments for ${label}: ${args}`);
|
||||||
case calldata.includes("auditReserves"):
|
|
||||||
|
switch (functionName) {
|
||||||
|
case "auditReserves":
|
||||||
return <AuditReservesParsed
|
return <AuditReservesParsed
|
||||||
isTable
|
isTable
|
||||||
|
key={index}
|
||||||
|
label={label}
|
||||||
|
chainId={chainId}
|
||||||
remove={remove}
|
remove={remove}
|
||||||
nativeCoin={nativeCoin}
|
nativeCoin={nativeCoin}
|
||||||
value={value}
|
value={value}
|
||||||
target={target}
|
target={target}
|
||||||
id={index}
|
id={index}
|
||||||
/>;
|
/>;
|
||||||
case calldata.includes("setAdjustment"):
|
case "setAdjustment":
|
||||||
return <SetAdjustmentParsed
|
return <SetAdjustmentParsed
|
||||||
isTable
|
isTable
|
||||||
|
key={index}
|
||||||
|
label={label}
|
||||||
remove={remove}
|
remove={remove}
|
||||||
nativeCoin={nativeCoin}
|
nativeCoin={nativeCoin}
|
||||||
value={value}
|
value={value}
|
||||||
target={target}
|
target={target}
|
||||||
id={index}
|
id={index}
|
||||||
/>;
|
/>;
|
||||||
case calldata.includes("createBond"):
|
case "create":
|
||||||
return <CreateBondParsed
|
return <CreateBondParsed
|
||||||
isTable
|
isTable
|
||||||
|
key={index}
|
||||||
|
label={label}
|
||||||
remove={remove}
|
remove={remove}
|
||||||
nativeCoin={nativeCoin}
|
nativeCoin={nativeCoin}
|
||||||
value={value}
|
value={value}
|
||||||
@ -51,7 +87,16 @@ export const parseFunctionCalldata = (calldata, index, nativeCoin, removeCalldat
|
|||||||
id={index}
|
id={index}
|
||||||
/>;
|
/>;
|
||||||
default:
|
default:
|
||||||
return null;
|
return <ParsedCell
|
||||||
|
isTable
|
||||||
|
key={index}
|
||||||
|
label={label}
|
||||||
|
remove={remove}
|
||||||
|
nativeCoin={nativeCoin}
|
||||||
|
value={value}
|
||||||
|
target={target}
|
||||||
|
id={index}
|
||||||
|
/>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,16 +113,16 @@ export const getFunctionArguments = (functionName) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getFunctionCalldata = (functionName) => {
|
export const getFunctionCalldata = (functionName, chainId) => {
|
||||||
switch (functionName) {
|
switch (functionName) {
|
||||||
case "auditReserves":
|
case "auditReserves":
|
||||||
return prepareAuditReservesCalldata();
|
return prepareAuditReservesCalldata(chainId);
|
||||||
case "setAdjustment":
|
case "setAdjustment":
|
||||||
return prepareSetAdjustmentCalldata();
|
return prepareSetAdjustmentCalldata(chainId);
|
||||||
case "createBond":
|
case "createBond":
|
||||||
return prepareCreateBondCalldata();
|
return prepareCreateBondCalldata(chainId);
|
||||||
default:
|
default:
|
||||||
return "";
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,10 +151,18 @@ export const BooleanValue = ({ left, text, isSelected, setSelected }) => {
|
|||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
borderRadius: left ? "12px 0 0 12px" : "0 12px 12px 0",
|
borderRadius: left ? "12px 0 0 12px" : "0 12px 12px 0",
|
||||||
flex: 1,
|
flex: 1,
|
||||||
border: `1px solid #fff`
|
border: "2px solid #fff",
|
||||||
|
borderLeft: left ? "2px solid #fff" : "none",
|
||||||
|
borderRight: left ? "none" : "2px solid #fff",
|
||||||
|
background: `${isSelected ? "#fff" : theme.colors.gray[600] }`
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography color={`${isSelected ? theme.colors.primary[300] : "#fff"}`} align="center">{text}</Typography>
|
<Typography
|
||||||
|
color={isSelected ? theme.colors.gray[600] : "#fff"}
|
||||||
|
align="center"
|
||||||
|
>
|
||||||
|
{text}
|
||||||
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -186,3 +239,39 @@ export const ArgumentInput = ({
|
|||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const ParsedCell = (props) => {
|
||||||
|
const etherscanLink = useMemo(() => {
|
||||||
|
const client = config.getClient();
|
||||||
|
let url = client?.chain?.blockExplorers?.default?.url;
|
||||||
|
if (url) {
|
||||||
|
url = url + `/address/${props.target}`;
|
||||||
|
}
|
||||||
|
return url;
|
||||||
|
}, [props]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableRow id={props.id + `--proposalFunction`} data-testid={props.id + `--proposalFunction`}>
|
||||||
|
<TableCell align="center" style={{ padding: "8px 0" }}>
|
||||||
|
<Typography>{props.label}</Typography>
|
||||||
|
</TableCell>
|
||||||
|
|
||||||
|
<TableCell align="center" style={{ padding: "8px 0" }}>
|
||||||
|
<Link href={etherscanLink} target="_blank" rel="noopener noreferrer">
|
||||||
|
<Typography>{shorten(props.target)}</Typography>
|
||||||
|
</Link>
|
||||||
|
</TableCell>
|
||||||
|
|
||||||
|
<TableCell align="center" style={{ padding: "8px 0" }}>
|
||||||
|
<Typography>{formatCurrency(props.value, 2, props.nativeCoin)}</Typography>
|
||||||
|
</TableCell>
|
||||||
|
|
||||||
|
{props.remove && <TableCell>
|
||||||
|
<div style={{ display: 'flex', gap: '8px' }}>
|
||||||
|
<TertiaryButton fullWidth onClick={() => alert("Do we need it????")}>Edit</TertiaryButton>
|
||||||
|
<TertiaryButton fullWidth onClick={() => props.remove()}>Delete</TertiaryButton>
|
||||||
|
</div>
|
||||||
|
</TableCell>}
|
||||||
|
</TableRow>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
@ -1,29 +1,70 @@
|
|||||||
|
import { useReadContract, useReadContracts } from "wagmi";
|
||||||
|
import { simulateContract, writeContract, waitForTransactionReceipt } from "@wagmi/core";
|
||||||
|
import toast from "react-hot-toast";
|
||||||
|
|
||||||
|
import { config } from "../../config";
|
||||||
|
|
||||||
|
import {
|
||||||
|
GHOST_GOVERNANCE_ADDRESSES,
|
||||||
|
} from "../../constants/addresses";
|
||||||
|
import { abi as GovernorAbi } from "../../abi/Governor.json";
|
||||||
|
import { abi as GovernorStorageAbi } from "../../abi/GovernorStorage.json";
|
||||||
|
import { abi as GovernorVotesQuorumFractionAbi } from "../../abi/GovernorVotesQuorumFraction.json";
|
||||||
|
|
||||||
import { DecimalBigNumber } from "../../helpers/DecimalBigNumber";
|
import { DecimalBigNumber } from "../../helpers/DecimalBigNumber";
|
||||||
import { getTokenDecimals } from "../helpers";
|
import { getTokenDecimals } from "../helpers";
|
||||||
|
|
||||||
export const useMinQuorum = (chainId) => {
|
export const useMinQuorum = (chainId) => {
|
||||||
const numerator = 69n;
|
const { data: quorumNumerator, refetch: quorumNumeratorRefetch } = useReadContract({
|
||||||
const denominator = 100n;
|
abi: GovernorVotesQuorumFractionAbi,
|
||||||
|
address: GHOST_GOVERNANCE_ADDRESSES[chainId],
|
||||||
|
functionName: "quorumNumerator",
|
||||||
|
scopeKey: `quorumNumerator-${chainId}`,
|
||||||
|
chainId: chainId,
|
||||||
|
});
|
||||||
|
|
||||||
let percentage = 0;
|
const { data: quorumDenominator, refetch: quorumDenominatorRefetch } = useReadContract({
|
||||||
|
abi: GovernorVotesQuorumFractionAbi,
|
||||||
|
address: GHOST_GOVERNANCE_ADDRESSES[chainId],
|
||||||
|
functionName: "quorumDenominator",
|
||||||
|
scopeKey: `quorumDenominator-${chainId}`,
|
||||||
|
chainId: chainId,
|
||||||
|
});
|
||||||
|
|
||||||
if (numerator && denominator && denominator > 0n) {
|
const numerator = quorumNumerator ?? 0n;
|
||||||
percentage = Number(100n * numerator / denominator) / 100;
|
const denominator = quorumDenominator ?? 1n;
|
||||||
}
|
const percentage = Number(100n * numerator / denominator) / 100;
|
||||||
|
|
||||||
return { numerator, denominator, percentage }
|
return { numerator, denominator, percentage }
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useProposalThreshold = (chainId, name) => {
|
export const useProposalThreshold = (chainId, name) => {
|
||||||
const decimals = getTokenDecimals(name);
|
const decimals = getTokenDecimals(name);
|
||||||
const threshold = new DecimalBigNumber(420_000_000_000_000_000_000n, decimals);
|
const { data, refetch } = useReadContract({
|
||||||
|
abi: GovernorStorageAbi,
|
||||||
|
address: GHOST_GOVERNANCE_ADDRESSES[chainId],
|
||||||
|
functionName: "proposalThreshold",
|
||||||
|
scopeKey: `proposalThreshold-${chainId}`,
|
||||||
|
chainId: chainId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const threshold = new DecimalBigNumber(data ?? 0n, decimals);
|
||||||
|
|
||||||
return { threshold };
|
return { threshold };
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useProposalCount = (chainId) => {
|
export const useProposalCount = (chainId) => {
|
||||||
const proposalsCount = 1337n;
|
const { data, refetch } = useReadContract({
|
||||||
return { proposalsCount };
|
abi: GovernorStorageAbi,
|
||||||
|
address: GHOST_GOVERNANCE_ADDRESSES[chainId],
|
||||||
|
functionName: "proposalCount",
|
||||||
|
scopeKey: `proposalCount-${chainId}`,
|
||||||
|
chainId: chainId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const proposalCount = data ?? 0n;
|
||||||
|
|
||||||
|
return { proposalCount };
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useProposalStatus = (chainId, proposalId) => {
|
export const useProposalStatus = (chainId, proposalId) => {
|
||||||
@ -73,11 +114,7 @@ export const useProposalVotingDelay = (chainId, proposalId) => {
|
|||||||
|
|
||||||
export const useProposals = (chainId, depth) => {
|
export const useProposals = (chainId, depth) => {
|
||||||
const decimals = getTokenDecimals(name);
|
const decimals = getTokenDecimals(name);
|
||||||
const { proposalsCount } = useProposalCount(chainId);
|
const { proposalCount } = useProposalCount(chainId);
|
||||||
|
|
||||||
let iterator = proposalsCount ? proposalsCount : 0n;
|
|
||||||
const bigIntDepth = BigInt(depth);
|
|
||||||
const edgeProposalId = iterator > bigIntDepth ? iterator - bigIntDepth : 0n;
|
|
||||||
|
|
||||||
const statuses = [
|
const statuses = [
|
||||||
"Active",
|
"Active",
|
||||||
@ -88,17 +125,18 @@ export const useProposals = (chainId, depth) => {
|
|||||||
];
|
];
|
||||||
let proposals = [];
|
let proposals = [];
|
||||||
|
|
||||||
while (iterator > proposalsCount - bigIntDepth) {
|
const start = Number(proposalCount);
|
||||||
iterator -= 1n;
|
const end = Math.max(0, start - depth);
|
||||||
|
|
||||||
|
for (let i = start - 1; i >= end; --i) {
|
||||||
const voteEnds = 50n;
|
const voteEnds = 50n;
|
||||||
const yesVotes = new DecimalBigNumber(1337_000_000_000_000_000_000, decimals);
|
const yesVotes = new DecimalBigNumber(1337_000_000_000_000_000_000, decimals);
|
||||||
const noVotes = new DecimalBigNumber(420_000_000_000_000_000_000, decimals);
|
const noVotes = new DecimalBigNumber(420_000_000_000_000_000_000, decimals);
|
||||||
|
|
||||||
proposals.push({
|
proposals.push({
|
||||||
id: iterator,
|
id: i,
|
||||||
discussion: "https://google.com",
|
discussion: "https://google.com",
|
||||||
status: statuses[Number(iterator) % statuses.length],
|
status: statuses[i % statuses.length],
|
||||||
voteEnds,
|
voteEnds,
|
||||||
yesVotes,
|
yesVotes,
|
||||||
noVotes
|
noVotes
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user