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

View File

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

View File

@ -93,22 +93,24 @@ const HydrateStore = () => {
async (info, context) => {
if (info?.lamports === 0) return
const lastSeenSlot = mangoStore.getState().mangoAccount.lastSlot
const mangoAccount = mangoStore.getState().mangoAccount.current
if (!mangoAccount) return
if (context.slot > lastSeenSlot) {
const newMangoAccount = await client.getMangoAccountFromAi(
const newMangoAccount = client.getMangoAccountFromAi(
mangoAccount.publicKey,
info,
)
// don't fetch serum3OpenOrders if the slot is old
if (context.slot > mangoStore.getState().mangoAccount.lastSlot) {
if (newMangoAccount.serum3Active().length > 0) {
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
})
}
}
actions.fetchOpenOrders()
}
},

View File

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

View File

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

View File

@ -108,11 +108,13 @@ const TopBar = () => {
<SolanaTps />
</div>
) : null} */}
<div className="bg-th-bkg-1 flex items-center justify-center h-[63px] w-16 md:hidden">
<img
className="mr-4 h-9 w-9 flex-shrink-0 md:hidden"
className="h-9 w-9 flex-shrink-0"
src={themeData.logoPath}
alt="logo"
/>
</div>
{!connected ? (
mangoAccount ? (
<span className="hidden items-center md:flex md:pl-6">
@ -189,7 +191,7 @@ const TopBar = () => {
{isUnownedAccount || (!connected && isMobile) ? null : isMobile ? (
<button
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>
) : (
<Button

View File

@ -111,7 +111,7 @@ function WithdrawForm({ onSuccess, token }: WithdrawFormProps) {
if (!mangoAccount || !group || !bank) return
setSubmitting(true)
try {
const tx = await client.tokenWithdraw(
const { signature: tx, slot } = await client.tokenWithdraw(
group,
mangoAccount,
bank.mint,
@ -123,7 +123,7 @@ function WithdrawForm({ onSuccess, token }: WithdrawFormProps) {
type: 'success',
txid: tx,
})
await actions.reloadMangoAccount()
await actions.reloadMangoAccount(slot)
setSubmitting(false)
onSuccess()
} 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 {
ArrowDownRightIcon,
@ -28,6 +28,7 @@ import useUnownedAccount from 'hooks/useUnownedAccount'
import { useViewport } from 'hooks/useViewport'
import { breakpoints } from 'utils/theme'
import MangoAccountSizeModal from '@components/modals/MangoAccountSizeModal'
import { getIsAccountSizeFull } from '@components/settings/AccountSettings'
export const handleCopyAddress = (
mangoAccount: MangoAccount,
@ -63,6 +64,11 @@ const AccountActions = () => {
}
}
const isAccountFull = useMemo(() => {
if (!mangoAccountAddress) return true
return getIsAccountSizeFull()
}, [mangoAccountAddress])
return (
<>
{isUnownedAccount ? null : (
@ -147,6 +153,7 @@ const AccountActions = () => {
<UserPlusIcon className="h-4 w-4" />
<span className="ml-2">{t('delegate-account')}</span>
</ActionsLinkButton>
{!isAccountFull ? (
<ActionsLinkButton
disabled={isDelegatedAccount}
mangoAccount={mangoAccount!}
@ -157,6 +164,7 @@ const AccountActions = () => {
{t('settings:increase-account-size')}
</span>
</ActionsLinkButton>
) : null}
<ActionsLinkButton
disabled={isDelegatedAccount}
mangoAccount={mangoAccount!}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,7 +3,10 @@ import MangoAccountSizeModal, {
} from '@components/modals/MangoAccountSizeModal'
import { LinkButton } from '@components/shared/Button'
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 useMangoAccount from 'hooks/useMangoAccount'
import { useTranslation } from 'next-i18next'
@ -47,6 +50,31 @@ export const getAvaialableAccountsColor = (used: number, total: number) => {
: '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 { t } = useTranslation(['common', 'settings'])
const { mangoAccountAddress } = useMangoAccount()
@ -81,10 +109,16 @@ const AccountSettings = () => {
]
}, [mangoAccountAddress])
const isAccountFull = useMemo(() => {
if (!mangoAccountAddress) return true
return getIsAccountSizeFull()
}, [mangoAccountAddress])
return (
<>
<div className="mb-4 flex items-center justify-between">
<h2 className="text-base">{t('account')}</h2>
{!isAccountFull ? (
<LinkButton
className="flex items-center"
onClick={() => setShowAccountSizeModal(true)}
@ -92,6 +126,14 @@ const AccountSettings = () => {
<SquaresPlusIcon className="h-4 w-4 mr-1.5" />
{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 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -22,28 +22,24 @@
},
"dependencies": {
"@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",
"@headlessui/react": "1.6.6",
"@heroicons/react": "2.0.10",
"@metaplex-foundation/js": "0.19.4",
"@next/font": "13.4.4",
"@project-serum/anchor": "0.25.0",
"@pythnetwork/client": "2.15.0",
"@sentry/nextjs": "7.58.0",
"@solana/spl-governance": "0.3.27",
"@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-wallets": "0.19.18",
"@solflare-wallet/pfp": "0.0.6",
"@solana/wallet-adapter-wallets": "0.19.20",
"@switchboard-xyz/solana.js": "2.4.7",
"@tanstack/react-query": "4.10.1",
"@tippyjs/react": "4.2.6",
"@types/howler": "2.2.7",
"@types/lodash": "4.14.185",
"@web3auth/sign-in-with-solana": "1.0.0",
"assert": "2.0.0",
"big.js": "6.2.1",
"clsx": "1.2.1",
"csv-stringify": "6.3.2",
@ -63,7 +59,6 @@
"next": "13.4.4",
"next-i18next": "14.0.0",
"next-themes": "0.2.0",
"process": "0.11.10",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-flip-numbers": "3.0.5",
@ -72,13 +67,11 @@
"react-i18next": "13.0.2",
"react-nice-dates": "3.1.0",
"react-number-format": "4.9.2",
"react-responsive-pagination": "^2.1.0",
"react-tsparticles": "2.2.4",
"react-window": "1.8.7",
"recharts": "2.5.0",
"tsparticles": "2.2.4",
"walktour": "5.1.1",
"webpack-node-externals": "3.0.0",
"zustand": "4.1.3"
},
"peerDependencies": {
@ -91,6 +84,7 @@
"@lavamoat/preinstall-always-fail": "^1.0.0",
"@types/big.js": "6.1.6",
"@types/js-cookie": "3.0.3",
"@types/lodash": "4.14.185",
"@types/node": "17.0.23",
"@types/react": "18.0.3",
"@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",
"dark": "Dark",
"display": "Display",
"error-account-size-full": "Account size is full",
"error-alphanumeric-only": "Alphanumeric characters only",
"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",

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-amount": "{{type}} must be greater than {{greaterThan}} and less than {{lessThan}}",
"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-amount": "{{type}} must be greater than {{greaterThan}} and less than {{lessThan}}",
"error-key-in-use": "Hot key already in use. Choose a unique key",

View File

@ -23,6 +23,7 @@
"custom": "自定",
"dark": "暗",
"display": "显示",
"error-account-size-full": "Account size is full",
"error-alphanumeric-only": "Alphanumeric characters only",
"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",

View File

@ -23,6 +23,7 @@
"custom": "自定",
"dark": "暗",
"display": "顯示",
"error-account-size-full": "Account size is full",
"error-alphanumeric-only": "Alphanumeric characters only",
"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",

View File

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

View File

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

View File

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

1158
yarn.lock

File diff suppressed because it is too large Load Diff