split data access into API-only (alchemy/viem) and DB-first wrappers (tokens/transactions)
alchemy/get-token-metadata: stripped DB logic, now pure API call viem/get-transaction-details: stripped DB logic, now pure viem call tokens/get-metadata: new DB-first wrapper for token metadata transactions/get-details: new DB-first wrapper for tx details transactions/get-history: stores individual Alchemy transfers in tx_history table with blockNum, from, to columns for searchable ordering
This commit is contained in:
+100
-33
@@ -8,19 +8,18 @@ import {
|
||||
defineElectrobunRPC,
|
||||
type RPCSchema,
|
||||
} from 'electrobun/bun'
|
||||
import { inspect } from 'util'
|
||||
import {
|
||||
getTokenMetadata,
|
||||
getTokensBalances,
|
||||
type Transaction,
|
||||
} from './lib/alchemy'
|
||||
import { getTokenMetadata } from './lib/tokens'
|
||||
import { getTokensBalances, type Transaction } from './lib/alchemy'
|
||||
import { tryCatch } from '@koins/utils'
|
||||
import { getTransactionHistory } from './lib/alchemy/get-transaction-history'
|
||||
import {
|
||||
getTransactionHistory,
|
||||
getTransactionDetails,
|
||||
} from './lib/transactions'
|
||||
import { migrate } from 'drizzle-orm/bun-sqlite/migrator'
|
||||
import { db } from './lib/db'
|
||||
import { join } from 'path'
|
||||
import { getENV } from './lib/get-env'
|
||||
import { getClient, getTransactionDetails } from './lib/viem'
|
||||
import { getClient } from './lib/viem'
|
||||
import {
|
||||
isBinaryInstalled,
|
||||
downloadBinary,
|
||||
@@ -168,7 +167,7 @@ type RPC = {
|
||||
hash: string
|
||||
chainid: string
|
||||
}
|
||||
response: TxDetailsResult | null
|
||||
response: ReturnType<typeof getTransactionDetails>
|
||||
}
|
||||
openExternal: {
|
||||
params: {
|
||||
@@ -206,7 +205,12 @@ type RPC = {
|
||||
response: { mnemonic: string; address: string }
|
||||
}
|
||||
moneroRestoreWallet: {
|
||||
params: { name: string; password: string; mnemonic: string; restoreHeight?: number }
|
||||
params: {
|
||||
name: string
|
||||
password: string
|
||||
mnemonic: string
|
||||
restoreHeight?: number
|
||||
}
|
||||
response: { address: string }
|
||||
}
|
||||
moneroOpenWallet: {
|
||||
@@ -509,7 +513,11 @@ const rpc = BrowserView.defineRPC<RPC>({
|
||||
if (!key) return null
|
||||
try {
|
||||
const client = getClient(chainid, key)
|
||||
const details = await getTransactionDetails(client, hash, chainid)
|
||||
const details = await getTransactionDetails(
|
||||
client,
|
||||
hash,
|
||||
chainid,
|
||||
)
|
||||
return details
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
@@ -517,12 +525,17 @@ const rpc = BrowserView.defineRPC<RPC>({
|
||||
}
|
||||
},
|
||||
moneroBinaryStatus: async () => {
|
||||
const status = { installed: isBinaryInstalled(), downloading: moneroDownloading }
|
||||
const status = {
|
||||
installed: isBinaryInstalled(),
|
||||
downloading: moneroDownloading,
|
||||
}
|
||||
console.log('[rpc] moneroBinaryStatus:', status)
|
||||
return status
|
||||
},
|
||||
moneroDownloadBinary: async () => {
|
||||
console.log('[rpc] moneroDownloadBinary: starting download...')
|
||||
console.log(
|
||||
'[rpc] moneroDownloadBinary: starting download...',
|
||||
)
|
||||
moneroDownloading = true
|
||||
try {
|
||||
await downloadBinary()
|
||||
@@ -543,10 +556,17 @@ const rpc = BrowserView.defineRPC<RPC>({
|
||||
await moneroManager.start(daemonAddress)
|
||||
} catch (e) {
|
||||
console.log('[rpc] moneroStart error:', e)
|
||||
return { running: false, walletOpen: false, connected: false }
|
||||
return {
|
||||
running: false,
|
||||
walletOpen: false,
|
||||
connected: false,
|
||||
}
|
||||
}
|
||||
const connected = await moneroManager.isConnected()
|
||||
console.log('[rpc] moneroStart complete, connected:', connected)
|
||||
console.log(
|
||||
'[rpc] moneroStart complete, connected:',
|
||||
connected,
|
||||
)
|
||||
return { running: true, walletOpen: false, connected }
|
||||
},
|
||||
moneroStop: async () => {
|
||||
@@ -558,32 +578,58 @@ const rpc = BrowserView.defineRPC<RPC>({
|
||||
},
|
||||
moneroCreateWallet: async ({ name, password }) => {
|
||||
console.log('[rpc] moneroCreateWallet:', name)
|
||||
if (!moneroManager) throw new Error('Monero wallet RPC not started')
|
||||
const result = await moneroManager.createWallet(name, password)
|
||||
if (!moneroManager)
|
||||
throw new Error('Monero wallet RPC not started')
|
||||
const result = await moneroManager.createWallet(
|
||||
name,
|
||||
password,
|
||||
)
|
||||
console.log('[rpc] moneroCreateWallet complete')
|
||||
return result
|
||||
},
|
||||
moneroRestoreWallet: async ({ name, password, mnemonic, restoreHeight }) => {
|
||||
moneroRestoreWallet: async ({
|
||||
name,
|
||||
password,
|
||||
mnemonic,
|
||||
restoreHeight,
|
||||
}) => {
|
||||
console.log('[rpc] moneroRestoreWallet:', name)
|
||||
if (!moneroManager) throw new Error('Monero wallet RPC not started')
|
||||
await moneroManager.restoreWallet(name, password, mnemonic, restoreHeight)
|
||||
if (!moneroManager)
|
||||
throw new Error('Monero wallet RPC not started')
|
||||
await moneroManager.restoreWallet(
|
||||
name,
|
||||
password,
|
||||
mnemonic,
|
||||
restoreHeight,
|
||||
)
|
||||
const address = await moneroManager.getAddress()
|
||||
console.log('[rpc] moneroRestoreWallet complete, address:', address)
|
||||
console.log(
|
||||
'[rpc] moneroRestoreWallet complete, address:',
|
||||
address,
|
||||
)
|
||||
return { address }
|
||||
},
|
||||
moneroOpenWallet: async ({ name, password }) => {
|
||||
console.log('[rpc] moneroOpenWallet:', name)
|
||||
if (!moneroManager) throw new Error('Monero wallet RPC not started')
|
||||
if (!moneroManager)
|
||||
throw new Error('Monero wallet RPC not started')
|
||||
await moneroManager.openWallet(name, password)
|
||||
},
|
||||
moneroGetBalance: async () => {
|
||||
console.log('[rpc] moneroGetBalance')
|
||||
if (!moneroManager) throw new Error('Monero wallet RPC not started')
|
||||
if (!moneroManager)
|
||||
throw new Error('Monero wallet RPC not started')
|
||||
const { balance, unlocked } = await moneroManager.getBalance()
|
||||
const address = await moneroManager.getAddress()
|
||||
const height = await moneroManager.getHeight()
|
||||
const daemonHeight = await moneroManager.getDaemonHeight()
|
||||
console.log('[rpc] balance:', { balance: balance.toString(), unlocked: unlocked.toString(), address, height, daemonHeight })
|
||||
console.log('[rpc] balance:', {
|
||||
balance: balance.toString(),
|
||||
unlocked: unlocked.toString(),
|
||||
address,
|
||||
height,
|
||||
daemonHeight,
|
||||
})
|
||||
return {
|
||||
balance: balance.toString(),
|
||||
unlocked: unlocked.toString(),
|
||||
@@ -594,40 +640,61 @@ const rpc = BrowserView.defineRPC<RPC>({
|
||||
},
|
||||
moneroGetTransactions: async () => {
|
||||
console.log('[rpc] moneroGetTransactions')
|
||||
if (!moneroManager) throw new Error('Monero wallet RPC not started')
|
||||
if (!moneroManager)
|
||||
throw new Error('Monero wallet RPC not started')
|
||||
const txs = await moneroManager.getTransactions()
|
||||
const result = (txs || []).map((tx: any) => ({
|
||||
hash: tx.hash,
|
||||
amount: tx.amount?.toString() ?? '0',
|
||||
timestamp: String(tx.timestamp ?? 0),
|
||||
direction: tx.direction === 'in' ? 'in' as const : 'out' as const,
|
||||
direction:
|
||||
tx.direction === 'in'
|
||||
? ('in' as const)
|
||||
: ('out' as const),
|
||||
height: tx.height ?? 0,
|
||||
}))
|
||||
console.log(`[rpc] moneroGetTransactions: ${result.length} txs`)
|
||||
console.log(
|
||||
`[rpc] moneroGetTransactions: ${result.length} txs`,
|
||||
)
|
||||
return result
|
||||
},
|
||||
moneroWalletStatus: async () => {
|
||||
if (!moneroManager) {
|
||||
console.log('[rpc] moneroWalletStatus: not running')
|
||||
return { running: false, walletOpen: false, connected: false }
|
||||
return {
|
||||
running: false,
|
||||
walletOpen: false,
|
||||
connected: false,
|
||||
}
|
||||
}
|
||||
const connected = await moneroManager.isConnected()
|
||||
const walletOpen = await moneroManager.isWalletOpen()
|
||||
console.log('[rpc] moneroWalletStatus: running, walletOpen:', walletOpen, 'connected:', connected)
|
||||
console.log(
|
||||
'[rpc] moneroWalletStatus: running, walletOpen:',
|
||||
walletOpen,
|
||||
'connected:',
|
||||
connected,
|
||||
)
|
||||
return { running: true, walletOpen, connected }
|
||||
},
|
||||
moneroGetAccounts: async () => {
|
||||
console.log('[rpc] moneroGetAccounts')
|
||||
if (!moneroManager) throw new Error('Monero wallet RPC not started')
|
||||
if (!moneroManager)
|
||||
throw new Error('Monero wallet RPC not started')
|
||||
const accounts = await moneroManager.getAccounts()
|
||||
console.log(`[rpc] moneroGetAccounts: ${accounts.length} accounts`)
|
||||
console.log(
|
||||
`[rpc] moneroGetAccounts: ${accounts.length} accounts`,
|
||||
)
|
||||
return accounts
|
||||
},
|
||||
moneroListWallets: async () => {
|
||||
console.log('[rpc] moneroListWallets')
|
||||
if (!moneroManager) throw new Error('Monero wallet RPC not started')
|
||||
if (!moneroManager)
|
||||
throw new Error('Monero wallet RPC not started')
|
||||
const wallets = moneroManager.listWallets()
|
||||
console.log(`[rpc] moneroListWallets: ${wallets.join(', ') || 'none'}`)
|
||||
console.log(
|
||||
`[rpc] moneroListWallets: ${wallets.join(', ') || 'none'}`,
|
||||
)
|
||||
return wallets
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user