From 3925f3a4aac81e1fcb581548e344e06299408df3 Mon Sep 17 00:00:00 2001 From: TZGyn Date: Mon, 25 May 2026 22:37:54 +0800 Subject: [PATCH] Add Monero fee estimates per priority level via daemon RPC --- apps/desktop/src/bun/index.ts | 13 + apps/desktop/src/bun/lib/monero/wallet.ts | 77 ++- apps/desktop/src/lib/rpc-schema.ts | 7 + apps/desktop/src/routes/monero/index.svelte | 699 ++++++++++++-------- 4 files changed, 510 insertions(+), 286 deletions(-) diff --git a/apps/desktop/src/bun/index.ts b/apps/desktop/src/bun/index.ts index 70bd3ff..e664ddd 100644 --- a/apps/desktop/src/bun/index.ts +++ b/apps/desktop/src/bun/index.ts @@ -814,6 +814,19 @@ const rpc = BrowserView.defineRPC({ ) return details }, + moneroGetFeeEstimate: async () => { + console.log('[rpc] moneroGetFeeEstimate') + if (!moneroManager) + throw new Error('Monero wallet RPC not started') + try { + const fee = await moneroManager.getFeeEstimate() + console.log('[monero][gas][fee]', fee) + return fee + } catch (error) { + console.log('[monero][gas][error]', error) + return + } + }, evmCreateWallet: async ({ name, phrase, passwordHash }) => { console.log('[rpc] evmCreateWallet:', name) const id = crypto.randomUUID() diff --git a/apps/desktop/src/bun/lib/monero/wallet.ts b/apps/desktop/src/bun/lib/monero/wallet.ts index d12f544..42ca3cb 100644 --- a/apps/desktop/src/bun/lib/monero/wallet.ts +++ b/apps/desktop/src/bun/lib/monero/wallet.ts @@ -294,14 +294,19 @@ export class MoneroWalletManager { hash: t.txid, amount: t.amount?.toString() ?? '0', timestamp: String(t.timestamp ?? 0), - direction: dir === 'in' ? ('in' as const) : ('out' as const), + direction: + dir === 'in' ? ('in' as const) : ('out' as const), height: t.height ?? 0, note: t.note, }) } } - all.sort((a: any, b: any) => Number(b.timestamp) - Number(a.timestamp)) - console.log(`[monero] transactions: ${all.length} returned${accountIndex !== undefined ? ` for account ${accountIndex}` : ''}`) + all.sort( + (a: any, b: any) => Number(b.timestamp) - Number(a.timestamp), + ) + console.log( + `[monero] transactions: ${all.length} returned${accountIndex !== undefined ? ` for account ${accountIndex}` : ''}`, + ) return all } @@ -312,13 +317,22 @@ export class MoneroWalletManager { const t = result.transfer const isIn = t.type === 'in' const isOut = t.type === 'out' - const dests = t.destinations?.map((d: any) => ({ - address: d.address, - amount: d.amount?.toString() ?? '0', - })) ?? [] + const dests = + t.destinations?.map((d: any) => ({ + address: d.address, + amount: d.amount?.toString() ?? '0', + })) ?? [] const subaddrIndices = isIn - ? [{ major: t.subaddr_index?.major ?? 0, minor: t.subaddr_index?.minor ?? 0 }] - : (t.subaddr_indices ?? []).map((s: any) => ({ major: s.major ?? 0, minor: s.minor ?? 0 })) + ? [ + { + major: t.subaddr_index?.major ?? 0, + minor: t.subaddr_index?.minor ?? 0, + }, + ] + : (t.subaddr_indices ?? []).map((s: any) => ({ + major: s.major ?? 0, + minor: s.minor ?? 0, + })) return { hash: t.txid, direction: isIn ? ('in' as const) : ('out' as const), @@ -344,6 +358,43 @@ export class MoneroWalletManager { return height } + async getFeeEstimate(): Promise<{ + fee: string + fees: string[] + estimatedFee: string + }> { + try { + const conn = new MoneroRpcConnection({ + uri: `http://${this.daemonAddress}`, + }) + const res = await conn.sendJsonRequest('get_fee_estimate', { + grace_blocks: 10, + }) + if (res?.error) throw new Error(res.error.message) + console.log('[rpc][get_fee_estimate][response]', res) + const result = res?.result + const txSizeKb = 2.5 + const feePerKb = BigInt(result.fee ?? '0') + const fees = (result.fees ?? []).map((f: string) => + BigInt(f).toString(), + ) + const estimated = + (feePerKb * BigInt(Math.round(txSizeKb * 10))) / 10n + return { + fee: feePerKb.toString(), + fees, + estimatedFee: estimated.toString(), + } + } catch (e) { + console.log('[monero] getFeeEstimate error:', e) + return { + fee: '0', + fees: ['0', '0', '0', '0'], + estimatedFee: '0', + } + } + } + async getDaemonHeight(): Promise { if (!this.wallet) throw new Error('Wallet RPC not started') try { @@ -366,7 +417,9 @@ export class MoneroWalletManager { accountIndex: number = 0, ): Promise<{ txHash: string; fee: string; amount: string }> { if (!this.wallet) throw new Error('Wallet RPC not started') - console.log(`[monero] transfer: ${address} amount=${amount.toString()} priority=${priority} account=${accountIndex}`) + console.log( + `[monero] transfer: ${address} amount=${amount.toString()} priority=${priority} account=${accountIndex}`, + ) const result = await this.rawRpc('transfer', { destinations: [{ address, amount: amount.toString() }], priority, @@ -375,7 +428,9 @@ export class MoneroWalletManager { get_tx_hex: false, get_tx_metadata: false, }) - console.log(`[monero] transfer result: tx_hash=${result.tx_hash} fee=${result.fee} amount=${result.amount}`) + console.log( + `[monero] transfer result: tx_hash=${result.tx_hash} fee=${result.fee} amount=${result.amount}`, + ) return { txHash: result.tx_hash, fee: result.fee?.toString() ?? '0', diff --git a/apps/desktop/src/lib/rpc-schema.ts b/apps/desktop/src/lib/rpc-schema.ts index 668f154..c8233fb 100644 --- a/apps/desktop/src/lib/rpc-schema.ts +++ b/apps/desktop/src/lib/rpc-schema.ts @@ -73,6 +73,12 @@ export type MoneroAccountEntry = { subaddresses: MoneroSubaddressEntry[] } +export type MoneroFeeEstimate = { + fee: string + fees: string[] + estimatedFee: string +} + export type TxEntry = { hash: string timeStamp: string @@ -164,6 +170,7 @@ export type RPC = { moneroListWallets: { params: {}; response: string[] } moneroTransfer: { params: { address: string; amount: string; priority?: number; accountIndex?: number }; response: MoneroSendResult } moneroGetTransferDetails: { params: { txid: string }; response: MoneroTransferDetails | null } + moneroGetFeeEstimate: { params: {}; response: MoneroFeeEstimate | null } evmCreateWallet: { params: { name: string; phrase: string; passwordHash?: string }; response: { id: string; name: string; createdAt: string } } evmListWallets: { params: {}; response: EvmWalletInfo[] } evmGetSeed: { params: { vaultKey: string }; response: string } diff --git a/apps/desktop/src/routes/monero/index.svelte b/apps/desktop/src/routes/monero/index.svelte index d9126f5..580cee2 100644 --- a/apps/desktop/src/routes/monero/index.svelte +++ b/apps/desktop/src/routes/monero/index.svelte @@ -1,5 +1,9 @@