Files
dydx-v4-web/src/lib/abacus/stateNotification.ts
T
Jared Vu 48a48b4d70 Screen (#56)
* useDydxClient: Add screen endpoint

* Screen api in onboarding flow

* PnlChart rounding

* UnauthorizedDialog

* Add RateLimitDialog

* Update dialog open logic

* nits

* Screen before Transfer

* Validate network, remove input autofill color

* Use screenAddresses from dydxClient

* Check recipientAddresses

* lock-file

* Change Wallet Restricted Dialog to v4-blocked message

* nits

* Unused param

* consolidate environment validateFn

* Remove extra space, simplify WithdrawForm error msg

* Simply map logic, rearrange priority of screened messages

* WalletRestricted -> RestrictedWallet

* Update restriction modal title and add something went wrong

* Handle 429 rate limit
2023-10-16 09:36:09 -07:00

205 lines
5.9 KiB
TypeScript

import { kollections } from '@dydxprotocol/v4-abacus';
import type {
AccountBalance,
AbacusApiState,
AbacusNotification,
AbacusStateNotificationProtocol,
Asset,
Nullable,
ParsingErrors,
PerpetualMarket,
PerpetualState,
PerpetualStateChanges,
SubaccountOrder,
} from '@/constants/abacus';
import { Changes } from '@/constants/abacus';
import type { RootStore } from '@/state/_store';
import {
setBalances,
setStakingBalances,
setFills,
setFundingPayments,
setHistoricalPnl,
setLatestOrder,
setRestrictionType,
setSubaccount,
setTransfers,
setWallet,
} from '@/state/account';
import { setApiState } from '@/state/app';
import { setAssets } from '@/state/assets';
import { setConfigs } from '@/state/configs';
import { setInputs } from '@/state/inputs';
import { setHistoricalFundings, setLiveTrades, setMarkets, setOrderbook } from '@/state/perpetuals';
import { isTruthy } from '../isTruthy';
class AbacusStateNotifier implements AbacusStateNotificationProtocol {
private store: RootStore | undefined;
constructor() {
this.store = undefined;
}
environmentsChanged(): void {
return;
}
notificationsChanged(notifications: kollections.List<AbacusNotification>): void {
return;
}
stateChanged(
updatedState: Nullable<PerpetualState>,
incomingChanges: Nullable<PerpetualStateChanges>
): void {
if (!this.store) return;
const { dispatch } = this.store;
const changes = new Set(incomingChanges?.changes.toArray() || []);
const marketIds = incomingChanges?.markets?.toArray();
const subaccountNumbers = incomingChanges?.subaccountNumbers?.toArray();
if (updatedState) {
if (changes.has(Changes.assets)) {
dispatch(
setAssets(
Object.fromEntries(
(updatedState?.assetIds()?.toArray() || []).map((assetId: string) => {
const assetData = updatedState?.asset(assetId);
return [assetId, assetData];
})
) as Record<string, Asset>
)
);
}
if (changes.has(Changes.accountBalances)) {
if (updatedState.account?.balances) {
const balances: Record<string, AccountBalance> = {};
for (const { k, v } of updatedState.account.balances.toArray()) {
balances[k] = v;
}
dispatch(setBalances(balances));
}
if (updatedState.account?.stakingBalances) {
const stakingBalances: Record<string, AccountBalance> = {};
for (const { k, v } of updatedState.account.stakingBalances.toArray()) {
stakingBalances[k] = v;
}
dispatch(setStakingBalances(stakingBalances));
}
}
if (changes.has(Changes.configs)) {
dispatch(setConfigs(updatedState.configs));
}
if (changes.has(Changes.input)) {
dispatch(setInputs(updatedState.input));
}
if (changes.has(Changes.wallet)) {
dispatch(setWallet(updatedState.wallet));
}
if (changes.has(Changes.markets)) {
dispatch(
setMarkets({
markets: Object.fromEntries(
(marketIds || updatedState.marketIds()?.toArray() || [])
.map((marketId: string) => {
const marketData = updatedState.market(marketId);
return [marketId, marketData];
})
.filter(isTruthy)
) as Record<string, PerpetualMarket>,
update: !!marketIds,
})
);
}
if (changes.has(Changes.restriction)) {
dispatch(setRestrictionType(updatedState.restriction));
}
subaccountNumbers?.forEach((subaccountId: number) => {
if (subaccountId !== null) {
if (changes.has(Changes.subaccount)) {
dispatch(setSubaccount(updatedState.subaccount(subaccountId)));
}
if (changes.has(Changes.fills)) {
const fills = updatedState.subaccountFills(subaccountId)?.toArray() || [];
dispatch(setFills(fills));
}
if (changes.has(Changes.fundingPayments)) {
const fundingPayments =
updatedState.subaccountFundingPayments(subaccountId)?.toArray() || [];
dispatch(setFundingPayments(fundingPayments));
}
if (changes.has(Changes.transfers)) {
const transfers = updatedState.subaccountTransfers(subaccountId)?.toArray() || [];
dispatch(setTransfers(transfers));
}
if (changes.has(Changes.historicalPnl)) {
const historicalPnl =
updatedState.subaccountHistoricalPnl(subaccountId)?.toArray() || [];
dispatch(setHistoricalPnl(historicalPnl));
}
}
});
marketIds?.forEach((market: string) => {
if (changes.has(Changes.orderbook)) {
const orderbook = updatedState.marketOrderbook(market);
if (orderbook) {
dispatch(setOrderbook({ orderbook, marketId: market }));
}
}
if (changes.has(Changes.trades)) {
const trades = updatedState.marketTrades(market)?.toArray() || [];
dispatch(setLiveTrades({ trades, marketId: market }));
}
if (changes.has(Changes.historicalFundings)) {
const historicalFundings = updatedState.historicalFunding(market)?.toArray() || [];
dispatch(
setHistoricalFundings({
marketId: market,
historicalFundings,
})
);
}
});
}
}
lastOrderChanged(order: SubaccountOrder) {
this.store?.dispatch(setLatestOrder(order));
}
errorsEmitted(errors: ParsingErrors) {
console.error('parse errors', errors.toArray());
}
apiStateChanged(apiState: AbacusApiState) {
this.store?.dispatch(setApiState(apiState));
}
setStore = (store: RootStore) => {
this.store = store;
};
}
export default AbacusStateNotifier;