Thirdweb is a platform that gives a collection of instruments for creators, artists, and entrepreneurs to construct, launch and handle a Web3 mission simply.
It allows customers so as to add options equivalent to NFTs, marketplaces, and social tokens to their Web3 initiatives with out writing a line of code.
On this article, you may higher perceive what DAO is, why you must create a DAO, and how one can create a DAO with Thirdweb.
It will enable customers to mint your DAO’s NFT, obtain cryptocurrency by way of airdrops, and take part within the DAO’s polls.
Conditions
Earlier than you possibly can proceed with this tutorial, you must:
- Have Metamask put in
- Have data of JavaScript/React.js, and the blockchain
- Have arrange an account with Alchemy
What’s a DAO?
Decentralized autonomous organizations (DAOs) are a sort of governance generally used for DApps, initiatives, and crypto-investment funds. DAOs are well-known for his or her openness, decentralization, and dealing with self-executing sensible contracts. There are such a lot of totally different definitions and explanations of what a DAO is.
Basically phrases, DAOs are member-owned communities with out centralized management. The exact authorized standing of one of these enterprise group is unclear. A DAO’s monetary transaction data and program guidelines are maintained on a blockchain.
Organising the DAO Consumer-side
To start out constructing your DAO client-side utility, you may be utilizing the thirdweb-CLI
command.
First, Set up the Thirdweb CLI globally device by typing the under command:
yarn add @thirdweb-dev/cli
Thirdweb accommodates starters that assist generate a base setup in your mission. Use the command under to generate a Thirdweb starter mission. Sort a mission title and identify of your selection for the mission listing. Comply with the prompts to finish the setup.
npx thirdweb create
As soon as the set up is full, head over to the mission listing and run the command under to begin your utility:
npm begin
Navigate to localhost:3000 to view your mission on a browser.
Get Metamask
Subsequent, you want an Ethereum pockets. There are a bunch of those, however for this mission, you’ll use Metamask. Obtain the browser extension and arrange your pockets right here. Even when you have already got one other pockets supplier, simply use Metamask for now.
However why Metamask?
Properly. You want to have the ability to name capabilities in your sensible contract that reside on the blockchain. And to do this, it’s essential have a pockets together with your Ethereum handle and personal key.
It is virtually like authentication. You want one thing to “Login” to the blockchain after which use these login credentials to make API requests out of your web site.
So, in your web site to speak to the blockchain, it’s essential one way or the other join your pockets to it. When you join your pockets to the web site, your web site may have permission to name sensible contracts in your behalf. Keep in mind, it is similar to authenticating into a web site.
So, go forward and set all of it up! Their setup stream is fairly self-explanatory.
When you arrange your pockets, change the community to “Rinkeby”, the take a look at community you may be working with.
Be sure you have testnet funds
You are not going to be deploying to the “Ethereum mainnet”. Why? As a result of it prices actual funds, and it isn’t price messing up. You are going to begin with a “testnet,” which is a clone of “mainnet,” nevertheless it makes use of pretend funds; you possibly can take a look at stuff out as a lot as you need. However, it is vital to know that testnets are run by precise miners and mimic real-world eventualities.
You will be utilizing Rinkeby, which the Ethereum Basis runs. To get some pretend ETH, head to the RINKEBY FAUCET web site, paste your handle within the enter type, and click on on the “Ship Me ETH” button.
As soon as your transaction is mined, you may have some pretend ETH in your pockets.
Specify your chain and pockets kind
So, in your web site to speak to the blockchain, it’s essential one way or the other join your pockets to it. When you join your pockets to your web site, the web site may have permission to name sensible contracts in your behalf. Keep in mind, it is similar to authenticating into a web site.
You might have constructed “Hook up with Pockets” buttons prior to now! This time, you may be utilizing thirdweb’s front-end SDK
, which makes it loopy straightforward.
Head over to src/index.js
in your React App and add the next code:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { ChainId, ThirdwebProvider } from '@thirdweb-dev/react';
const activeChainId = ChainId.Rinkeby;
ReactDOM.render(
<React.StrictMode>
<ThirdwebProvider desiredChainId={activeChainId}>
<App />
</ThirdwebProvider>
</React.StrictMode>,
doc.getElementById('root'),
);
Within the code snippet above, you probably did the next:
- Imported thirdweb dependency
- Specified the
chainId
of the chain you are engaged on, which is Rinkeby! - Wrapped all the things with
<ThirdwebProvider>
. This supplier holds the person’s authenticated pockets knowledge
Word: In case you’ve labored on dapps earlier than, be sure to disconnect your pockets from localhost:3000 on Metamask when you have ever related it.
Add Hook up with Pockets
In case you head to your net app, you may see a button to let customers join their wallets.
Head over to src/App.jsx
. Add the next code.
import { useAddress, useMetamask } from "@thirdweb-dev/react";
const App = () => {
const handle = useAddress();
const connectWithMetamask = useMetamask();
console.log("👋 Handle:", handle);
if (!handle) {
return (
<div className="touchdown">
<h1>Welcome to Web3WriterDAO</h1>
<button onClick={connectWithMetamask} className="btn-hero">
Join your pockets
</button>
</div>
);
}
return (
<div className="touchdown">
<h1>👀 Welcome to Web3Writer DAO membership</h1>
</div>
);
};
export default App;
Now, once you go to your net app, the online app appears to be like like this:
Subsequent, click on on the “Join your pockets” button, and you will see it pops Metamask!
After you authorize your pockets, you may see this display:
And should you go to your console, you may see it prints out your public handle. In case you refresh your web page right here, you may see your pockets connection additionally sticks round.
Including .env variables
You want to write some scripts that allow you to create and deploy your contract to Rinkeby utilizing Thirdweb. You will first create a .env
file that appears like this on the root of your mission.
PRIVATE_KEY=YOUR_PRIVATE_KEY_HERE
WALLET_ADDRESS=YOUR_WALLET_ADDRESS
ALCHEMY_API_URL=YOUR_QUICKNODE_API_URL
As a result of we don’t wish to push these to GitHub, you’ll want to add them in .gitignore
Creating an Alchemy app
Subsequent, head to Alchemy, register, click on on “Create App“, and supply the required particulars. Make certain to make use of the identical chain because the one you used within the thirdweb – in your case, it’s the Ethereum chain and the Rinkeby community.
After the app is created, copy the HTTP API key.
Getting the pockets’s non-public key
To mint NFTs and carry out sure scripts, you have to the pockets’s non-public key.
To entry it, open the MetaMask browser extension and click on on Account Particulars. You must see your non-public key right here; export it and replica it someplace protected.
Getting Began with Thirdweb
Superior! Now you can hook up with a person’s pockets to examine in the event that they’re in your DAO! To hitch your DAO, the person will want a membership NFT. If they do not have a membership NFT, you may immediate them truly to mint a membership NFT and be part of your DAO!
However, there’s an issue. For us to mint NFTs, you could write and deploy your personal NFT sensible contract. That is truly the place Thirdweb is available in clutch.
Thirdweb provides us a set of instruments to create all our sensible contracts with out writing any Solidity. You write no Solidity. All it’s essential do is write a script utilizing JavaScript to create and deploy your contracts.
Thirdweb will use a set of safe, customary contracts created right here. The cool half is after you create the contracts, you personal them, and so they’re related together with your pockets.
When you deploy the contract, you possibly can work together with these contracts out of your front-end simply utilizing their client-side SDK.
Thirdweb dashboard permits us to create contracts with out writing any code, however for this tutorial, we’ll create them with JavaScript. Additionally, thirdweb does not have a database; all of your knowledge is saved on-chain.
Initialize Thirdweb SDK
Now, write scripts that allow you to initialize Thirdweb SDK. You will create scripts
listing within the mission root folder and create a 1-initialize-sdk.js
file
import { ThirdwebSDK } from "@thirdweb-dev/sdk";
import ethers from "ethers";
import dotenv from "dotenv";
dotenv.config();
if (!course of.env.PRIVATE_KEY || course of.env.PRIVATE_KEY === "") {
console.log("🛑 Non-public key not discovered.");
}
if (!course of.env.ALCHEMY_API_URL || course of.env.ALCHEMY_API_URL === "") {
console.log("🛑 Alchemy API URL not discovered.");
}
if (!course of.env.WALLET_ADDRESS || course of.env.WALLET_ADDRESS === "") {
console.log("🛑 Pockets Handle not discovered.");
}
const sdk = new ThirdwebSDK(
new ethers.Pockets(
course of.env.PRIVATE_KEY,
ethers.getDefaultProvider(course of.env.ALCHEMY_API_URL)
)
);
(async () => {
attempt {
const handle = await sdk.getSigner().getAddress();
console.log("👋 SDK initialized by handle:", handle);
} catch (err) {
console.error("Did not get apps from the sdk", err);
course of.exit(1);
}
})();
export default sdk;
Within the code snippet above, all you are doing is initializing thirdweb
after which including an export default sdk
since you may be reusing the initialized sdk in different scripts. It is virtually like initializing a connection to a database from a server. You give it stuff like your non-public key and your supplier (which is Alchemy).
It will initialize the Thirdweb SDK, and as you possibly can see, we have to set up some packages:
npm i dotenv
yarn add dotenv
We’re utilizing modular imports right here, so create a brand new package deal.json
file contained in the scripts
folder and easily add the next:
{
"identify": "scripts",
"kind": "module"
}
Let’s execute it! Go to your terminal and paste the next command:
node scripts/1-initialize-sdk.js
The script could take a while to run, however you’ll get your app handle after a while.
You will want this within the subsequent steps, so retailer it someplace protected.
You’ll now create and deploy an ERC-1155 contract to Rinkeby. That is mainly the bottom module you may must create your NFTs. You are not creating your NFT right here but. You are simply establishing metadata across the assortment itself. That is stuff just like the identify of the gathering and a picture related to the gathering that reveals up on OpenSea because the header.
With an ERC-1155, a number of folks may be the holder of the identical NFT. On this case, your “membership NFT” is identical for everybody, so as a substitute of creating a brand new NFT each time, you possibly can merely assign the identical NFT to all of your members. That is additionally extra fuel environment friendly! This can be a widespread method for circumstances the place the NFT is identical for all holders.
Create a brand new file known as 2-deploy-drop.js
contained in the scripts
folder. Right here, add the next script:
import { AddressZero } from "@ethersproject/constants";
import sdk from "./1-initialize-sdk.js";
import { readFileSync } from "fs";
(async () => {
attempt {
const editionDropAddress = await sdk.deployer.deployEditionDrop({
identify: "Web3Writer Membership",
description: "A DAO for Web3 writers.",
picture: readFileSync("scripts/belongings/naruto.png"),
primary_sale_recipient: AddressZero,
});
const editionDrop = sdk.getEditionDrop(editionDropAddress);
const metadata = await editionDrop.metadata.get();
console.log(
"✅ Efficiently deployed editionDrop contract, handle:",
editionDropAddress
);
console.log("✅ editionDrop metadata:", metadata);
} catch (error) {
console.log("didn't deploy editionDrop contract", error);
}
})();
From the code snippet above, you give your assortment a identify
, description
, primary_sale_recipient
, and picture
. The picture you are loading is out of your native file, so you’ll want to embody that picture beneath scripts/belongings
. Ensure it is a PNG, JPG, or GIF for now and make certain it is a native picture — this may not work should you use an web hyperlink!
After you will have up to date the small print, run the next script:
node scripts/2-deploy-drop.js
Anticipate the script to run; you must get an handle and metadata.
You simply deployed an ERC-1155
contract to Rinkeby. That is proper! In case you head over to https://rinkeby.etherscan.io/
and paste within the handle of the editionDrop
contract, you may see you simply deployed a sensible contract! The best half is that you just personal this contract deployed out of your pockets. The “From” handle will probably be your public handle.
Word: Maintain the handle of your
editionDrop
round; you may want it later! should you ever lose it, you possibly can at all times retrieve it from the thirdweb dashboard
One other factor that occurred right here is that Thirdweb robotically uploaded and pinned your assortment’s picture to IPFS. You will see a hyperlink that begins with https://gateway.ipfscdn.io
printed out. In case you paste that into your browser, you may see your NFT’s picture retrieved from IPFS by way of Cloudflare!
Configuring NFT Information
Let’s truly deploy metadata related together with your membership NFT. You have not carried out that but. All you probably did to date was create the ERC-1155 contract and add some fundamental metadata.
Create a brand new 3-config-nft.js
file contained in the scripts
folder and add the next:
import sdk from "./1-initialize-sdk.js";
import { readFileSync } from "fs";
const editionDrop = sdk.getEditionDrop("INSERT_EDITION_DROP_ADDRESS");
(async () => {
attempt {
await editionDrop.createBatch([
{
name: "Hashnode",
description: "This NFT will give you access to Web3WriterDAO!",
image: readFileSync("scripts/assets/hashnodep.png"),
},
]);
console.log("✅ Efficiently created a brand new NFT within the drop!");
} catch (error) {
console.error("didn't create the brand new NFT", error);
}
})();
From the code snippet above, The very first thing you may be doing is accessing your editionDrop
contract, which is an ERC-1155. The INSERT_EDITION_DROP_ADDRESS
is the handle printed out from the step earlier than. It is the handle printed out after Efficiently deployed editionDrop contract, handle
. You may as well discover this in your thirdweb dashboard.
Then, you are establishing your precise NFT in your ERC-1155 utilizing createBatch
. You want to arrange some properties:
identify
: The identify of your NFT.description
: The outline of your NFTpicture
: The picture in your NFT. That is the picture of the NFT that customers will declare to have the ability to entry your DAO.
Keep in mind, as a result of it is an ERC-1155, all of your members will mint the identical NFT.
Upon getting up to date all of them, run the next script:
node scripts/3-config-nft.js
It ought to provide you with an output like this.
In case you see the module within the Thirdweb dashboard, you will notice that an NFT has been created! 🥳
Setup declare situation
Setting a declare situation will enable us to set a restrict for the NFTs and permit a selected max restrict per transaction.
Create a brand new 4-set-claim-condition.js
file contained in the scripts
folder and add the next:
import sdk from "./1-initialize-sdk.js";
import { MaxUint256 } from "@ethersproject/constants";
const editionDrop = sdk.getEditionDrop("INSERT_EDITION_DROP_ADDRESS");
(async () => {
attempt {
const claimConditions = [{
startTime: new Date(),
maxQuantity: 50_000,
price: 0,
quantityLimitPerTransaction: 1,
waitInSeconds: MaxUint256,
}]
await editionDrop.claimConditions.set("0", claimConditions);
console.log("✅ Efficiently set declare situation!");
} catch (error) {
console.error("Did not set declare situation", error);
}
})();
Within the code snippet above, you embody the next properties:
-
startTime
is when customers are allowed to begin minting NFTs; on this case, you simply set that date/time to the present time, that means minting can begin instantly -
maxQuantity
is the max variety of membership NFTs that may be minted. quantityLimitPerTransaction specifies what number of tokens somebody can declare in a single transaction; you set this to at least one since you solely need customers minting one NFT at a time worth
units the value of your NFT; in your case, 0 at no costwaitInSeconds
is the period of time between transactions; since you solely need folks claiming as soon as, you set it to the utmost quantity that the blockchain permits- Lastly, the
editionDrop.claimConditions.set("0", claimConditions)
and this can truly work together together with your deployed contract on-chain and regulate the situations
After working node scripts/4-set-claim-condition.js
, this is what you may get:
Letting customers mint their NFT
At this stage now, you may be checking two issues:
-
In case your person has a membership NFT, present them your “DAO Dashboard” display the place they will vote on proposals and see DAO-related information.
-
If the person does not have your NFT, you may give them a button to mint one.
Checking if customers personal a membership NFT
Head over to App.jsx
. Replace your imports to:
import { useAddress, useMetamask, useEditionDrop } from '@thirdweb-dev/react';
import { useState, useEffect } from 'react';
From there, under your console.log("👋 Handle:", handle);
you are going to add:
const editionDrop = useEditionDrop("INSERT_EDITION_DROP_ADDRESS");
const [hasClaimedNFT, setHasClaimedNFT] = useState(false);
useEffect(() => {
if (!handle) {
return;
}
const checkBalance = async () => {
attempt {
const stability = await editionDrop.balanceOf(handle, 0);
if (stability.gt(0)) {
setHasClaimedNFT(true);
console.log("🌟 this person has a membership NFT!");
} else {
setHasClaimedNFT(false);
console.log("😭 this person does not have a membership NFT.");
}
} catch (error) {
setHasClaimedNFT(false);
console.error("Did not get stability", error);
}
};
checkBalance();
}, [address, editionDrop]);
Within the code snippet above, you probably did the next:
- First, initialize your
editionDrop
contract - Create a state
hasClaimedNFT
to know if the person has your NFT - Use
editionDrop.balanceOf(handle, "0")
to examine if the person has our NFT.
In case you open the console on the web site, it ought to present that you just don’t have an NFT.
Making a button to mint NFTs
Let’s create the button to mint NFTs. However first, within the App.jsx
,and let’s add the isClaiming
state:
const [isClaiming, setIsClaiming] = useState(false);
Create a brand new perform known as mintNft
like so:
const mintNft = async () => {
attempt {
setIsClaiming(true);
await editionDrop.declare("0", 1);
console.log(`🌊 Efficiently Minted! Test it out on OpenSea: https:
setHasClaimedNFT(true);
} catch (error) {
setHasClaimedNFT(false);
console.error("Did not mint NFT", error);
} lastly {
setIsClaiming(false);
}
};
Let’s create the button now! Inside the ultimate return
block, add the next:
<div className="mint-nft">
<h1>Mint your free 🍪DAO Membership NFT</h1>
<button
disabled={isClaiming}
onClick={mintNft}
>
{isClaiming ? "Minting..." : "Mint your nft (FREE)"}
</button>
</div>
After you register, it ought to present you a display like this.
In case you click on on the Mint your nft (FREE) button, it ought to pop up in your MetaMask display to finish the transaction. Within the console, you must see the next.
As soon as it is carried out minting, you must see Efficiently Minted!
in your console together with the Testnet OpenSea hyperlink. On testnets.opensea.io
, you possibly can truly see NFTs minted on the testnet. While you head to your hyperlink, you may see one thing like this:
Present DAO Dashboard provided that the person owns the NFT
Lastly, simply above the ultimate return
block, add this examine to see if the person has claimed the NFT already:
if (hasClaimedNFT) {
return (
<div className="member-page">
<h1>Web3Writer DAO Member Web page</h1>
<p>Congratulations on being a member</p>
</div>
);
}
Now we have accomplished constructing the minting NFT performance.
Making a model new Token
Let’s create and deploy a token sensible contract! Create a brand new scripts/5-deploy-token.js
file contained in the scripts
folder and add the next:
import { AddressZero } from "@ethersproject/constants";
import sdk from "./1-initialize-sdk.js";
(async () => {
attempt {
const tokenAddress = await sdk.deployer.deployToken({
identify: "Web3Writer Token",
image: "W3W",
primary_sale_recipient: AddressZero,
});
console.log(
"✅ Efficiently deployed token module, handle:",
tokenAddress
);
} catch (error) {
console.error("didn't deploy token module", error);
}
})();
Run the scripts/5-deploy-token.js
file, and you will get this:
Growth! It deployed a contemporary token contract. In case you head to https://rinkeby.etherscan.io/
and search the token module’s handle, you’ll see the contract you simply deployed.
You possibly can even add your token to Metamask as a customized token. By clicking on Import Token
Then, paste in your ERC-20 contract handle, and also you’ll see Metamask magically seize your token image robotically:
Then, head again to your pockets, scroll down, and growth!
You formally have your personal token.
Minting your personal tokens
Create a brand new file known as 6-mint-token.js
contained in the scripts
folder and add the next:
import sdk from "./1-initialize-sdk.js";
const token = sdk.getToken("INSERT_TOKEN_ADDRESS");
(async () => {
attempt {
const quantity = 1_000_000;
await token.mintToSelf(quantity);
const totalSupply = await token.totalSupply();
console.log(
"✅ There now could be",
totalSupply.displayValue,
"$W3W in circulation"
);
} catch (error) {
console.error("Did not print cash", error);
}
})();
Right here’s what you may get once you run the script node scripts/6-mint-token.js
:
You must now see the quantity of tokens you minted in your MetaMask pockets!
Airdropping tokens
You may wish to airdrop the tokens to your NFT holders, so let’s construct a script for that. Create a brand new 7-airdrop-token.js
file inside scripts and add the next:
import sdk from "./1-initialize-sdk.js";
const editionDrop = sdk.getEditionDrop("INSERT_EDITION_DROP_ADDRESS");
const token = sdk.getToken("INSERT_TOKEN_ADDRESS");
(async () => {
attempt {
const walletAddresses = await editionDrop.historical past.getAllClaimerAddresses(0);
if (walletAddresses.size === 0) {
console.log(
"No NFTs have been claimed but; perhaps get some buddies to say your free NFTs!"
);
course of.exit(0);
}
const airdropTargets = walletAddresses.map((handle) => {
const randomAmount = Math.ground(
Math.random() * (10000 - 1000 + 1) + 1000
);
console.log("✅ Going to airdrop", randomAmount, "tokens to", handle);
const airdropTarget = {
toAddress: handle,
quantity: randomAmount,
};
return airdropTarget;
});
console.log("🌈 Beginning airdrop...");
await token.transferBatch(airdropTargets);
console.log(
"✅ Efficiently airdropped tokens to all of the holders of the NFT!"
);
} catch (err) {
console.error("Did not airdrop tokens", err);
}
})();
After you run the script, you must get one thing like this.
Presently, solely you will have minted an NFT, so it received’t ship the token to another person. However this can be utilized to ship to different NFT holders later.
Constructing a Treasury and Governance
A governance token is cool, nevertheless it’s ineffective if folks can’t use it to manipulate something! What you’re going to do subsequent right here is ready up a governance contract that lets folks vote on proposals utilizing their tokens.
Create a brand new deploy-vote.js
file within the scripts
folder and add the next:
import sdk from "./1-initialize-sdk.js";
(async () => {
attempt {
const voteContractAddress = await sdk.deployer.deployVote({
identify: "Web3Writer DAO proposal",
voting_token_address: "INSERT_TOKEN_ADDRESS",
voting_delay_in_blocks: 0,
voting_period_in_blocks: 6570,
voting_quorum_fraction: 0,
proposal_token_threshold: 0,
});
console.log(
"✅ Efficiently deployed vote contract, handle:",
voteContractAddress,
);
} catch (err) {
console.error("Did not deploy vote contract", err);
}
})();
Go forward and run this utilizing node scripts/deploy-vote.js
. Right here’s what you may find yourself getting:
Setup your treasury
You additionally must arrange a voting module, so create a brand new script known as setup-vote.js
and add the next:
import sdk from "./1-initialize-sdk.js";
const vote = sdk.getVote("INSERT_VOTE_ADDRESS");
const token = sdk.getToken("INSERT_TOKEN_ADDRESS");
(async () => {
attempt {
await token.roles.grant("minter", vote.getAddress());
console.log(
"Efficiently gave vote contract permissions to behave on token contract"
);
} catch (error) {
console.error(
"didn't grant vote contract permissions on token contract",
error
);
course of.exit(1);
}
attempt {
const ownedTokenBalance = await token.balanceOf(
course of.env.WALLET_ADDRESS
);
const ownedAmount = ownedTokenBalance.displayValue;
const percent90 = Quantity(ownedAmount) / 100 * 90;
await token.switch(
vote.getAddress(),
percent90
);
console.log("✅ Efficiently transferred " + percent90 + " tokens to vote contract");
} catch (err) {
console.error("didn't switch tokens to vote contract", err);
}
})();
When you end up, you possibly can run this utilizing node scripts/9-setup-vote.js
. Right here’s what you may get as your output:
Let customers vote on proposals.
Cool. All the things is ready up. Now, you simply must create your first proposal! Create a brand new file known as create-vote-proposals.js
contained in the scripts
folder and add the next:
import sdk from "./1-initialize-sdk.js";
import { ethers } from "ethers";
const vote = sdk.getVote("INSERT_VOTE_ADDRESS");
const token = sdk.getToken("INSERT_TOKEN_ADDRESS");
(async () => {
attempt {
const quantity = 420_000;
const description = "Ought to the DAO mint an extra " + quantity + " tokens into the treasury?";
const executions = [
{
toAddress: token.getAddress(),
nativeTokenValue: 0,
transactionData: token.encoder.encode(
"mintTo", [
vote.getAddress(),
ethers.utils.parseUnits(amount.toString(), 18),
]
),
}
];
await vote.suggest(description, executions);
console.log("✅ Efficiently created proposal to mint tokens");
} catch (error) {
console.error("didn't create first proposal", error);
course of.exit(1);
}
attempt {
const quantity = 6_900;
const description = "Ought to the DAO switch " + quantity + " tokens from the treasury to " +
course of.env.WALLET_ADDRESS + " for being superior?";
const executions = [
{
nativeTokenValue: 0,
transactionData: token.encoder.encode(
"transfer",
[
process.env.WALLET_ADDRESS,
ethers.utils.parseUnits(amount.toString(), 18),
]
),
toAddress: token.getAddress(),
},
];
await vote.suggest(description, executions);
console.log(
"✅ Efficiently created proposal to reward ourselves from the treasury, let's hope folks vote for it!"
);
} catch (error) {
console.error("didn't create second proposal", error);
}
})();
You want to replace the module addresses, and if you wish to replace the message of the proposal, you may also replace that.
Lastly, run the script. It ought to provide you with one thing like this.
In case you now examine the Thirdweb dashboard, the proposal has been created.
Let customers vote on proposals from the dashboard
Lastly, let’s deliver all of it to the online web page. Proper now, your proposals reside on sensible contracts. However, you need your customers to have the ability to see them and vote simply!
First, Head to App.jsx
. Add the useVote
hook to your imports:
import { useAddress, useMetamask, useEditionDrop, useToken, useVote } from '@thirdweb-dev/react';
We’re going to want three useStates, like so:
const [proposals, setProposals] = useState([]);
const [isVoting, setIsVoting] = useState(false);
const [hasVoted, setHasVoted] = useState(false);
Getting the proposals
The net app wants entry to your vote so customers can work together with that contract.
Let’s add the next code someplace beneath the shortenAddress
perform:
useEffect(() => {
if (!hasClaimedNFT) {
return;
}
const getAllProposals = async () => {
attempt {
const proposals = await vote.getAll();
setProposals(proposals);
console.log(" Proposals:", proposals);
} catch (error) {
console.log("didn't get proposals", error);
}
};
getAllProposals();
}, [hasClaimedNFT, vote]);
useEffect(() => {
if (!hasClaimedNFT) {
return;
}
if (!proposals.size) {
return;
}
const checkIfUserHasVoted = async () => {
attempt {
const hasVoted = await vote.hasVoted(proposals[0].proposalId, handle);
setHasVoted(hasVoted);
if (hasVoted) {
console.log("🥵 Consumer has already voted");
} else {
console.log("🙂 Consumer has not voted but");
}
} catch (error) {
console.error("Did not examine if the pockets has voted", error);
}
};
checkIfUserHasVoted();
}, [hasClaimedNFT, proposals, address, vote]);
The code above has two React useEffect
Hook which did the next:
- The primary
useEffect
used thevote.getAll()
to seize all of the proposals that exist in your governance contract after which doingsetProposals
to render them later - The second
useEffect
used thevote.hasVoted(proposals[0].proposalId, handle)
to checks if this handle has voted on the primary proposal. If it has, thesetHasVoted
so the person can’t vote once more!
Thirdweb not solely makes it very easy to deploy sensible contracts, nevertheless it additionally makes it very straightforward to work together with them out of your shopper with easy capabilities like
vote.getAll()
!
Go forward and refresh your web page, you must see your proposals printed out, and you may discover all the information.
Rendering the proposals
Add the zero handle import after your current imports:
import { AddressZero } from "@ethersproject/constants";
Go forward and substitute the code of if(hasClaimedNFT) { }
with the code here.
While you try your net app, you’ll see one thing like:
Eradicating Admin Privileges
In case you keep in mind, you truly nonetheless maintain “minting” rights on the ERC-20 contract. Meaning you possibly can go and create extra tokens if you’d like, which can freak out members of your DAO.
So, It’s greatest to revoke your “minting” function fully. That approach, solely the voting contract can mint new tokens.
We will do that by creating revoke-roles.js
file within the scripts
folder and the next:
import sdk from "./1-initialize-sdk.js";
const token = sdk.getToken("INSERT_TOKEN_ADDRESS");
(async () => {
attempt {
const allRoles = await token.roles.getAll();
console.log("👀 Roles that exist proper now:", allRoles);
await token.roles.setAll({ admin: [], minter: [] });
console.log(
"🎉 Roles after revoking ourselves",
await token.roles.getAll()
);
console.log("✅ Efficiently revoked our superpowers from the ERC-20 contract");
} catch (error) {
console.error("Did not revoke ourselves from the DAO treasury", error);
}
})();
While you run this utilizing node scripts/11-revoke-roles.js. you may get:
Deal with fundamental unsupported community error
To acknowledge a connection outdoors the Rinkeby community, let’s import one final hook, useNetwork
on the prime of App.jsx. We’re additionally importing ChainId
from the Thirdweb SDK to get Rinkeby’s chain ID.
import { useAddress, useMetamask, useEditionDrop, useToken, useVote, useNetwork } from '@thirdweb-dev/react';
import { ChainId } from '@thirdweb-dev/sdk'
Then, outline your useNetwork
hook beneath your useAddress
hook:
const community = useNetwork();
Subsequent, add the next in your App.jsx
file proper beneath the mintNft
perform:
if (handle && (community?.[0].knowledge.chain.id !== ChainId.Rinkeby)) {
return (
<div className="unsupported-network">
<h2>Please hook up with Rinkeby</h2>
<p>
This dapp solely works on the Rinkeby community. Please change networks
in your related pockets.
</p>
</div>
);
}
We’re checking if we’re discovering a series on our most popular community. In our case Rinkeby, if we aren’t, we’re prompting customers to change networks.
Conclusion
You’ve carried out it. You made it to the top. On this article, you deployed your personal customized ERC-20 token and deployed your personal ERC-1155 NFT folks can mint to affix your DAO.
You additionally realized to deploy your personal governance contract and treasury. Constructed a dapp that lets folks join their pockets, get an NFT, see a DAO Dashboard the place they will see different members, and vote on proposals executed instantly by your governance contract.
To study extra about NFTs, dApps, the blockchain, and different web3 content material, try Hashnode’s web3 blog.