Skip to content

Latest commit

 

History

History
476 lines (348 loc) · 27.2 KB

readmeInJa.md

File metadata and controls

476 lines (348 loc) · 27.2 KB

DAO コミュニティのためのスマートコントラクト

これは DAO コミュニティのスマートコントラクトのリポジトリです。スマートコントラクトは Solidity で書かれ、Foundry フレームワークを使用して開発およびテストされています。

はじめに

これは DAO コミュニティガバナンスのためのスマートコントラクトのリポジトリで、コミュニティのための基本的なツールです。 コミュニティガバナンスのために分離されたツールがあります。これらはスマートコントラクトに基づいて説明されます。

すべてのコントラクトはsrc/フォルダに配置されています。これらはプロトコルのコアコントラクトです。

このリポジトリは以下のスマートコントラクトで構成されています:

  • AmbassadorNft
    • コミュニティのメンバーシップを表す NFT のスマートコントラクト。
    • このスマートコントラクトは他のスマートコントラクトとは独立しています。
    • コントラクトは OpenZeppelin の ERC1155 コントラクトに基づいています。
  • ERC20UpgradeableTokenV1
    • コミュニティのユーティリティトークンを表す ERC20 トークンのスマートコントラクト。
    • その使用例は、コミュニティのガバナンストークンと交換することです。
    • 他の使用例も可能で、コミュニティによって定義されます。
    • コントラクトは OpenZeppelin の ERC20Upgradeable コントラクトに基づいています。
  • GovToken
    • コミュニティのガバナンストークンとして機能するスマートコントラクト。
    • このトークンは、譲渡不可能な保有者の投票力を表すために使用されます。
    • コントラクトは OpenZeppelin の ERC20Votes コントラクトに基づいています。
  • VotingPowerExchange
    • コミュニティの投票力交換のためのスマートコントラクト。
    • このコントラクトは、ユーザーが保有するユーティリティトークンを燃焼してガバナンストークンを取得するために使用されます。
    • このコントラクトはゼロから作成されています。
  • DaoGovernor
    • コミュニティの DAO ガバナンスのためのスマートコントラクト。
    • このコントラクトは、より分散化された方法でコミュニティの提案を管理するために使用されます。
    • コントラクトは OpenZeppelin の Governor コントラクトに基づいています。
  • Timelock
    • コミュニティのタイムロックのためのスマートコントラクト。
    • このコントラクトは DaoGovernor コントラクトの所有者になります。

ロール

システムは異なるロールによって管理されます。ロールはデフォルトの管理者ロールによって管理されます。

  • DEFAULT_ADMIN_ROLE: デフォルトの管理者ロールはコントラクトの所有者です。
    • これはコントラクト内で最高の権限を持つロールです。
    • 責任: 他のすべてのロールを管理する権限を持ちます。
    • 機能: 他のすべてのロールを付与および取り消すことができます。
  • MANAGER_ROLE:
    • 責任: コントラクトを管理し、特別な機能を呼び出すことができます。
    • 機能: setVotingPowerCap()
  • EXCHANGER_ROLE: 交換ロールは、ガバナンストークンをユーティリティトークンと交換できるロールです。
    • 責任: ガバナンストークンをユーティリティトークンと交換できます。
    • 機能: exchange()
  • MINTER_ROLE: ミンターロールは新しいトークンを発行できるロールです。
    • 責任: アンバサダー NFT、ユーティリティトークン、ガバナンストークンの新しいトークンを発行できます。
    • 機能: mint(), mintBatch()
  • BURNER_ROLE: バーナーロールはアンバサダー NFT、ユーティリティトークン、ガバナンストークンのトークンを燃焼できるロールです。
    • 責任: トークンを燃焼できます。
    • 機能: burn(), burnBatch(),burnByBurner()
  • URI_SETTER_ROLE: URI セッターロールはトークンの URI を設定できるロールです。
    • 責任: トークンの URI を設定できます。
    • 機能: setURI()
  • UPGRADER_ROLE: アップグレーダーロールはコントラクトをアップグレードできるロールです。
    • 責任: コントラクトをアップグレードできます。
    • 機能: upgradeToAndCall()

