Quickstart
Scaffold an App

Scaffold an App

Good day, developers! Today, we're diving deep into scaffolding a DAO app using the DAOhaus SDK. Let's get started.

Setting Up Starter

Begin by navigating to the DAOhaus GitHub organization. Here, you'll find the dao-app-starter-vite (opens in a new tab) repository. This is our primary and most maintained starter kit, designed to get you up and running swiftly.

Cloning Repository

Now, let's set up our project. If you glance at the README (opens in a new tab) you'll find the project setup instructions. We'll be using npx degit to clone this repository into a fresh directory. For those unfamiliar, 'degit' allows you to clone repositories without their Git history, providing a clean slate. Simply clone the repository then navigate into that directory. initialize git and install the dependencies.

npx degit HausDAO/dao-app-starter-vite my-daohaus-app
 
cd my-daohaus-app

Installing Dependencies

With the repository on your local machine, the next step is to install the necessary dependencies. We'll be using yarn for this. Initialize git and install the dependencies.

git init
 
yarn

Once installed, you can peek into the package.json file and the node_modules directory to see all the dependencies we've added.

Configuring Environment

Next, let's configure our environment. Start by making a copy of the sample environment .env.sample and renaming it .env. Details about the variables are provided in the README (opens in a new tab).

# rivet key for rpc calls, you can also pass in custom rpcs to many components
VITE_RIVET_KEY=
 
# add your graph api key if using mainnet or gnosischain
VITE_GRAPH_API_KEY_MAINNET=
 
# key from wallet connect is required
VITE_WALLET_CONNECT_ID=
 
# optional will use rate limited if not set
VITE_OPTIMISM_ALCHEMY_KEY=
VITE_ARBITRUM_ALCHEMY_KEY=
VITE_POLYGONPOS_ALCHEMY_KEY=
 
# add blockexplorer api keys for any supported networks
VITE_ETHERSCAN_KEY=
VITE_ARBISCAN_KEY=
VITE_GNOSISSCAN_KEY=
VITE_POLYGONSCAN_KEY=
VITE_OPTIMISMSCAN_KEY=
 
# corresponds to keys in targetDao.ts if scoping app to a single dao
VITE_TARGET_KEY=

The Rivet key is for making RPC calls. They allow users to read data on the blockchain and send transactions to the network. The free tier provides more than enough queries/transactions. If you'd like to use Rivet as your default RPC, ensure you add an environment variable for the Rivet key. These keys are available on the Rivet website (opens in a new tab).

Additionally, you can set backup keys for Alchemy (opens in a new tab) to use on Optimism, Arbitrum, and Polygon. While these are optional, they can be beneficial.

For those fetching ABIs, especially in proposal details, you'll need API keys for the block explorer on the chains you're supporting. Get an Etherscan API key (opens in a new tab).

We heavily utilize subgraphs. If you're building on Mainnet or Gnosis Chain, ensure you have an API key from the The Graph (opens in a new tab).

Your app will likely be making queries to the HausDAO subgraph. But you will need to sign into Subgraph Studio to Create API Keys (opens in a new tab) for your app. Once you name your app you are able to copy the key. This is the value needed in the .env.

The Graph requires having GRT deposited to the Billing contract for queries to work. It is difficult to estimate how many queries your app will be making but individual queries are not very expensive. Depositing 10-100 GRT should be more than enough for now.

To utilize the WalletConnect features in the DAOhaus Connect package you need to create new project and get the 'Project ID' from WalletConnect (opens in a new tab).

Lastly, there's a 'target key' which we'll delve into later. This is particularly useful if you're designing an app for a single DAO and is simply the contract address for the DAO your app is connected to.

Running Server

With our environment set up, it's time to run the development server. Execute the command yarn dev. This will run the app locally on port 5173. Once executed, open your browser and navigate to http://localhost:5173/ (opens in a new tab). You should see the app loading and ready to go.

your-haus

Repository Structure

Before diving into the user interface, let's familiarize ourselves with the repository's structure. At the base level, you'll find essential files like .env and .gitignore. The index.html file can be edited to customize your page title.

package.json lists all our scripts and dependencies. Notably, we're importing packages from the DAOhaus SDK. Our build tooling for this app is Vite (opens in a new tab). It's fast, efficient, and has served us well for rapid application development.

src is where the magic happens. It contains the main app, pages, components, utilities, and more. As you explore, you'll notice extensive use of the DAOhaus SDK, providing a plethora of custom components to streamline your development.

Single DAO vs Multi DAO

Let's dive into the flexibility of the DAOhaus SDK. Whether you're creating an app for a single DAO or building an app that pulls in multiple DAOs, we've got you covered. For those familiar with our Admin (opens in a new tab) app, it functions as a multi-tenant application, capable of loading multiple DAOs and providing consistent functionality.

