merge main

This commit is contained in:
saml33 2023-08-13 21:21:08 +10:00
commit 8ed1ab81bc
47 changed files with 959 additions and 730 deletions

View File

@ -118,7 +118,7 @@ function BorrowForm({ onSuccess, token }: BorrowFormProps) {
if (!mangoAccount || !group || !publicKey) return if (!mangoAccount || !group || !publicKey) return
setSubmitting(true) setSubmitting(true)
try { try {
const tx = await client.tokenWithdraw( const { signature: tx, slot } = await client.tokenWithdraw(
group, group,
mangoAccount, mangoAccount,
bank!.mint, bank!.mint,
@ -130,7 +130,7 @@ function BorrowForm({ onSuccess, token }: BorrowFormProps) {
type: 'success', type: 'success',
txid: tx, txid: tx,
}) })
await actions.reloadMangoAccount() await actions.reloadMangoAccount(slot)
actions.fetchWalletTokens(publicKey) actions.fetchWalletTokens(publicKey)
setSubmitting(false) setSubmitting(false)
onSuccess() onSuccess()

View File

@ -130,7 +130,7 @@ function DepositForm({ onSuccess, token }: DepositFormProps) {
setSubmitting(true) setSubmitting(true)
try { try {
const tx = await client.tokenDeposit( const { signature: tx, slot } = await client.tokenDeposit(
group, group,
mangoAccount, mangoAccount,
bank.mint, bank.mint,
@ -142,7 +142,7 @@ function DepositForm({ onSuccess, token }: DepositFormProps) {
txid: tx, txid: tx,
}) })
await actions.reloadMangoAccount() await actions.reloadMangoAccount(slot)
actions.fetchWalletTokens(publicKey) actions.fetchWalletTokens(publicKey)
setSubmitting(false) setSubmitting(false)
onSuccess() onSuccess()

View File

@ -93,22 +93,24 @@ const HydrateStore = () => {
async (info, context) => { async (info, context) => {
if (info?.lamports === 0) return if (info?.lamports === 0) return
const lastSeenSlot = mangoStore.getState().mangoAccount.lastSlot
const mangoAccount = mangoStore.getState().mangoAccount.current const mangoAccount = mangoStore.getState().mangoAccount.current
if (!mangoAccount) return if (!mangoAccount) return
const newMangoAccount = client.getMangoAccountFromAi(
if (context.slot > lastSeenSlot) { mangoAccount.publicKey,
const newMangoAccount = await client.getMangoAccountFromAi( info,
mangoAccount.publicKey, )
info, // don't fetch serum3OpenOrders if the slot is old
) if (context.slot > mangoStore.getState().mangoAccount.lastSlot) {
if (newMangoAccount.serum3Active().length > 0) { if (newMangoAccount.serum3Active().length > 0) {
await newMangoAccount.reloadSerum3OpenOrders(client) await newMangoAccount.reloadSerum3OpenOrders(client)
// check again that the slot is still the most recent after the reloading open orders
if (context.slot > mangoStore.getState().mangoAccount.lastSlot) {
set((s) => {
s.mangoAccount.current = newMangoAccount
s.mangoAccount.lastSlot = context.slot
})
}
} }
set((s) => {
s.mangoAccount.current = newMangoAccount
s.mangoAccount.lastSlot = context.slot
})
actions.fetchOpenOrders() actions.fetchOpenOrders()
} }
}, },

View File

@ -125,7 +125,7 @@ function RepayForm({ onSuccess, token }: RepayFormProps) {
setSubmitting(true) setSubmitting(true)
try { try {
const tx = await client.tokenDeposit( const { signature: tx, slot } = await client.tokenDeposit(
group, group,
mangoAccount, mangoAccount,
bank.mint, bank.mint,
@ -138,7 +138,7 @@ function RepayForm({ onSuccess, token }: RepayFormProps) {
txid: tx, txid: tx,
}) })
await actions.reloadMangoAccount() await actions.reloadMangoAccount(slot)
actions.fetchWalletTokens(publicKey) actions.fetchWalletTokens(publicKey)
setSubmitting(false) setSubmitting(false)
onSuccess() onSuccess()

View File

@ -61,7 +61,7 @@ const StatusBar = ({ collapsed }: { collapsed: boolean }) => {
rel="noreferrer noopener" rel="noreferrer noopener"
target="_blank" target="_blank"
> >
<span className="text-th-fgd-3 text-xs">v{IDL.version}</span> <span>v{IDL.version}</span>
</a> </a>
</Tooltip> </Tooltip>
{latestCommit.sha && latestCommit.url ? ( {latestCommit.sha && latestCommit.url ? (

View File

@ -108,11 +108,13 @@ const TopBar = () => {
<SolanaTps /> <SolanaTps />
</div> </div>
) : null} */} ) : null} */}
<img <div className="bg-th-bkg-1 flex items-center justify-center h-[63px] w-16 md:hidden">
className="mr-4 h-9 w-9 flex-shrink-0 md:hidden" <img
src={themeData.logoPath} className="h-9 w-9 flex-shrink-0"
alt="logo" src={themeData.logoPath}
/> alt="logo"
/>
</div>
{!connected ? ( {!connected ? (
mangoAccount ? ( mangoAccount ? (
<span className="hidden items-center md:flex md:pl-6"> <span className="hidden items-center md:flex md:pl-6">
@ -189,7 +191,7 @@ const TopBar = () => {
{isUnownedAccount || (!connected && isMobile) ? null : isMobile ? ( {isUnownedAccount || (!connected && isMobile) ? null : isMobile ? (
<button <button
onClick={() => handleDepositWithdrawModal('deposit')} onClick={() => handleDepositWithdrawModal('deposit')}
className="h-16 border-l border-th-bkg-3 px-4 font-display text-th-fgd-1" className="h-[63px] bg-th-bkg-1 border-l border-th-bkg-3 px-4 font-display text-center text-th-fgd-1"
>{`${t('deposit')} / ${t('withdraw')}`}</button> >{`${t('deposit')} / ${t('withdraw')}`}</button>
) : ( ) : (
<Button <Button

View File

@ -111,7 +111,7 @@ function WithdrawForm({ onSuccess, token }: WithdrawFormProps) {
if (!mangoAccount || !group || !bank) return if (!mangoAccount || !group || !bank) return
setSubmitting(true) setSubmitting(true)
try { try {
const tx = await client.tokenWithdraw( const { signature: tx, slot } = await client.tokenWithdraw(
group, group,
mangoAccount, mangoAccount,
bank.mint, bank.mint,
@ -123,7 +123,7 @@ function WithdrawForm({ onSuccess, token }: WithdrawFormProps) {
type: 'success', type: 'success',
txid: tx, txid: tx,
}) })
await actions.reloadMangoAccount() await actions.reloadMangoAccount(slot)
setSubmitting(false) setSubmitting(false)
onSuccess() onSuccess()
} catch (e) { } catch (e) {

View File

@ -1,4 +1,4 @@
import { Fragment, useState } from 'react' import { Fragment, useMemo, useState } from 'react'
import Button, { IconButton } from '../shared/Button' import Button, { IconButton } from '../shared/Button'
import { import {
ArrowDownRightIcon, ArrowDownRightIcon,
@ -28,6 +28,7 @@ import useUnownedAccount from 'hooks/useUnownedAccount'
import { useViewport } from 'hooks/useViewport' import { useViewport } from 'hooks/useViewport'
import { breakpoints } from 'utils/theme' import { breakpoints } from 'utils/theme'
import MangoAccountSizeModal from '@components/modals/MangoAccountSizeModal' import MangoAccountSizeModal from '@components/modals/MangoAccountSizeModal'
import { getIsAccountSizeFull } from '@components/settings/AccountSettings'
export const handleCopyAddress = ( export const handleCopyAddress = (
mangoAccount: MangoAccount, mangoAccount: MangoAccount,
@ -63,6 +64,11 @@ const AccountActions = () => {
} }
} }
const isAccountFull = useMemo(() => {
if (!mangoAccountAddress) return true
return getIsAccountSizeFull()
}, [mangoAccountAddress])
return ( return (
<> <>
{isUnownedAccount ? null : ( {isUnownedAccount ? null : (
@ -147,16 +153,18 @@ const AccountActions = () => {
<UserPlusIcon className="h-4 w-4" /> <UserPlusIcon className="h-4 w-4" />
<span className="ml-2">{t('delegate-account')}</span> <span className="ml-2">{t('delegate-account')}</span>
</ActionsLinkButton> </ActionsLinkButton>
<ActionsLinkButton {!isAccountFull ? (
disabled={isDelegatedAccount} <ActionsLinkButton
mangoAccount={mangoAccount!} disabled={isDelegatedAccount}
onClick={() => setShowAccountSizeModal(true)} mangoAccount={mangoAccount!}
> onClick={() => setShowAccountSizeModal(true)}
<SquaresPlusIcon className="h-4 w-4" /> >
<span className="ml-2"> <SquaresPlusIcon className="h-4 w-4" />
{t('settings:increase-account-size')} <span className="ml-2">
</span> {t('settings:increase-account-size')}
</ActionsLinkButton> </span>
</ActionsLinkButton>
) : null}
<ActionsLinkButton <ActionsLinkButton
disabled={isDelegatedAccount} disabled={isDelegatedAccount}
mangoAccount={mangoAccount!} mangoAccount={mangoAccount!}

View File

@ -50,11 +50,11 @@ const CreateAccountForm = ({
setLoading(true) setLoading(true)
try { try {
const newAccountNum = getNextAccountNumber(mangoAccounts) const newAccountNum = getNextAccountNumber(mangoAccounts)
const tx = await client.createMangoAccount( const { signature: tx } = await client.createMangoAccount(
group, group,
newAccountNum, newAccountNum,
name || `Account ${newAccountNum + 1}`, name || `Account ${newAccountNum + 1}`,
16, // tokenCount 10, // tokenCount
) )
if (tx) { if (tx) {
const pk = wallet.adapter.publicKey const pk = wallet.adapter.publicKey
@ -66,7 +66,6 @@ const CreateAccountForm = ({
(acc) => acc.accountNum === newAccountNum, (acc) => acc.accountNum === newAccountNum,
) )
if (newAccount) { if (newAccount) {
await newAccount.reloadSerum3OpenOrders(client)
set((s) => { set((s) => {
s.mangoAccount.current = newAccount s.mangoAccount.current = newAccount
s.mangoAccounts = reloadedMangoAccounts s.mangoAccounts = reloadedMangoAccounts

View File

@ -925,7 +925,7 @@ const ListToken = ({ goBack }: { goBack: () => void }) => {
</div> </div>
<ol className="list-decimal pl-4"> <ol className="list-decimal pl-4">
{!advForm.openBookMarketExternalPk && {!advForm.openBookMarketExternalPk &&
liqudityTier && listingTier &&
!loadingListingParams ? ( !loadingListingParams ? (
<li className="pl-2"> <li className="pl-2">
<div className="mb-4"> <div className="mb-4">
@ -956,7 +956,7 @@ const ListToken = ({ goBack }: { goBack: () => void }) => {
) : null} ) : null}
</li> </li>
) : null} ) : null}
{!advForm.oraclePk && liqudityTier && !loadingListingParams ? ( {!advForm.oraclePk && listingTier && !loadingListingParams ? (
<li <li
className={`my-4 pl-2 ${ className={`my-4 pl-2 ${
!advForm.openBookMarketExternalPk !advForm.openBookMarketExternalPk
@ -978,7 +978,7 @@ const ListToken = ({ goBack }: { goBack: () => void }) => {
type="error" type="error"
/> />
<CreateSwitchboardOracleModal <CreateSwitchboardOracleModal
tier={liqudityTier} tier={listingTier}
orcaPoolAddress={orcaPoolAddress} orcaPoolAddress={orcaPoolAddress}
raydiumPoolAddress={raydiumPoolAddress} raydiumPoolAddress={raydiumPoolAddress}
baseTokenName={currentTokenInfo.symbol} baseTokenName={currentTokenInfo.symbol}

View File

@ -24,7 +24,11 @@ const AccountNameModal = ({ isOpen, onClose }: ModalProps) => {
if (!mangoAccount || !group) return if (!mangoAccount || !group) return
setLoading(true) setLoading(true)
try { try {
const tx = await client.editMangoAccount(group, mangoAccount, name) const { signature: tx, slot } = await client.editMangoAccount(
group,
mangoAccount,
name,
)
setLoading(false) setLoading(false)
onClose() onClose()
@ -33,7 +37,7 @@ const AccountNameModal = ({ isOpen, onClose }: ModalProps) => {
type: 'success', type: 'success',
txid: tx, txid: tx,
}) })
await actions.reloadMangoAccount() await actions.reloadMangoAccount(slot)
} catch (e) { } catch (e) {
console.error(e) console.error(e)
setLoading(false) setLoading(false)

View File

@ -46,7 +46,10 @@ const CloseAccountModal = ({ isOpen, onClose }: ModalProps) => {
if (!mangoAccount || !group) return if (!mangoAccount || !group) return
setLoading(true) setLoading(true)
try { try {
const tx = await client.emptyAndCloseMangoAccount(group, mangoAccount) const { signature: tx } = await client.emptyAndCloseMangoAccount(
group,
mangoAccount,
)
if (tx) { if (tx) {
const newMangoAccounts = mangoAccounts.filter( const newMangoAccounts = mangoAccounts.filter(
(ma) => !ma.publicKey.equals(mangoAccount.publicKey), (ma) => !ma.publicKey.equals(mangoAccount.publicKey),

View File

@ -40,7 +40,7 @@ const DelegateModal = ({ isOpen, onClose }: ModalProps) => {
} }
try { try {
const tx = await client.editMangoAccount( const { signature: tx, slot } = await client.editMangoAccount(
group, group,
mangoAccount, mangoAccount,
undefined, undefined,
@ -57,7 +57,7 @@ const DelegateModal = ({ isOpen, onClose }: ModalProps) => {
type: 'success', type: 'success',
txid: tx, txid: tx,
}) })
await actions.reloadMangoAccount() await actions.reloadMangoAccount(slot)
} catch (e) { } catch (e) {
console.error(e) console.error(e)
if (!isMangoError(e)) return if (!isMangoError(e)) return

View File

@ -23,7 +23,7 @@ import {
const MIN_ACCOUNTS = 8 const MIN_ACCOUNTS = 8
export const MAX_ACCOUNTS: AccountSizeForm = { export const MAX_ACCOUNTS: AccountSizeForm = {
tokenAccounts: '16', tokenAccounts: '10',
spotOpenOrders: '8', spotOpenOrders: '8',
perpAccounts: '8', perpAccounts: '8',
perpOpenOrders: '64', perpOpenOrders: '64',
@ -87,12 +87,12 @@ const MangoAccountSizeModal = ({ isOpen, onClose }: ModalProps) => {
}, [mangoAccountAddress]) }, [mangoAccountAddress])
useEffect(() => { useEffect(() => {
if (mangoAccountAddress) { if (mangoAccount) {
setAccountSizeForm({ setAccountSizeForm({
tokenAccounts: mangoAccount?.tokens.length.toString(), tokenAccounts: mangoAccount.tokens.length.toString(),
spotOpenOrders: mangoAccount?.serum3.length.toString(), spotOpenOrders: mangoAccount.serum3.length.toString(),
perpAccounts: mangoAccount?.perps.length.toString(), perpAccounts: mangoAccount.perps.length.toString(),
perpOpenOrders: mangoAccount?.perpOpenOrders.length.toString(), perpOpenOrders: mangoAccount.perpOpenOrders.length.toString(),
}) })
} }
}, [mangoAccountAddress]) }, [mangoAccountAddress])
@ -203,7 +203,7 @@ const MangoAccountSizeModal = ({ isOpen, onClose }: ModalProps) => {
return return
setSubmitting(true) setSubmitting(true)
try { try {
const tx = await client.accountExpandV2( const { signature: tx, slot } = await client.accountExpandV2(
group, group,
mangoAccount, mangoAccount,
parseInt(tokenAccounts), parseInt(tokenAccounts),
@ -217,7 +217,7 @@ const MangoAccountSizeModal = ({ isOpen, onClose }: ModalProps) => {
type: 'success', type: 'success',
txid: tx, txid: tx,
}) })
await actions.reloadMangoAccount() await actions.reloadMangoAccount(slot)
setSubmitting(false) setSubmitting(false)
} catch (e) { } catch (e) {
console.error(e) console.error(e)
@ -246,6 +246,12 @@ const MangoAccountSizeModal = ({ isOpen, onClose }: ModalProps) => {
<div className="mb-4"> <div className="mb-4">
<AccountSizeFormInput <AccountSizeFormInput
availableAccounts={availableTokens} availableAccounts={availableTokens}
disabled={
mangoAccount
? mangoAccount.tokens.length >=
Number(MAX_ACCOUNTS.tokenAccounts)
: false
}
error={formErrors?.tokenAccounts} error={formErrors?.tokenAccounts}
label={t('tokens')} label={t('tokens')}
handleMax={() => handleMax('tokenAccounts')} handleMax={() => handleMax('tokenAccounts')}
@ -290,6 +296,12 @@ const MangoAccountSizeModal = ({ isOpen, onClose }: ModalProps) => {
<div> <div>
<AccountSizeFormInput <AccountSizeFormInput
availableAccounts={availablePerpOo} availableAccounts={availablePerpOo}
disabled={
mangoAccount
? mangoAccount.perpOpenOrders.length >=
Number(MAX_ACCOUNTS.perpOpenOrders)
: false
}
error={formErrors?.perpOpenOrders} error={formErrors?.perpOpenOrders}
label={t('settings:perp-open-orders')} label={t('settings:perp-open-orders')}
handleMax={() => handleMax('perpOpenOrders')} handleMax={() => handleMax('perpOpenOrders')}

View File

@ -85,7 +85,7 @@ const ModifyTvOrderModal = ({
: o.price : o.price
if (!group || !mangoAccount) return if (!group || !mangoAccount) return
try { try {
let tx = '' let tx
if (o instanceof PerpOrder) { if (o instanceof PerpOrder) {
tx = await client.modifyPerpOrder( tx = await client.modifyPerpOrder(
group, group,
@ -125,7 +125,7 @@ const ModifyTvOrderModal = ({
notify({ notify({
type: 'success', type: 'success',
title: 'Transaction successful', title: 'Transaction successful',
txid: tx, txid: tx.signature,
}) })
onClose() onClose()
} catch (e) { } catch (e) {
@ -139,7 +139,12 @@ const ModifyTvOrderModal = ({
}) })
} }
}, },
[findSerum3MarketPkInOpenOrders, modifiedOrderPrice, modifiedOrderSize], [
findSerum3MarketPkInOpenOrders,
modifiedOrderPrice,
modifiedOrderSize,
tickDecimals,
],
) )
return selectedMarket ? ( return selectedMarket ? (

View File

@ -103,7 +103,7 @@ const UserSetupModal = ({
if (!group || !publicKey) return if (!group || !publicKey) return
setLoadingAccount(true) setLoadingAccount(true)
try { try {
const tx = await client.createMangoAccount( const { signature: tx } = await client.createMangoAccount(
group, group,
0, 0,
accountName || 'Account 1', accountName || 'Account 1',
@ -143,7 +143,7 @@ const UserSetupModal = ({
if (!mangoAccount || !group || !bank) return if (!mangoAccount || !group || !bank) return
try { try {
setSubmitDeposit(true) setSubmitDeposit(true)
const tx = await client.tokenDeposit( const { signature: tx, slot } = await client.tokenDeposit(
group, group,
mangoAccount, mangoAccount,
bank.mint, bank.mint,
@ -155,7 +155,7 @@ const UserSetupModal = ({
txid: tx, txid: tx,
}) })
await actions.reloadMangoAccount() await actions.reloadMangoAccount(slot)
setSubmitDeposit(false) setSubmitDeposit(false)
onClose() onClose()
// setShowSetupStep(4) // setShowSetupStep(4)

View File

@ -15,7 +15,6 @@ import {
import { useState } from 'react' import { useState } from 'react'
import { MANGO_MINT_DECIMALS } from 'utils/governance/constants' import { MANGO_MINT_DECIMALS } from 'utils/governance/constants'
// import { useTranslation } from 'next-i18next' // import { useTranslation } from 'next-i18next'
// import ResponsivePagination from 'react-responsive-pagination'
import { ImgWithLoader } from '@components/ImgWithLoader' import { ImgWithLoader } from '@components/ImgWithLoader'
import NftMarketButton from './NftMarketButton' import NftMarketButton from './NftMarketButton'

View File

@ -3,7 +3,10 @@ import MangoAccountSizeModal, {
} from '@components/modals/MangoAccountSizeModal' } from '@components/modals/MangoAccountSizeModal'
import { LinkButton } from '@components/shared/Button' import { LinkButton } from '@components/shared/Button'
import Tooltip from '@components/shared/Tooltip' import Tooltip from '@components/shared/Tooltip'
import { SquaresPlusIcon } from '@heroicons/react/20/solid' import {
ExclamationCircleIcon,
SquaresPlusIcon,
} from '@heroicons/react/20/solid'
import mangoStore from '@store/mangoStore' import mangoStore from '@store/mangoStore'
import useMangoAccount from 'hooks/useMangoAccount' import useMangoAccount from 'hooks/useMangoAccount'
import { useTranslation } from 'next-i18next' import { useTranslation } from 'next-i18next'
@ -47,6 +50,31 @@ export const getAvaialableAccountsColor = (used: number, total: number) => {
: 'text-th-down' : 'text-th-down'
} }
const isAccountSlotFull = (slots: number, max: string) => {
const numberMax = Number(max)
return slots >= numberMax
}
export const getIsAccountSizeFull = () => {
const mangoAccount = mangoStore.getState().mangoAccount.current
if (!mangoAccount) return true
return (
isAccountSlotFull(
mangoAccount.tokens.length,
MAX_ACCOUNTS.tokenAccounts!,
) &&
isAccountSlotFull(
mangoAccount.serum3.length,
MAX_ACCOUNTS.spotOpenOrders!,
) &&
isAccountSlotFull(mangoAccount.perps.length, MAX_ACCOUNTS.perpAccounts!) &&
isAccountSlotFull(
mangoAccount.perpOpenOrders.length,
MAX_ACCOUNTS.perpOpenOrders!,
)
)
}
const AccountSettings = () => { const AccountSettings = () => {
const { t } = useTranslation(['common', 'settings']) const { t } = useTranslation(['common', 'settings'])
const { mangoAccountAddress } = useMangoAccount() const { mangoAccountAddress } = useMangoAccount()
@ -81,17 +109,31 @@ const AccountSettings = () => {
] ]
}, [mangoAccountAddress]) }, [mangoAccountAddress])
const isAccountFull = useMemo(() => {
if (!mangoAccountAddress) return true
return getIsAccountSizeFull()
}, [mangoAccountAddress])
return ( return (
<> <>
<div className="mb-4 flex items-center justify-between"> <div className="mb-4 flex items-center justify-between">
<h2 className="text-base">{t('account')}</h2> <h2 className="text-base">{t('account')}</h2>
<LinkButton {!isAccountFull ? (
className="flex items-center" <LinkButton
onClick={() => setShowAccountSizeModal(true)} className="flex items-center"
> onClick={() => setShowAccountSizeModal(true)}
<SquaresPlusIcon className="h-4 w-4 mr-1.5" /> >
{t('settings:increase-account-size')} <SquaresPlusIcon className="h-4 w-4 mr-1.5" />
</LinkButton> {t('settings:increase-account-size')}
</LinkButton>
) : (
<div className="flex items-center">
<ExclamationCircleIcon className="h-4 w-4 mr-1.5 text-th-error" />
<p className="text-th-error">
{t('settings:error-account-size-full')}
</p>
</div>
)}
</div> </div>
<div className="flex flex-col border-t border-th-bkg-3 py-4 md:flex-row md:items-center md:justify-between md:px-4"> <div className="flex flex-col border-t border-th-bkg-3 py-4 md:flex-row md:items-center md:justify-between md:px-4">
<Tooltip <Tooltip

View File

@ -10,7 +10,14 @@ import { breakpoints } from '../../utils/theme'
import ContentBox from '../shared/ContentBox' import ContentBox from '../shared/ContentBox'
import Tooltip from '@components/shared/Tooltip' import Tooltip from '@components/shared/Tooltip'
import { Bank } from '@blockworks-foundation/mango-v4' import { Bank } from '@blockworks-foundation/mango-v4'
import { Table, Td, Th, TrBody, TrHead } from '@components/shared/TableElements' import {
SortableColumnHeader,
Table,
Td,
Th,
TrBody,
TrHead,
} from '@components/shared/TableElements'
import useMangoGroup from 'hooks/useMangoGroup' import useMangoGroup from 'hooks/useMangoGroup'
import useBanksWithBalances from 'hooks/useBanksWithBalances' import useBanksWithBalances from 'hooks/useBanksWithBalances'
import { getOracleProvider } from 'hooks/useOracleProvider' import { getOracleProvider } from 'hooks/useOracleProvider'
@ -18,6 +25,8 @@ import { useRouter } from 'next/router'
import { goToTokenPage } from './TokenOverviewTable' import { goToTokenPage } from './TokenOverviewTable'
import { LinkButton } from '@components/shared/Button' import { LinkButton } from '@components/shared/Button'
import TokenLogo from '@components/shared/TokenLogo' import TokenLogo from '@components/shared/TokenLogo'
import { useCallback } from 'react'
import { useSortableData } from 'hooks/useSortableData'
const TokenDetailsTable = () => { const TokenDetailsTable = () => {
const { t } = useTranslation(['common', 'activity', 'token', 'trade']) const { t } = useTranslation(['common', 'activity', 'token', 'trade'])
@ -27,6 +36,45 @@ const TokenDetailsTable = () => {
const banks = useBanksWithBalances() const banks = useBanksWithBalances()
const router = useRouter() const router = useRouter()
const formattedTableData = useCallback(() => {
const formatted = []
for (const b of banks) {
const bank: Bank = b.bank
const mintInfo = group?.mintInfosMapByMint.get(bank.mint.toString())
const deposits = bank.uiDeposits()
const initAssetWeight = bank.scaledInitAssetWeight(bank.price)
const initLiabWeight = bank.scaledInitLiabWeight(bank.price)
const isInsured = mintInfo?.groupInsuranceFund ? t('yes') : t('no')
const liquidationFee = bank.liquidationFee.toNumber() * 100
const loanOriginationFee = 100 * bank.loanOriginationFeeRate.toNumber()
const [oracleProvider, oracleLinkPath] = getOracleProvider(bank)
const symbol = bank.name
const data = {
bank,
deposits,
initAssetWeight,
initLiabWeight,
isInsured,
liquidationFee,
loanOriginationFee,
oracleLinkPath,
oracleProvider,
symbol,
}
formatted.push(data)
}
return formatted.sort(
(a, b) => b.deposits * b.bank.uiPrice - a.deposits * a.bank.uiPrice,
)
}, [banks, group])
const {
items: tableData,
requestSort,
sortConfig,
} = useSortableData(formattedTableData())
return group ? ( return group ? (
<ContentBox hideBorder hidePadding> <ContentBox hideBorder hidePadding>
{showTableView ? ( {showTableView ? (
@ -34,117 +82,138 @@ const TokenDetailsTable = () => {
<Table> <Table>
<thead> <thead>
<TrHead> <TrHead>
<Th className="text-left">{t('token')}</Th> <Th className="text-left">
<SortableColumnHeader
sortKey="symbol"
sort={() => requestSort('symbol')}
sortConfig={sortConfig}
title={t('token')}
/>
</Th>
<Th> <Th>
<div className="flex justify-end text-right"> <div className="flex justify-end">
<Tooltip content={t('asset-liability-weight-desc')}> <Tooltip content={t('asset-liability-weight-desc')}>
<span className="tooltip-underline"> <SortableColumnHeader
{t('asset-liability-weight')} sortKey="initAssetWeight"
</span> sort={() => requestSort('initAssetWeight')}
sortConfig={sortConfig}
title={t('asset-liability-weight')}
/>
</Tooltip> </Tooltip>
</div> </div>
</Th> </Th>
<Th> <Th>
<div className="flex justify-end text-right"> <div className="flex justify-end">
<Tooltip content={t('tooltip-borrow-fee')}> <Tooltip content={t('tooltip-borrow-fee')}>
<span className="tooltip-underline"> <SortableColumnHeader
{t('borrow-fee')} sortKey="loanOriginationFee"
</span> sort={() => requestSort('loanOriginationFee')}
sortConfig={sortConfig}
title={t('borrow-fee')}
/>
</Tooltip> </Tooltip>
</div> </div>
</Th> </Th>
<Th> <Th>
<div className="flex justify-end text-right"> <div className="flex justify-end">
<Tooltip <Tooltip
content={t('token:tooltip-liquidation-fee', { content={t('token:tooltip-liquidation-fee', {
symbol: t('tokens').toLowerCase(), symbol: t('tokens').toLowerCase(),
})} })}
> >
<span className="tooltip-underline"> <SortableColumnHeader
{t('activity:liquidation-fee')} sortKey="liquidationFee"
</span> sort={() => requestSort('liquidationFee')}
sortConfig={sortConfig}
title={t('activity:liquidation-fee')}
/>
</Tooltip> </Tooltip>
</div> </div>
</Th> </Th>
<Th className="text-right"> <Th>
<Tooltip <div className="flex justify-end">
content={ <Tooltip
<div> content={
{t('trade:tooltip-insured', { tokenOrMarket: '' })} <div>
<a {t('trade:tooltip-insured', { tokenOrMarket: '' })}
className="mt-2 flex items-center" <a
href="https://docs.mango.markets/mango-markets/insurance-fund" className="mt-2 flex items-center"
rel="noopener noreferrer" href="https://docs.mango.markets/mango-markets/insurance-fund"
target="_blank" rel="noopener noreferrer"
> target="_blank"
Learn more >
</a> Learn more
</div> </a>
} </div>
> }
<span className="tooltip-underline"> >
{t('trade:insured', { token: '' })} <SortableColumnHeader
</span> sortKey="isInsured"
</Tooltip> sort={() => requestSort('isInsured')}
sortConfig={sortConfig}
title={t('trade:insured', { token: '' })}
/>
</Tooltip>
</div>
</Th>
<Th>
<div className="flex justify-end">
<SortableColumnHeader
sortKey="oracleProvider"
sort={() => requestSort('oracleProvider')}
sortConfig={sortConfig}
title={t('trade:oracle')}
/>
</div>
</Th> </Th>
<Th className="text-right">{t('trade:oracle')}</Th>
<Th /> <Th />
</TrHead> </TrHead>
</thead> </thead>
<tbody> <tbody>
{banks.map((b) => { {tableData.map((data) => {
const bank: Bank = b.bank const {
bank,
const [oracleProvider, oracleLinkPath] = getOracleProvider(bank) initAssetWeight,
initLiabWeight,
const mintInfo = group.mintInfosMapByMint.get( isInsured,
bank.mint.toString(), liquidationFee,
) loanOriginationFee,
oracleLinkPath,
oracleProvider,
symbol,
} = data
return ( return (
<TrBody <TrBody
className="default-transition md:hover:cursor-pointer md:hover:bg-th-bkg-2" className="default-transition md:hover:cursor-pointer md:hover:bg-th-bkg-2"
key={bank.name} key={symbol}
onClick={() => onClick={() => goToTokenPage(symbol.split(' ')[0], router)}
goToTokenPage(bank.name.split(' ')[0], router)
}
> >
<Td> <Td>
<div className="flex items-center"> <div className="flex items-center">
<div className="mr-2.5 flex flex-shrink-0 items-center"> <div className="mr-2.5 flex flex-shrink-0 items-center">
<TokenLogo bank={bank} /> <TokenLogo bank={bank} />
</div> </div>
<p className="font-body">{bank.name}</p> <p className="font-body">{symbol}</p>
</div> </div>
</Td> </Td>
<Td> <Td>
<div className="flex justify-end space-x-1.5 text-right"> <div className="flex justify-end space-x-1.5 text-right">
<p> <p>{initAssetWeight.toFixed(2)}</p>
{bank.scaledInitAssetWeight(bank.price).toFixed(2)}
</p>
<span className="text-th-fgd-4">|</span> <span className="text-th-fgd-4">|</span>
<p> <p>{initLiabWeight.toFixed(2)}</p>
{bank.scaledInitLiabWeight(bank.price).toFixed(2)}
</p>
</div> </div>
</Td> </Td>
<Td> <Td>
<p className="text-right"> <p className="text-right">
{(100 * bank.loanOriginationFeeRate.toNumber()).toFixed( {loanOriginationFee.toFixed(2)}%
2,
)}
%
</p> </p>
</Td> </Td>
<Td> <Td>
<p className="text-right"> <p className="text-right">{liquidationFee.toFixed(2)}%</p>
{(bank.liquidationFee.toNumber() * 100).toFixed(2)}%
</p>
</Td> </Td>
<Td> <Td>
<p className="text-right"> <p className="text-right">{isInsured}</p>
{mintInfo?.groupInsuranceFund ? t('yes') : t('no')}
</p>
</Td> </Td>
<Td> <Td>
{oracleLinkPath ? ( {oracleLinkPath ? (

View File

@ -84,7 +84,9 @@ const TokenOverviewTable = () => {
} }
formatted.push(data) formatted.push(data)
} }
return formatted return formatted.sort(
(a, b) => b.deposits * b.bank.uiPrice - a.deposits * a.bank.uiPrice,
)
}, [banks, group]) }, [banks, group])
const { const {

View File

@ -593,11 +593,11 @@ const LimitSwapForm = ({
notify({ notify({
title: 'Transaction confirmed', title: 'Transaction confirmed',
type: 'success', type: 'success',
txid: tx, txid: tx?.signature,
noSound: true, noSound: true,
}) })
actions.fetchGroup() actions.fetchGroup()
await actions.reloadMangoAccount() await actions.reloadMangoAccount(tx?.slot)
} catch (e) { } catch (e) {
console.error('onSwap error: ', e) console.error('onSwap error: ', e)
sentry.captureException(e) sentry.captureException(e)

View File

@ -108,7 +108,7 @@ const SwapOrders = () => {
setCancelId(id.toString()) setCancelId(id.toString())
try { try {
const tx = await client.tokenConditionalSwapCancel( const { signature: tx, slot } = await client.tokenConditionalSwapCancel(
group, group,
mangoAccount, mangoAccount,
id, id,
@ -120,7 +120,7 @@ const SwapOrders = () => {
noSound: true, noSound: true,
}) })
actions.fetchGroup() actions.fetchGroup()
await actions.reloadMangoAccount() await actions.reloadMangoAccount(slot)
} catch (e) { } catch (e) {
console.error('failed to cancel swap order', e) console.error('failed to cancel swap order', e)
sentry.captureException(e) sentry.captureException(e)
@ -151,10 +151,8 @@ const SwapOrders = () => {
setCancelId('all') setCancelId('all')
try { try {
const tx = await client.tokenConditionalSwapCancelAll( const { signature: tx, slot } =
group, await client.tokenConditionalSwapCancelAll(group, mangoAccount)
mangoAccount,
)
notify({ notify({
title: 'Transaction confirmed', title: 'Transaction confirmed',
type: 'success', type: 'success',
@ -162,7 +160,7 @@ const SwapOrders = () => {
noSound: true, noSound: true,
}) })
actions.fetchGroup() actions.fetchGroup()
await actions.reloadMangoAccount() await actions.reloadMangoAccount(slot)
} catch (e) { } catch (e) {
console.error('failed to cancel trigger orders', e) console.error('failed to cancel trigger orders', e)
sentry.captureException(e) sentry.captureException(e)

View File

@ -287,7 +287,7 @@ const SwapReviewRouteInfo = ({
) )
try { try {
const tx = await client.marginTrade({ const { signature: tx, slot } = await client.marginTrade({
group, group,
mangoAccount, mangoAccount,
inputMintPk: inputBank.mint, inputMintPk: inputBank.mint,
@ -311,7 +311,7 @@ const SwapReviewRouteInfo = ({
}) })
actions.fetchGroup() actions.fetchGroup()
actions.fetchSwapHistory(mangoAccount.publicKey.toString(), 30000) actions.fetchSwapHistory(mangoAccount.publicKey.toString(), 30000)
await actions.reloadMangoAccount() await actions.reloadMangoAccount(slot)
} catch (e) { } catch (e) {
console.error('onSwap error: ', e) console.error('onSwap error: ', e)
sentry.captureException(e) sentry.captureException(e)

View File

@ -392,7 +392,7 @@ const AdvancedTradeForm = () => {
: tradeForm.postOnly && tradeForm.tradeType !== 'Market' : tradeForm.postOnly && tradeForm.tradeType !== 'Market'
? Serum3OrderType.postOnly ? Serum3OrderType.postOnly
: Serum3OrderType.limit : Serum3OrderType.limit
const tx = await client.serum3PlaceOrder( const { signature: tx } = await client.serum3PlaceOrder(
group, group,
mangoAccount, mangoAccount,
selectedMarket.serumMarketExternal, selectedMarket.serumMarketExternal,
@ -427,7 +427,7 @@ const AdvancedTradeForm = () => {
: PerpOrderType.limit : PerpOrderType.limit
console.log('perpOrderType', perpOrderType) console.log('perpOrderType', perpOrderType)
const tx = await client.perpPlaceOrder( const { signature: tx } = await client.perpPlaceOrder(
group, group,
mangoAccount, mangoAccount,
selectedMarket.perpMarketIndex, selectedMarket.perpMarketIndex,

View File

@ -163,7 +163,7 @@ const MarketCloseModal: FunctionComponent<MarketCloseModalProps> = ({
) )
const maxSlippage = 0.025 const maxSlippage = 0.025
const tx = await client.perpPlaceOrder( const { signature: tx } = await client.perpPlaceOrder(
group, group,
mangoAccount, mangoAccount,
perpMarket.perpMarketIndex, perpMarket.perpMarketIndex,

View File

@ -93,7 +93,7 @@ const OpenOrders = () => {
setCancelId(o.orderId.toString()) setCancelId(o.orderId.toString())
try { try {
const tx = await client.serum3CancelOrder( const { signature: tx } = await client.serum3CancelOrder(
group, group,
mangoAccount, mangoAccount,
market!.serumMarketExternal, market!.serumMarketExternal,
@ -135,7 +135,7 @@ const OpenOrders = () => {
if (!group || !mangoAccount) return if (!group || !mangoAccount) return
setLoadingModifyOrder(true) setLoadingModifyOrder(true)
try { try {
let tx = '' let tx
if (o instanceof PerpOrder) { if (o instanceof PerpOrder) {
tx = await client.modifyPerpOrder( tx = await client.modifyPerpOrder(
group, group,
@ -175,7 +175,7 @@ const OpenOrders = () => {
notify({ notify({
type: 'success', type: 'success',
title: 'Transaction successful', title: 'Transaction successful',
txid: tx, txid: tx.signature,
}) })
} catch (e) { } catch (e) {
console.error('Error canceling', e) console.error('Error canceling', e)
@ -203,7 +203,7 @@ const OpenOrders = () => {
if (!group || !mangoAccount) return if (!group || !mangoAccount) return
setCancelId(o.orderId.toString()) setCancelId(o.orderId.toString())
try { try {
const tx = await client.perpCancelOrder( const { signature: tx } = await client.perpCancelOrder(
group, group,
mangoAccount, mangoAccount,
o.perpMarketIndex, o.perpMarketIndex,

View File

@ -31,7 +31,7 @@ import {
updatePerpMarketOnGroup, updatePerpMarketOnGroup,
} from 'utils/orderbook' } from 'utils/orderbook'
import { OrderbookData, OrderbookL2 } from 'types' import { OrderbookData, OrderbookL2 } from 'types'
import { isEqual } from 'lodash' import isEqual from 'lodash/isEqual'
const sizeCompacter = Intl.NumberFormat('en', { const sizeCompacter = Intl.NumberFormat('en', {
maximumFractionDigits: 6, maximumFractionDigits: 6,

View File

@ -200,7 +200,7 @@ export default function SpotMarketOrderSwapForm() {
) )
try { try {
const tx = await client.marginTrade({ const { signature: tx, slot } = await client.marginTrade({
group, group,
mangoAccount, mangoAccount,
inputMintPk: inputBank.mint, inputMintPk: inputBank.mint,
@ -227,7 +227,7 @@ export default function SpotMarketOrderSwapForm() {
}) })
actions.fetchGroup() actions.fetchGroup()
actions.fetchSwapHistory(mangoAccount.publicKey.toString(), 30000) actions.fetchSwapHistory(mangoAccount.publicKey.toString(), 30000)
await actions.reloadMangoAccount() await actions.reloadMangoAccount(slot)
set((s) => { set((s) => {
s.tradeForm.baseSize = '' s.tradeForm.baseSize = ''
s.tradeForm.quoteSize = '' s.tradeForm.quoteSize = ''

View File

@ -306,7 +306,7 @@ const TradeHotKeys = ({ children }: { children: ReactNode }) => {
notify({ notify({
type: 'success', type: 'success',
title: 'Transaction successful', title: 'Transaction successful',
txid: tx, txid: tx.signature,
}) })
} else if (selectedMarket instanceof PerpMarket) { } else if (selectedMarket instanceof PerpMarket) {
const perpOrderType = const perpOrderType =
@ -343,7 +343,7 @@ const TradeHotKeys = ({ children }: { children: ReactNode }) => {
notify({ notify({
type: 'success', type: 'success',
title: 'Transaction successful', title: 'Transaction successful',
txid: tx, txid: tx.signature,
}) })
} }
} catch (e) { } catch (e) {

View File

@ -232,7 +232,7 @@ const TradingViewChart = () => {
notify({ notify({
type: 'success', type: 'success',
title: 'Transaction successful', title: 'Transaction successful',
txid: tx, txid: tx.signature,
}) })
} catch (e) { } catch (e) {
console.error('Error canceling', e) console.error('Error canceling', e)
@ -266,7 +266,7 @@ const TradingViewChart = () => {
notify({ notify({
type: 'success', type: 'success',
title: 'Transaction successful', title: 'Transaction successful',
txid: tx, txid: tx.signature,
}) })
} catch (e) { } catch (e) {
console.error('Error canceling', e) console.error('Error canceling', e)

View File

@ -47,7 +47,7 @@ const UnsettledTrades = ({
setSettleMktAddress(mktAddress) setSettleMktAddress(mktAddress)
try { try {
const txid = await client.serum3SettleFunds( const tx = await client.serum3SettleFunds(
group, group,
mangoAccount, mangoAccount,
new PublicKey(mktAddress), new PublicKey(mktAddress),
@ -56,7 +56,7 @@ const UnsettledTrades = ({
notify({ notify({
type: 'success', type: 'success',
title: 'Successfully settled funds', title: 'Successfully settled funds',
txid, txid: tx.signature,
}) })
} catch (e) { } catch (e) {
if (isMangoError(e)) { if (isMangoError(e)) {
@ -107,7 +107,7 @@ const UnsettledTrades = ({
const unprofitableAccount = const unprofitableAccount =
mangoAccountPnl > 0 ? settleCandidates[0].account : mangoAccount mangoAccountPnl > 0 ? settleCandidates[0].account : mangoAccount
const txid = await client.perpSettlePnlAndFees( const { signature: txid, slot } = await client.perpSettlePnlAndFees(
group, group,
profitableAccount, profitableAccount,
unprofitableAccount, unprofitableAccount,
@ -115,7 +115,7 @@ const UnsettledTrades = ({
mangoAccount, mangoAccount,
market.perpMarketIndex, market.perpMarketIndex,
) )
actions.reloadMangoAccount() actions.reloadMangoAccount(slot)
notify({ notify({
type: 'success', type: 'success',
title: 'Successfully settled P&L', title: 'Successfully settled P&L',

View File

@ -22,28 +22,24 @@
}, },
"dependencies": { "dependencies": {
"@blockworks-foundation/mango-feeds": "0.1.7", "@blockworks-foundation/mango-feeds": "0.1.7",
"@blockworks-foundation/mango-v4": "^0.18.17", "@blockworks-foundation/mango-v4": "^0.19.2",
"@blockworks-foundation/mango-v4-settings": "0.2.6", "@blockworks-foundation/mango-v4-settings": "0.2.6",
"@headlessui/react": "1.6.6", "@headlessui/react": "1.6.6",
"@heroicons/react": "2.0.10", "@heroicons/react": "2.0.10",
"@metaplex-foundation/js": "0.19.4", "@metaplex-foundation/js": "0.19.4",
"@next/font": "13.4.4",
"@project-serum/anchor": "0.25.0", "@project-serum/anchor": "0.25.0",
"@pythnetwork/client": "2.15.0", "@pythnetwork/client": "2.15.0",
"@sentry/nextjs": "7.58.0", "@sentry/nextjs": "7.58.0",
"@solana/spl-governance": "0.3.27", "@solana/spl-governance": "0.3.27",
"@solana/spl-token": "0.3.7", "@solana/spl-token": "0.3.7",
"@solana/wallet-adapter-base": "0.9.22", "@solana/wallet-adapter-base": "0.9.23",
"@solana/wallet-adapter-react": "0.15.32", "@solana/wallet-adapter-react": "0.15.32",
"@solana/wallet-adapter-wallets": "0.19.18", "@solana/wallet-adapter-wallets": "0.19.20",
"@solflare-wallet/pfp": "0.0.6",
"@switchboard-xyz/solana.js": "2.4.7", "@switchboard-xyz/solana.js": "2.4.7",
"@tanstack/react-query": "4.10.1", "@tanstack/react-query": "4.10.1",
"@tippyjs/react": "4.2.6", "@tippyjs/react": "4.2.6",
"@types/howler": "2.2.7", "@types/howler": "2.2.7",
"@types/lodash": "4.14.185",
"@web3auth/sign-in-with-solana": "1.0.0", "@web3auth/sign-in-with-solana": "1.0.0",
"assert": "2.0.0",
"big.js": "6.2.1", "big.js": "6.2.1",
"clsx": "1.2.1", "clsx": "1.2.1",
"csv-stringify": "6.3.2", "csv-stringify": "6.3.2",
@ -63,7 +59,6 @@
"next": "13.4.4", "next": "13.4.4",
"next-i18next": "14.0.0", "next-i18next": "14.0.0",
"next-themes": "0.2.0", "next-themes": "0.2.0",
"process": "0.11.10",
"react": "18.2.0", "react": "18.2.0",
"react-dom": "18.2.0", "react-dom": "18.2.0",
"react-flip-numbers": "3.0.5", "react-flip-numbers": "3.0.5",
@ -72,13 +67,11 @@
"react-i18next": "13.0.2", "react-i18next": "13.0.2",
"react-nice-dates": "3.1.0", "react-nice-dates": "3.1.0",
"react-number-format": "4.9.2", "react-number-format": "4.9.2",
"react-responsive-pagination": "^2.1.0",
"react-tsparticles": "2.2.4", "react-tsparticles": "2.2.4",
"react-window": "1.8.7", "react-window": "1.8.7",
"recharts": "2.5.0", "recharts": "2.5.0",
"tsparticles": "2.2.4", "tsparticles": "2.2.4",
"walktour": "5.1.1", "walktour": "5.1.1",
"webpack-node-externals": "3.0.0",
"zustand": "4.1.3" "zustand": "4.1.3"
}, },
"peerDependencies": { "peerDependencies": {
@ -91,6 +84,7 @@
"@lavamoat/preinstall-always-fail": "^1.0.0", "@lavamoat/preinstall-always-fail": "^1.0.0",
"@types/big.js": "6.1.6", "@types/big.js": "6.1.6",
"@types/js-cookie": "3.0.3", "@types/js-cookie": "3.0.3",
"@types/lodash": "4.14.185",
"@types/node": "17.0.23", "@types/node": "17.0.23",
"@types/react": "18.0.3", "@types/react": "18.0.3",
"@types/react-dom": "18.0.0", "@types/react-dom": "18.0.0",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

After

Width:  |  Height:  |  Size: 36 KiB

View File

@ -23,6 +23,7 @@
"custom": "Custom", "custom": "Custom",
"dark": "Dark", "dark": "Dark",
"display": "Display", "display": "Display",
"error-account-size-full": "Account size is full",
"error-alphanumeric-only": "Alphanumeric characters only", "error-alphanumeric-only": "Alphanumeric characters only",
"error-amount": "{{type}} must be greater than {{greaterThan}} and less than {{lessThan}}", "error-amount": "{{type}} must be greater than {{greaterThan}} and less than {{lessThan}}",
"error-key-in-use": "Hot key already in use. Choose a unique key", "error-key-in-use": "Hot key already in use. Choose a unique key",

View File

@ -23,6 +23,7 @@
"custom": "Custom", "custom": "Custom",
"dark": "Dark", "dark": "Dark",
"display": "Display", "display": "Display",
"error-account-size-full": "Account size is full",
"error-alphanumeric-only": "Alphanumeric characters only", "error-alphanumeric-only": "Alphanumeric characters only",
"error-amount": "{{type}} must be greater than {{greaterThan}} and less than {{lessThan}}", "error-amount": "{{type}} must be greater than {{greaterThan}} and less than {{lessThan}}",
"error-key-in-use": "Hot key already in use. Choose a unique key", "error-key-in-use": "Hot key already in use. Choose a unique key",

View File

@ -23,6 +23,7 @@
"custom": "Custom", "custom": "Custom",
"dark": "Dark", "dark": "Dark",
"display": "Display", "display": "Display",
"error-account-size-full": "Account size is full",
"error-alphanumeric-only": "Alphanumeric characters only", "error-alphanumeric-only": "Alphanumeric characters only",
"error-amount": "{{type}} must be greater than {{greaterThan}} and less than {{lessThan}}", "error-amount": "{{type}} must be greater than {{greaterThan}} and less than {{lessThan}}",
"error-key-in-use": "Hot key already in use. Choose a unique key", "error-key-in-use": "Hot key already in use. Choose a unique key",

View File

@ -23,6 +23,7 @@
"custom": "自定", "custom": "自定",
"dark": "暗", "dark": "暗",
"display": "显示", "display": "显示",
"error-account-size-full": "Account size is full",
"error-alphanumeric-only": "Alphanumeric characters only", "error-alphanumeric-only": "Alphanumeric characters only",
"error-amount": "{{type}} must be greater than {{greaterThan}} and less than {{lessThan}}", "error-amount": "{{type}} must be greater than {{greaterThan}} and less than {{lessThan}}",
"error-key-in-use": "Hot key already in use. Choose a unique key", "error-key-in-use": "Hot key already in use. Choose a unique key",

View File

@ -23,6 +23,7 @@
"custom": "自定", "custom": "自定",
"dark": "暗", "dark": "暗",
"display": "顯示", "display": "顯示",
"error-account-size-full": "Account size is full",
"error-alphanumeric-only": "Alphanumeric characters only", "error-alphanumeric-only": "Alphanumeric characters only",
"error-amount": "{{type}} must be greater than {{greaterThan}} and less than {{lessThan}}", "error-amount": "{{type}} must be greater than {{greaterThan}} and less than {{lessThan}}",
"error-key-in-use": "Hot key already in use. Choose a unique key", "error-key-in-use": "Hot key already in use. Choose a unique key",

View File

@ -250,7 +250,7 @@ export type MangoStore = {
limit?: number, limit?: number,
) => Promise<void> ) => Promise<void>
fetchGroup: () => Promise<void> fetchGroup: () => Promise<void>
reloadMangoAccount: () => Promise<void> reloadMangoAccount: (slot?: number) => Promise<void>
fetchMangoAccounts: (ownerPk: PublicKey) => Promise<void> fetchMangoAccounts: (ownerPk: PublicKey) => Promise<void>
fetchNfts: (connection: Connection, walletPk: PublicKey) => void fetchNfts: (connection: Connection, walletPk: PublicKey) => void
fetchOpenOrders: (refetchMangoAccount?: boolean) => Promise<void> fetchOpenOrders: (refetchMangoAccount?: boolean) => Promise<void>
@ -571,31 +571,38 @@ const mangoStore = create<MangoStore>()(
} }
} }
}, },
reloadMangoAccount: async () => { reloadMangoAccount: async (confirmationSlot) => {
const set = get().set const set = get().set
const actions = get().actions const actions = get().actions
try { try {
const group = get().group const group = get().group
const client = get().client const client = get().client
const mangoAccount = get().mangoAccount.current const mangoAccount = get().mangoAccount.current
const lastSlot = get().mangoAccount.lastSlot
if (!group) throw new Error('Group not loaded') if (!group) throw new Error('Group not loaded')
if (!mangoAccount) if (!mangoAccount)
throw new Error('No mango account exists for reload') throw new Error('No mango account exists for reload')
const { value: reloadedMangoAccount, slot } = const { value: reloadedMangoAccount, slot } =
await mangoAccount.reloadWithSlot(client) await mangoAccount.reloadWithSlot(client)
if (slot > lastSlot) { const lastSlot = get().mangoAccount.lastSlot
const ma = get().mangoAccounts.find((ma) => if (
ma.publicKey.equals(reloadedMangoAccount.publicKey), !confirmationSlot ||
) (confirmationSlot && slot > confirmationSlot)
if (ma) { ) {
Object.assign(ma, reloadedMangoAccount) if (slot > lastSlot) {
const ma = get().mangoAccounts.find((ma) =>
ma.publicKey.equals(reloadedMangoAccount.publicKey),
)
if (ma) {
Object.assign(ma, reloadedMangoAccount)
}
set((state) => {
state.mangoAccount.current = reloadedMangoAccount
state.mangoAccount.lastSlot = slot
})
} }
set((state) => { } else if (confirmationSlot && slot < confirmationSlot) {
state.mangoAccount.current = reloadedMangoAccount actions.reloadMangoAccount(confirmationSlot)
state.mangoAccount.lastSlot = slot
})
} }
} catch (e) { } catch (e) {
console.error('Error reloading mango acct', e) console.error('Error reloading mango acct', e)

View File

@ -127,7 +127,7 @@ export async function castVote(
notify({ notify({
title: 'Transaction confirmed', title: 'Transaction confirmed',
type: 'success', type: 'success',
txid: tx, txid: tx.signature,
noSound: true, noSound: true,
}) })
} }

View File

@ -46,7 +46,7 @@ export async function relinquishVote(
notify({ notify({
title: 'Transaction confirmed', title: 'Transaction confirmed',
type: 'success', type: 'success',
txid: tx, txid: tx.signature,
noSound: true, noSound: true,
}) })
} }

1158
yarn.lock

File diff suppressed because it is too large Load Diff