スマートコントラクト

AmbassadorNft.sol

これはコミュニティのメンバーシップを表す NFT のスマートコントラクトです。可能な使用例と NFT の機能について説明します。

このコントラクトは、現在のシステムの他のスマートコントラクトとは独立しています。

可能な使用例と機能の説明

この NFT はコミュニティのメンバーシップを表すために使用できます。例えば、メンバーシップ A は NFT1155 の ID 0 で表され、メンバーシップ B は NFT1155 の ID 1 で表されます。NFT を保有する人は誰でもコミュニティのメンバーとみなされます。

デフォルトの管理者ロールは、ミンターとバーナーのロールを設定する権利を持ちます。ミンターロールは新しいトークンを発行できるロールです。バーナーロールは指定されたアカウントからトークンを燃焼できるロールです。

NFT をバッチで発行および燃焼する機能があります。これらの機能により、ミンターとバーナーのロールはメンバーのために NFT を簡単に発行および燃焼できます。

また、NFT の URI はコントラクトのデプロイ後に URI セッターロールによって設定できます。

ERC20UpgradeableTokenV1.sol

これはコミュニティのユーティリティトークンを表す ERC20 トークンのスマートコントラクトです。このユーティリティトークンは譲渡可能です。

使用例と機能の説明

このトークンはコミュニティのユーティリティトークンとして使用され、ミッションの遂行やコミュニティのための他の活動によって獲得できます。ユーザーはユーティリティトークンを使用してガバナンストークンと交換できます。

デフォルトの管理者ロールは、ミンターとバーナーのロールを設定する権利を持ちます。ミンターロールは新しいトークンを発行できるロールです。バーナーロールは指定されたアカウントからトークンを燃焼できるロールです。

コントラクト自体は一時停止可能です。ポーザーロールはコントラクトを一時停止および再開できるロールです。コントラクトが一時停止されている場合、トークンの発行と譲渡は無効になります。

注意点

  • コントラクトはアップグレード可能、一時停止可能、および ERC20Permit 準拠です。

GovToken.sol

これはコミュニティのガバナンストークンのスマートコントラクトです。コントラクトは OpenZeppelin の ERC20Votes コントラクトに基づいています。コントラクトは、保有者が燃焼したユーティリティトークンの量も記録します。

投票力交換コントラクトのみが、保有者が燃焼したユーティリティトークンの量を更新する権利を持ちます。

使用例と機能の説明

このトークンは保有者の投票力を表すために使用されます。トークンは譲渡不可能です。同時に、保有者のレベルを表すためにも使用されます。例えば、レベルが高いほど、保有者はより多くの投票力を持ちます。 例えば、1 トークンを保有することは保有者がレベル 2 であることを意味します。0 トークンを保有することは保有者がレベル 1 であることを意味します。

トークンは譲渡不可能です。つまり、トークン保有者は他のアドレスにトークンを譲渡できません。

ERC20Permit はここで継承されています。これは、OpenZeppelin のウィザードがそうしているためであり、私たちはそのコードに従いました。これは比較的安全な方法だと考えています。

注意点

このトークンをプロトコルで利用する際には 2 つのフェーズがあります。フェーズ 1 として開始した後、コミュニティガバナンスは観察下に置かれます。フェーズ 1 が安定し成熟したら、将来的にフェーズ 2 に徐々に移行します。

  • フェーズ 1: トークンを使用して保有者の投票力を表します。そして、ガバナンス参加者のトークン残高を使用してオフチェーンでガバナンスを管理します。
フェーズ1
  • フェーズ 2: トークンを使用して保有者の投票力、つまりレベルを表します。そして、ガバナンス参加者のトークン残高を使用してオンチェーンでガバナンスを管理します。
フェーズ2

