diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..6033a68
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,75 @@
+name: CI
+
+on:
+ pull_request:
+ push:
+ branches: [main]
+ workflow_dispatch:
+
+jobs:
+ lint:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/cache@v4
+ with:
+ path: ~/.cache/biome
+ key: biome-${{ runner.os }}-${{ hashFiles('biome.json') }}
+ restore-keys: biome-${{ runner.os }}-
+ - uses: biomejs/setup-biome@v2
+ with:
+ version: 2.1.2
+ - run: biome ci --linter-enabled=true --formatter-enabled=true
+
+ typecheck:
+ runs-on: ubuntu-latest
+ defaults:
+ run:
+ working-directory: frontend
+ steps:
+ - uses: actions/checkout@v4
+ - uses: pnpm/action-setup@v4
+ with:
+ version: 10
+ - uses: actions/setup-node@v4
+ with:
+ node-version: 22
+ cache: pnpm
+ cache-dependency-path: frontend/pnpm-lock.yaml
+ - run: pnpm install --frozen-lockfile
+ - run: pnpm typecheck
+
+ build:
+ runs-on: ubuntu-latest
+ defaults:
+ run:
+ working-directory: frontend
+ steps:
+ - uses: actions/checkout@v4
+ - uses: pnpm/action-setup@v4
+ with:
+ version: 10
+ - uses: actions/setup-node@v4
+ with:
+ node-version: 22
+ cache: pnpm
+ cache-dependency-path: frontend/pnpm-lock.yaml
+ - run: pnpm install --frozen-lockfile
+ - run: pnpm build
+
+ rust:
+ runs-on: ubuntu-latest
+ # Match the backend Dockerfile's build image so bindgen sees a libclang
+ # new enough for the upstream C23 (`constexpr`) headers from monad-bft.
+ container: rust:1.91-slim
+ steps:
+ - name: Install build dependencies
+ run: |
+ apt-get update
+ apt-get install -y git curl gcc g++ cmake pkg-config libssl-dev libclang-dev libzstd-dev libhugetlbfs-dev
+ - uses: actions/checkout@v4
+ - run: rustup component add rustfmt clippy
+ - uses: Swatinem/rust-cache@v2
+ - run: cargo fmt --all --check
+ - run: cargo clippy --all-targets --all-features -- -D warnings
+ - run: cargo build --all-targets
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
deleted file mode 100644
index a45e8ad..0000000
--- a/.github/workflows/lint.yml
+++ /dev/null
@@ -1,24 +0,0 @@
-name: Lint
-
-on:
- pull_request:
-
-jobs:
- lint:
- runs-on: ubuntu-latest
- steps:
- - name: Checkout
- uses: actions/checkout@v4
- - name: Cache Biome
- uses: actions/cache@v4
- with:
- path: ~/.cache/biome
- key: biome-${{ runner.os }}-${{ hashFiles('biome.json') }}
- restore-keys: |
- biome-${{ runner.os }}-
- - name: Setup Biome
- uses: biomejs/setup-biome@v2
- with:
- version: 2.1.2
- - name: Run Biome
- run: biome ci --linter-enabled=true --formatter-enabled=true
diff --git a/frontend/components/network-activity-tracker/tps-chart.tsx b/frontend/components/network-activity-tracker/tps-chart.tsx
index 1394b5a..f86efd4 100644
--- a/frontend/components/network-activity-tracker/tps-chart.tsx
+++ b/frontend/components/network-activity-tracker/tps-chart.tsx
@@ -1,6 +1,7 @@
'use client'
import Image from 'next/image'
+import { useEffect, useState } from 'react'
import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from 'recharts'
import {
type ChartConfig,
@@ -21,11 +22,28 @@ const chartConfig = {
},
} satisfies ChartConfig
+/** Visible time window, matching the TPS history kept by useTps */
+const WINDOW_MS = 5 * 60 * 1000
+
export function TpsChart() {
const { currentTps, peakTps, history } = useTps()
const totalTransactions = useTotalTransactions()
const hasData = history.length > 0
+ // Advance a "now" clock every animation frame so the time-windowed X axis
+ // domain slides continuously. New points enter smoothly from the right edge
+ // instead of popping in a discrete category slot.
+ const [now, setNow] = useState(() => Date.now())
+ useEffect(() => {
+ let frame: number
+ const tick = () => {
+ setNow(Date.now())
+ frame = requestAnimationFrame(tick)
+ }
+ frame = requestAnimationFrame(tick)
+ return () => cancelAnimationFrame(frame)
+ }, [])
+
return (
@@ -77,6 +95,10 @@ export function TpsChart() {
= 10'}
- cpu: [arm64]
- os: [darwin]
'@next/swc-darwin-x64@16.2.6':
resolution: {integrity: sha512-v/YLBHIY132Ced3puBJ7YJKw1lqsCrgcNo2aRJlCEyQrrCeRJlvGlnmxhPxNQI3KE3N1DN5r9TPNPvka3nq5RQ==}
- '@next/swc-darwin-x64@16.2.6':
- resolution: {integrity: sha512-v/YLBHIY132Ced3puBJ7YJKw1lqsCrgcNo2aRJlCEyQrrCeRJlvGlnmxhPxNQI3KE3N1DN5r9TPNPvka3nq5RQ==}
- engines: {node: '>= 10'}
- cpu: [x64]
- os: [darwin]
'@next/swc-linux-arm64-gnu@16.2.6':
resolution: {integrity: sha512-RPOvqlYBbcQjkz9VQQDZ2T2bARIjXZV1KFlt+V2Mr6SW/e4I9fcKsaA0hdyf2FHoTlsV2xnBd5Y912rP/1Ce6w==}
- '@next/swc-linux-arm64-gnu@16.2.6':
- resolution: {integrity: sha512-RPOvqlYBbcQjkz9VQQDZ2T2bARIjXZV1KFlt+V2Mr6SW/e4I9fcKsaA0hdyf2FHoTlsV2xnBd5Y912rP/1Ce6w==}
- engines: {node: '>= 10'}
- cpu: [arm64]
- os: [linux]
- libc: [glibc]
- libc: [glibc]
'@next/swc-linux-arm64-musl@16.2.6':
resolution: {integrity: sha512-URUTu1+dMkxJsPFgm+OeEvq9wf5sujw0EvgYy80TDGHTSLTnIHeqb0Eu8A3sC95IRgjejQL+kC4mw+4yPxiAXA==}
- '@next/swc-linux-arm64-musl@16.2.6':
- resolution: {integrity: sha512-URUTu1+dMkxJsPFgm+OeEvq9wf5sujw0EvgYy80TDGHTSLTnIHeqb0Eu8A3sC95IRgjejQL+kC4mw+4yPxiAXA==}
- engines: {node: '>= 10'}
- cpu: [arm64]
- os: [linux]
- libc: [musl]
- libc: [musl]
'@next/swc-linux-x64-gnu@16.2.6':
resolution: {integrity: sha512-DOj182mPV8G3UkrayLoREM5YEYI+Dk5wv7Ox9xl1fFibAELEsFD0lDPfHIeILlutMMfdyhlzYPELG3peuKaurw==}
- '@next/swc-linux-x64-gnu@16.2.6':
- resolution: {integrity: sha512-DOj182mPV8G3UkrayLoREM5YEYI+Dk5wv7Ox9xl1fFibAELEsFD0lDPfHIeILlutMMfdyhlzYPELG3peuKaurw==}
- engines: {node: '>= 10'}
- cpu: [x64]
- os: [linux]
- libc: [glibc]
- libc: [glibc]
'@next/swc-linux-x64-musl@16.2.6':
resolution: {integrity: sha512-HKQ5SP/V/ub73UvF7n/zeJlxk2kLmtL7Wzrg4WfmkjmNos5onJ2tKu7yZOPdL18A6Svfn3max29ym+ry7NkK4g==}
- '@next/swc-linux-x64-musl@16.2.6':
- resolution: {integrity: sha512-HKQ5SP/V/ub73UvF7n/zeJlxk2kLmtL7Wzrg4WfmkjmNos5onJ2tKu7yZOPdL18A6Svfn3max29ym+ry7NkK4g==}
- engines: {node: '>= 10'}
- cpu: [x64]
- os: [linux]
- libc: [musl]
- libc: [musl]
'@next/swc-win32-arm64-msvc@16.2.6':
resolution: {integrity: sha512-LZXpTlPyS5v7HhSmnvsLGP3iIYgYOBnc8r8ArlT55sGHV89bR2HlDdBjWQ+PY6SJMmk8TuVGFuxalnP3k/0Dwg==}
- '@next/swc-win32-arm64-msvc@16.2.6':
- resolution: {integrity: sha512-LZXpTlPyS5v7HhSmnvsLGP3iIYgYOBnc8r8ArlT55sGHV89bR2HlDdBjWQ+PY6SJMmk8TuVGFuxalnP3k/0Dwg==}
- engines: {node: '>= 10'}
- cpu: [arm64]
- os: [win32]
'@next/swc-win32-x64-msvc@16.2.6':
resolution: {integrity: sha512-F0+4i0h9J6C4eE3EAPWsoCk7UW/dbzOjyzxY0qnDUOYFu6FFmdZ6l97/XdV3/Nz3VYyO7UWjyEJUXkGqcoXfMA==}
- '@next/swc-win32-x64-msvc@16.2.6':
- resolution: {integrity: sha512-F0+4i0h9J6C4eE3EAPWsoCk7UW/dbzOjyzxY0qnDUOYFu6FFmdZ6l97/XdV3/Nz3VYyO7UWjyEJUXkGqcoXfMA==}
- engines: {node: '>= 10'}
- cpu: [x64]
- os: [win32]
'@noble/ciphers@1.3.0':
resolution: {integrity: sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==}
@@ -878,7 +812,6 @@ packages:
cpu: [arm64]
os: [linux]
libc: [glibc]
- libc: [glibc]
'@tailwindcss/oxide-linux-arm64-musl@4.1.17':
resolution: {integrity: sha512-HvZLfGr42i5anKtIeQzxdkw/wPqIbpeZqe7vd3V9vI3RQxe3xU1fLjss0TjyhxWcBaipk7NYwSrwTwK1hJARMg==}
@@ -886,7 +819,6 @@ packages:
cpu: [arm64]
os: [linux]
libc: [musl]
- libc: [musl]
'@tailwindcss/oxide-linux-x64-gnu@4.1.17':
resolution: {integrity: sha512-M3XZuORCGB7VPOEDH+nzpJ21XPvK5PyjlkSFkFziNHGLc5d6g3di2McAAblmaSUNl8IOmzYwLx9NsE7bplNkwQ==}
@@ -894,7 +826,6 @@ packages:
cpu: [x64]
os: [linux]
libc: [glibc]
- libc: [glibc]
'@tailwindcss/oxide-linux-x64-musl@4.1.17':
resolution: {integrity: sha512-k7f+pf9eXLEey4pBlw+8dgfJHY4PZ5qOUFDyNf7SI6lHjQ9Zt7+NcscjpwdCEbYi6FI5c2KDTDWyf2iHcCSyyQ==}
@@ -902,7 +833,6 @@ packages:
cpu: [x64]
os: [linux]
libc: [musl]
- libc: [musl]
'@tailwindcss/oxide-wasm32-wasi@4.1.17':
resolution: {integrity: sha512-cEytGqSSoy7zK4JRWiTCx43FsKP/zGr0CsuMawhH67ONlH+T79VteQeJQRO/X7L0juEUA8ZyuYikcRBf0vsxhg==}
@@ -1084,56 +1014,48 @@ packages:
cpu: [arm64]
os: [linux]
libc: [glibc]
- libc: [glibc]
'@unrs/resolver-binding-linux-arm64-musl@1.11.1':
resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==}
cpu: [arm64]
os: [linux]
libc: [musl]
- libc: [musl]
'@unrs/resolver-binding-linux-ppc64-gnu@1.11.1':
resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==}
cpu: [ppc64]
os: [linux]
libc: [glibc]
- libc: [glibc]
'@unrs/resolver-binding-linux-riscv64-gnu@1.11.1':
resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==}
cpu: [riscv64]
os: [linux]
libc: [glibc]
- libc: [glibc]
'@unrs/resolver-binding-linux-riscv64-musl@1.11.1':
resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==}
cpu: [riscv64]
os: [linux]
libc: [musl]
- libc: [musl]
'@unrs/resolver-binding-linux-s390x-gnu@1.11.1':
resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==}
cpu: [s390x]
os: [linux]
libc: [glibc]
- libc: [glibc]
'@unrs/resolver-binding-linux-x64-gnu@1.11.1':
resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==}
cpu: [x64]
os: [linux]
libc: [glibc]
- libc: [glibc]
'@unrs/resolver-binding-linux-x64-musl@1.11.1':
resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==}
cpu: [x64]
os: [linux]
libc: [musl]
- libc: [musl]
'@unrs/resolver-binding-wasm32-wasi@1.11.1':
resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==}
@@ -1275,10 +1197,6 @@ packages:
engines: {node: '>=6.0.0'}
hasBin: true
- baseline-browser-mapping@2.10.24:
- resolution: {integrity: sha512-I2NkZOOrj2XuguvWCK6OVh9GavsNjZjK908Rq3mIBK25+GD8vPX5w2WdxVqnQ7xx3SrZJiCiZFu+/Oz50oSYSA==}
- engines: {node: '>=6.0.0'}
- hasBin: true
baseline-browser-mapping@2.8.32:
resolution: {integrity: sha512-OPz5aBThlyLFgxyhdwf/s2+8ab3OvT7AdTNvKHBwpXomIYeXqpUUuT8LrdtxZSsWJ4R4CU1un4XGh5Ez3nlTpw==}
@@ -2024,7 +1942,6 @@ packages:
cpu: [arm64]
os: [linux]
libc: [glibc]
- libc: [glibc]
lightningcss-linux-arm64-musl@1.30.2:
resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==}
@@ -2032,7 +1949,6 @@ packages:
cpu: [arm64]
os: [linux]
libc: [musl]
- libc: [musl]
lightningcss-linux-x64-gnu@1.30.2:
resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==}
@@ -2040,7 +1956,6 @@ packages:
cpu: [x64]
os: [linux]
libc: [glibc]
- libc: [glibc]
lightningcss-linux-x64-musl@1.30.2:
resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==}
@@ -2048,7 +1963,6 @@ packages:
cpu: [x64]
os: [linux]
libc: [musl]
- libc: [musl]
lightningcss-win32-arm64-msvc@1.30.2:
resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==}
@@ -2137,26 +2051,6 @@ packages:
next@16.2.6:
resolution: {integrity: sha512-qOVgKJg1+At15NpeUP+eJgCHvTCgXsogweq87Ri/Ix7PkqQHg4sdaXmSFqKlgaIXE4kW0g25LE68W87UANlHtw==}
- next@16.2.6:
- resolution: {integrity: sha512-qOVgKJg1+At15NpeUP+eJgCHvTCgXsogweq87Ri/Ix7PkqQHg4sdaXmSFqKlgaIXE4kW0g25LE68W87UANlHtw==}
- engines: {node: '>=20.9.0'}
- hasBin: true
- peerDependencies:
- '@opentelemetry/api': ^1.1.0
- '@playwright/test': ^1.51.1
- babel-plugin-react-compiler: '*'
- react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0
- react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0
- sass: ^1.3.0
- peerDependenciesMeta:
- '@opentelemetry/api':
- optional: true
- '@playwright/test':
- optional: true
- babel-plugin-react-compiler:
- optional: true
- sass:
- optional: true
node-releases@2.0.27:
resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==}
@@ -2946,41 +2840,32 @@ snapshots:
optional: true
'@next/env@16.2.6': {}
- '@next/env@16.2.6': {}
'@next/eslint-plugin-next@16.0.6':
dependencies:
fast-glob: 3.3.1
- '@next/swc-darwin-arm64@16.2.6':
'@next/swc-darwin-arm64@16.2.6':
optional: true
- '@next/swc-darwin-x64@16.2.6':
'@next/swc-darwin-x64@16.2.6':
optional: true
- '@next/swc-linux-arm64-gnu@16.2.6':
'@next/swc-linux-arm64-gnu@16.2.6':
optional: true
- '@next/swc-linux-arm64-musl@16.2.6':
'@next/swc-linux-arm64-musl@16.2.6':
optional: true
- '@next/swc-linux-x64-gnu@16.2.6':
'@next/swc-linux-x64-gnu@16.2.6':
optional: true
- '@next/swc-linux-x64-musl@16.2.6':
'@next/swc-linux-x64-musl@16.2.6':
optional: true
- '@next/swc-win32-arm64-msvc@16.2.6':
'@next/swc-win32-arm64-msvc@16.2.6':
optional: true
- '@next/swc-win32-x64-msvc@16.2.6':
'@next/swc-win32-x64-msvc@16.2.6':
optional: true
@@ -3661,7 +3546,6 @@ snapshots:
baseline-browser-mapping@2.10.24: {}
- baseline-browser-mapping@2.10.24: {}
baseline-browser-mapping@2.8.32: {}
@@ -4613,25 +4497,15 @@ snapshots:
next@16.2.6(@babel/core@7.28.5)(react-dom@19.2.6(react@19.2.6))(react@19.2.6):
dependencies:
- '@next/env': 16.2.6
'@next/env': 16.2.6
'@swc/helpers': 0.5.15
baseline-browser-mapping: 2.10.24
- baseline-browser-mapping: 2.10.24
caniuse-lite: 1.0.30001759
postcss: 8.4.31
react: 19.2.6
react-dom: 19.2.6(react@19.2.6)
styled-jsx: 5.1.6(@babel/core@7.28.5)(react@19.2.6)
optionalDependencies:
- '@next/swc-darwin-arm64': 16.2.6
- '@next/swc-darwin-x64': 16.2.6
- '@next/swc-linux-arm64-gnu': 16.2.6
- '@next/swc-linux-arm64-musl': 16.2.6
- '@next/swc-linux-x64-gnu': 16.2.6
- '@next/swc-linux-x64-musl': 16.2.6
- '@next/swc-win32-arm64-msvc': 16.2.6
- '@next/swc-win32-x64-msvc': 16.2.6
'@next/swc-darwin-arm64': 16.2.6
'@next/swc-darwin-x64': 16.2.6
'@next/swc-linux-arm64-gnu': 16.2.6
diff --git a/frontend/pnpm-workspace.yaml b/frontend/pnpm-workspace.yaml
index 56dbf93..b0c9078 100644
--- a/frontend/pnpm-workspace.yaml
+++ b/frontend/pnpm-workspace.yaml
@@ -1,3 +1,7 @@
+allowBuilds:
+ sharp: true
+ unrs-resolver: true
+
minimumReleaseAge: 10080
minimumReleaseAgeExclude: