ghostrin / web3-monorepo

โšก๏ธ Get started with your Web3 project,๐Ÿ”‹ included: ๐Ÿชช DID + SSI from Walt.id, ๐ŸŒˆ RainbowKit, ๐Ÿ—‚ monorepo with NX, ๐Ÿ’ป Next.js + Next Auth + ChakraUI + Storybook for the frontend, ๐Ÿ’พ Hasura GraphQL server and Nest.js for the backend, ๐Ÿ”ฎ The Graph protocol to query live data from smart contracts.

Home Page:https://web3-monorepo.app

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

CodeFactor Quality Gate Status Maintainability Rating Bugs Code Smells Duplicated Lines (%) Commitizen friendly


All you need to start your web3 service, ๐Ÿ”‹ included.

This project has been deployed using Vercel, Hasura Cloud and Railway.app. You can check it out here. For more information about the deployment process, check the deployment section ๐Ÿš€.

Quick install

  1. First you need to install pnpm in your machine npm install -g pnpm

  2. Install all the dependencies pnpm install

  3. Create a .env

    Refer to this section to set your .env with the needed API keys

  4. Then you can run the project pnpm start

  5. Make sure to apply the migrations to the prisma db and client once the container is running pnpm prisma:migrate

Project structure

View in NX Graph

name

Access to the services and app URLs locally

The console is used as a backoffice to handle the graphQL server and to innerlink all the microservices.

This is the main web app client used to access the whole array of services.

  • Prisma Studio: pnpm prisma studio

The prisma studio is used to offer an admin interface to the database used by the Nestjs Server app.

This is the mail-catcher where all the mail are going in dev environment.

This is the toolkit server stack to access all the DID functionalities from walt.id: SSI, Wallet and NFT.

You can check the doc here for more information regarding the API.

Keycloak Identity and Access Management server is used as a provider for Next Auth. The IDP Kit from walt.id is used through the OpenID Connect protocol. The login to access the administration console is admin@web3-monorepo.com / password

Apps and Libs

  • apps/web: a Next.js app
  • apps/web-e2e: Cypress e2e test for the web app
  • apps/storybook-main: Main Storybook for the whole project (ui/web)
  • apps/nestjs-server: a Nest.js server app used to extend Hasura functionalities
  • hasura: contain the config / metadata / migrations / seeds for the Hasura service
  • prisma: Prisma database schema and migrations
  • tools: Set of tools to to be used for DX (Developer Experience) and testing purposes.
  • waltid-idpkit: Contain the config files, the encryption keys for the DID server and the registered OIDC client.
  • keycloak: Contain all the realm settings loaded by the keycloak container
  • libs/logger: Isomorphic logger (a small wrapper around console.log)
  • libs/utils: Common utils functions and types for the whole project
  • libs/workspace: Contain all the generators and tooling dedicated to maintaining the NX workspace.
  • libs/dlt/types: contain the typescript types/interfaces related to the DLT (Blockchain) used in the project
  • libs/client/gql/[user, admin]: a library containing all the GraphQL queries and mutations and the generated schemas to be used on the web app. It is divided on 3 folders: user, admin and anonymous depending of the role of the user.
  • libs/client/gql/thegraph: a library that use The Graph protocol in order to query data directly from smart contract on the blockchain.
  • libs/client/hasura/adapter: Next-auth adapter for the Hasura service.
  • libs/client/hasura/fetcher: Fetcher functions to query the Hasura service.
  • libs/client/hasura/utils: Utilities to interact with Hasura.
  • libs/client/did/provider: Next-auth OpenID Client provider for the walt.id idpkit
  • libs/client/siwe/provider: Next-auth OpenID Client provider for the rainwbow kit.
  • libs/client/next-auth/options: Contain all the configs for Next-Auth
  • libs/client/next-auth/common: Common functions used in the context of Next-Auth
  • libs/client/ui/components: React reusable components library
  • libs/client/ui/shared: Functions and assets shared in the context of the UI library
  • libs/client/ui/theme: Contains all the specification for the global style and components style
  • libs/test-utils/db: All the utilities relating the handling of db operation on the context of testing, for ex: seeding/deleting.
  • libs/test-utils/functions: All the utilities functions common to every test runner.
  • libs/test-utils/gql: Offer an sdk and different test user clients to be used on test in order to interact with the hasura service.
  • libs/server/api: API service to query the external services (ex: CoinGecko api)
  • libs/server/alchemy: Low level service to interact with the Alchemy RPC provider
  • libs/server/arbitrum: Service to interact with the Arbitrum RPC provider
  • libs/server/ethereum: Service to interact with the Ethereum RPC provider
  • libs/server/polygon: Service to interact with the Polygon RPC provider
  • libs/server/ethers: High level service to interact with EVM compatible blockchains
  • libs/server/common: Common functions used in the context of the server
  • libs/server/cryptocurrencies: High level service to get data related to cryptocurrencies: price, market cap, etc.
  • libs/server/prisma: Low level service to interact with the prisma database
  • libs/server/task: High level service for task scheduling, cron jobs, etc.

