mango-v4-ui/components/MangoProvider.tsx

222 lines
6.5 KiB
TypeScript
Raw Normal View History

2023-08-31 19:23:53 -07:00
import { useCallback, useEffect } from 'react'
import mangoStore from '@store/mangoStore'
2023-01-05 14:06:18 -08:00
import { Keypair, PublicKey } from '@solana/web3.js'
import { useRouter } from 'next/router'
2022-11-18 09:09:39 -08:00
import useMangoAccount from 'hooks/useMangoAccount'
import useInterval from './shared/useInterval'
2023-08-29 12:34:40 -07:00
import { LAST_WALLET_NAME, PRIORITY_FEE_KEY, SECONDS } from 'utils/constants'
2023-07-20 18:40:37 -07:00
import useNetworkSpeed from 'hooks/useNetworkSpeed'
2023-07-20 21:30:43 -07:00
import { useWallet } from '@solana/wallet-adapter-react'
import useLocalStorageState from 'hooks/useLocalStorageState'
2023-08-29 12:34:40 -07:00
import { DEFAULT_PRIORITY_FEE_LEVEL } from './settings/RpcSettings'
2023-09-03 07:07:40 -07:00
import { useHiddenMangoAccounts } from 'hooks/useHiddenMangoAccounts'
import { notify } from 'utils/notifications'
const set = mangoStore.getState().set
const actions = mangoStore.getState().actions
const HydrateStore = () => {
2022-11-21 19:56:56 -08:00
const router = useRouter()
const { name: marketName } = router.query
const { mangoAccountPk, mangoAccountAddress } = useMangoAccount()
2023-01-05 14:06:18 -08:00
const connection = mangoStore((s) => s.connection)
2023-07-20 18:40:37 -07:00
const slowNetwork = useNetworkSpeed()
2023-07-20 21:30:43 -07:00
const { wallet } = useWallet()
2023-08-15 05:29:10 -07:00
const [, setLastWalletName] = useLocalStorageState(LAST_WALLET_NAME, '')
2023-07-20 21:30:43 -07:00
2023-08-31 19:23:53 -07:00
const handleWindowResize = useCallback(() => {
if (typeof window !== 'undefined') {
set((s) => {
s.window.width = window.innerWidth
s.window.height = window.innerHeight
})
}
}, [])
// store the window width and height on resize
useEffect(() => {
handleWindowResize()
window.addEventListener('resize', handleWindowResize)
return () => window.removeEventListener('resize', handleWindowResize)
}, [handleWindowResize])
2023-07-20 21:30:43 -07:00
useEffect(() => {
if (wallet?.adapter) {
setLastWalletName(wallet?.adapter.name)
}
}, [wallet, setLastWalletName])
useEffect(() => {
2022-11-21 19:56:56 -08:00
if (marketName && typeof marketName === 'string') {
set((s) => {
s.selectedMarket.name = marketName
})
2022-11-01 23:03:50 -07:00
}
2023-02-23 16:28:49 -08:00
actions.fetchGroup()
2022-11-21 19:56:56 -08:00
}, [marketName])
2023-07-22 13:44:43 -07:00
useInterval(
() => {
actions.fetchGroup()
},
(slowNetwork ? 60 : 30) * SECONDS,
2023-07-22 13:44:43 -07:00
)
2023-02-23 16:28:49 -08:00
// refetches open orders every 30 seconds
// only the selected market's open orders are updated via websocket
2023-07-22 13:44:43 -07:00
useInterval(
() => {
if (mangoAccountAddress) {
actions.fetchOpenOrders()
}
},
(slowNetwork ? 60 : 30) * SECONDS,
)
2023-01-04 13:30:28 -08:00
2023-02-23 16:28:49 -08:00
// refetch trade history and activity feed when switching accounts
useEffect(() => {
const actions = mangoStore.getState().actions
if (mangoAccountAddress) {
actions.fetchActivityFeed(mangoAccountAddress)
}
}, [mangoAccountAddress])
2023-02-26 15:44:38 -08:00
// reload and parse market fills from the event queue
2023-07-22 13:44:43 -07:00
useInterval(
async () => {
const actions = mangoStore.getState().actions
actions.loadMarketFills()
},
(slowNetwork ? 60 : 20) * SECONDS,
)
2023-02-26 15:44:38 -08:00
2023-08-29 12:34:40 -07:00
// estimate the priority fee every 30 seconds
useInterval(
async () => {
if (mangoAccountAddress) {
const priorityFeeMultiplier = Number(
localStorage.getItem(PRIORITY_FEE_KEY) ??
DEFAULT_PRIORITY_FEE_LEVEL.value,
)
actions.estimatePriorityFee(priorityFeeMultiplier)
}
},
(slowNetwork ? 60 : 10) * SECONDS,
)
2023-01-05 14:06:18 -08:00
// The websocket library solana/web3.js uses closes its websocket connection when the subscription list
// is empty after opening its first time, preventing subsequent subscriptions from receiving responses.
// This is a hack to prevent the list from every getting empty
useEffect(() => {
const id = connection.onAccountChange(new Keypair().publicKey, () => {
return
})
return () => {
connection.removeAccountChangeListener(id)
}
}, [connection])
2022-10-27 13:58:54 -07:00
// watch selected Mango Account for changes
useEffect(() => {
const client = mangoStore.getState().client
if (!mangoAccountPk) return
2022-10-27 13:58:54 -07:00
const subscriptionId = connection.onAccountChange(
mangoAccountPk,
2022-10-28 12:24:05 -07:00
async (info, context) => {
2022-10-27 13:58:54 -07:00
if (info?.lamports === 0) return
const mangoAccount = mangoStore.getState().mangoAccount.current
if (!mangoAccount) return
const newMangoAccount = client.getMangoAccountFromAi(
mangoAccount.publicKey,
info,
)
// don't fetch serum3OpenOrders if the slot is old
if (context.slot > mangoStore.getState().mangoAccount.lastSlot) {
2023-03-08 16:34:13 -08:00
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
})
}
2023-03-08 16:34:13 -08:00
}
actions.fetchOpenOrders()
}
2023-07-21 11:47:53 -07:00
},
2022-10-27 13:58:54 -07:00
)
return () => {
connection.removeAccountChangeListener(subscriptionId)
}
}, [connection, mangoAccountPk])
2022-10-27 13:58:54 -07:00
return null
}
const ReadOnlyMangoAccount = () => {
const router = useRouter()
const groupLoaded = mangoStore((s) => s.groupLoaded)
2022-12-11 21:01:48 -08:00
const ma = router.query?.address
2023-09-03 07:07:40 -07:00
const { hiddenAccounts } = useHiddenMangoAccounts()
useEffect(() => {
if (!groupLoaded) return
const set = mangoStore.getState().set
const group = mangoStore.getState().group
if (hiddenAccounts?.includes(ma as string)) {
notify({
title: 'Private Account mode enabled',
type: 'info',
})
return
}
async function loadUnownedMangoAccount() {
try {
if (!ma || !group) return
const client = mangoStore.getState().client
const pk = new PublicKey(ma)
const readOnlyMangoAccount = await client.getMangoAccount(pk)
2023-02-09 13:22:54 -08:00
await readOnlyMangoAccount.reloadSerum3OpenOrders(client)
2022-10-27 13:58:54 -07:00
set((state) => {
state.mangoAccount.current = readOnlyMangoAccount
state.mangoAccount.initialLoad = false
})
await actions.fetchOpenOrders()
} catch (error) {
2022-11-01 11:13:02 -07:00
console.error('error', error)
notify({
title: 'No account found',
description: 'Account closed or invalid address',
type: 'error',
})
}
}
if (ma) {
set((state) => {
state.mangoAccount.initialLoad = true
})
loadUnownedMangoAccount()
}
}, [ma, groupLoaded, router])
return null
}
const MangoProvider = () => {
return (
<>
<HydrateStore />
<ReadOnlyMangoAccount />
</>
)
}
export default MangoProvider