Compare commits

...

5 Commits

Author SHA1 Message Date
718e9a7be4
app rev.7
Signed-off-by: Uncle Fatso <uncle.fatso@ghostchain.io>
2026-02-19 17:37:33 +03:00
6f0e5e2af3
change button text when proposal succeeded
Signed-off-by: Uncle Fatso <uncle.fatso@ghostchain.io>
2026-02-19 17:23:45 +03:00
44f927faf8
fix logic for buttons on detailed view
Signed-off-by: Uncle Fatso <uncle.fatso@ghostchain.io>
2026-02-19 17:20:06 +03:00
83dc5ea8e9
make proposals indexation correct inside hooks
Signed-off-by: Uncle Fatso <uncle.fatso@ghostchain.io>
2026-02-19 17:08:48 +03:00
a176a16aaf
fix for local storage on governance
Signed-off-by: Uncle Fatso <uncle.fatso@ghostchain.io>
2026-02-19 16:38:10 +03:00
11 changed files with 49 additions and 41 deletions

View File

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

View File

@ -43,7 +43,7 @@ const NewProposal = ({ config, address, connect, chainId }) => {
const theme = useTheme(); const theme = useTheme();
const myStoredProposals = localStorage.getItem(MY_PROPOSALS_PREFIX); const myStoredProposals = localStorage.getItem(`${MY_PROPOSALS_PREFIX}-${address}`);
const [myProposals, setMyProposals] = useState( const [myProposals, setMyProposals] = useState(
myStoredProposals ? JSON.parse(myStoredProposals).map(id => BigInt(id)) : [] myStoredProposals ? JSON.parse(myStoredProposals).map(id => BigInt(id)) : []
); );
@ -63,7 +63,7 @@ const NewProposal = ({ config, address, connect, chainId }) => {
useEffect(() => { useEffect(() => {
const toStore = JSON.stringify(myProposals.map(id => id.toString())); const toStore = JSON.stringify(myProposals.map(id => id.toString()));
localStorage.setItem(MY_PROPOSALS_PREFIX, toStore); localStorage.setItem(`${MY_PROPOSALS_PREFIX}-${address}`, toStore);
}, [myProposals]); }, [myProposals]);
useEffect(() => { useEffect(() => {
@ -163,6 +163,14 @@ const NewProposal = ({ config, address, connect, chainId }) => {
isVertical isVertical
> >
<Box display="flex" flexDirection="column" alignItems="center"> <Box display="flex" flexDirection="column" alignItems="center">
<TertiaryButton
sx={{ maxWidth: isSemiSmallScreen ? "100%" : "350px" }}
fullWidth
disabled={isPending}
onClick={() => setIsModalOpened(true)}
>
Add New Function
</TertiaryButton>
<PrimaryButton <PrimaryButton
disabled={ disabled={
proposalFunctions.length === 0 || proposalFunctions.length === 0 ||
@ -174,14 +182,6 @@ const NewProposal = ({ config, address, connect, chainId }) => {
> >
{isPending ? "Submitting..." : "Submit Proposal"} {isPending ? "Submitting..." : "Submit Proposal"}
</PrimaryButton> </PrimaryButton>
<TertiaryButton
sx={{ maxWidth: isSemiSmallScreen ? "100%" : "350px" }}
fullWidth
disabled={isPending}
onClick={() => setIsModalOpened(true)}
>
Add New
</TertiaryButton>
</Box> </Box>
</TokenAllowanceGuard> </TokenAllowanceGuard>
</Box> </Box>

View File

@ -168,23 +168,26 @@ const ProposalDetails = ({ chainId, address, connect, config }) => {
const result = await castVote(chainId, address, proposalId, support); const result = await castVote(chainId, address, proposalId, support);
if (result) { if (result) {
const toStore = JSON.stringify(proposalId.toString()); const storedVotedProposals = localStorage.getItem(`${VOTED_PROPOSALS_PREFIX}-${address}`);
localStorage.setItem(VOTED_PROPOSALS_PREFIX, toStore); const proposals = JSON.parse(storedVotedProposals || "[]").map(id => BigInt(id));
proposals.push(proposalId);
const toStore = JSON.stringify(proposals.map(id => id.toString()));
localStorage.setItem(`${VOTED_PROPOSALS_PREFIX}-${address}`, toStore);
} }
setIsPending(true); setIsPending(false);
} }
const handleExecute = async () => { const handleExecute = async () => {
setIsPending(true); setIsPending(true);
await executeProposal(chainId, address, proposalId); await executeProposal(chainId, address, proposalId);
setIsPending(true); setIsPending(false);
} }
const handleRelease = async (proposalId) => { const handleRelease = async (proposalId) => {
setIsPending(true); setIsPending(true);
await releaseLocked(chainId, address, proposalId); await releaseLocked(chainId, address, proposalId);
setIsPending(true); setIsPending(false);
} }
return ( return (
@ -193,7 +196,7 @@ const ProposalDetails = ({ chainId, address, connect, config }) => {
name={`GBP-${id.slice(-5)}`} name={`GBP-${id.slice(-5)}`}
subtitle={ subtitle={
<Typography component="span"> <Typography component="span">
Proposal details, need more in-depth description {`Cast $${ghstSymbol} to shape this proposal's outcome`}
</Typography> </Typography>
} }
/> />
@ -340,6 +343,7 @@ const ProposalDetails = ({ chainId, address, connect, config }) => {
isProposer={proposalProposer === address} isProposer={proposalProposer === address}
chainId={chainId} chainId={chainId}
proposalId={id} proposalId={id}
isPending={isPending}
/> />
</Paper> </Paper>
</Box> </Box>
@ -377,7 +381,7 @@ const ProposalDetails = ({ chainId, address, connect, config }) => {
) )
} }
const VotingTimeline = ({ connect, handleExecute, handleRelease, proposalLocked, proposalId, chainId, state, address, isProposer }) => { const VotingTimeline = ({ connect, handleExecute, handleRelease, proposalLocked, proposalId, chainId, state, address, isProposer, isPending }) => {
const { delay: propsalVotingDelay } = useProposalVotingDelay(chainId, proposalId); const { delay: propsalVotingDelay } = useProposalVotingDelay(chainId, proposalId);
const { snapshot: proposalSnapshot } = useProposalSnapshot(chainId, proposalId); const { snapshot: proposalSnapshot } = useProposalSnapshot(chainId, proposalId);
const { deadline: proposalDeadline } = useProposalDeadline(chainId, proposalId); const { deadline: proposalDeadline } = useProposalDeadline(chainId, proposalId);
@ -397,19 +401,19 @@ const VotingTimeline = ({ connect, handleExecute, handleRelease, proposalLocked,
<VotingTimelineItem chainId={chainId} occured={proposalDeadline} message="Voting ends" /> <VotingTimelineItem chainId={chainId} occured={proposalDeadline} message="Voting ends" />
</Timeline> </Timeline>
<Box width="100%" display="flex" gap="10px"> <Box width="100%" display="flex" gap="10px">
{isProposer && <SecondaryButton {(isProposer || (proposalLocked?._value ?? 0n) > 0n) && <SecondaryButton
fullWidth fullWidth
disabled={(proposalLocked?._value ?? 0n) === 0n || state < 2} disabled={isPending || state < 2}
onClick={() => address === "" ? connect() : handleRelease()} onClick={() => address === "" ? connect() : handleRelease()}
> >
{address === "" ? "Connect" : "Release"} {address === "" ? "Connect" : "Release"}
</SecondaryButton>} </SecondaryButton>}
<SecondaryButton <SecondaryButton
fullWidth fullWidth
disabled={state !== 4} disabled={isPending || state !== 4}
onClick={() => address === "" ? connect() : handleExecute()} onClick={() => address === "" ? connect() : handleExecute()}
> >
{address === "" ? "Connect" : "Execute"} {address === "" ? "Connect" : state === 4 ? "Execute" : convertStatusToLabel(state)}
</SecondaryButton> </SecondaryButton>
</Box> </Box>
</Box> </Box>

View File

@ -103,7 +103,11 @@ const InitialStep = ({ selectedOption, handleChange, handleCalldata, handleProce
return allPossibleFunctions.find(opt => opt.value === selected)?.label || selected; return allPossibleFunctions.find(opt => opt.value === selected)?.label || selected;
}} }}
/> />
<Typography align="center" variant="body2">{functionDescription}</Typography> <Typography align="center" variant="body2">
<b>{selectedOption}</b>
{" "}
{functionDescription}
</Typography>
{ready {ready
? <TertiaryButton disabled={!selectedOption} onClick={() => handleProceed()} fullWidth>Proceed</TertiaryButton> ? <TertiaryButton disabled={!selectedOption} onClick={() => handleProceed()} fullWidth>Proceed</TertiaryButton>
: <PrimaryButton disabled={!selectedOption} onClick={() => handleCalldata()} fullWidth>Create Function</PrimaryButton> : <PrimaryButton disabled={!selectedOption} onClick={() => handleCalldata()} fullWidth>Create Function</PrimaryButton>

View File

@ -52,12 +52,12 @@ const ProposalsList = ({ chainId, address, config }) => {
const [proposalsFilter, setProposalFilter] = useState("active"); const [proposalsFilter, setProposalFilter] = useState("active");
const myStoredProposals = localStorage.getItem(MY_PROPOSALS_PREFIX); const myStoredProposals = localStorage.getItem(`${MY_PROPOSALS_PREFIX}-${address}`);
const [myProposals, setMyProposals] = useState( const [myProposals, setMyProposals] = useState(
myStoredProposals ? JSON.parse(myStoredProposals).map(id => BigInt(id)) : [] myStoredProposals ? JSON.parse(myStoredProposals).map(id => BigInt(id)) : []
); );
const storedVotedProposals = localStorage.getItem(VOTED_PROPOSALS_PREFIX); const storedVotedProposals = localStorage.getItem(`${VOTED_PROPOSALS_PREFIX}-${address}`);
const [votedProposals, setVotedProposals] = useState( const [votedProposals, setVotedProposals] = useState(
storedVotedProposals ? JSON.parse(storedVotedProposals).map(id => BigInt(id)) : [] storedVotedProposals ? JSON.parse(storedVotedProposals).map(id => BigInt(id)) : []
); );

View File

@ -20,7 +20,7 @@ export const prepareAuditReservesCalldata = (chainId) => {
return { label, target, calldata, value }; return { label, target, calldata, value };
} }
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 prepareAuditReservesDescription = "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;

View File

@ -29,7 +29,7 @@ export const prepareCreateBondCalldata = (chainId, markets, terms, quoteToken, i
return { label, target, calldata, value }; return { label, target, calldata, value };
} }
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 prepareCreateBondDescription = "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) => {
const [isOpened, setIsOpened] = useState(false); const [isOpened, setIsOpened] = useState(false);
@ -129,7 +129,7 @@ export const CreateBondSteps = ({ nativeCurrency, ftsoSymbol, chainId, toInitial
createMode={createMode} createMode={createMode}
possibleTokens={possibleTokens} possibleTokens={possibleTokens}
setTokenAddress={createMode ? setTokenAddress : empty} setTokenAddress={createMode ? setTokenAddress : empty}
nativeCurrency={nativeCurrency} nativeCurrency={reserveSymbol}
ftsoSymbol={ftsoSymbol} ftsoSymbol={ftsoSymbol}
capacityInQuote={capacityInQuote} capacityInQuote={capacityInQuote}
setCapacityInQuote={createMode ? setCapacityInQuote : empty} setCapacityInQuote={createMode ? setCapacityInQuote : empty}

View File

@ -24,7 +24,7 @@ export const prepareSetAdjustmentCalldata = (chainId, rateChange, targetRate, in
return { label, target, calldata, value }; return { label, target, calldata, value };
} }
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 prepareSetAdjustmentDescription = "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) => {
const [isOpened, setIsOpened] = useState(false); const [isOpened, setIsOpened] = useState(false);

View File

@ -52,7 +52,7 @@ export const TotalDeposit = props => {
const _props = { const _props = {
...props, ...props,
label: "Total Deposit", label: "Total Deposit",
tooltip: `The total native coin reserves in the ghostDAO treasury backing the entire circulating supply of ${props.stnkSymbol}.`, tooltip: `Total reserves of native coins, LP tokens, and other assets in the ghostDAO treasury backing the entire circulating supply of ${props.stnkSymbol}.`,
}; };
if (deposit) _props.metric = `${formatCurrency(deposit, 2)}`; if (deposit) _props.metric = `${formatCurrency(deposit, 2)}`;

View File

@ -84,7 +84,7 @@ export const FatsoBacking = props => {
const _props = { const _props = {
...props, ...props,
label: `Backing per ${props.ftsoSymbol}`, label: `Backing per ${props.ftsoSymbol}`,
tooltip: `The total amount of native coins held by the ghostDAO treasury to support the value of each ${props.ftsoSymbol} in circulation.` tooltip: `The total amount of native coins, LP tokens, and other assets held by the ghostDAO treasury to support the value of each ${props.ftsoSymbol} in circulation.`
}; };
if (backing) _props.metric = formatCurrency(backing, 2); if (backing) _props.metric = formatCurrency(backing, 2);

View File

@ -335,7 +335,7 @@ export const useProposals = (chainId, depth, searchedIndexes) => {
const { data: proposalDeadlines } = useReadContracts({ const { data: proposalDeadlines } = useReadContracts({
contracts: indexes?.map(index => { contracts: indexes?.map(index => {
const proposalId = searchedIndexes const proposalId = searchedIndexes
? searchedIndexes?.at(0) ? searchedIndexes?.at(index)
: proposalsDetailsAt?.at(index)?.result?.at(0); : proposalsDetailsAt?.at(index)?.result?.at(0);
return { return {
@ -352,7 +352,7 @@ export const useProposals = (chainId, depth, searchedIndexes) => {
const { data: proposalVotes } = useReadContracts({ const { data: proposalVotes } = useReadContracts({
contracts: indexes?.map(index => { contracts: indexes?.map(index => {
const proposalId = searchedIndexes const proposalId = searchedIndexes
? searchedIndexes?.at(0) ? searchedIndexes?.at(index)
: proposalsDetailsAt?.at(index)?.result?.at(0); : proposalsDetailsAt?.at(index)?.result?.at(0);
return { return {
@ -369,7 +369,7 @@ export const useProposals = (chainId, depth, searchedIndexes) => {
const { data: proposalStates } = useReadContracts({ const { data: proposalStates } = useReadContracts({
contracts: indexes?.map(index => { contracts: indexes?.map(index => {
const proposalId = searchedIndexes const proposalId = searchedIndexes
? searchedIndexes?.at(0) ? searchedIndexes?.at(index)
: proposalsDetailsAt?.at(index)?.result?.at(0); : proposalsDetailsAt?.at(index)?.result?.at(0);
return { return {
@ -386,7 +386,7 @@ export const useProposals = (chainId, depth, searchedIndexes) => {
const { data: proposalSnapshots } = useReadContracts({ const { data: proposalSnapshots } = useReadContracts({
contracts: indexes?.map(index => { contracts: indexes?.map(index => {
const proposalId = searchedIndexes const proposalId = searchedIndexes
? searchedIndexes?.at(0) ? searchedIndexes?.at(index)
: proposalsDetailsAt?.at(index)?.result?.at(0); : proposalsDetailsAt?.at(index)?.result?.at(0);
return { return {
@ -401,8 +401,8 @@ export const useProposals = (chainId, depth, searchedIndexes) => {
}); });
const { data: proposalQuorums } = useReadContracts({ const { data: proposalQuorums } = useReadContracts({
contracts: indexes?.map(index => { contracts: proposalSnapshots?.map((proposal, index) => {
const timepoint = proposalSnapshots?.at(index)?.result; const timepoint = proposal?.result;
return { return {
abi: GovernorAbi, abi: GovernorAbi,
address: GHOST_GOVERNANCE_ADDRESSES[chainId], address: GHOST_GOVERNANCE_ADDRESSES[chainId],
@ -415,8 +415,8 @@ export const useProposals = (chainId, depth, searchedIndexes) => {
}); });
const { data: pastTotalSupplies } = useReadContracts({ const { data: pastTotalSupplies } = useReadContracts({
contracts: indexes?.map(index => { contracts: proposalSnapshots?.map((proposal, index) => {
const timepoint = proposalSnapshots?.at(index)?.result; const timepoint = proposal?.result;
return { return {
abi: ghstAbi, abi: ghstAbi,
address: ghstAddress, address: ghstAddress,
@ -431,7 +431,7 @@ export const useProposals = (chainId, depth, searchedIndexes) => {
const { data: proposalProposer } = useReadContracts({ const { data: proposalProposer } = useReadContracts({
contracts: indexes?.map(index => { contracts: indexes?.map(index => {
const proposalId = searchedIndexes const proposalId = searchedIndexes
? searchedIndexes?.at(0) ? searchedIndexes?.at(index)
: proposalsDetailsAt?.at(index)?.result?.at(0); : proposalsDetailsAt?.at(index)?.result?.at(0);
return { return {
@ -448,7 +448,7 @@ export const useProposals = (chainId, depth, searchedIndexes) => {
const hashes = indexes?.map(index => { const hashes = indexes?.map(index => {
let result = { short: index + 1, full: undefined }; let result = { short: index + 1, full: undefined };
const proposalId = searchedIndexes const proposalId = searchedIndexes
? searchedIndexes?.at(0) ? searchedIndexes?.at(index)
: proposalsDetailsAt?.at(index)?.result?.at(0); : proposalsDetailsAt?.at(index)?.result?.at(0);
if (proposalId) { if (proposalId) {