GovToken は、ある意味で達成記録係です。私たちは、達成システムがすべての参加者にとって透明で検証可能であることを確認したいと考えています。そのため、このトークンをアップグレード可能にしませんでした。

実際、トークンの投票単位は、実際の投票力としてカウントされるために誰かに委任されなければなりません。その理由は、OpenZeppelin コントラクトのドキュメントに記載されています。

実際、投票単位は実際の投票としてカウントされるために委任されなければなりません。アカウントが決定に参加したい場合や信頼できる代表者がいない場合は、その投票をアカウント自身に委任する必要があります。

VotingPowerExchange.sol

このコントラクトは、ユーティリティトークンをガバナンストークンと交換するために使用されます。交換は、ガバナンストークンを燃焼し、ユーティリティトークンを発行することで行われます。

投票力交換コントラクトは、ガバナンストークンのミンターであり、ユーティリティトークンのバーナーです。

使用例と機能の説明

このコントラクトには、保有者が燃焼したユーティリティトークンに基づいて、保有者が受け取るべきガバナンストークンの量を計算するいくつかの機能があります。

主要な機能はexchange()です。この機能は交換者ロールのみが呼び出すことができます。 交換者ロールは、プロトコル所有者によって管理されることを想定しています。

この機能は、まず送信者の署名を含む入力の有効性をチェックします。署名はオフチェーンで生成され、送信者自身によってのみ生成できます。

これにより、送信者自身がそのような量のトークンを交換する意図を持っていることを確認します。このようにして、交換者ロールが悪用されるのを防ぎたいと考えています。

さらに、この機能は署名のノンスと有効期限をチェックして、署名が新しく有効であることを確認します。

その後、保有者が受け取るべきガバナンストークンの量を計算します。

計算は、参考資料セクションの数学的公式に基づいています。

コントラクトは、保有者が取得できるガバナンストークンの量に上限を設定します。

誰かが上限以下で、上限を超えるユーティリティトークンを交換する場合、この機能は上限が許可する量のトークンのみを交換します。

誰かがすでに上限に達している場合、この機能は交換を許可しません。

誰も上限を超える投票力を得ることはできません。

計算後、この機能は保有者にガバナンストークンを発行し、保有者からユーティリティトークンを燃焼します。

この機能は、GovToken コントラクトで保有者が燃焼したユーティリティトークンの量も更新します。

注意点

  • このコントラクトはゼロから作成されています。
  • 計算の精度のために使用されるいくつかの変数があります。
  • SafeERC20は使用されていません。なぜなら、私たちが使用しているトークンコントラクトは安全であることが知られているからです。

DaoGovernor.sol

これはコミュニティの DAO ガバナンスのためのスマートコントラクトです。コントラクトは OpenZeppelin の Governor コントラクトに基づいています。

このコントラクトは、コミュニティガバナンスのフェーズ 2 で使用されます。

使用例と機能の説明

  • 基本的なガバナー機能(提案の作成、投票、実行)
  • 設定可能なガバナンス設定(投票遅延、投票期間、提案閾値)
  • 投票力のための ERC20Votes トークンとの統合
  • 総供給量の一部に基づく定足数要件
  • 遅延実行のためのタイムロック統合

主要な特徴とパラメータ:

  • 投票遅延:1 日(提案作成から投票開始までの時間)
    • 後で変更可能
  • 投票期間:1 週間(投票フェーズの期間)
    • 後で変更可能
  • 提案閾値:1e18 トークン(提案を作成するために必要な最小トークン)
    • 後で変更可能
  • 定足数:総トークン供給量の 1%(有効な投票のための最小参加)

注意点

  • このコントラクトは、特定の ERC20Votes トークン(おそらく前述の GovToken)と TimelockController と連携するように設計されています。
  • いくつかのパラメータ(投票遅延、投票期間、提案閾値、定足数)は、コントラクトがデプロイされたときのセットアップのためにコンストラクタでハードコードされています。
  • このコントラクトは OpenZeppelin の最新のコントラクト(v5.0.0)を使用しており、最新のセキュリティ機能とベストプラクティスを確保しています。
  • このコントラクトは、コミュニティガバナンスがフェーズ 2 で完全に分散化される準備ができたときに使用されることを想定しています。

