more governance functions added

Signed-off-by: Uncle Fatso <uncle.fatso@ghostchain.io>
This commit is contained in:
Uncle Fatso 2026-03-05 15:40:37 +03:00
parent 612573d433
commit de0000d6d5
Signed by: f4ts0
GPG Key ID: 565F4F2860226EBB
5 changed files with 232 additions and 67 deletions

View File

@ -1,7 +1,7 @@
{ {
"name": "ghost-dao-interface", "name": "ghost-dao-interface",
"private": true, "private": true,
"version": "0.5.41", "version": "0.5.42",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",

View File

@ -61,6 +61,15 @@ const Select = ({
IconComponent={KeyboardArrowDownIcon} IconComponent={KeyboardArrowDownIcon}
renderValue={renderValue} renderValue={renderValue}
displayEmpty displayEmpty
MenuProps={{
PaperProps: {
sx: {
maxHeight: 160,
overflowY: 'auto',
},
},
disableScrollLock: true,
}}
> >
{options.map((opt) => ( {options.map((opt) => (
<MenuItem key={opt.value} value={opt.value}> <MenuItem key={opt.value} value={opt.value}>

View File

@ -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 (
<>
<Modal
headerContent={
<Box display="flex" justifyContent="center" alignItems="center" gap="15px">
<Typography variant="h4">View setLateQuorumVoteExtension</Typography>
</Box>
}
open={isOpened}
onClose={() => setIsOpened(false)}
maxWidth="460px"
minHeight="80px"
>
<Box minHeight="100px" display="flex" alignItems="start" justifyContent="space-between" flexDirection="column">
<SetLateQuorumExtensionSteps {...props} />
</Box>
</Modal>
<ParsedCell isOpened={isOpened} setIsOpened={setIsOpened} {...props} />
</>
)
}
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 (
<Box height="100%" width="100%" display="flex" flexDirection="column" justifyContent={"space-between"}>
<ArgumentInput
disabled={!createMode}
endString="blocks"
label="lateQuorumVoteExtension"
value={lateQuorumVoteExtension ?? ""}
setValue={createMode ? setlateQuorumVoteExtension : () => {}}
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 && <Box width="100%" sx={{ marginTop: "20px" }} display="flex" flexDirection="column" gap="5px">
<Box display="flex" gap="10px">
<TertiaryButton onClick={toInitialStep} fullWidth>Back</TertiaryButton>
<TertiaryButton disabled fullWidth>Next</TertiaryButton>
</Box>
<PrimaryButton
disabled={!lateQuorumVoteExtension}
onClick={() => handleProceed()}
fullWidth
>
Create Function
</PrimaryButton>
</Box>}
</Box>
);
}

View File

@ -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 (
<>
<Modal
headerContent={
<Box display="flex" justifyContent="center" alignItems="center" gap="15px">
<Typography variant="h4">View setProposalThreshold</Typography>
</Box>
}
open={isOpened}
onClose={() => setIsOpened(false)}
maxWidth="460px"
minHeight="80px"
>
<Box minHeight="100px" display="flex" alignItems="start" justifyContent="space-between" flexDirection="column">
<SetProposalThresholdSteps {...props} />
</Box>
</Modal>
<ParsedCell isOpened={isOpened} setIsOpened={setIsOpened} {...props} />
</>
)
}
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 (
<Box height="100%" width="100%" display="flex" flexDirection="column" justifyContent={"space-between"}>
<ArgumentInput
disabled={!createMode}
endString="!CSPR units"
label="newProposalThreshold"
value={newThreshold ?? ""}
setValue={createMode ? setNewThreshold : () => {}}
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 && <Box width="100%" sx={{ marginTop: "20px" }} display="flex" flexDirection="column" gap="5px">
<Box display="flex" gap="10px">
<TertiaryButton onClick={toInitialStep} fullWidth>Back</TertiaryButton>
<TertiaryButton disabled fullWidth>Next</TertiaryButton>
</Box>
<PrimaryButton
disabled={!newThreshold}
onClick={() => handleProceed()}
fullWidth
>
Create Function
</PrimaryButton>
</Box>}
</Box>
);
}

View File

@ -10,6 +10,7 @@ import InfoTooltip from "../../../../components/Tooltip/InfoTooltip";
import { abi as TreasuryAbi } from "../../../../abi/GhostTreasury.json"; import { abi as TreasuryAbi } from "../../../../abi/GhostTreasury.json";
import { abi as DistributorAbi } from "../../../../abi/GhostDistributor.json"; import { abi as DistributorAbi } from "../../../../abi/GhostDistributor.json";
import { abi as DepositoryAbi } from "../../../../abi/GhostBondDepository.json"; import { abi as DepositoryAbi } from "../../../../abi/GhostBondDepository.json";
import { abi as GovernorAbi } from "../../../../abi/GhostGovernor.json";
import { config } from "../../../../config"; import { config } from "../../../../config";
import { shorten, formatCurrency } from "../../../../helpers"; import { shorten, formatCurrency } from "../../../../helpers";
@ -17,6 +18,8 @@ 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";
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." 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."
@ -24,9 +27,11 @@ export const allPossibleFunctions = [
{ value: "auditReserves", label: "auditReserves" }, { value: "auditReserves", label: "auditReserves" },
{ value: "setAdjustment", label: "setAdjustment" }, { value: "setAdjustment", label: "setAdjustment" },
{ value: "create", label: "create" }, { 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) => { const identifyAction = (calldata) => {
let decoded = { functionName: "Unknown", args: [] }; let decoded = { functionName: "Unknown", args: [] };
@ -57,72 +62,45 @@ export const parseFunctionCalldata = ({
const labelOrName = label ?? (functionName ?? "Unknown"); const labelOrName = label ?? (functionName ?? "Unknown");
const remove = removeCalldata && (() => removeCalldata(index)); const remove = removeCalldata && (() => removeCalldata(index));
const props = {
isTable,
calldata,
label: labelOrName,
chainId: chainId,
remove: removeCalldata,
nativeCoin,
value,
target,
args,
id: index,
};
switch (functionName) { switch (functionName) {
case "auditReserves": case allPossibleFunctions[0].value:
return <AuditReservesParsed return <AuditReservesParsed key={index} {...props} />;
isTable={isTable} case allPossibleFunctions[1].value:
key={index} return <SetAdjustmentParsed key={index} {...props} />;
calldata={calldata} case allPossibleFunctions[2].value:
label={labelOrName} return <CreateBondParsed {...props} />;
chainId={chainId} case allPossibleFunctions[3].value:
remove={remove} return <SetProposalThresholdParsed key={index} {...props} />;
nativeCoin={nativeCoin} case allPossibleFunctions[4].value:
value={value} return <SetLateQuorumExtensionParsed key={index} {...props} />;
target={target}
id={index}
/>;
case "setAdjustment":
return <SetAdjustmentParsed
isTable={isTable}
args={args}
key={index}
calldata={calldata}
label={labelOrName}
chainId={chainId}
remove={remove}
nativeCoin={nativeCoin}
value={value}
target={target}
id={index}
/>;
case "create":
return <CreateBondParsed
isTable={isTable}
args={args}
key={index}
calldata={calldata}
label={labelOrName}
chainId={chainId}
remove={remove}
nativeCoin={nativeCoin}
value={value}
target={target}
id={index}
/>;
default: default:
return <ParsedCell return <ParsedCell key={index} {...props} />;
isTable={isTable}
key={index}
calldata={calldata}
label="Unknown"
remove={remove}
nativeCoin={nativeCoin}
value={value}
target={target}
id={index}
/>;
} }
} }
export const getFunctionArguments = (functionName) => { export const getFunctionArguments = (functionName) => {
switch (functionName) { switch (functionName) {
case "auditReserves": case allPossibleFunctions[1].value:
return null;
case "setAdjustment":
return SetAdjustmentSteps; return SetAdjustmentSteps;
case "create": case allPossibleFunctions[2].value:
return CreateBondSteps; return CreateBondSteps;
case allPossibleFunctions[3].value:
return SetProposalThresholdSteps;
case allPossibleFunctions[4].value:
return SetLateQuorumExtensionSteps;
default: default:
return null; return null;
} }
@ -130,12 +108,16 @@ export const getFunctionArguments = (functionName) => {
export const getFunctionCalldata = (functionName, chainId) => { export const getFunctionCalldata = (functionName, chainId) => {
switch (functionName) { switch (functionName) {
case "auditReserves": case allPossibleFunctions[0].value:
return prepareAuditReservesCalldata(chainId); return prepareAuditReservesCalldata(chainId);
case "setAdjustment": case allPossibleFunctions[1].value:
return prepareSetAdjustmentCalldata(chainId); return prepareSetAdjustmentCalldata(chainId);
case "create": case allPossibleFunctions[2].value:
return prepareCreateBondCalldata(chainId); return prepareCreateBondCalldata(chainId);
case allPossibleFunctions[3].value:
return prepareSetProposalThresholdCalldata(chainId);
case allPossibleFunctions[4].value:
return prepareSetLateQuorumExtensionCalldata(chainId);
default: default:
return null; return null;
} }
@ -143,12 +125,16 @@ export const getFunctionCalldata = (functionName, chainId) => {
export const getFunctionDescription = (functionName) => { export const getFunctionDescription = (functionName) => {
switch (functionName) { switch (functionName) {
case "auditReserves": case allPossibleFunctions[0].value:
return prepareAuditReservesDescription; return prepareAuditReservesDescription;
case "setAdjustment": case allPossibleFunctions[1].value:
return prepareSetAdjustmentDescription; return prepareSetAdjustmentDescription;
case "create": case allPossibleFunctions[2].value:
return prepareCreateBondDescription; return prepareCreateBondDescription;
case allPossibleFunctions[3].value:
return prepareSetProposalThresholdDescription;
case allPossibleFunctions[4].value:
return prepareSetLateQuorumExtensionDescription;
default: default:
return DEFAULT_DESCRIPTION; return DEFAULT_DESCRIPTION;
} }