Merge branch 'main' into repay-modal
This commit is contained in:
commit
95df906a76
|
@ -15,6 +15,7 @@ import { useWallet } from '@solana/wallet-adapter-react'
|
|||
import mangoStore from '@store/mangoStore'
|
||||
import Decimal from 'decimal.js'
|
||||
import useLocalStorageState from 'hooks/useLocalStorageState'
|
||||
import useSolBalance from 'hooks/useSolBalance'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import Image from 'next/image'
|
||||
import {
|
||||
|
@ -65,26 +66,23 @@ const UserSetup = ({ onClose }: { onClose: () => void }) => {
|
|||
const [, setIsOnboarded] = useLocalStorageState(IS_ONBOARDED_KEY)
|
||||
const [showMaxSolWarning, setShowMaxSolWarning] = useState(false)
|
||||
const { handleConnect } = useEnhancedWallet()
|
||||
|
||||
const solBalance = useMemo(() => {
|
||||
return (
|
||||
walletTokens.find((t) =>
|
||||
t.mint.equals(TokenInstructions.WRAPPED_SOL_MINT)
|
||||
)?.uiAmount || 0
|
||||
)
|
||||
}, [walletTokens])
|
||||
const solBalance = useSolBalance()
|
||||
const maxSolDeposit = solBalance - MIN_SOL_BALANCE
|
||||
|
||||
useEffect(() => {
|
||||
const maxSolDeposit = solBalance - MIN_SOL_BALANCE
|
||||
if (depositToken === 'SOL' && maxSolDeposit < Number(depositAmount)) {
|
||||
setDepositAmount(maxSolDeposit.toString())
|
||||
setShowMaxSolWarning(true)
|
||||
} else {
|
||||
if (showMaxSolWarning) {
|
||||
setShowMaxSolWarning(false)
|
||||
}
|
||||
}
|
||||
}, [solBalance, depositAmount, depositToken])
|
||||
if (maxSolDeposit > 0 && depositAmount) {
|
||||
setDepositAmount(maxSolDeposit.toString())
|
||||
}
|
||||
}, [maxSolDeposit, depositAmount, depositToken])
|
||||
|
||||
useEffect(() => {
|
||||
if (depositToken !== 'SOL' && showMaxSolWarning) {
|
||||
setShowMaxSolWarning(false)
|
||||
}
|
||||
}, [depositToken, showMaxSolWarning])
|
||||
|
||||
const exceedsAlphaMax = useMemo(() => {
|
||||
const mangoAccount = mangoStore.getState().mangoAccount.current
|
||||
|
@ -429,7 +427,7 @@ const UserSetup = ({ onClose }: { onClose: () => void }) => {
|
|||
<div className="mt-2">
|
||||
<InlineNotification
|
||||
type="warning"
|
||||
desc={`SOL deposits are restricted to leave ${MIN_SOL_BALANCE} SOL in your wallet for sending transactions`}
|
||||
desc={`SOL deposits are restricted to leave ${MIN_SOL_BALANCE} SOL in your wallet for sending transactions. Add more SOL to your wallet`}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
|
@ -438,6 +436,7 @@ const UserSetup = ({ onClose }: { onClose: () => void }) => {
|
|||
<Label text={t('amount')} />
|
||||
<MaxAmountButton
|
||||
className="mb-2"
|
||||
disabled={depositToken === 'SOL' && maxSolDeposit <= 0}
|
||||
label="Wallet Max"
|
||||
onClick={() =>
|
||||
setDepositAmount(
|
||||
|
@ -487,6 +486,7 @@ const UserSetup = ({ onClose }: { onClose: () => void }) => {
|
|||
<div className="col-span-2 mt-2">
|
||||
<ButtonGroup
|
||||
activeValue={sizePercentage}
|
||||
disabled={depositToken === 'SOL' && maxSolDeposit <= 0}
|
||||
onChange={(p) => handleSizePercentage(p)}
|
||||
values={['10', '25', '50', '75', '100']}
|
||||
unit="%"
|
||||
|
|
|
@ -10,6 +10,7 @@ import {
|
|||
EllipsisHorizontalIcon,
|
||||
PencilIcon,
|
||||
TrashIcon,
|
||||
UsersIcon,
|
||||
} from '@heroicons/react/20/solid'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import IconDropMenu from '../shared/IconDropMenu'
|
||||
|
@ -21,6 +22,7 @@ import { notify } from 'utils/notifications'
|
|||
import { abbreviateAddress } from 'utils/formatting'
|
||||
import { HealthType, ZERO_I80F48 } from '@blockworks-foundation/mango-v4'
|
||||
import RepayModal from '@components/modals/RepayModal'
|
||||
import DelegateModal from '@components/modals/DelegateModal'
|
||||
|
||||
const AccountActions = () => {
|
||||
const { t } = useTranslation(['common', 'close-account'])
|
||||
|
@ -31,6 +33,7 @@ const AccountActions = () => {
|
|||
const [showEditAccountModal, setShowEditAccountModal] = useState(false)
|
||||
const [showWithdrawModal, setShowWithdrawModal] = useState(false)
|
||||
const [showRepayModal, setShowRepayModal] = useState(false)
|
||||
const [showDelegateModal, setShowDelegateModal] = useState(false)
|
||||
|
||||
const handleCopyAddress = (address: string) => {
|
||||
copyToClipboard(address)
|
||||
|
@ -101,6 +104,14 @@ const AccountActions = () => {
|
|||
<PencilIcon className="h-4 w-4" />
|
||||
<span className="ml-2">{t('edit-account')}</span>
|
||||
</LinkButton>
|
||||
<LinkButton
|
||||
className="whitespace-nowrap"
|
||||
disabled={!mangoAccount}
|
||||
onClick={() => setShowDelegateModal(true)}
|
||||
>
|
||||
<UsersIcon className="h-4 w-4" />
|
||||
<span className="ml-2">{t('delegate-account')}</span>
|
||||
</LinkButton>
|
||||
<LinkButton
|
||||
className="whitespace-nowrap"
|
||||
disabled={!mangoAccount}
|
||||
|
@ -135,10 +146,16 @@ const AccountActions = () => {
|
|||
onClose={() => setShowWithdrawModal(false)}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{showRepayModal ? (
|
||||
<RepayModal
|
||||
isOpen={showRepayModal}
|
||||
onClose={() => setShowRepayModal(false)}
|
||||
/>
|
||||
{showDelegateModal ? (
|
||||
<DelegateModal
|
||||
isOpen={showDelegateModal}
|
||||
onClose={() => setShowDelegateModal(false)}
|
||||
/>
|
||||
) : null}
|
||||
</>
|
||||
|
|
|
@ -12,6 +12,7 @@ import { MangoAccount } from '@blockworks-foundation/mango-v4'
|
|||
import { ArrowLeftIcon } from '@heroicons/react/20/solid'
|
||||
import { TokenInstructions } from '@project-serum/serum'
|
||||
import { MIN_SOL_BALANCE } from 'utils/constants'
|
||||
import useSolBalance from 'hooks/useSolBalance'
|
||||
|
||||
const getNextAccountNumber = (accounts: MangoAccount[]): number => {
|
||||
if (accounts.length > 1) {
|
||||
|
@ -39,15 +40,7 @@ const CreateAccountForm = ({
|
|||
const [loading, setLoading] = useState(false)
|
||||
const [name, setName] = useState('')
|
||||
const { wallet } = useWallet()
|
||||
const walletTokens = mangoStore((s) => s.wallet.tokens)
|
||||
|
||||
const solBalance = useMemo(() => {
|
||||
return (
|
||||
walletTokens.find((t) =>
|
||||
t.mint.equals(TokenInstructions.WRAPPED_SOL_MINT)
|
||||
)?.uiAmount || 0
|
||||
)
|
||||
}, [walletTokens])
|
||||
const solBalance = useSolBalance()
|
||||
|
||||
const handleNewAccount = async () => {
|
||||
const client = mangoStore.getState().client
|
||||
|
|
|
@ -3,6 +3,7 @@ import { FunctionComponent } from 'react'
|
|||
interface ButtonGroupProps {
|
||||
activeValue: string
|
||||
className?: string
|
||||
disabled?: boolean
|
||||
onChange: (x: string) => void
|
||||
unit?: string
|
||||
values: Array<any>
|
||||
|
@ -13,6 +14,7 @@ interface ButtonGroupProps {
|
|||
const ButtonGroup: FunctionComponent<ButtonGroupProps> = ({
|
||||
activeValue,
|
||||
className,
|
||||
disabled,
|
||||
unit,
|
||||
values,
|
||||
onChange,
|
||||
|
@ -20,7 +22,7 @@ const ButtonGroup: FunctionComponent<ButtonGroupProps> = ({
|
|||
large,
|
||||
}) => {
|
||||
return (
|
||||
<div className="rounded-md bg-th-bkg-3">
|
||||
<div className={`rounded-md bg-th-bkg-3 ${disabled ? 'opacity-50' : ''}`}>
|
||||
<div className="relative flex">
|
||||
{activeValue && values.includes(activeValue) ? (
|
||||
<div
|
||||
|
@ -35,7 +37,7 @@ const ButtonGroup: FunctionComponent<ButtonGroupProps> = ({
|
|||
) : null}
|
||||
{values.map((v, i) => (
|
||||
<button
|
||||
className={`${className} default-transition relative w-1/2 cursor-pointer rounded-md px-3 text-center ${
|
||||
className={`${className} default-transition relative w-1/2 cursor-pointer rounded-md px-3 text-center disabled:cursor-not-allowed ${
|
||||
large ? 'h-12 text-sm' : 'h-10 text-xs'
|
||||
} font-normal
|
||||
${
|
||||
|
@ -44,6 +46,7 @@ const ButtonGroup: FunctionComponent<ButtonGroupProps> = ({
|
|||
: `text-th-fgd-2 md:hover:text-th-primary`
|
||||
}
|
||||
`}
|
||||
disabled={disabled}
|
||||
key={`${v}${i}`}
|
||||
onClick={() => onChange(v)}
|
||||
style={{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
const Label = ({ text, optional }: { text: string; optional?: boolean }) => (
|
||||
<p className="mb-2 text-sm text-th-fgd-3">
|
||||
<p className="mb-2 text-left text-sm text-th-fgd-3">
|
||||
{text}{' '}
|
||||
{optional ? (
|
||||
<span className="ml-1 text-xs text-th-fgd-4">(Optional)</span>
|
||||
|
|
|
@ -26,6 +26,7 @@ import { withValueLimit } from '../swap/SwapForm'
|
|||
import { getMaxWithdrawForBank } from '../swap/useTokenMax'
|
||||
import MaxAmountButton from '@components/shared/MaxAmountButton'
|
||||
import HealthImpactTokenChange from '@components/HealthImpactTokenChange'
|
||||
import Tooltip from '@components/shared/Tooltip'
|
||||
|
||||
interface BorrowModalProps {
|
||||
token?: string
|
||||
|
@ -255,21 +256,37 @@ function BorrowModal({ isOpen, onClose, token }: ModalCombinedProps) {
|
|||
/>
|
||||
</div> */}
|
||||
</div>
|
||||
<div className="my-6 space-y-2 border-y border-th-bkg-3 px-2 py-4">
|
||||
<HealthImpactTokenChange
|
||||
mintPk={bank!.mint}
|
||||
uiAmount={Number(inputAmount)}
|
||||
/>
|
||||
<div className="flex justify-between">
|
||||
<p>{t('borrow-value')}</p>
|
||||
<p className="font-mono text-th-fgd-1">
|
||||
{formatFixedDecimals(
|
||||
bank?.uiPrice! * Number(inputAmount),
|
||||
true
|
||||
)}
|
||||
</p>
|
||||
{bank ? (
|
||||
<div className="my-6 space-y-2 border-y border-th-bkg-3 px-2 py-4">
|
||||
<HealthImpactTokenChange
|
||||
mintPk={bank.mint}
|
||||
uiAmount={Number(inputAmount)}
|
||||
/>
|
||||
<div className="flex justify-between">
|
||||
<p>{t('borrow-value')}</p>
|
||||
<p className="font-mono text-th-fgd-1">
|
||||
{formatFixedDecimals(
|
||||
bank.uiPrice * Number(inputAmount),
|
||||
true
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<Tooltip content={t('loan-origination-fee-tooltip')}>
|
||||
<p className="tooltip-underline">
|
||||
{t('loan-origination-fee')}
|
||||
</p>
|
||||
</Tooltip>
|
||||
<p className="font-mono text-th-fgd-1">
|
||||
{formatFixedDecimals(
|
||||
bank.loanOriginationFeeRate.toNumber() *
|
||||
Number(inputAmount),
|
||||
true
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
<Button
|
||||
onClick={handleWithdraw}
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
import { ModalProps } from '../../types/modal'
|
||||
import Modal from '../shared/Modal'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { notify } from '../../utils/notifications'
|
||||
import Button from '../shared/Button'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { ChangeEvent, useState } from 'react'
|
||||
import Input from '../forms/Input'
|
||||
import Label from '../forms/Label'
|
||||
import { PublicKey } from '@solana/web3.js'
|
||||
|
||||
const DelegateModal = ({ isOpen, onClose }: ModalProps) => {
|
||||
const { t } = useTranslation('common')
|
||||
const mangoAccount = mangoStore((s) => s.mangoAccount.current)
|
||||
const [loading, setLoading] = useState(false)
|
||||
console.log('mad', mangoAccount?.delegate?.toString())
|
||||
|
||||
const [delegateAddress, setDelegateAddress] = useState(
|
||||
mangoAccount?.delegate?.toString() !== '11111111111111111111111111111111'
|
||||
? mangoAccount?.delegate?.toString()
|
||||
: ''
|
||||
)
|
||||
|
||||
// This doesn't work yet...
|
||||
const handleUpdateccountName = async () => {
|
||||
const client = mangoStore.getState().client
|
||||
const group = mangoStore.getState().group
|
||||
const actions = mangoStore.getState().actions
|
||||
if (!mangoAccount || !group) return
|
||||
|
||||
if (
|
||||
delegateAddress &&
|
||||
delegateAddress !== '' &&
|
||||
!PublicKey.isOnCurve(delegateAddress)
|
||||
) {
|
||||
notify({
|
||||
type: 'error',
|
||||
title: 'Not a valid delegate address',
|
||||
description: 'Enter the public key of the delegate wallet',
|
||||
})
|
||||
}
|
||||
|
||||
setLoading(true)
|
||||
try {
|
||||
const tx = await client.editMangoAccount(
|
||||
group,
|
||||
mangoAccount,
|
||||
undefined,
|
||||
delegateAddress ? new PublicKey(delegateAddress) : undefined
|
||||
)
|
||||
|
||||
setLoading(false)
|
||||
onClose()
|
||||
notify({
|
||||
title: t('account-update-success'),
|
||||
type: 'success',
|
||||
txid: tx,
|
||||
})
|
||||
await actions.reloadMangoAccount()
|
||||
} catch (e: any) {
|
||||
setLoading(false)
|
||||
notify({
|
||||
title: t('account-update-failed'),
|
||||
txid: e?.signature,
|
||||
type: 'error',
|
||||
})
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal isOpen={isOpen} onClose={onClose}>
|
||||
<div className="h-64">
|
||||
<div className="flex h-full flex-col justify-between">
|
||||
<div className="pb-4">
|
||||
<h2 className="mb-1">{t('delegate-account')}</h2>
|
||||
<p className="mb-4">{t('delegate-desc')}</p>
|
||||
<Label text={t('wallet-address')} />
|
||||
<Input
|
||||
type="text"
|
||||
name="name"
|
||||
id="name"
|
||||
placeholder={t('delegate-placeholder')}
|
||||
value={delegateAddress}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) =>
|
||||
setDelegateAddress(e.target.value)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
className="w-full"
|
||||
onClick={handleUpdateccountName}
|
||||
size="large"
|
||||
>
|
||||
{t('update')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export default DelegateModal
|
|
@ -33,7 +33,7 @@ import { withValueLimit } from '../swap/SwapForm'
|
|||
import MaxAmountButton from '@components/shared/MaxAmountButton'
|
||||
import Tooltip from '@components/shared/Tooltip'
|
||||
import HealthImpactTokenChange from '@components/HealthImpactTokenChange'
|
||||
import { TokenInstructions } from '@project-serum/serum'
|
||||
import useSolBalance from 'hooks/useSolBalance'
|
||||
|
||||
interface DepositModalProps {
|
||||
token?: string
|
||||
|
@ -92,26 +92,23 @@ function DepositModal({ isOpen, onClose, token }: ModalCombinedProps) {
|
|||
|
||||
const { wallet } = useWallet()
|
||||
const walletTokens = mangoStore((s) => s.wallet.tokens)
|
||||
|
||||
const solBalance = useMemo(() => {
|
||||
return (
|
||||
walletTokens.find((t) =>
|
||||
t.mint.equals(TokenInstructions.WRAPPED_SOL_MINT)
|
||||
)?.uiAmount || 0
|
||||
)
|
||||
}, [walletTokens])
|
||||
const solBalance = useSolBalance()
|
||||
const maxSolDeposit = solBalance - MIN_SOL_BALANCE
|
||||
|
||||
useEffect(() => {
|
||||
const maxSolDeposit = solBalance - MIN_SOL_BALANCE
|
||||
if (selectedToken === 'SOL' && maxSolDeposit < Number(inputAmount)) {
|
||||
setInputAmount(maxSolDeposit.toString())
|
||||
setShowMaxSolWarning(true)
|
||||
} else {
|
||||
if (showMaxSolWarning) {
|
||||
setShowMaxSolWarning(false)
|
||||
}
|
||||
}
|
||||
}, [solBalance, inputAmount, selectedToken])
|
||||
if (maxSolDeposit > 0 && inputAmount) {
|
||||
setInputAmount(maxSolDeposit.toString())
|
||||
}
|
||||
}, [maxSolDeposit, inputAmount, selectedToken])
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedToken !== 'SOL' && showMaxSolWarning) {
|
||||
setShowMaxSolWarning(false)
|
||||
}
|
||||
}, [selectedToken, showMaxSolWarning])
|
||||
|
||||
const tokenMax = useMemo(() => {
|
||||
return walletBalanceForToken(walletTokens, selectedToken)
|
||||
|
@ -256,7 +253,7 @@ function DepositModal({ isOpen, onClose, token }: ModalCombinedProps) {
|
|||
<div className="mt-2">
|
||||
<InlineNotification
|
||||
type="warning"
|
||||
desc={`SOL deposits are restricted to leave ${MIN_SOL_BALANCE} SOL in your wallet for sending transactions`}
|
||||
desc={`SOL deposits are restricted to leave ${MIN_SOL_BALANCE} SOL in your wallet for sending transactions. Add more SOL to your wallet`}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
|
@ -265,6 +262,7 @@ function DepositModal({ isOpen, onClose, token }: ModalCombinedProps) {
|
|||
<Label text={t('token')} />
|
||||
<MaxAmountButton
|
||||
className="mb-2"
|
||||
disabled={selectedToken === 'SOL' && maxSolDeposit <= 0}
|
||||
label={t('wallet-balance')}
|
||||
onClick={setMax}
|
||||
value={floorToDecimal(
|
||||
|
@ -314,6 +312,7 @@ function DepositModal({ isOpen, onClose, token }: ModalCombinedProps) {
|
|||
<ButtonGroup
|
||||
activeValue={sizePercentage}
|
||||
className="font-mono"
|
||||
disabled={selectedToken === 'SOL' && maxSolDeposit <= 0}
|
||||
onChange={(p) => handleSizePercentage(p)}
|
||||
values={['10', '25', '50', '75', '100']}
|
||||
unit="%"
|
||||
|
|
|
@ -108,7 +108,7 @@ export const LinkButton: FunctionComponent<LinkButtonCombinedProps> = ({
|
|||
disabled={disabled}
|
||||
className={`flex items-center border-0 font-bold ${
|
||||
secondary ? 'text-th-primary' : 'text-th-fgd-2'
|
||||
} underline focus:outline-none disabled:cursor-not-allowed disabled:underline disabled:opacity-50 md:hover:no-underline ${className}`}
|
||||
} underline focus:outline-none disabled:cursor-not-allowed disabled:opacity-50 md:hover:no-underline ${className}`}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
|
|
|
@ -2,17 +2,23 @@ import { LinkButton } from './Button'
|
|||
|
||||
const MaxAmountButton = ({
|
||||
className,
|
||||
disabled,
|
||||
label,
|
||||
onClick,
|
||||
value,
|
||||
}: {
|
||||
className?: string
|
||||
disabled?: boolean
|
||||
label: string
|
||||
onClick: () => void
|
||||
value: string
|
||||
}) => {
|
||||
return (
|
||||
<LinkButton className={`no-underline ${className}`} onClick={onClick}>
|
||||
<LinkButton
|
||||
className={`no-underline ${className}`}
|
||||
disabled={disabled}
|
||||
onClick={onClick}
|
||||
>
|
||||
<span className="mr-1 font-normal text-th-fgd-4">{label}:</span>
|
||||
<span className="font-mono text-th-fgd-2 underline">{value}</span>
|
||||
</LinkButton>
|
||||
|
|
|
@ -2,7 +2,6 @@ import { Dialog } from '@headlessui/react'
|
|||
import { XMarkIcon } from '@heroicons/react/20/solid'
|
||||
|
||||
type ModalProps = {
|
||||
title?: string
|
||||
children: React.ReactNode
|
||||
disableOutsideClose?: boolean
|
||||
isOpen: boolean
|
||||
|
@ -11,7 +10,6 @@ type ModalProps = {
|
|||
}
|
||||
|
||||
function Modal({
|
||||
title = '',
|
||||
children,
|
||||
disableOutsideClose = false,
|
||||
isOpen,
|
||||
|
@ -22,18 +20,16 @@ function Modal({
|
|||
<Dialog
|
||||
open={isOpen}
|
||||
onClose={onClose}
|
||||
className="fixed inset-0 z-30 overflow-y-auto"
|
||||
className="relative z-30 overflow-y-auto"
|
||||
>
|
||||
<div className="min-h-screen px-4 text-center">
|
||||
<Dialog.Overlay
|
||||
className={`fixed inset-0 backdrop-blur-sm backdrop-brightness-75 ${
|
||||
disableOutsideClose ? 'pointer-events-none' : ''
|
||||
}`}
|
||||
/>
|
||||
<span className="inline-block h-screen align-middle" aria-hidden="true">
|
||||
​
|
||||
</span>
|
||||
<div className="my-8 inline-block w-full max-w-md transform rounded-lg border border-th-bkg-3 bg-th-bkg-1 p-6 text-left align-middle shadow-xl">
|
||||
<div
|
||||
className={`fixed inset-0 backdrop-blur-sm backdrop-brightness-75 ${
|
||||
disableOutsideClose ? 'pointer-events-none' : ''
|
||||
}`}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<div className="fixed inset-0 flex items-center justify-center px-4 text-center">
|
||||
<Dialog.Panel className="relative w-full max-w-md rounded-lg border border-th-bkg-3 bg-th-bkg-1 p-6">
|
||||
{!hideClose ? (
|
||||
<button
|
||||
onClick={onClose}
|
||||
|
@ -42,10 +38,8 @@ function Modal({
|
|||
<XMarkIcon className={`h-6 w-6`} />
|
||||
</button>
|
||||
) : null}
|
||||
<Dialog.Title>{title}</Dialog.Title>
|
||||
|
||||
{children}
|
||||
</div>
|
||||
<div>{children}</div>
|
||||
</Dialog.Panel>
|
||||
</div>
|
||||
</Dialog>
|
||||
)
|
||||
|
|
|
@ -19,6 +19,7 @@ import {
|
|||
import useLocalStorageState from 'hooks/useLocalStorageState'
|
||||
import { EXPLORERS } from 'pages/settings'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import useSolBalance from 'hooks/useSolBalance'
|
||||
|
||||
const setMangoStore = mangoStore.getState().set
|
||||
|
||||
|
@ -32,6 +33,7 @@ const NotificationList = () => {
|
|||
'bottom-left'
|
||||
)
|
||||
const [mounted, setMounted] = useState(false)
|
||||
const solBalance = useSolBalance()
|
||||
|
||||
// if a notification is shown with {"InstructionError":[0,{"Custom":1}]} then
|
||||
// add a notification letting the user know they may not have enough SOL
|
||||
|
@ -43,9 +45,6 @@ const NotificationList = () => {
|
|||
const notEnoughSolNotification = notifications.find(
|
||||
(n) => n.title && n.title.includes(notEnoughSoLMessage)
|
||||
)
|
||||
const solBalance = walletTokens.find((t) =>
|
||||
t.mint.equals(TokenInstructions.WRAPPED_SOL_MINT)
|
||||
)?.uiAmount
|
||||
|
||||
if (
|
||||
!notEnoughSolNotification &&
|
||||
|
@ -59,7 +58,7 @@ const NotificationList = () => {
|
|||
})
|
||||
}
|
||||
}
|
||||
}, [notifications, walletTokens])
|
||||
}, [notifications, walletTokens, solBalance])
|
||||
|
||||
const clearAll = useCallback(() => {
|
||||
setMangoStore((s) => {
|
||||
|
|
|
@ -72,7 +72,7 @@ const useJupiter = ({
|
|||
amount: JSBI.BigInt(
|
||||
new Decimal(inputAmount).mul(10 ** inputTokenInfo.decimals)
|
||||
),
|
||||
slippageBps: Math.ceil(slippage * 100), // The slippage in % terms
|
||||
slippage, // The slippage in % terms
|
||||
filterTopNResult: 10,
|
||||
onlyDirectRoutes: true,
|
||||
})
|
||||
|
|
|
@ -4,7 +4,7 @@ import TabUnderline from '@components/shared/TabUnderline'
|
|||
import { Popover } from '@headlessui/react'
|
||||
import { ChevronDownIcon } from '@heroicons/react/20/solid'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { group } from 'console'
|
||||
import useOraclePrice from 'hooks/useOraclePrice'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { DEFAULT_MARKET_NAME } from 'utils/constants'
|
||||
|
@ -110,34 +110,14 @@ const MarketSelectDropdown = () => {
|
|||
)
|
||||
}
|
||||
|
||||
const OraclePrice = () => {
|
||||
const group = mangoStore((s) => s.group)
|
||||
const selectedMarket = mangoStore((s) => s.selectedMarket.current)
|
||||
|
||||
if (!group || !selectedMarket) return null
|
||||
|
||||
let price
|
||||
if (selectedMarket instanceof Serum3Market) {
|
||||
price = group.getFirstBankByTokenIndex(
|
||||
selectedMarket?.baseTokenIndex
|
||||
).uiPrice
|
||||
} else {
|
||||
price = selectedMarket.uiPrice
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="font-mono text-xs text-th-fgd-2">
|
||||
${price ? formatFixedDecimals(price) : null}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const AdvancedMarketHeader = () => {
|
||||
const { t } = useTranslation(['common', 'trade'])
|
||||
const selectedMarket = mangoStore((s) => s.selectedMarket.current)
|
||||
const serumMarketPrices = mangoStore((s) => s.serumMarketPrices.data)
|
||||
const loadSerumMarketPrices = mangoStore((s) => s.serumMarketPrices.loading)
|
||||
const actions = mangoStore((s) => s.actions)
|
||||
const serumMarkets = mangoStore((s) => s.serumMarkets)
|
||||
const oraclePrice = useOraclePrice()
|
||||
|
||||
useEffect(() => {
|
||||
if (serumMarkets.length) {
|
||||
|
@ -158,11 +138,9 @@ const AdvancedMarketHeader = () => {
|
|||
}, [selectedMarket, serumMarketPrices])
|
||||
|
||||
const change = useMemo(() => {
|
||||
if (marketPrices) {
|
||||
if (marketPrices && oraclePrice) {
|
||||
return (
|
||||
((marketPrices[marketPrices.length - 1].value - marketPrices[0].value) /
|
||||
marketPrices[0].value) *
|
||||
100
|
||||
((oraclePrice - marketPrices[0].value) / marketPrices[0].value) * 100
|
||||
)
|
||||
}
|
||||
return 0
|
||||
|
@ -177,12 +155,20 @@ const AdvancedMarketHeader = () => {
|
|||
</div>
|
||||
<div id="trade-step-two" className="ml-6 flex-col">
|
||||
<div className="text-xs text-th-fgd-4">{t('trade:oracle-price')}</div>
|
||||
<OraclePrice />
|
||||
<div className="font-mono text-xs text-th-fgd-2">
|
||||
{oraclePrice ? (
|
||||
`$${formatFixedDecimals(oraclePrice)}`
|
||||
) : (
|
||||
<span className="text-th-fgd-4">–</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="ml-6 flex-col">
|
||||
<div className="text-xs text-th-fgd-4">{t('rolling-change')}</div>
|
||||
{change ? (
|
||||
<Change change={change} size="small" />
|
||||
) : loadSerumMarketPrices ? (
|
||||
<span className="text-th-fgd-4">–</span>
|
||||
) : (
|
||||
<div className="font-mono text-xs">{t('unavailable')}</div>
|
||||
)}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
import { Serum3Market } from '@blockworks-foundation/mango-v4'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
|
||||
export default function useOraclePrice() {
|
||||
const group = mangoStore((s) => s.group)
|
||||
const selectedMarket = mangoStore((s) => s.selectedMarket.current)
|
||||
|
||||
if (!group || !selectedMarket) return false
|
||||
|
||||
let price
|
||||
if (selectedMarket instanceof Serum3Market) {
|
||||
price = group.getFirstBankByTokenIndex(
|
||||
selectedMarket?.baseTokenIndex
|
||||
).uiPrice
|
||||
} else {
|
||||
price = selectedMarket.uiPrice
|
||||
}
|
||||
return price
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
import { TokenInstructions } from '@project-serum/serum'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { useMemo } from 'react'
|
||||
|
||||
export default function useSolBalance() {
|
||||
const walletTokens = mangoStore((s) => s.wallet.tokens)
|
||||
const solBalance = useMemo(() => {
|
||||
return (
|
||||
walletTokens.find((t) =>
|
||||
t.mint.equals(TokenInstructions.WRAPPED_SOL_MINT)
|
||||
)?.uiAmount || 0
|
||||
)
|
||||
}, [walletTokens])
|
||||
return solBalance
|
||||
}
|
|
@ -15,11 +15,11 @@
|
|||
"@blockworks-foundation/mango-v4": "https://tylersssss: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@github.com/blockworks-foundation/mango-v4.git#main",
|
||||
"@headlessui/react": "^1.6.6",
|
||||
"@heroicons/react": "^2.0.10",
|
||||
"@jup-ag/core": "^3.0.0-beta.8",
|
||||
"@jup-ag/core": "^2.0.0-beta.3",
|
||||
"@project-serum/anchor": "0.25.0",
|
||||
"@solana/wallet-adapter-base": "latest",
|
||||
"@solana/wallet-adapter-react": "latest",
|
||||
"@solana/wallet-adapter-wallets": "latest",
|
||||
"@solana/wallet-adapter-base": "^0.9.18",
|
||||
"@solana/wallet-adapter-react": "^0.15.24",
|
||||
"@solana/wallet-adapter-wallets": "^0.19.5",
|
||||
"@solflare-wallet/pfp": "^0.0.6",
|
||||
"@tanstack/react-query": "^4.10.1",
|
||||
"@tippyjs/react": "^4.2.6",
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
"cancel": "Cancel",
|
||||
"clear-all": "Clear All",
|
||||
"close-account": "Close Account",
|
||||
"close-account-desc": "Are you sure? Closing your account is irreversible.",
|
||||
"close-account-desc": "Are you sure? Closing your account is irreversible",
|
||||
"closing-account": "Closing your account...",
|
||||
"collateral-value": "Collateral Value",
|
||||
"connect": "Connect",
|
||||
|
@ -41,6 +41,9 @@
|
|||
"date": "Date",
|
||||
"date-from": "Date From",
|
||||
"date-to": "Date To",
|
||||
"delegate-account": "Delegate Account",
|
||||
"delegate-desc": "Delegate your Mango account to another wallet address",
|
||||
"delegate-placeholder": "Enter a wallet address to delegate to",
|
||||
"deposit": "Deposit",
|
||||
"deposit-more-sol": "Deposit more SOL to your wallet before creating an account.",
|
||||
"deposit-rate": "Deposit Rate (APR)",
|
||||
|
@ -63,6 +66,8 @@
|
|||
"leverage": "Leverage",
|
||||
"liability-weight": "Liability Weight",
|
||||
"liquidity": "Liquidity",
|
||||
"loan-origination-fee": "Loan Origination Fee",
|
||||
"loan-origination-fee-tooltip": "The fee for opening a borrow. This is paid to the Mango DAO Treasury",
|
||||
"market": "Market",
|
||||
"max": "Max",
|
||||
"max-borrow": "Max Borrow",
|
||||
|
@ -110,6 +115,7 @@
|
|||
"updating-account-name": "Updating Account Name...",
|
||||
"utilization": "Utilization",
|
||||
"value": "Value",
|
||||
"wallet-address": "Wallet Address",
|
||||
"wallet-balance": "Wallet Balance",
|
||||
"wallet-disconnected": "Disconnected from wallet",
|
||||
"withdraw": "Withdraw",
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
"cancel": "Cancel",
|
||||
"clear-all": "Clear All",
|
||||
"close-account": "Close Account",
|
||||
"close-account-desc": "Are you sure? Closing your account is irreversible.",
|
||||
"close-account-desc": "Are you sure? Closing your account is irreversible",
|
||||
"closing-account": "Closing your account...",
|
||||
"collateral-value": "Collateral Value",
|
||||
"connect": "Connect",
|
||||
|
@ -41,6 +41,9 @@
|
|||
"date": "Date",
|
||||
"date-from": "Date From",
|
||||
"date-to": "Date To",
|
||||
"delegate-account": "Delegate Account",
|
||||
"delegate-desc": "Delegate your Mango account to another wallet address",
|
||||
"delegate-placeholder": "Enter a wallet address to delegate to",
|
||||
"deposit": "Deposit",
|
||||
"deposit-more-sol": "Deposit more SOL to your wallet before creating an account.",
|
||||
"deposit-rate": "Deposit Rate (APR)",
|
||||
|
@ -63,6 +66,8 @@
|
|||
"leverage": "Leverage",
|
||||
"liability-weight": "Liability Weight",
|
||||
"liquidity": "Liquidity",
|
||||
"loan-origination-fee": "Loan Origination Fee",
|
||||
"loan-origination-fee-tooltip": "The fee for opening a borrow. This is paid to the Mango DAO Treasury",
|
||||
"market": "Market",
|
||||
"max": "Max",
|
||||
"max-borrow": "Max Borrow",
|
||||
|
@ -110,6 +115,7 @@
|
|||
"updating-account-name": "Updating Account Name...",
|
||||
"utilization": "Utilization",
|
||||
"value": "Value",
|
||||
"wallet-address": "Wallet Address",
|
||||
"wallet-balance": "Wallet Balance",
|
||||
"wallet-disconnected": "Disconnected from wallet",
|
||||
"withdraw": "Withdraw",
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
"cancel": "Cancel",
|
||||
"clear-all": "Clear All",
|
||||
"close-account": "Close Account",
|
||||
"close-account-desc": "Are you sure? Closing your account is irreversible.",
|
||||
"close-account-desc": "Are you sure? Closing your account is irreversible",
|
||||
"closing-account": "Closing your account...",
|
||||
"collateral-value": "Collateral Value",
|
||||
"connect": "Connect",
|
||||
|
@ -41,6 +41,9 @@
|
|||
"date": "Date",
|
||||
"date-from": "Date From",
|
||||
"date-to": "Date To",
|
||||
"delegate-account": "Delegate Account",
|
||||
"delegate-desc": "Delegate your Mango account to another wallet address",
|
||||
"delegate-placeholder": "Enter a wallet address to delegate to",
|
||||
"deposit": "Deposit",
|
||||
"deposit-more-sol": "Deposit more SOL to your wallet before creating an account.",
|
||||
"deposit-rate": "Deposit Rate (APR)",
|
||||
|
@ -63,6 +66,8 @@
|
|||
"leverage": "Leverage",
|
||||
"liability-weight": "Liability Weight",
|
||||
"liquidity": "Liquidity",
|
||||
"loan-origination-fee": "Loan Origination Fee",
|
||||
"loan-origination-fee-tooltip": "The fee for opening a borrow. This is paid to the Mango DAO Treasury",
|
||||
"market": "Market",
|
||||
"max": "Max",
|
||||
"max-borrow": "Max Borrow",
|
||||
|
@ -110,6 +115,7 @@
|
|||
"updating-account-name": "Updating Account Name...",
|
||||
"utilization": "Utilization",
|
||||
"value": "Value",
|
||||
"wallet-address": "Wallet Address",
|
||||
"wallet-balance": "Wallet Balance",
|
||||
"wallet-disconnected": "Disconnected from wallet",
|
||||
"withdraw": "Withdraw",
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
"cancel": "Cancel",
|
||||
"clear-all": "Clear All",
|
||||
"close-account": "Close Account",
|
||||
"close-account-desc": "Are you sure? Closing your account is irreversible.",
|
||||
"close-account-desc": "Are you sure? Closing your account is irreversible",
|
||||
"closing-account": "Closing your account...",
|
||||
"collateral-value": "Collateral Value",
|
||||
"connect": "Connect",
|
||||
|
@ -41,6 +41,9 @@
|
|||
"date": "Date",
|
||||
"date-from": "Date From",
|
||||
"date-to": "Date To",
|
||||
"delegate-account": "Delegate Account",
|
||||
"delegate-desc": "Delegate your Mango account to another wallet address",
|
||||
"delegate-placeholder": "Enter a wallet address to delegate to",
|
||||
"deposit": "Deposit",
|
||||
"deposit-more-sol": "Deposit more SOL to your wallet before creating an account.",
|
||||
"deposit-rate": "Deposit Rate (APR)",
|
||||
|
@ -63,6 +66,8 @@
|
|||
"leverage": "Leverage",
|
||||
"liability-weight": "Liability Weight",
|
||||
"liquidity": "Liquidity",
|
||||
"loan-origination-fee": "Loan Origination Fee",
|
||||
"loan-origination-fee-tooltip": "The fee for opening a borrow. This is paid to the Mango DAO Treasury",
|
||||
"market": "Market",
|
||||
"max": "Max",
|
||||
"max-borrow": "Max Borrow",
|
||||
|
@ -110,6 +115,7 @@
|
|||
"updating-account-name": "Updating Account Name...",
|
||||
"utilization": "Utilization",
|
||||
"value": "Value",
|
||||
"wallet-address": "Wallet Address",
|
||||
"wallet-balance": "Wallet Balance",
|
||||
"wallet-disconnected": "Disconnected from wallet",
|
||||
"withdraw": "Withdraw",
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
"cancel": "Cancel",
|
||||
"clear-all": "Clear All",
|
||||
"close-account": "Close Account",
|
||||
"close-account-desc": "Are you sure? Closing your account is irreversible.",
|
||||
"close-account-desc": "Are you sure? Closing your account is irreversible",
|
||||
"closing-account": "Closing your account...",
|
||||
"collateral-value": "Collateral Value",
|
||||
"connect": "Connect",
|
||||
|
@ -41,6 +41,9 @@
|
|||
"date": "Date",
|
||||
"date-from": "Date From",
|
||||
"date-to": "Date To",
|
||||
"delegate-account": "Delegate Account",
|
||||
"delegate-desc": "Delegate your Mango account to another wallet address",
|
||||
"delegate-placeholder": "Enter a wallet address to delegate to",
|
||||
"deposit": "Deposit",
|
||||
"deposit-more-sol": "Deposit more SOL to your wallet before creating an account.",
|
||||
"deposit-rate": "Deposit Rate (APR)",
|
||||
|
@ -63,6 +66,8 @@
|
|||
"leverage": "Leverage",
|
||||
"liability-weight": "Liability Weight",
|
||||
"liquidity": "Liquidity",
|
||||
"loan-origination-fee": "Loan Origination Fee",
|
||||
"loan-origination-fee-tooltip": "The fee for opening a borrow. This is paid to the Mango DAO Treasury",
|
||||
"market": "Market",
|
||||
"max": "Max",
|
||||
"max-borrow": "Max Borrow",
|
||||
|
@ -110,6 +115,7 @@
|
|||
"updating-account-name": "Updating Account Name...",
|
||||
"utilization": "Utilization",
|
||||
"value": "Value",
|
||||
"wallet-address": "Wallet Address",
|
||||
"wallet-balance": "Wallet Balance",
|
||||
"wallet-disconnected": "Disconnected from wallet",
|
||||
"withdraw": "Withdraw",
|
||||
|
|
Loading…
Reference in New Issue