Timelock.sol

Timelock.solコントラクトは、OpenZeppelin のTimelockControllerに基づいたタイムロックコントローラーです。

このコントラクトは、コミュニティガバナンスのフェーズ 2 で使用されます。

使用例と機能の説明

主な目的と機能は以下の通りです:

  1. 遅延実行:可決された提案に対して必須の待機期間を提供し、ガバナンスのセキュリティを強化します。
  2. アクセス制御:どのアドレスが操作を提案、実行、またはキャンセルできるかを管理します。提案者または実行者として address(0)が設定されている場合、誰でも提案または実行できます。
  3. 透明性:すべての保留中の操作は公開され、コミュニティメンバーがレビューし反応する時間を与えます。

DaoGovernor で提案が可決されると、タイムロックにキューイングされます。所定の遅延後、実際の実行はタイムロックによって行われます。

注意点

  • コントラクトの管理者ロールは最初に設定され、後で取り消すことが推奨されます。
  • 実行者ロールは最初に address(0)に設定できると想定しています。これは誰でも実行できることを意味します。そして、提案者ロールは最初にガバナーコントラクトに設定されます。これはガバナーコントラクトのみが提案する権利を持つことを意味します。
  • テストケースでタイムロックに gov トークンを発行するミンターロールを付与する必要がある理由:
    • 提案が可決されると、キュー操作が呼び出され、タイムロックの実際に呼び出される関数はscheduledBatch()です。その後、DaoGovernor のexecute()関数は誰でも呼び出して提案を実行できます。そしてこの関数はタイムロックのexecuteBatch()関数を呼び出して提案を実行します。実際の実行者はタイムロックです。

ガバナンスフロー

ユーザー A に gov トークンを発行するためにガバナンスを使用するテストケースのコードに書かれているように、ガバナンスのフローは以下の通りです:

準備:

  • ユーザー A はいくつかの投票力を持っています。
  1. 提案の値、ターゲット、コールデータ、説明を準備します。
  2. しばらくして、ユーザー A が提案を作成します:daoGovernor.propose()
  3. いくつかのユーザーが提案に投票します:daoGovernor.castVote()
  4. 提案はタイムロックにキューイングされます:daoGovernor.queue()
  5. 遅延後、誰でもこの関数を呼び出すことができます:daoGovernor.execute()
  6. トークンがユーザー A に発行されます。

監査について

スコープ

  • src/
    • AmbassadorNft.sol
    • ERC20UpgradeableTokenV1.sol
    • GovToken.sol
    • VotingPowerExchange.sol
    • DaoGovernor.sol
    • Timelock.sol

スコープ外

上記のスコープにあるファイル以外のすべてのファイル。

既知の問題

  • 2 段階の所有権移転プロセスは既知の問題です。私たちはそのリスクを受け入れています。
  • 投票力と燃焼されたトークンの計算における精度の損失は存在しますが、それによって引き起こされる価値の損失は非常に小さく(例:1e9 トークン)、無視できます。

いくつかの注意点

  • 平方根計算を含む数学的公式(参考資料セクションで言及)を使用しているため、計算において精度の損失が発生します。例えば、理論的に 1e9 ユーティリティトークンをガバナンストークンと交換する場合、得られるのは 0 トークンです。そしてユーザーは理由なくシステムにガス料金を消費させるためにリクエストをスパムする可能性があります。これを考慮して、誰かがexchange関数を呼び出したい場合、ユーティリティトークンの値を少なくとも 1e18 にしました。
  • テスト(ファジングテストも含む)がすべてのエッジケースをカバーできていない可能性があります。問題を見つけた場合は、お知らせください。

テスト

