├── .gitignore
├── LICENSE
├── README.md
├── frontend
├── README.md
├── package-lock.json
├── package.json
├── public
│ ├── favicon.ico
│ ├── index.html
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ └── robots.txt
└── src
│ ├── App.css
│ ├── App.js
│ ├── App.test.js
│ ├── components
│ └── Inputs.js
│ ├── contractABIs
│ ├── daoDealClientABI.json
│ └── governorABI.json
│ ├── index.css
│ ├── index.js
│ ├── logo.svg
│ ├── propose.js
│ ├── reportWebVitals.js
│ └── setupTests.js
└── hardhat
├── .env.example
├── .gitattributes
├── .gitmodules
├── .gitpod.yml
├── .npmignore
├── .prettierignore
├── .prettierrc
├── .solcover.js
├── .solhint.json
├── .solhintignore
├── README.md
├── contracts
├── DaoDealClient.sol
├── DataGovernanceToken.sol
├── GovernorContract.sol
└── TimeLock.sol
├── deploy
├── 01-data-governance-token-deploy.js
├── 02-time-lock-deploy.js
├── 03-governor-contract-deploy.js
├── 04-setup-roles.js
└── 05-dao-deal-client-deploy.js
├── hardhat.config.js
├── helper-hardhat-config.js
├── package.json
├── proposals.json
├── scripts
├── lighthouse-sdk
│ ├── get-api-key.mjs
│ └── upload-file.mjs
├── propose.js
├── queue-and-execute.js
└── vote.js
├── tasks
├── cid-to-bytes.js
├── get-address.js
└── index.js
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | # vscode
2 | .vscode
3 |
4 | # hardhat
5 | artifacts
6 | cache
7 | deployments
8 | node_modules
9 | coverage
10 | coverage.json
11 | typechain
12 |
13 | # Never push your environment files!
14 | .env
15 |
16 | # Built application files
17 | .DS*
18 | *.apk
19 | *.ap_
20 | *.aab
21 |
22 | # Files for the ART/Dalvik VM
23 | *.dex
24 |
25 | # Java class files
26 | *.class
27 |
28 | # Generated files
29 | bin/
30 | gen/
31 | out/
32 | # Uncomment the following line in case you need and you don't have the release build type files in your app
33 | # release/
34 |
35 | # Gradle files
36 | .gradle/
37 | build/
38 |
39 | # Local configuration file (sdk path, etc)
40 | local.properties
41 |
42 | # Proguard folder generated by Eclipse
43 | proguard/
44 |
45 | # Log Files
46 | *.log
47 |
48 | # Android Studio Navigation editor temp files
49 | .navigation/
50 |
51 | # Android Studio captures folder
52 | captures/
53 |
54 | # IntelliJ
55 | *.iml
56 | .idea/workspace.xml
57 | .idea/tasks.xml
58 | .idea/gradle.xml
59 | .idea/assetWizardSettings.xml
60 | .idea/dictionaries
61 | .idea/libraries
62 | # Android Studio 3 in .gitignore file.
63 | .idea/caches
64 | .idea/modules.xml
65 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you
66 | .idea/navEditor.xml
67 |
68 | # Keystore files
69 | # Uncomment the following lines if you do not want to check your keystore files in.
70 | #*.jks
71 | #*.keystore
72 |
73 | # External native build folder generated in Android Studio 2.2 and later
74 | .externalNativeBuild
75 |
76 | # Google Services (e.g. APIs or Firebase)
77 | # google-services.json
78 |
79 | # Freeline
80 | freeline.py
81 | freeline/
82 | freeline_project_description.json
83 |
84 | # fastlane
85 | fastlane/report.xml
86 | fastlane/Preview.html
87 | fastlane/screenshots
88 | fastlane/test_output
89 | fastlane/readme.md
90 |
91 | # Version control
92 | vcs.xml
93 |
94 | # lint
95 | lint/intermediates/
96 | lint/generated/
97 | lint/outputs/
98 | lint/tmp/
99 | # lint/reports/
100 |
101 | gas-report.txt
102 |
103 | contracts/test/fuzzing/crytic-export
104 |
105 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
106 |
107 | # dependencies
108 | /node_modules
109 | /.pnp
110 | .pnp.js
111 |
112 | # testing
113 | /coverage
114 |
115 | # production
116 | /build
117 |
118 | # misc
119 | .DS_Store
120 | .env.local
121 | .env.development.local
122 | .env.test.local
123 | .env.production.local
124 |
125 | npm-debug.log*
126 | yarn-debug.log*
127 | yarn-error.log*
128 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 ZakAyesh
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # FEVM-Data-DAO-Kit
2 |
3 | This is a beta kit to demo how to build a basic Decentralized Autonomous Organization (DAO) on Filecoin.
4 |
5 | ## About This Repo
6 |
7 | Start out in the "hardhat" directory and follow the readme there to begin deploying and interacting with contracts.
8 |
9 | Then go to the "frontend" directory to run an example frontend!
10 |
11 |
12 |
--------------------------------------------------------------------------------
/frontend/README.md:
--------------------------------------------------------------------------------
1 | # Getting Started with Create React App
2 |
3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
4 |
5 | ## Available Scripts
6 |
7 | In the project directory, you can run:
8 |
9 | ### `npm start`
10 |
11 | Runs the app in the development mode.\
12 | Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
13 |
14 | The page will reload when you make changes.\
15 | You may also see any lint errors in the console.
16 |
17 | ### `npm test`
18 |
19 | Launches the test runner in the interactive watch mode.\
20 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
21 |
22 | ### `npm run build`
23 |
24 | Builds the app for production to the `build` folder.\
25 | It correctly bundles React in production mode and optimizes the build for the best performance.
26 |
27 | The build is minified and the filenames include the hashes.\
28 | Your app is ready to be deployed!
29 |
30 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
31 |
32 | ### `npm run eject`
33 |
34 | **Note: this is a one-way operation. Once you `eject`, you can't go back!**
35 |
36 | If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
37 |
38 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own.
39 |
40 | You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it.
41 |
42 | ## Learn More
43 |
44 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
45 |
46 | To learn React, check out the [React documentation](https://reactjs.org/).
47 |
48 | ### Code Splitting
49 |
50 | This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)
51 |
52 | ### Analyzing the Bundle Size
53 |
54 | This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)
55 |
56 | ### Making a Progressive Web App
57 |
58 | This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)
59 |
60 | ### Advanced Configuration
61 |
62 | This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)
63 |
64 | ### Deployment
65 |
66 | This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)
67 |
68 | ### `npm run build` fails to minify
69 |
70 | This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)
71 |
--------------------------------------------------------------------------------
/frontend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dao-frontend",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^5.16.5",
7 | "@testing-library/react": "^13.4.0",
8 | "@testing-library/user-event": "^13.5.0",
9 | "cids": "^1.1.9",
10 | "ethers": "^6.6.0",
11 | "react": "^18.2.0",
12 | "react-bootstrap": "^2.8.0",
13 | "react-dom": "^18.2.0",
14 | "react-icons": "^4.10.1",
15 | "react-scripts": "5.0.1",
16 | "react-tooltip": "^5.15.0",
17 | "web-vitals": "^2.1.4"
18 | },
19 | "scripts": {
20 | "start": "react-scripts start",
21 | "build": "react-scripts build",
22 | "test": "react-scripts test",
23 | "eject": "react-scripts eject"
24 | },
25 | "eslintConfig": {
26 | "extends": [
27 | "react-app",
28 | "react-app/jest"
29 | ]
30 | },
31 | "browserslist": {
32 | "production": [
33 | ">0.2%",
34 | "not dead",
35 | "not op_mini all"
36 | ],
37 | "development": [
38 | "last 1 chrome version",
39 | "last 1 firefox version",
40 | "last 1 safari version"
41 | ]
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/frontend/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/filecoin-project/fevm-data-dao-kit/de87cc1ff379629cf3e939c7c797cb8b89f564b3/frontend/public/favicon.ico
--------------------------------------------------------------------------------
/frontend/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | React App
28 |
29 |
30 | You need to enable JavaScript to run this app.
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/frontend/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/filecoin-project/fevm-data-dao-kit/de87cc1ff379629cf3e939c7c797cb8b89f564b3/frontend/public/logo192.png
--------------------------------------------------------------------------------
/frontend/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/filecoin-project/fevm-data-dao-kit/de87cc1ff379629cf3e939c7c797cb8b89f564b3/frontend/public/logo512.png
--------------------------------------------------------------------------------
/frontend/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/frontend/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/frontend/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | height: 40vmin;
7 | pointer-events: none;
8 | }
9 |
10 | @media (prefers-reduced-motion: no-preference) {
11 | .App-logo {
12 | animation: App-logo-spin infinite 20s linear;
13 | }
14 | }
15 |
16 | .App-header {
17 | background-color: #282c34;
18 | min-height: 100vh;
19 | display: flex;
20 | flex-direction: column;
21 | align-items: center;
22 | justify-content: center;
23 | font-size: calc(10px + 2vmin);
24 | color: white;
25 | }
26 |
27 | .App-link {
28 | color: #61dafb;
29 | }
30 |
31 | @keyframes App-logo-spin {
32 | from {
33 | transform: rotate(0deg);
34 | }
35 | to {
36 | transform: rotate(360deg);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/frontend/src/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Inputs from './components/Inputs';
3 | import "./App.css";
4 |
5 | function App() {
6 |
7 | return (
8 |
9 |
10 |
11 | );
12 | }
13 |
14 | export default App;
--------------------------------------------------------------------------------
/frontend/src/App.test.js:
--------------------------------------------------------------------------------
1 | import { render, screen } from '@testing-library/react';
2 | import App from './App';
3 |
4 | test('renders learn react link', () => {
5 | render( );
6 | const linkElement = screen.getByText(/learn react/i);
7 | expect(linkElement).toBeInTheDocument();
8 | });
9 |
--------------------------------------------------------------------------------
/frontend/src/components/Inputs.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import governorContractABI from "../contractABIs/governorABI.json";
3 | import daoDealClientABI from "../contractABIs/daoDealClientABI.json";
4 | import "react-tooltip/dist/react-tooltip.css";
5 | import { Tooltip } from "react-tooltip";
6 | import { ethers } from "ethers";
7 | import { AiOutlineQuestionCircle } from "react-icons/ai";
8 | import Spinner from 'react-bootstrap/Spinner';
9 | const CID = require("cids");
10 |
11 | // Replace this address with the address of own instance of the deal client contract
12 | const governorContractAddress = "0xb57724c0cB71C4a9a967c586CcF54d2Da8234028";
13 | const daoDealClientAddress = "0x116de3162285EaD343E9C88b5c5d101596930128";
14 | let governor;
15 | let cid;
16 |
17 | function Inputs() {
18 | // Initialize with some dummy working default values
19 | const [commP, setCommP] = useState(
20 | "baga6ea4seaqkp2pjlh6avlvee6ib2maanav5sc35l5glf3zm6rd6hmfgcx5xeji"
21 | );
22 | const [carLink, setCarLink] = useState(
23 | "https://data-depot.lighthouse.storage/api/download/download_car?fileId=862fb115-d24a-4ff1-a1c8-eadbbbfd19cf.car"
24 | );
25 | const [errorMessageSubmit, setErrorMessageSubmit] = useState("");
26 | const [pieceSize, setPieceSize] = useState("32768");
27 | const [carSize, setCarSize] = useState("18445");
28 | const [proposalDescription, setProposalDescription] = useState("Test Proposal Description");
29 | const [txSubmitted, setTxSubmitted] = useState("");
30 | const [dealID, setDealID] = useState("");
31 | const [proposingDeal, setProposingDeal] = useState(false);
32 | const [network, setNetwork] = useState("");
33 |
34 | const handleChangeCommP = (event) => {
35 | setCommP(event.target.value);
36 | };
37 |
38 | const handleChangeCarLink = (event) => {
39 | // validate input data here
40 | setCarLink(event.target.value);
41 | };
42 |
43 | const handleChangePieceSize = (event) => {
44 | setPieceSize(event.target.value);
45 | };
46 |
47 | const handleChangeCarSize = (event) => {
48 | setCarSize(event.target.value);
49 | };
50 |
51 | const handleChangeProposalDescription = (event) => {
52 | setProposalDescription(event.target.value);
53 | };
54 |
55 |
56 | const handleSubmit = async (event) => {
57 | // This will be handling deal proposal submission sometime in the future.
58 | event.preventDefault();
59 | // do something with the carLink value, like send it to a backend API
60 | console.log(commP);
61 | console.log(carLink);
62 | console.log(pieceSize);
63 | console.log(carSize);
64 |
65 | try {
66 | setErrorMessageSubmit(
67 | ""
68 | );
69 | cid = new CID(commP);
70 | const { ethereum } = window;
71 | if (ethereum) {
72 | const provider = new ethers.BrowserProvider(ethereum);
73 | const signer = await provider.getSigner();
74 | governor = new ethers.Contract(
75 | governorContractAddress,
76 | governorContractABI,
77 | signer
78 | );
79 | const extraParamsV1 = [
80 | carLink,
81 | carSize,
82 | false, // taskArgs.skipIpniAnnounce,
83 | false, // taskArgs.removeUnsealedCopy
84 | ];
85 | const DealRequestStruct = [
86 | cid.bytes, //cidHex
87 | pieceSize, //taskArgs.pieceSize,
88 | false, //taskArgs.verifiedDeal,
89 | commP, //taskArgs.label,
90 | 520000, // startEpoch
91 | 1555200, // endEpoch
92 | 0, // taskArgs.storagePricePerEpoch,
93 | 0, // taskArgs.providerCollateral,
94 | 0, // taskArgs.clientCollateral,
95 | 1, //taskArgs.extraParamsVersion,
96 | extraParamsV1,
97 | ];
98 | // console.log(await provider.getBalance("0x42c930a33280a7218bc924732d67dd84d6247af4"));
99 | console.log(governor.interface);
100 | const encodedFunctionCall =
101 | daoDealClientABI.encodeFunctionData("makeDealProposal", [DealRequestStruct]);
102 | const transaction = await governor.propose(
103 | [daoDealClientAddress],
104 | [0],
105 | [encodedFunctionCall],
106 | proposalDescription
107 | );
108 | console.log("Proposing deal to DAO...");
109 | setProposingDeal(true);
110 | const receipt = await transaction.wait();
111 | console.log(receipt);
112 | setProposingDeal(false);
113 | setTxSubmitted("Transaction submitted! " + receipt.hash);
114 |
115 | governor.on("DealProposalCreate", (id, size, verified, price)=>{
116 | console.log(id, size, verified, price);
117 | })
118 |
119 | console.log("Deal proposed! CID: " + cid);
120 | } else {
121 | console.log("Ethereum object doesn't exist!");
122 | }
123 | } catch (error) {
124 | console.log(error);
125 | setErrorMessageSubmit(
126 | "Something went wrong. " + error.name + " " + error.message
127 | );
128 | return;
129 | }
130 | };
131 |
132 | const checkWalletIsConnected = async () => {
133 | const { ethereum } = window;
134 | if (!ethereum) {
135 | console.log("Make sure you have metamask!");
136 | return;
137 | } else {
138 | console.log("We have the ethereum object", ethereum);
139 | }
140 | const provider = new ethers.BrowserProvider(ethereum);
141 | const network = await provider.getNetwork();
142 | setNetwork(network.chainId);
143 | console.log(network.chainId);
144 |
145 | ethereum.request({ method: "eth_accounts" }).then((accounts) => {
146 | if (accounts.length !== 0) {
147 | const account = accounts[0];
148 | console.log("Found an account:", account);
149 | } else {
150 | console.log("No account found");
151 | }
152 | });
153 | };
154 |
155 | const connectWalletHandler = () => {
156 | const { ethereum } = window;
157 | if (!ethereum) {
158 | alert("Get MetaMask!");
159 | return;
160 | }
161 | ethereum
162 | .request({ method: "eth_requestAccounts" })
163 | .then((accounts) => {
164 | console.log("Connected", accounts[0]);
165 | })
166 | .catch((err) => console.log(err));
167 | };
168 |
169 | const connectWalletButton = () => {
170 | return (
171 |
172 |
176 | Connect Wallet
177 |
178 | { window &&
Connected
}
179 | { network &&
Network: Calibration
}
180 |
181 | );
182 | };
183 |
184 | const dealIDButton = () => {
185 | return (
186 |
189 | Get deal ID
190 |
191 | );
192 | };
193 |
194 | const dealIDHandler = async () => {
195 | setDealID("Waiting for acceptance by SP...");
196 | cid = new CID(commP);
197 | var refresh = setInterval(async () => {
198 | console.log(cid.bytes);
199 | if (cid === undefined) {
200 | setDealID("Error: CID not found");
201 | clearInterval(refresh);
202 | }
203 | console.log("Checking for deal ID...");
204 | const dealID = await governor.pieceDeals(cid.bytes);
205 | console.log(dealID);
206 | if (dealID !== undefined && dealID !== "0") {
207 | // If your deal has already been submitted, you can get the deal ID by going to https://calibration.filfox.info/en/deal/
208 | // The link will show up in the frontend: once a deal has been submitted, its deal ID stays constant. It will always have the same deal ID.
209 | setDealID("https://calibration.filfox.info/en/deal/" + dealID);
210 | clearInterval(refresh);
211 | }
212 | }, 5000
213 | );
214 | };
215 |
216 | useEffect(() => {
217 | checkWalletIsConnected();
218 | }, []);
219 |
220 | return (
221 |
222 |
223 |
224 | Basic DataDAO FrontEnd
225 |
226 |
227 | {connectWalletButton()}
228 |
229 |
230 |
359 |
360 |
361 |
362 |
363 |
364 |
365 | );
366 | }
367 |
368 | export default Inputs;
--------------------------------------------------------------------------------
/frontend/src/contractABIs/daoDealClientABI.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "inputs": [
4 | {
5 | "internalType": "int256",
6 | "name": "errorCode",
7 | "type": "int256"
8 | }
9 | ],
10 | "name": "ActorError",
11 | "type": "error"
12 | },
13 | {
14 | "inputs": [],
15 | "name": "ActorNotFound",
16 | "type": "error"
17 | },
18 | {
19 | "inputs": [],
20 | "name": "FailToCallActor",
21 | "type": "error"
22 | },
23 | {
24 | "inputs": [],
25 | "name": "InvalidAddress",
26 | "type": "error"
27 | },
28 | {
29 | "inputs": [
30 | {
31 | "internalType": "uint64",
32 | "name": "",
33 | "type": "uint64"
34 | }
35 | ],
36 | "name": "InvalidCodec",
37 | "type": "error"
38 | },
39 | {
40 | "inputs": [],
41 | "name": "InvalidResponseLength",
42 | "type": "error"
43 | },
44 | {
45 | "inputs": [],
46 | "name": "NegativeValueNotAllowed",
47 | "type": "error"
48 | },
49 | {
50 | "inputs": [
51 | {
52 | "internalType": "uint256",
53 | "name": "balance",
54 | "type": "uint256"
55 | },
56 | {
57 | "internalType": "uint256",
58 | "name": "value",
59 | "type": "uint256"
60 | }
61 | ],
62 | "name": "NotEnoughBalance",
63 | "type": "error"
64 | },
65 | {
66 | "anonymous": false,
67 | "inputs": [
68 | {
69 | "indexed": true,
70 | "internalType": "bytes32",
71 | "name": "id",
72 | "type": "bytes32"
73 | },
74 | {
75 | "indexed": false,
76 | "internalType": "uint64",
77 | "name": "size",
78 | "type": "uint64"
79 | },
80 | {
81 | "indexed": true,
82 | "internalType": "bool",
83 | "name": "verified",
84 | "type": "bool"
85 | },
86 | {
87 | "indexed": false,
88 | "internalType": "uint256",
89 | "name": "price",
90 | "type": "uint256"
91 | }
92 | ],
93 | "name": "DealProposalCreate",
94 | "type": "event"
95 | },
96 | {
97 | "anonymous": false,
98 | "inputs": [
99 | {
100 | "indexed": true,
101 | "internalType": "address",
102 | "name": "previousOwner",
103 | "type": "address"
104 | },
105 | {
106 | "indexed": true,
107 | "internalType": "address",
108 | "name": "newOwner",
109 | "type": "address"
110 | }
111 | ],
112 | "name": "OwnershipTransferred",
113 | "type": "event"
114 | },
115 | {
116 | "anonymous": false,
117 | "inputs": [
118 | {
119 | "indexed": false,
120 | "internalType": "string",
121 | "name": "received",
122 | "type": "string"
123 | }
124 | ],
125 | "name": "ReceivedDataCap",
126 | "type": "event"
127 | },
128 | {
129 | "inputs": [],
130 | "name": "AUTHENTICATE_MESSAGE_METHOD_NUM",
131 | "outputs": [
132 | {
133 | "internalType": "uint64",
134 | "name": "",
135 | "type": "uint64"
136 | }
137 | ],
138 | "stateMutability": "view",
139 | "type": "function"
140 | },
141 | {
142 | "inputs": [],
143 | "name": "DATACAP_ACTOR_ETH_ADDRESS",
144 | "outputs": [
145 | {
146 | "internalType": "address",
147 | "name": "",
148 | "type": "address"
149 | }
150 | ],
151 | "stateMutability": "view",
152 | "type": "function"
153 | },
154 | {
155 | "inputs": [],
156 | "name": "DATACAP_RECEIVER_HOOK_METHOD_NUM",
157 | "outputs": [
158 | {
159 | "internalType": "uint64",
160 | "name": "",
161 | "type": "uint64"
162 | }
163 | ],
164 | "stateMutability": "view",
165 | "type": "function"
166 | },
167 | {
168 | "inputs": [],
169 | "name": "MARKET_ACTOR_ETH_ADDRESS",
170 | "outputs": [
171 | {
172 | "internalType": "address",
173 | "name": "",
174 | "type": "address"
175 | }
176 | ],
177 | "stateMutability": "view",
178 | "type": "function"
179 | },
180 | {
181 | "inputs": [],
182 | "name": "MARKET_NOTIFY_DEAL_METHOD_NUM",
183 | "outputs": [
184 | {
185 | "internalType": "uint64",
186 | "name": "",
187 | "type": "uint64"
188 | }
189 | ],
190 | "stateMutability": "view",
191 | "type": "function"
192 | },
193 | {
194 | "inputs": [
195 | {
196 | "internalType": "uint256",
197 | "name": "value",
198 | "type": "uint256"
199 | }
200 | ],
201 | "name": "addBalance",
202 | "outputs": [],
203 | "stateMutability": "nonpayable",
204 | "type": "function"
205 | },
206 | {
207 | "inputs": [
208 | {
209 | "internalType": "bytes32",
210 | "name": "",
211 | "type": "bytes32"
212 | }
213 | ],
214 | "name": "dealRequestIdx",
215 | "outputs": [
216 | {
217 | "internalType": "uint256",
218 | "name": "idx",
219 | "type": "uint256"
220 | },
221 | {
222 | "internalType": "bool",
223 | "name": "valid",
224 | "type": "bool"
225 | }
226 | ],
227 | "stateMutability": "view",
228 | "type": "function"
229 | },
230 | {
231 | "inputs": [
232 | {
233 | "internalType": "uint256",
234 | "name": "",
235 | "type": "uint256"
236 | }
237 | ],
238 | "name": "dealRequests",
239 | "outputs": [
240 | {
241 | "internalType": "bytes",
242 | "name": "piece_cid",
243 | "type": "bytes"
244 | },
245 | {
246 | "internalType": "uint64",
247 | "name": "piece_size",
248 | "type": "uint64"
249 | },
250 | {
251 | "internalType": "bool",
252 | "name": "verified_deal",
253 | "type": "bool"
254 | },
255 | {
256 | "internalType": "string",
257 | "name": "label",
258 | "type": "string"
259 | },
260 | {
261 | "internalType": "int64",
262 | "name": "start_epoch",
263 | "type": "int64"
264 | },
265 | {
266 | "internalType": "int64",
267 | "name": "end_epoch",
268 | "type": "int64"
269 | },
270 | {
271 | "internalType": "uint256",
272 | "name": "storage_price_per_epoch",
273 | "type": "uint256"
274 | },
275 | {
276 | "internalType": "uint256",
277 | "name": "provider_collateral",
278 | "type": "uint256"
279 | },
280 | {
281 | "internalType": "uint256",
282 | "name": "client_collateral",
283 | "type": "uint256"
284 | },
285 | {
286 | "internalType": "uint64",
287 | "name": "extra_params_version",
288 | "type": "uint64"
289 | },
290 | {
291 | "components": [
292 | {
293 | "internalType": "string",
294 | "name": "location_ref",
295 | "type": "string"
296 | },
297 | {
298 | "internalType": "uint64",
299 | "name": "car_size",
300 | "type": "uint64"
301 | },
302 | {
303 | "internalType": "bool",
304 | "name": "skip_ipni_announce",
305 | "type": "bool"
306 | },
307 | {
308 | "internalType": "bool",
309 | "name": "remove_unsealed_copy",
310 | "type": "bool"
311 | }
312 | ],
313 | "internalType": "struct ExtraParamsV1",
314 | "name": "extra_params",
315 | "type": "tuple"
316 | }
317 | ],
318 | "stateMutability": "view",
319 | "type": "function"
320 | },
321 | {
322 | "inputs": [],
323 | "name": "dealsLength",
324 | "outputs": [
325 | {
326 | "internalType": "uint256",
327 | "name": "",
328 | "type": "uint256"
329 | }
330 | ],
331 | "stateMutability": "view",
332 | "type": "function"
333 | },
334 | {
335 | "inputs": [
336 | {
337 | "internalType": "uint256",
338 | "name": "index",
339 | "type": "uint256"
340 | }
341 | ],
342 | "name": "getDealByIndex",
343 | "outputs": [
344 | {
345 | "components": [
346 | {
347 | "internalType": "bytes",
348 | "name": "piece_cid",
349 | "type": "bytes"
350 | },
351 | {
352 | "internalType": "uint64",
353 | "name": "piece_size",
354 | "type": "uint64"
355 | },
356 | {
357 | "internalType": "bool",
358 | "name": "verified_deal",
359 | "type": "bool"
360 | },
361 | {
362 | "internalType": "string",
363 | "name": "label",
364 | "type": "string"
365 | },
366 | {
367 | "internalType": "int64",
368 | "name": "start_epoch",
369 | "type": "int64"
370 | },
371 | {
372 | "internalType": "int64",
373 | "name": "end_epoch",
374 | "type": "int64"
375 | },
376 | {
377 | "internalType": "uint256",
378 | "name": "storage_price_per_epoch",
379 | "type": "uint256"
380 | },
381 | {
382 | "internalType": "uint256",
383 | "name": "provider_collateral",
384 | "type": "uint256"
385 | },
386 | {
387 | "internalType": "uint256",
388 | "name": "client_collateral",
389 | "type": "uint256"
390 | },
391 | {
392 | "internalType": "uint64",
393 | "name": "extra_params_version",
394 | "type": "uint64"
395 | },
396 | {
397 | "components": [
398 | {
399 | "internalType": "string",
400 | "name": "location_ref",
401 | "type": "string"
402 | },
403 | {
404 | "internalType": "uint64",
405 | "name": "car_size",
406 | "type": "uint64"
407 | },
408 | {
409 | "internalType": "bool",
410 | "name": "skip_ipni_announce",
411 | "type": "bool"
412 | },
413 | {
414 | "internalType": "bool",
415 | "name": "remove_unsealed_copy",
416 | "type": "bool"
417 | }
418 | ],
419 | "internalType": "struct ExtraParamsV1",
420 | "name": "extra_params",
421 | "type": "tuple"
422 | }
423 | ],
424 | "internalType": "struct DealRequest",
425 | "name": "",
426 | "type": "tuple"
427 | }
428 | ],
429 | "stateMutability": "view",
430 | "type": "function"
431 | },
432 | {
433 | "inputs": [
434 | {
435 | "internalType": "bytes32",
436 | "name": "proposalId",
437 | "type": "bytes32"
438 | }
439 | ],
440 | "name": "getDealProposal",
441 | "outputs": [
442 | {
443 | "internalType": "bytes",
444 | "name": "",
445 | "type": "bytes"
446 | }
447 | ],
448 | "stateMutability": "view",
449 | "type": "function"
450 | },
451 | {
452 | "inputs": [
453 | {
454 | "internalType": "bytes32",
455 | "name": "proposalId",
456 | "type": "bytes32"
457 | }
458 | ],
459 | "name": "getExtraParams",
460 | "outputs": [
461 | {
462 | "internalType": "bytes",
463 | "name": "extra_params",
464 | "type": "bytes"
465 | }
466 | ],
467 | "stateMutability": "view",
468 | "type": "function"
469 | },
470 | {
471 | "inputs": [
472 | {
473 | "internalType": "bytes",
474 | "name": "cid",
475 | "type": "bytes"
476 | }
477 | ],
478 | "name": "getProposalIdSet",
479 | "outputs": [
480 | {
481 | "components": [
482 | {
483 | "internalType": "bytes32",
484 | "name": "requestId",
485 | "type": "bytes32"
486 | },
487 | {
488 | "internalType": "bool",
489 | "name": "valid",
490 | "type": "bool"
491 | }
492 | ],
493 | "internalType": "struct RequestId",
494 | "name": "",
495 | "type": "tuple"
496 | }
497 | ],
498 | "stateMutability": "view",
499 | "type": "function"
500 | },
501 | {
502 | "inputs": [
503 | {
504 | "internalType": "bytes",
505 | "name": "cid",
506 | "type": "bytes"
507 | }
508 | ],
509 | "name": "getProviderSet",
510 | "outputs": [
511 | {
512 | "components": [
513 | {
514 | "internalType": "bytes",
515 | "name": "provider",
516 | "type": "bytes"
517 | },
518 | {
519 | "internalType": "bool",
520 | "name": "valid",
521 | "type": "bool"
522 | }
523 | ],
524 | "internalType": "struct ProviderSet",
525 | "name": "",
526 | "type": "tuple"
527 | }
528 | ],
529 | "stateMutability": "view",
530 | "type": "function"
531 | },
532 | {
533 | "inputs": [
534 | {
535 | "internalType": "uint64",
536 | "name": "method",
537 | "type": "uint64"
538 | },
539 | {
540 | "internalType": "uint64",
541 | "name": "",
542 | "type": "uint64"
543 | },
544 | {
545 | "internalType": "bytes",
546 | "name": "params",
547 | "type": "bytes"
548 | }
549 | ],
550 | "name": "handle_filecoin_method",
551 | "outputs": [
552 | {
553 | "internalType": "uint32",
554 | "name": "",
555 | "type": "uint32"
556 | },
557 | {
558 | "internalType": "uint64",
559 | "name": "",
560 | "type": "uint64"
561 | },
562 | {
563 | "internalType": "bytes",
564 | "name": "",
565 | "type": "bytes"
566 | }
567 | ],
568 | "stateMutability": "nonpayable",
569 | "type": "function"
570 | },
571 | {
572 | "inputs": [
573 | {
574 | "components": [
575 | {
576 | "internalType": "bytes",
577 | "name": "piece_cid",
578 | "type": "bytes"
579 | },
580 | {
581 | "internalType": "uint64",
582 | "name": "piece_size",
583 | "type": "uint64"
584 | },
585 | {
586 | "internalType": "bool",
587 | "name": "verified_deal",
588 | "type": "bool"
589 | },
590 | {
591 | "internalType": "string",
592 | "name": "label",
593 | "type": "string"
594 | },
595 | {
596 | "internalType": "int64",
597 | "name": "start_epoch",
598 | "type": "int64"
599 | },
600 | {
601 | "internalType": "int64",
602 | "name": "end_epoch",
603 | "type": "int64"
604 | },
605 | {
606 | "internalType": "uint256",
607 | "name": "storage_price_per_epoch",
608 | "type": "uint256"
609 | },
610 | {
611 | "internalType": "uint256",
612 | "name": "provider_collateral",
613 | "type": "uint256"
614 | },
615 | {
616 | "internalType": "uint256",
617 | "name": "client_collateral",
618 | "type": "uint256"
619 | },
620 | {
621 | "internalType": "uint64",
622 | "name": "extra_params_version",
623 | "type": "uint64"
624 | },
625 | {
626 | "components": [
627 | {
628 | "internalType": "string",
629 | "name": "location_ref",
630 | "type": "string"
631 | },
632 | {
633 | "internalType": "uint64",
634 | "name": "car_size",
635 | "type": "uint64"
636 | },
637 | {
638 | "internalType": "bool",
639 | "name": "skip_ipni_announce",
640 | "type": "bool"
641 | },
642 | {
643 | "internalType": "bool",
644 | "name": "remove_unsealed_copy",
645 | "type": "bool"
646 | }
647 | ],
648 | "internalType": "struct ExtraParamsV1",
649 | "name": "extra_params",
650 | "type": "tuple"
651 | }
652 | ],
653 | "internalType": "struct DealRequest",
654 | "name": "deal",
655 | "type": "tuple"
656 | }
657 | ],
658 | "name": "makeDealProposal",
659 | "outputs": [
660 | {
661 | "internalType": "bytes32",
662 | "name": "",
663 | "type": "bytes32"
664 | }
665 | ],
666 | "stateMutability": "nonpayable",
667 | "type": "function"
668 | },
669 | {
670 | "inputs": [],
671 | "name": "owner",
672 | "outputs": [
673 | {
674 | "internalType": "address",
675 | "name": "",
676 | "type": "address"
677 | }
678 | ],
679 | "stateMutability": "view",
680 | "type": "function"
681 | },
682 | {
683 | "inputs": [
684 | {
685 | "internalType": "bytes",
686 | "name": "",
687 | "type": "bytes"
688 | }
689 | ],
690 | "name": "pieceDeals",
691 | "outputs": [
692 | {
693 | "internalType": "uint64",
694 | "name": "",
695 | "type": "uint64"
696 | }
697 | ],
698 | "stateMutability": "view",
699 | "type": "function"
700 | },
701 | {
702 | "inputs": [
703 | {
704 | "internalType": "bytes",
705 | "name": "",
706 | "type": "bytes"
707 | }
708 | ],
709 | "name": "pieceProviders",
710 | "outputs": [
711 | {
712 | "internalType": "bytes",
713 | "name": "provider",
714 | "type": "bytes"
715 | },
716 | {
717 | "internalType": "bool",
718 | "name": "valid",
719 | "type": "bool"
720 | }
721 | ],
722 | "stateMutability": "view",
723 | "type": "function"
724 | },
725 | {
726 | "inputs": [
727 | {
728 | "internalType": "bytes",
729 | "name": "",
730 | "type": "bytes"
731 | }
732 | ],
733 | "name": "pieceRequests",
734 | "outputs": [
735 | {
736 | "internalType": "bytes32",
737 | "name": "requestId",
738 | "type": "bytes32"
739 | },
740 | {
741 | "internalType": "bool",
742 | "name": "valid",
743 | "type": "bool"
744 | }
745 | ],
746 | "stateMutability": "view",
747 | "type": "function"
748 | },
749 | {
750 | "inputs": [
751 | {
752 | "internalType": "bytes",
753 | "name": "",
754 | "type": "bytes"
755 | }
756 | ],
757 | "name": "pieceStatus",
758 | "outputs": [
759 | {
760 | "internalType": "enum DaoDealClient.Status",
761 | "name": "",
762 | "type": "uint8"
763 | }
764 | ],
765 | "stateMutability": "view",
766 | "type": "function"
767 | },
768 | {
769 | "inputs": [],
770 | "name": "renounceOwnership",
771 | "outputs": [],
772 | "stateMutability": "nonpayable",
773 | "type": "function"
774 | },
775 | {
776 | "inputs": [
777 | {
778 | "internalType": "address",
779 | "name": "newOwner",
780 | "type": "address"
781 | }
782 | ],
783 | "name": "transferOwnership",
784 | "outputs": [],
785 | "stateMutability": "nonpayable",
786 | "type": "function"
787 | },
788 | {
789 | "inputs": [
790 | {
791 | "internalType": "bytes",
792 | "name": "pieceCid",
793 | "type": "bytes"
794 | }
795 | ],
796 | "name": "updateActivationStatus",
797 | "outputs": [],
798 | "stateMutability": "nonpayable",
799 | "type": "function"
800 | },
801 | {
802 | "inputs": [
803 | {
804 | "internalType": "address",
805 | "name": "client",
806 | "type": "address"
807 | },
808 | {
809 | "internalType": "uint256",
810 | "name": "value",
811 | "type": "uint256"
812 | }
813 | ],
814 | "name": "withdrawBalance",
815 | "outputs": [
816 | {
817 | "internalType": "uint256",
818 | "name": "",
819 | "type": "uint256"
820 | }
821 | ],
822 | "stateMutability": "nonpayable",
823 | "type": "function"
824 | }
825 | ]
--------------------------------------------------------------------------------
/frontend/src/contractABIs/governorABI.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "inputs": [
4 | {
5 | "internalType": "contract IVotes",
6 | "name": "_token",
7 | "type": "address"
8 | },
9 | {
10 | "internalType": "contract TimelockController",
11 | "name": "_timelock",
12 | "type": "address"
13 | },
14 | {
15 | "internalType": "uint256",
16 | "name": "_votingDelay",
17 | "type": "uint256"
18 | },
19 | {
20 | "internalType": "uint256",
21 | "name": "_votingPeriod",
22 | "type": "uint256"
23 | },
24 | {
25 | "internalType": "uint256",
26 | "name": "_quorumPercentage",
27 | "type": "uint256"
28 | }
29 | ],
30 | "stateMutability": "nonpayable",
31 | "type": "constructor"
32 | },
33 | {
34 | "inputs": [],
35 | "name": "Empty",
36 | "type": "error"
37 | },
38 | {
39 | "anonymous": false,
40 | "inputs": [
41 | {
42 | "indexed": false,
43 | "internalType": "uint256",
44 | "name": "proposalId",
45 | "type": "uint256"
46 | }
47 | ],
48 | "name": "ProposalCanceled",
49 | "type": "event"
50 | },
51 | {
52 | "anonymous": false,
53 | "inputs": [
54 | {
55 | "indexed": false,
56 | "internalType": "uint256",
57 | "name": "proposalId",
58 | "type": "uint256"
59 | },
60 | {
61 | "indexed": false,
62 | "internalType": "address",
63 | "name": "proposer",
64 | "type": "address"
65 | },
66 | {
67 | "indexed": false,
68 | "internalType": "address[]",
69 | "name": "targets",
70 | "type": "address[]"
71 | },
72 | {
73 | "indexed": false,
74 | "internalType": "uint256[]",
75 | "name": "values",
76 | "type": "uint256[]"
77 | },
78 | {
79 | "indexed": false,
80 | "internalType": "string[]",
81 | "name": "signatures",
82 | "type": "string[]"
83 | },
84 | {
85 | "indexed": false,
86 | "internalType": "bytes[]",
87 | "name": "calldatas",
88 | "type": "bytes[]"
89 | },
90 | {
91 | "indexed": false,
92 | "internalType": "uint256",
93 | "name": "startBlock",
94 | "type": "uint256"
95 | },
96 | {
97 | "indexed": false,
98 | "internalType": "uint256",
99 | "name": "endBlock",
100 | "type": "uint256"
101 | },
102 | {
103 | "indexed": false,
104 | "internalType": "string",
105 | "name": "description",
106 | "type": "string"
107 | }
108 | ],
109 | "name": "ProposalCreated",
110 | "type": "event"
111 | },
112 | {
113 | "anonymous": false,
114 | "inputs": [
115 | {
116 | "indexed": false,
117 | "internalType": "uint256",
118 | "name": "proposalId",
119 | "type": "uint256"
120 | }
121 | ],
122 | "name": "ProposalExecuted",
123 | "type": "event"
124 | },
125 | {
126 | "anonymous": false,
127 | "inputs": [
128 | {
129 | "indexed": false,
130 | "internalType": "uint256",
131 | "name": "proposalId",
132 | "type": "uint256"
133 | },
134 | {
135 | "indexed": false,
136 | "internalType": "uint256",
137 | "name": "eta",
138 | "type": "uint256"
139 | }
140 | ],
141 | "name": "ProposalQueued",
142 | "type": "event"
143 | },
144 | {
145 | "anonymous": false,
146 | "inputs": [
147 | {
148 | "indexed": false,
149 | "internalType": "uint256",
150 | "name": "oldProposalThreshold",
151 | "type": "uint256"
152 | },
153 | {
154 | "indexed": false,
155 | "internalType": "uint256",
156 | "name": "newProposalThreshold",
157 | "type": "uint256"
158 | }
159 | ],
160 | "name": "ProposalThresholdSet",
161 | "type": "event"
162 | },
163 | {
164 | "anonymous": false,
165 | "inputs": [
166 | {
167 | "indexed": false,
168 | "internalType": "uint256",
169 | "name": "oldQuorumNumerator",
170 | "type": "uint256"
171 | },
172 | {
173 | "indexed": false,
174 | "internalType": "uint256",
175 | "name": "newQuorumNumerator",
176 | "type": "uint256"
177 | }
178 | ],
179 | "name": "QuorumNumeratorUpdated",
180 | "type": "event"
181 | },
182 | {
183 | "anonymous": false,
184 | "inputs": [
185 | {
186 | "indexed": false,
187 | "internalType": "address",
188 | "name": "oldTimelock",
189 | "type": "address"
190 | },
191 | {
192 | "indexed": false,
193 | "internalType": "address",
194 | "name": "newTimelock",
195 | "type": "address"
196 | }
197 | ],
198 | "name": "TimelockChange",
199 | "type": "event"
200 | },
201 | {
202 | "anonymous": false,
203 | "inputs": [
204 | {
205 | "indexed": true,
206 | "internalType": "address",
207 | "name": "voter",
208 | "type": "address"
209 | },
210 | {
211 | "indexed": false,
212 | "internalType": "uint256",
213 | "name": "proposalId",
214 | "type": "uint256"
215 | },
216 | {
217 | "indexed": false,
218 | "internalType": "uint8",
219 | "name": "support",
220 | "type": "uint8"
221 | },
222 | {
223 | "indexed": false,
224 | "internalType": "uint256",
225 | "name": "weight",
226 | "type": "uint256"
227 | },
228 | {
229 | "indexed": false,
230 | "internalType": "string",
231 | "name": "reason",
232 | "type": "string"
233 | }
234 | ],
235 | "name": "VoteCast",
236 | "type": "event"
237 | },
238 | {
239 | "anonymous": false,
240 | "inputs": [
241 | {
242 | "indexed": true,
243 | "internalType": "address",
244 | "name": "voter",
245 | "type": "address"
246 | },
247 | {
248 | "indexed": false,
249 | "internalType": "uint256",
250 | "name": "proposalId",
251 | "type": "uint256"
252 | },
253 | {
254 | "indexed": false,
255 | "internalType": "uint8",
256 | "name": "support",
257 | "type": "uint8"
258 | },
259 | {
260 | "indexed": false,
261 | "internalType": "uint256",
262 | "name": "weight",
263 | "type": "uint256"
264 | },
265 | {
266 | "indexed": false,
267 | "internalType": "string",
268 | "name": "reason",
269 | "type": "string"
270 | },
271 | {
272 | "indexed": false,
273 | "internalType": "bytes",
274 | "name": "params",
275 | "type": "bytes"
276 | }
277 | ],
278 | "name": "VoteCastWithParams",
279 | "type": "event"
280 | },
281 | {
282 | "anonymous": false,
283 | "inputs": [
284 | {
285 | "indexed": false,
286 | "internalType": "uint256",
287 | "name": "oldVotingDelay",
288 | "type": "uint256"
289 | },
290 | {
291 | "indexed": false,
292 | "internalType": "uint256",
293 | "name": "newVotingDelay",
294 | "type": "uint256"
295 | }
296 | ],
297 | "name": "VotingDelaySet",
298 | "type": "event"
299 | },
300 | {
301 | "anonymous": false,
302 | "inputs": [
303 | {
304 | "indexed": false,
305 | "internalType": "uint256",
306 | "name": "oldVotingPeriod",
307 | "type": "uint256"
308 | },
309 | {
310 | "indexed": false,
311 | "internalType": "uint256",
312 | "name": "newVotingPeriod",
313 | "type": "uint256"
314 | }
315 | ],
316 | "name": "VotingPeriodSet",
317 | "type": "event"
318 | },
319 | {
320 | "inputs": [],
321 | "name": "BALLOT_TYPEHASH",
322 | "outputs": [
323 | {
324 | "internalType": "bytes32",
325 | "name": "",
326 | "type": "bytes32"
327 | }
328 | ],
329 | "stateMutability": "view",
330 | "type": "function"
331 | },
332 | {
333 | "inputs": [],
334 | "name": "COUNTING_MODE",
335 | "outputs": [
336 | {
337 | "internalType": "string",
338 | "name": "",
339 | "type": "string"
340 | }
341 | ],
342 | "stateMutability": "pure",
343 | "type": "function"
344 | },
345 | {
346 | "inputs": [],
347 | "name": "EXTENDED_BALLOT_TYPEHASH",
348 | "outputs": [
349 | {
350 | "internalType": "bytes32",
351 | "name": "",
352 | "type": "bytes32"
353 | }
354 | ],
355 | "stateMutability": "view",
356 | "type": "function"
357 | },
358 | {
359 | "inputs": [
360 | {
361 | "internalType": "uint256",
362 | "name": "proposalId",
363 | "type": "uint256"
364 | },
365 | {
366 | "internalType": "uint8",
367 | "name": "support",
368 | "type": "uint8"
369 | }
370 | ],
371 | "name": "castVote",
372 | "outputs": [
373 | {
374 | "internalType": "uint256",
375 | "name": "",
376 | "type": "uint256"
377 | }
378 | ],
379 | "stateMutability": "nonpayable",
380 | "type": "function"
381 | },
382 | {
383 | "inputs": [
384 | {
385 | "internalType": "uint256",
386 | "name": "proposalId",
387 | "type": "uint256"
388 | },
389 | {
390 | "internalType": "uint8",
391 | "name": "support",
392 | "type": "uint8"
393 | },
394 | {
395 | "internalType": "uint8",
396 | "name": "v",
397 | "type": "uint8"
398 | },
399 | {
400 | "internalType": "bytes32",
401 | "name": "r",
402 | "type": "bytes32"
403 | },
404 | {
405 | "internalType": "bytes32",
406 | "name": "s",
407 | "type": "bytes32"
408 | }
409 | ],
410 | "name": "castVoteBySig",
411 | "outputs": [
412 | {
413 | "internalType": "uint256",
414 | "name": "",
415 | "type": "uint256"
416 | }
417 | ],
418 | "stateMutability": "nonpayable",
419 | "type": "function"
420 | },
421 | {
422 | "inputs": [
423 | {
424 | "internalType": "uint256",
425 | "name": "proposalId",
426 | "type": "uint256"
427 | },
428 | {
429 | "internalType": "uint8",
430 | "name": "support",
431 | "type": "uint8"
432 | },
433 | {
434 | "internalType": "string",
435 | "name": "reason",
436 | "type": "string"
437 | }
438 | ],
439 | "name": "castVoteWithReason",
440 | "outputs": [
441 | {
442 | "internalType": "uint256",
443 | "name": "",
444 | "type": "uint256"
445 | }
446 | ],
447 | "stateMutability": "nonpayable",
448 | "type": "function"
449 | },
450 | {
451 | "inputs": [
452 | {
453 | "internalType": "uint256",
454 | "name": "proposalId",
455 | "type": "uint256"
456 | },
457 | {
458 | "internalType": "uint8",
459 | "name": "support",
460 | "type": "uint8"
461 | },
462 | {
463 | "internalType": "string",
464 | "name": "reason",
465 | "type": "string"
466 | },
467 | {
468 | "internalType": "bytes",
469 | "name": "params",
470 | "type": "bytes"
471 | }
472 | ],
473 | "name": "castVoteWithReasonAndParams",
474 | "outputs": [
475 | {
476 | "internalType": "uint256",
477 | "name": "",
478 | "type": "uint256"
479 | }
480 | ],
481 | "stateMutability": "nonpayable",
482 | "type": "function"
483 | },
484 | {
485 | "inputs": [
486 | {
487 | "internalType": "uint256",
488 | "name": "proposalId",
489 | "type": "uint256"
490 | },
491 | {
492 | "internalType": "uint8",
493 | "name": "support",
494 | "type": "uint8"
495 | },
496 | {
497 | "internalType": "string",
498 | "name": "reason",
499 | "type": "string"
500 | },
501 | {
502 | "internalType": "bytes",
503 | "name": "params",
504 | "type": "bytes"
505 | },
506 | {
507 | "internalType": "uint8",
508 | "name": "v",
509 | "type": "uint8"
510 | },
511 | {
512 | "internalType": "bytes32",
513 | "name": "r",
514 | "type": "bytes32"
515 | },
516 | {
517 | "internalType": "bytes32",
518 | "name": "s",
519 | "type": "bytes32"
520 | }
521 | ],
522 | "name": "castVoteWithReasonAndParamsBySig",
523 | "outputs": [
524 | {
525 | "internalType": "uint256",
526 | "name": "",
527 | "type": "uint256"
528 | }
529 | ],
530 | "stateMutability": "nonpayable",
531 | "type": "function"
532 | },
533 | {
534 | "inputs": [
535 | {
536 | "internalType": "address[]",
537 | "name": "targets",
538 | "type": "address[]"
539 | },
540 | {
541 | "internalType": "uint256[]",
542 | "name": "values",
543 | "type": "uint256[]"
544 | },
545 | {
546 | "internalType": "bytes[]",
547 | "name": "calldatas",
548 | "type": "bytes[]"
549 | },
550 | {
551 | "internalType": "bytes32",
552 | "name": "descriptionHash",
553 | "type": "bytes32"
554 | }
555 | ],
556 | "name": "execute",
557 | "outputs": [
558 | {
559 | "internalType": "uint256",
560 | "name": "",
561 | "type": "uint256"
562 | }
563 | ],
564 | "stateMutability": "payable",
565 | "type": "function"
566 | },
567 | {
568 | "inputs": [
569 | {
570 | "internalType": "address",
571 | "name": "account",
572 | "type": "address"
573 | },
574 | {
575 | "internalType": "uint256",
576 | "name": "blockNumber",
577 | "type": "uint256"
578 | }
579 | ],
580 | "name": "getVotes",
581 | "outputs": [
582 | {
583 | "internalType": "uint256",
584 | "name": "",
585 | "type": "uint256"
586 | }
587 | ],
588 | "stateMutability": "view",
589 | "type": "function"
590 | },
591 | {
592 | "inputs": [
593 | {
594 | "internalType": "address",
595 | "name": "account",
596 | "type": "address"
597 | },
598 | {
599 | "internalType": "uint256",
600 | "name": "blockNumber",
601 | "type": "uint256"
602 | },
603 | {
604 | "internalType": "bytes",
605 | "name": "params",
606 | "type": "bytes"
607 | }
608 | ],
609 | "name": "getVotesWithParams",
610 | "outputs": [
611 | {
612 | "internalType": "uint256",
613 | "name": "",
614 | "type": "uint256"
615 | }
616 | ],
617 | "stateMutability": "view",
618 | "type": "function"
619 | },
620 | {
621 | "inputs": [
622 | {
623 | "internalType": "uint256",
624 | "name": "proposalId",
625 | "type": "uint256"
626 | },
627 | {
628 | "internalType": "address",
629 | "name": "account",
630 | "type": "address"
631 | }
632 | ],
633 | "name": "hasVoted",
634 | "outputs": [
635 | {
636 | "internalType": "bool",
637 | "name": "",
638 | "type": "bool"
639 | }
640 | ],
641 | "stateMutability": "view",
642 | "type": "function"
643 | },
644 | {
645 | "inputs": [
646 | {
647 | "internalType": "address[]",
648 | "name": "targets",
649 | "type": "address[]"
650 | },
651 | {
652 | "internalType": "uint256[]",
653 | "name": "values",
654 | "type": "uint256[]"
655 | },
656 | {
657 | "internalType": "bytes[]",
658 | "name": "calldatas",
659 | "type": "bytes[]"
660 | },
661 | {
662 | "internalType": "bytes32",
663 | "name": "descriptionHash",
664 | "type": "bytes32"
665 | }
666 | ],
667 | "name": "hashProposal",
668 | "outputs": [
669 | {
670 | "internalType": "uint256",
671 | "name": "",
672 | "type": "uint256"
673 | }
674 | ],
675 | "stateMutability": "pure",
676 | "type": "function"
677 | },
678 | {
679 | "inputs": [],
680 | "name": "name",
681 | "outputs": [
682 | {
683 | "internalType": "string",
684 | "name": "",
685 | "type": "string"
686 | }
687 | ],
688 | "stateMutability": "view",
689 | "type": "function"
690 | },
691 | {
692 | "inputs": [
693 | {
694 | "internalType": "address",
695 | "name": "",
696 | "type": "address"
697 | },
698 | {
699 | "internalType": "address",
700 | "name": "",
701 | "type": "address"
702 | },
703 | {
704 | "internalType": "uint256[]",
705 | "name": "",
706 | "type": "uint256[]"
707 | },
708 | {
709 | "internalType": "uint256[]",
710 | "name": "",
711 | "type": "uint256[]"
712 | },
713 | {
714 | "internalType": "bytes",
715 | "name": "",
716 | "type": "bytes"
717 | }
718 | ],
719 | "name": "onERC1155BatchReceived",
720 | "outputs": [
721 | {
722 | "internalType": "bytes4",
723 | "name": "",
724 | "type": "bytes4"
725 | }
726 | ],
727 | "stateMutability": "nonpayable",
728 | "type": "function"
729 | },
730 | {
731 | "inputs": [
732 | {
733 | "internalType": "address",
734 | "name": "",
735 | "type": "address"
736 | },
737 | {
738 | "internalType": "address",
739 | "name": "",
740 | "type": "address"
741 | },
742 | {
743 | "internalType": "uint256",
744 | "name": "",
745 | "type": "uint256"
746 | },
747 | {
748 | "internalType": "uint256",
749 | "name": "",
750 | "type": "uint256"
751 | },
752 | {
753 | "internalType": "bytes",
754 | "name": "",
755 | "type": "bytes"
756 | }
757 | ],
758 | "name": "onERC1155Received",
759 | "outputs": [
760 | {
761 | "internalType": "bytes4",
762 | "name": "",
763 | "type": "bytes4"
764 | }
765 | ],
766 | "stateMutability": "nonpayable",
767 | "type": "function"
768 | },
769 | {
770 | "inputs": [
771 | {
772 | "internalType": "address",
773 | "name": "",
774 | "type": "address"
775 | },
776 | {
777 | "internalType": "address",
778 | "name": "",
779 | "type": "address"
780 | },
781 | {
782 | "internalType": "uint256",
783 | "name": "",
784 | "type": "uint256"
785 | },
786 | {
787 | "internalType": "bytes",
788 | "name": "",
789 | "type": "bytes"
790 | }
791 | ],
792 | "name": "onERC721Received",
793 | "outputs": [
794 | {
795 | "internalType": "bytes4",
796 | "name": "",
797 | "type": "bytes4"
798 | }
799 | ],
800 | "stateMutability": "nonpayable",
801 | "type": "function"
802 | },
803 | {
804 | "inputs": [
805 | {
806 | "internalType": "uint256",
807 | "name": "proposalId",
808 | "type": "uint256"
809 | }
810 | ],
811 | "name": "proposalDeadline",
812 | "outputs": [
813 | {
814 | "internalType": "uint256",
815 | "name": "",
816 | "type": "uint256"
817 | }
818 | ],
819 | "stateMutability": "view",
820 | "type": "function"
821 | },
822 | {
823 | "inputs": [
824 | {
825 | "internalType": "uint256",
826 | "name": "proposalId",
827 | "type": "uint256"
828 | }
829 | ],
830 | "name": "proposalEta",
831 | "outputs": [
832 | {
833 | "internalType": "uint256",
834 | "name": "",
835 | "type": "uint256"
836 | }
837 | ],
838 | "stateMutability": "view",
839 | "type": "function"
840 | },
841 | {
842 | "inputs": [
843 | {
844 | "internalType": "uint256",
845 | "name": "proposalId",
846 | "type": "uint256"
847 | }
848 | ],
849 | "name": "proposalSnapshot",
850 | "outputs": [
851 | {
852 | "internalType": "uint256",
853 | "name": "",
854 | "type": "uint256"
855 | }
856 | ],
857 | "stateMutability": "view",
858 | "type": "function"
859 | },
860 | {
861 | "inputs": [],
862 | "name": "proposalThreshold",
863 | "outputs": [
864 | {
865 | "internalType": "uint256",
866 | "name": "",
867 | "type": "uint256"
868 | }
869 | ],
870 | "stateMutability": "view",
871 | "type": "function"
872 | },
873 | {
874 | "inputs": [
875 | {
876 | "internalType": "uint256",
877 | "name": "proposalId",
878 | "type": "uint256"
879 | }
880 | ],
881 | "name": "proposalVotes",
882 | "outputs": [
883 | {
884 | "internalType": "uint256",
885 | "name": "againstVotes",
886 | "type": "uint256"
887 | },
888 | {
889 | "internalType": "uint256",
890 | "name": "forVotes",
891 | "type": "uint256"
892 | },
893 | {
894 | "internalType": "uint256",
895 | "name": "abstainVotes",
896 | "type": "uint256"
897 | }
898 | ],
899 | "stateMutability": "view",
900 | "type": "function"
901 | },
902 | {
903 | "inputs": [
904 | {
905 | "internalType": "address[]",
906 | "name": "targets",
907 | "type": "address[]"
908 | },
909 | {
910 | "internalType": "uint256[]",
911 | "name": "values",
912 | "type": "uint256[]"
913 | },
914 | {
915 | "internalType": "bytes[]",
916 | "name": "calldatas",
917 | "type": "bytes[]"
918 | },
919 | {
920 | "internalType": "string",
921 | "name": "description",
922 | "type": "string"
923 | }
924 | ],
925 | "name": "propose",
926 | "outputs": [
927 | {
928 | "internalType": "uint256",
929 | "name": "",
930 | "type": "uint256"
931 | }
932 | ],
933 | "stateMutability": "nonpayable",
934 | "type": "function"
935 | },
936 | {
937 | "inputs": [
938 | {
939 | "internalType": "address[]",
940 | "name": "targets",
941 | "type": "address[]"
942 | },
943 | {
944 | "internalType": "uint256[]",
945 | "name": "values",
946 | "type": "uint256[]"
947 | },
948 | {
949 | "internalType": "bytes[]",
950 | "name": "calldatas",
951 | "type": "bytes[]"
952 | },
953 | {
954 | "internalType": "bytes32",
955 | "name": "descriptionHash",
956 | "type": "bytes32"
957 | }
958 | ],
959 | "name": "queue",
960 | "outputs": [
961 | {
962 | "internalType": "uint256",
963 | "name": "",
964 | "type": "uint256"
965 | }
966 | ],
967 | "stateMutability": "nonpayable",
968 | "type": "function"
969 | },
970 | {
971 | "inputs": [
972 | {
973 | "internalType": "uint256",
974 | "name": "blockNumber",
975 | "type": "uint256"
976 | }
977 | ],
978 | "name": "quorum",
979 | "outputs": [
980 | {
981 | "internalType": "uint256",
982 | "name": "",
983 | "type": "uint256"
984 | }
985 | ],
986 | "stateMutability": "view",
987 | "type": "function"
988 | },
989 | {
990 | "inputs": [],
991 | "name": "quorumDenominator",
992 | "outputs": [
993 | {
994 | "internalType": "uint256",
995 | "name": "",
996 | "type": "uint256"
997 | }
998 | ],
999 | "stateMutability": "view",
1000 | "type": "function"
1001 | },
1002 | {
1003 | "inputs": [
1004 | {
1005 | "internalType": "uint256",
1006 | "name": "blockNumber",
1007 | "type": "uint256"
1008 | }
1009 | ],
1010 | "name": "quorumNumerator",
1011 | "outputs": [
1012 | {
1013 | "internalType": "uint256",
1014 | "name": "",
1015 | "type": "uint256"
1016 | }
1017 | ],
1018 | "stateMutability": "view",
1019 | "type": "function"
1020 | },
1021 | {
1022 | "inputs": [],
1023 | "name": "quorumNumerator",
1024 | "outputs": [
1025 | {
1026 | "internalType": "uint256",
1027 | "name": "",
1028 | "type": "uint256"
1029 | }
1030 | ],
1031 | "stateMutability": "view",
1032 | "type": "function"
1033 | },
1034 | {
1035 | "inputs": [
1036 | {
1037 | "internalType": "address",
1038 | "name": "target",
1039 | "type": "address"
1040 | },
1041 | {
1042 | "internalType": "uint256",
1043 | "name": "value",
1044 | "type": "uint256"
1045 | },
1046 | {
1047 | "internalType": "bytes",
1048 | "name": "data",
1049 | "type": "bytes"
1050 | }
1051 | ],
1052 | "name": "relay",
1053 | "outputs": [],
1054 | "stateMutability": "payable",
1055 | "type": "function"
1056 | },
1057 | {
1058 | "inputs": [
1059 | {
1060 | "internalType": "uint256",
1061 | "name": "newProposalThreshold",
1062 | "type": "uint256"
1063 | }
1064 | ],
1065 | "name": "setProposalThreshold",
1066 | "outputs": [],
1067 | "stateMutability": "nonpayable",
1068 | "type": "function"
1069 | },
1070 | {
1071 | "inputs": [
1072 | {
1073 | "internalType": "uint256",
1074 | "name": "newVotingDelay",
1075 | "type": "uint256"
1076 | }
1077 | ],
1078 | "name": "setVotingDelay",
1079 | "outputs": [],
1080 | "stateMutability": "nonpayable",
1081 | "type": "function"
1082 | },
1083 | {
1084 | "inputs": [
1085 | {
1086 | "internalType": "uint256",
1087 | "name": "newVotingPeriod",
1088 | "type": "uint256"
1089 | }
1090 | ],
1091 | "name": "setVotingPeriod",
1092 | "outputs": [],
1093 | "stateMutability": "nonpayable",
1094 | "type": "function"
1095 | },
1096 | {
1097 | "inputs": [
1098 | {
1099 | "internalType": "uint256",
1100 | "name": "proposalId",
1101 | "type": "uint256"
1102 | }
1103 | ],
1104 | "name": "state",
1105 | "outputs": [
1106 | {
1107 | "internalType": "enum IGovernor.ProposalState",
1108 | "name": "",
1109 | "type": "uint8"
1110 | }
1111 | ],
1112 | "stateMutability": "view",
1113 | "type": "function"
1114 | },
1115 | {
1116 | "inputs": [
1117 | {
1118 | "internalType": "bytes4",
1119 | "name": "interfaceId",
1120 | "type": "bytes4"
1121 | }
1122 | ],
1123 | "name": "supportsInterface",
1124 | "outputs": [
1125 | {
1126 | "internalType": "bool",
1127 | "name": "",
1128 | "type": "bool"
1129 | }
1130 | ],
1131 | "stateMutability": "view",
1132 | "type": "function"
1133 | },
1134 | {
1135 | "inputs": [],
1136 | "name": "timelock",
1137 | "outputs": [
1138 | {
1139 | "internalType": "address",
1140 | "name": "",
1141 | "type": "address"
1142 | }
1143 | ],
1144 | "stateMutability": "view",
1145 | "type": "function"
1146 | },
1147 | {
1148 | "inputs": [],
1149 | "name": "token",
1150 | "outputs": [
1151 | {
1152 | "internalType": "contract IVotes",
1153 | "name": "",
1154 | "type": "address"
1155 | }
1156 | ],
1157 | "stateMutability": "view",
1158 | "type": "function"
1159 | },
1160 | {
1161 | "inputs": [
1162 | {
1163 | "internalType": "uint256",
1164 | "name": "newQuorumNumerator",
1165 | "type": "uint256"
1166 | }
1167 | ],
1168 | "name": "updateQuorumNumerator",
1169 | "outputs": [],
1170 | "stateMutability": "nonpayable",
1171 | "type": "function"
1172 | },
1173 | {
1174 | "inputs": [
1175 | {
1176 | "internalType": "contract TimelockController",
1177 | "name": "newTimelock",
1178 | "type": "address"
1179 | }
1180 | ],
1181 | "name": "updateTimelock",
1182 | "outputs": [],
1183 | "stateMutability": "nonpayable",
1184 | "type": "function"
1185 | },
1186 | {
1187 | "inputs": [],
1188 | "name": "version",
1189 | "outputs": [
1190 | {
1191 | "internalType": "string",
1192 | "name": "",
1193 | "type": "string"
1194 | }
1195 | ],
1196 | "stateMutability": "view",
1197 | "type": "function"
1198 | },
1199 | {
1200 | "inputs": [],
1201 | "name": "votingDelay",
1202 | "outputs": [
1203 | {
1204 | "internalType": "uint256",
1205 | "name": "",
1206 | "type": "uint256"
1207 | }
1208 | ],
1209 | "stateMutability": "view",
1210 | "type": "function"
1211 | },
1212 | {
1213 | "inputs": [],
1214 | "name": "votingPeriod",
1215 | "outputs": [
1216 | {
1217 | "internalType": "uint256",
1218 | "name": "",
1219 | "type": "uint256"
1220 | }
1221 | ],
1222 | "stateMutability": "view",
1223 | "type": "function"
1224 | },
1225 | {
1226 | "stateMutability": "payable",
1227 | "type": "receive"
1228 | }
1229 | ]
--------------------------------------------------------------------------------
/frontend/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12 | monospace;
13 | }
14 |
--------------------------------------------------------------------------------
/frontend/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom/client';
3 | import './index.css';
4 | import App from './App';
5 | import reportWebVitals from './reportWebVitals';
6 |
7 | const root = ReactDOM.createRoot(document.getElementById('root'));
8 | root.render(
9 |
10 |
11 |
12 | );
13 |
14 | // If you want to start measuring performance in your app, pass a function
15 | // to log results (for example: reportWebVitals(console.log))
16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
17 | reportWebVitals();
18 |
--------------------------------------------------------------------------------
/frontend/src/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/frontend/src/propose.js:
--------------------------------------------------------------------------------
1 | function Propose() {
2 | return (
3 |
4 |
7 |
8 | );
9 | }
10 |
11 | export default App;
12 |
--------------------------------------------------------------------------------
/frontend/src/reportWebVitals.js:
--------------------------------------------------------------------------------
1 | const reportWebVitals = onPerfEntry => {
2 | if (onPerfEntry && onPerfEntry instanceof Function) {
3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
4 | getCLS(onPerfEntry);
5 | getFID(onPerfEntry);
6 | getFCP(onPerfEntry);
7 | getLCP(onPerfEntry);
8 | getTTFB(onPerfEntry);
9 | });
10 | }
11 | };
12 |
13 | export default reportWebVitals;
14 |
--------------------------------------------------------------------------------
/frontend/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom';
6 |
--------------------------------------------------------------------------------
/hardhat/.env.example:
--------------------------------------------------------------------------------
1 | PRIVATE_KEY="abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc1"
--------------------------------------------------------------------------------
/hardhat/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/hardhat/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "tools/go-generate-car"]
2 | path = tools/go-generate-car
3 | url = https://github.com/tech-greedy/go-generate-car.git
4 |
--------------------------------------------------------------------------------
/hardhat/.gitpod.yml:
--------------------------------------------------------------------------------
1 | tasks:
2 | - name: 👷 HARDHAT 👷
3 | command: yarn
--------------------------------------------------------------------------------
/hardhat/.npmignore:
--------------------------------------------------------------------------------
1 | hardhat.config.js
2 | scripts
3 | test
4 |
--------------------------------------------------------------------------------
/hardhat/.prettierignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | artifacts
3 | cache
4 | coverage*
5 | gasReporterOutput.json
6 | package.json
7 | img
8 | .env
9 | .*
10 | README.md
11 | coverage.json
12 | deployments
--------------------------------------------------------------------------------
/hardhat/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "tabWidth": 4,
3 | "useTabs": false,
4 | "semi": false,
5 | "singleQuote": false,
6 | "printWidth": 100
7 | }
8 |
--------------------------------------------------------------------------------
/hardhat/.solcover.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | skipFiles: ['test/fuzzing/KeepersCounterEchidnaTest.sol', 'test/LinkToken.sol', 'test/MockOracle.sol', 'test/MockV3Aggregator.sol', 'test/VRFCoordinatorV2Mock.sol'],
3 | };
--------------------------------------------------------------------------------
/hardhat/.solhint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "solhint:recommended",
3 | "rules": {
4 | "compiler-version": ["error", "^0.8.0"],
5 | "func-visibility": ["warn", { "ignoreConstructors": true }]
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/hardhat/.solhintignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | contracts/test
--------------------------------------------------------------------------------
/hardhat/README.md:
--------------------------------------------------------------------------------
1 | # FEVM-Data-DAO-Kit
2 |
3 | This is a beta kit to demo how to build a basic Decentralized Autonomous Organization (DAO) on Filecoin. Currently, this kit contains these [OpenZeppelin contracts](https://docs.openzeppelin.com/contracts/4.x/governance): Timelock.sol, Governor.sol, and ERC20Votes. These contracts are used in conjuction with the [Filecoin Client Contract](https://github.com/filecoin-project/fvm-starter-kit-deal-making) to create a DAO that can vote on whether to propose a specific storage deal. This initial version is based on Patrick Collin's excellent repo and tutorial so be sure to check them out to learn more about how this DAO template works!
4 |
5 | * [Video](https://www.youtube.com/watch?v=AhJtmUqhAqg)
6 | * [Original Repo](https://github.com/PatrickAlphaC/dao-template)
7 |
8 | ## Cloning the Repo
9 |
10 | Open up your terminal (or command prompt) and navigate to a directory you would like to store this code on. Once there type in the following command:
11 |
12 |
13 | ```
14 | git clone https://github.com/filecoin-project/fevm-data-dao-kit.git
15 | cd fevm-data-dao-kit
16 | yarn install
17 | ```
18 |
19 |
20 | This will clone the data dao kit onto your computer, switch directories into the newly installed kit, and install the dependencies the kit needs to work.
21 |
22 | ## Get a Private Key
23 |
24 | You can get a private key from a wallet provider [such as Metamask](https://metamask.zendesk.com/hc/en-us/articles/360015289632-How-to-export-an-account-s-private-key).
25 |
26 |
27 | ## Add your Private Key as an Environment Variable
28 |
29 | Add your private key as an environment variable by running this command:
30 |
31 | ```
32 | export PRIVATE_KEY='abcdef'
33 | ```
34 |
35 | If you use a .env file, don't commit and push any changes to .env files that may contain sensitive information, such as a private key! If this information reaches a public GitHub repository, someone can use it to check if you have any Mainnet funds in that wallet address, and steal them!
36 |
37 | ## Fund the Deployer Address
38 |
39 | Go to the [Calibration testnet faucet](https://faucet.calibration.fildev.network/), and paste in the Ethereum address from the previous step. This will send some Calibration testnet FIL to the account.
40 |
41 | ## Deploy the Contracts
42 |
43 | Currently there are 4 contracts in this repo:
44 |
45 | * DAO Deal Client: This is the [Filecoin Client Contract](https://github.com/filecoin-project/fvm-starter-kit-deal-making) which can propose deals to storage miners. This contract uses the [OpenZeppelin Ownable.sol contract](https://docs.openzeppelin.com/contracts/2.x/access-control#ownership-and-ownable) to switch the owner of this DealClient to be TimeLock.sol on deployment.
46 |
47 | * Data Governance Token: This contract mints [OpenZeppelin ERC20Votes](https://docs.openzeppelin.com/contracts/4.x/api/token/erc20#ERC20Votes) token which are used to vote on DAO proposals (or delegate another person to vote on your behalf).
48 |
49 | * Governor Contract: This contract, based on the [OpenZeppelin Governor contract](https://docs.openzeppelin.com/contracts/4.x/api/governance#Governor), manages proposals and votes. This is the "heart" of the DAO.
50 |
51 | * Time Lock: This contract, based on the [OpenZeppelin TimeLock contract](https://blog.openzeppelin.com/protect-your-users-with-smart-contract-timelocks/), creates a buffer between when proposals are passed and queued and when they can be executed. This allows gives users time to leave the DAO if a proposal that they don't agree with is passed.
52 |
53 |
54 | Type in the following command in the terminal to deploy all contracts:
55 |
56 | ```
57 | yarn hardhat deploy
58 | ```
59 |
60 | This will compile all the contracts in the contracts folder and deploy them automatically! The deployments scripts can be found in the deploy folder. This should also generate a deployments directory which can referenced for the address and details of each deployment.
61 |
62 | ## Preparing Data for Storage
63 |
64 | Before storing a file with a storage provider, it needs to be prepared by turning it into a .car file and the metadata must be recorded. To do this, the hardhat kit has a [tool submodule](https://github.com/filecoin-project/fevm-hardhat-kit/tree/main/tools), written in the language Go, which can do this for you. You can also use the [FVM Data Depot website](https://data.lighthouse.storage/) will automatically convert files to the .car format, output all the necessary metadata, and act as an HTTP retrieval point for the storage providers.
65 |
66 | ### How the Client Contract Works
67 |
68 | The client contract is an example contract that uses the Filecoin.sol API's to create storage deals via Solidity smart contracts on Filecoin. This works by emitting a Solidity event that [Boost storage providers](https://boost.filecoin.io/) can listen to. To learn more about this contract feel free to [checkout the app kit repo](https://github.com/filecoin-project/fvm-starter-kit-deal-making) which includes a detailed readme and a frontend.
--------------------------------------------------------------------------------
/hardhat/contracts/DaoDealClient.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity ^0.8.17;
3 |
4 | import "@openzeppelin/contracts/access/Ownable.sol";
5 | import {MarketAPI} from "@zondax/filecoin-solidity/contracts/v0.8/MarketAPI.sol";
6 | import {CommonTypes} from "@zondax/filecoin-solidity/contracts/v0.8/types/CommonTypes.sol";
7 | import {MarketTypes} from "@zondax/filecoin-solidity/contracts/v0.8/types/MarketTypes.sol";
8 | import {AccountTypes} from "@zondax/filecoin-solidity/contracts/v0.8/types/AccountTypes.sol";
9 | import {CommonTypes} from "@zondax/filecoin-solidity/contracts/v0.8/types/CommonTypes.sol";
10 | import {AccountCBOR} from "@zondax/filecoin-solidity/contracts/v0.8/cbor/AccountCbor.sol";
11 | import {MarketCBOR} from "@zondax/filecoin-solidity/contracts/v0.8/cbor/MarketCbor.sol";
12 | import {BytesCBOR} from "@zondax/filecoin-solidity/contracts/v0.8/cbor/BytesCbor.sol";
13 | import {BigNumbers, BigNumber} from "@zondax/solidity-bignumber/src/BigNumbers.sol";
14 | import {BigInts} from "@zondax/filecoin-solidity/contracts/v0.8/utils/BigInts.sol";
15 | import {CBOR} from "solidity-cborutils/contracts/CBOR.sol";
16 | import {Misc} from "@zondax/filecoin-solidity/contracts/v0.8/utils/Misc.sol";
17 | import {FilAddresses} from "@zondax/filecoin-solidity/contracts/v0.8/utils/FilAddresses.sol";
18 |
19 | using CBOR for CBOR.CBORBuffer;
20 |
21 | struct RequestId {
22 | bytes32 requestId;
23 | bool valid;
24 | }
25 |
26 | struct RequestIdx {
27 | uint256 idx;
28 | bool valid;
29 | }
30 |
31 | struct ProviderSet {
32 | bytes provider;
33 | bool valid;
34 | }
35 |
36 | // User request for this contract to make a deal. This structure is modelled after Filecoin's Deal
37 | // Proposal, but leaves out the provider, since any provider can pick up a deal broadcast by this
38 | // contract.
39 | struct DealRequest {
40 | bytes piece_cid;
41 | uint64 piece_size;
42 | bool verified_deal;
43 | string label;
44 | int64 start_epoch;
45 | int64 end_epoch;
46 | uint256 storage_price_per_epoch;
47 | uint256 provider_collateral;
48 | uint256 client_collateral;
49 | uint64 extra_params_version;
50 | ExtraParamsV1 extra_params;
51 | }
52 |
53 | // Extra parameters associated with the deal request. These are off-protocol flags that
54 | // the storage provider will need.
55 | struct ExtraParamsV1 {
56 | string location_ref;
57 | uint64 car_size;
58 | bool skip_ipni_announce;
59 | bool remove_unsealed_copy;
60 | }
61 |
62 | function serializeExtraParamsV1(
63 | ExtraParamsV1 memory params
64 | ) pure returns (bytes memory) {
65 | CBOR.CBORBuffer memory buf = CBOR.create(64);
66 | buf.startFixedArray(4);
67 | buf.writeString(params.location_ref);
68 | buf.writeUInt64(params.car_size);
69 | buf.writeBool(params.skip_ipni_announce);
70 | buf.writeBool(params.remove_unsealed_copy);
71 | return buf.data();
72 | }
73 |
74 | contract DaoDealClient is Ownable {
75 | using AccountCBOR for *;
76 | using MarketCBOR for *;
77 |
78 | uint64 public constant AUTHENTICATE_MESSAGE_METHOD_NUM = 2643134072;
79 | uint64 public constant DATACAP_RECEIVER_HOOK_METHOD_NUM = 3726118371;
80 | uint64 public constant MARKET_NOTIFY_DEAL_METHOD_NUM = 4186741094;
81 | address public constant MARKET_ACTOR_ETH_ADDRESS =
82 | address(0xff00000000000000000000000000000000000005);
83 | address public constant DATACAP_ACTOR_ETH_ADDRESS =
84 | address(0xfF00000000000000000000000000000000000007);
85 |
86 |
87 | enum Status {
88 | None,
89 | RequestSubmitted,
90 | DealPublished,
91 | DealActivated,
92 | DealTerminated
93 | }
94 |
95 | mapping(bytes32 => RequestIdx) public dealRequestIdx; // contract deal id -> deal index
96 | DealRequest[] public dealRequests;
97 |
98 | mapping(bytes => RequestId) public pieceRequests; // commP -> dealProposalID
99 | mapping(bytes => ProviderSet) public pieceProviders; // commP -> provider
100 | mapping(bytes => uint64) public pieceDeals; // commP -> deal ID
101 | mapping(bytes => Status) public pieceStatus;
102 |
103 | event ReceivedDataCap(string received);
104 | event DealProposalCreate(
105 | bytes32 indexed id,
106 | uint64 size,
107 | bool indexed verified,
108 | uint256 price
109 | );
110 |
111 | function getProviderSet(
112 | bytes calldata cid
113 | ) public view returns (ProviderSet memory) {
114 | return pieceProviders[cid];
115 | }
116 |
117 | function getProposalIdSet(
118 | bytes calldata cid
119 | ) public view returns (RequestId memory) {
120 | return pieceRequests[cid];
121 | }
122 |
123 | function dealsLength() public view returns (uint256) {
124 | return dealRequests.length;
125 | }
126 |
127 | function getDealByIndex(
128 | uint256 index
129 | ) public view returns (DealRequest memory) {
130 | return dealRequests[index];
131 | }
132 |
133 | function makeDealProposal(
134 | DealRequest calldata deal
135 | ) public onlyOwner returns (bytes32) {
136 |
137 | if (pieceStatus[deal.piece_cid] == Status.DealPublished ||
138 | pieceStatus[deal.piece_cid] == Status.DealActivated) {
139 | revert("deal with this pieceCid already published");
140 | }
141 |
142 | uint256 index = dealRequests.length;
143 | dealRequests.push(deal);
144 |
145 | // creates a unique ID for the deal proposal -- there are many ways to do this
146 | bytes32 id = keccak256(
147 | abi.encodePacked(block.timestamp, msg.sender, index)
148 | );
149 | dealRequestIdx[id] = RequestIdx(index, true);
150 |
151 | pieceRequests[deal.piece_cid] = RequestId(id, true);
152 | pieceStatus[deal.piece_cid] = Status.RequestSubmitted;
153 |
154 | // writes the proposal metadata to the event log
155 | emit DealProposalCreate(
156 | id,
157 | deal.piece_size,
158 | deal.verified_deal,
159 | deal.storage_price_per_epoch
160 | );
161 |
162 | return id;
163 | }
164 |
165 | // helper function to get deal request based from id
166 | function getDealRequest(
167 | bytes32 requestId
168 | ) internal view returns (DealRequest memory) {
169 | RequestIdx memory ri = dealRequestIdx[requestId];
170 | require(ri.valid, "proposalId not available");
171 | return dealRequests[ri.idx];
172 | }
173 |
174 | // Returns a CBOR-encoded DealProposal.
175 | function getDealProposal(
176 | bytes32 proposalId
177 | ) public view returns (bytes memory) {
178 | DealRequest memory deal = getDealRequest(proposalId);
179 |
180 | MarketTypes.DealProposal memory ret;
181 | ret.piece_cid = CommonTypes.Cid(deal.piece_cid);
182 | ret.piece_size = deal.piece_size;
183 | ret.verified_deal = deal.verified_deal;
184 | ret.client = FilAddresses.fromEthAddress(address(this));
185 | // Set a dummy provider. The provider that picks up this deal will need to set its own address.
186 | ret.provider = FilAddresses.fromActorID(0);
187 | ret.label = CommonTypes.DealLabel(bytes(deal.label), true);
188 | ret.start_epoch = CommonTypes.ChainEpoch.wrap(deal.start_epoch);
189 | ret.end_epoch = CommonTypes.ChainEpoch.wrap(deal.end_epoch);
190 | ret.storage_price_per_epoch = BigInts.fromUint256(
191 | deal.storage_price_per_epoch
192 | );
193 | ret.provider_collateral = BigInts.fromUint256(deal.provider_collateral);
194 | ret.client_collateral = BigInts.fromUint256(deal.client_collateral);
195 |
196 | return MarketCBOR.serializeDealProposal(ret);
197 | }
198 |
199 | function getExtraParams(
200 | bytes32 proposalId
201 | ) public view returns (bytes memory extra_params) {
202 | DealRequest memory deal = getDealRequest(proposalId);
203 | return serializeExtraParamsV1(deal.extra_params);
204 | }
205 |
206 |
207 | // authenticateMessage is the callback from the market actor into the contract
208 | // as part of PublishStorageDeals. This message holds the deal proposal from the
209 | // miner, which needs to be validated by the contract in accordance with the
210 | // deal requests made and the contract's own policies
211 | // @params - cbor byte array of AccountTypes.AuthenticateMessageParams
212 | function authenticateMessage(bytes memory params) internal view {
213 | require(
214 | msg.sender == MARKET_ACTOR_ETH_ADDRESS,
215 | "msg.sender needs to be market actor f05"
216 | );
217 |
218 | AccountTypes.AuthenticateMessageParams memory amp = params
219 | .deserializeAuthenticateMessageParams();
220 | MarketTypes.DealProposal memory proposal = MarketCBOR.deserializeDealProposal(
221 | amp.message
222 | );
223 |
224 | bytes memory pieceCid = proposal.piece_cid.data;
225 | require(pieceRequests[pieceCid].valid, "piece cid must be added before authorizing");
226 | require(!pieceProviders[pieceCid].valid, "deal failed policy check: provider already claimed this cid");
227 |
228 | DealRequest memory req = getDealRequest(pieceRequests[pieceCid].requestId);
229 | require(proposal.verified_deal == req.verified_deal, "verified_deal param mismatch");
230 | (uint256 proposalStoragePricePerEpoch, bool storagePriceConverted) = BigInts.toUint256(proposal.storage_price_per_epoch);
231 | require(!storagePriceConverted, "Issues converting uint256 to BigInt, may not have accurate values");
232 | (uint256 proposalClientCollateral, bool collateralConverted) = BigInts.toUint256(proposal.client_collateral);
233 | require(!collateralConverted, "Issues converting uint256 to BigInt, may not have accurate values");
234 | require(proposalStoragePricePerEpoch <= req.storage_price_per_epoch, "storage price greater than request amount");
235 | require(proposalClientCollateral <= req.client_collateral, "client collateral greater than request amount");
236 |
237 | }
238 |
239 | // dealNotify is the callback from the market actor into the contract at the end
240 | // of PublishStorageDeals. This message holds the previously approved deal proposal
241 | // and the associated dealID. The dealID is stored as part of the contract state
242 | // and the completion of this call marks the success of PublishStorageDeals
243 | // @params - cbor byte array of MarketDealNotifyParams
244 | function dealNotify(bytes memory params) internal {
245 | require(
246 | msg.sender == MARKET_ACTOR_ETH_ADDRESS,
247 | "msg.sender needs to be market actor f05"
248 | );
249 |
250 | MarketTypes.MarketDealNotifyParams memory mdnp = MarketCBOR.deserializeMarketDealNotifyParams(
251 | params
252 | );
253 | MarketTypes.DealProposal memory proposal = MarketCBOR.deserializeDealProposal(
254 | mdnp.dealProposal
255 | );
256 |
257 | // These checks prevent race conditions between the authenticateMessage and
258 | // marketDealNotify calls where someone could have 2 of the same deal proposals
259 | // within the same PSD msg, which would then get validated by authenticateMessage
260 | // However, only one of those deals should be allowed
261 | require(
262 | pieceRequests[proposal.piece_cid.data].valid,
263 | "piece cid must be added before authorizing"
264 | );
265 | require(
266 | !pieceProviders[proposal.piece_cid.data].valid,
267 | "deal failed policy check: provider already claimed this cid"
268 | );
269 |
270 | pieceProviders[proposal.piece_cid.data] = ProviderSet(
271 | proposal.provider.data,
272 | true
273 | );
274 | pieceDeals[proposal.piece_cid.data] = mdnp.dealId;
275 | pieceStatus[proposal.piece_cid.data] = Status.DealPublished;
276 | }
277 |
278 |
279 | // This function can be called/smartly polled to retrieve the deal activation status
280 | // associated with provided pieceCid and update the contract state based on that
281 | // info
282 | // @pieceCid - byte representation of pieceCid
283 | function updateActivationStatus(bytes memory pieceCid) public {
284 | require(pieceDeals[pieceCid] > 0, "no deal published for this piece cid");
285 |
286 | MarketTypes.GetDealActivationReturn memory ret = MarketAPI.getDealActivation(pieceDeals[pieceCid]);
287 | if (CommonTypes.ChainEpoch.unwrap(ret.terminated) > 0) {
288 | pieceStatus[pieceCid] = Status.DealTerminated;
289 | } else if (CommonTypes.ChainEpoch.unwrap(ret.activated) > 0) {
290 | pieceStatus[pieceCid] = Status.DealActivated;
291 | }
292 | }
293 |
294 | // addBalance funds the builtin storage market actor's escrow
295 | // with funds from the contract's own balance
296 | // @value - amount to be added in escrow in attoFIL
297 | function addBalance(uint256 value) public onlyOwner {
298 | MarketAPI.addBalance(FilAddresses.fromEthAddress(address(this)), value);
299 | }
300 |
301 | // This function attempts to withdraw the specified amount from the contract addr's escrow balance
302 | // If less than the given amount is available, the full escrow balance is withdrawn
303 | // @client - Eth address where the balance is withdrawn to. This can be the contract address or an external address
304 | // @value - amount to be withdrawn in escrow in attoFIL
305 | function withdrawBalance(
306 | address client,
307 | uint256 value
308 | ) public onlyOwner returns (uint) {
309 |
310 | MarketTypes.WithdrawBalanceParams memory params = MarketTypes
311 | .WithdrawBalanceParams(
312 | FilAddresses.fromEthAddress(client),
313 | BigInts.fromUint256(value)
314 | );
315 | CommonTypes.BigInt memory ret = MarketAPI.withdrawBalance(params);
316 |
317 | (uint256 withdrawBalanceAmount, bool withdrawBalanceConverted) = BigInts.toUint256(ret);
318 | require(withdrawBalanceConverted, "Problems converting withdraw balance into Big Int, may cause an overflow");
319 |
320 | return withdrawBalanceAmount;
321 | }
322 |
323 | function receiveDataCap(bytes memory params) internal {
324 | require(
325 | msg.sender == DATACAP_ACTOR_ETH_ADDRESS,
326 | "msg.sender needs to be datacap actor f07"
327 | );
328 | emit ReceivedDataCap("DataCap Received!");
329 | // Add get datacap balance api and store datacap amount
330 | }
331 |
332 |
333 | // handle_filecoin_method is the universal entry point for any evm based
334 | // actor for a call coming from a builtin filecoin actor
335 | // @method - FRC42 method number for the specific method hook
336 | // @params - CBOR encoded byte array params
337 | function handle_filecoin_method(
338 | uint64 method,
339 | uint64,
340 | bytes memory params
341 | ) public returns (uint32, uint64, bytes memory) {
342 | bytes memory ret;
343 | uint64 codec;
344 | // dispatch methods
345 | if (method == AUTHENTICATE_MESSAGE_METHOD_NUM) {
346 | authenticateMessage(params);
347 | // If we haven't reverted, we should return a CBOR true to indicate that verification passed.
348 | CBOR.CBORBuffer memory buf = CBOR.create(1);
349 | buf.writeBool(true);
350 | ret = buf.data();
351 | codec = Misc.CBOR_CODEC;
352 | } else if (method == MARKET_NOTIFY_DEAL_METHOD_NUM) {
353 | dealNotify(params);
354 | } else if (method == DATACAP_RECEIVER_HOOK_METHOD_NUM) {
355 | receiveDataCap(params);
356 | } else {
357 | revert("the filecoin method that was called is not handled");
358 | }
359 | return (0, codec, ret);
360 | }
361 | }
--------------------------------------------------------------------------------
/hardhat/contracts/DataGovernanceToken.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity ^0.8.17;
3 |
4 | import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol";
5 |
6 | contract DataGovernanceToken is ERC20Votes {
7 | uint256 public s_maxSupply = 1000000000000000000000000;
8 |
9 | constructor()
10 | ERC20("DataGovernanceToken", "DGT")
11 | ERC20Permit("DataGovernanceToken")
12 | {
13 | _mint(msg.sender, s_maxSupply);
14 | }
15 |
16 | function _afterTokenTransfer(
17 | address from,
18 | address to,
19 | uint256 amount
20 | ) internal override(ERC20Votes) {
21 | super._afterTokenTransfer(from, to, amount);
22 | }
23 |
24 | function _mint(address to, uint256 amount) internal override(ERC20Votes) {
25 | super._mint(to, amount);
26 | }
27 |
28 | function _burn(address account, uint256 amount) internal override(ERC20Votes) {
29 | super._burn(account, amount);
30 | }
31 | }
--------------------------------------------------------------------------------
/hardhat/contracts/GovernorContract.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity ^0.8.17;
3 |
4 | import "@openzeppelin/contracts/governance/Governor.sol";
5 | import "@openzeppelin/contracts/governance/extensions/GovernorSettings.sol";
6 | import "@openzeppelin/contracts/governance/extensions/GovernorCountingSimple.sol";
7 | import "@openzeppelin/contracts/governance/extensions/GovernorVotes.sol";
8 | import "@openzeppelin/contracts/governance/extensions/GovernorVotesQuorumFraction.sol";
9 | import "@openzeppelin/contracts/governance/extensions/GovernorTimelockControl.sol";
10 |
11 | contract GovernorContract is
12 | Governor,
13 | GovernorSettings,
14 | GovernorCountingSimple,
15 | GovernorVotes,
16 | GovernorVotesQuorumFraction,
17 | GovernorTimelockControl
18 | {
19 | constructor(
20 | IVotes _token,
21 | TimelockController _timelock,
22 | uint256 _votingDelay,
23 | uint256 _votingPeriod,
24 | uint256 _quorumPercentage
25 | )
26 | Governor("GovernorContract")
27 | GovernorSettings(_votingDelay, _votingPeriod, 0)
28 | GovernorVotes(_token)
29 | GovernorVotesQuorumFraction(_quorumPercentage)
30 | GovernorTimelockControl(_timelock)
31 | {}
32 | // The following functions are overrides required by Solidity.
33 |
34 | function votingDelay()
35 | public
36 | view
37 | override(IGovernor, GovernorSettings)
38 | returns (uint256)
39 | {
40 | return super.votingDelay();
41 | }
42 |
43 | function votingPeriod()
44 | public
45 | view
46 | override(IGovernor, GovernorSettings)
47 | returns (uint256)
48 | {
49 | return super.votingPeriod();
50 | }
51 |
52 | function quorum(uint256 blockNumber)
53 | public
54 | view
55 | override(IGovernor, GovernorVotesQuorumFraction)
56 | returns (uint256)
57 | {
58 | return super.quorum(blockNumber);
59 | }
60 |
61 | function state(uint256 proposalId)
62 | public
63 | view
64 | override(Governor, GovernorTimelockControl)
65 | returns (ProposalState)
66 | {
67 | return super.state(proposalId);
68 | }
69 |
70 | function propose(address[] memory targets, uint256[] memory values, bytes[] memory calldatas, string memory description)
71 | public
72 | override(Governor, IGovernor)
73 | returns (uint256)
74 | {
75 | return super.propose(targets, values, calldatas, description);
76 | }
77 |
78 | function proposalThreshold()
79 | public
80 | view
81 | override(Governor, GovernorSettings)
82 | returns (uint256)
83 | {
84 | return super.proposalThreshold();
85 | }
86 |
87 | function _execute(uint256 proposalId, address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash)
88 | internal
89 | override(Governor, GovernorTimelockControl)
90 | {
91 | super._execute(proposalId, targets, values, calldatas, descriptionHash);
92 | }
93 |
94 | function _cancel(address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash)
95 | internal
96 | override(Governor, GovernorTimelockControl)
97 | returns (uint256)
98 | {
99 | return super._cancel(targets, values, calldatas, descriptionHash);
100 | }
101 |
102 | function _executor()
103 | internal
104 | view
105 | override(Governor, GovernorTimelockControl)
106 | returns (address)
107 | {
108 | return super._executor();
109 | }
110 |
111 | function supportsInterface(bytes4 interfaceId)
112 | public
113 | view
114 | override(Governor, GovernorTimelockControl)
115 | returns (bool)
116 | {
117 | return super.supportsInterface(interfaceId);
118 | }
119 | }
--------------------------------------------------------------------------------
/hardhat/contracts/TimeLock.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity ^0.8.17;
3 |
4 | import "@openzeppelin/contracts/governance/TimelockController.sol";
5 |
6 | contract TimeLock is TimelockController {
7 |
8 | constructor(
9 | uint256 minDelay,
10 | address[] memory proposers,
11 | address[] memory executors,
12 | address admin
13 | ) TimelockController(minDelay, proposers, executors, admin) {}
14 | }
--------------------------------------------------------------------------------
/hardhat/deploy/01-data-governance-token-deploy.js:
--------------------------------------------------------------------------------
1 | require("hardhat-deploy")
2 | require("hardhat-deploy-ethers")
3 |
4 |
5 | const private_key = network.config.accounts[0]
6 | const wallet = new ethers.Wallet(private_key, ethers.provider)
7 |
8 | module.exports = async ({ deployments }) => {
9 | const { deploy } = deployments;
10 |
11 | const dataGovernanceToken = await deploy("DataGovernanceToken", {
12 | from: wallet.address,
13 | args: [],
14 | log: true,
15 | });
16 |
17 | //Define function to delegate to deployer wallet
18 | const delegate = async (
19 | dataGovernanceTokenAddress,
20 | delegatedAccount
21 | ) => {
22 | const dataGovernanceToken = await ethers.getContractAt(
23 | "DataGovernanceToken",
24 | dataGovernanceTokenAddress
25 | );
26 | delegateTx = await dataGovernanceToken.delegate(delegatedAccount);
27 | await delegateTx.wait();
28 | console.log(
29 | `Checkpoints ${await dataGovernanceToken.numCheckpoints(delegatedAccount)}`
30 | );
31 | }
32 |
33 | //Call delegate function below
34 | await delegate(dataGovernanceToken.address, wallet.address);
35 | console.log("Delegated to deployer wallet!")
36 | }
--------------------------------------------------------------------------------
/hardhat/deploy/02-time-lock-deploy.js:
--------------------------------------------------------------------------------
1 | require("hardhat-deploy")
2 | require("hardhat-deploy-ethers")
3 |
4 |
5 | const private_key = network.config.accounts[0]
6 | const wallet = new ethers.Wallet(private_key, ethers.provider)
7 |
8 | module.exports = async ({ deployments }) => {
9 | const { deploy } = deployments;
10 |
11 | const timeLock = await deploy("TimeLock", {
12 | from: wallet.address,
13 | args: [1, [], [], wallet.address],
14 | log: true,
15 | });
16 | }
--------------------------------------------------------------------------------
/hardhat/deploy/03-governor-contract-deploy.js:
--------------------------------------------------------------------------------
1 | require("hardhat-deploy")
2 | require("hardhat-deploy-ethers")
3 |
4 |
5 | const private_key = network.config.accounts[0]
6 | const wallet = new ethers.Wallet(private_key, ethers.provider)
7 |
8 | module.exports = async ({ deployments }) => {
9 | const { deploy, get } = deployments;
10 |
11 | const dataGovernanceToken = await get("DataGovernanceToken")
12 | const timeLock = await get("TimeLock")
13 |
14 | const governorContract = await deploy("GovernorContract", {
15 | from: wallet.address,
16 | args: [dataGovernanceToken.address, timeLock.address, 5, 100, 0],
17 | log: true,
18 | });
19 | }
--------------------------------------------------------------------------------
/hardhat/deploy/04-setup-roles.js:
--------------------------------------------------------------------------------
1 |
2 | require("hardhat-deploy")
3 | require("hardhat-deploy-ethers")
4 |
5 |
6 | const private_key = network.config.accounts[0]
7 | const wallet = new ethers.Wallet(private_key, ethers.provider)
8 |
9 | module.exports = async ({ deployments }) => {
10 | const { get } = deployments;
11 |
12 | const governor = await get("GovernorContract")
13 | const timeLock = await get("TimeLock")
14 |
15 | //Set Roles in TimeLock.sol
16 | //This gives control only to DAO
17 | console.log("Setting roles in TimeLock.sol")
18 | const timeLockContract = await ethers.getContractAt("TimeLock", timeLock.address)
19 |
20 | const proposerRole = await timeLockContract.PROPOSER_ROLE()
21 | const executorRole = await timeLockContract.EXECUTOR_ROLE()
22 | const adminRole = await timeLockContract.TIMELOCK_ADMIN_ROLE()
23 |
24 | const proposerTx = await timeLockContract.grantRole(proposerRole, governor.address)
25 | await proposerTx.wait()
26 | const executorTx = await timeLockContract.grantRole(executorRole, "0x0000000000000000000000000000000000000000")
27 | await executorTx.wait()
28 | const revokeTx = await timeLockContract.revokeRole(adminRole, wallet.address)
29 | await revokeTx.wait()
30 | console.log("Roles in TimeLock.sol set!")
31 | }
--------------------------------------------------------------------------------
/hardhat/deploy/05-dao-deal-client-deploy.js:
--------------------------------------------------------------------------------
1 | require("hardhat-deploy")
2 | require("hardhat-deploy-ethers")
3 |
4 |
5 | const private_key = network.config.accounts[0]
6 | const wallet = new ethers.Wallet(private_key, ethers.provider)
7 |
8 | module.exports = async ({ deployments }) => {
9 | const { deploy, get } = deployments;
10 | const timeLock = await get("TimeLock")
11 |
12 | const daoDealClient = await deploy("DaoDealClient", {
13 | from: wallet.address,
14 | args: [],
15 | log: true,
16 | });
17 |
18 | //Transfer Ownership to TimeLock.sol
19 | //Comment this out after deploying the first time
20 | console.log("Transferring DaoDealClient Owner to TimeLock.sol")
21 | const dealDaoClientContract = await ethers.getContractAt("DaoDealClient", daoDealClient.address)
22 | const transferOwnerTx = await dealDaoClientContract.transferOwnership(timeLock.address);
23 | await transferOwnerTx.wait();
24 | console.log("Ownership transferred");
25 | }
--------------------------------------------------------------------------------
/hardhat/hardhat.config.js:
--------------------------------------------------------------------------------
1 | require("@nomicfoundation/hardhat-toolbox")
2 | require("hardhat-deploy")
3 | require("hardhat-deploy-ethers")
4 | require("./tasks")
5 | require("dotenv").config()
6 |
7 | const PRIVATE_KEY = process.env.PRIVATE_KEY
8 | /** @type import('hardhat/config').HardhatUserConfig */
9 | module.exports = {
10 | solidity: {
11 | version: "0.8.17",
12 | settings: {
13 | optimizer: {
14 | enabled: true,
15 | runs: 1000,
16 | details: { yul: false },
17 | },
18 | },
19 | },
20 | defaultNetwork: "Calibration",
21 | networks: {
22 | Calibration: {
23 | chainId: 314159,
24 | url: "https://api.calibration.node.glif.io/rpc/v1",
25 | accounts: [PRIVATE_KEY],
26 | },
27 | FilecoinMainnet: {
28 | chainId: 314,
29 | url: "https://api.node.glif.io",
30 | accounts: [PRIVATE_KEY],
31 | },
32 | },
33 | paths: {
34 | sources: "./contracts",
35 | tests: "./test",
36 | cache: "./cache",
37 | artifacts: "./artifacts",
38 | },
39 | }
40 |
--------------------------------------------------------------------------------
/hardhat/helper-hardhat-config.js:
--------------------------------------------------------------------------------
1 | const { ethers } = require("hardhat")
2 |
3 | const networkConfig = {
4 | 314159: {
5 | name: "Calibration",
6 | },
7 | 314: {
8 | name: "FilecoinMainnet",
9 | },
10 | }
11 |
12 | const extraParamsV1 = [
13 | 'https://data-depot.lighthouse.storage/api/download/download_car?fileId=65e0bdfa-5fd3-4de7-ade1-045a8c7b353c.car',
14 | 1439273,
15 | 'true',
16 | 'false',
17 | ]
18 |
19 | const DealRequestStruct = [
20 | '0x000181e20392202007554549d24e42b38403cbd9d30d30299010c75e8473c4a131c6fa5b04267220',
21 | 2097152,
22 | false,
23 | 'bafybeicxcclvlid2ocrksh52lub3ny6vd3muic5etjppd2r7g6pcfdxufm',
24 | 270000,
25 | 700000,
26 | 0,
27 | 0,
28 | 0,
29 | 1,
30 | extraParamsV1,
31 | ]
32 |
33 | const proposalsFile = "proposals.json"
34 |
35 | const PROPOSAL_DESCRIPTION = "Proposal #1 Store ATTAK_CAT!"
36 |
37 | module.exports = {
38 | networkConfig,
39 | DealRequestStruct,
40 | proposalsFile,
41 | PROPOSAL_DESCRIPTION
42 | }
43 |
--------------------------------------------------------------------------------
/hardhat/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "FEVM-Hardhat-Kit",
3 | "version": "1.0.0",
4 | "description": "",
5 | "scripts": {
6 | "compile": "hardhat compile",
7 | "test": "hardhat test test/unit/*_test.js --network hardhat",
8 | "test-staging": "hardhat test test/staging/*_test.js --network goerli",
9 | "lint": "solhint 'contracts/*.sol'",
10 | "lint:fix": "solhint 'contracts/**/*.sol' --fix",
11 | "format": "prettier --write .",
12 | "coverage": "hardhat coverage --solcoverjs ./.solcover.js",
13 | "fuzzing": "docker run -it --rm -v $PWD:/src trailofbits/eth-security-toolbox"
14 | },
15 | "license": "MIT",
16 | "devDependencies": {
17 | "@nomiclabs/hardhat-ethers": "npm:hardhat-deploy-ethers@^0.3.0-beta.13",
18 | "@nomiclabs/hardhat-etherscan": "^3.0.0",
19 | "@nomiclabs/hardhat-waffle": "^2.0.1",
20 | "@types/chai": "^4.3.4",
21 | "@types/mocha": "^10.0.1",
22 | "@types/node": "^18.11.15",
23 | "chai": "^4.3.7",
24 | "cids": "^1.1.9",
25 | "ethereum-waffle": "^3.4.0",
26 | "ethers": "^5.5.1",
27 | "fs": "^0.0.1-security",
28 | "hardhat": "^2.11.2",
29 | "hardhat-contract-sizer": "^2.4.0",
30 | "hardhat-deploy": "^0.9.29",
31 | "hardhat-gas-reporter": "^1.0.7",
32 | "prettier": "^2.4.1",
33 | "prettier-plugin-solidity": "^1.0.0-beta.19",
34 | "solhint": "^3.3.6",
35 | "solidity-coverage": "^0.7.13"
36 | },
37 | "dependencies": {
38 | "@glif/filecoin-address": "^2.0.18",
39 | "@lighthouse-web3/sdk": "^0.2.6",
40 | "@nomicfoundation/hardhat-chai-matchers": "^1.0.0",
41 | "@nomicfoundation/hardhat-network-helpers": "^1.0.0",
42 | "@nomicfoundation/hardhat-toolbox": "^2.0.0",
43 | "@openzeppelin/contracts": "^4.9.3",
44 | "@typechain/hardhat": "^6.1.2",
45 | "@zondax/filecoin-solidity": "^4.0.2",
46 | "axios": "^1.4.0",
47 | "babel-eslint": "^10.1.0",
48 | "dotenv": "^10.0.0",
49 | "hardhat-deploy-ethers": "^0.3.0-beta.13",
50 | "ts-node": "^10.9.1",
51 | "typescript": "^4.9.4"
52 | },
53 | "mocha": {
54 | "timeout": 10000000
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/hardhat/proposals.json:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/hardhat/scripts/lighthouse-sdk/get-api-key.mjs:
--------------------------------------------------------------------------------
1 | import lighthouse from '@lighthouse-web3/sdk'
2 | import axios from 'axios'
3 | import pkg from 'hardhat'
4 | import fs from 'fs';
5 | import path from 'path';
6 | import dotenv from 'dotenv';
7 | import { fileURLToPath } from 'url';
8 |
9 | const { ethers, network } = pkg;
10 |
11 | const PRIVATE_KEY = network.config.accounts[0];
12 | const wallet = new ethers.Wallet(PRIVATE_KEY);
13 | const address = wallet.address;
14 |
15 | const signAuthMessage = async(privateKey, messageRequested) =>{
16 | const signer = new ethers.Wallet(privateKey);
17 | const signedMessage = await signer.signMessage(messageRequested);
18 | return(signedMessage)
19 | }
20 |
21 | const getApiKey = async() =>{
22 | const wallet = {
23 | publicKey: address, //>> Example: '0xEaF4E24ffC1A2f53c07839a74966A6611b8Cb8A1'
24 | privateKey: PRIVATE_KEY
25 | }
26 | const verificationMessage = (
27 | await axios.get(
28 | `https://api.lighthouse.storage/api/auth/get_message?publicKey=${wallet.publicKey}`
29 | )
30 | ).data
31 | const signedMessage = await signAuthMessage(wallet.privateKey, verificationMessage)
32 | const response = await lighthouse.getApiKey(wallet.publicKey, signedMessage)
33 | console.log(response)
34 | const apiKey = response.data.apiKey;
35 | const dirname = path.dirname(fileURLToPath(import.meta.url));
36 | const envPath = path.join(dirname, '..', '..', '.env');
37 | // Read the current content of the .env file
38 | const envContent = fs.readFileSync(envPath, 'utf-8');
39 |
40 | // Replace the existing API_KEY value or append a new one
41 | const newEnvContent = envContent.includes('API_KEY=')
42 | ? envContent.replace(/API_KEY=.*/, `API_KEY="${apiKey}"`)
43 | : envContent + `\nAPI_KEY="${apiKey}"`;
44 |
45 | // Write the updated content back to the .env file
46 | fs.writeFileSync(envPath, newEnvContent);
47 |
48 | }
49 |
50 | getApiKey()
51 |
--------------------------------------------------------------------------------
/hardhat/scripts/lighthouse-sdk/upload-file.mjs:
--------------------------------------------------------------------------------
1 | import * as dotenv from 'dotenv';
2 | dotenv.config();
3 | import lighthouse from '@lighthouse-web3/sdk';
4 |
5 | const uploadFile = async () => {
6 | const path = "YOUR_FILE_PATH"; // Provide the path to the file
7 | const apiKey = process.env.API_KEY;
8 | // Generate the API key from https://files.lighthouse.storage/
9 | //or using CLI (lighthouse-web3 api-key --new)
10 |
11 | // Both files and folders are supported by the upload function
12 | const response = await lighthouse.upload(path, apiKey);
13 |
14 | console.log(response);
15 | console.log("Visit at: https://gateway.lighthouse.storage/ipfs/" + response.data.Hash);
16 | }
17 |
18 | uploadFile();
--------------------------------------------------------------------------------
/hardhat/scripts/propose.js:
--------------------------------------------------------------------------------
1 | const { ethers, network } = require("hardhat");
2 | const { DealRequestStruct, PROPOSAL_DESCRIPTION, proposalsFile } = require("../helper-hardhat-config");
3 | const fs = require("fs");
4 |
5 | function storeProposalId(proposalId) {
6 | const chainId = network.config.chainId.toString();
7 | let proposals;
8 | try {
9 | const fileContent = fs.readFileSync(proposalsFile, "utf8");
10 | proposals = JSON.parse(fileContent);
11 | } catch (err) {
12 | console.error(`Error reading or parsing the proposalsFile: ${err.message}`);
13 | // You can initialize `proposals` with a default value if you'd like
14 | proposals = {};
15 | }
16 | // Ensure there is an array for the current chainId
17 | if (!proposals[chainId]) {
18 | proposals[chainId] = [];
19 | }
20 |
21 | proposals[chainId].push(proposalId.toString());
22 | fs.writeFileSync(proposalsFile, JSON.stringify(proposals), "utf8");
23 | }
24 |
25 | async function propose(args, functionToCall, proposalDescription) {
26 | const governor = await ethers.getContract("GovernorContract");
27 | const daoDealClient = await ethers.getContract("DaoDealClient");
28 | const encodedFunctionCall = daoDealClient.interface.encodeFunctionData(functionToCall, args);
29 | console.log(`Proposing ${functionToCall} on ${daoDealClient.address} with ${args}`);
30 | console.log(`Proposal Description:\n${proposalDescription}`);
31 | const proposeTx = await governor.propose(
32 | [daoDealClient.address],
33 | [0],
34 | [encodedFunctionCall],
35 | proposalDescription
36 | )
37 |
38 | const proposeReceipt = await proposeTx.wait()
39 | const proposalId = proposeReceipt.events[0].args.proposalId
40 | console.log(`Proposed with proposal ID:\n ${proposalId}`)
41 | const proposalState = await governor.state(proposalId)
42 |
43 | // save the proposalId
44 | storeProposalId(proposalId);
45 |
46 | // the Proposal State is an enum data type, defined in the IGovernor contract.
47 | // 0:Pending, 1:Active, 2:Canceled, 3:Defeated, 4:Succeeded, 5:Queued, 6:Expired, 7:Executed
48 | console.log(`Current Proposal State: ${proposalState}`)
49 | }
50 |
51 |
52 | propose([DealRequestStruct], "makeDealProposal", PROPOSAL_DESCRIPTION)
53 | .then(() => process.exit(0))
54 | .catch((error) => {
55 | console.error(error)
56 | process.exit(1)
57 | })
--------------------------------------------------------------------------------
/hardhat/scripts/queue-and-execute.js:
--------------------------------------------------------------------------------
1 | const { ethers, network } = require("hardhat")
2 | const {DealRequestStruct,
3 | PROPOSAL_DESCRIPTION,} =
4 | require("../helper-hardhat-config")
5 |
6 | async function queueAndExecute() {
7 | const args = [DealRequestStruct]
8 | const functionToCall = "makeDealProposal"
9 | const daoDealClient = await ethers.getContract("DaoDealClient")
10 | const encodedFunctionCall = daoDealClient.interface.encodeFunctionData(functionToCall, args)
11 | const descriptionHash = ethers.utils.keccak256(ethers.utils.toUtf8Bytes(PROPOSAL_DESCRIPTION))
12 | // could also use ethers.utils.id(PROPOSAL_DESCRIPTION)
13 |
14 | const governor = await ethers.getContract("GovernorContract")
15 | console.log("Queueing...")
16 | const queueTx = await governor.queue([daoDealClient.address], [0], [encodedFunctionCall], descriptionHash)
17 | await queueTx.wait(1)
18 |
19 | console.log("Executing...")
20 | // this will fail on a testnet because you need to wait for the MIN_DELAY!
21 | const executeTx = await governor.execute(
22 | [daoDealClient.address],
23 | [0],
24 | [encodedFunctionCall],
25 | descriptionHash
26 | )
27 | await executeTx.wait()
28 | console.log("Queued and Executed!")
29 | }
30 |
31 | queueAndExecute()
32 | .then(() => process.exit(0))
33 | .catch((error) => {
34 | console.error(error)
35 | process.exit(1)
36 | })
37 |
--------------------------------------------------------------------------------
/hardhat/scripts/vote.js:
--------------------------------------------------------------------------------
1 | const fs = require("fs")
2 | const { network, ethers } = require("hardhat")
3 | const { proposalsFile, developmentChains, VOTING_PERIOD } = require("../helper-hardhat-config")
4 |
5 |
6 |
7 | async function main() {
8 | const proposals = JSON.parse(fs.readFileSync(proposalsFile, "utf8"))
9 | // Get the last proposal for the network. You could also change it for your index
10 | const proposalId = proposals[network.config.chainId].at(-1);
11 | // 0 = Against, 1 = For, 2 = Abstain for this example
12 | const voteWay = 1
13 | const reason = "Lets get that cat stored"
14 | await vote(proposalId, voteWay, reason)
15 | }
16 |
17 | // 0 = Against, 1 = For, 2 = Abstain for this example
18 | async function vote(proposalId, voteWay, reason) {
19 | console.log("Voting...")
20 | const governor = await ethers.getContract("GovernorContract")
21 | const voteTx = await governor.castVoteWithReason(proposalId, voteWay, reason)
22 | const voteTxReceipt = await voteTx.wait(1)
23 | console.log(voteTxReceipt.events[0].args.reason)
24 | const proposalState = await governor.state(proposalId)
25 | console.log(`Current Proposal State: ${proposalState}`)
26 | }
27 |
28 | main()
29 | .then(() => process.exit(0))
30 | .catch((error) => {
31 | console.error(error)
32 | process.exit(1)
33 | })
--------------------------------------------------------------------------------
/hardhat/tasks/cid-to-bytes.js:
--------------------------------------------------------------------------------
1 | const CID = require('cids')
2 |
3 | task(
4 | "cid-to-bytes",
5 | "Converts CID to EVM compatible hex bytes."
6 | )
7 | .addParam("cid", "The piece CID of the data you want to put up a bounty for")
8 | .setAction(async (taskArgs) => {
9 | //store taskargs as useable variables
10 | const cid = taskArgs.cid
11 |
12 | //convert piece CID string to hex bytes
13 | const cidHexRaw = new CID(cid).toString('base16').substring(1)
14 | const cidHex = "0x00" + cidHexRaw
15 | console.log("Hex bytes are:", cidHex)
16 | console.log("Complete!")
17 | })
--------------------------------------------------------------------------------
/hardhat/tasks/get-address.js:
--------------------------------------------------------------------------------
1 | const fa = require("@glif/filecoin-address");
2 |
3 | task("get-address", "Gets Filecoin f4 address and corresponding Ethereum address.")
4 | .setAction(async (taskArgs) => {
5 |
6 | //create new Wallet object from private key
7 | const DEPLOYER_PRIVATE_KEY = network.config.accounts[0]
8 | const deployer = new ethers.Wallet(DEPLOYER_PRIVATE_KEY);
9 |
10 | //Convert Ethereum address to f4 address
11 | const f4Address = fa.newDelegatedEthAddress(deployer.address).toString();
12 | console.log("Ethereum address (this addresss should work for most tools):", deployer.address);
13 | console.log("f4address (also known as t4 address on testnets):", f4Address);
14 | })
--------------------------------------------------------------------------------
/hardhat/tasks/index.js:
--------------------------------------------------------------------------------
1 | exports.getAddress = require("./get-address")
2 | exports.cidToBytes = require("./cid-to-bytes")
--------------------------------------------------------------------------------