Each package/app is 100% TypeScript.

The Stack

Docker

This repo is configured to be built with Docker, and Docker compose.

To build all apps in this repo:

pnpm docker:build

To shutdown all running containers:

pnpm docker:stop

To launch all the services containers:

pnpm docker:services

The command to run all the services in this repo is

pnpm docker:services

The command to run all the containers for unit and integration test is

pnpm docker:test

Next.js

The web app is using next.js meta-framework v13 in order to leverage serverless api functions and react hybrid SSR/SSG/PWA capabilities. The web app is using the next-auth library to handle the authentication and the authorization and the ChakraUI components library.

 Hasura

The Hasura service is used as a GraphQL API gateway to the Postgres database and for introspection into the prisma database. It is also used to handle the authentication and authorization of the users through a Next-Auth adapter.

It act as the single endpoint for the web app to query the database and the external services like the Nestjs Server app in a federated way.

Prisma ORM

The Prisma ORM is used in the context of the Nest.js Server app to interact with the prisma Postgres database. It is used to generate the database schema and the migrations and offer an admin with Prisma Studio.

Nest.js

The Nest.js framework is used to extend the Hasura functionalities. It serves as a complementary layer to Hasura to handle the business logic of the application and to interact with the external services like the blockchain and the crypto APIs. Currently it serves as a service to handle the retrieval of the user's wallet balance of ERC20 tokens on the Ethereum/Polygon/Arbitrum blockchains. More info in the Nest.js Server app README.

Storybook

You can find the Storybook for this project here Stories are defined on the libs/ui/components. We use interaction testing with the storybook version of jest and testing library in order to provide dynamic demonstration of the usage of individual components along with testing. Aditionnaly, the service chromatic is launched on the CI in order to spot and approve/decline UI changes.

To create a new component, you can use the custom nx generator provided on this project @workspace - component provided from the libs/workspace. It will create the boilerplate code for the react component, the stories file and the jest spec file.

Utilities

This repo has some additional tools already setup for you:

  • TypeScript for static type checking
  • ESLint for code linting
  • Prettier for code formatting
  • Jest test runner for all things JavaScript
  • Husky Git hook library used to execute ESLint and Prettier on staged files before a commit.
  • Cypress test runner for E2E and components test
  • Graphql Code Generator a generator for the graphql schemas and a client builders with provided queries.
  • The Graph: Graph Client a library to easily query the data from smart contract on supported blockchain such as Ethereum.

Libraries

Next Auth

This project use Next-Auth to offer different way of authentication.

The user can sign in with a web3 wallet (Metamask, WalletConnect, etc) and the SIWE adapter will handle the request with Hasura.

You can offer login with OAuth2 providers from Google and Github by providing the corresponding env variables for users that want to connect with a web2 provider. As a fallback, it's also possible to connect with an email and password.

Additionally, this project offer a way to authenticate through a DID thanks to the Walt.id IDP Kit.

You can find the different providers used by next-auth in libs/client/next-auth/options

Hasura is used as an adapter to next-auth in order to persist in a database the user's provided information such as their id. The adapter is located in libs/client/hasura/adapter.

Rainbowkit

This project use Rainbowkit to offer a set of components and hooks to easily build a web3 application. Following the specs of SIWE (Sign In With Ethereum), it offers a way to authenticate in next-auth through the signature of a message with a given wallet.

Waltid-idpkit

This project use the IDP kit in order to offer web3 sign in with your DID.


