Files
koins/apps/desktop/src/bun/rpc/xrp/index.ts
T

151 lines
4.0 KiB
TypeScript

import {
generateWallet,
walletFromSecret,
getXrpWalletList,
saveXrpWalletList,
getBalance,
getTransactions,
getTxDetails,
sendPayment,
getFee,
} from '../../lib/xrp'
import type { XrpWalletInfo } from '../../../lib/rpc-schema'
import { getSecret, setSecret, deleteSecret } from '../../lib/secrets-cache'
const SERVICE = 'koins'
export function createXrpHandlers() {
return {
xrpListWallets: async () => {
console.log('[rpc] xrpListWallets')
return getXrpWalletList()
},
xrpCreateWallet: async ({
name,
hasPassword,
}: {
name: string
hasPassword?: boolean
}) => {
console.log('[rpc] xrpCreateWallet:', name)
const { address, seed } = generateWallet()
const id = crypto.randomUUID()
const vaultKey = `xrp_seed_${id}`
await setSecret(SERVICE, vaultKey, seed)
const wallets = await getXrpWalletList()
const createdAt = new Date().toISOString()
const info: XrpWalletInfo = {
id,
name,
address,
hasPassword: hasPassword ?? false,
vaultKey,
createdAt,
}
await saveXrpWalletList([...wallets, info])
console.log('[rpc] xrpCreateWallet complete:', id)
return { id, address, seed, createdAt }
},
xrpImportWallet: async ({
name,
secret,
hasPassword,
}: {
name: string
secret: string
hasPassword?: boolean
}) => {
console.log('[rpc] xrpImportWallet:', name)
const { address } = walletFromSecret(secret)
const id = crypto.randomUUID()
const vaultKey = `xrp_seed_${id}`
await setSecret(SERVICE, vaultKey, secret.trim())
const wallets = await getXrpWalletList()
const createdAt = new Date().toISOString()
const info: XrpWalletInfo = {
id,
name,
address,
hasPassword: hasPassword ?? false,
vaultKey,
createdAt,
}
await saveXrpWalletList([...wallets, info])
console.log('[rpc] xrpImportWallet complete:', id)
return { id, address, createdAt }
},
xrpDeleteWallet: async ({ id }: { id: string }) => {
console.log('[rpc] xrpDeleteWallet:', id)
const wallets = await getXrpWalletList()
const wallet = wallets.find((w) => w.id === id)
if (!wallet) throw new Error('Wallet not found')
await Promise.all([
deleteSecret(SERVICE, wallet.vaultKey),
deleteSecret(SERVICE, `xrp_auth_${id}`),
])
await saveXrpWalletList(wallets.filter((w) => w.id !== id))
console.log('[rpc] xrpDeleteWallet complete')
},
xrpGetSeed: async ({ vaultKey }: { vaultKey: string }) => {
console.log('[rpc] xrpGetSeed:', vaultKey)
const seed = await getSecret(SERVICE, vaultKey)
if (!seed) throw new Error('Seed not found in keychain')
return seed
},
xrpGetBalance: async ({ address }: { address: string }) => {
console.log('[rpc] xrpGetBalance:', address)
return getBalance(address)
},
xrpGetTransactions: async ({ address }: { address: string }) => {
console.log('[rpc] xrpGetTransactions:', address)
try {
return await getTransactions(address)
} catch (e) {
if (e instanceof Error && e.message.includes('Account not found')) {
return []
}
throw e
}
},
xrpGetTxDetails: async ({ hash }: { hash: string }) => {
console.log('[rpc] xrpGetTxDetails:', hash)
return getTxDetails(hash)
},
xrpSend: async ({
secret,
to,
amount,
destinationTag,
}: {
secret: string
to: string
amount: string
destinationTag?: number
}) => {
console.log('[rpc] xrpSend:', { to, amount, destinationTag })
const result = await sendPayment(secret, to, amount, destinationTag)
console.log('[rpc] xrpSend complete:', result.hash)
return result
},
xrpGetFee: async () => {
console.log('[rpc] xrpGetFee')
return getFee()
},
fetchXrpPrice: async () => {
try {
const res = await fetch(
'https://api.coingecko.com/api/v3/simple/price?ids=ripple&vs_currencies=usd',
{ signal: AbortSignal.timeout(10000) },
)
if (!res.ok) return null
const data = await res.json()
if (!data?.ripple?.usd) return null
return { usd: String(data.ripple.usd) }
} catch (error) {
console.log('[xrp][price] error:', error)
return null
}
},
}
}