2022-08-18 13:50:34 -07:00
|
|
|
import dayjs from 'dayjs'
|
|
|
|
import produce from 'immer'
|
2022-05-03 21:20:14 -07:00
|
|
|
import create from 'zustand'
|
|
|
|
import { subscribeWithSelector } from 'zustand/middleware'
|
2023-02-08 01:58:03 -08:00
|
|
|
import { AnchorProvider, BN, Wallet, web3 } from '@project-serum/anchor'
|
2022-05-03 21:20:14 -07:00
|
|
|
import { Connection, Keypair, PublicKey } from '@solana/web3.js'
|
2022-09-25 19:00:19 -07:00
|
|
|
import { OpenOrders, Order } from '@project-serum/serum/lib/market'
|
2022-12-14 12:54:08 -08:00
|
|
|
import { Orderbook } from '@project-serum/serum'
|
2022-09-27 11:47:15 -07:00
|
|
|
import { Wallet as WalletAdapter } from '@solana/wallet-adapter-react'
|
2022-05-03 21:20:14 -07:00
|
|
|
import {
|
|
|
|
MangoClient,
|
|
|
|
Group,
|
|
|
|
MangoAccount,
|
|
|
|
Serum3Market,
|
2022-06-21 03:58:57 -07:00
|
|
|
MANGO_V4_ID,
|
2022-08-18 13:50:34 -07:00
|
|
|
Bank,
|
2022-10-31 11:26:17 -07:00
|
|
|
PerpOrder,
|
2022-11-01 06:10:08 -07:00
|
|
|
PerpPosition,
|
2022-11-30 07:46:20 -08:00
|
|
|
BookSide,
|
2023-01-06 16:26:06 -08:00
|
|
|
FillEvent,
|
2022-05-03 21:20:14 -07:00
|
|
|
} from '@blockworks-foundation/mango-v4'
|
2022-08-18 13:50:34 -07:00
|
|
|
|
2022-05-03 21:20:14 -07:00
|
|
|
import EmptyWallet from '../utils/wallet'
|
2022-08-01 22:32:21 -07:00
|
|
|
import { Notification, notify } from '../utils/notifications'
|
2022-07-05 20:37:49 -07:00
|
|
|
import {
|
2022-08-01 22:32:21 -07:00
|
|
|
fetchNftsFromHolaplexIndexer,
|
2022-07-05 20:37:49 -07:00
|
|
|
getTokenAccountsByOwnerWithWrappedSol,
|
|
|
|
TokenAccount,
|
|
|
|
} from '../utils/tokens'
|
2022-07-11 20:00:22 -07:00
|
|
|
import { Token } from '../types/jupiter'
|
2022-08-20 11:17:57 -07:00
|
|
|
import {
|
2023-01-02 14:21:41 -08:00
|
|
|
CONNECTION_COMMITMENT,
|
2022-09-13 23:24:26 -07:00
|
|
|
DEFAULT_MARKET_NAME,
|
2022-08-20 11:17:57 -07:00
|
|
|
INPUT_TOKEN_DEFAULT,
|
|
|
|
LAST_ACCOUNT_KEY,
|
2023-01-18 05:13:29 -08:00
|
|
|
MANGO_DATA_API_URL,
|
2022-08-20 11:17:57 -07:00
|
|
|
OUTPUT_TOKEN_DEFAULT,
|
2023-01-12 16:16:10 -08:00
|
|
|
PAGINATION_PAGE_LENGTH,
|
2023-01-19 12:31:45 -08:00
|
|
|
PRIORITY_FEE_KEY,
|
2022-12-15 18:19:11 -08:00
|
|
|
RPC_PROVIDER_KEY,
|
2022-08-20 11:17:57 -07:00
|
|
|
} from '../utils/constants'
|
2023-01-18 20:34:25 -08:00
|
|
|
import {
|
|
|
|
OrderbookL2,
|
|
|
|
PerpTradeHistory,
|
|
|
|
SpotBalances,
|
|
|
|
SpotTradeHistory,
|
|
|
|
} from 'types'
|
2022-09-25 19:00:19 -07:00
|
|
|
import spotBalancesUpdater from './spotBalancesUpdater'
|
2022-10-10 19:16:13 -07:00
|
|
|
import { PerpMarket } from '@blockworks-foundation/mango-v4/'
|
2022-11-01 06:10:08 -07:00
|
|
|
import perpPositionsUpdater from './perpPositionsUpdater'
|
2023-02-03 13:23:36 -08:00
|
|
|
import { DEFAULT_PRIORITY_FEE } from '@components/settings/RpcSettings'
|
2023-02-08 01:58:03 -08:00
|
|
|
import { IOrderLineAdapter } from '@public/charting_library/charting_library'
|
2022-05-03 21:20:14 -07:00
|
|
|
|
2022-12-08 11:58:54 -08:00
|
|
|
const GROUP = new PublicKey('78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX')
|
2022-05-31 18:41:18 -07:00
|
|
|
|
2022-12-15 18:19:11 -08:00
|
|
|
const ENDPOINTS = [
|
|
|
|
{
|
|
|
|
name: 'mainnet-beta',
|
|
|
|
url:
|
|
|
|
process.env.NEXT_PUBLIC_ENDPOINT ||
|
|
|
|
'https://mango.rpcpool.com/0f9acc0d45173b51bf7d7e09c1e5',
|
|
|
|
websocket:
|
|
|
|
process.env.NEXT_PUBLIC_ENDPOINT ||
|
|
|
|
'https://mango.rpcpool.com/0f9acc0d45173b51bf7d7e09c1e5',
|
|
|
|
custom: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'devnet',
|
2022-12-27 13:13:15 -08:00
|
|
|
url: 'https://mango.devnet.rpcpool.com',
|
|
|
|
websocket: 'https://mango.devnet.rpcpool.com',
|
2022-12-15 18:19:11 -08:00
|
|
|
custom: false,
|
|
|
|
},
|
|
|
|
]
|
|
|
|
|
2022-06-30 13:12:36 -07:00
|
|
|
const options = AnchorProvider.defaultOptions()
|
2022-11-18 11:11:06 -08:00
|
|
|
export const CLUSTER: 'mainnet-beta' | 'devnet' = 'mainnet-beta'
|
2022-12-27 13:13:15 -08:00
|
|
|
const ENDPOINT = ENDPOINTS.find((e) => e.name === CLUSTER) || ENDPOINTS[0]
|
|
|
|
const emptyWallet = new EmptyWallet(Keypair.generate())
|
2022-12-15 18:19:11 -08:00
|
|
|
|
2023-01-19 12:31:45 -08:00
|
|
|
const initMangoClient = (
|
|
|
|
provider: AnchorProvider,
|
2023-02-03 13:23:36 -08:00
|
|
|
opts = { prioritizationFee: DEFAULT_PRIORITY_FEE.value }
|
2023-01-19 12:31:45 -08:00
|
|
|
): MangoClient => {
|
2022-12-15 18:19:11 -08:00
|
|
|
return MangoClient.connect(provider, CLUSTER, MANGO_V4_ID[CLUSTER], {
|
2023-01-19 12:31:45 -08:00
|
|
|
prioritizationFee: opts.prioritizationFee,
|
2022-12-08 11:58:54 -08:00
|
|
|
idsSource: 'get-program-accounts',
|
2022-12-15 18:19:11 -08:00
|
|
|
postSendTxCallback: ({ txid }: { txid: string }) => {
|
|
|
|
notify({
|
|
|
|
title: 'Transaction sent',
|
|
|
|
description: 'Waiting for confirmation',
|
|
|
|
type: 'confirm',
|
|
|
|
txid: txid,
|
|
|
|
})
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
2022-05-03 21:20:14 -07:00
|
|
|
|
2022-09-07 19:36:39 -07:00
|
|
|
export interface TotalInterestDataItem {
|
2022-08-12 05:13:11 -07:00
|
|
|
borrow_interest: number
|
|
|
|
deposit_interest: number
|
|
|
|
borrow_interest_usd: number
|
|
|
|
deposit_interest_usd: number
|
|
|
|
symbol: string
|
|
|
|
}
|
|
|
|
|
|
|
|
export interface PerformanceDataItem {
|
|
|
|
account_equity: number
|
|
|
|
borrow_interest_cumulative_usd: number
|
|
|
|
deposit_interest_cumulative_usd: number
|
|
|
|
pnl: number
|
|
|
|
spot_value: number
|
|
|
|
time: string
|
|
|
|
transfer_balance: number
|
|
|
|
}
|
|
|
|
|
2022-09-27 23:17:06 -07:00
|
|
|
export interface DepositWithdrawFeedItem {
|
2022-09-26 23:22:51 -07:00
|
|
|
activity_details: {
|
|
|
|
block_datetime: string
|
|
|
|
mango_account: string
|
|
|
|
quantity: number
|
|
|
|
signature: string
|
|
|
|
symbol: string
|
|
|
|
usd_equivalent: number
|
|
|
|
wallet_pk: string
|
|
|
|
}
|
|
|
|
activity_type: string
|
|
|
|
block_datetime: string
|
|
|
|
symbol: string
|
|
|
|
}
|
|
|
|
|
2022-09-27 23:17:06 -07:00
|
|
|
export interface LiquidationFeedItem {
|
|
|
|
activity_details: {
|
|
|
|
asset_amount: number
|
|
|
|
asset_price: number
|
|
|
|
asset_symbol: string
|
|
|
|
block_datetime: string
|
|
|
|
liab_amount: number
|
|
|
|
liab_price: number
|
|
|
|
liab_symbol: string
|
|
|
|
mango_account: string
|
|
|
|
mango_group: string
|
|
|
|
side: string
|
|
|
|
signature: string
|
|
|
|
}
|
|
|
|
activity_type: string
|
|
|
|
block_datetime: string
|
|
|
|
symbol: string
|
|
|
|
}
|
|
|
|
|
2022-09-26 23:22:51 -07:00
|
|
|
export interface SwapHistoryItem {
|
2022-08-12 23:06:09 -07:00
|
|
|
block_datetime: string
|
|
|
|
mango_account: string
|
|
|
|
signature: string
|
|
|
|
swap_in_amount: number
|
|
|
|
swap_in_loan: number
|
|
|
|
swap_in_loan_origination_fee: number
|
|
|
|
swap_in_price_usd: number
|
|
|
|
swap_in_symbol: string
|
|
|
|
swap_out_amount: number
|
|
|
|
loan: number
|
|
|
|
loan_origination_fee: number
|
|
|
|
swap_out_price_usd: number
|
|
|
|
swap_out_symbol: string
|
|
|
|
}
|
|
|
|
|
2022-08-01 22:32:21 -07:00
|
|
|
interface NFT {
|
|
|
|
address: string
|
|
|
|
image: string
|
|
|
|
}
|
|
|
|
|
2023-02-09 19:20:46 -08:00
|
|
|
export interface PerpStatsItem {
|
|
|
|
date_hour: string
|
|
|
|
fees_accrued: number
|
|
|
|
funding_rate_hourly: number
|
|
|
|
instantaneous_funding_rate: number
|
|
|
|
mango_group: string
|
|
|
|
market_index: number
|
|
|
|
open_interest: number
|
|
|
|
perp_market: string
|
|
|
|
price: number
|
|
|
|
stable_price: number
|
|
|
|
}
|
|
|
|
|
2022-09-20 18:03:59 -07:00
|
|
|
interface ProfileDetails {
|
|
|
|
profile_image_url?: string
|
|
|
|
profile_name: string
|
|
|
|
trader_category: string
|
|
|
|
wallet_pk: string
|
|
|
|
}
|
|
|
|
|
2022-09-22 21:00:42 -07:00
|
|
|
interface TourSettings {
|
2022-09-21 21:25:24 -07:00
|
|
|
account_tour_seen: boolean
|
|
|
|
swap_tour_seen: boolean
|
|
|
|
trade_tour_seen: boolean
|
|
|
|
wallet_pk: string
|
|
|
|
}
|
|
|
|
|
2022-12-05 19:23:22 -08:00
|
|
|
export interface TokenStatsItem {
|
|
|
|
borrow_apr: number
|
|
|
|
borrow_rate: number
|
|
|
|
collected_fees: number
|
|
|
|
date_hour: string
|
|
|
|
deposit_apr: number
|
|
|
|
deposit_rate: number
|
|
|
|
mango_group: string
|
|
|
|
price: number
|
|
|
|
symbol: string
|
|
|
|
token_index: number
|
|
|
|
total_borrows: number
|
|
|
|
total_deposits: number
|
|
|
|
}
|
|
|
|
|
2022-09-22 21:00:42 -07:00
|
|
|
// const defaultUserSettings = {
|
|
|
|
// account_tour_seen: false,
|
|
|
|
// default_language: 'English',
|
|
|
|
// default_market: 'SOL-Perp',
|
|
|
|
// orderbook_animation: false,
|
|
|
|
// rpc_endpoint: 'Triton (RPC Pool)',
|
|
|
|
// rpc_node_url: null,
|
|
|
|
// spot_margin: false,
|
|
|
|
// swap_tour_seen: false,
|
|
|
|
// theme: 'Mango',
|
|
|
|
// trade_tour_seen: false,
|
|
|
|
// wallet_pk: '',
|
|
|
|
// }
|
2022-09-21 21:25:24 -07:00
|
|
|
|
2022-12-14 12:54:25 -08:00
|
|
|
interface TradeForm {
|
|
|
|
side: 'buy' | 'sell'
|
|
|
|
price: string | undefined
|
|
|
|
baseSize: string
|
|
|
|
quoteSize: string
|
|
|
|
tradeType: 'Market' | 'Limit'
|
|
|
|
postOnly: boolean
|
|
|
|
ioc: boolean
|
2023-01-16 20:00:42 -08:00
|
|
|
reduceOnly: boolean
|
2022-12-14 12:54:25 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
export const DEFAULT_TRADE_FORM: TradeForm = {
|
|
|
|
side: 'buy',
|
|
|
|
price: undefined,
|
|
|
|
baseSize: '',
|
|
|
|
quoteSize: '',
|
|
|
|
tradeType: 'Limit',
|
|
|
|
postOnly: false,
|
|
|
|
ioc: false,
|
2023-01-16 20:00:42 -08:00
|
|
|
reduceOnly: false,
|
2022-12-14 12:54:25 -08:00
|
|
|
}
|
|
|
|
|
2022-05-03 21:20:14 -07:00
|
|
|
export type MangoStore = {
|
2022-09-26 23:22:51 -07:00
|
|
|
activityFeed: {
|
2022-09-27 23:17:06 -07:00
|
|
|
feed: Array<DepositWithdrawFeedItem | LiquidationFeedItem>
|
2022-09-26 23:22:51 -07:00
|
|
|
loading: boolean
|
2023-02-03 00:27:54 -08:00
|
|
|
queryParams: string
|
2022-09-26 23:22:51 -07:00
|
|
|
}
|
2022-07-05 20:37:49 -07:00
|
|
|
connected: boolean
|
2022-06-22 04:55:03 -07:00
|
|
|
connection: Connection
|
2022-05-03 21:20:14 -07:00
|
|
|
group: Group | undefined
|
2022-09-27 11:47:15 -07:00
|
|
|
groupLoaded: boolean
|
2022-05-03 21:20:14 -07:00
|
|
|
client: MangoClient
|
2022-07-27 23:35:18 -07:00
|
|
|
mangoAccount: {
|
|
|
|
current: MangoAccount | undefined
|
2022-08-19 14:17:30 -07:00
|
|
|
initialLoad: boolean
|
2022-10-29 17:30:37 -07:00
|
|
|
lastSlot: number
|
2022-09-25 19:00:19 -07:00
|
|
|
openOrderAccounts: OpenOrders[]
|
2022-10-31 11:26:17 -07:00
|
|
|
openOrders: Record<string, Order[] | PerpOrder[]>
|
2022-11-01 06:10:08 -07:00
|
|
|
perpPositions: PerpPosition[]
|
2022-09-25 19:00:19 -07:00
|
|
|
spotBalances: SpotBalances
|
2023-01-15 21:13:34 -08:00
|
|
|
interestTotals: { data: TotalInterestDataItem[]; loading: boolean }
|
|
|
|
performance: {
|
|
|
|
data: PerformanceDataItem[]
|
|
|
|
loading: boolean
|
|
|
|
}
|
|
|
|
swapHistory: {
|
|
|
|
data: SwapHistoryItem[]
|
2023-01-18 20:33:51 -08:00
|
|
|
loading: boolean
|
2022-08-12 05:13:11 -07:00
|
|
|
}
|
2023-01-18 20:34:25 -08:00
|
|
|
tradeHistory: {
|
|
|
|
data: Array<SpotTradeHistory | PerpTradeHistory>
|
|
|
|
loading: boolean
|
|
|
|
}
|
2022-07-27 23:35:18 -07:00
|
|
|
}
|
2022-10-07 04:47:15 -07:00
|
|
|
mangoAccounts: MangoAccount[]
|
2022-05-03 21:20:14 -07:00
|
|
|
markets: Serum3Market[] | undefined
|
2022-07-05 20:37:49 -07:00
|
|
|
notificationIdCounter: number
|
|
|
|
notifications: Array<Notification>
|
2022-10-10 19:16:13 -07:00
|
|
|
perpMarkets: PerpMarket[]
|
2022-12-07 17:31:50 -08:00
|
|
|
perpStats: {
|
|
|
|
loading: boolean
|
2023-02-09 19:20:46 -08:00
|
|
|
data: PerpStatsItem[] | null
|
2022-12-07 17:31:50 -08:00
|
|
|
}
|
2022-09-20 18:03:59 -07:00
|
|
|
profile: {
|
2022-12-23 16:12:32 -08:00
|
|
|
details: ProfileDetails | null
|
2022-09-20 18:03:59 -07:00
|
|
|
loadDetails: boolean
|
|
|
|
}
|
2022-09-13 23:24:26 -07:00
|
|
|
selectedMarket: {
|
|
|
|
name: string
|
2022-10-10 19:16:13 -07:00
|
|
|
current: Serum3Market | PerpMarket | undefined
|
2023-01-06 16:26:06 -08:00
|
|
|
fills: (FillEvent | any)[]
|
2022-12-14 12:54:08 -08:00
|
|
|
bidsAccount: BookSide | Orderbook | undefined
|
|
|
|
asksAccount: BookSide | Orderbook | undefined
|
|
|
|
orderbook: OrderbookL2
|
2022-11-25 02:10:23 -08:00
|
|
|
markPrice: number
|
2022-09-13 23:24:26 -07:00
|
|
|
}
|
|
|
|
serumMarkets: Serum3Market[]
|
2022-05-03 21:20:14 -07:00
|
|
|
serumOrders: Order[] | undefined
|
2022-09-21 21:25:24 -07:00
|
|
|
settings: {
|
|
|
|
loading: boolean
|
2022-09-22 21:00:42 -07:00
|
|
|
tours: TourSettings
|
2022-09-21 21:25:24 -07:00
|
|
|
uiLocked: boolean
|
|
|
|
}
|
2023-01-02 04:19:30 -08:00
|
|
|
successAnimation: {
|
|
|
|
swap: boolean
|
|
|
|
trade: boolean
|
|
|
|
}
|
2022-07-25 22:27:53 -07:00
|
|
|
swap: {
|
2022-08-18 13:50:34 -07:00
|
|
|
inputBank: Bank | undefined
|
|
|
|
outputBank: Bank | undefined
|
2022-08-02 11:04:00 -07:00
|
|
|
inputTokenInfo: Token | undefined
|
|
|
|
outputTokenInfo: Token | undefined
|
2022-08-08 10:42:18 -07:00
|
|
|
margin: boolean
|
|
|
|
slippage: number
|
2022-12-07 13:33:35 -08:00
|
|
|
swapMode: 'ExactIn' | 'ExactOut'
|
|
|
|
amountIn: string
|
|
|
|
amountOut: string
|
2022-07-25 22:27:53 -07:00
|
|
|
}
|
2022-05-03 21:20:14 -07:00
|
|
|
set: (x: (x: MangoStore) => void) => void
|
2022-12-05 19:23:22 -08:00
|
|
|
tokenStats: {
|
2022-12-11 02:08:50 -08:00
|
|
|
initialLoad: boolean
|
2022-12-05 19:23:22 -08:00
|
|
|
loading: boolean
|
2022-12-24 08:38:25 -08:00
|
|
|
data: TokenStatsItem[] | null
|
2022-12-05 19:23:22 -08:00
|
|
|
}
|
2022-12-14 12:54:25 -08:00
|
|
|
tradeForm: TradeForm
|
2023-02-08 01:58:03 -08:00
|
|
|
tradingView: {
|
|
|
|
orderLines: Map<string | BN, IOrderLineAdapter>
|
|
|
|
}
|
2022-07-05 20:37:49 -07:00
|
|
|
wallet: {
|
|
|
|
tokens: TokenAccount[]
|
2022-08-01 22:32:21 -07:00
|
|
|
nfts: {
|
|
|
|
data: NFT[] | []
|
|
|
|
loading: boolean
|
|
|
|
}
|
2022-07-05 20:37:49 -07:00
|
|
|
}
|
2022-05-03 21:20:14 -07:00
|
|
|
actions: {
|
2022-08-12 15:29:31 -07:00
|
|
|
fetchAccountInterestTotals: (mangoAccountPk: string) => Promise<void>
|
2022-09-26 23:22:51 -07:00
|
|
|
fetchActivityFeed: (
|
|
|
|
mangoAccountPk: string,
|
2022-09-28 20:35:34 -07:00
|
|
|
offset?: number,
|
|
|
|
params?: string
|
2022-09-26 23:22:51 -07:00
|
|
|
) => Promise<void>
|
2022-08-12 05:13:11 -07:00
|
|
|
fetchAccountPerformance: (
|
|
|
|
mangoAccountPk: string,
|
|
|
|
range: number
|
|
|
|
) => Promise<void>
|
2022-05-03 21:20:14 -07:00
|
|
|
fetchGroup: () => Promise<void>
|
2022-08-25 20:30:39 -07:00
|
|
|
reloadMangoAccount: () => Promise<void>
|
2023-01-14 13:50:45 -08:00
|
|
|
fetchMangoAccounts: (ownerPk: PublicKey) => Promise<void>
|
2022-08-01 22:32:21 -07:00
|
|
|
fetchNfts: (connection: Connection, walletPk: PublicKey) => void
|
2022-10-31 11:26:17 -07:00
|
|
|
fetchOpenOrders: (ma?: MangoAccount) => Promise<void>
|
2022-12-07 17:31:50 -08:00
|
|
|
fetchPerpStats: () => void
|
2022-09-20 18:03:59 -07:00
|
|
|
fetchProfileDetails: (walletPk: string) => void
|
2022-12-19 11:42:28 -08:00
|
|
|
fetchSwapHistory: (
|
|
|
|
mangoAccountPk: string,
|
2023-01-11 19:21:23 -08:00
|
|
|
timeout?: number,
|
|
|
|
offset?: number
|
2022-12-19 11:42:28 -08:00
|
|
|
) => Promise<void>
|
2022-12-05 19:23:22 -08:00
|
|
|
fetchTokenStats: () => void
|
2022-09-22 21:00:42 -07:00
|
|
|
fetchTourSettings: (walletPk: string) => void
|
2023-01-12 16:16:10 -08:00
|
|
|
fetchTradeHistory: (offset?: number) => Promise<void>
|
2023-01-14 13:50:45 -08:00
|
|
|
fetchWalletTokens: (walletPk: PublicKey) => Promise<void>
|
2022-09-27 11:47:15 -07:00
|
|
|
connectMangoClientWithWallet: (wallet: WalletAdapter) => Promise<void>
|
2022-11-20 20:16:11 -08:00
|
|
|
loadMarketFills: () => Promise<void>
|
2022-12-15 18:19:11 -08:00
|
|
|
updateConnection: (url: string) => void
|
2022-05-03 21:20:14 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-01 12:06:21 -07:00
|
|
|
const mangoStore = create<MangoStore>()(
|
|
|
|
subscribeWithSelector((_set, get) => {
|
2022-12-27 13:34:05 -08:00
|
|
|
let rpcUrl = ENDPOINT.url
|
2022-12-27 13:13:15 -08:00
|
|
|
|
2022-12-15 18:19:11 -08:00
|
|
|
if (typeof window !== 'undefined' && CLUSTER === 'mainnet-beta') {
|
|
|
|
const urlFromLocalStorage = localStorage.getItem(RPC_PROVIDER_KEY)
|
|
|
|
rpcUrl = urlFromLocalStorage
|
|
|
|
? JSON.parse(urlFromLocalStorage).value
|
2022-12-27 13:34:05 -08:00
|
|
|
: ENDPOINT.url
|
2022-12-15 18:19:11 -08:00
|
|
|
}
|
|
|
|
|
2022-12-27 13:34:05 -08:00
|
|
|
let connection: Connection
|
|
|
|
try {
|
2023-01-02 14:21:41 -08:00
|
|
|
connection = new web3.Connection(rpcUrl, CONNECTION_COMMITMENT)
|
2022-12-27 13:34:05 -08:00
|
|
|
} catch {
|
2023-01-02 14:21:41 -08:00
|
|
|
connection = new web3.Connection(ENDPOINT.url, CONNECTION_COMMITMENT)
|
2022-12-27 13:34:05 -08:00
|
|
|
}
|
2022-12-27 13:13:15 -08:00
|
|
|
const provider = new AnchorProvider(connection, emptyWallet, options)
|
2022-12-15 18:19:11 -08:00
|
|
|
provider.opts.skipPreflight = true
|
|
|
|
const client = initMangoClient(provider)
|
2022-12-27 13:13:15 -08:00
|
|
|
|
2022-05-03 21:20:14 -07:00
|
|
|
return {
|
2022-09-26 23:22:51 -07:00
|
|
|
activityFeed: {
|
|
|
|
feed: [],
|
2022-09-28 20:35:34 -07:00
|
|
|
loading: true,
|
2023-02-03 00:27:54 -08:00
|
|
|
queryParams: '',
|
2022-09-26 23:22:51 -07:00
|
|
|
},
|
2022-07-05 20:37:49 -07:00
|
|
|
connected: false,
|
2022-06-22 04:55:03 -07:00
|
|
|
connection,
|
2022-05-03 21:20:14 -07:00
|
|
|
group: undefined,
|
2022-09-27 11:47:15 -07:00
|
|
|
groupLoaded: false,
|
2022-12-15 18:19:11 -08:00
|
|
|
client,
|
2022-07-27 23:35:18 -07:00
|
|
|
mangoAccount: {
|
|
|
|
current: undefined,
|
2022-08-19 14:17:30 -07:00
|
|
|
initialLoad: true,
|
2022-10-29 17:30:37 -07:00
|
|
|
lastSlot: 0,
|
2022-09-25 19:00:19 -07:00
|
|
|
openOrderAccounts: [],
|
|
|
|
openOrders: {},
|
2022-11-01 06:10:08 -07:00
|
|
|
perpPositions: [],
|
2022-09-25 19:00:19 -07:00
|
|
|
spotBalances: {},
|
2023-01-18 16:19:46 -08:00
|
|
|
interestTotals: { data: [], loading: false },
|
2023-02-11 04:40:23 -08:00
|
|
|
performance: { data: [], loading: true },
|
2023-01-18 20:33:51 -08:00
|
|
|
swapHistory: { data: [], loading: true },
|
2023-01-12 16:16:10 -08:00
|
|
|
tradeHistory: { data: [], loading: true },
|
2022-07-27 23:35:18 -07:00
|
|
|
},
|
2022-10-07 04:47:15 -07:00
|
|
|
mangoAccounts: [],
|
2022-05-03 21:20:14 -07:00
|
|
|
markets: undefined,
|
2022-07-05 20:37:49 -07:00
|
|
|
notificationIdCounter: 0,
|
|
|
|
notifications: [],
|
2022-10-10 19:16:13 -07:00
|
|
|
perpMarkets: [],
|
2022-12-07 17:31:50 -08:00
|
|
|
perpStats: {
|
|
|
|
loading: false,
|
|
|
|
data: [],
|
|
|
|
},
|
2022-09-20 18:03:59 -07:00
|
|
|
profile: {
|
|
|
|
loadDetails: false,
|
|
|
|
details: { profile_name: '', trader_category: '', wallet_pk: '' },
|
|
|
|
},
|
2022-09-13 23:24:26 -07:00
|
|
|
selectedMarket: {
|
2022-11-21 19:56:56 -08:00
|
|
|
name: DEFAULT_MARKET_NAME,
|
2022-09-13 23:24:26 -07:00
|
|
|
current: undefined,
|
2022-11-20 20:16:11 -08:00
|
|
|
fills: [],
|
2022-11-30 07:46:20 -08:00
|
|
|
bidsAccount: undefined,
|
|
|
|
asksAccount: undefined,
|
2022-09-13 23:24:26 -07:00
|
|
|
orderbook: {
|
|
|
|
bids: [],
|
|
|
|
asks: [],
|
|
|
|
},
|
2022-11-25 02:10:23 -08:00
|
|
|
markPrice: 0,
|
2022-09-13 23:24:26 -07:00
|
|
|
},
|
|
|
|
serumMarkets: [],
|
2022-05-03 21:20:14 -07:00
|
|
|
serumOrders: undefined,
|
2022-09-01 12:06:21 -07:00
|
|
|
set: (fn) => _set(produce(fn)),
|
2022-09-13 23:24:26 -07:00
|
|
|
settings: {
|
2022-09-21 21:25:24 -07:00
|
|
|
loading: false,
|
2022-09-22 21:00:42 -07:00
|
|
|
tours: {
|
|
|
|
account_tour_seen: true,
|
|
|
|
swap_tour_seen: true,
|
|
|
|
trade_tour_seen: true,
|
|
|
|
wallet_pk: '',
|
|
|
|
},
|
2022-09-13 23:24:26 -07:00
|
|
|
uiLocked: true,
|
|
|
|
},
|
2023-01-02 04:19:30 -08:00
|
|
|
successAnimation: {
|
|
|
|
swap: false,
|
|
|
|
trade: false,
|
|
|
|
},
|
2022-12-07 13:33:35 -08:00
|
|
|
swap: {
|
|
|
|
inputBank: undefined,
|
|
|
|
outputBank: undefined,
|
|
|
|
inputTokenInfo: undefined,
|
|
|
|
outputTokenInfo: undefined,
|
|
|
|
margin: true,
|
|
|
|
slippage: 0.5,
|
|
|
|
swapMode: 'ExactIn',
|
|
|
|
amountIn: '',
|
|
|
|
amountOut: '',
|
|
|
|
},
|
2022-12-05 19:23:22 -08:00
|
|
|
tokenStats: {
|
2022-12-11 02:08:50 -08:00
|
|
|
initialLoad: false,
|
2022-12-05 19:23:22 -08:00
|
|
|
loading: false,
|
|
|
|
data: [],
|
|
|
|
},
|
2022-12-14 12:54:25 -08:00
|
|
|
tradeForm: DEFAULT_TRADE_FORM,
|
2023-02-08 01:58:03 -08:00
|
|
|
tradingView: {
|
|
|
|
orderLines: new Map(),
|
|
|
|
},
|
2022-07-05 20:37:49 -07:00
|
|
|
wallet: {
|
|
|
|
tokens: [],
|
2022-08-01 22:32:21 -07:00
|
|
|
nfts: {
|
|
|
|
data: [],
|
|
|
|
loading: false,
|
|
|
|
},
|
2022-07-05 20:37:49 -07:00
|
|
|
},
|
2022-05-03 21:20:14 -07:00
|
|
|
actions: {
|
2022-08-12 15:29:31 -07:00
|
|
|
fetchAccountInterestTotals: async (mangoAccountPk: string) => {
|
2022-08-12 05:13:11 -07:00
|
|
|
const set = get().set
|
|
|
|
set((state) => {
|
2023-01-15 21:13:34 -08:00
|
|
|
state.mangoAccount.interestTotals.loading = true
|
2022-08-12 05:13:11 -07:00
|
|
|
})
|
|
|
|
try {
|
|
|
|
const response = await fetch(
|
2023-01-18 05:13:29 -08:00
|
|
|
`${MANGO_DATA_API_URL}/stats/interest-account-total?mango-account=${mangoAccountPk}`
|
2022-08-12 05:13:11 -07:00
|
|
|
)
|
|
|
|
const parsedResponse = await response.json()
|
|
|
|
const entries: any = Object.entries(parsedResponse).sort((a, b) =>
|
|
|
|
b[0].localeCompare(a[0])
|
|
|
|
)
|
|
|
|
|
|
|
|
const stats = entries
|
|
|
|
.map(([key, value]: Array<{ key: string; value: number }>) => {
|
|
|
|
return { ...value, symbol: key }
|
|
|
|
})
|
|
|
|
.filter((x: string) => x)
|
|
|
|
|
|
|
|
set((state) => {
|
2023-01-15 21:13:34 -08:00
|
|
|
state.mangoAccount.interestTotals.data = stats
|
|
|
|
state.mangoAccount.interestTotals.loading = false
|
2022-08-12 05:13:11 -07:00
|
|
|
})
|
|
|
|
} catch {
|
|
|
|
set((state) => {
|
2023-01-15 21:13:34 -08:00
|
|
|
state.mangoAccount.interestTotals.loading = false
|
2022-08-12 05:13:11 -07:00
|
|
|
})
|
2022-12-24 08:54:04 -08:00
|
|
|
console.error({
|
2022-08-12 05:13:11 -07:00
|
|
|
title: 'Failed to load account interest totals',
|
|
|
|
type: 'error',
|
|
|
|
})
|
|
|
|
}
|
|
|
|
},
|
|
|
|
fetchAccountPerformance: async (
|
|
|
|
mangoAccountPk: string,
|
|
|
|
range: number
|
|
|
|
) => {
|
|
|
|
const set = get().set
|
|
|
|
try {
|
|
|
|
const response = await fetch(
|
2023-01-18 05:13:29 -08:00
|
|
|
`${MANGO_DATA_API_URL}/stats/performance_account?mango-account=${mangoAccountPk}&start-date=${dayjs()
|
2022-08-12 05:13:11 -07:00
|
|
|
.subtract(range, 'day')
|
|
|
|
.format('YYYY-MM-DD')}`
|
|
|
|
)
|
|
|
|
const parsedResponse = await response.json()
|
|
|
|
const entries: any = Object.entries(parsedResponse).sort((a, b) =>
|
|
|
|
b[0].localeCompare(a[0])
|
|
|
|
)
|
|
|
|
|
|
|
|
const stats = entries
|
|
|
|
.map(([key, value]: Array<{ key: string; value: number }>) => {
|
|
|
|
return { ...value, time: key }
|
|
|
|
})
|
|
|
|
.filter((x: string) => x)
|
|
|
|
|
|
|
|
set((state) => {
|
2023-01-15 21:13:34 -08:00
|
|
|
state.mangoAccount.performance.data = stats.reverse()
|
2022-08-12 05:13:11 -07:00
|
|
|
})
|
2022-12-02 15:27:08 -08:00
|
|
|
} catch (e) {
|
2023-01-15 21:13:34 -08:00
|
|
|
console.error('Failed to load account performance data', e)
|
|
|
|
} finally {
|
2022-08-12 05:13:11 -07:00
|
|
|
set((state) => {
|
2023-01-15 21:13:34 -08:00
|
|
|
state.mangoAccount.performance.loading = false
|
2022-08-12 05:13:11 -07:00
|
|
|
})
|
|
|
|
}
|
|
|
|
},
|
2022-09-28 20:35:34 -07:00
|
|
|
fetchActivityFeed: async (
|
|
|
|
mangoAccountPk: string,
|
|
|
|
offset = 0,
|
|
|
|
params = ''
|
|
|
|
) => {
|
2022-09-26 23:22:51 -07:00
|
|
|
const set = get().set
|
2023-01-11 19:21:23 -08:00
|
|
|
const loadedFeed = mangoStore.getState().activityFeed.feed
|
2022-12-04 19:46:31 -08:00
|
|
|
const connectedMangoAccountPk = mangoStore
|
|
|
|
.getState()
|
|
|
|
.mangoAccount.current?.publicKey.toString()
|
2022-12-19 21:33:43 -08:00
|
|
|
|
2022-09-26 23:22:51 -07:00
|
|
|
try {
|
|
|
|
const response = await fetch(
|
2023-01-18 16:11:02 -08:00
|
|
|
`${MANGO_DATA_API_URL}/stats/activity-feed?mango-account=${mangoAccountPk}&offset=${offset}&limit=${PAGINATION_PAGE_LENGTH}${
|
2022-09-29 20:22:55 -07:00
|
|
|
params ? params : ''
|
|
|
|
}`
|
2022-09-26 23:22:51 -07:00
|
|
|
)
|
|
|
|
const parsedResponse = await response.json()
|
|
|
|
const entries: any = Object.entries(parsedResponse).sort((a, b) =>
|
|
|
|
b[0].localeCompare(a[0])
|
|
|
|
)
|
|
|
|
|
2022-12-04 19:46:31 -08:00
|
|
|
const latestFeed = entries
|
|
|
|
.map(([key, value]: Array<{ key: string; value: number }>) => {
|
|
|
|
return { ...value, symbol: key }
|
|
|
|
})
|
|
|
|
.filter((x: string) => x)
|
|
|
|
.sort(
|
|
|
|
(
|
|
|
|
a: DepositWithdrawFeedItem | LiquidationFeedItem,
|
|
|
|
b: DepositWithdrawFeedItem | LiquidationFeedItem
|
|
|
|
) =>
|
|
|
|
dayjs(b.block_datetime).unix() -
|
|
|
|
dayjs(a.block_datetime).unix()
|
|
|
|
)
|
|
|
|
|
2022-12-20 01:32:17 -08:00
|
|
|
// only add to current feed if data request is offset and the mango account hasn't changed
|
2023-01-11 19:21:23 -08:00
|
|
|
const combinedFeed =
|
2022-12-20 01:32:17 -08:00
|
|
|
offset !== 0 &&
|
2022-12-04 19:46:31 -08:00
|
|
|
connectedMangoAccountPk ===
|
2023-01-11 19:21:23 -08:00
|
|
|
loadedFeed[0]?.activity_details?.mango_account
|
|
|
|
? loadedFeed.concat(latestFeed)
|
2022-12-04 19:46:31 -08:00
|
|
|
: latestFeed
|
2022-09-26 23:22:51 -07:00
|
|
|
|
|
|
|
set((state) => {
|
2023-01-11 19:21:23 -08:00
|
|
|
state.activityFeed.feed = combinedFeed
|
2022-09-26 23:22:51 -07:00
|
|
|
})
|
2023-02-03 00:27:54 -08:00
|
|
|
} catch (e) {
|
|
|
|
console.log('Failed to fetch account activity feed', e)
|
2022-09-26 23:22:51 -07:00
|
|
|
} finally {
|
|
|
|
set((state) => {
|
|
|
|
state.activityFeed.loading = false
|
|
|
|
})
|
|
|
|
}
|
|
|
|
},
|
2022-05-03 21:20:14 -07:00
|
|
|
fetchGroup: async () => {
|
|
|
|
try {
|
2022-06-21 03:58:57 -07:00
|
|
|
const set = get().set
|
2022-05-03 21:20:14 -07:00
|
|
|
const client = get().client
|
2022-08-03 14:46:37 -07:00
|
|
|
const group = await client.getGroup(GROUP)
|
2022-11-21 19:56:56 -08:00
|
|
|
const selectedMarketName = get().selectedMarket.name
|
2022-09-13 23:24:26 -07:00
|
|
|
|
2022-08-19 21:03:26 -07:00
|
|
|
const inputBank =
|
|
|
|
group?.banksMapByName.get(INPUT_TOKEN_DEFAULT)?.[0]
|
|
|
|
const outputBank =
|
|
|
|
group?.banksMapByName.get(OUTPUT_TOKEN_DEFAULT)?.[0]
|
2022-09-13 23:24:26 -07:00
|
|
|
const serumMarkets = Array.from(
|
|
|
|
group.serum3MarketsMapByExternal.values()
|
|
|
|
)
|
2023-02-07 06:17:24 -08:00
|
|
|
const perpMarkets = Array.from(
|
|
|
|
group.perpMarketsMapByName.values()
|
|
|
|
).filter(
|
|
|
|
(p) =>
|
|
|
|
p.publicKey.toString() !==
|
|
|
|
'9Y8paZ5wUpzLFfQuHz8j2RtPrKsDtHx9sbgFmWb5abCw'
|
|
|
|
)
|
2022-08-03 14:46:37 -07:00
|
|
|
|
2022-11-21 19:56:56 -08:00
|
|
|
const defaultMarket =
|
|
|
|
serumMarkets.find((m) => m.name === selectedMarketName) ||
|
|
|
|
perpMarkets.find((m) => m.name === selectedMarketName)
|
|
|
|
serumMarkets[0]
|
|
|
|
|
2022-05-03 21:20:14 -07:00
|
|
|
set((state) => {
|
|
|
|
state.group = group
|
2022-09-27 11:47:15 -07:00
|
|
|
state.groupLoaded = true
|
2022-09-13 23:24:26 -07:00
|
|
|
state.serumMarkets = serumMarkets
|
2022-10-10 19:16:13 -07:00
|
|
|
state.perpMarkets = perpMarkets
|
2022-09-13 23:24:26 -07:00
|
|
|
state.selectedMarket.current =
|
2022-11-21 19:56:56 -08:00
|
|
|
state.selectedMarket.current || defaultMarket
|
2022-08-19 21:03:26 -07:00
|
|
|
if (!state.swap.inputBank && !state.swap.outputBank) {
|
|
|
|
state.swap.inputBank = inputBank
|
|
|
|
state.swap.outputBank = outputBank
|
2022-08-25 17:39:09 -07:00
|
|
|
} else {
|
2022-08-26 09:01:28 -07:00
|
|
|
state.swap.inputBank = group.getFirstBankByMint(
|
|
|
|
state.swap.inputBank!.mint
|
|
|
|
)
|
2022-08-25 17:39:09 -07:00
|
|
|
state.swap.outputBank = group.getFirstBankByMint(
|
2022-08-26 09:01:28 -07:00
|
|
|
state.swap.outputBank!.mint
|
2022-08-25 17:39:09 -07:00
|
|
|
)
|
2022-08-19 21:03:26 -07:00
|
|
|
}
|
2022-05-03 21:20:14 -07:00
|
|
|
})
|
|
|
|
} catch (e) {
|
2022-12-14 07:47:47 -08:00
|
|
|
notify({ type: 'info', title: 'Unable to refresh data' })
|
2022-05-03 21:20:14 -07:00
|
|
|
console.error('Error fetching group', e)
|
|
|
|
}
|
|
|
|
},
|
2022-08-19 14:17:30 -07:00
|
|
|
reloadMangoAccount: async () => {
|
2022-08-03 14:46:37 -07:00
|
|
|
const set = get().set
|
2022-08-31 07:54:37 -07:00
|
|
|
const actions = get().actions
|
2022-05-03 21:20:14 -07:00
|
|
|
try {
|
|
|
|
const group = get().group
|
2022-08-18 13:50:34 -07:00
|
|
|
const client = get().client
|
2022-08-19 14:17:30 -07:00
|
|
|
const mangoAccount = get().mangoAccount.current
|
2022-10-29 17:30:37 -07:00
|
|
|
const lastSlot = get().mangoAccount.lastSlot
|
2022-05-31 18:41:18 -07:00
|
|
|
if (!group) throw new Error('Group not loaded')
|
2022-08-19 14:17:30 -07:00
|
|
|
if (!mangoAccount)
|
|
|
|
throw new Error('No mango account exists for reload')
|
2022-05-03 21:20:14 -07:00
|
|
|
|
2022-10-29 17:30:37 -07:00
|
|
|
const { value: reloadedMangoAccount, slot } =
|
|
|
|
await mangoAccount.reloadWithSlot(client)
|
|
|
|
if (slot > lastSlot) {
|
2023-02-03 13:27:31 -08:00
|
|
|
const ma = get().mangoAccounts.find((ma) =>
|
|
|
|
ma.publicKey.equals(reloadedMangoAccount.publicKey)
|
|
|
|
)
|
|
|
|
if (ma) {
|
|
|
|
Object.assign(ma, reloadedMangoAccount)
|
|
|
|
}
|
2022-10-29 17:30:37 -07:00
|
|
|
set((state) => {
|
|
|
|
state.mangoAccount.current = reloadedMangoAccount
|
|
|
|
state.mangoAccount.lastSlot = slot
|
|
|
|
})
|
|
|
|
}
|
2022-05-03 21:20:14 -07:00
|
|
|
} catch (e) {
|
2022-08-19 14:17:30 -07:00
|
|
|
console.error('Error reloading mango acct', e)
|
2022-08-31 07:54:37 -07:00
|
|
|
actions.reloadMangoAccount()
|
2022-08-19 14:17:30 -07:00
|
|
|
} finally {
|
2022-07-27 23:35:18 -07:00
|
|
|
set((state) => {
|
2022-08-19 14:17:30 -07:00
|
|
|
state.mangoAccount.initialLoad = false
|
2022-07-27 23:35:18 -07:00
|
|
|
})
|
2022-05-03 21:20:14 -07:00
|
|
|
}
|
|
|
|
},
|
2023-01-14 13:50:45 -08:00
|
|
|
fetchMangoAccounts: async (ownerPk: PublicKey) => {
|
2022-08-22 18:47:08 -07:00
|
|
|
const set = get().set
|
2022-08-31 07:54:37 -07:00
|
|
|
const actions = get().actions
|
2022-08-01 18:08:08 -07:00
|
|
|
try {
|
|
|
|
const group = get().group
|
|
|
|
const client = get().client
|
2022-08-19 14:17:30 -07:00
|
|
|
const selectedMangoAccount = get().mangoAccount.current
|
2022-08-01 18:08:08 -07:00
|
|
|
if (!group) throw new Error('Group not loaded')
|
|
|
|
if (!client) throw new Error('Client not loaded')
|
|
|
|
|
2022-08-04 09:42:03 -07:00
|
|
|
const mangoAccounts = await client.getMangoAccountsForOwner(
|
2022-08-01 18:08:08 -07:00
|
|
|
group,
|
2023-01-14 13:50:45 -08:00
|
|
|
ownerPk
|
2022-08-01 18:08:08 -07:00
|
|
|
)
|
2022-11-03 09:59:21 -07:00
|
|
|
const selectedAccountIsNotInAccountsList = mangoAccounts.find(
|
|
|
|
(x) =>
|
|
|
|
x.publicKey.toBase58() ===
|
|
|
|
selectedMangoAccount?.publicKey.toBase58()
|
|
|
|
)
|
|
|
|
if (!mangoAccounts?.length) {
|
|
|
|
set((state) => {
|
|
|
|
state.mangoAccounts = []
|
|
|
|
state.mangoAccount.current = undefined
|
|
|
|
})
|
|
|
|
return
|
|
|
|
}
|
2022-08-19 14:17:30 -07:00
|
|
|
|
|
|
|
let newSelectedMangoAccount = selectedMangoAccount
|
2022-11-03 09:59:21 -07:00
|
|
|
if (!selectedMangoAccount || !selectedAccountIsNotInAccountsList) {
|
2022-08-19 14:17:30 -07:00
|
|
|
const lastAccount = localStorage.getItem(LAST_ACCOUNT_KEY)
|
|
|
|
newSelectedMangoAccount = mangoAccounts[0]
|
|
|
|
|
|
|
|
if (typeof lastAccount === 'string') {
|
|
|
|
const lastViewedAccount = mangoAccounts.find(
|
|
|
|
(m) => m.publicKey.toString() === lastAccount
|
|
|
|
)
|
|
|
|
newSelectedMangoAccount = lastViewedAccount || mangoAccounts[0]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (newSelectedMangoAccount) {
|
2023-02-09 13:22:54 -08:00
|
|
|
await newSelectedMangoAccount.reloadSerum3OpenOrders(client)
|
2023-01-14 12:02:15 -08:00
|
|
|
set((state) => {
|
|
|
|
state.mangoAccount.current = newSelectedMangoAccount
|
|
|
|
state.mangoAccount.initialLoad = false
|
|
|
|
})
|
|
|
|
actions.fetchOpenOrders(newSelectedMangoAccount)
|
2022-08-19 14:17:30 -07:00
|
|
|
}
|
|
|
|
|
2023-01-14 12:02:15 -08:00
|
|
|
await Promise.all(
|
2023-02-09 13:22:54 -08:00
|
|
|
mangoAccounts.map((ma) => ma.reloadSerum3OpenOrders(client))
|
2023-01-14 12:02:15 -08:00
|
|
|
)
|
|
|
|
|
2022-08-16 16:49:39 -07:00
|
|
|
set((state) => {
|
2022-10-07 04:47:15 -07:00
|
|
|
state.mangoAccounts = mangoAccounts
|
2022-08-16 16:49:39 -07:00
|
|
|
})
|
2022-08-01 18:08:08 -07:00
|
|
|
} catch (e) {
|
|
|
|
console.error('Error fetching mango accts', e)
|
2023-01-16 13:09:15 -08:00
|
|
|
} finally {
|
|
|
|
set((state) => {
|
|
|
|
state.mangoAccount.initialLoad = false
|
|
|
|
})
|
2022-08-01 18:08:08 -07:00
|
|
|
}
|
|
|
|
},
|
2022-08-01 22:32:21 -07:00
|
|
|
fetchNfts: async (connection: Connection, ownerPk: PublicKey) => {
|
|
|
|
const set = get().set
|
|
|
|
set((state) => {
|
|
|
|
state.wallet.nfts.loading = true
|
|
|
|
})
|
|
|
|
try {
|
|
|
|
const data = await fetchNftsFromHolaplexIndexer(ownerPk)
|
|
|
|
set((state) => {
|
|
|
|
state.wallet.nfts.data = data.nfts
|
|
|
|
state.wallet.nfts.loading = false
|
|
|
|
})
|
|
|
|
} catch (error) {
|
|
|
|
notify({
|
|
|
|
type: 'error',
|
|
|
|
title: 'Unable to fetch nfts',
|
|
|
|
})
|
|
|
|
}
|
|
|
|
return []
|
|
|
|
},
|
2022-10-31 11:26:17 -07:00
|
|
|
fetchOpenOrders: async (providedMangoAccount) => {
|
2022-09-13 23:24:26 -07:00
|
|
|
const set = get().set
|
|
|
|
const client = get().client
|
2022-12-03 13:56:22 -08:00
|
|
|
const group = get().group
|
2022-12-14 17:07:48 -08:00
|
|
|
if (!providedMangoAccount) {
|
|
|
|
await get().actions.reloadMangoAccount()
|
|
|
|
}
|
2022-09-25 19:00:19 -07:00
|
|
|
const mangoAccount =
|
|
|
|
providedMangoAccount || get().mangoAccount.current
|
2022-09-13 23:24:26 -07:00
|
|
|
|
2022-12-03 13:56:22 -08:00
|
|
|
if (!mangoAccount || !group) return
|
2022-09-25 19:00:19 -07:00
|
|
|
|
2022-09-13 23:24:26 -07:00
|
|
|
try {
|
2022-11-19 17:40:06 -08:00
|
|
|
const openOrders: Record<string, Order[] | PerpOrder[]> = {}
|
2022-10-31 11:26:17 -07:00
|
|
|
let serumOpenOrderAccounts: OpenOrders[] = []
|
|
|
|
|
|
|
|
for (const serum3Orders of mangoAccount.serum3Active()) {
|
2022-10-27 11:39:43 -07:00
|
|
|
if (serum3Orders.marketIndex === 65535) continue
|
2022-10-07 05:22:18 -07:00
|
|
|
const market = group.getSerum3MarketByMarketIndex(
|
2022-09-25 19:00:19 -07:00
|
|
|
serum3Orders.marketIndex
|
|
|
|
)
|
|
|
|
if (market) {
|
|
|
|
const orders = await mangoAccount.loadSerum3OpenOrdersForMarket(
|
|
|
|
client,
|
|
|
|
group,
|
|
|
|
market.serumMarketExternal
|
|
|
|
)
|
|
|
|
openOrders[market.serumMarketExternal.toString()] = orders
|
|
|
|
}
|
|
|
|
}
|
2022-10-31 11:26:17 -07:00
|
|
|
if (
|
|
|
|
mangoAccount.serum3Active().length &&
|
|
|
|
Object.keys(openOrders).length
|
|
|
|
) {
|
|
|
|
serumOpenOrderAccounts =
|
2022-10-27 11:39:43 -07:00
|
|
|
await mangoAccount.loadSerum3OpenOrdersAccounts(client)
|
|
|
|
}
|
2022-10-31 11:26:17 -07:00
|
|
|
|
|
|
|
for (const perpOrder of mangoAccount.perpOrdersActive()) {
|
|
|
|
const market = group.getPerpMarketByMarketIndex(
|
|
|
|
perpOrder.orderMarket
|
|
|
|
)
|
|
|
|
const orders = await mangoAccount.loadPerpOpenOrdersForMarket(
|
|
|
|
client,
|
|
|
|
group,
|
|
|
|
perpOrder.orderMarket
|
|
|
|
)
|
|
|
|
openOrders[market.publicKey.toString()] = orders
|
|
|
|
}
|
|
|
|
|
|
|
|
set((s) => {
|
|
|
|
s.mangoAccount.openOrders = openOrders
|
|
|
|
s.mangoAccount.openOrderAccounts = serumOpenOrderAccounts
|
|
|
|
})
|
2022-09-13 23:24:26 -07:00
|
|
|
} catch (e) {
|
|
|
|
console.error('Failed loading open orders ', e)
|
|
|
|
}
|
|
|
|
},
|
2022-12-07 17:31:50 -08:00
|
|
|
fetchPerpStats: async () => {
|
|
|
|
const set = get().set
|
|
|
|
const group = get().group
|
|
|
|
const stats = get().perpStats.data
|
2023-02-09 19:20:46 -08:00
|
|
|
if ((stats && stats.length) || !group) return
|
2022-12-07 17:31:50 -08:00
|
|
|
set((state) => {
|
|
|
|
state.perpStats.loading = true
|
|
|
|
})
|
|
|
|
try {
|
|
|
|
const response = await fetch(
|
2023-01-18 05:13:29 -08:00
|
|
|
`${MANGO_DATA_API_URL}/perp-historical-stats?mango-group=${group?.publicKey.toString()}`
|
2022-12-07 17:31:50 -08:00
|
|
|
)
|
|
|
|
const data = await response.json()
|
|
|
|
|
|
|
|
set((state) => {
|
|
|
|
state.perpStats.data = data
|
|
|
|
state.perpStats.loading = false
|
|
|
|
})
|
|
|
|
} catch {
|
|
|
|
set((state) => {
|
|
|
|
state.perpStats.loading = false
|
|
|
|
})
|
|
|
|
notify({
|
|
|
|
title: 'Failed to fetch token stats data',
|
|
|
|
type: 'error',
|
|
|
|
})
|
|
|
|
}
|
|
|
|
},
|
2023-01-11 19:21:23 -08:00
|
|
|
fetchSwapHistory: async (
|
|
|
|
mangoAccountPk: string,
|
|
|
|
timeout = 0,
|
|
|
|
offset = 0
|
|
|
|
) => {
|
2022-08-12 23:06:09 -07:00
|
|
|
const set = get().set
|
2023-01-11 19:21:23 -08:00
|
|
|
const loadedSwapHistory =
|
2023-01-18 20:33:51 -08:00
|
|
|
mangoStore.getState().mangoAccount.swapHistory.data
|
2023-01-11 19:21:23 -08:00
|
|
|
|
2022-12-19 11:42:28 -08:00
|
|
|
setTimeout(async () => {
|
|
|
|
try {
|
|
|
|
const history = await fetch(
|
2023-01-18 20:33:51 -08:00
|
|
|
`${MANGO_DATA_API_URL}/stats/swap-history?mango-account=${mangoAccountPk}&offset=${offset}&limit=${PAGINATION_PAGE_LENGTH}`
|
2022-12-19 11:42:28 -08:00
|
|
|
)
|
|
|
|
const parsedHistory = await history.json()
|
|
|
|
const sortedHistory =
|
|
|
|
parsedHistory && parsedHistory.length
|
|
|
|
? parsedHistory.sort(
|
|
|
|
(a: SwapHistoryItem, b: SwapHistoryItem) =>
|
|
|
|
dayjs(b.block_datetime).unix() -
|
|
|
|
dayjs(a.block_datetime).unix()
|
|
|
|
)
|
|
|
|
: []
|
2022-08-12 23:06:09 -07:00
|
|
|
|
2023-01-11 19:21:23 -08:00
|
|
|
const combinedHistory =
|
2023-01-18 02:36:45 -08:00
|
|
|
offset !== 0
|
2023-01-11 19:21:23 -08:00
|
|
|
? loadedSwapHistory.concat(sortedHistory)
|
|
|
|
: sortedHistory
|
|
|
|
|
2022-12-19 11:42:28 -08:00
|
|
|
set((state) => {
|
2023-01-18 20:33:51 -08:00
|
|
|
state.mangoAccount.swapHistory.data = combinedHistory
|
2022-12-19 11:42:28 -08:00
|
|
|
})
|
2023-01-18 02:36:45 -08:00
|
|
|
} catch (e) {
|
|
|
|
console.error('Unable to fetch swap history', e)
|
2023-01-11 19:21:23 -08:00
|
|
|
} finally {
|
2022-12-19 11:42:28 -08:00
|
|
|
set((state) => {
|
2023-01-18 20:33:51 -08:00
|
|
|
state.mangoAccount.swapHistory.loading = false
|
2022-12-19 11:42:28 -08:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}, timeout)
|
2022-08-12 23:06:09 -07:00
|
|
|
},
|
2022-12-05 19:23:22 -08:00
|
|
|
fetchTokenStats: async () => {
|
|
|
|
const set = get().set
|
|
|
|
const group = get().group
|
2022-12-11 02:08:50 -08:00
|
|
|
if (!group) return
|
2022-12-05 19:23:22 -08:00
|
|
|
set((state) => {
|
|
|
|
state.tokenStats.loading = true
|
|
|
|
})
|
|
|
|
try {
|
|
|
|
const response = await fetch(
|
2023-01-18 05:13:29 -08:00
|
|
|
`${MANGO_DATA_API_URL}/token-historical-stats?mango-group=${group?.publicKey.toString()}`
|
2022-12-05 19:23:22 -08:00
|
|
|
)
|
|
|
|
const data = await response.json()
|
|
|
|
|
|
|
|
set((state) => {
|
|
|
|
state.tokenStats.data = data
|
2022-12-11 02:08:50 -08:00
|
|
|
state.tokenStats.initialLoad = true
|
2022-12-05 19:23:22 -08:00
|
|
|
state.tokenStats.loading = false
|
|
|
|
})
|
|
|
|
} catch {
|
|
|
|
set((state) => {
|
|
|
|
state.tokenStats.loading = false
|
|
|
|
})
|
|
|
|
notify({
|
2022-12-07 17:31:50 -08:00
|
|
|
title: 'Failed to fetch token stats data',
|
2022-12-05 19:23:22 -08:00
|
|
|
type: 'error',
|
|
|
|
})
|
|
|
|
}
|
|
|
|
},
|
2023-01-14 13:50:45 -08:00
|
|
|
fetchWalletTokens: async (walletPk: PublicKey) => {
|
2022-07-05 20:37:49 -07:00
|
|
|
const set = get().set
|
|
|
|
const connection = get().connection
|
|
|
|
|
2023-01-14 13:50:45 -08:00
|
|
|
if (walletPk) {
|
2022-07-05 20:37:49 -07:00
|
|
|
const token = await getTokenAccountsByOwnerWithWrappedSol(
|
|
|
|
connection,
|
2023-01-14 13:50:45 -08:00
|
|
|
walletPk
|
2022-07-05 20:37:49 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
set((state) => {
|
|
|
|
state.wallet.tokens = token
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
set((state) => {
|
|
|
|
state.wallet.tokens = []
|
|
|
|
})
|
|
|
|
}
|
|
|
|
},
|
2022-09-27 11:47:15 -07:00
|
|
|
connectMangoClientWithWallet: async (wallet: WalletAdapter) => {
|
2022-09-01 12:06:21 -07:00
|
|
|
const set = get().set
|
2022-08-18 13:50:34 -07:00
|
|
|
try {
|
|
|
|
const provider = new AnchorProvider(
|
|
|
|
connection,
|
2022-09-27 11:47:15 -07:00
|
|
|
wallet.adapter as unknown as Wallet,
|
2022-08-18 13:50:34 -07:00
|
|
|
options
|
|
|
|
)
|
|
|
|
provider.opts.skipPreflight = true
|
2023-01-19 12:31:45 -08:00
|
|
|
const prioritizationFee = Number(
|
2023-02-03 13:23:36 -08:00
|
|
|
localStorage.getItem(PRIORITY_FEE_KEY) ??
|
|
|
|
DEFAULT_PRIORITY_FEE.value
|
2023-01-19 12:31:45 -08:00
|
|
|
)
|
|
|
|
const client = initMangoClient(provider, { prioritizationFee })
|
2022-12-27 13:13:15 -08:00
|
|
|
|
2022-08-18 13:50:34 -07:00
|
|
|
set((s) => {
|
|
|
|
s.client = client
|
|
|
|
})
|
|
|
|
} catch (e: any) {
|
|
|
|
if (e.name.includes('WalletLoadError')) {
|
|
|
|
notify({
|
|
|
|
title: `${wallet.adapter.name} Error`,
|
|
|
|
type: 'error',
|
|
|
|
description: `Please install ${wallet.adapter.name} and then reload this page.`,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2022-09-21 21:25:24 -07:00
|
|
|
async fetchProfileDetails(walletPk: string) {
|
2022-07-26 21:40:17 -07:00
|
|
|
const set = get().set
|
2022-09-21 21:25:24 -07:00
|
|
|
set((state) => {
|
|
|
|
state.profile.loadDetails = true
|
|
|
|
})
|
2022-07-26 21:40:17 -07:00
|
|
|
try {
|
2022-09-21 21:25:24 -07:00
|
|
|
const response = await fetch(
|
2023-01-18 05:13:29 -08:00
|
|
|
`${MANGO_DATA_API_URL}/user-data/profile-details?wallet-pk=${walletPk}`
|
2022-09-21 21:25:24 -07:00
|
|
|
)
|
|
|
|
const data = await response.json()
|
2022-07-26 21:40:17 -07:00
|
|
|
set((state) => {
|
2022-09-21 21:25:24 -07:00
|
|
|
state.profile.details = data
|
|
|
|
state.profile.loadDetails = false
|
2022-07-26 21:40:17 -07:00
|
|
|
})
|
|
|
|
} catch (e) {
|
2022-09-21 21:25:24 -07:00
|
|
|
notify({ type: 'error', title: 'Failed to load profile details' })
|
2022-11-01 11:13:02 -07:00
|
|
|
console.error(e)
|
2022-07-26 21:40:17 -07:00
|
|
|
set((state) => {
|
2022-09-21 21:25:24 -07:00
|
|
|
state.profile.loadDetails = false
|
2022-07-26 21:40:17 -07:00
|
|
|
})
|
|
|
|
}
|
|
|
|
},
|
2022-09-22 21:00:42 -07:00
|
|
|
async fetchTourSettings(walletPk: string) {
|
2022-09-20 18:03:59 -07:00
|
|
|
const set = get().set
|
|
|
|
set((state) => {
|
2022-09-21 21:25:24 -07:00
|
|
|
state.settings.loading = true
|
2022-09-20 18:03:59 -07:00
|
|
|
})
|
|
|
|
try {
|
|
|
|
const response = await fetch(
|
2023-01-18 05:13:29 -08:00
|
|
|
`${MANGO_DATA_API_URL}/user-data/settings-unsigned?wallet-pk=${walletPk}`
|
2022-09-20 18:03:59 -07:00
|
|
|
)
|
|
|
|
const data = await response.json()
|
|
|
|
set((state) => {
|
2022-09-22 21:00:42 -07:00
|
|
|
state.settings.tours = data
|
2022-09-21 21:25:24 -07:00
|
|
|
state.settings.loading = false
|
2022-09-20 18:03:59 -07:00
|
|
|
})
|
|
|
|
} catch (e) {
|
|
|
|
notify({ type: 'error', title: 'Failed to load profile details' })
|
2022-09-25 19:00:19 -07:00
|
|
|
console.error(e)
|
2022-09-20 18:03:59 -07:00
|
|
|
set((state) => {
|
2022-09-21 21:25:24 -07:00
|
|
|
state.settings.loading = false
|
2022-09-20 18:03:59 -07:00
|
|
|
})
|
|
|
|
}
|
|
|
|
},
|
2022-11-20 20:16:11 -08:00
|
|
|
async loadMarketFills() {
|
|
|
|
const set = get().set
|
|
|
|
const selectedMarket = get().selectedMarket.current
|
|
|
|
const group = get().group
|
|
|
|
const client = get().client
|
|
|
|
const connection = get().connection
|
|
|
|
try {
|
|
|
|
let serumMarket
|
|
|
|
let perpMarket
|
|
|
|
if (!group || !selectedMarket) return
|
|
|
|
|
|
|
|
if (selectedMarket instanceof Serum3Market) {
|
|
|
|
serumMarket = group.getSerum3ExternalMarket(
|
|
|
|
selectedMarket.serumMarketExternal
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
perpMarket = selectedMarket
|
|
|
|
}
|
|
|
|
|
|
|
|
let loadedFills: any[] = []
|
|
|
|
if (serumMarket) {
|
|
|
|
loadedFills = await serumMarket.loadFills(connection, 10000)
|
|
|
|
loadedFills = loadedFills.filter((f) => !f?.eventFlags?.maker)
|
|
|
|
} else if (perpMarket) {
|
|
|
|
loadedFills = await perpMarket.loadFills(client)
|
2023-01-18 21:18:06 -08:00
|
|
|
loadedFills = loadedFills.reverse()
|
2022-11-20 20:16:11 -08:00
|
|
|
}
|
|
|
|
set((state) => {
|
|
|
|
state.selectedMarket.fills = loadedFills
|
|
|
|
})
|
|
|
|
} catch (err) {
|
2023-01-20 05:45:43 -08:00
|
|
|
console.error('Error fetching fills:', err)
|
2022-11-20 20:16:11 -08:00
|
|
|
}
|
|
|
|
},
|
2023-01-12 16:16:10 -08:00
|
|
|
async fetchTradeHistory(offset = 0) {
|
2023-01-06 16:26:06 -08:00
|
|
|
const set = get().set
|
2023-01-12 16:16:10 -08:00
|
|
|
const mangoAccountPk =
|
|
|
|
get().mangoAccount?.current?.publicKey.toString()
|
|
|
|
const loadedHistory =
|
|
|
|
mangoStore.getState().mangoAccount.tradeHistory.data
|
2023-01-06 16:26:06 -08:00
|
|
|
try {
|
2023-01-12 16:16:10 -08:00
|
|
|
const response = await fetch(
|
2023-01-18 16:11:02 -08:00
|
|
|
`${MANGO_DATA_API_URL}/stats/trade-history?mango-account=${mangoAccountPk}&limit=${PAGINATION_PAGE_LENGTH}&offset=${offset}`
|
2023-01-12 16:16:10 -08:00
|
|
|
)
|
2023-01-19 19:44:45 -08:00
|
|
|
const jsonResponse = await response.json()
|
|
|
|
if (jsonResponse?.length) {
|
|
|
|
const newHistory = jsonResponse.map(
|
|
|
|
(h: any) => h.activity_details
|
2023-01-10 09:36:23 -08:00
|
|
|
)
|
2023-01-19 19:44:45 -08:00
|
|
|
const history =
|
|
|
|
offset !== 0 ? loadedHistory.concat(newHistory) : newHistory
|
|
|
|
set((s) => {
|
|
|
|
s.mangoAccount.tradeHistory.data = history?.sort(
|
|
|
|
(x: any) => x.block_datetime
|
|
|
|
)
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
set((s) => {
|
|
|
|
s.mangoAccount.tradeHistory.data = []
|
|
|
|
})
|
|
|
|
}
|
2023-01-06 16:26:06 -08:00
|
|
|
} catch (e) {
|
|
|
|
console.error('Unable to fetch trade history', e)
|
2023-01-12 16:16:10 -08:00
|
|
|
} finally {
|
|
|
|
set((s) => {
|
|
|
|
s.mangoAccount.tradeHistory.loading = false
|
|
|
|
})
|
2023-01-06 16:26:06 -08:00
|
|
|
}
|
|
|
|
},
|
2022-12-15 18:19:11 -08:00
|
|
|
updateConnection(endpointUrl) {
|
|
|
|
const set = get().set
|
2022-12-27 13:13:15 -08:00
|
|
|
const client = mangoStore.getState().client
|
2023-01-02 14:21:41 -08:00
|
|
|
const newConnection = new web3.Connection(
|
|
|
|
endpointUrl,
|
|
|
|
CONNECTION_COMMITMENT
|
|
|
|
)
|
2022-12-27 13:13:15 -08:00
|
|
|
const oldProvider = client.program.provider as AnchorProvider
|
|
|
|
const newProvider = new AnchorProvider(
|
|
|
|
newConnection,
|
|
|
|
oldProvider.wallet,
|
|
|
|
options
|
|
|
|
)
|
2022-12-15 18:19:11 -08:00
|
|
|
newProvider.opts.skipPreflight = true
|
|
|
|
const newClient = initMangoClient(newProvider)
|
|
|
|
set((state) => {
|
|
|
|
state.connection = newConnection
|
|
|
|
state.client = newClient
|
|
|
|
})
|
|
|
|
},
|
2022-05-03 21:20:14 -07:00
|
|
|
},
|
|
|
|
}
|
|
|
|
})
|
|
|
|
)
|
|
|
|
|
2022-09-25 19:00:19 -07:00
|
|
|
mangoStore.subscribe((state) => state.mangoAccount.current, spotBalancesUpdater)
|
2022-12-14 10:46:01 -08:00
|
|
|
mangoStore.subscribe(
|
|
|
|
(state) => state.mangoAccount.openOrderAccounts,
|
|
|
|
spotBalancesUpdater
|
|
|
|
)
|
2022-11-01 06:10:08 -07:00
|
|
|
mangoStore.subscribe(
|
|
|
|
(state) => state.mangoAccount.current,
|
|
|
|
perpPositionsUpdater
|
|
|
|
)
|
2022-09-25 19:00:19 -07:00
|
|
|
|
2022-05-03 21:20:14 -07:00
|
|
|
export default mangoStore
|