In order to test it, you will need to follow this steps:
  1. Access the sign in page and click on the Walt.id IDPKit button
  2. Login a new account on the walt.id web wallet by entering any credentials or by connecting your wallet
  3. You will be presented with a page to ask you to get the needed crendentials to be able to connect to the service. Click on the 'Fetch credential from issuer' button. Screenshot 2022-10-12 at 16 16 28
  4. Put any credentials to go through the fake login page of the 'Demo Issuer Portal' Screenshot 20221004 at 19 00 19
  5. Confirm the claim of the Verifiable ID document. Screenshot 2022-10-12 at 16 16 49
  6. Accept the 'Received Credentials' Screenshot 2022-10-04 at 19 01 53
  7. Accept the 'Connection request' of 'Verifiable ID document' Screenshot 2022-10-12 at 16 17 45
  8. The user is logged in effectively and created on the DB through Hasura (Next Auth do it automatically for a new account) Screenshot 2022-10-12 at 16 35 23

The idpkit is configured to use the Demo Issuer Portal in order to get the credentials. This is a fake portal that will give you the credentials you need to go through the process.

This implementation of the IDP kit is by no mean production ready and is only here to show you how to use it. You will need to implement your own issuer portal and configure the IDP kit to use it.

An other use case of the IDP kit is to use it with the NFT Kit in order to sign in with an NFT. You can find the implementation of this use case in the tutorial Login with NFTs | Next.js

Keycloak

We use Keycloak as the main provider to authenticate with credentials or federated sign in with google. The IDP kit server is linked through with OpenID Connect protocol. Keycloak is then used as a provider by Next Auth to handle all the authentication process on the web application.

For any operation you do regarding the settings of keycloak, don't forget to export, rename the file to master-realm.json and replace the existing file in the keycloak folder. Otherwise your settings will not be persisted if you reset your containers or on the CI env. Also, for each exports, your secret will be erased from the config file "secret": "**********", "clientSecret": "**********". You will have to set the secrets with the one you saved but make sure to not do that on production environment.

For convenience purpose everything is set correctly on master-realm.json in order to use Keycloak directly with your app.

You will need to follow this steps to provide Keycloak with your own environment.

  1. Create a new Client with confidential Access Type
  • Go to the Clients section and add a new client.
  • Choose a client id, for instance myApp.
  • Select the Client Authentication option on the next page
  • On the settings page, set the Home URL, Valid redirect URIs, Web origins according to your app URL. In our case that would be http://localhost:3000/*
  • Click on the Credentials tab to reveal and copy the client secret.

You now have the id and secret of the client to populate in KEYCLOAK_ID and KEYCLOAK_SECRET

  1. Add IDPKit to Keycloak as a OpenID Connect provider

Check this tutorial for more information of how to register your own instance of IDP kit on the realm. To register your client as described in the tutorial you can use the following command:

curl --location --request GET 'http://localhost:3333/api/balances/eth/0xb21090C8f6bAC1ba614A3F529aAe728eA92B6487'

Be sure to copy the id and secret from the output in order to register it on keycloak. As you are running both keycloak and idpkit from docker, the resulting address in Discovery endpoint should be http://idpkit:9080/api/oidc/.well-known/openid-configuration

GraphQL code generator

The command pnpm graphql-codegen will launch the graphql-codegen script. All the codegen definitions are written in the file codegen.yml. You should run this command each time you modify a graphql query or update something on the hasura console to have the updated generated sdk and utilities functions.

The generator is divided in two parts, corresponding to the role of user and admin, targeting the graphql hasura server for those respective roles.

Each one have a grapqhl schema and an ast schema generated and specfic sdk.

User

The graphql queries definition are defined in libs/client/gql/user/queries. We use the React-Query module in order to facilitate the querying the data for the user role in the fontend client. The hasura service will read the auth cookie in order to validate the request. We also generate a generic sdk in order to facilitate testing of user query with jest on libs/test-utils/gql/src/generated/test-user.tswhere we provide a Bearer JWT instead of a cookie because jest is not capable to provide one.

Admin

The graphql queries definition are defined in libs/client/gql/admin/queries. We use a generic sdk with a simple fetch query in order to facilitate the querying the data for the admin role. Those queries are made on the server side of the frontend. Hasura will allow the request through the providing of the X-Hasura-Admin-Secret.

The Graph: Graph Client

The Graph Client library is used in order to interact easily with any smart contract on blockchain supported by The Graph protocol.

The library located in libs/client/gql/thegraph integrate the client and the toolset from The Graph in order to generate the graphql code to be used by the web app to fetch live data from desired smart contracts.

The query are defined in libs/client/gql/thegraph/queries and the smart contract sources are defined in libs/client/gql/thegraph/src/.graphclientrc.yml. When updating queries or smart contract sources, be sure to launch the command pnpm thegraph-build in order to generate the new version of the generated files located in libs/client/gql/thegraph/.graphclient.

