Skip to content

Commit

Permalink
Merge pull request #14 from HausDAO/feature/multi-ten
Browse files Browse the repository at this point in the history
preps for multi-ten
  • Loading branch information
skuhlmann authored Sep 8, 2023
2 parents 366aa73 + a566572 commit 2f21dbe
Show file tree
Hide file tree
Showing 12 changed files with 376 additions and 333 deletions.
116 changes: 63 additions & 53 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,45 +48,80 @@ yarn
cp .env.sample .env
```

Rivet is the default RPC - Get a free Rivet key [here](https://rivet.cloud/)

```yaml
VITE_RIVET_KEY
```

Get a free Rivet key [here](https://rivet.cloud/)
You can also use Alchemy API keys for Optimism, Arbitrum or Polygon

```yaml
VITE_EXPLORER_KEY
VITE_OPTIMISM_ALCHEMY_KEY
VITE_ARBITRUM_ALCHEMY_KEY
VITE_POLYGONPOS_ALCHEMY_KEY
```

Get an Etherscan API key [here](https://etherscan.io/apis)
Proposal details uses etherscan explorer APIs to fetch ABIs. Add a key for any chain you are supporting. Get an Etherscan API key [here](https://etherscan.io/apis)

```yaml
VITE_GRAPH_API_KEY_MAINNET
VITE_ETHERSCAN_KEY
VITE_ARBISCAN_KEY
VITE_GNOSISSCAN_KEY
VITE_POLYGONSCAN_KEY
VITE_OPTIMISMSCAN_KEY
```

If developing for Mainnet or Gnosis Chain you can get an API key [here](https://thegraph.com/explorer/subgraph?id=GfHFdFmiSwW1PKtnDhhcxhArwtTjVuMnXxQ5XcETF1bP&view=Overview). Ignore this one if not worried about mainnet or gnosis chain yet.

```yaml
VITE_GRAPH_API_KEY_MAINNET
```

This is the target address for the DAO you are developing the app for. You will get this value in the next step if you do not have an existing DAO. You'll need to use this if you are setting the app up for single DAO. More on this below.

```yaml
VITE_TARGET_KEY
```

This is the target address for the DAO you are developing the app for. You will get this value in the next step if you do not have an existing DAO.
### 3. Single DAO vs. Multi-DAO Setup

### 3. Target DAO Set-up
#### If your app is supporting a single DAO

[Summon](https://summon.daohaus.club) a DAO

#### Edit `src/targetDao.ts`
##### Edit `src/targetDao.ts`

Add your DAO's data to the property and values of the object

#### Edit `.env`
##### Edit `.env`

Add the DAO address in the `VITE_TARGET_KEY` variable

- You can add multiple DAOs as new objects in `targetDao.ts` and toggle with this `env` variable
- You can add other variables to `targetDao.ts` as needed

#### If your app is supporting multiple DAOs

Remove VITE_TARGET_KEY from the .env file.

You will now beable to navigate to any existing dao whenrunning the app with the following url pattern:

`/#/molochv3/:daochain/:daoid`

