fix biometric, tx dedup, loading crash; add flush cache; remove monero startup from evm init

- biometric-helper: use .deviceOwnerAuthentication so passcode can
  unlock Touch ID when biometrics are locked out
- get-transaction-history: dedup transfers by hash+category+contract
  instead of hash alone (was dropping token transfers sharing a tx hash)
- evm-wallet.svelte.ts: add missing loading  declaration (caused
  ReferenceError on createWallet); add flushTxCache method; comment out
  monero startup from evm init to speed up loading
- get-history.ts: remove dead caching logic (now handled by sync engine);
  import getTransactionHistory from alchemy directly
- backend RPC + settings UI: add flushTxCache to clear tx cache tables
This commit is contained in:
2026-05-22 03:03:03 +08:00
parent edd4f6fff0
commit dd57a72e11
9 changed files with 262 additions and 122 deletions
@@ -68,8 +68,9 @@ export const getTransactionHistory = async (
let lastTimestamp = ''
for (const t of transfers) {
if (!t.hash) continue
if (seen.has(t.hash)) continue
seen.add(t.hash)
const dedupKey = `${t.hash}_${t.category}_${t.rawContract?.address ?? ''}`
if (seen.has(dedupKey)) continue
seen.add(dedupKey)
all.push(t)
if (t.blockNum) {
@@ -87,7 +88,7 @@ export const getTransactionHistory = async (
console.log(
`[alchemy] ${direction} page ${page + 1}: ${transfers.length} transfers, ` +
`block ${pageMaxBlock}, ` +
`${new Date(firstTimestamp).toISOString()} → ${new Date(lastTimestamp).toISOString()}`,
`${firstTimestamp ? new Date(firstTimestamp).toISOString() : '?'} → ${lastTimestamp ? new Date(lastTimestamp).toISOString() : '?'}`,
)
if (pageMaxBlock === 0) break
@@ -1,7 +1,6 @@
import { eq, and, or, desc } from 'drizzle-orm'
import { db } from '../db'
import { txHistory } from '../db/schema'
import { getTransactionHistory as fetchFromAlchemy } from '../alchemy/get-transaction-history'
import type { Transaction } from '../alchemy/types'
export const getTransactionHistory = async (
@@ -10,58 +9,7 @@ export const getTransactionHistory = async (
address: string,
opts: { maxCount: number },
) => {
const result = await fetchFromAlchemy(key, chainid, address, opts)
if (result) {
for (const t of result) {
if (!t.hash) continue
const existing = await db.query.txHistory.findFirst({
where: {
hash: t.hash,
chainId: chainid,
},
})
if (!existing) {
await db.insert(txHistory).values({
chainId: chainid,
hash: t.hash,
blockNum: t.blockNum
? String(parseInt(t.blockNum, 16))
: null,
from: t.from?.toLowerCase() ?? null,
to: t.to?.toLowerCase() ?? null,
value: t.value?.toString() ?? null,
asset: t.asset ?? null,
category: t.category ?? null,
rawContractAddress:
t.rawContract?.address?.toLowerCase() ?? null,
rawContractDecimal: t.rawContract?.decimal ?? null,
metadataBlockTimestamp: t.metadata?.blockTimestamp ?? null,
raw: JSON.stringify(t),
syncedAt: new Date().toISOString(),
})
}
}
}
const addrLower = address.toLowerCase()
const rows = db
.select()
.from(txHistory)
.where(
and(
eq(txHistory.chainId, chainid),
or(
eq(txHistory.from, addrLower),
eq(txHistory.to, addrLower),
),
),
)
.orderBy(desc(txHistory.blockNum))
.all()
return rows.map(toTransfer)
return getCachedTransactionHistory(chainid, address)
}
export const getCachedTransactionHistory = (
@@ -1,2 +1,5 @@
export { getTransactionHistory, getCachedTransactionHistory } from './get-history'
export {
getTransactionHistory,
getCachedTransactionHistory,
} from './get-history'
export { getTransactionDetails } from './get-details'