However, if your goal is to cater to just one DAO, the setup is straightforward.

Setup Single DAO

To configure your app for a single DAO, you'll need to add a VITE_TARGET_KEY to the .env. This key essentially tells the app which DAO to connect with. You'll input the DAO contract address into this target key.

Following this, navigate to the /src/targetDao.ts file. This is where you'll provide some additional details about the chosen DAO. For clarity, the repository's README (opens in a new tab) offers step-by-step instructions.

export const TARGET_DAO: {
  [key: string]: {
    ADDRESS: string;
    SAFE_ADDRESS: string;
    CHAIN_ID: ValidNetwork;
  };
} = {
  '0xf6538c07324f59b3ba685d86393c65dce9676c70': {
    ADDRESS: '0xf6538c07324f59b3ba685d86393c65dce9676c70',
    SAFE_ADDRESS: '0xb64b12c4e68310fc222580dea1c86d202310f343',
    CHAIN_ID: '0x5',
  },
  '0xf844b98df9ccdfbe5d460d0d7bdca232cf9da923': {
    ADDRESS: '0xf844b98df9ccdfbe5d460d0d7bdca232cf9da923',
    SAFE_ADDRESS: '0xeb0dc703b854791914f30b5a73dd04d8d22a9aff',
    CHAIN_ID: '0x1',
  },
};

In the TARGET_DAO object, input the DAO contract address as the key. Then, within the object, provide the ADDRESS again. The SAFE_ADDRESS should be replaced with the contract address of the Gnosis Safe treasury. These values are available on the Settings page in the DAOhaus Admin (opens in a new tab) app. The CHAIN_ID is related to the network the DAO is deployed on. For a list of EVM networks visit Chainlist (opens in a new tab).

These are two DAO objects in targetDao.ts if you are working with a single DAO one can be deleted.

Single DAO Demo

Let's see this in action.

The contract address of the DAO App Starter Repo DAO (opens in a new tab) is 0xf6538c07324f59b3ba685d86393c65dce9676c70 on the Goerli testnet. You can see this in the URL structure or by visiting the Settings (opens in a new tab) page.

When you load the app, you'll notice it detects this target DAO and displays relevant data.

What if we want to switch DAOs?

Simply updating the VITE_TARGET_KEY in .env to 0xf844b98df9ccdfbe5d460d0d7bdca232cf9da923 connects the app to the old PublicHAUS DAO on Mainnet.

Please note: This will not work if you deleted the object for the second DAO in targetDao.ts in the previous step.

Set Up Multiple DAOs

If your aim is to cater to multiple DAOs, the process is equally simple. Start by removing VITE_TARGET_KEY from the .env variable. Once done, the app becomes versatile, ready to work with any DAO you choose. For instance, if you want to load data for the Haus Hats (opens in a new tab) DAO, simply adjust the URL in your app by following the pattern:

/#/molochv3/:daochain/:daoid

The app will look for the specific DAO called in the URL structure. This flexibility means you can incorporate features such as a DAO lookup tool allowing users to navigate between different DAOs with ease.

Navigating the App

Now that we've set up our environment, familiarized ourselves with the repository structure, and understand the differences between multi- and single-DAO setups, let's delve into the interface and the corresponding code sections.

Home

Starting with the homepage, Home.tsx is designed to be minimalistic, serving as a splash page to get you started. You can easily locate its content and make edits as needed. Notice the title from index.html and the Connect Wallet button from our SDK.

The Connect package is a gem. This makes it easy to allow users to connect to your app right from the get-go. Additionally, components/layout HomeContainer.tsx and DaoContainer.tsx setup DHLayout adding a navigation bar and footer. You can update the navigation in navLinks.

When you scope your app to a single DAO there will be a 'Target DAO Detected' link added to the homepage. Clicking this will show an expanded navigation offering more options and functionality.

image

DAO Pages

Let's dive into the DAO pages. The DAO overview page, for instance, pulls from the Moloch v3 Macro UI, one of our comprehensive React component libraries. This provides a holistic view of the DAO, including proposal information, token details, and more. The treasury page showcases the DAO's assets, while the proposals page lists all proposals with options to view detailed information, vote, cancel, or execute them. The members page offers a list of all DAO members, and by clicking on an individual member, you can view their detailed profile.

New pages are added in /src/Routes.tsx.

Macro Components

As you navigate through the app, you'll notice our extensive use of macro components. These are larger components that combine multiple smaller components, data, and functionality. For instance, the proposal details page is constructed using several macro components, such as proposal details, proposal actions, and proposal history. This modular approach allows for flexibility and customization. Similarly, the settings page uses the DaoSettings macro, while the profile page provides options to view and edit user profiles.

Modular Design

