diff --git a/.eslintrc.json b/.eslintrc.json index f4c8b114f..3609ee35d 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -11,7 +11,14 @@ "plugin:react-hooks/recommended", "prettier" ], - "overrides": [], + "overrides": [ + { + "files": ["**/abacus-ts/**"], + "rules": { + "no-restricted-imports": "off" + } + } + ], "parserOptions": { "project": "./tsconfig.json", "ecmaVersion": "latest", @@ -42,6 +49,17 @@ "no-multi-assign": "off", "no-nested-ternary": "off", "no-param-reassign": ["error", { "props": false }], + "no-restricted-imports": [ + "error", + { + "patterns": [ + "@/abacus-ts/*", + "!@/abacus-ts/ontology", + "!@/abacus-ts/lib", + "!@/abacus-ts/summaryTypes" + ] + } + ], "no-return-assign": "off", "no-return-await": "off", "no-underscore-dangle": "off", diff --git a/src/abacus-ts/ontology.ts b/src/abacus-ts/ontology.ts new file mode 100644 index 000000000..34c5d7749 --- /dev/null +++ b/src/abacus-ts/ontology.ts @@ -0,0 +1,98 @@ +import { type RootState } from '@/state/_store'; +import { getCurrentMarketId } from '@/state/perpetualsSelectors'; + +import { + getCurrentMarketAccountFills, + selectAccountFills, + selectAccountFillsLoading, + selectAccountOrdersLoading, + selectCurrentMarketOpenOrders, + selectCurrentMarketOrderHistory, + selectOpenOrders, + selectOrderHistory, + selectParentSubaccountOpenPositions, + selectParentSubaccountOpenPositionsLoading, + selectParentSubaccountSummary, + selectParentSubaccountSummaryLoading, +} from './selectors/account'; +import { + selectAllAssetsInfo, + selectAllAssetsInfoLoading, + selectCurrentMarketAssetInfo, +} from './selectors/assets'; +import { + selectRawIndexerHeightData, + selectRawIndexerHeightDataLoading, + selectRawValidatorHeightData, + selectRawValidatorHeightDataLoading, +} from './selectors/base'; +import { + selectAllMarketsInfo, + selectAllMarketsInfoLoading, + selectCurrentMarketInfo, +} from './selectors/markets'; + +// every leaf is a selector or a paramaterized selector +type NestedSelectors = { + [K: string]: + | NestedSelectors + | ((state: RootState) => any) + | (() => (state: RootState, ...other: any[]) => any); +}; + +// all data should be accessed via selectors in this file +// no files outside abacus-ts should access anything within abacus-ts except this file +export const BonsaiCore = { + account: { + parentSubaccountSummary: { + data: selectParentSubaccountSummary, + loading: selectParentSubaccountSummaryLoading, + }, + parentSubaccountPositions: { + data: selectParentSubaccountOpenPositions, + loading: selectParentSubaccountOpenPositionsLoading, + }, + openOrders: { + data: selectOpenOrders, + loading: selectAccountOrdersLoading, + }, + orderHistory: { + data: selectOrderHistory, + loading: selectAccountOrdersLoading, + }, + fills: { + data: selectAccountFills, + loading: selectAccountFillsLoading, + }, + }, + markets: { + currentMarketId: getCurrentMarketId, + markets: { + data: selectAllMarketsInfo, + loading: selectAllMarketsInfoLoading, + }, + assets: { data: selectAllAssetsInfo, loading: selectAllAssetsInfoLoading }, + }, + network: { + indexerHeight: { + data: selectRawIndexerHeightData, + loading: selectRawIndexerHeightDataLoading, + }, + validatorHeight: { + data: selectRawValidatorHeightData, + loading: selectRawValidatorHeightDataLoading, + }, + }, +} as const satisfies NestedSelectors; + +export const BonsaiHelpers = { + currentMarket: { + marketInfo: selectCurrentMarketInfo, + assetInfo: selectCurrentMarketAssetInfo, + account: { + openOrders: selectCurrentMarketOpenOrders, + orderHistory: selectCurrentMarketOrderHistory, + fills: getCurrentMarketAccountFills, + }, + }, +} as const satisfies NestedSelectors; diff --git a/src/abacus-ts/selectors/assets.ts b/src/abacus-ts/selectors/assets.ts index bf6ae5b13..d4b6cd7a8 100644 --- a/src/abacus-ts/selectors/assets.ts +++ b/src/abacus-ts/selectors/assets.ts @@ -1,14 +1,19 @@ import { createAppSelector } from '@/state/appTypes'; import { transformAssetsInfo } from '../calculators/assets'; -import { selectRawAssetsData } from './base'; +import { selectRawAssets, selectRawAssetsData } from './base'; import { selectCurrentMarketInfo } from './markets'; export const selectAllAssetsInfo = createAppSelector([selectRawAssetsData], (assets) => transformAssetsInfo(assets) ); -export const selectAssetInfo = () => +export const selectAllAssetsInfoLoading = createAppSelector( + [selectRawAssets], + (assets) => assets.status +); + +export const createSelectAssetInfo = () => createAppSelector( [selectAllAssetsInfo, (_s, assetId: string) => assetId], (assets, assetId) => assets?.[assetId] diff --git a/src/abacus-ts/selectors/base.ts b/src/abacus-ts/selectors/base.ts index 3087b2476..e88b48947 100644 --- a/src/abacus-ts/selectors/base.ts +++ b/src/abacus-ts/selectors/base.ts @@ -7,6 +7,7 @@ export const selectRawAccountState = (state: RootState) => state.raw.account; export const selectRawMarkets = (state: RootState) => state.raw.markets.allMarkets; export const selectRawMarketsData = (state: RootState) => state.raw.markets.allMarkets.data; export const selectRawAssetsData = (state: RootState) => state.raw.markets.assets.data; +export const selectRawAssets = (state: RootState) => state.raw.markets.assets; export const selectRawParentSubaccount = (state: RootState) => state.raw.account.parentSubaccount; export const selectRawParentSubaccountData = (state: RootState) => @@ -31,6 +32,10 @@ export const selectRawIndexerHeightData = (state: RootState) => state.raw.heights.indexerHeight.data; export const selectRawValidatorHeightData = (state: RootState) => state.raw.heights.validatorHeight.data; +export const selectRawIndexerHeightDataLoading = (state: RootState) => + state.raw.heights.indexerHeight.status; +export const selectRawValidatorHeightDataLoading = (state: RootState) => + state.raw.heights.validatorHeight.status; export const selectRawFillsRest = (state: RootState) => state.raw.account.fills; export const selectRawOrdersRest = (state: RootState) => state.raw.account.orders; diff --git a/src/abacus-ts/selectors/markets.ts b/src/abacus-ts/selectors/markets.ts index b663563ae..4fc93bfa3 100644 --- a/src/abacus-ts/selectors/markets.ts +++ b/src/abacus-ts/selectors/markets.ts @@ -14,4 +14,7 @@ export const selectCurrentMarketInfo = createAppSelector( (markets, currentMarketId) => (currentMarketId ? markets?.[currentMarketId] : undefined) ); -export const selectMarketsInfoLoading = createAppSelector([selectRawMarkets], mergeLoadableStatus); +export const selectAllMarketsInfoLoading = createAppSelector( + [selectRawMarkets], + mergeLoadableStatus +); diff --git a/src/hooks/useInitializePage.ts b/src/hooks/useInitializePage.ts index 1accf9aae..6c9a740ff 100644 --- a/src/hooks/useInitializePage.ts +++ b/src/hooks/useInitializePage.ts @@ -1,5 +1,6 @@ import { useEffect, useRef } from 'react'; +// eslint-disable-next-line no-restricted-imports import { IndexerWebsocketManager } from '@/abacus-ts/websocket/lib/indexerWebsocketManager'; import { LocalStorageKey } from '@/constants/localStorage'; diff --git a/src/hooks/useSeen.ts b/src/hooks/useSeen.ts index 6ae7934af..b3ad82550 100644 --- a/src/hooks/useSeen.ts +++ b/src/hooks/useSeen.ts @@ -1,6 +1,6 @@ import { useEffect, useRef } from 'react'; -import { selectRawIndexerHeightData } from '@/abacus-ts/selectors/base'; +import { BonsaiCore } from '@/abacus-ts/ontology'; import { shallowEqual } from 'react-redux'; import { getUserWalletAddress } from '@/state/accountSelectors'; @@ -14,7 +14,7 @@ export function useViewPanel( ) { const networkId = useAppSelector(getSelectedNetwork); const walletId = useAppSelector(getUserWalletAddress); - const height = useAppSelector(selectRawIndexerHeightData); + const height = useAppSelector(BonsaiCore.network.indexerHeight.data); const lastSetCore = useRef([]); const dispatch = useAppDispatch(); diff --git a/src/state/_store.ts b/src/state/_store.ts index dc0ae05ef..aff5413df 100644 --- a/src/state/_store.ts +++ b/src/state/_store.ts @@ -1,3 +1,5 @@ +// eslint-disable-next-line no-restricted-imports +import { storeLifecycles } from '@/abacus-ts/storeLifecycles'; import { Middleware, combineReducers, configureStore } from '@reduxjs/toolkit'; import { persistReducer, persistStore } from 'redux-persist'; import autoMergeLevel2 from 'redux-persist/lib/stateReconciler/autoMergeLevel2'; @@ -5,7 +7,6 @@ import storage from 'redux-persist/lib/storage'; import abacusStateManager from '@/lib/abacus'; import { runFn } from '@/lib/do'; -import { testFlags } from '@/lib/testFlags'; import { accountSlice } from './account'; import { accountUiMemorySlice } from './accountUiMemory'; @@ -98,13 +99,10 @@ export const persistor = persistStore(store); // Set store so (Abacus & v4-Client) classes can getState and dispatch abacusStateManager.setStore(store); -if (testFlags.useAbacusTs) { - runFn(async () => { - const { storeLifecycles } = await import('@/abacus-ts/storeLifecycles'); - // we ignore the cleanups for now since we want these running forever - storeLifecycles.forEach((fn) => fn(store)); - }); -} +runFn(async () => { + // we ignore the cleanups for now since we want these running forever + storeLifecycles.forEach((fn) => fn(store)); +}); export type RootStore = typeof store; export type RootState = ReturnType; diff --git a/src/state/accountSelectors.ts b/src/state/accountSelectors.ts index 49337c144..d2ea111ae 100644 --- a/src/state/accountSelectors.ts +++ b/src/state/accountSelectors.ts @@ -1,4 +1,4 @@ -import { selectRawIndexerHeightData } from '@/abacus-ts/selectors/base'; +import { BonsaiCore } from '@/abacus-ts/ontology'; import { OrderSide } from '@dydxprotocol/v4-client-js'; import BigNumber from 'bignumber.js'; import { groupBy, sum } from 'lodash'; @@ -702,7 +702,7 @@ export const createGetUnseenOrdersCount = () => createAppSelector( [ getCurrentAccountMemory, - selectRawIndexerHeightData, + BonsaiCore.network.indexerHeight.data, getSubaccountOrders, (state, market: string | undefined) => market, ], @@ -734,7 +734,7 @@ export const createGetUnseenFillsCount = () => createAppSelector( [ getCurrentAccountMemory, - selectRawIndexerHeightData, + BonsaiCore.network.indexerHeight.data, getSubaccountFills, (state, market: string | undefined) => market, ], diff --git a/src/state/raw.ts b/src/state/raw.ts index 2132af23a..1492ab57d 100644 --- a/src/state/raw.ts +++ b/src/state/raw.ts @@ -1,4 +1,5 @@ import { Loadable, loadableIdle } from '@/abacus-ts/lib/loadable'; +// eslint-disable-next-line no-restricted-imports import { AssetInfos, MarketsData,