diff --git a/apps/hyperdrive-trading/src/ui/hyperdrive/getRemainingTimeLabel.ts b/apps/hyperdrive-trading/src/ui/hyperdrive/getRemainingTimeLabel.ts index 13162e3f1..a96a12f00 100644 --- a/apps/hyperdrive-trading/src/ui/hyperdrive/getRemainingTimeLabel.ts +++ b/apps/hyperdrive-trading/src/ui/hyperdrive/getRemainingTimeLabel.ts @@ -33,7 +33,8 @@ export function getRemainingTimeLabel({ const suffix = showLeftSuffix ? " left" : ""; if (days > 0) { - return `${days} days${suffix}`; + const dayLabel = days === 1 ? "day" : "days"; + return `${days} ${dayLabel}${suffix}`; } // Condensed only needed when showing both hours and minutes. diff --git a/apps/hyperdrive-trading/src/ui/hyperdrive/longs/CloseLongForm/CloseLongForm.tsx b/apps/hyperdrive-trading/src/ui/hyperdrive/longs/CloseLongForm/CloseLongForm.tsx index 49070f58a..c30d1cd8f 100644 --- a/apps/hyperdrive-trading/src/ui/hyperdrive/longs/CloseLongForm/CloseLongForm.tsx +++ b/apps/hyperdrive-trading/src/ui/hyperdrive/longs/CloseLongForm/CloseLongForm.tsx @@ -232,6 +232,7 @@ export function CloseLongForm({ chainId={hyperdrive.chainId} maturity={long.maturity} statusCellClassName="mb-0 text-h3 w-full text-gray-50 font-bold" + showLeftSuffix={false} /> } /> diff --git a/apps/hyperdrive-trading/src/ui/hyperdrive/longs/OpenLongsTable/StatusCell.tsx b/apps/hyperdrive-trading/src/ui/hyperdrive/longs/OpenLongsTable/StatusCell.tsx index 6aaa8d29c..401a51340 100644 --- a/apps/hyperdrive-trading/src/ui/hyperdrive/longs/OpenLongsTable/StatusCell.tsx +++ b/apps/hyperdrive-trading/src/ui/hyperdrive/longs/OpenLongsTable/StatusCell.tsx @@ -8,10 +8,12 @@ export function StatusCell({ chainId, maturity, statusCellClassName, + showLeftSuffix, }: { chainId: number; maturity: bigint; statusCellClassName?: string; + showLeftSuffix?: boolean; }): ReactElement { const { data: currentBlock } = useBlock({ chainId }); const isTermComplete = maturity < (currentBlock?.timestamp || 0n); @@ -19,6 +21,7 @@ export function StatusCell({ const remainingTime = getRemainingTimeLabel({ maturitySeconds: Number(maturity), condensed: true, + showLeftSuffix, }); return ( diff --git a/apps/hyperdrive-trading/src/ui/hyperdrive/shorts/CloseShortForm/CloseShortForm.tsx b/apps/hyperdrive-trading/src/ui/hyperdrive/shorts/CloseShortForm/CloseShortForm.tsx index 37ff1d88e..f7d38064e 100644 --- a/apps/hyperdrive-trading/src/ui/hyperdrive/shorts/CloseShortForm/CloseShortForm.tsx +++ b/apps/hyperdrive-trading/src/ui/hyperdrive/shorts/CloseShortForm/CloseShortForm.tsx @@ -1,3 +1,4 @@ +import { fixed } from "@delvtech/fixed-point-wasm"; import { appConfig, findBaseToken, @@ -5,21 +6,27 @@ import { HyperdriveConfig, } from "@delvtech/hyperdrive-appconfig"; import { adjustAmountByPercentage, OpenShort } from "@delvtech/hyperdrive-viem"; -import { ConnectButton } from "@rainbow-me/rainbowkit"; import { MouseEvent, ReactElement } from "react"; -import { LabelValue } from "src/ui/base/components/LabelValue"; +import { isTestnetChain } from "src/chains/isTestnetChain"; +import { ConnectWalletButton } from "src/ui/base/components/ConnectWallet"; import { LoadingButton } from "src/ui/base/components/LoadingButton"; +import { PrimaryStat } from "src/ui/base/components/PrimaryStat"; import { formatBalance } from "src/ui/base/formatting/formatBalance"; import { useActiveItem } from "src/ui/base/hooks/useActiveItem"; import { useNumericInput } from "src/ui/base/hooks/useNumericInput"; +import { SwitchNetworksButton } from "src/ui/chains/SwitchChainButton/SwitchChainButton"; +import { InvalidTransactionButton } from "src/ui/hyperdrive/InvalidTransactionButton"; +import { StatusCell } from "src/ui/hyperdrive/longs/OpenLongsTable/StatusCell"; import { useCloseShort } from "src/ui/hyperdrive/shorts/hooks/useCloseShort"; import { usePreviewCloseShort } from "src/ui/hyperdrive/shorts/hooks/usePreviewCloseShort"; -import { TransactionViewOld } from "src/ui/hyperdrive/TransactionView"; +import { TransactionView } from "src/ui/hyperdrive/TransactionView"; import { useTokenBalance } from "src/ui/token/hooks/useTokenBalance"; -import { TokenInput } from "src/ui/token/TokenInput"; -import { TokenChoice, TokenPicker } from "src/ui/token/TokenPicker"; +import { useTokenFiatPrice } from "src/ui/token/hooks/useTokenFiatPrice"; +import { TokenInputTwo } from "src/ui/token/TokenInputTwo"; +import { TokenChoice } from "src/ui/token/TokenPicker"; +import { TokenPickerTwo } from "src/ui/token/TokenPickerTwo"; import { formatUnits, parseUnits } from "viem"; -import { useAccount } from "wagmi"; +import { useAccount, useChainId } from "wagmi"; interface CloseShortFormProps { hyperdrive: HyperdriveConfig; @@ -33,6 +40,7 @@ export function CloseShortForm({ short, }: CloseShortFormProps): ReactElement { const { address: account } = useAccount(); + const connectedChainId = useChainId(); const defaultItems = []; const baseToken = findBaseToken({ hyperdriveChainId: hyperdrive.chainId, @@ -72,6 +80,11 @@ export function CloseShortForm({ decimals: hyperdrive.decimals, }); + const { fiatPrice: activeWithdrawTokenPrice } = useTokenFiatPrice({ + tokenAddress: activeWithdrawToken.address, + chainId: activeWithdrawToken.chainId, + }); + // You can't close an amount that's larger than the position size const isAmountLargerThanPositionSize = !!( amountAsBigInt && amountAsBigInt > short.bondAmount @@ -130,60 +143,92 @@ export function CloseShortForm({ } return ( - setAmount(newAmount)} - /> - } - setting={ - withdrawTokenChoices.length > 1 ? ( - setActiveWithdrawToken(tokenAddress)} - label="Choose withdrawal asset" - /> - ) : undefined - } - transactionPreview={ -
- - {amountOut - ? `${formatBalance({ - balance: amountOut, +
+ setAmount(newAmount)} + bottomRightElement={ +
+ {short + ? `Balance: ${formatBalance({ + balance: short.bondAmount, decimals: hyperdrive.decimals, places: baseToken?.places, })}` - : "0"}{" "} - {activeWithdrawToken.symbol} -

+ : undefined} +
} /> - - + setActiveWithdrawToken(tokenAddress) + } + /> + } + value={ + amountOut ? fixed(amountOut, hyperdrive.decimals).toString() : "0" + } + maxValue={ + short ? formatUnits(short.bondAmount, hyperdrive.decimals) : "" + } + disabled + bottomLeftElement={ + // Defillama fetches the token price via {chain}:{tokenAddress}. Since the token address differs on testnet, price display is disabled there. + !isTestnetChain(hyperdrive.chainId) ? ( + + ) : null + } + onChange={(newAmount) => setAmount(newAmount)} + /> +
+ } + primaryStats={ +
+ + } + /> +
+ +
{flatPlusCurveFee ? `${formatBalance({ balance: flatPlusCurveFee, @@ -192,20 +237,31 @@ export function CloseShortForm({ places: 6, })}` : "0"}{" "} - {activeWithdrawToken.symbol} -

+
} + valueUnit={activeWithdrawToken.symbol} + valueContainerClassName="flex flex-row gap-2 items-end" />
} - disclaimer={ - !!amountAsBigInt && isAmountLargerThanPositionSize ? ( -

Insufficient balance

- ) : undefined - } actionButton={(() => { if (!account) { - return ; + return ; + } + if (connectedChainId !== hyperdrive.chainId) { + return ( + + ); + } + if (!!amountAsBigInt && isAmountLargerThanPositionSize) { + return ( + + Insufficient balance + + ); } if (closeShortStatus === "loading") { return ; diff --git a/apps/hyperdrive-trading/src/ui/hyperdrive/shorts/CloseShortModalButton/CloseShortModalButton.tsx b/apps/hyperdrive-trading/src/ui/hyperdrive/shorts/CloseShortModalButton/CloseShortModalButton.tsx index eeef1a00a..38a2e1a1a 100644 --- a/apps/hyperdrive-trading/src/ui/hyperdrive/shorts/CloseShortModalButton/CloseShortModalButton.tsx +++ b/apps/hyperdrive-trading/src/ui/hyperdrive/shorts/CloseShortModalButton/CloseShortModalButton.tsx @@ -6,14 +6,9 @@ import { findToken, } from "@delvtech/hyperdrive-appconfig"; import { OpenShort } from "@delvtech/hyperdrive-viem"; -import { CheckIcon, XMarkIcon } from "@heroicons/react/24/solid"; -import classNames from "classnames"; import { ReactElement } from "react"; import { Modal } from "src/ui/base/components/Modal/Modal"; import { ModalHeader } from "src/ui/base/components/Modal/ModalHeader"; -import { Stat } from "src/ui/base/components/Stat"; -import { formatDate } from "src/ui/base/formatting/formatDate"; -import { getRemainingTimeLabel } from "src/ui/hyperdrive/getRemainingTimeLabel"; import { CloseShortForm } from "src/ui/hyperdrive/shorts/CloseShortForm/CloseShortForm"; export interface CloseShortModalButtonProps { @@ -40,71 +35,22 @@ export function CloseShortModalButton({ ? getSubHeadingLabel(baseToken, hyperdrive, sharesToken) : ""; - const maturityMilliseconds = Number(short.maturity * 1000n); - const isMature = Date.now() > maturityMilliseconds; - function closeModal() { - (document.getElementById(modalId) as HTMLDialogElement)?.close(); - } - return ( -
-
- - {isMature ? : undefined} - {getRemainingTimeLabel({ - maturitySeconds: Number(short.maturity), - condensed: true, - })} - - } - /> -
-
- -
-
- + } modalId={modalId} modalContent={ -
- - { - // preventDefault since we don't want to close the modal while the - // tx is temporarily pending the user's signature in their wallet. - e.preventDefault(); - }} - /> -
+ { + // preventDefault since we don't want to close the modal while the + // tx is temporarily pending the user's signature in their wallet. + e.preventDefault(); + }} + /> } /> );