Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 62 additions & 23 deletions src/controllers/activity/activity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,13 @@ import {
isIdentifiedByUserOpHash,
PortfoliosToUpdate,
SubmittedAccountOp,
SubmittedAccountOpLike,
updateOpStatus
} from '../../libs/accountOp/submittedAccountOp'
import { AccountOpStatus } from '../../libs/accountOp/types'
import { getTransferLogTokens } from '../../libs/logsParser/parseLogs'
import { parseLogs } from '../../libs/userOperation/userOperation'
import { getDebugTraceTransaction } from '../../utils/debugTransaction'
import wait from '../../utils/wait'
import EventEmitter from '../eventEmitter/eventEmitter'
import { InternalSignedMessages, SignedMessage } from './types'
Expand All @@ -56,7 +58,13 @@ interface PaginationResult<T> {
maxPages: number
}

interface AccountsOps extends PaginationResult<SubmittedAccountOp> {}
interface AccountsOps extends PaginationResult<SubmittedAccountOpLike> {}

type AccountOpBalanceChangesBackfillReference = Pick<
SubmittedAccountOp,
'identifiedBy' | 'accountAddr' | 'chainId'
>

interface MessagesToBeSigned extends PaginationResult<SignedMessage> {}

export interface Filters {
Expand All @@ -70,6 +78,11 @@ export interface InternalAccountsOps {
[key: string]: { [key: string]: SubmittedAccountOp[] }
}

export interface ExternalAccountOps {
// account => network => SubmittedAccountOpLike[]
[key: string]: { [key: string]: SubmittedAccountOpLike[] }
}

// We are limiting items array to include no more than 1000 records,
// as we trim out the oldest ones (in the beginning of the items array).
// We do this to maintain optimal storage and performance.
Expand Down Expand Up @@ -180,6 +193,8 @@ export class ActivityController extends EventEmitter implements IActivityControl

#accountsOps: InternalAccountsOps = {}

#externalAccountOps: ExternalAccountOps = {}

accountsOps: {
[sessionId: string]: {
result: AccountsOps
Expand Down Expand Up @@ -262,12 +277,14 @@ export class ActivityController extends EventEmitter implements IActivityControl
async #load(): Promise<void> {
await this.#accounts.initialLoadPromise
await this.#selectedAccount.initialLoadPromise
const [accountsOps, signedMessages] = await Promise.all([
const [accountsOps, externalAccountOps, signedMessages] = await Promise.all([
this.#storage.get('accountsOps', {}),
this.#storage.get('externalAccountOps', {}),
this.#storage.get('signedMessages', {})
])

this.#accountsOps = accountsOps
this.#externalAccountOps = externalAccountOps
this.#signedMessages = signedMessages

this.emitUpdate()
Expand Down Expand Up @@ -362,29 +379,52 @@ export class ActivityController extends EventEmitter implements IActivityControl
pagination: Pagination = { fromPage: 0, itemsPerPage: 10 }
) {
await this.#initialLoadPromise
this.#externalAccountOps = await this.#storage.get(
'externalAccountOps',
this.#externalAccountOps
)

const enabledNetworkChainIds = this.#networks.networks.map(({ chainId }) => String(chainId))
const accountOpsEntriesOnEnabledNetworks = Object.entries(
this.#accountsOps[filters.account] || {}
const internalAccountOpsByChain = this.#accountsOps[filters.account] || {}
const externalAccountOpsByChain = this.#externalAccountOps[filters.account] || {}
const internalAccountOpsEntriesOnEnabledNetworks = Object.entries(
internalAccountOpsByChain
).filter(([chainId]) => enabledNetworkChainIds.includes(chainId))
let filteredItems: SubmittedAccountOp[]
const internalAccountOps = new Set(
internalAccountOpsEntriesOnEnabledNetworks.flatMap(([, accountOps]) => accountOps)
)
const accountOpsEntriesOnEnabledNetworks = enabledNetworkChainIds
.map(
(chainId) =>
[
chainId,
[
...(internalAccountOpsByChain[chainId] || []),
...(externalAccountOpsByChain[chainId] || [])
]
] as const
)
.filter(([, accountOps]) => accountOps.length)
let filteredItems: SubmittedAccountOpLike[]

if (filters.chainId && enabledNetworkChainIds.includes(String(filters.chainId))) {
filteredItems =
accountOpsEntriesOnEnabledNetworks.find(
filteredItems = [
...(accountOpsEntriesOnEnabledNetworks.find(
([chainId]) => chainId === String(filters.chainId)
)?.[1] || []
)?.[1] || [])
]
} else {
filteredItems = accountOpsEntriesOnEnabledNetworks.flatMap(([, accountOps]) => accountOps)
// By default, #accountsOps are grouped by network and sorted in descending order.
// However, when the network filter is omitted, #accountsOps from different networks are mixed,
// requiring additional sorting to ensure they are also in descending order.
filteredItems.sort((a, b) => b.timestamp - a.timestamp)
}

// By default, account ops are grouped by network and sorted in descending order.
// However, when internal and external ops are mixed, they need a final sort even
// when a network filter is present.
filteredItems.sort((a, b) => b.timestamp - a.timestamp)

// for benzin fetching
if (filters.identifiedBy) {
filteredItems.filter(
filteredItems = filteredItems.filter(
(i) => i.identifiedBy && i.identifiedBy.identifier === filters.identifiedBy!.identifier
)
}
Expand All @@ -400,8 +440,10 @@ export class ActivityController extends EventEmitter implements IActivityControl
// no need to console.log anything in the catch statement here
// as error handling is handled in backfillAccountOpBalanceChangesAndPersist.
const opsWithNoBalanceChanges = result.items.filter(
(op: SubmittedAccountOp) =>
op.status !== AccountOpStatus.BroadcastedButNotConfirmed && op.balanceChanges === undefined
(op): op is SubmittedAccountOp =>
internalAccountOps.has(op as SubmittedAccountOp) &&
op.status !== AccountOpStatus.BroadcastedButNotConfirmed &&
op.balanceChanges === undefined
)
if (opsWithNoBalanceChanges.length)
this.backfillAccountOpBalanceChangesAndPersist(opsWithNoBalanceChanges).catch((e) => null)
Expand Down Expand Up @@ -583,7 +625,7 @@ export class ActivityController extends EventEmitter implements IActivityControl
* We have this separation in order to persist to storage only after the
* end of an operation
*/
async backfillAccountOpBalanceChanges(accountOp: SubmittedAccountOp) {
async backfillAccountOpBalanceChanges(accountOp: AccountOpBalanceChangesBackfillReference) {
await this.#initialLoadPromise

// take the latest #accountOp, not a stale one from the UI
Expand Down Expand Up @@ -1094,13 +1136,10 @@ export class ActivityController extends EventEmitter implements IActivityControl
getTokenBalancesOnBlock: this.#portfolio.getTokenBalancesOnBlock.bind(this.#portfolio),
prevBlockNumber,
receipts,
debugTraceTransaction: (txnHash) =>
network.chainId === 999n
? this.#providers.providers[network.chainId.toString()]!.send(
'debug_traceTransaction',
[txnHash, { tracer: 'callTracer' }]
)
: Promise.resolve(null)
debugTraceTransaction: getDebugTraceTransaction(
network.chainId,
this.#providers.providers[network.chainId.toString()]
)
})

await this.setAccountOpBalanceChanges(
Expand Down
6 changes: 2 additions & 4 deletions src/controllers/providers/providers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { getAccountOpBalanceChanges } from '../../libs/accountOp/balanceChanges'
import { getProviderBatchMaxCount } from '../../libs/networks/networks'
import { GetOptions, Portfolio, TokenResult } from '../../libs/portfolio'
import { getRpcProvider } from '../../services/provider'
import { getDebugTraceTransaction } from '../../utils/debugTransaction'
import EventEmitter from '../eventEmitter/eventEmitter'

const STATUS_WRAPPED_METHODS = {
Expand Down Expand Up @@ -433,10 +434,7 @@ export class ProvidersController extends EventEmitter implements IProvidersContr
receiptBlockNumber: blockTag,
getTokenBalancesOnBlock,
receipts,
debugTraceTransaction: (txnHash) =>
chainId === 999n
? provider.send('debug_traceTransaction', [txnHash, { tracer: 'callTracer' }])
: Promise.resolve(null)
debugTraceTransaction: getDebugTraceTransaction(chainId, provider)
})

return this.#sendUiMessage({
Expand Down
2 changes: 1 addition & 1 deletion src/controllers/swapAndBridge/socketApiMock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,6 @@ export class SocketAPIMock {

// eslint-disable-next-line @typescript-eslint/no-unused-vars
async getRouteStatus({ txHash }: { txHash: string }) {
return 'completed'
return { status: 'completed', txnId: txHash }
}
}
Loading