Compare commits

..

No commits in common. "main" and "dao-governance" have entirely different histories.

18 changed files with 113 additions and 138 deletions

View File

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

View File

@ -9,12 +9,12 @@ const classes = {
const StyledMuiChip = styled(MuiChip, { const StyledMuiChip = styled(MuiChip, {
shouldForwardProp: prop => prop !== "template" && prop !== "strong", shouldForwardProp: prop => prop !== "template" && prop !== "strong",
})(({ theme, template, background, strong }) => { })(({ theme, template, strong }) => {
return { return {
[`&.${classes.chip}`]: { [`&.${classes.chip}`]: {
height: "21px", height: "21px",
borderRadius: "16px", borderRadius: "16px",
backgroundColor: background ? background : template backgroundColor: template
? template === "purple" ? template === "purple"
? theme.colors.special["olyZaps"] ? theme.colors.special["olyZaps"]
: template === "gray" : template === "gray"
@ -42,8 +42,8 @@ const StyledMuiChip = styled(MuiChip, {
}; };
}); });
const Chip = ({ background, template, strong = false, ...props }) => { const Chip = ({ template, strong = false, ...props }) => {
return <StyledMuiChip className={classes.chip} background={background} template={template} strong={strong} {...props} />; return <StyledMuiChip className={classes.chip} template={template} strong={strong} {...props} />;
}; };
export default Chip; export default Chip;

View File

@ -25,7 +25,7 @@ const LinearProgressBar = (props) => {
{props.target && <Box {props.target && <Box
sx={{ sx={{
position: 'absolute', position: 'absolute',
left: `${Math.min(Math.max(props.target, 0), 100)}%`, left: `${props.target}%`,
top: props.targetTop || 0, top: props.targetTop || 0,
bottom: props.targetBottom || 0, bottom: props.targetBottom || 0,
width: props.targetWidth || "2px", width: props.targetWidth || "2px",

View File

@ -67,7 +67,7 @@ export const DISTRIBUTOR_ADDRESSES = {
}; };
export const GHOST_GOVERNANCE_ADDRESSES = { export const GHOST_GOVERNANCE_ADDRESSES = {
[NetworkId.TESTNET_SEPOLIA]: "0xaf7Ad1b83C47405BB9aa96868bCFbb6D65e4C2a1", [NetworkId.TESTNET_SEPOLIA]: "0x4823F1DC785D721eAdD2bD218E1eeD63aF67fBF4",
}; };
export const BONDING_CALCULATOR_ADDRESSES = { export const BONDING_CALCULATOR_ADDRESSES = {

View File

@ -177,12 +177,12 @@ const BondInputArea = ({
)} )}
</span> </span>
} }
tooltip={`Total amount of ${ftsoSymbol} you will receive from this bond purchase`} tooltip={`The total amount of payout asset you will receive from this bond purchase`}
/> />
<DataRow <DataRow
title="Max You Can Buy" title="Max You Can Buy"
tooltip={`Maximum ${ftsoSymbol} that can be purchased in a single transaction. Prevents whales from buying entire bond supply at once.`} tooltip={`The maximum quantity of payout token offered via bonds at this moment in time`}
balance={ balance={
<span> <span>
{bond.baseToken.tokenAddress.toUpperCase() === bond.quoteToken.quoteTokenAddress.toUpperCase() {bond.baseToken.tokenAddress.toUpperCase() === bond.quoteToken.quoteTokenAddress.toUpperCase()
@ -195,13 +195,13 @@ const BondInputArea = ({
<DataRow <DataRow
title="Discount" title="Discount"
balance={<BondDiscount discount={bond.discount} textOnly />} balance={<BondDiscount discount={bond.discount} textOnly />}
tooltip={`The discount (or premium) between ${ftsoSymbol} market price and bond price. Higher discount = better deal for bond buyers.`} tooltip={`The bond discount is the percentage difference between ${ftsoSymbol} market value and the bond's price`}
/> />
<DataRow <DataRow
title={`Vesting Term`} title={`Vesting Term`}
balance={<BondVesting vesting={bond.vesting} />} balance={<BondVesting vesting={bond.vesting} />}
tooltip={"Time until bond fully vests and becomes claimable. Vesting period aligns bond buyer with the protocol by encouraging longer-term holding."} tooltip={"The duration of the Bond whereby the bond can be claimed in its entirety"}
/> />
{recipientAddress !== address && ( {recipientAddress !== address && (

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}-${address}`); const myStoredProposals = localStorage.getItem(MY_PROPOSALS_PREFIX);
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}-${address}`, toStore); localStorage.setItem(MY_PROPOSALS_PREFIX, toStore);
}, [myProposals]); }, [myProposals]);
useEffect(() => { useEffect(() => {
@ -163,14 +163,6 @@ 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 ||
@ -182,6 +174,14 @@ 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

@ -1,8 +1,7 @@
import { useEffect, useState, useMemo } from "react"; import { useEffect, useState, useMemo } from "react";
import ReactGA from "react-ga4"; import ReactGA from "react-ga4";
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
import { useQueryClient } from '@tanstack/react-query'; import { useBlock, useBlockNumber } from 'wagmi'
import { useBlock, useBlockNumber } from "wagmi";
import { import {
Box, Box,
@ -33,7 +32,7 @@ import { formatNumber, formatCurrency, shorten } from "../../helpers";
import { prettifySecondsInDays } from "../../helpers/timeUtil"; import { prettifySecondsInDays } from "../../helpers/timeUtil";
import { DecimalBigNumber, } from "../../helpers/DecimalBigNumber"; import { DecimalBigNumber, } from "../../helpers/DecimalBigNumber";
import { convertStatusToColor, convertStatusToLabel } from "./helpers"; import { convertStatusToTemplate, convertStatusToLabel } from "./helpers";
import { parseFunctionCalldata } from "./components/functions"; import { parseFunctionCalldata } from "./components/functions";
import { networkAvgBlockSpeed } from "../../constants"; import { networkAvgBlockSpeed } from "../../constants";
@ -73,7 +72,6 @@ import RepeatIcon from '@mui/icons-material/Repeat';
const HUNDRED = new DecimalBigNumber(100n, 0); const HUNDRED = new DecimalBigNumber(100n, 0);
const ProposalDetails = ({ chainId, address, connect, config }) => { const ProposalDetails = ({ chainId, address, connect, config }) => {
const { id } = useParams(); const { id } = useParams();
const proposalId = BigInt(id); const proposalId = BigInt(id);
@ -86,7 +84,6 @@ const ProposalDetails = ({ chainId, address, connect, config }) => {
const isVerySmallScreen = useMediaQuery("(max-width: 379px)"); const isVerySmallScreen = useMediaQuery("(max-width: 379px)");
const theme = useTheme(); const theme = useTheme();
const queryClient = useQueryClient();
const { symbol: ghstSymbol } = useTokenSymbol(chainId, "GHST"); const { symbol: ghstSymbol } = useTokenSymbol(chainId, "GHST");
const { balance } = useBalance(chainId, "GHST", address); const { balance } = useBalance(chainId, "GHST", address);
@ -115,42 +112,47 @@ const ProposalDetails = ({ chainId, address, connect, config }) => {
const votePercentage = useMemo(() => { const votePercentage = useMemo(() => {
if (totalSupply._value === 0n) return 0; if (totalSupply._value === 0n) return 0;
return totalVotes * HUNDRED / totalSupply; const value = (totalVotes?._value ?? 0n) * 100n / (totalSupply?._value ?? 1n);
return new DecimalBigNumber(value, 0);
}, [totalVotes, totalSupply]); }, [totalVotes, totalSupply]);
const forPercentage = useMemo(() => { const forPercentage = useMemo(() => {
if (totalSupply._value === 0n) return new DecimalBigNumber(0n, 2); if (totalSupply._value === 0n) return new DecimalBigNumber(0n, 2);
return forVotes * HUNDRED / totalSupply; const value = (forVotes?._value ?? 0n) * 10000n / (totalSupply?._value ?? 1n);
return new DecimalBigNumber(value, 2);
}, [forVotes, totalSupply]); }, [forVotes, totalSupply]);
const againstPercentage= useMemo(() => { const againstPercentage= useMemo(() => {
if (totalSupply._value === 0n) return new DecimalBigNumber(0n, 2); if (totalSupply._value === 0n) return new DecimalBigNumber(0n, 2);
return againstVotes * HUNDRED / totalSupply; const value = (againstVotes?._value ?? 0n) * 10000n / (totalSupply?._value ?? 1n);
return new DecimalBigNumber(value, 2);
}, [againstVotes, totalSupply]); }, [againstVotes, totalSupply]);
const voteWeightPercentage = useMemo(() => { const voteWeightPercentage = useMemo(() => {
if (totalSupply._value === 0n) return new DecimalBigNumber(0n, 2); if (totalSupply._value === 0n) return new DecimalBigNumber(0n, 2);
return pastVotes * HUNDRED / totalSupply; const value = (pastVotes?._value ?? 0n) * 10000n / (totalSupply?._value ?? 1n);
return new DecimalBigNumber(value, 2);
}, [pastVotes, totalSupply]); }, [pastVotes, totalSupply]);
const voteValue = useMemo(() => { const voteValue = useMemo(() => {
if (totalVotes?._value == 0n) { if (totalVotes?._value == 0n) {
return 0; return 0;
} }
const value = forVotes * HUNDRED / totalVotes; return Number(forVotes._value * 100n / totalVotes._value);
return Math.floor(Number(value.toString()));
}, [forVotes, totalVotes]); }, [forVotes, totalVotes]);
const voteTarget = useMemo(() => { const voteTarget = useMemo(() => {
if (totalSupply._value == 0n) { const first = (5n * againstVotes._value + forVotes._value);
const second = BigInt(Math.floor(Math.sqrt(Number(totalVotes._value))));
const bias = 3n * first + second;
const denominator = totalVotes._value + bias;
if (denominator === 0n) {
return 80; return 80;
} }
const value = Number(totalVotes / totalSupply); return Number(totalVotes?._value * 100n / denominator);
const result = (5 - Math.sqrt(1 + 80/9 * (value - 0.1) )) / 4 }, [againstVotes, forVotes, totalVotes]);
return Math.floor(result * 100);
}, [totalVotes, totalSupply]);
const nativeCurrency = useMemo(() => { const nativeCurrency = useMemo(() => {
const client = config?.getClient(); const client = config?.getClient();
@ -166,33 +168,29 @@ const ProposalDetails = ({ chainId, address, connect, config }) => {
return url; return url;
}, [proposalProposer, config]); }, [proposalProposer, config]);
const handleVote = async (support) => { const handleVote = async (against) => {
setIsPending(true); setIsPending(true);
const support = against ? 0 : 1;
const result = await castVote(chainId, address, proposalId, support); const result = await castVote(chainId, address, proposalId, support);
if (result) { if (result) {
const storedVotedProposals = localStorage.getItem(`${VOTED_PROPOSALS_PREFIX}-${address}`); const toStore = JSON.stringify(proposalId.toString());
const proposals = JSON.parse(storedVotedProposals || "[]").map(id => BigInt(id)); localStorage.setItem(VOTED_PROPOSALS_PREFIX, toStore);
proposals.push(proposalId);
const toStore = JSON.stringify(proposals.map(id => id.toString()));
localStorage.setItem(`${VOTED_PROPOSALS_PREFIX}-${address}`, toStore);
await queryClient.invalidateQueries();
} }
setIsPending(false);
setIsPending(true);
} }
const handleExecute = async () => { const handleExecute = async () => {
setIsPending(true); setIsPending(true);
await executeProposal(chainId, address, proposalId); await executeProposal(chainId, address, proposalId);
await queryClient.invalidateQueries(); setIsPending(true);
setIsPending(false);
} }
const handleRelease = async () => { const handleRelease = async (proposalId) => {
setIsPending(true); setIsPending(true);
await releaseLocked(chainId, address, proposalId); await releaseLocked(chainId, address, proposalId);
await queryClient.invalidateQueries(); setIsPending(true);
setIsPending(false);
} }
return ( return (
@ -201,7 +199,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">
{`Cast $${ghstSymbol} to shape this proposal's outcome`} Proposal details, need more in-depth description
</Typography> </Typography>
} }
/> />
@ -228,7 +226,7 @@ const ProposalDetails = ({ chainId, address, connect, config }) => {
<Chip <Chip
sx={{ marginTop: "4px", width: "88px" }} sx={{ marginTop: "4px", width: "88px" }}
label={convertStatusToLabel(proposalState)} label={convertStatusToLabel(proposalState)}
background={convertStatusToColor(proposalState)} template={convertStatusToTemplate(proposalState)}
/> />
</Box> </Box>
} }
@ -348,7 +346,6 @@ 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>
@ -386,7 +383,7 @@ const ProposalDetails = ({ chainId, address, connect, config }) => {
) )
} }
const VotingTimeline = ({ connect, handleExecute, handleRelease, proposalLocked, proposalId, chainId, state, address, isProposer, isPending }) => { const VotingTimeline = ({ connect, handleExecute, handleRelease, proposalLocked, proposalId, chainId, state, address, isProposer }) => {
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);
@ -406,19 +403,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 && (proposalLocked?._value ?? 0n) > 0n) && <SecondaryButton {isProposer && <SecondaryButton
fullWidth fullWidth
disabled={isPending || state < 2} disabled={(proposalLocked?._value ?? 0n) === 0n || state < 2}
onClick={() => address === "" ? connect() : handleRelease()} onClick={() => address === "" ? connect() : handleRelease()}
> >
{address === "" ? "Connect" : "Release"} {address === "" ? "Connect" : "Release"}
</SecondaryButton>} </SecondaryButton>}
<SecondaryButton <SecondaryButton
fullWidth fullWidth
disabled={isPending || state !== 4} disabled={state !== 4}
onClick={() => address === "" ? connect() : handleExecute()} onClick={() => address === "" ? connect() : handleExecute()}
> >
{address === "" ? "Connect" : state === 4 ? "Execute" : convertStatusToLabel(state)} {address === "" ? "Connect" : "Execute"}
</SecondaryButton> </SecondaryButton>
</Box> </Box>
</Box> </Box>

View File

@ -12,7 +12,7 @@ const GovernanceInfoText = () => {
ghostDAOs adaptive governance system algorithmically sets minimum collateral based on activity. ghostDAOs adaptive governance system algorithmically sets minimum collateral based on activity.
&nbsp;<Link &nbsp;<Link
color={theme.colors.primary[300]} color={theme.colors.primary[300]}
href="http://forum.ghostchain.io/" href="https://docs.dao.ghostchain.io/"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
>Learn more here.</Link> >Learn more here.</Link>

View File

@ -103,11 +103,7 @@ 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"> <Typography align="center" variant="body2">{functionDescription}</Typography>
<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

@ -23,7 +23,6 @@ import ArrowUpIcon from "../../../assets/icons/arrow-up.svg?react";
import { networkAvgBlockSpeed } from "../../../constants"; import { networkAvgBlockSpeed } from "../../../constants";
import { prettifySecondsInDays, prettifySeconds } from "../../../helpers/timeUtil"; import { prettifySecondsInDays, prettifySeconds } from "../../../helpers/timeUtil";
import { DecimalBigNumber } from "../../../helpers/DecimalBigNumber";
import Chip from "../../../components/Chip/Chip"; import Chip from "../../../components/Chip/Chip";
import Modal from "../../../components/Modal/Modal"; import Modal from "../../../components/Modal/Modal";
@ -33,7 +32,7 @@ import { PrimaryButton, TertiaryButton } from "../../../components/Button";
import ProposalInfoText from "./ProposalInfoText"; import ProposalInfoText from "./ProposalInfoText";
import { import {
convertStatusToColor, convertStatusToTemplate,
convertStatusToLabel, convertStatusToLabel,
MY_PROPOSALS_PREFIX, MY_PROPOSALS_PREFIX,
VOTED_PROPOSALS_PREFIX VOTED_PROPOSALS_PREFIX
@ -41,7 +40,9 @@ import {
import { useScreenSize } from "../../../hooks/useScreenSize"; import { useScreenSize } from "../../../hooks/useScreenSize";
import { useProposals } from "../../../hooks/governance"; import {
useProposals,
} from "../../../hooks/governance";
const MAX_PROPOSALS_TO_SHOW = 10; const MAX_PROPOSALS_TO_SHOW = 10;
@ -52,12 +53,12 @@ const ProposalsList = ({ chainId, address, config }) => {
const [proposalsFilter, setProposalFilter] = useState("active"); const [proposalsFilter, setProposalFilter] = useState("active");
const myStoredProposals = localStorage.getItem(`${MY_PROPOSALS_PREFIX}-${address}`); const myStoredProposals = localStorage.getItem(MY_PROPOSALS_PREFIX);
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}-${address}`); const storedVotedProposals = localStorage.getItem(VOTED_PROPOSALS_PREFIX);
const [votedProposals, setVotedProposals] = useState( const [votedProposals, setVotedProposals] = useState(
storedVotedProposals ? JSON.parse(storedVotedProposals).map(id => BigInt(id)) : [] storedVotedProposals ? JSON.parse(storedVotedProposals).map(id => BigInt(id)) : []
); );
@ -174,7 +175,7 @@ const ProposalTable = ({ children }) => (
<TableCell align="center" style={{ width: "130px", padding: "8px 0" }}>Status</TableCell> <TableCell align="center" style={{ width: "130px", 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>
<TableCell align="center" style={{ width: "180px", padding: "8px 0" }}></TableCell> <TableCell align="center" style={{ padding: "8px 0" }}></TableCell>
</TableRow> </TableRow>
</TableHead> </TableHead>
@ -187,38 +188,30 @@ const ProposalRow = ({ proposal, blockNumber, openProposal, chainId }) => {
const theme = useTheme(); const theme = useTheme();
const voteValue = useMemo(() => { const voteValue = useMemo(() => {
const againstVotes = proposal?.votes?.at(0)?._value ?? 0n const againstVotes = proposal?.votes?.at(0)?._value ?? 0n;
const forVotes = proposal?.votes?.at(1)?._value ?? 0n; const forVotes = proposal?.votes?.at(1)?._value ?? 0n;
const totalVotes = againstVotes + forVotes; const totalVotes = againstVotes + forVotes;
if (totalVotes == 0) {
if (totalVotes == 0n) {
return 0; return 0;
} }
const value = forVotes * 100n / totalVotes; return Number(forVotes * 100n / totalVotes);
return Math.floor(Number(value.toString()));
}, [proposal]); }, [proposal]);
const voteTarget = useMemo(() => { const voteTarget = useMemo(() => {
const againstVotes = proposal?.votes?.at(0)?._value ?? 0n; const againstVotes = proposal?.votes?.at(0)?._value ?? 0n;
const forVotes = proposal?.votes?.at(1)?._value ?? 0n; const forVotes = proposal?.votes?.at(1)?._value ?? 0n;
const totalVotes = againstVotes + forVotes;
const totalSupply = new DecimalBigNumber( const first = (5n * againstVotes + forVotes);
proposal?.pastTotalSupply?._value ?? 0n, const second = BigInt(Math.floor(Math.sqrt(Number(totalVotes))));
proposal?.pastTotalSupply?._decimals const bias = 3n * first + second;
); const denominator = totalVotes + bias;
const totalVotes = new DecimalBigNumber(
againstVotes + forVotes,
proposal?.pastTotalSupply?._decimals
);
if (totalSupply._value == 0n) { if (denominator === 0n) {
return 80; return 80;
} }
const value = Number(totalVotes / totalSupply); return Number(totalVotes * 100n / denominator);
const result = (5 - Math.sqrt(1 + 80/9 * (value - 0.1) )) / 4;
return Math.floor(result * 100);
}, [proposal]); }, [proposal]);
return ( return (
@ -231,7 +224,7 @@ const ProposalRow = ({ proposal, blockNumber, openProposal, chainId }) => {
<Chip <Chip
sx={{ width: "100px" }} sx={{ width: "100px" }}
label={convertStatusToLabel(proposal.state)} label={convertStatusToLabel(proposal.state)}
background={convertStatusToColor(proposal.state)} template={convertStatusToTemplate(proposal.state)}
/> />
</TableCell> </TableCell>
@ -290,7 +283,7 @@ const ProposalCard = ({ proposal, blockNumber, openProposal, chainId }) => {
<Chip <Chip
sx={{ width: "88px" }} sx={{ width: "88px" }}
label={convertStatusToLabel(proposal.state)} label={convertStatusToLabel(proposal.state)}
background={convertStatusToColor(proposal.state)} template={convertStatusToTemplate(proposal.state)}
/> />
</Box> </Box>
<Typography> <Typography>

View File

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

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 = "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 = "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) => {
const [isOpened, setIsOpened] = useState(false); const [isOpened, setIsOpened] = useState(false);
@ -118,7 +118,7 @@ export const CreateBondSteps = ({ nativeCurrency, ftsoSymbol, chainId, toInitial
}, [step, tokenAddress, capacity, initialPrice, debtBuffer, depositInterval, tuneInterval]); }, [step, tokenAddress, capacity, initialPrice, debtBuffer, depositInterval, tuneInterval]);
const possibleTokens = [ const possibleTokens = [
{ value: FTSO_DAI_LP_ADDRESSES[chainId], symbol: `${ftsoSymbol}-${reserveSymbol} LP`, label: `${ftsoSymbol}-${reserveSymbol} LP: ${shorten(FTSO_DAI_LP_ADDRESSES[chainId])}` }, { value: FTSO_DAI_LP_ADDRESSES[chainId], symbol: `${ftsoSymbol}-${nativeCurrency} LP`, label: `${ftsoSymbol}-${nativeCurrency} LP: ${shorten(FTSO_DAI_LP_ADDRESSES[chainId])}` },
{ value: RESERVE_ADDRESSES[chainId], symbol: reserveSymbol, label: `${reserveSymbol}: ${shorten(RESERVE_ADDRESSES[chainId])}` }, { value: RESERVE_ADDRESSES[chainId], symbol: reserveSymbol, label: `${reserveSymbol}: ${shorten(RESERVE_ADDRESSES[chainId])}` },
]; ];
@ -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={reserveSymbol} nativeCurrency={nativeCurrency}
ftsoSymbol={ftsoSymbol} ftsoSymbol={ftsoSymbol}
capacityInQuote={capacityInQuote} capacityInQuote={capacityInQuote}
setCapacityInQuote={createMode ? setCapacityInQuote : empty} setCapacityInQuote={createMode ? setCapacityInQuote : empty}
@ -296,7 +296,7 @@ const TokenAndBooleansArguments = ({
rightText={"False"} rightText={"False"}
setLeftValue={() => setCapacityInQuote(true)} setLeftValue={() => setCapacityInQuote(true)}
setRightValue={() => setCapacityInQuote(false)} setRightValue={() => setCapacityInQuote(false)}
tooltip={`Determines how the bond market capacity is measured. True = measured in _quoteToken, False = measured in ${ftsoSymbol}.`} tooltip={`Determines how the bond market capacity is measured. True = measured in ${nativeCurrency}, False = measured in ${ftsoSymbol}.`}
/> />
<BooleanTrigger <BooleanTrigger
value={fixedTerm} value={fixedTerm}

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 = "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 = "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) => {
const [isOpened, setIsOpened] = useState(false); const [isOpened, setIsOpened] = useState(false);

View File

@ -1,24 +1,18 @@
export const MY_PROPOSALS_PREFIX = "MY_PROPOSALS"; export const MY_PROPOSALS_PREFIX = "MY_PROPOSALS";
export const VOTED_PROPOSALS_PREFIX = "VOTED_PROPOSALS"; export const VOTED_PROPOSALS_PREFIX = "VOTED_PROPOSALS";
export const convertStatusToColor = (status) => { export const convertStatusToTemplate = (status) => {
switch (status) { switch (status) {
case 1:
return "#f2e370";
case 2:
return "#f06f73";
case 3:
return "#f06f73";
case 4:
return "#60c45b";
case 5:
return "#60c45b";
case 6:
return "#f06f73";
case 7: case 7:
return "#f2e370"; return 'darkGray';
case 2:
return 'warning';
case 4:
return 'success';
case 3:
return 'error';
default: default:
return "#a2b7ce"; return 'darkGray';
} }
} }

View File

@ -52,7 +52,7 @@ export const TotalDeposit = props => {
const _props = { const _props = {
...props, ...props,
label: "Total Deposit", label: "Total Deposit",
tooltip: `Total reserves of native coins, LP tokens, and other assets in the ghostDAO treasury backing the entire circulating supply of ${props.stnkSymbol}.`, tooltip: `The total stablecoin reserves 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, LP tokens, and other assets held by the ghostDAO treasury to support the value of each ${props.ftsoSymbol} in circulation.` tooltip: `The total amount of stablecoins 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

@ -138,7 +138,7 @@ const TokenInfo = ({ chainId, isMobileScreen }) => {
tokenName={ghstSymbol} tokenName={ghstSymbol}
balance={ghstBalance} balance={ghstBalance}
price={ghstPrice} price={ghstPrice}
description={`${ghstSymbol} is the governance token enabling pure Web3 cross-chain magic. 1 ${ghstSymbol} = 1 ${ftsoSymbol} x Current Index.`} description={`${ghstSymbol} enables ghostDAO to have on-chain governance and to be truly cross-chain. ${ghstSymbol} Price = ${ftsoSymbol} Price x Current Index.`}
/> />
<TokenTab <TokenTab
isMobileScreen={isMobileScreen} isMobileScreen={isMobileScreen}

View File

@ -96,7 +96,6 @@ export const useMinQuorum = (chainId) => {
export const useProposalThreshold = (chainId, name) => { export const useProposalThreshold = (chainId, name) => {
const decimals = getTokenDecimals(name); const decimals = getTokenDecimals(name);
const { proposalCount } = useProposalCount(chainId);
const { data } = useReadContract({ const { data } = useReadContract({
abi: GovernorStorageAbi, abi: GovernorStorageAbi,
@ -114,17 +113,13 @@ export const useProposalThreshold = (chainId, name) => {
chainId: chainId, chainId: chainId,
}); });
const lastIndex = proposalCount === 0n ? 0n : proposalCount - 1n;
const { proposalId } = useProposalDetailsAt(chainId, lastIndex, {
enabled: proposalCount !== 0n
});
const { state } = useProposalState(chainId, proposalId, {
enabled: proposalCount !== 0n && !!proposalId
});
let threshold = new DecimalBigNumber(data ?? 0n, decimals); let threshold = new DecimalBigNumber(data ?? 0n, decimals);
if (proposalCount !== 0n && state !== undefined && state < 2) { const { proposalCount } = useProposalCount(chainId);
const { proposalId } = useProposalDetailsAt(chainId, proposalCount === 0n ? 0n : proposalCount - 1n);
const { state } = useProposalState(chainId, proposalId);
if (state < 2) {
threshold = new DecimalBigNumber(activeProposedLock ?? 0n, decimals); threshold = new DecimalBigNumber(activeProposedLock ?? 0n, decimals);
} }
@ -340,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(index) ? searchedIndexes?.at(0)
: proposalsDetailsAt?.at(index)?.result?.at(0); : proposalsDetailsAt?.at(index)?.result?.at(0);
return { return {
@ -357,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(index) ? searchedIndexes?.at(0)
: proposalsDetailsAt?.at(index)?.result?.at(0); : proposalsDetailsAt?.at(index)?.result?.at(0);
return { return {
@ -374,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(index) ? searchedIndexes?.at(0)
: proposalsDetailsAt?.at(index)?.result?.at(0); : proposalsDetailsAt?.at(index)?.result?.at(0);
return { return {
@ -391,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(index) ? searchedIndexes?.at(0)
: proposalsDetailsAt?.at(index)?.result?.at(0); : proposalsDetailsAt?.at(index)?.result?.at(0);
return { return {
@ -406,8 +401,8 @@ export const useProposals = (chainId, depth, searchedIndexes) => {
}); });
const { data: proposalQuorums } = useReadContracts({ const { data: proposalQuorums } = useReadContracts({
contracts: proposalSnapshots?.map((proposal, index) => { contracts: indexes?.map(index => {
const timepoint = proposal?.result; const timepoint = proposalSnapshots?.at(index)?.result;
return { return {
abi: GovernorAbi, abi: GovernorAbi,
address: GHOST_GOVERNANCE_ADDRESSES[chainId], address: GHOST_GOVERNANCE_ADDRESSES[chainId],
@ -420,8 +415,8 @@ export const useProposals = (chainId, depth, searchedIndexes) => {
}); });
const { data: pastTotalSupplies } = useReadContracts({ const { data: pastTotalSupplies } = useReadContracts({
contracts: proposalSnapshots?.map((proposal, index) => { contracts: indexes?.map(index => {
const timepoint = proposal?.result; const timepoint = proposalSnapshots?.at(index)?.result;
return { return {
abi: ghstAbi, abi: ghstAbi,
address: ghstAddress, address: ghstAddress,
@ -436,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(index) ? searchedIndexes?.at(0)
: proposalsDetailsAt?.at(index)?.result?.at(0); : proposalsDetailsAt?.at(index)?.result?.at(0);
return { return {
@ -453,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(index) ? searchedIndexes?.at(0)
: proposalsDetailsAt?.at(index)?.result?.at(0); : proposalsDetailsAt?.at(index)?.result?.at(0);
if (proposalId) { if (proposalId) {
@ -469,10 +464,10 @@ export const useProposals = (chainId, depth, searchedIndexes) => {
proposer: proposalProposer?.at(index)?.result, proposer: proposalProposer?.at(index)?.result,
details: proposalsDetailsAt?.at(index)?.result, details: proposalsDetailsAt?.at(index)?.result,
deadline: proposalDeadlines?.at(index)?.result ?? 0n, deadline: proposalDeadlines?.at(index)?.result ?? 0n,
snapshot: proposalSnapshots?.at(index)?.result ?? 0n,
state: proposalStates?.at(index)?.result ?? 0, state: proposalStates?.at(index)?.result ?? 0,
pastTotalSupply: new DecimalBigNumber(pastTotalSupplies?.at(index)?.result ?? 0n, decimals), pastTotalSupply: new DecimalBigNumber(pastTotalSupplies?.at(index)?.result ?? 0n, decimals),
quorum: new DecimalBigNumber(proposalQuorums?.at(index)?.result ?? 0n, decimals), quorum: new DecimalBigNumber(proposalQuorums?.at(index)?.result ?? 0n, decimals),
snapshot: new DecimalBigNumber(proposalSnapshots?.at(index)?.result ?? 0n, decimals),
votes: proposalVotes?.at(index)?.result?.map( votes: proposalVotes?.at(index)?.result?.map(
vote => new DecimalBigNumber(vote ?? 0n, decimals), vote => new DecimalBigNumber(vote ?? 0n, decimals),
), ),