diff --git a/package.json b/package.json index 4e976a5..b7d74be 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ghost-dao-interface", "private": true, - "version": "0.5.7", + "version": "0.5.8", "type": "module", "scripts": { "dev": "vite", diff --git a/src/components/Select/Select.jsx b/src/components/Select/Select.jsx new file mode 100644 index 0000000..2a940b9 --- /dev/null +++ b/src/components/Select/Select.jsx @@ -0,0 +1,72 @@ +import { Box, MenuItem, Select as MuiSelect, Typography, useTheme } from "@mui/material"; +import { styled } from "@mui/material/styles"; +import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown'; + +const StyledSelectInput = styled(MuiSelect, { + shouldForwardProp: prop => prop !== "inputWidth" +})(({ theme, inputWidth }) => ({ + width: "100%", + "& .MuiSelect-select": { + padding: 0, + height: "24px !important", + minHeight: "24px !important", + display: "flex", + alignItems: "center", + fontSize: "18px", + fontWeight: 500, + paddingRight: "24px", + }, + "& .MuiOutlinedInput-notchedOutline": { + border: "none", + }, + "& .MuiSelect-icon": { + right: 0, + position: "absolute", + color: theme.colors.gray[500], + } +})); + +const Select = ({ + label, + value, + onChange, + options, + inputWidth, + width = "100%", +}) => { + const theme = useTheme(); + return ( + + {label && ( + + {label} + + )} + + + + {options.map((opt) => ( + + {opt.label} + + ))} + + + + ); +}; + +export default Select; diff --git a/src/components/Swap/SwapCard.jsx b/src/components/Swap/SwapCard.jsx index 4f7b416..160549e 100644 --- a/src/components/Swap/SwapCard.jsx +++ b/src/components/Swap/SwapCard.jsx @@ -7,7 +7,7 @@ import Token from "../Token/Token"; import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown'; -const StyledInputBase = styled(InputBase, { shouldForwardProp: prop => prop !== "inputWidth" })( +export const StyledInputBase = styled(InputBase, { shouldForwardProp: prop => prop !== "inputWidth" })( ({ inputWidth, inputFontSize }) => ({ "& .MuiInputBase-input": { padding: 0, diff --git a/src/containers/Bond/Bonds.jsx b/src/containers/Bond/Bonds.jsx index 20ee595..55c7ad0 100644 --- a/src/containers/Bond/Bonds.jsx +++ b/src/containers/Bond/Bonds.jsx @@ -1,4 +1,4 @@ -import { Box, Tab, Tabs, Container, useMediaQuery } from "@mui/material"; +import { Box, Tab, Tabs, Typography, Container, useMediaQuery } from "@mui/material"; import { useEffect, useState } from "react"; import ReactGA from "react-ga4"; diff --git a/src/containers/Governance/NewProposal.jsx b/src/containers/Governance/NewProposal.jsx index b377792..c6dbfd8 100644 --- a/src/containers/Governance/NewProposal.jsx +++ b/src/containers/Governance/NewProposal.jsx @@ -1,75 +1,153 @@ -import { useState } from "react"; +import { useState, useMemo } from "react"; import { Box, Container, + TableContainer, + Table, + TableRow, + TableBody, + TableHead, + TableCell, Typography, + Link, OutlinedInput, InputLabel, FormControl, useMediaQuery, + useTheme } from "@mui/material"; +import GhostStyledIcon from "../../components/Icon/GhostIcon"; +import ArrowUpIcon from "../../assets/icons/arrow-up.svg?react"; + import Paper from "../../components/Paper/Paper"; import PageTitle from "../../components/PageTitle/PageTitle"; -import { PrimaryButton } from "../../components/Button"; +import { PrimaryButton, TertiaryButton } from "../../components/Button"; + +import ProposalModal from "./components/ProposalModal"; +import { parseFunctionCalldata } from "./components/functions/index"; const NewProposal = ({ config, address, connect, chainId }) => { const isSemiSmallScreen = useMediaQuery("(max-width: 745px)"); const isSmallScreen = useMediaQuery("(max-width: 650px)"); const isVerySmallScreen = useMediaQuery("(max-width: 379px)"); - const [descriptionUrl, setDescriptionUrl] = useState(""); + const theme = useTheme(); + + const [isModalOpened, setIsModalOpened] = useState(false); + const [proposalFunctions, setProposalFunctions] = useState([]); + + const addCalldata = (calldata) => setProposalFunctions(prev => [...prev, calldata]); + const removeCalldata = (index) => setProposalFunctions(prev => prev.filter((_, i) => i !== index)); + + const nativeCurrency = useMemo(() => { + const client = config?.getClient(); + return client?.chain?.nativeCurrency?.symbol; + }, [config]); + + const submitProposal = () => { + alert("Proposal created"); + setProposalFunctions([]); + } return ( - - - - - - - Proposal Overview - + <> + setIsModalOpened(false)} /> + + + + + + + Proposal Functions + + + } + > + + + {proposalFunctions.length === 0 && + + Create new proposal by adding functions below + + + Learn more + + + } + + + + setIsModalOpened(true)}>Add New + submitProposal()}>Submit Proposal + - } - > - - - - - - ) -} + -const BasicInput = ({ id, label, value, eventHandler }) => { - return ( - - {label} - - - eventHandler(event.currentTarget.value)} - /> - + {proposalFunctions.length > 0 && + + Proposal Functions + + + } + > + + + + + Function + Target + Value + + + {proposalFunctions.map((calldata, index) => { + return parseFunctionCalldata(calldata, index, nativeCurrency, removeCalldata); + })} + + + } + + - + > ) } diff --git a/src/containers/Governance/ProposalDetails.jsx b/src/containers/Governance/ProposalDetails.jsx index 88a3e06..3a21b63 100644 --- a/src/containers/Governance/ProposalDetails.jsx +++ b/src/containers/Governance/ProposalDetails.jsx @@ -2,7 +2,7 @@ import { useEffect, useState, useMemo } from "react"; import ReactGA from "react-ga4"; import { useParams } from 'react-router-dom'; -import { Box, Container, Typography, useMediaQuery, useTheme } from "@mui/material"; +import { Box, Container, Typography, Link, useMediaQuery, useTheme } from "@mui/material"; import Paper from "../../components/Paper/Paper"; import PageTitle from "../../components/PageTitle/PageTitle"; @@ -11,12 +11,13 @@ import InfoTooltip from "../../components/Tooltip/InfoTooltip"; import Chip from "../../components/Chip/Chip"; import { SecondaryButton } from "../../components/Button"; +import GhostStyledIcon from "../../components/Icon/GhostIcon"; +import ArrowUpIcon from "../../assets/icons/arrow-up.svg?react"; + import { formatNumber } from "../../helpers"; import { prettifySecondsInDays } from "../../helpers/timeUtil"; import { DecimalBigNumber } from "../../helpers/DecimalBigNumber"; -import ProposalDiscussionModal from "./components/ProposalDiscussionModal"; -import ProposalDiscussion from "./components/ProposalDiscussion"; import { convertStatusToTemplate } from "./helpers"; import { useTokenSymbol, useTotalSupply, useBalance } from "../../hooks/tokens"; @@ -65,7 +66,7 @@ const ProposalDetails = ({ chainId, address }) => { const { proposer: proposalProposer } = useProposalProposer(chainId, id); const { locked: proposalLocked } = useProposalLocked(chainId, id); const { quorum: proposalQuorum } = useProposalQuorum(chainId, id); - const { forVotes, againstVotes } = useProposalVotes(chainId, id); + const { forVotes, againstVotes, totalVotes } = useProposalVotes(chainId, id); useEffect(() => { ReactGA.send({ hitType: "pageview", page: `/governance/${id}` }); @@ -75,130 +76,153 @@ const ProposalDetails = ({ chainId, address }) => { return selectedDiscussionUrl !== undefined; }, [selectedDiscussionUrl]); + const quorumPercentage = useMemo(() => { + if (totalSupply._value === 0n) return 0; + return proposalQuorum / totalSupply * HUNDRED; + }, [proposalQuorum, totalSupply]); + + const votePercentage = useMemo(() => { + if (totalSupply._value === 0n) return 0; + return totalVotes / totalSupply * HUNDRED; + }, [totalVotes, totalSupply]); + + const voteWeightPercentage = useMemo(() => { + if (totalSupply._value === 0n) return 0; + return balance / totalSupply * HUNDRED; + }, [balance, totalSupply]); + return ( - <> - setSelectedDiscussionUrl(undefined)} - /> - - - - - - - - Progress + + + + + + + + Progress + + + + } + topRight={ + + View Forum + + + } + > + + + + + For: {formatNumber(forVotes.toString(), 2)} ({formatNumber(forVotes * HUNDRED / proposalQuorum, 1)}%) + + + Against: {formatNumber(againstVotes.toString(), 2)} ({formatNumber(againstVotes * HUNDRED / proposalQuorum, 1)}%) - - } - topRight={ - setSelectedDiscussionUrl("dicks")} /> - } - > - - - - - For: {formatNumber(forVotes.toString(), 2)} ({formatNumber(forVotes * HUNDRED / proposalQuorum, 1)}%) - - - Against: {formatNumber(againstVotes.toString(), 2)} ({formatNumber(againstVotes * HUNDRED / proposalQuorum, 1)}%) - + + + + + + + Quorum + - + {formatNumber(proposalQuorum.toString(), 4)} ({formatNumber(quorumPercentage, 1)}%) - - - - Quorum - - - {formatNumber(proposalQuorum.toString(), 4)} - - - - - Total - - - {formatNumber(totalSupply.toString(), 4)} - - - - - Votes - - - {formatNumber(balance.toString(), 4)} + + + Total + + {formatNumber(totalSupply.toString(), 4)} ({formatNumber(votePercentage, 1)}%) - - alert("For vote casted")}>For - alert("Against vote casted")}>Against + + + Votes + + + {formatNumber(balance.toString(), 4)} ({formatNumber(voteWeightPercentage, 1)}%) - - - - Timeline - - - } - > - - - - - - - - Executable Code - + + alert("For vote casted")}>For + alert("Against vote casted")}>Against + - } - > - Here will be a list of decoded calldatas - - - - > + + + + + Timeline + + + } + > + + + + + + + + Executable Code + + + } + > + Here will be a list of decoded calldatas + + + ) } diff --git a/src/containers/Governance/components/Metric.jsx b/src/containers/Governance/components/Metric.jsx index 1b79ad7..9ee5822 100644 --- a/src/containers/Governance/components/Metric.jsx +++ b/src/containers/Governance/components/Metric.jsx @@ -37,7 +37,7 @@ export const ProposalThreshold = props => { const _props = { ...props, - label: `$${props.ghstSymbol} Threshold`, + label: "Min Collateral", tooltip: `Minimum $${props.ghstSymbol} required to be locked to create a proposal`, }; @@ -56,7 +56,7 @@ export const ProposalsCount = props => { tooltip: `Total proposals created`, }; - if (proposalsCount) _props.metric = proposalsCount.toString(); + if (proposalsCount) _props.metric = `${formatNumber(proposalsCount.toString(), 0)}`; else _props.isLoading = true; return ; diff --git a/src/containers/Governance/components/ProposalDiscussion.jsx b/src/containers/Governance/components/ProposalDiscussion.jsx deleted file mode 100644 index 56d4f54..0000000 --- a/src/containers/Governance/components/ProposalDiscussion.jsx +++ /dev/null @@ -1,29 +0,0 @@ -import { Link } from "@mui/material"; -import GhostStyledIcon from "../../../components/Icon/GhostIcon"; -import ArrowUpIcon from "../../../assets/icons/arrow-up.svg?react"; - -const ProposalDiscussion = (linkProps) => { - return ( - - Learn more - - - ) -} - -export default ProposalDiscussion; diff --git a/src/containers/Governance/components/ProposalDiscussionModal.jsx b/src/containers/Governance/components/ProposalDiscussionModal.jsx deleted file mode 100644 index ac2e902..0000000 --- a/src/containers/Governance/components/ProposalDiscussionModal.jsx +++ /dev/null @@ -1,64 +0,0 @@ -import { useState } from "react"; -import { Box, Typography, Link } from "@mui/material"; - -import Modal from "../../../components/Modal/Modal"; -import { PrimaryButton } from "../../../components/Button"; - -const ProposalDiscussionModal = ({ isOpened, closeModal, url }) => { - const [isCopied, setIsCopied] = useState(false); - - const copyToClipboard = () => { - navigator.clipboard.writeText(url) - .then(() => { - isCopied(true); - setTimeout(() => setIsCopied(false), 2000); - }) - .catch(err => console.error(err)); - } - - return ( - - Discussion URL - - } - open={isOpened} - onClose={closeModal} - maxWidth="460px" - minHeight="200px" - > - - - - You are leaving the ghost dao app. Check the link on your own, we are not in charge of your destiny. - - - {url} - - - - window.open(url, '_blank', 'noopener,noreferrer')} - > - Open - - - - ) -} - -export default ProposalDiscussionModal; diff --git a/src/containers/Governance/components/ProposalModal.jsx b/src/containers/Governance/components/ProposalModal.jsx new file mode 100644 index 0000000..8d94de1 --- /dev/null +++ b/src/containers/Governance/components/ProposalModal.jsx @@ -0,0 +1,100 @@ +import { useState, useEffect, useMemo, useCallback } from "react"; +import { Box, Typography } from "@mui/material"; + +import Modal from "../../../components/Modal/Modal"; +import Select from "../../../components/Select/Select"; +import { PrimaryButton, TertiaryButton } from "../../../components/Button"; + +import { + getFunctionArguments, + getFunctionCalldata, + getFunctionDescription, + allPossibleFunctions +} from "./functions"; + +const ProposalModal = ({ isOpened, closeModal, addCalldata }) => { + const [selectedOption, setSelectedOption] = useState(); + const [renderArguments, setRenderArguments] = useState(false); + + const handleChange = (event) => { + setSelectedOption(event.target.value); + }; + + const headerLabel = useMemo(() => { + const data = allPossibleFunctions.find(obj => obj.value === selectedOption); + if (data && renderArguments) { + return data.label; + } + return "Executable Code"; + }, [selectedOption, renderArguments]); + + const handleCalldata = useCallback(() => { + addCalldata(getFunctionCalldata(selectedOption)); + setSelectedOption(null); + closeModal(); + }, [selectedOption]); + + const handleClose = () => { + setSelectedOption(null); + setRenderArguments(false); + closeModal(); + } + + const handleAddCalldata = (calldata) => { + addCalldata(calldata); + handleClose(); + } + + const ArgumentsSteps = useMemo(() => getFunctionArguments(selectedOption), [selectedOption]); + + return ( + + {headerLabel} + + } + open={isOpened} + onClose={handleClose} + maxWidth="460px" + minHeight="200px" + > + + {renderArguments + ? setRenderArguments(false)} + /> + : setRenderArguments(true)} + ready={ArgumentsSteps !== null} + /> + } + + + ) +} + +const InitialStep = ({ selectedOption, handleChange, handleCalldata, handleProceed, ready }) => { + const functionDescription = useMemo(() => getFunctionDescription(selectedOption), [selectedOption]); + return ( + + + {functionDescription} + {ready + ? handleProceed()} fullWidth>Proceed + : handleCalldata()} fullWidth>Create Function + } + + ) +} + +export default ProposalModal; diff --git a/src/containers/Governance/components/ProposalsList.jsx b/src/containers/Governance/components/ProposalsList.jsx index 7e509c5..151c987 100644 --- a/src/containers/Governance/components/ProposalsList.jsx +++ b/src/containers/Governance/components/ProposalsList.jsx @@ -18,6 +18,9 @@ import { } from "@mui/material"; import { getBlockNumber } from "@wagmi/core"; +import GhostStyledIcon from "../../../components/Icon/GhostIcon"; +import ArrowUpIcon from "../../../assets/icons/arrow-up.svg?react"; + import { networkAvgBlockSpeed } from "../../../constants"; import { prettifySecondsInDays } from "../../../helpers/timeUtil"; @@ -27,8 +30,6 @@ import Paper from "../../../components/Paper/Paper"; import LinearProgressBar from "../../../components/Progress/LinearProgressBar"; import { PrimaryButton, TertiaryButton } from "../../../components/Button"; -import ProposalDiscussionModal from "./ProposalDiscussionModal"; -import ProposalDiscussion from "./ProposalDiscussion"; import ProposalInfoText from "./ProposalInfoText"; import { convertStatusToTemplate } from "../helpers"; @@ -46,16 +47,11 @@ const ProposalsList = ({ chainId, config }) => { const theme = useTheme(); const [blockNumber, setBlockNumber] = useState(0n); - const [selectedDiscussionUrl, setSelectedDiscussionUrl] = useState(undefined); const [proposalsFilter, setProposalFilter] = useState("active"); const { proposals } = useProposals(chainId, MAX_PROPOSALS_TO_SHOW); getBlockNumber(config).then(block => setBlockNumber(block)); - const isDiscussionModalOpened = useMemo(() => { - return selectedDiscussionUrl !== undefined; - }, [selectedDiscussionUrl]); - const filteredProposals = useMemo(() => { switch (proposalsFilter) { case "voted": @@ -77,100 +73,90 @@ const ProposalsList = ({ chainId, config }) => { if (isSmallScreen) { return ( - <> - setSelectedDiscussionUrl(undefined)} - /> - - - Proposals - - - } - > - - {filteredProposals?.map(proposal => ( - navigate(`/governance/${proposal.id}`)} - /> - ))} - - - {proposalsFilter === "active" && - - } - - > - ); - } - - return ( - <> - setSelectedDiscussionUrl(undefined)} - /> + Proposals - - - - Discussion Forum - - } > - - - + {filteredProposals?.map(proposal => ( - navigate(`/governance/${proposal.id}`)} /> ))} - + - {proposalsFilter === "active" && + {proposalsFilter === "active" && } - > + ); + } + + return ( + + + Proposals + + + + View Forum + + + + } + > + + + + {filteredProposals?.map(proposal => ( + navigate(`/governance/${proposal.id}`)} + /> + ))} + + + {proposalsFilter === "active" && + + } + ); } @@ -180,8 +166,7 @@ const ProposalTable = ({ children }) => ( Proposal ID - Status - Discussion + Status Vote Ends Voting Stats @@ -193,7 +178,7 @@ const ProposalTable = ({ children }) => ( ); -const ProposalRow = ({ proposal, setActive, blockNumber, openProposal, chainId }) => { +const ProposalRow = ({ proposal, blockNumber, openProposal, chainId }) => { const theme = useTheme(); return ( @@ -204,16 +189,12 @@ const ProposalRow = ({ proposal, setActive, blockNumber, openProposal, chainId } - - setActive(proposal.discussion)} /> - - {convertVoteEnds( @@ -257,7 +238,7 @@ const ProposalRow = ({ proposal, setActive, blockNumber, openProposal, chainId } ); } -const ProposalCard = ({ proposal, setActive, blockNumber, openProposal, chainId }) => { +const ProposalCard = ({ proposal, blockNumber, openProposal, chainId }) => { const theme = useTheme(); const isSmallScreen = useMediaQuery('(max-width: 450px)'); @@ -282,12 +263,6 @@ const ProposalCard = ({ proposal, setActive, blockNumber, openProposal, chainId )} - - setActive(proposal.discussion)} - /> - diff --git a/src/containers/Governance/components/functions/AuditReserves.jsx b/src/containers/Governance/components/functions/AuditReserves.jsx new file mode 100644 index 0000000..de6834c --- /dev/null +++ b/src/containers/Governance/components/functions/AuditReserves.jsx @@ -0,0 +1,45 @@ +import { Box, Typography, TableCell, TableRow, useTheme } from "@mui/material"; +import { TertiaryButton } from "../../../../components/Button"; + +export const prepareAuditReservesCalldata = (chainId) => { + return "0xauditReserves"; +} + +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 AuditReservesSteps = () => { + return null; +} + +export const AuditReservesParsed = (props) => { + return ( + <> + {props.isTable && } + > + ) +} + +const AuditReservesParsedCell = (props) => { + return ( + + + Audit Reserves + + + + {props.target} + + + + {props.value} {props.nativeCoin} + + + {props.remove && + + alert("Do we need it????")}>Edit + props.remove()}>Delete + + } + + ) +} diff --git a/src/containers/Governance/components/functions/CreateBond.jsx b/src/containers/Governance/components/functions/CreateBond.jsx new file mode 100644 index 0000000..63c8106 --- /dev/null +++ b/src/containers/Governance/components/functions/CreateBond.jsx @@ -0,0 +1,244 @@ +import { useRef, useState } from "react"; +import { Box, Typography, TableRow, TableCell, useTheme } from "@mui/material"; + +import { PrimaryButton, TertiaryButton } from "../../../../components/Button"; +import { BooleanTrigger, ArgumentInput } from "./index"; + +export const prepareCreateBondCalldata = (chainId) => { + return "0xcreateBond"; +} + +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 CreateBondParsed = (props) => { + return ( + <> + {props.isTable && } + > + ) +} + +const CreateBondParsedCell = (props) => { + return ( + + + Create Bond + + + + {props.target} + + + + {props.value} {props.nativeCoin} + + + {props.remove && + + alert("Do we need it????")}>Edit + props.remove()}>Delete + + } + + ) +} + +export const CreateBondSteps = ({ toInitialStep, addCalldata }) => { + const [step, setStep] = useState(1); + + const [capacity, setCapacity] = useState(); + const [initialPrice, setInitialPrice] = useState(); + const [debtBuffer, setDebtBuffer] = useState(); + + const [bondVesting, setBondVesting] = useState(); + const [bondDuration, setBondDuration] = useState(); + + const [tokenAddress, setTokenAddress] = useState(""); + const [capacityInQuote, setCapacityInQuote] = useState(true); + const [fixedTerm, setFixedTerm] = useState(false); + + const [vestingLength, setVestingLength] = useState(); + const [conclusionTimestamp, setConclusionTimestamp] = useState(); + + const handleProceed = () => { + addCalldata(prepareCreateBondCalldata()) + } + + const incrementStep = () => { + setStep(prev => prev + 1); + } + + const decrementStep = () => { + if (step > 1) setStep(prev => prev - 1); + else toInitialStep(); + } + + return ( + + {step === 1 && } + {step === 2 && } + {step === 3 && } + {step === 4 && } + + + decrementStep()} fullWidth>Back + incrementStep()} fullWidth>Next + + {step === 4 && handleProceed()} fullWidth>Create Function} + + + ); +} + +const MarketArguments = ({ + capacity, + setCapacity, + initialPrice, + setInitialPrice, + debtBuffer, + setDebtBuffer +}) => { + return ( + + + + + + ) +} + +const TermsArguments = ({ + bondVesting, + setBondVesting, + bondDuration, + setBondDuration, +}) => { + return ( + + + + + ) +} + +const IntervalsArguments = ({ + fixedTerm, + vestingLength, + setVestingLength, + conclusionTimestamp, + setConclusionTimestamp, +}) => { + return ( + + + + + ) +} + +const AddressAndBooleansArguments = ({ + tokenAddress, + setTokenAddress, + capacityInQuote, + setCapacityInQuote, + fixedTerm, + setFixedTerm, +}) => { + return ( + + setCapacityInQuote(true)} + setRightValue={() => setCapacityInQuote(false)} + tooltip="WTF is this" + /> + setFixedTerm(true)} + setRightValue={() => setFixedTerm(false)} + tooltip="Fixed term... No idea what it is" + /> + + + ) +} diff --git a/src/containers/Governance/components/functions/SetAdjustment.jsx b/src/containers/Governance/components/functions/SetAdjustment.jsx new file mode 100644 index 0000000..b4047c7 --- /dev/null +++ b/src/containers/Governance/components/functions/SetAdjustment.jsx @@ -0,0 +1,92 @@ +import { useState } from "react"; +import { Box, Typography, TableRow, TableCell, useTheme } from "@mui/material"; + +import { PrimaryButton, TertiaryButton } from "../../../../components/Button"; + +import { BooleanTrigger, ArgumentInput } from "./index"; + +export const prepareSetAdjustmentCalldata = (chainId) => { + return "0xsetAdjustment"; +} + +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 SetAdjustmentParsed = (props) => { + return ( + <> + {props.isTable && } + > + ) +} + +const SetAdjustmentParsedCell = (props) => { + return ( + + + Set Adjustment + + + + {props.target} + + + + {props.value} {props.nativeCoin} + + + {props.remove && + + alert("Do we need it????")}>Edit + props.remove()}>Delete + + } + + ) +} + +export const SetAdjustmentSteps = ({ toInitialStep, addCalldata }) => { + const [rate, setRate] = useState(); + const [target, setTarget] = useState(); + const [increase, setIncrease] = useState(false); + + const handleProceed = () => { + addCalldata(prepareSetAdjustmentCalldata()) + } + + return ( + + + setIncrease(true)} + setRightValue={() => setIncrease(false)} + label="Direction" + tooltip="To add or not to add" + /> + + + + + + Back + Next + + handleProceed()} fullWidth>Create Function + + + ); +} diff --git a/src/containers/Governance/components/functions/index.jsx b/src/containers/Governance/components/functions/index.jsx new file mode 100644 index 0000000..4cc094c --- /dev/null +++ b/src/containers/Governance/components/functions/index.jsx @@ -0,0 +1,188 @@ +import { useRef } from "react"; +import { Box, Typography, useTheme } from "@mui/material"; + +import { StyledInputBase } from "../../../../components/Swap/SwapCard"; +import InfoTooltip from "../../../../components/Tooltip/InfoTooltip"; + +import { prepareAuditReservesDescription, prepareAuditReservesCalldata, AuditReservesSteps, AuditReservesParsed } from "./AuditReserves"; +import { prepareSetAdjustmentDescription, prepareSetAdjustmentCalldata, SetAdjustmentSteps, SetAdjustmentParsed } from "./SetAdjustment"; +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." + +export const allPossibleFunctions = [ + { value: "auditReserves", label: "Audit Reserves" }, + { value: "setAdjustment", label: "Change APY" }, + { value: "createBond", label: "Create Bond" }, +]; + +export const parseFunctionCalldata = (calldata, index, nativeCoin, removeCalldata) => { + const target = "0x5324..123123"; + const value = 0; + + const remove = () => removeCalldata(index); + + switch (true) { + case calldata.includes("auditReserves"): + return ; + case calldata.includes("setAdjustment"): + return ; + case calldata.includes("createBond"): + return ; + default: + return null; + } +} + +export const getFunctionArguments = (functionName) => { + switch (functionName) { + case "auditReserves": + return null; + case "setAdjustment": + return SetAdjustmentSteps; + case "createBond": + return CreateBondSteps; + default: + return null; + } +} + +export const getFunctionCalldata = (functionName) => { + switch (functionName) { + case "auditReserves": + return prepareAuditReservesCalldata(); + case "setAdjustment": + return prepareSetAdjustmentCalldata(); + case "createBond": + return prepareCreateBondCalldata(); + default: + return ""; + } +} + +export const getFunctionDescription = (functionName) => { + switch (functionName) { + case "auditReserves": + return prepareAuditReservesDescription; + case "setAdjustment": + return prepareSetAdjustmentDescription; + case "createBond": + return prepareCreateBondDescription; + default: + return DEFAULT_DESCRIPTION; + } +} + +export const BooleanValue = ({ left, text, isSelected, setSelected }) => { + const theme = useTheme(); + return ( + setSelected()} + display="flex" + justifyContent="center" + alignItems="center" + sx={{ + cursor: "pointer", + borderRadius: left ? "12px 0 0 12px" : "0 12px 12px 0", + flex: 1, + border: `1px solid #fff` + }} + > + {text} + + ) +} + +export const ArgumentsWrapper = ({ label, tooltip, children }) => { + return ( + + + {label} + + + {children} + + ) +} + +export const BooleanTrigger = ({ value, label, tooltip, leftText, rightText, setLeftValue, setRightValue }) => { + return ( + + + + + + + ) +} + +export const ArgumentInput = ({ + endString, + label, + tooltip, + value, + setValue, + inputType = "number", + placeholder = "0", + maxWidth = "100%" +}) => { + const theme = useTheme(); + const ref = useRef(null); + + return ( + + + {label} + + + { + ref.current && ref.current.focus(); + }} + > + + setValue(e.target.value)} + sx={{ flex: 1 }} + /> + {endString && ( + + {endString} + + )} + + + + ) +} diff --git a/src/hooks/governance/index.js b/src/hooks/governance/index.js index af6c0bb..02eb64a 100644 --- a/src/hooks/governance/index.js +++ b/src/hooks/governance/index.js @@ -52,7 +52,8 @@ export const useProposalVotes = (chainId, proposalId) => { const decimals = getTokenDecimals(name); const forVotes = new DecimalBigNumber(420_000_000_000_000_000_000n, decimals); const againstVotes = new DecimalBigNumber(69_000_000_000_000_000_000n, decimals); - return { forVotes, againstVotes } + const totalVotes = new DecimalBigNumber(489_000_000_000_000_000_000n, decimals); + return { forVotes, againstVotes, totalVotes } } export const useProposalSnapshot = (chainId, proposalId) => {