テストはtest/ディレクトリに書かれています。以下のテストで構成されています:

  • ユニットテスト:test/unit/
  • 統合テスト:test/integration/
  • ファジングテスト:test/fuzz/

テストに関する詳細な情報はtest/readme.mdに記載されています。テストの詳細については、そちらを参照してください。

始め方

  1. リポジトリをクローンする
git clone https://github.com/codefox-inc/dao-community-contracts.git
  1. 依存関係を更新する
foundryup
  1. 依存関係をインストールする
make install
  1. 以下のコマンドでコントラクトをコンパイルします
forge compile
  1. 以下のコマンドでテストを実行します
make test
  1. 以下のコマンドでカバレッジを実行します
make coverage

参考資料

数学的公式と表 これらは、投票力 <-> バーントークン計算のための交換関数とテストで使用した値です。


x = (2 * sqrt(306.25 + 30y) - 5) / 30 - 1
y = (15*x^2+35\*x)/2

x: 発行されたトークン
y: バーンされたトークン

Minted Token (lvl) Level Burned Token
0 1 0
1 2 25
2 3 65
3 4 120
4 5 190
5 6 275
6 7 375
7 8 490
8 9 620
9 10 765
10 11 925
11 12 1100
12 13 1290
13 14 1495
14 15 1715
15 16 1950
16 17 2200
17 18 2465
18 19 2745
19 20 3040
20 21 3350
21 22 3675
22 23 4015
23 24 4370
24 25 4740
25 26 5125
26 27 5525
27 28 5940
28 29 6370
29 30 6815
30 31 7275
31 32 7750
32 33 8240
33 34 8745
34 35 9265
35 36 9800
36 37 10350
37 38 10915
38 39 11495
39 40 12090
40 41 12700
41 42 13325
42 43 13965
43 44 14620
44 45 15290
45 46 15975
46 47 16675
47 48 17390
48 49 18120
49 50 18865
50 51 19625
51 52 20400
52 53 21190
53 54 21995
54 55 22815
55 56 23650
56 57 24500
57 58 25365
58 59 26245
59 60 27140
60 61 28050
61 62 28975
62 63 29915
63 64 30870
64 65 31840
65 66 32825
66 67 33825
67 68 34840
68 69 35870
69 70 36915
70 71 37975
71 72 39050
72 73 40140
73 74 41245
74 75 42365
75 76 43500
76 77 44650
77 78 45815
78 79 46995
79 80 48190
80 81 49400
81 82 50625
82 83 51865
83 84 53120
84 85 54390
85 86 55675
86 87 56975
87 88 58290
88 89 59620
89 90 60965
90 91 62325
91 92 63700
92 93 65090
93 94 66495
94 95 67915
95 96 69350
96 97 70800
97 98 72265
98 99 73745
99 100 75240
100 101 76750
101 102 78275
102 103 79815
103 104 81370
104 105 82940
105 106 84525
106 107 86125
107 108 87740
108 109 89370
109 110 91015
110 111 92675

....

Documents

開発者向けの注意事項

  1. すべてのコントラクトはデプロイされる必要があります。その後、Web2 側から接続することができます。

    1. phase 1 では、下記画像にあるようになります。
  2. ユーザーに代わってリレーヤーが呼び出す必要がある主要な関数はexchange()関数です。

    1. この関数を呼び出すために、ユーザーは自身の秘密鍵で署名して独自の署名を生成する必要があります。
    2. 信頼されたリレーヤーは、署名されたメッセージを使用してこの関数を呼び出します。ガス代はリレーやーが負担します。
  3. 一部のデータはオンチェーンのコントラクトに保存されます。ただし、開発者はこのデータをデータベースにも保存するかどうかを決定できます。二重管理もやむを得ず可能になったりすると考えています。

  4. 特別な役割を持つ一部のアカウントは、最初にコントラクト内で初期化されます。言うまでもありませんが、これらのアカウントは慎重に扱われるべきです。

フェーズ1