Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Enable Deposits #268

Merged
merged 79 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
35b9a37
feat: add basic wallet packages
rickimoore Jul 16, 2024
5eaae36
feat: added wallet providers and test components
rickimoore Jul 16, 2024
83f00d0
don't use a keyfile for ssl cert
antondlr Jul 16, 2024
b547408
feat: refactor to use secure cookies and natively sent cookies instea…
rickimoore Nov 27, 2024
dfe8862
fix: fix runtime error in case no withdrawal address is available
rickimoore Nov 27, 2024
7cda67d
fix: removed unused code
rickimoore Nov 27, 2024
74ef340
feat: created utils to generate etherscan and beaconcha links
rickimoore Nov 27, 2024
e871f0c
feat: added new utils
rickimoore Nov 27, 2024
61a4f10
Update debounce.ts
rickimoore Nov 27, 2024
3731710
feat: added new styles and style configs
rickimoore Nov 27, 2024
2fbc98a
Update en-US.json
rickimoore Nov 27, 2024
28ae400
fix: removed unused recoil atoms and added new for wallet modal
rickimoore Nov 27, 2024
1b3d62a
Update yarn.lock
rickimoore Nov 27, 2024
16dba8f
feat: added and updated typings
rickimoore Nov 27, 2024
adfdf4b
fix: default to kubernets url for beacon
rickimoore Nov 27, 2024
262e266
fix: default to testnet for beacon chain network
rickimoore Nov 27, 2024
2083633
fix: use correct base effective_balance sum
rickimoore Nov 27, 2024
2cc3e8a
fix: removed unused constnts and added new urls
rickimoore Nov 27, 2024
048d64e
feat: added new backend packages for chainsafe and cookies
rickimoore Nov 27, 2024
c09d4a2
feat: added backend support for activity tracking
rickimoore Nov 27, 2024
ce17600
feat: added backend support to query validator status via single pubkey
rickimoore Nov 27, 2024
ef9dd5f
feat: update validator backend service to allow imports and other ref…
rickimoore Nov 27, 2024
172f693
Update yarn.lock
rickimoore Nov 27, 2024
26e0bd9
update next configs
rickimoore Nov 27, 2024
e2e72c9
feat: enable activity api
rickimoore Nov 27, 2024
efa6e3c
feat: enable validator import api
rickimoore Nov 27, 2024
fa1ad74
feat: enable activity stream api
rickimoore Nov 27, 2024
e24db01
feat: remove cookie from client app, check auth via fetch node
rickimoore Nov 27, 2024
ffc9941
feat: created util to copy text to clipboard
rickimoore Nov 27, 2024
6a66993
feat: added provider wagmi provider to app, removed rainbowkit
rickimoore Nov 27, 2024
6689dcd
feat: added activity data to all pages ssr loads
rickimoore Nov 27, 2024
d6729bb
feat: added new web3 hooks
rickimoore Nov 27, 2024
618e1f3
fix: remove unused type
rickimoore Nov 27, 2024
cc95a1c
Create depositContractAbi.ts
rickimoore Nov 27, 2024
2df2727
feat: added img assets
rickimoore Nov 27, 2024
e433b59
fix: update select dropdown and currency select for more flexible sty…
rickimoore Nov 27, 2024
ce899e6
fix: update alert icon styles
rickimoore Nov 27, 2024
b563de8
fix: remove unneeded cookie injection
rickimoore Nov 27, 2024
c41401f
fix: add framer motion to button component
rickimoore Nov 27, 2024
f6bda16
feat: add activity data to dashboard
rickimoore Nov 27, 2024
f25b53a
fix: update to use new useSSEData hook
rickimoore Nov 27, 2024
eba5708
feat: added motion framer to infobox
rickimoore Nov 27, 2024
26b8f2f
fix: style update
rickimoore Nov 27, 2024
a0db047
feat: added new font sizes
rickimoore Nov 27, 2024
74a9560
fix: transcript fix
rickimoore Nov 27, 2024
906a3b4
fix: style and render fixes
rickimoore Nov 27, 2024
6036c7a
feat: added wallet provider and connect components
rickimoore Nov 28, 2024
c79d0eb
feat: added activity history components
rickimoore Nov 28, 2024
27923e2
feat: added new helper components
rickimoore Nov 28, 2024
9a7861f
feat: add wallet and history components to topbar
rickimoore Nov 28, 2024
d53e0f1
feat: added components for deposit flow
rickimoore Nov 28, 2024
63928a9
feat: new validator views to management page
rickimoore Nov 28, 2024
db85d67
fix: clean up
rickimoore Nov 28, 2024
e0df283
fix: update packages and config
rickimoore Dec 3, 2024
c39ac5c
fix: remove unused import
rickimoore Dec 3, 2024
6409aab
fix: style fixes in mobile and 2xl screens
rickimoore Dec 3, 2024
f44d60d
fix: auth prompt height fix
rickimoore Dec 3, 2024
f5ade7e
fix: don't render scroll bottom anim if no func
rickimoore Dec 3, 2024
eaaacd0
fix: add a warning toast when user tries to add a too large size of v…
rickimoore Dec 3, 2024
b53414a
fix: update inline input size when using large numbers
rickimoore Dec 3, 2024
cdc1595
fix: remove finally so loading state remains until transaction is done
rickimoore Dec 3, 2024
ed8e0b2
fix: update next and tsconfig for prod build
rickimoore Dec 4, 2024
e43beeb
fix: lint
rickimoore Dec 4, 2024
123c58b
fix: type fixes
rickimoore Dec 4, 2024
eb8b8d7
fix: added new translations and updated Trans key usage
rickimoore Dec 4, 2024
074397c
fix: sort fix on history component
rickimoore Dec 4, 2024
a3c383b
fix: adjust logic for keystore and credentials for multi and signle t…
rickimoore Dec 4, 2024
b2a0a6e
fix: key phrase prop updates
rickimoore Dec 4, 2024
b6fca59
fix: update txHash typing
rickimoore Dec 4, 2024
0beb54b
fix: type fixes and catch mising key store password
rickimoore Dec 4, 2024
56bbd8b
fix: remove loadstar import and replaced functions
rickimoore Dec 4, 2024
2fd65bb
feat: added wallet type for chain
rickimoore Dec 4, 2024
e9fc9a2
Fix docker build warning
antondlr Dec 4, 2024
3136bb5
typo
antondlr Dec 4, 2024
4ac8db0
feat: added more info for connecting to local testnet in the .env and…
rickimoore Dec 4, 2024
240be5d
Merge branch 'feat/deposits' of https://github.com/sigp/siren into fe…
rickimoore Dec 4, 2024
159f86e
fix: remove default keyDerivationPath until needed
rickimoore Dec 9, 2024
e88198d
fix: removed unused loading state in custom hook
rickimoore Dec 9, 2024
4d1939a
fix: added error keys to translation file
rickimoore Dec 9, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,25 @@ DEBUG=false
# don't change these when building the docker image, only change when running outside of docker
PORT=3000
BACKEND_URL=http://127.0.0.1:3001


