Compare commits

...

4 Commits

Author SHA1 Message Date
eef0031a4a
ability to customize destination address for DEX
Signed-off-by: Uncle Fatso <uncle.fatso@ghostchain.io>
2026-03-07 13:54:41 +03:00
de0000d6d5
more governance functions added
Signed-off-by: Uncle Fatso <uncle.fatso@ghostchain.io>
2026-03-05 15:40:37 +03:00
612573d433
change UI representation of bond prices; should be correct formula
Signed-off-by: Uncle Fatso <uncle.fatso@ghostchain.io>
2026-03-05 13:39:34 +03:00
66238837c0
small UI fixes
Signed-off-by: Uncle Fatso <uncle.fatso@ghostchain.io>
2026-03-05 13:38:13 +03:00
11 changed files with 294 additions and 84 deletions

View File

@ -1,7 +1,7 @@
{ {
"name": "ghost-dao-interface", "name": "ghost-dao-interface",
"private": true, "private": true,
"version": "0.5.39", "version": "0.5.43",
"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

@ -1,5 +1,5 @@
import { CheckBoxOutlineBlank, CheckBoxOutlined } from "@mui/icons-material"; import { CheckBoxOutlineBlank, CheckBoxOutlined } from "@mui/icons-material";
import { Box, Checkbox, FormControlLabel } from "@mui/material"; import { Box, Checkbox, FormControlLabel, useMediaQuery } from "@mui/material";
import { useState, useMemo } from "react"; import { useState, useMemo } from "react";
import { useLocation } from "react-router-dom"; import { useLocation } from "react-router-dom";
@ -32,6 +32,8 @@ const BondInputArea = ({
address, address,
connect connect
}) => { }) => {
const isSemiSmallScreen = useMediaQuery("(max-width: 480px)");
const isVerySmallScreen = useMediaQuery("(max-width: 379px)");
const { pathname } = useLocation(); const { pathname } = useLocation();
const { currentIndex } = useCurrentIndex(chainId); const { currentIndex } = useCurrentIndex(chainId);
@ -95,7 +97,7 @@ const BondInputArea = ({
UpperSwapCard={ UpperSwapCard={
<SwapCard <SwapCard
maxWidth="476px" maxWidth="476px"
inputWidth="280px" inputWidth={isVerySmallScreen ? "100px" : isSemiSmallScreen ? "180px" : "250px"}
id="from" id="from"
token={<TokenStack tokens={bond.quoteToken.icons} sx={{ fontSize: "21px" }} />} token={<TokenStack tokens={bond.quoteToken.icons} sx={{ fontSize: "21px" }} />}
tokenName={bond.quoteToken.name} tokenName={bond.quoteToken.name}
@ -110,7 +112,7 @@ const BondInputArea = ({
LowerSwapCard={ LowerSwapCard={
<SwapCard <SwapCard
maxWidth="476px" maxWidth="476px"
inputWidth="280px" inputWidth={isVerySmallScreen ? "100px" : isSemiSmallScreen ? "180px" : "250px"}
id="to" id="to"
token={<TokenStack tokens={bond.baseToken.icons} sx={{ fontSize: "21px" }} />} token={<TokenStack tokens={bond.baseToken.icons} sx={{ fontSize: "21px" }} />}
tokenName={bond.baseToken.name} tokenName={bond.baseToken.name}

View File

@ -55,6 +55,8 @@ const Dex = ({ chainId, address, connect }) => {
const [secondsToWait, setSecondsToWait] = useState(localStorage.getItem("dex-deadline") || "60"); const [secondsToWait, setSecondsToWait] = useState(localStorage.getItem("dex-deadline") || "60");
const [slippage, setSlippage] = useState(localStorage.getItem("dex-slippage") || "5"); const [slippage, setSlippage] = useState(localStorage.getItem("dex-slippage") || "5");
const [formatDecimals, setFormatDecimals] = useState(localStorage.getItem("dex-decimals") || "5"); const [formatDecimals, setFormatDecimals] = useState(localStorage.getItem("dex-decimals") || "5");
const [actualDestinationAddress, setActualDestinationAddress] = useState(localStorage.getItem("dex-destination"));
const [destinationAddress, setDestinationAddress] = useState(actualDestinationAddress);
const [tokenAddressTop, setTokenAddressTop] = useState(RESERVE_ADDRESSES[chainId]); const [tokenAddressTop, setTokenAddressTop] = useState(RESERVE_ADDRESSES[chainId]);
const [tokenAddressBottom, setTokenAddressBottom] = useState(FTSO_ADDRESSES[chainId]); const [tokenAddressBottom, setTokenAddressBottom] = useState(FTSO_ADDRESSES[chainId]);
@ -162,6 +164,24 @@ const Dex = ({ chainId, address, connect }) => {
} }
} }
const setDestinationAddressInner = (value) => {
const cleanedValue = value.trim();
const isEvmAddress = /^0x[a-fA-F0-9]{40}$/.test(cleanedValue);
if (isEvmAddress) {
localStorage.setItem("dex-destination", value);
setActualDestinationAddress(value);
} else if (!isEvmAddress && actualDestinationAddress) {
localStorage.removeItem("dex-destination");
setActualDestinationAddress(undefined);
}
setDestinationAddress(value);
}
const handleCloseSetting = () => {
setDestinationAddress(undefined);
handleSettingsOpen(false);
}
return ( return (
<Box height="calc(100vh - 43px)"> <Box height="calc(100vh - 43px)">
<Helmet> <Helmet>
@ -203,7 +223,7 @@ const Dex = ({ chainId, address, connect }) => {
minHeight="200px" minHeight="200px"
open={settingsOpen} open={settingsOpen}
headerText={"Settings"} headerText={"Settings"}
onClose={() => handleSettingsOpen(false)} onClose={() => handleCloseSetting()}
> >
<Box> <Box>
<InputLabel htmlFor="slippage">Slippage</InputLabel> <InputLabel htmlFor="slippage">Slippage</InputLabel>
@ -267,6 +287,31 @@ const Dex = ({ chainId, address, connect }) => {
</Typography> </Typography>
</Box> </Box>
</Box> </Box>
<Box mt="32px">
<InputLabel htmlFor="recipient">
{`${actualDestinationAddress ? "Custom" : "Default"} destination address`}
</InputLabel>
<Box mt="8px">
<FormControl variant="outlined" color="primary" fullWidth>
<OutlinedInput
inputProps={{ "data-testid": "decimals-to-wait" }}
type="text"
id="destination-to-wait"
value={destinationAddress
? destinationAddress
: actualDestinationAddress ?? address
}
onChange={event => setDestinationAddressInner(event.currentTarget.value)}
/>
</FormControl>
</Box>
<Box mt="8px">
<Typography variant="body2" color="textSecondary">
Recipient address of swapped assets and liquidity tokens
</Typography>
</Box>
</Box>
</Modal> </Modal>
<TokenModal <TokenModal
@ -322,6 +367,7 @@ const Dex = ({ chainId, address, connect }) => {
dexAddresses={dexAddresses} dexAddresses={dexAddresses}
connect={connect} connect={connect}
slippage={slippage} slippage={slippage}
destination={actualDestinationAddress ? actualDestinationAddress : address}
secondsToWait={secondsToWait} secondsToWait={secondsToWait}
setTopTokenListOpen={setTopTokenListOpen} setTopTokenListOpen={setTopTokenListOpen}
setBottomTokenListOpen={setBottomTokenListOpen} setBottomTokenListOpen={setBottomTokenListOpen}
@ -338,6 +384,7 @@ const Dex = ({ chainId, address, connect }) => {
dexAddresses={dexAddresses} dexAddresses={dexAddresses}
connect={connect} connect={connect}
slippage={slippage} slippage={slippage}
destination={actualDestinationAddress ? actualDestinationAddress : address}
secondsToWait={secondsToWait} secondsToWait={secondsToWait}
setTopTokenListOpen={setTopTokenListOpen} setTopTokenListOpen={setTopTokenListOpen}
setBottomTokenListOpen={setBottomTokenListOpen} setBottomTokenListOpen={setBottomTokenListOpen}

View File

@ -23,6 +23,7 @@ const PoolContainer = ({
dexAddresses, dexAddresses,
connect, connect,
slippage, slippage,
destination,
secondsToWait, secondsToWait,
setTopTokenListOpen, setTopTokenListOpen,
setBottomTokenListOpen, setBottomTokenListOpen,
@ -129,8 +130,6 @@ const PoolContainer = ({
setIsPending(true); setIsPending(true);
const deadline = Math.floor(Date.now() / 1000) + secondsToWait; const deadline = Math.floor(Date.now() / 1000) + secondsToWait;
const destination = address;
const shares = 100000; const shares = 100000;
const one = BigInt(shares * 100); const one = BigInt(shares * 100);
const floatSlippage = slippage === "" ? 0 : parseFloat(slippage); const floatSlippage = slippage === "" ? 0 : parseFloat(slippage);

View File

@ -27,6 +27,7 @@ const SwapContainer = ({
setTopTokenListOpen, setTopTokenListOpen,
setBottomTokenListOpen, setBottomTokenListOpen,
slippage, slippage,
destination,
secondsToWait, secondsToWait,
setIsSwap, setIsSwap,
formatDecimals formatDecimals
@ -108,8 +109,6 @@ const SwapContainer = ({
setIsPending(true); setIsPending(true);
const deadline = Math.floor(Date.now() / 1000) + secondsToWait; const deadline = Math.floor(Date.now() / 1000) + secondsToWait;
const destination = address;
const shares = 100000; const shares = 100000;
const one = BigInt(shares * 100); const one = BigInt(shares * 100);
const floatSlippage = slippage === "" ? 0 : parseFloat(slippage); const floatSlippage = slippage === "" ? 0 : parseFloat(slippage);

View File

@ -222,7 +222,7 @@ const IntervalsArguments = ({
/> />
<ArgumentInput <ArgumentInput
endString="seconds" endString="seconds"
label="_intervals[0]" label="_intervals[1]"
value={tuneInterval ?? ""} value={tuneInterval ?? ""}
setValue={setTuneInterval} setValue={setTuneInterval}
tooltip="Time in seconds between bond price tuning events that evaluate actual vs. expected bond sales, adjusting how aggressively price decays in the next interval." tooltip="Time in seconds between bond price tuning events that evaluate actual vs. expected bond sales, adjusting how aggressively price decays in the next interval."

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,16 +18,20 @@ 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."
export const allPossibleFunctions = [ 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;
} }

View File

@ -13,7 +13,7 @@ import { abi as BondAbi } from "../../abi/GhostBondDepository.json";
import { abi as TreasuryAbi } from "../../abi/GhostTreasury.json"; import { abi as TreasuryAbi } from "../../abi/GhostTreasury.json";
import { abi as BondingCalculatorAbi } from "../../abi/GhostBondingCalculator.json"; import { abi as BondingCalculatorAbi } from "../../abi/GhostBondingCalculator.json";
import { useReservePrice } from "../prices"; import { useReservePrice, useFtsoPrice } from "../prices";
import { useOrinalCoefficient } from "../treasury"; import { useOrinalCoefficient } from "../treasury";
import { useTokenSymbol, useTokenSymbols } from "../tokens"; import { useTokenSymbol, useTokenSymbols } from "../tokens";
import { getTokenAddress, getTokenIcons, getBondNameDisplayName, getTokenPurchaseLink } from "../helpers"; import { getTokenAddress, getTokenIcons, getBondNameDisplayName, getTokenPurchaseLink } from "../helpers";
@ -21,6 +21,7 @@ import { DecimalBigNumber } from "../../helpers/DecimalBigNumber";
import { shorten } from "../../helpers"; import { shorten } from "../../helpers";
export const useLiveBonds = (chainId) => { export const useLiveBonds = (chainId) => {
const ftsoPrice = useFtsoPrice(chainId);
const baseTokenPerUsd = useReservePrice(chainId); const baseTokenPerUsd = useReservePrice(chainId);
const originalCoefficient = useOrinalCoefficient(chainId); const originalCoefficient = useOrinalCoefficient(chainId);
@ -128,14 +129,11 @@ export const useLiveBonds = (chainId) => {
const quoteTokenSymbol = quoteTokenSymbols?.at(index).result ? quoteTokenSymbols.at(index).result : ""; const quoteTokenSymbol = quoteTokenSymbols?.at(index).result ? quoteTokenSymbols.at(index).result : "";
const quoteTokenPerBaseToken = new DecimalBigNumber(marketPrice, 9); const quoteTokenPerBaseToken = new DecimalBigNumber(marketPrice, 9);
let priceInUsd = baseTokenPerUsd.mul(quoteTokenPerBaseToken); const priceInUsd = quoteTokenPerBaseToken.mul(baseTokenPerUsd).mul(quoteTokenPerUsd).mul(markdown).div(originalCoefficient);
if (Number(markdown?.toString() ?? "1") !== 1) {
priceInUsd = priceInUsd.div(originalCoefficient)
}
const discount = baseTokenPerUsd._value > 0n const discount = baseTokenPerUsd._value > 0n
? baseTokenPerUsd.sub(priceInUsd).div(baseTokenPerUsd) ? ftsoPrice.sub(priceInUsd).div(ftsoPrice)
: new DecimalBigNumber("0", baseTokenPerUsd._decimals); : new DecimalBigNumber("0", ftsoPrice._decimals);
const capacityInBaseToken = capacityInQuote const capacityInBaseToken = capacityInQuote
? new DecimalBigNumber(marketPrice > 0n ? marketCapacity / marketPrice : 0n, 9) ? new DecimalBigNumber(marketPrice > 0n ? marketCapacity / marketPrice : 0n, 9)
@ -177,7 +175,7 @@ export const useLiveBonds = (chainId) => {
price: { price: {
inUsd: priceInUsd, inUsd: priceInUsd,
inBaseToken: quoteTokenPerBaseToken, inBaseToken: quoteTokenPerBaseToken,
marketPriceInUsd: baseTokenPerUsd marketPriceInUsd: ftsoPrice
}, },
capacity: { capacity: {
inBaseToken: capacityInBaseToken, inBaseToken: capacityInBaseToken,