You can find an example of live query of smart contract on the Blockchain page.

Test

Jest

Jest is the test-runner used for unit and integration tests.

To run all the jest test on affected code, you can use the command:

curl --location --request GET 'http://localhost:3333/api/balances/arb/0x9a8eC29B75Bc10d68D97Dce73fD3Bbec43752870'
curl --location --request GET 'http://localhost:3333/api/balances/poly/0x3c89fC868803A2478C2E875A97299F240b0290C4'

You should receive an Error 400 if the address is not valid or if you enter an invalid chain name.

curl --location --request GET 'http://localhost:3333/api/balances/poly/0xWasaWasaWasaWassup'

To proceed, simply copy the value of the cookie next-auth.session-token once you login and paste the value for each users

The corresponding logins are:

You can check the tests on auth.cy.ts for example usages of thoses utilities.

NX

This project was generated using Nx.

๐Ÿ”Ž Smart, Fast and Extensible Build System

Categories of libraries

In a workspace, libraries are typically divided into four different types:

Feature

Libraries that implement โ€œsmartโ€ UI (e.g. is effectful, is connected to data sources, handles routing, etc.) for specific business use cases.

UI

Libraries that contain only presentational components. That is, compo- nents that render purely from their props, and calls function handlers when interaction occurs.

Data-access

Libraries that contain the means for interacting with external data services; external services are typically backend services.

Utility

Libraries that contain common utilities that are shared by many projects.

Adding capabilities to your workspace

Nx supports many plugins which add capabilities for developing different types of applications and different tools.

These capabilities include generating applications, libraries, etc as well as the devtools to test, and build projects as well.

Below are our core plugins:

  • React
  • npm install --save-dev @nrwl/react
  • Web (no framework frontends)
  • npm install --save-dev @nrwl/web
  • Node
  • npm install --save-dev @nrwl/node

There are also many community plugins you could add.

Generate an application

Run nx g @nrwl/react:app my-app to generate an application.

You can use any of the plugins above to generate applications as well.

When using Nx, you can create multiple applications and libraries in the same workspace.

Generate a library

Run nx g @nrwl/react:lib my-lib to generate a library.

You can also use any of the plugins above to generate libraries as well.

Libraries are shareable across libraries and applications. They can be imported from @workspace/mylib.

Development server

Run nx serve web for a dev server. Navigate to http://localhost:3000/. The app will automatically reload if you change any of the source files.

Code scaffolding

Run nx g @nrwl/react:component my-component --project=my-app to generate a new component.

Build

Run nx build my-app to build the project. The build artifacts will be stored in the dist/ directory. Use the --prod flag for a production build.

Running unit tests

Run nx test my-app to execute the unit tests via Jest.

Run nx affected:test to execute the unit tests affected by a change.

Running end-to-end tests

Run nx e2e my-app to execute the end-to-end tests via Cypress.

Run nx affected:e2e to execute the end-to-end tests affected by a change.

Understand your workspace

Run nx graph to see a diagram of the dependencies of your projects.

Further help

Visit the Nx Documentation to learn more.

โ˜ Nx Cloud

Distributed Computation Caching & Distributed Task Execution

Nx Cloud pairs with Nx in order to enable you to build and test code more rapidly, by up to 10 times. Even teams that are new to Nx can connect to Nx Cloud and start saving time instantly.

Teams using Nx gain the advantage of building full-stack applications with their preferred framework alongside Nxโ€™s advanced code generation and project dependency graph, plus a unified experience for both frontend and backend developers.

Visit Nx Cloud to learn more.

Configure the project with your own .env (mandatory)

In order to run the project, you need to configure the following environment variables in you .env:

The Nestjs and Nextjs Apps uses Alchemy as an RPC provider for the Ethereum, Polygon and Arbitrum blockchains. You need to create an account and get an API key for those on the alchemy dashboard:

ALCHEMY_ETHEREUM_MAINNET_TOKEN=
ALCHEMY_POLYGON_MAINNET_TOKEN=
ALCHEMY_ARBITRUM_MAINNET_TOKEN=
# Warning ! Those api keys are going to get leaked in the client side code so it's advised to set ALLOWLIST DOMAIN in the alchemy dashboard to your apex domain (in our case www.web3-monorepo.app) in order to avoid someone hijacking your api keys. By default a public rpc network is used for the client side code so you don't need to set those api keys if you don't want to.
# NEXT_APP_ALCHEMY_ETHEREUM_MAINNET_TOKEN=
# NEXT_APP_ALCHEMY_POLYGON_MAINNET_TOKEN=
# NEXT_APP_ALCHEMY_ARBITRUM_MAINNET_TOKEN=