One of the strengths of this starter kit is its modular design. Whether you're looking at atomic components or more complex macro components, you can easily mix, match, and customize to fit your needs. For instance, if you wanted to display only proposal details on a specific page, you could simply drop in the corresponding component. This flexibility accelerates development and fosters creativity.

Customization Example

Now, let's dive into the customization capabilities of the DAOhaus SDK. We'll explore how effortlessly you can edit pages and work with the components we provide.

For demonstration purposes, let's consider a scenario: You don't want a full-fledged members page. Instead, you'd like a condensed Members list right on the homepage.

Moving Components

The Members list provides a great example of the SDK's flexibility. While you could delete it entirely, for now, we'll repurpose it.

Navigate to the members page Members.tsx in the pages directory

<MemberList
  daoChain={daoChain}
  daoId={daoId}
  allowLinks={true}
  allowMemberMenu={true}
/>

The MemberList component requires the daoChain and daoId. Additionally, it offers options like allowLinks and allowMemberMenu, which enable or disable specific links.

Using the useCurrentDao() hook, the component fetches the DAO chain and DAO ID. Since we already have this data on our DAO overview page, integrating the member list should be straightforward. Let's add the member list to our DAO overview.

To achieve this, navigate to the pages directory. Here, you'll find the DAO overview page Dao.tsx.

  1. Add MemberList to:
import { DaoOverview } from '@daohaus/moloch-v3-macro-ui';
  1. Add Loading, useBreakpoint, widthQuery to:
import { SingleColumnLayout } from '@daohaus/ui';
  1. Add const isMd = useBreakpoint(widthQuery.md); to:
Dao();
  1. Add the following to SingleColumnLayout:
{
  !daoChain || !daoId ? (
    <Loading size={isMd ? 8 : 16} padding="6rem" />
  ) : (
    <MemberList
      daoChain={daoChain}
      daoId={daoId}
      allowLinks={true}
      allowMemberMenu={true}
    />
  );
}

Dao.tsx should now look like this:

import { useCurrentDao } from '@daohaus/moloch-v3-hooks';
import { DaoOverview, MemberList } from '@daohaus/moloch-v3-macro-ui';
import {
  SingleColumnLayout,
  Loading,
  useBreakpoint,
  widthQuery,
} from '@daohaus/ui';
 
export function Dao() {
  const { daoChain, daoId } = useCurrentDao();
  const isMd = useBreakpoint(widthQuery.md);
 
  return (
    <SingleColumnLayout>
      {daoId && daoChain && <DaoOverview daoChain={daoChain} daoId={daoId} />}
 
      {!daoChain || !daoId ? (
        <Loading size={isMd ? 8 : 16} padding="6rem" />
      ) : (
        <MemberList
          daoChain={daoChain}
          daoId={daoId}
          allowLinks={true}
          allowMemberMenu={true}
        />
      )}
    </SingleColumnLayout>
  );
}
 
export default Dao;

And there you have it, a seamlessly integrated members list right on the DAO overview!

Notice the links in the caret and dot dot dot menus? These were enabled by setting allowLinks and allowMemberMenu to true in the Members list component. This provides access to details about each member and features like 'Delegate To' and 'Guild Kick'

Enhancing Layout

While the layout looks good, let's enhance it further.

How about adding a header above the members list for clarity?

Using the DAOhaus UI, we can easily pull in an H2 header. Opting for a centered alignment gives it a polished look. Yes, yes, yes.

Add H2 to:

import {
  SingleColumnLayout,
  Loading,
  useBreakpoint,
  widthQuery,
} from '@daohaus/ui';

Below {daoId && daoChain && <DaoOverview daoChain={daoChain} daoId={daoId} />}

Add:

<H2>Members</H2>

Updating Navigation

Finally, let's declutter the navigation by removing the Members link.

  1. Open DaoContainer.tsx
  2. Delete:
{ label: "Members", href: `/${routePath}/members` },

And voila, it's gone!

Wrapping Up

In summary, whether you're aiming for a single or multi-DAO setup, the process is streamlined and user-friendly. For multiple DAOs, remember to omit the target key and utilize the URL structure for navigation. With these tools at your disposal, you're well-equipped to create a tailored experience for your users, be it for one or multiple DAOs.

We also demonstrated the ease of moving components, enhancing layouts, and updating the navigation using the DAOhaus SDK. The toolkit's flexibility ensures you can tailor the app to your specific needs, ensuring a unique and user-friendly experience.

The DAOhaus SDK is designed to be your springboard. It's not just about building a DAO app; it's about innovating, prototyping, and bringing your unique ideas to life. Our primary goal is to streamline the process, ensuring you can transition from concept to a fully functional DAO app in record time.

Think of the SDK as your blank canvas. While we provide the tools and the foundation, the masterpiece is yours to create. Dive in, experiment, and customize to your heart's content.

Best of luck on your DAO app journey, and remember, the possibilities are endless!