VenCura is a comprehensive custodial wallet platform for EVM (Ethereum Virtual Machine) networks, built to showcase secure wallet management and multi-chain compatibility within a modern Web3 application.
This monorepo includes:
- Backend: Developed with NestJS and Prisma for seamless interactions with PostgreSQL. Deployed via a CI/CD pipeline on Google Cloud Platform (GCP).
- Frontend: A responsive Next.js application that integrates wallet functionalities for a smooth and intuitive user experience.
Alfred L.
- GitHub: https://github.com/alliu930410
- Email: [email protected]
- Frontend App: VenCura on Vercel
- Backend API: VenCura Backend API
Note: CORS is configured to only allow requests from:
http://localhost:3003/
https://dynamic-ven-cura.vercel.app/
Additionally, please be aware that requests may be delayed, as the hosting instance enters idle mode after 15 minutes of inactivity.
We utilize Dynamic for streamlined authentication, offering seamless Web3 login across multiple wallet providers and chains. Dynamic also supports Web2 authentication options, such as Google and email, for a flexible, user-friendly login experience.
Note: All commands are executed from the root directory of this repository.
- Navigate to the backend directory:
cd backend
- Run
yarn docker:dev:up
to start a PostgreSQL container (usedocker ps
to check running containers; you should seeven_cura_local
mapped to port 5432).
- Navigate to the backend directory:
cd backend
- Install dependencies:
yarn
- Ensure the PostgreSQL container is running (see the Database section above).
- Create a
.env
file by copying.env.example
. Update the following variables: - Apply Prisma migrations:
yarn migrate:dev
- Start the API server:
yarn start:dev
- Access the server at http://localhost:3000
- View the API documentation at http://localhost:3000/api (Swagger).
- Navigate to the backend directory:
cd backend
- Run
yarn test
to execute the tests, which cover:- Controller logic for the
/custodial
entity (note: services are tested within the controllers) - Key generation validation for required fields
- Crypto encryption verification (see details in the Security section below)
- Controller logic for the
- Ensure the backend database and API are running (see above).
- Navigate to the frontend directory:
cd frontend
- Install dependencies:
yarn
- Create an
.env
file and addNEXT_PUBLIC_API_URL=http://localhost:3000
- Start the frontend:
yarn dev
- Access the frontend at http://localhost:3003
Note: Before proceeding, create a GCP project. IAM and service setups vary across projects, so they are not included here. Instead, the required configuration files are outlined below:
/backend/Dockerfile
: Dockerfile for building the base image/deploy/cloudbuild.staging.yaml
: YAML configuration for the CI/CD pipeline, including steps for each commit or push to the repository (currently triggered only on pushes to themain
branch)
-
Build Container Image
Uses/backend/Dockerfile
to create the container image. -
Push Image to GCP
Uploads the container image to Google Container Registry. -
Spin up a PostgreSQL Database
Initializes a PostgreSQL instance in the Cloud Build environment for testing purposes. -
Run Unit Tests
Executes unit tests in the Cloud Build environment. -
Shutdown PostgreSQL Database
Shuts down the test PostgreSQL instance gracefully after testing. -
Create Cloud SQL Socket Connection
Utilizes GCP Cloud SQL Auth proxy to establish a secure socket connection to the Cloud SQL instance on local port 5544, then applies Prisma migrations. -
Deploy to Cloud Run
Deploys the built container to a Cloud Run instance.
- [Frontend]: We use Dynamic for login and authentication. An
authToken
is created when a user logs in via Dynamic. - [Backend]: We implement a generic
JwtAuthGuard
to secure all API requests requiring authentication. This guard uses Dynamic's public key to decode or reject requests.
Key Creation: We use the native crypto package to generate private keys.
Key Security: The
encryptKey
anddecryptKey
implementations are located in/backend/utils/crypto.ts
.
-
Encryption: A random initialization vector (IV) is generated, and the key is encoded using the
WALLET_ENCRYPTION_KEY
buffer, retrieved from environment variables. Both theencryptedKey
and the IV are stored in the database. -
Decryption: We decrypt the
encryptedKey
and IV using theWALLET_ENCRYPTION_KEY
buffer from environment variables.
This approach ensures that, even in the event of a database leak, private keys remain secure, as decryption requires knowledge of the WALLET_ENCRYPTION_KEY
.