Provide the .env file to the github action CI job

The CI pipeline on github action will fail if you don't provide the Alchemy api keys as it's needed for the Nestjs Server app.

In order to do that, you need to:

  1. Go to the github repository Settings
  2. Go to the Environments section
  3. Create a new environment called staging (or any other name corresponding to the environment you want to deploy)
  4. Create a new Environment secrets with the key ENV_FILE and the value of the content of your .env file in the base64 format (you can use this command base64 -i .env to get the base64 value of your .env file)

Configure the project with your own .env (optional)

The following variables are optional, they are already set for you in the .env.local but you need to set them in your private .env if you want to use any of the related feature with you own project:

Google OAuth provider

Follow this tutorial from google to setup your own OAuth provider

Once you have retrieved your client id and client secret assign them in GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET located in the file .env.local

Github OAuth provider

Follow this tutorial from github to setup your own OAuth provider.

Once you have retrieved your client id and client secret assign them in GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET located in the file .env.local

JWT secret keys

In order to secure your JWT authentication provided by Next Auth you are going to need to generate your own RSA-256 keys.

Important ! For testing purpose, public and private keys are provided on this folder waltid-idpkit/data/OIDC/keystore/keys/c047f4e42cf54b66ad154d8ce51e03ef. You are going to need to generate your own. For that, please refer to the section Configure Hasura and Next Auth with same RSA key. The keys provided to the idpkit container will need to be the same in order for the authentication process to work.

Configure the OIDC client on the IDPKIT server

  1. Register a client with the IDP Kits CLI or the API exposed:
make idpkit-register-client -n "MyApp" --all-redirect-uris
  1. Update the IDPKIT_CLIENT_ID and IDPKIT_CLIENT_SECRET environment variables based on the response received from the client registration

For more informations to register your own client, [please check this documentation](Client registration - Docs).

NX Cloud access tokens

As refered in the section about access token in the nx doc, you have different strategies to setup your access to Nx Cloud. In order to beneficiate from local and remote cacheables operations, you can populate use this command to generate an access token allowing read-write access:

pnpx nx g @nrwl/nx-cloud:init

After that, you are going to need to setup your workspace on the nx cloud after registering an account.

Configure Hasura and Next Auth with same RSA key

You need to configure hasura and next auth to have the same asymmetric key. One is provided by default but you can generate your own RSA 256 key using those commands:

# Don't add passphrase

ssh-keygen -t rsa -P "" -b 4096 -m PEM -f jwtRS256.key

ssh-keygen -e -m PEM -f jwtRS256.key > jwtRS256.key.pub

https://hasura.io/blog/next-js-jwt-authentication-with-next-auth-and-integration-with-hasura/

  • Copy the public key in a single line format:
awk -v ORS='\\n' '1' jwtRS256.key.pub | pbcopy
  • Now paste this value in your clipboard to HASURA_GRAPHQL_JWT_SECRET env in the format
{ "type": "RS256", "key": "<insert-your-public-key-here>"}
  • Transform private key into a single line to copy to your clipboard to NEXTAUTH_SECRET env
awk -v ORS='\\n' '1' jwtRS256.key | pbcopy

Don't forget to add double quotes "" arround so that \n are interpreted correctly

Troubleshoot

In case you need your own image instead of sebpalluel/hasura_cli_with_socat_and_curl you can do the following command to publish it in docker hub.

Be sure to have activated the buildx module first by following this article

cd hasura && docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t <username>/<image>:latest --push .

Credits

This project is based on the nextstarter-chakra template

About

โšก๏ธ Get started with your Web3 project,๐Ÿ”‹ included: ๐Ÿชช DID + SSI from Walt.id, ๐ŸŒˆ RainbowKit, ๐Ÿ—‚ monorepo with NX, ๐Ÿ’ป Next.js + Next Auth + ChakraUI + Storybook for the frontend, ๐Ÿ’พ Hasura GraphQL server and Nest.js for the backend, ๐Ÿ”ฎ The Graph protocol to query live data from smart contracts.

https://web3-monorepo.app

License:MIT License


Languages

Language:TypeScript 99.5%Language:JavaScript 0.3%Language:Shell 0.1%Language:CSS 0.1%Language:Makefile 0.0%Language:Dockerfile 0.0%