diff --git a/.changeset/chatty-hats-flash.md b/.changeset/chatty-hats-flash.md
new file mode 100644
index 000000000..ccba8de0e
--- /dev/null
+++ b/.changeset/chatty-hats-flash.md
@@ -0,0 +1,5 @@
+---
+'@siafoundation/design-system': minor
+---
+
+The TransactionDetailsDialog now supports an Event type instead of txType.
diff --git a/.changeset/famous-pears-melt.md b/.changeset/famous-pears-melt.md
new file mode 100644
index 000000000..d37910885
--- /dev/null
+++ b/.changeset/famous-pears-melt.md
@@ -0,0 +1,7 @@
+---
+'@siafoundation/hostd-js': minor
+'@siafoundation/hostd-react': minor
+'@siafoundation/hostd-types': minor
+---
+
+Updated with v2 endpoints and data types. Closes https://github.com/SiaFoundation/hostd/issues/440
diff --git a/.changeset/kind-trains-bathe.md b/.changeset/kind-trains-bathe.md
new file mode 100644
index 000000000..ca2e0d58a
--- /dev/null
+++ b/.changeset/kind-trains-bathe.md
@@ -0,0 +1,9 @@
+---
+'@siafoundation/hostd-js': minor
+'@siafoundation/hostd-react': minor
+'@siafoundation/hostd-types': minor
+'@siafoundation/types': minor
+'@siafoundation/walletd-types': minor
+---
+
+Core Event types have been moved to the core types library. Closes https://github.com/SiaFoundation/hostd/issues/440
diff --git a/.changeset/old-hounds-camp.md b/.changeset/old-hounds-camp.md
new file mode 100644
index 000000000..516bc4c9b
--- /dev/null
+++ b/.changeset/old-hounds-camp.md
@@ -0,0 +1,5 @@
+---
+'hostd': minor
+---
+
+The app has been updated to use the new v2 endpoints and data types. Closes https://github.com/SiaFoundation/hostd/issues/440
diff --git a/.changeset/two-olives-whisper.md b/.changeset/two-olives-whisper.md
new file mode 100644
index 000000000..335c746db
--- /dev/null
+++ b/.changeset/two-olives-whisper.md
@@ -0,0 +1,6 @@
+---
+'walletd': minor
+'@siafoundation/units': minor
+---
+
+Event and transaction utility methods have been moved to the units library.
diff --git a/apps/hostd/components/CmdRoot/WalletCmdGroup.tsx b/apps/hostd/components/CmdRoot/WalletCmdGroup.tsx
index cdf41cd8b..ea3decf25 100644
--- a/apps/hostd/components/CmdRoot/WalletCmdGroup.tsx
+++ b/apps/hostd/components/CmdRoot/WalletCmdGroup.tsx
@@ -3,7 +3,7 @@ import { routes } from '../../config/routes'
import { useRouter } from 'next/router'
import { useDialog } from '../../contexts/dialog'
import { CommandGroup, CommandItemNav, CommandItemSearch } from './Item'
-import { useStateHost } from '@siafoundation/hostd-react'
+import { useWallet } from '@siafoundation/hostd-react'
import { Page } from './types'
const commandPage = {
@@ -20,7 +20,7 @@ type Props = {
export function WalletCmdGroup({ currentPage, parentPage, pushPage }: Props) {
const { openDialog, closeDialog } = useDialog()
const router = useRouter()
- const state = useStateHost({
+ const wallet = useWallet({
config: {
swr: {
revalidateOnFocus: false,
@@ -81,7 +81,7 @@ export function WalletCmdGroup({ currentPage, parentPage, pushPage }: Props) {
currentPage={currentPage}
commandPage={commandPage}
onSelect={() => {
- copyToClipboard(state.data?.walletAddress, 'wallet address')
+ copyToClipboard(wallet.data?.address, 'wallet address')
closeDialog()
}}
>
diff --git a/apps/hostd/components/Config/AnnounceButton.tsx b/apps/hostd/components/Config/AnnounceButton.tsx
index 847eaefdc..1b7db4420 100644
--- a/apps/hostd/components/Config/AnnounceButton.tsx
+++ b/apps/hostd/components/Config/AnnounceButton.tsx
@@ -10,7 +10,7 @@ import { useDialog } from '../../contexts/dialog'
import {
useSettings,
useSettingsAnnounce,
- useStateHost,
+ useHostState,
useTxPoolFee,
} from '@siafoundation/hostd-react'
import { humanSiacoin } from '@siafoundation/units'
@@ -21,7 +21,7 @@ export function AnnounceButton() {
const { openConfirmDialog } = useDialog()
const txpoolFee = useTxPoolFee()
const settingsAnnounce = useSettingsAnnounce()
- const host = useStateHost()
+ const host = useHostState()
const settings = useSettings({
config: {
swr: {
diff --git a/apps/hostd/components/HostdTestnetWarningBanner.tsx b/apps/hostd/components/HostdTestnetWarningBanner.tsx
index 4ea2ae6ea..cf2ab7c51 100644
--- a/apps/hostd/components/HostdTestnetWarningBanner.tsx
+++ b/apps/hostd/components/HostdTestnetWarningBanner.tsx
@@ -1,8 +1,8 @@
import { TestnetWarningBanner } from '@siafoundation/design-system'
-import { useStateHost } from '@siafoundation/hostd-react'
+import { useConsensusNetwork } from '@siafoundation/hostd-react'
export function HostdTestnetWarningBanner() {
- const host = useStateHost({
+ const host = useConsensusNetwork({
config: {
swr: {
revalidateOnFocus: false,
@@ -10,9 +10,9 @@ export function HostdTestnetWarningBanner() {
},
})
- if (!host.data || host.data.network === 'Mainnet') {
+ if (!host.data || host.data.name === 'mainnet') {
return null
}
- return
+ return
}
diff --git a/apps/hostd/components/Profile/index.tsx b/apps/hostd/components/Profile/index.tsx
index 0cc2fe218..643273d68 100644
--- a/apps/hostd/components/Profile/index.tsx
+++ b/apps/hostd/components/Profile/index.tsx
@@ -7,8 +7,10 @@ import {
} from '@siafoundation/design-system'
import {
useSettings,
- useStateHost,
+ useHostState,
useSyncerPeers,
+ useWallet,
+ useConsensusNetwork,
} from '@siafoundation/hostd-react'
import { useSyncStatus } from '../../hooks/useSyncStatus'
import { useDialog } from '../../contexts/dialog'
@@ -17,7 +19,21 @@ import { humanTime } from '@siafoundation/units'
export function Profile() {
const { openDialog } = useDialog()
- const state = useStateHost({
+ const state = useHostState({
+ config: {
+ swr: {
+ revalidateOnFocus: false,
+ },
+ },
+ })
+ const wallet = useWallet({
+ config: {
+ swr: {
+ revalidateOnFocus: false,
+ },
+ },
+ })
+ const network = useConsensusNetwork({
config: {
swr: {
revalidateOnFocus: false,
@@ -94,7 +110,7 @@ export function Profile() {
@@ -114,7 +130,7 @@ export function Profile() {
Network
- {state.data?.network}
+ {network.data?.name}
diff --git a/apps/hostd/components/Wallet/StateError.tsx b/apps/hostd/components/Wallet/StateError.tsx
new file mode 100644
index 000000000..e7e6d84fc
--- /dev/null
+++ b/apps/hostd/components/Wallet/StateError.tsx
@@ -0,0 +1,15 @@
+import { Text } from '@siafoundation/design-system'
+import { MisuseOutline32 } from '@siafoundation/react-icons'
+
+export function StateError() {
+ return (
+
+
+
+
+
+ Error fetching transactions.
+
+
+ )
+}
diff --git a/apps/hostd/components/Wallet/StateNoneMatching.tsx b/apps/hostd/components/Wallet/StateNoneMatching.tsx
new file mode 100644
index 000000000..db7256e7d
--- /dev/null
+++ b/apps/hostd/components/Wallet/StateNoneMatching.tsx
@@ -0,0 +1,15 @@
+import { Text } from '@siafoundation/design-system'
+import { Filter32 } from '@siafoundation/react-icons'
+
+export function StateNoneMatching() {
+ return (
+
+
+
+
+
+ No transactions matching filters.
+
+
+ )
+}
diff --git a/apps/hostd/components/Wallet/StateNoneYet.tsx b/apps/hostd/components/Wallet/StateNoneYet.tsx
new file mode 100644
index 000000000..3608574d9
--- /dev/null
+++ b/apps/hostd/components/Wallet/StateNoneYet.tsx
@@ -0,0 +1,15 @@
+import { Text } from '@siafoundation/design-system'
+import { Money32 } from '@siafoundation/react-icons'
+
+export function StateNoneYet() {
+ return (
+
+
+
+
+
+ The wallet has no transactions yet.
+
+
+ )
+}
diff --git a/apps/hostd/components/Wallet/index.tsx b/apps/hostd/components/Wallet/index.tsx
index 63e5cea4d..03a1cd0bb 100644
--- a/apps/hostd/components/Wallet/index.tsx
+++ b/apps/hostd/components/Wallet/index.tsx
@@ -1,8 +1,7 @@
import {
- EntityList,
WalletLayoutActions,
BalanceEvolution,
- PaginatorUnknownTotal,
+ Table,
} from '@siafoundation/design-system'
import { useWallet } from '@siafoundation/hostd-react'
import { useDialog } from '../../contexts/dialog'
@@ -11,9 +10,11 @@ import BigNumber from 'bignumber.js'
import { HostdSidenav } from '../HostdSidenav'
import { HostdAuthedLayout } from '../HostdAuthedLayout'
import { useSyncStatus } from '../../hooks/useSyncStatus'
-import { EmptyState } from './EmptyState'
import { useTransactions } from '../../contexts/transactions'
import { WalletFilterBar } from './WalletFilterBar'
+import { StateNoneMatching } from './StateNoneMatching'
+import { StateNoneYet } from './StateNoneYet'
+import { StateError } from './StateError'
export function Wallet() {
const { openDialog } = useDialog()
@@ -21,8 +22,18 @@ export function Wallet() {
const { isSynced, isWalletSynced, syncPercent, walletScanPercent } =
useSyncStatus()
- const { dataset, balances, metrics, offset, limit, dataState, pageCount } =
- useTransactions()
+ const {
+ balances,
+ metrics,
+ dataset,
+ dataState,
+ columns,
+ cellContext,
+ sortableColumns,
+ sortDirection,
+ sortField,
+ toggleSort,
+ } = useTransactions()
return (
}
>
-
+
{balances?.length && balances.find((b) => b.sc) ? (
) : null}
-
}
- actions={
-
+ emptyState={
+ dataState === 'noneMatchingFilters' ? (
+
+ ) : dataState === 'noneYet' ? (
+
+ ) : dataState === 'error' ? (
+
+ ) : null
}
+ pageSize={6}
+ data={dataset}
+ context={cellContext}
+ columns={columns}
+ sortableColumns={sortableColumns}
+ sortDirection={sortDirection}
+ sortField={sortField}
+ toggleSort={toggleSort}
/>
diff --git a/apps/hostd/config/routes.ts b/apps/hostd/config/routes.ts
index e24d5eeb9..21b329a71 100644
--- a/apps/hostd/config/routes.ts
+++ b/apps/hostd/config/routes.ts
@@ -1,4 +1,4 @@
-import { stateHostRoute } from '@siafoundation/hostd-types'
+import { hostStateRoute } from '@siafoundation/hostd-types'
export const routes = {
home: '/',
@@ -28,4 +28,4 @@ export const routes = {
login: '/login',
}
-export const connectivityRoute = stateHostRoute
+export const connectivityRoute = hostStateRoute
diff --git a/apps/hostd/contexts/config/index.tsx b/apps/hostd/contexts/config/index.tsx
index bb5aebf05..db297921e 100644
--- a/apps/hostd/contexts/config/index.tsx
+++ b/apps/hostd/contexts/config/index.tsx
@@ -17,7 +17,7 @@ import {
checkIfAnyResourcesErrored,
} from './resources'
import { useOnValid } from './useOnValid'
-import { useStateHost } from '@siafoundation/hostd-react'
+import { useHostState } from '@siafoundation/hostd-react'
export function useConfigMain() {
const { settings, settingsPinned, dynDNSCheck } = useResources()
@@ -54,7 +54,7 @@ export function useConfigMain() {
[resources]
)
- const state = useStateHost()
+ const state = useHostState()
const pinningEnabled = state.data?.explorer.enabled
const revalidateAndResetForm = useCallback(async () => {
const _settings = await settings.mutate()
diff --git a/apps/hostd/contexts/config/useForm.tsx b/apps/hostd/contexts/config/useForm.tsx
index 34454f476..36dd80139 100644
--- a/apps/hostd/contexts/config/useForm.tsx
+++ b/apps/hostd/contexts/config/useForm.tsx
@@ -4,7 +4,7 @@ import { useEffect, useMemo, useRef } from 'react'
import { getFields } from './fields'
import useLocalStorageState from 'use-local-storage-state'
import { useSiaCentralExchangeRates } from '@siafoundation/sia-central-react'
-import { useStateHost } from '@siafoundation/hostd-react'
+import { useHostState } from '@siafoundation/hostd-react'
import { useAutoCalculatedFields } from './useAutoCalculatedFields'
export function useForm() {
@@ -25,7 +25,7 @@ export function useForm() {
})
const rates = useSiaCentralExchangeRates()
- const state = useStateHost()
+ const state = useHostState()
const pinningEnabled = state.data?.explorer.enabled
// Field validation is only re-applied on re-mount,
// so we pass a ref with latest data that can be used interally.
diff --git a/apps/hostd/contexts/config/useOnValid.tsx b/apps/hostd/contexts/config/useOnValid.tsx
index 6250f8e29..e7fbf9360 100644
--- a/apps/hostd/contexts/config/useOnValid.tsx
+++ b/apps/hostd/contexts/config/useOnValid.tsx
@@ -8,9 +8,9 @@ import { SettingsData } from './types'
import { transformUpSettings, transformUpSettingsPinned } from './transform'
import { Resources } from './resources'
import {
+ useHostState,
useSettingsPinnedUpdate,
useSettingsUpdate,
- useStateHost,
} from '@siafoundation/hostd-react'
export function useOnValid({
@@ -20,16 +20,15 @@ export function useOnValid({
resources: Resources
revalidateAndResetForm: () => Promise
}) {
- const state = useStateHost()
- const settingsUpdate = useSettingsUpdate()
- const settingsPinnedUpdate = useSettingsPinnedUpdate()
- const host = useStateHost({
+ const state = useHostState({
config: {
swr: {
refreshInterval: minutesInMilliseconds(1),
},
},
})
+ const settingsUpdate = useSettingsUpdate()
+ const settingsPinnedUpdate = useSettingsPinnedUpdate()
const onValid = useCallback(
async (values: SettingsData) => {
if (!resources) {
@@ -60,7 +59,7 @@ export function useOnValid({
}
const needsToAnnounce =
- host.data?.lastAnnouncement?.address !== values.netAddress
+ state.data?.lastAnnouncement?.address !== values.netAddress
if (needsToAnnounce) {
triggerSuccessToast({
title: 'Settings have been saved',
@@ -86,7 +85,6 @@ export function useOnValid({
settingsUpdate,
settingsPinnedUpdate,
revalidateAndResetForm,
- host.data,
state.data,
]
)
diff --git a/apps/hostd/contexts/transactions/columns.tsx b/apps/hostd/contexts/transactions/columns.tsx
new file mode 100644
index 000000000..a747ae2b8
--- /dev/null
+++ b/apps/hostd/contexts/transactions/columns.tsx
@@ -0,0 +1,182 @@
+import {
+ Text,
+ TableColumn,
+ ValueCopyable,
+ LoadingDots,
+ ValueScFiat,
+ ValueSf,
+ Tooltip,
+ Badge,
+} from '@siafoundation/design-system'
+import { humanDate, getEventLabel } from '@siafoundation/units'
+import { CellContext, EventData, TableColumnId } from './types'
+import { Locked16, Unlocked16 } from '@siafoundation/react-icons'
+
+type EventsTableColumn = TableColumn & {
+ fixed?: boolean
+ category?: string
+}
+
+export const columns: EventsTableColumn[] = [
+ // {
+ // id: 'actions',
+ // label: '',
+ // fixed: true,
+ // cellClassName: 'w-[50px] !pl-2 !pr-4 [&+*]:!pl-0',
+ // render: ({ data: { name } }) => null,
+ // },
+ {
+ id: 'transactionId',
+ label: 'transaction ID',
+ category: 'general',
+ render: ({ data: { id }, context }) => {
+ if (!id) {
+ return null
+ }
+ return (
+
+ )
+ },
+ },
+ {
+ id: 'type',
+ label: 'type',
+ category: 'general',
+ fixed: true,
+ render: ({ data: { type } }) => {
+ return {getEventLabel(type)}
+ },
+ },
+ {
+ id: 'height',
+ label: 'height',
+ category: 'general',
+ contentClassName: 'justify-end',
+ render: ({ data: { height, pending, maturityHeight, isMature } }) => {
+ if (pending) {
+ return (
+
+
+
+ )
+ }
+ if (!height) {
+ return null
+ }
+ if (height && maturityHeight && maturityHeight > height) {
+ return (
+
+
+
+
+ {isMature ? : }
+ {maturityHeight.toLocaleString()}
+
+
+
+
+
+ {height.toLocaleString()}
+
+
+
+
+ )
+ }
+ return (
+
+ {height.toLocaleString()}
+
+ )
+ },
+ },
+ {
+ id: 'timestamp',
+ label: 'timestamp',
+ category: 'general',
+ contentClassName: 'justify-end',
+ render: ({ data: { timestamp, pending } }) => {
+ if (pending) {
+ return (
+
+
+
+ )
+ }
+ return (
+
+ {humanDate(timestamp, { timeStyle: 'short' })}
+
+ )
+ },
+ },
+ {
+ id: 'amount',
+ label: 'amount',
+ category: 'general',
+ contentClassName: 'w-[120px] justify-end',
+ render: ({ data: { amountSc, amountSf } }) => {
+ if (!amountSc) {
+ return null
+ }
+ return (
+
+ {!amountSc.isZero() && (
+
+ )}
+ {!!amountSf && }
+
+ )
+ },
+ },
+ {
+ id: 'fee',
+ label: 'fee',
+ category: 'general',
+ contentClassName: 'w-[120px] justify-end',
+ render: ({ data: { fee } }) => {
+ if (!fee) {
+ return null
+ }
+ return
+ },
+ },
+ {
+ id: 'contractId',
+ label: 'contract ID',
+ category: 'general',
+ render: ({ data: { contractId }, context }) => {
+ if (!contractId) {
+ return null
+ }
+ return (
+
+ )
+ },
+ },
+]
diff --git a/apps/hostd/contexts/transactions/index.tsx b/apps/hostd/contexts/transactions/index.tsx
index 6e17e556b..77bc88d94 100644
--- a/apps/hostd/contexts/transactions/index.tsx
+++ b/apps/hostd/contexts/transactions/index.tsx
@@ -1,24 +1,37 @@
import {
TxType,
daysInMilliseconds,
- getTransactionType,
useDatasetEmptyState,
+ useServerFilters,
+ useTableState,
} from '@siafoundation/design-system'
import {
useMetricsPeriod,
+ useWalletEvents,
useWalletPending,
- useWalletTransactions,
} from '@siafoundation/hostd-react'
import { createContext, useContext, useMemo } from 'react'
-import { useDialog } from '../dialog'
import BigNumber from 'bignumber.js'
import { useRouter } from 'next/router'
import { useSiascanUrl } from '../../hooks/useSiascanUrl'
import { Transaction } from '@siafoundation/types'
import { defaultDatasetRefreshInterval } from '../../config/swr'
+import { useSyncStatus } from '../../hooks/useSyncStatus'
+import { columns } from './columns'
+import {
+ calculateScValue,
+ getEventContractId,
+ getEventFee,
+} from '@siafoundation/units'
+import {
+ CellContext,
+ EventData,
+ columnsDefaultVisible,
+ defaultSortField,
+ sortOptions,
+} from './types'
const defaultLimit = 50
-const filters = []
export type TransactionData = {
id: string
@@ -39,7 +52,7 @@ function useTransactionsMain() {
const router = useRouter()
const limit = Number(router.query.limit || defaultLimit)
const offset = Number(router.query.offset || 0)
- const transactions = useWalletTransactions({
+ const events = useWalletEvents({
params: {
limit,
offset,
@@ -58,52 +71,90 @@ function useTransactionsMain() {
},
})
- const { openDialog } = useDialog()
- const siascanUrl = useSiascanUrl()
+ const { filters, setFilter, removeFilter, removeLastFilter, resetFilters } =
+ useServerFilters()
- const dataset: TransactionData[] | null = useMemo(() => {
- if (!pending.data || !transactions.data) {
+ const syncStatus = useSyncStatus()
+ const dataset = useMemo(() => {
+ if (!events.data || !pending.data) {
return null
}
- return [
- ...(pending.data || []).map((t): TransactionData => {
- const notRealTxn = t.source !== 'transaction'
- return {
- id: t.id,
- type: 'transaction',
- unconfirmed: true,
- txType: getTransactionType(t.transaction, t.source),
- hash: t.id,
- inflow: t.inflow,
- outflow: t.outflow,
- sc: new BigNumber(t.inflow).minus(t.outflow),
- siascanUrl: notRealTxn ? undefined : siascanUrl,
- timestamp: new Date(t.timestamp).getTime(),
- onClick: () => openDialog('transactionDetails', t.id),
- raw: t.transaction,
- }
- }),
- ...(transactions.data || [])
- .map((t): TransactionData => {
- const notRealTxn = t.source !== 'transaction'
- return {
- id: t.id,
- type: 'transaction',
- unconfirmed: false,
- txType: getTransactionType(t.transaction, t.source),
- hash: t.id,
- inflow: t.inflow,
- outflow: t.outflow,
- sc: new BigNumber(t.inflow).minus(t.outflow),
- siascanUrl: notRealTxn ? undefined : siascanUrl,
- timestamp: new Date(t.timestamp).getTime(),
- onClick: () => openDialog('transactionDetails', t.id),
- raw: t.transaction,
- }
- })
- .sort((a, b) => (a.timestamp < b.timestamp ? 1 : -1)),
- ]
- }, [pending, transactions, openDialog, siascanUrl])
+ const dataPending: EventData[] = pending.data.map((e) => {
+ const amountSc = calculateScValue(e)
+ const fee = getEventFee(e)
+ const event: EventData = {
+ id: e.id,
+ timestamp: 0,
+ pending: true,
+ type: e.type,
+ isMature: false,
+ amountSc,
+ fee,
+ }
+ return event
+ })
+ const dataEvents: EventData[] = events.data.map((e) => {
+ const amountSc = calculateScValue(e)
+ const fee = getEventFee(e)
+ const contractId = getEventContractId(e)
+ const isMature = e.maturityHeight <= syncStatus.nodeBlockHeight
+ const res: EventData = {
+ id: e.id,
+ type: e.type,
+ timestamp: new Date(e.timestamp).getTime(),
+ maturityHeight: e.maturityHeight,
+ isMature,
+ height: e.index.height,
+ pending: false,
+ amountSc,
+ fee,
+ contractId,
+ }
+ return res
+ })
+ return [...dataPending.reverse(), ...dataEvents]
+ }, [events.data, pending.data, syncStatus.nodeBlockHeight])
+
+ const {
+ configurableColumns,
+ enabledColumns,
+ sortableColumns,
+ toggleColumnVisibility,
+ setColumnsVisible,
+ setColumnsHidden,
+ toggleSort,
+ setSortDirection,
+ setSortField,
+ sortField,
+ sortDirection,
+ resetDefaultColumnVisibility,
+ } = useTableState('walletd/v0/events', {
+ columns,
+ columnsDefaultVisible,
+ sortOptions,
+ defaultSortField,
+ })
+
+ const filteredTableColumns = useMemo(
+ () =>
+ columns.filter(
+ (column) => column.fixed || enabledColumns.includes(column.id)
+ ),
+ [enabledColumns]
+ )
+
+ const isValidating = events.isValidating || pending.isValidating
+ const error = events.error || pending.error
+
+ const dataState = useDatasetEmptyState(dataset, isValidating, error, filters)
+
+ const siascanUrl = useSiascanUrl()
+ const cellContext = useMemo(
+ () => ({
+ siascanUrl,
+ }),
+ [siascanUrl]
+ )
const dayPeriods = 30
const start = useMemo(() => {
@@ -132,14 +183,6 @@ function useTransactionsMain() {
[metrics.data]
)
- const error = transactions.error
- const dataState = useDatasetEmptyState(
- dataset,
- transactions.isValidating,
- error,
- filters
- )
-
return {
balances,
metrics,
@@ -149,6 +192,26 @@ function useTransactionsMain() {
offset,
limit,
pageCount: dataset?.length || 0,
+ cellContext,
+ configurableColumns,
+ enabledColumns,
+ sortableColumns,
+ toggleColumnVisibility,
+ setColumnsVisible,
+ setColumnsHidden,
+ toggleSort,
+ setSortDirection,
+ setSortField,
+ sortField,
+ sortDirection,
+ resetDefaultColumnVisibility,
+ filters,
+ setFilter,
+ removeFilter,
+ removeLastFilter,
+ resetFilters,
+ filteredTableColumns,
+ columns,
}
}
diff --git a/apps/hostd/contexts/transactions/types.ts b/apps/hostd/contexts/transactions/types.ts
new file mode 100644
index 000000000..08492fad0
--- /dev/null
+++ b/apps/hostd/contexts/transactions/types.ts
@@ -0,0 +1,52 @@
+import { WalletEventType } from '@siafoundation/types'
+import BigNumber from 'bignumber.js'
+
+export type CellContext = {
+ siascanUrl: string
+}
+
+export type EventData = {
+ id: string
+ transactionId?: string
+ timestamp: number
+ height?: number
+ maturityHeight?: number
+ isMature?: boolean
+ pending: boolean
+ type: WalletEventType
+ fee?: BigNumber
+ amountSc?: BigNumber
+ amountSf?: number
+ contractId?: string
+ className?: string
+}
+
+export type TableColumnId =
+ // | 'actions'
+ | 'transactionId'
+ | 'type'
+ | 'height'
+ | 'timestamp'
+ | 'amount'
+ | 'fee'
+ | 'transactionId'
+ | 'contractId'
+
+export const columnsDefaultVisible: TableColumnId[] = [
+ 'transactionId',
+ 'type',
+ 'height',
+ 'timestamp',
+ 'amount',
+ 'fee',
+]
+
+export type SortField = 'id'
+
+export const defaultSortField: SortField = 'id'
+
+export const sortOptions: {
+ id: SortField
+ label: string
+ category: string
+}[] = []
diff --git a/apps/hostd/hooks/useHostOSPathSeparator.ts b/apps/hostd/hooks/useHostOSPathSeparator.ts
index 89e69acbc..ed5de51ae 100644
--- a/apps/hostd/hooks/useHostOSPathSeparator.ts
+++ b/apps/hostd/hooks/useHostOSPathSeparator.ts
@@ -1,7 +1,7 @@
-import { useStateHost } from '@siafoundation/hostd-react'
+import { useHostState } from '@siafoundation/hostd-react'
export function useHostOSPathSeparator() {
- const state = useStateHost({
+ const state = useHostState({
config: {
swr: {
revalidateOnFocus: false,
diff --git a/apps/hostd/hooks/useSiascanUrl.ts b/apps/hostd/hooks/useSiascanUrl.ts
index 92ce44e0c..059255883 100644
--- a/apps/hostd/hooks/useSiascanUrl.ts
+++ b/apps/hostd/hooks/useSiascanUrl.ts
@@ -1,9 +1,9 @@
import { webLinks } from '@siafoundation/design-system'
-import { useStateHost } from '@siafoundation/hostd-react'
+import { useConsensusNetwork } from '@siafoundation/hostd-react'
export function useSiascanUrl() {
- const state = useStateHost()
- return state.data?.network === 'Zen Testnet'
+ const state = useConsensusNetwork()
+ return state.data?.name === 'zen'
? webLinks.explore.testnetZen
: webLinks.explore.mainnet
}
diff --git a/apps/hostd/hooks/useSyncStatus.ts b/apps/hostd/hooks/useSyncStatus.ts
index 8b18be4d6..e576cf0f9 100644
--- a/apps/hostd/hooks/useSyncStatus.ts
+++ b/apps/hostd/hooks/useSyncStatus.ts
@@ -1,26 +1,29 @@
import { useAppSettings } from '@siafoundation/react-core'
import {
useEstimatedNetworkBlockHeight,
- useStateConsensus,
- useWallet,
+ useConsensusTipState,
+ useIndexTip,
} from '@siafoundation/hostd-react'
+import { hoursInMilliseconds } from '@siafoundation/design-system'
export function useSyncStatus() {
const { isUnlockedAndAuthedRoute } = useAppSettings()
- const state = useStateConsensus({
+
+ const state = useConsensusTipState({
config: {
swr: {
- refreshInterval: (data) => (data?.synced ? 60_000 : 10_000),
+ refreshInterval: (data) => (getIsSynced(data) ? 60_000 : 10_000),
},
},
})
+ const isSynced = getIsSynced(state.data)
const estimatedBlockHeight = useEstimatedNetworkBlockHeight()
- const nodeBlockHeight = state.data ? state.data?.chainIndex.height : 0
- const wallet = useWallet({
+ const nodeBlockHeight = state.data ? state.data?.index.height : 0
+ const scan = useIndexTip({
config: {
swr: {
refreshInterval: (data) =>
- data?.scanHeight >= nodeBlockHeight ? 60_000 : 10_000,
+ data?.height >= nodeBlockHeight ? 60_000 : 10_000,
},
},
})
@@ -33,11 +36,11 @@ export function useSyncStatus() {
: 0
const walletScanPercent =
- isUnlockedAndAuthedRoute && nodeBlockHeight && wallet.data
+ isUnlockedAndAuthedRoute && nodeBlockHeight && scan.data
? Number(
- (
- Math.min(wallet.data.scanHeight / estimatedBlockHeight, 1) * 100
- ).toFixed(1)
+ (Math.min(scan.data.height / estimatedBlockHeight, 1) * 100).toFixed(
+ 1
+ )
)
: 0
@@ -52,9 +55,8 @@ export function useSyncStatus() {
: false
return {
- isSynced: state.data?.synced,
- isWalletSynced:
- state.data?.synced && wallet.data?.scanHeight >= nodeBlockHeight - 1,
+ isSynced,
+ isWalletSynced: isSynced && scan.data?.height >= nodeBlockHeight - 1,
nodeBlockHeight,
estimatedBlockHeight,
syncPercent,
@@ -63,3 +65,11 @@ export function useSyncStatus() {
firstTimeSyncing,
}
}
+
+function getIsSynced(data?: { prevTimestamps: string[] }) {
+ // Last block is greater than 12 hours ago
+ return data?.prevTimestamps[0]
+ ? new Date(data?.prevTimestamps[0]).getTime() >
+ Date.now() - hoursInMilliseconds(12)
+ : false
+}
diff --git a/apps/renterd/dialogs/RenterdTransactionDetailsDialog.tsx b/apps/renterd/dialogs/RenterdTransactionDetailsDialog.tsx
index 917887560..4fe6ae20f 100644
--- a/apps/renterd/dialogs/RenterdTransactionDetailsDialog.tsx
+++ b/apps/renterd/dialogs/RenterdTransactionDetailsDialog.tsx
@@ -1,10 +1,8 @@
import { useMemo } from 'react'
import { TransactionDetailsDialog } from '@siafoundation/design-system'
import { useDialog } from '../contexts/dialog'
-import {
- TransactionDataConfirmed,
- useTransactions,
-} from '../contexts/transactions'
+import { useTransactions } from '../contexts/transactions'
+import { omit } from '@technically/lodash'
export function RenterdTransactionDetailsDialog() {
const { id, dialog, onOpenChange } = useDialog()
@@ -12,13 +10,18 @@ export function RenterdTransactionDetailsDialog() {
// TODO: add transaction endpoint
const { dataset } = useTransactions()
const transaction = useMemo(() => {
- return dataset?.find((t) => t['hash'] === id)
+ const txn = dataset?.find((t) => t['hash'] === id)
+ if (!txn) {
+ return null
+ }
+ // The incoming type is not a WalletEventType
+ return omit(txn, 'type')
}, [dataset, id])
return (
diff --git a/apps/walletd/contexts/events/columns.tsx b/apps/walletd/contexts/events/columns.tsx
index 179231228..5ab7f9d9b 100644
--- a/apps/walletd/contexts/events/columns.tsx
+++ b/apps/walletd/contexts/events/columns.tsx
@@ -8,10 +8,9 @@ import {
Tooltip,
Badge,
} from '@siafoundation/design-system'
-import { humanDate } from '@siafoundation/units'
+import { getEventLabel, humanDate } from '@siafoundation/units'
import { CellContext, EventData, TableColumnId } from './types'
import { Locked16, Unlocked16 } from '@siafoundation/react-icons'
-import { eventTypeToLabel } from './utils'
type EventsTableColumn = TableColumn & {
fixed?: boolean
@@ -51,7 +50,7 @@ export const columns: EventsTableColumn[] = [
category: 'general',
fixed: true,
render: ({ data: { type } }) => {
- return {eventTypeToLabel(type)}
+ return {getEventLabel(type)}
},
},
{
diff --git a/apps/walletd/contexts/events/index.tsx b/apps/walletd/contexts/events/index.tsx
index fb36de4ac..cb5499027 100644
--- a/apps/walletd/contexts/events/index.tsx
+++ b/apps/walletd/contexts/events/index.tsx
@@ -7,6 +7,12 @@ import {
useWalletEvents,
useWalletEventsUnconfirmed,
} from '@siafoundation/walletd-react'
+import {
+ calculateScValue,
+ calculateSfValue,
+ getEventContractId,
+ getEventFee,
+} from '@siafoundation/units'
import { createContext, useContext, useMemo } from 'react'
import {
CellContext,
@@ -20,8 +26,6 @@ import { useRouter } from 'next/router'
import { useSiascanUrl } from '../../hooks/useSiascanUrl'
import { defaultDatasetRefreshInterval } from '../../config/swr'
import { useSyncStatus } from '../../hooks/useSyncStatus'
-import { getContractId, getFee } from './utils'
-import { calculateScValue, calculateSfValue } from './transactionValue'
const defaultLimit = 100
@@ -65,7 +69,7 @@ export function useEventsMain() {
const dataTxPool: EventData[] = responseTxPool.data.map((e) => {
const amountSc = calculateScValue(e)
const amountSf = calculateSfValue(e)
- const fee = getFee(e)
+ const fee = getEventFee(e)
const event: EventData = {
id: e.id,
timestamp: 0,
@@ -81,8 +85,8 @@ export function useEventsMain() {
const dataEvents: EventData[] = responseEvents.data.map((e) => {
const amountSc = calculateScValue(e)
const amountSf = calculateSfValue(e)
- const fee = getFee(e)
- const contractId = getContractId(e)
+ const fee = getEventFee(e)
+ const contractId = getEventContractId(e)
const isMature = e.maturityHeight <= syncStatus.nodeBlockHeight
const res: EventData = {
id: e.id,
diff --git a/apps/walletd/contexts/events/types.ts b/apps/walletd/contexts/events/types.ts
index 0c9b9abb9..66d11afdd 100644
--- a/apps/walletd/contexts/events/types.ts
+++ b/apps/walletd/contexts/events/types.ts
@@ -1,4 +1,4 @@
-import { WalletEvent } from '@siafoundation/walletd-types'
+import { WalletEventType } from '@siafoundation/types'
import BigNumber from 'bignumber.js'
export type CellContext = {
@@ -13,7 +13,7 @@ export type EventData = {
maturityHeight?: number
isMature?: boolean
pending: boolean
- type: WalletEvent['type']
+ type: WalletEventType
fee?: BigNumber
amountSc?: BigNumber
amountSf?: number
diff --git a/libs/design-system/src/app/TransactionDetailsDialog.tsx b/libs/design-system/src/app/TransactionDetailsDialog.tsx
index 14b65303e..4f1be70ba 100644
--- a/libs/design-system/src/app/TransactionDetailsDialog.tsx
+++ b/libs/design-system/src/app/TransactionDetailsDialog.tsx
@@ -1,18 +1,20 @@
import { Codeblock } from '../core/Codeblock'
import { Text } from '../core/Text'
import { ValueSc } from '../components/ValueSc'
-import { humanDate } from '@siafoundation/units'
+import { getEventLabel, humanDate } from '@siafoundation/units'
import BigNumber from 'bignumber.js'
import { Dialog } from '../core/Dialog'
import { getTitleId } from '../lib/utils'
-import { Transaction } from '@siafoundation/types'
+import { Transaction, WalletEventType } from '@siafoundation/types'
import { getTxTypeLabel, TxType } from '../lib/entityTypes'
import { upperFirst } from '@technically/lodash'
type Props = {
id: string
transaction?: {
- txType: TxType
+ // deprecated
+ txType?: TxType
+ type?: WalletEventType
inflow?: string
outflow?: string
timestamp?: string | number
@@ -33,7 +35,9 @@ export function TransactionDetailsDialog({
return (