From de0000d6d5adfc658be6ea547406a5b37da28aac Mon Sep 17 00:00:00 2001 From: Uncle Fatso Date: Thu, 5 Mar 2026 15:40:37 +0300 Subject: [PATCH] more governance functions added Signed-off-by: Uncle Fatso --- package.json | 2 +- src/components/Select/Select.jsx | 9 ++ .../functions/LateQuorumExtension.jsx | 85 +++++++++++++ .../functions/ProposalThreshold.jsx | 85 +++++++++++++ .../Governance/components/functions/index.jsx | 118 ++++++++---------- 5 files changed, 232 insertions(+), 67 deletions(-) create mode 100644 src/containers/Governance/components/functions/LateQuorumExtension.jsx create mode 100644 src/containers/Governance/components/functions/ProposalThreshold.jsx diff --git a/package.json b/package.json index 1e3b38c..7d07c60 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ghost-dao-interface", "private": true, - "version": "0.5.41", + "version": "0.5.42", "type": "module", "scripts": { "dev": "vite", diff --git a/src/components/Select/Select.jsx b/src/components/Select/Select.jsx index f3b4123..2f1482c 100644 --- a/src/components/Select/Select.jsx +++ b/src/components/Select/Select.jsx @@ -61,6 +61,15 @@ const Select = ({ IconComponent={KeyboardArrowDownIcon} renderValue={renderValue} displayEmpty + MenuProps={{ + PaperProps: { + sx: { + maxHeight: 160, + overflowY: 'auto', + }, + }, + disableScrollLock: true, + }} > {options.map((opt) => ( diff --git a/src/containers/Governance/components/functions/LateQuorumExtension.jsx b/src/containers/Governance/components/functions/LateQuorumExtension.jsx new file mode 100644 index 0000000..b9ac438 --- /dev/null +++ b/src/containers/Governance/components/functions/LateQuorumExtension.jsx @@ -0,0 +1,85 @@ +import { useState } from "react"; +import { encodeFunctionData } from 'viem'; +import { Box, Typography, TableRow, TableCell, useTheme } from "@mui/material"; + +import Modal from "../../../../components/Modal/Modal"; +import { PrimaryButton, TertiaryButton } from "../../../../components/Button"; + +import { GHOST_GOVERNANCE_ADDRESSES } from "../../../../constants/addresses"; +import { abi as GovernorAbi } from "../../../../abi/GhostGovernor.json"; + +import { ArgumentInput, ParsedCell } from "./index"; + +export const prepareSetLateQuorumExtensionCalldata = (chainId, lateQuorumVoteExtension) => { + const value = 0n; + const label = "setLateQuorumVoteExtension"; + const target = GHOST_GOVERNANCE_ADDRESSES[chainId]; + const calldata = encodeFunctionData({ + abi: GovernorAbi, + functionName: 'setLateQuorumVoteExtension', + args: [lateQuorumVoteExtension] + }); + return { label, target, calldata, value }; +} + +export const prepareSetLateQuorumExtensionDescription = "updates the current value of the vote extension parameter: the number of blocks that are required to pass from the time a proposal reaches quorum until its voting period ends."; + +export const SetLateQuorumExtensionParsed = (props) => { + const [isOpened, setIsOpened] = useState(false); + return ( + <> + + View setLateQuorumVoteExtension + + } + open={isOpened} + onClose={() => setIsOpened(false)} + maxWidth="460px" + minHeight="80px" + > + + + + + + + ) +} + +export const SetLateQuorumExtensionSteps = ({ chainId, toInitialStep, addCalldata, args }) => { + const createMode = args === undefined; + + const [lateQuorumVoteExtension, setlateQuorumVoteExtension] = useState(args?.at(0)); + + const handleProceed = () => { + addCalldata(prepareSetLateQuorumExtensionCalldata(chainId, lateQuorumVoteExtension)); + } + + return ( + + {}} + tooltip="Vote extension defines extension in blocks if a vote causes quorum to be reached, the proposal's voting period may be extended so that it does not end before at least a specified time has passed" + /> + {createMode && + + Back + Next + + handleProceed()} + fullWidth + > + Create Function + + } + + ); +} diff --git a/src/containers/Governance/components/functions/ProposalThreshold.jsx b/src/containers/Governance/components/functions/ProposalThreshold.jsx new file mode 100644 index 0000000..38160ca --- /dev/null +++ b/src/containers/Governance/components/functions/ProposalThreshold.jsx @@ -0,0 +1,85 @@ +import { useState } from "react"; +import { encodeFunctionData } from 'viem'; +import { Box, Typography, TableRow, TableCell, useTheme } from "@mui/material"; + +import Modal from "../../../../components/Modal/Modal"; +import { PrimaryButton, TertiaryButton } from "../../../../components/Button"; + +import { GHOST_GOVERNANCE_ADDRESSES } from "../../../../constants/addresses"; +import { abi as GovernorAbi } from "../../../../abi/GhostGovernor.json"; + +import { ArgumentInput, ParsedCell } from "./index"; + +export const prepareSetProposalThresholdCalldata = (chainId, newThreshold) => { + const value = 0n; + const label = "setProposalThreshold"; + const target = GHOST_GOVERNANCE_ADDRESSES[chainId]; + const calldata = encodeFunctionData({ + abi: GovernorAbi, + functionName: 'setProposalThreshold', + args: [newThreshold] + }); + return { label, target, calldata, value }; +} + +export const prepareSetProposalThresholdDescription = "updates the minimum amount required to create a proposal. This threshold applies only when there are no Active or Pending proposals; otherwise, a higher threshold is enforced."; + +export const SetProposalThresholdParsed = (props) => { + const [isOpened, setIsOpened] = useState(false); + return ( + <> + + View setProposalThreshold + + } + open={isOpened} + onClose={() => setIsOpened(false)} + maxWidth="460px" + minHeight="80px" + > + + + + + + + ) +} + +export const SetProposalThresholdSteps = ({ chainId, toInitialStep, addCalldata, args }) => { + const createMode = args === undefined; + + const [newThreshold, setNewThreshold] = useState(args?.at(0)); + + const handleProceed = () => { + addCalldata(prepareSetProposalThresholdCalldata(chainId, newThreshold)); + } + + return ( + + {}} + tooltip="The new proposal threshold defines the minimum amount each proposer must lock for the duration of the proposal. This locked amount serves as the required deposit to create a proposal." + /> + {createMode && + + Back + Next + + handleProceed()} + fullWidth + > + Create Function + + } + + ); +} diff --git a/src/containers/Governance/components/functions/index.jsx b/src/containers/Governance/components/functions/index.jsx index e3073a7..5544d7b 100644 --- a/src/containers/Governance/components/functions/index.jsx +++ b/src/containers/Governance/components/functions/index.jsx @@ -10,6 +10,7 @@ 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 { abi as GovernorAbi } from "../../../../abi/GhostGovernor.json"; import { config } from "../../../../config"; import { shorten, formatCurrency } from "../../../../helpers"; @@ -17,16 +18,20 @@ import { shorten, formatCurrency } from "../../../../helpers"; import { prepareAuditReservesDescription, prepareAuditReservesCalldata, AuditReservesSteps, AuditReservesParsed } from "./AuditReserves"; import { prepareSetAdjustmentDescription, prepareSetAdjustmentCalldata, SetAdjustmentSteps, SetAdjustmentParsed } from "./SetAdjustment"; import { prepareCreateBondDescription, prepareCreateBondCalldata, CreateBondSteps, CreateBondParsed } from "./CreateBond"; +import { prepareSetProposalThresholdDescription, prepareSetProposalThresholdCalldata, SetProposalThresholdSteps, SetProposalThresholdParsed } from "./ProposalThreshold"; +import { prepareSetLateQuorumExtensionDescription, prepareSetLateQuorumExtensionCalldata, SetLateQuorumExtensionSteps, SetLateQuorumExtensionParsed } from "./LateQuorumExtension"; 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 = [ - { value: "auditReserves", label: "auditReserves" }, - { value: "setAdjustment", label: "setAdjustment" }, - { value: "create", label: "create" }, + { value: "auditReserves", label: "auditReserves" }, + { value: "setAdjustment", label: "setAdjustment" }, + { value: "create", label: "create" }, + { value: "setProposalThreshold", label: "setProposalThreshold" }, + { value: "setLateQuorumVoteExtension", label: "setLateQuorumVoteExtension" }, ]; -const allAbis = [TreasuryAbi, DistributorAbi, DepositoryAbi]; +const allAbis = [TreasuryAbi, DistributorAbi, DepositoryAbi, GovernorAbi]; const identifyAction = (calldata) => { let decoded = { functionName: "Unknown", args: [] }; @@ -57,72 +62,45 @@ export const parseFunctionCalldata = ({ const labelOrName = label ?? (functionName ?? "Unknown"); const remove = removeCalldata && (() => removeCalldata(index)); + const props = { + isTable, + calldata, + label: labelOrName, + chainId: chainId, + remove: removeCalldata, + nativeCoin, + value, + target, + args, + id: index, + }; switch (functionName) { - case "auditReserves": - return ; - case "setAdjustment": - return ; - case "create": - return ; + case allPossibleFunctions[0].value: + return ; + case allPossibleFunctions[1].value: + return ; + case allPossibleFunctions[2].value: + return ; + case allPossibleFunctions[3].value: + return ; + case allPossibleFunctions[4].value: + return ; default: - return ; + return ; } } export const getFunctionArguments = (functionName) => { switch (functionName) { - case "auditReserves": - return null; - case "setAdjustment": + case allPossibleFunctions[1].value: return SetAdjustmentSteps; - case "create": + case allPossibleFunctions[2].value: return CreateBondSteps; + case allPossibleFunctions[3].value: + return SetProposalThresholdSteps; + case allPossibleFunctions[4].value: + return SetLateQuorumExtensionSteps; default: return null; } @@ -130,12 +108,16 @@ export const getFunctionArguments = (functionName) => { export const getFunctionCalldata = (functionName, chainId) => { switch (functionName) { - case "auditReserves": + case allPossibleFunctions[0].value: return prepareAuditReservesCalldata(chainId); - case "setAdjustment": + case allPossibleFunctions[1].value: return prepareSetAdjustmentCalldata(chainId); - case "create": + case allPossibleFunctions[2].value: return prepareCreateBondCalldata(chainId); + case allPossibleFunctions[3].value: + return prepareSetProposalThresholdCalldata(chainId); + case allPossibleFunctions[4].value: + return prepareSetLateQuorumExtensionCalldata(chainId); default: return null; } @@ -143,12 +125,16 @@ export const getFunctionCalldata = (functionName, chainId) => { export const getFunctionDescription = (functionName) => { switch (functionName) { - case "auditReserves": + case allPossibleFunctions[0].value: return prepareAuditReservesDescription; - case "setAdjustment": + case allPossibleFunctions[1].value: return prepareSetAdjustmentDescription; - case "create": + case allPossibleFunctions[2].value: return prepareCreateBondDescription; + case allPossibleFunctions[3].value: + return prepareSetProposalThresholdDescription; + case allPossibleFunctions[4].value: + return prepareSetLateQuorumExtensionDescription; default: return DEFAULT_DESCRIPTION; }