284 lines
9.6 KiB
JavaScript
284 lines
9.6 KiB
JavaScript
import { useRef, useMemo } from "react";
|
|
import { Box, Typography, Link, TableCell, TableRow, useTheme } from "@mui/material";
|
|
import { decodeFunctionData } from 'viem';
|
|
|
|
import { StyledInputBase } from "../../../../components/Swap/SwapCard";
|
|
import { TertiaryButton } from "../../../../components/Button";
|
|
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 { config } from "../../../../config";
|
|
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";
|
|
|
|
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: "Audit Reserves" },
|
|
{ value: "setAdjustment", label: "Change APY" },
|
|
{ value: "createBond", label: "Create Bond" },
|
|
];
|
|
|
|
const allAbis = [TreasuryAbi, DistributorAbi, DepositoryAbi];
|
|
|
|
const identifyAction = (calldata) => {
|
|
let decoded = { functionName: "Unknown", args: [] };
|
|
for (const abi of allAbis) {
|
|
try {
|
|
decoded = decodeFunctionData({
|
|
abi: abi,
|
|
data: calldata,
|
|
});
|
|
return decoded;
|
|
} catch (err) {
|
|
continue;
|
|
}
|
|
}
|
|
return decoded;
|
|
}
|
|
|
|
export const parseFunctionCalldata = (metadata, index, chainId, nativeCoin, removeCalldata) => {
|
|
const { label, calldata, target, value } = metadata;
|
|
const { functionName, args } = identifyAction(calldata);
|
|
|
|
const remove = () => removeCalldata(index);
|
|
|
|
console.log(`function arguments for ${label}: ${args}`);
|
|
|
|
switch (functionName) {
|
|
case "auditReserves":
|
|
return <AuditReservesParsed
|
|
isTable
|
|
key={index}
|
|
label={label}
|
|
chainId={chainId}
|
|
remove={remove}
|
|
nativeCoin={nativeCoin}
|
|
value={value}
|
|
target={target}
|
|
id={index}
|
|
/>;
|
|
case "setAdjustment":
|
|
return <SetAdjustmentParsed
|
|
isTable
|
|
args={args}
|
|
key={index}
|
|
label={label}
|
|
chainId={chainId}
|
|
remove={remove}
|
|
nativeCoin={nativeCoin}
|
|
value={value}
|
|
target={target}
|
|
id={index}
|
|
/>;
|
|
case "create":
|
|
return <CreateBondParsed
|
|
isTable
|
|
args={args}
|
|
key={index}
|
|
label={label}
|
|
chainId={chainId}
|
|
remove={remove}
|
|
nativeCoin={nativeCoin}
|
|
value={value}
|
|
target={target}
|
|
id={index}
|
|
/>;
|
|
default:
|
|
return <ParsedCell
|
|
isTable
|
|
key={index}
|
|
label={label}
|
|
remove={remove}
|
|
nativeCoin={nativeCoin}
|
|
value={value}
|
|
target={target}
|
|
id={index}
|
|
/>;
|
|
}
|
|
}
|
|
|
|
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, chainId) => {
|
|
switch (functionName) {
|
|
case "auditReserves":
|
|
return prepareAuditReservesCalldata(chainId);
|
|
case "setAdjustment":
|
|
return prepareSetAdjustmentCalldata(chainId);
|
|
case "createBond":
|
|
return prepareCreateBondCalldata(chainId);
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
|
|
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 (
|
|
<Box
|
|
onClick={() => setSelected()}
|
|
display="flex"
|
|
justifyContent="center"
|
|
alignItems="center"
|
|
sx={{
|
|
cursor: "pointer",
|
|
borderRadius: left ? "12px 0 0 12px" : "0 12px 12px 0",
|
|
flex: 1,
|
|
border: "2px solid #fff",
|
|
borderLeft: left ? "2px solid #fff" : "none",
|
|
borderRight: left ? "none" : "2px solid #fff",
|
|
background: `${isSelected ? "#fff" : theme.colors.gray[600] }`
|
|
}}
|
|
>
|
|
<Typography
|
|
color={isSelected ? theme.colors.gray[600] : "#fff"}
|
|
align="center"
|
|
>
|
|
{text}
|
|
</Typography>
|
|
</Box>
|
|
)
|
|
}
|
|
|
|
export const ArgumentsWrapper = ({ label, tooltip, children }) => {
|
|
return (
|
|
<Box sx={{ marginBottom: "18px" }}>
|
|
<Box sx={{ marginLeft: "5px", marginBottom: "5px" }} display="flex" flexDirection="row" alignItems="center">
|
|
<Typography>{label}</Typography>
|
|
<InfoTooltip message={tooltip} />
|
|
</Box>
|
|
{children}
|
|
</Box>
|
|
)
|
|
}
|
|
|
|
export const BooleanTrigger = ({ value, label, tooltip, leftText, rightText, setLeftValue, setRightValue }) => {
|
|
return (
|
|
<ArgumentsWrapper label={label} tooltip={tooltip}>
|
|
<Box display="flex" width="100%" height="40px">
|
|
<BooleanValue setSelected={setLeftValue} left isSelected={value} text={leftText} />
|
|
<BooleanValue setSelected={setRightValue} isSelected={!value} text={rightText} />
|
|
</Box>
|
|
</ArgumentsWrapper>
|
|
)
|
|
}
|
|
|
|
export const ArgumentInput = ({
|
|
endString,
|
|
label,
|
|
tooltip,
|
|
value,
|
|
setValue,
|
|
disabled,
|
|
inputType = "number",
|
|
placeholder = "0",
|
|
maxWidth = "100%"
|
|
}) => {
|
|
const theme = useTheme();
|
|
const ref = useRef(null);
|
|
|
|
return (
|
|
<Box sx={{ marginBottom: "15px" }}>
|
|
<Box sx={{ marginLeft: "5px", marginBottom: "5px" }} display="flex" flexDirection="row" alignItems="center">
|
|
<Typography>{label}</Typography>
|
|
<InfoTooltip message={tooltip} />
|
|
</Box>
|
|
<Box
|
|
display="flex"
|
|
flexDirection="column"
|
|
maxWidth={maxWidth}
|
|
sx={{ backgroundColor: theme.colors.gray[750] }}
|
|
borderRadius="12px"
|
|
padding="6px"
|
|
onClick={() => {
|
|
ref.current && ref.current.focus();
|
|
}}
|
|
>
|
|
<Box width="100%" display="flex" flexDirection="row" justifyContent="space-between" alignItems="center">
|
|
<StyledInputBase
|
|
disabled={disabled}
|
|
placeholder={placeholder}
|
|
type={inputType}
|
|
fontSize="20px"
|
|
value={value}
|
|
onChange={(e) => setValue(e.target.value)}
|
|
sx={{ flex: 1 }}
|
|
/>
|
|
{endString && (
|
|
<Box sx={{ paddingRight: "10px", color: theme.colors.gray[500] }} fontSize="12px" lineHeight="15px">
|
|
{endString}
|
|
</Box>
|
|
)}
|
|
</Box>
|
|
</Box>
|
|
</Box>
|
|
)
|
|
}
|
|
|
|
export const ParsedCell = (props) => {
|
|
const etherscanLink = useMemo(() => {
|
|
const client = config.getClient();
|
|
let url = client?.chain?.blockExplorers?.default?.url;
|
|
if (url) {
|
|
url = url + `/address/${props.target}`;
|
|
}
|
|
return url;
|
|
}, [props]);
|
|
|
|
return (
|
|
<TableRow id={props.id + `--proposalFunction`} data-testid={props.id + `--proposalFunction`}>
|
|
<TableCell align="center" style={{ padding: "8px 0" }}>
|
|
<Typography>{props.label}</Typography>
|
|
</TableCell>
|
|
|
|
<TableCell align="center" style={{ padding: "8px 0" }}>
|
|
<Link href={etherscanLink} target="_blank" rel="noopener noreferrer">
|
|
<Typography>{shorten(props.target)}</Typography>
|
|
</Link>
|
|
</TableCell>
|
|
|
|
<TableCell align="center" style={{ padding: "8px 0" }}>
|
|
<Typography>{formatCurrency(props.value, 2, props.nativeCoin)}</Typography>
|
|
</TableCell>
|
|
|
|
<TableCell>
|
|
<div style={{ display: 'flex', gap: '8px' }}>
|
|
{props.args && <TertiaryButton fullWidth onClick={() => props.setIsOpened(!props.isOpened)}>View</TertiaryButton>}
|
|
{props.remove && <TertiaryButton fullWidth onClick={() => props.remove()}>Delete</TertiaryButton>}
|
|
</div>
|
|
</TableCell>
|
|
</TableRow>
|
|
)
|
|
}
|