merge main
This commit is contained in:
commit
e278b9d07f
|
@ -0,0 +1,116 @@
|
|||
import { FunctionComponent, useState } from 'react'
|
||||
import useMangoStore from '../stores/useMangoStore'
|
||||
import {
|
||||
ExclamationCircleIcon,
|
||||
InformationCircleIcon,
|
||||
} from '@heroicons/react/outline'
|
||||
import Input from './Input'
|
||||
import Button from './Button'
|
||||
import Modal from './Modal'
|
||||
import { ElementTitle } from './styles'
|
||||
import Tooltip from './Tooltip'
|
||||
import useConnection from '../hooks/useConnection'
|
||||
import { PublicKey } from '@solana/web3.js'
|
||||
// import { addMarginAccountInfo } from '../utils/mango'
|
||||
import { notify } from '../utils/notifications'
|
||||
|
||||
interface AccountNameModalProps {
|
||||
accountName?: string
|
||||
isOpen: boolean
|
||||
onClose?: (x?) => void
|
||||
}
|
||||
|
||||
const AccountNameModal: FunctionComponent<AccountNameModalProps> = ({
|
||||
accountName,
|
||||
isOpen,
|
||||
onClose,
|
||||
}) => {
|
||||
const [name, setName] = useState(accountName || '')
|
||||
const [invalidNameMessage, setInvalidNameMessage] = useState('')
|
||||
const wallet = useMangoStore.getState().wallet.current
|
||||
const selectedMangoGroup = useMangoStore((s) => s.selectedMangoGroup.current)
|
||||
const mangoAccount = useMangoStore((s) => s.selectedMangoAccount.current)
|
||||
const actions = useMangoStore((s) => s.actions)
|
||||
const { connection, programId } = useConnection()
|
||||
|
||||
const submitName = async () => {
|
||||
// addMarginAccountInfo(
|
||||
// connection,
|
||||
// new PublicKey(programId),
|
||||
// selectedMangoGroup,
|
||||
// mangoAccount,
|
||||
// wallet,
|
||||
// name
|
||||
// )
|
||||
// .then(() => {
|
||||
// actions.fetchMarginAccounts()
|
||||
// onClose()
|
||||
// })
|
||||
// .catch((err) => {
|
||||
// console.warn('Error setting account name:', err)
|
||||
// notify({
|
||||
// message: 'Could not set account name',
|
||||
// description: `${err}`,
|
||||
// txid: err.txid,
|
||||
// type: 'error',
|
||||
// })
|
||||
// })
|
||||
}
|
||||
|
||||
const validateNameInput = () => {
|
||||
if (name.length >= 33) {
|
||||
setInvalidNameMessage('Account name must be 32 characters or less')
|
||||
}
|
||||
if (name.length === 0) {
|
||||
setInvalidNameMessage('Enter an account name')
|
||||
}
|
||||
}
|
||||
|
||||
const onChangeNameInput = (name) => {
|
||||
setName(name)
|
||||
if (invalidNameMessage) {
|
||||
setInvalidNameMessage('')
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal onClose={onClose} isOpen={isOpen}>
|
||||
<Modal.Header>
|
||||
<div className="flex items-center">
|
||||
<ElementTitle noMarignBottom>Name your Account</ElementTitle>
|
||||
</div>
|
||||
</Modal.Header>
|
||||
<div className="flex items-center justify-center text-th-fgd-3 pb-4">
|
||||
Edit the public nickname for your account
|
||||
<Tooltip content="Account names are stored on-chain">
|
||||
<InformationCircleIcon className="h-5 w-5 ml-2 text-th-primary" />
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div className="pb-2 text-th-fgd-1">Account Name</div>
|
||||
<Input
|
||||
type="text"
|
||||
className={`border border-th-fgd-4 flex-grow`}
|
||||
error={!!invalidNameMessage}
|
||||
placeholder="e.g. Calypso"
|
||||
value={name}
|
||||
onBlur={validateNameInput}
|
||||
onChange={(e) => onChangeNameInput(e.target.value)}
|
||||
/>
|
||||
{invalidNameMessage ? (
|
||||
<div className="flex items-center pt-1.5 text-th-red">
|
||||
<ExclamationCircleIcon className="h-4 w-4 mr-1.5" />
|
||||
{invalidNameMessage}
|
||||
</div>
|
||||
) : null}
|
||||
<Button
|
||||
onClick={() => submitName()}
|
||||
disabled={name.length >= 33}
|
||||
className="mt-4 w-full"
|
||||
>
|
||||
Save Name
|
||||
</Button>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export default AccountNameModal
|
|
@ -11,7 +11,7 @@ import {
|
|||
MangoAccount,
|
||||
MangoCache,
|
||||
MangoGroup,
|
||||
ZERO_I80F48,
|
||||
// ZERO_I80F48,
|
||||
} from '@blockworks-foundation/mango-client'
|
||||
import { abbreviateAddress } from '../utils'
|
||||
import useLocalStorageState from '../hooks/useLocalStorageState'
|
||||
|
@ -187,17 +187,17 @@ const AccountInfo = ({
|
|||
}) => {
|
||||
const accountEquity = mangoAccount.computeValue(mangoGroup, mangoCache)
|
||||
|
||||
const leverage = accountEquity.gt(ZERO_I80F48)
|
||||
? mangoAccount
|
||||
.getLiabsVal(mangoGroup, mangoCache)
|
||||
.div(accountEquity)
|
||||
.toFixed(2)
|
||||
: '0.00'
|
||||
// const leverage = accountEquity.gt(ZERO_I80F48)
|
||||
// ? mangoAccount
|
||||
// .getLiabsVal(mangoGroup, mangoCache)
|
||||
// .div(accountEquity)
|
||||
// .toFixed(2)
|
||||
// : '0.00'
|
||||
|
||||
return (
|
||||
<div className="text-th-fgd-3 text-xs">
|
||||
${accountEquity.toFixed(2)}
|
||||
<span className="px-1.5 text-th-fgd-4">|</span>
|
||||
{/* <span className="px-1.5 text-th-fgd-4">|</span>
|
||||
<span
|
||||
className={
|
||||
parseFloat(leverage) > 4
|
||||
|
@ -208,7 +208,7 @@ const AccountInfo = ({
|
|||
}
|
||||
>
|
||||
{leverage}x
|
||||
</span>
|
||||
</span> */}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -7,11 +7,15 @@ import { InformationCircleIcon } from '@heroicons/react/outline'
|
|||
import Tooltip from './Tooltip'
|
||||
import { sleep } from '../utils'
|
||||
import { Market } from '@project-serum/serum'
|
||||
import { ZERO_I80F48 } from '@blockworks-foundation/mango-client'
|
||||
import {
|
||||
getTokenBySymbol,
|
||||
ZERO_I80F48,
|
||||
} from '@blockworks-foundation/mango-client'
|
||||
|
||||
const BalancesTable = () => {
|
||||
const balances = useBalances()
|
||||
const actions = useMangoStore((s) => s.actions)
|
||||
const mangoGroupConfig = useMangoStore((s) => s.selectedMangoGroup.config)
|
||||
|
||||
async function handleSettleAll() {
|
||||
const mangoAccount = useMangoStore.getState().selectedMangoAccount.current
|
||||
|
@ -117,53 +121,59 @@ const BalancesTable = () => {
|
|||
</Tr>
|
||||
</Thead>
|
||||
<Tbody>
|
||||
{balances.map((balance, index) => (
|
||||
<Tr
|
||||
key={`${index}`}
|
||||
className={`border-b border-th-bkg-3
|
||||
{balances.map((balance, index) => {
|
||||
const tokenConfig = getTokenBySymbol(
|
||||
mangoGroupConfig,
|
||||
balance.symbol.toUpperCase()
|
||||
)
|
||||
return (
|
||||
<Tr
|
||||
key={`${index}`}
|
||||
className={`border-b border-th-bkg-3
|
||||
${index % 2 === 0 ? `bg-th-bkg-3` : `bg-th-bkg-2`}
|
||||
`}
|
||||
>
|
||||
<Td
|
||||
className={`flex items-center px-4 py-2.5 whitespace-nowrap text-sm text-th-fgd-1`}
|
||||
>
|
||||
<img
|
||||
alt=""
|
||||
width="20"
|
||||
height="20"
|
||||
src={`/assets/icons/${balance.symbol.toLowerCase()}.svg`}
|
||||
className={`mr-2.5`}
|
||||
/>
|
||||
<Td
|
||||
className={`flex items-center px-4 py-2.5 whitespace-nowrap text-sm text-th-fgd-1`}
|
||||
>
|
||||
<img
|
||||
alt=""
|
||||
width="20"
|
||||
height="20"
|
||||
src={`/assets/icons/${balance.symbol.toLowerCase()}.svg`}
|
||||
className={`mr-2.5`}
|
||||
/>
|
||||
|
||||
{balance.symbol}
|
||||
</Td>
|
||||
<Td
|
||||
className={`px-4 py-2.5 whitespace-nowrap text-sm text-th-fgd-1`}
|
||||
>
|
||||
{balance.marginDeposits.toFixed()}
|
||||
</Td>
|
||||
<Td
|
||||
className={`px-4 py-2.5 whitespace-nowrap text-sm text-th-fgd-1`}
|
||||
>
|
||||
{balance.borrows.toFixed()}
|
||||
</Td>
|
||||
<Td
|
||||
className={`px-4 py-2.5 whitespace-nowrap text-sm text-th-fgd-1`}
|
||||
>
|
||||
{balance.orders}
|
||||
</Td>
|
||||
<Td
|
||||
className={`px-4 py-2.5 whitespace-nowrap text-sm text-th-fgd-1`}
|
||||
>
|
||||
{balance.unsettled}
|
||||
</Td>
|
||||
<Td
|
||||
className={`px-4 py-2.5 whitespace-nowrap text-sm text-th-fgd-1`}
|
||||
>
|
||||
{balance.net.toFixed()}
|
||||
</Td>
|
||||
</Tr>
|
||||
))}
|
||||
{balance.symbol}
|
||||
</Td>
|
||||
<Td
|
||||
className={`px-4 py-2.5 whitespace-nowrap text-sm text-th-fgd-1`}
|
||||
>
|
||||
{balance.marginDeposits.toFixed(tokenConfig.decimals)}
|
||||
</Td>
|
||||
<Td
|
||||
className={`px-4 py-2.5 whitespace-nowrap text-sm text-th-fgd-1`}
|
||||
>
|
||||
{balance.borrows.toFixed(tokenConfig.decimals)}
|
||||
</Td>
|
||||
<Td
|
||||
className={`px-4 py-2.5 whitespace-nowrap text-sm text-th-fgd-1`}
|
||||
>
|
||||
{balance.orders}
|
||||
</Td>
|
||||
<Td
|
||||
className={`px-4 py-2.5 whitespace-nowrap text-sm text-th-fgd-1`}
|
||||
>
|
||||
{balance.unsettled}
|
||||
</Td>
|
||||
<Td
|
||||
className={`px-4 py-2.5 whitespace-nowrap text-sm text-th-fgd-1`}
|
||||
>
|
||||
{balance.net.toFixed(tokenConfig.decimals)}
|
||||
</Td>
|
||||
</Tr>
|
||||
)
|
||||
})}
|
||||
</Tbody>
|
||||
</Table>
|
||||
</div>
|
||||
|
|
|
@ -44,8 +44,8 @@ const ConnectWalletButton = () => {
|
|||
{connected && wallet?.publicKey ? (
|
||||
<Menu>
|
||||
<div className="relative h-full">
|
||||
<Menu.Button className="bg-th-fgd-4 flex items-center justify-center rounded-full w-9 h-9 text-th-fgd-2 focus:outline-none hover:bg-th-bkg-3 hover:text-th-fgd-3">
|
||||
<ProfileIcon className="fill-current h-5 w-5" />
|
||||
<Menu.Button className="bg-th-fgd-4 flex items-center justify-center rounded-full w-10 h-10 text-th-fgd-2 focus:outline-none hover:bg-th-bkg-3 hover:text-th-fgd-3">
|
||||
<ProfileIcon className="fill-current h-6 w-6" />
|
||||
</Menu.Button>
|
||||
<Menu.Items className="bg-th-bkg-1 mt-2 p-1 absolute right-0 shadow-lg outline-none rounded-md w-48 z-20">
|
||||
<Menu.Item>
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
import { StyledMarketInfoLabel } from './MarketHeader'
|
||||
|
||||
const DayHighLow = () => {
|
||||
return (
|
||||
<div className="pr-6">
|
||||
<StyledMarketInfoLabel className="text-center text-th-fgd-3">
|
||||
24h Range
|
||||
</StyledMarketInfoLabel>
|
||||
<div className="text-center text-th-fgd-3 tiny-text">24h Range</div>
|
||||
<div className="flex items-center">
|
||||
<div className="pr-2 text-th-fgd-1 text-xs">$XX.XX</div>
|
||||
<div className="h-1.5 flex rounded bg-th-bkg-3 w-24">
|
||||
|
|
|
@ -5,27 +5,13 @@ import { DotsHorizontalIcon } from '@heroicons/react/outline'
|
|||
import FloatingElement from './FloatingElement'
|
||||
import { ElementTitle } from './styles'
|
||||
import useMangoStore from '../stores/useMangoStore'
|
||||
import {
|
||||
abbreviateAddress,
|
||||
divideBnToNumber,
|
||||
i80f48ToPercent,
|
||||
tokenPrecision,
|
||||
} from '../utils/index'
|
||||
import DepositModal from './DepositModal'
|
||||
import WithdrawModal from './WithdrawModal'
|
||||
// import BorrowModal from './BorrowModal'
|
||||
import Button from './Button'
|
||||
import Tooltip from './Tooltip'
|
||||
import AccountsModal from './AccountsModal'
|
||||
|
||||
export default function MarginBalances() {
|
||||
const selectedMangoGroup = useMangoStore((s) => s.selectedMangoGroup.current)
|
||||
const selectedMangoGroupConfig = useMangoStore(
|
||||
(s) => s.selectedMangoGroup.config
|
||||
)
|
||||
const selectedMangoGroupCache = useMangoStore(
|
||||
(s) => s.selectedMangoGroup.cache
|
||||
)
|
||||
const selectedMangoAccount = useMangoStore(
|
||||
(s) => s.selectedMangoAccount.current
|
||||
)
|
||||
|
@ -58,24 +44,10 @@ export default function MarginBalances() {
|
|||
return (
|
||||
<>
|
||||
<FloatingElement>
|
||||
<div className="flex justify-between pb-5">
|
||||
<div className="w-8 h-8" />
|
||||
<div className="flex flex-col items-center">
|
||||
<ElementTitle noMarignBottom>Mango Account</ElementTitle>
|
||||
{selectedMangoAccount ? (
|
||||
<Link href={'/account'}>
|
||||
<a className="pt-1 text-th-fgd-3 text-xs underline hover:no-underline">
|
||||
{selectedMangoAccount?.publicKey.toString()}
|
||||
</a>
|
||||
</Link>
|
||||
) : connected ? (
|
||||
<div className="pt-1 text-th-fgd-3">
|
||||
Deposit funds to get started
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
<Menu>
|
||||
<div className="relative h-full">
|
||||
<div className="flex justify-center">
|
||||
<ElementTitle noMarignBottom>Mango Account</ElementTitle>
|
||||
<div className="absolute right-0 pr-4">
|
||||
<Menu>
|
||||
<Menu.Button
|
||||
className="flex items-center justify-center rounded-full bg-th-bkg-3 w-8 h-8 hover:text-th-primary focus:outline-none disabled:cursor-not-allowed disabled:opacity-50"
|
||||
disabled={!connected}
|
||||
|
@ -118,10 +90,23 @@ export default function MarginBalances() {
|
|||
</button>
|
||||
</Menu.Item> */}
|
||||
</Menu.Items>
|
||||
</div>
|
||||
</Menu>
|
||||
</Menu>
|
||||
</div>
|
||||
</div>
|
||||
<div className={`flex justify-center items-center`}>
|
||||
<div className="flex justify-center mt-2">
|
||||
{selectedMangoAccount ? (
|
||||
<Link href={'/account'}>
|
||||
<a className="pt-1 text-th-fgd-3 text-xs underline hover:no-underline">
|
||||
{selectedMangoAccount?.publicKey.toString()}
|
||||
</a>
|
||||
</Link>
|
||||
) : connected ? (
|
||||
<div className="pt-1 text-th-fgd-3">
|
||||
Deposit funds to get started
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
<div className="flex justify-center items-center mt-2">
|
||||
<Button
|
||||
onClick={() => setShowDepositModal(true)}
|
||||
className="w-1/2"
|
||||
|
@ -149,10 +134,6 @@ export default function MarginBalances() {
|
|||
onClose={handleCloseWithdraw}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* {showBorrowModal && (
|
||||
<BorrowModal isOpen={showBorrowModal} onClose={handleCloseBorrow} />
|
||||
)} */}
|
||||
{showAccountsModal ? (
|
||||
<AccountsModal
|
||||
onClose={handleCloseAccounts}
|
||||
|
|
|
@ -19,39 +19,35 @@ export default function MarginInfo() {
|
|||
? mangoAccount.computeValue(mangoGroup, mangoCache)
|
||||
: ZERO_I80F48
|
||||
|
||||
const leverage =
|
||||
mangoAccount && equity.gt(ZERO_I80F48)
|
||||
? mangoAccount.getLiabsVal(mangoGroup, mangoCache).div(equity)
|
||||
: 0.0
|
||||
// const leverage =
|
||||
// mangoAccount && equity.gt(ZERO_I80F48)
|
||||
// ? mangoAccount.getLiabsVal(mangoGroup, mangoCache).div(equity)
|
||||
// : 0.0
|
||||
|
||||
return (
|
||||
<FloatingElement showConnect>
|
||||
<div className={!connected && 'filter blur-sm'}>
|
||||
<div className={!connected ? 'filter blur-sm' : undefined}>
|
||||
<ElementTitle>Account</ElementTitle>
|
||||
<div>
|
||||
<div>
|
||||
<div className={`flex justify-between pt-2 pb-2`}>
|
||||
<div className="flex justify-between pt-2 pb-2">
|
||||
<Tooltip content="Account value">
|
||||
<div
|
||||
className={`cursor-help font-normal text-th-fgd-3 border-b border-th-fgd-3 border-dashed border-opacity-20 leading-4 default-transition hover:border-th-bkg-2 hover:text-th-fgd-3`}
|
||||
>
|
||||
<div className="cursor-help font-normal text-th-fgd-3 border-b border-th-fgd-3 border-dashed border-opacity-20 leading-4 default-transition hover:border-th-bkg-2 hover:text-th-fgd-3">
|
||||
Equity
|
||||
</div>
|
||||
</Tooltip>
|
||||
<div className={`text-th-fgd-1`}>${equity.toFixed(2)}</div>
|
||||
<div className="text-th-fgd-1">${equity.toFixed(2)}</div>
|
||||
</div>
|
||||
<div className={`flex justify-between pt-2 pb-2`}>
|
||||
{/* <div className="flex justify-between pt-2 pb-2">
|
||||
<div className="font-normal text-th-fgd-3 leading-4">
|
||||
Leverage
|
||||
</div>
|
||||
<div className={`text-th-fgd-1`}>{leverage.toFixed(2)}x</div>
|
||||
</div>
|
||||
<div className="text-th-fgd-1">{leverage.toFixed(2)}x</div>
|
||||
</div> */}
|
||||
<div className={`flex justify-between pt-2 pb-2`}>
|
||||
<Tooltip content="Leverage">
|
||||
<div className="font-normal text-th-fgd-3 leading-4">
|
||||
Total Assets Value
|
||||
</div>
|
||||
</Tooltip>
|
||||
<div className="font-normal text-th-fgd-3 leading-4">
|
||||
Total Assets Value
|
||||
</div>
|
||||
<div className={`text-th-fgd-1`}>
|
||||
$
|
||||
{mangoAccount
|
||||
|
@ -60,11 +56,9 @@ export default function MarginInfo() {
|
|||
</div>
|
||||
</div>
|
||||
<div className={`flex justify-between pt-2 pb-2`}>
|
||||
<Tooltip content="Leverage">
|
||||
<div className="font-normal text-th-fgd-3 leading-4">
|
||||
Total Liabilities Value
|
||||
</div>
|
||||
</Tooltip>
|
||||
<div className="font-normal text-th-fgd-3 leading-4">
|
||||
Total Liabilities Value
|
||||
</div>
|
||||
<div className={`text-th-fgd-1`}>
|
||||
$
|
||||
{mangoAccount
|
||||
|
@ -73,14 +67,36 @@ export default function MarginInfo() {
|
|||
</div>
|
||||
</div>
|
||||
<div className={`flex justify-between pt-2 pb-2`}>
|
||||
<div className="font-normal text-th-fgd-3 leading-4">
|
||||
Maint Health
|
||||
</div>
|
||||
<div className={`text-th-fgd-1`}>
|
||||
{mangoAccount
|
||||
? mangoAccount
|
||||
.getHealth(mangoGroup, mangoCache, 'Maint')
|
||||
.toFixed(2)
|
||||
: 0}
|
||||
</div>
|
||||
</div>
|
||||
<div className={`flex justify-between pt-2 pb-2`}>
|
||||
<div className="font-normal text-th-fgd-3 leading-4">
|
||||
Init Health
|
||||
</div>
|
||||
<div className={`text-th-fgd-1`}>
|
||||
{mangoAccount
|
||||
? mangoAccount
|
||||
.getHealth(mangoGroup, mangoCache, 'Init')
|
||||
.toFixed(2)
|
||||
: 0}
|
||||
</div>
|
||||
</div>
|
||||
{/* <div className="flex justify-between pt-2 pb-2">
|
||||
<Tooltip content="Must be above 0% to borrow funds">
|
||||
<div
|
||||
className={`cursor-help font-normal text-th-fgd-3 border-b border-th-fgd-3 border-dashed border-opacity-20 leading-4 default-transition hover:border-th-bkg-2 hover:text-th-fgd-3`}
|
||||
>
|
||||
<div className="cursor-help font-normal text-th-fgd-3 border-b border-th-fgd-3 border-dashed border-opacity-20 leading-4 default-transition hover:border-th-bkg-2 hover:text-th-fgd-3">
|
||||
Init Ratio
|
||||
</div>
|
||||
</Tooltip>
|
||||
<div className={`text-th-fgd-1`}>
|
||||
<div className="text-th-fgd-1">
|
||||
{mangoAccount
|
||||
? mangoAccount
|
||||
.getHealthRatio(mangoGroup, mangoCache, 'Init')
|
||||
|
@ -88,7 +104,7 @@ export default function MarginInfo() {
|
|||
: 100.0}
|
||||
%
|
||||
</div>
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
<div className="border border-th-bkg-3 mt-4 p-4 rounded">
|
||||
<div className="flex flex-col">
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import React, { useCallback, useMemo, useState } from 'react'
|
||||
import styled from '@emotion/styled'
|
||||
import useMangoStore from '../stores/useMangoStore'
|
||||
import usePrevious from '../hooks/usePrevious'
|
||||
import useInterval from '../hooks/useInterval'
|
||||
|
@ -9,10 +8,6 @@ import ManualRefresh from './ManualRefresh'
|
|||
import useOraclePrice from '../hooks/useOraclePrice'
|
||||
import DayHighLow from './DayHighLow'
|
||||
|
||||
export const StyledMarketInfoLabel = styled.div`
|
||||
font-size: 0.7rem;
|
||||
`
|
||||
|
||||
const MarketHeader = () => {
|
||||
const oraclePrice = useOraclePrice()
|
||||
const marketConfig = useMangoStore((s) => s.selectedMarket.config)
|
||||
|
@ -75,7 +70,7 @@ const MarketHeader = () => {
|
|||
|
||||
return (
|
||||
<div
|
||||
className={`flex items-end sm:items-center justify-between pt-4 px-6 md:px-6`}
|
||||
className={`flex items-end sm:items-center justify-between pt-4 px-6 md:pb-1 md:pt-8 md:px-6`}
|
||||
>
|
||||
<div className="flex flex-col sm:flex-row sm:items-center">
|
||||
<div className="pb-3 sm:pb-0 pr-8">
|
||||
|
@ -99,17 +94,13 @@ const MarketHeader = () => {
|
|||
</div>
|
||||
<div className="flex items-center">
|
||||
<div className="pr-6">
|
||||
<StyledMarketInfoLabel className="text-th-fgd-3">
|
||||
Oracle price
|
||||
</StyledMarketInfoLabel>
|
||||
<div className="text-th-fgd-3 tiny-text">Oracle price</div>
|
||||
<div className="font-semibold text-th-fgd-1 text-xs">
|
||||
{oraclePrice ? oraclePrice.toFixed(2) : '--'}
|
||||
</div>
|
||||
</div>
|
||||
<div className="pr-4">
|
||||
<StyledMarketInfoLabel className="text-th-fgd-3">
|
||||
24h Change
|
||||
</StyledMarketInfoLabel>
|
||||
<div className="text-th-fgd-3 tiny-text">24h Change</div>
|
||||
{ohlcv && !loading ? (
|
||||
<div
|
||||
className={`font-semibold text-xs ${
|
||||
|
@ -128,15 +119,15 @@ const MarketHeader = () => {
|
|||
)}
|
||||
</div>
|
||||
<div className="pr-6">
|
||||
<StyledMarketInfoLabel className="text-th-fgd-3">
|
||||
24h Vol
|
||||
</StyledMarketInfoLabel>
|
||||
<div className="text-th-fgd-3 tiny-text">24h Vol</div>
|
||||
<div className="font-semibold text-th-fgd-1 text-xs">
|
||||
{ohlcv && !loading && volume ? (
|
||||
volume !== '--' ? (
|
||||
<>
|
||||
{volume.toFixed(2)}
|
||||
<span className="ml-1 text-th-fgd-3">{baseSymbol}</span>
|
||||
<span className="ml-1 text-th-fgd-3 tiny-text">
|
||||
{baseSymbol}
|
||||
</span>
|
||||
</>
|
||||
) : (
|
||||
volume
|
||||
|
@ -150,17 +141,13 @@ const MarketHeader = () => {
|
|||
{selectedMarketName.includes('PERP') ? (
|
||||
<>
|
||||
<div className="pr-6">
|
||||
<StyledMarketInfoLabel className="text-th-fgd-3">
|
||||
Funding (8h Ave)
|
||||
</StyledMarketInfoLabel>
|
||||
<div className="text-th-fgd-3 tiny-text">Funding (8h Ave)</div>
|
||||
<div className="font-semibold text-th-fgd-1 text-xs">
|
||||
0.001%
|
||||
</div>
|
||||
</div>
|
||||
<div className="pr-6">
|
||||
<StyledMarketInfoLabel className="text-th-fgd-3">
|
||||
Open Interest
|
||||
</StyledMarketInfoLabel>
|
||||
<div className="text-th-fgd-3 tiny-text">Open Interest</div>
|
||||
<div className="font-semibold text-th-fgd-1 text-xs">$XXXm</div>
|
||||
</div>
|
||||
</>
|
||||
|
|
|
@ -19,6 +19,7 @@ import {
|
|||
StepMonoIcon,
|
||||
SushiMonoIcon,
|
||||
UniMonoIcon,
|
||||
UsdtMonoIcon,
|
||||
} from './icons'
|
||||
|
||||
const symbolIcons = {
|
||||
|
@ -38,6 +39,7 @@ const symbolIcons = {
|
|||
StepMonoIcon,
|
||||
SushiMonoIcon,
|
||||
UniMonoIcon,
|
||||
UsdtMonoIcon,
|
||||
}
|
||||
|
||||
export default function MarketMenuItem({ menuTitle = '', linksArray = [] }) {
|
||||
|
|
|
@ -125,8 +125,10 @@ export default function MarketPosition() {
|
|||
<span className="text-th-fgd-2">{symbol}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="pb-2">
|
||||
<div className="text-th-fgd-3 tiny-text">Deposits</div>
|
||||
<div className="pb-3">
|
||||
<div className="pb-0.5 text-th-fgd-3 text-xs">
|
||||
Deposits
|
||||
</div>
|
||||
<div className={`text-th-fgd-1`}>
|
||||
{selectedMangoAccount
|
||||
? selectedMangoAccount
|
||||
|
@ -141,8 +143,10 @@ export default function MarketPosition() {
|
|||
: (0).toFixed(tokenPrecision[symbol])}
|
||||
</div>
|
||||
</div>
|
||||
<div className="pb-2">
|
||||
<div className="text-th-fgd-3 tiny-text">Borrows</div>
|
||||
<div className="pb-3">
|
||||
<div className="pb-0.5 text-th-fgd-3 text-xs">
|
||||
Borrows
|
||||
</div>
|
||||
<div className={`text-th-fgd-1`}>
|
||||
{selectedMangoAccount
|
||||
? selectedMangoAccount
|
||||
|
@ -160,7 +164,7 @@ export default function MarketPosition() {
|
|||
{/* <div className="w-1/4">
|
||||
<Tooltip content="Maximum available with leverage">
|
||||
<div
|
||||
className={`cursor-help font-normal pb-0.5 text-th-fgd-3 tiny-text default-transition hover:border-th-bkg-2 hover:text-th-fgd-3`}
|
||||
className={`cursor-help font-normal pb-0.5 text-th-fgd-3 text-xs default-transition hover:border-th-bkg-2 hover:text-th-fgd-3`}
|
||||
>
|
||||
Available
|
||||
</div>
|
||||
|
@ -170,7 +174,7 @@ export default function MarketPosition() {
|
|||
<div>
|
||||
<Tooltip content="Deposit APY and Borrow APR">
|
||||
<div
|
||||
className={`cursor-help font-normal pb-0.5 text-th-fgd-3 tiny-text default-transition hover:border-th-bkg-2 hover:text-th-fgd-3`}
|
||||
className={`cursor-help font-normal pb-0.5 text-th-fgd-3 text-xs default-transition hover:border-th-bkg-2 hover:text-th-fgd-3`}
|
||||
>
|
||||
Interest Rates
|
||||
</div>
|
||||
|
|
|
@ -6,6 +6,15 @@ import { LinkButton } from './Button'
|
|||
import MarketsModal from './MarketsModal'
|
||||
import useLocalStorageState from '../hooks/useLocalStorageState'
|
||||
|
||||
const StyledMarketSelectWrapper = styled.div`
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
|
||||
::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
`
|
||||
|
||||
const StyledMarketTypeToggleWrapper = styled.div`
|
||||
background: rgba(255, 255, 255, 0.12);
|
||||
`
|
||||
|
@ -44,7 +53,7 @@ const MarketSelect = () => {
|
|||
|
||||
return (
|
||||
<>
|
||||
<div className="bg-th-bkg-3 flex h-10">
|
||||
<StyledMarketSelectWrapper className="bg-th-bkg-3 flex h-10">
|
||||
<StyledMarketTypeToggleWrapper className="flex items-center pl-6 md:pl-9 pr-1">
|
||||
<LinkButton
|
||||
className="font-normal text-th-fgd-2 text-xs"
|
||||
|
@ -67,7 +76,7 @@ const MarketSelect = () => {
|
|||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</StyledMarketSelectWrapper>
|
||||
{showMarketsModal ? (
|
||||
<MarketsModal
|
||||
isOpen={showMarketsModal}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import React, { FunctionComponent, useEffect, useState } from 'react'
|
||||
import { ExclamationCircleIcon } from '@heroicons/react/outline'
|
||||
import React, { FunctionComponent, useEffect, useMemo, useState } from 'react'
|
||||
import {
|
||||
ExclamationCircleIcon,
|
||||
InformationCircleIcon,
|
||||
} from '@heroicons/react/outline'
|
||||
// import {
|
||||
// nativeToUi,
|
||||
// sleep,
|
||||
|
@ -18,6 +21,7 @@ import {
|
|||
import Loading from './Loading'
|
||||
import Button from './Button'
|
||||
import Slider from './Slider'
|
||||
import Tooltip from './Tooltip'
|
||||
import { notify } from '../utils/notifications'
|
||||
import useMangoGroupConfig from '../hooks/useMangoGroupConfig'
|
||||
import { deposit } from '../utils/mango'
|
||||
|
@ -36,6 +40,9 @@ const NewAccount: FunctionComponent<NewAccountProps> = ({
|
|||
const [invalidAmountMessage, setInvalidAmountMessage] = useState('')
|
||||
const [sliderPercentage, setSliderPercentage] = useState(0)
|
||||
const [maxButtonTransition, setMaxButtonTransition] = useState(false)
|
||||
const [showNewAccountName, setShowNewAccountName] = useState(true)
|
||||
const [invalidNameMessage, setInvalidNameMessage] = useState('')
|
||||
const [name, setName] = useState('')
|
||||
const walletTokens = useMangoStore((s) => s.wallet.tokens)
|
||||
const actions = useMangoStore((s) => s.actions)
|
||||
|
||||
|
@ -116,6 +123,22 @@ const NewAccount: FunctionComponent<NewAccountProps> = ({
|
|||
validateAmountInput(amount)
|
||||
}
|
||||
|
||||
const validateNameInput = () => {
|
||||
if (name.length >= 33) {
|
||||
setInvalidNameMessage('Account name must be 32 characters or less')
|
||||
}
|
||||
if (name.length === 0) {
|
||||
setInvalidNameMessage('Enter an account name')
|
||||
}
|
||||
}
|
||||
|
||||
const onChangeNameInput = (name) => {
|
||||
setName(name)
|
||||
if (invalidNameMessage) {
|
||||
setInvalidNameMessage('')
|
||||
}
|
||||
}
|
||||
|
||||
// turn off slider transition for dragging slider handle interaction
|
||||
useEffect(() => {
|
||||
if (maxButtonTransition) {
|
||||
|
@ -125,64 +148,103 @@ const NewAccount: FunctionComponent<NewAccountProps> = ({
|
|||
|
||||
return (
|
||||
<>
|
||||
<ElementTitle noMarignBottom>Create Margin Account</ElementTitle>
|
||||
<div className="text-th-fgd-3 text-center pb-4 pt-2">
|
||||
Make a deposit to initialize a new margin account
|
||||
</div>
|
||||
|
||||
<AccountSelect
|
||||
accounts={walletTokens}
|
||||
selectedAccount={selectedAccount}
|
||||
onSelectAccount={handleAccountSelect}
|
||||
/>
|
||||
<div className="flex justify-between pb-2 pt-4">
|
||||
<div className={`text-th-fgd-1`}>Amount</div>
|
||||
<div
|
||||
className="text-th-fgd-1 underline cursor-pointer default-transition hover:text-th-primary hover:no-underline"
|
||||
onClick={setMaxForSelectedAccount}
|
||||
>
|
||||
Max
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex">
|
||||
<Input
|
||||
type="number"
|
||||
min="0"
|
||||
className={`border border-th-fgd-4 flex-grow pr-11`}
|
||||
placeholder="0.00"
|
||||
error={!!invalidAmountMessage}
|
||||
onBlur={(e) => validateAmountInput(e.target.value)}
|
||||
value={inputAmount}
|
||||
onChange={(e) => onChangeAmountInput(e.target.value)}
|
||||
suffix={symbol}
|
||||
/>
|
||||
</div>
|
||||
{invalidAmountMessage ? (
|
||||
<div className="flex items-center pt-1.5 text-th-red">
|
||||
<ExclamationCircleIcon className="h-4 w-4 mr-1.5" />
|
||||
{invalidAmountMessage}
|
||||
</div>
|
||||
) : null}
|
||||
<div className="pt-3 pb-4">
|
||||
<Slider
|
||||
value={sliderPercentage}
|
||||
onChange={(v) => onChangeSlider(v)}
|
||||
step={1}
|
||||
maxButtonTransition={maxButtonTransition}
|
||||
/>
|
||||
</div>
|
||||
<div className={`pt-8 flex justify-center`}>
|
||||
<Button
|
||||
disabled={inputAmount <= 0 || inputAmount > selectedAccount.uiBalance}
|
||||
onClick={handleNewAccountDeposit}
|
||||
className="w-full"
|
||||
>
|
||||
<div className={`flex items-center justify-center`}>
|
||||
{submitting && <Loading className="-ml-1 mr-3" />}
|
||||
Create Account
|
||||
<ElementTitle noMarignBottom>New Account</ElementTitle>
|
||||
{/* {showNewAccountName ? (
|
||||
<>
|
||||
<div className="flex items-center justify-center text-th-fgd-3 pb-4 pt-2">
|
||||
Create a public nickname for your account
|
||||
<Tooltip content="Account names are stored on-chain">
|
||||
<InformationCircleIcon className="h-5 w-5 ml-2 text-th-primary" />
|
||||
</Tooltip>
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
<div className="pb-2 text-th-fgd-1">
|
||||
Account Name <span className="text-th-fgd-3">(Optional)</span>
|
||||
</div>
|
||||
<Input
|
||||
type="text"
|
||||
className={`border border-th-fgd-4 flex-grow`}
|
||||
error={!!invalidNameMessage}
|
||||
placeholder="e.g. Calypso"
|
||||
value={name}
|
||||
onBlur={validateNameInput}
|
||||
onChange={(e) => onChangeNameInput(e.target.value)}
|
||||
/>
|
||||
{invalidNameMessage ? (
|
||||
<div className="flex items-center pt-1.5 text-th-red">
|
||||
<ExclamationCircleIcon className="h-4 w-4 mr-1.5" />
|
||||
{invalidNameMessage}
|
||||
</div>
|
||||
) : null}
|
||||
<Button
|
||||
onClick={() => setShowNewAccountName(false)}
|
||||
disabled={name.length >= 33}
|
||||
className="mt-4 w-full"
|
||||
>
|
||||
Next
|
||||
</Button>
|
||||
</>
|
||||
) : ( */}
|
||||
<>
|
||||
<div className="text-th-fgd-3 text-center pb-4 pt-2">
|
||||
Make a deposit to initialize your new account
|
||||
</div>
|
||||
<AccountSelect
|
||||
accounts={walletTokens}
|
||||
selectedAccount={selectedAccount}
|
||||
onSelectAccount={handleAccountSelect}
|
||||
/>
|
||||
<div className="flex justify-between pb-2 pt-4">
|
||||
<div className={`text-th-fgd-1`}>Amount</div>
|
||||
<div
|
||||
className="text-th-fgd-1 underline cursor-pointer default-transition hover:text-th-primary hover:no-underline"
|
||||
onClick={setMaxForSelectedAccount}
|
||||
>
|
||||
Max
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex">
|
||||
<Input
|
||||
type="number"
|
||||
min="0"
|
||||
className={`border border-th-fgd-4 flex-grow pr-11`}
|
||||
placeholder="0.00"
|
||||
error={!!invalidAmountMessage}
|
||||
onBlur={(e) => validateAmountInput(e.target.value)}
|
||||
value={inputAmount}
|
||||
onChange={(e) => onChangeAmountInput(e.target.value)}
|
||||
suffix={symbol}
|
||||
/>
|
||||
</div>
|
||||
{invalidAmountMessage ? (
|
||||
<div className="flex items-center pt-1.5 text-th-red">
|
||||
<ExclamationCircleIcon className="h-4 w-4 mr-1.5" />
|
||||
{invalidAmountMessage}
|
||||
</div>
|
||||
) : null}
|
||||
<div className="pt-3 pb-4">
|
||||
<Slider
|
||||
value={sliderPercentage}
|
||||
onChange={(v) => onChangeSlider(v)}
|
||||
step={1}
|
||||
maxButtonTransition={maxButtonTransition}
|
||||
/>
|
||||
</div>
|
||||
<div className={`pt-8 flex justify-center`}>
|
||||
<Button
|
||||
disabled={
|
||||
inputAmount <= 0 || inputAmount > selectedAccount.uiBalance
|
||||
}
|
||||
onClick={handleNewAccountDeposit}
|
||||
className="w-full"
|
||||
>
|
||||
<div className={`flex items-center justify-center`}>
|
||||
{submitting && <Loading className="-ml-1 mr-3" />}
|
||||
Create New Account
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
{/* )} */}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -188,20 +188,11 @@ const OpenOrdersTable = () => {
|
|||
</Td>
|
||||
<Td className={`px-4 py-1 whitespace-nowrap text-left`}>
|
||||
<div className={`flex justify-end`}>
|
||||
{/* Todo: support order modification */}
|
||||
{/* <Button
|
||||
onClick={() =>
|
||||
console.log('trigger modify order modal')
|
||||
}
|
||||
className={`text-xs pt-0 pb-0 h-8 pl-3 pr-3`}
|
||||
>
|
||||
Modify
|
||||
</Button> */}
|
||||
<Button
|
||||
onClick={() =>
|
||||
handleCancelOrder(order, market.account)
|
||||
}
|
||||
className={`ml-3 text-xs pt-0 pb-0 h-8 pl-3 pr-3`}
|
||||
className="ml-3 text-xs pt-0 pb-0 h-8 pl-3 pr-3"
|
||||
>
|
||||
{cancelId + '' === order.orderId + '' ? (
|
||||
<Loading />
|
||||
|
|
|
@ -1,19 +1,30 @@
|
|||
import useMangoStore from '../stores/useMangoStore'
|
||||
import useMangoStore, { mangoClient } from '../stores/useMangoStore'
|
||||
import { Table, Thead, Tbody, Tr, Th, Td } from 'react-super-responsive-table'
|
||||
import {
|
||||
getMarketByPublicKey,
|
||||
nativeI80F48ToUi,
|
||||
nativeToUi,
|
||||
PerpAccount,
|
||||
PerpMarket,
|
||||
ZERO_I80F48,
|
||||
} from '@blockworks-foundation/mango-client'
|
||||
import { useMemo } from 'react'
|
||||
import Button from './Button'
|
||||
import { notify } from '../utils/notifications'
|
||||
import { QUOTE_INDEX } from '@blockworks-foundation/mango-client/lib/src/MangoGroup'
|
||||
import BN from 'bn.js'
|
||||
import SideBadge from './SideBadge'
|
||||
import { useState } from 'react'
|
||||
import Loading from './Loading'
|
||||
|
||||
const PositionsTable = () => {
|
||||
const actions = useMangoStore((s) => s.actions)
|
||||
const groupConfig = useMangoStore((s) => s.selectedMangoGroup.config)
|
||||
const mangoGroup = useMangoStore((s) => s.selectedMangoGroup.current)
|
||||
const mangoAccount = useMangoStore((s) => s.selectedMangoAccount.current)
|
||||
const mangoCache = useMangoStore((s) => s.selectedMangoGroup.cache)
|
||||
const allMarkets = useMangoStore((s) => s.selectedMangoGroup.markets)
|
||||
const [settlingPerpAcc, setSettlingPerpAcc] = useState(null)
|
||||
|
||||
const perpMarkets = useMemo(
|
||||
() =>
|
||||
mangoGroup
|
||||
|
@ -23,128 +34,187 @@ const PositionsTable = () => {
|
|||
: [],
|
||||
[mangoGroup]
|
||||
)
|
||||
const perpAccounts = useMemo(
|
||||
() =>
|
||||
mangoAccount
|
||||
? groupConfig.perpMarkets.map(
|
||||
(m) => mangoAccount.perpAccounts[m.marketIndex]
|
||||
)
|
||||
: [],
|
||||
[mangoAccount]
|
||||
const perpAccounts = mangoAccount
|
||||
? groupConfig.perpMarkets.map((m) => {
|
||||
return {
|
||||
perpAccount: mangoAccount.perpAccounts[m.marketIndex],
|
||||
marketIndex: m.marketIndex,
|
||||
}
|
||||
})
|
||||
: []
|
||||
const filteredPerpAccounts = perpAccounts.filter(
|
||||
({ perpAccount }) =>
|
||||
!(
|
||||
perpAccount.quotePosition.eq(ZERO_I80F48) &&
|
||||
perpAccount.basePosition.eq(new BN(0))
|
||||
)
|
||||
)
|
||||
|
||||
console.log({ perpMarkets, perpAccounts })
|
||||
const handleSettlePnl = async (
|
||||
perpMarket: PerpMarket,
|
||||
perpAccount: PerpAccount
|
||||
) => {
|
||||
const mangoAccount = useMangoStore.getState().selectedMangoAccount.current
|
||||
const mangoGroup = useMangoStore.getState().selectedMangoGroup.current
|
||||
const wallet = useMangoStore.getState().wallet.current
|
||||
const marketIndex = mangoGroup.getPerpMarketIndex(perpMarket.publicKey)
|
||||
setSettlingPerpAcc(perpAccount)
|
||||
try {
|
||||
const txid = await mangoClient.settlePnl(
|
||||
mangoGroup,
|
||||
mangoAccount,
|
||||
perpMarket,
|
||||
mangoGroup.rootBankAccounts[QUOTE_INDEX],
|
||||
mangoCache.priceCache[marketIndex].price,
|
||||
wallet
|
||||
)
|
||||
actions.fetchMangoAccounts()
|
||||
notify({
|
||||
title: 'Successfully settled PNL',
|
||||
description: '',
|
||||
txid,
|
||||
})
|
||||
} catch (e) {
|
||||
console.log('Error settling PNL: ', `${e}`, `${perpAccount}`)
|
||||
notify({
|
||||
title: 'Error settling PNL',
|
||||
description: e.message,
|
||||
txid: e.txid,
|
||||
type: 'error',
|
||||
})
|
||||
} finally {
|
||||
setSettlingPerpAcc(null)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`flex flex-col py-4`}>
|
||||
<div className={`-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8`}>
|
||||
<div className={`align-middle inline-block min-w-full sm:px-6 lg:px-8`}>
|
||||
{perpAccounts.length ? (
|
||||
<div
|
||||
className={`overflow-hidden border-b border-th-bkg-2 sm:rounded-md`}
|
||||
>
|
||||
<Table className={`min-w-full divide-y divide-th-bkg-2`}>
|
||||
<div className="flex flex-col py-4">
|
||||
<div className="-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
|
||||
<div className="align-middle inline-block min-w-full sm:px-6 lg:px-8">
|
||||
{filteredPerpAccounts.length ? (
|
||||
<div className="overflow-hidden border-b border-th-bkg-2 sm:rounded-m">
|
||||
<Table className="min-w-full divide-y divide-th-bkg-2">
|
||||
<Thead>
|
||||
<Tr className="text-th-fgd-3">
|
||||
<Th
|
||||
scope="col"
|
||||
className={`px-6 py-2 text-left font-normal`}
|
||||
>
|
||||
Market
|
||||
<Th scope="col" className="px-6 py-2 text-left font-normal">
|
||||
Perp Market
|
||||
</Th>
|
||||
<Th
|
||||
scope="col"
|
||||
className={`px-6 py-2 text-left font-normal`}
|
||||
>
|
||||
<Th scope="col" className="px-2 py-2 text-left font-normal">
|
||||
Side
|
||||
</Th>
|
||||
<Th scope="col" className="px-2 py-2 text-left font-normal">
|
||||
Base Position
|
||||
</Th>
|
||||
<Th
|
||||
scope="col"
|
||||
className={`px-6 py-2 text-left font-normal`}
|
||||
>
|
||||
<Th scope="col" className="px-2 py-2 text-left font-normal">
|
||||
Quote Position
|
||||
</Th>
|
||||
<Th
|
||||
scope="col"
|
||||
className={`px-6 py-2 text-left font-normal`}
|
||||
>
|
||||
<Th scope="col" className="px-2 py-2 text-left font-normal">
|
||||
Unrealized PnL
|
||||
</Th>
|
||||
<Th
|
||||
scope="col"
|
||||
className={`px-6 py-2 text-left font-normal`}
|
||||
>
|
||||
<Th scope="col" className="px-2 py-2 text-left font-normal">
|
||||
Health
|
||||
</Th>
|
||||
<Th scope="col" className={`relative px-6 py-2.5`}>
|
||||
<span className={`sr-only`}>Edit</span>
|
||||
</Th>
|
||||
</Tr>
|
||||
</Thead>
|
||||
<Tbody>
|
||||
{perpAccounts.map((acc, index) => {
|
||||
const market = perpMarkets[index]
|
||||
const marketConfig = getMarketByPublicKey(
|
||||
groupConfig,
|
||||
market.perpMarket
|
||||
)
|
||||
{filteredPerpAccounts.map(
|
||||
({ perpAccount, marketIndex }, index) => {
|
||||
const perpMarketInfo = perpMarkets[marketIndex]
|
||||
const marketConfig = getMarketByPublicKey(
|
||||
groupConfig,
|
||||
perpMarketInfo.perpMarket
|
||||
)
|
||||
|
||||
const marketCache =
|
||||
mangoCache.perpMarketCache[marketConfig.marketIndex]
|
||||
const price =
|
||||
mangoCache.priceCache[marketConfig.marketIndex].price
|
||||
const perpMarket = allMarkets[
|
||||
marketConfig.publicKey.toString()
|
||||
] as PerpMarket
|
||||
const marketCache =
|
||||
mangoCache.perpMarketCache[marketIndex]
|
||||
const price = mangoCache.priceCache[marketIndex].price
|
||||
const perpMarket = allMarkets[
|
||||
marketConfig.publicKey.toString()
|
||||
] as PerpMarket
|
||||
console.log('perp account: ', perpAccount)
|
||||
console.log('perp market: ', perpMarket)
|
||||
|
||||
return (
|
||||
<Tr
|
||||
key={`${index}`}
|
||||
className={`border-b border-th-bkg-3
|
||||
return (
|
||||
<Tr
|
||||
key={`${marketIndex}`}
|
||||
className={`border-b border-th-bkg-3
|
||||
${index % 2 === 0 ? `bg-th-bkg-3` : `bg-th-bkg-2`}
|
||||
`}
|
||||
>
|
||||
<Td
|
||||
className={`px-6 py-2.5 whitespace-nowrap text-sm text-th-fgd-1`}
|
||||
>
|
||||
{marketConfig.name}
|
||||
</Td>
|
||||
<Td
|
||||
className={`px-6 py-2.5 whitespace-nowrap text-sm text-th-fgd-1`}
|
||||
>
|
||||
{perpMarket.baseLotsToNumber(acc.basePosition)}
|
||||
</Td>
|
||||
<Td
|
||||
className={`px-6 py-2.5 whitespace-nowrap text-sm text-th-fgd-1`}
|
||||
>
|
||||
{nativeI80F48ToUi(
|
||||
acc.quotePosition,
|
||||
marketConfig.quoteDecimals
|
||||
).toFixed()}
|
||||
</Td>
|
||||
<Td
|
||||
className={`px-6 py-2.5 whitespace-nowrap text-sm text-th-fgd-1`}
|
||||
>
|
||||
$
|
||||
{nativeI80F48ToUi(
|
||||
acc.getPnl(market, price),
|
||||
marketConfig.quoteDecimals
|
||||
).toFixed()}
|
||||
</Td>
|
||||
<Td
|
||||
className={`px-6 py-2.5 whitespace-nowrap text-sm text-th-fgd-1`}
|
||||
>
|
||||
{acc
|
||||
.getHealth(
|
||||
market,
|
||||
price,
|
||||
market.maintAssetWeight,
|
||||
market.maintLiabWeight,
|
||||
marketCache.longFunding,
|
||||
marketCache.shortFunding
|
||||
)
|
||||
.toFixed(3)}
|
||||
</Td>
|
||||
</Tr>
|
||||
)
|
||||
})}
|
||||
<Td className="px-6 py-1 whitespace-nowrap text-sm text-th-fgd-1">
|
||||
<div className="flex items-center">
|
||||
<img
|
||||
alt=""
|
||||
width="20"
|
||||
height="20"
|
||||
src={`/assets/icons/${marketConfig.baseSymbol.toLowerCase()}.svg`}
|
||||
className={`mr-2.5`}
|
||||
/>
|
||||
<div>{marketConfig.name}</div>
|
||||
</div>
|
||||
</Td>
|
||||
<Td className="px-2 py-1 whitespace-nowrap text-sm text-th-fgd-1">
|
||||
<SideBadge
|
||||
side={
|
||||
perpAccount.basePosition.gt(new BN(0))
|
||||
? 'long'
|
||||
: 'short'
|
||||
}
|
||||
/>
|
||||
</Td>
|
||||
<Td className="px-2 py-1 whitespace-nowrap text-sm text-th-fgd-1">
|
||||
{perpMarket.baseLotsToNumber(
|
||||
perpAccount.basePosition
|
||||
)}
|
||||
</Td>
|
||||
<Td className="px-2 py-1 whitespace-nowrap text-sm text-th-fgd-1">
|
||||
{nativeI80F48ToUi(
|
||||
perpAccount.quotePosition,
|
||||
marketConfig.quoteDecimals
|
||||
).toFixed()}
|
||||
</Td>
|
||||
<Td className="px-2 py-1 whitespace-nowrap text-sm text-th-fgd-1">
|
||||
$
|
||||
{nativeI80F48ToUi(
|
||||
perpAccount.getPnl(perpMarketInfo, price),
|
||||
marketConfig.quoteDecimals
|
||||
).toFixed()}
|
||||
</Td>
|
||||
<Td className="px-2 py-1 whitespace-nowrap text-sm text-th-fgd-1">
|
||||
{perpAccount
|
||||
.getHealth(
|
||||
perpMarketInfo,
|
||||
price,
|
||||
perpMarketInfo.maintAssetWeight,
|
||||
perpMarketInfo.maintLiabWeight,
|
||||
marketCache.longFunding,
|
||||
marketCache.shortFunding
|
||||
)
|
||||
.toFixed(3)}
|
||||
</Td>
|
||||
<Td className="px-6 py-1 whitespace-nowrap text-sm text-th-fgd-1">
|
||||
<div className="flex justify-end">
|
||||
<Button
|
||||
onClick={() =>
|
||||
handleSettlePnl(perpMarket, perpAccount)
|
||||
}
|
||||
className="ml-3 text-xs pt-0 pb-0 h-8 pl-3 pr-3"
|
||||
>
|
||||
{settlingPerpAcc == perpAccount ? (
|
||||
<Loading />
|
||||
) : (
|
||||
<span>Settle PNL</span>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</Td>
|
||||
</Tr>
|
||||
)
|
||||
}
|
||||
)}
|
||||
</Tbody>
|
||||
</Table>
|
||||
</div>
|
||||
|
|
|
@ -1,15 +1,24 @@
|
|||
import { useState } from 'react'
|
||||
import { useCallback, useState } from 'react'
|
||||
import { MenuIcon, XIcon } from '@heroicons/react/outline'
|
||||
import { abbreviateAddress } from '../utils/index'
|
||||
import MenuItem from './MenuItem'
|
||||
import ThemeSwitch from './ThemeSwitch'
|
||||
import useMangoStore from '../stores/useMangoStore'
|
||||
import ConnectWalletButton from './ConnectWalletButton'
|
||||
import NavDropMenu from './NavDropMenu'
|
||||
import AccountsModal from './AccountsModal'
|
||||
import Button from './Button'
|
||||
|
||||
const TopBar = () => {
|
||||
const connected = useMangoStore((s) => s.wallet.connected)
|
||||
const mangoAccount = useMangoStore((s) => s.selectedMangoAccount.current)
|
||||
const wallet = useMangoStore((s) => s.wallet.current)
|
||||
const [showMenu, setShowMenu] = useState(false)
|
||||
const [showAccountsModal, setShowAccountsModal] = useState(false)
|
||||
|
||||
const handleCloseAccounts = useCallback(() => {
|
||||
setShowAccountsModal(false)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -47,8 +56,21 @@ const TopBar = () => {
|
|||
<div className={`pl-2`}>
|
||||
<ThemeSwitch />
|
||||
</div>
|
||||
{mangoAccount ? (
|
||||
<div className="pl-3">
|
||||
<Button
|
||||
className="pb-1 pt-1 pl-2 pr-2 text-xs"
|
||||
onClick={() => setShowAccountsModal(true)}
|
||||
>
|
||||
<div className="font-normal text-th-primary tiny-text">
|
||||
Account
|
||||
</div>
|
||||
{abbreviateAddress(mangoAccount.publicKey)}
|
||||
</Button>
|
||||
</div>
|
||||
) : null}
|
||||
<div className="flex">
|
||||
<div className="hidden md:block pl-4">
|
||||
<div className="hidden md:block pl-3">
|
||||
<ConnectWalletButton />
|
||||
</div>
|
||||
</div>
|
||||
|
@ -106,6 +128,12 @@ const TopBar = () => {
|
|||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
{showAccountsModal ? (
|
||||
<AccountsModal
|
||||
onClose={handleCloseAccounts}
|
||||
isOpen={showAccountsModal}
|
||||
/>
|
||||
) : null}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { ArrowSmDownIcon } from '@heroicons/react/solid'
|
||||
import BN from 'bn.js'
|
||||
import useTradeHistory from '../hooks/useTradeHistory'
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
|
@ -14,8 +15,14 @@ const TradeHistoryTable = () => {
|
|||
const { items, requestSort, sortConfig } = useSortableData(tradeHistory)
|
||||
const marketConfig = useMangoStore((s) => s.selectedMarket.config)
|
||||
|
||||
const renderTradeDateTime = (timestamp) => {
|
||||
const date = new Date(timestamp)
|
||||
const renderTradeDateTime = (timestamp: BN | string) => {
|
||||
let date
|
||||
if (timestamp instanceof BN) {
|
||||
date = new Date(timestamp.toNumber() * 1000)
|
||||
} else {
|
||||
date = new Date(timestamp)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div>{date.toLocaleDateString()}</div>
|
||||
|
@ -25,12 +32,12 @@ const TradeHistoryTable = () => {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className={`flex flex-col py-4`}>
|
||||
<div className={`-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8`}>
|
||||
<div className={`align-middle inline-block min-w-full sm:px-6 lg:px-8`}>
|
||||
<div className="flex flex-col py-4">
|
||||
<div className="-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
|
||||
<div className="align-middle inline-block min-w-full sm:px-6 lg:px-8">
|
||||
{tradeHistory && tradeHistory.length ? (
|
||||
<div className={`shadow overflow-hidden border-b border-th-bkg-2`}>
|
||||
<Table className={`min-w-full divide-y divide-th-bkg-2`}>
|
||||
<div className="shadow overflow-hidden border-b border-th-bkg-2">
|
||||
<Table className="min-w-full divide-y divide-th-bkg-2">
|
||||
<Thead>
|
||||
<Tr className="text-th-fgd-3 text-xs">
|
||||
<Th
|
||||
|
@ -53,10 +60,7 @@ const TradeHistoryTable = () => {
|
|||
/>
|
||||
</LinkButton>
|
||||
</Th>
|
||||
<Th
|
||||
scope="col"
|
||||
className={`px-6 py-3 text-left font-normal`}
|
||||
>
|
||||
<Th scope="col" className="px-6 py-3 text-left font-normal">
|
||||
<LinkButton
|
||||
className="flex items-center no-underline"
|
||||
onClick={() => requestSort('side')}
|
||||
|
@ -73,10 +77,7 @@ const TradeHistoryTable = () => {
|
|||
/>
|
||||
</LinkButton>
|
||||
</Th>
|
||||
<Th
|
||||
scope="col"
|
||||
className={`px-6 py-3 text-left font-normal`}
|
||||
>
|
||||
<Th scope="col" className="px-6 py-3 text-left font-normal">
|
||||
<LinkButton
|
||||
className="flex items-center no-underline"
|
||||
onClick={() => requestSort('size')}
|
||||
|
@ -93,10 +94,7 @@ const TradeHistoryTable = () => {
|
|||
/>
|
||||
</LinkButton>
|
||||
</Th>
|
||||
<Th
|
||||
scope="col"
|
||||
className={`px-6 py-3 text-left font-normal`}
|
||||
>
|
||||
<Th scope="col" className="px-6 py-3 text-left font-normal">
|
||||
<LinkButton
|
||||
className="flex items-center no-underline"
|
||||
onClick={() => requestSort('price')}
|
||||
|
@ -113,10 +111,7 @@ const TradeHistoryTable = () => {
|
|||
/>
|
||||
</LinkButton>
|
||||
</Th>
|
||||
<Th
|
||||
scope="col"
|
||||
className={`px-6 py-3 text-left font-normal`}
|
||||
>
|
||||
<Th scope="col" className="px-6 py-3 text-left font-normal">
|
||||
<LinkButton
|
||||
className="flex items-center no-underline"
|
||||
onClick={() => requestSort('value')}
|
||||
|
@ -133,10 +128,7 @@ const TradeHistoryTable = () => {
|
|||
/>
|
||||
</LinkButton>
|
||||
</Th>
|
||||
<Th
|
||||
scope="col"
|
||||
className={`px-6 py-3 text-left font-normal`}
|
||||
>
|
||||
<Th scope="col" className="px-6 py-3 text-left font-normal">
|
||||
<LinkButton
|
||||
className="flex items-center no-underline"
|
||||
onClick={() => requestSort('liquidity')}
|
||||
|
@ -153,10 +145,7 @@ const TradeHistoryTable = () => {
|
|||
/>
|
||||
</LinkButton>
|
||||
</Th>
|
||||
<Th
|
||||
scope="col"
|
||||
className={`px-6 py-3 text-left font-normal`}
|
||||
>
|
||||
<Th scope="col" className="px-6 py-3 text-left font-normal">
|
||||
<LinkButton
|
||||
className="flex items-center no-underline"
|
||||
onClick={() => requestSort('feeCost')}
|
||||
|
@ -173,15 +162,12 @@ const TradeHistoryTable = () => {
|
|||
/>
|
||||
</LinkButton>
|
||||
</Th>
|
||||
<Th
|
||||
scope="col"
|
||||
className={`px-6 py-3 text-left font-normal`}
|
||||
>
|
||||
<Th scope="col" className="px-6 py-3 text-left font-normal">
|
||||
<LinkButton
|
||||
className="flex items-center no-underline"
|
||||
onClick={() => requestSort('loadTimestamp')}
|
||||
>
|
||||
Approx Date
|
||||
Approx Time
|
||||
<ArrowSmDownIcon
|
||||
className={`default-transition flex-shrink-0 h-4 w-4 ml-1 ${
|
||||
sortConfig?.key === 'loadTimestamp'
|
||||
|
@ -203,57 +189,43 @@ const TradeHistoryTable = () => {
|
|||
${index % 2 === 0 ? `bg-th-bkg-3` : `bg-th-bkg-2`}
|
||||
`}
|
||||
>
|
||||
<Td
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-th-fgd-1`}
|
||||
>
|
||||
<Td className="px-6 py-4 whitespace-nowrap text-sm text-th-fgd-1">
|
||||
<div className="flex items-center">
|
||||
<img
|
||||
alt=""
|
||||
width="20"
|
||||
height="20"
|
||||
src={`/assets/icons/${trade.marketName
|
||||
.split('/')[0]
|
||||
.split(/-|\//)[0]
|
||||
.toLowerCase()}.svg`}
|
||||
className={`mr-2.5`}
|
||||
/>
|
||||
<div>{trade.marketName}</div>
|
||||
</div>
|
||||
</Td>
|
||||
<Td
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-th-fgd-1`}
|
||||
>
|
||||
<Td className="px-6 py-4 whitespace-nowrap text-sm text-th-fgd-1">
|
||||
<SideBadge side={trade.side} />
|
||||
</Td>
|
||||
<Td
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-th-fgd-1`}
|
||||
>
|
||||
<Td className="px-6 py-4 whitespace-nowrap text-sm text-th-fgd-1">
|
||||
{trade.size}
|
||||
</Td>
|
||||
<Td
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-th-fgd-1`}
|
||||
>
|
||||
<Td className="px-6 py-4 whitespace-nowrap text-sm text-th-fgd-1">
|
||||
{trade.price}
|
||||
</Td>
|
||||
<Td
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-th-fgd-1`}
|
||||
>
|
||||
${(trade.price * trade.size).toFixed(2)}
|
||||
<Td className="px-6 py-4 whitespace-nowrap text-sm text-th-fgd-1">
|
||||
${trade.value.toFixed(2)}
|
||||
</Td>
|
||||
<Td
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-th-fgd-1`}
|
||||
>
|
||||
<Td className="px-6 py-4 whitespace-nowrap text-sm text-th-fgd-1">
|
||||
{trade.liquidity}
|
||||
</Td>
|
||||
<Td
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-th-fgd-1`}
|
||||
>
|
||||
{trade.feeCost}
|
||||
<Td className="px-6 py-4 whitespace-nowrap text-sm text-th-fgd-1">
|
||||
${trade.feeCost}
|
||||
</Td>
|
||||
<Td
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-th-fgd-1`}
|
||||
>
|
||||
{trade.loadTimestamp
|
||||
? renderTradeDateTime(trade.loadTimestamp)
|
||||
<Td className="px-6 py-4 whitespace-nowrap text-sm text-th-fgd-1">
|
||||
{trade.loadTimestamp || trade.timestamp
|
||||
? renderTradeDateTime(
|
||||
trade.loadTimestamp || trade.timestamp
|
||||
)
|
||||
: 'Recent'}
|
||||
</Td>
|
||||
</Tr>
|
||||
|
@ -262,18 +234,11 @@ const TradeHistoryTable = () => {
|
|||
</Table>
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
className={`w-full text-center py-6 bg-th-bkg-1 text-th-fgd-3 rounded-md`}
|
||||
>
|
||||
<div className="w-full text-center py-6 bg-th-bkg-1 text-th-fgd-3 rounded-md">
|
||||
No {marketConfig.name} trade history.
|
||||
{asPath === '/account' ? (
|
||||
<Link href={'/'}>
|
||||
<a
|
||||
className={`inline-flex ml-2 py-0
|
||||
`}
|
||||
>
|
||||
Make a trade
|
||||
</a>
|
||||
<a className="inline-flex ml-2 py-0">Make a trade</a>
|
||||
</Link>
|
||||
) : null}
|
||||
</div>
|
||||
|
|
|
@ -32,6 +32,7 @@ export const defaultLayouts = {
|
|||
],
|
||||
lg: [
|
||||
{ i: 'tvChart', x: 0, y: 0, w: 8, h: 29, minW: 2 },
|
||||
{ i: 'depositWithdraw', x: 8, y: 0, w: 4, h: 6 },
|
||||
{ i: 'marketPosition', x: 8, y: 0, w: 4, h: 15, minW: 2 },
|
||||
{ i: 'marginInfo', x: 8, y: 1, w: 4, h: 14, minW: 2 },
|
||||
{ i: 'orderbook', x: 0, y: 2, w: 4, h: 17, minW: 2 },
|
||||
|
@ -41,6 +42,7 @@ export const defaultLayouts = {
|
|||
],
|
||||
md: [
|
||||
{ i: 'tvChart', x: 0, y: 0, w: 8, h: 29, minW: 2 },
|
||||
{ i: 'depositWithdraw', x: 8, y: 0, w: 4, h: 6 },
|
||||
{ i: 'marketPosition', x: 8, y: 0, w: 4, h: 15, minW: 2 },
|
||||
{ i: 'marginInfo', x: 8, y: 1, w: 4, h: 14, minW: 2 },
|
||||
{ i: 'orderbook', x: 0, y: 2, w: 4, h: 17, minW: 2 },
|
||||
|
@ -50,6 +52,7 @@ export const defaultLayouts = {
|
|||
],
|
||||
sm: [
|
||||
{ i: 'tvChart', x: 0, y: 0, w: 12, h: 25, minW: 6 },
|
||||
{ i: 'depositWithdraw', x: 0, y: 1, w: 6, h: 15 },
|
||||
{ i: 'marketPosition', x: 0, y: 1, w: 6, h: 15, minW: 2 },
|
||||
{ i: 'marginInfo', x: 6, y: 1, w: 6, h: 15, minW: 2 },
|
||||
{ i: 'tradeForm', x: 0, y: 2, w: 12, h: 13, minW: 3 },
|
||||
|
@ -86,11 +89,11 @@ const TradePageGrid = () => {
|
|||
const [mounted, setMounted] = useState(false)
|
||||
useEffect(() => setMounted(true), [])
|
||||
if (!mounted) return null
|
||||
|
||||
// TODO enable savedLayouts
|
||||
return (
|
||||
<ResponsiveGridLayout
|
||||
className="layout"
|
||||
layouts={savedLayouts || defaultLayouts}
|
||||
layouts={defaultLayouts}
|
||||
breakpoints={{ xl: 1600, lg: 1200, md: 1110, sm: 768, xs: 0 }}
|
||||
cols={{ xl: 12, lg: 12, md: 12, sm: 12, xs: 1 }}
|
||||
rowHeight={15}
|
||||
|
|
|
@ -10,7 +10,7 @@ import TradeHistoryTable from './TradeHistoryTable'
|
|||
const TABS = [
|
||||
'Balances',
|
||||
'Open Orders',
|
||||
'Positions',
|
||||
'Perp Positions',
|
||||
/*'Fee Discounts'*/
|
||||
'Trade History',
|
||||
]
|
||||
|
@ -72,7 +72,7 @@ const TabContent = ({ activeTab }) => {
|
|||
return <BalancesTable />
|
||||
case 'Trade History':
|
||||
return <TradeHistoryTable />
|
||||
case 'Positions':
|
||||
case 'Perp Positions':
|
||||
return <PositionsTable />
|
||||
// case 'Fee Discounts':
|
||||
// return <FeeDiscountsTable />
|
||||
|
|
|
@ -65,7 +65,7 @@ const WithdrawModal: FunctionComponent<WithdrawModalProps> = ({
|
|||
const [maxButtonTransition, setMaxButtonTransition] = useState(false)
|
||||
|
||||
const actions = useMangoStore((s) => s.actions)
|
||||
const selectedMangoGroup = useMangoStore((s) => s.selectedMangoGroup.current)
|
||||
const mangoGroup = useMangoStore((s) => s.selectedMangoGroup.current)
|
||||
const selectedMangoAccount = useMangoStore(
|
||||
(s) => s.selectedMangoAccount.current
|
||||
)
|
||||
|
@ -77,34 +77,33 @@ const WithdrawModal: FunctionComponent<WithdrawModalProps> = ({
|
|||
() => tokens.find((t) => t.symbol === withdrawTokenSymbol),
|
||||
[withdrawTokenSymbol, tokens]
|
||||
)
|
||||
const tokenIndex = selectedMangoGroup.getTokenIndex(token.mintKey)
|
||||
const tokenIndex = mangoGroup.getTokenIndex(token.mintKey)
|
||||
|
||||
useEffect(() => {
|
||||
if (!selectedMangoGroup || !selectedMangoAccount || !withdrawTokenSymbol)
|
||||
return
|
||||
if (!mangoGroup || !selectedMangoAccount || !withdrawTokenSymbol) return
|
||||
|
||||
const mintDecimals = selectedMangoGroup.tokens[tokenIndex].decimals
|
||||
const mintDecimals = mangoGroup.tokens[tokenIndex].decimals
|
||||
const deposits = selectedMangoAccount.getUiDeposit(
|
||||
mangoCache.rootBankCache[tokenIndex],
|
||||
selectedMangoGroup,
|
||||
mangoGroup,
|
||||
tokenIndex
|
||||
)
|
||||
const borrows = selectedMangoAccount.getUiBorrow(
|
||||
mangoCache.rootBankCache[tokenIndex],
|
||||
selectedMangoGroup,
|
||||
mangoGroup,
|
||||
tokenIndex
|
||||
)
|
||||
|
||||
const maxValForSelectedAsset = getDepositsForSelectedAsset().mul(
|
||||
selectedMangoGroup.getPrice(tokenIndex, mangoCache) || ONE_I80F48
|
||||
mangoGroup.getPrice(tokenIndex, mangoCache) || ONE_I80F48
|
||||
)
|
||||
|
||||
const currentAssetsVal = selectedMangoAccount
|
||||
.getAssetsVal(selectedMangoGroup, mangoCache, 'Init')
|
||||
.getAssetsVal(mangoGroup, mangoCache, 'Init')
|
||||
.sub(maxValForSelectedAsset)
|
||||
|
||||
const currentLiabsVal = selectedMangoAccount.getLiabsVal(
|
||||
selectedMangoGroup,
|
||||
mangoGroup,
|
||||
mangoCache,
|
||||
'Init'
|
||||
)
|
||||
|
@ -117,7 +116,9 @@ const WithdrawModal: FunctionComponent<WithdrawModalProps> = ({
|
|||
const amountToWithdraw = includeBorrow
|
||||
? liabsAvail
|
||||
.div(
|
||||
selectedMangoGroup.getPrice(tokenIndex, mangoCache) || ONE_I80F48
|
||||
(mangoGroup.getPrice(tokenIndex, mangoCache) || ONE_I80F48).mul(
|
||||
mangoGroup.spotMarkets[tokenIndex].initLiabWeight
|
||||
)
|
||||
)
|
||||
.add(getDepositsForSelectedAsset())
|
||||
: getDepositsForSelectedAsset()
|
||||
|
@ -152,18 +153,10 @@ const WithdrawModal: FunctionComponent<WithdrawModalProps> = ({
|
|||
.div(I80F48.fromNumber(Math.pow(10, mintDecimals)))
|
||||
.div(mangoCache.rootBankCache[tokenIndex].borrowIndex)
|
||||
|
||||
const assetsVal = simulation.getAssetsVal(
|
||||
selectedMangoGroup,
|
||||
mangoCache,
|
||||
'Init'
|
||||
)
|
||||
const liabsVal = simulation.getLiabsVal(
|
||||
selectedMangoGroup,
|
||||
mangoCache,
|
||||
'Init'
|
||||
)
|
||||
const assetsVal = simulation.getAssetsVal(mangoGroup, mangoCache, 'Init')
|
||||
const liabsVal = simulation.getLiabsVal(mangoGroup, mangoCache, 'Init')
|
||||
// const collateralRatio = simulation.getCollateralRatio(
|
||||
// selectedMangoGroup,
|
||||
// mangoGroup,
|
||||
// prices
|
||||
// )
|
||||
// const leverage = 1 / Math.max(0, collateralRatio - 1)
|
||||
|
@ -177,7 +170,7 @@ const WithdrawModal: FunctionComponent<WithdrawModalProps> = ({
|
|||
inputAmount,
|
||||
tokenIndex,
|
||||
selectedMangoAccount,
|
||||
selectedMangoGroup,
|
||||
mangoGroup,
|
||||
mangoCache,
|
||||
])
|
||||
|
||||
|
@ -186,7 +179,7 @@ const WithdrawModal: FunctionComponent<WithdrawModalProps> = ({
|
|||
|
||||
withdraw({
|
||||
amount: Number(inputAmount),
|
||||
token: selectedMangoGroup.tokens[tokenIndex].mint,
|
||||
token: mangoGroup.tokens[tokenIndex].mint,
|
||||
allowBorrow: includeBorrow,
|
||||
})
|
||||
.then((txid: string) => {
|
||||
|
@ -206,6 +199,7 @@ const WithdrawModal: FunctionComponent<WithdrawModalProps> = ({
|
|||
console.error('Error withdrawing:', err)
|
||||
notify({
|
||||
title: 'Could not perform withdraw',
|
||||
description: err.message,
|
||||
txid: err.txid,
|
||||
type: 'error',
|
||||
})
|
||||
|
@ -222,7 +216,7 @@ const WithdrawModal: FunctionComponent<WithdrawModalProps> = ({
|
|||
const getDepositsForSelectedAsset = (): I80F48 => {
|
||||
return selectedMangoAccount.getUiDeposit(
|
||||
mangoCache.rootBankCache[tokenIndex],
|
||||
selectedMangoGroup,
|
||||
mangoGroup,
|
||||
tokenIndex
|
||||
)
|
||||
}
|
||||
|
@ -394,7 +388,7 @@ const WithdrawModal: FunctionComponent<WithdrawModalProps> = ({
|
|||
{selectedMangoAccount
|
||||
.getUiDeposit(
|
||||
mangoCache.rootBankCache[tokenIndex],
|
||||
selectedMangoGroup,
|
||||
mangoGroup,
|
||||
tokenIndex
|
||||
)
|
||||
.toFixed(tokenPrecision[withdrawTokenSymbol])}
|
||||
|
@ -604,18 +598,10 @@ const WithdrawModal: FunctionComponent<WithdrawModalProps> = ({
|
|||
</div>
|
||||
<div className="flex justify-between pb-2">
|
||||
<div className="text-th-fgd-4">Leverage</div>
|
||||
{/* <div className="text-th-fgd-1">
|
||||
{simulation.leverage.toFixed(2)}x
|
||||
</div> */}
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<div className="text-th-fgd-4">Collateral Ratio</div>
|
||||
{/* <div className="text-th-fgd-1">
|
||||
{simulation.collateralRatio * 100 < 200
|
||||
? Math.floor(simulation.collateralRatio * 100)
|
||||
: '>200'}
|
||||
%
|
||||
</div> */}
|
||||
<div className="text-th-fgd-1">
|
||||
{/* {simulation.leverage.toFixed(2)}x */}
|
||||
X.XXx
|
||||
</div>
|
||||
</div>
|
||||
{simulation.liabsVal > 0.05 ? (
|
||||
<div className="flex justify-between pt-2">
|
||||
|
|
|
@ -570,3 +570,21 @@ export const UniMonoIcon = ({ className }) => {
|
|||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export const UsdtMonoIcon = ({ className }) => {
|
||||
return (
|
||||
<svg
|
||||
className={`${className}`}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 32 32"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path d="M16.023 15.7763C17.3269 15.7763 17.9114 15.7414 18.0245 15.7329L18.0207 15.732C22.0208 15.5547 25.0047 14.8571 25.0047 14.0237C25.0047 13.1903 22.0199 12.4927 18.0207 12.3145V15.0391C17.9085 15.0494 17.2854 15.1013 16.0409 15.1013C15.0039 15.1013 14.2535 15.057 13.9914 15.0381V12.3126C9.98372 12.4917 6.99236 13.1884 6.99236 14.0237C6.99236 14.859 9.98372 15.5566 13.9914 15.7329C14.2497 15.7452 14.986 15.7763 16.023 15.7763Z" />
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M0.0244761 14.4741L5.8592 2.21826C5.8783 2.17698 5.90893 2.14211 5.94741 2.11786C5.98588 2.0936 6.03055 2.081 6.07603 2.08156H25.9258C25.971 2.08144 26.0154 2.09436 26.0535 2.11877C26.0916 2.14318 26.1219 2.17804 26.1407 2.2192L31.9755 14.475C31.9977 14.5206 32.0047 14.5721 31.9955 14.622C31.9864 14.6719 31.9615 14.7175 31.9245 14.7522L16.1664 29.8514C16.1216 29.8943 16.062 29.9183 16 29.9183C15.9379 29.9183 15.8783 29.8943 15.8336 29.8514L0.075385 14.7513C0.0384323 14.7166 0.0135572 14.6709 0.00439729 14.6211C-0.00476259 14.5712 0.00227334 14.5197 0.0244761 14.4741ZM18.0245 9.59369V12.0326C22.5521 12.242 25.954 13.1385 25.954 14.2141C25.954 15.2898 22.5488 16.1873 18.0235 16.3957V24.214H13.9904V16.3985C9.45484 16.1892 6.04395 15.2917 6.04395 14.2151C6.04395 13.1385 9.45484 12.24 13.9904 12.0317V9.59369H8.41026V5.87451H23.6056V9.59369H18.0245Z"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import { Balances } from '../@types/types'
|
||||
import { nativeToUi } from '@blockworks-foundation/mango-client'
|
||||
import { nativeToUi, QUOTE_INDEX } from '@blockworks-foundation/mango-client'
|
||||
import useMangoStore from '../stores/useMangoStore'
|
||||
import { sumBy } from 'lodash'
|
||||
import { QUOTE_INDEX } from '@blockworks-foundation/mango-client/lib/src/MangoGroup'
|
||||
import { I80F48 } from '@blockworks-foundation/mango-client/lib/src/fixednum'
|
||||
|
||||
export function useBalances(): Balances[] {
|
||||
|
@ -122,7 +121,7 @@ export function useBalances(): Balances[] {
|
|||
.sub(quoteMeta.borrows)
|
||||
.sub(I80F48.fromNumber(quoteInOrders))
|
||||
|
||||
return baseBalances.concat([
|
||||
return [
|
||||
{
|
||||
market: null,
|
||||
key: `${quoteMeta.symbol}${quoteMeta.symbol}`,
|
||||
|
@ -133,5 +132,5 @@ export function useBalances(): Balances[] {
|
|||
unsettled,
|
||||
net,
|
||||
},
|
||||
])
|
||||
].concat(baseBalances)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { useEffect } from 'react'
|
||||
import { useCallback, useEffect } from 'react'
|
||||
import { AccountInfo } from '@solana/web3.js'
|
||||
import useMangoStore, {
|
||||
DEFAULT_CONNECTION,
|
||||
|
@ -78,28 +78,30 @@ const useHydrateStore = () => {
|
|||
}, [selectedMarket])
|
||||
|
||||
// fetch filled trades for selected market
|
||||
useInterval(() => {
|
||||
async function fetchFills() {
|
||||
const market = useMangoStore.getState().selectedMarket.current
|
||||
|
||||
if (!market) {
|
||||
return null
|
||||
}
|
||||
try {
|
||||
const loadedFills = await selectedMarket.loadFills(
|
||||
DEFAULT_CONNECTION,
|
||||
10000
|
||||
)
|
||||
setMangoStore((state) => {
|
||||
state.selectedMarket.fills = loadedFills
|
||||
})
|
||||
} catch (err) {
|
||||
console.log('Error fetching fills:', err)
|
||||
}
|
||||
const fetchFills = useCallback(async () => {
|
||||
if (!selectedMarket) {
|
||||
return null
|
||||
}
|
||||
try {
|
||||
const loadedFills = await selectedMarket.loadFills(
|
||||
DEFAULT_CONNECTION,
|
||||
10000
|
||||
)
|
||||
setMangoStore((state) => {
|
||||
state.selectedMarket.fills = loadedFills
|
||||
})
|
||||
} catch (err) {
|
||||
console.log('Error fetching fills:', err)
|
||||
}
|
||||
}, [selectedMarket, setMangoStore])
|
||||
|
||||
useInterval(() => {
|
||||
fetchFills()
|
||||
}, _SLOW_REFRESH_INTERVAL)
|
||||
|
||||
useEffect(() => {
|
||||
fetchFills()
|
||||
}, [fetchFills])
|
||||
}
|
||||
|
||||
export default useHydrateStore
|
||||
|
|
|
@ -63,10 +63,9 @@ const useMangoStats = () => {
|
|||
borrowInterest: rootBank
|
||||
.getBorrowRate(mangoGroup)
|
||||
.mul(I80F48.fromNumber(100)),
|
||||
utilization:
|
||||
totalDeposits > I80F48.fromNumber(0)
|
||||
? totalBorrows.div(totalDeposits)
|
||||
: I80F48.fromNumber(0),
|
||||
utilization: totalDeposits.gt(I80F48.fromNumber(0))
|
||||
? totalBorrows.div(totalDeposits)
|
||||
: I80F48.fromNumber(0),
|
||||
}
|
||||
})
|
||||
setLatestStats(latestStats)
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
import {
|
||||
getMarketIndexBySymbol,
|
||||
MangoGroup,
|
||||
} from '@blockworks-foundation/mango-client'
|
||||
import { PublicKey } from '@solana/web3.js'
|
||||
import useMangoStore from '../stores/useMangoStore'
|
||||
|
||||
const byTimestamp = (a, b) => {
|
||||
|
@ -6,14 +11,33 @@ const byTimestamp = (a, b) => {
|
|||
)
|
||||
}
|
||||
|
||||
const parsedPerpEvent = (event) => {
|
||||
const parsedPerpEvent = (
|
||||
mangoGroup: MangoGroup,
|
||||
mangoAccountPk: PublicKey,
|
||||
event
|
||||
) => {
|
||||
const mangoGroupConfig = useMangoStore.getState().selectedMangoGroup.config
|
||||
const marketIndex = getMarketIndexBySymbol(
|
||||
mangoGroupConfig,
|
||||
event.marketName.split(/-|\//)[0]
|
||||
)
|
||||
const perpMarketInfo = mangoGroup.perpMarkets[marketIndex]
|
||||
const maker = event.maker.equals(mangoAccountPk)
|
||||
const orderId = maker ? event.makerOrderId : event.takerOrderId
|
||||
const value = event.quantity * event.price
|
||||
const feeRate = maker
|
||||
? perpMarketInfo.makerFee.toNumber()
|
||||
: perpMarketInfo.takerFee.toNumber()
|
||||
|
||||
return {
|
||||
...event,
|
||||
key: `${event.orderId}-${event.uuid}`,
|
||||
liquidity: event.maker ? 'Maker' : 'Taker',
|
||||
value: event.price * event.size,
|
||||
key: orderId.toString(),
|
||||
liquidity: maker ? 'Maker' : 'Taker',
|
||||
size: event.quantity,
|
||||
price: event.price,
|
||||
value,
|
||||
feeCost: (feeRate * value).toFixed(4),
|
||||
side: event.side,
|
||||
feeCost: 0.0,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,14 +51,18 @@ const parsedSerumEvent = (event) => {
|
|||
}
|
||||
}
|
||||
|
||||
const formatTradeHistory = (newTradeHistory) => {
|
||||
const formatTradeHistory = (
|
||||
selectedMangoGroup,
|
||||
mangoAccountPk: PublicKey,
|
||||
newTradeHistory
|
||||
) => {
|
||||
return newTradeHistory
|
||||
.flat()
|
||||
.map((trade) => {
|
||||
if (trade.eventFlags) {
|
||||
return parsedSerumEvent(trade)
|
||||
} else {
|
||||
return parsedPerpEvent(trade)
|
||||
return parsedPerpEvent(selectedMangoGroup, mangoAccountPk, trade)
|
||||
}
|
||||
})
|
||||
.sort(byTimestamp)
|
||||
|
@ -73,11 +101,19 @@ export const useTradeHistory = () => {
|
|||
)
|
||||
const newTradeHistory = [...newFills, ...tradeHistory]
|
||||
if (newFills.length > 0 && newTradeHistory.length !== allTrades.length) {
|
||||
return formatTradeHistory(newTradeHistory)
|
||||
return formatTradeHistory(
|
||||
selectedMangoGroup,
|
||||
mangoAccount.publicKey,
|
||||
newTradeHistory
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return formatTradeHistory(tradeHistory)
|
||||
return formatTradeHistory(
|
||||
selectedMangoGroup,
|
||||
mangoAccount.publicKey,
|
||||
tradeHistory
|
||||
)
|
||||
}
|
||||
|
||||
export default useTradeHistory
|
||||
|
|
|
@ -93,7 +93,6 @@ export default function useWallet() {
|
|||
useEffect(() => {
|
||||
if (!wallet) return
|
||||
wallet.on('connect', async () => {
|
||||
console.log('connected wallet')
|
||||
sleep(250)
|
||||
await actions.fetchMangoAccounts()
|
||||
setMangoStore((state) => {
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import {
|
||||
CurrencyDollarIcon,
|
||||
DuplicateIcon,
|
||||
ExternalLinkIcon,
|
||||
LinkIcon,
|
||||
PencilIcon,
|
||||
} from '@heroicons/react/outline'
|
||||
import {
|
||||
getTokenBySymbol,
|
||||
|
@ -12,7 +14,7 @@ import {
|
|||
} from '@blockworks-foundation/mango-client'
|
||||
import useMangoStore from '../stores/useMangoStore'
|
||||
import { useBalances } from '../hooks/useBalances'
|
||||
import { abbreviateAddress } from '../utils'
|
||||
import { abbreviateAddress, copyToClipboard } from '../utils'
|
||||
import PageBodyContainer from '../components/PageBodyContainer'
|
||||
import TopBar from '../components/TopBar'
|
||||
import AccountAssets from '../components/account-page/AccountAssets'
|
||||
|
@ -21,7 +23,10 @@ import AccountOrders from '../components/account-page/AccountOrders'
|
|||
import AccountHistory from '../components/account-page/AccountHistory'
|
||||
import AccountsModal from '../components/AccountsModal'
|
||||
import AccountOverview from '../components/account-page/AccountOverview'
|
||||
import AccountNameModal from '../components/AccountNameModal'
|
||||
import Button from '../components/Button'
|
||||
import EmptyState from '../components/EmptyState'
|
||||
import { MangoAccount } from '@blockworks-foundation/mango-client'
|
||||
|
||||
const TABS = [
|
||||
'Overview',
|
||||
|
@ -33,12 +38,23 @@ const TABS = [
|
|||
'Activity',
|
||||
]
|
||||
|
||||
export function getMarginInfoString(marginAccount: MangoAccount) {
|
||||
return marginAccount?.info
|
||||
? String.fromCharCode(...marginAccount?.info).replaceAll(
|
||||
String.fromCharCode(0),
|
||||
''
|
||||
)
|
||||
: ''
|
||||
}
|
||||
|
||||
export default function Account() {
|
||||
const [activeTab, setActiveTab] = useState(TABS[0])
|
||||
const [showAccountsModal, setShowAccountsModal] = useState(false)
|
||||
const [portfolio, setPortfolio] = useState([])
|
||||
const allMarkets = useMangoStore((s) => s.selectedMangoGroup.markets)
|
||||
const balances = useBalances()
|
||||
const [showNameModal, setShowNameModal] = useState(false)
|
||||
const [isCopied, setIsCopied] = useState(false)
|
||||
const connected = useMangoStore((s) => s.wallet.connected)
|
||||
const groupConfig = useMangoStore((s) => s.selectedMangoGroup.config)
|
||||
const mangoAccount = useMangoStore((s) => s.selectedMangoAccount.current)
|
||||
|
@ -46,6 +62,9 @@ export default function Account() {
|
|||
const mangoCache = useMangoStore((s) => s.selectedMangoGroup.cache)
|
||||
const wallet = useMangoStore((s) => s.wallet.current)
|
||||
|
||||
const marginInfoString = getMarginInfoString(mangoAccount)
|
||||
const [accountName, setAccountName] = useState(marginInfoString)
|
||||
|
||||
const handleTabChange = (tabName) => {
|
||||
setActiveTab(tabName)
|
||||
}
|
||||
|
@ -124,42 +143,77 @@ export default function Account() {
|
|||
})
|
||||
setPortfolio(portfolio.sort((a, b) => b.value - a.value))
|
||||
}, [perpAccounts])
|
||||
const handleCopyPublicKey = (code) => {
|
||||
setIsCopied(true)
|
||||
copyToClipboard(code)
|
||||
}
|
||||
const handleCloseNameModal = useCallback(() => {
|
||||
setShowNameModal(false)
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (isCopied) {
|
||||
const timer = setTimeout(() => {
|
||||
setIsCopied(false)
|
||||
}, 1500)
|
||||
return () => clearTimeout(timer)
|
||||
}
|
||||
}, [isCopied])
|
||||
|
||||
return (
|
||||
<div className={`bg-th-bkg-1 text-th-fgd-1 transition-all`}>
|
||||
<TopBar />
|
||||
<PageBodyContainer>
|
||||
<div className="flex flex-col sm:flex-row items-center justify-between pt-8 pb-3 sm:pb-6 md:pt-10">
|
||||
<h1 className={`text-th-fgd-1 text-2xl font-semibold`}>Account</h1>
|
||||
{mangoAccount ? (
|
||||
<div className="divide-x divide-th-fgd-4 flex justify-center w-full pt-4 sm:pt-0 sm:justify-end">
|
||||
<div className="pr-4 text-xs text-th-fgd-1">
|
||||
<div className="pb-0.5 text-2xs text-th-fgd-3">Owner</div>
|
||||
<a
|
||||
className="default-transition flex items-center text-th-fgd-2"
|
||||
href={`https://explorer.solana.com/address/${mangoAccount?.owner}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<span>{abbreviateAddress(mangoAccount?.owner)}</span>
|
||||
<ExternalLinkIcon className={`h-3 w-3 ml-1`} />
|
||||
</a>
|
||||
</div>
|
||||
<div className="pl-4 text-xs text-th-fgd-1">
|
||||
<div className="pb-0.5 text-2xs text-th-fgd-3">
|
||||
Margin Account
|
||||
<>
|
||||
<div className="flex flex-col sm:flex-row sm:items-end pb-4 md:pb-0">
|
||||
<h1 className={`font-semibold mr-3 text-th-fgd-1 text-2xl`}>
|
||||
{accountName ? accountName : 'Account'}
|
||||
</h1>
|
||||
<div className="flex items-center pb-0.5 text-th-fgd-3 ">
|
||||
{abbreviateAddress(mangoAccount.publicKey)}
|
||||
<DuplicateIcon
|
||||
className="cursor-pointer default-transition h-4 w-4 ml-1.5 hover:text-th-fgd-1"
|
||||
onClick={() => handleCopyPublicKey(mangoAccount.publicKey)}
|
||||
/>
|
||||
{isCopied ? (
|
||||
<div className="ml-2 text-th-fgd-2 text-xs">Copied!</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
{/* Re-instate when added to program code */}
|
||||
|
||||
{/* <Button
|
||||
className="text-xs flex flex-grow items-center justify-center mr-2 pt-0 pb-0 h-8 pl-3 pr-3"
|
||||
onClick={() => setShowNameModal(true)}
|
||||
>
|
||||
<div className="flex items-center">
|
||||
<PencilIcon className="h-4 w-4 mr-1.5" />
|
||||
{accountName ? 'Edit Name' : 'Add Name'}
|
||||
</div>
|
||||
</Button> */}
|
||||
<a
|
||||
className="default-transition flex items-center text-th-fgd-2"
|
||||
className="border border-th-fgd-4 bg-th-bkg-2 default-transition flex flex-grow font-bold h-8 items-center justify-center pl-3 pr-3 rounded-md text-th-fgd-1 text-xs hover:bg-th-bkg-3 hover:text-th-fgd-1 focus:outline-none"
|
||||
href={`https://explorer.solana.com/address/${mangoAccount?.publicKey}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<span>{abbreviateAddress(mangoAccount?.publicKey)}</span>
|
||||
<ExternalLinkIcon className={`h-3 w-3 ml-1`} />
|
||||
<span>Explorer</span>
|
||||
<ExternalLinkIcon className={`h-4 w-4 ml-1.5`} />
|
||||
</a>
|
||||
<Button
|
||||
className="text-xs flex flex-grow items-center justify-center ml-2 pt-0 pb-0 h-8 pl-3 pr-3"
|
||||
onClick={() => setShowAccountsModal(true)}
|
||||
>
|
||||
<div className="flex items-center">
|
||||
<CurrencyDollarIcon className="h-4 w-4 mr-1.5" />
|
||||
Accounts
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
<div className="bg-th-bkg-2 overflow-none p-6 rounded-lg">
|
||||
|
@ -211,6 +265,13 @@ export default function Account() {
|
|||
isOpen={showAccountsModal}
|
||||
/>
|
||||
) : null}
|
||||
{showNameModal ? (
|
||||
<AccountNameModal
|
||||
accountName={accountName}
|
||||
isOpen={showNameModal}
|
||||
onClose={handleCloseNameModal}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<<<<<<< HEAD
|
||||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M16.023 15.7763C17.3269 15.7763 17.9114 15.7414 18.0245 15.7329L18.0207 15.732C22.0208 15.5547 25.0047 14.8571 25.0047 14.0237C25.0047 13.1903 22.0199 12.4927 18.0207 12.3145V15.0391C17.9085 15.0494 17.2854 15.1013 16.0409 15.1013C15.0039 15.1013 14.2535 15.057 13.9914 15.0381V12.3126C9.98372 12.4917 6.99236 13.1884 6.99236 14.0237C6.99236 14.859 9.98372 15.5566 13.9914 15.7329C14.2497 15.7452 14.986 15.7763 16.023 15.7763Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.0244761 14.4741L5.8592 2.21826C5.8783 2.17698 5.90893 2.14211 5.94741 2.11786C5.98588 2.0936 6.03055 2.081 6.07603 2.08156H25.9258C25.971 2.08144 26.0154 2.09436 26.0535 2.11877C26.0916 2.14318 26.1219 2.17804 26.1407 2.2192L31.9755 14.475C31.9977 14.5206 32.0047 14.5721 31.9955 14.622C31.9864 14.6719 31.9615 14.7175 31.9245 14.7522L16.1664 29.8514C16.1216 29.8943 16.062 29.9183 16 29.9183C15.9379 29.9183 15.8783 29.8943 15.8336 29.8514L0.075385 14.7513C0.0384323 14.7166 0.0135572 14.6709 0.00439729 14.6211C-0.00476259 14.5712 0.00227334 14.5197 0.0244761 14.4741ZM18.0245 9.59369V12.0326C22.5521 12.242 25.954 13.1385 25.954 14.2141C25.954 15.2898 22.5488 16.1873 18.0235 16.3957V24.214H13.9904V16.3985C9.45484 16.1892 6.04395 15.2917 6.04395 14.2151C6.04395 13.1385 9.45484 12.24 13.9904 12.0317V9.59369H8.41026V5.87451H23.6056V9.59369H18.0245Z" fill="white"/>
|
||||
</svg>
|
||||
=======
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32">
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<circle cx="16" cy="16" r="16" fill="#26A17B"/>
|
||||
<path fill="#FFF" d="M17.922 17.383v-.002c-.11.008-.677.042-1.942.042-1.01 0-1.721-.03-1.971-.042v.003c-3.888-.171-6.79-.848-6.79-1.658 0-.809 2.902-1.486 6.79-1.66v2.644c.254.018.982.061 1.988.061 1.207 0 1.812-.05 1.925-.06v-2.643c3.88.173 6.775.85 6.775 1.658 0 .81-2.895 1.485-6.775 1.657m0-3.59v-2.366h5.414V7.819H8.595v3.608h5.414v2.365c-4.4.202-7.709 1.074-7.709 2.118 0 1.044 3.309 1.915 7.709 2.118v7.582h3.913v-7.584c4.393-.202 7.694-1.073 7.694-2.116 0-1.043-3.301-1.914-7.694-2.117"/>
|
||||
</g>
|
||||
</svg>
|
||||
>>>>>>> 2e33486dbb113439af571877c0066425d0d88a20
|
|
@ -1 +1,4 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32"><g fill="none" fill-rule="evenodd"><circle cx="16" cy="16" r="16" fill="#26A17B"/><path fill="#FFF" d="M17.922 17.383v-.002c-.11.008-.677.042-1.942.042-1.01 0-1.721-.03-1.971-.042v.003c-3.888-.171-6.79-.848-6.79-1.658 0-.809 2.902-1.486 6.79-1.66v2.644c.254.018.982.061 1.988.061 1.207 0 1.812-.05 1.925-.06v-2.643c3.88.173 6.775.85 6.775 1.658 0 .81-2.895 1.485-6.775 1.657m0-3.59v-2.366h5.414V7.819H8.595v3.608h5.414v2.365c-4.4.202-7.709 1.074-7.709 2.118 0 1.044 3.309 1.915 7.709 2.118v7.582h3.913v-7.584c4.393-.202 7.694-1.073 7.694-2.116 0-1.043-3.301-1.914-7.694-2.117"/></g></svg>
|
||||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.8592 2.21826L0.0244761 14.4741C0.00227334 14.5197 -0.00476259 14.5712 0.00439729 14.6211C0.0135572 14.6709 0.0384323 14.7166 0.075385 14.7513L15.8336 29.8514C15.8783 29.8943 15.9379 29.9183 16 29.9183C16.062 29.9183 16.1216 29.8943 16.1664 29.8514L31.9245 14.7522C31.9615 14.7175 31.9864 14.6719 31.9955 14.622C32.0047 14.5721 31.9977 14.5206 31.9755 14.475L26.1407 2.2192C26.1219 2.17804 26.0916 2.14318 26.0535 2.11877C26.0154 2.09436 25.971 2.08144 25.9258 2.08156H6.07603C6.03055 2.081 5.98588 2.0936 5.94741 2.11786C5.90893 2.14211 5.8783 2.17698 5.8592 2.21826V2.21826Z" fill="#50AF95"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M18.0245 15.7329C17.9114 15.7414 17.3269 15.7763 16.023 15.7763C14.986 15.7763 14.2497 15.7452 13.9914 15.7329C9.98372 15.5566 6.99236 14.859 6.99236 14.0237C6.99236 13.1884 9.98372 12.4917 13.9914 12.3126V15.0381C14.2535 15.057 15.0039 15.1013 16.0409 15.1013C17.2854 15.1013 17.9085 15.0494 18.0207 15.0391V12.3145C22.0199 12.4927 25.0047 13.1903 25.0047 14.0237C25.0047 14.8571 22.0208 15.5547 18.0207 15.732L18.0245 15.7329ZM18.0245 12.0326V9.59369H23.6056V5.87451H8.41026V9.59369H13.9904V12.0317C9.45484 12.24 6.04395 13.1385 6.04395 14.2151C6.04395 15.2917 9.45484 16.1892 13.9904 16.3985V24.214H18.0235V16.3957C22.5488 16.1873 25.954 15.2898 25.954 14.2141C25.954 13.1385 22.5516 12.2409 18.0235 12.0317L18.0245 12.0326Z" fill="white"/>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 651 B After Width: | Height: | Size: 1.5 KiB |
|
@ -37,7 +37,7 @@ export const ENDPOINTS: EndpointInfo[] = [
|
|||
},
|
||||
{
|
||||
name: 'devnet',
|
||||
url: 'https://api.devnet.solana.com',
|
||||
url: 'https://mango.devnet.rpcpool.com',
|
||||
websocket: 'https://api.devnet.solana.com',
|
||||
custom: false,
|
||||
},
|
||||
|
@ -56,7 +56,7 @@ export const WEBSOCKET_CONNECTION = new Connection(
|
|||
'processed' as Commitment
|
||||
)
|
||||
|
||||
const DEFAULT_MANGO_GROUP_NAME = 'mango_test_v3.8'
|
||||
const DEFAULT_MANGO_GROUP_NAME = 'devnet.0'
|
||||
const DEFAULT_MANGO_GROUP_CONFIG = Config.ids().getGroup(
|
||||
CLUSTER,
|
||||
DEFAULT_MANGO_GROUP_NAME
|
||||
|
@ -299,7 +299,7 @@ const useMangoStore = create<MangoStore>((set, get) => ({
|
|||
const mangoCache = await mangoGroup.loadCache(DEFAULT_CONNECTION)
|
||||
const allMarketConfigs = getAllMarkets(mangoGroupConfig)
|
||||
const allMarketPks = allMarketConfigs.map((m) => m.publicKey)
|
||||
|
||||
console.log('mango group: ', mangoGroup)
|
||||
const allMarketAccountInfos = await getMultipleAccounts(
|
||||
DEFAULT_CONNECTION,
|
||||
allMarketPks
|
||||
|
|
|
@ -79,7 +79,8 @@ button {
|
|||
}
|
||||
|
||||
.tiny-text {
|
||||
font-size: 0.7rem;
|
||||
font-size: 0.65rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* Chart */
|
||||
|
|
22
yarn.lock
22
yarn.lock
|
@ -994,8 +994,8 @@
|
|||
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
|
||||
|
||||
"@blockworks-foundation/mango-client@git+https://github.com/blockworks-foundation/mango-client-v3.git":
|
||||
version "3.0.1"
|
||||
resolved "git+https://github.com/blockworks-foundation/mango-client-v3.git#e632d3fdc4cf7c70dbf5137de81265a5767af6c1"
|
||||
version "3.0.2"
|
||||
resolved "git+https://github.com/blockworks-foundation/mango-client-v3.git#34dc2dbb28c23a657855b9c4cf0b25a972673b80"
|
||||
dependencies:
|
||||
"@project-serum/serum" "^0.13.45"
|
||||
"@project-serum/sol-wallet-adapter" "^0.2.0"
|
||||
|
@ -1891,14 +1891,14 @@
|
|||
integrity sha512-7eQ2xYLLI/LsicL2nejW9Wyko3lcpN6O/z0ZLHrEQsg280zIdCv1t/0m6UtBjUHokCGBQ3gYTbHzDkZ1xOBwwg==
|
||||
|
||||
"@types/node@*":
|
||||
version "16.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.4.0.tgz#2c219eaa3b8d1e4d04f4dd6e40bc68c7467d5272"
|
||||
integrity sha512-HrJuE7Mlqcjj+00JqMWpZ3tY8w7EUd+S0U3L1+PQSWiXZbOgyQDvi+ogoUxaHApPJq5diKxYBQwA3iIlNcPqOg==
|
||||
version "16.4.6"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.4.6.tgz#1734d119dfa8fede5606d35ae10f9fc9c84d889b"
|
||||
integrity sha512-FKyawK3o5KL16AwbeFajen8G4K3mmqUrQsehn5wNKs8IzlKHE8TfnSmILXVMVziAEcnB23u1RCFU1NT6hSyr7Q==
|
||||
|
||||
"@types/node@^12.12.54":
|
||||
version "12.20.16"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.16.tgz#1acf34f6456208f495dac0434dd540488d17f991"
|
||||
integrity sha512-6CLxw83vQf6DKqXxMPwl8qpF8I7THFZuIwLt4TnNsumxkp1VsRZWT8txQxncT/Rl2UojTsFzWgDG4FRMwafrlA==
|
||||
version "12.20.17"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.17.tgz#ffd44c2801fc527a6fe6e86bc9b900261df1c87e"
|
||||
integrity sha512-so8EHl4S6MmatPS0f9sE1ND94/ocbcEshW5OpyYthRqeRpiYyW2uXYTo/84kmfdfeNrDycARkvuiXl6nO40NGg==
|
||||
|
||||
"@types/node@^14.14.25":
|
||||
version "14.17.3"
|
||||
|
@ -7583,9 +7583,9 @@ regenerate@^1.4.0:
|
|||
integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==
|
||||
|
||||
regenerator-runtime@^0.13.4:
|
||||
version "0.13.7"
|
||||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55"
|
||||
integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==
|
||||
version "0.13.9"
|
||||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52"
|
||||
integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==
|
||||
|
||||
regenerator-transform@^0.14.2:
|
||||
version "0.14.5"
|
||||
|
|
Loading…
Reference in New Issue