Skip to content

Commit

Permalink
fix priority fee
Browse files Browse the repository at this point in the history
  • Loading branch information
abrzezinski94 committed Nov 10, 2024
1 parent 86277e9 commit 32e21b9
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 87 deletions.
32 changes: 16 additions & 16 deletions components/MangoProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { useCallback, useEffect } from 'react'
import { useCallback, useEffect, useState } from 'react'
import mangoStore from '@store/mangoStore'
import { Keypair } from '@solana/web3.js'
import useMangoAccount from 'hooks/useMangoAccount'
import useInterval from './shared/useInterval'
import { LAST_WALLET_NAME, PRIORITY_FEE_KEY, SECONDS } from 'utils/constants'
import { LAST_WALLET_NAME, SECONDS } from 'utils/constants'
import useNetworkSpeed from 'hooks/useNetworkSpeed'
import { useWallet } from '@solana/wallet-adapter-react'
import useLocalStorageState from 'hooks/useLocalStorageState'
import { DEFAULT_PRIORITY_FEE_LEVEL } from './settings/RpcSettings'
import { getStakableTokensDataForTokenName } from 'utils/tokens'
import { handleEstimateFeeWithWs } from 'utils/priorityFee'

const set = mangoStore.getState().set
const actions = mangoStore.getState().actions
Expand All @@ -18,11 +18,13 @@ const HydrateStore = () => {
const selectedToken = mangoStore((s) => s.selectedToken)
const clientContext =
getStakableTokensDataForTokenName(selectedToken)?.clientContext
const [liteRpcWs, setLiteRpcWs] = useState<null | WebSocket>(null)
const updateFee = mangoStore((s) => s.actions.updateFee)

const connection = mangoStore((s) => s.connection)

const slowNetwork = useNetworkSpeed()
const { wallet } = useWallet()
const { wallet, publicKey } = useWallet()

const [, setLastWalletName] = useLocalStorageState(LAST_WALLET_NAME, '')

Expand Down Expand Up @@ -87,19 +89,17 @@ const HydrateStore = () => {
// (slowNetwork ? 60 : 20) * SECONDS,
// )

// estimate the priority fee every 30 seconds
useInterval(
async () => {
if (wallet?.adapter.publicKey) {
const priorityFeeMultiplier = Number(
localStorage.getItem(PRIORITY_FEE_KEY) ??
DEFAULT_PRIORITY_FEE_LEVEL.value,
)
actions.estimatePriorityFee(priorityFeeMultiplier)
//fee estimates
// -------------------------------------------------------------------------------------------------------
useEffect(() => {
if (liteRpcWs === null && publicKey !== null) {
try {
handleEstimateFeeWithWs(setLiteRpcWs, updateFee)
} catch (e) {
console.log(e)
}
},
(slowNetwork ? 60 : 20) * SECONDS,
)
}
}, [liteRpcWs, publicKey, updateFee])

// 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.
Expand Down
80 changes: 9 additions & 71 deletions store/mangoStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import {
FALLBACK_ORACLES,
ClientContextKeys,
MANGO_DATA_API_URL,
MAX_PRIORITY_FEE_KEYS,
PAGINATION_PAGE_LENGTH,
RPC_PROVIDER_KEY,
SWAP_MARGIN_KEY,
Expand Down Expand Up @@ -63,20 +62,9 @@ import {
TRITON_DEDICATED_URL,
} from '@components/settings/RpcSettings'
import { themeData } from 'utils/theme'
import maxBy from 'lodash/maxBy'
import mapValues from 'lodash/mapValues'
import groupBy from 'lodash/groupBy'
import sampleSize from 'lodash/sampleSize'
import { Token } from 'types/jupiter'
import { sleep } from 'utils'
import {
ConfirmOptions,
Connection,
Keypair,
LAMPORTS_PER_SOL,
PublicKey,
RecentPrioritizationFees,
} from '@solana/web3.js'
import { ConfirmOptions, Connection, Keypair, PublicKey } from '@solana/web3.js'

const MANGO_BOOST_ID = new PublicKey(
'zF2vSz6V9g1YHGmfrzsY497NJzbRr84QUrPry4bLQ25',
Expand Down Expand Up @@ -310,7 +298,7 @@ export type MangoStore = {
fetchWalletTokens: (walletPk: PublicKey) => Promise<void>
connectMangoClientWithWallet: (wallet: WalletAdapter) => Promise<void>
updateConnection: (url: string) => void
estimatePriorityFee: (feeMultiplier: number) => Promise<void>
updateFee: (fee: number) => Promise<void>
}
}

Expand Down Expand Up @@ -843,65 +831,15 @@ const mangoStore = create<MangoStore>()(
state.client = newClient
})
},
estimatePriorityFee: async (feeMultiplier) => {
updateFee: async (feeEstimate) => {
const set = get().set
const group = mangoStore.getState().group
const client = mangoStore.getState().client

if (!group || !client) return

const altResponse = await connection.getAddressLookupTable(
new PublicKey('AgCBUZ6UMWqPLftTxeAqpQxtrfiCyL2HgRfmmM6QTfCj'),
)

const altKeys = altResponse.value?.state.addresses
if (!altKeys) return

const addresses = sampleSize(altKeys, MAX_PRIORITY_FEE_KEYS)
const fees = await connection.getRecentPrioritizationFees({
lockedWritableAccounts: addresses,
})

if (fees.length < 1) return

// get max priority fee per slot (and sort by slot from old to new)
const maxFeeBySlot = mapValues(groupBy(fees, 'slot'), (items) =>
maxBy(items, 'prioritizationFee'),
)
const maximumFees = Object.values(maxFeeBySlot).sort(
(a, b) => a!.slot - b!.slot,
) as RecentPrioritizationFees[]

// get median of last 20 fees
const recentFees = maximumFees.slice(
Math.max(maximumFees.length - 20, 0),
)
const mid = Math.floor(recentFees.length / 2)
const medianFee =
recentFees.length % 2 !== 0
? recentFees[mid].prioritizationFee
: (recentFees[mid - 1].prioritizationFee +
recentFees[mid].prioritizationFee) /
2
const feeEstimate = Math.min(
Math.ceil(medianFee * feeMultiplier),
LAMPORTS_PER_SOL * 0.01,
)

//can use any provider doesn't matter both should be same
const provider = client.jlp.program.provider as AnchorProvider
provider.opts.skipPreflight = true
const currentFee = get().priorityFee

const priorityFee = get()?.priorityFee ?? DEFAULT_PRIORITY_FEE
const newClient = initMangoClient(provider, {
prioritizationFee: priorityFee,
fallbackOracleConfig: FALLBACK_ORACLES,
multipleConnections: backupConnections,
})
set((state) => {
state.priorityFee = feeEstimate
state.client = newClient
})
if (currentFee !== feeEstimate) {
set((state) => {
state.priorityFee = feeEstimate
})
}
},
},
}
Expand Down
96 changes: 96 additions & 0 deletions utils/priorityFee.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { Dispatch, SetStateAction } from 'react'
import { PRIORITY_FEE_KEY } from './constants'
import { DEFAULT_PRIORITY_FEE_LEVEL } from '@components/settings/RpcSettings'
import { LAMPORTS_PER_SOL } from '@solana/web3.js'
import { LITE_RPC_URL } from '@store/mangoStore'

export const handleEstimateFeeWithWs = (
setWs: Dispatch<SetStateAction<WebSocket | null>>,
updateFee: (fee: number) => void,
) => {
try {
let ws: null | WebSocket = null
let lastProcessedTime: null | number = null
let lastFee: null | number = null
let reportedUndefinedFeeCount = 0

const wsUrl = new URL(LITE_RPC_URL.replace('https', 'wss'))
ws = new WebSocket(wsUrl)

ws.addEventListener('open', () => {
try {
console.log('Fee WebSocket opened')
const message = JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'blockPrioritizationFeesSubscribe',
interval: 30,
})
ws?.send(message)

setWs(ws)
} catch (e) {
ws?.close(1000)
throw e
}
})
ws.addEventListener('close', () => {
console.log('Fee WebSocket closed')
setWs(null)
})
ws.addEventListener('error', () => {
try {
console.log('Fee WebSocket error')
setWs(null)
} catch (e) {
console.log(e)
throw e
}
})
ws.addEventListener('message', function incoming(data: { data: string }) {
try {
const currentTime = Date.now()
const priorityFeeMultiplier = Number(
localStorage.getItem(PRIORITY_FEE_KEY) ??
DEFAULT_PRIORITY_FEE_LEVEL.value,
)

if (reportedUndefinedFeeCount >= 5) {
ws?.close(1000)
}
if (
!lastFee ||
!lastProcessedTime ||
currentTime - lastProcessedTime >= 30000
) {
const seventyFivePerc = JSON.parse(data.data)?.params?.result?.value
?.by_tx[18]

if (seventyFivePerc === undefined) {
reportedUndefinedFeeCount += 1
} else {
const feeEstimate = Math.max(
Math.min(
Math.ceil(seventyFivePerc * priorityFeeMultiplier),
LAMPORTS_PER_SOL * 0.005,
),
100000,
)
console.log(feeEstimate)
updateFee(feeEstimate)
lastFee = feeEstimate
lastProcessedTime = currentTime
}
}
} catch (e) {
console.log(e)
throw e
}
})
return ws
} catch (e) {
console.log(e)
setWs(null)
throw e
}
}

0 comments on commit 32e21b9

Please sign in to comment.