This is the same pattern seen in the [DAOhaus admin app](https://admin.daohaus.club/#/molochv3/0x5/0xf6538c07324f59b3ba685d86393c65dce9676c70)

##### `:daochain` is the network ID for the DAO

'0x1' - mainnet
'0x5' - goerli
'0x64' - gnosis chain
'0x89' - polygon
'0xa' - optimism
'0xa4b1' - arbitrum

##### `:daoid` is the contract address for the DAO smart contract

### 4. Run the Development Server

```bash
Expand All @@ -98,13 +133,23 @@ yarn dev
### `main.tsx`

- Sets up the `react-query` provider `@daohaus/moloch-v3-hooks` will use
- Sets up `DHConnectProvider` - that handles the Wallet Connect functionality
- Sets up `HausThemeProvider` - that provides the styling theme to the app

### `App.tsx`

- Sets up `DHConnectProvider` - that handles the Wallet Connect functionality
- Adds the router to the app

### `HomeContainer.tsx`

- Parent component wrapping all routes/pages
- Parent component wrapping all on-dao scoped routes/pages
- Sets up `DHLayout` which adds the connect button and navigation to the app
- You can update the navigation in `navLinks`
-

### `DaoContainer.tsx`

- Parent component wrapping all dao scoped routes/pages
- Sets up `DHLayout` which adds the connect button and navigation to the app
- You can update the navigation in `navLinks`
- Sets up `TXBuilder` which enables easy transaction creation
Expand All @@ -115,50 +160,21 @@ yarn dev
- See the legos it is using at `legos/forms.ts`, `legos/fields.ts`, and `legos/tx.ts`
- These are recipes for creating forms and contract function interactions

### ToDo
### Pages/

- Ad routes/pages for dao overview, vaults, settings
- proposals, members and profile coming soon
- show hook data fetch
- show macro ui addition
- `moloch-v3-fields` package
- coming soon
- Example of many current DAO Admin pages
- Dao overview
- Proposal list and Proposal details
- Member list and Member details
- Dao Settings

### Adding UI Components

- [Storybook](https://storybook.js.org/)

### Methods for Accessing `daoid` and `daochain`

These values are used in most hooks and components and you have some options:

Get them from `targetDao.ts`

```tsx
const daoChain = TARGET_DAO[import.meta.env.VITE_TARGET_KEY].CHAIN_ID;
const daoId = TARGET_DAO[import.meta.env.VITE_TARGET_KEY].ADDRESS;
```

or load them into a context from the `@daohaus/moloch-v3-hooks` library and then there is a hook you can use.

Wrap your tree in this context:

```tsx
import { CurrentDaoProvider } from "@daohaus/moloch-v3-hooks";

...

<CurrentDaoProvider
targetDao={{
daoChain: TARGET_DAO[import.meta.env.VITE_TARGET_KEY].CHAIN_ID,
daoId: TARGET_DAO[import.meta.env.VITE_TARGET_KEY].ADDRESS,
}}
>
{children}
</CurrentDaoProvider>;
```

Then access this hook:
These values are used in most hooks and components and are loaded into a context from the `@daohaus/moloch-v3-hooks` library and then there is a hook you can use.

```tsx
import { useCurrentDao } from "@daohaus/moloch-v3-hooks";
Expand All @@ -167,8 +183,6 @@ import { useCurrentDao } from "@daohaus/moloch-v3-hooks";
const { daoChain, daoId } = useCurrentDao();
```

- Future: `urlParams` in a multi DAO app

### Adding Custom Fields

tbd
Expand All @@ -177,12 +191,8 @@ tbd

tbd

### Router Example for Multi DAO App

tbd

## Resources

- [DAO Toolbox](https://toolbox.daohaus.fun/) docs
- HausDAO monorepo [libs](https://github.com/HausDAO/monorepo/tree/develop/libs)
- monorepo admin/admin-new
- monorepo apps/admin
13 changes: 13 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { DHConnectProvider } from '@daohaus/connect';
import { useState } from 'react';
import { Routes } from './Routes';

export const App = () => {
const [daoChainId, setDaoChainId] = useState<string | undefined>();

return (
<DHConnectProvider daoChainId={daoChainId}>
<Routes setDaoChainId={setDaoChainId} />
</DHConnectProvider>
);
};
70 changes: 46 additions & 24 deletions src/Routes.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
import { Routes as Router, Route } from "react-router-dom";
import { useEffect } from "react";
import {
Routes as Router,
Route,
useLocation,
matchPath,
} from "react-router-dom";

import { ReactSetter } from "@daohaus/utils";

import Dao from "./pages/Dao";
import { FormTest } from "./pages/FormTest";
import { Home } from "./pages/Home";
import { LayoutContainer } from "./components/LayoutContainer";
import Dao from "./pages/Dao";
import { Safes } from "./pages/Safes";
import { Settings } from "./pages/Settings";
import { Proposals } from "./pages/Proposals";
Expand All @@ -11,31 +19,45 @@ import { Members } from "./pages/Members";
import { Member } from "./pages/Member";
import { TARGET_DAO } from "./targetDao";
import RageQuit from "./pages/RageQuit";
import { MULTI_DAO_ROUTER } from "@daohaus/moloch-v3-hooks";
import { HomeContainer } from "./components/layout/HomeContainer";
import { DaoContainer } from "./components/layout/DaoContainer";

export const Routes = ({
setDaoChainId,
}: {
setDaoChainId: ReactSetter<string | undefined>;
}) => {
const location = useLocation();
const pathMatch = matchPath("molochv3/:daochain/:daoid/*", location.pathname);

const routePath = `molochv3/${
TARGET_DAO[import.meta.env.VITE_TARGET_KEY].CHAIN_ID
}/${TARGET_DAO[import.meta.env.VITE_TARGET_KEY].ADDRESS}`;
useEffect(() => {
if (TARGET_DAO[import.meta.env.VITE_TARGET_KEY]?.CHAIN_ID) {
setDaoChainId(TARGET_DAO[import.meta.env.VITE_TARGET_KEY].CHAIN_ID);
}
if (pathMatch?.params?.daochain) {
setDaoChainId(pathMatch?.params?.daochain);
}
if (!pathMatch?.params?.daochain) {
setDaoChainId(undefined);
}
}, [pathMatch?.params?.daochain, setDaoChainId]);

export const Routes = () => {
return (
<Router>
<Route path="/" element={<LayoutContainer />}>
<Route index element={<Home />} />
<Route path={`${routePath}/formtest`} element={<FormTest />} />
<Route path={`${routePath}/dao`} element={<Dao />} />
<Route path={`${routePath}/safes`} element={<Safes />} />
<Route path={`${routePath}/settings`} element={<Settings />} />
<Route path={`${routePath}/proposals/`} element={<Proposals />} />
<Route
path={`${routePath}/proposal/:proposalId`}
element={<Proposal />}
/>
<Route path={`${routePath}/members/`} element={<Members />} />
<Route
path={`${routePath}/member/:memberAddress`}
element={<Member />}
/>
<Route path={`${routePath}/members/ragequit`} element={<RageQuit />} />
<Route path="/" element={<HomeContainer />}>
<Route path="/" element={<Home />} />
</Route>
<Route path={MULTI_DAO_ROUTER} element={<DaoContainer />}>
<Route index element={<Dao />} />
<Route path="formtest" element={<FormTest />} />
<Route path="safes" element={<Safes />} />
<Route path="settings" element={<Settings />} />
<Route path="proposals" element={<Proposals />} />
<Route path="proposal/:proposalId" element={<Proposal />} />
<Route path="members" element={<Members />} />
<Route path="member/:memberAddress" element={<Member />} />
<Route path="members/ragequit" element={<RageQuit />} />
</Route>
</Router>
);
Expand Down
7 changes: 0 additions & 7 deletions src/components/Layout.tsx

This file was deleted.

57 changes: 0 additions & 57 deletions src/components/LayoutContainer.tsx

This file was deleted.

Loading

0 comments on commit 2f21dbe

Please sign in to comment.