diff --git a/main/index.js b/main/index.js index 8ccf54fdb..737a3b11a 100644 --- a/main/index.js +++ b/main/index.js @@ -1,6 +1,6 @@ 'use strict' -const { app, dialog } = require('electron') +const { app, dialog, shell } = require('electron') const electronLog = require('electron-log') const path = require('node:path') @@ -117,7 +117,8 @@ const ctx = { confirmChangeWalletAddress: () => { throw new Error('never get here') }, restartToUpdate: () => { throw new Error('never get here') }, openReleaseNotes: () => { throw new Error('never get here') }, - getUpdaterStatus: () => { throw new Error('never get here') } + getUpdaterStatus: () => { throw new Error('never get here') }, + browseTransactionTracker: (/** @type {string} */ transactionHash) => { shell.openExternal(`https://explorer.glif.io/tx/${transactionHash}`) } } app.on('before-quit', () => { diff --git a/main/ipc.js b/main/ipc.js index 8f5aa601e..1642929d3 100644 --- a/main/ipc.js +++ b/main/ipc.js @@ -26,10 +26,15 @@ function setupIpcMain (/** @type {Context} */ ctx) { ipcMain.handle('saturn:getFilAddress', saturnNode.getFilAddress) ipcMain.handle('saturn:setFilAddress', (_event, address) => saturnNode.setFilAddress(address)) // Station-wide config - ipcMain.handle('station:getFilAddress', saturnNode.getFilAddress) - ipcMain.handle('station:setFilAddress', (_event, address) => saturnNode.setFilAddress(address)) ipcMain.handle('station:getOnboardingCompleted', stationConfig.getOnboardingCompleted) ipcMain.handle('station:setOnboardingCompleted', (_event) => stationConfig.setOnboardingCompleted()) + // Wallet-wide config + ipcMain.handle('station:getStationWalletAddress', stationConfig.getStationWalletAddress) + ipcMain.handle('station:getDestinationWalletAddress', stationConfig.getDestinationWalletAddress) + ipcMain.handle('station:setDestinationWalletAddress', (_event, address) => stationConfig.setDestinationWalletAddress(address)) + ipcMain.handle('station:getStationWalletBalance', stationConfig.getStationWalletBalance) + ipcMain.handle('station:getStationWalletTransactionsHistory', stationConfig.getStationWalletTransactionsHistory) + ipcMain.handle('station:transferAllFundsToDestinationWallet', (_event, _args) => stationConfig.transferAllFundsToDestinationWallet()) ipcMain.handle('station:getAllActivities', (_event, _args) => ctx.getAllActivities()) ipcMain.handle('station:getTotalJobsCompleted', (_event, _args) => ctx.getTotalJobsCompleted()) @@ -39,6 +44,7 @@ function setupIpcMain (/** @type {Context} */ ctx) { ipcMain.handle('station:restartToUpdate', (_event, _args) => ctx.restartToUpdate()) ipcMain.handle('station:openReleaseNotes', (_event) => ctx.openReleaseNotes()) ipcMain.handle('station:getUpdaterStatus', (_events, _args) => ctx.getUpdaterStatus()) + ipcMain.handle('station:browseTransactionTracker', (_events, transactionHash) => ctx.browseTransactionTracker(transactionHash)) } module.exports = { diff --git a/main/preload.js b/main/preload.js index 2673763a6..d4c604a1a 100644 --- a/main/preload.js +++ b/main/preload.js @@ -2,6 +2,7 @@ /** @typedef {import('electron').IpcRendererEvent} IpcRendererEvent */ /** @typedef {import('./typings').Activity} Activity */ +/** @typedef {import('./typings').FILTransaction} TransactionMessage */ const { contextBridge, ipcRenderer } = require('electron') @@ -22,14 +23,19 @@ contextBridge.exposeInMainWorld('electron', { isReady: () => ipcRenderer.invoke('saturn:isReady'), getLog: () => ipcRenderer.invoke('saturn:getLog'), getWebUrl: () => ipcRenderer.invoke('saturn:getWebUrl'), - getFilAddress: () => ipcRenderer.invoke('saturn:getFilAddress'), - setFilAddress: (/** @type {string | undefined} */ address) => ipcRenderer.invoke('saturn:setFilAddress', address) + getFilAddress: () => ipcRenderer.invoke('saturn:getFilAddress'), // soon to be removed + setFilAddress: (/** @type {string | undefined} */ address) => ipcRenderer.invoke('saturn:setFilAddress', address) // soon to be removed }, stationConfig: { - getFilAddress: () => ipcRenderer.invoke('station:getFilAddress'), - setFilAddress: (/** @type {string | undefined} */ address) => ipcRenderer.invoke('station:setFilAddress', address), getOnboardingCompleted: () => ipcRenderer.invoke('station:getOnboardingCompleted'), - setOnboardingCompleted: () => ipcRenderer.invoke('station:setOnboardingCompleted') + setOnboardingCompleted: () => ipcRenderer.invoke('station:setOnboardingCompleted'), + getStationWalletAddress: () => ipcRenderer.invoke('station:getStationWalletAddress'), + getDestinationWalletAddress: () => ipcRenderer.invoke('station:getDestinationWalletAddress'), + setDestinationWalletAddress: (/** @type {string | undefined} */ address) => ipcRenderer.invoke('station:setDestinationWalletAddress', address), + getStationWalletBalance: () => ipcRenderer.invoke('station:getStationWalletBalance'), + getStationWalletTransactionsHistory: () => ipcRenderer.invoke('station:getStationWalletTransactionsHistory'), + transferAllFundsToDestinationWallet: () => ipcRenderer.invoke('station:transferAllFundsToDestinationWallet'), + browseTransactionTracker: (/** @type {string } */ transactionHash) => ipcRenderer.invoke('station:browseTransactionTracker', transactionHash) }, stationEvents: { onActivityLogged: (/** @type {(value: Activity) => void} */ callback) => { @@ -54,6 +60,18 @@ contextBridge.exposeInMainWorld('electron', { const listener = () => callback() ipcRenderer.on('station:update-available', listener) return () => ipcRenderer.removeListener('station:update-available', listener) + }, + onBalanceUpdate: (/** @type {(value: number) => void} */ callback) => { + /** @type {(event: IpcRendererEvent, ...args: any[]) => void} */ + const listener = (_event, balance) => callback(balance) + ipcRenderer.on('station:wallet-balance-update', listener) + return () => ipcRenderer.removeListener('station:wallet-balance-update', listener) + }, + onTransactionUpdate: (/** @type {(value: TransactionMessage) => void} */ callback) => { + /** @type {(event: IpcRendererEvent, ...args: any[]) => void} */ + const listener = (_event, transactions) => callback(transactions) + ipcRenderer.on('station:transaction-update', listener) + return () => ipcRenderer.removeListener('station:transaction-update', listener) } }, dialogs: { diff --git a/main/station-config.js b/main/station-config.js index fa48ae39f..30dec6777 100644 --- a/main/station-config.js +++ b/main/station-config.js @@ -9,9 +9,12 @@ const ConfigKeys = { OnboardingCompleted: 'station.OnboardingCompleted', TrayOperationExplained: 'station.TrayOperationExplained', StationID: 'station.StationID', - FilAddress: 'station.FilAddress' + FilAddress: 'station.FilAddress', + DestinationFilAddress: 'station.FilAddress' // todo - replace by 'station.DestinationFilAddress' } +/** @typedef {import('./typings').FILTransaction} TransactionMessage */ + // Use this to test migrations // https://github.com/sindresorhus/electron-store/issues/205 // require('electron').app.setVersion('9999.9.9') @@ -37,6 +40,7 @@ log.info('Loading Station configuration from', configStore.path) let OnboardingCompleted = /** @type {boolean} */ (configStore.get(ConfigKeys.OnboardingCompleted, false)) let TrayOperationExplained = /** @type {boolean} */ (configStore.get(ConfigKeys.TrayOperationExplained, false)) let FilAddress = /** @type {string | undefined} */ (configStore.get(ConfigKeys.FilAddress)) +let DestinationFilAddress = /** @type {string | undefined} */ (configStore.get(ConfigKeys.DestinationFilAddress)) const StationID = /** @type {string} */ (configStore.get(ConfigKeys.StationID, randomUUID())) /** @@ -91,6 +95,49 @@ function getStationID () { return StationID } +/** + * @returns {string} + */ +function getStationWalletAddress () { + return FilAddress || '' +} + +/** + * @returns {string | undefined} + */ +function getDestinationWalletAddress () { + return DestinationFilAddress +} + +/** + * @param {string | undefined} address + */ +function setDestinationWalletAddress (address) { + DestinationFilAddress = address + configStore.set(ConfigKeys.DestinationFilAddress, DestinationFilAddress) +} + +/** + * @returns {number} + */ +function getStationWalletBalance () { + return 0 // todo - backend logic +} + +/** + * @returns { TransactionMessage[] } + */ +function getStationWalletTransactionsHistory () { + return [] // todo - backend logic +} + +/** + * @returns void + */ +function transferAllFundsToDestinationWallet () { + return {} // todo - backend logic +} + module.exports = { getOnboardingCompleted, setOnboardingCompleted, @@ -98,5 +145,11 @@ module.exports = { setTrayOperationExplained, getFilAddress, setFilAddress, - getStationID + getStationID, + getStationWalletAddress, + getDestinationWalletAddress, + setDestinationWalletAddress, + getStationWalletBalance, + getStationWalletTransactionsHistory, + transferAllFundsToDestinationWallet } diff --git a/main/typings.d.ts b/main/typings.d.ts index 918e514e7..fb589bdb8 100644 --- a/main/typings.d.ts +++ b/main/typings.d.ts @@ -1,5 +1,6 @@ export type ActivitySource = 'Station' | 'Saturn'; export type ActivityType = 'info' | 'error'; +export type TransactionStatus = 'sent' | 'processing' | 'failed' export interface Activity { id: string; @@ -9,6 +10,15 @@ export interface Activity { message: string; } +export type FILTransaction = { + hash: string + timestamp: number + status: TransactionStatus + outgoing: boolean + amount: string + address: string +} + export type RecordActivityArgs = Omit; export type ModuleJobStatsMap = Record; @@ -28,5 +38,6 @@ export interface Context { openReleaseNotes: () => void, restartToUpdate: () => void, - getUpdaterStatus: () => {updateAvailable: boolean} + getUpdaterStatus: () => {updateAvailable: boolean}, + browseTransactionTracker: (transactionHash: string) => void } diff --git a/renderer/src/components/Saturn.tsx b/renderer/src/components/Saturn.tsx index c32c7843a..b0fd17fce 100644 --- a/renderer/src/components/Saturn.tsx +++ b/renderer/src/components/Saturn.tsx @@ -1,13 +1,9 @@ import { useEffect } from 'react' -import { getFilAddress, startSaturnNode } from '../lib/station-config' +import { startSaturnNode } from '../lib/station-config' const Saturn = () => { useEffect(() => { - (async () => { - if (await getFilAddress()) { - startSaturnNode() - } - })() + startSaturnNode() }, []) return null diff --git a/renderer/src/hooks/StationWallet.tsx b/renderer/src/hooks/StationWallet.tsx new file mode 100644 index 000000000..3d0582ef1 --- /dev/null +++ b/renderer/src/hooks/StationWallet.tsx @@ -0,0 +1,98 @@ +import { useState, useEffect } from 'react' +import { + getDestinationWalletAddress, + setDestinationWalletAddress, + getStationWalletAddress, + getStationWalletBalance, + getStationWalletTransactionsHistory +} from '../lib/station-config' +import { FILTransaction } from '../typings' + +interface Wallet { + stationAddress: string, + destinationFilAddress: string | undefined, + walletBalance: number, + walletTransactions: FILTransaction[] | [], + editDestinationAddress: (address: string|undefined) => void, + currentTransaction: FILTransaction | undefined, + dismissCurrentTransaction: () => void +} + +const useWallet = (): Wallet => { + const [stationAddress, setStationAddress] = useState('') + const [destinationFilAddress, setDestinationFilAddress] = useState() + const [walletBalance, setWalletBalance] = useState(0) + const [walletTransactions, setWalletTransactions] = useState([]) + const [currentTransaction, setCurrentTransaction] = useState() + + const editDestinationAddress = async (address: string | undefined) => { + await setDestinationWalletAddress(address) + setDestinationFilAddress(address) + } + + const dismissCurrentTransaction = () => { + if (currentTransaction && currentTransaction.status !== 'processing') { + setWalletTransactions([currentTransaction, ...walletTransactions]) + setCurrentTransaction(undefined) + } + } + + useEffect(() => { + const loadStoredInfo = async () => { + setDestinationFilAddress(await getDestinationWalletAddress()) + } + loadStoredInfo() + }, [destinationFilAddress]) + + useEffect(() => { + const loadStoredInfo = async () => { + setStationAddress(await getStationWalletAddress()) + } + loadStoredInfo() + }, [stationAddress]) + + useEffect(() => { + const loadStoredInfo = async () => { + setWalletBalance(await getStationWalletBalance()) + } + loadStoredInfo() + }, []) + + useEffect(() => { + const loadStoredInfo = async () => { + setWalletTransactions(await getStationWalletTransactionsHistory()) + } + loadStoredInfo() + }, []) + + useEffect(() => { + const updateWalletTransactionsArray = (transactions: FILTransaction[]) => { + const newCurrentTransaction = transactions[0] + if (newCurrentTransaction.status === 'processing' || (currentTransaction && +currentTransaction.timestamp === +newCurrentTransaction.timestamp)) { + setCurrentTransaction(newCurrentTransaction) + if (newCurrentTransaction.status !== 'processing') { setTimeout(() => { setWalletTransactions(transactions); setCurrentTransaction(undefined) }, 6000) } + + const transactionsExceptLatest = transactions.filter((t) => { return t !== newCurrentTransaction }) + setWalletTransactions(transactionsExceptLatest) + } else { + setWalletTransactions(transactions) + } + } + + const unsubscribeOnTransactionUpdate = window.electron.stationEvents.onTransactionUpdate(updateWalletTransactionsArray) + return () => { + unsubscribeOnTransactionUpdate() + } + }, [currentTransaction]) + + useEffect(() => { + const unsubscribeOnBalanceUpdate = window.electron.stationEvents.onBalanceUpdate(setWalletBalance) + return () => { + unsubscribeOnBalanceUpdate() + } + }, [walletBalance]) + + return { stationAddress, destinationFilAddress, walletBalance, walletTransactions, editDestinationAddress, currentTransaction, dismissCurrentTransaction } +} + +export default useWallet diff --git a/renderer/src/lib/station-config.tsx b/renderer/src/lib/station-config.tsx index f4bedc7c6..04db50e65 100644 --- a/renderer/src/lib/station-config.tsx +++ b/renderer/src/lib/station-config.tsx @@ -1,4 +1,4 @@ -import { ActivityEventMessage } from '../typings' +import { ActivityEventMessage, FILTransaction } from '../typings' export async function getOnboardingCompleted (): Promise { return await window.electron.stationConfig.getOnboardingCompleted() @@ -8,18 +8,6 @@ export async function setOnboardingCompleted (): Promise { return await window.electron.stationConfig.setOnboardingCompleted() } -export async function getFilAddress (): Promise { - return await window.electron.stationConfig.getFilAddress() -} - -export async function setFilAddress (address: string | undefined): Promise { - return await window.electron.stationConfig.setFilAddress(address) -} - -export async function setStationFilAddress (address: string | undefined): Promise { - return await window.electron.stationConfig.setFilAddress(address) -} - export async function isSaturnNodeRunning (): Promise { return await window.electron.saturnNode.isRunning() } @@ -59,3 +47,32 @@ export async function restartToUpdate (): Promise { export function openReleaseNotes (): void { return window.electron.openReleaseNotes() } + +export async function getDestinationWalletAddress (): Promise { + return await window.electron.stationConfig.getDestinationWalletAddress() +} + +export async function setDestinationWalletAddress (address: string | undefined): Promise { + return await window.electron.saturnNode.setFilAddress(address) + // return await window.electron.stationConfig.setDestinationWalletAddress(address) +} + +export async function getStationWalletAddress (): Promise { + return await window.electron.stationConfig.getStationWalletAddress() +} + +export async function getStationWalletBalance (): Promise { + return await window.electron.stationConfig.getStationWalletBalance() +} + +export async function getStationWalletTransactionsHistory (): Promise { + return await window.electron.stationConfig.getStationWalletTransactionsHistory() +} + +export async function transferAllFundsToDestinationWallet (): Promise { + return await window.electron.stationConfig.transferAllFundsToDestinationWallet() +} + +export function brownseTransactionTracker (transactionHash: string): void { + return window.electron.stationConfig.browseTransactionTracker(transactionHash) +} diff --git a/renderer/src/pages/Dashboard.tsx b/renderer/src/pages/Dashboard.tsx index 2e5f97901..8ef352fb6 100644 --- a/renderer/src/pages/Dashboard.tsx +++ b/renderer/src/pages/Dashboard.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from 'react' -import { stopSaturnNode, setFilAddress, getFilAddress } from '../lib/station-config' +import { stopSaturnNode, setDestinationWalletAddress, getDestinationWalletAddress } from '../lib/station-config' import ActivityLog from '../components/ActivityLog' import HeaderBackgroundImage from '../assets/img/header.png' import WalletIcon from '../assets/img/wallet.svg' @@ -18,14 +18,14 @@ const Dashboard = (): JSX.Element => { const disconnect = async () => { if (!(await confirmChangeWalletAddress())) return await stopSaturnNode() - await setFilAddress('') + await setDestinationWalletAddress('') setAddress(undefined) navigate('/wallet', { replace: true }) } useEffect(() => { const loadStoredInfo = async () => { - setAddress(await getFilAddress()) + setAddress(await getDestinationWalletAddress()) } loadStoredInfo() }, []) diff --git a/renderer/src/pages/Onboarding.tsx b/renderer/src/pages/Onboarding.tsx index cc94ace58..9c40fcef9 100644 --- a/renderer/src/pages/Onboarding.tsx +++ b/renderer/src/pages/Onboarding.tsx @@ -1,6 +1,6 @@ import { useState, useEffect, useCallback } from 'react' import { useNavigate } from 'react-router-dom' -import { getFilAddress, getOnboardingCompleted, setOnboardingCompleted } from '../lib/station-config' +import { getOnboardingCompleted, setOnboardingCompleted } from '../lib/station-config' import Onboarding from '../components/Onboarding' import { ReactComponent as StationLogoLight } from '../assets/img/station-logo-light.svg' @@ -24,9 +24,6 @@ const OnboardingPage = (): JSX.Element => { useEffect(() => { (async () => { await sleep(2000) - if (await getFilAddress()) { - return navigate('/dashboard', { replace: true }) - } setIsOnboardingCompleted(await getOnboardingCompleted()) setIsLoading(false) })() diff --git a/renderer/src/pages/WalletConfig.tsx b/renderer/src/pages/WalletConfig.tsx index 88fa32a65..4565bf020 100644 --- a/renderer/src/pages/WalletConfig.tsx +++ b/renderer/src/pages/WalletConfig.tsx @@ -2,7 +2,7 @@ import { useCallback } from 'react' import FilAddressForm from '../components/FilAddressForm' import BackgroundGraph from './../assets/img/graph.svg' import { useNavigate } from 'react-router-dom' -import { startSaturnNode, setFilAddress as saveFilAddress } from '../lib/station-config' +import { startSaturnNode, setDestinationWalletAddress as saveFilAddress } from '../lib/station-config' import UpdateBanner from '../components/UpdateBanner' const WalletConfig = (): JSX.Element => { diff --git a/renderer/src/test/dashboard.test.tsx b/renderer/src/test/dashboard.test.tsx index f8d04c9b0..4b9e72316 100644 --- a/renderer/src/test/dashboard.test.tsx +++ b/renderer/src/test/dashboard.test.tsx @@ -19,8 +19,8 @@ describe('Dashboard page', () => { vi.restoreAllMocks() vi.mock('../lib/station-config', () => { return { - getFilAddress: () => Promise.resolve('f16m5slrkc6zumruuhdzn557a5sdkbkiellron4qa'), - setFilAddress: (address: string | undefined) => Promise.resolve(undefined), + getDestinationWalletAddress: () => Promise.resolve('f16m5slrkc6zumruuhdzn557a5sdkbkiellron4qa'), + setDestinationWalletAddress: (address: string | undefined) => Promise.resolve(undefined), getTotalJobsCompleted: () => Promise.resolve(0), getTotalEarnings: () => Promise.resolve(0), startSaturnNode: () => Promise.resolve(undefined), @@ -121,8 +121,8 @@ describe('Dashboard page', () => { vi.restoreAllMocks() vi.mock('../lib/station-config', () => { return { - getFilAddress: () => Promise.resolve('f16m5slrkc6zumruuhdzn557a5sdkbkiellron4qa'), - setFilAddress: (address: string | undefined) => Promise.resolve(undefined), + getDestinationWalletAddress: () => Promise.resolve('f16m5slrkc6zumruuhdzn557a5sdkbkiellron4qa'), + setDestinationWalletAddress: (address: string | undefined) => Promise.resolve(undefined), getTotalJobsCompleted: () => Promise.resolve(100), getTotalEarnings: () => Promise.resolve(100), startSaturnNode: () => Promise.resolve(undefined), diff --git a/renderer/src/test/onboarding.test.tsx b/renderer/src/test/onboarding.test.tsx index 5c270d8e4..f17377791 100644 --- a/renderer/src/test/onboarding.test.tsx +++ b/renderer/src/test/onboarding.test.tsx @@ -15,7 +15,7 @@ describe('Welcome page test', () => { return { setOnboardingCompleted: () => Promise.resolve(undefined), getOnboardingCompleted: (status: boolean) => Promise.resolve(true), - getFilAddress: () => Promise.resolve(undefined) + getDestinationWalletAddress: () => Promise.resolve('f16m5slrkc6zumruuhdzn557a5sdkbkiellron4qa') } }) @@ -46,7 +46,7 @@ describe('Welcome page test', () => { return { setOnboardingCompleted: () => Promise.resolve(undefined), getOnboardingCompleted: (status: boolean) => Promise.resolve(false), - getFilAddress: () => Promise.resolve(undefined) + getDestinationWalletAddress: () => Promise.resolve(undefined) } }) @@ -100,7 +100,7 @@ describe('Welcome page test', () => { vi.clearAllMocks() vi.mock('../lib/station-config', () => { return { - getFilAddress: () => Promise.resolve('f16m5slrkc6zumruuhdzn557a5sdkbkiellron4qa'), + getDestinationWalletAddress: () => Promise.resolve('f16m5slrkc6zumruuhdzn557a5sdkbkiellron4qa'), setOnboardingCompleted: () => Promise.resolve(undefined), getOnboardingCompleted: (status: boolean) => Promise.resolve(true) } diff --git a/renderer/src/test/walletconfig.test.tsx b/renderer/src/test/walletconfig.test.tsx index a86d2160f..c9930209d 100644 --- a/renderer/src/test/walletconfig.test.tsx +++ b/renderer/src/test/walletconfig.test.tsx @@ -13,8 +13,8 @@ describe('WalletConfig page test', () => { vi.restoreAllMocks() vi.mock('../lib/station-config', () => { return { - getFilAddress: () => Promise.resolve(undefined), - setFilAddress: (address: string | undefined) => Promise.resolve(undefined), + getDestinationWalletAddress: () => Promise.resolve(undefined), + setDestinationWalletAddress: (address: string | undefined) => Promise.resolve(undefined), startSaturnNode: () => Promise.resolve(undefined) } }) diff --git a/renderer/src/typings.d.ts b/renderer/src/typings.d.ts index ae66e113d..fac275606 100644 --- a/renderer/src/typings.d.ts +++ b/renderer/src/typings.d.ts @@ -26,16 +26,23 @@ export declare global { setFilAddress: (address: string | undefined) => Promise }, stationConfig: { - getFilAddress: () => Promise, - setFilAddress: (address: string | undefined) => Promise, getOnboardingCompleted: () => Promise, setOnboardingCompleted: () => Promise + getStationWalletAddress: () => Promise, + getDestinationWalletAddress: () => Promise, + setDestinationWalletAddress: (address: string | undefined) => Promise, + getStationWalletBalance: () => Promise, + getStationWalletTransactionsHistory: () => Promise, + transferAllFundsToDestinationWallet: () => Promise, + browseTransactionTracker: (transactionHash: string) => void }, stationEvents: { - onActivityLogged: (callback) => () => void - onJobProcessed: (callback) => () => void - onEarningsChanged: (callback) => () => void - onUpdateAvailable: (callback: () => void) => () => void + onActivityLogged: (callback) => () => void, + onJobProcessed: (callback) => () => void, + onEarningsChanged: (callback) => () => void, + onUpdateAvailable: (callback: () => void) => () => void, + onTransactionUpdate (callback: (allTransactions: TransactionMessage[]) => void), + onBalanceUpdate (callback: (balance: number) => void) }, dialogs: { confirmChangeWalletAddress: () => Promise @@ -45,9 +52,20 @@ export declare global { } export type ActivityEventMessage = { - id: string; - timestamp: number; - type: string; - source: string; - message: string; + id: string + timestamp: number + type: string + source: string + message: string +} + +export type FILTransactionStatus = 'sent' | 'processing' | 'failed' + +export type FILTransaction = { + hash: string + timestamp: number + status: TransactionStatus + outgoing: boolean + amount: string + address: string }