#For Local Development only

#Kubernets
#To reach the dashboard `http://localhost:9711/` once it is running

#Find the VC Url via `vc-1-geth-lighthouse` and the http-validator public-port
#VALIDATOR_URL=http://127.0.0.1:YOUR-KUBERNET-VC-PORT

#Find the Beancon Url via `cl-1-lighthouse-geth` and the http public-port
#BEACON_URL=http://127.0.0.1:YOUR-KUBERNET-CL-PORT

#Get Api Token: (change name to current vc-[vc_number])
#docker exec -ti $(docker ps -q -f name=vc-1) cat /validator-keys/keys/api-token.txt | pbcopy
#API_TOKEN=YOUR-COPIED-TOKEN

#This should remain the same but double check on kubernets dashboard
#NEXT_PUBLIC_TESTNET_CHAIN_ID=3151908

#Find the RPC port in `el-1-geth-lighthouse`
#NEXT_PUBLIC_TESTNET_RPC=http://127.0.0.1:YOUR-KUBERNET-RPC
2 changes: 1 addition & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"plugins": ["@typescript-eslint", "import", "react-hooks", "unused-imports"],
"plugins": ["@typescript-eslint", "import", "unused-imports"],
"extends": ["next/core-web-vitals"],
"rules": {
"@typescript-eslint/ban-ts-comment": "off",
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,4 @@ RUN rm /etc/nginx/sites-enabled/default; \

COPY --from=intermediate /app /app/

ENTRYPOINT /app/docker-assets/docker-entrypoint.sh
ENTRYPOINT ["/app/docker-assets/docker-entrypoint.sh"]
39 changes: 30 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,26 +21,25 @@ developers. Specifically the [Lighthouse UI](https://lighthouse-book.sigmaprime.

### Docker (Recommended)

Docker is the recommended way to run Siren. This will expose Siren as a webapp.
Docker is the recommended way to run Siren. This will expose Siren as a webapp.

Configuration is done through environment variables, the best way to get started is by copying `.env.example` to `.env` and editing the relevant sections (typically, this would at least include `BEACON_URL`, `VALIDATOR_URL` and `API_TOKEN`)

Then to run the image:

`docker compose up`
or
`docker run --rm -ti --name siren -p 3443:443 --env-file $PWD/.env sigp/siren`
`docker run --rm -ti --name siren -p 3443:443 --env-file $PWD/.env sigp/siren`

This will open port 3443 and allow your browser to connect.
This will open port 3443 and allow your browser to connect.


To start Siren, visit `https://localhost:3443` in your web browser (ignore the certificate warning).
To start Siren, visit `https://localhost:3443` in your web browser (ignore the certificate warning).

Advanced users can mount their own certificate (the config expects 3 files: `/certs/cert.pem` `/certs/key.pem` `/certs/key.pass`)

## Building From Source

### Docker
### Docker

The docker image can be built with the following command:
`docker build -f Dockerfile -t siren .`
Expand All @@ -50,10 +49,32 @@ The docker image can be built with the following command:
To build from source, ensure that your system has `Node v18.18` and `yarn` installed. Start by configuring your environment variables. The recommended approach is to duplicate the `.env.example` file, rename it to `.env`, and modify the necessary settings. Essential variables typically include `BEACON_URL`, `VALIDATOR_URL`, and `API_TOKEN`.

#### Build and run the backend
Navigate to the backend directory `cd backend`. Install all required Node packages by running `yarn`. Once the installation is complete, compile the backend with `yarn build`. Deploy the backend in a production environment, `yarn start:production`. This ensures optimal performance.

Navigate to the backend directory `cd backend`. Install all required Node packages by running `yarn`. Once the installation is complete, compile the backend with `yarn build`. Deploy the backend in a production environment, `yarn start:production`. This ensures optimal performance.

#### Build and run the frontend
After initializing the backend, return to the root directory. Install all frontend dependencies by executing `yarn`. Build the frontend using `yarn build`. Start the frontend production server with `yarn start`.

This will allow you to access siren at `http://localhost:3000` by default.
After initializing the backend, return to the root directory. Install all frontend dependencies by executing `yarn`. Build the frontend using `yarn build`. Start the frontend production server with `yarn start`.

This will allow you to access siren at `http://localhost:3000` by default.


## Running Local Testnet

If you want to run the local testnet, before running the `backend` you must start the `Kurtosis` network. Navigate to the testnet directory with `cd local-testnet` and run the script with `./start_local_testnet.sh`. When the script completes and the testnet is online you can reach the `Kurtosis Enclave Manager` via `http://localhost:9711/`.

#### Finding the VALIDATOR_URL
To find the variables needed for the `VALIDATOR_URL` open the `Kurtosis Enclave Manager` and click on the running `local-testnet` to gain access to all the services. There may be multiple `VC` running, you can select `vc-1-geth-lighthouse` and copy the `public port` from the `http-validator` row in the ports table. It should resemble `http://127.0.0.1:[YOUR-PORT-NUMBER]`

#### Finding the BEACON_URL
In a similar process to the validator url open the `Kurtosis Enclave Manager`and click on the running `local-testnet`. There may also be multiple `CL` running, you can select `cl-1-lighthouse-geth` and copy the `public ports` for the `http` row in the ports table. It will also resemble `http://127.0.0.1:[YOUR-PORT-NUMBER]`.

#### Finding the API_TOKEN
From your command line you can run the following command: `docker exec -ti $(docker ps -q -f name=vc-1) cat /validator-keys/keys/api-token.txt`. This will print your token, do not copy the `%` at the end of the string. It is not a part of the token.

#### Connection with your wallet
If you want to connect to siren with your browser wallet you must add some additional fields to your `.env` file. Firstly, you must set the `NEXT_PUBLIC_TESTNET_CHAIN_ID` to the one that corresponds to your local testnet. This should be the same as in the example, if not you can find it via the `Kurtosis Enclave Manager` in the local testnet file artifacts section. Scroll down and find the `genesis-el-cl-env-file` and open the `values.env`. Here you will find the `CHAIN_ID`, `MNEMONIC` and other node data.

Lastly you need to add the `NEXT_PUBLIC_TESTNET_RPC` variable to allow siren to connect your wallet. This can be found in the services table in the `EL`. There may be multiple but you can select `el-1-geth-lghthouse`. In the ports table you need to copy the `public ports` for the `rpc` row. It should resemble `http://127.0.0.1:YOUR-KUBERNET-RPC`

When everything is added correctly you need to import the `kurtosis` wallet into your browser wallet provider and add the same `NEXT_PUBLIC_TESTNET_RPC` as the `RPC_URL` so you can see the balance and make movements correctly.
124 changes: 57 additions & 67 deletions app/Main.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,22 @@
'use client';

import axios from 'axios';
import Cookies from 'js-cookie';
import { useRouter, useSearchParams } from 'next/navigation';
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import AppDescription from '../src/components/AppDescription/AppDescription';
import AuthPrompt from '../src/components/AuthPrompt/AuthPrompt';
import ConfigModal from '../src/components/ConfigModal/ConfigModal';
import LoadingSpinner from '../src/components/LoadingSpinner/LoadingSpinner';
import Typography from '../src/components/Typography/Typography';
import VersionModal from '../src/components/VersionModal/VersionModal';
import { REQUIRED_VALIDATOR_VERSION } from '../src/constants/constants';
import { UiMode } from '../src/constants/enums';
import useLocalStorage from '../src/hooks/useLocalStorage';
import { ToastType } from '../src/types';
import displayToast from '../utilities/displayToast';
import formatSemanticVersion from '../utilities/formatSemanticVersion';
import isExpiredToken from '../utilities/isExpiredToken';
import isRequiredVersion from '../utilities/isRequiredVersion';
'use client'

import axios from 'axios'
import { useRouter, useSearchParams } from 'next/navigation'
import { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import AppDescription from '../src/components/AppDescription/AppDescription'
import AuthPrompt from '../src/components/AuthPrompt/AuthPrompt'
import ConfigModal from '../src/components/ConfigModal/ConfigModal'
import LoadingSpinner from '../src/components/LoadingSpinner/LoadingSpinner'
import Typography from '../src/components/Typography/Typography'
import VersionModal from '../src/components/VersionModal/VersionModal'
import { REQUIRED_VALIDATOR_VERSION } from '../src/constants/constants'
import { UiMode } from '../src/constants/enums'
import useLocalStorage from '../src/hooks/useLocalStorage'
import { ToastType } from '../src/types'
import displayToast from '../utilities/displayToast'
import formatSemanticVersion from '../utilities/formatSemanticVersion'
import isRequiredVersion from '../utilities/isRequiredVersion'

const Main = () => {
const { t } = useTranslation()
Expand All @@ -29,57 +27,44 @@ const Main = () => {
const [step] = useState<number>(1)
const [isReady, setReady] = useState(false)
const [isVersionError, setVersionError] = useState(false)
const [sessionToken, setToken] = useState(Cookies.get('session-token'))
const [isAuthenticated, setIsAuthenticated] = useState(false)
const [, setUsername] = useLocalStorage<string>('username', 'Keeper')
const [healthCheck] = useLocalStorage<boolean>('health-check', false)

const [beaconNodeVersion, setBeaconVersion] = useState('')
const [lighthouseVersion, setLighthouseVersion] = useState('')

useEffect(() => {
if(sessionToken) {
if(isExpiredToken(sessionToken)) {
setToken(undefined)
return
}

(async () => {
try {
const config = {
headers: {
Authorization: `Bearer ${sessionToken}`
}
}

const [beaconResults, lightResults] = await Promise.all([
axios.get('/api/beacon-version', config),
axios.get('/api/lighthouse-version', config)
])

setBeaconVersion(beaconResults.data.version)
setLighthouseVersion(lightResults.data.version)

setReady(true)

} catch (e) {
setReady(true)
console.error(e)
}
})()
const fetchNodeVersion = async () => {
try {
const [beaconResults, lightResults] = await Promise.all([
axios.get('/api/beacon-version'),
axios.get('/api/lighthouse-version'),
])

setBeaconVersion(beaconResults.data.version)
setLighthouseVersion(lightResults.data.version)
setIsAuthenticated(true)
} catch (e) {
console.error(e)
} finally {
setReady(true)
}
}, [sessionToken])
}

useEffect(() => {
if(beaconNodeVersion && lighthouseVersion) {
void fetchNodeVersion()
}, [])

useEffect(() => {
if (beaconNodeVersion && lighthouseVersion) {
if (!isRequiredVersion(lighthouseVersion, REQUIRED_VALIDATOR_VERSION)) {
setVersionError(true)
return
}

let nextRoute = '/setup/health-check'

if(healthCheck) {
if (healthCheck) {
nextRoute = '/dashboard'
}

Expand All @@ -96,30 +81,35 @@ const Main = () => {
try {
setLoading(true)
setUsername(username)
const {status, data} = await axios.post('/api/authenticate', {password})
const token = data.token;
setLoading(false)
const { status } = await axios.post('/api/authenticate', { password })

if(status === 200) {
setToken(token)
Cookies.set('session-token', token)
if (status === 200) {
await fetchNodeVersion()
}

} catch (e: any) {
setLoading(false)
displayToast(t(e.response.data.error as string), ToastType.ERROR)
} finally {
setLoading(false)
}
}

return (
<div className='relative w-screen h-screen bg-gradient-to-r from-primary to-tertiary'>
<ConfigModal
isReady={isReady && configError && !!sessionToken}
beaconNodeVersion={beaconNodeVersion} lighthouseVersion={lighthouseVersion} />
isReady={isReady && configError && isAuthenticated}
beaconNodeVersion={beaconNodeVersion}
lighthouseVersion={lighthouseVersion}
/>
{vcVersion && (
<VersionModal currentVersion={vcVersion} isVisible={isReady && isVersionError}/>
<VersionModal currentVersion={vcVersion} isVisible={isReady && isVersionError} />
)}
<AuthPrompt isNamePrompt mode={UiMode.LIGHT} isLoading={isLoading} isVisible={!sessionToken} onSubmit={storeSessionCookie}/>
<AuthPrompt
isNamePrompt
mode={UiMode.LIGHT}
isLoading={isLoading}
isVisible={isReady && !isAuthenticated}
onSubmit={storeSessionCookie}
/>
<div className='absolute top-0 left-0 w-full h-full bg-cover bg-lighthouse' />
<div className='absolute top-1/2 -translate-y-1/2 left-1/2 -translate-x-1/2'>
<LoadingSpinner />
Expand Down
15 changes: 9 additions & 6 deletions app/Providers.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
'use client'

import { QueryClientProvider, QueryClient } from '@tanstack/react-query'
import React, { FC, ReactElement } from 'react'
import { QueryClient, QueryClientProvider } from 'react-query'
import { ToastContainer } from 'react-toastify'
import { RecoilRoot } from 'recoil'
import 'react-tooltip/dist/react-tooltip.css'
import 'react-toastify/dist/ReactToastify.min.css'
import 'rodal/lib/rodal.css'

import { WagmiProvider } from 'wagmi'
import createWagmiConfig from '../utilities/createWagmiConfig'
const queryClient = new QueryClient()

export interface ProviderProps {
Expand All @@ -17,10 +18,12 @@ export interface ProviderProps {
const Providers: FC<ProviderProps> = ({ children }) => {
return (
<RecoilRoot>
<QueryClientProvider client={queryClient}>
{children}
<ToastContainer />
</QueryClientProvider>
<WagmiProvider reconnectOnMount config={createWagmiConfig()}>
<QueryClientProvider client={queryClient}>
{children}
<ToastContainer />
</QueryClientProvider>
</WagmiProvider>
</RecoilRoot>
)
}
Expand Down
34 changes: 34 additions & 0 deletions app/api/activities.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import fetchFromApi from '../../utilities/fetchFromApi'

const backendUrl = process.env.BACKEND_URL

export interface fetchActivitiesProps {
token: string
offset?: string
limit?: string
order?: string
since?: string
}

export const fetchActivities = async (props: fetchActivitiesProps) => {
const { token, offset, limit, order, since } = props
const params = new URLSearchParams()

if (offset) params.append('offset', offset)
if (limit) params.append('limit', limit)
if (order) params.append('order', order)
if (since) params.append('since', since)

return await fetchFromApi(`${backendUrl}/activity?${params.toString()}`, token)
}

export const logActivity = async (data: any, token: string) =>
await fetchFromApi(`${backendUrl}/activity`, token, {
method: 'POST',
body: JSON.stringify(data),
})

export const readActivity = async (id: string, token: string) =>
await fetchFromApi(`${backendUrl}/activity/${id}/read`, token, {
method: 'PUT',
})
19 changes: 19 additions & 0 deletions app/api/activity/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { NextResponse } from 'next/server'
import getReqAuthToken from '../../../utilities/getReqAuthToken'
import { fetchActivities } from '../activities'

export async function GET(req: Request) {
try {
const { searchParams } = new URL(req.url)
const offset = searchParams.get('offset') || undefined
const limit = searchParams.get('limit') || undefined
const order = searchParams.get('order') || undefined
const since = searchParams.get('since') || undefined

const token = getReqAuthToken(req)
const data = await fetchActivities({ token, offset, limit, order, since })
return NextResponse.json(data)
} catch (error) {
return NextResponse.json({ error: 'Failed to fetch activities' }, { status: 500 })
}
}
Loading