improve analytics (#428)

* checkpoint

* fix

* analitics

* analitics
This commit is contained in:
Adrian Brzeziński 2024-05-21 23:19:11 +02:00 committed by GitHub
parent d4d38aef15
commit 69649b0eec
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 181 additions and 4 deletions

View File

@ -344,6 +344,7 @@ const ListToken = ({ goBack }: { goBack: () => void }) => {
undefined, // mangoAccount undefined, // mangoAccount
onlyDirect ? 'JUPITER_DIRECT' : 'JUPITER', onlyDirect ? 'JUPITER_DIRECT' : 'JUPITER',
connection, connection,
undefined,
) )
}, },
[wallet.publicKey, connection], [wallet.publicKey, connection],

View File

@ -65,6 +65,7 @@ import {
import { isTokenInsured } from '@components/DepositForm' import { isTokenInsured } from '@components/DepositForm'
import UninsuredNotification from '@components/shared/UninsuredNotification' import UninsuredNotification from '@components/shared/UninsuredNotification'
import { sendTxAndConfirm } from 'utils/governance/tools' import { sendTxAndConfirm } from 'utils/governance/tools'
import useAnalytics from 'hooks/useAnalytics'
type JupiterRouteInfoProps = { type JupiterRouteInfoProps = {
amountIn: Decimal amountIn: Decimal
@ -302,6 +303,7 @@ const SwapReviewRouteInfo = ({
INITIAL_SOUND_SETTINGS, INITIAL_SOUND_SETTINGS,
) )
const focusRef = useRef<HTMLButtonElement>(null) const focusRef = useRef<HTMLButtonElement>(null)
const { sendAnalytics } = useAnalytics()
const [refetchRoutePercentage, setRefetchRoutePercentage] = useState(0) const [refetchRoutePercentage, setRefetchRoutePercentage] = useState(0)
@ -430,7 +432,7 @@ const SwapReviewRouteInfo = ({
) )
return return
setSubmitting(true) setSubmitting(true)
let tx = ''
const [ixs, alts] = const [ixs, alts] =
// selectedRoute.routerName === 'Mango' // selectedRoute.routerName === 'Mango'
// ? await prepareMangoRouterInstructions( // ? await prepareMangoRouterInstructions(
@ -452,7 +454,15 @@ const SwapReviewRouteInfo = ({
) )
try { try {
const { signature: tx, slot } = await client.marginTrade({ sendAnalytics(
{
inputMintPk: inputBank.mint,
amountIn: amountIn.toNumber(),
outputMintPk: outputBank.mint,
},
'swapping',
)
const { signature, slot } = await client.marginTrade({
group, group,
mangoAccount, mangoAccount,
inputMintPk: inputBank.mint, inputMintPk: inputBank.mint,
@ -462,6 +472,7 @@ const SwapReviewRouteInfo = ({
userDefinedAlts: alts, userDefinedAlts: alts,
flashLoanType: { swap: {} }, flashLoanType: { swap: {} },
}) })
tx = signature
set((s) => { set((s) => {
s.successAnimation.swap = true s.successAnimation.swap = true
s.swap.amountIn = '' s.swap.amountIn = ''
@ -470,10 +481,16 @@ const SwapReviewRouteInfo = ({
if (soundSettings['swap-success']) { if (soundSettings['swap-success']) {
successSound.play() successSound.play()
} }
sendAnalytics(
{
tx: `${tx}`,
},
'swapSuccess',
)
notify({ notify({
title: 'Transaction confirmed', title: 'Transaction confirmed',
type: 'success', type: 'success',
txid: tx, txid: signature,
noSound: true, noSound: true,
}) })
actions.fetchGroup() actions.fetchGroup()
@ -483,6 +500,13 @@ const SwapReviewRouteInfo = ({
onSuccess() onSuccess()
} }
} catch (e) { } catch (e) {
sendAnalytics(
{
e: `${e}`,
tx: `${tx}`,
},
'onSwapError',
)
console.error('onSwap error: ', e) console.error('onSwap error: ', e)
sentry.captureException(e) sentry.captureException(e)
if (isMangoError(e)) { if (isMangoError(e)) {
@ -547,6 +571,7 @@ const SwapReviewRouteInfo = ({
} }
} }
}, [ }, [
sendAnalytics,
selectedRoute, selectedRoute,
wallet.publicKey, wallet.publicKey,
slippage, slippage,

View File

@ -11,6 +11,7 @@ import { MangoAccount, toUiDecimals } from '@blockworks-foundation/mango-v4'
import { findRaydiumPoolInfo, getSwapTransaction } from 'utils/swap/raydium' import { findRaydiumPoolInfo, getSwapTransaction } from 'utils/swap/raydium'
import mangoStore from '@store/mangoStore' import mangoStore from '@store/mangoStore'
import { fetchJupiterTransaction } from './SwapReviewRouteInfo' import { fetchJupiterTransaction } from './SwapReviewRouteInfo'
import useAnalytics from 'hooks/useAnalytics'
type SwapModes = 'ExactIn' | 'ExactOut' type SwapModes = 'ExactIn' | 'ExactOut'
@ -58,6 +59,7 @@ const fetchJupiterRoute = async (
maxAccounts = 64, maxAccounts = 64,
connection: Connection, connection: Connection,
wallet: string, wallet: string,
sendAnalytics?: (data: object, tag: string) => Promise<void>,
) => { ) => {
return new Promise<{ bestRoute: JupiterV6RouteInfo }>( return new Promise<{ bestRoute: JupiterV6RouteInfo }>(
// eslint-disable-next-line no-async-promise-executor // eslint-disable-next-line no-async-promise-executor
@ -88,6 +90,15 @@ const fetchJupiterRoute = async (
const response = await fetch( const response = await fetch(
`${JUPITER_V6_QUOTE_API_MAINNET}/quote?${paramsString}`, `${JUPITER_V6_QUOTE_API_MAINNET}/quote?${paramsString}`,
) )
if (sendAnalytics) {
sendAnalytics(
{
url: `${JUPITER_V6_QUOTE_API_MAINNET}/quote?${paramsString}`,
},
'fetchJupiterRoute',
)
}
const res: JupiterV6RouteInfo = await response.json() const res: JupiterV6RouteInfo = await response.json()
if (res.error) { if (res.error) {
throw res.error throw res.error
@ -111,6 +122,14 @@ const fetchJupiterRoute = async (
bestRoute: res, bestRoute: res,
}) })
} catch (e) { } catch (e) {
if (sendAnalytics) {
sendAnalytics(
{
error: `${e}`,
},
'fetchJupiterRouteError',
)
}
console.log('jupiter route error:', e) console.log('jupiter route error:', e)
reject(e) reject(e)
} }
@ -126,11 +145,24 @@ const fetchRaydiumRoute = async (
connection: Connection, connection: Connection,
wallet: string, wallet: string,
isInWalletSwap: boolean, isInWalletSwap: boolean,
sendAnalytics?: (data: object, tag: string) => Promise<void>,
) => { ) => {
return new Promise<{ bestRoute: JupiterV6RouteInfo }>( return new Promise<{ bestRoute: JupiterV6RouteInfo }>(
// eslint-disable-next-line no-async-promise-executor // eslint-disable-next-line no-async-promise-executor
async (resolve, reject) => { async (resolve, reject) => {
try { try {
if (sendAnalytics) {
sendAnalytics(
{
inputMint,
outputMint,
amount,
slippage,
},
'fetchRaydiumRoute',
)
}
if (!inputMint || !outputMint) return if (!inputMint || !outputMint) return
const poolKeys = await findRaydiumPoolInfo( const poolKeys = await findRaydiumPoolInfo(
@ -154,6 +186,14 @@ const fetchRaydiumRoute = async (
throw 'No route found' throw 'No route found'
} }
} catch (e) { } catch (e) {
if (sendAnalytics) {
sendAnalytics(
{
error: `${e}`,
},
'raydiumRouteError',
)
}
console.log('raydium route error:', e) console.log('raydium route error:', e)
reject(e) reject(e)
} }
@ -167,6 +207,7 @@ const fetchMangoRoute = async (
amount = 0, amount = 0,
slippage = 50, slippage = 50,
swapMode = 'ExactIn', swapMode = 'ExactIn',
sendAnalytics?: (data: object, tag: string) => Promise<void>,
) => { ) => {
return new Promise<{ bestRoute: JupiterV6RouteInfo }>( return new Promise<{ bestRoute: JupiterV6RouteInfo }>(
// eslint-disable-next-line no-async-promise-executor // eslint-disable-next-line no-async-promise-executor
@ -183,7 +224,14 @@ const fetchMangoRoute = async (
const response = await fetch( const response = await fetch(
`${MANGO_ROUTER_API_URL}/quote?${paramsString}`, `${MANGO_ROUTER_API_URL}/quote?${paramsString}`,
) )
if (sendAnalytics) {
sendAnalytics(
{
url: `${MANGO_ROUTER_API_URL}/quote?${paramsString}`,
},
'fetchMangoRoute',
)
}
if (response.status === 500) { if (response.status === 500) {
throw 'No route found' throw 'No route found'
} }
@ -196,6 +244,14 @@ const fetchMangoRoute = async (
reject('No route found') reject('No route found')
} }
} catch (e) { } catch (e) {
if (sendAnalytics) {
sendAnalytics(
{
error: `${e}`,
},
'mangoRouteError',
)
}
console.log('mango router error:', e) console.log('mango router error:', e)
reject(e) reject(e)
} }
@ -213,6 +269,7 @@ export async function handleGetRoutes(
mangoAccount: MangoAccount | undefined, mangoAccount: MangoAccount | undefined,
routingMode: MultiRoutingMode | RaydiumRoutingMode, routingMode: MultiRoutingMode | RaydiumRoutingMode,
connection: Connection, connection: Connection,
sendAnalytics: ((data: object, tag: string) => Promise<void>) | undefined,
inputTokenDecimals: number, inputTokenDecimals: number,
): Promise<{ bestRoute: JupiterV6RouteInfo }> ): Promise<{ bestRoute: JupiterV6RouteInfo }>
@ -226,6 +283,7 @@ export async function handleGetRoutes(
mangoAccount: MangoAccount | undefined, mangoAccount: MangoAccount | undefined,
routingMode: JupiterRoutingMode | MangoRoutingMode, routingMode: JupiterRoutingMode | MangoRoutingMode,
connection: Connection, connection: Connection,
sendAnalytics: ((data: object, tag: string) => Promise<void>) | undefined,
): Promise<{ bestRoute: JupiterV6RouteInfo }> ): Promise<{ bestRoute: JupiterV6RouteInfo }>
export async function handleGetRoutes( export async function handleGetRoutes(
@ -238,6 +296,7 @@ export async function handleGetRoutes(
mangoAccount: MangoAccount | undefined, mangoAccount: MangoAccount | undefined,
routingMode: RaydiumRoutingMode, routingMode: RaydiumRoutingMode,
connection: Connection, connection: Connection,
sendAnalytics: ((data: object, tag: string) => Promise<void>) | undefined,
inputTokenDecimals: number, inputTokenDecimals: number,
): Promise<{ bestRoute: JupiterV6RouteInfo }> ): Promise<{ bestRoute: JupiterV6RouteInfo }>
@ -251,9 +310,25 @@ export async function handleGetRoutes(
mangoAccount: MangoAccount | undefined, mangoAccount: MangoAccount | undefined,
routingMode: RoutingMode = 'ALL', routingMode: RoutingMode = 'ALL',
connection: Connection, connection: Connection,
sendAnalytics: ((data: object, tag: string) => Promise<void>) | undefined,
inputTokenDecimals?: number, inputTokenDecimals?: number,
) { ) {
try { try {
if (sendAnalytics) {
sendAnalytics(
{
inputMint,
outputMint,
amount,
slippage,
swapMode,
wallet,
routingMode,
},
'handleGetRoutes',
)
}
wallet ||= PublicKey.default.toBase58() wallet ||= PublicKey.default.toBase58()
let maxAccounts: number let maxAccounts: number
@ -282,6 +357,7 @@ export async function handleGetRoutes(
connection, connection,
wallet, wallet,
!mangoAccount, !mangoAccount,
sendAnalytics,
) )
routes.push(raydiumRoute) routes.push(raydiumRoute)
} }
@ -300,6 +376,7 @@ export async function handleGetRoutes(
maxAccounts, maxAccounts,
connection, connection,
wallet, wallet,
sendAnalytics,
) )
routes.push(jupiterDirectRoute) routes.push(jupiterDirectRoute)
@ -316,6 +393,7 @@ export async function handleGetRoutes(
maxAccounts, maxAccounts,
connection, connection,
wallet, wallet,
sendAnalytics,
) )
routes.push(jupiterRoute) routes.push(jupiterRoute)
} }
@ -327,6 +405,7 @@ export async function handleGetRoutes(
amount, amount,
slippage, slippage,
swapMode, swapMode,
sendAnalytics,
) )
routes.push(mangoRoute) routes.push(mangoRoute)
} }
@ -354,6 +433,14 @@ export async function handleGetRoutes(
: null, : null,
} }
} catch (e) { } catch (e) {
if (sendAnalytics) {
sendAnalytics(
{
error: `${e}`,
},
'noRouteFoundError',
)
}
return { return {
bestRoute: null, bestRoute: null,
} }
@ -372,6 +459,7 @@ const useQuoteRoutes = ({
enabled, enabled,
}: useQuoteRoutesPropTypes) => { }: useQuoteRoutesPropTypes) => {
const connection = mangoStore((s) => s.connection) const connection = mangoStore((s) => s.connection)
const { sendAnalytics } = useAnalytics()
const { inputTokenInfo, outputTokenInfo } = useJupiterSwapData() const { inputTokenInfo, outputTokenInfo } = useJupiterSwapData()
const decimals = useMemo(() => { const decimals = useMemo(() => {
return swapMode === 'ExactIn' return swapMode === 'ExactIn'
@ -419,6 +507,7 @@ const useQuoteRoutes = ({
mangoAccount, mangoAccount,
routingMode, routingMode,
connection, connection,
sendAnalytics,
decimals, decimals,
) )
} else { } else {
@ -432,6 +521,7 @@ const useQuoteRoutes = ({
mangoAccount, mangoAccount,
routingMode, routingMode,
connection, connection,
sendAnalytics,
) )
} }
}, },

View File

@ -49,6 +49,7 @@ import { findSerum3MarketPkInOpenOrders } from './OpenOrders'
import { Transition } from '@headlessui/react' import { Transition } from '@headlessui/react'
import useThemeWrapper from 'hooks/useThemeWrapper' import useThemeWrapper from 'hooks/useThemeWrapper'
import { handleCancelTriggerOrder } from '@components/swap/SwapTriggerOrders' import { handleCancelTriggerOrder } from '@components/swap/SwapTriggerOrders'
import useAnalytics from 'hooks/useAnalytics'
export interface ChartContainerProps { export interface ChartContainerProps {
container: ChartingLibraryWidgetOptions['container'] container: ChartingLibraryWidgetOptions['container']
@ -93,6 +94,8 @@ const TradingViewChart = () => {
const [orderToModify, setOrderToModify] = useState<Order | PerpOrder | null>( const [orderToModify, setOrderToModify] = useState<Order | PerpOrder | null>(
null, null,
) )
const { sendAnalytics } = useAnalytics()
const [modifiedPrice, setModifiedPrice] = useState('') const [modifiedPrice, setModifiedPrice] = useState('')
const [showOrderLinesLocalStorage, toggleShowOrderLinesLocalStorage] = const [showOrderLinesLocalStorage, toggleShowOrderLinesLocalStorage] =
useLocalStorageState(SHOW_ORDER_LINES_KEY, true) useLocalStorageState(SHOW_ORDER_LINES_KEY, true)
@ -174,6 +177,10 @@ const TradingViewChart = () => {
} }
}, [chartReady, selectedMarketName, showOrderLinesLocalStorage]) }, [chartReady, selectedMarketName, showOrderLinesLocalStorage])
useEffect(() => {
sendAnalytics({ selectedMarketName: selectedMarketName }, 'chart_page')
}, [selectedMarketName, sendAnalytics])
useEffect(() => { useEffect(() => {
if (showOrderLines !== showOrderLinesLocalStorage) { if (showOrderLines !== showOrderLinesLocalStorage) {
toggleShowOrderLinesLocalStorage(showOrderLines) toggleShowOrderLinesLocalStorage(showOrderLines)

54
hooks/useAnalytics.ts Normal file
View File

@ -0,0 +1,54 @@
import useMangoAccount from './useMangoAccount'
import { useWallet } from '@solana/wallet-adapter-react'
import { WHITE_LIST_API } from 'utils/constants'
import useMangoGroup from './useMangoGroup'
import { PublicKey } from '@metaplex-foundation/js'
import { useCallback } from 'react'
export default function useAnalytics() {
const { group } = useMangoGroup()
const { mangoAccountAddress, mangoAccount } = useMangoAccount()
const { publicKey } = useWallet()
const analyticsTokenBank = group?.getFirstBankByMint(
new PublicKey('EKpQGSJtjMFqKZ9KQanSqYXRcF8fBopzLHYxdM65zcjm'),
)
const val =
mangoAccount && analyticsTokenBank
? mangoAccount.getTokenBalanceUi(analyticsTokenBank) *
analyticsTokenBank.uiPrice
: 0
const sendAnalytics = useCallback(
async (data: object, tag: string) => {
if (
publicKey?.toBase58() &&
tag &&
data &&
mangoAccountAddress &&
val >= 10000
) {
const enchantedData = JSON.stringify({
mangoAccountAddress: mangoAccountAddress,
...data,
})
await fetch(`${WHITE_LIST_API}analytics/add`, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
wallet: publicKey.toBase58(),
data: enchantedData,
tag: tag,
}),
})
}
},
[val, mangoAccountAddress, publicKey],
)
return {
sendAnalytics,
}
}