diff --git a/apps/webapp/package.json b/apps/webapp/package.json
index 9988412c2a..51e66277f7 100644
--- a/apps/webapp/package.json
+++ b/apps/webapp/package.json
@@ -18,6 +18,7 @@
"@radix-ui/react-icons": "^1.3.0",
"@tanstack/react-query": "^5.24.1",
"bignumber.js": "^9.1.2",
+ "date-fns": "^3.3.1",
"immer": "^10.0.3",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/apps/webapp/src/components/footer/index.tsx b/apps/webapp/src/components/footer/index.tsx
new file mode 100644
index 0000000000..29f336c50a
--- /dev/null
+++ b/apps/webapp/src/components/footer/index.tsx
@@ -0,0 +1,26 @@
+import { format } from 'date-fns';
+
+export const Footer = () => {
+ const shortenedCommitHash = __COMMIT_HASH__.slice(0, 7);
+ const dateObj = new Date(__COMMIT_DATE__);
+ const formattedDate = format(dateObj, "MMM dd yyyy HH:mm:ss 'GMT'x");
+
+ return (
+
+
+
Frontend app version
+
+
+
+ );
+};
diff --git a/apps/webapp/src/components/layout.tsx b/apps/webapp/src/components/layout.tsx
index c706e9980d..38ded5c7bc 100644
--- a/apps/webapp/src/components/layout.tsx
+++ b/apps/webapp/src/components/layout.tsx
@@ -6,6 +6,7 @@ import '@penumbra-zone/ui/styles/globals.css';
import { isExtensionInstalled } from '../utils/is-connected';
import { getChainId } from '../fetchers/chain-id';
import { ExtensionNotInstalled } from './extension-not-installed';
+import { Footer } from './footer';
export type LayoutLoaderResult =
| { isInstalled: false }
@@ -34,6 +35,7 @@ export const Layout = () => {
+
>
diff --git a/apps/webapp/src/utils/commit-info-vite-plugin.ts b/apps/webapp/src/utils/commit-info-vite-plugin.ts
new file mode 100644
index 0000000000..b7eb4d3dda
--- /dev/null
+++ b/apps/webapp/src/utils/commit-info-vite-plugin.ts
@@ -0,0 +1,28 @@
+import { Plugin } from 'vite';
+import { execSync } from 'child_process';
+
+// Vite plugin used to inject the current commit hash + commit date + origin into React
+// so the user can be informed the version of minifront they are using
+export const commitInfoPlugin = (): Plugin => {
+ const commitHash = execSync('git rev-parse HEAD').toString().trim();
+ const commitDate = execSync('git log -1 --format=%cI').toString().trim();
+ const gitOriginUrl = execSync('git remote get-url origin')
+ .toString()
+ .trim()
+ .replace(/\.git$/, ''); // Origin urls often appended with .git
+
+ return {
+ name: 'vite-plugin-commit-info',
+ enforce: 'pre',
+ config() {
+ return {
+ // Inject the env variables into the code
+ define: {
+ __COMMIT_HASH__: JSON.stringify(commitHash),
+ __COMMIT_DATE__: JSON.stringify(commitDate),
+ __GIT_ORIGIN_URL__: JSON.stringify(gitOriginUrl),
+ },
+ };
+ },
+ };
+};
diff --git a/apps/webapp/src/vite-env.d.ts b/apps/webapp/src/vite-env.d.ts
index 11f02fe2a0..4c831f6b63 100644
--- a/apps/webapp/src/vite-env.d.ts
+++ b/apps/webapp/src/vite-env.d.ts
@@ -1 +1,4 @@
///
+declare const __COMMIT_HASH__: string;
+declare const __COMMIT_DATE__: string;
+declare const __GIT_ORIGIN_URL__: string;
diff --git a/apps/webapp/vite.config.ts b/apps/webapp/vite.config.ts
index 4251061977..216896506d 100644
--- a/apps/webapp/vite.config.ts
+++ b/apps/webapp/vite.config.ts
@@ -1,10 +1,11 @@
import { defineConfig, splitVendorChunkPlugin } from 'vite';
import react from '@vitejs/plugin-react-swc';
import basicSsl from '@vitejs/plugin-basic-ssl';
+import { commitInfoPlugin } from './src/utils/commit-info-vite-plugin';
export default defineConfig({
base: './',
- plugins: [react(), splitVendorChunkPlugin(), basicSsl()],
+ plugins: [react(), splitVendorChunkPlugin(), basicSsl(), commitInfoPlugin()],
build: {
rollupOptions: {
output: {
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 73ff75b687..27dda7a257 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -299,6 +299,9 @@ importers:
bignumber.js:
specifier: ^9.1.2
version: 9.1.2
+ date-fns:
+ specifier: ^3.3.1
+ version: 3.3.1
immer:
specifier: ^10.0.3
version: 10.0.3