Thirdweb is a platform that gives a collection of instruments for creators, artists, and entrepreneurs to construct, launch and handle a Web3 undertaking simply.
It permits customers so as to add options akin to NFTs, marketplaces, and social tokens to their Web3 tasks with out writing a line of code.
On this article, you may higher perceive what DAO is, why you need to create a DAO, and how one can create a DAO with Thirdweb.
This may permit customers to mint your DAO’s NFT, obtain cryptocurrency by way of airdrops, and take part within the DAO’s polls.
Stipulations
Earlier than you may proceed with this tutorial, you need to:
- 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 kind of governance generally used for DApps, tasks, 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 completely different definitions and explanations of what a DAO is.
Normally 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.
Establishing the DAO Shopper-side
To begin constructing your DAO client-side utility, you may be utilizing the thirdweb-CLI
command.
First, Set up the Thirdweb CLI globally software by typing the under command:
yarn add @thirdweb-dev/cli
Thirdweb comprises starters that assist generate a base setup to your undertaking. Use the command under to generate a Thirdweb starter undertaking. Kind a undertaking title and identify of your selection for the undertaking listing. Observe the prompts to finish the setup.
npx thirdweb create
As soon as the set up is full, head over to the undertaking listing and run the command under to begin your utility:
npm begin
Navigate to localhost:3000 to view your undertaking on a browser.
Get Metamask
Subsequent, you want an Ethereum pockets. There are a bunch of those, however for this undertaking, 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?
Effectively. You want to have the ability to name features in your sensible contract that dwell on the blockchain. And to try this, you want to have a pockets together with your Ethereum tackle 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, to your web site to speak to the blockchain, you want to in some way join your pockets to it. When you join your pockets to the web site, your web site can have permission to name sensible contracts in your behalf. Bear in mind, it is identical to authenticating into an internet site.
So, go forward and set all of it up! Their setup circulate is fairly self-explanatory.
When you arrange your pockets, change the community to “Rinkeby”, the check community you may be working with.
Be sure to 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 is not value messing up. You are going to begin with a “testnet,” which is a clone of “mainnet,” nevertheless it makes use of faux funds; you may check stuff out as a lot as you need. However, it is necessary to know that testnets are run by precise miners and mimic real-world eventualities.
You may be utilizing Rinkeby, which the Ethereum Basis runs. To get some faux ETH, head to the RINKEBY FAUCET web site, paste your tackle within the enter kind, and click on on the “Ship Me ETH” button.
As soon as your transaction is mined, you may have some faux ETH in your pockets.
Specify your chain and pockets sort
So, to your web site to speak to the blockchain, you want to in some way join your pockets to it. When you join your pockets to your web site, the web site can have permission to name sensible contracts in your behalf. Bear in mind, it is identical to authenticating into an internet site.
You’ll have constructed “Hook up with Pockets” buttons up 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 every part with
<ThirdwebProvider>
. This supplier holds the person’s authenticated pockets knowledge
Observe: Should you’ve labored on dapps earlier than, be sure you disconnect your pockets from localhost:3000 on Metamask when you’ve got ever linked it.
Add Hook up with Pockets
Should you head to your internet 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 tackle = useAddress();
const connectWithMetamask = useMetamask();
console.log("👋 Deal with:", tackle);
if (!tackle) {
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, if you go to your internet app, the net 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 in the event you go to your console, you may see it prints out your public tackle. Should you refresh your web page right here, you may see your pockets connection additionally sticks round.
Including .env variables
It’s worthwhile to write some scripts that allow you to create and deploy your contract to Rinkeby utilizing Thirdweb. You may first create a .env
file that appears like this on the root of your undertaking.
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, check in, click on on “Create App“, and supply the required particulars. Be 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 personal key
To mint NFTs and carry out sure scripts, you will have the pockets’s personal key.
To entry it, open the MetaMask browser extension and click on on Account Particulars. It is best to see your personal key right here; export it and replica it someplace protected.
Getting Began with Thirdweb
Superior! Now you can connect with a person’s pockets to examine in the event that they’re in your DAO! To affix your DAO, the person will want a membership NFT. If they do not have a membership NFT, you may immediate them really to mint a membership NFT and be a part of your DAO!
However, there’s an issue. For us to mint NFTs, you need to write and deploy your individual NFT sensible contract. That is really 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 you want to do is write a script utilizing JavaScript to create and deploy your contracts.
Thirdweb will use a set of safe, normal contracts created right here. The cool half is after you create the contracts, you personal them, they usually’re related together with your pockets.
When you deploy the contract, you may 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 are going to create them with JavaScript. Additionally, thirdweb would 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 may create scripts
listing within the undertaking 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("🛑 Personal 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 Deal with not discovered.");
}
const sdk = new ThirdwebSDK(
new ethers.Pockets(
course of.env.PRIVATE_KEY,
ethers.getDefaultProvider(course of.env.ALCHEMY_API_URL)
)
);
(async () => {
strive {
const tackle = await sdk.getSigner().getAddress();
console.log("👋 SDK initialized by tackle:", tackle);
} 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 personal key and your supplier (which is Alchemy).
This may initialize the Thirdweb SDK, and as you may 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 bundle.json
file contained in the scripts
folder and easily add the next:
{
"identify": "scripts",
"sort": "module"
}
Let’s execute it! Go to your terminal and paste the next command:
node scripts/1-initialize-sdk.js
The script might take a while to run, however you’ll get your app tackle after a while.
You’ll need 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 might be the holder of the identical NFT. On this case, your “membership NFT” is similar for everybody, so as a substitute of creating a brand new NFT each time, you may merely assign the identical NFT to all of your members. That is additionally extra gasoline environment friendly! It is a frequent method for circumstances the place the NFT is similar 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 () => {
strive {
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, tackle:",
editionDropAddress
);
console.log("✅ editionDrop metadata:", metadata);
} catch (error) {
console.log("did not 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 below scripts/belongings
. Make sure it is a PNG, JPG, or GIF for now and be certain it is a native picture — this would possibly not work in the event you use an web hyperlink!
After you’ve up to date the small print, run the next script:
node scripts/2-deploy-drop.js
Await the script to run; you need to get an tackle and metadata.
You simply deployed an ERC-1155
contract to Rinkeby. That is proper! Should you head over to https://rinkeby.etherscan.io/
and paste within the tackle of the editionDrop
contract, you may see you simply deployed a sensible contract! The best half is that you simply personal this contract deployed out of your pockets. The “From” tackle can be your public tackle.
Observe: Hold the tackle of your
editionDrop
round; you may want it later! in the event you ever lose it, you may at all times retrieve it from the thirdweb dashboard
One other factor that occurred right here is that Thirdweb mechanically uploaded and pinned your assortment’s picture to IPFS. You may see a hyperlink that begins with https://gateway.ipfscdn.io
printed out. Should 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 really deploy metadata related together with your membership NFT. You have not completed that but. All you probably did thus far was create the ERC-1155 contract and add some primary 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 () => {
strive {
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("did not 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 tackle printed out from the step earlier than. It is the tackle printed out after Efficiently deployed editionDrop contract, tackle
. You too can discover this in your thirdweb dashboard.
Then, you are establishing your precise NFT in your ERC-1155 utilizing createBatch
. It’s worthwhile to arrange some properties:
identify
: The identify of your NFT.description
: The outline of your NFTpicture
: The picture to your NFT. That is the picture of the NFT that customers will declare to have the ability to entry your DAO.
Bear 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.
Should you see the module within the Thirdweb dashboard, you will note that an NFT has been created! 🥳
Setup declare situation
Setting a declare situation will permit us to set a restrict for the NFTs and permit a particular 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 () => {
strive {
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 value
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 really work together together with your deployed contract on-chain and regulate the circumstances
After operating 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 would 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("👋 Deal with:", tackle);
you are going to add:
const editionDrop = useEditionDrop("INSERT_EDITION_DROP_ADDRESS");
const [hasClaimedNFT, setHasClaimedNFT] = useState(false);
useEffect(() => {
if (!tackle) {
return;
}
const checkBalance = async () => {
strive {
const stability = await editionDrop.balanceOf(tackle, 0);
if (stability.gt(0)) {
setHasClaimedNFT(true);
console.log("🌟 this person has a membership NFT!");
} else {
setHasClaimedNFT(false);
console.log("😭 this person would 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(tackle, "0")
to examine if the person has our NFT.
Should you open the console on the web site, it ought to present that you simply 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 operate known as mintNft
like so:
const mintNft = async () => {
strive {
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 check in, it ought to present you a display like this.
Should 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 need to see the next.
As soon as it is completed minting, you need to see Efficiently Minted!
in your console together with the Testnet OpenSea hyperlink. On testnets.opensea.io
, you may really see NFTs minted on the testnet. Whenever 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>
);
}
We now 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 () => {
strive {
const tokenAddress = await sdk.deployer.deployToken({
identify: "Web3Writer Token",
image: "W3W",
primary_sale_recipient: AddressZero,
});
console.log(
"✅ Efficiently deployed token module, tackle:",
tokenAddress
);
} catch (error) {
console.error("did not deploy token module", error);
}
})();
Run the scripts/5-deploy-token.js
file, and you will get this:
Increase! It deployed a recent token contract. Should you head to https://rinkeby.etherscan.io/
and search the token module’s tackle, 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 tackle, and also you’ll see Metamask magically seize your token image mechanically:
Then, head again to your pockets, scroll down, and growth!
You formally have your individual token.
Minting your individual 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 () => {
strive {
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 if you run the script node scripts/6-mint-token.js
:
It is best to now see the quantity of tokens you minted in your MetaMask pockets!
Airdropping tokens
You would possibly 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 () => {
strive {
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 assert your free NFTs!"
);
course of.exit(0);
}
const airdropTargets = walletAddresses.map((tackle) => {
const randomAmount = Math.flooring(
Math.random() * (10000 - 1000 + 1) + 1000
);
console.log("✅ Going to airdrop", randomAmount, "tokens to", tackle);
const airdropTarget = {
toAddress: tackle,
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 need to get one thing like this.
At the moment, solely you’ve 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 control something! What you’re going to do subsequent right here is about 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 () => {
strive {
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, tackle:",
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 () => {
strive {
await token.roles.grant("minter", vote.getAddress());
console.log(
"Efficiently gave vote contract permissions to behave on token contract"
);
} catch (error) {
console.error(
"did not grant vote contract permissions on token contract",
error
);
course of.exit(1);
}
strive {
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("did not switch tokens to vote contract", err);
}
})();
When you end up, you may 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. Every part is about 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 () => {
strive {
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("did not create first proposal", error);
course of.exit(1);
}
strive {
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("did not create second proposal", error);
}
})();
It’s worthwhile to replace the module addresses, and if you wish to replace the message of the proposal, you may as well replace that.
Lastly, run the script. It ought to provide you with one thing like this.
Should 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 net web page. Proper now, your proposals dwell 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
operate:
useEffect(() => {
if (!hasClaimedNFT) {
return;
}
const getAllProposals = async () => {
strive {
const proposals = await vote.getAll();
setProposals(proposals);
console.log(" Proposals:", proposals);
} catch (error) {
console.log("did not get proposals", error);
}
};
getAllProposals();
}, [hasClaimedNFT, vote]);
useEffect(() => {
if (!hasClaimedNFT) {
return;
}
if (!proposals.size) {
return;
}
const checkIfUserHasVoted = async () => {
strive {
const hasVoted = await vote.hasVoted(proposals[0].proposalId, tackle);
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, tackle)
to checks if this tackle 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 features like
vote.getAll()
!
Go forward and refresh your web page, you need to see your proposals printed out, and you’ll discover all the information.
Rendering the proposals
Add the zero tackle import after your current imports:
import { AddressZero } from "@ethersproject/constants";
Go forward and substitute the code of if(hasClaimedNFT) { }
with the code here.
Whenever you take a look at your internet app, you’ll see one thing like:
Eradicating Admin Privileges
Should you keep in mind, you really nonetheless maintain “minting” rights on the ERC-20 contract. Which means you may 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 are able to 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 () => {
strive {
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);
}
})();
Whenever you run this utilizing node scripts/11-revoke-roles.js. you may get:
Deal with primary unsupported community error
To acknowledge a connection outdoors the Rinkeby community, let’s import one final hook, useNetwork
on the high 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 below your useAddress
hook:
const community = useNetwork();
Subsequent, add the next in your App.jsx
file proper below the mintNft
operate:
if (tackle && (community?.[0].knowledge.chain.id !== ChainId.Rinkeby)) {
return (
<div className="unsupported-network">
<h2>Please connect with Rinkeby</h2>
<p>
This dapp solely works on the Rinkeby community. Please change networks
in your linked pockets.
</p>
</div>
);
}
We’re checking if we’re discovering a sequence on our most popular community. In our case Rinkeby, if we’re not, we’re prompting customers to change networks.
Conclusion
You’ve completed it. You made it to the tip. On this article, you deployed your individual customized ERC-20 token and deployed your individual ERC-1155 NFT folks can mint to hitch your DAO.
You additionally discovered to deploy your individual 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 straight by your governance contract.
To study extra about NFTs, dApps, the blockchain, and different web3 content material, take a look at Hashnode’s web3 blog.