From e73e07a3a415645ce04fb2f13fa37bd382f745eb Mon Sep 17 00:00:00 2001 From: Chewing Glass Date: Thu, 3 Aug 2023 11:17:19 -0500 Subject: [PATCH] Fix activity list --- src/features/account/AccountTokenScreen.tsx | 12 +- src/features/account/TransactionDetail.tsx | 164 +----------- src/features/account/TxnListItem.tsx | 8 +- .../account/useSolanaActivityList.tsx | 21 +- src/features/account/useTxn.tsx | 240 ++++++++---------- src/hooks/useMetaplexMetadata.ts | 46 ++-- src/locales/en.ts | 3 +- src/types/activity.ts | 32 +-- src/utils/solanaUtils.ts | 30 +-- 9 files changed, 183 insertions(+), 373 deletions(-) diff --git a/src/features/account/AccountTokenScreen.tsx b/src/features/account/AccountTokenScreen.tsx index d3fd7c4f5..3d7bd8dca 100644 --- a/src/features/account/AccountTokenScreen.tsx +++ b/src/features/account/AccountTokenScreen.tsx @@ -177,9 +177,10 @@ const AccountTokenScreen = () => { showTxnDetail({ item, accountAddress: currentAccount?.address || '', + mint, }) }, - [currentAccount, showTxnDetail], + [currentAccount, showTxnDetail, mint], ) const hasAirdrop = useMemo(() => { @@ -250,6 +251,7 @@ const AccountTokenScreen = () => { }} > { ) }, - [activityData, bottomScreenHeaderHeight, now, showTransactionDetail], + [ + activityData?.length, + bottomScreenHeaderHeight, + mint, + now, + showTransactionDetail, + ], ) const renderFooter = useCallback(() => { diff --git a/src/features/account/TransactionDetail.tsx b/src/features/account/TransactionDetail.tsx index 8253005a8..5e8d7c046 100644 --- a/src/features/account/TransactionDetail.tsx +++ b/src/features/account/TransactionDetail.tsx @@ -9,12 +9,11 @@ import { BottomSheetScrollView, } from '@gorhom/bottom-sheet' import useBackHandler from '@hooks/useBackHandler' -import animalName from 'angry-purple-tiger' -import { groupBy } from 'lodash' +import { PublicKey } from '@solana/web3.js' import React, { - createContext, FC, ReactNode, + createContext, useCallback, useContext, useMemo, @@ -26,7 +25,6 @@ import { LayoutChangeEvent } from 'react-native' import { Edge } from 'react-native-safe-area-context' import { useCreateExplorerUrl } from '../../constants/urls' import { Activity } from '../../types/activity' -import { ellipsizeAddress } from '../../utils/accountUtils' import TransactionLineItem from './TransactionLineItem' import { useTxnDetails } from './useTxn' @@ -34,7 +32,7 @@ const initialState = { show: () => undefined, } -type DetailData = { item: Activity; accountAddress: string } +type DetailData = { item: Activity; accountAddress: string; mint: PublicKey } type TransactionDetailSelectorActions = { show: (data: DetailData) => void } @@ -49,7 +47,7 @@ const TransactionDetailSelector = ({ children }: { children: ReactNode }) => { const [contentHeight, setContentHeight] = useState(0) const { handleDismiss, setIsShowing } = useBackHandler(bottomSheetModalRef) - const { item: txn } = detailData || {} + const { item: txn, mint } = detailData || {} const { amount, @@ -57,14 +55,12 @@ const TransactionDetailSelector = ({ children }: { children: ReactNode }) => { color, fee, feePayer, - hotspotName, icon, paymentsReceived, paymentsSent, time, title, - validatorName, - } = useTxnDetails(txn) + } = useTxnDetails(mint, txn) const createExplorerUrl = useCreateExplorerUrl() const snapPoints = useMemo(() => { @@ -115,35 +111,6 @@ const TransactionDetailSelector = ({ children }: { children: ReactNode }) => { const handleComponent = useCallback(() => , []) - const rewards = useMemo(() => { - if (!txn?.rewards?.length || txn.type === 'subnetwork_rewards_v1') { - return null - } - - const grouped = groupBy(txn.rewards, (reward) => { - if (reward.type === 'securities') return reward.type - - return `${reward.gateway}.${reward.type}` - }) - - return Object.keys(grouped).map((key) => { - const group = grouped[key] - const totalAmount = group.reduce((sum, { amount: amt }) => sum + amt, 0) - const typeName = t(`transactions.rewardTypes.${group[0].type}`) - let name = '' - if (group[0].gateway) { - name = animalName(group[0].gateway) - } else { - name = typeName - } - return { - name, - amount: totalAmount, - type: typeName, - } - }) - }, [t, txn]) - const handleContentLayout = useCallback((e: LayoutChangeEvent) => { setContentHeight(e.nativeEvent.layout.height) }, []) @@ -172,62 +139,14 @@ const TransactionDetailSelector = ({ children }: { children: ReactNode }) => { icon={icon} /> - {!!hotspotName && ( - - )} - {!!validatorName && ( - - )} - - {!!txn?.buyer && ( - - )} - - {!!txn?.seller && ( - - )} - - {!!txn?.payee && ( - - )} - - {paymentsSent.map(({ amount: amt, payee }, index) => ( + {paymentsSent.map(({ amount: amt }, index) => ( - ))} @@ -237,33 +156,11 @@ const TransactionDetailSelector = ({ children }: { children: ReactNode }) => { - ))} - {rewards?.map((reward, index) => { - return ( - - ) - })} - {!!amountTitle && ( { /> )} - {!!txn?.owner && ( - - )} - - {!!txn?.oldOwner && ( - - )} - - {!!txn?.oldAddress && ( - - )} - - {!!txn?.newOwner && ( - - )} - - {!!txn?.newAddress && ( - - )} - { export const useTransactionDetail = () => useContext(TransactionDetailSelectorContext) -export const withTransactionDetail = (Component: FC) => () => - ( +export const withTransactionDetail = (Component: FC) => () => { + return ( ) +} diff --git a/src/features/account/TxnListItem.tsx b/src/features/account/TxnListItem.tsx index 6cf199dee..fab5acc52 100644 --- a/src/features/account/TxnListItem.tsx +++ b/src/features/account/TxnListItem.tsx @@ -2,18 +2,22 @@ import Pending from '@assets/images/pending.svg' import Box from '@components/Box' import Text from '@components/Text' import TouchableOpacityBox from '@components/TouchableOpacityBox' +import { PublicKey } from '@solana/web3.js' import React, { memo, useCallback, useMemo } from 'react' import { Activity } from '../../types/activity' import useTxn from './useTxn' type Props = { + mint: PublicKey item: Activity now: Date isLast: boolean onPress: (item: Activity) => void } -const TxnListItem = ({ item, now, isLast, onPress }: Props) => { - const { listIcon, title, color, time, getAmount } = useTxn(item, { now }) +const TxnListItem = ({ mint, item, now, isLast, onPress }: Props) => { + const { listIcon, title, color, time, getAmount } = useTxn(mint, item, { + now, + }) const amt = useMemo(() => getAmount(), [getAmount]) const handlePress = useCallback(() => { diff --git a/src/features/account/useSolanaActivityList.tsx b/src/features/account/useSolanaActivityList.tsx index 87d17fcb4..5c74b53ba 100644 --- a/src/features/account/useSolanaActivityList.tsx +++ b/src/features/account/useSolanaActivityList.tsx @@ -94,20 +94,21 @@ export default ({ if (filter !== 'in' && filter !== 'out' && filter !== 'all') return [] if (filter === 'in' || filter === 'out') { - const payments = solanaActivity.data[account.solanaAddress]?.payment[ - mintStr - ]?.filter((txn) => txn.mint === mintStr) + const payments = + solanaActivity.data[account.solanaAddress]?.payment[mintStr] return payments?.filter((txn) => - filter === 'out' - ? txn.payee === account.solanaAddress - : txn.payee !== account.solanaAddress, + txn.payments?.some((payment) => + payment.mint === mintStr && + payment.owner === account?.solanaAddress && + filter === 'out' + ? payment.amount < 0 + : payment.amount > 0, + ), ) } - return solanaActivity.data[account.solanaAddress][filter][mintStr]?.filter( - (txn) => txn.mint === mintStr, - ) - }, [account, filter, solanaActivity.data, mintStr]) + return solanaActivity.data[account.solanaAddress][filter][mintStr] + }, [account?.solanaAddress, solanaActivity.data, mintStr, filter]) const loading = useMemo(() => { return solanaActivity.loading diff --git a/src/features/account/useTxn.tsx b/src/features/account/useTxn.tsx index aa93e8577..46684810d 100644 --- a/src/features/account/useTxn.tsx +++ b/src/features/account/useTxn.tsx @@ -1,11 +1,19 @@ import TxnReceive from '@assets/images/txnReceive.svg' import TxnSend from '@assets/images/txnSend.svg' -import { useMetaplexMetadata } from '@hooks/useMetaplexMetadata' +import { useAccounts } from '@helium/account-fetch-cache-hooks' +import { MintParser } from '@helium/helium-react-hooks' +import { truthy } from '@helium/spl-utils' +import { useCurrentWallet } from '@hooks/useCurrentWallet' +import { + METADATA_PARSER, + getMetadataId, + useMetaplexMetadata, +} from '@hooks/useMetaplexMetadata' import { usePublicKey } from '@hooks/usePublicKey' -import { LAMPORTS_PER_SOL } from '@solana/web3.js' +import { LAMPORTS_PER_SOL, PublicKey } from '@solana/web3.js' import { Color } from '@theme/theme' import { useColors } from '@theme/themeHooks' -import animalName from 'angry-purple-tiger' +import BN from 'bn.js' import { addMinutes, format, @@ -17,68 +25,68 @@ import { startCase } from 'lodash' import React, { useCallback, useMemo, useState } from 'react' import { useAsync } from 'react-async-hook' import { useTranslation } from 'react-i18next' -import { useAccountStorage } from '../../storage/AccountStorageProvider' import { Activity } from '../../types/activity' -import { ellipsizeAddress } from '../../utils/accountUtils' import shortLocale from '../../utils/formatDistance' -import { TXN_FEE_IN_LAMPORTS } from '../../utils/solanaUtils' -import { useOnboarding } from '../onboarding/OnboardingProvider' +import { TXN_FEE_IN_LAMPORTS, humanReadable } from '../../utils/solanaUtils' -export const TxnTypeKeys = ['payment_v2', 'dc_delegate', 'dc_mint'] as const +export const TxnTypeKeys = ['payment_v2'] as const type TxnType = typeof TxnTypeKeys[number] const useTxn = ( + mint?: PublicKey, item?: Activity, dateOpts?: { dateFormat?: string; now?: Date }, ) => { - const { currentNetworkAddress: address } = useAccountStorage() const colors = useColors() const { t } = useTranslation() - const { makers } = useOnboarding() const { symbol: ticker } = useMetaplexMetadata( usePublicKey(item?.payments?.[0]?.mint || undefined), ) - - const isSending = useMemo(() => { - return item?.payer === address - }, [address, item]) - - const isHotspotTxn = useMemo( + const wallet = useCurrentWallet() + const mintKeys = useMemo( () => - item?.type === 'assert_location_v1' || - item?.type === 'assert_location_v2' || - item?.type === 'add_gateway_v1' || - item?.type === 'transfer_hotspot_v1' || - item?.type === 'transfer_hotspot_v2', - [item], + [...new Set(item?.payments?.map((p) => p.mint))] + .filter(truthy) + .map((k) => new PublicKey(k)), + [item?.payments], ) - - const isValidatorTxn = useMemo( - () => - item?.type === 'stake_validator_v1' || - item?.type === 'transfer_validator_stake_v1' || - item?.type === 'unstake_validator_v1', - [item], + const metadataKeys = useMemo( + () => mintKeys.map((m) => getMetadataId(m)), + [mintKeys], ) + const { accounts: mintAccs } = useAccounts(mintKeys, MintParser) + const { accounts: metadataAccs } = useAccounts(metadataKeys, METADATA_PARSER) + const decimalsByMint = useMemo(() => { + return mintAccs?.reduce((acc, curr) => { + if (curr.info) { + acc[curr.publicKey.toBase58()] = curr.info.decimals + } + return acc + }, {} as { [key: string]: number }) + }, [mintAccs]) + + const symbolsByMint = useMemo(() => { + return metadataAccs?.reduce((acc, curr, index) => { + if (curr.info) { + acc[mintKeys[index].toBase58()] = curr.info.symbol + } + return acc + }, {} as { [key: string]: string }) + }, [metadataAccs, mintKeys]) - const getHotspotName = useCallback(() => { - if (!isHotspotTxn || !item?.gateway) return '' - return animalName(item.gateway) - }, [isHotspotTxn, item]) - - const getValidatorName = useCallback(() => { - if (!isValidatorTxn || !item?.address) return '' - return animalName(item.address) - }, [isValidatorTxn, item]) + const isSending = useMemo(() => { + return item?.payments?.some( + (p) => + p.owner === wallet?.toBase58() && + p.amount < 0 && + p.mint === mint?.toBase58(), + ) + }, [item?.payments, mint, wallet]) const color = useMemo((): Color => { switch (item?.type as TxnType) { case 'payment_v2': return isSending ? 'blueBright500' : 'greenBright500' - case 'dc_mint': - return 'greenBright500' - case 'dc_delegate': - return 'orange500' default: return 'primaryText' } @@ -113,10 +121,6 @@ const useTxn = ( ? t('transactions.sent', { ticker }) : t('transactions.received', { ticker }) } - case 'dc_delegate': - return t('transactions.delegated') - case 'dc_mint': - return t('transactions.received', { ticker: '' }) } }, [item, t, isSending, ticker]) @@ -129,8 +133,6 @@ const useTxn = ( ) : ( ) - case 'dc_delegate': - case 'dc_mint': default: return } @@ -147,34 +149,30 @@ const useTxn = ( }, [isSending, item]) const formatAmount = useCallback( - (prefix: '-' | '+' | '', amount?: number) => { - if (!amount) return '' - - return `${prefix}${amount.toFixed(4)}` + ( + prefix: '-' | '+' | '', + amount: number | undefined, + m: string | undefined | null, + ) => { + const decimals = m ? decimalsByMint?.[m] : undefined + if (!amount || typeof decimals === 'undefined') return '' + const symbolPart = m ? symbolsByMint?.[m] || '' : '' + + return `${prefix}${humanReadable( + new BN( + Math.abs(amount) + .toFixed(decimals || 0) + .replace('.', ''), + ), + decimals, + )} ${symbolPart}` }, - [], + [decimalsByMint, symbolsByMint], ) const getFee = useCallback(async () => { - return formatAmount('-', TXN_FEE_IN_LAMPORTS / LAMPORTS_PER_SOL) - }, [formatAmount]) - - const getFeePayer = useCallback(() => { - const type = item?.type - if ( - !item?.type || - !item.payer || - (type !== 'add_gateway_v1' && - type !== 'assert_location_v1' && - type !== 'assert_location_v2') - ) { - return '' - } - return ( - makers.find(({ address: makerAddress }) => makerAddress === item.payer) - ?.name || ellipsizeAddress(item.payer) - ) - }, [item, makers]) + return `-${TXN_FEE_IN_LAMPORTS / LAMPORTS_PER_SOL}` + }, []) const getAmountTitle = useCallback(async () => { if (!item) return '' @@ -188,39 +186,22 @@ const useTxn = ( if (!item) return '' switch (item.type as TxnType) { - case 'dc_delegate': - return formatAmount('-', Number(item.amount)) - case 'dc_mint': - return formatAmount('+', Number(item.amount)) case 'payment_v2': { - const paymentTotals = item.payments?.reduce((sums, current) => { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const mint = (current.mint || item.payments?.[0].mint)! - return { - ...sums, - [mint]: (sums[mint] || 0) + current.amount, - } - }, {} as Record) - if (!paymentTotals) return '' - return Object.keys(paymentTotals) - .flatMap((m) => { - const total = paymentTotals[m] - if (total === 0) return [] - const amt = formatAmount('', paymentTotals[m]) - return [amt] - }) - .join(', ') + const payment = item.payments?.find( + (p) => p.mint === mint?.toBase58() && p.owner === wallet?.toBase58(), + ) + if (payment) { + return formatAmount( + payment.amount < 0 ? '-' : '+', + Math.abs(payment.amount), + payment.mint, + ) } - - return `+${item.payments - ?.filter((p) => p.payee === address) - .map((p) => formatAmount('', p.amount)) - .join(', ')}` } } return '' - }, [item, formatAmount, address]) + }, [item, formatAmount, mint, wallet]) const time = useMemo(() => { if (!item) return '' @@ -251,28 +232,30 @@ const useTxn = ( }, [dateOpts, item, t]) const getPaymentsReceived = useCallback(async () => { - const payments = item?.payments?.filter(({ payee }) => payee === address) + const payments = item?.payments?.filter( + ({ owner, amount }) => owner === wallet?.toBase58() && amount > 0, + ) if (!payments) return [] const all = payments.map(async (p) => { - const balance = await formatAmount('+', p.amount) - return { amount: balance, payee: p.payee, memo: p.memo || '' } + const balance = await formatAmount('+', p.amount, p.mint) + return { amount: balance, owner: p.owner, memo: p.memo || '' } }) return Promise.all(all) - }, [address, formatAmount, item]) + }, [formatAmount, item?.payments, wallet]) const getPaymentsSent = useCallback(async () => { - if (item?.payer !== address || !item?.payments) { + if (!item?.payments) { return [] } - const all = item.payments.map( - async ({ amount: amt, payee, memo: paymentMemo }) => { - const balance = await formatAmount('', amt) - return { amount: balance, payee, memo: paymentMemo || '' } - }, - ) + const all = item.payments + .filter((p) => p.amount < 0 && p.owner === wallet?.toBase58()) + .map(async ({ amount: amt, owner, memo: paymentMemo, mint: m }) => { + const balance = await formatAmount('', amt, m) + return { amount: balance, owner, memo: paymentMemo || '' } + }) return Promise.all(all) - }, [address, formatAmount, item]) + }, [formatAmount, item, wallet]) return { time, @@ -282,20 +265,15 @@ const useTxn = ( title, color, isFee, - getFeePayer, getPaymentsReceived, getPaymentsSent, - isHotspotTxn, - isValidatorTxn, - getHotspotName, - getValidatorName, getAmountTitle, } } type Payment = { amount: string - payee: string + owner: string memo: string } type TxnDetails = { @@ -309,28 +287,19 @@ type TxnDetails = { paymentsSent: Payment[] amount: string amountTitle: string - hotspotName: string - validatorName: string - isValidatorTxn: boolean - isHotspotTxn: boolean } -export const useTxnDetails = (item?: Activity) => { +export const useTxnDetails = (mint?: PublicKey, item?: Activity) => { const { listIcon, title, time, color, - getFeePayer, getFee, getPaymentsReceived, getPaymentsSent, getAmount, - getHotspotName, - getValidatorName, - isHotspotTxn, - isValidatorTxn, getAmountTitle, - } = useTxn(item, { + } = useTxn(mint, item, { dateFormat: 'dd MMMM yyyy HH:MM', }) @@ -344,24 +313,18 @@ export const useTxnDetails = (item?: Activity) => { paymentsSent: [], amount: '', amountTitle: '', - validatorName: '', - hotspotName: '', - isHotspotTxn: false, - isValidatorTxn: false, }) useAsync(async () => { - const feePayer = await getFeePayer() const fee = await getFee() const paymentsReceived = await getPaymentsReceived() const paymentsSent = await getPaymentsSent() const amount = await getAmount() const amountTitle = await getAmountTitle() - const validatorName = await getValidatorName() - const hotspotName = await getHotspotName() setDetails({ - feePayer, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-non-null-asserted-optional-chain + feePayer: item?.feePayer!, icon: listIcon, title, time, @@ -371,16 +334,11 @@ export const useTxnDetails = (item?: Activity) => { paymentsSent, amount, amountTitle, - validatorName, - hotspotName, - isHotspotTxn, - isValidatorTxn, }) }, [ color, getAmount, getFee, - getFeePayer, getPaymentsReceived, getPaymentsSent, listIcon, diff --git a/src/hooks/useMetaplexMetadata.ts b/src/hooks/useMetaplexMetadata.ts index 8bc04baad..53434b5a7 100644 --- a/src/hooks/useMetaplexMetadata.ts +++ b/src/hooks/useMetaplexMetadata.ts @@ -7,7 +7,7 @@ import { toMetadata, } from '@metaplex-foundation/js' import { NATIVE_MINT } from '@solana/spl-token' -import { PublicKey } from '@solana/web3.js' +import { AccountInfo, PublicKey } from '@solana/web3.js' import { useMemo } from 'react' import { useAsync } from 'react-async-hook' @@ -27,6 +27,27 @@ async function getMetadata(uri: string | undefined): Promise { } } +export const METADATA_PARSER: TypedAccountParser = ( + publicKey: PublicKey, + account: AccountInfo, +) => { + return toMetadata( + parseMetadataAccount({ + ...account, + lamports: sol(account.lamports), + data: account.data, + publicKey, + }), + ) +} + +export function getMetadataId(mint: PublicKey): PublicKey { + return PublicKey.findProgramAddressSync( + [Buffer.from('metadata', 'utf-8'), MPL_PID.toBuffer(), mint.toBuffer()], + MPL_PID, + )[0] +} + export function useMetaplexMetadata(mint: PublicKey | undefined): { loading: boolean metadata: Metadata | undefined @@ -37,26 +58,15 @@ export function useMetaplexMetadata(mint: PublicKey | undefined): { } { const metadataAddr = useMemo(() => { if (mint) { - return PublicKey.findProgramAddressSync( - [Buffer.from('metadata', 'utf-8'), MPL_PID.toBuffer(), mint.toBuffer()], - MPL_PID, - )[0] + return getMetadataId(mint) } // eslint-disable-next-line react-hooks/exhaustive-deps }, [mint?.toBase58()]) - const parser: TypedAccountParser = useMemo(() => { - return (publicKey, account) => { - return toMetadata( - parseMetadataAccount({ - ...account, - lamports: sol(account.lamports), - data: account.data, - publicKey, - }), - ) - } - }, []) - const { info: metadataAcc, loading } = useAccount(metadataAddr, parser) + + const { info: metadataAcc, loading } = useAccount( + metadataAddr, + METADATA_PARSER, + ) const { result: json, loading: jsonLoading } = useAsync(getMetadata, [ metadataAcc?.uri, ]) diff --git a/src/locales/en.ts b/src/locales/en.ts index 4a7c3e765..4aaaa8184 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -952,8 +952,7 @@ export default { newOwner: 'New Owner', oldAddress: 'Old Address', oldOwner: 'Old Owner', - owner: 'Owner', - payee: 'Payee {{index}}', + owner: 'Owner {{index}}', pending: { inProcess: 'In Process', pending: 'Pending', diff --git a/src/types/activity.ts b/src/types/activity.ts index 8b11bd691..01cbaf275 100644 --- a/src/types/activity.ts +++ b/src/types/activity.ts @@ -1,49 +1,21 @@ export type Activity = { - account?: null | string address?: null | string amount?: null | number - amountToSeller?: null | number buyer?: null | string - elevation?: null | number - endEpoch?: null | number + feePayer?: string fee?: null | number - gain?: null | number gateway?: null | string hash: string height?: null | number - lat?: null | number - lng?: null | number - location?: null | string - memo?: null | string - newAddress?: null | string - newOwner?: null | string - nonce?: null | number - oldAddress?: null | string - oldOwner?: null | string - owner?: null | string payments?: null | Array pending?: null | boolean - rewards?: null | Array - seller?: null | string - stake?: null | number - stakeAmount?: null | number - stakingFee?: null | number - startEpoch?: null | number time?: null | number - mint?: null | string type: string } export type Payment = { amount: number memo?: null | string - payee: string + owner: string mint?: null | string } - -export type Reward = { - account?: null | string - amount: number - gateway?: null | string - type: string -} diff --git a/src/utils/solanaUtils.ts b/src/utils/solanaUtils.ts index dbb390041..a4eb9883d 100644 --- a/src/utils/solanaUtils.ts +++ b/src/utils/solanaUtils.ts @@ -79,7 +79,6 @@ import { Keypair, LAMPORTS_PER_SOL, Logs, - ParsedInstruction, ParsedTransactionWithMeta, PublicKey, SignatureResult, @@ -116,9 +115,9 @@ import { Mints, } from './constants' import { getH3Location } from './h3' +import { decimalSeparator, groupSeparator } from './i18n' import * as Logger from './logger' import sleep from './sleep' -import { decimalSeparator, groupSeparator } from './i18n' export function humanReadable( amount?: BN, @@ -1450,6 +1449,8 @@ export const solInstructionsToActivity = ( activity.fee = meta?.fee activity.height = slot + activity.feePayer = + parsedTxn.transaction.message.accountKeys[0].pubkey.toBase58() if (blockTime) { activity.time = blockTime @@ -1462,16 +1463,22 @@ export const solInstructionsToActivity = ( const preBalance = preTokenBalances.find( ({ accountIndex }) => accountIndex === post.accountIndex, ) - const pre = preBalance || { uiTokenAmount: { uiAmount: 0 } } + const pre = preBalance || { + uiTokenAmount: { uiAmount: 0 }, + owner: post.owner, + } const preAmount = pre.uiTokenAmount.uiAmount || 0 const postAmount = post.uiTokenAmount.uiAmount || 0 const amount = postAmount - preAmount - const p: Payment = { - amount, - payee: '', - mint: post.mint, + if (amount !== 0 && !Number.isNaN(amount)) { + const p: Payment = { + amount, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + owner: (post.owner || pre.owner)!, + mint: post.mint, + } + payments = [...payments, p] } - payments = [...payments, p] }) activity.payments = payments } @@ -1483,13 +1490,6 @@ export const solInstructionsToActivity = ( if (activity.type === 'unknown') return - const payment = activity.payments?.[0] - if (payment && payment.mint === DC_MINT.toBase58()) { - activity.type = payment.payee !== activity.payer ? 'dc_delegate' : 'dc_mint' - activity.amount = payment.amount - activity.mint = payment.mint - } - return activity }