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

Major backport of new code #117

Merged
merged 14 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
27 changes: 18 additions & 9 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,24 +1,33 @@
# PUBLIC ENV VARS

# General
NEXT_PUBLIC_DAO_ADDRESS=0x59447788F9dCf2df550F257F3692a07f05b922D7
NEXT_PUBLIC_TOKEN_ADDRESS=0x99372d3afa980c7a6acd3130f0fce5017e20454e
NEXT_PUBLIC_DELEGATION_ANNOUNCEMENTS_START_BLOCK=10541166 # per chain
NEXT_PUBLIC_DAO_ADDRESS=0xd9A924bF3FaE756417b9B9DCC94C24681534b8F7
NEXT_PUBLIC_TOKEN_ADDRESS=0x9A3218197C77F54BB2510FBBcc7Da3A4D2bE0DeE

# Plugin addresses
NEXT_PUBLIC_TOKEN_VOTING_PLUGIN_ADDRESS=0x1276a2f2F8Ea2172FAD053562C2fa05966111A42
NEXT_PUBLIC_DELEGATION_CONTRACT_ADDRESS=0xb3b899F190Af7f5FEE002f6f823743Ba80b2FfA1
NEXT_PUBLIC_DUAL_GOVERNANCE_PLUGIN_ADDRESS=0xa6796635D194442b4FAC81904E60E380cFE3eDAE
NEXT_PUBLIC_TOKEN_VOTING_PLUGIN_ADDRESS=0x7AdF2545e746E014887916e476DfCB3Fb57D78b0
NEXT_PUBLIC_LOCK_TO_VOTE_PLUGIN_ADDRESS=
NEXT_PUBLIC_MULTISIG_PLUGIN_ADDRESS=0xf49d54D40A331441536BDF74C44FFb527cf113c9
NEXT_PUBLIC_EMERGENCY_MULTISIG_PLUGIN_ADDRESS=0x3abd07A24a39eCEB2a701f3C4A5BBbcb7069460D
NEXT_PUBLIC_DUAL_GOVERNANCE_PLUGIN_ADDRESS=0x31df2Cf73f36732c10523E4F228a458292B8F6DF
NEXT_PUBLIC_PUBLIC_KEY_REGISTRY_CONTRACT_ADDRESS=0x4BA2de07E5B7FB284d363DBb4c481F330c25b2A5
NEXT_PUBLIC_DELEGATION_WALL_CONTRACT_ADDRESS=0x78b109462dEB44A5a94000b835ebbD7F078Aa12f

NEXT_PUBLIC_BRIDGE_ADDRESS=0x0000000000000000000000000000001234567890

# Network and services
NEXT_PUBLIC_CHAIN_NAME=sepolia
NEXT_PUBLIC_WEB3_URL_PREFIX=https://eth-sepolia.g.alchemy.com/v2/

NEXT_PUBLIC_ALCHEMY_API_KEY="ALCHEMY KEY"
NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID="YOUR WALLET CONNECT PROJECT ID"
NEXT_PUBLIC_IPFS_ENDPOINT="https://..."
NEXT_PUBLIC_IPFS_API_KEY="..."

NEXT_PUBLIC_IPFS_ENDPOINTS="https://domain1/api,https://domain2/api/v0"
NEXT_PUBLIC_PINATA_JWT="..."

NEXT_PUBLIC_ETHERSCAN_API_KEY="OPTIONAL: ETHERSCAN API"

# PRIVATE (scripts)
# PRIVATE (deployment scripts)
DEPLOYMENT_TARGET_CHAIN_ID=sepolia
DEPLOYMENT_WALLET_PRIVATE_KEY="0x..."
DEPLOYMENT_ALCHEMY_API_KEY="..."
Expand Down
2 changes: 2 additions & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ module.exports = {
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-unused-vars": ["warn", { ignoreRestSiblings: true }],
"@typescript-eslint/prefer-nullish-coalescing": "warn",
"@typescript-eslint/no-duplicate-enum-values": "off",
"@typescript-eslint/no-require-imports": "warn",
},
root: true,
};
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,4 @@ yarn-error.log*
next-env.d.ts

# editor
.vscode
.vscode
64 changes: 58 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,64 @@
# Aragonette 🚀
# Aragonette

Welcome to **Aragonette**, the sleek and snappy UI template designed for lightning-fast prototyping with Aragon DAOs and plugins! Built with the power of Next.js and the speed of Bun.js, Aragonette is your go-to toolkit for bringing your Aragon DAO visions to life with style and efficiency. 🎨✨
## Overview

## Getting Started 🏁
This project is the combination of a host UI including common tools and services and a set of example modules:

Before you dive into the world of DAOs and decentralized governance, make sure you have Bun installed on your machine. If not, hop over to [Bun's official documentation](https://bun.sh/) for installation instructions.
### Proposal section

This section displays all the proposals which need to be ratified by the community of token holders. Proposals follow an optimistic governance flow. They created by the Council and token holders have the chance to veto them for a certain amount of time.

This flow attempts to find a good balance between efficiency, agility, prevent spam or attacks and decentralization.

### Multisig Council

This section features a multisig plugin which is only visible to the Council members. It allows to create, approve and eventually relay proposals to the community section described above.

### Security Council

This section is also a multisig plugin, with the difference that a super majority of the Security Council can approve and execute proposals that are time critical. This plugin may be disabled in future iterations of the DAO but for the time being, it allows respond to potential security threats in a much quicker way.

The metadata and the actions of the proposal are encrypted until the proposal has been executed. See [Encryption and decryption flows](#encryption-and-decryption-flows) below.

### Members section

This section shows a recap of the delegates who publish an announcement, as well as the Security Council members. Delegates can use this section to create their own profile while token holders can browse delegates and can eventually delegate to a candidate of their trust.

## Encryption and decryption flows

In proposals where metadata needs to be kept private until the end, we implement a two-layer encryption model which combines symmetric and asymmetric keys.

The data that we need to encrypt includes:
- **Human readable data**, explaining why the proposal should be approved
- The **actions to execute** if the proposal passes

### Encryption steps

1. A user signs a static payload using his/her wallet. The resulting hash is used as a 256-bit private key to generate an ephemeral, in-memory key pair
2. One of the multisig members generates a random symmetric key and uses it to encrypt the metadata and the actions
3. The member fetches the public keys corresponding to the current Security Council members
4. For each member's public key, he uses it to encrypt the key from step (1)
5. This generates a payload with:
- The (symmetrically) encrypted metadata and proposals
- The (asymmetrically) encrypted keys that only each member can recover
6. The payload is pinned on IPFS
- The IPFS URI is published as the proposal metadata
- The hash of the unencrypted metadata is also published as part of the proposal

![](./readme-encryption-flow.png)

### Encryption steps

1. One of the multisig members fetches the proposal, along with the pinned IPFS metadata
2. The member signs the same predefined payload to generate the in-memory key pair
3. The user locates the key that was encrypted for his/her wallet
4. He then uses it as the symmetric key to decrypt the metadata and the proposal actions

![](./readme-decryption-flow.png)

## Getting Started with the UI

Before you start, make sure you have Bun installed on your machine. If not, hop over to [Bun's official documentation](https://bun.sh/) for installation instructions.

Once you're set with Bun, clone this repository to your local machine:

Expand All @@ -20,8 +74,6 @@ bun install
bun dev
```

And voilà! You're now in the fast lane to DAO prototyping. 🌟

## Adding Your Plugin 🧩

Got a plugin idea that's going to revolutionize the Aragon ecosystem? Adding it to Aragonette is as easy as pie:
Expand Down
Binary file modified bun.lockb
Binary file not shown.
39 changes: 39 additions & 0 deletions components/MissingContentView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { Button, IllustrationHuman } from "@aragon/ods";
import { ReactNode } from "react";

export const MissingContentView = ({
children,
callToAction,
onClick,
isLoading,
}: {
children: ReactNode;
callToAction?: string;
onClick?: () => any;
isLoading?: boolean;
}) => {
if (!callToAction) {
return (
<div className="w-full">
<p className="text-md text-neutral-400">{children}</p>
<Illustration />
</div>
);
}

return (
<div className="w-full">
<p className="text-md text-neutral-400">{children}</p>
<Illustration />
<div className="flex justify-center">
<Button size="md" variant="primary" isLoading={!!isLoading} onClick={onClick ? onClick : () => {}}>
<span>{callToAction}</span>
</Button>
</div>
</div>
);
};

function Illustration() {
return <IllustrationHuman className="mx-auto my-8 max-w-96" body="VOTING" expression="SMILE_WINK" hairs="CURLY" />;
}
15 changes: 12 additions & 3 deletions components/WalletContainer.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { PUB_ALCHEMY_API_KEY } from "@/constants";
import { PUB_ALCHEMY_API_KEY, PUB_CHAIN } from "@/constants";
import { formatHexString } from "@/utils/evm";
import { MemberAvatar } from "@aragon/ods";
import { useWeb3Modal } from "@web3modal/wagmi/react";
import classNames from "classnames";
import { useEffect } from "react";
import { createClient, http } from "viem";
import { normalize } from "viem/ens";
import { createConfig, useAccount, useEnsAvatar, useEnsName } from "wagmi";
import { createConfig, useAccount, useEnsAvatar, useEnsName, useSwitchChain } from "wagmi";
import { mainnet } from "wagmi/chains";

const config = createConfig({
Expand All @@ -22,7 +23,8 @@ const config = createConfig({
// TODO: update with ODS wallet module - [https://linear.app/aragon/issue/RD-198/create-ods-walletmodule]
const WalletContainer = () => {
const { open } = useWeb3Modal();
const { address, isConnected } = useAccount();
const { address, isConnected, chainId } = useAccount();
const { switchChain } = useSwitchChain();

const { data: ensName } = useEnsName({
config,
Expand All @@ -38,6 +40,13 @@ const WalletContainer = () => {
query: { enabled: !!ensName },
});

useEffect(() => {
if (!chainId) return;
else if (chainId === PUB_CHAIN.id) return;

switchChain({ chainId: PUB_CHAIN.id });
}, [chainId]);

return (
<button
className={classNames(
Expand Down
Loading
Loading